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