Overview
Even though I am a couple of years too late for World IPv6 Launch, I've finally decided to implement IPv6 at home. The following step by step guide, should help anyone with access to similar hardware in implementing this solution.
You will require the following:
Note, HE.net is not on the list and since there is no generic dyndns2 protocol option, there is no way to tell your FortiGate firewall to automatically update your tunnel end-point IP.
So a workaround I've put in place, is to configure ddclient according to these instructions, to run on a local Linux server, periodically detect my public IP and update the tunnel end-point if it changes.
For reference, my /etc/ddclient.conf looks like this:
This process updates your tunnel end-point IPv4 and since you've configured a hostname and API key on the tunnelbroker.net portal previously, it will also perform a chained update to your HE.net DDNS host entry.
In effect you will have two separate DDNS entries which both point to my dynamic IPv4 address:
Ideally, you would want your firewall/router to do this as part of it's PPPoE interface-up routines, but we are where we are..
EDIT: I've written a very basic script to obtain the current public IP from the FortiGate firewall directly, rather than going out to a remote site.
To use it, save it to your favourite script location and update the "use=" line in your ddclient.conf as follows:
Now, configure your LAN interface(s) to support IPv6:
Some notes on important flags:
Configure IPv6 address objects, which you will use later on in your IPv6 firewall policies:
Configure IPv6 firewall policies to allow access from your internal network and also to allow ICMP (ping) from hosts on the internet:
Test you work so far, by pinging your LAN IPv6 IP using an online ping tool while watching the tunnel interface with the packet sniffer:
I found, that when the internal FortiGate DNS server is forwarding to the default FortiGuard DNS resolvers upstream, it completely breaks NAT64.
Next, enable and configure NAT64:
Note, we are disabing the automatic synthesis of IPv6 addresses, since we dont want a synthetic address generated if a host already has an IPv6 address. In this case, an address will by synthethised only if the host does not have an IPv6 AAAA record.
Add an IP pool abd firewall policy to support NAT(ing) of IPv6 addresses to IPv4:
Now, switch off IPv4 support on your client and make sure you can no longer access an IPv4 only site (e.g. Fortinet):
This is expected, since we have turned off IPv4, but told cURL to specifically use it to access the web site.
Next, try to resolve the IPv4 only site using an external DNS server (e.g. Google):
Note that there are no IPv6 host records (AAAA) returned for www.fortinet.com.
Now try to resolve the same name using your internal DNS server, running on the firewall, which is now DNS64 enabled:
Note an IPv6 address is synthesised from the NAT64 Well-Known Prefix (64:ff9b::/96).
Finally, check to make sure you can access the web site using IPv6:
I've used the following reference material to prepare the solution described in this article. Many thanks to the respective authors.
Prerequisites
- Properly functioning IPv4 broadband Internet connection and LAN/WLAN at home.
- FortiGate firewall running FortiOS 5.0 (I've used v5.0,build0208 GA Patch 3) with IPv6 and Advanced Routing features enabled.
- A free account with Hurricane Electric IPv6 Tunnel Broker and DNS services.
- An Internet domain registered with an IPv6 capable domain name registrar (e.g. Gandi).
The following steps should hopefully guide you in setting up a tunneled, but fully functional IPv4/IPv6 configuration, which will further enable you to switch off IPv4 entirely and use NAT64 to continue accessing IPv4 resources from your IPv6-only network.
First, allow tunnelbroker.net ICMP (ping) access to your IPv4 public IP:
Also make sure your external interface allows ping access:
Next, create a regular tunnel following this link. Once you've created the tunnel, configure your firewall as follows:
Test your work so far, by pinging your server's IPv6 tunnel end-point IP:
Also try pinging an external IPv6 IP (e.g. Google):
Next, head to dns.he.net and add a new domain, which you have registered with an IPv6 compliant registrar (check with the registra if they support "IPv6 glue records").
Edit the newly added domain zone, create a new A host record (e.g. myip.mydomain.com), making sure to tick "Enable entry for dynamic dns" and set the TTL to 5 minutes.
Click the DDNS icon next to you new record and generate a new API key.
Got to the "Advanced" tab of the tunnelbroker.net tunnel management portal and register your hostname and API key.
Last, go to your domain name registrar's admin portal and delegate your entire domain or a sub-domain to HE.net's name servers (there are five).
Configuration
In the subsequent sections, the following example parameters are used. Make sure to substitute your own settings:
LAN firewall interface: internal
WAN firewall interface: external
Client IPv6 Address: 2001:470:1234:567::2/64
Routed /64 subnet: 2001:470:890a:bcd::/64
LAN IPv6 interface IP: 2001:470:890a:bcd::1/64
DHCP6 scope: 2001:470:890a:bcd::1000/112
LAN firewall interface: internal
WAN firewall interface: external
Client IPv6 Address: 2001:470:1234:567::2/64
Routed /64 subnet: 2001:470:890a:bcd::/64
LAN IPv6 interface IP: 2001:470:890a:bcd::1/64
DHCP6 scope: 2001:470:890a:bcd::1000/112
IPv6 Tunnel
The first step is to establish a tunnel to your IPv6 provider, which in this case will be tunnelbroker.net.
First, allow tunnelbroker.net ICMP (ping) access to your IPv4 public IP:
config system accprofile
edit "no_access"
next
end
config system admin
edit "HE"
set trusthost1 66.220.2.74 255.255.255.255
set accprofile "no_access"
set vdom "root"
set password "your_own_secret"
next
end
Also make sure your external interface allows ping access:
config system interface
# your external interface name may be different
edit "external"
set allowaccess ping ...
next
end
Next, create a regular tunnel following this link. Once you've created the tunnel, configure your firewall as follows:
config system sit-tunnel
edit "HE"
set destination 216.66.80.26
set interface "external"
set ip6 "client IPv6 address/mask from HE portal (e.g. 2001:470:1234:567::2/64)"
next
end
config router static6
edit 1
set device "HE"
next
end
Test your work so far, by pinging your server's IPv6 tunnel end-point IP:
# exec ping6 2001:470:1234:567::1
PING 2001:470:1234:567::1(2001:470:1234:567::1) 56 data bytes
64 bytes from 2001:470:1234:567::1: icmp_seq=1 ttl=64 time=13.4 ms
64 bytes from 2001:470:1234:567::1: icmp_seq=2 ttl=64 time=13.2 ms
...
Also try pinging an external IPv6 IP (e.g. Google):
# exec ping6 ipv6.google.com
PING ipv6.google.com(2a00:1450:4009:802::1012) 56 data bytes
64 bytes from 2a00:1450:4009:802::1012: icmp_seq=1 ttl=59 time=14.3 ms
64 bytes from 2a00:1450:4009:802::1012: icmp_seq=2 ttl=59 time=14.0 ms
...
Public DNS
If you have a dynamic IPv4 IP assigned to you by your Internet service provider, you would probably want a DNS name automatically updated, when it changes.
Using the HE portal, on your Tunnel Details page, click "Edit" next to "rDNS delegation" and click the link titled "Delegate to dns.he.net".Next, head to dns.he.net and add a new domain, which you have registered with an IPv6 compliant registrar (check with the registra if they support "IPv6 glue records").
Edit the newly added domain zone, create a new A host record (e.g. myip.mydomain.com), making sure to tick "Enable entry for dynamic dns" and set the TTL to 5 minutes.
Click the DDNS icon next to you new record and generate a new API key.
Got to the "Advanced" tab of the tunnelbroker.net tunnel management portal and register your hostname and API key.
Last, go to your domain name registrar's admin portal and delegate your entire domain or a sub-domain to HE.net's name servers (there are five).
Dynamic DNS (DDNS)
Since I do not have a static IP address with my Internet service provider, I've configured FortiOS to update my external IPv4 address, when it changes using dyn.com as follows:
config system ddns
edit 1
set ddns-server dyndns.org
set ddns-domain "myhost.dyndns.org"
set ddns-username "my username"
set ddns-password "my password"
set monitor-interface "external"
next
end
The problem with this approach however, is that your IPv6 tunnel provider doesn't know about those changes and cannot update your tunnel's public IPv4 address. So, every time you reboot your DSL/cable modem and get a new IP, your IPv6 tunnel will be down.
FotiOS currently only supports the following DDNS services:
FortiGuardDDNS FortiGuard DDNS service.
dhs.org members.dhs.org
dipdns.net dipdnsserver.dipdns.com
dyndns.org members.dyndns.org and dnsalias.com
dyns.net www.dyns.net
easydns.com members.easydns.com
genericDDNS Generic DDNS based on RFC2136.
now.net.cn ip.todayisp.com
ods.org ods.org
tzo.com rh.tzo.com
vavic.com Peanut Hull
Note, HE.net is not on the list and since there is no generic dyndns2 protocol option, there is no way to tell your FortiGate firewall to automatically update your tunnel end-point IP.
So a workaround I've put in place, is to configure ddclient according to these instructions, to run on a local Linux server, periodically detect my public IP and update the tunnel end-point if it changes.
For reference, my /etc/ddclient.conf looks like this:
# Configuration file for ddclient
#
# /etc/ddclient.conf
daemon=600 # check every 600 seconds
syslog=yes # log update msgs to syslog
#mail=root # mail all msgs to root
#mail-failure=root # mail failed update msgs to root
pid=/var/run/ddclient.pid # record PID in file.
ssl=yes # use ssl-support. Works with
# ssl-library
protocol=dyndns2
use=web, web=checkip.dyndns.org, web-skip='IP Address'
server=ipv4.tunnelbroker.net
script=/nic/update
login=your_username
password=your_password
username=#.tunnel.tserv#.lon#.ipv6.he.net
This process updates your tunnel end-point IPv4 and since you've configured a hostname and API key on the tunnelbroker.net portal previously, it will also perform a chained update to your HE.net DDNS host entry.
In effect you will have two separate DDNS entries which both point to my dynamic IPv4 address:
- myip.mydomain.com
- myhost.dyndns.org
Ideally, you would want your firewall/router to do this as part of it's PPPoE interface-up routines, but we are where we are..
EDIT: I've written a very basic script to obtain the current public IP from the FortiGate firewall directly, rather than going out to a remote site.
To use it, save it to your favourite script location and update the "use=" line in your ddclient.conf as follows:
...
use=cmd, cmd=/scripts/use-fg.sh
...
Internal LAN
config system interface
# your internal interface name may be different
edit "internal"
...
config ipv6
set ip6-allowaccess ping https ssh snmp
set ip6-address "first IPv6/mask in the routed/64 prefix from HE portal (e.g. 2001:470:890a:bcd::1/64)"
set ip6-send-adv enable
set ip6-manage-flag enable
set ip6-other-flag enable
config ip6-prefix-list
edit "routed/64 IPv6 prefix from HE portal e.g. 2001:470:890a:bcd::/64"
set autonomous-flag disable
set onlink-flag enable
next
end
end
next
end
Some notes on important flags:
- ip6-send-adv enables router advertisement messages.
- autonomous-flag enables stateless IPv6 configuration (dynamically generated IPv6 addresses within the prefix).
- ip6-manage-flag means that there is a DHCP6 server on the network handing out IPs (stateful).
- ip6-other-flag means the DHCP6 server is also handing out DNS information, etc.
- onlink-flag basically means the prefix is on a local (layer 2) network.
Configure IPv6 address objects, which you will use later on in your IPv6 firewall policies:
config firewall address6
edit "all"
next
edit "net_2001:470:890a:bcd::/64"
set ip6 2001:470:890a:bcd::/64
next
end
Configure IPv6 firewall policies to allow access from your internal network and also to allow ICMP (ping) from hosts on the internet:
config firewall policy6
edit 1
set srcintf "HE"
set dstintf "internal"
set srcaddr "all"
set dstaddr "net_2001:470:890a:bcd::/64"
set action accept
set schedule "always"
set service "ALL_ICMP6"
next
edit 2
set srcintf "internal"
set dstintf "HE"
set srcaddr "net_2001:470:890a:bcd::/64"
set dstaddr "all"
set action accept
set schedule "always"
set service "ALL"
next
end
Test you work so far, by pinging your LAN IPv6 IP using an online ping tool while watching the tunnel interface with the packet sniffer:
# diag sniffer packet HE "icmp6" 4
interfaces=[HE]
filters=[icmp6]
pcap_lookupnet: HE: no IPv4 address assigned
4.211481 HE -- 2001:1640:3::3 -> 2001:470:890a:bcd::1: icmp6: echo request seq 1
4.211575 HE -- 2001:470:890a:bcd::1 -> 2001:1640:3::3: icmp6: echo reply seq 1
...
DHCP6/DNS
We will be using DHCP6 to hand out IPv6 IPs as well as DNS server information.
Configure local DNS server on the internal firewall interface, which will be handed out by your DHCP server(s):
config system dns-server
edit "internal"
next
end
Configure DHCP6 server:
config system dhcp6 server
edit 1
set interface "internal"
config ip-range
edit 1
set end-ip 2001:470:890a:bcd::ffff
set start-ip 2001:470:890a:bcd::1000
next
end
set lease-time 3600
set rapid-commit enable
set subnet 2001:470:890a:bcd::/112
set dns-server1 2001:470:890a:bcd::1
next
end
Assuming you are also running DHCP on your IPv4 network, you may also want to update it to use the local DNS server:
Renew your DHCP lease on your IPv6 client and check to make sure it obtained a correct IPv6 address from your DHCP6 server:
Note, you will also see a link-local IPv6 address, which is randomly generated.
Next, make sure the local DNS server on the firewall is handed out by your DHCP6 server:
You can also check the leases on the firewall, to see what IPs your IPv6 clients have been issued:
Now you should be able to ping an external IPv6 IP from your IPv6 enabled client:
config system dhcp server
edit 1
set dns-service local
next
end
Renew your DHCP lease on your IPv6 client and check to make sure it obtained a correct IPv6 address from your DHCP6 server:
$ ifconfig
eth0 Link encap:Ethernet HWaddr xx:xx:xx:xx:xx:xx
inet6 addr: 2001:470:890a:bcd::1000/128 Scope:Global
inet6 addr: fe80::ba27:ebff:fee9:d775/64 Scope:Link
...
Note, you will also see a link-local IPv6 address, which is randomly generated.
Next, make sure the local DNS server on the firewall is handed out by your DHCP6 server:
$ grep 2001 /etc/resolv.conf
nameserver 2001:470:890a:bcd::1
You can also check the leases on the firewall, to see what IPs your IPv6 clients have been issued:
BeastGate # exec dhcp6 lease-list
Interface DUID IAID IP Expiry
internal:xx:xx:xx:xx:xx:xx 15 2001:470:890a:bcd::1000 Mon Jun 24 10:48:27 2013
Now you should be able to ping an external IPv6 IP from your IPv6 enabled client:
$ ping6 -c 2 ipv6.google.com
PING6(56=40+8+8 bytes) 2001:470:890a:bcd::1000 --> 2a00:1450:4009:809::1012
16 bytes from 2a00:1450:4009:809::1012, icmp_seq=0 hlim=58 time=22.427 ms
16 bytes from 2a00:1450:4009:809::1012, icmp_seq=1 hlim=58 time=31.112 ms
NAT64/DNS64 (Optional)
NAT64 is used in pure IPv6 networks to allow access to IPv4 resources. In practical terms, it means you can switch off IPv4 on your internal network and continue accessing IPv4 sites on the Internet via your IPv6 tunnel. For compatibility reasons however, you would probably want to operate a mixed IPv4/IPv6 environment, until at least your Internet provider is able to support IPv6 natively.
First, re-configure your system settings to use DNS resolvers other than FortiGuard (e.g. Google and HE.net):
config system dns
set primary 8.8.8.8
set secondary 8.8.4.4
set ip6-primary 2001:470:20::2
set ip6-secondary 2001:4860:4860::8888
end
I found, that when the internal FortiGate DNS server is forwarding to the default FortiGuard DNS resolvers upstream, it completely breaks NAT64.
Next, enable and configure NAT64:
config system nat64
set status enable
set always-synthesize-aaaa-record disable
end
Note, we are disabing the automatic synthesis of IPv6 addresses, since we dont want a synthetic address generated if a host already has an IPv6 address. In this case, an address will by synthethised only if the host does not have an IPv6 AAAA record.
Add an IP pool abd firewall policy to support NAT(ing) of IPv6 addresses to IPv4:
config firewall ippool
edit "nat64-exit-pool"
next
end
config firewall policy64
edit 1
set srcintf "internal"
set dstintf "external"
set srcaddr "net_2001:470:890a:bcd::/64"
set dstaddr "all"
set action accept
set schedule "always"
set service "ALL"
set ippool enable
set poolname "nat64-exit-pool"
next
end
Now, switch off IPv4 support on your client and make sure you can no longer access an IPv4 only site (e.g. Fortinet):
$ curl -I -4 www.fortinet.com
curl: (7) Failed to connect to 66.171.121.34: No route to host
This is expected, since we have turned off IPv4, but told cURL to specifically use it to access the web site.
Next, try to resolve the IPv4 only site using an external DNS server (e.g. Google):
$ dig aaaa www.fortinet.com @8.8.8.8
...
;; QUESTION SECTION:
;www.fortinet.com. IN AAAA
Note that there are no IPv6 host records (AAAA) returned for www.fortinet.com.
Now try to resolve the same name using your internal DNS server, running on the firewall, which is now DNS64 enabled:
$ dig aaaa www.fortinet.com
...
;; QUESTION SECTION:
;www.fortinet.com. IN AAAA
;; ANSWER SECTION:
www.fortinet.com. 2339 IN AAAA 64:ff9b::42ab:7922
...
Note an IPv6 address is synthesised from the NAT64 Well-Known Prefix (64:ff9b::/96).
Finally, check to make sure you can access the web site using IPv6:
$ curl -I -6 www.fortinet.com
HTTP/1.1 200 OK
Date: Sun, 23 Jun 2013 17:24:26 GMT
Server: Apache/2.2.3 (Red Hat)
...
Testing
To test your IPv6 setup, head to test-ipv6.com, which should get you a similar result:
Note, at the point you should probably re-enable IPv4 and re-run the test. The only difference will be, that it won't warn you anymore about limited IPv4 connectivity and the use of NAT64/DNS64.
I hope you found this guide useful and if you find any mistakes or have any suggestions please feel free to comment.
References
I've used the following reference material to prepare the solution described in this article. Many thanks to the respective authors.
No comments:
Post a Comment