linux - Ubuntu 9.04 而非 8.04 的 UDP 广播接收问题

标签 linux udp broadcast

更新

  • 01-27ter:添加了rp_filter信息
  • 01-27bis:请注意,9.04 box 在不同的界面上工作。
  • 01-27:增加接口(interface)配置信息和报文分析。

原帖

我有两个极其相似的硬件配置(SuperMicro 1U 系统,带有双 Xeon CPU 和板载两个以太网端口),一个运行 Ubuntu 8.04(Linux 2.6.24-26-server)和一个运行 Ubuntu 9.04(Linux 2.6 .28-17-服务器)。它们都将 eth1 连接到同一网络,在该网络上,各种其他服务器正在向各种端口发送广播 UDP 数据包。 在两台主机上,在 eth1 上使用 tcpdump,我可以看到这些广播 UDP 数据包到达。

然而,在 8.04 机器上,我可以让一个简单的程序很好地收听它们,而在 9.04 机器上,一个相同的程序永远不会接收到它们。作为高级概述,这里是一个示例 Haskell 程序,它适用于一个但不适用于另一个(两者都使用相同版本的 GHC):

import Network.Socket

port = 5515

main :: IO ()
main = do
     do sock <- socket AF_INET Datagram defaultProtocol
        bindSocket sock $ SockAddrInet (fromIntegral port) iNADDR_ANY
        loop sock
    where
        loop sock =
             do msg <- recv sock 2048
                print msg
                loop sock

如果问题恰好是 GHC 中非常奇怪的事情(尽管两者的构建相同),我编写了一个 C 程序来做同样的事情:

#include <arpa/inet.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>

#define BUFLEN 512
#define NPACK 10
#define PORT 5515

void diep(char *s)
{
    perror(s);
    exit(1);
}

void showb(int s) {
    int val, len, retval;
    len = sizeof(val);
    retval = getsockopt(s, SOL_SOCKET, SO_BROADCAST, &val, &len);
    printf("showb retval=%d val=%d\n", retval, val);
}

int main(int argc, char **argv)
{
    struct sockaddr_in si_me, si_other;
    int s, i, slen=sizeof(si_other);
    char buf[BUFLEN];

    if ((s=socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP))==-1)
        diep("socket");

    showb(s);
    i = 1;
    if (setsockopt(s, SOL_SOCKET, SO_BROADCAST, &i, sizeof(i))==-1)
        diep("setsockopt");
    showb(s);

    memset((char *) &si_me, 0, sizeof(si_me));
    si_me.sin_family = AF_INET;
    si_me.sin_port = htons(PORT);
    si_me.sin_addr.s_addr = htonl(INADDR_ANY);
    if (bind(s, &si_me, sizeof(si_me))==-1)
        diep("bind");

    puts("Listening.");

    for (i=0; i<NPACK; i++) {
        if (recvfrom(s, buf, BUFLEN, 0, &si_other, &slen)==-1)
            diep("recvfrom()");
        printf("Received packet from %s:%d\nData: %s\n\n",
               inet_ntoa(si_other.sin_addr), ntohs(si_other.sin_port), buf);
    }

    close(s);
    return 0;
}

你会注意到,在这种情况下只是为了好玩,我还在套接字上打开了 SO_BROADCAST 标志,并确认它已打开,尽管它对程序的行为没有影响,这是一样的。即使我将基于 8.04 构建的二进制文件复制到 9.04 机器上,反之亦然,在所有情况下,在 8.04 机器上运行的程序都会看到 UDP 广播数据包,而 9.04 机器则看不到。

我做错了什么?

更新 01-27:

这是工作 (8.04) 主机的 ip link 和 ip ether 的输出:

1: lo: <LOOPBACK,UP,LOWER_UP> mtu 16436 qdisc noqueue 
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1362 qdisc pfifo_fast qlen 1000
    link/ether 00:30:48:d3:4b:06 brd ff:ff:ff:ff:ff:ff
3: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast qlen 100
    link/ether 00:30:48:d3:4b:07 brd ff:ff:ff:ff:ff:ff
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 16436 qdisc noqueue 
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1362 qdisc pfifo_fast qlen 1000
    link/ether 00:30:48:d3:4b:06 brd ff:ff:ff:ff:ff:ff
    inet 192.168.228.130/28 brd 192.168.228.143 scope global eth0
    inet6 fe80::230:48ff:fed3:4b06/64 scope link 
       valid_lft forever preferred_lft forever
3: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast qlen 100
    link/ether 00:30:48:d3:4b:07 brd ff:ff:ff:ff:ff:ff
    inet 172.40.4.130/24 brd 172.40.4.255 scope global eth1
    inet6 fe80::230:48ff:fed3:4b07/64 scope link 
       valid_lft forever preferred_lft forever

对于非工作 (9.04) 服务器:

1: lo: <LOOPBACK,UP,LOWER_UP> mtu 16436 qdisc noqueue state UNKNOWN 
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1362 qdisc pfifo_fast state UP qlen 1000
    link/ether 00:30:48:d9:38:da brd ff:ff:ff:ff:ff:ff
3: eth2: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN qlen 1000
    link/ether 00:1b:21:36:19:fd brd ff:ff:ff:ff:ff:ff
4: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 100
    link/ether 00:30:48:d9:38:db brd ff:ff:ff:ff:ff:ff
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 16436 qdisc noqueue state UNKNOWN 
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1362 qdisc pfifo_fast state UP qlen 1000
    link/ether 00:30:48:d9:38:da brd ff:ff:ff:ff:ff:ff
    inet 192.168.228.132/28 brd 192.168.228.143 scope global eth0
    inet6 fe80::230:48ff:fed9:38da/64 scope link 
       valid_lft forever preferred_lft forever
3: eth2: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN qlen 1000
    link/ether 00:1b:21:36:19:fd brd ff:ff:ff:ff:ff:ff
4: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 100
    link/ether 00:30:48:d9:38:db brd ff:ff:ff:ff:ff:ff
    inet 172.40.4.132/24 brd 172.40.4.255 scope global eth1
    inet6 fe80::230:48ff:fed9:38db/64 scope link 
       valid_lft forever preferred_lft forever

请注意,对于这两种情况,eth1 都是广播到达的端口。

这是程序未接收到的示例广播数据包的完整解码(来自非工作 9.04 服务器上的 tshark):

Frame 193555 (271 bytes on wire, 271 bytes captured)
    Arrival Time: Jan 25, 2010 08:00:00.535345000
    [Time delta from previous captured frame: 0.001508000 seconds]
    [Time delta from previous displayed frame: 0.000000000 seconds]
    [Time since reference or first frame: 6590.956186000 seconds]
    Frame Number: 193555
    Frame Length: 271 bytes
    Capture Length: 271 bytes
    [Frame is marked: False]
    [Protocols in frame: eth:ip:udp:data]
Ethernet II, Src: Cisco_aa:c0:28 (00:d0:bb:aa:c0:28), Dst: Broadcast (ff:ff:ff:ff:ff:ff)
    Destination: Broadcast (ff:ff:ff:ff:ff:ff)
        Address: Broadcast (ff:ff:ff:ff:ff:ff)
        .... ...1 .... .... .... .... = IG bit: Group address (multicast/broadcast)
        .... ..1. .... .... .... .... = LG bit: Locally administered address (this is NOT the factory default)
    Source: Cisco_aa:c0:28 (00:d0:bb:aa:c0:28)
        Address: Cisco_aa:c0:28 (00:d0:bb:aa:c0:28)
        .... ...0 .... .... .... .... = IG bit: Individual address (unicast)
        .... ..0. .... .... .... .... = LG bit: Globally unique address (factory default)
    Type: IP (0x0800)
Internet Protocol, Src: 192.166.1.120 (192.166.1.120), Dst: 255.255.255.255 (255.255.255.255)
    Version: 4
    Header length: 20 bytes
    Differentiated Services Field: 0x00 (DSCP 0x00: Default; ECN: 0x00)
        0000 00.. = Differentiated Services Codepoint: Default (0x00)
        .... ..0. = ECN-Capable Transport (ECT): 0
        .... ...0 = ECN-CE: 0
    Total Length: 257
    Identification: 0xfad3 (64211)
    Flags: 0x04 (Don't Fragment)
        0... = Reserved bit: Not set
        .1.. = Don't fragment: Set
        ..0. = More fragments: Not set
    Fragment offset: 0
    Time to live: 252
    Protocol: UDP (0x11)
    Header checksum: 0xc0f9 [correct]
        [Good: True]
        [Bad : False]
    Source: 192.166.1.120 (192.166.1.120)
    Destination: 255.255.255.255 (255.255.255.255)
User Datagram Protocol, Src Port: 56172 (56172), Dst Port: 5515 (5515)
    Source port: 56172 (56172)
    Destination port: 5515 (5515)
    Length: 237
    Checksum: 0x01ba [correct]
        [Good Checksum: True]
        [Bad Checksum: False]
Data (229 bytes)

0000  41 37 30 33 34 30 38 30 30 30 30 30 30 31 31 30   A703408000000110
0010  4b 52 53 50 49 4f 50 4b 32 49 4b 52 34 32 30 31   KRSPIOPK2IKR4201
0020  45 32 32 32 35 33 30 30 32 31 30 30 30 30 30 30   E222530021000000
0030  30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30   0000000000000000
0040  30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30   0000000000000000
0050  30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30   0000000000000000
0060  30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30   0000000000000000
0070  30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30   0000000000000000
0080  30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30   0000000000000000
0090  30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30   0000000000000000
00a0  30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30   0000000000000000
00b0  30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30   0000000000000000
00c0  30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30   0000000000000000
00d0  30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30   0000000000000000
00e0  30 30 30 30 ff                                    0000.
    Data: 413730333430383030303030303131304B525350494F504B...

我已经将它与来自正在工作的 8.04 服务器上的转储中的相同数据包进行了比较,并且数据包本身是相同的;唯一的区别在于帧号(在 pcap 文件中)和接收数据包的时间(1.224 毫秒差异,考虑到两台主机使用相同的 NTP 服务器,这似乎很高,但并非完全不合理)。

更新01-27之二

我做了进一步的实验,在 8.04 主机上生成我自己的广播数据包并将它们发送到 9.04 主机,当 8.04 主机发送数据包并且它们到达 eth0 或 eth1 时,9.04 主机很好地接收数据包。

更新01-27之三

sp 3 的输出; sysctl -a 2>/dev/空 | grep '\.rp_filter' | 8.04 主机上的排序是:

net.ipv4.conf.all.rp_filter = 1
net.ipv4.conf.default.rp_filter = 1
net.ipv4.conf.eth0.rp_filter = 0
net.ipv4.conf.eth1.rp_filter = 0
net.ipv4.conf.lo.rp_filter = 1

在 9.04 主机上是:

net.ipv4.conf.all.rp_filter = 1
net.ipv4.conf.default.rp_filter = 1
net.ipv4.conf.eth0.rp_filter = 1
net.ipv4.conf.eth1.rp_filter = 1
net.ipv4.conf.eth2.rp_filter = 1
net.ipv4.conf.lo.rp_filter = 0

最佳答案

所以问题出在 net.ipv4.conf.eth1.rp_filter sysctl 设置上。在 8.04 机器上将它设置为 0,我正在做松散的反向路径检查,这意味着数据包可能来 self 可以在任何接口(interface)上路由到的任何目的地。在 9.04 机器上,我进行了严格的检查,这意味着如果对到达某个接口(interface)的数据包的回复来自另一个接口(interface),它将拒绝这些数据包。

到达 eth1 到 255.255.255.255 的数据包是我不应该在一切正常的情况下接收的数据包,因为 255.255.255.255 是本地网络广播地址,但这些数据包的来源不在本地网络上。所以本质上,在我接收提要的网络上有些地方配置错误,我必须处理这个错误配置。

关于linux - Ubuntu 9.04 而非 8.04 的 UDP 广播接收问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2130563/

相关文章:

c - C中的套接字编程

python - 创建一个服务器来监听特定端口。

c# - 将 UDP 数据包转发到多个保持原始源地址的 IP

Android Boot-Up BroadCast 不调用

networking - 在 LAN 上实现设备发现的最佳方法是什么

udp - 将 Docker 容器连接到网络接口(interface)/设备而不是 IP 地址

linux - 如何在 Linux 中重命名目录中的多个文件并保留扩展名

linux - 如何获取在 bash 脚本中执行的命令的进程 ID?

linux - SSH 交换 ctrl 和 caps

c++ - UDP 套接字 : recvfrom and receive address