interfaces: multiple type DHCP DUID support and generation; closes #2602

This commit is contained in:
marjohn56 2018-08-04 16:50:11 +01:00 committed by Franco Fichtner
parent 928222e747
commit d46d2a6edc
2 changed files with 137 additions and 47 deletions

View File

@ -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 */

View File

@ -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");
?>
<body>
<?php include("fbegin.inc"); ?>
<!-- row -->
<?php include("fbegin.inc"); ?>
<section class="page-content-main">
<div class="container-fluid">
<div class="row">
@ -271,22 +346,35 @@ include("head.inc");
<tr>
<td><a id="help_for_persistent_duid" href="#" class="showhelp"><i class="fa fa-info-circle"></i></a> <?=gettext("DHCP Unique Identifier"); ?></td>
<td>
<input name="ipv6duid" type="text" id="ipv6duid" value="<?=htmlspecialchars($pconfig['ipv6duid']);?>" />
<textarea name="ipv6duid" id="ipv6duid" rows="2" ><?=$pconfig['ipv6duid'];?></textarea>
<input name="ipv6_duid_llt_value" type="hidden" value="<?= html_safe($pconfig['ipv6_duid_llt_value']) ?>">
<input name="ipv6_duid_ll_value" type="hidden" value="<?= html_safe($pconfig['ipv6_duid_ll_value']) ?>">
<input name="ipv6_duid_uuid_value" type="hidden" value="<?= html_safe($pconfig['ipv6_duid_uuid_value']) ?>">
<a onclick="$('#ipv6duid').val('<?= html_safe($duid) ?>');" href="#"><?= gettext('Insert the existing DUID') ?></a><br/>
<a onclick="$('#ipv6duid').val('<?= html_safe($pconfig['ipv6_duid_llt_value']) ?>');" href="#"><?= gettext('Insert a new LLT DUID') ?></a><br/>
<a onclick="$('#ipv6duid').val('<?= html_safe($pconfig['ipv6_duid_ll_value']) ?>');" href="#"><?= gettext('Insert a new LL DUID') ?></a><br/>
<a onclick="$('#ipv6duid').val('<?= html_safe($pconfig['ipv6_duid_uuid_value']) ?>');" href="#"><?= gettext('Insert a new UUID DUID') ?></a><br/>
<a onclick="$('#ipv6duid').val('');" href="#"><?= gettext('Clear the existing DUID') ?></a><br/>
<div class="hidden" data-for="help_for_persistent_duid">
<?= gettext('This field can be used to enter an explicit DUID for use by IPv6 DHCP clients.') ?><br />
<a onclick="$('#ipv6duid').val('<?= html_safe($duid) ?>');" href="#"><?=gettext("Insert the existing DUID here"); ?></a>
</div>
</td>
</tr>
<tr>
<td>&nbsp;</td>
<td><input name="Submit" type="submit" class="btn btn-primary" value="<?=gettext("Save");?>" /></td>
</tr>
<tr>
<td colspan="2">
<?=gettext("This will take effect after you reboot the machine or re-configure each interface.");?>
</td>
</tr>
<?= gettext('This field can be used to enter an explicit DUID for use by IPv6 DHCP clients.') ?><br/>
<?= gettext('The correct format for each DUID type is as follows, all entries to be in hex format "xx" separated by a colon.') ?><br/>
<?= 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.') ?><br/>
<?= gettext('LL: 4 bytes "00:03:00:01" followed by 4 bytes Unix time e.g. "00:01:02:03".') ?><br/>
<?= gettext('UUID: 4 bytes "00:00:00:04" followed by 8 bytes of a universally unique identifier.') ?><br/>
<?= 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.') ?>
</div>
</td>
</tr>
<tr>
<td>&nbsp;</td>
<td><button name="submit" type="submit" class="btn btn-primary" value="yes"><?= gettext('Save') ?></button></td>
</tr>
<tr>
<td colspan="2">
<?= gettext('This will take effect after you reboot the machine or reconfigure each interface.') ?>
</td>
</tr>
</table>
</form>
</div>
@ -294,6 +382,6 @@ include("head.inc");
</div>
</div>
</section>
<?php
<?php include("foot.inc");
include("foot.inc");