2023-08-21 03:50:38 +00:00
|
|
|
package libp2pwebtransport
|
|
|
|
|
|
|
|
import (
|
|
|
|
"errors"
|
|
|
|
"fmt"
|
|
|
|
"net"
|
|
|
|
"strconv"
|
|
|
|
|
|
|
|
ma "github.com/multiformats/go-multiaddr"
|
|
|
|
manet "github.com/multiformats/go-multiaddr/net"
|
|
|
|
"github.com/multiformats/go-multibase"
|
|
|
|
"github.com/multiformats/go-multihash"
|
|
|
|
)
|
|
|
|
|
2024-10-12 18:55:17 +00:00
|
|
|
var webtransportMA, _ = ma.StringCast("/quic-v1/webtransport")
|
2023-08-21 03:50:38 +00:00
|
|
|
|
|
|
|
func toWebtransportMultiaddr(na net.Addr) (ma.Multiaddr, error) {
|
|
|
|
addr, err := manet.FromNetAddr(na)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
if _, err := addr.ValueForProtocol(ma.P_UDP); err != nil {
|
|
|
|
return nil, errors.New("not a UDP address")
|
|
|
|
}
|
|
|
|
return addr.Encapsulate(webtransportMA), nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func stringToWebtransportMultiaddr(str string) (ma.Multiaddr, error) {
|
|
|
|
host, portStr, err := net.SplitHostPort(str)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
port, err := strconv.ParseInt(portStr, 10, 32)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
ip := net.ParseIP(host)
|
|
|
|
if ip == nil {
|
|
|
|
return nil, errors.New("failed to parse IP")
|
|
|
|
}
|
|
|
|
return toWebtransportMultiaddr(&net.UDPAddr{IP: ip, Port: int(port)})
|
|
|
|
}
|
|
|
|
|
|
|
|
func extractCertHashes(addr ma.Multiaddr) ([]multihash.DecodedMultihash, error) {
|
|
|
|
certHashesStr := make([]string, 0, 2)
|
2024-10-12 18:55:17 +00:00
|
|
|
var err error
|
|
|
|
ma.ForEach(addr, func(c ma.Component, e error) bool {
|
|
|
|
if e != nil {
|
|
|
|
err = e
|
|
|
|
return false
|
|
|
|
}
|
2023-08-21 03:50:38 +00:00
|
|
|
if c.Protocol().Code == ma.P_CERTHASH {
|
|
|
|
certHashesStr = append(certHashesStr, c.Value())
|
|
|
|
}
|
|
|
|
return true
|
|
|
|
})
|
2024-10-12 18:55:17 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2023-08-21 03:50:38 +00:00
|
|
|
certHashes := make([]multihash.DecodedMultihash, 0, len(certHashesStr))
|
|
|
|
for _, s := range certHashesStr {
|
|
|
|
_, ch, err := multibase.Decode(s)
|
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("failed to multibase-decode certificate hash: %w", err)
|
|
|
|
}
|
|
|
|
dh, err := multihash.Decode(ch)
|
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("failed to multihash-decode certificate hash: %w", err)
|
|
|
|
}
|
|
|
|
certHashes = append(certHashes, *dh)
|
|
|
|
}
|
|
|
|
return certHashes, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func addrComponentForCert(hash []byte) (ma.Multiaddr, error) {
|
|
|
|
mh, err := multihash.Encode(hash, multihash.SHA2_256)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
certStr, err := multibase.Encode(multibase.Base58BTC, mh)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return ma.NewComponent(ma.ProtocolWithCode(ma.P_CERTHASH).Name, certStr)
|
|
|
|
}
|
|
|
|
|
|
|
|
// IsWebtransportMultiaddr returns true if the given multiaddr is a well formed
|
|
|
|
// webtransport multiaddr. Returns the number of certhashes found.
|
|
|
|
func IsWebtransportMultiaddr(multiaddr ma.Multiaddr) (bool, int) {
|
|
|
|
const (
|
|
|
|
init = iota
|
|
|
|
foundUDP
|
|
|
|
foundQuicV1
|
|
|
|
foundWebTransport
|
|
|
|
)
|
|
|
|
state := init
|
|
|
|
certhashCount := 0
|
|
|
|
|
2024-10-12 18:55:17 +00:00
|
|
|
ma.ForEach(multiaddr, func(c ma.Component, e error) bool {
|
|
|
|
if e != nil {
|
|
|
|
return false
|
|
|
|
}
|
2024-06-08 11:32:45 +00:00
|
|
|
switch c.Protocol().Code {
|
|
|
|
case ma.P_UDP:
|
|
|
|
if state == init {
|
|
|
|
state = foundUDP
|
|
|
|
}
|
|
|
|
case ma.P_QUIC_V1:
|
|
|
|
if state == foundUDP {
|
|
|
|
state = foundQuicV1
|
|
|
|
}
|
|
|
|
case ma.P_WEBTRANSPORT:
|
|
|
|
if state == foundQuicV1 {
|
|
|
|
state = foundWebTransport
|
|
|
|
}
|
|
|
|
case ma.P_CERTHASH:
|
|
|
|
if state == foundWebTransport {
|
|
|
|
certhashCount++
|
|
|
|
}
|
2023-08-21 03:50:38 +00:00
|
|
|
}
|
|
|
|
return true
|
|
|
|
})
|
|
|
|
return state == foundWebTransport, certhashCount
|
|
|
|
}
|