jabberd2
2.2.16
|
00001 /* 00002 * jabberd - Jabber Open Source Server 00003 * Copyright (c) 2002 Jeremie Miller, Thomas Muldowney, 00004 * Ryan Eatmon, Robert Norris 00005 * 00006 * This program is free software; you can redistribute it and/or modify 00007 * it under the terms of the GNU General Public License as published by 00008 * the Free Software Foundation; either version 2 of the License, or 00009 * (at your option) any later version. 00010 * 00011 * This program is distributed in the hope that it will be useful, 00012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the 00014 * GNU General Public License for more details. 00015 * 00016 * You should have received a copy of the GNU General Public License 00017 * along with this program; if not, write to the Free Software 00018 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA02111-1307USA 00019 */ 00020 00021 #include "s2s.h" 00022 00023 /* 00024 * we handle incoming connections, and the packets that arrive on them. 00025 * 00026 * action points: 00027 * 00028 * event_STREAM - new incoming connection 00029 * - create new dbconn (key stream id) 00030 * - DONE 00031 * 00032 * event_PACKET: <result from='them' to='us'>key</result> - auth request 00033 * - get dbconn for this sx 00034 * - if dbconn state is valid 00035 * - send result: <result to='them' from='us' type='valid'/> 00036 * - DONE 00037 * - out_packet(s2s, <verify to='them' from='us' id='stream id'>key</verify>) 00038 * - DONE 00039 * 00040 * event_PACKET: <verify from='them' to='us' id='123'>key</verify> - validate their key 00041 * - generate dbkey: sha1(secret+remote+id) 00042 * - if their key matches dbkey 00043 * - send them: <verify to='them' from='us' id='123' type='valid'/> 00044 * - else 00045 * - send them: <verify to='them' from='us' id='123' type='invalid'/> 00046 * - DONE 00047 * 00048 * event_PACKET - they're trying to send us something 00049 * - get dbconn for this sx 00050 * - if dbconn state is invalid 00051 * - drop packet 00052 * - DONE 00053 * - write packet to router 00054 * - DONE 00055 */ 00056 00057 /* forward decls */ 00058 static int _in_sx_callback(sx_t s, sx_event_t e, void *data, void *arg); 00059 static void _in_result(conn_t in, nad_t nad); 00060 static void _in_verify(conn_t in, nad_t nad); 00061 static void _in_packet(conn_t in, nad_t nad); 00062 00063 int in_mio_callback(mio_t m, mio_action_t a, mio_fd_t fd, void *data, void *arg) { 00064 conn_t in = (conn_t) arg; 00065 s2s_t s2s = (s2s_t) arg; 00066 struct sockaddr_storage sa; 00067 int namelen = sizeof(sa), port, nbytes, flags = 0; 00068 char ipport[INET6_ADDRSTRLEN + 17]; 00069 00070 switch(a) { 00071 case action_READ: 00072 log_debug(ZONE, "read action on fd %d", fd->fd); 00073 00074 ioctl(fd->fd, FIONREAD, &nbytes); 00075 if(nbytes == 0) { 00076 sx_kill(in->s); 00077 return 0; 00078 } 00079 00080 return sx_can_read(in->s); 00081 00082 case action_WRITE: 00083 log_debug(ZONE, "write action on fd %d", fd->fd); 00084 return sx_can_write(in->s); 00085 00086 case action_CLOSE: 00087 log_debug(ZONE, "close action on fd %d", fd->fd); 00088 00089 if (fd == s2s->server_fd) break; 00090 00091 /* !!! logging */ 00092 log_write(in->s2s->log, LOG_NOTICE, "[%d] [%s, port=%d] disconnect, packets: %i", fd->fd, in->ip, in->port, in->packet_count); 00093 00094 jqueue_push(in->s2s->dead, (void *) in->s, 0); 00095 00096 /* remove from open streams hash if online, or open connections if not */ 00097 if (in->online) 00098 xhash_zap(in->s2s->in, in->key); 00099 else { 00100 snprintf(ipport, INET6_ADDRSTRLEN + 16, "%s/%d", in->ip, in->port); 00101 xhash_zap(in->s2s->in_accept, ipport); 00102 } 00103 00104 jqueue_push(in->s2s->dead_conn, (void *) in, 0); 00105 00106 break; 00107 00108 case action_ACCEPT: 00109 s2s = (s2s_t) arg; 00110 00111 log_debug(ZONE, "accept action on fd %d", fd->fd); 00112 00113 getpeername(fd->fd, (struct sockaddr *) &sa, &namelen); 00114 port = j_inet_getport(&sa); 00115 00116 log_write(s2s->log, LOG_NOTICE, "[%d] [%s, port=%d] incoming connection", fd->fd, (char *) data, port); 00117 00118 /* new conn */ 00119 in = (conn_t) calloc(1, sizeof(struct conn_st)); 00120 00121 in->s2s = s2s; 00122 00123 strncpy(in->ip, (char *) data, INET6_ADDRSTRLEN); 00124 in->port = port; 00125 00126 in->states = xhash_new(101); 00127 in->states_time = xhash_new(101); 00128 00129 in->fd = fd; 00130 00131 in->init_time = time(NULL); 00132 00133 in->s = sx_new(s2s->sx_env, in->fd->fd, _in_sx_callback, (void *) in); 00134 mio_app(m, in->fd, in_mio_callback, (void *) in); 00135 00136 if(s2s->stanza_size_limit != 0) 00137 in->s->rbytesmax = s2s->stanza_size_limit; 00138 00139 /* add to incoming connections hash */ 00140 snprintf(ipport, INET6_ADDRSTRLEN + 16, "%s/%d", in->ip, in->port); 00141 xhash_put(s2s->in_accept, pstrdup(xhash_pool(s2s->in_accept),ipport), (void *) in); 00142 00143 flags = S2S_DB_HEADER; 00144 #ifdef HAVE_SSL 00145 if(s2s->sx_ssl != NULL) 00146 flags |= SX_SSL_STARTTLS_OFFER; 00147 #endif 00148 #ifdef HAVE_LIBZ 00149 if(s2s->compression) 00150 flags |= SX_COMPRESS_OFFER; 00151 #endif 00152 sx_server_init(in->s, flags); 00153 break; 00154 } 00155 00156 return 0; 00157 } 00158 00159 static int _in_sx_callback(sx_t s, sx_event_t e, void *data, void *arg) { 00160 conn_t in = (conn_t) arg; 00161 sx_buf_t buf = (sx_buf_t) data; 00162 int len; 00163 sx_error_t *sxe; 00164 nad_t nad; 00165 char ipport[INET6_ADDRSTRLEN + 17]; 00166 jid_t from; 00167 int attr; 00168 00169 switch(e) { 00170 case event_WANT_READ: 00171 log_debug(ZONE, "want read"); 00172 mio_read(in->s2s->mio, in->fd); 00173 break; 00174 00175 case event_WANT_WRITE: 00176 log_debug(ZONE, "want write"); 00177 mio_write(in->s2s->mio, in->fd); 00178 break; 00179 00180 case event_READ: 00181 log_debug(ZONE, "reading from %d", in->fd->fd); 00182 00183 /* do the read */ 00184 len = recv(in->fd->fd, buf->data, buf->len, 0); 00185 00186 if(len < 0) { 00187 if(MIO_WOULDBLOCK) { 00188 buf->len = 0; 00189 return 0; 00190 } 00191 00192 log_write(in->s2s->log, LOG_NOTICE, "[%d] [%s, port=%d] read error: %s (%d)", in->fd->fd, in->ip, in->port, MIO_STRERROR(MIO_ERROR), MIO_ERROR); 00193 00194 sx_kill(s); 00195 00196 return -1; 00197 } 00198 00199 else if(len == 0) { 00200 /* they went away */ 00201 sx_kill(s); 00202 00203 return -1; 00204 } 00205 00206 log_debug(ZONE, "read %d bytes", len); 00207 00208 buf->len = len; 00209 00210 return len; 00211 00212 case event_WRITE: 00213 log_debug(ZONE, "writing to %d", in->fd->fd); 00214 00215 len = send(in->fd->fd, buf->data, buf->len, 0); 00216 if(len >= 0) { 00217 log_debug(ZONE, "%d bytes written", len); 00218 return len; 00219 } 00220 00221 if(MIO_WOULDBLOCK) 00222 return 0; 00223 00224 log_write(in->s2s->log, LOG_NOTICE, "[%d] [%s, port=%d] write error: %s (%d)", in->fd->fd, in->ip, in->port, MIO_STRERROR(MIO_ERROR), MIO_ERROR); 00225 00226 sx_kill(s); 00227 00228 return -1; 00229 00230 case event_ERROR: 00231 sxe = (sx_error_t *) data; 00232 log_write(in->s2s->log, LOG_NOTICE, "[%d] [%s, port=%d] error: %s (%s)", in->fd->fd, in->ip, in->port, sxe->generic, sxe->specific); 00233 00234 break; 00235 00236 case event_STREAM: 00237 case event_OPEN: 00238 00239 log_debug(ZONE, "STREAM or OPEN event from %s port %d (id %s)", in->ip, in->port, s->id); 00240 00241 /* first time, bring them online */ 00242 if ((!in->online)||(strcmp(in->key,s->id)!=0)) { 00243 log_write(in->s2s->log, LOG_NOTICE, "[%d] [%s, port=%d] incoming stream online (id %s)", in->fd->fd, in->ip, in->port, s->id); 00244 00245 in->online = 1; 00246 00247 /* record the id */ 00248 if (in->key != NULL) { 00249 log_debug(ZONE,"adding new SSL stream id %s for stream id %s", s->id, in->key); 00250 00251 /* remove the initial (non-SSL) stream id from the in connections hash */ 00252 xhash_zap(in->s2s->in, in->key); 00253 free(in->key); 00254 } 00255 00256 in->key = strdup(s->id); 00257 00258 /* track it - add to open streams hash and remove from new connections hash */ 00259 xhash_put(in->s2s->in, in->key, (void *) in); 00260 00261 snprintf(ipport, INET6_ADDRSTRLEN + 16, "%s/%d", in->ip, in->port); 00262 xhash_zap(in->s2s->in_accept, ipport); 00263 } 00264 00265 break; 00266 00267 case event_PACKET: 00268 /* we're counting packets */ 00269 in->packet_count++; 00270 in->s2s->packet_count++; 00271 00272 nad = (nad_t) data; 00273 00274 /* update last packet timestamp */ 00275 in->last_packet = time(NULL); 00276 00277 /* dialback packets */ 00278 if(NAD_NURI_L(nad, NAD_ENS(nad, 0)) == strlen(uri_DIALBACK) && strncmp(uri_DIALBACK, NAD_NURI(nad, NAD_ENS(nad, 0)), strlen(uri_DIALBACK)) == 0 && 00279 (in->s2s->require_tls == 0 || s->ssf > 0)) { 00280 /* only result and verify mean anything */ 00281 if(NAD_ENAME_L(nad, 0) == 6) { 00282 if(strncmp("result", NAD_ENAME(nad, 0), 6) == 0) { 00283 _in_result(in, nad); 00284 return 0; 00285 } 00286 00287 if(strncmp("verify", NAD_ENAME(nad, 0), 6) == 0) { 00288 _in_verify(in, nad); 00289 return 0; 00290 } 00291 } 00292 00293 log_debug(ZONE, "unknown dialback packet, dropping it"); 00294 00295 nad_free(nad); 00296 return 0; 00297 } 00298 00299 /* 00300 * not dialback, so it has to be a normal-ish jabber packet: 00301 * - jabber:client or jabber:server 00302 * - message, presence or iq 00303 * - has to and from attributes 00304 */ 00305 00306 if(!( 00307 /* must be jabber:client or jabber:server */ 00308 NAD_ENS(nad, 0) >= 0 && 00309 ((NAD_NURI_L(nad, NAD_ENS(nad, 0)) == strlen(uri_CLIENT) && strncmp(uri_CLIENT, NAD_NURI(nad, NAD_ENS(nad, 0)), strlen(uri_CLIENT)) == 0) || 00310 (NAD_NURI_L(nad, NAD_ENS(nad, 0)) == strlen(uri_SERVER) && strncmp(uri_SERVER, NAD_NURI(nad, NAD_ENS(nad, 0)), strlen(uri_SERVER)) == 0)) && ( 00311 /* can be message */ 00312 (NAD_ENAME_L(nad, 0) == 7 && strncmp("message", NAD_ENAME(nad, 0), 7) == 0) || 00313 /* or presence */ 00314 (NAD_ENAME_L(nad, 0) == 8 && strncmp("presence", NAD_ENAME(nad, 0), 8) == 0) || 00315 /* or iq */ 00316 (NAD_ENAME_L(nad, 0) == 2 && strncmp("iq", NAD_ENAME(nad, 0), 2) == 0) 00317 ) && 00318 /* to and from required */ 00319 nad_find_attr(nad, 0, -1, "to", NULL) >= 0 && nad_find_attr(nad, 0, -1, "from", NULL) >= 0 00320 )) { 00321 log_debug(ZONE, "they sent us a non-jabber looking packet, dropping it"); 00322 nad_free(nad); 00323 return 0; 00324 } 00325 00326 /* perform check against whitelist */ 00327 attr = nad_find_attr(nad, 0, -1, "from", NULL); 00328 if(attr < 0 || (from = jid_new(NAD_AVAL(nad, attr), NAD_AVAL_L(nad, attr))) == NULL) { 00329 log_debug(ZONE, "missing or invalid from on incoming packet, attr is %d", attr); 00330 nad_free(nad); 00331 return 0; 00332 } 00333 00334 if (in->s2s->enable_whitelist > 0 && (s2s_domain_in_whitelist(in->s2s, from->domain) == 0)) { 00335 log_write(in->s2s->log, LOG_NOTICE, "received a packet not from a whitelisted domain %s, dropping it", from->domain); 00336 jid_free(from); 00337 nad_free(nad); 00338 return 0; 00339 } 00340 00341 jid_free(from); 00342 00343 _in_packet(in, nad); 00344 return 0; 00345 00346 case event_CLOSED: 00347 if (in->fd != NULL) { 00348 mio_close(in->s2s->mio, in->fd); 00349 in->fd = NULL; 00350 } 00351 return -1; 00352 } 00353 00354 return 0; 00355 } 00356 00358 static void _in_result(conn_t in, nad_t nad) { 00359 int attr, ns; 00360 jid_t from, to; 00361 char *rkey; 00362 nad_t verify; 00363 pkt_t pkt; 00364 time_t now; 00365 00366 attr = nad_find_attr(nad, 0, -1, "from", NULL); 00367 if(attr < 0 || (from = jid_new(NAD_AVAL(nad, attr), NAD_AVAL_L(nad, attr))) == NULL) { 00368 log_debug(ZONE, "missing or invalid from on db result packet"); 00369 nad_free(nad); 00370 return; 00371 } 00372 00373 attr = nad_find_attr(nad, 0, -1, "to", NULL); 00374 if(attr < 0 || (to = jid_new(NAD_AVAL(nad, attr), NAD_AVAL_L(nad, attr))) == NULL) { 00375 log_debug(ZONE, "missing or invalid to on db result packet"); 00376 jid_free(from); 00377 nad_free(nad); 00378 return; 00379 } 00380 00381 rkey = s2s_route_key(NULL, to->domain, from->domain); 00382 00383 log_write(in->s2s->log, LOG_NOTICE, "[%d] [%s, port=%d] received dialback auth request for route '%s'", in->fd->fd, in->ip, in->port, rkey); 00384 00385 /* get current state */ 00386 if((conn_state_t) xhash_get(in->states, rkey) == conn_VALID) { 00387 log_write(in->s2s->log, LOG_NOTICE, "[%d] [%s, port=%d] route '%s' is already valid: sending valid", in->fd->fd, in->ip, in->port, rkey); 00388 00389 /* its already valid, just reply right now */ 00390 stanza_tofrom(nad, 0); 00391 nad_set_attr(nad, 0, -1, "type", "valid", 5); 00392 nad->elems[0].icdata = nad->elems[0].itail = -1; 00393 nad->elems[0].lcdata = nad->elems[0].ltail = 0; 00394 00395 sx_nad_write(in->s, nad); 00396 00397 free(rkey); 00398 00399 jid_free(from); 00400 jid_free(to); 00401 00402 return; 00403 } 00404 00405 /* not valid, so we need to verify */ 00406 00407 /* need the key */ 00408 if(NAD_CDATA_L(nad, 0) <= 0) { 00409 log_write(in->s2s->log, LOG_NOTICE, "[%d] [%s, port=%d] no dialback key given with db result packet", in->fd->fd, in->ip, in->port, rkey); 00410 free(rkey); 00411 nad_free(nad); 00412 jid_free(from); 00413 jid_free(to); 00414 return; 00415 } 00416 00417 log_debug(ZONE, "requesting verification for route %s", rkey); 00418 00419 /* set the route status to INPROGRESS and set timestamp */ 00420 xhash_put(in->states, pstrdup(xhash_pool(in->states), rkey), (void *) conn_INPROGRESS); 00421 00422 /* record the time that we set conn_INPROGRESS state */ 00423 now = time(NULL); 00424 xhash_put(in->states_time, pstrdup(xhash_pool(in->states_time), rkey), (void *) now); 00425 00426 free(rkey); 00427 00428 /* new packet */ 00429 verify = nad_new(); 00430 ns = nad_add_namespace(verify, uri_DIALBACK, "db"); 00431 00432 nad_append_elem(verify, ns, "verify", 0); 00433 nad_append_attr(verify, -1, "to", from->domain); 00434 nad_append_attr(verify, -1, "from", to->domain); 00435 nad_append_attr(verify, -1, "id", in->s->id); 00436 nad_append_cdata(verify, NAD_CDATA(nad, 0), NAD_CDATA_L(nad, 0), 1); 00437 00438 /* new packet */ 00439 pkt = (pkt_t) calloc(1, sizeof(struct pkt_st)); 00440 00441 pkt->nad = verify; 00442 00443 pkt->to = from; 00444 pkt->from = to; 00445 00446 pkt->db = 1; 00447 00448 /* its away */ 00449 out_packet(in->s2s, pkt); 00450 00451 nad_free(nad); 00452 } 00453 00455 static void _in_verify(conn_t in, nad_t nad) { 00456 int attr; 00457 jid_t from, to; 00458 char *id, *dbkey, *type; 00459 00460 attr = nad_find_attr(nad, 0, -1, "from", NULL); 00461 if(attr < 0 || (from = jid_new(NAD_AVAL(nad, attr), NAD_AVAL_L(nad, attr))) == NULL) { 00462 log_debug(ZONE, "missing or invalid from on db verify packet"); 00463 nad_free(nad); 00464 return; 00465 } 00466 00467 attr = nad_find_attr(nad, 0, -1, "to", NULL); 00468 if(attr < 0 || (to = jid_new(NAD_AVAL(nad, attr), NAD_AVAL_L(nad, attr))) == NULL) { 00469 log_debug(ZONE, "missing or invalid to on db verify packet"); 00470 jid_free(from); 00471 nad_free(nad); 00472 return; 00473 } 00474 00475 attr = nad_find_attr(nad, 0, -1, "id", NULL); 00476 if(attr < 0) { 00477 log_debug(ZONE, "missing id on db verify packet"); 00478 jid_free(from); 00479 jid_free(to); 00480 nad_free(nad); 00481 return; 00482 } 00483 00484 if(NAD_CDATA_L(nad, 0) <= 0) { 00485 log_debug(ZONE, "no cdata on db verify packet"); 00486 jid_free(from); 00487 jid_free(to); 00488 nad_free(nad); 00489 return; 00490 } 00491 00492 /* extract the id */ 00493 id = (char *) malloc(sizeof(char) * (NAD_AVAL_L(nad, attr) + 1)); 00494 snprintf(id, NAD_AVAL_L(nad, attr) + 1, "%.*s", NAD_AVAL_L(nad, attr), NAD_AVAL(nad, attr)); 00495 00496 /* generate a dialback key */ 00497 dbkey = s2s_db_key(NULL, in->s2s->local_secret, from->domain, id); 00498 00499 /* valid */ 00500 if(NAD_CDATA_L(nad, 0) == strlen(dbkey) && strncmp(dbkey, NAD_CDATA(nad, 0), NAD_CDATA_L(nad, 0)) == 0) { 00501 log_debug(ZONE, "valid dialback key %s, verify succeeded", dbkey); 00502 type = "valid"; 00503 } else { 00504 log_debug(ZONE, "invalid dialback key %s, verify failed", dbkey); 00505 type = "invalid"; 00506 } 00507 00508 log_write(in->s2s->log, LOG_NOTICE, "[%d] [%s, port=%d] checking dialback verification from %s: sending %s", in->fd->fd, in->ip, in->port, from->domain, type); 00509 00510 log_debug(ZONE, "letting them know"); 00511 00512 /* now munge the packet and send it back to them */ 00513 stanza_tofrom(nad, 0); 00514 nad_set_attr(nad, 0, -1, "type", type, 0); 00515 nad->elems[0].icdata = nad->elems[0].itail = -1; 00516 nad->elems[0].lcdata = nad->elems[0].ltail = 0; 00517 00518 sx_nad_write(in->s, nad); 00519 00520 free(dbkey); 00521 free(id); 00522 00523 jid_free(from); 00524 jid_free(to); 00525 00526 return; 00527 } 00528 00530 static void _in_packet(conn_t in, nad_t nad) { 00531 int elem, attr, ns, sns; 00532 jid_t from, to; 00533 char *rkey; 00534 00535 attr = nad_find_attr(nad, 0, -1, "from", NULL); 00536 if(attr < 0 || (from = jid_new(NAD_AVAL(nad, attr), NAD_AVAL_L(nad, attr))) == NULL) { 00537 log_debug(ZONE, "missing or invalid from on incoming packet"); 00538 nad_free(nad); 00539 return; 00540 } 00541 00542 attr = nad_find_attr(nad, 0, -1, "to", NULL); 00543 if(attr < 0 || (to = jid_new(NAD_AVAL(nad, attr), NAD_AVAL_L(nad, attr))) == NULL) { 00544 log_debug(ZONE, "missing or invalid to on incoming packet"); 00545 jid_free(from); 00546 nad_free(nad); 00547 return; 00548 } 00549 00550 rkey = s2s_route_key(NULL, to->domain, from->domain); 00551 00552 log_debug(ZONE, "received packet from %s for %s", in->key, rkey); 00553 00554 /* drop packets received on routes not valid on that connection as per XMPP 8.3.10 */ 00555 if((conn_state_t) xhash_get(in->states, rkey) != conn_VALID) { 00556 log_write(in->s2s->log, LOG_NOTICE, "[%d] [%s, port=%d] dropping packet on unvalidated route: '%s'", in->fd->fd, in->ip, in->port, rkey); 00557 free(rkey); 00558 nad_free(nad); 00559 jid_free(from); 00560 jid_free(to); 00561 return; 00562 } 00563 00564 free(rkey); 00565 00566 /* its good, off to the router with it */ 00567 00568 log_debug(ZONE, "incoming packet on valid route, preparing it for the router"); 00569 00570 /* rewrite server packets into client packets */ 00571 ns = nad_find_namespace(nad, 0, uri_SERVER, NULL); 00572 if(ns >= 0) { 00573 if(nad->elems[0].ns == ns) 00574 nad->elems[0].ns = nad->nss[nad->elems[0].ns].next; 00575 else { 00576 for(sns = nad->elems[0].ns; sns >= 0 && nad->nss[sns].next != ns; sns = nad->nss[sns].next); 00577 nad->nss[sns].next = nad->nss[nad->nss[sns].next].next; 00578 } 00579 } 00580 00581 /* 00582 * If stanza is not in any namespace (either because we removed the 00583 * jabber:server namespace above or because it's in the default 00584 * namespace for this stream) then this packet is intended to be 00585 * handled by sm (and not just routed through the server), so set the 00586 * jabber:client namespace. 00587 */ 00588 if(ns >= 0 || nad->elems[0].ns < 0) { 00589 ns = nad_add_namespace(nad, uri_CLIENT, NULL); 00590 for(elem = 0; elem < nad->ecur; elem++) 00591 if(nad->elems[elem].ns == ns) 00592 nad->elems[elem].ns = nad->nss[nad->elems[elem].ns].next; 00593 nad->nss[ns].next = nad->elems[0].ns; 00594 nad->elems[0].ns = ns; 00595 nad->scope = -1; 00596 } 00597 00598 nad->elems[0].my_ns = nad->elems[0].ns; 00599 00600 /* wrap up the packet */ 00601 ns = nad_add_namespace(nad, uri_COMPONENT, NULL); 00602 00603 nad_wrap_elem(nad, 0, ns, "route"); 00604 00605 nad_set_attr(nad, 0, -1, "to", to->domain, 0); 00606 nad_set_attr(nad, 0, -1, "from", in->s2s->id, 0); /* route is from s2s, not packet source */ 00607 00608 log_debug(ZONE, "sending packet to %s", to->domain); 00609 00610 /* go */ 00611 sx_nad_write(in->s2s->router, nad); 00612 00613 jid_free(from); 00614 jid_free(to); 00615 }