/* find an assignable address, it check_expired is true, we check all the expired leases as well. * Maybe this should try expired leases by age... */ uint32_t find_address(int check_expired) { uint32_t addr, ret; struct dhcpOfferedAddr *lease = NULL; addr = ntohl(server_config.start); /* addr is in host order here */ for (;addr <= ntohl(server_config.end); addr++) { /* ie, 192.168.55.0 */ if (!(addr & 0xFF)) continue; /* ie, 192.168.55.255 */ if ((addr & 0xFF) == 0xFF) continue; /* Only do if it isn't an assigned as a static lease */ if (!reservedIp(server_config.static_leases, htonl(addr))) { /* lease is not taken */ ret = htonl(addr); lease = find_lease_by_yiaddr(ret); /* no lease or it expired and we are checking for expired leases */ if ( (!lease || (check_expired && lease_expired(lease))) && /* and it isn't on the network */ !check_ip(ret) ) { return ret; break; } } } return 0; }
/* get signal to write viTable to file */ void write_viTable() { FILE *fp; int count; pVI_OPTION_INFO pPtr=NULL; struct dhcpOfferedAddr *lease = NULL; if (!(fp = fopen("/var/udhcpd/managable.device", "w+"))) { LOG(LOG_ERR, "Unable to open %s for writing", "/var/udhcpd/managable.device"); return; } count = viList->count; fprintf(fp,"NumberOfDevices %d\n",count); if (count > 0) { pPtr = viList->pHead; while (pPtr) { if ((lease = find_lease_by_yiaddr(pPtr->ipAddr)) && lease_expired(lease)) { strcpy(pPtr->oui,""); strcpy(pPtr->serialNumber,""); strcpy(pPtr->productClass,""); } fprintf(fp,"IPaddr %x Enterprise %d OUI %s SerialNumber %s ProductClass %s\n", pPtr->ipAddr,pPtr->enterprise,pPtr->oui,pPtr->serialNumber, pPtr->productClass); pPtr = pPtr->next; } } fclose(fp); }
void write_leases(void) { FILE *fp; unsigned int i; char buf[255]; time_t curr = time(0); unsigned long lease_time; if (!(fp = fopen(server_config.lease_file, "w"))) { LOG(LOG_ERR, "Unable to open %s for writing", server_config.lease_file); return; } for (i = 0; i < server_config.max_leases; i++) { if (leases[i].yiaddr != 0) { if (server_config.remaining) { if (lease_expired(&(leases[i]))) lease_time = 0; else lease_time = leases[i].expires - curr; } else lease_time = leases[i].expires; lease_time = htonl(lease_time); fwrite(leases[i].chaddr, 16, 1, fp); fwrite(&(leases[i].yiaddr), 4, 1, fp); fwrite(&lease_time, 4, 1, fp); } } fclose(fp); if (server_config.notify_file) { sprintf(buf, "%s %s", server_config.notify_file, server_config.lease_file); system(buf); } }
/* the dummy var is here so this can be a signal handler */ void write_leases(int dummy) { FILE *fp; unsigned int i; char buf[255]; /*Start of Mod by y67514:time(0)取的系统时间会受SNTP影响,导致定时器混乱*/ time_t curr = getSysUpTime(); /*End of Mod by y67514:time(0)取的系统时间会受SNTP影响,导致定时器混乱*/ unsigned long lease_time; dummy = 0; if (!(fp = fopen(server_config.lease_file, "w"))) { LOG(LOG_ERR, "Unable to open %s for writing", server_config.lease_file); return; } for (i = 0; i < server_config.max_leases; i++) { if (leases[i].yiaddr != 0) { if (server_config.remaining) { if (lease_expired(&(leases[i]))) lease_time = 0; else lease_time = leases[i].expires - curr; } else lease_time = leases[i].expires; lease_time = htonl(lease_time); fwrite(leases[i].chaddr, 16, 1, fp); fwrite(&(leases[i].yiaddr), 4, 1, fp); fwrite(&lease_time, 4, 1, fp); fwrite(leases[i].hostname, 64, 1, fp); //w44771 add for test #ifdef SUPPORT_CHINATELECOM_DHCP fwrite(&leases[i].port, 4, 1, fp); #endif } } fclose(fp); if (server_config.notify_file) { sprintf(buf, "%s %s", server_config.notify_file, server_config.lease_file); system(buf); } }
void write_leases(void) { int i = 0; int index = 0; for (i = 0; i < server_config.max_leases; i++) { if (leases[i].yiaddr != 0) { /* only record when remaining is true */ if (server_config.remaining) { if (lease_expired(&(leases[i]))) { //printf("lease %d expired\n", i); memset(&leases[i], 0, sizeof(struct dhcpOfferedAddr)); //memset(&leases_shm[i], 0, sizeof(struct dhcpOfferedAddr)); } else /* record those not expired */ { if (leases[i].host_name[0] == 0 || (leases[i].chaddr[0] == 0 && leases[i].chaddr[1] == 0 && leases[i].chaddr[2] == 0 && leases[i].chaddr[3] == 0 && leases[i].chaddr[4] == 0 && leases[i].chaddr[5] == 0) ) { //printf("lease %d hostname or mac null\n", i); continue; } if (leases[i].state != DHCPACK) { //printf("lease %d not ack yet\n", i); continue; } leases_shm[index] = leases[i]; //printf("lease %d valid\n", i); if (leases_shm[index].expires != 0xFFFFFFFF) leases_shm[index].expires -= uptime()/*time(0)*/; index ++; } } //else // printf("no remaining\n"); } //else // printf("lease %d no ip ", i); } //printf("total leases num : %d\n", index); memset(&leases_shm[index], 0, sizeof(struct dhcpOfferedAddr)); #if 0 FILE *fp; unsigned int i; char buf[255]; time_t curr = time(0); unsigned long tmp_time; if (!(fp = fopen(server_config.lease_file, "w"))) { LOG(LOG_ERR, "Unable to open %s for writing", server_config.lease_file); return; } for (i = 0; i < server_config.max_leases; i++) { if (leases[i].yiaddr != 0) { /* screw with the time in the struct, for easier writing */ tmp_time = leases[i].expires; if (server_config.remaining) { if (lease_expired(&(leases[i]))) leases[i].expires = 0; else leases[i].expires -= curr; } /* else stick with the time we got */ leases[i].expires = htonl(leases[i].expires); /* 25JuL07 lishaozhang edited */ if (leases[i].expires > 0) { fwrite(&leases[i], sizeof(struct dhcpOfferedAddr), 1, fp); /* Then restore it when done. */ leases[i].expires = tmp_time; } else { /* discard the expired ones */ memset(&leases[i], 0, sizeof(struct dhcpOfferedAddr)); } } } fclose(fp); if (server_config.notify_file) { sprintf(buf, "%s %s", server_config.notify_file, server_config.lease_file); system(buf); } #endif }
void write_leases(void) { FILE *fp, *fp1; unsigned int i; char buf[255]; char file[255] = HTML_LEASES_FILE; time_t curr = time(0); unsigned long tmp_time; struct html_leases_s user_leases, curr_user_lease; struct in_addr addr; fp = fopen(server_config.lease_file, "w"); if (fp == NULL) { LOG(LOG_ERR, "Unable to open %s for writing", server_config.lease_file); return; } /* For http show dhcp client list (html.leases) */ fp1 = fopen(file, "w"); if (fp1 == NULL) { LOG(LOG_ERR, "Unable to open %s for writing", file); return; } /* write to html.leases */ for (i = 0; i < server_config.max_leases; i++) { if ( !lease_expired(&(leases[i])) && (leases[i].yiaddr != 0) ) { memset(&user_leases, 0 , sizeof(struct html_leases_s)); sprintf(user_leases.mac_addr,"%02x:%02x:%02x:%02x:%02x:%02x",leases[i].chaddr[0], leases[i].chaddr[1], leases[i].chaddr[2], leases[i].chaddr[3], leases[i].chaddr[4], leases[i].chaddr[5]); // LOG(LOG_DEBUG,"user_leases.mac_addr =%02x:%02x:%02x:%02x:%02x:%02x\n",leases[i].chaddr[0], leases[i].chaddr[1], leases[i].chaddr[2], leases[i].chaddr[3], leases[i].chaddr[4], leases[i].chaddr[5]); addr.s_addr = leases[i].yiaddr; sprintf(user_leases.ip_addr, "%s", inet_ntoa(addr)); // LOG(LOG_DEBUG,"user_leases.yiaddr =%s\n", inet_ntoa(addr)); strcpy(user_leases.expires, ctime(&leases[i].expires)); memset(user_leases.expires+strlen(user_leases.expires)-1, 0, (sizeof(user_leases.expires)-strlen(user_leases.expires)+1)); // LOG(LOG_DEBUG,"user_leases.expires =%s\n", user_leases.expires); strcpy(user_leases.hostname, leases[i].hostname); // LOG(LOG_DEBUG,"user_leases.hostname =%s\n", user_leases.hostname); if(!feof(fp1)) { fread(&curr_user_lease, sizeof(struct html_leases_s), 1, fp1); if(strcmp(curr_user_lease.mac_addr, user_leases.mac_addr) != 0) fwrite(&user_leases, sizeof(struct html_leases_s), 1, fp1); } else { fwrite(&user_leases, sizeof(struct html_leases_s), 1, fp1); } } } #if 1 for (i = 0; i < server_config.max_leases; i++) { if (leases[i].yiaddr != 0) { /* screw with the time in the struct, for easier writing */ tmp_time = leases[i].expires; if (server_config.remaining) { if (lease_expired(&(leases[i]))) leases[i].expires = 0; else leases[i].expires -= curr; } /* else stick with the time we got */ leases[i].expires = htonl(leases[i].expires); fwrite(&leases[i], sizeof(struct dhcpOfferedAddr), 1, fp); /* Then restore it when done. */ leases[i].expires = tmp_time; } } #endif fclose(fp1); fclose(fp); if (server_config.notify_file) { sprintf(buf, "%s %s", server_config.notify_file, server_config.lease_file); system(buf); } }
int main(int argc, char *argv[]) #endif { fd_set rfds; struct timeval tv; int server_socket = -1; int bytes, retval; struct dhcpMessage packet; unsigned char *state; unsigned char *server_id, *requested, *hostname; u_int32_t server_id_align, requested_align; unsigned long timeout_end; struct option_set *option; struct dhcpOfferedAddr *lease; int pid_fd; int max_sock; int sig; OPEN_LOG("udhcpd"); LOG(LOG_INFO, "udhcp server (v%s) started", VERSION); memset(&server_config, 0, sizeof(struct server_config_t)); if (argc < 2) read_config(DHCPD_CONF_FILE); else read_config(argv[1]); pid_fd = pidfile_acquire(server_config.pidfile); pidfile_write_release(pid_fd); 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; leases = malloc(sizeof(struct dhcpOfferedAddr) * server_config.max_leases); memset(leases, 0, sizeof(struct dhcpOfferedAddr) * server_config.max_leases); // Added by Joey to load static lease if (argc>=3) { load_leases(argv[2]); } read_leases(server_config.lease_file); if (read_interface(server_config.interface, &server_config.ifindex, &server_config.server, server_config.arp) < 0) exit_server(1); #ifndef DEBUGGING pid_fd = pidfile_acquire(server_config.pidfile); /* hold lock during fork. */ if (daemon(0, 0) == -1) { perror("fork"); exit_server(1); } pidfile_write_release(pid_fd); #endif /* ensure that stdin/stdout/stderr are never returned by pipe() */ if (fcntl(STDIN_FILENO, F_GETFL) == -1) (void) open("/dev/null", O_RDONLY); if (fcntl(STDOUT_FILENO, F_GETFL) == -1) (void) open("/dev/null", O_WRONLY); if (fcntl(STDERR_FILENO, F_GETFL) == -1) (void) open("/dev/null", O_WRONLY); /* setup signal handlers */ pipe(signal_pipe); signal(SIGUSR1, signal_handler); signal(SIGTERM, signal_handler); timeout_end = uptime() + 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, %s", strerror(errno)); exit_server(0); } FD_ZERO(&rfds); FD_SET(server_socket, &rfds); FD_SET(signal_pipe[0], &rfds); if (server_config.auto_time) { tv.tv_sec = timeout_end - uptime(); tv.tv_usec = 0; } if (!server_config.auto_time || tv.tv_sec > 0) { max_sock = server_socket > signal_pipe[0] ? server_socket : signal_pipe[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 = uptime() + server_config.auto_time; continue; } else if (retval < 0 && errno != EINTR) { DEBUG(LOG_INFO, "error on select"); continue; } if (FD_ISSET(signal_pipe[0], &rfds)) { if (read(signal_pipe[0], &sig, sizeof(sig)) < 0) continue; /* probably just EINTR */ switch (sig) { case SIGUSR1: LOG(LOG_INFO, "Received a SIGUSR1"); write_leases(); /* why not just reset the timeout, eh */ timeout_end = uptime() + server_config.auto_time; continue; case SIGTERM: LOG(LOG_INFO, "Received a SIGTERM"); exit_server(0); } } 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, %s, reopening socket", strerror(errno)); 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; } server_id = get_option(&packet, DHCP_SERVER_ID); if (server_id) { memcpy(&server_id_align, server_id, 4); if (server_id_align != server_config.server) { /* client talks to somebody else */ DEBUG(LOG_INFO,"server ID %08x doesn't match, ignoring", ntohl(server_id_align)); continue; } } /* ADDME: look for a static lease */ 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); hostname = get_option(&packet, DHCP_HOST_NAME); if (requested) memcpy(&requested_align, requested, 4); if (lease) { /*ADDME: or static lease */ if (server_id) { /* SELECTING State */ if (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'; if (!is_valid_hostname(lease->hostname)) lease->hostname[0] = '\0'; } else lease->hostname[0] = '\0'; /* what to do if we have no record of the client */ } else if (server_id) { /* SELECTING State */ if (requested) sendNAK(&packet); } 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 { sendNAK(&packet); } } else if (packet.ciaddr) { /* RENEWING or REBINDING State */ sendNAK(&packet); } break; case DHCPDECLINE: DEBUG(LOG_INFO,"received DECLINE"); if (lease) { memset(lease->chaddr, 0, 16); lease->expires = uptime() + server_config.decline_time; } break; case DHCPRELEASE: DEBUG(LOG_INFO,"received RELEASE"); if (lease) lease->expires = uptime(); 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 FAST_FUNC send_offer(struct dhcpMessage *oldpacket) { struct dhcpMessage packet; uint32_t req_align; uint32_t lease_time_aligned = server_config.lease; uint32_t static_lease_ip; uint8_t *req, *lease_time, *p_host_name; struct option_set *curr; struct in_addr addr; init_packet(&packet, oldpacket, DHCPOFFER); static_lease_ip = getIpByMac(server_config.static_leases, oldpacket->chaddr); /* ADDME: if static, short circuit */ if (!static_lease_ip) { struct dhcpOfferedAddr *lease; lease = find_lease_by_chaddr(oldpacket->chaddr); /* the client is in our lease/offered table */ if (lease) { signed_leasetime_t tmp = lease->expires - time(NULL); if (tmp >= 0) lease_time_aligned = tmp; packet.yiaddr = lease->yiaddr; /* Or the client has requested an ip */ } else if ((req = get_option(oldpacket, DHCP_REQUESTED_IP)) != NULL /* Don't look here (ugly hackish thing to do) */ && (move_from_unaligned32(req_align, req), 1) /* and the ip is in the lease range */ && ntohl(req_align) >= server_config.start_ip && ntohl(req_align) <= server_config.end_ip /* and is 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_free_or_expired_address(); } if (!packet.yiaddr) { bb_error_msg("no IP addresses to give - OFFER abandoned"); return -1; } p_host_name = get_option(oldpacket, DHCP_HOST_NAME); if (!add_lease(packet.chaddr, packet.yiaddr, server_config.offer_time, p_host_name)) { bb_error_msg("lease pool is full - OFFER abandoned"); return -1; } lease_time = get_option(oldpacket, DHCP_LEASE_TIME); if (lease_time) { move_from_unaligned32(lease_time_aligned, lease_time); lease_time_aligned = ntohl(lease_time_aligned); if (lease_time_aligned > server_config.lease) lease_time_aligned = server_config.lease; } /* Make sure we aren't just using the lease time from the previous offer */ if (lease_time_aligned < server_config.min_lease) lease_time_aligned = server_config.min_lease; } else { /* It is a static lease... use it */ packet.yiaddr = static_lease_ip; } add_simple_option(packet.options, DHCP_LEASE_TIME, htonl(lease_time_aligned)); 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); }
/* 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; unsigned char *req, *lease_time; struct option_set *curr; struct in_addr addr; unsigned char mac[6]; u_int32_t reserved_ip; memcpy(mac, oldpacket->chaddr, 6); init_packet(&packet, oldpacket, DHCPOFFER); /* ADDME: if static, short circuit */ /* the client is in our lease/offered table */ if ((lease = find_lease_by_chaddr(oldpacket->chaddr)) && /* Make sure the IP is not already used on network */ !check_ip(lease->yiaddr)) { if (!lease_expired(lease)) lease_time_align = lease->expires - time(0); packet.yiaddr = lease->yiaddr; /* Find a reserved ip for this MAC */ } else if ( (reserved_ip = find_reserved_ip(mac)) != 0) { packet.yiaddr = htonl(reserved_ip); /* 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) && /* check if the requested ip has been reserved */ check_reserved_ip(req_align, mac) && /* and the ip is in the lease range */ ntohl(req_align) >= ntohl(server_config.start) && ntohl(req_align) <= ntohl(server_config.end) && /* Check that this request ip is not on network */ //!check_ip(ntohl(req_align)) && /* the input parameter of check_ip() should be network order */ !check_ip(req_align) && /* modified by Max Ding, 07/07/2011 @TD #42 of WNR3500Lv2 */ /* and its not already taken/offered */ /* ADDME: check that its not a static lease */ ((!(lease = find_lease_by_yiaddr(req_align)) || /* or its taken, but expired */ /* ADDME: or maybe in here */ lease_expired(lease)))) { packet.yiaddr = req_align; /* otherwise, find a free IP */ /*ADDME: is it a static lease? */ } else { packet.yiaddr = find_address2(0, mac); /* try for an expired lease */ if (!packet.yiaddr) packet.yiaddr = find_address2(1, mac); } 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 = 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; /* For guest network clients, set lease time to 30 minutes */ if (is_guest_network(mac)) { lease_time_align = GUEST_LEASE_TIME; DEBUG(LOG_INFO, "send OFFER to guest network client with lease time %d sec", GUEST_LEASE_TIME); } /* ADDME: end of short circuit */ 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; LOG(LOG_INFO, "sending OFFER of %s", inet_ntoa(addr)); return send_packet(&packet, 0); }
u_int32_t find_address(int check_expired) #endif { u_int32_t addr, ret = 0; struct dhcpOfferedAddr *lease = NULL; #ifdef NK_CONFIG_SUPPORT_MULTI_DHCP_SUBNET addr = ntohl(selected_dhcp_pool->start_ip.s_addr); for (;ntohl(addr) <= ntohl(selected_dhcp_pool->end_ip.s_addr) ;addr = htonl(ntohl(addr) + 1)) { if (addr == ntohl(selected_dhcp_pool->server_ip.s_addr)) continue; if (ret == selected_dhcp_pool->server_ip.s_addr) continue; #else addr = ntohl(server_config.start); for (;ntohl(addr) <= ntohl(server_config.end) ;addr = htonl(ntohl(addr) + 1)) { if (addr == ntohl(server_config.server)) continue; if (ret == server_config.server) continue; #endif /* ie, 192.168.55.0 */ if (!(ntohl(addr) & 0xFF)) continue; /* ie, 192.168.55.255 */ if ((ntohl(addr) & 0xFF) == 0xFF) continue; /* lease is not taken */ if ((!(lease = find_lease_by_yiaddr(addr)) || /* or it expired and we are checking for expired leases */ (check_expired && lease_expired(lease))) && /* and it isn't on the network */ !check_ip(addr)) { ret = addr; break; } } return ret; } /* check is an IP is taken, if it is, add it to the lease table */ int check_ip(u_int32_t addr) { char blank_chaddr[] = {[0 ... 15] = 0}; struct in_addr temp; int i;//fix if lease is static IP,don't check arp for (i = 0; i < server_config.max_leases; i++) { if (leases[i].yiaddr == addr && leases[i].is_static == 1) { return 0; } } if (arpping(addr, server_config.server, server_config.arp, server_config.interface) == 0) { temp.s_addr = addr; LOG(LOG_INFO, "%s belongs to someone, reserving it for %ld seconds", inet_ntoa(temp), server_config.conflict_time); /* 2007/07/30 jane: bug fix dhcp status do not show client's host name */ #if 1 add_lease(blank_chaddr, addr, server_config.conflict_time, NULL, (u_int32_t)0); #else add_lease(blank_chaddr, addr, server_config.conflict_time); #endif return 1; } else return 0; }
int main(int argc, char *argv[]) #endif { fd_set rfds; struct timeval tv; int server_socket = -1; int bytes, retval; struct dhcpMessage packet; unsigned char *state; unsigned char *server_id, *requested, *hostname; u_int32_t server_id_align, requested_align; unsigned long timeout_end; struct option_set *option; struct dhcpOfferedAddr *lease; int pid_fd; int max_sock; int sig; /* DD-WRT (belanger) : ignore signals until we're ready */ signal(SIGUSR1, SIG_IGN); signal(SIGUSR2, SIG_IGN); signal(SIGHUP, SIG_IGN); signal(SIGTERM, SIG_IGN); OPEN_LOG("udhcpd"); LOG(LOG_INFO, "udhcp server (v%s) started", VERSION); memset(&server_config, 0, sizeof(struct server_config_t)); if (argc < 2) read_config(DHCPD_CONF_FILE); else read_config(argv[1]); pid_fd = pidfile_acquire(server_config.pidfile); pidfile_write_release(pid_fd); 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; leases = malloc(sizeof(struct dhcpOfferedAddr) * server_config.max_leases); memset(leases, 0, sizeof(struct dhcpOfferedAddr) * server_config.max_leases); read_leases(server_config.lease_file); read_statics(server_config.statics_file); /* DD-WRT (belanger) : write leases now */ write_leases(); if (read_interface(server_config.interface, &server_config.ifindex, &server_config.server, server_config.arp) < 0) exit_server(1); #ifndef DEBUGGING pid_fd = pidfile_acquire(server_config.pidfile); /* hold lock during fork. */ if (daemon(0, 0) == -1) { perror("fork"); exit_server(1); } pidfile_write_release(pid_fd); #endif socketpair(AF_UNIX, SOCK_STREAM, 0, signal_pipe); signal(SIGUSR1, signal_handler); signal(SIGUSR2, signal_handler); signal(SIGTERM, signal_handler); signal(SIGHUP, signal_handler); timeout_end = get_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, %s", strerror(errno)); exit_server(0); } FD_ZERO(&rfds); FD_SET(server_socket, &rfds); FD_SET(signal_pipe[0], &rfds); if (server_config.auto_time) { tv.tv_sec = timeout_end - get_time(0); tv.tv_usec = 0; } if (!server_config.auto_time || tv.tv_sec > 0) { max_sock = server_socket > signal_pipe[0] ? server_socket : signal_pipe[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 = get_time(0) + server_config.auto_time; continue; } else if (retval < 0 && errno != EINTR) { DEBUG(LOG_INFO, "error on select"); continue; } if (FD_ISSET(signal_pipe[0], &rfds)) { if (read(signal_pipe[0], &sig, sizeof(sig)) < 0) continue; /* probably just EINTR */ switch (sig) { case SIGUSR1: LOG(LOG_INFO, "Received a SIGUSR1"); write_leases(); /* why not just reset the timeout, eh */ timeout_end = get_time(0) + server_config.auto_time; continue; case SIGUSR2: LOG(LOG_INFO, "Received a SIGUSR2"); delete_leases(); continue; case SIGHUP: LOG(LOG_INFO, "Received a SIGHUP"); read_leases(server_config.lease_file); read_statics(server_config.statics_file); continue; case SIGTERM: LOG(LOG_INFO, "Received a SIGTERM"); exit_server(0); } } 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, %s, reopening socket", strerror(errno)); 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; } hostname = get_option(&packet, DHCP_HOST_NAME); /* ADDME: look for a static lease */ /* If a hostname is supplied, and that hostname is a static lease, and that static lease has an FF:FF:FF:FF:FF:FF MAC address, then use that entry. */ if ( NULL == hostname || NULL == (lease = find_lease_by_hostname(hostname)) || (lease->expires != EXPIRES_NEVER) || 0 != memcmp(lease->chaddr, MAC_BCAST_ADDR, strlen(MAC_BCAST_ADDR))) { /* Otherwise, look up the table using the supplied MAC address. */ lease = find_lease_by_chaddr(packet.chaddr); } switch (state[0]) { case DHCPDISCOVER: LOG(LOG_INFO,"received DISCOVER from %02x:%02x:%02x:%02x:%02x:%02x", packet.chaddr[0], packet.chaddr[1], packet.chaddr[2], packet.chaddr[3], packet.chaddr[4], packet.chaddr[5]); // modify by honor if (sendOffer(&packet, lease) < 0) { LOG(LOG_ERR, "send OFFER failed"); } break; case DHCPREQUEST: 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 (requested) { struct in_addr addr; addr.s_addr = requested_align; LOG(LOG_INFO, "received REQUEST for %s from %02x:%02x:%02x:%02x:%02x:%02x", inet_ntoa(addr), packet.chaddr[0], packet.chaddr[1], packet.chaddr[2], packet.chaddr[3], packet.chaddr[4], packet.chaddr[5]); } else { LOG(LOG_INFO, "received REQUEST from %02x:%02x:%02x:%02x:%02x:%02x", packet.chaddr[0], packet.chaddr[1], packet.chaddr[2], packet.chaddr[3], packet.chaddr[4], packet.chaddr[5]); } if (lease) { /*ADDME: or static 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 sendNAK(&packet); //Sveasoft - shouldn't we let them know we don't like the request? } 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 if (!packet.ciaddr) /* Accept an invalid request in RENEWING state, where the ciaddr should be set, but is not. */ /* e.g. Linksys Print Server */ // sendACK(&packet, lease->yiaddr); //note: let's not support broken stuff - Sveasoft 2005-01-19 else { /* don't know what to do!!!! */ sendNAK(&packet); } } } if (lease->expires != EXPIRES_NEVER) { /* Don't change hostname of static leases */ 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 */ sendNAK(&packet); // by honor } 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 { sendNAK(&packet); } } else if (packet.ciaddr) { /* RENEWING or REBINDING State */ sendNAK(&packet); } break; case DHCPDECLINE: LOG(LOG_INFO,"received DECLINE from %02x:%02x:%02x:%02x:%02x:%02x", packet.chaddr[0], packet.chaddr[1], packet.chaddr[2], packet.chaddr[3], packet.chaddr[4], packet.chaddr[5]); // modify by honor if (lease && lease->expires != EXPIRES_NEVER) { memset(lease->chaddr, 0, 16); lease->expires = get_time(0) + server_config.decline_time; } break; case DHCPRELEASE: LOG(LOG_INFO,"received RELEASE from %02x:%02x:%02x:%02x:%02x:%02x", packet.chaddr[0], packet.chaddr[1], packet.chaddr[2], packet.chaddr[3], packet.chaddr[4], packet.chaddr[5]); // modify by honor if (lease && lease->expires != EXPIRES_NEVER) lease->expires = get_time(0); break; case DHCPINFORM: LOG(LOG_INFO,"received INFORM from %02x:%02x:%02x:%02x:%02x:%02x", packet.chaddr[0], packet.chaddr[1], packet.chaddr[2], packet.chaddr[3], packet.chaddr[4], packet.chaddr[5]); // modify by honor send_inform(&packet); break; default: LOG(LOG_WARNING, "unsupported DHCP message (%02x) -- ignoring", state[0]); } } return 0; }
/* find an assignable address, it check_expired is true, we check all the expired leases as well. * Maybe this should try expired leases by age... */ u_int32_t find_address(int check_expired) { u_int32_t addr, ret; struct dhcpOfferedAddr *lease = NULL; addr = ntohl(server_config.start); /* addr is in host order here */ for (;addr <= ntohl(server_config.end); addr++) { #if 1 /* Network IP and BroadcastIP ie. netmask 255.255.255.0, server ip 192.168.55.1 can't lease 192.168.55.0 or 192.168.55.255 */ if(addr==(server_config.netmask & server_config.server)) continue; if(addr==((~(server_config.netmask))|(server_config.server))) continue; #else /* ie, 192.168.55.0 */ if (!(addr & 0xFF)) continue; /* ie, 192.168.55.255 */ if ((addr & 0xFF) == 0xFF) continue; #endif /* not lease server ip */ if(addr == server_config.server) continue; #ifdef STATIC_LEASE /* Only do if it isn't an assigned as a static lease */ if(!reservedIp(server_config.static_leases, htonl(addr))) #endif { /* lease is not taken */ ret = htonl(addr); if ((!(lease = find_lease_by_yiaddr(ret)) || /* or it expired and we are checking for expired leases */ ( (check_expired == 1) && lease_expired(lease))) && /* and it isn't on the network */ !check_ip(ret)) { return ret; } else if(check_expired == 2) //some one leases this ip and this ip is not expired. { int arpping_time = 0; int ret_arpping = 0; //printf("\r\n Any one use this ip[%x]?",ret); for(arpping_time = 0; arpping_time<3; arpping_time++) { char ret_hwaddr[6]; if (arpping(ret, server_config.server, server_config.arp, server_config.interface, ret_hwaddr) == 0) { ret_arpping = 1; break; } } // But this ip is not alive in network. we release this ip if ( ret_arpping == 1) { //printf(" YES.__[%s-%u]\r\n",__FILE__,__LINE__); } else { //printf(" NO.__[%s-%u]\r\n",__FILE__,__LINE__); return ret; } } } } 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; unsigned char *req, *lease_time; struct option_set *curr; struct in_addr addr; init_packet(&packet, oldpacket, DHCPOFFER); /* ADDME: if static, short circuit */ /* 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) && /* and its not already taken/offered */ /* ADDME: check that its not a static lease */ ((!(lease = find_lease_by_yiaddr(req_align)) || /* or its taken, but expired */ /* ADDME: or maybe in here */ lease_expired(lease)))) { packet.yiaddr = req_align; /* otherwise, find a free IP */ /*ADDME: is it a static lease? */ } 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 = 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 */ 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; LOG(LOG_INFO, "sending OFFER of %s", inet_ntoa(addr)); return send_packet(&packet, 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 = 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 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 = server_config.lease; char *req, *lease_time; struct option_set *curr; char * l_vdfoption[OPTION_LEN]; int l_ilen = 0; struct in_addr addr; #ifdef VDF_OPTION //add for option125 char VIinfo[VENDOR_IDENTIFYING_INFO_LEN]; unsigned char StrOption121[OPTION121_LEN]; #endif /*start A36D02806, s60000658, 20060906*/ struct option_set *opt = NULL; u_int32_t router_ip = 0; if(NULL != (opt = find_option(server_config.options, DHCP_ROUTER))) { router_ip = *(u_int32_t*)(opt->data + 2); } /*end A36D02806, s60000658, 20060906*/ init_packet(&packet, oldpacket, DHCPOFFER); #ifdef SUPPORT_MACMATCHIP if ( !ismacmatch(oldpacket->chaddr) ) { packet.yiaddr = find_matchip(oldpacket->chaddr); } else #endif /* the client is in our lease/offered table */ if ((lease = find_lease_by_chaddr(oldpacket->chaddr))) { /*Start of Mod by y67514:time(0)取的系统时间会受SNTP影响,导致定时器混乱*/ if (!lease_expired(lease)) lease_time_align = lease->expires - getSysUpTime(); /*End of Mod by y67514:time(0)取的系统时间会受SNTP影响,导致定时器混乱*/ 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) && #ifdef VDF_RESERVED //and the ip is not the reserved ip reservedIp(req_align)&& #endif #ifdef SUPPORT_MACMATCHIP isipmatch(req_align) && #endif /* and its not already taken/offered */ ((!(lease = find_lease_by_yiaddr(req_align)) || /* or its taken, but expired */ lease_expired(lease)))) { #ifdef SUPPORT_DHCP_FRAG int tmpNum = 1, i =0; if(1 == inmaster) { for(i = 0; i < 5; i++) { if(ntohl(req_align) >= ntohl(ipPool[i].start) && ntohl(req_align) <= ntohl(ipPool[i].end)) { tmpNum = 0; break; } } } #endif /*start of DHCP 网关会分配自己的维护IP porting by w44771 20060505*/ /*packet.yiaddr = req_align; */ if((req_align != server_config.server) #ifdef SUPPORT_DHCP_FRAG && (req_align != router_ip) && (1 == tmpNum))/*A36D02806, s60000658, 20060906*/ #else && (req_align != router_ip))/*A36D02806, s60000658, 20060906*/ #endif { packet.yiaddr = req_align; } else { #ifdef SUPPORT_DHCP_FRAG if(1 == inmaster)
/* send a DHCP OFFER to a DHCP DISCOVER */ int sendOffer(struct dhcpMessage *oldpacket) { #ifdef DHCPD_HEAP_REPLACE_STACK struct dhcpMessage *packet; #else struct dhcpMessage packet; #endif struct dhcpOfferedAddr *lease = NULL; u_int32_t req_align, lease_time_align = server_config.lease; unsigned char *req, *lease_time; struct option_set *curr; //struct in_addr addr; #ifdef DHCPD_HEAP_REPLACE_STACK packet = calloc(1,sizeof(struct dhcpMessage)); if (!packet) { DHCPD_LOG(LOG_ERR, "Calloc failed...%d",__LINE__); return -1; } init_packet(packet, oldpacket, DHCPOFFER); #else init_packet(&packet, oldpacket, DHCPOFFER); #endif /* ADDME: if static, short circuit */ /* 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); #ifdef DHCPD_HEAP_REPLACE_STACK packet->yiaddr = lease->yiaddr; #else packet.yiaddr = lease->yiaddr; #endif /* 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) && /* and its not already taken/offered */ /* ADDME: check that its not a static lease */ ((!(lease = find_lease_by_yiaddr(req_align)) || /* or its taken, but expired */ /* ADDME: or maybe in here */ lease_expired(lease)))) { #ifdef DHCPD_HEAP_REPLACE_STACK packet->yiaddr = req_align; /* FIXME: oh my, is there a host using this IP? */ #else packet.yiaddr = req_align; /* FIXME: oh my, is there a host using this IP? */ #endif /* otherwise, find a free IP */ /*ADDME: is it a static lease? */ } else { #ifdef DHCPD_HEAP_REPLACE_STACK packet->yiaddr = find_address(0); /* try for an expired lease */ if (!packet->yiaddr) packet->yiaddr = find_address(1); #else packet.yiaddr = find_address(0); /* try for an expired lease */ if (!packet.yiaddr) packet.yiaddr = find_address(1); #endif } #ifdef DHCPD_HEAP_REPLACE_STACK if(!(packet->yiaddr)) { if (packet != NULL) free(packet); #else if(!packet.yiaddr) { #endif DHCPD_LOG(LOG_WARNING, "no IP addresses to give -- OFFER abandoned"); return -1; } #ifdef DHCPD_HEAP_REPLACE_STACK if (!add_lease(packet->chaddr, packet->yiaddr, server_config.offer_time)) { if (packet != NULL) { free(packet); packet = NULL; } #else if (!add_lease(packet.chaddr, packet.yiaddr, server_config.offer_time)) { #endif DHCPD_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 */ #ifdef DHCPD_HEAP_REPLACE_STACK struct netif *netif = netif_find(server_config.interface); add_simple_option(packet->options, DHCP_LEASE_TIME, htonl(lease_time_align)); #ifdef __CONFIG_LWIP_V1 add_simple_option(packet->options, DHCP_SUBNET, ip4_addr_get_u32(&netif->netmask)); add_simple_option(packet->options, DHCP_ROUTER, ip4_addr_get_u32(&netif->gw)); add_simple_option(packet->options, DHCP_DNS_SERVER, ip4_addr_get_u32(&netif->ip_addr)); #elif LWIP_IPV4 /* now only for IPv4 */ add_simple_option(packet->options, DHCP_SUBNET, ip4_addr_get_u32(ip_2_ip4(&netif->netmask))); add_simple_option(packet->options, DHCP_ROUTER, ip4_addr_get_u32(ip_2_ip4(&netif->gw))); add_simple_option(packet->options, DHCP_DNS_SERVER, ip4_addr_get_u32(ip_2_ip4(&netif->ip_addr))); #else #error "IPv4 not support!" #endif #else add_simple_option(packet.options, DHCP_LEASE_TIME, htonl(lease_time_align)); #endif curr = server_config.options; while (curr) { if (curr->data[OPT_CODE] != DHCP_LEASE_TIME) #ifdef DHCPD_HEAP_REPLACE_STACK add_option_string(packet->options, curr->data); #else add_option_string(packet.options, curr->data); #endif curr = curr->next; } #ifdef DHCPD_HEAP_REPLACE_STACK add_bootp_options(packet); //addr.s_addr = packet->yiaddr; DHCPD_LOG(LOG_INFO, "sending OFFER of %s", inet_ntoa(packet->yiaddr)); int ret = send_packet(packet, 0); if (packet != NULL) { free(packet); packet = NULL; } return ret; #else add_bootp_options(&packet); addr.s_addr = packet.yiaddr; DHCPD_LOG(LOG_INFO, "sending OFFER of %s", inet_ntoa(addr)); return send_packet(&packet, 0); #endif } int sendNAK(struct dhcpMessage *oldpacket) { #ifdef DHCPD_HEAP_REPLACE_STACK struct dhcpMessage *packet; #else struct dhcpMessage packet; #endif #ifdef DHCPD_HEAP_REPLACE_STACK packet = calloc(1,sizeof(struct dhcpMessage)); if (!packet) DHCPD_LOG(LOG_ERR, "Calloc failed...%d",__LINE__); init_packet(packet, oldpacket, DHCPNAK); #else init_packet(&packet, oldpacket, DHCPNAK); #endif DEBUG(LOG_INFO, "sending NAK"); #ifdef DHCPD_HEAP_REPLACE_STACK int ret = send_packet(packet, 1); if (packet != NULL) free(packet); return ret; #else return send_packet(&packet, 1); #endif } int sendACK(struct dhcpMessage *oldpacket, u_int32_t yiaddr) { #ifdef DHCPD_HEAP_REPLACE_STACK struct dhcpMessage *packet; #else struct dhcpMessage packet; #endif struct option_set *curr; unsigned char *lease_time; u_int32_t lease_time_align = server_config.lease; //struct in_addr addr; #ifdef DHCPD_HEAP_REPLACE_STACK packet = calloc(1,sizeof(struct dhcpMessage)); if (!packet) DHCPD_LOG(LOG_ERR, "Calloc failed...%d",__LINE__); init_packet(packet, oldpacket, DHCPACK); packet->yiaddr = yiaddr; #else init_packet(&packet, oldpacket, DHCPACK); packet.yiaddr = yiaddr; #endif 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; else if (lease_time_align < server_config.min_lease) lease_time_align = server_config.lease; } #ifdef DHCPD_HEAP_REPLACE_STACK struct netif *netif = netif_find(server_config.interface); add_simple_option(packet->options, DHCP_LEASE_TIME, htonl(lease_time_align)); #ifdef __CONFIG_LWIP_V1 add_simple_option(packet->options, DHCP_SUBNET, ip4_addr_get_u32(&netif->netmask)); add_simple_option(packet->options, DHCP_ROUTER, ip4_addr_get_u32(&netif->gw)); add_simple_option(packet->options, DHCP_DNS_SERVER, ip4_addr_get_u32(&netif->ip_addr)); #elif LWIP_IPV4 /* now only for IPv4 */ add_simple_option(packet->options, DHCP_SUBNET, ip4_addr_get_u32(ip_2_ip4(&netif->netmask))); add_simple_option(packet->options, DHCP_ROUTER, ip4_addr_get_u32(ip_2_ip4(&netif->gw))); add_simple_option(packet->options, DHCP_DNS_SERVER, ip4_addr_get_u32(ip_2_ip4(&netif->ip_addr))); #else #error "IPv4 not support!" #endif #else add_simple_option(packet.options, DHCP_LEASE_TIME, htonl(lease_time_align)); #endif curr = server_config.options; while (curr) { if (curr->data[OPT_CODE] != DHCP_LEASE_TIME) #ifdef DHCPD_HEAP_REPLACE_STACK add_option_string(packet->options, curr->data); #else add_option_string(packet.options, curr->data); #endif curr = curr->next; } #ifdef DHCPD_HEAP_REPLACE_STACK add_bootp_options(packet); //addr.s_addr = packet->yiaddr; DHCPD_LOG(LOG_INFO, "sending ACK to %s", inet_ntoa(packet->yiaddr)); int ret = 0; if (send_packet(packet, 0) < 0) ret = -1; add_lease(packet->chaddr, packet->yiaddr, lease_time_align); if (packet) free(packet); return ret; #else add_bootp_options(&packet); //addr.s_addr = packet.yiaddr; DHCPD_LOG(LOG_INFO, "sending ACK to %s", inet_ntoa(packet->yiaddr)); if (send_packet(&packet, 0) < 0) return -1; add_lease(packet.chaddr, packet.yiaddr, lease_time_align); return 0; #endif } int send_inform(struct dhcpMessage *oldpacket) { #ifdef DHCPD_HEAP_REPLACE_STACK struct dhcpMessage *packet; #else struct dhcpMessage packet; #endif struct option_set *curr; #ifdef DHCPD_HEAP_REPLACE_STACK packet = calloc(1,sizeof(struct dhcpMessage)); if (!packet) DHCPD_LOG(LOG_ERR, "Calloc failed...%d",__LINE__); init_packet(packet, oldpacket, DHCPACK); #else init_packet(&packet, oldpacket, DHCPACK); #endif curr = server_config.options; while (curr) { if (curr->data[OPT_CODE] != DHCP_LEASE_TIME) #ifdef DHCPD_HEAP_REPLACE_STACK add_option_string(packet->options, curr->data); #else add_option_string(packet.options, curr->data); #endif curr = curr->next; } #ifdef DHCPD_HEAP_REPLACE_STACK add_bootp_options(packet); int ret = send_packet(packet, 0); if (packet) free(packet); return ret; #else add_bootp_options(&packet); return send_packet(&packet, 0); #endif }
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; }
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; 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]); /* 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; /* it is not impossible */ if (server_config.end < server_config.start) { uint32_t tmp_ip = server_config.start; server_config.start = server_config.end ; server_config.end = tmp_ip; } /* 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; } if (dhcps_shm_init() != 0) return -1; leases = xcalloc(server_config.max_leases, sizeof(struct dhcpOfferedAddr)); memset(leases, 0, 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 = uptime()/*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 - uptime()/*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 = uptime()/*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 = uptime()/*time(0)*/ + server_config.auto_time; continue; case SIGUSR2: LOG(LOG_INFO, "Received a SIGUSR2, now DHCP SERVER restart"); if (execv(argv[0], argv) == -1) printf("errno:%d\n", errno); /* NEVER reach here except execv failed! */ break; 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; } //printBuf(&packet, sizeof(struct dhcpMessage)); lease = find_lease_by_chaddr(packet.chaddr); if (!lease) { /* Look for a static lease */ static_lease_ip = getIpByMac(server_config.static_leases, &packet.chaddr); /* found */ if(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"); msglogd(LOG_INFO, LOGTYPE_DHCP, "DHCPS:Recv DISCOVER from %02X:%02X:%02X:%02X:%02X:%02X", packet.chaddr[0], packet.chaddr[1], packet.chaddr[2], packet.chaddr[3], packet.chaddr[4], packet.chaddr[5]); if (sendOffer(&packet) < 0) { LOG(LOG_ERR, "send OFFER failed"); } break; case DHCPREQUEST: //DEBUG(LOG_INFO, "received REQUEST"); msglogd(LOG_INFO, LOGTYPE_DHCP, "DHCPS:Recv REQUEST from %02X:%02X:%02X:%02X:%02X:%02X", packet.chaddr[0], packet.chaddr[1], packet.chaddr[2], packet.chaddr[3], packet.chaddr[4], packet.chaddr[5]); 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(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 { msglogd(LOG_INFO, LOGTYPE_DHCP, "DHCPS:Wrong Server id or request an invalid ip"); sendNAK(&packet); } } else { if (requested) { /* INIT-REBOOT State */ if (lease->yiaddr == requested_align) sendACK(&packet, lease->yiaddr); else { msglogd(LOG_INFO, LOGTYPE_DHCP, "DHCPS:Server id not found and request an invalid ip"); sendNAK(&packet); } } else { /* RENEWING or REBINDING State */ if (lease->yiaddr == packet.ciaddr) sendACK(&packet, lease->yiaddr); else { /* don't know what to do!!!! */ msglogd(LOG_INFO, LOGTYPE_DHCP, "DHCPS:Server id and requested ip not found"); msglogd(LOG_INFO, LOGTYPE_DHCP, "DHCPS:%x %x", lease->yiaddr, packet.ciaddr); 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 */ if ((lease = find_lease_by_yiaddr(requested_align))) { /* Requested IP already reserved by other one */ if (lease_expired(lease)) { /* probably best if we drop this lease */ memset(lease->chaddr, 0, 16); check_and_ack(&packet, requested_align); /* make some contention for this address */ } else /* still reserved by someone */ { msglogd(LOG_INFO, LOGTYPE_DHCP, "DHCPS:REQUEST ip %x already reserved by %02X:%02X:%02X:%02X:%02X:%02X", requested_align, lease->chaddr[0], lease->chaddr[1], lease->chaddr[2], lease->chaddr[3], lease->chaddr[4], lease->chaddr[5]); sendNAK(&packet); } } else /*if (requested_align < server_config.start || requested_align > server_config.end)*/ { check_and_ack(&packet, requested_align); } /* else remain silent */ } else { /* error state, just reply NAK modified by tiger 20090927 */ sendNAK(&packet); } break; case DHCPDECLINE: //DEBUG(LOG_INFO,"received DECLINE"); msglogd(LOG_INFO, LOGTYPE_DHCP, "DHCPS:Recv DECLINE from %02X:%02X:%02X:%02X:%02X:%02X", packet.chaddr[0], packet.chaddr[1], packet.chaddr[2], packet.chaddr[3], packet.chaddr[4], packet.chaddr[5]); if (lease) { memset(lease->chaddr, 0, 16); lease->expires = uptime()/*time(0)*/ + server_config.decline_time; } break; case DHCPRELEASE: //DEBUG(LOG_INFO,"received RELEASE"); msglogd(LOG_INFO, LOGTYPE_DHCP, "DHCPS:Recv RELEASE from %02X:%02X:%02X:%02X:%02X:%02X", packet.chaddr[0], packet.chaddr[1], packet.chaddr[2], packet.chaddr[3], packet.chaddr[4], packet.chaddr[5]); if (lease) { /* Delete the lease, lsz 080221 */ #if 1 memset(lease, 0, sizeof(struct dhcpOfferedAddr)); #else lease->expires = uptime()/*time(0)*/; #endif } break; case DHCPINFORM: //DEBUG(LOG_INFO,"received INFORM"); msglogd(LOG_INFO, LOGTYPE_DHCP, "DHCPS:Recv INFORM from %02X:%02X:%02X:%02X:%02X:%02X", packet.chaddr[0], packet.chaddr[1], packet.chaddr[2], packet.chaddr[3], packet.chaddr[4], packet.chaddr[5]); 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 dhcpOfferedAddr *lease) { struct dhcpMessage packet; u_int32_t req_align, lease_time_align = server_config.lease; unsigned char *req, *lease_time; struct option_set *curr; struct in_addr addr; unsigned long offer_time = server_config.offer_time; init_packet(&packet, oldpacket, DHCPOFFER); /* ADDME: if static, short circuit */ /* the client is in our lease/offered table */ if (lease) { #ifdef MY_DEBUG LOG(LOG_DEBUG,"(1)the client is in our lease/offered table"); #endif if(lease->expires == EXPIRES_NEVER) { /* static lease */ packet.yiaddr = lease->yiaddr; offer_time = EXPIRES_NEVER; /* offer infinite time */ } else if(!check_ip(lease->yiaddr)){ // Confirm the ip isn't used by someone, by honor if (!lease_expired(lease)) lease_time_align = lease->expires - get_time(0); else goto find_ip; packet.yiaddr = lease->yiaddr; } else goto find_ip; /* 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) && /* and its not already taken/offered */ /* ADDME: check that its not a static lease */ ((!(lease = find_lease_by_yiaddr(req_align)) || /* or its taken, but expired */ /* ADDME: or maybe in here */ lease_expired(lease)))) { #ifdef MY_DEBUG LOG(LOG_DEBUG,"(2)the client has a requested ip"); #endif if(req_align == server_config.server) // The request ip cann't be router ip, by honor goto find_ip; else if(!check_ip(req_align)) // Confirm the ip isn't used by someone, by honor packet.yiaddr = req_align; /* FIXME: oh my, is there a host using this IP? */ else goto find_ip; /* otherwise, find a free IP */ /*ADDME: is it a static lease? */ } else { find_ip: // by honor #ifdef MY_DEBUG LOG(LOG_DEBUG,"(3)find a free IP"); #endif 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, offer_time)) { 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 */ 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; LOG(LOG_INFO, "broadcasting OFFER of %s to %02x:%02x:%02x:%02x:%02x:%02x", inet_ntoa(addr), packet.chaddr[0], packet.chaddr[1], packet.chaddr[2], packet.chaddr[3], packet.chaddr[4], packet.chaddr[5]); return send_packet(&packet, 1); // Send broadcast rather than unicast, by honor }