必威体育Betway必威体育官网
当前位置:首页 > IT技术

libnet入门

时间:2019-07-04 04:43:24来源:IT技术作者:seo实验室小编阅读:86次「手机版」
 

libnet

在Unix系统平台上的网络安全工具开发中,目前最为流行的C API library有libnet、libpcap、libnids和libicmp等。它们分别从不同层次和角度提供了不同的功能函数。使网络开发人员能够忽略网络底层细节的实现,从而专注于程序本身具体功能的设计与开发。其中,

* libnet提供的接口函数主要实现和封装了数据包的构造和发送过程。

* libpcap提供的接口函数主要实现和封装了与数据包截获有关的过程。

* libnids提供的接口函数主要实现了开发网络入侵监测系统所必须的一些结构框架

* libicmp等相对较为简单,它封装的是ICMP数据包的主要处理过程(构造、发送、接收等)。 利用这些C函数库的接口,网络安全工具开发人员可以很方便地编写出具有结构化强、健壮性好、可移植性高等特点的程序,如scanner、sniffer、firewall、IDS等。

---[[ libnet ]]------------------------------------------

libnet库的最新版本为1.0.0,它一共约7600行C源代码,33个源程序文件,12个C头文件,50余个自定义函数,提供的接口函数包含15种数据包生成器和两种数据包发送器(ip层和数据链路层)。目前只支持IPv4,不支持IPv6。已经过测试的系统平台包括:

* OpenBSD 2.6snap, 2.5, 2.4, 2.3, 2.2 (i386)

* FreeBSD 4.0-STABLE, 3.3-STABLE, 3.2-RElease, 3.1-CURRENT, 3.0, 2.2 (i386)

* NetBSD 1.3.2 (i386)

* BSD/OS 3.x (i386)

* BSDi 3.0 (i386)

* linux 2.2.x, 2.0.3x, 2.1.124 (i386, alpha) (libc: 2.4.x, glibc: 2.0.x)

* Solaris 7 (SPARC, gcc 2.7.2[13], 2.8.2), 2.6 (SPARC, gcc 2.8.2),

2.5.x (SPARC, gcc 2.7.2[13])

* IRIX 6.2

* MacOS 5.3rhapsody (powerpc)

libnet提供的接口函数按其作用可分为四类:

* 内存管理(分配和释放)函数

* 地址解析函数

* 数据包构造函数

* 数据包发送函数

以下分别列出这些接口函数及其功能(其参数含义简单易懂,不再解释):

★ 内存管理函数

单数据包内存初始化:

int libnet_init_packet(u_short packet_size, u_char **buf);

单数据包内存释放:

void libnet_destroy_packet(u_char **buf);

多数据包内存初始化:

int libnet_init_packet_arena(struct libnet_arena **arena,

u_short packet_num, u_short packet_size);

访问多数据包内存中的下一个数据包:

u_char *libnet_next_packet_from_arena(struct libnet_arena **arena,

u_short packet_size);

多数据包内存释放:

void libnet_destroy_packet_arena(struct libnet_arena **arena);

★ 地址解析函数

解析主机名:

u_char *libnet_host_lookup(u_long ip, u_short use_name);

解析主机名(可重入函数):

void libnet_host_lookup_r(u_long ip, u_short use_name, u_char *buf);

域名解析:

u_long libnet_name_resolve(u_char *ip, u_short use_name);

获取接口设备IP地址:

u_long libnet_get_Ipaddr(struct libnet_link_int *l,

const u_char *device, const u_char *ebuf);

获取接口设备硬件地址:

struct ether_addr *libnet_get_hwaddr(struct libnet_link_int *l,

const u_char *device,

const u_char *ebuf);

★ 数据包构造函数

ARP协议数据包:

int libnet_build_arp(u_short hrdw, u_short prot, u_short h_len,

u_short p_len, u_short op, u_char *s_ha,

u_char *s_pa, u_char *t_ha, u_char *t_pa,

const u_char *payload, int payload_len,

u_char *packet_buf);

DNS协议数据包:

int libnet_build_dns(u_short id, u_short flags, u_short num_q,

u_short num_answ_rr, u_short num_auth_rr,

u_short num_add_rr, const u_char * payload,

int payload_len, u_char *packet_buf);

以太网协议数据包:

int libnet_build_ethernet(u_char *daddr, u_char *saddr, u_short id,

const u_char *payload, int payload_len,

u_char *packet_buf);

icmp协议数据包(ICMP_ECHO / ICMP_ECHOREPLY):

int libnet_build_icmp_echo(u_char type, u_char code, u_short id,

u_short seq, const u_char *payload,

int payload_len, u_char *packet_buf);

ICMP协议数据包(ICMP_MASKREQ / ICMP_MASKREPLY):

int libnet_build_icmp_mask(u_char type, u_char code, u_short id,

u_short seq, u_long mask,

const u_char *payload, int payload_len,

u_char *packet_buf);

ICMP协议数据包(ICMP_UNREACH):

int libnet_build_icmp_unreach(u_char type, u_char code,

u_short orig_len, u_char orig_tos,

u_short orig_id, u_short orig_frag,

u_char orig_ttl, u_char orig_prot,

u_long orig_saddr, u_long orig_daddr,

const u_char *payload, int payload_len,

u_char *packet_buf);

ICMP协议数据包(ICMP_TIMEXCEED):

int libnet_build_icmp_timeexceed(u_char type, u_char code,

u_short orig_len, u_char orig_tos,

u_short orig_id, u_short orig_frag,

u_char orig_ttl, u_char orig_prot,

u_long orig_saddr, u_long orig_daddr,

const u_char *payload, int payload_len,

u_char *packet_buf);

ICMP协议数据包(ICMP_REDIRECT):

int libnet_build_icmp_redirect(u_char type, u_char code, u_long gateway,

u_short orig_len, u_char orig_tos,

u_short orig_id, u_short orig_frag,

u_char orig_ttl, u_char orig_prot,

u_long orig_saddr, u_long orig_daddr,

const u_char *payload, int payload_len,

u_char *packet_buf);

ICMP协议数据包(ICMP_TSTAMP / ICMP_TSTAMPREPLY):

int libnet_build_icmp_timestamp(u_char type, u_char code, u_short id,

u_short seq, n_time otime, n_time rtime,

n_time ttime, const u_char *payload,

int payload_len, u_char *packet_buf);

IGMP协议数据包:

int libnet_build_igmp(u_char type, u_char code, u_long ip,

const u_char *payload, int payload_len,

u_char *packet_buf);

ip协议数据包:

int libnet_build_ip(u_short len, u_char tos, u_short ip_id, u_short frag,

u_char ttl, u_char protocol, u_long saddr,

u_long daddr, const u_char *payload, int payload_len,

u_char *packet_buf);

OSPF路由协议数据包:

int libnet_build_ospf(u_short len, u_char type, u_long router_id,

u_long area_id, u_short auth_type,

const char *payload, int payload_s, u_char *buf);

OSPF路由协议数据包(Hello):

int libnet_build_ospf_hello(u_long netmask, u_short Interval,

u_char options, u_char priority,

u_int dead_interval, u_long des_router,

u_long backup, u_long neighbor,

const char *payload, int payload_s,

u_char *buf);

OSPF路由协议数据包(DataBase Description (DBD)):

int libnet_build_ospf_dbd(u_short len, u_char options, u_char type,

u_int sequence_num, const char *payload,

int payload_s, u_char *buf);

OSPF路由协议数据包(Link State request (LSR)):

int libnet_build_ospf_lsr(u_int type, u_int ls_id, u_long adv_router,

const char *payload, int payload_s,

u_char *buf);

OSPF路由协议数据包(Link State Update (LSU)):

int libnet_build_ospf_lsu(u_int num, const char *payload,

int payload_s, u_char *buf);

OSPF路由协议数据包(Link State Acknowledgement (LSA)):

int libnet_build_ospf_lsa(u_short age, u_char options, u_char type,

u_int ls_id, u_long adv_router,

u_int sequence_num, u_short len,

const char *payload, int payload_s,

u_char *buf);

OSPF路由协议数据包(OSPF Link Sate NetworkLink State Router):

int libnet_build_ospf_lsa_net(u_long netmask, u_int router_id,

const char *payload, int payload_s,

u_char *buf);

OSPF路由协议数据包(Link State Router):

int libnet_build_ospf_lsa_rtr(u_short flags, u_short num, u_int id,

u_int data, u_char type, u_char tos,

u_short metric, const char *payload,

int payload_s, u_char *buf);

OSPF路由协议数据包(Link State Summary):

int libnet_build_ospf_lsa_sum(u_long netmask, u_int metric, u_int tos,

const char *payload, int payload_s,

u_char *buf);

OSPF路由协议数据包(Link State AS External):

int libnet_build_ospf_lsa_as(u_long netmask, u_int metric,

u_long fwd_addr, u_int tag,

const char *payload, int payload_s,

u_char *buf);

RIP路由协议数据包:

int libnet_build_rip(u_char cmd, u_char ver, u_short domain,

u_short addr_fam, u_short route_tag, u_long ip,

u_long mask, u_long next_hop, u_long metric,

const u_char *payload, int payload_len,

u_char *packet_buf);

TCP协议数据包:

int libnet_build_tcp(u_short th_sport, u_short th_dport, u_long th_seq,

u_long th_ack, u_char th_flags, u_short th_win,

u_short th_urg, const u_char *payload,

int payload_len, u_char *packet_buf);

udp协议数据包:

int libnet_build_udp(u_short sport, u_short dport, const u_char *payload,

int payload_len, u_char *packet_buf);

IP协议数据包选项:

int libnet_insert_ipo(struct ipoption *opt, u_char opt_len,

u_char *packet_buf);

TCP协议数据包选项:

int libnet_insert_tcpo(struct tcpoption *opt, u_char opt_len,

u_char *packet_buf);

★ 数据包发送函数

打开raw socket

int libnet_open_raw_sock(int protocol);

关闭raw socket:

int libnet_close_raw_sock(int socket);

选择接口设备:

int libnet_select_device(struct sockaddr_in *sin,

u_char **device, u_char *ebuf);

打开链路层接口设备:

struct libnet_link_int *libnet_open_link_interface(char *device,

char *ebuf);

关闭链路层接口设备:

int libnet_close_link_interface(struct libnet_link_int *l);

发送IP数据包:

int libnet_write_ip(int socket, u_char *packet, int packet_size);

发送链路层数据包:

int libnet_write_link_layer(struct libnet_link_int *l,

const u_char *device, u_char *packet,

int packet_size);

检验和计算:

int libnet_do_checksum(u_char *packet, int protocol, int packet_size);

★ 相关的支持函数

随机数种子生成器:

int libnet_seed_prand();

获取随机数:

u_long libnet_get_prand(int modulus);

16进制数据输出:

void libnet_hex_dump(u_char * buf, int len, int swap, FILE *stream);

端口列表链初始化:

int libnet_plist_chain_new(struct libnet_plist_chain **plist,

char *token_list);

获取端口列表链的下一项(端口范围):

int libnet_plist_chain_next_pair(struct libnet_plist_chain *plist,

u_short *bport, u_short *eport);

端口列表链输出显示:

int libnet_plist_chain_dump(struct libnet_plist_chain *plist);

获取端口列表链:

u_char *libnet_plist_chain_dump_string(struct libnet_plist_chain *plist);

端口列表链内存释放:

void libnet_plist_chain_free(struct libnet_plist_chain *plist);

★ 数据常量

==================================================================================

数据包头大小定义:

常量名 数值(字节数)

LIBNET_ARP_H 28

LIBNET_DNS_H 12

LIBNET_ETH_H 14

LIBNET_ICMP_H 4

LIBNET_ICMP_ECHO_H 8

LIBNET_ICMP_MASK_H 12

LIBNET_ICMP_UNREACH_H 8

LIBNET_ICMP_TIMXCEED_H 8

LIBNET_ICMP_REDIRECT_H 8

LIBNET_ICMP_TS_H 20

LIBNET_IGMP_H 8

LIBNET_IP_H 20

LIBNET_RIP_H 24

LIBNET_TCP_H 20

LIBNET_UDP_H 8

==================================================================================

数据包内存常量:

常量名 含义

LIBNET_PACKET TCP/UDP数据包头 + IP数据包头使用的内存

LIBNET_OPTS IP或TCP选项使用的内存

LIBNET_MAX_PACKET IP_MAXPACKET (65535字节)使用的内存

==================================================================================

随机数发生器常量(libnet_get_prand()函数使用):

常量名 数值

LIBNET_PRAND_MAX 65535

LIBNET_PR2 0 - 2

LIBNET_PR8 0 - 255

LIBNET_PR16 0 - 32767

LIBNET_PRu16 0 - 65535

LIBNET_PR32 0 - 2147483647

LIBNET_PRu32 0 - 4294967295

==================================================================================

错误消息常量(libnet_ERROR()函数使用):

常量名 含义

LIBNET_ERR_WARNING 警告类型消息

LIBNET_ERR_critical 紧急类型消息

LIBNET_ERR_FATAL 致命错误消息

==================================================================================

libnet_host_lookup()、libnet_host_lookup_r()和libnet_name_resolve()函数使用的常量:

常量名 含义

LIBNET_DONT_RESOLVE 不将IP地址解析为FQDN名

LIBNET_RESOLVE 尝试将IP地址解析为FQDN名

==================================================================================

宏定义

宏名 功能

LIBNET_GET_ARENA_SIZE(arena) 返回多数据包内存缓冲区大小(字节数)

LIBNET_GET_ARENA_REMAINING_BYTES(arena) 返回多数据包内存缓冲区剩余空间大小(字节数)

LIBNET_print_ETH_ADDR(e) 输出显示ether_addr结构中的以太网地址

==================================================================================

---[[ libnet应用实例 ]]----------------------------------

利用libnet函数库开发应用程序的基本步骤非常简单:

1、数据包内存初始化;

2、网络接口初始化;

3、构造所需数据包;

4、计算数据包检验和;

5、发送数据包;

6、关闭网络接口;

7、释放数据包内存。

以下是四个使用了libnet接口函数编写的数据包发送程序。在编译前必须确保libnet库已成功安装。

例一:

[cpp] view plain copy

  1. /*example1[rawsocketapi-TCPpacket]*/
  2. /*gcc-Wall`libnet-config--defines`libnet-example-x.c-olibnet-example-x\
  3. `libnet-config--libs`*/
  4. #include<libnet.h>
  5. voidusage(char*);
  6. intmain(intargc,char**argv)
  7. {
  8. intnetwork,/*ournetworkinterface*/
  9. packet_size,/*packetsize*/
  10. c;/*misc*/
  11. u_longsrc_ip,dst_ip;/*ipaddresses*/
  12. u_shortsrc_prt,dst_prt;/*ports*/
  13. u_char*cp,*packet;/*misc/packet*/
  14. printf("libnetexamplecode:\tmodule1\n\n");
  15. printf("packetinjectioninterface:\trawsocket\n");
  16. printf("packettype:\t\t\tTCP[nopayload]\n");
  17. src_ip=0;
  18. dst_ip=0;
  19. src_prt=0;
  20. dst_prt=0;
  21. while((c=getopt(argc,argv,"d:s:"))!=EOF)
  22. {
  23. switch(c)
  24. {
  25. /*
  26. *Weexpecttheinputtobeoftheform`ip.ip.ip.ip.port`.We
  27. *pointcptothelastdotoftheIPaddress/portstringand
  28. *thenseperatethemwithaNULLbyte.Theoptargnowpointsto
  29. *justtheIPaddress,andcppointstotheport.
  30. */
  31. case'd':
  32. if(!(cp=strrchr(optarg,'.')))
  33. {
  34. usage(argv[0]);
  35. }
  36. *cp++=0;
  37. dst_prt=(u_short)atoi(cp);
  38. if(!(dst_ip=libnet_name_resolve(optarg,LIBNET_RESOLVE)))
  39. {
  40. libnet_error(LIBNET_ERR_FATAL,
  41. "BaddestinationIPaddress:%s\n",optarg);
  42. }
  43. break;
  44. case's':
  45. if(!(cp=strrchr(optarg,'.')))
  46. {
  47. usage(argv[0]);
  48. }
  49. *cp++=0;
  50. src_prt=(u_short)atoi(cp);
  51. if(!(src_ip=libnet_name_resolve(optarg,LIBNET_RESOLVE)))
  52. {
  53. libnet_error(LIBNET_ERR_FATAL,
  54. "BadsourceIPaddress:%s\n",optarg);
  55. }
  56. break;
  57. }
  58. }
  59. if(!src_ip||!src_prt||!dst_ip||!dst_prt)
  60. {
  61. usage(argv[0]);
  62. exit(EXIT_FAILURE);
  63. }
  64. /*
  65. *We'rejustgoingtobuildaTCPpacketwithnopayloadusingthe
  66. *rawsocketsAPI,soweonlyneedmemoryforaTCPheaderandanIP
  67. *header.
  68. */
  69. packet_size=LIBNET_IP_H+LIBNET_TCP_H;
  70. /*
  71. *step1:Memoryinitialization(interchangablewithstep2).
  72. */
  73. libnet_init_packet(packet_size,&packet);
  74. if(packet==NULL)
  75. {
  76. libnet_error(LIBNET_ERR_FATAL,"libnet_init_packetfailed\n");
  77. }
  78. /*
  79. *Step2:Networkinitialization(interchangablewithstep1).
  80. */
  81. network=libnet_open_raw_sock(IPPROTO_RAW);
  82. if(network==-1)
  83. {
  84. libnet_error(LIBNET_ERR_FATAL,"Can'topennetwork.\n");
  85. }
  86. /*
  87. *Step3:Packetconstruction(IPheader).
  88. */
  89. libnet_build_ip(LIBNET_TCP_H,/*sizeofthepacketsansIPheader*/
  90. IPTOS_LOWDELAY,/*IPtos*/
  91. 242,/*IPID*/
  92. 0,/*fragstuff*/
  93. 48,/*TTL*/
  94. IPPROTO_TCP,/*transportprotocol*/
  95. src_ip,/*sourceIP*/
  96. dst_ip,/*destinationIP*/
  97. NULL,/*payload(none)*/
  98. 0,/*payloadlength*/
  99. packet);/*packetheadermemory*/
  100. /*
  101. *Step3:Packetconstruction(TCPheader).
  102. */
  103. libnet_build_tcp(src_prt,/*sourceTCPport*/
  104. dst_prt,/*destinationTCPport*/
  105. 0xa1d95,/*sequencenumber*/
  106. 0x53,/*acknowledgementnumber*/
  107. TH_SYN,/*controlflags*/
  108. 1024,/*windowsize*/
  109. 0,/*urgentpointer*/
  110. NULL,/*payload(none)*/
  111. 0,/*payloadlength*/
  112. packet+LIBNET_IP_H);/*packetheadermemory*/
  113. /*
  114. *Step4:Packetchecksums(TCPheaderonly).
  115. */
  116. if(libnet_do_checksum(packet,IPPROTO_TCP,LIBNET_TCP_H)==-1)
  117. {
  118. libnet_error(LIBNET_ERR_FATAL,"libnet_do_checksumfailed\n");
  119. }
  120. /*
  121. *Step5:Packetinjection.
  122. */
  123. c=libnet_write_ip(network,packet,packet_size);
  124. if(c<packet_size)
  125. {
  126. libnet_error(LN_ERR_WARNING,
  127. "libnet_write_iponlywrote%dbytes\n",c);
  128. }
  129. else
  130. {
  131. printf("constructionandinjectioncompleted,wroteall%dbytes\n",c);
  132. }
  133. /*
  134. *Shutdowntheinterface.
  135. */
  136. if(libnet_close_raw_sock(network)==-1)
  137. {
  138. libnet_error(LN_ERR_WARNING,
  139. "libnet_close_raw_sockcouldn'tclosetheinterface");
  140. }
  141. /*
  142. *Freepacketmemory.
  143. */
  144. libnet_destroy_packet(&packet);
  145. return(c==-1?EXIT_FAILURE:EXIT_SUCCESS);
  146. }
  147. voidusage(char*name)
  148. {
  149. fprintf(stderr,"usage:%s-ss_ip.s_port-dd_ip.d_port\n",name);
  150. }

例二:

[cpp] view plain copy

  1. /*Example2[linklayerapi-ICMP_MASK]*/
  2. /*gcc-Wall`libnet-config--defines`libnet-example-x.c-olibnet-example-x`libnet-config--libs`*/
  3. #include<libnet.h>
  4. voidusage(char*);
  5. u_charenet_src[6]={0x0d,0x0e,0x0a,0x0d,0x00,0x00};
  6. u_charenet_dst[6]={0xff,0xff,0xff,0xff,0xff,0xff};
  7. int
  8. main(intargc,char*argv[])
  9. {
  10. intpacket_size,/*sizeofourpacket*/
  11. c;/*misc*/
  12. u_longsrc_ip,dst_ip;/*sourceip,destip*/
  13. u_char*packet;/*pointertoourpacketbuffer*/
  14. charerr_buf[LIBNET_ERRBUF_SIZE];/*errorbuffer*/
  15. u_char*device;/*pointertothedevicetouse*/
  16. structlibnet_link_int*network;/*pointertolinkinterfacestruct*/
  17. printf("libnetexamplecode:\tmodule2\n\n");
  18. printf("packetinjectioninterface:\tlinklayer\n");
  19. printf("packettype:\t\t\tICMPnetmask[nopayload]\n");
  20. device=NULL;
  21. src_ip=0;
  22. dst_ip=0;
  23. while((c=getopt(argc,argv,"i:d:s:"))!=EOF)
  24. {
  25. switch(c)
  26. {
  27. case'd':
  28. if(!(dst_ip=libnet_name_resolve(optarg,LIBNET_RESOLVE)))
  29. {
  30. libnet_error(LIBNET_ERR_FATAL,
  31. "BaddestinationIPaddress:%s\n",optarg);
  32. }
  33. break;
  34. case'i':
  35. device=optarg;
  36. break;
  37. case's':
  38. if(!(src_ip=libnet_name_resolve(optarg,LIBNET_RESOLVE)))
  39. {
  40. libnet_error(LIBNET_ERR_FATAL,
  41. "BadsourceIPaddress:%s\n",optarg);
  42. }
  43. break;
  44. default:
  45. exit(EXIT_FAILURE);
  46. }
  47. }
  48. if(!src_ip||!dst_ip)
  49. {
  50. usage(argv[0]);
  51. exit(EXIT_FAILURE);
  52. }
  53. /*
  54. *Step1:NetworkInitialization(interchangablewithstep2).
  55. */
  56. if(device==NULL)
  57. {
  58. structsockaddr_insin;
  59. /*
  60. *Trytolocateadevice.
  61. */
  62. if(libnet_select_device(&sin,&device,err_buf)==-1)
  63. {
  64. libnet_error(LIBNET_ERR_FATAL,
  65. "libnet_select_devicefailed:%s\n",err_buf);
  66. }
  67. printf("device:\t\t\t\t%s\n",device);
  68. }
  69. if((network=libnet_open_link_interface(device,err_buf))==NULL)
  70. {
  71. libnet_error(LIBNET_ERR_FATAL,
  72. "libnet_open_link_interface:%s\n",err_buf);
  73. }
  74. /*
  75. *We'regoingtobuildanICMPpacketwithnopayloadusingthe
  76. *link-layerAPI,sothistimeweneedmemoryforaethernetheader
  77. *aswellasmemoryfortheICMPandIPheaders.
  78. */
  79. packet_size=LIBNET_IP_H+LIBNET_ETH_H+LIBNET_ICMP_MASK_H;
  80. /*
  81. *Step2:MemoryInitialization(interchangablewithstep1).
  82. */
  83. if(libnet_init_packet(packet_size,&packet)==-1)
  84. {
  85. libnet_error(LIBNET_ERR_FATAL,"libnet_init_packetfailed\n");
  86. }
  87. /*
  88. *Step3:Packetconstruction(ethernetheader).
  89. */
  90. libnet_build_ethernet(enet_dst,
  91. enet_src,
  92. ETHERTYPE_IP,
  93. NULL,
  94. 0,
  95. packet);
  96. /*
  97. *Step3:Packetconstruction(ICMPheader).
  98. */
  99. libnet_build_icmp_mask(ICMP_MASKREPLY,/*type*/
  100. 0,/*code*/
  101. 242,/*id*/
  102. 0,/*seq*/
  103. 0xffffffff,/*mask*/
  104. NULL,/*payload*/
  105. 0,/*payload_s*/
  106. packet+LIBNET_ETH_H+LIBNET_IP_H);
  107. /*
  108. *Step3:Packetconstruction(IPheader).
  109. */
  110. libnet_build_ip(ICMP_MASK_H,
  111. 0,/*IPtos*/
  112. 242,/*IPID*/
  113. 0,/*Frag*/
  114. 64,/*TTL*/
  115. IPPROTO_ICMP,/*Transportprotocol*/
  116. src_ip,/*SourceIP*/
  117. dst_ip,/*DestinationIP*/
  118. NULL,/*Pointertopayload(none)*/
  119. 0,
  120. packet+LIBNET_ETH_H);/*Packetheadermemory*/
  121. /*
  122. *Step4:Packetchecksums(ICMPheader*AND*IPheader).
  123. */
  124. if(libnet_do_checksum(packet+ETH_H,IPPROTO_ICMP,LIBNET_ICMP_MASK_H)==-1)
  125. {
  126. libnet_error(LIBNET_ERR_FATAL,"libnet_do_checksumfailed\n");
  127. }
  128. if(libnet_do_checksum(packet+ETH_H,IPPROTO_IP,LIBNET_IP_H)==-1)
  129. {
  130. libnet_error(LIBNET_ERR_FATAL,"libnet_do_checksumfailed\n");
  131. }
  132. /*
  133. *Step5:Packetinjection.
  134. */
  135. c=libnet_write_link_layer(network,device,packet,packet_size);
  136. if(c<packet_size)
  137. {
  138. libnet_error(LN_ERR_WARNING,
  139. "libnet_write_link_layeronlywrote%dbytes\n",c);
  140. }
  141. else
  142. {
  143. printf("constructionandinjectioncompleted,wroteall%dbytes\n",c);
  144. }
  145. /*
  146. *Shutdowntheinterface.
  147. */
  148. if(libnet_close_link_interface(network)==-1)
  149. {
  150. libnet_error(LN_ERR_WARNING,
  151. "libnet_close_link_interfacecouldn'tclosetheinterface");
  152. }
  153. /*
  154. *Freepacketmemory.
  155. */
  156. libnet_destroy_packet(&packet);
  157. return(c==-1?EXIT_FAILURE:EXIT_SUCCESS);
  158. }
  159. voidusage(char*name)
  160. {
  161. fprintf(stderr,"usage:%s[-iinterface]-ss_ip-dd_ip\n",name);
  162. }

例三:

[cpp] view plain copy

  1. /*Example3[rawsocketapi-ICMP_ECHOusinganarena]*/
  2. /*gcc-Wall`libnet-config--defines`libnet-example-x.c-olibnet-example-x\
  3. `libnet-config--libs`*/
  4. #include<libnet.h>
  5. voidusage(char*);
  6. intmain(intargc,char**argv)
  7. {
  8. intnetwork,n,c,number_of_packets,packet_size;
  9. structlibnet_arenaarena,*arena_p;
  10. u_char*packets[10];
  11. u_longsrc_ip,dst_ip;
  12. printf("libnetexamplecode:\tmodule3\n\n");
  13. printf("packetinjectioninterface:\tlinklayer\n");
  14. printf("packettype:\t\t\tICMP_ECHO[nopayload]usinganarena\n");
  15. src_ip=0;
  16. dst_ip=0;
  17. while((c=getopt(argc,argv,"d:s:"))!=EOF)
  18. {
  19. switch(c)
  20. {
  21. case'd':
  22. if(!(dst_ip=libnet_name_resolve(optarg,LIBNET_RESOLVE)))
  23. {
  24. libnet_error(LIBNET_ERR_FATAL,
  25. "BaddestinationIPaddress:%s\n",optarg);
  26. }
  27. break;
  28. case's':
  29. if(!(src_ip=libnet_name_resolve(optarg,LIBNET_RESOLVE)))
  30. {
  31. libnet_error(LIBNET_ERR_FATAL,
  32. "BadsourceIPaddress:%s\n",optarg);
  33. }
  34. break;
  35. }
  36. }
  37. if(!src_ip||!dst_ip)
  38. {
  39. usage(argv[0]);
  40. exit(EXIT_FAILURE);
  41. }
  42. /*
  43. *We'rejustgoingtobuildanICMPpacketwithnopayloadusingthe
  44. *rawsocketsAPI,soweonlyneedmemoryforaICMPheaderandanIP
  45. *header.
  46. */
  47. packet_size=LIBNET_IP_H+LIBNET_ICMP_ECHO_H;
  48. /*
  49. *Let'sjustbuildsay,10packets.
  50. */
  51. number_of_packets=10;
  52. arena_p=&arena;
  53. if(libnet_init_packet_arena(&arena_p,number_of_packets,packet_size)==-1)
  54. {
  55. libnet_error(LIBNET_ERR_FATAL,"libnet_init_packet_arenafailed\n");
  56. }
  57. else
  58. {
  59. printf("Allocatedanarenaof%ldbytes..\n",
  60. LIBNET_GET_ARENA_SIZE(arena));
  61. }
  62. network=libnet_open_raw_sock(IPPROTO_RAW);
  63. if(network==-1)
  64. {
  65. libnet_error(LIBNET_ERR_FATAL,"Can'topenthenetwork.\n");
  66. }
  67. for(n=0;n<number_of_packets;n++)
  68. {
  69. printf("%ldbytesremaininginarena\n",
  70. LIBNET_GET_ARENA_REMAINING_BYTES(arena));
  71. packets[n]=libnet_next_packet_from_arena(&arena_p,packet_size);
  72. if(!packets[n])
  73. {
  74. libnet_error(LIBNET_ERR_WARNING,"Arenaisempty\n");
  75. continue;
  76. }
  77. libnet_build_ip(ICMP_ECHO_H,/*Sizeofthepayload*/
  78. IPTOS_LOWDELAY|IPTOS_THROUGHPUT,/*IPtos*/
  79. 242,/*IPID*/
  80. 0,/*fragstuff*/
  81. 48,/*TTL*/
  82. IPPROTO_ICMP,/*transportprotocol*/
  83. src_ip,/*sourceIP*/
  84. dst_ip,/*destinationIP*/
  85. NULL,/*pointertopayload*/
  86. 0,/*payloadlength*/
  87. packets[n]);/*packetheadermemory*/
  88. libnet_build_icmp_echo(ICMP_ECHO,/*type*/
  89. 0,/*code*/
  90. 242,/*id*/
  91. 5,/*seq*/
  92. NULL,/*pointertopayload*/
  93. 0,/*payloadlength*/
  94. packets[n]+LIBNET_IP_H);/*packetheadermemory*/
  95. if(libnet_do_checksum(packets[n],IPPROTO_ICMP,LIBNET_ICMP_ECHO_H)==-1)
  96. {
  97. libnet_error(LIBNET_ERR_FATAL,"libnet_do_checksumfailed\n");
  98. }
  99. c=libnet_write_ip(network,packets[n],packet_size);
  100. if(c<packet_size)
  101. {
  102. libnet_error(LN_ERR_WARNING,
  103. "libnet_write_iponlywrote%dbytes\n",c);
  104. }
  105. else
  106. {
  107. printf("constructionandinjectionofpacket%dof%dcompleted,wroteall%dbytes\n",
  108. n+1,number_of_packets,c);
  109. }
  110. }
  111. libnet_destroy_packet_arena(&arena_p);
  112. return(c==-1?EXIT_FAILURE:EXIT_SUCCESS);
  113. }
  114. voidusage(char*name)
  115. {
  116. fprintf(stderr,"usage:%s-ssource_ip-ddestination_ip\n",name);
  117. }

例四:

[cpp] view plain copy

  1. /*Example4[link-layerapi-UDPpacketusingportlistchaining]*/
  2. /*gcc-Wall`libnet-config--defines`libnet-example-x.c-olibnet-example-x\
  3. `libnet-config--libs`*/
  4. #include<libnet.h>
  5. #defineMAX_PAYLOAD_SIZE1024
  6. voidusage(char*);
  7. u_charenet_src[6]={0x0d,0x0e,0x0a,0x0d,0x00,0x00};
  8. u_charenet_dst[6]={0xff,0xff,0xff,0xff,0xff,0xff};
  9. intmain(intargc,char*argv[])
  10. {
  11. intpacket_size,/*sizeofourpacket*/
  12. payload_size,/*sizeofourpacket*/
  13. c;/*misc*/
  14. u_longsrc_ip,dst_ip;/*sourceip,destip*/
  15. u_shortbport,eport;/*beginningandendports*/
  16. u_shortcport;/*currentport*/
  17. u_charpayload[MAX_PAYLOAD_SIZE];/*packetpayload*/
  18. u_char*packet;/*pointertoourpacketbuffer*/
  19. charerr_buf[LIBNET_ERRBUF_SIZE];/*errorbuffer*/
  20. u_char*device;/*pointertothedevicetouse*/
  21. structlibnet_link_int*network;/*pointertolinkinterfacestruct*/
  22. structlibnet_plist_chainplist;/*plistchain*/
  23. structlibnet_plist_chain*plist_p;/*plistchainpointer*/
  24. printf("libnetexamplecode:\tmodule4\n\n");
  25. printf("packetinjectioninterface:\tlinklayer\n");
  26. printf("packettype:\t\t\tUDP[withpayload]usingportlistchaining\n");
  27. plist_p=NULL;
  28. device=NULL;
  29. src_ip=0;
  30. dst_ip=0;
  31. while((c=getopt(argc,argv,"i:d:s:p:"))!=EOF)
  32. {
  33. switch(c)
  34. {
  35. case'd':
  36. if(!(dst_ip=libnet_name_resolve(optarg,LIBNET_RESOLVE)))
  37. {
  38. libnet_error(LIBNET_ERR_FATAL,
  39. "BaddestinationIPaddress:%s\n",optarg);
  40. }
  41. break;
  42. case'i':
  43. device=optarg;
  44. break;
  45. case's':
  46. if(!(src_ip=libnet_name_resolve(optarg,LIBNET_RESOLVE)))
  47. {
  48. libnet_error(LIBNET_ERR_FATAL,
  49. "BadsourceIPaddress:%s\n",optarg);
  50. }
  51. break;
  52. case'p':
  53. plist_p=&plist;
  54. if(libnet_plist_chain_new(&plist_p,optarg)==-1)
  55. {
  56. libnet_error(LIBNET_ERR_FATAL,
  57. "Couldnotbuildportlist\n");
  58. }
  59. break;
  60. default:
  61. usage(argv[0]);
  62. exit(EXIT_FAILURE);
  63. }
  64. }
  65. if(!src_ip||!dst_ip||!plist_p)
  66. {
  67. usage(argv[0]);
  68. exit(EXIT_FAILURE);
  69. }
  70. c=argc-optind;
  71. if(c!=1)
  72. {
  73. usage(argv[0]);
  74. exit(EXIT_FAILURE);
  75. }
  76. memset(payload,0,sizeof(payload));
  77. strncpy(payload,argv[optind],strlen(argv[optind]));
  78. /*
  79. *Step1:NetworkInitialization(interchangablewithstep2).
  80. */
  81. if(device==NULL)
  82. {
  83. structsockaddr_insin;
  84. /*
  85. *Trytolocateadevice.
  86. */
  87. if(libnet_select_device(&sin,&device,err_buf)==-1)
  88. {
  89. libnet_error(LIBNET_ERR_FATAL,
  90. "libnet_select_devicefailed:%s\n",err_buf);
  91. }
  92. printf("device:\t\t\t\t%s\n",device);
  93. }
  94. if((network=libnet_open_link_interface(device,err_buf))==NULL)
  95. {
  96. libnet_error(LIBNET_ERR_FATAL,
  97. "libnet_open_link_interface:%s\n",err_buf);
  98. }
  99. /*
  100. *Getthepayloadfromtheuser.Hrm.ThismightfailonaSparc
  101. *ifbytealignmentisoff...
  102. */
  103. payload_size=strlen(payload);
  104. /*
  105. *We'regoingtobuildaUDPpacketwithapayloadusingthe
  106. *link-layerAPI,sothistimeweneedmemoryforaethernetheader
  107. *aswellasmemoryfortheICMPandIPheadersandourpayload.
  108. */
  109. packet_size=LIBNET_IP_H+LIBNET_ETH_H+LIBNET_UDP_H+payload_size;
  110. /*
  111. *Step2:MemoryInitialization(interchangablewithstep1).
  112. */
  113. if(libnet_init_packet(packet_size,&packet)==-1)
  114. {
  115. libnet_error(LIBNET_ERR_FATAL,"libnet_init_packetfailed\n");
  116. }
  117. /*
  118. *Step3:Packetconstruction(ethernetheader).
  119. */
  120. libnet_build_ethernet(enet_dst,
  121. enet_src,
  122. ETHERTYPE_IP,
  123. NULL,
  124. 0,
  125. packet);
  126. /*
  127. *Step3:Packetconstruction(IPheader).
  128. */
  129. libnet_build_ip(LIBNET_UDP_H+payload_size,
  130. 0,/*IPtos*/
  131. 242,/*IPID*/
  132. 0,/*Frag*/
  133. 64,/*TTL*/
  134. IPPROTO_UDP,/*Transportprotocol*/
  135. src_ip,/*SourceIP*/
  136. dst_ip,/*DestinationIP*/
  137. NULL,/*Pointertopayload(none)*/
  138. 0,
  139. packet+LIBNET_ETH_H);/*Packetheadermemory*/
  140. while(libnet_plist_chain_next_pair(plist_p,&bport,&eport))
  141. {
  142. while(!(bport>eport)&&bport!=0)
  143. {
  144. cport=bport++;
  145. /*
  146. *Step3:Packetconstruction(UDPheader).
  147. */
  148. libnet_build_udp(242,/*sourceport*/
  149. cport,/*dest.port*/
  150. payload,/*payload*/
  151. payload_size,/*payloadlength*/
  152. packet+LIBNET_ETH_H+LIBNET_IP_H);
  153. /*
  154. *Step4:Packetchecksums(ICMPheader*AND*IPheader).
  155. */
  156. if(libnet_do_checksum(packet+ETH_H,IPPROTO_UDP,LIBNET_UDP_H+payload_size)==-1)
  157. {
  158. libnet_error(LIBNET_ERR_FATAL,"libnet_do_checksumfailed\n");
  159. }
  160. if(libnet_do_checksum(packet+ETH_H,IPPROTO_IP,LIBNET_IP_H)==-1)
  161. {
  162. libnet_error(LIBNET_ERR_FATAL,"libnet_do_checksumfailed\n");
  163. }
  164. /*
  165. *Step5:Packetinjection.
  166. */
  167. c=libnet_write_link_layer(network,device,packet,packet_size);
  168. if(c<packet_size)
  169. {
  170. libnet_error(LN_ERR_WARNING,
  171. "libnet_write_link_layeronlywrote%dbytes\n",c);
  172. }
  173. else
  174. {
  175. printf("constructionandinjectioncompleted,wroteall%dbytes,port%d\n",
  176. c,cport);
  177. }
  178. }
  179. }
  180. /*
  181. *Shutdowntheinterface.
  182. */
  183. if(libnet_close_link_interface(network)==-1)
  184. {
  185. libnet_error(LN_ERR_WARNING,
  186. "libnet_close_link_interfacecouldn'tclosetheinterface");
  187. }
  188. /*
  189. *Freepacketmemory.
  190. */
  191. libnet_destroy_packet(&packet);
  192. return(c==-1?EXIT_FAILURE:EXIT_SUCCESS);
  193. }
  194. voidusage(char*name)
  195. {
  196. fprintf(stderr,"usage:%s[-iinterface]-ss_ip-dd_ip-pportlistpayload\n",name);
  197. }

例五:

[cpp] view plain copy

  1. 给出一个综合应用libnet和libpcap的简单例程,其功能是在接收到一个来自特定主机的ARP请求报文之后,发出ARP回应报文,通知该主机请求的IP地址对应的MAC地址。这个程序实现了标准的ARP协议,但是却不同于操作系统内核中标准的实现方法:该程序利用了libpcap在数据链路层抓包,利用了libnet向数据链路层发包,是使用libnet和libpcap构造TCP/IP协议软件的一个例程。该程序很简单,但已经可以说明libnet和libpcap的综合使用方法:
  2. /*telldestinationhostwithip'dstip'thatthehostwith
  3. *requestip'srcip'iswithmacaddresssrcmac
  4. *author:whitecpf2003.5.15.
  5. *compile:gccarp.c-lnet-lpcap-oarp
  6. */
  7. #include"/usr/include/libnet.h"
  8. #include<pcap.h>
  9. voidusage(char*exename){
  10. printf("telldstipwithdstmacthatsrcipisatsrcmac.\n");
  11. printf("usage:%s-ddstip-ssrcip-Ddstmac-Ssrcmac\n",exename);
  12. return;
  13. }
  14. //程序输入:来自命令行参数
  15. u_charip_src[4],ip_dst[4];
  16. u_charenet_src[6],enet_dst[6];
  17. externintmac_strtochar6(u_char*enet,char*macstr);
  18. //将字符串格式的MAC地址转换为6字节类型r
  19. intget_cmdline(intargc,char*argv[]);//命令行参数处理函数
  20. intmain(intargc,char*argv[]){
  21. libnet_t*l;
  22. libnet_ptag_tt;
  23. u_char*packet;
  24. u_longpacket_s;
  25. chardevice[5]="eth0";
  26. charerrbuf[LIBNET_ERRBUF_SIZE];
  27. charfilter_str[100]="";
  28. structbpf_programfp;/*holdcompiledprogram*/
  29. char*dev;
  30. pcap_t*descr;
  31. structpcap_pkthdrhdr;/*pcap.h*/
  32. u_char*packet;
  33. bpf_u_int32maskp;/*subnetmask*/
  34. bpf_u_int32netp;/*ip*/
  35. intpromisc=0;/*settopromiscmode?*/
  36. intpcap_time_out=5;
  37. intc,ret;
  38. u_longi;
  39. if(get_cmdline(argc,argv)<=0){
  40. usage(argv[0]);
  41. exit(0);
  42. }
  43. dev=pcap_lookupdev(errbuf);
  44. if(dev==NULL){
  45. fprintf(stderr,"%s\n",errbuf);
  46. return-1;
  47. }
  48. ret=pcap_lookupnet(dev,&netp,&maskp,errbuf);
  49. if(ret==-1){
  50. fprintf(stderr,"%s\n",errbuf);
  51. return-1;
  52. }
  53. descr=pcap_open_live(dev,BUFSIZ,promisc,pcap_time_out,errbuf);
  54. if(descr==NULL){
  55. printf("pcap_open_live():%s\n",errbuf);
  56. return-1;
  57. }
  58. sprintf(filter_str,"arpand(srcnet%d.%d.%d.%d)",ip_dst[0],ip_dst[1],
  59. ip_dst[2],ip_dst[3]);
  60. if(pcap_compile(descr,&fp,filter_str,0,netp)==-1){
  61. printf("Errorcallingpcap_compile\n");
  62. return-1;
  63. }
  64. if(pcap_setfilter(descr,&fp)==-1){
  65. printf("Errorsettingfilter\n");
  66. return-1;
  67. }
  68. while(1){
  69. printf("waitpacket:filter:%s\n",filter_str);
  70. packet=pcap_next(descr,&hdr);
  71. if(packet==NULL){
  72. continue;
  73. }
  74. l=libnet_init(LIBNET_LINK_ADV,device,errbuf);
  75. if(l==NULL){
  76. fprintf(stderr,"libnet_init()failed:%s",errbuf);
  77. exit(EXIT_FAILURE);
  78. }
  79. t=libnet_build_arp(
  80. ARPHRD_ETHER,/*hardwareaddr*/
  81. ETHERTYPE_IP,/*protocoladdr*/
  82. 6,/*hardwareaddrsize*/
  83. 4,/*protocoladdrsize*/
  84. ARPOP_REPLY,/*operationtype*/
  85. enet_src,/*senderhardwareaddr*/
  86. ip_src,/*senderprotocoladdr*/
  87. enet_dst,/*targethardwareaddr*/
  88. ip_dst,/*targetprotocoladdr*/
  89. NULL,/*payload*/
  90. 0,/*payloadsize*/
  91. l,/*libnethandle*/
  92. 0);/*libnetid*/
  93. if(t==-1){
  94. fprintf(stderr,"Can'tbuildARPheader:%s\n",libnet_geterror(l));
  95. gotobad;
  96. }
  97. t=libnet_autobuild_ethernet(
  98. enet_dst,/*ethernetdestination*/
  99. ETHERTYPE_ARP,/*protocoltype*/
  100. l);/*libnethandle*/
  101. if(t==-1){
  102. fprintf(stderr,"Can'tbuildethernetheader:%s\n",libnet_geterror(l));
  103. gotobad;
  104. }
  105. c=libnet_adv_cull_packet(l,&packet,&packet_s);
  106. if(c==-1){
  107. fprintf(stderr,"libnet_adv_cull_packet:%s\n",libnet_geterror(l));
  108. gotobad;
  109. }
  110. c=libnet_write(l);
  111. if(c==-1){
  112. fprintf(stderr,"Writeerror:%s\n",libnet_geterror(l));
  113. gotobad;
  114. }
  115. continue;
  116. bad:
  117. libnet_destroy(l);
  118. return(EXIT_FAILURE);
  119. }
  120. libnet_destroy(l);
  121. return(EXIT_FAILURE);
  122. }
  123. intget_cmdline(intargc,char*argv[]){
  124. charc;
  125. charstring[]="d:s:D:S:h";
  126. while((c=getopt(argc,argv,string))!=EOF){
  127. if(c=='d')
  128. *((unsignedint*)ip_dst)=(unsignedint)inet_addr(optarg);
  129. elseif(c=='s')
  130. *((unsignedint*)ip_src)=(unsignedint)inet_addr(optarg);
  131. elseif(c=='D')
  132. mac_strtochar6(enet_dst,optarg);
  133. elseif(c=='S')
  134. mac_strtochar6(enet_dst,optarg);
  135. elseif(c=='h')
  136. return0;
  137. else
  138. return-1;
  139. }
  140. return1;
  141. }

例六:

[cpp] view plain copy

  1. #include<win32/libnet.h>
  2. #pragmacomment(lib,"libnet.lib")
  3. voidmain()
  4. {
  5. intpacket_size;//存放数据包长度的变量
  6. libnet_t*l;//libnet句柄
  7. libnet_ptag_tprotocol_tag;//协议块标记
  8. char*device=NULL;//设备名字,此时为NULL
  9. charerror_information[LIBNET_ERRBUF_SIZE];//用来存放错误信息
  10. char*destination_ip_str="192.168.0.2";//目的IP地址字符串变量,可以指定任意一个合法的IP地址
  11. char*source_ip_str="192.168.0.3";//源IP地址字符串变量,可以指定任意一个合法的IP地址
  12. u_charhardware_source[6]={0x01,0x02,0x03,0x04,0x05,0x06};//源MAC地址,可以是任意指定
  13. u_charhardware_destination[6]={0x06,0x05,0x04,0x03,0x02,0x01};//目的MAC地址,可以是任意指定
  14. u_longdestination_ip;//目的IP地址
  15. u_longsource_ip;//源IP地址
  16. l=libnet_init(
  17. LIBNET_LINK_ADV,//libnet类型*/
  18. device,//网络设备
  19. error_information);
  20. destination_ip=libnet_name2addr4(l,destination_ip_str,LIBNET_RESOLVE);
  21. //把目的IP地址字符串形式转化成网络顺序字节形式的数据
  22. source_ip=libnet_name2addr4(l,source_ip_str,LIBNET_RESOLVE);
  23. //把源IP地址字符串形式转化成网络顺序字节形式的数据
  24. protocol_tag=libnet_build_arp(
  25. //构造ARP协议块,函数的返回值是代表新生成的ARP协议块的一个协议块标记
  26. ARPHRD_ETHER,
  27. //硬件地址类型,在这里是以太网
  28. ETHERTYPE_IP,
  29. //协议地址类型,在这里是IP协议
  30. 6,
  31. //硬件地址长度,MAC地址的长度为6
  32. 4,
  33. //协议地址长度,IP地址的长度为4
  34. ARPOP_REPLY,
  35. //操作类型,在这里是ARP应答类型
  36. hardware_source,
  37. //源硬件地址
  38. (u_int8_t*)&source_ip,
  39. //源IP地址
  40. hardware_destination,
  41. //目标硬件地址
  42. (u_int8_t*)&destination_ip,
  43. //目标协议地址
  44. NULL,
  45. //负载,此时为NULL
  46. 0,
  47. //负载的长度,此时为0
  48. l,
  49. //libnet句柄,此句柄由libnet_init()函数生成
  50. 0
  51. //协议块标记,此时为0,表示构造一个新的ARP协议块,而不是修改已经存在的协议块
  52. );
  53. protocol_tag=libnet_autobuild_ethernet(
  54. //以auto的形式构造一个以太网协议块,返回一个指向此协议块的标记
  55. hardware_destination,
  56. //目的硬件地址
  57. ETHERTYPE_ARP,
  58. //以太网上层协议类型,此时为ARP类型
  59. l//libnet句柄
  60. );
  61. packet_size=libnet_write(l);//发送已经构造的ARP数据包
  62. printf("发送一个%d字节长度的ARP应答数据包",packet_size);//输出发送的ARP数据包的字节数
  63. libnet_destroy(l);//销毁libnet
  64. }

相关阅读

分享到:

栏目导航

推荐阅读

热门阅读