mirror of
https://github.com/v2fly/v2ray-core.git
synced 2024-12-21 09:36:34 -05:00
srtp header for kcp
This commit is contained in:
parent
a15e33f720
commit
0d73726930
@ -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
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
|
||||
|
@ -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
transport/internet/authenticator.go
Normal file
87
transport/internet/authenticator.go
Normal file
@ -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
transport/internet/authenticator_json.go
Normal file
9
transport/internet/authenticator_json.go
Normal file
@ -0,0 +1,9 @@
|
||||
// +build json
|
||||
|
||||
package internet
|
||||
|
||||
import "github.com/v2ray/v2ray-core/common/loader"
|
||||
|
||||
func init() {
|
||||
configCache = loader.NewJSONConfigLoader("type", "")
|
||||
}
|
51
transport/internet/internal/obsrtp/obsrtp.go
Normal file
51
transport/internet/internal/obsrtp/obsrtp.go
Normal file
@ -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) })
|
||||
}
|
@ -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,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
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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):
|
||||
|
@ -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())
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user