Trying to tail a log file (iptraf log) and grep a string to automatically ban people who hit a telnet port.

The log is forever rolling (Meaning it's constantly being written to) and i need to read from it constantly for every line that's added by iptraf.

UPDATE-1:

It gets the ip but now i need to use it, but if i replace echo with var= it does not trigger the bash command

#!/bin/bash
tail -f /iptraf/ip.log | 
while read LINE
    do
       echo "${LINE}" | grep -o '[0-9]\{0,3\}\.[0-9]\{0,3\}\.[0-9]\{0,3\}\.[0-9]\{0,3\}:[0-9]\{0,6\}\ to localhost:telnet' | cut -d':' -f1
done

This prints the first ip by splitting the returned grep with the semicolon and getting the first part which is the offenders ip.

Can't seem to put the echo part into a variable? I also need to be able to determine if it's an IP in an array ["x.x.x.x","x.x.x.x"] and not to ban those.

UPDATE-2:

#!/bin/bash

#Rolling log file
tail -f /iptraf/iplog.log | 

while read LINE
    do
        #get the ip of the offender x.x.x.x <----
        #Example of output
        #Sun Apr 21 09:54:41 2019; TCP; eth0; 52 bytes; from x.x.x.x:53923 to localhost:telnet; first packet (SYN)
        #Regex/cut output ends up with this: x.x.x.x

        ip=${
            "${LINE}" | sed -n 's/^.* from \(.*\) to localhost:telnet;.*/\1/p' | cut -d':' -f1
        };

        #bad substitution error?

        if [[$ip !== 'localhost']] then
            #ban offender and log to console
            iptables -I INPUT -s $ip -j DROP && route add -host $ip reject
            echo "Offender Banned: $ip";
        fi
done

With this one, console throws me a mean message "BAD SUBSTITUTION"

I know this is reinventing the wheel and all, but i need this to create my own scripts for other logs. I'm also dealing with a ton of hackers every day so it's extremely infuriating not being able to do it automatically.

Example of iptraf output

Sun Apr 21 01:50:44 2019; TCP; eth0; 52 bytes; from x.x.x.x:52364 to x.x.x.x:telnet; first packet (SYN)

PS, x.x.x.x are ACTUAL IP'S such as 111.111.111.111, just marked out.

UPDATE-3:

#!/bin/bash

tail -f /var/log/iptraf/ip_traffic-1.log |
awk -v skipIps="192.168.1.1,127.0.0.1" '
    BEGIN {
        split(skipIps,tmp,/,/)
        for (i in tmp) {
            skipSet[tmp[i]]
        }
    }
    /to localhost:telnet/ {
        ip = $11
        sub(/:.*/,"",ip)
        if ( !(ip in skipSet) ) {
            printf "BANNING TELNET: %s\n", ip | "cat>&2"
            print "[External] EXTERNAL HIT TELNET [Telnet Server Connection]:", ip
            fflush()
            system("iptables -I INPUT -s "ip" -j DROP && route add -host "ip" reject")
        } else {
            printf "That was US! TELNET: %s\n", ip | "cat>&2"
            print "[Allowed] INTERNAL HIT TELNET [Telnet Server Connection]:", ip
            fflush()
        }
    }
'

Now that we can ban ip's that hit ports, It would be best so clear the logs iptables every month to prevent it from slowing down the server right? - I can do that later my self, What I'm currently interested in right now is the part where it states the port "localhost:telnet" - I really need to be able to check multiple port names against a list of known port names like "telnet","ircd","ssh","ftp","sip-tls" etc etc.

It would be great if anyone can assist me with the multiple port names in update-3 of this post.

3 Answers

0
Ed Morton On Best Solutions
tail -f /logs/iptraf.log |
awk -v skipIps="a.b.c.d,w.x.y.z" '
    BEGIN {
        split(skipIps,tmp,/,/)
        for (i in tmp) {
            skipSet[tmp[i]]
        }
    }
    /to localhost:telnet/ {
        ip = $11
        sub(/:.*/,"",ip)
        if ( !(ip in skipSet) ) {
            printf "uhoh! - this ip %s hit telnet port.. We need to ban the ip\n", ip | "cat>&2"
            print ip
            fflush()
        }
    }
' | xargs -I {} iptables -I INPUT -s '{}' -j DROP

Look (using cat file in place of tail -f ... and adding an echo before iptables to demonstrate the rest of the script working):

$ cat file
Sun Apr 21 01:50:44 2019; TCP; eth0; 52 bytes; from x.x.x.x:52364 to localhost:telnet; first packet (SYN)

cat file |
awk '/to localhost:telnet/ {
    ip = $11
    sub(/:.*/,"",ip)
    printf "uhoh! - this ip %s hit telnet port.. We need to ban the ip\n", ip | "cat>&2"
    print ip
    fflush()
}' |
xargs -I {} echo iptables -I INPUT -s '{}' -j DROP
iptables -I INPUT -s x.x.x.x -j DROP
uhoh! - this ip x.x.x.x hit telnet port.. We need to ban the ip
0
sjsam On

Since you need a (somewhat) complex pattern match, you could directly pipe the tail result to awk like below :

# First pipe the tail output to awk
tail -f /logs/iptraf.log | awk '/to localhost:telnet/{
# The /pattern/ looks for a pattern
# We reach this stage only if the patten match is successful.
ip=gensub(/^.*from[[:blank:]]+([^[:blank:]]+).*$/,"\\1","g")
# Above lines searches a record($0) for the IP that we wish to block
# and assign it to an awk variable 'ip'
system("iptables -I INPUT -s " ip " -j DROP") 
# Above line executes a bash command using the system awk command
}'

Test

iptables -L # To see the modified rules.

Note: You should have a GNU awk for doing the above. Also, look here to see more about awk string functions.

1
Mark On

I've modified your code slightly:

tail -f /logs/iptraf.log | grep "to localhost:telnet"  |
while 
   read OFFENDING_IP EXTRA
do 
  echo "uhoh! - $OFFENDING_IP hit telnet port.. We need to ban the ip"
  iptables -I INPUT -s $OFFENDING_IP -j DROP
done

The code is untested. And I just assumed that the IP appears first on the line before "to localhost:telnet".

As for an explanation, you're code was reasonable. However, you didn't know how to extract the IP from the lines you grepped. The read command will take the output of the grep command since I changed your ; to a | to feed the output of grep to the next command. Moreover, the read command will parse the line into fields and stuff the values into the variables on the command line. The first field (presumably the IP) is placed in OFFENDING_IP field and the remainder of the line is stuffed into the EXTRA variable.