📄 527.htm
字号:
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
<title>CTerm非常精华下载</title>
</head>
<body bgcolor="#FFFFFF">
<table border="0" width="100%" cellspacing="0" cellpadding="0" height="577">
<tr><td width="32%" rowspan="3" height="123"><img src="DDl_back.jpg" width="300" height="129" alt="DDl_back.jpg"></td><td width="30%" background="DDl_back2.jpg" height="35"><p align="center"><a href="http://apue.dhs.org"><font face="黑体"><big><big>apue</big></big></font></a></td></tr>
<tr>
<td width="68%" background="DDl_back2.jpg" height="44"><big><big><font face="黑体"><p align="center"> ● UNIX网络编程 (BM: clown) </font></big></big></td></tr>
<tr>
<td width="68%" height="44" bgcolor="#000000"><font face="黑体"><big><big><p align="center"></big></big><a href="http://cterm.163.net"><img src="banner.gif" width="400" height="60" alt="banner.gif"border="0"></a></font></td>
</tr>
<tr><td width="100%" colspan="2" height="100" align="center" valign="top"><br><p align="center">[<a href="index.htm">回到开始</a>][<a href="519.htm">上一层</a>][<a href="528.htm">下一篇</a>]
<hr><p align="left"><small>发信人: scz (小四), 信区: Security <br>
标 题: libnet使用举例(2) <br>
发信站: 武汉白云黄鹤站 (Wed Jul 26 16:46:31 2000), 站内信件 <br>
作者:小四 < mailto: scz@isbase.com > <br>
主页:http://www.isbase.com <br>
日期:2000-07-26 20:10 <br>
这篇先介绍libnet_init_packet()函数,其函数原型如下: <br>
int libnet_init_packet ( size_t p_size, u_char ** buf ); <br>
该函数实际调用了malloc函数做了一次内存分配,第一个形参就是指定内存分配的大 <br>
小。第二个形参用于返回指向这块内存的指针。如果p_size被省略或为负值,将默认 <br>
使用LIBNET_MAX_PACKET。内存分配成功后初始化成0,函数返回1,否则返回-1。显 <br>
然有一个对应的函数释放内存: <br>
int libnet_destroy_packet ( u_char ** buf ); <br>
这个函数除了调用free(),目前没有其他动作。 <br>
在/usr/include/libnet/libnet-macros.h中有如下定义: <br>
#define LIBNET_MAX_PACKET 0xffff <br>
事实上我们完全可以不使用这两个函数,它们并没有操作什么内部数据结构,仅仅为 <br>
了统一封装起见使用它们。 <br>
针对p_size,libnet在/usr/include/libnet/libnet-headers.h中定义了一批宏: <br>
#define LIBNET_ARP_H 0x1c /* ARP header: 28 bytes */ <br>
#define LIBNET_DNS_H 0xc /* DNS header base: 12 bytes */ <br>
#define LIBNET_ETH_H 0xe /* Etherner header: 14 bytes */ <br>
#define LIBNET_ICMP_H 0x4 /* ICMP header base: 4 bytes */ <br>
#define LIBNET_IGMP_H 0x8 /* IGMP header: 8 bytes */ <br>
#define LIBNET_IP_H 0x14 /* IP header: 20 bytes */ <br>
#define LIBNET_RIP_H 0x18 /* RIP header base: 24 bytes */ <br>
#define LIBNET_TCP_H 0x14 /* TCP header: 20 bytes */ <br>
#define LIBNET_UDP_H 0x8 /* UDP header: 8 bytes */ <br>
上面仅仅列举了常用的几个宏,虽然不是必须使用,但建议尽量使用宏。 <br>
接下来介绍两个操作raw_socket的函数: <br>
int libnet_open_raw_sock ( int protocol ); <br>
int libnet_close_raw_sock ( int fd ); <br>
libnet_open_raw_sock()打开IPv4上指定协议类型的raw_socket,同时设置了 <br>
IP_HDRINCL选项,成功则返回socket,失败返回-1。libnet_close_raw_sock()关闭 <br>
前者打开的raw_socket,成功则返回1,失败返回-1。 <br>
实际上,形参protocol对应的就是socket()函数的第三个形参,所以可以指定 <br>
IPPROTO_RAW、IPPROTO_ICMP、IPPROTO_TCP等,当然还要看内核是否支持这样的指定。 <br>
<br>
我们可以类似W.Richard.Stevens那样处理,封装一下这个函数: <br>
-------------------------------------------------------------------------- <br>
int Libnet_open_raw_sock ( int protocol ) <br>
{ <br>
int s; <br>
if ( ( s = libnet_open_raw_sock( protocol ) ) == -1 ) <br>
{ <br>
{ <br>
libnet_error( LIBNET_ERR_FATAL, "Can't open raw socket %08x\n", proc <br>
otol <br>
); <br>
} <br>
return( s ); <br>
} /* end of Libnet_open_raw_sock */ <br>
-------------------------------------------------------------------------- <br>
在不使用libnet库编程的时候,打开raw_socket,接下来就是要构造IP头,libnet使 <br>
用如下函数完成这个工作: <br>
int libnet_build_ip ( u_short len, u_char tos, u_short id, u_short frag, <br>
u_char ttl, u_char prot, u_long saddr, u_long daddr, <br>
const u_char * payload, int payload_s, u_char * buf ); <br>
<br>
形参len指定的是IP数据区长度,既不是IP头部长度,也不是IP报文总长度,并没有 <br>
一个结构成员对应这个形参,习惯了socket编程的兄弟要注意。saddr和daddr均以网 <br>
络字节序提供,也就是big-endian序。payload指向可选的IP选项以及可能出现的填 <br>
充,payload_s指定这些数据的长度。至于最后一个参数buf,指向通过 <br>
libnet_init_packet分配并初始化过的数据区,将来包括IP头都要出现在该数据区, <br>
此时buf指向的实际是IP头。当然这里举例是以IP报文举例,如果是其他类型的报文, <br>
就不是这个结论了。不要把payload和IP数据区混淆了,否则libnet构造IP头的时候 <br>
出现混乱。 <br>
libnet使用下面这个函数进一步在IP报文上构造TCP头: <br>
int libnet_build_tcp ( u_short sport, u_short dport, u_long seq, <br>
u_long ack, u_char control, u_short win, u_short urg, <br>
<br>
const u_char * payload, int payload_s, u_char * buf ) <br>
; <br>
形参control对应我们熟悉的SYN、ACK、RST等标志的逻辑或。最后一个形参需要指向 <br>
一个已分配好的数据区,TCP头从该指针开始。类似IP层,这里payload指向可选的 <br>
TCP选项以及可能出现的填充,不要和TCP数据区相混淆。 <br>
接下来可能是你曾经如许头疼的TCP/UDP校验和计算问题: <br>
int libnet_do_checksum ( u_char * buf, int protocol, int len ); <br>
该函数用于计算传输层校验和并填写到适当头部位置,包括TCP/UDP校验和的计算。 <br>
显然该函数应该在传输层报文包括数据区构造完毕之后被调用,否则计算得到的校验 <br>
和必将因为传输层数据区的改变而失效。成功则返回1,否则返回-1。第一个形参需 <br>
要指向IP头,而不是TCP头什么的,第二个形参指定传输层协议类型,第三个形参指 <br>
定了IP数据区长度,不包括IP头部。 <br>
说点题外话,在raw_socket层上,IP头部校验和总是由内核亲自计算,但是如果直接 <br>
在链路层构造报文,必须显式计算IP头部校验和。 <br>
对于所有的build_*函数,如果buf指针为NULL,运行时会检查到这个错误并返回-1。 <br>
但是payload_s超长、头部超出预先分配大小等等,是无法检测到的,必须意识到这 <br>
个问题所在。 <br>
计算TCP/UDP头部校验和相对其他校验和的计算是显得复杂了点,却也没有想象的那 <br>
么的可怕,主要是现在很多书上并没有解释清楚、翻译清楚原意,可以参考许多现成 <br>
的源代码。libnet库提供这么一个封装过的函数固然不错,还是希望你能真正了解校 <br>
验和的计算过程。 <br>
下面要做的是把这样一个精心构造的报文丢到网络上去: <br>
int libnet_write_ip ( int sock, u_char * packet, int len ); <br>
第一个形参即libnet_open_raw_sock()的返回值,第二个形参指向IP头,第三个形参 <br>
指明了整个IP报文总长度。函数返回值对应发送出去的字节数,注意不见得构造多大 <br>
的报文就能发送出去这么大的报文,必须检查返回值。 <br>
到此为止,我们企图编写一个syn-flood的主力舰队都到齐了,至于如何编队、何时 <br>
出发且听下回分解,总得给我个灌水的机会吧,都一次灌完了如何长我那可怜的经验 <br>
值呢? <br>
<待续> <br>
-- <br>
也许有一天,他再从海上蓬蓬的雨点中升起, <br>
飞向西来,再形成一道江流,再冲倒两旁的石壁, <br>
再来寻夹岸的桃花。然而,我不敢说来生,也不敢信来生...... <br>
</small><hr>
<p align="center">[<a href="index.htm">回到开始</a>][<a href="519.htm">上一层</a>][<a href="528.htm">下一篇</a>]
<p align="center"><a href="http://cterm.163.net">欢迎访问Cterm主页</a></p>
</table>
</body>
</html>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -