1
0
mirror of https://github.com/v2fly/v2ray-core.git synced 2024-10-31 00:08:08 -04:00
v2fly/external/github.com/lucas-clemente/quic-go/internal/handshake/cookie_generator.go
2019-01-17 15:33:18 +01:00

110 lines
2.9 KiB
Go

package handshake
import (
"encoding/asn1"
"fmt"
"net"
"time"
"v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/protocol"
)
const (
cookiePrefixIP byte = iota
cookiePrefixString
)
// A Cookie is derived from the client address and can be used to verify the ownership of this address.
type Cookie struct {
RemoteAddr string
OriginalDestConnectionID protocol.ConnectionID
// The time that the Cookie was issued (resolution 1 second)
SentTime time.Time
}
// token is the struct that is used for ASN1 serialization and deserialization
type token struct {
RemoteAddr []byte
OriginalDestConnectionID []byte
Timestamp int64
}
// A CookieGenerator generates Cookies
type CookieGenerator struct {
cookieProtector cookieProtector
}
// NewCookieGenerator initializes a new CookieGenerator
func NewCookieGenerator() (*CookieGenerator, error) {
cookieProtector, err := newCookieProtector()
if err != nil {
return nil, err
}
return &CookieGenerator{
cookieProtector: cookieProtector,
}, nil
}
// NewToken generates a new Cookie for a given source address
func (g *CookieGenerator) NewToken(raddr net.Addr, origConnID protocol.ConnectionID) ([]byte, error) {
data, err := asn1.Marshal(token{
RemoteAddr: encodeRemoteAddr(raddr),
OriginalDestConnectionID: origConnID,
Timestamp: time.Now().Unix(),
})
if err != nil {
return nil, err
}
return g.cookieProtector.NewToken(data)
}
// DecodeToken decodes a Cookie
func (g *CookieGenerator) DecodeToken(encrypted []byte) (*Cookie, error) {
// if the client didn't send any Cookie, DecodeToken will be called with a nil-slice
if len(encrypted) == 0 {
return nil, nil
}
data, err := g.cookieProtector.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))
}
cookie := &Cookie{
RemoteAddr: decodeRemoteAddr(t.RemoteAddr),
SentTime: time.Unix(t.Timestamp, 0),
}
if len(t.OriginalDestConnectionID) > 0 {
cookie.OriginalDestConnectionID = protocol.ConnectionID(t.OriginalDestConnectionID)
}
return cookie, nil
}
// encodeRemoteAddr encodes a remote address such that it can be saved in the Cookie
func encodeRemoteAddr(remoteAddr net.Addr) []byte {
if udpAddr, ok := remoteAddr.(*net.UDPAddr); ok {
return append([]byte{cookiePrefixIP}, udpAddr.IP...)
}
return append([]byte{cookiePrefixString}, []byte(remoteAddr.String())...)
}
// decodeRemoteAddr decodes the remote address saved in the Cookie
func decodeRemoteAddr(data []byte) string {
// data will never be empty for a Cookie that we generated. Check it to be on the safe side
if len(data) == 0 {
return ""
}
if data[0] == cookiePrefixIP {
return net.IP(data[1:]).String()
}
return string(data[1:])
}