vcpe/srcs/service/dhcpd/db_interface.c

298 lines
11 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//
// Created by HuangXin on 2023/4/24.
//
#include <sqlite3.h>
#include "user_errno.h"
#include "database.h"
#include "dhcp_network.h"
#include "rfc2131.h"
#include "ip_pool.h"
#include "db_interface.h"
#include "misc.h"
#include "zlog_module.h"
#include "lease.h"
// 10小时以上清理无效的预分配IP
#define DCHP_STEP_CLEANUP_TIMEOUT (36000)
// 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 " \
"lease_index ON lease (uid, mac);"
#define CREATE_PRE_ASSIGN_TABLE() \
"CREATE TABLE IF NOT EXISTS pre_assign" \
" ( id INTEGER PRIMARY KEY AUTOINCREMENT," \
" uid INTEGER NOT NULL," \
" xid INTEGER NOT NULL," \
" hostname CHAR(64) DEFAULT '' NOT NULL," \
" mac CHAR(20) NOT NULL," \
" ip CHAR(24) NOT NULL," \
" lease INTEGER NOT NULL," \
" netmask CHAR(24)," \
" gateway CHAR(24)," \
" dns1 CHAR(24)," \
" dns2 CHAR(24)," \
" server CHAR(24) NOT NULL," \
" createTm TIMESTAMP DEFAULT (datetime('now', 'localtime')) NOT NULL" \
"); CREATE INDEX IF NOT EXISTS pre_assign_index ON pre_assign(ip, uid);"
#define INSERT_PRE_ASSIGN_ROW_FMT \
"INSERT INTO pre_assign (uid, xid, hostname, mac, ip, lease, netmask, gateway, dns1, dns2, server) " \
"VALUES (%d, %d, '%s', '%s', '%s', %d, '%s', '%s', '%s', '%s', '%s');"
#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;"
#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 \
"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;"
#define IP_IS_PRE_ASSIGN "SELECT ip FROM pre_assign WHERE ip = '%s' AND uid = %d"
#define IP_IS_PRE_ASSIGN_TIMEOUT_FMT \
"SELECT (strftime('%%s', 'now', 'localtime') - strftime('%%s', createTm)) as tm, id FROM pre_assign WHERE ip = " \
"'%s' AND tm >= %d AND uid = %d ORDER BY tm DESC LIMIT 1;"
#define GET_PRE_ASSIGN_ROW_FMT \
"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"
#define UPDATE_CREATE_TIME_BY_ID_FMT "UPDATE pre_assign SET createTm = datetime('now', 'localtime') WHERE id = %s"
int lease_lock_pre_assign_ip() {
int rc;
char buf[1024] = {0};
char **dbResult;
int nRow = 0, nColumn = 0;
snprintf(buf, 1024, GET_PRE_ASSIGN_ROW_FMT, DCHP_STEP_CLEANUP_TIMEOUT);
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);
}
// printf("-- Row %d value %s, %s, %s\n", i, dbResult[i * nColumn], dbResult[i * nColumn + 1], dbResult[i * nColumn + 2]);
}
}
sqlite3_free_table(dbResult);
return ERR_SUCCESS;
}
int lease_clearup_timeout_pre_assign() {
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);
if (rc != ERR_SUCCESS) {
return rc;
}
return ERR_SUCCESS;
}
int lease_ip_is_pre_assign(U32 uid, U32 ip) {
int rc;
char buf[1024] = {0};
char **dbResult;
int nRow = 0, nColumn = 0;
// 判断IP是否存曾经被预分配
snprintf(buf, 1024, IP_IS_PRE_ASSIGN, u32_to_str_ip(htonl(ip)), uid);
rc = db_sqlite3_get_rows(buf, &dbResult, &nRow, &nColumn, NULL);
sqlite3_free_table(dbResult);
if (rc == ERR_SUCCESS && nRow == 0) {
// 数据库没有相关记录,直接返回
LOG_MOD(trace, ZM_DHCP_DB, "New prepare assign ipaddr %s form user %u\n", u32_to_str_ip(htonl(ip)), uid);
return FALSE;
}
// 判断数据库中该IP是否未超时
memset(buf, 0, 1024);
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);
sqlite3_free_table(dbResult);
if (rc == ERR_SUCCESS && nRow > 0 && nColumn > 0) {
// 如果数据库存在记录说明该IP暂时不可以用
LOG_MOD(trace, ZM_DHCP_DB, "No free ip address form user %u\n", uid);
return TRUE;
}
// 判断是否有超时预分配的IP 存在的话可以预分配给其它请求
memset(buf, 0, 1024);
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);
if (rc == ERR_SUCCESS && nRow > 0 && nColumn > 0) {
// 清理超时资源并预分配
// 更新时间戳
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);
LOG_MOD(trace, ZM_DHCP_DB, "New prepare assign ipaddr %s form user %u by clearup resource\n",
u32_to_str_ip(htonl(ip)), uid);
return FALSE;
}
sqlite3_free_table(dbResult);
// 处理失败,默认返回
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 rc;
char buf[1024] = {0};
char **dbResult;
int nRow = 0, nColumn = 0;
snprintf(buf, 1024, GET_PRE_ASSIGN_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);
}
rc = ERR_ITEM_EXISTS;
} else {
rc = ERR_ITEM_UNEXISTS;
}
sqlite3_free_table(dbResult);
return rc;
}
int lease_db_add_pre_assign(PDHCP_REQ pReq, U32 ip, PPOOL_CTX pPool) {
int rc;
char buf[1024] = {0};
char macStr[20] = {0};
const char *pIp = u32_to_str_ip_safe(htonl(ip));
const char *pMask = u32_to_str_ip_safe(htonl(pPool->netMask));
const char *pGw = u32_to_str_ip_safe(htonl(pPool->gwAddr));
const char *pDns1 = u32_to_str_ip_safe(htonl(pPool->primeDNS));
const char *pDns2 = u32_to_str_ip_safe(htonl(pPool->salveDNS));
const char *pServer = u32_to_str_ip_safe(pReq->serverAddr);
MAC_TO_STR(pReq->cliMac, macStr);
snprintf(buf, 1024, INSERT_PRE_ASSIGN_ROW_FMT, pReq->uid, pReq->xid, pReq->hostName, macStr, pIp, pPool->leaseTime,
pMask, pGw, pDns1, pDns2, pServer);
free((void *)pIp);
free((void *)pMask);
free((void *)pGw);
free((void *)pDns1);
free((void *)pDns2);
free((void *)pServer);
rc = db_sqlite3_sql_exec(buf, NULL, NULL, NULL);
if (rc != ERR_SUCCESS) {
return rc;
}
return ERR_SUCCESS;
}
int lease_init_database() {
int rc;
rc = db_sqlite3_sql_exec(CREATE_LEASE_TABLE(), NULL, NULL, NULL);
if (rc != ERR_SUCCESS) {
return rc;
}
rc = db_sqlite3_sql_exec(CREATE_PRE_ASSIGN_TABLE(), NULL, NULL, NULL);
if (rc != ERR_SUCCESS) {
return rc;
}
return ERR_SUCCESS;
}