writing an ethernet bridge in python with scapy

后端 未结 2 955
遇见更好的自我
遇见更好的自我 2021-01-03 09:27

I\'d like to make something like this:

            10.1.1.0/24          10.1.2.0/24

+------------+       +------------+       +------------+
|            |          


        
相关标签:
2条回答
  • 2021-01-03 09:59

    It is kinda crazy to do this, but it's not a bad way to spend your time. You'll learn a bunch of interesting stuff. However you might want to think about hooking the packets a little lower - I don't think scapy is capable of actually intercepting packets - all libpcap does is set you promisc and let you see everything, so you and the kernel are both getting the same stuff. If you're turning around and resending it, thats likely the cause of your packet storm.

    However, you could set up some creative firewall rules that partition each interface off from each-other and hand the packets around that way, or use something like divert sockets to actually thieve the packets away from the kernel so you can have your way with them.

    0 讨论(0)
  • 2021-01-03 10:09

    IP packets bridging using scapy:

    1. first make sure you have ip forwarding disabled otherwise duplicate packets will be noticed:

    echo "0" > /proc/sys/net/ipv4/ip_forward <br>

    1. second run the following python/scapy script:

    !/usr/bin/python2

    from optparse import OptionParser
    from scapy.all import *
    from threading import Thread
    from struct import pack, unpack
    from time import sleep
    
    def sp_byte(val):
        return pack("<B", val)
    
    def su_nint(str):
        return unpack(">I", str)[0]
    
    def ipn2num(ipn):
        """ipn(etwork) is BE dotted string ip address
        """
        if ipn.count(".") != 3:
            print("ipn2num warning: string < %s > is not proper dotted IP address" % ipn)
    
        return su_nint( "".join([sp_byte(int(p)) for p in ipn.strip().split(".")]))
    
    def get_route_if(iface):
        try:
            return [route for route in conf.route.routes if route[3] == iface and route[2] == "0.0.0.0"][0]
        except IndexError:
            print("Interface '%s' has no ip address configured or link is down?" % (iface));
            return None;
    
    class PacketCapture(Thread):
    
        def __init__(self, net, nm, recv_iface, send_iface):
            Thread.__init__(self)
            
            self.net = net
            self.netmask = nm
            self.recv_iface = recv_iface
            self.send_iface = send_iface
            self.recv_mac = get_if_hwaddr(recv_iface)
            self.send_mac = get_if_hwaddr(send_iface)
            self.filter = "ether dst %s and ip" % self.recv_mac
            self.arp_cache = []
    
            self.name = "PacketCapture(%s on %s)" % (self.name, self.recv_iface)
    
            self.fw_count = 0
    
        def run(self):
            
            print("%s: waiting packets (%s) on interface %s" % (self.name, self.filter, self.recv_iface))
    
            sniff(count = 0,  prn = self.process, store = 0, filter = self.filter, iface = self.recv_iface)
    
        def process(self, pkt):
    
            # only bridge IP packets
            if pkt.haslayer(Ether) and pkt.haslayer(IP):
    
                dst_n = ipn2num(pkt[IP].dst)
                
                if dst_n & self.netmask != self.net:
                    # don't forward if the destination ip address
                    # doesn't match the destination network address
                    return
                
                # update layer 2 addresses
                rmac = self.get_remote_mac(pkt[IP].dst)
                if rmac == None:
                    print("%s: packet not forwarded %s %s -) %s %s" % (self.name, pkt[Ether].src, pkt[IP].src, pkt[Ether].dst, pkt[IP].dst))
                    return
    
                pkt[Ether].src = self.send_mac
                pkt[Ether].dst = rmac
                
                #print("%s: forwarding %s %s -> %s %s" % (self.name, pkt[Ether].src, pkt[IP].src, pkt[Ether].dst, pkt[IP].dst))
    
                sendp(pkt, iface = self.send_iface)
    
                self.fw_count += 1
        
        def get_remote_mac(self, ip):
    
            mac = ""
    
            for m in self.arp_cache:
                if m["ip"] == ip and m["mac"]:
                    return m["mac"]
    
            mac = getmacbyip(ip)
            if mac == None:
                print("%s: Could not resolve mac address for destination ip address %s" % (self.name, ip))
            else:
                self.arp_cache.append({"ip": ip, "mac": mac})
    
            return mac
    
        def stop(self):
            Thread._Thread__stop(self)
            print("%s stopped" % self.name)
    
    
    if __name__ == "__main__":
        parser = OptionParser(description = "Bridge packets", prog = "brscapy", usage = "Usage: brscapy -l <intf> (--left= <intf>) -r <inft> (--right=<intf>)")
        parser.add_option("-l", "--left",  action = "store", dest = "left",  default = None, choices = get_if_list(), help = "Left side network interface of the bridge")
        parser.add_option("-r", "--right", action = "store", dest = "right", default = None, choices = get_if_list(), help = "Right side network interface of the bridge")
    
        args, opts = parser.parse_args()
        
        if len(sys.argv) == 1:
            parser.print_help()
            sys.exit(1)
        
        lif = args.left
        rif = args.right
    
        lroute = get_route_if(lif)
        rroute = get_route_if(rif)
    
        if (lroute == None or rroute == None):
            print("Invalid ip addressing on given interfaces");
            exit(1)
        
        if (len(lroute) != 5 or len(rroute) != 5):
            print("Invalid scapy routes")
            exit(1)
        
        conf.verb = 0
    
        lthread = PacketCapture(rroute[0], rroute[1], lif, rif)
        rthread = PacketCapture(lroute[0], lroute[1], rif, lif)
    
        lthread.start()
        rthread.start()
    
        try:
            while True:
                sys.stdout.write("FORWARD count: [%s -> %s  %d] [%s <- %s  %d]\r" % (lif, rif, lthread.fw_count, lif, rif, rthread.fw_count))
                sys.stdout.flush()
                sleep(0.1)
        except KeyboardInterrupt:
            pass
    
        lthread.stop()
        rthread.stop()
    
        lthread.join()
        rthread.join()
    

    On my pc:

    # ./brscapy.py --help
    Usage: brscapy -l <intf> (--left= <intf>) -r <inft> (--right=<intf>)
    
    Bridge packets
    
    Options:
      -h, --help            show this help message and exit
      -l LEFT, --left=LEFT  Left side network interface of the bridge
      -r RIGHT, --right=RIGHT
                            Right side network interface of the bridge
    
    # ./brscapy.py -l e0 -r e2
    PacketCapture(Thread-1 on e0): waiting packets (ether dst 00:16:41:ea:ff:dc and ip) on interface e0
    PacketCapture(Thread-2 on e2): waiting packets (ether dst 00:0d:88:cc:ed:15 and ip) on interface e2
    FORWARD count: [e0 -> e2  5] [e0 <- e2  5]
    
    0 讨论(0)
提交回复
热议问题