From be5631dff1f4f28636ba1b88e9d17034fe4551d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Anton=20Luka=20=C5=A0ijanec?= Date: Sat, 31 Dec 2022 18:09:39 +0100 Subject: fixed bdecoding strncpy->memcpy +etc --- src/bencoding.c | 23 ++++++---------- src/dht.c | 24 ++++++++--------- src/main.c | 82 +++++++++++++++++++++++++++++++++++++++++++++++++++------ 3 files changed, 94 insertions(+), 35 deletions(-) (limited to 'src') diff --git a/src/bencoding.c b/src/bencoding.c index bcf8f17..66b43b3 100644 --- a/src/bencoding.c +++ b/src/bencoding.c @@ -146,20 +146,13 @@ struct bencoding * bstrs_set (struct bencoding * b, char * s) { * @param num [in] the number to be converted to a bencoding number */ -struct bencoding * bnum (long int num) { +struct bencoding * bnum (long int nr) { struct bencoding * b = calloc(1, sizeof *b); if (!b) return NULL; b->type = num; - /* char buf[512]; - sprintf(buf, "%ld", num); - b->value = strdup(buf); - if (!b->intvalue) { - free(b); - return NULL; - } */ // we could do this, but I don't think it's necessary. b->valuelen = 0; - b->intvalue = num; + b->intvalue = nr; return b; } @@ -513,7 +506,7 @@ struct bencoding * bdecode_safe (const char * s, int len, enum benc opts, unsign return NULL; default: if (!(s[0] >= '0' && s[0] <= '9')) { /* not a string. not checking this would allow DoS for parsing "lx" */ - fprintf(stderr, "bencoding: unknown type %c\n", s[0]); + fprintf(stderr, "bencoding: unknown type %d - %c\n", s[0], s[0]); free(b); return NULL; } @@ -523,7 +516,7 @@ struct bencoding * bdecode_safe (const char * s, int len, enum benc opts, unsign if (len != -1 && (unsigned)len < b->valuelen + (ch+1 - s) /* len minus prefix; strlen & colon */) b->valuelen = len - (ch+1 - s); /* malformed bencoded data, truncating string */ b->value = malloc(b->valuelen+1); - strncpy(b->value, ch+1, b->valuelen); + memcpy(b->value, ch+1, b->valuelen); // ofc not strncpy - binary strs b->value[b->valuelen] = '\0'; b->after = ch+1+b->valuelen; } else { @@ -541,7 +534,7 @@ struct bencoding * bdecode_safe (const char * s, int len, enum benc opts, unsign * * nonstandard things: this parser allows for dict keys to be of any type, valuekey * - * this is a wrapper function, the implementation is in bdecode_safe that was made as an afterthought to prevent stack overflows and limits the number of elements bdecoded to 2**16. + * this is a wrapper function, the implementation is in bdecode_safe that was made as an afterthought to prevent stack overflows and limits the number of elements bdecoded. * * @param len [in] * if set to -1, string is assumed to be correct and not NULL terminated, NULLs may be in strings. * - malicious strings may trigger reads past the end of the buffer, which may lead to undefined @@ -560,7 +553,7 @@ struct bencoding * bdecode_safe (const char * s, int len, enum benc opts, unsign */ struct bencoding * bdecode (const char * s, int len, enum benc opts) { - return bdecode_safe(s, len, opts, 0, 65535); + return bdecode_safe(s, len, opts, 0, 1 << 21); } /** @@ -664,7 +657,7 @@ int bencode_length (struct bencoding * b) { return strlen(buf)+bencode_length(b->key)+2; } if (b->type & string) { - sprintf(buf, "%ld", b->valuelen); + sprintf(buf, "%zu", b->valuelen); return strlen(buf)+1+b->valuelen+bencode_length(b->key); } if (b->type & (list | dict)) { @@ -704,7 +697,7 @@ char * bencode (char * dest, struct bencoding * b) { *dest++ = 'e'; } if (b->type & string) { - sprintf(buf, "%ld:", b->valuelen); + sprintf(buf, "%zu:", b->valuelen); strncpy(dest, buf, strlen(buf)); dest += strlen(buf); memcpy(dest, b->value, b->valuelen); diff --git a/src/dht.c b/src/dht.c index 996dcb1..b11580a 100644 --- a/src/dht.c +++ b/src/dht.c @@ -158,7 +158,6 @@ struct torrent { enum interested type; /**< is truthy only for manually added torrents */ unsigned char hash[20]; /**< infohash */ struct peer * peers; - time_t last; /**< last operation on this torrent, so that inactive torrents are purged */ struct node * nodes; /**< closest K DHT nodes to this hash, used only for announce, peers, info and dl torrents */ struct torrent * next; struct torrent * prev; /**< prev is here so that we can easily pop the oldest torrent. dht->last_torrent is useful here */ @@ -590,7 +589,8 @@ struct node * find (const unsigned char * id, struct bucket ** b, struct node ** prev = node; node = node->next; } - *n = prev; + if (n) + *n = prev; return node; } @@ -959,7 +959,7 @@ void compact (struct dht * d, const char * value, int len, struct torrent * t) { return; } struct node * node = node_init(); - memcpy(node->addr.sin6_addr.s6_addr, "\0\0\0\0\0\0\0\0\0\0\0\0\xFF\xFF\xFF\xFF", 12); + memcpy(node->addr.sin6_addr.s6_addr, "\0\0\0\0\0\0\0\0\0\0\xFF\xFF", 12); node->addr.sin6_port = *((uint16_t *) (value + len-2)); memcpy(node->addr.sin6_addr.s6_addr+(len == 4+2+20 ? 8 : 0), value + 20, len == 4+2+20 ? 4 : 16); memcpy(node->id, value, 20); @@ -1343,7 +1343,7 @@ void handle (struct dht * d, char * pkt, int len, struct sockaddr_in6 addr) { if (!(p->type & string) || (p->valuelen != 6 && p->valuelen != 18)) break; struct peer * peer = calloc(1, sizeof *peer); - memcpy(peer->addr.sin6_addr.s6_addr, "\0\0\0\0\0\0\0\0\0\0\0\0\xFF\xFF\xFF\xFF", 12); + memcpy(peer->addr.sin6_addr.s6_addr, "\0\0\0\0\0\0\0\0\0\0\xFF\xFF", 12); peer->addr.sin6_port = *((uint16_t *) (p->value + p->valuelen-2)); memcpy(peer->addr.sin6_addr.s6_addr+(p->valuelen == 6 ? 8 : 0), p->value, p->valuelen == 6 ? 4 : 16); add_peer(d, torrent, peer); @@ -1427,14 +1427,13 @@ void handle (struct dht * d, char * pkt, int len, struct sockaddr_in6 addr) { .sin6_family = AF_INET6, .sin6_port = *((uint16_t *) pkt) }; - memcpy(a.sin6_addr.s6_addr, "\0\0\0\0\0\0\0\0\xFF\xFF\xFF\xFF", 12); + memcpy(a.sin6_addr.s6_addr, "\0\0\0\0\0\0\0\0\0\0\xFF\xFF", 12); memcpy(a.sin6_addr.s6_addr+12, rr.rdata, 4); potential_node(NULL, &a, NULL); break; case 16: - if (!inet_ntop(AF_INET6, rr.rdata, address, INET6_ADDRSTRLEN+INET_ADDRSTRLEN+7)) { + if (!inet_ntop(AF_INET6, rr.rdata, address, INET6_ADDRSTRLEN+INET_ADDRSTRLEN+7)) L(d->log, "%s !inet_ntop(AF_INET6)", remote); - } sprintf(address+strlen(address), ":%u", ntohs(*((uint16_t *) pkt))); L(d->log, "%s: AAAA %s", remote, address); struct sockaddr_in6 aaaa = { @@ -1586,7 +1585,7 @@ void periodic (struct dht * d) { if (!refresh(d->buckets6)) dns++; if (dns) { - char packet[65536]; + char packet[512]; struct __res_state state; if (res_ninit(&state) == -1) { L(d->log, "res_ninit(&state) == -1"); @@ -1594,7 +1593,7 @@ void periodic (struct dht * d) { } #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wpointer-sign" - int size = res_nmkquery(&state, QUERY, "_dht._udp.travnik.sijanec.eu", ns_c_in, ns_t_srv, NULL, 0, NULL, packet, 65536) != -1; + int size = res_nmkquery(&state, QUERY, "_dht._udp.travnik.sijanec.eu", ns_c_in, ns_t_srv, NULL, 0, NULL, packet, 512) != -1; // for some reason always returns 1 #pragma GCC diagnostic pop if (size == -1) { L(d->log, "res_nmkquery(SRV) == -1"); @@ -1604,7 +1603,7 @@ void periodic (struct dht * d) { #pragma GCC diagnostic ignored "-Wincompatible-pointer-types" for (int i = 0; i < state.nscount; i++) if (state.nsaddr_list[i].sin_family == AF_INET) { // leider - if (sendto(d->socket, packet, size, MSG_DONTWAIT | MSG_NOSIGNAL, &state.nsaddr_list[i], sizeof state.nsaddr_list[i]) == -1) + if (sendto(d->socket, packet, 512, MSG_DONTWAIT | MSG_NOSIGNAL, &state.nsaddr_list[i], sizeof state.nsaddr_list[i]) == -1) L(d->log, "sendto: %s", strerror(errno)); d->txp++; d->txb += size; @@ -1669,6 +1668,7 @@ void periodic (struct dht * d) { */ void work (struct dht * d) { + L(d->log, "work()"); char packet[65536]; struct sockaddr_in6 addr; socklen_t addrlen = sizeof addr; @@ -1681,8 +1681,8 @@ void work (struct dht * d) { else if (ret > 65536) L(d->log, "recvfrom()d larger packet than 65536, not parsing packet"); else if (ret < 0) { - if (ret != EAGAIN) - L(d->log, "recvfrom(): %s", strerror(errno)); + if (errno != EAGAIN) + L(d->log, "recvfrom(): %s (%d)", strerror(errno), errno); else periodic(d); } else { diff --git a/src/main.c b/src/main.c index c054e31..c14af38 100644 --- a/src/main.c +++ b/src/main.c @@ -6,51 +6,117 @@ #include #include #include +#include +#include #define S0(x) (x ? x : "") #include +int samomor = 0; +int periodično = 0; +void handler (int s) { + switch (s) { + case SIGINT: + case SIGTERM: + samomor++; + break; + case SIGALRM: + periodično++; + break; + } +} int main (int argc, char ** argv) { int r = 0; + struct dht * dht = NULL; + struct sigaction sigact = { + .sa_handler = handler, + .sa_flags = SA_RESTART + }; + if (sigaction(SIGALRM, &sigact, NULL) == -1) + error_at_line(1, errno, __FILE__, __LINE__, "sigaction(SIGALRM)"); + if (sigaction(SIGINT, &sigact, NULL) == -1) + error_at_line(2, errno, __FILE__, __LINE__, "sigaction(SIGINT)"); + if (sigaction(SIGTERM, &sigact, NULL) == -1) + error_at_line(3, errno, __FILE__, __LINE__, "sigaction(SIGTERM)"); if (argc != 1+1) - error_at_line(1, 0, __FILE__, __LINE__, "%s configfile.ben", S0(argv[0])); + error_at_line(4, 0, __FILE__, __LINE__, "%s configfile.ben", S0(argv[0])); int cf = open(argv[1], O_RDWR | O_CLOEXEC | O_CREAT, 00664); if (cf == -1) - error_at_line(2, errno, __FILE__, __LINE__, "open(%s)", argv[1]); + error_at_line(5, errno, __FILE__, __LINE__, "open(%s)", argv[1]); struct stat statbuf; if (fstat(cf, &statbuf) == -1) { error_at_line(0, errno, __FILE__, __LINE__, "fstat(cf, &statbuf)"); - r = 3; + r = 6; goto r; } char * cfr = NULL; if (statbuf.st_size && !(cfr = mmap(NULL, statbuf.st_size, PROT_READ, MAP_SHARED, cf, 0))) { error_at_line(0, errno, __FILE__, __LINE__, "mmap(NULL, %ld, PROT_READ, MAP_SHARED, cf, 0)", statbuf.st_size); - r = 4; + r = 7; goto r; } struct bencoding * config = bdecode(cfr, statbuf.st_size, replace); - struct dht * dht = dht_init(config); + dht = dht_init(config); free_bencoding(config); + struct torrent * torrent = calloc(1, sizeof *torrent); + memcpy(torrent->hash, "\xdd\x82\x55\xec\xdc\x7c\xa5\x5f\xb0\xbb\xf8\x13\x23\xd8\x70\x62\xdb\x1f\x6d\x1c", 20); + torrent->type = announce | peers; + add_torrent(dht, torrent); + work(dht); + struct pollfd pollfd = { + .fd = dht->socket, + .events = POLLIN + }; + struct itimerval itimerval = { + .it_interval = { + .tv_sec = 13*60 + } + }; + setitimer(ITIMER_REAL, &itimerval, NULL); +w: + while (poll(&pollfd, 1, -1) == 1) { + work(dht); + } + if (errno == EINTR) { + if (periodično) { + periodično = 0; + work(dht); + goto w; + } + if (!samomor) { + error_at_line(0, errno, __FILE__, __LINE__, "poll"); + r = 108; + } + } else { + error_at_line(0, errno, __FILE__, __LINE__, "poll"); + r = 109; + goto r; + } config = persistent(dht); dht_free(dht); + dht = NULL; if (cfr && munmap(cfr, statbuf.st_size) == -1) { error_at_line(0, errno, __FILE__, __LINE__, "munmap(cf, %ld)", statbuf.st_size); - r = 105; + r = 110; goto r; } cfr = NULL; if (ftruncate(cf, (statbuf.st_size = bencode_length(config))) == -1) { error_at_line(0, errno, __FILE__, __LINE__, "ftruncate(cf, %ld)", statbuf.st_size); - r = 106; + r = 111; goto r; } if (!(cfr = mmap(NULL, statbuf.st_size, PROT_WRITE, MAP_SHARED, cf, 0))) { error_at_line(0, errno, __FILE__, __LINE__, "mmap(NULL, %ld, PROT_READ, MAP_SHARED, cf, 0)", statbuf.st_size); - r = 107; + r = 112; goto r; } bencode(cfr, config); free_bencoding(config); + config = NULL; r: + if (dht) { + dht_free(dht); + dht = NULL; + } if (cfr && munmap(cfr, statbuf.st_size) == -1) error_at_line(0, errno, __FILE__, __LINE__, "munmap(cf, %ld)", statbuf.st_size); if (close(cf) == -1) -- cgit v1.2.3