跨平台底层网络库libdnet源码分析系列(八)

admin 2026-03-29 23:46:03 网络安全文章 来源:ZONE.CI 全球网 0 阅读模式

文章总结: 本文详细解析libdnet库的数据包构造机制,涵盖以太网帧、ARP、IP、IPv6、TCP、UDP、ICMP、SCTP等各层协议。介绍了零拷贝设计、打包宏体系、跨平台字节序处理、结构对齐等核心技术,提供大量源码示例和实际应用场景。适合底层网络编程与安全工具开发参考。 综合评分: 85 文章分类: 安全开发,二进制安全,网络协议,代码审计,实战经验


cover_image

跨平台底层网络库libdnet源码分析系列(八)

原创

haidragon haidragon

安全狗的自我修养

2026年3月26日 15:32 湖南

官网:http://securitytech.cc

#

源码分析mettle后门工具学习 所使用的依赖库

#

#

原始数据包构造深入分析

目录

  1. 数据包构造基础概念
  2. libdnet数据包构造设计
  3. 以太网帧构造
  4. ARP数据包构造
  5. IP数据包构造
  6. IPv6数据包构造
  7. TCP数据包构造
  8. UDP数据包构造
  9. ICMP数据包构造
  10. ICMPv6数据包构造
  11. SCTP数据包构造
  12. 跨平台实现对比
  13. 实际应用示例
  14. 常见问题与解决方案

1. 数据包构造基础概念

1.1 网络协议栈层次结构

1. ┌─────────────────────────────────────────┐
2. │应用层(Application)│
3. ├─────────────────────────────────────────┤
4. │传输层(Transport)│← TCP/UDP/SCTP
5. ├─────────────────────────────────────────┤
6. │网络层(Network)│← IP/IPv6/ARP
7. ├─────────────────────────────────────────┤
8. │数据链路层(DataLink)│←Ethernet
9. ├─────────────────────────────────────────┤
10. │物理层(Physical)│
11. └─────────────────────────────────────────┘

1.2 数据包封装顺序

1. ┌────────────────────────────────────────────────────┐
2. │应用数据│
3. ├────────────────────────────────────────────────────┤
4. │  TCP/UDP/SCTP  头部|应用数据│
5. ├────────────────────────────────────────────────────┤
6. │    IP/IPv6头部| TCP/UDP/SCTP 头部|应用数据│
7. ├────────────────────────────────────────────────────┤
8. │Ethernet头部|   IP/IPv6头部|传输层...|数据│
9. └────────────────────────────────────────────────────┘

1.3 字节序问题

网络字节序:大端序(Big-Endian),高位字节在前

主机字节序

  • x86/x64:小端序(Little-Endian)
  • PowerPC/ARM:大端序(Big-Endian)

libdnet提供了宏自动处理:

1. #include<dnet.h>

3. // 转换为网络字节序
4. uint16_t&nbsp;port&nbsp;=&nbsp;htons(8080);
5. uint32_t&nbsp;addr&nbsp;=&nbsp;htonl(0x0a000001);

7. // 从网络字节序转换
8. uint16_t&nbsp;hport&nbsp;=&nbsp;ntohs(8080);
9. uint32_t&nbsp;haddr&nbsp;=&nbsp;ntohl(0x0a000001);

1.4 校验和计算

目的:检测数据传输过程中的错误

算法:16位反码求和

1. // 简化的校验和算法示例
2. uint16_t&nbsp;checksum(void*buf,size_t&nbsp;len){
3. uint16_t*ptr&nbsp;=(uint16_t*)buf;
4. uint32_t&nbsp;sum&nbsp;=0;

6. while(len&nbsp;>1){
7. sum&nbsp;+=*ptr++;
8. len&nbsp;-=2;
9. }

11. if(len&nbsp;==1){
12. sum&nbsp;+=*(uint8_t*)ptr&nbsp;<<8;
13. }

15. // 反码求和
16. while(sum&nbsp;>>16){
17. sum&nbsp;=(sum&nbsp;&0xffff)+(sum&nbsp;>>16);
18. }

20. return~sum;
21. }

2. libdnet数据包构造设计

2.1 核心设计原则

  1. 零拷贝:直接操作缓冲区
  2. 宏封装:使用宏简化构造代码
  3. 跨平台:自动处理字节序和结构对齐
  4. 灵活扩展:支持选项和扩展头

2.2 打包宏体系

libdnet提供了一套完整的打包宏:

| 协议 | 打包宏 | 位置 | | — | — | — | | Ethernet | eth_pack_hdr | include/dnet/eth.h:74-79 | | ARP | arp_pack_hdr_ethip | include/dnet/arp.h:83-95 | | IP | ip_pack_hdr | include/dnet/ip.h:415-431 | | IPv6 | ip6_pack_hdr | include/dnet/ip6.h:166-179 | | TCP | tcp_pack_hdr | include/dnet/tcp.h:177-193 | | UDP | udp_pack_hdr | include/dnet/udp.h:24-29 | | ICMP | icmp_pack_hdr_* | include/dnet/icmp.h:224-262 | | ICMPv6 | icmpv6_pack_hdr_* | include/dnet/icmpv6.h:91-114 | | SCTP | sctp_pack_hdr | include/dnet/sctp.h:31-36 |

2.3 数据结构对齐

libdnet使用 __attribute__((__packed__))确保结构紧凑:

1. // include/dnet/ip.h:35-53
2. struct&nbsp;ip_hdr&nbsp;{
3. #if&nbsp;DNET_BYTESEX == DNET_BIG_ENDIAN
4. uint8_t&nbsp;ip_v:4,// 版本号
5. ip_hl:4;// 头部长度
6. #elif&nbsp;DNET_BYTESEX&nbsp;==&nbsp;DNET_LIL_ENDIAN
7. uint8_t&nbsp;ip_hl:4,&nbsp;ip_v:4;
8. #endif
9. uint8_t&nbsp;ip_tos;// 服务类型
10. uint16_t&nbsp;ip_len;// 总长度
11. uint16_t&nbsp;ip_id;// 标识
12. uint16_t&nbsp;ip_off;// 片偏移
13. uint8_t&nbsp;ip_ttl;// 生存时间
14. uint8_t&nbsp;ip_p;// 协议
15. uint16_t&nbsp;ip_sum;// 校验和
16. ip_addr_t&nbsp;ip_src;// 源地址
17. ip_addr_t&nbsp;ip_dst;// 目的地址
18. }&nbsp;__attribute__((__packed__));

2.4 字节序自动处理

1. // include/config.h 中的字节序检测
2. #if&nbsp;defined(__BYTE_ORDER__)
3. #if&nbsp;__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
4. #define&nbsp;DNET_BYTESEX DNET_LIL_ENDIAN
5. #elif&nbsp;__BYTE_ORDER__&nbsp;==&nbsp;__ORDER_BIG_ENDIAN__
6. #define&nbsp;DNET_BYTESEX DNET_BIG_ENDIAN
7. #endif
8. #endif

3. 以太网帧构造

3.1 以太网帧结构

1. ┌──────┬──────┬──────┬────────────────────┬──────┐
2. │6B│6B│2B│46-1500B│4B│
3. │目的│源│类型│数据│&nbsp;CRC &nbsp;│
4. │&nbsp;MAC &nbsp;│&nbsp;MAC &nbsp;││││
5. └──────┴──────┴──────┴────────────────────┴──────┘

3.2 以太网头部定义

位置: include/dnet/eth.h:29-33

1. struct&nbsp;eth_hdr&nbsp;{
2. eth_addr_t&nbsp;eth_dst;// 目的MAC地址
3. eth_addr_t&nbsp;eth_src;// 源MAC地址
4. uint16_t&nbsp;eth_type;// 以太类型
5. };

3.3 常见以太类型

| 类型值 | 协议 | 定义位置 | | — | — | — | | 0x0800 | IPv4 | ETH_TYPE_IP | | 0x0806 | ARP | ETH_TYPE_ARP | | 0x86DD | IPv6 | ETH_TYPE_IPV6 | | 0x8100 | 802.1Q VLAN | ETH_TYPE_8021Q | | 0x8847 | MPLS | ETH_TYPE_MPLS |

位置: include/dnet/eth.h:38-52

3.4 打包宏实现

位置: include/dnet/eth.h:74-79

1. #define&nbsp;eth_pack_hdr(h,&nbsp;dst,&nbsp;src,&nbsp;type)do{&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; \
2. struct&nbsp;eth_hdr&nbsp;*eth_pack_p&nbsp;=(struct&nbsp;eth_hdr&nbsp;*)(h);&nbsp; &nbsp;\
3. memcpy(&eth_pack_p->eth_dst,&(dst),&nbsp;ETH_ADDR_LEN);&nbsp; \
4. memcpy(&eth_pack_p->eth_src,&(src),&nbsp;ETH_ADDR_LEN);&nbsp; \
5. eth_pack_p->eth_type&nbsp;=&nbsp;htons(type);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; \
6. }while(0)

3.5 构造示例

1. #include<dnet.h>

3. u_char frame[ETH_LEN_MAX];

5. // MAC地址定义
6. eth_addr_t&nbsp;src_mac&nbsp;={0x00,0x11,0x22,0x33,0x44,0x55};
7. eth_addr_t&nbsp;dst_mac&nbsp;={0xff,0xff,0xff,0xff,0xff,0xff};

9. // 构造以太网头部
10. eth_pack_hdr(frame,&nbsp;dst_mac,&nbsp;src_mac,&nbsp;ETH_TYPE_IP);

12. // 填充数据载荷
13. memcpy(frame&nbsp;+&nbsp;ETH_HDR_LEN,&nbsp;payload,&nbsp;payload_len);

15. // 发送
16. eth_send(eth,&nbsp;frame,&nbsp;ETH_HDR_LEN&nbsp;+&nbsp;payload_len);

3.6 VLAN标签支持

位置: include/dnet/eth.h:54-68

1. struct&nbsp;eth_8021q_hdr&nbsp;{
2. uint16_t&nbsp;priority_c_vid;// 优先级 | VLAN ID (TCI)
3. uint16_t&nbsp;len_eth_type;// 长度或类型
4. };

6. // VLAN掩码
7. #define&nbsp;ETH_8021Q_PRIMASK &nbsp;&nbsp;0x0007// 优先级掩码
8. #define&nbsp;ETH_8021Q_CFIMASK &nbsp;&nbsp;0x0001// CFI掩码
9. #define&nbsp;ETH_8021Q_VIDMASK &nbsp;&nbsp;0x0fff// VID掩码

11. // 判断是否为VLAN类型
12. #define&nbsp;ETH_TYPE_IS_VLAN(type)&nbsp;\
13. (((type)==&nbsp;ETH_TYPE_8021Q)||&nbsp;\
14. ((type)==&nbsp;ETH_TYPE_8021ad_0)||&nbsp;\
15. ((type)==&nbsp;ETH_TYPE_8021ad_1)||&nbsp;\
16. ((type)==&nbsp;ETH_TYPE_8021ad_2)||&nbsp;\
17. ((type)==&nbsp;ETH_TYPE_8021ad_3))

4. ARP数据包构造

4.1 ARP协议概述

ARP(Address Resolution Protocol)用于将IP地址解析为MAC地址。

4.2 ARP数据包结构

1. ┌──────┬──────┬────┬────┬────┬────────────────────────┐
2. │2B│2B│1B│1B│2B││
3. │硬件│协议│硬│协│操│可变长度(通常28B)│
4. │类型│类型│件│议│作││
5. │││长│长│││
6. └──────┴──────┴────┴────┴────┴────────────────────────┘

4.3 ARP头部定义

位置: include/dnet/arp.h:27-33

1. struct&nbsp;arp_hdr&nbsp;{
2. uint16_t&nbsp;ar_hrd;// 硬件地址格式
3. uint16_t&nbsp;ar_pro;// 协议地址格式
4. uint8_t&nbsp;ar_hln;// 硬件地址长度
5. uint8_t&nbsp;ar_pln;// 协议地址长度
6. uint16_t&nbsp;ar_op;// 操作类型
7. };

4.4 ARP操作类型

| 操作 | 值 | 说明 | | — | — | — | | ARP_OP_REQUEST | 1 | 请求解析 | | ARP_OP_REPLY | 2 | 响应 | | ARP_OP_REVREQUEST | 3 | 反向请求 | | ARP_OP_REVREPLY | 4 | 反向响应 |

位置: include/dnet/arp.h:56-59

4.5 Ethernet/IP ARP数据

位置: include/dnet/arp.h:64-69

1. struct&nbsp;arp_ethip&nbsp;{
2. eth_addr_t&nbsp;ar_sha;// 发送方硬件地址
3. ip_addr_t&nbsp;ar_spa;// 发送方协议地址
4. eth_addr_t&nbsp;ar_tha;// 目标硬件地址
5. ip_addr_t&nbsp;ar_tpa;// 目标协议地址
6. };

4.6 打包宏实现

位置: include/dnet/arp.h:83-95

1. #define&nbsp;arp_pack_hdr_ethip(hdr,&nbsp;op,&nbsp;sha,&nbsp;spa,&nbsp;tha,&nbsp;tpa)do{&nbsp; &nbsp; \
2. struct&nbsp;arp_hdr&nbsp;*pack_arp_p&nbsp;=(struct&nbsp;arp_hdr&nbsp;*)(hdr);&nbsp; &nbsp; &nbsp; &nbsp; \
3. struct&nbsp;arp_ethip&nbsp;*pack_ethip_p&nbsp;=(struct&nbsp;arp_ethip&nbsp;*)&nbsp; &nbsp; &nbsp; &nbsp;\
4. (pack_arp_p&nbsp;+1);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;\
5. pack_arp_p->ar_hrd&nbsp;=&nbsp;htons(ARP_HRD_ETH);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; \
6. pack_arp_p->ar_pro&nbsp;=&nbsp;htons(ARP_PRO_IP);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;\
7. pack_arp_p->ar_hln&nbsp;=&nbsp;ETH_ADDR_LEN;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; \
8. pack_arp_p->ar_pln&nbsp;=&nbsp;IP_ADDR_LEN;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;\
9. pack_arp_p->ar_op&nbsp;=&nbsp;htons(op);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; \
10. memcpy(&pack_ethip_p->ar_sha,&(sha),&nbsp;ETH_ADDR_LEN);&nbsp; &nbsp; &nbsp; &nbsp; \
11. memcpy(&pack_ethip_p->ar_spa,&(spa),&nbsp;IP_ADDR_LEN);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;\
12. memcpy(&pack_ethip_p->ar_tha,&(tha),&nbsp;ETH_ADDR_LEN);&nbsp; &nbsp; &nbsp; &nbsp; \
13. memcpy(&pack_ethip_p->ar_tpa,&(tpa),&nbsp;IP_ADDR_LEN);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;\
14. }while(0)

4.7 构造示例

1. #include<dnet.h>

3. u_char frame[ETH_HDR_LEN&nbsp;+&nbsp;ARP_HDR_LEN&nbsp;+&nbsp;ARP_ETHIP_LEN];

5. // 以太网头部
6. eth_pack_hdr(frame,
7. ETH_ADDR_BROADCAST,// 广播MAC
8. src_mac,
9. ETH_TYPE_ARP);

11. // ARP请求
12. eth_addr_t&nbsp;zero_mac&nbsp;={0};
13. arp_pack_hdr_ethip(frame&nbsp;+&nbsp;ETH_HDR_LEN,
14. ARP_OP_REQUEST,
15. src_mac,
16. src_ip,
17. zero_mac,
18. target_ip);

20. // 发送
21. eth_send(eth,&nbsp;frame,sizeof(frame));

4.8 ARP数据包发送实例

位置: src/ip-cooked.c:127-138

1. staticvoid
2. _request_arp(struct&nbsp;ip_intf&nbsp;*ipi,struct&nbsp;addr&nbsp;*dst)
3. {
4. u_char frame[ETH_HDR_LEN&nbsp;+&nbsp;ARP_HDR_LEN&nbsp;+&nbsp;ARP_ETHIP_LEN];

6. eth_pack_hdr(frame,&nbsp;ETH_ADDR_BROADCAST,&nbsp;ipi->ha.addr_eth,
7. ETH_TYPE_ARP);
8. arp_pack_hdr_ethip(frame&nbsp;+&nbsp;ETH_HDR_LEN,&nbsp;ARP_OP_REQUEST,
9. ipi->ha.addr_eth,&nbsp;ipi->pa.addr_ip,&nbsp;ETH_ADDR_BROADCAST,
10. dst->addr_ip);

12. eth_send(ipi->eth,&nbsp;frame,sizeof(frame));
13. }

5. IP数据包构造

5.1 IP协议概述

IP(Internet Protocol)是网络层的核心协议,负责数据包的寻址和路由。

5.2 IPv4头部结构

1. ┌───┬───┬────────┬────────┬──────┬────────┬──────┬────────┬────────┬────────┐
2. │4│4│8│16│16│16│8│8│16│32x2│
3. │版本│IHL│服务│总│标识│片偏移│&nbsp;TTL &nbsp;│协议│校验和│源/目的│
4. │││类型│长度││││││地址│
5. └───┴───┴────────┴────────┴──────┴────────┴──────┴────────┴────────┴────────┘

5.3 IP头部定义

位置: include/dnet/ip.h:35-53

1. struct&nbsp;ip_hdr&nbsp;{
2. #if&nbsp;DNET_BYTESEX == DNET_BIG_ENDIAN
3. uint8_t&nbsp;ip_v:4,// 版本号 (4)
4. ip_hl:4;// 头部长度 (以4字节为单位)
5. #elif&nbsp;DNET_BYTESEX&nbsp;==&nbsp;DNET_LIL_ENDIAN
6. uint8_t&nbsp;ip_hl:4,&nbsp;ip_v:4;
7. #endif
8. uint8_t&nbsp;ip_tos;// 服务类型
9. uint16_t&nbsp;ip_len;// 总长度(包括头部和数据)
10. uint16_t&nbsp;ip_id;// 标识
11. uint16_t&nbsp;ip_off;// 片偏移和标志
12. uint8_t&nbsp;ip_ttl;// 生存时间
13. uint8_t&nbsp;ip_p;// 协议
14. uint16_t&nbsp;ip_sum;// 校验和
15. ip_addr_t&nbsp;ip_src;// 源地址
16. ip_addr_t&nbsp;ip_dst;// 目的地址
17. }&nbsp;__attribute__((__packed__));

5.4 IP协议类型

| 协议 | 值 | 说明 | | — | — | — | | IP_PROTO_ICMP | 1 | ICMP | | IP_PROTO_TCP | 6 | TCP | | IP_PROTO_UDP | 17 | UDP | | IP_PROTO_SCTP | 132 | SCTP | | IP_PROTO_IPV6 | 41 | IPv6 |

位置: include/dnet/ip.h:108-246

5.5 分片标志

| 标志 | 值 | 说明 | | — | — | — | | IP_DF | 0x4000 | 不分片 | | IP_MF | 0x2000 | 更多分片 | | IP_OFFMASK | 0x1fff | 片偏移掩码 |

位置: include/dnet/ip.h:94-97

5.6 打包宏实现

位置: include/dnet/ip.h:415-431

1. staticinlinevoid&nbsp;ip_pack_hdr(void*buf,uint8_t&nbsp;tos,uint16_t&nbsp;len,
2. uint16_t&nbsp;id,uint16_t&nbsp;off,uint8_t&nbsp;ttl,uint8_t&nbsp;p,ip_addr_t&nbsp;src,
3. ip_addr_t&nbsp;dst)
4. {
5. struct&nbsp;ip_hdr&nbsp;{
6. uint32_t&nbsp;ip_v_hl_tos_len;
7. uint32_t&nbsp;ip_id_off;
8. uint32_t&nbsp;ip_ttl_p_sum;
9. ip_addr_t&nbsp;ip_src;
10. ip_addr_t&nbsp;ip_dst;
11. }*hdr&nbsp;=(struct&nbsp;ip_hdr&nbsp;*)buf;
12. hdr->ip_v_hl_tos_len&nbsp;=(0x45<<24)|(tos&nbsp;<<16)|&nbsp;htons(len);
13. hdr->ip_id_off&nbsp;=(htons(id)<<16)|&nbsp;htons(off);
14. hdr->ip_ttl_p_sum&nbsp;=(ttl&nbsp;<<24)|(p&nbsp;<<16);
15. hdr->ip_src&nbsp;=&nbsp;src;
16. hdr->ip_dst&nbsp;=&nbsp;dst;
17. }

5.7 构造示例

1. #include<dnet.h>

3. u_char packet[IP_LEN_MAX];

5. // 构造IP头部
6. ip_pack_hdr(packet,
7. 0,// TOS
8. total_len,// 总长度
9. rand()&0xffff,// ID
10. 0,// 片偏移
11. IP_TTL_DEFAULT,// TTL
12. IP_PROTO_TCP,// 协议
13. src_ip,// 源IP
14. dst_ip);// 目的IP

16. // 计算校验和
17. ip_checksum(packet,&nbsp;IP_HDR_LEN&nbsp;+&nbsp;payload_len,0);

19. // 发送
20. ip_send(ip,&nbsp;packet,&nbsp;total_len);

5.8 IP选项处理

位置: src/ip-util.c:40-99

1. ssize_t
2. ip_add_option(void*buf,size_t&nbsp;len,int&nbsp;proto,
3. constvoid*optbuf,size_t&nbsp;optlen)
4. {
5. struct&nbsp;ip_hdr&nbsp;*ip;
6. struct&nbsp;tcp_hdr&nbsp;*tcp&nbsp;=&nbsp;NULL;
7. u_char&nbsp;*p;
8. int&nbsp;hl,&nbsp;datalen,&nbsp;padlen;

10. if(proto&nbsp;!=&nbsp;IP_PROTO_IP&nbsp;&&&nbsp;proto&nbsp;!=&nbsp;IP_PROTO_TCP){
11. errno&nbsp;=&nbsp;EINVAL;
12. return(-1);
13. }
14. ip&nbsp;=(struct&nbsp;ip_hdr&nbsp;*)buf;
15. hl&nbsp;=&nbsp;ip->ip_hl&nbsp;<<2;
16. p&nbsp;=(u_char&nbsp;*)buf&nbsp;+&nbsp;hl;

18. if(proto&nbsp;==&nbsp;IP_PROTO_TCP){
19. tcp&nbsp;=(struct&nbsp;tcp_hdr&nbsp;*)p;
20. hl&nbsp;=&nbsp;tcp->th_off&nbsp;<<2;
21. p&nbsp;=(u_char&nbsp;*)tcp&nbsp;+&nbsp;hl;
22. }
23. datalen&nbsp;=&nbsp;ntohs(ip->ip_len)-(p&nbsp;-(u_char&nbsp;*)buf);

25. // 计算填充到下一个字边界
26. if((padlen&nbsp;=4-(optlen&nbsp;%4))==4)
27. padlen&nbsp;=0;

29. if(hl&nbsp;+&nbsp;optlen&nbsp;+&nbsp;padlen&nbsp;>&nbsp;IP_HDR_LEN_MAX&nbsp;||
30. ntohs(ip->ip_len)+&nbsp;optlen&nbsp;+&nbsp;padlen&nbsp;>&nbsp;len){
31. errno&nbsp;=&nbsp;EINVAL;
32. return(-1);
33. }

35. // 只填充类型的选项
36. if(IP_OPT_TYPEONLY(((struct&nbsp;ip_opt&nbsp;*)optbuf)->opt_type))
37. optlen&nbsp;=1;

39. // 移动现有数据
40. if(datalen){
41. memmove(p&nbsp;+&nbsp;optlen&nbsp;+&nbsp;padlen,&nbsp;p,&nbsp;datalen);
42. }

44. // 填充NOP
45. if(padlen){
46. memset(p,&nbsp;IP_OPT_NOP,&nbsp;padlen);
47. p&nbsp;+=&nbsp;padlen;
48. }
49. memmove(p,&nbsp;optbuf,&nbsp;optlen);
50. p&nbsp;+=&nbsp;optlen;
51. optlen&nbsp;+=&nbsp;padlen;

53. if(proto&nbsp;==&nbsp;IP_PROTO_IP)
54. ip->ip_hl&nbsp;=(p&nbsp;-(u_char&nbsp;*)ip)>>2;
55. elseif(proto&nbsp;==&nbsp;IP_PROTO_TCP)
56. tcp->th_off&nbsp;=(p&nbsp;-(u_char&nbsp;*)tcp)>>2;

58. ip->ip_len&nbsp;=&nbsp;htons(ntohs(ip->ip_len)+&nbsp;optlen);

60. return(optlen);
61. }

5.9 常用IP选项

| 选项 | 值 | 说明 | | — | — | — | | IP_OPT_EOL | 0 | 选项列表结束 | | IP_OPT_NOP | 1 | 无操作 | | IP_OPT_LSRR | 3 | 宽松源路由 | | IP_OPT_SSRR | 9 | 严格源路由 | | IP_OPT_TS | 4 | 时间戳 |

位置: include/dnet/ip.h:258-283


6. IPv6数据包构造

6.1 IPv6协议概述

IPv6是IPv4的继任者,提供更大的地址空间和简化的头部结构。

6.2 IPv6头部结构

1. ┌────┬──────┬────────┬──────┬────────┬────────┬────────┐
2. │4│8│20│8│8│128│128│
3. │版本│流│流标签│载荷│下一个│跳数│源/目的│
4. ││标签││长度│头部│限制│地址│
5. └────┴──────┴────────┴──────┴────────┴────────┴────────┘

6.3 IPv6头部定义

位置: include/dnet/ip6.h:36-48

1. struct&nbsp;ip6_hdr&nbsp;{
2. union{
3. struct&nbsp;ip6_hdr_ctl&nbsp;{
4. uint32_t&nbsp;ip6_un1_flow;// 流ID(20位)
5. uint16_t&nbsp;ip6_un1_plen;// 载荷长度
6. uint8_t&nbsp;ip6_un1_nxt;// 下一个头部
7. uint8_t&nbsp;ip6_un1_hlim;// 跳数限制
8. }&nbsp;ip6_un1;
9. uint8_t&nbsp;ip6_un2_vfc;// 版本(4位)和流量类(4位)
10. }&nbsp;ip6_ctlun;
11. ip6_addr_t&nbsp;ip6_src;
12. ip6_addr_t&nbsp;ip6_dst;
13. }&nbsp;__attribute__((__packed__));

6.4 打包宏实现

位置: include/dnet/ip6.h:166-179

1. staticinlinevoid&nbsp;ip6_pack_hdr(void*buf,uint8_t&nbsp;c,uint32_t&nbsp;l,
2. uint16_t&nbsp;plen,uint8_t&nbsp;nxt,uint8_t&nbsp;hlim,void*src,void*dst)
3. {
4. struct&nbsp;ip6_hdr&nbsp;{
5. uint32_t&nbsp;ip6_v_c_l;
6. uint32_t&nbsp;ip6_plen_nxt_hlim;
7. ip6_addr_t&nbsp;ip6_src;
8. ip6_addr_t&nbsp;ip6_dst;
9. }*hdr&nbsp;=(struct&nbsp;ip6_hdr&nbsp;*)buf;
10. hdr->ip6_v_c_l&nbsp;=(6<<28)|(c&nbsp;<<20)|(IP6_FLOWLABEL_MASK&nbsp;&&nbsp;l);
11. hdr->ip6_plen_nxt_hlim&nbsp;=(htons(plen)<<16)|(nxt&nbsp;<<8)|&nbsp;hlim;
12. memcpy(&hdr->ip6_src,&nbsp;src,&nbsp;IP6_ADDR_LEN);
13. memcpy(&hdr->ip6_dst,&nbsp;dst,&nbsp;IP6_ADDR_LEN);
14. }

6.5 构造示例

1. #include<dnet.h>

3. u_char packet[IP6_LEN_MAX];

5. // IPv6地址
6. ip6_addr_t&nbsp;src_ip6,&nbsp;dst_ip6;
7. ip6_pton("2001:db8::1",&src_ip6);
8. ip6_pton("2001:db8::2",&dst_ip6);

10. // 构造IPv6头部
11. ip6_pack_hdr(packet,
12. 0,// 流类
13. 0x12345,// 流标签
14. payload_len,// 载荷长度
15. IP_PROTO_TCP,// 下一个头部
16. IP6_HLIM_DEFAULT,// 跳数限制
17. &src_ip6,// 源地址
18. &dst_ip6);// 目的地址

20. // 计算校验和
21. ip6_checksum(packet,&nbsp;IP6_HDR_LEN&nbsp;+&nbsp;payload_len);

23. // 发送
24. ip_send(ip,&nbsp;packet,&nbsp;IP6_HDR_LEN&nbsp;+&nbsp;payload_len);

6.6 扩展头部支持

IPv6支持多种扩展头部:

| 扩展头部 | 协议值 | 说明 | | — | — | — | | Hop-by-Hop Options | 0 | 逐跳选项 | | Routing | 43 | 路由头部 | | Fragment | 44 | 分片头部 | | Destination Options | 60 | 目的选项 |

位置: include/dnet/ip6.h:82-118


7. TCP数据包构造

7.1 TCP协议概述

TCP(Transmission Control Protocol)是面向连接的可靠传输协议。

7.2 TCP头部结构

1. ┌──────────┬──────────┬────────┬────────┬────┬────────┬────────┬────────┐
2. │16│16│32│32│4│4│16│16│
3. │源端口│目的端口│序列号│确认号│偏移│保留│窗口│紧急│
4. ││││││/标志││指针│
5. └──────────┴──────────┴────────┴────────┴────┴────────┴────────┴────────┘
6. └───┬───┘
7. │
8. ┌───────┼─────────┐
9. │6│8│
10. │保留位│8个标志位│
11. └───────┴─────────┘

7.3 TCP头部定义

位置: include/dnet/tcp.h:26-43

1. struct&nbsp;tcp_hdr&nbsp;{
2. uint16_t&nbsp;th_sport;// 源端口
3. uint16_t&nbsp;th_dport;// 目的端口
4. uint32_t&nbsp;th_seq;// 序列号
5. uint32_t&nbsp;th_ack;// 确认号
6. #if&nbsp;DNET_BYTESEX == DNET_BIG_ENDIAN
7. uint8_t&nbsp;th_off:4,// 数据偏移(以4字节为单位)
8. th_x2:4;// 保留
9. #elif&nbsp;DNET_BYTESEX&nbsp;==&nbsp;DNET_LIL_ENDIAN
10. uint8_t&nbsp;th_x2:4,&nbsp;th_off:4;
11. #endif
12. uint8_t&nbsp;th_flags;// 控制标志
13. uint16_t&nbsp;th_win;// 窗口大小
14. uint16_t&nbsp;th_sum;// 校验和
15. uint16_t&nbsp;th_urp;// 紧急指针
16. }&nbsp;__attribute__((__packed__));

7.4 TCP标志位

| 标志 | 值 | 说明 | | — | — | — | | TH_FIN | 0x01 | 结束连接 | | TH_SYN | 0x02 | 同步序列号 | | TH_RST | 0x04 | 重置连接 | | TH_PUSH | 0x08 | 推送数据 | | TH_ACK | 0x10 | 确认号有效 | | TH_URG | 0x20 | 紧急指针有效 | | TH_ECE | 0x40 | ECN回显 | | TH_CWR | 0x80 | 拥塞窗口减少 |

位置: include/dnet/tcp.h:65-72

7.5 打包宏实现

位置: include/dnet/tcp.h:177-193

1. staticinlinevoid&nbsp;tcp_pack_hdr(void*buf,uint16_t&nbsp;sport,uint16_t&nbsp;dport,
2. uint32_t&nbsp;seq,uint32_t&nbsp;ack,uint8_t&nbsp;flags,uint16_t&nbsp;win,uint16_t&nbsp;urp)
3. {
4. struct&nbsp;tcp_hdr&nbsp;{
5. uint32_t&nbsp;th_sport_dport;
6. uint32_t&nbsp;th_seq;
7. uint32_t&nbsp;th_ack;
8. uint32_t&nbsp;th_off_x2_flags_win;
9. uint32_t&nbsp;th_sum_urp;
10. }*hdr&nbsp;=(struct&nbsp;tcp_hdr&nbsp;*)buf;

12. hdr->th_sport_dport&nbsp;=(htons(sport)<<16)|&nbsp;htons(dport);
13. hdr->th_seq&nbsp;=&nbsp;htonl(seq);
14. hdr->th_ack&nbsp;=&nbsp;htonl(ack);
15. hdr->th_off_x2_flags_win&nbsp;=(0x50<<24)|(flags&nbsp;<<16)|&nbsp;htons(win);
16. hdr->th_sum_urp&nbsp;=&nbsp;htons(urp);
17. }

7.6 构造示例

1. #include<dnet.h>

3. u_char packet[IP_HDR_LEN&nbsp;+&nbsp;TCP_HDR_LEN&nbsp;+&nbsp;payload_len];
4. struct&nbsp;ip_hdr&nbsp;*ip&nbsp;=(struct&nbsp;ip_hdr&nbsp;*)packet;
5. struct&nbsp;tcp_hdr&nbsp;*tcp&nbsp;=(struct&nbsp;tcp_hdr&nbsp;*)(packet&nbsp;+&nbsp;IP_HDR_LEN);

7. // 构造IP头部
8. ip_pack_hdr(ip,0,&nbsp;IP_HDR_LEN&nbsp;+&nbsp;TCP_HDR_LEN&nbsp;+&nbsp;payload_len,
9. rand()&0xffff,0,&nbsp;IP_TTL_DEFAULT,&nbsp;IP_PROTO_TCP,
10. src_ip,&nbsp;dst_ip);

12. // 构造TCP头部
13. tcp_pack_hdr(tcp,
14. htons(src_port),// 源端口
15. htons(dst_port),// 目的端口
16. htonl(seq_num),// 序列号
17. htonl(ack_num),// 确认号
18. TH_SYN&nbsp;|&nbsp;TH_ACK,// 标志
19. htons(65535),// 窗口
20. 0);// 紧急指针

22. // 计算校验和
23. tcp_checksum(ip,&nbsp;tcp,&nbsp;TCP_HDR_LEN&nbsp;+&nbsp;payload_len);

25. // 发送
26. ip_send(ip,&nbsp;packet,&nbsp;IP_HDR_LEN&nbsp;+&nbsp;TCP_HDR_LEN&nbsp;+&nbsp;payload_len);

7.7 TCP选项

| 选项 | 值 | 说明 | | — | — | — | | TCP_OPT_MSS | 2 | 最大分段大小 | | TCP_OPT_WSCALE | 3 | 窗口缩放 | | TCP_OPT_TIMESTAMP | 8 | 时间戳 | | TCP_OPT_SACKOK | 4 | 选择性ACK许可 |

位置: include/dnet/tcp.h:110-136


8. UDP数据包构造

8.1 UDP协议概述

UDP(User Datagram Protocol)是无连接的不可靠传输协议。

8.2 UDP头部结构

1. ┌──────────┬──────────┬────────┬────────┐
2. │16│16│16│16│
3. │源端口│目的端口│长度│校验和│
4. └──────────┴──────────┴────────┴────────┘

8.3 UDP头部定义

位置: include/dnet/udp.h:15-20

1. struct&nbsp;udp_hdr&nbsp;{
2. uint16_t&nbsp;uh_sport;// 源端口
3. uint16_t&nbsp;uh_dport;// 目的端口
4. uint16_t&nbsp;uh_ulen;// UDP长度(包括头部)
5. uint16_t&nbsp;uh_sum;// 校验和
6. };

8.4 打包宏实现

位置: include/dnet/udp.h:24-29

1. #define&nbsp;udp_pack_hdr(hdr,&nbsp;sport,&nbsp;dport,&nbsp;ulen)do{&nbsp; &nbsp; &nbsp; &nbsp; \
2. struct&nbsp;udp_hdr&nbsp;*udp_pack_p&nbsp;=(struct&nbsp;udp_hdr&nbsp;*)(hdr);&nbsp;\
3. udp_pack_p->uh_sport&nbsp;=&nbsp;htons(sport);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; \
4. udp_pack_p->uh_dport&nbsp;=&nbsp;htons(dport);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; \
5. udp_pack_p->uh_ulen&nbsp;=&nbsp;htons(ulen);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; \
6. }while(0)

8.5 构造示例

1. #include<dnet.h>

3. u_char packet[IP_HDR_LEN&nbsp;+&nbsp;UDP_HDR_LEN&nbsp;+&nbsp;payload_len];
4. struct&nbsp;ip_hdr&nbsp;*ip&nbsp;=(struct&nbsp;ip_hdr&nbsp;*)packet;
5. struct&nbsp;udp_hdr&nbsp;*udp&nbsp;=(struct&nbsp;udp_hdr&nbsp;*)(packet&nbsp;+&nbsp;IP_HDR_LEN);

7. // 构造IP头部
8. ip_pack_hdr(ip,0,&nbsp;IP_HDR_LEN&nbsp;+&nbsp;UDP_HDR_LEN&nbsp;+&nbsp;payload_len,
9. rand()&0xffff,0,&nbsp;IP_TTL_DEFAULT,&nbsp;IP_PROTO_UDP,
10. src_ip,&nbsp;dst_ip);

12. // 构造UDP头部
13. udp_pack_hdr(udp,
14. src_port,// 源端口
15. dst_port,// 目的端口
16. UDP_HDR_LEN&nbsp;+&nbsp;payload_len);// UDP长度

18. // 计算校验和
19. udp_checksum(ip,&nbsp;udp,&nbsp;UDP_HDR_LEN&nbsp;+&nbsp;payload_len);

21. // 发送
22. ip_send(ip,&nbsp;packet,&nbsp;IP_HDR_LEN&nbsp;+&nbsp;UDP_HDR_LEN&nbsp;+&nbsp;payload_len);

9. ICMP数据包构造

9.1 ICMP协议概述

ICMP(Internet Control Message Protocol)用于传递控制消息和错误报告。

9.2 ICMP头部结构

1. ┌────┬────┬────────┬────────────┐
2. │8│8│16│可变│
3. │类型│代码│校验和│数据│
4. └────┴────┴────────┴────────────┘

9.3 ICMP头部定义

位置: include/dnet/icmp.h:25-29

1. struct&nbsp;icmp_hdr&nbsp;{
2. uint8_t&nbsp;icmp_type;// 消息类型
3. uint8_t&nbsp;icmp_code;// 类型子代码
4. uint16_t&nbsp;icmp_cksum;// 校验和
5. };

9.4 ICMP消息类型

| 类型 | 值 | 说明 | | — | — | — | | ICMP_ECHOREPLY | 0 | 回显应答 | | ICMP_UNREACH | 3 | 目的不可达 | | ICMP_ECHO | 8 | 回显请求 | | ICMP_TIMEXCEED | 11 | 超时 | | ICMP_REDIRECT | 5 | 重定向 |

位置: include/dnet/icmp.h:36-95

9.5 打包宏实现

位置: include/dnet/icmp.h:224-262

1. // 基本头部
2. #define&nbsp;icmp_pack_hdr(hdr,&nbsp;type,&nbsp;code)do{&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;\
3. struct&nbsp;icmp_hdr&nbsp;*icmp_pack_p&nbsp;=(struct&nbsp;icmp_hdr&nbsp;*)(hdr);&nbsp;\
4. icmp_pack_p->icmp_type&nbsp;=&nbsp;type;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;\
5. icmp_pack_p->icmp_code&nbsp;=&nbsp;code;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;\
6. }while(0)

8. // Echo消息
9. #define&nbsp;icmp_pack_hdr_echo(hdr,&nbsp;type,&nbsp;code,&nbsp;id,&nbsp;seq,&nbsp;data,&nbsp;len)do{&nbsp; &nbsp;\
10. struct&nbsp;icmp_msg_echo&nbsp;*echo_pack_p&nbsp;=(struct&nbsp;icmp_msg_echo&nbsp;*)&nbsp; &nbsp; &nbsp; \
11. ((uint8_t*)(hdr)+&nbsp;ICMP_HDR_LEN);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;\
12. icmp_pack_hdr(hdr,&nbsp;type,&nbsp;code);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; \
13. echo_pack_p->icmp_id&nbsp;=&nbsp;htons(id);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; \
14. echo_pack_p->icmp_seq&nbsp;=&nbsp;htons(seq);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; \
15. if(data&nbsp;!=&nbsp;NULL)&nbsp;memcpy(echo_pack_p->icmp_data,&nbsp;data,&nbsp;len);&nbsp;\
16. }while(0)

18. // 掩码消息
19. #define&nbsp;icmp_pack_hdr_mask(hdr,&nbsp;type,&nbsp;code,&nbsp;id,&nbsp;seq,&nbsp;mask)do{&nbsp; &nbsp; &nbsp; &nbsp;\
20. struct&nbsp;icmp_msg_mask&nbsp;*mask_pack_p&nbsp;=(struct&nbsp;icmp_msg_mask&nbsp;*)&nbsp; &nbsp; &nbsp; \
21. ((uint8_t*)(hdr)+&nbsp;ICMP_HDR_LEN);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;\
22. icmp_pack_hdr(hdr,&nbsp;type,&nbsp;code);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; \
23. mask_pack_p->icmp_id&nbsp;=&nbsp;htons(id);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; \
24. mask_pack_p->icmp_seq&nbsp;=&nbsp;htons(seq);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; \
25. mask_pack_p->icmp_mask&nbsp;=&nbsp;htonl(mask);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; \
26. }while(0)

9.6 构造示例

1. #include<dnet.h>

3. u_char packet[IP_HDR_LEN&nbsp;+&nbsp;ICMP_HDR_LEN&nbsp;+sizeof(struct&nbsp;icmp_msg_echo)];
4. struct&nbsp;ip_hdr&nbsp;*ip&nbsp;=(struct&nbsp;ip_hdr&nbsp;*)packet;
5. struct&nbsp;icmp_hdr&nbsp;*icmp&nbsp;=(struct&nbsp;icmp_hdr&nbsp;*)(packet&nbsp;+&nbsp;IP_HDR_LEN);
6. struct&nbsp;icmp_msg_echo&nbsp;*echo&nbsp;=(struct&nbsp;icmp_msg_echo&nbsp;*)(packet&nbsp;+&nbsp;IP_HDR_LEN&nbsp;+&nbsp;ICMP_HDR_LEN);

8. // 构造IP头部
9. ip_pack_hdr(ip,0,&nbsp;IP_HDR_LEN&nbsp;+&nbsp;ICMP_HDR_LEN&nbsp;+sizeof(struct&nbsp;icmp_msg_echo),
10. rand()&0xffff,0,&nbsp;IP_TTL_DEFAULT,&nbsp;IP_PROTO_ICMP,
11. src_ip,&nbsp;dst_ip);

13. // 构造ICMP Echo请求
14. icmp_pack_hdr_echo(icmp,&nbsp;ICMP_ECHO,0,
15. htons(12345),// ID
16. htons(1),// 序列号
17. NULL,0);

19. // 计算校验和
20. icmp_checksum(icmp,&nbsp;ICMP_HDR_LEN&nbsp;+sizeof(struct&nbsp;icmp_msg_echo));

22. // 发送
23. ip_send(ip,&nbsp;packet,&nbsp;IP_HDR_LEN&nbsp;+&nbsp;ICMP_HDR_LEN&nbsp;+sizeof(struct&nbsp;icmp_msg_echo));

9.7 ICMP消息数据结构

位置: include/dnet/icmp.h:108-218

1. // Echo消息
2. struct&nbsp;icmp_msg_echo&nbsp;{
3. uint16_t&nbsp;icmp_id;
4. uint16_t&nbsp;icmp_seq;
5. uint8_t&nbsp;icmp_data __flexarr;
6. };

8. // 掩码消息
9. struct&nbsp;icmp_msg_mask&nbsp;{
10. uint32_t&nbsp;icmp_id;
11. uint32_t&nbsp;icmp_seq;
12. uint32_t&nbsp;icmp_mask;
13. };

15. // 时间戳消息
16. struct&nbsp;icmp_msg_tstamp&nbsp;{
17. uint32_t&nbsp;icmp_id;
18. uint32_t&nbsp;icmp_seq;
19. uint32_t&nbsp;icmp_ts_orig;
20. uint32_t&nbsp;icmp_ts_rx;
21. uint32_t&nbsp;icmp_ts_tx;
22. };

10. ICMPv6数据包构造

10.1 ICMPv6协议概述

ICMPv6是IPv6的控制消息协议,功能类似于ICMP但更加强大。

10.2 ICMPv6头部结构

1. ┌────┬────┬────────┬────────────┐
2. │8│8│16│可变│
3. │类型│代码│校验和│数据│
4. └────┴────┴────────┴────────────┘

10.3 ICMPv6头部定义

位置: include/dnet/icmpv6.h:24-28

1. struct&nbsp;icmpv6_hdr&nbsp;{
2. uint8_t&nbsp;icmpv6_type;// 消息类型
3. uint8_t&nbsp;icmpv6_code;// 类型子代码
4. uint16_t&nbsp;icmpv6_cksum;// 校验和
5. };

10.4 ICMPv6消息类型

| 类型 | 值 | 说明 | | — | — | — | | ICMPV6_ECHO | 128 | 回显请求 | | ICMPV6_ECHOREPLY | 129 | 回显应答 | | ICMPV6_NEIGHBOR_SOLICITATION | 135 | 邻居请求 | | ICMPV6_NEIGHBOR_ADVERTISEMENT | 136 | 邻居通告 |

位置: include/dnet/icmpv6.h:35-56

10.5 打包宏实现

位置: include/dnet/icmpv6.h:91-114

1. // 基本头部
2. #define&nbsp;icmpv6_pack_hdr(hdr,&nbsp;type,&nbsp;code)do{&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;\
3. struct&nbsp;icmpv6_hdr&nbsp;*icmpv6_pack_p&nbsp;=(struct&nbsp;icmpv6_hdr&nbsp;*)(hdr);&nbsp;\
4. icmpv6_pack_p->icmpv6_type&nbsp;=&nbsp;type;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; \
5. icmpv6_pack_p->icmpv6_code&nbsp;=&nbsp;code;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; \
6. }while(0)

8. // Echo消息
9. #define&nbsp;icmpv6_pack_hdr_echo(hdr,&nbsp;type,&nbsp;code,&nbsp;id,&nbsp;seq,&nbsp;data,&nbsp;len)do{&nbsp;\
10. struct&nbsp;icmpv6_msg_echo&nbsp;*echo_pack_p&nbsp;=(struct&nbsp;icmpv6_msg_echo&nbsp;*)&nbsp; \
11. ((uint8_t*)(hdr)+&nbsp;ICMPV6_HDR_LEN);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;\
12. icmpv6_pack_hdr(hdr,&nbsp;type,&nbsp;code);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;\
13. echo_pack_p->icmpv6_id&nbsp;=&nbsp;htons(id);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; \
14. echo_pack_p->icmpv6_seq&nbsp;=&nbsp;htons(seq);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; \
15. memmove(echo_pack_p->icmpv6_data,&nbsp;data,&nbsp;len);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; \
16. }while(0)

18. // 邻居请求(带MAC选项)
19. #define&nbsp;icmpv6_pack_hdr_ns_mac(hdr,&nbsp;targetip,&nbsp;srcmac)do{&nbsp; &nbsp; &nbsp; &nbsp;\
20. struct&nbsp;icmpv6_msg_nd&nbsp;*nd_pack_p&nbsp;=(struct&nbsp;icmpv6_msg_nd&nbsp;*)&nbsp; &nbsp;\
21. ((uint8_t*)(hdr)+&nbsp;ICMPV6_HDR_LEN);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;\
22. icmpv6_pack_hdr(hdr,&nbsp;ICMPV6_NEIGHBOR_SOLICITATION,0);&nbsp; &nbsp; &nbsp; &nbsp; \
23. nd_pack_p->icmpv6_flags&nbsp;=0;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;\
24. memmove(&nd_pack_p->icmpv6_target,&(targetip),&nbsp;IP6_ADDR_LEN);&nbsp;\
25. nd_pack_p->icmpv6_option_type&nbsp;=1;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; \
26. nd_pack_p->icmpv6_option_length&nbsp;=1;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; \
27. memmove(&nd_pack_p->icmpv6_mac,&(srcmac),&nbsp;ETH_ADDR_LEN);&nbsp; &nbsp; \
28. }while(0)

10.6 构造示例

1. #include<dnet.h>

3. u_char packet[IP6_HDR_LEN&nbsp;+&nbsp;ICMPV6_HDR_LEN&nbsp;+sizeof(struct&nbsp;icmpv6_msg_echo)];
4. struct&nbsp;ip6_hdr&nbsp;*ip6&nbsp;=(struct&nbsp;ip6_hdr&nbsp;*)packet;
5. struct&nbsp;icmpv6_hdr&nbsp;*icmpv6&nbsp;=(struct&nbsp;icmpv6_hdr&nbsp;*)(packet&nbsp;+&nbsp;IP6_HDR_LEN);

7. // 构造IPv6头部
8. ip6_pack_hdr(ip6,0,0,
9. ICMPV6_HDR_LEN&nbsp;+sizeof(struct&nbsp;icmpv6_msg_echo),
10. IP_PROTO_ICMPV6,&nbsp;IP6_HLIM_DEFAULT,
11. &src_ip6,&dst_ip6);

13. // 构造ICMPv6 Echo请求
14. icmpv6_pack_hdr_echo(icmpv6,&nbsp;ICMPV6_ECHO,0,
15. htons(12345),// ID
16. htons(1),// 序列号
17. NULL,0);

19. // 计算校验和(包含伪头部)
20. ip6_checksum(packet,&nbsp;IP6_HDR_LEN&nbsp;+&nbsp;ICMPV6_HDR_LEN&nbsp;+sizeof(struct&nbsp;icmpv6_msg_echo));

22. // 发送
23. ip_send(ip,&nbsp;packet,&nbsp;IP6_HDR_LEN&nbsp;+&nbsp;ICMPV6_HDR_LEN&nbsp;+sizeof(struct&nbsp;icmpv6_msg_echo));

11. SCTP数据包构造

11.1 SCTP协议概述

SCTP(Stream Control Transmission Protocol)是一种可靠的传输协议,提供多流和多宿主支持。

11.2 SCTP头部结构

1. ┌──────────┬──────────┬────────┬────────┐
2. │16│16│32│32│
3. │源端口│目的端口│验证标签│校验和│
4. └──────────┴──────────┴────────┴────────┘

11.3 SCTP头部定义

位置: include/dnet/sctp.h:22-27

1. struct&nbsp;sctp_hdr&nbsp;{
2. uint16_t&nbsp;sh_sport;// 源端口
3. uint16_t&nbsp;sh_dport;// 目的端口
4. uint32_t&nbsp;sh_vtag;// SCTP验证标签
5. uint32_t&nbsp;sh_sum;// SCTP校验和(CRC-32C)
6. }&nbsp;__attribute__((__packed__));

11.4 SCTP块类型

| 块类型 | 值 | 说明 | | — | — | — | | SCTP_DATA | 0x00 | 数据块 | | SCTP_INIT | 0x01 | 初始化块 | | SCTP_INIT_ACK | 0x02 | 初始化确认 | | SCTP_SACK | 0x03 | 选择性确认 | | SCTP_HEARTBEAT | 0x04 | 心跳 | | SCTP_ABORT | 0x06 | 中止 |

位置: include/dnet/sctp.h:44-65

11.5 打包宏实现

位置: include/dnet/sctp.h:31-36

1. #define&nbsp;sctp_pack_hdr(hdr,&nbsp;sport,&nbsp;dport,&nbsp;vtag)do{&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;\
2. struct&nbsp;sctp_hdr&nbsp;*sctp_pack_p&nbsp;=(struct&nbsp;sctp_hdr&nbsp;*)(hdr);&nbsp;\
3. sctp_pack_p->sh_sport&nbsp;=&nbsp;htons(sport);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; \
4. sctp_pack_p->sh_dport&nbsp;=&nbsp;htons(dport);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; \
5. sctp_pack_p->sh_vtag&nbsp;=&nbsp;htonl(vtag);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; \
6. }while(0)

11.6 构造示例

1. #include<dnet.h>

3. u_char packet[IP_HDR_LEN&nbsp;+&nbsp;SCTP_HDR_LEN&nbsp;+sizeof(struct&nbsp;sctp_chunkhdr)];
4. struct&nbsp;ip_hdr&nbsp;*ip&nbsp;=(struct&nbsp;ip_hdr&nbsp;*)packet;
5. struct&nbsp;sctp_hdr&nbsp;*sctp&nbsp;=(struct&nbsp;sctp_hdr&nbsp;*)(packet&nbsp;+&nbsp;IP_HDR_LEN);
6. struct&nbsp;sctp_chunkhdr&nbsp;*chunk&nbsp;=(struct&nbsp;sctp_chunkhdr&nbsp;*)(packet&nbsp;+&nbsp;IP_HDR_LEN&nbsp;+&nbsp;SCTP_HDR_LEN);

8. // 构造IP头部
9. ip_pack_hdr(ip,0,&nbsp;IP_HDR_LEN&nbsp;+&nbsp;SCTP_HDR_LEN&nbsp;+&nbsp;chunk_len,
10. rand()&0xffff,0,&nbsp;IP_TTL_DEFAULT,&nbsp;IP_PROTO_SCTP,
11. src_ip,&nbsp;dst_ip);

13. // 构造SCTP头部
14. sctp_pack_hdr(sctp,
15. src_port,// 源端口
16. dst_port,// 目的端口
17. 0x12345678);// 验证标签

19. // 构造块头部
20. sctp_pack_chunkhdr(chunk,&nbsp;SCTP_INIT,0,sizeof(chunk_data));

22. // 计算CRC-32C校验和
23. ip_checksum(packet,&nbsp;IP_HDR_LEN&nbsp;+&nbsp;SCTP_HDR_LEN&nbsp;+&nbsp;chunk_len,0);

25. // 发送
26. ip_send(ip,&nbsp;packet,&nbsp;IP_HDR_LEN&nbsp;+&nbsp;SCTP_HDR_LEN&nbsp;+&nbsp;chunk_len);

12. 跨平台实现对比

12.1 IP数据包发送实现对比

| 平台 | 实现文件 | Socket类型 | 特点 | | — | — | — | — | | Unix/Linux | src/ip.c | SOCK_RAWIPPROTO_RAW | 直接发送,高性能 | | Cooked | src/ip-cooked.c | 通过以太网发送 | 自动ARP解析 | | Windows | src/ip-win32.c | SOCK_RAWIPPROTO_RAW | 需要管理员权限 |

12.2 Unix/Linux实现

位置: src/ip.c:25-93

1. struct&nbsp;ip_handle&nbsp;{
2. int&nbsp;fd;
3. };

5. ip_t*
6. ip_open(void)
7. {
8. ip_t*i;
9. int&nbsp;n;
10. socklen_t&nbsp;len;

12. if((i&nbsp;=&nbsp;calloc(1,sizeof(*i)))==&nbsp;NULL)
13. return(NULL);

15. // 创建原始socket
16. if((i->fd&nbsp;=&nbsp;socket(AF_INET,&nbsp;SOCK_RAW,&nbsp;IPPROTO_RAW))<0)
17. return(ip_close(i));

19. #ifdef&nbsp;IP_HDRINCL
20. // 设置IP头部包含选项
21. n&nbsp;=1;
22. if(setsockopt(i->fd,&nbsp;IPPROTO_IP,&nbsp;IP_HDRINCL,&n,sizeof(n))<0)
23. return(ip_close(i));
24. #endif
25. #ifdef&nbsp;SO_SNDBUF
26. // 优化发送缓冲区
27. len&nbsp;=sizeof(n);
28. if(getsockopt(i->fd,&nbsp;SOL_SOCKET,&nbsp;SO_SNDBUF,&n,&len)<0)
29. return(ip_close(i));

31. for(n&nbsp;+=128;&nbsp;n&nbsp;<1048576;&nbsp;n&nbsp;+=128){
32. if(setsockopt(i->fd,&nbsp;SOL_SOCKET,&nbsp;SO_SNDBUF,&n,&nbsp;len)<0){
33. if(errno&nbsp;==&nbsp;ENOBUFS)
34. break;
35. return(ip_close(i));
36. }
37. }
38. #endif
39. #ifdef&nbsp;SO_BROADCAST
40. // 允许广播
41. n&nbsp;=1;
42. if(setsockopt(i->fd,&nbsp;SOL_SOCKET,&nbsp;SO_BROADCAST,&n,sizeof(n))<0)
43. return(ip_close(i));
44. #endif
45. return(i);
46. }

48. ssize_t
49. ip_send(ip_t*i,constvoid*buf,size_t&nbsp;len)
50. {
51. struct&nbsp;ip_hdr&nbsp;*ip;
52. struct&nbsp;sockaddr_in sin;

54. ip&nbsp;=(struct&nbsp;ip_hdr&nbsp;*)buf;

56. memset(&sin,0,sizeof(sin));
57. #ifdef&nbsp;HAVE_SOCKADDR_SA_LEN
58. sin.sin_len&nbsp;=sizeof(sin);
59. #endif
60. sin.sin_family&nbsp;=&nbsp;AF_INET;
61. sin.sin_addr.s_addr&nbsp;=&nbsp;ip->ip_dst;

63. #ifdef&nbsp;HAVE_RAWIP_HOST_OFFLEN
64. // 某些平台需要特殊处理
65. ip->ip_len&nbsp;=&nbsp;ntohs(ip->ip_len);
66. ip->ip_off&nbsp;=&nbsp;ntohs(ip->ip_off);

68. len&nbsp;=&nbsp;sendto(i->fd,&nbsp;buf,&nbsp;len,0,
69. (struct&nbsp;sockaddr&nbsp;*)&sin,sizeof(sin));

71. ip->ip_len&nbsp;=&nbsp;htons(ip->ip_len);
72. ip->ip_off&nbsp;=&nbsp;htons(ip->ip_off);

74. return(len);
75. #else
76. return(sendto(i->fd,&nbsp;buf,&nbsp;len,0,
77. (struct&nbsp;sockaddr&nbsp;*)&sin,sizeof(sin)));
78. #endif
79. }

12.3 Cooked实现(自动ARP)

位置: src/ip-cooked.c:32-246

1. struct&nbsp;ip_handle&nbsp;{
2. arp_t*arp;// ARP处理
3. intf_t*intf;// 接口处理
4. route_t*route;// 路由处理
5. int&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;fd;
6. struct&nbsp;sockaddr_in sin;
7. LIST_HEAD(,&nbsp;ip_intf)&nbsp;ip_intf_list;
8. };
9. // 查找接口
10. staticstruct&nbsp;ip_intf&nbsp;*
11. _lookup_ip_intf(ip_t*ip,ip_addr_t&nbsp;dst)
12. {
13. struct&nbsp;ip_intf&nbsp;*ipi;
14. int&nbsp;n;
15. ip->sin.sin_addr.s_addr&nbsp;=&nbsp;dst;
16. n&nbsp;=sizeof(ip->sin);
17. // 使用内核路由查找源接口
18. if(connect(ip->fd,(struct&nbsp;sockaddr&nbsp;*)&ip->sin,&nbsp;n)<0)
19. return(NULL);
20. if(getsockname(ip->fd,(struct&nbsp;sockaddr&nbsp;*)&ip->sin,&n)<0)
21. return(NULL);
22. LIST_FOREACH(ipi,&ip->ip_intf_list,&nbsp;next){
23. if(ipi->pa.addr_ip&nbsp;==&nbsp;ip->sin.sin_addr.s_addr){
24. if(ipi->eth&nbsp;==&nbsp;NULL){
25. if((ipi->eth&nbsp;=&nbsp;eth_open(ipi->name))==&nbsp;NULL)
26. return(NULL);
27. }
28. if(ipi&nbsp;!=&nbsp;LIST_FIRST(&ip->ip_intf_list)){
29. LIST_REMOVE(ipi,&nbsp;next);
30. LIST_INSERT_HEAD(&ip->ip_intf_list,&nbsp;ipi,&nbsp;next);
31. }
32. return(ipi);
33. }
34. }
35. return(NULL);
36. }
37. // 发送数据包
38. ssize_t
39. ip_send(ip_t*ip,constvoid*buf,size_t&nbsp;len)
40. {
41. struct&nbsp;ip_hdr&nbsp;*iph;
42. struct&nbsp;ip_intf&nbsp;*ipi;
43. struct&nbsp;arp_entry arpent;
44. struct&nbsp;route_entry rtent;
45. u_char frame[ETH_LEN_MAX];
46. int&nbsp;i,&nbsp;usec;
47. iph&nbsp;=(struct&nbsp;ip_hdr&nbsp;*)buf;
48. // 查找出接口
49. if((ipi&nbsp;=&nbsp;_lookup_ip_intf(ip,&nbsp;iph->ip_dst))==&nbsp;NULL){
50. errno&nbsp;=&nbsp;EHOSTUNREACH;
51. return(-1);
52. }
53. arpent.arp_pa.addr_type&nbsp;=&nbsp;ADDR_TYPE_IP;
54. arpent.arp_pa.addr_bits&nbsp;=&nbsp;IP_ADDR_BITS;
55. arpent.arp_pa.addr_ip&nbsp;=&nbsp;iph->ip_dst;
56. memcpy(&rtent.route_dst,&arpent.arp_pa,sizeof(rtent.route_dst));
57. // 尝试获取MAC地址(最多3次)
58. for(i&nbsp;=0,&nbsp;usec&nbsp;=10;&nbsp;i&nbsp;<3;&nbsp;i++,&nbsp;usec&nbsp;*=100){
59. if(arp_get(ip->arp,&arpent)==0)
60. break;
61. // 检查路由
62. if(route_get(ip->route,&rtent)==0&&
63. rtent.route_gw.addr_ip&nbsp;!=&nbsp;ipi->pa.addr_ip){
64. memcpy(&arpent.arp_pa,&rtent.route_gw,
65. sizeof(arpent.arp_pa));
66. if(arp_get(ip->arp,&arpent)==0)
67. break;
68. }
69. // 发送ARP请求
70. _request_arp(ipi,&arpent.arp_pa);
71. usleep(usec);
72. }
73. // 未找到则使用广播
74. if(i&nbsp;==3)
75. memset(&arpent.arp_ha.addr_eth,0xff,&nbsp;ETH_ADDR_LEN);
76. // 添加以太网头部并发送
77. eth_pack_hdr(frame,&nbsp;arpent.arp_ha.addr_eth,
78. ipi->ha.addr_eth,&nbsp;ETH_TYPE_IP);
79. if(len&nbsp;>&nbsp;ipi->mtu){
80. // 分片发送
81. u_char&nbsp;*p,*start,*end,*ip_data;
82. int&nbsp;ip_hl,&nbsp;fraglen;
83. ip_hl&nbsp;=&nbsp;iph->ip_hl&nbsp;<<2;
84. fraglen&nbsp;=&nbsp;ipi->mtu&nbsp;-&nbsp;ip_hl;
85. iph&nbsp;=(struct&nbsp;ip_hdr&nbsp;*)(frame&nbsp;+&nbsp;ETH_HDR_LEN);
86. memcpy(iph,&nbsp;buf,&nbsp;ip_hl);
87. ip_data&nbsp;=(u_char&nbsp;*)iph&nbsp;+&nbsp;ip_hl;
88. start&nbsp;=(u_char&nbsp;*)buf&nbsp;+&nbsp;ip_hl;
89. end&nbsp;=(u_char&nbsp;*)buf&nbsp;+&nbsp;len;
90. for(p&nbsp;=&nbsp;start;&nbsp;p&nbsp;<&nbsp;end;){
91. memcpy(ip_data,&nbsp;p,&nbsp;fraglen);
92. iph->ip_len&nbsp;=&nbsp;htons(ip_hl&nbsp;+&nbsp;fraglen);
93. iph->ip_off&nbsp;=&nbsp;htons(((p&nbsp;+&nbsp;fraglen&nbsp;<&nbsp;end)?&nbsp;IP_MF&nbsp;:0)|
94. ((p&nbsp;-&nbsp;start)>>3));
95. ip_checksum(iph,&nbsp;ip_hl&nbsp;+&nbsp;fraglen);
96. i&nbsp;=&nbsp;ETH_HDR_LEN&nbsp;+&nbsp;ip_hl&nbsp;+&nbsp;fraglen;
97. if(eth_send(ipi->eth,&nbsp;frame,&nbsp;i)!=&nbsp;i)
98. return(-1);
99. p&nbsp;+=&nbsp;fraglen;
100. if(end&nbsp;-&nbsp;p&nbsp;<&nbsp;fraglen)
101. fraglen&nbsp;=&nbsp;end&nbsp;-&nbsp;p;
102. }
103. return(len);
104. }
105. memcpy(frame&nbsp;+&nbsp;ETH_HDR_LEN,&nbsp;buf,&nbsp;len);
106. i&nbsp;=&nbsp;ETH_HDR_LEN&nbsp;+&nbsp;len;
107. if(eth_send(ipi->eth,&nbsp;frame,&nbsp;i)!=&nbsp;i)
108. return(-1);
109. return(len);
110. }

12.4 Windows实现

位置: src/ip-win32.c:18-75

1. struct&nbsp;ip_handle&nbsp;{
2. WSADATA &nbsp; &nbsp; &nbsp; &nbsp; wsdata;
3. SOCKET &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;fd;
4. struct&nbsp;sockaddr_in sin;
5. };

7. ip_t*
8. ip_open(void)
9. {
10. BOOL on;
11. ip_t*ip;

13. if((ip&nbsp;=&nbsp;calloc(1,sizeof(*ip)))!=&nbsp;NULL){
14. // 初始化Winsock
15. if(WSAStartup(MAKEWORD(2,2),&ip->wsdata)!=0){
16. free(ip);
17. return(NULL);
18. }
19. // 创建原始socket
20. if((ip->fd&nbsp;=&nbsp;socket(AF_INET,&nbsp;SOCK_RAW,&nbsp;IPPROTO_RAW))==
21. INVALID_SOCKET)
22. return(ip_close(ip));

24. on&nbsp;=&nbsp;TRUE;
25. // 设置IP头部包含
26. if(setsockopt(ip->fd,&nbsp;IPPROTO_IP,&nbsp;IP_HDRINCL,
27. (constchar*)&on,sizeof(on))==&nbsp;SOCKET_ERROR){
28. SetLastError(ERROR_NETWORK_ACCESS_DENIED);
29. return(ip_close(ip));
30. }
31. ip->sin.sin_family&nbsp;=&nbsp;AF_INET;
32. ip->sin.sin_port&nbsp;=&nbsp;htons(666);
33. }
34. return(ip);
35. }

37. ssize_t
38. ip_send(ip_t*ip,constvoid*buf,size_t&nbsp;len)
39. {
40. struct&nbsp;ip_hdr&nbsp;*hdr&nbsp;=(struct&nbsp;ip_hdr&nbsp;*)buf;

42. ip->sin.sin_addr.s_addr&nbsp;=&nbsp;hdr->ip_src;

44. if((len&nbsp;=&nbsp;sendto(ip->fd,(constchar*)buf,&nbsp;len,0,
45. (struct&nbsp;sockaddr&nbsp;*)&ip->sin,sizeof(ip->sin)))!=&nbsp;SOCKET_ERROR)
46. return(len);

48. return(-1);
49. }

12.5 跨平台对比表

| 特性 | Unix/Linux | Cooked | Windows | | — | — | — | — | | Socket类型 | SOCK_RAW | 以太网发送 | SOCK_RAW | | 权限要求 | root/CAPNETRAW | root | 管理员 | | 自动ARP | 否 | 是 | 否 | | 分片支持 | 内核 | 手动 | 内核 | | 性能 | 高 | 中 | 高 | | 代码复杂度 | 低 | 高 | 低 | | IPv6支持 | 是 | 否 | 是 |


13. 实际应用示例

13.1 发送自定义TCP SYN包

1. #include<dnet.h>
2. #include<stdio.h>
3. #include<stdlib.h>
4. #include<string.h>
5. #include<time.h>

7. int&nbsp;main(int&nbsp;argc,char*argv[])
8. {
9. ip_t*ip;
10. u_char packet[IP_HDR_LEN&nbsp;+&nbsp;TCP_HDR_LEN];
11. struct&nbsp;ip_hdr&nbsp;*iph&nbsp;=(struct&nbsp;ip_hdr&nbsp;*)packet;
12. struct&nbsp;tcp_hdr&nbsp;*tcph&nbsp;=(struct&nbsp;tcp_hdr&nbsp;*)(packet&nbsp;+&nbsp;IP_HDR_LEN);
13. struct&nbsp;addr src,&nbsp;dst;

15. if(argc&nbsp;!=3){
16. fprintf(stderr,"Usage: %s <src_ip> <dst_ip:port>\n",&nbsp;argv[0]);
17. return1;
18. }

20. // 解析地址
21. if(addr_pton(argv[1],&src)<0||
22. addr_pton(argv[2],&dst)<0){
23. perror("addr_pton");
24. return1;
25. }

27. // 打开IP句柄
28. if((ip&nbsp;=&nbsp;ip_open())==&nbsp;NULL){
29. perror("ip_open");
30. return1;
31. }

33. // 构造IP头部
34. ip_pack_hdr(iph,
35. 0,// TOS
36. IP_HDR_LEN&nbsp;+&nbsp;TCP_HDR_LEN,// 总长度
37. rand()&0xffff,// ID
38. 0,// 片偏移
39. IP_TTL_DEFAULT,// TTL
40. IP_PROTO_TCP,// 协议
41. src.addr_ip,// 源IP
42. dst.addr_ip);// 目的IP

44. // 构造TCP头部(SYN包)
45. tcp_pack_hdr(tcph,
46. htons(rand()&0xffff),// 源端口
47. dst.addr_port,// 目的端口
48. htonl(rand()),// 序列号
49. 0,// 确认号
50. TH_SYN,// 标志
51. htons(65535),// 窗口
52. 0);// 紧急指针

54. // 计算校验和
55. tcp_checksum(iph,&nbsp;tcph,&nbsp;TCP_HDR_LEN);
56. ip_checksum(packet,&nbsp;IP_HDR_LEN&nbsp;+&nbsp;TCP_HDR_LEN,0);

58. // 发送
59. if(ip_send(ip,&nbsp;packet,&nbsp;IP_HDR_LEN&nbsp;+&nbsp;TCP_HDR_LEN)<0){
60. perror("ip_send");
61. }else{
62. printf("TCP SYN packet sent\n");
63. }

65. ip_close(ip);
66. return0;
67. }

13.2 发送ICMP Echo请求

1. #include<dnet.h>
2. #include<stdio.h>
3. #include<stdlib.h>
4. #include<string.h>
5. #include<time.h>

7. int&nbsp;main(int&nbsp;argc,char*argv[])
8. {
9. ip_t*ip;
10. u_char packet[IP_HDR_LEN&nbsp;+&nbsp;ICMP_HDR_LEN&nbsp;+sizeof(struct&nbsp;icmp_msg_echo)];
11. struct&nbsp;ip_hdr&nbsp;*iph&nbsp;=(struct&nbsp;ip_hdr&nbsp;*)packet;
12. struct&nbsp;icmp_hdr&nbsp;*icmph&nbsp;=(struct&nbsp;icmp_hdr&nbsp;*)(packet&nbsp;+&nbsp;IP_HDR_LEN);
13. struct&nbsp;icmp_msg_echo&nbsp;*echo&nbsp;=(struct&nbsp;icmp_msg_echo&nbsp;*)
14. (packet&nbsp;+&nbsp;IP_HDR_LEN&nbsp;+&nbsp;ICMP_HDR_LEN);
15. struct&nbsp;addr src,&nbsp;dst;
16. uint16_t&nbsp;id&nbsp;=&nbsp;rand()&0xffff;

18. if(argc&nbsp;!=3){
19. fprintf(stderr,"Usage: %s <src_ip> <dst_ip>\n",&nbsp;argv[0]);
20. return1;
21. }

23. // 解析地址
24. if(addr_pton(argv[1],&src)<0||
25. addr_pton(argv[2],&dst)<0){
26. perror("addr_pton");
27. return1;
28. }

30. // 打开IP句柄
31. if((ip&nbsp;=&nbsp;ip_open())==&nbsp;NULL){
32. perror("ip_open");
33. return1;
34. }

36. // 构造IP头部
37. ip_pack_hdr(iph,
38. 0,
39. IP_HDR_LEN&nbsp;+&nbsp;ICMP_HDR_LEN&nbsp;+sizeof(struct&nbsp;icmp_msg_echo),
40. rand()&0xffff,
41. 0,
42. IP_TTL_DEFAULT,
43. IP_PROTO_ICMP,
44. src.addr_ip,
45. dst.addr_ip);

47. // 构造ICMP Echo请求
48. icmp_pack_hdr_echo(icmph,&nbsp;ICMP_ECHO,0,&nbsp;id,&nbsp;htons(1),&nbsp;NULL,0);

50. // 计算校验和
51. icmp_checksum(icmph,&nbsp;ICMP_HDR_LEN&nbsp;+sizeof(struct&nbsp;icmp_msg_echo));
52. ip_checksum(packet,&nbsp;IP_HDR_LEN&nbsp;+&nbsp;ICMP_HDR_LEN&nbsp;+sizeof(struct&nbsp;icmp_msg_echo),0);

54. // 发送
55. if(ip_send(ip,&nbsp;packet,&nbsp;IP_HDR_LEN&nbsp;+&nbsp;ICMP_HDR_LEN&nbsp;+sizeof(struct&nbsp;icmp_msg_echo))<0){
56. perror("ip_send");
57. }else{
58. printf("ICMP Echo request sent\n");
59. }

61. ip_close(ip);
62. return0;
63. }

13.3 发送UDP数据包

1. #include<dnet.h>
2. #include<stdio.h>
3. #include<stdlib.h>
4. #include<string.h>
5. #include<time.h>

7. int&nbsp;main(int&nbsp;argc,char*argv[])
8. {
9. ip_t*ip;
10. u_char packet[IP_HDR_LEN&nbsp;+&nbsp;UDP_HDR_LEN&nbsp;+32];
11. struct&nbsp;ip_hdr&nbsp;*iph&nbsp;=(struct&nbsp;ip_hdr&nbsp;*)packet;
12. struct&nbsp;udp_hdr&nbsp;*udph&nbsp;=(struct&nbsp;udp_hdr&nbsp;*)(packet&nbsp;+&nbsp;IP_HDR_LEN);
13. struct&nbsp;addr src,&nbsp;dst;
14. uint8_t&nbsp;payload[32];

16. if(argc&nbsp;!=3){
17. fprintf(stderr,"Usage: %s <src_ip:port> <dst_ip:port>\n",&nbsp;argv[0]);
18. return1;
19. }

21. // 解析地址
22. if(addr_pton(argv[1],&src)<0||
23. addr_pton(argv[2],&dst)<0){
24. perror("addr_pton");
25. return1;
26. }

28. // 准备载荷
29. memset(payload,0xAA,sizeof(payload));

31. // 打开IP句柄
32. if((ip&nbsp;=&nbsp;ip_open())==&nbsp;NULL){
33. perror("ip_open");
34. return1;
35. }

37. // 构造IP头部
38. ip_pack_hdr(iph,
39. 0,
40. IP_HDR_LEN&nbsp;+&nbsp;UDP_HDR_LEN&nbsp;+sizeof(payload),
41. rand()&0xffff,
42. 0,
43. IP_TTL_DEFAULT,
44. IP_PROTO_UDP,
45. src.addr_ip,
46. dst.addr_ip);

48. // 构造UDP头部
49. udp_pack_hdr(udph,
50. src.addr_port,
51. dst.addr_port,
52. UDP_HDR_LEN&nbsp;+sizeof(payload));

54. // 填充载荷
55. memcpy(packet&nbsp;+&nbsp;IP_HDR_LEN&nbsp;+&nbsp;UDP_HDR_LEN,&nbsp;payload,sizeof(payload));

57. // 计算校验和
58. udp_checksum(iph,&nbsp;udph,&nbsp;UDP_HDR_LEN&nbsp;+sizeof(payload));
59. ip_checksum(packet,&nbsp;IP_HDR_LEN&nbsp;+&nbsp;UDP_HDR_LEN&nbsp;+sizeof(payload),0);

61. // 发送
62. if(ip_send(ip,&nbsp;packet,&nbsp;IP_HDR_LEN&nbsp;+&nbsp;UDP_HDR_LEN&nbsp;+sizeof(payload))<0){
63. perror("ip_send");
64. }else{
65. printf("UDP packet sent\n");
66. }

68. ip_close(ip);
69. return0;
70. }

13.4 使用dnet命令行工具

发送TCP SYN包

1. # 构造TCP SYN包
2. echo&nbsp;"Hello"|&nbsp;dnet tcp sport&nbsp;12345&nbsp;dport&nbsp;80&nbsp;flags SYN&nbsp;|&nbsp;\
3. dnet ip src&nbsp;192.168.1.100&nbsp;dst&nbsp;192.168.1.1|&nbsp;\
4. dnet send eth0

发送ICMP Echo请求

1. # 构造ICMP Echo请求
2. echo&nbsp;"Ping"|&nbsp;dnet icmp type&nbsp;8&nbsp;code&nbsp;0|&nbsp;\
3. dnet ip src&nbsp;192.168.1.100&nbsp;dst&nbsp;192.168.1.1|&nbsp;\
4. dnet send

发送UDP数据包

1. # 构造UDP数据包
2. echo&nbsp;"UDP data"|&nbsp;dnet udp sport&nbsp;12345&nbsp;dport&nbsp;53|&nbsp;\
3. dnet ip src&nbsp;192.168.1.100&nbsp;dst&nbsp;8.8.8.8|&nbsp;\
4. dnet send

13.5 发送ARP请求

1. #include<dnet.h>
2. #include<stdio.h>
3. #include<stdlib.h>
4. #include<string.h>

6. int&nbsp;main(int&nbsp;argc,char*argv[])
7. {
8. eth_t*eth;
9. u_char frame[ETH_HDR_LEN&nbsp;+&nbsp;ARP_HDR_LEN&nbsp;+&nbsp;ARP_ETHIP_LEN];
10. struct&nbsp;addr src_mac,&nbsp;src_ip,&nbsp;dst_ip;
11. eth_addr_t&nbsp;zero_mac&nbsp;={0};

13. if(argc&nbsp;!=3){
14. fprintf(stderr,"Usage: %s <src_mac> <dst_ip>\n",&nbsp;argv[0]);
15. return1;
16. }

18. // 解析地址
19. if(addr_pton(argv[1],&src_mac)<0||
20. addr_pton(argv[2],&dst_ip)<0){
21. perror("addr_pton");
22. return1;
23. }

25. // 打开以太网设备
26. if((eth&nbsp;=&nbsp;eth_open("eth0"))==&nbsp;NULL){
27. perror("eth_open");
28. return1;
29. }

31. // 获取源IP
32. intf_t*intf;
33. struct&nbsp;intf_entry entry;
34. if((intf&nbsp;=&nbsp;intf_open())==&nbsp;NULL){
35. perror("intf_open");
36. eth_close(eth);
37. return1;
38. }
39. intf_get(intf,&entry);
40. src_ip&nbsp;=&nbsp;entry.intf_addr;
41. intf_close(intf);

43. // 构造以太网头部
44. eth_pack_hdr(frame,&nbsp;ETH_ADDR_BROADCAST,&nbsp;src_mac.addr_eth,&nbsp;ETH_TYPE_ARP);

46. // 构造ARP请求
47. arp_pack_hdr_ethip(frame&nbsp;+&nbsp;ETH_HDR_LEN,&nbsp;ARP_OP_REQUEST,
48. src_mac.addr_eth,&nbsp;src_ip.addr_ip,
49. zero_mac,&nbsp;dst_ip.addr_ip);

51. // 发送
52. if(eth_send(eth,&nbsp;frame,sizeof(frame))<0){
53. perror("eth_send");
54. }else{
55. printf("ARP request sent\n");
56. }

58. eth_close(eth);
59. return0;
60. }

13.6 完整的TCP SYN扫描器

1. #include<dnet.h>
2. #include<stdio.h>
3. #include<stdlib.h>
4. #include<string.h>
5. #include<time.h>
6. #include<pcap.h>

8. #define&nbsp;SNAPLEN&nbsp;65535
9. #define&nbsp;TIMEOUT&nbsp;1000

11. void&nbsp;packet_handler(u_char&nbsp;*args,conststruct&nbsp;pcap_pkthdr&nbsp;*header,
12. const&nbsp;u_char&nbsp;*packet)
13. {
14. struct&nbsp;ip_hdr&nbsp;*iph&nbsp;=(struct&nbsp;ip_hdr&nbsp;*)(packet&nbsp;+14);
15. struct&nbsp;tcp_hdr&nbsp;*tcph&nbsp;=(struct&nbsp;tcp_hdr&nbsp;*)(packet&nbsp;+14+(iph->ip_hl&nbsp;<<2));

17. if(iph->ip_p&nbsp;==&nbsp;IP_PROTO_TCP&nbsp;&&(tcph->th_flags&nbsp;&(TH_SYN&nbsp;|&nbsp;TH_ACK))==(TH_SYN&nbsp;|&nbsp;TH_ACK)){
18. printf("Port %d is OPEN\n",&nbsp;ntohs(tcph->th_sport));
19. }
20. }

22. int&nbsp;main(int&nbsp;argc,char*argv[])
23. {
24. ip_t*ip;
25. pcap_t*pcap;
26. struct&nbsp;addr src,&nbsp;dst;
27. char&nbsp;errbuf[PCAP_ERRBUF_SIZE];
28. u_char packet[IP_HDR_LEN&nbsp;+&nbsp;TCP_HDR_LEN];
29. struct&nbsp;ip_hdr&nbsp;*iph&nbsp;=(struct&nbsp;ip_hdr&nbsp;*)packet;
30. struct&nbsp;tcp_hdr&nbsp;*tcph&nbsp;=(struct&nbsp;tcp_hdr&nbsp;*)(packet&nbsp;+&nbsp;IP_HDR_LEN);
31. int&nbsp;port;

33. if(argc&nbsp;!=3){
34. fprintf(stderr,"Usage: %s <src_ip> <dst_ip>\n",&nbsp;argv[0]);
35. return1;
36. }

38. // 解析地址
39. if(addr_pton(argv[1],&src)<0||
40. addr_pton(argv[2],&dst)<0){
41. perror("addr_pton");
42. return1;
43. }

45. // 打开IP句柄
46. if((ip&nbsp;=&nbsp;ip_open())==&nbsp;NULL){
47. perror("ip_open");
48. return1;
49. }

51. // 打开pcap用于接收响应
52. pcap&nbsp;=&nbsp;pcap_open_live("eth0",&nbsp;SNAPLEN,1,&nbsp;TIMEOUT,&nbsp;errbuf);
53. if(pcap&nbsp;==&nbsp;NULL){
54. fprintf(stderr,"pcap_open_live: %s\n",&nbsp;errbuf);
55. ip_close(ip);
56. return1;
57. }

59. // 设置过滤器
60. struct&nbsp;bpf_program fp;
61. char&nbsp;filter[256];
62. snprintf(filter,sizeof(filter),"src host %s and tcp[tcpflags] & (tcp-syn|tcp-ack) == (tcp-syn|tcp-ack)",&nbsp;argv[2]);
63. if(pcap_compile(pcap,&fp,&nbsp;filter,0,&nbsp;PCAP_NETMASK_UNKNOWN)<0){
64. fprintf(stderr,"pcap_compile: %s\n",&nbsp;pcap_geterr(pcap));
65. pcap_close(pcap);
66. ip_close(ip);
67. return1;
68. }
69. if(pcap_setfilter(pcap,&fp)<0){
70. fprintf(stderr,"pcap_setfilter: %s\n",&nbsp;pcap_geterr(pcap));
71. pcap_freecode(&fp);
72. pcap_close(pcap);
73. ip_close(ip);
74. return1;
75. }
76. pcap_freecode(&fp);

78. // 扫描常见端口
79. printf("Scanning %s...\n",&nbsp;argv[2]);
80. for(port&nbsp;=1;&nbsp;port&nbsp;<=1024;&nbsp;port++){
81. // 构造IP头部
82. ip_pack_hdr(iph,
83. 0,
84. IP_HDR_LEN&nbsp;+&nbsp;TCP_HDR_LEN,
85. rand()&0xffff,
86. 0,
87. IP_TTL_DEFAULT,
88. IP_PROTO_TCP,
89. src.addr_ip,
90. dst.addr_ip);

92. // 构造TCP SYN包
93. tcp_pack_hdr(tcph,
94. htons(rand()&0xffff),
95. htons(port),
96. htonl(rand()),
97. 0,
98. TH_SYN,
99. htons(65535),
100. 0);

102. // 计算校验和
103. tcp_checksum(iph,&nbsp;tcph,&nbsp;TCP_HDR_LEN);
104. ip_checksum(packet,&nbsp;IP_HDR_LEN&nbsp;+&nbsp;TCP_HDR_LEN,0);

106. // 发送
107. ip_send(ip,&nbsp;packet,&nbsp;IP_HDR_LEN&nbsp;+&nbsp;TCP_HDR_LEN);

109. // 接收响应
110. pcap_dispatch(pcap,-1,&nbsp;packet_handler,&nbsp;NULL);
111. }

113. pcap_close(pcap);
114. ip_close(ip);
115. return0;
116. }

14. 常见问题与解决方案

14.1 权限问题

问题:创建原始socket失败

1. Operationnot&nbsp;permitted

解决方案

Unix/Linux:

1. # 使用root权限运行
2. sudo&nbsp;./program

4. # 或使用capabilities
5. sudo setcap cap_net_raw+ep&nbsp;./program

Windows:

1. # 以管理员身份运行cmd
2. # 右键点击cmd -> 以管理员身份运行

14.2 校验和错误

问题:数据包被接收方丢弃

解决方案

1. // 确保校验和计算正确
2. ip_checksum(packet,&nbsp;len,0);

4. // 或手动计算
5. uint16_t&nbsp;calc_checksum(void*buf,size_t&nbsp;len){
6. uint32_t&nbsp;sum&nbsp;=0;
7. uint16_t*ptr&nbsp;=(uint16_t*)buf;

9. while(len&nbsp;>1){
10. sum&nbsp;+=*ptr++;
11. len&nbsp;-=2;
12. }

14. if(len&nbsp;==1){
15. sum&nbsp;+=*(uint8_t*)ptr&nbsp;<<8;
16. }

18. while(sum&nbsp;>>16){
19. sum&nbsp;=(sum&nbsp;&0xffff)+(sum&nbsp;>>16);
20. }

22. return~sum;
23. }

14.3 字节序问题

问题:端口或地址解析错误

解决方案

1. // 始终使用htons/htonl转换
2. uint16_t&nbsp;port&nbsp;=&nbsp;htons(80);
3. uint32_t&nbsp;addr&nbsp;=&nbsp;htonl(0x0a000001);

5. // 检查时使用ntohs/ntohl
6. uint16_t&nbsp;hport&nbsp;=&nbsp;ntohs(tcph->th_sport);
7. uint32_t&nbsp;haddr&nbsp;=&nbsp;ntohl(iph->ip_src);

14.4 数据包长度错误

问题:数据包被截断

解决方案

1. // 确保总长度正确计算
2. ip->ip_len&nbsp;=&nbsp;htons(IP_HDR_LEN&nbsp;+&nbsp;TCP_HDR_LEN&nbsp;+&nbsp;payload_len);

4. // UDP也需要设置长度
5. udp->uh_ulen&nbsp;=&nbsp;htons(UDP_HDR_LEN&nbsp;+&nbsp;payload_len);

14.5 分片问题

问题:大数据包无法发送

解决方案

1. // 设置MTU或使用分片
2. #define&nbsp;MTU&nbsp;1500

4. if(total_len&nbsp;>&nbsp;MTU&nbsp;-&nbsp;IP_HDR_LEN){
5. // 使用ip-cooked模式的自动分片
6. // 或手动分片
7. int&nbsp;offset&nbsp;=0;
8. while(offset&nbsp;<&nbsp;total_len){
9. int&nbsp;frag_len&nbsp;=&nbsp;MTU&nbsp;-&nbsp;IP_HDR_LEN;
10. if(offset&nbsp;+&nbsp;frag_len&nbsp;>&nbsp;total_len)
11. frag_len&nbsp;=&nbsp;total_len&nbsp;-&nbsp;offset;

13. // 发送分片
14. // ...
15. offset&nbsp;+=&nbsp;frag_len;
16. }
17. }

14.6 ARP未解析

问题:数据包发送失败

解决方案

1. // 手动发送ARP请求
2. eth_addr_t&nbsp;broadcast&nbsp;={0xff,0xff,0xff,0xff,0xff,0xff};
3. eth_addr_t&nbsp;zero&nbsp;={0};

5. eth_pack_hdr(frame,&nbsp;broadcast,&nbsp;src_mac,&nbsp;ETH_TYPE_ARP);
6. arp_pack_hdr_ethip(frame&nbsp;+&nbsp;ETH_HDR_LEN,&nbsp;ARP_OP_REQUEST,
7. src_mac,&nbsp;src_ip,&nbsp;zero,&nbsp;dst_ip);
8. eth_send(eth,&nbsp;frame,sizeof(frame));

10. // 等待ARP响应
11. sleep(1);

14.7 Windows特殊处理

问题:Windows上IP头部不生效

解决方案

1. // 确保设置IP_HDRINCL选项
2. BOOL on&nbsp;=&nbsp;TRUE;
3. setsockopt(fd,&nbsp;IPPROTO_IP,&nbsp;IP_HDRINCL,(char*)&on,sizeof(on));

5. // 注意:Windows上某些字段会自动填充
6. // 不要设置IP头部中的TTL、校验和等字段

14.8 IPv6校验和问题

问题:IPv6数据包校验和错误

解决方案

1. // IPv6校验和包含伪头部
2. // 使用libdnet提供的函数
3. ip6_checksum(packet,&nbsp;len);

5. // 或手动计算
6. uint32_t&nbsp;sum&nbsp;=0;

8. // 添加伪头部(源地址 + 目的地址)
9. sum&nbsp;+=&nbsp;ip_cksum_add(&ip6->ip6_src,32,0);

11. // 添加上层协议和长度
12. sum&nbsp;+=&nbsp;htons(next_header&nbsp;+&nbsp;payload_len);

14. // 添加上层协议数据
15. sum&nbsp;+=&nbsp;ip_cksum_add(payload,&nbsp;payload_len,0);

17. // 计算最终校验和
18. checksum&nbsp;=&nbsp;ip_cksum_carry(sum);

14.9 选项添加错误

问题:添加IP或TCP选项失败

解决方案

1. // 使用libdnet提供的函数
2. ssize_t&nbsp;ret&nbsp;=&nbsp;ip_add_option(packet,sizeof(packet),
3. IP_PROTO_IP,&nbsp;optbuf,&nbsp;optlen);

5. if(ret&nbsp;<0){
6. perror("ip_add_option");
7. return-1;
8. }

10. // 注意:选项长度必须正确
11. // NOP选项长度为1
12. // 其他选项至少为2字节

14.10 性能优化

问题:发送大量数据包性能低

解决方案

1. // 1. 增加发送缓冲区
2. int&nbsp;sndbuf&nbsp;=1024*1024;// 1MB
3. setsockopt(fd,&nbsp;SOL_SOCKET,&nbsp;SO_SNDBUF,&sndbuf,sizeof(sndbuf));

5. // 2. 重用缓冲区
6. static&nbsp;u_char packet_buf[IP_LEN_MAX];

8. // 3. 批量发送
9. for(int&nbsp;i&nbsp;=0;&nbsp;i&nbsp;<&nbsp;count;&nbsp;i++){
10. // 构造数据包
11. ip_pack_hdr(packet_buf,...);
12. tcp_pack_hdr(packet_buf&nbsp;+&nbsp;IP_HDR_LEN,...);

14. // 发送
15. ip_send(ip,&nbsp;packet_buf,&nbsp;len);
16. }

18. // 4. 使用非阻塞IO
19. int&nbsp;flags&nbsp;=&nbsp;fcntl(fd,&nbsp;F_GETFL,0);
20. fcntl(fd,&nbsp;F_SETFL,&nbsp;flags&nbsp;|&nbsp;O_NONBLOCK);

总结

本文档深入分析了libdnet中原始数据包构造的实现机制,涵盖了从以太网到应用层的所有主要协议:

核心要点

  1. 分层构造:从物理层到应用层的完整数据包构造流程
  2. 宏封装:使用宏简化构造代码,提高可读性
  3. 跨平台支持:Unix/Linux、Windows等平台的差异处理
  4. 校验和计算:各种协议的校验和计算方法
  5. 实际应用:扫描器、网络工具等实用示例

关键文件

| 文件 | 说明 | | — | — | | include/dnet/eth.h | 以太网头部定义和宏 | | include/dnet/arp.h | ARP头部定义和宏 | | include/dnet/ip.h | IP头部定义和宏 | | include/dnet/ip6.h | IPv6头部定义和宏 | | include/dnet/tcp.h | TCP头部定义和宏 | | include/dnet/udp.h | UDP头部定义和宏 | | include/dnet/icmp.h | ICMP头部定义和宏 | | include/dnet/icmpv6.h | ICMPv6头部定义和宏 | | include/dnet/sctp.h | SCTP头部定义和宏 | | src/ip.c | Unix/Linux IP实现 | | src/ip-cooked.c | Cooked IP实现 | | src/ip-win32.c | Windows IP实现 | | src/ip-util.c | 校验和和选项处理 | | src/ip6.c | IPv6校验和处理 |

下一步

建议结合以下文档进一步学习:

  • 06-网络接口控制实现深入分析.md
  • 07-MAC地址处理深入分析.md
  • 04-ARP操作源码深入分析.md

文档版本:1.0 最后更新:2026年3月5日 作者:基于libdnet 1.13源码分析

  • 公众号:安全狗的自我修养
  • vx:2207344074
  • http://gitee.com/haidragon
  • http://github.com/haidragon
  • bilibili:haidragonx

#


免责声明:

本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。

任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。

本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我

本文转载自:安全狗的自我修养 haidragon haidragon《跨平台底层网络库libdnet源码分析系列(八)》

评论:0   参与:  0