【问题标题】:Is there a simple way to send a packet over a raw socket using Ruby's Socket class?有没有一种简单的方法可以使用 Ruby 的 Socket 类通过原始套接字发送数据包?
【发布时间】:2014-12-04 15:06:14
【问题描述】:

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

【问题讨论】:

    标签: ruby sockets translation


    【解决方案1】:

    这样就可以了:

    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 进行测试。希望对您有所帮助。

    干杯。

    【讨论】:

    • 成功了!太感谢了!或者,如果您有机会,我想请您详细说明错误之处以及这些更改产生正确结果的原因。
    【解决方案2】:

    我认为就创建套接字而言你做对了,你只是以错误的格式发送数据。 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*")
    

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

    【讨论】:

    • 很遗憾,这不会产生正确的数据包。我将使用捕获正确数据包的图片来更新问题。为了比较,这里是我/你的代码产生的结果:i.imgur.com/76K8bWs.png?1
    • 我认为发布正确的数据包会有很大帮助。
    • 抓包是关于除上述评论之外的主要问题。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-06-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-03-10
    相关资源
    最近更新 更多