Есть ли простой способ отправить пакет по сырому сокету с использованием класса Ruby Socket?

77
9

В настоящее время я пытаюсь написать что-то в Ruby, который отправит данные по сырому сокету. Это может быть отчасти из-за некоторого шаткого понимания сокетов, но я чувствую, что ресурсы почти - но не совсем там.

В частности, я пытаюсь преобразовать следующий код Python (в случае, если это помогает):

#!/usr/bin/env python
from socket import socket, AF_PACKET, SOCK_RAW
s = socket(AF_PACKET, SOCK_RAW)
s.bind(("lo", 0))

geonet_frame = "\x00\x1f\xc6\x51\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\xc6
\x51\x07\x07\x07\x07\x07\x07\xef\x06\x07\x35\x97\x00\x24\x8c\x7a\xdf\x6f\x08
\x00\x45\x00\x00\x3d\xf3\x7f\x40\x00\x40\x11\x30\xc6\x0a\x01\x01\x68\x0a\x01
\x01\x01\x99\x80\x00\x35\x00\x29\x16\xa5\x01\x76\x01\x00\x00\xff\x00\x00\x01
\x00\x00\x00"

s.send(geonet_frame)

При поиске материала результаты, которые я вижу чаще всего, представляют собой этот вопрос с переполнением стека, который напрямую не дает никаких рабочих примеров кода, и это объяснение, которое, кажется, делает намного больше, чем мне нужно, а также, похоже, содержит файл, который я не могу доступ.

Я пробовал несколько вещей, перечисленных в документации для класса Socket, но я никогда не могу достичь таких же результатов, даже если я могу заставить его работать. Например, я могу попробовать:

soc = Socket.open(Socket::PF_INET, Socket::SOCK_RAW, Socket::IPPROTO_RAW)
soc.send(mypacket, 0, Socket.pack_sockaddr_in(0, "127.0.0.1"))

... и пока он завершится, он не даст желаемого результата (в этом случае он не создает DOS на TCPDump, как обозначено здесь, в то время как эквивалентный код Python).

Это сложнее в Ruby, чем я ожидаю? Или мне просто не хватает волшебной комбинации функций, которые позволили бы мне это сделать?

Обновление: вот изображение захвата нужного пакета.

http://i.imgur.com/BnO2fLd.png?1

спросил(а) 2021-01-25T17:29:34+03:00 4 месяца, 4 недели назад
1
Решение
89

Это сделает это:

require 'socket'

interface = 'lo' # loopback interface
interface_index = 0x8933 # SIOCGIFINDEX
geonet_frame = "\x00\x1f\xc6\x51\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\xc6\x51\x07\x07\x07\x07\x07\x07\xef\x06\x07\x35\x97\x00\x24\x8c\x7a\xdf\x6f\x08\x00\x45\x00\x00\x3d\xf3\x7f\x40\x00\x40\x11\x30\xc6\x0a\x01\x01\x68\x0a\x01\x01\x01\x99\x80\x00\x35\x00\x29\x16\xa5\x01\x76\x01\x00\x00\xff\x00\x00\x01\x00\x00\x00"

socket = Socket.new(Socket::AF_PACKET, Socket::SOCK_RAW, Socket::IPPROTO_RAW)
ifreq = [interface.dup].pack 'a32'
socket.ioctl(interface_index, ifreq)
socket.bind([Socket::AF_PACKET].pack('s') + [Socket::IPPROTO_RAW].pack('n') + ifreq[16..20]+ ("\x00" * 12))

socket.send(geonet_frame, 0)

Я использовал AF_PACKET потому что он соответствовал примеру python, но вы можете заменить его PF_PACKET если ваша система не поддерживает его.

Замена geonet_frame переменных Cocoabean предложили также работают:

geonet_frame = [ 0x00, 0x1f, 0xc6, 0x51, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0xc6, 0x51, 0x07, 0x07, 0x07, 0x07,0x07, 0x07, 0xef, 0x06, 0x07, 0x35, 0x97, 0x00, 0x24, 0x8c, 0x7a, 0xdf, 0x6f, 0x08, 0x00, 0x45, 0x00, 0x00, 0x3d, 0xf3, 0x7f, 0x40, 0x00, 0x40, 0x11, 0x30, 0xc6, 0x0a, 0x01, 0x01, 0x68, 0x0a, 0x01, 0x01, 0x01, 0x99, 0x80, 0x00, 0x35, 0x00, 0x29, 0x16, 0xa5, 0x01, 0x76, 0x01, 0x00, 0x00, 0xff, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00].pack("C*")

Протестировано с рубином 1.9.3p484 на CentOS 6.6. Надеюсь, поможет.

Приветствия.

ответил(а) 2021-01-25T17:29:34+03:00 4 месяца, 4 недели назад
45

Я думаю, вы правильно поняли, насколько это сокет, вы просто отправляете данные в неправильном формате. Python видит серию байтов, тогда как Ruby видит строку символов. Метод pack создаст строку из массива байтов.

http://www.ruby-doc.org/core-2.1.5/Array.html#method-i-pack

Попробуйте использовать это как значение для mypacket в вашей попытке примера:


    mypacket = [ 0x00, 0x1f, 0xc6, 0x51, 0x07, 0x07, 0x07, 
0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0xc6, 0x51, 0x07,
0x07, 0x07, 0x07, 0x07, 0x07, 0xef, 0x06, 0x07, 0x35, 0x97,
0x00, 0x24, 0x8c, 0x7a, 0xdf, 0x6f, 0x08, 0x00, 0x45, 0x00,
0x00, 0x3d, 0xf3, 0x7f, 0x40, 0x00, 0x40, 0x11, 0x30, 0xc6,
0x0a, 0x01, 0x01, 0x68, 0x0a, 0x01, 0x01, 0x01, 0x99, 0x80,
0x00, 0x35, 0x00, 0x29, 0x16, 0xa5, 0x01, 0x76, 0x01, 0x00,
0x00, 0xff, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00].pack("C*")

Самый простой способ отправить необработанные байтовые массивы с использованием Ruby's TCPSocket-Class

ответил(а) 2021-01-25T17:29:34+03:00 4 месяца, 4 недели назад
Ваш ответ
Введите минимум 50 символов
Чтобы , пожалуйста,
Выберите тему жалобы:

Другая проблема