Search code examples
pythonsocketsipv6ttl

Python - how to set IPv6_HOPLIMIT in UDP datagram


How can you set the IPv6 Hop Limit in a Python socket? For IPv4 TTL, the following code works:

import socket
import binascii
ttl=70
target_ip='8.8.8.8'
target_port=53
hexstream='a2d2012000010000000000010377777706676f6f676c6503636f6d00000100010000291000000000000000'
message=binascii.unhexlify(hexstream)
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
s.setsockopt(socket.SOL_IP, socket.IP_TTL, ttl)
s.sendto(message, (target_ip, target_port))
data, address = s.recvfrom(4096)
print(f"Received response from {address}")
s.close()

But when I try to modify that for IPv6 Hop Limit, I get a "Protocol not available" error.

import socket
import binascii
hop_limit=61
target_ip="2001:4860:4860::8888"
target_port=53
hexstream='a2d2012000010000000000010377777706676f6f676c6503636f6d00000100010000291000000000000000'
message=binascii.unhexlify(hexstream)
s = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
s.setsockopt(socket.SOL_IP, socket.IPV6_HOPLIMIT, hop_limit)
s.sendto(message, (target_ip, target_port))
data, address = s.recvfrom(4096)
print(f"Received response from {address}")
s.close()

Output:

>>> s.setsockopt(socket.SOL_IP, socket.IPV6_HOPLIMIT, hop_limit)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
OSError: [Errno 92] Protocol not available

Solution

  • The API for IPv6 is in many cases different to the IPv4 API. With IPv6 it is not possible to set the hoplimit once using setsockopt. Instead it needs to be sent for each individual datagram using sendmsg.

    import socket
    import struct
    
    hop_limit = 11
    msg = b"test"
    s = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
    
    s.sendmsg([msg],
        [(socket.IPPROTO_IPV6, socket.IPV6_HOPLIMIT, struct.pack("i",hop_limit))],
        0, ('::1',1234))
    

    To verify with tcpdump:

    $ sudo tcpdump -i lo -v port 1234
    ... IP6 (flowlabel 0xfc1e4, hlim 11, ...) ::1.51437 > ::1.1234: ... UDP, length 4
                                ^^^^^^^