Tuesday, November 2, 2021

[SOLVED] Can't reach max tcp connections for single server

Issue

I'm testing max tcp connections in CentOS7. I changed open files limit to 1000000(ulimit -n 1000000) and edited sysctl.conf as shown below. Then I test with node.js as follow code (single server):

var net = require('net');
var count = 0
//server
let server = net.createServer(function(conn){
    conn.on("close", function(code, reason){
        console.log("close", code, reason);
    })
    conn.on("error", function(code, reason){
        console.log("error close", code, reason);
    })
}).listen({port : 8080, host: "0.0.0.0", backlog: 100000}).on("connection", _=>{count++});

//client
setInterval(_=>{new Array(300).fill(1).map((_,index)=>index+1926).map(p=>{
    new net.Socket().connect(8080,'127.0.0.1')
        .on('error',function(e){
            console.log(count);
            console.log(e);
            process.exit()}
        );
    })&&console.log('connection count:',count)},10)

Results:

connection count: 64200
connection count: 64500
64500
{ Error: connect EADDRNOTAVAIL 127.0.0.1:8080 - Local (127.0.0.1:0)
    at internalConnect (net.js:872:16)
    at defaultTriggerAsyncIdScope (internal/async_hooks.js:294:19)
    at defaultTriggerAsyncIdScope (net.js:962:9)
    at process._tickCallback (internal/process/next_tick.js:61:11)
  errno: 'EADDRNOTAVAIL',
  code: 'EADDRNOTAVAIL',
  syscall: 'connect',
  address: '127.0.0.1',
  port: 8080 }

It throw EADDRNOTAVAIL while connection count reach 64500. then I tried multiple server as follows:

var net = require('net');
var count = 0
//server
new Array(300).fill(1).map((_,index)=>index+1926).map(p=>{
    net.createServer().listen(p).on('connection',_=>count++)
    })

//client
setInterval(_=>{new Array(300).fill(1).map((_,index)=>index+1926).map(p=>{
    new net.Socket().connect(p,'127.0.0.1')
        .on('error',function(e){
            console.log(e);
            process.exit();
        })})&&console.log('connection count:',count);},10)

Results:

connection count: 392400
connection count: 392700
Aborted (core dumped)

Why multiple server connections can over 390000 but single server connections can only reach 64500 and throw EADDRNOTAVAIL error?


/etc/sysctl.conf:

net.ipv4.tcp_tw_reuse = 1

net.ipv4.tcp_tw_recycle = 1

net.ipv4.tcp_fin_timeout = 10

net.ipv4.tcp_keepalive_time = 1200

net.ipv4.tcp_max_tw_buckets = 5000

fs.file-max = 1000000

net.ipv4.ip_local_port_range= 1024 65535

net.core.somaxconn = 65535

net.ipv4.tcp_syncookies = 1

net.ipv4.tcp_max_syn_backlog = 65535

net.ipv4.tcp_synack_retries = 2

net.ipv4.tcp_syn_retries = 2

Solution

You aren't binding your outbound connection sockets. This causes the operating system to assign them a local source IP address and port. Likely it's using the same local source IP address (127.0.0.1) for all of them and thus only has around 65,000 ports. Bind it yourself to a random combination of local IP address inside the loopback range and port inside the unprivileged range. If you get EADDRNOTAVAIL, try a different random combination.



Answered By - David Schwartz