📄 dnsrv.c
字号:
l = pmalloco(p->p, sizeof(_dns_packet_list)); l->packet = p; l->stamp = time(NULL); xhash_put(d->packet_table, p->host, l); req = xmlnode_new_tag_pool(p->p,"host"); xmlnode_insert_cdata(req,p->host,-1); reqs = xmlnode2str(req); log_debug2(ZONE, LOGT_IO, "dnsrv: Transmitting lookup request: %s", reqs); pth_write(d->out, reqs, strlen(reqs));}result dnsrv_deliver(instance i, dpacket p, void* args){ dns_io di = (dns_io)args; xmlnode c; int timeout = di->cache_timeout; char *ip; jid to; /* if we get a route packet, it has to be to *us* and have the child as the real packet */ if(p->type == p_ROUTE) { if(j_strcmp(p->host,i->id) != 0 || (to = jid_new(p->p,xmlnode_get_attrib(xmlnode_get_firstchild(p->x),"to"))) == NULL) return r_ERR; p->x=xmlnode_get_firstchild(p->x); p->id = to; p->host = to->server; } /* Ensure this packet doesn't already have an IP */ if(xmlnode_get_attrib(p->x, "ip") || xmlnode_get_attrib(p->x, "iperror")) { log_notice(p->host, "dropping looping dns lookup request: %s", xmlnode2str(p->x)); xmlnode_free(p->x); return r_DONE; } /* try the cache first */ if((c = xhash_get(di->cache_table, p->host)) != NULL) { /* if there's no IP, cached failed lookup, time those out 10 times faster! (weird, I know, *shrug*) */ if((ip = xmlnode_get_attrib(c,"ip")) == NULL) timeout = timeout / 10; if((time(NULL) - *(time_t*)xmlnode_get_vattrib(c,"t")) > timeout) { /* timed out of the cache, lookup again */ xhash_zap(di->cache_table,p->host); xmlnode_free(c); }else{ /* yay, send back right from the cache */ dnsrv_resend(p->x, ip, xmlnode_get_attrib(c,"to")); return r_DONE; } } dnsrv_lookup(di, p); return r_DONE;}void dnsrv_process_xstream_io(int type, xmlnode x, void* arg){ dns_io di = (dns_io)arg; char* hostname = NULL; char* ipaddr = NULL; char* resendhost = NULL; dns_packet_list head = NULL; dns_packet_list heado = NULL; time_t *ttmp; /* Node Format: <host ip="201.83.28.2">foo.org</host> */ if (type == XSTREAM_NODE) { log_debug2(ZONE, LOGT_IO, "incoming resolution: %s",xmlnode2str(x)); hostname = xmlnode_get_data(x); /* whatever the response was, let's cache it */ xmlnode_free((xmlnode)xhash_get(di->cache_table,hostname)); /* free any old cache, shouldn't ever be any */ ttmp = pmalloc(xmlnode_pool(x),sizeof(time_t)); time(ttmp); xmlnode_put_vattrib(x,"t",(void*)ttmp); xhash_put(di->cache_table,hostname,(void*)x); /* Get the hostname and look it up in the hashtable */ head = xhash_get(di->packet_table, hostname); /* Process the packet list */ if (head != NULL) { ipaddr = xmlnode_get_attrib(x, "ip"); resendhost = xmlnode_get_attrib(x, "to"); /* Remove the list from the hashtable */ xhash_zap(di->packet_table, hostname); /* Walk the list and insert IPs */ while(head != NULL) { heado = head; /* Move to next.. */ head = head->next; /* Deliver the packet */ dnsrv_resend(heado->packet->x, ipaddr, resendhost); } } /* Host name was not found, something is _TERRIBLY_ wrong! */ else log_debug2(ZONE, LOGT_IO, "Resolved unknown host/ip request: %s\n", xmlnode2str(x)); return; /* we cached x above, so we don't free it below :) */ } xmlnode_free(x);} void* dnsrv_process_io(void* threadarg){ /* Get DNS IO info */ dns_io di = (dns_io)threadarg; int readlen = 0; char readbuf[1024]; xstream xs = NULL; /* Allocate an xstream for talking to the process */ xs = xstream_new(di->mempool, dnsrv_process_xstream_io, di); /* Loop forever */ while (1) { /* Hostname lookup completed from coprocess */ readlen = pth_read(di->in, readbuf, sizeof(readbuf)); if (readlen <= 0) { log_debug2(ZONE, LOGT_IO|LOGT_STRANGE, "dnsrv: Read error on coprocess: %d %s",errno,strerror(errno)); break; } if (xstream_eat(xs, readbuf, readlen) > XSTREAM_NODE) break; } /* Cleanup */ close(di->in); close(di->out); di->out = 0; waitpid(di->pid, &readlen, WNOHANG); /* reap any dead children */ /* silly to restart it if it died cuz we're shutting down, pretty hackish to do it this way tho... must be hackish when the comment is longer than the code itself, but I'm rambling */ if(jabberd__signalflag == SIGTERM || jabberd__signalflag == SIGINT) return NULL; log_debug2(ZONE, LOGT_INIT, "child being restarted..."); /* Fork out resolver function/process */ di->pid = dnsrv_fork_and_capture(dnsrv_child_main, di); /* Start new IO thread */ pth_spawn(PTH_ATTR_DEFAULT, dnsrv_process_io, (void*)di); return NULL;}void *dnsrv_thread(void *arg){ dns_io di=(dns_io)arg; /* Fork out resolver function/process */ di->pid = dnsrv_fork_and_capture(dnsrv_child_main, di); return NULL;}/* callback for walking the connecting hash tree */void _dnsrv_beat_packets(xht h, const char *key, void *data, void *arg){ dns_io di = (dns_io)arg; dns_packet_list n, l = (dns_packet_list)data; int now = time(NULL); int reap = 0; /* first, check the head */ if((now - l->stamp) > di->packet_timeout) { log_notice(l->packet->host,"timed out from dnsrv queue"); xhash_zap(di->packet_table,l->packet->host); reap = 1; }else{ while(l->next != NULL) { if((now - l->next->stamp) > di->packet_timeout) { reap = 1; n = l->next; l->next = NULL; /* chop off packets to be killed */ l = n; break; } l = l->next; } } if(reap == 0) return; /* time out individual queue'd packets */ while(l != NULL) { n = l->next; deliver_fail(l->packet,"Hostname Resolution Timeout"); l = n; }}result dnsrv_beat_packets(void *arg){ dns_io di = (dns_io)arg; xhash_walk(di->packet_table,_dnsrv_beat_packets,arg); return r_DONE;}void dnsrv(instance i, xmlnode x){ xdbcache xc = NULL; xmlnode config = NULL; xmlnode iternode = NULL; xmlnode inneriter = NULL; dns_resend_list tmplist = NULL; dns_resend_list_host_list tmphost = NULL; /* Setup a struct to hold dns_io handles */ dns_io di; di = pmalloco(i->p, sizeof(_dns_io)); di->mempool = i->p; /* Load config from xdb */ xc = xdb_cache(i); config = xdb_get(xc, jid_new(xmlnode_pool(x), "config@-internal"), "jabber:config:dnsrv"); /* Build a list of services/resend hosts */ iternode = xmlnode_get_lastchild(config); while (iternode != NULL) { if (j_strcmp("resend", xmlnode_get_name(iternode)) != 0) { iternode = xmlnode_get_prevsibling(iternode); continue; } /* Allocate a new list node */ tmplist = pmalloco(di->mempool, sizeof(_dns_resend_list)); tmplist->service = pstrdup(di->mempool, xmlnode_get_attrib(iternode, "service")); tmplist->weight_sum = 0; /* check for <partial/> childs */ inneriter = xmlnode_get_lastchild(iternode); if (inneriter != NULL) { while (inneriter != NULL) { if (j_strcmp("partial", xmlnode_get_name(inneriter)) != 0) { inneriter = xmlnode_get_prevsibling(inneriter); continue; } /* build the list entry for this host */ tmphost = pmalloco(di->mempool, sizeof(_dns_resend_list_host_list)); tmphost->host = pstrdup(di->mempool, xmlnode_get_data(inneriter)); tmphost->weight = j_atoi(xmlnode_get_attrib(inneriter, "weight"), 1); /* insert this host into the list for this service */ tmphost->next = tmplist->hosts; tmplist->hosts = tmphost; /* update the weight sum for this service */ tmplist->weight_sum += tmphost->weight; /* move to the next child */ inneriter = xmlnode_get_prevsibling(inneriter); } } /* if there were no <partial/> childs we read the CDATA for the <resend/> element (legacy configuration) */ if (tmplist->hosts == NULL) { /* legacy configuration withouth <partial/> childs and only a single destination as direct CDATA */ tmplist->hosts = pmalloco(di->mempool, sizeof(_dns_resend_list_host_list)); tmplist->hosts->host = pstrdup(di->mempool, xmlnode_get_data(iternode)); tmplist->hosts->weight = 1; tmplist->weight_sum = 1; } /* Insert this node into the list of services */ tmplist->next = di->svclist; di->svclist = tmplist; /* Move to next child */ iternode = xmlnode_get_prevsibling(iternode); } log_debug2(ZONE, LOGT_INIT|LOGT_CONFIG, "dnsrv debug: %s\n", xmlnode2str(config)); /* Setup the hash of dns_packet_list */ di->packet_table = xhash_new(j_atoi(xmlnode_get_attrib(config,"queuemax"),101)); pool_cleanup(i->p, (pool_cleaner)xhash_free, di->packet_table); di->packet_timeout = j_atoi(xmlnode_get_attrib(config,"queuetimeout"),60); register_beat(di->packet_timeout, dnsrv_beat_packets, (void *)di); /* Setup the internal hostname cache */ di->cache_table = xhash_new(j_atoi(xmlnode_get_attrib(config,"cachemax"),1999)); pool_cleanup(i->p, (pool_cleaner)xhash_free, di->cache_table); di->cache_timeout = j_atoi(xmlnode_get_attrib(config,"cachetimeout"),3600); /* 1 hour dns cache? XXX would be nice to get the right value from dns! */ xmlnode_free(config); /* spawn a thread that get's forked, and wait for it since it sets up the fd's */ pth_join(pth_spawn(PTH_ATTR_DEFAULT,(void*)dnsrv_thread,(void*)di),NULL); if(di->pid < 0) { log_error(i->id,"dnsrv failed to start, unable to fork and/or create pipes"); return; } /* Start IO thread */ pth_spawn(PTH_ATTR_DEFAULT, dnsrv_process_io, di); /* Register an incoming packet handler */ register_phandler(i, o_DELIVER, dnsrv_deliver, (void*)di);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -