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

IPFS/HTTPS via port 443 to allow direct connections via encrypted SNIs #7073

Closed
RubenKelevra opened this issue Apr 2, 2020 · 4 comments
Closed
Labels
kind/feature A new feature

Comments

@RubenKelevra
Copy link
Contributor

This proposal aims to extend the current functionality to allow a Webserver with HTTPS and an IPFS client on the same port, with different TLS-Keys.

Motivations

  • Corporations, Hotels, Public Wifis, etc. tend to block everything except port 80/443 as the destination
  • A firewall log would currently clearly show, that a computer is running IPFS because of a lot of connections to port 4001
  • Looking up the location of a CID and resolving an IPNS is slower than regular HTTPS+DNS
  • IPFS is currently easy to censorship since most servers run on port 4001, it's enough to block this port
  • Avoids the need to spin up the DHT client before the first bit can be received, in case of a slim client like ipget

Connection flow

Scenario: IPFS enabled client

  • User enters a Domain name
  • Client requests the IPNS record/CID via DNSLink over DNS
  • Client requests the IPv4/IPv6 from via DNS
  • Client requests the Publickey of the Node via DNSLink (v2?) over DNS
  • IPFS client tries to connect directly to the IPv6 (or IPv4) via QUIC, with the IPNS record/CID as encrypted Servername (encrypted SNI)
  • In case of an IPNS record: Server returns the record
  • Server returns the data corresponding to the CID

Scenario: IPFS enabled client - Server hold no data

  • User enters a Domain name
  • Client requests the IPNS record/CID via DNSLink over DNS
  • Client requests the IPv4/IPv6 from via DNS
  • Client requests the Publickey of the Node via DNSLink (v2?) over DNS
  • IPFS client tries to connect directly to the IPv6 (or IPv4) via QUIC, with the IPNS record/CID as encrypted Servername (encrypted SNI)
  • In case of an IPNS record: Server returns the record
  • Server response with 'I don't got that data' for the corresponding CID
  • The data is searched via Bitswap/DHT

Scenario: IPFS enabled client - Server is down

  • User enters a Domain name
  • Client requests the IPNS record/CID via DNSLink over DNS
  • Client requests the IPv4/IPv6 from via DNS
  • Client requests the Publickey of the Node via DNSLink (v2?) over DNS
  • IPFS client tries to connect directly to the IPv6 (or IPv4) via QUIC, with the IPNS record/CID as encrypted Servername (encrypted SNI)
  • The server is down
  • The data is searched via Bitswap/DHT

Scenario: IPFS enabled client - CryptoDNS

  • User enters a Domain name
  • Client requests the IPNS record/CID via DNSLink over CryptoDNS
  • Client requests the IPv4/IPv6 from via CryptoDNS
  • Client requests the Publickey of the Node via DNSLink (v2?) over CryptoDNS
  • IPFS client tries to connect directly to the IPv6 (or IPv4) via QUIC, with the IPNS record/CID as encrypted Servername (encrypted SNI)
  • In case of an IPNS record: Server returns the record
  • Server returns the data corresponding to the CID

Required changes to IPFS

DNSLink (v2?)

  • There need to be a new specification for DNSLink which allows specifying the public key of a node via a DNS record

IPFS-Node

  • The node needs to be able to path-thru a TLS connection with a non-matching encrypted SNI-header to a locally running Webserver
  • The node needs to support TLS1.3 encrypted SNI-records
  • The node needs to decode the SNI-record and respond to the CID/IPNS record with the matching data

Security implications

The same security implications apply which are true for the current DNSLink:

  • If no DNSSec/CryptoDNS is used, it's not secure
  • If (in case of DNS) the corresponding encryption methods DoH/DoT/DNSCurve/DNSCrypt are not used, everyone can sniff what you're requesting

Censor robustness

  • To censorship IPFS, every website which supports the proposed method has to be blocked
  • Some websites could offer a relay function, to enhance censorship resistance, by having IPFS-traffic look like regular HTTPS traffic

(This ticket originates from this discussion #7053.)

@RubenKelevra RubenKelevra added the kind/feature A new feature label Apr 2, 2020
@RubenKelevra
Copy link
Contributor Author

To circumvent that all systems need to have DNSSec and encryption enabled DNS resolver, we could integrate our own DNS Server, which can also resolve any crypto namesystem we like to support in the future.

More details here:

https://discuss.ipfs.io/t/coredns-ipfs-ipns-dns-servers/7605/4?u=rubenkelevra

@lidel
Copy link
Member

lidel commented Apr 18, 2020

DNSAddr is "DNSLink for multiaddrs"

@RubenKelevra FYI we already have /dnsaddr which works just like DNSLink, but for full peer multiaddrs:

$ dig +short TXT _dnsaddr.bootstrap.libp2p.io
"dnsaddr=/dnsaddr/ams-2.bootstrap.libp2p.io/tcp/4001/ipfs/QmbLHAnMoJPWSCR5Zhtx6BHJX9KiKNN6tpvbUcqanj75Nb"
"dnsaddr=/dnsaddr/ewr-1.bootstrap.libp2p.io/tcp/4001/ipfs/QmQCU2EcMqAqQPR2i9bChDtGNJchTbq5TbXJJ16u19uLTa"
"dnsaddr=/dnsaddr/nrt-1.bootstrap.libp2p.io/tcp/4001/ipfs/QmcZf59bWwK5XFi76CZX8cbJ4BhTzzA3gU1ZjYZcYW3dwt"
"dnsaddr=/dnsaddr/sjc-1.bootstrap.libp2p.io/tcp/4001/ipfs/QmNnooDu7bfjPFoTZYxMNLWUQJyrVwtbZg5gBMjTezGAJN"

This means a domain example.com can have both set up for clients to resolve DNS TXT records:

  • _dnsaddr.example.com provides one or more multiaddrs of peers with pubkey hash at the end
  • _dnslink.example.com provides content path

HTTPS Gateway and libp2p listener on the same port

We could integrate something like that in the future, as an option for specific hostnames defined in Gateway.PublicGateways, but for now I think its worth looking at documenting ways of archieving this in userland.

Prior art: I've been using sslh for exposing HTTPS and SSH on the same port:

sslh accepts connections on specified ports, and forwards them further based on tests performed on the first data packet sent by the remote client.

Probes for HTTP, TLS/SSL (including SNI and ALPN), SSH, OpenVPN, tinc, XMPP, SOCKS5, are implemented, and any other protocol that can be tested using a regular expression, can be recognised.

It acts as reverse proxy which runs in front of SSH/nginx, so as the first step one could try running it in front of go-ipfs and sharing results/configuration in this issue.

@RubenKelevra
Copy link
Contributor Author

Thanks for the input!

I think the port sharing thing is the easiest and can be done in the userland (until it's implemented in IPFS).

The connection (with the Hostkey from DNS) and query for IPNS and then query directly for the CID just on that node, is the complex part - but also the most interesting.

A node queried with a (special?) command could return not only the IPNS to CID information but also start streaming the first CID blocks, basically as prefetching, immediately on connection establishment, based on the encrypted SNI.

This gives the receiving node time to confirm the IPNS record and process the first CID block, while the data is already being received.

This should bring the time to first byte down to one roundtrip plus the processing time for the handshake, IPNS validation and CID processing since QUIC and TLS1.3 can return early data (there are some security implications doing this, though).

With TLS over TCP/IP we're still slower (if there's no TCP fast open available, but it should be like one magnitude faster than querying the DHT.

@Stebalien
Copy link
Member

This would add a lot of complexity and isn't necessary.

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

No branches or pull requests

3 participants