#define __USE_GNU #include <arpa/inet.h> #include <arpa/nameser.h> #include <errno.h> #include <fcntl.h> #include <linux/sched.h> #include <net/if.h> #include <net/route.h> #include <netdb.h> #include <netinet/in.h> #include <netinet/ip6.h> #include <netinet/tcp.h> #include <pthread.h> #include <resolv.h> #include <stdlib.h> #include <string.h> #include <sys/ioctl.h> #include <sys/resource.h> #include <sys/socket.h> #include <sys/stat.h> #include <sys/time.h> #include <sys/types.h> #include <sys/wait.h> #include <unistd.h> #include <libhfuzz/libhfuzz.h> static void unsh(void) { if (linuxEnterNs(CLONE_NEWUSER | CLONE_NEWNET | CLONE_NEWNS) == false) { exit(1); } if (linuxIfaceUp("lo") == false) { exit(1); } } static size_t rlen = 0; static const char *rbuf = NULL; static void *getdata(void *unused) { int myfd = socket(AF_INET, SOCK_STREAM, IPPROTO_IP); if (myfd == -1) { perror("socket"); exit(1); } struct sockaddr_in saddr; saddr.sin_family = AF_INET; saddr.sin_port = htons(53); saddr.sin_addr.s_addr = inet_addr("127.0.0.53"); if (bind(myfd, (struct sockaddr *)&saddr, sizeof(saddr)) == -1) { perror("bind"); exit(1); } if (listen(myfd, SOMAXCONN) == -1) { perror("listen"); exit(1); } for (;;) { struct sockaddr_in cli; socklen_t cli_len = sizeof(cli); int nfd = accept(myfd, (struct sockaddr *)&cli, &cli_len); if (nfd == -1) { perror("accept"); exit(1); } char b[1024 * 1024]; ssize_t sz = recv(nfd, b, sizeof(b), 0); if (sz <= 0) { perror("recv"); exit(1); } if (sz < 4) { close(nfd); continue; } /* Copy the TCP len to the beginning of the reply packet */ *((uint16_t *)rbuf) = htons(rlen - 2); /* Copy the DNS request ID back */ memcpy((char *)&rbuf[2], &b[2], 2); if (send(nfd, rbuf, rlen, MSG_NOSIGNAL) == -1) { if (errno != ECONNRESET) { perror("send"); exit(1); } } close(nfd); } return NULL; } static void launchthr(void) { pthread_attr_t attr; pthread_attr_init(&attr); pthread_attr_setstacksize(&attr, 1024 * 1024 * 4); pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); pthread_t t; if (pthread_create(&t, &attr, getdata, NULL) < 0) { perror("pthread_create"); exit(1); } } /* main entry point, possibly hooked */ int main(int argc, char *argv[]) { /* Use TCP connections for DNS */ setenv("RES_OPTIONS", "use-vc", 1); res_init(); if (getenv("NO_FUZZ") == NULL) { unsh(); launchthr(); } /* Wait for the DNS server to set up */ usleep(100000); for (;;) { const char *buf; size_t len; HF_ITER((const uint8_t **)&buf, &len); rlen = 0; rbuf = NULL; if (len < 8) { continue; } uint32_t tmplen = *((const uint32_t *)buf); buf = &buf[sizeof(uint32_t)]; len -= sizeof(uint32_t); tmplen %= len; rbuf = &buf[tmplen]; rlen = len - tmplen; len = tmplen; char b[1024 * 1024]; strncpy(b, buf, len); b[len] = '\0'; gethostbyname(b); struct hostent he; struct hostent *result; char sbuf[1024 * 32]; extern int h_errno; gethostbyname2_r(b, AF_INET, &he, sbuf, sizeof(sbuf), &result, &h_errno); gethostbyname2_r(b, AF_INET6, &he, sbuf, sizeof(sbuf), &result, &h_errno); struct addrinfo *res = NULL; if (getaddrinfo(b, NULL, NULL, &res) == 0) { freeaddrinfo(res); } } }