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パケットを送信できます。CB

ポートとをスニッフィングするscapyプログラムを実行してこの機能を構築しようとしました。いずれの場合も、パケット内の宛先IPアドレスとMACアドレスを変更して、他のインターフェイスを介して送信します。何かのようなもの:Bef

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パケットに対して独自の処理を行っていることが原因であるのではないかと疑っています...パケットをスニッフィングした後、OSがパケットを処理しないようにする方法はありますか?

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

私の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]
于 2016-02-29T17:45:45.653 に答える
2

これを行うのはちょっとクレイジーですが、それはあなたの時間を過ごすのに悪い方法ではありません。あなたはたくさんの面白いことを学ぶでしょう。ただし、パケットを少し低くフックすることを検討することをお勧めします-scapyが実際にパケットを傍受できるとは思いません-libpcapが行うことはすべて、promiscを設定し、すべてを表示できるようにすることです。したがって、ユーザーとカーネルは両方とも同じになります。もの。振り返って再送する場合は、パケットストームの原因である可能性があります。

ただし、各インターフェイスを相互に分割してパケットをそのように渡すいくつかのクリエイティブなファイアウォールルールを設定するか、迂回ソケットなどを使用して実際にカーネルからパケットを盗み出し、それらを使用できるようにすることができます。 。

于 2012-02-18T04:51:29.843 に答える