Commit 06e6d9bc authored by Dimitris Aragiorgis's avatar Dimitris Aragiorgis

Support ra-stateless IPv6 configuration

This means that IPv6 will be auto-configured but DNS info
will be obtained via DHCPv6 requests.

With other words our router advertisements have the "O" flag set
and we add another handler that serves DHCPv6 requests by
passing DNS info.

Use a separate NFQUEUE to mangle the DHCPv6 traffic. Add another
ferm rule to achieve that.

This is done because Windows do not support RFC 6101:

http://tools.ietf.org/search/rfc6106
http://social.technet.microsoft.com/Forums/windowsserver/en-US/5757980a-5983-4efc-a5f3-27687b90fe41/does-win7-or-w2k8-server-support-rfc-6106?forum=ipv6Signed-off-by: 's avatarDimitris Aragiorgis <dimara@grnet.gr>
parent fac9f928
......@@ -53,6 +53,9 @@ from scapy.layers.inet6 import IPv6, ICMPv6ND_RA, ICMPv6ND_NA, \
ICMPv6NDOptPrefixInfo, \
ICMPv6NDOptRDNSS
from scapy.layers.dhcp import BOOTP, DHCP
from scapy.layers.dhcp6 import DHCP6_Reply, DHCP6OptDNSServers, \
DHCP6OptServerId, DHCP6OptClientId, \
DUID_LLT, DHCP6_InfoRequest
DEFAULT_CONFIG = "/etc/nfdhcpd/nfdhcpd.conf"
......@@ -91,6 +94,7 @@ enable_ipv6 = boolean(default=True)
ra_period = integer(min=1, max=4294967295)
rs_queue = integer(min=0, max=65535)
ns_queue = integer(min=0, max=65535)
dhcp_queue = integer(min=0, max=65535)
nameservers = ip_addr_list(family=6)
"""
......@@ -349,7 +353,7 @@ class Subnet(object):
class VMNetProxy(object): # pylint: disable=R0902
def __init__(self, data_path, dhcp_queue_num=None, # pylint: disable=R0913
rs_queue_num=None, ns_queue_num=None,
rs_queue_num=None, ns_queue_num=None, dhcpv6_queue_num=None,
dhcp_lease_lifetime=DEFAULT_LEASE_LIFETIME,
dhcp_lease_renewal=DEFAULT_LEASE_RENEWAL,
dhcp_domain='',
......@@ -405,6 +409,10 @@ class VMNetProxy(object): # pylint: disable=R0902
self._setup_nfqueue(ns_queue_num, AF_INET6, self.ns_response, 10)
self.ipv6_enabled = True
if dhcpv6_queue_num is not None:
self._setup_nfqueue(dhcpv6_queue_num, AF_INET6, self.dhcpv6_response, 10)
self.ipv6_enabled = True
def get_binding(self, ifindex, mac):
try:
if self.mac_indexed_clients:
......@@ -694,6 +702,68 @@ class VMNetProxy(object): # pylint: disable=R0902
logging.warn(" - Unkown error during DHCP response on %s (%s): %s",
binding.tap, binding.hostname, str(e))
def dhcpv6_response(self, arg1, arg2=None): # pylint: disable=W0613
logging.info(" * Processing pending DHCPv6 request")
# Workaround for supporting both squeezy's nfqueue-bindings-python
# and wheezy's python-nfqueue because for some reason the function's
# signature has changed and has broken compatibility
# See bug http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=718894
if arg2:
payload = arg2
else:
payload = arg1
pkt = IPv6(payload.get_data())
indev = get_indev(payload)
#TODO: figure out how to find the src mac
mac = None
binding = self.get_binding(indev, mac)
if binding is None:
# We don't know anything about this interface, so accept the packet
# and return
logging.debug(" - Ignoring dhcpv6 request for mac %s", mac)
# We don't know what to do with this packet, so let the kernel
# handle it
payload.set_verdict(nfqueue.NF_ACCEPT)
return
# Signal the kernel that it shouldn't further process the packet
payload.set_verdict(nfqueue.NF_DROP)
subnet = binding.net6
indevmac = self.get_iface_hw_addr(binding.indev)
ifll = subnet.make_ll64(indevmac)
if ifll is None:
return
ofll = subnet.make_ll64(binding.mac)
if ofll is None:
return
logging.info(" - Generating DHCPv6 response for host %s (mac %s) on tap %s",
binding.hostname, binding.mac, binding.tap)
resp = Ether(src=indevmac, dst=binding.mac)/\
IPv6(tc=192, src=str(ifll), dst=str(ofll))/\
UDP(sport=pkt.dport, dport=pkt.sport)/\
DHCP6_Reply(trid=pkt[DHCP6_InfoRequest].trid)/\
DHCP6OptClientId(duid=pkt[DHCP6OptClientId].duid)/\
DHCP6OptServerId(duid=DUID_LLT(lladdr=indevmac, timeval=time.time()))/\
DHCP6OptDNSServers(dnsservers=self.ipv6_nameservers,
optlen=16 * len(self.ipv6_nameservers))
try:
binding.sendp(resp)
except socket.error, e:
logging.warn(" - DHCPv6 on %s (%s) failed: %s",
binding.tap, binding.hostname, str(e))
except Exception, e:
logging.warn(" - Unkown error during DHCPv6 on %s (%s): %s",
binding.tap, binding.hostname, str(e))
def rs_response(self, arg1, arg2=None): # pylint: disable=W0613
""" Generate a reply to a BOOTP/DHCP request
......@@ -750,7 +820,7 @@ class VMNetProxy(object): # pylint: disable=R0902
binding.hostname, mac, binding.tap)
resp = Ether(src=indevmac)/\
IPv6(src=str(ifll))/ICMPv6ND_RA(routerlifetime=14400)/\
IPv6(src=str(ifll))/ICMPv6ND_RA(O=1, routerlifetime=14400)/\
ICMPv6NDOptPrefixInfo(prefix=str(subnet.prefix),
prefixlen=subnet.prefixlen)
......@@ -1111,6 +1181,7 @@ if __name__ == "__main__":
if config["ipv6"].as_bool("enable_ipv6"):
proxy_opts.update({
"dhcpv6_queue_num": config["ipv6"].as_int("dhcp_queue"),
"rs_queue_num": config["ipv6"].as_int("rs_queue"),
"ns_queue_num": config["ipv6"].as_int("ns_queue"),
"ra_period": config["ipv6"].as_int("ra_period"),
......
......@@ -24,5 +24,6 @@ enable_ipv6 = yes
ra_period = 300 # seconds
rs_queue = 43 # NFQUEUE number to listen on for router solicitations
ns_queue = 44 # NFQUEUE number to listen on for neighbor solicitations
dhcp_queue = 45 # NFQUEUE number to listen on for neighbor solicitations
# IPv6 nameservers to send using the ICMPv6 RA RDNSS option (RFC 5006)
nameservers = 2001:db8:100::1, 2001:db8:200::2
......@@ -3,6 +3,7 @@ domain ip {
chain PREROUTING {
interface tap+ proto udp dport 67 NFQUEUE queue-num 42;
interface prv+ proto udp dport 67 NFQUEUE queue-num 42;
interface br+ proto udp dport 67 NFQUEUE queue-num 42;
}
}
}
......@@ -12,6 +13,7 @@ domain ip6 {
chain PREROUTING {
interface tap+ proto icmpv6 icmpv6-type router-solicitation NFQUEUE queue-num 43;
interface tap+ proto icmpv6 icmpv6-type neighbour-solicitation NFQUEUE queue-num 44;
interface tap+ proto udp dport 547 NFQUEUE queue-num 45;
}
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment