1
0
mirror of https://github.com/v2fly/v2ray-core.git synced 2024-12-21 17:46:58 -05:00

srtp header for kcp

This commit is contained in:
v2ray 2016-08-06 21:59:22 +02:00
parent a15e33f720
commit 0d73726930
No known key found for this signature in database
GPG Key ID: 7251FFA14BB18169
14 changed files with 219 additions and 39 deletions

View File

@ -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
}

View File

@ -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)
}

View File

@ -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())
}

View 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)
}
}

View File

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

View 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) })
}

View File

@ -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 {

View File

@ -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
}

View File

@ -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)

View File

@ -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

View File

@ -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
}

View File

@ -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)

View File

@ -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):

View File

@ -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())
}