diff --git a/dovecot/edit_net.cgi b/dovecot/edit_net.cgi
index 4561247b7..71eabe7d9 100755
--- a/dovecot/edit_net.cgi
+++ b/dovecot/edit_net.cgi
@@ -34,19 +34,24 @@ print &ui_table_row($text{'net_ssl_disable'},
@listens = &find("imap_listen", $conf, 2) ?
("imap_listen", "pop3_listen", "imaps_listen", "pop3s_listen") :
- ("listen", "ssl_listen");
+ ("listen");
foreach $l (@listens) {
$listen = &find_value($l, $conf);
$mode = !$listen ? 0 :
- $listen eq "[::]" ? 1 :
+ # All interfaces, put in any order, e.g. "[::], *" or "*, ::"
+ $listen =~ /^(\*|::|\[::\]),\s*(\*|::|\[::\])$/ ? 1 :
+ # IPv6 only, e.g. "[::]" or "::"
+ $listen =~ /^(?:\:\:|\[\:\:\])$/ ? 4 :
+ # IPv4 only, e.g. "*"
$listen eq "*" ? 2 : 3,
print &ui_table_row($text{'net_'.$l},
&ui_radio($l."_mode", $mode,
[ [ 0, $text{'net_listen0'} ],
[ 1, $text{'net_listen1'} ],
[ 2, $text{'net_listen2'} ],
+ [ 4, $text{'net_listen4'} ],
[ 3, $text{'net_listen3'} ] ])."\n".
- &ui_textbox($l, $mode == 3 ? $listen : "", 20), 3);
+ &ui_textbox($l, $mode == 3 ? $listen : "", 40), 3);
}
print &ui_table_end();
diff --git a/dovecot/lang/en b/dovecot/lang/en
index d9cc02348..058f46311 100644
--- a/dovecot/lang/en
+++ b/dovecot/lang/en
@@ -31,19 +31,15 @@ net_imap_listen=Interfaces for IMAP connections
net_pop3_listen=Interfaces for POP3 connections
net_imaps_listen=Interfaces for IMAP SSL connections
net_pop3s_listen=Interfaces for POP3 SSL connections
-net_listen=Interfaces for non-SSL connections
-net_ssl_listen=Interfaces for SSL connections
+net_listen=Listen on
net_listen0=Default
net_listen1=All IPv4 and IPv6
net_listen2=All IPv4
+net_listen4=All IPv6
net_listen3=IP address
net_err=Failed to save networking options
-net_eimap_listen=Invalid IP address for IMAP connections
-net_epop3_listen=Invalid IP address for POP3 connections
-net_eimaps_listen=Invalid IP address for IMAP SSL connections
-net_epop3s_listen=Invalid IP address for POP3 SSL connections
-net_elisten=Invalid IP address for non-SSL connections
-net_essl_listen=Invalid IP address for SSL connections
+net_ealisten=Invalid IP address to listen on : $1
+net_ealisten_invalid_mix=Cannot use an individual IP address $1 together with the $2 wildcard. Specify either specific IP addresses or use the wildcard, not both
imap_title=IMAP Options
diff --git a/dovecot/save_net.cgi b/dovecot/save_net.cgi
index 6bb7a9e86..7dcda765b 100755
--- a/dovecot/save_net.cgi
+++ b/dovecot/save_net.cgi
@@ -12,20 +12,50 @@ $sslopt = &find("ssl_disable", $conf, 2) ? "ssl_disable" : "ssl";
&save_directive($conf, $sslopt, $in{$sslopt} eq '' ? undef : $in{$sslopt});
@listens = &find("imap_listen", $conf, 2) ?
("imap_listen", "pop3_listen", "imaps_listen", "pop3s_listen") :
- ("listen", "ssl_listen");
+ ("listen");
foreach $l (@listens) {
if ($in{$l."_mode"} == 0) {
$listen = undef;
}
elsif ($in{$l."_mode"} == 1) {
- $listen = "[::]";
+ $listen = "*, ::";
}
elsif ($in{$l."_mode"} == 2) {
$listen = "*";
}
+ elsif ($in{$l."_mode"} == 4) {
+ $listen = "::";
+ }
elsif ($in{$l."_mode"} == 3) {
- &check_ipaddress($in{$l}) || &error($text{'net_e'.$l});
- $listen = $in{$l};
+ # Check each IP address
+ my @ips_list = split(/[\s,]+/, $in{$l});
+ my @ips_valid;
+ my $has_ip4_wildcard = grep { $_ eq "*" } @ips_list;
+ my $has_ip6_wildcard = grep { /^(\[::\]|::)$/ } @ips_list;
+ foreach my $ip (@ips_list) {
+ # Check for wildcards
+ if ($ip =~ /^(\*|::|\[::\])$/) {
+ push(@ips_valid, $ip);
+ next;
+ }
+
+ # Validate IP address
+ my $is_ipv4 = &check_ipaddress($ip);
+ my $is_ipv6 = &check_ip6address($ip);
+ if (!$is_ipv4 && !$is_ipv6) {
+ &error(&text("net_ealisten", $ip));
+ }
+
+ # Add IP address to list
+ push(@ips_valid, $ip);
+
+ # Validate against wildcards
+ &error(&text("net_ealisten_invalid_mix", $ip, "*"))
+ if ($has_ip4_wildcard && &check_ipaddress($ip));
+ &error(&text("net_ealisten_invalid_mix", $ip, "::"))
+ if ($has_ip6_wildcard && &check_ip6address($ip));
+ }
+ $listen = join(", ", @ips_valid) if (@ips_valid);
}
&save_directive($conf, $l, $listen);
}