// // Created by xajhuang on 2023/3/16. // #include #include #include #include #include #include #include #include #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" #include "lease.h" #define MAXIMUM_SNAPLEN (262144) /* 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 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 #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}, #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}, {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 }; #endif static struct sock_fprog bpf; static PACKET_MMAP_RING g_pkgRing; static NIC_INFO g_nicInfo; static uv_udp_t g_uvRawSockReq; static DHCP_WORK_MODE g_dhcpMode; VLAN_TYPE get_package_vlan_type(void *pBuf) { U8 *p = (U8 *)pBuf; if (p[12] == 0x81 && p[13] == 0x00 && p[16] == 0x81 && p[17] == 0x00) { return VLAN_LEVEL2; } else if (p[12] == 0x81 && p[13] == 0x00) { return VLAN_LEVEL1; } else { return VLAN_NONE; } } U32 dhcp_get_default_netmask() { return g_nicInfo.netmask; } void *get_pkg_free_buf() { int i; 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 void add_eth_head(U8 *pRsp, struct ethhdr *pEth, int isBst) { struct ethhdr *p = (struct ethhdr *)pRsp; // 二层头 // 目的 MAC 地址 if (!isBst) { memcpy(p->h_dest, pEth->h_source, ETH_ALEN); } else { memset(p->h_dest, 0xFF, ETH_ALEN); } // 源 MAC 地址 memcpy(p->h_source, g_nicInfo.macAddr, ETH_ALEN); // protol p->h_proto = pEth->h_proto; } static void add_vlan_head(U8 *pRsp, PVLAN_PKG_HDR1 pvHdr) { PVLAN_PKG_HDR1 p = (PVLAN_PKG_HDR1)pRsp; // QinQ 隧道 p->vlan.id = pvHdr->vlan.id; p->vlan.type = pvHdr->vlan.type; } static void add_vlan2_head(U8 *pRsp, PVLAN_PKG_HDR2 pvHdr) { PVLAN_PKG_HDR2 p = (PVLAN_PKG_HDR2)pRsp; // QinQ 隧道 p->vlan.id1 = pvHdr->vlan.id1; p->vlan.h_type = pvHdr->vlan.h_type; p->vlan.id2 = pvHdr->vlan.id2; p->vlan.type = pvHdr->vlan.type; } static void add_ip_head(struct iphdr *p, struct iphdr *pIp) { // IP 头 memcpy(p, pIp, sizeof(struct iphdr)); // TOS p->tos = 0; // 更新源IP p->saddr = g_nicInfo.ipAddr; // 更新目的IP地址,广播255.255.255.255 if (pIp->saddr == 0) { p->daddr = 0xFFFFFFFF; } else { p->daddr = pIp->saddr; } } static void add_udp_head(struct udphdr *p, struct udphdr *pUdp) { // UDP 头 // 目的端口 p->dest = pUdp->source; // 源端口 p->source = pUdp->dest; } static void add_dhcp_common(PDHCP_PROTO p, PDHCP_PROTO pDhcp) { //DHCP 协议 // 返回类型 p->op = BOOTP_REPLY; // 地址类型长度 p->htype = pDhcp->htype; // 地址长度 p->hlen = pDhcp->hlen; // xid p->xid = pDhcp->xid; // 客户端 MAC 地址 memcpy(p->chaddr, pDhcp->chaddr, ETH_ALEN); // DHCP服务端主机名 memcpy(p->sname, g_nicInfo.hostname, MIN(64, strlen(g_nicInfo.hostname))); // Magic Cookie: DHCP // // memcpy(&pRsp->dhcp.cookie, DHCP_COOKIE_VAL, 4); p->cookie = htonl(DHCP_COOKIE_VAL); p->hops = 0; p->secs = 0; p->flags = 0; p->ciaddr = 0; p->siaddr = 0; p->giaddr = 0; } static PDHCP_PROTO fill_pkg(U8 *pRsp, U8 *pReq) { U8 *p; struct ethhdr *pEth = (struct ethhdr *)pReq; struct iphdr *pIp = NULL; struct udphdr *pUdp = NULL; PDHCP_PROTO pDhcp = NULL; memset(pRsp, 0, MAX_DHCP_PKG_SIZE); switch (get_package_vlan_type(pReq)) { default: pIp = (struct iphdr *)(pReq + IP_HDR_OFFSET); pUdp = (struct udphdr *)(UDP_HDR_OFFSET); pDhcp = (PDHCP_PROTO)((U8 *)pReq + DHCP_OFFSET); p = pRsp + sizeof(struct ethhdr); break; case VLAN_LEVEL1: pIp = (struct iphdr *)(pReq + IP_HDR_OFFSET + sizeof(VLAN_HDR)); pUdp = (struct udphdr *)(pReq + UDP_HDR_OFFSET + sizeof(VLAN_HDR)); pDhcp = (PDHCP_PROTO)((U8 *)pReq + DHCP_OFFSET + sizeof(VLAN_HDR)); add_vlan_head(pRsp, (PVLAN_PKG_HDR1)pReq); p = pRsp + sizeof(struct ethhdr) + sizeof(VLAN_HDR); break; case VLAN_LEVEL2: pIp = (struct iphdr *)(pReq + IP_HDR_OFFSET + sizeof(VLAN_HDR2)); pUdp = (struct udphdr *)(pReq + UDP_HDR_OFFSET + sizeof(VLAN_HDR2)); pDhcp = (PDHCP_PROTO)((U8 *)pReq + DHCP_OFFSET + sizeof(VLAN_HDR2)); add_vlan2_head(pRsp, (PVLAN_PKG_HDR2)pReq); p = pRsp + sizeof(struct ethhdr) + sizeof(VLAN_HDR2); break; } add_eth_head(pRsp, pEth, (pIp->saddr == 0) ? TRUE : FALSE); add_ip_head((struct iphdr *)p, pIp); p += sizeof(struct iphdr); add_udp_head((struct udphdr *)p, pUdp); p += sizeof(struct udphdr); add_dhcp_common((PDHCP_PROTO)p, pDhcp); return (PDHCP_PROTO)p; } static int dhcp_prepare_tx(U8 *pRsp, U32 optSize) { struct iphdr *pIp = NULL; struct udphdr *pUdp = NULL; U16 csum; U32 tolSize; U8 vlanSize = 0; switch (get_package_vlan_type(pRsp)) { default: pIp = (struct iphdr *)(pRsp + IP_HDR_OFFSET); pUdp = (struct udphdr *)(UDP_HDR_OFFSET); // 计算包总长度 tolSize = optSize + sizeof(DHCP_PROTO) + DHCP_OFFSET; break; case VLAN_LEVEL1: pIp = (struct iphdr *)(pRsp + IP_HDR_OFFSET + sizeof(VLAN_HDR)); pUdp = (struct udphdr *)(pRsp + UDP_HDR_OFFSET + sizeof(VLAN_HDR)); // 计算包总长度 tolSize = optSize + sizeof(DHCP_PROTO) + DHCP_OFFSET + sizeof(VLAN_HDR); vlanSize = sizeof(VLAN_HDR); break; case VLAN_LEVEL2: pIp = (struct iphdr *)(pRsp + IP_HDR_OFFSET + sizeof(VLAN_HDR2)); pUdp = (struct udphdr *)(pRsp + UDP_HDR_OFFSET + sizeof(VLAN_HDR2)); // 计算包总长度 tolSize = optSize + sizeof(DHCP_PROTO) + DHCP_OFFSET + sizeof(VLAN_HDR2); vlanSize = sizeof(VLAN_HDR2); break; } // 计算 IP 数据长度 pIp->tot_len = htons(tolSize - sizeof(struct ethhdr) - vlanSize); // 计算 UDP 数据长度 pUdp->len = htons(tolSize - sizeof(struct ethhdr) - vlanSize - sizeof(struct iphdr)); // 计算 IP 校验和 csum = htons(ip_checksum((unsigned char *)pIp)); pIp->check = htons(csum); // 计算 UDP 校验和 csum = htons(udp_checksum(pIp->saddr, pIp->daddr, (unsigned char *)pUdp)); pUdp->check = htons(csum); LOG_MOD(trace, ZM_DHCP_NET, "Total size: %d\n", tolSize); // 发送数据 if (pkg_mmap_tx((U8 *)pRsp, tolSize) != tolSize) { LOG_MOD(error, ZM_DHCP_NET, "Send package(%u bytes) error\n", tolSize); return -ERR_SOCK_SEND; } return ERR_SUCCESS; } static int dhcp_resp_nack(void *pReq) { U8 *pOpt; PDHCP_PROTO pDhcp = NULL; U8 *pRsp = get_pkg_free_buf(); if (pRsp == NULL) { LOG_MOD(error, ZM_DHCP_NET, "Malloc memory error: %u\n", MAX_DHCP_PKG_SIZE); return -ERR_MALLOC_MEMORY; } pDhcp = fill_pkg(pRsp, (U8 *)pReq); // DHCP Options pOpt = pDhcp->options; // DHCP 消息类型 pOpt += dhcp_add_u8_option(pOpt, OPT_MESSAGETYPE, DHCP_MSG_NAK); *pOpt = OPT_END; return dhcp_prepare_tx(pRsp, (int)((pOpt - pDhcp->options) + 1)); } static int dhcp_resp_ack(void *pReq, PPOOL_CTX pIpInfo) { U8 *pOpt; PDHCP_PROTO pDhcp = NULL; U8 *pRsp = get_pkg_free_buf(); if (pRsp == NULL) { LOG_MOD(error, ZM_DHCP_NET, "Malloc memory error: %u\n", MAX_DHCP_PKG_SIZE); return -ERR_MALLOC_MEMORY; } pDhcp = fill_pkg((U8 *)pRsp, (U8 *)pReq); // 分配的 IP 地址 pDhcp->yiaddr = htonl(pIpInfo->minAddr); // DHCP Options pOpt = pDhcp->options; // DHCP 消息类型 pOpt += dhcp_add_u8_option(pOpt, OPT_MESSAGETYPE, DHCP_MSG_ACK); // 子网掩码 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; return dhcp_prepare_tx(pRsp, (int)((pOpt - pDhcp->options) + 1)); } static int dhcp_resp_offer(void *pReq, PPOOL_CTX pIpInfo, U32 ip) { U8 *pOpt; PDHCP_PROTO pDhcp = NULL; U8 *pRsp = get_pkg_free_buf(); if (pRsp == NULL) { LOG_MOD(error, ZM_DHCP_NET, "Malloc memory error: %u\n", MAX_DHCP_PKG_SIZE); return -ERR_MALLOC_MEMORY; } pDhcp = fill_pkg(pRsp, (U8 *)pReq); // 分配的 IP 地址 pDhcp->yiaddr = htonl(ip); // DHCP Options pOpt = pDhcp->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; return dhcp_prepare_tx(pRsp, (int)((pOpt - pDhcp->options) + 1)); } PDHCP_PROTO get_dhcp_date(void *pBuf, U32 *pOptSize, U32 bufSize) { U8 *p = (U8 *)pBuf; U32 hdrCom = sizeof(struct ethhdr) + sizeof(struct iphdr) + sizeof(struct udphdr); if (p[12] == 0x81 && p[13] == 0x00 && p[16] == 0x81 && p[17] == 0x00) { *pOptSize = bufSize - hdrCom - sizeof(DHCP_PROTO) - sizeof(VLAN_HDR2); return (PDHCP_PROTO)(p + hdrCom + 8); } else if (p[12] == 0x81 && p[13] == 0x00) { *pOptSize = bufSize - hdrCom - sizeof(DHCP_PROTO) - sizeof(VLAN_HDR); return (PDHCP_PROTO)(p + hdrCom + 4); } else { *pOptSize = bufSize - hdrCom - sizeof(DHCP_PROTO); return (PDHCP_PROTO)(p + hdrCom); } } U32 dhcp_get_uid(void *pBuf) { U8 *p = (U8 *)pBuf; PVLAN_HDR pQinQ = (PVLAN_HDR)(p + sizeof(struct ethhdr)); if (p[12] == 0x81 && p[13] == 0x00 && p[16] == 0x81 && p[17] == 0x00) { PVLAN_HDR2 pHdr = (PVLAN_HDR2)pQinQ; return (pHdr->id1 & 0x0FFF) >> 12 | (pHdr->id2 & 0x0FFF) << 12; } else if (p[12] == 0x81 && p[13] == 0x00) { return (pQinQ->id & 0x0FFF); } else { return 0; } } static void on_sock_recv(uv_work_t *req) { U32 optSize = 0; char macStr[20] = {0}; U32 ip; PPOOL_CTX pIpInfo; DHCP_REQ reqDhcp; DHCP_OPT optMsg, opt; int ret; PPKG_PROCESS_INFO pWork = (PPKG_PROCESS_INFO)req->data; PDHCP_PROTO pkg = get_dhcp_date(pWork->pPkgBase, &optSize, pWork->nSize); struct iphdr *pIpHdr = (struct iphdr *)((U8 *)pkg - sizeof(struct iphdr) - sizeof(struct udphdr)); //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->op != BOOTP_REQUEST) { LOG_MOD(error, ZM_DHCP_NET, "Error message op code %d\n", pkg->op); LOG_MSG_HEX(error, pkg, pWork->nSize); return; } // 获取消息类型 ret = dhcp_get_option(OPT_MESSAGETYPE, pkg->options, optSize, &optMsg); if (ret != ERR_SUCCESS) { LOG_MOD(error, ZM_DHCP_NET, "Get \'message type\' option error %d\n", ret); return; } memset(&reqDhcp, 0, sizeof(DHCP_REQ)); reqDhcp.unicast = pkg->flags != 0 ? TRUE : FALSE; reqDhcp.xid = DHCP_XID(pkg->xid); reqDhcp.uid = dhcp_get_uid(pWork->pPkgBase); reqDhcp.serverAddr = g_nicInfo.ipAddr; reqDhcp.cliAddr = ntohl(pkg->ciaddr); memcpy(reqDhcp.cliMac, pkg->chaddr, ETH_ALEN); MAC_TO_STR(reqDhcp.cliMac, macStr); switch (*optMsg.pValue) { case DHCP_MSG_DISCOVER: // region DHCP Discover 处理 ret = dhcp_get_option(OPT_REQUESTEDIPADDR, pkg->options, optSize, &opt); if (ret == ERR_SUCCESS && opt.len == sizeof(U32)) { reqDhcp.reqIpAddr = ntohl(*((U32 *)opt.pValue)); } ret = dhcp_get_option(OPT_IPADDRLEASE, pkg->options, optSize, &opt); if (ret == ERR_SUCCESS && opt.len == sizeof(U32)) { reqDhcp.leaseTime = ntohl(*((U32 *)opt.pValue)); } ret = dhcp_get_option(OPT_CLIENTID, pkg->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->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->options, optSize, &opt); if (ret == ERR_SUCCESS) { strncpy(reqDhcp.hostName, (char *)opt.pValue, MIN((int)opt.len, 256)); } ret = pre_alloc_dhcp_res(&reqDhcp, pWork->pUser, &ip, &pIpInfo); if (ret == ERR_SUCCESS) { LOG_MOD(debug, ZM_DHCP_NET, "User %u DHCP prepare assign ipaddress: [%s(%s)] --> %s\n", reqDhcp.uid, macStr, reqDhcp.hostName, u32_to_str_ip(ntohl(ip))); ret = dhcp_resp_offer(pWork->pPkgBase, pIpInfo, ip); if (ret != ERR_SUCCESS) { LOG_MOD(error, ZM_DHCP_NET, "Send Offer error: %d\n", ret); } } else { LOG_MOD(error, ZM_DHCP_NET, "DHCP prepare assign ipaddress error: User %u [%s(%s)] resion %s\n", reqDhcp.uid, macStr, reqDhcp.hostName, getErrorEnumNameString(ret)); // Send NACK ret = dhcp_resp_nack(pWork->pPkgBase); } if (ret != ERR_SUCCESS) { LOG_MOD(error, ZM_DHCP_NET, "Send Offer error: %d\n", ret); } // endregion break; case DHCP_MSG_REQUEST: // region DHCP Request 处理 // 客户端请求的服务器 ret = dhcp_get_option(OPT_SERVERID, pkg->options, optSize, &opt); if (ret == ERR_SUCCESS && opt.len == sizeof(U32)) { reqDhcp.reqServer = ntohl(*((U32 *)opt.pValue)); } else { // Request 服务器IP可以取目的 IP 地址 if (pIpHdr->saddr != 0) { reqDhcp.reqServer = ntohl(pIpHdr->daddr); } } // 客户端请求的IP ret = dhcp_get_option(OPT_REQUESTEDIPADDR, pkg->options, optSize, &opt); if (ret == ERR_SUCCESS && opt.len == sizeof(U32)) { reqDhcp.reqIpAddr = ntohl(*((U32 *)opt.pValue)); } else { reqDhcp.reqIpAddr = reqDhcp.cliAddr; } // 客户端主机名 ret = dhcp_get_option(OPT_HOSTNAME, pkg->options, optSize, &opt); if (ret == ERR_SUCCESS) { strncpy(reqDhcp.hostName, (char *)opt.pValue, MIN((int)opt.len, 256)); } // 当改请求的服务端不是本机时,忽略该消息 if (reqDhcp.reqServer != ntohl(g_nicInfo.ipAddr) && reqDhcp.reqServer != 0) { const char *pReq = u32_to_str_ip_safe(htonl(reqDhcp.reqServer)); const char *pLocal = u32_to_str_ip_safe(g_nicInfo.ipAddr); LOG_MOD_HEX(error, ZM_DHCP_NET, pWork->pPkgBase, pWork->nSize); LOG_MOD(debug, ZM_DHCP_NET, "Receive others server's DHCP request: request need %s, localhost %s\n", pReq, pLocal); free((void *)pReq); free((void *)pLocal); } else { POOL_CTX ctx = {0}; if ((ret = is_pre_assigned(&reqDhcp, &ctx)) == ERR_SUCCESS) { LOG_MOD(debug, ZM_DHCP_NET, "User %u DHCP assign ipaddress: [%s(%s)] --> %s\n", reqDhcp.uid, macStr, reqDhcp.hostName, u32_to_str_ip(ntohl(ctx.minAddr))); ret = dhcp_resp_ack(pWork->pPkgBase, &ctx); } else { LOG_MOD(error, ZM_DHCP_NET, "DHCP assign ipaddress error: User %u [%s(%s)] resion %s\n", reqDhcp.uid, macStr, reqDhcp.hostName, getErrorEnumNameString(ret)); // Send NACK ret = dhcp_resp_nack(pWork->pPkgBase); } if (ret != ERR_SUCCESS) { LOG_MOD(error, ZM_DHCP_NET, "Send Ack error: %d\n", ret); } } // endregion break; case DHCP_MSG_RELEASE: // region DHCP Release 处理 // 客户端请求的服务器 ret = dhcp_get_option(OPT_SERVERID, pkg->options, optSize, &opt); if (ret == ERR_SUCCESS && opt.len == sizeof(U32)) { reqDhcp.reqServer = ntohl(*((U32 *)opt.pValue)); } else { // Request 服务器IP可以取目的 IP 地址 if (pIpHdr->saddr != 0) { reqDhcp.reqServer = ntohl(pIpHdr->saddr); } } reqDhcp.reqIpAddr = ntohl(pkg->ciaddr); lease_release(&reqDhcp); LOG_MOD(debug, ZM_DHCP_NET, "User %u DHCP release lease: [%s(%s)] --> %s\n", reqDhcp.uid, macStr, reqDhcp.hostName, u32_to_str_ip(ntohl(reqDhcp.reqIpAddr))); // endregion break; case DHCP_MSG_INFORM: // 客户端主机名 ret = dhcp_get_option(OPT_HOSTNAME, pkg->options, optSize, &opt); if (ret == ERR_SUCCESS) { strncpy(reqDhcp.hostName, (char *)opt.pValue, MIN((int)opt.len, 256)); } // 当前分配的租约添加到本地数据库中, 后续分配能够发现对应的主机信息 ret = lease_add_host(&reqDhcp); if (ret == ERR_SUCCESS) { LOG_MOD(debug, ZM_DHCP_NET, "User %u DHCP prepare assign ipaddress: [%s(%s)] --> %s\n", reqDhcp.uid, macStr, reqDhcp.hostName, u32_to_str_ip(ntohl(reqDhcp.cliAddr))); // 可以向客户端回复租约信息 } else { LOG_MOD(error, ZM_DHCP_NET, "DHCP prepare assign ipaddress error: User %u [%s(%s)] resion %s\n", reqDhcp.uid, macStr, reqDhcp.hostName, getErrorEnumNameString(ret)); } break; case DHCP_MSG_DECLINE: // 清理掉上次分配的租约 break; default: LOG_MOD(error, ZM_DHCP_NET, "Unkonwn DHCP message type: %d\n", *optMsg.pValue); LOG_MSG_HEX(trace, pkg, pWork->nSize); break; } //dhcp_option_prase(optMsg, pkg->options, pWork->nSize - sizeof(DHCP_PACKAGE)); //LOG_MSG_HEX(trace, pkg, pWork->nSize); //LOG_MSG(info, "Recv, xid: 0x%08X\n", DHCP_XID(pkg->xid)); #if 0 LOG_MOD(info, ZM_DHCP_NET, "vlan = %u\n", VXLAN_VIN_ID_PACK(pkg->hdr.vlan.id)); LOG_MSG(info, "xid: 0x%08X\n", ntohl(pkg->xid)); LOG_MSG(info, "dest mac: %02X:%02X:%02X:%02X:%02X:%02X\n", pkg->hdr.eth.h_dest[0], pkg->hdr.eth.h_dest[1], pkg->hdr.eth.h_dest[2], pkg->hdr.eth.h_dest[3], pkg->hdr.eth.h_dest[4], pkg->hdr.eth.h_dest[5]); LOG_MSG(info, "client mac: %02X:%02X:%02X:%02X:%02X:%02X\n", pkg->chaddr[0], pkg->chaddr[1], pkg->chaddr[2], pkg->chaddr[3], pkg->chaddr[4], pkg->chaddr[5]); #endif } static void after_msg_recv(uv_work_t *req, int UNUSED(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, ZM_DHCP_NET, "---Free resources: %p\n", pMsg); free(pMsg->pPkgInfo); free(pMsg); } } 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; if (status >= 0 && (events & UV_READABLE)) { struct block_desc *pbd = (struct block_desc *)g_pkgRing.rx[block_num].iov_base; if ((pbd->h1.block_status & TP_STATUS_USER) && (pbd->h1.num_pkts > 0)) { 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, ZM_DHCP_NET, "Malloc memory error: %lu\n", sizeof(PKG_MSG)); return; } memset(pMsg, 0, sizeof(PKG_MSG)); pMsg->pPkgInfo = (PPKG_PROCESS_INFO)malloc(memSize); if (pMsg->pPkgInfo == NULL) { LOG_MOD(error, ZM_DHCP_NET, "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++) { U32 uid; 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 (g_dhcpMode == MODE_DHCP_SERVER) { uid = dhcp_get_uid(pMsg->pPkgInfo[i].pPkgBase); pMsg->pPkgInfo[i].pUser = dhcp_user_create(uid); // LOG_MOD(trace, ZM_DHCP_NET, ">>> User %u xid %08X addr %p\n", uid, DHCP_XID(pkg->dhcp.xid), // pMsg->pPkgInfo[i].pUser); } 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); } } pbd->h1.block_status = TP_STATUS_KERNEL; block_num = (block_num + 1) % PKG_MMAP_BLOCKNUM; } } int create_udp_raw_socket(const char *pNicName) { struct sockaddr_ll addr; unsigned int size; int i; int err; int v = TPACKET_V3; // 1. create socket int sock_fd = socket(PF_PACKET, SOCK_RAW, 0); if (sock_fd < 0) { LOG_MOD(error, ZM_DHCP_NET, "Socket created failure: %s --> %s\n", pNicName, strerror(errno)); return -ERR_SOCK_CREATE; } // 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, ZM_DHCP_NET, "Attaching filter failed: %d\n", err); return -ERR_SOCK_SETOPT; } // 3. set PACKET_MMAP version if ((err = setsockopt(sock_fd, SOL_PACKET, PACKET_VERSION, &v, sizeof(v))) < 0) { LOG_MOD(error, ZM_DHCP_NET, "Set PACKET_VERSION option failed: %d\n", err); 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; if ((err = setsockopt(sock_fd, SOL_PACKET, PACKET_RX_RING, &g_pkgRing.recv, sizeof(g_pkgRing.recv))) < 0) { LOG_MOD(error, ZM_DHCP_NET, "Set PACKET_RX_RING option failed: %d\n", err); 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, ZM_DHCP_NET, "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; if (g_pkgRing.map_recv == MAP_FAILED) { LOG_MOD(error, ZM_DHCP_NET, "MMAP socket ring failed\n"); perror("title"); return -ERR_MMAP_MEMORY; } LOG_MOD(trace, ZM_DHCP_NET, "size = %u\n", size); LOG_MOD(trace, ZM_DHCP_NET, "MMAP address recv = %p, send = %p\n", g_pkgRing.map_recv, g_pkgRing.map_send); // 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, ZM_DHCP_NET, "Malloc memory failed: %lu\n", g_pkgRing.recv.tp_block_nr * sizeof(struct iovec)); 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; } // 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, ZM_DHCP_NET, "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; addr.sll_protocol = htons(ETH_P_ALL); addr.sll_hatype = 0; addr.sll_pkttype = 0; addr.sll_halen = 0; if ((err = bind(sock_fd, (struct sockaddr *)&addr, sizeof(struct sockaddr_ll))) < 0) { LOG_MOD(error, ZM_DHCP_NET, "Bind raw socket failed: %d\n", err); 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, ZM_DHCP_NET, "Send packet error\n"); } break; } } } 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; 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; 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); } int dhcpd_init(DHCP_WORK_MODE workMode) { int ret; size_t size = MAX_PATH; g_dhcpMode = workMode; 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); init_filter(config_get_dhcp_net_filter()); ret = create_udp_raw_socket(g_nicInfo.pIfName); if (ret != ERR_SUCCESS) { LOG_MOD(error, ZM_DHCP_NET, "Create receive RAW Socket Error: %s(%d)\n", getErrorEnumNameString(-ret), ret); return ret; } // 加载所有DHCP配置 ip_pool_init_from_config(); dhcp_user_mgr_init(); dhcp_option_cfg_init(); dhcp_lease_init(); init_raw_socket_poll(NULL, NULL); return ERR_SUCCESS; } 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); return ERR_SUCCESS; }