dnsd.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472
  1. /*
  2. * Mini DNS server implementation for busybox
  3. *
  4. * Copyright (C) 2005 Roberto A. Foglietta (me@roberto.foglietta.name)
  5. * Copyright (C) 2005 Odd Arild Olsen (oao at fibula dot no)
  6. * Copyright (C) 2003 Paul Sheer
  7. * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
  8. *
  9. * Odd Arild Olsen started out with the sheerdns [1] of Paul Sheer and rewrote
  10. * it into a shape which I believe is both easier to understand and maintain.
  11. * I also reused the input buffer for output and removed services he did not
  12. * need. [1] http://threading.2038bug.com/sheerdns/
  13. *
  14. * Some bugfix and minor changes was applied by Roberto A. Foglietta who made
  15. * the first porting of oao' scdns to busybox also.
  16. */
  17. #include <unistd.h>
  18. #include <string.h>
  19. #include <signal.h>
  20. #include <arpa/inet.h>
  21. #include <sys/socket.h>
  22. #include <ctype.h>
  23. #include "libbb.h"
  24. static char *fileconf = "/etc/dnsd.conf";
  25. #define LOCK_FILE "/var/run/dnsd.lock"
  26. #define LOG_FILE "/var/log/dnsd.log"
  27. enum {
  28. MAX_HOST_LEN = 16, // longest host name allowed is 15
  29. IP_STRING_LEN = 18, // .xxx.xxx.xxx.xxx\0
  30. //must be strlen('.in-addr.arpa') larger than IP_STRING_LEN
  31. MAX_NAME_LEN = (IP_STRING_LEN + 13),
  32. /* Cannot get bigger packets than 512 per RFC1035
  33. In practice this can be set considerably smaller:
  34. Length of response packet is header (12B) + 2*type(4B) + 2*class(4B) +
  35. ttl(4B) + rlen(2B) + r (MAX_NAME_LEN =21B) +
  36. 2*querystring (2 MAX_NAME_LEN= 42B), all together 90 Byte
  37. */
  38. MAX_PACK_LEN = 512 + 1,
  39. DEFAULT_TTL = 30, // increase this when not testing?
  40. REQ_A = 1,
  41. REQ_PTR = 12
  42. };
  43. struct dns_repl { // resource record, add 0 or 1 to accepted dns_msg in resp
  44. uint16_t rlen;
  45. uint8_t *r; // resource
  46. uint16_t flags;
  47. };
  48. struct dns_head { // the message from client and first part of response mag
  49. uint16_t id;
  50. uint16_t flags;
  51. uint16_t nquer; // accepts 0
  52. uint16_t nansw; // 1 in response
  53. uint16_t nauth; // 0
  54. uint16_t nadd; // 0
  55. };
  56. struct dns_prop {
  57. uint16_t type;
  58. uint16_t class;
  59. };
  60. struct dns_entry { // element of known name, ip address and reversed ip address
  61. struct dns_entry *next;
  62. char ip[IP_STRING_LEN]; // dotted decimal IP
  63. char rip[IP_STRING_LEN]; // length decimal reversed IP
  64. char name[MAX_HOST_LEN];
  65. };
  66. static struct dns_entry *dnsentry = NULL;
  67. static int daemonmode = 0;
  68. static uint32_t ttl = DEFAULT_TTL;
  69. /*
  70. * Convert host name from C-string to dns length/string.
  71. */
  72. static void
  73. convname(char *a, uint8_t *q)
  74. {
  75. int i = (q[0] == '.') ? 0 : 1;
  76. for(; i < MAX_HOST_LEN-1 && *q; i++, q++)
  77. a[i] = tolower(*q);
  78. a[0] = i - 1;
  79. a[i] = 0;
  80. }
  81. /*
  82. * Insert length of substrings insetad of dots
  83. */
  84. static void
  85. undot(uint8_t * rip)
  86. {
  87. int i = 0, s = 0;
  88. while(rip[i]) i++;
  89. for(--i; i >= 0; i--) {
  90. if(rip[i] == '.') {
  91. rip[i] = s;
  92. s = 0;
  93. } else s++;
  94. }
  95. }
  96. /*
  97. * Append message to log file
  98. */
  99. static void
  100. log_message(char *filename, char *message)
  101. {
  102. FILE *logfile;
  103. if (!daemonmode)
  104. return;
  105. logfile = fopen(filename, "a");
  106. if (!logfile)
  107. return;
  108. fprintf(logfile, "%s\n", message);
  109. fclose(logfile);
  110. }
  111. /*
  112. * Read one line of hostname/IP from file
  113. * Returns 0 for each valid entry read, -1 at EOF
  114. * Assumes all host names are lower case only
  115. * Hostnames with more than one label is not handled correctly.
  116. * Presently the dot is copied into name without
  117. * converting to a length/string substring for that label.
  118. */
  119. static int
  120. getfileentry(FILE * fp, struct dns_entry *s, int verb)
  121. {
  122. unsigned int a,b,c,d;
  123. char *r, *name;
  124. restart:
  125. if(!(r = bb_get_line_from_file(fp)))
  126. return -1;
  127. while(*r == ' ' || *r == '\t') {
  128. r++;
  129. if(!*r || *r == '#' || *r == '\n')
  130. goto restart; /* skipping empty/blank and commented lines */
  131. }
  132. name = r;
  133. while(*r != ' ' && *r != '\t')
  134. r++;
  135. *r++ = 0;
  136. if(sscanf(r,"%u.%u.%u.%u",&a,&b,&c,&d) != 4)
  137. goto restart; /* skipping wrong lines */
  138. sprintf(s->ip,"%u.%u.%u.%u",a,b,c,d);
  139. sprintf(s->rip,".%u.%u.%u.%u",d,c,b,a);
  140. undot((uint8_t*)s->rip);
  141. convname(s->name,(uint8_t*)name);
  142. if(verb)
  143. fprintf(stderr,"\tname:%s, ip:%s\n",&(s->name[1]),s->ip);
  144. return 0; /* warningkiller */
  145. }
  146. /*
  147. * Read hostname/IP records from file
  148. */
  149. static void
  150. dnsentryinit(int verb)
  151. {
  152. FILE *fp;
  153. struct dns_entry *m, *prev;
  154. prev = dnsentry = NULL;
  155. if(!(fp = fopen(fileconf, "r")))
  156. bb_perror_msg_and_die("open %s",fileconf);
  157. while (1) {
  158. if(!(m = (struct dns_entry *)malloc(sizeof(struct dns_entry))))
  159. bb_perror_msg_and_die("malloc dns_entry");
  160. m->next = NULL;
  161. if (getfileentry(fp, m, verb))
  162. break;
  163. if (prev == NULL)
  164. dnsentry = m;
  165. else
  166. prev->next = m;
  167. prev = m;
  168. }
  169. fclose(fp);
  170. }
  171. /*
  172. * Set up UDP socket
  173. */
  174. static int
  175. listen_socket(char *iface_addr, int listen_port)
  176. {
  177. struct sockaddr_in a;
  178. char msg[100];
  179. int s;
  180. int yes = 1;
  181. if ((s = socket(PF_INET, SOCK_DGRAM, 0)) < 0)
  182. bb_perror_msg_and_die("socket() failed");
  183. #ifdef SO_REUSEADDR
  184. if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *)&yes, sizeof(yes)) < 0)
  185. bb_perror_msg_and_die("setsockopt() failed");
  186. #endif
  187. memset(&a, 0, sizeof(a));
  188. a.sin_port = htons(listen_port);
  189. a.sin_family = AF_INET;
  190. if (!inet_aton(iface_addr, &a.sin_addr))
  191. bb_perror_msg_and_die("bad iface address");
  192. if (bind(s, (struct sockaddr *)&a, sizeof(a)) < 0)
  193. bb_perror_msg_and_die("bind() failed");
  194. listen(s, 50);
  195. sprintf(msg, "accepting UDP packets on addr:port %s:%d\n",
  196. iface_addr, (int)listen_port);
  197. log_message(LOG_FILE, msg);
  198. return s;
  199. }
  200. /*
  201. * Look query up in dns records and return answer if found
  202. * qs is the query string, first byte the string length
  203. */
  204. static int
  205. table_lookup(uint16_t type, uint8_t * as, uint8_t * qs)
  206. {
  207. int i;
  208. struct dns_entry *d=dnsentry;
  209. do {
  210. #ifdef DEBUG
  211. char *p,*q;
  212. q = (char *)&(qs[1]);
  213. p = &(d->name[1]);
  214. fprintf(stderr, "\ntest: %d <%s> <%s> %d", strlen(p), p, q, strlen(q));
  215. #endif
  216. if (type == REQ_A) { /* search by host name */
  217. for(i = 1; i <= (int)(d->name[0]); i++)
  218. if(tolower(qs[i]) != d->name[i])
  219. continue;
  220. #ifdef DEBUG
  221. fprintf(stderr, " OK");
  222. #endif
  223. strcpy((char *)as, d->ip);
  224. #ifdef DEBUG
  225. fprintf(stderr, " %s ", as);
  226. #endif
  227. return 0;
  228. }
  229. else if (type == REQ_PTR) { /* search by IP-address */
  230. if (!strncmp((char*)&d->rip[1], (char*)&qs[1], strlen(d->rip)-1)) {
  231. strcpy((char *)as, d->name);
  232. return 0;
  233. }
  234. }
  235. } while ((d = d->next) != NULL);
  236. return -1;
  237. }
  238. /*
  239. * Decode message and generate answer
  240. */
  241. #define eret(s) do { fprintf (stderr, "%s\n", s); return -1; } while (0)
  242. static int
  243. process_packet(uint8_t * buf)
  244. {
  245. struct dns_head *head;
  246. struct dns_prop *qprop;
  247. struct dns_repl outr;
  248. void *next, *from, *answb;
  249. uint8_t answstr[MAX_NAME_LEN + 1];
  250. int lookup_result, type, len, packet_len;
  251. uint16_t flags;
  252. answstr[0] = '\0';
  253. head = (struct dns_head *)buf;
  254. if (head->nquer == 0)
  255. eret("no queries");
  256. if ((head->flags & 0x8000))
  257. eret("ignoring response packet");
  258. from = (void *)&head[1]; // start of query string
  259. next = answb = from + strlen((char *)&head[1]) + 1 + sizeof(struct dns_prop); // where to append answer block
  260. outr.rlen = 0; // may change later
  261. outr.r = NULL;
  262. outr.flags = 0;
  263. qprop = (struct dns_prop *)(answb - 4);
  264. type = ntohs(qprop->type);
  265. // only let REQ_A and REQ_PTR pass
  266. if (!(type == REQ_A || type == REQ_PTR)) {
  267. goto empty_packet; /* we can't handle the query type */
  268. }
  269. if (ntohs(qprop->class) != 1 /* class INET */ ) {
  270. outr.flags = 4; /* not supported */
  271. goto empty_packet;
  272. }
  273. /* we only support standard queries */
  274. if ((ntohs(head->flags) & 0x7800) != 0)
  275. goto empty_packet;
  276. // We have a standard query
  277. log_message(LOG_FILE, (char *)head);
  278. lookup_result = table_lookup(type, answstr, (uint8_t*)(&head[1]));
  279. if (lookup_result != 0) {
  280. outr.flags = 3 | 0x0400; //name do not exist and auth
  281. goto empty_packet;
  282. }
  283. if (type == REQ_A) { // return an address
  284. struct in_addr a;
  285. if (!inet_aton((char*)answstr, &a)) {//dotted dec to long conv
  286. outr.flags = 1; /* Frmt err */
  287. goto empty_packet;
  288. }
  289. memcpy(answstr, &a.s_addr, 4); // save before a disappears
  290. outr.rlen = 4; // uint32_t IP
  291. }
  292. else
  293. outr.rlen = strlen((char *)answstr) + 1; // a host name
  294. outr.r = answstr; // 32 bit ip or a host name
  295. outr.flags |= 0x0400; /* authority-bit */
  296. // we have an answer
  297. head->nansw = htons(1);
  298. // copy query block to answer block
  299. len = answb - from;
  300. memcpy(answb, from, len);
  301. next += len;
  302. // and append answer rr
  303. *(uint32_t *) next = htonl(ttl);
  304. next += 4;
  305. *(uint16_t *) next = htons(outr.rlen);
  306. next += 2;
  307. memcpy(next, (void *)answstr, outr.rlen);
  308. next += outr.rlen;
  309. empty_packet:
  310. flags = ntohs(head->flags);
  311. // clear rcode and RA, set responsebit and our new flags
  312. flags |= (outr.flags & 0xff80) | 0x8000;
  313. head->flags = htons(flags);
  314. head->nauth = head->nadd = htons(0);
  315. head->nquer = htons(1);
  316. packet_len = next - (void *)buf;
  317. return packet_len;
  318. }
  319. /*
  320. * Exit on signal
  321. */
  322. static void
  323. interrupt(int x)
  324. {
  325. unlink(LOCK_FILE);
  326. write(2, "interrupt exiting\n", 18);
  327. exit(2);
  328. }
  329. #define is_daemon() (flags&16)
  330. #define is_verbose() (flags&32)
  331. //#define DEBUG 1
  332. int dnsd_main(int argc, char **argv)
  333. {
  334. int udps;
  335. uint16_t port = 53;
  336. uint8_t buf[MAX_PACK_LEN];
  337. unsigned long flags = 0;
  338. char *listen_interface = "0.0.0.0";
  339. char *sttl=NULL, *sport=NULL;
  340. if(argc > 1)
  341. flags = bb_getopt_ulflags(argc, argv, "i:c:t:p:dv", &listen_interface, &fileconf, &sttl, &sport);
  342. if(sttl)
  343. if(!(ttl = atol(sttl)))
  344. bb_show_usage();
  345. if(sport)
  346. if(!(port = atol(sport)))
  347. bb_show_usage();
  348. if(is_verbose()) {
  349. fprintf(stderr,"listen_interface: %s\n", listen_interface);
  350. fprintf(stderr,"ttl: %d, port: %d\n", ttl, port);
  351. fprintf(stderr,"fileconf: %s\n", fileconf);
  352. }
  353. if(is_daemon())
  354. #if defined(__uClinux__)
  355. /* reexec for vfork() do continue parent */
  356. vfork_daemon_rexec(1, 0, argc, argv, "-d");
  357. #else /* uClinux */
  358. if (daemon(1, 0) < 0) {
  359. bb_perror_msg_and_die("daemon");
  360. }
  361. #endif /* uClinuvx */
  362. dnsentryinit(is_verbose());
  363. signal(SIGINT, interrupt);
  364. signal(SIGPIPE, SIG_IGN);
  365. signal(SIGHUP, SIG_IGN);
  366. #ifdef SIGTSTP
  367. signal(SIGTSTP, SIG_IGN);
  368. #endif
  369. #ifdef SIGURG
  370. signal(SIGURG, SIG_IGN);
  371. #endif
  372. udps = listen_socket(listen_interface, port);
  373. if (udps < 0)
  374. exit(1);
  375. while (1) {
  376. fd_set fdset;
  377. int r;
  378. FD_ZERO(&fdset);
  379. FD_SET(udps, &fdset);
  380. // Block until a message arrives
  381. if((r = select(udps + 1, &fdset, NULL, NULL, NULL)) < 0)
  382. bb_perror_msg_and_die("select error");
  383. else
  384. if(r == 0)
  385. bb_perror_msg_and_die("select spurious return");
  386. /* Can this test ever be false? */
  387. if (FD_ISSET(udps, &fdset)) {
  388. struct sockaddr_in from;
  389. int fromlen = sizeof(from);
  390. r = recvfrom(udps, buf, sizeof(buf), 0,
  391. (struct sockaddr *)&from,
  392. (void *)&fromlen);
  393. if(is_verbose())
  394. fprintf(stderr, "\n--- Got UDP ");
  395. log_message(LOG_FILE, "\n--- Got UDP ");
  396. if (r < 12 || r > 512) {
  397. bb_error_msg("invalid packet size");
  398. continue;
  399. }
  400. if (r > 0) {
  401. r = process_packet(buf);
  402. if (r > 0)
  403. sendto(udps, buf,
  404. r, 0, (struct sockaddr *)&from,
  405. fromlen);
  406. }
  407. } // end if
  408. } // end while
  409. return 0;
  410. }