作者:小四 < 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
主页: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