vcpe/dhcp_tools/uv_rawsocket.c

285 lines
8.7 KiB
C
Raw Normal View History

//
// Created by xajhuang on 2023/4/20.
//
#include <uv.h>
#include <string.h>
#include <sys/time.h>
#include "user_errno.h"
#include "dhcp_network.h"
#include "dhcp_options.h"
#include "zlog_module.h"
#include "main.h"
#include "rfc2131.h"
#include "misc.h"
static U8 g_dhcpReqParams[] = {0x01, 0x1c, 0x02, 0x03, 0x0f, 0x06, 0x77, 0x0c, 0x2c, 0x2f, 0x1a, 0x79, 0x2a};
static char *g_pNicName = NULL;
static void pkg_init_head(PDHCP_PACKAGE p, PDHCP_INFO pInfo) {
// 目的地 MAC 地址
memset(p->hdr.eth.h_dest, 0xFF, ETH_ALEN);
// 源 MAC 地址
memcpy(p->hdr.eth.h_source, pInfo->mac, ETH_ALEN);
#if VLAN_SUPPORT
// 协议 VLAN
p->hdr.eth.h_proto = htons(ETH_P_8021Q);
// VLAN 隧道信息
p->hdr.vlan.id = htons(pInfo->vni);
p->hdr.vlan.type = htons(ETH_P_IP);
#else
// 协议 VLAN
p->hdr.eth.h_proto = htons(ETH_P_IP);
#endif
// IP 头
p->hdr.ip.version = IPVERSION;
p->hdr.ip.ihl = 5;
p->hdr.ip.tos = 0;
p->hdr.ip.tot_len = 0;
p->hdr.ip.id = 0;
p->hdr.ip.frag_off = 0;
p->hdr.ip.ttl = 128;
p->hdr.ip.protocol = IPPROTO_UDP;
p->hdr.ip.check = 0;
p->hdr.ip.saddr = INADDR_ANY;
p->hdr.ip.daddr = INADDR_BROADCAST;
// UDP 头
p->hdr.udp.source = htons(DHCP_CLI_PORT);
p->hdr.udp.dest = htons(DHCP_SVR_PORT);
p->hdr.udp.len = 0;
p->hdr.udp.check = 0;
// DHCP 协议内容
p->dhcp.op = BOOTP_REQUEST;
p->dhcp.htype = 0x01;
p->dhcp.hlen = ETH_ALEN;
p->dhcp.hops = 0;
p->dhcp.xid = 0;
p->dhcp.secs = 0;
p->dhcp.flags = 0;
p->dhcp.ciaddr = INADDR_ANY;
p->dhcp.yiaddr = INADDR_ANY;
p->dhcp.siaddr = INADDR_ANY;
p->dhcp.giaddr = INADDR_ANY;
memcpy(p->dhcp.chaddr, pInfo->mac, ETH_ALEN);
p->dhcp.cookie = htonl(DHCP_COOKIE_VAL);
}
static void cacl_package_checksum(PDHCP_PACKAGE p, int tolSize) {
U16 csum;
// 计算 IP 数据长度
p->hdr.ip.tot_len = htons(tolSize - sizeof(struct ethhdr) - sizeof(struct vlan_hdr));
// 计算 UDP 数据长度
p->hdr.udp.len = htons(tolSize - sizeof(struct ethhdr) - sizeof(struct vlan_hdr) - sizeof(struct iphdr));
// 计算 IP 校验和
csum = htons(ip_checksum((unsigned char *)&p->hdr.ip));
p->hdr.ip.check = htons(csum);
// 计算 UDP 校验和
csum = htons(udp_checksum(p->hdr.ip.saddr, p->hdr.ip.daddr, (unsigned char *)&p->hdr.udp));
p->hdr.udp.check = htons(csum);
}
U8 *dhcp_create_request_req(PDHCP_INFO pInfo, int *pOutSize) {
U8 *pOpt;
int tolSize;
U8 *pReqData = (U8 *)malloc(MAX_DHCP_PKG_SIZE);
if (pReqData) {
PDHCP_PACKAGE p = (PDHCP_PACKAGE)pReqData;
memset(pReqData, 0, MAX_DHCP_PKG_SIZE);
pkg_init_head(p, pInfo);
p->dhcp.xid = htonl(pInfo->offerRsp.xid);
// DHCP Options
pOpt = p->dhcp.options;
// DHCP 消息类型
pOpt += dhcp_add_u8_option(pOpt, OPT_MESSAGETYPE, DHCP_MSG_REQUEST);
// DHCP 请求参数列表
pOpt += dhcp_add_buf_option(pOpt, OPT_PARAMREQLIST, g_dhcpReqParams, 13);
// DHCP 主机名
pOpt += dhcp_add_string_option(pOpt, OPT_HOSTNAME, pInfo->hostname);
// DHCP Server 主机
pOpt += dhcp_add_u32_option(pOpt, OPT_SERVERID, htonl(pInfo->offerRsp.svrIp));
// DHCP 请求分配IP
pOpt += dhcp_add_u32_option(pOpt, OPT_REQUESTEDIPADDR, htonl(pInfo->offerRsp.ipAddr));
// 结束
*pOpt = OPT_END;
// 计算包总长度
tolSize = (int)((pOpt - p->dhcp.options) + 1 + sizeof(DHCP_PACKAGE));
cacl_package_checksum(p, tolSize);
*pOutSize = tolSize;
}
return pReqData;
}
U8 *dhcp_create_discover_req(PDHCP_INFO pInfo, int *pOutSize) {
U8 *pOpt;
int tolSize;
U8 *pReqData = (U8 *)malloc(MAX_DHCP_PKG_SIZE);
if (pReqData) {
PDHCP_PACKAGE p = (PDHCP_PACKAGE)pReqData;
memset(pReqData, 0, MAX_DHCP_PKG_SIZE);
pkg_init_head(p, pInfo);
p->dhcp.xid = htonl((rand_number() & 0xFF000000) + pInfo->index);
// DHCP Options
pOpt = p->dhcp.options;
// DHCP 消息类型
pOpt += dhcp_add_u8_option(pOpt, OPT_MESSAGETYPE, DHCP_MSG_DISCOVER);
// DHCP 主机名
pOpt += dhcp_add_string_option(pOpt, OPT_HOSTNAME, pInfo->hostname);
// DHCP 请求参数列表
pOpt += dhcp_add_buf_option(pOpt, OPT_PARAMREQLIST, g_dhcpReqParams, 13);
// 结束
*pOpt = OPT_END;
// 计算包总长度
tolSize = (int)((pOpt - p->dhcp.options) + 1 + sizeof(DHCP_PACKAGE));
cacl_package_checksum(p, tolSize);
*pOutSize = tolSize;
}
return pReqData;
}
static void on_dhcp_recv(uv_work_t *req) {
PDHCP_INFO pInfo;
DHCP_RSP rspDhcp;
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);
// Check op flag
if (pkg->dhcp.op != BOOTP_REPLY) {
LOG_MOD(error, ZM_DHCP_NET, "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, ZM_DHCP_NET, "Get \'message type\' option error %d\n", ret);
return;
}
pInfo = get_dhcp_info_by_id(DHCP_XID(pkg->dhcp.xid));
if (pInfo == NULL) {
LOG_MOD(error, ZM_DHCP_NET, "Unknown Client %d\n", DHCP_XID(pkg->dhcp.xid) & 0xFFFFFF);
return;
}
memset(&rspDhcp, 0, sizeof(DHCP_RSP));
rspDhcp.xid = DHCP_XID(pkg->dhcp.xid);
rspDhcp.ipAddr = ntohl(pkg->dhcp.yiaddr);
memcpy(rspDhcp.cliMac, pkg->dhcp.chaddr, ETH_ALEN);
memcpy(rspDhcp.svrHostname, pkg->dhcp.sname, 64);
switch (*optMsg.pValue) {
case DHCP_MSG_OFFER:
ret = dhcp_get_option(OPT_NETMASK, pkg->dhcp.options, optSize, &opt);
if (ret == ERR_SUCCESS && opt.len == sizeof(U32)) {
rspDhcp.netmask = ntohl(*((U32 *)opt.pValue));
}
ret = dhcp_get_option(OPT_DNS, pkg->dhcp.options, optSize, &opt);
if (ret == ERR_SUCCESS) {
U32 *pVal = (U32 *)opt.pValue;
rspDhcp.primeDNS = ntohl(*pVal);
if (optSize == 8) {
pVal++;
rspDhcp.secondDNS = ntohl(*pVal);
}
}
ret = dhcp_get_option(OPT_ROUTER, pkg->dhcp.options, optSize, &opt);
if (ret == ERR_SUCCESS) {
rspDhcp.route = ntohl(*((U32 *)opt.pValue));
}
ret = dhcp_get_option(OPT_IPADDRLEASE, pkg->dhcp.options, optSize, &opt);
if (ret == ERR_SUCCESS) {
rspDhcp.leaseTime = ntohl(*((U32 *)opt.pValue));
}
ret = dhcp_get_option(OPT_SERVERID, pkg->dhcp.options, optSize, &opt);
if (ret == ERR_SUCCESS) {
rspDhcp.svrIp = ntohl(*((U32 *)opt.pValue));
}
ret = dhcp_get_option(OPT_DOMAINNAME, pkg->dhcp.options, optSize, &opt);
if (ret == ERR_SUCCESS) {
strncpy(rspDhcp.domainName, (char *)opt.pValue, MIN((int)opt.len, 64));
}
pInfo->step = STEP_OFFER;
pInfo->status = STA_RECV_RSP;
cacheDhcpOfferBuffer(pInfo, pWork->pPkgBase, pWork->nSize);
memcpy(&pInfo->offerRsp, &rspDhcp, sizeof(DHCP_RSP));
gettimeofday(&pInfo->pOfferBuf.tm, NULL);
break;
case DHCP_MSG_ACK:
pInfo->step = STEP_ACK;
pInfo->status = STA_RECV_RSP;
cacheDhcpAckBuffer(pInfo, pWork->pPkgBase, pWork->nSize);
memcpy(&pInfo->ackRsp, &rspDhcp, sizeof(DHCP_RSP));
gettimeofday(&pInfo->pAckBuf.tm, NULL);
break;
case DHCP_MSG_NAK:
break;
}
}
int dhcp_tools_init_network(const char *pNicName) {
int ret;
if (g_pNicName == NULL) {
g_pNicName = strdup(pNicName);
} else if (strcmp(pNicName, g_pNicName) != 0) {
dhcp_uninit();
free(g_pNicName);
g_pNicName = strdup(pNicName);
} else {
return ERR_SUCCESS;
}
#if VLAN_SUPPORT
init_filter("vlan and udp and dst port 68");
#else
init_filter("udp and dst port 68");
#endif
ret = create_udp_raw_socket(g_pNicName);
if (ret != ERR_SUCCESS) {
LOG_MOD(error, ZM_DHCP_NET, "Create receive RAW Socket Error: %s(%d)\n", getErrorEnumNameString(-ret), ret);
return ret;
}
dhcp_option_cfg_init();
init_raw_socket_poll(on_dhcp_recv, NULL);
return ERR_SUCCESS;
}