OCT 1. DHCP 服务支持 ACK, RELEASE, INFO 消息处理

2. DHCP 测试工具支持接收 ACK数据
This commit is contained in:
黄昕 2023-04-28 15:19:00 +08:00
parent 6ef6baaba3
commit 85b6b108df
9 changed files with 463 additions and 117 deletions

View File

@ -78,6 +78,7 @@ int dhcp_tools_init_network(const char *pNicName);
U8 *dhcp_create_discover_req(PDHCP_INFO pInfo, int *pOutSize);
U8 *dhcp_create_request_req(PDHCP_INFO pInfo, int *pOutSize);
int cacheDhcpOfferBuffer(PDHCP_INFO pInfo, U8 *pBuf, int size);
int cacheDhcpAckBuffer(PDHCP_INFO pInfo, U8 *pBuf, int size);
void details_wnd_create(GtkBuilder *builder);
void details_wnd_show(PDHCP_INFO pInfo);
#endif //VCPE_MAIN_H

View File

@ -316,6 +316,17 @@ int cacheDhcpOfferBuffer(PDHCP_INFO pInfo, U8 *pBuf, int size) {
return -ERR_MALLOC_MEMORY;
}
int cacheDhcpAckBuffer(PDHCP_INFO pInfo, U8 *pBuf, int size) {
pInfo->pAckBuf.p = (U8 *)malloc(size);
if (pInfo->pAckBuf.p) {
memcpy(pInfo->pAckBuf.p, pBuf, size);
pInfo->pAckBuf.buf_size = size;
return ERR_SUCCESS;
}
return -ERR_MALLOC_MEMORY;
}
_Noreturn static void *dhcpThreadCb(void *pData) {
U8 *pkg;
int size = 0;

View File

@ -2,7 +2,6 @@
// Created by xajhuang on 2023/4/20.
//
#include <uv.h>
#include <linux/filter.h>
#include <string.h>
#include "user_errno.h"
#include "dhcp_network.h"
@ -233,6 +232,11 @@ static void on_dhcp_recv(uv_work_t *req) {
memcpy(&pInfo->offerRsp, &rspDhcp, sizeof(DHCP_RSP));
break;
case DHCP_MSG_ACK:
pInfo->step = STEP_ACK;
pInfo->status = STA_RECV_RSP;
cacheDhcpAckBuffer(pInfo, pWork->pPkgBase, pWork->nSize);
memcpy(&pInfo->ackRsp, &rspDhcp, sizeof(DHCP_RSP));
break;
case DHCP_MSG_NAK:
break;

View File

@ -25,14 +25,13 @@
" mac CHAR(20) NOT NULL," \
" ip INTEGER NOT NULL," \
" lease INTEGER NOT NULL," \
" createTm INTEGER NOT NULL," \
" netmask INTEGER," \
" gateway INTEGER," \
" dns1 INTEGER," \
" dns2 INTEGER," \
" server INTEGER NOT NULL," \
" hostname CHAR(64) DEFAULT '' NOT NULL," \
" keyType INTEGER NOT NULL" \
" createTm TIMESTAMP DEFAULT (datetime('now', 'localtime')) NOT NULL" \
");" \
"CREATE INDEX IF NOT EXISTS " \
"lease_index ON lease (uid, mac);"
@ -80,10 +79,121 @@
"SELECT ip, uid FROM pre_assign WHERE (strftime('%%s', 'now', 'localtime') - strftime('%%s', createTm)) < %d;"
#define CLS_TIMEOUT_PRE_ASSIGN_ROW_FMT \
"DELETE FROM pre_assign WHERE (strftime('%%s', 'now', 'localtime') - - strftime('%%s', createTm)) > %d"
"DELETE FROM pre_assign WHERE (strftime('%%s', 'now', 'localtime') - strftime('%%s', createTm)) > %d;"
#define UPDATE_CREATE_TIME_BY_ID_FMT "UPDATE pre_assign SET createTm = datetime('now', 'localtime') WHERE id = %s"
#define INSERT_LEASE_FMT \
"INSERT INTO lease(uid, hostname, mac, ip, lease, netmask, gateway, dns1, dns2, server) " \
"VALUES (%d, '%s', '%s', '%s', %d, '%s', '%s', '%s', '%s', '%s');"
#define LEASE_FIND_ITEM_FMT \
"SELECT id FROM lease WHERE mac = '%s' AND hostname = '%s' AND uid = %d AND ip = '%s' ORDER BY createTm DESC " \
"LIMIT 1;"
#define LEASE_ITEM_UPDATE_FMT \
"UPDATE lease SET lease = %d, netmask = '%s', gateway = '%s', dns1 = '%s', dns2 = '%s', server = '%s', " \
"createTm = datetime('now', 'localtime') WHERE id = %s;"
#define CLS_TIMEOUT_LEASE_ROW_FMT \
"DELETE FROM lease WHERE (strftime('%%s', 'now', 'localtime') - - strftime('%%s', createTm)) > lease.lease"
#define GET_LEASE_ROW_FMT \
"SELECT ip, uid FROM lease WHERE (strftime('%%s', 'now', 'localtime') - strftime('%%s', createTm)) < lease.lease;"
#define GET_LEASE_EXISTS_ROW_FMT \
"SELECT ip, id FROM lease WHERE mac = '%s' AND hostname = '%s' AND uid = %d AND (strftime('%%s', 'now', " \
"'localtime') - strftime('%%s', createTm)) < lease.lease ORDER BY createTm DESC LIMIT 1;"
#define GET_LEASE_INFO_FMT \
"SELECT id, ip, lease, netmask, gateway, dns1, dns2 FROM lease WHERE mac = '%s' AND hostname = '%s' AND " \
"uid = %d AND server = '%s' AND (strftime('%%s', 'now','localtime') - strftime('%%s', createTm)) < lease.lease " \
"ORDER BY createTm DESC LIMIT 1;"
#define UPDATE_LEASE_TIME_BY_ID_FMT "UPDATE lease SET createTm = datetime('now', 'localtime') WHERE id = %llu"
#define LEASE_RELEASE_FMT "DELETE FROM lease WHERE uid = %d AND mac = '%s' AND ip = '%s'"
static int lease_add(PDHCP_REQ pReq,
const char *ip,
const char *netmask,
const char *gw,
const char *dns1,
const char *dns2,
U32 leaseTime) {
int rc;
char buf[2048] = {0};
char macStr[20] = {0};
char **dbResult;
int nRow = 0, nColumn = 0;
MAC_TO_STR(pReq->cliMac, macStr);
snprintf(buf, 2048, LEASE_FIND_ITEM_FMT, macStr, pReq->hostName, pReq->uid, ip);
rc = db_sqlite3_get_rows(buf, &dbResult, &nRow, &nColumn, NULL);
if (rc == ERR_SUCCESS) {
// 已经存在,则更新
if (nRow > 0 && nColumn > 0) {
memset(buf, 0, 2048);
snprintf(buf, 2048, LEASE_ITEM_UPDATE_FMT, leaseTime, netmask, gw, dns1, dns2,
u32_to_str_ip(pReq->serverAddr), dbResult[nColumn]);
rc = db_sqlite3_sql_exec(buf, NULL, NULL, NULL);
if (rc != ERR_SUCCESS) {
LOG_MOD(error, ZM_DHCP_DB, "Add upgrade to lease db error: id = %s\n", dbResult[nColumn]);
}
} else {
//添加一个新的
// 记录设备分配的DHCP信息到数据库
memset(buf, 0, 2048);
snprintf(buf, 2048, INSERT_LEASE_FMT, pReq->uid, pReq->hostName, macStr, ip, leaseTime, netmask, gw, dns1,
dns2, u32_to_str_ip(pReq->serverAddr));
rc = db_sqlite3_sql_exec(buf, NULL, NULL, NULL);
if (rc != ERR_SUCCESS) {
LOG_MOD(error, ZM_DHCP_DB, "Add date to lease db error\n");
}
}
}
sqlite3_free_table(dbResult);
return ERR_SUCCESS;
}
int db_add_lease(PDHCP_REQ pReq, PPOOL_CTX pCtx) {
const char *pNetmask = u32_to_str_ip_safe(htonl(pCtx->netMask));
const char *pGateway = u32_to_str_ip_safe(htonl(pCtx->gwAddr));
const char *pDns1 = u32_to_str_ip_safe(htonl(pCtx->primeDNS));
const char *pDns2 = u32_to_str_ip_safe(htonl(pCtx->salveDNS));
const char *pIp = u32_to_str_ip_safe(htonl(pReq->cliAddr));
// 添加租约信息到lease数据库
lease_add(pReq, pIp, pNetmask, pGateway, pDns1, pDns2, pCtx->leaseTime);
free((void *)pNetmask);
free((void *)pGateway);
free((void *)pDns1);
free((void *)pDns2);
free((void *)pIp);
return ERR_SUCCESS;
}
int db_release_lease(PDHCP_REQ pReq) {
int rc;
char buf[1024] = {0};
char macStr[20] = {0};
MAC_TO_STR(pReq->cliMac, macStr);
snprintf(buf, 1024, LEASE_RELEASE_FMT, pReq->uid, macStr, u32_to_str_ip(htonl(pReq->reqIpAddr)));
rc = db_sqlite3_sql_exec(buf, NULL, NULL, NULL);
if (rc != ERR_SUCCESS) {
LOG_MOD(error, ZM_DHCP_DB, "DB remove lease item error: %s\n", buf);
}
return ERR_SUCCESS;
}
int lease_lock_pre_assign_ip() {
int rc;
char buf[1024] = {0};
@ -109,19 +219,45 @@ int lease_lock_pre_assign_ip() {
}
sqlite3_free_table(dbResult);
memset(buf, 0, 1024);
snprintf(buf, 1024, GET_LEASE_ROW_FMT);
rc = db_sqlite3_get_rows(buf, &dbResult, &nRow, &nColumn, NULL);
if (rc == ERR_SUCCESS && nRow > 0 && nColumn > 0) {
int i;
for (i = 1; i <= nRow; i++) {
U32 uid = strtoul(dbResult[i * nColumn + 1], NULL, 10);
U32 ip = ntohl(inet_addr(dbResult[i * nColumn]));
PDHCP_USER pUser = dhcp_user_create(uid);
if (pUser) {
usr_lease_lock_ip(pUser, ip);
LOG_MOD(debug, ZM_DHCP_DB, "Lock prepare assign ip %s for user %u\n", dbResult[i * nColumn], uid);
}
}
}
sqlite3_free_table(dbResult);
return ERR_SUCCESS;
}
int lease_clearup_timeout_pre_assign() {
int lease_clearup_timeout_items() {
int rc;
char buf[1024] = {0};
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(buf, NULL, NULL, NULL);
LOG_MOD(trace, ZM_DHCP_DB, "Cleanup pre_assign database timeout(%u seconds) data\n", DCHP_STEP_CLEANUP_TIMEOUT);
if (rc != ERR_SUCCESS) {
return rc;
LOG_MOD(error, ZM_DHCP_DB, "Cleanup pre_assign database error: %s\n", buf);
}
rc = db_sqlite3_sql_exec(CLS_TIMEOUT_LEASE_ROW_FMT, NULL, NULL, NULL);
LOG_MOD(trace, ZM_DHCP_DB, "Cleanup assign database lease expire data\n");
if (rc != ERR_SUCCESS) {
LOG_MOD(error, ZM_DHCP_DB, "Cleanup lease database error: %s\n", buf);
}
return ERR_SUCCESS;
@ -176,18 +312,110 @@ int lease_ip_is_pre_assign(U32 uid, U32 ip) {
return TRUE;
}
int lease_get_assign_info(PDHCP_REQ pReq, PPOOL_CTX pAssign, U64 *pCtx) {
static int lease_get_info(PPOOL_CTX pAssign, const char *pRunSql, U64 *pDbId) {
int rc;
char buf[2048] = {0};
char macStr[20] = {0};
U32 ipAddr;
char **dbResult;
int nRow = 0, nColumn = 0;
rc = db_sqlite3_get_rows(pRunSql, &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));
}
if (pDbId) {
*pDbId = strtoull(dbResult[nColumn], NULL, 10);
}
sqlite3_free_table(dbResult);
return ERR_SUCCESS;
} else {
sqlite3_free_table(dbResult);
return -ERR_ITEM_UNEXISTS;
}
}
int lease_get_from_lease(PDHCP_REQ pReq, PPOOL_CTX pAssign) {
int rc;
U64 id;
char buf[2048] = {0};
char macStr[20] = {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),
snprintf(buf, 2048, GET_LEASE_INFO_FMT, macStr, pReq->hostName, pReq->uid, u32_to_str_ip(pReq->serverAddr));
rc = lease_get_info(pAssign, buf, &id);
if (rc == ERR_SUCCESS) {
// 更新租约时间信息
memset(buf, 0, 1024);
snprintf(buf, 1024, UPDATE_LEASE_TIME_BY_ID_FMT, id);
if (db_sqlite3_sql_exec(buf, NULL, NULL, NULL) != ERR_SUCCESS) {
LOG_MOD(warn, ZM_DHCP_DB, "Update %llu lease time error: %s\n", id, buf);
}
return ERR_SUCCESS;
}
return -ERR_ITEM_UNEXISTS;
}
int lease_get_from_pre_assign(PDHCP_REQ pReq, PPOOL_CTX pAssign) {
int rc;
char buf[2048] = {0};
char macStr[20] = {0};
U64 id;
MAC_TO_STR(pReq->cliMac, macStr);
snprintf(buf, 2048, GET_ASSIGN_IP_INFO_FMT, macStr, pReq->hostName, pReq->uid, u32_to_str_ip(pReq->serverAddr),
DCHP_STEP_REQUEST_TIMEOUT);
rc = lease_get_info(pAssign, buf, &id);
if (rc == ERR_SUCCESS) {
const char *pNetmask = u32_to_str_ip_safe(htonl(pAssign->netMask));
const char *pGateway = u32_to_str_ip_safe(htonl(pAssign->gwAddr));
const char *pDns1 = u32_to_str_ip_safe(htonl(pAssign->primeDNS));
const char *pDns2 = u32_to_str_ip_safe(htonl(pAssign->salveDNS));
const char *pIp = u32_to_str_ip_safe(htonl(pAssign->minAddr));
// 删除预分配IP信息
memset(buf, 0, 2048);
sprintf(buf, "DELETE FROM pre_assign WHERE id = %llu;", id);
db_sqlite3_sql_exec(buf, NULL, NULL, NULL);
// 添加租约信息到lease数据库
lease_add(pReq, pIp, pNetmask, pGateway, pDns1, pDns2, pAssign->leaseTime);
free((void *)pNetmask);
free((void *)pGateway);
free((void *)pDns1);
free((void *)pDns2);
free((void *)pIp);
return ERR_SUCCESS;
}
return -ERR_ITEM_UNEXISTS;
#if 0
rc = db_sqlite3_get_rows(buf, &dbResult, &nRow, &nColumn, NULL);
if (rc == ERR_SUCCESS && nRow > 0 && nColumn > 0) {
char *pNetmask = dbResult[nColumn + 3];
@ -215,11 +443,22 @@ int lease_get_assign_info(PDHCP_REQ pReq, PPOOL_CTX pAssign, U64 *pCtx) {
pAssign->salveDNS = ntohl(inet_addr(pDns2));
}
*pCtx = strtoull(dbResult[nColumn], NULL, 10);
// 删除预分配IP信息
memset(buf, 0, 2048);
sprintf(buf, "DELETE FROM pre_assign WHERE id = %s;", dbResult[nColumn]);
//db_sqlite3_sql_exec(buf, NULL, NULL, NULL);
lease_add(pReq, dbResult[nColumn + 1], pNetmask, pGateway, pDns1, pDns2, pAssign->leaseTime);
sqlite3_free_table(dbResult);
return ERR_SUCCESS;
} else {
LOG_MOD(error, ZM_DHCP_DB, "No previously records: \n%s\n", buf);
}
sqlite3_free_table(dbResult);
return -ERR_ITEM_UNEXISTS;
#endif
}
int lease_get_pre_assign(U32 uid, const char *mac, const char *hostname, U32 *preAssign) {
@ -239,13 +478,30 @@ int lease_get_pre_assign(U32 uid, const char *mac, const char *hostname, U32 *pr
snprintf(buf, 1024, UPDATE_CREATE_TIME_BY_ID_FMT, dbResult[3]);
db_sqlite3_sql_exec(buf, NULL, NULL, NULL);
}
rc = ERR_ITEM_EXISTS;
sqlite3_free_table(dbResult);
return ERR_ITEM_EXISTS;
} else {
rc = ERR_ITEM_UNEXISTS;
memset(buf, 0, 1024);
snprintf(buf, 1024, GET_LEASE_EXISTS_ROW_FMT, mac, hostname, uid);
rc = db_sqlite3_get_rows(buf, &dbResult, &nRow, &nColumn, NULL);
if (rc == ERR_SUCCESS && nRow > 0 && nColumn > 0) {
if (preAssign) {
*preAssign = ntohl(inet_addr(dbResult[2]));
// 更新时间戳
memset(buf, 0, 1024);
snprintf(buf, 1024, UPDATE_CREATE_TIME_BY_ID_FMT, dbResult[3]);
db_sqlite3_sql_exec(buf, NULL, NULL, NULL);
}
sqlite3_free_table(dbResult);
return rc;
return ERR_ITEM_EXISTS;
}
}
sqlite3_free_table(dbResult);
return ERR_ITEM_UNEXISTS;
}
int lease_db_add_pre_assign(PDHCP_REQ pReq, U32 ip, PPOOL_CTX pPool) {

View File

@ -187,7 +187,12 @@ static void fill_package(PDHCP_PACKAGE pRsp, PDHCP_PACKAGE pReq) {
// 二层头
// 目的IP地址
if (pReq->vlan_hdr.ip.saddr != 0) {
memcpy(pRsp->vlan_hdr.eth.h_dest, pRsp->vlan_hdr.eth.h_source, ETH_ALEN);
} else {
memset(pRsp->vlan_hdr.eth.h_dest, 0xFF, ETH_ALEN);
}
// 源 IP 地址
memcpy(pRsp->vlan_hdr.eth.h_source, g_nicInfo.macAddr, ETH_ALEN);
// protol
@ -205,7 +210,11 @@ static void fill_package(PDHCP_PACKAGE pRsp, PDHCP_PACKAGE pReq) {
// 更新源IP
pRsp->vlan_hdr.ip.saddr = g_nicInfo.ipAddr;
// 更新目的IP地址广播255.255.255.255
if (pReq->vlan_hdr.ip.saddr == 0) {
pRsp->vlan_hdr.ip.daddr = 0xFFFFFFFF;
} else {
pRsp->vlan_hdr.ip.daddr = pReq->vlan_hdr.ip.saddr;
}
// UDP 头
// 目的端口
@ -239,10 +248,60 @@ static void fill_package(PDHCP_PACKAGE pRsp, PDHCP_PACKAGE pReq) {
pRsp->dhcp.giaddr = 0;
}
static int dhcp_resp_ack(PDHCP_PACKAGE pReq, PPOOL_CTX pIpInfo) {
U8 *pOpt;
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->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_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) {
@ -286,38 +345,11 @@ static int dhcp_resp_ack(PDHCP_PACKAGE pReq, PPOOL_CTX pIpInfo) {
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;
return dhcp_prepare_tx(pOpt, pRsp);
}
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) {
@ -360,32 +392,7 @@ static int dhcp_resp_offer(PDHCP_PACKAGE pReq, PPOOL_CTX pIpInfo, U32 ip) {
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;
return dhcp_prepare_tx(pOpt, pRsp);
}
static void on_sock_recv(uv_work_t *req) {
@ -419,7 +426,9 @@ static void on_sock_recv(uv_work_t *req) {
reqDhcp.xid = DHCP_XID(pkg->dhcp.xid);
reqDhcp.uid = VLAN_VNI_ID(pkg->vlan_hdr.vlan.id);
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:
@ -449,7 +458,6 @@ static void on_sock_recv(uv_work_t *req) {
strncpy(reqDhcp.hostName, (char *)opt.pValue, MIN((int)opt.len, 256));
}
MAC_TO_STR(reqDhcp.cliMac, macStr);
ret = pre_alloc_dhcp_res(&reqDhcp, pWork->pUser, &ip, &pIpInfo);
if (ret == ERR_SUCCESS) {
@ -457,7 +465,6 @@ static void on_sock_recv(uv_work_t *req) {
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);
}
@ -468,15 +475,24 @@ static void on_sock_recv(uv_work_t *req) {
// 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->vlan_hdr.ip.saddr != 0) {
reqDhcp.reqServer = ntohl(pkg->vlan_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;
}
// 客户端主机名
@ -495,29 +511,64 @@ static void on_sock_recv(uv_work_t *req) {
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);
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 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));
}
}
// 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->vlan_hdr.ip.saddr != 0) {
reqDhcp.reqServer = ntohl(pkg->vlan_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);

View File

@ -11,9 +11,12 @@ int lease_db_add_pre_assign(PDHCP_REQ pReq, U32 ip, PPOOL_CTX pPool);
int lease_init_database();
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_get_assign_info(PDHCP_REQ pReq, PPOOL_CTX pAssign, U64 *pCtx);
int lease_clearup_timeout_pre_assign();
int lease_get_from_pre_assign(PDHCP_REQ pReq, PPOOL_CTX pAssign);
int lease_get_from_lease(PDHCP_REQ pReq, PPOOL_CTX pAssign);
int lease_clearup_timeout_items();
int lease_lock_pre_assign_ip();
int db_release_lease(PDHCP_REQ pReq);
int db_add_lease(PDHCP_REQ pReq, PPOOL_CTX pCtx);
#ifdef __cplusplus
}
#endif

View File

@ -31,7 +31,9 @@ typedef struct {
int dhcp_lease_init();
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 is_pre_assigned(PDHCP_REQ pReq, PPOOL_CTX pCtx, U64 *dbId);
int is_pre_assigned(PDHCP_REQ pReq, PPOOL_CTX pCtx);
int lease_release(PDHCP_REQ pReq);
int lease_add_host(PDHCP_REQ pReq);
#ifdef __cplusplus
}
#endif

View File

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

View File

@ -39,8 +39,36 @@ int usr_lease_lock_ip(PDHCP_USER pUser, U32 ip) {
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 lease_add_host(PDHCP_REQ pReq) {
PDHCP_USER pUser = dhcp_user_create(pReq->uid);
if (pUser) {
PPOOL_CTX pPool, pTemp;
// 查找对应的地址池
LL_FOREACH_SAFE(pUser->pUserPool, pPool, pTemp) {
// 比较 IP 范围
if (pPool->minAddr <= pReq->cliAddr && pPool->maxAddr >= pReq->cliAddr) {
// 添加记录到数据库
db_add_lease(pReq, pPool);
return ERR_SUCCESS;
}
}
}
return ERR_SUCCESS;
}
int is_pre_assigned(PDHCP_REQ pReq, PPOOL_CTX pCtx) {
// 首先从租约信息中获取数据
if (lease_get_from_lease(pReq, pCtx) == ERR_SUCCESS) {
return ERR_SUCCESS;
}
// 从预分配IP中获取信息
return lease_get_from_pre_assign(pReq, pCtx);
}
int lease_release(PDHCP_REQ pReq) {
return db_release_lease(pReq);
}
//int pre_alloc_dhcp_res(U32 uid, const char *pMac, U32 *pOutIp, PIPPOOL_INFO *pOutPool) {
@ -70,7 +98,6 @@ int pre_alloc_dhcp_res(PDHCP_REQ pReq, PDHCP_USER pUser, U32 *pOutIp, PPOOL_CTX
// 该 IP 可用
if (pLock == NULL) {
#if 1
if (lease_ip_is_pre_assign(pReq->uid, addr) == FALSE) {
usr_lease_lock_ip(pUser, addr);
*pOutIp = addr;
@ -80,16 +107,6 @@ int pre_alloc_dhcp_res(PDHCP_REQ pReq, PDHCP_USER pUser, U32 *pOutIp, PPOOL_CTX
return ERR_SUCCESS;
}
#else
usr_lease_lock_ip(pUser, addr);
*pOutIp = addr;
*pOutPool = pPool;
lease_db_add_pre_assign(pReq, addr, pPool);
// LOG_MOD(debug, ZM_DHCP_LEASE, "User %u(%u) prepar assign ipaddr %08X of %p\n", pReq->uid, pUser->uid,
// addr, pPool);
return ERR_SUCCESS;
#endif
}
addr++;
@ -97,7 +114,7 @@ int pre_alloc_dhcp_res(PDHCP_REQ pReq, PDHCP_USER pUser, U32 *pOutIp, PPOOL_CTX
}
// 清理所有超时的预分配IP
lease_clearup_timeout_pre_assign();
lease_clearup_timeout_items();
// 没有可预分配的IP报错
//LOG_MOD(error, ZM_DHCP_LEASE, "No free ipaddress in poll: uid = %u, pool = %p\n", pReq->uid, pUser->pUserPool);
return -ERR_DHCP_NO_ADDR;
@ -113,7 +130,7 @@ int dhcp_lease_init() {
}
// 清理所有超时的预分配IP
lease_clearup_timeout_pre_assign();
lease_clearup_timeout_items();
// lock 预分配 IP
lease_lock_pre_assign_ip();