Last active
August 27, 2024 13:46
-
-
Save neoxic/0d9314ec756d37ca4303bced49b94543 to your computer and use it in GitHub Desktop.
SOCK_DGRAM: race between 'bind()' and 'connect()' leads to a connected socket receiving unfiltered datagrams
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <err.h> | |
#include <stdio.h> | |
#include <string.h> | |
#include <unistd.h> | |
#include <netdb.h> | |
#include <sys/types.h> | |
#include <sys/socket.h> | |
#define check(expr) if ((expr) == -1) err(1, "%s", #expr); | |
int main(int argc, char *argv[]) { | |
struct sockaddr_storage sa; | |
struct addrinfo *ai; | |
socklen_t sl; | |
int res, i, j, fd; | |
char buf[64]; | |
if (argc != 3) errx(1, "Invalid number of arguments"); | |
if ((res = getaddrinfo(argv[1], argv[2], 0, &ai))) errx(1, "%s: %s", argv[0], gai_strerror(res)); | |
memcpy(&sa, ai->ai_addr, sl = ai->ai_addrlen); | |
freeaddrinfo(ai); | |
for (i = 0; i < 20; ++i) { | |
check(fd = socket(sa.ss_family, SOCK_DGRAM, 0)); | |
check(connect(fd, (struct sockaddr *)&sa, sl)); | |
for (j = 0; j < 20; ++j) check(write(fd, buf, sprintf(buf, "%d-%d", i, j))); | |
check(close(fd)); | |
} | |
return 0; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <err.h> | |
#include <stdio.h> | |
#include <string.h> | |
#include <unistd.h> | |
#include <netdb.h> | |
#include <poll.h> | |
#include <fcntl.h> | |
#include <sys/types.h> | |
#include <sys/socket.h> | |
#define check(expr) if ((expr) == -1) err(1, "%s", #expr); | |
int main(int argc, char *argv[]) { | |
struct sockaddr_storage lsa, csa, csa_; | |
struct addrinfo *ai; | |
struct pollfd fds[1000]; | |
socklen_t lsl, csl, csl_; | |
int res, fd, i, nfd = 0, on = 1; | |
if (argc != 3) errx(1, "Invalid number of arguments"); | |
if ((res = getaddrinfo(argv[1], argv[2], 0, &ai))) errx(1, "%s: %s", argv[0], gai_strerror(res)); | |
memcpy(&lsa, ai->ai_addr, lsl = ai->ai_addrlen); | |
freeaddrinfo(ai); | |
check(fd = socket(lsa.ss_family, SOCK_DGRAM, 0)); | |
check(fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK)); | |
#ifdef __linux__ | |
check(setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof on)); | |
#else | |
check(setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &on, sizeof on)); | |
#endif | |
check(bind(fd, (struct sockaddr *)&lsa, lsl)); | |
fds[nfd].fd = fd; | |
fds[nfd].events = POLLIN; | |
++nfd; | |
for (;;) { | |
check(poll(fds, nfd, -1)); | |
for (i = 0; i < nfd; ++i) { | |
if (!(fds[i].revents & POLLIN)) continue; | |
fd = fds[i].fd; | |
if (i == nfd - 1) { /* New connection */ | |
csl = sizeof csa; | |
check(res = recvfrom(fd, 0, 0, 0, (struct sockaddr *)&csa, &csl)); | |
/* Create new socket */ | |
check(fd = socket(csa.ss_family, SOCK_DGRAM, 0)); | |
check(fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK)); | |
#ifdef __linux__ | |
check(setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof on)); | |
#else | |
check(setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &on, sizeof on)); | |
#endif | |
check(getsockname(fds[i].fd, (struct sockaddr *)&lsa, &lsl)); | |
check(bind(fd, (struct sockaddr *)&lsa, lsl)); | |
if (connect(fd, (struct sockaddr *)&csa, csl)) { /* Duplicate connection */ | |
close(fd); | |
continue; | |
} | |
fds[nfd].fd = fds[i].fd; | |
fds[nfd].events = POLLIN; | |
fds[i].fd = fd; | |
++nfd; | |
break; | |
} | |
/* Check peer's address */ | |
csl = sizeof csa; | |
check(res = recvfrom(fd, 0, 0, 0, (struct sockaddr *)&csa, &csl)); | |
check(getpeername(fd, (struct sockaddr *)&csa_, &csl_)); | |
if (csl != csl_ || memcmp(&csa, &csa_, csl_)) printf("#%d: address mismatch!\n", fd); | |
} | |
} | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Compile:
Run:
while firing packets with: