Przeglądaj źródła

srtp header for kcp

v2ray 9 lat temu
rodzic
commit
0d73726930

+ 10 - 6
common/loader/json_conf.go

@@ -34,28 +34,32 @@ func (this *JSONConfigLoader) LoadWithID(raw []byte, id string) (interface{}, er
 	return config, nil
 }
 
-func (this *JSONConfigLoader) Load(raw []byte) (interface{}, error) {
+func (this *JSONConfigLoader) Load(raw []byte) (interface{}, string, error) {
 	var obj map[string]json.RawMessage
 	if err := json.Unmarshal(raw, &obj); err != nil {
-		return nil, err
+		return nil, "", err
 	}
 	rawID, found := obj[this.idKey]
 	if !found {
 		log.Error(this.idKey, " not found in JSON content.")
-		return nil, ErrConfigIDKeyNotFound
+		return nil, "", ErrConfigIDKeyNotFound
 	}
 	var id string
 	if err := json.Unmarshal(rawID, &id); err != nil {
-		return nil, err
+		return nil, "", err
 	}
 	rawConfig := json.RawMessage(raw)
 	if len(this.configKey) > 0 {
 		configValue, found := obj[this.configKey]
 		if !found {
 			log.Error(this.configKey, " not found in JSON content.")
-			return nil, ErrConfigIDKeyNotFound
+			return nil, "", ErrConfigIDKeyNotFound
 		}
 		rawConfig = configValue
 	}
-	return this.LoadWithID([]byte(rawConfig), id)
+	config, err := this.LoadWithID([]byte(rawConfig), id)
+	if err != nil {
+		return nil, id, err
+	}
+	return config, id, nil
 }

+ 1 - 1
common/loader/loader.go

@@ -15,7 +15,7 @@ type ConfigCreator func() interface{}
 type ConfigLoader interface {
 	RegisterCreator(string, ConfigCreator) error
 	CreateConfig(string) (interface{}, error)
-	Load([]byte) (interface{}, error)
+	Load([]byte) (interface{}, string, error)
 	LoadWithID([]byte, string) (interface{}, error)
 }
 

+ 1 - 1
proxy/blackhole/config_json.go

@@ -24,7 +24,7 @@ func (this *Config) UnmarshalJSON(data []byte) error {
 		loader := loader.NewJSONConfigLoader("type", "")
 		loader.RegisterCreator("none", func() interface{} { return new(NoneResponse) })
 		loader.RegisterCreator("http", func() interface{} { return new(HTTPResponse) })
-		response, err := loader.Load(jsonConfig.Response)
+		response, _, err := loader.Load(jsonConfig.Response)
 		if err != nil {
 			return errors.New("Blackhole: Failed to parse response config: " + err.Error())
 		}

+ 87 - 0
transport/internet/authenticator.go

@@ -0,0 +1,87 @@
+package internet
+
+import (
+	"errors"
+
+	"github.com/v2ray/v2ray-core/common/alloc"
+	"github.com/v2ray/v2ray-core/common/loader"
+)
+
+type Authenticator interface {
+	Seal(*alloc.Buffer)
+	Open(*alloc.Buffer) bool
+	Overhead() int
+}
+
+type AuthenticatorFactory interface {
+	Create(AuthenticatorConfig) Authenticator
+}
+
+type AuthenticatorConfig interface {
+}
+
+var (
+	ErrDuplicatedAuthenticator = errors.New("Authenticator already registered.")
+	ErrAuthenticatorNotFound   = errors.New("Authenticator not found.")
+
+	authenticatorCache = make(map[string]AuthenticatorFactory)
+	configCache        loader.ConfigLoader
+)
+
+func RegisterAuthenticator(name string, factory AuthenticatorFactory, configCreator loader.ConfigCreator) error {
+	if _, found := authenticatorCache[name]; found {
+		return ErrDuplicatedAuthenticator
+	}
+	authenticatorCache[name] = factory
+	return configCache.RegisterCreator(name, configCreator)
+}
+
+func CreateAuthenticator(name string, config AuthenticatorConfig) (Authenticator, error) {
+	factory, found := authenticatorCache[name]
+	if !found {
+		return nil, ErrAuthenticatorNotFound
+	}
+	return factory.Create(config.(AuthenticatorConfig)), nil
+}
+
+func CreateAuthenticatorConfig(rawConfig []byte) (string, AuthenticatorConfig, error) {
+	config, name, err := configCache.Load(rawConfig)
+	if err != nil {
+		return name, nil, err
+	}
+	return name, config, nil
+}
+
+type AuthenticatorChain struct {
+	authenticators []Authenticator
+}
+
+func NewAuthenticatorChain(auths ...Authenticator) Authenticator {
+	return &AuthenticatorChain{
+		authenticators: auths,
+	}
+}
+
+func (this *AuthenticatorChain) Overhead() int {
+	total := 0
+	for _, auth := range this.authenticators {
+		total += auth.Overhead()
+	}
+	return total
+}
+
+func (this *AuthenticatorChain) Open(payload *alloc.Buffer) bool {
+	for _, auth := range this.authenticators {
+		if !auth.Open(payload) {
+			return false
+		}
+	}
+	return true
+}
+
+func (this *AuthenticatorChain) Seal(payload *alloc.Buffer) {
+	for i := len(this.authenticators) - 1; i >= 0; i-- {
+		auth := this.authenticators[i]
+		auth.Seal(payload)
+	}
+}

+ 9 - 0
transport/internet/authenticator_json.go

@@ -0,0 +1,9 @@
+// +build json
+
+package internet
+
+import "github.com/v2ray/v2ray-core/common/loader"
+
+func init() {
+	configCache = loader.NewJSONConfigLoader("type", "")
+}

+ 51 - 0
transport/internet/internal/obsrtp/obsrtp.go

@@ -0,0 +1,51 @@
+package obsrtp
+
+import (
+	"math/rand"
+
+	"github.com/v2ray/v2ray-core/common/alloc"
+	"github.com/v2ray/v2ray-core/transport/internet"
+)
+
+type Config struct {
+	Version     byte
+	Padding     bool
+	Extension   bool
+	CSRCCount   byte
+	Marker      bool
+	PayloadType byte
+}
+
+type ObfuscatorSRTP struct {
+	header uint16
+	number uint16
+}
+
+func (this *ObfuscatorSRTP) Overhead() int {
+	return 4
+}
+
+func (this *ObfuscatorSRTP) Open(payload *alloc.Buffer) bool {
+	payload.SliceFrom(this.Overhead())
+	return true
+}
+
+func (this *ObfuscatorSRTP) Seal(payload *alloc.Buffer) {
+	this.number++
+	payload.PrependUint16(this.number)
+	payload.PrependUint16(this.header)
+}
+
+type ObfuscatorSRTPFactory struct {
+}
+
+func (this ObfuscatorSRTPFactory) Create(rawSettings internet.AuthenticatorConfig) internet.Authenticator {
+	return &ObfuscatorSRTP{
+		header: 0xB5E8,
+		number: uint16(rand.Intn(65536)),
+	}
+}
+
+func init() {
+	internet.RegisterAuthenticator("srtp", ObfuscatorSRTPFactory{}, func() interface{} { return new(Config) })
+}

+ 18 - 0
transport/internet/kcp/config.go

@@ -1,5 +1,9 @@
 package kcp
 
+import (
+	"github.com/v2ray/v2ray-core/transport/internet"
+)
+
 type Config struct {
 	Mtu              uint32 // Maximum transmission unit
 	Tti              uint32
@@ -8,12 +12,26 @@ type Config struct {
 	Congestion       bool
 	WriteBuffer      uint32
 	ReadBuffer       uint32
+	HeaderType       string
+	HeaderConfig     internet.AuthenticatorConfig
 }
 
 func (this *Config) Apply() {
 	effectiveConfig = *this
 }
 
+func (this *Config) GetAuthenticator() (internet.Authenticator, error) {
+	auth := NewSimpleAuthenticator()
+	if this.HeaderConfig != nil {
+		header, err := internet.CreateAuthenticator(this.HeaderType, this.HeaderConfig)
+		if err != nil {
+			return nil, err
+		}
+		auth = internet.NewAuthenticatorChain(header, auth)
+	}
+	return auth, nil
+}
+
 func (this *Config) GetSendingInFlightSize() uint32 {
 	size := this.UplinkCapacity * 1024 * 1024 / this.Mtu / (1000 / this.Tti) / 2
 	if size == 0 {

+ 11 - 7
transport/internet/kcp/config_json.go

@@ -11,13 +11,14 @@ import (
 
 func (this *Config) UnmarshalJSON(data []byte) error {
 	type JSONConfig struct {
-		Mtu             *uint32 `json:"mtu"`
-		Tti             *uint32 `json:"tti"`
-		UpCap           *uint32 `json:"uplinkCapacity"`
-		DownCap         *uint32 `json:"downlinkCapacity"`
-		Congestion      *bool   `json:"congestion"`
-		ReadBufferSize  *uint32 `json:"readBufferSize"`
-		WriteBufferSize *uint32 `json:"writeBufferSize"`
+		Mtu             *uint32         `json:"mtu"`
+		Tti             *uint32         `json:"tti"`
+		UpCap           *uint32         `json:"uplinkCapacity"`
+		DownCap         *uint32         `json:"downlinkCapacity"`
+		Congestion      *bool           `json:"congestion"`
+		ReadBufferSize  *uint32         `json:"readBufferSize"`
+		WriteBufferSize *uint32         `json:"writeBufferSize"`
+		HeaderConfig    json.RawMessage `json:"header"`
 	}
 	jsonConfig := new(JSONConfig)
 	if err := json.Unmarshal(data, &jsonConfig); err != nil {
@@ -64,6 +65,9 @@ func (this *Config) UnmarshalJSON(data []byte) error {
 			this.WriteBuffer = 512 * 1024
 		}
 	}
+	if len(jsonConfig.HeaderConfig) > 0 {
+		this.HeaderConfig = jsonConfig.HeaderConfig
+	}
 
 	return nil
 }

+ 3 - 2
transport/internet/kcp/connection.go

@@ -10,6 +10,7 @@ import (
 
 	"github.com/v2ray/v2ray-core/common/alloc"
 	"github.com/v2ray/v2ray-core/common/log"
+	"github.com/v2ray/v2ray-core/transport/internet"
 )
 
 var (
@@ -121,7 +122,7 @@ func (this *RoundTripInfo) SmoothedTime() uint32 {
 
 // Connection is a KCP connection over UDP.
 type Connection struct {
-	block          Authenticator
+	block          internet.Authenticator
 	local, remote  net.Addr
 	rd             time.Time
 	wd             time.Time // write deadline
@@ -149,7 +150,7 @@ type Connection struct {
 }
 
 // NewConnection create a new KCP connection between local and remote.
-func NewConnection(conv uint16, writerCloser io.WriteCloser, local *net.UDPAddr, remote *net.UDPAddr, block Authenticator) *Connection {
+func NewConnection(conv uint16, writerCloser io.WriteCloser, local *net.UDPAddr, remote *net.UDPAddr, block internet.Authenticator) *Connection {
 	log.Info("KCP|Connection: creating connection ", conv)
 
 	conn := new(Connection)

+ 6 - 2
transport/internet/kcp/connection_test.go

@@ -9,6 +9,8 @@ import (
 
 	v2net "github.com/v2ray/v2ray-core/common/net"
 	"github.com/v2ray/v2ray-core/testing/assert"
+	"github.com/v2ray/v2ray-core/transport/internet"
+	"github.com/v2ray/v2ray-core/transport/internet/internal/obsrtp"
 	. "github.com/v2ray/v2ray-core/transport/internet/kcp"
 )
 
@@ -40,10 +42,12 @@ func TestConnectionReadWrite(t *testing.T) {
 	upReader, upWriter := io.Pipe()
 	downReader, downWriter := io.Pipe()
 
-	connClient := NewConnection(1, upWriter, &net.UDPAddr{IP: v2net.LocalHostIP.IP(), Port: 1}, &net.UDPAddr{IP: v2net.LocalHostIP.IP(), Port: 2}, NewSimpleAuthenticator())
+	auth := internet.NewAuthenticatorChain(obsrtp.ObfuscatorSRTPFactory{}.Create(nil), NewSimpleAuthenticator())
+
+	connClient := NewConnection(1, upWriter, &net.UDPAddr{IP: v2net.LocalHostIP.IP(), Port: 1}, &net.UDPAddr{IP: v2net.LocalHostIP.IP(), Port: 2}, auth)
 	connClient.FetchInputFrom(downReader)
 
-	connServer := NewConnection(1, downWriter, &net.UDPAddr{IP: v2net.LocalHostIP.IP(), Port: 2}, &net.UDPAddr{IP: v2net.LocalHostIP.IP(), Port: 1}, NewSimpleAuthenticator())
+	connServer := NewConnection(1, downWriter, &net.UDPAddr{IP: v2net.LocalHostIP.IP(), Port: 2}, &net.UDPAddr{IP: v2net.LocalHostIP.IP(), Port: 1}, auth)
 	connServer.FetchInputFrom(upReader)
 
 	totalWritten := 1024 * 1024

+ 3 - 13
transport/internet/kcp/crypt.go

@@ -5,26 +5,16 @@ import (
 
 	"github.com/v2ray/v2ray-core/common/alloc"
 	"github.com/v2ray/v2ray-core/common/serial"
+	"github.com/v2ray/v2ray-core/transport/internet"
 )
 
-type Authenticator interface {
-	HeaderSize() int
-	// Encrypt encrypts the whole block in src into dst.
-	// Dst and src may point at the same memory.
-	Seal(buffer *alloc.Buffer)
-
-	// Decrypt decrypts the whole block in src into dst.
-	// Dst and src may point at the same memory.
-	Open(buffer *alloc.Buffer) bool
-}
-
 type SimpleAuthenticator struct{}
 
-func NewSimpleAuthenticator() Authenticator {
+func NewSimpleAuthenticator() internet.Authenticator {
 	return &SimpleAuthenticator{}
 }
 
-func (this *SimpleAuthenticator) HeaderSize() int {
+func (this *SimpleAuthenticator) Overhead() int {
 	return 6
 }
 

+ 4 - 1
transport/internet/kcp/dialer.go

@@ -22,7 +22,10 @@ func DialKCP(src v2net.Address, dest v2net.Destination) (internet.Connection, er
 		return nil, err
 	}
 
-	cpip := NewSimpleAuthenticator()
+	cpip, err := effectiveConfig.GetAuthenticator()
+	if err != nil {
+		return nil, err
+	}
 	conv := uint16(atomic.AddUint32(&globalConv, 1))
 	session := NewConnection(conv, conn, conn.LocalAddr().(*net.UDPAddr), conn.RemoteAddr().(*net.UDPAddr), cpip)
 	session.FetchInputFrom(conn)

+ 12 - 4
transport/internet/kcp/listener.go

@@ -17,7 +17,7 @@ import (
 type Listener struct {
 	sync.Mutex
 	running       bool
-	block         Authenticator
+	authenticator internet.Authenticator
 	sessions      map[string]*Connection
 	awaitingConns chan *Connection
 	hub           *udp.UDPHub
@@ -25,8 +25,12 @@ type Listener struct {
 }
 
 func NewListener(address v2net.Address, port v2net.Port) (*Listener, error) {
+	auth, err := effectiveConfig.GetAuthenticator()
+	if err != nil {
+		return nil, err
+	}
 	l := &Listener{
-		block:         NewSimpleAuthenticator(),
+		authenticator: auth,
 		sessions:      make(map[string]*Connection),
 		awaitingConns: make(chan *Connection, 64),
 		localAddr: &net.UDPAddr{
@@ -47,7 +51,7 @@ func NewListener(address v2net.Address, port v2net.Port) (*Listener, error) {
 func (this *Listener) OnReceive(payload *alloc.Buffer, src v2net.Destination) {
 	defer payload.Release()
 
-	if valid := this.block.Open(payload); !valid {
+	if valid := this.authenticator.Open(payload); !valid {
 		log.Info("KCP|Listener: discarding invalid payload from ", src)
 		return
 	}
@@ -81,7 +85,11 @@ func (this *Listener) OnReceive(payload *alloc.Buffer, src v2net.Destination) {
 			IP:   src.Address().IP(),
 			Port: int(src.Port()),
 		}
-		conn = NewConnection(conv, writer, this.localAddr, srcAddr, this.block)
+		auth, err := effectiveConfig.GetAuthenticator()
+		if err != nil {
+			log.Error("KCP|Listener: Failed to create authenticator: ", err)
+		}
+		conn = NewConnection(conv, writer, this.localAddr, srcAddr, auth)
 		select {
 		case this.awaitingConns <- conn:
 		case <-time.After(time.Second * 5):

+ 3 - 2
transport/internet/kcp/output.go

@@ -6,6 +6,7 @@ import (
 
 	"github.com/v2ray/v2ray-core/common/alloc"
 	v2io "github.com/v2ray/v2ray-core/common/io"
+	"github.com/v2ray/v2ray-core/transport/internet"
 )
 
 type SegmentWriter interface {
@@ -59,7 +60,7 @@ func (this *BufferedSegmentWriter) Flush() {
 }
 
 type AuthenticationWriter struct {
-	Authenticator Authenticator
+	Authenticator internet.Authenticator
 	Writer        io.Writer
 }
 
@@ -74,5 +75,5 @@ func (this *AuthenticationWriter) Write(payload *alloc.Buffer) error {
 func (this *AuthenticationWriter) Release() {}
 
 func (this *AuthenticationWriter) Mtu() uint32 {
-	return effectiveConfig.Mtu - uint32(this.Authenticator.HeaderSize())
+	return effectiveConfig.Mtu - uint32(this.Authenticator.Overhead())
 }