Ruby SCGI/XMLRPC client - ruby

How is it possible to talk directly to the rtorrent via scgi interface? Ruby's XMLRPC client from stdlib can communicate only over HTTP protocol and rtorrent is only SCGI capable.

as a starter:
#!ruby
require "xmlrpc/client"
class XMLRPC::RTorrent < XMLRPC::Client
def do_rpc(xml, async=false)
headers = {
'CONTENT_LENGTH' => xml.size,
'SCGI' => 1
}
header = "#{headers.to_a.flatten.join("\x00")}"
request = "#{header.size}:#{header},#{xml}"
TCPSocket.open(#host, #port) do |s|
s.write(request)
s.read.split(/\n\s*?\n/, 2)[1]
end
end
end
server = XMLRPC::RTorrent.new("127.0.0.1", '', 5000)
p server.call("system.listMethods")
it ignores async, rtorrent rpc is on port 5000.
more details: http://python.ca/scgi/protocol.txt

Related

How to connect to FTP via SOCKS5 proxy with Ruby?

I'm trying to connect to FTP via SOCKS5 proxy using ruby's library Net::FTP. Documentation says to set env variable SOCKS_SERVER in order to connect through proxy (http://ruby-doc.org/stdlib-2.0.0/libdoc/net/ftp/rdoc/Net/FTP.html#method-i-connect), but it seems like it does not work.
Code I'm running is this:
irb(main):054:0> ftp = Net::FTP.new
=> #<Net::FTP:0x007efd08c73768 #mon_owner=nil, #mon_count=0, #mon_mutex=#<Thread::Mutex:0x007efd08c73718>, #binary=true, #passive=true, #debug_mode=false, #resume=false, #sock=#<Net::FTP::NullSocket:0x007efd08c736f0>, #logged_in=false, #open_timeout=nil, #read_timeout=60>
irb(main):056:0> ENV['SOCKS_SERVER'] = 'host:port'
=> "host:port"
irb(main):055:0> ftp.connect('test.rebex.net')
=> nil
irb(main):057:0> ftp.login('demo', 'password')
=> true
irb(main):058:0> ftp.ls
=> ["10-27-15 03:46PM <DIR> pub", "04-08-14 03:09PM 403 readme.txt"]
When I look to proxy logs I can not see any requests going through.
What I'm doing wrong or does anybody have an example how to achieve that?
If your on Windows computer you'll need to use dress_socks gem and Monkeypath:
$socks_server = '127.0.0.1'
$socks_port = '9090'
require 'dress_socks'
class Net::FTP
def open_socket(host, port) # :nodoc:
# puts "opening socket #{#host}:#{port}"
return DressSocks::Socket.new(#host, port,
socks_server: $socks_server, socks_port: $socks_port)
end
end

Ruby HTTP2 GET request

I'm trying to use the Ruby gem http-2 to send a GET request to Google.
I've lifted the code directly from the example and simplified it slightly:
require 'http/2'
require 'socket'
require 'openssl'
require 'uri'
uri = URI.parse('http://www.google.com/')
tcp = TCPSocket.new(uri.host, uri.port)
sock = tcp
conn = HTTP2::Client.new
conn.on(:frame) do |bytes|
# puts "Sending bytes: #{bytes.unpack("H*").first}"
sock.print bytes
sock.flush
end
conn.on(:frame_sent) do |frame|
puts "Sent frame: #{frame.inspect}"
end
conn.on(:frame_received) do |frame|
puts "Received frame: #{frame.inspect}"
end
stream = conn.new_stream
stream.on(:close) do
puts 'stream closed'
sock.close
end
stream.on(:half_close) do
puts 'closing client-end of the stream'
end
stream.on(:headers) do |h|
puts "response headers: #{h}"
end
stream.on(:data) do |d|
puts "response data chunk: <<#{d}>>"
end
head = {
':scheme' => uri.scheme,
':method' => 'GET',
':path' => uri.path
}
puts 'Sending HTTP 2.0 request'
stream.headers(head, end_stream: true)
while !sock.closed? && !sock.eof?
data = sock.read_nonblock(1024)
# puts "Received bytes: #{data.unpack("H*").first}"
begin
conn << data
rescue => e
puts "#{e.class} exception: #{e.message} - closing socket."
e.backtrace.each { |l| puts "\t" + l }
sock.close
end
end
The output is:
Sending HTTP 2.0 request
Sent frame: {:type=>:settings, :stream=>0, :payload=>[[:settings_max_concurrent_streams, 100]]}
Sent frame: {:type=>:headers, :flags=>[:end_headers, :end_stream], :payload=>[[":scheme", "http"], [":method", "GET"], [":path", "/"]], :stream=>1}
closing client-end of the stream
(Note: you get pretty much the same output as above by running the actual example file, i.e., ruby client.rb http://www.google.com/)
Why is no response data being displayed?
Public servers like google.com do not support HTTP/2 in clear text.
You are trying to connect to http://google.com, while you should really connect to https://google.com (note the https scheme).
In order to do that, you may need to wrap the TCP socket using TLS (see for example here), if http-2 does not do it for you.
Note also that HTTP/2 requires strong TLS ciphers and ALPN, so make sure that you have an updated version of OpenSSL (at least 1.0.2).
Given that the author of http-2 is a strong HTTP/2 supporter, I am guessing that your only problem is the fact that you tried clear-text http rather than https, and I expect that TLS cipher strength and ALPN are taken care of by the http-2 library.

Ruby send and receive custom TCP packets using PacketFu

I have a server running on port 3000 and a simple ruby program that reads lines from the server
require 'socket'
require 'packetfu'
s = TCPSocket.open('localhost', 3000)
config = PacketFu::Config.new(:iface=> "wlan0").config
pkt = PacketFu::TCPPacket.new(:config => $config , :flavor => "Linux")
while line = s.gets
puts line.chop
end
s.close
Server
require 'socket'
server = TCPServer.open('localhost', 3000)
loop {
client = server.accept
client.close
}
I want to build a simple TCP packet using packetfu that sends a WAKE-UP call and receive ACK from the server. What changes should i make to build this packet and receive the response?

How to capture POST data from a simple Ruby server

I have a basic Ruby server that I'd like to listen to a specific port, read incoming POST data and do blah...
I have this:
require 'socket' # Get sockets from stdlib
server = TCPServer.open(2000) # Socket to listen on port 2000
loop { # Servers run forever
client = server.accept # Wait for a client to connect
client.puts(Time.now.ctime) # Send the time to the client
client.puts "Closing the connection. Bye!"
client.close # Disconnect from the client
}
How would I go about capturing the POST data?
Thanks for any help.
It's possible to do this without adding much to your server:
require 'socket' # Get sockets from stdlib
server = TCPServer.open(2000) # Socket to listen on port 2000
loop { # Servers run forever
client = server.accept # Wait for a client to connect
method, path = client.gets.split # In this case, method = "POST" and path = "/"
headers = {}
while line = client.gets.split(' ', 2) # Collect HTTP headers
break if line[0] == "" # Blank line means no more headers
headers[line[0].chop] = line[1].strip # Hash headers by type
end
data = client.read(headers["Content-Length"].to_i) # Read the POST data as specified in the header
puts data # Do what you want with the POST data
client.puts(Time.now.ctime) # Send the time to the client
client.puts "Closing the connection. Bye!"
client.close # Disconnect from the client
}
For really simple apps you probably want to write something using Sinatra which is about as basic as you can get.
post('/') do
# Do stuff with post data stored in params
puts params[:example]
end
Then you can stick this in a Rack script, config.ru, and host it easily using any Rack-compliant server.
client.read(length) # length is length of request header content

savon ruby best practices - global client or one per request?

I have Savon working in a Sinatra ruby application. The application will be called frequently, and I don't want to lean on the server too much.
It looks to me that everytime the /test_savon GET is hit, I am going to the server and asking for the wdsl again. I would only need to do that once, it would seem.
Should I make a few clients as ruby globals (one for each wsdl) and use them repeatedly?
Here is my code which works: NTLM auth - talking to a MS DynamicsNav Server
get '/test_savon' do
# create a client for the service
client = Savon.client(wsdl: 'http://somedynamicsnavserver:7047/WS/Page/Salesperson', ntlm: ["username", "password"]) do
convert_request_keys_to :camelcase
end
operations = client.operations
puts "operations are #{operations.to_s}" if operations
puts "checked operations" if operations
# => [:find_user, :list_users]
# call the 'findUser' operation
response = client.call(:read, message: { code: 'salepersonIDhere' })
puts "response is #{response.to_s}" if response
response.body.to_s
# => {:read_result=>{:salesperson=>{:key=>"aKey", :code=>"salepersonIDhere", :name=>"Jim Kirk", :global_code=>"X", :phone_no=>"4407"}, :#xmlns=>"urn:microsoft-dynamics-schemas/page/salesperson"}}
end
I usually don't use a WSDL at all but work without it. That should be much faster because you should have less roundtrips.
A small example:
#!ruby
gem "savon", "~>2.0"
require 'savon'
stock_handle = ARGV[0] || 'OTEX'
client = Savon.client(
endpoint: 'http://www.webservicex.net/stockquote.asmx',
namespace: 'http://www.webserviceX.NET/',
convert_request_keys_to: :camelcase, # :camelcase, :upcase, :none
log: true,
log_level: :debug,
pretty_print_xml: true
)
response = client.call(
:get_quote,
soap_action: 'http://www.webserviceX.NET/GetQuote',
message: { "wsdl:symbol" => stock_handle}
)
print response.to_hash

Resources