"Fossies" - the Fresh Open Source Software Archive

Member "links-1.03/dns.c" (16 Nov 2011, 7124 Bytes) of archive /linux/www/links-1.03.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "dns.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 2.8_vs_1.03.

    1 #include "links.h"
    2 
    3 #if defined(HAVE_GETHOSTBYNAME_BUG) || !defined(HAVE_GETHOSTBYNAME)
    4 #define EXTERNAL_LOOKUP
    5 #endif
    6 
    7 struct dnsentry {
    8     struct dnsentry *next;
    9     struct dnsentry *prev;
   10     ttime get_time;
   11     ip addr;
   12     unsigned char name[1];
   13 };
   14 
   15 #ifndef THREAD_SAFE_LOOKUP
   16 struct dnsquery *dns_queue = NULL;
   17 #endif
   18 
   19 struct dnsquery {
   20 #ifndef THREAD_SAFE_LOOKUP
   21     struct dnsquery *next_in_queue;
   22 #endif
   23     void (*fn)(void *, int);
   24     void *data;
   25     void (*xfn)(struct dnsquery *, int);
   26     int h;
   27     struct dnsquery **s;
   28     ip *addr;
   29     unsigned char name[1];
   30 };
   31 
   32 struct list_head dns_cache = {&dns_cache, &dns_cache};
   33 
   34 static int get_addr_byte(unsigned char **ptr, unsigned char *res, unsigned char stp)
   35 {
   36     unsigned u = 0;
   37     if (!(**ptr >= '0' && **ptr <= '9')) return -1;
   38     while (**ptr >= '0' && **ptr <= '9') {
   39         u = u * 10 + **ptr - '0';
   40         if (u >= 256) return -1;
   41         (*ptr)++;
   42     }
   43     if (stp != 255 && **ptr != stp) return -1;
   44     (*ptr)++;
   45     *res = u;
   46     return 0;
   47 }
   48 
   49 #ifdef EXTERNAL_LOOKUP
   50 
   51 static int do_external_lookup(unsigned char *name, ip *host)
   52 {
   53     unsigned char buffer[1024];
   54     unsigned char sink[16];
   55     int rd;
   56     int pi[2];
   57     pid_t f;
   58     unsigned char *n;
   59     if (pipe(pi) == -1)
   60         return -1;
   61     f = fork();
   62     if (f == -1) {
   63         close(pi[0]);
   64         close(pi[1]);
   65         return -1;
   66     }
   67     if (!f) {
   68         close(pi[0]);
   69         if (dup2(pi[1], 1) == -1) _exit(1);
   70         if (dup2(pi[1], 2) == -1) _exit(1);
   71         close(pi[1]);
   72         execlp("host", "host", name, NULL);
   73         execl("/usr/sbin/host", "host", name, NULL);
   74         _exit(1);
   75     }
   76     close(pi[1]);
   77     rd = hard_read(pi[0], buffer, sizeof buffer - 1);
   78     if (rd >= 0) buffer[rd] = 0;
   79     if (rd > 0) {
   80         while (hard_read(pi[0], sink, sizeof sink) > 0);
   81     }
   82     close(pi[0]);
   83     /* Don't wait for the process, we already have sigchld handler that
   84      * does cleanup.
   85      * waitpid(f, NULL, 0); */
   86     if (rd < 0) return -1;
   87     /*fprintf(stderr, "query: '%s', result: %s\n", name, buffer);*/
   88     while ((n = strstr(buffer, name))) {
   89         memset(n, '-', strlen(name));
   90     }
   91     for (n = buffer; n < buffer + rd; n++) {
   92         if (*n >= '0' && *n <= '9') {
   93             if (get_addr_byte(&n, ((unsigned char *)host + 0), '.')) goto skip_addr;
   94             if (get_addr_byte(&n, ((unsigned char *)host + 1), '.')) goto skip_addr;
   95             if (get_addr_byte(&n, ((unsigned char *)host + 2), '.')) goto skip_addr;
   96             if (get_addr_byte(&n, ((unsigned char *)host + 3), 255)) goto skip_addr;
   97             return 0;
   98 skip_addr:
   99             if (n >= buffer + rd) break;
  100         }
  101     }
  102     return -1;
  103 }
  104 
  105 #endif
  106 
  107 int do_real_lookup(unsigned char *name, ip *host)
  108 {
  109     unsigned char *n;
  110     struct hostent *hst;
  111     if (!*name) return -1;
  112     for (n = name; *n; n++) if (*n != '.' && (*n < '0' || *n > '9')) goto nogethostbyaddr;
  113     n = name;
  114     if (get_addr_byte(&n, ((unsigned char *)host + 0), '.')) goto skip_addr;
  115     if (get_addr_byte(&n, ((unsigned char *)host + 1), '.')) goto skip_addr;
  116     if (get_addr_byte(&n, ((unsigned char *)host + 2), '.')) goto skip_addr;
  117     if (get_addr_byte(&n, ((unsigned char *)host + 3), 0)) goto skip_addr;
  118     return 0;
  119     skip_addr:
  120 #ifdef HAVE_GETHOSTBYADDR
  121     if (!(hst = gethostbyaddr(name, strlen(name), AF_INET)))
  122 #endif
  123     {
  124         nogethostbyaddr:
  125 #ifdef HAVE_GETHOSTBYNAME
  126         if (!(hst = gethostbyname(name)))
  127 #endif
  128         {
  129 #ifdef EXTERNAL_LOOKUP
  130             return do_external_lookup(name, host);
  131 #endif
  132             return -1;
  133         }
  134     }
  135     memcpy(host, hst->h_addr_list[0], sizeof(ip));
  136     return 0;
  137 }
  138 
  139 void lookup_fn(unsigned char *name, int h)
  140 {
  141     ip host;
  142     if (do_real_lookup(name, &host)) return;
  143     write(h, &host, sizeof(ip));
  144 }
  145 
  146 void end_real_lookup(struct dnsquery *q)
  147 {
  148     int r = 1;
  149     if (!q->addr || read(q->h, q->addr, sizeof(ip)) != sizeof(ip)) goto end;
  150     r = 0;
  151 
  152     end:
  153     set_handlers(q->h, NULL, NULL, NULL, NULL);
  154     close(q->h);
  155     q->xfn(q, r);
  156 }
  157 
  158 void failed_real_lookup(struct dnsquery *q)
  159 {
  160     set_handlers(q->h, NULL, NULL, NULL, NULL);
  161     close(q->h);
  162     q->xfn(q, -1);
  163 }
  164 
  165 int do_lookup(struct dnsquery *q, int force_async)
  166 {
  167     /*debug("starting lookup for %s", q->name);*/
  168 #ifndef NO_ASYNC_LOOKUP
  169     if (!async_lookup && !force_async) {
  170 #endif
  171         int r;
  172 #ifndef NO_ASYNC_LOOKUP
  173         sync_lookup:
  174 #endif
  175         r = do_real_lookup(q->name, q->addr);
  176         q->xfn(q, r);
  177         return 0;
  178 #ifndef NO_ASYNC_LOOKUP
  179     } else {
  180         if ((q->h = start_thread((void (*)(void *, int))lookup_fn, q->name, strlen(q->name) + 1)) == -1) goto sync_lookup;
  181         set_handlers(q->h, (void (*)(void *))end_real_lookup, NULL, (void (*)(void *))failed_real_lookup, q);
  182         return 1;
  183     }
  184 #endif
  185 }
  186 
  187 int do_queued_lookup(struct dnsquery *q)
  188 {
  189 #ifndef THREAD_SAFE_LOOKUP
  190     q->next_in_queue = NULL;
  191     if (!dns_queue) {
  192         dns_queue = q;
  193         /*debug("direct lookup");*/
  194 #endif
  195         return do_lookup(q, 0);
  196 #ifndef THREAD_SAFE_LOOKUP
  197     } else {
  198         /*debug("queuing lookup for %s", q->name);*/
  199         if (dns_queue->next_in_queue) internal("DNS queue corrupted");
  200         dns_queue->next_in_queue = q;
  201         dns_queue = q;
  202         return 1;
  203     }
  204 #endif
  205 }
  206 
  207 int find_in_dns_cache(unsigned char *name, struct dnsentry **dnsentry)
  208 {
  209     struct dnsentry *e;
  210     foreach(e, dns_cache)
  211         if (!strcasecmp(e->name, name)) {
  212             del_from_list(e);
  213             add_to_list(dns_cache, e);
  214             *dnsentry=e;
  215             return 0;
  216         }
  217     return -1;
  218 }
  219 
  220 void end_dns_lookup(struct dnsquery *q, int a)
  221 {
  222     struct dnsentry *dnsentry;
  223     void (*fn)(void *, int);
  224     void *data;
  225     /*debug("end lookup %s", q->name);*/
  226 #ifndef THREAD_SAFE_LOOKUP
  227     if (q->next_in_queue) {
  228         /*debug("processing next in queue: %s", q->next_in_queue->name);*/
  229         do_lookup(q->next_in_queue, 1);
  230     } else dns_queue = NULL;
  231 #endif
  232     if (!q->fn || !q->addr) {
  233         free(q);
  234         return;
  235     }
  236     if (!find_in_dns_cache(q->name, &dnsentry)) {
  237         if (a) {
  238             memcpy(q->addr, &dnsentry->addr, sizeof(ip));
  239             a = 0;
  240             goto e;
  241         }
  242         del_from_list(dnsentry);
  243         mem_free(dnsentry);
  244     }
  245     if (a) goto e;
  246     dnsentry = mem_alloc(sizeof(struct dnsentry) + strlen(q->name) + 1);
  247     strcpy(dnsentry->name, q->name);
  248     memcpy(&dnsentry->addr, q->addr, sizeof(ip));
  249     dnsentry->get_time = get_time();
  250     add_to_list(dns_cache, dnsentry);
  251     e:
  252     if (q->s) *q->s = NULL;
  253     fn = q->fn;
  254     data = q->data;
  255     free(q);
  256     fn(data, a);
  257 }
  258 
  259 int find_host_no_cache(unsigned char *name, ip *addr, void **qp, void (*fn)(void *, int), void *data)
  260 {
  261     struct dnsquery *q;
  262     if (!(q = (struct dnsquery *)malloc(sizeof(struct dnsquery) + strlen(name) + 1))) {
  263         fn(data, -1);
  264         return 0;
  265     }
  266     q->fn = fn;
  267     q->data = data;
  268     q->s = (struct dnsquery **)qp;
  269     q->addr = addr;
  270     strcpy(q->name, name);
  271     if (qp) *(struct dnsquery **) qp = q;
  272     q->xfn = end_dns_lookup;
  273     return do_queued_lookup(q);
  274 }
  275 
  276 int find_host(unsigned char *name, ip *addr, void **qp, void (*fn)(void *, int), void *data)
  277 {
  278     struct dnsentry *dnsentry;
  279     if (qp) *qp = NULL;
  280     if (!find_in_dns_cache(name, &dnsentry)) {
  281         if ((uttime)get_time() - (uttime)dnsentry->get_time > DNS_TIMEOUT) goto timeout;
  282         memcpy(addr, &dnsentry->addr, sizeof(ip));
  283         fn(data, 0);
  284         return 0;
  285     }
  286     timeout:
  287     return find_host_no_cache(name, addr, qp, fn, data);
  288 }
  289 
  290 void kill_dns_request(void **qp)
  291 {
  292     struct dnsquery *q = *qp;
  293     /*set_handlers(q->h, NULL, NULL, NULL, NULL);
  294     close(q->h);
  295     mem_free(q);*/
  296     q->fn = NULL;
  297     q->addr = NULL;
  298     *qp = NULL;
  299 }
  300 
  301 void shrink_dns_cache(int u)
  302 {
  303     struct dnsentry *d, *e;
  304     foreach(d, dns_cache) if (u || (uttime)get_time() - (uttime)d->get_time > DNS_TIMEOUT) {
  305         e = d;
  306         d = d->prev;
  307         del_from_list(e);
  308         mem_free(e);
  309     }
  310 }