📄 dhcp-client-states.c
字号:
if(passed_ip == NULL) { FATAL_MESSAGE("No IP address passed. Cannot perform system configuration."); } if(memcmp(&interface_ip, passed_ip, IP_ADDR_LEN)) { INFO_MESSAGE("using ARP to detect address collision"); if(!arp_discover_hardware_address(dc->rawnet, 1, 5, *passed_ip, ð_addr)) { ERROR_MESSAGE("DHCP server assigned us a used address. Declining."); client_decline(dc); /* sleep for up to ten seconds: fixme: make this configurable. */ INFO_MESSAGE("sleeping before retry (for %"PRIu16" seconds)", 10); client_cache_delete_cache(dc->cache); sleep_random(10); return STATE_INIT; } } /* since we're going to use this address, let's reply for it * and let everyone know we're using it. */ if(client_broadcast_arp_reply(dc, *passed_ip) < 0) { return STATE_FATAL_ERROR; } client_setup_timers(dc); do_sysconf(options, dc, STATE_SETUP); dhcp_opt_destroy_option_list(options); return STATE_BOUND;}/* utility state: call this if reinitializing our client control * useful when recreating the control (e.g. after a fork). */int client_reinitialize(dhcp_client_control_t *dc){ client_setup_timers(dc); return 0;}/****************** * check routines * ******************//* check the requested options */static int client_check_requested_options(dhcp_client_control_t *dc){ eth_addr_t eth_addr; ip_addr_t ip_addr; char *eth_addr_string; char *ip_addr_string; uint8_t *required_options; uint8_t received_options[MAX_OPTIONS_HANDLED_NUM]; dhcp_opt_t *dhcp_option; int i; /* get the mac address, and ip address from the packet. */ ip_addr = ip_get_src_addr(dc->rawnet->ip_p); eth_addr = eth_get_src_addr(dc->rawnet->ether_p); /* find out if we have a list of required options. */ required_options = client_conf_get_opt_required_bit_array(dc->conf, ip_addr, eth_addr); if(required_options == NULL) { WARN_MESSAGE("no required options set. accepting first response."); return 1; } /* build our received options array. */ memset(received_options, 0, sizeof(received_options)); dhcp_reset_option_seek(dc->rawnet->dhcp_p); while((dhcp_option = dhcp_get_next_option(dc->rawnet->dhcp_p)) != NULL) { /* if it's in our range fill it in or ignore it and give a warning. */ if(dhcp_opt_get_tag(dhcp_option) > MAX_OPTIONS_HANDLED) { WARN_MESSAGE("ignoring received option tag which is out of our range: %d", dhcp_opt_get_tag(dhcp_option)); continue; } received_options[dhcp_opt_get_tag(dhcp_option)] = 1; } /* make sure everything in our required option list is in our requested option list. */ for(i = 0;i < MAX_OPTIONS_HANDLED;i++) { if(required_options[i] && !received_options[i]) { /* make the strings of the addresses. */ eth_addr_string = eth_addr_to_string(eth_addr); ip_addr_string = ip_addr_to_string(ip_addr); WARN_MESSAGE("ignoring offer from server (%s : %s) : failed to supply required option: %s", ip_addr_string, eth_addr_string, dhcp_option_printable_string_get(i)); xfree(ip_addr_string); xfree(eth_addr_string); return 0; } } return 1;}/* basic DHCP test on incoming rawnet packet. */static int client_check_dhcp(dhcp_client_control_t *dc){ /* check for generic dhcp response. * we check for type, * validity, matching xid, and * matching server source port */ /* is rawnet happy with the packet? */ if(((!rawnet_is_valid(dc->rawnet)) && /* is it a DHCP packet? */ (dc->rawnet->type != RAWNET_DHCP) && /* does the XID match up? */ (dhcp_get_xid(dc->rawnet->dhcp_p) != dc->xid) && /* is it from a server? */ (udp_get_src_port(dc->rawnet->udp_p) != dc->server_port))) return 0; /* great: valid dhcp response. */ return 1;}/* check for valid discover responses. */static int client_check_discover(void *arg){ dhcp_client_control_t *dc = arg; /* check for a valid dhcp packet. */ if(client_check_dhcp(dc) && /* check that the type is an offer. */ dhcp_is_type(dc->rawnet->dhcp_p, DHCP_OFFER_TM) && /* check if the requested options match what we want. */ client_check_requested_options(dc)) { return 1; } else { return 0; }}/* check for valid request responses. */static int client_check_request(void *arg){ dhcp_client_control_t *dc = arg; if(client_check_dhcp(dc) && (dhcp_is_type(dc->rawnet->dhcp_p, DHCP_DHCPACK_TM) || dhcp_is_type(dc->rawnet->dhcp_p, DHCP_DHCPNAK_TM))) return 1; else return 0;}/* check for valid renew response. */static int client_check_renew(void *arg){ /* we're expecting the same as request :-) */ return (client_check_request(arg));}/* check for valid renew response. */static int client_check_rebind(void *arg){ /* we're expecting the same as request :-) */ return (client_check_request(arg));}/*************************** * client states * ***************************//* we have an offered lease we want and are selecting it. */int client_select(dhcp_client_control_t *dc){ list_t *dump_options; ip_addr_t yiaddr, siaddr; INFO_MESSAGE("performing DHCP SELECT"); /* This is not relay agent friendly: FIXME later. */ /* get the address on the packet as the server ip and hardware address. */ dhcp_client_set_server_ip_address(dc, ip_get_src_addr(dc->rawnet->ip_p)); dhcp_client_set_server_hw_address(dc, eth_get_src_addr(dc->rawnet->ether_p)); /* get the yiaddr/siaddr fields. */ yiaddr = dhcp_get_yiaddr(dc->rawnet->dhcp_p); siaddr = dhcp_get_siaddr(dc->rawnet->dhcp_p); /* if these options haven't been set, we can set them ourselves from the yiaddr/siaddr. */ if(!dhcp_have_option(dc->rawnet->dhcp_p, TAG_DHCP_REQUESTED_IP_ADDRESS)) { list_add(dc->rawnet->dhcp_p->options, dhcp_opt_create_from_internal_data(TAG_DHCP_REQUESTED_IP_ADDRESS, &yiaddr, IP_ADDR_LEN)); } if(!dhcp_have_option(dc->rawnet->dhcp_p, TAG_DHCP_SERVER_IDENTIFIER)) { list_add(dc->rawnet->dhcp_p->options, dhcp_opt_create_from_internal_data(TAG_DHCP_SERVER_IDENTIFIER, &siaddr, IP_ADDR_LEN)); } /* before dumping options strip options we never want to dump */ dump_options = client_remove_protocol_only_options(dc->rawnet->dhcp_p->options); /* dump cache file. */ if(client_cache_dump_options(dc->cache, dump_options)) { ERROR_MESSAGE("could not create temporary cache."); return STATE_FATAL_ERROR; } dhcp_opt_destroy_option_list(dump_options); return STATE_REQUEST;}/* init state: no lease exists. */int client_init(dhcp_client_control_t *dc){ list_t *options; int retval; int retries, timeout; uint8_t received_response = 0; INFO_MESSAGE("attempting DHCP DISCOVER"); /* get the number of retries we will attempt. */ retries = client_conf_get_dhcp_discovery_retries(dc->conf); timeout = client_conf_get_dhcp_discover_timeout(dc->conf); /* build discovery option list. */ options = client_build_discover_option_list(dc); /* when we begin transmitting discover we setup our secs * field. this is because relay agents and dhcp servers can * use this to see how bad off we are. */ dhcp_client_reset_secs(dc); /* update new xid per start of discovery . */ dhcp_client_update_xid(dc); /* build our dhcp discover packet. */ build_dhcp_discover(dc->rawnet, dc->xid, dc->secs, options); while(retries--) { retval = rawnet_packet_transact(dc->rawnet, dc, client_update_packet, client_check_discover, timeout); switch (retval) { case RAWNET_TIMEOUT: break; case RAWNET_OK: received_response = 1; break; case RAWNET_ERROR: ERROR_MESSAGE("received error from raw network handler."); return STATE_FATAL_ERROR; case RAWNET_USER_INTERRUPT: ERROR_MESSAGE("caught user interrupt."); return STATE_USER_INTERRUPT; default: FATAL_MESSAGE("invalid return value from raw network handler -- this a bug report it."); } if(received_response) /* if we got a response that passed our filters (and is good enough) then break here. */ break; } if(received_response) { /* just call client_select to select the lease and store the information. */ return client_select(dc); } else { /* otherwise we're out of retries and have not received a lease. */ return STATE_NO_LEASES; }}static int client_requesting_proc(dhcp_client_control_t *dc, int state){ list_t *options, *cache_options; int retval; int retries, timeout; uint8_t received_response = 0; INFO_MESSAGE("attempting DHCP REQUEST"); /* get number of retries we should attempt with DHCP REQUEST. */ retries = client_conf_get_dhcp_request_retries(dc->conf); timeout = client_conf_get_dhcp_request_timeout(dc->conf); /* Build options along with the options in our cache. */ options = client_build_request_option_list(dc); if(state == STATE_INIT_REBOOT) cache_options = client_cache_load_options(dc->cache, 0); /* get cache. */ else cache_options = client_cache_load_options(dc->cache, 1); /* get temporary cache. */ list_join(options, cache_options); /* destroys cache_options. */ build_dhcp_request_broadcast(dc->rawnet, dc->xid, dc->secs, 0, 0, options); while(retries--) { retval = rawnet_packet_transact(dc->rawnet, dc, NULL, client_check_request, timeout); switch (retval) { case RAWNET_TIMEOUT: break; /* timeout, do a retry. */ case RAWNET_OK: received_response = 1; break; case RAWNET_ERROR: ERROR_MESSAGE("received error from raw network handler."); return STATE_FATAL_ERROR; case RAWNET_USER_INTERRUPT: ERROR_MESSAGE("caught user interrupt."); return STATE_USER_INTERRUPT; default: FATAL_MESSAGE("invalid return value from raw network handler -- this a bug report it."); } if(received_response) break; } /* check for a valid response. */ if(received_response) { /* if we got a pack we're good to go, if we haven't * then we need to revert to discover state after waiting at least ten seconds. */ if(dhcp_is_type(dc->rawnet->dhcp_p, DHCP_DHCPACK_TM)) { /* if init-reboot then record the server which replied. */ if(state == STATE_INIT_REBOOT) { dhcp_client_set_server_ip_address(dc, ip_get_src_addr(dc->rawnet->ip_p)); dhcp_client_set_server_hw_address(dc, eth_get_src_addr(dc->rawnet->ether_p)); } else client_cache_update(dc->cache); return STATE_SETUP; } else { /* anything is else NACK because of our earlier test on the packet. */ INFO_MESSAGE("received NACK response to request. waiting for retry."); client_cache_delete_tmp_cache(dc->cache);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -