TechnitiumSoftware / DnsServer

Technitium DNS Server
https://technitium.com/dns/
GNU General Public License v3.0
4.53k stars 431 forks source link

private IPs forwarding via ECS #978

Closed valerioxyz closed 2 months ago

valerioxyz commented 4 months ago

i am using 2 technitium dns servers (dns_1, dns_2) in a kubernetes cluster.

dns_1 has a conditional forwarding zone to dns_2. dns_2 returns an A record to the dns_1 which fires it back to the client. (ok so far)

Now, i created a Technitium App on the dns_1 that:

  1. changes question name (from test.example.com to aaa.bbb.it)
  2. writes a static IP in the ECS
  3. forwards the dns request to the dns_2.

The forwarding works. The question name change too. However, writing a static IP in the ECS gives sometimes problems. In particular, writing a private IP in the ECS returns 0.0.0.0/0 and not 192.168.1.1, for example.

FIRST DNS LOGS:

[2024-07-22 13:50:02 UTC] [10.30.10.40:34825] [UDP] QNAME: test.example.com; QTYPE: A; QCLASS: IN; RCODE: NoError; ANSWER: [192.168.1.1]; ECS: 10.168.1.1/32
[2024-07-22 13:50:04 UTC] [10.30.10.40:44921] [UDP] QNAME: test.example.com; QTYPE: A; QCLASS: IN; RCODE: NoError; ANSWER: [192.168.1.1]; ECS: 19.168.0.255/32
[2024-07-22 13:50:07 UTC] [10.30.10.40:33437] [UDP] QNAME: test.example.com; QTYPE: A; QCLASS: IN; RCODE: NoError; ANSWER: [192.168.1.1]; ECS: 10.168.1.1/32
[2024-07-22 13:50:08 UTC] [10.30.10.40:35668] [UDP] QNAME: test.example.com; QTYPE: A; QCLASS: IN; RCODE: NoError; ANSWER: [192.168.1.1]; ECS: 19.168.0.255/32

SECOND DNS LOGS:

[2024-07-22 13:50:02 UTC] [10.244.113.207:56714] [UDP] QNAME: aaa.bbb.com; QTYPE: A; QCLASS: IN; RCODE: NoError; ANSWER: [192.168.1.1]
[2024-07-22 13:50:04 UTC] [10.244.113.207:56168] [UDP] QNAME: aaa.bbb.com; QTYPE: A; QCLASS: IN; RCODE: NoError; ANSWER: [192.168.1.1]; ECS: 19.168.0.255/0
[2024-07-22 13:50:07 UTC] [10.244.113.207:46774] [UDP] QNAME: aaa.bbb.com; QTYPE: A; QCLASS: IN; RCODE: NoError; ANSWER: [192.168.1.1]; ECS: 0.0.0.0/0
[2024-07-22 13:50:08 UTC] [10.244.113.207:52718] [UDP] QNAME: aaa.bbb.com; QTYPE: A; QCLASS: IN; RCODE: NoError; ANSWER: [192.168.1.1]; ECS: 19.168.0.255/0

In the logs you can see the dns_1 only receives the ECS when it's not a private IP. Is it a known behaviour? Can i disable this feature?

ShreyasZare commented 4 months ago

Thanks for the post. I am not sure what you are trying to achieve here. It would be good if you can elaborate and explain why you need to use ECS option this way so that I can understand your scenario correctly.

The ECS implementation in the DNS server works only for public IP address. When private IP address is received, it will ignore it by design. This is done since ECS's purpose is to allow name servers to provide answers based on a user's geo location and allowing private IP in such queries does not make sense.

valerioxyz commented 4 months ago

The goal is dns_2 to view the ip of the client that does the request. Since the dns_1 overrides the client ip, i thought adding client ip as ECS field in the dns_1 and forward to dns_2

ShreyasZare commented 4 months ago

In that case, you should use PROXY Protocol. On dns_2 enable it from Settings > Optional Protocols to allow it to read client IP from requests and, use the same protocol to send the request in your app code on dns_1. The PROXY protocol implementation is already available in the TechnitiumLibrary.Net project which you can use.

valerioxyz commented 4 months ago

What if I have public addresses? Will ECS be automatically added to packet by dns_1 if EDNS Client Subnet (ECS) is enabled or should I still implement via an app?

ShreyasZare commented 4 months ago

For public IP address, it will be used but it wont be reported as the "client IP address" internally by the DNS server in the logs or on the Dashboard stats. It can only be used by DNS apps for example the Geo Continent, Geo Country, and Geo Distance apps use it to return optimal answer using IP location database.

ECS is not a proper tool to report client IP. Some DNS server software do use it for that purpose but its not designed for it. The PROXY Protocol was designed for this very purpose and works well without interfering with the ECS protocol.

Technitium DNS Server supports the PROXY protocol for inbound requests and will log correct IP of the actual client in logs. This can also be used with reverse proxy like nginx that support the PROXY protocol.

valerioxyz commented 4 months ago

can I bypass the ignore logic of private IPs via an APP? so the receiver dns (dns_2) parses the requestECS manually

ShreyasZare commented 4 months ago

can I bypass the ignore logic of private IPs via an APP? so the receiver dns (dns_2) parses the requestECS manually

If you are using IDnsAppRecordRequestHandler or IDnsAuthoritativeRequestHandler for your APP then you will get ECS data as-is in the request. The DNS Server will remove ECS data from requests only when it tries to do recursive resolution. So once the request is processed for recursive resolution, the ECS data will get removed and there wont be anything logged for the response.

Other issues will be that you wont see the client IP in the logs and desktop stats. Nor will features like query rate limiting will work to limit requests for such cases. The dns_1's IP address will be used in all these places. Which is why I would recommend that you use the PROXY protocol.

valerioxyz commented 4 months ago

I saw in the logs the ECS data is seen in dns_1 (even if private). So when dns_1 makes a recursive query to dns_2 it's the dns_1 that clears the field or the dns_2 that ignores it?

ShreyasZare commented 4 months ago

I saw in the logs the ECS data is seen in dns_1 (even if private). So when dns_1 makes a recursive query to dns_2 it's the dns_1 that clears the field or the dns_2 that ignores it?

The receiving server will not use the ECS and it will remove it from request when it tries to do recursive resolution.

valerioxyz commented 4 months ago

I saw in the logs the ECS data is seen in dns_1 (even if private). So when dns_1 makes a recursive query to dns_2 it's the dns_1 that clears the field or the dns_2 that ignores it?

The receiving server will not use the ECS and it will remove it from request when it tries to do recursive resolution.

Oh thanks! Where this behaviour is implemented? I can't find it in the repo

ShreyasZare commented 4 months ago

The receiving server will not use the ECS and it will remove it from request when it tries to do recursive resolution.

Oh thanks! Where this behaviour is implemented? I can't find it in the repo

You can check these lines in code.

For logging and other places where client IP address is used, its either directly sourced from the socket remote address or from the PROXY protocol.

ShreyasZare commented 4 months ago

It would also be best to know what your app is trying to achieve. I may be able to suggest an alternative way to achieve the same result.