Merge pull request #205 from mkuron/forwardinghosts
Add a "Forwarding Hosts" feature so messages from certain servers are never rejectedmaster
commit
29983dfe8d
|
@ -23,6 +23,7 @@ RUN apt-get install -y --no-install-recommends supervisor \
|
||||||
gnupg \
|
gnupg \
|
||||||
python-gpgme \
|
python-gpgme \
|
||||||
sudo \
|
sudo \
|
||||||
|
curl \
|
||||||
dirmngr
|
dirmngr
|
||||||
|
|
||||||
RUN addgroup --system --gid 600 zeyple
|
RUN addgroup --system --gid 600 zeyple
|
||||||
|
|
|
@ -24,7 +24,7 @@ milter_default_action = accept
|
||||||
milter_protocol = 6
|
milter_protocol = 6
|
||||||
minimal_backoff_time = 300s
|
minimal_backoff_time = 300s
|
||||||
plaintext_reject_code = 550
|
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_bare_newline_enable = no
|
||||||
postscreen_blacklist_action = drop
|
postscreen_blacklist_action = drop
|
||||||
postscreen_cache_cleanup_interval = 24h
|
postscreen_cache_cleanup_interval = 24h
|
||||||
|
|
|
@ -55,3 +55,5 @@ zeyple unix - n n - - pipe
|
||||||
-o smtpd_recipient_restrictions=permit_mynetworks,reject
|
-o smtpd_recipient_restrictions=permit_mynetworks,reject
|
||||||
-o mynetworks=127.0.0.0/8
|
-o mynetworks=127.0.0.0/8
|
||||||
-o smtpd_authorized_xforward_hosts=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
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
while read QUERY; do
|
||||||
|
QUERY=($QUERY)
|
||||||
|
if [ "${QUERY[0]}" != "get" ]; then
|
||||||
|
echo "500 dunno"
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
result=$(curl -s http://172.22.1.251:8081/forwardinghosts.php?host=${QUERY[1]})
|
||||||
|
logger -t whitelist_forwardinghosts -p mail.info "Look up ${QUERY[1]} on whitelist, result $result"
|
||||||
|
echo $result
|
||||||
|
done
|
|
@ -0,0 +1,56 @@
|
||||||
|
<?php
|
||||||
|
header('Content-Type: text/plain');
|
||||||
|
require_once "vars.inc.php";
|
||||||
|
|
||||||
|
ini_set('error_reporting', 0);
|
||||||
|
|
||||||
|
function in_net($addr, $net)
|
||||||
|
{
|
||||||
|
$net = explode('/', $net);
|
||||||
|
if (count($net) > 1)
|
||||||
|
$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;
|
||||||
|
if (!isset($mask))
|
||||||
|
$mask = $length * 8;
|
||||||
|
|
||||||
|
$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 host 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 '200 dunno';
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
?>
|
|
@ -32,6 +32,35 @@ catch (PDOException $e) {
|
||||||
?>
|
?>
|
||||||
settings {
|
settings {
|
||||||
<?php
|
<?php
|
||||||
|
try {
|
||||||
|
$stmt = $pdo->query("SELECT `host` FROM `forwarding_hosts`");
|
||||||
|
$rows = $stmt->fetchAll(PDO::FETCH_COLUMN);
|
||||||
|
}
|
||||||
|
catch (PDOException $e) {
|
||||||
|
$rows = array();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($rows)
|
||||||
|
{
|
||||||
|
?>
|
||||||
|
whitelist_forwarding_hosts {
|
||||||
|
priority = high;
|
||||||
|
<?php
|
||||||
|
foreach ($rows as $host) {
|
||||||
|
echo "\t\t" . 'ip = "' . $host . '";' . "\n";
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
apply "default" {
|
||||||
|
actions {
|
||||||
|
reject = 999.9;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
symbols [
|
||||||
|
"WHITELIST_FORWARDING_HOST"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
<?php
|
||||||
|
}
|
||||||
$stmt = $pdo->query("SELECT DISTINCT `object` FROM `filterconf` WHERE `option` = 'highspamlevel' OR `option` = 'lowspamlevel'");
|
$stmt = $pdo->query("SELECT DISTINCT `object` FROM `filterconf` WHERE `option` = 'highspamlevel' OR `option` = 'lowspamlevel'");
|
||||||
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
|
|
|
@ -183,6 +183,8 @@ $tfa_data = get_tfa();
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<h4><span class="glyphicon glyphicon-wrench" aria-hidden="true"></span> <?=$lang['admin']['configuration'];?></h4>
|
<h4><span class="glyphicon glyphicon-wrench" aria-hidden="true"></span> <?=$lang['admin']['configuration'];?></h4>
|
||||||
|
<div class="panel-group" id="accordion_access">
|
||||||
|
|
||||||
<div class="panel panel-default">
|
<div class="panel panel-default">
|
||||||
<div class="panel-heading"><?=$lang['admin']['dkim_keys'];?></div>
|
<div class="panel-heading"><?=$lang['admin']['dkim_keys'];?></div>
|
||||||
<div id="collapseDKIM" class="panel-collapse">
|
<div id="collapseDKIM" class="panel-collapse">
|
||||||
|
@ -298,6 +300,77 @@ $tfa_data = get_tfa();
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="panel panel-default">
|
||||||
|
<div style="cursor:pointer;" class="panel-heading" data-toggle="collapse" data-parent="#accordion_access" data-target="#collapseForwardingHosts">
|
||||||
|
<span class="accordion-toggle"><?=$lang['admin']['forwarding_hosts'];?></span>
|
||||||
|
</div>
|
||||||
|
<div id="collapseForwardingHosts" class="panel-collapse collapse">
|
||||||
|
<div class="panel-body">
|
||||||
|
<p style="margin-bottom:40px"><?=$lang['admin']['forwarding_hosts_hint'];?></p>
|
||||||
|
<form method="post">
|
||||||
|
<div class="table-responsive">
|
||||||
|
<table class="table table-striped" id="forwardinghoststable">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th style="min-width: 100px;"><?=$lang['edit']['host'];?></th>
|
||||||
|
<th style="min-width: 100px;"><?=$lang['edit']['source'];?></th>
|
||||||
|
<th style="text-align: right; min-width: 200px;"><?=$lang['admin']['action'];?></th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<?php
|
||||||
|
$forwarding_hosts = get_forwarding_hosts();
|
||||||
|
if ($forwarding_hosts) {
|
||||||
|
foreach ($forwarding_hosts as $host) {
|
||||||
|
$source = $host->source;
|
||||||
|
$host = $host->host;
|
||||||
|
?>
|
||||||
|
<tr id="data">
|
||||||
|
<td><?=htmlspecialchars(strtolower($host));?></td>
|
||||||
|
<td><?=htmlspecialchars(strtolower($source));?></td>
|
||||||
|
<td style="text-align: right;">
|
||||||
|
<div class="btn-group">
|
||||||
|
<a href="delete.php?forwardinghost=<?=$host;?>" class="btn btn-xs btn-danger"><span class="glyphicon glyphicon-trash"></span> <?=$lang['admin']['remove'];?></a>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<?php
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
?>
|
||||||
|
<tr id="no-data"><td colspan="4" style="text-align: center; font-style: italic;"><?=$lang['admin']['no_record'];?></td></tr>
|
||||||
|
<?php
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
<small>
|
||||||
|
<legend><?=$lang['admin']['add_forwarding_host'];?></legend>
|
||||||
|
<p style="margin-bottom:10px"><?=$lang['admin']['forwarding_hosts_add_hint'];?></p>
|
||||||
|
<form class="form-horizontal" role="form" method="post">
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="control-label col-sm-2" for="hostname"><?=$lang['edit']['host'];?>:</label>
|
||||||
|
<div class="col-sm-10">
|
||||||
|
<input type="text" class="form-control" name="hostname" id="hostname" required>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<div class="col-sm-offset-2 col-sm-10">
|
||||||
|
<button type="submit" name="add_forwarding_host" class="btn btn-default"><?=$lang['admin']['add'];?></button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</small>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
</div> <!-- /container -->
|
</div> <!-- /container -->
|
||||||
<script type='text/javascript'>
|
<script type='text/javascript'>
|
||||||
<?php
|
<?php
|
||||||
|
|
|
@ -105,6 +105,23 @@ if (isset($_SESSION['mailcow_cc_role']) && ($_SESSION['mailcow_cc_role'] == "adm
|
||||||
</form>
|
</form>
|
||||||
<?php
|
<?php
|
||||||
}
|
}
|
||||||
|
// DELETE FORWARDING HOST
|
||||||
|
elseif (isset($_GET["forwardinghost"]) &&
|
||||||
|
!empty($_GET["forwardinghost"]) &&
|
||||||
|
$_SESSION['mailcow_cc_role'] == "admin") {
|
||||||
|
$host = $_GET["forwardinghost"];
|
||||||
|
?>
|
||||||
|
<div class="alert alert-warning" role="alert"><?=sprintf($lang['delete']['remove_forwardinghost_warning'], htmlspecialchars($_GET["forwardinghost"]));?></div>
|
||||||
|
<form class="form-horizontal" role="form" method="post" action="/admin.php">
|
||||||
|
<input type="hidden" name="forwardinghost" value="<?=htmlspecialchars($host);?>">
|
||||||
|
<div class="form-group">
|
||||||
|
<div class="col-sm-offset-1 col-sm-10">
|
||||||
|
<button type="submit" name="delete_forwarding_host" class="btn btn-default btn-sm"><?=$lang['delete']['remove_button'];?></button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
<?php
|
||||||
|
}
|
||||||
// DELETE MAILBOX
|
// DELETE MAILBOX
|
||||||
elseif (isset($_GET["mailbox"]) &&
|
elseif (isset($_GET["mailbox"]) &&
|
||||||
filter_var($_GET["mailbox"], FILTER_VALIDATE_EMAIL) &&
|
filter_var($_GET["mailbox"], FILTER_VALIDATE_EMAIL) &&
|
||||||
|
|
|
@ -4932,4 +4932,93 @@ function get_u2f_registrations($username) {
|
||||||
$sel->execute(array($username));
|
$sel->execute(array($username));
|
||||||
return $sel->fetchAll(PDO::FETCH_OBJ);
|
return $sel->fetchAll(PDO::FETCH_OBJ);
|
||||||
}
|
}
|
||||||
|
function get_forwarding_hosts() {
|
||||||
|
global $pdo;
|
||||||
|
$sel = $pdo->prepare("SELECT host, source FROM `forwarding_hosts`");
|
||||||
|
$sel->execute();
|
||||||
|
return $sel->fetchAll(PDO::FETCH_OBJ);
|
||||||
|
}
|
||||||
|
function add_forwarding_host($postarray) {
|
||||||
|
require_once 'spf.inc.php';
|
||||||
|
global $pdo;
|
||||||
|
global $lang;
|
||||||
|
if ($_SESSION['mailcow_cc_role'] != "admin") {
|
||||||
|
$_SESSION['return'] = array(
|
||||||
|
'type' => 'danger',
|
||||||
|
'msg' => sprintf($lang['danger']['access_denied'])
|
||||||
|
);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
$source = $postarray['hostname'];
|
||||||
|
$host = $postarray['hostname'];
|
||||||
|
$hosts = array();
|
||||||
|
if (preg_match('/^[0-9a-fA-F:\/]+$/', $host)) { // IPv6 address
|
||||||
|
$hosts = array($host);
|
||||||
|
}
|
||||||
|
elseif (preg_match('/^[0-9\.\/]+$/', $host)) { // IPv4 address
|
||||||
|
$hosts = array($host);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$hosts = get_outgoing_hosts_best_guess($host);
|
||||||
|
}
|
||||||
|
if (!$hosts)
|
||||||
|
{
|
||||||
|
$_SESSION['return'] = array(
|
||||||
|
'type' => 'danger',
|
||||||
|
'msg' => 'Invalid host specified: '. htmlspecialchars($host)
|
||||||
|
);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
foreach ($hosts as $host) {
|
||||||
|
if ($source == $host)
|
||||||
|
$source = '';
|
||||||
|
try {
|
||||||
|
$stmt = $pdo->prepare("INSERT IGNORE INTO `forwarding_hosts` (`host`, `source`) VALUES (:host, :source)");
|
||||||
|
$stmt->execute(array(
|
||||||
|
':host' => $host,
|
||||||
|
':source' => $source,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
catch (PDOException $e) {
|
||||||
|
$_SESSION['return'] = array(
|
||||||
|
'type' => 'danger',
|
||||||
|
'msg' => 'MySQL: '.$e
|
||||||
|
);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$_SESSION['return'] = array(
|
||||||
|
'type' => 'success',
|
||||||
|
'msg' => sprintf($lang['success']['forwarding_host_added'], htmlspecialchars(implode(', ', $hosts)))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
function delete_forwarding_host($postarray) {
|
||||||
|
global $pdo;
|
||||||
|
global $lang;
|
||||||
|
if ($_SESSION['mailcow_cc_role'] != "admin") {
|
||||||
|
$_SESSION['return'] = array(
|
||||||
|
'type' => 'danger',
|
||||||
|
'msg' => sprintf($lang['danger']['access_denied'])
|
||||||
|
);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
$host = $postarray['forwardinghost'];
|
||||||
|
try {
|
||||||
|
$stmt = $pdo->prepare("DELETE FROM `forwarding_hosts` WHERE `host` = :host");
|
||||||
|
$stmt->execute(array(
|
||||||
|
':host' => $host,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
catch (PDOException $e) {
|
||||||
|
$_SESSION['return'] = array(
|
||||||
|
'type' => 'danger',
|
||||||
|
'msg' => 'MySQL: '.$e
|
||||||
|
);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
$_SESSION['return'] = array(
|
||||||
|
'type' => 'success',
|
||||||
|
'msg' => sprintf($lang['success']['forwarding_host_removed'], htmlspecialchars($host))
|
||||||
|
);
|
||||||
|
}
|
||||||
?>
|
?>
|
||||||
|
|
|
@ -263,6 +263,18 @@ function init_db_schema() {
|
||||||
),
|
),
|
||||||
"attr" => "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC"
|
"attr" => "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC"
|
||||||
),
|
),
|
||||||
|
"forwarding_hosts" => array(
|
||||||
|
"cols" => array(
|
||||||
|
"host" => "VARCHAR(255) NOT NULL",
|
||||||
|
"source" => "VARCHAR(255) NOT NULL"
|
||||||
|
),
|
||||||
|
"keys" => array(
|
||||||
|
"primary" => array(
|
||||||
|
"" => array("host")
|
||||||
|
),
|
||||||
|
),
|
||||||
|
"attr" => "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC"
|
||||||
|
),
|
||||||
"sogo_acl" => array(
|
"sogo_acl" => array(
|
||||||
"cols" => array(
|
"cols" => array(
|
||||||
"c_folder_id" => "INT NOT NULL",
|
"c_folder_id" => "INT NOT NULL",
|
||||||
|
|
|
@ -0,0 +1,127 @@
|
||||||
|
<?php
|
||||||
|
function get_spf_allowed_hosts($domain)
|
||||||
|
{
|
||||||
|
$hosts = array();
|
||||||
|
|
||||||
|
$records = dns_get_record($domain, DNS_TXT);
|
||||||
|
foreach ($records as $record)
|
||||||
|
{
|
||||||
|
$txt = explode(' ', $record['entries'][0]);
|
||||||
|
if (array_shift($txt) != 'v=spf1') // only handle SPF records
|
||||||
|
continue;
|
||||||
|
|
||||||
|
foreach ($txt as $mech)
|
||||||
|
{
|
||||||
|
$qual = substr($mech, 0, 1);
|
||||||
|
if ($qual == '-' || $qual == '~') // only handle pass or neutral records
|
||||||
|
continue(2);
|
||||||
|
|
||||||
|
if ($qual == '+' || $qual == '?')
|
||||||
|
$mech = substr($mech, 1); // remove the qualifier
|
||||||
|
|
||||||
|
if (strpos($mech, '=') !== FALSE) // handle a modifier
|
||||||
|
{
|
||||||
|
$mod = explode('=', $mech);
|
||||||
|
if ($mod[0] == 'redirect') // handle a redirect
|
||||||
|
{
|
||||||
|
$hosts = get_spf_allowed_hosts($mod[1]);
|
||||||
|
return $hosts;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
unset($cidr);
|
||||||
|
if (strpos($mech, ':') !== FALSE) // handle a domain specification
|
||||||
|
{
|
||||||
|
$split = explode(':', $mech);
|
||||||
|
$mech = array_shift($split);
|
||||||
|
$domain = implode(':', $split);
|
||||||
|
if (strpos($domain, '/') !== FALSE) // remove CIDR specification
|
||||||
|
{
|
||||||
|
$split = explode('/', $domain);
|
||||||
|
$domain = $split[0];
|
||||||
|
$cidr = $split[1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$new_hosts = array();
|
||||||
|
if ($mech == 'include') // handle an inclusion
|
||||||
|
{
|
||||||
|
$new_hosts = get_spf_allowed_hosts($domain);
|
||||||
|
}
|
||||||
|
elseif ($mech == 'a') // handle a mechanism
|
||||||
|
{
|
||||||
|
$new_hosts = get_a_hosts($domain);
|
||||||
|
}
|
||||||
|
elseif ($mech == 'mx') // handle mx mechanism
|
||||||
|
{
|
||||||
|
$new_hosts = get_mx_hosts($domain);
|
||||||
|
}
|
||||||
|
elseif ($mech == 'ip4' || $mech == 'ip6') // handle ip mechanism
|
||||||
|
{
|
||||||
|
$new_hosts = array($domain);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($cidr)) // add CIDR specification if present
|
||||||
|
{
|
||||||
|
foreach ($new_hosts as &$host)
|
||||||
|
{
|
||||||
|
$host .= '/' . $cidr;
|
||||||
|
}
|
||||||
|
unset($host);
|
||||||
|
}
|
||||||
|
|
||||||
|
$hosts = array_unique(array_merge($hosts,$new_hosts), SORT_REGULAR);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $hosts;
|
||||||
|
}
|
||||||
|
|
||||||
|
function get_mx_hosts($domain)
|
||||||
|
{
|
||||||
|
$hosts = array();
|
||||||
|
|
||||||
|
$mx_records = dns_get_record($domain, DNS_MX);
|
||||||
|
foreach ($mx_records as $mx_record)
|
||||||
|
{
|
||||||
|
$new_hosts = get_a_hosts($mx_record['target']);
|
||||||
|
$hosts = array_unique(array_merge($hosts,$new_hosts), SORT_REGULAR);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $hosts;
|
||||||
|
}
|
||||||
|
|
||||||
|
function get_a_hosts($domain)
|
||||||
|
{
|
||||||
|
$hosts = array();
|
||||||
|
|
||||||
|
$a_records = dns_get_record($domain, DNS_A);
|
||||||
|
foreach ($a_records as $a_record)
|
||||||
|
{
|
||||||
|
$hosts[] = $a_record['ip'];
|
||||||
|
}
|
||||||
|
$a_records = dns_get_record($domain, DNS_AAAA);
|
||||||
|
foreach ($a_records as $a_record)
|
||||||
|
{
|
||||||
|
$hosts[] = $a_record['ipv6'];
|
||||||
|
}
|
||||||
|
|
||||||
|
return $hosts;
|
||||||
|
}
|
||||||
|
|
||||||
|
function get_outgoing_hosts_best_guess($domain)
|
||||||
|
{
|
||||||
|
// try the SPF record to get hosts that are allowed to send outgoing mails for this domain
|
||||||
|
$hosts = get_spf_allowed_hosts($domain);
|
||||||
|
if ($hosts) return $hosts;
|
||||||
|
|
||||||
|
// try the MX record to get mail servers for this domain
|
||||||
|
$hosts = get_mx_hosts($domain);
|
||||||
|
if ($hosts) return $hosts;
|
||||||
|
|
||||||
|
// fall back to the A record to get the host name for this domain
|
||||||
|
return get_a_hosts($domain);
|
||||||
|
}
|
||||||
|
?>
|
|
@ -72,6 +72,12 @@ if (isset($_SESSION['mailcow_cc_role']) && $_SESSION['mailcow_cc_role'] == "admi
|
||||||
if (isset($_POST["delete_domain_admin"])) {
|
if (isset($_POST["delete_domain_admin"])) {
|
||||||
delete_domain_admin($_POST);
|
delete_domain_admin($_POST);
|
||||||
}
|
}
|
||||||
|
if (isset($_POST["add_forwarding_host"])) {
|
||||||
|
add_forwarding_host($_POST);
|
||||||
|
}
|
||||||
|
if (isset($_POST["delete_forwarding_host"])) {
|
||||||
|
delete_forwarding_host($_POST);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (isset($_SESSION['mailcow_cc_role']) && $_SESSION['mailcow_cc_role'] == "user") {
|
if (isset($_SESSION['mailcow_cc_role']) && $_SESSION['mailcow_cc_role'] == "user") {
|
||||||
if (isset($_POST["edit_user_account"])) {
|
if (isset($_POST["edit_user_account"])) {
|
||||||
|
|
|
@ -450,11 +450,20 @@ $lang['admin']['unchanged_if_empty'] = 'Unverändert, wenn leer';
|
||||||
$lang['admin']['yes'] = '✔';
|
$lang['admin']['yes'] = '✔';
|
||||||
$lang['admin']['no'] = '✘';
|
$lang['admin']['no'] = '✘';
|
||||||
$lang['admin']['access'] = 'Zugang';
|
$lang['admin']['access'] = 'Zugang';
|
||||||
$lang['admin']['invalid_max_msg_size'] = 'Invalid max. message size'; // NEEDS TRANSLATION
|
$lang['admin']['invalid_max_msg_size'] = 'Ungültige maximale Nachrichtengröße';
|
||||||
$lang['admin']['site_not_found'] = 'Kann mailcow Site-Konfiguration nicht finden';
|
$lang['admin']['site_not_found'] = 'Kann mailcow Site-Konfiguration nicht finden';
|
||||||
$lang['admin']['public_folder_empty'] = 'Public folder name must not be empty'; // NEEDS TRANSLATION
|
$lang['admin']['public_folder_empty'] = 'Name des öffentlichen Ordners darf nicht leer sein';
|
||||||
$lang['admin']['set_rr_failed'] = 'Kann Postfix Restriktionen nicht setzen';
|
$lang['admin']['set_rr_failed'] = 'Kann Postfix Restriktionen nicht setzen';
|
||||||
$lang['admin']['no_record'] = 'Kein Eintrag';
|
$lang['admin']['no_record'] = 'Kein Eintrag';
|
||||||
$lang['admin']['filter_table'] = 'Tabelle Filtern';
|
$lang['admin']['filter_table'] = 'Tabelle Filtern';
|
||||||
$lang['admin']['empty'] = 'Keine Einträge vorhanden';
|
$lang['admin']['empty'] = 'Keine Einträge vorhanden';
|
||||||
|
$lang['admin']['forwarding_hosts'] = 'Weiterleitungs-Hosts';
|
||||||
|
$lang['admin']['forwarding_hosts_hint'] = 'Eingehende Nachrichten werden von den hier gelisteten Hosts bedingungslos akzeptiert. Diese Hosts werden dann nicht mit DNSBLs abgeglichen oder Greylisting unterworfen. Von ihnen empfangener Spam wird nie abgelehnt und immer in den Spam-Ordner einsortiert. Die übliche Verwendung für diese Funktion ist, um Mailserver anzugeben, auf denen eine Weiterleitung zu Ihrem Mailcow-Server eingerichtet wurde.';
|
||||||
|
$lang['admin']['forwarding_hosts_add_hint'] = 'Sie können entweder IPv4/IPv6-Adressen, Netzwerke in CIDR-Notation, Hostnamen (die zu IP-Adressen aufgelöst werden), oder Domainnamen (die zu IP-Adressen aufgelöst werden, indem ihr SPF-Record abgefragt wird oder, in dessen Abwesenheit, ihre MX-Records) angeben.';
|
||||||
|
$lang['edit']['host'] = 'Host';
|
||||||
|
$lang['edit']['source'] = 'Quelle';
|
||||||
|
$lang['admin']['add_forwarding_host'] = 'Weiterleitungs-Host hinzufügen';
|
||||||
|
$lang['delete']['remove_forwardinghost_warning'] = '<b>Warnung:</b> Sie entfernen den Weiterleitungs-Host <b>%s</b>!';
|
||||||
|
$lang['success']['forwarding_host_removed'] = "Weiterleitungs-Host %s wurde entfernt";
|
||||||
|
$lang['success']['forwarding_host_added'] = "Weiterleitungs-Host %s wurde hinzugefügt";
|
||||||
?>
|
?>
|
||||||
|
|
|
@ -468,4 +468,13 @@ $lang['admin']['set_rr_failed'] = 'Cannot set Postfix restrictions';
|
||||||
$lang['admin']['no_record'] = 'No record';
|
$lang['admin']['no_record'] = 'No record';
|
||||||
$lang['admin']['filter_table'] = 'Filter table';
|
$lang['admin']['filter_table'] = 'Filter table';
|
||||||
$lang['admin']['empty'] = 'No results';
|
$lang['admin']['empty'] = 'No results';
|
||||||
|
$lang['admin']['forwarding_hosts'] = 'Forwarding Hosts';
|
||||||
|
$lang['admin']['forwarding_hosts_hint'] = 'Incoming messages are unconditionally accepted from any hosts listed here. These hosts are then not checked against DNSBLs or subjected to greylisting. Spam received from them is never rejected and always filed into the Junk folder. The most common use for this is to specify mail servers on which you have set up a rule that forwards incoming emails to your Mailcow server.';
|
||||||
|
$lang['admin']['forwarding_hosts_add_hint'] = 'You can either specify IPv4/IPv6 addresses, networks in CIDR notation, host names (which will be resolved to IP addresses), or domain names (which will be resolved to IP addresses by querying SPF records or, in their absence, MX records).';
|
||||||
|
$lang['edit']['host'] = 'Host';
|
||||||
|
$lang['edit']['source'] = 'Source';
|
||||||
|
$lang['admin']['add_forwarding_host'] = 'Add Forwarding Host';
|
||||||
|
$lang['delete']['remove_forwardinghost_warning'] = '<b>Warning:</b> You are about to remove the forwarding host <b>%s</b>!';
|
||||||
|
$lang['success']['forwarding_host_removed'] = "Forwarding host %s has been removed";
|
||||||
|
$lang['success']['forwarding_host_added'] = "Forwarding host %s has been added";
|
||||||
?>
|
?>
|
||||||
|
|
Loading…
Reference in New Issue