Opened 3 years ago

Closed 21 months ago

#2175 closed enhancement (fixed)

Mitigating the IPv6 firewalled issue

Reported by: jogger Owned by: zzz
Priority: minor Milestone: 0.9.44
Component: router/transport Version: 0.9.33
Keywords: Cc:
Parent Tickets: Sensitive: no


I have run into this issue multiple times with Win 10 and Debian running the default network manager, both systems using default DHCP v4/v6 with no v6 DHCP server running on the network (also standard).

I have full dual stack internet connectivity with a consumer type router as a firewall. So I open the i2p port for TCP and UDP v4 and v6.

For IPv6 the above system configuration leads into multiple v6 addresses being assigned for the I2p router (verify in the i2p network settings or with "ip addr / ipconfig").

The internet router might open the i2p port for just one of these addresses (and might not even show which one in its user interface) while i2p picks and advertises a different ipv6 address. BANG: IPv6 inbound is blocked.

Partial solution would be for i2p to check a port/address combination is reachable from the internet and try all available public v6 addresses before advertising the router address.

This still can fail if the internet router opens an address not in use on the i2p machine (the internet router might blindly use the default v6 address derived from the MAC interface address which is not in use by Debian in the above setup). This calls for detailed additional documentation how to circumvent the issue.


Change History (22)

comment:1 Changed 3 years ago by Eche|on

Owner: set to zzz
Status: newassigned

comment:2 Changed 3 years ago by zzz

Component: router/generalrouter/transport

I added some logic in late 2016 for 0.9.28 that avoids the "temporary" IPv6 addresses on Linux. But those seemed to be visible on an older Debian distro only. This seems to be a different issue.

We added IPv6 peer testing in 0.9.27 (see #1752 and proposal 126). As with IPv4, if we have a public IP address on an interface, we assume we aren't firewalled to begin with, but then we do peer testing, which will later reveal the firewalled state and we will change our status.

One alternative would be to just advertise all addresses to begin with, peer test all of them as we go, and gradually remove the ones that fail. But right now we only support one each of IPv4 and IPv6 addresses and that's a big mess I don't want to get into anytime soon if I don't have to.

We may be able to get a hint from the firewall if it supports IPv6 UPnP or returns IPv6 addresses when we query it.

Workaround for now would be to assign the IP addresses on /config, but of course if they change later, you have a worse problem.

Also a problem to get a good test setup for this.

Not easy and won't be fixed soon. Thanks for the report.

comment:3 Changed 3 years ago by jogger

I understand this is not so easy. One can file a bug report with the router manufacturer, mandating that the manually opened port is opened for all IPv6 addresses on the destination machine that the router learns about. I have done this for AVM.

For Linux a ticket could be opened for "network-manager" to change the default settings from DHCPv6 to IPv6 auto config. Makes sense anyway, but beyond my scope.

My router supports urn:schemas-upnp-org:service:WANIPv6FirewallControl:1 but did not work out on a test machine with i2p.

comment:4 Changed 3 years ago by zzz

Milestone: undecided0.9.35

Researched a little more on UPnP (see comment 2 above)

When I first added UPnP support 9 years ago, I disabled IPv6 in the UPnP library. Not sure what that actually did or didn't disable, as I didn't have IPv6 support in my firewall/router at the time. Now I do, but I still don't have IPv6 from my ISP, so the UPnP doesn't return any public addresses. I may be able to set up a chain of a couple of devices, or hard-config one, to report an IPv6 address, but it will take some time and I may need to purchase some specifically for testing and development.

I'm also not sure if we have full support for IPv6 in our "bridge" code that we originally got from Freenet, that connects to the UPnP library, or our "bridge" code that connects to the Freenet code.

For further research…

comment:5 Changed 3 years ago by zzz

OK, it appears that WANIPv6FirewallControl is IGD:2 based. We don't have support for either in our bridging code. In addition, my firewall/router does not support it. It is miniupnpd-based, but IGD:2 is not fully included by default in miniupnpd builds, for "compatibility reasons".

comment:6 Changed 3 years ago by zzz

miniupnpd is in Debian, and as-built, supports IGD 2. So I'm running it on my server for testing. I'll be checking in basic IGD 2 support (which is pretty much the same as 1, except for WANIPv6FirewallControl) soon.

Unfortunately - quoting the WANIPv6FirewallControl spec:

This service deploys access control, as defined in, that restricts operations to duly authorized control points
and users.
This service does not provide the following functionality:
• To avoid some potential security issues, it is not possible for control points to retrieve information
on any pinholes; For example, a control point can't retrieve information like the external port or
the remaining lease duration of any pinhole (even if the CP created this pinhole).
• Control of outbound packet filtering; For example, if the gateway's firewall forbids outbound
HTTP connection from the CP to the Internet, the CP can't change this behavior through this
• It is not possible for control points to modify the security policy applied by the IGD.

So we may not, as I proposed in comment 2 above, query the firewall, get all the mappings, and use whatever one is already open. All we can do is open it ourselves.

So all we can do is open up the firewall for the address we want to use.

comment:7 Changed 3 years ago by zzz

Basic IGD 2 support and display of WIFC vars in 2f53eeed0412dec1123e57b2d4937629e2771575 to be 0.9.33-11. Other cleanups in the two checkins before that.

I'd really like to know how to determine if v6 addresses are temporary or deprecated on Windows. That would be a big help. Things do work better on Linux where we have that capability.

comment:8 Changed 3 years ago by mysterious2

@zzz: Are you saying that on linux I2P is supposed to avoid the temporary addresses altogether? (from my experience it doesn't, neither for TCP nor UDP)

(For the record, I have dual stack IPV4/6, but no UPNP)

comment:9 Changed 3 years ago by zzz

Yeah, the problem with the temporary ones is they go away. What I've seen is that you can get inbound conns on them for a day, then outbound for another 6 days, then they disappear. We don't deal with that well.

If there are non-temporary addresses, we'll prefer those. Otherwise we'll use a temporary one.

The identification of temporary only works on linux where we have /proc/net/if_inet6 to find out.

Our CLI tool:
java -jar $I2P/lib/i2p.jar addresses
will tell you what I2P sees.

comment:10 Changed 3 years ago by jogger

Given this information I can help a bit, at least for Stretch using v6 autoconfiguration. Today my internet connection reset and I got new public IP addresses. After 20 minutes no inbound v6 traffic and the router advertised the new v4 address along with the old v6 address. The CLI tool listed the old v6 address as deprecated as well as the correct one. After some time the old v6 address vanished, but I restarted the router before and it the picked the correct one. So here the switch could be made faster.

comment:11 Changed 3 years ago by mysterious2


I2P recognizes the temporary flag, yet last weekend when I was wiresharking my connection I saw every UDP6 response go over temporary, and a lot of TCP6 traffic as well (but not all). Is there a way I can help in diagnosing and/or fixing that?

comment:12 Changed 3 years ago by zzz

There's a few things going on here.

  • The OS setting on whether to use temporary ("privacy") address is:

Linux: /proc/sys/net/ipv6/conf/all/use_tempaddr
Mac/BSD: sysctl net.inet6.ip6.use_tempaddr
Win: netsh interface ipv6 show privacy

For non-Linux, where we don't have /proc/net/if_inet6, I'm implementing the following heuristics and will check in soon:
Take IPv6 address bytes 0-15 (numbered left to right)
If bytes 8-11 are all zeros, it's not temporary.
If bytes 13-15 match the last 3 bytes of the MAC address, it's not temporary.
For Mac/BSD, if byte 8 bit 1 (numbered right to left, i.e. address[8] & 0x02) is 1, it's not temporary
Otherwise, it is temporary.

I'd like to know if those heuristics look right.

comment:13 Changed 3 years ago by mysterious2

You seem to be using some scheme to detect EUI-64 addresses, why not check properly?
Byte 8-10 equal to the first 3 bytes of the MAC (with the exception of the 7th bit)
Byte 11-12 0xFFFE
Byte 13-15 equal to the last 3 bytes of the MAC

The rest of the heuristics I don't recognize.
Please keep in mind that "stable privacy" addresses also exist, it doesn't seem that they follow a strict convention that can be easily detected:

If the OS handles the outbound IP, does I2P handle receiving packets from random IPs, while still being able to correlate request/reply messages?

comment:14 Changed 3 years ago by zzz

Implementing based on heuristics and real-world testing, rather than just specs, because:

  • There are lots of specs
  • RFC 7217 says ignore the other specs
  • RFC 7136 says ignore all the specs
  • There's a lot of variance in observed behavior
  • The whole thing is best-effort identification anyway, we can't be perfect and don't need to be

Changes from comment 12, more or less, in 380efb74a08cffdba1602fc39ba0855d889d73c6 0.9.33-11

re: handle receiving packets, NTCP should just work, SSU is harder. There's also handshake signature issues. As I said in comment 2 above, IPv6 is a work in progress, not easy, and is slowed by my lack of a test setup. It's not all going to be fixed at once.

comment:15 Changed 3 years ago by mysterious2

I understand that you don't have a setup, and I'm willing to help, but I can't judge if for example the I2P protocol even contains enough information to not need IP address as identification (for SSU). A bugfixing mindset doesn't work when there a design or a protocol problem for example. Is there a known problem list somewhere?

comment:16 Changed 2 years ago by jogger

I suggest a simple first step to solve this most common issue:

While the i2p router is running, the internet connection breaks. While for IPv4 a new address is assigned, recording an address changed event, i2p retains the IPv6 router addresses forever, not noting that a new IPv6 address with a longer preferred lifetime is available on the network interface.

This leads to the situation that IPv6 inbound stops working immediately. A router restart within the first 4 hours does not help because the old IPv6 address still has some preferred lifetime remaining. This forces the user to reboot the machine or manually remove the stale IPv6 address from the interface or wait 4 hours, and then restart the router. After 4 hours one could also switch IPv6 off and on using /confignet, breaking all tunnels.

i2p should conduct an IPv6 address change similar to IPv4 that could be triggered by one of the following:

  • The IPv6 we use does not have the longest preferred lifetime on the network interface
  • Our peers reflect we use an IPv6 address different from what we advertise
  • or (after 4 hours) the remaining single IPv6 address on the interface (displayed on /confignet) is different from what we advertise.

I observed that an IPv4 address change does not affect IPv6, tunnels keep running, this could be handled the other way round also. For some routers I run IPv4 and IPv6 through different ISPs, works good unless IPv6 breaks.

comment:17 Changed 2 years ago by zzz

Milestone: 0.9.350.9.42

Thanks for bumping this, I'll try to take another look. Sadly, I still don't have access to the test setup I would need. Re: comment 15, it's not a protocol issue. It is a design issue, in that the address change recognition and handling design is completely different for v4 and v6.

comment:18 Changed 23 months ago by zzz

Milestone: 0.9.420.9.43
Sensitive: unset

Several changes in 0.9.42-3 and -4. Still WIP and needs more testing.

re: comment 16, we have no access from java to the remaining lifetimes of each address. That info is not available in the Java API, it is not published in /proc/net/if_inet6 and of course we don't have that file at all on non-linux. However with the changes in -4 we should use the best one, and switch when it switches.

comment:19 Changed 23 months ago by zzz

… and more changes in -5.

Summary of changes in last couple of weeks:

  • fix periodic ipv6 testing
  • fix detection of ipv6 firewalled
  • fix removal of ipv6 addresses from RI when firewalled
  • fix detection of ipv6 address changes
  • log ipv6 address changes in event log

What's not fixed:

  • detection of transition from ipv6 firewalled to ipv6 non-firewalled, and adding the address to the RI

not sure if I'll get to that for 43 or not.

comment:20 Changed 21 months ago by zzz

Milestone: 0.9.430.9.44

Publish RI on transition to non-firewalled in 96aae331afed2431ebeffda5f064847944178824 0.9.43-2, didn't make it in to .43 release.

Leaving ticket open for testing and possible additional changes: Don't start assuming IPv6 address is non-firewalled? Or remember IPv6 firewalled state accross restarts? Or both?

comment:21 Changed 21 months ago by zzz

Add'l fixes for above change in 05cb4c94fca4250e83b275e600b0459d027e794d to be 0.9.43-5
Leaving open to address issues described in the previous comment.

comment:22 Changed 21 months ago by zzz

Resolution: fixed
Status: assignedclosed

Save IPv6 firewalled status across restarts in 73aa0c0a0294f3b75f108437e1cd0913cb699245 to be 0.9.43-5
A couple of very minor issues remaining, but pretty much done.

Note: See TracTickets for help on using tickets.