Beaglebone Black 无法使用 Python 将原始 UDP 数据包发送到运行 Ubuntu 16.04 的笔记本电脑

Beaglebone Black 无法使用 Python 将原始 UDP 数据包发送到运行 Ubuntu 16.04 的笔记本电脑

我创建了一个 Python 3.6 脚本,该脚本通过以太网创建原始 UDP 数据包到具有已知 MAC 地址和 IPv4 地址的系统。该脚本在 Beaglebone Black (BBB) 上运行,该 BBB 通过以太网直接连接到运行 Ubuntu 16.04 的笔记本电脑。该脚本也在Ubuntu系统上运行(src和dst地址明显改变)。我还通过串行连接访问 BBB 终端。 BBB 可以成功 ping 笔记本电脑,反之亦然。当笔记本电脑运行Python脚本时,数据包显示为Wireshark发送的,以太网端口灯闪烁,然后tcpdumpBBB上运行的实例确认数据包已发送。但是在BBB上运行脚本时, tcpdumpBBB上的实例显示数据包已发送;但以太网端口灯不亮,笔记本电脑没有收到数据包。在两个系统启动时,当我运行时ifconfig,两个以太网接口都没有 IP 地址,因此我必须将它们设置为任意地址(即使在我这样做之前,数据包也会将笔记本电脑发送到 BBB,而不是相反)。

笔记本电脑的 MAC 地址为 AX:XX:XX:XX:XX:XA,其 IP 为 192.168.1.XA BBB 的 MAC 地址为 BX:XX:XX:XX:XX:XB,其 IP 为 192.168.1.XB我使用端口 1235 进行所有操作。

ifconfig在笔记本电脑上调用会给出:

enp0s31f6 Link encap:Ethernet  HWaddr AX:XX:XX:XX:XX:XA  
          inet addr:192.168.1.XA  Bcast:192.168.1.255  Mask:255.255.255.0
          inet6 addr: fe80::56ee:75ff:fece:4227/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:537 errors:0 dropped:0 overruns:0 frame:0
          TX packets:2912 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000 
          RX bytes:154829 (154.8 KB)  TX bytes:516547 (516.5 KB)
          Interrupt:16 Memory:f2200000-f2220000 

调用ifconfigBBB 会给出:

eth0      Link encap:Ethernet  HWaddr BX:XX:XX:XX:XX:XB                        
          inet addr:192.168.1.XB  Bcast:192.168.1.255  Mask:255.255.255.0      
          inet6 addr: fe80::6a3:16ff:feba:676a%132688/64 Scope:Link             
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1                    
          RX packets:2124 errors:0 dropped:0 overruns:0 frame:0                 
          TX packets:669 errors:0 dropped:0 overruns:0 carrier:0                
          collisions:0 txqueuelen:1000                                          
          RX bytes:402654 (393.2 KiB)  TX bytes:173920 (169.8 KiB)              
          Interrupt:174  

当脚本在笔记本电脑上运行时,BBBtcpdump -n udp -vv -X如下所示:

04:47:15.179497 IP (tos 0x0, ttl 64, id 52223, offset 0, flags [DF], proto UDP (17), length 33)                                                                 
    192.168.1.XA.1235 > 192.168.1.XB.1235: [no cksum] UDP, length 5           
        0x0000:  4500 0021 cbff 4000 4011 ea79 c0a8 017f  E..!..@[email protected]....      
        0x0010:  c0a8 0183 04d3 04d3 000d 0000 0003 020f  ................      
        0x0020:  0f00 0000 0000 0000 0000 0000 0000       .............. 

当脚本在BBB上运行时,笔记本电脑没有收到它,但tcpdump -n udp -vv -XBBB上的显示已发送:

04:51:31.613740 IP (tos 0x0, ttl 64, id 34794, offset 0, flags [DF], proto UDP (17), length 33)
    192.168.1.XB.1235 > 192.168.1.XA.1235: [no cksum] UDP, length 5
        0x0000:  4500 0021 87ea 4000 4011 2e8f c0a8 0183  E..!..@.@.......
        0x0010:  c0a8 017f 04d3 04d3 000d 0000 0003 020f  ................
        0x0020:  0f                                       .

在笔记本电脑和 BBB 上运行的 python3.6 脚本是:

import socket
import time
import struct
import random

#the following lists are specified as [src, dst]
#The order of the elements of these two element lists are reversed for the BBB
MAC = ["AX XX XX XX XX XA", "BX XX XX XX XX XB"]
IP = ["192.168.1.XA", "192.168.1.XB"]
port = [1235, 1235]
address = (IP[1], port[1])

#iface = 'eth0' for the BBB, 'enp0s31f6' for Laptop running Ubuntu 16.04
iface = 'enp0s31f6'


def shex(str):
    result = hex(int(str))
    return result[2:].zfill(2)


def ipToHex(ip):
    a = ip.split('.')
    return '{:02X} {:02X} {:02X} {:02X}'.format(*map(int, a))


def checksum(hdr):
    hdr = "".join(hdr.split())
    hdr = " ".join(hdr[i:i + 2] for i in range(0, len(hdr), 2)).split()
    hdr = list(map(lambda x: int(x, 16), hdr))
    hdr = struct.pack("%dB" % len(hdr), *hdr)

    cksum = 0
    for i in range(0, len(hdr), 2):
        word = hdr[i] + (hdr[i + 1] << 8)
        temp = cksum + word
        cksum = (temp & 0xFFFF) + (temp >> 16)
    res = ~cksum & 0xFFFF
    return '{:04X}'.format(((res << 8) & 0xFF00) | ((res >> 8) & 0x00FF))


class EthernetPacket:
    def __init__(self, mac, payload):
        self.srcMAC = mac[0]
        self.dstMAC = mac[1]
        self.type = '{:04X}'.format(0x0800)
        self.payload = payload

    def send(self, sock):
        sock.send(bytes.fromhex(self.srcMAC + self.dstMAC + self.type + self.payload.construct()))
        time.sleep(0.005)


class IPv4Packet:
    def __init__(self, ip, payload):
        self.srcIP = ipToHex(ip[0])
        self.dstIP = ipToHex(ip[1])
        self.ver = "45 00"
        self.id = '{:04X}'.format(0xFFFF & random.randrange(0, 65536)) + " 40 00 40 11"
        self.length = payload.length + 20
        self.payload = payload
        hdr = self.ver + '{:04X}'.format(self.length) + self.id + "0000" + self.srcIP + self.dstIP
        self.checksum = checksum(hdr)

    def construct(self):
        return self.ver + '{:04X}'.format(
        self.length) + self.id + self.checksum + self.srcIP + self.dstIP + self.payload.construct()


class UDPPacket:
    def __init__(self, port, payload):
        self.srcPort = '{:04X}'.format(port[0])
        self.dstPort = '{:04X}'.format(port[1])
        self.checksum = "0000"
        self.length = len(bytes.fromhex(payload)) + 8
        self.payload = payload

    def construct(self):
        return self.srcPort + self.dstPort + '{:04X}'.format(self.length) + self.checksum + self.payload


def main():
    sock = socket.socket(socket.AF_PACKET, socket.SOCK_RAW)
    sock.bind((iface, 1235))

    msg = 0

    cmd = input("Enter Command: ")
    task = cmd.split()

    if not task:
        task = ['null']

    while task[0] != 'exit' and task[0] != 'quit' and task[0] != 'close':
        if task[0] == 'light':
            param1, param2 = shex('00') + ' ', shex('00')
        if len(task) > 1:
            param1 = shex(task[1]) + ' '
        if len(task) > 2:
            param2 = shex(task[2])
        msg = '00 03 02 ' + param1 + param2

        u = UDPPacket(port, msg)
        i = IPv4Packet(IP, u)
        e = EthernetPacket(MAC, i)
        e.send(sock)

        cmd = input("Enter Command: ")
        task = cmd.split()

    sock.close()


if __name__ == "__main__":
    main()

任何帮助表示赞赏。

相关内容