Dec 062010
 

This time i’ll show you how to randomize your smtp outbound’s IP addresses. This can be done via transport map. But, since ordinary Postfix lookup tables store information as (key, value) pairs. it will provide static value only. we need someting that can manipulate the value (right hand side) of a lookup table. In order to answer random transport value.

first come to mind was tcp_tables, tcp_tables lookup table gives some flexibility for us to execute our tiny perl script that will randomizing transport. that’s the basic idea.

Ok, here’s the first part, create perl script call random.pl, anyway this script only provide answer in “catch-all” manner. so it will randomized, all outgoing mail.

# cd /etc/postfix
# vi random.pl
#!/usr/bin/perl -w
# author: Hari Hendaryanto <hari.h -at- csmcom.com>

use strict;
use warnings;
use Sys::Syslog qw(:DEFAULT setlogsock);

#
# our transports array, we will define this in master.cf as transport services
#

our @array = (
'rotate1:',
'rotate2:',
'rotate3:',
'rotate4:',
'rotate5:'
);

#
# Initalize and open syslog.
#
openlog('postfix/randomizer','pid','mail');

#
# Autoflush standard output.
#
select STDOUT; $|++;

while (<>) {
        chomp;
        # randomizing transports array
        my $random_smtp = int(rand(scalar(@array)));
        if (/^get\s(.+)$/i) {
                print "200 $array[$random_smtp]\n";
                syslog("info","Using: %s Transport Service", $random_smtp);
                next;
        }

	print "200 smtp:";
}

Make it executable

# chmod 755 random.pl

master.cf parts

Run the scripts via postfix spawn daemon service.

127.0.0.1:2527 inet  n       n       n       -       0      spawn
          user=nobody argv=/etc/postfix/random.pl

add 5 smtp client services called rotate1, rotate2, rotate3, rotate4, rotate5, that bind to its own ip
address and has uniq syslog/helo name.

# random smtp
rotate1  unix -       -       n       -       -       smtp
          -o syslog_name=postfix-rotate1
          -o smtp_helo_name=smtp1.example.com
          -o smtp_bind_address=1.2.3.1

rotate2  unix -       -       n       -       -       smtp
          -o syslog_name=postfix-rotate2
          -o smtp_helo_name=smtp2.example.com
          -o smtp_bind_address=1.2.3.2

rotate3  unix -       -       n       -       -       smtp
          -o syslog_name=postfix-rotate3
          -o smtp_helo_name=smtp3.example.com
          -o smtp_bind_address=1.2.3.3

rotate4  unix -       -       n       -       -       smtp
          -o syslog_name=postfix-rotate4
          -o smtp_helo_name=smtp4.example.com
          -o smtp_bind_address=1.2.3.4

rotate5  unix -       -       n       -       -       smtp
          -o syslog_name=postfix-rotate5
          -o smtp_helo_name=smtp5.example.com
          -o smtp_bind_address=1.2.3.5

Before we actually implement our randomize transport, let’s make sure that the setting actually work.

Reload postfix

# postfix reload

Run this query fiew times, and you’ll see the perl script will return “random answer” transport

# postmap -q "whatever" tcp:127.0.0.1:2527
rotate1:
# postmap -q "whatever" tcp:127.0.0.1:2527
rotate5:

And so on..

Note on “whatever”, since the script acted in “catch-all” mode as i’ve mentioned earlier, what ever postfix transport_maps client asked. it will be answered with random values such as rotate1, rotate2, rotate3, rotate4, rotate5 in randomized fashion.

main.cf parts

Add these lines

transport_maps = tcp:[127.0.0.1]:2527
127.0.0.1:2527_time_limit = 3600s

Reload postfix
that’s it. example log would be like these and that’s indicate that randomizer is working.

Month date 12:26:53 host postfix-rotate1/smtp[4252]: A1CA68480A4: to=<xxx@example.com>, relay=mx.example.com.com[xx.xx.xxx.xx]:25], delay=3.6, delays=0.69/0.01/0.81/2, dsn=2.0.0, status=sent (250 ok dirdel)
--snip--
Month date 12:27:06 host postfix-rotate5/smtp[4253]: 41C2E8480A4: to=<xxx@example.net>, relay=mx.example.net[xx.xxx.xxx.xxx]:25], delay=6, delays=0.14/0.01/0.85/5, dsn=2.0.0, status=sent (250 ok dirdel)
--snip--
Month date 12:27:22 host postfix-rotate3/smtp[4277]: 4BA9F8480A4: to=<xxx@example.org>, relay=mx.example.org[xx.xxx.xx.xxx]:25], delay=7.9, delays=0.85/0.02/0.61/6.4, dsn=2.0.0, status=sent (250 ok dirdel)

disclaimer:
I’m not taking any responsible if the reader “misuse” this tutorial.the tutorial is provide as-is for experimental purposes.

use Sys::Syslog qw(:DEFAULT setlogsock);
Share

  70 Responses to “Postfix Randomizing Outgoing IP Using TCP_TABLE And Perl”

Comments (69) Pingbacks (1)
  1. I’ve deployed this configuration, but it has a strange behaviour…


    Delivered-To: jesusrafael@gmail.com
    Received: by 10.194.16.5 with SMTP id b5csp211917wjd;
    Sun, 11 Nov 2012 13:18:54 -0800 (PST)
    Received: by 10.69.1.1 with SMTP id bc1mr52225163pbd.102.1352668734095;
    Sun, 11 Nov 2012 13:18:54 -0800 (PST)
    Return-Path:
    Received: from mail2.quedondeycuanto.com (mail3.quedondeycuanto.com. [184.95.62.36])
    by mx.google.com with ESMTP id ux7si6960278pbc.12.2012.11.11.13.18.53;
    Sun, 11 Nov 2012 13:18:53 -0800 (PST)
    Received-SPF: pass (google.com: domain of info@quedondeycuanto.com designates 184.95.62.36 as permitted sender) client-ip=184.95.62.36;
    Authentication-Results: mx.google.com; spf=pass (google.com: domain of info@quedondeycuanto.com designates 184.95.62.36 as permitted sender) smtp.mail=info@quedondeycuanto.com
    Received: by ns1.quedondeycuanto.com (Postfix, from userid 514)
    id 79FA76EE006A; Sun, 11 Nov 2012 17:18:52 -0400 (AST)
    From: "Correo Destinatario"
    Subject: prueba
    To: jesusrafael@gmail.com
    Message-Id:
    Cc: gsusrafael@hotmail.com
    X-Originating-IP: 190.167.170.29
    X-Mailer: Usermin 1.520
    Date: Sun, 11 Nov 2012 17:18:52 -0400 (AST)
    Content-Type: text/plain

    could you please explain this to me?

    • can you point me what exactly “strange behaviour” specifically? i’ve just seen different helo name bound to different ip/hostname there.
      that might be typo in your master.cf.

      • It isn’t a typo, anyways i’ll check it again…


        from mail2.quedondeycuanto.com (mail3.quedondeycuanto.com. [184.95.62.36])

        but the rotator must only change the ip address and its respective hostname, unlike is shown above

  2. Right now there is other problem…


    This is the mail system at host ns1.quedondeycuanto.com.

    I'm sorry to have to inform you that your message could not
    be delivered to one or more recipients. It's attached below.

    For further assistance, please send mail to postmaster.

    If you do so, please include this problem report. You can
    delete your own text from the attached returned message.

    The mail system

    (expanded from
    ): unknown user:
    "jjescobar.quedondeycuanto@ns1.quedondeycuanto.com"

    Final-Recipient: rfc822; jjescobar.quedondeycuanto@ns1.quedondeycuanto.com
    Original-Recipient: rfc822;jjescobar@quedondeycuanto.com
    Action: failed
    Status: 5.1.1
    Diagnostic-Code: X-Postfix; unknown user:
    "jjescobar.quedondeycuanto@ns1.quedondeycuanto.com"

    • This is the log part i got…


      Nov 18 23:11:05 ns1 postfix/virtual[12699]: 2AE0D6EE0082: to=jjescobar.quedondeycuanto@ns1.quedondeycuanto.com>, orig_to=, relay=virtual, delay=1.4, delays=1.3/0.01/0/0.03, dsn=5.1.1, status=bounced (unknown user: "jjescobar.quedondeycuanto@ns1.quedondeycuanto.com")

      • when i first wrote the article, it was intended to be used for outgoing email only, no local/virtual user in the system.
        script works in catchall ways. but you can always make exception for local/virtual user in the script.

        example:

        while (<>) {
                chomp;
                # randomizing transports array
                my $random_smtp = int(rand(scalar(@array)));
                if (/^get\s(.+)$/i) {
                        my $local_domain = $1;
                        $local_domain =~ s/.*\@//i;
                        if ($local_domain eq "ns1.quedondeycuanto.com") {
                           print "200 local:\n";
                        } else {
                           print "200 $array[$random_smtp]\n";
                        }
                        next;
                }
         
            print "200 smtp:";
        }
        

        cheers

  3. Hi I would like to have postfix listen to as many as 20-30 different IP/Domain combinations and when sending email use the specific IP/Domain info in the header as was used by the client.
    For example:

    User 1 uses the domain mail.mymail1.com to send email with IP 1.1.1.1

    User 2 uses the domain mail.mymail2.com to send email with IP 2.2.2.2

    I need the header of each email to use that specific domain/ip per user.

    Please Help,
    Thanks

  4. Using your solution how we can implement Throttling per domain? It’s possible? Because Throttling involve to manipule the transport too.

    Thanks,
    Wilson

 Leave a Reply

(required)

(required)


*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>