# -*- ruby -*-

s25r = Object.new
s25r.instance_eval do
  @whitelist = []
  @blacklist = []
  @only_check_ipv4 = true
end

class << s25r
  def add_whitelist(host_matcher=Proc.new)
    @whitelist << host_matcher
  end

  def add_blacklist(host_matcher=Proc.new)
    @blacklist << host_matcher
  end

  def white?(host, address)
    return true if only_check_ipv4? and !address.ipv4?
    match?(@whitelist, host)
  end

  def black?(host, address)
    return false if only_check_ipv4? and !address.ipv4?
    match?(@blacklist, host)
  end

  def only_check_ipv4?
    @only_check_ipv4
  end

  def only_check_ipv4=(boolean)
    @only_check_ipv4 = boolean
  end

  private
  def match?(list, host)
    list.any? do |matcher|
      if matcher.respond_to?(:call)
        matcher.call(host)
      else
        matcher === host
      end
    end
  end
end

singleton_class = class << self; self; end
singleton_class.send(:define_method, :s25r) do
  s25r
end

s25r.add_whitelist(/\.google\.com\z/)
s25r.add_whitelist(/\.obsmtp\.com\z/)
s25r.add_whitelist(/\.smtp-out\.amazonses\.com\z/)
s25r.add_whitelist(/\.slack\.com\z/)
s25r.add_whitelist(/\.mg\.gitlab\.com\z/)
s25r.add_whitelist(/\.sendgrid\.net\z/)

s25r.add_blacklist("unknown")
s25r.add_blacklist(/\A\[.+\]\z/)
s25r.add_blacklist(/\A[^.]*\d[^\d.]+\d.*\./)
s25r.add_blacklist(/\A[^.]*\d{5}/)
s25r.add_blacklist(/\A(?:[^.]+\.)?\d[^.]*\.[^.]+\..+\.[a-z]/i)
s25r.add_blacklist(/\A[^.]*\d\.[^.]*\d-\d/)
s25r.add_blacklist(/\A[^.]*\d\.[^.]*\d\.[^.]+\..+\./)
s25r.add_blacklist(/\A(?:dhcp|dialup|ppp|[achrsvx]?dsl)[^.]*\d/i)

define_applicable_condition("S25R") do |condition|
  condition.description = "Selective SMTP Rejection"

  condition.define_connect_stopper do |context, host, address|
    if s25r.white?(host, address)
      true
    elsif s25r.black?(host, address)
      false
    else
      true
    end
  end
end
