1

我在 python 中使用原始 IPv6 套接字时遇到了一些问题。我通过以下方式连接:

    if self._socket != None:
        # Close out old socket first
        self._socket.close()
    self._socket = socket.socket(socket.AF_INET6, socket.SOCK_RAW)
    self._socket.bind((self._interface,0))
    self._socket.sendall(data)

其中 self._interface 是我的本地地址;特别是“fe80::fa1e:dfff:fed6:221d”。尝试此操作时,我收到以下错误:

  File "raw.py", line 164, in connect
    self._socket.bind((self._interface,0))
  File "<string>", line 1, in bind
socket.error: [Errno 49] Can't assign requested address

如果我使用我的 ipv6 localhost 地址作为 self._interface ("::1") 我实际上可以绑定地址,但不能发送任何东西:

    self._socket.sendall(data)
  File "<string>", line 1, in sendall
socket.error: [Errno 39] Destination address required

为什么原始套接字需要目标地址?有没有人在 python 中使用原始 IPv6 套接字,并且可以帮助我理解为什么会这样?

4

3 回答 3

2

虽然这是一个老问题,但我想添加一个有效的答案,并帮助任何后来偶然发现它的人。

关键问题是:

原始套接字未绑定并连接到其他套接字。sendto也是要使用的正确 api。

此外,ipv6 数据包需要 4 个用于目标地址的元组结构,而 ipv4 需要两个元组结构。

最后,堆栈(至少在 Linux mint 15 上)对 ipv6 数据包更加严格。如果您尝试发送一个空的 icmpv4 回显请求,python 会允许它并在线发送一个意义较小的数据包。在 ipv6 的情况下,当您尝试发送空数据包时,它只会给出“无效参数”的错误。因此,在 ipv6 的情况下也需要有效的请求。以下示例针对 ipv6 执行所有操作,并向环回地址发送有效的 ping 回显请求。

import socket

def main(dest_name):
    addrs = socket.getaddrinfo(dest_name, 0, socket.AF_INET6, 0, socket.SOL_IP)


    print addrs
    dest = addrs[0]

    # A minimal ICMP6-echo message (thanks to abarnert)
    data = '\x80\0\0\0\0\0\0\0'

    icmp = socket.getprotobyname('ipv6-icmp')
    #print icmp

    send_socket = socket.socket(socket.AF_INET6, socket.SOCK_RAW, icmp)
    print "sent to " + str(dest[4])
    send_socket.sendto(data, dest[4])
    send_socket.close()

if __name__ == '__main__':
    main('::1')
于 2013-11-20T07:48:51.417 回答
0

此代码提供了一个具有 L2 访问权限的原始套接字。不幸的是 OSX 不支持 socket.PF_PACKET ...

soc = socket.socket(socket.PF_PACKET, socket.SOCK_RAW) #create the raw-socket
soc.bind(("lo0", 0))

soc.send(packet)
于 2010-10-20T01:56:11.593 回答
0

我不明白你的bindand组合sendall。据我了解,bind用于服务器套接字并且sendall需要连接。你的意思是connect代替bind吗?

无论如何,根据手册页,INADDR_ANY 的 IPv6 等效项是 IN6ADDR_ANY_INIT。Python 没有为它定义一个常量,但这与'::'(全为零)相同。

这对我有用(作为根):

>>> import socket
>>> s = socket.socket(socket.AF_INET6, socket.SOCK_RAW, socket.IPPROTO_RAW)
>>> s.bind(('::', 0))

编辑: 哎呀,我第一次没有看到您实际上设法将套接字绑定到一个地址。但是,您的第二个问题很明显:您必须先连接到某个地址,然后才能发送数据。或sendto与地址一起使用。这与 IPv4 没有什么不同。

于 2010-10-20T00:33:27.690 回答