3

我想做这样的事情:

            10.1.1.0/24          10.1.2.0/24

+------------+       +------------+       +------------+
|            |       |            |       |            |
|            |       |            |       |            |
|     A    d +-------+ e   B    f +-------+ g   C      |
|            |       |            |       |            |
|            |       |            |       |            |
+------------+       +------------+       +------------+

    d              e           f           g
    10.1.1.1       10.1.1.2    10.1.2.1    10.1.2.2

这样就A可以将数据包发送到Cthrough B

我试图通过运行一个scapy程序来构建这个东西,B它会嗅探端口ef,并在每种情况下修改数据包中的目标 IP 和 MAC 地址,然后通过另一个接口发送它。就像是:

my_macs = [get_if_hwaddr(i) for i in get_if_list()]
pktcnt = 0
dest_mac_address = discover_mac_for_ip(dest_ip) # 
output_mac = get_if_hwaddr(output_interface)

def process_packet(pkt):
    # ignore packets that were sent from one of our own interfaces
    if pkt[Ether].src in my_macs:
        return

    pktcnt += 1
    p = pkt.copy()
    # if this packet has an IP layer, change the dst field
    # to our final destination
    if IP in p:
        p[IP].dst = dest_ip

    # if this packet has an ethernet layer, change the dst field
    # to our final destination. We have to worry about this since
    # we're using sendp (rather than send) to send the packet.  We
    # also don't fiddle with it if it's a broadcast address.
    if Ether in p \
       and p[Ether].dst != 'ff:ff:ff:ff:ff:ff':
        p[Ether].dst = dest_mac_address
        p[Ether].src = output_mac

    # use sendp to avoid ARP'ing and stuff
    sendp(p, iface=output_interface)

sniff(iface=input_interface, prn=process_packet)

然而,当我运行这个东西(这里的完整源代码)时,各种疯狂的事情开始发生......一些数据包通过了,我什至得到了一些响应(用 测试ping)但是有某种类型的反馈循环导致了一堆重复的数据包被发送......

有什么想法吗?尝试这样做是不是很疯狂?

我有点怀疑反馈循环是由B对数据包进行自己的一些处理这一事实引起的......有没有办法阻止操作系统在我嗅探数据包后处理它?

4

2 回答 2

3

使用 scapy 桥接 IP 数据包:

  1. 首先确保您禁用了 ip 转发,否则会注意到重复的数据包:

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

  1. 第二次运行以下 python/scapy 脚本:

!/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()

在我的电脑上:

# ./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]
于 2016-02-29T17:45:45.653 回答
2

这样做有点疯狂,但这并不是一个消磨时间的坏方法。你会学到很多有趣的东西。但是,您可能想考虑将数据包挂低一点 - 我不认为 scapy 能够真正拦截数据包 - libpcap 所做的一切都是让您混杂并让您看到所有内容,因此您和内核都得到相同的东西。如果您转身重新发送它,那可能是您的数据包风暴的原因。

但是,您可以设置一些创造性的防火墙规则,将每个接口彼此隔开,并以这种方式传递数据包,或者使用诸如转移套接字之类的东西将数据包从内核中偷走,这样您就可以随心所欲地处理它们.

于 2012-02-18T04:51:29.843 回答