#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);
}
}
}