How to create an ICMP traceroute in Python
Question: I am trying to implement an ICMP based Traceroute in Python.

I found a very helpful guide (
<https://blogs.oracle.com/ksplice/entry/learning_by_doing_writing_your> ) that
has allowed me to create a UDP based Traceroute (code below) so just needs
modification. I have tried changing the send socket to ICMP however I can't
get anything to run without exceptions.

Note - The below code works however this is a UDP traceroute (sends a UDP
packet and receives an ICMP one) and I need my program to send an ICMP packet
and receive an ICMP packet. This is because these days firewalls are smarter
than they used to be and don't always send an ICMP response after receiving a
UDP packet for a random port. Essentially the UDP socket needs to be changed
for an ICMP one.

I guess this isn't the most common thing to try and achieve and am having
trouble researching on the net on how to do this. If anybody can provide some
insight it would be REALLY appreciated :-)

Main point to remember is that traceroutes work by setting the TTL so if the
solution is to use an ICMP library then it needs to have a configurable TTL
:-)

    
    
    #!/usr/bin/python
    
    import socket
    
    def main(dest_name):
        dest_addr = socket.gethostbyname(dest_name)
        port = 33434
        max_hops = 30
        icmp = socket.getprotobyname('icmp')
        udp = socket.getprotobyname('udp')
        ttl = 1
        while True:
            recv_socket = socket.socket(socket.AF_INET, socket.SOCK_RAW, icmp)
            send_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, udp)
            send_socket.setsockopt(socket.SOL_IP, socket.IP_TTL, ttl)
            recv_socket.bind(("", port))
            send_socket.sendto("", (dest_name, port))
            curr_addr = None
            curr_name = None
            try:
                _, curr_addr = recv_socket.recvfrom(512)
                curr_addr = curr_addr[0]
                try:
                    curr_name = socket.gethostbyaddr(curr_addr)[0]
                except socket.error:
                    curr_name = curr_addr
            except socket.error:
                pass
            finally:
                send_socket.close()
                recv_socket.close()
    
            if curr_addr is not None:
                curr_host = "%s (%s)" % (curr_name, curr_addr)
            else:
                curr_host = "*"
            print "%d\t%s" % (ttl, curr_host)
    
            ttl += 1
            if curr_addr == dest_addr or ttl &gt; max_hops:
                break
    
    if __name__ == "__main__":
        main('google.com')
    


Answer: Here is the solution using Scapy - thanks to KillianDS.

Sending the ping

    
    
    ans,unans=sr(IP(dst="www.google.com",ttl=X)/ICMP())
    

Accessing the reply

    
    
    ans.summary(lambda (s,r): r.sprintf("%IP.src%") )
    

