ceremonyclient/go-libp2p/p2p/transport/webrtc/sdp.go
Cassie Heart ebb31fd792 v1.4.19
2024-06-08 11:32:45 +00:00

144 lines
3.3 KiB
Go

package libp2pwebrtc
import (
"crypto"
"fmt"
"net"
"strings"
"github.com/multiformats/go-multihash"
)
// clientSDP describes an SDP format string which can be used
// to infer a client's SDP offer from the incoming STUN message.
// The fingerprint used to render a client SDP is arbitrary since
// it fingerprint verification is disabled in favour of a noise
// handshake. The max message size is fixed to 16384 bytes.
const clientSDP = `v=0
o=- 0 0 IN %[1]s %[2]s
s=-
c=IN %[1]s %[2]s
t=0 0
m=application %[3]d UDP/DTLS/SCTP webrtc-datachannel
a=mid:0
a=ice-options:ice2
a=ice-ufrag:%[4]s
a=ice-pwd:%[4]s
a=fingerprint:sha-256 ba:78:16:bf:8f:01:cf:ea:41:41:40:de:5d:ae:22:23:b0:03:61:a3:96:17:7a:9c:b4:10:ff:61:f2:00:15:ad
a=setup:actpass
a=sctp-port:5000
a=max-message-size:16384
`
func createClientSDP(addr *net.UDPAddr, ufrag string) string {
ipVersion := "IP4"
if addr.IP.To4() == nil {
ipVersion = "IP6"
}
return fmt.Sprintf(
clientSDP,
ipVersion,
addr.IP,
addr.Port,
ufrag,
)
}
// serverSDP defines an SDP format string used by a dialer
// to infer the SDP answer of a server based on the provided
// multiaddr, and the locally set ICE credentials. The max
// message size is fixed to 16384 bytes.
const serverSDP = `v=0
o=- 0 0 IN %[1]s %[2]s
s=-
t=0 0
a=ice-lite
m=application %[3]d UDP/DTLS/SCTP webrtc-datachannel
c=IN %[1]s %[2]s
a=mid:0
a=ice-options:ice2
a=ice-ufrag:%[4]s
a=ice-pwd:%[4]s
a=fingerprint:%[5]s
a=setup:passive
a=sctp-port:5000
a=max-message-size:16384
a=candidate:1 1 UDP 1 %[2]s %[3]d typ host
a=end-of-candidates
`
func createServerSDP(addr *net.UDPAddr, ufrag string, fingerprint multihash.DecodedMultihash) (string, error) {
ipVersion := "IP4"
if addr.IP.To4() == nil {
ipVersion = "IP6"
}
sdpString, err := getSupportedSDPString(fingerprint.Code)
if err != nil {
return "", err
}
var builder strings.Builder
builder.Grow(len(fingerprint.Digest)*3 + 8)
builder.WriteString(sdpString)
builder.WriteByte(' ')
builder.WriteString(encodeInterspersedHex(fingerprint.Digest))
fp := builder.String()
return fmt.Sprintf(
serverSDP,
ipVersion,
addr.IP,
addr.Port,
ufrag,
fp,
), nil
}
// getSupportedSDPHash converts a multihash code to the
// corresponding crypto.Hash for supported protocols. If a
// crypto.Hash cannot be found, it returns `(0, false)`
func getSupportedSDPHash(code uint64) (crypto.Hash, bool) {
switch code {
case multihash.MD5:
return crypto.MD5, true
case multihash.SHA1:
return crypto.SHA1, true
case multihash.SHA3_224:
return crypto.SHA3_224, true
case multihash.SHA2_256:
return crypto.SHA256, true
case multihash.SHA3_384:
return crypto.SHA3_384, true
case multihash.SHA2_512:
return crypto.SHA512, true
default:
return 0, false
}
}
// getSupportedSDPString converts a multihash code
// to a string format recognised by pion for fingerprint
// algorithms
func getSupportedSDPString(code uint64) (string, error) {
// values based on (cryto.Hash).String()
switch code {
case multihash.MD5:
return "md5", nil
case multihash.SHA1:
return "sha-1", nil
case multihash.SHA3_224:
return "sha3-224", nil
case multihash.SHA2_256:
return "sha-256", nil
case multihash.SHA3_384:
return "sha3-384", nil
case multihash.SHA2_512:
return "sha-512", nil
default:
return "", fmt.Errorf("unsupported hash code (%d)", code)
}
}