diff options
author | Scott Ullrich <sullrich@pfsense.org> | 2009-01-20 16:12:33 -0500 |
---|---|---|
committer | Scott Ullrich <sullrich@pfsense.org> | 2009-01-20 16:12:33 -0500 |
commit | d378a8bc50c594d4e75b993242183c5759874e06 (patch) | |
tree | ff315005112659662b492db086f30e4815f6b5d2 /etc | |
parent | fce9b046462521e8e1dfc428a01e1f01f2d483a4 (diff) | |
parent | 9ce5e10ac4fe43e9b580344454dd27172b6c4456 (diff) | |
download | pfsense-d378a8bc50c594d4e75b993242183c5759874e06.zip pfsense-d378a8bc50c594d4e75b993242183c5759874e06.tar.gz |
Merge branch 'master' of http://gitweb.pfsense.org/pfsense/mainline
Diffstat (limited to 'etc')
-rw-r--r-- | etc/inc/IPv6.inc | 918 | ||||
-rw-r--r-- | etc/inc/filter.inc | 196 | ||||
-rw-r--r-- | etc/inc/interfaces.inc | 84 | ||||
-rw-r--r-- | etc/inc/pfsense-utils.inc | 52 | ||||
-rw-r--r-- | etc/inc/system.inc | 145 | ||||
-rw-r--r-- | etc/inc/util.inc | 64 |
6 files changed, 1323 insertions, 136 deletions
diff --git a/etc/inc/IPv6.inc b/etc/inc/IPv6.inc new file mode 100644 index 0000000..45ea2d7 --- /dev/null +++ b/etc/inc/IPv6.inc @@ -0,0 +1,918 @@ +<?php
+
+/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
+
+/**
+ * This file contains the implementation of the Net_IPv6 class
+ *
+ * PHP versions 4 and 5
+ *
+ * LICENSE: This source file is subject to the New BSD license, that is
+ * available through the world-wide-web at
+ * http://www.opensource.org/licenses/bsd-license.php
+ * If you did not receive a copy of the new BSDlicense and are unable
+ * to obtain it through the world-wide-web, please send a note to
+ * license@php.net so we can mail you a copy immediately
+ *
+ * @category Net
+ * @package Net_IPv6
+ * @author Alexander Merz <alexander.merz@web.de>
+ * @copyright 2003-2005 The PHP Group
+ * @license http://www.opensource.org/licenses/bsd-license.php
+ * @version CVS: $Id: IPv6.inc,v 1.2 2008/11/26 03:54:43 sumacob Exp $
+ * @link http://pear.php.net/package/Net_IPv6
+ */
+
+// {{{ constants
+
+/**
+ * Error message if netmask bits was not found
+ * @see isInNetmask
+ */
+define("NET_IPV6_NO_NETMASK_MSG", "Netmask length not found");
+
+/**
+ * Error code if netmask bits was not found
+ * @see isInNetmask
+ */
+define("NET_IPV6_NO_NETMASK", 10);
+
+/**
+ * Address Type: Unassigned (RFC 1884, Section 2.3)
+ * @see getAddressType()
+ */
+define("NET_IPV6_UNASSIGNED", 1);
+
+/**
+ * Address Type: Reserved (RFC 1884, Section 2.3)
+ * @see getAddressType()
+ */
+define("NET_IPV6_RESERVED", 11);
+
+/**
+ * Address Type: Reserved for NSAP Allocation (RFC 1884, Section 2.3)
+ * @see getAddressType()
+ */
+define("NET_IPV6_RESERVED_NSAP", 12);
+
+/**
+ * Address Type: Reserved for IPX Allocation (RFC 1884, Section 2.3)
+ * @see getAddressType()
+ */
+define("NET_IPV6_RESERVED_IPX", 13);
+
+/**
+ * Address Type: Reserved for Geographic-Based Unicast Addresses
+ * (RFC 1884, Section 2.3)
+ * @see getAddressType()
+ */
+define("NET_IPV6_RESERVED_UNICAST_GEOGRAPHIC", 14);
+
+/**
+ * Address Type: Provider-Based Unicast Address (RFC 1884, Section 2.3)
+ * @see getAddressType()
+ */
+define("NET_IPV6_UNICAST_PROVIDER", 22);
+
+/**
+ * Address Type: Multicast Addresses (RFC 1884, Section 2.3)
+ * @see getAddressType()
+ */
+define("NET_IPV6_MULTICAST", 31);
+
+/**
+ * Address Type: Link Local Use Addresses (RFC 1884, Section 2.3)
+ * @see getAddressType()
+ */
+define("NET_IPV6_LOCAL_LINK", 42);
+
+/**
+ * Address Type: Link Local Use Addresses (RFC 1884, Section 2.3)
+ * @see getAddressType()
+ */
+define("NET_IPV6_LOCAL_SITE", 43);
+
+/**
+ * Address Type: address can not assigned to a specific type
+ * @see getAddressType()
+ */
+define("NET_IPV6_UNKNOWN_TYPE", 1001);
+
+// }}}
+// {{{ Net_IPv6
+
+/**
+ * Class to validate and to work with IPv6 addresses.
+ *
+ * @category Net
+ * @package Net_IPv6
+ * @copyright 2003-2005 The PHP Group
+ * @license http://www.opensource.org/licenses/bsd-license.php
+ * @version $Release$
+ * @link http://pear.php.net/package/Net_IPv6
+ * @author Alexander Merz <alexander.merz@web.de>
+ * @author <elfrink at introweb dot nl>
+ * @author Josh Peck <jmp at joshpeck dot org>
+ */
+class Net_IPv6 {
+
+ // {{{ removeNetmaskBits()
+
+ /**
+ * Removes a possible existing netmask specification at an IP addresse.
+ *
+ * @param String $ip the (compressed) IP as Hex representation
+ *
+ * @return String the IP without netmask length
+ * @since 1.1.0
+ * @access public
+ * @static
+ */
+ function removeNetmaskSpec($ip)
+ {
+ $addr = $ip;
+
+ if (false !== strpos($ip, '/')) {
+
+ $elements = explode('/', $ip);
+
+ if (2 == count($elements)) {
+
+ $addr = $elements[0];
+
+ }
+
+ }
+
+ return $addr;
+ }
+
+ /**
+ * Returns a possible existing netmask specification at an IP addresse.
+ *
+ * @param String $ip the (compressed) IP as Hex representation
+ *
+ * @return String the netmask spec
+ * @since 1.1.0
+ * @access public
+ * @static
+ */
+ function getNetmaskSpec($ip)
+ {
+ $spec = '';
+
+ if (false !== strpos($ip, '/')) {
+
+ $elements = explode('/', $ip);
+
+ if (2 == count($elements)) {
+
+ $spec = $elements[1];
+
+ }
+
+ }
+
+ return $spec;
+ }
+
+ // }}}
+ // {{{ getNetmask()
+
+ /**
+ * Calculates the network prefix based on the netmask bits.
+ *
+ * @param String $ip the (compressed) IP in Hex format
+ * @param int $bits if the number of netmask bits is not part of the IP
+ * you must provide the number of bits
+ *
+ * @return String the network prefix
+ * @since 1.1.0
+ * @access public
+ * @static
+ */
+ function getNetmask($ip, $bits = null)
+ {
+ if (null==$bits) {
+
+ $elements = explode('/', $ip);
+
+ if (2 == count($elements)) {
+
+ $addr = $elements[0];
+ $bits = $elements[1];
+
+ } else {
+
+ include_once 'PEAR.inc';
+
+ return PEAR::raiseError(NET_IPV6_NO_NETMASK_MSG,
+ NET_IPV6_NO_NETMASK);
+ }
+
+ } else {
+
+ $addr = $ip;
+
+ }
+
+ $addr = Net_IPv6::uncompress($addr);
+ $binNetmask = str_repeat('1', $bits).str_repeat('0', 128 - $bits);
+
+ return Net_IPv6::_bin2Ip(Net_IPv6::_ip2Bin($addr) & $binNetmask);
+ }
+
+ // }}}
+ // {{{ isInNetmask()
+
+ /**
+ * Checks if an (compressed) IP is in a specific address space.
+ *
+ * IF the IP does not contains the number of netmask bits (F8000::FFFF/16)
+ * then you have to use the $bits parameter.
+ *
+ * @param String $ip the IP to check (eg. F800::FFFF)
+ * @param String $netmask the netmask (eg F800::)
+ * @param int $bits the number of netmask bits to compare,
+ * if not given in $ip
+ *
+ * @return boolean true if $ip is in the netmask
+ * @since 1.1.0
+ * @access public
+ * @static
+ */
+ function isInNetmask($ip, $netmask, $bits=null)
+ {
+ // try to get the bit count
+
+ if (null == $bits) {
+
+ $elements = explode('/', $ip);
+
+ if (2 == count($elements)) {
+
+ $ip = $elements[0];
+ $bits = $elements[1];
+
+ } else if (null == $bits) {
+
+ $elements = explode('/', $netmask);
+
+ if (2 == count($elements)) {
+
+ $netmask = $elements[0];
+ $bits = $elements[1];
+
+ }
+
+ if (null == $bits) {
+
+ include_once 'PEAR.inc';
+ return PEAR::raiseError(NET_IPV6_NO_NETMASK_MSG,
+ NET_IPV6_NO_NETMASK);
+
+ }
+
+ }
+
+ }
+
+ $binIp = Net_IPv6::_ip2Bin(Net_IPv6::removeNetmaskSpec($ip));
+ $binNetmask = Net_IPv6::_ip2Bin(Net_IPv6::removeNetmaskSpec($netmask));
+
+ if (null != $bits
+ && "" != $bits
+ && 0 == strncmp( $binNetmask, $binIp, $bits)) {
+
+ return true;
+
+ }
+
+ return false;
+ }
+
+ // }}}
+ // {{{ getAddressType()
+
+ /**
+ * Returns the type of an IPv6 address.
+ *
+ * RFC 1883, Section 2.3 describes several types of addresses in
+ * the IPv6 addresse space.
+ * Several addresse types are markers for reserved spaces and as
+ * consequence a subject to change.
+ *
+ * @param String $ip the IP address in Hex format,
+ * compressed IPs are allowed
+ *
+ * @return int one of the addresse type constants
+ * @access public
+ * @since 1.1.0
+ * @static
+ *
+ * @see NET_IPV6_UNASSIGNED
+ * @see NET_IPV6_RESERVED
+ * @see NET_IPV6_RESERVED_NSAP
+ * @see NET_IPV6_RESERVED_IPX
+ * @see NET_IPV6_RESERVED_UNICAST_GEOGRAPHIC
+ * @see NET_IPV6_UNICAST_PROVIDER
+ * @see NET_IPV6_MULTICAST
+ * @see NET_IPV6_LOCAL_LINK
+ * @see NET_IPV6_LOCAL_SITE
+ * @see NET_IPV6_UNKNOWN_TYPE
+ */
+ function getAddressType($ip)
+ {
+ $ip = Net_IPv6::removeNetmaskSpec($ip);
+ $binip = Net_IPv6::_ip2Bin($ip);
+
+ if (0 == strncmp('1111111010', $binip, 10)) {
+
+ return NET_IPV6_LOCAL_LINK;
+
+ } else if (0 == strncmp('1111111011', $binip, 10)) {
+
+ return NET_IPV6_LOCAL_SITE;
+
+ } else if (0 == strncmp('111111100', $binip, 9)) {
+
+ return NET_IPV6_UNASSIGNED;
+
+ } else if (0 == strncmp('11111111', $binip, 8)) {
+
+ return NET_IPV6_MULTICAST;
+
+ } else if (0 == strncmp('00000000', $binip, 8)) {
+
+ return NET_IPV6_RESERVED;
+
+ } else if (0 == strncmp('00000001', $binip, 8)
+ || 0 == strncmp('1111110', $binip, 7)) {
+
+ return NET_IPV6_UNASSIGNED;
+
+ } else if (0 == strncmp('0000001', $binip, 7)) {
+
+ return NET_IPV6_RESERVED_NSAP;
+
+ } else if (0 == strncmp('0000010', $binip, 7)) {
+
+ return NET_IPV6_RESERVED_IPX;;
+
+ } else if (0 == strncmp('0000011', $binip, 7) ||
+ 0 == strncmp('111110', $binip, 6) ||
+ 0 == strncmp('11110', $binip, 5) ||
+ 0 == strncmp('00001', $binip, 5) ||
+ 0 == strncmp('1110', $binip, 4) ||
+ 0 == strncmp('0001', $binip, 4) ||
+ 0 == strncmp('001', $binip, 3) ||
+ 0 == strncmp('011', $binip, 3) ||
+ 0 == strncmp('101', $binip, 3) ||
+ 0 == strncmp('110', $binip, 3)) {
+
+ return NET_IPV6_UNASSIGNED;
+
+ } else if (0 == strncmp('010', $binip, 3)) {
+
+ return NET_IPV6_UNICAST_PROVIDER;
+
+ } else if (0 == strncmp('100', $binip, 3)) {
+
+ return NET_IPV6_RESERVED_UNICAST_GEOGRAPHIC;
+
+ }
+
+ return NET_IPV6_UNKNOWN_TYPE;
+ }
+
+ // }}}
+ // {{{ Uncompress()
+
+ /**
+ * Uncompresses an IPv6 adress
+ *
+ * RFC 2373 allows you to compress zeros in an adress to '::'. This
+ * function expects an valid IPv6 adress and expands the '::' to
+ * the required zeros.
+ *
+ * Example: FF01::101 -> FF01:0:0:0:0:0:0:101
+ * ::1 -> 0:0:0:0:0:0:0:1
+ *
+ * @access public
+ * @see Compress()
+ * @static
+ * @param string $ip a valid IPv6-adress (hex format)
+ * @return string the uncompressed IPv6-adress (hex format)
+ */
+ function uncompress($ip)
+ {
+
+ $prefix = Net_IPv6::getPrefixLength($ip);
+
+ if (false === $prefix) {
+
+ $prefix = '';
+
+ } else {
+
+ $ip = Net_IPv6::removePrefixLength($ip);
+ $prefix = '/'.$prefix;
+
+ }
+
+ $netmask = Net_IPv6::getNetmaskSpec($ip);
+ $uip = Net_IPv6::removeNetmaskSpec($ip);
+
+ $c1 = -1;
+ $c2 = -1;
+
+ if (false !== strpos($uip, '::') ) {
+
+ list($ip1, $ip2) = explode('::', $uip);
+
+ if("" == $ip1) {
+
+ $c1 = -1;
+
+ } else {
+
+ $pos = 0;
+
+ if (0 < ($pos = substr_count($ip1, ':'))) {
+
+ $c1 = $pos;
+
+ } else {
+
+ $c1 = 0;
+
+ }
+ }
+ if ("" == $ip2) {
+
+ $c2 = -1;
+
+ } else {
+
+ $pos = 0;
+
+ if (0 < ($pos = substr_count($ip2, ':'))) {
+
+ $c2 = $pos;
+
+ } else {
+
+ $c2 = 0;
+
+ }
+
+ }
+
+ if (strstr($ip2, '.')) {
+
+ $c2++;
+
+ }
+ if (-1 == $c1 && -1 == $c2) { // ::
+
+ $uip = "0:0:0:0:0:0:0:0";
+
+ } else if (-1 == $c1) { // ::xxx
+
+ $fill = str_repeat('0:', 7-$c2);
+ $uip = str_replace('::', $fill, $uip);
+
+ } else if (-1 == $c2) { // xxx::
+
+ $fill = str_repeat(':0', 7-$c1);
+ $uip = str_replace('::', $fill, $uip);
+
+ } else { // xxx::xxx
+
+ $fill = str_repeat(':0:', 6-$c2-$c1);
+ $uip = str_replace('::', $fill, $uip);
+ $uip = str_replace('::', ':', $uip);
+
+ }
+ }
+ if ('' != $netmask) {
+
+ $uip = $uip.'/'.$netmask;
+
+ }
+
+ return $uip.$prefix;
+ }
+
+ // }}}
+ // {{{ Compress()
+
+ /**
+ * Compresses an IPv6 adress
+ *
+ * RFC 2373 allows you to compress zeros in an adress to '::'. This
+ * function expects an valid IPv6 adress and compresses successive zeros
+ * to '::'
+ *
+ * Example: FF01:0:0:0:0:0:0:101 -> FF01::101
+ * 0:0:0:0:0:0:0:1 -> ::1
+ *
+ * @access public
+ * @see Uncompress()
+ * @static
+ * @param string $ip a valid IPv6-adress (hex format)
+ * @return string the compressed IPv6-adress (hex format)
+ * @author elfrink at introweb dot nl
+ */
+ function compress($ip)
+ {
+ $prefix = Net_IPv6::getPrefixLength($ip);
+
+ if (false === $prefix) {
+
+ $prefix = '';
+
+ } else {
+
+ $ip = Net_IPv6::removePrefixLength($ip);
+ $prefix = '/'.$prefix;
+
+ }
+
+ $netmask = Net_IPv6::getNetmaskSpec($ip);
+ $ip = Net_IPv6::removeNetmaskSpec($ip);
+
+ if (!strstr($ip, '::')) {
+
+ $ipp = explode(':',$ip);
+
+ for ($i = 0; $i < count($ipp); $i++) {
+
+ $ipp[$i] = dechex(hexdec($ipp[$i]));
+
+ }
+
+ $cip = ':' . join(':',$ipp) . ':';
+
+ preg_match_all("/(:0)+/", $cip, $zeros);
+
+ if (count($zeros[0]) > 0) {
+
+ $match = '';
+
+ foreach($zeros[0] as $zero) {
+
+ if (strlen($zero) > strlen($match)) {
+
+ $match = $zero;
+
+ }
+ }
+
+ $cip = preg_replace('/' . $match . '/', ':', $cip, 1);
+
+ }
+
+ $cip = preg_replace('/((^:)|(:$))/', '' ,$cip);
+ $cip = preg_replace('/((^:)|(:$))/', '::' ,$cip);
+
+ }
+ if ('' != $netmask) {
+
+ $cip = $cip.'/'.$netmask;
+
+ }
+
+ return $cip.$prefix;
+ }
+
+ // }}}
+ // {{{ SplitV64()
+
+ /**
+ * Splits an IPv6 adress into the IPv6 and a possible IPv4 part
+ *
+ * RFC 2373 allows you to note the last two parts of an IPv6 adress as
+ * an IPv4 compatible adress
+ *
+ * Example: 0:0:0:0:0:0:13.1.68.3
+ * 0:0:0:0:0:FFFF:129.144.52.38
+ *
+ * @param string $ip a valid IPv6-adress (hex format)
+ *
+ * @return array [0] contains the IPv6 part,
+ * [1] the IPv4 part (hex format)
+ * @access public
+ * @static
+ */
+ function SplitV64($ip, $uncompress = true)
+ {
+ $ip = Net_IPv6::removeNetmaskSpec($ip);
+
+ if ($uncompress) {
+
+ $ip = Net_IPv6::Uncompress($ip);
+
+ }
+
+ if (strstr($ip, '.')) {
+
+ $pos = strrpos($ip, ':');
+ $ip{$pos} = '_';
+ $ipPart = explode('_', $ip);
+
+ return $ipPart;
+
+ } else {
+
+ return array($ip, "");
+
+ }
+ }
+
+ // }}}
+ // {{{ checkIPv6()
+
+ /**
+ * Checks an IPv6 adress
+ *
+ * Checks if the given IP is IPv6-compatible
+ *
+ * @access public
+ * @static
+ * @param string $ip a valid IPv6-adress
+ * @return boolean true if $ip is an IPv6 adress
+ */
+ function checkIPv6($ip)
+ {
+ $ip = Net_IPv6::removePrefixLength($ip);
+ $ip = Net_IPv6::removeNetmaskSpec($ip);
+
+ $ipPart = Net_IPv6::SplitV64($ip);
+ $count = 0;
+
+ if (!empty($ipPart[0]))
+ {
+ $ipv6 =explode(':', $ipPart[0]);
+
+ for ($i = 0; $i < count($ipv6); $i++) {
+
+ $dec = hexdec($ipv6[$i]);
+ $hex = strtoupper(preg_replace("/^[0]{1,3}(.*[0-9a-fA-F])$/",
+ "\\1",
+ $ipv6[$i]));
+
+ if ($ipv6[$i] >= 0 && $dec <= 65535
+ && $hex == strtoupper(dechex($dec))) {
+
+ $count++;
+
+ }
+
+ }
+
+ if (8 == $count) {
+
+ return true;
+
+ } else if (6 == $count and !empty($ipPart[1])) {
+
+ $ipv4 = explode('.',$ipPart[1]);
+ $count = 0;
+
+ for ($i = 0; $i < count($ipv4); $i++) {
+
+ if ($ipv4[$i] >= 0 && (integer)$ipv4[$i] <= 255
+ && preg_match("/^\d{1,3}$/", $ipv4[$i])) {
+
+ $count++;
+
+ }
+
+ }
+
+ if (4 == $count) {
+
+ return true;
+
+ }
+
+ } else {
+
+ return false;
+
+ }
+
+ } else {
+
+ return false;
+
+ }
+
+ }
+
+ // }}}
+ // {{{ getPrefixLength()
+
+ /**
+ * Tests for a prefix length specification in the address
+ * and returns the prefix length, if exists
+ *
+ * @param String $ip a valid ipv6 address
+ *
+ * @return Mixed the prefix as String or false, if no prefix was found
+ * @access public
+ * @static
+ */
+ function getPrefixLength($ip)
+ {
+ if (preg_match("/^([0-9a-fA-F:]{2,39})\/(\d{1,3})*$/",
+ $ip, $matches)) {
+
+ return $matches[2];
+
+ } else {
+
+ return false;
+
+ }
+
+ }
+
+ // }}}
+ // {{{ removePrefixLength()
+
+ /**
+ * Tests for a prefix length specification in the address
+ * and removes the prefix length, if exists
+ *
+ * @param String $ip a valid ipv6 address
+ *
+ * @return String the address without a prefix length
+ * @access public
+ * @static
+ */
+ function removePrefixLength($ip)
+ {
+ $pos = strrpos($ip, '/');
+
+ if (false !== $pos) {
+
+ return substr($ip, 0, $pos);
+
+ }
+
+ return $ip;
+ }
+
+ // }}}
+
+ // {{{ _parseAddress()
+
+ /**
+ * Returns the lowest and highest IPv6 address
+ * for a given IP and netmask specification
+ *
+ * The netmask may be a part of the $ip or
+ * the number of netwask bits is provided via $bits
+ *
+ * The result is an indexed array. The key 'start'
+ * contains the lowest possible IP adress. The key
+ * 'end' the highest address.
+ *
+ * @param String $ip the IPv6 address
+ * @param String $bits the optional count of netmask bits
+ *
+ * @return Array ['start', 'end'] the lowest and highest IPv6 address
+ * @access public
+ * @static
+ * @author Nicholas Williams
+ */
+
+ function parseAddress($ipToParse, $bits = null)
+ {
+
+ $ip = null;
+ $bitmask = null;
+
+ if( null == $bits )
+ {
+
+ $elements = explode('/', $ipToParse);
+
+ if( 2 == count($elements) ) {
+
+ $ip = Net_IPv6::uncompress($elements[0]);
+ $bitmask = $elements[1];
+
+ } else {
+
+ include_once 'PEAR.inc';
+
+ return PEAR::raiseError(NET_IPV6_NO_NETMASK_MSG,
+ NET_IPV6_NO_NETMASK);
+ }
+ }
+ else
+ {
+
+ $ip = Net_IPv6::uncompress($ipToParse);
+ $bitmask = $bits;
+
+ }
+
+ $binNetmask = str_repeat('1', $bitmask).
+ str_repeat('0', 128 - $bitmask);
+ $maxNetmask = str_repeat('1', 128);
+ $netmask = Net_IPv6::_bin2Ip($binNetmask);
+
+ $startAddress = Net_IPv6::_bin2Ip(Net_IPv6::_ip2Bin($ip)
+ & $binNetmask);
+ $endAddress = Net_IPv6::_bin2Ip(Net_IPv6::_ip2Bin($ip)
+ | ($binNetmask ^ $maxNetmask));
+
+ return array('start' => $startAddress, 'end' => $endAddress);
+ }
+
+ // }}}
+
+ // {{{ _ip2Bin()
+
+ /**
+ * Converts an IPv6 address from Hex into Binary representation.
+ *
+ * @param String $ip the IP to convert (a:b:c:d:e:f:g:h),
+ * compressed IPs are allowed
+ *
+ * @return String the binary representation
+ * @access private
+ @ @since 1.1.0
+ */
+ function _ip2Bin($ip)
+ {
+ $binstr = '';
+
+ $ip = Net_IPv6::removeNetmaskSpec($ip);
+ $ip = Net_IPv6::Uncompress($ip);
+
+ $parts = explode(':', $ip);
+
+ foreach($parts as $v) {
+
+ $str = base_convert($v, 16, 2);
+ $binstr .= str_pad($str, 16, '0', STR_PAD_LEFT);
+
+ }
+
+ return $binstr;
+ }
+
+ // }}}
+ // {{{ _bin2Ip()
+
+ /**
+ * Converts an IPv6 address from Binary into Hex representation.
+ *
+ * @param String $ip the IP as binary
+ *
+ * @return String the uncompressed Hex representation
+ * @access private
+ @ @since 1.1.0
+ */
+ function _bin2Ip($bin)
+ {
+ $ip = "";
+
+ if (strlen($bin) < 128) {
+
+ $bin = str_pad($str, 128, '0', STR_PAD_LEFT);
+
+ }
+
+ $parts = str_split($bin, "16");
+
+ foreach($parts as $v) {
+
+ $str = base_convert($v, 2, 16);
+ $ip .= $str.":";
+
+ }
+
+ $ip = substr($ip, 0,-1);
+
+ return $ip;
+ }
+
+ // }}}
+}
+// }}}
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * c-hanging-comment-ender-p: nil
+ * End:
+ */
+
+?> diff --git a/etc/inc/filter.inc b/etc/inc/filter.inc index 4867aea..fc3af04 100644 --- a/etc/inc/filter.inc +++ b/etc/inc/filter.inc @@ -40,7 +40,8 @@ require_once("functions.inc"); require_once("pkg-utils.inc"); require_once("notices.inc"); -require_once ("shaper.inc"); +require_once("shaper.inc"); +require_once("IPv6.inc"); /* holds the items that will be executed *AFTER* the filter is fully loaded */ $after_filter_configure_run = array(); @@ -176,6 +177,7 @@ function filter_configure_sync() { $max_states = pfsense_default_state_size(); $rules .= "set limit states {$max_states}\n"; } + $rules .= "set skip on { lo0, gif, tun, enc }\n"; $rules .= "\n"; update_filter_reload_status("Setting up SCRUB information"); $rules .= filter_generate_scrubing(); @@ -391,12 +393,15 @@ function generate_optcfg_array() $oic = array(); $oic['if'] = get_real_interface($if); $oic['ip'] = get_interface_ip($if); + $oic['ip6'] = get_interface_ip($if, 'ipv6'); if (!is_ipaddr($oc['ipaddr']) && !empty($oc['ipaddr'])) $oic['type'] = $oc['ipaddr']; $oic['sn'] = get_interface_subnet($if); + $oic['sn6'] = get_interface_subnet($if, 'ipv6'); $oic['mtu'] = $oc['mtu']; $oic['descr'] = $ifdetail; $oic['sa'] = gen_subnet($oic['ip'], $oic['sn']); + $oic['sa6'] = $oic['ip6'] != '' ? Net_IPv6::getNetmask($oic['ip6'], $oic['sn6']) : null; $oic['nonat'] = $oc['nonat']; $oic['ftpproxy'] = !isset($oc['disableftpproxy']); $oic['alias-address'] = $oc['alias-address']; @@ -1240,13 +1245,24 @@ function generate_user_filter_rule($rule) /* do not process reply-to for gateway'd rules */ if ($rule['gateway'] == "" && interface_has_gateway($rule['interface'])) { - $rg = get_interface_gateway($rule['interface']); - if (is_ipaddr($rg)) { - $aline['reply'] = "reply-to ( {$ifcfg['if']} {$rg} ) "; - } else { - if($rule['interface'] <> "pptp") { + if (Net_IPv6::checkIPv6($rule['source']['address']) || Net_IPv6::checkIPv6($rule['destination']['address'])) { + $rg = get_interface_gateway($rule['interface'], 'IPv6'); + + if (Net_IPv6::checkIPv6($rg)) { + $aline['reply'] = "reply-to ( {$ifcfg['if']} {$rg} ) "; + } else { log_error("Could not find gateway for interface({$rule['interface']})."); } + } else { + $rg = get_interface_gateway($rule['interface']); + + if (is_ipaddr($rg)) { + $aline['reply'] = "reply-to ( {$ifcfg['if']} {$rg} ) "; + } else { + if($rule['interface'] <> "pptp") { + log_error("Could not find gateway for interface({$rule['interface']})."); + } + } } } /* if user has selected a custom gateway, lets work with it */ @@ -1300,12 +1316,29 @@ function generate_user_filter_rule($rule) } } if (isset($rule['protocol'])) { - if($rule['protocol'] == "tcp/udp") - $aline['prot'] = " proto { tcp udp } "; - elseif($rule['protocol'] == "icmp") + switch($rule['protocol']) { + case 'tcp/udp': + $aline['prot'] = " inet proto { tcp udp } "; + break; + case 'tcp6/udp6': + $aline['prot'] = " inet6 proto { tcp udp } "; + break; + case 'tcp6': + $aline['prot'] = " inet6 proto tcp "; + break; + case 'udp6': + $aline['prot'] = " inet6 proto udp "; + break; + case 'icmp': $aline['prot'] = " inet proto icmp "; - else + break; + case 'icmp6': + $aline['prot'] = " inet6 proto ipv6-icmp "; + break; + default: $aline['prot'] = " proto {$rule['protocol']} "; + break; + } } else { if($rule['source']['port'] <> "" || $rule['destination']['port'] <> "") { $aline['prot'] = " proto tcp "; @@ -1328,30 +1361,58 @@ function generate_user_filter_rule($rule) } } else { switch ($rule['source']['network']) { - case 'wanip': - $src = $FilterIflist["wan"]['ip']; - break; - case 'lanip': - $src = $FilterIflist["lan"]['ip']; - break; - case 'lan': - $lansa = $FilterIflist['lan']['sa']; - $lansn = $FilterIflist['lan']['sn']; - $src = "{$lansa}/{$lansn}"; - break; - case 'pptp': - $pptpsa = gen_subnet($FilterIflist['pptp']['ip'], $FilterIflist['pptp']['sn']); - $pptpsn = $FilterIflist['pptp']['sn']; - $src = "{$pptpsa}/{$pptpsn}"; - break; - case 'pppoe': - $pppoesa = gen_subnet($FilterIflist['pppoe']['ip'], $FilterIflist['pppoe']['sn']); - $pppoesn = $FilterIflist['pppoe']['sn']; - $src = "{$pppoesa}/{$pppoesn}"; - break; + case 'wanip': + if (isset($FilterIflist['wan']['ip6']) && isset($FilterIflist['wan']['ip'])) { + $src = "{ {$FilterIflist['wan']['ip6']}, {$FilterIflist['wan']['ip']} }"; + } else if (isset($FilterIflist['wan']['ip6'])) { + $src = $FilterIflist['wan']['ip6']; + } else { + $src = $FilterIflist['wan']['ip']; } - if (isset($rule['source']['not'])) $src = "!{$src}"; + + break; + case 'lanip': + if (isset($FilterIflist['lan']['ip6']) && isset($FilterIflist['lan']['ip'])) { + $src = "{ {$FilterIflist['lan']['ip6']}, {$FilterIflist['lan']['ip']} }"; + } else if (isset($FilterIflist['lan']['ip6'])) { + $src = $FilterIflist['lan']['ip6']; + } else { + $src = $FilterIflist['lan']['ip']; + } + + break; + case 'lan': + if ($FilterIflist['lan']['sa6'] != '' && $FilterIflist['lan']['sn6'] != '' && + $FilterIflist['lan']['sa'] != '' && $FilterIflist['lan']['sn'] != '') { + $lansa = $FilterIflist['lan']['sa']; + $lansn = $FilterIflist['lan']['sn']; + $lansa6 = $FilterIflist['lan']['sa6']; + $lansn6 = $FilterIflist['lan']['sn6']; + $src = "{ $lansa/$lansn, $lansa6/$lansn6 }"; + } else if ($FilterIflist['lan']['sa6'] != '' && $FilterIflist['lan']['sn6'] != '') { + $lansa6 = $FilterIflist['lan']['sa6']; + $lansn6 = $FilterIflist['lan']['sn6']; + $src = "{ $lansa6/$lansn6 }"; + } else { + $lansa = $FilterIflist['lan']['sa']; + $lansn = $FilterIflist['lan']['sn']; + $src = "{ $lansa/$lansn }"; + } + + break; + case 'pptp': + $pptpsa = gen_subnet($FilterIflist['pptp']['ip'], $FilterIflist['pptp']['sn']); + $pptpsn = $FilterIflist['pptp']['sn']; + $src = "{$pptpsa}/{$pptpsn}"; + break; + case 'pppoe': + $pppoesa = gen_subnet($FilterIflist['pppoe']['ip'], $FilterIflist['pppoe']['sn']); + $pppoesn = $FilterIflist['pppoe']['sn']; + $src = "{$pppoesa}/{$pppoesn}"; + break; } + if (isset($rule['source']['not'])) $src = "!{$src}"; + } } else if ($rule['source']['address']) { $expsrc = alias_expand($rule['source']['address']); if (isset($rule['source']['not'])) @@ -1427,27 +1488,54 @@ function generate_user_filter_rule($rule) if (isset($rule['destination']['not'])) $dst = " !{$dst}"; } else { switch ($rule['destination']['network']) { - case 'wanip': - $dst = $FilterIflist["wan"]['ip']; - break; - case 'lanip': - $dst = $FilterIflist["lan"]['ip']; - break; - case 'lan': + case 'wanip': + if (isset($FilterIflist['wan']['ip6']) && isset($FilterIflist['wan']['ip'])) { + $dst = "{ {$FilterIflist['wan']['ip6']}, {$FilterIflist['wan']['ip']} }"; + } else if (isset($FilterIflist['wan']['ip6'])) { + $dst = $FilterIflist['wan']['ip6']; + } else { + $dst = $FilterIflist['wan']['ip']; + } + + break; + case 'lanip': + if (isset($FilterIflist['lan']['ip6']) && isset($FilterIflist['lan']['ip'])) { + $dst = "{ {$FilterIflist['lan']['ip6']}, {$FilterIflist['lan']['ip']} }"; + } else if (isset($FilterIflist['lan']['ip6'])) { + $dst = $FilterIflist['lan']['ip6']; + } else { + $dst = $FilterIflist['lan']['ip']; + } + + break; + case 'lan': + if (isset($FilterIflist['lan']['sa6']) && isset($FilterIflist['lan']['sn6']) && + isset($FilterIflist['lan']['sa']) && isset($FilterIflist['lan']['sn'])) { $lansa = $FilterIflist['lan']['sa']; $lansn = $FilterIflist['lan']['sn']; - $dst = "{$lansa}/{$lansn}"; - break; - case 'pptp': - $pptpsa = gen_subnet($FilterIflist['pptp']['ip'], $FilterIflist['pptp']['sn']); - $pptpsn = $FilterIflist['pptp']['sn']; - $dst = "{$pptpsa}/{$pptpsn}"; - break; - case 'pppoe': - $pppoesa = gen_subnet($FilterIflist['pppoe']['ip'], $FilterIflist['pppoe']['sn']); - $pppoesn = $FilterIflist['pppoe']['sn']; - $dst = "{$pppoesa}/{$pppoesn}"; - break; + $lansa6 = $FilterIflist['lan']['sa6']; + $lansn6 = $FilterIflist['lan']['sn6']; + $dst = "{ $lansa/$lansn, $lansa6/$lansn6 }"; + } else if (isset($FilterIflist['lan']['sa6']) && isset($FilterIflist['lan']['sn6'])) { + $lansa6 = $FilterIflist['lan']['sa6']; + $lansn6 = $FilterIflist['lan']['sn6']; + $dst = "{ $lansa6/$lansn6 }"; + } else { + $lansa = $FilterIflist['lan']['sa']; + $lansn = $FilterIflist['lan']['sn']; + $dst = "{ $lansa/$lansn }"; + } + break; + case 'pptp': + $pptpsa = gen_subnet($FilterIflist['pptp']['ip'], $FilterIflist['pptp']['sn']); + $pptpsn = $FilterIflist['pptp']['sn']; + $dst = "{$pptpsa}/{$pptpsn}"; + break; + case 'pppoe': + $pppoesa = gen_subnet($FilterIflist['pppoe']['ip'], $FilterIflist['pppoe']['sn']); + $pppoesn = $FilterIflist['pppoe']['sn']; + $dst = "{$pppoesa}/{$pppoesn}"; + break; } if (isset($rule['destination']['not'])) $dst = " !{$dst}"; } @@ -1520,6 +1608,9 @@ function generate_user_filter_rule($rule) if (($rule['protocol'] == "icmp") && $rule['icmptype']) { $aline['icmp-type'] = "icmp-type {$rule['icmptype']} "; } + if (($rule['protocol'] == "icmp6") && $rule['icmp6type']) { + $aline['icmp-type'] = "icmp6-type {$rule['icmp6type']} "; + } if ($type == "pass") { if (isset($rule['tag']) && $rule['tag'] <> "") $aline['tag'] = " tag " .$rule['tag']. " "; @@ -2433,7 +2524,7 @@ function generate_ipsec_filter_rules() { $interface = $FilterIflist[$parentinterface]['if']; /* Just in case */ - if (!is_ipaddr($gateway) || empty($interface)) { + if ((!is_ipaddr($gateway) && !Net_IPv6::checkIPv6($gateway)) || empty($interface)) { $route_to = " "; $reply_to = " "; } else { @@ -2441,6 +2532,7 @@ function generate_ipsec_filter_rules() { $reply_to = " reply-to ( $interface $gateway ) "; } + /* TODO: Put IPv6 here */ /* Add rules to allow IKE to pass */ $shorttunneldescr = substr($descr, 0, 36); $ipfrules .= <<<EOD diff --git a/etc/inc/interfaces.inc b/etc/inc/interfaces.inc index 23a5ca6..c3f507b 100644 --- a/etc/inc/interfaces.inc +++ b/etc/inc/interfaces.inc @@ -51,6 +51,7 @@ function interfaces_bring_up($interface) { function interfaces_loopback_configure() { mwexec("/sbin/ifconfig lo0 127.0.0.1"); + mwexec("/sbin/ifconfig lo0 inet6 ::1 prefixlen 128"); interfaces_bring_up("lo0"); return 0; } @@ -970,7 +971,8 @@ EOD; } -function interfaces_ipalias_configure() { +function interfaces_ipalias_configure() +{ global $g, $config; if(isset($config['system']['developerspew'])) { $mt = microtime(); @@ -981,7 +983,11 @@ function interfaces_ipalias_configure() { foreach ($viparr as $vip) { if ($vip['mode'] == "ipalias") { $if = get_real_interface($vip['interface']); - mwexec("/sbin/ifconfig " . escapeshellarg($if) . " " . $vip['subnet'] . "/" . escapeshellarg($vip['subnet_bits']) . " alias"); + if ($vip['subnet_ipv6'] != '') { + mwexec("/sbin/ifconfig " . escapeshellarg($if) . " inet6 {$vip['subnet_ipv6']} alias"); + } else { + mwexec("/sbin/ifconfig " . escapeshellarg($if) . " " . $vip['subnet'] . "/" . escapeshellarg($vip['subnet_bits']) . " alias"); + } } } } @@ -1258,12 +1264,21 @@ function interface_configure($interface = "wan") { $realif = get_real_interface($interface); - if(!$g['booting']) { - /* remove all addresses first */ + if (!$g['booting']) { + /* remove all IPv4 addresses */ while (mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " -alias", true) == 0); interface_bring_down($interface); + + /* remove all IPv6 addresses */ + $str = <<<EOD + while i="`/sbin/ifconfig $realif | /usr/bin/grep inet6 | /usr/bin/grep -m 1 -v '%'`"; do + ifconfig $realif \$i delete + done +EOD; + mwexec("($str)"); mwexec("/sbin/ifconfig " . escapeshellarg($wancfg['if']) . " down"); - } + } + /* wireless configuration? */ if (is_array($wancfg['wireless'])) interface_wireless_configure($realif, $wancfg['wireless']); @@ -1326,15 +1341,32 @@ function interface_configure($interface = "wan") { escapeshellarg($wancfg['ipaddr'] . "/" . $wancfg['subnet']) . " " . escapeshellarg($wancfg['pointtopoint']) . " up"); } else { - if($wancfg['ipaddr'] && $wancfg['subnet']) + if($wancfg['ipaddr'] && $wancfg['subnet']) { mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " " . escapeshellarg($wancfg['ipaddr'] . "/" . $wancfg['subnet'])); + } } } - if (is_ipaddr($wancfg['gateway'])) + if ($wancfg['ipaddr_ipv6'] <> "" && $wancfg['subnet_ipv6'] <> "") { + if (isset($wancfg['ispointtopoint_ipv6']) && $wancfg['pointtopoint_ipv6']) { + // TODO: do something + } else { + mwexec("/sbin/ifconfig " . escapeshellarg($realif) . + " inet6 " . escapeshellarg($wancfg['ipaddr_ipv6'] . "/" . + $wancfg['subnet_ipv6'])); + } + } + + if (is_ipaddr($wancfg['gateway'])) { file_put_contents("/tmp/{$realif}_router", $wancfg['gateway']); + } + + if (Net_IPv6::checkIPv6($wancfg['gateway_ipv6'])) { + // TODO: IPv6 needs to be configured too + file_put_contents("/tmp/{$realif}_router_ipv6", $wancfg['gateway_ipv6']); + } } if($wancfg['if']) interfaces_bring_up($wancfg['if']); @@ -1502,6 +1534,10 @@ pppoeclient: EOD; + /* + * XXX: mpd seems to use netgraph interfaces so ngX interfaces are created + * instead of pppoeX. =) -simoncpu- + */ if ($interface == "wan") $realif = "pppoe0"; else { @@ -1816,6 +1852,10 @@ function get_real_interface($interface = "wan") { } break; case "pppoe": + /* + * XXX: mpd seems to use netgraph interfaces so ngX interfaces are created + * instead of pppoeX. =) -simoncpu- + */ if ($if == "wan") $wanif = "pppoe0"; else @@ -1841,28 +1881,42 @@ function get_real_interface($interface = "wan") { return $wanif; } -function get_interface_ip($interface = "wan") { +function get_interface_ip($interface = "wan", $type = "ipv4") +{ + global $config, $g; + $realif = get_real_interface($interface); /* Do we really come here for these interfaces ?! */ if (in_array($realif, array("pptp", "pppoe", "openvpn", "enc0" /* , "ppp" */))) return ""; - $curip = find_interface_ip($realif); - if ($curip && is_ipaddr($curip) && ($curip != "0.0.0.0")) - return $curip; + $curip = find_interface_ip($realif, false, $type); + + if ($type == 'ipv6') { + if ($curip && Net_IPv6::checkIPv6($curip)) { + return $curip; + } + } else { + if ($curip && is_ipaddr($curip) && ($curip != "0.0.0.0")) { + return $curip; + } + } return null; } -function get_interface_subnet($interface = "wan") { +function get_interface_subnet($interface = "wan", $type = "ipv4") +{ $realif = get_real_interface($interface); /* Do we really come here for these interfaces ?! */ - if (in_array($realif, array("pptp", "pppoe", "openvpn", "enc0" /* , "ppp" */))) + if (in_array($realif, array("pptp", "pppoe", "openvpn", "enc0" /* , "ppp" */))) { return ""; + } - $cursn = find_interface_subnet($realif); - if (!empty($cursn)) + $cursn = find_interface_subnet($realif, false, $type); + if (!empty($cursn)) { return $cursn; + } return null; } diff --git a/etc/inc/pfsense-utils.inc b/etc/inc/pfsense-utils.inc index 300c102..c493371 100644 --- a/etc/inc/pfsense-utils.inc +++ b/etc/inc/pfsense-utils.inc @@ -1424,36 +1424,61 @@ function convert_ip_to_network_format($ip, $subnet) { /* * find_interface_ip($interface): return the interface ip (first found) */ -function find_interface_ip($interface, $flush = false) { +function find_interface_ip($interface, $flush = false, $type = "ipv4") { global $interface_ip_arr_cache; + global $interface_ip_arr_cache_ipv6; // putting this into a 2D array is a good idea $interface = str_replace("\n", "", $interface); if(does_interface_exist($interface) == false) return; /* Setup IP cache */ - if (!isset($interface_ip_arr_cache[$interface]) or $flush) { - $interface_ip_arr_cache[$interface] = exec_command("/sbin/ifconfig {$interface} | /usr/bin/grep -w \"inet\" | /usr/bin/cut -d\" \" -f 2| /usr/bin/head -1"); - $interface_ip_arr_cache[$interface] = str_replace("\n", "", $interface_ip_arr_cache[$interface]); - } + if ($type == 'ipv4') { + if (!isset($interface_ip_arr_cache[$interface]) or $flush) { + $interface_ip_arr_cache[$interface] = exec_command("/sbin/ifconfig {$interface} | /usr/bin/grep -w \"inet\" | /usr/bin/cut -d\" \" -f 2| /usr/bin/head -1"); + $interface_ip_arr_cache[$interface] = str_replace("\n", "", $interface_ip_arr_cache[$interface]); + } - return $interface_ip_arr_cache[$interface]; + return $interface_ip_arr_cache[$interface]; + } else { + /* + This assumes that the first IP in ifconfig is the "real" IP. + What if the first IP is an alias? + */ + if (!isset($interface_ip_arr_cache_ipv6[$interface]) or $flush) { + $interface_ip_arr_cache_ipv6[$interface] = exec_command("/sbin/ifconfig {$interface} | /usr/bin/grep -w \"inet6\" | /usr/bin/grep -v '%' | /usr/bin/cut -d\" \" -f 2| /usr/bin/head -1"); + $interface_ip_arr_cache_ipv6[$interface] = str_replace("\n", "", $interface_ip_arr_cache_ipv6[$interface]); + } + return $interface_ip_arr_cache_ipv6[$interface]; + } } -function find_interface_subnet($interface, $flush = false) +function find_interface_subnet($interface, $flush = false, $type = "ipv4") { global $interface_sn_arr_cache; + global $interface_sn_arr_cache_ipv6; $interface = str_replace("\n", "", $interface); - if (does_interface_exist($interface) == false) + if (does_interface_exist($interface) == false) { return; - - if (!isset($interface_sn_arr_cache[$interface]) or $flush) { - $interface_sn_arr_cache[$interface] = exec_command("/sbin/ifconfig {$interface} | /usr/bin/grep -w \"inet\" | /usr/bin/cut -d\" \" -f 4 | /usr/bin/head -1"); - $interface_sn_arr_cache[$interface] = strlen(str_replace("0", "", base_convert(str_replace("\n", "", $interface_sn_arr_cache[$interface]),16, 2))); } - return $interface_sn_arr_cache[$interface]; + if ($type == 'ipv4') { + if (!isset($interface_sn_arr_cache[$interface]) or $flush) { + $interface_sn_arr_cache[$interface] = exec_command("/sbin/ifconfig {$interface} | /usr/bin/grep -w \"inet\" | /usr/bin/cut -d\" \" -f 4 | /usr/bin/head -1"); + $interface_sn_arr_cache[$interface] = strlen(str_replace("0", "", base_convert(str_replace("\n", "", $interface_sn_arr_cache[$interface]),16, 2))); + log_error("int:{$interface} - generated subnet mask {$interface_sn_arr_cache[$interface]}"); + } + + return $interface_sn_arr_cache[$interface]; + } else { + if (!isset($interface_sn_arr_cache_ipv6[$interface]) or $flush) { + $interface_sn_arr_cache_ipv6[$interface] = exec_command("/sbin/ifconfig {$interface} | /usr/bin/grep -w \"inet6\" | /usr/bin/grep -v '%' | /usr/bin/cut -d\" \" -f 4 | /usr/bin/head -1"); + log_error("int:{$interface} - IPv6 prefixlen {$interface_sn_arr_cache_ipv6[$interface]}"); + } + + return $interface_sn_arr_cache_ipv6[$interface]; + } } function guess_interface_from_ip($ipaddress) { @@ -3488,5 +3513,4 @@ function compare_hostname_to_dnscache($hostname) { } } - ?> diff --git a/etc/inc/system.inc b/etc/inc/system.inc index 36aa641..4359782 100644 --- a/etc/inc/system.inc +++ b/etc/inc/system.inc @@ -218,9 +218,14 @@ function system_routing_configure() { return 1; } while (!feof($fd)) { - $oldrt = trim(fgets($fd)); - if (($oldrt) && (stristr($route_str, $oldrt))) - mwexec("/sbin/route delete " . escapeshellarg($oldrt)); + $oldrt = fgets($fd); + if ($oldrt && stristr($route_str, trim($oldrt))) { + if (Net_IPv6::checkIPv6(trim($oldrt))) { + mwexec("/sbin/route delete -inet6 " . escapeshellarg(trim($oldrt))); + } else { + mwexec("/sbin/route delete " . escapeshellarg(trim($oldrt))); + } + } } fclose($fd); unlink("{$g['vardb_path']}/routes.db"); @@ -229,19 +234,21 @@ function system_routing_configure() { /* if list */ $iflist = get_configured_interface_list(); - $dont_remove_route = false; - foreach ($iflist as $ifent => $ifname) { - /* do not process interfaces that will end up with gateways */ - if (interface_has_gateway($ifent)) - $dont_remove_route = true; - } + $dont_remove_route = false; + foreach ($iflist as $ifent => $ifname) { + /* do not process interfaces that will end up with gateways */ + if (interface_has_gateway($ifent)) + $dont_remove_route = true; + } - if($config['interfaces']['wan']['ipaddr'] == "carpdev-dhcp") + if($config['interfaces']['wan']['ipaddr'] == "carpdev-dhcp") { $dont_remove_route = true; + } if($dont_remove_route == false) { - /* remove default route */ - mwexec("/sbin/route delete default", true); + /* remove default routes */ + mwexec("/sbin/route delete default"); + mwexec("/sbin/route delete -inet6 default"); } $dont_add_route = false; @@ -256,14 +263,41 @@ function system_routing_configure() { if($dont_add_route == false) { if(is_array($config['gateways']['gateway_item'])) { + $gatewayip = ''; + $interfacegw = ''; + + $gatewayip_ipv6 = ''; + $interfacegw_ipv6 = ''; + foreach($config['gateways']['gateway_item'] as $gateway) { if(isset($gateway['defaultgw'])) { - $gatewayip = $gateway['gateway']; - $interfacegw = $gateway['interface']; + if ($gateway['type'] == 'IPv4') { + $gatewayip = $gateway['gateway']; + $interfacegw = $gateway['interface']; + } else if ($gateway['type'] == 'IPv6') { + $gatewayip_ipv6 = $gateway['gateway']; + $interfacegw_ipv6 = $gateway['interface']; + } + } + } + + if($interfacegw != "bgpd") { + /* + if (Net_IPv6::checkIPv6($gatewayip)) { + mwexec("/sbin/route add -inet6 default " . escapeshellarg($gatewayip)); + } else { + mwexec("/sbin/route add default " . escapeshellarg($gatewayip)); + } + */ + + if ($gatewayip != '') { + mwexec("/sbin/route add default " . escapeshellarg($gatewayip), true); + } + + if ($gatewayip_ipv6 != '') { + mwexec("/sbin/route add -inet6 default " . escapeshellarg($gatewayip_ipv6), true); } } - if(($interfacegw <> "bgpd") && (is_ipaddr($gatewayip))) - mwexec("/sbin/route add default " . escapeshellarg($gatewayip), true); } else { /* FIXME */ /* adding gateway for 1.2-style configs without the new @@ -275,6 +309,11 @@ function system_routing_configure() { $gatewayip = $config['interfaces']['wan']['gateway']; mwexec("/sbin/route add default " . escapeshellarg($gatewayip), true); } + + if (Net_IPv6::checkIPv6($config['interfaces']['wan']['gateway_ipv6'])) { + $gatewayip = $config['interfaces']['wan']['gateway_ipv6']; + mwexec("/sbin/route add -inet6 default " . escapeshellarg($gatewayip), true); + } } } @@ -295,19 +334,42 @@ function system_routing_configure() { } } } - if((is_ipaddr($rtent['gateway'])) && ($gatewayip == "")) { - $gatewayip = $rtent['gateway']; - $interfacegw = $rtent['interface']; - } - if(isset($rtent['interfacegateway'])) { - mwexec("/sbin/route add " . escapeshellarg($rtent['network']) . - " -iface " . escapeshellarg(convert_friendly_interface_to_real_interface_name($interfacegw))); - } else { - mwexec("/sbin/route add " . escapeshellarg($rtent['network']) . - " " . escapeshellarg($gatewayip)); + + if ($rtent['ip_version'] == 'IPv4') { + if(is_ipaddr($rtent['gateway']) && $gatewayip == "") { + $gatewayip = $rtent['gateway']; + $interfacegw = $rtent['interface']; + } + + if(isset($rtent['interfacegateway'])) { + mwexec("/sbin/route add " . escapeshellarg($rtent['network']) . + " -iface " . escapeshellarg(convert_friendly_interface_to_real_interface_name($interfacegw))); + } else { + mwexec("/sbin/route add " . escapeshellarg($rtent['network']) . + " " . escapeshellarg($gatewayip)); + } + + /* record route so it can be easily removed later (if necessary) */ + fwrite($fd, $rtent['network'] . "\n"); + } else if ($rtent['ip_version'] == 'IPv6') { + /// + if(Net_IPv6::checkIPv6($rtent['gateway']) && $gatewayip == "") { + $gatewayip = $rtent['gateway']; + $interfacegw = $rtent['interface']; + } + + if(isset($rtent['interfacegateway'])) { + mwexec("/sbin/route add -inet6 " . escapeshellarg($rtent['network']) . + " -iface " . escapeshellarg(convert_friendly_interface_to_real_interface_name($interfacegw))); + } else { + mwexec("/sbin/route add -inet6 " . escapeshellarg($rtent['network']) . + " " . escapeshellarg($gatewayip)); + } + + /* record route so it can be easily removed later (if necessary) */ + fwrite($fd, $rtent['network'] . "\n"); } - /* record route so it can be easily removed later (if necessary) */ - fwrite($fd, $rtent['network'] . "\n"); + } fclose($fd); } @@ -317,12 +379,17 @@ function system_routing_configure() { function system_routing_enable() { global $config, $g; + $retval = false; + if(isset($config['system']['developerspew'])) { $mt = microtime(); echo "system_routing_enable() being called $mt\n"; } - return mwexec("/sbin/sysctl net.inet.ip.forwarding=1"); + $retval = mwexec("/sbin/sysctl net.inet.ip.forwarding=1") && mwexec("/sbin/sysctl net.inet6.ip6.forwarding=1"); + + return $retval; + } function system_syslogd_start() { @@ -622,9 +689,9 @@ function system_generate_lighty_config($filename, if($captive_portal == true) { $bin_environment = <<<EOC - "bin-environment" => ( - "PHP_FCGI_CHILDREN" => "16", - "PHP_FCGI_MAX_REQUESTS" => "{$max_requests}" + "bin-environment" => ( + "PHP_FCGI_CHILDREN" => "16", + "PHP_FCGI_MAX_REQUESTS" => "{$max_requests}" ), EOC; @@ -649,7 +716,7 @@ fastcgi.server = ( ".php" => ( "localhost" => ( "socket" => "/tmp/php-fastcgi.socket", - "min-procs" => 1, + "min-procs" => 2, "max-procs" => {$max_procs}, {$bin_environment} "bin-path" => "/usr/local/bin/php" @@ -829,6 +896,8 @@ expire.url = ( "" => "access 50 hours", ) +server.use-ipv6 = "enable" + EOD; $cert = str_replace("\r", "", $cert); @@ -848,7 +917,7 @@ EOD; fwrite($fd, "\n"); fwrite($fd, $key); fclose($fd); - $lighty_config .= "\n"; + $lighty_config .= "## ssl configuration\n"; $lighty_config .= "ssl.engine = \"enable\"\n"; $lighty_config .= "ssl.pemfile = \"{$g['varetc_path']}/{$cert_location}\"\n\n"; @@ -862,6 +931,12 @@ EOD; fwrite($fd, $lighty_config); fclose($fd); + /* + * Hard-code sysctl knob to ensure that lighttpd would work + * with IPv4 + IPv6. + */ + mwexec("/sbin/sysctl net.inet6.ip6.v6only=0"); + return 0; } @@ -925,7 +1000,7 @@ function system_ntp_configure() { $ifaces = array_filter($ifaces, 'does_interface_exist'); $ips = array_map('find_interface_ip', $ifaces); foreach ($ips as $ip) { - if (is_ipaddr($ip)) + if (is_ipaddr($ip) || Net_IPv6::checkIPv6($ip)) fwrite($fd, "listen on $ip\n"); } } diff --git a/etc/inc/util.inc b/etc/inc/util.inc index 3ef01fc..7b8ebe8 100644 --- a/etc/inc/util.inc +++ b/etc/inc/util.inc @@ -27,6 +27,8 @@ POSSIBILITY OF SUCH DAMAGE. */ +require_once 'IPv6.inc'; + /* kill a process by pid file */ function killbypid($pidfile) { sigkillbypid($pidfile, "TERM"); @@ -120,9 +122,8 @@ function is_ipaddr($ipaddr) { return false; } -/* returns true if $ipaddr is a valid dotted IPv4 address or an alias thereof */ +/* returns true if $ipaddr is a valid IPv4/IPv6 address or an alias thereof */ function is_ipaddroralias($ipaddr) { - global $aliastable, $config; if(is_array($config['aliases']['alias'])) { @@ -132,22 +133,22 @@ function is_ipaddroralias($ipaddr) { } } - if (isset($aliastable[$ipaddr]) && is_ipaddr($aliastable[$ipaddr])) + if (isset($aliastable[$ipaddr]) && (is_ipaddr($aliastable[$ipaddr]) || Net_IPv6::checkIPv6($aliastable[$ipaddr]))) { return true; - else - return is_ipaddr($ipaddr); - + } else { + return (is_ipaddr($ipaddr) || Net_IPv6::checkIPv6($ipaddr)); + } } /* returns true if $ipaddr is a valid dotted IPv4 address or any alias */ function is_ipaddroranyalias($ipaddr) { - global $aliastable; - if (isset($aliastable[$ipaddr])) + if (isset($aliastable[$ipaddr])) { return true; - else - return is_ipaddr($ipaddr); + } else { + return (is_ipaddr($ipaddr) || Net_IPv6::checkIPv6($ipaddr)); + } } /* returns true if $subnet is a valid subnet in CIDR format */ @@ -166,6 +167,26 @@ function is_subnet($subnet) { return true; } +/* returns true if $subnet is a valid IPv6 network address */ +function is_subnet_ipv6($subnet, $max = 64) { + if (!is_string($subnet)) { + return false; + } + + list ($hp, $np) = explode('/', $subnet); + + if (!Net_IPv6::checkIPv6($hp)) { + return false; + } + + if (!is_numeric($np) || ($np < 1) || ($np > $max)) { + return false; + } + + return true; +} + + /* returns true if $subnet is a valid subnet in CIDR format or an alias thereof */ function is_subnetoralias($subnet) { @@ -503,15 +524,15 @@ function alias_expand_value($name) { /* expand a host or network alias, if necessary */ function alias_expand($name) { - global $aliastable; - if (isset($aliastable[$name])) + if (isset($aliastable[$name])) { return "\${$name}"; - else if (is_ipaddr($name) || is_subnet($name)) + } else if (is_ipaddr($name) || is_subnet($name) || Net_IPv6::checkIPv6($name) || is_subnet_ipv6($name)) { return "{$name}"; - else + } else { return null; + } } /* expand a host alias, if necessary */ @@ -521,14 +542,16 @@ function alias_expand_host($name) { if (isset($aliastable[$name])) { $ip_arr = explode(" ", $aliastable[$name]); foreach($ip_arr as $ip) { - if (!is_ipaddr($ip)) + if (!is_ipaddr($ip) || Net_IPv6::checkIPv6($ip)) { return null; + } } return $aliastable[$name]; - } else if (is_ipaddr($name)) + } else if (is_ipaddr($name) || Net_IPv6::checkIPv6($name)) { return $name; - else + } else { return null; + } } /* expand a network alias, if necessary */ @@ -612,8 +635,8 @@ function arp_get_mac_by_ip($ip) { /* return a fieldname that is safe for xml usage */ function xml_safe_fieldname($fieldname) { - $replace = array('/', '-', ' ', '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', - '_', '+', '=', '{', '}', '[', ']', '|', '/', '<', '>', '?', + $replace = array('/', ' ', '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', + '+', '=', '{', '}', '[', ']', '|', '/', '<', '>', '?', ':', ',', '.', '\'', '\\' ); return strtolower(str_replace($replace, "", $fieldname)); @@ -647,8 +670,9 @@ function mac_format($clientmac) { function resolve_retry($hostname, $retries = 5) { - if (is_ipaddr($hostname)) + if (is_ipaddr($hostname) || Net_IPv6::checkIPv6($hostname)) { return $hostname; + } for ($i = 0; $i < $retries; $i++) { $ip = gethostbyname($hostname); |