Ejemplo n.º 1
0
    def examine(self, suspect):
        if not HAVE_SRS:
            return DUNNO

        forward_domain = self.config.get(self.section, 'forward_domain')
        if suspect.to_domain != forward_domain:
            self.logger.debug('SRS: ignoring mail to %s - only accepting %s' %
                              (suspect.to_address, forward_domain))
            return DUNNO

        action = DUNNO
        message = None

        srs = self._init_srs()
        if suspect.to_address.lower().startswith('srs'):
            orig_rcpt = suspect.to_address
            try:
                recipient = srs.reverse(orig_rcpt)
                self.logger.info('SRS: decrypted bounce address %s to %s' %
                                 (orig_rcpt, recipient))
            except Exception as e:
                self.logger.error('SRS: Failed to decrypt %s reason: %s' %
                                  (orig_rcpt, str(e)))
                action = REJECT
                message = apply_template(
                    self.config.get(self.section, 'messagetemplate'), suspect)
        else:
            self.logger.debug('SRS: ignoring unsigned address %s' %
                              (suspect.to_address))
            if not self.config.getboolean(self.section, 'accept_unsigned'):
                action = REJECT
                message = apply_template(
                    self.config.get(self.section, 'messagetemplate'), suspect)

        return action, message
Ejemplo n.º 2
0
    def examine(self, suspect):
        if not HAVE_DNS:
            return DUNNO

        from_address = suspect.get_value('sender')
        if from_address is None:
            self.logger.warning('No FROM address found')
            return DEFER_IF_PERMIT, 'internal policy error (no from address)'

        from_address = strip_address(from_address)
        from_domain = extract_domain(from_address)

        if self._is_whitelisted(from_domain):
            return DUNNO

        from_address = self._email_normalise(from_address)
        addr_hash = self._create_hash(from_address)
        listed, message = self._ebl_lookup(addr_hash)

        if listed:
            values = {
                'dnszone': self.config.get(self.section, 'dnszone',
                                           '').strip(),
                'message': message,
            }
            message = apply_template(
                self.config.get(self.section, 'messagetemplate'), suspect,
                values)
            return REJECT, message
        else:
            return DUNNO
Ejemplo n.º 3
0
    def examine(self,suspect):

        helo_name=suspect.get_value('helo_name')

        if helo_name is None :
            self.logger.error('missing helo')
            return DUNNO

        helo_tld=helo_name.split('.')[-1].lower()

        #initialize loaders
        tld_file=self.config.get(self.section,'tldfile')
        if self.tld_loader is None:
            self.tld_loader=FileList(tld_file,lowercase=True,minimum_time_between_reloads=3600)

        if helo_tld in self.tld_loader.get_list():
            return DUNNO,''

        exceptionfile=self.config.get(self.section,'exceptionfile')
        if self.exception_loader is None:
            self.exception_loader=FileList(exceptionfile,lowercase=True,minimum_time_between_reloads=10)

        if helo_tld in self.exception_loader.get_list():
            return DUNNO,''

        message = apply_template(self.config.get(self.section,'messagetemplate'),suspect,dict(helo_tld=helo_tld))
        action=self.config.get(self.section,"on_fail")

        return action, message
Ejemplo n.º 4
0
    def examine(self, suspect):

        helo_name = suspect.get_value('helo_name')

        if helo_name is None:
            self.logger.error('missing helo')
            return DUNNO

        helo_tld = helo_name.split('.')[-1].lower()

        #initialize loaders
        tld_file = self.config.get(self.section, 'tldfile')
        if self.tld_loader is None:
            self.tld_loader = FileList(tld_file,
                                       lowercase=True,
                                       minimum_time_between_reloads=3600)

        if helo_tld in self.tld_loader.get_list():
            return DUNNO, ''

        exceptionfile = self.config.get(self.section, 'exceptionfile')
        if self.exception_loader is None:
            self.exception_loader = FileList(exceptionfile,
                                             lowercase=True,
                                             minimum_time_between_reloads=10)

        if helo_tld in self.exception_loader.get_list():
            return DUNNO, ''

        message = apply_template(
            self.config.get(self.section, 'messagetemplate'), suspect,
            dict(helo_tld=helo_tld))
        action = self.config.get(self.section, "on_fail")

        return action, message
Ejemplo n.º 5
0
    def examine(self, suspect):
        if not DNSQUERY_EXTENSION_ENABLED:
            return DUNNO
        
        from_address=suspect.get_value('sender')
        if from_address is None:
            self.logger.warning('No FROM address found')
            return DEFER_IF_PERMIT,'internal policy error (no from address)'
        
        from_address=strip_address(from_address)
        if self.config.getboolean(self.section,'check_srs_only') and not self._is_srs(from_address):
            self.logger.info('skipping non SRS address %s' % from_address)
            return DUNNO
        
        if HAVE_SRS and self.config.getboolean(self.section,'decode_srs'):
            from_address = self._decode_srs(from_address)

        from_domain=extract_domain(from_address)
        if self._is_whitelisted(from_domain):
            return DUNNO
        
        from_address = self._email_normalise(from_address)
        addr_hash = self._create_hash(from_address)
        listed, message = self._ebl_lookup(addr_hash)
        
        if listed:
            values = {
                'dnszone': self.config.get(self.section,'dnszone','').strip(),
                'message': message,
            }
            message = apply_template(self.config.get(self.section,'messagetemplate'),suspect, values)
            return REJECT, message
        else:
            return DUNNO
Ejemplo n.º 6
0
    def examine(self, suspect):
        if not HAVE_SPF:
            return DUNNO

        client_address = suspect.get_value('client_address')
        helo_name = suspect.get_value('helo_name')
        sender = suspect.get_value('sender')
        if client_address is None or helo_name is None or sender is None:
            self.logger.error('missing client_address or helo or sender')
            return DUNNO

        if self.ip_whitelisted(client_address):
            self.logger.info("Client %s is whitelisted - no SPF check" %
                             client_address)
            return DUNNO

        sender_email = strip_address(sender)
        if sender_email == '' or sender_email is None:
            return DUNNO

        sender_domain = extract_domain(sender_email)
        if sender_domain is None:
            self.logger.error('no domain found in sender address %s' %
                              sender_email)
            return DUNNO

        if not self.check_this_domain(sender_domain):
            self.logger.debug('skipping SPF check for %s' % sender_domain)
            return DUNNO

        result, explanation = spf.check2(client_address, sender_email,
                                         helo_name)
        suspect.tags['spf'] = result
        if result != 'none':
            self.logger.info(
                'SPF client=%s, sender=%s, h=%s result=%s : %s' %
                (client_address, sender_email, helo_name, result, explanation))

        action = DUNNO
        message = apply_template(
            self.config.get(self.section, 'messagetemplate'), suspect,
            dict(result=result, explanation=explanation))

        configopt = 'on_%s' % result
        if self.config.has_option(self.section, configopt):
            action = string_to_actioncode(
                self.config.get(self.section, configopt))

        return action, message
Ejemplo n.º 7
0
    def examine(self,suspect):
        if not have_spf:
            return DUNNO
        
        client_address=suspect.get_value('client_address')
        helo_name=suspect.get_value('helo_name')
        sender=suspect.get_value('sender')
        if client_address is None or helo_name is None or sender is None:
            self.logger.error('missing client_address or helo or sender')
            return DUNNO

        if self.ip_whitelisted(client_address):
            self.logger.info("Client %s is whitelisted - no SPF check"%client_address)
            return DUNNO

        sender_email = strip_address(sender)
        if sender_email=='' or sender_email is None:
            return DUNNO

        selective_sender_domain_file=self.config.get(self.section,'domain_selective_spf_file')
        if selective_sender_domain_file!='':
            if self.selective_domain_loader is None:
                self.selective_domain_loader=FileList(selective_sender_domain_file,lowercase=True)
            try:
                sender_domain = extract_domain(sender_email)
                if sender_domain is None:
                    return DUNNO
            except ValueError as e:
                self.logger.warning(str(e))
                return DUNNO
            if not sender_domain.lower() in self.selective_domain_loader.get_list():
                return DUNNO

        result, explanation = spf.check2(client_address, sender_email, helo_name)
        suspect.tags['spf']=result
        if result!='none':
            self.logger.info('SPF client=%s, sender=%s, h=%s result=%s : %s' % (client_address, sender_email, helo_name, result,explanation))
        
        action = DUNNO
        message = apply_template(self.config.get(self.section,'messagetemplate'),suspect,dict(result=result,explanation=explanation))

        configopt='on_%s'%result
        if self.config.has_option(self.section,configopt):
            action=self.config.get(self.section,configopt)

        return action, message
Ejemplo n.º 8
0
    def examine(self, suspect):
        encryption_protocol = suspect.get_value('encryption_protocol')
        recipient=suspect.get_value('recipient')
        
        rcpt_email = strip_address(recipient)
        if rcpt_email=='' or rcpt_email is None:
            return DUNNO

        enforce = self.enforce_domain(extract_domain(rcpt_email))

        action = DUNNO
        message = None
        if enforce and encryption_protocol == '':
            action=string_to_actioncode(self.config.get(self.section, 'action'))
            message = apply_template(self.config.get(self.section,'messagetemplate'),suspect)
            
        return action, message
Ejemplo n.º 9
0
    def examine(self, suspect):
        encryption_protocol = suspect.get_value('encryption_protocol')
        recipient=suspect.get_value('recipient')
        
        rcpt_email = strip_address(recipient)
        if rcpt_email=='' or rcpt_email is None:
            return DUNNO

        enforce = self.enforce_domain(extract_domain(rcpt_email))

        action = DUNNO
        message = None
        if enforce and encryption_protocol == '':
            action=string_to_actioncode(self.config.get(self.section, 'action'))
            message = apply_template(self.config.get(self.section,'messagetemplate'),suspect)
            
        return action, message
Ejemplo n.º 10
0
    def examine(self,suspect):
        if not HAVE_SPF:
            return DUNNO
        
        client_address=suspect.get_value('client_address')
        helo_name=suspect.get_value('helo_name')
        sender=suspect.get_value('sender')
        if client_address is None or helo_name is None or sender is None:
            self.logger.error('missing client_address or helo or sender')
            return DUNNO

        if self.ip_whitelisted(client_address):
            self.logger.info("Client %s is whitelisted - no SPF check"%client_address)
            return DUNNO

        sender_email = strip_address(sender)
        if sender_email=='' or sender_email is None:
            return DUNNO
        
        sender_domain = extract_domain(sender_email)
        if sender_domain is None:
            self.logger.error('no domain found in sender address %s' % sender_email)
            return DUNNO
        
        if not self.check_this_domain(sender_domain):
            self.logger.debug('skipping SPF check for %s' % sender_domain)
            return DUNNO

        result, explanation = spf.check2(client_address, sender_email, helo_name)
        suspect.tags['spf'] = result
        if result != 'none':
            self.logger.info('SPF client=%s, sender=%s, h=%s result=%s : %s' % (client_address, sender_email, helo_name, result,explanation))
        
        action = DUNNO
        message = apply_template(self.config.get(self.section, 'messagetemplate'), suspect, dict(result=result, explanation=explanation))

        configopt = 'on_%s' % result
        if self.config.has_option(self.section, configopt):
            action=string_to_actioncode(self.config.get(self.section, configopt))

        return action, message
Ejemplo n.º 11
0
 def examine(self,suspect):
     starttime=time.time()
     retaction=DUNNO
     retmessage=None
     self.reload_if_necessary()
     
     to_domain=suspect.to_domain
     to_address=suspect.to_address
     
     for rec in [to_address,to_domain,'global']:
         if rec in self.ruledict:
             lg.debug("Found rules for %s"%rec)
             for recrule in self.ruledict[rec]:
                 result=recrule.hit(suspect)
                 if result:
                     return recrule.action,apply_template(recrule.message,suspect)
     
     endtime=time.time()
     difftime=endtime-starttime
     suspect.tags['RecipientRules.time']="%.4f"%difftime
     return retaction,retmessage
Ejemplo n.º 12
0
    def examine(self, suspect):
        if HAVE_GEOIP == LIB_GEOIP_NONE:
            return DUNNO

        database = self.config.get(self.section, 'database')
        if not os.path.exists(database):
            return DUNNO
        self.geoip.filename = database
        self.geoip.reloadifnecessary(database)

        client_address = suspect.get_value('client_address')
        if client_address is None:
            self.logger.info('No client address found')
            return DUNNO

        blacklist = self._get_list('blacklist')
        whitelist = self._get_list('whitelist')
        on_unknown = self.config.get(self.section, 'on_unknown')
        unknown = DUNNO
        if on_unknown.strip().upper() == 'REJECT':
            unknown = REJECT

        cc = self.geoip.country_code(client_address)
        cn = self.geoip.country_name(cc)

        action = DUNNO
        message = None

        if cn == 'unknown':
            action = unknown
        elif cc in blacklist or (whitelist and cc not in whitelist):
            action = REJECT

        if action == REJECT:
            rejmsg = self.config.get(self.section, 'reject_message').strip()
            message = apply_template(rejmsg, suspect, dict(cn=cn, cc=cc))

        self.logger.debug('IP: %s country: %s action: %s' %
                          (client_address, cc, action))
        return action, message
Ejemplo n.º 13
0
    def examine(self, suspect):
        starttime = time.time()
        retaction = DUNNO
        retmessage = None
        self.reload_if_necessary()

        to_domain = suspect.to_domain
        to_address = suspect.to_address

        for rec in [to_address, to_domain, 'global']:
            if rec in self.ruledict:
                lg.debug("Found rules for %s" % rec)
                for recrule in self.ruledict[rec]:
                    result = recrule.hit(suspect)
                    if result:
                        return recrule.action, apply_template(
                            recrule.message, suspect)

        endtime = time.time()
        difftime = endtime - starttime
        suspect.tags['RecipientRules.time'] = "%.4f" % difftime
        return retaction, retmessage
Ejemplo n.º 14
0
    def examine(self, suspect):
        if not DNSQUERY_EXTENSION_ENABLED:
            return DUNNO

        from_address = suspect.get_value('sender')
        if from_address is None:
            self.logger.warning('No FROM address found')
            return DEFER_IF_PERMIT, 'internal policy error (no from address)'

        from_address = strip_address(from_address)
        if self.config.getboolean(
                self.section,
                'check_srs_only') and not self._is_srs(from_address):
            self.logger.info('skipping non SRS address %s' % from_address)
            return DUNNO

        if HAVE_SRS and self.config.getboolean(self.section, 'decode_srs'):
            from_address = self._decode_srs(from_address)

        from_domain = extract_domain(from_address)
        if self._is_whitelisted(from_domain):
            return DUNNO

        from_address = self._email_normalise(from_address)
        addr_hash = self._create_hash(from_address)
        listed, message = self._ebl_lookup(addr_hash)

        if listed:
            values = {
                'dnszone': self.config.get(self.section, 'dnszone',
                                           '').strip(),
                'message': message,
            }
            message = apply_template(
                self.config.get(self.section, 'messagetemplate'), suspect,
                values)
            return REJECT, message
        else:
            return DUNNO
Ejemplo n.º 15
0
    def examine(self,suspect):
        if HAVE_GEOIP == LIB_GEOIP_NONE:
            return DUNNO
        
        database = self.config.get(self.section, 'database')
        if not os.path.exists(database):
            return DUNNO
        self.geoip.filename = database
        self.geoip._reload_if_necessary()
        
        client_address=suspect.get_value('client_address')
        if client_address is None:
            self.logger.info('No client address found')
            return DUNNO
        
        blacklist = self._get_list('blacklist')
        whitelist = self._get_list('whitelist')
        on_unknown = self.config.get(self.section, 'on_unknown')
        unknown = DUNNO
        if on_unknown.strip().upper() == 'REJECT':
            unknown = REJECT
        
        cc = self.geoip.country_code(client_address)
        cn = self.geoip.country_name(cc)
        
        action = DUNNO
        message = None
        
        if cn == 'unknown':
            action = unknown
        elif cc in blacklist or (whitelist and cc not in whitelist):
            action = REJECT
            
        if action == REJECT:
            rejmsg = self.config.get(self.section, 'reject_message').strip()
            message = apply_template(rejmsg, suspect, dict(cn=cn, cc=cc))

        self.logger.debug('IP: %s country: %s action: %s' % (client_address, cc, action))
        return action, message
Ejemplo n.º 16
0
    def examine(self, suspect):
        if self.limiters is None:
            filename = self.config.get(self.section, 'limiterfile')
            if not os.path.exists(filename):
                self.logger.error('Limiter config file %s not found', filename)
                return
            with open(filename) as filehandle:
                limiterconfig = filehandle.read()
            limiters = self.load_limiter_config(limiterconfig)
            self.limiters = limiters
            self.logger.info('Found %d limiter configurations', len(limiters))
            
            self.load_backends()

        skiplist = []
        for limiter in self.limiters:
            if limiter.name in skiplist: # check if this limiter is skipped by a previous one
                self.logger.debug('limiter %s skipped due to previous match', limiter.name)
                continue

            #get field values
            allfieldsavailable = True
            fieldvalues = []
            for fieldname in limiter.fields:
                if hasattr(suspect, fieldname):
                    fieldvalues.append(getattr(suspect, fieldname))
                elif suspect.get_tag(fieldname):
                    fieldvalues.append(str(suspect.get_tag(fieldname)))
                else:
                    allfieldsavailable = False
                    self.logger.debug('Skipping limiter %s - suspect field or tag %s not available',
                                      limiter.name, fieldname)
                    break
            if not allfieldsavailable: #rate limit can not be applied
                continue

            checkval = ','.join(fieldvalues)
            if limiter.regex is not None:
                if re.match(limiter.regex, checkval):
                    if limiter.skip is not None:
                        skiplist.extend(limiter.skip)
                else: #no match, skip this limiter
                    self.logger.debug('Skipping limiter %s - regex does not match', limiter.name)
                    continue

            eventname = limiter.name+checkval
            timespan = limiter.timespan

            if limiter.max < 0: #no limit
                continue

            try:
                (allow, count) = self.backends[limiter.strategy].check_allowed(eventname, limiter.max, timespan)
                self.logger.debug('Limiter event %s count: %d', eventname, count)
                if not allow:
                    return limiter.action, apply_template(limiter.message, suspect)
            except Exception as ex:
                error = type(ex).__name__, ex.message
                self.logger.error('Failed to run limitter backend for strategy "%s" eventname %s error %s',
                                  limiter.strategy,
                                  eventname,
                                  error)
Ejemplo n.º 17
0
    def examine(self, suspect):
        if self.limiters is None:
            filename = self.config.get(self.section, 'limiterfile')
            if not os.path.exists(filename):
                self.logger.error("Limiter config file %s not found" %
                                  filename)
                return
            with open(filename) as fp:
                limiterconfig = fp.read()
            limiters = self.load_limiter_config(limiterconfig)
            self.limiters = limiters
            self.logger.info("Found %s limiter configurations" %
                             (len(limiters)))

        if self.backend_instance is None:
            btype = self.config.get(self.section, 'backendtype')
            if btype not in AVAILABLE_RATELIMIT_BACKENDS:
                self.logger.error('ratelimit backend %s not available' %
                                  (btype))
                return
            self.backend_instance = AVAILABLE_RATELIMIT_BACKENDS[btype](
                self.config.get(self.section, 'backendconfig'))

        skiplist = []
        for limiter in self.limiters:
            if limiter.name in skiplist:  # check if this limiter is skipped by a previous one
                self.logger.debug('limiter %s skipped due to previous match' %
                                  limiter.name)
                continue

            #get field values
            allfieldsavailable = True
            fieldvalues = []
            for fieldname in limiter.fields:
                if hasattr(suspect, fieldname):
                    fieldvalues.append(getattr(suspect, fieldname))
                else:
                    allfieldsavailable = False
                    self.logger.debug(
                        'Skipping limiter %s - field %s not available' %
                        (limiter.name, fieldname))
                    break
            if not allfieldsavailable:  #rate limit can not be applied
                continue

            checkval = ','.join(fieldvalues)
            if limiter.regex is not None:
                if re.match(limiter.regex, checkval):
                    if limiter.skip is not None:
                        skiplist.extend(limiter.skip)
                else:  #no match, skip this limiter
                    self.logger.debug(
                        'Skipping limiter %s - regex does not match' %
                        (limiter.name))
                    continue
            #self.logger.debug("check %s"%str(limiter))
            eventname = limiter.name + checkval
            timespan = limiter.timespan
            max = limiter.max
            if max < 0:  #no limit
                continue
            event_count = self.backend_instance.check_count(
                eventname, timespan)
            self.logger.debug("Limiter event %s  count: %s" %
                              (eventname, event_count))
            if event_count > max:
                return limiter.action, apply_template(limiter.message, suspect)