Revision f8e790c4

b/kvm-vif-bridge
12 12
function clear_tap {
13 13

  
14 14
 arptables -D OUTPUT -o $INTERFACE --opcode request -j mangle >/dev/null 2>&1
15
 while ip rule del dev $INTERFACE; do :; done
16
 iptables -D FORWARD -i $INTERFACE -p udp --dport 67 -j DROP 2>/dev/null
15
 while ip rule del dev $INTERFACE; do :; done >/dev/null 2>&1
16
 iptables -D FORWARD -i $INTERFACE -p udp --dport 67 -j DROP > /dev/null 2>&1
17 17

  
18 18

  
19 19
}
......
24 24
	arptables -A OUTPUT -o $INTERFACE --opcode request -j mangle --mangle-ip-s    "$GATEWAY"
25 25

  
26 26
	# route interface to the proper routing table
27
	ip rule add dev $INTERFACE table $TABLE
27
	ip rule add dev $INTERFACE table $TABLE 
28 28

  
29 29
	# static route mapping IP -> INTERFACE
30 30
	ip route replace $IP proto static dev $INTERFACE table $TABLE
......
39 39
	uplink=$GATEWAY6
40 40
	eui64=$($MAC2EUI64 $MAC $prefix)
41 41

  
42
	while ip -6 rule del dev $INTERFACE; do :; done
42
  
43
	while ip -6 rule del dev $INTERFACE; do :; done > /dev/null 2>&1
43 44
	ip -6 rule add dev $INTERFACE table $TABLE
44 45
	ip -6 ro replace $eui64/128 dev $INTERFACE table $TABLE
45
	ip -6 neigh add proxy $eui64 dev $uplink
46
	ip -6 neigh add proxy $eui64 dev $uplink > /dev/null 2>&1
46 47

  
47 48
	# disable proxy NDP since we're handling this on userspace
48 49
	# this should be the default, but better safe than sorry
......
104 105
fi
105 106
if [ -n "$SUBNET6" ]; then
106 107
 echo SUBNET6=$SUBNET6 >> $FILE
108
 eui64=$($MAC2EUI64 $MAC $SUBNET6)
109
 echo EUI64=$eui64 >> $FILE
107 110
fi
108 111

  
109 112
}
......
116 119
  exist=$(ebtables -L | grep $TAP)
117 120

  
118 121
  if [ ! -z "$exist" ]; then
119
    ebtables -D INPUT -i $TAP -j $FROM
120
    ebtables -D FORWARD -i $TAP -j $FROM
121
    ebtables -D FORWARD -o $TAP -j $TO
122
    ebtables -D OUTPUT -o $TAP -j $TO
122
    ebtables -D INPUT -i $TAP -j $FROM > /dev/null 2>&1
123
    ebtables -D FORWARD -i $TAP -j $FROM > /dev/null 2>&1
124
    ebtables -D FORWARD -o $TAP -j $TO > /dev/null 2>&1
125
    ebtables -D OUTPUT -o $TAP -j $TO > /dev/null 2>&1
123 126

  
124
    ebtables -X $FROM
125
    ebtables -X $TO
127
    ebtables -X $FROM > /dev/null 2>&1
128
    ebtables -X $TO > /dev/null 2>&1
126 129
  fi
127 130
}
128 131

  
......
179 182
if [ "$MODE" = "routed" ]; then
180 183
  TABLE=rt_$NETWORK
181 184
	# special proxy-ARP/NDP routing mode
182
  clear_tap
185
  clear_tap > /dev/null 2>&1
186
  clear_ebtables >/dev/null 2>&1
183 187
	# use a constant predefined MAC address for the tap
184 188
	ip link set $INTERFACE addr $TAP_CONSTANT_MAC
185 189
	# bring the tap up
......
188 192
	# Drop unicast BOOTP/DHCP packets
189 193
	iptables -A FORWARD -i $INTERFACE -p udp --dport 67 -j DROP
190 194

  
191
	routed_setup_ipv4
192
	routed_setup_ipv6
195
	routed_setup_ipv4 > /dev/null 2>&1
196
	routed_setup_ipv6 > /dev/null 2>&1
193 197
	routed_setup_firewall
194 198
	setup_nfdhcpd $INTERFACE
195
  clear_ebtables >/dev/null 2>&1
196 199
elif [ "$MODE" = "bridged" ]; then
197
  clear_tap
200
  clear_tap > /dev/null 2>&1
198 201
  clear_ebtables >/dev/null 2>&1
199 202
	ifconfig $INTERFACE 0.0.0.0 up
200 203
	brctl addif $BRIDGE $INTERFACE
b/nfdhcpd/nfdhcpd
135 135
    gateway = None
136 136
    subnet6 = None
137 137
    gateway6 = None
138
    eui64 = None
138 139

  
139 140
    for line in iffile:
140 141
        if line.startswith("IP="):
......
154 155
            subnet6 = line.strip().split("=")[1]
155 156
        elif line.startswith("GATEWAY6="):
156 157
            gateway6 = line.strip().split("=")[1]
158
        elif line.startswith("EUI64="):
159
            eui64 = line.strip().split("=")[1]
157 160

  
158 161
    return Client(tap=tap, mac=mac, ips=ips, 
159 162
                  hostname=hostname, indev=indev, subnet=subnet,
160
                  gateway=gateway, subnet6=subnet6, gateway6=gateway6 )
163
                  gateway=gateway, subnet6=subnet6, gateway6=gateway6, eui64=eui64 )
161 164

  
162 165
class ClientFileHandler(pyinotify.ProcessEvent):
163 166
    def __init__(self, server):
......
183 186

  
184 187
class Client(object):
185 188
    def __init__(self, tap=None, indev=None, mac=None, ips=None, hostname=None, 
186
                 subnet=None, gateway=None, subnet6=None, gateway6=None ):
189
                 subnet=None, gateway=None, subnet6=None, gateway6=None, eui64=None ):
187 190
        self.mac = mac
188 191
        self.ips = ips
189 192
        self.hostname = hostname
......
195 198
        self.subnet6 = subnet6
196 199
        self.gateway6 = gateway6
197 200
        self.net6 = Subnet(net=subnet6, gw=gateway6, dev=tap)
201
        self.eui64 = eui64
198 202

  
199 203
    @property
200 204
    def ip(self):
......
296 300

  
297 301
        self.clients = {}
298 302
        #self.subnets = {}
299
        self.ifaces = {}
303
        #self.ifaces = {}
300 304
        #self.v6nets = {}
301 305
        self.nfq = {}
302 306
        self.l2socket = socket.socket(socket.AF_PACKET,
......
452 456
            if binding.is_valid():
453 457
                self.clients[binding.mac] = binding
454 458
                logging.debug("Added client %s on %s", binding.hostname, tap)
455
                self.ifaces[ifindex] = binding.indev
459
        logging.debug("clients %s", self.clients.keys())
456 460

  
457 461
    def remove_tap(self, tap):
458 462
        """ Cleanup clients on a removed interface
459 463

  
460 464
        """
461
        for mac in self.clients.keys():
462
            logging.debug("mac %s", mac)
463
            logging.debug("tap %s", self.clients[mac].tap)
464
            logging.debug("indev %s", self.clients[mac].indev)
465
            if self.clients[mac].tap == tap:
466
                indev = self.clients[mac].indev
467
                del self.clients[mac]
468

  
469
        for ifindex in self.ifaces.keys():
470
            if self.ifaces[ifindex] == indev == tap:
471
                del self.ifaces[ifindex]
465
        for b in self.clients.values():
466
            if b.tap == tap:
467
                del b
472 468

  
473 469
        logging.debug("Removed interface %s", tap)
474 470

  
......
476 472
        """ Generate a reply to bnetfilter-queue-deva BOOTP/DHCP request
477 473

  
478 474
        """
479
        indevidx = payload.get_indev()
480
        try:
481
            # Get the actual interface from the ifindex
482
            indev = self.ifaces[indevidx]
483
        except KeyError:
484
            # We don't know anything about this interface, so accept the packet
485
            # and return
486
            logging.debug("Ignoring DHCP request on unknown iface %d", indev)
487
            # We don't know what to do with this packet, so let the kernel
488
            # handle it
489
            payload.set_verdict(nfqueue.NF_ACCEPT)
490
            return
491

  
492 475
        # Decode the response - NFQUEUE relays IP packets
493 476
        pkt = IP(payload.get_data())
494 477

  
495
        # Signal the kernel that it shouldn't further process the packet
496
        payload.set_verdict(nfqueue.NF_DROP)
497

  
498 478
        # Get the client MAC address
499 479
        resp = pkt.getlayer(BOOTP).copy()
500 480
        hlen = resp.hlen
......
508 488
        try:
509 489
            binding = self.clients[mac]
510 490
        except KeyError:
511
            logging.warn("Invalid client %s on %s", mac, indev)
491
            logging.warn("Invalid client for mac %s ", mac)
492
            payload.set_verdict(nfqueue.NF_ACCEPT)
512 493
            return
513 494

  
514
        if indev != binding.indev:
515
            logging.warn("Received spoofed DHCP request for %s from interface"
516
                         " %s instead of %s", mac, indev, binding.indev)
517
            return
495
        # Signal the kernel that it shouldn't further process the packet
496
        payload.set_verdict(nfqueue.NF_DROP)
518 497

  
519
        resp = Ether(dst=mac, src=self.get_iface_hw_addr(indev))/\
498
        resp = Ether(dst=mac, src=self.get_iface_hw_addr(binding.indev))/\
520 499
               IP(src=DHCP_DUMMY_SERVER_IP, dst=binding.ip)/\
521 500
               UDP(sport=pkt.dport, dport=pkt.sport)/resp
522 501
        subnet = binding.net
......
579 558
        ]
580 559
        resp /= DHCP(options=dhcp_options)
581 560

  
561
        if payload.get_indev() != self.get_ifindex(binding.indev):
562
            logging.warn("Received spoofed DHCP request for %s from interface"
563
                         " %s instead of %s", mac, payload.get_indev(), binding.indev)
564
            return
565

  
582 566
        logging.info("%s to %s (%s) on %s", DHCP_TYPES[resp_type], mac,
583 567
                     binding.ip, binding.tap)
584
        self.sendp(resp, indev )
568
        self.sendp(resp, binding.indev)
585 569

  
586 570
    def rs_response(self, i, payload): # pylint: disable=W0613
587 571
        """ Generate a reply to a BOOTP/DHCP request
588 572

  
589 573
        """
590
        indevidx = payload.get_indev()
574
        pkt = IPv6(payload.get_data())
575
        mac = pkt.lladdr
576
        logging.debug("rs for mac %s", mac)
591 577
        try:
592
            # Get the actual interface from the ifindex
593
            indev = self.ifaces[indevidx]
578
          binding = self.clients[mac]
594 579
        except KeyError:
595 580
            logging.debug("Ignoring router solicitation on"
596
                          " unknown interface %d", indev)
581
                          " for mac %s", mac)
597 582
            # We don't know what to do with this packet, so let the kernel
598 583
            # handle it
599 584
            payload.set_verdict(nfqueue.NF_ACCEPT)
600 585
            return
586
  
587
        # Signal the kernel that it shouldn't further process the packet
588
        payload.set_verdict(nfqueue.NF_DROP)
589

  
590
        subnet = binding.net6
601 591

  
602
        binding = [ b for b in self.clients.values() if b.tap == indev ]
603
        subnet = binding[0].net6
604 592
        if subnet.net is None:
605 593
          logging.debug("No IPv6 network assigned for the interface")
606 594
          return
595

  
596
        ifmac = self.get_iface_hw_addr(binding.indev)
607 597
        ifll = subnet.make_ll64(ifmac)
608 598

  
609
        # Signal the kernel that it shouldn't further process the packet
610
        payload.set_verdict(nfqueue.NF_DROP)
611 599

  
612
        resp = Ether(src=self.get_iface_hw_addr(indev))/\
600
        resp = Ether(src=ifmac)/\
613 601
               IPv6(src=str(ifll))/ICMPv6ND_RA(routerlifetime=14400)/\
614 602
               ICMPv6NDOptPrefixInfo(prefix=str(subnet.prefix),
615 603
                                     prefixlen=subnet.prefixlen)
......
618 606
            resp /= ICMPv6NDOptRDNSS(dns=self.ipv6_nameservers,
619 607
                                     lifetime=self.ra_period * 3)
620 608

  
621
        logging.info("RA on %s for %s", indev, subnet.net)
622
        self.sendp(resp, indev)
609
        logging.info("RA on %s for %s", binding.indev, subnet.net)
610
        self.sendp(resp, binding.indev)
623 611

  
624 612
    def ns_response(self, i, payload): # pylint: disable=W0613
625 613
        """ Generate a reply to an ICMPv6 neighbor solicitation
626 614

  
627 615
        """
628
        indevidx = payload.get_indev()
629
        try:
630
            # Get the actual interface from the ifindex
631
            indev = self.ifaces[indevidx]
632
        except KeyError:
616
        ns = IPv6(payload.get_data())
617

  
618
        binding = None
619
        for b in self.clients.values():
620
          if b.eui64 == ns.tgt:
621
            binding = b
622
            break
623

  
624
        if binding is None:
633 625
            logging.debug("Ignoring neighbour solicitation on"
634
                          " unknown interface %d", indev)
626
                          " for eui64 %s", ns.tgt)
635 627
            # We don't know what to do with this packet, so let the kernel
636 628
            # handle it
637 629
            payload.set_verdict(nfqueue.NF_ACCEPT)
638 630
            return
639 631

  
640
        binding = [ b for b in self.clients.values() if b.tap == indev ]
641
        subnet = binding[0].net6
632
        payload.set_verdict(nfqueue.NF_DROP)
633

  
634
        subnet = binding.net6
642 635
        if subnet.net is None:
643 636
          logging.debug("No IPv6 network assigned for the interface")
644 637
          return
645 638

  
646
        indevmac = self.get_iface_hw_addr(indev)
639
        indevmac = self.get_iface_hw_addr(binding.indev)
647 640

  
648 641
        ifll = subnet.make_ll64(indevmac)
649 642

  
650
        ns = IPv6(payload.get_data())
651

  
652 643
        if not (subnet.net.overlaps(ns.tgt) or str(ns.tgt) == str(ifll)):
653 644
            logging.debug("Received NS for a non-routable IP (%s)", ns.tgt)
654 645
            payload.set_verdict(nfqueue.NF_ACCEPT)
655 646
            return 1
656 647

  
657
        payload.set_verdict(nfqueue.NF_DROP)
658

  
659
        try:
660
            client_lladdr = ns.lladdr
661
        except AttributeError:
662
            return 1
663
        
664
        resp = Ether(src=indevmac, dst=client_lladdr)/\
648
        logging.debug("na ether %s %s", binding.mac, ns.src)
649
        resp = Ether(src=indevmac, dst=binding.mac)/\
665 650
               IPv6(src=str(ifll), dst=ns.src)/\
666 651
               ICMPv6ND_NA(R=1, O=0, S=1, tgt=ns.tgt)/\
667 652
               ICMPv6NDOptDstLLAddr(lladdr=indevmac)
668 653

  
669
        logging.info("NA on %s for %s", indev, ns.tgt)
670
        self.sendp(resp, indev)
671
        return 1
654
        logging.info("NA on %s for %s", binding.indev, ns.tgt)
655
        self.sendp(resp, binding.indev)
672 656

  
673 657
    def send_periodic_ra(self):
674 658
        # Use a separate thread as this may take a _long_ time with

Also available in: Unified diff