diff options
-rw-r--r-- | networking/dnsd.c | 475 |
1 files changed, 238 insertions, 237 deletions
diff --git a/networking/dnsd.c b/networking/dnsd.c index 77d37d996..433b12443 100644 --- a/networking/dnsd.c +++ b/networking/dnsd.c @@ -7,10 +7,10 @@ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. * * Odd Arild Olsen started out with the sheerdns [1] of Paul Sheer and rewrote - * it into a shape which I believe is both easier to understand and maintain. - * I also reused the input buffer for output and removed services he did not + * it into a shape which I believe is both easier to understand and maintain. + * I also reused the input buffer for output and removed services he did not * need. [1] http://threading.2038bug.com/sheerdns/ - * + * * Some bugfix and minor changes was applied by Roberto A. Foglietta who made * the first porting of oao' scdns to busybox also. */ @@ -19,6 +19,7 @@ #include <string.h> #include <signal.h> #include <arpa/inet.h> +#include <sys/socket.h> #include <ctype.h> #include "libbb.h" @@ -34,8 +35,8 @@ static const int MAX_NAME_LEN = (IP_STRING_LEN + 13); /* Cannot get bigger packets than 512 per RFC1035 In practice this can be set considerably smaller: - Length of response packet is header (12B) + 2*type(4B) + 2*class(4B) + - ttl(4B) + rlen(2B) + r (MAX_NAME_LEN =21B) + + Length of response packet is header (12B) + 2*type(4B) + 2*class(4B) + + ttl(4B) + rlen(2B) + r (MAX_NAME_LEN =21B) + 2*querystring (2 MAX_NAME_LEN= 42B), all together 90 Byte */ static const int MAX_PACK_LEN = 512 + 1; @@ -45,28 +46,28 @@ static const int MAX_PACK_LEN = 512 + 1; static const int REQ_A = 1; static const int REQ_PTR = 12; -struct dns_repl { // resource record, add 0 or 1 to accepted dns_msg in resp - uint16_t rlen; - uint8_t *r; // resource - uint16_t flags; +struct dns_repl { // resource record, add 0 or 1 to accepted dns_msg in resp + uint16_t rlen; + uint8_t *r; // resource + uint16_t flags; }; -struct dns_head { // the message from client and first part of response mag - uint16_t id; - uint16_t flags; - uint16_t nquer; // accepts 0 - uint16_t nansw; // 1 in response - uint16_t nauth; // 0 - uint16_t nadd; // 0 +struct dns_head { // the message from client and first part of response mag + uint16_t id; + uint16_t flags; + uint16_t nquer; // accepts 0 + uint16_t nansw; // 1 in response + uint16_t nauth; // 0 + uint16_t nadd; // 0 }; struct dns_prop { - uint16_t type; - uint16_t class; + uint16_t type; + uint16_t class; }; -struct dns_entry { // element of known name, ip address and reversed ip address - struct dns_entry *next; - char ip[IP_STRING_LEN]; // dotted decimal IP - char rip[IP_STRING_LEN]; // length decimal reversed IP +struct dns_entry { // element of known name, ip address and reversed ip address + struct dns_entry *next; + char ip[IP_STRING_LEN]; // dotted decimal IP + char rip[IP_STRING_LEN]; // length decimal reversed IP char name[MAX_HOST_LEN]; }; @@ -75,15 +76,15 @@ static int daemonmode = 0; static uint32_t ttl = DEFAULT_TTL; /* - * Convert host name from C-string to dns length/string. + * Convert host name from C-string to dns length/string. */ static void convname(char *a, uint8_t *q) { - int i = (q[0] == '.')?0:1; + int i = (q[0] == '.') ? 0 : 1; for(; i < MAX_HOST_LEN-1 && *q; i++, q++) a[i] = tolower(*q); - a[0] = i - 1; + a[0] = i - 1; a[i] = 0; } @@ -93,7 +94,7 @@ convname(char *a, uint8_t *q) static void undot(uint8_t * rip) { - int i=0, s=0; + int i = 0, s = 0; while(rip[i]) i++; for(--i; i >= 0; i--) { if(rip[i] == '.') { @@ -103,23 +104,23 @@ undot(uint8_t * rip) } } -/* +/* * Append message to log file */ static void log_message(char *filename, char *message) { - FILE *logfile; - if (!daemonmode) - return; - logfile = fopen(filename, "a"); - if (!logfile) - return; - fprintf(logfile, "%s\n", message); - fclose(logfile); + FILE *logfile; + if (!daemonmode) + return; + logfile = fopen(filename, "a"); + if (!logfile) + return; + fprintf(logfile, "%s\n", message); + fclose(logfile); } -/* +/* * Read one line of hostname/IP from file * Returns 0 for each valid entry read, -1 at EOF * Assumes all host names are lower case only @@ -132,14 +133,14 @@ static int getfileentry(FILE * fp, struct dns_entry *s, int verb) { unsigned int a,b,c,d; - char *r, *name; + char *r, *name; restart: if(!(r = bb_get_line_from_file(fp))) return -1; while(*r == ' ' || *r == '\t') { r++; - if(!*r || *r == '#' || *r == '\n') + if(!*r || *r == '#' || *r == '\n') goto restart; /* skipping empty/blank and commented lines */ } name = r; @@ -153,8 +154,8 @@ restart: sprintf(s->rip,".%u.%u.%u.%u",d,c,b,a); undot((uint8_t*)s->rip); convname(s->name,(uint8_t*)name); - - if(verb) + + if(verb) fprintf(stderr,"\tname:%s, ip:%s\n",&(s->name[1]),s->ip); return 0; /* warningkiller */ @@ -166,28 +167,28 @@ restart: static void dnsentryinit(int verb) { - FILE *fp; - struct dns_entry *m, *prev; - prev = dnsentry = NULL; + FILE *fp; + struct dns_entry *m, *prev; + prev = dnsentry = NULL; - if(!(fp = fopen(fileconf, "r"))) + if(!(fp = fopen(fileconf, "r"))) bb_perror_msg_and_die("open %s",fileconf); - while (1) { - if(!(m = (struct dns_entry *)malloc(sizeof(struct dns_entry)))) + while (1) { + if(!(m = (struct dns_entry *)malloc(sizeof(struct dns_entry)))) bb_perror_msg_and_die("malloc dns_entry"); - m->next = NULL; - if (getfileentry(fp, m, verb)) - break; - - if (prev == NULL) - dnsentry = m; - else - prev->next = m; - prev = m; - } - fclose(fp); + m->next = NULL; + if (getfileentry(fp, m, verb)) + break; + + if (prev == NULL) + dnsentry = m; + else + prev->next = m; + prev = m; + } + fclose(fp); } @@ -197,48 +198,48 @@ dnsentryinit(int verb) static int listen_socket(char *iface_addr, int listen_port) { - struct sockaddr_in a; - char msg[100]; - int s; - int yes = 1; - if ((s = socket(PF_INET, SOCK_DGRAM, 0)) < 0) - bb_perror_msg_and_die("socket() failed"); + struct sockaddr_in a; + char msg[100]; + int s; + int yes = 1; + if ((s = socket(PF_INET, SOCK_DGRAM, 0)) < 0) + bb_perror_msg_and_die("socket() failed"); #ifdef SO_REUSEADDR - if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *)&yes, sizeof(yes)) < 0) - bb_perror_msg_and_die("setsockopt() failed"); + if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *)&yes, sizeof(yes)) < 0) + bb_perror_msg_and_die("setsockopt() failed"); #endif - memset(&a, 0, sizeof(a)); - a.sin_port = htons(listen_port); - a.sin_family = AF_INET; - if (!inet_aton(iface_addr, &a.sin_addr)) - bb_perror_msg_and_die("bad iface address"); - if (bind(s, (struct sockaddr *)&a, sizeof(a)) < 0) - bb_perror_msg_and_die("bind() failed"); - listen(s, 50); - sprintf(msg, "accepting UDP packets on addr:port %s:%d\n", - iface_addr, (int)listen_port); - log_message(LOG_FILE, msg); - return s; + memset(&a, 0, sizeof(a)); + a.sin_port = htons(listen_port); + a.sin_family = AF_INET; + if (!inet_aton(iface_addr, &a.sin_addr)) + bb_perror_msg_and_die("bad iface address"); + if (bind(s, (struct sockaddr *)&a, sizeof(a)) < 0) + bb_perror_msg_and_die("bind() failed"); + listen(s, 50); + sprintf(msg, "accepting UDP packets on addr:port %s:%d\n", + iface_addr, (int)listen_port); + log_message(LOG_FILE, msg); + return s; } /* - * Look query up in dns records and return answer if found + * Look query up in dns records and return answer if found * qs is the query string, first byte the string length - */ + */ static int table_lookup(uint16_t type, uint8_t * as, uint8_t * qs) { int i; - struct dns_entry *d=dnsentry; + struct dns_entry *d=dnsentry; - do { + do { #ifdef DEBUG - char *p,*q; + char *p,*q; q = (char *)&(qs[1]); p = &(d->name[1]); - fprintf(stderr, "\ntest: %d <%s> <%s> %d", strlen(p), p, q, strlen(q)); + fprintf(stderr, "\ntest: %d <%s> <%s> %d", strlen(p), p, q, strlen(q)); #endif - if (type == REQ_A) { /* search by host name */ + if (type == REQ_A) { /* search by host name */ for(i = 1; i <= (int)(d->name[0]); i++) if(tolower(qs[i]) != d->name[i]) continue; @@ -250,126 +251,126 @@ table_lookup(uint16_t type, uint8_t * as, uint8_t * qs) fprintf(stderr, " %s ", as); #endif return 0; - } - else if (type == REQ_PTR) { /* search by IP-address */ + } + else if (type == REQ_PTR) { /* search by IP-address */ if (!strncmp((char*)&d->rip[1], (char*)&qs[1], strlen(d->rip)-1)) { - strcpy((char *)as, d->name); - return 0; - } - } - } while ((d = d->next) != NULL); - return -1; + strcpy((char *)as, d->name); + return 0; + } + } + } while ((d = d->next) != NULL); + return -1; } -/* +/* * Decode message and generate answer */ -#define eret(s) do { fprintf (stderr, "%s\n", s); return -1; } while (0) +#define eret(s) do { fprintf (stderr, "%s\n", s); return -1; } while (0) static int process_packet(uint8_t * buf) { - struct dns_head *head; - struct dns_prop *qprop; - struct dns_repl outr; - void *next, *from, *answb; - - uint8_t answstr[MAX_NAME_LEN + 1]; - int lookup_result, type, len, packet_len; - uint16_t flags; - - answstr[0] = '\0'; - - head = (struct dns_head *)buf; - if (head->nquer == 0) - eret("no queries"); - - if ((head->flags & 0x8000)) - eret("ignoring response packet"); - - from = (void *)&head[1]; // start of query string - next = answb = from + strlen((char *)&head[1]) + 1 + sizeof(struct dns_prop); // where to append answer block - - outr.rlen = 0; // may change later - outr.r = NULL; - outr.flags = 0; - - qprop = (struct dns_prop *)(answb - 4); - type = ntohs(qprop->type); - - // only let REQ_A and REQ_PTR pass - if (!(type == REQ_A || type == REQ_PTR)) { - goto empty_packet; /* we can't handle the query type */ - } - - if (ntohs(qprop->class) != 1 /* class INET */ ) { - outr.flags = 4; /* not supported */ - goto empty_packet; - } - /* we only support standard queries */ - - if ((ntohs(head->flags) & 0x7800) != 0) - goto empty_packet; - - // We have a standard query - - log_message(LOG_FILE, (char *)head); - lookup_result = table_lookup(type, answstr, (uint8_t*)(&head[1])); - if (lookup_result != 0) { - outr.flags = 3 | 0x0400; //name do not exist and auth - goto empty_packet; - } - if (type == REQ_A) { // return an address - struct in_addr a; - if (!inet_aton((char*)answstr, &a)) {//dotted dec to long conv - outr.flags = 1; /* Frmt err */ - goto empty_packet; - } - memcpy(answstr, &a.s_addr, 4); // save before a disappears - outr.rlen = 4; // uint32_t IP - } - else - outr.rlen = strlen((char *)answstr) + 1; // a host name - outr.r = answstr; // 32 bit ip or a host name - outr.flags |= 0x0400; /* authority-bit */ - // we have an answer - head->nansw = htons(1); - - // copy query block to answer block - len = answb - from; - memcpy(answb, from, len); - next += len; - - // and append answer rr - *(uint32_t *) next = htonl(ttl); - next += 4; - *(uint16_t *) next = htons(outr.rlen); - next += 2; - memcpy(next, (void *)answstr, outr.rlen); - next += outr.rlen; + struct dns_head *head; + struct dns_prop *qprop; + struct dns_repl outr; + void *next, *from, *answb; + + uint8_t answstr[MAX_NAME_LEN + 1]; + int lookup_result, type, len, packet_len; + uint16_t flags; + + answstr[0] = '\0'; + + head = (struct dns_head *)buf; + if (head->nquer == 0) + eret("no queries"); + + if ((head->flags & 0x8000)) + eret("ignoring response packet"); + + from = (void *)&head[1]; // start of query string + next = answb = from + strlen((char *)&head[1]) + 1 + sizeof(struct dns_prop); // where to append answer block + + outr.rlen = 0; // may change later + outr.r = NULL; + outr.flags = 0; + + qprop = (struct dns_prop *)(answb - 4); + type = ntohs(qprop->type); + + // only let REQ_A and REQ_PTR pass + if (!(type == REQ_A || type == REQ_PTR)) { + goto empty_packet; /* we can't handle the query type */ + } + + if (ntohs(qprop->class) != 1 /* class INET */ ) { + outr.flags = 4; /* not supported */ + goto empty_packet; + } + /* we only support standard queries */ + + if ((ntohs(head->flags) & 0x7800) != 0) + goto empty_packet; + + // We have a standard query + + log_message(LOG_FILE, (char *)head); + lookup_result = table_lookup(type, answstr, (uint8_t*)(&head[1])); + if (lookup_result != 0) { + outr.flags = 3 | 0x0400; //name do not exist and auth + goto empty_packet; + } + if (type == REQ_A) { // return an address + struct in_addr a; + if (!inet_aton((char*)answstr, &a)) {//dotted dec to long conv + outr.flags = 1; /* Frmt err */ + goto empty_packet; + } + memcpy(answstr, &a.s_addr, 4); // save before a disappears + outr.rlen = 4; // uint32_t IP + } + else + outr.rlen = strlen((char *)answstr) + 1; // a host name + outr.r = answstr; // 32 bit ip or a host name + outr.flags |= 0x0400; /* authority-bit */ + // we have an answer + head->nansw = htons(1); + + // copy query block to answer block + len = answb - from; + memcpy(answb, from, len); + next += len; + + // and append answer rr + *(uint32_t *) next = htonl(ttl); + next += 4; + *(uint16_t *) next = htons(outr.rlen); + next += 2; + memcpy(next, (void *)answstr, outr.rlen); + next += outr.rlen; empty_packet: - flags = ntohs(head->flags); - // clear rcode and RA, set responsebit and our new flags - flags |= (outr.flags & 0xff80) | 0x8000; - head->flags = htons(flags); - head->nauth = head->nadd = htons(0); - head->nquer = htons(1); + flags = ntohs(head->flags); + // clear rcode and RA, set responsebit and our new flags + flags |= (outr.flags & 0xff80) | 0x8000; + head->flags = htons(flags); + head->nauth = head->nadd = htons(0); + head->nquer = htons(1); - packet_len = next - (void *)buf; - return packet_len; + packet_len = next - (void *)buf; + return packet_len; } -/* +/* * Exit on signal */ static void interrupt(int x) { - unlink(LOCK_FILE); - write(2, "interrupt exiting\n", 18); - exit(2); + unlink(LOCK_FILE); + write(2, "interrupt exiting\n", 18); + exit(2); } #define is_daemon() (flags&16) @@ -378,14 +379,14 @@ interrupt(int x) int dnsd_main(int argc, char **argv) { - int i, udps; - uint16_t port = 53; - uint8_t buf[MAX_PACK_LEN]; + int udps; + uint16_t port = 53; + uint8_t buf[MAX_PACK_LEN]; unsigned long flags = 0; - char *listen_interface = "0.0.0.0"; + char *listen_interface = "0.0.0.0"; char *sttl=NULL, *sport=NULL; - if(argc > 1) + if(argc > 1) flags = bb_getopt_ulflags(argc, argv, "i:c:t:p:dv", &listen_interface, &fileconf, &sttl, &sport); if(sttl) if(!(ttl = atol(sttl))) @@ -393,14 +394,14 @@ int dnsd_main(int argc, char **argv) if(sport) if(!(port = atol(sport))) bb_show_usage(); - + if(is_verbose()) { fprintf(stderr,"listen_interface: %s\n", listen_interface); fprintf(stderr,"ttl: %d, port: %d\n", ttl, port); fprintf(stderr,"fileconf: %s\n", fileconf); } - - if(is_daemon()) + + if(is_daemon()) #if defined(__uClinux__) /* reexec for vfork() do continue parent */ vfork_daemon_rexec(1, 0, argc, argv, "-d"); @@ -409,60 +410,60 @@ int dnsd_main(int argc, char **argv) bb_perror_msg_and_die("daemon"); } #endif /* uClinuvx */ - - dnsentryinit(is_verbose()); - signal(SIGINT, interrupt); - signal(SIGPIPE, SIG_IGN); - signal(SIGHUP, SIG_IGN); + dnsentryinit(is_verbose()); + + signal(SIGINT, interrupt); + signal(SIGPIPE, SIG_IGN); + signal(SIGHUP, SIG_IGN); #ifdef SIGTSTP - signal(SIGTSTP, SIG_IGN); + signal(SIGTSTP, SIG_IGN); #endif #ifdef SIGURG - signal(SIGURG, SIG_IGN); + signal(SIGURG, SIG_IGN); #endif - udps = listen_socket(listen_interface, port); - if (udps < 0) - exit(1); + udps = listen_socket(listen_interface, port); + if (udps < 0) + exit(1); - while (1) { - fd_set fdset; - int r; + while (1) { + fd_set fdset; + int r; - FD_ZERO(&fdset); - FD_SET(udps, &fdset); - // Block until a message arrives - if((r = select(udps + 1, &fdset, NULL, NULL, NULL)) < 0) + FD_ZERO(&fdset); + FD_SET(udps, &fdset); + // Block until a message arrives + if((r = select(udps + 1, &fdset, NULL, NULL, NULL)) < 0) bb_perror_msg_and_die("select error"); - else - if(r == 0) - bb_perror_msg_and_die("select spurious return"); - - /* Can this test ever be false? */ - if (FD_ISSET(udps, &fdset)) { - struct sockaddr_in from; - int fromlen = sizeof(from); - r = recvfrom(udps, buf, sizeof(buf), 0, - (struct sockaddr *)&from, - (void *)&fromlen); - if(is_verbose()) - fprintf(stderr, "\n--- Got UDP "); - log_message(LOG_FILE, "\n--- Got UDP "); - - if (r < 12 || r > 512) { - bb_error_msg("invalid packet size"); - continue; - } - if (r > 0) { - r = process_packet(buf); - if (r > 0) - sendto(udps, buf, - r, 0, (struct sockaddr *)&from, - fromlen); - } - } // end if - } // end while + else + if(r == 0) + bb_perror_msg_and_die("select spurious return"); + + /* Can this test ever be false? */ + if (FD_ISSET(udps, &fdset)) { + struct sockaddr_in from; + int fromlen = sizeof(from); + r = recvfrom(udps, buf, sizeof(buf), 0, + (struct sockaddr *)&from, + (void *)&fromlen); + if(is_verbose()) + fprintf(stderr, "\n--- Got UDP "); + log_message(LOG_FILE, "\n--- Got UDP "); + + if (r < 12 || r > 512) { + bb_error_msg("invalid packet size"); + continue; + } + if (r > 0) { + r = process_packet(buf); + if (r > 0) + sendto(udps, buf, + r, 0, (struct sockaddr *)&from, + fromlen); + } + } // end if + } // end while return 0; } |