ISC DHCP  4.4.2b1
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,
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,
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 }
omapi_connection_writefd
int omapi_connection_writefd(omapi_object_t *h)
Definition: connection.c:594
__omapi_connection_object::in_bytes
u_int32_t in_bytes
Definition: omapip_p.h:188
dhcp_context::mctx
isc_mem_t * mctx
Definition: isclib.h:95
omapi_object_reference
isc_result_t omapi_object_reference(omapi_object_t **, omapi_object_t *, const char *, int)
Definition: alloc.c:571
omapi_addr_list_new
isc_result_t omapi_addr_list_new(omapi_addr_list_t **, unsigned, const char *, int)
Definition: alloc.c:1104
omapip_p.h
__omapi_connection_object::out_key
dst_key_t * out_key
Definition: omapip_p.h:197
omapi_listener_connect
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
nameser.h
line
const char int line
Definition: dhcpd.h:3793
trace_write_packet
isc_result_t trace_write_packet(trace_type_t *, unsigned, const char *, const char *, int)
omapi_typed_data_new
isc_result_t omapi_typed_data_new(const char *, int, omapi_typed_data_t **, omapi_datatype_t,...)
Definition: alloc.c:803
omapi_buffer_dereference
isc_result_t omapi_buffer_dereference(omapi_buffer_t **, const char *, int)
Definition: alloc.c:766
NS_TSIG_ALG_HMAC_MD5
#define NS_TSIG_ALG_HMAC_MD5
Definition: nameser.h:214
isclib_make_dst_key
isc_result_t isclib_make_dst_key(char *inname, char *algorithm, unsigned char *secret, int length, dst_key_t **dstkey)
Definition: isclib.c:332
dhcpd.h
omapi_data_string_t
Definition: omapip.h:80
omapi_connection_set_value
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
trace_stop
void trace_stop(void)
uerr2isc
isc_result_t uerr2isc(int)
Definition: toisc.c:37
trace_type_register
trace_type_t * trace_type_register(const char *, void *, void(*)(trace_type_t *, unsigned, char *), void(*)(trace_type_t *), const char *, int)
omapi_register_io_object
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
omapi_connection_connect
isc_result_t omapi_connection_connect(omapi_object_t *h)
Definition: connection.c:603
OMAPI_OBJECT_ALLOC
OMAPI_OBJECT_ALLOC(omapi_connection, omapi_connection_object_t, omapi_type_connection)
Definition: connection.c:47
omapi_make_int_value
isc_result_t omapi_make_int_value(omapi_value_t **, omapi_data_string_t *, int, const char *, int)
Definition: support.c:709
value
Definition: data.h:205
omapi_connection_register
void omapi_connection_register(omapi_connection_object_t *, const char *, int)
omapi_addr_list_t
Definition: omapip.h:141
__omapi_connection_object::inbufs
omapi_buffer_t * inbufs
Definition: omapip_p.h:189
omapi_connection_reader
isc_result_t omapi_connection_reader(omapi_object_t *)
Definition: buffer.c:131
cleanup
void cleanup(void)
omapi_connection_trace_setup
void omapi_connection_trace_setup(void)
DHCP_R_HOSTUNKNOWN
#define DHCP_R_HOSTUNKNOWN
Definition: result.h:46
omapi_addr_list_dereference
isc_result_t omapi_addr_list_dereference(omapi_addr_list_t **, const char *, int)
Definition: alloc.c:1142
omapi_typed_data_reference
isc_result_t omapi_typed_data_reference(omapi_typed_data_t **, omapi_typed_data_t *, const char *, int)
Definition: alloc.c:880
omapi_array_t
Definition: omapip.h:189
omapi_typed_data_t::u
union omapi_typed_data_t::@3 u
dhcp_gbl_ctx
dhcp_context_t dhcp_gbl_ctx
Definition: isclib.c:33
omapi_disconnect
isc_result_t omapi_disconnect(omapi_object_t *h, int force)
Definition: connection.c:455
trace_iov::len
unsigned len
Definition: trace.h:76
DHCP_R_NOTYET
#define DHCP_R_NOTYET
Definition: result.h:50
trace_write_packet_iov
isc_result_t trace_write_packet_iov(trace_type_t *, int, trace_iov_t *, const char *, int)
omapi_signal_in
isc_result_t omapi_signal_in(omapi_object_t *, const char *,...)
Definition: support.c:285
omapi_object_dereference
isc_result_t omapi_object_dereference(omapi_object_t **, const char *, int)
Definition: alloc.c:593
dfree
void dfree(void *, const char *, int)
Definition: alloc.c:145
MDL
#define MDL
Definition: omapip.h:567
omapi_connection_unconnected
Definition: omapip_p.h:96
omapi_connection_stuff_values
isc_result_t omapi_connection_stuff_values(omapi_object_t *c, omapi_object_t *id, omapi_object_t *m)
Definition: connection.c:1094
omapi_connect_list
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
omapi_array_foreach_begin
#define omapi_array_foreach_begin(array, stype, var)
Definition: omapip.h:242
log_error
int log_error(const char *,...) __attribute__((__format__(__printf__
omapi_connection_connected
Definition: omapip_p.h:98
omapi_make_value
isc_result_t omapi_make_value(omapi_value_t **, omapi_data_string_t *, omapi_typed_data_t *, const char *, int)
Definition: support.c:651
omapi_ds_strcmp
int omapi_ds_strcmp(omapi_data_string_t *, const char *)
Definition: support.c:581
trace_playback
int trace_playback(void)
omapi_typed_data_dereference
isc_result_t omapi_typed_data_dereference(omapi_typed_data_t **, const char *, int)
Definition: alloc.c:901
omapi_value_dereference
isc_result_t omapi_value_dereference(omapi_value_t **, const char *, int)
Definition: alloc.c:1060
omapi_connection_sign_data
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
trace_iov
Definition: trace.h:74
omapi_addr_list_reference
isc_result_t omapi_addr_list_reference(omapi_addr_list_t **, omapi_addr_list_t *, const char *, int)
Definition: alloc.c:1120
file
const char * file
Definition: dhcpd.h:3793
omapi_datatype_string
Definition: omapip.h:43
omapi_datatype_data
Definition: omapip.h:44
omapi_connection_require
isc_result_t omapi_connection_require(omapi_object_t *h, unsigned bytes)
Definition: connection.c:560
omapi_connection_connecting
Definition: omapip_p.h:97
omapi_array_foreach_end
#define omapi_array_foreach_end(array, stype, var)
Definition: omapip.h:256
trace_record
int trace_record(void)
SIG_MODE_INIT
#define SIG_MODE_INIT
Definition: omapip_p.h:70
SHUT_RD
#define SHUT_RD
Definition: osdep.h:276
omapi_signal
isc_result_t omapi_signal(omapi_object_t *, const char *,...)
Definition: support.c:267
__omapi_connection_object::outbufs
omapi_buffer_t * outbufs
Definition: omapip_p.h:191
__omapi_connection_object::socket
int socket
Definition: omapip_p.h:179
__omapi_listener_object
Definition: omapip_p.h:169
omapi_connect
isc_result_t omapi_connect(omapi_object_t *, const char *, unsigned)
omapi_typed_data_t
Definition: omapip.h:48
omapi_connection_writer
isc_result_t omapi_connection_writer(omapi_object_t *)
Definition: buffer.c:448
trace_type
Definition: trace.h:65
omapi_typed_data_t::buffer
struct omapi_typed_data_t::@3::@4 buffer
__omapi_connection_object::in_key
dst_key_t * in_key
Definition: omapip_p.h:194
omapi_connection_disconnecting
Definition: omapip_p.h:99
OMAPI_ARRAY_TYPE
#define OMAPI_ARRAY_TYPE(name, stype)
Definition: omapip.h:197
DHCP_R_INCOMPLETE
#define DHCP_R_INCOMPLETE
Definition: result.h:58
__omapi_connection_object
Definition: omapip_p.h:177
__omapi_object
Definition: omapip.h:127
dmalloc
void * dmalloc(size_t, const char *, int)
Definition: alloc.c:57
omapi_connection_readfd
int omapi_connection_readfd(omapi_object_t *h)
Definition: connection.c:577
__omapi_connection_object::out_bytes
u_int32_t out_bytes
Definition: omapip_p.h:190
omapi_connection_destroy
isc_result_t omapi_connection_destroy(omapi_object_t *h, const char *file, int line)
Definition: connection.c:1054
omapi_connection_signal_handler
isc_result_t omapi_connection_signal_handler(omapi_object_t *h, const char *name, va_list ap)
Definition: connection.c:1075
log_debug
int int int log_debug(const char *,...) __attribute__((__format__(__printf__
omapi_connection_closed
Definition: omapip_p.h:100
omapi_connection_get_value
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
omapi_get_value_str
isc_result_t omapi_get_value_str(omapi_object_t *, omapi_object_t *, const char *, omapi_value_t **)
Definition: support.c:482
omapi_reregister_io_object
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
DHCP_R_INVALIDARG
#define DHCP_R_INVALIDARG
Definition: result.h:49
omapi_datatype_object
Definition: omapip.h:45
omapi_addr_t
Definition: omapip.h:134
omapi_value_t
Definition: omapip.h:87
omapi_connection_output_auth_length
isc_result_t omapi_connection_output_auth_length(omapi_object_t *h, unsigned *l)
Definition: connection.c:896
trace_iov::buf
const char * buf
Definition: trace.h:75
ISC_R_SUCCESS
#define ISC_R_SUCCESS
omapi_connection_reaper
isc_result_t omapi_connection_reaper(omapi_object_t *h)
Definition: connection.c:741
omapi_unregister_io_object
isc_result_t omapi_unregister_io_object(omapi_object_t *)
Definition: dispatch.c:355
omapi_type_connection
omapi_object_type_t * omapi_type_connection
Definition: support.c:33
DHCP_HMAC_MD5_NAME
#define DHCP_HMAC_MD5_NAME
Definition: isclib.h:116
SIG_MODE_FINAL
#define SIG_MODE_FINAL
Definition: omapip_p.h:72
omapi_typed_data_t::type
omapi_datatype_t type
Definition: omapip.h:50
omapi_value_t::value
omapi_typed_data_t * value
Definition: omapip.h:90