221 lines
6.8 KiB
C
221 lines
6.8 KiB
C
//
|
|
// Created by xajhuang on 2023/4/20.
|
|
//
|
|
#include <uv.h>
|
|
#include <linux/filter.h>
|
|
#include <string.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 char *g_pNicName = NULL;
|
|
|
|
static struct sock_filter g_filterCode[] = {
|
|
// 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},
|
|
{0x30, 0, 0, 0xfffff030},
|
|
{0x15, 7, 0, 0x00000001},
|
|
{0x0, 0, 0, 0x00000004},
|
|
{0x2, 0, 0, 0x00000000},
|
|
{0x2, 0, 0, 0x00000001},
|
|
{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},
|
|
{0x6, 0, 0, 0x00040000},
|
|
{0x6, 0, 0, 0x00000000},
|
|
// endregion
|
|
};
|
|
|
|
static struct sock_fprog bpf = {
|
|
.len = sizeof(g_filterCode) / (sizeof(struct sock_filter)),
|
|
.filter = g_filterCode,
|
|
};
|
|
|
|
U8 *dhcp_create_discover_req(PDHCP_INFO pInfo, int *pOutSize) {
|
|
static U8 reqParams[] = {0x01, 0x1c, 0x02, 0x03, 0x0f, 0x06, 0x77, 0x0c, 0x2c, 0x2f, 0x1a, 0x79, 0x2a};
|
|
U8 *pOpt;
|
|
U16 csum;
|
|
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);
|
|
|
|
// 目的地 MAC 地址
|
|
memset(p->vlan_hdr.eth.h_dest, 0xFF, ETH_ALEN);
|
|
// 源 MAC 地址
|
|
memcpy(p->vlan_hdr.eth.h_source, pInfo->mac, ETH_ALEN);
|
|
// 协议 VLAN
|
|
p->vlan_hdr.eth.h_proto = htons(ETH_P_8021Q);
|
|
|
|
// VLAN 隧道信息
|
|
p->vlan_hdr.vlan.id = htons(pInfo->vni);
|
|
p->vlan_hdr.vlan.type = htons(ETH_P_IP);
|
|
|
|
// IP 头
|
|
p->vlan_hdr.ip.version = IPVERSION;
|
|
p->vlan_hdr.ip.ihl = 5;
|
|
p->vlan_hdr.ip.tos = 0x10;
|
|
p->vlan_hdr.ip.tot_len = 0;
|
|
p->vlan_hdr.ip.id = 0;
|
|
p->vlan_hdr.ip.frag_off = 0;
|
|
p->vlan_hdr.ip.ttl = 128;
|
|
p->vlan_hdr.ip.protocol = IPPROTO_UDP;
|
|
p->vlan_hdr.ip.check = 0;
|
|
p->vlan_hdr.ip.saddr = INADDR_ANY;
|
|
p->vlan_hdr.ip.daddr = INADDR_BROADCAST;
|
|
|
|
// UDP 头
|
|
p->vlan_hdr.udp.source = htons(DHCP_CLI_PORT);
|
|
p->vlan_hdr.udp.dest = htons(DHCP_SVR_PORT);
|
|
p->vlan_hdr.udp.len = 0;
|
|
p->vlan_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 = htonl(rand_number());
|
|
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);
|
|
|
|
// 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, reqParams, 13);
|
|
// 结束
|
|
*pOpt = OPT_END;
|
|
|
|
// 计算包总长度
|
|
tolSize = (int)((pOpt - p->dhcp.options) + 1 + sizeof(DHCP_PACKAGE));
|
|
|
|
// 计算 IP 数据长度
|
|
p->vlan_hdr.ip.tot_len = htons(tolSize - sizeof(struct ethhdr) - sizeof(struct vlan_hdr));
|
|
// 计算 UDP 数据长度
|
|
p->vlan_hdr.udp.len = htons(tolSize - sizeof(struct ethhdr) - sizeof(struct vlan_hdr) - sizeof(struct iphdr));
|
|
|
|
// 计算 IP 校验和
|
|
csum = htons(ip_checksum((unsigned char *)&p->vlan_hdr.ip));
|
|
p->vlan_hdr.ip.check = htons(csum);
|
|
|
|
// 计算 UDP 校验和
|
|
csum = htons(udp_checksum(p->vlan_hdr.ip.saddr, p->vlan_hdr.ip.daddr, (unsigned char *)&p->vlan_hdr.udp));
|
|
p->vlan_hdr.udp.check = htons(csum);
|
|
|
|
*pOutSize = tolSize;
|
|
}
|
|
|
|
return pReqData;
|
|
}
|
|
|
|
static void on_dhcp_recv(uv_work_t *req) {
|
|
printf("+++++++++++++recv\n");
|
|
//LOG_MOD_HEX(debug, ZLOG_MOD_MAIN, dhcp_create_discover_req(&info), 512);
|
|
}
|
|
|
|
int dhcp_tools_init_network(const char *pNicName) {
|
|
static RECV_CB_DATA rcData;
|
|
static uv_poll_t uvSocket;
|
|
static uv_timer_t uvTm;
|
|
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;
|
|
}
|
|
|
|
init_filter("vlan and udp and port 67 and port 68");
|
|
|
|
ret = create_udp_raw_socket(g_pNicName);
|
|
if (ret != ERR_SUCCESS) {
|
|
LOG_MOD(error, ZLOG_MOD_DHCPD, "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;
|
|
} |