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 libdhcp_state_string(state,&(buf[0]))
00276 );
00277 control -> finished = 1;
00278 break;
00279
00280 case DHC4_PREINIT:
00281 {
00282 } break;
00283
00284 case DHC4_BOUND:
00285 case DHC4_REBOOT:
00286 case DHC4_RENEW:
00287 case DHC4_REBIND:
00288 case DHC4_TIMEOUT:
00289 {
00290 control -> lease = dhcpv4_lease( arg );
00291 dhc4_log
00292 ( control, LOG_DEBUG,
00293 "DHCPv4 %s - BOUND: %p", control->if_name, dhcpv4_lease
00294 );
00295 control -> finished = 1;
00296 break;
00297 }
00298
00299 case DHC4_RELEASE:
00300 case DHC4_EXPIRE:
00301 case DHC4_FAIL:
00302 case DHC4_STOP:
00303
00304
00305 control -> finished = 1;
00306 break;
00307
00308 default:
00309 dhc4_log
00310 ( control, LOG_ERR,
00311 "DHCPv4 %s - entered unhandled state.",
00312 control->if_name
00313 );
00314 }
00315 return 0;
00316 }
00317
00318 int dhcp4_process_lease(DHCPv4_control *ctl)
00319 {
00320 if( ( ctl == 0L ) || (ctl->lease == 0L) ) return(0);
00321
00322 DHCPv4_lease *lease = ctl->lease;
00323 char buf[32];
00324 ip_addr_t lease_address;
00325
00326 ctl->lease = lease;
00327
00328 lease_address = ip_addr_in( &lease->address );
00329
00330 dhc4_log
00331 ( ctl, LOG_INFO,
00332 "DHCPv4 %s - obtained lease %s",
00333 ctl->if_name,
00334 ip_text_addr(&lease_address, buf, 32)
00335 );
00336 ctl->lease = lease;
00337 ctl->ip4 = nic_addr(ctl->nh, lease_address );
00338
00339 IPaddr_list_node_t *n = calloc(1,sizeof(IPaddr_list_node_t));
00340 n->addr = ctl->ip4;
00341 STAILQ_INSERT_TAIL( &(ctl->addr_list), n, link );
00342
00343 dhcpv4_process_options(lease, dhcp4_nic_option_handler, ctl);
00344
00345 return ((!STAILQ_EMPTY(&(ctl->addr_list))) || (ctl->lease->options != 0));
00346 }
00347
00348 uint32_t dhcpv4_mtu_option( DHCPv4_control *ctl )
00349 {
00350 return ctl->mtu;
00351 }
00352
00353 void dhcp4_nic_option_handler( DHCPv4_option *option, void *arg )
00354 {
00355 DHCPv4_control *control = arg;
00356 char buf[32];
00357
00358 if ( option -> unicode == DHC_DHCP_Universe )
00359 {
00360 switch( option -> code )
00361 {
00362 case DHCO_SUBNET_MASK:
00363 {
00364 dhc4_log
00365 ( control, LOG_INFO, "DHCPv4 %s - option subnet-mask: %s",
00366 control->if_name,
00367 inet_ntop( AF_INET, (struct in_addr*)&(option->value[0]), &(buf[0]), sizeof(buf))
00368 );
00369 ip_addr_t ip4 = nic_ip_addr(control->ip4);
00370 uint32_t sm=0;
00371 uint32_t i=32, b=1;
00372 memcpy(&sm, &(option->value[0]), sizeof(uint32_t));
00373 sm = ntohl(sm);
00374 for(; i && ((sm & b) != b); i-=1, b <<= 1);
00375 nic_addr_set_prefix( control->ip4, i);
00376 ip_addr_t ip4_broadcast = ip_v4_broadcast( &ip4, i );
00377 nic_addr_set_broadcast( control->ip4, ip4_broadcast );
00378 dhc4_log
00379 ( control, LOG_INFO, "DHCPv4 %s - option subnet-mask - prefix_len: %d broadcast: %s",
00380 control->if_name, i, ip_text_addr(&ip4_broadcast, buf, 32)
00381 );
00382 }
00383 break;
00384
00385 case DHCO_ROUTERS:
00386 {
00387 int i;
00388 struct in_addr *routers = (struct in_addr*) &(option->value[0]);
00389 dhc4_log
00390 ( control, LOG_INFO, "DHCPv4 %s - option routers:",
00391 control->if_name
00392 );
00393
00394 for( i = 0; i < option->n_elements; i++, routers++ )
00395 {
00396 ip_addr_t gw = ip_addr_in( routers );
00397
00398 dhc4_log
00399 ( control, LOG_DEBUG, "DHCPv4 %s - option routers default gateway %d: %s",
00400 control->if_name, i,
00401 ip_text_addr(&gw,&(buf[0]),32)
00402 );
00403
00404 IProute_t route =
00405 nic_route_new
00406 ( control->nh,
00407 nic_get_index(control->nic),
00408 0L,0,
00409 &gw,
00410 -1,
00411 -1,
00412 -1,
00413 (i > 0) ? (int8_t)i : -1,
00414 -1,
00415 0L, 0L, 0
00416 );
00417 IProute_list_node_t *n = calloc(1,sizeof(IProute_list_node_t));
00418 n->route = route;
00419 STAILQ_INSERT_TAIL(&(control->route_list),n,link);
00420 }
00421 }
00422 break;
00423 case DHCO_STATIC_ROUTES:
00424 {
00425 dhc4_log
00426 ( control, LOG_DEBUG, "DHCPv4 %s - option static-routes:",
00427 control->if_name
00428 );
00429
00430 char buf2[32];
00431 int i;
00432 struct { struct in_addr dst, gw; } *routes = (void*)&(option->value[0]);
00433 IProute_t route;
00434
00435 for( i = 0; i < option->n_elements; i++, routes++ )
00436 {
00437 ip_addr_t
00438 dst=ip_addr_in( &(routes->dst) ),
00439 gw=ip_addr_in( &(routes->gw) );
00440
00441 dhc4_log
00442 ( control, LOG_DEBUG, "DHCPv4 %s - option static-routes - route %d: %s via %s",
00443 control->if_name,
00444 ip_text_addr( &dst, &(buf[0]), sizeof(buf)),
00445 ip_text_addr( &gw , &(buf2[0]),sizeof(buf))
00446 );
00447
00448 uint32_t dip= ip_v4_addr(&dst);
00449 uint32_t dst_len=32, b=1;
00450 for(; dst_len && ((dip & b) != b); dst_len--, b <<= 1);
00451 route =
00452 nic_route_new
00453 ( control->nh,
00454 nic_get_index(control->nic),
00455 &dst, dst_len,
00456 &gw,
00457 -1,
00458 -1,
00459 -1,
00460 (i > 0) ? (int8_t)i : -1,
00461 -1,
00462 0L, 0L,0
00463 );
00464 IProute_list_node_t *n = calloc(1,sizeof(IProute_list_node_t));
00465 n->route = route;
00466 STAILQ_INSERT_TAIL(&(control->route_list),n,link);
00467 }
00468 }
00469 break;
00470
00471 case DHCO_DOMAIN_NAME:
00472 dhc4_log
00473 ( control, LOG_DEBUG, "DHCPv4 %s - option domain-name: %s",
00474 control->if_name, (char*)(option->value)
00475 );
00476 control->search_list = strdup( (char*)option->value );
00477 break;
00478
00479 case DHCO_HOST_NAME:
00480 dhc4_log
00481 ( control, LOG_DEBUG, "DHCPv4 %s - option host-name: %s",
00482 control->if_name, (char*)(option->value)
00483 );
00484 control->host_name = strdup( (char*)option->value );
00485 break;
00486
00487 case DHCO_DOMAIN_NAME_SERVERS:
00488 {
00489 dhc4_log
00490 ( control, LOG_DEBUG, "DHCPv4 %s - option domain-name-servers:",
00491 control->if_name
00492 );
00493 int i;
00494 struct in_addr *dns = (struct in_addr*) &(option->value[0]);
00495 for( i = 0; i < option->n_elements; i++, dns++ )
00496 {
00497 dhc4_log
00498 ( control, LOG_DEBUG, "DHCPv4 %s - domain-name-server %d: %s",
00499 control->if_name, i,
00500 inet_ntop(AF_INET, dns, buf, sizeof(buf))
00501 );
00502 IPaddr_t dnsIP = nic_addr(control->nh, ip_addr_in(dns));
00503 IPaddr_list_node_t *n = calloc(1,sizeof(IPaddr_list_node_t));
00504 n->addr = dnsIP;
00505 STAILQ_INSERT_TAIL(&(control->dns_list), n, link);
00506 }
00507 }
00508 break;
00509 case DHCO_INTERFACE_MTU:
00510 {
00511 dhc4_log
00512 ( control, LOG_DEBUG, "DHCPv4 %s - option interface-mtu: %d",
00513 control->if_name, *((uint32_t*)&(option->value[0]))
00514 );
00515 control->mtu = *((uint32_t*)&(option->value[0]));
00516 }
00517 break;
00518 default:
00519
00520 break;
00521 }
00522 }
00523 }