From mboxrd@z Thu Jan 1 00:00:00 1970 From: Bernhard Bitsch <bbitsch@ipfire.org> To: development@lists.ipfire.org Subject: Re: [PATCH] RPZ: update code to include WEBGUI and additional languages Date: Fri, 14 Feb 2025 15:16:49 +0100 Message-ID: <7918fcbf-9787-4b55-aa63-09a215c9d294@ipfire.org> In-Reply-To: <A242CED5-A2BC-498C-B860-41793005478A@ipfire.org> MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="===============1659952175765241016==" List-Id: <development.lists.ipfire.org> --===============1659952175765241016== Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Hello Michael, I use the hagezi lists (=20 https://github.com/hagezi/dns-blocklists?tab=3Dreadme-ov-file#zap-dns-blockli= sts---for-a-better-internet=20 ) which allow more selections. Regards, Bernhard Am 14.02.2025 um 14:52 schrieb Michael Tremer: > Hello Bernhard, >=20 >> On 14 Feb 2025, at 12:58, Bernhard Bitsch <bbitsch(a)ipfire.org> wrote: >> >> Hello Michael, >> >> thanks for your clear words. But nevertheless let be comment at some topic= s. >> >> Am 14.02.2025 um 13:07 schrieb Michael Tremer: >>> Hello Jon, >>> It very much depends on the kind of contribution. A one-line patch obviou= sly has fewer strings attached to it than a larger patch set like this. >>> However, we have outlined the process in the wiki already, starting from = here: >>> https://www.ipfire.org/docs/devel/submit-patches >>> This contains some useful pointers about the how (how do I actually make = my changes happen, how do I build IPFire, etc), and at the bottom it contains= a lot of information about the format the changes should be submitted; split= into smaller chunks that are ideally as independent from each other so that = they can be individually reviewed and merged. Usually a development process t= akes long time and we have already shipped parts of code that we will need fo= r certain features that are not ready yet. This is a good practice to let cod= e mature, especially when it is touching rather critical bits like the firewa= ll and networking stacks. >>> There are also some guidelines on how to write a good commit message and = how to use Git tags: >>> https://www.ipfire.org/docs/devel/git/commit-messages >>> https://www.ipfire.org/docs/devel/git/tags >>> Then there is something about how to get in touch with the right person a= nd legal stuff: >>> https://www.ipfire.org/docs/devel/contact >>> https://www.ipfire.org/docs/legal/ipca >> >> IMO, this facts are known by Jon. He just did a big part besides this gene= ral process. Including publishing his efforts to the community for review and= test. >> >>> Finally, we have a bit of an underused roadmap section on the wiki. It wo= uld be nice if we could use that a little bit more because then it would be e= asier for everyone to keep track of progress on certain features; people coul= d see what is being worked on and see if they can help development and testin= g and so on: >>> https://www.ipfire.org/docs/roadmap >>> There is a template on how to create new pages: >>> https://www.ipfire.org/docs/roadmap/template >>> And this is a good example of what this could look like: >>> https://www.ipfire.org/docs/roadmap/openvpn-26 >>> All of these steps are coming *after* there has been some initial discuss= ion about what actually has a chance to become part of the distribution. For = that, we do not have any specific guidelines because it is not very trivial t= o write these things. There are just too many possibilities. In the past, the= re has also been very little need for this, but that does not mean that there= have not been problems before. >>> The reason why I am raising the bar this high here is simply that we have= made mistakes in the past that we don=E2=80=99t want to repeat. We have lear= ned a couple of lessons in a not very pleasant way and I under no circumstanc= es would want to do this again. The objective is that we want to provide an e= xcellent distribution. Although IPFire of course has its shortcomings here an= d there, it is a very stable distribution and we have a very good track recor= d that I want to keep. This is what our users deserve. >>> In the past, people have =E2=80=9Cdropped=E2=80=9D their patches on this = list (or sometimes elsewhere) and we were left with dealing with the entire i= ntegration only to find out later what problems there were hidden in the code= . The original author(s) had no interest in fixing any of that because it wor= ked just fine for them, and so why spend any time on the problems of somebody= else? Usually I am the fallback for this and I simply don=E2=80=99t want to = be that. I have lots of my own projects inside IPFire that are moving at snai= l speed because fixing existing code usually takes priority over writing new = code. >>> Therefore we need a commitment to sort out these problems in the first pl= ace. It has to be proven that people actually *care* about the patches that t= hey post here. I am not sure this needs writing down as this should be the sa= me policy with almost any open source project. If you contribute a line, ther= e is probably less maintenance required in the future, but if you contribute = a large code base, then you will need to look after it for the foreseeable fu= ture. It is your feature and not mine after all. >> >> Being one of the first testers and revisors, I commit me to support the de= velopment. Point. >> >>> Then, what actually has a chance to make it into the distribution? Probab= ly not a lot. IPFire has a very clear use case. There will not be any space f= or a desktop environment and running Chrome on it, we also don=E2=80=99t it t= o make coffee and cook me a dinner. We would currently only accept things tha= t were actually maintainable by the current team in case a contributor moves = on (see above), because we simply only have so much man power. We already hav= e a large zoo of features that are very abandoned and we are potentially look= ing at getting rid of more things simply because we cannot support them prope= rly. Time just doesn=E2=80=99t permit. Adding something large is therefore ve= ry difficult at the moment. >>> I understand that in this specific case you have been trying to not invol= ve the development team and I understand your motivation. But you cannot forg= et about how much time and effort a review process can take. Therefore we wan= t to plan things well; we want to even split it; and we want to have a conver= sation in advance so that the roadmap is clear and the actual code review ide= ally only becomes a formality. >>> All of this above has been for a general case. Please read through this a= nd feel free to ask any questions if something isn=E2=80=99t clear. >>> To move forward with this feature, we should start by planning a roadmap.= We need to discuss what this project should cover and what it should not cov= er. I believe we don=E2=80=99t need to talk much about implementation details= because you have figured out a lot of them; we need to find what feature we = want to provide to our users. Are you up for that? >> >> As a first input to the 'official' discussion, some thoughts. >> - Usage of encrypted data traffic is increasing. Especially in communicati= ons not aware to the user. These unwanted traffic is more and more difficult = to block with IP orientated tools. Even the proxy based solution do not reall= y function efficient. >> - To circumvent these problems a widely used approach is DNS filtering. Th= is comes in two flavours: 1. online providers, 2. local filtering DNS servers= like PiHole. >> - Solution 1 isn't wantable. Many providers store the access data, outside= the local network. >> - Solution 2 installs another DNS server inside the local networks. It isn= 't trivial to ensure that all DNS traffic is handled by this server. >> - Therefore it is desirable that this filtering is done in the only DNS se= rver in a IPFire governed network, unbound on the IPFire system. The RPZ func= tionality allows exactly this. >> - There are, IMO, good filter lists outside. The updating of these lists i= s part of the RPZ module. There is some effort left to investigate these and = to develop recommendations for a good mix of appliance, we do this for the ex= ternal DNS servers already. >=20 > You are thinking too much about the *how* here, but we should think of the = *what* first. What features do we want to offer and what do we not want to of= fer. >=20 > Regarding the lists: I am running a test with one client which has about 20= 00 users on their network on a daily basis. There have been *huge* amounts of= false positives from the OISD list and it has been occasionally painful to w= hitelist those. The quality of this feature stands and falls with the quality= of the lists that we can feed into this. >=20 > I have also raised before that those lists collect random stuff together an= d in the end you only have one list that you can either take or leave. Coming= from URL filter, we have some categorisation there like =E2=80=9Cadult=E2=80= =9D, =E2=80=9Cgambling=E2=80=9D, =E2=80=9Csocial networks=E2=80=9D, and so on= which we don=E2=80=99t have here. Would that not be nice to have, too? >=20 >> Regards, >> Bernhard >> >>> Best, >>> -Michael >>>> On 13 Feb 2025, at 21:34, jon <jon.murphy(a)ipfire.org> wrote: >>>> >>>> Michael, >>>> >>>> I=E2=80=99ve read through your comments a few times and I ended up with = many more questions. >>>> >>>> >>>>> What I rather mean is that it has never been added as a topic on the ag= enda and it has not been pitched by yourself. >>>> >>>> >>>> To me the efforts to get new code accepted seem to have changed and it s= eemed 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? / Wh= at 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=99t know what exactly= is needed. Please be specific. >>>> >>>> >>>> Jon >>>> >>>> PS - I am not ignoring your other comments, I am just trying to move for= ward and keep things simple. >>>> >>>> >>>> >>>>> On Feb 8, 2025, at 1:27=E2=80=AFPM, Michael Tremer <michael.tremer(a)ip= fire.org> wrote: >>>>> >>>>> Hello Jon, >>>>> >>>>> Thanks for your reply. And good that you are copying everyone into this= conversation. >>>>> >>>>>> On 8 Feb 2025, at 18:41, jon <jon.murphy(a)ipfire.org> wrote: >>>>>> >>>>>> Michael, >>>>>> >>>>>>> I think I have covered this all at lengths before that this project h= as been started as a separate effort >>>>>> >>>>>> 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 m= y 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. >>>>> >>>>> 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 swif= tly 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 worki= ng on something without involving the core team is a risky undertaking. Of co= urse IPFire is free software and so everyone is free to fork if they wish to = do so. >>>>> >>>>>>> and as far as I am aware none of the other team members has been invo= lved. This has not been discussed either on this list, on our calls. >>>>>> >>>>>> You were aware many steps along the way. See your email on July 28, 2= 024, 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 som= etimes silence. (Yes, I get it, people are busy.) >>>>>> >>>>>> You and Adolf, Leo, Erik and Bernhard have been aware since the beginn= ing. You mention you were aware of the "proof-of-concept". If you include t= hose beginning posts, since Sep 2023. >>>>> >>>>> Yes, I am aware of a proof-of-concept that I have been running myself f= or 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? >>>>> >>>>>>> This has not been discussed . . . on our calls. >>>>>> >>>>>> 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 als= o 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 no= tes. >>>>> >>>>> I am not at all insulting you. I don=E2=80=99t want to take this down t= o 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 thing= s on the calls, the weather, politics, how our pets are. None of that makes i= t 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. >>>>> >>>>>>> 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 conversat= ion. >>>>>> >>>>>> Regular conversation on the Dev Mailing list is many times met with si= lence. 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. >>>>> >>>>> And you think my emails are not being met with silence? This has nothin= g 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 involv= ed in all the things and simply will ignore emails simply based on their subj= ect line. >>>>> >>>>>> 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 h= ave a great group of people in the Community. It is a shame you don=E2=80=99= t want to have others help. It would reduce your workload. >>>>> >>>>> You should stop making statements that are not true. Who doesn=E2=80=99= t want anyone to help? >>>>> >>>>> Not having this conversation on a Saturday evening would reduce my work= load. At least it would free up time for something else. Helping with the thi= ngs 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 alre= ady have a hundred things on the go. >>>>> >>>>>>> Therefore, what am I supposed to do with this email? >>>>>> >>>>>> 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 t= he correct way. And be specific. I am trying to help. I am trying to make t= hings better. I am trying to do things the right way. >>>>> >>>>> To me it isn=E2=80=99t. This is yet another project that has been dumpe= d 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 a= bout 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. >>>>> >>>>>>> I don=E2=80=99t want to merge code that I don=E2=80=99t agree with. >>>>>> >>>>>> I asked multiple times if you "agreed with the concept" and again, met= with silence. Yes I get it, people are busy. >>>>> >>>>> Having support for RPZ? Yes, it was definitely on the roadmap. That I a= gree with. >>>>> >>>>>>> So many fundamental things that I have been raising have either not b= een discussed or outright dismissed. >>>>>> >>>>>> You mentioned this a in the past, but for some reason you do not discl= ose 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 comment= s. 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. >>>>> >>>>> 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 hav= e stated that this should never be an add-on considering it is supposed to re= place URL Filter. We should never allow people to add their own sources. I ha= ve also stated that we cannot download any lists over HTTPS again and again a= nd again. The implementation that we have here seems to exactly do that and t= herefore I think that my feedback has been dismissed entirely. >>>>> >>>>>>> I don=E2=80=99t want to merge code that has no future inside IPFire a= s there is no constructive conversation with the maintainers of it. >>>>>> >>>>>> 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! >>>>> >>>>> You. I don=E2=80=99t care much about the providers of the lists. >>>>> >>>>>> See, this is where it gets confusing. There are hundreds of open sour= ce packages as part of IPFire. Pick the last five years of items added to th= e IPFire build. You're telling me you have "constructive conversation with t= he maintainers" of all of the added packages? >>>>> >>>>> They publish their software and they don=E2=80=99t care whether I am pu= lling it or not. They publish it with the commitment to maintain it - sometim= es for better and sometimes for worse. >>>>> >>>>> You care about me pulling your code and I don=E2=80=99t know whether yo= u would commit to maintain this. >>>>> >>>>> These two are very different cases. >>>>> >>>>>> Pick the IP Blocklists list (i.e., 3CORESEC, ABUSECH, DSHIELD, SPAMHAU= S, etc.) or the Suricata lists (i.e., Emergingthreats.net, Abuse.ch, etc.). = So you=E2=80=99ve have "constructive conversation with the maintainers"? >>>>> >>>>> Yes, occasionally I have phone calls with a few of these providers. >>>>> >>>>>>> Having been trying for a long time to make you aware of this, nothing= of this should come as a surprise. >>>>>> >>>>>> Ha! Yes a surprise. In the beginning you seemed interested as IPFire= needed a replacement for URL Filter. You asked good questions about the lis= ts 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 par= t of the core system?=E2=80=9D from your Jul 28, 2024 email. >>>>> >>>>> 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 bein= g ignored, why should I put this to the top of my list of priorities? I am no= t disappointed about this, just trying to be very good with my time. >>>>> >>>>>> And on January 16, 2025 I wrote a message looking for help. And you w= ere 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. >>>>> >>>>> 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. >>>>> >>>>>>> Please consider if that can be changed and if there is a path forward= with this. >>>>>> >>>>>> Be more specific, what has to change? What exactly did I dismiss? >>>>> >>>>> 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 cont= ain much of it. Repeatedly I have been pointing out that we should think befo= re we build. I am sure a lot of hours have now gone into some code that simpl= y does not satisfy me. And I am not not talking about the code itself, what i= t 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 whet= her we want a certain feature now. Then there should be a clear roadmap for e= veryone to follow; tasks can be split-up as we go and hopefully then have som= ething that is maintainable, interesting for our users and even would do us p= roud. This is how this should work. >>>>> >>>>> So, what has to change? I don=E2=80=99t think with shouting at each oth= er, throwing patches around and making me generally unhappy is a good start. >>>>> >>>>> -Michael >>>>> >>>>>> Jon >>>>>> >>>>>> >>>>>> >>>>>>> On Feb 6, 2025, at 2:13=E2=80=AFPM, Michael Tremer <michael.tremer(a)= 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 disapp= oint you. >>>>>>> >>>>>>> I think I have covered this all at lengths before that this project h= as been started as a separate effort and as far as I am aware none of the oth= er 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 fo= rum 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. S= o many fundamental things that I have been raising have either not been discu= ssed or outright dismissed. >>>>>>> >>>>>>> I don=E2=80=99t want to merge code that has no future inside IPFire a= s 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 >>>>>>> >>>>>>>> On 6 Feb 2025, at 16:35, Jon Murphy <jon.murphy(a)ipfire.org> wrote: >>>>>>>> >>>>>>>> What is it? >>>>>>>> Response Policy Zone (RPZ) is a mechanism to define local policies i= n a >>>>>>>> standardized way and load those policies from external sources. >>>>>>>> Bottom line: RPZ allows admins to easily block access to websites vi= a DNS lookup. >>>>>>>> >>>>>>>> RPZ can block websites via categories. Examples include: fake websi= tes, annoying >>>>>>>> pop-up ads, newly registered domains, DoH bypass sites, bad "host" s= ervices, >>>>>>>> maliscious top level domains (e.g., *.zip, *.mov), piracy, gambling,= pornography, >>>>>>>> and more. RPZ lists come from various RPZ providers and their avail= able >>>>>>>> catagories. >>>>>>>> >>>>>>>> This RPZ add-on enables the RPZ functionality by adding a couple lin= es 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, Frenc= h, 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 ac= cess >>>>>>>> gateway, which is (should be) solely used as DNS source of the inter= nal network. >>>>>>>> >>>>>>>> - As most sites use HTTPS it makes it difficult to filter traffic wi= th URL >>>>>>>> Filter without also properly configuring conventional (non-transpare= nt) >>>>>>>> mode on the proxy. RPZ is a nice replacement for the URL Filter. >>>>>>>> >>>>>>>> - No need to install and maintain an additional device like PiHole o= r AdBlock >>>>>>>> browser extensions on multiple user devices. >>>>>>>> >>>>>>>> - This is an additional layer of protection for users. Less worry so= meone will >>>>>>>> click on something that gets them into trouble. And, saying this wit= h emphasis, >>>>>>>> the ability to do it in one place! >>>>>>>> >>>>>>>> - Blocked sites save on unneeded traffic and can lessen the threat o= f 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), school= s, >>>>>>>> ministerial, and at the office. Device counts are small (2-6) to me= dium (~80) >>>>>>>> to mediam-large (200+). >>>>>>>> >>>>>>>> - RPZ can block ads, popups, phishing, scammers, spyware, malware, a= nnoying >>>>>>>> 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 validat= e 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 li= st >>>>>>>> - 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/b= lock 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` displaye= d 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-ipf= ire) >>>>>>>> >>>>>>>> --- >>>>>>>> >>>>>>>> rpz-beta-0.1.11-11.ipfire on 2024-10-18 >>>>>>>> rpz.cgi: >>>>>>>> - new feature: added new language file for Italian (thank you umbert= o) >>>>>>>> - new feature: added new language file for Spanish (thank you Robert= o) >>>>>>>> >>>>>>>> --- >>>>>>>> >>>>>>>> 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 siosio= s) >>>>>>>> >>>>>>>> --- >>>>>>>> >>>>>>>> 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 we= bgui!! >>>>>>>> - 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 cou= nt, by >>>>>>>> "enabled" list or all lists >>>>>>>> >>>>>>>> backups: >>>>>>>> - bug fix: include all files in `/var/ipfire/dns/rpz` directory in b= ackup >>>>>>>> >>>>>>>> update.sh: >>>>>>>> - bug fix: corrected ownership for `/var/ipfire/dns/rpz` directory d= uring 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(a)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(a)ipfire.org> >>>>>>>> Contribution-by: Erik Kapfer <erik.kapfer(a)ipfire.org> >>>>>>>> Signed-off-by: Jon Murphy <jon.murphy(a)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/c= ommon/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/roo= tfiles/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/packag= es/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(a)ipfire.org> = # >>>>>>>> +# = # >>>>>>>> +# This program is free software: you can redistribute it and/or mo= dify # >>>>>>>> +# it under the terms of the GNU General Public License as publishe= d by # >>>>>>>> +# the Free Software Foundation, either version 3 of the License, o= r # >>>>>>>> +# (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 Licens= e # >>>>>>>> +# along with this program. If not, see <http://www.gnu.org/licens= es/>. # >>>>>>>> +# = # >>>>>>>> +###################################################################= ############ >>>>>>>> + >>>>>>>> +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 op= tion >>>>>>>> +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 e= xists. 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 n= ot exist. exit" >>>>>>>> + exit 106 >>>>>>>> + fi >>>>>>>> + >>>>>>>> + msg_log "info: rpz: remove config file & rpz file \"${rpzNa= me}\"" >>>>>>>> + 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> <OP= TION> <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(a)ipfire.org> = # >>>>>>>> +# = # >>>>>>>> +# This program is free software: you can redistribute it and/or mo= dify # >>>>>>>> +# it under the terms of the GNU General Public License as publishe= d by # >>>>>>>> +# the Free Software Foundation, either version 3 of the License, o= r # >>>>>>>> +# (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 Licens= e # >>>>>>>> +# along with this program. If not, see <http://www.gnu.org/licens= es/>. # >>>>>>>> +# = # >>>>>>>> +###################################################################= ############ >>>>>>>> + >>>>>>>> +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 res= erved NAMEs >>>>>>>> + if [[ ! "${theName}" =3D~ $regex ]] || [[ "${theName}" =3D~ $re= gex1 ]] ; 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-checkco= nf\"" >>>>>>>> + >>>>>>>> + if ! unbound-checkconf ; then >>>>>>>> + msg_log "error: rpz: unbound-checkconf found invalid co= nfiguration." >>>>>>>> + msg_log \ >>>>>>>> + "error: rpz: In Terminal run the command \"unbound-ch= eckconf\" 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(a)ipfire.org> = # >>>>>>>> +# = # >>>>>>>> +# This program is free software: you can redistribute it and/or mo= dify # >>>>>>>> +# it under the terms of the GNU General Public License as publishe= d by # >>>>>>>> +# the Free Software Foundation, either version 3 of the License, o= r # >>>>>>>> +# (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 Licens= e # >>>>>>>> +# along with this program. If not, see <http://www.gnu.org/licens= es/>. # >>>>>>>> +# = # >>>>>>>> +###################################################################= ############ >>>>>>>> + >>>>>>>> +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 de= fault 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 fi= les >>>>>>>> + set_permissions "${theConfig}" >>>>>>>> +} >>>>>>>> + >>>>>>>> +# create the config file for block >>>>>>>> +make_block_config () { >>>>>>>> + local theLog=3D"${1:-yes}" # lo= g default ON >>>>>>>> + local theConfig=3D"/etc/unbound/local.d/block.rpz.conf" # ou= tput zone conf file >>>>>>>> + local theList=3D"/var/ipfire/dns/rpz/blocklist" # in= put 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 rp= z 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-passthr= u.' >>>>>>>> + >>>>>>>> + # 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 rp= z 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 wild= card >>>>>>>> + # - 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 op= tion >>>>>>>> +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(a)ipfire.org> = # >>>>>>>> +# = # >>>>>>>> +# This program is free software: you can redistribute it and/or mo= dify # >>>>>>>> +# it under the terms of the GNU General Public License as publishe= d by # >>>>>>>> +# the Free Software Foundation, either version 3 of the License, o= r # >>>>>>>> +# (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 Licens= e # >>>>>>>> +# along with this program. If not, see <http://www.gnu.org/licens= es/>. # >>>>>>>> +# = # >>>>>>>> +###################################################################= ############ >>>>>>>> + >>>>>>>> +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 op= tion >>>>>>>> +done >>>>>>>> + >>>>>>>> +# get the list of message logs for N weeks >>>>>>>> +messageLogs=3D$( find /var/log/messages* -type f | sort --version-s= ort | >>>>>>>> + 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" "la= st 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}" ) ; t= hen >>>>>>>> + 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" <<< "${li= neCount}" ) ; 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" <<< "${mo= dDateList}" ) ; 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(a)ipfire.org> = # >>>>>>>> +# = # >>>>>>>> +# This program is free software: you can redistribute it and/or mo= dify # >>>>>>>> +# it under the terms of the GNU General Public License as publishe= d by # >>>>>>>> +# the Free Software Foundation, either version 3 of the License, o= r # >>>>>>>> +# (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 Licens= e # >>>>>>>> +# along with this program. If not, see <http://www.gnu.org/licens= es/>. # >>>>>>>> +# = # >>>>>>>> +###################################################################= ############ >>>>>>>> + >>>>>>>> +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 min= utes) >>>>>>>> + >>>>>>>> +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>B= eispiel: 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>Bei= spiel: 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 Zei= chen', >>>>>>>> +'rpz exitcode 102' =3D> 'unbound-checkconf hat eine fehlerhafte Kon= figuration 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 is= t leer', >>>>>>>> +'rpz exitcode 104' =3D> 'Ein Eintrag mit identischem Namen existier= t bereits', >>>>>>>> +'rpz exitcode 105' =3D> 'Die URL ist ung=C3=BCltig', >>>>>>>> +'rpz exitcode 106' =3D> 'Eintrag kann nicht entfernt werden, der Na= me existiert nicht', >>>>>>>> +'rpz exitcode 107' =3D> 'Der Name ist ung=C3=BCltig - nur "allow" o= der "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 en= th=C3=A4lt unzul=C3=A4ssige Eintr=C3=A4ge', >>>>>>>> +'rpz exitcode 201' =3D> 'Die Anmerkung enth=C3=A4lt unzul=C3=A4ssig= e Zeichen', >>>>>>>> +'rpz exitcode 202' =3D> 'Ung=C3=BCltiger Eintrag in der benutzerdef= inierten Allowlist, Zeile ', >>>>>>>> +'rpz exitcode 203' =3D> 'Ung=C3=BCltiger Eintrag in der benutzerdef= inierten 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 configurat= ion. 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 invali= d 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 u= nderscore.', >>>>>>>> +'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 config= uraci=C3=B3n no v=C3=A1lida. Desde Terminal, ejecute el comando unbound-check= conf 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 ex= iste', >>>>>>>> +'rpz exitcode 107' =3D> 'el NOMBRE no es v=C3=A1lido - s=C3=B3lo "p= ermitir" 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 perso= nnalis=C3=A9e:', >>>>>>>> +'rpz cl allow info' =3D> 'Domaines autoris=C3=A9s (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>E= xample: 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 p= as', >>>>>>>> +'rpz exitcode 107' =3D> 'le NOM n\'est pas valide - =C2=AB autorise= r =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 en= tr=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\'au= torisation, ligne ', >>>>>>>> +'rpz exitcode 203' =3D> 'entr=C3=A9e non valide dans la liste de bl= ocs, ligne ', >>>>>>>> +'rpz exitcode 204' =3D> 'L\'entr=C3=A9e s=C3=A9lectionn=C3=A9e n\'e= xiste 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>Esemp= io: 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 configura= zione non valida. Dal Terminale esegui il comando unbound-checkconf per maggi= ori 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 cont= iene 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 yapilan= dirma bulundu. Terminalde daha fazla bilgi i=EF=BF=BDin Unbound-checkConf kom= utunu =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(a)ipfire.org> = # >>>>>>>> +# = # >>>>>>>> +# This program is free software: you can redistribute it and/or mod= ify # >>>>>>>> +# 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/license= s/>. # >>>>>>>> +# = # >>>>>>>> +###################################################################= ############ >>>>>>>> + >>>>>>>> +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 enabl= ed) >>>>>>>> +my $CUSTOMLISTS_CONF =3D "${General::swroot}/dns/rpz/customlists.co= nf"; >>>>>>>> + >>>>>>>> +# 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', "$CUSTOMLI= STS_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, e= mpty =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 con= figuration >>>>>>>> +sub _zonefiles_load { >>>>>>>> + # Clean start >>>>>>>> + %zonefiles =3D (); >>>>>>>> + >>>>>>>> + # Source 1: Get the currently enabled zonefiles from rpz-config (e= xpected format [name]=3D[URL]) >>>>>>>> + my @enabled_files =3D &General::system_output('/usr/sbin/rpz-confi= g', '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 configur= ation 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-confi= g. 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 o= r 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{'bl= ock'}{'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 disab= led >>>>>>>> +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::t= r{'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::t= r{'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 value= s (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'}: <img src=3D"/blob.gif" a= lt=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: <img src=3D"/blob.gif" alt=3D"*"></td> >>>>>>>> + <td><input type=3D"url" name=3D"ZF_URL" value=3D"$cgiparams{'ZF_UR= L'}" 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{'Z= F_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"*"> $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'}{'l= ist'}}); >>>>>>>> + $cgiparams{'BLOCK_LIST'} =3D join("\n", @{$customlists{'block'}{'l= ist'}}); >>>>>>>> + >>>>>>>> + $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{'r= pz cl allow info'}</td> >>>>>>>> + <td colspan=3D"2"><b>$Lang::tr{'rpz cl block'}</b><br>$Lang::tr{'r= pz cl block info'}</td> >>>>>>>> + </tr> >>>>>>>> + <tr> >>>>>>>> + <td colspan=3D"2"><textarea name=3D"ALLOW_LIST" class=3D"domainlis= t" cols=3D"45"> >>>>>>>> +$cgiparams{'ALLOW_LIST'}</textarea></td> >>>>>>>> + <td colspan=3D"2"><textarea name=3D"BLOCK_LIST" class=3D"domainlis= t" 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::t= r{'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 but= ton >>>>>>>> + 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', $ac= tion_key, '--no-reload'); >>>>>>>> + } else { >>>>>>>> + $enabled =3D 'on'; >>>>>>>> + $result =3D &General::system('/usr/sbin/rpz-config', 'add', $actio= n_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 ent= ry >>>>>>>> + >>>>>>>> + # 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($nam= e) 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 $cgip= arams{'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_EN= ABLED'}) ? 'on' : 'off'; >>>>>>>> + $customlists{'block'}{'enabled'} =3D (defined $cgiparams{'BLOCK_EN= ABLED'}) ? '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 failur= e. Check for non-zero results. >>>>>>>> +# listref =3D array reference, cleanup =3D remove invalid entries i= nstead 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(a)ipfire.org> = # >>>>>>>> +# = # >>>>>>>> +# This program is free software: you can redistribute it and/or mod= ify # >>>>>>>> +# 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/license= s/>. # >>>>>>>> +# = # >>>>>>>> +###################################################################= ############ >>>>>>>> + >>>>>>>> +###################################################################= ############ >>>>>>>> +# Definitions >>>>>>>> +###################################################################= ############ >>>>>>>> + >>>>>>>> +include Config >>>>>>>> + >>>>>>>> +SUMMARY =3D response policy zone - RPZ reputation system for unb= ound 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-fu= nctions} \ >>>>>>>> + --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/i= ncludes/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(a)ipfire.org> = # >>>>>>>> +# = # >>>>>>>> +# This program is free software: you can redistribute it and/or mo= dify # >>>>>>>> +# it under the terms of the GNU General Public License as publishe= d by # >>>>>>>> +# the Free Software Foundation, either version 3 of the License, o= r # >>>>>>>> +# (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 Licens= e # >>>>>>>> +# along with this program. If not, see <http://www.gnu.org/licens= es/>. # >>>>>>>> +# = # >>>>>>>> +###################################################################= ############ >>>>>>>> +# >>>>>>>> +. /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(a)ipfire.org> = # >>>>>>>> +# = # >>>>>>>> +# This program is free software: you can redistribute it and/or mo= dify # >>>>>>>> +# it under the terms of the GNU General Public License as publishe= d by # >>>>>>>> +# the Free Software Foundation, either version 3 of the License, o= r # >>>>>>>> +# (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 Licens= e # >>>>>>>> +# along with this program. If not, see <http://www.gnu.org/licens= es/>. # >>>>>>>> +# = # >>>>>>>> +###################################################################= ############ >>>>>>>> +# >>>>>>>> +. /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: Connect= ion 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(a)ipfire.org> = # >>>>>>>> +# = # >>>>>>>> +# This program is free software: you can redistribute it and/or mo= dify # >>>>>>>> +# it under the terms of the GNU General Public License as publishe= d by # >>>>>>>> +# the Free Software Foundation, either version 3 of the License, o= r # >>>>>>>> +# (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 Licens= e # >>>>>>>> +# along with this program. If not, see <http://www.gnu.org/licens= es/>. # >>>>>>>> +# = # >>>>>>>> +###################################################################= ############ >>>>>>>> +# >>>>>>>> +. /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 >>>>>>>> --=20 >>>>>>>> 2.39.5 >>>>>>>> >>>>>>> >>>>>> >>>>>> Jon >>>>>> >>>>>> >>>>>> --=20 >>>>>> Jon Murphy >>>>>> jon.murphy(a)ipfire.org >>>> >>>> >>>> Jon >>>> >>>> >>>> --=20 >>>> Jon Murphy >>>> jon.murphy(a)ipfire.org >=20 >=20 --===============1659952175765241016==--