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

[RFC] Changing the default ports #7053

Closed
RubenKelevra opened this issue Mar 29, 2020 · 11 comments
Closed

[RFC] Changing the default ports #7053

RubenKelevra opened this issue Mar 29, 2020 · 11 comments
Labels
kind/enhancement A net-new feature or improvement to an existing feature

Comments

@RubenKelevra
Copy link
Contributor

RubenKelevra commented Mar 29, 2020

I know the team is probably quite busy working on #6776, but I think we should consider changing the currently used default ports. I know this might lead to kind of a mess because a lot of stuff build around ipfs might have hardcoded ports, but hear me out.

IPFS uses 3 ports:

Swarm - currently port 4001

We're using TLS and QUIC (soon by default), so it makes sense to use the default port 443 for incoming connections. This circumvents simple censorship approaches.

Starting with TLS1.3 it's impossible to detect what server-name the user requested, so it's going to be easy to hide an IPFS-instance behind a regular HTTPS server - OpenVPN offers such a feature for example.

Additionally, the ongoing efforts to include DNS encryption in all operating systems by default will allow to fully hide the real hostname of the IPFS-Server (bootstrap servers use DNS).

This is obviously just limited to the server profile, and not for the desktop client/desktop profile (#4989). Non-server-nodes should ideally just use a random port for incoming connections, to avoid that it's obvious what application is running. IPFS already supports this, by setting the port definition in the config file to 0.

API - currently port 5001

The default port for the API is currently 5001 on localhost. This isn't ideal because it's also used by Iperf. It's also a registered port by IANA. I think we should use a non-registered port, to be able to add it maybe in the future to /etc/services.

Web gateway - currently port 8080

The default port for the web gateway is currently 8080 on localhost. This is an extremely bad choice since it's used heavily by other services as default.

I think we should just use a different localhost IP (like 127.0.0.80) to circumvent this issue as systemd-resolved does. We can then add a hostname (like gateway.ipfs.local) via host file to the IP and give IPFS the capability to bind to port 80.

This would make a much prettier URL than the current "127.0.0.1:8080".

@RubenKelevra RubenKelevra added the kind/enhancement A net-new feature or improvement to an existing feature label Mar 29, 2020
@RubenKelevra RubenKelevra changed the title [RFC] default ports change [RFC] Changing the default ports Mar 29, 2020
@Stebalien
Copy link
Member

You're right in that we should evaluate the default ports. But it would be a non-trivial change and has minimal benefit so it has a pretty low priority.

In general, resisting censorship of the protocol itself by default is a loosing battle. The only reliable approach is to tunnel out of the country via another protocol. All nodes operating this way would have to connect to the rest of the IPFS network through secret relays.

We're using TLS and QUIC (soon by default), so it makes sense to use the default port 443 for incoming connections. This circumvents simple censorship approaches.

Unfortunately, we can't by default because most users run IPFS as a non-privileged user, even when run on servers.

Starting with TLS1.3 it's impossible to detect what server-name the user requested, so it's going to be easy to hide an IPFS-instance behind a regular HTTPS server - OpenVPN offers such a feature for example.

Impossible without an active MITM. Unfortunately, countries that censor the internet will just perform an active MITM on the first connection attempt. This feature primarily protects against snoopy ISPs.

just use a random port for incoming connections, to avoid that it's obvious what application is running.

We have considered this but:

  • It sucks for documentation purposes ("which port should I open in my firewall").
  • It's a non-trivial breaking change.

However, I agree we should still consider it as it would make it slightly harder to effortlessly block IPFS.

@RubenKelevra
Copy link
Contributor Author

Unfortunately, we can't by default because most users run IPFS as a non-privileged user, even when run on servers.

Starting with TLS1.3 it's impossible to detect what server-name the user requested, so it's going to be easy to hide an IPFS-instance behind a regular HTTPS server - OpenVPN offers such a feature for example.

Impossible without an active MITM. Unfortunately, countries that censor the internet will just perform an active MITM on the first connection attempt. This feature primarily protects against snoopy ISPs.

True, like all web servers etc. But a simple AmbientCapabilities=CAP_NET_BIND_SERVICE gives the user service the capability to bind a privileged port. We just have to document this as a requirement for (not changing) the server profile.

I still think running IPFS on Port 443 should be the default. We could alter the TLS handshake in a way that a usual browser would get a 503 HTTP response back, while IPFS clients authenticate with their client certificate.

With a switch, we could allow that regular web traffic goes through the IPFS daemon to a real web server in the background unless an IPFS client authenticates.

When adding a 'whitelist' of known good client certificates we could easily provide the ability to allow only incoming connections and thus providing the technical capability for secret relays.

Apart from this censorship aspect, an IPFS capable browser could resolve a Domain Name via DNS and if there's a DNSLink entry try to authenticate with his TLS certificate to the IPFS daemon directly. If this fails (based on user settings) it could fall back to DHT for finding the content or to HTTPS. I'm not entirely sure about TLS via TCP (because you might not be able to fetch content after a client certificate failed), but at least via UDP/QUIC the "established" connection in the connection tracking and the socket from the system etc. could be reused for the second try to fetch via HTTPS.

just use a random port for incoming connections, to avoid that it's obvious what application is running.

We have considered this but:

  • It sucks for documentation purposes ("which port should I open in my firewall").

That's what UPnP is for. And it's not needed for IPv6 which gets adopted quite fast.

We could implement a helper popup which solves this issue: If there's no working connection for incoming traffic except for relays, just ask the user if the current random port should be used statically and explain where a help page is for how to open a firewall port.

  • It's a non-trivial breaking change.

However, I agree we should still consider it as it would make it slightly harder to effortlessly block IPFS.

Sure, but worth it. :)

@RubenKelevra
Copy link
Contributor Author

I forgot, there's also STUN for nat traversal if UPnP isn't working. WebRTC uses this, too.

@Stebalien
Copy link
Member

That's what UPnP is for.

We have UPnP support on by default and it barely helps.

And it's not needed for IPv6 which gets adopted quite fast.

In practice, routers block all inbound connections by default for security reasons, even IPv6 ones.

True, like all web servers etc. But a simple AmbientCapabilities=CAP_NET_BIND_SERVICE gives the user service the capability to bind a privileged port. We just have to document this as a requirement for (not changing) the server profile.

No. Just no. We could add documentation suggesting that users should consider switching to port 443. We could also add a "camouflage" profile to change the default ports. We could even add a special "hidden" transport where you need to know the remote peer's peer ID to talk to them. But switching to port 443 by default, even on the server profile, would be a shit show.

Sure, but worth it. :)

It's really not. We'd spend a lot of effort for some ineffective privacy measures or we'd spend a massive amount of effort for some actually effective privacy measures. We need to do the later eventually, but we need to focus on getting IPFS to work well in less hostile networks first.

@RubenKelevra
Copy link
Contributor Author

That's what UPnP is for.

We have UPnP support on by default and it barely helps.

Yeah, because many providers changed to carrier grade NAT, because of address shortages.

And it's not needed for IPv6 which gets adopted quite fast.

In practice, routers block all inbound connections by default for security reasons, even IPv6 ones.

Well, but since there's no NAT we can easily punch holes in the firewall using QUIC, we just need a way to communicate this interconnection before it's established.

So basically we need to use messaging via a relay, but can establish the direct connection with a short delay.

Not ideal but it should work 100% of the time.

The only thing we need to consider is, that some IPv6 implementations by providers have black holes, so we need to robustly detect the maximum MTU.

True, like all web servers etc. But a simple AmbientCapabilities=CAP_NET_BIND_SERVICE gives the user service the capability to bind a privileged port. We just have to document this as a requirement for (not changing) the server profile.

No. Just no. We could add documentation suggesting that users should consider switching to port 443. We could also add a "camouflage" profile to change the default ports. We could even add a special "hidden" transport where you need to know the remote peer's peer ID to talk to them. But switching to port 443 by default, even on the server profile, would be a shit show.

This camouflage idea sounds nice! :)

I'll work tomorrow on that.

Sure, but worth it. :)

It's really not. We'd spend a lot of effort for some ineffective privacy measures or we'd spend a massive amount of effort for some actually effective privacy measures. We need to do the later eventually, but we need to focus on getting IPFS to work well in less hostile networks first.

Well, in this case I could extend the documentations on how to configure a router correctly and change the default port - and why this is important.

I'm not that sure how the current practice by providers are, but I was pretty sure UPnP is a standard-on feature.

If not we might want to communicate this better.

@RubenKelevra
Copy link
Contributor Author

We could even add a special "hidden" transport where you need to know the remote peer's peer ID to talk to them.

What do you think about using sslh to separate between https traffic and ipfs traffic? This way the 443 port can be shared with e.g. Nginx.

For a curious network admin who tests where a connection does lead to, an Nginx would offer a webpage :)

@hsanjuan
Copy link
Contributor

hsanjuan commented Apr 1, 2020

Hi, thanks for sending this @RubenKelevra .

I don't want to see the actionable ideas and requests in this issue languish here, but this has very quickly muddled into a longer discussion beyond the original request. I am going to try to unwrap:

  • We're not changing the default API ports to a privileged port. Reasons are above.

  • Please open an additional issue about having a "camouflage" profile. This is something that can be worked on.

  • For additional documentation and guides (I think it would be great to have a guide on how to camouflage IPFS), you can request and submit here: https://github.com/ipfs/docs

We could alter the TLS handshake in a way that a usual browser would get a 503 HTTP response back, while IPFS clients authenticate with their client certificate.

  • I am not sure this is doable, but please, open a different concrete issue for it.

Well, but since there's no NAT we can easily punch holes in the firewall using QUIC, we just need a way to communicate this interconnection before it's established.
So basically we need to use messaging via a relay, but can establish the direct connection with a short delay.

  • For QUIC, relay, NAT whole punching discussions, head to libp2p. There is a lot of work ongoing (https://github.com/libp2p/go-libp2p-autonat). By the way: nothing is simple here. It may look like that, but if you look at the commit history you can glimpse that things are not simple at all.

Apart from this censorship aspect, an IPFS capable browser could resolve a Domain Name via DNS and if there's a DNSLink entry try to authenticate with his TLS certificate to the IPFS daemon directly. If this fails (based on user settings) it could fall back to DHT for finding the content or to HTTPS

  • This is another idea, but I'd take this to discuss as we are not building an "IPFS capable browser" ourselves.


Thus we are left with the original action items here that would need a decision:

  • Changing the API port to something not reserved by IANA
  • Changing the Swarm port to something not reserved by IANA
  • Changing the Gateway port to something else

But it would be a non-trivial change and has minimal benefit so it has a pretty low priority.

@Stebalien let's discuss this and try to either come up with an actionable that we want to do or close it because we don't want to do it at the moment.

I think:

  • it would be a good thing to use non-assigned ports.
  • While the change is easy on go-ipfs, this will break documentation and tools that default to using those ports which is a mess.
  • Therefore I see little benefit to change 4001 and 5001 at this point and would rather keep them.
  • I think we could change the default gateway port though, given its tendency to conflict with other things.

@Stebalien
Copy link
Member

Hole punching work: libp2p/specs#173

@RubenKelevra
Copy link
Contributor Author

Well, but since there's no NAT we can easily punch holes in the firewall using QUIC, we just need a way to communicate this interconnection before it's established.
So basically we need to use messaging via a relay, but can establish the direct connection with a short delay.

  • For QUIC, relay, NAT whole punching discussions, head to libp2p. There is a lot of work ongoing (https://github.com/libp2p/go-libp2p-autonat). By the way: nothing is simple here. It may look like that, but if you look at the commit history you can glimpse that things are not simple at all.

This wasn't meant that way. I'm sorry. I really appreciate all the work you're investing! :)

Apart from this censorship aspect, an IPFS capable browser could resolve a Domain Name via DNS and if there's a DNSLink entry try to authenticate with his TLS certificate to the IPFS daemon directly. If this fails (based on user settings) it could fall back to DHT for finding the content or to HTTPS

  • This is another idea, but I'd take this to discuss as we are not building an "IPFS capable browser" ourselves.

The idea was more to consider this option since this would eliminate the whole DHT roundtrip for a faster website lookup.

I'll merge both ideas into one ticket. :)

@RubenKelevra

This comment has been minimized.

@RubenKelevra
Copy link
Contributor Author

duplicate #874

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
kind/enhancement A net-new feature or improvement to an existing feature
Projects
None yet
Development

No branches or pull requests

3 participants