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
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073 #include <sys/types.h>
00074 #include <unistd.h>
00075 #include <sys/ioctl.h>
00076 #include <sys/queue.h>
00077 #include <errno.h>
00078 #include <string.h>
00079 #include <assert.h>
00080 #include <pump.h>
00081 #include <netlink/netlink.h>
00082 #include <netlink/netlink-kernel.h>
00083
00084 #include <dhcp4client/dhcp4client.h>
00085 #include <dhcp4client/isc_dhcp/dhcpd.h>
00086
00087 enum {
00088 OOM,
00089 DHCP_FAILED,
00090 };
00091
00092 static char * const pump_errors[] = {
00093 [OOM] = "out of memory",
00094 [DHCP_FAILED] = "DHCP configuration failed",
00095 NULL
00096 };
00097
00098 char * pumpSetupInterface(struct pumpNetIntf * ifx)
00099 {
00100 static char buf[512];
00101 NIC_t nic = 0;
00102 IPaddr_t addr = 0;
00103 IProute_t route = 0;
00104 int err=0;
00105 char *tag="";
00106
00107 if ( ifx->dhcp_nic )
00108 {
00109
00110 assert(ifx->dhcp_nic->nh);
00111
00112 int r = dhcp_nic_configure(ifx->dhcp_nic);
00113
00114 dhcp_nic_free(ifx->dhcp_nic);
00115 ifx->dhcp_nic = 0L;
00116 if ( r < 0 )
00117 {
00118 snprintf(buf, 512, "DHCP configuration failed - %d %s.",
00119 -r, strerror(-r)
00120 );
00121 relinquish_timeouts();
00122 return buf;
00123 }
00124 relinquish_timeouts();
00125 return NULL;
00126 }
00127
00128
00129 if (!ifx->nh) {
00130 ifx->nh = nic_open( 0 );
00131 if (!ifx->nh) {
00132 err = ENOMEM;
00133 tag = "nic_open";
00134 goto return_emsg;
00135 }
00136 }
00137
00138 nic = nic_by_name( ifx->nh, ifx->device );
00139 if ( nic == 0 )
00140 {
00141 err = ENODEV;
00142 tag = "get link";
00143 nic_close(&ifx->nh);
00144 goto return_emsg;
00145 }
00146
00147 uint32_t flags = nic_get_flags( nic );
00148
00149 if ( flags & ( IFF_UP | IFF_RUNNING | IFF_BROADCAST ) )
00150 nic_set_flags(nic, flags | IFF_UP | IFF_RUNNING | IFF_BROADCAST);
00151
00152 if ( ( ifx->set & PUMP_INTFINFO_HAS_MTU ) && ( ifx->mtu ) )
00153 nic_set_mtu(nic, ifx->mtu);
00154
00155 tag = "set link";
00156 if ( (err = - nic_update ( nic )) > 0 )
00157 {
00158 nic_close(&ifx->nh);
00159 goto return_emsg;
00160 }
00161
00162 if ( (ifx->ip.sa_family != AF_INET) && (ifx->ip.sa_family != AF_INET6) )
00163 {
00164 nic_close(&ifx->nh);
00165 return NULL;
00166 }
00167
00168 addr = nic_addr( ifx->nh, ifx->ip );
00169 uint8_t prefix = 0;
00170 uint8_t isIPv4 = 0;
00171
00172 if ( addr == 0L )
00173 {
00174 err = ENOMEM;
00175 tag = "new addr";
00176 nic_close(&ifx->nh);
00177 goto return_emsg;
00178 }
00179
00180 if( ifx->netmask.sa_family )
00181 switch( ifx->ip.sa_family )
00182 {
00183 case AF_INET:
00184
00185 isIPv4 = 1;
00186
00187 if ( ip_v4_addr( &(ifx->netmask) ) )
00188 {
00189 nic_addr_set_prefix
00190 ( addr,
00191 prefix = ip_v4_netmask_to_prefix( &(ifx->netmask) )
00192 );
00193 }
00194 break;
00195
00196 case AF_INET6:
00197
00198 if ( ifx->ipv6_prefixlen )
00199 {
00200 nic_addr_set_prefix
00201 ( addr,
00202 ifx->ipv6_prefixlen
00203 );
00204 }
00205 break;
00206 }
00207
00208 if ( ifx->broadcast.sa_family ) {
00209 nic_addr_set_broadcast
00210 (
00211 addr,
00212 ifx->broadcast
00213 );
00214 } else if ( prefix && isIPv4 ) {
00215 nic_addr_set_broadcast
00216 (
00217 addr,
00218 ip_v4_broadcast( &(ifx->ip), prefix )
00219 );
00220 }
00221
00222 tag = "create addr";
00223
00224 if( (err = - nic_add_address( nic, addr )) > 0 )
00225 {
00226 nic_addr_free(addr);
00227 nic_close(&ifx->nh);
00228 goto return_emsg;
00229 }
00230
00231
00232
00233
00234
00235 route = 0;
00236
00237 if( ifx->gateway.sa_family )
00238 {
00239 tag = "new route";
00240 route =
00241 nic_route_new
00242 ( ifx->nh,
00243 nic_get_index(nic),
00244 0L,0,
00245 &ifx->gateway,
00246 -1,
00247 -1,
00248 -1,
00249 -1,
00250 -1,
00251 0L,
00252 0L,
00253 0
00254 );
00255
00256 if( route == 0 )
00257 {
00258 err = ENOMEM;
00259 nic_addr_free(addr);
00260 nic_close(&ifx->nh);
00261 goto return_emsg;
00262 }
00263
00264 tag = "create route";
00265
00266 if((err = - nic_add_route( route )) > 0)
00267 {
00268 nic_route_free(route);
00269 nic_addr_free(addr);
00270 nic_close(&ifx->nh);
00271 goto return_emsg;
00272 }
00273 }
00274
00275 nic_route_free(route);
00276 nic_addr_free(addr);
00277 nic_close(&ifx->nh);
00278 return NULL;
00279
00280 return_emsg:
00281 snprintf(buf,512, "pumpSetupInterface failed: %s - %d: %s.",
00282 tag, err, strerror(err)
00283 );
00284 return buf;
00285 }
00286
00287 extern int asprintf(char **strp, const char *fmt, ...);
00288
00289 static void
00290 ifxDHCPv6( struct pumpNetIntf * ifx )
00291 {
00292 IPaddr_t addr = STAILQ_FIRST( &(ifx->dhcp_nic->dhcpv6->address_list) )->addr;
00293 if( ifx->set & PUMP_INTFINFO_HAS_IP )
00294 {
00295 ifx->ipv6 = nic_ip_addr( addr );
00296 if( (ifx->ipv6_prefixlen = nic_addr_get_prefix( addr )) > 0 )
00297 ifx->set |= PUMP_INTFINFO_HAS_IPV6_PREFIX;
00298 ifx->set |= PUMP_INTFINFO_HAS_IPV6_IP;
00299 }else
00300 {
00301 ifx->ip = nic_ip_addr( addr );
00302 ifx->set |= PUMP_INTFINFO_HAS_IP;
00303 ifx->ipv6_prefixlen = nic_addr_get_prefix( addr );
00304 if ( ifx->ipv6_prefixlen )
00305 {
00306 ifx->network = ip_mask(&ifx->ip, ifx->ipv6_prefixlen);
00307 ifx->set |= PUMP_INTFINFO_HAS_NETWORK;
00308 }
00309 }
00310 if( !STAILQ_EMPTY(&(ifx->dhcp_nic->dhcpv6->dns_list)) )
00311 {
00312 IPaddr_list_node_t *n=0;
00313 STAILQ_FOREACH(n, &(ifx->dhcp_nic->dhcpv6->dns_list), link)
00314 {
00315 if( ifx->numDns >= MAX_DNS_SERVERS )
00316 break;
00317 ifx->dnsServers[ ifx->numDns++ ] = nic_ip_addr( n->addr );
00318 ifx->set |= PUMP_NETINFO_HAS_DNS;
00319 }
00320 }
00321 if( (ifx->set & PUMP_NETINFO_HAS_DNS)
00322 && ifx->dhcp_nic->dhcpv6->search_list
00323 )
00324 {
00325 char *s=ifx->domain;
00326 asprintf
00327 ( &(ifx->domain),
00328 "%s%s%s",
00329 s ? s : "",
00330 s ? " " : "" ,
00331 ifx->dhcp_nic->dhcpv6->search_list
00332 );
00333 if( s )
00334 free(s);
00335 ifx->set |= PUMP_NETINFO_HAS_DOMAIN;
00336 }
00337 }
00338
00339 static void
00340 ifxDHCPv4( struct pumpNetIntf *ifx )
00341 {
00342 IPaddr_t addr = STAILQ_FIRST( &(ifx->dhcp_nic->dhcpv4->address_list) )->addr;
00343 if( ifx->set & PUMP_INTFINFO_HAS_IP )
00344 {
00345 ifx->ipv4 = nic_ip_addr( addr );
00346 ifx->set |= PUMP_INTFINFO_HAS_IPV4_IP;
00347 }else
00348 {
00349 ifx->ip = nic_ip_addr( addr );
00350 ifx->set |= PUMP_INTFINFO_HAS_IP;
00351 if ( nic_addr_get_prefix( addr ) )
00352 {
00353 ifx->network = ip_mask(&ifx->ip, nic_addr_get_prefix( addr ) );
00354 ifx->set |= PUMP_INTFINFO_HAS_NETWORK;
00355 }
00356 }
00357 if ( nic_addr_get_prefix( addr ) )
00358 {
00359 ifx->netmask = ip_v4_prefix_to_netmask( nic_addr_get_prefix( addr ) );
00360 ifx->set |= PUMP_INTFINFO_HAS_NETMASK;
00361
00362 ip_addr_t broadcast = nic_addr_get_broadcast( addr );
00363 if( broadcast.sa_family )
00364 {
00365 ifx->broadcast = broadcast;
00366 ifx->set |= PUMP_INTFINFO_HAS_BROADCAST;
00367 }
00368 }
00369 if( ifx->dhcp_nic->dhcpv4
00370 &&( !STAILQ_EMPTY( &( ifx->dhcp_nic->dhcpv4->route_list )) )
00371 )
00372 {
00373 IProute_list_node_t *n;
00374 STAILQ_FOREACH( n, &( ifx->dhcp_nic->dhcpv4->route_list ), link )
00375 {
00376 ip_addr_t dst = nic_route_get_dst( n->route );
00377 ip_addr_t gw = nic_route_get_gateway( n->route );
00378 uint8_t dst_len = nic_route_get_dst_len( n->route );
00379 if( (dst.sa_family == 0)
00380 &&(dst_len == 0)
00381 &&(gw.sa_family == AF_INET)
00382 )
00383 {
00384 ifx->gateway = gw;
00385 ifx->set |= PUMP_NETINFO_HAS_GATEWAY;
00386 break;
00387 }
00388 }
00389 }
00390 if( ifx->dhcp_nic->dhc4ctl
00391 && dhcpv4_mtu_option( ifx->dhcp_nic->dhc4ctl )
00392 )
00393 {
00394 ifx->mtu = dhcpv4_mtu_option( ifx->dhcp_nic->dhc4ctl );
00395 ifx->set |= PUMP_INTFINFO_HAS_MTU;
00396 }
00397 if( ifx->dhcp_nic->dhcpv4->lease.dhcp4_lease )
00398 {
00399 DHCPv4_lease *lease=ifx->dhcp_nic->dhcpv4->lease.dhcp4_lease;
00400 if ( lease->server_address.s_addr != 0 )
00401 {
00402 ifx->nextServer = ip_addr_in(&(lease->server_address));
00403 ifx->set |= PUMP_INTFINFO_HAS_NEXTSERVER;
00404 }
00405 if ( lease->filename )
00406 {
00407 ifx->bootFile = strdup( lease->filename );
00408 ifx->set |= PUMP_INTFINFO_HAS_BOOTFILE;
00409 }
00410 }
00411
00412 if( !STAILQ_EMPTY(&(ifx->dhcp_nic->dhcpv4->dns_list)) )
00413 {
00414 IPaddr_list_node_t *n=0;
00415 STAILQ_FOREACH(n, &(ifx->dhcp_nic->dhcpv4->dns_list), link)
00416 {
00417 if( ifx->numDns >= MAX_DNS_SERVERS )
00418 break;
00419 ifx->dnsServers[ ifx->numDns++ ] = nic_ip_addr( n->addr );
00420 ifx->set |= PUMP_NETINFO_HAS_DNS;
00421 }
00422 }
00423 if( (ifx->set & PUMP_NETINFO_HAS_DNS)
00424 && ifx->dhcp_nic->dhcpv4->search_list
00425 )
00426 {
00427 char *s=ifx->domain;
00428 asprintf
00429 ( &(ifx->domain),
00430 "%s%s%s",
00431 s ? s : "",
00432 s ? " " : "" ,
00433 ifx->dhcp_nic->dhcpv4->search_list
00434 );
00435 if( s )
00436 free(s);
00437 ifx->set |= PUMP_NETINFO_HAS_DOMAIN;
00438 }
00439 if( ifx->dhcp_nic->dhcpv4->host_name )
00440 {
00441 ifx->set |= PUMP_NETINFO_HAS_HOSTNAME;
00442 if(ifx->hostname)
00443 free(ifx->hostname);
00444 ifx->hostname = strdup( ifx->dhcp_nic->dhcpv4->host_name );
00445 }
00446 }
00447
00448 char * pumpDhcpClassRun
00449 ( struct pumpNetIntf * ifx,
00450 char * hostname,
00451 char * vendor_class,
00452 DHCP_Preference dhcp_preference ,
00453 LIBDHCP_Capability dhcp_capability ,
00454 time_t timeout,
00455 void (*logger)(void*,int,char*,va_list),
00456 int log_level
00457 )
00458 {
00459 char *disret;
00460 disret = pumpDisableInterface(ifx->device);
00461 if (disret != NULL)
00462 return disret;
00463
00464 assert(!ifx->nh);
00465
00466 if (!(ifx->nh = nic_open(NETLINK_ROUTE)))
00467 return pump_errors[OOM];
00468
00469 if ( logger )
00470 {
00471 nic_set_va_logger(ifx->nh, (NIC_VA_Error_Handler_t)logger, &ifx);
00472 nic_set_loglevel(ifx->nh, log_level );
00473 }
00474 ifx->dhcp_nic =
00475 dhcp_nic
00476 (
00477 ifx->nh,
00478 dhcp_preference,
00479 ifx->device,
00480 dhcp_capability,
00481 timeout,
00482 (LIBDHCP_Error_Handler)logger,
00483 log_level,
00484 "-V", vendor_class,
00485 hostname ? "-H" : 0L,
00486 hostname ? hostname : 0L,
00487 0L
00488 );
00489 if ( ifx->dhcp_nic )
00490 {
00491
00492
00493
00494
00495 if ( ( ifx->dhcp_nic->dhcpv4 && ifx->dhcp_nic->dhcpv6 )
00496 &&( !STAILQ_EMPTY( &( ifx->dhcp_nic->dhcpv4->address_list )) )
00497 &&( !STAILQ_EMPTY( &( ifx->dhcp_nic->dhcpv6->address_list )) )
00498 )
00499 {
00500 if ( dhcp_preference & IPv6_PREFERENCE )
00501 {
00502 ifxDHCPv6( ifx );
00503 ifxDHCPv4( ifx );
00504 }else
00505 {
00506 ifxDHCPv4( ifx );
00507 ifxDHCPv6( ifx );
00508 }
00509 }else
00510 if( ifx->dhcp_nic->dhcpv4
00511 &&( !STAILQ_EMPTY( &( ifx->dhcp_nic->dhcpv4->address_list )) )
00512 )
00513 {
00514 ifxDHCPv4( ifx );
00515 }else
00516 if( ifx->dhcp_nic->dhcpv6
00517 &&( !STAILQ_EMPTY( &( ifx->dhcp_nic->dhcpv6->address_list )) )
00518 )
00519 {
00520 ifxDHCPv6( ifx );
00521 }
00522 ifx->nh = NULL;
00523 }else
00524 {
00525 nic_close(&ifx->nh);
00526 return pump_errors[DHCP_FAILED];
00527 }
00528 return NULL;
00529 }
00530
00531 char * pumpDisableInterface(char * device)
00532 {
00533 static char buf[512];
00534 struct ifreq req;
00535 int s, e;
00536
00537 s = socket(AF_INET, SOCK_DGRAM, 0);
00538
00539 memset(&req,0,sizeof(req));
00540
00541 strcpy(req.ifr_name, device);
00542 if (ioctl(s, SIOCGIFFLAGS, &req)) {
00543 e = errno;
00544 snprintf(buf, 512,
00545 "ioctl SIOCGIFFLAGS failed: %d %s\n",
00546 e, strerror(e)
00547 );
00548 close(s);
00549 return &(buf[0]);
00550 }
00551
00552 req.ifr_flags &= ~(IFF_UP | IFF_RUNNING);
00553 if (ioctl(s, SIOCSIFFLAGS, &req)) {
00554 e = errno;
00555 snprintf(buf, 512,
00556 "ioctl SIOCSIFFLAGS failed: %d %s\n",
00557 e, strerror(e)
00558 );
00559 close(s);
00560 return &(buf[0]);
00561 }
00562
00563 close(s);
00564
00565 return NULL;
00566 }
00567
00568
00569
00570