Search code examples
shellawksshnetstat

Shell script command help to shorten?


I have a command that is like this:

/bin/netstat -an | /usr/bin/awk -vmax=100 '/tcp/{split($5,a,":"); if(a[1] > 0 && a[1]!="0.0.0.0" && a[1]!="127.0.0.1" && a[1]!="111.222.111.222" ... 50 addresses... && a[1]!="211.112.211.112"){c[a[1]]++}} END{for(ip in c){if(c[ip]>max){print ip}}}' | while read ip; do /sbin/iptables -m comment --comment "SCAN BLOCK" -I INPUT 1 -s $ip -j DROP; done

How can I shorten it to read IP addresses from file, or from a array list above command, or something like that as I have now almost 100 IPs and all are one next to another in one big command line.

Basicaly, how to make command something like this:

/bin/netstat -an | /usr/bin/awk -vmax=100 '/tcp/{split($5,a,":"); if(a[1] > 0 && a[1]!="read from file"){c[a[1]]++}} END{for(ip in c){if(c[ip]>max){print ip}}}' | while read ip; do /sbin/iptables -m comment --comment "SCAN BLOCK" -I INPUT 1 -s $ip -j DROP; done

Solution

  • Place the list of ips in a file, eg:

    $ cat iplist.txt
    0.0.0.0
    127.0.0.1
    111.222.111.222
    ... snip ...
    211.112.211.112
    

    The general approach is to have awk process 2 input files with different logic, eg:

    /bin/netstat -an | 
    /usr/bin/awk -vmax=100 '
    
    # process 1st file (iplist.txt): 
    
    FNR==NR { iplist[$1]                 # FNR==NR is only true for the 1st file; for follow-on files FNR resets to 1 but NR keeps increasing
              next                       # skip to next input record; keeps from running follow-on code against 1st file contents
            }   
    
    # process 2nd file (stdin):
    
    /tcp/   { split($5,a,":")
              if (a[1] > 0 && !(a[1] in iplist))
                 c[a[1]]++
            }
    END     { for (ip in c) 
                  if (c[ip]>max)
                     print ip
            }
    ' iplist.txt -                      # 2nd file actually says to read from stdin (ie, output from netstat call)
    

    NOTE: OP would then pipe this output to the same while/iptables loop, eg:

    /bin/netstat -an | 
    /usr/bin/awk -vmax=100 '
    FNR==NR { iplist[$1] 
    ... snip ...
                     print ip
            }
    ' iplist.txt - |  while read ip; do /sbin/iptables ...;done
    
    # or collapsed to one line (though harder to read and/or troubleshoot):
    
    netstat -an | awk -vmax=100 'FNR==NR{iplist[$1];next} /tcp/{split($5,a,":"); if (a[1] > 0 && !(a[1] in iplist)) c[a[1]]++} END{for (ip in c) if (c[ip]>max) print ip}' iplist.txt - | while read ip; do /sbin/iptables ...;done