Recently I noticed that the ping source code has an interesting trick. It creates a UDP socket and bind connect to the destnation using port 1025. The code is here.

At first glance it is strange as we know the ping just uses ICMP to detect the connection of two ip.

So Let’s see what happened.

In one terminal we use tcpdump to capture the packet.

    root@ubuntu:/home/test# tcpdump -nn -vv host

In another terminal we strace the ping.

    test@ubuntu:~$ strace -o ping.txt ping -c 1

After the ping terminated. We can see the tcmpdump has no packet related with the 1025 port.

    root@ubuntu:/home/test# tcpdump -nn -vv host
    tcpdump: listening on ens33, link-type EN10MB (Ethernet), capture size 262144 bytes
    07:29:19.390097 IP (tos 0x0, ttl 64, id 9390, offset 0, flags [DF], proto ICMP (1), length 84) > ICMP echo request, id 2, seq 1, length 64
    07:29:19.688639 IP (tos 0x0, ttl 128, id 44019, offset 0, flags [none], proto ICMP (1), length 84) > ICMP echo reply, id 2, seq 1, length 64

Let’s see the strace log.

    connect(5, {sa_family=AF_INET, sin_port=htons(1025), sin_addr=inet_addr("")}, 16) = 0
    getsockname(5, {sa_family=AF_INET, sin_port=htons(43043), sin_addr=inet_addr("")}, [16]) = 0
    close(5)                                = 0

The UDP 1025 port is just there and exists just socket/connect/getsockname/close.

So after search the internet I just found this is a trick to get current source IP that ping program used.

The use of 1025 is in the condition of no source ip specified. If we specify the source IP, there is no connect in the strace log.

    test@ubuntu:~$ strace -o ping.txt ping -I -c 1

Finally let’s just go to kernel to see.

    SYSCALL_DEFINE3(connect, int, fd, struct sockaddr __user *, uservaddr,
            int, addrlen)
        return __sys_connect(fd, uservaddr, addrlen);


It seems that ‘ip_route_output_key_hash_rcu’ choose the source address.

	if (!fl4->saddr) {
		if (ipv4_is_multicast(fl4->daddr))
			fl4->saddr = inet_select_addr(dev_out, 0,
		else if (!fl4->daddr)
			fl4->saddr = inet_select_addr(dev_out, 0,

    if (!inet->inet_saddr)
        inet->inet_saddr = fl4->saddr;	/* Update source address */

In the getsockname syscall, we can see it gets the source IP from ‘inet->inet_saddr’.

    int inet_getname(struct socket *sock, struct sockaddr *uaddr,
            int peer)
        struct sock *sk		= sock->sk;
        struct inet_sock *inet	= inet_sk(sk);
        DECLARE_SOCKADDR(struct sockaddr_in *, sin, uaddr);

        sin->sin_family = AF_INET;
        if (peer) {
        } else {
            __be32 addr = inet->inet_rcv_saddr;
            if (!addr)
                addr = inet->inet_saddr;
            sin->sin_port = inet->inet_sport;
            sin->sin_addr.s_addr = addr;






blog comments powered by Disqus