Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

REPLY_ADDR4/6 has multiple purposes #1291

Closed
pdc1 opened this issue Jan 29, 2022 · 9 comments · Fixed by #1293
Closed

REPLY_ADDR4/6 has multiple purposes #1291

pdc1 opened this issue Jan 29, 2022 · 9 comments · Fixed by #1293

Comments

@pdc1
Copy link

pdc1 commented Jan 29, 2022

Versions

  • Pi-hole version is v5.8.1 (Latest: v5.8.1)
  • AdminLTE version is v5.10.1 (Latest: v5.10.1)
  • FTL version is v5.13 (Latest: v5.13)

Platform

  • OS and version: Debian Buster
  • Platform: Raspberry Pi 4B

Expected behavior

A clear and concise description of what you expected to happen.

Background: I use a server called pixelserv-tls that handles ad domains. It returns a transparent 1x1 (pixel) image, and it handles spoofing HTTPS. This server runs on my router using a distinct IP address (10.0.0.2) separate from DHCP and any other host. This allows ads to be replaced with a transparent gif, which hides them more effectively than blocking with other methods.

I specify the following in pihole-FTL.conf:

BLOCKINGMODE=IP-NODATA-AAAA
REPLY_ADDR4=10.0.0.2

Expected behavior is that ads are forwarded to REPLY_ADDR4. Implied in this expectation is that DNS for the pihole server address continues to return the actual IP address.

Actual behavior / bug

A clear and concise description of what the bug is.

The blocking mode functions as expected, but the pihole DNS returns its own IP address as 10.0.0.2!

This causes all kinds of problems, as you can expect, since clients are attempting to connect to a different (and largely non-functional) server.

Steps to reproduce

Steps to reproduce the behavior:

  1. Configure pihole-FTL.conf with the following lines:
BLOCKINGMODE=IP-NODATA-AAAA
REPLY_ADDR4=10.0.0.2
  1. Observe that DNS for the the local server hosting pihole returns the REPLY_ADDR4 value instead of the server's actual IP address:
; <<>> DiG 9.11.5-P4-5.1+deb10u6-Raspbian <<>> @localhost raspi4
; (2 servers found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 33592
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;raspi4.				IN	A

;; ANSWER SECTION:
raspi4.			0	IN	A	10.0.0.2

;; Query time: 0 msec
;; SERVER: 127.0.0.1#53(127.0.0.1)
;; WHEN: Sat Jan 29 15:09:23 CST 2022
;; MSG SIZE  rcvd: 51

Debug Token

  • URL: N/A

Screenshots

If applicable, add screenshots to help explain your problem.
N/A

Additional context

Add any other context about the problem here.

I first configured this in FTL v5.8, which I was excited to see included the option to forward to a specified address. Now that I see the current config documentation, I have the feeling that even though REPLY_ADDR4/6 allows redirecting ad sites, there are other uses for the configuration that are most certainly not what I want.

I wrote this as a bug since this it appears that REPLY_ADDR4/6 is being used for two different purposes that, for me, are in conflict. If the current behavior is intentional I can resubmit this as a feature request. What I really want is the ability to configure the IP address returned for BLOCKINGMODE=IP-NODATA-AAAA that is independent of the pihole server address.

I copied the content below from a different issue, I think it explains why this worked in FTL v5.8 but not since. A change was introduced with FTL v5.9, emphasis added:

Interface-dependent handling of pi.hole and the machine’s hostname
This makes FTL automatically reply with the appropriate IP address to both pi.hole and the machines hostname. Before this change, FTL always used a hard-coded address set during the weekly gravity updates (pihole -g). The new method is interface-aware and may reply with different addresses on different interfaces (e.g. Ethernet, WiFi or Wireguard network). The address FTL replies with can be overwritten using the REPLY_ADDR4/6 settings in /etc/pihole/pihole-FTL.conf.

@DL6ER
Copy link
Member

DL6ER commented Jan 30, 2022

This is expected and designed behavior. In addition to the documentation, the code is even more explicit about that this should be the IP address of your Pi-hole:

FTL/src/config.c

Lines 505 to 507 in 7387e81

// REPLY_ADDR4
// Use a specific IP address instead of automatically detecting the
// IPv4 interface address a query arrived on

The feature was mainly meant for Pi-holes running in virtualization containers (such as docker) that, depending on their networking configuration, may not be allowed to determine the IP address of the network interface outside of the container.
This can only be achieved with an additional setting.

Pointing blocked IPs to a foreign server that is not identical with the Pi-hole itself does seem like a valid use case, however, let me still ask why you are running the pixelserv-tls on a dedicated machine in the first place?


Let's skip the feature request and immediately start trying this new feature using

pihole checkout ftl new/force_ip46

Please change your config from

BLOCKINGMODE=IP-NODATA-AAAA
REPLY_ADDR4=10.0.0.2

to

BLOCKINGMODE=IP-NODATA-AAAA
FORCE_IP4=10.0.0.2

The new option allows for the following configurations (IP blocking mode assumed):

  • Neither REPLY_ADDR nor FORCE_IP set
    Hostname address inferred from the interface, same in IP blocking mode (preserving current behavior)
  • Only REPLY_ADDR specified
    This address is both used for the hostname and blocked domains (preserving current behavior)
  • Only FORCE_IP set
    Hostname infers from the interface, FORCE_IP address is used for blocked domains
  • REPLY_ADDR and FORCE_IP set
    REPLY_ADDRis used for the hostname,FORCE_IP` for blocked domains

I'd appreciate it if you could test this new feature as much as you can!

@pdc1
Copy link
Author

pdc1 commented Jan 30, 2022

Pointing blocked IPs to a foreign server that is not identical with the Pi-hole itself does seem like a valid use case, however, let me still ask why you are running the pixelserv-tls on a dedicated machine in the first place?

I'm not sure what alternative you have in mind, but it needs to be a separate IP address since requests are generally going to be http/https, and I already have ports 80/443 in use for local web services. I suppose I could figure out some approach based on source address and route external requests to a pixelserv reverse proxy, but it was very easy to just install pixelserv-tls on my router using Entware and send all blocked traffic to that IP address.

Thanks so much for implementing/prototyping a solution!! 😎 From a naming perspective I would suggest including something about blocking so maybe BLOCKING_FORCE_IP4/6?

As a side comment, this text in the current description of IP blocking does not seem completely accurate given this configuration:

The block page can only be displayed for unencrypted http connections. Since the majority of web pages today are accessed over encrypted https connections, no block page will be displayed. This option may be removed in the future.

Now https spoofing is obviously an advanced (and possibly controversial) configuration, and I can see you may not want to mention that, but I hope the option is not removed regardless. The cert spoofing does not always work (it's increasingly common for sites to check their cert and so the handshake fails) but it still works often enough to be useful. And of course I'm not serving a block page but a one pixel transparent gif.

If it would help I'd be happy to help with documentation, though I would need some hand-holding on how exactly.

I'd appreciate it if you could test this new feature as much as you can!

Absolutely! I put this on a test server, and I am not getting the local host name resolved from localhost (the local server is "snack"). Other hosts in my local network are still resolved (e.g. "lunch"). If I do dig @snack snack from other hosts it works as expected, so maybe it's just something specific about localhost (looks like IPv6 localhost at that, might ?).

From the pihole host:

  • dig @localhost snack - returns no data?
Jan 30 11:34:39 dnsmasq[708051]: query[A] snack from ::1
Jan 30 11:34:39 dnsmasq[708051]: Pi-hole hostname snack is NODATA
  • dig @127.0.0.1 snack - returns 127.0.0.1
Jan 30 11:35:51 dnsmasq[708051]: query[A] snack from 127.0.0.1
Jan 30 11:35:51 dnsmasq[708051]: Pi-hole hostname snack is 127.0.0.1
  • dig @localhost lunch - works as expected
Jan 30 11:36:36 dnsmasq[708051]: query[A] lunch from ::1
Jan 30 11:36:36 dnsmasq[708051]: forwarded lunch to 10.0.0.8
Jan 30 11:36:36 dnsmasq[708051]: reply lunch is 10.0.0.50
  • dig @localhost google.com - works as expected
Jan 30 11:36:47 dnsmasq[708051]: query[A] google.com from ::1
Jan 30 11:36:47 dnsmasq[708051]: forwarded google.com to 10.0.0.8
Jan 30 11:36:47 dnsmasq[708051]: reply google.com is 142.250.191.110

From a different host

  • dig @snack snack - works as expected
Jan 30 11:40:33 dnsmasq[708051]: query[A] snack from 10.0.0.3
Jan 30 11:40:33 dnsmasq[708051]: Pi-hole hostname snack is 10.0.0.4

I'm not quite sure why the IPv6 localhost returns no-data, might that be due to my blocking mode BLOCKINGMODE=IP-NODATA-AAAA? Or perhaps that is expected?

Otherwise it is working great! I'm going to make this change on my primary pihole, and will let you know if I see any oddities.

Thanks again! 👍

@DL6ER
Copy link
Member

DL6ER commented Jan 30, 2022

From a naming perspective I would suggest including something about blocking so maybe BLOCKING_FORCE_IP4/6?

Yeah, I'm not happy with my choice, either, but I'm also not yet convinced by yours. Let's throw a few things at the wall and see what sticks.

If it would help I'd be happy to help with documentation, though I would need some hand-holding on how exactly.

We'd appreciate this! The documentation is open source itself and hosted at https://github.com/pi-hole/docs - check out the directory docs/ for the entire source code of the documentation. Any pull requests can be made against branch master and will receive a dedicated demo/preview link once a pull request is opened.


The dig @::1 pi.hole case is indeed broken - not by this branch but in general in development. Thanks for discovering this!
It is caused by an optimization that skipped interface analysis when the IPv6 address is unspecified (all zero). This is meaningful, however, this particular test actually checked only the first 32 of the 128 IPv6 bits. The loopback address indeed is all zero in the first 32 bits and, hence, triggered this shortcut where it shouldn't have. I just pushed a commit to the branch that will fix this, too.

@pdc1
Copy link
Author

pdc1 commented Jan 30, 2022

I did some brainstorming on the new variable name, and it's tricky because "IP" can refer to both the blocking mode and the reply address. I saw some other variables with a BLOCK prefix, so I thought a prefix of BLOCK_IP might work (or possibly IP_MODE). And then I thought, given its relation to REPLY_ADDR4/6, how about BLOCK_IP_REPLY_ADDR4/6 (or IP_MODE_REPLY_ADDR4/6)?

My other ideas were BLOCK_IP_MODE_ADDR4/6 or BLOCK_IP_ANSWER4/6, maybe those will help... Naming is hard!

Pretty cool this helped find a bug to boot!

@dschaper
Copy link
Member

If one is for pi.hole's response and one is for IP response:

PI_HOLE_IPV4/6 and BLOCK_RESPONSE_IPV4/6?

@pdc1
Copy link
Author

pdc1 commented Jan 31, 2022

@dschaper great insight! I like your approach, good idea to rename REPLY_ADDR as well.

Just to see how this looks, I copied your examples into @DL6ER's sample documentation:

  • Neither PI_HOLE_IPV4/6 nor BLOCK_RESPONSE_IPV4/6 set
    Hostname address inferred from the interface, same in IP blocking mode (preserving current behavior)
  • Only PI_HOLE_IPV4/6 specified
    This address is both used for the hostname and blocked domains (preserving current behavior)
  • Only BLOCK_RESPONSE_IPV4/6 set
    Hostname infers from the interface, BLOCK_RESPONSE_IPV4/6 address is used for blocked domains
  • PI_HOLE_IPV4/6 and BLOCK_RESPONSE_IPV4/6 set
    PI_HOLE_IPV4/6 is used for the hostname, BLOCK_RESPONSE_IPV4/6 for blocked domains

I think that seems clear and reads well, those variable names work for me...

@DL6ER
Copy link
Member

DL6ER commented Feb 1, 2022

It's not only for pi.hole but also the hostname (with and without local domain). I'd hence propose LOCAL_IPV4/6 and a shorter BLOCK_IPV4/6

@DL6ER DL6ER changed the title REPLY_ADDR4/6 has multiple conflicting purposes REPLY_ADDR4/6 has multiple purposes Feb 1, 2022
@yubiuser yubiuser linked a pull request Feb 1, 2022 that will close this issue
5 tasks
@pdc1
Copy link
Author

pdc1 commented Feb 1, 2022

My only concern with BLOCK_IPV4/6 is to me it sounds a bit like pihole is blocking that IP rather than it is the response of the blocking. To that end I like the longer BLOCK_RESPONSE_IPV4/6 but I am okay either way. Thanks for the engagement! 😎

@yubiuser
Copy link
Member

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants