diff --git a/.clang-format b/.clang-format
index 770640c..e7a61da 100644
--- a/.clang-format
+++ b/.clang-format
@@ -72,7 +72,7 @@ BreakConstructorInitializersBeforeComma: false
 BreakConstructorInitializers: BeforeColon
 BreakAfterJavaFieldAnnotations: false
 BreakStringLiterals: true
-ColumnLimit: 120
+ColumnLimit: 140
 CommentPragmas: '^ IWYU pragma:'
 CompactNamespaces: true
 ConstructorInitializerAllOnOneLineOrOnePerLine: true
@@ -135,7 +135,7 @@ ObjCSpaceBeforeProtocolList: true
 PenaltyBreakAssignment: 1000
 PenaltyBreakBeforeFirstCallParameter: 1
 PenaltyBreakComment: 300
-PenaltyBreakFirstLessLess: 120
+PenaltyBreakFirstLessLess: 140
 PenaltyBreakString: 1000
 PenaltyBreakTemplateDeclaration: 10
 PenaltyExcessCharacter: 1000000
diff --git a/CMakeLists.txt b/CMakeLists.txt
index ea4d8d5..94821b5 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -131,9 +131,21 @@ ENDIF ()
 
 IF (USED_SQLITE)
     MESSAGE("Select Option USED_SQLITE")
+    LIST(APPEND COMMON_DEFINE "-DSQLITE_ON")
+ENDIF ()
+
+IF (USED_MYSQL)
+    MESSAGE("Select Option USED_MYSQL")
+    LIST(APPEND COMMON_DEFINE "-DUSED_MYSQL")
+ENDIF ()
+
+IF (USED_REDIS)
+    MESSAGE("Select Option USED_REDIS")
+    LIST(APPEND COMMON_DEFINE "-DUSED_REDIS")
 ENDIF ()
 
 IF (USED_SQLITE_CRYPTO)
+    LIST(APPEND COMMON_DEFINE "-DSQLITE_CRYPTO_ON")
     MESSAGE("Select Option USED_SQLITE_CRYPTO")
 ENDIF ()
 
diff --git a/config/vcpe.cfg b/config/vcpe.cfg
index 2a7bb71..4f40009 100644
--- a/config/vcpe.cfg
+++ b/config/vcpe.cfg
@@ -40,8 +40,8 @@ application:
         mysql_passwd = "AES@5/BQyUIfVxgV9BZAz/D3Rg==";      # mysql 数据库密码
         mysql_database = "test";                            # mysql 数据库名称
 
-        sqlite_dbname = "vcpe.db";                          # sqlite3 数据库文件名
-        sqlite_passwd = "test123";                          # sqlite3 数据库密码
+        sqlite_dbname = "/home/hx/vcpe.db";                          # sqlite3 数据库文件名
+        sqlite_passwd = "";                                 # sqlite3 数据库密码
     };
 
     # MQ 相关配置
@@ -101,7 +101,7 @@ application:
         # mac_filter = ["00:01:02:03:04:07", "00:01:02:03:04:01"];
         # IP地址池配置
         range_set: (
-            {   dhcp_range = "192.168.101.2-192.168.101.4";
+            {   dhcp_range = "192.168.101.0-192.168.101.4";
                 subnet_mask = "255.255.255.0";
                 domain_server = "114.114.114.114,8.8.8.8";
                 gateway = "192.168.101.1";
diff --git a/srcs/include/service/dhcpd.h b/srcs/include/service/dhcpd.h
index 3d5094b..0f461b1 100644
--- a/srcs/include/service/dhcpd.h
+++ b/srcs/include/service/dhcpd.h
@@ -9,6 +9,9 @@
 extern "C" {
 #endif
 
+#define DHCP_SVR_PORT     (67)
+#define DHCP_CLI_PORT     (68)
+
 /**
  * Message op code / message type
  * Request Message
@@ -21,6 +24,7 @@ extern "C" {
 #define BOOTP_REPLY       2
 
 #define DHCP_MSG_NONE     0
+
 /**
  * DHCP客户端在请求IP地址时并不知道DHCP服务器的位置,
  * 因此DHCP客户端会在本地网络内以广播方式发送Discover请求报文,以发现网络中的DHCP服务器。
@@ -28,6 +32,7 @@ extern "C" {
  * DHCP客户端据此可以知道网络中存在的DHCP服务器的位置
  */
 #define DHCP_MSG_DISCOVER 1
+
 /**
  * DHCP服务器收到Discover报文后,就会在所配置的地址池中查找一个合适的IP地址,
  * 加上相应的租约期限和其他配置信息(如网关、DNS服务器等),构造一个Offer报文,
@@ -35,6 +40,7 @@ extern "C" {
  * 最终还需要客户端通过ARP来检测该IP地址是否重复
  */
 #define DHCP_MSG_OFFER    2
+
 /**
  * DHCP客户端可能会收到很多Offer请求报文,所以必须在这些应答中选择一个。
  * 通常是选择第一个Offer应答报文的服务器作为自己的目标服务器,
@@ -44,28 +50,33 @@ extern "C" {
  * 如果没有收到ACK报文,在租期达到87.5%时,会再次发送广播的Request请求报文以请求续延租约
  */
 #define DHCP_MSG_REQUEST  3
+
 /**
  * DHCP客户端收到DHCP服务器ACK应答报文后,
  * 通过地址冲突检测发现服务器分配的地址冲突或者由于其他原因导致不能使用,
  * 则会向DHCP服务器发送Decline请求报文,通知服务器所分配的IP地址不可用,以期获得新的IP地址
  */
 #define DHCP_MSG_DECLINE  4
+
 /**
  * DHCP服务器收到Request请求报文后,根据Request报文中携带的用户MAC来查找有没有相应的租约记录,
  * 如果有则发送ACK应答报文,通知用户可以使用分配的IP地址
  */
 #define DHCP_MSG_ACK      5
+
 /**
  * 如果DHCP服务器收到Request请求报文后,没有发现有相应的租约记录或者由于某些原因无法正常分配IP地址,
  * 则向DHCP客户端发送NAK应答报文,通知用户无法分配合适的IP地址
  */
 #define DHCP_MSG_NAK      6
+
 /**
  * 当DHCP客户端不再需要使用分配IP地址时(一般出现在客户端关机、下线等状况)
  * 就会主动向DHCP服务器发送RELEASE请求报文,告知服务器用户不再需要分配IP地址,
  * 请求DHCP服务器释放对应的IP地址
  */
 #define DHCP_MSG_RELEASE  7
+
 /**
  * DHCP客户端如果需要从DHCP服务器端获取更为详细的配置信息,
  * 则向DHCP服务器发送Inform请求报文;DHCP服务器在收到该报文后,
diff --git a/srcs/libs/CMakeLists.txt b/srcs/libs/CMakeLists.txt
index b805af6..f0bf074 100644
--- a/srcs/libs/CMakeLists.txt
+++ b/srcs/libs/CMakeLists.txt
@@ -10,13 +10,14 @@ IF (USED_SQLITE_CRYPTO)
 ENDIF ()
 
 INCLUDE_DIRECTORIES(include ../opendhcp183 mongoose
-                    ./ ./include ../lwip/src/include ../lwip/src/arch_linux/include ../include)
+        ./ ./include ../lwip/src/include ../lwip/src/arch_linux/include ../include)
 FILE(GLOB C_HEADS ./include/network/*.h include/*.h include/uthash/*.h include/s2j/*.h vector/*.h ${CMAKE_BINARY_DIR}/*.h ${PROJECT_BINARY_DIR}/*.h)
 
 AUX_SOURCE_DIRECTORY(json C_SRC)
 AUX_SOURCE_DIRECTORY(args C_SRC)
 AUX_SOURCE_DIRECTORY(init C_SRC)
 AUX_SOURCE_DIRECTORY(misc C_SRC)
+AUX_SOURCE_DIRECTORY(bitset C_SRC)
 AUX_SOURCE_DIRECTORY(banner C_SRC)
 AUX_SOURCE_DIRECTORY(configure C_SRC)
 AUX_SOURCE_DIRECTORY(network C_SRC)
@@ -40,22 +41,13 @@ IF (USED_HTTP_SVR)
     AUX_SOURCE_DIRECTORY(mongoose C_SRC)
 ENDIF ()
 
-IF (USED_REDIS)
-    ADD_DEFINITIONS(-DUSED_REDIS)
-ENDIF ()
-
 IF (USED_SQLITE)
-    ADD_DEFINITIONS(-DSQLITE_ON)
+    LIST(APPEND C_SRC database/database.c)
     IF (SQLITE_CRYPTO_ON)
-        ADD_DEFINITIONS(-DSQLITE_CRYPTO_ON)
         AUX_SOURCE_DIRECTORY(database/sqlite3 C_SRC)
     ENDIF ()
 ENDIF ()
 
-IF (USED_MYSQL)
-    ADD_DEFINITIONS(-DUSED_MYSQL)
-ENDIF ()
-
 SET(CMAKE_C_STANDARD 99)
 
 SET_SOURCE_FILES_PROPERTIES(misc/zvector.c PROPERTIES COMPILE_FLAGS "-Wall -Wextra -flto")
@@ -63,7 +55,7 @@ SET_SOURCE_FILES_PROPERTIES(mongoose/mongoose.c PROPERTIES COMPILE_FLAGS "-Wall
 
 IF (USED_SQLITE_CRYPTO)
     SET_SOURCE_FILES_PROPERTIES(database/sqlite3/sqlite3.c PROPERTIES
-                                COMPILE_FLAGS "-DSQLITE_HAS_CODEC \
+            COMPILE_FLAGS "-DSQLITE_HAS_CODEC \
 -DSQLCIPHER_CRYPTO_OPENSSL -DSQLITE_OS_UNIX=1 \
 -D_HAVE_SQLITE_CONFIG_H -DBUILD_sqlite -DNDEBUG -DSQLITE_THREADSAFE=1 \
 -DSQLITE_ENABLE_MATH_FUNCTIONS -DSQLITE_ENABLE_UPDATE_DELETE_LIMIT \
@@ -71,7 +63,11 @@ IF (USED_SQLITE_CRYPTO)
 -DSQLITE_HAVE_ZLIB=1 -DSQLITE_TEMP_STORE=2")
 ENDIF ()
 
-ADD_DEFINITIONS(${COMMON_DEFINE} -DMG_ARCH=MG_ARCH_UNIX -DMG_ENABLE_OPENSSL=1)
+ADD_DEFINITIONS(${COMMON_DEFINE})
+
+IF (USED_HTTP_SVR)
+    ADD_DEFINITIONS(-DMG_ARCH=MG_ARCH_UNIX -DMG_ENABLE_OPENSSL=1)
+ENDIF ()
 
 ADD_LIBRARY(${LIB_PROJECT_TARGET} ${C_SRC} ${C_HEADS})
 
diff --git a/srcs/libs/bitset/bitset.c b/srcs/libs/bitset/bitset.c
new file mode 100644
index 0000000..1565fe4
--- /dev/null
+++ b/srcs/libs/bitset/bitset.c
@@ -0,0 +1,382 @@
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+
+#include "bitset/bitset.h"
+
+/* Create a new bitset. Return NULL in case of failure. */
+bitset_t *bitset_create() {
+    bitset_t *bitset = NULL;
+    /* Allocate the bitset itself. */
+    if ((bitset = (bitset_t *)malloc(sizeof(bitset_t))) == NULL) {
+        return NULL;
+    }
+    bitset->array     = NULL;
+    bitset->arraysize = 0;
+    bitset->capacity  = 0;
+    return bitset;
+}
+
+/* Create a new bitset able to contain size bits. Return NULL in case of failure. */
+bitset_t *bitset_create_with_capacity(size_t size) {
+    bitset_t *bitset = NULL;
+    /* Allocate the bitset itself. */
+    if ((bitset = (bitset_t *)malloc(sizeof(bitset_t))) == NULL) {
+        return NULL;
+    }
+    bitset->arraysize = (size + sizeof(uint64_t) * 8 - 1) / (sizeof(uint64_t) * 8);
+    bitset->capacity  = bitset->arraysize;
+    if ((bitset->array = (uint64_t *)calloc(bitset->arraysize, sizeof(uint64_t))) == NULL) {
+        free(bitset);
+        return NULL;
+    }
+    return bitset;
+}
+
+/* Create a copy */
+bitset_t *bitset_copy(const bitset_t *bitset) {
+    bitset_t *copy = NULL;
+    /* Allocate the bitset itself. */
+    if ((copy = (bitset_t *)malloc(sizeof(bitset_t))) == NULL) {
+        return NULL;
+    }
+    memcpy(copy, bitset, sizeof(bitset_t));
+    copy->capacity = copy->arraysize;
+    if ((copy->array = (uint64_t *)malloc(sizeof(uint64_t) * bitset->arraysize)) == NULL) {
+        free(copy);
+        return NULL;
+    }
+    memcpy(copy->array, bitset->array, sizeof(uint64_t) * bitset->arraysize);
+    return copy;
+}
+
+void bitset_clear(bitset_t *bitset) {
+    memset(bitset->array, 0, sizeof(uint64_t) * bitset->arraysize);
+}
+
+void bitset_shift_left(bitset_t *bitset, size_t s) {
+    size_t extra_words  = s / 64;
+    int    inword_shift = (int)(s % 64);
+    size_t as           = bitset->arraysize;
+    if (inword_shift == 0) {
+        bitset_resize(bitset, as + extra_words, FALSE);
+        // could be done with a memmove
+        for (size_t i = as + extra_words; i > extra_words; i--) {
+            bitset->array[i - 1] = bitset->array[i - 1 - extra_words];
+        }
+    } else {
+        bitset_resize(bitset, as + extra_words + 1, TRUE);
+        bitset->array[as + extra_words] = bitset->array[as - 1] >> (64 - inword_shift);
+        for (size_t i = as + extra_words; i >= extra_words + 2; i--) {
+            bitset->array[i - 1] = (bitset->array[i - 1 - extra_words] << inword_shift) |
+                (bitset->array[i - 2 - extra_words] >> (64 - inword_shift));
+        }
+        bitset->array[extra_words] = bitset->array[0] << inword_shift;
+    }
+    for (size_t i = 0; i < extra_words; i++) {
+        bitset->array[i] = 0;
+    }
+}
+
+void bitset_shift_right(bitset_t *bitset, size_t s) {
+    size_t extra_words  = s / 64;
+    int    inword_shift = (int)(s % 64);
+    size_t as           = bitset->arraysize;
+    if (inword_shift == 0) {
+        // could be done with a memmove
+        for (size_t i = 0; i < as - extra_words; i++) {
+            bitset->array[i] = bitset->array[i + extra_words];
+        }
+        bitset_resize(bitset, as - extra_words, FALSE);
+
+    } else {
+        for (size_t i = 0; i + extra_words + 1 < as; i++) {
+            bitset->array[i] = (bitset->array[i + extra_words] >> inword_shift) |
+                (bitset->array[i + extra_words + 1] << (64 - inword_shift));
+        }
+        bitset->array[as - extra_words - 1] = (bitset->array[as - 1] >> inword_shift);
+        bitset_resize(bitset, as - extra_words, FALSE);
+    }
+}
+
+/* Free memory. */
+void bitset_free(bitset_t *bitset) {
+    free(bitset->array);
+    free(bitset);
+}
+
+/* Resize the bitset so that it can support newarraysize * 64 bits. Return TRUE in case of success, FALSE for failure. */
+int bitset_resize(bitset_t *bitset, size_t newarraysize, int padwithzeroes) {
+    size_t smallest = newarraysize < bitset->arraysize ? newarraysize : bitset->arraysize;
+    if (bitset->capacity < newarraysize) {
+        uint64_t *newarray;
+        bitset->capacity = newarraysize * 2;
+        if ((newarray = (uint64_t *)realloc(bitset->array, sizeof(uint64_t) * bitset->capacity)) == NULL) {
+            free(bitset->array);
+            return FALSE;
+        }
+        bitset->array = newarray;
+    }
+    if (padwithzeroes && (newarraysize > smallest)) {
+        memset(bitset->array + smallest, 0, sizeof(uint64_t) * (newarraysize - smallest));
+    }
+    bitset->arraysize = newarraysize;
+    return TRUE;    // success!
+}
+
+size_t bitset_count(const bitset_t *bitset) {
+    size_t card = 0;
+    size_t k    = 0;
+    // assumes that long long is 8 bytes
+    for (; k + 7 < bitset->arraysize; k += 8) {
+        card += __builtin_popcountll(bitset->array[k]);
+        card += __builtin_popcountll(bitset->array[k + 1]);
+        card += __builtin_popcountll(bitset->array[k + 2]);
+        card += __builtin_popcountll(bitset->array[k + 3]);
+        card += __builtin_popcountll(bitset->array[k + 4]);
+        card += __builtin_popcountll(bitset->array[k + 5]);
+        card += __builtin_popcountll(bitset->array[k + 6]);
+        card += __builtin_popcountll(bitset->array[k + 7]);
+    }
+    for (; k + 3 < bitset->arraysize; k += 4) {
+        card += __builtin_popcountll(bitset->array[k]);
+        card += __builtin_popcountll(bitset->array[k + 1]);
+        card += __builtin_popcountll(bitset->array[k + 2]);
+        card += __builtin_popcountll(bitset->array[k + 3]);
+    }
+    for (; k < bitset->arraysize; k++) {
+        card += __builtin_popcountll(bitset->array[k]);
+    }
+    return card;
+}
+
+int bitset_inplace_union(bitset_t *CBITSET_RESTRICT b1, const bitset_t *CBITSET_RESTRICT b2) {
+    size_t minlength = b1->arraysize < b2->arraysize ? b1->arraysize : b2->arraysize;
+    for (size_t k = 0; k < minlength; ++k) {
+        b1->array[k] |= b2->array[k];
+    }
+    if (b2->arraysize > b1->arraysize) {
+        size_t oldsize = b1->arraysize;
+        if (!bitset_resize(b1, b2->arraysize, FALSE)) {
+            return FALSE;
+        }
+        memcpy(b1->array + oldsize, b2->array + oldsize, (b2->arraysize - oldsize) * sizeof(uint64_t));
+    }
+    return TRUE;
+}
+
+size_t bitset_minimum(const bitset_t *bitset) {
+    for (size_t k = 0; k < bitset->arraysize; k++) {
+        uint64_t w = bitset->array[k];
+        if (w != 0) {
+            return __builtin_ctzll(w) + k * 64;
+        }
+    }
+    return 0;
+}
+
+size_t bitset_maximum(const bitset_t *bitset) {
+    for (size_t k = bitset->arraysize; k > 0; k--) {
+        uint64_t w = bitset->array[k - 1];
+        if (w != 0) {
+            return 63 - __builtin_clzll(w) + (k - 1) * 64;
+        }
+    }
+    return 0;
+}
+
+/* Returns TRUE if bitsets share no common elements, FALSE otherwise.
+ *
+ * Performs early-out if common element found. */
+int bitsets_disjoint(const bitset_t *b1, const bitset_t *b2) {
+    size_t minlength = b1->arraysize < b2->arraysize ? b1->arraysize : b2->arraysize;
+
+    for (size_t k = 0; k < minlength; k++) {
+        if ((b1->array[k] & b2->array[k]) != 0) {
+            return FALSE;
+        }
+    }
+    return TRUE;
+}
+
+/* Returns TRUE if bitsets contain at least 1 common element, FALSE if they are
+ * disjoint.
+ *
+ * Performs early-out if common element found. */
+int bitsets_intersect(const bitset_t *b1, const bitset_t *b2) {
+    size_t minlength = b1->arraysize < b2->arraysize ? b1->arraysize : b2->arraysize;
+
+    for (size_t k = 0; k < minlength; k++) {
+        if ((b1->array[k] & b2->array[k]) != 0) {
+            return TRUE;
+        }
+    }
+    return FALSE;
+}
+
+/* Returns TRUE if b has any bits set in or after b->array[starting_loc]. */
+static int any_bits_set(const bitset_t *b, size_t starting_loc) {
+    if (starting_loc >= b->arraysize) {
+        return FALSE;
+    }
+    for (size_t k = starting_loc; k < b->arraysize; k++) {
+        if (b->array[k] != 0) {
+            return TRUE;
+        }
+    }
+    return FALSE;
+}
+
+/* Returns TRUE if b1 has all of b2's bits set.
+ *
+ * Performs early out if a bit is found in b2 that is not found in b1. */
+int bitset_contains_all(const bitset_t *b1, const bitset_t *b2) {
+    for (size_t k = 0; k < b1->arraysize; k++) {
+        if ((b1->array[k] & b2->array[k]) != b2->array[k]) {
+            return FALSE;
+        }
+    }
+    if (b2->arraysize > b1->arraysize) {
+        /* Need to check if b2 has any bits set beyond b1's array */
+        return !any_bits_set(b2, b1->arraysize);
+    }
+    return TRUE;
+}
+
+size_t bitset_union_count(const bitset_t *CBITSET_RESTRICT b1, const bitset_t *CBITSET_RESTRICT b2) {
+    size_t answer    = 0;
+    size_t minlength = b1->arraysize < b2->arraysize ? b1->arraysize : b2->arraysize;
+    size_t k         = 0;
+    for (; k + 3 < minlength; k += 4) {
+        answer += __builtin_popcountll(b1->array[k] | b2->array[k]);
+        answer += __builtin_popcountll(b1->array[k + 1] | b2->array[k + 1]);
+        answer += __builtin_popcountll(b1->array[k + 2] | b2->array[k + 2]);
+        answer += __builtin_popcountll(b1->array[k + 3] | b2->array[k + 3]);
+    }
+    for (; k < minlength; ++k) {
+        answer += __builtin_popcountll(b1->array[k] | b2->array[k]);
+    }
+    if (b2->arraysize > b1->arraysize) {
+        //k = b1->arraysize;
+        for (; k + 3 < b2->arraysize; k += 4) {
+            answer += __builtin_popcountll(b2->array[k]);
+            answer += __builtin_popcountll(b2->array[k + 1]);
+            answer += __builtin_popcountll(b2->array[k + 2]);
+            answer += __builtin_popcountll(b2->array[k + 3]);
+        }
+        for (; k < b2->arraysize; ++k) {
+            answer += __builtin_popcountll(b2->array[k]);
+        }
+    } else {
+        //k = b2->arraysize;
+        for (; k + 3 < b1->arraysize; k += 4) {
+            answer += __builtin_popcountll(b1->array[k]);
+            answer += __builtin_popcountll(b1->array[k + 1]);
+            answer += __builtin_popcountll(b1->array[k + 2]);
+            answer += __builtin_popcountll(b1->array[k + 3]);
+        }
+        for (; k < b1->arraysize; ++k) {
+            answer += __builtin_popcountll(b1->array[k]);
+        }
+    }
+    return answer;
+}
+
+void bitset_inplace_intersection(bitset_t *CBITSET_RESTRICT b1, const bitset_t *CBITSET_RESTRICT b2) {
+    size_t minlength = b1->arraysize < b2->arraysize ? b1->arraysize : b2->arraysize;
+    size_t k         = 0;
+    for (; k < minlength; ++k) {
+        b1->array[k] &= b2->array[k];
+    }
+    for (; k < b1->arraysize; ++k) {
+        b1->array[k] = 0;    // memset could, maybe, be a tiny bit faster
+    }
+}
+
+size_t bitset_intersection_count(const bitset_t *CBITSET_RESTRICT b1, const bitset_t *CBITSET_RESTRICT b2) {
+    size_t answer    = 0;
+    size_t minlength = b1->arraysize < b2->arraysize ? b1->arraysize : b2->arraysize;
+    for (size_t k = 0; k < minlength; ++k) {
+        answer += __builtin_popcountll(b1->array[k] & b2->array[k]);
+    }
+    return answer;
+}
+
+void bitset_inplace_difference(bitset_t *CBITSET_RESTRICT b1, const bitset_t *CBITSET_RESTRICT b2) {
+    size_t minlength = b1->arraysize < b2->arraysize ? b1->arraysize : b2->arraysize;
+    size_t k         = 0;
+    for (; k < minlength; ++k) {
+        b1->array[k] &= ~(b2->array[k]);
+    }
+}
+
+size_t bitset_difference_count(const bitset_t *CBITSET_RESTRICT b1, const bitset_t *CBITSET_RESTRICT b2) {
+    size_t minlength = b1->arraysize < b2->arraysize ? b1->arraysize : b2->arraysize;
+    size_t k         = 0;
+    size_t answer    = 0;
+    for (; k < minlength; ++k) {
+        answer += __builtin_popcountll(b1->array[k] & ~(b2->array[k]));
+    }
+    for (; k < b1->arraysize; ++k) {
+        answer += __builtin_popcountll(b1->array[k]);
+    }
+    return answer;
+}
+
+int bitset_inplace_symmetric_difference(bitset_t *CBITSET_RESTRICT b1, const bitset_t *CBITSET_RESTRICT b2) {
+    size_t minlength = b1->arraysize < b2->arraysize ? b1->arraysize : b2->arraysize;
+    size_t k         = 0;
+    for (; k < minlength; ++k) {
+        b1->array[k] ^= b2->array[k];
+    }
+    if (b2->arraysize > b1->arraysize) {
+        size_t oldsize = b1->arraysize;
+        if (!bitset_resize(b1, b2->arraysize, FALSE)) {
+            return FALSE;
+        }
+        memcpy(b1->array + oldsize, b2->array + oldsize, (b2->arraysize - oldsize) * sizeof(uint64_t));
+    }
+    return TRUE;
+}
+
+size_t bitset_symmetric_difference_count(const bitset_t *CBITSET_RESTRICT b1, const bitset_t *CBITSET_RESTRICT b2) {
+    size_t minlength = b1->arraysize < b2->arraysize ? b1->arraysize : b2->arraysize;
+    size_t k         = 0;
+    size_t answer    = 0;
+    for (; k < minlength; ++k) {
+        answer += __builtin_popcountll(b1->array[k] ^ b2->array[k]);
+    }
+    if (b2->arraysize > b1->arraysize) {
+        for (; k < b2->arraysize; ++k) {
+            answer += __builtin_popcountll(b2->array[k]);
+        }
+    } else {
+        for (; k < b1->arraysize; ++k) {
+            answer += __builtin_popcountll(b1->array[k]);
+        }
+    }
+    return answer;
+}
+
+int bitset_trim(bitset_t *bitset) {
+    size_t newsize = bitset->arraysize;
+    while (newsize > 0) {
+        if (bitset->array[newsize - 1] == 0) {
+            newsize -= 1;
+        } else {
+            break;
+        }
+    }
+    if (bitset->capacity == newsize) {
+        return TRUE;    // nothing to do
+    }
+    bitset->capacity  = newsize;
+    bitset->arraysize = newsize;
+    uint64_t *newarray;
+    if ((newarray = (uint64_t *)realloc(bitset->array, sizeof(uint64_t) * bitset->capacity)) == NULL) {
+        free(bitset->array);
+        return FALSE;
+    }
+    bitset->array = newarray;
+    return TRUE;
+}
diff --git a/srcs/libs/database/database.c b/srcs/libs/database/database.c
new file mode 100644
index 0000000..f0e6937
--- /dev/null
+++ b/srcs/libs/database/database.c
@@ -0,0 +1,63 @@
+//
+// Created by xajhuang on 2023/3/29.
+//
+#ifdef SQLITE_ON
+#include <sqlite3.h>
+#include <string.h>
+#include "zlog_module.h"
+#include "user_errno.h"
+#include "config.h"
+#include "database.h"
+
+static sqlite3 *g_pSqlHandle = NULL;
+
+int db_sqlite3_init() {
+    int         rc;
+    const char *pDbPath = cfg_get_sqlite_db_name();
+
+    if (pDbPath == NULL || strlen(pDbPath) == 0) {
+        return ERR_SUCCESS;
+    }
+
+    if (g_pSqlHandle == NULL) {
+        rc = sqlite3_open_v2(pDbPath, &g_pSqlHandle, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, NULL);
+
+        if (rc != SQLITE_OK) {
+            LOG_MOD(error, ZLOG_MOD_DB, "Create SQLite3 Database at %s error: %s(%d)\n", pDbPath, sqlite3_errstr(rc), rc);
+            return -ERR_DB_CONNECT;
+        }
+    }
+
+    LOG_MOD(info, ZLOG_MOD_DB, "Used SQLite3 database: %s\n", pDbPath);
+
+    return ERR_SUCCESS;
+}
+
+int db_sqlite3_sql_exec(const char *pSqlCmd, void *pCallback, void *pData, char **pErr) {
+
+    if (pSqlCmd == NULL || strlen(pSqlCmd) == 0) {
+        LOG_MOD(error, ZLOG_MOD_DB, "Input params pSqlCmd error\n");
+        return -ERR_INPUT_PARAMS;
+    }
+
+    if (g_pSqlHandle) {
+        int rc = sqlite3_exec(g_pSqlHandle, pSqlCmd, pCallback, pData, pErr);
+
+        if (rc != SQLITE_OK) {
+            LOG_MOD(error, ZLOG_MOD_DB, "Run {%s} SQL command error:\n%s\n", pSqlCmd, sqlite3_errmsg(g_pSqlHandle));
+            return -ERR_DB_SQL_EXEC;
+        }
+
+        return ERR_SUCCESS;
+    } else {
+        LOG_MOD(error, ZLOG_MOD_DB, "SQlite3 database uninit\n");
+        return -ERR_DB_UNINIT;
+    }
+}
+
+void db_sqlite3_uninit() {
+    if (g_pSqlHandle) {
+        sqlite3_close(g_pSqlHandle);
+    }
+}
+#endif
\ No newline at end of file
diff --git a/srcs/libs/include/bitset/bitset.h b/srcs/libs/include/bitset/bitset.h
new file mode 100644
index 0000000..6b0f1ea
--- /dev/null
+++ b/srcs/libs/include/bitset/bitset.h
@@ -0,0 +1,271 @@
+//
+// Created by xajhuang on 2023/4/6.
+//
+
+#ifndef VCPE_BITSET_H
+#define VCPE_BITSET_H
+#include <common.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+// For compatibility with MSVC with the use of `restrict`
+#if (__STDC_VERSION__ >= 199901L) || (defined(__GNUC__) && defined(__STDC_VERSION__))
+#define CBITSET_RESTRICT restrict
+#else
+#define CBITSET_RESTRICT
+#endif    // (__STDC_VERSION__ >= 199901L) || (defined(__GNUC__) && defined(__STDC_VERSION__ ))
+
+struct bitset_s {
+    uint64_t *CBITSET_RESTRICT array;
+    size_t                     arraysize;
+    size_t                     capacity;
+};
+
+typedef struct bitset_s bitset_t;
+
+/* Create a new bitset. Return NULL in case of failure. */
+bitset_t *bitset_create(void);
+
+/* Create a new bitset able to contain size bits. Return NULL in case of failure. */
+bitset_t *bitset_create_with_capacity(size_t size);
+
+/* Free memory. */
+void bitset_free(bitset_t *bitset);
+
+/* Set all bits to zero. */
+void bitset_clear(bitset_t *bitset);
+
+/* Create a copy */
+bitset_t *bitset_copy(const bitset_t *bitset);
+
+/* Resize the bitset. Return TRUE in case of success, FALSE for failure. Pad with zeroes new buffer areas if requested. */
+int bitset_resize(bitset_t *bitset, size_t newarraysize, int padwithzeroes);
+
+/* returns how many bytes of memory the backend buffer uses */
+static inline size_t bitset_size_in_bytes(const bitset_t *bitset) {
+    return bitset->arraysize * sizeof(uint64_t);
+}
+
+/* returns how many bits can be accessed */
+static inline size_t bitset_size_in_bits(const bitset_t *bitset) {
+    return bitset->arraysize * 64;
+}
+
+/* returns how many words (64-bit) of memory the backend buffer uses */
+static inline size_t bitset_size_in_words(const bitset_t *bitset) {
+    return bitset->arraysize;
+}
+
+/* Grow the bitset so that it can support newarraysize * 64 bits with padding. Return TRUE in case of success, FALSE for failure. */
+static inline int bitset_grow(bitset_t *bitset, size_t newarraysize) {
+    if (bitset->capacity < newarraysize) {
+        uint64_t *newarray;
+        bitset->capacity = newarraysize * 2;
+        if ((newarray = (uint64_t *)realloc(bitset->array, sizeof(uint64_t) * bitset->capacity)) == NULL) {
+            free(bitset->array);
+            return FALSE;
+        }
+        bitset->array = newarray;
+    }
+    memset(bitset->array + bitset->arraysize, 0, sizeof(uint64_t) * (newarraysize - bitset->arraysize));
+    bitset->arraysize = newarraysize;
+    return TRUE;    // success!
+}
+
+/* attempts to recover unused memory, return FALSE in case of reallocation failure */
+int bitset_trim(bitset_t *bitset);
+
+/* shifts all bits by 's' positions so that the bitset representing values 1,2,10 would represent values 1+s, 2+s, 10+s */
+void bitset_shift_left(bitset_t *bitset, size_t s);
+
+/* shifts all bits by 's' positions so that the bitset representing values 1,2,10 would represent values 1-s, 2-s, 10-s, negative values are deleted */
+void bitset_shift_right(bitset_t *bitset, size_t s);
+
+/* Set the ith bit. Attempts to resize the bitset if needed (may silently fail) */
+static inline void bitset_set(bitset_t *bitset, size_t i) {
+    size_t shiftedi = i >> 6;
+    if (shiftedi >= bitset->arraysize) {
+        if (!bitset_grow(bitset, shiftedi + 1)) {
+            return;
+        }
+    }
+    bitset->array[shiftedi] |= ((uint64_t)1) << (i % 64);
+}
+
+/* Set the ith bit to the specified value. Attempts to resize the bitset if needed (may silently fail) */
+static inline void bitset_set_to_value(bitset_t *bitset, size_t i, int flag) {
+    size_t   shiftedi = i >> 6;
+    uint64_t mask     = ((uint64_t)1) << (i % 64);
+    uint64_t dynmask  = ((uint64_t)flag) << (i % 64);
+    if (shiftedi >= bitset->arraysize) {
+        if (!bitset_grow(bitset, shiftedi + 1)) {
+            return;
+        }
+    }
+    uint64_t w               = bitset->array[shiftedi];
+    w                       &= ~mask;
+    w                       |= dynmask;
+    bitset->array[shiftedi]  = w;
+}
+
+static inline void bitset_cls_bit(bitset_t *bitset, size_t i) {
+    bitset_set_to_value(bitset, i, 0);
+}
+
+/* Get the value of the ith bit.  */
+static inline int bitset_get(const bitset_t *bitset, size_t i) {
+    size_t shiftedi = i >> 6;
+    if (shiftedi >= bitset->arraysize) {
+        return FALSE;
+    }
+    return (bitset->array[shiftedi] & (((uint64_t)1) << (i % 64))) != 0;
+}
+
+/* Count number of bits set.  */
+size_t bitset_count(const bitset_t *bitset);
+
+/* Find the index of the first bit set.  */
+size_t bitset_minimum(const bitset_t *bitset);
+
+/* Find the index of the last bit set.  */
+size_t bitset_maximum(const bitset_t *bitset);
+
+/* compute the union in-place (to b1), returns TRUE if successful, to generate a new bitset first call bitset_copy */
+int bitset_inplace_union(bitset_t *CBITSET_RESTRICT b1, const bitset_t *CBITSET_RESTRICT b2);
+
+/* report the size of the union (without materializing it) */
+size_t bitset_union_count(const bitset_t *CBITSET_RESTRICT b1, const bitset_t *CBITSET_RESTRICT b2);
+
+/* compute the intersection in-place (to b1), to generate a new bitset first call bitset_copy */
+void bitset_inplace_intersection(bitset_t *CBITSET_RESTRICT b1, const bitset_t *CBITSET_RESTRICT b2);
+
+/* report the size of the intersection (without materializing it) */
+size_t bitset_intersection_count(const bitset_t *CBITSET_RESTRICT b1, const bitset_t *CBITSET_RESTRICT b2);
+
+/* returns TRUE if the bitsets contain no common elements */
+int bitsets_disjoint(const bitset_t *b1, const bitset_t *b2);
+
+/* returns TRUE if the bitsets contain any common elements */
+int bitsets_intersect(const bitset_t *b1, const bitset_t *b2);
+
+/* returns TRUE if b1 contains all the set bits of b2 */
+int bitset_contains_all(const bitset_t *b1, const bitset_t *b2);
+
+/* compute the difference in-place (to b1), to generate a new bitset first call bitset_copy */
+void bitset_inplace_difference(bitset_t *CBITSET_RESTRICT b1, const bitset_t *CBITSET_RESTRICT b2);
+
+/* compute the size of the difference */
+size_t bitset_difference_count(const bitset_t *CBITSET_RESTRICT b1, const bitset_t *CBITSET_RESTRICT b2);
+
+/* compute the symmetric difference in-place (to b1), return TRUE if successful, to generate a new bitset first call bitset_copy */
+int bitset_inplace_symmetric_difference(bitset_t *CBITSET_RESTRICT b1, const bitset_t *CBITSET_RESTRICT b2);
+
+/* compute the size of the symmetric difference  */
+size_t bitset_symmetric_difference_count(const bitset_t *CBITSET_RESTRICT b1, const bitset_t *CBITSET_RESTRICT b2);
+
+/* iterate over the set bits
+ like so :
+  for(size_t i = 0; nextSetBit(b,&i) ; i++) {
+    //.....
+  }
+  */
+static inline int nextSetBit(const bitset_t *bitset, size_t *i) {
+    size_t x = *i >> 6;
+    if (x >= bitset->arraysize) {
+        return FALSE;
+    }
+    uint64_t w   = bitset->array[x];
+    w          >>= (*i & 63);
+    if (w != 0) {
+        *i += __builtin_ctzll(w);
+        return TRUE;
+    }
+    x++;
+    while (x < bitset->arraysize) {
+        w = bitset->array[x];
+        if (w != 0) {
+            *i = x * 64 + __builtin_ctzll(w);
+            return TRUE;
+        }
+        x++;
+    }
+    return FALSE;
+}
+
+/* Iterate over the set bits
+ like so :
+   size_t buffer[256];
+   size_t howmany = 0;
+  for(size_t startfrom = 0; (howmany = nextSetBits(b,buffer,256, &startfrom)) > 0 ; startfrom++) {
+    //.....
+  }
+  */
+static inline size_t nextSetBits(const bitset_t *bitset, size_t *buffer, size_t capacity, size_t *startfrom) {
+    if (capacity == 0) {
+        return 0;    // sanity check
+    }
+    size_t x = *startfrom >> 6;
+    if (x >= bitset->arraysize) {
+        return 0;    // nothing more to iterate over
+    }
+    uint64_t w       = bitset->array[x];
+    w              >>= (*startfrom & 63);
+    size_t howmany   = 0;
+    size_t base      = x << 6;
+    while (howmany < capacity) {
+        while (w != 0) {
+            uint64_t t        = w & (~w + 1);
+            int      r        = __builtin_ctzll(w);
+            buffer[howmany++] = r + base;
+            if (howmany == capacity) {
+                goto end;
+            }
+            w ^= t;
+        }
+        x += 1;
+        if (x == bitset->arraysize) {
+            break;
+        }
+        base += 64;
+        w     = bitset->array[x];
+    }
+end:
+    if (howmany > 0) {
+        *startfrom = buffer[howmany - 1];
+    }
+    return howmany;
+}
+
+typedef int (*bitset_iterator)(size_t value, void *param);
+
+// return TRUE if uninterrupted
+static inline int bitset_for_each(const bitset_t *b, bitset_iterator iterator, void *ptr) {
+    size_t base = 0;
+    for (size_t i = 0; i < b->arraysize; ++i) {
+        uint64_t w = b->array[i];
+        while (w != 0) {
+            uint64_t t = w & (~w + 1);
+            int      r = __builtin_ctzll(w);
+            if (!iterator(r + base, ptr)) {
+                return FALSE;
+            }
+            w ^= t;
+        }
+        base += 64;
+    }
+    return TRUE;
+}
+
+//static inline void bitset_print(const bitset_t *b) {
+//    printf("{");
+//    for (size_t i = 0; nextSetBit(b, &i); i++) {
+//        printf("%zu, ", i);
+//    }
+//    printf("}");
+//}
+
+#ifdef __cplusplus
+}
+#endif
+#endif    //VCPE_BITSET_H
diff --git a/srcs/libs/include/common.h b/srcs/libs/include/common.h
index 394c92c..6bbc73d 100644
--- a/srcs/libs/include/common.h
+++ b/srcs/libs/include/common.h
@@ -11,6 +11,26 @@ extern "C" {
 #define _STR(s) #s
 #define STR(s)  _STR(s)
 
+#ifndef MIN
+#define MIN(a, b)                                  \
+    ({                                             \
+        typeof(a) __min1__ = (a);                  \
+        typeof(b) __min2__ = (b);                  \
+        (void)(&__min1__ == &__min2__);            \
+        __min1__ < __min2__ ? __min1__ : __min2__; \
+    })
+#endif
+
+#ifndef MAX
+#define MAX(a, b)                                  \
+    ({                                             \
+        typeof(a) __max1__ = (a);                  \
+        typeof(b) __max2__ = (b);                  \
+        (void)(&__max1__ == &__max2__);            \
+        __max1__ < __max2__ ? __max1__ : __max2__; \
+    })
+#endif
+
 #ifndef ARRAY_SIZE
 //#ifdef __cplusplus
 #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
@@ -48,11 +68,10 @@ typedef unsigned char      U8;
 typedef unsigned short     U16;
 typedef unsigned int       U32;
 typedef unsigned long long U64;
-
-typedef char      S8;
-typedef short     S16;
-typedef int       S32;
-typedef long long S64;
+typedef char               S8;
+typedef short              S16;
+typedef int                S32;
+typedef long long          S64;
 
 #ifdef __cplusplus
 }
diff --git a/srcs/libs/include/database.h b/srcs/libs/include/database.h
index ac0a096..006752c 100644
--- a/srcs/libs/include/database.h
+++ b/srcs/libs/include/database.h
@@ -8,10 +8,9 @@
 extern "C" {
 #endif
 
-int   db_redis_init(void);
-int   db_mysql_init(void);
-void *get_mysql_handle();
-void  db_mysql_uninit();
+int  db_sqlite3_init();
+void db_sqlite3_uninit();
+int  db_sqlite3_sql_exec(const char *pSqlCmd, void *pCallback, void *pData, char **pErr);
 #ifdef __cplusplus
 }
 #endif
diff --git a/srcs/libs/include/ipaddr.h b/srcs/libs/include/ipaddr.h
index 6ec499c..b35e4e7 100644
--- a/srcs/libs/include/ipaddr.h
+++ b/srcs/libs/include/ipaddr.h
@@ -4,10 +4,13 @@
 
 #ifndef VCPE_IPADDR_H
 #define VCPE_IPADDR_H
+#include "common.h"
 #ifdef __cplusplus
 extern "C" {
 #endif
-
+U32 ipv4_get_network_addr(U32 ipAddr, U32 netmask);
+U32 ipv4_get_boardcast_addr(U32 ipAddr, U32 netmask);
+U32 ipv4_network_total_addr(U32 netmask);
 #ifdef __cplusplus
 }
 #endif
diff --git a/srcs/libs/include/user_errno.h b/srcs/libs/include/user_errno.h
index c552535..2caf25d 100644
--- a/srcs/libs/include/user_errno.h
+++ b/srcs/libs/include/user_errno.h
@@ -8,67 +8,71 @@
 extern "C" {
 #endif
 
-#define DEF_ERR_CODE(ERR_CODE)                                      \
-    ERR_CODE(ERR_SUCCESS, 0, "成功")                                \
-    ERR_CODE(ERR_INPUT_PARAMS, 1, "输入参数错误")                   \
-    ERR_CODE(ERR_UN_SUPPORT, 2, "不支持的操作")                     \
-    ERR_CODE(ERR_CALL_SHELL, 3, "调用Shell命令失败")                \
-    ERR_CODE(ERR_ITEM_EXISTS, 4, "该内容已经存在")                  \
-    ERR_CODE(ERR_ITEM_UNEXISTS, 5, "该内容不存在")                  \
-    ERR_CODE(ERR_SYS_INIT, 6, "系统中断")                           \
-    ERR_CODE(ERR_SYS_CALL, 7, "系统调用")                           \
-    ERR_CODE(ERR_OPEN_FILE, 8, "打开文件失败")                      \
-    ERR_CODE(ERR_READ_FILE, 9, "读取文件失败")                      \
-    ERR_CODE(ERR_FILE_NOT_EXISTS, 10, "文件不存在")                 \
-    ERR_CODE(ERR_FILE_LOCKED, 11, "文件被锁定")                     \
-    ERR_CODE(ERR_GET_FILE_SIZE, 12, "获取文件大小失败")             \
-    ERR_CODE(ERR_COPY_FILE, 13, "复制文件失败")                     \
-    ERR_CODE(ERR_MALLOC_MEMORY, 14, "分配内存失败")                 \
-    ERR_CODE(ERR_MMAP_MEMORY, 15, "共享内存失败")                   \
-    ERR_CODE(ERR_EVP_KEY_SIZE, 16, "秘钥大小不正确")                \
-    ERR_CODE(ERR_UNSUP_EVP_TYPE, 17, "不支持的加解密算法")          \
-    ERR_CODE(ERR_EVP_INIT_KEY, 18, "初始化秘钥失败")                \
-    ERR_CODE(ERR_EVP_UPDATE, 19, "加解密数据失败")                  \
-    ERR_CODE(ERR_EVP_FINALE, 20, "错误的加解密结果")                \
-    ERR_CODE(ERR_EVP_CREATE_CTX, 21, "初始化加解密失败")            \
-    ERR_CODE(ERR_AES_KEYGEN, 22, "AES秘钥失败")                     \
-    ERR_CODE(ERR_EVP_ENCRYPTION, 23, "加密失败")                    \
-    ERR_CODE(ERR_EVP_DECRYPTION, 24, "解密失败")                    \
-    ERR_CODE(ERR_CONFIG_INIT, 25, "配置文件初始化失败")             \
-    ERR_CODE(ERR_UNCOMPATIBILITY_TYPE, 26, "未兼容的类型")          \
-    ERR_CODE(ERR_STRING_TO_NUMBER, 27, "字符串转数字失败")          \
-    ERR_CODE(ERR_UNKNOWN_CFG_ID, 28, "未识别的配置项")              \
-    ERR_CODE(ERR_ZLOG_INIT, 29, "日志系统初始化失败")               \
-    ERR_CODE(ERR_SYS_GET_CPU_INFO, 30, "获取CPU信息失败")           \
-    ERR_CODE(ERR_SYS_NOT_FOUND_CPU, 31, "找不到CPU信息")            \
-    ERR_CODE(ERR_SYS_DISK_GET_INFO, 32, "获取磁盘空间占用信息失败") \
-    ERR_CODE(ERR_SYS_IPMI_UNSUP, 33, "服务器IPMI接口不支持")        \
-    ERR_CODE(ERR_SYS_SENSOR_GET_INFO, 34, "获取传感器信息失败")     \
-    ERR_CODE(ERR_DB_CONNECT, 35, "数据库连接失败")                  \
-    ERR_CODE(ERR_MQ_CREATE_MQ, 36, "创建消息队列失败")              \
-    ERR_CODE(ERR_MQ_CREATE_REP, 37, "创建REP消息队列失败")          \
-    ERR_CODE(ERR_MQ_BIND_SOCKET, 38, "消息队列BIND Socket失败")     \
-    ERR_CODE(ERR_MQ_CONN_SERVER, 39, "消息队列连接服务器失败")      \
-    ERR_CODE(ERR_MQ_SEND_MSG, 40, "消息队列发送消息失败")           \
-    ERR_CODE(ERR_JSON_CREAT_OBJ, 41, "创建JSON对象失败")            \
-    ERR_CODE(ERR_JSON_PARSE_OBJ, 42, "解析JSON对象失败")            \
-    ERR_CODE(ERR_JSON_VALID_SCH, 43, "JSON数据验证失败")            \
-    ERR_CODE(ERR_CREATE_NETIF, 44, "创建网络接口失败")              \
-    ERR_CODE(ERR_CREATE_PPPOE_NETIF, 45, "创建PPPoE网络接口失败")   \
-    ERR_CODE(ERR_CREATE_PPP_SESSION, 46, "创建PPP连接失败")         \
-    ERR_CODE(ERR_MISC_GET_IPADDR, 47, "获取网卡IP地址失败")         \
-    ERR_CODE(ERR_MISC_GET_NETMASK, 48, "获取网卡子网掩码失败")      \
-    ERR_CODE(ERR_MISC_GET_GATEWAY, 49, "获取网卡网关地址失败")      \
-    ERR_CODE(ERR_MISC_GET_MACADDR, 50, "获取网卡MAC地址失败")       \
-    ERR_CODE(ERR_MENU_EXIT, 51, "菜单执行完后自动退出")             \
-    ERR_CODE(ERR_HTTP_UNSUP_METHOD, 52, "不支持的 HTTP 请求方法")   \
-    ERR_CODE(ERR_HTTP_UNSUP_PAGE, 53, "找不到 HTTP 服务")           \
-    ERR_CODE(ERR_PROTO_DECODE, 54, "HTTP 协议解析失败")             \
-    ERR_CODE(ERR_MSG_CONTENT, 55, "msgContent内容不正确")           \
-    ERR_CODE(ERR_SOCK_CREATE, 56, "创建套接字失败")                 \
-    ERR_CODE(ERR_SOCK_SETOPT, 57, "设置套接字参数失败")
+#define DEF_ERR_CODE(ERR_CODE)                                  \
+    ERR_CODE(ERR_SUCCESS, "成功")                               \
+    ERR_CODE(ERR_INPUT_PARAMS, "输入参数错误")                  \
+    ERR_CODE(ERR_UN_SUPPORT, "不支持的操作")                    \
+    ERR_CODE(ERR_CALL_SHELL, "调用Shell命令失败")               \
+    ERR_CODE(ERR_ITEM_EXISTS, "该内容已经存在")                 \
+    ERR_CODE(ERR_ITEM_UNEXISTS, "该内容不存在")                 \
+    ERR_CODE(ERR_SYS_INIT, "系统中断")                          \
+    ERR_CODE(ERR_SYS_CALL, "系统调用")                          \
+    ERR_CODE(ERR_OPEN_FILE, "打开文件失败")                     \
+    ERR_CODE(ERR_READ_FILE, "读取文件失败")                     \
+    ERR_CODE(ERR_FILE_NOT_EXISTS, "文件不存在")                 \
+    ERR_CODE(ERR_FILE_LOCKED, "文件被锁定")                     \
+    ERR_CODE(ERR_GET_FILE_SIZE, "获取文件大小失败")             \
+    ERR_CODE(ERR_COPY_FILE, "复制文件失败")                     \
+    ERR_CODE(ERR_MALLOC_MEMORY, "分配内存失败")                 \
+    ERR_CODE(ERR_MMAP_MEMORY, "共享内存失败")                   \
+    ERR_CODE(ERR_EVP_KEY_SIZE, "秘钥大小不正确")                \
+    ERR_CODE(ERR_UNSUP_EVP_TYPE, "不支持的加解密算法")          \
+    ERR_CODE(ERR_EVP_INIT_KEY, "初始化秘钥失败")                \
+    ERR_CODE(ERR_EVP_UPDATE, "加解密数据失败")                  \
+    ERR_CODE(ERR_EVP_FINALE, "错误的加解密结果")                \
+    ERR_CODE(ERR_EVP_CREATE_CTX, "初始化加解密失败")            \
+    ERR_CODE(ERR_AES_KEYGEN, "AES秘钥失败")                     \
+    ERR_CODE(ERR_EVP_ENCRYPTION, "加密失败")                    \
+    ERR_CODE(ERR_EVP_DECRYPTION, "解密失败")                    \
+    ERR_CODE(ERR_CONFIG_INIT, "配置文件初始化失败")             \
+    ERR_CODE(ERR_UNCOMPATIBILITY_TYPE, "未兼容的类型")          \
+    ERR_CODE(ERR_STRING_TO_NUMBER, "字符串转数字失败")          \
+    ERR_CODE(ERR_UNKNOWN_CFG_ID, "未识别的配置项")              \
+    ERR_CODE(ERR_ZLOG_INIT, "日志系统初始化失败")               \
+    ERR_CODE(ERR_SYS_GET_CPU_INFO, "获取CPU信息失败")           \
+    ERR_CODE(ERR_SYS_NOT_FOUND_CPU, "找不到CPU信息")            \
+    ERR_CODE(ERR_SYS_DISK_GET_INFO, "获取磁盘空间占用信息失败") \
+    ERR_CODE(ERR_SYS_IPMI_UNSUP, "服务器IPMI接口不支持")        \
+    ERR_CODE(ERR_SYS_SENSOR_GET_INFO, "获取传感器信息失败")     \
+    ERR_CODE(ERR_DB_UNINIT, "数据库未连接")                     \
+    ERR_CODE(ERR_DB_CONNECT, "数据库连接失败")                  \
+    ERR_CODE(ERR_DB_SQL_EXEC, "数据库SQL命令执行失败")          \
+    ERR_CODE(ERR_MQ_CREATE_MQ, "创建消息队列失败")              \
+    ERR_CODE(ERR_MQ_CREATE_REP, "创建REP消息队列失败")          \
+    ERR_CODE(ERR_MQ_BIND_SOCKET, "消息队列BIND Socket失败")     \
+    ERR_CODE(ERR_MQ_CONN_SERVER, "消息队列连接服务器失败")      \
+    ERR_CODE(ERR_MQ_SEND_MSG, "消息队列发送消息失败")           \
+    ERR_CODE(ERR_JSON_CREAT_OBJ, "创建JSON对象失败")            \
+    ERR_CODE(ERR_JSON_PARSE_OBJ, "解析JSON对象失败")            \
+    ERR_CODE(ERR_JSON_VALID_SCH, "JSON数据验证失败")            \
+    ERR_CODE(ERR_CREATE_NETIF, "创建网络接口失败")              \
+    ERR_CODE(ERR_CREATE_PPPOE_NETIF, "创建PPPoE网络接口失败")   \
+    ERR_CODE(ERR_CREATE_PPP_SESSION, "创建PPP连接失败")         \
+    ERR_CODE(ERR_MISC_GET_IPADDR, "获取网卡IP地址失败")         \
+    ERR_CODE(ERR_MISC_GET_NETMASK, "获取网卡子网掩码失败")      \
+    ERR_CODE(ERR_MISC_GET_GATEWAY, "获取网卡网关地址失败")      \
+    ERR_CODE(ERR_MISC_GET_MACADDR, "获取网卡MAC地址失败")       \
+    ERR_CODE(ERR_MENU_EXIT, "菜单执行完后自动退出")             \
+    ERR_CODE(ERR_HTTP_UNSUP_METHOD, "不支持的 HTTP 请求方法")   \
+    ERR_CODE(ERR_HTTP_UNSUP_PAGE, "找不到 HTTP 服务")           \
+    ERR_CODE(ERR_PROTO_DECODE, "HTTP 协议解析失败")             \
+    ERR_CODE(ERR_MSG_CONTENT, "msgContent内容不正确")           \
+    ERR_CODE(ERR_DHCP_NO_POOL, "找不到可用地址池")              \
+    ERR_CODE(ERR_DHCP_NO_ADDR, "找不到可用IP地址")              \
+    ERR_CODE(ERR_SOCK_CREATE, "创建套接字失败")                 \
+    ERR_CODE(ERR_SOCK_SETOPT, "设置套接字参数失败")
 
-#define GENERATE_ENUM(ENUM, no, x) ENUM,
+#define GENERATE_ENUM(ENUM, x) ENUM,
 
 typedef enum {
     DEF_ERR_CODE(GENERATE_ENUM)
diff --git a/srcs/libs/include/zlog_module.h b/srcs/libs/include/zlog_module.h
index de9e6a7..94f86d1 100644
--- a/srcs/libs/include/zlog_module.h
+++ b/srcs/libs/include/zlog_module.h
@@ -7,6 +7,7 @@
 #ifdef __cplusplus
 extern "C" {
 #endif
+
 #include <zlog.h>
 
 enum {
@@ -14,13 +15,13 @@ enum {
 };
 
 typedef enum {
-    trace  = ZLOG_LEVEL_TRACE,
-    debug  = ZLOG_LEVEL_DEBUG,
-    info   = ZLOG_LEVEL_INFO,
+    trace = ZLOG_LEVEL_TRACE,
+    debug = ZLOG_LEVEL_DEBUG,
+    info = ZLOG_LEVEL_INFO,
     notice = ZLOG_LEVEL_NOTICE,
-    warn   = ZLOG_LEVEL_WARN,
-    error  = ZLOG_LEVEL_ERROR,
-    fatal  = ZLOG_LEVEL_FATAL
+    warn = ZLOG_LEVEL_WARN,
+    error = ZLOG_LEVEL_ERROR,
+    fatal = ZLOG_LEVEL_FATAL
 } ZLOG_LV;
 
 #define DEF_ZLOG_MOD(ZLOG_MOD)                            \
@@ -30,6 +31,7 @@ typedef enum {
     ZLOG_MOD(ZLOG_MOD_MISC, ZLOG_LEVEL_DEBUG, "MISC")     \
     ZLOG_MOD(ZLOG_MOD_WATCH, ZLOG_LEVEL_DEBUG, "WATCH")   \
     ZLOG_MOD(ZLOG_MOD_CONFIG, ZLOG_LEVEL_DEBUG, "CONFIG") \
+    ZLOG_MOD(ZLOG_MOD_DB, ZLOG_LEVEL_DEBUG, "DB")         \
     ZLOG_MOD(ZLOG_MOD_NET, ZLOG_LEVEL_DEBUG, "NET")       \
     ZLOG_MOD(ZLOG_MOD_CRYPTO, ZLOG_LEVEL_DEBUG, "CRYPTO") \
     ZLOG_MOD(ZLOG_MOD_MQ, ZLOG_LEVEL_DEBUG, "MQ")         \
@@ -88,8 +90,11 @@ typedef enum {
     } while (0)
 
 zlog_category_t *zlog_get_mod_cat(ZLOG_MOD_NAME logMod);
-int              zlog_verify_level(int level, ZLOG_MOD_NAME logMod);
-const char      *zlog_vni_tag_get();
+
+int zlog_verify_level(int level, ZLOG_MOD_NAME logMod);
+
+const char *zlog_vni_tag_get();
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/srcs/libs/init/init_runtime.c b/srcs/libs/init/init_runtime.c
index 75c2473..e974c6d 100644
--- a/srcs/libs/init/init_runtime.c
+++ b/srcs/libs/init/init_runtime.c
@@ -19,6 +19,9 @@
 #include "lib_config.h"
 #include "prj_config.h"
 #include "zlog_module.h"
+#ifdef SQLITE_ON
+#include "database.h"
+#endif
 #ifdef ZEROMQ_ON
 #include "msg_queue.h"
 #endif
@@ -137,6 +140,10 @@ int user_init(const char *pAppCfgFile, const char *pCfgDirectory, const char *pK
     if (cfg_get_hardware_watch_enable()) {
         init_hardware();
     }
+#ifdef SQLITE_ON
+    db_sqlite3_init();
+#endif
+
 #ifdef ZEROMQ_ON
     if ((ret = mq_init()) != ERR_SUCCESS) {
         LOG_MOD(error, ZLOG_MOD_INIT, "Message queue init error: %d\n", ret);
@@ -157,6 +164,9 @@ int user_init(const char *pAppCfgFile, const char *pCfgDirectory, const char *pK
 void user_uninit() {
     if (g_isInited) {
         task_manager_exit();
+#ifdef SQLITE_ON
+        db_sqlite3_uninit();
+#endif
 #ifdef HTTPSERVER_ON
         http_svr_uinit();
 #endif
diff --git a/srcs/libs/ipaddr/ipaddr.c b/srcs/libs/ipaddr/ipaddr.c
index 885bb03..2994d59 100644
--- a/srcs/libs/ipaddr/ipaddr.c
+++ b/srcs/libs/ipaddr/ipaddr.c
@@ -1,4 +1,16 @@
 //
 // Created by xajhuang on 2023/3/21.
 //
-#include "ipaddr.h"
\ No newline at end of file
+#include "ipaddr.h"
+
+U32 ipv4_get_network_addr(U32 ipAddr, U32 netmask) {
+    return (ipAddr & netmask);
+}
+
+U32 ipv4_get_boardcast_addr(U32 ipAddr, U32 netmask) {
+    return (ipAddr | netmask);
+}
+
+U32 ipv4_network_total_addr(U32 netmask) {
+    return (~netmask) + 1;
+}
\ No newline at end of file
diff --git a/srcs/libs/misc/err.c b/srcs/libs/misc/err.c
index a0262d8..6db4d08 100644
--- a/srcs/libs/misc/err.c
+++ b/srcs/libs/misc/err.c
@@ -4,8 +4,8 @@
 #include <user_errno.h>
 #include "common.h"
 
-#define MAX_DESC_LENGTH                   (256)
-#define GENERATE_STRING(STRING, no, desc) {#STRING, desc},
+#define MAX_DESC_LENGTH               (256)
+#define GENERATE_STRING(STRING, desc) {#STRING, desc},
 
 static const char *g_enumStrVal[][MAX_DESC_LENGTH] = {
     DEF_ERR_CODE(GENERATE_STRING) {"ERR_UNKNOWN", "未知错误"},
diff --git a/srcs/service/dhcpd/dhcp_option.c b/srcs/service/dhcpd/dhcp_option.c
index e80840b..497a541 100644
--- a/srcs/service/dhcpd/dhcp_option.c
+++ b/srcs/service/dhcpd/dhcp_option.c
@@ -141,6 +141,24 @@ void dhcp_option_cfg_init() {
     }
 }
 
+void dhcp_add_number_option(U8 *pBegin, int opt, U8 value, U8 nSize) {
+    *pBegin = opt;
+    pBegin++;
+    *pBegin = nSize;
+    pBegin++;
+    memcpy(pBegin, &value, nSize);
+    pBegin += nSize;
+}
+
+void dhcp_add_buf_option(U8 *pBegin, int opt, U8 *buf, U8 nSize) {
+    *pBegin = opt;
+    pBegin++;
+    *pBegin = nSize;
+    pBegin++;
+    memcpy(pBegin, buf, nSize);
+    pBegin += nSize;
+}
+
 int dhcp_get_option(int opt, U8 *pOptData, U32 nSize, PDHCP_OPT pVal) {
     U8 *p = pOptData;
 
diff --git a/srcs/service/dhcpd/dhcpd_network.c b/srcs/service/dhcpd/dhcpd_network.c
index 53896a6..3eae98f 100644
--- a/srcs/service/dhcpd/dhcpd_network.c
+++ b/srcs/service/dhcpd/dhcpd_network.c
@@ -18,18 +18,26 @@
 #include "network/vlan.h"
 #include "dhcp_options.h"
 #include "config.h"
-#include "ip_pool.h"
+#include "misc.h"
 #include "user_mgr.h"
 
-#define PKG_MMAP_BLOCKSIZ (1 << 22)
-#define PKG_MMAP_FRAMESIZ (1 << 11)
-#define PKG_MMAP_BLOCKNUM (64)
+#define PKG_MMAP_BLOCKSIZ    (1 << 22)
+#define PKG_MMAP_FRAMESIZ    (1 << 11)
+#define PKG_MMAP_BLOCKNUM    (64)
+#define MAX_DHCP_PKG_SIZE    (512)
 
-#define MIN_IPADDR        (0xC0A80202)
-#define DHCP_NETMASK      (0xFFFF0000)
-#define GW_IPADDR         (0xC0A80201)
-#define MASTER_DNS        (0x08080808)
-#define SALVE_DNS         (0x72727272)
+#define MAC_TO_STR(mac, str) sprintf(str, "%02X:%02X:%02X:%02X:%02X:%02X", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5])
+
+typedef struct {
+    U8   unicast;
+    U8   cliMac[ETH_ALEN];
+    U32  xid;
+    U32  reqIpAddr;
+    U32  leaseTime;
+    char clientId[256];
+    char vendorClassId[256];
+    char hostName[256];
+} DHCP_REQ, *PDHCP_REQ;
 
 typedef struct {
     struct iovec       *rd;
@@ -37,6 +45,14 @@ typedef struct {
     struct tpacket_req3 req;
 } PACKET_MMAP_RING, *PPACKET_MMAP_RING;
 
+typedef struct {
+    char *pIfName;
+    U32   ipAddr;
+    U32   netmask;
+    U8    macAddr[ETH_ALEN];
+    S8    hostname[MAX_PATH];
+} NIC_INFO, *PNIC_INFO;
+
 struct block_desc {
     uint32_t              version;
     uint32_t              offset_to_priv;
@@ -63,6 +79,7 @@ typedef struct {
 } PKG_MSG, *PPKG_MSG;
 
 #pragma pack()
+
 /*
 TORs (Top of Rack switch) at Facebook run DHCP relayers, these relayers are
 responsible for relaying broadcast DHCP traffic (DISCOVERY and SOLICIT
@@ -70,7 +87,8 @@ messages) originating within their racks to anycast VIPs, one DHCPv4 and one
 for DHCPv6.
 */
 static struct sock_filter g_filterCode[] = {
-#ifdef UDP_DHCP_FILTER  // create by: tcpdump "udp and port 67 and port 68" -dd
+#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},
@@ -99,13 +117,13 @@ static struct sock_filter g_filterCode[] = {
     {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},
+        // 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
@@ -182,6 +200,7 @@ static struct sock_filter g_filterCode[] = {
 };
 
 static PACKET_MMAP_RING g_pkgRing;
+static NIC_INFO         g_nicInfo;
 
 #define VLAN_VNI_ID(x) ntohs((x))
 #define DHCP_XID(x)    ntohl((x))
@@ -191,17 +210,110 @@ static struct sock_fprog bpf = {
     .filter = g_filterCode,
 };
 
-typedef struct {
-    U8    unicast;
-    U8    cliMac[ETH_ALEN];
-    U32   xid;
-    U32   reqIpAddr;
-    U32   leaseTime;
-    char *clientId;
-    char *vendorClassId;
-} DHCP_REQ, *PDHCP_REQ;
+static int dhcp_resp_offer(PDHCP_PACKAGE pReq, PIPPOOL_INFO pIpInfo, U32 ip) {
+    PDHCP_PACKAGE pRsp = (PDHCP_PACKAGE)malloc(MAX_DHCP_PKG_SIZE);
+    U8           *pOpt = pRsp->dhcp.options;
+
+    if (pRsp == NULL) {
+        LOG_MOD(error, ZLOG_MOD_DHCPD, "Malloc memory error: %u\n", MAX_DHCP_PKG_SIZE);
+        return -ERR_MALLOC_MEMORY;
+    }
+
+    memset(pRsp, 0, MAX_DHCP_PKG_SIZE);
+
+    // 二层头
+    // 目的IP地址
+    memset(pRsp->vlan_hdr.eth.h_dest, 0xFF, ETH_ALEN);
+    // 源 IP 地址
+    memcpy(pRsp->vlan_hdr.eth.h_source, g_nicInfo.macAddr, ETH_ALEN);
+    // protol
+    pRsp->vlan_hdr.eth.h_proto = pReq->vlan_hdr.eth.h_proto;
+
+    // QinQ 隧道
+    pRsp->vlan_hdr.vlan.id   = pReq->vlan_hdr.vlan.id;
+    pRsp->vlan_hdr.vlan.type = pReq->vlan_hdr.vlan.type;
+    // TODO 可能的二层QinQ隧道
+
+    // IP 头
+    memcpy(&pRsp->vlan_hdr.ip, &pReq->vlan_hdr.ip, sizeof(struct iphdr));
+    // 更新源IP
+    pRsp->vlan_hdr.ip.saddr = htonl(g_nicInfo.ipAddr);
+    // 更新目的IP地址,广播255.255.255.255
+    pRsp->vlan_hdr.ip.daddr = 0xFFFFFFFF;
+
+    // UDP 头
+    // 目的端口
+    pRsp->vlan_hdr.udp.dest   = pReq->vlan_hdr.udp.source;
+    // 源端口
+    pRsp->vlan_hdr.udp.source = pReq->vlan_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;
+    // 分配的 IP 地址
+    pRsp->dhcp.yiaddr = htonl(ip);
+    // 客户端 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", 4);
+    pRsp->dhcp.hops   = 0;
+    pRsp->dhcp.secs   = 0;
+    pRsp->dhcp.flags  = 0;
+    pRsp->dhcp.ciaddr = 0;
+    pRsp->dhcp.siaddr = 0;
+    pRsp->dhcp.giaddr = 0;
+
+    // DHCP Options
+    // DHCP 消息类型
+    dhcp_add_number_option(pOpt, OPT_MESSAGETYPE, DHCP_MSG_OFFER, 1);
+    pOpt += 3;
+    // 子网掩码
+    dhcp_add_number_option(pOpt, OPT_NETMASK, pIpInfo->netMask, 4);
+    pOpt += 6;
+    // 租约
+    dhcp_add_number_option(pOpt, OPT_IPADDRLEASE, htonl(pIpInfo->leaseTime), 4);
+    pOpt += 6;
+    // DHCP Server
+    dhcp_add_number_option(pOpt, OPT_SERVERID, g_nicInfo.ipAddr, 4);
+    pOpt += 6;
+    // DNS
+    if (pIpInfo->primeDNS != 0) {
+        if (pIpInfo->salveDNS == 0) {
+            dhcp_add_number_option(pOpt, OPT_DNS, pIpInfo->primeDNS, 4);
+            pOpt += 6;
+        } else {
+            dhcp_add_buf_option(pOpt, OPT_DNS, (U8 *)&pIpInfo->primeDNS, 8);
+            pOpt += 10;
+        }
+    }
+    // 网关
+    if (pIpInfo->gwAddr != 0) {
+        dhcp_add_number_option(pOpt, OPT_ROUTER, pIpInfo->gwAddr, 4);
+        pOpt += 6;
+    }
+    // DHCP 主机名
+    dhcp_add_buf_option(pOpt, OPT_DOMAINNAME, (U8 *)g_nicInfo.hostname, strlen(g_nicInfo.hostname));
+    pOpt += strlen(g_nicInfo.hostname) + 2;
+
+    *pOpt = OPT_END;
+
+    LOG_MSG_HEX(debug, pRsp, 256);
+
+    return ERR_SUCCESS;
+}
 
 static void on_sock_recv(uv_work_t *req) {
+    char              macStr[20] = {0};
+    U32               ip;
+    PIPPOOL_INFO      pIpInfo;
     DHCP_REQ          reqDhcp;
     DHCP_OPT          optMsg, opt;
     int               ret;
@@ -209,6 +321,8 @@ static void on_sock_recv(uv_work_t *req) {
     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, ZLOG_MOD_DHCPD, "Error message op code %d\n", pkg->dhcp.op);
@@ -241,12 +355,33 @@ static void on_sock_recv(uv_work_t *req) {
 
             ret = dhcp_get_option(OPT_CLIENTID, pkg->dhcp.options, optSize, &opt);
             if (ret == ERR_SUCCESS) {
-                reqDhcp.clientId = (char *)opt.pValue;
+                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) {
-                reqDhcp.vendorClassId = (char *)opt.pValue;
+                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));
+            }
+
+            MAC_TO_STR(reqDhcp.cliMac, macStr);
+            ret = pre_alloc_dhcp_res(VLAN_VNI_ID(pkg->vlan_hdr.vlan.id), macStr, &ip, &pIpInfo);
+
+            if (ret == ERR_SUCCESS) {
+                LOG_MOD(trace,
+                        ZLOG_MOD_DHCPD,
+                        "DHCP prepare assign ipaddress: [%s(%s)] --> %s\n",
+                        macStr,
+                        reqDhcp.hostName,
+                        u32_to_str_ip(ntohl(ip)));
+
+                ret = dhcp_resp_offer(pkg, pIpInfo, ip);
+            } else {
+                //LOG_MOD(error, ZLOG_MOD_DHCPD, );
             }
             break;
         case DHCP_MSG_REQUEST:
@@ -417,7 +552,7 @@ static int create_udp_socket() {
 #endif
     // 6. bind socket
     memset(&addr, 0, sizeof(addr));
-    addr.sll_ifindex  = (int)if_nametoindex(config_get_dhcp_nic_name());
+    addr.sll_ifindex  = (int)if_nametoindex(g_nicInfo.pIfName);
     addr.sll_family   = AF_PACKET;
     addr.sll_protocol = htons(ETH_P_ALL);
     addr.sll_hatype   = 0;
@@ -435,8 +570,16 @@ static int create_udp_socket() {
 int dhcpd_init() {
     static uv_udp_t  uvRaw;
     static uv_poll_t uvSocket;
+    int              sock;
+    size_t           size = MAX_PATH;
 
-    int sock = create_udp_socket();
+    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);
+
+    sock = create_udp_socket();
 
     if (sock <= 0) {
         return sock;
@@ -444,6 +587,7 @@ int dhcpd_init() {
 
     dhcp_user_mgr_init();
     dhcp_option_cfg_init();
+    dhcp_lease_init();
 
     uv_udp_init(get_task_manager(), &uvRaw);
     uv_udp_open(&uvRaw, sock);
diff --git a/srcs/service/dhcpd/include/dhcp_options.h b/srcs/service/dhcpd/include/dhcp_options.h
index 1c5633e..d7e446e 100644
--- a/srcs/service/dhcpd/include/dhcp_options.h
+++ b/srcs/service/dhcpd/include/dhcp_options.h
@@ -141,6 +141,8 @@ typedef struct {
     U8  len;
 } DHCP_OPT, *PDHCP_OPT;
 
+void dhcp_add_number_option(U8 *pBegin, int opt, U8 value, U8 nSize);
+void dhcp_add_buf_option(U8 *pBegin, int opt, U8 *buf, U8 nSize);
 int  dhcp_get_option(int opt, U8 *pOptData, U32 nSize, PDHCP_OPT pVal);
 void dhcp_option_cfg_init();
 #ifdef __cplusplus
diff --git a/srcs/service/dhcpd/include/ip_pool.h b/srcs/service/dhcpd/include/ip_pool.h
index 57cfdab..dd957f9 100644
--- a/srcs/service/dhcpd/include/ip_pool.h
+++ b/srcs/service/dhcpd/include/ip_pool.h
@@ -6,6 +6,8 @@
 #define VCPE_IP_POOL_H
 #include <uthash/uthash.h>
 #include <common.h>
+#include <bitset/bitset.h>
+
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -18,7 +20,7 @@ extern "C" {
 #define MAX_POOL_HASH_KEY (18)
 
 typedef struct {
-    S8             poolKey[MAX_POOL_HASH_KEY];
+    U32            poolKey;
     U32            minAddr;
     U32            maxAddr;
     U32            netMask;
@@ -26,6 +28,7 @@ typedef struct {
     U32            primeDNS;
     U32            salveDNS;
     U32            leaseTime;
+    bitset_t      *assignPool;
     UT_hash_handle hh;
 } IPPOOL_INFO, *PIPPOOL_INFO;
 
diff --git a/srcs/service/dhcpd/include/lease.h b/srcs/service/dhcpd/include/lease.h
index 1220ff3..bda166b 100644
--- a/srcs/service/dhcpd/include/lease.h
+++ b/srcs/service/dhcpd/include/lease.h
@@ -7,6 +7,7 @@
 #include <uthash/uthash.h>
 #include <linux/if_ether.h>
 #include <common.h>
+#include "ip_pool.h"
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -24,6 +25,8 @@ typedef struct {
     U32 express;
 } LEASE_CACHE, *PLEASE_CACHE;
 
+int dhcp_lease_init();
+int pre_alloc_dhcp_res(U32 uid, const char *pMac, U32 *pOutIp, PIPPOOL_INFO *pOutPool);
 #ifdef __cplusplus
 }
 #endif
diff --git a/srcs/service/dhcpd/include/user_mgr.h b/srcs/service/dhcpd/include/user_mgr.h
index 663108f..28ddb29 100644
--- a/srcs/service/dhcpd/include/user_mgr.h
+++ b/srcs/service/dhcpd/include/user_mgr.h
@@ -20,8 +20,9 @@ typedef struct {
     UT_hash_handle hh;
 } DHCP_USER_INFO, *PDHCP_USER_INFO;
 
-int user_add_ip_pool(U32 uId, PIPPOOL_INFO pPool);
-int dhcp_user_mgr_init();
+int          user_add_ip_pool(U32 uId, PIPPOOL_INFO pPool);
+int          dhcp_user_mgr_init();
+PIPPOOL_INFO user_get_pool(U32 uId);
 #ifdef HTTPSERVER_ON
 int user_init_httpd();
 #endif
diff --git a/srcs/service/dhcpd/ip_pool.c b/srcs/service/dhcpd/ip_pool.c
index 766c423..e49a0bb 100644
--- a/srcs/service/dhcpd/ip_pool.c
+++ b/srcs/service/dhcpd/ip_pool.c
@@ -8,8 +8,7 @@
 #include "user_errno.h"
 #include "zlog_module.h"
 #include "user_mgr.h"
-
-#define GEN_IP_POOL_HASH_KEY(p) (sprintf((p)->poolKey, "%08X-%08X", (p)->minAddr, (p)->maxAddr))
+#include "ipaddr.h"
 
 static PIPPOOL_INFO g_defPool = NULL;
 
@@ -34,6 +33,8 @@ void init_default_pool() {
                 continue;
             }
 
+            memset(p, 0, sizeof(IPPOOL_INFO));
+
             if (strlen(pRange->rangAddr) == 0) {
                 LOG_MOD(error, ZLOG_MOD_OPENDHCPD, "Error ip pool configure of address\n");
                 free(p);
@@ -61,7 +62,7 @@ void init_default_pool() {
                     free(p);
                     continue;
                 } else {
-                    p->minAddr = addr.s_addr;
+                    p->minAddr = ntohl(addr.s_addr);
                 }
 
                 if (inet_aton(pSecIp, &addr) == 0) {
@@ -69,30 +70,48 @@ void init_default_pool() {
                     free(p);
                     continue;
                 } else {
-                    p->maxAddr = addr.s_addr;
+                    p->maxAddr = ntohl(addr.s_addr);
                 }
-
-                // 填充POOL Hash Key
-                GEN_IP_POOL_HASH_KEY(p);
             } else {
                 LOG_MOD(error, ZLOG_MOD_DHCPD, "Bad DHCP range format: %s\n", tmpStr);
                 free(p);
                 continue;
             }
 
+            if (strlen(pRange->subnet) > 0) {
+                if (inet_aton(pRange->subnet, &addr) == 0) {
+                    LOG_MOD(error, ZLOG_MOD_DHCPD, "Convert ip ERROR: %s\n", pRange->subnet);
+                } else {
+                    p->netMask = ntohl(addr.s_addr);
+                }
+            } else {
+                // 当前网络默认IP地址池
+                if (inet_aton("255.255.255.0", &addr) == 0) {
+                    LOG_MOD(error, ZLOG_MOD_DHCPD, "Convert ip ERROR: %s\n", pRange->subnet);
+                } else {
+                    p->netMask = ntohl(addr.s_addr);
+                }
+            }
+
+            // 填充POOL Hash Key
+            p->poolKey    = ipv4_get_network_addr(p->minAddr, p->netMask);
+            p->assignPool = bitset_create_with_capacity(ipv4_network_total_addr(p->netMask));
+
+            if (!p->assignPool) {
+                LOG_MOD(error,
+                        ZLOG_MOD_DHCPD,
+                        "Create address pool bitset ERROR: 0x%08X total address %u\n",
+                        htonl(p->netMask),
+                        ipv4_network_total_addr(p->netMask));
+                free(p);
+                continue;
+            }
+
             if (strlen(pRange->gateway) > 0) {
                 if (inet_aton(pRange->gateway, &addr) == 0) {
                     LOG_MOD(error, ZLOG_MOD_DHCPD, "Convert ip ERROR: %s\n", pRange->gateway);
                 } else {
-                    p->gwAddr = addr.s_addr;
-                }
-            }
-
-            if (strlen(pRange->subnet) > 0) {
-                if (inet_aton(pRange->subnet, &addr) == 0) {
-                    LOG_MOD(error, ZLOG_MOD_DHCPD, "Convert ip ERROR: %s\n", pRange->subnet);
-                } else {
-                    p->netMask = addr.s_addr;
+                    p->gwAddr = ntohl(addr.s_addr);
                 }
             }
 
@@ -109,19 +128,19 @@ void init_default_pool() {
                     if (inet_aton(tmpStr, &addr) == 0) {
                         LOG_MOD(error, ZLOG_MOD_DHCPD, "Convert ip ERROR: %s of %s\n", tmpStr, pRange->dnsSvr);
                     } else {
-                        p->primeDNS = addr.s_addr;
+                        p->primeDNS = ntohl(addr.s_addr);
                     }
 
                     if (inet_aton(pSecIp, &addr) == 0) {
                         LOG_MOD(error, ZLOG_MOD_DHCPD, "Convert ip ERROR: %s of %s\n", pSecIp, pRange->dnsSvr);
                     } else {
-                        p->salveDNS = addr.s_addr;
+                        p->salveDNS = ntohl(addr.s_addr);
                     }
                 } else {
                     if (inet_aton(pRange->dnsSvr, &addr) == 0) {
                         LOG_MOD(error, ZLOG_MOD_DHCPD, "Convert ip ERROR: %s of %s\n", tmpStr, pRange->dnsSvr);
                     } else {
-                        p->primeDNS = addr.s_addr;
+                        p->primeDNS = ntohl(addr.s_addr);
                     }
                 }
             }
diff --git a/srcs/service/dhcpd/lease.c b/srcs/service/dhcpd/lease.c
index 2f7a822..0cd0690 100644
--- a/srcs/service/dhcpd/lease.c
+++ b/srcs/service/dhcpd/lease.c
@@ -2,7 +2,162 @@
 // Created by xajhuang on 2023/3/23.
 //
 
+#include <time.h>
 #include "lease.h"
+#include "user_errno.h"
+#include "zlog_module.h"
+#include "database.h"
+#include "user_mgr.h"
 
-static PMAC_FILTER g_allowTbl     = NULL;
-static PMAC_FILTER g_blackListTbl = NULL;
\ No newline at end of file
+#define LEASE_DB_NAME       ("lease")
+#define PREALLOC_IP_TIMEOUT (60)
+
+typedef struct {
+    U32            ipAddr;
+    char           macAddr[20];
+    U32            bitset;
+    PIPPOOL_INFO   pCtx;
+    U32            timeStamp;
+    UT_hash_handle hh;
+} PRE_ALLOC_IP, *PPRE_ALLOC_IP;
+
+//static PMAC_FILTER   g_allowTbl     = NULL;
+//static PMAC_FILTER   g_blackListTbl = NULL;
+static PPRE_ALLOC_IP g_pPreAllocIp = NULL;
+
+#define CREATE_LEASE_TABLE(name)                        \
+    "CREATE TABLE IF NOT EXISTS " #name                 \
+    " (  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 " #name "_index ON " #name " (uid, mac);"
+
+int pre_alloc_dhcp_res(U32 uid, const char *pMac, U32 *pOutIp, PIPPOOL_INFO *pOutPool) {
+    PIPPOOL_INFO  pPool, pTemp;
+    PPRE_ALLOC_IP pNewIp, pTmp, pCache = NULL;
+    PIPPOOL_INFO  pUserPool;
+
+    if (pOutIp == NULL || pOutPool == NULL) {
+        LOG_MOD(error, ZLOG_MOD_DHCPD, "Input params error: %p, %p\n", pOutIp, pOutPool);
+        return -ERR_INPUT_PARAMS;
+    }
+
+    pUserPool = user_get_pool(uid);
+    if (pUserPool == NULL) {
+        LOG_MOD(error, ZLOG_MOD_DHCPD, "Can't found avaliable address pool\n");
+        return -ERR_DHCP_NO_POOL;
+    }
+
+    // 遍历当前用户所有IP地址池
+    HASH_ITER(hh, pUserPool, pPool, pTemp) {
+        U32 addr;
+
+        // 查看是否预分配过该设备
+        if (pMac && strlen(pMac) > 0) {
+            HASH_ITER(hh, g_pPreAllocIp, pNewIp, pTmp) {
+                if (strcmp(pNewIp->macAddr, pMac) == 0) {
+                    *pOutIp   = pNewIp->ipAddr;
+                    *pOutPool = pPool;
+
+                    return ERR_SUCCESS;
+                }
+            }
+        }
+
+        while ((addr = bitset_minimum(pPool->assignPool)) > 0) {
+            U32 ipAddr = (pPool->minAddr & pPool->netMask) + addr;
+
+            // 查找租约配置文件中是否记录了曾经分配的地址, 如果已经分配则获取下一个
+            // TODO: add process
+            //            if (FALSE) {
+            //                bitset_set(pPool->assignPool, addr);
+            //                continue;
+            //            }
+
+            // 查找IP地址是否已经被预分配
+            HASH_FIND_INT(g_pPreAllocIp, &ipAddr, pNewIp);
+
+            if (pNewIp == NULL) {
+                pNewIp = (PPRE_ALLOC_IP)malloc(sizeof(PRE_ALLOC_IP));
+
+                if (!pNewIp) {
+                    LOG_MOD(error, ZLOG_MOD_DHCPD, "Malloc memory error: %lu\n", sizeof(PRE_ALLOC_IP));
+                    continue;
+                }
+
+                memset(pNewIp, 0, sizeof(PRE_ALLOC_IP));
+
+                pNewIp->timeStamp = time(NULL);
+                pNewIp->pCtx      = pPool;
+                pNewIp->ipAddr    = ipAddr;
+                pNewIp->bitset    = addr;
+                if (pMac) {
+                    strcpy(pNewIp->macAddr, pMac);
+                }
+
+                HASH_ADD_INT(g_pPreAllocIp, ipAddr, pNewIp);
+
+                *pOutIp   = ipAddr;
+                *pOutPool = pPool;
+
+                bitset_cls_bit(pPool->assignPool, addr);
+                return ERR_SUCCESS;
+            } else {
+                if (time(NULL) - pNewIp->timeStamp < PREALLOC_IP_TIMEOUT) {
+                    continue;
+                }
+
+                *pOutIp   = pNewIp->ipAddr;
+                *pOutPool = pPool;
+
+                return ERR_SUCCESS;
+            }
+        }
+    }
+
+    // 如果没有分配到IP,清理过期的预分配IP
+    HASH_ITER(hh, g_pPreAllocIp, pNewIp, pTmp) {
+        if (time(NULL) - pNewIp->timeStamp > PREALLOC_IP_TIMEOUT) {
+            if (pCache == NULL) {
+                pCache = pNewIp;
+            } else {
+                HASH_DEL(g_pPreAllocIp, pNewIp);
+                free(pNewIp);
+                bitset_cls_bit(pNewIp->pCtx->assignPool, pNewIp->bitset);
+            }
+        }
+    }
+
+    if (pCache) {
+        *pOutIp   = pCache->ipAddr;
+        *pOutPool = pPool;
+        return ERR_SUCCESS;
+    }
+
+    // 没有可预分配的IP,报错
+    LOG_MOD(error, ZLOG_MOD_DHCPD, "No free ipaddress in poll:  uid = %u, pool = 0x%08X\n", uid, pUserPool->poolKey);
+    return -ERR_DHCP_NO_ADDR;
+}
+
+int dhcp_lease_init() {
+    int rc = 0;
+
+    rc = db_sqlite3_sql_exec(CREATE_LEASE_TABLE(LEASE_DB_NAME), NULL, NULL, NULL);
+
+    if (rc != ERR_SUCCESS) {
+        return rc;
+    }
+
+    return ERR_SUCCESS;
+}
\ No newline at end of file
diff --git a/srcs/service/dhcpd/user_mgr.c b/srcs/service/dhcpd/user_mgr.c
index b6248a8..d51980e 100644
--- a/srcs/service/dhcpd/user_mgr.c
+++ b/srcs/service/dhcpd/user_mgr.c
@@ -176,6 +176,7 @@ int user_init_httpd() {
 
     return ERR_SUCCESS;
 }
+
 // endregion
 #endif
 
@@ -196,7 +197,30 @@ int user_alloc_addr(U32 uId, U8 mac[ETH_ALEN], U32 *pAddr) {
     return ERR_SUCCESS;
 }
 
+PIPPOOL_INFO user_get_pool(U32 uId) {
+    PDHCP_USER_INFO pUser;
+
+    HASH_FIND_INT(g_dhcpUsrCfg, &uId, pUser);
+
+    if (pUser == NULL) {
+        U32 id = 0;
+
+        HASH_FIND_INT(g_dhcpUsrCfg, &id, pUser);
+
+        if (pUser == NULL) {
+            return NULL;
+        }
+
+        return pUser->pPoolMgr;
+    }
+
+    return NULL;
+}
+
 int user_add_ip_pool(U32 uId, PIPPOOL_INFO pPool) {
+    U32             k;
+    U32             begin;
+    U32             end;
     PIPPOOL_INFO    pPoolCfg;
     PDHCP_USER_INFO pUserCfg, pTemp;
 
@@ -207,15 +231,24 @@ int user_add_ip_pool(U32 uId, PIPPOOL_INFO pPool) {
         return ERR_SUCCESS;
     }
 
-    HASH_FIND_STR(pUserCfg->pPoolMgr, pPool->poolKey, pPoolCfg);
+    HASH_FIND_INT(pUserCfg->pPoolMgr, &pPool->poolKey, pPoolCfg);
 
     // 改地址池已经存在,提示错误
     if (pPoolCfg != NULL) {
-        return -ERR_ITEM_EXISTS;
+        free(pPool);
+    } else {
+        // 添加新地址池当前用户配置项中
+        HASH_ADD_INT(pUserCfg->pPoolMgr, poolKey, pPool);
+        pPoolCfg = pPool;
     }
 
-    // 添加到当前用户配置项中
-    HASH_ADD_STR(pUserCfg->pPoolMgr, poolKey, pPool);
+    // 计算可用的IP
+    begin = ntohl(pPoolCfg->minAddr) & ntohl(~pPoolCfg->netMask);
+    end   = ntohl(pPoolCfg->maxAddr) & ntohl(~pPoolCfg->netMask);
+
+    for (k = MAX(begin, 1U); k <= MIN(end, ntohl(~pPoolCfg->netMask) - 1); k++) {
+        bitset_set(pPoolCfg->assignPool, k);
+    }
 
     return ERR_SUCCESS;
 }