jabberd2  2.2.17
out.c
Go to the documentation of this file.
1 /*
2  * jabberd - Jabber Open Source Server
3  * Copyright (c) 2002 Jeremie Miller, Thomas Muldowney,
4  * Ryan Eatmon, Robert Norris
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA02111-1307USA
19  */
20 
21 #define _GNU_SOURCE
22 #include <string.h>
23 
24 #include "s2s.h"
25 
26 #include <idna.h>
27 
28 /*
29  * we handle packets going from the router to the world, and stuff
30  * that comes in on connections we initiated.
31  *
32  * action points:
33  *
34  * out_packet(s2s, nad) - send this packet out
35  * - extract to domain
36  * - get dbconn for this domain using out_route
37  * - if dbconn not available bounce packet
38  * - DONE
39  * - if conn in progress (tcp)
40  * - add packet to queue for this domain
41  * - DONE
42  * - if dbconn state valid for this domain, or packet is dialback
43  * - send packet
44  * - DONE
45  * - if dbconn state invalid for this domain
46  * - bounce packet (502)
47  * - DONE
48  * - add packet to queue for this domain
49  * - if dbconn state inprogress for this domain
50  * - DONE
51  * - out_dialback(dbconn, from, to)
52  *
53  * out_route(s2s, route, out, allow_bad)
54  * - if dbconn not found
55  * - check internal resolver cache for domain
56  * - if not found
57  * - ask resolver for name
58  * - DONE
59  * - if outgoing ip/port is to be reused
60  * - get dbconn for any valid ip/port
61  * - if dbconn not found
62  * - create new dbconn
63  * - initiate connect to ip/port
64  * - DONE
65  * - create new dbconn
66  * - initiate connect to ip/port
67  * - DONE
68  *
69  * out_dialback(dbconn, from, to) - initiate dialback
70  * - generate dbkey: sha1(secret+remote+stream id)
71  * - send auth request: <result to='them' from='us'>dbkey</result>
72  * - set dbconn state for this domain to inprogress
73  * - DONE
74  *
75  * out_resolve(s2s, query) - responses from resolver
76  * - store ip/port/ttl in resolver cache
77  * - flush domain queue -> out_packet(s2s, domain)
78  * - DONE
79  *
80  * event_STREAM - ip/port open
81  * - get dbconn for this sx
82  * - for each route handled by this conn, out_dialback(dbconn, from, to)
83  * - DONE
84  *
85  * event_PACKET: <result from='them' to='us' type='xxx'/> - response to our auth request
86  * - get dbconn for this sx
87  * - if type valid
88  * - set dbconn state for this domain to valid
89  * - flush dbconn queue for this domain -> out_packet(s2s, pkt)
90  * - DONE
91  * - set dbconn state for this domain to invalid
92  * - bounce dbconn queue for this domain (502)
93  * - DONE
94  *
95  * event_PACKET: <verify from='them' to='us' id='123' type='xxx'/> - incoming stream authenticated
96  * - get dbconn for given id
97  * - if type is valid
98  * - set dbconn state for this domain to valid
99  * - send result: <result to='them' from='us' type='xxx'/>
100  * - DONE
101  */
102 
103 /* forward decls */
104 static int _out_mio_callback(mio_t m, mio_action_t a, mio_fd_t fd, void *data, void *arg);
105 static int _out_sx_callback(sx_t s, sx_event_t e, void *data, void *arg);
106 static void _out_result(conn_t out, nad_t nad);
107 static void _out_verify(conn_t out, nad_t nad);
108 static void _dns_result_aaaa(struct dns_ctx *ctx, struct dns_rr_a6 *result, void *data);
109 static void _dns_result_a(struct dns_ctx *ctx, struct dns_rr_a4 *result, void *data);
110 
112 static void _out_packet_queue(s2s_t s2s, pkt_t pkt) {
113  char *rkey = s2s_route_key(NULL, pkt->from->domain, pkt->to->domain);
114  jqueue_t q = (jqueue_t) xhash_get(s2s->outq, rkey);
115 
116  if(q == NULL) {
117  log_debug(ZONE, "creating new out packet queue for '%s'", rkey);
118  q = jqueue_new();
119  q->key = rkey;
120  xhash_put(s2s->outq, q->key, (void *) q);
121  } else {
122  free(rkey);
123  }
124 
125  log_debug(ZONE, "queueing packet for '%s'", q->key);
126 
127  jqueue_push(q, (void *) pkt, 0);
128 }
129 
130 static void _out_dialback(conn_t out, char *rkey, int rkeylen) {
131  char *c, *dbkey, *tmp;
132  nad_t nad;
133  int elem, ns;
134  int from_len, to_len;
135  time_t now;
136 
137  now = time(NULL);
138 
139  c = memchr(rkey, '/', rkeylen);
140  from_len = c - rkey;
141  c++;
142  to_len = rkeylen - (c - rkey);
143 
144  /* kick off the dialback */
145  tmp = strndup(c, to_len);
146  dbkey = s2s_db_key(NULL, out->s2s->local_secret, tmp, out->s->id);
147  free(tmp);
148 
149  nad = nad_new();
150 
151  /* request auth */
152  ns = nad_add_namespace(nad, uri_DIALBACK, "db");
153  elem = nad_append_elem(nad, ns, "result", 0);
154  nad_set_attr(nad, elem, -1, "from", rkey, from_len);
155  nad_set_attr(nad, elem, -1, "to", c, to_len);
156  nad_append_cdata(nad, dbkey, strlen(dbkey), 1);
157 
158  log_debug(ZONE, "sending auth request for %.*s (key %s)", rkeylen, rkey, dbkey);
159  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);
160 
161  /* off it goes */
162  sx_nad_write(out->s, nad);
163 
164  free(dbkey);
165 
166  /* we're in progress now */
167  xhash_put(out->states, pstrdupx(xhash_pool(out->states), rkey, rkeylen), (void *) conn_INPROGRESS);
168 
169  /* record the time that we set conn_INPROGRESS state */
170  xhash_put(out->states_time, pstrdupx(xhash_pool(out->states_time), rkey, rkeylen), (void *) now);
171 }
172 
174  if (out->s2s->dns_bad_timeout > 0) {
175  dnsres_t bad;
176  char *ipport;
177 
178  /* mark this host as bad */
179  ipport = dns_make_ipport(out->ip, out->port);
180  bad = xhash_get(out->s2s->dns_bad, ipport);
181  if (bad == NULL) {
182  bad = (dnsres_t) calloc(1, sizeof(struct dnsres_st));
183  bad->key = ipport;
184  xhash_put(out->s2s->dns_bad, ipport, bad);
185  }
186  bad->expiry = time(NULL) + out->s2s->dns_bad_timeout;
187  }
188 }
189 
190 int dns_select(s2s_t s2s, char *ip, int *port, time_t now, dnscache_t dns, int allow_bad) {
191  /* list of results */
192  dnsres_t l_reuse[DNS_MAX_RESULTS];
193  dnsres_t l_aaaa[DNS_MAX_RESULTS];
195  dnsres_t l_bad[DNS_MAX_RESULTS];
196  /* running weight sums of results */
197  int rw_reuse[DNS_MAX_RESULTS];
198  int rw_aaaa[DNS_MAX_RESULTS];
199  int rw_a[DNS_MAX_RESULTS];
200  int s_reuse = 0, s_aaaa = 0, s_a = 0, s_bad = 0; /* count */
201  int p_reuse = 0, p_aaaa = 0, p_a = 0; /* list prio */
202  int wt_reuse = 0, wt_aaaa = 0, wt_a = 0; /* weight total */
203  int c_expired_good = 0;
204  union xhashv xhv;
205  dnsres_t res;
206  char *ipport;
207  int ipport_len;
208  char *c;
209  int c_len;
210  char *tmp;
211 
212  /* for all results:
213  * - if not expired
214  * - put highest priority reuseable addrs into list1
215  * - put highest priority ipv6 addrs into list2
216  * - put highest priority ipv4 addrs into list3
217  * - put bad addrs into list4
218  * - pick weighted random entry from first non-empty list
219  */
220 
221  if (dns->results == NULL) {
222  log_debug(ZONE, "negative cache entry for '%s'", dns->name);
223  return -1;
224  }
225  log_debug(ZONE, "selecting DNS result for '%s'", dns->name);
226 
227  xhv.dnsres_val = &res;
228  if (xhash_iter_first(dns->results)) {
229  dnsres_t bad = NULL;
230  do {
231  xhash_iter_get(dns->results, (const char **) &ipport, &ipport_len, xhv.val);
232 
233  if (s2s->dns_bad_timeout > 0)
234  bad = xhash_getx(s2s->dns_bad, ipport, ipport_len);
235 
236  if (now > res->expiry) {
237  /* good host? */
238  if (bad == NULL)
239  c_expired_good++;
240 
241  log_debug(ZONE, "host '%s' expired", res->key);
242  continue;
243  } else if (bad != NULL && !(now > bad->expiry)) {
244  /* bad host (connection failure) */
245  l_bad[s_bad++] = res;
246 
247  log_debug(ZONE, "host '%s' bad", res->key);
248  } else if (s2s->out_reuse && xhash_getx(s2s->out_host, ipport, ipport_len) != NULL) {
249  /* existing connection */
250  log_debug(ZONE, "host '%s' exists", res->key);
251  if (s_reuse == 0 || p_reuse > res->prio) {
252  p_reuse = res->prio;
253  s_reuse = 0;
254  wt_reuse = 0;
255 
256  log_debug(ZONE, "reset prio list, using prio %d", res->prio);
257  }
258  if (res->prio <= p_reuse) {
259  l_reuse[s_reuse] = res;
260  wt_reuse += res->weight;
261  rw_reuse[s_reuse] = wt_reuse;
262  s_reuse++;
263 
264  log_debug(ZONE, "added host with weight %d (%d), running weight %d",
265  (res->weight >> 8), res->weight, wt_reuse);
266  } else {
267  log_debug(ZONE, "ignored host with prio %d", res->prio);
268  }
269  } else if (memchr(ipport, ':', ipport_len) != NULL) {
270  /* ipv6 */
271  log_debug(ZONE, "host '%s' IPv6", res->key);
272  if (s_aaaa == 0 || p_aaaa > res->prio) {
273  p_aaaa = res->prio;
274  s_aaaa = 0;
275  wt_aaaa = 0;
276 
277  log_debug(ZONE, "reset prio list, using prio %d", res->prio);
278  }
279  if (res->prio <= p_aaaa) {
280  l_aaaa[s_aaaa] = res;
281  wt_aaaa += res->weight;
282  rw_aaaa[s_aaaa] = wt_aaaa;
283  s_aaaa++;
284 
285  log_debug(ZONE, "added host with weight %d (%d), running weight %d",
286  (res->weight >> 8), res->weight, wt_aaaa);
287  } else {
288  log_debug(ZONE, "ignored host with prio %d", res->prio);
289  }
290  } else {
291  /* ipv4 */
292  log_debug(ZONE, "host '%s' IPv4", res->key);
293  if (s_a == 0 || p_a > res->prio) {
294  p_a = res->prio;
295  s_a = 0;
296  wt_a = 0;
297 
298  log_debug(ZONE, "reset prio list, using prio %d", res->prio);
299  }
300  if (res->prio <= p_a) {
301  l_a[s_a] = res;
302  wt_a += res->weight;
303  rw_a[s_a] = wt_a;
304  s_a++;
305 
306  log_debug(ZONE, "added host with weight %d (%d), running weight %d",
307  (res->weight >> 8), res->weight, wt_a);
308  } else {
309  log_debug(ZONE, "ignored host with prio %d", res->prio);
310  }
311  }
312  } while(xhash_iter_next(dns->results));
313  }
314 
315  /* pick a result at weighted random (RFC 2782)
316  * all weights are guaranteed to be >= 16 && <= 16776960
317  * (assuming max 50 hosts, the total/running sums won't exceed 2^31)
318  */
319  ipport = NULL;
320  if (s_reuse > 0) {
321  int i, r;
322 
323  log_debug(ZONE, "using existing hosts, total weight %d", wt_reuse);
324  assert((wt_reuse + 1) > 0);
325 
326  r = rand() % (wt_reuse + 1);
327  log_debug(ZONE, "random number %d", r);
328 
329  for (i = 0; i < s_reuse; i++)
330  if (rw_reuse[i] >= r) {
331  log_debug(ZONE, "selected host '%s', running weight %d",
332  l_reuse[i]->key, rw_reuse[i]);
333 
334  ipport = l_reuse[i]->key;
335  break;
336  }
337  } else if (s_aaaa > 0 && (s_a == 0 || p_aaaa <= p_a)) {
338  int i, r;
339 
340  log_debug(ZONE, "using IPv6 hosts, total weight %d", wt_aaaa);
341  assert((wt_aaaa + 1) > 0);
342 
343  r = rand() % (wt_aaaa + 1);
344  log_debug(ZONE, "random number %d", r);
345 
346  for (i = 0; i < s_aaaa; i++)
347  if (rw_aaaa[i] >= r) {
348  log_debug(ZONE, "selected host '%s', running weight %d",
349  l_aaaa[i]->key, rw_aaaa[i]);
350 
351  ipport = l_aaaa[i]->key;
352  break;
353  }
354  } else if (s_a > 0) {
355  int i, r;
356 
357  log_debug(ZONE, "using IPv4 hosts, total weight %d", wt_a);
358  assert((wt_a + 1) > 0);
359 
360  r = rand() % (wt_a + 1);
361  log_debug(ZONE, "random number %d", r);
362 
363  for (i = 0; i < s_a; i++)
364  if (rw_a[i] >= r) {
365  log_debug(ZONE, "selected host '%s', running weight %d",
366  l_a[i]->key, rw_a[i]);
367 
368  ipport = l_a[i]->key;
369  break;
370  }
371  } else if (s_bad > 0) {
372  ipport = l_bad[rand() % s_bad]->key;
373 
374  log_debug(ZONE, "using bad hosts, allow_bad=%d", allow_bad);
375 
376  /* there are expired good hosts, expire cache immediately */
377  if (c_expired_good > 0) {
378  log_debug(ZONE, "expiring this DNS cache entry, %d expired hosts",
379  c_expired_good);
380 
381  dns->expiry = 0;
382  }
383 
384  if (!allow_bad)
385  return -1;
386  }
387 
388  /* results cannot all expire before the collection does */
389  assert(ipport != NULL);
390 
391  /* copy the ip and port to the packet */
392  ipport_len = strlen(ipport);
393  c = strchr(ipport, '/');
394  strncpy(ip, ipport, c-ipport);
395  ip[c-ipport] = '\0';
396  c++;
397  c_len = ipport_len - (c - ipport);
398  tmp = strndup(c, c_len);
399  *port = atoi(tmp);
400  free(tmp);
401 
402  return 0;
403 }
404 
406 int out_route(s2s_t s2s, char *route, int routelen, conn_t *out, int allow_bad) {
407  dnscache_t dns;
408  char ipport[INET6_ADDRSTRLEN + 16], *dkey, *c;
409  time_t now;
410  int reuse = 0;
411  char ip[INET6_ADDRSTRLEN] = {0};
412  int port, c_len, from_len;
413 
414  c = memchr(route, '/', routelen);
415  from_len = c - route;
416  c++;
417  c_len = routelen - (c - route);
418  dkey = strndup(c, c_len);
419 
420  log_debug(ZONE, "trying to find connection for '%s'", dkey);
421  *out = (conn_t) xhash_get(s2s->out_dest, dkey);
422  if(*out == NULL) {
423  log_debug(ZONE, "connection for '%s' not found", dkey);
424 
425  /* check resolver cache for ip/port */
426  dns = xhash_get(s2s->dnscache, dkey);
427  if(dns == NULL) {
428  /* new resolution */
429  log_debug(ZONE, "no dns for %s, preparing for resolution", dkey);
430 
431  dns = (dnscache_t) calloc(1, sizeof(struct dnscache_st));
432 
433  strcpy(dns->name, dkey);
434 
435  xhash_put(s2s->dnscache, dns->name, (void *) dns);
436 
437 #if 0
438  /* this is good for testing */
439  dns->pending = 0;
440  strcpy(dns->ip, "127.0.0.1");
441  dns->port = 3000;
442  dns->expiry = time(NULL) + 99999999;
443 #endif
444  }
445 
446  /* resolution in progress */
447  if(dns->pending) {
448  log_debug(ZONE, "pending resolution");
449  free(dkey);
450  return 0;
451  }
452 
453  /* has it expired (this is 0 for new cache objects, so they're always expired */
454  now = time(NULL); /* each entry must be expired no earlier than the collection */
455  if(now > dns->expiry) {
456  /* resolution required */
457  log_debug(ZONE, "requesting resolution for %s", dkey);
458 
459  dns->init_time = time(NULL);
460  dns->pending = 1;
461 
462  dns_resolve_domain(s2s, dns);
463  free(dkey);
464  return 0;
465  }
466 
467  /* dns is valid */
468  if (dns_select(s2s, ip, &port, now, dns, allow_bad)) {
469  /* failed to find anything acceptable */
470  free(dkey);
471  return -1;
472  }
473 
474  /* re-request resolution if dns_select expired the data */
475  if (now > dns->expiry) {
476  /* resolution required */
477  log_debug(ZONE, "requesting resolution for %s", dkey);
478 
479  dns->init_time = time(NULL);
480  dns->pending = 1;
481 
482  dns_resolve_domain(s2s, dns);
483 
484  free(dkey);
485  return 0;
486  }
487 
488  /* generate the ip/port pair, this is the hash key for the conn */
489  snprintf(ipport, INET6_ADDRSTRLEN + 16, "%s/%d", ip, port);
490 
491  /* try to re-use an existing connection */
492  if (s2s->out_reuse)
493  *out = (conn_t) xhash_get(s2s->out_host, ipport);
494 
495  if (*out != NULL) {
496  log_write(s2s->log, LOG_NOTICE, "[%d] [%s, port=%d] using connection for '%s'", (*out)->fd->fd, (*out)->ip, (*out)->port, dkey);
497 
498  /* associate existing connection with domain */
499  xhash_put(s2s->out_dest, s2s->out_reuse ? pstrdup(xhash_pool((*out)->routes), dkey) : dkey, (void *) *out);
500 
501  reuse = 1;
502  } else{
503  /* no conn, create one */
504  *out = (conn_t) calloc(1, sizeof(struct conn_st));
505 
506  (*out)->s2s = s2s;
507 
508  (*out)->key = strdup(ipport);
509  if (s2s->out_reuse)
510  (*out)->dkey = NULL;
511  else
512  (*out)->dkey = dkey;
513 
514  strcpy((*out)->ip, ip);
515  (*out)->port = port;
516 
517  (*out)->states = xhash_new(101);
518  (*out)->states_time = xhash_new(101);
519 
520  (*out)->routes = xhash_new(101);
521 
522  (*out)->init_time = time(NULL);
523 
524  if (s2s->out_reuse)
525  xhash_put(s2s->out_host, (*out)->key, (void *) *out);
526  xhash_put(s2s->out_dest, s2s->out_reuse ? pstrdup(xhash_pool((*out)->routes), dkey) : dkey, (void *) *out);
527 
528  xhash_put((*out)->routes, pstrdupx(xhash_pool((*out)->routes), route, routelen), (void *) 1);
529 
530  /* connect */
531  log_debug(ZONE, "initiating connection to %s", ipport);
532 
533  /* APPLE: multiple origin_ips may be specified; use IPv6 if possible or otherwise IPv4 */
534  int ip_is_v6 = 0;
535  if (strchr(ip, ':') != NULL)
536  ip_is_v6 = 1;
537  int i;
538  for (i = 0; i < s2s->origin_nips; i++) {
539  // only bother with mio_connect if the src and dst IPs are of the same type
540  if ((ip_is_v6 && (strchr(s2s->origin_ips[i], ':') != NULL)) || // both are IPv6
541  (! ip_is_v6 && (strchr(s2s->origin_ips[i], ':') == NULL))) // both are IPv4
542  (*out)->fd = mio_connect(s2s->mio, port, ip, s2s->origin_ips[i], _out_mio_callback, (void *) *out);
543 
544  if ((*out)->fd != NULL) break;
545  }
546 
547  if ((*out)->fd == NULL) {
548  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);
549 
550  _out_dns_mark_bad(*out);
551 
552  if (s2s->out_reuse)
553  xhash_zap(s2s->out_host, (*out)->key);
554  xhash_zap(s2s->out_dest, dkey);
555 
556  xhash_free((*out)->states);
557  xhash_free((*out)->states_time);
558 
559  xhash_free((*out)->routes);
560 
561  free((*out)->key);
562  free((*out)->dkey);
563  free(*out);
564  *out = NULL;
565 
566  /* try again without allowing bad hosts */
567  return out_route(s2s, route, routelen, out, 0);
568  } else {
569  log_write(s2s->log, LOG_NOTICE, "[%d] [%s, port=%d] outgoing connection for '%s'", (*out)->fd->fd, (*out)->ip, (*out)->port, dkey);
570 
571  (*out)->s = sx_new(s2s->sx_env, (*out)->fd->fd, _out_sx_callback, (void *) *out);
572 
573 #ifdef HAVE_SSL
574  /* Send a stream version of 1.0 if we can do STARTTLS */
575  if(s2s->sx_ssl != NULL) {
576  sx_client_init((*out)->s, S2S_DB_HEADER, uri_SERVER, dkey, pstrdupx(xhash_pool((*out)->routes), route, from_len), "1.0");
577  } else {
578  sx_client_init((*out)->s, S2S_DB_HEADER, uri_SERVER, NULL, NULL, NULL);
579  }
580 #else
581  sx_client_init((*out)->s, S2S_DB_HEADER, uri_SERVER, NULL, NULL, NULL);
582 #endif
583  /* dkey is now used by the hash table */
584  return 0;
585  }
586  }
587  } else {
588  log_debug(ZONE, "connection for '%s' found (%d %s/%d)", dkey, (*out)->fd->fd, (*out)->ip, (*out)->port);
589  }
590 
591  /* connection in progress, or re-using connection: add to routes list */
592  if (!(*out)->online || reuse) {
593  if (xhash_getx((*out)->routes, route, routelen) == NULL)
594  xhash_put((*out)->routes, pstrdupx(xhash_pool((*out)->routes), route, routelen), (void *) 1);
595  }
596 
597  free(dkey);
598  return 0;
599 }
600 
602 {
603  nad_free(pkt->nad);
604  jid_free(pkt->from);
605  jid_free(pkt->to);
606  free(pkt);
607 }
608 
610 int out_packet(s2s_t s2s, pkt_t pkt) {
611  char *rkey;
612  int rkeylen;
613  conn_t out;
614  conn_state_t state;
615  int ret;
616 
617  /* perform check against whitelist */
618  if (s2s->enable_whitelist > 0 &&
619  (pkt->to->domain != NULL) &&
620  (s2s_domain_in_whitelist(s2s, pkt->to->domain) == 0)) {
621  log_write(s2s->log, LOG_NOTICE, "sending a packet to domain not in the whitelist, dropping it");
622  if (pkt->to != NULL)
623  jid_free(pkt->to);
624  if (pkt->from != NULL)
625  jid_free(pkt->from);
626  if (pkt->nad != NULL)
627  nad_free(pkt->nad);
628  free(pkt);
629 
630  return;
631  }
632 
633  /* new route key */
634  rkey = s2s_route_key(NULL, pkt->from->domain, pkt->to->domain);
635  rkeylen = strlen(rkey);
636 
637  /* get a connection */
638  ret = out_route(s2s, rkey, rkeylen, &out, 1);
639 
640  if (out == NULL) {
641  /* connection not available, queue packet */
642  _out_packet_queue(s2s, pkt);
643 
644  /* check if out_route was successful in attempting a connection */
645  if (ret) {
646  /* bounce queue */
648 
649  free(rkey);
650  return -1;
651  }
652 
653  free(rkey);
654  return 0;
655  }
656 
657  /* connection in progress */
658  if(!out->online) {
659  log_debug(ZONE, "connection in progress, queueing packet");
660 
661  _out_packet_queue(s2s, pkt);
662 
663  free(rkey);
664  return 0;
665  }
666 
667  /* connection state */
668  state = (conn_state_t) xhash_get(out->states, rkey);
669 
670  /* valid conns or dialback packets */
671  if(state == conn_VALID || pkt->db) {
672  log_debug(ZONE, "writing packet for %s to outgoing conn %d", rkey, out->fd->fd);
673 
674  /* send it straight out */
675  if(pkt->db) {
676  /* if this is a db:verify packet, increment counter and set timestamp */
677  if(NAD_ENAME_L(pkt->nad, 0) == 6 && strncmp("verify", NAD_ENAME(pkt->nad, 0), 6) == 0) {
678  out->verify++;
679  out->last_verify = time(NULL);
680  }
681 
682  /* dialback packet */
683  sx_nad_write(out->s, pkt->nad);
684  } else {
685  /* if the outgoing stanza has a jabber:client namespace, remove it so that the stream jabber:server namespaces will apply (XMPP 11.2.2) */
686  int ns = nad_find_namespace(pkt->nad, 1, uri_CLIENT, NULL);
687  if(ns >= 0) {
688  /* clear the namespaces of elem 0 (internal route element) and elem 1 (message|iq|presence) */
689  pkt->nad->elems[0].ns = -1;
690  pkt->nad->elems[0].my_ns = -1;
691  pkt->nad->elems[1].ns = -1;
692  pkt->nad->elems[1].my_ns = -1;
693  }
694 
695  /* send it out */
696  sx_nad_write_elem(out->s, pkt->nad, 1);
697  }
698 
699  /* update timestamp */
700  out->last_packet = time(NULL);
701 
702  jid_free(pkt->from);
703  jid_free(pkt->to);
704  free(pkt);
705 
706  free(rkey);
707  return 0;
708  }
709 
710  /* can't be handled yet, queue */
711  _out_packet_queue(s2s, pkt);
712 
713  /* if dialback is in progress, then we're done for now */
714  if(state == conn_INPROGRESS) {
715  free(rkey);
716  return 0;
717  }
718 
719  /* this is a new route - send dialback auth request to piggyback on the existing connection */
720  if (out->s2s->require_tls == 0 || out->s->ssf > 0) {
721  _out_dialback(out, rkey, rkeylen);
722  }
723  free(rkey);
724  return 0;
725 }
726 
727 char *dns_make_ipport(char *host, int port) {
728  char *c;
729  assert(port > 0 && port < 65536);
730 
731  c = (char *) malloc(strlen(host) + 7);
732  sprintf(c, "%s/%d", host, port);
733  return c;
734 }
735 
736 static void _dns_add_result(dnsquery_t query, char *ip, int port, int prio, int weight, unsigned int ttl) {
737  char *ipport = dns_make_ipport(ip, port);
738  dnsres_t res = xhash_get(query->results, ipport);
739 
740  if (res != NULL) {
741  if (prio < res->prio)
742  res->prio = prio;
743 
744  if (prio < res->prio) {
745  /* duplicate host at lower prio - reset weight */
746  res->weight = weight;
747  } else if (prio == res->prio) {
748  /* duplicate host at same prio - add to weight */
749  res->weight += weight;
750  if (res->weight > (65535 << 8))
751  res->weight = (65535 << 8);
752  }
753 
754  if (ttl > res->expiry)
755  res->expiry = ttl;
756 
757  if (ttl > query->expiry)
758  query->expiry = ttl;
759 
760  log_debug(ZONE, "dns result updated for %s@%p: %s (%d/%d/%d)", query->name, query, ipport,
761  res->prio, (res->weight >> 8), res->expiry);
762  } else if (xhash_count(query->results) < DNS_MAX_RESULTS) {
763  res = pmalloc(xhash_pool(query->results), sizeof(struct dnsres_st));
764  res->key = pstrdup(xhash_pool(query->results), ipport);
765  res->prio = prio;
766  res->weight = weight;
767  res->expiry = ttl;
768 
769  if (ttl > query->expiry)
770  query->expiry = ttl;
771 
772  xhash_put(query->results, res->key, res);
773 
774  log_debug(ZONE, "dns result added for %s@%p: %s (%d/%d/%d)", query->name, query, ipport,
775  res->prio, (res->weight >> 8), res->expiry);
776  } else {
777  log_debug(ZONE, "dns result ignored for %s@%p: %s (%d/%d/%d)", query->name, query, ipport,
778  prio, (weight >> 8), ttl);
779  }
780 
781  free(ipport);
782 }
783 
784 static void _dns_add_host(dnsquery_t query, char *ip, int port, int prio, int weight, unsigned int ttl) {
785  char *ipport = dns_make_ipport(ip, port);
786  dnsres_t res = xhash_get(query->hosts, ipport);
787 
788  /* update host weights:
789  * RFC 2482 "In the presence of records containing weights greater
790  * than 0, records with weight 0 should have a very small chance of
791  * being selected."
792  * 0 -> 16
793  * 1-65535 -> 256-16776960
794  */
795  if (weight == 0)
796  weight = 1 << 4;
797  else
798  weight <<= 8;
799 
800  if (res != NULL) {
801  if (prio < res->prio)
802  res->prio = prio;
803 
804  if (prio < res->prio) {
805  /* duplicate host at lower prio - reset weight */
806  res->weight = weight;
807  } else if (prio == res->prio) {
808  /* duplicate host at same prio - add to weight */
809  res->weight += weight;
810  if (res->weight > (65535 << 8))
811  res->weight = (65535 << 8);
812  }
813 
814  if (ttl > res->expiry)
815  res->expiry = ttl;
816 
817  log_debug(ZONE, "dns host updated for %s@%p: %s (%d/%d/%d)", query->name, query, ipport,
818  res->prio, (res->weight >> 8), res->expiry);
819  } else if (xhash_count(query->hosts) < DNS_MAX_RESULTS) {
820  res = pmalloc(xhash_pool(query->hosts), sizeof(struct dnsres_st));
821  res->key = pstrdup(xhash_pool(query->hosts), ipport);
822  res->prio = prio;
823  res->weight = weight;
824  res->expiry = ttl;
825 
826  xhash_put(query->hosts, res->key, res);
827 
828  log_debug(ZONE, "dns host added for %s@%p: %s (%d/%d/%d)", query->name, query, ipport,
829  res->prio, (res->weight >> 8), res->expiry);
830  } else {
831  log_debug(ZONE, "dns host ignored for %s@%p: %s (%d/%d/%d)", query->name, query, ipport,
832  prio, (weight >> 8), ttl);
833  }
834 
835  free(ipport);
836 }
837 
838 /* this function is called with a NULL ctx to start the SRV process */
839 static void _dns_result_srv(struct dns_ctx *ctx, struct dns_rr_srv *result, void *data) {
840  dnsquery_t query = data;
841  assert(query != NULL);
842  query->query = NULL;
843 
844  if (ctx != NULL && result == NULL) {
845  log_debug(ZONE, "dns failure for %s@%p: SRV %s (%d)", query->name, query,
846  query->s2s->lookup_srv[query->srv_i], dns_status(ctx));
847  } else if (result != NULL) {
848  int i;
849 
850  log_debug(ZONE, "dns response for %s@%p: SRV %s %d (%d)", query->name, query,
851  result->dnssrv_qname, result->dnssrv_nrr, result->dnssrv_ttl);
852 
853  for (i = 0; i < result->dnssrv_nrr; i++) {
854  if (strlen(result->dnssrv_srv[i].name) > 0
855  && result->dnssrv_srv[i].port > 0
856  && result->dnssrv_srv[i].port < 65536) {
857  log_debug(ZONE, "dns response for %s@%p: SRV %s[%d] %s/%d (%d/%d)", query->name,
858  query, result->dnssrv_qname, i,
859  result->dnssrv_srv[i].name, result->dnssrv_srv[i].port,
860  result->dnssrv_srv[i].priority, result->dnssrv_srv[i].weight);
861 
862  _dns_add_host(query, result->dnssrv_srv[i].name,
863  result->dnssrv_srv[i].port, result->dnssrv_srv[i].priority,
864  result->dnssrv_srv[i].weight, result->dnssrv_ttl);
865  }
866  }
867 
868  free(result);
869  }
870 
871  /* check next SRV service name */
872  query->srv_i++;
873  if (query->srv_i < query->s2s->lookup_nsrv) {
874  log_debug(ZONE, "dns request for %s@%p: SRV %s", query->name, query,
875  query->s2s->lookup_srv[query->srv_i]);
876 
877  query->query = dns_submit_srv(NULL, query->name, query->s2s->lookup_srv[query->srv_i], "tcp",
878  DNS_NOSRCH, _dns_result_srv, query);
879 
880  /* if submit failed, call ourselves with a NULL result */
881  if (query->query == NULL)
882  _dns_result_srv(ctx, NULL, query);
883  } else {
884  /* no more SRV records to check, resolve hosts */
885  if (xhash_count(query->hosts) > 0) {
886  _dns_result_a(NULL, NULL, query);
887 
888  /* no SRV records returned, resolve hostname */
889  } else {
890  query->cur_host = strdup(query->name);
891  query->cur_port = 5269;
892  query->cur_prio = 0;
893  query->cur_weight = 0;
894  query->cur_expiry = 0;
895  if (query->s2s->resolve_aaaa) {
896  log_debug(ZONE, "dns request for %s@%p: AAAA %s", query->name, query, query->name);
897 
898  query->query = dns_submit_a6(NULL, query->name,
899  DNS_NOSRCH, _dns_result_aaaa, query);
900 
901  /* if submit failed, call ourselves with a NULL result */
902  if (query->query == NULL)
903  _dns_result_aaaa(ctx, NULL, query);
904  } else {
905  log_debug(ZONE, "dns request for %s@%p: A %s", query->name, query, query->name);
906 
907  query->query = dns_submit_a4(NULL, query->name,
908  DNS_NOSRCH, _dns_result_a, query);
909 
910  /* if submit failed, call ourselves with a NULL result */
911  if (query->query == NULL)
912  _dns_result_a(ctx, NULL, query);
913  }
914  }
915  }
916 }
917 
918 static void _dns_result_aaaa(struct dns_ctx *ctx, struct dns_rr_a6 *result, void *data) {
919  dnsquery_t query = data;
920  char ip[INET6_ADDRSTRLEN];
921  int i;
922  assert(query != NULL);
923  query->query = NULL;
924 
925  if (ctx != NULL && result == NULL) {
926  log_debug(ZONE, "dns failure for %s@%p: AAAA %s (%d)", query->name, query,
927  query->cur_host, dns_status(ctx));
928  } else if (result != NULL) {
929  log_debug(ZONE, "dns response for %s@%p: AAAA %s %d (%d)", query->name, query,
930  result->dnsa6_qname, result->dnsa6_nrr, result->dnsa6_ttl);
931 
932  if (query->cur_expiry > 0 && result->dnsa6_ttl > query->cur_expiry)
933  result->dnsa6_ttl = query->cur_expiry;
934 
935  for (i = 0; i < result->dnsa6_nrr; i++) {
936  if (inet_ntop(AF_INET6, &result->dnsa6_addr[i], ip, INET6_ADDRSTRLEN) != NULL) {
937  log_debug(ZONE, "dns response for %s@%p: AAAA %s[%d] %s/%d", query->name,
938  query, result->dnsa6_qname, i, ip, query->cur_port);
939 
940  _dns_add_result(query, ip, query->cur_port,
941  query->cur_prio, query->cur_weight, result->dnsa6_ttl);
942  }
943  }
944  }
945 
946  if (query->cur_host != NULL) {
947  /* do ipv4 resolution too */
948  log_debug(ZONE, "dns request for %s@%p: A %s", query->name, query, query->cur_host);
949 
950  query->query = dns_submit_a4(NULL, query->cur_host,
951  DNS_NOSRCH, _dns_result_a, query);
952 
953  /* if submit failed, call ourselves with a NULL result */
954  if (query->query == NULL)
955  _dns_result_a(ctx, NULL, query);
956  } else {
957  /* uh-oh */
958  log_debug(ZONE, "dns result for %s@%p: AAAA host vanished...", query->name, query);
959  _dns_result_a(NULL, NULL, query);
960  }
961 
962  free(result);
963 }
964 
965 /* try /etc/hosts if the A process did not return any results */
966 static int _etc_hosts_lookup(const char *cszName, char *szIP, const int ciMaxIPLen) {
967 #define EHL_LINE_LEN 260
968  int iSuccess = 0;
969  size_t iLen;
970  char szLine[EHL_LINE_LEN + 1]; /* one extra for the space character (*) */
971  char *pcStart, *pcEnd;
972  FILE *fHosts;
973 
974  do {
975  /* initialization */
976  fHosts = NULL;
977 
978  /* sanity checks */
979  if ((cszName == NULL) || (szIP == NULL) || (ciMaxIPLen <= 0))
980  break;
981  szIP[0] = 0;
982 
983  /* open the hosts file */
984 #ifdef _WIN32
985  pcStart = getenv("WINDIR");
986  if (pcStart != NULL) {
987  sprintf(szLine, "%s\\system32\\drivers\\etc\\hosts", pcStart);
988  } else {
989  strcpy(szLine, "C:\\WINDOWS\\system32\\drivers\\etc\\hosts");
990  }
991 #else
992  strcpy(szLine, "/etc/hosts");
993 #endif
994  fHosts = fopen(szLine, "r");
995  if (fHosts == NULL)
996  break;
997 
998  /* read line by line ... */
999  while (fgets(szLine, EHL_LINE_LEN, fHosts) != NULL) {
1000  /* remove comments */
1001  pcStart = strchr (szLine, '#');
1002  if (pcStart != NULL)
1003  *pcStart = 0;
1004  strcat(szLine, " "); /* append a space character for easier parsing (*) */
1005 
1006  /* first to appear: IP address */
1007  iLen = strspn(szLine, "1234567890.");
1008  if ((iLen < 7) || (iLen > 15)) /* superficial test for anything between x.x.x.x and xxx.xxx.xxx.xxx */
1009  continue;
1010  pcEnd = szLine + iLen;
1011  *pcEnd = 0;
1012  pcEnd++; /* not beyond the end of the line yet (*) */
1013 
1014  /* check strings separated by blanks, tabs or newlines */
1015  pcStart = pcEnd + strspn(pcEnd, " \t\n");
1016  while (*pcStart != 0) {
1017  pcEnd = pcStart + strcspn(pcStart, " \t\n");
1018  *pcEnd = 0;
1019  pcEnd++; /* not beyond the end of the line yet (*) */
1020 
1021  if (strcasecmp(pcStart, cszName) == 0) {
1022  strncpy(szIP, szLine, ciMaxIPLen - 1);
1023  szIP[ciMaxIPLen - 1] = '\0';
1024  iSuccess = 1;
1025  break;
1026  }
1027 
1028  pcStart = pcEnd + strspn(pcEnd, " \t\n");
1029  }
1030  if (iSuccess)
1031  break;
1032  }
1033  } while (0);
1034 
1035  if (fHosts != NULL)
1036  fclose(fHosts);
1037 
1038  return (iSuccess);
1039 }
1040 
1041 /* this function is called with a NULL ctx to start the A/AAAA process */
1042 static void _dns_result_a(struct dns_ctx *ctx, struct dns_rr_a4 *result, void *data) {
1043  dnsquery_t query = data;
1044  assert(query != NULL);
1045  query->query = NULL;
1046 
1047  if (ctx != NULL && result == NULL) {
1048 #define DRA_IP_LEN 16
1049  char szIP[DRA_IP_LEN];
1050  if (_etc_hosts_lookup (query->name, szIP, DRA_IP_LEN)) {
1051  log_debug(ZONE, "/etc/lookup for %s@%p: %s (%d)", query->name,
1052  query, szIP, query->s2s->etc_hosts_ttl);
1053 
1054  _dns_add_result (query, szIP, query->cur_port,
1055  query->cur_prio, query->cur_weight, query->s2s->etc_hosts_ttl);
1056  } else {
1057  log_debug(ZONE, "dns failure for %s@%p: A %s (%d)", query->name, query,
1058  query->cur_host, dns_status(ctx));
1059  }
1060  } else if (result != NULL) {
1061  char ip[INET_ADDRSTRLEN];
1062  int i;
1063 
1064  log_debug(ZONE, "dns response for %s@%p: A %s %d (%d)", query->name,
1065  query, result->dnsa4_qname, result->dnsa4_nrr, result->dnsa4_ttl);
1066 
1067  if (query->cur_expiry > 0 && result->dnsa4_ttl > query->cur_expiry)
1068  result->dnsa4_ttl = query->cur_expiry;
1069 
1070  for (i = 0; i < result->dnsa4_nrr; i++) {
1071  if (inet_ntop(AF_INET, &result->dnsa4_addr[i], ip, INET_ADDRSTRLEN) != NULL) {
1072  log_debug(ZONE, "dns response for %s@%p: A %s[%d] %s/%d", query->name,
1073  query, result->dnsa4_qname, i, ip, query->cur_port);
1074 
1075  _dns_add_result(query, ip, query->cur_port,
1076  query->cur_prio, query->cur_weight, result->dnsa4_ttl);
1077  }
1078  }
1079 
1080  free(result);
1081  }
1082 
1083  /* resolve the next host in the list */
1084  if (xhash_iter_first(query->hosts)) {
1085  char *ipport, *c, *tmp;
1086  int ipport_len, ip_len, port_len;
1087  dnsres_t res;
1088  union xhashv xhv;
1089 
1090  xhv.dnsres_val = &res;
1091 
1092  /* get the first entry */
1093  xhash_iter_get(query->hosts, (const char **) &ipport, &ipport_len, xhv.val);
1094 
1095  /* remove the host from the list */
1096  xhash_iter_zap(query->hosts);
1097 
1098  c = memchr(ipport, '/', ipport_len);
1099  ip_len = c - ipport;
1100  c++;
1101  port_len = ipport_len - (c - ipport);
1102 
1103  /* resolve hostname */
1104  free(query->cur_host);
1105  query->cur_host = strndup(ipport, ip_len);
1106  tmp = strndup(c, port_len);
1107  query->cur_port = atoi(tmp);
1108  free(tmp);
1109  query->cur_prio = res->prio;
1110  query->cur_weight = res->weight;
1111  query->cur_expiry = res->expiry;
1112  log_debug(ZONE, "dns ttl for %s@%p limited to %d", query->name, query, query->cur_expiry);
1113 
1114  if (query->s2s->resolve_aaaa) {
1115  log_debug(ZONE, "dns request for %s@%p: AAAA %s", query->name, query, query->cur_host);
1116 
1117  query->query = dns_submit_a6(NULL, query->cur_host, DNS_NOSRCH, _dns_result_aaaa, query);
1118 
1119  /* if submit failed, call ourselves with a NULL result */
1120  if (query->query == NULL)
1121  _dns_result_aaaa(ctx, NULL, query);
1122  } else {
1123  log_debug(ZONE, "dns request for %s@%p: A %s", query->name, query, query->cur_host);
1124 
1125  query->query = dns_submit_a4(NULL, query->cur_host, DNS_NOSRCH, _dns_result_a, query);
1126 
1127  /* if submit failed, call ourselves with a NULL result */
1128  if (query->query == NULL)
1129  _dns_result_a(ctx, NULL, query);
1130  }
1131 
1132  /* finished */
1133  } else {
1134  time_t now = time(NULL);
1135  char *domain;
1136 
1137  free(query->cur_host);
1138  query->cur_host = NULL;
1139 
1140  log_debug(ZONE, "dns requests for %s@%p complete: %d (%d)", query->name,
1141  query, xhash_count(query->results), query->expiry);
1142 
1143  /* update query TTL */
1144  if (query->expiry > query->s2s->dns_max_ttl)
1145  query->expiry = query->s2s->dns_max_ttl;
1146 
1147  if (query->expiry < query->s2s->dns_min_ttl)
1148  query->expiry = query->s2s->dns_min_ttl;
1149 
1150  query->expiry += now;
1151 
1152  /* update result TTLs - the query expiry MUST NOT be longer than all result expiries */
1153  if (xhash_iter_first(query->results)) {
1154  union xhashv xhv;
1155  dnsres_t res;
1156 
1157  xhv.dnsres_val = &res;
1158 
1159  do {
1160  xhash_iter_get(query->results, NULL, NULL, xhv.val);
1161 
1162  if (res->expiry > query->s2s->dns_max_ttl)
1163  res->expiry = query->s2s->dns_max_ttl;
1164 
1165  if (res->expiry < query->s2s->dns_min_ttl)
1166  res->expiry = query->s2s->dns_min_ttl;
1167 
1168  res->expiry += now;
1169  } while(xhash_iter_next(query->results));
1170  }
1171 
1172  xhash_free(query->hosts);
1173  query->hosts = NULL;
1174  if (idna_to_unicode_8z8z(query->name, &domain, 0) != IDNA_SUCCESS) {
1175  log_write(query->s2s->log, LOG_ERR, "idna dns decode for %s failed", query->name);
1176  /* fake empty results to shortcut resolution failure */
1177  xhash_free(query->results);
1178  query->results = xhash_new(71);
1179  query->expiry = time(NULL) + 99999999;
1180  domain = strdup(query->name);
1181  }
1182  out_resolve(query->s2s, domain, query->results, query->expiry);
1183  free(domain);
1184  free(query->name);
1185  free(query);
1186  }
1187 }
1188 
1190  dnsquery_t query = (dnsquery_t) calloc(1, sizeof(struct dnsquery_st));
1191 
1192  query->s2s = s2s;
1193  query->results = xhash_new(71);
1194  if (idna_to_ascii_8z(dns->name, &query->name, 0) != IDNA_SUCCESS) {
1195  log_write(s2s->log, LOG_ERR, "idna dns encode for %s failed", dns->name);
1196  /* shortcut resolution failure */
1197  query->expiry = time(NULL) + 99999999;
1198  out_resolve(query->s2s, dns->name, query->results, query->expiry);
1199  return;
1200  }
1201  query->hosts = xhash_new(71);
1202  query->srv_i = -1;
1203  query->expiry = 0;
1204  query->cur_host = NULL;
1205  query->cur_port = 0;
1206  query->cur_expiry = 0;
1207  query->query = NULL;
1208  dns->query = query;
1209 
1210  log_debug(ZONE, "dns resolve for %s@%p started", query->name, query);
1211 
1212  /* - resolve all SRV records to host/port
1213  * - if no results, include domain/5269
1214  * - resolve all host/port combinations
1215  * - return result
1216  */
1217  _dns_result_srv(NULL, NULL, query);
1218 }
1219 
1221 void out_resolve(s2s_t s2s, char *domain, xht results, time_t expiry) {
1222  dnscache_t dns;
1223 
1224  /* no results, resolve failed */
1225  if(xhash_count(results) == 0) {
1226  dns = xhash_get(s2s->dnscache, domain);
1227  if (dns != NULL) {
1228  /* store negative DNS cache */
1229  xhash_free(dns->results);
1230  dns->query = NULL;
1231  dns->results = NULL;
1232  dns->expiry = expiry;
1233  dns->pending = 0;
1234  }
1235 
1236  log_write(s2s->log, LOG_NOTICE, "dns lookup for %s failed", domain);
1237 
1238  /* bounce queue */
1240 
1241  xhash_free(results);
1242  return;
1243  }
1244 
1245  log_write(s2s->log, LOG_NOTICE, "dns lookup for %s returned %d result%s (ttl %d)",
1246  domain, xhash_count(results), xhash_count(results)!=1?"s":"", expiry - time(NULL));
1247 
1248  /* get the cache entry */
1249  dns = xhash_get(s2s->dnscache, domain);
1250 
1251  if(dns == NULL) {
1252  /* retry using punycode */
1253  char *punydomain;
1254  if (idna_to_ascii_8z(domain, &punydomain, 0) == IDNA_SUCCESS) {
1255  dns = xhash_get(s2s->dnscache, punydomain);
1256  free(punydomain);
1257  }
1258  }
1259 
1260  if(dns == NULL) {
1261  log_write(s2s->log, LOG_ERR, "weird, never requested %s resolution", domain);
1262  return;
1263  }
1264 
1265  /* fill it out */
1266  xhash_free(dns->results);
1267  dns->query = NULL;
1268  dns->results = results;
1269  dns->expiry = expiry;
1270  dns->pending = 0;
1271 
1272  out_flush_domain_queues(s2s, domain);
1273 
1274  /* delete the cache entry if caching is disabled */
1275  if (!s2s->dns_cache_enabled && !dns->pending) {
1276  xhash_free(dns->results);
1277  xhash_zap(s2s->dnscache, domain);
1278  free(dns);
1279  }
1280 }
1281 
1283 static int _out_mio_callback(mio_t m, mio_action_t a, mio_fd_t fd, void *data, void *arg) {
1284  conn_t out = (conn_t) arg;
1285  char ipport[INET6_ADDRSTRLEN + 17];
1286  int nbytes;
1287 
1288  switch(a) {
1289  case action_READ:
1290  log_debug(ZONE, "read action on fd %d", fd->fd);
1291 
1292  /* they did something */
1293  out->last_activity = time(NULL);
1294 
1295  ioctl(fd->fd, FIONREAD, &nbytes);
1296  if(nbytes == 0) {
1297  sx_kill(out->s);
1298  return 0;
1299  }
1300 
1301  return sx_can_read(out->s);
1302 
1303  case action_WRITE:
1304  log_debug(ZONE, "write action on fd %d", fd->fd);
1305 
1306  /* update activity timestamp */
1307  out->last_activity = time(NULL);
1308 
1309  return sx_can_write(out->s);
1310 
1311  case action_CLOSE:
1312  log_debug(ZONE, "close action on fd %d", fd->fd);
1313 
1314  jqueue_push(out->s2s->dead, (void *) out->s, 0);
1315 
1316  log_write(out->s2s->log, LOG_NOTICE, "[%d] [%s, port=%d] disconnect, packets: %i", fd->fd, out->ip, out->port, out->packet_count);
1317 
1318 
1319  if (out->s2s->out_reuse) {
1320  /* generate the ip/port pair */
1321  snprintf(ipport, INET6_ADDRSTRLEN + 16, "%s/%d", out->ip, out->port);
1322 
1323  xhash_zap(out->s2s->out_host, ipport);
1324  }
1325 
1326  if (xhash_iter_first(out->routes)) {
1327  char *rkey;
1328  int rkeylen;
1329  char *c;
1330  int c_len;
1331 
1332  /* remove all the out_dest entries */
1333  do {
1334  xhash_iter_get(out->routes, (const char **) &rkey, &rkeylen, NULL);
1335  c = memchr(rkey, '/', rkeylen);
1336  c++;
1337  c_len = rkeylen - (c - rkey);
1338 
1339  log_debug(ZONE, "route '%.*s'", rkeylen, rkey);
1340  if (xhash_getx(out->s2s->out_dest, c, c_len) != NULL) {
1341  log_debug(ZONE, "removing dest entry for '%.*s'", c_len, c);
1342  xhash_zapx(out->s2s->out_dest, c, c_len);
1343  }
1344  } while(xhash_iter_next(out->routes));
1345  }
1346 
1347  if (xhash_iter_first(out->routes)) {
1348  char *rkey;
1349  int rkeylen;
1350  jqueue_t q;
1351  int npkt;
1352 
1353  /* retry all the routes */
1354  do {
1355  xhash_iter_get(out->routes, (const char **) &rkey, &rkeylen, NULL);
1356 
1357  q = xhash_getx(out->s2s->outq, rkey, rkeylen);
1358  if (out->s2s->retry_limit > 0 && q != NULL && jqueue_age(q) > out->s2s->retry_limit) {
1359  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);
1360  q = NULL;
1361  }
1362 
1363  if (q != NULL && (npkt = jqueue_size(q)) > 0 && xhash_get(out->states, rkey) != (void*) conn_INPROGRESS) {
1364  conn_t retry;
1365 
1366  log_debug(ZONE, "retrying connection for '%.*s' queue", rkeylen, rkey);
1367  if (!out_route(out->s2s, rkey, rkeylen, &retry, 0)) {
1368  log_debug(ZONE, "retry successful");
1369 
1370  if (retry != NULL) {
1371  /* flush queue */
1372  out_flush_route_queue(out->s2s, rkey, rkeylen);
1373  }
1374  } else {
1375  log_debug(ZONE, "retry failed");
1376 
1377  /* bounce queue */
1379  _out_dns_mark_bad(out);
1380  }
1381  } else {
1382  /* bounce queue */
1384  _out_dns_mark_bad(out);
1385  }
1386  } while(xhash_iter_next(out->routes));
1387  }
1388 
1389  jqueue_push(out->s2s->dead_conn, (void *) out, 0);
1390 
1391  case action_ACCEPT:
1392  break;
1393  }
1394 
1395  return 0;
1396 }
1397 
1399 {
1400  char *rkey;
1401  int rkeylen;
1402 
1403  if (out->s2s->dns_bad_timeout > 0) {
1404  dnsres_t bad = xhash_get(out->s2s->dns_bad, out->key);
1405 
1406  if (bad != NULL) {
1407  log_debug(ZONE, "removing bad host entry for '%s'", out->key);
1408  xhash_zap(out->s2s->dns_bad, out->key);
1409  free(bad->key);
1410  free(bad);
1411  }
1412  }
1413 
1414  if (xhash_iter_first(out->routes)) {
1415  log_debug(ZONE, "sending dialback packets for %s", out->key);
1416  do {
1417  xhash_iter_get(out->routes, (const char **) &rkey, &rkeylen, NULL);
1418  _out_dialback(out, rkey, rkeylen);
1419  } while(xhash_iter_next(out->routes));
1420  }
1421 
1422  return;
1423 }
1424 
1425 static int _out_sx_callback(sx_t s, sx_event_t e, void *data, void *arg) {
1426  conn_t out = (conn_t) arg;
1427  sx_buf_t buf = (sx_buf_t) data;
1428  int len, ns, elem, starttls = 0;
1429  sx_error_t *sxe;
1430  nad_t nad;
1431 
1432  switch(e) {
1433  case event_WANT_READ:
1434  log_debug(ZONE, "want read");
1435  mio_read(out->s2s->mio, out->fd);
1436  break;
1437 
1438  case event_WANT_WRITE:
1439  log_debug(ZONE, "want write");
1440  mio_write(out->s2s->mio, out->fd);
1441  break;
1442 
1443  case event_READ:
1444  log_debug(ZONE, "reading from %d", out->fd->fd);
1445 
1446  /* do the read */
1447  len = recv(out->fd->fd, buf->data, buf->len, 0);
1448 
1449  if(len < 0) {
1450  if(MIO_WOULDBLOCK) {
1451  buf->len = 0;
1452  return 0;
1453  }
1454 
1455  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);
1456 
1457  if (!out->online) {
1458  _out_dns_mark_bad(out);
1459  }
1460 
1461  sx_kill(s);
1462 
1463  return -1;
1464  }
1465 
1466  else if(len == 0) {
1467  /* they went away */
1468  sx_kill(s);
1469 
1470  return -1;
1471  }
1472 
1473  log_debug(ZONE, "read %d bytes", len);
1474 
1475  buf->len = len;
1476 
1477  return len;
1478 
1479  case event_WRITE:
1480  log_debug(ZONE, "writing to %d", out->fd->fd);
1481 
1482  len = send(out->fd->fd, buf->data, buf->len, 0);
1483  if(len >= 0) {
1484  log_debug(ZONE, "%d bytes written", len);
1485  return len;
1486  }
1487 
1488  if(MIO_WOULDBLOCK)
1489  return 0;
1490 
1491  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);
1492 
1493  if (!out->online) {
1494  _out_dns_mark_bad(out);
1495  }
1496 
1497  sx_kill(s);
1498 
1499  return -1;
1500 
1501  case event_ERROR:
1502  sxe = (sx_error_t *) data;
1503  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);
1504 
1505  /* mark as bad if we did not manage to connect or there is unrecoverable stream error */
1506  if (!out->online ||
1507  (sxe->code == SX_ERR_STREAM &&
1508  (strstr(sxe->specific, "host-gone") || /* it's not there now */
1509  strstr(sxe->specific, "host-unknown") || /* they do not service the host */
1510  strstr(sxe->specific, "not-authorized") || /* they do not want us there */
1511  strstr(sxe->specific, "see-other-host") || /* we do not support redirections yet */
1512  strstr(sxe->specific, "system-shutdown") || /* they are going down */
1513  strstr(sxe->specific, "policy-violation") || /* they do not want us there */
1514  strstr(sxe->specific, "remote-connection-failed") || /* the required remote entity is gone */
1515  strstr(sxe->specific, "unsupported-encoding") || /* they do not like our encoding */
1516  strstr(sxe->specific, "undefined-condition") || /* something bad happend */
1517  strstr(sxe->specific, "internal-server-error") || /* that server is broken */
1518  strstr(sxe->specific, "unsupported-version") /* they do not support our stream version */
1519  ))) {
1520  _out_dns_mark_bad(out);
1521  }
1522 
1523  sx_kill(s);
1524 
1525  return -1;
1526 
1527  case event_OPEN:
1528  log_debug(ZONE, "OPEN event for %s", out->key);
1529  break;
1530 
1531  case event_STREAM:
1532  /* check stream version - NULl = pre-xmpp (some jabber1 servers) */
1533  log_debug(ZONE, "STREAM event for %s stream version is %s", out->key, out->s->res_version);
1534 
1535  /* first time, bring them online */
1536  if(!out->online) {
1537  log_debug(ZONE, "outgoing conn to %s is online", out->key);
1538 
1539  /* if no stream version from either side, kick off dialback for each route, */
1540  /* otherwise wait for stream features */
1541  if (((out->s->res_version==NULL) || (out->s2s->sx_ssl == NULL)) && out->s2s->require_tls == 0) {
1542  log_debug(ZONE, "no stream version, sending dialbacks for %s immediately", out->key);
1543  out->online = 1;
1544  send_dialbacks(out);
1545  } else
1546  log_debug(ZONE, "outgoing conn to %s - waiting for STREAM features", out->key);
1547  }
1548 
1549  break;
1550 
1551  case event_PACKET:
1552  /* we're counting packets */
1553  out->packet_count++;
1554  out->s2s->packet_count++;
1555 
1556  nad = (nad_t) data;
1557 
1558  /* watch for the features packet - STARTTLS and/or SASL*/
1559  if ((out->s->res_version!=NULL)
1560  && NAD_NURI_L(nad, NAD_ENS(nad, 0)) == strlen(uri_STREAMS)
1561  && strncmp(uri_STREAMS, NAD_NURI(nad, NAD_ENS(nad, 0)), strlen(uri_STREAMS)) == 0
1562  && NAD_ENAME_L(nad, 0) == 8 && strncmp("features", NAD_ENAME(nad, 0), 8) == 0) {
1563  log_debug(ZONE, "got the stream features packet");
1564 
1565 #ifdef HAVE_SSL
1566  /* starttls if we can */
1567  if(out->s2s->sx_ssl != NULL && s->ssf == 0) {
1568  ns = nad_find_scoped_namespace(nad, uri_TLS, NULL);
1569  if(ns >= 0) {
1570  elem = nad_find_elem(nad, 0, ns, "starttls", 1);
1571  if(elem >= 0) {
1572  log_debug(ZONE, "got STARTTLS in stream features");
1573  if(sx_ssl_client_starttls(out->s2s->sx_ssl, s, out->s2s->local_pemfile) == 0) {
1574  starttls = 1;
1575  nad_free(nad);
1576  return 0;
1577  }
1578  log_write(out->s2s->log, LOG_ERR, "unable to establish encrypted session with peer");
1579  }
1580  }
1581  }
1582 
1583  /* If we're not establishing a starttls connection, send dialbacks */
1584  if (!starttls) {
1585  if (out->s2s->require_tls == 0 || s->ssf > 0) {
1586  log_debug(ZONE, "No STARTTLS, sending dialbacks for %s", out->key);
1587  out->online = 1;
1588  send_dialbacks(out);
1589  } else {
1590  log_debug(ZONE, "No STARTTLS, dialbacks disabled for non-TLS connections, cannot complete negotiation");
1591  }
1592  }
1593 #else
1594  if (out->s2s->require_tls == 0) {
1595  out->online = 1;
1596  send_dialbacks(out);
1597  }
1598 #endif
1599  }
1600 
1601 
1602  /* we only accept dialback packets */
1603  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) {
1604  log_debug(ZONE, "got a non-dialback packet on an outgoing conn, dropping it");
1605  nad_free(nad);
1606  return 0;
1607  }
1608 
1609  /* and then only result and verify */
1610  if(NAD_ENAME_L(nad, 0) == 6) {
1611  if(strncmp("result", NAD_ENAME(nad, 0), 6) == 0) {
1612  _out_result(out, nad);
1613  return 0;
1614  }
1615 
1616  if(strncmp("verify", NAD_ENAME(nad, 0), 6) == 0) {
1617  _out_verify(out, nad);
1618  return 0;
1619  }
1620  }
1621 
1622  log_debug(ZONE, "unknown dialback packet, dropping it");
1623 
1624  nad_free(nad);
1625  return 0;
1626 
1627  case event_CLOSED:
1628  if (out->fd != NULL) {
1629  mio_close(out->s2s->mio, out->fd);
1630  out->fd = NULL;
1631  }
1632  return -1;
1633  }
1634 
1635  return 0;
1636 }
1637 
1639 static void _out_result(conn_t out, nad_t nad) {
1640  int attr;
1641  jid_t from, to;
1642  char *rkey;
1643  int rkeylen;
1644 
1645  attr = nad_find_attr(nad, 0, -1, "from", NULL);
1646  if(attr < 0 || (from = jid_new(NAD_AVAL(nad, attr), NAD_AVAL_L(nad, attr))) == NULL) {
1647  log_debug(ZONE, "missing or invalid from on db result packet");
1648  nad_free(nad);
1649  return;
1650  }
1651 
1652  attr = nad_find_attr(nad, 0, -1, "to", NULL);
1653  if(attr < 0 || (to = jid_new(NAD_AVAL(nad, attr), NAD_AVAL_L(nad, attr))) == NULL) {
1654  log_debug(ZONE, "missing or invalid to on db result packet");
1655  jid_free(from);
1656  nad_free(nad);
1657  return;
1658  }
1659 
1660  rkey = s2s_route_key(NULL, to->domain, from->domain);
1661  rkeylen = strlen(rkey);
1662 
1663  /* key is valid */
1664  if(nad_find_attr(nad, 0, -1, "type", "valid") >= 0 && xhash_get(out->states, rkey) == (void*) conn_INPROGRESS) {
1665  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" : "");
1666 
1667  xhash_put(out->states, pstrdup(xhash_pool(out->states), rkey), (void *) conn_VALID); /* !!! small leak here */
1668 
1669  log_debug(ZONE, "%s valid, flushing queue", rkey);
1670 
1671  /* flush the queue */
1672  out_flush_route_queue(out->s2s, rkey, rkeylen);
1673 
1674  free(rkey);
1675 
1676  jid_free(from);
1677  jid_free(to);
1678 
1679  nad_free(nad);
1680 
1681  return;
1682  }
1683 
1684  /* invalid */
1685  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);
1686 
1687  /* close connection */
1688  log_write(out->s2s->log, LOG_NOTICE, "[%d] [%s, port=%d] closing connection", out->fd->fd, out->ip, out->port);
1689 
1690  /* report stream error */
1691  sx_error(out->s, stream_err_INVALID_ID, "dialback negotiation failed");
1692 
1693  /* close the stream */
1694  sx_close(out->s);
1695 
1696  /* bounce queue */
1698 
1699  free(rkey);
1700 
1701  jid_free(from);
1702  jid_free(to);
1703 
1704  nad_free(nad);
1705 }
1706 
1708 static void _out_verify(conn_t out, nad_t nad) {
1709  int attr, ns;
1710  jid_t from, to;
1711  conn_t in;
1712  char *rkey;
1713  int valid;
1714 
1715  attr = nad_find_attr(nad, 0, -1, "from", NULL);
1716  if(attr < 0 || (from = jid_new(NAD_AVAL(nad, attr), NAD_AVAL_L(nad, attr))) == NULL) {
1717  log_debug(ZONE, "missing or invalid from on db verify packet");
1718  nad_free(nad);
1719  return;
1720  }
1721 
1722  attr = nad_find_attr(nad, 0, -1, "to", NULL);
1723  if(attr < 0 || (to = jid_new(NAD_AVAL(nad, attr), NAD_AVAL_L(nad, attr))) == NULL) {
1724  log_debug(ZONE, "missing or invalid to on db verify packet");
1725  jid_free(from);
1726  nad_free(nad);
1727  return;
1728  }
1729 
1730  attr = nad_find_attr(nad, 0, -1, "id", NULL);
1731  if(attr < 0) {
1732  log_debug(ZONE, "missing id on db verify packet");
1733  jid_free(from);
1734  jid_free(to);
1735  nad_free(nad);
1736  return;
1737  }
1738 
1739  /* get the incoming conn */
1740  in = xhash_getx(out->s2s->in, NAD_AVAL(nad, attr), NAD_AVAL_L(nad, attr));
1741  if(in == NULL) {
1742  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));
1743  jid_free(from);
1744  jid_free(to);
1745  nad_free(nad);
1746  return;
1747  }
1748 
1749  rkey = s2s_route_key(NULL, to->domain, from->domain);
1750 
1751  attr = nad_find_attr(nad, 0, -1, "type", "valid");
1752  if(attr >= 0 && xhash_get(in->states, rkey) == (void*) conn_INPROGRESS) {
1753  xhash_put(in->states, pstrdup(xhash_pool(in->states), rkey), (void *) conn_VALID);
1754  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" : "");
1755  valid = 1;
1756  } else {
1757  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);
1758  valid = 0;
1759  }
1760 
1761  free(rkey);
1762 
1763  nad_free(nad);
1764 
1765  /* decrement outstanding verify counter */
1766  --out->verify;
1767 
1768  /* let them know what happened */
1769  nad = nad_new();
1770 
1771  ns = nad_add_namespace(nad, uri_DIALBACK, "db");
1772  nad_append_elem(nad, ns, "result", 0);
1773  nad_append_attr(nad, -1, "to", from->domain);
1774  nad_append_attr(nad, -1, "from", to->domain);
1775  nad_append_attr(nad, -1, "type", valid ? "valid" : "invalid");
1776 
1777  /* off it goes */
1778  sx_nad_write(in->s, nad);
1779 
1780  /* if invalid, close the stream */
1781  if (!valid) {
1782  /* generate stream error */
1783  sx_error(in->s, stream_err_INVALID_ID, "dialback negotiation failed");
1784 
1785  /* close the incoming stream */
1786  sx_close(in->s);
1787  }
1788 
1789  jid_free(from);
1790  jid_free(to);
1791 }
1792 
1793 /* bounce all packets in the queues for domain */
1794 int out_bounce_domain_queues(s2s_t s2s, const char *domain, int err)
1795 {
1796  char *rkey;
1797  int rkeylen;
1798  int pktcount = 0;
1799 
1800  if (xhash_iter_first(s2s->outq)) {
1801  do {
1802  xhash_iter_get(s2s->outq, (const char **) &rkey, &rkeylen, NULL);
1803  if(s2s_route_key_match(NULL, (char *) domain, rkey, rkeylen))
1804  pktcount += out_bounce_route_queue(s2s, rkey, rkeylen, err);
1805  } while(xhash_iter_next(s2s->outq));
1806  }
1807 
1808  return pktcount;
1809 }
1810 
1811 /* bounce all packets in the queue for route */
1812 int out_bounce_route_queue(s2s_t s2s, char *rkey, int rkeylen, int err)
1813 {
1814  jqueue_t q;
1815  pkt_t pkt;
1816  int pktcount = 0;
1817 
1818  q = xhash_getx(s2s->outq, rkey, rkeylen);
1819  if(q == NULL)
1820  return 0;
1821 
1822  while((pkt = jqueue_pull(q)) != NULL) {
1823  /* only packets with content, in namespace jabber:client and not already errors */
1824  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) {
1825  sx_nad_write(s2s->router, stanza_tofrom(stanza_tofrom(stanza_error(pkt->nad, 1, err), 1), 0));
1826  pktcount++;
1827  }
1828  else
1829  nad_free(pkt->nad);
1830 
1831  jid_free(pkt->to);
1832  jid_free(pkt->from);
1833  free(pkt);
1834  }
1835 
1836  /* delete queue and remove domain from queue hash */
1837  log_debug(ZONE, "deleting out packet queue for %.*s", rkeylen, rkey);
1838  rkey = q->key;
1839  jqueue_free(q);
1840  xhash_zap(s2s->outq, rkey);
1841  free(rkey);
1842 
1843  return pktcount;
1844 }
1845 
1847 {
1848  char *rkey;
1849  int rkeylen;
1850  int pktcount = 0;
1851 
1852  /* bounce queues for all domains handled by this connection - iterate through routes */
1853  if (xhash_iter_first(out->routes)) {
1854  do {
1855  xhash_iter_get(out->routes, (const char **) &rkey, &rkeylen, NULL);
1856  pktcount += out_bounce_route_queue(out->s2s, rkey, rkeylen, err);
1857  } while(xhash_iter_next(out->routes));
1858  }
1859 
1860  return pktcount;
1861 }
1862 
1863 void out_flush_domain_queues(s2s_t s2s, const char *domain) {
1864  char *rkey;
1865  int rkeylen;
1866  char *c;
1867  int c_len;
1868 
1869  if (xhash_iter_first(s2s->outq)) {
1870  do {
1871  xhash_iter_get(s2s->outq, (const char **) &rkey, &rkeylen, NULL);
1872  c = memchr(rkey, '/', rkeylen);
1873  c++;
1874  c_len = rkeylen - (c - rkey);
1875  if (strncmp(domain, c, c_len) == 0)
1876  out_flush_route_queue(s2s, rkey, rkeylen);
1877  } while(xhash_iter_next(s2s->outq));
1878  }
1879 }
1880 
1881 void out_flush_route_queue(s2s_t s2s, char *rkey, int rkeylen) {
1882  jqueue_t q;
1883  pkt_t pkt;
1884  int npkt, i, ret;
1885 
1886  q = xhash_getx(s2s->outq, rkey, rkeylen);
1887  if(q == NULL)
1888  return;
1889 
1890  npkt = jqueue_size(q);
1891  log_debug(ZONE, "flushing %d packets for '%.*s' to out_packet", npkt, rkeylen, rkey);
1892 
1893  for(i = 0; i < npkt; i++) {
1894  pkt = jqueue_pull(q);
1895  if(pkt) {
1896  ret = out_packet(s2s, pkt);
1897  if (ret) {
1898  /* uh-oh. the queue was deleted...
1899  q and pkt have been freed
1900  if q->key == rkey, rkey has also been freed */
1901  return;
1902  }
1903  }
1904  }
1905 
1906  /* delete queue for route and remove route from queue hash */
1907  if (jqueue_size(q) == 0) {
1908  log_debug(ZONE, "deleting out packet queue for '%.*s'", rkeylen, rkey);
1909  rkey = q->key;
1910  jqueue_free(q);
1911  xhash_zap(s2s->outq, rkey);
1912  free(rkey);
1913  } else {
1914  log_debug(ZONE, "emptied queue gained more packets...");
1915  }
1916 }