00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030 #include "dhcpd.h"
00031
00032 #include <omapip/omapip_p.h>
00033 #include <errno.h>
00034
00035 #if defined (TRACING)
00036 omapi_array_t *trace_listeners;
00037 static void trace_listener_accept_input (trace_type_t *, unsigned, char *);
00038 static void trace_listener_remember (omapi_listener_object_t *,
00039 const char *, int);
00040 static void trace_listener_accept_stop (trace_type_t *);
00041 trace_type_t *trace_listener_accept;
00042 #endif
00043
00044 OMAPI_OBJECT_ALLOC (omapi_listener,
00045 omapi_listener_object_t, omapi_type_listener)
00046
00047 isc_result_t omapi_listen (omapi_object_t *h,
00048 unsigned port,
00049 int max)
00050 {
00051 omapi_addr_t addr;
00052
00053 #ifdef DEBUG_PROTOCOL
00054 log_debug ("omapi_listen(port=%d, max=%d)", port, max);
00055 #endif
00056
00057 addr.addrtype = AF_INET;
00058 addr.addrlen = sizeof (struct in_addr);
00059 memset (addr.address, 0, sizeof addr.address);
00060 addr.port = port;
00061
00062 return omapi_listen_addr (h, &addr, max);
00063 }
00064
00065 isc_result_t omapi_listen_addr (omapi_object_t *h,
00066 omapi_addr_t *addr,
00067 int max)
00068 {
00069 isc_result_t status;
00070 omapi_listener_object_t *obj;
00071 int i;
00072
00073
00074 if (addr->addrtype != AF_INET)
00075 return DHCP_R_INVALIDARG;
00076
00077
00078 obj = (omapi_listener_object_t *)0;
00079 status = omapi_listener_allocate (&obj, MDL);
00080 if (status != ISC_R_SUCCESS)
00081
00082
00083
00084
00085
00086
00087
00088 goto error_exit;
00089 obj->socket = -1;
00090
00091
00092 status = omapi_object_reference (&h -> outer,
00093 (omapi_object_t *)obj, MDL);
00094 if (status != ISC_R_SUCCESS)
00095 goto error_exit;
00096 status = omapi_object_reference (&obj -> inner, h, MDL);
00097 if (status != ISC_R_SUCCESS)
00098 goto error_exit;
00099
00100
00101 obj -> address.sin_port = htons (addr -> port);
00102 memcpy (&obj -> address.sin_addr,
00103 addr -> address, sizeof obj -> address.sin_addr);
00104 #if defined (HAVE_SA_LEN)
00105 obj -> address.sin_len =
00106 sizeof (struct sockaddr_in);
00107 #endif
00108 obj -> address.sin_family = AF_INET;
00109 memset (&(obj -> address.sin_zero), 0,
00110 sizeof obj -> address.sin_zero);
00111
00112 #if defined (TRACING)
00113
00114
00115 if (trace_playback ()) {
00116 trace_listener_remember (obj, MDL);
00117 } else {
00118 #endif
00119
00120 obj -> socket = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP);
00121 if (obj->socket == -1) {
00122 if (errno == EMFILE
00123 || errno == ENFILE || errno == ENOBUFS)
00124 status = ISC_R_NORESOURCES;
00125 else
00126 status = ISC_R_UNEXPECTED;
00127 goto error_exit;
00128 }
00129
00130 #if defined (HAVE_SETFD)
00131 if (fcntl (obj -> socket, F_SETFD, 1) < 0) {
00132 status = ISC_R_UNEXPECTED;
00133 goto error_exit;
00134 }
00135 #endif
00136
00137
00138
00139 i = 1;
00140 if (setsockopt (obj -> socket, SOL_SOCKET, SO_REUSEADDR,
00141 (char *)&i, sizeof i) < 0) {
00142 status = ISC_R_UNEXPECTED;
00143 goto error_exit;
00144 }
00145
00146
00147
00148 i = bind (obj -> socket,
00149 (struct sockaddr *)&obj -> address,
00150 sizeof obj -> address);
00151 if (i < 0) {
00152 if (errno == EADDRINUSE)
00153 status = ISC_R_ADDRNOTAVAIL;
00154 else if (errno == EPERM)
00155 status = ISC_R_NOPERM;
00156 else
00157 status = ISC_R_UNEXPECTED;
00158 goto error_exit;
00159 }
00160
00161
00162 if (listen (obj -> socket, max)) {
00163 status = ISC_R_UNEXPECTED;
00164 goto error_exit;
00165 }
00166
00167 if (fcntl (obj -> socket, F_SETFL, O_NONBLOCK) < 0) {
00168 status = ISC_R_UNEXPECTED;
00169 goto error_exit;
00170 }
00171
00172 status = omapi_register_io_object ((omapi_object_t *)obj,
00173 omapi_listener_readfd, 0,
00174 omapi_accept, 0, 0);
00175 #if defined (TRACING)
00176 }
00177 #endif
00178
00179 omapi_listener_dereference (&obj, MDL);
00180 return status;
00181
00182 error_exit:
00183 if (obj != NULL) {
00184 if (h->outer == (omapi_object_t *)obj) {
00185 omapi_object_dereference((omapi_object_t **)&h->outer,
00186 MDL);
00187 }
00188 if (obj->inner == h) {
00189 omapi_object_dereference((omapi_object_t **)&obj->inner,
00190 MDL);
00191 }
00192 if (obj->socket != -1) {
00193 close(obj->socket);
00194 }
00195 omapi_listener_dereference(&obj, MDL);
00196 }
00197 return status;
00198 }
00199
00200
00201
00202 int omapi_listener_readfd (omapi_object_t *h)
00203 {
00204 omapi_listener_object_t *l;
00205
00206 if (h -> type != omapi_type_listener)
00207 return -1;
00208 l = (omapi_listener_object_t *)h;
00209
00210 return l -> socket;
00211 }
00212
00213
00214 isc_result_t omapi_accept (omapi_object_t *h)
00215 {
00216 isc_result_t status;
00217 socklen_t len;
00218 omapi_connection_object_t *obj;
00219 omapi_listener_object_t *listener;
00220 struct sockaddr_in addr;
00221 int socket;
00222
00223 if (h -> type != omapi_type_listener)
00224 return DHCP_R_INVALIDARG;
00225 listener = (omapi_listener_object_t *)h;
00226
00227
00228 len = sizeof addr;
00229 socket = accept (listener -> socket,
00230 ((struct sockaddr *)&(addr)), &len);
00231 if (socket < 0) {
00232 if (errno == EMFILE || errno == ENFILE || errno == ENOBUFS)
00233 return ISC_R_NORESOURCES;
00234 return ISC_R_UNEXPECTED;
00235 }
00236
00237 #if defined (TRACING)
00238
00239 if (trace_record ()) {
00240 trace_iov_t iov [3];
00241 iov [0].buf = (char *)&addr.sin_port;
00242 iov [0].len = sizeof addr.sin_port;
00243 iov [1].buf = (char *)&addr.sin_addr;
00244 iov [1].len = sizeof addr.sin_addr;
00245 iov [2].buf = (char *)&listener -> address.sin_port;
00246 iov [2].len = sizeof listener -> address.sin_port;
00247 trace_write_packet_iov (trace_listener_accept,
00248 3, iov, MDL);
00249 }
00250 #endif
00251
00252 obj = (omapi_connection_object_t *)0;
00253 status = omapi_listener_connect (&obj, listener, socket, &addr);
00254 if (status != ISC_R_SUCCESS) {
00255 close (socket);
00256 return status;
00257 }
00258
00259 status = omapi_register_io_object ((omapi_object_t *)obj,
00260 omapi_connection_readfd,
00261 omapi_connection_writefd,
00262 omapi_connection_reader,
00263 omapi_connection_writer,
00264 omapi_connection_reaper);
00265
00266
00267
00268 omapi_connection_dereference (&obj, MDL);
00269 if (status != ISC_R_SUCCESS)
00270 omapi_disconnect ((omapi_object_t *)(obj), 1);
00271 return status;
00272 }
00273
00274 isc_result_t omapi_listener_connect (omapi_connection_object_t **obj,
00275 omapi_listener_object_t *listener,
00276 int socket,
00277 struct sockaddr_in *remote_addr)
00278 {
00279 isc_result_t status;
00280 omapi_object_t *h = (omapi_object_t *)listener;
00281 omapi_addr_t addr;
00282
00283 #ifdef DEBUG_PROTOCOL
00284 log_debug ("omapi_accept()");
00285 #endif
00286
00287
00288 status = omapi_connection_allocate (obj, MDL);
00289 if (status != ISC_R_SUCCESS)
00290 return status;
00291
00292 (*obj) -> state = omapi_connection_connected;
00293 (*obj) -> remote_addr = *remote_addr;
00294 (*obj) -> socket = socket;
00295
00296
00297 if (listener -> verify_addr) {
00298 addr.addrtype = AF_INET;
00299 addr.addrlen = sizeof (remote_addr -> sin_addr);
00300 memcpy (addr.address, &remote_addr -> sin_addr,
00301 sizeof (remote_addr -> sin_addr));
00302 addr.port = ntohs(remote_addr -> sin_port);
00303
00304 status = (listener -> verify_addr) (h, &addr);
00305 if (status != ISC_R_SUCCESS) {
00306 omapi_disconnect ((omapi_object_t *)(*obj), 1);
00307 omapi_connection_dereference (obj, MDL);
00308 return status;
00309 }
00310 }
00311
00312 omapi_listener_reference (&(*obj) -> listener, listener, MDL);
00313 #if defined (TRACING)
00314 omapi_connection_register (*obj, MDL);
00315 #endif
00316 status = omapi_signal (h, "connect", (*obj));
00317 return status;
00318 }
00319
00320 #if defined (TRACING)
00321 OMAPI_ARRAY_TYPE(omapi_listener, omapi_listener_object_t)
00322
00323 void omapi_listener_trace_setup (void) {
00324 trace_listener_accept =
00325 trace_type_register ("listener-accept", (void *)0,
00326 trace_listener_accept_input,
00327 trace_listener_accept_stop, MDL);
00328 }
00329
00330 static void trace_listener_remember (omapi_listener_object_t *obj,
00331 const char *file, int line)
00332 {
00333 isc_result_t status;
00334 if (!trace_listeners) {
00335 status = omapi_listener_array_allocate (&trace_listeners,
00336 file, line);
00337 if (status != ISC_R_SUCCESS) {
00338 foo:
00339 log_error ("trace_listener_remember: %s",
00340 isc_result_totext (status));
00341 return;
00342 }
00343 }
00344 status = omapi_listener_array_extend (trace_listeners, obj,
00345 &obj -> index, MDL);
00346 if (status != ISC_R_SUCCESS)
00347 goto foo;
00348 }
00349
00350 static void trace_listener_accept_input (trace_type_t *ttype,
00351 unsigned length, char *buf)
00352 {
00353 struct in_addr *addr;
00354 u_int16_t *remote_port;
00355 u_int16_t *local_port;
00356 omapi_connection_object_t *obj;
00357 isc_result_t status;
00358 struct sockaddr_in remote_addr;
00359
00360 addr = (struct in_addr *)buf;
00361 remote_port = (u_int16_t *)(addr + 1);
00362 local_port = remote_port + 1;
00363
00364 memset (&remote_addr, 0, sizeof remote_addr);
00365 remote_addr.sin_addr = *addr;
00366 remote_addr.sin_port = *remote_port;
00367
00368 omapi_array_foreach_begin (trace_listeners,
00369 omapi_listener_object_t, lp) {
00370 if (lp -> address.sin_port == *local_port) {
00371 obj = (omapi_connection_object_t *)0;
00372 status = omapi_listener_connect (&obj,
00373 lp, 0, &remote_addr);
00374 if (status != ISC_R_SUCCESS) {
00375 log_error("%s:%d: OMAPI: Failed to connect "
00376 "a listener.", MDL);
00377 }
00378 omapi_listener_dereference (&lp, MDL);
00379 return;
00380 }
00381 } omapi_array_foreach_end (trace_listeners,
00382 omapi_listener_object_t, lp);
00383 log_error ("trace_listener_accept: %s from %s/%d to port %d",
00384 "unexpected connect",
00385 inet_ntoa (*addr), *remote_port, *local_port);
00386 }
00387
00388 static void trace_listener_accept_stop (trace_type_t *ttype) { }
00389
00390
00391 #endif
00392
00393 isc_result_t omapi_listener_configure_security (omapi_object_t *h,
00394 isc_result_t (*verify_addr)
00395 (omapi_object_t *,
00396 omapi_addr_t *))
00397 {
00398 omapi_listener_object_t *l;
00399
00400 if (h -> type != omapi_type_listener)
00401 return DHCP_R_INVALIDARG;
00402 l = (omapi_listener_object_t *)h;
00403
00404 l -> verify_addr = verify_addr;
00405
00406 return ISC_R_SUCCESS;
00407 }
00408
00409 isc_result_t omapi_listener_set_value (omapi_object_t *h,
00410 omapi_object_t *id,
00411 omapi_data_string_t *name,
00412 omapi_typed_data_t *value)
00413 {
00414 if (h -> type != omapi_type_listener)
00415 return DHCP_R_INVALIDARG;
00416
00417 if (h -> inner && h -> inner -> type -> set_value)
00418 return (*(h -> inner -> type -> set_value))
00419 (h -> inner, id, name, value);
00420 return ISC_R_NOTFOUND;
00421 }
00422
00423 isc_result_t omapi_listener_get_value (omapi_object_t *h,
00424 omapi_object_t *id,
00425 omapi_data_string_t *name,
00426 omapi_value_t **value)
00427 {
00428 if (h -> type != omapi_type_listener)
00429 return DHCP_R_INVALIDARG;
00430
00431 if (h -> inner && h -> inner -> type -> get_value)
00432 return (*(h -> inner -> type -> get_value))
00433 (h -> inner, id, name, value);
00434 return ISC_R_NOTFOUND;
00435 }
00436
00437 isc_result_t omapi_listener_destroy (omapi_object_t *h,
00438 const char *file, int line)
00439 {
00440 omapi_listener_object_t *l;
00441
00442 if (h -> type != omapi_type_listener)
00443 return DHCP_R_INVALIDARG;
00444 l = (omapi_listener_object_t *)h;
00445
00446 #ifdef DEBUG_PROTOCOL
00447 log_debug ("omapi_listener_destroy()");
00448 #endif
00449
00450 if (l -> socket != -1) {
00451 close (l -> socket);
00452 l -> socket = -1;
00453 }
00454 return ISC_R_SUCCESS;
00455 }
00456
00457 isc_result_t omapi_listener_signal_handler (omapi_object_t *h,
00458 const char *name, va_list ap)
00459 {
00460 if (h -> type != omapi_type_listener)
00461 return DHCP_R_INVALIDARG;
00462
00463 if (h -> inner && h -> inner -> type -> signal_handler)
00464 return (*(h -> inner -> type -> signal_handler)) (h -> inner,
00465 name, ap);
00466 return ISC_R_NOTFOUND;
00467 }
00468
00469
00470
00471
00472 isc_result_t omapi_listener_stuff_values (omapi_object_t *c,
00473 omapi_object_t *id,
00474 omapi_object_t *l)
00475 {
00476 if (l -> type != omapi_type_listener)
00477 return DHCP_R_INVALIDARG;
00478
00479 if (l -> inner && l -> inner -> type -> stuff_values)
00480 return (*(l -> inner -> type -> stuff_values)) (c, id,
00481 l -> inner);
00482 return ISC_R_SUCCESS;
00483 }
00484