使用Ubuntu 9.04但不是8.04的UDP广播接收问题

时间:2010-01-25 06:19:31

标签: linux udp broadcast

更新

  • 01-27ter:已添加rp_filter信息
  • 01-27bis:请注意,9.04框可以在不同的界面上使用。
  • 01-27:添加了接口配置信息和数据包分析。

原帖

我有两个非常相似的硬件配置(SuperMicro 1U系统带有双Xeon CPU和两个以太网端口),一个运行Ubuntu 8.04(Linux 2.6.24-26服务器)和一个运行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-27bis

我进一步尝试,在8.04主机上生成我自己的广播数据包并将它们发送到9.04主机,当8.04主机发送它们时,9.04主机接收数据包就好了,它们到达eth0或eth1。< / p>

更新01-27ter

8.04主机上sp 3; sysctl -a 2>/dev/null | grep '\.rp_filter' | sort的输出为:

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

1 个答案:

答案 0 :(得分:1)

所以问题是net.ipv4.conf.eth1.rp_filter sysctl设置。在8.04框中将其设置为0,我正在进行宽松的反向路径检查,这意味着数据包可能来自任何可以在任何接口上路由的目的地。在9.04框中,我正在进行严格的检查,这意味着它会拒绝到达接口的数据包,如果对这些数据包的回复会出现在不同的接口上。​​

到达eth1到255.255.255.255的数据包是我不应该接收的数据包,因为255.255.255.255是本地网络广播地址,但是这些数据包的来源不在本地网络上。基本上,在我收到订阅源的网络上有些配置错误,我必须处理这种错误配置。