Commit f54e48af authored by Dimitris Aragiorgis's avatar Dimitris Aragiorgis

Refactor nfdhcpd to support get_physindev()

If get_physindev is supported in nfqueue then the clients are indexed
by their tap ifindex. If not then clients are indexed by their macs.
Signed-off-by: default avatarDimitris Aragiorgis <dimara@grnet.gr>
parent d2c81e80
......@@ -117,6 +117,33 @@ DHCP_REQRESP = {
}
def get_indev(payload):
try:
indev_ifindex = payload.get_physindev()
if indev_ifindex:
logging.debug("Incomming packet from bridge %s", indev_ifindex)
return indev_ifindex
except AttributeError:
#TODO: return error value
logging.debug("No get_physindev supported")
return 0
indev_ifindex = payload.get_indev()
logging.debug("Incomming packet from tap %s", indev_ifindex)
return indev_ifindex
def get_binding(proxy, ifindex, mac):
try:
if proxy.mac_indexed_clients:
b = proxy.clients[mac]
else:
b = proxy.clients[ifindex]
return b
except KeyError:
logging.debug("No client found for mac/ifindex %s/%s", mac, ifindex)
return None
def parse_binding_file(path):
""" Read a client configuration from a tap file
......@@ -284,6 +311,11 @@ class VMNetProxy(object): # pylint: disable=R0902
dhcp_server_ip=DHCP_DUMMY_SERVER_IP, dhcp_nameservers=None,
ra_period=DEFAULT_RA_PERIOD, ipv6_nameservers=None):
try:
getattr(nfqueue.payload, 'get_physindev')
self.mac_indexed_clients = False
except AttributeError:
self.mac_indexed_clients = True
self.data_path = data_path
self.lease_lifetime = dhcp_lease_lifetime
self.lease_renewal = dhcp_lease_renewal
......@@ -458,24 +490,31 @@ class VMNetProxy(object): # pylint: disable=R0902
logging.warn("Stale configuration for %s found", tap)
else:
if b.is_valid():
self.clients[b.mac] = b
if self.mac_indexed_clients:
self.clients[b.mac] = b
else:
self.clients[ifindex] = b
logging.debug("Added client:")
logging.debug("%10s %20s %7s %15s", b.hostname, b.mac, b.tap, b.ip)
logging.debug("%5s: %10s %20s %7s %15s",
ifindex, b.hostname, b.mac, b.tap, b.ip)
logging.debug("\n\n\n\n\n")
logging.debug("%10s %20s %7s %15s", 'Client', 'MAC', 'TAP', 'IP')
for mac in self.clients.keys():
b = self.clients[mac]
logging.debug("%10s %20s %7s %15s", b.hostname, b.mac, b.tap, b.ip)
for b in self.clients.values():
logging.debug("%10s %20s %7s %15s", b.hostname, b.mac, b.tap, b.ip)
def remove_tap(self, tap):
""" Cleanup clients on a removed interface
"""
for b in self.clients.values():
if b.tap == tap:
#os.remove(self.data_path+'/'+tap)
logging.debug("Removed interface %s", self.data_path+'/'+tap)
logging.debug("%10s %20s %7s %15s", b.hostname, b.mac, b.tap, b.ip)
del b
try:
for k in self.clients.keys():
if self.clients[k].tap = tap:
logging.debug("Removing client on interface %s", tap)
logging.debug("%10s %20s %7s %15s",
b.hostname, b.mac, b.tap, b.ip)
del self.clients[k]
except:
logging.debug("Client on %s disappeared!!!", tap)
def dhcp_response(self, i, payload): # pylint: disable=W0613,R0914
......@@ -485,7 +524,7 @@ class VMNetProxy(object): # pylint: disable=R0902
# Decode the response - NFQUEUE relays IP packets
pkt = IP(payload.get_data())
logging.debug("IN DHCP RESPONCE")
logging.debug(pkt.show())
#logging.debug(pkt.show())
# Get the client MAC address
resp = pkt.getlayer(BOOTP).copy()
......@@ -497,16 +536,26 @@ class VMNetProxy(object): # pylint: disable=R0902
resp.op = "BOOTREPLY"
del resp.payload
try:
binding = self.clients[mac]
except KeyError:
logging.warn("Invalid client for mac %s ", mac)
indev = get_indev(payload)
binding = get_binding(self, indev, mac)
if binding is None:
# We don't know anything about this interface, so accept the packet
# and return
logging.debug("Ignoring DHCP request on unknown iface %d", indev)
# 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)
if mac != binding.mac:
logging.warn("Recieved spoofed DHCP request for mac %s from tap %s", mac, tap)
return
resp = Ether(dst=mac, src=self.get_iface_hw_addr(binding.indev))/\
IP(src=DHCP_DUMMY_SERVER_IP, dst=binding.ip)/\
UDP(sport=pkt.dport, dport=pkt.sport)/resp
......@@ -536,12 +585,12 @@ class VMNetProxy(object): # pylint: disable=R0902
if req_type == DHCPREQUEST and requested_addr != binding.ip:
resp_type = DHCPNAK
logging.info("Sending DHCPNAK to %s on %s: requested %s"
" instead of %s", binding.mac, binding.tap, requested_addr,
binding.ip)
" instead of %s", binding.mac, binding.tap,
requested_addr, binding.ip)
elif req_type in (DHCPDISCOVER, DHCPREQUEST):
resp_type = DHCP_REQRESP[req_type]
resp.yiaddr = self.clients[mac].ip
resp.yiaddr = binding.ip
dhcp_options += [
("hostname", binding.hostname),
("domain", domainname),
......@@ -575,11 +624,6 @@ class VMNetProxy(object): # pylint: disable=R0902
]
resp /= DHCP(options=dhcp_options)
if payload.get_indev() != self.get_ifindex(binding.indev):
logging.warn("Received spoofed DHCP request for %s from interface"
" %s instead of %s", mac, payload.get_indev(), binding.indev)
return
logging.info("%s to %s (%s) on %s", DHCP_TYPES[resp_type], mac,
binding.ip, binding.tap)
self.sendp(resp, binding.indev)
......@@ -590,14 +634,17 @@ class VMNetProxy(object): # pylint: disable=R0902
"""
pkt = IPv6(payload.get_data())
logging.debug("IN RS RESPONCE")
logging.debug(pkt.show())
#logging.debug(pkt.show())
mac = pkt.lladdr
logging.debug("rs for mac %s", mac)
try:
binding = self.clients[mac]
except KeyError:
logging.debug("Ignoring router solicitation on"
" for mac %s", mac)
indev = get_indev(payload)
binding = get_binding(self, indev, mac)
if binding is None:
# We don't know anything about this interface, so accept the packet
# and return
logging.debug("Ignoring router solicitation on 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)
......@@ -606,17 +653,21 @@ class VMNetProxy(object): # pylint: disable=R0902
# Signal the kernel that it shouldn't further process the packet
payload.set_verdict(nfqueue.NF_DROP)
if mac != binding.mac:
logging.warn("Recieved spoofed RS request for mac %s from tap %s", mac, tap)
return
subnet = binding.net6
if subnet.net is None:
logging.debug("No IPv6 network assigned for the interface")
return
ifmac = self.get_iface_hw_addr(binding.indev)
ifll = subnet.make_ll64(ifmac)
indevmac = self.get_iface_hw_addr(binding.indev)
ifll = subnet.make_ll64(indevmac)
resp = Ether(src=ifmac)/\
resp = Ether(src=indevmac)/\
IPv6(src=str(ifll))/ICMPv6ND_RA(routerlifetime=14400)/\
ICMPv6NDOptPrefixInfo(prefix=str(subnet.prefix),
prefixlen=subnet.prefixlen)
......@@ -635,26 +686,33 @@ class VMNetProxy(object): # pylint: disable=R0902
ns = IPv6(payload.get_data())
logging.debug("IN NS RESPONCE")
logging.debug(ns.show())
mac = ns.lladdr
logging.debug("dst %s tgt %s" , ns.dst, ns.tgt)
try:
binding = self.clients[ns.lladdr]
except:
logging.debug("Ignoring neighbour solicitation for eui64 %s", ns.tgt)
# We don't know what to do with this packet, so let the kernel
# handle it
payload.set_verdict(nfqueue.NF_ACCEPT)
return
indev = get_indev(payload)
binding = get_binding(self, indev, mac)
if binding is None:
# We don't know anything about this interface, so accept the packet
# and return
logging.debug("Ignoring neighbour solicitation for eui64 %s", ns.tgt)
# We don't know what to do with this packet, so let the kernel
# handle it
payload.set_verdict(nfqueue.NF_ACCEPT)
return
payload.set_verdict(nfqueue.NF_DROP)
if mac != binding.mac:
logging.warn("Recieved spoofed NS request for mac %s from tap %s", mac, tap)
return
subnet = binding.net6
if subnet.net is None:
logging.debug("No IPv6 network assigned for the interface")
payload.set_verdict(nfqueue.NF_ACCEPT)
return
payload.set_verdict(nfqueue.NF_DROP)
indevmac = self.get_iface_hw_addr(binding.indev)
ifll = subnet.make_ll64(indevmac)
......
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