Around two weeks ago, I ran into a limitation with the Path.net DDoS protection that wasn’t described anywhere: a limit to the amount of TCP connections a single user can open.
Path offers a revolutionary solution to ensure the security, uptime and longevity of your investments by offering cutting-edge analytics, monitoring and mitigation solutions.
Path.net
Thankfully, Path employees are pretty easy to reach (and friendly, too), so I asked whether they did have a filter in place for the total number of TCP connections, but they said they didn’t (I was almost certain they would have, given that it could be an attack vector). Well, hm, but I think you might, so I needed to test more.
I could replicate the problem easily with my application: open X active TCP connections to a server and subsequent connections would be filtered on the network. My next question was whether this was specific to my application (it sends and receives a lot of data, so perhaps we’re triggering something), or TCP connections in general. Surely, someone else must have experienced the same problem? It turns out they did. After I spoke to the Path employees on Discord, another user chipped in and explained they experienced a similar limitation a while ago. Time for some digging!
I figured the easiest way to test this would be to create a basic standalone TCP client and server – a simple ping pong like the good old IRC days.
Mongoose, a networking library for C++
I’ve used Mongoose in quite a few applications now – HTTP, UDP, TCP and Websockets. It’s super easy to set up and use, which is why I love it, so headed straight for it to look into this problem further. We’ll use Mongoose to set up a basic TCP client and server in Visual Studio 2019 in this walkthrough.
Download the latest version of Mongoose and extract it to a folder: https://github.com/cesanta/mongoose
A TCP Server
Create a new project and add the Mongoose folder to the C/C++ > General > Additional Include Directories
. Then, paste the following code into your project file:
#pragma comment(lib, "WS2_32")
#include "mongoose.h"
#include <iostream>
#include <string>
static void cb(struct mg_connection* c, int ev, void* ev_data, void* fn_data) {
if(ev == MG_EV_READ) {
std::string data = std::string((char*)c->recv.buf, c->recv.len);
std::cout << data << std::endl;
std::string reply = "PONG";
mg_send(c, reply.c_str(), reply.size());
mg_iobuf_del(&c->recv, 0, c->recv.len);
}
}
int main(int argc, char* argv[]) {
struct mg_mgr mgr;
mg_mgr_init(&mgr);
mg_listen(&mgr, "tcp://127.0.0.1:10000", cb, &mgr);
for (;;) mg_mgr_poll(&mgr, 1000);
mg_mgr_free(&mgr);
return 0;
}
A TCP Client
Create a new project and add the Mongoose folder to the C/C++ > General > Additional Include Directories
. Then, paste the following code into your project file:
#pragma comment(lib, "WS2_32")
#include "mongoose.h"
#include <iostream>
#include <string>
static void cb(struct mg_connection* c, int ev, void* ev_data, void* fn_data) {
if (ev == MG_EV_READ) {
std::string data = std::string((char*)c->recv.buf, c->recv.len);
std::cout << data << std::endl;
mg_iobuf_del(&c->recv, 0, c->recv.len);
}
}
int main(int argc, char* argv[]) {
struct mg_mgr mgr;
mg_mgr_init(&mgr);
struct mg_connection* nc = mg_connect(&mgr, "tcp://127.0.0.1:10000", cb, &mgr);
std::string data = "PING";
mg_send(nc, data.c_str(), data.size());
mg_iobuf_del(&nc->recv, 0, nc->recv.len);
while (!finished) mg_mgr_poll(&mgr, 1000);
mg_mgr_free(&mgr);
return 0;
}
And… that’s… it. Your first TCP client and server. It really is that easy. Mongoose brings a lot of power to the table, and this is the absolute bare bones of its capabilities. I would highly recommend going through its documentation, as you can really do some amazing things with it.
Issue Replicated
Now that I have a standalone application to play with, it was evident that there was a TCP connection limit somewhere on the Path network which was unknown to Path employees, and could now be easily replicated in seconds.
With the code for the client and server I had made promptly sent over to them, I heard back a few days later to say that they had identified the problem and they were on their way to resolve it, and that they also plan on expanding their TCP symmetric rule set in the future to give users more control over TCP connection limits for their application.