Obfuscator interface in core & relay/proxy CLI support

This commit is contained in:
Toby 2020-04-23 14:43:12 -07:00
parent c441afea35
commit 5ebe556d8d
11 changed files with 145 additions and 7 deletions

View file

@ -7,6 +7,7 @@ import (
"github.com/lucas-clemente/quic-go/congestion"
hyCongestion "github.com/tobyxdd/hysteria/pkg/congestion"
"github.com/tobyxdd/hysteria/pkg/core"
"github.com/tobyxdd/hysteria/pkg/obfs"
"github.com/tobyxdd/hysteria/pkg/socks5"
"io/ioutil"
"log"
@ -52,11 +53,16 @@ func proxyClient(args []string) {
quicConfig.MaxReceiveConnectionFlowControlWindow = DefaultMaxReceiveConnectionFlowControlWindow
}
var obfuscator core.Obfuscator
if len(config.Obfs) > 0 {
obfuscator = obfs.XORObfuscator(config.Obfs)
}
client, err := core.NewClient(config.ServerAddr, config.Username, config.Password, tlsConfig, quicConfig,
uint64(config.UpMbps)*mbpsToBps, uint64(config.DownMbps)*mbpsToBps,
func(refBPS uint64) congestion.SendAlgorithmWithDebugInfos {
return hyCongestion.NewBrutalSender(congestion.ByteCount(refBPS))
})
}, obfuscator)
if err != nil {
log.Fatalln("Client initialization failed:", err)
}

View file

@ -16,6 +16,7 @@ type proxyClientConfig struct {
DownMbps int `json:"down_mbps" desc:"Download speed in Mbps"`
ReceiveWindowConn uint64 `json:"recv_window_conn" desc:"Max receive window size per connection"`
ReceiveWindow uint64 `json:"recv_window" desc:"Max receive window size"`
Obfs string `json:"obfs" desc:"Obfuscation key"`
}
func (c *proxyClientConfig) Check() error {
@ -48,6 +49,7 @@ type proxyServerConfig struct {
ReceiveWindowConn uint64 `json:"recv_window_conn" desc:"Max receive window size per connection"`
ReceiveWindowClient uint64 `json:"recv_window_client" desc:"Max receive window size per client"`
MaxConnClient int `json:"max_conn_client" desc:"Max simultaneous connections allowed per client"`
Obfs string `json:"obfs" desc:"Obfuscation key"`
}
func (c *proxyServerConfig) Check() error {

View file

@ -7,6 +7,7 @@ import (
"github.com/lucas-clemente/quic-go/congestion"
hyCongestion "github.com/tobyxdd/hysteria/pkg/congestion"
"github.com/tobyxdd/hysteria/pkg/core"
"github.com/tobyxdd/hysteria/pkg/obfs"
"io"
"log"
"net"
@ -55,11 +56,17 @@ func proxyServer(args []string) {
log.Println("WARNING: No authentication configured. This server can be used by anyone!")
}
var obfuscator core.Obfuscator
if len(config.Obfs) > 0 {
obfuscator = obfs.XORObfuscator(config.Obfs)
}
server, err := core.NewServer(config.ListenAddr, tlsConfig, quicConfig,
uint64(config.UpMbps)*mbpsToBps, uint64(config.DownMbps)*mbpsToBps,
func(refBPS uint64) congestion.SendAlgorithmWithDebugInfos {
return hyCongestion.NewBrutalSender(congestion.ByteCount(refBPS))
},
obfuscator,
func(addr net.Addr, username string, password string, sSend uint64, sRecv uint64) (core.AuthResult, string) {
if len(config.AuthFile) == 0 {
log.Printf("%s (%s) connected, negotiated speed (Mbps): Up %d / Down %d\n",

View file

@ -8,6 +8,7 @@ import (
"github.com/tobyxdd/hysteria/internal/utils"
hyCongestion "github.com/tobyxdd/hysteria/pkg/congestion"
"github.com/tobyxdd/hysteria/pkg/core"
"github.com/tobyxdd/hysteria/pkg/obfs"
"io/ioutil"
"log"
"net"
@ -60,11 +61,16 @@ func relayClient(args []string) {
quicConfig.MaxReceiveConnectionFlowControlWindow = DefaultMaxReceiveConnectionFlowControlWindow
}
var obfuscator core.Obfuscator
if len(config.Obfs) > 0 {
obfuscator = obfs.XORObfuscator(config.Obfs)
}
client, err := core.NewClient(config.ServerAddr, config.Name, "", tlsConfig, quicConfig,
uint64(config.UpMbps)*mbpsToBps, uint64(config.DownMbps)*mbpsToBps,
func(refBPS uint64) congestion.SendAlgorithmWithDebugInfos {
return hyCongestion.NewBrutalSender(congestion.ByteCount(refBPS))
})
}, obfuscator)
if err != nil {
log.Fatalln("Client initialization failed:", err)
}

View file

@ -14,6 +14,7 @@ type relayClientConfig struct {
DownMbps int `json:"down_mbps" desc:"Download speed in Mbps"`
ReceiveWindowConn uint64 `json:"recv_window_conn" desc:"Max receive window size per connection"`
ReceiveWindow uint64 `json:"recv_window" desc:"Max receive window size"`
Obfs string `json:"obfs" desc:"Obfuscation key"`
}
func (c *relayClientConfig) Check() error {
@ -43,6 +44,7 @@ type relayServerConfig struct {
ReceiveWindowConn uint64 `json:"recv_window_conn" desc:"Max receive window size per connection"`
ReceiveWindowClient uint64 `json:"recv_window_client" desc:"Max receive window size per client"`
MaxConnClient int `json:"max_conn_client" desc:"Max simultaneous connections allowed per client"`
Obfs string `json:"obfs" desc:"Obfuscation key"`
}
func (c *relayServerConfig) Check() error {

View file

@ -6,6 +6,7 @@ import (
"github.com/lucas-clemente/quic-go/congestion"
hyCongestion "github.com/tobyxdd/hysteria/pkg/congestion"
"github.com/tobyxdd/hysteria/pkg/core"
"github.com/tobyxdd/hysteria/pkg/obfs"
"io"
"log"
"net"
@ -48,11 +49,17 @@ func relayServer(args []string) {
quicConfig.MaxIncomingStreams = DefaultMaxIncomingStreams
}
var obfuscator core.Obfuscator
if len(config.Obfs) > 0 {
obfuscator = obfs.XORObfuscator(config.Obfs)
}
server, err := core.NewServer(config.ListenAddr, tlsConfig, quicConfig,
uint64(config.UpMbps)*mbpsToBps, uint64(config.DownMbps)*mbpsToBps,
func(refBPS uint64) congestion.SendAlgorithmWithDebugInfos {
return hyCongestion.NewBrutalSender(congestion.ByteCount(refBPS))
},
obfuscator,
func(addr net.Addr, username string, password string, sSend uint64, sRecv uint64) (core.AuthResult, string) {
// No authentication logic in relay, just log username and speed
log.Printf("%s (%s) connected, negotiated speed (Mbps): Up %d / Down %d\n",

View file

@ -29,10 +29,11 @@ type Client struct {
quicConfig *quic.Config
sendBPS, recvBPS uint64
congestionFactory CongestionFactory
obfuscator Obfuscator
}
func NewClient(serverAddr string, username string, password string, tlsConfig *tls.Config, quicConfig *quic.Config,
sendBPS uint64, recvBPS uint64, congestionFactory CongestionFactory) (*Client, error) {
sendBPS uint64, recvBPS uint64, congestionFactory CongestionFactory, obfuscator Obfuscator) (*Client, error) {
c := &Client{
serverAddr: serverAddr,
username: username,
@ -42,6 +43,7 @@ func NewClient(serverAddr string, username string, password string, tlsConfig *t
sendBPS: sendBPS,
recvBPS: recvBPS,
congestionFactory: congestionFactory,
obfuscator: obfuscator,
}
if err := c.connectToServer(); err != nil {
return nil, err
@ -97,7 +99,22 @@ func (c *Client) Close() error {
}
func (c *Client) connectToServer() error {
qs, err := quic.DialAddr(c.serverAddr, c.tlsConfig, c.quicConfig)
serverUDPAddr, err := net.ResolveUDPAddr("udp", c.serverAddr)
if err != nil {
return err
}
packetConn, err := net.ListenPacket("udp", "")
if err != nil {
return err
}
if c.obfuscator != nil {
// Wrap PacketConn with obfuscator
packetConn = &obfsPacketConn{
Orig: packetConn,
Obfuscator: c.obfuscator,
}
}
qs, err := quic.Dial(packetConn, serverUDPAddr, c.serverAddr, c.tlsConfig, c.quicConfig)
if err != nil {
return err
}

56
internal/core/obfs.go Normal file
View file

@ -0,0 +1,56 @@
package core
import (
"net"
"time"
)
type Obfuscator interface {
Deobfuscate(buf []byte, n int) int
Obfuscate(p []byte) []byte
}
type obfsPacketConn struct {
Orig net.PacketConn
Obfuscator Obfuscator
}
func (c *obfsPacketConn) ReadFrom(p []byte) (n int, addr net.Addr, err error) {
oldN, addr, err := c.Orig.ReadFrom(p)
if oldN > 0 {
newN := c.Obfuscator.Deobfuscate(p, oldN)
return newN, addr, err
} else {
return 0, addr, err
}
}
func (c *obfsPacketConn) WriteTo(p []byte, addr net.Addr) (n int, err error) {
np := c.Obfuscator.Obfuscate(p)
_, err = c.Orig.WriteTo(np, addr)
if err != nil {
return 0, err
} else {
return len(p), nil
}
}
func (c *obfsPacketConn) Close() error {
return c.Orig.Close()
}
func (c *obfsPacketConn) LocalAddr() net.Addr {
return c.Orig.LocalAddr()
}
func (c *obfsPacketConn) SetDeadline(t time.Time) error {
return c.Orig.SetDeadline(t)
}
func (c *obfsPacketConn) SetReadDeadline(t time.Time) error {
return c.Orig.SetReadDeadline(t)
}
func (c *obfsPacketConn) SetWriteDeadline(t time.Time) error {
return c.Orig.SetWriteDeadline(t)
}

View file

@ -32,11 +32,23 @@ type Server struct {
func NewServer(addr string, tlsConfig *tls.Config, quicConfig *quic.Config,
sendBPS uint64, recvBPS uint64, congestionFactory CongestionFactory,
obfuscator Obfuscator,
clientAuthFunc ClientAuthFunc,
clientDisconnectedFunc ClientDisconnectedFunc,
handleRequestFunc HandleRequestFunc,
requestClosedFunc RequestClosedFunc) (*Server, error) {
listener, err := quic.ListenAddr(addr, tlsConfig, quicConfig)
packetConn, err := net.ListenPacket("udp", addr)
if err != nil {
return nil, err
}
if obfuscator != nil {
// Wrap PacketConn with obfuscator
packetConn = &obfsPacketConn{
Orig: packetConn,
Obfuscator: obfuscator,
}
}
listener, err := quic.Listen(packetConn, tlsConfig, quicConfig)
if err != nil {
return nil, err
}

View file

@ -25,6 +25,7 @@ const (
)
type CongestionFactory core.CongestionFactory
type Obfuscator core.Obfuscator
type ClientAuthFunc func(addr net.Addr, username string, password string, sSend uint64, sRecv uint64) (AuthResult, string)
type ClientDisconnectedFunc core.ClientDisconnectedFunc
type HandleRequestFunc func(addr net.Addr, username string, id int, packet bool, reqAddr string) (ConnectResult, string, io.ReadWriteCloser)
@ -38,11 +39,13 @@ type Server interface {
func NewServer(addr string, tlsConfig *tls.Config, quicConfig *quic.Config,
sendBPS uint64, recvBPS uint64, congestionFactory CongestionFactory,
obfuscator Obfuscator,
clientAuthFunc ClientAuthFunc,
clientDisconnectedFunc ClientDisconnectedFunc,
handleRequestFunc HandleRequestFunc,
requestClosedFunc RequestClosedFunc) (Server, error) {
return core.NewServer(addr, tlsConfig, quicConfig, sendBPS, recvBPS, core.CongestionFactory(congestionFactory),
core.Obfuscator(obfuscator),
func(addr net.Addr, username string, password string, sSend uint64, sRecv uint64) (core.AuthResult, string) {
r, msg := clientAuthFunc(addr, username, password, sSend, sRecv)
return core.AuthResult(r), msg
@ -65,7 +68,7 @@ type Client interface {
func NewClient(serverAddr string, username string, password string,
tlsConfig *tls.Config, quicConfig *quic.Config, sendBPS uint64, recvBPS uint64,
congestionFactory CongestionFactory) (Client, error) {
congestionFactory CongestionFactory, obfuscator Obfuscator) (Client, error) {
return core.NewClient(serverAddr, username, password, tlsConfig, quicConfig, sendBPS, recvBPS,
core.CongestionFactory(congestionFactory))
core.CongestionFactory(congestionFactory), core.Obfuscator(obfuscator))
}

20
pkg/obfs/xor.go Normal file
View file

@ -0,0 +1,20 @@
package obfs
type XORObfuscator []byte
func (x XORObfuscator) Deobfuscate(buf []byte, n int) int {
l := len(x)
for i := range buf {
buf[i] ^= x[i%l]
}
return n
}
func (x XORObfuscator) Obfuscate(p []byte) []byte {
np := make([]byte, len(p))
l := len(x)
for i := range p {
np[i] = p[i] ^ x[i%l]
}
return np
}