2017-11-25 88 views
5

Próbuję użyć portu z dwóch aplikacji i każdy z nich odbierze pakiet z innego zestawu adresów IP. Aby to osiągnąć, używam opcji gniazd SO_REUSEPORT i SO_ATTACH_REUSEPORT_CBPF. Mój kod wygląda następująco:SO_ATTACH_REUSEPORT_CBPF opcja gniazda nieoczekiwane zachowanie

parentfd = socket(AF_INET, SOCK_STREAM, 0); 
if (parentfd < 0) 
    error("ERROR opening socket"); 

struct sock_filter code[]={ 
    { 0x28, 0, 0, 0x0000000c }, 
    { 0x15, 0, 3, 0x00000800 }, 
    { 0x20, 0, 0, 0x0000001a }, 
    { 0x15, 2, 0, 0xc0a8ff01 }, 
    { 0x6, 0, 0, 0x00000000 }, 
    { 0x6, 0, 0, 0x00040000 }, 
    { 0x6, 0, 0, 0x00000001 }, 
}; 

struct sock_fprog bpf = { 
    .len = ARRAY_SIZE(code), 
    .filter = code, 
}; 

if (setsockopt(parentfd, SOL_SOCKET, SO_REUSEPORT, (const void *)&optval,sizeof(optval))) 
    error("ERROR setting SO_REUSEPORT"); 

if (setsockopt(parentfd, SOL_SOCKET, SO_ATTACH_REUSEPORT_CBPF, (const void *)&bpf, sizeof(bpf))) 
    error("ERROR setting SO_ATTACH_REUSEPORT_CBPF); 

Mam też inny proces, który nasłuchuje do tego samego portu, używając tylko flaga SO_REUSEPORT. Z maszyny z IP 192.168.255.1 używam echo 1234 | ncat 192.168.255.150 1234. Na podstawie mojego filtru oczekiwałbym, że cały ruch z tego adresu IP zostanie odebrany przez drugi proces. Jednak wszystko jest odbierane przez pierwszego. Kiedy wymienić filtr do prostego:

struct sock_filter code[]={ { 0x6, 0, 0, 0x00000001 }, };

To działa zgodnie z oczekiwaniami i wszystkie pakiety są odbierane przez drugi proces. Jakiś pomysł, dlaczego tak się dzieje?

+1

Jak pan wpadł na oryginalnym filtrem ? –

Odpowiedz

1

Dowiedziałem się, na czym polegał problem. Filtr jest stosowany do wszystkich pakietów, nawet do pakietów uzgadniania TCP. Ponadto wskaźnik bazowy wskazuje na pierwszy bajt pakietu danych, a nie na nagłówki. Stąd, gdy wykonuje

ldh[12] 

robi się z granicami pakietu (pakietów SYN ma 0 bajtów ładowności) i domyślnym zachowaniem jest powrót 0.

0

Kod zakaz pracy wynosi:

l0: ldh [12]     /* read EtherType (2 bytes), which is found at offset 12 (decimal) */ 
l1: jeq #0x800, l2, l5   /* if EtherType == `0x800` (IPv4), jump to `l2`, otherwise jump to `l5` */ 
l2: ld [26]     /* read source IP address (4 bytes) */ 
l3: jeq #0xc0a8ff01, l6, l4 /* if source IP address == 192.168.255.1, jump to l6 (return 1), else jump to l4 (return 0) */ 
l4: ret #0 
l5: ret #0x40000 
l6: ret #0x1 

Kodeks pracy jest:

ret #0x1 

socket (7) mówi:

Program BPF musi powrócić indeksu pomiędzy 0 i N -1 oznacza gniazdo, które powinno odebrać pakiet (gdzie N jest liczbą gniazd w grupie). Jeśli program BPF zwróci nieprawidłowy indeks, wybór gniazda powróci do zwykłego mechanizmu SO_REUSEPORT.

Na moim komputerze tcpdump -i lo -ddd 'src host 192.168.255.1' produkuje

10 
40 0 0 12 
21 0 2 2048 
32 0 0 26 
21 4 5 3232300801 
21 1 0 2054 
21 0 3 32821 
32 0 0 28 
21 0 1 3232300801 
6 0 0 262144 
6 0 0 0 

Która jest

l0: ldh [12] 
l1: jeq #0x800, l2, l4 
l2: ld [26] 
l3: jeq #0xc0a8ff01, l8, l9 
l4: jeq #0x806, l6, l5 
l5: jeq #0x8035, l6, l9 
l6: ld [28] 
l7: jeq #0xc0a8ff01, l8, l9 
l8: ret #0x40000 
l9: ret #0 

nie widzę niczego, co oczywiście nie tak z twoim kodzie.

Czy próbowałeś uruchomić tcpdump na serwerze? Być może zapomniałeś usunąć dodatkowy adres IP na kliencie lub gdzieś jest zapomniana zasada SNAT?

Która wersja jądra jest uruchomiona? Czy mógłbyś opublikować minimalną aplikację C, która powiela problem?

Powiązane problemy