From 85b6b108dfd2932e9304bc47bdcff80beab584da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BB=84=E6=98=95?= Date: Fri, 28 Apr 2023 15:19:00 +0800 Subject: [PATCH] =?UTF-8?q?OCT=201.=20DHCP=20=E6=9C=8D=E5=8A=A1=E6=94=AF?= =?UTF-8?q?=E6=8C=81=20ACK=EF=BC=8C=20RELEASE=EF=BC=8C=20INFO=20=E6=B6=88?= =?UTF-8?q?=E6=81=AF=E5=A4=84=E7=90=86=202.=20DHCP=20=E6=B5=8B=E8=AF=95?= =?UTF-8?q?=E5=B7=A5=E5=85=B7=E6=94=AF=E6=8C=81=E6=8E=A5=E6=94=B6=20ACK?= =?UTF-8?q?=E6=95=B0=E6=8D=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- dhcp_tools/main.h | 1 + dhcp_tools/main_wnd.c | 11 + dhcp_tools/uv_rawsocket.c | 6 +- srcs/service/dhcpd/db_interface.c | 316 ++++++++++++++++++++-- srcs/service/dhcpd/dhcpd_network.c | 187 ++++++++----- srcs/service/dhcpd/include/db_interface.h | 7 +- srcs/service/dhcpd/include/lease.h | 4 +- srcs/service/dhcpd/include/rfc2131.h | 1 + srcs/service/dhcpd/lease.c | 47 +++- 9 files changed, 463 insertions(+), 117 deletions(-) diff --git a/dhcp_tools/main.h b/dhcp_tools/main.h index 3a98829..c75f777 100644 --- a/dhcp_tools/main.h +++ b/dhcp_tools/main.h @@ -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 diff --git a/dhcp_tools/main_wnd.c b/dhcp_tools/main_wnd.c index 01c1876..47b81b6 100644 --- a/dhcp_tools/main_wnd.c +++ b/dhcp_tools/main_wnd.c @@ -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; diff --git a/dhcp_tools/uv_rawsocket.c b/dhcp_tools/uv_rawsocket.c index 6a332f9..cf42b57 100644 --- a/dhcp_tools/uv_rawsocket.c +++ b/dhcp_tools/uv_rawsocket.c @@ -2,7 +2,6 @@ // Created by xajhuang on 2023/4/20. // #include -#include #include #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; diff --git a/srcs/service/dhcpd/db_interface.c b/srcs/service/dhcpd/db_interface.c index 6e7c128..8467b73 100644 --- a/srcs/service/dhcpd/db_interface.c +++ b/srcs/service/dhcpd/db_interface.c @@ -18,23 +18,22 @@ // Discover 预分配IP 和Request 请求间的超时时间 #define DCHP_STEP_REQUEST_TIMEOUT (600000) -#define CREATE_LEASE_TABLE() \ - "CREATE TABLE IF NOT EXISTS lease " \ - " ( id INTEGER PRIMARY KEY AUTOINCREMENT," \ - " uid INTEGER NOT NULL," \ - " 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" \ - ");" \ - "CREATE INDEX IF NOT EXISTS " \ +#define CREATE_LEASE_TABLE() \ + "CREATE TABLE IF NOT EXISTS lease " \ + " ( id INTEGER PRIMARY KEY AUTOINCREMENT," \ + " uid INTEGER NOT NULL," \ + " mac CHAR(20) NOT NULL," \ + " ip INTEGER NOT NULL," \ + " lease INTEGER NOT NULL," \ + " netmask INTEGER," \ + " gateway INTEGER," \ + " dns1 INTEGER," \ + " dns2 INTEGER," \ + " server INTEGER NOT NULL," \ + " hostname CHAR(64) DEFAULT '' NOT NULL," \ + " createTm TIMESTAMP DEFAULT (datetime('now', 'localtime')) NOT NULL" \ + ");" \ + "CREATE INDEX IF NOT EXISTS " \ "lease_index ON lease (uid, mac);" #define CREATE_PRE_ASSIGN_TABLE() \ @@ -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 ERR_ITEM_EXISTS; + } } sqlite3_free_table(dbResult); - return rc; + return ERR_ITEM_UNEXISTS; } int lease_db_add_pre_assign(PDHCP_REQ pReq, U32 ip, PPOOL_CTX pPool) { diff --git a/srcs/service/dhcpd/dhcpd_network.c b/srcs/service/dhcpd/dhcpd_network.c index 4c3d55f..1dd48c5 100644 --- a/srcs/service/dhcpd/dhcpd_network.c +++ b/srcs/service/dhcpd/dhcpd_network.c @@ -187,7 +187,12 @@ static void fill_package(PDHCP_PACKAGE pRsp, PDHCP_PACKAGE pReq) { // 二层头 // 目的IP地址 - memset(pRsp->vlan_hdr.eth.h_dest, 0xFF, ETH_ALEN); + 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 - pRsp->vlan_hdr.ip.daddr = 0xFFFFFFFF; + 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_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; - U16 csum; - int tolSize; 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); - - 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)); + // 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_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); diff --git a/srcs/service/dhcpd/include/db_interface.h b/srcs/service/dhcpd/include/db_interface.h index 2b7aed3..dbfd4fa 100644 --- a/srcs/service/dhcpd/include/db_interface.h +++ b/srcs/service/dhcpd/include/db_interface.h @@ -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 diff --git a/srcs/service/dhcpd/include/lease.h b/srcs/service/dhcpd/include/lease.h index 46c3463..a3a63b9 100644 --- a/srcs/service/dhcpd/include/lease.h +++ b/srcs/service/dhcpd/include/lease.h @@ -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 diff --git a/srcs/service/dhcpd/include/rfc2131.h b/srcs/service/dhcpd/include/rfc2131.h index 8b759fb..5715b13 100644 --- a/srcs/service/dhcpd/include/rfc2131.h +++ b/srcs/service/dhcpd/include/rfc2131.h @@ -29,6 +29,7 @@ typedef struct { char vendorClassId[256]; U32 reqServer; U32 serverAddr; + U32 cliAddr; char hostName[256]; } DHCP_REQ, *PDHCP_REQ; diff --git a/srcs/service/dhcpd/lease.c b/srcs/service/dhcpd/lease.c index b6991d7..ee58880 100644 --- a/srcs/service/dhcpd/lease.c +++ b/srcs/service/dhcpd/lease.c @@ -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();