ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/branches/8.2.x/src/listener.c
Revision: 8280
Committed: Tue Feb 20 19:30:33 2018 UTC (6 years, 1 month ago) by michael
Content type: text/x-csrc
File size: 10242 byte(s)
Log Message:
- Update copyright years

File Contents

# User Rev Content
1 adx 30 /*
2 michael 2916 * ircd-hybrid: an advanced, lightweight Internet Relay Chat Daemon (ircd)
3 adx 30 *
4 michael 8280 * Copyright (c) 1999-2018 ircd-hybrid development team
5 adx 30 *
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 michael 4564 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
19 adx 30 * USA
20     */
21    
22 michael 2916 /*! \file listener.c
23     * \brief Implementation for handling listening sockets.
24     * \version $Id$
25     */
26    
27 adx 30 #include "stdinc.h"
28 michael 1011 #include "list.h"
29 adx 30 #include "listener.h"
30     #include "client.h"
31     #include "fdlist.h"
32     #include "irc_string.h"
33     #include "ircd.h"
34     #include "ircd_defs.h"
35     #include "s_bsd.h"
36 michael 1309 #include "conf.h"
37 adx 30 #include "send.h"
38     #include "memory.h"
39    
40 michael 4520 #define TOOFAST_WARNING "ERROR :Your host is trying to (re)connect too fast -- throttled.\r\n"
41     #define DLINE_WARNING "ERROR :You have been D-lined.\r\n"
42 michael 4839 #define ALLINUSE_WARNING "ERROR :All connections in use\r\n"
43 michael 4520
44 michael 4519 static dlink_list listener_list;
45 adx 30
46 michael 6365 const dlink_list *
47     listener_get_list(void)
48     {
49     return &listener_list;
50     }
51    
52 adx 30 static struct Listener *
53 michael 6368 listener_make(const int port, const struct irc_ssaddr *addr)
54 adx 30 {
55 michael 7033 struct Listener *listener = xcalloc(sizeof(struct Listener));
56 adx 30
57     listener->port = port;
58     memcpy(&listener->addr, addr, sizeof(struct irc_ssaddr));
59    
60     return listener;
61     }
62    
63 michael 6368 static void
64     listener_free(struct Listener *listener)
65 adx 30 {
66 michael 4519 dlinkDelete(&listener->node, &listener_list);
67 michael 7033 xfree(listener);
68 adx 30 }
69    
70     /*
71 michael 6368 * listener_get_name - return displayable listener name and port
72 michael 1242 * returns "host.foo.org/6667" for a given listener
73 adx 30 */
74     const char *
75 michael 7346 listener_get_name(const struct Listener *listener)
76 adx 30 {
77 michael 4374 static char buf[HOSTLEN + HOSTIPLEN + PORTNAMELEN + 4]; /* +4 for [,/,],\0 */
78 adx 30
79 michael 1123 snprintf(buf, sizeof(buf), "%s[%s/%u]", me.name,
80     listener->name, listener->port);
81 michael 900 return buf;
82 adx 30 }
83    
84 michael 7350 void
85     listener_count_memory(unsigned int *count, size_t *bytes)
86     {
87     (*count) = dlink_list_length(&listener_list);
88     (*bytes) = *count * sizeof(struct Listener);
89     }
90    
91 michael 4520 static void
92     listener_accept_connection(fde_t *pfd, void *data)
93     {
94 michael 7329 static uintmax_t rate = 0;
95 michael 4520 struct irc_ssaddr addr;
96     int fd;
97     int pe;
98 michael 4936 struct Listener *const listener = data;
99 michael 4520
100     assert(listener);
101    
102     /* There may be many reasons for error return, but
103     * in otherwise correctly working environment the
104     * probable cause is running out of file descriptors
105     * (EMFILE, ENFILE or others?). The man pages for
106     * accept don't seem to list these as possible,
107     * although it's obvious that it may happen here.
108     * Thus no specific errors are tested at this
109     * point, just assume that connections cannot
110     * be accepted until some old is closed first.
111     */
112 michael 8252 while ((fd = comm_accept(&listener->fd, &addr)) != -1)
113 michael 4520 {
114     /*
115     * check for connection limit
116     */
117     if (number_fd > hard_fdlimit - 10)
118     {
119     ++ServerStats.is_ref;
120     sendto_realops_flags_ratelimited(&rate, "All connections in use. (%s)",
121 michael 6368 listener_get_name(listener));
122 michael 4520
123     if (!(listener->flags & LISTENER_SSL))
124 michael 4839 send(fd, ALLINUSE_WARNING, sizeof(ALLINUSE_WARNING) - 1, 0);
125 michael 4520
126     close(fd);
127     break; /* jump out and re-register a new io request */
128     }
129    
130     /*
131     * Do an initial check we aren't connecting too fast or with too many
132     * from this IP...
133     */
134     if ((pe = conf_connect_allowed(&addr, addr.ss.ss_family)))
135     {
136     ++ServerStats.is_ref;
137    
138     if (!(listener->flags & LISTENER_SSL))
139     {
140     switch (pe)
141     {
142     case BANNED_CLIENT:
143     send(fd, DLINE_WARNING, sizeof(DLINE_WARNING)-1, 0);
144     break;
145     case TOO_FAST:
146     send(fd, TOOFAST_WARNING, sizeof(TOOFAST_WARNING)-1, 0);
147     break;
148     }
149     }
150    
151     close(fd);
152     continue; /* drop the one and keep on clearing the queue */
153     }
154    
155     ++ServerStats.is_ac;
156     add_connection(listener, &addr, fd);
157     }
158    
159     /* Re-register a new IO request for the next accept .. */
160     comm_setselect(&listener->fd, COMM_SELECT_READ, listener_accept_connection,
161     listener, 0);
162     }
163    
164    
165 adx 30 /*
166     * inetport - create a listener socket in the AF_INET or AF_INET6 domain,
167     * bind it to the port given in 'port' and listen to it
168     * returns true (1) if successful false (0) on error.
169     *
170     * If the operating system has a define for SOMAXCONN, use it, otherwise
171     * use HYBRID_SOMAXCONN
172     */
173     #ifdef SOMAXCONN
174     #undef HYBRID_SOMAXCONN
175     #define HYBRID_SOMAXCONN SOMAXCONN
176     #endif
177    
178 michael 2916 static int
179 adx 30 inetport(struct Listener *listener)
180     {
181     struct irc_ssaddr lsin;
182     socklen_t opt = 1;
183    
184 michael 1123 memset(&lsin, 0, sizeof(lsin));
185     memcpy(&lsin, &listener->addr, sizeof(lsin));
186    
187 michael 5050 getnameinfo((const struct sockaddr *)&lsin, lsin.ss_len, listener->name,
188 michael 1123 sizeof(listener->name), NULL, 0, NI_NUMERICHOST);
189    
190 adx 30 /*
191     * At first, open a new socket
192     */
193     if (comm_open(&listener->fd, listener->addr.ss.ss_family, SOCK_STREAM, 0,
194     "Listener socket") == -1)
195     {
196     report_error(L_ALL, "opening listener socket %s:%s",
197 michael 6368 listener_get_name(listener), errno);
198 adx 30 return 0;
199     }
200    
201     if (setsockopt(listener->fd.fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)))
202     {
203     report_error(L_ALL, "setting SO_REUSEADDR for listener %s:%s",
204 michael 6368 listener_get_name(listener), errno);
205 adx 30 fd_close(&listener->fd);
206 michael 900 return 0;
207 adx 30 }
208    
209     /*
210     * Bind a port to listen for new connections if port is non-null,
211     * else assume it is already open and try get something from it.
212     */
213     lsin.ss_port = htons(listener->port);
214    
215     if (bind(listener->fd.fd, (struct sockaddr *)&lsin, lsin.ss_len))
216     {
217     report_error(L_ALL, "binding listener socket %s:%s",
218 michael 6368 listener_get_name(listener), errno);
219 adx 30 fd_close(&listener->fd);
220 michael 900 return 0;
221 adx 30 }
222    
223     if (listen(listener->fd.fd, HYBRID_SOMAXCONN))
224     {
225     report_error(L_ALL, "listen failed for %s:%s",
226 michael 6368 listener_get_name(listener), errno);
227 adx 30 fd_close(&listener->fd);
228 michael 900 return 0;
229 adx 30 }
230    
231     /* Listen completion events are READ events .. */
232    
233 michael 4520 listener_accept_connection(&listener->fd, listener);
234 adx 30 return 1;
235     }
236    
237     static struct Listener *
238 michael 6368 listener_find(int port, struct irc_ssaddr *addr)
239 adx 30 {
240 michael 4816 dlink_node *node;
241 adx 30 struct Listener *listener = NULL;
242     struct Listener *last_closed = NULL;
243    
244 michael 4816 DLINK_FOREACH(node, listener_list.head)
245 adx 30 {
246 michael 4816 listener = node->data;
247 adx 30
248     if ((port == listener->port) &&
249     (!memcmp(addr, &listener->addr, sizeof(struct irc_ssaddr))))
250     {
251     /* Try to return an open listener, otherwise reuse a closed one */
252     if (!listener->fd.flags.open)
253     last_closed = listener;
254     else
255     return (listener);
256     }
257     }
258    
259     return (last_closed);
260     }
261    
262     /*
263 michael 4426 * close_listener - close a single listener
264     */
265     static void
266 michael 6368 listener_close(struct Listener *listener)
267 michael 4426 {
268     if (listener->fd.flags.open)
269     fd_close(&listener->fd);
270    
271     listener->active = 0;
272    
273     if (listener->ref_count)
274     return;
275    
276 michael 6368 listener_free(listener);
277 michael 4426 }
278    
279     /*
280 michael 6368 * listener_close_marked - close and free all listeners that are not being used
281 michael 4426 */
282     void
283 michael 6368 listener_close_marked(void)
284 michael 4426 {
285 michael 4816 dlink_node *node = NULL, *node_next = NULL;
286 michael 4426
287     /* close all 'extra' listening ports we have */
288 michael 4816 DLINK_FOREACH_SAFE(node, node_next, listener_list.head)
289 michael 6368 listener_close(node->data);
290 michael 4426 }
291    
292 michael 4429 void
293     listener_release(struct Listener *listener)
294     {
295     assert(listener->ref_count > 0);
296    
297     if (--listener->ref_count == 0 && !listener->active)
298 michael 6368 listener_close(listener);
299 michael 4429 }
300    
301 michael 4426 /*
302 michael 6368 * listener_add- create a new listener
303 adx 30 * port - the port number to listen on
304     * vhost_ip - if non-null must contain a valid IP address string in
305     * the format "255.255.255.255"
306     */
307 michael 2916 void
308 michael 6368 listener_add(int port, const char *vhost_ip, unsigned int flags)
309 adx 30 {
310     struct Listener *listener;
311     struct irc_ssaddr vaddr;
312     struct addrinfo hints, *res;
313     char portname[PORTNAMELEN + 1];
314     static short int pass = 0; /* if ipv6 and no address specified we need to
315     have two listeners; one for each protocol. */
316    
317     /*
318     * if no or invalid port in conf line, don't bother
319     */
320     if (!(port > 0 && port <= 0xFFFF))
321     return;
322    
323     memset(&vaddr, 0, sizeof(vaddr));
324    
325     /* Set up the hints structure */
326     memset(&hints, 0, sizeof(hints));
327     hints.ai_family = AF_UNSPEC;
328     hints.ai_socktype = SOCK_STREAM;
329     /* Get us ready for a bind() and don't bother doing dns lookup */
330     hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST;
331    
332 michael 4414 /* TBD: This makes no sense here at all. Needs to be reworked */
333 adx 30
334 michael 4414 snprintf(portname, sizeof(portname), "%d", port);
335     getaddrinfo("::", portname, &hints, &res);
336     vaddr.ss.ss_family = AF_INET6;
337    
338 michael 5002 assert(res);
339    
340 michael 4414 memcpy((struct sockaddr*)&vaddr, res->ai_addr, res->ai_addrlen);
341     vaddr.ss_port = port;
342     vaddr.ss_len = res->ai_addrlen;
343     freeaddrinfo(res);
344     #ifdef MAKES_NO_SENSE
345 adx 30 {
346     struct sockaddr_in *v4 = (struct sockaddr_in*) &vaddr;
347     v4->sin_addr.s_addr = INADDR_ANY;
348     vaddr.ss.ss_family = AF_INET;
349     vaddr.ss_len = sizeof(struct sockaddr_in);
350     v4->sin_port = htons(port);
351     }
352 michael 4414 #endif
353 adx 30
354     snprintf(portname, PORTNAMELEN, "%d", port);
355    
356 michael 1669 if (!EmptyString(vhost_ip))
357 adx 30 {
358 michael 1123 if (getaddrinfo(vhost_ip, portname, &hints, &res))
359     return;
360 adx 30
361 michael 3335 assert(res);
362 adx 30
363     memcpy((struct sockaddr*)&vaddr, res->ai_addr, res->ai_addrlen);
364     vaddr.ss_port = port;
365     vaddr.ss_len = res->ai_addrlen;
366 michael 1123 freeaddrinfo(res);
367 adx 30 }
368 michael 4414 else if (pass == 0)
369 adx 30 {
370     /* add the ipv4 listener if we havent already */
371     pass = 1;
372 michael 6368 listener_add(port, "0.0.0.0", flags);
373 adx 30 }
374 michael 4414
375 adx 30 pass = 0;
376    
377 michael 6368 if ((listener = listener_find(port, &vaddr)))
378 adx 30 {
379     listener->flags = flags;
380 michael 3335
381 adx 30 if (listener->fd.flags.open)
382     return;
383     }
384     else
385     {
386 michael 6368 listener = listener_make(port, &vaddr);
387 michael 4519 dlinkAdd(listener, &listener->node, &listener_list);
388 adx 30 listener->flags = flags;
389     }
390    
391     if (inetport(listener))
392     listener->active = 1;
393     else
394 michael 6368 listener_close(listener);
395 adx 30 }

Properties

Name Value
svn:eol-style native
svn:keywords Id