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