ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/branches/8.2.x/src/listener.c
Revision: 8348
Committed: Sun Mar 4 13:23:49 2018 UTC (6 years, 1 month ago) by michael
Content type: text/x-csrc
File size: 10381 byte(s)
Log Message:
- Style corrections

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 8309 struct Listener *listener = xcalloc(sizeof(*listener));
56 adx 30
57     listener->port = port;
58 michael 8309 memcpy(&listener->addr, addr, sizeof(listener->addr));
59 adx 30
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 michael 8348 listener_accept_connection(fde_t *F, void *data)
93 michael 4520 {
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 michael 8348 assert(listener->fd == F);
102 michael 8338 assert(listener->fd);
103     assert(listener->fd->flags.open);
104 michael 4520
105     /* There may be many reasons for error return, but
106     * in otherwise correctly working environment the
107     * probable cause is running out of file descriptors
108     * (EMFILE, ENFILE or others?). The man pages for
109     * accept don't seem to list these as possible,
110     * although it's obvious that it may happen here.
111     * Thus no specific errors are tested at this
112     * point, just assume that connections cannot
113     * be accepted until some old is closed first.
114     */
115 michael 8338 while ((fd = comm_accept(listener->fd->fd, &addr)) != -1)
116 michael 4520 {
117     /*
118     * check for connection limit
119     */
120     if (number_fd > hard_fdlimit - 10)
121     {
122     ++ServerStats.is_ref;
123     sendto_realops_flags_ratelimited(&rate, "All connections in use. (%s)",
124 michael 6368 listener_get_name(listener));
125 michael 4520
126     if (!(listener->flags & LISTENER_SSL))
127 michael 4839 send(fd, ALLINUSE_WARNING, sizeof(ALLINUSE_WARNING) - 1, 0);
128 michael 4520
129     close(fd);
130     break; /* jump out and re-register a new io request */
131     }
132    
133     /*
134     * Do an initial check we aren't connecting too fast or with too many
135     * from this IP...
136     */
137     if ((pe = conf_connect_allowed(&addr, addr.ss.ss_family)))
138     {
139     ++ServerStats.is_ref;
140    
141     if (!(listener->flags & LISTENER_SSL))
142     {
143     switch (pe)
144     {
145     case BANNED_CLIENT:
146     send(fd, DLINE_WARNING, sizeof(DLINE_WARNING)-1, 0);
147     break;
148     case TOO_FAST:
149     send(fd, TOOFAST_WARNING, sizeof(TOOFAST_WARNING)-1, 0);
150     break;
151     }
152     }
153    
154     close(fd);
155     continue; /* drop the one and keep on clearing the queue */
156     }
157    
158     ++ServerStats.is_ac;
159     add_connection(listener, &addr, fd);
160     }
161    
162     /* Re-register a new IO request for the next accept .. */
163 michael 8338 comm_setselect(listener->fd, COMM_SELECT_READ, listener_accept_connection,
164 michael 4520 listener, 0);
165     }
166    
167    
168 adx 30 /*
169     * inetport - create a listener socket in the AF_INET or AF_INET6 domain,
170     * bind it to the port given in 'port' and listen to it
171     * returns true (1) if successful false (0) on error.
172     *
173     * If the operating system has a define for SOMAXCONN, use it, otherwise
174     * use HYBRID_SOMAXCONN
175     */
176     #ifdef SOMAXCONN
177     #undef HYBRID_SOMAXCONN
178     #define HYBRID_SOMAXCONN SOMAXCONN
179     #endif
180    
181 michael 2916 static int
182 adx 30 inetport(struct Listener *listener)
183     {
184     struct irc_ssaddr lsin;
185     socklen_t opt = 1;
186    
187 michael 1123 memset(&lsin, 0, sizeof(lsin));
188     memcpy(&lsin, &listener->addr, sizeof(lsin));
189    
190 michael 5050 getnameinfo((const struct sockaddr *)&lsin, lsin.ss_len, listener->name,
191 michael 1123 sizeof(listener->name), NULL, 0, NI_NUMERICHOST);
192    
193 adx 30 /*
194     * At first, open a new socket
195     */
196 michael 8338 int fd = comm_socket(listener->addr.ss.ss_family, SOCK_STREAM, 0);
197     if (fd == -1)
198 adx 30 {
199     report_error(L_ALL, "opening listener socket %s:%s",
200 michael 6368 listener_get_name(listener), errno);
201 adx 30 return 0;
202     }
203    
204 michael 8338 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)))
205 adx 30 {
206     report_error(L_ALL, "setting SO_REUSEADDR for listener %s:%s",
207 michael 6368 listener_get_name(listener), errno);
208 michael 8338 close(fd);
209 michael 900 return 0;
210 adx 30 }
211    
212     /*
213     * Bind a port to listen for new connections if port is non-null,
214     * else assume it is already open and try get something from it.
215     */
216     lsin.ss_port = htons(listener->port);
217    
218 michael 8338 if (bind(fd, (struct sockaddr *)&lsin, lsin.ss_len))
219 adx 30 {
220     report_error(L_ALL, "binding listener socket %s:%s",
221 michael 6368 listener_get_name(listener), errno);
222 michael 8338 close(fd);
223 michael 900 return 0;
224 adx 30 }
225    
226 michael 8338 if (listen(fd, HYBRID_SOMAXCONN))
227 adx 30 {
228     report_error(L_ALL, "listen failed for %s:%s",
229 michael 6368 listener_get_name(listener), errno);
230 michael 8338 close(fd);
231 michael 900 return 0;
232 adx 30 }
233    
234 michael 8338 listener->fd = fd_open(fd, 1, "Listener socket");
235    
236 adx 30 /* Listen completion events are READ events .. */
237    
238 michael 8338 listener_accept_connection(listener->fd, listener);
239 adx 30 return 1;
240     }
241    
242     static struct Listener *
243 michael 6368 listener_find(int port, struct irc_ssaddr *addr)
244 adx 30 {
245 michael 4816 dlink_node *node;
246 adx 30 struct Listener *listener = NULL;
247     struct Listener *last_closed = NULL;
248    
249 michael 4816 DLINK_FOREACH(node, listener_list.head)
250 adx 30 {
251 michael 4816 listener = node->data;
252 adx 30
253     if ((port == listener->port) &&
254 michael 8309 (!memcmp(addr, &listener->addr, sizeof(*addr))))
255 adx 30 {
256     /* Try to return an open listener, otherwise reuse a closed one */
257 michael 8338 if (listener->fd)
258     {
259     assert(listener->fd->flags.open);
260 adx 30 last_closed = listener;
261 michael 8338 }
262 adx 30 else
263     return (listener);
264     }
265     }
266    
267     return (last_closed);
268     }
269    
270     /*
271 michael 4426 * close_listener - close a single listener
272     */
273     static void
274 michael 6368 listener_close(struct Listener *listener)
275 michael 4426 {
276 michael 8338 if (listener->fd)
277     {
278     assert(listener->fd->flags.open);
279 michael 4426
280 michael 8338 fd_close(listener->fd);
281     listener->fd = NULL;
282     }
283    
284 michael 4426 listener->active = 0;
285    
286     if (listener->ref_count)
287     return;
288    
289 michael 6368 listener_free(listener);
290 michael 4426 }
291    
292     /*
293 michael 6368 * listener_close_marked - close and free all listeners that are not being used
294 michael 4426 */
295     void
296 michael 6368 listener_close_marked(void)
297 michael 4426 {
298 michael 8348 dlink_node *node, *node_next;
299 michael 4426
300     /* close all 'extra' listening ports we have */
301 michael 4816 DLINK_FOREACH_SAFE(node, node_next, listener_list.head)
302 michael 6368 listener_close(node->data);
303 michael 4426 }
304    
305 michael 4429 void
306     listener_release(struct Listener *listener)
307     {
308     assert(listener->ref_count > 0);
309    
310     if (--listener->ref_count == 0 && !listener->active)
311 michael 6368 listener_close(listener);
312 michael 4429 }
313    
314 michael 4426 /*
315 michael 6368 * listener_add- create a new listener
316 adx 30 * port - the port number to listen on
317     * vhost_ip - if non-null must contain a valid IP address string in
318     * the format "255.255.255.255"
319     */
320 michael 2916 void
321 michael 6368 listener_add(int port, const char *vhost_ip, unsigned int flags)
322 adx 30 {
323     struct Listener *listener;
324     struct irc_ssaddr vaddr;
325     struct addrinfo hints, *res;
326     char portname[PORTNAMELEN + 1];
327     static short int pass = 0; /* if ipv6 and no address specified we need to
328     have two listeners; one for each protocol. */
329    
330     /*
331     * if no or invalid port in conf line, don't bother
332     */
333     if (!(port > 0 && port <= 0xFFFF))
334     return;
335    
336     memset(&vaddr, 0, sizeof(vaddr));
337    
338     /* Set up the hints structure */
339     memset(&hints, 0, sizeof(hints));
340     hints.ai_family = AF_UNSPEC;
341     hints.ai_socktype = SOCK_STREAM;
342     /* Get us ready for a bind() and don't bother doing dns lookup */
343     hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST;
344    
345 michael 4414 /* TBD: This makes no sense here at all. Needs to be reworked */
346 adx 30
347 michael 4414 snprintf(portname, sizeof(portname), "%d", port);
348     getaddrinfo("::", portname, &hints, &res);
349     vaddr.ss.ss_family = AF_INET6;
350    
351 michael 5002 assert(res);
352    
353 michael 4414 memcpy((struct sockaddr*)&vaddr, res->ai_addr, res->ai_addrlen);
354     vaddr.ss_port = port;
355     vaddr.ss_len = res->ai_addrlen;
356     freeaddrinfo(res);
357     #ifdef MAKES_NO_SENSE
358 adx 30 {
359     struct sockaddr_in *v4 = (struct sockaddr_in*) &vaddr;
360     v4->sin_addr.s_addr = INADDR_ANY;
361     vaddr.ss.ss_family = AF_INET;
362     vaddr.ss_len = sizeof(struct sockaddr_in);
363     v4->sin_port = htons(port);
364     }
365 michael 4414 #endif
366 adx 30
367     snprintf(portname, PORTNAMELEN, "%d", port);
368    
369 michael 1669 if (!EmptyString(vhost_ip))
370 adx 30 {
371 michael 1123 if (getaddrinfo(vhost_ip, portname, &hints, &res))
372     return;
373 adx 30
374 michael 3335 assert(res);
375 adx 30
376     memcpy((struct sockaddr*)&vaddr, res->ai_addr, res->ai_addrlen);
377     vaddr.ss_port = port;
378     vaddr.ss_len = res->ai_addrlen;
379 michael 1123 freeaddrinfo(res);
380 adx 30 }
381 michael 4414 else if (pass == 0)
382 adx 30 {
383     /* add the ipv4 listener if we havent already */
384     pass = 1;
385 michael 6368 listener_add(port, "0.0.0.0", flags);
386 adx 30 }
387 michael 4414
388 adx 30 pass = 0;
389    
390 michael 6368 if ((listener = listener_find(port, &vaddr)))
391 adx 30 {
392     listener->flags = flags;
393 michael 3335
394 michael 8338 if (listener->fd)
395     {
396     assert(listener->fd->flags.open);
397 adx 30 return;
398 michael 8338 }
399 adx 30 }
400     else
401     {
402 michael 6368 listener = listener_make(port, &vaddr);
403 michael 4519 dlinkAdd(listener, &listener->node, &listener_list);
404 adx 30 listener->flags = flags;
405     }
406    
407     if (inetport(listener))
408     listener->active = 1;
409     else
410 michael 6368 listener_close(listener);
411 adx 30 }

Properties

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