Почему netcat не может получить второе широковещательное сообщение?

Во время экспериментирования с широковещательными сообщениями (на виртуальной машине Debian 8.3, работающей на VirtualBox 5.0.14 на ноутбуке Windows 7), я обнаружил, что netcat (nc) получает только первое широковещательное сообщение. Он не получает второе широковещательное сообщение.

Программы

Вот клиентская программа.

// client.c
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>

#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netdb.h>

int main()
{
    int sockfd;
    int ret;
    char buffer[1024];
    ssize_t bytes;
    int yes = 1;
    struct addrinfo hints, *ai, *aii;

    memset(&hints, 0, sizeof hints);
    hints.ai_family = AF_INET;
    hints.ai_socktype = SOCK_DGRAM;

    if ((ret = getaddrinfo("255.255.255.255", "9090", &hints, &ai)) == -1) {
        fprintf(stderr, "client: getaddrinfo() error: %s\n", gai_strerror(ret));
        return EXIT_FAILURE;
    }

    for (aii = ai; aii != NULL; aii = aii->ai_next) {
        sockfd = socket(aii->ai_family, aii->ai_socktype, aii->ai_protocol);
        if (sockfd == -1) {
            perror("client: socket()");
            continue;
        }
        break;
    }

    freeaddrinfo(ai);

    if (aii == NULL) {
        fprintf(stderr, "client: cannot create socket\n");
        return EXIT_FAILURE;
    }

    if (setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, &yes, sizeof yes) == -1) {
        perror("client: setsockopt()");
        return EXIT_FAILURE;
    }

    // 1st sendto().
    strncpy(buffer, "hello from client\n", sizeof buffer);
    bytes = sendto(sockfd, buffer, strlen(buffer), 0,
                   aii->ai_addr, aii->ai_addrlen);
    printf("client: sent %jd bytes\n", (intmax_t) bytes);

    // 2nd sendto().
    strncpy(buffer, "bye from client\n", sizeof buffer);
    bytes = sendto(sockfd, buffer, strlen(buffer), 0,
                   aii->ai_addr, aii->ai_addrlen);
    printf("client: sent %jd bytes\n", (intmax_t) bytes);

    close(sockfd);
    return EXIT_SUCCESS;
}

Вот серверная программа.

// server.c
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>

#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netdb.h>

int main()
{
    int sockfd;
    int ret;
    struct addrinfo hints, *ai, *aii;
    char ip[INET_ADDRSTRLEN];
    struct sockaddr_in *sa;

    memset(&hints, 0, sizeof hints);
    hints.ai_family = AF_INET;
    hints.ai_socktype = SOCK_DGRAM;
    hints.ai_flags = AI_PASSIVE;

    if ((ret = getaddrinfo(NULL, "9090", &hints, &ai)) == -1) {
        fprintf(stderr, "server: getaddrinfo() error: %s\n", gai_strerror(ret));
        return EXIT_FAILURE;
    }

    for (aii = ai; aii != NULL; aii = aii->ai_next) {

        sockfd = socket(aii->ai_family, aii->ai_socktype, aii->ai_protocol);
        if (sockfd == -1) {
            perror("socket()");
            continue;
        }

        if (bind(sockfd, aii->ai_addr, aii->ai_addrlen) == -1) {
            perror("bind()");
            close(sockfd);
            continue;
        }

        break;
    }

    if (aii == NULL) {
        fprintf(stderr, "server: error: could not bind to any address\n");
        return EXIT_FAILURE;
    }

    sa = (struct sockaddr_in *) aii->ai_addr;
    inet_ntop(AF_INET, &sa->sin_addr, ip, sizeof ip);
    printf("Bound to %s:%d.\n", ip, ntohs(sa->sin_port));

    freeaddrinfo(ai);

    /* recvfrom() loop */
    while (1) {
        struct sockaddr_storage conn_addr;
        socklen_t conn_addrlen = sizeof conn_addr;
        char buffer[1024];
        ssize_t bytes;

        bytes = recvfrom(sockfd, buffer, sizeof buffer, 0,
                         (struct sockaddr *) &conn_addr, &conn_addrlen);

        if (bytes <= 0)
            break;

        sa = (struct sockaddr_in *) &conn_addr;
        inet_ntop(AF_INET, &sa->sin_addr, ip, sizeof ip);

        printf("server: recvfrom() %jd bytes from %s:%d: %.*s",
               (intmax_t) bytes, ip, ntohs(sa->sin_port), (int) bytes,
               buffer);
    }

    close(sockfd);
    return EXIT_FAILURE;
}

Программы были скомпилированы.

gcc -std=c99 -pedantic -Wall -Wextra -D_POSIX_C_SOURCE=200112L client.c -o client
gcc -std=c99 -pedantic -Wall -Wextra -D_POSIX_C_SOURCE=200112L server.c -o server

Эксперимент 1: клиент = > сервер (широковещательный)

Клиентская программа показывает следующий вывод.

$ ./client
client: sent 18 bytes
client: sent 16 bytes

Оба широковещательных сообщения принимаются программой сервера.

$ ./server 
Bound to 0.0.0.0:9090.
server: recvfrom() 18 bytes from 10.0.2.15:45807: hello from client
server: recvfrom() 16 bytes from 10.0.2.15:45807: bye from client

Эксперимент 2: клиент = > nc (широковещательный)

Однако, если netcat запускается вместо этого в качестве слушателя на порт 9090, он получает только первое широковещательное сообщение.

Вот результат из клиентской программы.

$ ./client
client: sent 18 bytes
client: sent 16 bytes

Программа сервера не получает второе широковещательное сообщение.

$ nc -vvnulp 9090
listening on [any] 9090 ...
connect to [10.0.2.15] from (UNKNOWN) [10.0.2.15] 39126
hello from client

Эксперимент 3: client = > nc (одноадресный)

Далее клиентская программа client.c изменена для создания новой программы client2.c, так что он выполняет одноадресную рассылку.

$ diff -u client.c client2.c
--- client.c    2016-10-22 16:13:46.637123187 +0530
+++ client2.c   2016-10-22 16:13:41.313123187 +0530
@@ -16,14 +16,13 @@
     int ret;
     char buffer[1024];
     ssize_t bytes;
-    int yes = 1;
     struct addrinfo hints, *ai, *aii;

     memset(&hints, 0, sizeof hints);
     hints.ai_family = AF_INET;
     hints.ai_socktype = SOCK_DGRAM;

-    if ((ret = getaddrinfo("255.255.255.255", "9090", &hints, &ai)) == -1) {
+    if ((ret = getaddrinfo("10.0.2.15", "9090", &hints, &ai)) == -1) {
         fprintf(stderr, "client: getaddrinfo() error: %s\n", gai_strerror(ret));
         return EXIT_FAILURE;
     }
@@ -44,11 +43,6 @@
         return EXIT_FAILURE;
     }

-    if (setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, &yes, sizeof yes) == -1) {
-        perror("client: setsockopt()");
-        return EXIT_FAILURE;
-    }
-
     // 1st sendto().
     strncpy(buffer, "hello from client\n", sizeof buffer);
     bytes = sendto(sockfd, buffer, strlen(buffer), 0,

Вот результат из клиентской программы.

$ gcc -std=c99 -pedantic -Wall -Wextra -D_POSIX_C_SOURCE=200112L client2.c -o client2
$ ./client2 
client: sent 18 bytes
client: sent 16 bytes

В этот раз netcat получает как одноадресные сообщения.

$ nc -vvnulp 9090                                                                                                                                   
listening on [any] 9090 ...
connect to [10.0.2.15] from (UNKNOWN) [10.0.2.15] 55522
hello from client
bye from client

Трассировка системного вызова

Вот трассировка системного вызова для netcat в эксперименте 2.

$ strace nc -vvnulp 9090
execve("/bin/nc", ["nc", "-vvnulp", "9090"], [/* 39 vars */]) = 0
brk(0)                                  = 0xc19000
access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f2fcd7ed000
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=76016, ...}) = 0
mmap(NULL, 76016, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f2fcd7da000
close(3)                                = 0
access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)
open("/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0P\34\2\0\0\0\0\0"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0755, st_size=1738176, ...}) = 0
mmap(NULL, 3844640, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f2fcd224000
mprotect(0x7f2fcd3c6000, 2093056, PROT_NONE) = 0
mmap(0x7f2fcd5c5000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1a1000) = 0x7f2fcd5c5000
mmap(0x7f2fcd5cb000, 14880, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7f2fcd5cb000
close(3)                                = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f2fcd7d9000
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f2fcd7d8000
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f2fcd7d7000
arch_prctl(ARCH_SET_FS, 0x7f2fcd7d8700) = 0
mprotect(0x7f2fcd5c5000, 16384, PROT_READ) = 0
mprotect(0x605000, 4096, PROT_READ)     = 0
mprotect(0x7f2fcd7ef000, 4096, PROT_READ) = 0
munmap(0x7f2fcd7da000, 76016)           = 0
getpid()                                = 4161
brk(0)                                  = 0xc19000
brk(0xc3a000)                           = 0xc3a000
open("/etc/resolv.conf", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=248, ...}) = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f2fcd7ec000
read(3, "# Generated by NetworkManager\nna"..., 4096) = 248
read(3, "", 4096)                       = 0
close(3)                                = 0
munmap(0x7f2fcd7ec000, 4096)            = 0
uname({sys="Linux", node="debian1", ...}) = 0
rt_sigaction(SIGINT, {0x4025d0, [INT], SA_RESTORER|SA_RESTART, 0x7f2fcd2590e0}, {SIG_DFL, [], 0}, 8) = 0
rt_sigaction(SIGQUIT, {0x4025d0, [QUIT], SA_RESTORER|SA_RESTART, 0x7f2fcd2590e0}, {SIG_DFL, [], 0}, 8) = 0
rt_sigaction(SIGTERM, {0x4025d0, [TERM], SA_RESTORER|SA_RESTART, 0x7f2fcd2590e0}, {SIG_DFL, [], 0}, 8) = 0
rt_sigaction(SIGURG, {SIG_IGN, [URG], SA_RESTORER|SA_RESTART, 0x7f2fcd2590e0}, {SIG_DFL, [], 0}, 8) = 0
rt_sigaction(SIGPIPE, {SIG_IGN, [PIPE], SA_RESTORER|SA_RESTART, 0x7f2fcd2590e0}, {SIG_DFL, [], 0}, 8) = 0
socket(PF_LOCAL, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0) = 3
connect(3, {sa_family=AF_LOCAL, sun_path="/var/run/nscd/socket"}, 110) = -1 ENOENT (No such file or directory)
close(3)                                = 0
socket(PF_LOCAL, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0) = 3
connect(3, {sa_family=AF_LOCAL, sun_path="/var/run/nscd/socket"}, 110) = -1 ENOENT (No such file or directory)
close(3)                                = 0
open("/etc/nsswitch.conf", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=529, ...}) = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f2fcd7ec000
read(3, "# /etc/nsswitch.conf\n#\n# Example"..., 4096) = 529
read(3, "", 4096)                       = 0
close(3)                                = 0
munmap(0x7f2fcd7ec000, 4096)            = 0
open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=76016, ...}) = 0
mmap(NULL, 76016, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f2fcd7da000
close(3)                                = 0
access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)
open("/lib/x86_64-linux-gnu/tls/x86_64/libnss_db.so.2", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/lib/x86_64-linux-gnu/tls/x86_64", 0x7ffe5c622430) = -1 ENOENT (No such file or directory)
open("/lib/x86_64-linux-gnu/tls/libnss_db.so.2", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/lib/x86_64-linux-gnu/tls", 0x7ffe5c622430) = -1 ENOENT (No such file or directory)
open("/lib/x86_64-linux-gnu/x86_64/libnss_db.so.2", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/lib/x86_64-linux-gnu/x86_64", 0x7ffe5c622430) = -1 ENOENT (No such file or directory)
open("/lib/x86_64-linux-gnu/libnss_db.so.2", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/lib/x86_64-linux-gnu", {st_mode=S_IFDIR|0755, st_size=12288, ...}) = 0
open("/usr/lib/x86_64-linux-gnu/tls/x86_64/libnss_db.so.2", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/usr/lib/x86_64-linux-gnu/tls/x86_64", 0x7ffe5c622430) = -1 ENOENT (No such file or directory)
open("/usr/lib/x86_64-linux-gnu/tls/libnss_db.so.2", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/usr/lib/x86_64-linux-gnu/tls", 0x7ffe5c622430) = -1 ENOENT (No such file or directory)
open("/usr/lib/x86_64-linux-gnu/x86_64/libnss_db.so.2", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/usr/lib/x86_64-linux-gnu/x86_64", 0x7ffe5c622430) = -1 ENOENT (No such file or directory)
open("/usr/lib/x86_64-linux-gnu/libnss_db.so.2", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/usr/lib/x86_64-linux-gnu", {st_mode=S_IFDIR|0755, st_size=49152, ...}) = 0
open("/lib/tls/x86_64/libnss_db.so.2", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/lib/tls/x86_64", 0x7ffe5c622430) = -1 ENOENT (No such file or directory)
open("/lib/tls/libnss_db.so.2", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/lib/tls", 0x7ffe5c622430)        = -1 ENOENT (No such file or directory)
open("/lib/x86_64/libnss_db.so.2", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/lib/x86_64", 0x7ffe5c622430)     = -1 ENOENT (No such file or directory)
open("/lib/libnss_db.so.2", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/lib", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
open("/usr/lib/tls/x86_64/libnss_db.so.2", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/usr/lib/tls/x86_64", 0x7ffe5c622430) = -1 ENOENT (No such file or directory)
open("/usr/lib/tls/libnss_db.so.2", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/usr/lib/tls", 0x7ffe5c622430)    = -1 ENOENT (No such file or directory)
open("/usr/lib/x86_64/libnss_db.so.2", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/usr/lib/x86_64", 0x7ffe5c622430) = -1 ENOENT (No such file or directory)
open("/usr/lib/libnss_db.so.2", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/usr/lib", {st_mode=S_IFDIR|0755, st_size=12288, ...}) = 0
munmap(0x7f2fcd7da000, 76016)           = 0
open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=76016, ...}) = 0
mmap(NULL, 76016, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f2fcd7da000
close(3)                                = 0
access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)
open("/lib/x86_64-linux-gnu/libnss_files.so.2", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\240\"\0\0\0\0\0\0"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0644, st_size=47712, ...}) = 0
mmap(NULL, 2144392, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f2fcd018000
mprotect(0x7f2fcd023000, 2093056, PROT_NONE) = 0
mmap(0x7f2fcd222000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0xa000) = 0x7f2fcd222000
close(3)                                = 0
mprotect(0x7f2fcd222000, 4096, PROT_READ) = 0
munmap(0x7f2fcd7da000, 76016)           = 0
open("/etc/services", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=19605, ...}) = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f2fcd7ec000
read(3, "# Network services, Internet sty"..., 4096) = 4096
read(3, "\t\t# IPX\nipx\t\t213/udp\nimap3\t\t220/"..., 4096) = 4096
read(3, "nessus\t\t1241/tcp\t\t\t# Nessus vuln"..., 4096) = 4096
read(3, "347/tcp\t\t\t# gnutella\ngnutella-rt"..., 4096) = 4096
read(3, "ureg\t779/udp\t\tmoira_ureg\t# Moira"..., 4096) = 3221
read(3, "", 4096)                       = 0
close(3)                                = 0
munmap(0x7f2fcd7ec000, 4096)            = 0
socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP) = 3
setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0
setsockopt(3, SOL_SOCKET, SO_REUSEPORT, [1], 4) = 0
bind(3, {sa_family=AF_INET, sin_port=htons(9090), sin_addr=inet_addr("0.0.0.0")}, 16) = 0
getsockname(3, {sa_family=AF_INET, sin_port=htons(9090), sin_addr=inet_addr("0.0.0.0")}, [16]) = 0
write(2, "listening on [any] 9090 ...", 27listening on [any] 9090 ...) = 27
write(2, "\n", 1
)                       = 1
rt_sigaction(SIGALRM, {SIG_IGN, [ALRM], SA_RESTORER|SA_RESTART, 0x7f2fcd2590e0}, {SIG_DFL, [], 0}, 8) = 0
alarm(0)                                = 0
rt_sigprocmask(SIG_BLOCK, NULL, [], 8)  = 0
recvfrom(3, "hello from client\n", 8192, MSG_PEEK, {sa_family=AF_INET, sin_port=htons(44926), sin_addr=inet_addr("10.0.2.15")}, [16]) = 18
rt_sigaction(SIGALRM, {SIG_IGN, [ALRM], SA_RESTORER|SA_RESTART, 0x7f2fcd2590e0}, {SIG_IGN, [ALRM], SA_RESTORER|SA_RESTART, 0x7f2fcd2590e0}, 8) = 0
alarm(0)                                = 0
connect(3, {sa_family=AF_INET, sin_port=htons(44926), sin_addr=inet_addr("10.0.2.15")}, 16) = 0
getsockopt(3, SOL_IP, IP_OPTIONS, "", [0]) = 0
getsockname(3, {sa_family=AF_INET, sin_port=htons(9090), sin_addr=inet_addr("10.0.2.15")}, [16]) = 0
write(2, "connect to [10.0.2.15] from (UNK"..., 55connect to [10.0.2.15] from (UNKNOWN) [10.0.2.15] 44926) = 55
write(2, "\n", 1
)                       = 1
select(4, [0 3], NULL, NULL, NULL)      = 1 (in [3])
read(3, "hello from client\n", 8192)    = 18
write(1, "hello from client\n", 18hello from client
)     = 18
select(4, [0 3], NULL, NULL, NULL

Вот трассировка системного вызова для netcat в эксперименте 3.

$ strace nc -vvnulp 9090
execve("/bin/nc", ["nc", "-vvnulp", "9090"], [/* 39 vars */]) = 0
brk(0)                                  = 0x198e000
access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fcec1035000
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=76016, ...}) = 0
mmap(NULL, 76016, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7fcec1022000
close(3)                                = 0
access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)
open("/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0P\34\2\0\0\0\0\0"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0755, st_size=1738176, ...}) = 0
mmap(NULL, 3844640, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7fcec0a6c000
mprotect(0x7fcec0c0e000, 2093056, PROT_NONE) = 0
mmap(0x7fcec0e0d000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1a1000) = 0x7fcec0e0d000
mmap(0x7fcec0e13000, 14880, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7fcec0e13000
close(3)                                = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fcec1021000
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fcec1020000
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fcec101f000
arch_prctl(ARCH_SET_FS, 0x7fcec1020700) = 0
mprotect(0x7fcec0e0d000, 16384, PROT_READ) = 0
mprotect(0x605000, 4096, PROT_READ)     = 0
mprotect(0x7fcec1037000, 4096, PROT_READ) = 0
munmap(0x7fcec1022000, 76016)           = 0
getpid()                                = 4181
brk(0)                                  = 0x198e000
brk(0x19af000)                          = 0x19af000
open("/etc/resolv.conf", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=248, ...}) = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fcec1034000
read(3, "# Generated by NetworkManager\nna"..., 4096) = 248
read(3, "", 4096)                       = 0
close(3)                                = 0
munmap(0x7fcec1034000, 4096)            = 0
uname({sys="Linux", node="debian1", ...}) = 0
rt_sigaction(SIGINT, {0x4025d0, [INT], SA_RESTORER|SA_RESTART, 0x7fcec0aa10e0}, {SIG_DFL, [], 0}, 8) = 0
rt_sigaction(SIGQUIT, {0x4025d0, [QUIT], SA_RESTORER|SA_RESTART, 0x7fcec0aa10e0}, {SIG_DFL, [], 0}, 8) = 0
rt_sigaction(SIGTERM, {0x4025d0, [TERM], SA_RESTORER|SA_RESTART, 0x7fcec0aa10e0}, {SIG_DFL, [], 0}, 8) = 0
rt_sigaction(SIGURG, {SIG_IGN, [URG], SA_RESTORER|SA_RESTART, 0x7fcec0aa10e0}, {SIG_DFL, [], 0}, 8) = 0
rt_sigaction(SIGPIPE, {SIG_IGN, [PIPE], SA_RESTORER|SA_RESTART, 0x7fcec0aa10e0}, {SIG_DFL, [], 0}, 8) = 0
socket(PF_LOCAL, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0) = 3
connect(3, {sa_family=AF_LOCAL, sun_path="/var/run/nscd/socket"}, 110) = -1 ENOENT (No such file or directory)
close(3)                                = 0
socket(PF_LOCAL, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0) = 3
connect(3, {sa_family=AF_LOCAL, sun_path="/var/run/nscd/socket"}, 110) = -1 ENOENT (No such file or directory)
close(3)                                = 0
open("/etc/nsswitch.conf", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=529, ...}) = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fcec1034000
read(3, "# /etc/nsswitch.conf\n#\n# Example"..., 4096) = 529
read(3, "", 4096)                       = 0
close(3)                                = 0
munmap(0x7fcec1034000, 4096)            = 0
open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=76016, ...}) = 0
mmap(NULL, 76016, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7fcec1022000
close(3)                                = 0
access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)
open("/lib/x86_64-linux-gnu/tls/x86_64/libnss_db.so.2", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/lib/x86_64-linux-gnu/tls/x86_64", 0x7ffcde8fa140) = -1 ENOENT (No such file or directory)
open("/lib/x86_64-linux-gnu/tls/libnss_db.so.2", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/lib/x86_64-linux-gnu/tls", 0x7ffcde8fa140) = -1 ENOENT (No such file or directory)
open("/lib/x86_64-linux-gnu/x86_64/libnss_db.so.2", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/lib/x86_64-linux-gnu/x86_64", 0x7ffcde8fa140) = -1 ENOENT (No such file or directory)
open("/lib/x86_64-linux-gnu/libnss_db.so.2", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/lib/x86_64-linux-gnu", {st_mode=S_IFDIR|0755, st_size=12288, ...}) = 0
open("/usr/lib/x86_64-linux-gnu/tls/x86_64/libnss_db.so.2", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/usr/lib/x86_64-linux-gnu/tls/x86_64", 0x7ffcde8fa140) = -1 ENOENT (No such file or directory)
open("/usr/lib/x86_64-linux-gnu/tls/libnss_db.so.2", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/usr/lib/x86_64-linux-gnu/tls", 0x7ffcde8fa140) = -1 ENOENT (No such file or directory)
open("/usr/lib/x86_64-linux-gnu/x86_64/libnss_db.so.2", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/usr/lib/x86_64-linux-gnu/x86_64", 0x7ffcde8fa140) = -1 ENOENT (No such file or directory)
open("/usr/lib/x86_64-linux-gnu/libnss_db.so.2", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/usr/lib/x86_64-linux-gnu", {st_mode=S_IFDIR|0755, st_size=49152, ...}) = 0
open("/lib/tls/x86_64/libnss_db.so.2", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/lib/tls/x86_64", 0x7ffcde8fa140) = -1 ENOENT (No such file or directory)
open("/lib/tls/libnss_db.so.2", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/lib/tls", 0x7ffcde8fa140)        = -1 ENOENT (No such file or directory)
open("/lib/x86_64/libnss_db.so.2", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/lib/x86_64", 0x7ffcde8fa140)     = -1 ENOENT (No such file or directory)
open("/lib/libnss_db.so.2", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/lib", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
open("/usr/lib/tls/x86_64/libnss_db.so.2", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/usr/lib/tls/x86_64", 0x7ffcde8fa140) = -1 ENOENT (No such file or directory)
open("/usr/lib/tls/libnss_db.so.2", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/usr/lib/tls", 0x7ffcde8fa140)    = -1 ENOENT (No such file or directory)
open("/usr/lib/x86_64/libnss_db.so.2", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/usr/lib/x86_64", 0x7ffcde8fa140) = -1 ENOENT (No such file or directory)
open("/usr/lib/libnss_db.so.2", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/usr/lib", {st_mode=S_IFDIR|0755, st_size=12288, ...}) = 0
munmap(0x7fcec1022000, 76016)           = 0
open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=76016, ...}) = 0
mmap(NULL, 76016, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7fcec1022000
close(3)                                = 0
access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)
open("/lib/x86_64-linux-gnu/libnss_files.so.2", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\240\"\0\0\0\0\0\0"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0644, st_size=47712, ...}) = 0
mmap(NULL, 2144392, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7fcec0860000
mprotect(0x7fcec086b000, 2093056, PROT_NONE) = 0
mmap(0x7fcec0a6a000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0xa000) = 0x7fcec0a6a000
close(3)                                = 0
mprotect(0x7fcec0a6a000, 4096, PROT_READ) = 0
munmap(0x7fcec1022000, 76016)           = 0
open("/etc/services", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=19605, ...}) = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fcec1034000
read(3, "# Network services, Internet sty"..., 4096) = 4096
read(3, "\t\t# IPX\nipx\t\t213/udp\nimap3\t\t220/"..., 4096) = 4096
read(3, "nessus\t\t1241/tcp\t\t\t# Nessus vuln"..., 4096) = 4096
read(3, "347/tcp\t\t\t# gnutella\ngnutella-rt"..., 4096) = 4096
read(3, "ureg\t779/udp\t\tmoira_ureg\t# Moira"..., 4096) = 3221
read(3, "", 4096)                       = 0
close(3)                                = 0
munmap(0x7fcec1034000, 4096)            = 0
socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP) = 3
setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0
setsockopt(3, SOL_SOCKET, SO_REUSEPORT, [1], 4) = 0
bind(3, {sa_family=AF_INET, sin_port=htons(9090), sin_addr=inet_addr("0.0.0.0")}, 16) = 0
getsockname(3, {sa_family=AF_INET, sin_port=htons(9090), sin_addr=inet_addr("0.0.0.0")}, [16]) = 0
write(2, "listening on [any] 9090 ...", 27listening on [any] 9090 ...) = 27
write(2, "\n", 1
)                       = 1
rt_sigaction(SIGALRM, {SIG_IGN, [ALRM], SA_RESTORER|SA_RESTART, 0x7fcec0aa10e0}, {SIG_DFL, [], 0}, 8) = 0
alarm(0)                                = 0
rt_sigprocmask(SIG_BLOCK, NULL, [], 8)  = 0
recvfrom(3, "hello from client\n", 8192, MSG_PEEK, {sa_family=AF_INET, sin_port=htons(50392), sin_addr=inet_addr("10.0.2.15")}, [16]) = 18
rt_sigaction(SIGALRM, {SIG_IGN, [ALRM], SA_RESTORER|SA_RESTART, 0x7fcec0aa10e0}, {SIG_IGN, [ALRM], SA_RESTORER|SA_RESTART, 0x7fcec0aa10e0}, 8) = 0
alarm(0)                                = 0
connect(3, {sa_family=AF_INET, sin_port=htons(50392), sin_addr=inet_addr("10.0.2.15")}, 16) = 0
getsockopt(3, SOL_IP, IP_OPTIONS, "", [0]) = 0
getsockname(3, {sa_family=AF_INET, sin_port=htons(9090), sin_addr=inet_addr("10.0.2.15")}, [16]) = 0
write(2, "connect to [10.0.2.15] from (UNK"..., 55connect to [10.0.2.15] from (UNKNOWN) [10.0.2.15] 50392) = 55
write(2, "\n", 1
)                       = 1
select(4, [0 3], NULL, NULL, NULL)      = 1 (in [3])
read(3, "hello from client\n", 8192)    = 18
write(1, "hello from client\n", 18hello from client
)     = 18
select(4, [0 3], NULL, NULL, NULL)      = 1 (in [3])
read(3, "bye from client\n", 8192)      = 16
write(1, "bye from client\n", 16bye from client
)       = 16
select(4, [0 3], NULL, NULL, NULL

Вопрос

Почему netcat не получает как широковещательные сообщения в эксперименте 2?

Ответ 1

Ниже приведена измененная копия вашей клиентской программы. Я добавил несколько отсутствующих include-утверждений, удалил некоторые приведения, добавил проверку ошибок и, главное изменение, переместил вызов freeaddrinfo() вниз. Много. Указатель aii, указывающий на ai, использовался в вызовах sendto(), что не очень хорошая идея.

Теперь netcat видит оба отправленных сообщения, по крайней мере, на моем компьютере, на котором запущена Fedora 24. Первоначальная клиентская программа фактически сообщила об ошибке во втором вызове sendto().

НТН

PS: Cudos для очень хорошо сформулированного вопроса.

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

int main(void)
{
    int sockfd;
    int ret;
    ssize_t bytes;
    int yes = 1;
    struct addrinfo hints, *ai, *aii;
    char *msg;

    memset(&hints, 0, sizeof hints);
    hints.ai_family = AF_INET;
    hints.ai_socktype = SOCK_DGRAM;

    if ((ret = getaddrinfo("255.255.255.255", "9090", &hints, &ai)) == -1) {
        fprintf(stderr, "client: getaddrinfo() error: %s\n", gai_strerror(ret));
        return EXIT_FAILURE;
    }

    for (aii = ai; aii != NULL; aii = aii->ai_next) {
        sockfd = socket(aii->ai_family, aii->ai_socktype, aii->ai_protocol);
        if (sockfd == -1) {
            perror("client: socket()");
            continue;
        }
        break;
    }

    if (aii == NULL) {
        fprintf(stderr, "client: cannot create socket\n");
        return EXIT_FAILURE;
    }

    if (setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, &yes, sizeof yes) == -1) {
        perror("client: setsockopt()");
        return EXIT_FAILURE;
    }

    // 1st sendto().
    msg = "hello from client\n";
    bytes = sendto(sockfd, msg, strlen(msg), 0, aii->ai_addr, aii->ai_addrlen);
    if (bytes == -1) {
        perror("sendto 1");
        return EXIT_FAILURE;
    }
    printf("client: sent %zd bytes\n", bytes);

    // 2nd sendto().
    msg = "bye from client\n";
    bytes = sendto(sockfd, msg, strlen(msg), 0, aii->ai_addr, aii->ai_addrlen);
    if (bytes == -1) {
        perror("sendto 2");
        return EXIT_FAILURE;
    }

    printf("client: sent %zd bytes\n", bytes);

    close(sockfd);
    freeaddrinfo(ai);
    return EXIT_SUCCESS;
}