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