924 lines
32 KiB
C
924 lines
32 KiB
C
//
|
||
// Created by xajhuang on 2023/3/16.
|
||
//
|
||
#include <stdlib.h>
|
||
#include <string.h>
|
||
#include <linux/filter.h>
|
||
#include <net/if.h>
|
||
#include <sys/socket.h>
|
||
#include <sys/mman.h>
|
||
#include <pcap/pcap.h>
|
||
#include <unistd.h>
|
||
|
||
#include "user_errno.h"
|
||
#include "task_manager.h"
|
||
#include "zlog_module.h"
|
||
|
||
#include "dhcp_options.h"
|
||
#include "config.h"
|
||
#include "misc.h"
|
||
#include "user_mgr.h"
|
||
#include "rfc2131.h"
|
||
#include "dhcp_network.h"
|
||
#include "lease.h"
|
||
|
||
#define MAXIMUM_SNAPLEN (262144)
|
||
|
||
/*
|
||
TORs (Top of Rack switch) at Facebook run DHCP relayers, these relayers are
|
||
responsible for relaying broadcast DHCP traffic (DISCOVERY and SOLICIT
|
||
messages) originating within their racks to anycast VIPs, one DHCPv4 and one
|
||
for DHCPv6.
|
||
*/
|
||
|
||
#ifdef USED_DEFAULT_BPF
|
||
static struct sock_filter g_filterCode[] = {
|
||
#ifdef UDP_DHCP_FILTER
|
||
// create by: tcpdump "udp and port 67 and port 68" -dd
|
||
{0x28, 0, 0, 0x0000000c},
|
||
{0x15, 0, 9, 0x000086dd},
|
||
{0x30, 0, 0, 0x00000014},
|
||
{0x15, 0, 21, 0x00000011},
|
||
{0x28, 0, 0, 0x00000036},
|
||
{0x15, 0, 2, 0x00000043},
|
||
{0x28, 0, 0, 0x00000038},
|
||
{0x15, 16, 17, 0x00000044},
|
||
{0x15, 0, 16, 0x00000044},
|
||
{0x28, 0, 0, 0x00000038},
|
||
{0x15, 13, 14, 0x00000043},
|
||
{0x15, 0, 13, 0x00000800},
|
||
{0x30, 0, 0, 0x00000017},
|
||
{0x15, 0, 11, 0x00000011},
|
||
{0x28, 0, 0, 0x00000014},
|
||
{0x45, 9, 0, 0x00001fff},
|
||
{0xb1, 0, 0, 0x0000000e},
|
||
{0x48, 0, 0, 0x0000000e},
|
||
{0x15, 0, 2, 0x00000043},
|
||
{0x48, 0, 0, 0x00000010},
|
||
{0x15, 3, 4, 0x00000044},
|
||
{0x15, 0, 3, 0x00000044},
|
||
{0x48, 0, 0, 0x00000010},
|
||
{0x15, 0, 1, 0x00000043},
|
||
{0x6, 0, 0, 0x00040000},
|
||
{0x6, 0, 0, 0x00000000},
|
||
#endif
|
||
#if 0
|
||
// create by: tcpdump "vxlan" -dd
|
||
{0x28, 0, 0, 0x0000000c},
|
||
{0x15, 2, 0, 0x00008100},
|
||
{0x15, 1, 0, 0x000088a8},
|
||
{0x15, 0, 1, 0x00009100},
|
||
{0x6, 0, 0, 0x00040000},
|
||
{0x6, 0, 0, 0x00000000},
|
||
#endif
|
||
// region BPF code
|
||
// create by: tcpdump "vlan and udp and port 67 and port 68" -dd
|
||
{0x0, 0, 0, 0x00000000},
|
||
{0x2, 0, 0, 0x00000000},
|
||
{0x2, 0, 0, 0x00000001},
|
||
{0x30, 0, 0, 0xfffff030},
|
||
{0x15, 7, 0, 0x00000001},
|
||
{0x0, 0, 0, 0x00000004},
|
||
{0x2, 0, 0, 0x00000000},
|
||
{0x2, 0, 0, 0x00000001},
|
||
{0x28, 0, 0, 0x0000000c},
|
||
{0x15, 2, 0, 0x00008100},
|
||
{0x15, 1, 0, 0x000088a8},
|
||
{0x15, 0, 56, 0x00009100},
|
||
{0x61, 0, 0, 0x00000001},
|
||
{0x48, 0, 0, 0x0000000c},
|
||
{0x15, 0, 13, 0x000086dd},
|
||
{0x61, 0, 0, 0x00000000},
|
||
{0x50, 0, 0, 0x00000014},
|
||
{0x15, 0, 50, 0x00000011},
|
||
{0x61, 0, 0, 0x00000000},
|
||
{0x48, 0, 0, 0x00000036},
|
||
{0x15, 0, 3, 0x00000043},
|
||
{0x61, 0, 0, 0x00000000},
|
||
{0x48, 0, 0, 0x00000038},
|
||
{0x15, 43, 44, 0x00000044},
|
||
{0x15, 0, 43, 0x00000044},
|
||
{0x61, 0, 0, 0x00000000},
|
||
{0x48, 0, 0, 0x00000038},
|
||
{0x15, 39, 40, 0x00000043},
|
||
{0x15, 0, 39, 0x00000800},
|
||
{0x61, 0, 0, 0x00000000},
|
||
{0x50, 0, 0, 0x00000017},
|
||
{0x15, 0, 36, 0x00000011},
|
||
{0x61, 0, 0, 0x00000000},
|
||
{0x48, 0, 0, 0x00000014},
|
||
{0x45, 33, 0, 0x00001fff},
|
||
{0x61, 0, 0, 0x00000000},
|
||
{0x50, 0, 0, 0x0000000e},
|
||
{0x54, 0, 0, 0x0000000f},
|
||
{0x64, 0, 0, 0x00000002},
|
||
{0xc, 0, 0, 0x00000000},
|
||
{0x7, 0, 0, 0x00000000},
|
||
{0x48, 0, 0, 0x0000000e},
|
||
{0x15, 0, 8, 0x00000043},
|
||
{0x61, 0, 0, 0x00000000},
|
||
{0x50, 0, 0, 0x0000000e},
|
||
{0x54, 0, 0, 0x0000000f},
|
||
{0x64, 0, 0, 0x00000002},
|
||
{0xc, 0, 0, 0x00000000},
|
||
{0x7, 0, 0, 0x00000000},
|
||
{0x48, 0, 0, 0x00000010},
|
||
{0x15, 16, 17, 0x00000044},
|
||
{0x61, 0, 0, 0x00000000},
|
||
{0x50, 0, 0, 0x0000000e},
|
||
{0x54, 0, 0, 0x0000000f},
|
||
{0x64, 0, 0, 0x00000002},
|
||
{0xc, 0, 0, 0x00000000},
|
||
{0x7, 0, 0, 0x00000000},
|
||
{0x48, 0, 0, 0x0000000e},
|
||
{0x15, 0, 9, 0x00000044},
|
||
{0x61, 0, 0, 0x00000000},
|
||
{0x50, 0, 0, 0x0000000e},
|
||
{0x54, 0, 0, 0x0000000f},
|
||
{0x64, 0, 0, 0x00000002},
|
||
{0xc, 0, 0, 0x00000000},
|
||
{0x7, 0, 0, 0x00000000},
|
||
{0x48, 0, 0, 0x00000010},
|
||
{0x15, 0, 1, 0x00000043},
|
||
{0x6, 0, 0, 0x00040000},
|
||
{0x6, 0, 0, 0x00000000},
|
||
// endregion
|
||
};
|
||
#endif
|
||
|
||
static struct sock_fprog bpf;
|
||
static PACKET_MMAP_RING g_pkgRing;
|
||
static NIC_INFO g_nicInfo;
|
||
static uv_udp_t g_uvRawSockReq;
|
||
static DHCP_WORK_MODE g_dhcpMode;
|
||
|
||
U32 dhcp_get_default_netmask() {
|
||
return g_nicInfo.netmask;
|
||
}
|
||
|
||
void *get_pkg_free_buf() {
|
||
int i;
|
||
struct tpacket3_hdr *hdr;
|
||
|
||
for (i = 0; i < g_pkgRing.send.tp_frame_nr; i++) {
|
||
hdr = (struct tpacket3_hdr *)(g_pkgRing.tx[0].iov_base + (g_pkgRing.send.tp_frame_size * g_pkgRing.index));
|
||
g_pkgRing.index = (g_pkgRing.index + 1) % g_pkgRing.send.tp_frame_nr;
|
||
|
||
if (!(hdr->tp_status & (TP_STATUS_SEND_REQUEST | TP_STATUS_SENDING))) {
|
||
return (U8 *)hdr + TPACKET3_HDRLEN - sizeof(struct sockaddr_ll);
|
||
}
|
||
}
|
||
|
||
return NULL;
|
||
}
|
||
|
||
U32 pkg_mmap_tx(U8 *pData, U32 nBytes) {
|
||
struct tpacket3_hdr *hdr = (struct tpacket3_hdr *)(pData + sizeof(struct sockaddr_ll) - TPACKET3_HDRLEN);
|
||
|
||
hdr->tp_next_offset = 0;
|
||
hdr->tp_len = nBytes;
|
||
hdr->tp_snaplen = nBytes;
|
||
hdr->tp_status = TP_STATUS_SEND_REQUEST;
|
||
return hdr->tp_len;
|
||
}
|
||
|
||
static void fill_package(PDHCP_PACKAGE pRsp, PDHCP_PACKAGE pReq) {
|
||
memset(pRsp, 0, MAX_DHCP_PKG_SIZE);
|
||
|
||
// 二层头
|
||
// 目的IP地址
|
||
if (pReq->hdr.ip.saddr != 0) {
|
||
memcpy(pRsp->hdr.eth.h_dest, pRsp->hdr.eth.h_source, ETH_ALEN);
|
||
} else {
|
||
memset(pRsp->hdr.eth.h_dest, 0xFF, ETH_ALEN);
|
||
}
|
||
|
||
// 源 IP 地址
|
||
memcpy(pRsp->hdr.eth.h_source, g_nicInfo.macAddr, ETH_ALEN);
|
||
// protol
|
||
pRsp->hdr.eth.h_proto = pReq->hdr.eth.h_proto;
|
||
|
||
#if VLAN_SUPPORT
|
||
// QinQ 隧道
|
||
pRsp->hdr.vlan.id = pReq->hdr.vlan.id;
|
||
pRsp->hdr.vlan.type = pReq->hdr.vlan.type;
|
||
// TODO 可能的二层QinQ隧道
|
||
#endif
|
||
// IP 头
|
||
memcpy(&pRsp->hdr.ip, &pReq->hdr.ip, sizeof(struct iphdr));
|
||
// TOS
|
||
pRsp->hdr.ip.tos = 0;
|
||
// 更新源IP
|
||
pRsp->hdr.ip.saddr = g_nicInfo.ipAddr;
|
||
// 更新目的IP地址,广播255.255.255.255
|
||
if (pReq->hdr.ip.saddr == 0) {
|
||
pRsp->hdr.ip.daddr = 0xFFFFFFFF;
|
||
} else {
|
||
pRsp->hdr.ip.daddr = pReq->hdr.ip.saddr;
|
||
}
|
||
|
||
// UDP 头
|
||
// 目的端口
|
||
pRsp->hdr.udp.dest = pReq->hdr.udp.source;
|
||
// 源端口
|
||
pRsp->hdr.udp.source = pReq->hdr.udp.dest;
|
||
|
||
//DHCP 协议
|
||
// 返回类型
|
||
pRsp->dhcp.op = BOOTP_REPLY;
|
||
// 地址类型长度
|
||
pRsp->dhcp.htype = pReq->dhcp.htype;
|
||
// 地址长度
|
||
pRsp->dhcp.hlen = pReq->dhcp.hlen;
|
||
// xid
|
||
pRsp->dhcp.xid = pReq->dhcp.xid;
|
||
// 客户端 MAC 地址
|
||
memcpy(pRsp->dhcp.chaddr, pReq->dhcp.chaddr, ETH_ALEN);
|
||
// DHCP服务端主机名
|
||
memcpy(pRsp->dhcp.sname, g_nicInfo.hostname, MIN(64, strlen(g_nicInfo.hostname)));
|
||
// Magic Cookie: DHCP
|
||
//
|
||
// memcpy(&pRsp->dhcp.cookie, DHCP_COOKIE_VAL, 4);
|
||
pRsp->dhcp.cookie = htonl(DHCP_COOKIE_VAL);
|
||
|
||
pRsp->dhcp.hops = 0;
|
||
pRsp->dhcp.secs = 0;
|
||
pRsp->dhcp.flags = 0;
|
||
pRsp->dhcp.ciaddr = 0;
|
||
pRsp->dhcp.siaddr = 0;
|
||
pRsp->dhcp.giaddr = 0;
|
||
}
|
||
|
||
static int dhcp_prepare_tx(U8 *pOpt, PDHCP_PACKAGE pRsp) {
|
||
U16 csum;
|
||
int tolSize;
|
||
// 计算包总长度
|
||
tolSize = (int)((pOpt - pRsp->dhcp.options) + 1 + sizeof(DHCP_PACKAGE));
|
||
|
||
// 计算 IP 数据长度
|
||
pRsp->hdr.ip.tot_len = htons(tolSize - sizeof(struct ethhdr) - sizeof(struct vlan_hdr));
|
||
// 计算 UDP 数据长度
|
||
pRsp->hdr.udp.len = htons(tolSize - sizeof(struct ethhdr) - sizeof(struct vlan_hdr) - sizeof(struct iphdr));
|
||
|
||
// 计算 IP 校验和
|
||
csum = htons(ip_checksum((unsigned char *)&pRsp->hdr.ip));
|
||
pRsp->hdr.ip.check = htons(csum);
|
||
|
||
// 计算 UDP 校验和
|
||
csum = htons(udp_checksum(pRsp->hdr.ip.saddr, pRsp->hdr.ip.daddr, (unsigned char *)&pRsp->hdr.udp));
|
||
pRsp->hdr.udp.check = htons(csum);
|
||
|
||
LOG_MOD(trace, ZM_DHCP_NET, "OPTIONS size: %ld\n", (intptr_t)(pOpt - pRsp->dhcp.options) + 1);
|
||
LOG_MOD(trace, ZM_DHCP_NET, "Total size: %d\n", tolSize);
|
||
|
||
// 发送数据
|
||
if (pkg_mmap_tx((U8 *)pRsp, tolSize) != tolSize) {
|
||
LOG_MOD(error, ZM_DHCP_NET, "Send package(%u bytes) error\n", tolSize);
|
||
return -ERR_SOCK_SEND;
|
||
}
|
||
|
||
return ERR_SUCCESS;
|
||
}
|
||
|
||
static int dhcp_resp_nack(PDHCP_PACKAGE pReq) {
|
||
U8 *pOpt;
|
||
PDHCP_PACKAGE pRsp = get_pkg_free_buf();
|
||
|
||
if (pRsp == NULL) {
|
||
LOG_MOD(error, ZM_DHCP_NET, "Malloc memory error: %u\n", MAX_DHCP_PKG_SIZE);
|
||
return -ERR_MALLOC_MEMORY;
|
||
}
|
||
|
||
fill_package(pRsp, pReq);
|
||
|
||
// DHCP Options
|
||
pOpt = pRsp->dhcp.options;
|
||
|
||
// DHCP 消息类型
|
||
pOpt += dhcp_add_u8_option(pOpt, OPT_MESSAGETYPE, DHCP_MSG_NAK);
|
||
*pOpt = OPT_END;
|
||
|
||
return dhcp_prepare_tx(pOpt, pRsp);
|
||
}
|
||
|
||
static int dhcp_resp_ack(PDHCP_PACKAGE pReq, PPOOL_CTX pIpInfo) {
|
||
U8 *pOpt;
|
||
PDHCP_PACKAGE pRsp = get_pkg_free_buf();
|
||
|
||
if (pRsp == NULL) {
|
||
LOG_MOD(error, ZM_DHCP_NET, "Malloc memory error: %u\n", MAX_DHCP_PKG_SIZE);
|
||
return -ERR_MALLOC_MEMORY;
|
||
}
|
||
|
||
fill_package(pRsp, pReq);
|
||
|
||
// 分配的 IP 地址
|
||
pRsp->dhcp.yiaddr = htonl(pIpInfo->minAddr);
|
||
|
||
// DHCP Options
|
||
pOpt = pRsp->dhcp.options;
|
||
|
||
// DHCP 消息类型
|
||
pOpt += dhcp_add_u8_option(pOpt, OPT_MESSAGETYPE, DHCP_MSG_ACK);
|
||
// 子网掩码
|
||
pOpt += dhcp_add_u32_option(pOpt, OPT_NETMASK, htonl(pIpInfo->netMask));
|
||
// 租约
|
||
pOpt += dhcp_add_u32_option(pOpt, OPT_IPADDRLEASE, htonl(pIpInfo->leaseTime));
|
||
// DHCP Server
|
||
pOpt += dhcp_add_u32_option(pOpt, OPT_SERVERID, g_nicInfo.ipAddr);
|
||
// DNS
|
||
if (pIpInfo->primeDNS != 0) {
|
||
if (pIpInfo->salveDNS == 0) {
|
||
pOpt += dhcp_add_u32_option(pOpt, OPT_DNS, htonl(pIpInfo->primeDNS));
|
||
} else {
|
||
U8 buf[8] = {0};
|
||
U32 *pVal = (U32 *)buf;
|
||
*pVal++ = htonl(pIpInfo->primeDNS);
|
||
*pVal = htonl(pIpInfo->salveDNS);
|
||
pOpt += dhcp_add_buf_option(pOpt, OPT_DNS, buf, 8);
|
||
}
|
||
}
|
||
// 网关
|
||
if (pIpInfo->gwAddr != 0) {
|
||
pOpt += dhcp_add_u32_option(pOpt, OPT_ROUTER, htonl(pIpInfo->gwAddr));
|
||
}
|
||
// DHCP 主机名
|
||
pOpt += dhcp_add_string_option(pOpt, OPT_DOMAINNAME, "workgroup");
|
||
*pOpt = OPT_END;
|
||
|
||
return dhcp_prepare_tx(pOpt, pRsp);
|
||
}
|
||
|
||
static int dhcp_resp_offer(PDHCP_PACKAGE pReq, PPOOL_CTX pIpInfo, U32 ip) {
|
||
U8 *pOpt;
|
||
PDHCP_PACKAGE pRsp = get_pkg_free_buf();
|
||
|
||
if (pRsp == NULL) {
|
||
LOG_MOD(error, ZM_DHCP_NET, "Malloc memory error: %u\n", MAX_DHCP_PKG_SIZE);
|
||
return -ERR_MALLOC_MEMORY;
|
||
}
|
||
|
||
fill_package(pRsp, pReq);
|
||
// 分配的 IP 地址
|
||
pRsp->dhcp.yiaddr = htonl(ip);
|
||
|
||
// DHCP Options
|
||
pOpt = pRsp->dhcp.options;
|
||
|
||
// DHCP 消息类型
|
||
pOpt += dhcp_add_u8_option(pOpt, OPT_MESSAGETYPE, DHCP_MSG_OFFER);
|
||
// 子网掩码
|
||
pOpt += dhcp_add_u32_option(pOpt, OPT_NETMASK, htonl(pIpInfo->netMask));
|
||
// 租约
|
||
pOpt += dhcp_add_u32_option(pOpt, OPT_IPADDRLEASE, htonl(pIpInfo->leaseTime));
|
||
// DHCP Server
|
||
pOpt += dhcp_add_u32_option(pOpt, OPT_SERVERID, g_nicInfo.ipAddr);
|
||
// DNS
|
||
if (pIpInfo->primeDNS != 0) {
|
||
if (pIpInfo->salveDNS == 0) {
|
||
pOpt += dhcp_add_u32_option(pOpt, OPT_DNS, htonl(pIpInfo->primeDNS));
|
||
} else {
|
||
U8 buf[8] = {0};
|
||
U32 *pVal = (U32 *)buf;
|
||
*pVal++ = htonl(pIpInfo->primeDNS);
|
||
*pVal = htonl(pIpInfo->salveDNS);
|
||
pOpt += dhcp_add_buf_option(pOpt, OPT_DNS, buf, 8);
|
||
}
|
||
}
|
||
// 网关
|
||
if (pIpInfo->gwAddr != 0) {
|
||
pOpt += dhcp_add_u32_option(pOpt, OPT_ROUTER, htonl(pIpInfo->gwAddr));
|
||
}
|
||
// DHCP 主机名
|
||
pOpt += dhcp_add_string_option(pOpt, OPT_DOMAINNAME, "workgroup");
|
||
*pOpt = OPT_END;
|
||
|
||
return dhcp_prepare_tx(pOpt, pRsp);
|
||
}
|
||
|
||
static void on_sock_recv(uv_work_t *req) {
|
||
char macStr[20] = {0};
|
||
U32 ip;
|
||
PPOOL_CTX pIpInfo;
|
||
DHCP_REQ reqDhcp;
|
||
DHCP_OPT optMsg, opt;
|
||
int ret;
|
||
PPKG_PROCESS_INFO pWork = (PPKG_PROCESS_INFO)req->data;
|
||
PDHCP_PACKAGE pkg = (PDHCP_PACKAGE)pWork->pPkgBase;
|
||
U32 optSize = pWork->nSize - sizeof(DHCP_PACKAGE);
|
||
|
||
//sprintf(macStr, "%02X:%02X:%02X:%02X:%02X:%02X", macStr[0], macStr[1], macStr[2], macStr[3], macStr[4], macStr[5]);
|
||
|
||
// Check op flag
|
||
if (pkg->dhcp.op != BOOTP_REQUEST) {
|
||
LOG_MOD(error, ZM_DHCP_NET, "Error message op code %d\n", pkg->dhcp.op);
|
||
return;
|
||
}
|
||
|
||
// 获取消息类型
|
||
ret = dhcp_get_option(OPT_MESSAGETYPE, pkg->dhcp.options, optSize, &optMsg);
|
||
if (ret != ERR_SUCCESS) {
|
||
LOG_MOD(error, ZM_DHCP_NET, "Get \'message type\' option error %d\n", ret);
|
||
return;
|
||
}
|
||
|
||
memset(&reqDhcp, 0, sizeof(DHCP_REQ));
|
||
reqDhcp.unicast = pkg->dhcp.flags != 0 ? TRUE : FALSE;
|
||
reqDhcp.xid = DHCP_XID(pkg->dhcp.xid);
|
||
#if VLAN_SUPPORT
|
||
reqDhcp.uid = VLAN_VNI_ID(pkg->hdr.vlan.id);
|
||
#else
|
||
reqDhcp.uid = 0;
|
||
#endif
|
||
reqDhcp.serverAddr = g_nicInfo.ipAddr;
|
||
reqDhcp.cliAddr = ntohl(pkg->dhcp.ciaddr);
|
||
memcpy(reqDhcp.cliMac, pkg->dhcp.chaddr, ETH_ALEN);
|
||
MAC_TO_STR(reqDhcp.cliMac, macStr);
|
||
|
||
switch (*optMsg.pValue) {
|
||
case DHCP_MSG_DISCOVER:
|
||
// region DHCP Discover 处理
|
||
ret = dhcp_get_option(OPT_REQUESTEDIPADDR, pkg->dhcp.options, optSize, &opt);
|
||
if (ret == ERR_SUCCESS && opt.len == sizeof(U32)) {
|
||
reqDhcp.reqIpAddr = ntohl(*((U32 *)opt.pValue));
|
||
}
|
||
|
||
ret = dhcp_get_option(OPT_IPADDRLEASE, pkg->dhcp.options, optSize, &opt);
|
||
if (ret == ERR_SUCCESS && opt.len == sizeof(U32)) {
|
||
reqDhcp.leaseTime = ntohl(*((U32 *)opt.pValue));
|
||
}
|
||
|
||
ret = dhcp_get_option(OPT_CLIENTID, pkg->dhcp.options, optSize, &opt);
|
||
if (ret == ERR_SUCCESS) {
|
||
strncpy(reqDhcp.clientId, (char *)opt.pValue, MIN((int)opt.len, 256));
|
||
}
|
||
|
||
ret = dhcp_get_option(OPT_VENDORCLASSID, pkg->dhcp.options, optSize, &opt);
|
||
if (ret == ERR_SUCCESS) {
|
||
strncpy(reqDhcp.vendorClassId, (char *)opt.pValue, MIN((int)opt.len, 256));
|
||
}
|
||
|
||
ret = dhcp_get_option(OPT_HOSTNAME, pkg->dhcp.options, optSize, &opt);
|
||
if (ret == ERR_SUCCESS) {
|
||
strncpy(reqDhcp.hostName, (char *)opt.pValue, MIN((int)opt.len, 256));
|
||
}
|
||
|
||
ret = pre_alloc_dhcp_res(&reqDhcp, pWork->pUser, &ip, &pIpInfo);
|
||
|
||
if (ret == ERR_SUCCESS) {
|
||
LOG_MOD(debug, ZM_DHCP_NET, "User %u DHCP prepare assign ipaddress: [%s(%s)] --> %s\n", reqDhcp.uid,
|
||
macStr, reqDhcp.hostName, u32_to_str_ip(ntohl(ip)));
|
||
|
||
ret = dhcp_resp_offer(pkg, pIpInfo, ip);
|
||
if (ret != ERR_SUCCESS) {
|
||
LOG_MOD(error, ZM_DHCP_NET, "Send Offer error: %d\n", ret);
|
||
}
|
||
} else {
|
||
LOG_MOD(error, ZM_DHCP_NET, "DHCP prepare assign ipaddress error: User %u [%s(%s)] resion %s\n",
|
||
reqDhcp.uid, macStr, reqDhcp.hostName, getErrorEnumNameString(ret));
|
||
|
||
// Send NACK
|
||
ret = dhcp_resp_nack(pkg);
|
||
}
|
||
|
||
if (ret != ERR_SUCCESS) {
|
||
LOG_MOD(error, ZM_DHCP_NET, "Send Offer error: %d\n", ret);
|
||
}
|
||
// endregion
|
||
break;
|
||
case DHCP_MSG_REQUEST:
|
||
// region DHCP Request 处理
|
||
// 客户端请求的服务器
|
||
ret = dhcp_get_option(OPT_SERVERID, pkg->dhcp.options, optSize, &opt);
|
||
if (ret == ERR_SUCCESS && opt.len == sizeof(U32)) {
|
||
reqDhcp.reqServer = ntohl(*((U32 *)opt.pValue));
|
||
} else {
|
||
// Request 服务器IP可以取目的 IP 地址
|
||
if (pkg->hdr.ip.saddr != 0) {
|
||
reqDhcp.reqServer = ntohl(pkg->hdr.ip.daddr);
|
||
}
|
||
}
|
||
|
||
// 客户端请求的IP
|
||
ret = dhcp_get_option(OPT_REQUESTEDIPADDR, pkg->dhcp.options, optSize, &opt);
|
||
if (ret == ERR_SUCCESS && opt.len == sizeof(U32)) {
|
||
reqDhcp.reqIpAddr = ntohl(*((U32 *)opt.pValue));
|
||
} else {
|
||
reqDhcp.reqIpAddr = reqDhcp.cliAddr;
|
||
}
|
||
|
||
// 客户端主机名
|
||
ret = dhcp_get_option(OPT_HOSTNAME, pkg->dhcp.options, optSize, &opt);
|
||
if (ret == ERR_SUCCESS) {
|
||
strncpy(reqDhcp.hostName, (char *)opt.pValue, MIN((int)opt.len, 256));
|
||
}
|
||
|
||
// 当改请求的服务端不是本机时,忽略该消息
|
||
if (reqDhcp.reqServer != ntohl(g_nicInfo.ipAddr) && reqDhcp.reqServer != 0) {
|
||
const char *pReq = u32_to_str_ip_safe(htonl(reqDhcp.reqServer));
|
||
const char *pLocal = u32_to_str_ip_safe(g_nicInfo.ipAddr);
|
||
LOG_MOD_HEX(error, ZM_DHCP_NET, pWork->pPkgBase, pWork->nSize);
|
||
LOG_MOD(debug, ZM_DHCP_NET, "Receive others server's DHCP request: request need %s, localhost %s\n",
|
||
pReq, pLocal);
|
||
free((void *)pReq);
|
||
free((void *)pLocal);
|
||
} else {
|
||
POOL_CTX ctx = {0};
|
||
if ((ret = is_pre_assigned(&reqDhcp, &ctx)) == ERR_SUCCESS) {
|
||
LOG_MOD(debug, ZM_DHCP_NET, "User %u DHCP assign ipaddress: [%s(%s)] --> %s\n", reqDhcp.uid, macStr,
|
||
reqDhcp.hostName, u32_to_str_ip(ntohl(ctx.minAddr)));
|
||
|
||
ret = dhcp_resp_ack(pkg, &ctx);
|
||
} else {
|
||
LOG_MOD(error, ZM_DHCP_NET, "DHCP assign ipaddress error: User %u [%s(%s)] resion %s\n",
|
||
reqDhcp.uid, macStr, reqDhcp.hostName, getErrorEnumNameString(ret));
|
||
// Send NACK
|
||
ret = dhcp_resp_nack(pkg);
|
||
}
|
||
|
||
if (ret != ERR_SUCCESS) {
|
||
LOG_MOD(error, ZM_DHCP_NET, "Send Ack error: %d\n", ret);
|
||
}
|
||
}
|
||
// endregion
|
||
break;
|
||
case DHCP_MSG_RELEASE:
|
||
// region DHCP Release 处理
|
||
// 客户端请求的服务器
|
||
ret = dhcp_get_option(OPT_SERVERID, pkg->dhcp.options, optSize, &opt);
|
||
if (ret == ERR_SUCCESS && opt.len == sizeof(U32)) {
|
||
reqDhcp.reqServer = ntohl(*((U32 *)opt.pValue));
|
||
} else {
|
||
// Request 服务器IP可以取目的 IP 地址
|
||
if (pkg->hdr.ip.saddr != 0) {
|
||
reqDhcp.reqServer = ntohl(pkg->hdr.ip.saddr);
|
||
}
|
||
}
|
||
|
||
reqDhcp.reqIpAddr = ntohl(pkg->dhcp.ciaddr);
|
||
lease_release(&reqDhcp);
|
||
|
||
LOG_MOD(debug, ZM_DHCP_NET, "User %u DHCP release lease: [%s(%s)] --> %s\n", reqDhcp.uid, macStr,
|
||
reqDhcp.hostName, u32_to_str_ip(ntohl(reqDhcp.reqIpAddr)));
|
||
// endregion
|
||
break;
|
||
case DHCP_MSG_INFORM:
|
||
// 客户端主机名
|
||
ret = dhcp_get_option(OPT_HOSTNAME, pkg->dhcp.options, optSize, &opt);
|
||
if (ret == ERR_SUCCESS) {
|
||
strncpy(reqDhcp.hostName, (char *)opt.pValue, MIN((int)opt.len, 256));
|
||
}
|
||
|
||
// 当前分配的租约添加到本地数据库中, 后续分配能够发现对应的主机信息
|
||
ret = lease_add_host(&reqDhcp);
|
||
|
||
if (ret == ERR_SUCCESS) {
|
||
LOG_MOD(debug, ZM_DHCP_NET, "User %u DHCP prepare assign ipaddress: [%s(%s)] --> %s\n", reqDhcp.uid,
|
||
macStr, reqDhcp.hostName, u32_to_str_ip(ntohl(reqDhcp.cliAddr)));
|
||
// 可以向客户端回复租约信息
|
||
} else {
|
||
LOG_MOD(error, ZM_DHCP_NET, "DHCP prepare assign ipaddress error: User %u [%s(%s)] resion %s\n",
|
||
reqDhcp.uid, macStr, reqDhcp.hostName, getErrorEnumNameString(ret));
|
||
}
|
||
break;
|
||
case DHCP_MSG_DECLINE:
|
||
// 清理掉上次分配的租约
|
||
break;
|
||
default:
|
||
LOG_MOD(error, ZM_DHCP_NET, "Unkonwn DHCP message type: %d\n", *optMsg.pValue);
|
||
LOG_MSG_HEX(trace, pkg, pWork->nSize);
|
||
break;
|
||
}
|
||
|
||
//dhcp_option_prase(optMsg, pkg->dhcp.options, pWork->nSize - sizeof(DHCP_PACKAGE));
|
||
|
||
LOG_MSG_HEX(trace, pkg, pWork->nSize);
|
||
//LOG_MSG(info, "vni: %d, xid: 0x%08X\n", VLAN_VNI_ID(pkg->hdr.vlan.id), DHCP_XID(pkg->dhcp.xid));
|
||
|
||
#if 0
|
||
LOG_MOD(info, ZM_DHCP_NET, "vlan = %u\n", VXLAN_VIN_ID_PACK(pkg->hdr.vlan.id));
|
||
LOG_MSG(info, "xid: 0x%08X\n", ntohl(pkg->dhcp.xid));
|
||
LOG_MSG(info,
|
||
"dest mac: %02X:%02X:%02X:%02X:%02X:%02X\n",
|
||
pkg->hdr.eth.h_dest[0],
|
||
pkg->hdr.eth.h_dest[1],
|
||
pkg->hdr.eth.h_dest[2],
|
||
pkg->hdr.eth.h_dest[3],
|
||
pkg->hdr.eth.h_dest[4],
|
||
pkg->hdr.eth.h_dest[5]);
|
||
LOG_MSG(info,
|
||
"client mac: %02X:%02X:%02X:%02X:%02X:%02X\n",
|
||
pkg->dhcp.chaddr[0],
|
||
pkg->dhcp.chaddr[1],
|
||
pkg->dhcp.chaddr[2],
|
||
pkg->dhcp.chaddr[3],
|
||
pkg->dhcp.chaddr[4],
|
||
pkg->dhcp.chaddr[5]);
|
||
#endif
|
||
}
|
||
|
||
static void after_msg_recv(uv_work_t *req, int status) {
|
||
PPKG_PROCESS_INFO pInfo = (PPKG_PROCESS_INFO)req->data;
|
||
PPKG_MSG pMsg = (PPKG_MSG)pInfo->pData;
|
||
|
||
pMsg->nf -= 1;
|
||
if (pMsg->nf == 0) {
|
||
LOG_MOD(trace, ZM_DHCP_NET, "---Free resources: %p\n", pMsg);
|
||
free(pMsg->pPkgInfo);
|
||
free(pMsg);
|
||
}
|
||
}
|
||
|
||
void raw_sock_recv_cb(uv_poll_t *handle, int status, int events) {
|
||
static unsigned int block_num = 0;
|
||
PRECV_CB_DATA pCbData = handle->data;
|
||
|
||
if (status >= 0 && (events & UV_READABLE)) {
|
||
struct block_desc *pbd = (struct block_desc *)g_pkgRing.rx[block_num].iov_base;
|
||
|
||
if ((pbd->h1.block_status & TP_STATUS_USER) && (pbd->h1.num_pkts > 0)) {
|
||
int i;
|
||
struct tpacket3_hdr *ppd;
|
||
unsigned int memSize = sizeof(PKG_PROCESS_INFO) * pbd->h1.num_pkts;
|
||
PPKG_MSG pMsg = (PPKG_MSG)malloc(sizeof(PKG_MSG));
|
||
|
||
if (pMsg == NULL) {
|
||
LOG_MOD(error, ZM_DHCP_NET, "Malloc memory error: %lu\n", sizeof(PKG_MSG));
|
||
return;
|
||
}
|
||
|
||
memset(pMsg, 0, sizeof(PKG_MSG));
|
||
pMsg->pPkgInfo = (PPKG_PROCESS_INFO)malloc(memSize);
|
||
|
||
if (pMsg->pPkgInfo == NULL) {
|
||
LOG_MOD(error, ZM_DHCP_NET, "Malloc memory error: %u\n", memSize);
|
||
free(pMsg);
|
||
return;
|
||
}
|
||
|
||
memset(pMsg->pPkgInfo, 0, memSize);
|
||
|
||
pMsg->nf = pbd->h1.num_pkts;
|
||
ppd = (struct tpacket3_hdr *)((uint8_t *)pbd + pbd->h1.offset_to_first_pkt);
|
||
for (i = 0; i < pbd->h1.num_pkts; i++) {
|
||
PDHCP_PACKAGE pkg;
|
||
U32 uid;
|
||
pMsg->pPkgInfo[i].pPkgBase = ((uint8_t *)ppd + ppd->tp_mac);
|
||
pMsg->pPkgInfo[i].nSize = ppd->tp_snaplen;
|
||
pMsg->pPkgInfo[i].uvWork.data = &pMsg->pPkgInfo[i];
|
||
pMsg->pPkgInfo[i].pData = pMsg;
|
||
if (g_dhcpMode == MODE_DHCP_SERVER) {
|
||
#if VLAN_SUPPORT
|
||
pkg = (PDHCP_PACKAGE)pMsg->pPkgInfo[i].pPkgBase;
|
||
uid = VLAN_VNI_ID(pkg->hdr.vlan.id);
|
||
#else
|
||
uid = 0;
|
||
#endif
|
||
pMsg->pPkgInfo[i].pUser = dhcp_user_create(uid);
|
||
|
||
// LOG_MOD(trace, ZM_DHCP_NET, ">>> User %u xid %08X addr %p\n", uid, DHCP_XID(pkg->dhcp.xid),
|
||
// pMsg->pPkgInfo[i].pUser);
|
||
}
|
||
if (pCbData) {
|
||
uv_queue_work(get_task_manager(), &(pMsg->pPkgInfo[i].uvWork),
|
||
pCbData->work_cb ? pCbData->work_cb : on_sock_recv,
|
||
pCbData->after_work_cb ? pCbData->after_work_cb : after_msg_recv);
|
||
} else {
|
||
uv_queue_work(get_task_manager(), &(pMsg->pPkgInfo[i].uvWork), on_sock_recv, after_msg_recv);
|
||
}
|
||
|
||
ppd = (struct tpacket3_hdr *)((uint8_t *)ppd + ppd->tp_next_offset);
|
||
}
|
||
}
|
||
|
||
pbd->h1.block_status = TP_STATUS_KERNEL;
|
||
block_num = (block_num + 1) % PKG_MMAP_BLOCKNUM;
|
||
}
|
||
}
|
||
|
||
int create_udp_raw_socket(const char *pNicName) {
|
||
struct sockaddr_ll addr;
|
||
unsigned int size;
|
||
int i;
|
||
int err;
|
||
int v = TPACKET_V3;
|
||
|
||
// 1. create socket
|
||
int sock_fd = socket(PF_PACKET, SOCK_RAW, 0);
|
||
if (sock_fd < 0) {
|
||
LOG_MOD(error, ZM_DHCP_NET, "Socket created failure: %s --> %s\n", pNicName, strerror(errno));
|
||
return -ERR_SOCK_CREATE;
|
||
}
|
||
|
||
// 2. attach filter (no need to call bind)
|
||
if ((err = setsockopt(sock_fd, SOL_SOCKET, SO_ATTACH_FILTER, &bpf, sizeof(bpf))) < 0) {
|
||
LOG_MOD(error, ZM_DHCP_NET, "Attaching filter failed: %d\n", err);
|
||
return -ERR_SOCK_SETOPT;
|
||
}
|
||
|
||
// 3. set PACKET_MMAP version
|
||
if ((err = setsockopt(sock_fd, SOL_PACKET, PACKET_VERSION, &v, sizeof(v))) < 0) {
|
||
LOG_MOD(error, ZM_DHCP_NET, "Set PACKET_VERSION option failed: %d\n", err);
|
||
return -ERR_SOCK_SETOPT;
|
||
}
|
||
|
||
// 4. setup PAKCET_MMAP rx ring
|
||
memset(&g_pkgRing.recv, 0, sizeof(g_pkgRing.recv));
|
||
g_pkgRing.recv.tp_block_size = PKG_MMAP_BLOCKSIZ;
|
||
g_pkgRing.recv.tp_frame_size = PKG_MMAP_FRAMESIZ;
|
||
g_pkgRing.recv.tp_block_nr = PKG_MMAP_BLOCKNUM;
|
||
g_pkgRing.recv.tp_frame_nr = (PKG_MMAP_BLOCKSIZ * PKG_MMAP_BLOCKNUM) / PKG_MMAP_FRAMESIZ;
|
||
g_pkgRing.recv.tp_retire_blk_tov = 60;
|
||
g_pkgRing.recv.tp_feature_req_word = TP_FT_REQ_FILL_RXHASH;
|
||
|
||
if ((err = setsockopt(sock_fd, SOL_PACKET, PACKET_RX_RING, &g_pkgRing.recv, sizeof(g_pkgRing.recv))) < 0) {
|
||
LOG_MOD(error, ZM_DHCP_NET, "Set PACKET_RX_RING option failed: %d\n", err);
|
||
return -ERR_SOCK_SETOPT;
|
||
}
|
||
|
||
// 5. setup PACKET_MMAP tx ring
|
||
memset(&g_pkgRing.send, 0, sizeof(g_pkgRing.send));
|
||
g_pkgRing.send.tp_block_size = PKG_MMAP_BLOCKSIZ;
|
||
g_pkgRing.send.tp_frame_size = PKG_MMAP_FRAMESIZ;
|
||
g_pkgRing.send.tp_block_nr = PKG_MMAP_BLOCKNUM;
|
||
g_pkgRing.send.tp_frame_nr = (PKG_MMAP_BLOCKSIZ * PKG_MMAP_BLOCKNUM) / PKG_MMAP_FRAMESIZ;
|
||
|
||
if ((err = setsockopt(sock_fd, SOL_PACKET, PACKET_TX_RING, &g_pkgRing.send, sizeof(g_pkgRing.recv))) < 0) {
|
||
LOG_MOD(error, ZM_DHCP_NET, "Set PACKET_TX_RING option failed: %d\n", err);
|
||
return -ERR_SOCK_SETOPT;
|
||
}
|
||
|
||
// 6. mmap RX/TX ring
|
||
size = g_pkgRing.recv.tp_block_size * g_pkgRing.recv.tp_block_nr +
|
||
g_pkgRing.send.tp_block_size * g_pkgRing.send.tp_block_nr;
|
||
|
||
g_pkgRing.map_recv = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_LOCKED | MAP_POPULATE, sock_fd, 0);
|
||
g_pkgRing.map_send = g_pkgRing.map_recv + g_pkgRing.recv.tp_block_size * g_pkgRing.recv.tp_block_nr;
|
||
|
||
if (g_pkgRing.map_recv == MAP_FAILED) {
|
||
LOG_MOD(error, ZM_DHCP_NET, "MMAP socket ring failed\n");
|
||
perror("title");
|
||
return -ERR_MMAP_MEMORY;
|
||
}
|
||
|
||
LOG_MOD(trace, ZM_DHCP_NET, "size = %u\n", size);
|
||
LOG_MOD(trace, ZM_DHCP_NET, "MMAP address recv = %p, send = %p\n", g_pkgRing.map_recv, g_pkgRing.map_send);
|
||
|
||
// 7. malloc read buffer
|
||
g_pkgRing.rx = malloc(g_pkgRing.recv.tp_block_nr * sizeof(struct iovec));
|
||
if (g_pkgRing.rx == NULL) {
|
||
LOG_MOD(error, ZM_DHCP_NET, "Malloc memory failed: %lu\n", g_pkgRing.recv.tp_block_nr * sizeof(struct iovec));
|
||
return -ERR_MMAP_MEMORY;
|
||
}
|
||
|
||
memset(g_pkgRing.rx, 0, g_pkgRing.recv.tp_block_nr * sizeof(struct iovec));
|
||
for (i = 0; i < g_pkgRing.recv.tp_block_nr; ++i) {
|
||
g_pkgRing.rx[i].iov_base = g_pkgRing.map_recv + (i * g_pkgRing.recv.tp_block_size);
|
||
g_pkgRing.rx[i].iov_len = g_pkgRing.recv.tp_block_size;
|
||
}
|
||
|
||
// 8. malloc send buffer
|
||
g_pkgRing.tx = malloc(g_pkgRing.send.tp_block_nr * sizeof(struct iovec));
|
||
if (g_pkgRing.tx == NULL) {
|
||
LOG_MOD(error, ZM_DHCP_NET, "Malloc memory failed: %lu\n", g_pkgRing.send.tp_block_nr * sizeof(struct iovec));
|
||
|
||
munmap(g_pkgRing.map_recv, size * 2);
|
||
return -ERR_MMAP_MEMORY;
|
||
}
|
||
|
||
memset(g_pkgRing.tx, 0, g_pkgRing.send.tp_block_nr * sizeof(struct iovec));
|
||
for (i = 0; i < g_pkgRing.send.tp_block_nr; ++i) {
|
||
g_pkgRing.tx[i].iov_base = g_pkgRing.map_send + (i * g_pkgRing.send.tp_block_size);
|
||
g_pkgRing.tx[i].iov_len = g_pkgRing.send.tp_block_size;
|
||
}
|
||
|
||
// 9. bind socket
|
||
memset(&addr, 0, sizeof(struct sockaddr_ll));
|
||
addr.sll_ifindex = (int)if_nametoindex(pNicName);
|
||
addr.sll_family = PF_PACKET;
|
||
addr.sll_protocol = htons(ETH_P_ALL);
|
||
addr.sll_hatype = 0;
|
||
addr.sll_pkttype = 0;
|
||
addr.sll_halen = 0;
|
||
|
||
if ((err = bind(sock_fd, (struct sockaddr *)&addr, sizeof(struct sockaddr_ll))) < 0) {
|
||
LOG_MOD(error, ZM_DHCP_NET, "Bind raw socket failed: %d\n", err);
|
||
return -ERR_SOCK_SETOPT;
|
||
}
|
||
|
||
g_pkgRing.sock = sock_fd;
|
||
|
||
return ERR_SUCCESS;
|
||
}
|
||
|
||
void socket_send_task(uv_timer_t *UNUSED(pArg)) {
|
||
int i;
|
||
struct tpacket3_hdr *hdr;
|
||
|
||
for (i = 0; i < g_pkgRing.send.tp_frame_nr && g_pkgRing.sock != 0; i++) {
|
||
hdr = (struct tpacket3_hdr *)(g_pkgRing.tx[0].iov_base + (g_pkgRing.send.tp_frame_size * i));
|
||
if ((hdr->tp_status & TP_STATUS_SEND_REQUEST) || (hdr->tp_status & TP_STATUS_SENDING)) {
|
||
ssize_t ret = sendto(g_pkgRing.sock, NULL, 0, MSG_DONTWAIT, NULL, sizeof(struct sockaddr_ll));
|
||
|
||
if (ret == -1) {
|
||
LOG_MOD(error, ZM_DHCP_NET, "Send packet error\n");
|
||
}
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
void init_filter(const char *pNetFilter) {
|
||
#ifdef USED_DEFAULT_BPF
|
||
bpf.len = sizeof(g_filterCode) / (sizeof(struct sock_filter));
|
||
bpf.filter = g_filterCode;
|
||
#else
|
||
static pcap_t *pd;
|
||
pd = pcap_open_dead(DLT_EN10MB, MAXIMUM_SNAPLEN);
|
||
struct bpf_program fcode;
|
||
|
||
pcap_compile(pd, &fcode, pNetFilter, 1, 0);
|
||
|
||
struct bpf_insn *insn = fcode.bf_insns;
|
||
struct sock_filter *g_filters = (struct sock_filter *)malloc(fcode.bf_len * sizeof(struct sock_filter));
|
||
for (int i = 0; i < fcode.bf_len; ++insn, ++i) {
|
||
g_filters[i].code = insn->code;
|
||
g_filters[i].jt = insn->jt;
|
||
g_filters[i].jf = insn->jf;
|
||
g_filters[i].k = insn->k;
|
||
}
|
||
|
||
bpf.len = fcode.bf_len;
|
||
bpf.filter = g_filters;
|
||
|
||
pcap_close(pd);
|
||
pcap_freecode(&fcode);
|
||
#endif
|
||
}
|
||
|
||
void init_raw_socket_poll(void *pRecv, void *pClean) {
|
||
static RECV_CB_DATA rcData;
|
||
static uv_poll_t uvSocket;
|
||
static uv_timer_t uvTm;
|
||
|
||
uv_udp_init(get_task_manager(), &g_uvRawSockReq);
|
||
uv_udp_open(&g_uvRawSockReq, g_pkgRing.sock);
|
||
|
||
uv_poll_init_socket(get_task_manager(), &uvSocket, g_pkgRing.sock);
|
||
rcData.work_cb = pRecv;
|
||
rcData.after_work_cb = pClean;
|
||
uvSocket.data = &rcData;
|
||
|
||
uv_poll_start(&uvSocket, UV_READABLE, raw_sock_recv_cb);
|
||
|
||
uv_timer_init(get_task_manager(), &uvTm);
|
||
uv_timer_start(&uvTm, socket_send_task, 3000, 100);
|
||
}
|
||
|
||
int dhcpd_init(DHCP_WORK_MODE workMode) {
|
||
int ret;
|
||
size_t size = MAX_PATH;
|
||
|
||
g_dhcpMode = workMode;
|
||
|
||
memset(&g_nicInfo, 0, sizeof(NIC_INFO));
|
||
g_nicInfo.pIfName = (char *)config_get_dhcp_nic_name();
|
||
uv_os_gethostname(g_nicInfo.hostname, &size);
|
||
|
||
get_nic_info(g_nicInfo.pIfName, &g_nicInfo.ipAddr, &g_nicInfo.netmask, NULL, g_nicInfo.macAddr);
|
||
|
||
init_filter(config_get_dhcp_net_filter());
|
||
|
||
ret = create_udp_raw_socket(g_nicInfo.pIfName);
|
||
if (ret != ERR_SUCCESS) {
|
||
LOG_MOD(error, ZM_DHCP_NET, "Create receive RAW Socket Error: %s(%d)\n", getErrorEnumNameString(-ret), ret);
|
||
return ret;
|
||
}
|
||
// 加载所有DHCP配置
|
||
ip_pool_init_from_config();
|
||
dhcp_user_mgr_init();
|
||
dhcp_option_cfg_init();
|
||
dhcp_lease_init();
|
||
|
||
init_raw_socket_poll(NULL, NULL);
|
||
|
||
return ERR_SUCCESS;
|
||
}
|
||
|
||
int dhcp_uninit() {
|
||
unsigned int size = g_pkgRing.recv.tp_block_size * g_pkgRing.recv.tp_block_nr +
|
||
g_pkgRing.send.tp_block_size * g_pkgRing.send.tp_block_nr;
|
||
close(g_pkgRing.sock);
|
||
g_pkgRing.sock = -1;
|
||
if (g_pkgRing.tx) {
|
||
free(g_pkgRing.tx);
|
||
}
|
||
|
||
if (g_pkgRing.rx) {
|
||
free(g_pkgRing.rx);
|
||
}
|
||
|
||
munmap(g_pkgRing.map_recv, size);
|
||
|
||
return ERR_SUCCESS;
|
||
} |