From patchwork Sun Mar 8 17:31:14 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Stefan Schantl X-Patchwork-Id: 9557 Return-Path: Received: from mail01.ipfire.org (mail01.haj.ipfire.org [172.28.1.202]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange x25519) (Client CN "mail01.haj.ipfire.org", Issuer "R12" (not verified)) by web04.haj.ipfire.org (Postfix) with ESMTPS id 4fTS1l2Bgvz3wkB for ; Sun, 08 Mar 2026 17:34:19 +0000 (UTC) Received: from mail02.haj.ipfire.org (mail02.haj.ipfire.org [172.28.1.201]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange x25519) (Client CN "mail02.haj.ipfire.org", Issuer "E7" (not verified)) by mail01.ipfire.org (Postfix) with ESMTPS id 4fTS1k2MNYz605 for ; Sun, 08 Mar 2026 17:34:18 +0000 (UTC) Received: from mail02.haj.ipfire.org (localhost [IPv6:::1]) by mail02.haj.ipfire.org (Postfix) with ESMTP id 4fTS1j6QNTz33vV for ; Sun, 08 Mar 2026 17:34:17 +0000 (UTC) X-Original-To: development@lists.ipfire.org Received: from mail01.ipfire.org (mail01.haj.ipfire.org [IPv6:2001:678:b28::25]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange x25519 server-signature ECDSA (secp384r1) server-digest SHA384 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mail01.haj.ipfire.org", Issuer "R12" (not verified)) by mail02.haj.ipfire.org (Postfix) with ESMTPS id 4fTS1g35bDz33B6 for ; Sun, 08 Mar 2026 17:34:15 +0000 (UTC) Received: from [127.0.0.1] (localhost [127.0.0.1]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange x25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by mail01.ipfire.org (Postfix) with ESMTPSA id 4fTS1d3Rmcz34F; Sun, 08 Mar 2026 17:34:13 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ipfire.org; s=202003rsa; t=1772991253; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding; bh=YEAR5OTaVFKsGO6rAP0olrvbJ5kF5eGHRmXS7b0zO4A=; b=vS1spJ8pNhm+PbCEmF+J+/Gh1gS2n43Sb9ctq3ck+sOpXWqVKYFCMm5G5+Dj6hv40874jK 2h/OHIGU9s4IW3Z6W6W6wi+AMB8Jj02/REOA8Qrf1+4u5tdrq/x2NkoFwrcIQOssTFVZxr y6v1qAsoU2yEewqocmteIZdic+Mw7Q1wNtWVxH/zpjLJgEf1a2mTu+xXAVWotdOySjNsKa tos4rzN5mLaisVID+pYGKqWCogEXJk9VMIG/oxtlLjjNJ1hj3SSfq8FeWCyGrKb6REVYsU IZq5KqDpakR+n7ShoVhbD+/3chtvzDqJrCP/x2zXOQCUPiPt4ZSUKXkNLLYj7w== DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=ipfire.org; s=202003ed25519; t=1772991253; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding; bh=YEAR5OTaVFKsGO6rAP0olrvbJ5kF5eGHRmXS7b0zO4A=; b=h86t9JpJZ+bcvUMnY45mNIIlRfks9y7vqcw/XqFu1dA4xKmolCpe2N1UwLR7jKrdlW4he4 L2FvcRVB3O35oeAQ== From: Stefan Schantl To: development@lists.ipfire.org Cc: Stefan Schantl Subject: [PATCH 1/2] perl-Net-LibIDN2: New package Date: Sun, 8 Mar 2026 18:31:14 +0100 Message-ID: <20260308173115.105058-1-stefan.schantl@ipfire.org> Precedence: list List-Id: List-Subscribe: , List-Unsubscribe: , List-Post: List-Help: Sender: Mail-Followup-To: MIME-Version: 1.0 This perl package provides C bindings to the libidn2, and can be used to convert international domain names into the "idn ascii" format and vice versa. Signed-off-by: Stefan Schantl --- config/rootfiles/common/perl-Net-LibIDN2 | 6 ++ lfs/perl-Net-LibIDN2 | 77 ++++++++++++++++++++++++ make.sh | 1 + 3 files changed, 84 insertions(+) create mode 100644 config/rootfiles/common/perl-Net-LibIDN2 create mode 100644 lfs/perl-Net-LibIDN2 diff --git a/config/rootfiles/common/perl-Net-LibIDN2 b/config/rootfiles/common/perl-Net-LibIDN2 new file mode 100644 index 000000000..1d23bd083 --- /dev/null +++ b/config/rootfiles/common/perl-Net-LibIDN2 @@ -0,0 +1,6 @@ +usr/lib/perl5/site_perl/5.36.0/xxxMACHINExxx-linux-thread-multi/Net/LibIDN2.pm +#usr/lib/perl5/site_perl/5.36.0/xxxMACHINExxx-linux-thread-multi/auto/Net/LibIDN2 +#usr/lib/perl5/site_perl/5.36.0/xxxMACHINExxx-linux-thread-multi/auto/Net/LibIDN2/.packlist +#usr/lib/perl5/site_perl/5.36.0/xxxMACHINExxx-linux-thread-multi/auto/Net/LibIDN2/LibIDN2.bs +usr/lib/perl5/site_perl/5.36.0/xxxMACHINExxx-linux-thread-multi/auto/Net/LibIDN2/LibIDN2.so +#usr/share/man/man3/Net::LibIDN2.3 diff --git a/lfs/perl-Net-LibIDN2 b/lfs/perl-Net-LibIDN2 new file mode 100644 index 000000000..5e7afb613 --- /dev/null +++ b/lfs/perl-Net-LibIDN2 @@ -0,0 +1,77 @@ +############################################################################### +# # +# IPFire.org - A linux based firewall # +# Copyright (C) 2007-2026 IPFire Team # +# # +# This program is free software: you can redistribute it and/or modify # +# it under the terms of the GNU General Public License as published by # +# the Free Software Foundation, either version 3 of the License, or # +# (at your option) any later version. # +# # +# This program is distributed in the hope that it will be useful, # +# but WITHOUT ANY WARRANTY; without even the implied warranty of # +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # +# GNU General Public License for more details. # +# # +# You should have received a copy of the GNU General Public License # +# along with this program. If not, see . # +# # +############################################################################### + +############################################################################### +# Definitions +############################################################################### + +include Config + +VER = 1.02 + +THISAPP = Net-LibIDN2-$(VER) +DL_FILE = $(THISAPP).tar.gz +DL_FROM = $(URL_IPFIRE) +DIR_APP = $(DIR_SRC)/$(THISAPP) +TARGET = $(DIR_INFO)/$(THISAPP) + +############################################################################### +# Top-level Rules +############################################################################### + +objects = $(DL_FILE) + +$(DL_FILE) = $(DL_FROM)/$(DL_FILE) + +$(DL_FILE)_BLAKE2 = 0ccbadd445fcec84d082acdc6c43566a50276fc9bb4cc5a1e954761889b2712c8fde4012e1ffacfefcea796d7d04698a74928895ce822ef84d74f44c97b36b37 + +install : $(TARGET) + +check : $(patsubst %,$(DIR_CHK)/%,$(objects)) + +download :$(patsubst %,$(DIR_DL)/%,$(objects)) + +b2 : $(subst %,%_BLAKE2,$(objects)) + +############################################################################### +# Downloading, checking, b2sum +############################################################################### + +$(patsubst %,$(DIR_CHK)/%,$(objects)) : + @$(CHECK) + +$(patsubst %,$(DIR_DL)/%,$(objects)) : + @$(LOAD) + +$(subst %,%_BLAKE2,$(objects)) : + @$(B2SUM) + +############################################################################### +# Installation Details +############################################################################### + +$(TARGET) : $(patsubst %,$(DIR_DL)/%,$(objects)) + @$(PREBUILD) + @rm -rf $(DIR_APP) && cd $(DIR_SRC) && tar zxf $(DIR_DL)/$(DL_FILE) + cd $(DIR_APP) && perl Build.PL + cd $(DIR_APP) && perl Build + cd $(DIR_APP) && perl Build install + @rm -rf $(DIR_APP) + @$(POSTBUILD) diff --git a/make.sh b/make.sh index 5309b5675..225767f91 100755 --- a/make.sh +++ b/make.sh @@ -2160,6 +2160,7 @@ build_system() { lfsmake2 arpwatch lfsmake2 suricata-reporter lfsmake2 lldpd + lfsmake2 perl-Net-LibIDN2 lfsmake2 linux lfsmake2 linux-initrd From patchwork Sun Mar 8 17:31:15 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Stefan Schantl X-Patchwork-Id: 9556 Return-Path: Received: from mail01.ipfire.org (mail01.haj.ipfire.org [172.28.1.202]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange x25519 server-signature ECDSA (secp384r1) server-digest SHA384 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mail01.haj.ipfire.org", Issuer "R12" (not verified)) by web04.haj.ipfire.org (Postfix) with ESMTPS id 4fTS1l1XzKz3wk2 for ; Sun, 08 Mar 2026 17:34:19 +0000 (UTC) Received: from mail02.haj.ipfire.org (mail02.haj.ipfire.org [IPv6:2001:678:b28::201]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange x25519) (Client CN "mail02.haj.ipfire.org", Issuer "E7" (not verified)) by mail01.ipfire.org (Postfix) with ESMTPS id 4fTS1k0Vcfz601 for ; Sun, 08 Mar 2026 17:34:18 +0000 (UTC) Received: from mail02.haj.ipfire.org (localhost [IPv6:::1]) by mail02.haj.ipfire.org (Postfix) with ESMTP id 4fTS1j4kRXz33gC for ; Sun, 08 Mar 2026 17:34:17 +0000 (UTC) X-Original-To: development@lists.ipfire.org Received: from mail01.ipfire.org (mail01.haj.ipfire.org [172.28.1.202]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange x25519 server-signature ECDSA (secp384r1) server-digest SHA384 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mail01.haj.ipfire.org", Issuer "R12" (not verified)) by mail02.haj.ipfire.org (Postfix) with ESMTPS id 4fTS1g1RDxz2xKC for ; Sun, 08 Mar 2026 17:34:15 +0000 (UTC) Received: from [127.0.0.1] (localhost [127.0.0.1]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange x25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by mail01.ipfire.org (Postfix) with ESMTPSA id 4fTS1f5YM0z3Ws; Sun, 08 Mar 2026 17:34:14 +0000 (UTC) DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=ipfire.org; s=202003ed25519; t=1772991254; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=j7B1tK8cLJxoTSsRA3NtcLqmBwy9BE3/Xy20pzZnmbk=; b=gRI8zBn9veGtcH4uZ6XdNzbjyE9ZOJLcMOgVtC8BI3ioFXnkkqSH79Stvp+m0c6SJovfqo bDxmhcoOUHwB2iCQ== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ipfire.org; s=202003rsa; t=1772991254; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=j7B1tK8cLJxoTSsRA3NtcLqmBwy9BE3/Xy20pzZnmbk=; b=jBoWVx0l/dHtuz9RgjCWrg1fRc3sA8XDdWa/sauDAOD7/tAcyY2qcJ8cCUrrzONNETOesS sIWtHfnBENRgmdgy2k4niiCrLSge8AFyatYTCPWmvQiRjtgpGp5dXEEOEZlVYBUrKHHVVi d60oy3QVrrAFElKp3ZPuyXWdV5QxuT0hWVSI+Oy4W8VRwvai5lhkdrsVX2T0OkoN604aB5 ehUoAyqXNv8GbpShga9Y3/56+5qxzwpu5Cak33AzWc6Q1qR0aZguTJbPz6+Jg5LOuwEpqR kWFa0e3BWz4WcJ0rPt4R04EvCzs8xdOE3wE4H5P8tNCvVGwblzUiEbyEKVl+tw== From: Stefan Schantl To: development@lists.ipfire.org Cc: Stefan Schantl Subject: [PATCH 2/2] dnsbl.cgi: Add support for IDN Date: Sun, 8 Mar 2026 18:31:15 +0100 Message-ID: <20260308173115.105058-2-stefan.schantl@ipfire.org> In-Reply-To: <20260308173115.105058-1-stefan.schantl@ipfire.org> References: <20260308173115.105058-1-stefan.schantl@ipfire.org> Precedence: list List-Id: List-Subscribe: , List-Unsubscribe: , List-Post: List-Help: Sender: Mail-Followup-To: MIME-Version: 1.0 Use the LibIDN2 perl module to convert international domain names in the custom allow and block list, into the idn ascii format (punnycode). Signed-off-by: Stefan Schantl --- html/cgi-bin/dnsbl.cgi | 122 +++++++++++++++++++++++++++++++++++------ 1 file changed, 106 insertions(+), 16 deletions(-) diff --git a/html/cgi-bin/dnsbl.cgi b/html/cgi-bin/dnsbl.cgi index e81b144c2..16e6dded2 100644 --- a/html/cgi-bin/dnsbl.cgi +++ b/html/cgi-bin/dnsbl.cgi @@ -21,6 +21,7 @@ use strict; use JSON::PP; +use Net::LibIDN2 ':all'; # enable only the following on debugging purpose #use warnings; @@ -168,6 +169,8 @@ if ($cgiparams{'ACTION'} eq "$Lang::tr{'save'}") { } elsif ($cgiparams{'CUSTOM_DOMAINS'} eq "$Lang::tr{'save'}") { my @cgi_allowed_domains; my @cgi_blocked_domains; + my @ascii_allowed_domains; + my @ascii_blocked_domains; # Get the current configured custom domains to allow or block &readsettings("$custom_domains_file", \%custom_domains) if (-f "$custom_domains_file"); @@ -184,36 +187,32 @@ if ($cgiparams{'ACTION'} eq "$Lang::tr{'save'}") { @cgi_allowed_domains = &General::uniq(@cgi_allowed_domains); @cgi_blocked_domains = &General::uniq(@cgi_blocked_domains); + # Check domains and convert into ascii format. + @ascii_allowed_domains = &format_domains(\@cgi_allowed_domains, "ascii"); + @ascii_blocked_domains = &format_domains(\@cgi_blocked_domains, "ascii"); + # Merge temporary merge both arrays for duplicate and valid check. - my @merged = (@cgi_allowed_domains, @cgi_blocked_domains); + my @ascii_merged = (@ascii_allowed_domains, @ascii_blocked_domains); # Check if there are duplicate entries on the merged list. # This assumes a domain which has been entered on both - my $dup = &check_for_duplicates(@merged); + my $dup = &check_for_duplicates(@ascii_merged); # If a duplicate has been found, raise an error if ($dup) { push(@errormessages, "$dup - $Lang::tr{'dnsbl error domain specified twice'}"); } - # Loop through the arrays and check for valid domains and duplicates - foreach my $domain (@merged) { - # Check if the domain is valid - unless (&General::validdomainname($domain)) { - push(@errormessages, "$domain - $Lang::tr{'invalid domain name'}"); - } - } - # Check if a domain from the posted blocked domains array is allready part of # the saved allowed domains array - $dup = &compare_arrays(\@custom_allowed_domains, \@cgi_blocked_domains); + $dup = &compare_arrays(\@custom_allowed_domains, \@ascii_blocked_domains); if ($dup) { push(@errormessages, "$dup - $Lang::tr{'dnsbl error domain specified twice'}"); } # Check if a domain from the posted allowed domains array is allready part of # the saved blocked domains array. - $dup = &compare_arrays(\@custom_blocked_domains, \@cgi_allowed_domains); + $dup = &compare_arrays(\@custom_blocked_domains, \@ascii_allowed_domains); if ($dup) { push(@errormessages, "$dup - $Lang::tr{'dnsbl error domain specified twice'}"); } @@ -222,11 +221,11 @@ if ($cgiparams{'ACTION'} eq "$Lang::tr{'save'}") { my %tmp; # Assign the allowed and blocked domain arrays to the temporary hash - foreach my $domain (@cgi_allowed_domains) { + foreach my $domain (@ascii_allowed_domains) { $tmp{$domain} = [ "allowed" ]; } - foreach my $domain (@cgi_blocked_domains) { + foreach my $domain (@ascii_blocked_domains) { $tmp{$domain} = [ "blocked" ]; } @@ -271,9 +270,9 @@ sub show_mainpage() { my $status = $custom_domains{$domain}[0]; if ($status eq "allowed") { - push(@custom_allowed_domains, $domain); + push(@custom_allowed_domains, &format_domain_to_unicode($domain)); } elsif ($status eq "blocked") { - push(@custom_blocked_domains, $domain); + push(@custom_blocked_domains, &format_domain_to_unicode($domain)); } } } @@ -539,3 +538,94 @@ sub compare_arrays (\@\@) { } } } + +sub format_domains(\@$) { + my ($arrayref, $format) = @_; + my @formated_domains; + + # Deref and assign array. + my @domains = @{ $arrayref }; + + # Exit if not data passed. + return unless (@domains); + + # Loop through the given domains array. + foreach my $domain (@domains) { + my $formated_domain; + + # Check the output format and convert the domain into requested format. + if ($format eq "ascii") { + $formated_domain = &format_domain_to_ascii($domain); + } elsif ($format eq "unicode") { + $formated_domain = &format_domain_to_unicode($domain); + } else { + # Unknown format requested. + return; + } + + # Check if the domain could be converted. + if ($formated_domain) { + # Add the converted domain to the array of ascii domains. + push(@formated_domains, $formated_domain); + } else { + # Add the invalid domain to the array of error messages. + push(@errormessages, "$domain - $Lang::tr{'invalid domain name'}"); + } + } + + return @formated_domains; +} + +sub format_domain_to_ascii($) { + my ($domain) = @_; + my $ascii; + my $ret; + + # Early exit on empty input. + return unless($domain); + + # Spit the given domain name into parts. + my @parts = split(/\./, $domain); + + # Exit if the given domain does not contain at least one dot. + return if(scalar(@parts) < 2); + + # Use the perl module to convert the domain into the idn ascii format. + $ascii = &Net::LibIDN2::idn2_to_ascii_8($domain, "", $ret); + + # Check if an error occured. + if ($ret) { + # Get the error message. + my $error = &Net::LibIDN2::idn2_strerror($ret); + + push(@errormessages, "$domain - LibIDN2: $error"); + } + + # Exit if the given domain could not be converted. + return unless($ascii); + + # Return the converted domain. + return $ascii; +} + +sub format_domain_to_unicode($) { + my ($ascii) = @_; + my $unicode; + my $ret; + + # Exit if no input has been given. + return unless($ascii); + + # Convert the idn_ascii formated domain back to unicode and return it. + $unicode = &Net::LibIDN2::idn2_to_unicode_88($ascii, $ret); + + # Check if an error occured. + if ($ret) { + # Get the error message. + my $error = &Net::LibIDN2::idn2_strerror($ret); + + push(@errormessages, "$ascii - LibIDN2: $error"); + } + + return $unicode; +}