From a75d916b74a78f3d1f9a07eaf7920f113569bc9f Mon Sep 17 00:00:00 2001
From: Michael Kuron <m.kuron@gmx.de>
Date: Mon, 17 Apr 2017 15:42:35 +0200
Subject: [PATCH] Forwarding hosts in postscreen

---
 data/Dockerfiles/postfix/Dockerfile           |  1 +
 data/conf/postfix/main.cf                     |  2 +-
 data/conf/postfix/master.cf                   |  2 +
 .../conf/postfix/whitelist_forwardinghosts.sh | 11 ++++
 data/conf/rspamd/dynmaps/forwardinghosts.php  | 53 +++++++++++++++++++
 5 files changed, 68 insertions(+), 1 deletion(-)
 create mode 100755 data/conf/postfix/whitelist_forwardinghosts.sh
 create mode 100644 data/conf/rspamd/dynmaps/forwardinghosts.php

diff --git a/data/Dockerfiles/postfix/Dockerfile b/data/Dockerfiles/postfix/Dockerfile
index 0fcdc893..ba004827 100644
--- a/data/Dockerfiles/postfix/Dockerfile
+++ b/data/Dockerfiles/postfix/Dockerfile
@@ -23,6 +23,7 @@ RUN apt-get install -y --no-install-recommends supervisor \
 	gnupg \
 	python-gpgme \
 	sudo \
+	curl \
 	dirmngr
 
 RUN addgroup --system --gid 600 zeyple
diff --git a/data/conf/postfix/main.cf b/data/conf/postfix/main.cf
index b28f6eb9..52e86681 100644
--- a/data/conf/postfix/main.cf
+++ b/data/conf/postfix/main.cf
@@ -24,7 +24,7 @@ milter_default_action = accept
 milter_protocol = 6
 minimal_backoff_time = 300s
 plaintext_reject_code = 550
-postscreen_access_list = permit_mynetworks, cidr:/opt/postfix/conf/postscreen_access.cidr
+postscreen_access_list = permit_mynetworks, cidr:/opt/postfix/conf/postscreen_access.cidr, tcp:127.0.0.1:10027
 postscreen_bare_newline_enable = no
 postscreen_blacklist_action = drop
 postscreen_cache_cleanup_interval = 24h
diff --git a/data/conf/postfix/master.cf b/data/conf/postfix/master.cf
index 3802c9a0..61aeb592 100644
--- a/data/conf/postfix/master.cf
+++ b/data/conf/postfix/master.cf
@@ -55,3 +55,5 @@ zeyple    unix  -       n       n       -       -       pipe
   -o smtpd_recipient_restrictions=permit_mynetworks,reject
   -o mynetworks=127.0.0.0/8
   -o smtpd_authorized_xforward_hosts=127.0.0.0/8
+
+127.0.0.1:10027 inet  n       n       n       -       0      spawn user=nobody argv=/opt/postfix/conf/whitelist_forwardinghosts.sh
diff --git a/data/conf/postfix/whitelist_forwardinghosts.sh b/data/conf/postfix/whitelist_forwardinghosts.sh
new file mode 100755
index 00000000..aa9df608
--- /dev/null
+++ b/data/conf/postfix/whitelist_forwardinghosts.sh
@@ -0,0 +1,11 @@
+#!/bin/bash
+
+while true; do
+	read QUERY
+	QUERY=($QUERY)
+	if [ "${QUERY[0]}" != "get" ]; then
+		echo "500 dunno"
+		continue
+	fi
+	echo $(curl -s http://172.22.1.251:8081/forwardinghosts.php?host=${QUERY[1]})
+done
diff --git a/data/conf/rspamd/dynmaps/forwardinghosts.php b/data/conf/rspamd/dynmaps/forwardinghosts.php
new file mode 100644
index 00000000..95773e45
--- /dev/null
+++ b/data/conf/rspamd/dynmaps/forwardinghosts.php
@@ -0,0 +1,53 @@
+<?php
+header('Content-Type: text/plain');
+require_once "vars.inc.php";
+
+ini_set('error_reporting', 0);
+
+function in_net($addr, $net)
+{
+	$net = explode('/', $net);
+	$mask = $net[1];
+	$net = inet_pton($net[0]);
+	$addr = inet_pton($addr);
+
+	$length = strlen($net); // 4 for IPv4, 16 for IPv6
+	if (strlen($net) != strlen($addr))
+		return FALSE;
+
+	$addr_bin = '';
+	$net_bin = '';
+	for ($i = 0; $i < $length; ++$i)
+	{
+		$addr_bin .= str_pad(decbin(ord(substr($addr, $i, $i+1))), 8, '0', STR_PAD_LEFT);
+		$net_bin .= str_pad(decbin(ord(substr($net, $i, $i+1))), 8, '0', STR_PAD_LEFT);
+	}
+
+	return substr($addr_bin, 0, $mask) == substr($net_bin, 0, $mask);
+}
+
+$dsn = $database_type . ':host=' . $database_host . ';dbname=' . $database_name;
+$opt = [
+    PDO::ATTR_ERRMODE            => PDO::ERRMODE_EXCEPTION,
+    PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
+    PDO::ATTR_EMULATE_PREPARES   => false,
+];
+try {
+  $pdo = new PDO($dsn, $database_user, $database_pass, $opt);
+  $stmt = $pdo->query("SELECT * FROM `forwarding_hosts`");
+  $networks = $stmt->fetchAll(PDO::FETCH_COLUMN);
+  foreach ($networks as $network)
+  {
+    if (in_net($_GET['host'], $network))
+    {
+      echo '200 permit';
+      exit;
+    }
+  }
+  echo '200 dunno';
+}
+catch (PDOException $e) {
+  echo 'settings { }';
+  exit;
+}
+?>