/[svn]/ircd-hybrid/branches/8.2.x/src/listener.c
ViewVC logotype

Contents of /ircd-hybrid/branches/8.2.x/src/listener.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 9995 - (show annotations)
Thu Jun 17 16:20:00 2021 UTC (3 months, 1 week ago) by michael
File MIME type: text/x-chdr
File size: 10919 byte(s)
- listener.c:listener_add(): remove pointless code

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

Properties

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

svnadmin@ircd-hybrid.org
ViewVC Help
Powered by ViewVC 1.1.28