Привязка IPv6-адреса к сокету Python в качестве исходного ip-адреса

ранее я использовал приведенный ниже код для привязки IPv4-адреса к сокету Python в качестве исходного ip-адреса.

import socket
true_socket = socket.socket
def bound_socket(*a, **k):
    sock = true_socket(*a, **k)
    sock.bind((sourceIP, 0))
    return sock
socket.socket = bound_socket

работает ли приведенный выше код для IPv6-адреса? Если нет, как я могу привязать IPv6-адрес?

спасибо заранее!

3 ответов


вы можете попробовать это, чтобы получить адрес IPV6, рекомендуется использовать socket.getaddrinfo он вернет все разные адреса как IPV4, так и IPV6, вы можете связать их все или только тот, который вам нужен/нужен.

import socket
def bound_socket(*a, **k):
    sock = socket.socket(*a, **k)
    if socket.AF_INET6 in a:
        if not socket.has_ipv6:
            raise ValueError("There's no support for IPV6!")
        else:
            address = [addr for addr in socket.getaddrinfo(source_ip, None)
                        if socket.AF_INET6 == addr[0]] # You ussually want the first one.
            if not address:
                raise ValueError("Couldn't find ipv6 address for source %s" % source_ip)
            sock.bind(address[0][-1])
    else:
        sock.bind((source_ip, 0))
    return sock

если вы действительно хотите обширное решение, вы можете расширить свое решение для использования getaddrinfo():

import socket
l = socket.getaddrinfo(None, "", 0, socket.SOCK_STREAM, 0, socket.AI_PASSIVE)
for i in l: print i

это дает

(2, 1, 6, '', ('0.0.0.0', 0))
(10, 1, 6, '', ('::', 0, 0, 0))

это параметры, которые вы должны создать сокет с:

s = socket.socket(i[0], i[1], i[2])
if i[0] == AF_INET6: s.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, 1)
s.bind(i[4])

теперь у вас есть столько сокетов, сколько у вас есть протоколов, и вы можете использовать их. (Увы,IPV6_V6ONLY не работает в старых версиях Windows...)

если у вас есть заданное имя хоста / IP для привязки, сделайте

l = socket.getaddrinfo("mylocalIP", None, 0, socket.SOCK_STREAM, 0, socket.AI_PASSIVE)

и это выберете правильный адрес / семейство протоколов для вас:

>>> socket.getaddrinfo("::1", None, 0, socket.SOCK_STREAM, 0, socket.AI_PASSIVE)
[(10, 1, 6, '', ('::1', 0, 0, 0))]
>>> socket.getaddrinfo("127.0.0.1", None, 0, socket.SOCK_STREAM, 0, socket.AI_PASSIVE)
[(2, 1, 6, '', ('127.0.0.1', 0))]
>>> socket.getaddrinfo("localhost", None, 0, socket.SOCK_STREAM, 0, socket.AI_PASSIVE)
[(10, 1, 6, '', ('::1', 0, 0, 0)), (2, 1, 6, '', ('127.0.0.1', 0))]
>>> socket.getaddrinfo("192.168.1.32", None, 0, socket.SOCK_STREAM, 0, socket.AI_PASSIVE)
[(2, 1, 6, '', ('192.168.1.32', 0))]

etc.

2 vs 10 are AF_INET и AF_INET6; socket.AI_PASSIVE означает, что вам нужен этот адрес для bind()ing.


это должно сделать трюк... установите семейство адресов.

import socket
s = socket.socket(family=socket.AF_INET6)
s.bind(('::1', 1234))