diff --git a/src/etc/inc/interfaces.inc b/src/etc/inc/interfaces.inc
index 8710fdaa5..0248d690a 100644
--- a/src/etc/inc/interfaces.inc
+++ b/src/etc/inc/interfaces.inc
@@ -2863,13 +2863,11 @@ function interface_dhcpv6_configure($interface = 'wan', $wancfg)
{
global $config;
- if (!is_array($wancfg)) {
- return;
- }
-
/* write DUID if override was set */
if (!empty($config['system']['ipv6duid'])) {
- $temp = str_replace(':', '', $config['system']['ipv6duid']);
+ $temp = explode(':', $config['system']['ipv6duid']);
+ array_unshift($temp, sprintf('%02x', count($temp)), '00');
+ $temp = implode('', $temp);
$duid_binstring = pack('H*', $temp);
$fd = fopen('/var/db/dhcp6c_duid', 'wb');
if ($fd) {
@@ -2878,6 +2876,10 @@ function interface_dhcpv6_configure($interface = 'wan', $wancfg)
}
}
+ if (!is_array($wancfg)) {
+ return;
+ }
+
$wanif = get_real_interface($interface, 'inet6');
/* accept router advertisements for this interface */
diff --git a/src/www/system_advanced_network.php b/src/www/system_advanced_network.php
index 07f989b4b..0038becc5 100644
--- a/src/www/system_advanced_network.php
+++ b/src/www/system_advanced_network.php
@@ -34,18 +34,68 @@ require_once("interfaces.inc");
require_once("filter.inc");
require_once("system.inc");
-/*
- * Format a string to look (more) like the expected DUID format:
- *
- * 1) Replace any "-" with ":"
- * 2) If the user inputs 14 components, then add the expected "0e:00:" to the front.
- * This is convenience, because the actual DUID (which is reported in logs) is the last 14 components.
- * 3) If any components are input with just a single char (hex digit hopefully), put a "0" in front.
- *
- * The final result should be closer to:
- *
- * "0e:00:00:01:00:01:nn:nn:nn:nn:nn:nn:nn:nn:nn:nn"
- */
+function get_mac_address()
+{
+ $ip = getenv('REMOTE_ADDR');
+ $mac = `/usr/sbin/arp -an | grep {$ip} | cut -d" " -f4`;
+ $mac = str_replace("\n","",$mac);
+ return $mac;
+}
+
+function generate_new_duid($duid_type)
+{
+ switch ($duid_type) {
+ case '1': //LLT
+ $mac = get_mac_address();
+ $ts = time() - 946684800;
+ $hts = dechex($ts);
+ $timestamp = sprintf("%s",$hts);
+ $timestamp_array = str_split($timestamp,2);
+ $timestamp = implode(":",$timestamp_array);
+ $type = "\x00\x01\x00\x01";
+ while ($count < strlen($type)) {
+ $new_duid .= bin2hex( $type[$count]);
+ $count++;
+ if ($count < strlen($type)) {
+ $new_duid .= ':';
+ }
+ }
+ $new_duid = $new_duid.':'.$timestamp.':'.$mac;
+ break;
+ case '2': //LL
+ $ts = time() - 946684800;
+ $hts = dechex($ts);
+ $timestamp = sprintf("%s",$hts);
+ $timestamp_array = str_split($timestamp,2);
+ $timestamp = implode(":",$timestamp_array);
+ $type = "\x00\x03\x00\x01";
+ while ($count < strlen($type)) {
+ $new_duid .= bin2hex( $type[$count]);
+ $count++;
+ if ($count < strlen($type)) {
+ $new_duid .= ':';
+ }
+ }
+ $new_duid = $new_duid.':'.$timestamp;
+ break;
+ case '3': //UUID
+ $type = "\x00\x00\x00\x04".openssl_random_pseudo_bytes(16);
+ while ($count < strlen($type)) {
+ $new_duid .= bin2hex( $type[$count]);
+ $count++;
+ if ($count < strlen($type)) {
+ $new_duid .= ':';
+ }
+ }
+ break;
+ default:
+ $new_duid = 'XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX';
+ break;
+ }
+
+ return $new_duid;
+}
+
function format_duid($duid)
{
$values = explode(':', strtolower(str_replace('-', ':', $duid)));
@@ -63,13 +113,33 @@ function format_duid($duid)
function is_duid($duid)
{
+ // Duid's can be any length. Just check the format is correct.
$values = explode(":", $duid);
- if (count($values) != 16 || strlen($duid) != 47) {
+ // need to get the DUID type. There are four types, in the
+ // first three the type number is in byte[2] in the fourth it's
+ // in byte[4]. Offset is either 0 or 2 depending if it's the read #
+ // from file duid or the user input.
+
+ $valid_duid = false;
+
+ $duid_length = count($values);
+ $test1 = hexdec($values[1]);
+ $test2 = hexdec($values[3]);
+ if (($test1 == 1 && $test2 == 1 ) || ($test1 == 3 && $test2 == 1 ) || ($test1 == 0 && $test2 == 4 ) || ($test1 == 2)) {
+ $valid_duid = true;
+ }
+
+ /* max DUID length is 128, but with the seperators it could be up to 254 */
+ if ($duid_length < 6 || $duid_length > 254) {
+ $valid_duid = false;
+ }
+
+ if ($valid_duid == false) {
return false;
}
- for ($i = 0; $i < 16; $i++) {
+ for ($i = 0; $i < count($values); $i++) {
if (ctype_xdigit($values[$i]) == false) {
return false;
}
@@ -86,20 +156,22 @@ function read_duid()
{
$duid = '';
$count = 0;
+ if (file_exists('/var/db/dhcp6c_duid')) {
+ $filesize = filesize('/var/db/dhcp6c_duid');
+ if ($fd = fopen('/var/db/dhcp6c_duid', 'r')) {
+ $buffer = fread($fd, $filesize);
+ fclose($fd);
- if (file_exists('/var/db/dhcp6c_duid') &&
- ($fd = fopen('/var/db/dhcp6c_duid', 'r'))) {
- if (filesize('/var/db/dhcp6c_duid') == 16) {
- $buffer = fread($fd, 16);
- while ($count < 16) {
- $duid .= bin2hex($buffer[$count]);
+ $duid_length = hexdec(bin2hex($buffer[0])); // This is the length of the duid, NOT the file
+
+ while ($count < $duid_length) {
+ $duid .= bin2hex($buffer[$count+2]); // Offset by 2 bytes
$count++;
- if ($count < 16) {
+ if ($count < $duid_length) {
$duid .= ':';
}
}
}
- fclose($fd);
}
if (!is_duid($duid)) {
@@ -123,6 +195,9 @@ if ($_SERVER['REQUEST_METHOD'] === 'GET') {
$pconfig['disablevlanhwfilter'] = $config['system']['disablevlanhwfilter'];
}
$pconfig['sharednet'] = isset($config['system']['sharednet']);
+ $pconfig['ipv6_duid_llt_value'] = generate_new_duid('1');
+ $pconfig['ipv6_duid_ll_value'] = generate_new_duid('2');
+ $pconfig['ipv6_duid_uuid_value'] = generate_new_duid('3');
} elseif ($_SERVER['REQUEST_METHOD'] === 'POST') {
$input_errors = array();
$pconfig = $_POST;
@@ -168,11 +243,13 @@ if ($_SERVER['REQUEST_METHOD'] === 'GET') {
unset($config['system']['ipv6duid']);
/* clear the file as this means auto-generate */
@unlink('/var/db/dhcp6c_duid');
+ @unlink('/conf/dhcp6c_duid');
}
$savemsg = get_std_save_message();
write_config();
+ interface_dhcpv6_configure('duidonly', null); /* XXX refactor */
system_arp_wrong_if();
}
}
@@ -184,9 +261,7 @@ include("head.inc");
?>
-
-
-
+
@@ -271,22 +346,35 @@ include("head.inc");
=gettext("DHCP Unique Identifier"); ?>
-
+
+
+
+
+ = gettext('Insert the existing DUID') ?>
+ = gettext('Insert a new LLT DUID') ?>
+ = gettext('Insert a new LL DUID') ?>
+ = gettext('Insert a new UUID DUID') ?>
+ = gettext('Clear the existing DUID') ?>
-
-
-
-
- " />
-
-
-
- =gettext("This will take effect after you reboot the machine or re-configure each interface.");?>
-
-
+ = gettext('This field can be used to enter an explicit DUID for use by IPv6 DHCP clients.') ?>
+ = gettext('The correct format for each DUID type is as follows, all entries to be in hex format "xx" separated by a colon.') ?>
+ = gettext('LLT: 4 bytes "00:01:00:01" followed by 4 bytes Unix time e.g. "00:01:02:03", followed by six bytes of the MAC address.') ?>
+ = gettext('LL: 4 bytes "00:03:00:01" followed by 4 bytes Unix time e.g. "00:01:02:03".') ?>
+ = gettext('UUID: 4 bytes "00:00:00:04" followed by 8 bytes of a universally unique identifier.') ?>
+ = gettext('EN: 2 bytes "00:02" followed by 4 bytes of the enterprise number e.g. "00:00:00:01", ' .
+ 'followed by a variable length identifier of hex values up to 122 bytes in length.') ?>
+
+
+
+
+
+ = gettext('Save') ?>
+
+
+
+ = gettext('This will take effect after you reboot the machine or reconfigure each interface.') ?>
+
+
@@ -294,6 +382,6 @@ include("head.inc");
+