2010-10-19 5 views
1

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

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 и может помочь мне понять, почему это происходит?

ответ

0

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

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

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

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

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

+0

Честно говоря, я после Сырого класса сокета, созданный в рамках Fuzzing Peach (http://peachfuzz.svn.sourceforge.net/viewvc/peachfuzz/branches/Peach2.3/Peach/Publishers/raw. ру?Пересмотр = & вид тысяча четыреста сорок-семь = разметка). то, что я пытаюсь сделать, это создать произвольные пакеты (от уровня IP и выше), чтобы fuzz ipv6 ... Подключение, кажется, включает в себя уровень IP - я пытаюсь произвольно создать это. – wuntee

+0

ОК. возможно ли создать необработанный пакет и поместить его на провод? – wuntee

+0

@wuntee: Я думаю, вы могли бы использовать 'sendto': http://docs.python.org/library/socket.html#socket.socket.sendto –

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

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

Основными проблемами являются:

Сырые сокеты не связаны и соединены с другими сокетов. Также sendto - правильный api для использования.

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

Наконец, стек (по крайней мере, на Linux mint 15) более строг на пакетах ipv6. Если вы попытаетесь отправить пустой echo-запрос 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')