vcpe/srcs/service/dhcpd/dhcpd_network.c

727 lines
25 KiB
C
Raw Normal View History

2023-03-17 07:42:37 +00:00
//
// Created by xajhuang on 2023/3/16.
//
#include <stdlib.h>
#include <string.h>
#include <linux/filter.h>
#include <net/if.h>
#include <sys/socket.h>
2023-03-20 02:47:22 +00:00
#include <sys/mman.h>
#include <pcap/pcap.h>
#include <unistd.h>
2023-03-17 07:42:37 +00:00
#include "user_errno.h"
#include "task_manager.h"
#include "zlog_module.h"
#include "dhcp_options.h"
#include "config.h"
#include "misc.h"
#include "user_mgr.h"
#include "rfc2131.h"
#include "dhcp_network.h"
2023-03-20 02:47:22 +00:00
#define MAXIMUM_SNAPLEN (262144)
2023-03-20 02:47:22 +00:00
/*
TORs (Top of Rack switch) at Facebook run DHCP relayers, these relayers are
responsible for relaying broadcast DHCP traffic (DISCOVERY and SOLICIT
messages) originating within their racks to anycast VIPs, one DHCPv4 and one
for DHCPv6.
*/
#ifdef USED_DEFAULT_BPF
2023-03-17 07:42:37 +00:00
static struct sock_filter g_filterCode[] = {
#ifdef UDP_DHCP_FILTER
// create by: tcpdump "udp and port 67 and port 68" -dd
2023-03-17 07:42:37 +00:00
{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
2023-03-20 02:47:22 +00:00
#if 0
2023-03-31 06:32:32 +00:00
// 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},
2023-03-20 02:47:22 +00:00
#endif
// region BPF code
// create by: tcpdump "vlan and udp and port 67 and port 68" -dd
{0x0, 0, 0, 0x00000000},
{0x2, 0, 0, 0x00000000},
{0x2, 0, 0, 0x00000001},
2023-03-20 02:47:22 +00:00
{0x30, 0, 0, 0xfffff030},
{0x15, 7, 0, 0x00000001},
{0x0, 0, 0, 0x00000004},
{0x2, 0, 0, 0x00000000},
{0x2, 0, 0, 0x00000001},
2023-03-20 02:47:22 +00:00
{0x28, 0, 0, 0x0000000c},
{0x15, 2, 0, 0x00008100},
{0x15, 1, 0, 0x000088a8},
{0x15, 0, 56, 0x00009100},
{0x61, 0, 0, 0x00000001},
{0x48, 0, 0, 0x0000000c},
{0x15, 0, 13, 0x000086dd},
{0x61, 0, 0, 0x00000000},
{0x50, 0, 0, 0x00000014},
{0x15, 0, 50, 0x00000011},
{0x61, 0, 0, 0x00000000},
{0x48, 0, 0, 0x00000036},
{0x15, 0, 3, 0x00000043},
{0x61, 0, 0, 0x00000000},
{0x48, 0, 0, 0x00000038},
{0x15, 43, 44, 0x00000044},
{0x15, 0, 43, 0x00000044},
{0x61, 0, 0, 0x00000000},
{0x48, 0, 0, 0x00000038},
{0x15, 39, 40, 0x00000043},
{0x15, 0, 39, 0x00000800},
{0x61, 0, 0, 0x00000000},
{0x50, 0, 0, 0x00000017},
{0x15, 0, 36, 0x00000011},
{0x61, 0, 0, 0x00000000},
{0x48, 0, 0, 0x00000014},
{0x45, 33, 0, 0x00001fff},
{0x61, 0, 0, 0x00000000},
{0x50, 0, 0, 0x0000000e},
{0x54, 0, 0, 0x0000000f},
{0x64, 0, 0, 0x00000002},
{0xc, 0, 0, 0x00000000},
{0x7, 0, 0, 0x00000000},
{0x48, 0, 0, 0x0000000e},
{0x15, 0, 8, 0x00000043},
{0x61, 0, 0, 0x00000000},
{0x50, 0, 0, 0x0000000e},
{0x54, 0, 0, 0x0000000f},
{0x64, 0, 0, 0x00000002},
{0xc, 0, 0, 0x00000000},
{0x7, 0, 0, 0x00000000},
{0x48, 0, 0, 0x00000010},
{0x15, 16, 17, 0x00000044},
{0x61, 0, 0, 0x00000000},
{0x50, 0, 0, 0x0000000e},
{0x54, 0, 0, 0x0000000f},
{0x64, 0, 0, 0x00000002},
{0xc, 0, 0, 0x00000000},
{0x7, 0, 0, 0x00000000},
{0x48, 0, 0, 0x0000000e},
{0x15, 0, 9, 0x00000044},
{0x61, 0, 0, 0x00000000},
{0x50, 0, 0, 0x0000000e},
{0x54, 0, 0, 0x0000000f},
{0x64, 0, 0, 0x00000002},
{0xc, 0, 0, 0x00000000},
{0x7, 0, 0, 0x00000000},
{0x48, 0, 0, 0x00000010},
{0x15, 0, 1, 0x00000043},
2023-03-20 02:47:22 +00:00
{0x6, 0, 0, 0x00040000},
{0x6, 0, 0, 0x00000000},
// endregion
2023-03-17 07:42:37 +00:00
};
#endif
static struct sock_fprog bpf;
static PACKET_MMAP_RING g_pkgRing;
static NIC_INFO g_nicInfo;
static uv_udp_t g_uvRawSockReq;
2023-03-17 07:42:37 +00:00
void *get_pkg_free_buf() {
int i;
ssize_t ret;
struct tpacket3_hdr *hdr;
for (i = 0; i < g_pkgRing.send.tp_frame_nr; i++) {
hdr = (struct tpacket3_hdr *)(g_pkgRing.tx[0].iov_base + (g_pkgRing.send.tp_frame_size * g_pkgRing.index));
g_pkgRing.index = (g_pkgRing.index + 1) % g_pkgRing.send.tp_frame_nr;
if (!(hdr->tp_status & (TP_STATUS_SEND_REQUEST | TP_STATUS_SENDING))) {
return (U8 *)hdr + TPACKET3_HDRLEN - sizeof(struct sockaddr_ll);
}
}
return NULL;
}
U32 pkg_mmap_tx(U8 *pData, U32 nBytes) {
struct tpacket3_hdr *hdr = (struct tpacket3_hdr *)(pData + sizeof(struct sockaddr_ll) - TPACKET3_HDRLEN);
hdr->tp_next_offset = 0;
hdr->tp_len = nBytes;
hdr->tp_snaplen = nBytes;
hdr->tp_status = TP_STATUS_SEND_REQUEST;
return hdr->tp_len;
}
static int dhcp_resp_offer(PDHCP_PACKAGE pReq, PIPPOOL_INFO pIpInfo, U32 ip) {
U8 *pOpt;
U16 csum;
int tolSize;
PDHCP_PACKAGE pRsp = get_pkg_free_buf();
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));
// TOS
pRsp->vlan_hdr.ip.tos = 0;
// 更新源IP
pRsp->vlan_hdr.ip.saddr = 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_COOKIE_VAL, 4);
pRsp->dhcp.cookie = htonl(DHCP_COOKIE_VAL);
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
pOpt = pRsp->dhcp.options;
// DHCP 消息类型
pOpt += dhcp_add_u8_option(pOpt, OPT_MESSAGETYPE, DHCP_MSG_OFFER);
// 子网掩码
pOpt += dhcp_add_u32_option(pOpt, OPT_NETMASK, htonl(pIpInfo->netMask));
// 租约
pOpt += dhcp_add_u32_option(pOpt, OPT_IPADDRLEASE, htonl(pIpInfo->leaseTime));
// DHCP Server
pOpt += dhcp_add_u32_option(pOpt, OPT_SERVERID, g_nicInfo.ipAddr);
// DNS
if (pIpInfo->primeDNS != 0) {
if (pIpInfo->salveDNS == 0) {
pOpt += dhcp_add_u32_option(pOpt, OPT_DNS, htonl(pIpInfo->primeDNS));
} else {
U8 buf[8] = {0};
U32 *pVal = (U32 *)buf;
*pVal++ = htonl(pIpInfo->primeDNS);
*pVal = htonl(pIpInfo->salveDNS);
pOpt += dhcp_add_buf_option(pOpt, OPT_DNS, buf, 8);
}
}
// 网关
if (pIpInfo->gwAddr != 0) {
pOpt += dhcp_add_u32_option(pOpt, OPT_ROUTER, htonl(pIpInfo->gwAddr));
}
// DHCP 主机名
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, ZLOG_MOD_DHCPD, "OPTIONS size: %ld\n", (intptr_t)(pOpt - pRsp->dhcp.options) + 1);
LOG_MOD(trace, ZLOG_MOD_DHCPD, "Total size: %d\n", tolSize);
// 发送数据
if (pkg_mmap_tx((U8 *)pRsp, tolSize) != tolSize) {
LOG_MOD(error, ZLOG_MOD_DHCPD, "Send package(%u bytes) error\n", tolSize);
return -ERR_SOCK_SEND;
}
return ERR_SUCCESS;
}
2023-03-20 02:47:22 +00:00
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;
PPKG_PROCESS_INFO pWork = (PPKG_PROCESS_INFO)req->data;
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);
return;
}
// 获取消息类型
ret = dhcp_get_option(OPT_MESSAGETYPE, pkg->dhcp.options, optSize, &optMsg);
if (ret != ERR_SUCCESS) {
LOG_MOD(error, ZLOG_MOD_DHCPD, "Get \'message type\' option error %d\n", ret);
return;
}
memset(&reqDhcp, 0, sizeof(DHCP_REQ));
reqDhcp.unicast = pkg->dhcp.flags != 0 ? TRUE : FALSE;
reqDhcp.xid = DHCP_XID(pkg->dhcp.xid);
memcpy(reqDhcp.cliMac, pkg->dhcp.chaddr, ETH_ALEN);
switch (*optMsg.pValue) {
case DHCP_MSG_DISCOVER:
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));
}
ret = dhcp_get_option(OPT_IPADDRLEASE, pkg->dhcp.options, optSize, &opt);
if (ret == ERR_SUCCESS && opt.len == sizeof(U32)) {
reqDhcp.leaseTime = ntohl(*((U32 *)opt.pValue));
}
ret = dhcp_get_option(OPT_CLIENTID, pkg->dhcp.options, optSize, &opt);
if (ret == ERR_SUCCESS) {
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) {
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);
if (ret != ERR_SUCCESS) {
LOG_MOD(error, ZLOG_MOD_DHCPD, "Send Offer error: %d\n", ret);
}
} else {
LOG_MOD(error,
ZLOG_MOD_DHCPD,
"DHCP prepare assign ipaddress error: [%s(%s)]\n",
macStr,
reqDhcp.hostName);
}
break;
case DHCP_MSG_REQUEST:
break;
case DHCP_MSG_RELEASE:
break;
case DHCP_MSG_INFORM:
break;
case DHCP_MSG_DECLINE:
break;
default:
LOG_MOD(error, ZLOG_MOD_DHCPD, "Unkonwn DHCP message type: %d\n", *optMsg.pValue);
LOG_MSG_HEX(trace, pkg, pWork->nSize);
break;
}
//dhcp_option_prase(optMsg, pkg->dhcp.options, pWork->nSize - sizeof(DHCP_PACKAGE));
//LOG_MSG_HEX(trace, pkg, pWork->nSize);
LOG_MSG(info, "vni: %d, xid: 0x%08X\n", VLAN_VNI_ID(pkg->vlan_hdr.vlan.id), DHCP_XID(pkg->dhcp.xid));
2023-03-20 02:47:22 +00:00
#if 0
LOG_MOD(info, ZLOG_MOD_DHCPD, "vlan = %u\n", VXLAN_VIN_ID_PACK(pkg->vlan_hdr.vlan.id));
2023-03-20 02:47:22 +00:00
LOG_MSG(info, "xid: 0x%08X\n", ntohl(pkg->dhcp.xid));
LOG_MSG(info,
"dest mac: %02X:%02X:%02X:%02X:%02X:%02X\n",
pkg->vlan_hdr.eth.h_dest[0],
pkg->vlan_hdr.eth.h_dest[1],
pkg->vlan_hdr.eth.h_dest[2],
pkg->vlan_hdr.eth.h_dest[3],
pkg->vlan_hdr.eth.h_dest[4],
pkg->vlan_hdr.eth.h_dest[5]);
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]);
#endif
2023-03-17 07:42:37 +00:00
}
2023-03-20 02:47:22 +00:00
static void after_msg_recv(uv_work_t *req, int status) {
PPKG_PROCESS_INFO pInfo = (PPKG_PROCESS_INFO)req->data;
PPKG_MSG pMsg = (PPKG_MSG)pInfo->pData;
pMsg->nf -= 1;
if (pMsg->nf == 0) {
LOG_MOD(trace, ZLOG_MOD_DHCPD, "---Free resources: %p\n", pMsg);
2023-03-20 02:47:22 +00:00
free(pMsg->pPkgInfo);
free(pMsg);
}
2023-03-17 07:42:37 +00:00
}
2023-03-20 02:47:22 +00:00
void raw_sock_recv_cb(uv_poll_t *handle, int status, int events) {
static unsigned int block_num = 0;
PRECV_CB_DATA pCbData = handle->data;
2023-03-20 02:47:22 +00:00
if (status >= 0 && (events & UV_READABLE)) {
struct block_desc *pbd = (struct block_desc *)g_pkgRing.rx[block_num].iov_base;
2023-03-20 02:47:22 +00:00
if ((pbd->h1.block_status & TP_STATUS_USER) && (pbd->h1.num_pkts > 0)) {
2023-03-20 02:47:22 +00:00
int i;
struct tpacket3_hdr *ppd;
unsigned int memSize = sizeof(PKG_PROCESS_INFO) * pbd->h1.num_pkts;
PPKG_MSG pMsg = (PPKG_MSG)malloc(sizeof(PKG_MSG));
if (pMsg == NULL) {
LOG_MOD(error, ZLOG_MOD_DHCPD, "Malloc memory error: %lu\n", sizeof(PKG_MSG));
return;
}
LOG_MOD(trace, ZLOG_MOD_DHCPD, "++++Malloc resources: %p\n", pMsg);
memset(pMsg, 0, sizeof(PKG_MSG));
pMsg->pPkgInfo = (PPKG_PROCESS_INFO)malloc(memSize);
if (pMsg->pPkgInfo == NULL) {
LOG_MOD(error, ZLOG_MOD_DHCPD, "Malloc memory error: %u\n", memSize);
free(pMsg);
return;
}
memset(pMsg->pPkgInfo, 0, memSize);
pMsg->nf = pbd->h1.num_pkts;
ppd = (struct tpacket3_hdr *)((uint8_t *)pbd + pbd->h1.offset_to_first_pkt);
for (i = 0; i < pbd->h1.num_pkts; i++) {
pMsg->pPkgInfo[i].pPkgBase = ((uint8_t *)ppd + ppd->tp_mac);
pMsg->pPkgInfo[i].nSize = ppd->tp_snaplen;
pMsg->pPkgInfo[i].uvWork.data = &pMsg->pPkgInfo[i];
pMsg->pPkgInfo[i].pData = pMsg;
if (pCbData) {
uv_queue_work(get_task_manager(),
&(pMsg->pPkgInfo[i].uvWork),
pCbData->work_cb ? pCbData->work_cb : on_sock_recv,
pCbData->after_work_cb ? pCbData->after_work_cb : after_msg_recv);
} else {
uv_queue_work(get_task_manager(), &(pMsg->pPkgInfo[i].uvWork), on_sock_recv, after_msg_recv);
}
ppd = (struct tpacket3_hdr *)((uint8_t *)ppd + ppd->tp_next_offset);
2023-03-20 02:47:22 +00:00
}
2023-03-17 07:42:37 +00:00
}
2023-03-20 02:47:22 +00:00
pbd->h1.block_status = TP_STATUS_KERNEL;
block_num = (block_num + 1) % PKG_MMAP_BLOCKNUM;
2023-03-17 07:42:37 +00:00
}
}
int create_udp_raw_socket(const char *pNicName) {
2023-03-17 07:42:37 +00:00
struct sockaddr_ll addr;
unsigned int size;
int i;
int err;
int v = TPACKET_V3;
2023-03-17 07:42:37 +00:00
// 1. create socket
int sock_fd = socket(PF_PACKET, SOCK_RAW, 0);
2023-03-17 07:42:37 +00:00
if (sock_fd < 0) {
LOG_MOD(error, ZLOG_MOD_DHCPD, "Socket created failure\n");
2023-03-17 07:42:37 +00:00
return -ERR_SOCK_CREATE;
}
2023-03-20 02:47:22 +00:00
// 2. attach filter (no need to call bind)
if ((err = setsockopt(sock_fd, SOL_SOCKET, SO_ATTACH_FILTER, &bpf, sizeof(bpf))) < 0) {
LOG_MOD(error, ZLOG_MOD_DHCPD, "Attaching filter failed: %d\n", err);
2023-03-20 02:47:22 +00:00
return -ERR_SOCK_SETOPT;
}
2023-03-20 02:47:22 +00:00
// 3. set PACKET_MMAP version
if ((err = setsockopt(sock_fd, SOL_PACKET, PACKET_VERSION, &v, sizeof(v))) < 0) {
LOG_MOD(error, ZLOG_MOD_DHCPD, "Set PACKET_VERSION option failed: %d\n", err);
2023-03-20 02:47:22 +00:00
return -ERR_SOCK_SETOPT;
}
// 4. setup PAKCET_MMAP rx ring
memset(&g_pkgRing.recv, 0, sizeof(g_pkgRing.recv));
g_pkgRing.recv.tp_block_size = PKG_MMAP_BLOCKSIZ;
g_pkgRing.recv.tp_frame_size = PKG_MMAP_FRAMESIZ;
g_pkgRing.recv.tp_block_nr = PKG_MMAP_BLOCKNUM;
g_pkgRing.recv.tp_frame_nr = (PKG_MMAP_BLOCKSIZ * PKG_MMAP_BLOCKNUM) / PKG_MMAP_FRAMESIZ;
g_pkgRing.recv.tp_retire_blk_tov = 60;
g_pkgRing.recv.tp_feature_req_word = TP_FT_REQ_FILL_RXHASH;
2023-03-20 02:47:22 +00:00
if ((err = setsockopt(sock_fd, SOL_PACKET, PACKET_RX_RING, &g_pkgRing.recv, sizeof(g_pkgRing.recv))) < 0) {
LOG_MOD(error, ZLOG_MOD_DHCPD, "Set PACKET_RX_RING option failed: %d\n", err);
2023-03-20 02:47:22 +00:00
return -ERR_SOCK_SETOPT;
}
// 5. setup PACKET_MMAP tx ring
memset(&g_pkgRing.send, 0, sizeof(g_pkgRing.send));
g_pkgRing.send.tp_block_size = PKG_MMAP_BLOCKSIZ;
g_pkgRing.send.tp_frame_size = PKG_MMAP_FRAMESIZ;
g_pkgRing.send.tp_block_nr = PKG_MMAP_BLOCKNUM;
g_pkgRing.send.tp_frame_nr = (PKG_MMAP_BLOCKSIZ * PKG_MMAP_BLOCKNUM) / PKG_MMAP_FRAMESIZ;
if ((err = setsockopt(sock_fd, SOL_PACKET, PACKET_TX_RING, &g_pkgRing.send, sizeof(g_pkgRing.recv))) < 0) {
LOG_MOD(error, ZLOG_MOD_DHCPD, "Set PACKET_TX_RING option failed: %d\n", err);
return -ERR_SOCK_SETOPT;
}
// 6. mmap RX/TX ring
size = g_pkgRing.recv.tp_block_size * g_pkgRing.recv.tp_block_nr +
g_pkgRing.send.tp_block_size * g_pkgRing.send.tp_block_nr;
g_pkgRing.map_recv = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_LOCKED | MAP_POPULATE, sock_fd, 0);
g_pkgRing.map_send = g_pkgRing.map_recv + g_pkgRing.recv.tp_block_size * g_pkgRing.recv.tp_block_nr;
2023-03-20 02:47:22 +00:00
if (g_pkgRing.map_recv == MAP_FAILED) {
LOG_MOD(error, ZLOG_MOD_DHCPD, "MMAP socket ring failed\n");
perror("title");
2023-03-20 02:47:22 +00:00
return -ERR_MMAP_MEMORY;
}
LOG_MOD(trace, ZLOG_MOD_DHCPD, "size = %u\n", size);
LOG_MOD(trace, ZLOG_MOD_DHCPD, "MMAP address recv = %p, send = %p\n", g_pkgRing.map_recv, g_pkgRing.map_send);
2023-03-20 02:47:22 +00:00
// 7. malloc read buffer
g_pkgRing.rx = malloc(g_pkgRing.recv.tp_block_nr * sizeof(struct iovec));
if (g_pkgRing.rx == NULL) {
LOG_MOD(error,
ZLOG_MOD_DHCPD,
"Malloc memory failed: %lu\n",
g_pkgRing.recv.tp_block_nr * sizeof(struct iovec));
2023-03-20 02:47:22 +00:00
return -ERR_MMAP_MEMORY;
}
memset(g_pkgRing.rx, 0, g_pkgRing.recv.tp_block_nr * sizeof(struct iovec));
for (i = 0; i < g_pkgRing.recv.tp_block_nr; ++i) {
g_pkgRing.rx[i].iov_base = g_pkgRing.map_recv + (i * g_pkgRing.recv.tp_block_size);
g_pkgRing.rx[i].iov_len = g_pkgRing.recv.tp_block_size;
2023-03-20 02:47:22 +00:00
}
// 8. malloc send buffer
g_pkgRing.tx = malloc(g_pkgRing.send.tp_block_nr * sizeof(struct iovec));
if (g_pkgRing.tx == NULL) {
LOG_MOD(error,
ZLOG_MOD_DHCPD,
"Malloc memory failed: %lu\n",
g_pkgRing.send.tp_block_nr * sizeof(struct iovec));
munmap(g_pkgRing.map_recv, size * 2);
return -ERR_MMAP_MEMORY;
}
memset(g_pkgRing.tx, 0, g_pkgRing.send.tp_block_nr * sizeof(struct iovec));
for (i = 0; i < g_pkgRing.send.tp_block_nr; ++i) {
g_pkgRing.tx[i].iov_base = g_pkgRing.map_send + (i * g_pkgRing.send.tp_block_size);
g_pkgRing.tx[i].iov_len = g_pkgRing.send.tp_block_size;
}
// 9. bind socket
memset(&addr, 0, sizeof(struct sockaddr_ll));
addr.sll_ifindex = (int)if_nametoindex(pNicName);
addr.sll_family = PF_PACKET;
2023-03-17 07:42:37 +00:00
addr.sll_protocol = htons(ETH_P_ALL);
2023-03-20 02:47:22 +00:00
addr.sll_hatype = 0;
addr.sll_pkttype = 0;
addr.sll_halen = 0;
2023-03-17 07:42:37 +00:00
if ((err = bind(sock_fd, (struct sockaddr *)&addr, sizeof(struct sockaddr_ll))) < 0) {
LOG_MOD(error, ZLOG_MOD_DHCPD, "Bind raw socket failed: %d\n", err);
2023-03-17 07:42:37 +00:00
return -ERR_SOCK_SETOPT;
}
g_pkgRing.sock = sock_fd;
return ERR_SUCCESS;
}
void socket_send_task(uv_timer_t *UNUSED(pArg)) {
int i;
struct tpacket3_hdr *hdr;
for (i = 0; i < g_pkgRing.send.tp_frame_nr && g_pkgRing.sock != 0; i++) {
hdr = (struct tpacket3_hdr *)(g_pkgRing.tx[0].iov_base + (g_pkgRing.send.tp_frame_size * i));
if ((hdr->tp_status & TP_STATUS_SEND_REQUEST) || (hdr->tp_status & TP_STATUS_SENDING)) {
ssize_t ret = sendto(g_pkgRing.sock, NULL, 0, MSG_DONTWAIT, NULL, sizeof(struct sockaddr_ll));
if (ret == -1) {
LOG_MOD(error, ZLOG_MOD_DHCPD, "Send packet error\n");
}
break;
}
}
2023-03-17 07:42:37 +00:00
}
void init_filter(const char *pNetFilter) {
#ifdef USED_DEFAULT_BPF
bpf.len = sizeof(g_filterCode) / (sizeof(struct sock_filter));
bpf.filter = g_filterCode;
#else
static pcap_t *pd;
pd = pcap_open_dead(DLT_EN10MB, MAXIMUM_SNAPLEN);
struct bpf_program fcode;
//char *cmd_buf = "vlan and udp and port 67 and port 68";
pcap_compile(pd, &fcode, pNetFilter, 1, 0);
struct bpf_insn *insn = fcode.bf_insns;
struct sock_filter *g_filters = (struct sock_filter *)malloc(fcode.bf_len * sizeof(struct sock_filter));
for (int i = 0; i < fcode.bf_len; ++insn, ++i) {
g_filters[i].code = insn->code;
g_filters[i].jt = insn->jt;
g_filters[i].jf = insn->jf;
g_filters[i].k = insn->k;
}
bpf.len = fcode.bf_len;
bpf.filter = g_filters;
2023-04-19 01:34:38 +00:00
pcap_close(pd);
pcap_freecode(&fcode);
#endif
}
void init_raw_socket_poll(void *pRecv, void *pClean) {
static RECV_CB_DATA rcData;
static uv_poll_t uvSocket;
static uv_timer_t uvTm;
uv_udp_init(get_task_manager(), &g_uvRawSockReq);
uv_udp_open(&g_uvRawSockReq, g_pkgRing.sock);
uv_poll_init_socket(get_task_manager(), &uvSocket, g_pkgRing.sock);
rcData.work_cb = pRecv;
rcData.after_work_cb = pClean;
uvSocket.data = &rcData;
uv_poll_start(&uvSocket, UV_READABLE, raw_sock_recv_cb);
uv_timer_init(get_task_manager(), &uvTm);
uv_timer_start(&uvTm, socket_send_task, 3000, 100);
}
2023-03-17 07:42:37 +00:00
int dhcpd_init() {
int ret;
size_t size = MAX_PATH;
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);
2023-03-17 07:42:37 +00:00
init_filter("vlan and udp and port 67 and port 68");
ret = create_udp_raw_socket(g_nicInfo.pIfName);
if (ret != ERR_SUCCESS) {
LOG_MOD(error, ZLOG_MOD_DHCPD, "Create receive RAW Socket Error: %s(%d)\n", getErrorEnumNameString(-ret), ret);
return ret;
2023-03-17 07:42:37 +00:00
}
dhcp_user_mgr_init();
dhcp_option_cfg_init();
2023-03-31 06:32:32 +00:00
dhcp_lease_init();
2023-03-17 07:42:37 +00:00
init_raw_socket_poll(NULL, NULL);
2023-03-17 07:42:37 +00:00
return ERR_SUCCESS;
}
2023-03-17 07:42:37 +00:00
int dhcp_uninit() {
unsigned int size = g_pkgRing.recv.tp_block_size * g_pkgRing.recv.tp_block_nr +
g_pkgRing.send.tp_block_size * g_pkgRing.send.tp_block_nr;
close(g_pkgRing.sock);
g_pkgRing.sock = -1;
if (g_pkgRing.tx) {
free(g_pkgRing.tx);
}
if (g_pkgRing.rx) {
free(g_pkgRing.rx);
}
munmap(g_pkgRing.map_recv, size);
2023-03-17 07:42:37 +00:00
return ERR_SUCCESS;
}