mirror of
https://github.com/apernet/hysteria.git
synced 2025-04-03 20:47:38 +03:00
commit
f396cae604
11 changed files with 173 additions and 14 deletions
|
@ -68,7 +68,7 @@ func client(config *clientConfig) {
|
|||
// Obfuscator
|
||||
var obfuscator core.Obfuscator
|
||||
if len(config.Obfs) > 0 {
|
||||
obfuscator = obfs.XORObfuscator(config.Obfs)
|
||||
obfuscator = obfs.NewXPlusObfuscator([]byte(config.Obfs))
|
||||
}
|
||||
// ACL
|
||||
var aclEngine *acl.Engine
|
||||
|
|
|
@ -99,7 +99,7 @@ func server(config *serverConfig) {
|
|||
// Obfuscator
|
||||
var obfuscator core.Obfuscator
|
||||
if len(config.Obfs) > 0 {
|
||||
obfuscator = obfs.XORObfuscator(config.Obfs)
|
||||
obfuscator = obfs.NewXPlusObfuscator([]byte(config.Obfs))
|
||||
}
|
||||
// ACL
|
||||
var aclEngine *acl.Engine
|
||||
|
|
|
@ -9,6 +9,7 @@ import (
|
|||
"github.com/lucas-clemente/quic-go"
|
||||
"github.com/lucas-clemente/quic-go/congestion"
|
||||
"github.com/lunixbochs/struc"
|
||||
"github.com/tobyxdd/hysteria/pkg/utils"
|
||||
"net"
|
||||
"strconv"
|
||||
"sync"
|
||||
|
@ -66,6 +67,10 @@ func (c *Client) connectToServer() error {
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := utils.SetDontFragment(udpConn); err != nil {
|
||||
_ = udpConn.Close()
|
||||
return err
|
||||
}
|
||||
var qs quic.Session
|
||||
if c.obfuscator != nil {
|
||||
// Wrap PacketConn with obfuscator
|
||||
|
@ -74,11 +79,13 @@ func (c *Client) connectToServer() error {
|
|||
Obfuscator: c.obfuscator,
|
||||
}, serverUDPAddr, c.serverAddr, c.tlsConfig, c.quicConfig)
|
||||
if err != nil {
|
||||
_ = udpConn.Close()
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
qs, err = quic.Dial(udpConn, serverUDPAddr, c.serverAddr, c.tlsConfig, c.quicConfig)
|
||||
if err != nil {
|
||||
_ = udpConn.Close()
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@ import (
|
|||
)
|
||||
|
||||
type Obfuscator interface {
|
||||
Deobfuscate(buf []byte, n int) int
|
||||
Deobfuscate(in []byte, out []byte) int
|
||||
Obfuscate(p []byte) []byte
|
||||
}
|
||||
|
||||
|
@ -21,13 +21,21 @@ func (c *obfsUDPConn) SyscallConn() (syscall.RawConn, error) {
|
|||
return c.Orig.SyscallConn()
|
||||
}
|
||||
|
||||
func (c *obfsUDPConn) 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 *obfsUDPConn) ReadFrom(p []byte) (int, net.Addr, error) {
|
||||
buf := make([]byte, udpBufferSize)
|
||||
for {
|
||||
n, addr, err := c.Orig.ReadFrom(buf)
|
||||
if n <= 0 {
|
||||
return 0, addr, err
|
||||
}
|
||||
newN := c.Obfuscator.Deobfuscate(buf[:n], p)
|
||||
if newN > 0 {
|
||||
// Valid packet
|
||||
return newN, addr, err
|
||||
} else if err != nil {
|
||||
// Not valid and Orig.ReadFrom had some error
|
||||
return 0, addr, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@ import (
|
|||
"github.com/lunixbochs/struc"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"github.com/tobyxdd/hysteria/pkg/acl"
|
||||
"github.com/tobyxdd/hysteria/pkg/utils"
|
||||
"net"
|
||||
)
|
||||
|
||||
|
@ -47,6 +48,10 @@ func NewServer(addr string, tlsConfig *tls.Config, quicConfig *quic.Config,
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := utils.SetDontFragment(udpConn); err != nil {
|
||||
_ = udpConn.Close()
|
||||
return nil, err
|
||||
}
|
||||
var listener quic.Listener
|
||||
if obfuscator != nil {
|
||||
// Wrap PacketConn with obfuscator
|
||||
|
@ -55,11 +60,13 @@ func NewServer(addr string, tlsConfig *tls.Config, quicConfig *quic.Config,
|
|||
Obfuscator: obfuscator,
|
||||
}, tlsConfig, quicConfig)
|
||||
if err != nil {
|
||||
_ = udpConn.Close()
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
listener, err = quic.Listen(udpConn, tlsConfig, quicConfig)
|
||||
if err != nil {
|
||||
_ = udpConn.Close()
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,12 +2,12 @@ package obfs
|
|||
|
||||
type XORObfuscator []byte
|
||||
|
||||
func (x XORObfuscator) Deobfuscate(buf []byte, n int) int {
|
||||
func (x XORObfuscator) Deobfuscate(in []byte, out []byte) int {
|
||||
l := len(x)
|
||||
for i := range buf {
|
||||
buf[i] ^= x[i%l]
|
||||
for i := range in {
|
||||
out[i] = in[i] ^ x[i%l]
|
||||
}
|
||||
return n
|
||||
return len(in)
|
||||
}
|
||||
|
||||
func (x XORObfuscator) Obfuscate(p []byte) []byte {
|
||||
|
|
52
pkg/obfs/xplus.go
Normal file
52
pkg/obfs/xplus.go
Normal file
|
@ -0,0 +1,52 @@
|
|||
package obfs
|
||||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"math/rand"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
// [salt(16)][obfuscated payload]
|
||||
|
||||
type XPlusObfuscator struct {
|
||||
Key []byte
|
||||
RandSrc *rand.Rand
|
||||
|
||||
lk sync.Mutex
|
||||
}
|
||||
|
||||
func NewXPlusObfuscator(key []byte) *XPlusObfuscator {
|
||||
return &XPlusObfuscator{
|
||||
Key: key,
|
||||
RandSrc: rand.New(rand.NewSource(time.Now().UnixNano())),
|
||||
}
|
||||
}
|
||||
|
||||
func (x *XPlusObfuscator) Deobfuscate(in []byte, out []byte) int {
|
||||
pLen := len(in) - 16
|
||||
if pLen <= 0 || len(out) < pLen {
|
||||
// Invalid
|
||||
return 0
|
||||
}
|
||||
key := sha256.Sum256(append(x.Key, in[:16]...))
|
||||
// Deobfuscate the payload
|
||||
for i, c := range in[16:] {
|
||||
out[i] = c ^ key[i%sha256.Size]
|
||||
}
|
||||
return pLen
|
||||
}
|
||||
|
||||
func (x *XPlusObfuscator) Obfuscate(p []byte) []byte {
|
||||
pLen := len(p)
|
||||
buf := make([]byte, 16+pLen)
|
||||
x.lk.Lock()
|
||||
_, _ = x.RandSrc.Read(buf[:16]) // salt
|
||||
x.lk.Unlock()
|
||||
// Obfuscate the payload
|
||||
key := sha256.Sum256(append(x.Key, buf[:16]...))
|
||||
for i, c := range p {
|
||||
buf[i+16] = c ^ key[i%sha256.Size]
|
||||
}
|
||||
return buf
|
||||
}
|
31
pkg/obfs/xplus_test.go
Normal file
31
pkg/obfs/xplus_test.go
Normal file
|
@ -0,0 +1,31 @@
|
|||
package obfs
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestXPlusObfuscator(t *testing.T) {
|
||||
x := NewXPlusObfuscator([]byte("Vaundy"))
|
||||
tests := []struct {
|
||||
name string
|
||||
p []byte
|
||||
}{
|
||||
{name: "1", p: []byte("HelloWorld")},
|
||||
{name: "2", p: []byte("Regret is just a horrible attempt at time travel that ends with you feeling like crap")},
|
||||
{name: "3", p: []byte("To be, or not to be, that is the question:\nWhether 'tis nobler in the mind to suffer\n" +
|
||||
"The slings and arrows of outrageous fortune,\nOr to take arms against a sea of troubles\n" +
|
||||
"And by opposing end them. To die—to sleep,\nNo more; and by a sleep to say we end")},
|
||||
{name: "empty", p: []byte("")},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
bs := x.Obfuscate(tt.p)
|
||||
outBs := make([]byte, len(bs))
|
||||
n := x.Deobfuscate(bs, outBs)
|
||||
if !bytes.Equal(tt.p, outBs[:n]) {
|
||||
t.Errorf("Inconsistent deobfuscate result: got %v, want %v", outBs[:n], tt.p)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
21
pkg/utils/df_linux.go
Normal file
21
pkg/utils/df_linux.go
Normal file
|
@ -0,0 +1,21 @@
|
|||
package utils
|
||||
|
||||
import (
|
||||
"net"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
func SetDontFragment(conn *net.UDPConn) error {
|
||||
rawConn, err := conn.SyscallConn()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var err1, err2 error
|
||||
err1 = rawConn.Control(func(fd uintptr) {
|
||||
err2 = syscall.SetsockoptInt(int(fd), syscall.IPPROTO_IP, syscall.IP_MTU_DISCOVER, syscall.IP_PMTUDISC_PROBE)
|
||||
})
|
||||
if err1 != nil {
|
||||
return err1
|
||||
}
|
||||
return err2
|
||||
}
|
10
pkg/utils/df_stub.go
Normal file
10
pkg/utils/df_stub.go
Normal file
|
@ -0,0 +1,10 @@
|
|||
// +build !linux,!windows
|
||||
|
||||
package utils
|
||||
|
||||
import "net"
|
||||
|
||||
func SetDontFragment(conn *net.UDPConn) error {
|
||||
// Not implemented
|
||||
return nil
|
||||
}
|
23
pkg/utils/df_windows.go
Normal file
23
pkg/utils/df_windows.go
Normal file
|
@ -0,0 +1,23 @@
|
|||
package utils
|
||||
|
||||
import (
|
||||
"net"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
func SetDontFragment(conn *net.UDPConn) error {
|
||||
rawConn, err := conn.SyscallConn()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var err1, err2 error
|
||||
err1 = rawConn.Control(func(fd uintptr) {
|
||||
// https://docs.microsoft.com/en-us/troubleshoot/windows/win32/header-library-requirement-socket-ipproto-ip
|
||||
// #define IP_DONTFRAGMENT 14 /* don't fragment IP datagrams */
|
||||
err2 = syscall.SetsockoptInt(syscall.Handle(fd), syscall.IPPROTO_IP, 14, 1)
|
||||
})
|
||||
if err1 != nil {
|
||||
return err1
|
||||
}
|
||||
return err2
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue