socket conneted using localhost but not 127.0.0.1 - ruby

i have the following code
require 'socket'
def connect(socket)
while line = socket.gets # Read lines from socket
puts line # and print them
end
socket.close # close socket when done
end
def serve(server)
loop do
client = server.accept # Wait for a client to connect
client.puts "Hello !"
client.puts "Time is #{Time.now}"
client.close
end
end
if ARGV[0] == "-s"
ip_port = ARGV[1]
server = TCPServer.new ip_port
serve(server)
elsif ARGV.length == 2
ip_address = ARGV[0]
ip_port = ARGV[1]
puts ip_address
puts ip_port
socket = TCPSocket.new ip_address , ip_port
connect(socket)
else
puts "PLease enter an IP address and IP port"
end
The code above is a basic server and client. use the -s flag to tell the program to act like a server.
This code works when I use localhost as a address but does not work when I use 127.0.0.1 as the address. I receive a No connection could be made because the target machine actively refused it. - connect(2) error when i use 127.0.0.1. was wondering if anyone knows what the problem is.

I don't think there's anything wrong with the code itself, this looks like more of an issue due to firewall settings or perhaps something else on the machine.
You could always try opening the port and then attempting to telnet into it from a different terminal telnet 127.0.0.1 port. You can also use netstat -atun to check if the port is indeed open and to which address it is bound (0.0.0.0 means accessible by all IP addresses).

Related

Connection won't raise error with bad host

The application I'm working on allows users to add additional connections to other databases through a UI. I'm simply trying to create a validation that ensures that a connection can be made.
I created a separate class to test the DB connections:
class StoredProcConnection < ActiveRecord::Base
def self.abstract_class?
true # So it gets its own connection
end
end
I then create the connection:
def connect
adapter = sql_server? ? 'mssql' : 'mysql2'
default_port = sql_server? ? '1443' : '3306'
#connection_pool = StoredProcConnection.establish_connection(
adapter: adapter,
username: username,
password: password,
host: host,
database: database_name,
port: port || default_port,
timeout: 300)
end
def connection_pool
connect unless #connection_pool
#connection_pool
end
Then I validate it with this method:
def connection_test
if connection_pool.connection
#remove the connection from the StoredProcConnection pool
connection_pool.remove(connection_pool.connection)
return true
else
return false
end
rescue Exception => error
logger.info "unable to create connection with connection.id = #{id} - #{error}"
return false
end
Unfortunately, when it gets to this line with a bad host address like 127.0.0.abcdefg or 666.666.666.666
if connection_pool.connect
The app gets stuck, no errors raised or anything. It just freezes and I have to shut down the server manually.
I have a workaround but it feels quite sloppy. I am just inserting my own timeout in there, but I feel like Active Record should be throwing some kind of error.
def connection_test
Timeout::timeout(3) {
if connection_pool.connection
#remove the connection from the StoredProcConnection pool
connection_pool.remove(connection_pool.connection)
return true
else
return false
end
}
rescue Exception => error
logger.info "unable to create connection with connection.id = #{id} - #{error}"
return false
end
Does anyone see anything that might be causing the freeze? It seems pretty straight forward to me. I'm not sure why the connection pool is even created in the first place with a bad host passed in.
It just freezes...
Odds are good it's not frozen, it's just waiting to see if that connection can be made. TCP/IP has a long timeout value, which fools people into thinking things are frozen, when actually it's being patient.
Few people really understand how the internet works, and how it's really a house built of straw that we try to keep running no matter what. Long IP timeouts are one of the ways that we try to make it self-healing. Software doesn't care about how long something takes, only people care.
Since it appears you're concerned about malformed IP addresses, why aren't you pre-testing them to make sure they're at least in a valid format?
Use Ruby's built-in IPAddr class and try to parse them:
require 'ipaddr'
%w[
127.0.0.abcdefg
666.666.666.666
127.0.0.1
192.168.0.1
255.255.255.255
].each do |ip|
begin
IPAddr.new ip
puts "Good: #{ ip }"
rescue IPAddr::InvalidAddressError => e
puts "#{ e }: #{ ip }"
end
end
# >> invalid address: 127.0.0.abcdefg
# >> invalid address: 666.666.666.666
# >> Good: 127.0.0.1
# >> Good: 192.168.0.1
# >> Good: 255.255.255.255
For "fun reading" there's "TCP Timeout and Retransmission" and "TCP Socket no connection timeout".

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

Ruby hide exception output in script

I have the following code:
#!/usr/bin/ruby
require 'socket'
server = '221.186.184.68'
if ( server =~ /^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/ )
hostname = Socket.gethostbyaddr(server.split(".").map(&:to_i).pack("CCCC")).first
puts hostname
end
All well, but when I input an IP Address that doesn't reverse I get exeception error:
i.rb:8:in `gethostbyaddr': host not found (SocketError)
from i.rb:8
How can I hide the message? Thanks!
use exception handling
#!/usr/bin/ruby
require 'socket'
server = '221.186.184.68'
begin
if ( server =~ /^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/ )
hostname = Socket.gethostbyaddr(server.split(".").map(&:to_i).pack("CCCC")).first
puts hostname
end
rescue => err
#puts "I don't want to print this #{err.message}. Hence commented"
end

Ruby IO from a service at port 6557 in Sinatra

I have to take a dump of a service in sinatra and display it in the content area of the webpage.
The Service I have to access via code runs on server at port 6557. It doesnt use any encryption or authentication. Its a plain readonly request response thingy like http.
Here is what works in teminal
$ echo "GET hosts" | nc 192.168.1.1 6557
gives me the intended output. I need to do something similar using the sinatra application.
I wrote this code but is grossly incorrect. Can sombody help me with code or lookup materials or examples.
get '/' do
host = "192.168.1.1"
port = 6557
dat = ""
#socket = TCPSocket.open (host, port)
while(true)
if(IO.select([],[],[#socket],0))
socket.close
return
end
begin
while( (data = #socket.recv_nonblock(100)) != "")
dat = dat+ data
end
rescue Errno::EAGAIN
end
begin
#str = "GET hosts"
#socket.puts(#str);
rescue Errno::EAGAIN
rescue EOFError
exit
end
IO.select([#socket], [#socket], [#socket])
end
#line = dat
erb :info
end
The code on execution just hangs up.
Also if possible please give some links to read up to get a conceptual context of the problem.
I think the Ruby equivalent to your shell command should be as simple as:
require "socket"
socket = TCPSocket.new "192.168.1.1", 6557
socket.puts "GET hosts"
socket.read
According to the docs, #read should close the socket automatically, so you don't need to worry about doing that manually.
You can execute shell commands directly from ruby using backticks or the system command. Something like this may work for you:
get "/" do
#line = `echo "GET hosts" | nc 192.168.1.1 6557`
erb :info
end
Check out the ruby docs for Kernel#system for more info.

Reject Non-localhost Attempts to Access Webrick

I'm trying to block all non-localhost attempts to access a Webrick process. This is my current code
def do_GET(req, res)
host_name = "localhost:3344".split(":")[0]
if host_name != "localhost" && host_name != "127.0.0.1"
puts "Security alert, accessing through #{host_name}"
return
else
puts "we're fine, #{host_name}"
end
# etc.
Is this easy to break? My thought is that the hostname is hard to spoof to the webserver itself.
Maybe just bind the server to the localhost ip address 127.0.0.1 and then you wont have to worry about non-localhost connections:
s = WEBrick::HTTPServer.new( :Port => 3344, :BindAddress => "127.0.0.1" )
s.start
(the above code is off the top of my head but im sure you get the idea)

Resources