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 #define _GNU_SOURCE 00022 #include <string.h> 00023 00024 #include "s2s.h" 00025 00026 #include <idna.h> 00027 00028 /* 00029 * we handle packets going from the router to the world, and stuff 00030 * that comes in on connections we initiated. 00031 * 00032 * action points: 00033 * 00034 * out_packet(s2s, nad) - send this packet out 00035 * - extract to domain 00036 * - get dbconn for this domain using out_route 00037 * - if dbconn not available bounce packet 00038 * - DONE 00039 * - if conn in progress (tcp) 00040 * - add packet to queue for this domain 00041 * - DONE 00042 * - if dbconn state valid for this domain, or packet is dialback 00043 * - send packet 00044 * - DONE 00045 * - if dbconn state invalid for this domain 00046 * - bounce packet (502) 00047 * - DONE 00048 * - add packet to queue for this domain 00049 * - if dbconn state inprogress for this domain 00050 * - DONE 00051 * - out_dialback(dbconn, from, to) 00052 * 00053 * out_route(s2s, route, out, allow_bad) 00054 * - if dbconn not found 00055 * - check internal resolver cache for domain 00056 * - if not found 00057 * - ask resolver for name 00058 * - DONE 00059 * - if outgoing ip/port is to be reused 00060 * - get dbconn for any valid ip/port 00061 * - if dbconn not found 00062 * - create new dbconn 00063 * - initiate connect to ip/port 00064 * - DONE 00065 * - create new dbconn 00066 * - initiate connect to ip/port 00067 * - DONE 00068 * 00069 * out_dialback(dbconn, from, to) - initiate dialback 00070 * - generate dbkey: sha1(secret+remote+stream id) 00071 * - send auth request: <result to='them' from='us'>dbkey</result> 00072 * - set dbconn state for this domain to inprogress 00073 * - DONE 00074 * 00075 * out_resolve(s2s, query) - responses from resolver 00076 * - store ip/port/ttl in resolver cache 00077 * - flush domain queue -> out_packet(s2s, domain) 00078 * - DONE 00079 * 00080 * event_STREAM - ip/port open 00081 * - get dbconn for this sx 00082 * - for each route handled by this conn, out_dialback(dbconn, from, to) 00083 * - DONE 00084 * 00085 * event_PACKET: <result from='them' to='us' type='xxx'/> - response to our auth request 00086 * - get dbconn for this sx 00087 * - if type valid 00088 * - set dbconn state for this domain to valid 00089 * - flush dbconn queue for this domain -> out_packet(s2s, pkt) 00090 * - DONE 00091 * - set dbconn state for this domain to invalid 00092 * - bounce dbconn queue for this domain (502) 00093 * - DONE 00094 * 00095 * event_PACKET: <verify from='them' to='us' id='123' type='xxx'/> - incoming stream authenticated 00096 * - get dbconn for given id 00097 * - if type is valid 00098 * - set dbconn state for this domain to valid 00099 * - send result: <result to='them' from='us' type='xxx'/> 00100 * - DONE 00101 */ 00102 00103 /* forward decls */ 00104 static int _out_mio_callback(mio_t m, mio_action_t a, mio_fd_t fd, void *data, void *arg); 00105 static int _out_sx_callback(sx_t s, sx_event_t e, void *data, void *arg); 00106 static void _out_result(conn_t out, nad_t nad); 00107 static void _out_verify(conn_t out, nad_t nad); 00108 static void _dns_result_aaaa(struct dns_ctx *ctx, struct dns_rr_a6 *result, void *data); 00109 static void _dns_result_a(struct dns_ctx *ctx, struct dns_rr_a4 *result, void *data); 00110 00112 static void _out_packet_queue(s2s_t s2s, pkt_t pkt) { 00113 char *rkey = s2s_route_key(NULL, pkt->from->domain, pkt->to->domain); 00114 jqueue_t q = (jqueue_t) xhash_get(s2s->outq, rkey); 00115 00116 if(q == NULL) { 00117 log_debug(ZONE, "creating new out packet queue for '%s'", rkey); 00118 q = jqueue_new(); 00119 q->key = rkey; 00120 xhash_put(s2s->outq, q->key, (void *) q); 00121 } else { 00122 free(rkey); 00123 } 00124 00125 log_debug(ZONE, "queueing packet for '%s'", q->key); 00126 00127 jqueue_push(q, (void *) pkt, 0); 00128 } 00129 00130 static void _out_dialback(conn_t out, char *rkey, int rkeylen) { 00131 char *c, *dbkey, *tmp; 00132 nad_t nad; 00133 int elem, ns; 00134 int from_len, to_len; 00135 time_t now; 00136 00137 now = time(NULL); 00138 00139 c = memchr(rkey, '/', rkeylen); 00140 from_len = c - rkey; 00141 c++; 00142 to_len = rkeylen - (c - rkey); 00143 00144 /* kick off the dialback */ 00145 tmp = strndup(c, to_len); 00146 dbkey = s2s_db_key(NULL, out->s2s->local_secret, tmp, out->s->id); 00147 free(tmp); 00148 00149 nad = nad_new(); 00150 00151 /* request auth */ 00152 ns = nad_add_namespace(nad, uri_DIALBACK, "db"); 00153 elem = nad_append_elem(nad, ns, "result", 0); 00154 nad_set_attr(nad, elem, -1, "from", rkey, from_len); 00155 nad_set_attr(nad, elem, -1, "to", c, to_len); 00156 nad_append_cdata(nad, dbkey, strlen(dbkey), 1); 00157 00158 log_debug(ZONE, "sending auth request for %.*s (key %s)", rkeylen, rkey, dbkey); 00159 log_write(out->s2s->log, LOG_NOTICE, "[%d] [%s, port=%d] sending dialback auth request for route '%.*s'", out->fd->fd, out->ip, out->port, rkeylen, rkey); 00160 00161 /* off it goes */ 00162 sx_nad_write(out->s, nad); 00163 00164 free(dbkey); 00165 00166 /* we're in progress now */ 00167 xhash_put(out->states, pstrdupx(xhash_pool(out->states), rkey, rkeylen), (void *) conn_INPROGRESS); 00168 00169 /* record the time that we set conn_INPROGRESS state */ 00170 xhash_put(out->states_time, pstrdupx(xhash_pool(out->states_time), rkey, rkeylen), (void *) now); 00171 } 00172 00173 void _out_dns_mark_bad(conn_t out, char *ipport) { 00174 dnsres_t bad; 00175 int ipport_allocated = 0; 00176 00177 if (out->s2s->dns_bad_timeout > 0) { 00178 /* mark this host as bad */ 00179 if(ipport == NULL) { 00180 ipport_allocated = 1; 00181 ipport = dns_make_ipport(out->ip, out->port); 00182 } 00183 bad = xhash_get(out->s2s->dns_bad, ipport); 00184 if (bad == NULL) { 00185 bad = (dnsres_t) calloc(1, sizeof(struct dnsres_st)); 00186 bad->key = ipport; 00187 xhash_put(out->s2s->dns_bad, ipport, bad); 00188 } else if(ipport_allocated) { 00189 free(ipport); 00190 } 00191 bad->expiry = time(NULL) + out->s2s->dns_bad_timeout; 00192 } 00193 } 00194 00195 int dns_select(s2s_t s2s, char *ip, int *port, time_t now, dnscache_t dns, int allow_bad) { 00196 /* list of results */ 00197 dnsres_t l_reuse[DNS_MAX_RESULTS]; 00198 dnsres_t l_aaaa[DNS_MAX_RESULTS]; 00199 dnsres_t l_a[DNS_MAX_RESULTS]; 00200 dnsres_t l_bad[DNS_MAX_RESULTS]; 00201 /* running weight sums of results */ 00202 int rw_reuse[DNS_MAX_RESULTS]; 00203 int rw_aaaa[DNS_MAX_RESULTS]; 00204 int rw_a[DNS_MAX_RESULTS]; 00205 int s_reuse = 0, s_aaaa = 0, s_a = 0, s_bad = 0; /* count */ 00206 int p_reuse = 0, p_aaaa = 0, p_a = 0; /* list prio */ 00207 int wt_reuse = 0, wt_aaaa = 0, wt_a = 0; /* weight total */ 00208 int c_expired_good = 0; 00209 union xhashv xhv; 00210 dnsres_t res; 00211 char *ipport; 00212 int ipport_len; 00213 char *c; 00214 int c_len; 00215 char *tmp; 00216 00217 /* for all results: 00218 * - if not expired 00219 * - put highest priority reuseable addrs into list1 00220 * - put highest priority ipv6 addrs into list2 00221 * - put highest priority ipv4 addrs into list3 00222 * - put bad addrs into list4 00223 * - pick weighted random entry from first non-empty list 00224 */ 00225 00226 if (dns->results == NULL) { 00227 log_debug(ZONE, "negative cache entry for '%s'", dns->name); 00228 return -1; 00229 } 00230 log_debug(ZONE, "selecting DNS result for '%s'", dns->name); 00231 00232 xhv.dnsres_val = &res; 00233 if (xhash_iter_first(dns->results)) { 00234 dnsres_t bad = NULL; 00235 do { 00236 xhash_iter_get(dns->results, (const char **) &ipport, &ipport_len, xhv.val); 00237 00238 if (s2s->dns_bad_timeout > 0) 00239 bad = xhash_getx(s2s->dns_bad, ipport, ipport_len); 00240 00241 if (now > res->expiry) { 00242 /* good host? */ 00243 if (bad == NULL) 00244 c_expired_good++; 00245 00246 log_debug(ZONE, "host '%s' expired", res->key); 00247 continue; 00248 } else if (bad != NULL && !(now > bad->expiry)) { 00249 /* bad host (connection failure) */ 00250 l_bad[s_bad++] = res; 00251 00252 log_debug(ZONE, "host '%s' bad", res->key); 00253 } else if (s2s->out_reuse && xhash_getx(s2s->out_host, ipport, ipport_len) != NULL) { 00254 /* existing connection */ 00255 log_debug(ZONE, "host '%s' exists", res->key); 00256 if (s_reuse == 0 || p_reuse > res->prio) { 00257 p_reuse = res->prio; 00258 s_reuse = 0; 00259 wt_reuse = 0; 00260 00261 log_debug(ZONE, "reset prio list, using prio %d", res->prio); 00262 } 00263 if (res->prio <= p_reuse) { 00264 l_reuse[s_reuse] = res; 00265 wt_reuse += res->weight; 00266 rw_reuse[s_reuse] = wt_reuse; 00267 s_reuse++; 00268 00269 log_debug(ZONE, "added host with weight %d (%d), running weight %d", 00270 (res->weight >> 8), res->weight, wt_reuse); 00271 } else { 00272 log_debug(ZONE, "ignored host with prio %d", res->prio); 00273 } 00274 } else if (memchr(ipport, ':', ipport_len) != NULL) { 00275 /* ipv6 */ 00276 log_debug(ZONE, "host '%s' IPv6", res->key); 00277 if (s_aaaa == 0 || p_aaaa > res->prio) { 00278 p_aaaa = res->prio; 00279 s_aaaa = 0; 00280 wt_aaaa = 0; 00281 00282 log_debug(ZONE, "reset prio list, using prio %d", res->prio); 00283 } 00284 if (res->prio <= p_aaaa) { 00285 l_aaaa[s_aaaa] = res; 00286 wt_aaaa += res->weight; 00287 rw_aaaa[s_aaaa] = wt_aaaa; 00288 s_aaaa++; 00289 00290 log_debug(ZONE, "added host with weight %d (%d), running weight %d", 00291 (res->weight >> 8), res->weight, wt_aaaa); 00292 } else { 00293 log_debug(ZONE, "ignored host with prio %d", res->prio); 00294 } 00295 } else { 00296 /* ipv4 */ 00297 log_debug(ZONE, "host '%s' IPv4", res->key); 00298 if (s_a == 0 || p_a > res->prio) { 00299 p_a = res->prio; 00300 s_a = 0; 00301 wt_a = 0; 00302 00303 log_debug(ZONE, "reset prio list, using prio %d", res->prio); 00304 } 00305 if (res->prio <= p_a) { 00306 l_a[s_a] = res; 00307 wt_a += res->weight; 00308 rw_a[s_a] = wt_a; 00309 s_a++; 00310 00311 log_debug(ZONE, "added host with weight %d (%d), running weight %d", 00312 (res->weight >> 8), res->weight, wt_a); 00313 } else { 00314 log_debug(ZONE, "ignored host with prio %d", res->prio); 00315 } 00316 } 00317 } while(xhash_iter_next(dns->results)); 00318 } 00319 00320 /* pick a result at weighted random (RFC 2782) 00321 * all weights are guaranteed to be >= 16 && <= 16776960 00322 * (assuming max 50 hosts, the total/running sums won't exceed 2^31) 00323 */ 00324 ipport = NULL; 00325 if (s_reuse > 0) { 00326 int i, r; 00327 00328 log_debug(ZONE, "using existing hosts, total weight %d", wt_reuse); 00329 assert((wt_reuse + 1) > 0); 00330 00331 r = rand() % (wt_reuse + 1); 00332 log_debug(ZONE, "random number %d", r); 00333 00334 for (i = 0; i < s_reuse; i++) 00335 if (rw_reuse[i] >= r) { 00336 log_debug(ZONE, "selected host '%s', running weight %d", 00337 l_reuse[i]->key, rw_reuse[i]); 00338 00339 ipport = l_reuse[i]->key; 00340 break; 00341 } 00342 } else if (s_aaaa > 0 && (s_a == 0 || p_aaaa <= p_a)) { 00343 int i, r; 00344 00345 log_debug(ZONE, "using IPv6 hosts, total weight %d", wt_aaaa); 00346 assert((wt_aaaa + 1) > 0); 00347 00348 r = rand() % (wt_aaaa + 1); 00349 log_debug(ZONE, "random number %d", r); 00350 00351 for (i = 0; i < s_aaaa; i++) 00352 if (rw_aaaa[i] >= r) { 00353 log_debug(ZONE, "selected host '%s', running weight %d", 00354 l_aaaa[i]->key, rw_aaaa[i]); 00355 00356 ipport = l_aaaa[i]->key; 00357 break; 00358 } 00359 } else if (s_a > 0) { 00360 int i, r; 00361 00362 log_debug(ZONE, "using IPv4 hosts, total weight %d", wt_a); 00363 assert((wt_a + 1) > 0); 00364 00365 r = rand() % (wt_a + 1); 00366 log_debug(ZONE, "random number %d", r); 00367 00368 for (i = 0; i < s_a; i++) 00369 if (rw_a[i] >= r) { 00370 log_debug(ZONE, "selected host '%s', running weight %d", 00371 l_a[i]->key, rw_a[i]); 00372 00373 ipport = l_a[i]->key; 00374 break; 00375 } 00376 } else if (s_bad > 0) { 00377 ipport = l_bad[rand() % s_bad]->key; 00378 00379 log_debug(ZONE, "using bad hosts, allow_bad=%d", allow_bad); 00380 00381 /* there are expired good hosts, expire cache immediately */ 00382 if (c_expired_good > 0) { 00383 log_debug(ZONE, "expiring this DNS cache entry, %d expired hosts", 00384 c_expired_good); 00385 00386 dns->expiry = 0; 00387 } 00388 00389 if (!allow_bad) 00390 return -1; 00391 } 00392 00393 /* results cannot all expire before the collection does */ 00394 assert(ipport != NULL); 00395 00396 /* copy the ip and port to the packet */ 00397 ipport_len = strlen(ipport); 00398 c = strchr(ipport, '/'); 00399 strncpy(ip, ipport, c-ipport); 00400 ip[c-ipport] = '\0'; 00401 c++; 00402 c_len = ipport_len - (c - ipport); 00403 tmp = strndup(c, c_len); 00404 *port = atoi(tmp); 00405 free(tmp); 00406 00407 return 0; 00408 } 00409 00411 int out_route(s2s_t s2s, char *route, int routelen, conn_t *out, int allow_bad) { 00412 dnscache_t dns; 00413 char ipport[INET6_ADDRSTRLEN + 16], *dkey, *c; 00414 time_t now; 00415 int reuse = 0; 00416 char ip[INET6_ADDRSTRLEN] = {0}; 00417 int port, c_len, from_len; 00418 00419 c = memchr(route, '/', routelen); 00420 from_len = c - route; 00421 c++; 00422 c_len = routelen - (c - route); 00423 dkey = strndup(c, c_len); 00424 00425 log_debug(ZONE, "trying to find connection for '%s'", dkey); 00426 *out = (conn_t) xhash_get(s2s->out_dest, dkey); 00427 if(*out == NULL) { 00428 log_debug(ZONE, "connection for '%s' not found", dkey); 00429 00430 /* check resolver cache for ip/port */ 00431 dns = xhash_get(s2s->dnscache, dkey); 00432 if(dns == NULL) { 00433 /* new resolution */ 00434 log_debug(ZONE, "no dns for %s, preparing for resolution", dkey); 00435 00436 dns = (dnscache_t) calloc(1, sizeof(struct dnscache_st)); 00437 00438 strcpy(dns->name, dkey); 00439 00440 xhash_put(s2s->dnscache, dns->name, (void *) dns); 00441 00442 #if 0 00443 /* this is good for testing */ 00444 dns->pending = 0; 00445 strcpy(dns->ip, "127.0.0.1"); 00446 dns->port = 3000; 00447 dns->expiry = time(NULL) + 99999999; 00448 #endif 00449 } 00450 00451 /* resolution in progress */ 00452 if(dns->pending) { 00453 log_debug(ZONE, "pending resolution"); 00454 free(dkey); 00455 return 0; 00456 } 00457 00458 /* has it expired (this is 0 for new cache objects, so they're always expired */ 00459 now = time(NULL); /* each entry must be expired no earlier than the collection */ 00460 if(now > dns->expiry) { 00461 /* resolution required */ 00462 log_debug(ZONE, "requesting resolution for %s", dkey); 00463 00464 dns->init_time = time(NULL); 00465 dns->pending = 1; 00466 00467 dns_resolve_domain(s2s, dns); 00468 free(dkey); 00469 return 0; 00470 } 00471 00472 /* dns is valid */ 00473 if (dns_select(s2s, ip, &port, now, dns, allow_bad)) { 00474 /* failed to find anything acceptable */ 00475 free(dkey); 00476 return -1; 00477 } 00478 00479 /* re-request resolution if dns_select expired the data */ 00480 if (now > dns->expiry) { 00481 /* resolution required */ 00482 log_debug(ZONE, "requesting resolution for %s", dkey); 00483 00484 dns->init_time = time(NULL); 00485 dns->pending = 1; 00486 00487 dns_resolve_domain(s2s, dns); 00488 00489 free(dkey); 00490 return 0; 00491 } 00492 00493 /* generate the ip/port pair, this is the hash key for the conn */ 00494 snprintf(ipport, INET6_ADDRSTRLEN + 16, "%s/%d", ip, port); 00495 00496 /* try to re-use an existing connection */ 00497 if (s2s->out_reuse) 00498 *out = (conn_t) xhash_get(s2s->out_host, ipport); 00499 00500 if (*out != NULL) { 00501 log_write(s2s->log, LOG_NOTICE, "[%d] [%s, port=%d] using connection for '%s'", (*out)->fd->fd, (*out)->ip, (*out)->port, dkey); 00502 00503 /* associate existing connection with domain */ 00504 xhash_put(s2s->out_dest, s2s->out_reuse ? pstrdup(xhash_pool((*out)->routes), dkey) : dkey, (void *) *out); 00505 00506 reuse = 1; 00507 } else{ 00508 /* no conn, create one */ 00509 *out = (conn_t) calloc(1, sizeof(struct conn_st)); 00510 00511 (*out)->s2s = s2s; 00512 00513 (*out)->key = strdup(ipport); 00514 if (s2s->out_reuse) 00515 (*out)->dkey = NULL; 00516 else 00517 (*out)->dkey = dkey; 00518 00519 strcpy((*out)->ip, ip); 00520 (*out)->port = port; 00521 00522 (*out)->states = xhash_new(101); 00523 (*out)->states_time = xhash_new(101); 00524 00525 (*out)->routes = xhash_new(101); 00526 00527 (*out)->init_time = time(NULL); 00528 00529 if (s2s->out_reuse) 00530 xhash_put(s2s->out_host, (*out)->key, (void *) *out); 00531 xhash_put(s2s->out_dest, s2s->out_reuse ? pstrdup(xhash_pool((*out)->routes), dkey) : dkey, (void *) *out); 00532 00533 xhash_put((*out)->routes, pstrdupx(xhash_pool((*out)->routes), route, routelen), (void *) 1); 00534 00535 /* connect */ 00536 log_debug(ZONE, "initiating connection to %s", ipport); 00537 00538 /* APPLE: multiple origin_ips may be specified; use IPv6 if possible or otherwise IPv4 */ 00539 int ip_is_v6 = 0; 00540 if (strchr(ip, ':') != NULL) 00541 ip_is_v6 = 1; 00542 int i; 00543 for (i = 0; i < s2s->origin_nips; i++) { 00544 // only bother with mio_connect if the src and dst IPs are of the same type 00545 if ((ip_is_v6 && (strchr(s2s->origin_ips[i], ':') != NULL)) || // both are IPv6 00546 (! ip_is_v6 && (strchr(s2s->origin_ips[i], ':') == NULL))) // both are IPv4 00547 (*out)->fd = mio_connect(s2s->mio, port, ip, s2s->origin_ips[i], _out_mio_callback, (void *) *out); 00548 00549 if ((*out)->fd != NULL) break; 00550 } 00551 00552 if ((*out)->fd == NULL) { 00553 log_write(s2s->log, LOG_NOTICE, "[%d] [%s, port=%d] mio_connect error: %s (%d)", -1, (*out)->ip, (*out)->port, MIO_STRERROR(MIO_ERROR), MIO_ERROR); 00554 00555 _out_dns_mark_bad(*out, ipport); 00556 00557 if (s2s->out_reuse) 00558 xhash_zap(s2s->out_host, (*out)->key); 00559 xhash_zap(s2s->out_dest, dkey); 00560 00561 xhash_free((*out)->states); 00562 xhash_free((*out)->states_time); 00563 00564 xhash_free((*out)->routes); 00565 00566 free((*out)->key); 00567 free((*out)->dkey); 00568 free(*out); 00569 *out = NULL; 00570 00571 /* try again without allowing bad hosts */ 00572 return out_route(s2s, route, routelen, out, 0); 00573 } else { 00574 log_write(s2s->log, LOG_NOTICE, "[%d] [%s, port=%d] outgoing connection for '%s'", (*out)->fd->fd, (*out)->ip, (*out)->port, dkey); 00575 00576 (*out)->s = sx_new(s2s->sx_env, (*out)->fd->fd, _out_sx_callback, (void *) *out); 00577 00578 #ifdef HAVE_SSL 00579 /* Send a stream version of 1.0 if we can do STARTTLS */ 00580 if(s2s->sx_ssl != NULL) { 00581 sx_client_init((*out)->s, S2S_DB_HEADER, uri_SERVER, dkey, pstrdupx(xhash_pool((*out)->routes), route, from_len), "1.0"); 00582 } else { 00583 sx_client_init((*out)->s, S2S_DB_HEADER, uri_SERVER, NULL, NULL, NULL); 00584 } 00585 #else 00586 sx_client_init((*out)->s, S2S_DB_HEADER, uri_SERVER, NULL, NULL, NULL); 00587 #endif 00588 /* dkey is now used by the hash table */ 00589 return 0; 00590 } 00591 } 00592 } else { 00593 log_debug(ZONE, "connection for '%s' found (%d %s/%d)", dkey, (*out)->fd->fd, (*out)->ip, (*out)->port); 00594 } 00595 00596 /* connection in progress, or re-using connection: add to routes list */ 00597 if (!(*out)->online || reuse) { 00598 if (xhash_getx((*out)->routes, route, routelen) == NULL) 00599 xhash_put((*out)->routes, pstrdupx(xhash_pool((*out)->routes), route, routelen), (void *) 1); 00600 } 00601 00602 free(dkey); 00603 return 0; 00604 } 00605 00606 void out_pkt_free(pkt_t pkt) 00607 { 00608 nad_free(pkt->nad); 00609 jid_free(pkt->from); 00610 jid_free(pkt->to); 00611 free(pkt); 00612 } 00613 00615 int out_packet(s2s_t s2s, pkt_t pkt) { 00616 char *rkey; 00617 int rkeylen; 00618 conn_t out; 00619 conn_state_t state; 00620 int ret; 00621 00622 /* perform check against whitelist */ 00623 if (s2s->enable_whitelist > 0 && 00624 (pkt->to->domain != NULL) && 00625 (s2s_domain_in_whitelist(s2s, pkt->to->domain) == 0)) { 00626 log_write(s2s->log, LOG_NOTICE, "sending a packet to domain not in the whitelist, dropping it"); 00627 if (pkt->to != NULL) 00628 jid_free(pkt->to); 00629 if (pkt->from != NULL) 00630 jid_free(pkt->from); 00631 if (pkt->nad != NULL) 00632 nad_free(pkt->nad); 00633 free(pkt); 00634 00635 return; 00636 } 00637 00638 /* new route key */ 00639 rkey = s2s_route_key(NULL, pkt->from->domain, pkt->to->domain); 00640 rkeylen = strlen(rkey); 00641 00642 /* get a connection */ 00643 ret = out_route(s2s, rkey, rkeylen, &out, 1); 00644 00645 if (out == NULL) { 00646 /* connection not available, queue packet */ 00647 _out_packet_queue(s2s, pkt); 00648 00649 /* check if out_route was successful in attempting a connection */ 00650 if (ret) { 00651 /* bounce queue */ 00652 out_bounce_route_queue(s2s, rkey, rkeylen, stanza_err_SERVICE_UNAVAILABLE); 00653 00654 free(rkey); 00655 return -1; 00656 } 00657 00658 free(rkey); 00659 return 0; 00660 } 00661 00662 /* connection in progress */ 00663 if(!out->online) { 00664 log_debug(ZONE, "connection in progress, queueing packet"); 00665 00666 _out_packet_queue(s2s, pkt); 00667 00668 free(rkey); 00669 return 0; 00670 } 00671 00672 /* connection state */ 00673 state = (conn_state_t) xhash_get(out->states, rkey); 00674 00675 /* valid conns or dialback packets */ 00676 if(state == conn_VALID || pkt->db) { 00677 log_debug(ZONE, "writing packet for %s to outgoing conn %d", rkey, out->fd->fd); 00678 00679 /* send it straight out */ 00680 if(pkt->db) { 00681 /* if this is a db:verify packet, increment counter and set timestamp */ 00682 if(NAD_ENAME_L(pkt->nad, 0) == 6 && strncmp("verify", NAD_ENAME(pkt->nad, 0), 6) == 0) { 00683 out->verify++; 00684 out->last_verify = time(NULL); 00685 } 00686 00687 /* dialback packet */ 00688 sx_nad_write(out->s, pkt->nad); 00689 } else { 00690 /* if the outgoing stanza has a jabber:client namespace, remove it so that the stream jabber:server namespaces will apply (XMPP 11.2.2) */ 00691 int ns = nad_find_namespace(pkt->nad, 1, uri_CLIENT, NULL); 00692 if(ns >= 0) { 00693 /* clear the namespaces of elem 0 (internal route element) and elem 1 (message|iq|presence) */ 00694 pkt->nad->elems[0].ns = -1; 00695 pkt->nad->elems[0].my_ns = -1; 00696 pkt->nad->elems[1].ns = -1; 00697 pkt->nad->elems[1].my_ns = -1; 00698 } 00699 00700 /* send it out */ 00701 sx_nad_write_elem(out->s, pkt->nad, 1); 00702 } 00703 00704 /* update timestamp */ 00705 out->last_packet = time(NULL); 00706 00707 jid_free(pkt->from); 00708 jid_free(pkt->to); 00709 free(pkt); 00710 00711 free(rkey); 00712 return 0; 00713 } 00714 00715 /* can't be handled yet, queue */ 00716 _out_packet_queue(s2s, pkt); 00717 00718 /* if dialback is in progress, then we're done for now */ 00719 if(state == conn_INPROGRESS) { 00720 free(rkey); 00721 return 0; 00722 } 00723 00724 /* this is a new route - send dialback auth request to piggyback on the existing connection */ 00725 if (out->s2s->require_tls == 0 || out->s->ssf > 0) { 00726 _out_dialback(out, rkey, rkeylen); 00727 } 00728 free(rkey); 00729 return 0; 00730 } 00731 00732 char *dns_make_ipport(char *host, int port) { 00733 char *c; 00734 assert(port > 0 && port < 65536); 00735 00736 c = (char *) malloc(strlen(host) + 7); 00737 sprintf(c, "%s/%d", host, port); 00738 return c; 00739 } 00740 00741 static void _dns_add_result(dnsquery_t query, char *ip, int port, int prio, int weight, unsigned int ttl) { 00742 char *ipport = dns_make_ipport(ip, port); 00743 dnsres_t res = xhash_get(query->results, ipport); 00744 00745 if (res != NULL) { 00746 if (prio < res->prio) 00747 res->prio = prio; 00748 00749 if (prio < res->prio) { 00750 /* duplicate host at lower prio - reset weight */ 00751 res->weight = weight; 00752 } else if (prio == res->prio) { 00753 /* duplicate host at same prio - add to weight */ 00754 res->weight += weight; 00755 if (res->weight > (65535 << 8)) 00756 res->weight = (65535 << 8); 00757 } 00758 00759 if (ttl > res->expiry) 00760 res->expiry = ttl; 00761 00762 if (ttl > query->expiry) 00763 query->expiry = ttl; 00764 00765 log_debug(ZONE, "dns result updated for %s@%p: %s (%d/%d/%d)", query->name, query, ipport, 00766 res->prio, (res->weight >> 8), res->expiry); 00767 } else if (xhash_count(query->results) < DNS_MAX_RESULTS) { 00768 res = pmalloc(xhash_pool(query->results), sizeof(struct dnsres_st)); 00769 res->key = pstrdup(xhash_pool(query->results), ipport); 00770 res->prio = prio; 00771 res->weight = weight; 00772 res->expiry = ttl; 00773 00774 if (ttl > query->expiry) 00775 query->expiry = ttl; 00776 00777 xhash_put(query->results, res->key, res); 00778 00779 log_debug(ZONE, "dns result added for %s@%p: %s (%d/%d/%d)", query->name, query, ipport, 00780 res->prio, (res->weight >> 8), res->expiry); 00781 } else { 00782 log_debug(ZONE, "dns result ignored for %s@%p: %s (%d/%d/%d)", query->name, query, ipport, 00783 prio, (weight >> 8), ttl); 00784 } 00785 00786 free(ipport); 00787 } 00788 00789 static void _dns_add_host(dnsquery_t query, char *ip, int port, int prio, int weight, unsigned int ttl) { 00790 char *ipport = dns_make_ipport(ip, port); 00791 dnsres_t res = xhash_get(query->hosts, ipport); 00792 00793 /* update host weights: 00794 * RFC 2482 "In the presence of records containing weights greater 00795 * than 0, records with weight 0 should have a very small chance of 00796 * being selected." 00797 * 0 -> 16 00798 * 1-65535 -> 256-16776960 00799 */ 00800 if (weight == 0) 00801 weight = 1 << 4; 00802 else 00803 weight <<= 8; 00804 00805 if (res != NULL) { 00806 if (prio < res->prio) 00807 res->prio = prio; 00808 00809 if (prio < res->prio) { 00810 /* duplicate host at lower prio - reset weight */ 00811 res->weight = weight; 00812 } else if (prio == res->prio) { 00813 /* duplicate host at same prio - add to weight */ 00814 res->weight += weight; 00815 if (res->weight > (65535 << 8)) 00816 res->weight = (65535 << 8); 00817 } 00818 00819 if (ttl > res->expiry) 00820 res->expiry = ttl; 00821 00822 log_debug(ZONE, "dns host updated for %s@%p: %s (%d/%d/%d)", query->name, query, ipport, 00823 res->prio, (res->weight >> 8), res->expiry); 00824 } else if (xhash_count(query->hosts) < DNS_MAX_RESULTS) { 00825 res = pmalloc(xhash_pool(query->hosts), sizeof(struct dnsres_st)); 00826 res->key = pstrdup(xhash_pool(query->hosts), ipport); 00827 res->prio = prio; 00828 res->weight = weight; 00829 res->expiry = ttl; 00830 00831 xhash_put(query->hosts, res->key, res); 00832 00833 log_debug(ZONE, "dns host added for %s@%p: %s (%d/%d/%d)", query->name, query, ipport, 00834 res->prio, (res->weight >> 8), res->expiry); 00835 } else { 00836 log_debug(ZONE, "dns host ignored for %s@%p: %s (%d/%d/%d)", query->name, query, ipport, 00837 prio, (weight >> 8), ttl); 00838 } 00839 00840 free(ipport); 00841 } 00842 00843 /* this function is called with a NULL ctx to start the SRV process */ 00844 static void _dns_result_srv(struct dns_ctx *ctx, struct dns_rr_srv *result, void *data) { 00845 dnsquery_t query = data; 00846 assert(query != NULL); 00847 query->query = NULL; 00848 00849 if (ctx != NULL && result == NULL) { 00850 log_debug(ZONE, "dns failure for %s@%p: SRV %s (%d)", query->name, query, 00851 query->s2s->lookup_srv[query->srv_i], dns_status(ctx)); 00852 } else if (result != NULL) { 00853 int i; 00854 00855 log_debug(ZONE, "dns response for %s@%p: SRV %s %d (%d)", query->name, query, 00856 result->dnssrv_qname, result->dnssrv_nrr, result->dnssrv_ttl); 00857 00858 for (i = 0; i < result->dnssrv_nrr; i++) { 00859 if (strlen(result->dnssrv_srv[i].name) > 0 00860 && result->dnssrv_srv[i].port > 0 00861 && result->dnssrv_srv[i].port < 65536) { 00862 log_debug(ZONE, "dns response for %s@%p: SRV %s[%d] %s/%d (%d/%d)", query->name, 00863 query, result->dnssrv_qname, i, 00864 result->dnssrv_srv[i].name, result->dnssrv_srv[i].port, 00865 result->dnssrv_srv[i].priority, result->dnssrv_srv[i].weight); 00866 00867 _dns_add_host(query, result->dnssrv_srv[i].name, 00868 result->dnssrv_srv[i].port, result->dnssrv_srv[i].priority, 00869 result->dnssrv_srv[i].weight, result->dnssrv_ttl); 00870 } 00871 } 00872 00873 free(result); 00874 } 00875 00876 /* check next SRV service name */ 00877 query->srv_i++; 00878 if (query->srv_i < query->s2s->lookup_nsrv) { 00879 log_debug(ZONE, "dns request for %s@%p: SRV %s", query->name, query, 00880 query->s2s->lookup_srv[query->srv_i]); 00881 00882 query->query = dns_submit_srv(NULL, query->name, query->s2s->lookup_srv[query->srv_i], "tcp", 00883 DNS_NOSRCH, _dns_result_srv, query); 00884 00885 /* if submit failed, call ourselves with a NULL result */ 00886 if (query->query == NULL) 00887 _dns_result_srv(ctx, NULL, query); 00888 } else { 00889 /* no more SRV records to check, resolve hosts */ 00890 if (xhash_count(query->hosts) > 0) { 00891 _dns_result_a(NULL, NULL, query); 00892 00893 /* no SRV records returned, resolve hostname */ 00894 } else { 00895 query->cur_host = strdup(query->name); 00896 query->cur_port = 5269; 00897 query->cur_prio = 0; 00898 query->cur_weight = 0; 00899 query->cur_expiry = 0; 00900 if (query->s2s->resolve_aaaa) { 00901 log_debug(ZONE, "dns request for %s@%p: AAAA %s", query->name, query, query->name); 00902 00903 query->query = dns_submit_a6(NULL, query->name, 00904 DNS_NOSRCH, _dns_result_aaaa, query); 00905 00906 /* if submit failed, call ourselves with a NULL result */ 00907 if (query->query == NULL) 00908 _dns_result_aaaa(ctx, NULL, query); 00909 } else { 00910 log_debug(ZONE, "dns request for %s@%p: A %s", query->name, query, query->name); 00911 00912 query->query = dns_submit_a4(NULL, query->name, 00913 DNS_NOSRCH, _dns_result_a, query); 00914 00915 /* if submit failed, call ourselves with a NULL result */ 00916 if (query->query == NULL) 00917 _dns_result_a(ctx, NULL, query); 00918 } 00919 } 00920 } 00921 } 00922 00923 static void _dns_result_aaaa(struct dns_ctx *ctx, struct dns_rr_a6 *result, void *data) { 00924 dnsquery_t query = data; 00925 char ip[INET6_ADDRSTRLEN]; 00926 int i; 00927 assert(query != NULL); 00928 query->query = NULL; 00929 00930 if (ctx != NULL && result == NULL) { 00931 log_debug(ZONE, "dns failure for %s@%p: AAAA %s (%d)", query->name, query, 00932 query->cur_host, dns_status(ctx)); 00933 } else if (result != NULL) { 00934 log_debug(ZONE, "dns response for %s@%p: AAAA %s %d (%d)", query->name, query, 00935 result->dnsa6_qname, result->dnsa6_nrr, result->dnsa6_ttl); 00936 00937 if (query->cur_expiry > 0 && result->dnsa6_ttl > query->cur_expiry) 00938 result->dnsa6_ttl = query->cur_expiry; 00939 00940 for (i = 0; i < result->dnsa6_nrr; i++) { 00941 if (inet_ntop(AF_INET6, &result->dnsa6_addr[i], ip, INET6_ADDRSTRLEN) != NULL) { 00942 log_debug(ZONE, "dns response for %s@%p: AAAA %s[%d] %s/%d", query->name, 00943 query, result->dnsa6_qname, i, ip, query->cur_port); 00944 00945 _dns_add_result(query, ip, query->cur_port, 00946 query->cur_prio, query->cur_weight, result->dnsa6_ttl); 00947 } 00948 } 00949 } 00950 00951 if (query->cur_host != NULL) { 00952 /* do ipv4 resolution too */ 00953 log_debug(ZONE, "dns request for %s@%p: A %s", query->name, query, query->cur_host); 00954 00955 query->query = dns_submit_a4(NULL, query->cur_host, 00956 DNS_NOSRCH, _dns_result_a, query); 00957 00958 /* if submit failed, call ourselves with a NULL result */ 00959 if (query->query == NULL) 00960 _dns_result_a(ctx, NULL, query); 00961 } else { 00962 /* uh-oh */ 00963 log_debug(ZONE, "dns result for %s@%p: AAAA host vanished...", query->name, query); 00964 _dns_result_a(NULL, NULL, query); 00965 } 00966 00967 free(result); 00968 } 00969 00970 /* try /etc/hosts if the A process did not return any results */ 00971 static int _etc_hosts_lookup(const char *cszName, char *szIP, const int ciMaxIPLen) { 00972 #define EHL_LINE_LEN 260 00973 int iSuccess = 0; 00974 size_t iLen; 00975 char szLine[EHL_LINE_LEN + 1]; /* one extra for the space character (*) */ 00976 char *pcStart, *pcEnd; 00977 FILE *fHosts; 00978 00979 do { 00980 /* initialization */ 00981 fHosts = NULL; 00982 00983 /* sanity checks */ 00984 if ((cszName == NULL) || (szIP == NULL) || (ciMaxIPLen <= 0)) 00985 break; 00986 szIP[0] = 0; 00987 00988 /* open the hosts file */ 00989 #ifdef _WIN32 00990 pcStart = getenv("WINDIR"); 00991 if (pcStart != NULL) { 00992 sprintf(szLine, "%s\\system32\\drivers\\etc\\hosts", pcStart); 00993 } else { 00994 strcpy(szLine, "C:\\WINDOWS\\system32\\drivers\\etc\\hosts"); 00995 } 00996 #else 00997 strcpy(szLine, "/etc/hosts"); 00998 #endif 00999 fHosts = fopen(szLine, "r"); 01000 if (fHosts == NULL) 01001 break; 01002 01003 /* read line by line ... */ 01004 while (fgets(szLine, EHL_LINE_LEN, fHosts) != NULL) { 01005 /* remove comments */ 01006 pcStart = strchr (szLine, '#'); 01007 if (pcStart != NULL) 01008 *pcStart = 0; 01009 strcat(szLine, " "); /* append a space character for easier parsing (*) */ 01010 01011 /* first to appear: IP address */ 01012 iLen = strspn(szLine, "1234567890."); 01013 if ((iLen < 7) || (iLen > 15)) /* superficial test for anything between x.x.x.x and xxx.xxx.xxx.xxx */ 01014 continue; 01015 pcEnd = szLine + iLen; 01016 *pcEnd = 0; 01017 pcEnd++; /* not beyond the end of the line yet (*) */ 01018 01019 /* check strings separated by blanks, tabs or newlines */ 01020 pcStart = pcEnd + strspn(pcEnd, " \t\n"); 01021 while (*pcStart != 0) { 01022 pcEnd = pcStart + strcspn(pcStart, " \t\n"); 01023 *pcEnd = 0; 01024 pcEnd++; /* not beyond the end of the line yet (*) */ 01025 01026 if (strcasecmp(pcStart, cszName) == 0) { 01027 strncpy(szIP, szLine, ciMaxIPLen - 1); 01028 szIP[ciMaxIPLen - 1] = '\0'; 01029 iSuccess = 1; 01030 break; 01031 } 01032 01033 pcStart = pcEnd + strspn(pcEnd, " \t\n"); 01034 } 01035 if (iSuccess) 01036 break; 01037 } 01038 } while (0); 01039 01040 if (fHosts != NULL) 01041 fclose(fHosts); 01042 01043 return (iSuccess); 01044 } 01045 01046 /* this function is called with a NULL ctx to start the A/AAAA process */ 01047 static void _dns_result_a(struct dns_ctx *ctx, struct dns_rr_a4 *result, void *data) { 01048 dnsquery_t query = data; 01049 assert(query != NULL); 01050 query->query = NULL; 01051 01052 if (ctx != NULL && result == NULL) { 01053 #define DRA_IP_LEN 16 01054 char szIP[DRA_IP_LEN]; 01055 if (_etc_hosts_lookup (query->name, szIP, DRA_IP_LEN)) { 01056 log_debug(ZONE, "/etc/lookup for %s@%p: %s (%d)", query->name, 01057 query, szIP, query->s2s->etc_hosts_ttl); 01058 01059 _dns_add_result (query, szIP, query->cur_port, 01060 query->cur_prio, query->cur_weight, query->s2s->etc_hosts_ttl); 01061 } else { 01062 log_debug(ZONE, "dns failure for %s@%p: A %s (%d)", query->name, query, 01063 query->cur_host, dns_status(ctx)); 01064 } 01065 } else if (result != NULL) { 01066 char ip[INET_ADDRSTRLEN]; 01067 int i; 01068 01069 log_debug(ZONE, "dns response for %s@%p: A %s %d (%d)", query->name, 01070 query, result->dnsa4_qname, result->dnsa4_nrr, result->dnsa4_ttl); 01071 01072 if (query->cur_expiry > 0 && result->dnsa4_ttl > query->cur_expiry) 01073 result->dnsa4_ttl = query->cur_expiry; 01074 01075 for (i = 0; i < result->dnsa4_nrr; i++) { 01076 if (inet_ntop(AF_INET, &result->dnsa4_addr[i], ip, INET_ADDRSTRLEN) != NULL) { 01077 log_debug(ZONE, "dns response for %s@%p: A %s[%d] %s/%d", query->name, 01078 query, result->dnsa4_qname, i, ip, query->cur_port); 01079 01080 _dns_add_result(query, ip, query->cur_port, 01081 query->cur_prio, query->cur_weight, result->dnsa4_ttl); 01082 } 01083 } 01084 01085 free(result); 01086 } 01087 01088 /* resolve the next host in the list */ 01089 if (xhash_iter_first(query->hosts)) { 01090 char *ipport, *c, *tmp; 01091 int ipport_len, ip_len, port_len; 01092 dnsres_t res; 01093 union xhashv xhv; 01094 01095 xhv.dnsres_val = &res; 01096 01097 /* get the first entry */ 01098 xhash_iter_get(query->hosts, (const char **) &ipport, &ipport_len, xhv.val); 01099 01100 /* remove the host from the list */ 01101 xhash_iter_zap(query->hosts); 01102 01103 c = memchr(ipport, '/', ipport_len); 01104 ip_len = c - ipport; 01105 c++; 01106 port_len = ipport_len - (c - ipport); 01107 01108 /* resolve hostname */ 01109 free(query->cur_host); 01110 query->cur_host = strndup(ipport, ip_len); 01111 tmp = strndup(c, port_len); 01112 query->cur_port = atoi(tmp); 01113 free(tmp); 01114 query->cur_prio = res->prio; 01115 query->cur_weight = res->weight; 01116 query->cur_expiry = res->expiry; 01117 log_debug(ZONE, "dns ttl for %s@%p limited to %d", query->name, query, query->cur_expiry); 01118 01119 if (query->s2s->resolve_aaaa) { 01120 log_debug(ZONE, "dns request for %s@%p: AAAA %s", query->name, query, query->cur_host); 01121 01122 query->query = dns_submit_a6(NULL, query->cur_host, DNS_NOSRCH, _dns_result_aaaa, query); 01123 01124 /* if submit failed, call ourselves with a NULL result */ 01125 if (query->query == NULL) 01126 _dns_result_aaaa(ctx, NULL, query); 01127 } else { 01128 log_debug(ZONE, "dns request for %s@%p: A %s", query->name, query, query->cur_host); 01129 01130 query->query = dns_submit_a4(NULL, query->cur_host, DNS_NOSRCH, _dns_result_a, query); 01131 01132 /* if submit failed, call ourselves with a NULL result */ 01133 if (query->query == NULL) 01134 _dns_result_a(ctx, NULL, query); 01135 } 01136 01137 /* finished */ 01138 } else { 01139 time_t now = time(NULL); 01140 char *domain; 01141 01142 free(query->cur_host); 01143 query->cur_host = NULL; 01144 01145 log_debug(ZONE, "dns requests for %s@%p complete: %d (%d)", query->name, 01146 query, xhash_count(query->results), query->expiry); 01147 01148 /* update query TTL */ 01149 if (query->expiry > query->s2s->dns_max_ttl) 01150 query->expiry = query->s2s->dns_max_ttl; 01151 01152 if (query->expiry < query->s2s->dns_min_ttl) 01153 query->expiry = query->s2s->dns_min_ttl; 01154 01155 query->expiry += now; 01156 01157 /* update result TTLs - the query expiry MUST NOT be longer than all result expiries */ 01158 if (xhash_iter_first(query->results)) { 01159 union xhashv xhv; 01160 dnsres_t res; 01161 01162 xhv.dnsres_val = &res; 01163 01164 do { 01165 xhash_iter_get(query->results, NULL, NULL, xhv.val); 01166 01167 if (res->expiry > query->s2s->dns_max_ttl) 01168 res->expiry = query->s2s->dns_max_ttl; 01169 01170 if (res->expiry < query->s2s->dns_min_ttl) 01171 res->expiry = query->s2s->dns_min_ttl; 01172 01173 res->expiry += now; 01174 } while(xhash_iter_next(query->results)); 01175 } 01176 01177 xhash_free(query->hosts); 01178 query->hosts = NULL; 01179 if (idna_to_unicode_8z8z(query->name, &domain, 0) != IDNA_SUCCESS) { 01180 log_write(query->s2s->log, LOG_ERR, "idna dns decode for %s failed", query->name); 01181 /* fake empty results to shortcut resolution failure */ 01182 xhash_free(query->results); 01183 query->results = xhash_new(71); 01184 query->expiry = time(NULL) + 99999999; 01185 domain = strdup(query->name); 01186 } 01187 out_resolve(query->s2s, domain, query->results, query->expiry); 01188 free(domain); 01189 free(query->name); 01190 free(query); 01191 } 01192 } 01193 01194 void dns_resolve_domain(s2s_t s2s, dnscache_t dns) { 01195 dnsquery_t query = (dnsquery_t) calloc(1, sizeof(struct dnsquery_st)); 01196 01197 query->s2s = s2s; 01198 query->results = xhash_new(71); 01199 if (idna_to_ascii_8z(dns->name, &query->name, 0) != IDNA_SUCCESS) { 01200 log_write(s2s->log, LOG_ERR, "idna dns encode for %s failed", dns->name); 01201 /* shortcut resolution failure */ 01202 query->expiry = time(NULL) + 99999999; 01203 out_resolve(query->s2s, dns->name, query->results, query->expiry); 01204 return; 01205 } 01206 query->hosts = xhash_new(71); 01207 query->srv_i = -1; 01208 query->expiry = 0; 01209 query->cur_host = NULL; 01210 query->cur_port = 0; 01211 query->cur_expiry = 0; 01212 query->query = NULL; 01213 dns->query = query; 01214 01215 log_debug(ZONE, "dns resolve for %s@%p started", query->name, query); 01216 01217 /* - resolve all SRV records to host/port 01218 * - if no results, include domain/5269 01219 * - resolve all host/port combinations 01220 * - return result 01221 */ 01222 _dns_result_srv(NULL, NULL, query); 01223 } 01224 01226 void out_resolve(s2s_t s2s, char *domain, xht results, time_t expiry) { 01227 dnscache_t dns; 01228 01229 /* no results, resolve failed */ 01230 if(xhash_count(results) == 0) { 01231 dns = xhash_get(s2s->dnscache, domain); 01232 if (dns != NULL) { 01233 /* store negative DNS cache */ 01234 xhash_free(dns->results); 01235 dns->query = NULL; 01236 dns->results = NULL; 01237 dns->expiry = expiry; 01238 dns->pending = 0; 01239 } 01240 01241 log_write(s2s->log, LOG_NOTICE, "dns lookup for %s failed", domain); 01242 01243 /* bounce queue */ 01244 out_bounce_domain_queues(s2s, domain, stanza_err_REMOTE_SERVER_NOT_FOUND); 01245 01246 xhash_free(results); 01247 return; 01248 } 01249 01250 log_write(s2s->log, LOG_NOTICE, "dns lookup for %s returned %d result%s (ttl %d)", 01251 domain, xhash_count(results), xhash_count(results)!=1?"s":"", expiry - time(NULL)); 01252 01253 /* get the cache entry */ 01254 dns = xhash_get(s2s->dnscache, domain); 01255 01256 if(dns == NULL) { 01257 /* retry using punycode */ 01258 char *punydomain; 01259 if (idna_to_ascii_8z(domain, &punydomain, 0) == IDNA_SUCCESS) { 01260 dns = xhash_get(s2s->dnscache, punydomain); 01261 free(punydomain); 01262 } 01263 } 01264 01265 if(dns == NULL) { 01266 log_write(s2s->log, LOG_ERR, "weird, never requested %s resolution", domain); 01267 return; 01268 } 01269 01270 /* fill it out */ 01271 xhash_free(dns->results); 01272 dns->query = NULL; 01273 dns->results = results; 01274 dns->expiry = expiry; 01275 dns->pending = 0; 01276 01277 out_flush_domain_queues(s2s, domain); 01278 01279 /* delete the cache entry if caching is disabled */ 01280 if (!s2s->dns_cache_enabled && !dns->pending) { 01281 xhash_free(dns->results); 01282 xhash_zap(s2s->dnscache, domain); 01283 free(dns); 01284 } 01285 } 01286 01288 static int _out_mio_callback(mio_t m, mio_action_t a, mio_fd_t fd, void *data, void *arg) { 01289 conn_t out = (conn_t) arg; 01290 char ipport[INET6_ADDRSTRLEN + 17]; 01291 int nbytes; 01292 01293 switch(a) { 01294 case action_READ: 01295 log_debug(ZONE, "read action on fd %d", fd->fd); 01296 01297 /* they did something */ 01298 out->last_activity = time(NULL); 01299 01300 ioctl(fd->fd, FIONREAD, &nbytes); 01301 if(nbytes == 0) { 01302 sx_kill(out->s); 01303 return 0; 01304 } 01305 01306 return sx_can_read(out->s); 01307 01308 case action_WRITE: 01309 log_debug(ZONE, "write action on fd %d", fd->fd); 01310 01311 /* update activity timestamp */ 01312 out->last_activity = time(NULL); 01313 01314 return sx_can_write(out->s); 01315 01316 case action_CLOSE: 01317 log_debug(ZONE, "close action on fd %d", fd->fd); 01318 01319 jqueue_push(out->s2s->dead, (void *) out->s, 0); 01320 01321 log_write(out->s2s->log, LOG_NOTICE, "[%d] [%s, port=%d] disconnect, packets: %i", fd->fd, out->ip, out->port, out->packet_count); 01322 01323 01324 if (out->s2s->out_reuse) { 01325 /* generate the ip/port pair */ 01326 snprintf(ipport, INET6_ADDRSTRLEN + 16, "%s/%d", out->ip, out->port); 01327 01328 xhash_zap(out->s2s->out_host, ipport); 01329 } 01330 01331 if (xhash_iter_first(out->routes)) { 01332 char *rkey; 01333 int rkeylen; 01334 char *c; 01335 int c_len; 01336 01337 /* remove all the out_dest entries */ 01338 do { 01339 xhash_iter_get(out->routes, (const char **) &rkey, &rkeylen, NULL); 01340 c = memchr(rkey, '/', rkeylen); 01341 c++; 01342 c_len = rkeylen - (c - rkey); 01343 01344 log_debug(ZONE, "route '%.*s'", rkeylen, rkey); 01345 if (xhash_getx(out->s2s->out_dest, c, c_len) != NULL) { 01346 log_debug(ZONE, "removing dest entry for '%.*s'", c_len, c); 01347 xhash_zapx(out->s2s->out_dest, c, c_len); 01348 } 01349 } while(xhash_iter_next(out->routes)); 01350 } 01351 01352 if (xhash_iter_first(out->routes)) { 01353 char *rkey; 01354 int rkeylen; 01355 jqueue_t q; 01356 int npkt; 01357 01358 /* retry all the routes */ 01359 do { 01360 xhash_iter_get(out->routes, (const char **) &rkey, &rkeylen, NULL); 01361 01362 q = xhash_getx(out->s2s->outq, rkey, rkeylen); 01363 if (out->s2s->retry_limit > 0 && q != NULL && jqueue_age(q) > out->s2s->retry_limit) { 01364 log_write(out->s2s->log, LOG_NOTICE, "[%d] [%s, port=%d] retry limit reached for '%.*s' queue", fd->fd, out->ip, out->port, rkeylen, rkey); 01365 q = NULL; 01366 } 01367 01368 if (q != NULL && (npkt = jqueue_size(q)) > 0 && xhash_get(out->states, rkey) != (void*) conn_INPROGRESS) { 01369 conn_t retry; 01370 01371 log_debug(ZONE, "retrying connection for '%.*s' queue", rkeylen, rkey); 01372 if (!out_route(out->s2s, rkey, rkeylen, &retry, 0)) { 01373 log_debug(ZONE, "retry successful"); 01374 01375 if (retry != NULL) { 01376 /* flush queue */ 01377 out_flush_route_queue(out->s2s, rkey, rkeylen); 01378 } 01379 } else { 01380 log_debug(ZONE, "retry failed"); 01381 01382 /* bounce queue */ 01383 out_bounce_route_queue(out->s2s, rkey, rkeylen, stanza_err_SERVICE_UNAVAILABLE); 01384 _out_dns_mark_bad(out, NULL); 01385 } 01386 } else { 01387 /* bounce queue */ 01388 out_bounce_route_queue(out->s2s, rkey, rkeylen, stanza_err_REMOTE_SERVER_TIMEOUT); 01389 _out_dns_mark_bad(out, NULL); 01390 } 01391 } while(xhash_iter_next(out->routes)); 01392 } 01393 01394 jqueue_push(out->s2s->dead_conn, (void *) out, 0); 01395 01396 case action_ACCEPT: 01397 break; 01398 } 01399 01400 return 0; 01401 } 01402 01403 void send_dialbacks(conn_t out) 01404 { 01405 char *rkey; 01406 int rkeylen; 01407 01408 if (out->s2s->dns_bad_timeout > 0) { 01409 dnsres_t bad = xhash_get(out->s2s->dns_bad, out->key); 01410 01411 if (bad != NULL) { 01412 log_debug(ZONE, "removing bad host entry for '%s'", out->key); 01413 xhash_zap(out->s2s->dns_bad, out->key); 01414 free(bad->key); 01415 free(bad); 01416 } 01417 } 01418 01419 if (xhash_iter_first(out->routes)) { 01420 log_debug(ZONE, "sending dialback packets for %s", out->key); 01421 do { 01422 xhash_iter_get(out->routes, (const char **) &rkey, &rkeylen, NULL); 01423 _out_dialback(out, rkey, rkeylen); 01424 } while(xhash_iter_next(out->routes)); 01425 } 01426 01427 return; 01428 } 01429 01430 static int _out_sx_callback(sx_t s, sx_event_t e, void *data, void *arg) { 01431 conn_t out = (conn_t) arg; 01432 sx_buf_t buf = (sx_buf_t) data; 01433 int len, ns, elem, starttls = 0; 01434 sx_error_t *sxe; 01435 nad_t nad; 01436 01437 switch(e) { 01438 case event_WANT_READ: 01439 log_debug(ZONE, "want read"); 01440 mio_read(out->s2s->mio, out->fd); 01441 break; 01442 01443 case event_WANT_WRITE: 01444 log_debug(ZONE, "want write"); 01445 mio_write(out->s2s->mio, out->fd); 01446 break; 01447 01448 case event_READ: 01449 log_debug(ZONE, "reading from %d", out->fd->fd); 01450 01451 /* do the read */ 01452 len = recv(out->fd->fd, buf->data, buf->len, 0); 01453 01454 if(len < 0) { 01455 if(MIO_WOULDBLOCK) { 01456 buf->len = 0; 01457 return 0; 01458 } 01459 01460 log_write(out->s2s->log, LOG_NOTICE, "[%d] [%s, port=%d] read error: %s (%d)", out->fd->fd, out->ip, out->port, MIO_STRERROR(MIO_ERROR), MIO_ERROR); 01461 01462 if (!out->online) { 01463 _out_dns_mark_bad(out, NULL); 01464 } 01465 01466 sx_kill(s); 01467 01468 return -1; 01469 } 01470 01471 else if(len == 0) { 01472 /* they went away */ 01473 sx_kill(s); 01474 01475 return -1; 01476 } 01477 01478 log_debug(ZONE, "read %d bytes", len); 01479 01480 buf->len = len; 01481 01482 return len; 01483 01484 case event_WRITE: 01485 log_debug(ZONE, "writing to %d", out->fd->fd); 01486 01487 len = send(out->fd->fd, buf->data, buf->len, 0); 01488 if(len >= 0) { 01489 log_debug(ZONE, "%d bytes written", len); 01490 return len; 01491 } 01492 01493 if(MIO_WOULDBLOCK) 01494 return 0; 01495 01496 log_write(out->s2s->log, LOG_NOTICE, "[%d] [%s, port=%d] write error: %s (%d)", out->fd->fd, out->ip, out->port, MIO_STRERROR(MIO_ERROR), MIO_ERROR); 01497 01498 if (!out->online) { 01499 _out_dns_mark_bad(out, NULL); 01500 } 01501 01502 sx_kill(s); 01503 01504 return -1; 01505 01506 case event_ERROR: 01507 sxe = (sx_error_t *) data; 01508 log_write(out->s2s->log, LOG_NOTICE, "[%d] [%s, port=%d] error: %s (%s)", out->fd->fd, out->ip, out->port, sxe->generic, sxe->specific); 01509 01510 /* mark as bad if we did not manage to connect or there is unrecoverable stream error */ 01511 if (!out->online || 01512 (sxe->code == SX_ERR_STREAM && 01513 (strstr(sxe->specific, "host-gone") || /* it's not there now */ 01514 strstr(sxe->specific, "host-unknown") || /* they do not service the host */ 01515 strstr(sxe->specific, "not-authorized") || /* they do not want us there */ 01516 strstr(sxe->specific, "see-other-host") || /* we do not support redirections yet */ 01517 strstr(sxe->specific, "system-shutdown") || /* they are going down */ 01518 strstr(sxe->specific, "policy-violation") || /* they do not want us there */ 01519 strstr(sxe->specific, "remote-connection-failed") || /* the required remote entity is gone */ 01520 strstr(sxe->specific, "unsupported-encoding") || /* they do not like our encoding */ 01521 strstr(sxe->specific, "undefined-condition") || /* something bad happend */ 01522 strstr(sxe->specific, "internal-server-error") || /* that server is broken */ 01523 strstr(sxe->specific, "unsupported-version") /* they do not support our stream version */ 01524 ))) { 01525 _out_dns_mark_bad(out, NULL); 01526 } 01527 01528 sx_kill(s); 01529 01530 return -1; 01531 01532 case event_OPEN: 01533 log_debug(ZONE, "OPEN event for %s", out->key); 01534 break; 01535 01536 case event_STREAM: 01537 /* check stream version - NULl = pre-xmpp (some jabber1 servers) */ 01538 log_debug(ZONE, "STREAM event for %s stream version is %s", out->key, out->s->res_version); 01539 01540 /* first time, bring them online */ 01541 if(!out->online) { 01542 log_debug(ZONE, "outgoing conn to %s is online", out->key); 01543 01544 /* if no stream version from either side, kick off dialback for each route, */ 01545 /* otherwise wait for stream features */ 01546 if (((out->s->res_version==NULL) || (out->s2s->sx_ssl == NULL)) && out->s2s->require_tls == 0) { 01547 log_debug(ZONE, "no stream version, sending dialbacks for %s immediately", out->key); 01548 out->online = 1; 01549 send_dialbacks(out); 01550 } else 01551 log_debug(ZONE, "outgoing conn to %s - waiting for STREAM features", out->key); 01552 } 01553 01554 break; 01555 01556 case event_PACKET: 01557 /* we're counting packets */ 01558 out->packet_count++; 01559 out->s2s->packet_count++; 01560 01561 nad = (nad_t) data; 01562 01563 /* watch for the features packet - STARTTLS and/or SASL*/ 01564 if ((out->s->res_version!=NULL) 01565 && NAD_NURI_L(nad, NAD_ENS(nad, 0)) == strlen(uri_STREAMS) 01566 && strncmp(uri_STREAMS, NAD_NURI(nad, NAD_ENS(nad, 0)), strlen(uri_STREAMS)) == 0 01567 && NAD_ENAME_L(nad, 0) == 8 && strncmp("features", NAD_ENAME(nad, 0), 8) == 0) { 01568 log_debug(ZONE, "got the stream features packet"); 01569 01570 #ifdef HAVE_SSL 01571 /* starttls if we can */ 01572 if(out->s2s->sx_ssl != NULL && s->ssf == 0) { 01573 ns = nad_find_scoped_namespace(nad, uri_TLS, NULL); 01574 if(ns >= 0) { 01575 elem = nad_find_elem(nad, 0, ns, "starttls", 1); 01576 if(elem >= 0) { 01577 log_debug(ZONE, "got STARTTLS in stream features"); 01578 if(sx_ssl_client_starttls(out->s2s->sx_ssl, s, out->s2s->local_pemfile) == 0) { 01579 starttls = 1; 01580 nad_free(nad); 01581 return 0; 01582 } 01583 log_write(out->s2s->log, LOG_ERR, "unable to establish encrypted session with peer"); 01584 } 01585 } 01586 } 01587 01588 /* If we're not establishing a starttls connection, send dialbacks */ 01589 if (!starttls) { 01590 if (out->s2s->require_tls == 0 || s->ssf > 0) { 01591 log_debug(ZONE, "No STARTTLS, sending dialbacks for %s", out->key); 01592 out->online = 1; 01593 send_dialbacks(out); 01594 } else { 01595 log_debug(ZONE, "No STARTTLS, dialbacks disabled for non-TLS connections, cannot complete negotiation"); 01596 } 01597 } 01598 #else 01599 if (out->s2s->require_tls == 0) { 01600 out->online = 1; 01601 send_dialbacks(out); 01602 } 01603 #endif 01604 } 01605 01606 01607 /* we only accept dialback packets */ 01608 if(NAD_ENS(nad, 0) < 0 || NAD_NURI_L(nad, NAD_ENS(nad, 0)) != uri_DIALBACK_L || strncmp(uri_DIALBACK, NAD_NURI(nad, NAD_ENS(nad, 0)), uri_DIALBACK_L) != 0) { 01609 log_debug(ZONE, "got a non-dialback packet on an outgoing conn, dropping it"); 01610 nad_free(nad); 01611 return 0; 01612 } 01613 01614 /* and then only result and verify */ 01615 if(NAD_ENAME_L(nad, 0) == 6) { 01616 if(strncmp("result", NAD_ENAME(nad, 0), 6) == 0) { 01617 _out_result(out, nad); 01618 return 0; 01619 } 01620 01621 if(strncmp("verify", NAD_ENAME(nad, 0), 6) == 0) { 01622 _out_verify(out, nad); 01623 return 0; 01624 } 01625 } 01626 01627 log_debug(ZONE, "unknown dialback packet, dropping it"); 01628 01629 nad_free(nad); 01630 return 0; 01631 01632 case event_CLOSED: 01633 if (out->fd != NULL) { 01634 mio_close(out->s2s->mio, out->fd); 01635 out->fd = NULL; 01636 } 01637 return -1; 01638 } 01639 01640 return 0; 01641 } 01642 01644 static void _out_result(conn_t out, nad_t nad) { 01645 int attr; 01646 jid_t from, to; 01647 char *rkey; 01648 int rkeylen; 01649 01650 attr = nad_find_attr(nad, 0, -1, "from", NULL); 01651 if(attr < 0 || (from = jid_new(NAD_AVAL(nad, attr), NAD_AVAL_L(nad, attr))) == NULL) { 01652 log_debug(ZONE, "missing or invalid from on db result packet"); 01653 nad_free(nad); 01654 return; 01655 } 01656 01657 attr = nad_find_attr(nad, 0, -1, "to", NULL); 01658 if(attr < 0 || (to = jid_new(NAD_AVAL(nad, attr), NAD_AVAL_L(nad, attr))) == NULL) { 01659 log_debug(ZONE, "missing or invalid to on db result packet"); 01660 jid_free(from); 01661 nad_free(nad); 01662 return; 01663 } 01664 01665 rkey = s2s_route_key(NULL, to->domain, from->domain); 01666 rkeylen = strlen(rkey); 01667 01668 /* key is valid */ 01669 if(nad_find_attr(nad, 0, -1, "type", "valid") >= 0) { 01670 log_write(out->s2s->log, LOG_NOTICE, "[%d] [%s, port=%d] outgoing route '%s' is now valid%s%s", out->fd->fd, out->ip, out->port, rkey, (out->s->flags & SX_SSL_WRAPPER) ? ", TLS negotiated" : "", out->s->compressed ? ", ZLIB compression enabled" : ""); 01671 01672 xhash_put(out->states, pstrdup(xhash_pool(out->states), rkey), (void *) conn_VALID); /* !!! small leak here */ 01673 01674 log_debug(ZONE, "%s valid, flushing queue", rkey); 01675 01676 /* flush the queue */ 01677 out_flush_route_queue(out->s2s, rkey, rkeylen); 01678 01679 free(rkey); 01680 01681 jid_free(from); 01682 jid_free(to); 01683 01684 nad_free(nad); 01685 01686 return; 01687 } 01688 01689 /* invalid */ 01690 log_write(out->s2s->log, LOG_NOTICE, "[%d] [%s, port=%d] outgoing route '%s' is now invalid", out->fd->fd, out->ip, out->port, rkey); 01691 01692 /* close connection */ 01693 log_write(out->s2s->log, LOG_NOTICE, "[%d] [%s, port=%d] closing connection", out->fd->fd, out->ip, out->port); 01694 01695 /* report stream error */ 01696 sx_error(out->s, stream_err_INVALID_ID, "dialback negotiation failed"); 01697 01698 /* close the stream */ 01699 sx_close(out->s); 01700 01701 /* bounce queue */ 01702 out_bounce_route_queue(out->s2s, rkey, rkeylen, stanza_err_SERVICE_UNAVAILABLE); 01703 01704 free(rkey); 01705 01706 jid_free(from); 01707 jid_free(to); 01708 01709 nad_free(nad); 01710 } 01711 01713 static void _out_verify(conn_t out, nad_t nad) { 01714 int attr, ns; 01715 jid_t from, to; 01716 conn_t in; 01717 char *rkey; 01718 int valid; 01719 01720 attr = nad_find_attr(nad, 0, -1, "from", NULL); 01721 if(attr < 0 || (from = jid_new(NAD_AVAL(nad, attr), NAD_AVAL_L(nad, attr))) == NULL) { 01722 log_debug(ZONE, "missing or invalid from on db verify packet"); 01723 nad_free(nad); 01724 return; 01725 } 01726 01727 attr = nad_find_attr(nad, 0, -1, "to", NULL); 01728 if(attr < 0 || (to = jid_new(NAD_AVAL(nad, attr), NAD_AVAL_L(nad, attr))) == NULL) { 01729 log_debug(ZONE, "missing or invalid to on db verify packet"); 01730 jid_free(from); 01731 nad_free(nad); 01732 return; 01733 } 01734 01735 attr = nad_find_attr(nad, 0, -1, "id", NULL); 01736 if(attr < 0) { 01737 log_debug(ZONE, "missing id on db verify packet"); 01738 jid_free(from); 01739 jid_free(to); 01740 nad_free(nad); 01741 return; 01742 } 01743 01744 /* get the incoming conn */ 01745 in = xhash_getx(out->s2s->in, NAD_AVAL(nad, attr), NAD_AVAL_L(nad, attr)); 01746 if(in == NULL) { 01747 log_debug(ZONE, "got a verify for incoming conn %.*s, but it doesn't exist, dropping the packet", NAD_AVAL_L(nad, attr), NAD_AVAL(nad, attr)); 01748 jid_free(from); 01749 jid_free(to); 01750 nad_free(nad); 01751 return; 01752 } 01753 01754 rkey = s2s_route_key(NULL, to->domain, from->domain); 01755 01756 attr = nad_find_attr(nad, 0, -1, "type", "valid"); 01757 if(attr >= 0) { 01758 xhash_put(in->states, pstrdup(xhash_pool(in->states), rkey), (void *) conn_VALID); 01759 log_write(in->s2s->log, LOG_NOTICE, "[%d] [%s, port=%d] incoming route '%s' is now valid%s%s", in->fd->fd, in->ip, in->port, rkey, (in->s->flags & SX_SSL_WRAPPER) ? ", TLS negotiated" : "", in->s->compressed ? ", ZLIB compression enabled" : ""); 01760 valid = 1; 01761 } else { 01762 log_write(in->s2s->log, LOG_NOTICE, "[%d] [%s, port=%d] incoming route '%s' is now invalid", in->fd->fd, in->ip, in->port, rkey); 01763 valid = 0; 01764 } 01765 01766 free(rkey); 01767 01768 nad_free(nad); 01769 01770 /* decrement outstanding verify counter */ 01771 --out->verify; 01772 01773 /* let them know what happened */ 01774 nad = nad_new(); 01775 01776 ns = nad_add_namespace(nad, uri_DIALBACK, "db"); 01777 nad_append_elem(nad, ns, "result", 0); 01778 nad_append_attr(nad, -1, "to", from->domain); 01779 nad_append_attr(nad, -1, "from", to->domain); 01780 nad_append_attr(nad, -1, "type", valid ? "valid" : "invalid"); 01781 01782 /* off it goes */ 01783 sx_nad_write(in->s, nad); 01784 01785 /* if invalid, close the stream */ 01786 if (!valid) { 01787 /* generate stream error */ 01788 sx_error(in->s, stream_err_INVALID_ID, "dialback negotiation failed"); 01789 01790 /* close the incoming stream */ 01791 sx_close(in->s); 01792 } 01793 01794 jid_free(from); 01795 jid_free(to); 01796 } 01797 01798 /* bounce all packets in the queues for domain */ 01799 int out_bounce_domain_queues(s2s_t s2s, const char *domain, int err) 01800 { 01801 char *rkey; 01802 int rkeylen; 01803 int pktcount = 0; 01804 01805 if (xhash_iter_first(s2s->outq)) { 01806 do { 01807 xhash_iter_get(s2s->outq, (const char **) &rkey, &rkeylen, NULL); 01808 if(s2s_route_key_match(NULL, (char *) domain, rkey, rkeylen)) 01809 pktcount += out_bounce_route_queue(s2s, rkey, rkeylen, err); 01810 } while(xhash_iter_next(s2s->outq)); 01811 } 01812 01813 return pktcount; 01814 } 01815 01816 /* bounce all packets in the queue for route */ 01817 int out_bounce_route_queue(s2s_t s2s, char *rkey, int rkeylen, int err) 01818 { 01819 jqueue_t q; 01820 pkt_t pkt; 01821 int pktcount = 0; 01822 01823 q = xhash_getx(s2s->outq, rkey, rkeylen); 01824 if(q == NULL) 01825 return 0; 01826 01827 while((pkt = jqueue_pull(q)) != NULL) { 01828 /* only packets with content, in namespace jabber:client and not already errors */ 01829 if(pkt->nad->ecur > 1 && NAD_NURI_L(pkt->nad, NAD_ENS(pkt->nad, 1)) == strlen(uri_CLIENT) && strncmp(NAD_NURI(pkt->nad, NAD_ENS(pkt->nad, 1)), uri_CLIENT, strlen(uri_CLIENT)) == 0 && nad_find_attr(pkt->nad, 0, -1, "error", NULL) < 0) { 01830 sx_nad_write(s2s->router, stanza_tofrom(stanza_tofrom(stanza_error(pkt->nad, 1, err), 1), 0)); 01831 pktcount++; 01832 } 01833 else 01834 nad_free(pkt->nad); 01835 01836 jid_free(pkt->to); 01837 jid_free(pkt->from); 01838 free(pkt); 01839 } 01840 01841 /* delete queue and remove domain from queue hash */ 01842 log_debug(ZONE, "deleting out packet queue for %.*s", rkeylen, rkey); 01843 rkey = q->key; 01844 jqueue_free(q); 01845 xhash_zap(s2s->outq, rkey); 01846 free(rkey); 01847 01848 return pktcount; 01849 } 01850 01851 int out_bounce_conn_queues(conn_t out, int err) 01852 { 01853 char *rkey; 01854 int rkeylen; 01855 int pktcount = 0; 01856 01857 /* bounce queues for all domains handled by this connection - iterate through routes */ 01858 if (xhash_iter_first(out->routes)) { 01859 do { 01860 xhash_iter_get(out->routes, (const char **) &rkey, &rkeylen, NULL); 01861 pktcount += out_bounce_route_queue(out->s2s, rkey, rkeylen, err); 01862 } while(xhash_iter_next(out->routes)); 01863 } 01864 01865 return pktcount; 01866 } 01867 01868 void out_flush_domain_queues(s2s_t s2s, const char *domain) { 01869 char *rkey; 01870 int rkeylen; 01871 char *c; 01872 int c_len; 01873 01874 if (xhash_iter_first(s2s->outq)) { 01875 do { 01876 xhash_iter_get(s2s->outq, (const char **) &rkey, &rkeylen, NULL); 01877 c = memchr(rkey, '/', rkeylen); 01878 c++; 01879 c_len = rkeylen - (c - rkey); 01880 if (strncmp(domain, c, c_len) == 0) 01881 out_flush_route_queue(s2s, rkey, rkeylen); 01882 } while(xhash_iter_next(s2s->outq)); 01883 } 01884 } 01885 01886 void out_flush_route_queue(s2s_t s2s, char *rkey, int rkeylen) { 01887 jqueue_t q; 01888 pkt_t pkt; 01889 int npkt, i, ret; 01890 01891 q = xhash_getx(s2s->outq, rkey, rkeylen); 01892 if(q == NULL) 01893 return; 01894 01895 npkt = jqueue_size(q); 01896 log_debug(ZONE, "flushing %d packets for '%.*s' to out_packet", npkt, rkeylen, rkey); 01897 01898 for(i = 0; i < npkt; i++) { 01899 pkt = jqueue_pull(q); 01900 if(pkt) { 01901 ret = out_packet(s2s, pkt); 01902 if (ret) { 01903 /* uh-oh. the queue was deleted... 01904 q and pkt have been freed 01905 if q->key == rkey, rkey has also been freed */ 01906 return; 01907 } 01908 } 01909 } 01910 01911 /* delete queue for route and remove route from queue hash */ 01912 if (jqueue_size(q) == 0) { 01913 log_debug(ZONE, "deleting out packet queue for '%.*s'", rkeylen, rkey); 01914 rkey = q->key; 01915 jqueue_free(q); 01916 xhash_zap(s2s->outq, rkey); 01917 free(rkey); 01918 } else { 01919 log_debug(ZONE, "emptied queue gained more packets..."); 01920 } 01921 }