ISC DHCP  4.3.6b1
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 }
const char * buf
Definition: trace.h:75
isc_result_t omapi_reregister_io_object(omapi_object_t *, int(*)(omapi_object_t *), int(*)(omapi_object_t *), isc_result_t(*)(omapi_object_t *), isc_result_t(*)(omapi_object_t *), isc_result_t(*)(omapi_object_t *))
Definition: dispatch.c:306
isc_result_t omapi_disconnect(omapi_object_t *h, int force)
Definition: connection.c:456
isc_result_t omapi_typed_data_new(const char *, int, omapi_typed_data_t **, omapi_datatype_t,...)
Definition: alloc.c:803
isc_result_t omapi_connection_reader(omapi_object_t *)
Definition: buffer.c:132
const char int line
Definition: dhcpd.h:3723
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
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:766
isc_result_t omapi_object_reference(omapi_object_t **, omapi_object_t *, const char *, int)
Definition: alloc.c:571
#define NS_TSIG_ALG_HMAC_MD5
Definition: nameser.h:214
#define 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:193
isc_result_t omapi_signal_in(omapi_object_t *, const char *,...)
Definition: support.c:286
int trace_playback(void)
int log_error(const char *,...) __attribute__((__format__(__printf__
#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:191
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:897
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:912
OMAPI_OBJECT_ALLOC(omapi_connection, omapi_connection_object_t, omapi_type_connection)
Definition: connection.c:48
isc_result_t omapi_addr_list_reference(omapi_addr_list_t **, omapi_addr_list_t *, const char *, int)
Definition: alloc.c:1120
trace_type_t * trace_type_register(const char *, void *, void(*)(trace_type_t *, unsigned, char *), void(*)(trace_type_t *), const char *, int)
void trace_stop(void)
unsigned len
Definition: trace.h:76
isc_result_t omapi_connection_writer(omapi_object_t *)
Definition: buffer.c: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:593
isc_result_t omapi_signal(omapi_object_t *, const char *,...)
Definition: support.c:268
isc_result_t trace_write_packet_iov(trace_type_t *, int, trace_iov_t *, const char *, int)
isc_result_t omapi_connection_reaper(omapi_object_t *h)
Definition: connection.c:742
isc_result_t omapi_connection_require(omapi_object_t *h, unsigned bytes)
Definition: connection.c:561
void dfree(void *, const char *, int)
Definition: alloc.c:145
isc_result_t omapi_make_value(omapi_value_t **, omapi_data_string_t *, omapi_typed_data_t *, const char *, int)
Definition: support.c: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:1142
isc_result_t uerr2isc(int)
Definition: toisc.c:37
int trace_record(void)
void * dmalloc(size_t, const char *, int)
Definition: alloc.c:57
isc_result_t omapi_connect(omapi_object_t *, const char *, unsigned)
isc_result_t omapi_typed_data_reference(omapi_typed_data_t **, omapi_typed_data_t *, const char *, int)
Definition: alloc.c:880
void cleanup(void)
isc_result_t omapi_value_dereference(omapi_value_t **, const char *, int)
Definition: alloc.c:1060
isc_result_t omapi_connection_stuff_values(omapi_object_t *c, omapi_object_t *id, omapi_object_t *m)
Definition: connection.c:1095
isc_result_t isclib_make_dst_key(char *inname, char *algorithm, unsigned char *secret, int length, dst_key_t **dstkey)
Definition: isclib.c:286
#define DHCP_HMAC_MD5_NAME
Definition: isclib.h:112
isc_result_t omapi_connection_get_value(omapi_object_t *h, omapi_object_t *id, omapi_data_string_t *name, omapi_value_t **value)
Definition: connection.c:981
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:604
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 omapi_connection_signal_handler(omapi_object_t *h, const char *name, va_list ap)
Definition: connection.c:1076
isc_result_t omapi_listener_connect(omapi_connection_object_t **obj, omapi_listener_object_t *listener, int socket, struct sockaddr_in *remote_addr)
Definition: listener.c:278
#define OMAPI_ARRAY_TYPE(name, stype)
Definition: omapip.h:198
#define DHCP_R_INCOMPLETE
Definition: result.h:57
const char * file
Definition: dhcpd.h:3723
int omapi_connection_readfd(omapi_object_t *h)
Definition: connection.c:578
isc_result_t trace_write_packet(trace_type_t *, unsigned, const char *, const char *, int)
int omapi_connection_writefd(omapi_object_t *h)
Definition: connection.c:595
#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:1055
isc_result_t omapi_typed_data_dereference(omapi_typed_data_t **, const char *, int)
Definition: alloc.c:901
#define omapi_array_foreach_begin(array, stype, var)
Definition: omapip.h:243
isc_result_t omapi_addr_list_new(omapi_addr_list_t **, unsigned, const char *, int)
Definition: alloc.c:1104