1

I'm writing a simple program to get the number of hops from my machine to an arbitrary site (in this case, www.google.com.

My program seems to get stuck on the recvfrom() call. I've set it to be a non-blocking socket, so I'm able to see the error:

[WinError 10035] A non-blocking socket operation could not be completed immediately

When I run it as a blocking socket, the program simply runs forever.

Below is my source code. Any idea why I'm running into this issue? Thanks!

import socket
import select
import queue

def main(dest_name):
    print('launch')
    dest_addr = socket.gethostbyname(dest_name)
    # Define UDP and ICMP
    udp = socket.getprotobyname('udp')
    icmp = socket.getprotobyname('icmp')
    timer = 0
    port = 54321
    maxHops = 40
    while True:
        # Create sender and receiver. Sender uses UDP, receiver uses IDMP
        sender = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, udp)
        receiver = socket.socket(socket.AF_INET, socket.SOCK_RAW, icmp)
        receiver.setblocking(0)

        print('sockets assigned')
        # Assign TTL to sender, increment TTL
        sender.setsockopt(socket.SOL_IP, socket.IP_TTL, timer)
        print('ttl assigned')
        # Bind socket and send message from sender to receiver
        receiver.setblocking(0)
        receiver.bind(("", port))
        print('receiver bound')
        sender.sendto(bytes("", 'UTF-8'), (dest_name, port))
        print('sent')
        addr = None
        print('addr assigned')

        try:
            # Reads an array of 512-byte sized blocks from sender into addr
            (_,addr) = receiver.recvfrom(512)
            addr = addr[0]
            print("%f\n", addr)
       # Process socket errors
        except socket.error as exc:
            print('Error: please try again.\n')
            print('%s\n', exc)
            pass
        # Close both sockets
        finally:
           sender.close()
           receiver.close()
           print('closing')

        timer += 1

        if dest_addr == addr or timer == maxHops:
           break

if __name__ == "__main__":
    main('www.google.com')
Haley
  • 77
  • 1
  • 12

1 Answers1

0

How about that :

#!/usr/bin/python

import socket

def main(dest_name):
    dest_addr = socket.gethostbyname(dest_name)
    port = 54321
    max_hops = 40
    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')
Loïc
  • 11,804
  • 1
  • 31
  • 49
  • the > isn't recognized by my system for some reason. I changed it to == and it still didn't return anything; it simply ran forever. – Haley Dec 03 '15 at 20:57
  • woops, it's not > it's ">" the "Greater than" encoded, sorry (edited answer) – Loïc Dec 03 '15 at 21:03
  • 1
    Never mind. I ran this on a Linux VM and it worked! Seems to have something to do with running it on a Windows machine. Thanks for your help. – Haley Dec 03 '15 at 21:05
  • I'm noticing that the code never reaches a break. It seems the current_addr == dest_addr comparison is never true, even when it should be. Any idea why? – Haley Dec 03 '15 at 21:49
  • hmm no, but maybe print both you'll get a lead. – Loïc Dec 03 '15 at 21:52
  • It appears to somehow reach an address that cannot be pinged every time. Here is the output: Now contacting www.cnn.com 1 129.22.144.2 (129.22.144.2) 1.069069 ms 2 10.2.0.98 (10.2.0.98) 1.125097 ms 3 10.2.3.165 (10.2.3.165) 23.368120 ms When I try to ping 10.2.3.165 normally, it can't be contacted. Not sure how the program is reaching an unpingable address. – Haley Dec 03 '15 at 22:25