1
/* Copyright (c) 2009-2012 Sam Trenholme
5
* Redistribution and use in source and binary forms, with or without
6
* modification, are permitted provided that the following conditions
9
* 1. Redistributions of source code must retain the above copyright
10
* notice, this list of conditions and the following disclaimer.
11
* 2. Redistributions in binary form must reproduce the above copyright
12
* notice, this list of conditions and the following disclaimer in the
13
* documentation and/or other materials provided with the distribution.
15
* This software is provided 'as is' with no guarantees of correctness or
16
* fitness for purpose.
19
#include <sys/socket.h>
20
#include <netinet/in.h>
21
#include <arpa/inet.h>
29
/* We use a special SOCKET type for easier Windows porting */
32
/* This is the header placed before the 4-byte IP; we change the last four
33
* bytes to set the IP we give out in replies */
35
"\xc0\x0c\x00\x01\x00\x01\x00\x00\x00\xff\x00\x04\x7f\x7f\x7f\x7f";
37
uint32_t get_ip(int argc, char **argv) {
41
/* Set the BIND ip and the IP we give everyone */
42
if(argc < 2 || argc > 3) {
44
"Usage: microdns {ip to give out} [{ip of microdns server}]\n"
49
/* Set the IP we give everyone */
50
ip = inet_addr(argv[1]);
52
p[12] = (ip & 0xff000000) >> 24;
53
p[13] = (ip & 0x00ff0000) >> 16;
54
p[14] = (ip & 0x0000ff00) >> 8;
55
p[15] = (ip & 0x000000ff);
57
/* Set the IP we bind to (default is "0", which means "all IPs) */
60
ip = inet_addr(argv[2]);
62
/* Return the IP we bind to */
66
/* Get port: Get a port locally and return the socket the port is on */
67
SOCKET get_port(uint32_t ip, char **argv, struct sockaddr_in *dns_udp) {
72
sock = socket(AF_INET,SOCK_DGRAM,0);
74
perror("socket error");
77
memset(dns_udp,0,sizeof(struct sockaddr_in));
78
dns_udp->sin_family = AF_INET;
79
dns_udp->sin_port = htons(53);
80
dns_udp->sin_addr.s_addr = ip;
81
if(dns_udp->sin_addr.s_addr == INADDR_NONE) {
82
printf("Problem with bind IP %s\n",argv[2]);
85
len_inet = sizeof(struct sockaddr_in);
86
if(bind(sock,(struct sockaddr *)dns_udp,len_inet) == -1) {
91
/* Linux kernel bug */
92
/* fcntl(sock, F_SETFL, O_NONBLOCK); */
97
int main(int argc, char **argv) {
101
socklen_t foo = sizeof(in);
102
struct sockaddr_in dns_udp;
103
uint32_t ip = 0; /* 0.0.0.0; default bind IP */
104
int leni = sizeof(struct sockaddr);
105
int truncated_trigger = 1;
107
ip = get_ip(argc, argv);
108
sock = get_port(ip,argv,&dns_udp);
110
/* Now that we know the IP and are on port 53, process incoming
113
/* Get data from UDP port 53 */
114
len_inet = recvfrom(sock,in,255,0,(struct sockaddr *)&dns_udp,
116
/* Roy Arends check: We only answer questions */
117
if(len_inet < 3 || (in[2] & 0x80) != 0x00) {
121
/* Prepare the reply */
123
/* Make this an answer */
125
if(in[11] == 0) { /* EDNS not supported */
126
/* We add an additional answer */
129
in[3] &= 0xf0; in[3] |= 4; /* NOTIMPL */
133
/* EDNS not supported */
135
in[len_inet + a] = p[a];
138
if(truncated_trigger == 1) {
139
truncated_trigger = 0;
143
} else { /* Half of the replies are EasyDNS-style truncated */
144
truncated_trigger = 1;
148
sendto(sock,in,len_inet + 16,0, (struct sockaddr *)&dns_udp,