DNS server, which rejects all requests.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

101 lines
3.1 KiB

/*
* nodnsd - DNS server, which rejects all requests.
*
* The musl library has the misfeature (IMHO), that the resolver
* does DNS requests to localhost, if no nameservers are defined.
* As localhost normally doesn't answer DNS requests, the use of
* unknown hosts leads to a delay until an error is returned.
*
* By starting this server all DNS requests are immediately
* rejected and a delay is avoided.
*
* This program is put into the public domain, use it as you like.
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#define BUFLEN 1500 /* length of buffer */
#define PORT 53 /* DNS port */
#define DNS_FLAG_OFF 2 /* DNS flag offset */
#define DNS_FLAG_RESP 0x848f /* DNS response field mask */
#define DNS_FLAG_NXDOM 0x8003 /* DNS response: non-existent domain */
#define DNS_FLAG_RD 0x0100 /* DNS recursion desired */
#define DNS_FLAG_RA 0x0080 /* DNS recursion available */
static void die(char *s) {
perror(s);
exit(1);
}
int main(int argc, char *argv[]) {
struct sockaddr_in6 si_me, si_peer;
socklen_t si_len;
unsigned char buf[BUFLEN];
uint16_t dns_flags;
int ipv6_only;
int pid;
int recv_len;
int sock;
/* no command line arguments */
if (argc > 1) {
fprintf(stderr, "nodnsd - DNS server, which rejects all requests.\n");
exit(1);
}
/* create an UDP socket */
if ((sock = socket(PF_INET6, SOCK_DGRAM, IPPROTO_UDP)) < 0)
die("socket");
/* protocol / address / port for bind() */
memset(&si_me, 0, sizeof(si_me));
si_me.sin6_family = AF_INET6;
si_me.sin6_port = htons(PORT);
si_me.sin6_addr = in6addr_any;
/* bind to both IPv4 and IPv6 */
ipv6_only = 0;
if (setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY,
&ipv6_only, sizeof(ipv6_only)))
die("setsockopt");
/* bind socket to port */
if (bind(sock , (struct sockaddr*)&si_me, sizeof(si_me) ) < 0)
die("bind");
/* background our process */
pid = fork();
if (pid < 0) die("fork");
if (pid > 0) exit(0);
freopen("/dev/null", "r", stdin);
if (setsid() < 0) die("setsid");
/* keep listening for data */
while (1) {
/* try to receive some data, this is a blocking call */
si_len = sizeof(si_peer);
recv_len = recvfrom(sock, buf, sizeof(buf), 0,
(struct sockaddr *)&si_peer, &si_len);
if (recv_len < 0) die("recvfrom");
/* set DNS response to non-existent domain */
dns_flags = (buf[DNS_FLAG_OFF] << 8) | buf[DNS_FLAG_OFF+1];
dns_flags &= ~DNS_FLAG_RESP; /* clear response bits */
dns_flags |= DNS_FLAG_NXDOM; /* set response */
if (dns_flags & DNS_FLAG_RD) dns_flags |= DNS_FLAG_RA;
buf[DNS_FLAG_OFF] = (dns_flags >> 8) & 0xFF;
buf[DNS_FLAG_OFF+1] = dns_flags & 0xFF;
/* now send reply to the client */
if (sendto(sock, buf, recv_len, 0, (struct sockaddr*) &si_peer, si_len) < 0)
die("sendto");
}
close(sock);
return 0;
}