00001
00002
00003
00004
00005
00006
00007
00008
00009 #include "copyright.h"
00010 #include "config.h"
00011
00012 #include <stdio.h>
00013 #include <stdlib.h>
00014 #include <unistd.h>
00015 #include <string.h>
00016 #include <sys/types.h>
00017 #include <sys/stat.h>
00018 #include <sys/file.h>
00019 #include <sys/ioctl.h>
00020 #include <sys/wait.h>
00021 #include <signal.h>
00022 #include <errno.h>
00023 #include "externs.h"
00024 #include "debug.h"
00025
00026 static struct dns_query_state_t {
00027 DESC *desc;
00028 struct event ev;
00029 struct dns_query_state_t *next;
00030 int pid;
00031 int fd;
00032 } *running = NULL;
00033
00034 static int running_queries = 0;
00035 static int dnschild_state = 0;
00036
00037 static struct timeval query_timeout = { 60, 0 };
00038
00039 static void dnschild_finish(int fd, short event, void *arg);
00040
00041 int dnschild_init()
00042 {
00043 dprintk("dnschild initialized.");
00044 dnschild_state = 1;
00045 return 1;
00046 }
00047
00048 void *dnschild_request(DESC * d)
00049 {
00050 int fds[2];
00051 struct dns_query_state_t *dqst;
00052 char address[1024];
00053 char outbuffer[255];
00054 int length;
00055 int result;
00056
00057 if(!dnschild_state) {
00058 dprintk("bailing query, dnschild is shut down.");
00059 return 0;
00060 }
00061
00062 dqst = malloc(sizeof(struct dns_query_state_t));
00063 memset(dqst, 0, sizeof(struct dns_query_state_t));
00064
00065 dqst->desc = d;
00066
00067 if(pipe(fds) < 0) {
00068 log_perror("DNS", "ERR", NULL, "pipe");
00069 }
00070
00071 event_set(&dqst->ev, fds[0], EV_TIMEOUT | EV_READ, dnschild_finish, dqst);
00072 event_add(&dqst->ev, &query_timeout);
00073
00074 dqst->pid = fork();
00075 if(dqst->pid == 0) {
00076 close(fds[0]);
00077
00078 unbind_signals();
00079 memset(address, 0, 1023);
00080 if((result=getnameinfo((struct sockaddr *) &d->saddr, d->saddr_len,
00081 address, 1023, NULL, 0, NI_NAMEREQD))) {
00082 length = snprintf(outbuffer, 255, "0%s/%s", gai_strerror(result), strerror(errno));
00083 outbuffer[length++] = '\0';
00084 write(fds[1], outbuffer, length);
00085 } else {
00086 length = snprintf(outbuffer, 255, "1%s", address);
00087 outbuffer[length++] = '\0';
00088 write(fds[1], outbuffer, length);
00089 }
00090 close(fds[1]);
00091 exit(0);
00092
00093 }
00094 dqst->fd = fds[0];
00095 close(fds[1]);
00096 dqst->next = running;
00097 running = dqst;
00098 running_queries++;
00099 return (void *) dqst;
00100 }
00101
00102 void dnschild_destruct()
00103 {
00104 struct dns_query_state_t *dqst;
00105 dprintk("dnschild expiring queries and shutting down.");
00106 dnschild_state = 0;
00107 while (running) {
00108 dqst = running;
00109 dprintk("dnschild query for %s aborting early.", dqst->desc->addr);
00110 if(event_pending(&dqst->ev, EV_READ, NULL))
00111 event_del(&dqst->ev);
00112 close(dqst->fd);
00113 dqst->desc->outstanding_dnschild_query = NULL;
00114 running = running->next;
00115 free(dqst);
00116 }
00117 }
00118
00119 void dnschild_kill(void *arg)
00120 {
00121 struct dns_query_state_t *dqst = (struct dns_query_state_t *) arg, *iter;
00122
00123 dprintk("dnschild query for %s aborting early.", dqst->desc->addr);
00124
00125 iter = running;
00126 if(running == dqst) {
00127 running = dqst->next;
00128 } else {
00129 while (iter) {
00130 if(iter->next == dqst) {
00131 iter->next = dqst->next;
00132 break;
00133 }
00134 iter = iter->next;
00135 }
00136 }
00137
00138 if(event_pending(&dqst->ev, EV_READ, NULL))
00139 event_del(&dqst->ev);
00140 dqst->desc->outstanding_dnschild_query = NULL;
00141 close(dqst->fd);
00142 free(dqst);
00143 }
00144
00145 static void dnschild_finish(int fd, short event, void *arg)
00146 {
00147 char buffer[2048];
00148 struct dns_query_state_t *dqst = (struct dns_query_state_t *) arg, *iter;
00149
00150 iter = running;
00151 if(running == dqst) {
00152 running = dqst->next;
00153 } else {
00154 while (iter) {
00155 if(iter->next == dqst) {
00156 iter->next = dqst->next;
00157 break;
00158 }
00159 iter = iter->next;
00160 }
00161 }
00162
00163 dqst->desc->outstanding_dnschild_query = NULL;
00164
00165 if(event & EV_TIMEOUT || !dnschild_state) {
00166 kill(dqst->pid, SIGTERM);
00167 log_perror("DNS", "ERR", NULL, "dnschild failed to finish.");
00168 close(fd);
00169 free(dqst);
00170 return;
00171 }
00172
00173 read(fd, buffer, 2048);
00174
00175 if(buffer[0] == '0') {
00176 dprintk("dnschild failed with error: %s", buffer + 1);
00177 close(fd);
00178 free(dqst);
00179 return;
00180 }
00181
00182 strncpy(dqst->desc->addr, buffer + 1, sizeof(dqst->desc->addr) - 1);
00183 dprintk("dnschild resolved %s correctly.", buffer + 1);
00184 close(fd);
00185 free(dqst);
00186 return;
00187 }