📄 dnsrv.c
字号:
/* -------------------------------------------------------------------------- * * License * * The contents of this file are subject to the Jabber Open Source License * Version 1.0 (the "JOSL"). You may not copy or use this file, in either * source code or executable form, except in compliance with the JOSL. You * may obtain a copy of the JOSL at http://www.jabber.org/ or at * http://www.opensource.org/. * * Software distributed under the JOSL is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the JOSL * for the specific language governing rights and limitations under the * JOSL. * * Copyrights * * Portions created by or assigned to Jabber.com, Inc. are * Copyright (c) 1999-2002 Jabber.com, Inc. All Rights Reserved. Contact * information for Jabber.com, Inc. is available at http://www.jabber.com/. * * Portions Copyright (c) 1998-1999 Jeremie Miller. * * Acknowledgements * * Special thanks to the Jabber Open Source Contributors for their * suggestions and support of Jabber. * * Alternatively, the contents of this file may be used under the terms of the * GNU General Public License Version 2 or later (the "GPL"), in which case * the provisions of the GPL are applicable instead of those above. If you * wish to allow use of your version of this file only under the terms of the * GPL and not to allow others to use your version of this file under the JOSL, * indicate your decision by deleting the provisions above and replace them * with the notice and other provisions required by the GPL. If you do not * delete the provisions above, a recipient may use your version of this file * under either the JOSL or the GPL. * * * --------------------------------------------------------------------------*//** * @file dnsrv.c * @brief implements the main part of the DNS resolver component * * Config format: * <dnsrv xmlns='jabber:config:dnsrv'> * <resend service="_jabber._tcp">s2s-component</resend> * </dnsrv> * * Note: You must specify the services in the order you want them tried */#include "jabberd.h"#include "srv_resolv.h"#include <sys/wait.h>#ifdef LIBIDN# include <idna.h>#endif/** * @brief structure to build a list that holds all hosts to which the packets are resent for a service */typedef struct __dns_resend_list_host_list { char *host; int weight; struct __dns_resend_list_host_list *next;} *dns_resend_list_host_list, _dns_resend_list_host_list;/** * struct to store list of services and resend hosts */typedef struct __dns_resend_list { char* service; /**< the service that is defined */ dns_resend_list_host_list hosts; /**< resend to which hosts */ int weight_sum; /**< sum of weights of the hosts */ struct __dns_resend_list* next; /**< next entry in the list */} *dns_resend_list, _dns_resend_list;/** * struct to keep track of a DNS coprocess */typedef struct { int in; /**< Inbound data handle */ int out; /**< Outbound data handle */ int pid; /**< Coprocess PID */ xht packet_table; /**< Hash of dns_packet_lists */ int packet_timeout; /**< how long to keep packets in the queue */ xht cache_table; /**< Hash of resolved IPs */ int cache_timeout; /**< how long to keep resolutions in the cache */ pool mempool; /**< memory pool to use */ dns_resend_list svclist; /**< list of defined services */} *dns_io, _dns_io;/** * prototype for the resolver function * * @param di pointer to the instance global data */typedef int (*RESOLVEFUNC)(dns_io di);/** * struct to store list of dpackets which need to be delivered */typedef struct __dns_packet_list { dpacket packet; /**< the dpacket list item */ int stamp; /**< timestamp */ struct __dns_packet_list* next; /**< next list entry */} *dns_packet_list, _dns_packet_list;/** * signal handler: just die after any signal * * @param sig the signal number that has been sent */void _dnsrv_signal(int sig){ exit(0);}/** * coprocess functionality */void dnsrv_child_process_xstream_io(int type, xmlnode x, void* args) { dns_io di = (dns_io)args; char *hostname, *ascii_hostname = NULL; char *str = NULL; dns_resend_list iternode = NULL; if (type == XSTREAM_NODE) { /* Get the hostname out... */ hostname = xmlnode_get_data(x); log_debug2(ZONE, LOGT_IO, "dnsrv: Recv'd lookup request for %s", hostname); if (hostname != NULL) {#ifdef LIBIDN if (idna_to_ascii_8z(hostname, &ascii_hostname, 0) == IDNA_SUCCESS) { log_debug2(ZONE, LOGT_IO, "dnsrv: IDN conversion %s to %s", hostname, ascii_hostname); hostname = ascii_hostname; }#endif /* For each entry in the svclist, try and resolve using the specified service and resend it to the specified host */ iternode = di->svclist; while (iternode != NULL) { str = srv_lookup(x->p, iternode->service, hostname); if (str != NULL) { dns_resend_list_host_list iterhost = iternode->hosts; /* play the dice, to select one of the s2s hosts */ /* XXX should we statically distribute to the hosts using a hash over the destination? */ int host_die = iternode->weight_sum <= 1 ? 0 : rand()%(iternode->weight_sum); /* find the host selected by our host_die */ while (host_die >= iterhost->weight && iterhost->next != NULL) { /* try next host */ host_die -= iterhost->weight; iterhost = iterhost->next; } log_debug2(ZONE, LOGT_IO, "Resolved %s(%s): %s\tresend to:%s", hostname, iternode->service, str, iterhost->host); xmlnode_put_attrib(x, "ip", str); xmlnode_put_attrib(x, "to", iterhost->host); break; } iternode = iternode->next; } str = xmlnode2str(x); write(di->out, str, strlen(str));#ifdef LIBIDN if (ascii_hostname != NULL) free(ascii_hostname);#endif } } xmlnode_free(x);}int dnsrv_child_main(dns_io di){ pool p = pool_new(); xstream xs = xstream_new(p, dnsrv_child_process_xstream_io, di); int len; char readbuf[1024]; log_debug2(ZONE, LOGT_INIT, "DNSRV CHILD: starting"); /* Transmit stream header */ write(di->out, "<stream>", 8); /* Loop forever, processing requests and feeding them to the xstream*/ while (1) { len = read(di->in, &readbuf, 1024); if (len <= 0) { log_debug2(ZONE, LOGT_IO|LOGT_STRANGE, "dnsrv: Read error on coprocess(%d): %d %s",getppid(),errno,strerror(errno)); break; } log_debug2(ZONE, LOGT_IO, "DNSRV CHILD: Read from buffer: %.*s",len,readbuf); if (xstream_eat(xs, readbuf, len) > XSTREAM_NODE) { log_debug2(ZONE, LOGT_IO|LOGT_STRANGE, "DNSRV CHILD: xstream died"); break; } } /* child is out of loop... normal exit so parent will start us again */ log_debug2(ZONE, LOGT_STRANGE|LOGT_CLEANUP, "DNSRV CHILD: out of loop.. exiting normal"); pool_free(p); exit(0); return 0;}/* Core functionality */int dnsrv_fork_and_capture(RESOLVEFUNC f, dns_io di){ int left_fds[2], right_fds[2]; int pid; /* Create left and right pipes */ if (pipe(left_fds) < 0 || pipe(right_fds) < 0) return -1; pid = fork(); if (pid < 0) return -1; else if (pid > 0) /* Parent */ { /* Close unneeded file handles */ close(left_fds[STDIN_FILENO]); close(right_fds[STDOUT_FILENO]); /* Return the in and out file descriptors */ di->in = right_fds[STDIN_FILENO]; di->out = left_fds[STDOUT_FILENO]; /* Transmit root element to coprocess */ pth_write(di->out, "<stream>", 8); return pid; } else /* Child */ { /* set up the new process */ pth_kill(); signal(SIGHUP,_dnsrv_signal); signal(SIGINT,_dnsrv_signal); signal(SIGTERM,_dnsrv_signal); close(left_fds[STDOUT_FILENO]); close(right_fds[STDIN_FILENO]); /* Start the specified function, passing the in/out descriptors */ di->in = left_fds[STDIN_FILENO]; di->out = right_fds[STDOUT_FILENO]; return (*f)(di); }}void dnsrv_resend(xmlnode pkt, char *ip, char *to){ if(ip != NULL) { /* maybe the packet as a query by a component, that wants to get the result back to itself */ /* this is needed for handling db:verify by the s2s component: if the component is clustered, * the result for the db:verify packet has to be the s2s component that verifies the db */ char *dnsresultto = xmlnode_get_attrib(pkt, "dnsqueryby"); if (dnsresultto == NULL) dnsresultto = to; log_debug2(ZONE, LOGT_IO, "delivering DNS result to: %s", dnsresultto); pkt = xmlnode_wrap(pkt,"route"); xmlnode_put_attrib(pkt, "to", dnsresultto); xmlnode_put_attrib(pkt, "ip", ip); }else{ jutil_error_xmpp(pkt, (xterror){502, "Unable to resolve hostname.","wait","service-unavailable"}); xmlnode_put_attrib(pkt, "iperror", ""); } deliver(dpacket_new(pkt),NULL);}/* Hostname lookup requested */void dnsrv_lookup(dns_io d, dpacket p){ dns_packet_list l, lnew; xmlnode req; char *reqs; /* make sure we have a child! */ if(d->out <= 0) { deliver_fail(p, "DNS Resolver Error"); return; } /* Attempt to lookup this hostname in the packet table */ l = (dns_packet_list)xhash_get(d->packet_table, p->host); /* IF: hashtable has the hostname, a lookup is already pending, so push the packet on the top of the list (most recent at the top) */ if (l != NULL) { log_debug2(ZONE, LOGT_IO, "dnsrv: Adding lookup request for %s to pending queue.", p->host); lnew = pmalloco(p->p, sizeof(_dns_packet_list)); lnew->packet = p; lnew->stamp = time(NULL); lnew->next = l; xhash_put(d->packet_table, p->host, lnew); return; } /* insert the packet into the packet_table using the hostname as the key and send a request to the coprocess */ log_debug2(ZONE, LOGT_IO, "dnsrv: Creating lookup request queue for %s", p->host);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -