#!/usr/bin/env python
'''
Created on 11 jan. 2013

@author: sander
'''

from ipaddress import ip_address, IPv4Address, IPv6Address
from pylisp.packet.ip import IPv4Packet, IPv6Packet, UDPMessage
from pylisp.packet.lisp.control import (EncapsulatedControlMessage,
    MapRequestMessage, ControlMessage)
import random
import socket
import sys

my_name = socket.getfqdn()
query = ip_address(unicode(sys.argv[1]))
if isinstance(query, IPv4Address):
    query_source = IPv4Address(u'0.0.0.0')
else:
    query_source = IPv6Address(u'::')
source_port = random.choice(range(30000, 40000))

# Build the map request
nonce = ''.join([chr(random.choice(xrange(256))) for i in range(8)])

d_addrs = socket.getaddrinfo('mr.lispnet.net', 4342, 0, 0, socket.SOL_UDP)
for d_family, d_socktype, d_proto, d_canonname, d_sockaddr in d_addrs:
    destination = ip_address(unicode(d_sockaddr[0]))
    print 'Try %s' % destination

    s_addrs = socket.getaddrinfo(my_name, source_port, d_family, d_socktype,
                                 d_proto)
    for s_family, s_socktype, s_proto, s_canonname, s_sockaddr in s_addrs:
        source = ip_address(unicode(s_sockaddr[0]))
        print '- From %s' % source

        # Build packet
        req = MapRequestMessage(nonce=nonce,
                                source_eid=query_source,
                                itr_rlocs=[source],
                                eid_prefixes=[query])
        udp = UDPMessage(source_port=source_port,
                         destination_port=4342,
                         payload=req)
        udp.checksum = udp.calculate_checksum(source=query_source,
                                              destination=query)
        if isinstance(query, IPv4Address):
            ecm_content = IPv4Packet(ttl=64,
                                     protocol=udp.header_type,
                                     source=query_source,
                                     destination=query,
                                     payload=udp)
        else:
            ecm_content = IPv6Packet(next_header=17,
                                     hop_limit=64,
                                     source=query_source,
                                     destination=query,
                                     payload=udp)

        ecm = EncapsulatedControlMessage(payload=ecm_content)

        try:
            sock = socket.socket(d_family, d_socktype, d_proto)
            sock.settimeout(3)
            sock.bind(s_sockaddr)
            sock.sendto(bytes(ecm), d_sockaddr)
            data = sock.recv(4096)
            response = ControlMessage.from_bytes(data)
            print repr(response)
            print response.nonce == nonce
        except socket.error:
            continue

        # Print result
        print
