00001 /** 00002 * @defgroup OV Overview 00003 * @{ 00004 @verbatim 00005 ------------------------------------------------------------------------- 00006 LIBDHCP : library programming interface to the ISC DHCP and DHPv6 clients 00007 00008 An Overview 00009 00010 author: Jason Vas Dias<jvdias@redhat.com> Red Hat, Inc, May 2006 00011 ------------------------------------------------------------------------- 00012 @endverbatim 00013 00014 LIBDHCP enables programs to invoke the ISC dhclient (IPv4 DHCP) and DHCPv6 client 00015 (IPv6 DHCP) libraries, libdhcp4client and libdhcp6client, within one process, 00016 to use the lease objects returned to configure network interface parameters, 00017 and provides a full-featured Network Interface Configuration (NIC) library 00018 for static or dynamic network parameter configuration. 00019 00020 The primary, tested, intended interface is as follows, though there are quite a few 00021 other ways of using the code (by no means all of them bug free ! :-). 00022 00023 First, include the main interface header: 00024 00025 @code 00026 #include <libdhcp/dhcp_nic.h> 00027 @endcode 00028 00029 it will include all required headers from libdhcp. 00030 00031 Choose which IPv6/IPv4 DHCP policy you wish libdhcp to implement, 00032 from the enum type "DHCP_Preference" in dhcp_nic.h : 00033 @code 00034 DHCPv4_DISABLE = 1, \/\* Don't do IPv4 DHCP \*\/ 00035 DHCPv6_DISABLE = 2, \/\* Don't do IPv6 DHCP \*\/ 00036 IPv6_PREFERENCE = 4, \/\* Configure IPv6 addresses / routes / DNS first \*\/ 00037 DHCPv4_DISABLE_ADDRESSES = 8, \/\* Don't configure DHCPv4 addresses \*\/ 00038 DHCPv4_DISABLE_ROUTES = 16, \/\* Don't configure DHCPv4 routes \*\/ 00039 DHCPv4_DISABLE_RESOLVER = 32, \/\* Don't configure DHCPv4 resolv.conf entries \*\/ 00040 DHCPv6_DISABLE_ADDRESSES = 64, \/\* Don't configure DHCPv6 address (ie. use radvd) \*\/ 00041 DHCPv6_DISABLE_RESOLVER = 128,\/\* Don't configure DHCPv6 resolv.conf entries \*\/ 00042 DHCPv4_DISABLE_HOSTNAME_SET=256\/\* Don't set hostname if DHCPv4 host-name option sent \*\/ 00043 DHCP_ACCEPT_FIRST_LEASE = 512 \/\* If timeout == 0, v4 and v6 clients are in separate 00044 * processes; if this preference is set, the first client 00045 * to get a lease will cause that lease to be accepted 00046 * and the other client process to be terminated. \*\/ 00047 00048 @endcode 00049 00050 You can specify the "capabilities" the DHCP clients are allowed to exercise, with 00051 enum type "DHCP_Capability" from libdhcp.h: 00052 00053 @code 00054 \/\* DHCP client "capabilities" \*\/ 00055 DHCP_USE_LEASE_DATABASE = 1, \/\* use / do not use persistent lease database files \*\/ 00056 DHCP_USE_PID_FILE = 2, \/\* use / do not use pid file \*\/ 00057 \/\* 00058 * DHCPv6 supports these capabilities in process, 00059 * while the DHCPv4 client would fork and exec the dhclient-script to implement them if these 00060 * bits are set - otherwise, if no bits are set, the callback is called and the script is 00061 * not run. 00062 \*\/ 00063 DHCP_CONFIGURE_INTERFACES = 4, \/\* configure interfaces UP/DOWN as required \*\/ 00064 DHCP_CONFIGURE_ADDRESSES = 8, \/\* configure interface addresses as required \*\/ 00065 DHCP_CONFIGURE_ROUTES =16, \/\* configure routes as required \*\/ 00066 DHCP_CONFIGURE_RESOLVER =32, \/\* configure resolv.conf as required \*\/ 00067 \/\* DHCPv6 only: \*\/ 00068 DHCP_CONFIGURE_RADVD =64, \/\* configure radvd.conf & restart radvd as required \*\/ 00069 @endcode 00070 00071 Then, call the main dhcp interface function, 'do_dhcp' (from dhcp_nic.h) with the values you 00072 chose: 00073 00074 @code 00075 extern 00076 NIC_Res_t *do_dhcp 00077 ( 00078 DHCP_Preference preference, 00079 char *eth_if_name, 00080 LIBDHCP_Capability dhc_cap, 00081 time_t timeout, 00082 LIBDHCP_Error_Handler error_handler, 00083 uint8_t log_level, 00084 ... \/\* extra DHCPv4 dhclient arguments; 00085 * last arg MUST be 0 . 00086 \*\/ 00087 ); 00088 @endcode 00089 00090 The timeout is a hard timeout that each client has to contact the server, 00091 until it gives up. 00092 00093 If the timeout is 0, and neither DHCPv4_DISABLE nor DHCPv6_DISABLE is 00094 specified, then each client will be run in a separate process, and each 00095 client will try to contact the server indefinitely until a lease is 00096 obtained. 00097 00098 You can define an error handler to handle all debug / error / info 00099 log messages emanating from the clients: 00100 00101 @code 00102 int( *LIBDHCP_Error_Handler ) 00103 ( struct libdhcp_control_s *ctl, 00104 int priority, \/\* ala syslog(3): LOG_EMERG=0 - LOG_DEBUG=7 (+ LOG_FATAL=8 : finished -> 1) \*\/ 00105 const char *fmt, 00106 va_list ap 00107 ); 00108 @endcode 00109 00110 "log_level" in the dhcp_nic call sets the maximum level that will be logged. 00111 Two standard error handlers are defined: 00112 @verbatim 00113 libdhcp_stderr_logger : writes log messages to stderr 00114 libdhcp_syslogger : writes log messages to syslog 00115 @endverbatim 00116 No logging is done if "error_handler" is 0 . 00117 00118 You can specify any normal dhclient command line arg in the va_list . 00119 00120 ie. a call that specifies that libdhcp should runs DHCPv4 and DHCPv4, 00121 for interface named "eth0", with extra dhclient args to send the 00122 dhcp-client-identifier, vendor-class-identifier, and host-name would be: 00123 00124 @code 00125 NIC_Res_t r = 00126 dhcp_nic 00127 ( 0, 00128 "eth0", 00129 0, 00130 10, \/\* each client has 10 seconds to get a lease \*\/ 00131 libdhcp_stderr_logger, 00132 LOG_INFO, 00133 "-V","i386-redhat-fc6", 00134 "-I", "1:00:0D:60:CF:98:E3", 00135 "-H", "mypc", 00136 0 \/\* !!! THE ESSENTIAL TRAILING 0 !!! \*\/ 00137 ); 00138 @endcode 00139 This call would then actually invoke the clients in the same process as the 00140 caller (no forks / execs / system() calls involved) and would configure the 00141 network interface "eth0" with the parameters returned. 00142 00143 You may want to inspect and modify the network parameters returned by DHCP 00144 before going ahead and configuring the interface. For this, the 'dhcp_nic' 00145 function is provided: 00146 00147 @code 00148 extern 00149 DHCP_nic *dhcp_nic 00150 ( 00151 NLH_t nh, \/\* nic library handle \*\/ 00152 DHCP_Preference preference, 00153 char *eth_if_name, 00154 LIBDHCP_Capability dhc_cap, 00155 time_t timeout, 00156 LIBDHCP_Error_Handler error_handler, 00157 uint8_t log_level, 00158 ... \/\* extra DHCPv4 dhclient arguments; 00159 * last arg MUST be 0 . 00160 \*\/ 00161 ); 00162 @endcode 00163 00164 This returns a "Network Interface Configuration" ( NIC ) structure - well, actually 00165 two NIC structures, one for each client, encapsulated in the "DHCP_nic" structure - 00166 at this point, no actual interface configuration beyond setting the interface flags 00167 to (IFF_UP & IFF_RUNNING) would have been done. 00168 00169 ( That is, of course, only if you have both the DHCPv6 IPv6 DHCP dhcp6s 00170 server and the IPv4 DHCP ISC dhcpd server running on your network. 00171 An example working /etc/dhcp6s.conf for dhcp6s is: 00172 @verbatim 00173 --- 00174 # /etc/dhcp6s.conf 00175 interface eth0 { 00176 link eth0 { 00177 range fec0::10 to fec0::19/64; 00178 }; 00179 }; 00180 --- 00181 - see 'man 5 dhcps.conf' and 'man 5 dhcpd.conf'. 00182 @endverbatim 00183 ). 00184 00185 The dhcp_nic structure can then be configured on the network interfaces with the 00186 call: 00187 @code 00188 dhcp_nic_configure( nic ); 00189 @endcode 00190 00191 If this returns 0, all configuration parameters have been successfully applied. 00192 00193 libdhcp contains an interface to the 'libnl' (lib NETLINK) library, 00194 ( by Thomas Graf, http://people.suug.ch/~tgr/libnl/ ), in the 00195 "nic.[ch]" files, that implement its "Network Interface Configurator", 00196 which enables the DHCP client lease parameters to be configured on the 00197 network devices - it is also a full-featured static network configurator. 00198 00199 For example, you can use this function: 00200 00201 @code 00202 extern 00203 NIC_Res_t 00204 nic_configure 00205 ( 00206 NLH_t nh, 00207 NIC_t nic, 00208 IPaddr_list_t *addresses, 00209 IProute_list_t *routes, 00210 IPaddr_list_t *dns_servers, 00211 char *search_list, 00212 char *host_name 00213 ); 00214 @endcode 00215 00216 to configure a list of addresses and routes on an interface , 00217 and to configure resolv.conf and set the host name. 00218 Zero-valued pointer parameters are safely ignored. 00219 For instance, the calls : 00220 00221 @code 00222 NIC_t nic = nic_by_name("eth0"); 00223 IPaddr_t 00224 a1 = nic_addr_from_text("172.16.80.1/22"), 00225 a2 = nic_addr_from_text("192.168.2.1/16"), 00226 a3 = nic_addr_from_text("2006:0:0:5::18/64"), 00227 gw1= nic_addr_from_text("192.168.2.254"), 00228 n2 = nic_addr_from_text("2006:0:0:6::/64"), 00229 gw2= nic_addr_from_text("2006:0:0:5::100"), 00230 ns1= nic_addr_from_text("192.168.2.200"), 00231 ns2= nic_addr_from_text("2006:0:0:5::200"); 00232 int sa_len; 00233 IProute_t 00234 r1 = nic_route_new 00235 ( nh, 00236 nic_get_index(nic), 00237 0, \/\* destination: 0 means "default" \*\/ 00238 32, \/\* destination prefix bits - 32 for default \*\/ 00239 nic_addr_sa(gw1,&sa_len), \/\* gateway \*\/ 00240 -1, \/\* default scope: global \*\/ 00241 -1 , \/\* no priority: increase if more than one default! \*\/ 00242 -1, \/\* table: default (local) \*\/ 00243 -1\/\*no iif\*\/, 0L,0\/\*no src\*\/ 00244 ), 00245 r2 = nic_route_new 00246 ( nh, nic_get_index(nic), 00247 nic_addr_sa(n2,&sa_len), 00248 nic_addr_get_prefix(n2), 00249 nic_addr_sa(gw2,&sa_len), 00250 -1,-1,-1,-1, 0L, 0 00251 ); 00252 IPaddr_list_t 00253 al = nic_address_list_new(a1,a2,a3,0), 00254 nl = nic_address_list_new(ns2,ns1,0); 00255 IProute_list_t 00256 rl = nic_route_list_new(r1,r2,0); 00257 nic_set_flags( nic, IFF_UP | IFF_RUNNING ); 00258 nic_configure( nh, nic, al, rl, nl, "my.domain.com", "myhost"); 00259 @endcode 00260 00261 Would configure the "myhost.my.domain.com" interface eth0 with the 00262 addresses 172.16.80.1/22, 192.168.2.1/16, and 2006:0:0:5::18/64, 00263 the default gateway 192.168.2.254, the additional route 00264 '2006:0:0:6::/64 via 2006:0:0:5::100', and DNS nameservers 00265 192.168.2.200 and 2006:0:0:5::1, IFF all goes according to 00266 plan (and you are running the program as root!). 00267 00268 The complete details of each DHCP lease are also encapsulated in the 00269 DHCP_nic 'lease' field, including all the lease times - see 00270 'dhcp4_lease.h' and 'dhcp6_lease.h' for details. 00271 00272 DHCv6 does not return options of interest that are not handled by 00273 the default configurer, and there is no support in DHCPv6 for 00274 user defined options, as yet. 00275 00276 But ISC IPv4 DHCP returns MANY options that are not handled in libdhcp, 00277 and supports user defined options, and libdhcp fully supports this also. 00278 00279 Having obtained a DHCPv4_lease in a DHCP_nic 'nic' as nic->dhcp4_lease, 00280 you can define your own option handler: 00281 00282 @code 00283 void dhcp4_nic_option_handler( DHCPv4_option *option, void *arg ) 00284 { 00285 switch ( option->unicode ) 00286 { 00287 case DHCP_UNIVERSE: 00288 switch ( option->code ) 00289 case MY_OPTION_CODE: 00290 struct my_option *opt = (void*)&(option->value); 00291 ... 00292 } 00293 } 00294 @endcode 00295 00296 and the dhcp4_lease code will guarantee that the option is correctly 00297 laid out as a C structure according to the DHCP option format. 00298 00299 For instance, you could have in your server dhcpd.conf and client 00300 dhclient.conf: 00301 @verbatim 00302 ' 00303 option space redhat; 00304 option redhat.install-server code 1 = domain-name; 00305 option redhat.kickstart code 2 = string; 00306 option redhat.install-iso code 3 = string; 00307 option redhat.routes code 4 = array of { ip-address, int8, ip-address, int8, int16, int8, int32 }; 00308 ' 00309 @endverbatim 00310 00311 And in the dhcpd server's dhcpd.conf: 00312 @verbatim 00313 ' 00314 class "vendor-classes" { 00315 match option vendor-class-identifier; 00316 } 00317 00318 subclass "vendor-classes" "i386-redhat-fc6" { 00319 option redhat.install-server my.i386repo.server.com; 00320 option redhat.kickstart "i386-fc6.ks"; 00321 } 00322 00323 subclass "vendor-classes" "ia64-redhat-fc6" { 00324 option redhat.install-server my.ia64repo.server.com; 00325 option redhat.kickstart "ia64-fc6.ks"; 00326 } 00327 00328 option redhat.routes 1.2.3.4 2 4.3.2.1 1 512 2 0xfabdab, 00329 8.4.2.1 6 1.4.2.8 4 768 1 0xdabfab; 00330 00331 option dhcp.redhat-encapsulation code 128 = encapsulate redhat; 00332 ' 00333 @endverbatim 00334 00335 And the client must be configured to request these options 00336 in dhclient.conf: 00337 @verbatim 00338 request dhcp.redhat-encapsulation; 00339 @endverbatim 00340 00341 Then you can define an option handler to handle these options: 00342 00343 @code 00344 void dhcp4_nic_option_handler( DHCPv4_option *option, void *arg ) 00345 { 00346 switch ( option->unicode ) 00347 { 00348 case REDHAT_UNIVERSE: 00349 switch ( option->code ) 00350 case REDHAT_ROUTES: 00351 struct r_r 00352 { 00353 u_int32_t ip1; 00354 u_int8_t b1; 00355 u_int32_t ip2; 00356 u_int16_t s1; 00357 u_int8_t b2; 00358 i_int32_t i1; 00359 } * r = (void*) &(option->value), 00360 * e = &(((r_r*) &(option->value))[option->n_elements]); 00361 for(; r < e; r++) 00362 ... 00363 } 00364 } 00365 @endcode 00366 00367 and call the function: 00368 @code 00369 dhcpv4_process_options ( nic->lease.dhcpv4_lease, dhcp4_nic_option_handler, arg) 00370 @endcode 00371 and the dhcp4_nic_option_handler will be called for each DHCP optoin in the lease, 00372 and for the "REDHAT_ROUTES" option, the 'r_r' structure members will be correctly laid out 00373 for access by your C program. 00374 00375 00376 CAVEATS: 00377 00378 ABOVE ALL: USE AT YOUR OWN RISK ! the code is very new and is still in further 00379 development and refinement. 00380 00381 Please report any issues / suggestions / ideas via Red Hat Bugzilla or by email 00382 to jvdias@redhat.com. 00383 /**@}*/ 00384 /** 00385 * @defgroup LIBDHCP libdhcp library interface 00386 * API for libdhcp, a minimal interface to the ISC dhcp IPv4 client library, 00387 * libdhcp4client, and to the dhcpv6 DHCPv6 client library, libdhcp6client . 00388 * @defgroup IP Generic IP Addresses 00389 * Generic IP address representation and conversion utilities. 00390 * @defgroup DHCP DHCP Client Invocation and Control 00391 * @{ 00392 * Network Interface Configurator for BOTH the ISC DHCP IPv4 client library 00393 * and the DHCPv6 IPv6 client library. 00394 * @defgroup DHCPv4 IPv4 DHCP Client Control and Configuration 00395 * @{ 00396 * Network Interface Configurator for the ISC DHCP IPv4 client library. 00397 * @defgroup DHCPv4_lease IPv4 DHCP Lease Options 00398 * @defgroup 00399 * @} 00400 * @defgroup DHCPv6 IPv6 DHCP Client Control and Configuration 00401 * @{ 00402 * Network Interface Configurator for the DHCPv6 IPv6 client library. 00403 * @defgroup DHCPv6_lease IPv6 DHCP Lease Options 00404 * @defgroup 00405 * @} 00406 * @defgroup 00407 * @} 00408 * @defgroup NIC Network Interface Configurator 00409 * @{ 00410 * Provides facilities for configuring network interfaces, addresses, and routes, 00411 * with an interface to the libnl netlink library. 00412 * @defgroup NICH NIC Module Interface 00413 * NIC Module initialisation / shutdown and error logging. 00414 * @defgroup NICI Network Interfaces 00415 * Provides facilities for configuring network interface devices. 00416 * @defgroup NICA Addresses 00417 * Provides facilities for configuring addresses on network interfaces. 00418 * @defgroup NICR Routes 00419 * Provides facilities for configuring routes on network interfaces. 00420 * @defgroup NICG Global Configuration Operations 00421 * Provides facilites for configuring interfaces, address, routes, and resolver 00422 * with a single-call interface. 00423 * @defgroup 00424 * @} 00425 */