Fun with Shell Commands

I’m now running a mailserver, and I was trying to set up Mailman to handle a mailing list. I was having some odd behavior causing Mailman to barf up a fatal error, so I used a trailing monitor on the log file with tail -f.

In the course of doing that, I noticed several hosts connect attempting to deliver mail (presumably spam) to “bumttwagnerfor@domain…”, a bizarre address that definitely doesn’t exist.

It’s not a big deal, because the mail’s just bouncing. But it got irritating watching them all in the log file.

I wanted to ban them. It turns out that Linux makes this easy: there’s a hosts.deny file, and anyone in it is banned from connecting. I already have a script that watches for repeat failed login attempts on ssh and bans them. (And I have something like 200 IPs banned, although I suspect that it’s not purging them appropriately.)

All the log entries are in a common format, and look like this:


Oct 8 05:41:31 oxygen postfix/smtpd[23212]: NOQUEUE: reject: RCPT from unknown[62.233.163.250]: 550 5.1.1 <bumttwagnerfor@ttwagner.com>: Recipient address rejected: User unknown in local recipient table; from=<kqcwglupoqb@bonairenews.com> to=<bumttwagnerfor@ttwagner.com> proto=ESMTP helo=<250.248/30.163.233.62.in-addr.arpa>

We can see (actually, guess, in my case) that the IP is the 10th ‘column’ (using a ‘space’ as a delimiter). So we can begin a rudimentary script to print out just that:

# grep bumttwagnerfor /var/log/messages  | awk '{ print $10}' | head
unknown[211.49.17.175]:
81.202.185.36.dyn.user.ono.com[81.202.185.36]:
host-89-228-234-224.kalisz.mm.pl[89.228.234.224]:
LSt-Amand-152-32-14-78.w82-127.abo.wanadoo.fr[82.127.29.78]:

But there’s an obvious problem: the hostname is rammed up against the IP. I want to just ban the IP, and strip out the hostname. The correct way is to write a lengthy regular expression to match just whatever’s between the [ and ]. (Note that you can’t just write a regular expression to match IPs: the very first one has an IP in its hostname, for example, which would throw you off.)

The quick and easy solution is to replace the [ with a space and the ] with a space, which gives you “hostname IP “. And then you use awk again to print it:

grep bumttwagnerfor /var/log/messages | awk '{ print $10}' | sed "s/[/ /g" | sed "s/]/ /g" | awk '{print $2}'

This is a pretty ugly command. Just the way I like it. 😉

But we’re not quite done! The format for hosts.deny is “Service: Address.” We’re just getting addresses here. I want the output to be something like ALL: 1.2.3.4 for each entry. (If they’re spamming me, I don’t want to allow them access to any other services.)

When it’s all said and done, here’s the command:

grep bumttwagnerfor /var/log/messages | awk '{ print $10}' | sed "s/[/ /g" | sed "s/]/ /g" | awk '{print "ALL", $2}'

You can just append a >> hosts.deny to deny them right away, or parse it through head or less to review first.

And viola. 440 IPs banned.

Seriously, though. wtf is going on? 440 different people have tried spamming this address that has definitely never existed.

6 thoughts on “Fun with Shell Commands

  1. Thanks to Andrew for teaching me how uniq works… You have to sort first. So appending a | sort | uniq will weed out dupes. (Oddly, there were very few.)

    Here’s another fun one: Get a list of bouncing mail addresses:

    grep “Recipient address rejected” /var/log/messages | awk ‘{print $13}’ | sed “s// /g” | awk ‘{print $1}’ | sort | uniq

    (The verbiage probably changes if you’re not using Postfix, and just searching for “550” produces some extraneous results.)

  2. :-[

    I set up a Mailman list for the BSGO. I set you as a “Moderator,” thinking it would let you send mail to the list. It apparently instead forwards all the bounces to you.

    Next time I’ll figure out what it does before having it send you 100 e-mails. :-[

  3. Bah, php’s system() doesn’t have the privileges to view /var/log/messages… Which I suppose is kind of a good thing?

    The workaround is to write some back-end process that gets the data and lets PHP read it… But that’s far too much work for tonight.

Leave a Reply

Your email address will not be published. Required fields are marked *