📄 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. * * * --------------------------------------------------------------------------*/#include "jabberd.h"#include "srv_resolv.h"#include <sys/wait.h>#ifdef __CYGWIN__#include <process.h>#endif/* Config format: <dnsrv xmlns='jabber:config:dnsrv'> <resend service="_jabber._tcp">foo.org</resend> ... </dnsrv> Notes: * You must specify the services in the order you want them tried*//* ------------------------------------------------- *//* Struct to store list of services and resend hosts */typedef struct __dns_resend_list{ char* service; char* host; struct __dns_resend_list* next;} *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 */ HASHTABLE packet_table; /* Hash of dns_packet_lists */ int packet_timeout; /* how long to keep packets in the queue */ HASHTABLE cache_table; /* Hash of resolved IPs */ int cache_timeout; /* how long to keep resolutions in the cache */ pool mempool; dns_resend_list svclist;} *dns_io, _dns_io;typedef int (*RESOLVEFUNC)(dns_io di);/* ----------------------------------------------------------- *//* Struct to store list of dpackets which need to be delivered */typedef struct __dns_packet_list{ dpacket packet; int stamp; struct __dns_packet_list* next;} *dns_packet_list, _dns_packet_list;// ---------------------------------------------------------------------------// This code is not used in cygwin#ifndef __CYGWIN__/* ----------------------- *//* Coprocess functionality */void dnsrv_child_process_xstream_io(int type, xmlnode x, void* args){ dns_io di = (dns_io)args; char* hostname; char* str = NULL; dns_resend_list iternode = NULL; if (type == XSTREAM_NODE) { /* Get the hostname out... */ hostname = xmlnode_get_data(x); log_debug(ZONE, "dnsrv: Recv'd lookup request for %s", hostname); if (hostname != NULL) { /* 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) { log_debug(ZONE, "Resolved %s(%s): %s\tresend to:%s", hostname, iternode->service, str, iternode->host); xmlnode_put_attrib(x, "ip", str); xmlnode_put_attrib(x, "to", iternode->host); break; } iternode = iternode->next; } str = xmlnode2str(x); write(di->out, str, strlen(str)); } } 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]; sigset_t sigs; sigemptyset(&sigs); sigaddset(&sigs, SIGHUP); sigprocmask(SIG_BLOCK, &sigs, NULL); log_debug(ZONE,"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_debug(ZONE,"dnsrv: Read error on coprocess(%d): %d %s",getppid(),errno,strerror(errno)); break; } log_debug(ZONE, "DNSRV CHILD: Read from buffer: %.*s",len,readbuf); if (xstream_eat(xs, readbuf, len) > XSTREAM_NODE) { log_debug(ZONE, "DNSRV CHILD: xstream died"); break; } } /* child is out of loop... normal exit so parent will start us again */ log_debug(ZONE, "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 = pth_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]; return pid; } else /* Child */ { /* Close unneeded file handles */ pth_kill(); 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); }}#endif// ---------------------------------------------------------------------------// Replacement functions for cygwin#ifdef __CYGWIN__/** * Dummy dnsrv_child_main */int dnsrv_child_main(dns_io di) { return 0;}/** * Spawn a separate process for ADNS */int dnsrv_fork_and_capture(RESOLVEFUNC f, dns_io di){ int pid; int childToParent[2]; int parentToChild[2]; char childWriteHandle[10]; char childReadHandle[10]; char debugging[10]; int READ=0; int WRITE=1; // create pipes for communication with child pipe(childToParent); pipe(parentToChild); // convert the handles as they should be seen by the child to // strings so we can pass them as arguments to it sprintf(childWriteHandle, "%i", childToParent[WRITE]); sprintf(childReadHandle, "%i", parentToChild[READ]); sprintf(debugging, "%i", get_debug_flag()); // try and spawn the child process pid = spawnlp(_P_NOWAIT, "jabadns", "jabadns", childReadHandle, childWriteHandle, debugging, NULL); if (pid < 0) { return -1; } // setup di structure di->pid = pid; di->in = childToParent[READ]; di->out = parentToChild[WRITE]; // OK! return pid;}#endifvoid dnsrv_resend(xmlnode pkt, char *ip, char *to){ if(ip != NULL) { pkt = xmlnode_wrap(pkt,"route"); xmlnode_put_attrib(pkt, "to", to); xmlnode_put_attrib(pkt, "ip", ip); }else{ jutil_error(pkt, (terror){502, "Unable to resolve hostname."}); 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)ghash_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_debug(ZONE, "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; ghash_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_debug(ZONE, "dnsrv: Creating lookup request queue for %s", p->host); l = pmalloco(p->p, sizeof(_dns_packet_list)); l->packet = p; l->stamp = time(NULL); ghash_put(d->packet_table, p->host, l);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -