jabberd2  2.2.16
s2s/in.c
Go to the documentation of this file.
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 }