【问题标题】:How to get sender IP of a desired broadcast address:port combination?如何获取所需广播地址的发件人 IP:端口组合?
【发布时间】:2014-03-24 20:15:35
【问题描述】:

我在 Wireshark 上看到了一些广播数据包,我希望能够使用一个简单的 Linux 命令行实用程序来检查这些数据包。它看起来像这样:

getsenders bcast_IP port timeout

它会简单地打印在超时期间遇到的每个新发件人 IP。

例如:

getsenders 192.168.0.255 12345 0.150

或(或者)

getsenders 192.168.0.0/8 12345 0.150

将侦听发送到 192.168.0.255:12345 的广播数据包,然后打印遇到的每个唯一发件人。为指定接口上的任何广播发送者列出了另一种方法。

不幸的是,我的 socket-fu 很弱。我所知道的是程序必须以 root 权限 (suid) 运行才能监听广播套接字。

我已经投入大量时间(几天)尝试从 Python 执行此操作,但看起来该路由需要使用原始套接字并解析数据包(数据包嗅探器,呃!)。我还研究了使用 socat/netcat(通过仅执行的 suid bash 脚本),但也无济于事。

是否有一些简单的 Linux 代码可以为我做到这一点?我不在乎工具或源语言是什么,只要可以设置 suid-root 并从命令行运行即可。

顺便说一句,我有一个简单的 Python 解决方案,可以在 MS Windows 下运行,但在 Linux 下死机:

myip = <IP address of local interface to listen on>
p = <broadcast port>
timeout = 0.150    # 150 ms
addresses = {}

if "windows" in sys.platform.tolower():
    # Create the broadcast reception socket
    bsock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    bsock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    bsock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
    bsock.settimeout(timeout)
    bsock.bind((myip, p))
    while True: # Look for all senders
        try:
            __, address = bsock.recvfrom(1024)   # Don't care about payload
        except BaseException, e:
            break   # Nothing found
        else:   # A desired broadcast packet was detected
            if address[0] not in addresses:
                addresses[address[0]] = 1
            else:
                addresses[address[0]] += 1
                if addresses[address[0]] >= 3:
                    break   # Go until timeout or any sender is seen 3 times
        finally:
            bsock.close()
            bsock = None
            print(', '.join([k for k in addresses]))

【问题讨论】:

  • 忘了说我还在广播地址的子网中为接口添加了一个别名。因此,如果我看到发送到 192.168.0.155 的数据包,我会添加一个别名,其空闲地址在 192.168.0.1 到 192.168.0.254 范围内。
  • 您的代码有什么问题? recvfrom() 提供发件人地址。剩下的只是编程。
  • 我的错:我应该强调我需要一个至少可以在 Windows 7+ 和 Linux 上运行的跨平台解决方案。问题是,要么绑定失败,要么什么也收不到,即使数据包已经到达接口。
  • 更改标题以反映我不关心使用的语言。

标签: linux udp broadcast


【解决方案1】:

在下载并测试了许多示例之后,我终于让它工作了,然后将代码一分为二并合并,直到我在两个平台上都有最小的差异。

归结为一行:Linux 必须绑定到特定的广播地址(以 root 身份),而 Windows 可以绑定到广播数据包预计到达的本地接口地址(以普通用户身份)。

这是修改后的代码sn-p:

bcast_addr = <IP addr of broadcast: Must end with at least one '.255'>
myip = <IP addr of local interface receiving from bcast_addr>
p = <broadcast port>
timeout = 0.150    # 150 ms
addresses = {}

# Create the broadcast reception socket
bsock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
bsock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
bsock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
bsock.settimeout(timeout)
if "windows" in sys.platform.tolower():
    bsock.bind((myip, p))
elif os.getuid() == 0:  # Must be root for Linux!
    bsock.bind((bcast_addr, p))
while True: # Look for all senders
    try:
        __, address = bsock.recvfrom(1024)   # Don't care about payload
    except BaseException, e:
        break   # Nothing found
    else:   # A desired broadcast packet was detected
        if address[0] not in addresses:
            addresses[address[0]] = 1
        else:
            addresses[address[0]] += 1
            if addresses[address[0]] >= 3:
                break   # Go until timeout or any sender is seen 3 times
    finally:
        bsock.close()
        bsock = None
        print(', '.join([k for k in addresses]))

【讨论】:

  • 这是我认为 Windows 可能比 Linux 做得“更好”的少数情况之一。虽然混杂的接口和完整的广播绑定 (255.255.255.255) 可能相当受限于 root,但应该允许普通用户绑定到受限的广播地址(至少第一个八位字节不是 255)。
猜你喜欢
  • 2014-12-01
  • 1970-01-01
  • 2021-12-09
  • 1970-01-01
  • 2021-11-27
  • 2013-04-16
  • 2019-07-27
  • 1970-01-01
  • 2015-06-22
相关资源
最近更新 更多