From mboxrd@z Thu Jan  1 00:00:00 1970
Return-Path: <development+bounces-469-archive=lists.ipfire.org@lists.ipfire.org>
Received: from mail02.haj.ipfire.org (localhost [127.0.0.1])
	by mail02.haj.ipfire.org (Postfix) with ESMTP id 4b3CJJ13xFz3375
	for <archive@lists.ipfire.org>; Thu, 22 May 2025 15:44:00 +0000 (UTC)
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)
	 client-signature RSA-PSS (4096 bits))
	(Client CN "mail01.haj.ipfire.org", Issuer "R10" (verified OK))
	by mail02.haj.ipfire.org (Postfix) with ESMTPS id 4b3CJD17nxz32f1
	for <development@lists.ipfire.org>; Thu, 22 May 2025 15:43:56 +0000 (UTC)
Received: from [127.0.0.1] (localhost [127.0.0.1])
	(using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits))
	(No client certificate requested)
	by mail01.ipfire.org (Postfix) with ESMTPSA id 4b3CJC3ySVzGc;
	Thu, 22 May 2025 15:43:55 +0000 (UTC)
DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=ipfire.org;
	s=202003ed25519; t=1747928635;
	h=from:from:reply-to:subject:subject:date:date:message-id:message-id:
	 to:to:cc:cc:mime-version:mime-version:content-type:content-type:
	 content-transfer-encoding:content-transfer-encoding:
	 in-reply-to:in-reply-to:references:references;
	bh=kukaq62tyLLUoSZdXIgFmVw5/8T4KJRKbWVU5/jtcMg=;
	b=evHL9kpn8l68bUXj6spXKWV3LSMd3907xJ0HBn2KET1u5sZYQ6KSL0B7BoWQqxrBS2Ppot
	b7dpOuCKYJzZg8BQ==
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ipfire.org; s=202003rsa;
	t=1747928635;
	h=from:from:reply-to:subject:subject:date:date:message-id:message-id:
	 to:to:cc:cc:mime-version:mime-version:content-type:content-type:
	 content-transfer-encoding:content-transfer-encoding:
	 in-reply-to:in-reply-to:references:references;
	bh=kukaq62tyLLUoSZdXIgFmVw5/8T4KJRKbWVU5/jtcMg=;
	b=s5FLc3XsUc0dpgLoRsLEEFjHq6F9qdxyZB9ghfcdmBrz+AmD/aAoaMLsPlqLI8izi4JVEK
	lOYONeM12QwLXk2UbV+nCFhrIN78ZifaqlDbk0+v7IpC8A1EL7BQdwcRWqPqYAotMAor45
	ab7NMk6hcw5zNYJQn3Ztn0ZK30/CY0xEdM7wwl0MkVGhECOK/5xa4Prfsh8j7Gx9VnKBZw
	tOTFRdnjsCY6CwnlMItsnFh6Ta4+QkZQ/3lwCwxuYzH3yw8m/BxWQj3D0fJNXA45DOzY01
	QEYomVQPVESxD2Sm/bExoFtxnkK8/wZjyXKJ6dJzSq4fNIAJx9dt9ZG+bdW+Pg==
Content-Type: text/plain;
	charset=utf-8
Precedence: list
List-Id: <development.lists.ipfire.org>
List-Subscribe: <https://lists.ipfire.org/>,
 <mailto:development+subscribe@lists.ipfire.org?subject=subscribe>
List-Unsubscribe: <https://lists.ipfire.org/>,
 <mailto:development+unsubscribe@lists.ipfire.org?subject=unsubscribe>
List-Post: <mailto:development@lists.ipfire.org>
List-Help: <mailto:development+help@lists.ipfire.org?subject=help>
Sender: <development@lists.ipfire.org>
Mail-Followup-To: <development@lists.ipfire.org>
Mime-Version: 1.0
Subject: Re: [PATCH] RPZ: update code to include WEBGUI and additional
 languages
From: Michael Tremer <michael.tremer@ipfire.org>
In-Reply-To: <em5b48e622-ea4f-4528-b509-17b70627e6d2@e4a72e70.com>
Date: Thu, 22 May 2025 16:43:55 +0100
Cc: Bernhard Bitsch <bbitsch@ipfire.org>,
 "IPFire: Development-List" <development@lists.ipfire.org>
Content-Transfer-Encoding: quoted-printable
Message-Id: <0261B2EC-034E-4231-B105-DEFB8091BF07@ipfire.org>
References: <20250206163522.2363178-1-jon.murphy@ipfire.org>
 <A0568469-68D8-4C26-9154-E9961F4AAA60@ipfire.org>
 <ED243073-E39A-47BA-BBF0-728A13C439BF@ipfire.org>
 <FEF2E201-5067-429B-A829-A472354FF615@ipfire.org>
 <C28A0D7E-6C16-4F6F-9366-A8498F40631E@ipfire.org>
 <8b594873-86ca-46b9-bb4b-94fd6b0239b1@ipfire.org>
 <A1492735-FF13-4F2B-8F5B-0800FB1D669F@ipfire.org>
 <d970c80d-2c13-4f71-9b0f-356a0f3013c6@ipfire.org>
 <9A0DBDA4-75B0-40D2-AE06-78D9BA5EE7D3@ipfire.org>
 <afcb2a99-1281-43e3-bd3d-d915024683f6@ipfire.org>
 <89101199-33D1-40AC-8CCE-DD97583129F2@ipfire.org>
 <em3ba7826f-2bff-4c2c-bf92-b540b8864013@78ba6e0b.com>
 <8703C3D8-C30C-4A56-9F30-7B90BB1E3027@ipfire.org>
 <502fa002-d6da-45d6-9b3e-d4130e59f50a@ipfire.org>
 <64617942-44E2-4E7B-A8AB-D5C22F94F68B@ipfire.org>
 <em524a73af-b1c4-46a3-b1bf-bdfbec02d48a@78ba6e0b.com>
 <8D5093D0-A699-4C4E-AEA3-185AD323EF67@ipfire.org>
 <em1522345b-bb45-442c-a981-51662434afab@78ba6e0b.com>
 <9221F825-15BB-484C-A921-118C7F3266AC@ipfire.org>
 <em2b6fdf23-3c41-4448-b79e-c3d052f06d31@78ba6e0b.com>
 <BAA426BB-19B8-45FF-BF7D-4D7D41E64DCF@ipfire.org>
 <emdb723861-7930-453c-b27c-15857af4618d@6c678a4d.com>
 <ACCBF35D-C5C8-471F-AFE8-77EC4D752D5D@ipfire.org>
 <em5b48e622-ea4f-4528-b509-17b70627e6d2@e4a72e70.com>
To: Jon Murphy <jon.murphy@ipfire.org>

I stated that before. I need to block adult websites.

> On 22 May 2025, at 16:42, Jon Murphy <jon.murphy@ipfire.org> wrote:
>=20
> Now I am curious! What is your use-case?  Tell me more...
>=20
>=20
> ------ Original Message ------
> =46rom "Michael Tremer" <michael.tremer@ipfire.org>
> To "Jon Murphy" <jon.murphy@ipfire.org>
> Cc "Bernhard Bitsch" <bbitsch@ipfire.org>; "IPFire: Development-List" =
<development@lists.ipfire.org>
> Date 5/22/2025 10:40:38=E2=80=AFAM
> Subject Re: [PATCH] RPZ: update code to include WEBGUI and additional =
languages
>=20
>> Hello Jon,
>>=20
>> I have not been spending on time on this at all since we talked last.
>>=20
>> I don=E2=80=99t need Unbound to download any files for my use-case =
either.
>>=20
>> -Michael
>>=20
>>> On 20 May 2025, at 17:30, Jon Murphy <jon.murphy@ipfire.org> wrote:
>>>=20
>>> Michael,
>>>=20
>>> Were you able to debug RPZ and get Unbound to download `.rpz` files?
>>>=20
>>>=20
>>> Jon
>>>=20
>>>=20
>>>=20
>>> ------ Original Message ------
>>> =46rom "Michael Tremer" <michael.tremer@ipfire.org>
>>> To "Jon Murphy" <jon.murphy@ipfire.org>
>>> Cc "Bernhard Bitsch" <bbitsch@ipfire.org>; "IPFire: =
Development-List" <development@lists.ipfire.org>
>>> Date 3/24/2025 9:43:37=E2=80=AFAM
>>> Subject Re: [PATCH] RPZ: update code to include WEBGUI and =
additional languages
>>>=20
>>>> Yes, I don=E2=80=99t need any debugging of this...
>>>>=20
>>>>> On 24 Mar 2025, at 14:42, Jon Murphy <jon.murphy@ipfire.org> =
wrote:
>>>>>=20
>>>>> Is there a:
>>>>>=20
>>>>> server:
>>>>>    module-config: "respip validator iterator"
>>>>>=20
>>>>> In your RPZ set-up?
>>>>>=20
>>>>>=20
>>>>> ------ Original Message ------
>>>>> =46rom "Michael Tremer" <michael.tremer@ipfire.org>
>>>>> To "Jon Murphy" <jon.murphy@ipfire.org>
>>>>> Cc "Bernhard Bitsch" <bbitsch@ipfire.org>; "IPFire: =
Development-List" <development@lists.ipfire.org>
>>>>> Date 3/24/2025 9:40:15=E2=80=AFAM
>>>>> Subject Re: [PATCH] RPZ: update code to include WEBGUI and =
additional languages
>>>>>=20
>>>>>> Because it is not doing it on my system...
>>>>>>=20
>>>>>>> On 24 Mar 2025, at 14:38, Jon Murphy <jon.murphy@ipfire.org> =
wrote:
>>>>>>>=20
>>>>>>> Actually it did.
>>>>>>>=20
>>>>>>> Why do you think Unbound did not?
>>>>>>>=20
>>>>>>>=20
>>>>>>> ------ Original Message ------
>>>>>>> =46rom "Michael Tremer" <michael.tremer@ipfire.org>
>>>>>>> To "Jon Murphy" <jon.murphy@ipfire.org>
>>>>>>> Cc "Bernhard Bitsch" <bbitsch@ipfire.org>; "IPFire: =
Development-List" <development@lists.ipfire.org>
>>>>>>> Date 3/24/2025 9:36:53=E2=80=AFAM
>>>>>>> Subject Re: [PATCH] RPZ: update code to include WEBGUI and =
additional languages
>>>>>>>=20
>>>>>>>> Unbound did not put those there...
>>>>>>>>=20
>>>>>>>>> On 24 Mar 2025, at 14:33, Jon Murphy <jon.murphy@ipfire.org> =
wrote:
>>>>>>>>>=20
>>>>>>>>>=20
>>>>>>>>>=20
>>>>>>>>> And where are these stored?
>>>>>>>>>=20
>>>>>>>>> In `/etc/unbound/zonefiles`:
>>>>>>>>>=20
>>>>>>>>>=20
>>>>>>>>> [root@ipfire ~] # ls -al /etc/unbound/zonefiles
>>>>>>>>> total 20664
>>>>>>>>> drwxr-xr-x 2 nobody nobody     4096 Mar 24 04:40 .
>>>>>>>>> drwxr-xr-x 4 root   root       4096 Mar 19 16:24 ..
>>>>>>>>> -rw-r--r-- 1 nobody nobody  3999087 Mar 23 15:11 adhocSB.rpz
>>>>>>>>> -rw-r--r-- 1 nobody nobody     1411 Mar 23 14:23 allow.rpz
>>>>>>>>> -rw-r--r-- 1 nobody nobody    25355 Mar 24 04:40 =
AmazonTrkrHZ.rpz
>>>>>>>>> -rw-r--r-- 1 nobody nobody     7241 Mar 24 04:40 =
AppleTrkrHZ.rpz
>>>>>>>>> -rw-r--r-- 1 nobody nobody      178 Mar 23 14:23 block.rpz
>>>>>>>>> -rw-r--r-- 1 nobody nobody    78496 Mar 24 04:40 =
DOHblockHZ.rpz
>>>>>>>>> -rw-r--r-- 1 nobody nobody 16983551 Mar 24 04:40 =
MxProPlusHZ.rpz
>>>>>>>>> -rw-r--r-- 1 nobody nobody     2893 Mar 24 04:40 tldHZ.rpz
>>>>>>>>> -rw-r--r-- 1 nobody nobody    29419 Mar 24 04:40 WinTrkrHZ.rpz
>>>>>>>>> [root@ipfire ~] #
>>>>>>>>>=20
>>>>>>>>>=20
>>>>>>>>>=20
>>>>>>>>> ------ Original Message ------
>>>>>>>>> =46rom "Michael Tremer" <michael.tremer@ipfire.org>
>>>>>>>>> To "Bernhard Bitsch" <bbitsch@ipfire.org>
>>>>>>>>> Cc development@lists.ipfire.org
>>>>>>>>> Date 3/24/2025 9:25:40=E2=80=AFAM
>>>>>>>>> Subject Re: [PATCH] RPZ: update code to include WEBGUI and =
additional languages
>>>>>>>>>=20
>>>>>>>>>> Hello,
>>>>>>>>>>=20
>>>>>>>>>>>=20
>>>>>>>>>>> On 24 Mar 2025, at 13:33, Bernhard Bitsch =
<bbitsch@ipfire.org> wrote:
>>>>>>>>>>>    Am 24.03.2025 um 11:17 schrieb Michael Tremer:
>>>>>>>>>>>>=20
>>>>>>>>>>>>=20
>>>>>>>>>>>> Hello Jon,
>>>>>>>>>>>>>=20
>>>>>>>>>>>>>=20
>>>>>>>>>>>>> On 24 Mar 2025, at 00:00, Jon Murphy =
<jon.murphy@ipfire.org> wrote:
>>>>>>>>>>>>>  Michael,
>>>>>>>>>>>>>  FYI - I was wrong Unbound RPZ is _not_ watching the =
serial number, it is watching the "refresh", the number after the serial =
number.
>>>>>>>>>>>>=20
>>>>>>>>>>>> Refresh just tells the client how often to check for an =
update.
>>>>>>>>>>>> If that is actually being set by the list publisher, then =
we have another problem here, because they could put some insanely low =
value there and we would then DDoS their infrastructure. I think we =
should keep it like we have it in other places that we control how often =
we want to check or pull for updates.
>>>>>>>>>>>>=20
>>>>>>>>>>>  You are right. But an extra update process wastes =
additional processor time. The update mechanism of unbound does the =
check for update ( however it is realized ) nevertheless.
>>>>>>>>>>=20
>>>>>>>>>>  Yes, doing more things needs resources. But we are not =
seriously considering whether an IPFire system has enough resources to =
perform the download of a text file, or are we?
>>>>>>>>>>=20
>>>>>>>>>>>=20
>>>>>>>>>>>>> I understand that you don=E2=80=99t speak C, but you got =
the information from somewhere. Documentation maybe? Since that is out =
of date very often I like to consult the code.
>>>>>>>>>>>>> =46rom testing. Downloading rpz files using rpz unbound, =
and watching what happens. If the rpz file is setup for "once per day" =
refresh, then it only downloads one time.
>>>>>>>>>>>>>    However that won=E2=80=99t solve our problem . . . and =
having no cache.
>>>>>>>>>>>>> In `/etc/unbound/tuning.conf` there is `rrset-cache-size: =
128m`. Are you referring to a different cache.
>>>>>>>>>>>>=20
>>>>>>>>>>>> Naturally unbound is loading the zone into its memory which =
we generally call cache.
>>>>>>>>>>>> When I say cache I am thinking about persistent data =
storage across multiple restarts of Unbound. If I am downloading 100 MiB =
of RPZ lists (which is presumably still on the lower end) and I reboot =
my firewall, I do not want to download the same data again. We can only =
ever download a list *once* unless we are 100% certain that it has =
changed. Then we can download it once again.
>>>>>>>>>>>=20
>>>>>>>>>>>  The RPZ lists are stored in files in persistent storage. =
Unbound creates the internal cache from these.
>>>>>>>>>>=20
>>>>>>>>>>  And where are these stored?
>>>>>>>>>>=20
>>>>>>>>>>>=20
>>>>>>>>>>>>> Maybe we need to implement both?
>>>>>>>>>>>>>  Yes. There are very few AXFR list (I think only four were =
found). And many more HTTPS rpz files.
>>>>>>>>>>>>>    Jon
>>>>>>>>>>>>>   ------ Original Message ------
>>>>>>>>>>>>> =46rom "Michael Tremer" <michael.tremer@ipfire.org>
>>>>>>>>>>>>> To "Jon Murphy" <jon.murphy@ipfire.org>
>>>>>>>>>>>>> Cc "IPFire: Development-List" =
<development@lists.ipfire.org>
>>>>>>>>>>>>> Date 3/20/2025 11:26:43=E2=80=AFAM
>>>>>>>>>>>>> Subject Re: [PATCH] RPZ: update code to include WEBGUI and =
additional languages
>>>>>>>>>>>>>=20
>>>>>>>>>>>>>>=20
>>>>>>>>>>>>>> Hello Jon,
>>>>>>>>>>>>>> Please don=E2=80=99t forget to Cc the list...
>>>>>>>>>>>>>>=20
>>>>>>>>>>>>>>>=20
>>>>>>>>>>>>>>>  On 19 Mar 2025, at 18:27, Jon Murphy =
<jon.murphy@ipfire.org> wrote:
>>>>>>>>>>>>>>> Michael,
>>>>>>>>>>>>>>>=20
>>>>>>>>>>>>>>>>=20
>>>>>>>>>>>>>>>>  Where in the code is this implemented? I cannot find =
anything like this:
>>>>>>>>>>>>>>>=20
>>>>>>>>>>>>>>>  Keep in mind I am not a "C" person. Maybe in this =
section?:
>>>>>>>>>>>>>>> =
https://git.ipfire.org/?p=3Dthirdparty/unbound.git;a=3Dblob;f=3Dservices/a=
uthzone.c;hb=3D30b9cb5f813003d0a2b1c2e678652396615b1b7d#l5875
>>>>>>>>>>>>>>=20
>>>>>>>>>>>>>>  This where the AXFR response is being handled when doing =
a DNS zone transfer. This code is not being called when performing a =
HTTP download.
>>>>>>>>>>>>>> I understand that you don=E2=80=99t speak C, but you got =
the information from somewhere. Documentation maybe? Since that is out =
of date very often I like to consult the code.
>>>>>>>>>>>>>>=20
>>>>>>>>>>>>>>>=20
>>>>>>>>>>>>>>>  =E2=80=94
>>>>>>>>>>>>>>> When I was just learning about RPZ I created a separate =
RPZ file for testing. When I changed the SOA line with a new serial =
number, the RPZ file download would happen in about 5 minutes.
>>>>>>>>>>>>>>> https://people.ipfire.org/~jon/sblack-adhoc.rpz
>>>>>>>>>>>>>>=20
>>>>>>>>>>>>>>  It might well be that the file is not being reloaded if =
the download matches the content that unbound already has. That would of =
course save some resources.
>>>>>>>>>>>>>> However that won=E2=80=99t solve our problem with =
redundant downloads and having no cache.
>>>>>>>>>>>>>>=20
>>>>>>>>>>>>>>>=20
>>>>>>>>>>>>>>>  That is how I found out the SOA line is watched for a =
serial number change.
>>>>>>>>>>>>>>> I=E2=80=99ll reconfirm my findings.
>>>>>>>>>>>>>>>=20
>>>>>>>>>>>>>>>>=20
>>>>>>>>>>>>>>>>=20
>>>>>>>>>>>>>>>>>=20
>>>>>>>>>>>>>>>>>> The second reason is that we have a lot of firewalls =
out there. Not all of them will enable this feature and all of the =
lists, but even if it is a good chunk, we will generate terabytes of =
traffic which put load on the infrastructure and will cost money. It =
simply is not what we want to do, regardless of self-hosting those lists =
and pulling them from somewhere else.
>>>>>>>>>>>>>>>=20
>>>>>>>>>>>>>>>  So I understand, are you thinking of hosting RPZ AXFR =
(DNS zone transfer) on IPFire infrastructure?
>>>>>>>>>>>>>>=20
>>>>>>>>>>>>>>  No, I don=E2=80=99t think that we can generally do this. =
The biggest problem is licensing as we cannot take anyones content and =
host it ourselves. We would re-distribute those lists and that will only =
work with permission of the publishers. I assume that would be too much =
work to actually get some useful content out there. We might limit =
ourselves to only those lists that are under a very permissive license. =
Nobody wants that.
>>>>>>>>>>>>>> =46rom a technical point of view, DNS over TCP might not =
be very nice in terms of forging the transfer and so we would need TLS =
as well=E2=80=A6 It should work, but even if we would be able to =
encourage other people to publish their lists I doubt they would =
implement DNS over TLS for authoritative DNS. That standard is in very =
early stages as well.
>>>>>>>>>>>>>> As far as I can see, those vendors who offer a list as a =
commercial product are using DNS to distribute it (e.g. Spamhaus). Those =
people who have made this all a hobby are throwing the lists onto GitHub =
and let them handle the traffic.
>>>>>>>>>>>>>> Maybe we need to implement both?
>>>>>>>>>>>>>> -Michael
>>>>>>>>>>>>>>=20
>>>>>>>>>>>>>>>=20
>>>>>>>>>>>>>>>  Jon
>>>>>>>>>>>>>>> On 3/19/25 5:35 AM, Michael Tremer wrote:
>>>>>>>>>>>>>>>>=20
>>>>>>>>>>>>>>>>=20
>>>>>>>>>>>>>>>>   Hello Jon,
>>>>>>>>>>>>>>>> Where in the code is this implemented? I cannot find =
anything like this:
>>>>>>>>>>>>>>>> Unbound loads the entire file into memory and then =
starts parsing it. The only special treatment there is is to check =
whether the first line is a valid zone entry. It does not even have to =
be a SOA record.
>>>>>>>>>>>>>>>> =
https://git.ipfire.org/?p=3Dthirdparty/unbound.git;a=3Dblob;f=3Dservices/a=
uthzone.c;hb=3D30b9cb5f813003d0a2b1c2e678652396615b1b7d#l1188
>>>>>>>>>>>>>>>> I am also concerned that Unbound will not be able to =
support an upstream proxy for any downloads. The caching situation is =
also unclear for me, so I believe that we will be looking at writing a =
custom downloader that implements all these things.
>>>>>>>>>>>>>>>> -Michael
>>>>>>>>>>>>>>>>=20
>>>>>>>>>>>>>>>>>=20
>>>>>>>>>>>>>>>>>  On 19 Mar 2025, at 02:58, Jon Murphy =
<jon.murphy@ipfire.org> wrote:
>>>>>>>>>>>>>>>>> Michael,
>>>>>>>>>>>>>>>>>=20
>>>>>>>>>>>>>>>>>>=20
>>>>>>>>>>>>>>>>>>  The emphasis is on the repeated downloads of the =
same list. That is
>>>>>>>>>>>>>>>>>=20
>>>>>>>>>>>>>>>>>  =E2=80=8B> what cannot happen.
>>>>>>>>>>>>>>>>> The Unbound RPZ code, as installed within IPFire, =
watches for a change
>>>>>>>>>>>>>>>>> =E2=80=8Bin the SOA line of each RPZ file. This is an =
example of the first few
>>>>>>>>>>>>>>>>> =E2=80=8Blines for every RPZ file.
>>>>>>>>>>>>>>>>> $TTL 300
>>>>>>>>>>>>>>>>> @ SOA localhost. root.localhost. 1742298960 43200 3600 =
86400 300
>>>>>>>>>>>>>>>>> NS localhost.
>>>>>>>>>>>>>>>>> ;
>>>>>>>>>>>>>>>>> ; Title: HaGeZi's Pop-Up Ads DNS Blocklist
>>>>>>>>>>>>>>>>> ; Description: Blocks annoying and malicious pop-up =
ads.
>>>>>>>>>>>>>>>>> If the SOA serial number changes (e.g. the =
1742298960), then Unbound RPZ
>>>>>>>>>>>>>>>>> =E2=80=8Bcode does its thing and downloads. Otherwise =
there is no download.
>>>>>>>>>>>>>>>>>=20
>>>>>>>>>>>>>>>>>>=20
>>>>>>>>>>>>>>>>>>  So there has to be a way to ensure that we won=E2=80=99=
t download a list again
>>>>>>>>>>>>>>>>>=20
>>>>>>>>>>>>>>>>>  =E2=80=8B> unless it has actually changed.
>>>>>>>>>>>>>>>>> This should do what you want but I may be missing your =
point.
>>>>>>>>>>>>>>>>>=20
>>>>>>>>>>>>>>>>>>=20
>>>>>>>>>>>>>>>>>>  DNS has a builtin functionality called AXFR. It =
simply does the job
>>>>>>>>>>>>>>>>>=20
>>>>>>>>>>>>>>>>>  =E2=80=8B> for you. I was just wondering whether that =
was not being used.
>>>>>>>>>>>>>>>>> I need to read about AXFR/IXFR and learn a little =
more.
>>>>>>>>>>>>>>>>> Jon
>>>>>>>>>>>>>>>>> On 3/17/25 5:35 AM, Michael Tremer wrote:
>>>>>>>>>>>>>>>>>>=20
>>>>>>>>>>>>>>>>>>=20
>>>>>>>>>>>>>>>>>>   Good Morning Jon,
>>>>>>>>>>>>>>>>>>=20
>>>>>>>>>>>>>>>>>>>=20
>>>>>>>>>>>>>>>>>>>  On 16 Mar 2025, at 17:00, Jon Murphy =
<jon.murphy@ipfire.org> wrote:
>>>>>>>>>>>>>>>>>>> Michael,
>>>>>>>>>>>>>>>>>>> I was reading through you response again an I want =
to understand this post:
>>>>>>>>>>>>>>>>>>>=20
>>>>>>>>>>>>>>>>>>>>=20
>>>>>>>>>>>>>>>>>>>>  I have also stated that we cannot download any =
lists over HTTPS again and again and again. The implementation that we =
have here seems to exactly do that and therefore I think that my =
feedback has been dismissed entirely.
>>>>>>>>>>>>>>>>>>>=20
>>>>>>>>>>>>>>>>>>>  So if RPZ doesn't use HTTPS, what is it using? I am =
missing a key point here.
>>>>>>>>>>>>>>>>>>=20
>>>>>>>>>>>>>>>>>>  The emphasis is on the repeated downloads of the =
same list. That is what cannot happen.
>>>>>>>>>>>>>>>>>> Although it might not affect a lot of people in our =
general user-base, there are some that have a metered connection and =
will pay for data by volume. Some of the lists I looked at are just =
under 20 MiB. Therefore we need to keep any traffic down to a minimum. =
The second reason is that we have a lot of firewalls out there. Not all =
of them will enable this feature and all of the lists, but even if it is =
a good chunk, we will generate terabytes of traffic which put load on =
the infrastructure and will cost money. It simply is not what we want to =
do, regardless of self-hosting those lists and pulling them from =
somewhere else.
>>>>>>>>>>>>>>>>>> So there has to be a way to ensure that we won=E2=80=99=
t download a list again unless it has actually changed.
>>>>>>>>>>>>>>>>>> DNS has a builtin functionality called AXFR. It =
simply does the job for you. I was just wondering whether that was not =
being used.
>>>>>>>>>>>>>>>>>> HTTPS is an option because that is simply what we use =
elsewhere, but extra functionality will have to be built for it.
>>>>>>>>>>>>>>>>>> -Michael
>>>>>>>>>>>>>>>>>>=20
>>>>>>>>>>>>>>>>>>>=20
>>>>>>>>>>>>>>>>>>>  Jon
>>>>>>>>>>>>>>>>>>> On 2/13/25 3:34 PM, jon wrote:
>>>>>>>>>>>>>>>>>>>>=20
>>>>>>>>>>>>>>>>>>>>=20
>>>>>>>>>>>>>>>>>>>>   Michael,
>>>>>>>>>>>>>>>>>>>> I=E2=80=99ve read through your comments a few times =
and I ended up with many more questions.
>>>>>>>>>>>>>>>>>>>>=20
>>>>>>>>>>>>>>>>>>>>>=20
>>>>>>>>>>>>>>>>>>>>>  What I rather mean is that it has never been =
added as a topic on the agenda and it has not been pitched by yourself.
>>>>>>>>>>>>>>>>>>>>=20
>>>>>>>>>>>>>>>>>>>>  To me the efforts to get new code accepted seem to =
have changed and it seemed easier in the past. In the past I made the =
Core Team aware via the Dev Mailing List and wrote a simple two or three =
paragraphs of "What is it? / What is the value? / Here is the code"
>>>>>>>>>>>>>>>>>>>> So in an effort to move forward: How exactly is =
something presented to the Core Team?
>>>>>>>>>>>>>>>>>>>> Is there an example of a recent effort that was =
presented that I can see as a sample? (This type of info can also be =
added to the Wiki)
>>>>>>>>>>>>>>>>>>>> I understand you want it this way, but I don=E2=80=99=
t know what exactly is needed. Please be specific.
>>>>>>>>>>>>>>>>>>>> Jon
>>>>>>>>>>>>>>>>>>>> PS - I am not ignoring your other comments, I am =
just trying to move forward and keep things simple.
>>>>>>>>>>>>>>>>>>>>=20
>>>>>>>>>>>>>>>>>>>>>=20
>>>>>>>>>>>>>>>>>>>>>  On Feb 8, 2025, at 1:27=E2=80=AFPM, Michael =
Tremer <michael.tremer@ipfire.org> wrote:
>>>>>>>>>>>>>>>>>>>>> Hello Jon,
>>>>>>>>>>>>>>>>>>>>> Thanks for your reply. And good that you are =
copying everyone into this conversation.
>>>>>>>>>>>>>>>>>>>>>=20
>>>>>>>>>>>>>>>>>>>>>>=20
>>>>>>>>>>>>>>>>>>>>>>  On 8 Feb 2025, at 18:41, jon =
<jon.murphy@ipfire.org> wrote:
>>>>>>>>>>>>>>>>>>>>>> Michael,
>>>>>>>>>>>>>>>>>>>>>>=20
>>>>>>>>>>>>>>>>>>>>>>>=20
>>>>>>>>>>>>>>>>>>>>>>>  I think I have covered this all at lengths =
before that this project has been started as a separate effort
>>>>>>>>>>>>>>>>>>>>>>=20
>>>>>>>>>>>>>>>>>>>>>>  Yes, this has been a separate effort (a very =
public separate effort). Yes, as you pointed this out early on with the =
"proof-of-concept" and then my request for people to help test RPZ. =
Nothing was hidden.
>>>>>>>>>>>>>>>>>>>>>> This was done because you (and maybe others) did =
not have the time and I wanted to help and because I needed assistance =
with RPZ. I tried my best to do this without bothering you.
>>>>>>>>>>>>>>>>>>>>>=20
>>>>>>>>>>>>>>>>>>>>>  I don=E2=80=99t that it is accurate that nobody =
wanted to help on this. The list was always open - although not every =
email has been replied to swiftly it is also your responsibility to =
raise a question again if it was missed. People here have open ears.
>>>>>>>>>>>>>>>>>>>>> It was also stated on this very list on in our =
documentation that working on something without involving the core team =
is a risky undertaking. Of course IPFire is free software and so =
everyone is free to fork if they wish to do so.
>>>>>>>>>>>>>>>>>>>>>=20
>>>>>>>>>>>>>>>>>>>>>>=20
>>>>>>>>>>>>>>>>>>>>>>=20
>>>>>>>>>>>>>>>>>>>>>>>=20
>>>>>>>>>>>>>>>>>>>>>>> and as far as I am aware none of the other team =
members has been involved. This has not been discussed either on this =
list, on our calls.
>>>>>>>>>>>>>>>>>>>>>>=20
>>>>>>>>>>>>>>>>>>>>>>  You were aware many steps along the way. See =
your email on July 28, 2024, August 15, 2024, September 30, 2024, =
December 23, 2024, and January 16. My attempts to get the team involved =
were met with "things are busy" and sometimes silence. (Yes, I get it, =
people are busy.)
>>>>>>>>>>>>>>>>>>>>>> You and Adolf, Leo, Erik and Bernhard have been =
aware since the beginning. You mention you were aware of the =
"proof-of-concept". If you include those beginning posts, since Sep =
2023.
>>>>>>>>>>>>>>>>>>>>>=20
>>>>>>>>>>>>>>>>>>>>>  Yes, I am aware of a proof-of-concept that I have =
been running myself for a long time. I am also aware of the efforts that =
you have been taking.
>>>>>>>>>>>>>>>>>>>>> Yet I don=E2=80=99t think there has ever been any =
joint effort, or am I seeing that wrong?
>>>>>>>>>>>>>>>>>>>>>=20
>>>>>>>>>>>>>>>>>>>>>>=20
>>>>>>>>>>>>>>>>>>>>>>=20
>>>>>>>>>>>>>>>>>>>>>>>=20
>>>>>>>>>>>>>>>>>>>>>>> This has not been discussed . . . on our calls.
>>>>>>>>>>>>>>>>>>>>>>=20
>>>>>>>>>>>>>>>>>>>>>>  On the July 28th you stated:
>>>>>>>>>>>>>>>>>>>>>> "We have talked about RPZ many times on the =
monthly call since the URL filter feature is falling more and more out =
of fashion. I think there is also many posts about this on the forum."
>>>>>>>>>>>>>>>>>>>>>> Please don=E2=80=99t insult me again by stating =
"you know what I mean".
>>>>>>>>>>>>>>>>>>>>>> And it has been discussed but not documented in =
the Monthly Meeting notes.
>>>>>>>>>>>>>>>>>>>>>=20
>>>>>>>>>>>>>>>>>>>>>  I am not at all insulting you. I don=E2=80=99t =
want to take this down to a personal level at all. This is a public =
mailing list and people who read this don=E2=80=99t need to listen to an =
argument we are having. They are here for the tech inside IPFire.
>>>>>>>>>>>>>>>>>>>>> When I wrote that it has not been discussed that =
does not mean that we have not been touching on the topic. We have been =
talking about lots of things on the calls, the weather, politics, how =
our pets are. None of that makes it to the logs. What I rather mean is =
that it has never been added as a topic on the agenda and it has not =
been pitched by yourself.
>>>>>>>>>>>>>>>>>>>>>=20
>>>>>>>>>>>>>>>>>>>>>>=20
>>>>>>>>>>>>>>>>>>>>>>=20
>>>>>>>>>>>>>>>>>>>>>>>=20
>>>>>>>>>>>>>>>>>>>>>>> Instead there has been a separate conversation =
on the forum with the occasional dip here to the list. But that was not =
a regular two-way conversation.
>>>>>>>>>>>>>>>>>>>>>>=20
>>>>>>>>>>>>>>>>>>>>>>  Regular conversation on the Dev Mailing list is =
many times met with silence. I get it, people are busy.
>>>>>>>>>>>>>>>>>>>>>> And regular two-way conversation doesn=E2=80=99t =
happen on the list. At least not with me. I=E2=80=99d be happy to point =
out the posts that were met with silence.
>>>>>>>>>>>>>>>>>>>>>> Again, I get it, people are busy.
>>>>>>>>>>>>>>>>>>>>>=20
>>>>>>>>>>>>>>>>>>>>>  And you think my emails are not being met with =
silence? This has nothing to do with this specific topic. This has =
something to do with how occupied people are and how engaged they are on =
certain topics. Not everyone is involved in all the things and simply =
will ignore emails simply based on their subject line.
>>>>>>>>>>>>>>>>>>>>>=20
>>>>>>>>>>>>>>>>>>>>>>=20
>>>>>>>>>>>>>>>>>>>>>>  But the "dip here to the list" were my attempts =
to get a conversation started. As I said, many time met with silence.
>>>>>>>>>>>>>>>>>>>>>> The only place I was not met with silence was on =
the Community. You have a great group of people in the Community. It is =
a shame you don=E2=80=99t want to have others help. It would reduce your =
workload.
>>>>>>>>>>>>>>>>>>>>>=20
>>>>>>>>>>>>>>>>>>>>>  You should stop making statements that are not =
true. Who doesn=E2=80=99t want anyone to help?
>>>>>>>>>>>>>>>>>>>>> Not having this conversation on a Saturday evening =
would reduce my workload. At least it would free up time for something =
else. Helping with the things that are already on the go would reduce =
the workload of the entire team. Starting one thing at a time and =
finishing it is a lot better to manage than starting a hundred things =
and not even finish one. I can tell you that I already have a hundred =
things on the go.
>>>>>>>>>>>>>>>>>>>>>=20
>>>>>>>>>>>>>>>>>>>>>>=20
>>>>>>>>>>>>>>>>>>>>>>=20
>>>>>>>>>>>>>>>>>>>>>>>=20
>>>>>>>>>>>>>>>>>>>>>>> Therefore, what am I supposed to do with this =
email?
>>>>>>>>>>>>>>>>>>>>>>=20
>>>>>>>>>>>>>>>>>>>>>>  To me it is beyond obvious=E2=80=A6
>>>>>>>>>>>>>>>>>>>>>> If it isn=E2=80=99t what you want, then guide me =
with how to do this the correct way. And be specific. I am trying to =
help. I am trying to make things better. I am trying to do things the =
right way.
>>>>>>>>>>>>>>>>>>>>>=20
>>>>>>>>>>>>>>>>>>>>>  To me it isn=E2=80=99t. This is yet another =
project that has been dumped to the list like so many before and later =
on everyone has left to have the team deal with the rest.
>>>>>>>>>>>>>>>>>>>>> It is a huge patch set. You explained what the =
vision is, but that is about it. There is no chance this will continue =
if this disagreement isn=E2=80=99t solved first. I didn=E2=80=99t even =
look at the code.
>>>>>>>>>>>>>>>>>>>>>=20
>>>>>>>>>>>>>>>>>>>>>>=20
>>>>>>>>>>>>>>>>>>>>>>=20
>>>>>>>>>>>>>>>>>>>>>>>=20
>>>>>>>>>>>>>>>>>>>>>>> I don=E2=80=99t want to merge code that I =
don=E2=80=99t agree with.
>>>>>>>>>>>>>>>>>>>>>>=20
>>>>>>>>>>>>>>>>>>>>>>  I asked multiple times if you "agreed with the =
concept" and again, met with silence. Yes I get it, people are busy.
>>>>>>>>>>>>>>>>>>>>>=20
>>>>>>>>>>>>>>>>>>>>>  Having support for RPZ? Yes, it was definitely on =
the roadmap. That I agree with.
>>>>>>>>>>>>>>>>>>>>>=20
>>>>>>>>>>>>>>>>>>>>>>=20
>>>>>>>>>>>>>>>>>>>>>>=20
>>>>>>>>>>>>>>>>>>>>>>>=20
>>>>>>>>>>>>>>>>>>>>>>> So many fundamental things that I have been =
raising have either not been discussed or outright dismissed.
>>>>>>>>>>>>>>>>>>>>>>=20
>>>>>>>>>>>>>>>>>>>>>>  You mentioned this a in the past, but for some =
reason you do not disclose what I dismissed. Why do you continue to make =
this harder, wouldn=E2=80=99t it not be easier to tell me what I have =
dismissed?
>>>>>>>>>>>>>>>>>>>>>> I have sent multiple emails trying to answer your =
concerns and comments. On July 28, Aug 14, Aug 22, Aug 23, Sep 30, etc.
>>>>>>>>>>>>>>>>>>>>>> I=E2=80=99ve gone through all of the questions =
you asked and I cannot find a "dismissed" item.
>>>>>>>>>>>>>>>>>>>>>=20
>>>>>>>>>>>>>>>>>>>>>  Maybe I need to be *more clear*. I feel humoured =
by this.
>>>>>>>>>>>>>>>>>>>>> It is late on a Saturday and I want my dinner =
soon, but certainly I have stated that this should never be an add-on =
considering it is supposed to replace URL Filter. We should never allow =
people to add their own sources. I have also stated that we cannot =
download any lists over HTTPS again and again and again. The =
implementation that we have here seems to exactly do that and therefore =
I think that my feedback has been dismissed entirely.
>>>>>>>>>>>>>>>>>>>>>=20
>>>>>>>>>>>>>>>>>>>>>>=20
>>>>>>>>>>>>>>>>>>>>>>=20
>>>>>>>>>>>>>>>>>>>>>>>=20
>>>>>>>>>>>>>>>>>>>>>>> I don=E2=80=99t want to merge code that has no =
future inside IPFire as there is no constructive conversation with the =
maintainers of it.
>>>>>>>>>>>>>>>>>>>>>>=20
>>>>>>>>>>>>>>>>>>>>>>  The maintainers of Unbound and/or RPZ?
>>>>>>>>>>>>>>>>>>>>>> The maintainers of Hagezi list, the threatfox =
list, the urlhaus list, etc.?
>>>>>>>>>>>>>>>>>>>>>> What else? The maintainers or the RPZ scripts? =
That is me. Let=E2=80=99s talk!
>>>>>>>>>>>>>>>>>>>>>=20
>>>>>>>>>>>>>>>>>>>>>  You. I don=E2=80=99t care much about the =
providers of the lists.
>>>>>>>>>>>>>>>>>>>>>=20
>>>>>>>>>>>>>>>>>>>>>>=20
>>>>>>>>>>>>>>>>>>>>>>  See, this is where it gets confusing. There are =
hundreds of open source packages as part of IPFire. Pick the last five =
years of items added to the IPFire build. You're telling me you have =
"constructive conversation with the maintainers" of all of the added =
packages?
>>>>>>>>>>>>>>>>>>>>>=20
>>>>>>>>>>>>>>>>>>>>>  They publish their software and they don=E2=80=99t =
care whether I am pulling it or not. They publish it with the commitment =
to maintain it - sometimes for better and sometimes for worse.
>>>>>>>>>>>>>>>>>>>>> You care about me pulling your code and I don=E2=80=99=
t know whether you would commit to maintain this.
>>>>>>>>>>>>>>>>>>>>> These two are very different cases.
>>>>>>>>>>>>>>>>>>>>>=20
>>>>>>>>>>>>>>>>>>>>>>=20
>>>>>>>>>>>>>>>>>>>>>>  Pick the IP Blocklists list (i.e., 3CORESEC, =
ABUSECH, DSHIELD, SPAMHAUS, etc.) or the Suricata lists =
(i.e.,Emergingthreats.net <http://emergingthreats.net/>,Abuse.ch =
<http://abuse.ch/>, etc.). So you=E2=80=99ve have "constructive =
conversation with the maintainers"?
>>>>>>>>>>>>>>>>>>>>>=20
>>>>>>>>>>>>>>>>>>>>>  Yes, occasionally I have phone calls with a few =
of these providers.
>>>>>>>>>>>>>>>>>>>>>=20
>>>>>>>>>>>>>>>>>>>>>>=20
>>>>>>>>>>>>>>>>>>>>>>=20
>>>>>>>>>>>>>>>>>>>>>>>=20
>>>>>>>>>>>>>>>>>>>>>>> Having been trying for a long time to make you =
aware of this, nothing of this should come as a surprise.
>>>>>>>>>>>>>>>>>>>>>>=20
>>>>>>>>>>>>>>>>>>>>>>  Ha! Yes a surprise. In the beginning you seemed =
interested as IPFire needed a replacement for URL Filter. You asked good =
questions about the lists picked, asked for the value to the users, etc. =
And I answered the best I could.
>>>>>>>>>>>>>>>>>>>>>> You even asked: =E2=80=9CWhy is this realised as =
an add-on and not part of the core system?=E2=80=9D from your Jul 28, =
2024 email.
>>>>>>>>>>>>>>>>>>>>>=20
>>>>>>>>>>>>>>>>>>>>>  Ah, so, why is the patch creating an add-on? Not =
that I am saying that what I say is law, but it has not been challenged =
either. If my input is being ignored, why should I put this to the top =
of my list of priorities? I am not disappointed about this, just trying =
to be very good with my time.
>>>>>>>>>>>>>>>>>>>>>=20
>>>>>>>>>>>>>>>>>>>>>>=20
>>>>>>>>>>>>>>>>>>>>>>  And on January 16, 2025 I wrote a message =
looking for help. And you were kind to respond quickly. So in three =
weeks time, since the kind response, something has changed. You went =
from supportive to "this".
>>>>>>>>>>>>>>>>>>>>>> So yes, I am surprised.
>>>>>>>>>>>>>>>>>>>>>=20
>>>>>>>>>>>>>>>>>>>>>  Well, maybe I should not have replied to that =
email. It was clear that you were on some path that was not right, but =
you were not interested before in finding the right path from the =
beginning.
>>>>>>>>>>>>>>>>>>>>>=20
>>>>>>>>>>>>>>>>>>>>>>=20
>>>>>>>>>>>>>>>>>>>>>>=20
>>>>>>>>>>>>>>>>>>>>>>>=20
>>>>>>>>>>>>>>>>>>>>>>> Please consider if that can be changed and if =
there is a path forward with this.
>>>>>>>>>>>>>>>>>>>>>>=20
>>>>>>>>>>>>>>>>>>>>>>  Be more specific, what has to change? What =
exactly did I dismiss?
>>>>>>>>>>>>>>>>>>>>>=20
>>>>>>>>>>>>>>>>>>>>>  Dismissal is just my assumption. I don=E2=80=99t =
know what you actually did with my feedback. I can only see the end =
product that does not seem contain much of it. Repeatedly I have been =
pointing out that we should think before we build. I am sure a lot of =
hours have now gone into some code that simply does not satisfy me. And =
I am not not talking about the code itself, what it does is what I =
don=E2=80=99t think is right for us.
>>>>>>>>>>>>>>>>>>>>> The process is very clear for me that we should =
first of all think whether we want a certain feature now. Then there =
should be a clear roadmap for everyone to follow; tasks can be split-up =
as we go and hopefully then have something that is maintainable, =
interesting for our users and even would do us proud. This is how this =
should work.
>>>>>>>>>>>>>>>>>>>>> So, what has to change? I don=E2=80=99t think with =
shouting at each other, throwing patches around and making me generally =
unhappy is a good start.
>>>>>>>>>>>>>>>>>>>>> -Michael
>>>>>>>>>>>>>>>>>>>>>=20
>>>>>>>>>>>>>>>>>>>>>>=20
>>>>>>>>>>>>>>>>>>>>>>  Jon
>>>>>>>>>>>>>>>>>>>>>>=20
>>>>>>>>>>>>>>>>>>>>>>>=20
>>>>>>>>>>>>>>>>>>>>>>>  On Feb 6, 2025, at 2:13=E2=80=AFPM, Michael =
Tremer <michael.tremer@ipfire.org> wrote:
>>>>>>>>>>>>>>>>>>>>>>> Hello Jon,
>>>>>>>>>>>>>>>>>>>>>>> Well, here we are again with another patch =
regarding this feature.
>>>>>>>>>>>>>>>>>>>>>>> I cannot quite see from your email what the =
question is, but if this is a request to have this merged into IPFire, I =
am once again sorry to disappoint you.
>>>>>>>>>>>>>>>>>>>>>>> I think I have covered this all at lengths =
before that this project has been started as a separate effort and as =
far as I am aware none of the other team members has been involved. This =
has not been discussed either on this list, on our calls. Instead there =
has been a separate conversation on the forum with the occasional dip =
here to the list. But that was not a regular two-way conversation. =
Therefore, what am I supposed to do with this email?
>>>>>>>>>>>>>>>>>>>>>>> I don=E2=80=99t want to merge code that I =
don=E2=80=99t agree with. So many fundamental things that I have been =
raising have either not been discussed or outright dismissed.
>>>>>>>>>>>>>>>>>>>>>>> I don=E2=80=99t want to merge code that has no =
future inside IPFire as there is no constructive conversation with the =
maintainers of it.
>>>>>>>>>>>>>>>>>>>>>>> Having been trying for a long time to make you =
aware of this, nothing of this should come as a surprise.
>>>>>>>>>>>>>>>>>>>>>>> Please consider if that can be changed and if =
there is a path forward with this.
>>>>>>>>>>>>>>>>>>>>>>> All the best,
>>>>>>>>>>>>>>>>>>>>>>> -Michael
>>>>>>>>>>>>>>>>>>>>>>>=20
>>>>>>>>>>>>>>>>>>>>>>>>=20
>>>>>>>>>>>>>>>>>>>>>>>>  On 6 Feb 2025, at 16:35, Jon Murphy =
<jon.murphy@ipfire.org> wrote:
>>>>>>>>>>>>>>>>>>>>>>>> What is it?
>>>>>>>>>>>>>>>>>>>>>>>> Response Policy Zone (RPZ) is a mechanism to =
define local policies in a
>>>>>>>>>>>>>>>>>>>>>>>> standardized way and load those policies from =
external sources.
>>>>>>>>>>>>>>>>>>>>>>>> Bottom line: RPZ allows admins to easily block =
access to websites via DNS lookup.
>>>>>>>>>>>>>>>>>>>>>>>> RPZ can block websites via categories. Examples =
include: fake websites, annoying
>>>>>>>>>>>>>>>>>>>>>>>> pop-up ads, newly registered domains, DoH =
bypass sites, bad "host" services,
>>>>>>>>>>>>>>>>>>>>>>>> maliscious top level domains (e.g., *.zip, =
*.mov), piracy, gambling, pornography,
>>>>>>>>>>>>>>>>>>>>>>>> and more. RPZ lists come from various RPZ =
providers and their available
>>>>>>>>>>>>>>>>>>>>>>>> catagories.
>>>>>>>>>>>>>>>>>>>>>>>> This RPZ add-on enables the RPZ functionality =
by adding a couple lines in a
>>>>>>>>>>>>>>>>>>>>>>>> configuration file. This add-on simply adds =
configuration files and adds
>>>>>>>>>>>>>>>>>>>>>>>> scripts (config, metrics and sleep) to make RPZ =
easier for the admin to use.
>>>>>>>>>>>>>>>>>>>>>>>> The RPZ scripts include additional languages: =
German, Spanish, French, Turkish,
>>>>>>>>>>>>>>>>>>>>>>>> and Italian.
>>>>>>>>>>>>>>>>>>>>>>>> RPZ itself was release in 2010 and has been =
part of the IPFire build since ~2015.
>>>>>>>>>>>>>>>>>>>>>>>> Why is it needed? What is its value?
>>>>>>>>>>>>>>>>>>>>>>>> - The RPZ concept places this filtering into =
IPFire, our internet access
>>>>>>>>>>>>>>>>>>>>>>>> gateway, which is (should be) solely used as =
DNS source of the internal network.
>>>>>>>>>>>>>>>>>>>>>>>> - As most sites use HTTPS it makes it difficult =
to filter traffic with URL
>>>>>>>>>>>>>>>>>>>>>>>> Filter without also properly configuring =
conventional (non-transparent)
>>>>>>>>>>>>>>>>>>>>>>>> mode on the proxy. RPZ is a nice replacement =
for the URL Filter.
>>>>>>>>>>>>>>>>>>>>>>>> - No need to install and maintain an additional =
device like PiHole or AdBlock
>>>>>>>>>>>>>>>>>>>>>>>> browser extensions on multiple user devices.
>>>>>>>>>>>>>>>>>>>>>>>> - This is an additional layer of protection for =
users. Less worry someone will
>>>>>>>>>>>>>>>>>>>>>>>> click on something that gets them into trouble. =
And, saying this with emphasis,
>>>>>>>>>>>>>>>>>>>>>>>> the ability to do it in one place!
>>>>>>>>>>>>>>>>>>>>>>>> - Blocked sites save on unneeded traffic and =
can lessen the threat of malware
>>>>>>>>>>>>>>>>>>>>>>>> in advertisements
>>>>>>>>>>>>>>>>>>>>>>>> - Logging allows the admin to see the site =
blocked and take actions
>>>>>>>>>>>>>>>>>>>>>>>> - RPZ will be used at the home, home-office =
(work from home), schools,
>>>>>>>>>>>>>>>>>>>>>>>> ministerial, and at the office. Device counts =
are small (2-6) to medium (~80)
>>>>>>>>>>>>>>>>>>>>>>>> to mediam-large (200+).
>>>>>>>>>>>>>>>>>>>>>>>> - RPZ can block ads, popups, phishing, =
scammers, spyware, malware, annoying
>>>>>>>>>>>>>>>>>>>>>>>> popups, NSFW links, DOH servers, and the usual =
internet trash.
>>>>>>>>>>>>>>>>>>>>>>>> ------------------------------
>>>>>>>>>>>>>>>>>>>>>>>> Change Log for RPZ add-on
>>>>>>>>>>>>>>>>>>>>>>>> rpz-1.0.0-18 on 2025-02-05
>>>>>>>>>>>>>>>>>>>>>>>> - Build for approval & release as IPFire add-on
>>>>>>>>>>>>>>>>>>>>>>>> ---
>>>>>>>>>>>>>>>>>>>>>>>> rpz-beta-0.1.18-18.ipfire on 2025-02-01
>>>>>>>>>>>>>>>>>>>>>>>> rpz.cgi:
>>>>>>>>>>>>>>>>>>>>>>>> - new feature: added a mod key to force a =
unbound restart
>>>>>>>>>>>>>>>>>>>>>>>> rpz-config and rpz-make:
>>>>>>>>>>>>>>>>>>>>>>>> - new feature: added action for unbound restart =
`rpz-config unbound-restart`
>>>>>>>>>>>>>>>>>>>>>>>> rpz-metrics:
>>>>>>>>>>>>>>>>>>>>>>>> - simple reformatting
>>>>>>>>>>>>>>>>>>>>>>>> - rename far right column from "last update" to =
"last download"
>>>>>>>>>>>>>>>>>>>>>>>> ---
>>>>>>>>>>>>>>>>>>>>>>>> rpz-beta-0.1.17-17.ipfire on 2024-12-09
>>>>>>>>>>>>>>>>>>>>>>>> rpz-make
>>>>>>>>>>>>>>>>>>>>>>>> - bug fix: corrected validation regex for =
wildcards like: `*.domain.com`
>>>>>>>>>>>>>>>>>>>>>>>> ---
>>>>>>>>>>>>>>>>>>>>>>>> rpz-beta-0.1.16-16.ipfire on 2024-11-18
>>>>>>>>>>>>>>>>>>>>>>>> rpz-make
>>>>>>>>>>>>>>>>>>>>>>>> - new feature: updated validation regex
>>>>>>>>>>>>>>>>>>>>>>>> - bug fix: moved validation to beginning of =
process. Now we validate before
>>>>>>>>>>>>>>>>>>>>>>>> creating config files.
>>>>>>>>>>>>>>>>>>>>>>>> rpz.cgi:
>>>>>>>>>>>>>>>>>>>>>>>> - new feature: use CSS color variables of the =
main ipfire theme
>>>>>>>>>>>>>>>>>>>>>>>> - bug fix: empty zonefile remarks were stored =
as =E2=80=9Cundef=E2=80=9D and caused a warning
>>>>>>>>>>>>>>>>>>>>>>>> - bug fix: HTML textarea removes the first =
empty line in a custom list
>>>>>>>>>>>>>>>>>>>>>>>> - thank you Leo!
>>>>>>>>>>>>>>>>>>>>>>>> ---
>>>>>>>>>>>>>>>>>>>>>>>> rpz-beta-0.1.15-15.ipfire on 2024-11-04
>>>>>>>>>>>>>>>>>>>>>>>> rpz.cgi:
>>>>>>>>>>>>>>>>>>>>>>>> - new feature: added new language file for =
Turkish (thank you Peppe)
>>>>>>>>>>>>>>>>>>>>>>>> rpz-make
>>>>>>>>>>>>>>>>>>>>>>>> - bug fix: corrected empty allow/block list =
issue. An empty allow/block list
>>>>>>>>>>>>>>>>>>>>>>>> will now remove contents of allow/block.rpz =
files and remove unneeded
>>>>>>>>>>>>>>>>>>>>>>>> allow/block.conf file. (thank you iptom)
>>>>>>>>>>>>>>>>>>>>>>>> ---
>>>>>>>>>>>>>>>>>>>>>>>> rpz-beta-0.1.14-14.ipfire on 2024-10-29
>>>>>>>>>>>>>>>>>>>>>>>> rpz-config:
>>>>>>>>>>>>>>>>>>>>>>>> - bug fix: correct missing rpz extension. =
`rpz-config list` displayed URL
>>>>>>>>>>>>>>>>>>>>>>>> incorrectly (thank you Bernhard)
>>>>>>>>>>>>>>>>>>>>>>>> rpz.cgi:
>>>>>>>>>>>>>>>>>>>>>>>> - bug fix: remove extra `"` in language files =
(thank you Bernhard)
>>>>>>>>>>>>>>>>>>>>>>>> - new feature: slightly dim "apply" button when =
not enabled
>>>>>>>>>>>>>>>>>>>>>>>> ---
>>>>>>>>>>>>>>>>>>>>>>>> rpz-beta-0.1.13-13.ipfire on 2024-10-27
>>>>>>>>>>>>>>>>>>>>>>>> - skipped
>>>>>>>>>>>>>>>>>>>>>>>> ---
>>>>>>>>>>>>>>>>>>>>>>>> rpz-beta-0.1.12-12.ipfire on 2024-10-21
>>>>>>>>>>>>>>>>>>>>>>>> rpz.cgi:
>>>>>>>>>>>>>>>>>>>>>>>> - new feature: added new language file for =
French (thank you gw-ipfire)
>>>>>>>>>>>>>>>>>>>>>>>> ---
>>>>>>>>>>>>>>>>>>>>>>>> rpz-beta-0.1.11-11.ipfire on 2024-10-18
>>>>>>>>>>>>>>>>>>>>>>>> rpz.cgi:
>>>>>>>>>>>>>>>>>>>>>>>> - new feature: added new language file for =
Italian (thank you umberto)
>>>>>>>>>>>>>>>>>>>>>>>> - new feature: added new language file for =
Spanish (thank you Roberto)
>>>>>>>>>>>>>>>>>>>>>>>> ---
>>>>>>>>>>>>>>>>>>>>>>>> rpz-beta-0.1.10-10.ipfire on 2024-10-15
>>>>>>>>>>>>>>>>>>>>>>>> rpz-make:
>>>>>>>>>>>>>>>>>>>>>>>> - bug fix: corrected validation error for a =
custom list entry (thank you siosios)
>>>>>>>>>>>>>>>>>>>>>>>> - e.g., `*.cloudflare-dns.com`
>>>>>>>>>>>>>>>>>>>>>>>> install.sh:
>>>>>>>>>>>>>>>>>>>>>>>> - bug fix: add chown to correct user created =
files
>>>>>>>>>>>>>>>>>>>>>>>> update.sh:
>>>>>>>>>>>>>>>>>>>>>>>> - bug fix: add chown to correct user created =
files (thank you siosios)
>>>>>>>>>>>>>>>>>>>>>>>> ---
>>>>>>>>>>>>>>>>>>>>>>>> rpz-beta-0.1.9-9.ipfire on 2024-10-08
>>>>>>>>>>>>>>>>>>>>>>>> rpz.cgi:
>>>>>>>>>>>>>>>>>>>>>>>> - new feature: added new language file for =
German (thank you Leo)
>>>>>>>>>>>>>>>>>>>>>>>> - bug fix: add missing "rpz exitcode 110"
>>>>>>>>>>>>>>>>>>>>>>>> - bug fix: corrected missing RPZ menu item at =
menu > IPFire
>>>>>>>>>>>>>>>>>>>>>>>> ---
>>>>>>>>>>>>>>>>>>>>>>>> rpz-beta-0.1.8-8.ipfire on 2024-10-04
>>>>>>>>>>>>>>>>>>>>>>>> - skipped
>>>>>>>>>>>>>>>>>>>>>>>> ---
>>>>>>>>>>>>>>>>>>>>>>>> rpz-beta-0.1.7-7.ipfire on 2024-10-03
>>>>>>>>>>>>>>>>>>>>>>>> All:
>>>>>>>>>>>>>>>>>>>>>>>> - new feature: includes beta version numbers =
for pakfire package,
>>>>>>>>>>>>>>>>>>>>>>>> instead of only `rpz-1.0.0-1.ipfire`, for each =
release.
>>>>>>>>>>>>>>>>>>>>>>>> rpz.cgi:
>>>>>>>>>>>>>>>>>>>>>>>> - new feature: added new WebGUI at `rpz.cgi`
>>>>>>>>>>>>>>>>>>>>>>>> - a BIG thank you to Leo Hofmann for all of his =
work creating the webgui!!
>>>>>>>>>>>>>>>>>>>>>>>> - bug fix: corrected missing RPZ menu item at =
menu > IPFire
>>>>>>>>>>>>>>>>>>>>>>>> rpz-make:
>>>>>>>>>>>>>>>>>>>>>>>> - new feature: validate entries in allowlist =
and blocklist
>>>>>>>>>>>>>>>>>>>>>>>> - new feature: add "no-reload" option for =
WebGUI
>>>>>>>>>>>>>>>>>>>>>>>> rpz-metrics:
>>>>>>>>>>>>>>>>>>>>>>>> - new feature: info can be sorted by name, by =
hit count, by line count, by
>>>>>>>>>>>>>>>>>>>>>>>> "enabled" list or all lists
>>>>>>>>>>>>>>>>>>>>>>>> backups:
>>>>>>>>>>>>>>>>>>>>>>>> - bug fix: include all files in =
`/var/ipfire/dns/rpz` directory in backup
>>>>>>>>>>>>>>>>>>>>>>>> update.sh:
>>>>>>>>>>>>>>>>>>>>>>>> - bug fix: corrected ownership for =
`/var/ipfire/dns/rpz` directory during an
>>>>>>>>>>>>>>>>>>>>>>>> update
>>>>>>>>>>>>>>>>>>>>>>>> Build:
>>>>>>>>>>>>>>>>>>>>>>>> - bug fix: `block.rpz.conf` and `block.rpz` =
from build. Files to be created
>>>>>>>>>>>>>>>>>>>>>>>> by `rpz-make`
>>>>>>>>>>>>>>>>>>>>>>>> WebGUI and German language file
>>>>>>>>>>>>>>>>>>>>>>>> Contribution-by: Leo-Andres Hofmann =
<hofmann@leo-andres.de>
>>>>>>>>>>>>>>>>>>>>>>>> Spanish language file
>>>>>>>>>>>>>>>>>>>>>>>> Contribution-by: Roberto Pe=C3=B1a
>>>>>>>>>>>>>>>>>>>>>>>> Italian language file
>>>>>>>>>>>>>>>>>>>>>>>> Contribution-by: Umberto Parma
>>>>>>>>>>>>>>>>>>>>>>>> French language file
>>>>>>>>>>>>>>>>>>>>>>>> Contribution-by: gw-ipfire
>>>>>>>>>>>>>>>>>>>>>>>> Turkish language file
>>>>>>>>>>>>>>>>>>>>>>>> Contribution-by: Peppe Tech
>>>>>>>>>>>>>>>>>>>>>>>> Contribution-by: Bernhard Bitsch =
<bbitsch@ipfire.org>
>>>>>>>>>>>>>>>>>>>>>>>> Contribution-by: Erik Kapfer =
<erik.kapfer@ipfire.org>
>>>>>>>>>>>>>>>>>>>>>>>> Signed-off-by: Jon Murphy =
<jon.murphy@ipfire.org
>>>>>>>>>>>>>>>>>>>>>>>> ---
>>>>>>>>>>>>>>>>>>>>>>>> config/backup/includes/rpz | 4 +
>>>>>>>>>>>>>>>>>>>>>>>> config/cfgroot/manualpages | 1 +
>>>>>>>>>>>>>>>>>>>>>>>> config/menu/EX-rpz.menu | 6 +
>>>>>>>>>>>>>>>>>>>>>>>> config/rootfiles/common/configroot | 1 +
>>>>>>>>>>>>>>>>>>>>>>>> config/rootfiles/common/web-user-interface | 1 =
+
>>>>>>>>>>>>>>>>>>>>>>>> config/rootfiles/packages/rpz | 20 +
>>>>>>>>>>>>>>>>>>>>>>>> config/rpz/00-rpz.conf | 10 +
>>>>>>>>>>>>>>>>>>>>>>>> config/rpz/rpz-config | 130 +++
>>>>>>>>>>>>>>>>>>>>>>>> config/rpz/rpz-functions | 85 ++
>>>>>>>>>>>>>>>>>>>>>>>> config/rpz/rpz-make | 203 +++++
>>>>>>>>>>>>>>>>>>>>>>>> config/rpz/rpz-metrics | 170 ++++
>>>>>>>>>>>>>>>>>>>>>>>> config/rpz/rpz-sleep | 58 ++
>>>>>>>>>>>>>>>>>>>>>>>> config/rpz/rpz.de.pl | 30 +
>>>>>>>>>>>>>>>>>>>>>>>> config/rpz/rpz.en.pl | 30 +
>>>>>>>>>>>>>>>>>>>>>>>> config/rpz/rpz.es.pl | 30 +
>>>>>>>>>>>>>>>>>>>>>>>> config/rpz/rpz.fr.pl | 30 +
>>>>>>>>>>>>>>>>>>>>>>>> config/rpz/rpz.it.pl | 30 +
>>>>>>>>>>>>>>>>>>>>>>>> config/rpz/rpz.tr.pl | 30 +
>>>>>>>>>>>>>>>>>>>>>>>> html/cgi-bin/rpz.cgi | 923 =
+++++++++++++++++++++
>>>>>>>>>>>>>>>>>>>>>>>> lfs/rpz | 96 +++
>>>>>>>>>>>>>>>>>>>>>>>> make.sh | 3 +-
>>>>>>>>>>>>>>>>>>>>>>>> src/paks/rpz/install.sh | 36 +
>>>>>>>>>>>>>>>>>>>>>>>> src/paks/rpz/uninstall.sh | 38 +
>>>>>>>>>>>>>>>>>>>>>>>> src/paks/rpz/update.sh | 52 ++
>>>>>>>>>>>>>>>>>>>>>>>> 24 files changed, 2016 insertions(+), 1 =
deletion(-)
>>>>>>>>>>>>>>>>>>>>>>>> create mode 100644 config/backup/includes/rpz
>>>>>>>>>>>>>>>>>>>>>>>> create mode 100644 config/menu/EX-rpz.menu
>>>>>>>>>>>>>>>>>>>>>>>> create mode 100644 =
config/rootfiles/packages/rpz
>>>>>>>>>>>>>>>>>>>>>>>> create mode 100644 config/rpz/00-rpz.conf
>>>>>>>>>>>>>>>>>>>>>>>> create mode 100644 config/rpz/rpz-config
>>>>>>>>>>>>>>>>>>>>>>>> create mode 100644 config/rpz/rpz-functions
>>>>>>>>>>>>>>>>>>>>>>>> create mode 100644 config/rpz/rpz-make
>>>>>>>>>>>>>>>>>>>>>>>> create mode 100755 config/rpz/rpz-metrics
>>>>>>>>>>>>>>>>>>>>>>>> create mode 100755 config/rpz/rpz-sleep
>>>>>>>>>>>>>>>>>>>>>>>> create mode 100644 config/rpz/rpz.de.pl
>>>>>>>>>>>>>>>>>>>>>>>> create mode 100644 config/rpz/rpz.en.pl
>>>>>>>>>>>>>>>>>>>>>>>> create mode 100644 config/rpz/rpz.es.pl
>>>>>>>>>>>>>>>>>>>>>>>> create mode 100644 config/rpz/rpz.fr.pl
>>>>>>>>>>>>>>>>>>>>>>>> create mode 100644 config/rpz/rpz.it.pl
>>>>>>>>>>>>>>>>>>>>>>>> create mode 100644 config/rpz/rpz.tr.pl
>>>>>>>>>>>>>>>>>>>>>>>> create mode 100644 html/cgi-bin/rpz.cgi
>>>>>>>>>>>>>>>>>>>>>>>> create mode 100644 lfs/rpz
>>>>>>>>>>>>>>>>>>>>>>>> create mode 100644 src/paks/rpz/install.sh
>>>>>>>>>>>>>>>>>>>>>>>> create mode 100644 src/paks/rpz/uninstall.sh
>>>>>>>>>>>>>>>>>>>>>>>> create mode 100644 src/paks/rpz/update.sh
>>>>>>>>>>>>>>>>>>>>>>>> diff --git a/config/backup/includes/rpz =
b/config/backup/includes/rpz
>>>>>>>>>>>>>>>>>>>>>>>> new file mode 100644
>>>>>>>>>>>>>>>>>>>>>>>> index 000000000..36513e494
>>>>>>>>>>>>>>>>>>>>>>>> --- /dev/null
>>>>>>>>>>>>>>>>>>>>>>>> +++ b/config/backup/includes/rpz
>>>>>>>>>>>>>>>>>>>>>>>> @@ -0,0 +1,4 @@
>>>>>>>>>>>>>>>>>>>>>>>> +/var/ipfire/dns/rpz/*
>>>>>>>>>>>>>>>>>>>>>>>> +/etc/unbound/zonefiles/allow.rpz
>>>>>>>>>>>>>>>>>>>>>>>> +/etc/unbound/zonefiles/block.rpz
>>>>>>>>>>>>>>>>>>>>>>>> +/etc/unbound/local.d/*rpz.conf
>>>>>>>>>>>>>>>>>>>>>>>> diff --git a/config/cfgroot/manualpages =
b/config/cfgroot/manualpages
>>>>>>>>>>>>>>>>>>>>>>>> index 1f7e01efc..d3a48c633 100644
>>>>>>>>>>>>>>>>>>>>>>>> --- a/config/cfgroot/manualpages
>>>>>>>>>>>>>>>>>>>>>>>> +++ b/config/cfgroot/manualpages
>>>>>>>>>>>>>>>>>>>>>>>> @@ -70,6 +70,7 @@ =
pakfire.cgi=3Dconfiguration/ipfire/pakfire
>>>>>>>>>>>>>>>>>>>>>>>> wlanap.cgi=3Daddons/wireless
>>>>>>>>>>>>>>>>>>>>>>>> tor.cgi=3Daddons/tor
>>>>>>>>>>>>>>>>>>>>>>>> samba.cgi=3Daddons/samba
>>>>>>>>>>>>>>>>>>>>>>>> +rpz.cgi=3Daddons/rpz
>>>>>>>>>>>>>>>>>>>>>>>> # Logs menu
>>>>>>>>>>>>>>>>>>>>>>>> logs.cgi/summary.dat=3Dconfiguration/logs/summary=

>>>>>>>>>>>>>>>>>>>>>>>> diff --git a/config/menu/EX-rpz.menu =
b/config/menu/EX-rpz.menu
>>>>>>>>>>>>>>>>>>>>>>>> new file mode 100644
>>>>>>>>>>>>>>>>>>>>>>>> index 000000000..2f4daf410
>>>>>>>>>>>>>>>>>>>>>>>> --- /dev/null
>>>>>>>>>>>>>>>>>>>>>>>> +++ b/config/menu/EX-rpz.menu
>>>>>>>>>>>>>>>>>>>>>>>> @@ -0,0 +1,6 @@
>>>>>>>>>>>>>>>>>>>>>>>> +$subipfire->{'20.rpz'} =3D {
>>>>>>>>>>>>>>>>>>>>>>>> + 'caption' =3D> $Lang::tr{'rpz'},
>>>>>>>>>>>>>>>>>>>>>>>> + 'uri' =3D> '/cgi-bin/rpz.cgi',
>>>>>>>>>>>>>>>>>>>>>>>> + 'title' =3D> "RPZ",
>>>>>>>>>>>>>>>>>>>>>>>> + 'enabled' =3D> 1,
>>>>>>>>>>>>>>>>>>>>>>>> +};
>>>>>>>>>>>>>>>>>>>>>>>> diff --git a/config/rootfiles/common/configroot =
b/config/rootfiles/common/configroot
>>>>>>>>>>>>>>>>>>>>>>>> index 9839eee45..b30d6aae4 100644
>>>>>>>>>>>>>>>>>>>>>>>> --- a/config/rootfiles/common/configroot
>>>>>>>>>>>>>>>>>>>>>>>> +++ b/config/rootfiles/common/configroot
>>>>>>>>>>>>>>>>>>>>>>>> @@ -120,6 +120,7 @@ =
var/ipfire/menu.d/70-log.menu
>>>>>>>>>>>>>>>>>>>>>>>> #var/ipfire/menu.d/EX-apcupsd.menu
>>>>>>>>>>>>>>>>>>>>>>>> #var/ipfire/menu.d/EX-guardian.menu
>>>>>>>>>>>>>>>>>>>>>>>> #var/ipfire/menu.d/EX-mympd.menu
>>>>>>>>>>>>>>>>>>>>>>>> +#var/ipfire/menu.d/EX-rpz.menu
>>>>>>>>>>>>>>>>>>>>>>>> #var/ipfire/menu.d/EX-samba.menu
>>>>>>>>>>>>>>>>>>>>>>>> #var/ipfire/menu.d/EX-tor.menu
>>>>>>>>>>>>>>>>>>>>>>>> #var/ipfire/menu.d/EX-transmission.menu
>>>>>>>>>>>>>>>>>>>>>>>> diff --git =
a/config/rootfiles/common/web-user-interface =
b/config/rootfiles/common/web-user-interface
>>>>>>>>>>>>>>>>>>>>>>>> index 816241dae..e00464076 100644
>>>>>>>>>>>>>>>>>>>>>>>> --- =
a/config/rootfiles/common/web-user-interface
>>>>>>>>>>>>>>>>>>>>>>>> +++ =
b/config/rootfiles/common/web-user-interface
>>>>>>>>>>>>>>>>>>>>>>>> @@ -69,6 +69,7 @@ =
srv/web/ipfire/cgi-bin/proxy.cgi
>>>>>>>>>>>>>>>>>>>>>>>> srv/web/ipfire/cgi-bin/qos.cgi
>>>>>>>>>>>>>>>>>>>>>>>> srv/web/ipfire/cgi-bin/remote.cgi
>>>>>>>>>>>>>>>>>>>>>>>> srv/web/ipfire/cgi-bin/routing.cgi
>>>>>>>>>>>>>>>>>>>>>>>> +#srv/web/ipfire/cgi-bin/rpz.cgi
>>>>>>>>>>>>>>>>>>>>>>>> #srv/web/ipfire/cgi-bin/samba.cgi
>>>>>>>>>>>>>>>>>>>>>>>> srv/web/ipfire/cgi-bin/services.cgi
>>>>>>>>>>>>>>>>>>>>>>>> srv/web/ipfire/cgi-bin/shutdown.cgi
>>>>>>>>>>>>>>>>>>>>>>>> diff --git a/config/rootfiles/packages/rpz =
b/config/rootfiles/packages/rpz
>>>>>>>>>>>>>>>>>>>>>>>> new file mode 100644
>>>>>>>>>>>>>>>>>>>>>>>> index 000000000..1c8663049
>>>>>>>>>>>>>>>>>>>>>>>> --- /dev/null
>>>>>>>>>>>>>>>>>>>>>>>> +++ b/config/rootfiles/packages/rpz
>>>>>>>>>>>>>>>>>>>>>>>> @@ -0,0 +1,20 @@
>>>>>>>>>>>>>>>>>>>>>>>> +etc/unbound/local.d/00-rpz.conf
>>>>>>>>>>>>>>>>>>>>>>>> +etc/unbound/zonefiles
>>>>>>>>>>>>>>>>>>>>>>>> +etc/unbound/zonefiles/allow.rpz
>>>>>>>>>>>>>>>>>>>>>>>> +usr/sbin/rpz-config
>>>>>>>>>>>>>>>>>>>>>>>> +usr/sbin/rpz-functions
>>>>>>>>>>>>>>>>>>>>>>>> +usr/sbin/rpz-make
>>>>>>>>>>>>>>>>>>>>>>>> +usr/sbin/rpz-metrics
>>>>>>>>>>>>>>>>>>>>>>>> +usr/sbin/rpz-sleep
>>>>>>>>>>>>>>>>>>>>>>>> +var/ipfire/addon-lang/rpz.de.pl
>>>>>>>>>>>>>>>>>>>>>>>> +var/ipfire/addon-lang/rpz.en.pl
>>>>>>>>>>>>>>>>>>>>>>>> +var/ipfire/addon-lang/rpz.es.pl
>>>>>>>>>>>>>>>>>>>>>>>> +var/ipfire/addon-lang/rpz.fr.pl
>>>>>>>>>>>>>>>>>>>>>>>> +var/ipfire/addon-lang/rpz.it.pl
>>>>>>>>>>>>>>>>>>>>>>>> +var/ipfire/addon-lang/rpz.tr.pl
>>>>>>>>>>>>>>>>>>>>>>>> +var/ipfire/backup/addons/includes/rpz
>>>>>>>>>>>>>>>>>>>>>>>> +var/ipfire/dns/rpz
>>>>>>>>>>>>>>>>>>>>>>>> +var/ipfire/dns/rpz/allowlist
>>>>>>>>>>>>>>>>>>>>>>>> +var/ipfire/dns/rpz/blocklist
>>>>>>>>>>>>>>>>>>>>>>>> +var/ipfire/menu.d/EX-rpz.menu
>>>>>>>>>>>>>>>>>>>>>>>> +srv/web/ipfire/cgi-bin/rpz.cgi
>>>>>>>>>>>>>>>>>>>>>>>> diff --git a/config/rpz/00-rpz.conf =
b/config/rpz/00-rpz.conf
>>>>>>>>>>>>>>>>>>>>>>>> new file mode 100644
>>>>>>>>>>>>>>>>>>>>>>>> index 000000000..f005a4f2e
>>>>>>>>>>>>>>>>>>>>>>>> --- /dev/null
>>>>>>>>>>>>>>>>>>>>>>>> +++ b/config/rpz/00-rpz.conf
>>>>>>>>>>>>>>>>>>>>>>>> @@ -0,0 +1,10 @@
>>>>>>>>>>>>>>>>>>>>>>>> +server:
>>>>>>>>>>>>>>>>>>>>>>>> + module-config: "respip validator iterator"
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +rpz:
>>>>>>>>>>>>>>>>>>>>>>>> + name: allow.rpz
>>>>>>>>>>>>>>>>>>>>>>>> + zonefile: /etc/unbound/zonefiles/allow.rpz
>>>>>>>>>>>>>>>>>>>>>>>> + rpz-action-override: passthru
>>>>>>>>>>>>>>>>>>>>>>>> + rpz-log: yes
>>>>>>>>>>>>>>>>>>>>>>>> + rpz-log-name: allow
>>>>>>>>>>>>>>>>>>>>>>>> + rpz-signal-nxdomain-ra: yes
>>>>>>>>>>>>>>>>>>>>>>>> diff --git a/config/rpz/rpz-config =
b/config/rpz/rpz-config
>>>>>>>>>>>>>>>>>>>>>>>> new file mode 100644
>>>>>>>>>>>>>>>>>>>>>>>> index 000000000..c72d50f9b
>>>>>>>>>>>>>>>>>>>>>>>> --- /dev/null
>>>>>>>>>>>>>>>>>>>>>>>> +++ b/config/rpz/rpz-config
>>>>>>>>>>>>>>>>>>>>>>>> @@ -0,0 +1,130 @@
>>>>>>>>>>>>>>>>>>>>>>>> +#!/bin/bash
>>>>>>>>>>>>>>>>>>>>>>>> =
+#########################################################################=
######
>>>>>>>>>>>>>>>>>>>>>>>> +# #
>>>>>>>>>>>>>>>>>>>>>>>> +# IPFire.org - A linux based firewall #
>>>>>>>>>>>>>>>>>>>>>>>> +# Copyright (C) 2024-2025 IPFire Team =
<info@ipfire.org> #
>>>>>>>>>>>>>>>>>>>>>>>> +# #
>>>>>>>>>>>>>>>>>>>>>>>> +# 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 =
<http://www.gnu.org/licenses/>. #
>>>>>>>>>>>>>>>>>>>>>>>> +# #
>>>>>>>>>>>>>>>>>>>>>>>> =
+#########################################################################=
######
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +version=3D"2025-01-11 - v44"
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +############### Functions ###############
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +source /usr/sbin/rpz-functions
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +############### Main ###############
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +tagName=3D"unbound"
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +rpzAction=3D"${1}" # input RPZ action
>>>>>>>>>>>>>>>>>>>>>>>> +rpzName=3D"${2}" # input RPZ name
>>>>>>>>>>>>>>>>>>>>>>>> +rpzURL=3D"${3}" # input RPZ URL
>>>>>>>>>>>>>>>>>>>>>>>> +rpzOption1=3D"${4}" # input RPZ option #1
>>>>>>>>>>>>>>>>>>>>>>>> +rpzOption2=3D"${5}" # input RPZ option #2
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> =
+rpzConfig=3D"/etc/unbound/local.d/${rpzName}.rpz.conf" # output zone =
conf file
>>>>>>>>>>>>>>>>>>>>>>>> =
+rpzFile=3D"/etc/unbound/zonefiles/${rpzName}.rpz" # output for RPZ file
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +rpzLog=3D"yes" # log default is yes
>>>>>>>>>>>>>>>>>>>>>>>> +ucReload=3D"yes" # reload default is yes
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +while [[ $# -gt 0 ]] ; do
>>>>>>>>>>>>>>>>>>>>>>>> + case "$1" in
>>>>>>>>>>>>>>>>>>>>>>>> + --no-log ) rpzLog=3D"no" ;;
>>>>>>>>>>>>>>>>>>>>>>>> + --no-reload ) ucReload=3D"no" ; =
checkConf=3D"no" ;;
>>>>>>>>>>>>>>>>>>>>>>>> + esac
>>>>>>>>>>>>>>>>>>>>>>>> + shift # Shift after checking all the cases to =
get next option
>>>>>>>>>>>>>>>>>>>>>>>> +done
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +case "${rpzAction}" in
>>>>>>>>>>>>>>>>>>>>>>>> + # add new rpz list
>>>>>>>>>>>>>>>>>>>>>>>> + add )
>>>>>>>>>>>>>>>>>>>>>>>> + check_name "${rpzName}" # is this a valid =
name?
>>>>>>>>>>>>>>>>>>>>>>>> + # does this config already exist? If yes, =
then exit
>>>>>>>>>>>>>>>>>>>>>>>> + if [[ -f "${rpzConfig}" ]] ; then
>>>>>>>>>>>>>>>>>>>>>>>> + msg_log "error: rpz: duplicate - ${rpzConfig} =
already exists. exit"
>>>>>>>>>>>>>>>>>>>>>>>> + exit 104
>>>>>>>>>>>>>>>>>>>>>>>> + fi
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> + # is this a valid URL?
>>>>>>>>>>>>>>>>>>>>>>>> + =
regex=3D'^https://[-[:alnum:]\+&@#/%?=3D~_|!:,.;]*[-[:alnum:]\+&@#/%=3D~_|=
]'
>>>>>>>>>>>>>>>>>>>>>>>> + if ! [[ "${rpzURL}" =3D~ $regex ]] ; then
>>>>>>>>>>>>>>>>>>>>>>>> + msg_log "error: rpz: the URL is not valid: =
\"${rpzURL}\". exit."
>>>>>>>>>>>>>>>>>>>>>>>> + exit 105
>>>>>>>>>>>>>>>>>>>>>>>> + fi
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> + # create the zone config file
>>>>>>>>>>>>>>>>>>>>>>>> + {
>>>>>>>>>>>>>>>>>>>>>>>> + echo "rpz:"
>>>>>>>>>>>>>>>>>>>>>>>> + echo " name: ${rpzName}.rpz"
>>>>>>>>>>>>>>>>>>>>>>>> + echo " zonefile: ${rpzFile}"
>>>>>>>>>>>>>>>>>>>>>>>> + echo " url: ${rpzURL}"
>>>>>>>>>>>>>>>>>>>>>>>> + echo " rpz-action-override: nxdomain"
>>>>>>>>>>>>>>>>>>>>>>>> + echo " rpz-log: ${rpzLog}"
>>>>>>>>>>>>>>>>>>>>>>>> + echo " rpz-log-name: ${rpzName}"
>>>>>>>>>>>>>>>>>>>>>>>> + echo " rpz-signal-nxdomain-ra: yes"
>>>>>>>>>>>>>>>>>>>>>>>> + } > "${rpzConfig}"
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> + # set-up zonefile
>>>>>>>>>>>>>>>>>>>>>>>> + # create an empty rpz file if it does not =
exist
>>>>>>>>>>>>>>>>>>>>>>>> + if [[ ! -f "${rpzFile}" ]] ; then
>>>>>>>>>>>>>>>>>>>>>>>> + touch "${rpzFile}"
>>>>>>>>>>>>>>>>>>>>>>>> + # unbound requires these settings for rpz =
files
>>>>>>>>>>>>>>>>>>>>>>>> + set_permissions "${rpzFile}" "${rpzConfig}"
>>>>>>>>>>>>>>>>>>>>>>>> + fi
>>>>>>>>>>>>>>>>>>>>>>>> + ;;
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> + # trash config file & rpz file
>>>>>>>>>>>>>>>>>>>>>>>> + remove )
>>>>>>>>>>>>>>>>>>>>>>>> + if ! [[ -f "${rpzConfig}" ]] ; then
>>>>>>>>>>>>>>>>>>>>>>>> + msg_log "error: rpz: cannot remove =
${rpzConfig}, does not exist. exit"
>>>>>>>>>>>>>>>>>>>>>>>> + exit 106
>>>>>>>>>>>>>>>>>>>>>>>> + fi
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> + msg_log "info: rpz: remove config file & rpz =
file \"${rpzName}\""
>>>>>>>>>>>>>>>>>>>>>>>> + rm "${rpzConfig}"
>>>>>>>>>>>>>>>>>>>>>>>> + rm "${rpzFile}"
>>>>>>>>>>>>>>>>>>>>>>>> + ;;
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> + reload )
>>>>>>>>>>>>>>>>>>>>>>>> + check_unbound_conf "${checkConf}"
>>>>>>>>>>>>>>>>>>>>>>>> + ;;
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> + list )
>>>>>>>>>>>>>>>>>>>>>>>> + awk -F':' '/^\s*name:/{ =
gsub(/[[:blank:]]|\.rpz/, "",$2) ; NAME=3D$2 } \
>>>>>>>>>>>>>>>>>>>>>>>> + /^\s*url:/{ gsub(/[[:blank:]]/, "") ; print =
NAME"=3D"$2":"$3} ' \
>>>>>>>>>>>>>>>>>>>>>>>> + /etc/unbound/local.d/*rpz.conf
>>>>>>>>>>>>>>>>>>>>>>>> + exit
>>>>>>>>>>>>>>>>>>>>>>>> + ;;
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> + unbound-restart )
>>>>>>>>>>>>>>>>>>>>>>>> + check_unbound_conf "${checkConf}"
>>>>>>>>>>>>>>>>>>>>>>>> + unbound_restart
>>>>>>>>>>>>>>>>>>>>>>>> + exit
>>>>>>>>>>>>>>>>>>>>>>>> + ;;
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> + * )
>>>>>>>>>>>>>>>>>>>>>>>> + msg_log "error: rpz: missing or incorrect =
parameter"
>>>>>>>>>>>>>>>>>>>>>>>> + printf "Usage: $(basename "$0") <ACTION> =
<NAME> <URL> <OPTION> <OPTION>\n"
>>>>>>>>>>>>>>>>>>>>>>>> + printf "Version: ${version}\n"
>>>>>>>>>>>>>>>>>>>>>>>> + exit 108
>>>>>>>>>>>>>>>>>>>>>>>> + ;;
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +esac
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +unbound_control_reload "${ucReload}"
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +exit
>>>>>>>>>>>>>>>>>>>>>>>> diff --git a/config/rpz/rpz-functions =
b/config/rpz/rpz-functions
>>>>>>>>>>>>>>>>>>>>>>>> new file mode 100644
>>>>>>>>>>>>>>>>>>>>>>>> index 000000000..ace1d2690
>>>>>>>>>>>>>>>>>>>>>>>> --- /dev/null
>>>>>>>>>>>>>>>>>>>>>>>> +++ b/config/rpz/rpz-functions
>>>>>>>>>>>>>>>>>>>>>>>> @@ -0,0 +1,85 @@
>>>>>>>>>>>>>>>>>>>>>>>> +#!/bin/bash
>>>>>>>>>>>>>>>>>>>>>>>> =
+#########################################################################=
######
>>>>>>>>>>>>>>>>>>>>>>>> +# #
>>>>>>>>>>>>>>>>>>>>>>>> +# IPFire.org - A linux based firewall #
>>>>>>>>>>>>>>>>>>>>>>>> +# Copyright (C) 2024 IPFire Team =
<info@ipfire.org> #
>>>>>>>>>>>>>>>>>>>>>>>> +# #
>>>>>>>>>>>>>>>>>>>>>>>> +# 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 =
<http://www.gnu.org/licenses/>. #
>>>>>>>>>>>>>>>>>>>>>>>> +# #
>>>>>>>>>>>>>>>>>>>>>>>> =
+#########################################################################=
######
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +version=3D"2024-12-10 - v02"
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +############### Functions ###############
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +msg_log () {
>>>>>>>>>>>>>>>>>>>>>>>> + logger --tag "${tagName}" "$*"
>>>>>>>>>>>>>>>>>>>>>>>> + if tty --silent ; then
>>>>>>>>>>>>>>>>>>>>>>>> + echo "${tagName}:" "$*"
>>>>>>>>>>>>>>>>>>>>>>>> + fi
>>>>>>>>>>>>>>>>>>>>>>>> +}
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +# check for a valid name
>>>>>>>>>>>>>>>>>>>>>>>> +check_name () {
>>>>>>>>>>>>>>>>>>>>>>>> + local theName=3D"${1}"
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> + regex=3D'^[a-zA-Z0-9_]+$' # no dash or plus, =
alpha numeric only
>>>>>>>>>>>>>>>>>>>>>>>> + regex1=3D'^(allow|block)$' # allow and block =
are reserved NAMEs
>>>>>>>>>>>>>>>>>>>>>>>> + if [[ ! "${theName}" =3D~ $regex ]] || [[ =
"${theName}" =3D~ $regex1 ]] ; then
>>>>>>>>>>>>>>>>>>>>>>>> + msg_log "error: rpz: the NAME is not valid: =
\"${theName}\". exit."
>>>>>>>>>>>>>>>>>>>>>>>> + exit 101
>>>>>>>>>>>>>>>>>>>>>>>> + fi
>>>>>>>>>>>>>>>>>>>>>>>> +}
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +set_permissions () {
>>>>>>>>>>>>>>>>>>>>>>>> + chown nobody:nobody "$@"
>>>>>>>>>>>>>>>>>>>>>>>> + chmod 644 "$@"
>>>>>>>>>>>>>>>>>>>>>>>> +}
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +check_unbound_conf () {
>>>>>>>>>>>>>>>>>>>>>>>> + local thecheckConf=3D"${1:-yes}" # check =
config default is yes
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> + # check the above config files
>>>>>>>>>>>>>>>>>>>>>>>> + if [[ "${thecheckConf}" =3D=3D yes ]] ; then
>>>>>>>>>>>>>>>>>>>>>>>> + msg_log "info: rpz: check for errors with =
\"unbound-checkconf\""
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> + if ! unbound-checkconf ; then
>>>>>>>>>>>>>>>>>>>>>>>> + msg_log "error: rpz: unbound-checkconf found =
invalid configuration."
>>>>>>>>>>>>>>>>>>>>>>>> + msg_log \
>>>>>>>>>>>>>>>>>>>>>>>> + "error: rpz: In Terminal run the command =
\"unbound-checkconf\" for more information. exit."
>>>>>>>>>>>>>>>>>>>>>>>> + exit 102
>>>>>>>>>>>>>>>>>>>>>>>> + fi
>>>>>>>>>>>>>>>>>>>>>>>> + fi
>>>>>>>>>>>>>>>>>>>>>>>> +}
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +unbound_control_reload () {
>>>>>>>>>>>>>>>>>>>>>>>> + local theReload=3D"${1:-yes}" # reload =
default is yes
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> + if [[ "${theReload}" =3D=3D yes ]] ; then
>>>>>>>>>>>>>>>>>>>>>>>> + # reload due to the changes
>>>>>>>>>>>>>>>>>>>>>>>> + msg_log "info: rpz: run \"unbound-control =
reload\""
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> + if ! unbound-control reload ; then
>>>>>>>>>>>>>>>>>>>>>>>> + msg_log "error: rpz: unbound-control reload. =
exit."
>>>>>>>>>>>>>>>>>>>>>>>> + exit 109
>>>>>>>>>>>>>>>>>>>>>>>> + fi
>>>>>>>>>>>>>>>>>>>>>>>> + fi
>>>>>>>>>>>>>>>>>>>>>>>> +}
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +unbound_restart () {
>>>>>>>>>>>>>>>>>>>>>>>> + # restart due to the changes
>>>>>>>>>>>>>>>>>>>>>>>> + msg_log "info: rpz: run \"unbound restart\""
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> + /usr/local/bin/unboundctrl restart
>>>>>>>>>>>>>>>>>>>>>>>> +}
>>>>>>>>>>>>>>>>>>>>>>>> diff --git a/config/rpz/rpz-make =
b/config/rpz/rpz-make
>>>>>>>>>>>>>>>>>>>>>>>> new file mode 100644
>>>>>>>>>>>>>>>>>>>>>>>> index 000000000..927d55170
>>>>>>>>>>>>>>>>>>>>>>>> --- /dev/null
>>>>>>>>>>>>>>>>>>>>>>>> +++ b/config/rpz/rpz-make
>>>>>>>>>>>>>>>>>>>>>>>> @@ -0,0 +1,203 @@
>>>>>>>>>>>>>>>>>>>>>>>> +#!/bin/bash
>>>>>>>>>>>>>>>>>>>>>>>> =
+#########################################################################=
######
>>>>>>>>>>>>>>>>>>>>>>>> +# #
>>>>>>>>>>>>>>>>>>>>>>>> +# IPFire.org - A linux based firewall #
>>>>>>>>>>>>>>>>>>>>>>>> +# Copyright (C) 2024-2025 IPFire Team =
<info@ipfire.org> #
>>>>>>>>>>>>>>>>>>>>>>>> +# #
>>>>>>>>>>>>>>>>>>>>>>>> +# 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 =
<http://www.gnu.org/licenses/>. #
>>>>>>>>>>>>>>>>>>>>>>>> +# #
>>>>>>>>>>>>>>>>>>>>>>>> =
+#########################################################################=
######
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +version=3D"2025-01-11 - v14"
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +############### Functions ###############
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +source /usr/sbin/rpz-functions
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +# create the config file for allow
>>>>>>>>>>>>>>>>>>>>>>>> +make_allow_config () {
>>>>>>>>>>>>>>>>>>>>>>>> + local theLog=3D"${1:-yes}" # log default ON
>>>>>>>>>>>>>>>>>>>>>>>> + local =
theConfig=3D"/etc/unbound/local.d/00-rpz.conf" # output zone conf file
>>>>>>>>>>>>>>>>>>>>>>>> + local theList=3D"/var/ipfire/dns/rpz/allowlist"=
 # input custom list of domains
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> + msg_log "info: rpz: make config file =
\"00-rpz.conf\""
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> + echo "server:
>>>>>>>>>>>>>>>>>>>>>>>> + module-config: \"respip validator iterator\"" =
> "${theConfig}"
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> + # does allow list exist?
>>>>>>>>>>>>>>>>>>>>>>>> + if [[ -s "${theList}" ]] && grep -q . =
"${theList}" ; then
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> + echo "rpz:
>>>>>>>>>>>>>>>>>>>>>>>> + name: allow.rpz
>>>>>>>>>>>>>>>>>>>>>>>> + zonefile: /etc/unbound/zonefiles/allow.rpz
>>>>>>>>>>>>>>>>>>>>>>>> + rpz-action-override: passthru
>>>>>>>>>>>>>>>>>>>>>>>> + rpz-log: ${theLog}
>>>>>>>>>>>>>>>>>>>>>>>> + rpz-log-name: allow
>>>>>>>>>>>>>>>>>>>>>>>> + rpz-signal-nxdomain-ra: yes" >> =
"${theConfig}"
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> + fi
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> + # set-up zonefile - unbound requires these =
settings for rpz files
>>>>>>>>>>>>>>>>>>>>>>>> + set_permissions "${theConfig}"
>>>>>>>>>>>>>>>>>>>>>>>> +}
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +# create the config file for block
>>>>>>>>>>>>>>>>>>>>>>>> +make_block_config () {
>>>>>>>>>>>>>>>>>>>>>>>> + local theLog=3D"${1:-yes}" # log default ON
>>>>>>>>>>>>>>>>>>>>>>>> + local =
theConfig=3D"/etc/unbound/local.d/block.rpz.conf" # output zone conf =
file
>>>>>>>>>>>>>>>>>>>>>>>> + local theList=3D"/var/ipfire/dns/rpz/blocklist"=
 # input custom list of domains
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> + msg_log "info: rpz: make config file =
\"block.rpz.conf\""
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> + # does block list exist?
>>>>>>>>>>>>>>>>>>>>>>>> + if [[ -s "${theList}" ]] && grep -q . =
"${theList}" ; then
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> + echo "rpz:
>>>>>>>>>>>>>>>>>>>>>>>> + name: block.rpz
>>>>>>>>>>>>>>>>>>>>>>>> + zonefile: /etc/unbound/zonefiles/block.rpz
>>>>>>>>>>>>>>>>>>>>>>>> + rpz-action-override: nxdomain
>>>>>>>>>>>>>>>>>>>>>>>> + rpz-log: ${theLog}
>>>>>>>>>>>>>>>>>>>>>>>> + rpz-log-name: block
>>>>>>>>>>>>>>>>>>>>>>>> + rpz-signal-nxdomain-ra: yes" > "${theConfig}"
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> + # set-up zonefile - unbound requires these =
settings for rpz files
>>>>>>>>>>>>>>>>>>>>>>>> + set_permissions "${theConfig}"
>>>>>>>>>>>>>>>>>>>>>>>> + else
>>>>>>>>>>>>>>>>>>>>>>>> + # no - trash the config file
>>>>>>>>>>>>>>>>>>>>>>>> + rm --verbose =
/etc/unbound/local.d/block.rpz.conf
>>>>>>>>>>>>>>>>>>>>>>>> + fi
>>>>>>>>>>>>>>>>>>>>>>>> +}
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +# create an RPZ file for allow or block
>>>>>>>>>>>>>>>>>>>>>>>> +make_rpz_file () {
>>>>>>>>>>>>>>>>>>>>>>>> + local theName=3D"${1}" # allow or block
>>>>>>>>>>>>>>>>>>>>>>>> + local theAction=3D'.' # the default is =
nxdomain or block
>>>>>>>>>>>>>>>>>>>>>>>> + local actionList
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> + local =
theList=3D"/var/ipfire/dns/rpz/${theName}list" # input custom list of =
domains
>>>>>>>>>>>>>>>>>>>>>>>> + local =
theZonefile=3D"/etc/unbound/zonefiles/${theName}.rpz" # output file for =
RPZ
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> + # does a list exist?
>>>>>>>>>>>>>>>>>>>>>>>> + if [[ -s "${theList}" ]] && grep -q . =
"${theList}" ; then
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> + # for allow set to passthru
>>>>>>>>>>>>>>>>>>>>>>>> + [[ "${theName}" =3D=3D allow ]] && =
theAction=3D'rpz-passthru.'
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> + # drop any extra "blanks" and add "CNAME <RPZ =
action>." to each line
>>>>>>>>>>>>>>>>>>>>>>>> + actionList=3D$( awk '{$1=3D$1};1' =
"${theList}" |
>>>>>>>>>>>>>>>>>>>>>>>> + sed "/^[^;].*[[:alnum:]]/ s|$| CNAME =
${theAction}|" )
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> + msg_log "info: rpz: create zonefile for =
\"${theName}list\""
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +echo "; Name: ${theName} list
>>>>>>>>>>>>>>>>>>>>>>>> +; Last modified: $(date "+%Y-%m-%d at %H.%M.%S =
%Z")
>>>>>>>>>>>>>>>>>>>>>>>> +;
>>>>>>>>>>>>>>>>>>>>>>>> +; domains with actions list
>>>>>>>>>>>>>>>>>>>>>>>> +;
>>>>>>>>>>>>>>>>>>>>>>>> +${actionList}" > "${theZonefile}"
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> + # set-up zonefile - unbound requires these =
settings for rpz files
>>>>>>>>>>>>>>>>>>>>>>>> + set_permissions "${theZonefile}"
>>>>>>>>>>>>>>>>>>>>>>>> + # set-up allow/block list files
>>>>>>>>>>>>>>>>>>>>>>>> + set_permissions "${theList}"
>>>>>>>>>>>>>>>>>>>>>>>> + else
>>>>>>>>>>>>>>>>>>>>>>>> + msg_log "info: rpz: the ${theList} is empty."
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> + rm --verbose "${theZonefile}" # trash the RPZ =
file
>>>>>>>>>>>>>>>>>>>>>>>> + fi
>>>>>>>>>>>>>>>>>>>>>>>> +}
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +# check if allow/block list is valid
>>>>>>>>>>>>>>>>>>>>>>>> +validate_list () {
>>>>>>>>>>>>>>>>>>>>>>>> + local theName=3D"${1}" # allow or block
>>>>>>>>>>>>>>>>>>>>>>>> + local =
theList=3D"/var/ipfire/dns/rpz/${theName}list" # input custom list of =
domains
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> + # remove good:
>>>>>>>>>>>>>>>>>>>>>>>> + # - properly formated domain names with or =
without leading wildcard
>>>>>>>>>>>>>>>>>>>>>>>> + # - properly formated top level domain (TLD) =
names with wildcard
>>>>>>>>>>>>>>>>>>>>>>>> + # - blank lines and comment lines
>>>>>>>>>>>>>>>>>>>>>>>> + # remaining lines are considered "bad"
>>>>>>>>>>>>>>>>>>>>>>>> + bad_lines=3D$( sed --regexp-extended \
>>>>>>>>>>>>>>>>>>>>>>>> + =
'/^(\*\.)?([a-zA-Z0-9](([a-zA-Z0-9\-]){0,61}[a-zA-Z0-9])?\.)+([a-zA-Z]{2,}=
|xn--[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])$/d ;
>>>>>>>>>>>>>>>>>>>>>>>> + /^(\*\.)([a-z]{2,61}|xn--[a-z0-9]{1,60})$/d ;
>>>>>>>>>>>>>>>>>>>>>>>> + /^$/d ; /^;/d' "${theList}" )
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> + if [[ ! -z "${bad_lines}" ]] ; then
>>>>>>>>>>>>>>>>>>>>>>>> + msg_log "error: rpz: invalid line(s) in =
${theList}."
>>>>>>>>>>>>>>>>>>>>>>>> + printf "%s\n" "bad line(s): ${bad_lines}"
>>>>>>>>>>>>>>>>>>>>>>>> + exit 110
>>>>>>>>>>>>>>>>>>>>>>>> + fi
>>>>>>>>>>>>>>>>>>>>>>>> +}
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +############### Main ###############
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +tagName=3D"unbound"
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +rpzName=3D"${1}" # input RPZ name
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +rpzLog=3D"yes" # log default is yes
>>>>>>>>>>>>>>>>>>>>>>>> +ucReload=3D"yes" # reload default is yes
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +while [[ $# -gt 0 ]] ; do
>>>>>>>>>>>>>>>>>>>>>>>> + case "$1" in
>>>>>>>>>>>>>>>>>>>>>>>> + --no-log ) rpzLog=3D"no" ;;
>>>>>>>>>>>>>>>>>>>>>>>> + --no-reload ) ucReload=3D"no" ; =
checkConf=3D"no" ;;
>>>>>>>>>>>>>>>>>>>>>>>> + esac
>>>>>>>>>>>>>>>>>>>>>>>> + shift # Shift after checking all the cases to =
get next option
>>>>>>>>>>>>>>>>>>>>>>>> +done
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +case "${rpzName}" in
>>>>>>>>>>>>>>>>>>>>>>>> + # make a new allow or block rpz file
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> + allow )
>>>>>>>>>>>>>>>>>>>>>>>> + validate_list 'allow' # is the allowlist =
valid?
>>>>>>>>>>>>>>>>>>>>>>>> + make_allow_config "${rpzLog}"
>>>>>>>>>>>>>>>>>>>>>>>> + make_rpz_file 'allow'
>>>>>>>>>>>>>>>>>>>>>>>> + ;;
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> + allowblock )
>>>>>>>>>>>>>>>>>>>>>>>> + validate_list 'allow' # is the list valid?
>>>>>>>>>>>>>>>>>>>>>>>> + make_allow_config "${rpzLog}"
>>>>>>>>>>>>>>>>>>>>>>>> + make_rpz_file 'allow'
>>>>>>>>>>>>>>>>>>>>>>>> + ;&
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> + block )
>>>>>>>>>>>>>>>>>>>>>>>> + validate_list 'block' # is the blocklist =
valid?
>>>>>>>>>>>>>>>>>>>>>>>> + make_block_config "${rpzLog}"
>>>>>>>>>>>>>>>>>>>>>>>> + make_rpz_file 'block'
>>>>>>>>>>>>>>>>>>>>>>>> + ;;
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> + reload )
>>>>>>>>>>>>>>>>>>>>>>>> + check_unbound_conf "${checkConf}"
>>>>>>>>>>>>>>>>>>>>>>>> + ;;
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> + unbound-restart )
>>>>>>>>>>>>>>>>>>>>>>>> + check_unbound_conf "${checkConf}"
>>>>>>>>>>>>>>>>>>>>>>>> + unbound_restart
>>>>>>>>>>>>>>>>>>>>>>>> + exit
>>>>>>>>>>>>>>>>>>>>>>>> + ;;
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> + * )
>>>>>>>>>>>>>>>>>>>>>>>> + msg_log "error: rpz: missing or incorrect =
parameter"
>>>>>>>>>>>>>>>>>>>>>>>> + printf "Usage: $(basename "$0") <NAME> =
<OPTION> <OPTION>\n"
>>>>>>>>>>>>>>>>>>>>>>>> + printf "Version: ${version}\n"
>>>>>>>>>>>>>>>>>>>>>>>> + exit 108
>>>>>>>>>>>>>>>>>>>>>>>> + ;;
>>>>>>>>>>>>>>>>>>>>>>>> +esac
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +unbound_control_reload "${ucReload}"
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +exit
>>>>>>>>>>>>>>>>>>>>>>>> diff --git a/config/rpz/rpz-metrics =
b/config/rpz/rpz-metrics
>>>>>>>>>>>>>>>>>>>>>>>> new file mode 100755
>>>>>>>>>>>>>>>>>>>>>>>> index 000000000..4d43e1629
>>>>>>>>>>>>>>>>>>>>>>>> --- /dev/null
>>>>>>>>>>>>>>>>>>>>>>>> +++ b/config/rpz/rpz-metrics
>>>>>>>>>>>>>>>>>>>>>>>> @@ -0,0 +1,170 @@
>>>>>>>>>>>>>>>>>>>>>>>> +#!/bin/bash
>>>>>>>>>>>>>>>>>>>>>>>> =
+#########################################################################=
######
>>>>>>>>>>>>>>>>>>>>>>>> +# #
>>>>>>>>>>>>>>>>>>>>>>>> +# IPFire.org - A linux based firewall #
>>>>>>>>>>>>>>>>>>>>>>>> +# Copyright (C) 2024 IPFire Team =
<info@ipfire.org> #
>>>>>>>>>>>>>>>>>>>>>>>> +# #
>>>>>>>>>>>>>>>>>>>>>>>> +# 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 =
<http://www.gnu.org/licenses/>. #
>>>>>>>>>>>>>>>>>>>>>>>> +# #
>>>>>>>>>>>>>>>>>>>>>>>> =
+#########################################################################=
######
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +version=3D"2025-01-20 - v25"
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +############### Main ###############
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +weeks=3D"2" # default to two message logs
>>>>>>>>>>>>>>>>>>>>>>>> +sortBy=3D"name" # default "by name"
>>>>>>>>>>>>>>>>>>>>>>>> +rpzActive=3D"enabled" # default "enabled only"
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +while [[ $# -gt 0 ]] ; do
>>>>>>>>>>>>>>>>>>>>>>>> + case "$1" in
>>>>>>>>>>>>>>>>>>>>>>>> + --by-names | --by-name | name ) sortBy=3D"name"=
 ;;
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> + --by-hits | --by-hit | hits | hit ) =
sortBy=3D"hit" ;;
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> + --by-lines | --by-line | lines | line ) =
sortBy=3D"line" ;;
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> + --by-effect ) sortBy=3D"effect" ;;
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> + --enabled-only ) rpzActive=3D"enabled" ;;
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> + --active-all | --all | all ) rpzActive=3D"all" =
;;
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> + [0-9] | [0-9][0-9] ) weeks=3D$1 ;;
>>>>>>>>>>>>>>>>>>>>>>>> + esac
>>>>>>>>>>>>>>>>>>>>>>>> + shift # Shift after checking all the cases to =
get next option
>>>>>>>>>>>>>>>>>>>>>>>> +done
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +# get the list of message logs for N weeks
>>>>>>>>>>>>>>>>>>>>>>>> +messageLogs=3D$( find /var/log/messages* -type =
f | sort --version-sort |
>>>>>>>>>>>>>>>>>>>>>>>> + head -"${weeks}" )
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +# get the list of RPZ names & counts from the =
message log(s)
>>>>>>>>>>>>>>>>>>>>>>>> +rpzNameCount=3D$( for logf in ${messageLogs} ; =
do
>>>>>>>>>>>>>>>>>>>>>>>> + zgrep --text --fixed-strings 'info: rpz: =
applied' "${logf}" |
>>>>>>>>>>>>>>>>>>>>>>>> + awk '$10 ~ /\[\w*]/ { print $10 }' ;
>>>>>>>>>>>>>>>>>>>>>>>> + done | sort | uniq --count )
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +# flip results and remove brackets `[` and `]`
>>>>>>>>>>>>>>>>>>>>>>>> +rpzNameCount=3D$( echo "${rpzNameCount}" |
>>>>>>>>>>>>>>>>>>>>>>>> + awk '{ print $2, $1 }' |
>>>>>>>>>>>>>>>>>>>>>>>> + sed --regexp-extended 's|^\[(.*)\]|\1|' )
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +# grab only names
>>>>>>>>>>>>>>>>>>>>>>>> +rpzNames=3D$( echo "${rpzNameCount}" | awk '{ =
print $1 }' )
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +# get list of RPZ files
>>>>>>>>>>>>>>>>>>>>>>>> +rpzFileList=3D$( find /etc/unbound/zonefiles =
-type f -iname "*.rpz" )
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +# get basename of those files
>>>>>>>>>>>>>>>>>>>>>>>> +rpzBaseNames=3D$( echo "${rpzFileList}" |
>>>>>>>>>>>>>>>>>>>>>>>> + sed 's|/etc/unbound/zonefiles/||g ; =
s|\.rpz||g ;' )
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +# add to rpzNames
>>>>>>>>>>>>>>>>>>>>>>>> +rpzNames=3D"${rpzNames}"$'\n'"${rpzBaseNames}"
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +# drop duplicate names
>>>>>>>>>>>>>>>>>>>>>>>> +rpzNames=3D$( echo "${rpzNames}" | sort =
--unique )
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +# get line count for each RPZ
>>>>>>>>>>>>>>>>>>>>>>>> +lineCount=3D$( echo "${rpzFileList}" | xargs =
wc -l )
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +# get comment line count and blank line count =
for each RPZ
>>>>>>>>>>>>>>>>>>>>>>>> +commentCount=3D$( echo "${rpzFileList}" | =
xargs grep --count -e "^$" -e "^;" )
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +# get modified date each RPZ
>>>>>>>>>>>>>>>>>>>>>>>> +modDateList=3D$( echo "${rpzFileList}" | xargs =
stat -c '%.10y %n' )
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +ucListAuthZones=3D$( unbound-control =
list_auth_zones )
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +# get width of RPZ names
>>>>>>>>>>>>>>>>>>>>>>>> +pWidth=3D$( echo "${rpzNames}" | awk '{ print =
$1" " }' | wc -L )
>>>>>>>>>>>>>>>>>>>>>>>> +pFormat=3D"%-${pWidth}s %-8s %-8s %8s %12s =
%12s\n"
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +# print title line
>>>>>>>>>>>>>>>>>>>>>>>> +printf "${pFormat}" "name" "hits" "active" =
"lines" " hits/line" "last download"
>>>>>>>>>>>>>>>>>>>>>>>> +printf -- "--------------"
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +theResults=3D""
>>>>>>>>>>>>>>>>>>>>>>>> +totalLines=3D0
>>>>>>>>>>>>>>>>>>>>>>>> +totalHits=3D0
>>>>>>>>>>>>>>>>>>>>>>>> +while read -r theName
>>>>>>>>>>>>>>>>>>>>>>>> +do
>>>>>>>>>>>>>>>>>>>>>>>> + printf -- "--" # pretend progress bar
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> + # is this RPZ list active?
>>>>>>>>>>>>>>>>>>>>>>>> + theActive=3D"disabled"
>>>>>>>>>>>>>>>>>>>>>>>> + if grep --quiet "^${theName}\.rpz" <<< =
"${ucListAuthZones}"
>>>>>>>>>>>>>>>>>>>>>>>> + then
>>>>>>>>>>>>>>>>>>>>>>>> + theActive=3D"enabled"
>>>>>>>>>>>>>>>>>>>>>>>> + else
>>>>>>>>>>>>>>>>>>>>>>>> + [[ "${rpzActive}" =3D=3D enabled ]] && =
continue
>>>>>>>>>>>>>>>>>>>>>>>> + fi
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> + # get hit count
>>>>>>>>>>>>>>>>>>>>>>>> + theHits=3D"0"
>>>>>>>>>>>>>>>>>>>>>>>> + if output=3D$( grep "^${theName}\s" <<< =
"${rpzNameCount}" ) ; then
>>>>>>>>>>>>>>>>>>>>>>>> + theHits=3D$( echo "${output}" | awk '{ print =
$2 }' )
>>>>>>>>>>>>>>>>>>>>>>>> + totalHits=3D$(( totalHits + theHits ))
>>>>>>>>>>>>>>>>>>>>>>>> + fi
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> + # get line count
>>>>>>>>>>>>>>>>>>>>>>>> + theLines=3D"n/a"
>>>>>>>>>>>>>>>>>>>>>>>> + hitsPerLine=3D"0"
>>>>>>>>>>>>>>>>>>>>>>>> + if output=3D$( grep --fixed-strings =
"/${theName}.rpz" <<< "${lineCount}" ) ; then
>>>>>>>>>>>>>>>>>>>>>>>> + theLines=3D$( echo "${output}" | awk '{ print =
$1 }' )
>>>>>>>>>>>>>>>>>>>>>>>> + totalLines=3D$(( totalLines + theLines ))
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> + if [[ "${theLines}" -gt 2 ]] ; then
>>>>>>>>>>>>>>>>>>>>>>>> + hitsPerLine=3D$(( 100 * theHits / theLines ))
>>>>>>>>>>>>>>>>>>>>>>>> + fi
>>>>>>>>>>>>>>>>>>>>>>>> + fi
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> + # get modification date
>>>>>>>>>>>>>>>>>>>>>>>> + theModDate=3D"n/a"
>>>>>>>>>>>>>>>>>>>>>>>> + if output=3D$( grep --fixed-strings =
"/${theName}.rpz" <<< "${modDateList}" ) ; then
>>>>>>>>>>>>>>>>>>>>>>>> + theModDate=3D$( echo "${output}" | awk '{ =
print $1 }' )
>>>>>>>>>>>>>>>>>>>>>>>> + fi
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> + # add to results list
>>>>>>>>>>>>>>>>>>>>>>>> + theResults+=3D"${theName} ${theHits} =
${theActive} ${theLines} ${hitsPerLine} ${theModDate}"$'\n'
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +done <<< "${rpzNames}"
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +case "${sortBy}" in
>>>>>>>>>>>>>>>>>>>>>>>> + # sort by "active" then by "name"
>>>>>>>>>>>>>>>>>>>>>>>> + name) sortArg=3D(-k3,3r -k1,1) ;;
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> + # sort by "active" then by "hits" then by =
"name"
>>>>>>>>>>>>>>>>>>>>>>>> + hit) sortArg=3D(-k3,3r -k2,2nr -k1,1) ;;
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> + # sort by "active" then by "lines" then by =
"name"
>>>>>>>>>>>>>>>>>>>>>>>> + line) sortArg=3D(-k3,3r -k4,4nr -k1,1) ;;
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> + # sort by "active" then by "effect" then by =
"name"
>>>>>>>>>>>>>>>>>>>>>>>> + effect) sortArg=3D(-k3,3r -k5,5nr -k1,1) ;;
>>>>>>>>>>>>>>>>>>>>>>>> +esac
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +printf -- "--------------\n"
>>>>>>>>>>>>>>>>>>>>>>>> +# remove blank lines, sort, print as columns
>>>>>>>>>>>>>>>>>>>>>>>> +echo "${theResults}" |
>>>>>>>>>>>>>>>>>>>>>>>> + awk '!/^[[:space:]]*$/' |
>>>>>>>>>>>>>>>>>>>>>>>> + sort "${sortArg[@]}" |
>>>>>>>>>>>>>>>>>>>>>>>> + awk --assign=3Dwidth=3D"${pWidth}" \
>>>>>>>>>>>>>>>>>>>>>>>> + '{ printf "%-*s %-8s %-8s %8s %10s %% =
%12s\n", width, $1, $2, $3, $4, $5, $6 }'
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +printf "${pFormat}" "" "=3D=3D=3D=3D=3D=3D=3D" =
"" "=3D=3D=3D=3D=3D=3D=3D=3D" "" ""
>>>>>>>>>>>>>>>>>>>>>>>> +printf "${pFormat}" "Totals -->" =
"${totalHits}" "" "${totalLines}" "" ""
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +exit
>>>>>>>>>>>>>>>>>>>>>>>> diff --git a/config/rpz/rpz-sleep =
b/config/rpz/rpz-sleep
>>>>>>>>>>>>>>>>>>>>>>>> new file mode 100755
>>>>>>>>>>>>>>>>>>>>>>>> index 000000000..dd3603599
>>>>>>>>>>>>>>>>>>>>>>>> --- /dev/null
>>>>>>>>>>>>>>>>>>>>>>>> +++ b/config/rpz/rpz-sleep
>>>>>>>>>>>>>>>>>>>>>>>> @@ -0,0 +1,58 @@
>>>>>>>>>>>>>>>>>>>>>>>> +#!/bin/bash
>>>>>>>>>>>>>>>>>>>>>>>> =
+#########################################################################=
######
>>>>>>>>>>>>>>>>>>>>>>>> +# #
>>>>>>>>>>>>>>>>>>>>>>>> +# IPFire.org - A linux based firewall #
>>>>>>>>>>>>>>>>>>>>>>>> +# Copyright (C) 2024 IPFire Team =
<info@ipfire.org> #
>>>>>>>>>>>>>>>>>>>>>>>> +# #
>>>>>>>>>>>>>>>>>>>>>>>> +# 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 =
<http://www.gnu.org/licenses/>. #
>>>>>>>>>>>>>>>>>>>>>>>> +# #
>>>>>>>>>>>>>>>>>>>>>>>> =
+#########################################################################=
######
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +version=3D"2024-08-16" # v05
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +############### Functions ###############
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +# send message to message log
>>>>>>>>>>>>>>>>>>>>>>>> +msg_log () {
>>>>>>>>>>>>>>>>>>>>>>>> + logger --tag "${tagName}" "$*"
>>>>>>>>>>>>>>>>>>>>>>>> + if tty --silent ; then
>>>>>>>>>>>>>>>>>>>>>>>> + echo "${tagName}:" "$*"
>>>>>>>>>>>>>>>>>>>>>>>> + fi
>>>>>>>>>>>>>>>>>>>>>>>> +}
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +############### Main ###############
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +tagName=3D"unbound"
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +sleepTime=3D"${1:-5m}" # default to sleep for =
5m (5 minutes)
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +zoneList=3D$( unbound-control list_auth_zones =
| awk '{print $1}' )
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +for zone in ${zoneList} ; do
>>>>>>>>>>>>>>>>>>>>>>>> + printf "disable ${zone}\t"
>>>>>>>>>>>>>>>>>>>>>>>> + unbound-control rpz_disable "${zone}"
>>>>>>>>>>>>>>>>>>>>>>>> +done
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +msg_log "info: rpz: disabled all zones for =
${sleepTime}"
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +sleep "${sleepTime}"
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +for zone in ${zoneList} ; do
>>>>>>>>>>>>>>>>>>>>>>>> + printf "enable ${zone}\t"
>>>>>>>>>>>>>>>>>>>>>>>> + unbound-control rpz_enable "${zone}"
>>>>>>>>>>>>>>>>>>>>>>>> +done
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +msg_log "info: rpz: enabled all zones"
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +exit
>>>>>>>>>>>>>>>>>>>>>>>> diff --git a/config/rpz/rpz.de.pl =
b/config/rpz/rpz.de.pl
>>>>>>>>>>>>>>>>>>>>>>>> new file mode 100644
>>>>>>>>>>>>>>>>>>>>>>>> index 000000000..3770c6bb0
>>>>>>>>>>>>>>>>>>>>>>>> --- /dev/null
>>>>>>>>>>>>>>>>>>>>>>>> +++ b/config/rpz/rpz.de.pl
>>>>>>>>>>>>>>>>>>>>>>>> @@ -0,0 +1,30 @@
>>>>>>>>>>>>>>>>>>>>>>>> +# Added for Response Policy Zone (RPZ) add-on
>>>>>>>>>>>>>>>>>>>>>>>> +%tr =3D (%tr,
>>>>>>>>>>>>>>>>>>>>>>>> +'rpz' =3D> 'Response Policy Zones (RPZ)',
>>>>>>>>>>>>>>>>>>>>>>>> +'rpz apply' =3D> '=C3=9Cbernehmen',
>>>>>>>>>>>>>>>>>>>>>>>> +'rpz cl allow enable' =3D> 'Benutzerdefinierte =
Allowlist aktivieren:',
>>>>>>>>>>>>>>>>>>>>>>>> +'rpz cl allow info' =3D> 'Zugelassene Domains =
(eine pro Zeile)<br>Beispiel: domain.com, *.domain.com',
>>>>>>>>>>>>>>>>>>>>>>>> +'rpz cl allow' =3D> 'Benutzerdefinierte =
Allowlist',
>>>>>>>>>>>>>>>>>>>>>>>> +'rpz cl block enable' =3D> 'Benutzerdefinierte =
Blocklist aktivieren:',
>>>>>>>>>>>>>>>>>>>>>>>> +'rpz cl block info' =3D> 'Gesperrte Domains =
(eine pro Zeile)<br>Beispiel: domain.com, *.domain.com',
>>>>>>>>>>>>>>>>>>>>>>>> +'rpz cl block' =3D> 'Benutzerdefinierte =
Blocklist',
>>>>>>>>>>>>>>>>>>>>>>>> +'rpz cl' =3D> 'Benutzerdefinierte Listen',
>>>>>>>>>>>>>>>>>>>>>>>> +'rpz exitcode 101' =3D> 'Der Name enth=C3=A4lt =
unzul=C3=A4ssige Zeichen',
>>>>>>>>>>>>>>>>>>>>>>>> +'rpz exitcode 102' =3D> 'unbound-checkconf hat =
eine fehlerhafte Konfiguration ermittelt. F=C3=BChren Sie das Kommando =
unbound-checkconf auf der Konsole aus, um weitere Informationen zu =
erhalten.',
>>>>>>>>>>>>>>>>>>>>>>>> +'rpz exitcode 103' =3D> 'Die =
benutzerdefinierte Allow-/Blocklist ist leer',
>>>>>>>>>>>>>>>>>>>>>>>> +'rpz exitcode 104' =3D> 'Ein Eintrag mit =
identischem Namen existiert bereits',
>>>>>>>>>>>>>>>>>>>>>>>> +'rpz exitcode 105' =3D> 'Die URL ist =
ung=C3=BCltig',
>>>>>>>>>>>>>>>>>>>>>>>> +'rpz exitcode 106' =3D> 'Eintrag kann nicht =
entfernt werden, der Name existiert nicht',
>>>>>>>>>>>>>>>>>>>>>>>> +'rpz exitcode 107' =3D> 'Der Name ist =
ung=C3=BCltig - nur "allow" oder "block" m=C3=B6glich',
>>>>>>>>>>>>>>>>>>>>>>>> +'rpz exitcode 108' =3D> 'Fehlende oder =
inkorrekte Parameter',
>>>>>>>>>>>>>>>>>>>>>>>> +'rpz exitcode 109' =3D> 'unbound-control =
reload ist fehlgeschlagen',
>>>>>>>>>>>>>>>>>>>>>>>> +'rpz exitcode 110' =3D> 'Die =
benutzerdefinierte Allow-/Blocklist enth=C3=A4lt unzul=C3=A4ssige =
Eintr=C3=A4ge',
>>>>>>>>>>>>>>>>>>>>>>>> +'rpz exitcode 201' =3D> 'Die Anmerkung =
enth=C3=A4lt unzul=C3=A4ssige Zeichen',
>>>>>>>>>>>>>>>>>>>>>>>> +'rpz exitcode 202' =3D> 'Ung=C3=BCltiger =
Eintrag in der benutzerdefinierten Allowlist, Zeile ',
>>>>>>>>>>>>>>>>>>>>>>>> +'rpz exitcode 203' =3D> 'Ung=C3=BCltiger =
Eintrag in der benutzerdefinierten Blocklist, Zeile ',
>>>>>>>>>>>>>>>>>>>>>>>> +'rpz exitcode 204' =3D> 'Ausgew=C3=A4hlter =
Eintrag existiert nicht: ',
>>>>>>>>>>>>>>>>>>>>>>>> +'rpz zf editor' =3D> 'Zonendatei-Eintrag =
bearbeiten',
>>>>>>>>>>>>>>>>>>>>>>>> +'rpz zf imported' =3D> '(importiert aus =
rpz-config)',
>>>>>>>>>>>>>>>>>>>>>>>> +'rpz zf remark info' =3D> 'Erlaubte Zeichen =
sind a-z, A-Z, 0-9 und Unterstriche',
>>>>>>>>>>>>>>>>>>>>>>>> +'rpz zf' =3D> 'Zonendateien',
>>>>>>>>>>>>>>>>>>>>>>>> +);
>>>>>>>>>>>>>>>>>>>>>>>> diff --git a/config/rpz/rpz.en.pl =
b/config/rpz/rpz.en.pl
>>>>>>>>>>>>>>>>>>>>>>>> new file mode 100644
>>>>>>>>>>>>>>>>>>>>>>>> index 000000000..0720a8940
>>>>>>>>>>>>>>>>>>>>>>>> --- /dev/null
>>>>>>>>>>>>>>>>>>>>>>>> +++ b/config/rpz/rpz.en.pl
>>>>>>>>>>>>>>>>>>>>>>>> @@ -0,0 +1,30 @@
>>>>>>>>>>>>>>>>>>>>>>>> +# Added for Response Policy Zone (RPZ) add-on
>>>>>>>>>>>>>>>>>>>>>>>> +%tr =3D (%tr,
>>>>>>>>>>>>>>>>>>>>>>>> +'rpz' =3D> 'Response Policy Zones (RPZ)',
>>>>>>>>>>>>>>>>>>>>>>>> +'rpz apply' =3D> 'Apply',
>>>>>>>>>>>>>>>>>>>>>>>> +'rpz cl allow enable' =3D> 'Enable custom =
allowlist:',
>>>>>>>>>>>>>>>>>>>>>>>> +'rpz cl allow info' =3D> 'Allowed domains (one =
per line)<br>Example: domain.com, *.domain.com',
>>>>>>>>>>>>>>>>>>>>>>>> +'rpz cl allow' =3D> 'Custom allowlist',
>>>>>>>>>>>>>>>>>>>>>>>> +'rpz cl block enable' =3D> 'Enable custom =
blocklist:',
>>>>>>>>>>>>>>>>>>>>>>>> +'rpz cl block info' =3D> 'Blocked domains (one =
per line)<br>Example: domain.com, *.domain.com',
>>>>>>>>>>>>>>>>>>>>>>>> +'rpz cl block' =3D> 'Custom blocklist',
>>>>>>>>>>>>>>>>>>>>>>>> +'rpz cl' =3D> 'Custom lists',
>>>>>>>>>>>>>>>>>>>>>>>> +'rpz exitcode 101' =3D> 'the NAME is not =
valid',
>>>>>>>>>>>>>>>>>>>>>>>> +'rpz exitcode 102' =3D> 'unbound-checkconf =
found invalid configuration. In the Terminal run the command =
unbound-checkconf for more information',
>>>>>>>>>>>>>>>>>>>>>>>> +'rpz exitcode 103' =3D> 'the allow/block list =
is empty',
>>>>>>>>>>>>>>>>>>>>>>>> +'rpz exitcode 104' =3D> 'duplicate - NAME =
already exists',
>>>>>>>>>>>>>>>>>>>>>>>> +'rpz exitcode 105' =3D> 'the URL is not =
valid',
>>>>>>>>>>>>>>>>>>>>>>>> +'rpz exitcode 106' =3D> 'cannot remove the =
NAME does not exist',
>>>>>>>>>>>>>>>>>>>>>>>> +'rpz exitcode 107' =3D> 'the NAME is not valid =
- "allow" or "block" only',
>>>>>>>>>>>>>>>>>>>>>>>> +'rpz exitcode 108' =3D> 'missing or incorrect =
parameter',
>>>>>>>>>>>>>>>>>>>>>>>> +'rpz exitcode 109' =3D> 'unbound-control =
reload failed',
>>>>>>>>>>>>>>>>>>>>>>>> +'rpz exitcode 110' =3D> 'custom =
Allowlist/Blocklist contains invalid entries',
>>>>>>>>>>>>>>>>>>>>>>>> +'rpz exitcode 201' =3D> 'the REMARK is not =
valid',
>>>>>>>>>>>>>>>>>>>>>>>> +'rpz exitcode 202' =3D> 'invalid entry in =
allowlist, line ',
>>>>>>>>>>>>>>>>>>>>>>>> +'rpz exitcode 203' =3D> 'invalid entry in =
blocklist, line ',
>>>>>>>>>>>>>>>>>>>>>>>> +'rpz exitcode 204' =3D> 'Selected entry does =
not exist: ',
>>>>>>>>>>>>>>>>>>>>>>>> +'rpz zf editor' =3D> 'Edit zonefiles entry',
>>>>>>>>>>>>>>>>>>>>>>>> +'rpz zf imported' =3D> '(imported from =
rpz-config)',
>>>>>>>>>>>>>>>>>>>>>>>> +'rpz zf remark info' =3D> 'Valid characters =
are a-z, A-Z, 0-9 and underscore.',
>>>>>>>>>>>>>>>>>>>>>>>> +'rpz zf' =3D> 'Zonefiles',
>>>>>>>>>>>>>>>>>>>>>>>> +);
>>>>>>>>>>>>>>>>>>>>>>>> diff --git a/config/rpz/rpz.es.pl =
b/config/rpz/rpz.es.pl
>>>>>>>>>>>>>>>>>>>>>>>> new file mode 100644
>>>>>>>>>>>>>>>>>>>>>>>> index 000000000..98628e4aa
>>>>>>>>>>>>>>>>>>>>>>>> --- /dev/null
>>>>>>>>>>>>>>>>>>>>>>>> +++ b/config/rpz/rpz.es.pl
>>>>>>>>>>>>>>>>>>>>>>>> @@ -0,0 +1,30 @@
>>>>>>>>>>>>>>>>>>>>>>>> +# Added for Response Policy Zone (RPZ) add-on
>>>>>>>>>>>>>>>>>>>>>>>> +%tr =3D (%tr,
>>>>>>>>>>>>>>>>>>>>>>>> +'rpz' =3D> 'Zonas de pol=C3=ADtica de =
respuesta (RPZ)',
>>>>>>>>>>>>>>>>>>>>>>>> +'rpz apply' =3D> 'Aplicar',
>>>>>>>>>>>>>>>>>>>>>>>> +'rpz cl allow enable' =3D> 'Habilitar la lista =
blanca personalizada:',
>>>>>>>>>>>>>>>>>>>>>>>> +'rpz cl allow info' =3D> 'Dominio permitido =
(uno por l=C3=ADnea)<br>Ejemplo: domain.com, *.domain.com',
>>>>>>>>>>>>>>>>>>>>>>>> +'rpz cl allow' =3D> 'Lista blanca =
personalizada',
>>>>>>>>>>>>>>>>>>>>>>>> +'rpz cl block enable' =3D> 'Habilitar la lista =
negra personalizada:',
>>>>>>>>>>>>>>>>>>>>>>>> +'rpz cl block info' =3D> 'Dominio bloqueado =
(uno por l=C3=ADnea)<br>Ejemplo: domain.com, *.domain.com',
>>>>>>>>>>>>>>>>>>>>>>>> +'rpz cl block' =3D> 'Lista negra =
personalizada',
>>>>>>>>>>>>>>>>>>>>>>>> +'rpz cl' =3D> 'Lista personalizada',
>>>>>>>>>>>>>>>>>>>>>>>> +'rpz exitcode 101' =3D> 'El NOMBRE no es =
v=C3=A1lido',
>>>>>>>>>>>>>>>>>>>>>>>> +'rpz exitcode 102' =3D> 'unbound-checkconf ha =
encontrado una configuraci=C3=B3n no v=C3=A1lida. Desde Terminal, =
ejecute el comando unbound-checkconf para mayor informaci=C3=B3n',
>>>>>>>>>>>>>>>>>>>>>>>> +'rpz exitcode 103' =3D> 'La lista de =
permitidos/bloqueados est=C3=A1 vac=C3=ADa',
>>>>>>>>>>>>>>>>>>>>>>>> +'rpz exitcode 104' =3D> 'duplicado - NOMBRE ya =
existe',
>>>>>>>>>>>>>>>>>>>>>>>> +'rpz exitcode 105' =3D> 'la URL no es =
v=C3=A1lida',
>>>>>>>>>>>>>>>>>>>>>>>> +'rpz exitcode 106' =3D> 'no es posible =
eliminar el NOMBRE que no existe',
>>>>>>>>>>>>>>>>>>>>>>>> +'rpz exitcode 107' =3D> 'el NOMBRE no es =
v=C3=A1lido - s=C3=B3lo "permitir" o "bloquear"',
>>>>>>>>>>>>>>>>>>>>>>>> +'rpz exitcode 108' =3D> 'par=C3=A1metro =
faltante o incorrecto',
>>>>>>>>>>>>>>>>>>>>>>>> +'rpz exitcode 109' =3D> 'Error al recargar =
unbound-control',
>>>>>>>>>>>>>>>>>>>>>>>> +'rpz exitcode 110' =3D> 'la Lista blanca/Lista =
negra personalizada contiene entradas no v=C3=A1lidas',
>>>>>>>>>>>>>>>>>>>>>>>> +'rpz exitcode 201' =3D> 'el COMENTARIO no es =
v=C3=A1lido',
>>>>>>>>>>>>>>>>>>>>>>>> +'rpz exitcode 202' =3D> 'entrada no v=C3=A1lida =
en la lista blanca, l=C3=ADnea ',
>>>>>>>>>>>>>>>>>>>>>>>> +'rpz exitcode 203' =3D> 'entrada no v=C3=A1lida =
en la lista negra, l=C3=ADnea ',
>>>>>>>>>>>>>>>>>>>>>>>> +'rpz exitcode 204' =3D> 'La entrada =
seleccionada no existe: ',
>>>>>>>>>>>>>>>>>>>>>>>> +'rpz zf editor' =3D> 'Editar la entrada de =
archivos de zona',
>>>>>>>>>>>>>>>>>>>>>>>> +'rpz zf imported' =3D> '(importado de =
rpz-config)',
>>>>>>>>>>>>>>>>>>>>>>>> +'rpz zf remark info' =3D> 'Los caracteres =
v=C3=A1lidos son a-z, A-Z, 0-9 y gui=C3=B3n bajo',
>>>>>>>>>>>>>>>>>>>>>>>> +'rpz zf' =3D> 'Archivos de zona',
>>>>>>>>>>>>>>>>>>>>>>>> +);
>>>>>>>>>>>>>>>>>>>>>>>> diff --git a/config/rpz/rpz.fr.pl =
b/config/rpz/rpz.fr.pl
>>>>>>>>>>>>>>>>>>>>>>>> new file mode 100644
>>>>>>>>>>>>>>>>>>>>>>>> index 000000000..f35f3c2d0
>>>>>>>>>>>>>>>>>>>>>>>> --- /dev/null
>>>>>>>>>>>>>>>>>>>>>>>> +++ b/config/rpz/rpz.fr.pl
>>>>>>>>>>>>>>>>>>>>>>>> @@ -0,0 +1,30 @@
>>>>>>>>>>>>>>>>>>>>>>>> +# Added for Response Policy Zone (RPZ) add-on
>>>>>>>>>>>>>>>>>>>>>>>> +%tr =3D (%tr,
>>>>>>>>>>>>>>>>>>>>>>>> +'rpz' =3D> 'Response Policy Zones (RPZ)',
>>>>>>>>>>>>>>>>>>>>>>>> +'rpz apply' =3D> 'Appliquer',
>>>>>>>>>>>>>>>>>>>>>>>> +'rpz cl allow enable' =3D> 'Activer la liste =
d\'autorisations personnalis=C3=A9e:',
>>>>>>>>>>>>>>>>>>>>>>>> +'rpz cl allow info' =3D> 'Domaines autoris=C3=A9=
s (un par ligne)<br>Example: domain.com, *.domain.com',
>>>>>>>>>>>>>>>>>>>>>>>> +'rpz cl allow' =3D> 'Liste d\'autorisations =
personnalis=C3=A9e',
>>>>>>>>>>>>>>>>>>>>>>>> +'rpz cl block enable' =3D> 'Activer la liste =
de blocage personnalis=C3=A9e:',
>>>>>>>>>>>>>>>>>>>>>>>> +'rpz cl block info' =3D> 'Domaines bloqu=C3=A9s =
(un par ligne)<br>Example: domain.com, *.domain.com',
>>>>>>>>>>>>>>>>>>>>>>>> +'rpz cl block' =3D> 'liste de blocage =
personnalis=C3=A9',
>>>>>>>>>>>>>>>>>>>>>>>> +'rpz cl' =3D> 'Listes personnalis=C3=A9es',
>>>>>>>>>>>>>>>>>>>>>>>> +'rpz exitcode 101' =3D> 'le NOM n\'est pas =
valide',
>>>>>>>>>>>>>>>>>>>>>>>> +'rpz exitcode 102' =3D> 'unbound-checkconf =
configuration non valide trouv=C3=A9e. Dans le terminal, ex=C3=A9cutez =
la commande unbound-checkconf pour plus d\'informations',
>>>>>>>>>>>>>>>>>>>>>>>> +'rpz exitcode 103' =3D> 'la liste =
autoriser/bloquer est vide',
>>>>>>>>>>>>>>>>>>>>>>>> +'rpz exitcode 104' =3D> 'le NOM existe =
d=C3=A9j=C3=A0',
>>>>>>>>>>>>>>>>>>>>>>>> +'rpz exitcode 105' =3D> 'L\'URL n\'est pas =
valide',
>>>>>>>>>>>>>>>>>>>>>>>> +'rpz exitcode 106' =3D> 'impossible de =
supprimer le NOM n\'existe pas',
>>>>>>>>>>>>>>>>>>>>>>>> +'rpz exitcode 107' =3D> 'le NOM n\'est pas =
valide - =C2=AB autoriser =C2=BB ou =C2=AB bloquer =C2=BB seulement',
>>>>>>>>>>>>>>>>>>>>>>>> +'rpz exitcode 108' =3D> 'param=C3=A8tre =
manquant ou incorrect',
>>>>>>>>>>>>>>>>>>>>>>>> +'rpz exitcode 109' =3D> 'unbound-control =
rechargement =C3=A9chou=C3=A9',
>>>>>>>>>>>>>>>>>>>>>>>> +'rpz exitcode 110' =3D> 'la liste =
autoriser/bloquer contient des entr=C3=A9es non valides',
>>>>>>>>>>>>>>>>>>>>>>>> +'rpz exitcode 201' =3D> 'la REMARQUE n\'est =
pas valable',
>>>>>>>>>>>>>>>>>>>>>>>> +'rpz exitcode 202' =3D> 'entr=C3=A9e non =
valide dans la liste d\'autorisation, ligne ',
>>>>>>>>>>>>>>>>>>>>>>>> +'rpz exitcode 203' =3D> 'entr=C3=A9e non =
valide dans la liste de blocs, ligne ',
>>>>>>>>>>>>>>>>>>>>>>>> +'rpz exitcode 204' =3D> 'L\'entr=C3=A9e =
s=C3=A9lectionn=C3=A9e n\'existe pas: ',
>>>>>>>>>>>>>>>>>>>>>>>> +'rpz zf editor' =3D> 'Modifier l\'entr=C3=A9e =
Fichiers Zone',
>>>>>>>>>>>>>>>>>>>>>>>> +'rpz zf imported' =3D> '(import=C3=A9 de =
rpz-config)',
>>>>>>>>>>>>>>>>>>>>>>>> +'rpz zf remark info' =3D> 'Les caract=C3=A8res =
valides sont a-z, A-Z, 0-9 et soulignement.',
>>>>>>>>>>>>>>>>>>>>>>>> +'rpz zf' =3D> 'Fichiers Zone',
>>>>>>>>>>>>>>>>>>>>>>>> +);
>>>>>>>>>>>>>>>>>>>>>>>> diff --git a/config/rpz/rpz.it.pl =
b/config/rpz/rpz.it.pl
>>>>>>>>>>>>>>>>>>>>>>>> new file mode 100644
>>>>>>>>>>>>>>>>>>>>>>>> index 000000000..ee81605c9
>>>>>>>>>>>>>>>>>>>>>>>> --- /dev/null
>>>>>>>>>>>>>>>>>>>>>>>> +++ b/config/rpz/rpz.it.pl
>>>>>>>>>>>>>>>>>>>>>>>> @@ -0,0 +1,30 @@
>>>>>>>>>>>>>>>>>>>>>>>> +# Added for Response Policy Zone (RPZ) add-on
>>>>>>>>>>>>>>>>>>>>>>>> +%tr =3D (%tr,
>>>>>>>>>>>>>>>>>>>>>>>> +'rpz' =3D> 'Response Policy Zones (RPZ)',
>>>>>>>>>>>>>>>>>>>>>>>> +'rpz apply' =3D> 'Applica',
>>>>>>>>>>>>>>>>>>>>>>>> +'rpz cl allow enable' =3D> 'Abilita la =
Whitelist personalizzata:',
>>>>>>>>>>>>>>>>>>>>>>>> +'rpz cl allow info' =3D> 'Domini consentiti =
(uno per riga)<br>Esempio: domain.com, *.domain.com',
>>>>>>>>>>>>>>>>>>>>>>>> +'rpz cl allow' =3D> 'Whitelist =
personalizzata',
>>>>>>>>>>>>>>>>>>>>>>>> +'rpz cl block enable' =3D> 'Abilita la =
Blacklist personalizzata:',
>>>>>>>>>>>>>>>>>>>>>>>> +'rpz cl block info' =3D> 'Domini bloccati (uno =
per riga)<br>Esempio: domain.com, *.domain.com',
>>>>>>>>>>>>>>>>>>>>>>>> +'rpz cl block' =3D> 'Blacklist =
personalizzata',
>>>>>>>>>>>>>>>>>>>>>>>> +'rpz cl' =3D> 'Liste personalizzate',
>>>>>>>>>>>>>>>>>>>>>>>> +'rpz exitcode 101' =3D> 'il NOME non =C3=A8 =
valido',
>>>>>>>>>>>>>>>>>>>>>>>> +'rpz exitcode 102' =3D> 'unbound-checkconf ha =
trovato una configurazione non valida. Dal Terminale esegui il comando =
unbound-checkconf per maggiori informazioni',
>>>>>>>>>>>>>>>>>>>>>>>> +'rpz exitcode 103' =3D> 'l\'elenco =
consentiti/bloccati =C3=A8 vuoto',
>>>>>>>>>>>>>>>>>>>>>>>> +'rpz exitcode 104' =3D> 'duplicato - NAME =
esiste di gi=C3=A0',
>>>>>>>>>>>>>>>>>>>>>>>> +'rpz exitcode 105' =3D> 'l\'URL non =C3=A8 =
valido',
>>>>>>>>>>>>>>>>>>>>>>>> +'rpz exitcode 106' =3D> 'non =C3=A8 possibile =
rimuovere il NOME non esiste',
>>>>>>>>>>>>>>>>>>>>>>>> +'rpz exitcode 107' =3D> 'il NOME non =C3=A8 =
valido - solo "consenti" o "blocca"',
>>>>>>>>>>>>>>>>>>>>>>>> +'rpz exitcode 108' =3D> 'parametro mancante o =
non corretto',
>>>>>>>>>>>>>>>>>>>>>>>> +'rpz exitcode 109' =3D> 'ricaricamento del =
controllo non associato non riuscito',
>>>>>>>>>>>>>>>>>>>>>>>> +'rpz exitcode 110' =3D> 'la =
Whitelist/Blacklist personalizzata contiene voci non valide',
>>>>>>>>>>>>>>>>>>>>>>>> +'rpz exitcode 201' =3D> 'l"OSSERVAZIONE non =C3=A8=
 valida',
>>>>>>>>>>>>>>>>>>>>>>>> +'rpz exitcode 202' =3D> 'voce non valida nella =
Whitelist, riga ',
>>>>>>>>>>>>>>>>>>>>>>>> +'rpz exitcode 203' =3D> 'voce non valida nella =
Blacklist, riga ',
>>>>>>>>>>>>>>>>>>>>>>>> +'rpz exitcode 204' =3D> 'La voce selezionata =
non esiste: ',
>>>>>>>>>>>>>>>>>>>>>>>> +'rpz zf editor' =3D> 'Modifica la voce dei =
file di zona',
>>>>>>>>>>>>>>>>>>>>>>>> +'rpz zf imported' =3D> '(importato da =
rpz-config)',
>>>>>>>>>>>>>>>>>>>>>>>> +'rpz zf remark info' =3D> 'I caratteri validi =
sono a-z, A-Z, 0-9 e trattino basso',
>>>>>>>>>>>>>>>>>>>>>>>> +'rpz zf' =3D> 'Zonefiles',
>>>>>>>>>>>>>>>>>>>>>>>> +);
>>>>>>>>>>>>>>>>>>>>>>>> diff --git a/config/rpz/rpz.tr.pl =
b/config/rpz/rpz.tr.pl
>>>>>>>>>>>>>>>>>>>>>>>> new file mode 100644
>>>>>>>>>>>>>>>>>>>>>>>> index 000000000..00226e192
>>>>>>>>>>>>>>>>>>>>>>>> --- /dev/null
>>>>>>>>>>>>>>>>>>>>>>>> +++ b/config/rpz/rpz.tr.pl
>>>>>>>>>>>>>>>>>>>>>>>> @@ -0,0 +1,30 @@
>>>>>>>>>>>>>>>>>>>>>>>> +# I=EF=BF=BDin eklendi Ayriyeten Response =
Policy Zone (RPZ)
>>>>>>>>>>>>>>>>>>>>>>>> +%tr =3D (%tr,
>>>>>>>>>>>>>>>>>>>>>>>> +'rpz' =3D> 'Response Policy Zones (RPZ)',
>>>>>>>>>>>>>>>>>>>>>>>> +'rpz apply' =3D> 'Uygulamak',
>>>>>>>>>>>>>>>>>>>>>>>> +'rpz cl allow enable' =3D> '=EF=BF=BDzel =
Etkinlestir allowlist:',
>>>>>>>>>>>>>>>>>>>>>>>> +'rpz cl allow info' =3D> 'Izin verilmis =
domains (satir basina bir)<br>=EF=BF=BDrnegin: domain.com, =
*.domain.com',
>>>>>>>>>>>>>>>>>>>>>>>> +'rpz cl allow' =3D> 'Etkinlestir allowlist',
>>>>>>>>>>>>>>>>>>>>>>>> +'rpz cl block enable' =3D> '=EF=BF=BDzel =
Etkinlestir blocklist:',
>>>>>>>>>>>>>>>>>>>>>>>> +'rpz cl block info' =3D> 'Engellenmis domains =
(satir basina bir)<br>=EF=BF=BDrnegin: domain.com, *.domain.com',
>>>>>>>>>>>>>>>>>>>>>>>> +'rpz cl block' =3D> 'Engellenmis blocklist',
>>>>>>>>>>>>>>>>>>>>>>>> +'rpz cl' =3D> 'Engellenmis lists',
>>>>>>>>>>>>>>>>>>>>>>>> +'rpz exitcode 101' =3D> 'NAME ge=EF=BF=BDerli =
degil',
>>>>>>>>>>>>>>>>>>>>>>>> +'rpz exitcode 102' =3D> 'unbound-checkconf =
ge=EF=BF=BDersiz yapilandirma bulundu. Terminalde daha fazla bilgi =
i=EF=BF=BDin Unbound-checkConf komutunu =EF=BF=BDalistirin',
>>>>>>>>>>>>>>>>>>>>>>>> +'rpz exitcode 103' =3D> 'allow/block liste =
bos',
>>>>>>>>>>>>>>>>>>>>>>>> +'rpz exitcode 104' =3D> 'kopyalamak - NAME =
zaten var',
>>>>>>>>>>>>>>>>>>>>>>>> +'rpz exitcode 105' =3D> 'URL ge=EF=BF=BDerli =
degil',
>>>>>>>>>>>>>>>>>>>>>>>> +'rpz exitcode 106' =3D> '=EF=BF=BDikarilamiyor =
NAME yok',
>>>>>>>>>>>>>>>>>>>>>>>> +'rpz exitcode 107' =3D> 'NAME ge=EF=BF=BDerli =
degil - "allow" veya "block" yalniz',
>>>>>>>>>>>>>>>>>>>>>>>> +'rpz exitcode 108' =3D> 'Parametre eksik veya =
yanlis',
>>>>>>>>>>>>>>>>>>>>>>>> +'rpz exitcode 109' =3D> 'unbound-control =
basarisiz',
>>>>>>>>>>>>>>>>>>>>>>>> +'rpz exitcode 110' =3D> 'Engellenmis =
Allowlist/Blocklist ge=EF=BF=BDersiz girisler i=EF=BF=BDerir',
>>>>>>>>>>>>>>>>>>>>>>>> +'rpz exitcode 201' =3D> 'REMARK ge=EF=BF=BDerli =
degil',
>>>>>>>>>>>>>>>>>>>>>>>> +'rpz exitcode 202' =3D> 'Ge=EF=BF=BDersiz =
giris allowlist, line ',
>>>>>>>>>>>>>>>>>>>>>>>> +'rpz exitcode 203' =3D> 'Ge=EF=BF=BDersiz =
giris blocklist, line ',
>>>>>>>>>>>>>>>>>>>>>>>> +'rpz exitcode 204' =3D> 'Se=EF=BF=BDilen giris =
yok: ',
>>>>>>>>>>>>>>>>>>>>>>>> +'rpz zf editor' =3D> 'yazimlamak zonefiles =
giris',
>>>>>>>>>>>>>>>>>>>>>>>> +'rpz zf imported' =3D> '(ithal edildi =
rpz-config)',
>>>>>>>>>>>>>>>>>>>>>>>> +'rpz zf remark info' =3D> 'Ge=EF=BF=BDerli =
karakterler a-z, A-Z, 0-9ve alt=EF=BF=BDst.',
>>>>>>>>>>>>>>>>>>>>>>>> +'rpz zf' =3D> 'Zonefiles',
>>>>>>>>>>>>>>>>>>>>>>>> +);
>>>>>>>>>>>>>>>>>>>>>>>> diff --git a/html/cgi-bin/rpz.cgi =
b/html/cgi-bin/rpz.cgi
>>>>>>>>>>>>>>>>>>>>>>>> new file mode 100644
>>>>>>>>>>>>>>>>>>>>>>>> index 000000000..a821c92ac
>>>>>>>>>>>>>>>>>>>>>>>> --- /dev/null
>>>>>>>>>>>>>>>>>>>>>>>> +++ b/html/cgi-bin/rpz.cgi
>>>>>>>>>>>>>>>>>>>>>>>> @@ -0,0 +1,923 @@
>>>>>>>>>>>>>>>>>>>>>>>> +#!/usr/bin/perl
>>>>>>>>>>>>>>>>>>>>>>>> =
+#########################################################################=
######
>>>>>>>>>>>>>>>>>>>>>>>> +# #
>>>>>>>>>>>>>>>>>>>>>>>> +# IPFire.org - A linux based firewall #
>>>>>>>>>>>>>>>>>>>>>>>> +# Copyright (C) 2005-2024 IPFire Team =
<info@ipfire.org> #
>>>>>>>>>>>>>>>>>>>>>>>> +# #
>>>>>>>>>>>>>>>>>>>>>>>> +# 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 =
<http://www.gnu.org/licenses/>. #
>>>>>>>>>>>>>>>>>>>>>>>> +# #
>>>>>>>>>>>>>>>>>>>>>>>> =
+#########################################################################=
######
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +use strict;
>>>>>>>>>>>>>>>>>>>>>>>> +use Scalar::Util qw(looks_like_number);
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +# debugging
>>>>>>>>>>>>>>>>>>>>>>>> +#use warnings;
>>>>>>>>>>>>>>>>>>>>>>>> +#use CGI::Carp 'fatalsToBrowser';
>>>>>>>>>>>>>>>>>>>>>>>> +#use Data::Dumper;
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +require '/var/ipfire/general-functions.pl';
>>>>>>>>>>>>>>>>>>>>>>>> +require "${General::swroot}/lang.pl";
>>>>>>>>>>>>>>>>>>>>>>>> +require "${General::swroot}/header.pl";
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +###--- Extra HTML ---###
>>>>>>>>>>>>>>>>>>>>>>>> +my $extraHead =3D <<END
>>>>>>>>>>>>>>>>>>>>>>>> +<style>
>>>>>>>>>>>>>>>>>>>>>>>> + /* alternating row background */
>>>>>>>>>>>>>>>>>>>>>>>> + .tbl tr:nth-child(2n+2) {
>>>>>>>>>>>>>>>>>>>>>>>> + background-color: var(--color-light-grey);
>>>>>>>>>>>>>>>>>>>>>>>> + }
>>>>>>>>>>>>>>>>>>>>>>>> + .tbl tr:nth-child(2n+3) {
>>>>>>>>>>>>>>>>>>>>>>>> + background-color: var(--color-grey);
>>>>>>>>>>>>>>>>>>>>>>>> + }
>>>>>>>>>>>>>>>>>>>>>>>> + /* text styles */
>>>>>>>>>>>>>>>>>>>>>>>> + .tbl th:not(:last-child) {
>>>>>>>>>>>>>>>>>>>>>>>> + text-align: left;
>>>>>>>>>>>>>>>>>>>>>>>> + }
>>>>>>>>>>>>>>>>>>>>>>>> + div.right {
>>>>>>>>>>>>>>>>>>>>>>>> + text-align: right;
>>>>>>>>>>>>>>>>>>>>>>>> + margin-top: 0.5em;
>>>>>>>>>>>>>>>>>>>>>>>> + }
>>>>>>>>>>>>>>>>>>>>>>>> + /* customlist input */
>>>>>>>>>>>>>>>>>>>>>>>> + textarea.domainlist {
>>>>>>>>>>>>>>>>>>>>>>>> + margin: 0.5em 0;
>>>>>>>>>>>>>>>>>>>>>>>> + resize: vertical;
>>>>>>>>>>>>>>>>>>>>>>>> + min-height: 10em;
>>>>>>>>>>>>>>>>>>>>>>>> + overflow: auto;
>>>>>>>>>>>>>>>>>>>>>>>> + white-space: pre;
>>>>>>>>>>>>>>>>>>>>>>>> + }
>>>>>>>>>>>>>>>>>>>>>>>> + button[type=3Dsubmit]:disabled {
>>>>>>>>>>>>>>>>>>>>>>>> + opacity: 0.6;
>>>>>>>>>>>>>>>>>>>>>>>> + }
>>>>>>>>>>>>>>>>>>>>>>>> +</style>
>>>>>>>>>>>>>>>>>>>>>>>> +END
>>>>>>>>>>>>>>>>>>>>>>>> +;
>>>>>>>>>>>>>>>>>>>>>>>> +###--- End of extra HTML ---###
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +### Settings ###
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +# Request DNS service reload after =
configuration change
>>>>>>>>>>>>>>>>>>>>>>>> +my $RPZ_RELOAD_FLAG =3D =
"${General::swroot}/dns/rpz/reload.flag";
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +# Configuration file for all available =
zonefiles
>>>>>>>>>>>>>>>>>>>>>>>> +# Format: index, name (unique), enabled =
(on/off), URL, remark
>>>>>>>>>>>>>>>>>>>>>>>> +my $ZONEFILES_CONF =3D =
"${General::swroot}/dns/rpz/zonefiles.conf";
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +# Configuration file for custom lists
>>>>>>>>>>>>>>>>>>>>>>>> +# IDs: 0=3Dallowlist, 1=3Dblocklist, 2=3Doptions=
 (allow/block enabled)
>>>>>>>>>>>>>>>>>>>>>>>> +my $CUSTOMLISTS_CONF =3D =
"${General::swroot}/dns/rpz/customlists.conf";
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +# Export custom lists to rpz-config
>>>>>>>>>>>>>>>>>>>>>>>> +my $RPZ_ALLOWLIST =3D =
"${General::swroot}/dns/rpz/allowlist";
>>>>>>>>>>>>>>>>>>>>>>>> +my $RPZ_BLOCKLIST =3D =
"${General::swroot}/dns/rpz/blocklist";
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +### Preparation ###
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +# Create missing config files
>>>>>>>>>>>>>>>>>>>>>>>> +unless(-f $ZONEFILES_CONF) { =
&General::system('touch', "$ZONEFILES_CONF"); }
>>>>>>>>>>>>>>>>>>>>>>>> +unless(-f $CUSTOMLISTS_CONF) { =
&General::system('touch', "$CUSTOMLISTS_CONF"); }
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +## Global gui data
>>>>>>>>>>>>>>>>>>>>>>>> +my $errormessage =3D "";
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +## Global configuration data
>>>>>>>>>>>>>>>>>>>>>>>> +my %zonefiles =3D ();
>>>>>>>>>>>>>>>>>>>>>>>> +my %customlists =3D ();
>>>>>>>>>>>>>>>>>>>>>>>> +&_zonefiles_load();
>>>>>>>>>>>>>>>>>>>>>>>> +&_customlists_load();
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +## Global CGI form data
>>>>>>>>>>>>>>>>>>>>>>>> +my %cgiparams =3D ();
>>>>>>>>>>>>>>>>>>>>>>>> +&Header::getcgihash(\%cgiparams);
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +my $action =3D $cgiparams{'ACTION'} // 'NONE';
>>>>>>>>>>>>>>>>>>>>>>>> +my $action_key =3D $cgiparams{'KEY'} // ''; # =
entry being edited, empty =3D none/new
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +###--- Process form actions ---###
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +# Zonefiles action: Check whether the =
requested entry exists
>>>>>>>>>>>>>>>>>>>>>>>> +if((substr($action, 0, 3) eq 'ZF_') && =
($action_key)) {
>>>>>>>>>>>>>>>>>>>>>>>> + unless(defined $zonefiles{$action_key}) {
>>>>>>>>>>>>>>>>>>>>>>>> + $errormessage =3D &_rpz_error_tr(204, =
$action_key);
>>>>>>>>>>>>>>>>>>>>>>>> + $action =3D 'NONE';
>>>>>>>>>>>>>>>>>>>>>>>> + }
>>>>>>>>>>>>>>>>>>>>>>>> +}
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +## Perform actions
>>>>>>>>>>>>>>>>>>>>>>>> +if($action eq 'ZF_SAVE') { ## Save new or =
modified zonefiles entry
>>>>>>>>>>>>>>>>>>>>>>>> + if(&_action_zf_save()) {
>>>>>>>>>>>>>>>>>>>>>>>> + $action =3D 'NONE'; # success, return to main =
page
>>>>>>>>>>>>>>>>>>>>>>>> + &_http_prg_redirect();
>>>>>>>>>>>>>>>>>>>>>>>> + } else {
>>>>>>>>>>>>>>>>>>>>>>>> + $action =3D 'ZF_EDIT'; # error occured, keep =
editing
>>>>>>>>>>>>>>>>>>>>>>>> + }
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +} elsif($action eq 'ZF_TOGGLE') { ## Toggle =
on/off
>>>>>>>>>>>>>>>>>>>>>>>> + if(&_action_zf_toggle()) {
>>>>>>>>>>>>>>>>>>>>>>>> + $action =3D 'NONE';
>>>>>>>>>>>>>>>>>>>>>>>> + &_http_prg_redirect();
>>>>>>>>>>>>>>>>>>>>>>>> + }
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +} elsif($action eq 'ZF_REMOVE') { ## Remove =
entry
>>>>>>>>>>>>>>>>>>>>>>>> + if(&_action_zf_remove()) {
>>>>>>>>>>>>>>>>>>>>>>>> + $action =3D 'NONE';
>>>>>>>>>>>>>>>>>>>>>>>> + &_http_prg_redirect();
>>>>>>>>>>>>>>>>>>>>>>>> + }
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +} elsif($action eq 'CL_SAVE') { ## Save custom =
lists
>>>>>>>>>>>>>>>>>>>>>>>> + if(&_action_cl_save()) {
>>>>>>>>>>>>>>>>>>>>>>>> + $action =3D 'NONE';
>>>>>>>>>>>>>>>>>>>>>>>> + &_http_prg_redirect();
>>>>>>>>>>>>>>>>>>>>>>>> + }
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +} elsif($action eq 'RPZ_RELOAD') { ## Reload =
dns configuration
>>>>>>>>>>>>>>>>>>>>>>>> + if(&_action_rpz_reload()) {
>>>>>>>>>>>>>>>>>>>>>>>> + $action =3D 'NONE';
>>>>>>>>>>>>>>>>>>>>>>>> + &_http_prg_redirect();
>>>>>>>>>>>>>>>>>>>>>>>> + }
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +} elsif($action eq 'UNB_RESTART') { ## Restart =
unbound service
>>>>>>>>>>>>>>>>>>>>>>>> + if(&_action_unb_restart()) {
>>>>>>>>>>>>>>>>>>>>>>>> + $action =3D 'NONE';
>>>>>>>>>>>>>>>>>>>>>>>> + &_http_prg_redirect();
>>>>>>>>>>>>>>>>>>>>>>>> + }
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +}
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +###--- Start GUI ---###
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +## Start http output
>>>>>>>>>>>>>>>>>>>>>>>> +&Header::showhttpheaders();
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +# Start HTML
>>>>>>>>>>>>>>>>>>>>>>>> +&Header::openpage($Lang::tr{'rpz'}, 1, =
$extraHead);
>>>>>>>>>>>>>>>>>>>>>>>> +&Header::openbigbox('100%', 'left', '');
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +# Show error messages
>>>>>>>>>>>>>>>>>>>>>>>> +if($errormessage) {
>>>>>>>>>>>>>>>>>>>>>>>> + &_print_message($errormessage);
>>>>>>>>>>>>>>>>>>>>>>>> +}
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +# Handle zonefile add/edit mode
>>>>>>>>>>>>>>>>>>>>>>>> +if($action eq "ZF_EDIT") {
>>>>>>>>>>>>>>>>>>>>>>>> + &_print_zonefile_editor();
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> + # Finalize page and exit cleanly
>>>>>>>>>>>>>>>>>>>>>>>> + &Header::closebigbox();
>>>>>>>>>>>>>>>>>>>>>>>> + &Header::closepage();
>>>>>>>>>>>>>>>>>>>>>>>> + exit(0);
>>>>>>>>>>>>>>>>>>>>>>>> +}
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +# Show gui elements
>>>>>>>>>>>>>>>>>>>>>>>> +&_print_zonefiles();
>>>>>>>>>>>>>>>>>>>>>>>> +&_print_customlists();
>>>>>>>>>>>>>>>>>>>>>>>> +&_print_gui_extras();
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +&Header::closebigbox();
>>>>>>>>>>>>>>>>>>>>>>>> +&Header::closepage();
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +###--- End of GUI ---###
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +###--- Internal configuration file functions =
---###
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +# Load all available zonefiles from rpz-config =
and the internal configuration
>>>>>>>>>>>>>>>>>>>>>>>> +sub _zonefiles_load {
>>>>>>>>>>>>>>>>>>>>>>>> + # Clean start
>>>>>>>>>>>>>>>>>>>>>>>> + %zonefiles =3D ();
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> + # Source 1: Get the currently enabled =
zonefiles from rpz-config (expected format [name]=3D[URL])
>>>>>>>>>>>>>>>>>>>>>>>> + my @enabled_files =3D =
&General::system_output('/usr/sbin/rpz-config', 'list');
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> + foreach my $row (@enabled_files) {
>>>>>>>>>>>>>>>>>>>>>>>> + chomp($row);
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> + # Use regex instead of split() to skip =
non-matching lines
>>>>>>>>>>>>>>>>>>>>>>>> + next unless($row =3D~ /^(\w+)=3D(.+)$/);
>>>>>>>>>>>>>>>>>>>>>>>> + my ($name, $url) =3D ($1, $2);
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> + # Unique names are already guaranteed by =
rpz-config
>>>>>>>>>>>>>>>>>>>>>>>> + if(&_rpz_validate_zonefile($name, $url, '', =
0) =3D=3D 0) {
>>>>>>>>>>>>>>>>>>>>>>>> + # Populate global data hash, mark all found =
entries as enabled
>>>>>>>>>>>>>>>>>>>>>>>> + my %entry =3D ('enabled' =3D> 'on',
>>>>>>>>>>>>>>>>>>>>>>>> + 'url' =3D> $url,
>>>>>>>>>>>>>>>>>>>>>>>> + 'remark' =3D> $Lang::tr{'rpz zf imported'});
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> + $zonefiles{$name} =3D \%entry;
>>>>>>>>>>>>>>>>>>>>>>>> + }
>>>>>>>>>>>>>>>>>>>>>>>> + }
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> + # Source 2: Get additional data and disabled =
entries from configuration file
>>>>>>>>>>>>>>>>>>>>>>>> + my %configured_files =3D ();
>>>>>>>>>>>>>>>>>>>>>>>> + &General::readhasharray($ZONEFILES_CONF, =
\%configured_files);
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> + foreach my $row (values (%configured_files)) =
{
>>>>>>>>>>>>>>>>>>>>>>>> + my ($name, $enabled, $url, $remark) =3D =
@$row;
>>>>>>>>>>>>>>>>>>>>>>>> + $remark //=3D "";
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> + next unless($name);
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> + # Check whether this row belongs to an entry =
already imported from rpz-config
>>>>>>>>>>>>>>>>>>>>>>>> + if(defined $zonefiles{$name}) {
>>>>>>>>>>>>>>>>>>>>>>>> + # Existing entry, only merge additional data
>>>>>>>>>>>>>>>>>>>>>>>> + $zonefiles{$name}{'remark'} =3D $remark;
>>>>>>>>>>>>>>>>>>>>>>>> + } else {
>>>>>>>>>>>>>>>>>>>>>>>> + # Skip entry if it is marked as enabled but =
not found by rpz-config. It was then deleted manually
>>>>>>>>>>>>>>>>>>>>>>>> + if($enabled ne 'on') {
>>>>>>>>>>>>>>>>>>>>>>>> + # Populate global data hash
>>>>>>>>>>>>>>>>>>>>>>>> + my %entry =3D ('enabled' =3D> 'off',
>>>>>>>>>>>>>>>>>>>>>>>> + 'url' =3D> $url // "",
>>>>>>>>>>>>>>>>>>>>>>>> + 'remark' =3D> $remark);
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> + $zonefiles{$name} =3D \%entry;
>>>>>>>>>>>>>>>>>>>>>>>> + }
>>>>>>>>>>>>>>>>>>>>>>>> + }
>>>>>>>>>>>>>>>>>>>>>>>> + }
>>>>>>>>>>>>>>>>>>>>>>>> +}
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +# Save internal zonefiles configuration
>>>>>>>>>>>>>>>>>>>>>>>> +sub _zonefiles_save_conf {
>>>>>>>>>>>>>>>>>>>>>>>> + my $index =3D 0;
>>>>>>>>>>>>>>>>>>>>>>>> + my %export =3D ();
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> + # Loop trough all zonefiles and create =
"hasharray" type export
>>>>>>>>>>>>>>>>>>>>>>>> + foreach my $name (keys %zonefiles) {
>>>>>>>>>>>>>>>>>>>>>>>> + my @entry =3D ($name,
>>>>>>>>>>>>>>>>>>>>>>>> + $zonefiles{$name}{'enabled'},
>>>>>>>>>>>>>>>>>>>>>>>> + $zonefiles{$name}{'url'},
>>>>>>>>>>>>>>>>>>>>>>>> + $zonefiles{$name}{'remark'});
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> + $export{$index++} =3D \@entry;
>>>>>>>>>>>>>>>>>>>>>>>> + }
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> + &General::writehasharray($ZONEFILES_CONF, =
\%export);
>>>>>>>>>>>>>>>>>>>>>>>> +}
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +# Load custom lists from rpz-config and the =
internal configuration
>>>>>>>>>>>>>>>>>>>>>>>> +sub _customlists_load {
>>>>>>>>>>>>>>>>>>>>>>>> + # Clean start
>>>>>>>>>>>>>>>>>>>>>>>> + %customlists =3D ();
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> + # Load configuration file
>>>>>>>>>>>>>>>>>>>>>>>> + my %lists_conf =3D ();
>>>>>>>>>>>>>>>>>>>>>>>> + &General::readhasharray($CUSTOMLISTS_CONF, =
\%lists_conf);
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> + # Get list options, enabled by default to =
start import
>>>>>>>>>>>>>>>>>>>>>>>> + $customlists{'allow'}{'enabled'} =3D =
$lists_conf{2}[0] // 'on';
>>>>>>>>>>>>>>>>>>>>>>>> + $customlists{'block'}{'enabled'} =3D =
$lists_conf{2}[1] // 'on';
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> + # Import enabled list from rpz-config, =
otherwise retrieve stored or empty list from configuration file
>>>>>>>>>>>>>>>>>>>>>>>> + if($customlists{'allow'}{'enabled'} eq 'on') =
{
>>>>>>>>>>>>>>>>>>>>>>>> + &_customlist_import('allow', $RPZ_ALLOWLIST);
>>>>>>>>>>>>>>>>>>>>>>>> + } else {
>>>>>>>>>>>>>>>>>>>>>>>> + $customlists{'allow'}{'list'} =3D =
$lists_conf{0} // [];
>>>>>>>>>>>>>>>>>>>>>>>> + }
>>>>>>>>>>>>>>>>>>>>>>>> + if($customlists{'block'}{'enabled'} eq 'on') =
{
>>>>>>>>>>>>>>>>>>>>>>>> + &_customlist_import('block', $RPZ_BLOCKLIST);
>>>>>>>>>>>>>>>>>>>>>>>> + } else {
>>>>>>>>>>>>>>>>>>>>>>>> + $customlists{'block'}{'list'} =3D =
$lists_conf{1} // [];
>>>>>>>>>>>>>>>>>>>>>>>> + }
>>>>>>>>>>>>>>>>>>>>>>>> +}
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +# Save internal custom lists configuration
>>>>>>>>>>>>>>>>>>>>>>>> +sub _customlists_save_conf {
>>>>>>>>>>>>>>>>>>>>>>>> + my %export =3D ();
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> + # Match IDs with import function
>>>>>>>>>>>>>>>>>>>>>>>> + $export{0} =3D $customlists{'allow'}{'list'};
>>>>>>>>>>>>>>>>>>>>>>>> + $export{1} =3D $customlists{'block'}{'list'};
>>>>>>>>>>>>>>>>>>>>>>>> + $export{2} =3D =
[$customlists{'allow'}{'enabled'}, $customlists{'block'}{'enabled'}];
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> + &General::writehasharray($CUSTOMLISTS_CONF, =
\%export);
>>>>>>>>>>>>>>>>>>>>>>>> +}
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +# Import a custom list from plain file, =
returns empty list if file is missing
>>>>>>>>>>>>>>>>>>>>>>>> +sub _customlist_import {
>>>>>>>>>>>>>>>>>>>>>>>> + my ($listname, $filename) =3D @_;
>>>>>>>>>>>>>>>>>>>>>>>> + my @list =3D ();
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> + # File exists, load and check all lines
>>>>>>>>>>>>>>>>>>>>>>>> + if(-f $filename) {
>>>>>>>>>>>>>>>>>>>>>>>> + open(my $FH, '<', $filename) or die "Can't =
read $filename: $!";
>>>>>>>>>>>>>>>>>>>>>>>> + while(my $line =3D <$FH>) {
>>>>>>>>>>>>>>>>>>>>>>>> + chomp($line);
>>>>>>>>>>>>>>>>>>>>>>>> + push(@list, $line);
>>>>>>>>>>>>>>>>>>>>>>>> + }
>>>>>>>>>>>>>>>>>>>>>>>> + close($FH);
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> + # Clean up imported data
>>>>>>>>>>>>>>>>>>>>>>>> + &_rpz_validate_customlist(\@list, 1);
>>>>>>>>>>>>>>>>>>>>>>>> + }
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> + $customlists{$listname}{'list'} =3D \@list;
>>>>>>>>>>>>>>>>>>>>>>>> +}
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +# Export a custom list to plain file or clear =
file if list is disabled
>>>>>>>>>>>>>>>>>>>>>>>> +sub _customlist_export {
>>>>>>>>>>>>>>>>>>>>>>>> + my ($listname, $filename) =3D @_;
>>>>>>>>>>>>>>>>>>>>>>>> + return unless(defined =
$customlists{$listname});
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> + # Write enabled domain list to file, =
otherwise save empty file
>>>>>>>>>>>>>>>>>>>>>>>> + open(my $FH, '>', $filename) or die "Can't =
write $filename: $!";
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> + if($customlists{$listname}{'enabled'} eq =
'on') {
>>>>>>>>>>>>>>>>>>>>>>>> + foreach my $line =
(@{$customlists{$listname}{'list'}}) {
>>>>>>>>>>>>>>>>>>>>>>>> + print $FH "$line\n";
>>>>>>>>>>>>>>>>>>>>>>>> + }
>>>>>>>>>>>>>>>>>>>>>>>> + } else {
>>>>>>>>>>>>>>>>>>>>>>>> + print $FH "; Note: This list is currently =
disabled by $ENV{'SCRIPT_NAME'}\n";
>>>>>>>>>>>>>>>>>>>>>>>> + }
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> + close($FH);
>>>>>>>>>>>>>>>>>>>>>>>> +}
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +###--- Internal gui functions ---###
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +# Show simple message box
>>>>>>>>>>>>>>>>>>>>>>>> +sub _print_message {
>>>>>>>>>>>>>>>>>>>>>>>> + my ($message, $title) =3D @_;
>>>>>>>>>>>>>>>>>>>>>>>> + $title ||=3D $Lang::tr{'error messages'};
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> + &Header::openbox('100%', 'left', $title);
>>>>>>>>>>>>>>>>>>>>>>>> + print "<span>$message</span>";
>>>>>>>>>>>>>>>>>>>>>>>> + &Header::closebox();
>>>>>>>>>>>>>>>>>>>>>>>> +}
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +# Show all zone files and related gui elements
>>>>>>>>>>>>>>>>>>>>>>>> +sub _print_zonefiles {
>>>>>>>>>>>>>>>>>>>>>>>> + &Header::openbox('100%', 'left', =
$Lang::tr{'rpz zf'});
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> + print <<END
>>>>>>>>>>>>>>>>>>>>>>>> +<table class=3D"tbl" width=3D"100%">
>>>>>>>>>>>>>>>>>>>>>>>> + <tr>
>>>>>>>>>>>>>>>>>>>>>>>> + <th>$Lang::tr{'name'}</th>
>>>>>>>>>>>>>>>>>>>>>>>> + <th>URL</th>
>>>>>>>>>>>>>>>>>>>>>>>> + <th>$Lang::tr{'remark'}</th>
>>>>>>>>>>>>>>>>>>>>>>>> + <th colspan=3D"3">$Lang::tr{'action'}</th>
>>>>>>>>>>>>>>>>>>>>>>>> + </tr>
>>>>>>>>>>>>>>>>>>>>>>>> +END
>>>>>>>>>>>>>>>>>>>>>>>> +;
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> + # Sort zonefiles by name and loop trough all =
entries
>>>>>>>>>>>>>>>>>>>>>>>> + foreach my $name (sort keys %zonefiles) {
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> + # Toggle button label translation
>>>>>>>>>>>>>>>>>>>>>>>> + my $toggle_tr =3D =
($zonefiles{$name}{'enabled'} eq 'on') ? $Lang::tr{'click to disable'} : =
$Lang::tr{'click to enable'};
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> + print <<END
>>>>>>>>>>>>>>>>>>>>>>>> + <tr>
>>>>>>>>>>>>>>>>>>>>>>>> + <td>$name</td>
>>>>>>>>>>>>>>>>>>>>>>>> + <td>$zonefiles{$name}{'url'}</td>
>>>>>>>>>>>>>>>>>>>>>>>> + <td>$zonefiles{$name}{'remark'}</td>
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> + <td align=3D"center" width=3D"5%">
>>>>>>>>>>>>>>>>>>>>>>>> + <form method=3D"post" =
action=3D"$ENV{'SCRIPT_NAME'}">
>>>>>>>>>>>>>>>>>>>>>>>> + <input type=3D"hidden" name=3D"KEY" =
value=3D"$name">
>>>>>>>>>>>>>>>>>>>>>>>> + <input type=3D"hidden" name=3D"ACTION" =
value=3D"ZF_TOGGLE">
>>>>>>>>>>>>>>>>>>>>>>>> + <input type=3D"image" =
src=3D"/images/$zonefiles{$name}{'enabled'}.gif" title=3D"$toggle_tr" =
alt=3D"$toggle_tr">
>>>>>>>>>>>>>>>>>>>>>>>> + </form>
>>>>>>>>>>>>>>>>>>>>>>>> + </td>
>>>>>>>>>>>>>>>>>>>>>>>> + <td align=3D"center" width=3D"5%">
>>>>>>>>>>>>>>>>>>>>>>>> + <form method=3D"post" =
action=3D"$ENV{'SCRIPT_NAME'}">
>>>>>>>>>>>>>>>>>>>>>>>> + <input type=3D"hidden" name=3D"KEY" =
value=3D"$name">
>>>>>>>>>>>>>>>>>>>>>>>> + <input type=3D"hidden" name=3D"ACTION" =
value=3D"ZF_EDIT">
>>>>>>>>>>>>>>>>>>>>>>>> + <input type=3D"image" src=3D"/images/edit.gif" =
title=3D"$Lang::tr{'edit'}" alt=3D"$Lang::tr{'edit'}">
>>>>>>>>>>>>>>>>>>>>>>>> + </form>
>>>>>>>>>>>>>>>>>>>>>>>> + </td>
>>>>>>>>>>>>>>>>>>>>>>>> + <td align=3D"center" width=3D"5%">
>>>>>>>>>>>>>>>>>>>>>>>> + <form method=3D"post" =
action=3D"$ENV{'SCRIPT_NAME'}">
>>>>>>>>>>>>>>>>>>>>>>>> + <input type=3D"hidden" name=3D"KEY" =
value=3D"$name">
>>>>>>>>>>>>>>>>>>>>>>>> + <input type=3D"hidden" name=3D"ACTION" =
value=3D"ZF_REMOVE">
>>>>>>>>>>>>>>>>>>>>>>>> + <input type=3D"image" =
src=3D"/images/delete.gif" title=3D"$Lang::tr{'remove'}" =
alt=3D"$Lang::tr{'remove'}">
>>>>>>>>>>>>>>>>>>>>>>>> + </form>
>>>>>>>>>>>>>>>>>>>>>>>> + </td>
>>>>>>>>>>>>>>>>>>>>>>>> + </tr>
>>>>>>>>>>>>>>>>>>>>>>>> +END
>>>>>>>>>>>>>>>>>>>>>>>> +;
>>>>>>>>>>>>>>>>>>>>>>>> + }
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> + # Disable reload button if not needed
>>>>>>>>>>>>>>>>>>>>>>>> + my $reload_state =3D &_rpz_needs_reload() ? =
"" : " disabled";
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> + print <<END
>>>>>>>>>>>>>>>>>>>>>>>> +</table>
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +<div class=3D"right">
>>>>>>>>>>>>>>>>>>>>>>>> + <form method=3D"post" =
action=3D"$ENV{'SCRIPT_NAME'}">
>>>>>>>>>>>>>>>>>>>>>>>> + <input type=3D"hidden" name=3D"KEY" value=3D"">=

>>>>>>>>>>>>>>>>>>>>>>>> + <button type=3D"submit" name=3D"ACTION" =
value=3D"ZF_EDIT">$Lang::tr{'add'}</button>
>>>>>>>>>>>>>>>>>>>>>>>> + <button type=3D"submit" name=3D"ACTION" =
value=3D"RPZ_RELOAD" class=3D"commit"$reload_state>$Lang::tr{'rpz =
apply'}</button>
>>>>>>>>>>>>>>>>>>>>>>>> + </form>
>>>>>>>>>>>>>>>>>>>>>>>> +</div>
>>>>>>>>>>>>>>>>>>>>>>>> +END
>>>>>>>>>>>>>>>>>>>>>>>> +;
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> + &Header::closebox();
>>>>>>>>>>>>>>>>>>>>>>>> +}
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +# Show zonefiles entry editor
>>>>>>>>>>>>>>>>>>>>>>>> +sub _print_zonefile_editor {
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> + # Key specified: Edit existing entry
>>>>>>>>>>>>>>>>>>>>>>>> + if(($action_key) && (defined =
$zonefiles{$action_key})) {
>>>>>>>>>>>>>>>>>>>>>>>> + # Load data to be edited, but don't override =
already present values (allows user to edit after error)
>>>>>>>>>>>>>>>>>>>>>>>> + $cgiparams{'ZF_NAME'} //=3D $action_key;
>>>>>>>>>>>>>>>>>>>>>>>> + $cgiparams{'ZF_URL'} //=3D =
$zonefiles{$action_key}{'url'};
>>>>>>>>>>>>>>>>>>>>>>>> + $cgiparams{'ZF_REMARK'} //=3D =
$zonefiles{$action_key}{'remark'};
>>>>>>>>>>>>>>>>>>>>>>>> + }
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> + # Fallback to empty form
>>>>>>>>>>>>>>>>>>>>>>>> + $cgiparams{'ZF_NAME'} //=3D "";
>>>>>>>>>>>>>>>>>>>>>>>> + $cgiparams{'ZF_URL'} //=3D "";
>>>>>>>>>>>>>>>>>>>>>>>> + $cgiparams{'ZF_REMARK'} //=3D "";
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> + &Header::openbox('100%', 'left', =
$Lang::tr{'rpz zf editor'});
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> + print <<END
>>>>>>>>>>>>>>>>>>>>>>>> +<form method=3D"post" =
action=3D"$ENV{'SCRIPT_NAME'}">
>>>>>>>>>>>>>>>>>>>>>>>> +<input type=3D"hidden" name=3D"KEY" =
value=3D"$action_key">
>>>>>>>>>>>>>>>>>>>>>>>> +<table width=3D"100%">
>>>>>>>>>>>>>>>>>>>>>>>> + <tr>
>>>>>>>>>>>>>>>>>>>>>>>> + <td width=3D"20%">$Lang::tr{'name'}:&nbsp;<img =
src=3D"/blob.gif" alt=3D"*"></td>
>>>>>>>>>>>>>>>>>>>>>>>> + <td><input type=3D"text" name=3D"ZF_NAME" =
value=3D"$cgiparams{'ZF_NAME'}" size=3D"40" maxlength=3D"32" =
title=3D"$Lang::tr{'rpz zf remark info'}" pattern=3D"[a-zA-Z0-9_]{1,32}" =
required></td>
>>>>>>>>>>>>>>>>>>>>>>>> + </tr>
>>>>>>>>>>>>>>>>>>>>>>>> + <tr>
>>>>>>>>>>>>>>>>>>>>>>>> + <td width=3D"20%">URL:&nbsp;<img =
src=3D"/blob.gif" alt=3D"*"></td>
>>>>>>>>>>>>>>>>>>>>>>>> + <td><input type=3D"url" name=3D"ZF_URL" =
value=3D"$cgiparams{'ZF_URL'}" size=3D"40" maxlength=3D"128" =
required></td>
>>>>>>>>>>>>>>>>>>>>>>>> + </tr>
>>>>>>>>>>>>>>>>>>>>>>>> + <tr>
>>>>>>>>>>>>>>>>>>>>>>>> + <td width=3D"20%">$Lang::tr{'remark'}:</td>
>>>>>>>>>>>>>>>>>>>>>>>> + <td><input type=3D"text" name=3D"ZF_REMARK" =
value=3D"$cgiparams{'ZF_REMARK'}" size=3D"40" maxlength=3D"32"></td>
>>>>>>>>>>>>>>>>>>>>>>>> + </tr>
>>>>>>>>>>>>>>>>>>>>>>>> + <tr>
>>>>>>>>>>>>>>>>>>>>>>>> + <td colspan=3D"2"><hr></td>
>>>>>>>>>>>>>>>>>>>>>>>> + </tr>
>>>>>>>>>>>>>>>>>>>>>>>> + <tr>
>>>>>>>>>>>>>>>>>>>>>>>> + <td width=3D"55%"><img src=3D"/blob.gif" =
alt=3D"*">&nbsp;$Lang::tr{'required field'}</td>
>>>>>>>>>>>>>>>>>>>>>>>> + <td align=3D"right"><button type=3D"submit" =
name=3D"ACTION" value=3D"ZF_SAVE">$Lang::tr{'save'}</button></td>
>>>>>>>>>>>>>>>>>>>>>>>> + </tr>
>>>>>>>>>>>>>>>>>>>>>>>> +</table>
>>>>>>>>>>>>>>>>>>>>>>>> +</form>
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +<div class=3D"right">
>>>>>>>>>>>>>>>>>>>>>>>> + <form method=3D"post" =
action=3D"$ENV{'SCRIPT_NAME'}">
>>>>>>>>>>>>>>>>>>>>>>>> + <button type=3D"submit" name=3D"ACTION" =
value=3D"NONE">$Lang::tr{'back'}</button>
>>>>>>>>>>>>>>>>>>>>>>>> + </form>
>>>>>>>>>>>>>>>>>>>>>>>> +</div>
>>>>>>>>>>>>>>>>>>>>>>>> +END
>>>>>>>>>>>>>>>>>>>>>>>> +;
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> + &Header::closebox();
>>>>>>>>>>>>>>>>>>>>>>>> +}
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +# Show custom allow/block files and related =
gui elements
>>>>>>>>>>>>>>>>>>>>>>>> +sub _print_customlists {
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> + # Load lists from config, unless they are =
currently being edited
>>>>>>>>>>>>>>>>>>>>>>>> + if($action ne 'CL_SAVE') {
>>>>>>>>>>>>>>>>>>>>>>>> + $cgiparams{'ALLOW_LIST'} =3D join("\n", =
@{$customlists{'allow'}{'list'}});
>>>>>>>>>>>>>>>>>>>>>>>> + $cgiparams{'BLOCK_LIST'} =3D join("\n", =
@{$customlists{'block'}{'list'}});
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> + $cgiparams{'ALLOW_ENABLED'} =3D =
($customlists{'allow'}{'enabled'} eq 'on') ? 'on' : undef;
>>>>>>>>>>>>>>>>>>>>>>>> + $cgiparams{'BLOCK_ENABLED'} =3D =
($customlists{'block'}{'enabled'} eq 'on') ? 'on' : undef;
>>>>>>>>>>>>>>>>>>>>>>>> + }
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> + # Fallback to empty form
>>>>>>>>>>>>>>>>>>>>>>>> + $cgiparams{'ALLOW_LIST'} //=3D "";
>>>>>>>>>>>>>>>>>>>>>>>> + $cgiparams{'BLOCK_LIST'} //=3D "";
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> + # HTML checkboxes, unchecked =3D no or undef =
value in POST data
>>>>>>>>>>>>>>>>>>>>>>>> + my %checked =3D ();
>>>>>>>>>>>>>>>>>>>>>>>> + $checked{'ALLOW_ENABLED'} =3D (defined =
$cgiparams{'ALLOW_ENABLED'}) ? " checked" : "";
>>>>>>>>>>>>>>>>>>>>>>>> + $checked{'BLOCK_ENABLED'} =3D (defined =
$cgiparams{'BLOCK_ENABLED'}) ? " checked" : "";
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> + # Disable reload button if not needed
>>>>>>>>>>>>>>>>>>>>>>>> + my $reload_state =3D &_rpz_needs_reload() ? =
"" : " disabled";
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> + &Header::openbox('100%', 'left', =
$Lang::tr{'rpz cl'});
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> + print <<END
>>>>>>>>>>>>>>>>>>>>>>>> +<form method=3D"post" =
action=3D"$ENV{'SCRIPT_NAME'}">
>>>>>>>>>>>>>>>>>>>>>>>> +<table width=3D"100%">
>>>>>>>>>>>>>>>>>>>>>>>> + <tr>
>>>>>>>>>>>>>>>>>>>>>>>> + <td colspan=3D"2"><b>$Lang::tr{'rpz cl =
allow'}</b><br>$Lang::tr{'rpz cl allow info'}</td>
>>>>>>>>>>>>>>>>>>>>>>>> + <td colspan=3D"2"><b>$Lang::tr{'rpz cl =
block'}</b><br>$Lang::tr{'rpz cl block info'}</td>
>>>>>>>>>>>>>>>>>>>>>>>> + </tr>
>>>>>>>>>>>>>>>>>>>>>>>> + <tr>
>>>>>>>>>>>>>>>>>>>>>>>> + <td colspan=3D"2"><textarea name=3D"ALLOW_LIST"=
 class=3D"domainlist" cols=3D"45">
>>>>>>>>>>>>>>>>>>>>>>>> +$cgiparams{'ALLOW_LIST'}</textarea></td>
>>>>>>>>>>>>>>>>>>>>>>>> + <td colspan=3D"2"><textarea name=3D"BLOCK_LIST"=
 class=3D"domainlist" cols=3D"45">
>>>>>>>>>>>>>>>>>>>>>>>> +$cgiparams{'BLOCK_LIST'}</textarea></td>
>>>>>>>>>>>>>>>>>>>>>>>> + </tr>
>>>>>>>>>>>>>>>>>>>>>>>> + <tr>
>>>>>>>>>>>>>>>>>>>>>>>> + <td><label for=3D"allow_enabled">$Lang::tr{'rpz=
 cl allow enable'}</label></td>
>>>>>>>>>>>>>>>>>>>>>>>> + <td width=3D"15%"><input type=3D"checkbox" =
name=3D"ALLOW_ENABLED" id=3D"allow_enabled"$checked{'ALLOW_ENABLED'}></td>=

>>>>>>>>>>>>>>>>>>>>>>>> + <td><label for=3D"block_enabled">$Lang::tr{'rpz=
 cl block enable'}</label></td>
>>>>>>>>>>>>>>>>>>>>>>>> + <td width=3D"15%"><input type=3D"checkbox" =
name=3D"BLOCK_ENABLED" id=3D"block_enabled"$checked{'BLOCK_ENABLED'}></td>=

>>>>>>>>>>>>>>>>>>>>>>>> + </tr>
>>>>>>>>>>>>>>>>>>>>>>>> + <tr>
>>>>>>>>>>>>>>>>>>>>>>>> + <td colspan=3D"4"><hr></td>
>>>>>>>>>>>>>>>>>>>>>>>> + </tr>
>>>>>>>>>>>>>>>>>>>>>>>> + <tr>
>>>>>>>>>>>>>>>>>>>>>>>> + <td align=3D"right" colspan=3D"4">
>>>>>>>>>>>>>>>>>>>>>>>> + <button type=3D"submit" name=3D"ACTION" =
value=3D"CL_SAVE">$Lang::tr{'save'}</button>
>>>>>>>>>>>>>>>>>>>>>>>> + <button type=3D"submit" name=3D"ACTION" =
value=3D"RPZ_RELOAD" class=3D"commit"$reload_state>$Lang::tr{'rpz =
apply'}</button>
>>>>>>>>>>>>>>>>>>>>>>>> + </td>
>>>>>>>>>>>>>>>>>>>>>>>> +</table>
>>>>>>>>>>>>>>>>>>>>>>>> +</form>
>>>>>>>>>>>>>>>>>>>>>>>> +END
>>>>>>>>>>>>>>>>>>>>>>>> +;
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> + &Header::closebox();
>>>>>>>>>>>>>>>>>>>>>>>> +}
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +# Output javascript and extra gui elements
>>>>>>>>>>>>>>>>>>>>>>>> +sub _print_gui_extras {
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> + # Apply/Restart button modifier key handler
>>>>>>>>>>>>>>>>>>>>>>>> + if(&_rpz_needs_reload()) {
>>>>>>>>>>>>>>>>>>>>>>>> + print <<END
>>>>>>>>>>>>>>>>>>>>>>>> +<script>
>>>>>>>>>>>>>>>>>>>>>>>> + // Commit modifier key handler
>>>>>>>>>>>>>>>>>>>>>>>> + (function(jq, document) {
>>>>>>>>>>>>>>>>>>>>>>>> + var keyEventsOn =3D false; // Keyboard events =
attached
>>>>>>>>>>>>>>>>>>>>>>>> + var keyModify =3D false; // Modifier key =
pressed
>>>>>>>>>>>>>>>>>>>>>>>> + var mouseHover =3D false; // Mouse over =
commit button
>>>>>>>>>>>>>>>>>>>>>>>> + var btnModified =3D false; // Button modified =
to "Restart"
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> + // Document-level key events, enable only =
while cursor is over button
>>>>>>>>>>>>>>>>>>>>>>>> + function attachKeyEvents() {
>>>>>>>>>>>>>>>>>>>>>>>> + if(keyEventsOn) {
>>>>>>>>>>>>>>>>>>>>>>>> + return;
>>>>>>>>>>>>>>>>>>>>>>>> + }
>>>>>>>>>>>>>>>>>>>>>>>> + keyEventsOn =3D true;
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> + jq(document).on("keydown.rpz", =
function(event) {
>>>>>>>>>>>>>>>>>>>>>>>> + if((!keyModify) && event.shiftKey) {
>>>>>>>>>>>>>>>>>>>>>>>> + keyModify =3D true;
>>>>>>>>>>>>>>>>>>>>>>>> + handleModify();
>>>>>>>>>>>>>>>>>>>>>>>> + }
>>>>>>>>>>>>>>>>>>>>>>>> + });
>>>>>>>>>>>>>>>>>>>>>>>> + jq(document).on("keyup.rpz", function(event) =
{
>>>>>>>>>>>>>>>>>>>>>>>> + if(keyModify && (!event.shiftKey)) {
>>>>>>>>>>>>>>>>>>>>>>>> + keyModify =3D false;
>>>>>>>>>>>>>>>>>>>>>>>> + handleModify();
>>>>>>>>>>>>>>>>>>>>>>>> + }
>>>>>>>>>>>>>>>>>>>>>>>> + });
>>>>>>>>>>>>>>>>>>>>>>>> + }
>>>>>>>>>>>>>>>>>>>>>>>> + function removeKeyEvents() {
>>>>>>>>>>>>>>>>>>>>>>>> + keyModify =3D false;
>>>>>>>>>>>>>>>>>>>>>>>> + if(keyEventsOn) {
>>>>>>>>>>>>>>>>>>>>>>>> + jq(document).off("keydown.rpz keyup.rpz");
>>>>>>>>>>>>>>>>>>>>>>>> + keyEventsOn =3D false;
>>>>>>>>>>>>>>>>>>>>>>>> + }
>>>>>>>>>>>>>>>>>>>>>>>> + }
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> + // Attach mouse hover events to commit =
buttons
>>>>>>>>>>>>>>>>>>>>>>>> + function attachMouseEvents() {
>>>>>>>>>>>>>>>>>>>>>>>> + jq("button.commit").on("mouseenter", =
function(event) {
>>>>>>>>>>>>>>>>>>>>>>>> + if(!mouseHover) {
>>>>>>>>>>>>>>>>>>>>>>>> + mouseHover =3D true;
>>>>>>>>>>>>>>>>>>>>>>>> + attachKeyEvents();
>>>>>>>>>>>>>>>>>>>>>>>> + // Handle already pressed key
>>>>>>>>>>>>>>>>>>>>>>>> + keyModify =3D !!(event.shiftKey);
>>>>>>>>>>>>>>>>>>>>>>>> + handleModify();
>>>>>>>>>>>>>>>>>>>>>>>> + }
>>>>>>>>>>>>>>>>>>>>>>>> + });
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> + // Cursor moved away: Disable key listener to =
minimize events
>>>>>>>>>>>>>>>>>>>>>>>> + jq("button.commit").on("mouseleave", =
function() {
>>>>>>>>>>>>>>>>>>>>>>>> + if(mouseHover) {
>>>>>>>>>>>>>>>>>>>>>>>> + mouseHover =3D false;
>>>>>>>>>>>>>>>>>>>>>>>> + removeKeyEvents();
>>>>>>>>>>>>>>>>>>>>>>>> + handleModify();
>>>>>>>>>>>>>>>>>>>>>>>> + }
>>>>>>>>>>>>>>>>>>>>>>>> + });
>>>>>>>>>>>>>>>>>>>>>>>> + }
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> + // Modify commit button
>>>>>>>>>>>>>>>>>>>>>>>> + function handleModify() {
>>>>>>>>>>>>>>>>>>>>>>>> + let modify =3D mouseHover && keyModify;
>>>>>>>>>>>>>>>>>>>>>>>> + if(btnModified !=3D modify) {
>>>>>>>>>>>>>>>>>>>>>>>> + if(modify) {
>>>>>>>>>>>>>>>>>>>>>>>> + =
jq("button.commit").text("$Lang::tr{'restart'}").val("UNB_RESTART");
>>>>>>>>>>>>>>>>>>>>>>>> + } else {
>>>>>>>>>>>>>>>>>>>>>>>> + jq("button.commit").text("$Lang::tr{'rpz =
apply'}").val("RPZ_RELOAD");
>>>>>>>>>>>>>>>>>>>>>>>> + }
>>>>>>>>>>>>>>>>>>>>>>>> + btnModified =3D modify;
>>>>>>>>>>>>>>>>>>>>>>>> + }
>>>>>>>>>>>>>>>>>>>>>>>> + }
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> + // jQuery DOM ready
>>>>>>>>>>>>>>>>>>>>>>>> + jq(function() {
>>>>>>>>>>>>>>>>>>>>>>>> + attachMouseEvents();
>>>>>>>>>>>>>>>>>>>>>>>> + });
>>>>>>>>>>>>>>>>>>>>>>>> + })(jQuery, document);
>>>>>>>>>>>>>>>>>>>>>>>> +</script>
>>>>>>>>>>>>>>>>>>>>>>>> +END
>>>>>>>>>>>>>>>>>>>>>>>> +;
>>>>>>>>>>>>>>>>>>>>>>>> + } # End of modifier key handler
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +}
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +###--- Internal action processing functions =
---###
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +# Toggle zonefile on/off
>>>>>>>>>>>>>>>>>>>>>>>> +sub _action_zf_toggle {
>>>>>>>>>>>>>>>>>>>>>>>> + return unless(defined =
$zonefiles{$action_key});
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> + my $result =3D 0;
>>>>>>>>>>>>>>>>>>>>>>>> + my $enabled =3D =
$zonefiles{$action_key}{'enabled'};
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> + # Perform toggle action
>>>>>>>>>>>>>>>>>>>>>>>> + if($enabled eq 'on') {
>>>>>>>>>>>>>>>>>>>>>>>> + $enabled =3D 'off';
>>>>>>>>>>>>>>>>>>>>>>>> + $result =3D =
&General::system('/usr/sbin/rpz-config', 'remove', $action_key, =
'--no-reload');
>>>>>>>>>>>>>>>>>>>>>>>> + } else {
>>>>>>>>>>>>>>>>>>>>>>>> + $enabled =3D 'on';
>>>>>>>>>>>>>>>>>>>>>>>> + $result =3D =
&General::system('/usr/sbin/rpz-config', 'add', $action_key, =
$zonefiles{$action_key}{'url'}, '--no-reload');
>>>>>>>>>>>>>>>>>>>>>>>> + }
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> + # Check for errors, request service reload on =
success
>>>>>>>>>>>>>>>>>>>>>>>> + return unless &_rpz_check_result($result, 1);
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> + # Save changes
>>>>>>>>>>>>>>>>>>>>>>>> + $zonefiles{$action_key}{'enabled'} =3D =
$enabled;
>>>>>>>>>>>>>>>>>>>>>>>> + &_zonefiles_save_conf();
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> + return 1;
>>>>>>>>>>>>>>>>>>>>>>>> +}
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +# Remove zonefile
>>>>>>>>>>>>>>>>>>>>>>>> +sub _action_zf_remove {
>>>>>>>>>>>>>>>>>>>>>>>> + return unless(defined =
$zonefiles{$action_key});
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> + # Remove from rpz-config if currently active
>>>>>>>>>>>>>>>>>>>>>>>> + if($zonefiles{$action_key}{'enabled'} eq =
'on') {
>>>>>>>>>>>>>>>>>>>>>>>> + my $result =3D =
&General::system('/usr/sbin/rpz-config', 'remove', $action_key, =
'--no-reload');
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> + # Check for errors, request service reload on =
success
>>>>>>>>>>>>>>>>>>>>>>>> + return unless &_rpz_check_result($result, 1);
>>>>>>>>>>>>>>>>>>>>>>>> + }
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> + # Remove from data hash and save changes
>>>>>>>>>>>>>>>>>>>>>>>> + delete $zonefiles{$action_key};
>>>>>>>>>>>>>>>>>>>>>>>> + &_zonefiles_save_conf();
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> + # Clear action_key, as the entry is now =
removed entirely
>>>>>>>>>>>>>>>>>>>>>>>> + $action_key =3D "";
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> + return 1;
>>>>>>>>>>>>>>>>>>>>>>>> +}
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +# Create or update zonefile entry
>>>>>>>>>>>>>>>>>>>>>>>> +# Returns undef if gui needs to stay in editor =
mode
>>>>>>>>>>>>>>>>>>>>>>>> +sub _action_zf_save {
>>>>>>>>>>>>>>>>>>>>>>>> + my $result =3D 0;
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> + my $name =3D $cgiparams{'ZF_NAME'} // "";
>>>>>>>>>>>>>>>>>>>>>>>> + my $url =3D $cgiparams{'ZF_URL'} // "";
>>>>>>>>>>>>>>>>>>>>>>>> + my $remark =3D $cgiparams{'ZF_REMARK'} // "";
>>>>>>>>>>>>>>>>>>>>>>>> + my $enabled =3D 'on'; # Enable new entries by =
default
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> + # Note on variables:
>>>>>>>>>>>>>>>>>>>>>>>> + # name =3D unique key, will be used to =
address the entry
>>>>>>>>>>>>>>>>>>>>>>>> + # action_key =3D name of the entry being =
edited, empty for new entry
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> + # Only check for unique name if it changed
>>>>>>>>>>>>>>>>>>>>>>>> + # (this also checks new entries because the =
action_key is empty in this case)
>>>>>>>>>>>>>>>>>>>>>>>> + $result =3D &_rpz_validate_zonefile($name, =
$url, $remark, (lc($name) ne lc($action_key)));
>>>>>>>>>>>>>>>>>>>>>>>> + return unless &_rpz_check_result($result, 0);
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> + # Edit existing entry: Determine what was =
changed
>>>>>>>>>>>>>>>>>>>>>>>> + if(($action_key) && (defined =
$zonefiles{$action_key})) {
>>>>>>>>>>>>>>>>>>>>>>>> + # Name und URL remain unchanged, only save =
remark and finish
>>>>>>>>>>>>>>>>>>>>>>>> + if(($name eq $action_key) && ($url eq =
$zonefiles{$action_key}{'url'})) {
>>>>>>>>>>>>>>>>>>>>>>>> + $zonefiles{$action_key}{'remark'} =3D =
$remark;
>>>>>>>>>>>>>>>>>>>>>>>> + &_zonefiles_save_conf();
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> + return 1;
>>>>>>>>>>>>>>>>>>>>>>>> + }
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> + # Entry was changed and needs to be =
recreated, preserve status
>>>>>>>>>>>>>>>>>>>>>>>> + $enabled =3D =
$zonefiles{$action_key}{'enabled'};
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> + # Remove from rpz-config
>>>>>>>>>>>>>>>>>>>>>>>> + return unless &_action_zf_remove();
>>>>>>>>>>>>>>>>>>>>>>>> + }
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> + # Add new entry to rpz-config
>>>>>>>>>>>>>>>>>>>>>>>> + if($enabled eq 'on') {
>>>>>>>>>>>>>>>>>>>>>>>> + $result =3D =
&General::system('/usr/sbin/rpz-config', 'add', $name, $url, =
'--no-reload');
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> + # Check for errors, request service reload on =
success
>>>>>>>>>>>>>>>>>>>>>>>> + return unless &_rpz_check_result($result, 1);
>>>>>>>>>>>>>>>>>>>>>>>> + }
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> + # Add to global data hash and save changes
>>>>>>>>>>>>>>>>>>>>>>>> + my %entry =3D ('enabled' =3D> $enabled,
>>>>>>>>>>>>>>>>>>>>>>>> + 'url' =3D> $url,
>>>>>>>>>>>>>>>>>>>>>>>> + 'remark' =3D> $remark);
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> + $zonefiles{$name} =3D \%entry;
>>>>>>>>>>>>>>>>>>>>>>>> + &_zonefiles_save_conf();
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> + return 1;
>>>>>>>>>>>>>>>>>>>>>>>> +}
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +# Save custom lists
>>>>>>>>>>>>>>>>>>>>>>>> +sub _action_cl_save {
>>>>>>>>>>>>>>>>>>>>>>>> + return unless((defined =
$cgiparams{'ALLOW_LIST'}) && (defined $cgiparams{'BLOCK_LIST'}));
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> + my $result =3D 0;
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> + my @allowlist =3D split(/\R/, =
$cgiparams{'ALLOW_LIST'});
>>>>>>>>>>>>>>>>>>>>>>>> + my @blocklist =3D split(/\R/, =
$cgiparams{'BLOCK_LIST'});
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> + # Validate lists
>>>>>>>>>>>>>>>>>>>>>>>> + $result =3D =
&_rpz_validate_customlist(\@allowlist);
>>>>>>>>>>>>>>>>>>>>>>>> + if($result !=3D 0) {
>>>>>>>>>>>>>>>>>>>>>>>> + $errormessage =3D &_rpz_error_tr(202, =
$result);
>>>>>>>>>>>>>>>>>>>>>>>> + return;
>>>>>>>>>>>>>>>>>>>>>>>> + }
>>>>>>>>>>>>>>>>>>>>>>>> + $result =3D =
&_rpz_validate_customlist(\@blocklist);
>>>>>>>>>>>>>>>>>>>>>>>> + if($result !=3D 0) {
>>>>>>>>>>>>>>>>>>>>>>>> + $errormessage =3D &_rpz_error_tr(203, =
$result);
>>>>>>>>>>>>>>>>>>>>>>>> + return;
>>>>>>>>>>>>>>>>>>>>>>>> + }
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> + # Add to global data hash and save changes
>>>>>>>>>>>>>>>>>>>>>>>> + $customlists{'allow'}{'list'} =3D =
\@allowlist;
>>>>>>>>>>>>>>>>>>>>>>>> + $customlists{'block'}{'list'} =3D =
\@blocklist;
>>>>>>>>>>>>>>>>>>>>>>>> + $customlists{'allow'}{'enabled'} =3D (defined =
$cgiparams{'ALLOW_ENABLED'}) ? 'on' : 'off';
>>>>>>>>>>>>>>>>>>>>>>>> + $customlists{'block'}{'enabled'} =3D (defined =
$cgiparams{'BLOCK_ENABLED'}) ? 'on' : 'off';
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> + &_customlists_save_conf();
>>>>>>>>>>>>>>>>>>>>>>>> + &_customlist_export('allow', $RPZ_ALLOWLIST);
>>>>>>>>>>>>>>>>>>>>>>>> + &_customlist_export('block', $RPZ_BLOCKLIST);
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> + # Make new lists, request service reload on =
success
>>>>>>>>>>>>>>>>>>>>>>>> + $result =3D =
&General::system('/usr/sbin/rpz-make', 'allowblock', '--no-reload');
>>>>>>>>>>>>>>>>>>>>>>>> + return unless &_rpz_check_result($result, 1);
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> + return 1;
>>>>>>>>>>>>>>>>>>>>>>>> +}
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +# Trigger rpz-config reload
>>>>>>>>>>>>>>>>>>>>>>>> +sub _action_rpz_reload {
>>>>>>>>>>>>>>>>>>>>>>>> + return 1 unless &_rpz_needs_reload();
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> + # Immediately clear flag to prevent multiple =
reloads
>>>>>>>>>>>>>>>>>>>>>>>> + if(-f $RPZ_RELOAD_FLAG) {
>>>>>>>>>>>>>>>>>>>>>>>> + unlink($RPZ_RELOAD_FLAG) or die "Can't remove =
$RPZ_RELOAD_FLAG: $!";
>>>>>>>>>>>>>>>>>>>>>>>> + }
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> + # Perform reload, recreate reload flag on =
error to enable retry
>>>>>>>>>>>>>>>>>>>>>>>> + my $result =3D =
&General::system('/usr/sbin/rpz-config', 'reload');
>>>>>>>>>>>>>>>>>>>>>>>> + if(not &_rpz_check_result($result, 0)) {
>>>>>>>>>>>>>>>>>>>>>>>> + &General::system('touch', =
"$RPZ_RELOAD_FLAG");
>>>>>>>>>>>>>>>>>>>>>>>> + return;
>>>>>>>>>>>>>>>>>>>>>>>> + }
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> + return 1;
>>>>>>>>>>>>>>>>>>>>>>>> +}
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +# Trigger unbound restart
>>>>>>>>>>>>>>>>>>>>>>>> +sub _action_unb_restart {
>>>>>>>>>>>>>>>>>>>>>>>> + return 1 unless &_rpz_needs_reload();
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> + # Immediately clear flag to prevent multiple =
restarts
>>>>>>>>>>>>>>>>>>>>>>>> + if(-f $RPZ_RELOAD_FLAG) {
>>>>>>>>>>>>>>>>>>>>>>>> + unlink($RPZ_RELOAD_FLAG) or die "Can't remove =
$RPZ_RELOAD_FLAG: $!";
>>>>>>>>>>>>>>>>>>>>>>>> + }
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> + # Perform restart, unboundctrl always exits =
zero
>>>>>>>>>>>>>>>>>>>>>>>> + =
&General::system('/usr/local/bin/unboundctrl', 'restart');
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> + return 1;
>>>>>>>>>>>>>>>>>>>>>>>> +}
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +###--- Internal rpz-config functions ---###
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +# Translate rpz-config exitcodes and messages
>>>>>>>>>>>>>>>>>>>>>>>> +# 100-199: rpz-config, 200-299: webgui
>>>>>>>>>>>>>>>>>>>>>>>> +sub _rpz_error_tr {
>>>>>>>>>>>>>>>>>>>>>>>> + my ($error, $append) =3D @_;
>>>>>>>>>>>>>>>>>>>>>>>> + $append //=3D '';
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> + # Translate numeric exit codes
>>>>>>>>>>>>>>>>>>>>>>>> + if(looks_like_number($error)) {
>>>>>>>>>>>>>>>>>>>>>>>> + if(defined $Lang::tr{"rpz exitcode $error"}) =
{
>>>>>>>>>>>>>>>>>>>>>>>> + $error =3D $Lang::tr{"rpz exitcode $error"};
>>>>>>>>>>>>>>>>>>>>>>>> + }
>>>>>>>>>>>>>>>>>>>>>>>> + }
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> + return "RPZ $Lang::tr{'error'}: $error" . =
&Header::escape($append);
>>>>>>>>>>>>>>>>>>>>>>>> +}
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +# Check result of rpz-config system call, =
request reload on success
>>>>>>>>>>>>>>>>>>>>>>>> +sub _rpz_check_result {
>>>>>>>>>>>>>>>>>>>>>>>> + my ($result, $request_reload) =3D @_;
>>>>>>>>>>>>>>>>>>>>>>>> + $request_reload //=3D 0;
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> + # exitcode 0 =3D success
>>>>>>>>>>>>>>>>>>>>>>>> + if($result !=3D 0) {
>>>>>>>>>>>>>>>>>>>>>>>> + $errormessage =3D &_rpz_error_tr($result);
>>>>>>>>>>>>>>>>>>>>>>>> + return;
>>>>>>>>>>>>>>>>>>>>>>>> + }
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> + # Set reload flag
>>>>>>>>>>>>>>>>>>>>>>>> + if($request_reload) {
>>>>>>>>>>>>>>>>>>>>>>>> + &General::system('touch', =
"$RPZ_RELOAD_FLAG");
>>>>>>>>>>>>>>>>>>>>>>>> + }
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> + return 1;
>>>>>>>>>>>>>>>>>>>>>>>> +}
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +# Test whether reload flag is set
>>>>>>>>>>>>>>>>>>>>>>>> +sub _rpz_needs_reload {
>>>>>>>>>>>>>>>>>>>>>>>> + return (-f $RPZ_RELOAD_FLAG);
>>>>>>>>>>>>>>>>>>>>>>>> +}
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +# Validate a zonefile entry, returns =
rpz-config exitcode on failure. Use _rpz_check_result to verify.
>>>>>>>>>>>>>>>>>>>>>>>> +# unique =3D check for unique name
>>>>>>>>>>>>>>>>>>>>>>>> +sub _rpz_validate_zonefile {
>>>>>>>>>>>>>>>>>>>>>>>> + my ($name, $url, $remark, $unique) =3D @_;
>>>>>>>>>>>>>>>>>>>>>>>> + $unique //=3D 1;
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> + unless($name =3D~ /^[a-zA-Z0-9_]{1,32}$/) {
>>>>>>>>>>>>>>>>>>>>>>>> + return 101;
>>>>>>>>>>>>>>>>>>>>>>>> + }
>>>>>>>>>>>>>>>>>>>>>>>> + unless($url =3D~ =
/^[\w+\.:;\/\\&@#%?=3D\-~|!]{1,128}$/) {
>>>>>>>>>>>>>>>>>>>>>>>> + return 105;
>>>>>>>>>>>>>>>>>>>>>>>> + }
>>>>>>>>>>>>>>>>>>>>>>>> + unless($remark =3D~ /^[\w =
\-()\.:;*\/\\?!&=3D]{0,32}$/) {
>>>>>>>>>>>>>>>>>>>>>>>> + return 201;
>>>>>>>>>>>>>>>>>>>>>>>> + }
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> + # Check against already existing names
>>>>>>>>>>>>>>>>>>>>>>>> + if($unique) {
>>>>>>>>>>>>>>>>>>>>>>>> + foreach my $existing (keys %zonefiles) {
>>>>>>>>>>>>>>>>>>>>>>>> + if(lc($name) eq lc($existing)) {
>>>>>>>>>>>>>>>>>>>>>>>> + return 104;
>>>>>>>>>>>>>>>>>>>>>>>> + }
>>>>>>>>>>>>>>>>>>>>>>>> + }
>>>>>>>>>>>>>>>>>>>>>>>> + }
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> + return 0;
>>>>>>>>>>>>>>>>>>>>>>>> +}
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +# Validate a custom list, returns number of =
rejected line on failure. Check for non-zero results.
>>>>>>>>>>>>>>>>>>>>>>>> +# listref =3D array reference, cleanup =3D =
remove invalid entries instead of returning an error
>>>>>>>>>>>>>>>>>>>>>>>> +sub _rpz_validate_customlist {
>>>>>>>>>>>>>>>>>>>>>>>> + my ($listref, $cleanup) =3D @_;
>>>>>>>>>>>>>>>>>>>>>>>> + $cleanup //=3D 0;
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> + foreach my $index (reverse 0..$#{$listref}) {
>>>>>>>>>>>>>>>>>>>>>>>> + my $row =3D @$listref[$index];
>>>>>>>>>>>>>>>>>>>>>>>> + next unless($row); # Skip/allow empty lines
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> + # Reject/remove everything besides wildcard =
domains and remarks
>>>>>>>>>>>>>>>>>>>>>>>> + if((not =
&General::validwildcarddomainname($row)) && (not $row =3D~ /^;[\w =
\-()\.:;*\/\\?!&=3D]*$/)) {
>>>>>>>>>>>>>>>>>>>>>>>> + unless($cleanup) {
>>>>>>>>>>>>>>>>>>>>>>>> + # +1 for user friendly line number and to =
ensure non-zero exitcode
>>>>>>>>>>>>>>>>>>>>>>>> + return $index + 1;
>>>>>>>>>>>>>>>>>>>>>>>> + }
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> + # Remove current row
>>>>>>>>>>>>>>>>>>>>>>>> + splice(@$listref, $index, 1);
>>>>>>>>>>>>>>>>>>>>>>>> + }
>>>>>>>>>>>>>>>>>>>>>>>> + }
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> + return 0;
>>>>>>>>>>>>>>>>>>>>>>>> +}
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +###--- Internal misc functions ---###
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +# Send HTTP 303 redirect headers for =
post/request/get pattern
>>>>>>>>>>>>>>>>>>>>>>>> +# (Must be sent before calling =
&Header::showhttpheaders())
>>>>>>>>>>>>>>>>>>>>>>>> +sub _http_prg_redirect {
>>>>>>>>>>>>>>>>>>>>>>>> + my $location =3D =
"https://$ENV{'SERVER_NAME'}:$ENV{'SERVER_PORT'}$ENV{'SCRIPT_NAME'}";
>>>>>>>>>>>>>>>>>>>>>>>> + print "Status: 303 See Other\n";
>>>>>>>>>>>>>>>>>>>>>>>> + print "Location: $location\n";
>>>>>>>>>>>>>>>>>>>>>>>> +}
>>>>>>>>>>>>>>>>>>>>>>>> diff --git a/lfs/rpz b/lfs/rpz
>>>>>>>>>>>>>>>>>>>>>>>> new file mode 100644
>>>>>>>>>>>>>>>>>>>>>>>> index 000000000..7ddbc38e5
>>>>>>>>>>>>>>>>>>>>>>>> --- /dev/null
>>>>>>>>>>>>>>>>>>>>>>>> +++ b/lfs/rpz
>>>>>>>>>>>>>>>>>>>>>>>> @@ -0,0 +1,96 @@
>>>>>>>>>>>>>>>>>>>>>>>> =
+#########################################################################=
######
>>>>>>>>>>>>>>>>>>>>>>>> +# #
>>>>>>>>>>>>>>>>>>>>>>>> +# IPFire.org - A linux based firewall #
>>>>>>>>>>>>>>>>>>>>>>>> +# Copyright (C) 2024 IPFire Team =
<info@ipfire.org> #
>>>>>>>>>>>>>>>>>>>>>>>> +# #
>>>>>>>>>>>>>>>>>>>>>>>> +# 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 =
<http://www.gnu.org/licenses/>. #
>>>>>>>>>>>>>>>>>>>>>>>> +# #
>>>>>>>>>>>>>>>>>>>>>>>> =
+#########################################################################=
######
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> =
+#########################################################################=
######
>>>>>>>>>>>>>>>>>>>>>>>> +# Definitions
>>>>>>>>>>>>>>>>>>>>>>>> =
+#########################################################################=
######
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +include Config
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +SUMMARY =3D response policy zone - RPZ =
reputation system for unbound DNS
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +VER =3D 1.0.0
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +THISAPP =3D rpz-$(VER)
>>>>>>>>>>>>>>>>>>>>>>>> +DIR_APP =3D $(DIR_SRC)/$(THISAPP)
>>>>>>>>>>>>>>>>>>>>>>>> +TARGET =3D $(DIR_INFO)/$(THISAPP)
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +PROG =3D rpz
>>>>>>>>>>>>>>>>>>>>>>>> +PAK_VER =3D 18
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +DEPS =3D
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +SERVICES =3D
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> =
+#########################################################################=
######
>>>>>>>>>>>>>>>>>>>>>>>> +# Top-level Rules
>>>>>>>>>>>>>>>>>>>>>>>> =
+#########################################################################=
######
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +install : $(TARGET)
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +check :
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +download :
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +b2 :
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +dist:
>>>>>>>>>>>>>>>>>>>>>>>> + @$(PAK)
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> =
+#########################################################################=
######
>>>>>>>>>>>>>>>>>>>>>>>> +# Installation Details
>>>>>>>>>>>>>>>>>>>>>>>> =
+#########################################################################=
######
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +$(TARGET) :
>>>>>>>>>>>>>>>>>>>>>>>> + @$(PREBUILD)
>>>>>>>>>>>>>>>>>>>>>>>> + @rm -rf $(DIR_APP)
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> + # RPZ scripts
>>>>>>>>>>>>>>>>>>>>>>>> + install --verbose --mode=3D755 \
>>>>>>>>>>>>>>>>>>>>>>>> + =
$(DIR_CONF)/rpz/{rpz-config,rpz-metrics,rpz-sleep,rpz-make,rpz-functions} =
\
>>>>>>>>>>>>>>>>>>>>>>>> + --target-directory=3D/usr/sbin
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> + # RPZ config files
>>>>>>>>>>>>>>>>>>>>>>>> + mkdir -pv /etc/unbound/local.d
>>>>>>>>>>>>>>>>>>>>>>>> + install --verbose --mode=3D644 --owner=3Dnobody=
 --group=3Dnobody \
>>>>>>>>>>>>>>>>>>>>>>>> + $(DIR_CONF)/rpz/00-rpz.conf \
>>>>>>>>>>>>>>>>>>>>>>>> + --target-directory=3D/etc/unbound/local.d
>>>>>>>>>>>>>>>>>>>>>>>> + chown --verbose --recursive nobody:nobody =
/etc/unbound/local.d
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> + # RPZ custom list files for allow and block
>>>>>>>>>>>>>>>>>>>>>>>> + mkdir -pv /var/ipfire/dns/rpz
>>>>>>>>>>>>>>>>>>>>>>>> + touch =
/var/ipfire/dns/rpz/{allowlist,blocklist}
>>>>>>>>>>>>>>>>>>>>>>>> + chown --verbose --recursive nobody:nobody =
/var/ipfire/dns/rpz
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> + # RPZ zone files
>>>>>>>>>>>>>>>>>>>>>>>> + # create empty RPZ config file to avoid a =
unbound config error
>>>>>>>>>>>>>>>>>>>>>>>> + mkdir -pv /etc/unbound/zonefiles
>>>>>>>>>>>>>>>>>>>>>>>> + touch /etc/unbound/zonefiles/allow.rpz
>>>>>>>>>>>>>>>>>>>>>>>> + chown --verbose --recursive nobody:nobody =
/etc/unbound/zonefiles
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> + # Install addon-specific language-files
>>>>>>>>>>>>>>>>>>>>>>>> + install --verbose --mode=3D004 =
$(DIR_CONF)/rpz/rpz.*.pl \
>>>>>>>>>>>>>>>>>>>>>>>> + --target-directory=3D/var/ipfire/addon-lang
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> + # Install backup definition
>>>>>>>>>>>>>>>>>>>>>>>> + cp -vf $(DIR_CONF)/backup/includes/rpz =
/var/ipfire/backup/addons/includes/rpz
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> + @rm -rf $(DIR_APP)
>>>>>>>>>>>>>>>>>>>>>>>> + @$(POSTBUILD)
>>>>>>>>>>>>>>>>>>>>>>>> diff --git a/make.sh b/make.sh
>>>>>>>>>>>>>>>>>>>>>>>> index 827ea9e77..a77535b13 100755
>>>>>>>>>>>>>>>>>>>>>>>> --- a/make.sh
>>>>>>>>>>>>>>>>>>>>>>>> +++ b/make.sh
>>>>>>>>>>>>>>>>>>>>>>>> @@ -390,7 +390,7 @@ prepareenv() {
>>>>>>>>>>>>>>>>>>>>>>>> if [ "${free_space}" -lt "${required_space}" ]; =
then
>>>>>>>>>>>>>>>>>>>>>>>> # Add any consumed space
>>>>>>>>>>>>>>>>>>>>>>>> while read -r consumed_space path; do
>>>>>>>>>>>>>>>>>>>>>>>> - (( free_space +=3D consumed_space / 1024 / =
1024 ))
>>>>>>>>>>>>>>>>>>>>>>>> + (( free_space +=3D consumed_space / 1024 / =
1024 ))
>>>>>>>>>>>>>>>>>>>>>>>> done <<< "$(du --summarize --bytes =
"${BUILD_DIR}" "${IMAGES_DIR}" "${LOG_DIR}" 2>/dev/null)"
>>>>>>>>>>>>>>>>>>>>>>>> fi
>>>>>>>>>>>>>>>>>>>>>>>> @@ -2087,6 +2087,7 @@ build_system() {
>>>>>>>>>>>>>>>>>>>>>>>> lfsmake2 btrfs-progs
>>>>>>>>>>>>>>>>>>>>>>>> lfsmake2 inotify-tools
>>>>>>>>>>>>>>>>>>>>>>>> lfsmake2 grub-btrfs
>>>>>>>>>>>>>>>>>>>>>>>> + lfsmake2 rpz
>>>>>>>>>>>>>>>>>>>>>>>> lfsmake2 linux
>>>>>>>>>>>>>>>>>>>>>>>> lfsmake2 rtl8812au
>>>>>>>>>>>>>>>>>>>>>>>> diff --git a/src/paks/rpz/install.sh =
b/src/paks/rpz/install.sh
>>>>>>>>>>>>>>>>>>>>>>>> new file mode 100644
>>>>>>>>>>>>>>>>>>>>>>>> index 000000000..ef99bf742
>>>>>>>>>>>>>>>>>>>>>>>> --- /dev/null
>>>>>>>>>>>>>>>>>>>>>>>> +++ b/src/paks/rpz/install.sh
>>>>>>>>>>>>>>>>>>>>>>>> @@ -0,0 +1,36 @@
>>>>>>>>>>>>>>>>>>>>>>>> +#!/bin/bash
>>>>>>>>>>>>>>>>>>>>>>>> =
+#########################################################################=
######
>>>>>>>>>>>>>>>>>>>>>>>> +# #
>>>>>>>>>>>>>>>>>>>>>>>> +# IPFire.org - A linux based firewall #
>>>>>>>>>>>>>>>>>>>>>>>> +# Copyright (C) 2024 IPFire Team =
<info@ipfire.org> #
>>>>>>>>>>>>>>>>>>>>>>>> +# #
>>>>>>>>>>>>>>>>>>>>>>>> +# 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 =
<http://www.gnu.org/licenses/>. #
>>>>>>>>>>>>>>>>>>>>>>>> +# #
>>>>>>>>>>>>>>>>>>>>>>>> =
+#########################################################################=
######
>>>>>>>>>>>>>>>>>>>>>>>> +#
>>>>>>>>>>>>>>>>>>>>>>>> +. /opt/pakfire/lib/functions.sh
>>>>>>>>>>>>>>>>>>>>>>>> +extract_files
>>>>>>>>>>>>>>>>>>>>>>>> +restore_backup ${NAME}
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +# fix user created files
>>>>>>>>>>>>>>>>>>>>>>>> +chown --verbose --recursive nobody:nobody \
>>>>>>>>>>>>>>>>>>>>>>>> + /var/ipfire/dns/rpz \
>>>>>>>>>>>>>>>>>>>>>>>> + /etc/unbound/zonefiles \
>>>>>>>>>>>>>>>>>>>>>>>> + /etc/unbound/local.d
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +# Update Language cache
>>>>>>>>>>>>>>>>>>>>>>>> +/usr/local/bin/update-lang-cache
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +# restart unbound to load config file
>>>>>>>>>>>>>>>>>>>>>>>> +/etc/init.d/unbound restart
>>>>>>>>>>>>>>>>>>>>>>>> diff --git a/src/paks/rpz/uninstall.sh =
b/src/paks/rpz/uninstall.sh
>>>>>>>>>>>>>>>>>>>>>>>> new file mode 100644
>>>>>>>>>>>>>>>>>>>>>>>> index 000000000..e11427df3
>>>>>>>>>>>>>>>>>>>>>>>> --- /dev/null
>>>>>>>>>>>>>>>>>>>>>>>> +++ b/src/paks/rpz/uninstall.sh
>>>>>>>>>>>>>>>>>>>>>>>> @@ -0,0 +1,38 @@
>>>>>>>>>>>>>>>>>>>>>>>> +#!/bin/bash
>>>>>>>>>>>>>>>>>>>>>>>> =
+#########################################################################=
######
>>>>>>>>>>>>>>>>>>>>>>>> +# #
>>>>>>>>>>>>>>>>>>>>>>>> +# IPFire.org - A linux based firewall #
>>>>>>>>>>>>>>>>>>>>>>>> +# Copyright (C) 2024 IPFire Team =
<info@ipfire.org> #
>>>>>>>>>>>>>>>>>>>>>>>> +# #
>>>>>>>>>>>>>>>>>>>>>>>> +# 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 =
<http://www.gnu.org/licenses/>. #
>>>>>>>>>>>>>>>>>>>>>>>> +# #
>>>>>>>>>>>>>>>>>>>>>>>> =
+#########################################################################=
######
>>>>>>>>>>>>>>>>>>>>>>>> +#
>>>>>>>>>>>>>>>>>>>>>>>> +. /opt/pakfire/lib/functions.sh
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +# stop unbound to delete RPZ conf file
>>>>>>>>>>>>>>>>>>>>>>>> +/etc/init.d/unbound stop
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +make_backup ${NAME}
>>>>>>>>>>>>>>>>>>>>>>>> +remove_files
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +# delete rpz config files. Otherwise unbound =
will throw error:
>>>>>>>>>>>>>>>>>>>>>>>> +# "[1723428668] unbound-control[17117:0] =
error: connect: Connection refused for 127.0.0.1 port 8953"
>>>>>>>>>>>>>>>>>>>>>>>> +/bin/rm --verbose --force =
/etc/unbound/local.d/*.rpz.conf
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +# Update Language cache
>>>>>>>>>>>>>>>>>>>>>>>> +/usr/local/bin/update-lang-cache
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +# start unbound to load unbound config file
>>>>>>>>>>>>>>>>>>>>>>>> +/etc/init.d/unbound start
>>>>>>>>>>>>>>>>>>>>>>>> diff --git a/src/paks/rpz/update.sh =
b/src/paks/rpz/update.sh
>>>>>>>>>>>>>>>>>>>>>>>> new file mode 100644
>>>>>>>>>>>>>>>>>>>>>>>> index 000000000..9bc340bc6
>>>>>>>>>>>>>>>>>>>>>>>> --- /dev/null
>>>>>>>>>>>>>>>>>>>>>>>> +++ b/src/paks/rpz/update.sh
>>>>>>>>>>>>>>>>>>>>>>>> @@ -0,0 +1,52 @@
>>>>>>>>>>>>>>>>>>>>>>>> +#!/bin/bash
>>>>>>>>>>>>>>>>>>>>>>>> =
+#########################################################################=
######
>>>>>>>>>>>>>>>>>>>>>>>> +# #
>>>>>>>>>>>>>>>>>>>>>>>> +# IPFire.org - A linux based firewall #
>>>>>>>>>>>>>>>>>>>>>>>> +# Copyright (C) 2024 IPFire Team =
<info@ipfire.org> #
>>>>>>>>>>>>>>>>>>>>>>>> +# #
>>>>>>>>>>>>>>>>>>>>>>>> +# 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 =
<http://www.gnu.org/licenses/>. #
>>>>>>>>>>>>>>>>>>>>>>>> +# #
>>>>>>>>>>>>>>>>>>>>>>>> =
+#########################################################################=
######
>>>>>>>>>>>>>>>>>>>>>>>> +#
>>>>>>>>>>>>>>>>>>>>>>>> +. /opt/pakfire/lib/functions.sh
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +# from update.sh
>>>>>>>>>>>>>>>>>>>>>>>> +extract_backup_includes
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +# stop unbound to delete RPZ conf file
>>>>>>>>>>>>>>>>>>>>>>>> +/etc/init.d/unbound stop
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +# from uninstall.sh
>>>>>>>>>>>>>>>>>>>>>>>> +make_backup ${NAME}
>>>>>>>>>>>>>>>>>>>>>>>> +remove_files
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +# delete rpz config files. Otherwise unbound =
will throw error:
>>>>>>>>>>>>>>>>>>>>>>>> +# "unbound-control[nn:0] error: connect: =
Connection refused for 127.0.0.1 port 8953"
>>>>>>>>>>>>>>>>>>>>>>>> +/bin/rm --verbose --force =
/etc/unbound/local.d/*.rpz.conf
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +# from install.sh
>>>>>>>>>>>>>>>>>>>>>>>> +extract_files
>>>>>>>>>>>>>>>>>>>>>>>> +restore_backup ${NAME}
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +# fix user created files
>>>>>>>>>>>>>>>>>>>>>>>> +chown --verbose --recursive nobody:nobody \
>>>>>>>>>>>>>>>>>>>>>>>> + /var/ipfire/dns/rpz \
>>>>>>>>>>>>>>>>>>>>>>>> + /etc/unbound/zonefiles \
>>>>>>>>>>>>>>>>>>>>>>>> + /etc/unbound/local.d
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +# Update Language cache
>>>>>>>>>>>>>>>>>>>>>>>> +/usr/local/bin/update-lang-cache
>>>>>>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>>>>>>> +# restart unbound to load config files
>>>>>>>>>>>>>>>>>>>>>>>> +/etc/init.d/unbound start
>>>>>>>>>>>>>>>>>>>>>>>> --
>>>>>>>>>>>>>>>>>>>>>>>> 2.39.5
>>>>>>>>>>>>>>>>>>>>>>>>=20
>>>>>>>>>>>>>>>>>>>>>> Jon
>>>>>>>>>>>>>>>>>>>>>> --
>>>>>>>>>>>>>>>>>>>>>> Jon Murphy
>>>>>>>>>>>>>>>>>>>>>> jon.murphy@ipfire.org
>>>>>>>>>>>>>>>>>>>>=20
>>>>>>>>>>>>>>>>>>>>  Jon
>>>>>>>>>>>>>>>>>>>> --
>>>>>>>>>>>>>>>>>>>> Jon Murphy
>>>>>>>>>>>>>>>>>>>> jon.murphy@ipfire.org
>>>>>>>>=20
>>>>>>>>=20
>>>>>>>>=20
>>>>>>=20
>>>>>>=20
>>>>=20
>>>>=20
>>>=20
>>=20
>>=20