后面我将给你一个IPC的dhcps模块,给我注释,大概1000行代码, /* dhcps.h */
#ifndef _DHCPS_H
#define _DHCPS_H
#include "dhcp.h"
#define MAX_FILE_NAME_LEN 256
#define MAX_BOOTP_SRV_NAME_LEN 16
#define DHCPS_DOMAIN_NAME_LENGTH 32
#define DHCP_4G_ROUTER_STR "4g router"
#define DHCP_4G_ROUTER_LEN 9
/*****************************************************************************************
**********************DHCPS SERVER CLASS**************************************************
*****************************************************************************************/
#define DHCPS_LEASE_LIST_SIZE 128
typedef struct _DHCPS_LEASE
{
U8 host_name[32];
U8 mac[6];
U32 state;
U32 ip;
U32 expires;
}DHCPS_LEASE;
typedef struct _DHCP_OPTION_STATIC
{
UINT8 lease[6];
UINT8 subnet[6];
UINT8 router[6];
UINT8 dns[10];
char domain[34];
UINT8 router4g[DHCP_4G_ROUTER_LEN+2];
}DHCP_OPTION_STATIC;
/* Struct to store public server config.*/
typedef struct _DHCPS_PARAMS
{
S32 sock; /* Berkeley Packet Filter Device in vxworks OS or skt in linux OS */
S32 inet_iendx;
S32 timer_index;
char dev_name[32];
S32 dev;
UINT8 mac[6]; /* Our mac address */
U32 decline_time; /* how long an address is reserved if a client returns a * decline message */
U32 conflict_time; /* how long an arp conflict offender is leased for */
U32 offer_time; /* how long an offered address is reserved */
U32 min_lease; /* minimum lease a client can request*/
U32 server; /* Our IP, in network order */
U32 netmask; /* Our netmask */
U32 gateway; /*added by yangying for*/
U32 dns_server[2];
char host_name[DHCPS_DOMAIN_NAME_LENGTH];
DHCP_OPTION_STATIC options; /* List of DHCP options loaded from the config file */
U32 start; /* Start address of leases, network order */
U32 end; /* End of leases, network order */
U32 lease_time; /* lease time in seconds (host order) */
U32 siaddr; /* next server bootp option */
char sname[MAX_BOOTP_SRV_NAME_LEN]; /* bootp server name */
char boot_file[MAX_FILE_NAME_LEN]; /* bootp boot file option */
DHCPS_LEASE lease[DHCPS_LEASE_LIST_SIZE];
U16 is_lte;
}DHCPS_PARAMS;
#define DHCPS_DEBUG(fmt, ...) NSD_DEBUG("[DHCPS]" fmt, ##__VA_ARGS__)
#define DHCPS_INFO(fmt, ...) NSD_LOG(LOG_INFO, "[Network][DHCP]" fmt, ##__VA_ARGS__)
#define DHCPS_WARN(fmt, ...) NSD_WARN("[DHCPS]" fmt, ##__VA_ARGS__)
#endif
/* dhcps.c
*
* udhcp Server
* Copyright (C) 1999 Matthew Ramsay <matthewr@moreton.com.au>
* Chris Trew <ctrew@moreton.com.au>
*
* Rewrite by Russ Dill <Russ.Dill@asu.edu> July 2001
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <netinet/if_ether.h>
#include <linux/filter.h>
#include <linux/if_packet.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "options.h"
#include "packet.h"
#include "dhcp.h"
#include "dhcps.h"
#include "libds.h"
/* DHCPS模块中各个参数项单位都改为秒 */
#define LEASE_TIME_MAX (48*60*60) /* 租期最长2天 */
#define LEASE_TIME_MIN (1*60) /* 租期最短一分钟 */
#define LEASE_OFFER_TIME (2*60*60)
#define DECLINE_TIME (60*60)
#define CONFLICT_TIME (60*60)
#define DHCP_CHANGE_RECEIVE_PORT 52261
#define DHCP_CHANGE_SEND_PORT 52262
#define DEFAULT_DHCPS_IP "192.168.191.1"
#define DEFAULT_DHCPS_MASK "255.255.255.0"
#define DEF_DHCPS_IP_BEGIN "192.168.191.120"
#define DEF_DHCPS_IP_END "192.168.191.199"
#define DHCPS_HOST_NAME_LEN 32
#define DHCPS_OPTION_AUTO "auto"
#define DHCPS_OPTION_ENABLE "enable"
#define DHCPS_OPTION_POOLSTART "pool_start"
#define DHCPS_OPTION_POOLEND "pool_end"
#define DHCPS_OPTION_LEASETIME "lease_time"
#define DHCPS_OPTION_GATEWAY "gateway"
#define DHCPS_OPTION_PRIDNS "pri_dns"
#define DHCPS_OPTION_SNDDNS "snd_dns"
#define DHCPS_OPTION_IP "ip"
#define DHCPS_OPTION_MAC "mac"
#define DHCPS_OPTION_EXPIRES "expires"
#define DHCPS_OPTION_HOSTNAME "hostname"
DHCPS_PARAMS dhcps_params;
LOCAL struct dhcp_packet recv_dhcp_packet;
LOCAL struct dhcp_packet packet;
#define DHCPS_MALLOC(size) malloc(size)
#define DHCPS_FREE(addr) free((UINT8*)(addr))
#define ISNOTSAMESUBNET(ip1, ip2, mask) (0 != (((ip1) ^ (ip2)) & (mask)))
/* 是否4G IPC - 4G上网模式 */
LOCAL U16 get_lte_enabled(void)
{
LTE_CAPABILITY lte_cap = {0};
LTE_CONFIG_INFO_DATA lte_config = {0};
if (0 == ds_read(LTE_CAPABILITY_PATH, (U8 *)<e_cap, sizeof(lte_cap)))
{
//未定义lte_capability,判断为非4G IPC,未开启4G上网模式
return 0;
}
if (0 == ds_read(LTE_INFO_DATA_PATH, (U8 *)<e_config, sizeof(lte_config)))
{
//4G IPC默认4G上网模式,获取失败时按照4G上网处理
return 1;
}
return !(lte_cap.internet_wired_support && lte_config.internet_wired_enable);
}
/* clear every lease out that chaddr OR yiaddr matches and is nonzero */
LOCAL void clear_lease(U8 *mac, U32 ip, DHCPS_LEASE *leases)
{
S32 i, j, k;
for (j = 0; j < CHADDR_LEN && !mac[j]; j++);
for (i = 0; i < DHCPS_LEASE_LIST_SIZE; i++)
{
if ((j != CHADDR_LEN && !memcmp(leases[i].mac, mac, 6)) ||
(ip && leases[i].ip == ip))
{
memset(&(leases[i]), 0, sizeof(leases[i]));
for (k = i;(k + 1) < DHCPS_LEASE_LIST_SIZE; k++)
{
memcpy(&(leases[k]), &(leases[k + 1]), sizeof(leases[k]));
memset(&(leases[k + 1]), 0, sizeof(leases[k + 1]));
}
i--;
}
}
}
/* Find the oldest expired lease, NULL if there are no expired leases */
LOCAL S32 oldest_expired_lease(DHCPS_LEASE *leases)
{
U32 i;
for (i = 0; i < DHCPS_LEASE_LIST_SIZE; i++)
{
if (leases[i].expires == 0)
{
return i;
}
}
return -1;
}
/* add a lease into the table, clearing out any old ones */
LOCAL S32 add_lease(U32 state, char *host_name, U8 *mac, U32 ip, U32 time_lease, DHCPS_LEASE *dhcps_lease)
{
S32 lease_index = -1 ;
IP_ADDR ipAddr = {0};
/* clean out any old ones */
clear_lease(mac, ip, dhcps_lease);
lease_index = oldest_expired_lease(dhcps_lease);
if (lease_index != -1)
{
dhcps_lease[lease_index].state = state;
DHCPS_DEBUG("state = %d", dhcps_lease[lease_index].state);
memcpy(dhcps_lease[lease_index].host_name, host_name, 32); /* add by Li Shaozhang, 07Jun07 */
DHCPS_DEBUG("hostname = %s", dhcps_lease[lease_index].host_name);
memcpy(dhcps_lease[lease_index].mac, mac, 6);
DHCPS_DEBUG("mac = %02x-%02x-%02x-%02x-%02x-%02x", dhcps_lease[lease_index].mac[0],\
dhcps_lease[lease_index].mac[1], dhcps_lease[lease_index].mac[2],\
dhcps_lease[lease_index].mac[3], dhcps_lease[lease_index].mac[4],\
dhcps_lease[lease_index].mac[5]);
dhcps_lease[lease_index].ip = ip;
ipAddr.ipAddr = ip;
DHCPS_DEBUG("ip = %d.%d.%d.%d", ipAddr.ipAddrByteFormat[0], ipAddr.ipAddrByteFormat[1],
ipAddr.ipAddrByteFormat[2], ipAddr.ipAddrByteFormat[3]);
dhcps_lease[lease_index].expires = time_lease;
DHCPS_DEBUG("lease = %d", dhcps_lease[lease_index].expires);
}
return lease_index;
}
/* true if a lease has expired */
LOCAL S32 lease_expired(S32 lease_index, DHCPS_LEASE *dhcps_lease)
{
return (dhcps_lease[lease_index].expires == 0);
}
/*
* Find the first lease that matches chaddr, NULL if no match.
* Modified by xcl, if the lease ip is not in the same subnet, deleted it and return null.
*/
LOCAL S32 find_lease_by_mac(U8 *mac, DHCPS_LEASE *dhcps_lease)
{
U32 i;
for (i = 0; i < DHCPS_LEASE_LIST_SIZE; i++)
{
if (!memcmp(dhcps_lease[i].mac, mac, 6))
{
/* If not in the very subnet, delete this lease. Modified by xcl.*/
if (0 == ((dhcps_lease[i].ip ^ dhcps_params.server) & dhcps_params.netmask))
{
return i;
}
memset(&(dhcps_lease[i]), 0, sizeof(dhcps_lease[i]));
}
}
return -1;
}
/* Find the first lease that matches yiaddr, NULL is no match */
LOCAL S32 find_lease_by_ip(U32 ip, DHCPS_LEASE *dhcps_lease)
{
U32 i;
for (i = 0; i < DHCPS_LEASE_LIST_SIZE; i++)
{
if (dhcps_lease[i].ip == ip)
{
return i;
}
}
return -1;
}
/* check is an IP is taken, if it is, add it to the lease table */
LOCAL S32 check_ip(U32 addr, DHCPS_LEASE *dhcps_lease)
{
char strIp[18] = {0};
/* Added for bug: dut会将lan IP(若在地址池范围内)分配出去,若收到此IP的Client无
* 免费arp检查功能,将导致IP冲突. 2011-12-27, xcl.*/
if (addr == dhcps_params.server)
{
DHCPS_WARN("The IP distributed equals to server ip, ignore!!!");
return 1;
}
if (0 == arpping(addr, recv_dhcp_packet.chaddr, dhcps_params.server, dhcps_params.mac, dhcps_params.dev_name, 500))
{
DHCPS_WARN("%s belongs to someone, reserving it for %ld seconds.",
strIp, dhcps_params.conflict_time);
return 1;
}
return 0;
}
/* Check if an ip is in dhcp server pool or not. */
LOCAL S32 ip_in_srv_pool(U32 ip)
{
IP_ADDR ipAddr = {0};
ipAddr.ipAddr = ip;
ip = ntohl(ip);
if ((ip >= ntohl(dhcps_params.start)) &&
(ip <= ntohl(dhcps_params.end)) && (ip != ntohl(dhcps_params.server)))
{
return 1;
}
DHCPS_WARN("IP(%d.%d.%d.%d) not in dhcp pool or equal to server ip, ignore!!!", ipAddr.ipAddrByteFormat[0],
ipAddr.ipAddrByteFormat[1], ipAddr.ipAddrByteFormat[2], ipAddr.ipAddrByteFormat[3]);
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... */
LOCAL U32 find_address(S32 check_expired, DHCPS_LEASE *dhcps_lease)
{
U32 addrStart, addrEnd; /* 主机序,用于遍历地址池 */
U32 ret; /* 网络序,存放查找到的地址 */
S32 lease_index = -1;
U32 mask = 0;
mask = ntohl(dhcps_params.netmask);
addrStart = ntohl(dhcps_params.start);
addrEnd = ntohl(dhcps_params.end);
for (; addrStart <= addrEnd; addrStart++)/* Modified by xcl, 2011-06-01.*/
{
ret = htonl(addrStart);
/* ie, 192.168.55.0 */
if (!(ret & (~mask)))
{
continue;
}
/* ie, 192.168.55.255 */
if ((ret & (~mask)) == (~mask))
{
continue;
}
/* ip已被dhcps分配出去 */
if (-1 != (lease_index = find_lease_by_ip(ret, dhcps_lease)))
{
if (check_expired && lease_expired(lease_index, dhcps_lease))
{
return ret;
}
continue;
}
/* 有静态接入主机正在使用该IP也要跳过 */
if (TRUE == check_ip(ret, dhcps_lease))
{
continue;
}
return ret;
}
return 0;
}
/* send a dhcp packet, if force broadcast is set, the packet will be broadcast to the client */
LOCAL S32 send_packet(struct dhcp_packet *payload, S32 force_broadcast)
{
U8 *chaddr = NULL;
U32 ciaddr = 0;
if (force_broadcast)
{
DHCPS_DEBUG("Broadcasting packet to client (NAK).");
ciaddr = INADDR_BROADCAST;
chaddr = MAC_BCAST_ADDR;
}
else if (ntohs(payload->flags) & BROADCAST_FLAG)
{
DHCPS_DEBUG("Broadcasting packet to client (requested).");
ciaddr = INADDR_BROADCAST;
chaddr = MAC_BCAST_ADDR;
}
else if ((0 == payload->yiaddr) && (payload->ciaddr))
{
DHCPS_DEBUG("Unicasting packet to client ciaddr.");
ciaddr = payload->ciaddr;
chaddr = payload->chaddr;
}
else
{
ciaddr = payload->yiaddr;
chaddr = payload->chaddr;
}
return make_and_send_dhcp_frame(payload, dhcps_params.server, SERVER_PORT,
ciaddr, CLIENT_PORT, chaddr, dhcps_params.dev);
}
LOCAL void init_packet(struct dhcp_packet *packet, struct dhcp_packet *old_packet, char type)
{
init_header(packet, type);
packet->xid = old_packet->xid;
memcpy(packet->chaddr, old_packet->chaddr, CHADDR_LEN);
packet->flags = old_packet->flags;
packet->giaddr = old_packet->giaddr;
packet->ciaddr = old_packet->ciaddr;
add_simple_option(packet->options, DHCP_SERVER_ID, dhcps_params.server);
}
/* add in the bootp options */
LOCAL void add_bootp_options(struct dhcp_packet *packet)
{
packet->siaddr = dhcps_params.siaddr;
if (dhcps_params.sname)
{
strncpy((char *)packet->sname, dhcps_params.sname, sizeof(packet->sname) - 1);
}
if (dhcps_params.boot_file)
{
strncpy((char *)packet->file, dhcps_params.boot_file, sizeof(packet->file) - 1);
}
}
LOCAL S32 get_host_name_len(char* name, S32 len)
{
S32 index = 0;
S32 language_flag = 0;
if (len < 32)
{
return len;
}
for (index=0; index < 31; index++)
{
/* GB2312编码每个汉字及符号以两个字节来表示,高位字节使用了0xA1-0xF7,低位字节使用了0xA1-0xFE。*/
/* 为保障存储汉字不出现乱码,出现奇数个大于0xA1的字节时,去掉最后一个。这种方法只能解决采用 */
/* GB2312编码的乱码问题 */
if (*(UINT8*)(name + index) >= 0xA1)
{
language_flag ^= 1;
}
}
if (language_flag == 0)
{
return 31;
}
return 30;
}
/* send a DHCP OFFER to a DHCP DISCOVER */
LOCAL S32 send_offer(struct dhcp_packet *old_packet, DHCPS_LEASE *dhcps_lease)
{
S32 lease_index = -1;
U32 req_align, lease_time_align = dhcps_params.lease_time;
U8 *req, *lease_time;
char blank_hostname[] = /*"Unknown"*/"";
S32 copy_host_name_len;
IP_ADDR ip_addr = {0};
char host_name[DHCPS_HOST_NAME_LEN];
char *host_name_start, *host_name_len;
U32 lease_ip;
DHCPS_DEBUG("before init_packet.");
init_packet(&packet, old_packet, DHCPOFFER);
/* the client has a requested ip */
if ((req = get_option(old_packet, DHCP_REQUESTED_IP)) &&
memcpy(&req_align, req, 4) && ip_in_srv_pool(req_align) &&
(((-1 == (lease_index = find_lease_by_ip(req_align, dhcps_lease))) ||
lease_expired(lease_index, dhcps_lease))))
{
lease_ip = req_align;
if (TRUE == check_ip(lease_ip, dhcps_lease))
{
goto choose_dynamic_lease_ip;
}
packet.yiaddr = lease_ip;
goto send_offer;
}
choose_dynamic_lease_ip:
lease_index = find_lease_by_mac(old_packet->chaddr, dhcps_lease);
if (-1 != lease_index)
{
/* lease的时间到期或者ip已经不在地址池中。 */
if ((FALSE == ip_in_srv_pool(dhcps_lease[lease_index].ip)) ||
lease_expired(lease_index, dhcps_lease))
{
memset(&(dhcps_lease[lease_index]), 0, sizeof(dhcps_lease[lease_index]));
lease_index = -1;
goto choose_pool_ip;
}
lease_time_align = dhcps_lease[lease_index].expires;
packet.yiaddr = dhcps_lease[lease_index].ip;
goto send_offer;
}
choose_pool_ip:
packet.yiaddr = find_address(0, dhcps_lease);
if (0 == packet.yiaddr)
{
packet.yiaddr = find_address(1, dhcps_lease);
}
if(0 == packet.yiaddr)
{
DHCPS_WARN("No ip addresses to give, OFFER abandoned.");
return -1;
}
send_offer:
if (0xFFFFFFFF != lease_time_align) /* 非静态条目。 */
{
if (!(host_name_start = (char *)get_option(old_packet, DHCP_HOST_NAME)))
{
DHCPS_WARN("Lease host name not found.");
/* host_name_start = blank_hostname;*/
memset(host_name, 0, DHCPS_HOST_NAME_LEN);
memcpy(host_name, blank_hostname, strlen(blank_hostname));
}
else
{
host_name_len = host_name_start - OPT_LEN;
memset(host_name, 0, DHCPS_HOST_NAME_LEN);
/* fix host name length bug by tiger 20091208 */
copy_host_name_len = get_host_name_len(host_name_start, *host_name_len);
memcpy(host_name, host_name_start, copy_host_name_len);
}
if (-1 == add_lease(DHCPOFFER, host_name, packet.chaddr, packet.yiaddr, dhcps_params.offer_time, dhcps_lease))
{
DHCPS_WARN("Lease pool is full, OFFER abandoned.");
return -1;
}
if ((lease_time = get_option(old_packet, DHCP_LEASE_TIME)))
{
memcpy(&lease_time_align, lease_time, 4);
DHCPS_DEBUG("lease time = %d ", lease_time);
lease_time_align = ntohl(lease_time_align);
if (lease_time_align > (dhcps_params.lease_time*60))
{
lease_time_align = (dhcps_params.lease_time*60);
}
}
/* Make sure we aren't just using the lease time from the previous offer */
if (lease_time_align < dhcps_params.min_lease)
{
lease_time_align = dhcps_params.lease_time;
}
}
DHCPS_DEBUG("OFFER lease time = %d; configed dhcp lease = %d\n", lease_time_align, dhcps_params.lease_time);
add_simple_option(packet.options, DHCP_LEASE_TIME, htonl(lease_time_align));
add_option_string(packet.options, dhcps_params.options.dns);
add_option_string(packet.options, dhcps_params.options.subnet);
add_option_string(packet.options, dhcps_params.options.router);
if(dhcps_params.is_lte)
{
DHCPS_DEBUG("OFFER: lte enabled\n");
add_option_string(packet.options, dhcps_params.options.router4g);
}
/*addVendorSpecInfo(oldpacket, packet.options);*/
add_bootp_options(&packet);
ip_addr.ipAddr = packet.yiaddr;
DHCPS_INFO("Send OFFER with ip %d.%d.%d.%d.", ip_addr.ipAddrByteFormat[0], ip_addr.ipAddrByteFormat[1],
ip_addr.ipAddrByteFormat[2], ip_addr.ipAddrByteFormat[3]);
return send_packet(&packet, 0);
}
LOCAL S32 send_NAK(struct dhcp_packet *old_packet)
{
init_packet(&packet, old_packet, DHCPNAK);
return send_packet(&packet, 1);
}
LOCAL S32 send_ACK(struct dhcp_packet *old_packet, U32 ip, DHCPS_LEASE *dhcps_lease)
{
U8 *lease_time;
U32 lease_time_align = dhcps_params.lease_time;
char blank_hostname[] = /*"Unknown"*/"";
IP_ADDR ipAddr = {0};
U8 host_name[DHCPS_HOST_NAME_LEN];
U8 *host_name_start = NULL;
U8 *host_name_len = NULL;
S32 copy_host_name_len = 0;
init_packet(&packet, old_packet, DHCPACK);
packet.yiaddr = ip;
if ((lease_time = get_option(old_packet, DHCP_LEASE_TIME)))
{
memcpy(&lease_time_align, lease_time, 4);
lease_time_align = ntohl(lease_time_align);
if ((lease_time_align < dhcps_params.min_lease) || (lease_time_align > dhcps_params.lease_time))
{
lease_time_align = dhcps_params.lease_time;
}
}
DHCPS_DEBUG("ACK lease time = %d\n", lease_time_align);
add_simple_option(packet.options, DHCP_LEASE_TIME, htonl(lease_time_align));
add_option_string(packet.options, dhcps_params.options.dns);
add_option_string(packet.options, dhcps_params.options.subnet);
add_option_string(packet.options, dhcps_params.options.router);
if(dhcps_params.is_lte)
{
DHCPS_DEBUG("ACK: lte enabled\n");
add_option_string(packet.options, dhcps_params.options.router4g);
}
/*addVendorSpecInfo(oldpacket, packet.options);*/
add_bootp_options(&packet);
ipAddr.ipAddr = packet.yiaddr;
DHCPS_DEBUG("Send ACK to %d.%d.%d.%d.", ipAddr.ipAddrByteFormat[0], ipAddr.ipAddrByteFormat[1],
ipAddr.ipAddrByteFormat[2], ipAddr.ipAddrByteFormat[3]); /* TODO:只在请求OFFER时输出信息 */
if (send_packet(&packet, 0) < 0)
{
return -1;
}
if (!(host_name_start = get_option(old_packet, DHCP_HOST_NAME)))
{
DHCPS_DEBUG("Lease host name not found."); /* TODO:只在请求OFFER时输出信息 */
memset(host_name, 0, DHCPS_HOST_NAME_LEN);
memcpy(host_name, blank_hostname, strlen(blank_hostname));
}
else
{
/* fix host name length bug by tiger 20091208 */
host_name_len = host_name_start - OPT_LEN;
copy_host_name_len = get_host_name_len((char *)host_name_start, (int)*host_name_len);
if(copy_host_name_len > DHCPS_HOST_NAME_LEN)
{
return -1;
}
memset(host_name, 0, DHCPS_HOST_NAME_LEN);
memcpy(host_name, host_name_start, copy_host_name_len);
}
add_lease(DHCPACK, (char *)host_name, packet.chaddr, packet.yiaddr, lease_time_align, dhcps_lease);
return OK;
}
LOCAL S32 send_inform(struct dhcp_packet *old_packet)
{
init_packet(&packet, old_packet, DHCPACK);
add_option_string(packet.options, dhcps_params.options.dns);
add_option_string(packet.options, dhcps_params.options.subnet);
add_option_string(packet.options, dhcps_params.options.router);
if(dhcps_params.is_lte)
{
DHCPS_DEBUG("INFORM: lte enabled\n");
add_option_string(packet.options, dhcps_params.options.router4g);
}
add_bootp_options(&packet);
return send_packet(&packet, 0);
}
LOCAL S32 check_and_ack(struct dhcp_packet* packet, UINT32 ip, DHCPS_LEASE *dhcps_lease)
{
IP_ADDR ip_addr1 = {0};
ip_addr1.ipAddr = ip;
/* if some one reserve it */
if (ip != packet->ciaddr && check_ip(ip, dhcps_lease))
{
DHCPS_INFO("REQUEST ip %d.%d.%d.%d already reserved by someone", ip_addr1.ipAddrByteFormat[0],
ip_addr1.ipAddrByteFormat[1], ip_addr1.ipAddrByteFormat[2] ,ip_addr1.ipAddrByteFormat[3]);
return send_NAK(packet);
}
if (!ip_in_srv_pool(ip))
{
DHCPS_INFO("REQUEST ip %d.%d.%d.%d is not in the address pool", ip_addr1.ipAddrByteFormat[0],
ip_addr1.ipAddrByteFormat[1], ip_addr1.ipAddrByteFormat[2] ,ip_addr1.ipAddrByteFormat[3]);
return send_NAK(packet);
}
return send_ACK(packet, ip, dhcps_lease);
}
LOCAL void destroy_sock(S32 sock)
{
if (-1 != sock)
{
close(sock);
}
}
LOCAL S32 create_sock()
{
struct sockaddr_in sock_addr;
S32 option = 1;
S32 sock = -1;
/* 因为MAX_GROUP_NUM为1,而且这里也只有1份DHCP服务器配置,这里就暂不考虑为多网段提供DHCP服务了。 */
if (ERROR == (sock = socket(AF_INET, SOCK_DGRAM, 0)))
{
DHCPS_WARN("server socket call failed: %m");
goto error_exit;
}
if (ERROR == setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
(char *)&option, sizeof(option)))
{
DHCPS_WARN("server socket set reuseaddr option failed: %m");
goto error_exit;
}
if (ERROR == setsockopt(sock, SOL_SOCKET, SO_BROADCAST,
(char *) &option, sizeof(option)))
{
DHCPS_WARN("server socket set broadcast option failed: %m");
goto error_exit;
}
memset(&sock_addr, 0, sizeof(sock_addr));
sock_addr.sin_family = AF_INET;
sock_addr.sin_port = htons(SERVER_PORT);
sock_addr.sin_addr.s_addr = INADDR_ANY; /* 这里只是针对单个网段提供服务,可以这样做,但如果考虑多网段,多接口,则必须绑定接口的实际地址。 */
if (ERROR == bind(sock, (struct sockaddr *)&sock_addr, sizeof(sock_addr)))
{
DHCPS_WARN("server socket set broadcast option failed: %m");
goto error_exit;
}
return sock;
error_exit:
destroy_sock(sock);
return -1;
}
LOCAL void dhcps_check_timer()
{
U32 index = 0;
U32 move_index = 0;
DHCPS_LEASE *dhcps_lease = NULL;
dhcps_lease = dhcps_params.lease;
for (index = 0; index < DHCPS_LEASE_LIST_SIZE; index++)
{
if (dhcps_lease[index].ip == 0 || dhcps_lease[index].expires == 0xFFFFFFFF)
{
continue;
}
if (dhcps_lease[index].expires > 0)
{
dhcps_lease[index].expires -= 1;
continue;
}
for (move_index = index; (move_index + 1) < DHCPS_LEASE_LIST_SIZE; move_index++)
{
memcpy(&(dhcps_lease[move_index]), &(dhcps_lease[move_index + 1]), sizeof(dhcps_lease[move_index]));
memset(&(dhcps_lease[move_index + 1]), 0, sizeof(dhcps_lease[move_index + 1]));
}
index--;
}
}
LOCAL void dhcps_handle(S32 sock)
{
U8 *server_id, *requested;
U32 server_id_align, requested_align;
S32 bytes = 0;
U8 *state = NULL;
S32 lease_index = -1;
DHCPS_LEASE *dhcps_lease = NULL;
U32 move_index = 0;
IP_ADDR ip_addr1 = {0};
IP_ADDR ip_addr2 = {0};
dhcps_lease = dhcps_params.lease;
if ((bytes = get_packet(&recv_dhcp_packet, dhcps_params.sock)) < 0)
{
DHCPS_WARN("Error on read, %m, reopening socket.");
return;
}
if ((state = get_option(&recv_dhcp_packet, DHCP_MESSAGE_TYPE)) == NULL)
{
DHCPS_WARN("Couldn't get option from packet, ignoring.");
return;
}
lease_index = find_lease_by_mac(recv_dhcp_packet.chaddr, dhcps_lease);
if (-1 != lease_index)
{
/* 如果租约过期需要老化,或者租约与地址段不匹配,需要强制老化。 */
if ((lease_expired(lease_index, dhcps_lease)) || !ip_in_srv_pool(dhcps_lease[lease_index].ip))
{
memset(&(dhcps_lease[lease_index]), 0, sizeof(dhcps_lease[lease_index]));
lease_index = -1;
}
}
switch (state[0])
{
case DHCPDISCOVER:
DHCPS_DEBUG("Recv DISCOVER from %02X:%02X:%02X:%02X:%02X:%02X.",
recv_dhcp_packet.chaddr[0], recv_dhcp_packet.chaddr[1], recv_dhcp_packet.chaddr[2],
recv_dhcp_packet.chaddr[3], recv_dhcp_packet.chaddr[4], recv_dhcp_packet.chaddr[5]); /* 防止被攻击时持续刷log */
if (send_offer(&recv_dhcp_packet, dhcps_lease) < 0)
{
DHCPS_WARN("Send OFFER failed.");
}
break;
case DHCPREQUEST:
DHCPS_DEBUG("Recv REQUEST from %02X:%02X:%02X:%02X:%02X:%02X.",
recv_dhcp_packet.chaddr[0], recv_dhcp_packet.chaddr[1], recv_dhcp_packet.chaddr[2],
recv_dhcp_packet.chaddr[3], recv_dhcp_packet.chaddr[4], recv_dhcp_packet.chaddr[5]);
requested = get_option(&recv_dhcp_packet, DHCP_REQUESTED_IP);
server_id = get_option(&recv_dhcp_packet, DHCP_SERVER_ID);
if (NULL != requested)
{
memcpy(&requested_align, requested, 4);
}
if (NULL != server_id)
{
memcpy(&server_id_align, server_id, 4);
}
if (-1 != lease_index)
{
/* SELECTING State */
if ((NULL != server_id) && (server_id_align == dhcps_params.server) &&
(NULL != requested) && (requested_align == dhcps_lease[lease_index].ip))
{
send_ACK(&recv_dhcp_packet, dhcps_lease[lease_index].ip, dhcps_lease);
}
/* INIT-REBOOT State */
else if ((NULL == server_id) && (NULL != requested) &&
(dhcps_lease[lease_index].ip == requested_align))
{
send_ACK(&recv_dhcp_packet, dhcps_lease[lease_index].ip, dhcps_lease);
}
/* RENEWING or REBINDING State */
else if ((NULL == server_id) && (NULL == requested) &&
(dhcps_lease[lease_index].ip == recv_dhcp_packet.ciaddr))
{
send_ACK(&recv_dhcp_packet, dhcps_lease[lease_index].ip, dhcps_lease);
}
else
{
/* todo: 显示有效的requested_align */
ip_addr1.ipAddr = recv_dhcp_packet.ciaddr;
ip_addr2.ipAddr = dhcps_lease[lease_index].ip;
DHCPS_INFO("Send NAK to %d.%d.%d.%d, lease ip %d.%d.%d.%d.", ip_addr1.ipAddrByteFormat[0],
ip_addr1.ipAddrByteFormat[1], ip_addr1.ipAddrByteFormat[2] ,ip_addr1.ipAddrByteFormat[3],
ip_addr2.ipAddrByteFormat[0], ip_addr2.ipAddrByteFormat[1],ip_addr2.ipAddrByteFormat[2],
ip_addr2.ipAddrByteFormat[3]);
send_NAK(&recv_dhcp_packet);
}
}
else if (NULL != requested)
{
/* INIT-REBOOT State */
if (-1 != (lease_index = find_lease_by_ip(requested_align, dhcps_lease)))
{
/* Requested IP already reserved by other one */
if (lease_expired(lease_index, dhcps_lease))
{
/* probably best if we drop this lease */
memset(&(dhcps_lease[lease_index]), 0, sizeof(dhcps_lease[lease_index]));
lease_index = -1;
check_and_ack(&recv_dhcp_packet, requested_align, dhcps_lease);
/* make some contention for this address */
}
else /* still reserved by someone */
{
ip_addr1.ipAddr = requested_align;
DHCPS_INFO("REQUEST ip %d.%d.%d.%d already reserved by %02X:%02X:%02X:%02X:%02X:%02X",
ip_addr1.ipAddrByteFormat[0], ip_addr1.ipAddrByteFormat[1], ip_addr1.ipAddrByteFormat[2],
ip_addr1.ipAddrByteFormat[3], dhcps_lease[lease_index].mac[0], dhcps_lease[lease_index].mac[1],
dhcps_lease[lease_index].mac[2], dhcps_lease[lease_index].mac[3],
dhcps_lease[lease_index].mac[4], dhcps_lease[lease_index].mac[5]);
send_NAK(&recv_dhcp_packet);
}
}
else
{
check_and_ack(&recv_dhcp_packet, requested_align, dhcps_lease);
}
}
else
{
ip_addr1.ipAddr = recv_dhcp_packet.ciaddr;
DHCPS_INFO("Send NAK to %d.%d.%d.%d.", ip_addr1.ipAddrByteFormat[0], ip_addr1.ipAddrByteFormat[1],
ip_addr1.ipAddrByteFormat[2], ip_addr1.ipAddrByteFormat[3]);
send_NAK(&recv_dhcp_packet);
}
/* otherwise on reply. */
break;
case DHCPDECLINE:
DHCPS_INFO("Recv DECLINE from %02X:%02X:%02X:%02X:%02X:%02X.",
recv_dhcp_packet.chaddr[0], recv_dhcp_packet.chaddr[1], recv_dhcp_packet.chaddr[2],
recv_dhcp_packet.chaddr[3], recv_dhcp_packet.chaddr[4], recv_dhcp_packet.chaddr[5]);
if (lease_index != -1)
{
memset(dhcps_lease[lease_index].mac, 0, 6);
dhcps_lease[lease_index].expires = dhcps_params.decline_time;
dhcps_lease[lease_index].state = 0;
}
break;
case DHCPRELEASE:
DHCPS_INFO("Recv RELEASE from %02X:%02X:%02X:%02X:%02X:%02X.",
recv_dhcp_packet.chaddr[0], recv_dhcp_packet.chaddr[1], recv_dhcp_packet.chaddr[2],
recv_dhcp_packet.chaddr[3], recv_dhcp_packet.chaddr[4], recv_dhcp_packet.chaddr[5]);
if (lease_index != -1)
{
/* Delete the lease, lsz 080221 */
memset(&(dhcps_lease[lease_index]), 0, sizeof(dhcps_lease[lease_index]));
for (move_index = lease_index; (move_index + 1) < DHCPS_LEASE_LIST_SIZE; move_index++)
{
memcpy(&(dhcps_lease[move_index]), &(dhcps_lease[move_index + 1]), sizeof(dhcps_lease[move_index]));
memset(&(dhcps_lease[move_index + 1]), 0, sizeof(dhcps_lease[move_index + 1]));
}
}
break;
case DHCPINFORM:
DHCPS_DEBUG("Recv INFORM from %02X:%02X:%02X:%02X:%02X:%02X.",
recv_dhcp_packet.chaddr[0], recv_dhcp_packet.chaddr[1], recv_dhcp_packet.chaddr[2],
recv_dhcp_packet.chaddr[3], recv_dhcp_packet.chaddr[4], recv_dhcp_packet.chaddr[5]);
send_inform(&recv_dhcp_packet);
break;
default:
DHCPS_WARN("Unsupported DHCP message (%02x) -- ignoring.", state[0]);
}
return;
}
LOCAL S32 dhcps_start_cb(dms_handler_t *handler, U8 *mbuf, U32 mlen, U32 sender_dms_id)
{
DHCPS_MSG *dhcps_msg = (DHCPS_MSG *)mbuf;
U32 temp_ip = 0;
IP_ADDR ipaddr;
if ((NULL == dhcps_msg) || (mlen != sizeof(DHCPS_MSG)))
{
return ERROR;
}
strcpy(dhcps_params.dev_name, dhcps_msg->dev_name);
if (0 > read_interface_info(dhcps_params.dev_name, &dhcps_params.dev, dhcps_params.mac))
{
DHCPS_DEBUG("Read interface info error");
return ERROR;
}
if (ntohl(dhcps_msg->pool_start) > ntohl(dhcps_msg->pool_end))
{
temp_ip = dhcps_msg->pool_start;
dhcps_msg->pool_start = dhcps_msg->pool_end;
dhcps_msg->pool_end = temp_ip;
}
if ((dhcps_msg->pool_start != dhcps_params.start) ||
(dhcps_msg->pool_end != dhcps_params.end))
{
dhcps_params.start= dhcps_msg->pool_start;
dhcps_params.end = dhcps_msg->pool_end;
memset(dhcps_params.lease, 0, sizeof(DHCPS_LEASE)*DHCPS_LEASE_LIST_SIZE);
}
dhcps_params.gateway = dhcps_msg->gateway;
dhcps_params.lease_time = dhcps_msg->lease_time;
dhcps_params.dns_server[0] = dhcps_msg->pri_dns;
dhcps_params.dns_server[1] = dhcps_msg->snd_dns;
dhcps_params.server = dhcps_msg->gateway;
dhcps_params.netmask = dhcps_msg->netmask;
/* 是否4G路由 */
dhcps_params.is_lte = get_lte_enabled();
memset(&dhcps_params.options, 0, sizeof(DHCP_OPTION_STATIC));
dhcps_params.options.lease[0] = DHCP_LEASE_TIME;
dhcps_params.options.lease[1] = 4;
memcpy(&(dhcps_params.options.lease[2]), &(dhcps_params.lease_time), 4);
temp_ip = dhcps_params.netmask;
dhcps_params.options.subnet[0] = DHCP_SUBNET;
dhcps_params.options.subnet[1] = 4;
memcpy(&(dhcps_params.options.subnet[2]), (char *)&temp_ip, 4);
dhcps_params.options.router[0] = DHCP_ROUTER;
dhcps_params.options.router[1] = 4;
memcpy(&(dhcps_params.options.router[2]), (char *)&dhcps_params.gateway, 4);
dhcps_params.options.dns[0] = DHCP_DNS_SERVER;
dhcps_params.options.dns[1] = 4;
memcpy(&(dhcps_params.options.dns[2]), (char *)&dhcps_params.dns_server[0], 4);
dhcps_params.options.router4g[0] = DHCP_4G_ROUTER;
dhcps_params.options.router4g[1] = DHCP_4G_ROUTER_LEN;
memcpy(&(dhcps_params.options.router4g[2]), DHCP_4G_ROUTER_STR, DHCP_4G_ROUTER_LEN);
if (-1 == dhcps_params.sock)
{
dhcps_params.sock = create_sock();
if (-1 == dhcps_params.sock)
{
DHCPS_DEBUG("create socket error");
return ERROR;
}
}
if (-1 == dhcps_params.inet_iendx)
{
dhcps_params.inet_iendx = inet_add_socket(dhcps_params.sock, (void*)dhcps_handle, NULL, NULL);
if (ERROR == dhcps_params.inet_iendx)
{
destroy_sock(dhcps_params.sock);
dhcps_params.sock = -1;
DHCPS_DEBUG("Listen socket error");
return ERROR;
}
}
if (-1 == dhcps_params.timer_index)
{
dhcps_params.timer_index = inet_add_timer((void*)dhcps_check_timer, 0, 1, EXECUTE_FOREVER);
if (ERROR == dhcps_params.timer_index)
{
inet_del_socket(dhcps_params.inet_iendx);
dhcps_params.inet_iendx = -1;
destroy_sock(dhcps_params.sock);
dhcps_params.sock = -1;
DHCPS_DEBUG("Add timer error");
return ERROR;
}
}
DHCPS_INFO("Start DHCP server");
ipaddr.ipAddr = dhcps_params.server;
DHCPS_DEBUG("Server = %d.%d.%d.%d", ipaddr.ipAddrByteFormat[0], ipaddr.ipAddrByteFormat[1],
ipaddr.ipAddrByteFormat[2], ipaddr.ipAddrByteFormat[3]);
ipaddr.ipAddr = dhcps_params.netmask;
DHCPS_DEBUG("Netmask = %d.%d.%d.%d", ipaddr.ipAddrByteFormat[0], ipaddr.ipAddrByteFormat[1],
ipaddr.ipAddrByteFormat[2], ipaddr.ipAddrByteFormat[3]);
ipaddr.ipAddr = dhcps_params.dns_server[0];
DHCPS_DEBUG("DNS1 = %d.%d.%d.%d", ipaddr.ipAddrByteFormat[0], ipaddr.ipAddrByteFormat[1],
ipaddr.ipAddrByteFormat[2], ipaddr.ipAddrByteFormat[3]);
ipaddr.ipAddr = dhcps_params.dns_server[1];
DHCPS_DEBUG("DNS2 = %d.%d.%d.%d", ipaddr.ipAddrByteFormat[0], ipaddr.ipAddrByteFormat[1],
ipaddr.ipAddrByteFormat[2], ipaddr.ipAddrByteFormat[3]);
ipaddr.ipAddr = dhcps_params.start;
DHCPS_DEBUG("Pool Start = %d.%d.%d.%d", ipaddr.ipAddrByteFormat[0], ipaddr.ipAddrByteFormat[1],
ipaddr.ipAddrByteFormat[2], ipaddr.ipAddrByteFormat[3]);
ipaddr.ipAddr = dhcps_params.end;
DHCPS_DEBUG("Pool End = %d.%d.%d.%d", ipaddr.ipAddrByteFormat[0], ipaddr.ipAddrByteFormat[1],
ipaddr.ipAddrByteFormat[2], ipaddr.ipAddrByteFormat[3]);
DHCPS_DEBUG("Lease Time = %d", dhcps_params.lease_time);
return OK;
}
LOCAL S32 dhcps_stop_cb(dms_handler_t *handler, U8 *mbuf, U32 mlen, U32 sender_dms_id)
{
if (-1 != dhcps_params.inet_iendx)
{
inet_del_socket(dhcps_params.inet_iendx);
dhcps_params.inet_iendx = -1;
}
if (-1 != dhcps_params.sock)
{
destroy_sock(dhcps_params.sock);
dhcps_params.sock = -1;
}
if (-1 != dhcps_params.timer_index)
{
inet_del_timer(dhcps_params.timer_index);
dhcps_params.timer_index = -1;
}
return OK;
}
LOCAL int dhcps_init()
{
memset(&recv_dhcp_packet, 0, sizeof(recv_dhcp_packet));
memset(&dhcps_params, 0, sizeof(DHCPS_PARAMS));
dhcps_params.inet_iendx = -1;
dhcps_params.timer_index = -1;
dhcps_params.sock = -1;
dhcps_params.decline_time = DECLINE_TIME;
dhcps_params.conflict_time = CONFLICT_TIME;
dhcps_params.offer_time = LEASE_OFFER_TIME;
dhcps_params.min_lease = LEASE_TIME_MIN;
msg_attach_handler(DHCPS_START_MSG, dhcps_start_cb);
msg_attach_handler(DHCPS_STOP_MSG, dhcps_stop_cb);
return OK;
}
LOCAL S32 dhcps_reload(DS_MSG *msg)
{
/* 4G上网模式变化 */
if (ds_path_id_exist(msg->id, msg->num, LTE_INFO_DATA_PATH))
{
dhcps_params.is_lte = get_lte_enabled();
}
return OK;
}
LOCAL void dhcps_main()
{
DS_DAT_MON_DESC dhcps_monitor[] =
{
DS_DAT_MON(LTE_INFO_DATA_PATH, DATA_ATTRI_NOTIFY),
};
DS_MOD_DESC dhcps_module =
DS_STRUCT_MOD("dhcps", dhcps_init, NULL, dhcps_reload, NULL, NULL,
NULL, dhcps_monitor);
MODULE *module_node = ds_register_module("dhcps", &dhcps_module);
NSD_ASSERT(NULL != module_node);
}
NSD_INIT(dhcps_main);
最新发布