3
votes

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 > max_hops:
            break

if __name__ == "__main__":
    main('google.com')
2
you are describing too broad a problem (basically saying "do all my work for me"). you are much more likely to get useful answers if you post the code with exceptions, show the exceptions, and ask how to fix them. at the moment you're post does not even include an explicit question. you need to ask something.andrew cooke

2 Answers

0
votes

If you do not want to manage the sockets yourself, scapy is a great tool to build your own packets and do basic send/receive with them. You can find an example here of how to ping, from this (and reading some docs) you should be able to quite easily build your own traceroute.

3
votes

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%") )