int udhcpd_main(int argc, char **argv) { fd_set rfds; struct timeval tv; int server_socket = -1, bytes, retval, max_sock; struct dhcpMessage packet; uint8_t *state, *server_id, *requested; uint32_t server_id_align, requested_align, static_lease_ip; unsigned timeout_end; unsigned num_ips; unsigned opt; struct option_set *option; struct dhcpOfferedAddr *lease, static_lease; opt = getopt32(argv, "fS"); argv += optind; if (!(opt & 1)) { /* no -f */ bb_daemonize_or_rexec(0, argv); logmode &= ~LOGMODE_STDIO; } if (opt & 2) { /* -S */ openlog(applet_name, LOG_PID, LOG_LOCAL0); logmode |= LOGMODE_SYSLOG; } /* Would rather not do read_config before daemonization - * otherwise NOMMU machines will parse config twice */ read_config(argv[0] ? argv[0] : DHCPD_CONF_FILE); /* Make sure fd 0,1,2 are open */ bb_sanitize_stdio(); /* Equivalent of doing a fflush after every \n */ setlinebuf(stdout); /* Create pidfile */ write_pidfile(server_config.pidfile); /* if (!..) bb_perror_msg("cannot create pidfile %s", pidfile); */ bb_info_msg("%s (v"BB_VER") started", applet_name); option = find_option(server_config.options, DHCP_LEASE_TIME); server_config.lease = LEASE_TIME; if (option) { memcpy(&server_config.lease, option->data + 2, 4); server_config.lease = ntohl(server_config.lease); } /* Sanity check */ num_ips = server_config.end_ip - server_config.start_ip + 1; if (server_config.max_leases > num_ips) { bb_error_msg("max_leases=%u is too big, setting to %u", (unsigned)server_config.max_leases, num_ips); server_config.max_leases = num_ips; } leases = xzalloc(server_config.max_leases * sizeof(*leases)); read_leases(server_config.lease_file); if (read_interface(server_config.interface, &server_config.ifindex, &server_config.server, server_config.arp)) { retval = 1; goto ret; } /* Setup the signal pipe */ udhcp_sp_setup(); timeout_end = monotonic_sec() + server_config.auto_time; while (1) { /* loop until universe collapses */ if (server_socket < 0) { server_socket = listen_socket(/*INADDR_ANY,*/ SERVER_PORT, server_config.interface); } max_sock = udhcp_sp_fd_set(&rfds, server_socket); if (server_config.auto_time) { tv.tv_sec = timeout_end - monotonic_sec(); tv.tv_usec = 0; } retval = 0; if (!server_config.auto_time || tv.tv_sec > 0) { retval = select(max_sock + 1, &rfds, NULL, NULL, server_config.auto_time ? &tv : NULL); } if (retval == 0) { write_leases(); timeout_end = monotonic_sec() + server_config.auto_time; continue; } if (retval < 0 && errno != EINTR) { DEBUG("error on select"); continue; } switch (udhcp_sp_read(&rfds)) { case SIGUSR1: bb_info_msg("Received a SIGUSR1"); write_leases(); /* why not just reset the timeout, eh */ timeout_end = monotonic_sec() + server_config.auto_time; continue; case SIGTERM: bb_info_msg("Received a SIGTERM"); goto ret0; case 0: break; /* no signal */ default: continue; /* signal or error (probably EINTR) */ } bytes = udhcp_recv_packet(&packet, server_socket); /* this waits for a packet - idle */ if (bytes < 0) { if (bytes == -1 && errno != EINTR) { DEBUG("error on read, %s, reopening socket", strerror(errno)); close(server_socket); server_socket = -1; } continue; } state = get_option(&packet, DHCP_MESSAGE_TYPE); if (state == NULL) { bb_error_msg("cannot get option from packet, ignoring"); continue; } /* Look for a static lease */ static_lease_ip = getIpByMac(server_config.static_leases, &packet.chaddr); if (static_lease_ip) { bb_info_msg("Found static lease: %x", static_lease_ip); memcpy(&static_lease.chaddr, &packet.chaddr, 16); static_lease.yiaddr = static_lease_ip; static_lease.expires = 0; lease = &static_lease; } else { lease = find_lease_by_chaddr(packet.chaddr); } switch (state[0]) { case DHCPDISCOVER: DEBUG("Received DISCOVER"); if (sendOffer(&packet) < 0) { bb_error_msg("send OFFER failed"); } /* circle test Stat. add by wangpu begin */ g_offercount ++; printf("Circle test: [DHCPS] send OFFER packet num:[%d]\n",g_offercount); memset(g_acCmd,0,sizeof(g_acCmd)); memset(g_interface,0,sizeof(g_interface)); sprintf(g_interface,"%s",server_config.interface); sprintf(g_acCmd,"echo %d > /var/circle/%s",g_offercount,g_interface); system(g_acCmd); /* circle test Stat. add by wangpu end */ break; case DHCPREQUEST: DEBUG("received REQUEST"); #if 0 /* ?¡¤??2a¨º? add by wangpu begin */ g_offercount ++; printf("Circle test: [DHCPS] send OFFER packet num:[%d]\n",g_offercount); memset(g_acCmd,0,sizeof(g_acCmd)); memset(g_interface,0,sizeof(g_interface)); sprintf(g_interface,"%s",server_config.interface); sprintf(g_acCmd,"echo %d > /var/circle/%s",g_offercount,g_interface); system(g_acCmd); /* ?¡¤??2a¨º? add by wangpu begin */ #endif requested = get_option(&packet, DHCP_REQUESTED_IP); server_id = get_option(&packet, DHCP_SERVER_ID); if (requested) memcpy(&requested_align, requested, 4); if (server_id) memcpy(&server_id_align, server_id, 4); if (lease) { if (server_id) { /* SELECTING State */ DEBUG("server_id = %08x", ntohl(server_id_align)); if (server_id_align == server_config.server && requested && requested_align == lease->yiaddr ) { sendACK(&packet, lease->yiaddr); } } else if (requested) { /* INIT-REBOOT State */ if (lease->yiaddr == requested_align) sendACK(&packet, lease->yiaddr); else sendNAK(&packet); } else if (lease->yiaddr == packet.ciaddr) { /* RENEWING or REBINDING State */ sendACK(&packet, lease->yiaddr); } else { /* don't know what to do!!!! */ sendNAK(&packet); } /* what to do if we have no record of the client */ } else if (server_id) { /* SELECTING State */ } else if (requested) { /* INIT-REBOOT State */ lease = find_lease_by_yiaddr(requested_align); if (lease) { if (lease_expired(lease)) { /* probably best if we drop this lease */ memset(lease->chaddr, 0, 16); /* make some contention for this address */ } else sendNAK(&packet); } else { uint32_t r = ntohl(requested_align); if (r < server_config.start_ip || r > server_config.end_ip ) { sendNAK(&packet); } /* else remain silent */ } } else { /* RENEWING or REBINDING State */ } break; case DHCPDECLINE: DEBUG("Received DECLINE"); if (lease) { memset(lease->chaddr, 0, 16); lease->expires = time(0) + server_config.decline_time; } break; case DHCPRELEASE: DEBUG("Received RELEASE"); if (lease) lease->expires = time(0); break; case DHCPINFORM: DEBUG("Received INFORM"); send_inform(&packet); break; default: bb_info_msg("Unsupported DHCP message (%02x) - ignoring", state[0]); } } ret0: retval = 0; ret: /*if (server_config.pidfile) - server_config.pidfile is never NULL */ remove_pidfile(server_config.pidfile); return retval; }
/* send a DHCP OFFER to a DHCP DISCOVER */ int sendOffer(struct dhcpMessage *oldpacket) { struct dhcpMessage packet; struct dhcpOfferedAddr *lease = NULL; u_int32_t req_align, lease_time_align = cur_iface->lease; char *req, *lease_time; struct option_set *curr; struct in_addr addr; //For static IP lease uint32_t static_lease_ip; //brcm begin char VIinfo[VENDOR_IDENTIFYING_INFO_LEN]; //brcm end init_packet(&packet, oldpacket, DHCPOFFER); //For static IP lease static_lease_ip = getIpByMac(cur_iface->static_leases, oldpacket->chaddr); if(!static_lease_ip) { /* the client is in our lease/offered table */ if ((lease = find_lease_by_chaddr(oldpacket->chaddr))) { if (!lease_expired(lease)) lease_time_align = lease->expires - time(0); packet.yiaddr = lease->yiaddr; /* Or the client has a requested ip */ } else if ((req = (char *)get_option(oldpacket, DHCP_REQUESTED_IP)) && /* Don't look here (ugly hackish thing to do) */ memcpy(&req_align, req, 4) && /* and the ip is in the lease range */ ntohl(req_align) >= ntohl(cur_iface->start) && ntohl(req_align) <= ntohl(cur_iface->end) && /* and its not already taken/offered */ ((!(lease = find_lease_by_yiaddr(req_align)) || /* or its taken, but expired */ lease_expired(lease)))) { packet.yiaddr = req_align; /* otherwise, find a free IP */ } else { packet.yiaddr = find_address(0); /* try for an expired lease */ if (!packet.yiaddr) packet.yiaddr = find_address(1); } if(!packet.yiaddr) { LOG(LOG_WARNING, "no IP addresses to give -- " "OFFER abandoned"); return -1; } if (!add_lease(packet.chaddr, packet.yiaddr, server_config.offer_time)) { LOG(LOG_WARNING, "lease pool is full -- " "OFFER abandoned"); return -1; } if ((lease_time = (char *)get_option(oldpacket, DHCP_LEASE_TIME))) { memcpy(&lease_time_align, lease_time, 4); lease_time_align = ntohl(lease_time_align); if (lease_time_align > cur_iface->lease) lease_time_align = cur_iface->lease; } /* Make sure we aren't just using the lease time from the * previous offer */ if (lease_time_align < server_config.min_lease) lease_time_align = cur_iface->lease; //<< jojopo : wifi leasetime 300 seconds , 2015/12/25 if(isHostFromWireless(packet.chaddr)) lease_time_align = 300; //>> jojopo : end } else { /* It is a static lease... use it */ packet.yiaddr = static_lease_ip; } add_simple_option(packet.options, DHCP_LEASE_TIME, lease_time_align); curr = cur_iface->options; while (curr) { if (curr->data[OPT_CODE] != DHCP_LEASE_TIME) add_option_string(packet.options, curr->data); curr = curr->next; } add_bootp_options(&packet); //brcm begin /* if DHCPDISCOVER from client has device identity, send back gateway identity */ if ((req = (char *)get_option(oldpacket, DHCP_VENDOR_IDENTIFYING))) { if (createVIoption(VENDOR_IDENTIFYING_FOR_GATEWAY, VIinfo) != -1) add_option_string(packet.options, (unsigned char *)VIinfo); } //brcm end addr.s_addr = packet.yiaddr; LOG(LOG_INFO, "sending OFFER of %s", inet_ntoa(addr)); return send_packet(&packet, 0); }
/* send a DHCP OFFER to a DHCP DISCOVER */ int send_offer(struct dhcpMessage *oldpacket) { struct dhcpMessage packet; struct dhcpOfferedAddr *lease = NULL; uint32_t req_align, lease_time_align = server_config.lease; uint8_t *req, *lease_time; struct option_set *curr; struct in_addr addr; uint32_t static_lease_ip; init_packet(&packet, oldpacket, DHCPOFFER); static_lease_ip = getIpByMac(server_config.static_leases, oldpacket->chaddr); /* ADDME: if static, short circuit */ if (!static_lease_ip) { /* the client is in our lease/offered table */ lease = find_lease_by_chaddr(oldpacket->chaddr); if (lease) { if (!lease_expired(lease)) lease_time_align = lease->expires - time(0); packet.yiaddr = lease->yiaddr; /* Or the client has a requested ip */ } else if ((req = get_option(oldpacket, DHCP_REQUESTED_IP)) /* Don't look here (ugly hackish thing to do) */ && memcpy(&req_align, req, 4) /* and the ip is in the lease range */ && ntohl(req_align) >= server_config.start_ip && ntohl(req_align) <= server_config.end_ip && !static_lease_ip /* Check that its not a static lease */ /* and is not already taken/offered */ && (!(lease = find_lease_by_yiaddr(req_align)) /* or its taken, but expired */ /* ADDME: or maybe in here */ || lease_expired(lease)) ) { packet.yiaddr = req_align; /* FIXME: oh my, is there a host using this IP? */ /* otherwise, find a free IP */ } else { /* Is it a static lease? (No, because find_address skips static lease) */ packet.yiaddr = find_address(0); /* try for an expired lease */ if (!packet.yiaddr) packet.yiaddr = find_address(1); } if (!packet.yiaddr) { bb_error_msg("no IP addresses to give - OFFER abandoned"); return -1; } if (!add_lease(packet.chaddr, packet.yiaddr, server_config.offer_time)) { bb_error_msg("lease pool is full - OFFER abandoned"); return -1; } lease_time = get_option(oldpacket, DHCP_LEASE_TIME); if (lease_time) { memcpy(&lease_time_align, lease_time, 4); lease_time_align = ntohl(lease_time_align); if (lease_time_align > server_config.lease) lease_time_align = server_config.lease; } /* Make sure we aren't just using the lease time from the previous offer */ if (lease_time_align < server_config.min_lease) lease_time_align = server_config.lease; /* ADDME: end of short circuit */ } else { /* It is a static lease... use it */ packet.yiaddr = static_lease_ip; } add_simple_option(packet.options, DHCP_LEASE_TIME, htonl(lease_time_align)); curr = server_config.options; while (curr) { if (curr->data[OPT_CODE] != DHCP_LEASE_TIME) add_option_string(packet.options, curr->data); curr = curr->next; } add_bootp_options(&packet); addr.s_addr = packet.yiaddr; bb_info_msg("Sending OFFER of %s", inet_ntoa(addr)); return send_packet(&packet, 0); }
int main(int argc, char *argv[]) #endif { fd_set rfds; struct timeval tv; int server_socket = -1; int bytes, retval; struct dhcpMessage packet; uint8_t *state; uint8_t *server_id, *requested; uint8_t *hostname; uint32_t server_id_align, requested_align; unsigned long timeout_end; struct option_set *option; struct dhcpOfferedAddr *lease; struct dhcpOfferedAddr static_lease; int max_sock; unsigned long num_ips; uint32_t static_lease_ip; memset(&server_config, 0, sizeof(struct server_config_t)); read_config(argc < 2 ? DHCPD_CONF_FILE : argv[1]); read_config_static_leases(DHCPD_STATIC_LEASES_FILE); /* Start the log, sanitize fd's, and write a pid file */ start_log_and_pid("udhcpd", server_config.pidfile); if ((option = find_option(server_config.options, DHCP_LEASE_TIME))) { memcpy(&server_config.lease, option->data + 2, 4); server_config.lease = ntohl(server_config.lease); } else server_config.lease = LEASE_TIME; /* Sanity check */ num_ips = ntohl(server_config.end) - ntohl(server_config.start) + 1; if (server_config.max_leases > num_ips) { // LOG(LOG_ERR, "max_leases value (%lu) not sane, " // "setting to %lu instead", // server_config.max_leases, num_ips); server_config.max_leases = num_ips; } leases = xcalloc(server_config.max_leases, sizeof(struct dhcpOfferedAddr)); read_leases(server_config.lease_file); if (read_interface(server_config.interface, &server_config.ifindex, &server_config.server, server_config.arp) < 0) return 1; #ifndef UDHCP_DEBUG background(server_config.pidfile); /* hold lock during fork. */ #endif /* Setup the signal pipe */ udhcp_sp_setup(); timeout_end = time(0) + server_config.auto_time; while(1) { /* loop until universe collapses */ if (server_socket < 0) if ((server_socket = listen_socket(INADDR_ANY, SERVER_PORT, server_config.interface)) < 0) { LOG(LOG_ERR, "FATAL: couldn't create server socket, %m"); return 2; } max_sock = udhcp_sp_fd_set(&rfds, server_socket); if (server_config.auto_time) { tv.tv_sec = timeout_end - time(0); tv.tv_usec = 0; } if (!server_config.auto_time || tv.tv_sec > 0) { retval = select(max_sock + 1, &rfds, NULL, NULL, server_config.auto_time ? &tv : NULL); } else retval = 0; /* If we already timed out, fall through */ if (retval == 0) { write_leases(); timeout_end = time(0) + server_config.auto_time; continue; } else if (retval < 0 && errno != EINTR) { DEBUG(LOG_INFO, "error on select"); continue; } switch (udhcp_sp_read(&rfds)) { case SIGUSR1: LOG(LOG_INFO, "Received a SIGUSR1"); write_leases(); /* why not just reset the timeout, eh */ timeout_end = time(0) + server_config.auto_time; continue; case SIGTERM: LOG(LOG_INFO, "Received a SIGTERM"); return 0; case 0: break; /* no signal */ default: continue; /* signal or error (probably EINTR) */ } if ((bytes = get_packet(&packet, server_socket)) < 0) { /* this waits for a packet - idle */ if (bytes == -1 && errno != EINTR) { DEBUG(LOG_INFO, "error on read, %m, reopening socket"); close(server_socket); server_socket = -1; } continue; } if ((state = get_option(&packet, DHCP_MESSAGE_TYPE)) == NULL) { DEBUG(LOG_ERR, "couldn't get option from packet, ignoring"); continue; } /* Look for a static lease */ static_lease_ip = getIpByMac(server_config.static_leases, &packet.chaddr); if(static_lease_ip) { printf("Found static lease: %x\n", static_lease_ip); memcpy(&static_lease.chaddr, &packet.chaddr, 16); static_lease.yiaddr = static_lease_ip; static_lease.expires = 0; lease = &static_lease; } else { lease = find_lease_by_chaddr(packet.chaddr); } switch (state[0]) { case DHCPDISCOVER: DEBUG(LOG_INFO,"received DISCOVER"); if (sendOffer(&packet) < 0) { LOG(LOG_ERR, "send OFFER failed"); } break; case DHCPREQUEST: DEBUG(LOG_INFO, "received REQUEST"); requested = get_option(&packet, DHCP_REQUESTED_IP); server_id = get_option(&packet, DHCP_SERVER_ID); hostname = get_option(&packet, DHCP_HOST_NAME); if (requested) memcpy(&requested_align, requested, 4); if (server_id) memcpy(&server_id_align, server_id, 4); if (lease) { if (server_id) { /* SELECTING State */ DEBUG(LOG_INFO, "server_id = %08x", ntohl(server_id_align)); if (server_id_align == server_config.server && requested && requested_align == lease->yiaddr) { sendACK(&packet, lease->yiaddr); } } else { if (requested) { /* INIT-REBOOT State */ if (lease->yiaddr == requested_align) sendACK(&packet, lease->yiaddr); else sendNAK(&packet); } else { /* RENEWING or REBINDING State */ if (lease->yiaddr == packet.ciaddr) sendACK(&packet, lease->yiaddr); else { /* don't know what to do!!!! */ sendNAK(&packet); } } } if (hostname) { bytes = hostname[-1]; if (bytes >= (int) sizeof(lease->hostname)) bytes = sizeof(lease->hostname) - 1; strncpy(lease->hostname, hostname, bytes); lease->hostname[bytes] = '\0'; } else lease->hostname[0] = '\0'; /* what to do if we have no record of the client */ } else if (server_id) { /* SELECTING State */ } else if (requested) { /* INIT-REBOOT State */ if ((lease = find_lease_by_yiaddr(requested_align))) { if (lease_expired(lease)) { /* probably best if we drop this lease */ memset(lease->chaddr, 0, 16); /* make some contention for this address */ } else sendNAK(&packet); } else if (requested_align < server_config.start || requested_align > server_config.end) { sendNAK(&packet); } /* else remain silent */ } else { /* RENEWING or REBINDING State */ } break; case DHCPDECLINE: DEBUG(LOG_INFO,"received DECLINE"); if (lease) { memset(lease->chaddr, 0, 16); lease->expires = time(0) + server_config.decline_time; } break; case DHCPRELEASE: DEBUG(LOG_INFO,"received RELEASE"); if (lease) lease->expires = time(0); break; case DHCPINFORM: DEBUG(LOG_INFO,"received INFORM"); send_inform(&packet); break; default: LOG(LOG_WARNING, "unsupported DHCP message (%02x) -- ignoring", state[0]); } } return 0; }
/* send a DHCP OFFER to a DHCP DISCOVER */ int sendOffer(struct dhcpMessage *oldpacket) { struct dhcpMessage packet; struct dhcpOfferedAddr *lease = NULL; u_int32_t req_align, lease_time_align = server_config.lease; char *req, *lease_time; struct option_set *curr; struct in_addr addr; char *hostname; char hostname_copy[64]; uint32_t static_lease_ip; init_packet(&packet, oldpacket, DHCPOFFER); static_lease_ip = getIpByMac(server_config.static_leases, oldpacket->chaddr); /* ADDME: if static, short circuit */ if(!static_lease_ip) { /* the client is in our lease/offered table */ if ((lease = find_lease_by_chaddr(oldpacket->chaddr))) { if (!lease_expired(lease)) lease_time_align = lease->expires - time(0); packet.yiaddr = lease->yiaddr; /* Or the client has a requested ip */ } else if ((req = get_option(oldpacket, DHCP_REQUESTED_IP)) && /* Don't look here (ugly hackish thing to do) */ memcpy(&req_align, req, 4) && /* and the ip is in the lease range */ ntohl(req_align) >= ntohl(server_config.start) && ntohl(req_align) <= ntohl(server_config.end) && !static_lease_ip && /* Check that its not a static lease */ /* and its not already taken/offered */ ((!(lease = find_lease_by_yiaddr(req_align)) || /* or its taken, but expired */ lease_expired(lease)))) { packet.yiaddr = req_align; /* otherwise, find a free IP */ } else { packet.yiaddr = find_address(0); /* try for an expired lease */ if (!packet.yiaddr) packet.yiaddr = find_address(1); } if(!packet.yiaddr) { LOG(LOG_WARNING, "no IP addresses to give -- OFFER abandoned"); return -1; } hostname = get_option(oldpacket, DHCP_HOST_NAME); memset(hostname_copy, 0, sizeof(hostname_copy)); if (hostname) { memcpy(hostname_copy, hostname, hostname[-1]); } if (!add_lease(packet.chaddr, packet.yiaddr, server_config.offer_time, hostname_copy)) { LOG(LOG_WARNING, "lease pool is full -- OFFER abandoned"); return -1; } if ((lease_time = get_option(oldpacket, DHCP_LEASE_TIME))) { memcpy(&lease_time_align, lease_time, 4); lease_time_align = ntohl(lease_time_align); if (lease_time_align > server_config.lease) lease_time_align = server_config.lease; } /* Make sure we aren't just using the lease time from the previous offer */ if (lease_time_align < server_config.min_lease) lease_time_align = server_config.lease; } /* ADDME: end of short circuit */ else { /* It is a static lease... use it */ packet.yiaddr = static_lease_ip; } add_simple_option(packet.options, DHCP_LEASE_TIME, lease_time_align); curr = server_config.options; while (curr) { if (curr->data[OPT_CODE] != DHCP_LEASE_TIME) add_option_string(packet.options, curr->data); curr = curr->next; } add_bootp_options(&packet); addr.s_addr = packet.yiaddr; LOG(LOG_INFO, "sending OFFER of %s", inet_ntoa(addr)); return send_packet(&packet, 0); }