Обновление
- 01-27ter: добавлена информация rp_filter
- 01-27bis: обратите внимание, что окно 9.04 работает на другом интерфейсе.
- 01-27: добавлена информация о конфигурации интерфейса и анализ пакета.
Оригинальный пост
У меня есть две чрезвычайно похожие конфигурации оборудования (системы SuperMicro 1U с двумя процессорами Xeon и двумя портами Ethernet на плате), одна работает под управлением Ubuntu 8.04 (сервер Linux 2.6.24-26) и одна работает под управлением Ubuntu 9.04 (Linux 2.6). .28-17-сервер). Оба эти устройства имеют соединение eth1, подключенное к одной и той же сети, в которой различные другие серверы отправляют широковещательные пакеты UDP на различные порты.
На обоих хостах, используя tcpdump на eth1, я вижу поступающие эти широковещательные 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:
Вот вывод ip link и ip ether для рабочего (8.04) хоста:
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 - это порт, на который приходят трансляции.
Вот полное декодирование (из tshark на нерабочем сервере 9.04) образца широковещательного пакета, который программа не получает:
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, и хост 9.04 прекрасно принимает пакеты, когда хост 8.04 отправляет их, и они приходят либо на eth0, либо на eth1.
Обновление 01-27ter
Выход sp 3; sysctl -a 2>/dev/null | grep '\.rp_filter' | sort
на хосте 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