PythonでUDPトレースルート(traceroute)〜ネットワーク経路調査
目的のホストまでのネットワーク経路を表示するPythonスクリプト。
Tracerouteの原理は以下のような感じで、目的のホストまでUDPパケットを出して手前のルーターから一つずつ探っていく感じ。
http://ja.wikipedia.org/wiki/Traceroute
tracerouteはTTLを1ずつ増やしながらパケットを送信することで、経路情報を取得する。 TTLとはパケットの生存期間を表し、ルータを1つ経由することに1ずつ減算される。 ルータはTTLが2以上のパケットが届いた場合、TTLの値を1だけ小さくし次のルータへ転送する。 TTLが1のパケットが届いた場合、届いたパケットを破棄しICMP time exceededパケットを送信者に返す。
tracerouteはまず、TTLを1にセットしたパケットを送信する。最初のルータに届いた時点でTTLがゼロになり、ICMP time exceededメッセージが戻ってくる。このメッセージの送信元アドレスを見れば、最初のルータのIPアドレスがわかる。次にTTLを2にセットして送信すると、今度は2番目のルータからICMP time exceededが戻ってくる。以降、TTLを3、4・・・と増やしていく事で、順にルータのIPアドレスを得る事ができる。
#!/usr/bin/env python import sys import socket def traceroute(dest_name, port, max_hops): dest_addr = socket.gethostbyname(dest_name) print "target ==> %s (%s)" % (dest_name, dest_addr) socket.setdefaulttimeout(10) 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_addr, 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_name == dest_name or curr_addr == dest_addr or ttl > max_hops: break if __name__ == "__main__": traceroute(sys.argv[1], int(sys.argv[2]), int(sys.argv[3]))
使い方(実行はroot権限で)
./traceroute.py google.com 13402 30