The Net Wizard HauptseiteISP SetupNetzwerkeVelotourenSoftwareKryptografieVaria

MYSQLList

Gesucht war ein Plugin für Samassassin, mit dem man eine per User basierte White- resp Blacklist in einer masql-Datenbank führen kann. Der Hintergrund dafür ist, dass man sppamassassin relativ leicht für unterschiedliche Kunden auf demselben Mailserver personalisieren kann, dass daür aber eine lokale Konfigurationsdatei auf dem Filesystem erforderlich ist. Mein Problem war, dass ich die Mails nur von Spam und Viren befreien muss, diese dann aber an den entsprechenden MDA weiterleiten muss. Folglich gibt es auch kein lokales Verzeichnis, in dem die ppersonalisierten Rules stehen können. Darum habe ich mich entschieden, diese Regeln zentral in einer Datenbank zu führen und spamassassin so anzupassen, dass diese Regeln berücksichtigt werden.
    001:
    002:
    003:
    004:
    005:
    006:
    007:
    008:
    009:
    010:
    011:
    012:
    013:
    014:
    015:
    016:
    017:
    018:
    019:
    020:
    021:
    022:
    023:
    024:
    025:
    026:
    027:
    028:
    029:
    030:
    031:
    032:
    033:
    034:
    035:
    036:
    037:
    038:
    039:
    040:
    041:
    042:
    043:
    044:
    045:
    046:
    047:
    048:
    049:
    050:
    051:
    052:
    053:
    054:
    055:
    056:
    057:
    058:
    059:
    060:
    061:
    062:
    063:
    064:
    065:
    066:
    067:
    068:
    069:
    070:
    071:
    072:
    073:
    074:
    075:
    076:
    077:
    078:
    079:
    080:
    081:
    082:
    083:
    084:
    085:
    086:
    087:
    088:
    089:
    090:
    091:
    092:
    093:
    094:
    095:
    096:
    097:
    098:
    099:
    100:
    101:
    102:
    103:
    104:
    105:
    106:
    107:
    108:
    109:
    110:
    111:
    112:
    113:
    114:
    115:
    116:
    117:
    118:
    119:
    120:
    121:
    122:
    123:
    124:
    125:
    126:
    127:
    128:
    129:
    130:
    131:
    132:
    133:
    134:
    135:
    136:
    137:
    138:
    139:
    140:
    141:
    142:
    143:
    144:
    145:
    146:
    147:
    148:
    149:
    150:
    151:
    152:
    153:
    154:
    155:
    156:
    157:
    158:
    159:
    160:
    161:
    162:
    163:
    164:
    165:
    166:
    167:
    168:
    169:
    170:
    171:
    172:
    173:
    174:
    175:
    176:
    177:
    178:
    179:
    180:
    181:
    182:
    183:
    184:
    185:
    186:
    187:
    188:
    189:
    190:
    191:
    192:
    193:
    194:
    195:
    196:
    197:
    198:
    199:
    200:
    201:
    202:
    203:
    204:
    205:
    206:
    207:
    208:
    209:
    210:
    211:
    212:
    213:
    214:
    215:
    216:
    217:
    218:
    219:
    220:
    221:
    222:
    223:
    224:
    225:
    226:
    227:
    228:
    229:
    230:
    231:
    232:
    233:
    234:
    235:
    236:
    237:
    238:
    239:
    240:
    241:
    242:
    243:
    244:
    245:
    246:
    247:
    248:
    249:
    250:
    251:
    252:
    253:
    254:
    255:
    256:
    257:
    258:
    259:
    260:
    261:
    262:
    263:
    264:
    265:
    266:
    267:
    268:
    269:
    270:
    271:
    272:
    273:
    274:
    275:
    276:
    277:
    278:
    279:
    280:
    281:
    282:
    283:
    284:
    285:
    286:
    287:
    288:
    289:
    290:
    291:
    292:
    293:
    294:
    295:
    296:
    297:
    298:
    299:
    300:
    301:
    302:
    303:
    304:
    305:
    306:
    307:
    308:
    309:
    310:
    311:
    312:
    313:
    314:
    315:
    316:
    317:
    318:
    319:
    320:
    321:
    322:
    323:
    324:
    325:
    326:
    #
    # Mail::SpamAssassin::Plugin::MYSQLList:
    # version 0.01, April 13, 2007
    #
    # Robert Meyer <r.meyer@net-wizard.org>
    #
    # <@LICENSE>
    # Copyright 2008 R. Meyer, r.meyer@net-wizard.org
    #
    # Licensed under the Apache License, Version 2.0 (the "License");
    # you may not use this file except in compliance with the License.
    # You may obtain a copy of the License at
    #
    #     http://www.apache.org/licenses/LICENSE-2.0
    #
    # CHANGELOG
    #
    # v0.0.1 -- initial release

    =head1 NAME
    Mail::SpamAssassin::Plugin::MYSQLList telist according to Sender / Recepient combinations found in a MYSQL-Database

    =head1 DESCRIPTION

    This plugin checks a mysql database for combinations of From and To adresses. If a match occurs,
    the score will be altered according to the value in the database

    I have tried to write this plugin as generic as possible (given my knoledge of Perl). It should be
    possible to add custom rules, defined in a mysql-DB. See coments below.

    A possible Configuration-File looks as follows:
    --- START CONFIG ---
    loadplugin MYSQLList mysqllist.pm

    header          MYSQLLIST_FROM_TO       eval:mysqllist_from_to()
    describe        MYSQLLIST_FROM_TO       Dynamic From-To pairs
    score           MYSQLLIST_FROM_TO       20.0

    mysqllist_host          localhost
    mysqllist_dbname        mysqllist
    mysqllist_user          mysqllist_user
    mysqllist_pwd           **********
    mysqllist_table         pairs
    --- END CONFIG ---


    =head1 SYNOPSIS

       loadplugin Mail::SpamAssassin::Plugin::MYSQLList mysqllist.pm

    =cut



    package Mail::SpamAssassin::Plugin::MYSQLList;
    #package MYSQLList;

    our $VERSION = "0.02";

    use strict;
    use Data::Dumper;
    use Mail::SpamAssassin;
    use Mail::SpamAssassin::Plugin;
    use DBI;
    our @ISA = qw(Mail::SpamAssassin::Plugin);

    #
    # register the module
    #
    sub new {

        # Object constructor

        my ($class, $permsgstatus) = @_;
        $class = ref($class) || $class;
        my $self = $class->SUPER::new($permsgstatus);
        bless ($self, $class);

        # Default values
        $self->{mysqllist_host} = "localhost";
        $self->{mysqllist_dbname} = "mysqllist";
        $self->{mysqllist_user} = "mysqllist_user";
        $self->{mysqllist_table} = "pairs";
        $self->{mysqllist_pwd} = "";


        # register the eval rules
        $self->register_eval_rule ("mysqllist_from_to");
        dbg ("MYSQLList: Done constructor");
        return $self;
    }

    #
    # this gets called as each parameter in the .cf file is encountered.
    #
    sub parse_config {

        # Get the config object
        #
        my ($self, $config) = @_;

        dbg ("MyPlugin: parse_config got ".$config->{line}."\n");
        dbg ("MYSQLList: $self->{mysqllist_host}, $self->{mysqllist_table}, $self->{mysqllist_dbname}, $self->{mysqllist_user}, $self->{mysqllist_pwd}");
        if ($config->{key} eq 'mysqllist_host') {
            $self->{mysqllist_host} = $config->{value};
            return 1;
        }

        if ($config->{key} eq 'mysqllist_table') {
            $self->{mysqllist_table} = $config->{value};
            return 1;
        }

        if ($config->{key} eq 'mysqllist_dbname') {
            $self->{mysqllist_dbname} = $config->{value};
            return 1;
        }

        if ($config->{key} eq 'mysqllist_user') {
            $self->{mysqllist_user} = $config->{value};
            return 1;
        }

        if ($config->{key} eq 'mysqllist_pwd') {
            $self->{mysqllist_pwd} = $config->{value};
            return 1;
        }
        dbg ("MYSQLList: Done parse_config");
    }

    # Mysql-Part.
    sub create_mysql_session {

        # suck down the permsgstatus object
        #
        my ($self, $permsgstatus) = @_;

        # clean up any possible leftover from previous sessions
        #
        undef $self->{mysql_session};

        if ( ! defined $self->{mysql_session} ) {

            dbg ("MYSQLList\: MYSQL session  does not exist ... connecting");
            dbg ("MYSQLList\: $self->{mysqllist_dbname},$self->{mysqllist_host},$self->{mysqllist_user},$self->{mysqllist_pwd}");

            $self->{mysql_session} = DBI->connect("dbi:mysql:$self->{mysqllist_dbname}:$self->{mysqllist_host}",
                        $self->{mysqllist_user},
                        $self->{mysqllist_pwd});
            $self->{mysql_session}->{'mysql_use_result'} = 1; #enable mysql_use_result
        }
        
        if ( ! defined $self->{mysql_session} ) {
            dbg ("MYSQLList\: Could mot connect to $self->mysqllist_host\n");
            return 0;
        } else {
            dbg ("MYSQLList\: Connected to $self->mysqllist_host\n");
        }

        return 1;
    }

    # The rules
    # A generic Rule-Subrutine contains the following Elents:
    # $self->get_mailinfo (e.g. $self->get_addr): Get the relevant Information out of the Mail
    # $self->init: Initialize DB-Connection ....
    # $self->set_score (If you want to get the score out of the DB, instead out of the Configuration).


    sub mysqllist_from_to {

        # Get $permsgstatus
        my ($self, $permsgstatus) = @_;

        # Need From: and To. Adresses
        if ( $self->get_addr($permsgstatus) == 0 ) {
            return 0;
        }
        dbg ("MYSQLList: Entering mysqllist_from_to\n");

        # Run rule only once per Mail
        #
        $self->init($permsgstatus) unless $permsgstatus->{searched};
        if ( defined $permsgstatus->{searched} ) {
            if ( $permsgstatus->{searched} != 0 ) {
                return 0;
            }
        }


        # set the {searched} flag to prevent multiple lookups per message
        #
        $permsgstatus->{searched} = 1;

        # Prepare the SQL-Statement
        # 
        my $sql_stmt="SELECT score FROM $self->{mysqllist_table} WHERE from_addr=? AND to_addr=?";
        $self->{mysql_prepare}=$self->{mysql_session}->prepare($sql_stmt);


        # Do the tests.
        $self->{score}=0;
        foreach my $f_addr (@{$self->{from_addr}}) {
            # Check for valid email-adress (catches most of the valid addresses)
            dbg("MYSQLList: t66 $f_addr");
            #next unless ( $f_addr =~ /^[\w-]+(?:\.[\w-]+)*@(?:[\w-]+\.)+[a-zA-Z]{2,7}$/ );
            foreach my $t_addr (@{$self->{to_addr}}) {
                dbg("MYSQLList: t67 $t_addr");
                #next unless ( $t_addr =~ /^[\w-]+(?:\.[\w-]+)*@(?:[\w-]+\.)+[a-zA-Z]{2,7}$/ );
                dbg ("MYSQLList $f_addr, $t_addr");
                $self->{mysql_prepare}->execute($f_addr,$t_addr);
                while ( my @row = $self->{mysql_prepare}->fetchrow_array ) {
                    if ( scalar @row > 0 ) {
                        $self->{score}=$row[0];
                    }
                }
            }
            if ( $self->{score} != 0 ) {
                last;
            }
        }
        if ( $self->{score} != 0 ) {
            #Set rulename, description and area (body vs. header) of your rule from the configuration file
            #required for dynamic scoring
            $self->{rulename} = "MYSQLLIST_FROM_TO";
            $self->{description} = $permsgstatus->{conf}->{descriptions}->{$self->{rulename}};
            $self->{area} = "HEADER: ";
            if ( $self->set_score($permsgstatus) == 0 ) {
                return 0;
            }
            #$permsgstatus->{mysqllist_from_to} = 1;
        }
        dbg ("MYSQLList: done mysqllist_from_to");

        return $permsgstatus->{mysqllist_from_to};
    }


    sub set_score {

        my ($self, $permsgstatus) = @_;

        if ( $self->{score} ) {
            #The magic call
            dbg ("t0 $self->{rulename},$self->{score},$self->{area},$self->{description}");
            $permsgstatus->_handle_hit("$self->{rulename}",$self->{score},"$self->{area}",$self->{description});

            #Yet another magic call
            #The for loop is necessary to set all 4 values
            for my $set (0..3) {
                $permsgstatus->{conf}->{scoreset}->[$set]->{$self->{rulename}} = sprintf("%0.3f", $self->{score});
            }
        }
        return 1;
    }


    sub get_addr {

        # suck down the permsgstatus object
        #
        my ($self, $permsgstatus) = @_;

        if (exists $permsgstatus->{all_from_addrs}) {
            $self->{from_addr} = $permsgstatus->{all_from_addrs};
        } else {
            return 0;
        }

        if (exists $permsgstatus->{all_to_addrs}) {
            $self->{to_addr} = $permsgstatus->{all_to_addrs};
        } else {
            return 0;
        }

        # No From, no action
        #
        if (! scalar @{$self->{from_addr}} >0 ) {
            dbg ("MYSQLList\: No From-Adress found, terminating");
            return 0;
        }

        # No To, no action
        #
        if (! scalar @{$self->{to_addr}} >0 ) {
            dbg ("MYSQLList\: No To-Adress found, terminating");
            return 0;
        }
        dbg ("MYSQLList: done get_addr");
        return 1;
    }

    sub init {

        # suck down the permsgstatus object
        #
        my ($self, $permsgstatus) = @_;

        # set the default return code values
        #
        $permsgstatus->{mysqllist_from_to} = 0;
        # see if an MYSQL session is already active
        #
        if (! defined $self->{mysql_session} ) {

            # try to create a session
            #
            if ($self->create_mysql_session($permsgstatus) == 0) {

                # unable to create a session so exit
                #
                return 0;
            } else {
                dbg ("Connecting to mysql");
            }
        }
        # End of part specific to from_to_list
        dbg ("MYSQLList: done init");
    }

    # Print debugging information
    sub dbg {
        Mail::SpamAssassin::dbg (@_);
    }

    1;

Powered by w3.css