A fun thing to do with traceroute implementations is to try to set speed records. The classic traceroute loop is unnecessarily slow, because it waits for the response from probe n before sending probe n+1; you can just send them all at once. You can traceroute with a variety of different protocols (Windows uses TCP, IIRC, because it gets through more firewalls). There are more esoteric tricks, too; for instance, there was a time when you could get the IP Record Route option to work.
When i was a youngster, back in linux kernel 2.0.33 days, I hacked my kernel so that it spoofed traceroute.
When it was going to send an ICMP time exceeded, it would change the source ip to the next one in a list of curious ips. Simple change but taught me heaps about network programming, the kernel, c, etc..
Toy traceroute using ping on Linux (Debian, in my case):
$ for ttl in {1..30}; do ping -4 -c 1 -t $ttl example.com; done | grep -i from | nl -s ' ' -w 2
1 From router2-lon.linode.com (212.111.33.230) icmp_seq=1 Time to live exceeded
2 From if-11-0-0-1-0.gw2.lon1.gb.linode.com (109.74.207.48) icmp_seq=1 Time to live exceeded
3 From ldn-b2-link.ip.twelve99.net (62.115.41.64) icmp_seq=1 Time to live exceeded
4 From ldn-bb1-link.ip.twelve99.net (62.115.122.188) icmp_seq=1 Time to live exceeded
5 From nyk-bb2-link.ip.twelve99.net (62.115.113.20) icmp_seq=1 Time to live exceeded
6 From nyk-b1-link.ip.twelve99.net (62.115.135.133) icmp_seq=1 Time to live exceeded
7 From edgecast-ic317659-nyk-b6.ip.twelve99-cust.net (62.115.147.199) icmp_seq=1 Time to live exceeded
8 From ae-65.core1.nyb.edgecastcdn.net (152.195.68.131) icmp_seq=1 Time to live exceeded
9 64 bytes from 93.184.216.34 (93.184.216.34): icmp_seq=1 ttl=56 time=73.7 ms
10 64 bytes from 93.184.216.34 (93.184.216.34): icmp_seq=1 ttl=56 time=73.6 ms
11 64 bytes from 93.184.216.34 (93.184.216.34): icmp_seq=1 ttl=56 time=73.7 ms
12 64 bytes from 93.184.216.34 (93.184.216.34): icmp_seq=1 ttl=56 time=73.6 ms
...
This loop sends out multiple ICMP echo requests with different TTL values (1, 2, 3, etc.). Each router on the path decrements the TTL by one. Everytime a router finds that the TTL is 0, we get an ICMP TTL exceeded message from that router. The traceroute is complete when we see the ping responses appearing. For comparison, here is the output of the actual traceroute command:
$ traceroute -4 example.com
traceroute to example.com (93.184.216.34), 30 hops max, 60 byte packets
1 router2-lon.linode.com (212.111.33.230) 0.550 ms router1-lon.linode.com (212.111.33.229) 0.525 ms router2-lon.linode.com (212.111.33.230) 0.694 ms
2 if-0-1-0-1-0.gw2.lon1.gb.linode.com (109.74.207.6) 0.503 ms 0.491 ms if-11-0-0-1-0.gw1.lon1.gb.linode.com (109.74.207.24) 0.417 ms
3 be5787.rcr51.lon10.atlas.cogentco.com (204.68.252.58) 0.969 ms 1.029 ms ldn-b2-link.ip.twelve99.net (62.115.41.64) 1.281 ms
4 be2589.ccr41.lon13.atlas.cogentco.com (154.54.59.37) 1.351 ms 1.404 ms 1.474 ms
5 nyk-bb1-link.ip.twelve99.net (62.115.112.244) 70.847 ms 70.802 ms be2099.ccr31.bos01.atlas.cogentco.com (154.54.82.34) 63.580 ms
6 verizondms.bos01.atlas.cogentco.com (154.54.11.54) 63.639 ms 64.945 ms nyk-b1-link.ip.twelve99.net (62.115.135.133) 76.193 ms
7 edgecast-ic317660-nyk-b6.ip.twelve99-cust.net (62.115.147.201) 73.460 ms ae-65.core1.bsa.edgecastcdn.net (152.195.232.129) 63.659 ms edgecast-ic317660-nyk-b6.ip.twelve99-cust.net (62.115.147.201) 71.224 ms
8 ae-70.core1.nyb.edgecastcdn.net (152.195.68.141) 72.759 ms 93.184.216.34 (93.184.216.34) 62.964 ms ae-71.core1.nyb.edgecastcdn.net (152.195.69.139) 74.359 ms
9 93.184.216.34 (93.184.216.34) 63.023 ms 70.599 ms 73.223 ms
On macOS, the ping loop would look like this due to differences in what the ping option names mean:
for ttl in {1..30}; do ping -c 1 -t 1 -m $ttl example.com; done | grep -i from | nl -s ' ' -w 2
On macOS, the -t option of ping specifies a timeout (not ICMP TTL) which we need to specify to prevent ping from waiting for too long. The -m option specifies the ICMP TTL on macOS.
https://undeadly.org/cgi?action=article;sid=20210903094704