From 46bc6e545a17e77202aaf01ec0cd8d5a46567525 Mon Sep 17 00:00:00 2001 From: Renato Botelho Date: Tue, 25 Aug 2015 08:08:24 -0300 Subject: Move main pfSense content to src/ --- src/etc/inc/services.inc | 2541 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 2541 insertions(+) create mode 100644 src/etc/inc/services.inc (limited to 'src/etc/inc/services.inc') diff --git a/src/etc/inc/services.inc b/src/etc/inc/services.inc new file mode 100644 index 0000000..c254c35 --- /dev/null +++ b/src/etc/inc/services.inc @@ -0,0 +1,2541 @@ +. + Copyright (C) 2010 Ermal Luçi + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. +*/ + +/* + pfSense_BUILDER_BINARIES: /usr/bin/killall /bin/pgrep /bin/sh /usr/local/sbin/dhcpd /usr/local/sbin/igmpproxy + pfSense_BUILDER_BINARIES: /sbin/ifconfig /usr/local/sbin/dnsmasq + pfSense_BUILDER_BINARIES: /usr/local/sbin/miniupnpd /usr/sbin/radvd + pfSense_BUILDER_BINARIES: /usr/local/sbin/dhcleases6 /usr/sbin/bsnmpd + pfSense_MODULE: utils +*/ + +define('DYNDNS_PROVIDER_VALUES', 'citynetwork cloudflare custom custom-v6 dhs dnsexit dnsimple dnsmadeeasy dnsomatic dyndns dyndns-custom dyndns-static dyns easydns eurodns freedns glesys googledomains gratisdns he-net he-net-v6 he-net-tunnelbroker loopia namecheap noip noip-free ods opendns ovh-dynhost route53 selfhost zoneedit'); +define('DYNDNS_PROVIDER_DESCRIPTIONS', 'City Network,CloudFlare,Custom,Custom (v6),DHS,DNSexit,DNSimple,DNS Made Easy,DNS-O-Matic,DynDNS (dynamic),DynDNS (custom),DynDNS (static),DyNS,easyDNS,Euro Dns,freeDNS,GleSYS,Google Domains,GratisDNS,HE.net,HE.net (v6),HE.net Tunnelbroker,Loopia,Namecheap,No-IP,No-IP (free),ODS.org,OpenDNS,OVH DynHOST,Route 53,SelfHost,ZoneEdit'); + +/* implement ipv6 route advertising daemon */ +function services_radvd_configure($blacklist = array()) { + global $config, $g; + + if (isset($config['system']['developerspew'])) { + $mt = microtime(); + echo "services_radvd_configure() being called $mt\n"; + } + + if (!is_array($config['dhcpdv6'])) { + $config['dhcpdv6'] = array(); + } + + $Iflist = get_configured_interface_list(); + $Iflist = array_merge($Iflist, get_configured_pppoe_server_interfaces()); + $carplist = get_configured_carp_interface_list(); + + $radvdconf = "# Automatically Generated, do not edit\n"; + + /* Process all links which need the router advertise daemon */ + $radvdifs = array(); + + /* handle manually configured DHCP6 server settings first */ + foreach ($config['dhcpdv6'] as $dhcpv6if => $dhcpv6ifconf) { + if (!is_array($config['interfaces'][$dhcpv6if])) { + continue; + } + if (!isset($config['interfaces'][$dhcpv6if]['enable'])) { + continue; + } + + /* Do not put in the config an interface which is down */ + if (isset($blacklist[$dhcpv6if])) { + continue; + } + if (!isset($dhcpv6ifconf['ramode'])) { + $dhcpv6ifconf['ramode'] = $dhcpv6ifconf['mode']; + } + + /* are router advertisements enabled? */ + if ($dhcpv6ifconf['ramode'] == "disabled") { + continue; + } + + if (!isset($dhcpv6ifconf['rapriority'])) { + $dhcpv6ifconf['rapriority'] = "medium"; + } + + /* always start with the real parent, we override with the carp if later */ + $carpif = false; + /* check if we need to listen on a CARP interface */ + if (!empty($dhcpv6ifconf['rainterface'])) { + if (!empty($carplist[$dhcpv6ifconf['rainterface']])) { + $dhcpv6if = $dhcpv6ifconf['rainterface']; + $carpif = true; + } + } + + if (strstr($dhcpv6if, "_vip")) { + // CARP IP, check if it's enabled and find parent + if (!get_carp_status() || get_carp_interface_status($dhcpv6if) != "MASTER") { + continue; + } + $ifparent = link_carp_interface_to_parent($dhcpv6if); + $realif = convert_friendly_interface_to_real_interface_name($ifparent); + } else { + $realif = get_real_interface($dhcpv6if, "inet6"); + } + + if (isset($radvdifs[$realif])) { + continue; + } + + $ifcfgipv6 = get_interface_ipv6($dhcpv6if); + if (!is_ipaddrv6($ifcfgipv6)) { + continue; + } + + $ifcfgsnv6 = get_interface_subnetv6($dhcpv6if); + $subnetv6 = gen_subnetv6($ifcfgipv6, $ifcfgsnv6); + $radvdifs[$realif] = $realif; + + $radvdconf .= "# Generated for DHCPv6 Server $dhcpv6if\n"; + $radvdconf .= "interface {$realif} {\n"; + if (strstr($realif, "ovpn")) { + $radvdconf .= "\tUnicastOnly on;\n"; + } + $radvdconf .= "\tAdvSendAdvert on;\n"; + $radvdconf .= "\tMinRtrAdvInterval 5;\n"; + $radvdconf .= "\tMaxRtrAdvInterval 20;\n"; + $mtu = get_interface_mtu($realif); + if (is_numeric($mtu)) { + $radvdconf .= "\tAdvLinkMTU {$mtu};\n"; + } else { + $radvdconf .= "\tAdvLinkMTU 1280;\n"; + } + // $radvdconf .= "\tDeprecatePrefix on;\n"; + switch ($dhcpv6ifconf['rapriority']) { + case "low": + $radvdconf .= "\tAdvDefaultPreference low;\n"; + break; + case "high": + $radvdconf .= "\tAdvDefaultPreference high;\n"; + break; + default: + $radvdconf .= "\tAdvDefaultPreference medium;\n"; + break; + } + switch ($dhcpv6ifconf['ramode']) { + case "managed": + case "assist": + $radvdconf .= "\tAdvManagedFlag on;\n"; + $radvdconf .= "\tAdvOtherConfigFlag on;\n"; + break; + case "stateless_dhcp": + $radvdconf .= "\tAdvManagedFlag off;\n"; + $radvdconf .= "\tAdvOtherConfigFlag on;\n"; + break; + } + $radvdconf .= "\tprefix {$subnetv6}/{$ifcfgsnv6} {\n"; + if ($carpif == true) { + $radvdconf .= "\t\tDeprecatePrefix off;\n"; + } else { + $radvdconf .= "\t\tDeprecatePrefix on;\n"; + } + switch ($dhcpv6ifconf['ramode']) { + case "managed": + $radvdconf .= "\t\tAdvOnLink on;\n"; + $radvdconf .= "\t\tAdvAutonomous off;\n"; + $radvdconf .= "\t\tAdvRouterAddr on;\n"; + break; + case "router": + $radvdconf .= "\t\tAdvOnLink off;\n"; + $radvdconf .= "\t\tAdvAutonomous off;\n"; + $radvdconf .= "\t\tAdvRouterAddr on;\n"; + break; + case "stateless_dhcp": + case "assist": + $radvdconf .= "\t\tAdvOnLink on;\n"; + $radvdconf .= "\t\tAdvAutonomous on;\n"; + $radvdconf .= "\t\tAdvRouterAddr on;\n"; + break; + case "unmanaged": + $radvdconf .= "\t\tAdvOnLink on;\n"; + $radvdconf .= "\t\tAdvAutonomous on;\n"; + $radvdconf .= "\t\tAdvRouterAddr on;\n"; + break; + } + $radvdconf .= "\t};\n"; + + if (is_array($dhcpv6ifconf['subnets']['item'])) { + foreach ($dhcpv6ifconf['subnets']['item'] as $subnet) { + if (is_subnetv6($subnet)) { + $radvdconf .= "\tprefix {$subnet} {\n"; + if ($carpif == true) { + $radvdconf .= "\t\tDeprecatePrefix off;\n"; + } else { + $radvdconf .= "\t\tDeprecatePrefix on;\n"; + } + switch ($dhcpv6ifconf['ramode']) { + case "managed": + $radvdconf .= "\t\tAdvOnLink on;\n"; + $radvdconf .= "\t\tAdvAutonomous off;\n"; + $radvdconf .= "\t\tAdvRouterAddr on;\n"; + break; + case "router": + $radvdconf .= "\t\tAdvOnLink off;\n"; + $radvdconf .= "\t\tAdvAutonomous off;\n"; + $radvdconf .= "\t\tAdvRouterAddr on;\n"; + break; + case "assist": + $radvdconf .= "\t\tAdvOnLink on;\n"; + $radvdconf .= "\t\tAdvAutonomous on;\n"; + $radvdconf .= "\t\tAdvRouterAddr on;\n"; + break; + case "unmanaged": + $radvdconf .= "\t\tAdvOnLink on;\n"; + $radvdconf .= "\t\tAdvAutonomous on;\n"; + $radvdconf .= "\t\tAdvRouterAddr on;\n"; + break; + } + $radvdconf .= "\t};\n"; + } + } + } + if ($carpif === true) { + $radvdconf .= "\troute ::/0 {\n"; + $radvdconf .= "\t\tRemoveRoute off;\n"; + $radvdconf .= "\t};\n"; + } else { + $radvdconf .= "\troute ::/0 {\n"; + $radvdconf .= "\t\tRemoveRoute on;\n"; + $radvdconf .= "\t};\n"; + } + + /* add DNS servers */ + $dnslist = array(); + if (isset($dhcpv6ifconf['rasamednsasdhcp6']) && is_array($dhcpv6ifconf['dnsserver']) && !empty($dhcpv6ifconf['dnsserver'])) { + foreach ($dhcpv6ifconf['dnsserver'] as $server) { + if (is_ipaddrv6($server)) { + $dnslist[] = $server; + } + } + } elseif (!isset($dhcpv6ifconf['rasamednsasdhcp6']) && isset($dhcpv6ifconf['radnsserver']) && is_array($dhcpv6ifconf['radnsserver'])) { + foreach ($dhcpv6ifconf['radnsserver'] as $server) { + if (is_ipaddrv6($server)) { + $dnslist[] = $server; + } + } + } elseif (isset($config['dnsmasq']['enable']) || isset($config['unbound']['enable'])) { + $dnslist[] = get_interface_ipv6($realif); + } elseif (is_array($config['system']['dnsserver']) && !empty($config['system']['dnsserver'])) { + foreach ($config['system']['dnsserver'] as $server) { + if (is_ipaddrv6($server)) { + $dnslist[] = $server; + } + } + } + if (count($dnslist) > 0) { + $dnsstring = implode(" ", $dnslist); + if ($dnsstring <> "") { + $radvdconf .= "\tRDNSS {$dnsstring} { };\n"; + } + } + if (!empty($dhcpv6ifconf['domain'])) { + $radvdconf .= "\tDNSSL {$dhcpv6ifconf['domain']} { };\n"; + } elseif (!empty($config['system']['domain'])) { + $radvdconf .= "\tDNSSL {$config['system']['domain']} { };\n"; + } + $radvdconf .= "};\n"; + } + + /* handle DHCP-PD prefixes and 6RD dynamic interfaces */ + foreach ($Iflist as $if => $ifdescr) { + if (!isset($config['interfaces'][$if]['track6-interface'])) { + continue; + } + if (!isset($config['interfaces'][$if]['enable'])) { + continue; + } + /* Do not put in the config an interface which is down */ + if (isset($blacklist[$if])) { + continue; + } + $trackif = $config['interfaces'][$if]['track6-interface']; + if (empty($config['interfaces'][$trackif])) { + continue; + } + + if (strstr($if, "_vip")) { + // CARP IP, find parent + $ifparent = link_carp_interface_to_parent($if); + $realif = convert_friendly_interface_to_real_interface_name($ifparent); + } else { + $realif = get_real_interface($if, "inet6"); + } + + /* prevent duplicate entries, manual overrides */ + if (isset($radvdifs[$realif])) { + continue; + } + + $ifcfgipv6 = get_interface_ipv6($if); + if (!is_ipaddrv6($ifcfgipv6)) { + $subnetv6 = "::"; + $ifcfgsnv6 = "64"; + } else { + $ifcfgsnv6 = get_interface_subnetv6($if); + $subnetv6 = gen_subnetv6($ifcfgipv6, $ifcfgsnv6); + } + $radvdifs[$realif] = $realif; + + $autotype = $config['interfaces'][$trackif]['ipaddrv6']; + + if ($g['debug']) { + log_error("configuring RA on {$if} for type {$autotype} radvd subnet {$subnetv6}/{$ifcfgsnv6}"); + } + + $radvdconf .= "# Generated config for {$autotype} delegation from {$trackif} on {$if}\n"; + $radvdconf .= "interface {$realif} {\n"; + $radvdconf .= "\tAdvSendAdvert on;\n"; + $radvdconf .= "\tMinRtrAdvInterval 3;\n"; + $radvdconf .= "\tMaxRtrAdvInterval 10;\n"; + $mtu = get_interface_mtu($realif); + if (is_numeric($mtu)) { + $radvdconf .= "\tAdvLinkMTU {$mtu};\n"; + } else { + $radvdconf .= "\tAdvLinkMTU 1280;\n"; + } + $radvdconf .= "\tAdvOtherConfigFlag on;\n"; + $radvdconf .= "\t\tprefix {$subnetv6}/{$ifcfgsnv6} {\n"; + $radvdconf .= "\t\tAdvOnLink on;\n"; + $radvdconf .= "\t\tAdvAutonomous on;\n"; + $radvdconf .= "\t\tAdvRouterAddr on;\n"; + $radvdconf .= "\t};\n"; + + /* add DNS servers */ + $dnslist = array(); + if (isset($config['dnsmasq']['enable']) || isset($config['unbound']['enable'])) { + $dnslist[] = $ifcfgipv6; + } elseif (is_array($config['system']['dnsserver']) && !empty($config['system']['dnsserver'])) { + foreach ($config['system']['dnsserver'] as $server) { + if (is_ipaddrv6($server)) { + $dnslist[] = $server; + } + } + } + if (count($dnslist) > 0) { + $dnsstring = implode(" ", $dnslist); + if (!empty($dnsstring)) { + $radvdconf .= "\tRDNSS {$dnsstring} { };\n"; + } + } + if (!empty($config['system']['domain'])) { + $radvdconf .= "\tDNSSL {$config['system']['domain']} { };\n"; + } + $radvdconf .= "};\n"; + } + + /* write radvd.conf */ + if (!@file_put_contents("{$g['varetc_path']}/radvd.conf", $radvdconf)) { + log_error("Error: cannot open radvd.conf in services_radvd_configure().\n"); + if (platform_booting()) { + printf("Error: cannot open radvd.conf in services_radvd_configure().\n"); + } + } + unset($radvdconf); + + if (count($radvdifs) > 0) { + if (isvalidpid("{$g['varrun_path']}/radvd.pid")) { + sigkillbypid("{$g['varrun_path']}/radvd.pid", "HUP"); + } else { + mwexec("/usr/local/sbin/radvd -p {$g['varrun_path']}/radvd.pid -C {$g['varetc_path']}/radvd.conf -m syslog"); + } + } else { + /* we need to shut down the radvd cleanly, it will send out the prefix + * information with a lifetime of 0 to notify clients of a (possible) new prefix */ + if (isvalidpid("{$g['varrun_path']}/radvd.pid")) { + log_error("Shutting down Router Advertisment daemon cleanly"); + killbypid("{$g['varrun_path']}/radvd.pid"); + @unlink("{$g['varrun_path']}/radvd.pid"); + } + } + return 0; +} + +function services_dhcpd_configure($family = "all", $blacklist = array()) { + global $config, $g; + + /* configure DHCPD chroot once */ + $fd = fopen("{$g['tmp_path']}/dhcpd.sh", "w"); + fwrite($fd, "/bin/mkdir -p {$g['dhcpd_chroot_path']}\n"); + fwrite($fd, "/bin/mkdir -p {$g['dhcpd_chroot_path']}/dev\n"); + fwrite($fd, "/bin/mkdir -p {$g['dhcpd_chroot_path']}/etc\n"); + fwrite($fd, "/bin/mkdir -p {$g['dhcpd_chroot_path']}/usr/local/sbin\n"); + fwrite($fd, "/bin/mkdir -p {$g['dhcpd_chroot_path']}/var/db\n"); + fwrite($fd, "/bin/mkdir -p {$g['dhcpd_chroot_path']}/var/run\n"); + fwrite($fd, "/bin/mkdir -p {$g['dhcpd_chroot_path']}/usr\n"); + fwrite($fd, "/bin/mkdir -p {$g['dhcpd_chroot_path']}/lib\n"); + fwrite($fd, "/bin/mkdir -p {$g['dhcpd_chroot_path']}/run\n"); + fwrite($fd, "/usr/sbin/chown -R dhcpd:_dhcp {$g['dhcpd_chroot_path']}/*\n"); + fwrite($fd, "/bin/cp -n /lib/libc.so.* {$g['dhcpd_chroot_path']}/lib/\n"); + fwrite($fd, "/bin/cp -n /usr/local/sbin/dhcpd {$g['dhcpd_chroot_path']}/usr/local/sbin/\n"); + fwrite($fd, "/bin/chmod a+rx {$g['dhcpd_chroot_path']}/usr/local/sbin/dhcpd\n"); + + $status = `/sbin/mount | /usr/bin/grep -v grep | /usr/bin/grep "{$g['dhcpd_chroot_path']}/dev"`; + if (!trim($status)) { + fwrite($fd, "/sbin/mount -t devfs devfs {$g['dhcpd_chroot_path']}/dev\n"); + } + fclose($fd); + mwexec("/bin/sh {$g['tmp_path']}/dhcpd.sh"); + + if ($family == "all" || $family == "inet") { + services_dhcpdv4_configure(); + } + if ($family == "all" || $family == "inet6") { + services_dhcpdv6_configure($blacklist); + services_radvd_configure($blacklist); + } +} + +function services_dhcpdv4_configure() { + global $config, $g; + $need_ddns_updates = false; + $ddns_zones = array(); + + if ($g['services_dhcp_server_enable'] == false) { + return; + } + + if (isset($config['system']['developerspew'])) { + $mt = microtime(); + echo "services_dhcpdv4_configure($if) being called $mt\n"; + } + + /* kill any running dhcpd */ + if (isvalidpid("{$g['dhcpd_chroot_path']}{$g['varrun_path']}/dhcpd.pid")) { + killbypid("{$g['dhcpd_chroot_path']}{$g['varrun_path']}/dhcpd.pid"); + } + + /* DHCP enabled on any interfaces? */ + if (!is_dhcp_server_enabled()) { + return 0; + } + + /* if OLSRD is enabled, allow WAN to house DHCP. */ + if (!function_exists('is_package_installed')) { + require_once('pkg-utils.inc'); + } + if (is_package_installed('olsrd') && isset($config['installedpackages']['olsrd'])) { + foreach ($config['installedpackages']['olsrd']['config'] as $olsrd) { + if (isset($olsrd['enable']) && $olsrd['enable'] == "on") { + $is_olsr_enabled = true; + break; + } + } + } + + if (platform_booting()) { + /* restore the leases, if we have them */ + if (file_exists("{$g['cf_conf_path']}/dhcpleases.tgz")) { + $dhcprestore = ""; + $dhcpreturn = ""; + exec("cd /;LANG=C /usr/bin/tar -xzf {$g['cf_conf_path']}/dhcpleases.tgz 2>&1", $dhcprestore, $dhcpreturn); + $dhcprestore = implode(" ", $dhcprestore); + if ($dhcpreturn <> 0) { + log_error(sprintf(gettext('DHCP leases restore failed exited with %1$s, the error is: %2$s%3$s'), $dhcpreturn, $dhcprestore, "\n")); + } + } + /* If this backup is still there on a full install, but we aren't going to use ram disks, remove the archive since this is a transition. */ + if (($g['platform'] == "pfSense") && !isset($config['system']['use_mfs_tmpvar'])) { + unlink_if_exists("{$g['cf_conf_path']}/dhcpleases.tgz"); + } + } + + $syscfg = $config['system']; + if (!is_array($config['dhcpd'])) { + $config['dhcpd'] = array(); + } + $dhcpdcfg = $config['dhcpd']; + $Iflist = get_configured_interface_list(); + + /* Only consider DNS servers with IPv4 addresses for the IPv4 DHCP server. */ + $dns_arrv4 = array(); + if (is_array($syscfg['dnsserver'])) { + foreach ($syscfg['dnsserver'] as $dnsserver) { + if (is_ipaddrv4($dnsserver)) { + $dns_arrv4[] = $dnsserver; + } + } + } + + if (platform_booting()) { + echo gettext("Starting DHCP service..."); + } else { + sleep(1); + } + + $custoptions = ""; + foreach ($dhcpdcfg as $dhcpif => $dhcpifconf) { + if (is_array($dhcpifconf['numberoptions']) && is_array($dhcpifconf['numberoptions']['item'])) { + foreach ($dhcpifconf['numberoptions']['item'] as $itemidx => $item) { + if (!empty($item['type'])) { + $itemtype = $item['type']; + } else { + $itemtype = "text"; + } + $custoptions .= "option custom-{$dhcpif}-{$itemidx} code {$item['number']} = {$itemtype};\n"; + } + } + } + + $dhcpdconf = << $dhcpifconf) { + + if (!isset($config['interfaces'][$dhcpif]['enable'])) { + continue; + } + + interfaces_staticarp_configure($dhcpif); + + if (!isset($dhcpifconf['enable'])) { + continue; + } + + if ($dhcpifconf['failover_peerip'] <> "") { + $intip = get_interface_ip($dhcpif); + /* + * yep, failover peer is defined. + * does it match up to a defined vip? + */ + $skew = 110; + if (is_array($config['virtualip']['vip'])) { + foreach ($config['virtualip']['vip'] as $vipent) { + if ($vipent['interface'] == $dhcpif) { + $carp_nw = gen_subnet($vipent['subnet'], $vipent['subnet_bits']); + if (ip_in_subnet($dhcpifconf['failover_peerip'], "{$carp_nw}/{$vipent['subnet_bits']}")) { + /* this is the interface! */ + if (is_numeric($vipent['advskew']) && (intval($vipent['advskew']) < 20)) { + $skew = 0; + break; + } + } + } + } + } else { + log_error(gettext("Warning! DHCP Failover setup and no CARP virtual IPs defined!")); + } + if ($skew > 10) { + $type = "secondary"; + $my_port = "520"; + $peer_port = "519"; + } else { + $my_port = "519"; + $peer_port = "520"; + $type = "primary"; + $dhcpdconf_pri = "split 128;\n"; + $dhcpdconf_pri .= " mclt 600;\n"; + } + + if (is_ipaddrv4($intip)) { + $dhcpdconf .= << $dhcpifconf) { + + $newzone = array(); + $ifcfg = $config['interfaces'][$dhcpif]; + + if (!isset($dhcpifconf['enable']) || !isset($Iflist[$dhcpif])) { + continue; + } + $ifcfgip = get_interface_ip($dhcpif); + $ifcfgsn = get_interface_subnet($dhcpif); + $subnet = gen_subnet($ifcfgip, $ifcfgsn); + $subnetmask = gen_subnet_mask($ifcfgsn); + + if (!is_ipaddr($subnet)) { + continue; + } + + if ($is_olsr_enabled == true) { + if ($dhcpifconf['netmask']) { + $subnetmask = gen_subnet_mask($dhcpifconf['netmask']); + } + } + + $all_pools = array(); + $all_pools[] = $dhcpifconf; + if (is_array($dhcpifconf['pool'])) { + $all_pools = array_merge($all_pools, $dhcpifconf['pool']); + } + + $dnscfg = ""; + + if ($dhcpifconf['domain']) { + $dnscfg .= " option domain-name \"{$dhcpifconf['domain']}\";\n"; + } + + if ($dhcpifconf['domainsearchlist'] <> "") { + $dnscfg .= " option domain-search \"" . join("\",\"", preg_split("/[ ;]+/", $dhcpifconf['domainsearchlist'])) . "\";\n"; + } + + if (isset($dhcpifconf['ddnsupdate'])) { + $need_ddns_updates = true; + $newzone = array(); + if ($dhcpifconf['ddnsdomain'] <> "") { + $newzone['domain-name'] = $dhcpifconf['ddnsdomain']; + $dnscfg .= " ddns-domainname \"{$dhcpifconf['ddnsdomain']}\";\n"; + } else { + $newzone['domain-name'] = $config['system']['domain']; + } + $revsubnet = explode(".", $subnet); + $revsubnet = array_reverse($revsubnet); + foreach ($revsubnet as $octet) { + if ($octet != "0") { + break; + } + array_shift($revsubnet); + } + $newzone['ptr-domain'] = implode(".", $revsubnet) . ".in-addr.arpa"; + } + + if (is_array($dhcpifconf['dnsserver']) && ($dhcpifconf['dnsserver'][0])) { + $dnscfg .= " option domain-name-servers " . join(",", $dhcpifconf['dnsserver']) . ";"; + if ($newzone['domain-name']) { + $newzone['dns-servers'] = $dhcpifconf['dnsserver']; + } + } else if (isset($config['dnsmasq']['enable'])) { + $dnscfg .= " option domain-name-servers {$ifcfgip};"; + if ($newzone['domain-name'] && is_array($syscfg['dnsserver']) && ($syscfg['dnsserver'][0])) { + $newzone['dns-servers'] = $syscfg['dnsserver']; + } + } else if (isset($config['unbound']['enable'])) { + $dnscfg .= " option domain-name-servers {$ifcfgip};"; + } else if (!empty($dns_arrv4)) { + $dnscfg .= " option domain-name-servers " . join(",", $dns_arrv4) . ";"; + if ($newzone['domain-name']) { + $newzone['dns-servers'] = $dns_arrv4; + } + } + + /* Create classes - These all contain comma separated lists. Join them into one + big comma separated string then split them all up. */ + $all_mac_strings = array(); + if (is_array($dhcpifconf['pool'])) { + foreach ($all_pools as $poolconf) { + $all_mac_strings[] = $poolconf['mac_allow']; + $all_mac_strings[] = $poolconf['mac_deny']; + } + } + $all_mac_strings[] = $dhcpifconf['mac_allow']; + $all_mac_strings[] = $dhcpifconf['mac_deny']; + if (!empty($all_mac_strings)) { + $all_mac_list = array_unique(explode(',', implode(',', $all_mac_strings))); + foreach ($all_mac_list as $mac) { + if (empty($mac)) { + continue; + } + $dhcpdconf .= 'class "' . str_replace(':', '', $mac) . '" {' . "\n"; + // Skip the first octet of the MAC address - for media type, typically Ethernet ("01") and match the rest. + $dhcpdconf .= ' match if substring (hardware, 1, ' . (substr_count($mac, ':') + 1) . ') = ' . $mac . ';' . "\n"; + $dhcpdconf .= '}' . "\n"; + } + } + + $dhcpdconf .= "subnet {$subnet} netmask {$subnetmask} {\n"; + + // Setup pool options + foreach ($all_pools as $poolconf) { + $dhcpdconf .= " pool {\n"; + /* is failover dns setup? */ + if (is_array($poolconf['dnsserver']) && $poolconf['dnsserver'][0] <> "") { + $dhcpdconf .= " option domain-name-servers {$poolconf['dnsserver'][0]}"; + if ($poolconf['dnsserver'][1] <> "") { + $dhcpdconf .= ",{$poolconf['dnsserver'][1]}"; + } + if ($poolconf['dnsserver'][2] <> "") { + $dhcpdconf .= ",{$poolconf['dnsserver'][2]}"; + } + if ($poolconf['dnsserver'][3] <> "") { + $dhcpdconf .= ",{$poolconf['dnsserver'][3]}"; + } + $dhcpdconf .= ";\n"; + } + + /* allow/deny MACs */ + $mac_allow_list = array_unique(explode(',', $poolconf['mac_allow'])); + foreach ($mac_allow_list as $mac) { + if (empty($mac)) { + continue; + } + $dhcpdconf .= " allow members of \"" . str_replace(':', '', $mac) . "\";\n"; + } + $mac_deny_list = array_unique(explode(',', $poolconf['mac_deny'])); + foreach ($mac_deny_list as $mac) { + if (empty($mac)) { + continue; + } + $dhcpdconf .= " deny members of \"" . str_replace(':', '', $mac) . "\";\n"; + } + + if ($poolconf['failover_peerip'] <> "") { + $dhcpdconf .= " deny dynamic bootp clients;\n"; + } + + if (isset($poolconf['denyunknown'])) { + $dhcpdconf .= " deny unknown-clients;\n"; + } + + if ($poolconf['gateway'] && $poolconf['gateway'] != "none" && ($poolconf['gateway'] != $dhcpifconf['gateway'])) { + $dhcpdconf .= " option routers {$poolconf['gateway']};\n"; + } + + if ($dhcpifconf['failover_peerip'] <> "") { + $dhcpdconf .= " failover peer \"dhcp_{$dhcpif}\";\n"; + } + + $pdnscfg = ""; + + if ($poolconf['domain'] && ($poolconf['domain'] != $dhcpifconf['domain'])) { + $pdnscfg .= " option domain-name \"{$poolconf['domain']}\";\n"; + } + + if (!empty($poolconf['domainsearchlist']) && ($poolconf['domainsearchlist'] != $dhcpifconf['domainsearchlist'])) { + $pdnscfg .= " option domain-search \"" . join("\",\"", preg_split("/[ ;]+/", $poolconf['domainsearchlist'])) . "\";\n"; + } + + if (isset($poolconf['ddnsupdate'])) { + if (($poolconf['ddnsdomain'] <> "") && ($poolconf['ddnsdomain'] != $dhcpifconf['ddnsdomain'])) { + $pdnscfg .= " ddns-domainname \"{$poolconf['ddnsdomain']}\";\n"; + } + $pdnscfg .= " ddns-update-style interim;\n"; + } + + if (is_array($poolconf['dnsserver']) && ($poolconf['dnsserver'][0]) && ($poolconf['dnsserver'][0] != $dhcpifconf['dnsserver'][0])) { + $pdnscfg .= " option domain-name-servers " . join(",", $poolconf['dnsserver']) . ";\n"; + } + $dhcpdconf .= "{$pdnscfg}"; + + // default-lease-time + if ($poolconf['defaultleasetime'] && ($poolconf['defaultleasetime'] != $dhcpifconf['defaultleasetime'])) { + $dhcpdconf .= " default-lease-time {$poolconf['defaultleasetime']};\n"; + } + + // max-lease-time + if ($poolconf['maxleasetime'] && ($poolconf['maxleasetime'] != $dhcpifconf['maxleasetime'])) { + $dhcpdconf .= " max-lease-time {$poolconf['maxleasetime']};\n"; + } + + // netbios-name* + if (is_array($poolconf['winsserver']) && $poolconf['winsserver'][0] && ($poolconf['winsserver'][0] != $dhcpifconf['winsserver'][0])) { + $dhcpdconf .= " option netbios-name-servers " . join(",", $poolconf['winsserver']) . ";\n"; + $dhcpdconf .= " option netbios-node-type 8;\n"; + } + + // ntp-servers + if (is_array($poolconf['ntpserver']) && $poolconf['ntpserver'][0] && ($poolconf['ntpserver'][0] != $dhcpifconf['ntpserver'][0])) { + $dhcpdconf .= " option ntp-servers " . join(",", $poolconf['ntpserver']) . ";\n"; + } + + // tftp-server-name + if (!empty($poolconf['tftp']) && ($poolconf['tftp'] != $dhcpifconf['tftp'])) { + $dhcpdconf .= " option tftp-server-name \"{$poolconf['tftp']}\";\n"; + } + + // ldap-server + if (!empty($poolconf['ldap']) && ($poolconf['ldap'] != $dhcpifconf['ldap'])) { + $dhcpdconf .= " option ldap-server \"{$poolconf['ldap']}\";\n"; + } + + // net boot information + if (isset($poolconf['netboot'])) { + if (!empty($poolconf['nextserver']) && ($poolconf['nextserver'] != $dhcpifconf['nextserver'])) { + $dhcpdconf .= " next-server {$poolconf['nextserver']};\n"; + } + if (!empty($poolconf['filename']) && ($poolconf['filename'] != $dhcpifconf['filename'])) { + $dhcpdconf .= " filename \"{$poolconf['filename']}\";\n"; + } + if (!empty($poolconf['rootpath']) && ($poolconf['rootpath'] != $dhcpifconf['rootpath'])) { + $dhcpdconf .= " option root-path \"{$poolconf['rootpath']}\";\n"; + } + } + $dhcpdconf .= " range {$poolconf['range']['from']} {$poolconf['range']['to']};\n"; + $dhcpdconf .= " }\n\n"; + } +// End of settings inside pools + + if ($dhcpifconf['gateway'] && $dhcpifconf['gateway'] != "none") { + $routers = $dhcpifconf['gateway']; + $add_routers = true; + } elseif ($dhcpifconf['gateway'] == "none") { + $add_routers = false; + } else { + $add_routers = $enable_add_routers; + $routers = $ifcfgip; + } + if ($add_routers) { + $dhcpdconf .= " option routers {$routers};\n"; + } + + $dhcpdconf .= << "") { + $dhcpdconf .= " option tftp-server-name \"{$dhcpifconf['tftp']}\";\n"; + } + + // Handle option, number rowhelper values + $dhcpdconf .= "\n"; + if ($dhcpifconf['numberoptions']['item']) { + foreach ($dhcpifconf['numberoptions']['item'] as $itemidx => $item) { + if (empty($item['type']) || $item['type'] == "text") { + $dhcpdconf .= " option custom-{$dhcpif}-{$itemidx} \"{$item['value']}\";\n"; + } else { + $dhcpdconf .= " option custom-{$dhcpif}-{$itemidx} {$item['value']};\n"; + } + } + } + + // ldap-server + if ($dhcpifconf['ldap'] <> "") { + $dhcpdconf .= " option ldap-server \"{$dhcpifconf['ldap']}\";\n"; + } + + // net boot information + if (isset($dhcpifconf['netboot'])) { + if ($dhcpifconf['nextserver'] <> "") { + $dhcpdconf .= " next-server {$dhcpifconf['nextserver']};\n"; + } + if (!empty($dhcpifconf['filename']) && !empty($dhcpifconf['filename32']) && !empty($dhcpifconf['filename64'])) { + $dhcpdconf .= " if option arch = 00:06 {\n"; + $dhcpdconf .= " filename \"{$dhcpifconf['filename32']}\";\n"; + $dhcpdconf .= " } else if option arch = 00:07 {\n"; + $dhcpdconf .= " filename \"{$dhcpifconf['filename64']}\";\n"; + $dhcpdconf .= " } else {\n"; + $dhcpdconf .= " filename \"{$dhcpifconf['filename']}\";\n"; + $dhcpdconf .= " }\n\n"; + } elseif (!empty($dhcpifconf['filename'])) { + $dhcpdconf .= " filename \"{$dhcpifconf['filename']}\";\n"; + } + if (!empty($dhcpifconf['rootpath'])) { + $dhcpdconf .= " option root-path \"{$dhcpifconf['rootpath']}\";\n"; + } + } + + $dhcpdconf .= << "") && ($sm['ddnsdomain'] != $dhcpifconf['ddnsdomain'])) { + $pdnscfg .= " ddns-domainname \"{$sm['ddnsdomain']}\";\n"; + } + $pdnscfg .= " ddns-update-style interim;\n"; + } + + if (is_array($sm['dnsserver']) && ($sm['dnsserver'][0]) && ($sm['dnsserver'][0] != $dhcpifconf['dnsserver'][0])) { + $smdnscfg .= " option domain-name-servers " . join(",", $sm['dnsserver']) . ";\n"; + } + $dhcpdconf .= "{$smdnscfg}"; + + // default-lease-time + if ($sm['defaultleasetime'] && ($sm['defaultleasetime'] != $dhcpifconf['defaultleasetime'])) { + $dhcpdconf .= " default-lease-time {$sm['defaultleasetime']};\n"; + } + + // max-lease-time + if ($sm['maxleasetime'] && ($sm['maxleasetime'] != $dhcpifconf['maxleasetime'])) { + $dhcpdconf .= " max-lease-time {$sm['maxleasetime']};\n"; + } + + // netbios-name* + if (is_array($sm['winsserver']) && $sm['winsserver'][0] && ($sm['winsserver'][0] != $dhcpifconf['winsserver'][0])) { + $dhcpdconf .= " option netbios-name-servers " . join(",", $sm['winsserver']) . ";\n"; + $dhcpdconf .= " option netbios-node-type 8;\n"; + } + + // ntp-servers + if (is_array($sm['ntpserver']) && $sm['ntpserver'][0] && ($sm['ntpserver'][0] != $dhcpifconf['ntpserver'][0])) { + $dhcpdconf .= " option ntp-servers " . join(",", $sm['ntpserver']) . ";\n"; + } + + // tftp-server-name + if (!empty($sm['tftp']) && ($sm['tftp'] != $dhcpifconf['tftp'])) { + $dhcpdconf .= " option tftp-server-name \"{$sm['tftp']}\";\n"; + } + + $dhcpdconf .= "}\n"; + $i++; + } + } + + $dhcpdifs[] = get_real_interface($dhcpif); + if ($newzone['domain-name']) { + if ($need_ddns_updates) { + $newzone['dns-servers'] = array($dhcpifconf['ddnsdomainprimary']); + } + $ddns_zones[] = $newzone; + } + } + + if ($need_ddns_updates) { + $dhcpdconf .= "ddns-update-style interim;\n"; + $dhcpdconf .= "update-static-leases on;\n"; + + $dhcpdconf .= dhcpdkey($dhcpifconf); + $dhcpdconf .= dhcpdzones($ddns_zones, $dhcpifconf); + } + + /* write dhcpd.conf */ + if (!@file_put_contents("{$g['dhcpd_chroot_path']}/etc/dhcpd.conf", $dhcpdconf)) { + printf(gettext("Error: cannot open dhcpd.conf in services_dhcpdv4_configure().%s"), "\n"); + unset($dhcpdconf); + return 1; + } + unset($dhcpdconf); + + /* create an empty leases database */ + if (!file_exists("{$g['dhcpd_chroot_path']}/var/db/dhcpd.leases")) { + @touch("{$g['dhcpd_chroot_path']}/var/db/dhcpd.leases"); + } + + /* make sure there isn't a stale dhcpd.pid file, which can make dhcpd fail to start. */ + /* if we get here, dhcpd has been killed and is not started yet */ + unlink_if_exists("{$g['dhcpd_chroot_path']}{$g['varrun_path']}/dhcpd.pid"); + + /* fire up dhcpd in a chroot */ + if (count($dhcpdifs) > 0) { + mwexec("/usr/local/sbin/dhcpd -user dhcpd -group _dhcp -chroot {$g['dhcpd_chroot_path']} -cf /etc/dhcpd.conf -pf {$g['varrun_path']}/dhcpd.pid " . + join(" ", $dhcpdifs)); + } + + if (platform_booting()) { + print "done.\n"; + } + + return 0; +} + +function dhcpdkey($dhcpifconf) { + $dhcpdconf = ""; + if ($dhcpifconf['ddnsdomainkeyname'] <> "" && $dhcpifconf['ddnsdomainkey'] <> "") { + $dhcpdconf .= "key {$dhcpifconf['ddnsdomainkeyname']} {\n"; + $dhcpdconf .= " algorithm hmac-md5;\n"; + $dhcpdconf .= " secret {$dhcpifconf['ddnsdomainkey']};\n"; + $dhcpdconf .= "}\n"; + } + + return $dhcpdconf; +} + +function dhcpdzones($ddns_zones, $dhcpifconf) { + $dhcpdconf = ""; + + if (is_array($ddns_zones)) { + $added_zones = array(); + foreach ($ddns_zones as $zone) { + if (!is_array($zone) || empty($zone) || !is_array($zone['dns-servers'])) { + continue; + } + $primary = $zone['dns-servers'][0]; + $secondary = empty($zone['dns-servers'][1]) ? "" : $zone['dns-servers'][1]; + + // Make sure we aren't using any invalid or IPv6 DNS servers. + if (!is_ipaddrv4($primary)) { + if (is_ipaddrv4($secondary)) { + $primary = $secondary; + $secondary = ""; + } else { + continue; + } + } + + // We don't need to add zones multiple times. + if ($zone['domain-name'] && !in_array($zone['domain-name'], $added_zones)) { + $dhcpdconf .= "zone {$zone['domain-name']}. {\n"; + $dhcpdconf .= " primary {$primary};\n"; + if (is_ipaddrv4($secondary)) { + $dhcpdconf .= " secondary {$secondary};\n"; + } + if ($dhcpifconf['ddnsdomainkeyname'] <> "" && $dhcpifconf['ddnsdomainkey'] <> "") { + $dhcpdconf .= " key {$dhcpifconf['ddnsdomainkeyname']};\n"; + } + $dhcpdconf .= "}\n"; + $added_zones[] = $zone['domain-name']; + } + if ($zone['ptr-domain'] && !in_array($zone['ptr-domain'], $added_zones)) { + $dhcpdconf .= "zone {$zone['ptr-domain']} {\n"; + $dhcpdconf .= " primary {$primary};\n"; + if (is_ipaddrv4($secondary)) { + $dhcpdconf .= " secondary {$secondary};\n"; + } + if ($dhcpifconf['ddnsdomainkeyname'] <> "" && $dhcpifconf['ddnsdomainkey'] <> "") { + $dhcpdconf .= " key {$dhcpifconf['ddnsdomainkeyname']};\n"; + } + $dhcpdconf .= "}\n"; + $added_zones[] = $zone['ptr-domain']; + } + } + } + + return $dhcpdconf; +} + +function services_dhcpdv6_configure($blacklist = array()) { + global $config, $g; + + if ($g['services_dhcp_server_enable'] == false) { + return; + } + + if (isset($config['system']['developerspew'])) { + $mt = microtime(); + echo "services_dhcpd_configure($if) being called $mt\n"; + } + + /* kill any running dhcpd */ + if (isvalidpid("{$g['dhcpd_chroot_path']}{$g['varrun_path']}/dhcpdv6.pid")) { + killbypid("{$g['dhcpd_chroot_path']}{$g['varrun_path']}/dhcpdv6.pid"); + } + if (isvalidpid("{$g['varrun_path']}/dhcpleases6.pid")) { + killbypid("{$g['varrun_path']}/dhcpleases6.pid"); + } + + /* DHCP enabled on any interfaces? */ + if (!is_dhcpv6_server_enabled()) { + return 0; + } + + if (platform_booting()) { + if ($g['platform'] != "pfSense") { + /* restore the leases, if we have them */ + if (file_exists("{$g['cf_conf_path']}/dhcp6leases.tgz")) { + $dhcprestore = ""; + $dhcpreturn = ""; + exec("cd /;LANG=C /usr/bin/tar -xzf {$g['cf_conf_path']}/dhcp6leases.tgz 2>&1", $dhcprestore, $dhcpreturn); + $dhcprestore = implode(" ", $dhcprestore); + if ($dhcpreturn <> 0) { + log_error("DHCP leases v6 restore failed exited with $dhcpreturn, the error is: $dhcprestore\n"); + } + } + } + } + + $syscfg = $config['system']; + if (!is_array($config['dhcpdv6'])) { + $config['dhcpdv6'] = array(); + } + $dhcpdv6cfg = $config['dhcpdv6']; + $Iflist = get_configured_interface_list(); + $Iflist = array_merge($Iflist, get_configured_pppoe_server_interfaces()); + + + if (platform_booting()) { + echo "Starting DHCPv6 service..."; + } else { + sleep(1); + } + + /* we add a fake entry for interfaces that are set to track6 another WAN */ + foreach ($Iflist as $ifname) { + /* Do not put in the config an interface which is down */ + if (isset($blacklist[$ifname])) { + continue; + } + if (!empty($config['interfaces'][$ifname]['track6-interface'])) { + $realif = get_real_interface($ifname, "inet6"); + $ifcfgipv6 = get_interface_ipv6($ifname); + if (!is_ipaddrv6($ifcfgipv6)) { + continue; + } + $ifcfgipv6 = Net_IPv6::getNetmask($ifcfgipv6, 64); + $trackifname = $config['interfaces'][$ifname]['track6-interface']; + $trackcfg = $config['interfaces'][$trackifname]; + $pdlen = calculate_ipv6_delegation_length($trackifname); + $ifcfgipv6arr =explode(":", $ifcfgipv6); + $dhcpdv6cfg[$ifname] = array(); + $dhcpdv6cfg[$ifname]['enable'] = true; + /* range */ + $ifcfgipv6arr[7] = "1000"; + $dhcpdv6cfg[$ifname]['range'] = array(); + $dhcpdv6cfg[$ifname]['range']['from'] = Net_IPv6::compress(implode(":", $ifcfgipv6arr)); + $ifcfgipv6arr[7] = "2000"; + $dhcpdv6cfg[$ifname]['range']['to'] = Net_IPv6::compress(implode(":", $ifcfgipv6arr)); + /* prefix length > 0? We can add dhcp6 prefix delegation server */ + if ($pdlen > 2) { + $pdlenmax = $pdlen; + $pdlenhalf = $pdlenmax -1; + $pdlenmin = (64 - ceil($pdlenhalf / 4)); + $dhcpdv6cfg[$ifname]['prefixrange'] = array(); + $dhcpdv6cfg[$ifname]['prefixrange']['prefixlength'] = $pdlenmin; + + /* set the delegation start to half the current address block */ + $range = Net_IPv6::parseAddress($ifcfgipv6, (64 - $pdlenmax)); + $range['start'] = Net_IPv6::getNetmask($range['end'], (64 - $pdlenhalf)); + + /* set the end range to a multiple of the prefix delegation size, required by dhcpd */ + $range = Net_IPv6::parseAddress($range['end'], (64 - $pdlenhalf)); + $range['end'] = Net_IPv6::getNetmask($range['end'], (64 - round($pdlen / 2))); + + $dhcpdv6cfg[$ifname]['prefixrange']['from'] = Net_IPv6::compress($range['start']); + $dhcpdv6cfg[$ifname]['prefixrange']['to'] = Net_IPv6::compress($range['end']); + } + $dhcpdv6cfg[$ifname]['dns6ip'] = get_interface_ipv6($ifname); + } + } + + $custoptionsv6 = ""; + foreach ($dhcpdv6cfg as $dhcpv6if => $dhcpv6ifconf) { + if (is_array($dhcpv6ifconf['numberoptions']) && is_array($dhcpv6ifconf['numberoptions']['item'])) { + foreach ($dhcpv6ifconf['numberoptions']['item'] as $itemv6idx => $itemv6) { + $custoptionsv6 .= "option custom-{$dhcpv6if}-{$itemv6idx} code {$itemv6['number']} = text;\n"; + } + } + } + + if (isset($dhcpv6ifconf['netboot']) && !empty($dhcpv6ifconf['bootfile_url'])) { + $custoptionsv6 .= "option dhcp6.bootfile-url code 59 = string;\n"; + } + + $dhcpdv6conf = << $dhcpv6ifconf) { + + $ddns_zones = array(); + + $ifcfgv6 = $config['interfaces'][$dhcpv6if]; + + if (!isset($dhcpv6ifconf['enable']) || !isset($Iflist[$dhcpv6if]) || !isset($ifcfgv6['enable'])) { + continue; + } + $ifcfgipv6 = get_interface_ipv6($dhcpv6if); + $ifcfgsnv6 = get_interface_subnetv6($dhcpv6if); + $subnetv6 = gen_subnetv6($ifcfgipv6, $ifcfgsnv6); + + if ($is_olsr_enabled == true) { + if ($dhcpv6ifconf['netmask']) { + $subnetmask = gen_subnet_maskv6($dhcpv6ifconf['netmask']); + } + } + + $dnscfgv6 = ""; + + if ($dhcpv6ifconf['domain']) { + $dnscfgv6 .= " option domain-name \"{$dhcpv6ifconf['domain']}\";\n"; + } + + if ($dhcpv6ifconf['domainsearchlist'] <> "") { + $dnscfgv6 .= " option domain-search \"" . join("\",\"", preg_split("/[ ;]+/", $dhcpv6ifconf['domainsearchlist'])) . "\";\n"; + } + + if (isset($dhcpv6ifconf['ddnsupdate'])) { + if ($dhcpv6ifconf['ddnsdomain'] <> "") { + $dnscfgv6 .= " ddns-domainname \"{$dhcpv6ifconf['ddnsdomain']}\";\n"; + } + $dnscfgv6 .= " ddns-update-style interim;\n"; + $nsupdate = true; + } + + if (is_array($dhcpv6ifconf['dnsserver']) && ($dhcpv6ifconf['dnsserver'][0])) { + $dnscfgv6 .= " option dhcp6.name-servers " . join(",", $dhcpv6ifconf['dnsserver']) . ";"; + } else if (((isset($config['dnsmasq']['enable'])) || isset($config['unbound']['enable'])) && (is_ipaddrv6($ifcfgipv6))) { + $dnscfgv6 .= " option dhcp6.name-servers {$ifcfgipv6};"; + } else if (is_array($syscfg['dnsserver']) && ($syscfg['dnsserver'][0])) { + $dns_arrv6 = array(); + foreach ($syscfg['dnsserver'] as $dnsserver) { + if (is_ipaddrv6($dnsserver)) { + $dns_arrv6[] = $dnsserver; + } + } + if (!empty($dns_arrv6)) { + $dnscfgv6 .= " option dhcp6.name-servers " . join(",", $dns_arrv6) . ";"; + } + } + + if ($dhcpv6ifconf['domain']) { + $newzone = array(); + $newzone['domain-name'] = $dhcpv6ifconf['domain']; + $newzone['dns-servers'][] = $dhcpv6ifconf['ddnsdomainprimary']; + $ddns_zones[] = $newzone; + } + + if (is_ipaddrv6($ifcfgipv6)) { + $dhcpdv6conf .= "subnet6 {$subnetv6}/{$ifcfgsnv6}"; + } else { + $subnet6 = gen_subnetv6($dhcpv6ifconf['range']['from'], "64"); + $dhcpdv6conf .= "subnet6 {$subnet6}/64"; + } + $dhcpdv6conf .= " {\n"; + + $dhcpdv6conf .= << 0) { + $dhcpdv6conf .= " option dhcp6.sntp-servers " . join(",", $dhcpv6ifconf['ntpserver']) . ";\n"; + } + } + // tftp-server-name + /* Needs ISC DHCPD support + if ($dhcpv6ifconf['tftp'] <> "") { + $dhcpdv6conf .= " option tftp-server-name \"{$dhcpv6ifconf['tftp']}\";\n"; + } + */ + + // Handle option, number rowhelper values + $dhcpdv6conf .= "\n"; + if ($dhcpv6ifconf['numberoptions']['item']) { + foreach ($dhcpv6ifconf['numberoptions']['item'] as $itemv6idx => $itemv6) { + $dhcpdv6conf .= " option custom-{$dhcpv6if}-{$itemv6idx} \"{$itemv6['value']}\";\n"; + } + } + + // ldap-server + if ($dhcpv6ifconf['ldap'] <> "") { + $dhcpdv6conf .= " option ldap-server \"{$dhcpv6ifconf['ldap']}\";\n"; + } + + // net boot information + if (isset($dhcpv6ifconf['netboot'])) { + if (!empty($dhcpv6ifconf['bootfile_url'])) { + $dhcpdv6conf .= " option dhcp6.bootfile-url \"{$dhcpv6ifconf['bootfile_url']}\";\n"; + } + } + + $dhcpdv6conf .= "}\n"; + + /* add static mappings */ + /* Needs to use DUID */ + if (is_array($dhcpv6ifconf['staticmap'])) { + $i = 0; + foreach ($dhcpv6ifconf['staticmap'] as $sm) { + $dhcpdv6conf .= << "unmanaged" && isset($config['interfaces'][$dhcpv6if]['enable'])) { + if (preg_match("/poes/si", $dhcpv6if)) { + /* magic here */ + $dhcpdv6ifs = array_merge($dhcpdv6ifs, get_pppoes_child_interfaces($dhcpv6if)); + } else { + $realif = get_real_interface($dhcpv6if, "inet6"); + if (stristr("$realif", "bridge")) { + $mac = get_interface_mac($realif); + $v6address = generate_ipv6_from_mac($mac); + /* Create link local address for bridges */ + mwexec("/sbin/ifconfig {$realif} inet6 {$v6address}"); + } + $realif = escapeshellcmd($realif); + $dhcpdv6ifs[] = $realif; + } + } + } + + if ($nsupdate) { + $dhcpdv6conf .= "ddns-update-style interim;\n"; + } else { + $dhcpdv6conf .= "ddns-update-style none;\n"; + } + + /* write dhcpdv6.conf */ + if (!@file_put_contents("{$g['dhcpd_chroot_path']}/etc/dhcpdv6.conf", $dhcpdv6conf)) { + log_error("Error: cannot open {$g['dhcpd_chroot_path']}/etc/dhcpdv6.conf in services_dhcpdv6_configure().\n"); + if (platform_booting()) { + printf("Error: cannot open {$g['dhcpd_chroot_path']}/etc/dhcpdv6.conf in services_dhcpdv6_configure().\n"); + } + unset($dhcpdv6conf); + return 1; + } + unset($dhcpdv6conf); + + /* create an empty leases v6 database */ + if (!file_exists("{$g['dhcpd_chroot_path']}/var/db/dhcpd6.leases")) { + @touch("{$g['dhcpd_chroot_path']}/var/db/dhcpd6.leases"); + } + + /* make sure there isn't a stale dhcpdv6.pid file, which may make dhcpdv6 fail to start. */ + /* if we get here, dhcpdv6 has been killed and is not started yet */ + unlink_if_exists("{$g['dhcpd_chroot_path']}{$g['varrun_path']}/dhcpdv6.pid"); + + /* fire up dhcpd in a chroot */ + if (count($dhcpdv6ifs) > 0) { + mwexec("/usr/local/sbin/dhcpd -6 -user dhcpd -group _dhcp -chroot {$g['dhcpd_chroot_path']} -cf /etc/dhcpdv6.conf -pf {$g['varrun_path']}/dhcpdv6.pid " . + join(" ", $dhcpdv6ifs)); + mwexec("/usr/local/sbin/dhcpleases6 -c \"/usr/local/bin/php-cgi -f /usr/local/sbin/prefixes.php|/bin/sh\" -l {$g['dhcpd_chroot_path']}/var/db/dhcpd6.leases"); + } + if (platform_booting()) { + print gettext("done.") . "\n"; + } + + return 0; +} + +function services_igmpproxy_configure() { + global $config, $g; + + /* kill any running igmpproxy */ + killbyname("igmpproxy"); + + if (!is_array($config['igmpproxy']['igmpentry']) || (count($config['igmpproxy']['igmpentry']) == 0)) { + return 1; + } + + $iflist = get_configured_interface_list(); + + $igmpconf = << "") { + $item = explode(" ", $igmpcf['address']); + foreach ($item as $iww) { + $igmpconf .= "altnet {$iww}\n"; + } + } + $igmpconf .= "\n"; + } + foreach ($iflist as $ifn) { + $realif = get_real_interface($ifn); + $igmpconf .= "phyint {$realif} disabled\n"; + } + $igmpconf .= "\n"; + + $igmpfl = fopen($g['tmp_path'] . "/igmpproxy.conf", "w"); + if (!$igmpfl) { + log_error(gettext("Could not write Igmpproxy configuration file!")); + return; + } + fwrite($igmpfl, $igmpconf); + fclose($igmpfl); + unset($igmpconf); + + /* NOTE: -d4 means everything LOG_WARNING and smaller */ + mwexec("/usr/local/sbin/igmpproxy -d4 -c {$g['tmp_path']}/igmpproxy.conf"); + log_error(gettext("Started IGMP proxy service.")); + + return 0; +} + +function services_dhcrelay_configure() { + global $config, $g; + + if (isset($config['system']['developerspew'])) { + $mt = microtime(); + echo "services_dhcrelay_configure() being called $mt\n"; + } + + /* kill any running dhcrelay */ + killbypid("{$g['varrun_path']}/dhcrelay.pid"); + + $dhcrelaycfg =& $config['dhcrelay']; + + /* DHCPRelay enabled on any interfaces? */ + if (!isset($dhcrelaycfg['enable'])) { + return 0; + } + + if (platform_booting()) { + echo gettext("Starting DHCP relay service..."); + } else { + sleep(1); + } + + $iflist = get_configured_interface_list(); + + $dhcifaces = explode(",", $dhcrelaycfg['interface']); + foreach ($dhcifaces as $dhcrelayif) { + if (!isset($iflist[$dhcrelayif]) || + link_interface_to_bridge($dhcrelayif)) { + continue; + } + + if (is_ipaddr(get_interface_ip($dhcrelayif))) { + $dhcrelayifs[] = get_real_interface($dhcrelayif); + } + } + + $srvips = explode(",", $dhcrelaycfg['server']); + if (!is_array($srvips)) { + log_error("No destination IP has been configured!"); + return; + } + + $dhcrelayifs = array_unique($dhcrelayifs); + + /* fire up dhcrelay */ + if (empty($dhcrelayifs)) { + log_error("No suitable interface found for running dhcrelay!"); + return; /* XXX */ + } + + $cmd = "/usr/local/sbin/dhcrelay -i " . implode(" -i ", $dhcrelayifs); + + if (isset($dhcrelaycfg['agentoption'])) { + $cmd .= " -a -m replace"; + } + + $cmd .= " " . implode(" ", $srvips); + mwexec($cmd); + unset($cmd); + + return 0; +} + +function services_dhcrelay6_configure() { + global $config, $g; + + if (isset($config['system']['developerspew'])) { + $mt = microtime(); + echo "services_dhcrelay6_configure() being called $mt\n"; + } + + /* kill any running dhcrelay */ + killbypid("{$g['varrun_path']}/dhcrelay6.pid"); + + $dhcrelaycfg =& $config['dhcrelay6']; + + /* DHCPv6 Relay enabled on any interfaces? */ + if (!isset($dhcrelaycfg['enable'])) { + return 0; + } + + if (platform_booting()) { + echo gettext("Starting DHCPv6 relay service..."); + } else { + sleep(1); + } + + $iflist = get_configured_interface_list(); + + $dhcifaces = explode(",", $dhcrelaycfg['interface']); + foreach ($dhcifaces as $dhcrelayif) { + if (!isset($iflist[$dhcrelayif]) || + link_interface_to_bridge($dhcrelayif)) { + continue; + } + + if (is_ipaddrv6(get_interface_ipv6($dhcrelayif))) { + $dhcrelayifs[] = get_real_interface($dhcrelayif); + } + } + $dhcrelayifs = array_unique($dhcrelayifs); + + $srvips = explode(",", $dhcrelaycfg['server']); + if (!is_array($srvips)) { + log_error("No destination IP has been configured!"); + return; + } + + /* fire up dhcrelay */ + if (empty($dhcrelayifs) || empty($srvifaces)) { + log_error("No suitable interface found for running dhcrelay -6!"); + return; /* XXX */ + } + + $cmd = "/usr/local/sbin/dhcrelay -6 -pf \"{$g['varrun_path']}/dhcrelay6.pid\""; + foreach ($dhcrelayifs as $dhcrelayif) { + $cmd .= " -l {$dhcrelayif}"; + } + foreach ($srvifaces as $srviface) { + $cmd .= " -u \"{$srviface}\""; + } + mwexec($cmd); + unset($cmd); + + return 0; +} + +function services_dyndns_configure_client($conf) { + + if (!isset($conf['enable'])) { + return; + } + + /* load up the dyndns.class */ + require_once("dyndns.class"); + + $dns = new updatedns($dnsService = $conf['type'], + $dnsHost = $conf['host'], + $dnsUser = $conf['username'], + $dnsPass = $conf['password'], + $dnsWildcard = $conf['wildcard'], + $dnsMX = $conf['mx'], + $dnsIf = "{$conf['interface']}", + $dnsBackMX = NULL, + $dnsServer = NULL, + $dnsPort = NULL, + $dnsUpdateURL = "{$conf['updateurl']}", + $forceUpdate = $conf['force'], + $dnsZoneID = $conf['zoneid'], + $dnsTTL = $conf['ttl'], + $dnsResultMatch = "{$conf['resultmatch']}", + $dnsRequestIf = "{$conf['requestif']}", + $dnsID = "{$conf['id']}", + $dnsVerboseLog = $conf['verboselog'], + $curlIpresolveV4 = $conf['curl_ipresolve_v4'], + $curlSslVerifypeer = $conf['curl_ssl_verifypeer']); +} + +function services_dyndns_configure($int = "") { + global $config, $g; + if (isset($config['system']['developerspew'])) { + $mt = microtime(); + echo "services_dyndns_configure() being called $mt\n"; + } + + $dyndnscfg = $config['dyndnses']['dyndns']; + $gwgroups = return_gateway_groups_array(); + if (is_array($dyndnscfg)) { + if (platform_booting()) { + echo gettext("Starting DynDNS clients..."); + } + + foreach ($dyndnscfg as $dyndns) { + if ((empty($int)) || ($int == $dyndns['interface']) || (is_array($gwgroups[$dyndns['interface']]))) { + $dyndns['verboselog'] = isset($dyndns['verboselog']); + $dyndns['curl_ipresolve_v4'] = isset($dyndns['curl_ipresolve_v4']); + $dyndns['curl_ssl_verifypeer'] = isset($dyndns['curl_ssl_verifypeer']); + services_dyndns_configure_client($dyndns); + sleep(1); + } + } + + if (platform_booting()) { + echo gettext("done.") . "\n"; + } + } + + return 0; +} + +function dyndnsCheckIP($int) { + global $config; + $ip_address = get_interface_ip($int); + if (is_private_ip($ip_address)) { + $gateways_status = return_gateways_status(true); + // If the gateway for this interface is down, then the external check cannot work. + // Avoid the long wait for the external check to timeout. + if (stristr($gateways_status[$config['interfaces'][$int]['gateway']]['status'], "down")) { + return "down"; + } + $hosttocheck = "http://checkip.dyndns.org"; + $ip_ch = curl_init($hosttocheck); + curl_setopt($ip_ch, CURLOPT_RETURNTRANSFER, 1); + curl_setopt($ip_ch, CURLOPT_SSL_VERIFYPEER, FALSE); + curl_setopt($ip_ch, CURLOPT_INTERFACE, 'host!' . $ip_address); + curl_setopt($ip_ch, CURLOPT_CONNECTTIMEOUT, '30'); + curl_setopt($ip_ch, CURLOPT_TIMEOUT, 120); + curl_setopt($ip_ch, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4); + $ip_result_page = curl_exec($ip_ch); + curl_close($ip_ch); + $ip_result_decoded = urldecode($ip_result_page); + preg_match('=Current IP Address: (.*)=siU', $ip_result_decoded, $matches); + $ip_address = trim($matches[1]); + } + return $ip_address; +} + +function services_dnsmasq_configure() { + global $config, $g; + $return = 0; + + // hard coded args: will be removed to avoid duplication if specified in custom_options + $standard_args = array( + "dns-forward-max" => "--dns-forward-max=5000", + "cache-size" => "--cache-size=10000", + "local-ttl" => "--local-ttl=1" + ); + + + if (isset($config['system']['developerspew'])) { + $mt = microtime(); + echo "services_dnsmasq_configure() being called $mt\n"; + } + + /* kill any running dnsmasq */ + if (file_exists("{$g['varrun_path']}/dnsmasq.pid")) { + sigkillbypid("{$g['varrun_path']}/dnsmasq.pid", "TERM"); + } + + if (isset($config['dnsmasq']['enable'])) { + + if (platform_booting()) { + echo gettext("Starting DNS forwarder..."); + } else { + sleep(1); + } + + /* generate hosts file */ + if (system_hosts_generate() != 0) { + $return = 1; + } + + $args = ""; + + if (isset($config['dnsmasq']['regdhcp'])) { + $args .= " --dhcp-hostsfile={$g['varetc_path']}/hosts "; + } + + /* Setup listen port, if non-default */ + if (is_port($config['dnsmasq']['port'])) { + $args .= " --port={$config['dnsmasq']['port']} "; + } + + $listen_addresses = ""; + if (isset($config['dnsmasq']['interface'])) { + $interfaces = explode(",", $config['dnsmasq']['interface']); + foreach ($interfaces as $interface) { + if (is_ipaddrv4($interface)) { + $listen_addresses .= " --listen-address={$interface} "; + } else if (is_ipaddrv6($interface)) { + /* + * XXX: Since dnsmasq does not support link-local address + * with scope specified. These checks are being done. + */ + if (is_linklocal($interface) && strstr($interface, "%")) { + $tmpaddrll6 = explode("%", $interface); + $listen_addresses .= " --listen-address={$tmpaddrll6[0]} "; + } else { + $listen_addresses .= " --listen-address={$interface} "; + } + } else if (strstr($interface, "_vip")) { + $laddr = get_configured_carp_interface_list($interface); + if (is_ipaddr($laddr)) { + $listen_addresses .= " --listen-address={$laddr} "; + } + } else { + $if = get_real_interface($interface); + if (does_interface_exist($if)) { + $laddr = get_interface_ip($interface); + if (is_ipaddrv4($laddr)) { + $listen_addresses .= " --listen-address={$laddr} "; + } + $laddr6 = get_interface_ipv6($interface); + if (is_ipaddrv6($laddr6) && !isset($config['dnsmasq']['strictbind'])) { + /* + * XXX: Since dnsmasq does not support link-local address + * with scope specified. These checks are being done. + */ + if (is_linklocal($laddr6) && strstr($laddr6, "%")) { + $tmpaddrll6 = explode("%", $laddr6); + $listen_addresses .= " --listen-address={$tmpaddrll6[0]} "; + } else { + $listen_addresses .= " --listen-address={$laddr6} "; + } + } + } + } + } + if (!empty($listen_addresses)) { + $args .= " {$listen_addresses} "; + if (isset($config['dnsmasq']['strictbind'])) { + $args .= " --bind-interfaces "; + } + } + } + + /* If selected, then first forward reverse lookups for private IPv4 addresses to nowhere. */ + /* Only make entries for reverse domains that do not have a matching domain override. */ + if (isset($config['dnsmasq']['no_private_reverse'])) { + /* Note: Carrier Grade NAT (CGN) addresses 100.64.0.0/10 are intentionally not here. */ + /* End-users should not be aware of CGN addresses, so reverse lookups for these should not happen. */ + /* Just the pfSense WAN might get a CGN address from an ISP. */ + + // Build an array of domain overrides to help in checking for matches. + $override_a = array(); + if (isset($config['dnsmasq']['domainoverrides']) && is_array($config['dnsmasq']['domainoverrides'])) { + foreach ($config['dnsmasq']['domainoverrides'] as $override) { + $override_a[$override['domain']] = "y"; + } + } + + // Build an array of the private reverse lookup domain names + $reverse_domain_a = array("10.in-addr.arpa", "168.192.in-addr.arpa"); + // Unfortunately the 172.16.0.0/12 range does not map nicely to the in-addr.arpa scheme. + for ($subnet_num = 16; $subnet_num < 32; $subnet_num++) { + $reverse_domain_a[] = "$subnet_num.172.in-addr.arpa"; + } + + // Set the --server parameter to nowhere for each reverse domain name that was not specifically specified in a domain override. + foreach ($reverse_domain_a as $reverse_domain) { + if (!isset($override_a[$reverse_domain])) { + $args .= " --server=/$reverse_domain/ "; + } + } + unset($override_a); + unset($reverse_domain_a); + } + + /* Setup forwarded domains */ + if (isset($config['dnsmasq']['domainoverrides']) && is_array($config['dnsmasq']['domainoverrides'])) { + foreach ($config['dnsmasq']['domainoverrides'] as $override) { + if ($override['ip'] == "!") { + $override[ip] = ""; + } + $args .= ' --server=/' . $override['domain'] . '/' . $override['ip']; + } + } + + /* Allow DNS Rebind for forwarded domains */ + if (isset($config['dnsmasq']['domainoverrides']) && is_array($config['dnsmasq']['domainoverrides'])) { + if (!isset($config['system']['webgui']['nodnsrebindcheck'])) { + foreach ($config['dnsmasq']['domainoverrides'] as $override) { + $args .= ' --rebind-domain-ok=/' . $override['domain'] . '/ '; + } + } + } + + if (!isset($config['system']['webgui']['nodnsrebindcheck'])) { + $dns_rebind = "--rebind-localhost-ok --stop-dns-rebind"; + } + + if (isset($config['dnsmasq']['strict_order'])) { + $args .= " --strict-order "; + } + + if (isset($config['dnsmasq']['domain_needed'])) { + $args .= " --domain-needed "; + } + + if ($config['dnsmasq']['custom_options']) { + foreach (preg_split('/\s+/', $config['dnsmasq']['custom_options']) as $c) { + $args .= " " . escapeshellarg("--{$c}"); + $p = explode('=', $c); + if (array_key_exists($p[0], $standard_args)) { + unset($standard_args[$p[0]]); + } + } + } + $args .= ' ' . implode(' ', array_values($standard_args)); + + /* run dnsmasq */ + $cmd = "/usr/local/sbin/dnsmasq --all-servers {$dns_rebind} {$args}"; + //log_error("dnsmasq command: {$cmd}"); + mwexec_bg($cmd); + unset($args); + + system_dhcpleases_configure(); + + if (platform_booting()) { + echo gettext("done.") . "\n"; + } + } + + if (!platform_booting()) { + if (services_dhcpd_configure() != 0) { + $return = 1; + } + } + + return $return; +} + +function services_unbound_configure() { + global $config, $g; + $return = 0; + + if (isset($config['system']['developerspew'])) { + $mt = microtime(); + echo "services_unbound_configure() being called $mt\n"; + } + + // kill any running Unbound instance + if (file_exists("{$g['varrun_path']}/unbound.pid")) { + sigkillbypid("{$g['varrun_path']}/unbound.pid", "TERM"); + } + + if (isset($config['unbound']['enable'])) { + if (platform_booting()) { + echo gettext("Starting DNS Resolver..."); + } else { + sleep(1); + } + + /* generate hosts file */ + if (system_hosts_generate() != 0) { + $return = 1; + } + + require_once('/etc/inc/unbound.inc'); + sync_unbound_service(); + if (platform_booting()) { + echo gettext("done.") . "\n"; + } + + system_dhcpleases_configure(); + } + + if (!platform_booting()) { + if (services_dhcpd_configure() != 0) { + $return = 1; + } + } + + return $return; +} + +function services_snmpd_configure() { + global $config, $g; + if (isset($config['system']['developerspew'])) { + $mt = microtime(); + echo "services_snmpd_configure() being called $mt\n"; + } + + /* kill any running snmpd */ + sigkillbypid("{$g['varrun_path']}/snmpd.pid", "TERM"); + sleep(2); + if (is_process_running("bsnmpd")) { + mwexec("/usr/bin/killall bsnmpd", true); + } + + if (isset($config['snmpd']['enable'])) { + + if (platform_booting()) { + echo gettext("Starting SNMP daemon... "); + } + + /* generate snmpd.conf */ + $fd = fopen("{$g['varetc_path']}/snmpd.conf", "w"); + if (!$fd) { + printf(gettext("Error: cannot open snmpd.conf in services_snmpd_configure().%s"), "\n"); + return 1; + } + + + $snmpdconf = << $dnsupdate) { + if (!isset($dnsupdate['enable'])) { + continue; + } + if (!empty($int) && $int != $dnsupdate['interface']) { + continue; + } + if (!empty($updatehost) && ($updatehost != $dnsupdate['host'])) { + continue; + } + + /* determine interface name */ + $if = get_real_interface($dnsupdate['interface']); + + if (isset($dnsupdate['usepublicip'])) { + $wanip = dyndnsCheckIP($dnsupdate['interface']); + } else { + $wanip = get_interface_ip($dnsupdate['interface']); + } + + $wanipv6 = get_interface_ipv6($dnsupdate['interface']); + $cacheFile = "{$g['conf_path']}/dyndns_{$dnsupdate['interface']}_rfc2136_" . escapeshellarg($dnsupdate['host']) . "_{$dnsupdate['server']}.cache"; + $currentTime = time(); + + if ($wanip || $wanipv6) { + $keyname = $dnsupdate['keyname']; + /* trailing dot */ + if (substr($keyname, -1) != ".") { + $keyname .= "."; + } + + $hostname = $dnsupdate['host']; + /* trailing dot */ + if (substr($hostname, -1) != ".") { + $hostname .= "."; + } + + /* write private key file + this is dumb - public and private keys are the same for HMAC-MD5, + but nsupdate insists on having both */ + $fd = fopen("{$g['varetc_path']}/K{$i}{$keyname}+157+00000.private", "w"); + $privkey = << $maxCacheAgeSecs) || $forced) { + $upinst .= "update delete {$dnsupdate['host']}. A\n"; + $upinst .= "update add {$dnsupdate['host']}. {$dnsupdate['ttl']} A {$wanip}\n"; + $notify_text .= sprintf(gettext("DynDNS updated IP Address (A) for {$dnsupdate['host']} on %s (%s) to %s"), convert_real_interface_to_friendly_descr($if), $if, $wanip) . "\n"; + @file_put_contents($cacheFile, "{$wanip}|{$currentTime}"); + log_error("phpDynDNS: updating cache file {$cacheFile}: {$wanip}"); + $need_update = true; + } else { + log_error("phpDynDNS: Not updating {$dnsupdate['host']} A record because the IP address has not changed."); + } + } else { + @unlink($cacheFile); + } + + /* Update IPv6 if we have it. */ + if (is_ipaddrv6($wanipv6) && $dnsupdate['recordtype'] != "A") { + if (($wanipv6 != $cachedipv6) || (($currentTime - $cacheTimev6) > $maxCacheAgeSecs) || $forced) { + $upinst .= "update delete {$dnsupdate['host']}. AAAA\n"; + $upinst .= "update add {$dnsupdate['host']}. {$dnsupdate['ttl']} AAAA {$wanipv6}\n"; + $notify_text .= sprintf(gettext("DynDNS updated IPv6 Address (AAAA) for {$dnsupdate['host']} on %s (%s) to %s"), convert_real_interface_to_friendly_descr($if), $if, $wanipv6) . "\n"; + @file_put_contents("{$cacheFile}.ipv6", "{$wanipv6}|{$currentTime}"); + log_error("phpDynDNS: updating cache file {$cacheFile}.ipv6: {$wanipv6}"); + $need_update = true; + } else { + log_error("phpDynDNS: Not updating {$dnsupdate['host']} AAAA record because the IPv6 address has not changed."); + } + } else { + @unlink("{$cacheFile}.ipv6"); + } + conf_mount_ro(); + + $upinst .= "\n"; /* mind that trailing newline! */ + + if ($need_update) { + @file_put_contents("{$g['varetc_path']}/nsupdatecmds{$i}", $upinst); + unset($upinst); + /* invoke nsupdate */ + $cmd = "/usr/local/bin/nsupdate -k {$g['varetc_path']}/K{$i}{$keyname}+157+00000.key"; + if (isset($dnsupdate['usetcp'])) { + $cmd .= " -v"; + } + $cmd .= " {$g['varetc_path']}/nsupdatecmds{$i}"; + mwexec_bg($cmd); + unset($cmd); + } + } + } + if (!empty($notify_text)) { + notify_all_remote($notify_text); + } + } + + return 0; +} + +/* configure cron service */ +function configure_cron() { + global $g, $config; + + conf_mount_rw(); + /* preserve existing crontab entries */ + $crontab_contents = file("/etc/crontab", FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES); + + for ($i = 0; $i < count($crontab_contents); $i++) { + $cron_item =& $crontab_contents[$i]; + if (strpos($cron_item, "# pfSense specific crontab entries") !== false) { + array_splice($crontab_contents, $i - 1); + break; + } + } + $crontab_contents = implode("\n", $crontab_contents) . "\n"; + + + if (is_array($config['cron']['item'])) { + $crontab_contents .= "#\n"; + $crontab_contents .= "# " . gettext("pfSense specific crontab entries") . "\n"; + $crontab_contents .= "# " .gettext("Created:") . " " . date("F j, Y, g:i a") . "\n"; + $crontab_contents .= "#\n"; + + if (isset($config['system']['proxyurl']) && !empty($config['system']['proxyurl'])) { + $http_proxy = $config['system']['proxyurl']; + if (isset($config['system']['proxyport']) && !empty($config['system']['proxyport'])) { + $http_proxy .= ':' . $config['system']['proxyport']; + } + $crontab_contents .= "HTTP_PROXY={$http_proxy}"; + } + + foreach ($config['cron']['item'] as $item) { + $crontab_contents .= "\n{$item['minute']}\t"; + $crontab_contents .= "{$item['hour']}\t"; + $crontab_contents .= "{$item['mday']}\t"; + $crontab_contents .= "{$item['month']}\t"; + $crontab_contents .= "{$item['wday']}\t"; + $crontab_contents .= "{$item['who']}\t"; + $crontab_contents .= "{$item['command']}"; + } + + $crontab_contents .= "\n#\n"; + $crontab_contents .= "# " . gettext("If possible do not add items to this file manually.") . "\n"; + $crontab_contents .= "# " . gettext("If you do so, this file must be terminated with a blank line (e.g. new line)") . "\n"; + $crontab_contents .= "#\n\n"; + } + + /* please maintain the newline at the end of file */ + file_put_contents("/etc/crontab", $crontab_contents); + unset($crontab_contents); + + /* do a HUP kill to force sync changes */ + sigkillbypid("{$g['varrun_path']}/cron.pid", "HUP"); + + conf_mount_ro(); +} + +function upnp_action ($action) { + global $g, $config; + switch ($action) { + case "start": + if (file_exists('/var/etc/miniupnpd.conf')) { + @unlink("{$g['varrun_path']}/miniupnpd.pid"); + mwexec_bg("/usr/local/sbin/miniupnpd -f /var/etc/miniupnpd.conf -P {$g['varrun_path']}/miniupnpd.pid"); + } + break; + case "stop": + killbypid("{$g['varrun_path']}/miniupnpd.pid"); + while ((int)exec("/bin/pgrep -a miniupnpd | wc -l") > 0) { + mwexec('killall miniupnpd 2>/dev/null', true); + } + mwexec('/sbin/pfctl -aminiupnpd -Fr 2>&1 >/dev/null'); + mwexec('/sbin/pfctl -aminiupnpd -Fn 2>&1 >/dev/null'); + break; + case "restart": + upnp_action('stop'); + upnp_action('start'); + break; + } +} + +function upnp_start() { + global $config; + + if (!isset($config['installedpackages']['miniupnpd']['config'])) { + return; + } + + if ($config['installedpackages']['miniupnpd']['config'][0]['enable']) { + echo gettext("Starting UPnP service... "); + require_once('/usr/local/pkg/miniupnpd.inc'); + sync_package_miniupnpd(); + echo "done.\n"; + } +} + +function install_cron_job($command, $active = false, $minute = "0", $hour = "*", $monthday = "*", $month = "*", $weekday = "*", $who = "root") { + global $config, $g; + + $is_installed = false; + $cron_changed = true; + + if (!is_array($config['cron'])) { + $config['cron'] = array(); + } + if (!is_array($config['cron']['item'])) { + $config['cron']['item'] = array(); + } + + $x = 0; + foreach ($config['cron']['item'] as $item) { + if (strstr($item['command'], $command)) { + $is_installed = true; + break; + } + $x++; + } + + if ($active) { + $cron_item = array(); + $cron_item['minute'] = $minute; + $cron_item['hour'] = $hour; + $cron_item['mday'] = $monthday; + $cron_item['month'] = $month; + $cron_item['wday'] = $weekday; + $cron_item['who'] = $who; + $cron_item['command'] = $command; + if (!$is_installed) { + $config['cron']['item'][] = $cron_item; + write_config(sprintf(gettext("Installed cron job for %s"), $command)); + } else { + if ($config['cron']['item'][$x] == $cron_item) { + $cron_changed = false; + log_error(sprintf(gettext("Checked cron job for %s, no change needed"), $command)); + } else { + $config['cron']['item'][$x] = $cron_item; + write_config(sprintf(gettext("Updated cron job for %s"), $command)); + } + } + } else { + if ($is_installed == true) { + unset($config['cron']['item'][$x]); + write_config(sprintf(gettext("Removed cron job for %s"), $command)); + } + } + + if ($cron_changed) { + configure_cron(); + } +} + +?> -- cgit v1.1