ping

下载地址:

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

 

你可能感兴趣的:(linux)