#include <fcntl.h>
#include <netdb.h>
#include <netinet/in.h>
-#include <poll.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <sys/resource.h>
-#include <sys/socket.h>
#include <time.h>
#include <unistd.h>
+#include <sys/caprights.h>
+#include <sys/capsicum.h>
+#include <sys/event.h>
+#include <sys/resource.h>
+#include <sys/socket.h>
+
+#undef MIN
#define MIN(x, y) ((x) <= (y) ? (x) : (y))
+#define MAX_PKT_SIZE 1536
+
#define ERROR 0
#define REPLY 1
#define PING 2
unsigned char id[160];
struct sockaddr_storage ss;
socklen_t sslen;
+ char _pad[4];
};
#define CIRCULAR_LIST_SIZE 256
static bool verbose = true;
+struct Pkt {
+ unsigned char buf[MAX_PKT_SIZE];
+ struct sockaddr_storage ss;
+ size_t len;
+ socklen_t salen;
+ char _pad[4];
+};
+
+static struct Pkt pkt;
+static int sockW = -1;
+
// ------------------------ >8 ------------------------
static const char *
if (p) {
size_t i = p - buf + 9;
unsigned long j = 0, j6 = 0;
- while (1) {
+ for (;;) {
l = strtoul((const char *)buf + i, &q, 10);
if (q && *q == ':' && l > 0) {
CHECK(q + 1, l);
#define ADD_V(buf, offset, size) COPY(buf, offset, my_v, (sizeof my_v), size)
static bool
-is_martian(const struct sockaddr *sa)
+is_martian(const struct sockaddr_storage *ss)
{
- switch (sa->sa_family) {
+ switch (((const struct sockaddr *)ss)->sa_family) {
case AF_INET: {
- const struct sockaddr_in *sin = (const struct sockaddr_in *)sa;
+ const struct sockaddr_in *sin = (const struct sockaddr_in *)ss;
const unsigned char *address = (const unsigned char *)&sin->sin_addr;
return sin->sin_port == 0 || (address[0] == 0) || (address[0] == 127) ||
((address[0] & 0xE0) == 0xE0);
}
case AF_INET6: {
- const struct sockaddr_in6 *sin6 = (const struct sockaddr_in6 *)sa;
+ const struct sockaddr_in6 *sin6 = (const struct sockaddr_in6 *)ss;
const unsigned char *address = (const unsigned char *)&sin6->sin6_addr;
return sin6->sin6_port == 0 || (address[0] == 0xFF) ||
(address[0] == 0xFE && (address[1] & 0xC0) == 0x80) ||
time_t now = time(NULL);
if (token_bucket_tokens == 0) {
token_bucket_tokens =
- MIN(MAX_TOKEN_BUCKET_TOKENS, 4 * (now - token_bucket_time));
+ MIN(MAX_TOKEN_BUCKET_TOKENS, 4 * (int)(now - token_bucket_time));
token_bucket_time = now;
}
if (token_bucket_tokens == 0)
return true;
}
+static ssize_t
+pktSend(const struct Pkt *p)
+{
+ int s = -1;
+ const struct sockaddr *sa = (const struct sockaddr *)&(p->ss);
+ switch (sa->sa_family) {
+ case AF_INET:
+ s = dht_socket;
+ break;
+ case AF_INET6:
+ s = dht_socket6;
+ break;
+ default:
+ abort();
+ }
+ return sendto(s, p->buf, p->len, 0, sa, p->salen);
+}
+
static ssize_t
dht_send(
const void *buf,
{
if (salen == 0)
abort();
- int s;
- if (sa->sa_family == AF_INET)
- s = dht_socket;
- else if (sa->sa_family == AF_INET6)
- s = dht_socket6;
- else
- s = -1;
- if (s < 0) {
- errno = EAFNOSUPPORT;
- return -1;
- }
- return sendto(s, buf, len, 0, sa, salen);
+ memcpy(&(pkt.ss), sa, sizeof(struct sockaddr_storage));
+ memcpy(pkt.buf, buf, len);
+ pkt.len = len;
+ pkt.salen = salen;
+ if (sockW == -1)
+ return pktSend(&pkt);
+ return write(sockW, &pkt, sizeof(struct Pkt));
}
static ssize_t
struct sockaddr_storage ss;
socklen_t sslen;
- int rc;
if (dopop) {
- rc = list_pop(list, &ss, &sslen);
- if (rc == 0)
+ if (list_pop(list, &ss, &sslen) == 0)
return 0;
} else {
- rc = list_random(list, NULL, &ss, &sslen);
- if (rc == 0)
+ if (list_random(list, NULL, &ss, &sslen) == 0)
return 0;
}
struct sockaddr_storage ss;
socklen_t sslen;
unsigned char id[20];
- int rc;
int n = 0;
while (n < 8) {
- rc = list_random(list, id, &ss, &sslen);
- if (rc < 1)
+ if (list_random(list, id, &ss, &sslen) < 1)
break;
switch (af) {
case AF_INET: {
char *ipv6addr = NULL;
int opt = 0;
- while (1) {
+ for (;;) {
opt = getopt(argc, argv, "q4:6:");
if (opt < 0)
break;
arc4random_buf(myid, sizeof myid);
memcpy(my_v, "1:v4:JB\0\0", 9);
+ memset(&(pkt.ss), 0, sizeof(struct sockaddr_storage));
int rc = 0;
unsigned char ttid[4];
infop = info;
while (infop) {
make_tid(ttid, "pn", 0);
- send_ping(infop->ai_addr, infop->ai_addrlen, ttid, 4);
+ if (send_ping(infop->ai_addr, infop->ai_addrlen, ttid, 4) == -1)
+ err(EXIT_FAILURE, "sendto()");
infop = infop->ai_next;
}
freeaddrinfo(info);
-
i++;
}
- token_bucket_time = time(NULL);
- token_bucket_tokens = MAX_TOKEN_BUCKET_TOKENS;
- bool send4 = false;
- struct pollfd fds[2];
- fds[0].fd = dht_socket;
- fds[0].events = POLLIN;
- fds[1].fd = dht_socket6;
- fds[1].events = POLLIN;
-
close(STDIN_FILENO);
if (!verbose)
close(STDOUT_FILENO);
+
+ int sockets[2];
+ if (socketpair(PF_LOCAL, SOCK_DGRAM, 0, sockets) != 0)
+ err(EXIT_FAILURE, "socketpair()");
+ int sockR = sockets[0];
+ sockW = sockets[1];
+ pid_t pid = fork();
+ if (pid == -1)
+ err(EXIT_FAILURE, "fork()");
+ if (pid == 0) {
+ close(sockW);
+
+ rlimited(RLIMIT_NPROC);
+ rlimited(RLIMIT_FSIZE);
+ rlimited(RLIMIT_NOFILE);
+ ssize_t n = 0;
+ unsigned char buf[sizeof(struct Pkt)];
+ for (;;) {
+ n = read(sockR, buf, sizeof buf);
+ if (n == -1) {
+ perror("read()");
+ continue;
+ }
+ if (pktSend((struct Pkt *)buf) == -1)
+ perror("sendto()");
+ }
+ }
+ close(sockR);
+
+ cap_rights_t caprights;
+ cap_rights_init(&caprights, CAP_WRITE);
+ if (cap_rights_limit(STDERR_FILENO, &caprights) != 0)
+ err(EXIT_FAILURE, "cap_rights_limit(stderr)");
+ if (!verbose)
+ if (cap_rights_limit(STDOUT_FILENO, &caprights) != 0)
+ err(EXIT_FAILURE, "cap_rights_limit(stdout)");
+ if (cap_rights_limit(sockW, &caprights) != 0)
+ err(EXIT_FAILURE, "cap_rights_limit(sockW)");
+ if (cap_enter() != 0)
+ err(EXIT_FAILURE, "cap_enter()");
+
+ token_bucket_time = time(NULL);
+ token_bucket_tokens = MAX_TOKEN_BUCKET_TOKENS;
+
+ int kq = kqueue();
+ if (kq == -1)
+ err(EXIT_FAILURE, "kqueue()");
+ struct kevent chs[2];
+ struct kevent ev;
+ int chsLen = 0;
+ if (dht_socket != -1) {
+ EV_SET(&(chs[chsLen]), dht_socket, EVFILT_READ, EV_ADD, 0, 0, NULL);
+ chsLen++;
+ }
+ if (dht_socket6 != -1) {
+ EV_SET(&(chs[chsLen]), dht_socket6, EVFILT_READ, EV_ADD, 0, 0, NULL);
+ chsLen++;
+ }
+
rlimited(RLIMIT_NPROC);
rlimited(RLIMIT_FSIZE);
-#if __FreeBSD__
rlimited(RLIMIT_NOFILE);
-#endif // __FreeBSD__
- while (1) {
- int tv_sec = 0;
+ struct timespec tm;
+ bool send4;
+ for (;;) {
if ((dht_socket >= 0 && list_elements(&v4_confirmed) <= 16) ||
(dht_socket6 >= 0 && list_elements(&v6_confirmed) <= 16))
- tv_sec = 0;
+ tm.tv_sec = 0;
else
- tv_sec = random() % 30;
- int tv_msec = random() % 1000;
+ tm.tv_sec = random() % 30;
+ tm.tv_nsec = 1000000 * (random() % 1000);
-#ifndef __linux__
setproctitle_fast(
"%d+%d %d+%d",
list_elements(&v4_confirmed),
list_elements(&v6_confirmed),
list_elements(&v4_new),
list_elements(&v6_new));
-#endif // __linux__
- rc = poll(fds, 2, tv_sec * 1000 + tv_msec);
- if (rc < 0) {
- perror("poll");
- sleep(1);
- }
+ rc = kevent(kq, chs, chsLen, &ev, 1, &tm);
+ if (rc < 0)
+ err(EXIT_FAILURE, "kevent()");
if (rc > 0) {
+ ssize_t got = -1;
+ unsigned char buf[MAX_PKT_SIZE];
+ struct sockaddr_storage source_storage;
+ struct sockaddr *source = (struct sockaddr *)&source_storage;
+ socklen_t sourcelen = sizeof(source_storage);
+ if (ev.flags & EV_ERROR) {
+ fprintf(stderr, "EV_ERROR: %s\n", strerror((int)(ev.data)));
+ } else {
+ got = recvfrom((int)ev.ident, buf, MAX_PKT_SIZE, 0, source, &sourcelen);
+ }
+ if (got < 0 || sourcelen > sizeof(struct sockaddr_storage))
+ goto dontread;
+ if (is_martian(&source_storage))
+ goto dontread;
+ if (got < MAX_PKT_SIZE) {
+ buf[got] = '\0';
+ } else {
+ if (verbose)
+ printf("%s : overlong message\n", getAddr(source, sourcelen));
+ goto dontread;
+ }
+
int message;
unsigned char tid[16];
unsigned char id[20];
unsigned char info_hash[20];
unsigned char target[20];
- unsigned char buf[1536];
unsigned char nodes[256];
unsigned char nodes6[1024];
unsigned char token[128];
size_t values_len = sizeof values;
size_t values6_len = sizeof values6;
int want;
- struct sockaddr_storage source_storage;
- struct sockaddr *source = (struct sockaddr *)&source_storage;
- socklen_t sourcelen = sizeof(source_storage);
- ssize_t got = 0;
- if (fds[0].revents != 0) {
- if ((fds[0].revents & (POLLERR | POLLNVAL)) > 0) {
- fprintf(stderr, "error in fds[0]");
- got = -1;
- } else {
- got = recvfrom(dht_socket, buf, 1536, 0, source, &sourcelen);
- }
- } else if (fds[1].revents != 0) {
- if ((fds[1].revents & (POLLERR | POLLNVAL)) > 0) {
- fprintf(stderr, "error in fds[1]");
- got = -1;
- } else {
- got = recvfrom(dht_socket6, buf, 1536, 0, source, &sourcelen);
- }
- }
-
- if (got < 0 || sourcelen > sizeof(struct sockaddr_storage))
- goto dontread;
-
- if (is_martian(source))
- goto dontread;
-
- /* There's a bug in parse_message -- it will happily overflow the
- buffer if it's not NUL-terminated. For now, put a NUL at the
- end of buffers. */
-
- if (got < 1536) {
- buf[got] = '\0';
- } else {
- if (verbose)
- printf("%s : overlong message\n", getAddr(source, sourcelen));
- goto dontread;
- }
-
message = parse_message(
buf,
(size_t)got,
if (!token_bucket()) {
if (verbose)
printf(
- "%s : dropping request due to rate limiting.\n",
+ "%s : dropping request due to rate limiting\n",
getAddr(source, sourcelen));
goto dontread;
}