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