00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include <sys/types.h>
00024 #include <unistd.h>
00025 #include <netinet/in.h>
00026 #include <sys/socket.h>
00027 #include <string.h>
00028 #include <time.h>
00029 #include <errno.h>
00030 #include <stdio.h>
00031 #include <stdlib.h>
00032
00033 #include <dhcp4_nic.h>
00034 #include <dhcp4client.h>
00035 #include <isc_dhcp/dhcpd.h>
00036
00037 struct dhcpv4_control_s
00038 {
00039
00040 LIBDHCP_Callback callback;
00041 uint16_t capability;
00042 uint8_t finished;
00043 uint8_t decline;
00044 time_t timeout;
00045 time_t now;
00046 void *arg;
00047 LIBDHCP_Error_Handler eh;
00048
00049 uint8_t log_level;
00050
00051 NLH_t nh;
00052 NIC_t nic;
00053 IPaddr_list_t addr_list;
00054 IProute_list_t route_list;
00055 IPaddr_list_t dns_list;
00056 char *search_list;
00057 char *host_name;
00058 DHCPv4_lease *lease;
00059
00060 IPaddr_t ip4;
00061 uint32_t mtu;
00062 char *if_name;
00063 char **argv;
00064 int argc;
00065 };
00066
00067 static void
00068 dhc4_log( DHCPv4_control *ctl, int priority, char *fmt, ...)
00069 {
00070 va_list va;
00071 if((ctl == 0)|| ((ctl->eh == 0) || (ctl->log_level < priority)))
00072 return;
00073 va_start(va, fmt);
00074 ctl->eh((LIBDHCP_Control*)ctl, priority, fmt, va);
00075 va_end(va);
00076 }
00077
00078 DHCPv4_control*
00079 dhcpv4_control_va
00080 (
00081 NLH_t nh,
00082 char *eth_if_name,
00083 LIBDHCP_Capability dhc_cap,
00084 time_t timeout,
00085 LIBDHCP_Error_Handler error_handler,
00086 uint8_t log_level,
00087 va_list va
00088 )
00089 {
00090 DHCPv4_control *dhc = calloc( 1, sizeof( DHCPv4_control ) );
00091 char **argv, *a[32]={strdup("dhclient")}, *p;
00092 int argc,i;
00093 uint8_t d_needed=1, if_needed=1;
00094
00095 if( dhc == 0L )
00096 return 0;
00097
00098 dhc->nh = nh;
00099
00100 if( (dhc->nic = nic_by_name(dhc->nh, eth_if_name)) == 0L ) {
00101 free(dhc);
00102 return 0;
00103 }
00104
00105 dhc->capability = dhc_cap;
00106 dhc->callback = dhcp4_nic_callback;
00107 dhc->timeout = timeout;
00108 dhc->arg = 0;
00109 dhc->eh = error_handler;
00110 dhc->log_level = log_level;
00111 dhc->if_name = strdup(eth_if_name);
00112
00113 for(argc=1, argv=&(a[1]); (argc < 31) && (p = va_arg(va, char *)); argc++, argv++)
00114 {
00115 *argv = strdup(p);
00116 if( strcmp(p,"-d") == 0)
00117 d_needed = 0;
00118 if( strcmp(p,eth_if_name) == 0)
00119 if_needed = 0;
00120 }
00121
00122 if ( d_needed )
00123 {
00124 if ( argc > 31 )
00125 {
00126 dhcpv4_control_free(dhc);
00127 return 0L;
00128 }
00129 a[argc++] = strdup("-d");
00130 }
00131
00132 if ( if_needed )
00133 {
00134 if ( argc > 31 )
00135 {
00136 dhcpv4_control_free(dhc);
00137 return 0L;
00138 }
00139 a[argc++] = strdup(eth_if_name);
00140 }
00141
00142 a[argc] = 0L;
00143 argv = calloc(argc+1, sizeof(char*));
00144 if( argv == 0 )
00145 {
00146 dhcpv4_control_free(dhc);
00147 return 0L;
00148 }
00149 dhc->argc = argc;
00150 for(i=0; i < argc; i++)
00151 argv[i] = a[i];
00152 argv[i]=0;
00153 dhc->argv = argv;
00154 STAILQ_INIT( &(dhc->addr_list) );
00155 STAILQ_INIT( &(dhc->route_list) );
00156 STAILQ_INIT( &(dhc->dns_list) );
00157 return dhc;
00158 }
00159
00160 DHCPv4_control*
00161 dhcpv4_control
00162 (
00163 NLH_t nh,
00164 char *eth_if_name,
00165 LIBDHCP_Capability dhc_cap,
00166 time_t timeout,
00167 LIBDHCP_Error_Handler error_handler,
00168 uint8_t log_level,
00169 ...
00170 )
00171 {
00172 va_list va;
00173 va_start( va, log_level );
00174 DHCPv4_control * dhc =
00175 dhcpv4_control_va
00176 (
00177 nh,
00178 eth_if_name,
00179 dhc_cap,
00180 timeout,
00181 error_handler,
00182 log_level,
00183 va
00184 );
00185 va_end(va);
00186 return(dhc);
00187 }
00188
00189 void dhcpv4_control_free( DHCPv4_control *dhc )
00190 {
00191 if(dhc->lease)
00192 {
00193 dhcpv4_lease_free(dhc->lease);
00194 dhc->lease = NULL;
00195 }
00196 if(dhc->if_name)
00197 {
00198 free(dhc->if_name);
00199 dhc->if_name = NULL;
00200 }
00201 if( dhc->argv )
00202 {
00203 char **p;
00204 for(p=dhc->argv; *p; p++)
00205 free(*p);
00206 free(dhc->argv);
00207 dhc->argv = 0;
00208 }
00209 if( !STAILQ_EMPTY( &(dhc->addr_list) ) )
00210 nic_address_list_free(&(dhc->addr_list));
00211 if( !STAILQ_EMPTY( &(dhc->dns_list) ) )
00212 nic_address_list_free(&(dhc->dns_list));
00213 if( !STAILQ_EMPTY( &(dhc->route_list) ) )
00214 nic_route_list_free(&(dhc->route_list));
00215
00216 if( dhc->search_list )
00217 free(dhc->search_list);
00218 if( dhc->host_name )
00219 free(dhc->host_name);
00220
00221 free(dhc);
00222 }
00223
00224 extern char **environ;
00225
00226 DHCPv4_nic *do_dhcpv4( DHCPv4_control *dh4c )
00227 {
00228 dhcpv4_client((LIBDHCP_Control*)dh4c, dh4c->argc, dh4c->argv, environ);
00229
00230 if(dh4c->lease == 0)
00231 {
00232 dhcpv4_control_free( dh4c );
00233 return 0;
00234 }
00235 return (DHCPv4_nic*)&(dh4c->nh);
00236 }
00237
00238 NIC_Res_t dhcpv4_nic(NLH_t nh, DHCPv4_nic *nic )
00239 {
00240 return
00241 nic_configure
00242 (
00243 nh,
00244 nic->nic,
00245 &(nic->address_list),
00246 &(nic->route_list),
00247 &(nic->dns_list),
00248 nic->search_list,
00249 nic->host_name
00250 );
00251 }
00252
00253 DHCPv4_nic *dhcp4_set_lease(DHCPv4_control *ctl, DHCPv4_lease *lease)
00254 {
00255 ctl->lease = lease;
00256 return (DHCPv4_nic*)&(ctl->nh);
00257 }
00258
00259 int dhcp4_nic_callback
00260 ( LIBDHCP_Control *cp,
00261 DHCP_State state,
00262 void *arg
00263 )
00264 {
00265 DHCPv4_control *control = (DHCPv4_control *) cp;
00266 char buf[32];
00267 dhc4_log
00268 ( control, LOG_DEBUG,
00269 "DHCPv4 %s - state: %s",
00270 control->if_name,
00271 libdhcp_state_string(state,&(buf[0]))
00272 );
00273 switch( state )
00274 {
00275 case DHC_TIMEDOUT:
00276 dhc4_log
00277 ( control, LOG_INFO,
00278 "DHCPv4 %s - TIMED OUT.",
00279 control->if_name,
00280 libdhcp_state_string(state,&(buf[0]))
00281 );
00282 control -> finished = 1;
00283 break;
00284
00285 case DHC4_PREINIT:
00286 {
00287 } break;
00288
00289 case DHC4_BOUND:
00290 case DHC4_REBOOT:
00291 case DHC4_RENEW:
00292 case DHC4_REBIND:
00293 case DHC4_TIMEOUT:
00294 {
00295 control -> lease = dhcpv4_lease( arg );
00296 dhc4_log
00297 ( control, LOG_DEBUG,
00298 "DHCPv4 %s - BOUND: %p", control->if_name, dhcpv4_lease
00299 );
00300 control -> finished = 1;
00301 break;
00302 }
00303
00304 case DHC4_RELEASE:
00305 case DHC4_EXPIRE:
00306 case DHC4_FAIL:
00307 case DHC4_STOP:
00308
00309
00310 control -> finished = 1;
00311 break;
00312
00313 default:
00314 dhc4_log
00315 ( control, LOG_ERR,
00316 "DHCPv4 %s - entered unhandled state.",
00317 control->if_name
00318 );
00319 }
00320 return 0;
00321 }
00322
00323 int dhcp4_process_lease(DHCPv4_control *ctl)
00324 {
00325 if( ( ctl == 0L ) || (ctl->lease == 0L) ) return(0);
00326
00327 DHCPv4_lease *lease = ctl->lease;
00328 char buf[32];
00329 ip_addr_t lease_address;
00330
00331 ctl->lease = lease;
00332
00333 lease_address = ip_addr_in( &lease->address );
00334
00335 dhc4_log
00336 ( ctl, LOG_INFO,
00337 "DHCPv4 %s - obtained lease %s",
00338 ctl->if_name,
00339 ip_text_addr(&lease_address, buf, 32)
00340 );
00341 ctl->lease = lease;
00342 ctl->ip4 = nic_addr(ctl->nh, lease_address );
00343
00344 IPaddr_list_node_t *n = calloc(1,sizeof(IPaddr_list_node_t));
00345 n->addr = ctl->ip4;
00346 STAILQ_INSERT_TAIL( &(ctl->addr_list), n, link );
00347
00348 dhcpv4_process_options(lease, dhcp4_nic_option_handler, ctl);
00349
00350 return ((!STAILQ_EMPTY(&(ctl->addr_list))) || (ctl->lease->options != 0));
00351 }
00352
00353 uint32_t dhcpv4_mtu_option( DHCPv4_control *ctl )
00354 {
00355 return ctl->mtu;
00356 }
00357
00358 void dhcp4_nic_option_handler( DHCPv4_option *option, void *arg )
00359 {
00360 DHCPv4_control *control = arg;
00361 char buf[32];
00362
00363 if ( option -> unicode == DHC_DHCP_Universe )
00364 {
00365 switch( option -> code )
00366 {
00367 case DHCO_SUBNET_MASK:
00368 {
00369 dhc4_log
00370 ( control, LOG_INFO, "DHCPv4 %s - option subnet-mask: %s",
00371 control->if_name,
00372 inet_ntop( AF_INET, (struct in_addr*)&(option->value[0]), &(buf[0]), sizeof(buf))
00373 );
00374 ip_addr_t ip4 = nic_ip_addr(control->ip4);
00375 uint32_t sm=0;
00376 uint32_t i=32, b=1;
00377 memcpy(&sm, &(option->value[0]), sizeof(uint32_t));
00378 sm = ntohl(sm);
00379 for(; i && ((sm & b) != b); i-=1, b <<= 1);
00380 nic_addr_set_prefix( control->ip4, i);
00381 ip_addr_t ip4_broadcast = ip_v4_broadcast( &ip4, i );
00382 nic_addr_set_broadcast( control->ip4, ip4_broadcast );
00383 dhc4_log
00384 ( control, LOG_INFO, "DHCPv4 %s - option subnet-mask - prefix_len: %d broadcast: %s",
00385 control->if_name, i, ip_text_addr(&ip4_broadcast, buf, 32)
00386 );
00387 }
00388 break;
00389
00390 case DHCO_ROUTERS:
00391 {
00392 int i;
00393 struct in_addr *routers = (struct in_addr*) &(option->value[0]);
00394 dhc4_log
00395 ( control, LOG_INFO, "DHCPv4 %s - option routers:",
00396 control->if_name
00397 );
00398
00399 for( i = 0; i < option->n_elements; i++, routers++ )
00400 {
00401 ip_addr_t gw = ip_addr_in( routers );
00402
00403 dhc4_log
00404 ( control, LOG_DEBUG, "DHCPv4 %s - option routers default gateway %d: %s",
00405 control->if_name, i,
00406 ip_text_addr(&gw,&(buf[0]),32)
00407 );
00408
00409 IProute_t route =
00410 nic_route_new
00411 ( control->nh,
00412 nic_get_index(control->nic),
00413 0L,0,
00414 &gw,
00415 -1,
00416 -1,
00417 -1,
00418 (i > 0) ? (int8_t)i : -1,
00419 -1,
00420 0L, 0L, 0
00421 );
00422 IProute_list_node_t *n = calloc(1,sizeof(IProute_list_node_t));
00423 n->route = route;
00424 STAILQ_INSERT_TAIL(&(control->route_list),n,link);
00425 }
00426 }
00427 break;
00428 case DHCO_STATIC_ROUTES:
00429 {
00430 dhc4_log
00431 ( control, LOG_DEBUG, "DHCPv4 %s - option static-routes:",
00432 control->if_name
00433 );
00434
00435 char buf2[32];
00436 int i;
00437 struct { struct in_addr dst, gw; } *routes = (void*)&(option->value[0]);
00438 IProute_t route;
00439
00440 for( i = 0; i < option->n_elements; i++, routes++ )
00441 {
00442 ip_addr_t
00443 dst=ip_addr_in( &(routes->dst) ),
00444 gw=ip_addr_in( &(routes->gw) );
00445
00446 dhc4_log
00447 ( control, LOG_DEBUG, "DHCPv4 %s - option static-routes - route %d: %s via %s",
00448 control->if_name,
00449 ip_text_addr( &dst, &(buf[0]), sizeof(buf)),
00450 ip_text_addr( &gw , &(buf2[0]),sizeof(buf))
00451 );
00452
00453 uint32_t dip= ip_v4_addr(&dst);
00454 uint32_t dst_len=32, b=1;
00455 for(; dst_len && ((dip & b) != b); dst_len--, b <<= 1);
00456 route =
00457 nic_route_new
00458 ( control->nh,
00459 nic_get_index(control->nic),
00460 &dst, dst_len,
00461 &gw,
00462 -1,
00463 -1,
00464 -1,
00465 (i > 0) ? (int8_t)i : -1,
00466 -1,
00467 0L, 0L,0
00468 );
00469 IProute_list_node_t *n = calloc(1,sizeof(IProute_list_node_t));
00470 n->route = route;
00471 STAILQ_INSERT_TAIL(&(control->route_list),n,link);
00472 }
00473 }
00474 break;
00475
00476 case DHCO_DOMAIN_NAME:
00477 dhc4_log
00478 ( control, LOG_DEBUG, "DHCPv4 %s - option domain-name: %s",
00479 control->if_name, (char*)(option->value)
00480 );
00481 control->search_list = strdup( (char*)option->value );
00482 break;
00483
00484 case DHCO_HOST_NAME:
00485 dhc4_log
00486 ( control, LOG_DEBUG, "DHCPv4 %s - option host-name: %s",
00487 control->if_name, (char*)(option->value)
00488 );
00489 control->host_name = strdup( (char*)option->value );
00490 break;
00491
00492 case DHCO_DOMAIN_NAME_SERVERS:
00493 {
00494 dhc4_log
00495 ( control, LOG_DEBUG, "DHCPv4 %s - option domain-name-servers:",
00496 control->if_name
00497 );
00498 int i;
00499 struct in_addr *dns = (struct in_addr*) &(option->value[0]);
00500 for( i = 0; i < option->n_elements; i++, dns++ )
00501 {
00502 dhc4_log
00503 ( control, LOG_DEBUG, "DHCPv4 %s - domain-name-server %d: %s",
00504 control->if_name, i,
00505 inet_ntop(AF_INET, dns, buf, sizeof(buf))
00506 );
00507 IPaddr_t dnsIP = nic_addr(control->nh, ip_addr_in(dns));
00508 IPaddr_list_node_t *n = calloc(1,sizeof(IPaddr_list_node_t));
00509 n->addr = dnsIP;
00510 STAILQ_INSERT_TAIL(&(control->dns_list), n, link);
00511 }
00512 }
00513 break;
00514 case DHCO_INTERFACE_MTU:
00515 {
00516 dhc4_log
00517 ( control, LOG_DEBUG, "DHCPv4 %s - option interface-mtu: %d",
00518 control->if_name, *((uint32_t*)&(option->value[0]))
00519 );
00520 control->mtu = *((uint32_t*)&(option->value[0]));
00521 }
00522 break;
00523 default:
00524
00525 break;
00526 }
00527 }
00528 }