provide option to include private IP addresses
Hello!
I use caddy-dynamicdns to enable ddns on my private network/VPN (via Tailscale). Unfortunately, the change in #61 regresses my use case since private IPs are no longer returned by ip_source interface.
I'm able to work around this with a custom caddy module to provide a new IPSource. However, after seeing @jm355 call out my exact use case https://github.com/mholt/caddy-dynamicdns/issues/59#issuecomment-1984940664_ I wanted to track this for posterity should anyone else run into this!
@Monviech's suggestion in #59 to include a include_private_ips flag sounds good to me. I'm happy to get started on a PR, unless maintainers have a better idea 🙂
Heh, I guess that will work then. :+1: Want to submit a PR?
I'm not sure what happens if both a public and private ip gets returned. Based on the name include_private_ips, I'm guessing it would return both, so maybe calling it something else like only_private_ips and only returning a private ip might be better? Just a minor nitpick/pointer, and it's been a while since I looked at this so I'm not sure
Good point. It's almost like you'd need to toggle public/private, but not have both.
If I'm reading it correctly issue 59 describes situations where there may even be multiple private IPs assigned to an interface. In this scenario the user is probably only interested in one of them (or rather one ipv4, one ipv6), and so a flag to use private IPs doesn't necessarily solve the problem.
However I think that people looking to find a private IP will know the subnet it is expected to be in.
So how about a more general solution then: include_subnets which can take one or more ipv4/ipv6 CIDR ranges, and will discard IPs outside of those ranges. If include_subnets is not specified then we take the default behavior of ignoring private IPs. I think it's a nice bonus that this also acts as a bit of a sanity check on the sourced IP.
Either way I'd like to work on a PR, but let me know if I'd be stepping on your toes @tylervick as it's been a few months so I assume you haven't found the time.
That sounds good to me but I haven't looked closely, it's been a while, and I'm no expert on ip addresses. Might also make sense to have an exclude_subnets option, if for example you want to explicitly exclude link-local addresses (fe80::/10) or any other subnet(s)
Yes that makes sense, and this also makes the default behaviour easily expressible with an explicit config which I think ties it together a bit more nicely.
I'm not super familiar with caddy and caddyfile syntax, but I assume the end result here wants to look something like:
ip_source interface lan {
include_subnets "192.168.1.0/24" "whatever"
exclude_subnets "blah"
}
Where the trailing block is optional? If that makes sense to you as a starting point then I'll just jump in.
Although now I'm wondering if this would make sense to lift out of the ip_source.interface config so that it could be applied to other IP sources too. Would that be useful... Well I'll take a closer look how everything works before I start to ask too many questions I don't have the context for.
The other nice thing about having an exclude/include subnet option is that because the normal "permanent" ipv6 address postfix is based on your mac address iirc, but your prefix may come from your isp and be subject to change, you can explicitly use/not use the "static" address postfix by including/excluding ::1234:5678:9abc:def0/::ffff:ffff:ffff:ffff
Keep in mind this formatting could be way off, I'm having trouble finding info online about the proper syntax for filtering out the prefix but keeping the postfix
Ah that's interesting. I also am no expert on ipv6, but I can't find any reference to this syntax or any indication that it's at all standardised. In fact I see at least one alternative non-standard solution used by e.g. nftables here https://michael.kjorling.se/blog/2024/prefix-agnostic-ipv6-address-filtering-in-linux-nftables/
Your way is a bit nicer to use than that, but still perhaps non standard? In any case I can start by shooting for basic CIDR ranges and see where it goes.
I don't remember the exact thread, but I think I first learned of that format from a forum thread on freshtomato which you can use to port forward for certain ipv6 addresses. I also think it's justified because I saw a lot of cidr things saying that the /<number> format is equivalent to something like ffff:ffff:: which makes sense if it's just bitmasks
For sure, the logic of it makes sense and I like the idea. But it's the difference between using the standard lib CIDR parser and writing a bunch of parsing & bitmasking logic. It's not the most complex thing in the world but I'd rather not lump so much into the same PR for a first pass.