📄 dhclient.c
字号:
void send_discover (cpp) void *cpp;{ struct client_state *client = cpp; int result; int interval; int increase = 1; /* Figure out how long it's been since we started transmitting. */ interval = cur_time - client -> first_sending; /* If we're past the panic timeout, call the script and tell it we haven't found anything for this interface yet. */ if (interval > client -> config -> timeout) { state_panic (client); return; } /* If we're selecting media, try the whole list before doing the exponential backoff, but if we've already received an offer, stop looping, because we obviously have it right. */ if (!client -> offered_leases && client -> config -> media) { int fail = 0; again: if (client -> medium) { client -> medium = client -> medium -> next; increase = 0; } if (!client -> medium) { if (fail) log_fatal ("No valid media types for %s!", client -> interface -> name); client -> medium = client -> config -> media; increase = 1; } log_info ("Trying medium \"%s\" %d", client -> medium -> string, increase); script_init (client, "MEDIUM", client -> medium); if (script_go (client)) { fail = 1; goto again; } } /* If we're supposed to increase the interval, do so. If it's currently zero (i.e., we haven't sent any packets yet), set it to one; otherwise, add to it a random number between zero and two times itself. On average, this means that it will double with every transmission. */ if (increase) { if (!client -> interval) client -> interval = client -> config -> initial_interval; else client -> interval += ((random () >> 2) % (2 * client -> interval)); /* Don't backoff past cutoff. */ if (client -> interval > client -> config -> backoff_cutoff) client -> interval = ((client -> config -> backoff_cutoff / 2) + ((random () >> 2) % client -> config -> backoff_cutoff)); } else if (!client -> interval) client -> interval = client -> config -> initial_interval; /* If the backoff would take us to the panic timeout, just use that as the interval. */ if (cur_time + client -> interval > client -> first_sending + client -> config -> timeout) client -> interval = (client -> first_sending + client -> config -> timeout) - cur_time + 1; /* Record the number of seconds since we started sending. */ if (interval < 65536) client -> packet.secs = htons (interval); else client -> packet.secs = htons (65535); client -> secs = client -> packet.secs; log_info ("DHCPDISCOVER on %s to %s port %d interval %ld", client -> name ? client -> name : client -> interface -> name, inet_ntoa (sockaddr_broadcast.sin_addr), ntohs (sockaddr_broadcast.sin_port), (long)(client -> interval)); /* Send out a packet. */ result = send_packet (client -> interface, (struct packet *)0, &client -> packet, client -> packet_length, inaddr_any, &sockaddr_broadcast, (struct hardware *)0); add_timeout (cur_time + client -> interval, send_discover, client, 0, 0);}/* state_panic gets called if we haven't received any offers in a preset amount of time. When this happens, we try to use existing leases that haven't yet expired, and failing that, we call the client script and hope it can do something. */void state_panic (cpp) void *cpp;{ struct client_state *client = cpp; struct client_lease *loop; struct client_lease *lp; loop = lp = client -> active; log_info ("No DHCPOFFERS received."); /* We may not have an active lease, but we may have some predefined leases that we can try. */ if (!client -> active && client -> leases) goto activate_next; /* Run through the list of leases and see if one can be used. */ while (client -> active) { if (client -> active -> expiry > cur_time) { log_info ("Trying recorded lease %s", piaddr (client -> active -> address)); /* Run the client script with the existing parameters. */ script_init (client, "TIMEOUT", client -> active -> medium); script_write_params (client, "new_", client -> active); if (client -> alias) script_write_params (client, "alias_", client -> alias); /* If the old lease is still good and doesn't yet need renewal, go into BOUND state and timeout at the renewal time. */ if (!script_go (client)) { if (cur_time < client -> active -> renewal) { client -> state = S_BOUND; log_info ("bound: renewal in %ld %s.", (long)(client -> active -> renewal - cur_time), "seconds"); add_timeout (client -> active -> renewal, state_bound, client, 0, 0); } else { client -> state = S_BOUND; log_info ("bound: immediate renewal."); state_bound (client); } reinitialize_interfaces (); go_daemon (); return; } } /* If there are no other leases, give up. */ if (!client -> leases) { client -> leases = client -> active; client -> active = (struct client_lease *)0; break; } activate_next: /* Otherwise, put the active lease at the end of the lease list, and try another lease.. */ for (lp = client -> leases; lp -> next; lp = lp -> next) ; lp -> next = client -> active; if (lp -> next) { lp -> next -> next = (struct client_lease *)0; } client -> active = client -> leases; client -> leases = client -> leases -> next; /* If we already tried this lease, we've exhausted the set of leases, so we might as well give up for now. */ if (client -> active == loop) break; else if (!loop) loop = client -> active; } /* No leases were available, or what was available didn't work, so tell the shell script that we failed to allocate an address, and try again later. */ if (onetry) { if (!quiet) log_info ("Unable to obtain a lease on first try.%s", " Exiting."); exit (2); } log_info ("No working leases in persistent database - sleeping."); script_init (client, "FAIL", (struct string_list *)0); if (client -> alias) script_write_params (client, "alias_", client -> alias); script_go (client); client -> state = S_INIT; add_timeout (cur_time + ((client -> config -> retry_interval + 1) / 2 + (random () % client -> config -> retry_interval)), state_init, client, 0, 0); go_daemon ();}void send_request (cpp) void *cpp;{ struct client_state *client = cpp; int result; int interval; struct sockaddr_in destination; struct in_addr from; /* Figure out how long it's been since we started transmitting. */ interval = cur_time - client -> first_sending; /* If we're in the INIT-REBOOT or REQUESTING state and we're past the reboot timeout, go to INIT and see if we can DISCOVER an address... */ /* XXX In the INIT-REBOOT state, if we don't get an ACK, it means either that we're on a network with no DHCP server, or that our server is down. In the latter case, assuming that there is a backup DHCP server, DHCPDISCOVER will get us a new address, but we could also have successfully reused our old address. In the former case, we're hosed anyway. This is not a win-prone situation. */ if ((client -> state == S_REBOOTING || client -> state == S_REQUESTING) && interval > client -> config -> reboot_timeout) { cancel: client -> state = S_INIT; cancel_timeout (send_request, client); state_init (client); return; } /* If we're in the reboot state, make sure the media is set up correctly. */ if (client -> state == S_REBOOTING && !client -> medium && client -> active -> medium ) { script_init (client, "MEDIUM", client -> active -> medium); /* If the medium we chose won't fly, go to INIT state. */ if (script_go (client)) goto cancel; /* Record the medium. */ client -> medium = client -> active -> medium; } /* If the lease has expired, relinquish the address and go back to the INIT state. */ if (client -> state != S_REQUESTING && cur_time > client -> active -> expiry) { /* Run the client script with the new parameters. */ script_init (client, "EXPIRE", (struct string_list *)0); script_write_params (client, "old_", client -> active); if (client -> alias) script_write_params (client, "alias_", client -> alias); script_go (client); /* Now do a preinit on the interface so that we can discover a new address. */ script_init (client, "PREINIT", (struct string_list *)0); if (client -> alias) script_write_params (client, "alias_", client -> alias); script_go (client); client -> state = S_INIT; state_init (client); return; } /* Do the exponential backoff... */ if (!client -> interval) client -> interval = client -> config -> initial_interval; else { client -> interval += ((random () >> 2) % (2 * client -> interval)); } /* Don't backoff past cutoff. */ if (client -> interval > client -> config -> backoff_cutoff) client -> interval = ((client -> config -> backoff_cutoff / 2) + ((random () >> 2) % client -> interval)); /* If the backoff would take us to the expiry time, just set the timeout to the expiry time. */ if (client -> state != S_REQUESTING && cur_time + client -> interval > client -> active -> expiry) client -> interval = client -> active -> expiry - cur_time + 1; /* If the lease T2 time has elapsed, or if we're not yet bound, broadcast the DHCPREQUEST rather than unicasting. */ if (client -> state == S_REQUESTING || client -> state == S_REBOOTING || cur_time > client -> active -> rebind) destination.sin_addr = sockaddr_broadcast.sin_addr; else memcpy (&destination.sin_addr.s_addr, client -> destination.iabuf, sizeof destination.sin_addr.s_addr); destination.sin_port = remote_port; destination.sin_family = AF_INET;#ifdef HAVE_SA_LEN destination.sin_len = sizeof destination;#endif if (client -> state == S_RENEWING || client -> state == S_REBINDING) memcpy (&from, client -> active -> address.iabuf, sizeof from); else from.s_addr = INADDR_ANY; /* Record the number of seconds since we started sending. */ if (client -> state == S_REQUESTING) client -> packet.secs = client -> secs; else { if (interval < 65536) client -> packet.secs = htons (interval); else client -> packet.secs = htons (65535); } log_info ("DHCPREQUEST on %s to %s port %d", client -> name ? client -> name : client -> interface -> name, inet_ntoa (destination.sin_addr), ntohs (destination.sin_port)); if (destination.sin_addr.s_addr != INADDR_BROADCAST && fallback_interface) result = send_packet (fallback_interface, (struct packet *)0, &client -> packet, client -> packet_length, from, &destination, (struct hardware *)0); else /* Send out a packet. */ result = send_packet (client -> interface, (struct packet *)0, &client -> packet, client -> packet_length, from, &destination, (struct hardware *)0); add_timeout (cur_time + client -> interval, send_request, client, 0, 0);}void send_decline (cpp) void *cpp;{ struct client_state *client = cpp; int result; log_info ("DHCPDECLINE on %s to %s port %d", client -> name ? client -> name : client -> interface -> name, inet_ntoa (sockaddr_broadcast.sin_addr), ntohs (sockaddr_broadcast.sin_port)); /* Send out a packet. */ result = send_packet (client -> interface, (struct packet *)0, &client -> packet, client -> packet_length, inaddr_any, &sockaddr_broadcast, (struct hardware *)0);}void send_release (cpp) void *cpp;{ struct client_state *client = cpp; int result; struct sockaddr_in destination; struct in_addr from; memcpy (&from, client -> active -> address.iabuf, sizeof from); memcpy (&destination.sin_addr.s_addr, client -> destination.iabuf, sizeof destination.sin_addr.s_addr); destination.sin_port = remote_port; destination.sin_family = AF_INET;#ifdef HAVE_SA_LEN destination.sin_len = sizeof destination;#endif /* Set the lease to end now, so that we don't accidentally reuse it if we restart before the old expiry time. */ client -> active -> expiry = client -> active -> renewal = client -> active -> rebind = cur_time; if (!write_client_lease (client, client -> active, 1, 1)) { log_error ("Can't release lease: lease write failed."); return; } log_info ("DHCPRELEASE on %s to %s port %d", client -> name ? client -> name : client -> interface -> name, inet_ntoa (destination.sin_addr), ntohs (destination.sin_port)); if (fallback_interface) result = send_packet (fallback_interface, (struct packet *)0, &client -> packet, client -> packet_length, from, &destination, (struct hardware *)0); else /* Send out a packet. */ result = send_packet (client -> interface, (struct packet *)0, &client -> packet, client -> packet_length, from, &destination, (struct hardware *)0);}void make_client_options (client, lease, type, sid, rip, prl, op) struct client_state *client; struct client_lease *lease; u_int8_t *type; struct option_cache *sid; struct iaddr *rip; u_int32_t *prl; struct option_state **op;{ unsigned i; struct option_cache *oc; struct buffer *bp = (struct buffer *)0; /* If there are any leftover options, get rid of them. */ if (*op) option_state_dereference (op, MDL);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -