下载地址:
git clone [email protected]:iputils/iputils.git
还有另外一个gnu的ping:
wget http://ftp.gnu.org/gnu/inetutils/inetutils-1.9.4.tar.xz
struct icmphdr {
__u8 type;
__u8 code;
__sum16 checksum;
union {
struct {
__be16 id;
__be16 sequence;
} echo;
__be32 gateway;
struct {
__be16 __unused;
__be16 mtu;
} frag;
__u8 reserved[4];
} un;
};
对gnu的ping来说id是当前进程的pid:
ping = ping_init (ICMP_ECHO, getpid ());
对iputils的ping来说id是随机数,在函数setup()中设置:
rts->ident = rand() & 0xFFFF;
ping包一般98个字节,mac 14个字节,ip 20个字节,icmp 8个字节,后面有16个字节是time,然后填充40个字节,从16到55。
[Sat Dec 7 21:00:54 2019] skbuff: __skb_checksum_complete 1: csum_valid: 0, ip_summed: 0, skb->csum: 0, csum: 79b98646, sum: 0, skb->len: 84, seq: 4, checksum: ab3c
[Sat Dec 7 21:00:54 2019] dump: 00000000415dcb24: e4 e7 49 93 bd 84 00 21 cc 6f 3e 0d 08 00
[Sat Dec 7 21:00:54 2019] dump: 00000000073121ad: 45 00 00 54 45 55 00 00 40 01 31 50 01 01 01 02
[Sat Dec 7 21:00:54 2019] dump: 00000000117c98fe: 01 01 01 01
[Sat Dec 7 21:00:54 2019] dump: 00000000f00539cd: 00 00 ab 3c 9e 84 00 04 87 a2 eb 5d 00 00 00 00
[Sat Dec 7 21:00:54 2019] dump: 00000000a7249ac9: 84 67 00 00 00 00 00 00 10 11 12 13 14 15 16 17
[Sat Dec 7 21:00:54 2019] dump: 000000007fd39aec: 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27
[Sat Dec 7 21:00:54 2019] dump: 0000000074706ee1: 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37
[Sat Dec 7 21:00:54 2019] skbuff: __skb_checksum_complete 2: csum_valid: 1, ip_summed: 2, skb->csum: 4686b979, csum: 4686b979, sum: 0
crash> timeval
struct timeval {
__kernel_time_t tv_sec;
__kernel_suseconds_t tv_usec;
}
SIZE: 16
发送的时候通过gettimeofday设置这16个字节,收到reply后通过函数gather_statistics()计算出延迟:
uint8_t *ptr = icmph + icmplen;
if (rts->timing && cc >= (int)(8 + sizeof(struct timeval))) {
struct timeval tmp_tv;
memcpy(&tmp_tv, ptr, sizeof(tmp_tv));
tvsub(tv, &tmp_tv);
triptime = tv->tv_sec * 1000000 + tv->tv_usec;
如果将id设为0的话,icmp的checksum对每个sequence来说都是一样的了。发送端调用关系如下:
ping4_run
setup
main_loop
pinger
send_probe/ping4_send_probe
sendto
crash> ps ping
PID PPID CPU TASK ST %MEM VSZ RSS COMM
3128 2275 4 ffff96e0b9be0000 IN 0.0 19984 3580 ping
crash> files 3128
PID: 3128 TASK: ffff96e0b9be0000 CPU: 7 COMMAND: "ping"
ROOT: / CWD: /home/chrism
FD FILE DENTRY INODE TYPE PATH
0 ffff96e0b963d400 ffff96e073948240 ffff96e07c0946d8 CHR /dev/pts/1
1 ffff96e0b963d400 ffff96e073948240 ffff96e07c0946d8 CHR /dev/pts/1
2 ffff96e0b963d400 ffff96e073948240 ffff96e07c0946d8 CHR /dev/pts/1
3 ffff96e0a88c7000 ffff96e07de8dcc0 ffff96e04ba34980 SOCK RAW
4 ffff96e0a88c6f00 ffff96e07de8db40 ffff96e04ba34f80 SOCK RAWv6
crash> struct file.private_data ffff96e0a88c7000
private_data = 0xffff96e04ba34900
crash> socket.sk 0xffff96e04ba34900
sk = 0xffff96e0b7140000
crash> sock 0xffff96e0b7140000
第一步,发送
1.828172 3128 3128 ping e1000_xmit_frame
e1000_xmit_frame+0x1 [kernel]
dev_hard_start_xmit+0x8d [kernel]
sch_direct_xmit+0xe6 [kernel]
__dev_queue_xmit+0x665 [kernel]
ip_finish_output2+0x2c8 [kernel]
ip_output+0x71 [kernel]
ip_send_skb+0x15 [kernel]
raw_sendmsg+0x87b [kernel]
sock_sendmsg+0x41 [kernel]
__sys_sendto+0xee [kernel]
__x64_sys_sendto+0x25 [kernel]
do_syscall_64+0x4f [kernel]
entry_SYSCALL_64_after_hwframe+0x44 [kernel]
raw_sendmsg
ip_push_pending_frames
ip_send_skb
第二步,对端收到后,发送reply
1.875067 0 0 swapper/4 e1000_xmit_frame
e1000_xmit_frame+0x1 [kernel]
dev_hard_start_xmit+0x8d [kernel]
sch_direct_xmit+0xe6 [kernel]
__dev_queue_xmit+0x665 [kernel]
ip_finish_output2+0x2c8 [kernel]
ip_output+0x71 [kernel]
ip_send_skb+0x15 [kernel]
icmp_reply.constprop.0+0x28e [kernel]
icmp_echo.part.0+0x5b [kernel]
icmp_echo+0x2c [kernel]
icmp_rcv+0x159 [kernel]
ip_protocol_deliver_rcu+0x1aa [kernel]
ip_local_deliver_finish+0x44 [kernel]
ip_local_deliver+0xe5 [kernel]
ip_rcv+0xbc [kernel]
__netif_receive_skb_one_core+0x5b [kernel]
netif_receive_skb_internal+0x2f [kernel]
napi_gro_receive+0xf6 [kernel]
e1000_clean_rx_irq+0x20b [kernel]
e1000e_poll+0x76 [kernel]
net_rx_action+0x131 [kernel]
__do_softirq+0xe0 [kernel]
irq_exit+0xa0 [kernel]
do_IRQ+0x81 [kernel]
ret_from_intr+0x0 [kernel]
cpuidle_enter_state+0xbc [kernel]
cpuidle_enter+0x29 [kernel]
do_idle+0x1d3 [kernel]
cpu_startup_entry+0x19 [kernel]
start_secondary+0x153 [kernel]
secondary_startup_64+0xa4 [kernel]
第三步,发送端收到reply后计算延迟
2.159475 0 0 swapper/6 ping_rcv
ping_rcv+0x1 [kernel]
icmp_rcv+0x159 [kernel]
ip_protocol_deliver_rcu+0x1aa [kernel]
ip_local_deliver_finish+0x44 [kernel]
ip_local_deliver+0xe5 [kernel]
ip_rcv+0xbc [kernel]
__netif_receive_skb_one_core+0x5b [kernel]
netif_receive_skb_internal+0x2f [kernel]
napi_gro_receive+0xf6 [kernel]
e1000_clean_rx_irq+0x20b [kernel]
e1000e_poll+0x76 [kernel]
net_rx_action+0x131 [kernel]
__do_softirq+0xe0 [kernel]
irq_exit+0xa0 [kernel]
do_IRQ+0x81 [kernel]
ret_from_intr+0x0 [kernel]
cpuidle_enter_state+0xbc [kernel]
cpuidle_enter+0x29 [kernel]
do_idle+0x1d3 [kernel]
cpu_startup_entry+0x19 [kernel]
start_secondary+0x153 [kernel]
secondary_startup_64+0xa4 [kernel]
ping用的是SOCK_RAW,通过打印全局变量net_families和inetsw,可以得到下面的输出:
family: 1, create: unix_create
family: 2, create: inet_create
family: 10, create: inet6_create
family: 16, create: netlink_create
family: 17, create: packet_create
family: 30, create: tipc_sk_create
type: 1, protocol: 6, prot: tcp_prot, ops: inet_stream_ops
type: 2, protocol: 17, prot: udp_prot, ops: inet_dgram_ops
type: 2, protocol: 136, prot: udplite_prot, ops: inet_dgram_ops
type: 2, protocol: 1, prot: ping_prot, ops: inet_sockraw_ops
type: 3, protocol: 0, prot: raw_prot, ops: inet_sockraw_ops
SOCK_STREAM: 1
SOCK_DGRAM: 2
SOCK_RAW: 3