ISC DHCP 4.4.3-P1
A reference DHCPv4 and DHCPv6 implementation
 
Loading...
Searching...
No Matches
connection.c
Go to the documentation of this file.
1/* connection.c
2
3 Subroutines for dealing with connections. */
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#include <isc/util.h>
31#include <omapip/omapip_p.h>
32#include <arpa/inet.h>
33#include <arpa/nameser.h>
34#include <errno.h>
35
36#if defined (TRACING)
37static void trace_connect_input (trace_type_t *, unsigned, char *);
38static void trace_connect_stop (trace_type_t *);
39static void trace_disconnect_input (trace_type_t *, unsigned, char *);
40static void trace_disconnect_stop (trace_type_t *);
41trace_type_t *trace_connect;
42trace_type_t *trace_disconnect;
43extern omapi_array_t *trace_listeners;
44#endif
45static isc_result_t omapi_connection_connect_internal (omapi_object_t *);
46
47static isc_result_t ctring_from_attribute(omapi_object_t *obj, char *attr_name,
48 char **cstr);
49
50OMAPI_OBJECT_ALLOC (omapi_connection,
52
53isc_result_t omapi_connect (omapi_object_t *c,
54 const char *server_name,
55 unsigned port)
56{
57 struct hostent *he;
58 unsigned i, hix;
60 struct in_addr foo;
61 isc_result_t status;
62
63#ifdef DEBUG_PROTOCOL
64 log_debug ("omapi_connect(%s, port=%d)", server_name, port);
65#endif
66
67 if (!inet_aton (server_name, &foo)) {
68 /* If we didn't get a numeric address, try for a domain
69 name. It's okay for this call to block. */
70 he = gethostbyname (server_name);
71 if (!he)
72 return DHCP_R_HOSTUNKNOWN;
73 for (i = 0; he -> h_addr_list [i]; i++)
74 ;
75 if (i == 0)
76 return DHCP_R_HOSTUNKNOWN;
77 hix = i;
78
79 status = omapi_addr_list_new (&addrs, hix, MDL);
80 if (status != ISC_R_SUCCESS)
81 return status;
82 for (i = 0; i < hix; i++) {
83 addrs -> addresses [i].addrtype = he -> h_addrtype;
84 addrs -> addresses [i].addrlen = he -> h_length;
85 memcpy (addrs -> addresses [i].address,
86 he -> h_addr_list [i],
87 (unsigned)he -> h_length);
88 addrs -> addresses [i].port = port;
89 }
90 } else {
91 status = omapi_addr_list_new (&addrs, 1, MDL);
92 if (status != ISC_R_SUCCESS)
93 return status;
94 addrs -> addresses [0].addrtype = AF_INET;
95 addrs -> addresses [0].addrlen = sizeof foo;
96 memcpy (addrs -> addresses [0].address, &foo, sizeof foo);
97 addrs -> addresses [0].port = port;
98 }
99 status = omapi_connect_list (c, addrs, (omapi_addr_t *)0);
101 return status;
102}
103
105 omapi_addr_list_t *remote_addrs,
106 omapi_addr_t *local_addr)
107{
108 isc_result_t status;
110 int flag;
111 struct sockaddr_in local_sin;
112
113 obj = (omapi_connection_object_t *)0;
114 status = omapi_connection_allocate (&obj, MDL);
115 if (status != ISC_R_SUCCESS)
116 return status;
117
118 status = omapi_object_reference (&c -> outer, (omapi_object_t *)obj,
119 MDL);
120 if (status != ISC_R_SUCCESS) {
121 omapi_connection_dereference (&obj, MDL);
122 return status;
123 }
124 status = omapi_object_reference (&obj -> inner, c, MDL);
125 if (status != ISC_R_SUCCESS) {
126 omapi_connection_dereference (&obj, MDL);
127 return status;
128 }
129
130 /* Store the address list on the object. */
131 omapi_addr_list_reference (&obj -> connect_list, remote_addrs, MDL);
132 obj -> cptr = 0;
133 obj -> state = omapi_connection_unconnected;
134
135#if defined (TRACING)
136 /* If we're playing back, don't actually try to connect - just leave
137 the object available for a subsequent connect or disconnect. */
138 if (!trace_playback ()) {
139#endif
140 /* Create a socket on which to communicate. */
141 obj -> socket =
142 socket (PF_INET, SOCK_STREAM, IPPROTO_TCP);
143 if (obj -> socket < 0) {
144 omapi_connection_dereference (&obj, MDL);
145 if (errno == EMFILE || errno == ENFILE
146 || errno == ENOBUFS)
147 return ISC_R_NORESOURCES;
148 return ISC_R_UNEXPECTED;
149 }
150
151 /* Set up the local address, if any. */
152 if (local_addr) {
153 /* Only do TCPv4 so far. */
154 if (local_addr -> addrtype != AF_INET) {
155 close(obj->socket);
156 omapi_connection_dereference (&obj, MDL);
157 return DHCP_R_INVALIDARG;
158 }
159 local_sin.sin_port = htons (local_addr -> port);
160 memcpy (&local_sin.sin_addr,
161 local_addr -> address,
162 local_addr -> addrlen);
163#if defined (HAVE_SA_LEN)
164 local_sin.sin_len = sizeof local_addr;
165#endif
166 local_sin.sin_family = AF_INET;
167 memset (&local_sin.sin_zero, 0,
168 sizeof local_sin.sin_zero);
169
170 if (bind (obj -> socket, (struct sockaddr *)&local_sin,
171 sizeof local_sin) < 0) {
172 omapi_connection_object_t **objp = &obj;
173 omapi_object_t **o = (omapi_object_t **)objp;
174 close(obj->socket);
176 if (errno == EADDRINUSE)
177 return ISC_R_ADDRINUSE;
178 if (errno == EADDRNOTAVAIL)
179 return ISC_R_ADDRNOTAVAIL;
180 if (errno == EACCES)
181 return ISC_R_NOPERM;
182 return ISC_R_UNEXPECTED;
183 }
184 obj -> local_addr = local_sin;
185 }
186
187#if defined(F_SETFD)
188 if (fcntl (obj -> socket, F_SETFD, 1) < 0) {
189 close (obj -> socket);
190 omapi_connection_dereference (&obj, MDL);
191 return ISC_R_UNEXPECTED;
192 }
193#endif
194
195 /* Set the SO_REUSEADDR flag (this should not fail). */
196 flag = 1;
197 if (setsockopt (obj -> socket, SOL_SOCKET, SO_REUSEADDR,
198 (char *)&flag, sizeof flag) < 0) {
199 omapi_connection_dereference (&obj, MDL);
200 return ISC_R_UNEXPECTED;
201 }
202
203 /* Set the file to nonblocking mode. */
204 if (fcntl (obj -> socket, F_SETFL, O_NONBLOCK) < 0) {
205 omapi_connection_dereference (&obj, MDL);
206 return ISC_R_UNEXPECTED;
207 }
208
209#ifdef SO_NOSIGPIPE
210 /*
211 * If available stop the OS from killing our
212 * program on a SIGPIPE failure
213 */
214 flag = 1;
215 if (setsockopt(obj->socket, SOL_SOCKET, SO_NOSIGPIPE,
216 (char *)&flag, sizeof(flag)) < 0) {
217 omapi_connection_dereference (&obj, MDL);
218 return ISC_R_UNEXPECTED;
219 }
220#endif
221
223 ((omapi_object_t *)obj,
227 if (status != ISC_R_SUCCESS)
228 goto out;
229 status = omapi_connection_connect_internal ((omapi_object_t *)
230 obj);
231 /*
232 * inprogress is the same as success but used
233 * to indicate to the dispatch code that we should
234 * mark the socket as requiring more attention.
235 * Routines calling this function should handle
236 * success properly.
237 */
238 if (status == ISC_R_INPROGRESS) {
239 status = ISC_R_SUCCESS;
240 }
241#if defined (TRACING)
242 }
244#endif
245
246 out:
247 omapi_connection_dereference (&obj, MDL);
248 return status;
249}
250
251#if defined (TRACING)
252omapi_array_t *omapi_connections;
253
255
257 trace_connect = trace_type_register ("connect", (void *)0,
258 trace_connect_input,
259 trace_connect_stop, MDL);
260 trace_disconnect = trace_type_register ("disconnect", (void *)0,
261 trace_disconnect_input,
262 trace_disconnect_stop, MDL);
263}
264
266 const char *file, int line)
267{
268 isc_result_t status;
269 trace_iov_t iov [6];
270 int iov_count = 0;
271 int32_t connect_index, listener_index;
272 static int32_t index;
273
274 if (!omapi_connections) {
275 status = omapi_connection_array_allocate (&omapi_connections,
276 file, line);
277 if (status != ISC_R_SUCCESS)
278 return;
279 }
280
281 status = omapi_connection_array_extend (omapi_connections, obj,
282 (int *)0, file, line);
283 if (status != ISC_R_SUCCESS) {
284 obj -> index = -1;
285 return;
286 }
287
288#if defined (TRACING)
289 if (trace_record ()) {
290 /* Connection registration packet:
291
292 int32_t index
293 int32_t listener_index [-1 means no listener]
294 u_int16_t remote_port
295 u_int16_t local_port
296 u_int32_t remote_addr
297 u_int32_t local_addr */
298
299 connect_index = htonl (index);
300 index++;
301 if (obj -> listener)
302 listener_index = htonl (obj -> listener -> index);
303 else
304 listener_index = htonl (-1);
305 iov [iov_count].buf = (char *)&connect_index;
306 iov [iov_count++].len = sizeof connect_index;
307 iov [iov_count].buf = (char *)&listener_index;
308 iov [iov_count++].len = sizeof listener_index;
309 iov [iov_count].buf = (char *)&obj -> remote_addr.sin_port;
310 iov [iov_count++].len = sizeof obj -> remote_addr.sin_port;
311 iov [iov_count].buf = (char *)&obj -> local_addr.sin_port;
312 iov [iov_count++].len = sizeof obj -> local_addr.sin_port;
313 iov [iov_count].buf = (char *)&obj -> remote_addr.sin_addr;
314 iov [iov_count++].len = sizeof obj -> remote_addr.sin_addr;
315 iov [iov_count].buf = (char *)&obj -> local_addr.sin_addr;
316 iov [iov_count++].len = sizeof obj -> local_addr.sin_addr;
317
318 status = trace_write_packet_iov (trace_connect,
319 iov_count, iov, file, line);
320 }
321#endif
322}
323
324static void trace_connect_input (trace_type_t *ttype,
325 unsigned length, char *buf)
326{
327 struct sockaddr_in remote, local;
328 int32_t connect_index, listener_index;
329 char *s = buf;
331 isc_result_t status;
332 int i;
333
334 if (length != ((sizeof connect_index) +
335 (sizeof remote.sin_port) +
336 (sizeof remote.sin_addr)) * 2) {
337 log_error ("Trace connect: invalid length %d", length);
338 return;
339 }
340
341 memset (&remote, 0, sizeof remote);
342 memset (&local, 0, sizeof local);
343 memcpy (&connect_index, s, sizeof connect_index);
344 s += sizeof connect_index;
345 memcpy (&listener_index, s, sizeof listener_index);
346 s += sizeof listener_index;
347 memcpy (&remote.sin_port, s, sizeof remote.sin_port);
348 s += sizeof remote.sin_port;
349 memcpy (&local.sin_port, s, sizeof local.sin_port);
350 s += sizeof local.sin_port;
351 memcpy (&remote.sin_addr, s, sizeof remote.sin_addr);
352 s += sizeof remote.sin_addr;
353 memcpy (&local.sin_addr, s, sizeof local.sin_addr);
354 s += sizeof local.sin_addr;
355 POST(s);
356
357 connect_index = ntohl (connect_index);
358 listener_index = ntohl (listener_index);
359
360 /* If this was a connect to a listener, then we just slap together
361 a new connection. */
362 if (listener_index != -1) {
363 omapi_listener_object_t *listener;
364 listener = (omapi_listener_object_t *)0;
365 omapi_array_foreach_begin (trace_listeners,
367 if (lp -> address.sin_port == local.sin_port) {
368 omapi_listener_reference (&listener, lp, MDL);
369 omapi_listener_dereference (&lp, MDL);
370 break;
371 }
372 } omapi_array_foreach_end (trace_listeners,
374 if (!listener) {
375 log_error ("%s%ld, addr %s, port %d",
376 "Spurious traced listener connect - index ",
377 (long int)listener_index,
378 inet_ntoa (local.sin_addr),
379 ntohs (local.sin_port));
380 return;
381 }
382 obj = (omapi_connection_object_t *)0;
383 status = omapi_listener_connect (&obj, listener, -1, &remote);
384 if (status != ISC_R_SUCCESS) {
385 log_error ("traced listener connect: %s",
386 isc_result_totext (status));
387 }
388 if (obj)
389 omapi_connection_dereference (&obj, MDL);
390 omapi_listener_dereference (&listener, MDL);
391 return;
392 }
393
394 /* Find the matching connect object, if there is one. */
395 omapi_array_foreach_begin (omapi_connections,
397 for (i = 0; (lp->connect_list &&
398 i < lp->connect_list->count); i++) {
399 if (!memcmp (&remote.sin_addr,
400 &lp->connect_list->addresses[i].address,
401 sizeof remote.sin_addr) &&
402 (ntohs (remote.sin_port) ==
403 lp->connect_list->addresses[i].port)) {
404 lp->state = omapi_connection_connected;
405 lp->remote_addr = remote;
406 lp->remote_addr.sin_family = AF_INET;
407 omapi_addr_list_dereference(&lp->connect_list, MDL);
408 lp->index = connect_index;
409 status = omapi_signal_in((omapi_object_t *)lp,
410 "connect");
411 omapi_connection_dereference (&lp, MDL);
412 return;
413 }
414 }
415 } omapi_array_foreach_end (omapi_connections,
417
418 log_error ("Spurious traced connect - index %ld, addr %s, port %d",
419 (long int)connect_index, inet_ntoa (remote.sin_addr),
420 ntohs (remote.sin_port));
421 return;
422}
423
424static void trace_connect_stop (trace_type_t *ttype) { }
425
426static void trace_disconnect_input (trace_type_t *ttype,
427 unsigned length, char *buf)
428{
429 int32_t *index;
430 if (length != sizeof *index) {
431 log_error ("trace disconnect: wrong length %d", length);
432 return;
433 }
434
435 index = (int32_t *)buf;
436
437 omapi_array_foreach_begin (omapi_connections,
439 if (lp -> index == ntohl (*index)) {
441 omapi_connection_dereference (&lp, MDL);
442 return;
443 }
444 } omapi_array_foreach_end (omapi_connections,
446
447 log_error ("trace disconnect: no connection matching index %ld",
448 (long int)ntohl (*index));
449}
450
451static void trace_disconnect_stop (trace_type_t *ttype) { }
452#endif
453
454/* Disconnect a connection object from the remote end. If force is nonzero,
455 close the connection immediately. Otherwise, shut down the receiving end
456 but allow any unsent data to be sent before actually closing the socket. */
457
459 int force)
460{
462
463#ifdef DEBUG_PROTOCOL
464 log_debug ("omapi_disconnect(force=%d)", force);
465#endif
466
468 if (c -> type != omapi_type_connection)
469 return DHCP_R_INVALIDARG;
470
471#if defined (TRACING)
472 if (trace_record ()) {
473 isc_result_t status;
474 int32_t index;
475
476 index = htonl (c -> index);
477 status = trace_write_packet (trace_disconnect,
478 sizeof index, (char *)&index,
479 MDL);
480 if (status != ISC_R_SUCCESS) {
481 trace_stop ();
482 log_error ("trace_write_packet: %s",
483 isc_result_totext (status));
484 }
485 }
486 if (!trace_playback ()) {
487#endif
488 if (!force) {
489 /* If we're already disconnecting, we don't have to do
490 anything. */
491 if (c -> state == omapi_connection_disconnecting)
492 return ISC_R_SUCCESS;
493
494 /* Try to shut down the socket - this sends a FIN to
495 the remote end, so that it won't send us any more
496 data. If the shutdown succeeds, and we still
497 have bytes left to write, defer closing the socket
498 until that's done. */
499 if (!shutdown (c -> socket, SHUT_RD)) {
500 if (c -> out_bytes > 0) {
501 c -> state =
503 return ISC_R_SUCCESS;
504 }
505 }
506 }
507 close (c -> socket);
508#if defined (TRACING)
509 }
510#endif
511 c -> state = omapi_connection_closed;
512
513#if 0
514 /*
515 * Disconnecting from the I/O object seems incorrect as it doesn't
516 * cause the I/O object to be cleaned and released. Previous to
517 * using the isc socket library this wouldn't have caused a problem
518 * with the socket library we would have a reference to a closed
519 * socket. Instead we now do an unregister to properly free the
520 * I/O object.
521 */
522
523 /* Disconnect from I/O object, if any. */
524 if (h -> outer) {
525 if (h -> outer -> inner)
526 omapi_object_dereference (&h -> outer -> inner, MDL);
527 omapi_object_dereference (&h -> outer, MDL);
528 }
529#else
530 if (h->outer) {
532 }
533#endif
534
535 /* If whatever created us registered a signal handler, send it
536 a disconnect signal. */
537 omapi_signal (h, "disconnect", h);
538
539 /* Disconnect from protocol object, if any. */
540 if (h->inner != NULL) {
541 if (h->inner->outer != NULL) {
542 omapi_object_dereference(&h->inner->outer, MDL);
543 }
544 omapi_object_dereference(&h->inner, MDL);
545 }
546
547 /* XXX: the code to free buffers should be in the dereference
548 function, but there is no special-purpose function to
549 dereference connections, so these just get leaked */
550 /* Free any buffers */
551 if (c->inbufs != NULL) {
553 }
554 c->in_bytes = 0;
555 if (c->outbufs != NULL) {
557 }
558 c->out_bytes = 0;
559
560 return ISC_R_SUCCESS;
561}
562
563isc_result_t omapi_connection_require (omapi_object_t *h, unsigned bytes)
564{
566
567 if (h -> type != omapi_type_connection)
568 return DHCP_R_INVALIDARG;
570
571 c -> bytes_needed = bytes;
572 if (c -> bytes_needed <= c -> in_bytes) {
573 return ISC_R_SUCCESS;
574 }
575 return DHCP_R_NOTYET;
576}
577
578/* Return the socket on which the dispatcher should wait for readiness
579 to read, for a connection object. */
581{
583 if (h -> type != omapi_type_connection)
584 return -1;
586 if (c -> state != omapi_connection_connected)
587 return -1;
588 return c -> socket;
589}
590
591/*
592 * Return the socket on which the dispatcher should wait for readiness
593 * to write, for a connection object. When bytes are buffered we should
594 * also poke the dispatcher to tell it to start or re-start watching the
595 * socket.
596 */
598{
600 if (h -> type != omapi_type_connection)
601 return -1;
603 return c->socket;
604}
605
607{
608 isc_result_t status;
609
610 /*
611 * We use the INPROGRESS status to indicate that
612 * we want more from the socket. In this case we
613 * have now connected and are trying to write to
614 * the socket for the first time. For the signaling
615 * code this is the same as a SUCCESS so we don't
616 * pass it on as a signal.
617 */
618 status = omapi_connection_connect_internal (h);
619 if (status == ISC_R_INPROGRESS)
620 return ISC_R_INPROGRESS;
621
622 if (status != ISC_R_SUCCESS)
623 omapi_signal (h, "status", status);
624
625 return ISC_R_SUCCESS;
626}
627
628static isc_result_t omapi_connection_connect_internal (omapi_object_t *h)
629{
630 int error = 0;
632 socklen_t sl;
633 isc_result_t status;
634
635 if (h -> type != omapi_type_connection)
636 return DHCP_R_INVALIDARG;
638
639 if (c -> state == omapi_connection_connecting) {
640 sl = sizeof error;
641 if (getsockopt (c -> socket, SOL_SOCKET, SO_ERROR,
642 (char *)&error, &sl) < 0) {
643 omapi_disconnect (h, 1);
644 return ISC_R_SUCCESS;
645 }
646 if (!error)
647 c -> state = omapi_connection_connected;
648 }
649 if (c -> state == omapi_connection_connecting ||
650 c -> state == omapi_connection_unconnected) {
651 if (c -> cptr >= c -> connect_list -> count) {
652 switch (error) {
653 case ECONNREFUSED:
654 status = ISC_R_CONNREFUSED;
655 break;
656 case ENETUNREACH:
657 status = ISC_R_NETUNREACH;
658 break;
659 default:
660 status = uerr2isc (error);
661 break;
662 }
663 omapi_disconnect (h, 1);
664 return status;
665 }
666
667 if (c -> connect_list -> addresses [c -> cptr].addrtype !=
668 AF_INET) {
669 omapi_disconnect (h, 1);
670 return DHCP_R_INVALIDARG;
671 }
672
673 memcpy (&c -> remote_addr.sin_addr,
674 &c -> connect_list -> addresses [c -> cptr].address,
675 sizeof c -> remote_addr.sin_addr);
676 c -> remote_addr.sin_family = AF_INET;
677 c -> remote_addr.sin_port =
678 htons (c -> connect_list -> addresses [c -> cptr].port);
679#if defined (HAVE_SA_LEN)
680 c -> remote_addr.sin_len = sizeof c -> remote_addr;
681#endif
682 memset (&c -> remote_addr.sin_zero, 0,
683 sizeof c -> remote_addr.sin_zero);
684 ++c -> cptr;
685
686 error = connect (c -> socket,
687 (struct sockaddr *)&c -> remote_addr,
688 sizeof c -> remote_addr);
689 if (error < 0) {
690 error = errno;
691 if (error != EINPROGRESS) {
692 omapi_disconnect (h, 1);
693 switch (error) {
694 case ECONNREFUSED:
695 status = ISC_R_CONNREFUSED;
696 break;
697 case ENETUNREACH:
698 status = ISC_R_NETUNREACH;
699 break;
700 default:
701 status = uerr2isc (error);
702 break;
703 }
704 return status;
705 }
706 c -> state = omapi_connection_connecting;
707 return DHCP_R_INCOMPLETE;
708 }
709 c -> state = omapi_connection_connected;
710 }
711
712 /* I don't know why this would fail, so I'm tempted not to test
713 the return value. */
714 sl = sizeof (c -> local_addr);
715 if (getsockname (c -> socket,
716 (struct sockaddr *)&c -> local_addr, &sl) < 0) {
717 }
718
719 /* Reregister with the I/O object. If we don't already have an
720 I/O object this turns into a register call, otherwise we simply
721 modify the pointers in the I/O object. */
722
723 status = omapi_reregister_io_object (h,
729
730 if (status != ISC_R_SUCCESS) {
731 omapi_disconnect (h, 1);
732 return status;
733 }
734
735 omapi_signal_in (h, "connect");
736 omapi_addr_list_dereference (&c -> connect_list, MDL);
737 return ISC_R_INPROGRESS;
738}
739
740/* Reaper function for connection - if the connection is completely closed,
741 reap it. If it's in the disconnecting state, there were bytes left
742 to write when the user closed it, so if there are now no bytes left to
743 write, we can close it. */
745{
747
748 if (h -> type != omapi_type_connection)
749 return DHCP_R_INVALIDARG;
750
752 if (c -> state == omapi_connection_disconnecting &&
753 c -> out_bytes == 0) {
754#ifdef DEBUG_PROTOCOL
755 log_debug ("omapi_connection_reaper(): disconnect");
756#endif
757 omapi_disconnect (h, 1);
758 }
759 if (c -> state == omapi_connection_closed) {
760#ifdef DEBUG_PROTOCOL
761 log_debug ("omapi_connection_reaper(): closed");
762#endif
763 return ISC_R_NOTCONNECTED;
764 }
765 return ISC_R_SUCCESS;
766}
767
768static isc_result_t make_dst_key (dst_key_t **dst_key, omapi_object_t *a) {
769 omapi_value_t *key = 0;
770 char *name_str = 0;
771 char *algorithm_str = 0;
772 isc_result_t status = ISC_R_SUCCESS;
773
774 /* Get the key name as a C string. */
775 status = ctring_from_attribute(a, "name", &name_str);
776 if (status == ISC_R_SUCCESS) {
777 /* Get the algorithm name as a C string. */
778 status = ctring_from_attribute(a, "algorithm", &algorithm_str);
779 if (status == ISC_R_SUCCESS) {
780 /* Get the key secret value */
781 status = omapi_get_value_str(a, 0, "key", &key);
782 if (status == ISC_R_SUCCESS) {
783 /* Now let's try and create the key */
784 status = isclib_make_dst_key(
785 name_str,
786 algorithm_str,
787 key->value->u.buffer.value,
788 key->value->u.buffer.len,
789 dst_key);
790
791 if (*dst_key == NULL) {
792 status = ISC_R_NOMEMORY;
793 }
794 }
795 }
796 }
797
798 if (name_str)
799 dfree (name_str, MDL);
800 if (algorithm_str)
801 dfree (algorithm_str, MDL);
802 if (key)
804
805 return status;
806}
807
808isc_result_t omapi_connection_sign_data (int mode,
809 dst_key_t *key,
810 void **context,
811 const unsigned char *data,
812 const unsigned len,
813 omapi_typed_data_t **result)
814{
816 isc_result_t status;
817 dst_context_t **dctx = (dst_context_t **)context;
818
819 /* Create the context for the dst module */
820 if (mode & SIG_MODE_INIT) {
821 status = dst_context_create(key, dhcp_gbl_ctx.mctx, dctx);
822 if (status != ISC_R_SUCCESS) {
823 return status;
824 }
825 }
826
827 /* If we have any data add it to the context */
828 if (len != 0) {
829 isc_region_t region;
830 region.base = (unsigned char *)data;
831 region.length = len;
832 dst_context_adddata(*dctx, &region);
833 }
834
835 /* Finish the signature and clean up the context */
836 if (mode & SIG_MODE_FINAL) {
837 unsigned int sigsize;
838 isc_buffer_t sigbuf;
839
840 status = dst_key_sigsize(key, &sigsize);
841 if (status != ISC_R_SUCCESS) {
842 goto cleanup;
843 }
844
845 status = omapi_typed_data_new (MDL, &td,
847 sigsize);
848 if (status != ISC_R_SUCCESS) {
849 goto cleanup;
850 }
851
852 isc_buffer_init(&sigbuf, td->u.buffer.value, td->u.buffer.len);
853 status = dst_context_sign(*dctx, &sigbuf);
854 if (status != ISC_R_SUCCESS) {
855 goto cleanup;
856 }
857
858 if (result) {
859 omapi_typed_data_reference (result, td, MDL);
860 }
861
862 cleanup:
863 /* We are done with the context and the td. On success
864 * the td is now referenced from result, on failure we
865 * don't need it any more */
866 if (td) {
868 }
869 dst_context_destroy(dctx);
870 return status;
871 }
872
873 return ISC_R_SUCCESS;
874}
875
877 unsigned *l)
878{
880
881 if (h->type != omapi_type_connection)
882 return DHCP_R_INVALIDARG;
884
885 if (c->out_key == NULL)
886 return ISC_R_NOTFOUND;
887
888 return(dst_key_sigsize(c->out_key, l));
889}
890
892 omapi_object_t *id,
895{
897 isc_result_t status;
898
899 if (h -> type != omapi_type_connection)
900 return DHCP_R_INVALIDARG;
902
903 if (omapi_ds_strcmp (name, "input-authenticator") == 0) {
904 if (value && value -> type != omapi_datatype_object)
905 return DHCP_R_INVALIDARG;
906
907 if (c -> in_context) {
909 c -> in_key,
910 &c -> in_context,
911 0, 0,
912 (omapi_typed_data_t **) 0);
913 }
914
915 if (c->in_key != NULL) {
916 dst_key_free(&c->in_key);
917 }
918
919 if (value) {
920 status = make_dst_key (&c -> in_key,
921 value -> u.object);
922 if (status != ISC_R_SUCCESS)
923 return status;
924 }
925
926 return ISC_R_SUCCESS;
927 }
928 else if (omapi_ds_strcmp (name, "output-authenticator") == 0) {
929 if (value && value -> type != omapi_datatype_object)
930 return DHCP_R_INVALIDARG;
931
932 if (c -> out_context) {
934 c -> out_key,
935 &c -> out_context,
936 0, 0,
937 (omapi_typed_data_t **) 0);
938 }
939
940 if (c->out_key != NULL) {
941 dst_key_free(&c->out_key);
942 }
943
944 if (value) {
945 status = make_dst_key (&c -> out_key,
946 value -> u.object);
947 if (status != ISC_R_SUCCESS)
948 return status;
949 }
950
951 return ISC_R_SUCCESS;
952 }
953
954 if (h -> inner && h -> inner -> type -> set_value)
955 return (*(h -> inner -> type -> set_value))
956 (h -> inner, id, name, value);
957 return ISC_R_NOTFOUND;
958}
959
961 omapi_object_t *id,
964{
967 isc_result_t status;
968 unsigned int sigsize;
969
970 if (h -> type != omapi_type_connection)
971 return DHCP_R_INVALIDARG;
973
974 if (omapi_ds_strcmp (name, "input-signature") == 0) {
975 if (!c -> in_key || !c -> in_context)
976 return ISC_R_NOTFOUND;
977
979 c -> in_key,
980 &c -> in_context,
981 0, 0, &td);
982 if (status != ISC_R_SUCCESS)
983 return status;
984
985 status = omapi_make_value (value, name, td, MDL);
987 return status;
988
989 } else if (omapi_ds_strcmp (name, "input-signature-size") == 0) {
990 if (c->in_key == NULL)
991 return ISC_R_NOTFOUND;
992
993 status = dst_key_sigsize(c->in_key, &sigsize);
994 if (status != ISC_R_SUCCESS) {
995 return(status);
996 }
997
998 return omapi_make_int_value(value, name, sigsize, MDL);
999
1000 } else if (omapi_ds_strcmp (name, "output-signature") == 0) {
1001 if (!c -> out_key || !c -> out_context)
1002 return ISC_R_NOTFOUND;
1003
1005 c -> out_key,
1006 &c -> out_context,
1007 0, 0, &td);
1008 if (status != ISC_R_SUCCESS)
1009 return status;
1010
1011 status = omapi_make_value (value, name, td, MDL);
1013 return status;
1014
1015 } else if (omapi_ds_strcmp (name, "output-signature-size") == 0) {
1016 if (c->out_key == NULL)
1017 return ISC_R_NOTFOUND;
1018
1019
1020 status = dst_key_sigsize(c->out_key, &sigsize);
1021 if (status != ISC_R_SUCCESS) {
1022 return(status);
1023 }
1024
1025 return omapi_make_int_value(value, name, sigsize, MDL);
1026 }
1027
1028 if (h -> inner && h -> inner -> type -> get_value)
1029 return (*(h -> inner -> type -> get_value))
1030 (h -> inner, id, name, value);
1031 return ISC_R_NOTFOUND;
1032}
1033
1035 const char *file, int line)
1036{
1038
1039#ifdef DEBUG_PROTOCOL
1040 log_debug ("omapi_connection_destroy()");
1041#endif
1042
1043 if (h -> type != omapi_type_connection)
1044 return ISC_R_UNEXPECTED;
1045 c = (omapi_connection_object_t *)(h);
1046 if (c -> state == omapi_connection_connected)
1047 omapi_disconnect (h, 1);
1048 if (c -> listener)
1049 omapi_listener_dereference (&c -> listener, file, line);
1050 if (c -> connect_list)
1051 omapi_addr_list_dereference (&c -> connect_list, file, line);
1052 return ISC_R_SUCCESS;
1053}
1054
1056 const char *name, va_list ap)
1057{
1058 if (h -> type != omapi_type_connection)
1059 return DHCP_R_INVALIDARG;
1060
1061#ifdef DEBUG_PROTOCOL
1062 log_debug ("omapi_connection_signal_handler(%s)", name);
1063#endif
1064
1065 if (h -> inner && h -> inner -> type -> signal_handler)
1066 return (*(h -> inner -> type -> signal_handler)) (h -> inner,
1067 name, ap);
1068 return ISC_R_NOTFOUND;
1069}
1070
1071/* Write all the published values associated with the object through the
1072 specified connection. */
1073
1075 omapi_object_t *id,
1076 omapi_object_t *m)
1077{
1078 if (m -> type != omapi_type_connection)
1079 return DHCP_R_INVALIDARG;
1080
1081 if (m -> inner && m -> inner -> type -> stuff_values)
1082 return (*(m -> inner -> type -> stuff_values)) (c, id,
1083 m -> inner);
1084 return ISC_R_SUCCESS;
1085}
1086
1087/* @brief Fetches the value of an attribute in an object as an allocated
1088 * C string
1089 *
1090 * @param obj ompapi object containing the desire attribute
1091 * @param attr_name name of the desired attribute
1092 * @param[out] cstr pointer in which to place the allocated C string's address
1093 *
1094 * Caller is responsible for freeing (via dfree) the allocated string.
1095 *
1096 * @return ISC_R_SUCCESS if successful, otherwise indicates the type of failure
1097*/
1098static isc_result_t ctring_from_attribute(omapi_object_t *obj, char *attr_name,
1099 char **cstr) {
1100 isc_result_t status = ISC_R_SUCCESS;
1101 omapi_value_t *attr = 0;
1102
1103 /* Find the attribute in the object. */
1104 status = omapi_get_value_str(obj, (omapi_object_t *)0, attr_name,
1105 &attr);
1106 if (status != ISC_R_SUCCESS) {
1107 return (status);
1108 }
1109
1110 /* Got it, let's make sure it's either data or string type. */
1111 if (attr->value->type != omapi_datatype_data &&
1112 attr->value->type != omapi_datatype_string) {
1113 return (DHCP_R_INVALIDARG);
1114 }
1115
1116 /* Make a C string from the attribute value. */
1117 *cstr = dmalloc (attr->value->u.buffer.len + 1, MDL);
1118 if (!(*cstr)) {
1119 status = ISC_R_NOMEMORY;
1120 } else {
1121 memcpy (*cstr, attr->value->u.buffer.value,
1122 attr->value->u.buffer.len);
1123 (*cstr)[attr->value->u.buffer.len] = 0;
1124 }
1125
1126 /* Get rid of the attribute reference */
1127 if (attr) {
1129 }
1130
1131 return (status);
1132}
isc_result_t omapi_buffer_dereference(omapi_buffer_t **, const char *, int)
Definition alloc.c:766
isc_result_t omapi_connection_destroy(omapi_object_t *h, const char *file, int line)
int omapi_connection_readfd(omapi_object_t *h)
Definition connection.c:580
isc_result_t omapi_connection_connect(omapi_object_t *h)
Definition connection.c:606
isc_result_t omapi_connection_set_value(omapi_object_t *h, omapi_object_t *id, omapi_data_string_t *name, omapi_typed_data_t *value)
Definition connection.c:891
isc_result_t omapi_connection_reaper(omapi_object_t *h)
Definition connection.c:744
isc_result_t omapi_connect_list(omapi_object_t *c, omapi_addr_list_t *remote_addrs, omapi_addr_t *local_addr)
Definition connection.c:104
isc_result_t omapi_connection_signal_handler(omapi_object_t *h, const char *name, va_list ap)
isc_result_t omapi_connection_output_auth_length(omapi_object_t *h, unsigned *l)
Definition connection.c:876
isc_result_t omapi_connection_sign_data(int mode, dst_key_t *key, void **context, const unsigned char *data, const unsigned len, omapi_typed_data_t **result)
Definition connection.c:808
isc_result_t omapi_connection_get_value(omapi_object_t *h, omapi_object_t *id, omapi_data_string_t *name, omapi_value_t **value)
Definition connection.c:960
isc_result_t omapi_connection_require(omapi_object_t *h, unsigned bytes)
Definition connection.c:563
isc_result_t omapi_connection_stuff_values(omapi_object_t *c, omapi_object_t *id, omapi_object_t *m)
int omapi_connection_writefd(omapi_object_t *h)
Definition connection.c:597
isc_result_t omapi_disconnect(omapi_object_t *h, int force)
Definition connection.c:458
const char int line
Definition dhcpd.h:3802
void cleanup(void)
const char * file
Definition dhcpd.h:3802
dhcp_context_t dhcp_gbl_ctx
Definition isclib.c:33
isc_result_t isclib_make_dst_key(char *inname, char *algorithm, unsigned char *secret, int length, dst_key_t **dstkey)
Definition isclib.c:332
#define ISC_R_SUCCESS
isc_result_t omapi_value_dereference(omapi_value_t **, const char *, int)
Definition alloc.c:1060
#define MDL
Definition omapip.h:567
#define omapi_array_foreach_begin(array, stype, var)
Definition omapip.h:242
isc_result_t omapi_typed_data_reference(omapi_typed_data_t **, omapi_typed_data_t *, const char *, int)
Definition alloc.c:880
#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_unregister_io_object(omapi_object_t *)
Definition dispatch.c:355
isc_result_t omapi_connection_reader(omapi_object_t *)
Definition buffer.c:131
isc_result_t omapi_addr_list_dereference(omapi_addr_list_t **, const char *, int)
Definition alloc.c:1142
isc_result_t omapi_make_value(omapi_value_t **, omapi_data_string_t *, omapi_typed_data_t *, const char *, int)
Definition support.c:651
isc_result_t omapi_addr_list_reference(omapi_addr_list_t **, omapi_addr_list_t *, const char *, int)
Definition alloc.c:1120
struct __omapi_object omapi_object_t
Definition omapip.h:39
isc_result_t omapi_connection_writer(omapi_object_t *)
Definition buffer.c:448
isc_result_t omapi_connection_reaper(omapi_object_t *)
Definition connection.c:744
isc_result_t omapi_connect(omapi_object_t *, const char *, unsigned)
@ omapi_datatype_string
Definition omapip.h:43
@ omapi_datatype_object
Definition omapip.h:45
@ omapi_datatype_data
Definition omapip.h:44
isc_result_t omapi_typed_data_dereference(omapi_typed_data_t **, const char *, int)
Definition alloc.c:901
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_in(omapi_object_t *, const char *,...)
Definition support.c:285
isc_result_t omapi_signal(omapi_object_t *, const char *,...)
Definition support.c:267
isc_result_t omapi_reregister_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:305
isc_result_t omapi_addr_list_new(omapi_addr_list_t **, unsigned, const char *, int)
Definition alloc.c:1104
#define omapi_array_foreach_end(array, stype, var)
Definition omapip.h:256
int omapi_ds_strcmp(omapi_data_string_t *, const char *)
Definition support.c:581
omapi_object_type_t * omapi_type_connection
Definition support.c:33
isc_result_t omapi_typed_data_new(const char *, int, omapi_typed_data_t **, omapi_datatype_t,...)
Definition alloc.c:803
void * dmalloc(size_t, const char *, int)
Definition alloc.c:57
#define OMAPI_ARRAY_TYPE(name, stype)
Definition omapip.h:197
void dfree(void *, const char *, int)
Definition alloc.c:145
isc_result_t omapi_get_value_str(omapi_object_t *, omapi_object_t *, const char *, omapi_value_t **)
Definition support.c:482
isc_result_t omapi_connection_connect(omapi_object_t *)
Definition connection.c:606
isc_result_t omapi_make_int_value(omapi_value_t **, omapi_data_string_t *, int, const char *, int)
Definition support.c:709
isc_result_t uerr2isc(int)
Definition toisc.c:37
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
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
#define SIG_MODE_FINAL
Definition omapip_p.h:75
void omapi_connection_trace_setup(void)
struct __omapi_listener_object omapi_listener_object_t
Definition omapip_p.h:253
#define SIG_MODE_INIT
Definition omapip_p.h:73
void omapi_connection_register(omapi_connection_object_t *, const char *, int)
@ omapi_connection_unconnected
Definition omapip_p.h:99
@ omapi_connection_connected
Definition omapip_p.h:101
@ omapi_connection_disconnecting
Definition omapip_p.h:102
@ omapi_connection_closed
Definition omapip_p.h:103
@ omapi_connection_connecting
Definition omapip_p.h:100
#define SHUT_RD
Definition osdep.h:276
#define DHCP_R_INVALIDARG
Definition result.h:49
#define DHCP_R_NOTYET
Definition result.h:50
#define DHCP_R_INCOMPLETE
Definition result.h:58
#define DHCP_R_HOSTUNKNOWN
Definition result.h:46
omapi_buffer_t * outbufs
Definition omapip_p.h:194
omapi_buffer_t * inbufs
Definition omapip_p.h:192
struct omapi_typed_data_t::@005330231110240362320041053235346164005276246221::@131374275124060200224243254021133345104025056044 buffer
omapi_datatype_t type
Definition omapip.h:50
unsigned char value[1]
Definition omapip.h:57
union omapi_typed_data_t::@005330231110240362320041053235346164005276246221 u
unsigned len
Definition omapip.h:53
omapi_typed_data_t * value
Definition omapip.h:90
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)
isc_result_t trace_write_packet(trace_type_t *, unsigned, const char *, 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)
void trace_stop(void)
int trace_playback(void)
Definition data.h:205