Author: Bleep <tomh@inxpress.net>
[ircu2.10.12-pk.git] / ircd / listener.c
1 /************************************************************************
2  *   IRC - Internet Relay Chat, src/listener.c
3  *   Copyright (C) 1999 Thomas Helvey <tomh@inxpress.net>
4  *
5  *   This program is free software; you can redistribute it and/or modify
6  *   it under the terms of the GNU General Public License as published by
7  *   the Free Software Foundation; either version 1, or (at your option)
8  *   any later version.
9  *
10  *   This program is distributed in the hope that it will be useful,
11  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *   GNU General Public License for more details.
14  *
15  *   You should have received a copy of the GNU General Public License
16  *   along with this program; if not, write to the Free Software
17  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18  *
19  *  $Id$
20  */
21 #include "listener.h"
22 #include "client.h"
23 #include "ircd.h"
24 #include "ircd_alloc.h"
25 #include "ircd_osdep.h"
26 #include "ircd_string.h"
27 #include "numeric.h"
28 #include "s_bsd.h"
29 #include "s_conf.h"
30 #include "s_misc.h"
31 #include "send.h"
32 #include "sprintf_irc.h"
33 #include "sys.h"         /* MAXCLIENTS */
34
35 #include <assert.h>
36 #include <stdio.h>
37 #include <string.h>
38 #include <errno.h>
39 #include <stdlib.h>
40 #include <unistd.h>
41 #include <netdb.h>
42 #include <sys/socket.h>
43 #include <arpa/inet.h>
44
45 #ifndef INADDR_NONE
46 #define INADDR_NONE ((unsigned int) 0xffffffff)
47 #endif
48
49 struct Listener* ListenerPollList = 0;
50
51 static struct Listener* make_listener(int port, struct in_addr addr)
52 {
53   struct Listener* listener = 
54     (struct Listener*) MyMalloc(sizeof(struct Listener));
55   assert(0 != listener);
56
57   memset(listener, 0, sizeof(struct Listener));
58
59   listener->fd          = -1;
60   listener->port        = port;
61   listener->addr.s_addr = addr.s_addr;
62
63 #ifdef NULL_POINTER_NOT_ZERO
64   listener->next = NULL;
65   listener->conf = NULL;
66 #endif
67   return listener;
68 }
69
70 static void free_listener(struct Listener* listener)
71 {
72   assert(0 != listener);
73   MyFree(listener);
74 }
75
76 #define PORTNAMELEN 10  /* ":31337" */
77
78 /*
79  * get_listener_name - return displayable listener name and port
80  * returns "host.foo.org:6667" for a given listener
81  */
82 const char* get_listener_name(const struct Listener* listener)
83 {
84   static char buf[HOSTLEN + PORTNAMELEN + 4];
85   assert(0 != listener);
86   sprintf_irc(buf, "%s:%u", me.name, listener->port);
87   return buf;
88 }
89
90 /*
91  * count_listener_memory - count memory and listeners
92  */
93 void count_listener_memory(int* count_out, size_t* size_out)
94 {
95   struct Listener* l;
96   int              count = 0;
97   assert(0 != count_out);
98   assert(0 != size_out);
99   for (l = ListenerPollList; l; l = l->next)
100     ++count;
101   *count_out = count;
102   *size_out  = count * sizeof(struct Listener);
103 }
104   
105 /*
106  * show_ports - send port listing to a client
107  * inputs       - pointer to client to show ports to
108  * output       - none
109  * side effects - show ports
110  * author       - Dianora
111  */
112 void show_ports(struct Client* sptr, int show_hidden, int port, int count)
113 {
114   struct Listener* listener = 0;
115   char             flags[8];
116   assert(0 != sptr);
117
118   for (listener = ListenerPollList; listener; listener = listener->next) {
119     if (port && port != listener->port)
120       continue;
121     flags[0] = (listener->server) ? 'S' : 'C';
122     if (listener->hidden) {
123       if (!show_hidden)
124         continue;
125       flags[1] = 'H';
126       flags[2] = '\0';
127     }
128     else
129       flags[1] = '\0';
130         
131     sendto_one(sptr, rpl_str(RPL_STATSPLINE),
132                me.name, sptr->name, listener->port,
133                listener->ref_count, flags, 
134                (listener->active) ? "active" : "disabled");
135     if (--count == 0)
136       break;
137   }
138 }
139
140 /*
141  * inetport - create a listener socket in the AF_INET domain, 
142  * bind it to the port given in 'port' and listen to it  
143  * returns true (1) if successful false (0) on error.
144  *
145  * If the operating system has a define for SOMAXCONN, use it, otherwise
146  * use HYBRID_SOMAXCONN -Dianora
147  * NOTE: Do this in os_xxxx.c files
148  */
149 #ifdef SOMAXCONN
150 #define HYBRID_SOMAXCONN SOMAXCONN
151 #else
152 #define HYBRID_SOMAXCONN 64
153 #endif
154
155 static int inetport(struct Listener* listener)
156 {
157   struct sockaddr_in sin;
158   int                fd;
159
160   /*
161    * At first, open a new socket
162    */
163   if (-1 == (fd = socket(AF_INET, SOCK_STREAM, 0))) {
164     report_error(SOCKET_ERROR_MSG, get_listener_name(listener), errno);
165     return 0;
166   }
167   else if (fd > MAXCLIENTS - 1) {
168     report_error(CONNLIMIT_ERROR_MSG, get_listener_name(listener), 0);
169     close(fd);
170     return 0;
171   }
172
173   if (!os_set_reuseaddr(fd)) {
174     report_error(REUSEADDR_ERROR_MSG, get_listener_name(listener), errno);
175     close(fd);
176     return 0;
177   }
178   /*
179    * Bind a port to listen for new connections if port is non-null,
180    * else assume it is already open and try get something from it.
181    */
182   memset(&sin, 0, sizeof(sin));
183   sin.sin_family = AF_INET;
184   sin.sin_addr   = listener->addr;
185   sin.sin_port   = htons(listener->port);
186
187   if (bind(fd, (struct sockaddr*) &sin, sizeof(sin))) {
188     report_error(BIND_ERROR_MSG, get_listener_name(listener), errno);
189     close(fd);
190     return 0;
191   }
192   /*
193    * Set the buffer sizes for the listener. Accepted connections
194    * inherit the accepting sockets settings for SO_RCVBUF S_SNDBUF
195    * The window size is set during the SYN ACK so setting it anywhere
196    * else has no effect whatsoever on the connection.
197    * NOTE: this must be set before listen is called
198    */
199   if (!os_set_sockbufs(fd, (listener->server) ? SERVER_TCP_WINDOW : CLIENT_TCP_WINDOW)) {
200     report_error(SETBUFS_ERROR_MSG, get_listener_name(listener), errno);
201     close(fd);
202     return 0;
203   }
204   if (!os_set_listen(fd, HYBRID_SOMAXCONN)) {
205     report_error(LISTEN_ERROR_MSG, get_listener_name(listener), errno);
206     close(fd);
207     return 0;
208   }
209   /*
210    * XXX - this should always work, performance will suck if it doesn't
211    */
212   if (!os_set_nonblocking(fd)) {
213     report_error(NONB_ERROR_MSG, get_listener_name(listener), errno);
214     close(fd);
215     return 0;
216   }
217   listener->fd = fd;
218
219   return 1;
220 }
221
222 /*
223  * find_listener - find a listener in the list
224  *
225  * XXX - this function does N comparisons so if the list is huge
226  * we may want to do something else for this. (rehash and init use this)
227  */
228 static struct Listener* find_listener(int port, struct in_addr addr)
229 {
230   struct Listener* listener;
231   for (listener = ListenerPollList; listener; listener = listener->next) {
232     if (port == listener->port && addr.s_addr == listener->addr.s_addr)
233       return listener;
234   }
235   return 0;
236 }
237
238 /*
239  * set_listener_mask - set the connection mask for this listener
240  */
241 static void set_listener_mask(struct Listener* listener, const char* mask)
242 {
243   int  ad[4];
244   char ipname[20];
245
246   assert(0 != listener);
247
248   if (EmptyString(mask) && strcmp(mask,"*")!=0) {
249     listener->mask.s_addr = 0;
250     return;
251   }
252   ad[0] = ad[1] = ad[2] = ad[3] = 0;
253   /*
254    * do it this way because building ip# from separate values for each
255    * byte requires endian knowledge or some nasty messing. Also means
256    * easy conversion of "*" 0.0.0.0 or 134.* to 134.0.0.0 :-)
257    */
258   sscanf(mask, "%d.%d.%d.%d", &ad[0], &ad[1], &ad[2], &ad[3]);
259   sprintf_irc(ipname, "%d.%d.%d.%d", ad[0], ad[1], ad[2], ad[3]);
260   listener->mask.s_addr = inet_addr(ipname);
261 }
262
263 /*
264  * connection_allowed - spin through mask and addr passed to see if connect 
265  * allowed on a listener, uses mask generated by set_listener_mask
266  */
267 static int connection_allowed(const char* addr, const char* mask)
268 {
269   int i = 4;
270   for ( ; i > 0; --i) {
271     if (*mask && *addr != *mask)
272       break;
273     ++addr;
274     ++mask;
275   }
276   return (0 == i);
277 }
278
279
280 /*
281  * add_listener- create a new listener 
282  * port - the port number to listen on
283  * vhost_ip - if non-null must contain a valid IP address string in
284  * the format "255.255.255.255"
285  */
286 void add_listener(int port, const char* vhost_ip, const char* mask,
287                   int is_server, int is_hidden) 
288 {
289   struct Listener* listener;
290   struct in_addr   vaddr;
291
292   /*
293    * if no port in conf line, don't bother
294    */
295   if (0 == port)
296     return;
297
298   vaddr.s_addr = INADDR_ANY;
299
300   if (!EmptyString(vhost_ip) && strcmp(vhost_ip,"*") != 0) {
301     vaddr.s_addr = inet_addr(vhost_ip);
302     if (INADDR_NONE == vaddr.s_addr)
303       return;
304   }
305
306   if ((listener = find_listener(port, vaddr))) {
307     /*
308      * set active flag and change connect mask here, it's the only thing 
309      * that can change on a rehash
310      */
311     listener->active = 1;
312     set_listener_mask(listener, mask);
313     listener->hidden = is_hidden;
314     listener->server = is_server;
315     return;
316   }
317
318   listener = make_listener(port, vaddr);
319
320   if (inetport(listener)) {
321     listener->active = 1;
322     set_listener_mask(listener, mask);
323     listener->hidden = is_hidden;
324     listener->server = is_server;
325     listener->next   = ListenerPollList;
326     ListenerPollList = listener; 
327   }
328   else
329     free_listener(listener);
330 }
331
332 /*
333  * mark_listeners_closing - iterate through listeners and mark them as
334  * inactive
335  */
336 void mark_listeners_closing(void)
337 {
338   struct Listener* listener;
339   for (listener = ListenerPollList; listener; listener = listener->next)
340     listener->active = 0;
341 }
342
343 /*
344  * close_listener - close a single listener
345  */
346 void close_listener(struct Listener* listener)
347 {
348   assert(0 != listener);
349   /*
350    * remove from listener list
351    */
352   if (listener == ListenerPollList)
353     ListenerPollList = listener->next;
354   else {
355     struct Listener* prev = ListenerPollList;
356     for ( ; prev; prev = prev->next) {
357       if (listener == prev->next) {
358         prev->next = listener->next;
359         break; 
360       }
361     }
362   }
363   if (-1 < listener->fd)
364     close(listener->fd);
365   free_listener(listener);
366 }
367  
368 /*
369  * close_listeners - close and free all listeners that are not being used
370  */
371 void close_listeners()
372 {
373   struct Listener* listener;
374   struct Listener* listener_next = 0;
375   /*
376    * close all 'extra' listening ports we have
377    */
378   for (listener = ListenerPollList; listener; listener = listener_next) {
379     listener_next = listener->next;
380     if (0 == listener->active && 0 == listener->ref_count)
381       close_listener(listener);
382   }
383 }
384
385 void release_listener(struct Listener* listener)
386 {
387   assert(0 != listener);
388   assert(0 < listener->ref_count);
389   if (0 == --listener->ref_count && !listener->active)
390     close_listener(listener);
391 }
392
393 /*
394  * accept_connection - accept a connection on a listener
395  */
396 void accept_connection(struct Listener* listener)
397 {
398   struct sockaddr_in addr;
399   size_t             addrlen = sizeof(struct sockaddr_in);
400   int                fd;
401
402   assert(0 != listener);
403
404   listener->last_accept = CurrentTime;
405   /*
406    * There may be many reasons for error return, but
407    * in otherwise correctly working environment the
408    * probable cause is running out of file descriptors
409    * (EMFILE, ENFILE or others?). The man pages for
410    * accept don't seem to list these as possible,
411    * although it's obvious that it may happen here.
412    * Thus no specific errors are tested at this
413    * point, just assume that connections cannot
414    * be accepted until some old is closed first.
415    */
416   if (-1 == (fd = accept(listener->fd, (struct sockaddr*) &addr, &addrlen)))
417     return;
418   /*
419    * check for connection limit
420    */
421   if (fd > MAXCLIENTS - 1) {
422     ++ServerStats->is_ref;
423     send(fd, "ERROR :All connections in use\r\n", 32, 0);
424     close(fd);
425     return;
426   }
427   /*
428    * check to see if listener is shutting down
429    */
430   if (!listener->active) {
431     ++ServerStats->is_ref;
432     send(fd, "ERROR :Use another port\r\n", 25, 0);
433     close(fd);
434     return;
435   }
436   /*
437    * check to see if connection is allowed for this address mask
438    */
439   if (!connection_allowed((const char*) &addr, (const char*) &listener->mask)) {
440     ++ServerStats->is_ref;
441     send(fd, "ERROR :Use another port\r\n", 25, 0);
442     close(fd);
443     return;
444   }
445 #if 0
446   /*
447    * check conf for ip address access
448    */
449   if (!conf_connect_allowed(addr.sin_addr)) {
450     ++ServerStats->is_ref;
451     send(fd, "ERROR :Not authorized\r\n", 23, 0);
452     close(fd);
453     return;
454   }
455 #endif
456   ++ServerStats->is_ac;
457   nextping = CurrentTime;
458
459   add_connection(listener, fd);
460 }
461
462