Python 原始 IPv6 套接字错误

发布于 2024-09-27 20:35:24 字数 934 浏览 1 评论 0原文

我在 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 本地主机地址作为 self._interface ("::1") 我实际上可以绑定该地址,但无法发送任何内容:

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

Why would a raw socket need a target address ?有没有人在 python 中使用过原始 IPv6 套接字,并且可以帮助我理解为什么会发生这种情况?

I am having some problems using raw IPv6 sockets in python. I connect via:

    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)

where self._interface is my local address; specifically "fe80::fa1e:dfff:fed6:221d". When trying this, I get the following error:

  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

If I use my ipv6 localhost address for self._interface ("::1") I can actually bind the address, but can not send anything:

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

Why would a raw socket need a destination address? Has anyone worked with raw IPv6 sockets in python, and can help me understand why this is happening?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

紫轩蝶泪 2024-10-04 20:35:24

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

关键问题是:

原始套接字未绑定并连接到其他套接字。另外,sendto 是要使用的正确 API。

此外,ipv6 数据包需要 4 个元组结构作为目标地址,而不是 ipv4 需要两个元组结构。

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

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')

Although this is an old question, i thought of adding an answer that works and helps any one who stumbles upon it latter.

The key problems are:

Raw sockets are not bound and connected to other sockets. Also sendto is the correct api to use.

Moreover, 4 tuple structure for destination address is required for ipv6 packets as opposed to two tuple ones for ipv4.

Lastly, the stack (at least on Linux mint 15) is more strict on ipv6 packets. If you try sending an empty icmpv4 echo request, python allows it and sends a meaning less packet on wire. Where as in case of ipv6, it simply gives error of 'invalid argument' when you try sending an empty packet. Hence a valid request is also required in case of ipv6. Following example does that all for ipv6 and sends a valid ping echo request to loop back address.

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')
泪之魂 2024-10-04 20:35:24

我不明白您的 bindsendall 组合。根据我的理解,bind 用于服务器套接字,sendall 需要连接。您是指connect 而不是bind 吗?

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

这对我有用(作为root):

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

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

I don't understand your combination of bind and sendall. In my understanding, bind is for server sockets and sendall requires a connection. Did you mean connect instead of bind?

Anyway, the IPv6 equivalent of INADDR_ANY is, according to the man page, IN6ADDR_ANY_INIT. Python does not define a constant for it, but this is the same as '::' (all zero).

This worked for me (as root):

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

EDIT:
Oops, I first did not saw that you actually managed to bind the socket to an address. However your second problem is obvious: You must first connect to some address before you can send data. Or use sendto with an address. This is not different from IPv4.

锦爱 2024-10-04 20:35:24

此代码提供了具有 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)

This code provides a raw socket with L2 access. Unfortunately OSX does not support the socket.PF_PACKET...

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

soc.send(packet)
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文