mirror of
https://codeberg.org/h3xx/you-dont-need-pihole.git
synced 2026-06-14 17:55:39 +00:00
Compare commits
No commits in common. "266c1bae3760d923d3e7553cec3a987833a86e1e" and "85d9a5feca07ede379ef69a06865f3e7a1d71970" have entirely different histories.
266c1bae37
...
85d9a5feca
5 changed files with 42 additions and 277 deletions
11
CHANGELOG.md
11
CHANGELOG.md
|
|
@ -7,13 +7,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
|
||||
## [Unreleased]
|
||||
|
||||
### Changed
|
||||
- Require Perl 5.12
|
||||
|
||||
### Fixed
|
||||
- Fix warning when writing blocklist to stdout.
|
||||
- Various script clean-ups
|
||||
|
||||
## [0.2.0] - 2023-06-19
|
||||
|
||||
### Added
|
||||
|
|
@ -35,7 +28,3 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
|
||||
## [0.1.0] - 2022-11-12
|
||||
Initial published version
|
||||
|
||||
[Unreleased]: https://codeberg.org/h3xx/you-dont-need-pihole/compare/v0.2.0...HEAD
|
||||
[0.2.0]: https://codeberg.org/h3xx/you-dont-need-pihole/compare/v0.1.0...v0.2.0
|
||||
[0.1.0]: https://codeberg.org/h3xx/you-dont-need-pihole/releases/tag/v0.1.0
|
||||
|
|
|
|||
51
README.md
51
README.md
|
|
@ -3,9 +3,7 @@
|
|||
**Network-wide DNS blocking without extra hardware.**
|
||||
|
||||
This project implements the ad-blocking functionality of a
|
||||
[Pi-hole](https://pi-hole.net) without needing any extra hardware. All you need
|
||||
is a Linux computer on your network. This might also work with a Mac OSX
|
||||
computer, but I haven't tested it.
|
||||
[Pi-hole](https://pi-hole.net) without needing any extra hardware.
|
||||
|
||||
A Pi-hole is a [Raspberry Pi](https://www.raspberrypi.com/) based "black hole"
|
||||
for Internet advertisements. It works by intercepting and answering DNS queries
|
||||
|
|
@ -24,20 +22,12 @@ You'll need `dnsmasq` installed for this.
|
|||
git clone --recursive https://codeberg.org/h3xx/you-dont-need-pihole.git /etc/you-dont-need-pihole
|
||||
```
|
||||
|
||||
2. Run `update.sh` to generate the initial blocklist:
|
||||
2. Run `update.sh` to generate the blocklist.
|
||||
|
||||
```sh
|
||||
/etc/you-dont-need-pihole/update.sh
|
||||
```
|
||||
3. Update `dnsmasq.d/01-you-dont-need-pihole.conf`, replacing `/etc/you-dont-need-pihole` with wherever the root
|
||||
of this project is installed to.
|
||||
|
||||
> [!IMPORTANT]
|
||||
> If you didn't use `/etc/you-dont-need-pihole` as the installation directory,
|
||||
> update `dnsmasq.d/01-you-dont-need-pihole.conf`, replacing
|
||||
> `/etc/you-dont-need-pihole` with wherever the root of this project is
|
||||
> installed to.
|
||||
|
||||
4. Add You Don't Need Pi Hole's `dnsmasq.d` configuration directory path to
|
||||
`dnsmasq.conf`:
|
||||
4. Add the configuration directory to `dnsmasq.conf`:
|
||||
|
||||
```sh
|
||||
echo 'conf-dir=/etc/you-dont-need-pihole/dnsmasq.d' >> /etc/dnsmasq.conf
|
||||
|
|
@ -46,32 +36,21 @@ echo 'conf-dir=/etc/you-dont-need-pihole/dnsmasq.d' >> /etc/dnsmasq.conf
|
|||
You can also copy or symlink `dnsmasq.d/01-you-dont-need-pihole.conf` if you need
|
||||
the config to live somewhere else.
|
||||
|
||||
5. Restart the `dnsmasq` service:
|
||||
5. Restart the `dnsmasq` service.
|
||||
|
||||
```sh
|
||||
# Debian & Ubuntu, RedHat & CentOS
|
||||
service dnsmasq restart
|
||||
```
|
||||
6. Make sure `53/udp` is unfirewalled.
|
||||
|
||||
6. Make sure `53/udp` is unfirewalled:
|
||||
7. Go into your router settings and change the IP addressed provied via DHCP to
|
||||
be your server's local IP address. [See this thread for a
|
||||
walkthrough.](https://discourse.pi-hole.net/t/how-do-i-configure-my-devices-to-use-pi-hole-as-their-dns-server/245)
|
||||
|
||||
```sh
|
||||
# Debian & Ubuntu, RedHat & CentOS
|
||||
sudo firewall-cmd --add-port=53/udp --permanent
|
||||
```
|
||||
|
||||
7. Go into your router settings and change the DNS IP address provided via your
|
||||
router's DHCP responses to be your server's (i.e. the one with You Don't
|
||||
Need Pi Hole) local IP address.
|
||||
[See this thread for a walkthrough.](https://discourse.pi-hole.net/t/how-do-i-configure-my-devices-to-use-pi-hole-as-their-dns-server/245)
|
||||
|
||||
8. Recommended: If you use the You Don't Need Pi Hole machine as a general
|
||||
computer, configure it to use the local `dnsmasq` daemon for client DNS
|
||||
queries. This is a good idea because it may save some network traffic
|
||||
8. Recommended: Configure your local machine to use the local `dnsmasq` daemon
|
||||
for client DNS queries, i.e. software running on the same server as
|
||||
`dnsmasq`. This is a good idea because it may save some network traffic
|
||||
depending on how your router works. Worst case scenario, it'll do nothing.
|
||||
|
||||
If your OS uses `dhcpcd` for network configuration (Slackware), you can add
|
||||
this line to your `/etc/dhcpcd.conf`:
|
||||
If your OS uses `dhcpcd` for network configuration, you can add this line to your
|
||||
`/etc/dhcpcd.conf`
|
||||
|
||||
```
|
||||
static domain_name_servers=127.0.0.1
|
||||
|
|
|
|||
|
|
@ -1,181 +0,0 @@
|
|||
#!perl
|
||||
use 5.012;
|
||||
use warnings FATAL => 'all';
|
||||
|
||||
use Test::More 'no_plan';
|
||||
|
||||
use FindBin qw//;
|
||||
my $changelog = "$FindBin::Bin/../CHANGELOG.md";
|
||||
my $braced_inner_r = qr/(?:[^\]\\]|\\.)*/;
|
||||
use constant PROJECT_GIT => 'https://codeberg.org/h3xx/you-dont-need-pihole';
|
||||
|
||||
SKIP: {
|
||||
my $clh;
|
||||
unless (open $clh, '<', $changelog) {
|
||||
skip("failed to open changelog file to test: $!");
|
||||
}
|
||||
my @cl_lines = <$clh>;
|
||||
close $clh;
|
||||
|
||||
ok(scalar @cl_lines,
|
||||
'changelog contains at least one line'
|
||||
);
|
||||
|
||||
my %end_links = _link_references(@cl_lines);
|
||||
my @reflinks = _ref_links(@cl_lines);
|
||||
|
||||
my @unresolved = _unresolved_links(\%end_links, \@reflinks);
|
||||
ok(!scalar @unresolved, ChangelogError->new('unresolved links', @unresolved));
|
||||
|
||||
my %unused_links = _unused_links(\%end_links, \@reflinks);
|
||||
ok(!scalar %unused_links, ChangelogError->new('unused end links', values %unused_links));
|
||||
|
||||
my @incorrect_links = _incorrect_end_links(\%end_links, \@reflinks);
|
||||
ok(!scalar @incorrect_links, ChangelogError->new('incorrect end links', @incorrect_links));
|
||||
|
||||
}
|
||||
|
||||
sub _link_references {
|
||||
my @lines = @_;
|
||||
my $end_link_r = qr/^\s*\[(?<key>$braced_inner_r)\]:\s*(?<url>.*?)\s*$/;
|
||||
my %end_links;
|
||||
my $line_number = 0;
|
||||
foreach my $line (@lines) {
|
||||
++$line_number;
|
||||
if ($line =~ $end_link_r) {
|
||||
$end_links{$+{key}} = {
|
||||
line_number => $line_number,
|
||||
url => $+{url},
|
||||
key => $+{key},
|
||||
};
|
||||
}
|
||||
}
|
||||
return %end_links;
|
||||
}
|
||||
|
||||
sub _ref_links {
|
||||
my @lines = @_;
|
||||
my $ref_link_r = qr/\[(?<text>$braced_inner_r)\]\[(?<key>$braced_inner_r)\]/;
|
||||
# Make sure not to catch:
|
||||
# - Normal links "[text](url)"
|
||||
# - End links "[key]: url"
|
||||
my $bare_ref_link_r = qr/\[(?<textkey>$braced_inner_r)\](?!\s*[(:])/;
|
||||
my @reflinks;
|
||||
my $line_number = 0;
|
||||
foreach my $line (@lines) {
|
||||
++$line_number;
|
||||
if ($line =~ $ref_link_r) {
|
||||
push @reflinks, {
|
||||
line_number => $line_number,
|
||||
text => $+{text},
|
||||
key => $+{key},
|
||||
};
|
||||
} elsif ($line =~ $bare_ref_link_r) {
|
||||
push @reflinks, {
|
||||
line_number => $line_number,
|
||||
text => $+{textkey},
|
||||
key => $+{textkey},
|
||||
};
|
||||
}
|
||||
}
|
||||
return @reflinks;
|
||||
}
|
||||
|
||||
sub _unused_links {
|
||||
my ($end_links, $reflinks) = @_;
|
||||
# Make a copy, lest we destroy data
|
||||
my %unused = %{$end_links};
|
||||
foreach my $link (@{$reflinks}) {
|
||||
my $key = $link->{key};
|
||||
delete $unused{$key};
|
||||
}
|
||||
return %unused;
|
||||
}
|
||||
|
||||
sub _unresolved_links {
|
||||
my ($end_links, $reflinks) = @_;
|
||||
my @unresolved;
|
||||
foreach my $link (@{$reflinks}) {
|
||||
my $key = $link->{key};
|
||||
unless (exists $end_links->{$key}) {
|
||||
push @unresolved, $link;
|
||||
}
|
||||
}
|
||||
return @unresolved;
|
||||
}
|
||||
|
||||
sub _incorrect_end_links {
|
||||
my ($end_links, $reflinks) = @_;
|
||||
my @versions_in_order;
|
||||
my %versions_seen;
|
||||
foreach my $link (@{$reflinks}) {
|
||||
my $key = $link->{key};
|
||||
if (_is_version($key) && !exists $versions_seen{$key}) {
|
||||
$versions_seen{$key} = 1;
|
||||
push @versions_in_order, $key;
|
||||
}
|
||||
}
|
||||
my %expected_links = (
|
||||
Unreleased => _make_tag_link("v$versions_in_order[0]", 'HEAD'),
|
||||
$versions_in_order[-1] => _make_tag_link("v$versions_in_order[-1]"),
|
||||
);
|
||||
foreach my $idx (0 .. ($#versions_in_order - 1)) {
|
||||
my $this_version = $versions_in_order[$idx];
|
||||
my $last_version = $versions_in_order[$idx + 1];
|
||||
$expected_links{$this_version} = _make_tag_link("v$last_version", "v$this_version");
|
||||
}
|
||||
|
||||
my @incorrect_links;
|
||||
while (my ($key, $link) = each %{$end_links}) {
|
||||
if (exists $expected_links{$key}) {
|
||||
my $got = $link->{url};
|
||||
my $expected = $expected_links{$key};
|
||||
if ($got ne $expected) {
|
||||
$link->{url_expected} = $expected;
|
||||
push @incorrect_links, $link;
|
||||
}
|
||||
}
|
||||
}
|
||||
return @incorrect_links;
|
||||
}
|
||||
|
||||
sub _make_tag_link {
|
||||
my ($before_tag, $after_tag) = @_;
|
||||
unless (defined $after_tag) {
|
||||
return sprintf '%s/releases/tag/%s', PROJECT_GIT, $before_tag;
|
||||
}
|
||||
return sprintf '%s/compare/%s...%s', PROJECT_GIT, $before_tag, $after_tag;
|
||||
}
|
||||
|
||||
sub _is_version {
|
||||
my $ver = shift;
|
||||
return $ver =~ /^[0-9.]+$/;
|
||||
}
|
||||
|
||||
package ChangelogError;
|
||||
use 5.012;
|
||||
use warnings FATAL => 'all';
|
||||
use overload '""' => '_as_string';
|
||||
|
||||
sub new {
|
||||
my ($class, $name, @data) = @_;
|
||||
return bless {
|
||||
_name => $name,
|
||||
_data => \@data,
|
||||
}, $class;
|
||||
}
|
||||
|
||||
sub _as_string {
|
||||
my $self = shift;
|
||||
my @all = ($self->{_name});
|
||||
foreach my $datum (@{$self->{_data}}) {
|
||||
my @out;
|
||||
foreach my $key (qw/ line_number key text url url_expected /) {
|
||||
if (defined $datum->{$key}) {
|
||||
push @out, "$key: $datum->{$key}";
|
||||
}
|
||||
}
|
||||
push @all, '- ' . (join ', ', @out);
|
||||
}
|
||||
return join "\n", @all;
|
||||
}
|
||||
|
|
@ -16,7 +16,6 @@
|
|||
use 5.012;
|
||||
use warnings;
|
||||
|
||||
use Carp qw/ croak /;
|
||||
use Getopt::Long qw/ GetOptions :config bundling no_getopt_compat no_ignore_case /;
|
||||
use FindBin qw//;
|
||||
|
||||
|
|
@ -24,26 +23,23 @@ my %domains;
|
|||
my $dupes = 0;
|
||||
my $skip = 0;
|
||||
my $removed_allowed = 0;
|
||||
|
||||
sub _add_domain_list {
|
||||
sub add_domain_list {
|
||||
my $file = shift;
|
||||
foreach my $line (_read_stripped($file)) {
|
||||
foreach my $line (read_stripped($file)) {
|
||||
my $domain = lc $line;
|
||||
if (defined $domains{$domain}) {
|
||||
++$dupes;
|
||||
}
|
||||
$domains{$domain} = 1;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
sub _add_host_file {
|
||||
sub add_host_file {
|
||||
my $file = shift;
|
||||
foreach my $line (_read_stripped($file)) {
|
||||
foreach my $line (read_stripped($file)) {
|
||||
my @parts = split /\s+/, $line;
|
||||
if (@parts < 2) {
|
||||
croak("Malformed line in $file: $line; @parts");
|
||||
}
|
||||
die "Malformed line in $file: $line; @parts"
|
||||
unless @parts > 1;
|
||||
if (lc $parts[0] eq lc $parts[1]) {
|
||||
++$skip;
|
||||
next;
|
||||
|
|
@ -58,30 +54,20 @@ sub _add_host_file {
|
|||
}
|
||||
$domains{$domain} = 1;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
sub _read_stripped {
|
||||
sub read_stripped {
|
||||
my $file = shift;
|
||||
|
||||
my @stripped_lines;
|
||||
my $add_stripped = sub {
|
||||
my $line = shift;
|
||||
chomp $line;
|
||||
# Strip whitespace and comments
|
||||
$line =~ s/^\s+|\s+$|\s*#.*$//;
|
||||
if ($line) {
|
||||
push @stripped_lines, $line;
|
||||
}
|
||||
};
|
||||
open my $fhi, '<', $file
|
||||
or croak("Failed to open file $file for reading: $!");
|
||||
open my $fni, '<', $file
|
||||
or die "Failed to open file $file for reading: $!";
|
||||
|
||||
while (my $line = <$fhi>) {
|
||||
$add_stripped->($line);
|
||||
}
|
||||
close $fhi;
|
||||
return @stripped_lines;
|
||||
map {
|
||||
chomp;
|
||||
# Strip whitespace and comments
|
||||
s/^\s+|\s+$|\s*#.*$//;
|
||||
$_ || ()
|
||||
} <$fni>;
|
||||
}
|
||||
|
||||
MAIN: {
|
||||
|
|
@ -101,36 +87,38 @@ MAIN: {
|
|||
my @allow_lists = glob "$workdir/allowlists/*.domains";
|
||||
|
||||
foreach my $listfile (@domain_lists) {
|
||||
_add_domain_list($listfile);
|
||||
add_domain_list($listfile);
|
||||
}
|
||||
foreach my $hostfile (@hosts_lists) {
|
||||
_add_host_file($hostfile);
|
||||
add_host_file($hostfile);
|
||||
}
|
||||
|
||||
# Apply allowlists
|
||||
my @allow_domains;
|
||||
foreach my $allowlist (@allow_lists) {
|
||||
push @allow_domains, _read_stripped($allowlist);
|
||||
push @allow_domains, read_stripped($allowlist);
|
||||
}
|
||||
my $before = %domains;
|
||||
delete %domains{@allow_domains};
|
||||
# Count number removed
|
||||
$removed_allowed = $before - %domains;
|
||||
|
||||
my @block_ip = sort split /\s+/, $block_ip;
|
||||
my $written = 0;
|
||||
my $fho = \*STDOUT;
|
||||
if (defined $out && length $out) {
|
||||
open $fho, '>', $out
|
||||
or croak("Failed to open file $out for writing: $!");
|
||||
or die "Failed to open file $out for writing: $!";
|
||||
}
|
||||
foreach my $domain (sort keys %domains) {
|
||||
print $fho map {
|
||||
my @block_ip = sort split /\s+/, $block_ip;
|
||||
print $fho map {
|
||||
++$written;
|
||||
my $domain = $_;
|
||||
map {
|
||||
"$_ $domain\n"
|
||||
} @block_ip;
|
||||
}
|
||||
close $fho;
|
||||
} sort keys %domains;
|
||||
|
||||
printf STDERR "%d domains written to %s from\n", (scalar %domains), $out // 'STDOUT';
|
||||
printf STDERR "%d domains written to %s from\n", $written, $out // 'STDOUT';
|
||||
printf STDERR " - %d .domains files\n", (scalar @domain_lists);
|
||||
printf STDERR " - %d .hosts files\n", (scalar @hosts_lists);
|
||||
if ($dupes) {
|
||||
|
|
|
|||
|
|
@ -1,10 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
WORKDIR=${0%/*}
|
||||
BASEDIR="$WORKDIR/.."
|
||||
cd "$BASEDIR" || exit
|
||||
|
||||
if ! prove 'dev-t'; then
|
||||
printf 'Developer tests failed!\n' >&2
|
||||
exit 1
|
||||
fi
|
||||
Loading…
Add table
Add a link
Reference in a new issue