/*
|
|
* 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;
|
|
}
|