libnet使用举例(12) 作者:小四 < mailto: scz@nsfocus.com > 主页:http://www.nsfocus.com 日期:2000-12-14 本系列1-11都是raw socket layer programming,今天介绍link layer programming, 下面是链路层编程用到的部分关键函数: int libnet_build_ethernet ( u_char * daddr, u_char * saddr, u_short id, const u_char * payload, int payload_s, u_char * buf ); 该函数用于构造以太网物理帧,daddr、saddr分别指向一个6字节数组,对应物理帧 的目标MAC、源MAC。id指定物理帧类型,有效值如下: 值 代表的类型 ETHERTYPE_PUP PUP protocol ETHERTYPE_IP IP protocol ETHERTYPE_ARP ARP protocol ETHERTYPE_REVARP Reverse ARP protocol ETHERTYPE_VLAN IEEE VLAN tagging ETHERTYPE_LOOPBACK Used to test intefaces payload为NULL,payload_s为零。最后一个参数buf,指向通过libnet_init_packet 分配并初始化过的数据区,此时buf指向的实际是物理帧头。 必须意识到,某些链路层接口(比如BPF)不允许伪装物理帧源MAC,除非你自己更改内 核。 int libnet_build_arp ( u_short hrd, u_short pro, u_short hln, u_short pln, u_short op, u_char * sha, u_char * spa, u_char * tha, u_char * tpa, const u_char * payload, int payload_s, u_char * buf ); 该函数用于构造ARP报文。对于常见应用来说,hrd为ARPHRD_ETHER,pro为 ETHERTYPE_IP,hln为ETHER_ADDR_LEN(就是6,MAC地址长度),pln为4(IPv4地址长度), op指定ARP操作类型,有效取值有ARPOP_REQUEST、ARPOP_REPLY、ARPOP_REVREQUEST、 ARPOP_REVREPLY、ARPOP_INVREQUEST 以及 ARPOP_INVREPLY,我不知道最后两种类型 是什么意思,这里op以主机字节序提供,比如0x0002就是ARPOP_REPLY。sha指定发送 方MAC地址,spa指定发送方IP地址,tha指定接收方MAC地址,tpa指定接收方IP地址, payload为NULL,payload_s为零。形参buf需要指向一个已分配好的数据区,ARP层从 该指针开始。 struct libnet_link_int * libnet_open_link_interface ( char * device, char * ebuf ); int libnet_close_link_interface ( struct libnet_link_int * l ); 如果需要直接发送链路层物理帧,必须事先使用libnet_open_link_interface()打开 接口设备。device指定接口设备名,对于Linux就是"eth0"一类的名字。ebuf通常定 义如下: char err_buf[ LIBNET_ERRBUF_SIZE ]; /usr/include/libnet/libnet-macros.h: #define LIBNET_ERRBUF_SIZE 256 如果调用失败返回NULL,成功则填充一个libnet_link_int结构,并返回这个结构指 针。libnet_close_link_interface()与libnet_open_link_interface()对应,关闭 先前打开的接口设备,失败返回-1,成功返回1。 int libnet_select_device ( struct sockaddr_in * sin, u_char ** device, u_char * ebuf ); 如果你不能确定libnet_open_link_interface()第一形参使用什么样的接口设备名, 可以调用libnet_select_device()获取它。后者遍历接口链表,从中选择第一个可用 的非回送接口。sin、device不得为NULL,sin必须指向一个sockaddr_in结构, device必须指向一个指针,*sin、*device的初值无所谓。调用成功返回1,*device 指向一个有效接口设备名,可以用于后续的libnet_open_link_interface()调用。失 败返回-1,ebuf将包含失败原因。 struct ether_addr * libnet_get_hwaddr ( struct libnet_link_int * l, const u_char * device, const u_char * ebuf ); 第一形参来自libnet_open_link_interface(),device指向接口设备名。成功则返回 指定接口的MAC地址,失败返回0(NULL),ebuf将包含失败原因。 int libnet_write_link_layer ( struct libnet_link_int * l, const u_char * device, u_char * buf, int len ); 该函数用于直接发送链路层物理帧,第一形参来自libnet_open_link_interface(), device指向接口设备名。buf指向物理帧头,一般由libnet_init_packet分配并初始 化,libnet_destroy_packet()负责释放。len指定物理帧长度。失败返回-1,否则返 回发送出去的字节数。 写个arpsend程序来验证这些可爱的函数,recvMac必须为真实有效的MAC地址,否则 谁接收呢。sendMac根据需要可以伪装,但链路层支持为BPF时无法伪装,除非自己更 改内核。关于ARP协议本身的讨论太多,不做进一步说明。没有提供随机数支持,如 果你自己有特殊需要,可以参看本系列1-11中反复使用的技术,也可以直接使用 libnet本身提供的libnet_seed_prand()、libnet_get_prand()函数。如果有时间, 会提供另外一个程序演示这两个随机函数。 -------------------------------------------------------------------------- /* * File : arpsend program for I386/Linux using libnet * Version: 0.01 aleph * Author : scz < mailto: scz@nsfocus.com > * : http://www.nsfocus.com * Complie: gcc -O3 -o arpsend arpsend.c `libnet-config --defines --cflags` `libnet-config --libs` -Wall * Usage : ./arpsend --recv 000000111111 --si 192.168.8.90 --sm 000000222222 --num 30 * Date : 2000-12-13 16:43 */ /******************************************************************* * * * Head File * * * *******************************************************************/ #define _GNU_SOURCE #include <stdio.h> #include <stdlib.h> #include <getopt.h> /* for getopt() */ #include <libnet.h> /******************************************************************* * * * Macro * * * *******************************************************************/ #define SUCCESS 0 #define FAILURE -1 #define DEFAULTARPNUMBER 0x5 /* 缺省发送ARP报文数目 */ /******************************************************************* * * * Static Global Var * * * *******************************************************************/ static u_char * packet = NULL; static size_t packet_size = LIBNET_ETH_H + LIBNET_ARP_H; static struct libnet_link_int * link_handler = NULL; /******************************************************************* * * * Function Prototype * * * *******************************************************************/ static void Libnet_close_link_interface ( struct libnet_link_int * l ); /* static void Libnet_get_hwaddr ( struct libnet_link_int * l, const u_char * device, u_char * mac ); */ static void Libnet_init_packet ( size_t p_size, u_char ** buf ); static struct libnet_link_int * Libnet_open_link_interface ( char * device ); static void Libnet_select_device ( u_char ** device ); static void Libnet_write_link_layer ( struct libnet_link_int * l, const u_char * device, u_char * buf, int len ); static char * Strncpy ( char * dest, const char * src, size_t n ); static void usage ( char * arg ); /*----------------------------------------------------------------------*/ static void Libnet_close_link_interface ( struct libnet_link_int * l ) { if ( libnet_close_link_interface( l ) == -1 ) { libnet_error( LIBNET_ERR_WARNING, "libnet_close_link_interface failed/n" ); } return; } /* end of Libnet_close_link_interface */ /* static void Libnet_get_hwaddr ( struct libnet_link_int * l, const u_char * device, u_char * mac ) { char err_buf[ LIBNET_ERRBUF_SIZE ]; struct ether_addr * m = NULL; if ( mac == NULL ) { return; } m = libnet_get_hwaddr( l, device, err_buf ); if ( m == NULL ) { libnet_error( LIBNET_ERR_WARNING, "libnet_get_hwaddr failed: %s/n", err_buf ); } else { memmove( mac, ( u_char * )m, 6 ); } return; } */ static void Libnet_init_packet ( size_t p_size, u_char ** buf ) { if ( libnet_init_packet( p_size, buf ) == -1 ) { libnet_error( LIBNET_ERR_FATAL, "Can't initialize packet/n" ); } return; } /* end of Libnet_init_packet */ static struct libnet_link_int * Libnet_open_link_interface ( char * device ) { struct libnet_link_int * link = NULL; char err_buf[ LIBNET_ERRBUF_SIZE ]; if ( ( link = libnet_open_link_interface( device, err_buf ) ) == NULL ) { libnet_error( LIBNET_ERR_FATAL, "libnet_open_link_interface failed: %s/n", err_buf ); } return( link ); } /* end of Libnet_open_link_interface */ static void Libnet_select_device ( u_char ** device ) { struct sockaddr_in sin; char err_buf[ LIBNET_ERRBUF_SIZE ]; if ( device == NULL ) { libnet_error( LIBNET_ERR_FATAL, "Can't locate a device/n" ); } if ( libnet_select_device( &sin, device, err_buf ) == -1 ) { libnet_error( LIBNET_ERR_FATAL, "libnet_select_device failed: %s/n", err_buf ); } fprintf( stderr, "[ device --> %s ]/n", *device ); return; } /* end of Libnet_select_device */ static void Libnet_write_link_layer ( struct libnet_link_int * l, const u_char * device, u_char * buf, int len ) { int w; if ( ( w = libnet_write_link_layer( l, device, buf, len ) ) < len ) { libnet_error( LIBNET_ERR_WARNING, "libnet_write_link_layer only wrote %d bytes/n", w ); } return; } /* end of Libnet_write_link_layer */ static char * Strncpy ( char * dest, const char * src, size_t n ) { char * pChar; pChar = strncpy( dest, src, n ); if ( pChar == NULL ) { exit( FAILURE ); } else { *( pChar + n - 1 ) = '/0'; } return( pChar ); } /* end of Strncpy */ static void usage ( char * arg ) { fprintf( stderr, " Usage: %s [--send sendMac] [--recv recvMac]/n/t" "[--si srcIp] [--di dstIp] [--sm srcMac] [--dm dstMac]/n/t" "[--arpOp arpOp] [--num arpNumber]/n", arg ); exit( FAILURE ); } /* end of usage */ int main ( int argc, char * argv[] ) { #define LONGOPTIONCHAR '-' /* 定义长选项 */ static struct option longOption[] = { { "send", 1, 0, LONGOPTIONCHAR }, /* 发送MAC */ { "recv", 1, 0, LONGOPTIONCHAR }, /* 接收MAC */ { "si", 1, 0, LONGOPTIONCHAR }, /* 源IP */ { "di", 1, 0, LONGOPTIONCHAR }, /* 目标IP */ { "sm", 1, 0, LONGOPTIONCHAR }, /* 源MAC */ { "dm", 1, 0, LONGOPTIONCHAR }, /* 目标MAC */ { "arpOp", 1, 0, LONGOPTIONCHAR }, /* ARP操作类型 */ { "num", 1, 0, LONGOPTIONCHAR }, /* ARP报文数目 */ { 0, 0, 0, 0 } }; int longOptionIndex = 0; /* 用于处理长选项 */ u_char sendMac[6] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; u_char recvMac[6] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; u_char srcMac[6] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; u_char dstMac[6] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; u_long srcIp = 0xffffffff; /* 源IP使用使用网络字节序指定 */ u_long dstIp = 0xffffffff; u_short arpOp = ARPOP_REPLY; /* little-endian 序 */ u_long arpNumber = DEFAULTARPNUMBER; /* ARP报文数目 */ char tempString1[16] = ""; char tempString2[3] = ""; u_short tempUshort = 0; int c, i; u_long a; u_char * device; if ( argc == 1 ) { usage( argv[0] ); } opterr = 0; /* don't want getopt() writing to stderr */ while ( ( c = getopt_long( argc, argv, "h", longOption, &longOptionIndex ) ) != EOF ) { switch ( c ) { case LONGOPTIONCHAR: /* 处理长选项 */ /* fprintf( stderr, "option %s", longOption[ longOptionIndex ].name ); if ( optarg ) { fprintf( stderr, " with arg %s", optarg ); } fprintf( stderr, "/n" ); */ if ( optarg ) { switch ( longOptionIndex ) { case 0: Strncpy( tempString1, optarg, 16 ); tempUshort = strlen( tempString1 ); if ( tempUshort == 12 ) { tempString2[2] = '/0'; for ( i = 0; i < 6; i++ ) { tempString2[0] = tempString1[ i << 1 ]; tempString2[1] = tempString1[ ( i << 1 ) + 1 ]; sendMac[ i ] = ( u_char )strtoul( tempString2, NULL, 16 ); } /* end of for */ } break; case 1: Strncpy( tempString1, optarg, 16 ); tempUshort = strlen( tempString1 ); if ( tempUshort == 12 ) { tempString2[2] = '/0'; for ( i = 0; i < 6; i++ ) { tempString2[0] = tempString1[ i << 1 ]; tempString2[1] = tempString1[ ( i << 1 ) + 1 ]; recvMac[ i ] = ( u_char )strtoul( tempString2, NULL, 16 ); } /* end of for */ } break; case 2: /* 返回值是big-endian序 */ srcIp = libnet_name_resolve( optarg, LIBNET_DONT_RESOLVE ); if ( srcIp == -1 ) { libnet_error( LIBNET_ERR_FATAL, "Bad srcIp: %s/n", optarg ); } break; case 3: /* 返回值是big-endian序 */ dstIp = libnet_name_resolve( optarg, LIBNET_DONT_RESOLVE ); if ( dstIp == -1 ) { /* 第一个参数为LIBNET_ERR_FATAL,会导致exit */ libnet_error( LIBNET_ERR_FATAL, "Bad dstIp: %s/n", optarg ); } break; case 4: Strncpy( tempString1, optarg, 16 ); tempUshort = strlen( tempString1 ); if ( tempUshort == 12 ) { tempString2[2] = '/0'; for ( i = 0; i < 6; i++ ) { tempString2[0] = tempString1[ i << 1 ]; tempString2[1] = tempString1[ ( i << 1 ) + 1 ]; srcMac[ i ] = ( u_char )strtoul( tempString2, NULL, 16 ); } /* end of for */ } break; case 5: Strncpy( tempString1, optarg, 16 ); tempUshort = strlen( tempString1 ); if ( tempUshort == 12 ) { tempString2[2] = '/0'; for ( i = 0; i < 6; i++ ) { tempString2[0] = tempString1[ i << 1 ]; tempString2[1] = tempString1[ ( i << 1 ) + 1 ]; dstMac[ i ] = ( u_char )strtoul( tempString2, NULL, 16 ); } /* end of for */ } break; case 6: arpOp = ( u_short )strtoul( optarg, NULL, 10 ); break; case 7: /* 采用10进制 */ arpNumber = ( u_long )strtoul( optarg, NULL, 10 ); if ( arpNumber == 0 ) { fprintf( stderr, "Check your arpNumber/n" ); exit( FAILURE ); } break; default: break; } /* end of switch */ } break; case 'h': &am |
libnet使用举例(12)
最新推荐文章于 2024-01-29 08:47:41 发布