libnet使用举例(2)

     作者:小四 < mailto: scz@isbase.com >
主页:http://www.isbase.com
日期:2000-07-26 20:10

这篇先介绍libnet_init_packet()函数,其函数原型如下:

int libnet_init_packet ( size_t p_size, u_char ** buf );

该函数实际调用了malloc函数做了一次内存分配,第一个形参就是指定内存分配的大
小。第二个形参用于返回指向这块内存的指针。如果p_size被省略或为负值,将默认
使用LIBNET_MAX_PACKET。内存分配成功后初始化成0,函数返回1,否则返回-1。显
然有一个对应的函数释放内存:

int libnet_destroy_packet ( u_char ** buf );

这个函数除了调用free(),目前没有其他动作。

在/usr/include/libnet/libnet-macros.h中有如下定义:

#define LIBNET_MAX_PACKET 0xffff

事实上我们完全可以不使用这两个函数,它们并没有操作什么内部数据结构,仅仅为
了统一封装起见使用它们。

针对p_size,libnet在/usr/include/libnet/libnet-headers.h中定义了一批宏:

#define LIBNET_ARP_H 0x1c /* ARP header: 28 bytes */
#define LIBNET_DNS_H 0xc /* DNS header base: 12 bytes */
#define LIBNET_ETH_H 0xe /* Etherner header: 14 bytes */
#define LIBNET_ICMP_H 0x4 /* ICMP header base: 4 bytes */
#define LIBNET_IGMP_H 0x8 /* IGMP header: 8 bytes */
#define LIBNET_IP_H 0x14 /* IP header: 20 bytes */
#define LIBNET_RIP_H 0x18 /* RIP header base: 24 bytes */
#define LIBNET_TCP_H 0x14 /* TCP header: 20 bytes */
#define LIBNET_UDP_H 0x8 /* UDP header: 8 bytes */

上面仅仅列举了常用的几个宏,虽然不是必须使用,但建议尽量使用宏。
接下来介绍两个操作raw_socket的函数:

int libnet_open_raw_sock ( int protocol );
int libnet_close_raw_sock ( int fd );

libnet_open_raw_sock()打开IPv4上指定协议类型的raw_socket,同时设置了
IP_HDRINCL选项,成功则返回socket,失败返回-1。libnet_close_raw_sock()关闭
前者打开的raw_socket,成功则返回1,失败返回-1。

实际上,形参protocol对应的就是socket()函数的第三个形参,所以可以指定
IPPROTO_RAW、IPPROTO_ICMP、IPPROTO_TCP等,当然还要看内核是否支持这样的指定。

我们可以类似W.Richard.Stevens那样处理,封装一下这个函数:

--------------------------------------------------------------------------
int Libnet_open_raw_sock ( int protocol )
{
int s;
if ( ( s = libnet_open_raw_sock( protocol ) ) == -1 )
{
libnet_error( LIBNET_ERR_FATAL, "Can"t open raw socket %08x\n", procotol );
}
return( s );
} /* end of Libnet_open_raw_sock */
--------------------------------------------------------------------------

在不使用libnet库编程的时候,打开raw_socket,接下来就是要构造IP头,libnet使
用如下函数完成这个工作:

int libnet_build_ip ( u_short len, u_char tos, u_short id, u_short frag,
u_char ttl, u_char prot, u_long saddr, u_long daddr,
const u_char * payload, int payload_s, u_char * buf );

形参len指定的是IP数据区长度,既不是IP头部长度,也不是IP报文总长度,并没有
一个结构成员对应这个形参,习惯了socket编程的兄弟要注意。saddr和daddr均以网
络字节序提供,也就是big-endian序。payload指向可选的IP选项以及可能出现的填
充,payload_s指定这些数据的长度。至于最后一个参数buf,指向通过
libnet_init_packet分配并初始化过的数据区,将来包括IP头都要出现在该数据区,
此时buf指向的实际是IP头。当然这里举例是以IP报文举例,如果是其他类型的报文,
就不是这个结论了。不要把payload和IP数据区混淆了,否则libnet构造IP头的时候
出现混乱。

libnet使用下面这个函数进一步在IP报文上构造TCP头:

int libnet_build_tcp ( u_short sport, u_short dport, u_long seq,
u_long ack, u_char control, u_short win, u_short urg,
const u_char * payload, int payload_s, u_char * buf );

形参control对应我们熟悉的SYN、ACK、RST等标志的逻辑或。最后一个形参需要指向
一个已分配好的数据区,TCP头从该指针开始。类似IP层,这里payload指向可选的
TCP选项以及可能出现的填充,不要和TCP数据区相混淆。

接下来可能是你曾经如许头疼的TCP/UDP校验和计算问题:

int libnet_do_checksum ( u_char * buf, int protocol, int len );

该函数用于计算传输层校验和并填写到适当头部位置,包括TCP/UDP校验和的计算。
显然该函数应该在传输层报文包括数据区构造完毕之后被调用,否则计算得到的校验
和必将因为传输层数据区的改变而失效。成功则返回1,否则返回-1。第一个形参需
要指向IP头,而不是TCP头什么的,第二个形参指定传输层协议类型,第三个形参指
定了IP数据区长度,不包括IP头部。

说点题外话,在raw_socket层上,IP头部校验和总是由内核亲自计算,但是如果直接
在链路层构造报文,必须显式计算IP头部校验和。

对于所有的build_*函数,如果buf指针为NULL,运行时会检查到这个错误并返回-1。
但是payload_s超长、头部超出预先分配大小等等,是无法检测到的,必须意识到这
个问题所在。

计算TCP/UDP头部校验和相对其他校验和的计算是显得复杂了点,却也没有想象的那
么的可怕,主要是现在很多书上并没有解释清楚、翻译清楚原意,可以参考许多现成
的源代码。libnet库提供这么一个封装过的函数固然不错,还是希望你能真正了解校
验和的计算过程。

下面要做的是把这样一个精心构造的报文丢到网络上去:

int libnet_write_ip ( int sock, u_char * packet, int len );

第一个形参即libnet_open_raw_sock()的返回值,第二个形参指向IP头,第三个形参
指明了整个IP报文总长度。函数返回值对应发送出去的字节数,注意不见得构造多大
的报文就能发送出去这么大的报文,必须检查返回值。

到此为止,我们企图编写一个syn-flood的主力舰队都到齐了,至于如何编队、何时
出发且听下回分解,总得给我个灌水的机会吧,都一次灌完了如何长我那可怜的经验
值呢?
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值