diff options
author | Matthew Grooms <mgrooms@pfsense.org> | 2008-07-13 23:28:45 +0000 |
---|---|---|
committer | Matthew Grooms <mgrooms@pfsense.org> | 2008-07-13 23:28:45 +0000 |
commit | 3462a52903223da3bf931ab0dda9267242c4bb6c (patch) | |
tree | c48c6e58b55e61d592bea303dbbb9a9bdf4c4f05 /etc | |
parent | 916c50019bb2bf3116f023fd5933f236598c5fd7 (diff) | |
download | pfsense-3462a52903223da3bf931ab0dda9267242c4bb6c.zip pfsense-3462a52903223da3bf931ab0dda9267242c4bb6c.tar.gz |
Introduce a new and improved version of IPsec mobile client support. The
mobile client tab is now used to configure user authentication (Xauth) and
client configuration (mode-cfg) options. User authentication is currently
limited to system password file entries. This will be extended to support
external RADIUS and LDAP account DBs in a follow up comiit.
Diffstat (limited to 'etc')
-rw-r--r-- | etc/inc/filter.inc | 47 | ||||
-rw-r--r-- | etc/inc/ipsec.inc | 75 | ||||
-rw-r--r-- | etc/inc/vpn.inc | 223 |
3 files changed, 265 insertions, 80 deletions
diff --git a/etc/inc/filter.inc b/etc/inc/filter.inc index be07d56..09c7291 100644 --- a/etc/inc/filter.inc +++ b/etc/inc/filter.inc @@ -2979,8 +2979,7 @@ EOD; * -mgrooms 06/07/2008 */ if(isset($config['ipsec']['enable']) && - is_array($config['ipsec']['phase1']) && - is_array($config['ipsec']['phase2'])) { + is_array($config['ipsec']['phase1'])) { /* step through all phase1 entries */ foreach ($config['ipsec']['phase1'] as $ph1ent) { @@ -3004,18 +3003,24 @@ EOD; $lgip = vpn_endpoint_determine($ph1ent, $wan_ip); - $rgip = $ph1ent['remote-gateway']; - if(!is_ipaddr($rgip)) - $rgip = resolve_retry($rgip); - if (!$lgip) { - $ipfrules .= "# ERROR! Unable to determine local IPsec peer address for {$ph1ent['remote-gateway']}\n"; + $ipfrules .= "# ERROR! Unable to determine local IPsec peer address for {$ph1ent['descr']}\n"; continue; } - if (!$rgip) { - $ipfrules .= "# ERROR! Unable to determine remote IPsec peer address for {$ph1ent['remote-gateway']}\n"; - continue; + + if (!isset($ph1ent['mobile'])) { + + $rgip = $ph1ent['remote-gateway']; + if(!is_ipaddr($rgip)) + $rgip = resolve_retry($rgip); + + if (!$rgip) { + $ipfrules .= "# ERROR! Unable to determine remote IPsec peer address for {$ph1ent['descr']}\n"; + continue; + } } + else + $rgip = "any"; /* Step through the interface list and the assigned IP * addresses. @@ -3071,14 +3076,20 @@ EOD; /* Another conversion. Why? */ $ifalias = convert_friendly_interface_to_friendly_descr($ifr); + /* Determine best description */ + if ($ph1ent['descr']) + $descr = $ph1ent['descr']; + else + $descr = $rgip; + /* Add rules to allow IKE to pass */ - $ipfrules .= "pass out on \${$ifalias} $route_to proto udp from any to {$rgip} port = 500 keep state label \"IPsec: {$ph1ent['descr']} - outbound isakmp\"\n"; - $ipfrules .= "pass in on \${$ifalias} $reply_to proto udp from {$rgip} to any port = 500 keep state label \"IPsec: {$ph1ent['descr']} - inbound isakmp\"\n"; + $ipfrules .= "pass out on \${$ifalias} $route_to proto udp from any to {$rgip} port = 500 keep state label \"IPsec: {$descr} - outbound isakmp\"\n"; + $ipfrules .= "pass in on \${$ifalias} $reply_to proto udp from {$rgip} to any port = 500 keep state label \"IPsec: {$descr} - inbound isakmp\"\n"; /* If NAT-T is enabled, add additional rules */ if ($ph1ent['nat_traversal'] != "off" ) { - $ipfrules .= "pass out on \${$ifalias} $route_to proto udp from any to {$rgip} port = 4500 keep state label \"IPsec: {$ph1ent['descr']} - outbound nat-t\"\n"; - $ipfrules .= "pass in on \${$ifalias} $reply_to proto udp from {$rgip} to any port = 4500 keep state label \"IPsec: {$ph1ent['descr']} - inbound nat-t\"\n"; + $ipfrules .= "pass out on \${$ifalias} $route_to proto udp from any to {$rgip} port = 4500 keep state label \"IPsec: {$descr} - outbound nat-t\"\n"; + $ipfrules .= "pass in on \${$ifalias} $reply_to proto udp from {$rgip} to any port = 4500 keep state label \"IPsec: {$descr} - inbound nat-t\"\n"; } /* Step through all phase2 entries and determine @@ -3102,12 +3113,12 @@ EOD; /* Add rules to allow the protocols in use */ if ($prot_used_esp) { - $ipfrules .= "pass out on \${$ifalias} $route_to proto esp from any to {$rgip} keep state label \"IPsec: {$ph1ent['descr']} - outbound esp proto\"\n"; - $ipfrules .= "pass in on \${$ifalias} $reply_to proto esp from {$rgip} to any keep state label \"IPsec: {$ph1ent['descr']} - inbound esp proto\"\n"; + $ipfrules .= "pass out on \${$ifalias} $route_to proto esp from any to {$rgip} keep state label \"IPsec: {$descr} - outbound esp proto\"\n"; + $ipfrules .= "pass in on \${$ifalias} $reply_to proto esp from {$rgip} to any keep state label \"IPsec: {$descr} - inbound esp proto\"\n"; } if ($prot_used_ah) { - $ipfrules .= "pass out on \${$ifalias} $route_to proto ah from any to {$rgip} keep state label \"IPsec: {$ph1ent['descr']} - outbound ah proto\"\n"; - $ipfrules .= "pass in on \${$ifalias} $reply_to proto ah from {$rgip} to any keep state label \"IPsec: {$ph1ent['descr']} - inbound ah proto\"\n"; + $ipfrules .= "pass out on \${$ifalias} $route_to proto ah from any to {$rgip} keep state label \"IPsec: {$descr} - outbound ah proto\"\n"; + $ipfrules .= "pass in on \${$ifalias} $reply_to proto ah from {$rgip} to any keep state label \"IPsec: {$descr} - inbound ah proto\"\n"; } } } diff --git a/etc/inc/ipsec.inc b/etc/inc/ipsec.inc index 23cd4ba..e5cd46d 100644 --- a/etc/inc/ipsec.inc +++ b/etc/inc/ipsec.inc @@ -30,6 +30,63 @@ POSSIBILITY OF SUCH DAMAGE. */ +/* IPsec defines */ +$my_identifier_list = array( + 'myaddress' => array( 'desc' => 'My IP address', 'mobile' => true ), + 'address' => array( 'desc' => 'IP address', 'mobile' => true ), + 'fqdn' => array( 'desc' => 'Distinguished name', 'mobile' => true ), + 'user_fqdn' => array( 'desc' => 'User distinguished name', 'mobile' => true ), + 'asn1dn' => array( 'desc' => 'ASN.1 distinguished Name', 'mobile' => true ), + 'keyid tag' => array( 'desc' => 'KeyID tag', 'mobile' => true ), + 'dyn_dns' => array( 'desc' => 'Dynamic DNS', 'mobile' => true )); + +$peer_identifier_list = array( + 'peeraddress' => array( 'desc' => 'Peer IP address', 'mobile' => false ), + 'address' => array( 'desc' => 'IP address', 'mobile' => false ), + 'fqdn' => array( 'desc' => 'Distinguished name', 'mobile' => true ), + 'user_fqdn' => array( 'desc' => 'User distinguished name', 'mobile' => true ), + 'asn1dn' => array( 'desc' => 'ASN.1 distinguished Name', 'mobile' => true ), + 'keyid tag' => array( 'desc' =>'KeyID tag', 'mobile' => true )); + +$p1_ealgos = array( + 'aes' => array( 'name' => 'AES', 'keysel' => array( 'lo' => 128, 'hi' => 256, 'step' => 64 ) ), + 'blowfish' => array( 'name' => 'Blowfish', 'keysel' => array( 'lo' => 128, 'hi' => 256, 'step' => 8 ) ), + '3des' => array( 'name' => '3DES' ), + 'cast128' => array( 'name' => 'CAST128' ), + 'des' => array( 'name' => 'DES' )); + +$p2_ealgos = array( + 'aes' => array( 'name' => 'AES', 'keysel' => array( 'lo' => 128, 'hi' => 256, 'step' => 64 ) ), + 'blowfish' => array( 'name' => 'Blowfish', 'keysel' => array( 'lo' => 128, 'hi' => 256, 'step' => 8 ) ), + '3des' => array( 'name' => '3DES' ), + 'cast128' => array( 'name' => 'CAST128' ), + 'des' => array( 'name' => 'DES' )); + +$p1_halgos = array( + 'sha1' => 'SHA1', + 'md5' => 'MD5'); + +$p2_halgos = array( + 'hmac_sha1' => 'SHA1', + 'hmac_md5' => 'MD5'); + +$p1_authentication_methods = array( + 'hybrid_rsa_server' => array( 'name' => 'Hybrid RSA + Xauth', 'mobile' => true ), + 'xauth_rsa_server' => array( 'name' => 'Mutual RSA + Xauth', 'mobile' => true ), + 'xauth_psk_server' => array( 'name' => 'Mutual PSK + Xauth', 'mobile' => true ), + 'rsasig' => array( 'name' => 'Mutual RSA', 'mobile' => false ), + 'pre_shared_key' => array( 'name' => 'Mutual PSK', 'mobile' => false ) ); + +$p2_protos = array( + 'esp' => 'ESP', + 'ah' => 'AH'); + +$p2_pfskeygroups = array( + '0' => 'off', + '1' => '1', + '2' => '2', + '5' => '5'); + /* * Return phase1 local address */ @@ -47,6 +104,18 @@ function ipsec_get_phase1_src(& $ph1ent) { } /* + * Return phase1 local address + */ +function ipsec_get_phase1_dst(& $ph1ent) { + + $rg = $ph1ent['remote-gateway']; + if (!is_ipaddr($rg)) + return resolve_retry($rg); + + return $rg; +} + +/* * Return phase2 idinfo in cidr format */ function ipsec_idinfo_to_cidr(& $idinfo,$addrbits = false) { @@ -61,6 +130,8 @@ function ipsec_idinfo_to_cidr(& $idinfo,$addrbits = false) { return $idinfo['address']; case "network": return $idinfo['address']."/".$idinfo['netbits']; + case "mobile": + return "0.0.0.0/0"; default: $address = $config['interfaces']['lan']['ipaddr']; $netbits = $config['interfaces'][$idinfo['type']]['subnet']; @@ -84,6 +155,8 @@ function ipsec_idinfo_to_subnet(& $idinfo,$addrbits = false) { return $idinfo['address']; case "network": return $idinfo['address']."/".gen_subnet_mask($idinfo['netbits']); + case "mobile": + return "0.0.0.0/0"; default: $address = $config['interfaces']['lan']['ipaddr']; $netbits = $config['interfaces'][$idinfo['type']]['subnet']; @@ -104,6 +177,8 @@ function ipsec_idinfo_to_text(& $idinfo) { return $idinfo['address']; case "network": return $idinfo['address']."/".$idinfo['netbits']; + case "mobile": + return "Mobile Client"; default: return strtoupper($idinfo['type']); } diff --git a/etc/inc/vpn.inc b/etc/inc/vpn.inc index 95a115b..141f954 100644 --- a/etc/inc/vpn.inc +++ b/etc/inc/vpn.inc @@ -35,42 +35,6 @@ /* include all configuration functions */ require_once ("functions.inc"); -/* IPsec defines */ -$my_identifier_list = array('myaddress' => 'My IP address', - 'address' => 'IP address', - 'keyid tag' => 'KeyID Tag', - 'fqdn' => 'Domain name', - 'user_fqdn' => 'User FQDN', - 'asn1dn' => 'Distinguished Name', - 'dyn_dns' => 'Dynamic DNS'); - -$peer_identifier_list = array('peeraddress' => 'Peer IP address', - 'address' => 'IP address', - 'keyid tag' => 'KeyID Tag', - 'fqdn' => 'Domain name', - 'user_fqdn' => 'User FQDN', - 'asn1dn' => 'Distinguished Name'); - -$p1_ealgos = array( - 'aes' => array( 'name' => 'AES', 'keysel' => array( 'lo' => 128, 'hi' => 256, 'step' => 64 ) ), - 'blowfish' => array( 'name' => 'Blowfish', 'keysel' => array( 'lo' => 128, 'hi' => 256, 'step' => 8 ) ), - '3des' => array( 'name' => '3DES' ), - 'cast128' => array( 'name' => 'CAST128' ), - 'des' => array( 'name' => 'DES' ) ); - -$p2_ealgos = array( - 'aes' => array( 'name' => 'AES', 'keysel' => array( 'lo' => 128, 'hi' => 256, 'step' => 64 ) ), - 'blowfish' => array( 'name' => 'Blowfish', 'keysel' => array( 'lo' => 128, 'hi' => 256, 'step' => 8 ) ), - '3des' => array( 'name' => '3DES' ), - 'cast128' => array( 'name' => 'CAST128' ), - 'des' => array( 'name' => 'DES' ) ); - -$p1_halgos = array('sha1' => 'SHA1', 'md5' => 'MD5'); -$p1_authentication_methods = array('pre_shared_key' => 'Pre-shared key', 'rsasig' => 'RSA signature'); -$p2_halgos = array('hmac_sha1' => 'SHA1', 'hmac_md5' => 'MD5'); -$p2_protos = array('esp' => 'ESP', 'ah' => 'AH'); -$p2_pfskeygroups = array('0' => 'off', '1' => '1', '2' => '2', '5' => '5'); - /* master setup for vpn (mpd) */ function vpn_setup() { /* start pptpd */ @@ -173,6 +137,7 @@ function vpn_ipsec_configure($ipchg = false) $ipseccfg = $config['ipsec']; $a_phase1 = $config['ipsec']['phase1']; $a_phase2 = $config['ipsec']['phase2']; + $a_client = $config['ipsec']['client']; $lancfg = $config['interfaces']['lan']; $lanip = $lancfg['ipaddr']; $lansa = gen_subnet($lancfg['ipaddr'], $lancfg['subnet']); @@ -232,6 +197,9 @@ function vpn_ipsec_configure($ipchg = false) /* see if this tunnel has a hostname for the remote-gateway. If so, try to resolve it now and add it to the list for dnswatch */ + if (isset ($ph1ent['mobile'])) + continue; + $rg = $ph1ent['remote-gateway']; if (!is_ipaddr($rg)) { @@ -300,16 +268,15 @@ function vpn_ipsec_configure($ipchg = false) if (isset($ph1ent['disabled'])) continue; - $rgip = $rgmap[$ph1ent['remote-gateway']]; - if (!$rgip) - continue; + if (strstr($ph1ent['authentication_method'],'rsa')) + continue; $peerid_type = $ph1ent['peerid_type']; switch ($peerid_type) { case "peeraddress": $peerid_type = "address"; - $peerid_data = $rgip; + $peerid_data = $rgmap[$ph1ent['remote-gateway']]; break; case "address"; @@ -323,7 +290,7 @@ function vpn_ipsec_configure($ipchg = false) break; } - $pskconf .= "{$peerid_data}\t\t\t{$ph1ent['pre-shared-key']}\n"; + $pskconf .= "{$peerid_data}\t{$ph1ent['pre-shared-key']}\n"; } } @@ -357,19 +324,113 @@ function vpn_ipsec_configure($ipchg = false) $racoonconf .= "}\n\n"; } + /* begin mode_cfg section */ + if (is_array($a_client) && isset($a_client['enable'])) { + + $racoonconf .= "\nmode_cfg\n"; + $racoonconf .= "{\n"; + + if ($a_client['user_source']) + $racoonconf .= "\tauth_source {$a_client['user_source']};\n"; + if ($a_client['group_source']) + $racoonconf .= "\tgroup_source {$a_client['group_source']};\n"; + + if ($a_client['pool_address'] && $a_client['pool_netbits']) { + $pool_address = $a_client['pool_address']; + $pool_netmask = gen_subnet_mask($a_client['pool_netbits']); + + $pool_address = long2ip(ip2long($pool_address)+1); + $pool_size = ~ip2long($pool_netmask) - 2; + + $racoonconf .= "\tpool_size {$pool_size};\n"; + $racoonconf .= "\tnetwork4 {$pool_address};\n"; + $racoonconf .= "\tnetmask4 {$pool_netmask};\n"; + } + + if (isset($a_client['net_list'])) { + + $net_list = ''; + + foreach ($a_phase2 as $ph2ent) { + + if (isset($ph2ent['disabled'])) + continue; + + if (!isset($ph2ent['mobile'])) + continue; + + $localid = ipsec_idinfo_to_cidr($ph2ent['localid'],true); + + if ($net_list) + $net_list .= ", "; + $net_list .= $localid; + } + + if ($net_list) + $racoonconf .= "\tsplit_network include {$net_list};\n"; + } + + if ($a_client['dns_server1']) + $racoonconf .= "\tdns4 {$a_client['dns_server1']};\n"; + if ($a_client['dns_server2']) + $racoonconf .= "\tdns4 {$a_client['dns_server2']};\n"; + if ($a_client['dns_server3']) + $racoonconf .= "\tdns4 {$a_client['dns_server3']};\n"; + if ($a_client['dns_server4']) + $racoonconf .= "\tdns4 {$a_client['dns_server4']};\n"; + + if ($a_client['wins_server1']) + $racoonconf .= "\twins4 {$a_client['wins_server1']};\n"; + if ($a_client['wins_server2']) + $racoonconf .= "\twins4 {$a_client['wins_server2']};\n"; + + if ($a_client['dns_domain']) + $racoonconf .= "\tdefault_domain \"{$a_client['dns_domain']}\";\n"; + + if ($a_client['pfs_group']) + $racoonconf .= "\tpfs_group {$a_client['pfs_group']};\n"; + + if ($a_client['login_banner']) { + $fn = "{$g['varetc_path']}/racoon.motd"; + $fd1 = fopen($fn, "w"); + if (!$fd1) { + printf("Error: cannot open server{$fn} in vpn.\n"); + return 1; + } + + fwrite($fd1, $a_client['login_banner']); + fclose($fd1); + + $racoonconf .= "\tbanner \"{$fn}\";\n"; + } + + $racoonconf .= "}\n\n"; + } + /* end mode_cfg section */ + /* begin remote sections */ if (is_array($a_phase1) && count($a_phase1)) { /* begin remote */ foreach ($a_phase1 as $ph1ent) { + if (isset($ph1ent['disabled'])) continue; + if (isset($ph1ent['mobile']) && !isset($a_client['enable'])) + continue; + $ikeid = $ph1ent['ikeid']; $ep = vpn_endpoint_determine($ph1ent, $curwanip); if (!$ep) continue; + if (!isset($ph1ent['mobile'])) { + $rgip = $rgmap[$ph1ent['remote-gateway']]; + if (!$rgip) + continue; + } + $myid_type = $ph1ent['myid_type']; switch ($myid_type) { @@ -397,10 +458,6 @@ function vpn_ipsec_configure($ipchg = false) break; } - $rgip = $rgmap[$ph1ent['remote-gateway']]; - if (!$rgip) - continue; - $peerid_type = $ph1ent['peerid_type']; switch ($peerid_type) { @@ -423,9 +480,24 @@ function vpn_ipsec_configure($ipchg = false) break; } - $nattline = ''; + $natt = "off"; if (isset($ph1ent['nat_traversal'])) - $nattline = "nat_traversal {$ph1ent['nat_traversal']};"; + $natt = $ph1ent['nat_traversal']; + + $init = "on"; + $genp = "off"; + if (isset($ph1ent['mobile'])) { + $rgip = "anonymous"; + $init = "off"; + $genp = "unique"; + } + + $dpdline1 = ''; + $dpdline2 = ''; + if ($ph1ent['dpd_delay'] && $ph1ent['dpd_maxfail']) { + $dpdline1 = "dpd_delay = {$ph1ent['dpd_delay']};"; + $dpdline2 = "dpd_maxfail = {$ph1ent['dpd_maxfail']};"; + } if (isset ($ph1ent['authentication_method'])) $authmethod = $ph1ent['authentication_method']; @@ -434,7 +506,7 @@ function vpn_ipsec_configure($ipchg = false) $certline = ''; - if ($authmethod == 'rsasig') { + if (strstr($authmethod,'rsa')) { if ($ph1ent['cert'] && $ph1ent['private-key']) { $cert = base64_decode($ph1ent['cert']); $private_key = base64_decode($ph1ent['private-key']); @@ -494,11 +566,11 @@ function vpn_ipsec_configure($ipchg = false) $lifeline = ''; if ($ph1ent['lifetime']) $lifeline = "lifetime time {$ph1ent['lifetime']} secs;"; - + /* add remote section to configuration */ $racoonconf .=<<<EOD - + remote {$rgip} { ph1id {$ikeid}; @@ -506,9 +578,12 @@ remote {$rgip} my_identifier {$myid_type} {$myid_data}; peers_identifier {$peerid_type} {$peerid_data}; ike_frag on; - {$nattline} + generate_policy = {$genp}; + initial_contact = {$init}; + nat_traversal = {$natt}; {$certline} - initial_contact on; + {$dpdline1} + {$dpdline2} support_proxy on; proposal_check claim; @@ -530,21 +605,36 @@ EOD; /* begin sainfo sections */ if (is_array($a_phase2) && count($a_phase2)) { + /* begin sainfo */ foreach ($a_phase2 as $ph2ent) { $ikeid = $ph2ent['ikeid']; + if (isset($ph2ent['disabled'])) + continue; + + if (isset($ph2ent['mobile']) && !isset($a_client['enable'])) + continue; + $localid_type = $ph2ent['localid']['type']; if ($localid_type != "address") $localid_type = "subnet"; - $remoteid_type = $ph2ent['remoteid']['type']; - if ($remoteid_type != "address") - $remoteid_type = "subnet"; - $localid_data = ipsec_idinfo_to_cidr($ph2ent['localid']); - $remoteid_data = ipsec_idinfo_to_cidr($ph2ent['remoteid']); + $localid_spec = $localid_type." ".$localid_data." any"; + + if (!isset($ph2ent['mobile'])) { + + $remoteid_type = $ph2ent['remoteid']['type']; + if ($remoteid_type != "address") + $remoteid_type = "subnet"; + + $remoteid_data = ipsec_idinfo_to_cidr($ph2ent['remoteid']); + $remoteid_spec = $remoteid_type." ".$remoteid_data." any"; + + } else + $remoteid_spec = "anonymous"; $ealgos = ''; $halgos = join(",", $ph2ent['hash-algorithm-option']); @@ -552,6 +642,11 @@ EOD; $pfsline = ''; if ($ph2ent['pfsgroup']) $pfsline = "pfs_group {$ph2ent['pfsgroup']};"; + if (isset($a_client['pfs_group'])) { + $pfsline = ''; + if ($a_client['pfs_group']) + $pfsline = "pfs_group {$a_client['pfs_group']};"; + } $lifeline = ''; if ($ph2ent['lifetime']) @@ -589,14 +684,14 @@ EOD; $racoonconf .=<<<EOD -sainfo {$localid_type} {$localid_data} any {$remoteid_type} {$remoteid_data} any +sainfo {$localid_spec} {$remoteid_spec} { remoteid {$ikeid}; encryption_algorithm {$ealgos}; authentication_algorithm {$halgos}; compression_algorithm deflate; - ${pfsline} - ${lifeline} + {$pfsline} + {$lifeline} } EOD; @@ -628,13 +723,17 @@ EOD; $spdconf .= "spdadd {$lansa}/{$lansn} {$lanip}/32 any -P in none;\n"; foreach ($a_phase2 as $ph2ent) { + if( !ipsec_lookup_phase1($ph2ent,$ph1ent)) continue; - if (isset ($ph1ent['disabled'])) + if (isset($ph1ent['mobile'])) + continue; + + if (isset($ph1ent['disabled'])) continue; - if (isset ($ph2ent['disabled'])) + if (isset($ph2ent['disabled'])) continue; $ep = vpn_endpoint_determine($ph1ent, $curwanip); |