From 48602503cd7ec5ef158c129bca371e22294d0b8b Mon Sep 17 00:00:00 2001 From: Ilia Ross Date: Tue, 18 Mar 2025 14:04:38 +0200 Subject: [PATCH] Add support to configure listen for any type of address https://github.com/webmin/webmin/issues/2436 --- dovecot/edit_net.cgi | 11 ++++++++--- dovecot/lang/en | 12 ++++-------- dovecot/save_net.cgi | 38 ++++++++++++++++++++++++++++++++++---- 3 files changed, 46 insertions(+), 15 deletions(-) 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); }