From b36960f878ca9aae09920ae5c08100a913d24b4d Mon Sep 17 00:00:00 2001 From: huangxin Date: Fri, 17 Mar 2023 15:42:37 +0800 Subject: [PATCH] =?UTF-8?q?OCT=201.=20=E6=B7=BB=E5=8A=A0dhcp=E5=8D=8F?= =?UTF-8?q?=E8=AE=AE=E8=A7=A3=E6=9E=90=E5=9F=BA=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- srcs/include/service/dhcpd.h | 105 ++++++++++++++++ srcs/service/CMakeLists.txt | 6 + srcs/service/dhcpd/dhcpd_network.c | 185 +++++++++++++++++++++++++++++ 3 files changed, 296 insertions(+) create mode 100644 srcs/include/service/dhcpd.h create mode 100644 srcs/service/CMakeLists.txt create mode 100644 srcs/service/dhcpd/dhcpd_network.c diff --git a/srcs/include/service/dhcpd.h b/srcs/include/service/dhcpd.h new file mode 100644 index 0000000..cec581a --- /dev/null +++ b/srcs/include/service/dhcpd.h @@ -0,0 +1,105 @@ +// +// Created by xajhuang on 2023/3/16. +// + +#ifndef VCPE_DHCPD_H +#define VCPE_DHCPD_H +#include +#ifdef __cplusplus +extern "C" { +#endif + +#pragma pack(push) +#pragma pack(1) + +/* + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | op (1) | htype (1) | hlen (1) | hops (1) | + +---------------+---------------+---------------+---------------+ + | xid (4) | + +-------------------------------+-------------------------------+ + | secs (2) | flags (2) | + +-------------------------------+-------------------------------+ + | ciaddr (4) | + +---------------------------------------------------------------+ + | yiaddr (4) | + +---------------------------------------------------------------+ + | siaddr (4) | + +---------------------------------------------------------------+ + | giaddr (4) | + +---------------------------------------------------------------+ + | | + | chaddr (16) | + | | + | | + +---------------------------------------------------------------+ + | | + | sname (64) | + +---------------------------------------------------------------+ + | | + | file (128) | + +---------------------------------------------------------------+ + | | + | options (variable) | + +---------------------------------------------------------------+ + */ +typedef struct { + ///< 报文的操作类型。分为请求报文和响应报文。1:请求报文,2:应答报文。即client送给server的封包,设为1,反之为2 + U8 op; + ///< DHCP客户端的MAC地址类型。MAC地址类型其实是指明网络类型。htype值为1时表示为最常见的以太网MAC地址类型 + U8 htype; + ///< DHCP客户端的MAC地址长度。以太网MAC地址长度为6个字节,即以太网时hlen值为6 + U8 hlen; + ///< DHCP报文经过的DHCP中继的数目,默认为0。DHCP请求报文每经过一个DHCP中继,该字段就会增加1。没有经过DHCP中继时值为0 + U8 hops; + ///< 客户端通过DHCP Discover报文发起一次IP地址请求时选择的随机数,相当于请求标识。用来标识一次IP地址请求过程。在一次请求中所有报文的Xid都是一样的 + U32 xid; + ///< DHCP客户端从获取到IP地址或者续约过程开始到现在所消耗的时间,以秒为单位。 + ///< 在没有获得IP地址前该字段始终为0(DHCP客户端开始DHCP请求后所经过的时间。目前尚未使用,固定为0) + U16 secs; + ///< 标志位,只使用第0比特位,是广播应答标识位,用来标识DHCP服务器应答报文是采用单播还是广播发送, + ///< 0表示采用单播发送方式,1表示采用广播发送方式。其余位尚未使用。(即从0-15bits,最左1bit为1时表示server将以广播方式传送封包给client。) + U16 flags; + ///< DHCP客户端的IP地址。仅在DHCP服务器发送的ACK报文中显示,因为在得到DHCP服务器确认前,DHCP客户端是还没有分配到IP地址的。 + ///< 在其他报文中均显示,只有客户端是Bound、Renew、Rebinding状态,并且能响应ARP请求时,才能被填充 + U32 ciaddr; + ///< DHCP服务器分配给客户端的IP地址。仅在DHCP服务器发送的Offer和ACK报文中显示,其他报文中显示为0 + U32 yiaddr; + ///< 下一个为DHCP客户端分配IP地址等信息的DHCP服务器IP地址。仅在DHCP Offer、DHCP ACK报文中显示,其他报文中显示为0 + U32 siaddr; + ///< DHCP客户端发出请求报文后经过的第一个DHCP中继的IP地址。如果没有经过DHCP中继,则显示为0。(转发代理(网关)IP地址) + U32 giaddr; + ///< DHCP客户端的MAC地址。在每个报文中都会显示对应DHCP客户端的MAC地址 + U8 chaddr[16]; + ///< 为DHCP客户端分配IP地址的DHCP服务器名称(DNS域名格式)。在Offer和ACK报文中显示发送报文的DHCP服务器名称,其他报文显示为0 + U8 sname[64]; + ///< DHCP服务器为DHCP客户端指定的启动配置文件名称及路径信息。仅在DHCP Offer报文中显示,其他报文中显示为空 + U8 file[128]; + ///< 可选项字段,长度可变,格式为"代码+长度+数据" + U8 options[0]; +} DHCP_PROTO, *PDHCP_PROTO; + +typedef struct { + U8 flags; + U8 res1; + U8 res2; + U8 res3; + U32 vni; +} VXLAN_HDR, *PVXLAN_HDR; + +typedef struct { + U16 out_priority_cfi_and_id; + U16 in_type; + U16 in_priority_cfi_and_id; + U16 origin_type; +} QINQ_HDR, *PQINQ_HDR; + +#pragma pack(pop) + +int dhcpd_init(); +#ifdef __cplusplus +} +#endif +#endif //VCPE_DHCPD_H diff --git a/srcs/service/CMakeLists.txt b/srcs/service/CMakeLists.txt new file mode 100644 index 0000000..3610a95 --- /dev/null +++ b/srcs/service/CMakeLists.txt @@ -0,0 +1,6 @@ + +INCLUDE_DIRECTORIES(. ../include ../libs/include) + +AUX_SOURCE_DIRECTORY(dhcpd DHCPD_SRC) + +ADD_LIBRARY(dhcpd ${DHCPD_SRC} ${DHCPD_HEADS}) \ No newline at end of file diff --git a/srcs/service/dhcpd/dhcpd_network.c b/srcs/service/dhcpd/dhcpd_network.c new file mode 100644 index 0000000..26ce8ea --- /dev/null +++ b/srcs/service/dhcpd/dhcpd_network.c @@ -0,0 +1,185 @@ +// +// Created by xajhuang on 2023/3/16. +// +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "service/dhcpd.h" +#include "user_errno.h" +#include "task_manager.h" +#include "zlog_module.h" + +#pragma pack(1) + +typedef struct { + struct ethhdr eth; + struct iphdr ip; + struct udphdr udp; + DHCP_PROTO dhcp; +} DHCP_PACKAGE, *PDHCP_PACKAGE; + +#pragma pack() + +typedef struct { + unsigned int vni; + unsigned short q1; + unsigned short q2; +} VXLAN_TAG, *PVXLAN_TAG; + +static struct sock_filter g_filterCode[] = { +#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}, + {0x15, 0, 21, 0x00000011}, + {0x28, 0, 0, 0x00000036}, + {0x15, 0, 2, 0x00000043}, + {0x28, 0, 0, 0x00000038}, + {0x15, 16, 17, 0x00000044}, + {0x15, 0, 16, 0x00000044}, + {0x28, 0, 0, 0x00000038}, + {0x15, 13, 14, 0x00000043}, + {0x15, 0, 13, 0x00000800}, + {0x30, 0, 0, 0x00000017}, + {0x15, 0, 11, 0x00000011}, + {0x28, 0, 0, 0x00000014}, + {0x45, 9, 0, 0x00001fff}, + {0xb1, 0, 0, 0x0000000e}, + {0x48, 0, 0, 0x0000000e}, + {0x15, 0, 2, 0x00000043}, + {0x48, 0, 0, 0x00000010}, + {0x15, 3, 4, 0x00000044}, + {0x15, 0, 3, 0x00000044}, + {0x48, 0, 0, 0x00000010}, + {0x15, 0, 1, 0x00000043}, + {0x6, 0, 0, 0x00040000}, + {0x6, 0, 0, 0x00000000}, +#endif + // 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}, +}; + +static struct sock_fprog bpf = { + .len = sizeof(g_filterCode) / (sizeof(struct sock_filter)), + .filter = g_filterCode, +}; + +static void alloc_buffer(uv_handle_t *handle, size_t suggested_size, uv_buf_t *buf) { + *buf = uv_buf_init(malloc(suggested_size), suggested_size); +} + +static void package_process(uv_work_t *req) { + PDHCP_PACKAGE pkg = (PDHCP_PACKAGE)req->data; +} + +static void on_read(uv_udp_t *req, ssize_t nread, const uv_buf_t *buf, const struct sockaddr *addr, unsigned flags) { + if (nread > 0) { + uv_work_t *pWork = (uv_work_t *)malloc(sizeof(uv_work_t)); + + if (!pWork) { + free(buf->base); + LOG_MOD(error, ZLOG_MOD_OPENDHCPD, "Malloc %lu memory error\n", sizeof(uv_work_t)); + return; + } + + pWork->data = (void *)buf; + uv_queue_work(get_task_manager(), pWork, package_process, NULL); + + PDHCP_PACKAGE pkg = (PDHCP_PACKAGE)buf->base; + LOG_MSG(info, "xid: 0x%08X\n", ntohl(pkg->dhcp.xid)); + LOG_MSG(info, + "client mac: %02X:%02X:%02X:%02X:%02X:%02X\n", + pkg->dhcp.chaddr[0], + pkg->dhcp.chaddr[1], + pkg->dhcp.chaddr[2], + pkg->dhcp.chaddr[3], + pkg->dhcp.chaddr[4], + pkg->dhcp.chaddr[5]); + //LOG_MSG_HEX(debug, buf->base, nread); + } + + free(buf->base); +} + +static int create_udp_socket() { + struct sockaddr_ll addr; + + // 1. create socket + int sock_fd = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL)); + if (sock_fd < 0) { + perror("socket created failure"); + return -ERR_SOCK_CREATE; + } + + const char *iface_name = "ens192"; + memset(&addr, 0, sizeof(addr)); + addr.sll_ifindex = (int)if_nametoindex(iface_name); + addr.sll_family = AF_PACKET; + addr.sll_protocol = htons(ETH_P_ALL); + + // 2. attach filter (no need to call bind) + if (setsockopt(sock_fd, SOL_SOCKET, SO_ATTACH_FILTER, &bpf, sizeof(bpf)) < 0) { + perror("attaching filter failed"); + return -ERR_SOCK_SETOPT; + } + + return sock_fd; +} + +#if 0 +#define MAX_DATE_ITEMS (64) + +void fib(uv_work_t *req) { + int cnt = 3; + fprintf(stderr, "Task %ld\n", (long)(req->data)); + while (cnt--) { + uv_sleep(1000); + } +} + +void after_fib(uv_work_t *req, int status) { + fprintf(stderr, "Finish Task %ld\n", (long)(req->data)); +} +#endif +int dhcpd_init() { + static uv_udp_t uvRaw; +#if 0 + static unsigned int data[MAX_DATE_ITEMS]; + static uv_work_t req[MAX_DATE_ITEMS]; + int i; + + for (i = 0; i < MAX_DATE_ITEMS; i++) { + req[i].data = (void *)(intptr_t)i; + uv_queue_work(get_task_manager(), &req[i], fib, after_fib); + } +#endif + + int sock = create_udp_socket(); + + if (sock <= 0) { + return sock; + } + + LOG_MSG(info, "sizeof DHCP_PACKAGE = %lu\n", sizeof(DHCP_PACKAGE)); + + uv_udp_init(get_task_manager(), &uvRaw); + uv_udp_open(&uvRaw, sock); + + uv_udp_recv_start(&uvRaw, alloc_buffer, on_read); + + return ERR_SUCCESS; +} \ No newline at end of file