package handshake
import (
"bytes"
"encoding/asn1"
"fmt"
"net"
"time"
"github.com/quic-go/quic-go/internal/protocol"
)
const (
tokenPrefixIP byte = iota
tokenPrefixString
)
type Token struct {
IsRetryToken bool
SentTime time .Time
encodedRemoteAddr []byte
RTT time .Duration
OriginalDestConnectionID protocol .ConnectionID
RetrySrcConnectionID protocol .ConnectionID
}
func (t *Token ) ValidateRemoteAddr (addr net .Addr ) bool {
return bytes .Equal (encodeRemoteAddr (addr ), t .encodedRemoteAddr )
}
type token struct {
IsRetryToken bool
RemoteAddr []byte
Timestamp int64
RTT int64
OriginalDestConnectionID []byte
RetrySrcConnectionID []byte
}
type TokenGenerator struct {
tokenProtector tokenProtector
}
func NewTokenGenerator (key TokenProtectorKey ) *TokenGenerator {
return &TokenGenerator {tokenProtector : *newTokenProtector (key )}
}
func (g *TokenGenerator ) NewRetryToken (
raddr net .Addr ,
origDestConnID protocol .ConnectionID ,
retrySrcConnID protocol .ConnectionID ,
) ([]byte , error ) {
data , err := asn1 .Marshal (token {
IsRetryToken : true ,
RemoteAddr : encodeRemoteAddr (raddr ),
OriginalDestConnectionID : origDestConnID .Bytes (),
RetrySrcConnectionID : retrySrcConnID .Bytes (),
Timestamp : time .Now ().UnixNano (),
})
if err != nil {
return nil , err
}
return g .tokenProtector .NewToken (data )
}
func (g *TokenGenerator ) NewToken (raddr net .Addr , rtt time .Duration ) ([]byte , error ) {
data , err := asn1 .Marshal (token {
RemoteAddr : encodeRemoteAddr (raddr ),
Timestamp : time .Now ().UnixNano (),
RTT : rtt .Microseconds (),
})
if err != nil {
return nil , err
}
return g .tokenProtector .NewToken (data )
}
func (g *TokenGenerator ) DecodeToken (encrypted []byte ) (*Token , error ) {
if len (encrypted ) == 0 {
return nil , nil
}
data , err := g .tokenProtector .DecodeToken (encrypted )
if err != nil {
return nil , err
}
t := &token {}
rest , err := asn1 .Unmarshal (data , t )
if err != nil {
return nil , err
}
if len (rest ) != 0 {
return nil , fmt .Errorf ("rest when unpacking token: %d" , len (rest ))
}
token := &Token {
IsRetryToken : t .IsRetryToken ,
SentTime : time .Unix (0 , t .Timestamp ),
encodedRemoteAddr : t .RemoteAddr ,
}
if t .IsRetryToken {
token .OriginalDestConnectionID = protocol .ParseConnectionID (t .OriginalDestConnectionID )
token .RetrySrcConnectionID = protocol .ParseConnectionID (t .RetrySrcConnectionID )
} else {
token .RTT = time .Duration (t .RTT ) * time .Microsecond
}
return token , nil
}
func encodeRemoteAddr(remoteAddr net .Addr ) []byte {
if udpAddr , ok := remoteAddr .(*net .UDPAddr ); ok {
return append ([]byte {tokenPrefixIP }, udpAddr .IP ...)
}
return append ([]byte {tokenPrefixString }, []byte (remoteAddr .String ())...)
}
The pages are generated with Golds v0.8.2 . (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu .
PR and bug reports are welcome and can be submitted to the issue list .
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds .