]> jfr.im git - solanum.git/blob - src/listener.c
Trying again - this will need ssld integration from me
[solanum.git] / src / listener.c
1 /*
2 * ircd-ratbox: A slightly useful ircd.
3 * listener.c: Listens on a port.
4 *
5 * Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
6 * Copyright (C) 1996-2002 Hybrid Development Team
7 * Copyright (C) 2002-2005 ircd-ratbox development team
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
22 * USA
23 *
24 * $Id: listener.c 25169 2008-03-29 21:41:31Z jilles $
25 */
26
27 #include "stdinc.h"
28 #include "struct.h"
29 #include "ratbox_lib.h"
30 #include "listener.h"
31 #include "client.h"
32 #include "match.h"
33 #include "ircd.h"
34 #include "numeric.h"
35 #include "s_conf.h"
36 #include "s_newconf.h"
37 #include "s_stats.h"
38 #include "send.h"
39 #include "s_auth.h"
40 #include "reject.h"
41 #include "s_log.h"
42 #include "sslproc.h"
43 #include "hash.h"
44
45 static rb_dlink_list listener_list;
46 static int accept_precallback(rb_fde_t *F, struct sockaddr *addr, rb_socklen_t addrlen, void *data);
47 static void accept_callback(rb_fde_t *F, int status, struct sockaddr *addr, rb_socklen_t addrlen, void *data);
48
49
50
51 static struct Listener *
52 make_listener(struct rb_sockaddr_storage *addr)
53 {
54 struct Listener *listener = rb_malloc(sizeof(struct Listener));
55 s_assert(0 != listener);
56 listener->name = ServerInfo.name; /* me.name may not be valid yet -- jilles */
57 listener->F = NULL;
58 memcpy(&listener->addr, addr, sizeof(struct rb_sockaddr_storage));
59 return listener;
60 }
61
62 void
63 free_listener(struct Listener *listener)
64 {
65 s_assert(NULL != listener);
66 if(listener == NULL)
67 return;
68
69 rb_dlinkDelete(&listener->node, &listener_list);
70 rb_free(listener);
71 }
72
73 #define PORTNAMELEN 6 /* ":31337" */
74
75 /*
76 * get_listener_name - return displayable listener name and port
77 * returns "host.foo.org:6667" for a given listener
78 */
79 const char *
80 get_listener_name(struct Listener *listener)
81 {
82 static char buf[HOSTLEN + HOSTLEN + PORTNAMELEN + 4];
83 int port = 0;
84
85 s_assert(NULL != listener);
86 if(listener == NULL)
87 return NULL;
88
89 #ifdef IPV6
90 if(GET_SS_FAMILY(&listener->addr) == AF_INET6)
91 port = ntohs(((const struct sockaddr_in6 *)&listener->addr)->sin6_port);
92 else
93 #endif
94 port = ntohs(((const struct sockaddr_in *)&listener->addr)->sin_port);
95
96 rb_snprintf(buf, sizeof(buf), "%s[%s/%u]", me.name, listener->name, port);
97 return buf;
98 }
99
100 /*
101 * show_ports - send port listing to a client
102 * inputs - pointer to client to show ports to
103 * output - none
104 * side effects - show ports
105 */
106 void
107 show_ports(struct Client *source_p)
108 {
109 struct Listener *listener;
110 rb_dlink_node *ptr;
111
112 RB_DLINK_FOREACH(ptr, listener_list.head)
113 {
114 listener = ptr->data;
115 sendto_one_numeric(source_p, RPL_STATSPLINE,
116 form_str(RPL_STATSPLINE), 'P',
117 #ifdef IPV6
118 ntohs(GET_SS_FAMILY(&listener->addr) == AF_INET ? ((struct sockaddr_in *)&listener->addr)->sin_port :
119 ((struct sockaddr_in6 *)&listener->addr)->sin6_port),
120 #else
121 ntohs(((struct sockaddr_in *)&listener->addr)->sin_port),
122 #endif
123 IsOperAdmin(source_p) ? listener->name : me.name,
124 listener->ref_count, (listener->active) ? "active" : "disabled",
125 listener->ssl ? " ssl" : "");
126 }
127 }
128
129 /*
130 * inetport - create a listener socket in the AF_INET or AF_INET6 domain,
131 * bind it to the port given in 'port' and listen to it
132 * returns true (1) if successful false (0) on error.
133 *
134 * If the operating system has a define for SOMAXCONN, use it, otherwise
135 * use RATBOX_SOMAXCONN
136 */
137 #ifdef SOMAXCONN
138 #undef RATBOX_SOMAXCONN
139 #define RATBOX_SOMAXCONN SOMAXCONN
140 #endif
141
142 static int
143 inetport(struct Listener *listener)
144 {
145 rb_fde_t *F;
146 int ret;
147 int opt = 1;
148
149 /*
150 * At first, open a new socket
151 */
152
153 F = rb_socket(GET_SS_FAMILY(&listener->addr), SOCK_STREAM, 0, "Listener socket");
154
155 #ifdef IPV6
156 if(GET_SS_FAMILY(&listener->addr) == AF_INET6)
157 {
158 struct sockaddr_in6 *in6 = (struct sockaddr_in6 *)&listener->addr;
159 if(!IN6_ARE_ADDR_EQUAL(&in6->sin6_addr, &in6addr_any))
160 {
161 rb_inet_ntop(AF_INET6, &in6->sin6_addr, listener->vhost, sizeof(listener->vhost));
162 listener->name = listener->vhost;
163 }
164 } else
165 #endif
166 {
167 struct sockaddr_in *in = (struct sockaddr_in *)&listener->addr;
168 if(in->sin_addr.s_addr != INADDR_ANY)
169 {
170 rb_inet_ntop(AF_INET, &in->sin_addr, listener->vhost, sizeof(listener->vhost));
171 listener->name = listener->vhost;
172 }
173 }
174
175
176 if(F == NULL)
177 {
178 report_error("opening listener socket %s:%s",
179 get_listener_name(listener),
180 get_listener_name(listener), errno);
181 return 0;
182 }
183 else if((maxconnections - 10) < rb_get_fd(F)) /* XXX this is kinda bogus*/
184 {
185 report_error("no more connections left for listener %s:%s",
186 get_listener_name(listener),
187 get_listener_name(listener), errno);
188 rb_close(F);
189 return 0;
190 }
191 /*
192 * XXX - we don't want to do all this crap for a listener
193 * set_sock_opts(listener);
194 */
195 if(setsockopt(rb_get_fd(F), SOL_SOCKET, SO_REUSEADDR, (char *) &opt, sizeof(opt)))
196 {
197 report_error("setting SO_REUSEADDR for listener %s:%s",
198 get_listener_name(listener),
199 get_listener_name(listener), errno);
200 rb_close(F);
201 return 0;
202 }
203
204 /*
205 * Bind a port to listen for new connections if port is non-null,
206 * else assume it is already open and try get something from it.
207 */
208
209 if(bind(rb_get_fd(F), (struct sockaddr *) &listener->addr, GET_SS_LEN(&listener->addr)))
210 {
211 report_error("binding listener socket %s:%s",
212 get_listener_name(listener),
213 get_listener_name(listener), errno);
214 rb_close(F);
215 return 0;
216 }
217
218 if((ret = rb_listen(F, RATBOX_SOMAXCONN)))
219 {
220 report_error("listen failed for %s:%s",
221 get_listener_name(listener),
222 get_listener_name(listener), errno);
223 rb_close(F);
224 return 0;
225 }
226
227 listener->F = F;
228
229 rb_accept_tcp(listener->F, accept_precallback, accept_callback, listener);
230 return 1;
231 }
232
233 static struct Listener *
234 find_listener(struct rb_sockaddr_storage *addr)
235 {
236 struct Listener *listener = NULL;
237 struct Listener *last_closed = NULL;
238 rb_dlink_node *ptr;
239
240 RB_DLINK_FOREACH(ptr, listener_list.head)
241 {
242 listener = ptr->data;
243 if(GET_SS_FAMILY(addr) != GET_SS_FAMILY(&listener->addr))
244 continue;
245
246 switch(GET_SS_FAMILY(addr))
247 {
248 case AF_INET:
249 {
250 struct sockaddr_in *in4 = (struct sockaddr_in *)addr;
251 struct sockaddr_in *lin4 = (struct sockaddr_in *)&listener->addr;
252 if(in4->sin_addr.s_addr == lin4->sin_addr.s_addr &&
253 in4->sin_port == lin4->sin_port )
254 {
255 if(listener->F == NULL)
256 last_closed = listener;
257 else
258 return(listener);
259 }
260 break;
261 }
262 #ifdef IPV6
263 case AF_INET6:
264 {
265 struct sockaddr_in6 *in6 = (struct sockaddr_in6 *)addr;
266 struct sockaddr_in6 *lin6 =(struct sockaddr_in6 *)&listener->addr;
267 if(IN6_ARE_ADDR_EQUAL(&in6->sin6_addr, &lin6->sin6_addr) &&
268 in6->sin6_port == lin6->sin6_port)
269 {
270 if(listener->F == NULL)
271 last_closed = listener;
272 else
273 return(listener);
274 }
275 break;
276
277 }
278 #endif
279
280 default:
281 break;
282 }
283 }
284 return last_closed;
285 }
286
287 /*
288 * add_listener- create a new listener
289 * port - the port number to listen on
290 * vhost_ip - if non-null must contain a valid IP address string in
291 * the format "255.255.255.255"
292 */
293 void
294 add_listener(int port, const char *vhost_ip, int family, int ssl)
295 {
296 struct Listener *listener;
297 struct rb_sockaddr_storage vaddr;
298
299 /*
300 * if no port in conf line, don't bother
301 */
302 if(port == 0)
303 return;
304
305 memset(&vaddr, 0, sizeof(vaddr));
306 GET_SS_FAMILY(&vaddr) = family;
307
308 if(vhost_ip != NULL)
309 {
310 if(rb_inet_pton_sock(vhost_ip, (struct sockaddr *)&vaddr) <= 0)
311 return;
312 } else
313 {
314 switch(family)
315 {
316 case AF_INET:
317 ((struct sockaddr_in *)&vaddr)->sin_addr.s_addr = INADDR_ANY;
318 break;
319 #ifdef IPV6
320 case AF_INET6:
321 memcpy(&((struct sockaddr_in6 *)&vaddr)->sin6_addr, &in6addr_any, sizeof(struct in6_addr));
322 break;
323 #endif
324 default:
325 return;
326 }
327 }
328 switch(family)
329 {
330 case AF_INET:
331 SET_SS_LEN(&vaddr, sizeof(struct sockaddr_in));
332 ((struct sockaddr_in *)&vaddr)->sin_port = htons(port);
333 break;
334 #ifdef IPV6
335 case AF_INET6:
336 SET_SS_LEN(&vaddr, sizeof(struct sockaddr_in6));
337 ((struct sockaddr_in6 *)&vaddr)->sin6_port = htons(port);
338 break;
339 #endif
340 default:
341 break;
342 }
343 if((listener = find_listener(&vaddr)))
344 {
345 if(listener->F != NULL)
346 return;
347 }
348 else
349 {
350 listener = make_listener(&vaddr);
351 rb_dlinkAdd(listener, &listener->node, &listener_list);
352 }
353
354 listener->F = NULL;
355 listener->ssl = ssl;
356 if(inetport(listener))
357 listener->active = 1;
358 else
359 close_listener(listener);
360 }
361
362 /*
363 * close_listener - close a single listener
364 */
365 void
366 close_listener(struct Listener *listener)
367 {
368 s_assert(listener != NULL);
369 if(listener == NULL)
370 return;
371 if(listener->F != NULL)
372 {
373 rb_close(listener->F);
374 listener->F = NULL;
375 }
376
377 listener->active = 0;
378
379 if(listener->ref_count)
380 return;
381
382 free_listener(listener);
383 }
384
385 /*
386 * close_listeners - close and free all listeners that are not being used
387 */
388 void
389 close_listeners()
390 {
391 struct Listener *listener;
392 rb_dlink_node *ptr, *next;
393
394 RB_DLINK_FOREACH_SAFE(ptr, next, listener_list.head)
395 {
396 listener = ptr->data;
397 close_listener(listener);
398 }
399 }
400
401 /*
402 * add_connection - creates a client which has just connected to us on
403 * the given fd. The sockhost field is initialized with the ip# of the host.
404 * The client is sent to the auth module for verification, and not put in
405 * any client list yet.
406 */
407 static void
408 add_connection(struct Listener *listener, rb_fde_t *F, struct sockaddr *sai, struct sockaddr *lai, void *ssl_ctl)
409 {
410 struct Client *new_client;
411 s_assert(NULL != listener);
412 /*
413 * get the client socket name from the socket
414 * the client has already been checked out in accept_connection
415 */
416 new_client = make_client(NULL);
417
418 memcpy(&new_client->localClient->ip, sai, sizeof(struct rb_sockaddr_storage));
419 new_client->localClient->lip = rb_malloc(sizeof(struct rb_sockaddr_storage));
420 memcpy(new_client->localClient->lip, lai, sizeof(struct rb_sockaddr_storage));
421
422 /*
423 * copy address to 'sockhost' as a string, copy it to host too
424 * so we have something valid to put into error messages...
425 */
426 rb_inet_ntop_sock((struct sockaddr *)&new_client->localClient->ip, new_client->sockhost,
427 sizeof(new_client->sockhost));
428
429
430 rb_strlcpy(new_client->host, new_client->sockhost, sizeof(new_client->host));
431
432 #ifdef IPV6
433 if(GET_SS_FAMILY(&new_client->localClient->ip) == AF_INET6 && ConfigFileEntry.dot_in_ip6_addr == 1)
434 {
435 rb_strlcat(new_client->host, ".", sizeof(new_client->host));
436 }
437 #endif
438
439 new_client->localClient->F = F;
440 add_to_cli_fd_hash(new_client);
441 new_client->localClient->listener = listener;
442 new_client->localClient->ssl_ctl = ssl_ctl;
443 if(ssl_ctl != NULL || rb_fd_ssl(F))
444 SetSSL(new_client);
445
446 ++listener->ref_count;
447
448 start_auth(new_client);
449 }
450
451 static time_t last_oper_notice = 0;
452
453 static const char *toofast = "ERROR :Reconnecting too fast, throttled.\r\n";
454
455 static int
456 accept_precallback(rb_fde_t *F, struct sockaddr *addr, rb_socklen_t addrlen, void *data)
457 {
458 struct Listener *listener = (struct Listener *)data;
459 char buf[BUFSIZE];
460 struct ConfItem *aconf;
461
462 if(listener->ssl && (!ssl_ok || !get_ssld_count()))
463 {
464 fprintf(stderr, "closed socket\n");
465 rb_close(F);
466 return 0;
467 }
468
469 if((maxconnections - 10) < rb_get_fd(F)) /* XXX this is kinda bogus */
470 {
471 ++ServerStats.is_ref;
472 /*
473 * slow down the whining to opers bit
474 */
475 if((last_oper_notice + 20) <= rb_current_time())
476 {
477 sendto_realops_flags(UMODE_ALL, L_ALL,
478 "All connections in use. (%s)",
479 get_listener_name(listener));
480 last_oper_notice = rb_current_time();
481 }
482
483 rb_write(F, "ERROR :All connections in use\r\n", 32);
484 rb_close(F);
485 /* Re-register a new IO request for the next accept .. */
486 return 0;
487 }
488
489 aconf = find_dline(addr);
490 if(aconf != NULL && (aconf->status & CONF_EXEMPTDLINE))
491 return 1;
492
493 /* Do an initial check we aren't connecting too fast or with too many
494 * from this IP... */
495 if(aconf != NULL)
496 {
497 ServerStats.is_ref++;
498
499 if(ConfigFileEntry.dline_with_reason)
500 {
501 if (rb_snprintf(buf, sizeof(buf), "ERROR :*** Banned: %s\r\n", aconf->passwd) >= (int)(sizeof(buf)-1))
502 {
503 buf[sizeof(buf) - 3] = '\r';
504 buf[sizeof(buf) - 2] = '\n';
505 buf[sizeof(buf) - 1] = '\0';
506 }
507 }
508 else
509 strcpy(buf, "ERROR :You have been D-lined.\r\n");
510
511 rb_write(F, buf, strlen(buf));
512 rb_close(F);
513 return 0;
514 }
515
516 if(check_reject(F, addr))
517 return 0;
518
519 if(throttle_add(addr))
520 {
521 rb_write(F, toofast, strlen(toofast));
522 rb_close(F);
523 return 0;
524 }
525
526 return 1;
527 }
528
529 static void
530 accept_ssld(rb_fde_t *F, struct sockaddr *addr, struct sockaddr *laddr, struct Listener *listener)
531 {
532 ssl_ctl_t *ctl;
533 rb_fde_t *xF[2];
534 rb_socketpair(AF_UNIX, SOCK_STREAM, 0, &xF[0], &xF[1], "Incoming ssld Connection");
535 ctl = start_ssld_accept(F, xF[1], rb_get_fd(xF[0])); /* this will close F for us */
536 add_connection(listener, xF[0], addr, laddr, ctl);
537 }
538
539 static void
540 accept_callback(rb_fde_t *F, int status, struct sockaddr *addr, rb_socklen_t addrlen, void *data)
541 {
542 struct Listener *listener = data;
543 struct rb_sockaddr_storage lip;
544 unsigned int locallen = sizeof(struct rb_sockaddr_storage);
545
546 ServerStats.is_ac++;
547 if(getsockname(rb_get_fd(F), (struct sockaddr *) &lip, &locallen) < 0)
548 {
549 /* this shouldn't fail so... */
550 /* XXX add logging of this */
551 rb_close(F);
552 }
553 if(listener->ssl)
554 accept_ssld(F, addr, (struct sockaddr *)&lip, listener);
555 else
556 add_connection(listener, F, addr, (struct sockaddr *)&lip, NULL);
557 }