merge ss and ssu
This commit is contained in:
@ -3,6 +3,7 @@ package main
|
|||||||
import (
|
import (
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/go-gost/gost/pkg/bypass"
|
"github.com/go-gost/gost/pkg/bypass"
|
||||||
"github.com/go-gost/gost/pkg/chain"
|
"github.com/go-gost/gost/pkg/chain"
|
||||||
@ -62,6 +63,11 @@ func buildService(cfg *config.Config) (services []*service.Service) {
|
|||||||
handler.BypassOption(bypasses[svc.Bypass]),
|
handler.BypassOption(bypasses[svc.Bypass]),
|
||||||
handler.LoggerOption(handlerLogger),
|
handler.LoggerOption(handlerLogger),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if forwarder, ok := h.(handler.Forwarder); ok {
|
||||||
|
forwarder.Forward(forwarderFromConfig(svc.Forwarder))
|
||||||
|
}
|
||||||
|
|
||||||
if err := h.Init(metadata.MapMetadata(svc.Handler.Metadata)); err != nil {
|
if err := h.Init(metadata.MapMetadata(svc.Handler.Metadata)); err != nil {
|
||||||
handlerLogger.Fatal("init: ", err)
|
handlerLogger.Fatal("init: ", err)
|
||||||
}
|
}
|
||||||
@ -85,7 +91,7 @@ func chainFromConfig(cfg *config.ChainConfig) *chain.Chain {
|
|||||||
|
|
||||||
c := &chain.Chain{}
|
c := &chain.Chain{}
|
||||||
|
|
||||||
selector := selectorFromConfig(cfg.LB)
|
selector := selectorFromConfig(cfg.Selector)
|
||||||
for _, hop := range cfg.Hops {
|
for _, hop := range cfg.Hops {
|
||||||
group := &chain.NodeGroup{}
|
group := &chain.NodeGroup{}
|
||||||
for _, v := range hop.Nodes {
|
for _, v := range hop.Nodes {
|
||||||
@ -127,7 +133,7 @@ func chainFromConfig(cfg *config.ChainConfig) *chain.Chain {
|
|||||||
}
|
}
|
||||||
|
|
||||||
sel := selector
|
sel := selector
|
||||||
if s := selectorFromConfig(hop.LB); s != nil {
|
if s := selectorFromConfig(hop.Selector); s != nil {
|
||||||
sel = s
|
sel = s
|
||||||
}
|
}
|
||||||
group.WithSelector(sel)
|
group.WithSelector(sel)
|
||||||
@ -162,7 +168,7 @@ func logFromConfig(cfg *config.LogConfig) logger.Logger {
|
|||||||
return logger.NewLogger(opts...)
|
return logger.NewLogger(opts...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func selectorFromConfig(cfg *config.LoadbalancingConfig) chain.Selector {
|
func selectorFromConfig(cfg *config.SelectorConfig) chain.Selector {
|
||||||
if cfg == nil {
|
if cfg == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -173,7 +179,7 @@ func selectorFromConfig(cfg *config.LoadbalancingConfig) chain.Selector {
|
|||||||
strategy = chain.RoundRobinStrategy()
|
strategy = chain.RoundRobinStrategy()
|
||||||
case "random":
|
case "random":
|
||||||
strategy = chain.RandomStrategy()
|
strategy = chain.RandomStrategy()
|
||||||
case "fifio":
|
case "fifo":
|
||||||
strategy = chain.FIFOStrategy()
|
strategy = chain.FIFOStrategy()
|
||||||
default:
|
default:
|
||||||
strategy = chain.RoundRobinStrategy()
|
strategy = chain.RoundRobinStrategy()
|
||||||
@ -190,6 +196,19 @@ func bypassFromConfig(cfg *config.BypassConfig) bypass.Bypass {
|
|||||||
if cfg == nil {
|
if cfg == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return bypass.NewBypassPatterns(cfg.Reverse, cfg.Matchers...)
|
return bypass.NewBypassPatterns(cfg.Reverse, cfg.Matchers...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func forwarderFromConfig(cfg *config.ForwarderConfig) *chain.NodeGroup {
|
||||||
|
if cfg == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
group := &chain.NodeGroup{}
|
||||||
|
for _, target := range cfg.Targets {
|
||||||
|
if v := strings.TrimSpace(target); v != "" {
|
||||||
|
group.AddNode(chain.NewNode(target, target))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return group.WithSelector(selectorFromConfig(cfg.Selector))
|
||||||
|
}
|
||||||
|
@ -10,7 +10,7 @@ profiling:
|
|||||||
services:
|
services:
|
||||||
- name: http+tcp
|
- name: http+tcp
|
||||||
url: "http://gost:gost@:8000"
|
url: "http://gost:gost@:8000"
|
||||||
addr: ":8000"
|
addr: ":28000"
|
||||||
handler:
|
handler:
|
||||||
type: http
|
type: http
|
||||||
metadata:
|
metadata:
|
||||||
@ -27,38 +27,27 @@ services:
|
|||||||
keepAlive: 15s
|
keepAlive: 15s
|
||||||
chain: chain01
|
chain: chain01
|
||||||
# bypass: bypass01
|
# bypass: bypass01
|
||||||
- name: ss+tcp
|
- name: ss
|
||||||
url: "ss://chacha20:gost@:8000"
|
url: "ss://chacha20:gost@:8000"
|
||||||
addr: ":8338"
|
addr: ":28338"
|
||||||
handler:
|
handler:
|
||||||
type: ss
|
type: ss
|
||||||
metadata:
|
metadata:
|
||||||
method: AES-256-GCM
|
method: chacha20-ietf
|
||||||
password: gost
|
password: gost
|
||||||
readTimeout: 5s
|
readTimeout: 5s
|
||||||
retry: 3
|
retry: 3
|
||||||
|
udp: true
|
||||||
|
bufferSize: 4096
|
||||||
listener:
|
listener:
|
||||||
type: tcp
|
type: tcp
|
||||||
metadata:
|
metadata:
|
||||||
keepAlive: 15s
|
keepAlive: 15s
|
||||||
chain: chain01
|
# chain: chain01
|
||||||
# bypass: bypass01
|
# bypass: bypass01
|
||||||
- name: ssu
|
- name: socks5
|
||||||
url: "ss://chacha20:gost@:8000"
|
|
||||||
addr: ":8388"
|
|
||||||
handler:
|
|
||||||
type: ssu
|
|
||||||
metadata:
|
|
||||||
# method: AES-256-GCM
|
|
||||||
# password: gost
|
|
||||||
readTimeout: 5s
|
|
||||||
retry: 3
|
|
||||||
listener:
|
|
||||||
type: tcp
|
|
||||||
# chain: chain-ssu
|
|
||||||
- name: socks5+tcp
|
|
||||||
url: "socks5://gost:gost@:1080"
|
url: "socks5://gost:gost@:1080"
|
||||||
addr: ":1080"
|
addr: ":21080"
|
||||||
handler:
|
handler:
|
||||||
type: socks5
|
type: socks5
|
||||||
metadata:
|
metadata:
|
||||||
@ -72,11 +61,11 @@ services:
|
|||||||
type: tcp
|
type: tcp
|
||||||
metadata:
|
metadata:
|
||||||
keepAlive: 15s
|
keepAlive: 15s
|
||||||
chain: chain-socks5
|
chain: chain-ss
|
||||||
# bypass: bypass01
|
# bypass: bypass01
|
||||||
- name: socks5+tcp
|
- name: socks5+tcp
|
||||||
url: "socks5://gost:gost@:1080"
|
url: "socks5://gost:gost@:1080"
|
||||||
addr: ":11080"
|
addr: ":21081"
|
||||||
handler:
|
handler:
|
||||||
type: socks5
|
type: socks5
|
||||||
metadata:
|
metadata:
|
||||||
@ -90,18 +79,40 @@ services:
|
|||||||
type: tcp
|
type: tcp
|
||||||
metadata:
|
metadata:
|
||||||
keepAlive: 15s
|
keepAlive: 15s
|
||||||
|
- name: forward
|
||||||
|
url: "socks5://gost:gost@:1080"
|
||||||
|
addr: ":10053"
|
||||||
|
forwarder:
|
||||||
|
targets:
|
||||||
|
- 192.168.8.8:53
|
||||||
|
- 192.168.8.1:53
|
||||||
|
- 1.1.1.1:53
|
||||||
|
selector:
|
||||||
|
strategy: fifo
|
||||||
|
maxFails: 1
|
||||||
|
failTimeout: 30s
|
||||||
|
handler:
|
||||||
|
type: forward
|
||||||
|
metadata:
|
||||||
|
readTimeout: 5s
|
||||||
|
retry: 3
|
||||||
|
listener:
|
||||||
|
type: udp
|
||||||
|
metadata:
|
||||||
|
keepAlive: 15s
|
||||||
|
chain: chain-ss
|
||||||
|
|
||||||
chains:
|
chains:
|
||||||
- name: chain01
|
- name: chain01
|
||||||
# chain level load balancing
|
# chain level selector
|
||||||
lb:
|
selector:
|
||||||
strategy: round
|
strategy: round
|
||||||
maxFails: 1
|
maxFails: 1
|
||||||
failTimeout: 30s
|
failTimeout: 30s
|
||||||
hops:
|
hops:
|
||||||
- name: hop01
|
- name: hop01
|
||||||
# hop level load balancing
|
# hop level selector
|
||||||
lb:
|
selector:
|
||||||
strategy: round
|
strategy: round
|
||||||
maxFails: 1
|
maxFails: 1
|
||||||
failTimeout: 30s
|
failTimeout: 30s
|
||||||
@ -131,8 +142,8 @@ chains:
|
|||||||
type: tcp
|
type: tcp
|
||||||
metadata: {}
|
metadata: {}
|
||||||
- name: hop02
|
- name: hop02
|
||||||
# hop level load balancing
|
# hop level selector
|
||||||
lb:
|
selector:
|
||||||
strategy: round
|
strategy: round
|
||||||
maxFails: 1
|
maxFails: 1
|
||||||
failTimeout: 30s
|
failTimeout: 30s
|
||||||
@ -179,19 +190,25 @@ chains:
|
|||||||
dialer:
|
dialer:
|
||||||
type: tcp
|
type: tcp
|
||||||
metadata: {}
|
metadata: {}
|
||||||
- name: chain-ssu
|
- name: chain-ss
|
||||||
hops:
|
hops:
|
||||||
- name: hop01
|
- name: hop01
|
||||||
nodes:
|
nodes:
|
||||||
- name: node01
|
- name: node01
|
||||||
addr: ":8339"
|
addr: ":28338"
|
||||||
url: "http://gost:gost@:8081"
|
url: "http://gost:gost@:8081"
|
||||||
# bypass: bypass01
|
# bypass: bypass01
|
||||||
connector:
|
connector:
|
||||||
type: ssu
|
type: ss
|
||||||
metadata: {}
|
metadata:
|
||||||
|
method: chacha20-ietf
|
||||||
|
password: gost
|
||||||
|
readTimeout: 5s
|
||||||
|
nodelay: true
|
||||||
|
udp: true
|
||||||
|
bufferSize: 4096
|
||||||
dialer:
|
dialer:
|
||||||
type: udp
|
type: tcp
|
||||||
metadata: {}
|
metadata: {}
|
||||||
|
|
||||||
bypasses:
|
bypasses:
|
||||||
|
@ -6,18 +6,17 @@ import (
|
|||||||
_ "github.com/go-gost/gost/pkg/connector/socks/v4"
|
_ "github.com/go-gost/gost/pkg/connector/socks/v4"
|
||||||
_ "github.com/go-gost/gost/pkg/connector/socks/v5"
|
_ "github.com/go-gost/gost/pkg/connector/socks/v5"
|
||||||
_ "github.com/go-gost/gost/pkg/connector/ss"
|
_ "github.com/go-gost/gost/pkg/connector/ss"
|
||||||
_ "github.com/go-gost/gost/pkg/connector/ssu"
|
|
||||||
|
|
||||||
// Register dialers
|
// Register dialers
|
||||||
_ "github.com/go-gost/gost/pkg/dialer/tcp"
|
_ "github.com/go-gost/gost/pkg/dialer/tcp"
|
||||||
_ "github.com/go-gost/gost/pkg/dialer/udp"
|
_ "github.com/go-gost/gost/pkg/dialer/udp"
|
||||||
|
|
||||||
// Register handlers
|
// Register handlers
|
||||||
|
_ "github.com/go-gost/gost/pkg/handler/forward/local"
|
||||||
_ "github.com/go-gost/gost/pkg/handler/http"
|
_ "github.com/go-gost/gost/pkg/handler/http"
|
||||||
_ "github.com/go-gost/gost/pkg/handler/socks/v4"
|
_ "github.com/go-gost/gost/pkg/handler/socks/v4"
|
||||||
_ "github.com/go-gost/gost/pkg/handler/socks/v5"
|
_ "github.com/go-gost/gost/pkg/handler/socks/v5"
|
||||||
_ "github.com/go-gost/gost/pkg/handler/ss"
|
_ "github.com/go-gost/gost/pkg/handler/ss"
|
||||||
_ "github.com/go-gost/gost/pkg/handler/ssu"
|
|
||||||
|
|
||||||
// Register listeners
|
// Register listeners
|
||||||
_ "github.com/go-gost/gost/pkg/listener/ftcp"
|
_ "github.com/go-gost/gost/pkg/listener/ftcp"
|
||||||
|
@ -12,14 +12,14 @@ type Node struct {
|
|||||||
addr string
|
addr string
|
||||||
transport *Transport
|
transport *Transport
|
||||||
bypass bypass.Bypass
|
bypass bypass.Bypass
|
||||||
marker *failMarker
|
marker *FailMarker
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewNode(name, addr string) *Node {
|
func NewNode(name, addr string) *Node {
|
||||||
return &Node{
|
return &Node{
|
||||||
name: name,
|
name: name,
|
||||||
addr: addr,
|
addr: addr,
|
||||||
marker: &failMarker{},
|
marker: &FailMarker{},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -31,6 +31,10 @@ func (node *Node) Addr() string {
|
|||||||
return node.addr
|
return node.addr
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (node *Node) Marker() *FailMarker {
|
||||||
|
return node.marker
|
||||||
|
}
|
||||||
|
|
||||||
func (node *Node) WithTransport(tr *Transport) *Node {
|
func (node *Node) WithTransport(tr *Transport) *Node {
|
||||||
node.transport = tr
|
node.transport = tr
|
||||||
return node
|
return node
|
||||||
@ -80,13 +84,13 @@ func (g *NodeGroup) Next() *Node {
|
|||||||
return selector.Select(g.nodes...)
|
return selector.Select(g.nodes...)
|
||||||
}
|
}
|
||||||
|
|
||||||
type failMarker struct {
|
type FailMarker struct {
|
||||||
failTime int64
|
failTime int64
|
||||||
failCount uint32
|
failCount uint32
|
||||||
mux sync.RWMutex
|
mux sync.RWMutex
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *failMarker) FailTime() int64 {
|
func (m *FailMarker) FailTime() int64 {
|
||||||
if m == nil {
|
if m == nil {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
@ -97,7 +101,7 @@ func (m *failMarker) FailTime() int64 {
|
|||||||
return m.failTime
|
return m.failTime
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *failMarker) FailCount() uint32 {
|
func (m *FailMarker) FailCount() uint32 {
|
||||||
if m == nil {
|
if m == nil {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
@ -108,7 +112,7 @@ func (m *failMarker) FailCount() uint32 {
|
|||||||
return m.failCount
|
return m.failCount
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *failMarker) Mark() {
|
func (m *FailMarker) Mark() {
|
||||||
if m == nil {
|
if m == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -120,7 +124,7 @@ func (m *failMarker) Mark() {
|
|||||||
m.failCount++
|
m.failCount++
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *failMarker) Reset() {
|
func (m *FailMarker) Reset() {
|
||||||
if m == nil {
|
if m == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -26,33 +26,33 @@ func (r *Route) Connect(ctx context.Context) (conn net.Conn, err error) {
|
|||||||
node := r.nodes[0]
|
node := r.nodes[0]
|
||||||
cc, err := node.transport.Dial(ctx, r.nodes[0].Addr())
|
cc, err := node.transport.Dial(ctx, r.nodes[0].Addr())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
node.marker.Mark()
|
node.Marker().Mark()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
cn, err := node.transport.Handshake(ctx, cc)
|
cn, err := node.transport.Handshake(ctx, cc)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
cc.Close()
|
cc.Close()
|
||||||
node.marker.Mark()
|
node.Marker().Mark()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
node.marker.Reset()
|
node.Marker().Reset()
|
||||||
|
|
||||||
preNode := node
|
preNode := node
|
||||||
for _, node := range r.nodes[1:] {
|
for _, node := range r.nodes[1:] {
|
||||||
cc, err = preNode.transport.Connect(ctx, cn, "tcp", node.Addr())
|
cc, err = preNode.transport.Connect(ctx, cn, "tcp", node.Addr())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
cn.Close()
|
cn.Close()
|
||||||
node.marker.Mark()
|
node.Marker().Mark()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
cc, err = node.transport.Handshake(ctx, cc)
|
cc, err = node.transport.Handshake(ctx, cc)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
cn.Close()
|
cn.Close()
|
||||||
node.marker.Mark()
|
node.Marker().Mark()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
node.marker.Reset()
|
node.Marker().Reset()
|
||||||
|
|
||||||
cn = cc
|
cn = cc
|
||||||
preNode = node
|
preNode = node
|
||||||
@ -89,7 +89,7 @@ func (r *Route) dialDirect(ctx context.Context, network, address string) (net.Co
|
|||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
|
|
||||||
d := &net.Dialer{}
|
d := net.Dialer{}
|
||||||
return d.DialContext(ctx, network, address)
|
return d.DialContext(ctx, network, address)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -15,10 +15,6 @@ const (
|
|||||||
DefaultFailTimeout = 30 * time.Second
|
DefaultFailTimeout = 30 * time.Second
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
|
||||||
defaultSelector Selector = NewSelector(nil)
|
|
||||||
)
|
|
||||||
|
|
||||||
type Selector interface {
|
type Selector interface {
|
||||||
Select(nodes ...*Node) *Node
|
Select(nodes ...*Node) *Node
|
||||||
}
|
}
|
||||||
@ -145,8 +141,8 @@ func (f *failFilter) Filter(nodes ...*Node) []*Node {
|
|||||||
}
|
}
|
||||||
var nl []*Node
|
var nl []*Node
|
||||||
for _, node := range nodes {
|
for _, node := range nodes {
|
||||||
if node.marker.FailCount() < uint32(maxFails) ||
|
if node.Marker().FailCount() < uint32(maxFails) ||
|
||||||
time.Since(time.Unix(node.marker.FailTime(), 0)) >= failTimeout {
|
time.Since(time.Unix(node.Marker().FailTime(), 0)) >= failTimeout {
|
||||||
nl = append(nl, node)
|
nl = append(nl, node)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -29,7 +29,7 @@ type ProfilingConfig struct {
|
|||||||
Enabled bool
|
Enabled bool
|
||||||
}
|
}
|
||||||
|
|
||||||
type LoadbalancingConfig struct {
|
type SelectorConfig struct {
|
||||||
Strategy string
|
Strategy string
|
||||||
MaxFails int
|
MaxFails int
|
||||||
FailTimeout time.Duration
|
FailTimeout time.Duration
|
||||||
@ -50,6 +50,11 @@ type HandlerConfig struct {
|
|||||||
Metadata map[string]interface{}
|
Metadata map[string]interface{}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ForwarderConfig struct {
|
||||||
|
Targets []string
|
||||||
|
Selector *SelectorConfig
|
||||||
|
}
|
||||||
|
|
||||||
type DialerConfig struct {
|
type DialerConfig struct {
|
||||||
Type string
|
Type string
|
||||||
Metadata map[string]interface{}
|
Metadata map[string]interface{}
|
||||||
@ -61,25 +66,26 @@ type ConnectorConfig struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type ServiceConfig struct {
|
type ServiceConfig struct {
|
||||||
Name string
|
Name string
|
||||||
URL string
|
URL string
|
||||||
Addr string
|
Addr string
|
||||||
Listener *ListenerConfig
|
Listener *ListenerConfig
|
||||||
Handler *HandlerConfig
|
Handler *HandlerConfig
|
||||||
Chain string
|
Forwarder *ForwarderConfig
|
||||||
Bypass string
|
Chain string
|
||||||
|
Bypass string
|
||||||
}
|
}
|
||||||
|
|
||||||
type ChainConfig struct {
|
type ChainConfig struct {
|
||||||
Name string
|
Name string
|
||||||
LB *LoadbalancingConfig
|
Selector *SelectorConfig
|
||||||
Hops []HopConfig
|
Hops []HopConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
type HopConfig struct {
|
type HopConfig struct {
|
||||||
Name string
|
Name string
|
||||||
LB *LoadbalancingConfig
|
Selector *SelectorConfig
|
||||||
Nodes []NodeConfig
|
Nodes []NodeConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
type NodeConfig struct {
|
type NodeConfig struct {
|
||||||
|
@ -49,6 +49,7 @@ func (c *httpConnector) Connect(ctx context.Context, conn net.Conn, network, add
|
|||||||
"network": network,
|
"network": network,
|
||||||
"address": address,
|
"address": address,
|
||||||
})
|
})
|
||||||
|
c.logger.Infof("connect: %s/%s", address, network)
|
||||||
|
|
||||||
switch network {
|
switch network {
|
||||||
case "tcp", "tcp4", "tcp6":
|
case "tcp", "tcp4", "tcp6":
|
||||||
@ -71,8 +72,6 @@ func (c *httpConnector) Connect(ctx context.Context, conn net.Conn, network, add
|
|||||||
}
|
}
|
||||||
req.Header.Set("Proxy-Connection", "keep-alive")
|
req.Header.Set("Proxy-Connection", "keep-alive")
|
||||||
|
|
||||||
c.logger.Infof("connect: ", address)
|
|
||||||
|
|
||||||
if user := c.md.User; user != nil {
|
if user := c.md.User; user != nil {
|
||||||
u := user.Username()
|
u := user.Username()
|
||||||
p, _ := user.Password()
|
p, _ := user.Password()
|
||||||
|
@ -2,6 +2,7 @@ package v4
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
"net/url"
|
"net/url"
|
||||||
@ -47,6 +48,7 @@ func (c *socks4Connector) Connect(ctx context.Context, conn net.Conn, network, a
|
|||||||
"network": network,
|
"network": network,
|
||||||
"address": address,
|
"address": address,
|
||||||
})
|
})
|
||||||
|
c.logger.Infof("connect: %s/%s", address, network)
|
||||||
|
|
||||||
switch network {
|
switch network {
|
||||||
case "tcp", "tcp4", "tcp6":
|
case "tcp", "tcp4", "tcp6":
|
||||||
@ -56,8 +58,6 @@ func (c *socks4Connector) Connect(ctx context.Context, conn net.Conn, network, a
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
c.logger.Info("connect: ", address)
|
|
||||||
|
|
||||||
var addr *gosocks4.Addr
|
var addr *gosocks4.Addr
|
||||||
|
|
||||||
if c.md.disable4a {
|
if c.md.disable4a {
|
||||||
@ -107,7 +107,9 @@ func (c *socks4Connector) Connect(ctx context.Context, conn net.Conn, network, a
|
|||||||
c.logger.Debug(reply)
|
c.logger.Debug(reply)
|
||||||
|
|
||||||
if reply.Code != gosocks4.Granted {
|
if reply.Code != gosocks4.Granted {
|
||||||
return nil, fmt.Errorf("error: %d", reply.Code)
|
err = errors.New("host unreachable")
|
||||||
|
c.logger.Error(err)
|
||||||
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return conn, nil
|
return conn, nil
|
||||||
|
@ -67,6 +67,7 @@ func (c *socks5Connector) Init(md md.Metadata) (err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Handshake implements connector.Handshaker.
|
||||||
func (c *socks5Connector) Handshake(ctx context.Context, conn net.Conn) (net.Conn, error) {
|
func (c *socks5Connector) Handshake(ctx context.Context, conn net.Conn) (net.Conn, error) {
|
||||||
c.logger = c.logger.WithFields(map[string]interface{}{
|
c.logger = c.logger.WithFields(map[string]interface{}{
|
||||||
"remote": conn.RemoteAddr().String(),
|
"remote": conn.RemoteAddr().String(),
|
||||||
@ -92,17 +93,18 @@ func (c *socks5Connector) Connect(ctx context.Context, conn net.Conn, network, a
|
|||||||
"network": network,
|
"network": network,
|
||||||
"address": address,
|
"address": address,
|
||||||
})
|
})
|
||||||
|
c.logger.Infof("connect: %s/%s", address, network)
|
||||||
|
|
||||||
switch network {
|
switch network {
|
||||||
|
case "udp", "udp4", "udp6":
|
||||||
|
return c.connectUDP(ctx, conn, network, address)
|
||||||
case "tcp", "tcp4", "tcp6":
|
case "tcp", "tcp4", "tcp6":
|
||||||
default:
|
default:
|
||||||
err := fmt.Errorf("network %s unsupported, should be tcp, tcp4 or tcp6", network)
|
err := fmt.Errorf("network %s unsupported", network)
|
||||||
c.logger.Error(err)
|
c.logger.Error(err)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
c.logger.Info("connect: ", address)
|
|
||||||
|
|
||||||
addr := gosocks5.Addr{}
|
addr := gosocks5.Addr{}
|
||||||
if err := addr.ParseFrom(address); err != nil {
|
if err := addr.ParseFrom(address); err != nil {
|
||||||
c.logger.Error(err)
|
c.logger.Error(err)
|
||||||
@ -129,12 +131,48 @@ func (c *socks5Connector) Connect(ctx context.Context, conn net.Conn, network, a
|
|||||||
c.logger.Debug(reply)
|
c.logger.Debug(reply)
|
||||||
|
|
||||||
if reply.Rep != gosocks5.Succeeded {
|
if reply.Rep != gosocks5.Succeeded {
|
||||||
return nil, errors.New("service unavailable")
|
err = errors.New("host unreachable")
|
||||||
|
c.logger.Error(err)
|
||||||
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return conn, nil
|
return conn, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *socks5Connector) connectUDP(ctx context.Context, conn net.Conn, network, address string) (net.Conn, error) {
|
||||||
|
addr, err := net.ResolveUDPAddr(network, address)
|
||||||
|
if err != nil {
|
||||||
|
c.logger.Error(err)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
req := gosocks5.NewRequest(socks.CmdUDPTun, nil)
|
||||||
|
if err := req.Write(conn); err != nil {
|
||||||
|
c.logger.Error(err)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
c.logger.Debug(req)
|
||||||
|
|
||||||
|
reply, err := gosocks5.ReadReply(conn)
|
||||||
|
if err != nil {
|
||||||
|
c.logger.Error(err)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
c.logger.Debug(reply)
|
||||||
|
|
||||||
|
if reply.Rep != gosocks5.Succeeded {
|
||||||
|
return nil, errors.New("get socks5 UDP tunnel failure")
|
||||||
|
}
|
||||||
|
|
||||||
|
baddr, err := net.ResolveUDPAddr("udp", reply.Addr.String())
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
c.logger.Debugf("associate on %s OK", baddr)
|
||||||
|
|
||||||
|
return socks.UDPTunClientConn(conn, addr), nil
|
||||||
|
}
|
||||||
|
|
||||||
func (c *socks5Connector) parseMetadata(md md.Metadata) (err error) {
|
func (c *socks5Connector) parseMetadata(md md.Metadata) (err error) {
|
||||||
if v := md.GetString(auth); v != "" {
|
if v := md.GetString(auth); v != "" {
|
||||||
ss := strings.SplitN(v, ":", 2)
|
ss := strings.SplitN(v, ":", 2)
|
||||||
|
@ -2,6 +2,7 @@ package ss
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
"time"
|
"time"
|
||||||
@ -9,6 +10,7 @@ import (
|
|||||||
"github.com/go-gost/gosocks5"
|
"github.com/go-gost/gosocks5"
|
||||||
"github.com/go-gost/gost/pkg/connector"
|
"github.com/go-gost/gost/pkg/connector"
|
||||||
"github.com/go-gost/gost/pkg/internal/bufpool"
|
"github.com/go-gost/gost/pkg/internal/bufpool"
|
||||||
|
"github.com/go-gost/gost/pkg/internal/utils/socks"
|
||||||
"github.com/go-gost/gost/pkg/internal/utils/ss"
|
"github.com/go-gost/gost/pkg/internal/utils/ss"
|
||||||
"github.com/go-gost/gost/pkg/logger"
|
"github.com/go-gost/gost/pkg/logger"
|
||||||
md "github.com/go-gost/gost/pkg/metadata"
|
md "github.com/go-gost/gost/pkg/metadata"
|
||||||
@ -46,15 +48,23 @@ func (c *ssConnector) Connect(ctx context.Context, conn net.Conn, network, addre
|
|||||||
"network": network,
|
"network": network,
|
||||||
"address": address,
|
"address": address,
|
||||||
})
|
})
|
||||||
|
c.logger.Infof("connect: %s/%s", address, network)
|
||||||
|
|
||||||
switch network {
|
switch network {
|
||||||
case "tcp", "tcp4", "tcp6":
|
case "tcp", "tcp4", "tcp6":
|
||||||
|
case "udp", "udp4", "udp6":
|
||||||
|
if c.md.enableUDP {
|
||||||
|
return c.connectUDP(ctx, conn, network, address)
|
||||||
|
} else {
|
||||||
|
err := errors.New("UDP relay is disabled")
|
||||||
|
c.logger.Error(err)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
err := fmt.Errorf("network %s unsupported, should be tcp, tcp4 or tcp6", network)
|
err := fmt.Errorf("network %s unsupported", network)
|
||||||
c.logger.Error(err)
|
c.logger.Error(err)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
c.logger.Infof("connect: ", address)
|
|
||||||
|
|
||||||
addr := gosocks5.Addr{}
|
addr := gosocks5.Addr{}
|
||||||
if err := addr.ParseFrom(address); err != nil {
|
if err := addr.ParseFrom(address); err != nil {
|
||||||
@ -94,18 +104,28 @@ func (c *ssConnector) Connect(ctx context.Context, conn net.Conn, network, addre
|
|||||||
return sc, nil
|
return sc, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *ssConnector) parseMetadata(md md.Metadata) (err error) {
|
func (c *ssConnector) connectUDP(ctx context.Context, conn net.Conn, network, address string) (net.Conn, error) {
|
||||||
c.md.cipher, err = ss.ShadowCipher(
|
if c.md.connectTimeout > 0 {
|
||||||
md.GetString(method),
|
conn.SetDeadline(time.Now().Add(c.md.connectTimeout))
|
||||||
md.GetString(password),
|
defer conn.SetDeadline(time.Time{})
|
||||||
md.GetString(key),
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
c.md.connectTimeout = md.GetDuration(connectTimeout)
|
taddr, _ := net.ResolveUDPAddr(network, address)
|
||||||
c.md.noDelay = md.GetBool(noDelay)
|
if taddr == nil {
|
||||||
|
taddr = &net.UDPAddr{}
|
||||||
|
}
|
||||||
|
|
||||||
return
|
pc, ok := conn.(net.PacketConn)
|
||||||
|
if ok {
|
||||||
|
if c.md.cipher != nil {
|
||||||
|
pc = c.md.cipher.PacketConn(pc)
|
||||||
|
}
|
||||||
|
|
||||||
|
return ss.UDPClientConn(pc, conn.RemoteAddr(), taddr, c.md.udpBufferSize), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.md.cipher != nil {
|
||||||
|
conn = ss.ShadowConn(c.md.cipher.StreamConn(conn), nil)
|
||||||
|
}
|
||||||
|
return socks.UDPTunClientConn(conn, taddr), nil
|
||||||
}
|
}
|
||||||
|
@ -3,19 +3,53 @@ package ss
|
|||||||
import (
|
import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/go-gost/gost/pkg/internal/utils/ss"
|
||||||
|
md "github.com/go-gost/gost/pkg/metadata"
|
||||||
"github.com/shadowsocks/go-shadowsocks2/core"
|
"github.com/shadowsocks/go-shadowsocks2/core"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
|
||||||
method = "method"
|
|
||||||
password = "password"
|
|
||||||
key = "key"
|
|
||||||
connectTimeout = "timeout"
|
|
||||||
noDelay = "noDelay"
|
|
||||||
)
|
|
||||||
|
|
||||||
type metadata struct {
|
type metadata struct {
|
||||||
cipher core.Cipher
|
cipher core.Cipher
|
||||||
connectTimeout time.Duration
|
connectTimeout time.Duration
|
||||||
noDelay bool
|
noDelay bool
|
||||||
|
enableUDP bool
|
||||||
|
udpBufferSize int
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ssConnector) parseMetadata(md md.Metadata) (err error) {
|
||||||
|
const (
|
||||||
|
method = "method"
|
||||||
|
password = "password"
|
||||||
|
key = "key"
|
||||||
|
connectTimeout = "timeout"
|
||||||
|
noDelay = "noDelay"
|
||||||
|
enableUDP = "udp" // enable UDP relay
|
||||||
|
udpBufferSize = "udpBufferSize" // udp buffer size
|
||||||
|
)
|
||||||
|
|
||||||
|
c.md.cipher, err = ss.ShadowCipher(
|
||||||
|
md.GetString(method),
|
||||||
|
md.GetString(password),
|
||||||
|
md.GetString(key),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c.md.connectTimeout = md.GetDuration(connectTimeout)
|
||||||
|
c.md.noDelay = md.GetBool(noDelay)
|
||||||
|
c.md.enableUDP = md.GetBool(enableUDP)
|
||||||
|
|
||||||
|
if c.md.udpBufferSize > 0 {
|
||||||
|
if c.md.udpBufferSize < 512 {
|
||||||
|
c.md.udpBufferSize = 512
|
||||||
|
}
|
||||||
|
if c.md.udpBufferSize > 65*1024 {
|
||||||
|
c.md.udpBufferSize = 65 * 1024
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
c.md.udpBufferSize = 4096
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
@ -1,105 +0,0 @@
|
|||||||
package ssu
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"fmt"
|
|
||||||
"net"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/go-gost/gost/pkg/connector"
|
|
||||||
"github.com/go-gost/gost/pkg/internal/utils/socks"
|
|
||||||
"github.com/go-gost/gost/pkg/internal/utils/ss"
|
|
||||||
"github.com/go-gost/gost/pkg/logger"
|
|
||||||
md "github.com/go-gost/gost/pkg/metadata"
|
|
||||||
"github.com/go-gost/gost/pkg/registry"
|
|
||||||
)
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
registry.RegiserConnector("ssu", NewConnector)
|
|
||||||
}
|
|
||||||
|
|
||||||
type ssuConnector struct {
|
|
||||||
md metadata
|
|
||||||
logger logger.Logger
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewConnector(opts ...connector.Option) connector.Connector {
|
|
||||||
options := &connector.Options{}
|
|
||||||
for _, opt := range opts {
|
|
||||||
opt(options)
|
|
||||||
}
|
|
||||||
|
|
||||||
return &ssuConnector{
|
|
||||||
logger: options.Logger,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *ssuConnector) Init(md md.Metadata) (err error) {
|
|
||||||
return c.parseMetadata(md)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *ssuConnector) Connect(ctx context.Context, conn net.Conn, network, address string, opts ...connector.ConnectOption) (net.Conn, error) {
|
|
||||||
c.logger = c.logger.WithFields(map[string]interface{}{
|
|
||||||
"remote": conn.RemoteAddr().String(),
|
|
||||||
"local": conn.LocalAddr().String(),
|
|
||||||
"network": network,
|
|
||||||
"address": address,
|
|
||||||
})
|
|
||||||
|
|
||||||
switch network {
|
|
||||||
case "udp", "udp4", "udp6":
|
|
||||||
default:
|
|
||||||
err := fmt.Errorf("network %s unsupported, should be udp, udp4 or udp6", network)
|
|
||||||
c.logger.Error(err)
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
c.logger.Info("connect: ", address)
|
|
||||||
|
|
||||||
if c.md.connectTimeout > 0 {
|
|
||||||
conn.SetDeadline(time.Now().Add(c.md.connectTimeout))
|
|
||||||
defer conn.SetDeadline(time.Time{})
|
|
||||||
}
|
|
||||||
|
|
||||||
taddr, _ := net.ResolveUDPAddr(network, address)
|
|
||||||
if taddr == nil {
|
|
||||||
taddr = &net.UDPAddr{}
|
|
||||||
}
|
|
||||||
|
|
||||||
pc, ok := conn.(net.PacketConn)
|
|
||||||
if ok {
|
|
||||||
if c.md.cipher != nil {
|
|
||||||
pc = c.md.cipher.PacketConn(pc)
|
|
||||||
}
|
|
||||||
|
|
||||||
return ss.UDPClientConn(pc, conn.RemoteAddr(), taddr, c.md.bufferSize), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return socks.UDPTunClientConn(conn, taddr), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *ssuConnector) parseMetadata(md md.Metadata) (err error) {
|
|
||||||
c.md.cipher, err = ss.ShadowCipher(
|
|
||||||
md.GetString(method),
|
|
||||||
md.GetString(password),
|
|
||||||
md.GetString(key),
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
c.md.connectTimeout = md.GetDuration(connectTimeout)
|
|
||||||
c.md.bufferSize = md.GetInt(bufferSize)
|
|
||||||
if c.md.bufferSize > 0 {
|
|
||||||
if c.md.bufferSize < 512 {
|
|
||||||
c.md.bufferSize = 512
|
|
||||||
}
|
|
||||||
if c.md.bufferSize > 65*1024 {
|
|
||||||
c.md.bufferSize = 65 * 1024
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
c.md.bufferSize = 4096
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
@ -1,21 +0,0 @@
|
|||||||
package ssu
|
|
||||||
|
|
||||||
import (
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/shadowsocks/go-shadowsocks2/core"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
method = "method"
|
|
||||||
password = "password"
|
|
||||||
key = "key"
|
|
||||||
connectTimeout = "timeout"
|
|
||||||
bufferSize = "bufferSize"
|
|
||||||
)
|
|
||||||
|
|
||||||
type metadata struct {
|
|
||||||
cipher core.Cipher
|
|
||||||
connectTimeout time.Duration
|
|
||||||
bufferSize int
|
|
||||||
}
|
|
113
pkg/handler/forward/local/handler.go
Normal file
113
pkg/handler/forward/local/handler.go
Normal file
@ -0,0 +1,113 @@
|
|||||||
|
package local
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"net"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/go-gost/gost/pkg/bypass"
|
||||||
|
"github.com/go-gost/gost/pkg/chain"
|
||||||
|
"github.com/go-gost/gost/pkg/handler"
|
||||||
|
"github.com/go-gost/gost/pkg/logger"
|
||||||
|
md "github.com/go-gost/gost/pkg/metadata"
|
||||||
|
"github.com/go-gost/gost/pkg/registry"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
registry.RegisterHandler("forward", NewHandler)
|
||||||
|
}
|
||||||
|
|
||||||
|
type localForwardHandler struct {
|
||||||
|
group *chain.NodeGroup
|
||||||
|
chain *chain.Chain
|
||||||
|
bypass bypass.Bypass
|
||||||
|
logger logger.Logger
|
||||||
|
md metadata
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewHandler(opts ...handler.Option) handler.Handler {
|
||||||
|
options := &handler.Options{}
|
||||||
|
for _, opt := range opts {
|
||||||
|
opt(options)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &localForwardHandler{
|
||||||
|
chain: options.Chain,
|
||||||
|
bypass: options.Bypass,
|
||||||
|
logger: options.Logger,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *localForwardHandler) Init(md md.Metadata) (err error) {
|
||||||
|
return h.parseMetadata(md)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Forward implements handler.Forwarder.
|
||||||
|
func (h *localForwardHandler) Forward(group *chain.NodeGroup) {
|
||||||
|
h.group = group
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *localForwardHandler) Handle(ctx context.Context, conn net.Conn) {
|
||||||
|
defer conn.Close()
|
||||||
|
|
||||||
|
start := time.Now()
|
||||||
|
h.logger = h.logger.WithFields(map[string]interface{}{
|
||||||
|
"remote": conn.RemoteAddr().String(),
|
||||||
|
"local": conn.LocalAddr().String(),
|
||||||
|
})
|
||||||
|
|
||||||
|
h.logger.Infof("%s <> %s", conn.RemoteAddr(), conn.LocalAddr())
|
||||||
|
defer func() {
|
||||||
|
h.logger.WithFields(map[string]interface{}{
|
||||||
|
"duration": time.Since(start),
|
||||||
|
}).Infof("%s >< %s", conn.RemoteAddr(), conn.LocalAddr())
|
||||||
|
}()
|
||||||
|
|
||||||
|
target := h.group.Next()
|
||||||
|
if target == nil {
|
||||||
|
h.logger.Error("no target available")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
h.logger = h.logger.WithFields(map[string]interface{}{
|
||||||
|
"dst": target.Addr(),
|
||||||
|
})
|
||||||
|
|
||||||
|
h.logger.Infof("%s >> %s", conn.RemoteAddr(), target.Addr())
|
||||||
|
|
||||||
|
r := (&handler.Router{}).
|
||||||
|
WithChain(h.chain).
|
||||||
|
WithRetry(h.md.retryCount).
|
||||||
|
WithLogger(h.logger)
|
||||||
|
|
||||||
|
network := "tcp"
|
||||||
|
if _, ok := conn.(net.PacketConn); ok {
|
||||||
|
network = "udp"
|
||||||
|
}
|
||||||
|
|
||||||
|
cc, err := r.Dial(ctx, network, target.Addr())
|
||||||
|
if err != nil {
|
||||||
|
h.logger.Error(err)
|
||||||
|
// TODO: the router itself may be failed due to the failed node in the router,
|
||||||
|
// the dead marker may be a wrong operation.
|
||||||
|
target.Marker().Mark()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer cc.Close()
|
||||||
|
target.Marker().Reset()
|
||||||
|
|
||||||
|
t := time.Now()
|
||||||
|
h.logger.Infof("%s <-> %s", conn.RemoteAddr(), target.Addr())
|
||||||
|
handler.Transport(conn, cc)
|
||||||
|
h.logger.
|
||||||
|
WithFields(map[string]interface{}{
|
||||||
|
"duration": time.Since(t),
|
||||||
|
}).
|
||||||
|
Infof("%s >-< %s", conn.RemoteAddr(), target.Addr())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *localForwardHandler) parseMetadata(md md.Metadata) (err error) {
|
||||||
|
h.md.readTimeout = md.GetDuration(readTimeout)
|
||||||
|
h.md.retryCount = md.GetInt(retryCount)
|
||||||
|
return
|
||||||
|
}
|
15
pkg/handler/forward/local/metadata.go
Normal file
15
pkg/handler/forward/local/metadata.go
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
package local
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
readTimeout = "readTimeout"
|
||||||
|
retryCount = "retry"
|
||||||
|
)
|
||||||
|
|
||||||
|
type metadata struct {
|
||||||
|
readTimeout time.Duration
|
||||||
|
retryCount int
|
||||||
|
}
|
@ -4,6 +4,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"net"
|
"net"
|
||||||
|
|
||||||
|
"github.com/go-gost/gost/pkg/chain"
|
||||||
"github.com/go-gost/gost/pkg/metadata"
|
"github.com/go-gost/gost/pkg/metadata"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -11,3 +12,7 @@ type Handler interface {
|
|||||||
Init(metadata.Metadata) error
|
Init(metadata.Metadata) error
|
||||||
Handle(context.Context, net.Conn)
|
Handle(context.Context, net.Conn)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Forwarder interface {
|
||||||
|
Forward(*chain.NodeGroup)
|
||||||
|
}
|
||||||
|
@ -36,6 +36,7 @@ func (r *Router) Dial(ctx context.Context, network, address string) (conn net.Co
|
|||||||
if count <= 0 {
|
if count <= 0 {
|
||||||
count = 1
|
count = 1
|
||||||
}
|
}
|
||||||
|
r.logger.Debugf("dial: %s/%s", address, network)
|
||||||
|
|
||||||
for i := 0; i < count; i++ {
|
for i := 0; i < count; i++ {
|
||||||
route := r.chain.GetRouteFor(network, address)
|
route := r.chain.GetRouteFor(network, address)
|
||||||
|
@ -90,13 +90,29 @@ func (h *socks5Handler) Handle(ctx context.Context, conn net.Conn) {
|
|||||||
case gosocks5.CmdConnect:
|
case gosocks5.CmdConnect:
|
||||||
h.handleConnect(ctx, conn, req.Addr.String())
|
h.handleConnect(ctx, conn, req.Addr.String())
|
||||||
case gosocks5.CmdBind:
|
case gosocks5.CmdBind:
|
||||||
h.handleBind(ctx, conn, req)
|
if h.md.enableBind {
|
||||||
|
h.handleBind(ctx, conn, req)
|
||||||
|
} else {
|
||||||
|
h.logger.Error("BIND is diabled")
|
||||||
|
}
|
||||||
case socks.CmdMuxBind:
|
case socks.CmdMuxBind:
|
||||||
h.handleMuxBind(ctx, conn, req)
|
if h.md.enableBind {
|
||||||
|
h.handleMuxBind(ctx, conn, req)
|
||||||
|
} else {
|
||||||
|
h.logger.Error("BIND is diabled")
|
||||||
|
}
|
||||||
case gosocks5.CmdUdp:
|
case gosocks5.CmdUdp:
|
||||||
h.handleUDP(ctx, conn, req)
|
if h.md.enableUDP {
|
||||||
|
h.handleUDP(ctx, conn, req)
|
||||||
|
} else {
|
||||||
|
h.logger.Error("UDP relay is diabled")
|
||||||
|
}
|
||||||
case socks.CmdUDPTun:
|
case socks.CmdUDPTun:
|
||||||
h.handleUDPTun(ctx, conn, req)
|
if h.md.enableUDP {
|
||||||
|
h.handleUDPTun(ctx, conn, req)
|
||||||
|
} else {
|
||||||
|
h.logger.Error("UDP relay is diabled")
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
h.logger.Errorf("unknown cmd: %d", req.Cmd)
|
h.logger.Errorf("unknown cmd: %d", req.Cmd)
|
||||||
resp := gosocks5.NewReply(gosocks5.CmdUnsupported, nil)
|
resp := gosocks5.NewReply(gosocks5.CmdUnsupported, nil)
|
||||||
|
@ -10,18 +10,6 @@ import (
|
|||||||
md "github.com/go-gost/gost/pkg/metadata"
|
md "github.com/go-gost/gost/pkg/metadata"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
|
||||||
certFile = "certFile"
|
|
||||||
keyFile = "keyFile"
|
|
||||||
caFile = "caFile"
|
|
||||||
authsKey = "auths"
|
|
||||||
readTimeout = "readTimeout"
|
|
||||||
timeout = "timeout"
|
|
||||||
retryCount = "retry"
|
|
||||||
noTLS = "notls"
|
|
||||||
udpBufferSize = "udpBufferSize"
|
|
||||||
)
|
|
||||||
|
|
||||||
type metadata struct {
|
type metadata struct {
|
||||||
tlsConfig *tls.Config
|
tlsConfig *tls.Config
|
||||||
authenticator auth.Authenticator
|
authenticator auth.Authenticator
|
||||||
@ -29,10 +17,26 @@ type metadata struct {
|
|||||||
readTimeout time.Duration
|
readTimeout time.Duration
|
||||||
retryCount int
|
retryCount int
|
||||||
noTLS bool
|
noTLS bool
|
||||||
|
enableBind bool
|
||||||
|
enableUDP bool
|
||||||
udpBufferSize int
|
udpBufferSize int
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *socks5Handler) parseMetadata(md md.Metadata) error {
|
func (h *socks5Handler) parseMetadata(md md.Metadata) error {
|
||||||
|
const (
|
||||||
|
certFile = "certFile"
|
||||||
|
keyFile = "keyFile"
|
||||||
|
caFile = "caFile"
|
||||||
|
authsKey = "auths"
|
||||||
|
readTimeout = "readTimeout"
|
||||||
|
timeout = "timeout"
|
||||||
|
retryCount = "retry"
|
||||||
|
noTLS = "notls"
|
||||||
|
enableBind = "bind"
|
||||||
|
enableUDP = "udp"
|
||||||
|
udpBufferSize = "udpBufferSize"
|
||||||
|
)
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
h.md.tlsConfig, err = util_tls.LoadTLSConfig(
|
h.md.tlsConfig, err = util_tls.LoadTLSConfig(
|
||||||
md.GetString(certFile),
|
md.GetString(certFile),
|
||||||
@ -62,6 +66,8 @@ func (h *socks5Handler) parseMetadata(md md.Metadata) error {
|
|||||||
h.md.timeout = md.GetDuration(timeout)
|
h.md.timeout = md.GetDuration(timeout)
|
||||||
h.md.retryCount = md.GetInt(retryCount)
|
h.md.retryCount = md.GetInt(retryCount)
|
||||||
h.md.noTLS = md.GetBool(noTLS)
|
h.md.noTLS = md.GetBool(noTLS)
|
||||||
|
h.md.enableBind = md.GetBool(enableBind)
|
||||||
|
h.md.enableUDP = md.GetBool(enableUDP)
|
||||||
|
|
||||||
h.md.udpBufferSize = md.GetInt(udpBufferSize)
|
h.md.udpBufferSize = md.GetInt(udpBufferSize)
|
||||||
if h.md.udpBufferSize > 0 {
|
if h.md.udpBufferSize > 0 {
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package ss
|
package ss
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bufio"
|
||||||
"context"
|
"context"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
@ -61,24 +62,55 @@ func (h *ssHandler) Handle(ctx context.Context, conn net.Conn) {
|
|||||||
}).Infof("%s >< %s", conn.RemoteAddr(), conn.LocalAddr())
|
}).Infof("%s >< %s", conn.RemoteAddr(), conn.LocalAddr())
|
||||||
}()
|
}()
|
||||||
|
|
||||||
sc := conn
|
// standard UDP relay.
|
||||||
|
if pc, ok := conn.(net.PacketConn); ok {
|
||||||
|
if h.md.enableUDP {
|
||||||
|
h.handleUDP(ctx, conn.RemoteAddr(), pc)
|
||||||
|
return
|
||||||
|
} else {
|
||||||
|
h.logger.Error("UDP relay is diabled")
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if h.md.cipher != nil {
|
if h.md.cipher != nil {
|
||||||
sc = ss.ShadowConn(h.md.cipher.StreamConn(conn), nil)
|
conn = ss.ShadowConn(h.md.cipher.StreamConn(conn), nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
if h.md.readTimeout > 0 {
|
if h.md.readTimeout > 0 {
|
||||||
sc.SetReadDeadline(time.Now().Add(h.md.readTimeout))
|
conn.SetReadDeadline(time.Now().Add(h.md.readTimeout))
|
||||||
}
|
}
|
||||||
|
|
||||||
addr := &gosocks5.Addr{}
|
br := bufio.NewReader(conn)
|
||||||
_, err := addr.ReadFrom(sc)
|
data, err := br.Peek(3)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
h.logger.Error(err)
|
h.logger.Error(err)
|
||||||
h.discard(conn)
|
h.discard(conn)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
conn.SetReadDeadline(time.Time{})
|
||||||
|
|
||||||
sc.SetReadDeadline(time.Time{})
|
conn = handler.NewBufferReaderConn(conn, br)
|
||||||
|
if data[2] == 0xff {
|
||||||
|
if h.md.enableUDP {
|
||||||
|
// UDP-over-TCP relay
|
||||||
|
h.handleUDPTun(ctx, conn)
|
||||||
|
} else {
|
||||||
|
h.logger.Error("UDP relay is diabled")
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// standard TCP.
|
||||||
|
addr := &gosocks5.Addr{}
|
||||||
|
if _, err = addr.ReadFrom(conn); err != nil {
|
||||||
|
h.logger.Error(err)
|
||||||
|
h.discard(conn)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
conn.SetReadDeadline(time.Time{})
|
||||||
|
|
||||||
h.logger = h.logger.WithFields(map[string]interface{}{
|
h.logger = h.logger.WithFields(map[string]interface{}{
|
||||||
"dst": addr.String(),
|
"dst": addr.String(),
|
||||||
@ -103,7 +135,7 @@ func (h *ssHandler) Handle(ctx context.Context, conn net.Conn) {
|
|||||||
|
|
||||||
t := time.Now()
|
t := time.Now()
|
||||||
h.logger.Infof("%s <-> %s", conn.RemoteAddr(), addr)
|
h.logger.Infof("%s <-> %s", conn.RemoteAddr(), addr)
|
||||||
handler.Transport(sc, cc)
|
handler.Transport(conn, cc)
|
||||||
h.logger.
|
h.logger.
|
||||||
WithFields(map[string]interface{}{
|
WithFields(map[string]interface{}{
|
||||||
"duration": time.Since(t),
|
"duration": time.Since(t),
|
||||||
@ -114,18 +146,3 @@ func (h *ssHandler) Handle(ctx context.Context, conn net.Conn) {
|
|||||||
func (h *ssHandler) discard(conn net.Conn) {
|
func (h *ssHandler) discard(conn net.Conn) {
|
||||||
io.Copy(ioutil.Discard, conn)
|
io.Copy(ioutil.Discard, conn)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *ssHandler) parseMetadata(md md.Metadata) (err error) {
|
|
||||||
h.md.cipher, err = ss.ShadowCipher(
|
|
||||||
md.GetString(method),
|
|
||||||
md.GetString(password),
|
|
||||||
md.GetString(key),
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
h.md.readTimeout = md.GetDuration(readTimeout)
|
|
||||||
h.md.retryCount = md.GetInt(retryCount)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
@ -3,19 +3,53 @@ package ss
|
|||||||
import (
|
import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/go-gost/gost/pkg/internal/utils/ss"
|
||||||
|
md "github.com/go-gost/gost/pkg/metadata"
|
||||||
"github.com/shadowsocks/go-shadowsocks2/core"
|
"github.com/shadowsocks/go-shadowsocks2/core"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
|
||||||
method = "method"
|
|
||||||
password = "password"
|
|
||||||
key = "key"
|
|
||||||
readTimeout = "readTimeout"
|
|
||||||
retryCount = "retry"
|
|
||||||
)
|
|
||||||
|
|
||||||
type metadata struct {
|
type metadata struct {
|
||||||
cipher core.Cipher
|
cipher core.Cipher
|
||||||
readTimeout time.Duration
|
readTimeout time.Duration
|
||||||
retryCount int
|
retryCount int
|
||||||
|
bufferSize int
|
||||||
|
enableUDP bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *ssHandler) parseMetadata(md md.Metadata) (err error) {
|
||||||
|
const (
|
||||||
|
method = "method"
|
||||||
|
password = "password"
|
||||||
|
key = "key"
|
||||||
|
readTimeout = "readTimeout"
|
||||||
|
retryCount = "retry"
|
||||||
|
enableUDP = "udp"
|
||||||
|
bufferSize = "bufferSize"
|
||||||
|
)
|
||||||
|
|
||||||
|
h.md.cipher, err = ss.ShadowCipher(
|
||||||
|
md.GetString(method),
|
||||||
|
md.GetString(password),
|
||||||
|
md.GetString(key),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
h.md.readTimeout = md.GetDuration(readTimeout)
|
||||||
|
h.md.retryCount = md.GetInt(retryCount)
|
||||||
|
h.md.enableUDP = md.GetBool(enableUDP)
|
||||||
|
|
||||||
|
h.md.bufferSize = md.GetInt(bufferSize)
|
||||||
|
if h.md.bufferSize > 0 {
|
||||||
|
if h.md.bufferSize < 512 {
|
||||||
|
h.md.bufferSize = 512 // min buffer size
|
||||||
|
}
|
||||||
|
if h.md.bufferSize > 65*1024 {
|
||||||
|
h.md.bufferSize = 65 * 1024 // max buffer size
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
h.md.bufferSize = 4096 // default buffer size
|
||||||
|
}
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
@ -1,64 +1,21 @@
|
|||||||
package ssu
|
package ss
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"net"
|
"net"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/go-gost/gost/pkg/bypass"
|
|
||||||
"github.com/go-gost/gost/pkg/chain"
|
|
||||||
"github.com/go-gost/gost/pkg/handler"
|
"github.com/go-gost/gost/pkg/handler"
|
||||||
"github.com/go-gost/gost/pkg/internal/bufpool"
|
"github.com/go-gost/gost/pkg/internal/bufpool"
|
||||||
"github.com/go-gost/gost/pkg/internal/utils/socks"
|
"github.com/go-gost/gost/pkg/internal/utils/socks"
|
||||||
"github.com/go-gost/gost/pkg/internal/utils/ss"
|
"github.com/go-gost/gost/pkg/internal/utils/ss"
|
||||||
"github.com/go-gost/gost/pkg/logger"
|
|
||||||
md "github.com/go-gost/gost/pkg/metadata"
|
|
||||||
"github.com/go-gost/gost/pkg/registry"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func (h *ssHandler) handleUDP(ctx context.Context, raddr net.Addr, conn net.PacketConn) {
|
||||||
registry.RegisterHandler("ssu", NewHandler)
|
if h.md.cipher != nil {
|
||||||
}
|
conn = h.md.cipher.PacketConn(conn)
|
||||||
|
|
||||||
type ssuHandler struct {
|
|
||||||
chain *chain.Chain
|
|
||||||
bypass bypass.Bypass
|
|
||||||
logger logger.Logger
|
|
||||||
md metadata
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewHandler(opts ...handler.Option) handler.Handler {
|
|
||||||
options := &handler.Options{}
|
|
||||||
for _, opt := range opts {
|
|
||||||
opt(options)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return &ssuHandler{
|
|
||||||
chain: options.Chain,
|
|
||||||
bypass: options.Bypass,
|
|
||||||
logger: options.Logger,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *ssuHandler) Init(md md.Metadata) (err error) {
|
|
||||||
return h.parseMetadata(md)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *ssuHandler) Handle(ctx context.Context, conn net.Conn) {
|
|
||||||
defer conn.Close()
|
|
||||||
|
|
||||||
start := time.Now()
|
|
||||||
h.logger = h.logger.WithFields(map[string]interface{}{
|
|
||||||
"remote": conn.RemoteAddr().String(),
|
|
||||||
"local": conn.LocalAddr().String(),
|
|
||||||
})
|
|
||||||
h.logger.Infof("%s <> %s", conn.RemoteAddr(), conn.LocalAddr())
|
|
||||||
defer func() {
|
|
||||||
h.logger.WithFields(map[string]interface{}{
|
|
||||||
"duration": time.Since(start),
|
|
||||||
}).Infof("%s >< %s", conn.RemoteAddr(), conn.LocalAddr())
|
|
||||||
}()
|
|
||||||
|
|
||||||
// obtain a udp connection
|
// obtain a udp connection
|
||||||
r := (&handler.Router{}).
|
r := (&handler.Router{}).
|
||||||
WithChain(h.chain).
|
WithChain(h.chain).
|
||||||
@ -81,28 +38,40 @@ func (h *ssuHandler) Handle(ctx context.Context, conn net.Conn) {
|
|||||||
"bind": cc.LocalAddr().String(),
|
"bind": cc.LocalAddr().String(),
|
||||||
})
|
})
|
||||||
h.logger.Infof("bind on %s OK", cc.LocalAddr().String())
|
h.logger.Infof("bind on %s OK", cc.LocalAddr().String())
|
||||||
|
t := time.Now()
|
||||||
|
h.logger.Infof("%s <-> %s", raddr, cc.LocalAddr())
|
||||||
|
h.relayPacket(
|
||||||
|
ss.UDPServerConn(conn, raddr, h.md.bufferSize),
|
||||||
|
cc,
|
||||||
|
)
|
||||||
|
h.logger.
|
||||||
|
WithFields(map[string]interface{}{"duration": time.Since(t)}).
|
||||||
|
Infof("%s >-< %s", raddr, cc.LocalAddr())
|
||||||
|
}
|
||||||
|
|
||||||
pc, ok := conn.(net.PacketConn)
|
func (h *ssHandler) handleUDPTun(ctx context.Context, conn net.Conn) {
|
||||||
if ok {
|
// obtain a udp connection
|
||||||
if h.md.cipher != nil {
|
r := (&handler.Router{}).
|
||||||
pc = h.md.cipher.PacketConn(pc)
|
WithChain(h.chain).
|
||||||
}
|
WithRetry(h.md.retryCount).
|
||||||
|
WithLogger(h.logger)
|
||||||
t := time.Now()
|
c, err := r.Dial(ctx, "udp", "")
|
||||||
h.logger.Infof("%s <-> %s", conn.RemoteAddr(), cc.LocalAddr())
|
if err != nil {
|
||||||
h.relayPacket(
|
h.logger.Error(err)
|
||||||
ss.UDPServerConn(pc, conn.RemoteAddr(), h.md.bufferSize),
|
|
||||||
cc,
|
|
||||||
)
|
|
||||||
h.logger.
|
|
||||||
WithFields(map[string]interface{}{"duration": time.Since(t)}).
|
|
||||||
Infof("%s >-< %s", conn.RemoteAddr(), cc.LocalAddr())
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if h.md.cipher != nil {
|
cc, ok := c.(net.PacketConn)
|
||||||
conn = ss.ShadowConn(h.md.cipher.StreamConn(conn), nil)
|
if !ok {
|
||||||
|
h.logger.Errorf("%s: not a packet connection")
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
defer cc.Close()
|
||||||
|
|
||||||
|
h.logger = h.logger.WithFields(map[string]interface{}{
|
||||||
|
"bind": cc.LocalAddr().String(),
|
||||||
|
})
|
||||||
|
h.logger.Infof("bind on %s OK", cc.LocalAddr().String())
|
||||||
|
|
||||||
t := time.Now()
|
t := time.Now()
|
||||||
h.logger.Infof("%s <-> %s", conn.RemoteAddr(), cc.LocalAddr())
|
h.logger.Infof("%s <-> %s", conn.RemoteAddr(), cc.LocalAddr())
|
||||||
@ -112,7 +81,7 @@ func (h *ssuHandler) Handle(ctx context.Context, conn net.Conn) {
|
|||||||
Infof("%s >-< %s", conn.RemoteAddr(), cc.LocalAddr())
|
Infof("%s >-< %s", conn.RemoteAddr(), cc.LocalAddr())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *ssuHandler) relayPacket(pc1, pc2 net.PacketConn) (err error) {
|
func (h *ssHandler) relayPacket(pc1, pc2 net.PacketConn) (err error) {
|
||||||
bufSize := h.md.bufferSize
|
bufSize := h.md.bufferSize
|
||||||
errc := make(chan error, 2)
|
errc := make(chan error, 2)
|
||||||
|
|
||||||
@ -183,7 +152,7 @@ func (h *ssuHandler) relayPacket(pc1, pc2 net.PacketConn) (err error) {
|
|||||||
return <-errc
|
return <-errc
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *ssuHandler) tunnelUDP(tunnel, c net.PacketConn) (err error) {
|
func (h *ssHandler) tunnelUDP(tunnel, c net.PacketConn) (err error) {
|
||||||
bufSize := h.md.bufferSize
|
bufSize := h.md.bufferSize
|
||||||
errc := make(chan error, 2)
|
errc := make(chan error, 2)
|
||||||
|
|
||||||
@ -255,31 +224,3 @@ func (h *ssuHandler) tunnelUDP(tunnel, c net.PacketConn) (err error) {
|
|||||||
|
|
||||||
return <-errc
|
return <-errc
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *ssuHandler) parseMetadata(md md.Metadata) (err error) {
|
|
||||||
h.md.cipher, err = ss.ShadowCipher(
|
|
||||||
md.GetString(method),
|
|
||||||
md.GetString(password),
|
|
||||||
md.GetString(key),
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
h.md.readTimeout = md.GetDuration(readTimeout)
|
|
||||||
h.md.retryCount = md.GetInt(retryCount)
|
|
||||||
|
|
||||||
h.md.bufferSize = md.GetInt(bufferSize)
|
|
||||||
if h.md.bufferSize > 0 {
|
|
||||||
if h.md.bufferSize < 512 {
|
|
||||||
h.md.bufferSize = 512 // min buffer size
|
|
||||||
}
|
|
||||||
if h.md.bufferSize > 65*1024 {
|
|
||||||
h.md.bufferSize = 65 * 1024 // max buffer size
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
h.md.bufferSize = 4096 // default buffer size
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
@ -1,23 +0,0 @@
|
|||||||
package ssu
|
|
||||||
|
|
||||||
import (
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/shadowsocks/go-shadowsocks2/core"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
method = "method"
|
|
||||||
password = "password"
|
|
||||||
key = "key"
|
|
||||||
readTimeout = "readTimeout"
|
|
||||||
retryCount = "retry"
|
|
||||||
bufferSize = "bufferSize"
|
|
||||||
)
|
|
||||||
|
|
||||||
type metadata struct {
|
|
||||||
cipher core.Cipher
|
|
||||||
readTimeout time.Duration
|
|
||||||
retryCount int
|
|
||||||
bufferSize int
|
|
||||||
}
|
|
@ -1,7 +1,9 @@
|
|||||||
package handler
|
package handler
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bufio"
|
||||||
"io"
|
"io"
|
||||||
|
"net"
|
||||||
|
|
||||||
"github.com/go-gost/gost/pkg/internal/bufpool"
|
"github.com/go-gost/gost/pkg/internal/bufpool"
|
||||||
)
|
)
|
||||||
@ -30,3 +32,19 @@ func copyBuffer(dst io.Writer, src io.Reader) error {
|
|||||||
_, err := io.CopyBuffer(dst, src, buf)
|
_, err := io.CopyBuffer(dst, src, buf)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type bufferReaderConn struct {
|
||||||
|
net.Conn
|
||||||
|
br *bufio.Reader
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewBufferReaderConn(conn net.Conn, br *bufio.Reader) net.Conn {
|
||||||
|
return &bufferReaderConn{
|
||||||
|
Conn: conn,
|
||||||
|
br: br,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *bufferReaderConn) Read(b []byte) (int, error) {
|
||||||
|
return c.br.Read(b)
|
||||||
|
}
|
||||||
|
@ -76,6 +76,7 @@ func (c *UDPTunConn) WriteTo(b []byte, addr net.Addr) (n int, err error) {
|
|||||||
Data: b,
|
Data: b,
|
||||||
}
|
}
|
||||||
dgram.Header.Rsv = uint16(len(dgram.Data))
|
dgram.Header.Rsv = uint16(len(dgram.Data))
|
||||||
|
dgram.Header.Frag = 0xff // UDP tun relay flag, used by shadowsocks
|
||||||
_, err = dgram.WriteTo(c.Conn)
|
_, err = dgram.WriteTo(c.Conn)
|
||||||
n = len(b)
|
n = len(b)
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user