jabberd2
2.2.16
|
00001 /* 00002 * jabberd - Jabber Open Source Server 00003 * Copyright (c) 2002 Jeremie Miller, Thomas Muldowney, 00004 * Ryan Eatmon, Robert Norris 00005 * 00006 * This program is free software; you can redistribute it and/or modify 00007 * it under the terms of the GNU General Public License as published by 00008 * the Free Software Foundation; either version 2 of the License, or 00009 * (at your option) any later version. 00010 * 00011 * This program is distributed in the hope that it will be useful, 00012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the 00014 * GNU General Public License for more details. 00015 * 00016 * You should have received a copy of the GNU General Public License 00017 * along with this program; if not, write to the Free Software 00018 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA02111-1307USA 00019 */ 00020 00021 #include "s2s.h" 00022 00023 #include <stringprep.h> 00024 00025 static sig_atomic_t s2s_shutdown = 0; 00026 sig_atomic_t s2s_lost_router = 0; 00027 static sig_atomic_t s2s_logrotate = 0; 00028 00029 static void _s2s_signal(int signum) { 00030 s2s_shutdown = 1; 00031 s2s_lost_router = 0; 00032 } 00033 00034 static void _s2s_signal_hup(int signum) { 00035 s2s_logrotate = 1; 00036 } 00037 00038 static void _s2s_signal_usr1(int signum) 00039 { 00040 set_debug_flag(0); 00041 } 00042 00043 static void _s2s_signal_usr2(int signum) 00044 { 00045 set_debug_flag(1); 00046 } 00047 00049 static void _s2s_pidfile(s2s_t s2s) { 00050 char *pidfile; 00051 FILE *f; 00052 pid_t pid; 00053 00054 pidfile = config_get_one(s2s->config, "pidfile", 0); 00055 if(pidfile == NULL) 00056 return; 00057 00058 pid = getpid(); 00059 00060 if((f = fopen(pidfile, "w+")) == NULL) { 00061 log_write(s2s->log, LOG_ERR, "couldn't open %s for writing: %s", pidfile, strerror(errno)); 00062 return; 00063 } 00064 00065 if(fprintf(f, "%d", pid) < 0) { 00066 log_write(s2s->log, LOG_ERR, "couldn't write to %s: %s", pidfile, strerror(errno)); 00067 fclose(f); 00068 return; 00069 } 00070 00071 fclose(f); 00072 00073 log_write(s2s->log, LOG_INFO, "process id is %d, written to %s", pid, pidfile); 00074 } 00075 00077 static void _s2s_config_expand(s2s_t s2s) { 00078 char *str, secret[41]; 00079 config_elem_t elem; 00080 int i, r; 00081 00082 set_debug_log_from_config(s2s->config); 00083 00084 s2s->id = config_get_one(s2s->config, "id", 0); 00085 if(s2s->id == NULL) 00086 s2s->id = "s2s"; 00087 00088 s2s->router_ip = config_get_one(s2s->config, "router.ip", 0); 00089 if(s2s->router_ip == NULL) 00090 s2s->router_ip = "127.0.0.1"; 00091 00092 s2s->router_port = j_atoi(config_get_one(s2s->config, "router.port", 0), 5347); 00093 00094 s2s->router_user = config_get_one(s2s->config, "router.user", 0); 00095 if(s2s->router_user == NULL) 00096 s2s->router_user = "jabberd"; 00097 s2s->router_pass = config_get_one(s2s->config, "router.pass", 0); 00098 if(s2s->router_pass == NULL) 00099 s2s->router_pass = "secret"; 00100 00101 s2s->router_pemfile = config_get_one(s2s->config, "router.pemfile", 0); 00102 00103 s2s->retry_init = j_atoi(config_get_one(s2s->config, "router.retry.init", 0), 3); 00104 s2s->retry_lost = j_atoi(config_get_one(s2s->config, "router.retry.lost", 0), 3); 00105 if((s2s->retry_sleep = j_atoi(config_get_one(s2s->config, "router.retry.sleep", 0), 2)) < 1) 00106 s2s->retry_sleep = 1; 00107 00108 s2s->router_default = config_count(s2s->config, "router.non-default") ? 0 : 1; 00109 00110 s2s->log_type = log_STDOUT; 00111 if(config_get(s2s->config, "log") != NULL) { 00112 if((str = config_get_attr(s2s->config, "log", 0, "type")) != NULL) { 00113 if(strcmp(str, "file") == 0) 00114 s2s->log_type = log_FILE; 00115 else if(strcmp(str, "syslog") == 0) 00116 s2s->log_type = log_SYSLOG; 00117 } 00118 } 00119 00120 if(s2s->log_type == log_SYSLOG) { 00121 s2s->log_facility = config_get_one(s2s->config, "log.facility", 0); 00122 s2s->log_ident = config_get_one(s2s->config, "log.ident", 0); 00123 if(s2s->log_ident == NULL) 00124 s2s->log_ident = "jabberd/s2s"; 00125 } else if(s2s->log_type == log_FILE) 00126 s2s->log_ident = config_get_one(s2s->config, "log.file", 0); 00127 00128 s2s->packet_stats = config_get_one(s2s->config, "stats.packet", 0); 00129 00130 if(s2s->local_ip == NULL) 00131 s2s->local_ip = "0.0.0.0"; 00132 00133 /* 00134 * If no origin IP is specified, use local IP as the originating one: 00135 * it makes most sense, at least for SSL'ized connections. 00136 * APPLE: make origin an array of addresses so that both IPv4 and IPv6 can be specified. 00137 */ 00138 s2s->local_ip = config_get_one(s2s->config, "local.ip", 0); 00139 if((elem = config_get(s2s->config, "local.origins.ip")) != NULL) { 00140 s2s->origin_ips = elem->values; 00141 s2s->origin_nips = elem->nvalues; 00142 } 00143 if (s2s->origin_nips == 0) { 00144 s2s->origin_ips = (char **)malloc(sizeof(s2s->origin_ips)); 00145 s2s->origin_ips[0] = strdup(s2s->local_ip); 00146 s2s->origin_nips = 1; 00147 } 00148 00149 s2s->local_port = j_atoi(config_get_one(s2s->config, "local.port", 0), 0); 00150 00151 if(config_get(s2s->config, "local.secret") != NULL) 00152 s2s->local_secret = strdup(config_get_one(s2s->config, "local.secret", 0)); 00153 else { 00154 for(i = 0; i < 40; i++) { 00155 r = (int) (36.0 * rand() / RAND_MAX); 00156 secret[i] = (r >= 0 && r <= 9) ? (r + 48) : (r + 87); 00157 } 00158 secret[40] = '\0'; 00159 00160 s2s->local_secret = strdup(secret); 00161 } 00162 00163 if(s2s->local_secret == NULL) 00164 s2s->local_secret = "secret"; 00165 00166 s2s->local_pemfile = config_get_one(s2s->config, "local.pemfile", 0); 00167 s2s->local_cachain = config_get_one(s2s->config, "local.cachain", 0); 00168 s2s->local_verify_mode = j_atoi(config_get_one(s2s->config, "local.verify-mode", 0), 0); 00169 00170 s2s->io_max_fds = j_atoi(config_get_one(s2s->config, "io.max_fds", 0), 1024); 00171 00172 s2s->compression = (config_get(s2s->config, "io.compression") != NULL); 00173 00174 s2s->stanza_size_limit = j_atoi(config_get_one(s2s->config, "io.limits.stanzasize", 0), 0); 00175 s2s->require_tls = j_atoi(config_get_one(s2s->config, "security.require_tls", 0), 0); 00176 s2s->enable_whitelist = j_atoi(config_get_one(s2s->config, "security.enable_whitelist", 0), 0); 00177 if((elem = config_get(s2s->config, "security.whitelist_domain")) != NULL) { 00178 _s2s_populate_whitelist_domains(s2s, elem->values, elem->nvalues); 00179 } 00180 00181 s2s->check_interval = j_atoi(config_get_one(s2s->config, "check.interval", 0), 60); 00182 s2s->check_queue = j_atoi(config_get_one(s2s->config, "check.queue", 0), 60); 00183 s2s->check_keepalive = j_atoi(config_get_one(s2s->config, "check.keepalive", 0), 0); 00184 s2s->check_idle = j_atoi(config_get_one(s2s->config, "check.idle", 0), 86400); 00185 s2s->check_dnscache = j_atoi(config_get_one(s2s->config, "check.dnscache", 0), 300); 00186 s2s->retry_limit = j_atoi(config_get_one(s2s->config, "check.retry", 0), 300); 00187 00188 if((elem = config_get(s2s->config, "lookup.srv")) != NULL) { 00189 s2s->lookup_srv = elem->values; 00190 s2s->lookup_nsrv = elem->nvalues; 00191 } 00192 00193 s2s->resolve_aaaa = config_count(s2s->config, "lookup.resolve-ipv6") ? 1 : 0; 00194 s2s->dns_cache_enabled = config_count(s2s->config, "lookup.no-cache") ? 0 : 1; 00195 s2s->dns_bad_timeout = j_atoi(config_get_one(s2s->config, "lookup.bad-host-timeout", 0), 3600); 00196 s2s->dns_min_ttl = j_atoi(config_get_one(s2s->config, "lookup.min-ttl", 0), 30); 00197 if (s2s->dns_min_ttl < 5) 00198 s2s->dns_min_ttl = 5; 00199 s2s->dns_max_ttl = j_atoi(config_get_one(s2s->config, "lookup.max-ttl", 0), 86400); 00200 s2s->etc_hosts_ttl = j_atoi(config_get_one(s2s->config, "lookup.etc-hosts-ttl", 0), 86400); 00201 s2s->out_reuse = config_count(s2s->config, "out-conn-reuse") ? 1 : 0; 00202 } 00203 00204 static void _s2s_hosts_expand(s2s_t s2s) 00205 { 00206 char *realm; 00207 config_elem_t elem; 00208 char id[1024]; 00209 int i; 00210 00211 elem = config_get(s2s->config, "local.id"); 00212 00213 if (elem) for(i = 0; i < elem->nvalues; i++) { 00214 host_t host = (host_t) pmalloco(xhash_pool(s2s->hosts), sizeof(struct host_st)); 00215 if(!host) { 00216 log_write(s2s->log, LOG_ERR, "cannot allocate memory for new host, aborting"); 00217 exit(1); 00218 } 00219 00220 realm = j_attr((const char **) elem->attrs[i], "realm"); 00221 00222 /* stringprep ids (domain names) so that they are in canonical form */ 00223 strncpy(id, elem->values[i], 1024); 00224 id[1023] = '\0'; 00225 if (stringprep_nameprep(id, 1024) != 0) { 00226 log_write(s2s->log, LOG_ERR, "cannot stringprep id %s, aborting", id); 00227 exit(1); 00228 } 00229 00230 host->realm = (realm != NULL) ? realm : pstrdup(xhash_pool(s2s->hosts), id); 00231 00232 host->host_pemfile = j_attr((const char **) elem->attrs[i], "pemfile"); 00233 00234 host->host_cachain = j_attr((const char **) elem->attrs[i], "cachain"); 00235 00236 host->host_verify_mode = j_atoi(j_attr((const char **) elem->attrs[i], "verify-mode"), 0); 00237 00238 #ifdef HAVE_SSL 00239 if(host->host_pemfile != NULL) { 00240 if(s2s->sx_ssl == NULL) { 00241 s2s->sx_ssl = sx_env_plugin(s2s->sx_env, sx_ssl_init, host->realm, host->host_pemfile, host->host_cachain, host->host_verify_mode); 00242 if(s2s->sx_ssl == NULL) { 00243 log_write(s2s->log, LOG_ERR, "failed to load %s SSL pemfile", host->realm); 00244 host->host_pemfile = NULL; 00245 } 00246 } else { 00247 if(sx_ssl_server_addcert(s2s->sx_ssl, host->realm, host->host_pemfile, host->host_cachain, host->host_verify_mode) != 0) { 00248 log_write(s2s->log, LOG_ERR, "failed to load %s SSL pemfile", host->realm); 00249 host->host_pemfile = NULL; 00250 } 00251 } 00252 } 00253 #endif 00254 00255 /* insert into vHosts xhash */ 00256 xhash_put(s2s->hosts, pstrdup(xhash_pool(s2s->hosts), id), host); 00257 00258 log_write(s2s->log, LOG_NOTICE, "[%s] configured; realm=%s", id, host->realm); 00259 } 00260 } 00261 00262 static int _s2s_router_connect(s2s_t s2s) { 00263 log_write(s2s->log, LOG_NOTICE, "attempting connection to router at %s, port=%d", s2s->router_ip, s2s->router_port); 00264 00265 s2s->fd = mio_connect(s2s->mio, s2s->router_port, s2s->router_ip, NULL, s2s_router_mio_callback, (void *) s2s); 00266 if(s2s->fd == NULL) { 00267 if(errno == ECONNREFUSED) 00268 s2s_lost_router = 1; 00269 log_write(s2s->log, LOG_NOTICE, "connection attempt to router failed: %s (%d)", MIO_STRERROR(MIO_ERROR), MIO_ERROR); 00270 return 1; 00271 } 00272 00273 s2s->router = sx_new(s2s->sx_env, s2s->fd->fd, s2s_router_sx_callback, (void *) s2s); 00274 sx_client_init(s2s->router, 0, NULL, NULL, NULL, "1.0"); 00275 00276 return 0; 00277 } 00278 00279 int _s2s_check_conn_routes(s2s_t s2s, conn_t conn, const char *direction) 00280 { 00281 char *rkey; 00282 int rkeylen; 00283 conn_state_t state; 00284 time_t now, dialback_time; 00285 00286 now = time(NULL); 00287 00288 if(xhash_iter_first(conn->states)) 00289 do { 00290 /* retrieve state in a separate operation, as sizeof(int) != sizeof(void *) on 64-bit platforms, 00291 so passing a pointer to state in xhash_iter_get is unsafe */ 00292 xhash_iter_get(conn->states, (const char **) &rkey, &rkeylen, NULL); 00293 state = (conn_state_t) xhash_getx(conn->states, rkey, rkeylen); 00294 00295 if (state == conn_INPROGRESS) { 00296 dialback_time = (time_t) xhash_getx(conn->states_time, rkey, rkeylen); 00297 00298 if(now > dialback_time + s2s->check_queue) { 00299 log_write(s2s->log, LOG_NOTICE, "[%d] [%s, port=%d] dialback for %s route '%.*s' timed out", conn->fd->fd, conn->ip, conn->port, direction, rkeylen, rkey); 00300 00301 xhash_zapx(conn->states, rkey, rkeylen); 00302 xhash_zapx(conn->states_time, rkey, rkeylen); 00303 00304 /* stream error */ 00305 sx_error(conn->s, stream_err_CONNECTION_TIMEOUT, "dialback timed out"); 00306 00307 /* close connection as per XMPP/RFC3920 */ 00308 sx_close(conn->s); 00309 00310 /* indicate that we closed the connection */ 00311 return 0; 00312 } 00313 } 00314 } while(xhash_iter_next(conn->states)); 00315 00316 /* all ok */ 00317 return 1; 00318 } 00319 00320 static void _s2s_time_checks(s2s_t s2s) { 00321 conn_t conn; 00322 time_t now; 00323 char *rkey, *key; 00324 int keylen; 00325 jqueue_t q; 00326 dnscache_t dns; 00327 char *c; 00328 int c_len; 00329 union xhashv xhv; 00330 00331 now = time(NULL); 00332 00333 /* queue expiry */ 00334 if(s2s->check_queue > 0) { 00335 if(xhash_iter_first(s2s->outq)) 00336 do { 00337 xhv.jq_val = &q; 00338 xhash_iter_get(s2s->outq, (const char **) &rkey, &keylen, xhv.val); 00339 00340 log_debug(ZONE, "running time checks for %.*s", keylen, rkey); 00341 c = memchr(rkey, '/', keylen); 00342 c++; 00343 c_len = keylen - (c - rkey); 00344 00345 /* dns lookup timeout check first */ 00346 dns = xhash_getx(s2s->dnscache, c, c_len); 00347 if(dns != NULL && dns->pending) { 00348 log_debug(ZONE, "dns lookup pending for %.*s", c_len, c); 00349 if(now > dns->init_time + s2s->check_queue) { 00350 log_write(s2s->log, LOG_NOTICE, "dns lookup for %.*s timed out", c_len, c); 00351 00352 /* bounce queue */ 00353 out_bounce_route_queue(s2s, rkey, keylen, stanza_err_REMOTE_SERVER_NOT_FOUND); 00354 00355 /* expire pending dns entry */ 00356 xhash_zap(s2s->dnscache, dns->name); 00357 xhash_free(dns->results); 00358 if (dns->query != NULL) { 00359 if (dns->query->query != NULL) 00360 dns_cancel(NULL, dns->query->query); 00361 xhash_free(dns->query->hosts); 00362 xhash_free(dns->query->results); 00363 free(dns->query->name); 00364 free(dns->query); 00365 } 00366 free(dns); 00367 } 00368 00369 continue; 00370 } 00371 00372 /* get the conn */ 00373 conn = xhash_getx(s2s->out_dest, c, c_len); 00374 if(conn == NULL) { 00375 if(jqueue_size(q) > 0) { 00376 /* no pending conn? perhaps it failed? */ 00377 log_debug(ZONE, "no pending connection for %.*s, bouncing %i packets in queue", c_len, c, jqueue_size(q)); 00378 00379 /* bounce queue */ 00380 out_bounce_route_queue(s2s, rkey, keylen, stanza_err_REMOTE_SERVER_TIMEOUT); 00381 } 00382 00383 continue; 00384 } 00385 00386 /* connect timeout check */ 00387 if(!conn->online && now > conn->init_time + s2s->check_queue) { 00388 dnsres_t bad; 00389 char *ipport; 00390 00391 log_write(s2s->log, LOG_NOTICE, "[%d] [%s, port=%d] connection to %s timed out", conn->fd->fd, conn->ip, conn->port, c); 00392 00393 if (s2s->dns_bad_timeout > 0) { 00394 /* mark this host as bad */ 00395 ipport = dns_make_ipport(conn->ip, conn->port); 00396 bad = xhash_get(s2s->dns_bad, ipport); 00397 if (bad == NULL) { 00398 bad = (dnsres_t) calloc(1, sizeof(struct dnsres_st)); 00399 bad->key = ipport; 00400 xhash_put(s2s->dns_bad, ipport, bad); 00401 } else { 00402 free(ipport); 00403 } 00404 bad->expiry = time(NULL) + s2s->dns_bad_timeout; 00405 } 00406 00407 /* close connection as per XMPP/RFC3920 */ 00408 /* the close function will retry or bounce the queue */ 00409 sx_close(conn->s); 00410 } 00411 } while(xhash_iter_next(s2s->outq)); 00412 } 00413 00414 /* expiry of connected routes in conn_INPROGRESS state */ 00415 if(s2s->check_queue > 0) { 00416 00417 /* outgoing connections */ 00418 if(s2s->out_reuse) { 00419 if(xhash_iter_first(s2s->out_host)) 00420 do { 00421 xhv.conn_val = &conn; 00422 xhash_iter_get(s2s->out_host, (const char **) &key, &keylen, xhv.val); 00423 log_debug(ZONE, "checking dialback state for outgoing conn %.*s", keylen, key); 00424 if (_s2s_check_conn_routes(s2s, conn, "outgoing")) { 00425 log_debug(ZONE, "checking pending verify requests for outgoing conn %.*s", keylen, key); 00426 if (conn->verify > 0 && now > conn->last_verify + s2s->check_queue) { 00427 log_write(s2s->log, LOG_NOTICE, "[%d] [%s, port=%d] dialback verify request timed out", conn->fd->fd, conn->ip, conn->port); 00428 sx_error(conn->s, stream_err_CONNECTION_TIMEOUT, "dialback verify request timed out"); 00429 sx_close(conn->s); 00430 } 00431 } 00432 } while(xhash_iter_next(s2s->out_host)); 00433 } else { 00434 if(xhash_iter_first(s2s->out_dest)) 00435 do { 00436 xhv.conn_val = &conn; 00437 xhash_iter_get(s2s->out_dest, (const char **) &key, &keylen, xhv.val); 00438 log_debug(ZONE, "checking dialback state for outgoing conn %s (%s)", conn->dkey, conn->key); 00439 if (_s2s_check_conn_routes(s2s, conn, "outgoing")) { 00440 log_debug(ZONE, "checking pending verify requests for outgoing conn %s (%s)", conn->dkey, conn->key); 00441 if (conn->verify > 0 && now > conn->last_verify + s2s->check_queue) { 00442 log_write(s2s->log, LOG_NOTICE, "[%d] [%s, port=%d] dialback verify request timed out", conn->fd->fd, conn->ip, conn->port); 00443 sx_error(conn->s, stream_err_CONNECTION_TIMEOUT, "dialback verify request timed out"); 00444 sx_close(conn->s); 00445 } 00446 } 00447 } while(xhash_iter_next(s2s->out_dest)); 00448 } 00449 00450 /* incoming open streams */ 00451 if(xhash_iter_first(s2s->in)) 00452 do { 00453 xhv.conn_val = &conn; 00454 xhash_iter_get(s2s->in, (const char **) &key, &keylen, xhv.val); 00455 00456 log_debug(ZONE, "checking dialback state for incoming conn %.*s", keylen, key); 00457 if (_s2s_check_conn_routes(s2s, conn, "incoming")) 00458 /* if the connection is still valid, check that dialbacks have been initiated */ 00459 if(!xhash_count(conn->states) && now > conn->init_time + s2s->check_queue) { 00460 log_write(s2s->log, LOG_NOTICE, "[%d] [%s, port=%d] no dialback started", conn->fd->fd, conn->ip, conn->port); 00461 sx_error(conn->s, stream_err_CONNECTION_TIMEOUT, "no dialback initiated"); 00462 sx_close(conn->s); 00463 } 00464 } while(xhash_iter_next(s2s->in)); 00465 00466 /* incoming open connections (not yet streams) */ 00467 if(xhash_iter_first(s2s->in_accept)) 00468 do { 00469 xhv.conn_val = &conn; 00470 xhash_iter_get(s2s->in_accept, (const char **) &key, &keylen, xhv.val); 00471 00472 log_debug(ZONE, "checking stream connection state for incoming conn %i", conn->fd->fd); 00473 if(!conn->online && now > conn->init_time + s2s->check_queue) { 00474 log_write(s2s->log, LOG_NOTICE, "[%d] [%s, port=%d] stream initiation timed out", conn->fd->fd, conn->ip, conn->port); 00475 sx_close(conn->s); 00476 } 00477 } while(xhash_iter_next(s2s->in_accept)); 00478 00479 } 00480 00481 /* keepalives */ 00482 if(s2s->out_reuse) { 00483 if(xhash_iter_first(s2s->out_host)) 00484 do { 00485 xhv.conn_val = &conn; 00486 xhash_iter_get(s2s->out_host, NULL, NULL, xhv.val); 00487 00488 if(s2s->check_keepalive > 0 && conn->last_activity > 0 && now > conn->last_activity + s2s->check_keepalive && conn->s->state >= state_STREAM) { 00489 log_debug(ZONE, "sending keepalive for %d", conn->fd->fd); 00490 00491 sx_raw_write(conn->s, " ", 1); 00492 } 00493 } while(xhash_iter_next(s2s->out_host)); 00494 } else { 00495 if(xhash_iter_first(s2s->out_dest)) 00496 do { 00497 xhv.conn_val = &conn; 00498 xhash_iter_get(s2s->out_dest, NULL, NULL, xhv.val); 00499 00500 if(s2s->check_keepalive > 0 && conn->last_activity > 0 && now > conn->last_activity + s2s->check_keepalive && conn->s->state >= state_STREAM) { 00501 log_debug(ZONE, "sending keepalive for %d", conn->fd->fd); 00502 00503 sx_raw_write(conn->s, " ", 1); 00504 } 00505 } while(xhash_iter_next(s2s->out_dest)); 00506 } 00507 00508 /* idle timeouts - disconnect connections through which no packets have been sent for <idle> seconds */ 00509 if(s2s->check_idle > 0) { 00510 00511 /* outgoing connections */ 00512 if(s2s->out_reuse) { 00513 if(xhash_iter_first(s2s->out_host)) 00514 do { 00515 xhv.conn_val = &conn; 00516 xhash_iter_get(s2s->out_host, (const char **) &key, &keylen, xhv.val); 00517 log_debug(ZONE, "checking idle state for %.*s", keylen, key); 00518 if (conn->last_packet > 0 && now > conn->last_packet + s2s->check_idle && conn->s->state >= state_STREAM) { 00519 log_write(s2s->log, LOG_NOTICE, "[%d] [%s, port=%d] idle timeout", conn->fd->fd, conn->ip, conn->port); 00520 sx_close(conn->s); 00521 } 00522 } while(xhash_iter_next(s2s->out_host)); 00523 } else { 00524 if(xhash_iter_first(s2s->out_dest)) 00525 do { 00526 xhv.conn_val = &conn; 00527 xhash_iter_get(s2s->out_dest, (const char **) &key, &keylen, xhv.val); 00528 log_debug(ZONE, "checking idle state for %s (%s)", conn->dkey, conn->key); 00529 if (conn->last_packet > 0 && now > conn->last_packet + s2s->check_idle && conn->s->state >= state_STREAM) { 00530 log_write(s2s->log, LOG_NOTICE, "[%d] [%s, port=%d] idle timeout", conn->fd->fd, conn->ip, conn->port); 00531 sx_close(conn->s); 00532 } 00533 } while(xhash_iter_next(s2s->out_dest)); 00534 } 00535 00536 /* incoming connections */ 00537 if(xhash_iter_first(s2s->in)) 00538 do { 00539 xhv.conn_val = &conn; 00540 xhash_iter_get(s2s->in, (const char **) &key, &keylen, xhv.val); 00541 log_debug(ZONE, "checking idle state for %.*s", keylen, key); 00542 if (conn->last_packet > 0 && now > conn->last_packet + s2s->check_idle && conn->s->state >= state_STREAM) { 00543 log_write(s2s->log, LOG_NOTICE, "[%d] [%s, port=%d] idle timeout", conn->fd->fd, conn->ip, conn->port); 00544 sx_close(conn->s); 00545 } 00546 } while(xhash_iter_next(s2s->in)); 00547 00548 } 00549 00550 return; 00551 } 00552 00553 static void _s2s_dns_expiry(s2s_t s2s) { 00554 time_t now; 00555 dnscache_t dns = NULL; 00556 dnsres_t res = NULL; 00557 union xhashv xhv; 00558 00559 now = time(NULL); 00560 00561 /* dnscache timeouts */ 00562 if(xhash_iter_first(s2s->dnscache)) 00563 do { 00564 xhv.dns_val = &dns; 00565 xhash_iter_get(s2s->dnscache, NULL, NULL, xhv.val); 00566 if (dns && !dns->pending && now > dns->expiry) { 00567 log_debug(ZONE, "expiring DNS cache for %s", dns->name); 00568 xhash_iter_zap(s2s->dnscache); 00569 00570 xhash_free(dns->results); 00571 if (dns->query != NULL) { 00572 if (dns->query->query != NULL) 00573 dns_cancel(NULL, dns->query->query); 00574 xhash_free(dns->query->hosts); 00575 xhash_free(dns->query->results); 00576 free(dns->query->name); 00577 free(dns->query); 00578 } 00579 free(dns); 00580 } 00581 else if (dns == NULL) { 00582 xhash_iter_zap(s2s->dnscache); 00583 } 00584 } while(xhash_iter_next(s2s->dnscache)); 00585 00586 if(xhash_iter_first(s2s->dns_bad)) 00587 do { 00588 xhv.dnsres_val = &res; 00589 xhash_iter_get(s2s->dns_bad, NULL, NULL, xhv.val); 00590 if (res && now > res->expiry) { 00591 log_debug(ZONE, "expiring DNS bad host %s", res->key); 00592 xhash_iter_zap(s2s->dns_bad); 00593 00594 free(res->key); 00595 free(res); 00596 } 00597 else if (res == NULL) { 00598 xhash_iter_zap(s2s->dns_bad); 00599 } 00600 } while(xhash_iter_next(s2s->dns_bad)); 00601 } 00603 static int _mio_resolver_callback(mio_t m, mio_action_t a, mio_fd_t fd, void *data, void *arg) { 00604 00605 switch(a) { 00606 case action_READ: 00607 log_debug(ZONE, "read action on fd %d", fd->fd); 00608 00609 dns_ioevent(0, time(NULL)); 00610 00611 default: 00612 break; 00613 } 00614 00615 return 0; 00616 } 00617 00618 /* Populate the whitelist_domains array with the config file values */ 00619 int _s2s_populate_whitelist_domains(s2s_t s2s, char **values, int nvalues) { 00620 int i, j; 00621 int elem_len; 00622 s2s->whitelist_domains = (char **)malloc(sizeof(char*) * (nvalues)); 00623 memset(s2s->whitelist_domains, 0, (sizeof(char *) * (nvalues))); 00624 for (i = 0, j = 0; i < nvalues; i++) { 00625 elem_len = strlen(values[i]); 00626 if (elem_len > MAX_DOMAIN_LEN) { 00627 log_debug(ZONE, "whitelist domain element is too large, skipping"); 00628 continue; 00629 } 00630 if (elem_len == 0) { 00631 log_debug(ZONE, "whitelist domain element is blank, skipping"); 00632 continue; 00633 } 00634 s2s->whitelist_domains[j] = (char *) malloc(sizeof(char) * (elem_len+1)); 00635 memset(s2s->whitelist_domains[j], 0, (sizeof(char) * (elem_len+1))); 00636 strncpy(s2s->whitelist_domains[j], values[i], elem_len); 00637 s2s->whitelist_domains[j][elem_len+1] = '\0'; 00638 log_debug(ZONE, "s2s whitelist domain read from file: %s\n", s2s->whitelist_domains[j]); 00639 j++; 00640 } 00641 00642 s2s->n_whitelist_domains = j; 00643 log_debug(ZONE, "n_whitelist_domains = %d", s2s->n_whitelist_domains); 00644 return 0; 00645 } 00646 00647 00648 /* Compare a domain with whitelist values. 00649 The whitelist values may be FQDN or domain only (with no prepended hostname). 00650 returns 1 on match, 0 on failure to match 00651 */ 00652 int s2s_domain_in_whitelist(s2s_t s2s, char *in_domain) { 00653 int segcount = 0; 00654 int dotcount; 00655 char **segments = NULL; 00656 char **dst = NULL; 00657 char *seg_tmp = NULL; 00658 int seg_tmp_len; 00659 char matchstr[MAX_DOMAIN_LEN + 1]; 00660 int domain_index; 00661 int x, i; 00662 int wl_index; 00663 int wl_len; 00664 int matchstr_len; 00665 char domain[1024]; 00666 char *domain_ptr = &domain[0]; 00667 int domain_len; 00668 00669 strncpy(domain, in_domain, sizeof(domain)); 00670 domain[sizeof(domain)-1] = '\0'; 00671 domain_len = strlen((const char *)&domain); 00672 00673 if (domain_len <= 0) { 00674 log_write(s2s->log, LOG_NOTICE, "s2s_domain_in_whitelist: in_domain is empty"); 00675 return 0; 00676 } 00677 00678 if (domain_len > MAX_DOMAIN_LEN) { 00679 log_write(s2s->log, LOG_NOTICE, "s2s_domain_in_whitelist: in_domain is longer than %s chars", MAX_DOMAIN_LEN); 00680 return 0; 00681 } 00682 00683 // first try matching the FQDN with whitelist domains 00684 if (s2s->n_whitelist_domains <= 0) 00685 return 0; 00686 00687 for (wl_index =0; wl_index < s2s->n_whitelist_domains; wl_index++) { 00688 wl_len = strlen(s2s->whitelist_domains[wl_index]); 00689 if (!strncmp((const char *)&domain, s2s->whitelist_domains[wl_index], (domain_len > wl_len) ? domain_len : wl_len)) { 00690 log_debug(ZONE, "domain \"%s\" matches whitelist entry", &domain); 00691 return 1; 00692 } 00693 else { 00694 //log_debug(ZONE, "domain: %s (len %d) does not match whitelist_domains[%d]: %s (len %d)", &domain, strlen((const char *)&domain), wl_index, s2s->whitelist_domains[wl_index], strlen(s2s->whitelist_domains[wl_index])); 00695 } 00696 } 00697 00698 // break domain into segments for domain-only comparision 00699 for (dotcount = 0, x = 0; domain[x] != '\0'; x++) { 00700 if (domain[x] == '.') 00701 dotcount++; 00702 } 00703 00704 segments = (char **)malloc(sizeof(char*) * (dotcount + 1)); 00705 if (segments == NULL) { 00706 log_write(s2s->log, LOG_ERR, "s2s_domain_in_whitelist: malloc() error"); 00707 return 0; 00708 } 00709 memset((char **)segments, 0, (sizeof(char*) * (dotcount + 1))); 00710 00711 do { 00712 if (segcount > (dotcount+1)) { 00713 log_write(s2s->log, LOG_ERR, "s2s_domain_in_whitelist: did not malloc enough room for domain segments; should never get here"); 00714 if (seg_tmp != NULL) { 00715 free(seg_tmp); 00716 seg_tmp = NULL; 00717 } 00718 for (x = 0; x < segcount; x++) { 00719 free(segments[x]); 00720 segments[x] = NULL; 00721 } 00722 free(segments); 00723 segments = NULL; 00724 return 0; 00725 } 00726 seg_tmp = strsep(&domain_ptr, "."); 00727 if (seg_tmp == NULL) { 00728 break; 00729 } 00730 00731 seg_tmp_len = strlen(seg_tmp); 00732 if (seg_tmp_len > MAX_DOMAIN_LEN) { 00733 log_write(s2s->log, LOG_NOTICE, "s2s_domain_in_whitelist: domain contains a segment greater than %s chars", MAX_DOMAIN_LEN); 00734 if (seg_tmp != NULL) { 00735 free(seg_tmp); 00736 seg_tmp = NULL; 00737 } 00738 for (x = 0; x < segcount; x++) { 00739 free(segments[x]); 00740 segments[x] = NULL; 00741 } 00742 free(segments); 00743 segments = NULL; 00744 return 0; 00745 } 00746 dst = &segments[segcount]; 00747 *dst = (char *)malloc(seg_tmp_len + 1); 00748 if (*dst != NULL) { 00749 strncpy(*dst, seg_tmp, seg_tmp_len + 1); 00750 dst[seg_tmp_len] = '\0'; 00751 } else { 00752 if (seg_tmp != NULL) { 00753 free(seg_tmp); 00754 seg_tmp = NULL; 00755 } 00756 for (x = 0; x < segcount; x++) { 00757 free(segments[x]); 00758 segments[x] = NULL; 00759 } 00760 free(segments); 00761 segments = NULL; 00762 log_write(s2s->log, LOG_ERR, "s2s_domain_in_whitelist: malloc() error"); 00763 return 0; 00764 } 00765 segcount++; 00766 } while (seg_tmp != NULL); 00767 00768 if (segcount > 1) { 00769 for (domain_index = segcount-2; domain_index > 0; domain_index--) { 00770 matchstr[0] = '\0'; 00771 for (i = domain_index; i < segcount; i++) { 00772 if (i > domain_index) { 00773 strncat((char *)&matchstr, ".", sizeof(matchstr)); 00774 matchstr[sizeof(matchstr)-1] = '\0'; 00775 } 00776 strncat((char *)&matchstr, (char *)segments[i], sizeof(matchstr)); 00777 matchstr[sizeof(matchstr)-1] = '\0'; 00778 } 00779 for (wl_index = 0; wl_index < s2s->n_whitelist_domains; wl_index++) { 00780 wl_len = strlen(s2s->whitelist_domains[wl_index]); 00781 matchstr_len = strlen((const char *)&matchstr); 00782 if (!strncmp((const char *)&matchstr, s2s->whitelist_domains[wl_index], (wl_len > matchstr_len ? wl_len : matchstr_len))) { 00783 log_debug(ZONE, "matchstr \"%s\" matches whitelist entry", &matchstr); 00784 for (x = 0; x < segcount; x++) { 00785 free(segments[x]); 00786 segments[x] = NULL; 00787 } 00788 free(segments); 00789 segments = NULL; 00790 return 1; 00791 } 00792 else { 00793 //log_debug(ZONE, "matchstr: %s (len %d) does not match whitelist_domains[%d]: %s (len %d)", &matchstr, strlen((const char *)&matchstr), wl_index, s2s->whitelist_domains[wl_index], strlen(s2s->whitelist_domains[wl_index])); 00794 } 00795 } 00796 } 00797 } 00798 for (x = 0; x < segcount; x++) { 00799 free(segments[x]); 00800 segments[x] = NULL; 00801 } 00802 free(segments); 00803 segments = NULL; 00804 00805 return 0; 00806 } 00807 00808 JABBER_MAIN("jabberd2s2s", "Jabber 2 S2S", "Jabber Open Source Server: Server to Server", "jabberd2router\0") 00809 { 00810 s2s_t s2s; 00811 char *config_file; 00812 int optchar; 00813 conn_t conn; 00814 jqueue_t q; 00815 dnscache_t dns; 00816 dnsres_t res; 00817 union xhashv xhv; 00818 time_t check_time = 0, now = 0; 00819 const char *cli_id = 0; 00820 00821 #ifdef HAVE_UMASK 00822 umask((mode_t) 0027); 00823 #endif 00824 00825 srand(time(NULL)); 00826 00827 #ifdef HAVE_WINSOCK2_H 00828 /* get winsock running */ 00829 { 00830 WORD wVersionRequested; 00831 WSADATA wsaData; 00832 int err; 00833 00834 wVersionRequested = MAKEWORD( 2, 2 ); 00835 00836 err = WSAStartup( wVersionRequested, &wsaData ); 00837 if ( err != 0 ) { 00838 /* !!! tell user that we couldn't find a usable winsock dll */ 00839 return 0; 00840 } 00841 } 00842 #endif 00843 00844 jabber_signal(SIGINT, _s2s_signal); 00845 jabber_signal(SIGTERM, _s2s_signal); 00846 #ifdef SIGHUP 00847 jabber_signal(SIGHUP, _s2s_signal_hup); 00848 #endif 00849 #ifdef SIGPIPE 00850 jabber_signal(SIGPIPE, SIG_IGN); 00851 #endif 00852 jabber_signal(SIGUSR1, _s2s_signal_usr1); 00853 jabber_signal(SIGUSR2, _s2s_signal_usr2); 00854 00855 00856 s2s = (s2s_t) calloc(1, sizeof(struct s2s_st)); 00857 00858 /* load our config */ 00859 s2s->config = config_new(); 00860 00861 config_file = CONFIG_DIR "/s2s.xml"; 00862 00863 /* cmdline parsing */ 00864 while((optchar = getopt(argc, argv, "Dc:hi:?")) >= 0) 00865 { 00866 switch(optchar) 00867 { 00868 case 'c': 00869 config_file = optarg; 00870 break; 00871 case 'D': 00872 #ifdef DEBUG 00873 set_debug_flag(1); 00874 #else 00875 printf("WARN: Debugging not enabled. Ignoring -D.\n"); 00876 #endif 00877 break; 00878 case 'i': 00879 cli_id = optarg; 00880 break; 00881 case 'h': case '?': default: 00882 fputs( 00883 "s2s - jabberd server-to-server connector (" VERSION ")\n" 00884 "Usage: s2s <options>\n" 00885 "Options are:\n" 00886 " -c <config> config file to use [default: " CONFIG_DIR "/s2s.xml]\n" 00887 " -i id Override <id> config element\n" 00888 #ifdef DEBUG 00889 " -D Show debug output\n" 00890 #endif 00891 , 00892 stdout); 00893 config_free(s2s->config); 00894 free(s2s); 00895 return 1; 00896 } 00897 } 00898 00899 if(config_load_with_id(s2s->config, config_file, cli_id) != 0) { 00900 fputs("s2s: couldn't load config, aborting\n", stderr); 00901 config_free(s2s->config); 00902 free(s2s); 00903 return 2; 00904 } 00905 00906 _s2s_config_expand(s2s); 00907 00908 s2s->log = log_new(s2s->log_type, s2s->log_ident, s2s->log_facility); 00909 log_write(s2s->log, LOG_NOTICE, "starting up (interval=%i, queue=%i, keepalive=%i, idle=%i)", s2s->check_interval, s2s->check_queue, s2s->check_keepalive, s2s->check_idle); 00910 00911 _s2s_pidfile(s2s); 00912 00913 s2s->outq = xhash_new(401); 00914 s2s->out_host = xhash_new(401); 00915 s2s->out_dest = xhash_new(401); 00916 s2s->in = xhash_new(401); 00917 s2s->in_accept = xhash_new(401); 00918 s2s->dnscache = xhash_new(401); 00919 s2s->dns_bad = xhash_new(401); 00920 00921 s2s->dead = jqueue_new(); 00922 s2s->dead_conn = jqueue_new(); 00923 00924 s2s->sx_env = sx_env_new(); 00925 00926 #ifdef HAVE_SSL 00927 /* get the ssl context up and running */ 00928 if(s2s->local_pemfile != NULL) { 00929 s2s->sx_ssl = sx_env_plugin(s2s->sx_env, sx_ssl_init, NULL, s2s->local_pemfile, s2s->local_cachain, s2s->local_verify_mode); 00930 00931 if(s2s->sx_ssl == NULL) { 00932 log_write(s2s->log, LOG_ERR, "failed to load local SSL pemfile, SSL will not be available to peers"); 00933 s2s->local_pemfile = NULL; 00934 } else 00935 log_debug(ZONE, "loaded pemfile for SSL connections to peers"); 00936 } 00937 00938 /* try and get something online, so at least we can encrypt to the router */ 00939 if(s2s->sx_ssl == NULL && s2s->router_pemfile != NULL) { 00940 s2s->sx_ssl = sx_env_plugin(s2s->sx_env, sx_ssl_init, NULL, s2s->router_pemfile, NULL, NULL); 00941 if(s2s->sx_ssl == NULL) { 00942 log_write(s2s->log, LOG_ERR, "failed to load router SSL pemfile, channel to router will not be SSL encrypted"); 00943 s2s->router_pemfile = NULL; 00944 } 00945 } 00946 #endif 00947 00948 #ifdef HAVE_LIBZ 00949 /* get compression up and running */ 00950 if(s2s->compression) 00951 sx_env_plugin(s2s->sx_env, sx_compress_init); 00952 #endif 00953 00954 /* get sasl online */ 00955 s2s->sx_sasl = sx_env_plugin(s2s->sx_env, sx_sasl_init, "xmpp", NULL, NULL); 00956 if(s2s->sx_sasl == NULL) { 00957 log_write(s2s->log, LOG_ERR, "failed to initialise SASL context, aborting"); 00958 exit(1); 00959 } 00960 00961 /* hosts mapping */ 00962 s2s->hosts = xhash_new(1021); 00963 _s2s_hosts_expand(s2s); 00964 00965 s2s->sx_db = sx_env_plugin(s2s->sx_env, s2s_db_init); 00966 00967 s2s->mio = mio_new(s2s->io_max_fds); 00968 00969 if((s2s->udns_fd = dns_init(NULL, 1)) < 0) { 00970 log_write(s2s->log, LOG_ERR, "unable to initialize dns library, aborting"); 00971 exit(1); 00972 } 00973 s2s->udns_mio_fd = mio_register(s2s->mio, s2s->udns_fd, _mio_resolver_callback, (void *) s2s); 00974 00975 s2s->retry_left = s2s->retry_init; 00976 _s2s_router_connect(s2s); 00977 00978 while(!s2s_shutdown) { 00979 mio_run(s2s->mio, dns_timeouts(0, 5, time(NULL))); 00980 00981 now = time(NULL); 00982 00983 if(s2s_logrotate) { 00984 set_debug_log_from_config(s2s->config); 00985 00986 log_write(s2s->log, LOG_NOTICE, "reopening log ..."); 00987 log_free(s2s->log); 00988 s2s->log = log_new(s2s->log_type, s2s->log_ident, s2s->log_facility); 00989 log_write(s2s->log, LOG_NOTICE, "log started"); 00990 00991 s2s_logrotate = 0; 00992 } 00993 00994 if(s2s_lost_router) { 00995 if(s2s->retry_left < 0) { 00996 log_write(s2s->log, LOG_NOTICE, "attempting reconnect"); 00997 sleep(s2s->retry_sleep); 00998 s2s_lost_router = 0; 00999 if (s2s->router) sx_free(s2s->router); 01000 _s2s_router_connect(s2s); 01001 } 01002 01003 else if(s2s->retry_left == 0) { 01004 s2s_shutdown = 1; 01005 } 01006 01007 else { 01008 log_write(s2s->log, LOG_NOTICE, "attempting reconnect (%d left)", s2s->retry_left); 01009 s2s->retry_left--; 01010 sleep(s2s->retry_sleep); 01011 s2s_lost_router = 0; 01012 if (s2s->router) sx_free(s2s->router); 01013 _s2s_router_connect(s2s); 01014 } 01015 } 01016 01017 /* this has to be read unconditionally - we could receive replies to queries we cancelled */ 01018 mio_read(s2s->mio, s2s->udns_mio_fd); 01019 01020 /* cleanup dead sx_ts */ 01021 while(jqueue_size(s2s->dead) > 0) 01022 sx_free((sx_t) jqueue_pull(s2s->dead)); 01023 01024 /* cleanup dead conn_ts */ 01025 while(jqueue_size(s2s->dead_conn) > 0) { 01026 conn = (conn_t) jqueue_pull(s2s->dead_conn); 01027 xhash_free(conn->states); 01028 xhash_free(conn->states_time); 01029 xhash_free(conn->routes); 01030 01031 free(conn->key); 01032 free(conn->dkey); 01033 free(conn); 01034 } 01035 01036 /* time checks */ 01037 if(s2s->check_interval > 0 && now >= s2s->next_check) { 01038 log_debug(ZONE, "running time checks"); 01039 01040 _s2s_time_checks(s2s); 01041 01042 s2s->next_check = now + s2s->check_interval; 01043 log_debug(ZONE, "next time check at %d", s2s->next_check); 01044 } 01045 01046 /* dnscache expiry */ 01047 if(s2s->check_dnscache > 0 && now >= s2s->next_expiry) { 01048 log_debug(ZONE, "running dns expiry"); 01049 01050 _s2s_dns_expiry(s2s); 01051 01052 s2s->next_expiry = now + s2s->check_dnscache; 01053 log_debug(ZONE, "next dns expiry at %d", s2s->next_expiry); 01054 } 01055 01056 if(now > check_time + 60) { 01057 #ifdef POOL_DEBUG 01058 pool_stat(1); 01059 #endif 01060 if(s2s->packet_stats != NULL) { 01061 int fd = open(s2s->packet_stats, O_TRUNC | O_CREAT | O_WRONLY, S_IRUSR | S_IWUSR | S_IRGRP); 01062 if(fd) { 01063 char buf[100]; 01064 int len = snprintf(buf, 100, "%lld\n", s2s->packet_count); 01065 write(fd, buf, len); 01066 close(fd); 01067 } else { 01068 log_write(s2s->log, LOG_ERR, "failed to write packet statistics to: %s", s2s->packet_stats); 01069 s2s_shutdown = 1; 01070 } 01071 } 01072 01073 check_time = now; 01074 } 01075 } 01076 01077 log_write(s2s->log, LOG_NOTICE, "shutting down"); 01078 01079 /* close active streams gracefully */ 01080 xhv.conn_val = &conn; 01081 if(s2s->out_reuse) { 01082 if(xhash_iter_first(s2s->out_host)) 01083 do { 01084 xhash_iter_get(s2s->out_host, NULL, NULL, xhv.val); 01085 if(conn) { 01086 sx_error(conn->s, stream_err_SYSTEM_SHUTDOWN, "s2s shutdown"); 01087 out_bounce_conn_queues(conn, stanza_err_SERVICE_UNAVAILABLE); 01088 sx_close(conn->s); 01089 } 01090 } while(xhash_iter_next(s2s->out_host)); 01091 } else { 01092 if(xhash_iter_first(s2s->out_dest)) 01093 do { 01094 xhash_iter_get(s2s->out_dest, NULL, NULL, xhv.val); 01095 if(conn) { 01096 sx_error(conn->s, stream_err_SYSTEM_SHUTDOWN, "s2s shutdown"); 01097 out_bounce_conn_queues(conn, stanza_err_SERVICE_UNAVAILABLE); 01098 sx_close(conn->s); 01099 } 01100 } while(xhash_iter_next(s2s->out_dest)); 01101 } 01102 01103 if(xhash_iter_first(s2s->in)) 01104 do { 01105 xhash_iter_get(s2s->in, NULL, NULL, xhv.val); 01106 if(conn) { 01107 sx_error(conn->s, stream_err_SYSTEM_SHUTDOWN, "s2s shutdown"); 01108 out_bounce_conn_queues(conn, stanza_err_SERVICE_UNAVAILABLE); 01109 sx_close(conn->s); 01110 } 01111 } while(xhash_iter_next(s2s->in)); 01112 01113 if(xhash_iter_first(s2s->in_accept)) 01114 do { 01115 xhash_iter_get(s2s->in_accept, NULL, NULL, xhv.val); 01116 if(conn) { 01117 out_bounce_conn_queues(conn, stanza_err_SERVICE_UNAVAILABLE); 01118 sx_close(conn->s); 01119 } 01120 } while(xhash_iter_next(s2s->in_accept)); 01121 01122 01123 /* remove dead streams */ 01124 while(jqueue_size(s2s->dead) > 0) 01125 sx_free((sx_t) jqueue_pull(s2s->dead)); 01126 01127 /* cleanup dead conn_ts */ 01128 while(jqueue_size(s2s->dead_conn) > 0) { 01129 conn = (conn_t) jqueue_pull(s2s->dead_conn); 01130 xhash_free(conn->states); 01131 xhash_free(conn->states_time); 01132 xhash_free(conn->routes); 01133 01134 if(conn->key != NULL) free(conn->key); 01135 if(conn->dkey != NULL) free(conn->dkey); 01136 free(conn); 01137 } 01138 01139 /* free outgoing queues */ 01140 xhv.jq_val = &q; 01141 if(xhash_iter_first(s2s->outq)) 01142 do { 01143 xhash_iter_get(s2s->outq, NULL, NULL, xhv.val); 01144 while (jqueue_size(q) > 0) 01145 out_pkt_free((pkt_t) jqueue_pull(q)); 01146 free(q->key); 01147 jqueue_free(q); 01148 } while(xhash_iter_next(s2s->outq)); 01149 01150 /* walk & free resolve queues */ 01151 xhv.dns_val = &dns; 01152 if(xhash_iter_first(s2s->dnscache)) 01153 do { 01154 xhash_iter_get(s2s->dnscache, NULL, NULL, xhv.val); 01155 xhash_free(dns->results); 01156 if (dns->query != NULL) { 01157 if (dns->query->query != NULL) 01158 dns_cancel(NULL, dns->query->query); 01159 xhash_free(dns->query->hosts); 01160 xhash_free(dns->query->results); 01161 free(dns->query->name); 01162 free(dns->query); 01163 } 01164 free(dns); 01165 } while(xhash_iter_next(s2s->dnscache)); 01166 01167 xhv.dnsres_val = &res; 01168 if(xhash_iter_first(s2s->dns_bad)) 01169 do { 01170 xhash_iter_get(s2s->dns_bad, NULL, NULL, xhv.val); 01171 free(res->key); 01172 free(res); 01173 } while(xhash_iter_next(s2s->dns_bad)); 01174 01175 if (dns_active(NULL) > 0) 01176 log_debug(ZONE, "there are still active dns queries (%d)", dns_active(NULL)); 01177 dns_close(NULL); 01178 01179 /* close mio */ 01180 mio_close(s2s->mio, s2s->udns_mio_fd); 01181 if(s2s->fd != NULL) 01182 mio_close(s2s->mio, s2s->fd); 01183 if(s2s->server_fd != NULL) 01184 mio_close(s2s->mio, s2s->server_fd); 01185 01186 /* free hashes */ 01187 xhash_free(s2s->outq); 01188 xhash_free(s2s->out_host); 01189 xhash_free(s2s->out_dest); 01190 xhash_free(s2s->in); 01191 xhash_free(s2s->in_accept); 01192 xhash_free(s2s->dnscache); 01193 xhash_free(s2s->dns_bad); 01194 xhash_free(s2s->hosts); 01195 01196 jqueue_free(s2s->dead); 01197 jqueue_free(s2s->dead_conn); 01198 01199 sx_free(s2s->router); 01200 01201 sx_env_free(s2s->sx_env); 01202 01203 mio_free(s2s->mio); 01204 01205 log_free(s2s->log); 01206 01207 config_free(s2s->config); 01208 01209 free(s2s->local_secret); 01210 free(s2s); 01211 01212 #ifdef POOL_DEBUG 01213 pool_stat(1); 01214 #endif 01215 01216 return 0; 01217 }