OCT 1. 增加 DHCP ACK 功能

This commit is contained in:
黄昕 2023-04-27 17:04:43 +08:00
parent f680e4c414
commit 6ef6baaba3
8 changed files with 215 additions and 30 deletions

View File

@ -12,6 +12,10 @@ static const char *g_enumStrVal[][MAX_DESC_LENGTH] = {
}; };
const char *getErrorEnumNameString(int errCode) { const char *getErrorEnumNameString(int errCode) {
if (errCode < 0) {
errCode = -errCode;
}
if (errCode >= ARRAY_SIZE(g_enumStrVal) || errCode < 0) { if (errCode >= ARRAY_SIZE(g_enumStrVal) || errCode < 0) {
return g_enumStrVal[ARRAY_SIZE(g_enumStrVal) - 1][0]; return g_enumStrVal[ARRAY_SIZE(g_enumStrVal) - 1][0];
} }

View File

@ -14,7 +14,9 @@
#include "lease.h" #include "lease.h"
// 10小时以上清理无效的预分配IP // 10小时以上清理无效的预分配IP
#define DCHP_STEP_TIMEOUT (36000) #define DCHP_STEP_CLEANUP_TIMEOUT (36000)
// Discover 预分配IP 和Request 请求间的超时时间
#define DCHP_STEP_REQUEST_TIMEOUT (600000)
#define CREATE_LEASE_TABLE() \ #define CREATE_LEASE_TABLE() \
"CREATE TABLE IF NOT EXISTS lease " \ "CREATE TABLE IF NOT EXISTS lease " \
@ -59,6 +61,11 @@
#define GET_PRE_ASSIGN_EXISTS_ROW_FMT \ #define GET_PRE_ASSIGN_EXISTS_ROW_FMT \
"SELECT ip, id FROM pre_assign WHERE mac = '%s' AND hostname = '%s' AND uid = %d ORDER BY createTm DESC LIMIT 1;" "SELECT ip, id FROM pre_assign WHERE mac = '%s' AND hostname = '%s' AND uid = %d ORDER BY createTm DESC LIMIT 1;"
#define GET_ASSIGN_IP_INFO_FMT \
"SELECT id, ip, lease, netmask, gateway, dns1, dns2 FROM pre_assign WHERE mac = '%s' AND hostname = '%s' AND " \
"uid = %d AND server = '%s' AND (strftime('%%s', 'now', 'localtime') - strftime('%%s', createTm)) < " \
"%d ORDER BY createTm DESC LIMIT 1;"
#define IP_IS_PRE_ASSIGN_NOT_TIMEOUT_FMT \ #define IP_IS_PRE_ASSIGN_NOT_TIMEOUT_FMT \
"SELECT (strftime('%%s', 'now', 'localtime') - strftime('%%s', createTm)) as tm FROM pre_assign WHERE ip = " \ "SELECT (strftime('%%s', 'now', 'localtime') - strftime('%%s', createTm)) as tm FROM pre_assign WHERE ip = " \
"'%s' AND tm < %d AND uid = %d ORDER BY tm DESC LIMIT 1;" "'%s' AND tm < %d AND uid = %d ORDER BY tm DESC LIMIT 1;"
@ -83,7 +90,7 @@ int lease_lock_pre_assign_ip() {
char **dbResult; char **dbResult;
int nRow = 0, nColumn = 0; int nRow = 0, nColumn = 0;
snprintf(buf, 1024, GET_PRE_ASSIGN_ROW_FMT, DCHP_STEP_TIMEOUT); snprintf(buf, 1024, GET_PRE_ASSIGN_ROW_FMT, DCHP_STEP_CLEANUP_TIMEOUT);
rc = db_sqlite3_get_rows(buf, &dbResult, &nRow, &nColumn, NULL); rc = db_sqlite3_get_rows(buf, &dbResult, &nRow, &nColumn, NULL);
if (rc == ERR_SUCCESS && nRow > 0 && nColumn > 0) { if (rc == ERR_SUCCESS && nRow > 0 && nColumn > 0) {
@ -109,7 +116,7 @@ int lease_clearup_timeout_pre_assign() {
int rc; int rc;
char buf[1024] = {0}; char buf[1024] = {0};
snprintf(buf, 1024, CLS_TIMEOUT_PRE_ASSIGN_ROW_FMT, DCHP_STEP_TIMEOUT); snprintf(buf, 1024, CLS_TIMEOUT_PRE_ASSIGN_ROW_FMT, DCHP_STEP_CLEANUP_TIMEOUT);
rc = db_sqlite3_sql_exec(CREATE_LEASE_TABLE(), NULL, NULL, NULL); rc = db_sqlite3_sql_exec(CREATE_LEASE_TABLE(), NULL, NULL, NULL);
@ -138,7 +145,7 @@ int lease_ip_is_pre_assign(U32 uid, U32 ip) {
// 判断数据库中该IP是否未超时 // 判断数据库中该IP是否未超时
memset(buf, 0, 1024); memset(buf, 0, 1024);
snprintf(buf, 1024, IP_IS_PRE_ASSIGN_NOT_TIMEOUT_FMT, u32_to_str_ip(htonl(ip)), DCHP_STEP_TIMEOUT, uid); snprintf(buf, 1024, IP_IS_PRE_ASSIGN_NOT_TIMEOUT_FMT, u32_to_str_ip(htonl(ip)), DCHP_STEP_CLEANUP_TIMEOUT, uid);
rc = db_sqlite3_get_rows(buf, &dbResult, &nRow, &nColumn, NULL); rc = db_sqlite3_get_rows(buf, &dbResult, &nRow, &nColumn, NULL);
sqlite3_free_table(dbResult); sqlite3_free_table(dbResult);
@ -150,7 +157,7 @@ int lease_ip_is_pre_assign(U32 uid, U32 ip) {
// 判断是否有超时预分配的IP 存在的话可以预分配给其它请求 // 判断是否有超时预分配的IP 存在的话可以预分配给其它请求
memset(buf, 0, 1024); memset(buf, 0, 1024);
snprintf(buf, 1024, IP_IS_PRE_ASSIGN_TIMEOUT_FMT, u32_to_str_ip(htonl(ip)), DCHP_STEP_TIMEOUT, uid); snprintf(buf, 1024, IP_IS_PRE_ASSIGN_TIMEOUT_FMT, u32_to_str_ip(htonl(ip)), DCHP_STEP_CLEANUP_TIMEOUT, uid);
rc = db_sqlite3_get_rows(buf, &dbResult, &nRow, &nColumn, NULL); rc = db_sqlite3_get_rows(buf, &dbResult, &nRow, &nColumn, NULL);
if (rc == ERR_SUCCESS && nRow > 0 && nColumn > 0) { if (rc == ERR_SUCCESS && nRow > 0 && nColumn > 0) {
// 清理超时资源并预分配 // 清理超时资源并预分配
@ -169,6 +176,52 @@ int lease_ip_is_pre_assign(U32 uid, U32 ip) {
return TRUE; return TRUE;
} }
int lease_get_assign_info(PDHCP_REQ pReq, PPOOL_CTX pAssign, U64 *pCtx) {
int rc;
char buf[2048] = {0};
char macStr[20] = {0};
U32 ipAddr;
char **dbResult;
int nRow = 0, nColumn = 0;
MAC_TO_STR(pReq->cliMac, macStr);
snprintf(buf, 1024, GET_ASSIGN_IP_INFO_FMT, macStr, pReq->hostName, pReq->uid, u32_to_str_ip(pReq->serverAddr),
DCHP_STEP_REQUEST_TIMEOUT);
rc = db_sqlite3_get_rows(buf, &dbResult, &nRow, &nColumn, NULL);
if (rc == ERR_SUCCESS && nRow > 0 && nColumn > 0) {
char *pNetmask = dbResult[nColumn + 3];
char *pGateway = dbResult[nColumn + 4];
char *pDns1 = dbResult[nColumn + 5];
char *pDns2 = dbResult[nColumn + 6];
// minAddr 记录可分配的IP
pAssign->minAddr = ntohl(inet_addr(dbResult[nColumn + 1]));
pAssign->leaseTime = strtoul(dbResult[nColumn + 2], NULL, 10);
if (strlen(pNetmask) > 0) {
pAssign->netMask = ntohl(inet_addr(pNetmask));
}
if (strlen(pGateway) > 0) {
pAssign->gwAddr = ntohl(inet_addr(pGateway));
}
if (strlen(pDns1) > 0) {
pAssign->primeDNS = ntohl(inet_addr(pDns1));
}
if (strlen(pDns2) > 0) {
pAssign->salveDNS = ntohl(inet_addr(pDns2));
}
*pCtx = strtoull(dbResult[nColumn], NULL, 10);
return ERR_SUCCESS;
}
return -ERR_ITEM_UNEXISTS;
}
int lease_get_pre_assign(U32 uid, const char *mac, const char *hostname, U32 *preAssign) { int lease_get_pre_assign(U32 uid, const char *mac, const char *hostname, U32 *preAssign) {
int rc; int rc;
char buf[1024] = {0}; char buf[1024] = {0};

View File

@ -158,7 +158,6 @@ U32 dhcp_get_default_netmask() {
void *get_pkg_free_buf() { void *get_pkg_free_buf() {
int i; int i;
ssize_t ret;
struct tpacket3_hdr *hdr; struct tpacket3_hdr *hdr;
for (i = 0; i < g_pkgRing.send.tp_frame_nr; i++) { for (i = 0; i < g_pkgRing.send.tp_frame_nr; i++) {
@ -183,17 +182,7 @@ U32 pkg_mmap_tx(U8 *pData, U32 nBytes) {
return hdr->tp_len; return hdr->tp_len;
} }
static int dhcp_resp_offer(PDHCP_PACKAGE pReq, PPOOL_CTX pIpInfo, U32 ip) { static void fill_package(PDHCP_PACKAGE pRsp, PDHCP_PACKAGE pReq) {
U8 *pOpt;
U16 csum;
int tolSize;
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;
}
memset(pRsp, 0, MAX_DHCP_PKG_SIZE); memset(pRsp, 0, MAX_DHCP_PKG_SIZE);
// 二层头 // 二层头
@ -233,8 +222,6 @@ static int dhcp_resp_offer(PDHCP_PACKAGE pReq, PPOOL_CTX pIpInfo, U32 ip) {
pRsp->dhcp.hlen = pReq->dhcp.hlen; pRsp->dhcp.hlen = pReq->dhcp.hlen;
// xid // xid
pRsp->dhcp.xid = pReq->dhcp.xid; pRsp->dhcp.xid = pReq->dhcp.xid;
// 分配的 IP 地址
pRsp->dhcp.yiaddr = htonl(ip);
// 客户端 MAC 地址 // 客户端 MAC 地址
memcpy(pRsp->dhcp.chaddr, pReq->dhcp.chaddr, ETH_ALEN); memcpy(pRsp->dhcp.chaddr, pReq->dhcp.chaddr, ETH_ALEN);
// DHCP服务端主机名 // DHCP服务端主机名
@ -250,6 +237,97 @@ static int dhcp_resp_offer(PDHCP_PACKAGE pReq, PPOOL_CTX pIpInfo, U32 ip) {
pRsp->dhcp.ciaddr = 0; pRsp->dhcp.ciaddr = 0;
pRsp->dhcp.siaddr = 0; pRsp->dhcp.siaddr = 0;
pRsp->dhcp.giaddr = 0; pRsp->dhcp.giaddr = 0;
}
static int dhcp_resp_ack(PDHCP_PACKAGE pReq, PPOOL_CTX pIpInfo) {
U8 *pOpt;
U16 csum;
int tolSize;
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;
// 计算包总长度
tolSize = (int)((pOpt - pRsp->dhcp.options) + 1 + sizeof(DHCP_PACKAGE));
// 计算 IP 数据长度
pRsp->vlan_hdr.ip.tot_len = htons(tolSize - sizeof(struct ethhdr) - sizeof(struct vlan_hdr));
// 计算 UDP 数据长度
pRsp->vlan_hdr.udp.len = htons(tolSize - sizeof(struct ethhdr) - sizeof(struct vlan_hdr) - sizeof(struct iphdr));
// 计算 IP 校验和
csum = htons(ip_checksum((unsigned char *)&pRsp->vlan_hdr.ip));
pRsp->vlan_hdr.ip.check = htons(csum);
// 计算 UDP 校验和
csum = htons(udp_checksum(pRsp->vlan_hdr.ip.saddr, pRsp->vlan_hdr.ip.daddr, (unsigned char *)&pRsp->vlan_hdr.udp));
pRsp->vlan_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_offer(PDHCP_PACKAGE pReq, PPOOL_CTX pIpInfo, U32 ip) {
U8 *pOpt;
U16 csum;
int tolSize;
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 // DHCP Options
pOpt = pRsp->dhcp.options; pOpt = pRsp->dhcp.options;
@ -343,11 +421,9 @@ static void on_sock_recv(uv_work_t *req) {
reqDhcp.serverAddr = g_nicInfo.ipAddr; reqDhcp.serverAddr = g_nicInfo.ipAddr;
memcpy(reqDhcp.cliMac, pkg->dhcp.chaddr, ETH_ALEN); memcpy(reqDhcp.cliMac, pkg->dhcp.chaddr, ETH_ALEN);
// LOG_MOD(trace, ZM_DHCP_NET, "<<< User %u xid %08X addr %p with user %u\n", reqDhcp.uid, reqDhcp.xid, pWork->pUser,
// pWork->pUser->uid);
switch (*optMsg.pValue) { switch (*optMsg.pValue) {
case DHCP_MSG_DISCOVER: case DHCP_MSG_DISCOVER:
// region DHCP Discover 处理
ret = dhcp_get_option(OPT_REQUESTEDIPADDR, pkg->dhcp.options, optSize, &opt); ret = dhcp_get_option(OPT_REQUESTEDIPADDR, pkg->dhcp.options, optSize, &opt);
if (ret == ERR_SUCCESS && opt.len == sizeof(U32)) { if (ret == ERR_SUCCESS && opt.len == sizeof(U32)) {
reqDhcp.reqIpAddr = ntohl(*((U32 *)opt.pValue)); reqDhcp.reqIpAddr = ntohl(*((U32 *)opt.pValue));
@ -377,7 +453,7 @@ static void on_sock_recv(uv_work_t *req) {
ret = pre_alloc_dhcp_res(&reqDhcp, pWork->pUser, &ip, &pIpInfo); ret = pre_alloc_dhcp_res(&reqDhcp, pWork->pUser, &ip, &pIpInfo);
if (ret == ERR_SUCCESS) { if (ret == ERR_SUCCESS) {
LOG_MOD(debug, ZM_DHCP_NET, "User %5u DHCP prepare assign ipaddress: [%s(%s)] --> %s\n", reqDhcp.uid, 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))); macStr, reqDhcp.hostName, u32_to_str_ip(ntohl(ip)));
ret = dhcp_resp_offer(pkg, pIpInfo, ip); ret = dhcp_resp_offer(pkg, pIpInfo, ip);
@ -387,10 +463,55 @@ static void on_sock_recv(uv_work_t *req) {
} }
} else { } else {
LOG_MOD(error, ZM_DHCP_NET, "DHCP prepare assign ipaddress error: User %u [%s(%s)] resion %s\n", 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)); reqDhcp.uid, macStr, reqDhcp.hostName, getErrorEnumNameString(ret));
} }
// endregion
break; break;
case DHCP_MSG_REQUEST: case DHCP_MSG_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));
}
// 客户端请求的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));
}
// 客户端主机名
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)) {
const char *pReq = u32_to_str_ip_safe(htonl(reqDhcp.reqServer));
const char *pLocal = u32_to_str_ip_safe(g_nicInfo.ipAddr);
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};
U64 id = 0;
if ((ret = is_pre_assigned(&reqDhcp, &ctx, &id)) == ERR_SUCCESS) {
MAC_TO_STR(reqDhcp.cliMac, macStr);
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);
if (ret != ERR_SUCCESS) {
LOG_MOD(error, ZM_DHCP_NET, "Send Offer error: %d\n", ret);
}
} 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));
}
}
break; break;
case DHCP_MSG_RELEASE: case DHCP_MSG_RELEASE:
break; break;

View File

@ -11,6 +11,7 @@ int lease_db_add_pre_assign(PDHCP_REQ pReq, U32 ip, PPOOL_CTX pPool);
int lease_init_database(); int lease_init_database();
int lease_get_pre_assign(U32 uid, const char *mac, const char *hostname, U32 *preAssign); int lease_get_pre_assign(U32 uid, const char *mac, const char *hostname, U32 *preAssign);
int lease_ip_is_pre_assign(U32 uid, U32 ip); int lease_ip_is_pre_assign(U32 uid, U32 ip);
int lease_get_assign_info(PDHCP_REQ pReq, PPOOL_CTX pAssign, U64 *pCtx);
int lease_clearup_timeout_pre_assign(); int lease_clearup_timeout_pre_assign();
int lease_lock_pre_assign_ip(); int lease_lock_pre_assign_ip();
#ifdef __cplusplus #ifdef __cplusplus

View File

@ -31,6 +31,7 @@ typedef struct {
int dhcp_lease_init(); int dhcp_lease_init();
int pre_alloc_dhcp_res(PDHCP_REQ pReq, PDHCP_USER pUser, U32 *pOutIp, PPOOL_CTX *pOutPool); int pre_alloc_dhcp_res(PDHCP_REQ pReq, PDHCP_USER pUser, U32 *pOutIp, PPOOL_CTX *pOutPool);
int usr_lease_lock_ip(PDHCP_USER pUser, U32 ip); int usr_lease_lock_ip(PDHCP_USER pUser, U32 ip);
int is_pre_assigned(PDHCP_REQ pReq, PPOOL_CTX pCtx, U64 *dbId);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View File

@ -27,6 +27,7 @@ typedef struct {
U32 leaseTime; U32 leaseTime;
char clientId[256]; char clientId[256];
char vendorClassId[256]; char vendorClassId[256];
U32 reqServer;
U32 serverAddr; U32 serverAddr;
char hostName[256]; char hostName[256];
} DHCP_REQ, *PDHCP_REQ; } DHCP_REQ, *PDHCP_REQ;

View File

@ -39,6 +39,10 @@ int usr_lease_lock_ip(PDHCP_USER pUser, U32 ip) {
return -ERR_MALLOC_MEMORY; return -ERR_MALLOC_MEMORY;
} }
int is_pre_assigned(PDHCP_REQ pReq, PPOOL_CTX pCtx, U64 *dbId) {
return lease_get_assign_info(pReq, pCtx, dbId);
}
//int pre_alloc_dhcp_res(U32 uid, const char *pMac, U32 *pOutIp, PIPPOOL_INFO *pOutPool) { //int pre_alloc_dhcp_res(U32 uid, const char *pMac, U32 *pOutIp, PIPPOOL_INFO *pOutPool) {
int pre_alloc_dhcp_res(PDHCP_REQ pReq, PDHCP_USER pUser, U32 *pOutIp, PPOOL_CTX *pOutPool) { int pre_alloc_dhcp_res(PDHCP_REQ pReq, PDHCP_USER pUser, U32 *pOutIp, PPOOL_CTX *pOutPool) {
PPOOL_CTX pPool, pTemp; PPOOL_CTX pPool, pTemp;