How does Ruby manage localhost communications via TCP under Windows 7? - ruby

I am trying to implement a simple local TCP communication between a Ruby server and a C++ library interfaced to Unreal Engine 4.
I have used some sample code for the ruby server, which uses the socket library and instanciates a TCPServer:
require 'socket'
puts "Starting up server..."
# establish the server
## Server established to listen for connections on port 2008
server = TCPServer.new(15300)
# setup to listen and accept connections
while (session = server.accept)
#start new thread conversation
## Here we will establish a new thread for a connection client
Thread.start do
## I want to be sure to output something on the server side
## to show that there has been a connection
puts "log: Connection from #{session.peeraddr[2]} at
#{session.peeraddr[3]}"
puts "log: got input from client"
## lets see what the client has to say by grabbing the input
## then display it. Please note that the session.gets will look
## for an end of line character "\n" before moving forward.
input = session.gets
puts input
## Lets respond with a nice warm welcome message
session.puts "Server: Welcome #{session.peeraddr[2]}\n"
# reply with goodbye
## now lets end the session since all we wanted to do is
## acknowledge the client
puts "log: sending goodbye"
session.puts "Server: Goodbye\n"
end #end thread conversation
end #end loop
This application, if tested with a ruby client, works perfectly fine.
This is the client:
require 'socket'
# establish connection
## We need to tell the client where to connect
## Conveniently it is on localhost at port 15300!
clientSession = TCPSocket.new( "localhost", 15300 )
puts "log: starting connection"
#send a quick message
## Note that this has a carriage return. Remember our server
## uses the method gets() to get input back from the server.
puts "log: saying hello"
clientSession.puts "Client: Hello Server World!\n"
#wait for messages from the server
## You've sent your message, now we need to make sure
## the session isn't closed, spit out any messages the server
## has to say, and check to see if any of those messages
## contain 'Goodbye'. If they do we can close the connection
while !(clientSession.closed?) &&
(serverMessage = clientSession.gets)
## lets output our server messages
puts serverMessage
#if one of the messages contains 'Goodbye' we'll disconnect
## we disconnect by 'closing' the session.
if serverMessage.include?("Goodbye")
puts "log: closing connection"
clientSession.close
end
end #end loop
Server output:
Starting up server...
log: Connection from ::1 at
::1
log: got input from client
Client: Hello Server World!
log: sending goodbye
But when I try to connect to the server using C++11 and the TCP functions in Unreal Engine 4 I do not get any kind of response from the server implemented in ruby (not even "Connection from...").
To understand what was the problem I tried to run some netwrok analysis, starting from the simplest (Window's Resource Monitor), to the most complex (ZenMap). In no case there was a single service running with the selected port open (port 15300). I have double checked every single possible cause for this (e.g. firewall, other security software) but there was no block to the ruby interpreter.
In order to understand why such a simple application is not working I started using Wireshark. It was then that I noticed that there is no local loopback interface, which required me to use RawCap (wich manages to capture the local communications and dump them on file). Using it I managed to dump the local communications on my machine during both a run of the ruby client/server pair and Cygwin Socat/Unreal Engine 4. What I found was pretty baffling: there were NO open local TCP sockets on the port for the ruby pair (port 15300), but the TCP ports opened by Unreal Engine 4 were there (along with port 15301, the one I used for the tests).
Update 01
I have changed the code in my Unreal Engine 4 application, as the first version used an included TCPsocket builder which used bind by default instead of connect. Now the code is:
bool UNetworkBlueprintLibrary::NetworkSetup(int32 ServerPort) {
bool res = false;
// Creating a Socket pointer, wich will temporary contain our
FSocket* Socket = nullptr;
ISocketSubsystem* SocketSubsystem = ISocketSubsystem::Get(PLATFORM_SOCKETSUBSYSTEM);
// Instead of that useless FTcpSocketBuilder I will try to create the socket by hand and then debug it... >:(
if (SocketSubsystem != nullptr) {
// Try to create a stream socket using the system-intependent interface
Socket = SocketSubsystem->CreateSocket(NAME_Stream, TEXT("Server Socket"), false);
if (Socket != nullptr) {
FIPv4Address ServerAddress = FIPv4Address(127, 0, 0, 1);
TSharedRef<FInternetAddr> LocalAddress = ISocketSubsystem::Get(PLATFORM_SOCKETSUBSYSTEM)->CreateInternetAddr();
uint16 castServerPort = (uint16)ServerPort;
// Attach received port and IPAddress to Internet Address pointer
LocalAddress->SetIp(ServerAddress.GetValue());
LocalAddress->SetPort(castServerPort);
bool SocketCreationError = !Socket->Connect(*LocalAddress);
if (SocketCreationError)
{
GLog->Logf(TEXT("Failed to create Server Socket as configured!"));
SocketSubsystem->DestroySocket(Socket);
Socket = nullptr;
}
}
}
if (Socket != nullptr){
UNetworkBlueprintLibrary::ServerSocket = Socket;
res = true;
}
else {
res = false;
}
return res;
}
In order to test whether the code in Unreal Engine 4 is working or not I have used socat under Cygwin:
socat tcp-listen:15300 readline
Once my Unreal Engine 4 application starts I can send data over the socket. I have confirmed this works, removing the possibility that my application developed in Unreal Engine 4 was not communicating through the TCP socket.
Given this positive result I have tried again to use the server code reported on top of this question, removing the lines that wait for a message from the client but the result is the same: the server does not even output the debug lines it should print when there is a connection:
puts "log: Connection from #{session.peeraddr[2]} at #{session.peeraddr[3]}"
Update 02
Back once again!
I have managed to make ruby and Unreal Engine 4 communicate through local TCP sockets. What I needed to make the ruby server work was explicitly providing the local address, like so:
server = TCPServer.new("127.0.0.1", 15300)
However, even if this matter is solved, I am still interested in some of the questions I put the first time.
Update 03
Just one consideration that I made in the last hour.
When I did not provide an explicit server address the server, this command
puts "log: Connection from #{session.peeraddr[2]} at
#{session.peeraddr[3]}"
Returned
log: Connection from ::1 at
::1
Which is indeed correct! ::1 is the IPv6 version of 127.0.0.1, so it looks like that ruby assumes that it has to create an IPv6 socket, instead of an IPv4. Unreal Engine 4 does not provide an IPv6 interface, so this might have been the reason why the application did not work.
Now communications over localhost when dumped, show the following communications over port 15300:
No. Time Source Destination Protocol Length Info
105 7.573433 127.0.0.1 127.0.0.1 TCP 52 9994→15300 [SYN] Seq=0 Win=8192 Len=0 MSS=65495 WS=256 SACK_PERM=1
106 7.573433 127.0.0.1 127.0.0.1 TCP 52 15300→9994 [SYN, ACK] Seq=0 Ack=1 Win=8192 Len=0 MSS=65495 WS=256 SACK_PERM=1
107 7.573433 127.0.0.1 127.0.0.1 TCP 40 9994→15300 [ACK] Seq=1 Ack=1 Win=8192 Len=0
108 7.583434 127.0.0.1 127.0.0.1 TCP 66 15300→9994 [PSH, ACK] Seq=1 Ack=1 Win=8192 Len=26
109 7.583434 127.0.0.1 127.0.0.1 TCP 40 9994→15300 [ACK] Seq=1 Ack=27 Win=7936 Len=0
110 7.583434 127.0.0.1 127.0.0.1 TCP 56 15300→9994 [PSH, ACK] Seq=27 Ack=1 Win=8192 Len=16
111 7.583434 127.0.0.1 127.0.0.1 TCP 40 9994→15300 [ACK] Seq=1 Ack=43 Win=7936 Len=0
208 16.450941 127.0.0.1 127.0.0.1 TCP 52 9995→15300 [SYN] Seq=0 Win=8192 Len=0 MSS=65495 WS=256 SACK_PERM=1
209 16.451941 127.0.0.1 127.0.0.1 TCP 52 15300→9995 [SYN, ACK] Seq=0 Ack=1 Win=8192 Len=0 MSS=65495 WS=256 SACK_PERM=1
210 16.451941 127.0.0.1 127.0.0.1 TCP 40 9995→15300 [ACK] Seq=1 Ack=1 Win=8192 Len=0
211 16.456941 127.0.0.1 127.0.0.1 TCP 66 15300→9995 [PSH, ACK] Seq=1 Ack=1 Win=8192 Len=26
212 16.456941 127.0.0.1 127.0.0.1 TCP 40 9995→15300 [ACK] Seq=1 Ack=27 Win=7936 Len=0
213 16.456941 127.0.0.1 127.0.0.1 TCP 56 15300→9995 [PSH, ACK] Seq=27 Ack=1 Win=8192 Len=16
214 16.456941 127.0.0.1 127.0.0.1 TCP 40 9995→15300 [ACK] Seq=1 Ack=43 Win=7936 Len=0
When a packages show a LEN of either 26 or 16 means that they are sending either
Server: Welcome 127.0.0.1.
or
Server: Goodbye.
I just wanted to share this information, as it is not really useful for the answer, but shows how IPv6 communications do not pass through the standard localhost virtual adapter.
The questions
What I would like to understand is:
As there is no local loopback interface how does ruby communicate through local TCP sockets?

Related

Pinging local host doesn't function

elasticsearch==7.10.0
I wish to ping local host '5601' to ensure kibana is running or not but apparently unable to ping.
Note: I am aware that elastic search has in-built function to ping but I still wish to ping using cmd line for a specific reason in my project.
C:\User>ping 5601
Pinging f00:b00:f00:b00 with 32 bytes of data:
PING: transmit failed. General failure.
PING: transmit failed. General failure.
PING: transmit failed. General failure.
PING: transmit failed. General failure.
Ping statistics for f00:b00:f00:b00:
Packets: Sent = 4, Received = 0, Lost = 4 (100% loss)
C:\User>ping http://localhost:5601
Ping request could not find host http://localhost:5601. Please check the name and try again.
Could someone help me?
You can use netstat to check if the port exposed by the Kibana UI, 5061 is in LISTEN mode
$ netstat -tlpn | grep 5601
(Not all processes could be identified, non-owned process info
will not be shown, you would have to be root to see it all.)
tcp6 0 0 :::5601 :::* LISTEN -
Or if you want to establish a connection to destination port 5601 you can use nc
$ nc -vz localhost 5601
Connection to localhost 5601 port [tcp/*] succeeded!

Unable to bind any program to IPv4 TCP port 80 on Mac [duplicate]

I have the following very simple docker-compose.yml, running on a Mac:
version: "3.7"
services:
apache:
image: httpd:2.4.41
ports:
- 80:80
I run docker-compose up, then I run this curl and Apache returns content:
/tmp/test $ curl -v http://localhost
* Trying ::1:80...
* TCP_NODELAY set
* Connected to localhost (::1) port 80 (#0)
> GET / HTTP/1.1
> Host: localhost
> User-Agent: curl/7.66.0
> Accept: */*
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< Date: Sat, 26 Oct 2019 18:30:03 GMT
< Server: Apache/2.4.41 (Unix)
< Last-Modified: Mon, 11 Jun 2007 18:53:14 GMT
< ETag: "2d-432a5e4a73a80"
< Accept-Ranges: bytes
< Content-Length: 45
< Content-Type: text/html
<
<html><body><h1>It works!</h1></body></html>
* Connection #0 to host localhost left intact
However, if I try to access the container using 127.0.0.1 instead of localhost, I get connection refused:
/tmp/test $ curl -v http://127.0.0.1
* Trying 127.0.0.1:80...
* TCP_NODELAY set
* Connection failed
* connect to 127.0.0.1 port 80 failed: Connection refused
* Failed to connect to 127.0.0.1 port 80: Connection refused
* Closing connection 0
curl: (7) Failed to connect to 127.0.0.1 port 80: Connection refused
Localhost does point to 127.0.0.1:
/tmp/test $ ping localhost
PING localhost (127.0.0.1): 56 data bytes
And netstat shows all local IP addresses port 80 to be forwarded:
/tmp/test $ netstat -tna | grep 80
...
tcp46 0 0 *.80 *.* LISTEN
...
I came to this actually trying to access the container using a custom domain I had on my /etc/hosts file pointing to 127.0.0.1. I thought there was something wrong with that domain name, but then I tried 127.0.0.1 and didn't work either, so I'm concluding there is something very basic about docker I'm not doing right.
Why is curl http://localhost working but curl http://127.0.0.1 is not?
UPDATE
It seems localhost is resolving to IPv6 ::1, so port forwarding seems to be working on IPv6 but not IPv4 addresses. Does that make any sense?
UPDATE 2
I wasn't able to fix it, but pointing my domain name to ::1 instead of 127.0.0.1 in my /etc/hosts serves as a workaround for the time being.
UPDATE 3
8 months later I bumped into the same issue and found my own question here, still unanswered. But this time I can't apply the same workaround, because I need to bind the port forwarding to my IPv4 address so it can be accessed from other hosts.
Found the culprit: pfctl
AFAIK, pfctl is not supposed to run automatically but my /System/Library/LaunchDaemons/com.apple.pfctl.plist said otherwise.
The Packet Filtering was configured to redirect all incoming traffic on port 80 to 8080, and 443 to 8443. And this is done without any process actually listening to port 80 and 443, that's why lsof and netstat wouldn't show anything,.
/Library/LaunchDaemons/it.winged.httpdfwd.plist has the following
<key>ProgramArguments</key>
<array>
<string>sh</string>
<string>-c</string>
<string>echo "rdr pass proto tcp from any to any port {80,8080} -> 127.0.0.1 port 8080" | pfctl -a "com.apple/260.HttpFwdFirewall" -Ef - && echo "rdr pass proto tcp from any to any port {443,8443} -> 127.0.0.1 port 8443" | pfctl -a "com.apple/261.HttpFwdFirewall" -Ef - && sysctl -w net.inet.ip.forwarding=1</string>
</array>
<key>RunAtLoad</key>
The solution was simply to listen on ports 8080 and 8443. All requests to ports 80 and 443 are now being redirected transparently.
While debugging this I found countless open questions about similar problems without answers. I hope this helps somebody.

Ruby application does not receive UDP packet from different host

Sending a UDP packet from Ruby client to Ruby server using the server address 192.168.1.30 works as expected, but only if client and server are on the same host. If the client runs on a different machine, the UDP packet finds its way to the server, but my server process won't notice.
Server:
require 'socket'
sock = UDPSocket.new()
sock.bind('', 8999)
p sock
while true do
p sock.recvfrom(2000)
end
sock.close
Client:
require 'socket'
sock = UDPSocket.new
p sock.send("foo", 0, "192.168.1.30", 8999)
sock.close
After starting the server, netstat -n --udp --listen approves that the socket is open:
Proto Recv-Q Send-Q Local Address Foreign Address State
udp 0 0 0.0.0.0:8999 0.0.0.0:*
After running the client twice (on 192.168.1.30 and on .23), server output shows only one incoming packet, missing the one from 192.168.1.23:
#<UDPSocket:fd 7, AF_INET, 0.0.0.0, 8999>
["foo", ["AF_INET", 52187, "192.168.1.30", "192.168.1.30"]]
while Wireshark indicates that two packets were noticed
No Time Source Destination Proto Length Info
1 0.000000000 192.168.1.30 192.168.1.30 UDP 47 52187 → 8999 Len=3
2 2.804243569 192.168.1.23 192.168.1.30 UDP 62 39800 → 8999 Len=3
Which probably obvious detail am I missing?
Check if you have any firewall rules active:
sudo iptables -L
sudo ufw status

Why does Active Directory close LDAP connections with [RST, ACK] instead of [FIN, ACK]?

This is more of a curiosity than a problem, as I don't see any negative impacts, but I am wondering why does Active Directory close LDAP connections with [RST, ACK] instead of [FIN, ACK] after a [FIN, ACK] from a client?
Just any simple LDAP search to Active Directory (Windows Server 2012 R2) will make a TCP connection that is terminated client-side but ACK'd by the server with a [RST, ACK] instead of a [FIN, ACK].
A search similar to this will reproduce this:
ldapsearch -s sub -a always -x -h myhost.ad.corp.com -y passfile -D "administrator#ad.corp.com" -b "dc=ad,dc=corp,dc=com" "(fsmoroleowner=*)"
Before running this, use tcpdump similar to this:
sudo tcpdump -w output.pcap port ldap
If you examine the packet capture file, you will see that the AD server responds to the client TCP close's [FIN, ACK] with a [RST, ACK]. Either way the connection is closed, but based on what I know about TCP, it seems more correct for the server to send a [FIN, ACK].

Send and receive TCP data in ruby

I have a TCP server running which accepts the command "GETHELLO" and return "HELLO".
I test it by using Telnet in linux shell :
:~$ telnet 192.168.1.10 3000
Trying 192.168.1.10...
Connected to 192.168.1.10.
Escape character is '^]'.
GETHELLO
HELLO
How can I do this in ruby using TCPSocket ? (send "GETHELLO" and read the data "HELLO" returned by the server)
Thanks!
require 'socket'
sock = TCPSocket.new('192.168.1.10', 3000)
sock.write 'GETHELLO'
puts sock.read(5) # Since the response message has 5 bytes.
sock.close

Resources