diff options
-rw-r--r-- | etc/inc/interfaces.inc | 121 | ||||
-rw-r--r-- | etc/inc/system.inc | 20 | ||||
-rwxr-xr-x | etc/rc.newwanipv6 | 42 | ||||
-rwxr-xr-x | sbin/dhclient6-script | 244 |
4 files changed, 316 insertions, 111 deletions
diff --git a/etc/inc/interfaces.inc b/etc/inc/interfaces.inc index 9a23e20..5d831fd 100644 --- a/etc/inc/interfaces.inc +++ b/etc/inc/interfaces.inc @@ -37,7 +37,7 @@ pfSense_BUILDER_BINARIES: /sbin/dhclient /bin/sh /usr/bin/grep /usr/bin/xargs /usr/bin/awk /usr/local/sbin/choparp pfSense_BUILDER_BINARIES: /sbin/ifconfig /sbin/route /usr/sbin/ngctl /usr/sbin/arp /bin/kill /usr/local/sbin/mpd5 - pfSense_BUILDER_BINARIES: /usr/local/sbin/dhcp6c + pfSense_BUILDER_BINARIES: /usr/local/sbin/dhclient pfSense_MODULE: interfaces */ @@ -2642,7 +2642,7 @@ function find_dhclient_process($interface) { function find_dhcp6c_process($interface) { if ($interface) - $pid = `/bin/ps auxw|grep "[d]hcp6c" |grep "{$interface}"|awk '{print $2}'`; + $pid = `/bin/ps auxww|grep "[d]hclient[ ]-6" |grep "{$interface}"|awk '{print $2}'`; else return(false); @@ -3078,10 +3078,21 @@ function interface_track6_dhcp6_configure($interface = "lan") { if (empty($wancfg)) $wancfg = array(); + $realwanif = get_real_interface($wanif); + if(is_readable("{$g['vardb_path']}/{$realwanif}_pd_ipv6")) { + $ifcfgipv6pfx = file_get_contents("{$g['vardb_path']}/{$realwanif}_pd_ipv6"); + } else { + log_error("No DHCP-PD delegated prefix found, exiting"); + return false; + } + + log_error("Delegated IPv6 prefix is {$ifcfgipv6pfx}"); + $ifcfgipv6pfxarr = explode("/", $ifcfgipv6pfx); + $ifcfgipv6 = $ifcfgipv6pfxarr[0]; - $ifcfgipv6 = find_interface_ipv6($lanif); if(is_ipaddrv6($ifcfgipv6)) { $dhcp6lanarr = explode(":", Net_IPv6::uncompress($ifcfgipv6)); + /* we need to fold the $lancfg['track6-prefix-id'] into this address */ $dhcp6lanarr[4] = 0; $dhcp6lanarr[5] = 0; $dhcp6lanarr[6] = 0; @@ -3089,6 +3100,8 @@ function interface_track6_dhcp6_configure($interface = "lan") { $dhcp6lan = Net_IPv6::compress(implode(":", $dhcp6lanarr)); log_error("dhcp6 {$interface} with ipv6 address {$dhcp6lan} based on {$lancfg['track6-interface']}"); mwexec("/sbin/ifconfig {$lanif} inet6 {$dhcp6lan} prefixlen 64"); + } else { + log_error("The DHCP-PD interface {$interface} address {$ifcfgipv6} is not a valid IPv6 address"); } return 0; } @@ -3287,105 +3300,49 @@ function interface_dhcpv6_configure($interface = "wan") { $wanif = get_real_interface($interface); - /* Add ISC IPv6 dhclient here, only wide-dhcp6c works for now. */ + /* Add ISC IPv6 dhclient here */ $fd = fopen("{$g['varetc_path']}/dhcp6c_{$interface}.conf", "w"); if (!$fd) { printf("Error: cannot open dhcp6c_{$interface}.conf in interface_dhcpv6_configure() for writing.\n"); return 1; } - $dhcp6cconf = ""; - $dhcp6cconf .= "interface {$wanif} {\n"; + $dhcp6cconf = "interface \"{$wanif}\" {\n"; + $dhcp6cconf .= "script \"/sbin/dhclient6-script\";\n"; + $dhcp6cconf .= "}\n"; - /* for SLAAC interfaces we do fire off a dhcp6 client for just our name servers */ - if($wancfg['ipaddrv6'] == "slaac") { - $dhcp6cconf .= " information-only;\n"; - $dhcp6cconf .= " request domain-name-servers;\n"; - $dhcp6cconf .= " request domain-name;\n"; - $dhcp6cconf .= " script \"{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\"; # we'd like some nameservers please\n"; - $dhcp6cconf .= "};\n"; - } else { - - $dhcp6cconf .= " send ia-na 0; # request stateful address\n"; - if(is_numeric($wancfg['dhcp6-ia-pd-len'])) { - $dhcp6cconf .= " send ia-pd 0; # request prefix delegation\n"; - } - $dhcp6cconf .= "request domain-name-servers;\n"; - $dhcp6cconf .= "request domain-name;\n"; - $dhcp6cconf .= "script \"{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\"; # we'd like some nameservers please\n"; - - $dhcp6cconf .= "};\n"; - $dhcp6cconf .= "id-assoc na 0 { };\n"; - if(is_numeric($wancfg['dhcp6-ia-pd-len'])) { - /* Setup the prefix delegation */ - $dhcp6cconf .= "id-assoc pd 0 {\n"; - foreach($iflist as $friendly => $ifdescr) { - if($config['interfaces'][$friendly]['track6-interface'] != $interface) - continue; - if(is_numeric($config['interfaces'][$friendly]['track6-prefix-id'])) { - log_error("setting up $friendly - {$config['interfaces'][$friendly]['track6-prefix-id']}"); - $realif = get_real_interface($friendly); - $dhcp6cconf .= " prefix-interface {$realif} {\n"; - $dhcp6cconf .= " sla-id {$config['interfaces'][$friendly]['track6-prefix-id']};\n"; - $dhcp6cconf .= " sla-len {$wancfg['dhcp6-ia-pd-len']};\n"; - $dhcp6cconf .= " };\n"; - } - } - $dhcp6cconf .= "};\n"; - } - } fwrite($fd, $dhcp6cconf); fclose($fd); - /* Add wide-dhcp6c shell script here. Because we can not pass a argument to it. */ - $fds = fopen("{$g['varetc_path']}/dhcp6c_{$interface}_script.sh", "w"); - if (!$fds) { - printf("Error: cannot open dhcp6c_{$interface}_script.sh in interface_dhcpv6_configure() for writing.\n"); - return 1; - } - $dhcp6cscript = "#!/bin/sh\n"; - $dhcp6cscript .= "# This shell script launches /etc/rc.newwanipv6 with a interface argument.\n"; - $dhcp6cscript .= "/etc/rc.newwanipv6 $interface \n"; - - fwrite($fds, $dhcp6cscript); - fclose($fds); - chmod("{$g['varetc_path']}/dhcp6c_{$interface}_script.sh", 0755); - - /* accept router advertisements for this interface */ mwexec("/sbin/sysctl -w net.inet6.ip6.accept_rtadv=1"); log_error("Accept router advertisements on interface {$wanif} "); mwexec("/sbin/ifconfig {$wanif} inet6 accept_rtadv"); /* run a filter configure so that the filter rules allow traffic before we launch the client */ - filter_configure(); + filter_configure_sync(); sleep(3); - /* fire up dhcp6c for IPv6 first, this backgrounds immediately */ - mwexec("/usr/local/sbin/dhcp6c -d -c {$g['varetc_path']}/dhcp6c_{$interface}.conf {$wanif}"); - sleep(1); - exec("/sbin/rtsol -d {$wanif} 2>&1", $out, $ret); - if(!empty($out)) { - foreach($out as $line) { - if((stristr($line, "received")) && (!stristr($line, "unexpected"))) { - $parts = explode(" ", $line); - if(is_ipaddrv6($parts[3])) { - log_error("Found IPv6 default gateway '{$parts[3]}' by RA."); - file_put_contents("{$g['tmp_path']}/{$wanif}_routerv6", "{$parts[3]}\n"); - file_put_contents("{$g['tmp_path']}/{$wanif}_defaultgwv6", "{$parts[3]}\n"); - break; - } - } - } + /* dhclient -6 + * -T temprorary address + * -S information only + * -P Prefix + * -N request address with temporary or prefix + */ + + $dhcp6c_options = ""; + if($wancfg['ipaddrv6'] == "slaac") { + $dhcp6c_options .= "-S "; } - /* worst case is that the rc.newwanipv6 handles setting up the track6 interface */ - if($wancfg['ippaddrv6'] != "slaac") { - /* configure dependent interfaces */ - foreach($iflist as $if => $ifname) { - if($config['interfaces'][$if]['track6-interface'] == $interface) - interface_track6_configure($if); - } + if($wancfg['ipaddrv6'] == "dhcp6") { + $dhcp6c_options .= "-N "; + } + if(is_numeric($wancfg['dhcp6-ia-pd-len'])) { + $dhcp6c_options .= "-P "; } + /* fire up dhcp6c for IPv6 first, this backgrounds immediately */ + mwexec("/usr/local/sbin/dhclient -6 {$dhcp6c_options} -cf {$g['varetc_path']}/dhcp6c_{$interface}.conf -lf {$g['varetc_path']}/dhcp6c_{$interface}.leases -pf {$g['varrun_path']}/dhcp6c_{$interface}.pid {$wanif}"); + sleep(5); return 0; } diff --git a/etc/inc/system.inc b/etc/inc/system.inc index 2e3b44f..76f2c39 100644 --- a/etc/inc/system.inc +++ b/etc/inc/system.inc @@ -1672,4 +1672,24 @@ function get_possible_listen_ips() { return $listenips; } +/* Pick up IPv6 router advertisements on the interface */ +function pickup_ipv6_router_advertisement($interface) { + global $g; + $realif = get_real_interface($interface); + exec("/sbin/rtsol -d {$realif} 2>&1", $out, $ret); + if(!empty($out)) { + foreach($out as $line) { + if((stristr($line, "received")) && (!stristr($line, "unexpected"))) { + $parts = explode(" ", $line); + if(is_ipaddrv6($parts[3])) { + log_error("Found IPv6 default gateway '{$parts[3]}' on interface {$realif} by RA."); + file_put_contents("{$g['tmp_path']}/{$realif}_routerv6", "{$parts[3]}\n"); + file_put_contents("{$g['tmp_path']}/{$realif}_defaultgwv6", "{$parts[3]}\n"); + break; + } + } + } + } +} + ?> diff --git a/etc/rc.newwanipv6 b/etc/rc.newwanipv6 index e09b4c7..cc1927e 100755 --- a/etc/rc.newwanipv6 +++ b/etc/rc.newwanipv6 @@ -49,15 +49,6 @@ if($g['booting']) exit; -// echo print_r($_ENV, true); -/*Array -( - [REASON] => NBI - [new_domain_name_servers] => 2001:470:20::2 - [new_domain_name] => domain.nl. -) -*/ - function restart_packages() { global $oldip, $curwanipv6, $g; @@ -70,24 +61,16 @@ function restart_packages() { log_error("rc.newwanipv6: Informational is starting."); -/* FIXME: how can we find out about the correct interface name? */ -/* switch to ISC dhcp6 client? */ -$curwanipv6 = get_interface_ipv6(); -$interface = "wan"; -$interface_real = get_real_interface(); - -$name_servers = explode(" ", $_ENV['new_domain_name_servers']); -$valid_ns = array(); -foreach($name_servers as $ns) { - if(is_ipaddrv6(trim($ns))) - $valid_ns[] = trim($ns); -} -if(count($valid_ns > 0)) - file_put_contents("{$g['varetc_path']}/nameserver_v6{$interface}", implode("\n", $valid_ns)); +/* Interface IP address has changed */ +$argument = str_replace("\n", "", $argv[1]); -if(!empty($_ENV['new_domain_name'])) { - file_put_contents("{$g['varetc_path']}/searchdomain_v6{$interface}", $_ENV['new_domain_name']); -} +if($argument != "") + $interface = convert_real_interface_to_friendly_interface_name($argument); +else + $interface = "wan"; + +$interface_real = get_real_interface($interface); +$curwanipv6 = get_interface_ipv6($interface_real); log_error("rc.newwanipv6: on (IP address: {$curwanipv6}) (interface: {$interface}) (real interface: {$interface_real})."); @@ -117,6 +100,10 @@ system_resolvconf_generate(true); /* write current WAN IPv6 to file */ file_put_contents("{$g['vardb_path']}/{$interface}_ipv6", $curwanipv6); +/* pickup ipv6 router advertisements */ +pickup_ipv6_router_advertisement($interface_real); +sleep(3); + /* check native IPv6 interface tracking */ switch($config['interfaces'][$interface]['ipaddrv6']) { case "dhcp6": @@ -158,9 +145,6 @@ services_dnsupdate_process($interface); /* signal dyndns update */ services_dyndns_configure($interface); -/* wait for the dhcp6c process to configure the LAN interface */ -sleep(5); - /* reconfigure IPsec tunnels */ vpn_ipsec_force_reload(); diff --git a/sbin/dhclient6-script b/sbin/dhclient6-script new file mode 100755 index 0000000..f0f2ffa --- /dev/null +++ b/sbin/dhclient6-script @@ -0,0 +1,244 @@ +#!/bin/sh +# $Id$ +# $OpenBSD: dhclient-script,v 1.6 2004/05/06 18:22:41 claudio Exp $ +# $FreeBSD: src/sbin/dhclient/dhclient-script,v 1.4 2005/06/10 03:41:18 brooks Exp $ +# +# Copyright (c) 2003 Kenneth R Westerback <krw@openbsd.org> +# +# Permission to use, copy, modify, and distribute this software for any +# purpose with or without fee is hereby granted, provided that the above +# copyright notice and this permission notice appear in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +# + +NETSTAT=/usr/bin/netstat +GREP=/usr/bin/grep +AWK=/usr/bin/awk +HOSTNAME=/bin/hostname +GREP=/usr/bin/grep +ROUTE=/sbin/route +SED=/usr/bin/sed +ARP=/usr/sbin/arp +IFCONFIG=/sbin/ifconfig + +LOCALHOST=::1 + +if [ -x /usr/bin/logger ]; then + LOGGER="/usr/bin/logger -s -p user.notice -t dhclient6" +else + LOGGER=echo +fi + +# +# Helper functions that implement common actions. +# + +check_hostname() { + current_hostname=`$HOSTNAME` + if [ -z "$current_hostname" ]; then + $LOGGER "New Hostname ($interface): $new_host_name" + $HOSTNAME $new_host_name + elif [ "$current_hostname" = "$old_host_name" -a \ + "$new_host_name" != "$old_host_name" ]; then + $LOGGER "New Hostname ($interface): $new_host_name" + $HOSTNAME $new_host_name + fi +} + +delete_old_states() { + $LOGGER "Starting delete_old_states()" + # If the IP changed, remove states from the old one + if [ -f /var/db/${interface}_ipv6 ]; then + OLD_IPv6 = `cat /var/db/${interface}_ipv6` + $LOGGER "Comparing IPv6s: Old: ${OLD_IPv6} New: ${new_ip6_address}" + if [ -n "${OLD_IPv6}" ] && [ "${OLD_IPv6}" != "${new_ip6_address}" ]; then + $LOGGER "Removing states from old IPv6 '${OLD_IPv6}' (new IP '${new_ip6_address}')" + /sbin/pfctl -k :: -k ${OLD_IPv6}/128 + /sbin/pfctl -k ${OLD_IPv6}/128 + pfctl -K ${OLD_IPv6}/128 + fi + fi + # Delete states through old gateway if it's not the same + # FIXME: dhcp6 doesn't know about routers. Needs fixing elsewhere. +} + +delete_old_address() { + /bin/rm -f /var/db/${interface}_ipv6 + $IFCONFIG $interface inet6 -alias $old_ip6_address +} + +add_new_address() { + if [ -z $new_ip6_address ]; then + return; + fi + + $LOGGER "Starting add_new_address()" + $LOGGER "ifconfig $interface inet6 $new_ip6_address prefixlen $new_ip6_prefixlen" + $IFCONFIG $interface \ + inet6 $new_ip6_address \ + prefixlen $new_ip6_prefixlen + + $LOGGER "New IPv6 Address ($interface): $new_ip6_address" + $LOGGER "New Prefix Length ($interface): $new_ip6_prefixlen" + + echo $new_ip6_address > /var/db/${interface}_ipv6 +} + +add_new_prefix() { + if [ -z $new_ip6_prefix ]; then + return + fi + $LOGGER "Starting add_new_prefix()" + echo $new_ip6_prefix > /var/db/${interface}_pd_ipv6 +} + +delete_old_prefix() { + if [ -z $old_ip6_prefix ]; then + return + fi + $LOGGER "Starting delete_old_prefix()" + rm -f /var/db/${interface}_pd_ipv6 +} + +delete_old_alias() { + if [ -n "$alias_ip6_address" ]; then + $IFCONFIG $interface inet6 -alias $alias_ip6_address > /dev/null 2>&1 + $ROUTE delete -inet6 $alias_ip6_address $LOCALHOST > /dev/null 2>&1 + fi +} + +add_new_alias() { + if [ -n "$alias_ip6_address" ]; then + $IFCONFIG $interface inet6 alias $alias_ip6_address prefixlen $new_ip6_prefixlen + $ROUTE add -inet6 $alias_ip6_address $LOCALHOST + fi +} + +add_new_resolv_conf() { + $LOGGER "Creating resolv.conf" + if [ -f "/var/etc/nameserver_v6$interface" ]; then + # Remove old entries + for nameserver in `cat /var/etc/nameserver_v6$interface`; do + $ROUTE delete -inet6 $nameserver >/dev/null 2>&1 + done + fi + if [ -n "$new_dhcp6_name_servers" ]; then + /bin/rm -f /var/etc/nameserver_v6$interface + ALLOWOVERRIDE=`/usr/bin/grep dnsallowoverride /conf/config.xml | /usr/bin/wc -l` + for nameserver in $new_dhcp6_name_servers; do + # Add a route to the nameserver out the correct interface + # so that mulitple wans work correctly with multiple dns + # also backup the nameserver for later route removal + if [ $ALLOWOVERRIDE -gt 0 ]; then + echo $nameserver >>/var/etc/nameserver_v6$interface + $ROUTE add -inet6 $nameserver -iface $interface + fi + done + echo $new_dhcp6_domain_search >/var/etc/searchdomain_v6$interface + fi + + return 0 +} + +# Notify rc.newwanip of changes to an interface +notify_rc_newwanipv6() { + /etc/rc.newwanipv6 $interface + # /usr/local/sbin/pfSctl -c "interface newipv6 $interface" +} + +# +# Start of active code. +# + +# Invoke the local dhcp client enter hooks, if they exist. +if [ -f /etc/dhclient-enter-hooks ]; then + $LOGGER "dhclient-enter-hooks" + exit_status=0 + . /etc/dhclient-enter-hooks + # allow the local script to abort processing of this state + # local script must set exit_status variable to nonzero. + if [ $exit_status -ne 0 ]; then + exit $exit_status + fi +fi + +$LOGGER $reason +case $reason in +PREINIT6) + delete_old_alias + delete_old_prefix + $IFCONFIG $interface inet6 up + delete_old_states + ;; + +BOUND6|RENEW6|REBIND6|REBOOT6) + + set + check_hostname + changes="no" + if [ "$old_ip6_address" != "$new_ip6_address" ]; then + delete_old_states + fi + if [ -n "$old_ip6_address" ]; then + if [ "$old_ip6_address" != "$alias_ip6_address" ]; then + delete_old_alias + changes="yes" + fi + fi + if [ "$old_ip6_prefix" != "$new_ip6_prefix" ]; then + delete_old_prefix + changes="yes" + fi + if [ "$reason" = BOUND6 ] || \ + [ "$reason" = REBOOT6 ] || \ + [ "$reason" = REBIND6 ] || \ + [ -z "$old_ip6_address" ] || \ + [ "$old_ip6_address" || "$new_ip6_address" ]; then + add_new_address + add_new_prefix + changes="yes" + fi + if [ -n "$alias_ip6_address" ] && \ + [ "$new_ip6_address" != "$alias_ip6_address" ]; then + add_new_alias + changes="yes" + fi + add_new_resolv_conf + if [ "$changes" = "yes" ] ; then + notify_rc_newwanipv6 + fi + ;; + +EXPIRE6|FAIL6) + delete_old_alias + delete_old_states + if [ -n "$old_ip6_address" ]; then + delete_old_address + fi + ;; + +TIMEOUT6) + delete_old_alias + add_new_address + /bin/sleep 1 + $IFCONFIG $interface inet6 -alias $new_ip6_address $medium + delete_old_states + ;; +esac + +# Invoke the local dhcp client exit hooks, if they exist. +if [ -f /etc/dhclient-exit-hooks ]; then + $LOGGER "dhclient-exit-hooks" + exit_status=0 + . /etc/dhclient-exit-hooks + # allow the local script to abort processing of this state + # local script must set exit_status variable to nonzero. + exit $exit_status +fi |