Skip to content

Conversation

@Self-Hosting-Group
Copy link
Contributor

@Self-Hosting-Group Self-Hosting-Group commented Sep 18, 2024

Commits

As this PR is extensive, the descriptions of the individual commits are collapsed here:

update daemon to 2.3.9 to fix issues and refresh building
  • Update daemon to 2.3.9 to fix removal of nftables rules in upnp_forward and
    return the correct client port. This also resulted in the excessive opening of
    new ports
  • Build from GitHub releases to get a reliable HTTPS server, as the
    HTTP-only/HTTPS mirror were only available ~85%/77% over 3 months
    https://redirect.github.com/miniupnp/miniupnp/issues/770
    https://stats.uptimerobot.com/DwGDxUB914
  • Not in: Build from HTTP-only mirror of the project, as building from the HTTPS
    mirror was recently and frequently impossible
  • Not in: Build from GitHub tag archives, as release archive differ in code
    comments to the public repository, in project since 2012, makes backports more
    complex
  • Build daemon with --disable-pppconn to remove the old/IGDv1-only extra SSDP
    WANPPPConnection announcements workaround not included in other
    implementations since >15y
  • Build daemon with --vendorcfg to allow customisation of the router/friendly
    name (+5 potential options) displayed in Windows Explorer, 384 bytes extra
    required on ARMv7 (binary)
  • Remove old (iptables variant) patches: 200-remove-default-cflags as it
    compiles/runs without it, and 300-macos... as seems no longer needed
  • Remove clean_ruleset_interval/threshold UCI config options as not
    standard/working since OpenWrt 22.03, as nftables not supported

Fix: https://redirect.github.com/openwrt/openwrt/issues/18011
Fix: https://redirect.github.com/openwrt/luci/issues/7759

patch for UPnP IGD compatibility with Microsoft/Apple clients
  • Add workaround for listing port maps with Windows IGDv2-incompatible clients
    by returning an infinite (0) lease duration, so that listing and editing works
    via GUI (Explorer/Network) when daemon has been compiled with IGDv2
  • Detect Microsoft clients more specifically and add Xbox
  • Detect Apple IGDv2-incompatible clients and apply existing workaround Only
    caused problems if PCP/NAT-PMP (prioritised) was disabled

(proposed for inclusion)

Link: https://redirect.github.com/FreshTomato-Project/freshtomato-arm/issues/75

patch to fix description filter option

To fix the non-working description regex filter option

(proposed for inclusion)

Link: https://redirect.github.com/miniupnp/miniupnp/pull/853

new/revised UCI options and improve daemon init/config-gen

The following settings UCI options been added or changed, and the previous
options are migrated on the service restart:

upnpd.config UCI options Change Previous name
enabled Match default (1)
enabled_protocols=upnp-igd Combined option enable_upnp=1
enabled_protocols=pcp+nat-pmp Combined option enable_natpmp=1
allow_cgnat Allow allow-filtered (2) use_stun
stun_host Allow port inclusion (3)
stun_port Removed, included in host
allow_third_party_mapping=0 Inverted/extended to PCP secure_mode=1
log_output Allow info log level
lease_file Set by default + IPv6 (4) upnp_lease_file
upnp_igd_compat=igdv1 Renamed/match default (1) igdv1=1
download_kbps In kbit/s and renamed (5) download
upload_kbps In kbit/s and renamed (5) upload
friendly_name New option, router name
http_port Renamed, rem. if default port
notify_interval Removed if <900s, minimum
internal_iface Migrated, new section
internal_network UCI options Change Previous name
interface New option added
access_preset New option added (6)
accept_ports New option added (6)
reject_ports New option added (7)
custom_acl_before New option added (6)

Notes:

  1. Init UCI default now matches LuCI and initial config file defaults for:
    enabled=0 and upnp_igd_compat=igdv1
  2. Allow allow-filtered for IPv4 CGNAT use and migrate option from X-Wrt and
    only use STUN when necessary with a private/CGNAT external IPv4
  3. Remove known incompatible STUN servers and set compatible by default
  4. Configure undocumented daemon option lease_file6=${lease_file}-ipv6 so that
    active IPv6 port maps are not lost when service restarts, e.g. by deleting an
    active port map. Use /run path, symlinked and appeared in FHS 3.0 in 2015 and
    remove option if UCI default is set
  5. Gets converted, config file now defaults to interface link speed instead of
    8/4 Mbit/s, which is removed on migration
  6. New options added to select a preset for all devices on the network and
    decide if the custom ACL should be checked before the preset. Extra ports can
    also be set that are accepted/rejected. Presets:
    accept-high-ports/accept-high-ports+web[+dns]/accept-all-ports/0
  7. Reject ports regardless of other settings. By default reject unsafe: 21
    (FTP), 23 (Telnet), DCE/NetBIOS/SMB (135/137-139/445), RDP (3389)

Code refactoring:

  • Add a function for logging and output to stderr, and extend logging
  • Revise daemon init/config-gen slightly by declare all UCI options (incl.
    booleans) according to the same principle and remove upnpd_write_bool
  • Document and reformat default /etc/config/upnpd UCI config file

Related LuCI PR: https://redirect.github.com/openwrt/luci/pull/7822

Close: https://redirect.github.com/openwrt/packages/pull/26531

group/rearrange config-gen and refactoring
  • Group and rearrange UCI option declaration and config-gen by function/LuCI UI,
    and comment
  • Encode required XML entities of text UPnP IGD config options until the daemon
    does so using the created function xml_encode
  • Only generate UPnP IGD config if the protocol is enabled

(to merge with prior)

new/revised custom ACL UCI options and migrate section
  • Note that the custom ACL is now rejected by default, if it is alone used, with
    no preset or listed accepted ports. Add (ignored) custom ACL template entries
    on migration
  • Migrate custom ACL entries to the new section name acl_entry
  • The following custom ACL UCI options been added or changed, and the previous
    options are migrated on the service restart:
acl_entry UCI options Change Previous name
action New/updated values (1)
int_port Remove colon separator (2) int_ports
ext_port Remove colon separator (2) ext_ports
descr_filter New option added (3)
  1. Allow ignore, and update action option to use the nftables terms (allow/deny
    -> accept/reject). To avoid adding inverted actions when changing via LuCI,
    ensure any missing are set, as LuCI and UCI had not matching action defaults.
    Missing actions are now ignored/logged
  2. Ensure that the hyphen (-) is only used as a port range separator by
    migration, as the colon (:) is not valid in LuCI
  3. Add missing UCI option to set a regular expression to check for a UPnP IGD
    IPv4 port map description, and fix the current collision with the comment
    field which was not noticed due to a daemon bug
    https://redirect.github.com/openwrt/packages/pull/24495
    https://redirect.github.com/miniupnp/miniupnp/pull/853

Code refactoring:

  • Add a more universal usable is_port_or_range function instead of
    upnpd_get_port_range and check if it has a valid range, and removes a
    shellcheck warning
  • Rename conf_rule_add function to upnpd_add_custom_acl_entry
rename UCI section name to `settings` (v2.0)

Inspired/address copilot's PR review for a clearer config by rename UCI section
name config (v1.0) -> settings (v2.0), helps on migration and to distinguish
the updated config from the previous one easily

(to merge with prior)

refactoring by separate service start and config-gen
  • Remove config_foreach upnpd "upnpd" and replace it with regular function
    call, as init was not designed for a multi-instance setup, as the same
    tmpconf will be used/overwritten, and non-anonymous section
  • Move code to make the custom vs. config file generation decision earlier, and
    only perform external interface detection with the second one, and rename
    function upnpd to upnpd_generate_config
  • Replace unnecessary if cases with elif in init/hotplug
  • Exit with 1 on errors to get an inactive service status
  • Do not restart daemon in hotplug when using a custom config file, as then this
    file will not be regenerated on restarts

(to merge with prior)

rearrange init functions

Arrange start_service and main init functions first

(to merge with prior)

(The italic commits are intended to be merged with the previous ones after review.)

Screenshots

The new network-wide access control functionality can best be described using the LuCI screenshots:

Enabled Networks / Access Control luci-network-list
Edit network access control settings luci-network-edit
Advanced Settings tab with new CGNAT functionality luci-advanced
New UPnP IGD Adjustments tab luci-igd
LuCI notification if the related package is not updated luci-notification
Full LuCI screenshot luci-screenshot

Related LuCI PR: openwrt/luci#7822

Tested on: OpenWrt 24.10.4

The Port Control Protocol (PCP) is the successor to NAT-PMP, shares similar protocol concepts and packet formats, but supports IPv6 port mapping and options/extensions. For more information, see:
Port Mapping Protocols Overview and Comparison 2025: About UPnP IGD & PCP/NAT-PMP
https://github.com/Self-Hosting-Group/wiki/wiki/Port-Mapping-Protocols-Overview

@Self-Hosting-Group Self-Hosting-Group force-pushed the miniupnpd-uci-revision branch 3 times, most recently from 618ed1f to 6da251a Compare October 1, 2024 08:21
@Self-Hosting-Group Self-Hosting-Group marked this pull request as ready for review October 1, 2024 09:06
@Neustradamus
Copy link

@Self-Hosting-Group: Nice PR!

cc: @systemcrash

@Self-Hosting-Group Self-Hosting-Group force-pushed the miniupnpd-uci-revision branch 3 times, most recently from cfbf68e to cb7a02d Compare December 17, 2024 07:14
@Self-Hosting-Group Self-Hosting-Group force-pushed the miniupnpd-uci-revision branch 2 times, most recently from cc180f0 to 86f6935 Compare January 6, 2025 09:53
@Self-Hosting-Group Self-Hosting-Group changed the title miniupnpd: Revise several upnpd UCI configuration options and defaults miniupnpd: Daemon hotfix for 24.10 and revise several upnpd UCI config options Jan 6, 2025
@systemcrash
Copy link
Contributor

A downgrade included in a patchset won't get accepted, since a downgrade may subtly reintroducing bugs for existing users, if we assume that point releases fix bugs only. Better to wait for a new release, and bump to that version.

Migrations are probably a more serious matter: those must be carried basically 'forever'. The best way is simply to avoid those. One might introduce a new setting, and deprecate the old one, and change the UI over to use the new one. Still a bit of a bumpy road.

I think personally this is minor in the grand scheme of things (rather unimportant settings), but other reviewers may take a much firmer stance on it since you are, after all, changing setting names.

@systemcrash
Copy link
Contributor

What do you think about backporting the commit?

Acceptable. It just breaks compile at the next release bump when it no longer applies. Minor, I guess.

@systemcrash
Copy link
Contributor

Every single test-build failed: Dirty patches detected, please refresh and review the diff

@Self-Hosting-Group Self-Hosting-Group force-pushed the miniupnpd-uci-revision branch 10 times, most recently from 6eaafdb to 50eda40 Compare January 17, 2025 13:45
Self-Hosting-Group added a commit to Self-Hosting-Group/luci that referenced this pull request Jan 17, 2025
Self-Hosting-Group added a commit to Self-Hosting-Group/luci that referenced this pull request Jan 20, 2025
Arrange `start_service` and main init functions first

(to merge with prior)

Signed-off-by: Self-Hosting-Group <[email protected]>
@Self-Hosting-Group
Copy link
Contributor Author

Hello @BKPepe. Now, no new pushes to this repository, package works well! Finally, some code was moved and now I think is the right time to review the following commits. ;-) The mirror issues are addressed by using the official GitHub releases, see below. And thanks for your comments.

PKG_SOURCE_URL:=https://github.com/miniupnp/miniupnp/releases/download/miniupnpd_$(shell echo $(PKG_VERSION) | tr "." "_")

  • The commits were recreated in a better order, and are easier to review
  • Thanks to optimisations, the additional code for the new features in init is only ~37 lines, not counting the migration code
  • I have deleted the comment with the questions. Because everything, including the separate service start and config-gen, and cancel earlier if no migration is necessary, has now been implemented or has been resolved in the meantime

In my eyes, everything fits, and I don't see anything else that needs to be done.
The optimisations took a while, but it's now ready for review.

I've looked right now at only one commit, which should be quick and the easiest one to get merged: aa7e58c

Yes, this commit was intended for cherry-picking, as were the two LuCI commits, as preparation to display a message to update in the event of an unsuitable config file being found, and get prepared for the section change. These commits have no dependencies.

Daemon PR:

  1. update daemon to 2.3.9 to fix issues and refresh building
  2. patch for UPnP IGD compatibility with Microsoft/Apple clients
  3. patch to fix description filter option
  4. new/revised UCI options and improve daemon init/config-gen
  5. group/rearrange config-gen and refactoring
  6. new/revised custom ACL UCI options and migrate section
  7. rename UCI section name to settings (v2.0)
  8. refactoring by separate service start and config-gen
  9. rearrange init functions

LuCI PR:

  1. improve existing UI slightly
  2. add UPnP IGD Adjustments tab, rearrange as many options
  3. ui redesign and adapt to new/revised package UCI options
  4. new/revised custom ACL UCI options and migrate section
  5. rename UCI section name to settings (v2.0)

(The commits in bold were for cherry-picking, and those in italics were intended to be merged with the previous commit.)

This PR has now implemented all the functions, from my point of view. The following LuCI screenshots are provided to help you understand the new/extended network-wide access control functionality during the review process. Thanks to the universal implementation of the acl_accept_ports/acl_reject_ports options, this functionality provides a more powerful and useful alternative to existing custom ACL entries in many user cases.

The new network-wide access control functionality can best be described using the LuCI screenshots:

Enabled Networks / Access Control luci-network-list
Edit network access control settings luci-network-edit
Advanced Settings tab with new CGNAT functionality luci-advanced
New UPnP IGD Adjustments tab luci-igd
LuCI notification if the related package is not updated luci-notification
Full LuCI screenshot luci-screenshot

@Self-Hosting-Group
Copy link
Contributor Author

Hello @BKPepe. Please review the following commits. UPnP IGD daemon compatibility patch added. An enhancement tag has been added in the meantime, which also fits with the PR.

@Self-Hosting-Group
Copy link
Contributor Author

Self-Hosting-Group commented Nov 10, 2025

Hello @systemcrash.

  1. Could you please advise on the wording for the additional tab in LuCI? I have currently named it UPnP IGD Adjustments. Now I would like to to add a header with the same name in OPNsense.
    I used a different word to Settings because these options are rarely changed and are usually just for adjusting reported values, such as the friendly name. The following options are included: download_kbps, upload_kbps, friendly_name, model_number, serial_number, presentation_url, uuid, http_port, notify_interval.
    (italic options are now hidden in LuCI, and upnp_igd_compat is exceptionally in Service Setup)
    I am OK with the current wording, but perhaps you have a suggestion for a better and shorter alternative?

  2. The same for this UI option:
    UPnP IGD compatibility mode (shorter/better wording?)
    Report a specific device to workaround IGDv2-incompatible clients (or) Act/emulate as a specific/different device to workaround/support/handle/bypass/assist/mitigate IGDv2-incompatible clients (alternative text welcome)
    Options:

  • IGDv1 (IPv4 only)
  • IGDv2 (with workarounds)
  1. Custom Access Control List: Good wording and capitalisation? Also for for Service Setup, Advanced Settings and Enabled Networks / Access Control? Is there a guideline for the capitalisation in headlines and tabs?

This would help me a lot to continue working on OPNsense and to complete the PR there next week. I also think that some standardisation between new introduced options in the router OSs makes sense.

@Self-Hosting-Group
Copy link
Contributor Author

@BKPepe As you can see, the rate of change has slowed down. This time, only a few of the UCI option names were shortened, with no code changes. No bugs have been found for months!

@Self-Hosting-Group
Copy link
Contributor Author

PR description updated

@Self-Hosting-Group
Copy link
Contributor Author

Hello @Rondom @kilroy98 @AquanJSW @Neustradamus

You all responded positively to my PR description. I think it will increase the reviewer's confidence if not only I have tested the new, revised daemon and LuCI packages in practice, but also if you find the new functionality useful for your user cases.

If you do not have an OpenWrt build environment for creating the new packages, I can compile them for easy installation if you wish. To do this, I need the router's Target Platform (from Status/Overview).

@AquanJSW
Copy link
Contributor

Just compiled and tested on my machine, it seems to be working fine.
But no plan to add ext_allow_private_ipv4 related option?

@Self-Hosting-Group
Copy link
Contributor Author

Great! ;-) Thanks for testing.

Just compiled and tested on my machine, it seems to be working fine. But no plan to add ext_allow_private_ipv4 related option?

# Commented out as allow-filtered detects a public IPv4, required by some (e.g. PCP/NAT-PMP) clients
# [ "$allow_cgnat" = "allow-private-ext-ipv4" ] && external_ip=203.1.2.3

Setting the existing UCI option external_ip to, e.g., 203.1.2.3 (public IPv4) is a better solution in terms of client compatibility than using ext_allow_private_ipv4=yes.

The ext_perform_stun=allow-filtered daemon option, which was added shortly afterwards (my contribution, unfortunately not published under my name because the maintainer (@miniupnp) blocked me), is IMHO better, as it returns the correct IPv4.

Even though ext_allow_private_ipv4=yes option had to be corrected after its introduction and unexpectedly changed the logging (new issue), I am no longer sure whether it should have been introduced at all, with all this trouble and regression. I know of others that were recently introduced, but the maintainer does not want me to submit them to get resolved.

And the reason why allow-filtered with STUN is necessary at all under OpenWrt with an unrestricted endpoint-independent IPv4 CGNAT is that the CGNAT test in the daemon has always been badly implemented. This requires that all UDP ports (random test ports) on the external IPv4 are open, which is not the case in any modern route OS for security reasons, instead of what would make much more sense, namely adding regular port maps to itself (internal IP) for the test, which would then work directly everywhere. This idea was also well received by a FreeBSD developer.

Screenshot of Advanced Settings tab with new CGNAT functionality luci-advanced

@Self-Hosting-Group
Copy link
Contributor Author

(PS: I also heard about a recent bug bounty where a user liked a bug fix, but he gave up on his plan after contacting the maintainer, who maybe have lost interest in the project.)

@Neustradamus
Copy link

@Self-Hosting-Group: Good job since more one year about it.
I hope to see the merging one day!
Maybe you can update the title, it is not only for 24.10...

To test with Tailscale. Also adds the required daemon fix

(proposed for inclusion, to merge with prior)

Signed-off-by: Self-Hosting-Group <[email protected]>
@AquanJSW
Copy link
Contributor

AquanJSW commented Nov 11, 2025

Great! ;-) Thanks for testing.

Just compiled and tested on my machine, it seems to be working fine. But no plan to add ext_allow_private_ipv4 related option?

# Commented out as allow-filtered detects a public IPv4, required by some (e.g. PCP/NAT-PMP) clients
# [ "$allow_cgnat" = "allow-private-ext-ipv4" ] && external_ip=203.1.2.3

Setting the existing UCI option external_ip to, e.g., 203.1.2.3 (public IPv4) is a better solution in terms of client compatibility than using ext_allow_private_ipv4=yes.

The ext_perform_stun=allow-filtered daemon option, which was added shortly afterwards (my contribution, unfortunately not published under my name because the maintainer (@miniupnp) blocked me), is IMHO better, as it returns the correct IPv4.

Even though ext_allow_private_ipv4=yes option had to be corrected after its introduction and unexpectedly changed the logging (new issue), I am no longer sure whether it should have been introduced at all, with all this trouble and regression. I know of others that were recently introduced, but the maintainer does not want me to submit them to get resolved.

And the reason why allow-filtered with STUN is necessary at all under OpenWrt with an unrestricted endpoint-independent IPv4 CGNAT is that the CGNAT test in the daemon has always been badly implemented. This requires that all UDP ports (random test ports) on the external IPv4 are open, which is not the case in any modern route OS for security reasons, instead of what would make much more sense, namely adding regular port maps to itself (internal IP) for the test, which would then work directly everywhere. This idea was also well received by a FreeBSD developer.

Screenshot of Advanced Settings tab with new CGNAT functionality

Thanks for your explanation, but there actually exist some scenarios that only ext_allow_private_ipv4 can resolve, at least in my test.

Hope we can add this in the future when it becomes stable.

@Self-Hosting-Group
Copy link
Contributor Author

Thanks for your explanation, but there actually exist some scenarios that only ext_allow_private_ipv4 can resolve, at least in my test.

Could you please explain this in more detail and describe a scenario in which the STUN function cannot work with allow-filtered?

Hope we can add this in the future when it becomes stable.

How? The fact that some PCP/NAT-PMP clients are not compatible when a private IPv4 address is returned will not change. They require a public IPv4 address to function, with these protocols, it is required that the external IP address (reported by the router) must be sent along with the renewal. Therefore, I see the only option as sending a public IPv4 address so that port mapping works with all clients. And I don't want to suggest new, additional options that create compatibility issues.

Removing the comment of this code would work immediately and would be a more compatible alternative to the daemon option if someone does not want to use STUN:

# [ "$allow_cgnat" = "allow-private-ext-ipv4" ] && external_ip=203.1.2.3

If we have a use case, I will gladly enable the code.

@Self-Hosting-Group
Copy link
Contributor Author

With UCI/LuCI this is already possible:
luci-ext-ipv4

@Self-Hosting-Group
Copy link
Contributor Author

The known affected clients are: Apple and miniupnp natpmpc, and probably more.

@AquanJSW
Copy link
Contributor

Thanks for your explanation, but there actually exist some scenarios that only ext_allow_private_ipv4 can resolve, at least in my test.

Could you please explain this in more detail and describe a scenario in which the STUN function cannot work with allow-filtered?

Hope we can add this in the future when it becomes stable.

How? The fact that some PCP/NAT-PMP clients are not compatible when a private IPv4 address is returned will not change. They require a public IPv4 address to function, with these protocols, it is required that the external IP address (reported by the router) must be sent along with the renewal. Therefore, I see the only option as sending a public IPv4 address so that port mapping works with all clients. And I don't want to suggest new, additional options that create compatibility issues.

Removing the comment of this code would work immediately and would be a more compatible alternative to the daemon option if someone does not want to use STUN:

# [ "$allow_cgnat" = "allow-private-ext-ipv4" ] && external_ip=203.1.2.3

If we have a use case, I will gladly enable the code.

If I do want a PCP/NAT-PMP client to get private IP of the wan port reported, not sure if there is any other way, but in my test, only ext_allow_private_ipv4 works for me.

@Self-Hosting-Group
Copy link
Contributor Author

Hello @AquanJSW

but in my test, only ext_allow_private_ipv4 works for me.

These incompatible clients don't actually care if the returned IPv4 address is the real public IP, as long as it's not private. The mapping actually works, but the API returns an error, which is shown to the user.

  1. Since UCI allow_cgnat=allow-filtered has worked reliably in all my tests, and in order to follow up on this, please provide debug logs (log_output=debug, best collapsed in the comment) when setting the option. Have you tested it with a custom (compatible?) STUN server? Defaults to stun.nextcloud.com
  2. And what does not work with the provided alternative, setting UCI external_ip=203.1.2.3?

Please also note that an additional bug in the ext_allow_private_ipv4 option exists in daemon version 2.3.9 that affects UPnP IGD clients (it has recently been fixed, but not yet released). Therefore, this option currently has another disadvantage.

I want to cover all user cases with the revision of the packages. Therefore, it is important to me that this also works for you.

(And possibly not quote the entire comment, to avoid making the PR history even longer.)

@AquanJSW
Copy link
Contributor

Hello @AquanJSW

but in my test, only ext_allow_private_ipv4 works for me.

These incompatible clients don't actually care if the returned IPv4 address is the real public IP, as long as it's not private. The mapping actually works, but the API returns an error, which is shown to the user.

  1. Since UCI allow_cgnat=allow-filtered has worked reliably in all my tests, and in order to follow up on this, please provide debug logs (log_output=debug, best collapsed in the comment) when setting the option. Have you tested it with a custom (compatible?) STUN server? Defaults to stun.nextcloud.com
  2. And what does not work with the provided alternative, setting UCI external_ip=203.1.2.3?

Please also note that an additional bug in the ext_allow_private_ipv4 option exists in daemon version 2.3.9 that affects UPnP IGD clients (it has recently been fixed, but not yet released). Therefore, this option currently has another disadvantage.

I want to cover all user cases with the revision of the packages. Therefore, it is important to me that this also works for you.

(And possibly not quote the entire comment, to avoid making the PR history even longer.)

Sorry I didn't make it clear, if two tailscale client that behind a same private network want a direct connection between themselves though that private network but not a public one, they need to known the private IP each other, but not a pseudo or real public IP.

@Self-Hosting-Group
Copy link
Contributor Author

Self-Hosting-Group commented Nov 11, 2025

Sorry I didn't make it clear, if two tailscale client that behind a same private network want a direct connection between themselves though that private network but not a public one, they need to known the private IP each other, but not a pseudo or real public IP.

This user case is still not fully clear to me. These two clients should share the same IPv4 subnet so they can connect to each other directly, and they cannot learn each other's IPv4 addresses using this service, only the router's external address.

For this specific use case, I could, if the other reviewers also wish, incorporate a UCI option that would then work for Tailscale but cause more problems for standard clients.

Would a UCI option be sufficient for you? I would prefer not to burden LuCI users with an additional/confusing UI option, but could also add it when wished, with an client compatibility warning. Had this long time ago in, but removed it when I discovered the current UPnP IGD daemon bug with the option.

Old LuCI CGNAT option screenshot including this additional option:
luci-cgnat-old

@AquanJSW
Copy link
Contributor

Sorry I didn't make it clear, if two tailscale client that behind a same private network want a direct connection between themselves though that private network but not a public one, they need to known the private IP each other, but not a pseudo or real public IP.

This user case is still not fully clear to me. These two clients should share the same IPv4 subnet so they can connect to each other directly, and they cannot learn each other's IPv4 addresses using this service, only the router's external address.

For this specific use case, I could, if the other reviewers also wish, incorporate a UCI option that would then work for Tailscale but cause more problems for standard clients.

Would this UCI option be sufficient for you? I would prefer not to burden LuCI users with an additional UI option, even with the current bug.

My test looks like this:

Client A: 192.168.1.100 -- Router A: 192.168.1.1 & 10.0.0.100 -- Router ... PUBIP A
Client B: 192.168.2.100 -- Router B: 192.168.2.1 & 10.0.0.101 -- Router ... PUBIP B

So if one wish the direct connection happens at 10.0.0.100 - 10.0.0.101, a private IP report is needed then.

@Self-Hosting-Group
Copy link
Contributor Author

Client A: 192.168.1.100 -- Router A: 192.168.1.1 & 10.0.0.100 -- Router ... PUBIP A
Client B: 192.168.2.100 -- Router B: 192.168.2.1 & 10.0.0.101 -- Router ... PUBIP B

OK. But you never mentioned having multiple routers before.

Would this UCI option be sufficient for you? I would prefer not to burden LuCI users with an additional UI option, even with the current bug.

?

@AquanJSW
Copy link
Contributor

Would this UCI option be sufficient for you? I would prefer not to burden LuCI users with an additional UI option, even with the current bug.

Yes, it would be better for me to have a ext_allow_private_ipv4 related UCI option :)

@Self-Hosting-Group
Copy link
Contributor Author

Yes, it would be better for me to have a ext_allow_private_ipv4 related UCI option :)

One more question about your setup. Does it currently work (tested?) by manually setting up firewall rules instead of using the service in OpenWrt, since the service has not been working so far for this specific user case (except with the X-Wrt enhancements)?

If you have a testable setup, would you be willing to do a full test, including trying out the LuCI UI, to see if it works for you? I would then add this option as an additional, optional commit and see if the other reviewers also find this useful.

@AquanJSW
Copy link
Contributor

One more question about your setup. Does it currently work (tested?) by manually setting up firewall rules instead of using the service in OpenWrt, since the service has not been working so far for this specific user case (except with the X-Wrt enhancements)?

No, manually setting up firewall rules doesn't work in this case.

If you have a testable setup, would you be willing to do a full test, including trying out the LuCI UI, to see if it works for you? I would then add this option as an additional, optional commit and see if the other reviewers also find this useful.

The LuCI UI seems to be working fine to me so far.

@Self-Hosting-Group
Copy link
Contributor Author

No, manually setting up firewall rules doesn't work in this case.

I'll add the commit, and then can you run the Tailscale test? I only want to introduce this option if it's proven to work with it. Otherwise, we probably don't need it.

By the way: You need an unrestricted endpoint-independent (1:1) CGNAT to test with your setup whether the port maps between the routers work when they are not located at the same site.

@AquanJSW
Copy link
Contributor

By the way: You need an unrestricted endpoint-independent (1:1) CGNAT to test with your setup whether the port maps between the routers work when they are not located at the same site.

I'm here thanks to my symmetric NAT, so probably I can't perform such a test.

I'll add the commit, and you'll run the test? I only want to introduce this option if it's proven to work with Tailscale. Otherwise, we probably don't need it.

Yeah, glad to test :)

@Self-Hosting-Group
Copy link
Contributor Author

Yeah, glad to test :)

Commit pushed for testing. Please recompile the daemon package with the latest commit. To easily test the LuCI plugin (including the rpcd ucode update) without compilation, I have prepared the following script to be executed on the router:

latestcommit=f9986b09ff7d506a2b09daf38585808ca5afc490 # 2025-11-11
baseurl=https://raw.githubusercontent.com/openwrt/luci/$latestcommit/applications/luci-app-upnp
wget -O /www/luci-static/resources/view/upnp/upnp.js $baseurl/htdocs/luci-static/resources/view/upnp/upnp.js
wget -O /www/luci-static/resources/view/status/include/80_upnp.js $baseurl/htdocs/luci-static/resources/view/status/include/80_upnp.js
wget -O /usr/share/rpcd/ucode/luci.upnp $baseurl/root/usr/share/rpcd/ucode/luci.upnp
/etc/init.d/rpcd restart

@Self-Hosting-Group
Copy link
Contributor Author

I'm here thanks to my symmetric NAT, so probably I can't perform such a test.

Perhaps you will find someone for such a Tailscale test.

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

8 participants