Необработанные ошибки сокета IPv6 Python

У меня возникли проблемы с использованием необработанных сокетов IPv6 в python. Подключаюсь через:

    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

Зачем необработанному сокету нужен адрес назначения? Кто-нибудь работал с необработанными сокетами IPv6 в python и может помочь мне понять, почему это происходит?


person wuntee    schedule 19.10.2010    source источник


Ответы (3)


Хотя это старый вопрос, я подумал добавить ответ, который работает и поможет любому, кто наткнется на него последним.

Ключевые проблемы:

Необработанные сокеты не связаны и не связаны с другими сокетами. Кроме того, 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')
person fkl    schedule 20.11.2013

Я не понимаю вашу комбинацию bind и sendall. Насколько я понимаю, bind предназначен для серверных сокетов, а sendall требует подключения. Вы имели в виду connect вместо bind?

Во всяком случае, IPv6-эквивалентом INADDR_ANY, согласно справочной странице, является IN6ADDR_ANY_INIT. Python не определяет для него константу, но это то же самое, что и '::' (все нули).

Это сработало для меня (как root):

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

EDIT: К сожалению, сначала я не увидел, что вам действительно удалось привязать сокет к адресу. Однако ваша вторая проблема очевидна: вы должны сначала подключиться к какому-то адресу, прежде чем сможете отправлять данные. Или используйте sendto с адресом. Это ничем не отличается от IPv4.

person Bernd Petersohn    schedule 20.10.2010
comment
Честно говоря, я следую классу сокетов Raw, созданному в среде фаззинга Peach (peachfuzz.svn.sourceforge.net/viewvc/peachfuzz/branches/). то, что я пытаюсь сделать, это создать произвольные пакеты (от IP-уровня и выше), чтобы фаззить ipv6... Connect, похоже, включает IP-уровень - я пытаюсь произвольно создать это. - person wuntee; 20.10.2010
comment
в порядке. возможно ли создать необработанный пакет и передать его по сети? - person wuntee; 20.10.2010
comment
@wuntee: я думаю, вы могли бы использовать sendto: docs.python.org/ библиотека/socket.html#socket.socket.sendto - person Bernd Petersohn; 20.10.2010
comment
@wuntee: вас также может заинтересовать stackoverflow .com/questions/1319261/ - person Bernd Petersohn; 20.10.2010
comment
Разве функция sendto не требует от вас определения адреса назначения - IP? если так, то я не смог бы определить уровень IP в пакете... - person wuntee; 20.10.2010
comment
@wuntee: я думаю, что если вы установите протокол IPPROTO_RAW, предполагается, что вы предоставите заголовок IP. См. lists.openwall.net/netdev/2009/01/15/168. - person Bernd Petersohn; 20.10.2010

Этот код предоставляет необработанный сокет с доступом 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)
person wuntee    schedule 20.10.2010