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