创建时间: 2017-08-17
最后修改时间: 2017-08-17因个人水平有限,文章中存在不足,错误之处,还望指正
实验环境
Linux 2.6.32
gcc version 4.4.6 20120305 (Red Hat 4.4.6-4) (GCC)
引言
本ping程序并没有提供网络上公开可得的ping程序那样强大的功能(支持众多不同的选项),而是仅实现最基本的功能来了解我们所关注的问题:网络编程的概念和技巧。
ping程序简介
ping程序可以用来测试网络上的节点是否可达或网络连接速度。该程序发送一个ICMP回显请求给目的端,并等待其返回ICMP回显应答。
一般来说,如果不能ping到某主机,那么就不能Telnet到该主机。但这并不是绝对的,随着Internet安全意识的增强,出现了提供访问控制的路由器和防火墙,一台主机的可达性可能不只取决于IP层是否可达,还取决于使用何种协议以及端口。ping程序运行结果显示某台主机不可达,但我们却可以用Telnet远程登录该主机。
IP和ICMP协议简介
IP(Internet Protocol),网际协议,是TCP/IP协议族中最为核心的协议。所有TCP、UDP、ICMP及IGMP数据都以IP数据报格式传输。
它提供不可靠、无连接的数据报传送服务。
不可靠的意思是它不能保证IP数据报能成功地到达目的地。如果发生某种错误时,如某个路由器的缓冲区已满,IP有一个简单的错误处理方法:丢弃该数据报,然后发送ICMP消息给源端。任何要求的可靠性必须由上层服务来提供,如TCP。
无连接的意思是IP并不维护任何关于后续数据报信息。每个数据报的处理是相互独立的。这说明,IP数据报可以不按发送顺序接收。如果源端向目的端发送两个连续的数据报A、B,每个数据报都是独立进行路由选择,可能选择不同的线路,因此B可能在A之前先到达。
IP首部
0 4 8 16 19 32
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|Version| IHL |Type Of Service| Total Length(in bytes) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Identification |Flags| Fragment Offset |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Time To Live | Protocol | Header Checksum |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Source Ipv4 Address |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Destination Ipv4 Address |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
~ Options (if any) ~
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
~ Data ~
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
IPv4首部
ICMP(Internet Control Message Protocol),Internet控制消息协议,是TCP/IP协议族的一个子协议,属于网络层协议,用于传递差错报文以及其他需要注意的信息。
ICMP报文在IP数据报内部被传输的。如下:
|------------------------- IP数据报 ------------------------|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| IP首部 | ICMP报文 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
ICMP报文有许多种类型,这里只列出我们所关注的报文格式:
0 8 16 32
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Type | Code | Checksum |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Identifier | Sequence Number |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
~ Option Data ~
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
ICMP回显请求和回显应答报文首部
Type ICMP报文类型
Code 代码
Checksum 检验和
Identifier 标识符,由源端设定,应答报文的Identifier与请求报文的保持一致
Sequence Number 序列号,由源端设定,一般是递增的,应答报文的Sequence Number与请求报文的保持一致
Option Data 数据,应答报文的Option Data与请求报文的保持一致
与IP和ICMP首部相关的结构
在/usr/include/目录下可找到这些头文件。
ip结构体在头文件 “netinet/ip.h”中定义如下:
struct ip
{
#if __BYTE_ORDER == __LITTLE_ENDIAN
unsigned int ip_hl:4; /* header length */
unsigned int ip_v:4; /* version */
#endif
#if __BYTE_ORDER == __BIG_ENDIAN
unsigned int ip_v:4; /* version */
unsigned int ip_hl:4; /* header length */
#endif
u_int8_t ip_tos; /* type of service */
u_short ip_len; /* total length */
u_short ip_id; /* identification */
u_short ip_off; /* fragment offset field */
#define IP_RF 0x8000 /* reserved fragment flag */
#define IP_DF 0x4000 /* dont fragment flag */
#define IP_MF 0x2000 /* more fragments flag */
#define IP_OFFMASK 0x1fff /* mask for fragmenting bits
*/
u_int8_t ip_ttl; /* time to live */
u_int8_t ip_p; /* protocol */
u_short ip_sum; /* checksum */
struct in_addr ip_src, ip_dst; /* source and dest address */
};
icmp结构体在头文件”netinet/ip_icmp.h”中定义如下:
struct icmp
{
u_int8_t icmp_type; /* type of message, see below */
u_int8_t icmp_code; /* type sub code */
u_int16_t icmp_cksum; /* ones complement checksum of struct */
union
{
u_char ih_pptr; /* ICMP_PARAMPROB */
struct in_addr ih_gwaddr; /* gateway address */
struct ih_idseq /* echo datagram */
{
u_int16_t icd_id;
u_int16_t icd_seq;
} ih_idseq;
u_int32_t ih_void;
/* ICMP_UNREACH_NEEDFRAG -- Path MTU Discovery (RFC1191) */
struct ih_pmtu
{
u_in