Ошибки Python raw IPv6 socket - PullRequest
       16

Ошибки Python raw IPv6 socket

1 голос
/ 20 октября 2010

У меня проблемы с использованием сырых сокетов 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._socket.sendall(data)
  File "<string>", line 1, in sendall
socket.error: [Errno 39] Destination address required

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

Ответы [ 3 ]

2 голосов
/ 20 ноября 2013

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

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

Необработанные сокеты не связаны и соединены с другими сокетами. Также sendto является правильным API для использования.

Кроме того, для пакетов ipv6 требуется 4 структуры кортежей для адреса назначения, а для ipv4 - две структуры кортежей.

Наконец, стек (по крайней мере в Linux mint 15) более строг в отношении пакетов ipv6. Если вы попытаетесь отправить пустой эхо-запрос icmpv4, python разрешит его и отправит пакет с меньшим значением по проводам. Где, как и в случае с ipv6, он просто выдает ошибку «неверный аргумент», когда вы пытаетесь отправить пустой пакет. Следовательно, действительный запрос также требуется в случае ipv6. Следующий пример делает все это для ipv6 и отправляет действительный запрос эхо-запроса на обратный адрес.

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')
0 голосов
/ 20 октября 2010

Этот код предоставляет необработанный сокет с доступом L2.К сожалению, OSX не поддерживает сокет. PF_PACKET ...

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

soc.send(packet)
0 голосов
/ 20 октября 2010

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

В любом случае, эквивалент IPAD6 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.

...