# [SOLVED] Check total number of connections per IP + restrict

## danny_b85

Hi all,

I have somewhat of a problem which I haven't been able to solve on my own so far so I want to ask anybody who's willing to help for some assistance.

I'm working on a server which gets overloaded from time to time on the networking part due to the large number of TCP/UDP connections and an IP ban is required from time.

Now I'm checking the number of connections on the server via the following command:

```
netstat -anp | grep 'tcp\|udp' | sed -n -e '/[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}/p' | awk '{print $5}' | sed 's/::ffff://' | cut -d: -f1 | sort | uniq -c | sort -n
```

Which gives me an output something like this:

```

     38 123.123.123.123

     42 123.123.123.124

     47 123.123.123.125

     49 123.123.123.126

     59 123.123.123.127

     68 123.123.123.128

     71 123.123.123.129

```

In the output the first column contains the number of simultaneous connections to the server from any one IP address. If I see more than 90 simultaneous connections from any IP, I ban it via:

```
csf -td IP
```

Right now I'm doing this manually but I want to automatize this via a script. What I've tried so far is this:

```
#!/bin/bash

VAR=`netstat -anp | grep 'tcp\|udp' | sed -n -e '/[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}/p' | awk '{print $5}' | sed 's/::ffff://' | cut -d: -f1 | sort | uniq -c | sort -n`

if [ $1 > 90 ]; then

for line in $VAR; do 

csf -td $2

done

fi
```

and:

```
#!/bin/bash

VAR=`netstat -anp | grep 'tcp\|udp' | sed -n -e '/[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}/p' | awk '{print $5}' | sed 's/::ffff://' | cut -d: -f1 | sort | uniq -c | sort -n > file`

while read file; do

if [ `cat file | awk '{print $1}'` > 90 ]; then

csf -td `cat file | awk '{print $2}'`

fi

done
```

So far I haven't had any luck with either of the two, my guess is that for the first script the $1 argument from the if statement doesn't take the the output from the above mentioned variable VAR, as for the second script I don't get why it doesn't work, theoretically the second script should have worked.

Does anyone have any ideas related to this, suggestions, maybe even another way of achieving the same goal?

Thank you in advance.Last edited by danny_b85 on Wed Jun 18, 2008 7:44 am; edited 1 time in total

----------

## truc

first you can simplify a little bit the script by piping the output of the netstat command to awk, and let it do the main job (determining ip with more than 90 connections)

```
netstat -an | awk '

   ($1 ~ /^(tcp|udp)$/ && $6 ~ /^ESTABLISHED$/ ) { 

        sub(/:[0-9]+$/, "", $5);

        nb_conn[$5]++;

   }

   END {

      for (ip in nb_conn)

         if (nb_conn[ip] > 90) print ip;

   }

'

```

Notes: 

1) this only looks at the tcp&udp lines (no more tcp6 or udp6, but you can modify it of course

2) I've change the /^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}:/ to $6 ~ /^ESTABLISHED$/  for two reasons:

a) by 1) I only have lines with "IPv4" IPs

b) we don't need the 'LISTEN' lines

to ban these IP, according to your post, you just have to issue csf -td IP

so just pipe the output of the above command to something like this

```
blalba | while read IP ; do csf -td $IP ; done
```

Hope this helps

----------

## xtz

What's csf?

----------

## danny_b85

 *Quote:*   

> What's csf?

 

# ConfigServer Security&Firewall (or csf for short) is a plugin for cPanel.

 *Quote:*   

> Hope this helps

 

Oh, you practically saved the day man  :Very Happy: 

The command finally works all the way.

```
netstat -an | awk '($1 ~ /^(tcp|udp)$/ && $4 !~ /121:21$/ ) {sub(/::ffff:/, "", $5); sub(/:[0-9]+/, "", $5); nb_conn[$5]++; } END { for (ip in nb_conn) if (nb_conn[ip] > 89) print ip;}' | while read IP ; do echo $IP ; done

DROP  all opt -- in eth0 out *  8*.3*.1.1**  -> 0.0.0.0/0

csf: 8*.3*.1.1** blocked on port * for 3600 seconds inbound

DROP  all opt -- in eth0 out *  8*.1**.1*.1**  -> 0.0.0.0/0

csf: 8*.1**.1*.1** blocked on port * for 3600 seconds inbound
```

I have a couple of questions though, so please bare with me as you are the only person able of answering this question in some ... 4 Linux forums, and about 20 Linux users I've asked so far.

```
($1 ~ /^(tcp|udp)$/ && $4 !~ /121:21$/ )
```

The above code searches in the output of netstat for tcp or udp connections, from what I can understand it says if the first argument is equal to the following regex (which stays between / and /) and and  :Smile:  if the last affirmation is true it goes to the next which means take the fourth argument and not put into the output of the command. Correct?

What other params can I put instead of the ~ and !~ and what do they do?

I've included this code into a bash script, however a problem appears, the rules from awk don't work and the output is something like this

```
tcp 0 0 ::ffff:1**.1**.2**.1**:80 ::ffff:8*.1**.6*.2**:1733 TIME_WAIT

tcp 0 0 ::ffff:1**.1**.2**.1**:80 ::ffff:9*.8*.8*.2**:52016 TIME_WAIT

tcp 0 0 ::ffff:1**.1**.2**.1**:80 ::ffff:8*.1**.8*.2**:50449 TIME_WAIT

tcp 0 0 ::ffff:1**.1**.2**.1**:80 ::ffff:8*.1**.6*.2**:1734 TIME_WAIT

tcp 0 0 ::ffff:1**.1**.2**.1**:80 ::ffff:7*.1**.3*.2**:2138 TIME_WAIT

tcp 0 0 ::ffff:1**.1**.2**.1**:80 ::ffff:8*.1**.8*.2**:50448 TIME_WAIT

tcp 0 0 ::ffff:1**.1**.2**.1**:80 ::ffff:8*.1**.1**.7*:4994 TIME_WAIT

tcp 0 0 ::ffff:1**.1**.2**.1**:80 ::ffff:8*.1**.1**.5*:2280 TIME_WAIT
```

and this is the script

```
#!/bin/bash

netstat -an | awk '($1 ~ /^(tcp|udp)$/ && $4 !~ /121:21$/ )

{sub(/::ffff:/, "", $5); sub(/:[0-9]+/, "", $5); nb_conn[$5]++; } END {

for (ip in nb_conn) if (nb_conn[ip] > 89) print ip;}' | while read IP ;

do echo $IP ; done
```

I've modified it because csf was giving me an error, saying there is no IP called [tcp], which made me input the echo into the script for troubleshooting.

Any ideas why it does this?

----------

## truc

 *danny_b85 wrote:*   

> The above code searches in the output of netstat for tcp or udp connections, from what I can understand it says if the first argument is equal to the following regex (which stays between / and /) and and  if the last affirmation is true it goes to the next which means take the fourth argument and not put into the output of the command. Correct?

 

Not sure to fully understand what you meant, but, it's just normal conditionnal statement:

(condition) { action }

if condition is true, then action !

so 

```
($1 ~ /^(tcp|udp)$/ && $4 !~ /121:21$/ )
```

 means if ( ($1=tcp or $1=udp ) and $4 doesn't end with 121:21$ ) then do { action }

awk split the line, and the Field Separator is by default [:space:], so in a line like this one

```
tcp 0 0 ::ffff:1**.1**.2**.1**:80 ::ffff:8*.1**.6*.2**:1733 TIME_WAIT
```

$1=tcp

$2=0

$3=0

$4=::ffff:1**.1**.2**.1**:80

$5=::ffff:8*.1**.6*.2**:1733

and so on

 *Quote:*   

> What other params can I put instead of the ~ and !~ and what do they do?

 you really should read the manual, plenty of valuable information  :Smile: 

 *Quote:*   

> I've included this code into a bash script, however a problem appears, the rules from awk don't work and the output is something like this
> 
> ```
> tcp 0 0 ::ffff:1**.1**.2**.1**:80 ::ffff:8*.1**.6*.2**:1733 TIME_WAIT
> 
> ...

 

You're working with ipv6 so are you sure this: sub(/:[0-9]+/, "", $5) is what you want to do? wouldn't it be something like sub(/:[0-9]+$/, "", $5) instead?

----------

## danny_b85

 *Quote:*   

> Not sure to fully understand what you meant, but, it's just normal conditionnal statement:
> 
> (condition) { action } 

 

Ok, I get it.

 *Quote:*   

> You're working with ipv6 so are you sure this: sub(/:[0-9]+/, "", $5) is what you want to do? wouldn't it be something like sub(/:[0-9]+$/, "", $5) instead?

 

You're right, I missed the $ at the end.

 *Quote:*   

> you really should read the manual, plenty of valuable information  

 

You are right, this is usually the best solution and the choice I would have made and I would still love to read a book on awk, 'cause it's pretty complex and worth looking into ... but I would do it if I had some more time, I have to study for some Cisco exams and that's why I didn't look more into the problem and resorted to asking on the forums ....

Now to the problem @ hand

```
netstat -an | awk '($1 ~ /^(tcp|udp)$/ && $4 !~ /121:21$/ )

{sub(/::ffff:/, "", $5); sub(/:[0-9]+$/, "", $5); nb_conn[$5]++; } END {

for (ip in nb_conn) if (nb_conn[ip] > 89) print ip;}' | while read IP ;

do echo $IP ; done
```

If executed as a command it works, and only prints the IP's with more than 89 connections, which is correct, however if I put into a script:

```
#!/bin/bash

netstat -an | awk '($1 ~ /^(tcp|udp)$/ && $4 !~ /121:21$/ )

{sub(/::ffff:/, "", $5); sub(/:[0-9]+$/, "", $5); nb_conn[$5]++; } END {

for (ip in nb_conn) if (nb_conn[ip] > 89) print ip;}' | while read IP ;

do echo $IP ; done
```

it outputs

```
tcp 0 0 ::ffff:1**.1**.2**.1**:80 ::ffff:8*.1**.6*.2**:1733 TIME_WAIT

tcp 0 0 ::ffff:1**.1**.2**.1**:80 ::ffff:9*.8*.8*.2**:52016 TIME_WAIT

tcp 0 0 ::ffff:1**.1**.2**.1**:80 ::ffff:8*.1**.8*.2**:50449 TIME_WAIT

tcp 0 0 ::ffff:1**.1**.2**.1**:80 ::ffff:8*.1**.6*.2**:1734 TIME_WAIT

tcp 0 0 ::ffff:1**.1**.2**.1**:80 ::ffff:7*.1**.3*.2**:2138 TIME_WAIT

tcp 0 0 ::ffff:1**.1**.2**.1**:80 ::ffff:8*.1**.8*.2**:50448 TIME_WAIT

tcp 0 0 ::ffff:1**.1**.2**.1**:80 ::ffff:8*.1**.1**.7*:4994 TIME_WAIT

tcp 0 0 ::ffff:1**.1**.2**.1**:80 ::ffff:8*.1**.1**.5*:2280 TIME_WAIT
```

So that's the problem I'm stuck with, everything worked fine until I put it into a script.

Any ideas on this? 

Thank you in advance

----------

## truc

```
#!/bin/bash

netstat -an | awk '

   ($1 ~ /^(tcp|udp)$/ && $4 !~ /121:21$/ ) { 

      sub(/::ffff:/, "", $5);

      sub(/:[0-9]+$/, "", $5);

      nb_conn[$5]++;

   }   

   END {

      for (ip in nb_conn)

         if (nb_conn[ip] > 1) print ip; 

   }   

' | while read IP ;do 

   echo $IP 

done

```

works fine here

----------

## danny_b85

Hey, 10x man, it works just fine.

Je vous remercie pour maider, et si vous venez en Roumanie je vous donner une biere  :Wink: 

Hope I said it right.

----------

## truc

You're welcomed  :Smile: 

I won't forget for the beer  :Wink: 

----------

