jabberd2  2.3.6
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  }
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  const 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, const 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((void*)(*out)->key);
562  free((void*)(*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 0;
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(const 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, const 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, const 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((void*)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((void*)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((void*)query->name);
1185  free(query);
1186  }
1187 }
1188 
1190  dnsquery_t query = (dnsquery_t) calloc(1, sizeof(struct dnsquery_st));
1191  char *name;
1192 
1193  query->s2s = s2s;
1194  query->results = xhash_new(71);
1195  if (idna_to_ascii_8z(dns->name, &name, 0) != IDNA_SUCCESS) {
1196  log_write(s2s->log, LOG_ERR, "idna dns encode for %s failed", dns->name);
1197  /* shortcut resolution failure */
1198  query->expiry = time(NULL) + 99999999;
1199  out_resolve(query->s2s, dns->name, query->results, query->expiry);
1200  return;
1201  }
1202  query->name = name;
1203  query->hosts = xhash_new(71);
1204  query->srv_i = -1;
1205  query->expiry = 0;
1206  query->cur_host = NULL;
1207  query->cur_port = 0;
1208  query->cur_expiry = 0;
1209  query->query = NULL;
1210  dns->query = query;
1211 
1212  log_debug(ZONE, "dns resolve for %s@%p started", query->name, query);
1213 
1214  /* - resolve all SRV records to host/port
1215  * - if no results, include domain/5269
1216  * - resolve all host/port combinations
1217  * - return result
1218  */
1219  _dns_result_srv(NULL, NULL, query);
1220 }
1221 
1223 void out_resolve(s2s_t s2s, const char *domain, xht results, time_t expiry) {
1224  dnscache_t dns;
1225 
1226  /* no results, resolve failed */
1227  if(xhash_count(results) == 0) {
1228  dns = xhash_get(s2s->dnscache, domain);
1229  if (dns != NULL) {
1230  /* store negative DNS cache */
1231  xhash_free(dns->results);
1232  dns->query = NULL;
1233  dns->results = NULL;
1234  dns->expiry = expiry;
1235  dns->pending = 0;
1236  }
1237 
1238  log_write(s2s->log, LOG_NOTICE, "dns lookup for %s failed", domain);
1239 
1240  /* bounce queue */
1242 
1243  xhash_free(results);
1244  return;
1245  }
1246 
1247  log_write(s2s->log, LOG_NOTICE, "dns lookup for %s returned %d result%s (ttl %d)",
1248  domain, xhash_count(results), xhash_count(results)!=1?"s":"", expiry - time(NULL));
1249 
1250  /* get the cache entry */
1251  dns = xhash_get(s2s->dnscache, domain);
1252 
1253  if(dns == NULL) {
1254  /* retry using punycode */
1255  char *punydomain;
1256  if (idna_to_ascii_8z(domain, &punydomain, 0) == IDNA_SUCCESS) {
1257  dns = xhash_get(s2s->dnscache, punydomain);
1258  free(punydomain);
1259  }
1260  }
1261 
1262  if(dns == NULL) {
1263  log_write(s2s->log, LOG_ERR, "weird, never requested %s resolution", domain);
1264  return;
1265  }
1266 
1267  /* fill it out */
1268  xhash_free(dns->results);
1269  dns->query = NULL;
1270  dns->results = results;
1271  dns->expiry = expiry;
1272  dns->pending = 0;
1273 
1274  out_flush_domain_queues(s2s, domain);
1275 
1276  /* delete the cache entry if caching is disabled */
1277  if (!s2s->dns_cache_enabled && !dns->pending) {
1278  xhash_free(dns->results);
1279  xhash_zap(s2s->dnscache, domain);
1280  free(dns);
1281  }
1282 }
1283 
1285 static int _out_mio_callback(mio_t m, mio_action_t a, mio_fd_t fd, void *data, void *arg) {
1286  conn_t out = (conn_t) arg;
1287  char ipport[INET6_ADDRSTRLEN + 17];
1288  int nbytes;
1289 
1290  switch(a) {
1291  case action_READ:
1292  log_debug(ZONE, "read action on fd %d", fd->fd);
1293 
1294  /* they did something */
1295  out->last_activity = time(NULL);
1296 
1297  ioctl(fd->fd, FIONREAD, &nbytes);
1298  if(nbytes == 0) {
1299  sx_kill(out->s);
1300  return 0;
1301  }
1302 
1303  return sx_can_read(out->s);
1304 
1305  case action_WRITE:
1306  log_debug(ZONE, "write action on fd %d", fd->fd);
1307 
1308  /* update activity timestamp */
1309  out->last_activity = time(NULL);
1310 
1311  return sx_can_write(out->s);
1312 
1313  case action_CLOSE:
1314  log_debug(ZONE, "close action on fd %d", fd->fd);
1315 
1316  jqueue_push(out->s2s->dead, (void *) out->s, 0);
1317 
1318  log_write(out->s2s->log, LOG_NOTICE, "[%d] [%s, port=%d] disconnect, packets: %i", fd->fd, out->ip, out->port, out->packet_count);
1319 
1320 
1321  if (out->s2s->out_reuse) {
1322  /* generate the ip/port pair */
1323  snprintf(ipport, INET6_ADDRSTRLEN + 16, "%s/%d", out->ip, out->port);
1324 
1325  xhash_zap(out->s2s->out_host, ipport);
1326  }
1327 
1328  if (xhash_iter_first(out->routes)) {
1329  char *rkey;
1330  int rkeylen;
1331  char *c;
1332  int c_len;
1333 
1334  /* remove all the out_dest entries */
1335  do {
1336  xhash_iter_get(out->routes, (const char **) &rkey, &rkeylen, NULL);
1337  c = memchr(rkey, '/', rkeylen);
1338  c++;
1339  c_len = rkeylen - (c - rkey);
1340 
1341  log_debug(ZONE, "route '%.*s'", rkeylen, rkey);
1342  if (xhash_getx(out->s2s->out_dest, c, c_len) != NULL) {
1343  log_debug(ZONE, "removing dest entry for '%.*s'", c_len, c);
1344  xhash_zapx(out->s2s->out_dest, c, c_len);
1345  }
1346  } while(xhash_iter_next(out->routes));
1347  }
1348 
1349  if (xhash_iter_first(out->routes)) {
1350  char *rkey;
1351  int rkeylen;
1352  jqueue_t q;
1353  int npkt;
1354 
1355  /* retry all the routes */
1356  do {
1357  xhash_iter_get(out->routes, (const char **) &rkey, &rkeylen, NULL);
1358 
1359  q = xhash_getx(out->s2s->outq, rkey, rkeylen);
1360  if (out->s2s->retry_limit > 0 && q != NULL && jqueue_age(q) > out->s2s->retry_limit) {
1361  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);
1362  q = NULL;
1363  }
1364 
1365  if (q != NULL && (npkt = jqueue_size(q)) > 0 && xhash_get(out->states, rkey) != (void*) conn_INPROGRESS) {
1366  conn_t retry;
1367 
1368  log_debug(ZONE, "retrying connection for '%.*s' queue", rkeylen, rkey);
1369  if (!out_route(out->s2s, rkey, rkeylen, &retry, 0)) {
1370  log_debug(ZONE, "retry successful");
1371 
1372  if (retry != NULL) {
1373  /* flush queue */
1374  out_flush_route_queue(out->s2s, rkey, rkeylen);
1375  }
1376  } else {
1377  log_debug(ZONE, "retry failed");
1378 
1379  /* bounce queue */
1381  _out_dns_mark_bad(out);
1382  }
1383  } else {
1384  /* bounce queue */
1386  _out_dns_mark_bad(out);
1387  }
1388  } while(xhash_iter_next(out->routes));
1389  }
1390 
1391  jqueue_push(out->s2s->dead_conn, (void *) out, 0);
1392 
1393  case action_ACCEPT:
1394  break;
1395  }
1396 
1397  return 0;
1398 }
1399 
1401 {
1402  char *rkey;
1403  int rkeylen;
1404 
1405  if (out->s2s->dns_bad_timeout > 0) {
1406  dnsres_t bad = xhash_get(out->s2s->dns_bad, out->key);
1407 
1408  if (bad != NULL) {
1409  log_debug(ZONE, "removing bad host entry for '%s'", out->key);
1410  xhash_zap(out->s2s->dns_bad, out->key);
1411  free((void*)bad->key);
1412  free(bad);
1413  }
1414  }
1415 
1416  if (xhash_iter_first(out->routes)) {
1417  log_debug(ZONE, "sending dialback packets for %s", out->key);
1418  do {
1419  xhash_iter_get(out->routes, (const char **) &rkey, &rkeylen, NULL);
1420  _out_dialback(out, rkey, rkeylen);
1421  } while(xhash_iter_next(out->routes));
1422  }
1423 
1424  return;
1425 }
1426 
1427 static int _out_sx_callback(sx_t s, sx_event_t e, void *data, void *arg) {
1428  conn_t out = (conn_t) arg;
1429  sx_buf_t buf = (sx_buf_t) data;
1430  int len, ns, elem, starttls = 0;
1431  sx_error_t *sxe;
1432  nad_t nad;
1433 
1434  switch(e) {
1435  case event_WANT_READ:
1436  log_debug(ZONE, "want read");
1437  mio_read(out->s2s->mio, out->fd);
1438  break;
1439 
1440  case event_WANT_WRITE:
1441  log_debug(ZONE, "want write");
1442  mio_write(out->s2s->mio, out->fd);
1443  break;
1444 
1445  case event_READ:
1446  log_debug(ZONE, "reading from %d", out->fd->fd);
1447 
1448  /* do the read */
1449  len = recv(out->fd->fd, buf->data, buf->len, 0);
1450 
1451  if(len < 0) {
1452  if(MIO_WOULDBLOCK) {
1453  buf->len = 0;
1454  return 0;
1455  }
1456 
1457  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);
1458 
1459  if (!out->online) {
1460  _out_dns_mark_bad(out);
1461  }
1462 
1463  sx_kill(s);
1464 
1465  return -1;
1466  }
1467 
1468  else if(len == 0) {
1469  /* they went away */
1470  sx_kill(s);
1471 
1472  return -1;
1473  }
1474 
1475  log_debug(ZONE, "read %d bytes", len);
1476 
1477  buf->len = len;
1478 
1479  return len;
1480 
1481  case event_WRITE:
1482  log_debug(ZONE, "writing to %d", out->fd->fd);
1483 
1484  len = send(out->fd->fd, buf->data, buf->len, 0);
1485  if(len >= 0) {
1486  log_debug(ZONE, "%d bytes written", len);
1487  return len;
1488  }
1489 
1490  if(MIO_WOULDBLOCK)
1491  return 0;
1492 
1493  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);
1494 
1495  if (!out->online) {
1496  _out_dns_mark_bad(out);
1497  }
1498 
1499  sx_kill(s);
1500 
1501  return -1;
1502 
1503  case event_ERROR:
1504  sxe = (sx_error_t *) data;
1505  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);
1506 
1507  /* mark as bad if we did not manage to connect or there is unrecoverable stream error */
1508  if (!out->online ||
1509  (sxe->code == SX_ERR_STREAM &&
1510  (strstr(sxe->specific, "host-gone") || /* it's not there now */
1511  strstr(sxe->specific, "host-unknown") || /* they do not service the host */
1512  strstr(sxe->specific, "not-authorized") || /* they do not want us there */
1513  strstr(sxe->specific, "see-other-host") || /* we do not support redirections yet */
1514  strstr(sxe->specific, "system-shutdown") || /* they are going down */
1515  strstr(sxe->specific, "policy-violation") || /* they do not want us there */
1516  strstr(sxe->specific, "remote-connection-failed") || /* the required remote entity is gone */
1517  strstr(sxe->specific, "unsupported-encoding") || /* they do not like our encoding */
1518  strstr(sxe->specific, "undefined-condition") || /* something bad happend */
1519  strstr(sxe->specific, "internal-server-error") || /* that server is broken */
1520  strstr(sxe->specific, "unsupported-version") /* they do not support our stream version */
1521  ))) {
1522  _out_dns_mark_bad(out);
1523  }
1524 
1525  sx_kill(s);
1526 
1527  return -1;
1528 
1529  case event_OPEN:
1530  log_debug(ZONE, "OPEN event for %s", out->key);
1531  break;
1532 
1533  case event_STREAM:
1534  /* check stream version - NULl = pre-xmpp (some jabber1 servers) */
1535  log_debug(ZONE, "STREAM event for %s stream version is %s", out->key, out->s->res_version);
1536 
1537  /* first time, bring them online */
1538  if(!out->online) {
1539  log_debug(ZONE, "outgoing conn to %s is online", out->key);
1540 
1541  /* if no stream version from either side, kick off dialback for each route, */
1542  /* otherwise wait for stream features */
1543  if (((out->s->res_version==NULL) || (out->s2s->sx_ssl == NULL)) && out->s2s->require_tls == 0) {
1544  log_debug(ZONE, "no stream version, sending dialbacks for %s immediately", out->key);
1545  out->online = 1;
1546  send_dialbacks(out);
1547  } else
1548  log_debug(ZONE, "outgoing conn to %s - waiting for STREAM features", out->key);
1549  }
1550 
1551  break;
1552 
1553  case event_PACKET:
1554  /* we're counting packets */
1555  out->packet_count++;
1556  out->s2s->packet_count++;
1557 
1558  nad = (nad_t) data;
1559 
1560  /* watch for the features packet - STARTTLS and/or SASL*/
1561  if ((out->s->res_version!=NULL)
1562  && NAD_NURI_L(nad, NAD_ENS(nad, 0)) == strlen(uri_STREAMS)
1563  && strncmp(uri_STREAMS, NAD_NURI(nad, NAD_ENS(nad, 0)), strlen(uri_STREAMS)) == 0
1564  && NAD_ENAME_L(nad, 0) == 8 && strncmp("features", NAD_ENAME(nad, 0), 8) == 0) {
1565  log_debug(ZONE, "got the stream features packet");
1566 
1567 #ifdef HAVE_SSL
1568  /* starttls if we can */
1569  if(out->s2s->sx_ssl != NULL && s->ssf == 0) {
1570  ns = nad_find_scoped_namespace(nad, uri_TLS, NULL);
1571  if(ns >= 0) {
1572  elem = nad_find_elem(nad, 0, ns, "starttls", 1);
1573  if(elem >= 0) {
1574  log_debug(ZONE, "got STARTTLS in stream features");
1576  starttls = 1;
1577  nad_free(nad);
1578  return 0;
1579  }
1580  log_write(out->s2s->log, LOG_ERR, "unable to establish encrypted session with peer");
1581  }
1582  }
1583  }
1584 
1585  /* If we're not establishing a starttls connection, send dialbacks */
1586  if (!starttls) {
1587  if (out->s2s->require_tls == 0 || s->ssf > 0) {
1588  log_debug(ZONE, "No STARTTLS, sending dialbacks for %s", out->key);
1589  out->online = 1;
1590  send_dialbacks(out);
1591  } else {
1592  log_debug(ZONE, "No STARTTLS, dialbacks disabled for non-TLS connections, cannot complete negotiation");
1593  }
1594  }
1595 #else
1596  if (out->s2s->require_tls == 0) {
1597  out->online = 1;
1598  send_dialbacks(out);
1599  }
1600 #endif
1601  }
1602 
1603 
1604  /* we only accept dialback packets */
1605  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) {
1606  log_debug(ZONE, "got a non-dialback packet on an outgoing conn, dropping it");
1607  nad_free(nad);
1608  return 0;
1609  }
1610 
1611  /* and then only result and verify */
1612  if(NAD_ENAME_L(nad, 0) == 6) {
1613  if(strncmp("result", NAD_ENAME(nad, 0), 6) == 0) {
1614  _out_result(out, nad);
1615  return 0;
1616  }
1617 
1618  if(strncmp("verify", NAD_ENAME(nad, 0), 6) == 0) {
1619  _out_verify(out, nad);
1620  return 0;
1621  }
1622  }
1623 
1624  log_debug(ZONE, "unknown dialback packet, dropping it");
1625 
1626  nad_free(nad);
1627  return 0;
1628 
1629  case event_CLOSED:
1630  if (out->fd != NULL) {
1631  mio_close(out->s2s->mio, out->fd);
1632  out->fd = NULL;
1633  }
1634  return -1;
1635  }
1636 
1637  return 0;
1638 }
1639 
1641 static void _out_result(conn_t out, nad_t nad) {
1642  int attr;
1643  jid_t from, to;
1644  char *rkey;
1645  int rkeylen;
1646 
1647  attr = nad_find_attr(nad, 0, -1, "from", NULL);
1648  if(attr < 0 || (from = jid_new(NAD_AVAL(nad, attr), NAD_AVAL_L(nad, attr))) == NULL) {
1649  log_debug(ZONE, "missing or invalid from on db result packet");
1650  nad_free(nad);
1651  return;
1652  }
1653 
1654  attr = nad_find_attr(nad, 0, -1, "to", NULL);
1655  if(attr < 0 || (to = jid_new(NAD_AVAL(nad, attr), NAD_AVAL_L(nad, attr))) == NULL) {
1656  log_debug(ZONE, "missing or invalid to on db result packet");
1657  jid_free(from);
1658  nad_free(nad);
1659  return;
1660  }
1661 
1662  rkey = s2s_route_key(NULL, to->domain, from->domain);
1663  rkeylen = strlen(rkey);
1664 
1665  /* key is valid */
1666  if(nad_find_attr(nad, 0, -1, "type", "valid") >= 0 && xhash_get(out->states, rkey) == (void*) conn_INPROGRESS) {
1667  log_write(out->s2s->log, LOG_NOTICE, "[%d] [%s, port=%d] outgoing route '%s' is now valid %s",
1668  out->fd->fd, out->ip, out->port, rkey, _sx_flags(out->s));
1669 
1670  xhash_put(out->states, pstrdup(xhash_pool(out->states), rkey), (void *) conn_VALID); /* !!! small leak here */
1671 
1672  log_debug(ZONE, "%s valid, flushing queue", rkey);
1673 
1674  /* flush the queue */
1675  out_flush_route_queue(out->s2s, rkey, rkeylen);
1676 
1677  free(rkey);
1678 
1679  jid_free(from);
1680  jid_free(to);
1681 
1682  nad_free(nad);
1683 
1684  return;
1685  }
1686 
1687  /* invalid */
1688  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);
1689 
1690  /* close connection */
1691  log_write(out->s2s->log, LOG_NOTICE, "[%d] [%s, port=%d] closing connection", out->fd->fd, out->ip, out->port);
1692 
1693  /* report stream error */
1694  sx_error(out->s, stream_err_INVALID_ID, "dialback negotiation failed");
1695 
1696  /* close the stream */
1697  sx_close(out->s);
1698 
1699  /* bounce queue */
1701 
1702  free(rkey);
1703 
1704  jid_free(from);
1705  jid_free(to);
1706 
1707  nad_free(nad);
1708 }
1709 
1711 static void _out_verify(conn_t out, nad_t nad) {
1712  int attr, ns;
1713  jid_t from, to;
1714  conn_t in;
1715  char *rkey;
1716  int valid;
1717 
1718  attr = nad_find_attr(nad, 0, -1, "from", NULL);
1719  if(attr < 0 || (from = jid_new(NAD_AVAL(nad, attr), NAD_AVAL_L(nad, attr))) == NULL) {
1720  log_debug(ZONE, "missing or invalid from on db verify packet");
1721  nad_free(nad);
1722  return;
1723  }
1724 
1725  attr = nad_find_attr(nad, 0, -1, "to", NULL);
1726  if(attr < 0 || (to = jid_new(NAD_AVAL(nad, attr), NAD_AVAL_L(nad, attr))) == NULL) {
1727  log_debug(ZONE, "missing or invalid to on db verify packet");
1728  jid_free(from);
1729  nad_free(nad);
1730  return;
1731  }
1732 
1733  attr = nad_find_attr(nad, 0, -1, "id", NULL);
1734  if(attr < 0) {
1735  log_debug(ZONE, "missing id on db verify packet");
1736  jid_free(from);
1737  jid_free(to);
1738  nad_free(nad);
1739  return;
1740  }
1741 
1742  /* get the incoming conn */
1743  in = xhash_getx(out->s2s->in, NAD_AVAL(nad, attr), NAD_AVAL_L(nad, attr));
1744  if(in == NULL) {
1745  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));
1746  jid_free(from);
1747  jid_free(to);
1748  nad_free(nad);
1749  return;
1750  }
1751 
1752  rkey = s2s_route_key(NULL, to->domain, from->domain);
1753 
1754  attr = nad_find_attr(nad, 0, -1, "type", "valid");
1755  if(attr >= 0 && xhash_get(in->states, rkey) == (void*) conn_INPROGRESS) {
1756  xhash_put(in->states, pstrdup(xhash_pool(in->states), rkey), (void *) conn_VALID);
1757  log_write(in->s2s->log, LOG_NOTICE, "[%d] [%s, port=%d] incoming route '%s' is now valid %s",
1758  in->fd->fd, in->ip, in->port, rkey, _sx_flags(in->s));
1759  valid = 1;
1760  } else {
1761  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);
1762  valid = 0;
1763  }
1764 
1765  free(rkey);
1766 
1767  nad_free(nad);
1768 
1769  /* decrement outstanding verify counter */
1770  --out->verify;
1771 
1772  /* let them know what happened */
1773  nad = nad_new();
1774 
1775  ns = nad_add_namespace(nad, uri_DIALBACK, "db");
1776  nad_append_elem(nad, ns, "result", 0);
1777  nad_append_attr(nad, -1, "to", from->domain);
1778  nad_append_attr(nad, -1, "from", to->domain);
1779  nad_append_attr(nad, -1, "type", valid ? "valid" : "invalid");
1780 
1781  /* off it goes */
1782  sx_nad_write(in->s, nad);
1783 
1784  /* if invalid, close the stream */
1785  if (!valid) {
1786  /* generate stream error */
1787  sx_error(in->s, stream_err_INVALID_ID, "dialback negotiation failed");
1788 
1789  /* close the incoming stream */
1790  sx_close(in->s);
1791  }
1792 
1793  jid_free(from);
1794  jid_free(to);
1795 }
1796 
1797 /* bounce all packets in the queues for domain */
1798 int out_bounce_domain_queues(s2s_t s2s, const char *domain, int err)
1799 {
1800  char *rkey;
1801  int rkeylen;
1802  int pktcount = 0;
1803 
1804  if (xhash_iter_first(s2s->outq)) {
1805  do {
1806  xhash_iter_get(s2s->outq, (const char **) &rkey, &rkeylen, NULL);
1807  if(s2s_route_key_match(NULL, (char *) domain, rkey, rkeylen))
1808  pktcount += out_bounce_route_queue(s2s, rkey, rkeylen, err);
1809  } while(xhash_iter_next(s2s->outq));
1810  }
1811 
1812  return pktcount;
1813 }
1814 
1815 /* bounce all packets in the queue for route */
1816 int out_bounce_route_queue(s2s_t s2s, const char *rkey, int rkeylen, int err)
1817 {
1818  jqueue_t q;
1819  pkt_t pkt;
1820  int pktcount = 0;
1821 
1822  q = xhash_getx(s2s->outq, rkey, rkeylen);
1823  if(q == NULL)
1824  return 0;
1825 
1826  while((pkt = jqueue_pull(q)) != NULL) {
1827  /* only packets with content, in namespace jabber:client and not already errors */
1828  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) {
1829  sx_nad_write(s2s->router, stanza_tofrom(stanza_tofrom(stanza_error(pkt->nad, 1, err), 1), 0));
1830  pktcount++;
1831  }
1832  else
1833  nad_free(pkt->nad);
1834 
1835  jid_free(pkt->to);
1836  jid_free(pkt->from);
1837  free(pkt);
1838  }
1839 
1840  /* delete queue and remove domain from queue hash */
1841  log_debug(ZONE, "deleting out packet queue for %.*s", rkeylen, rkey);
1842  rkey = q->key;
1843  jqueue_free(q);
1844  xhash_zap(s2s->outq, rkey);
1845  free((void*)rkey);
1846 
1847  return pktcount;
1848 }
1849 
1851 {
1852  char *rkey;
1853  int rkeylen;
1854  int pktcount = 0;
1855 
1856  /* bounce queues for all domains handled by this connection - iterate through routes */
1857  if (xhash_iter_first(out->routes)) {
1858  do {
1859  xhash_iter_get(out->routes, (const char **) &rkey, &rkeylen, NULL);
1860  pktcount += out_bounce_route_queue(out->s2s, rkey, rkeylen, err);
1861  } while(xhash_iter_next(out->routes));
1862  }
1863 
1864  return pktcount;
1865 }
1866 
1867 void out_flush_domain_queues(s2s_t s2s, const char *domain) {
1868  char *rkey;
1869  int rkeylen;
1870  char *c;
1871  int c_len;
1872 
1873  if (xhash_iter_first(s2s->outq)) {
1874  do {
1875  xhash_iter_get(s2s->outq, (const char **) &rkey, &rkeylen, NULL);
1876  c = memchr(rkey, '/', rkeylen);
1877  c++;
1878  c_len = rkeylen - (c - rkey);
1879  if (strncmp(domain, c, c_len) == 0)
1880  out_flush_route_queue(s2s, rkey, rkeylen);
1881  } while(xhash_iter_next(s2s->outq));
1882  }
1883 }
1884 
1885 void out_flush_route_queue(s2s_t s2s, const char *rkey, int rkeylen) {
1886  jqueue_t q;
1887  pkt_t pkt;
1888  int npkt, i, ret;
1889 
1890  q = xhash_getx(s2s->outq, rkey, rkeylen);
1891  if(q == NULL)
1892  return;
1893 
1894  npkt = jqueue_size(q);
1895  log_debug(ZONE, "flushing %d packets for '%.*s' to out_packet", npkt, rkeylen, rkey);
1896 
1897  for(i = 0; i < npkt; i++) {
1898  pkt = jqueue_pull(q);
1899  if(pkt) {
1900  ret = out_packet(s2s, pkt);
1901  if (ret) {
1902  /* uh-oh. the queue was deleted...
1903  q and pkt have been freed
1904  if q->key == rkey, rkey has also been freed */
1905  return;
1906  }
1907  }
1908  }
1909 
1910  /* delete queue for route and remove route from queue hash */
1911  if (jqueue_size(q) == 0) {
1912  log_debug(ZONE, "deleting out packet queue for '%.*s'", rkeylen, rkey);
1913  rkey = q->key;
1914  jqueue_free(q);
1915  xhash_zap(s2s->outq, rkey);
1916  free((void*)rkey);
1917  } else {
1918  log_debug(ZONE, "emptied queue gained more packets...");
1919  }
1920 }
#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:1867
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:729
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'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:736
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:435
int db
Definition: s2s.h:240
Definition: sx.h:59
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:1400
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
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:1223
int nad_find_elem(nad_t nad, 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:204
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:737
#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:333
#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:762
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:1816
void out_pkt_free(pkt_t pkt)
Definition: out.c:601
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:695
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:178
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:1427
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:784
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:1189
void nad_set_attr(nad_t nad, 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:403
#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'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:401
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:1042
#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:680
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:839
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:1285
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:1885
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:498
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:1641
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:727
static void _dns_result_aaaa(struct dns_ctx *ctx, struct dns_rr_a6 *result, void *data)
Definition: out.c:918
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:406
time_t last_packet
Definition: s2s.h:284
static int _etc_hosts_lookup(const char *cszName, char *szIP, const int ciMaxIPLen)
Definition: out.c:966
int resolve_aaaa
if we resolve AAAA records
Definition: s2s.h:161
int ssf
Definition: sx.h:340
void * jqueue_pull(jqueue_t q)
Definition: jqueue.c:96
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'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
int nad_find_namespace(nad_t nad, int elem, const char *uri, const char *prefix)
get a matching ns on this elem, both uri and optional prefix
Definition: nad.c:262
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:1850
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:513
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:1711
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:399
#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 nad_find_attr(nad_t nad, 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:235
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:610
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:1116
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:1798
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:290
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:190