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