boost::asio::connect reports success on wrong subnet - c++

Using Boost v1.74:
int main()
{
auto ctx = boost::asio::io_context{};
auto socket = boost::asio::ip::tcp::socket{ctx};
auto ep = boost::asio::ip::tcp::endpoint{
boost::asio::ip::make_address_v4("192.168.0.52"),
80};
boost::asio::connect(socket, std::array{std::move(ep)});
std::cout << "Success!" << std::endl;
}
The IP address of my machine on my local network is 192.168.0.31/24, and so trying to connect to a non-existent address in the same subnet with the above code gives:
10:24:55: Starting /home/cmannett85/workspace/build-scratch-Desktop-Debug/scratch ...
terminate called after throwing an instance of 'boost::wrapexcept<boost::system::system_error>'
what(): connect: No route to host
10:24:59: The program has unexpectedly finished.
This is all expected. If I change the bottom octet of the subnet in the address (e.g. 192.168.1.52), then the app just waits for a few minutes - presumably because it sent messages to any routers to see if they own the requested subnet. There aren't any routers on my network, so it eventually times out:
10:27:39: Starting /home/cmannett85/workspace/build-scratch-Desktop-Debug/scratch ...
terminate called after throwing an instance of 'boost::wrapexcept<boost::system::system_error>'
what(): connect: Connection timed out
10:29:49: The program has unexpectedly finished.
Again, as expected. If I change the next octet (e.g. 192.167.0.52) instead, I would expect this to behave exactly the same as it is an equally unknown subnet as the previous. But it suceeds!
10:31:22: Starting /home/cmannett85/workspace/build-scratch-Desktop-Debug/scratch ...
Success!
This address is definitely not on my network:
$ ping 192.167.0.52
PING 192.167.0.52 (192.167.0.52) 56(84) bytes of data.
^C
--- 192.167.0.52 ping statistics ---
17 packets transmitted, 0 received, 100% packet loss, time 16368ms
So why is the code reporting that it is connected? And why is changing the second octet different to the third?

Any IP address of the form 192.168.xx.xx is a non-internet-routable network. This means no internet routers will route it. So the only way packets get routed off your subnet is if you configure a route on your own router or host. 192.167.xx.xx is an internet routable network, Presumable there is a host out there on the internet that uses the address you specified. So if you can connect your host to the internet, some internet router will get your packet to the address specified.

It's something related to my VPN. I didn't think it was relevant as the tunnel address is 10.17.0.60/16, but disabling it makes the above code work as expected.
Thanks to a suggestion by #dewaffled, Curl is showing that there is something on the otherside of this connection that is completing the TCP handshake, but after a timeout of a few minutes closes the connection.
$ curl -v http://192.167.0.52
* Trying 192.167.0.52:80...
* Connected to 192.167.0.52 (192.167.0.52) port 80 (#0)
> GET / HTTP/1.1
> Host: 192.167.0.52
> User-Agent: curl/7.74.0
> Accept: */*
>
* Recv failure: Connection reset by peer
* Closing connection 0
curl: (56) Recv failure: Connection reset by peer
I know nothing about how VPNs work, but I suspect this is an implementation detail of my particular provider. Hopefully this 'answer' will limit confusion for anyone else!

Related

SSL_connect returned=1 errno=0 state=SSLv2/v3 read server hello A: (null) when communicating with Chef Automate server

I am having difficulty connecting to my Chef Automate server, hosted on AWS OpsWorks.
I am usually connecting to it at least once per day, however since the start of the week I have been unable to.
There is some weekly maintenance performed on the server on a Friday, however this seems to go unnoticed.
When I try and communicate with the server I get the following error:
knife environment from file environments/production.json
ERROR: SSL Validation failure connecting to host: crmpicco-production-lay0vgyp4ighjsxv.us-east-1.opsworks-cm.io - SSL_connect returned=1 errno=0 state=SSLv2/v3 read server hello A: (null)
ERROR: SSL Error connecting to https://crmpicco-production-lay0vgyp4ighjsxv.us-east-1.opsworks-cm.io/organizations/rfc1872/environments/production, retry 1/5
In the events, I can see the following:
2022-08-26T12:25:26Z Maintenance completed successfully
2022-08-26T12:24:54Z Updating stack arn:aws:cloudformation:us-east-1:367114569123:stack/aws-opsworks-cm-instance-mc-prod-chef-1661515433111/27c16c50-2537-22ed-80ab-12a4e5696267 to associate EIP 2.51.125.211
2022-08-26T12:24:23Z Updating stack arn:aws:cloudformation:us-east-1:367114569123:stack/aws-opsworks-cm-instance-mc-prod-chef-1660910626222/fad95750-1fb6-22ed-817f-0aca43928f1d to disassociate EIP 2.51.125.211
2022-08-26T12:24:11Z Checking health of new instance
I have tried a knife ssl fetch, but that is also unable to communicate with the server.

Error reconnecting boost beast (asio) websocket and http connection after disconnect

I am creating a client application that connects to a server using a an ssl Websocket connection and an ssl Http (Keep-Alive) connection and I am using boost::beast package to do the same. So as to detect a dead connection i have implemented a simple ping-pong mechanism. These all work fine, but an issue comes up when handling the ping-pong failure. The issue is as follows:
For testing my code i connected to the remote server, sent few messages and then turned off my wifi. As expected after a certain period it detected that it did not receive any message from the server and it tried to do an async_shutdown for the http connection and an async_close for the websocket connection. First thing i noticed was that both these calls block their respective strands until the wifi is back up.
And after the wifi is up, the application tries to reset the stream before reconnect:
void HttpKeepAliveConnection::recreateSocket()
{
_receivedPongForLastPing = true;
_sslContext.reset(new boost::asio::ssl::context({boost::asio::ssl::context::sslv23_client}));
_stream.reset(new HttpStream(_ioContext, *_sslContext));
}
And reset ws variable for websocket:
void WebsocketConnection::recreateSocket()
{
_receivedPongForLastPing = true;
_sslContext.reset(new boost::asio::ssl::context({boost::asio::ssl::context::sslv23_client}));
_ws.reset(new WebSocket(_ioContext, *_sslContext));
}
Unfortunately it fails at either on_connect or on_ssl_handshake. Following are my logs:
156 AsioConnectionBase.cpp:53 (2018-08-06 15:34:38.458536) [0x00007ffff601e700] : Started connect sequence. Connection Name: HttpKeepAliveConn
157 AsioConnectionBase.cpp:122 (2018-08-06 15:34:38.459802) [0x00007ffff481b700] : Failed establishing connection to destination. Connection failed. Connection Name: HttpKeepAliveConn. Host: xxxxxxxxx. Port: 443. Error: Operation canceled
158 APIManager.cpp:175 (2018-08-06 15:34:38.459886) [0x00007ffff481b700] : Received error callback from connection. Restarting connection in a sec. Connection Name: HttpKeepAliveConn
159 AsioConnectionBase.cpp:53 (2018-08-06 15:34:39.460009) [0x00007ffff481b700] : Started connect sequence. Connection Name: HttpKeepAliveConn
160 HttpKeepAliveConnection.cpp:32 (2018-08-06 15:34:39.460515) [0x00007ffff481b700] : Failed ssl handshake. Connection failed.Connection Name: HttpKeepAliveConn. Host: xxxxxxxxx. Port: 443. Error: Bad file descriptor
161 APIManager.cpp:175 (2018-08-06 15:34:39.460674) [0x00007ffff481b700] : Received error callback from connection. Restarting connection in a sec. Connection Name: HttpKeepAliveConn
So I have 2 questions:
How do we close a connection if internet is down and a proper tcp close is not possible.
Before reconnecting what are the variables in boost::beast (or for that matter boost::asio as boost::beast is built on top of asio) that needs to be reset
Have been stuck trying to debug this for couple of hours. Any help is appreciated
EDIT
So I figured out where I went wrong. Both Alan Birtles and Vinnie Falco were right. The way to close a dead ssl connection after your ping timer has expired (and none of the handlers have returned yet) is
In your timer handler
_stream->lowest_layer().close();
For websocket
_ws->lowest_layer().close();
Wait for one of your handlers (typically read handler) to return with error (typically boost::asio::error::operation_aborted error). From there, queue the start of the next reconnect. (Do not queue the reconnect immediately after step 1, it will result in memory issues that I faced. I know this is asio 101, but is easy to forget)
For resetting socket, all that is required is for the stream to be reset
_stream.reset(new HttpStream(_ioContext, _sslContext));
For websocket
_ws.reset(new WebSocket(_ioContext, _sslContext));
I don't think asio::ssl::stream can be used again after being closed.
How do we close a connection if internet is down and a proper tcp close is not possible.
Simply allow the socket or stream object to be destroyed.

KeepAlived + HAProxy gets connection refused after a while

I´ve the next scenario, 4 VM´s running Red Hat Enterprise Linux 7:
20.1.67.230 server (VIRTUAL IP) (not a host)
20.1.67.219 haproxy1 (LOAD BALANCER)
20.1.67.229 haproxy2 (LOAD BALANCER)
20.1.67.223 server1 (LOAD TO BALANCE)
20.1.67.213 server2 (LOAD TO BALANCE)
My keepalived.conf file is:
vrrp_script chk_haproxy {
script "killall -0 haproxy" # check the haproxy process
interval 2 # every 2 seconds
weight 2 # add 2 points if OK
}
vrrp_instance VI_1 {
interface enp0s3 # interface to monitor
state MASTER# MASTER on haproxy1, BACKUP on haproxy2
virtual_router_id 51
priority 101 # 101 on haproxy1, 100 on haproxy2
unicast_src_ip 20.1.67.229 # This is the IP of the interface keepalived listens on
unicast_peer { # This is the IP of the peer instance
20.1.67.219
}
virtual_ipaddress {
20.1.67.230 # virtual ip address
}
track_script {
chk_haproxy
}
}
When a execute a request to the VIRTUAL IP, for instance:
curl server:8888/info
everything is ok, but just for a while, after some requests the command returns me : connection refused
So I´ve to restart the keepalived service manually , this way:
systemctl restart keepalived.service
The whole system seems work well, VRRP messages between haproxy1 and haproxy2 are OK, it´s just like the Virtual IP is not working properly.
Can anyone point me in the right direction to diagnose and fix this problem?
It was a networking issue. There was a device on the net with same IP as the Virtual IP I had chosen.

Queued Emails Fail in AWS VPC Environment

I have a system that sends out emails and queues them if volume increases.
If it's 1 or 2 emails per hour, it sends out fine.
On busier times, the queue gets backed up and soon email sending starts to fail.
I've load-tested the SMTP server from my local - no problems there.
However, when I try to do the load-test from my EC2 server
- which is in a private subnet of a VPC
- where outgoing traffic goes through a NAT
- and where we've set up our own DNS server
the first few go out fine - and the rest starts to throw errors.
Here's the C# exception ToString()
System.Net.Mail.SmtpException: Failure sending mail. ---> System.Net.WebExcept
ion: Unable to connect to the remote server ---> System.Net.Sockets.SocketExcept
ion: A connection attempt failed because the connected party did not properly re
spond after a period of time, or established connection failed because connected
host has failed to respond [SMTPServerIP]:25
at System.Net.Sockets.Socket.DoConnect(EndPoint endPointSnapshot, SocketAddre
ss socketAddress)
at System.Net.ServicePoint.ConnectSocketInternal(Boolean connectFailure, Sock
et s4, Socket s6, Socket& socket, IPAddress& address, ConnectSocketState state,
IAsyncResult asyncResult, Exception& exception)
--- End of inner exception stack trace ---
at System.Net.ServicePoint.GetConnection(PooledStream PooledStream, Object ow
ner, Boolean async, IPAddress& address, Socket& abortSocket, Socket& abortSocket
6)
at System.Net.PooledStream.Activate(Object owningObject, Boolean async, Gener
alAsyncDelegate asyncCallback)
at System.Net.PooledStream.Activate(Object owningObject, GeneralAsyncDelegate
asyncCallback)
at System.Net.ConnectionPool.GetConnection(Object owningObject, GeneralAsyncD
elegate asyncCallback, Int32 creationTimeout)
at System.Net.Mail.SmtpConnection.GetConnection(ServicePoint servicePoint)
at System.Net.Mail.SmtpTransport.GetConnection(ServicePoint servicePoint)
at System.Net.Mail.SmtpClient.GetConnection()
at System.Net.Mail.SmtpClient.Send(MailMessage message)
--- End of inner exception stack trace ---
at System.Net.Mail.SmtpClient.Send(MailMessage message)
at ConsoleApplication2.Program.Main(String[] args) in c:\ConsoleApplication2\
Program.cs:line 49
I'm pretty sure it's not a code issue - most likely a setting on the NAS or DNS.
Can someone point me in the right direction?
After some more googling - it seems to be a throttle on AWS' end
Source:
http://aws.amazon.com/ec2/faqs/
Q: Are there any limitations in sending email from EC2 instances?
Yes. In order to maintain the quality of EC2 addresses for sending email, we enforce default limits on the amount of email that can be sent from EC2 accounts. If you wish to send larger amounts of email from EC2, you can apply to have these limits removed from your account by filling out this form .
Better details here:
Amazon EC2/SES SMTP Timeout

Arduino hangs during multiple http requests on Linux but not on Windows

i have a problem when i send http requests from the arduino to linux mysql server. It randomly hangs after some requests (~150) but on windows it runs smoothly.
Because of this i am thinking that the problem is not on the arduino code but somewhere else.
The linux server runs on a raspberry pi (Raspbian).
Any suggestions?
The arduino code HERE
if(!getPage(server,serverPort)) Serial.print(F("Fail "));
byte getPage(IPAddress ipBuf,int thisPort)
{
int inChar;
Serial.print(F("connecting..."));
if(client.connect(ipBuf,thisPort))
{
Serial.println(F("connected"));
strcpy(outBuf,"GET /write3.php?value0=");
itoa(value0,tBuf,10);
strcat(outBuf,tBuf);
strcat(outBuf,"&value1=");
itoa(dht_humidity,tBuf,10);
strcat(outBuf,tBuf);
strcat(outBuf,"&value2=");
itoa(temperature,tBuf,10);
strcat(outBuf,tBuf);
strcat(outBuf,"&value3=");
itoa(pressure,tBuf,10);
strcat(outBuf,tBuf);
strcat(outBuf,"&value4=");
itoa(altitude,tBuf,10);
strcat(outBuf,tBuf);
strcat(outBuf,"&value5=");
itoa(gust,tBuf,10);
strcat(outBuf,tBuf);
strcat(outBuf,"&value6=");
itoa(dir,tBuf,10);
strcat(outBuf,tBuf);
strcat(outBuf,"&value7=");
itoa(rain,tBuf,10);
strcat(outBuf,tBuf);
strcat(outBuf,"&value8=");
itoa(knots,tBuf,10);
strcat(outBuf,tBuf);
client.write(outBuf);
client.println(" HTTP/1.1");
client.println("Host: 192.168.1.3");
client.println("Connection: close");
client.println();
EDIT: Just hanged at DEBUG___3
Serial.println("DEBUG___2");
client.write(outBuf);
Serial.println("DEBUG___3");
client.println(" HTTP/1.1");
Serial.println("DEBUG___4");
client.println("Host: 192.168.1.3");
Serial.println("DEBUG___5");
client.println("Connection: close");
client.println();
I captured the network traffic with wireshark when it hanged:
(Large pics: hanged http request ---- successfull http request)
Here is the http request that hanged
And here is a successful request:
Any ideas guys? Still stuck there !!!
Presuming you are certain the outBuf is not overflowed (it is smaller than maximum possible request string size and you are using strcat (source of all evil))
The server may timeout in the long time between when the connection is opened, and when you actually send any bytes. Preconstruct the outBuf so that it is ready to go when the connection opens.
strncat(outBuf,...,127);
... request is fully constructed
if(client.connect(ipBuf,thisPort)) {
client.write(outBuf);
client.println(" HTTP/1.1");
client.println("Host: 192.168.1.3");
...
To the server, the connection that is SYN'd but not used is a resource to be recovered. The Arduino will be so slow, it will look like an idle connection. Also a SYN flood is an old denial of service vector that most servers will protect against.
A difference in the timeout values would explain why the Linux and Win based server act different. You could confirm this by running Wireshark on the traffic. If the server is timing out on the Arduino, you will see this sequence:
the SYN handshake proceed between server and Arduino
a little time passes
a RST from the server indicating the connection is dead
the Arduino sends the request string to the now dead connection
the Arduino program hangs at the client.write() because the connection state is out of
sync
the client will probably be retrying - you should see some retransmissions