ISC DHCP 4.4.3-P1
A reference DHCPv4 and DHCPv6 implementation
 
Loading...
Searching...
No Matches
listener.c
Go to the documentation of this file.
1/* listener.c
2
3 Subroutines that support the generic listener object. */
4
5/*
6 * Copyright (C) 2004-2022 Internet Systems Consortium, Inc. ("ISC")
7 * Copyright (c) 1999-2003 by Internet Software Consortium
8 *
9 * This Source Code Form is subject to the terms of the Mozilla Public
10 * License, v. 2.0. If a copy of the MPL was not distributed with this
11 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
12 *
13 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
14 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
15 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
16 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
17 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
18 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
19 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20 *
21 * Internet Systems Consortium, Inc.
22 * PO Box 360
23 * Newmarket, NH 03857 USA
24 * <info@isc.org>
25 * https://www.isc.org/
26 *
27 */
28
29#include "dhcpd.h"
30
31#include <omapip/omapip_p.h>
32#include <errno.h>
33
34#if defined (TRACING)
35omapi_array_t *trace_listeners;
36static void trace_listener_accept_input (trace_type_t *, unsigned, char *);
37static void trace_listener_remember (omapi_listener_object_t *,
38 const char *, int);
39static void trace_listener_accept_stop (trace_type_t *);
40trace_type_t *trace_listener_accept;
41#endif
42
43OMAPI_OBJECT_ALLOC (omapi_listener,
45
46isc_result_t omapi_listen (omapi_object_t *h,
47 unsigned port,
48 int max)
49{
50 omapi_addr_t addr;
51
52#ifdef DEBUG_PROTOCOL
53 log_debug ("omapi_listen(port=%d, max=%d)", port, max);
54#endif
55
56 addr.addrtype = AF_INET;
57 addr.addrlen = sizeof (struct in_addr);
58 memset (addr.address, 0, sizeof addr.address); /* INADDR_ANY */
59 addr.port = port;
60
61 return omapi_listen_addr (h, &addr, max);
62}
63
65 omapi_addr_t *addr,
66 int max)
67{
68 isc_result_t status;
70 int i;
71
72 /* Currently only support IPv4 addresses. */
73 if (addr->addrtype != AF_INET)
74 return DHCP_R_INVALIDARG;
75
76 /* Get the handle. */
77 obj = (omapi_listener_object_t *)0;
78 status = omapi_listener_allocate (&obj, MDL);
79 if (status != ISC_R_SUCCESS)
80 /*
81 * we could simply return here but by going to
82 * error_exit we keep the code check tools happy
83 * without removing the NULL check on obj at
84 * the exit, which we could skip curently but
85 * might want in the future.
86 */
87 goto error_exit;
88 obj->socket = -1;
89
90 /* Connect this object to the inner object. */
91 status = omapi_object_reference (&h -> outer,
92 (omapi_object_t *)obj, MDL);
93 if (status != ISC_R_SUCCESS)
94 goto error_exit;
95 status = omapi_object_reference (&obj -> inner, h, MDL);
96 if (status != ISC_R_SUCCESS)
97 goto error_exit;
98
99 /* Set up the address on which we will listen... */
100 obj -> address.sin_port = htons (addr -> port);
101 memcpy (&obj -> address.sin_addr,
102 addr -> address, sizeof obj -> address.sin_addr);
103#if defined (HAVE_SA_LEN)
104 obj -> address.sin_len =
105 sizeof (struct sockaddr_in);
106#endif
107 obj -> address.sin_family = AF_INET;
108 memset (&(obj -> address.sin_zero), 0,
109 sizeof obj -> address.sin_zero);
110
111#if defined (TRACING)
112 /* If we're playing back a trace file, we remember the object
113 on the trace listener queue. */
114 if (trace_playback ()) {
115 trace_listener_remember (obj, MDL);
116 } else {
117#endif
118 /* Create a socket on which to listen. */
119 obj -> socket = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP);
120 if (obj->socket == -1) {
121 if (errno == EMFILE
122 || errno == ENFILE || errno == ENOBUFS)
123 status = ISC_R_NORESOURCES;
124 else
125 status = ISC_R_UNEXPECTED;
126 goto error_exit;
127 }
128
129#if defined (HAVE_SETFD)
130 if (fcntl (obj -> socket, F_SETFD, 1) < 0) {
131 status = ISC_R_UNEXPECTED;
132 goto error_exit;
133 }
134#endif
135
136 /* Set the REUSEADDR option so that we don't fail to start if
137 we're being restarted. */
138 i = 1;
139 if (setsockopt (obj -> socket, SOL_SOCKET, SO_REUSEADDR,
140 (char *)&i, sizeof i) < 0) {
141 status = ISC_R_UNEXPECTED;
142 goto error_exit;
143 }
144
145 /* Try to bind to the wildcard address using the port number
146 we were given. */
147 i = bind (obj -> socket,
148 (struct sockaddr *)&obj -> address,
149 sizeof obj -> address);
150 if (i < 0) {
151 if (errno == EADDRINUSE)
152 status = ISC_R_ADDRNOTAVAIL;
153 else if (errno == EPERM)
154 status = ISC_R_NOPERM;
155 else
156 status = ISC_R_UNEXPECTED;
157 goto error_exit;
158 }
159
160 /* Now tell the kernel to listen for connections. */
161 if (listen (obj -> socket, max)) {
162 status = ISC_R_UNEXPECTED;
163 goto error_exit;
164 }
165
166 if (fcntl (obj -> socket, F_SETFL, O_NONBLOCK) < 0) {
167 status = ISC_R_UNEXPECTED;
168 goto error_exit;
169 }
170
173 omapi_accept, 0, 0);
174#if defined (TRACING)
175 }
176#endif
177
178 omapi_listener_dereference (&obj, MDL);
179 return status;
180
181error_exit:
182 if (obj != NULL) {
183 if (h->outer == (omapi_object_t *)obj) {
185 MDL);
186 }
187 if (obj->inner == h) {
189 MDL);
190 }
191 if (obj->socket != -1) {
192 close(obj->socket);
193 }
194 omapi_listener_dereference(&obj, MDL);
195 }
196 return status;
197}
198
199/* Return the socket on which the dispatcher should wait for readiness
200 to read, for a listener object. */
202{
204
205 if (h -> type != omapi_type_listener)
206 return -1;
208
209 return l -> socket;
210}
211
212/* Reader callback for a listener object. Accept an incoming connection. */
214{
215 isc_result_t status;
216 socklen_t len;
218 omapi_listener_object_t *listener;
219 struct sockaddr_in addr;
220 int socket;
221
222 if (h -> type != omapi_type_listener)
223 return DHCP_R_INVALIDARG;
224 listener = (omapi_listener_object_t *)h;
225
226 /* Accept the connection. */
227 len = sizeof addr;
228 socket = accept (listener -> socket,
229 ((struct sockaddr *)&(addr)), &len);
230 if (socket < 0) {
231 if (errno == EMFILE || errno == ENFILE || errno == ENOBUFS)
232 return ISC_R_NORESOURCES;
233 return ISC_R_UNEXPECTED;
234 }
235
236 if ((MAX_FD_VALUE != 0) && (socket > MAX_FD_VALUE)) {
237 close(socket);
238 return (ISC_R_NORESOURCES);
239 }
240
241#if defined (TRACING)
242 /* If we're recording a trace, remember the connection. */
243 if (trace_record ()) {
244 trace_iov_t iov [3];
245 iov [0].buf = (char *)&addr.sin_port;
246 iov [0].len = sizeof addr.sin_port;
247 iov [1].buf = (char *)&addr.sin_addr;
248 iov [1].len = sizeof addr.sin_addr;
249 iov [2].buf = (char *)&listener -> address.sin_port;
250 iov [2].len = sizeof listener -> address.sin_port;
251 trace_write_packet_iov (trace_listener_accept,
252 3, iov, MDL);
253 }
254#endif
255
256 obj = (omapi_connection_object_t *)0;
257 status = omapi_listener_connect (&obj, listener, socket, &addr);
258 if (status != ISC_R_SUCCESS) {
259 close (socket);
260 return status;
261 }
262
269
270 /* Lose our reference to the connection, so it'll be gc'd when it's
271 reaped. */
272 omapi_connection_dereference (&obj, MDL);
273 if (status != ISC_R_SUCCESS)
274 omapi_disconnect ((omapi_object_t *)(obj), 1);
275 return status;
276}
277
279 omapi_listener_object_t *listener,
280 int socket,
281 struct sockaddr_in *remote_addr)
282{
283 isc_result_t status;
284 omapi_object_t *h = (omapi_object_t *)listener;
285 omapi_addr_t addr;
286
287#ifdef DEBUG_PROTOCOL
288 log_debug ("omapi_accept()");
289#endif
290
291 /* Get the handle. */
292 status = omapi_connection_allocate (obj, MDL);
293 if (status != ISC_R_SUCCESS)
294 return status;
295
296 (*obj) -> state = omapi_connection_connected;
297 (*obj) -> remote_addr = *remote_addr;
298 (*obj) -> socket = socket;
299
300 /* Verify that this host is allowed to connect. */
301 if (listener -> verify_addr) {
302 addr.addrtype = AF_INET;
303 addr.addrlen = sizeof (remote_addr -> sin_addr);
304 memcpy (addr.address, &remote_addr -> sin_addr,
305 sizeof (remote_addr -> sin_addr));
306 addr.port = ntohs(remote_addr -> sin_port);
307
308 status = (listener -> verify_addr) (h, &addr);
309 if (status != ISC_R_SUCCESS) {
310 omapi_disconnect ((omapi_object_t *)(*obj), 1);
311 omapi_connection_dereference (obj, MDL);
312 return status;
313 }
314 }
315
316 omapi_listener_reference (&(*obj) -> listener, listener, MDL);
317#if defined (TRACING)
319#endif
320 status = omapi_signal (h, "connect", (*obj));
321 return status;
322}
323
324#if defined (TRACING)
326
327void omapi_listener_trace_setup (void) {
328 trace_listener_accept =
329 trace_type_register ("listener-accept", (void *)0,
330 trace_listener_accept_input,
331 trace_listener_accept_stop, MDL);
332}
333
334static void trace_listener_remember (omapi_listener_object_t *obj,
335 const char *file, int line)
336{
337 isc_result_t status;
338 if (!trace_listeners) {
339 status = omapi_listener_array_allocate (&trace_listeners,
340 file, line);
341 if (status != ISC_R_SUCCESS) {
342 foo:
343 log_error ("trace_listener_remember: %s",
344 isc_result_totext (status));
345 return;
346 }
347 }
348 status = omapi_listener_array_extend (trace_listeners, obj,
349 &obj -> index, MDL);
350 if (status != ISC_R_SUCCESS)
351 goto foo;
352}
353
354static void trace_listener_accept_input (trace_type_t *ttype,
355 unsigned length, char *buf)
356{
357 struct in_addr *addr;
358 u_int16_t *remote_port;
359 u_int16_t *local_port;
361 isc_result_t status;
362 struct sockaddr_in remote_addr;
363
364 addr = (struct in_addr *)buf;
365 remote_port = (u_int16_t *)(addr + 1);
367
368 memset (&remote_addr, 0, sizeof remote_addr);
369 remote_addr.sin_addr = *addr;
370 remote_addr.sin_port = *remote_port;
371
372 omapi_array_foreach_begin (trace_listeners,
374 if (lp -> address.sin_port == *local_port) {
375 obj = (omapi_connection_object_t *)0;
376 status = omapi_listener_connect (&obj,
377 lp, 0, &remote_addr);
378 if (status != ISC_R_SUCCESS) {
379 log_error("%s:%d: OMAPI: Failed to connect "
380 "a listener.", MDL);
381 }
382 omapi_listener_dereference (&lp, MDL);
383 return;
384 }
385 } omapi_array_foreach_end (trace_listeners,
387 log_error ("trace_listener_accept: %s from %s/%d to port %d",
388 "unexpected connect",
389 inet_ntoa (*addr), *remote_port, *local_port);
390}
391
392static void trace_listener_accept_stop (trace_type_t *ttype) { }
393
394
395#endif
396
398 isc_result_t (*verify_addr)
400 omapi_addr_t *))
401{
403
404 if (h -> type != omapi_type_listener)
405 return DHCP_R_INVALIDARG;
407
408 l -> verify_addr = verify_addr;
409
410 return ISC_R_SUCCESS;
411}
412
414 omapi_object_t *id,
417{
418 if (h -> type != omapi_type_listener)
419 return DHCP_R_INVALIDARG;
420
421 if (h -> inner && h -> inner -> type -> set_value)
422 return (*(h -> inner -> type -> set_value))
423 (h -> inner, id, name, value);
424 return ISC_R_NOTFOUND;
425}
426
428 omapi_object_t *id,
431{
432 if (h -> type != omapi_type_listener)
433 return DHCP_R_INVALIDARG;
434
435 if (h -> inner && h -> inner -> type -> get_value)
436 return (*(h -> inner -> type -> get_value))
437 (h -> inner, id, name, value);
438 return ISC_R_NOTFOUND;
439}
440
442 const char *file, int line)
443{
445
446 if (h -> type != omapi_type_listener)
447 return DHCP_R_INVALIDARG;
449
450#ifdef DEBUG_PROTOCOL
451 log_debug ("omapi_listener_destroy()");
452#endif
453
454 if (l -> socket != -1) {
455 close (l -> socket);
456 l -> socket = -1;
457 }
458 return ISC_R_SUCCESS;
459}
460
462 const char *name, va_list ap)
463{
464 if (h -> type != omapi_type_listener)
465 return DHCP_R_INVALIDARG;
466
467 if (h -> inner && h -> inner -> type -> signal_handler)
468 return (*(h -> inner -> type -> signal_handler)) (h -> inner,
469 name, ap);
470 return ISC_R_NOTFOUND;
471}
472
473/* Write all the published values associated with the object through the
474 specified connection. */
475
477 omapi_object_t *id,
479{
480 if (l -> type != omapi_type_listener)
481 return DHCP_R_INVALIDARG;
482
483 if (l -> inner && l -> inner -> type -> stuff_values)
484 return (*(l -> inner -> type -> stuff_values)) (c, id,
485 l -> inner);
486 return ISC_R_SUCCESS;
487}
u_int16_t remote_port
Definition discover.c:49
u_int16_t local_port
Definition discover.c:48
const char int line
Definition dhcpd.h:3802
const char * file
Definition dhcpd.h:3802
#define ISC_R_SUCCESS
isc_result_t omapi_accept(omapi_object_t *h)
Definition listener.c:213
isc_result_t omapi_listener_connect(omapi_connection_object_t **obj, omapi_listener_object_t *listener, int socket, struct sockaddr_in *remote_addr)
Definition listener.c:278
isc_result_t omapi_listener_destroy(omapi_object_t *h, const char *file, int line)
Definition listener.c:441
isc_result_t omapi_listener_get_value(omapi_object_t *h, omapi_object_t *id, omapi_data_string_t *name, omapi_value_t **value)
Definition listener.c:427
isc_result_t omapi_listen_addr(omapi_object_t *h, omapi_addr_t *addr, int max)
Definition listener.c:64
int omapi_listener_readfd(omapi_object_t *h)
Definition listener.c:201
isc_result_t omapi_listener_set_value(omapi_object_t *h, omapi_object_t *id, omapi_data_string_t *name, omapi_typed_data_t *value)
Definition listener.c:413
isc_result_t omapi_listener_signal_handler(omapi_object_t *h, const char *name, va_list ap)
Definition listener.c:461
isc_result_t omapi_listener_stuff_values(omapi_object_t *c, omapi_object_t *id, omapi_object_t *l)
Definition listener.c:476
isc_result_t omapi_listener_configure_security(omapi_object_t *h, isc_result_t(*verify_addr)(omapi_object_t *, omapi_addr_t *))
Definition listener.c:397
#define MDL
Definition omapip.h:567
#define omapi_array_foreach_begin(array, stype, var)
Definition omapip.h:242
#define OMAPI_OBJECT_ALLOC(name, stype, type)
Definition omapip.h:160
isc_result_t omapi_register_io_object(omapi_object_t *, int(*)(omapi_object_t *), int(*)(omapi_object_t *), isc_result_t(*)(omapi_object_t *), isc_result_t(*)(omapi_object_t *), isc_result_t(*)(omapi_object_t *))
Definition dispatch.c:198
isc_result_t omapi_object_dereference(omapi_object_t **, const char *, int)
Definition alloc.c:593
int omapi_connection_writefd(omapi_object_t *)
Definition connection.c:597
isc_result_t omapi_connection_reader(omapi_object_t *)
Definition buffer.c:131
struct __omapi_object omapi_object_t
Definition omapip.h:39
isc_result_t omapi_connection_writer(omapi_object_t *)
Definition buffer.c:448
int omapi_listener_readfd(omapi_object_t *)
Definition listener.c:201
isc_result_t omapi_disconnect(omapi_object_t *, int)
Definition connection.c:458
isc_result_t omapi_connection_reaper(omapi_object_t *)
Definition connection.c:744
int omapi_connection_readfd(omapi_object_t *)
Definition connection.c:580
isc_result_t omapi_object_reference(omapi_object_t **, omapi_object_t *, const char *, int)
Definition alloc.c:571
isc_result_t omapi_signal(omapi_object_t *, const char *,...)
Definition support.c:267
#define omapi_array_foreach_end(array, stype, var)
Definition omapip.h:256
omapi_object_type_t * omapi_type_listener
Definition support.c:34
#define OMAPI_ARRAY_TYPE(name, stype)
Definition omapip.h:197
isc_result_t omapi_accept(omapi_object_t *)
Definition listener.c:213
isc_result_t omapi_listen(omapi_object_t *, unsigned, int)
int log_error(const char *,...) __attribute__((__format__(__printf__
int int int log_debug(const char *,...) __attribute__((__format__(__printf__
struct __omapi_connection_object omapi_connection_object_t
void omapi_listener_trace_setup(void)
struct __omapi_listener_object omapi_listener_object_t
Definition omapip_p.h:253
void omapi_connection_register(omapi_connection_object_t *, const char *, int)
@ omapi_connection_connected
Definition omapip_p.h:101
#define DHCP_R_INVALIDARG
Definition result.h:49
#define MAX_FD_VALUE
Definition site.h:325
unsigned char address[16]
Definition omapip.h:137
unsigned addrlen
Definition omapip.h:136
unsigned addrtype
Definition omapip.h:135
unsigned port
Definition omapip.h:138
unsigned len
Definition trace.h:76
const char * buf
Definition trace.h:75
int trace_record(void)
struct trace_iov trace_iov_t
trace_type_t * trace_type_register(const char *, void *, void(*)(trace_type_t *, unsigned, char *), void(*)(trace_type_t *), const char *, int)
struct trace_type trace_type_t
Definition trace.h:63
isc_result_t trace_write_packet_iov(trace_type_t *, int, trace_iov_t *, const char *, int)
int trace_playback(void)
Definition data.h:205