jabberd2  2.3.6
router.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 #include "s2s.h"
22 
24 int s2s_router_sx_callback(sx_t s, sx_event_t e, void *data, void *arg) {
25  s2s_t s2s = (s2s_t) arg;
26  sx_buf_t buf = (sx_buf_t) data;
27  sx_error_t *sxe;
28  nad_t nad;
29  int len, ns, elem, attr, i;
30  pkt_t pkt;
31 
32  switch(e) {
33  case event_WANT_READ:
34  log_debug(ZONE, "want read");
35  mio_read(s2s->mio, s2s->fd);
36  break;
37 
38  case event_WANT_WRITE:
39  log_debug(ZONE, "want write");
40  mio_write(s2s->mio, s2s->fd);
41  break;
42 
43  case event_READ:
44  log_debug(ZONE, "reading from %d", s2s->fd->fd);
45 
46  /* do the read */
47  len = recv(s2s->fd->fd, buf->data, buf->len, 0);
48 
49  if(len < 0) {
50  if(MIO_WOULDBLOCK) {
51  buf->len = 0;
52  return 0;
53  }
54 
55  log_write(s2s->log, LOG_NOTICE, "[%d] [router] read error: %s (%d)", s2s->fd->fd, MIO_STRERROR(MIO_ERROR), MIO_ERROR);
56 
57  sx_kill(s);
58 
59  return -1;
60  }
61 
62  else if(len == 0) {
63  /* they went away */
64  sx_kill(s);
65 
66  return -1;
67  }
68 
69  log_debug(ZONE, "read %d bytes", len);
70 
71  buf->len = len;
72 
73  return len;
74 
75  case event_WRITE:
76  log_debug(ZONE, "writing to %d", s2s->fd->fd);
77 
78  len = send(s2s->fd->fd, buf->data, buf->len, 0);
79  if(len >= 0) {
80  log_debug(ZONE, "%d bytes written", len);
81  return len;
82  }
83 
84  if(MIO_WOULDBLOCK)
85  return 0;
86 
87  log_write(s2s->log, LOG_NOTICE, "[%d] [router] write error: %s (%d)", s2s->fd->fd, MIO_STRERROR(MIO_ERROR), MIO_ERROR);
88 
89  sx_kill(s);
90 
91  return -1;
92 
93  case event_ERROR:
94  sxe = (sx_error_t *) data;
95  log_write(s2s->log, LOG_NOTICE, "error from router: %s (%s)", sxe->generic, sxe->specific);
96 
97  if(sxe->code == SX_ERR_AUTH)
98  sx_close(s);
99 
100  break;
101 
102  case event_STREAM:
103  break;
104 
105  case event_OPEN:
106  log_write(s2s->log, LOG_NOTICE, "connection to router established");
107 
108  /* set connection attempts counter */
109  s2s->retry_left = s2s->retry_lost;
110 
111  nad = nad_new();
112  ns = nad_add_namespace(nad, uri_COMPONENT, NULL);
113  nad_append_elem(nad, ns, "bind", 0);
114  nad_append_attr(nad, -1, "name", s2s->id);
115  if(s2s->router_default)
116  nad_append_elem(nad, ns, "default", 1);
117 
118  log_debug(ZONE, "requesting component bind for '%s'", s2s->id);
119 
120  sx_nad_write(s2s->router, nad);
121 
122  break;
123 
124  case event_PACKET:
125  nad = (nad_t) data;
126 
127  /* drop unqualified packets */
128  if(NAD_ENS(nad, 0) < 0) {
129  nad_free(nad);
130  return 0;
131  }
132 
133  /* watch for the features packet */
134  if(s->state == state_STREAM) {
135  if(NAD_NURI_L(nad, NAD_ENS(nad, 0)) != strlen(uri_STREAMS) || strncmp(uri_STREAMS, NAD_NURI(nad, NAD_ENS(nad, 0)), strlen(uri_STREAMS)) != 0 || NAD_ENAME_L(nad, 0) != 8 || strncmp("features", NAD_ENAME(nad, 0), 8) != 0) {
136  log_debug(ZONE, "got a non-features packet on an unauth'd stream, dropping");
137  nad_free(nad);
138  return 0;
139  }
140 
141 #ifdef HAVE_SSL
142  /* starttls if we can */
143  if(s2s->sx_ssl != NULL && s2s->router_pemfile != NULL && s->ssf == 0) {
144  ns = nad_find_scoped_namespace(nad, uri_TLS, NULL);
145  if(ns >= 0) {
146  elem = nad_find_elem(nad, 0, ns, "starttls", 1);
147  if(elem >= 0) {
149  nad_free(nad);
150  return 0;
151  }
152  log_write(s2s->log, LOG_NOTICE, "unable to establish encrypted session with router");
153  }
154  }
155  }
156 #endif
157 
158  /* !!! pull the list of mechanisms, and choose the best one.
159  * if there isn't an appropriate one, error and bail */
160 
161  /* authenticate */
162  sx_sasl_auth(s2s->sx_sasl, s, "jabberd-router", "DIGEST-MD5", s2s->router_user, s2s->router_pass);
163 
164  nad_free(nad);
165  return 0;
166  }
167 
168  /* watch for the bind response */
169  if(s->state == state_OPEN && !s2s->online) {
170  if(NAD_NURI_L(nad, NAD_ENS(nad, 0)) != strlen(uri_COMPONENT) || strncmp(uri_COMPONENT, NAD_NURI(nad, NAD_ENS(nad, 0)), strlen(uri_COMPONENT)) != 0 || NAD_ENAME_L(nad, 0) != 4 || strncmp("bind", NAD_ENAME(nad, 0), 4)) {
171  log_debug(ZONE, "got a packet from router, but we're not online, dropping");
172  nad_free(nad);
173  return 0;
174  }
175 
176  /* catch errors */
177  attr = nad_find_attr(nad, 0, -1, "error", NULL);
178  if(attr >= 0) {
179  log_write(s2s->log, LOG_NOTICE, "router refused bind request (%.*s)", NAD_AVAL_L(nad, attr), NAD_AVAL(nad, attr));
180  exit(1);
181  }
182 
183  log_debug(ZONE, "coming online");
184 
185  /* if we're coming online for the first time, setup listening sockets */
186  if(s2s->server_fd == 0) {
187  if(s2s->local_port != 0) {
188  s2s->server_fd = mio_listen(s2s->mio, s2s->local_port, s2s->local_ip, in_mio_callback, (void *) s2s);
189  if(s2s->server_fd == NULL) {
190  log_write(s2s->log, LOG_ERR, "[%s, port=%d] failed to listen", s2s->local_ip, s2s->local_port);
191  exit(1);
192  } else
193  log_write(s2s->log, LOG_NOTICE, "[%s, port=%d] listening for connections", s2s->local_ip, s2s->local_port);
194  }
195  }
196 
197  /* we're online */
198  s2s->online = s2s->started = 1;
199  log_write(s2s->log, LOG_NOTICE, "ready for connections", s2s->id);
200 
201  nad_free(nad);
202  return 0;
203  }
204 
205  log_debug(ZONE, "got a packet");
206 
207  /* sanity checks */
208  if(NAD_NURI_L(nad, NAD_ENS(nad, 0)) != strlen(uri_COMPONENT) || strncmp(uri_COMPONENT, NAD_NURI(nad, NAD_ENS(nad, 0)), strlen(uri_COMPONENT)) != 0) {
209  log_debug(ZONE, "unknown namespace, dropping packet");
210  nad_free(nad);
211  return 0;
212  }
213 
214  if(NAD_ENAME_L(nad, 0) != 5 || strncmp("route", NAD_ENAME(nad, 0), 5) != 0) {
215  log_debug(ZONE, "dropping non-route packet");
216  nad_free(nad);
217  return 0;
218  }
219 
220  if(nad_find_attr(nad, 0, -1, "type", NULL) >= 0) {
221  log_debug(ZONE, "dropping non-unicast packet");
222  nad_free(nad);
223  return 0;
224  }
225 
226  /* packets to us */
227  attr = nad_find_attr(nad, 0, -1, "to", NULL);
228  if(NAD_AVAL_L(nad, attr) == strlen(s2s->id) && strncmp(s2s->id, NAD_AVAL(nad, attr), NAD_AVAL_L(nad, attr)) == 0) {
229  log_debug(ZONE, "dropping unknown or invalid packet for s2s component proper");
230  nad_free(nad);
231 
232  return 0;
233  }
234 
235  /* mangle error packet to create bounce */
236  if((attr = nad_find_attr(nad, 0, -1, "error", NULL)) >= 0) {
237  log_debug(ZONE, "bouncing error packet");
239  if(attr >= 0) {
240  for(i=0; _stanza_errors[i].code != NULL; i++)
241  if(strncmp(_stanza_errors[i].code, NAD_AVAL(nad, attr), NAD_AVAL_L(nad, attr)) == 0) {
242  elem = stanza_err_BAD_REQUEST + i;
243  break;
244  }
245  }
246  stanza_tofrom(stanza_tofrom(stanza_error(nad, 1, elem), 1), 0);
247  if( (elem = nad_find_attr(nad, 1, -1, "to", NULL)) >= 0 )
248  nad_set_attr(nad, 0, -1, "to", NAD_AVAL(nad, elem), NAD_AVAL_L(nad, elem));
249  }
250 
251  /* new packet */
252  pkt = (pkt_t) calloc(1, sizeof(struct pkt_st));
253 
254  pkt->nad = nad;
255 
256  if((attr = nad_find_attr(pkt->nad, 1, -1, "from", NULL)) >= 0 && NAD_AVAL_L(pkt->nad, attr) > 0)
257  pkt->from = jid_new(NAD_AVAL(pkt->nad, attr), NAD_AVAL_L(pkt->nad, attr));
258  else {
259  attr = nad_find_attr(nad, 0, -1, "from", NULL);
260  pkt->from = jid_new(NAD_AVAL(nad, attr), NAD_AVAL_L(nad, attr));
261  }
262 
263  if((attr = nad_find_attr(pkt->nad, 1, -1, "to", NULL)) >= 0 && NAD_AVAL_L(pkt->nad, attr) > 0)
264  pkt->to = jid_new(NAD_AVAL(pkt->nad, attr), NAD_AVAL_L(pkt->nad, attr));
265  else {
266  attr = nad_find_attr(nad, 0, -1, "to", NULL);
267  pkt->to = jid_new(NAD_AVAL(nad, attr), NAD_AVAL_L(nad, attr));
268  }
269 
270  /* change the packet so it looks like it came to us, so the router won't reject it if we bounce it later */
271  nad_set_attr(nad, 0, -1, "to", s2s->id, 0);
272 
273  /* flag dialback */
274  if(NAD_NURI_L(pkt->nad, 0) == uri_DIALBACK_L && strncmp(uri_DIALBACK, NAD_NURI(pkt->nad, 0), uri_DIALBACK_L) == 0)
275  pkt->db = 1;
276 
277  /* send it out */
278  out_packet(s2s, pkt);
279 
280  return 0;
281 
282  case event_CLOSED:
283  mio_close(s2s->mio, s2s->fd);
284  s2s->fd = NULL;
285  return -1;
286  }
287 
288  return 0;
289 }
290 
291 int s2s_router_mio_callback(mio_t m, mio_action_t a, mio_fd_t fd, void *data, void *arg) {
292  s2s_t s2s = (s2s_t) arg;
293  int nbytes;
294 
295  switch(a) {
296  case action_READ:
297  log_debug(ZONE, "read action on fd %d", fd->fd);
298 
299  ioctl(fd->fd, FIONREAD, &nbytes);
300  if(nbytes == 0) {
301  sx_kill(s2s->router);
302  return 0;
303  }
304 
305  return sx_can_read(s2s->router);
306 
307  case action_WRITE:
308  log_debug(ZONE, "write action on fd %d", fd->fd);
309  return sx_can_write(s2s->router);
310 
311  case action_CLOSE:
312  log_debug(ZONE, "close action on fd %d", fd->fd);
313  log_write(s2s->log, LOG_NOTICE, "connection to router closed");
314 
315  s2s_lost_router = 1;
316 
317  /* we're offline */
318  s2s->online = 0;
319 
320  break;
321 
322  case action_ACCEPT:
323  break;
324  }
325 
326  return 0;
327 }
Definition: nad.h:93
struct _stanza_error_st _stanza_errors[]
if you change these, reflect your changes in the defines in util.h
Definition: stanza.c:24
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
sx_t router
router's conn
Definition: s2s.h:91
_sx_state_t state
Definition: sx.h:316
#define sx_nad_write(s, nad)
Definition: sx.h:167
int db
Definition: s2s.h:240
Definition: sx.h:59
const char * local_ip
ip/port to listen on
Definition: s2s.h:119
log_t log
logging
Definition: s2s.h:101
int s2s_router_mio_callback(mio_t m, mio_action_t a, mio_fd_t fd, void *data, void *arg)
Definition: router.c:291
const char * router_pass
Definition: s2s.h:74
jid_t jid_new(const char *id, int len)
make a new jid
Definition: jid.c:81
int started
this is true if we've connected to the router at least once
Definition: s2s.h:198
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
void log_write(log_t log, int level, const char *msgfmt,...)
Definition: log.c:104
error info for event_ERROR
Definition: sx.h:99
int s2s_router_sx_callback(sx_t s, sx_event_t e, void *data, void *arg)
our master callback
Definition: router.c:24
#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
mio_fd_t fd
Definition: s2s.h:92
int nad_add_namespace(nad_t nad, const char *uri, const char *prefix)
bring a new namespace into scope
Definition: nad.c:762
const char * code
Definition: util.h:398
#define NAD_ENAME(N, E)
Definition: nad.h:183
mio_action_t
these are the actions and a handler type assigned by the applicaiton using mio
Definition: mio.h:106
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
void nad_free(nad_t nad)
free that nad
Definition: nad.c:178
Definition: sx.h:60
#define mio_read(m, fd)
process read events for this fd
Definition: mio.h:161
int local_port
Definition: s2s.h:120
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
#define MIO_WOULDBLOCK
Definition: mio.h:171
int sx_can_read(sx_t s)
we can read
Definition: io.c:196
#define SX_ERR_AUTH
Definition: sx.h:95
holds the state for a single stream
Definition: sx.h:253
char * data
Definition: sx.h:114
jid_t from
packet addressing (not used for routing)
Definition: sm.h:140
int online
true if we're bound in the router
Definition: s2s.h:201
packet summary data wrapper
Definition: sm.h:129
#define uri_DIALBACK_L
Definition: uri.h:38
#define NAD_ENAME_L(N, E)
Definition: nad.h:184
#define NAD_NURI_L(N, NS)
Definition: nad.h:192
nad_t nad
nad of the entire packet
Definition: sm.h:146
sx_plugin_t sx_ssl
Definition: s2s.h:86
#define stanza_err_BAD_REQUEST
Definition: util.h:367
#define mio_listen(m, port, sourceip, app, arg)
for creating a new listen socket in this mio (returns new fd or <0)
Definition: mio.h:140
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
int in_mio_callback(mio_t m, mio_action_t a, mio_fd_t fd, void *data, void *arg)
Definition: in.c:63
struct pkt_st * pkt_t
packet summary data wrapper
#define stanza_err_REMOTE_SERVER_NOT_FOUND
Definition: util.h:381
#define NAD_AVAL_L(N, A)
Definition: nad.h:190
int router_default
Definition: s2s.h:79
void sx_close(sx_t s)
Definition: io.c:498
#define log_debug(...)
Definition: log.h:65
const char * router_pemfile
Definition: s2s.h:75
#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 NAD_AVAL(N, A)
Definition: nad.h:189
struct _sx_buf_st * sx_buf_t
utility: buffer
Definition: sx.h:112
mio_fd_t server_fd
listening sockets
Definition: s2s.h:95
int retry_lost
Definition: s2s.h:114
JABBERD2_API int sx_sasl_auth(sx_plugin_t p, sx_t s, const char *appname, const char *mech, const char *user, const char *pass)
trigger for client auth
Definition: sasl.c:908
int ssf
Definition: sx.h:340
const char * specific
Definition: sx.h:102
int fd
Definition: mio.h:102
unsigned int len
Definition: sx.h:115
sig_atomic_t s2s_lost_router
Definition: main.c:30
struct s2s_st * s2s_t
Definition: s2s.h:39
const char * router_private_key_password
Definition: s2s.h:77
jid_t to
Definition: sm.h:140
const char * id
our id (hostname) with the router
Definition: s2s.h:68
mio_t mio
mio context
Definition: s2s.h:82
Definition: mio.h:100
void sx_kill(sx_t s)
Definition: io.c:513
const char * router_user
Definition: s2s.h:73
#define uri_COMPONENT
Definition: uri.h:52
#define mio_close(m, fd)
request that mio close this fd
Definition: mio.h:155
#define mio_write(m, fd)
mio should try the write action on this fd now
Definition: mio.h:158
#define ZONE
Definition: mio_impl.h:76
#define NAD_NURI(N, NS)
Definition: nad.h:191
sx_event_t
things that can happen
Definition: sx.h:56
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
Definition: sx.h:74
#define uri_DIALBACK
Definition: uri.h:37
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
int sx_ssl_client_starttls(sx_plugin_t p, sx_t s, const char *pemfile, const char *private_key_password)
Definition: ssl.c:1116
sx_plugin_t sx_sasl
Definition: s2s.h:87
#define NAD_ENS(N, E)
Definition: nad.h:196
int retry_left
Definition: s2s.h:116
int nad_find_scoped_namespace(nad_t nad, const char *uri, const char *prefix)
find a namespace in scope
Definition: nad.c:290