有没有一种简单的方法使用Ruby的Socket类通过原始套接字发送数据包?

时间:2014-11-27 03:34:43

标签: ruby sockets translation

我目前正在尝试用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)

在搜索问题时,我最常看到的结果是this Stack Overflow question,它不会直接提供任何可行的代码示例,而this explanation似乎比我需要的更多,而且看起来似乎也是如此包含我无法访问的文件。

我已经尝试了documentation for the Socket class中列出的一些内容,但即使我能够使其工作,我也似乎无法达到相同的效果。例如,我可能会尝试:

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

...虽然它将完成,但它不会产生所需的结果(在这种情况下,它不会在TCPDump上创建DOS,如here所示,而等效的Python代码会)。

Ruby中的这个比我期待的更复杂吗?或者我只是缺少一些可以让我这样做的神奇功能组合?

更新:这是捕获所需数据包的图片。

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

2 个答案:

答案 0 :(得分:3)

这样做:

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

以Cocoabean建议替换geonet_frame变量也有效:

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*")

在CentOS 6.6上使用ruby 1.9.3p484进行测试。希望它有所帮助。

干杯。

答案 1 :(得分:0)

我认为你创建套接字是正确的,你只是以错误的格式发送数据。 Python看到一系列字节,而ruby看到一串字符。 pack方法将从字节数组中创建一个String。

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*")

simplest way to send raw Byte-arrays using Ruby's TCPSocket-Class