add KCP support
This commit is contained in:
parent
684ccca252
commit
9b2bd7a88c
@ -6,7 +6,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
// ErrEmptyChain is an error that implies the chain is empty
|
// ErrEmptyChain is an error that implies the chain is empty.
|
||||||
ErrEmptyChain = errors.New("empty chain")
|
ErrEmptyChain = errors.New("empty chain")
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -5,7 +5,6 @@ import (
|
|||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httputil"
|
"net/http/httputil"
|
||||||
"net/url"
|
|
||||||
|
|
||||||
"github.com/ginuerzh/gost/gost"
|
"github.com/ginuerzh/gost/gost"
|
||||||
)
|
)
|
||||||
@ -28,6 +27,7 @@ func main() {
|
|||||||
},
|
},
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
// socks5+tcp
|
// socks5+tcp
|
||||||
gost.Node{
|
gost.Node{
|
||||||
Addr: "127.0.0.1:1080",
|
Addr: "127.0.0.1:1080",
|
||||||
@ -36,6 +36,7 @@ func main() {
|
|||||||
gost.TCPTransporter(),
|
gost.TCPTransporter(),
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
// ss+tcp
|
// ss+tcp
|
||||||
@ -83,6 +84,15 @@ func main() {
|
|||||||
),
|
),
|
||||||
},
|
},
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
// http+kcp
|
||||||
|
gost.Node{
|
||||||
|
Addr: "127.0.0.1:8388",
|
||||||
|
Client: gost.NewClient(
|
||||||
|
gost.HTTPConnector(nil),
|
||||||
|
gost.KCPTransporter(nil),
|
||||||
|
),
|
||||||
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
conn, err := chain.Dial("localhost:10000")
|
conn, err := chain.Dial("localhost:10000")
|
||||||
|
@ -5,15 +5,15 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// Client is a proxy client.
|
// Client is a proxy client.
|
||||||
|
// A client is divided into two layers: connector and transporter.
|
||||||
|
// Connector is responsible for connecting to the destination address through this proxy.
|
||||||
|
// Transporter performs a handshake with this proxy.
|
||||||
type Client struct {
|
type Client struct {
|
||||||
Connector Connector
|
Connector Connector
|
||||||
Transporter Transporter
|
Transporter Transporter
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewClient creates a proxy client.
|
// NewClient creates a proxy client.
|
||||||
// A client is divided into two layers: connector and transporter.
|
|
||||||
// Connector is responsible for connecting to the destination address through this proxy.
|
|
||||||
// Transporter performs a handshake with this proxy.
|
|
||||||
func NewClient(c Connector, tr Transporter) *Client {
|
func NewClient(c Connector, tr Transporter) *Client {
|
||||||
return &Client{
|
return &Client{
|
||||||
Connector: c,
|
Connector: c,
|
||||||
@ -21,9 +21,9 @@ func NewClient(c Connector, tr Transporter) *Client {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Dial connects to the target address
|
// Dial connects to the target address.
|
||||||
func (c *Client) Dial(addr string) (net.Conn, error) {
|
func (c *Client) Dial(addr string) (net.Conn, error) {
|
||||||
return net.Dial(c.Transporter.Network(), addr)
|
return c.Transporter.Dial(addr)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handshake performs a handshake with the proxy.
|
// Handshake performs a handshake with the proxy.
|
||||||
@ -38,7 +38,7 @@ func (c *Client) Connect(conn net.Conn, addr string) (net.Conn, error) {
|
|||||||
return c.Connector.Connect(conn, addr)
|
return c.Connector.Connect(conn, addr)
|
||||||
}
|
}
|
||||||
|
|
||||||
// DefaultClient is a standard HTTP proxy client
|
// DefaultClient is a standard HTTP proxy client.
|
||||||
var DefaultClient = NewClient(HTTPConnector(nil), TCPTransporter())
|
var DefaultClient = NewClient(HTTPConnector(nil), TCPTransporter())
|
||||||
|
|
||||||
// Dial connects to the address addr via the DefaultClient.
|
// Dial connects to the address addr via the DefaultClient.
|
||||||
@ -46,7 +46,7 @@ func Dial(addr string) (net.Conn, error) {
|
|||||||
return DefaultClient.Dial(addr)
|
return DefaultClient.Dial(addr)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handshake performs a handshake via the DefaultClient
|
// Handshake performs a handshake via the DefaultClient.
|
||||||
func Handshake(conn net.Conn) (net.Conn, error) {
|
func Handshake(conn net.Conn) (net.Conn, error) {
|
||||||
return DefaultClient.Handshake(conn)
|
return DefaultClient.Handshake(conn)
|
||||||
}
|
}
|
||||||
@ -56,26 +56,27 @@ func Connect(conn net.Conn, addr string) (net.Conn, error) {
|
|||||||
return DefaultClient.Connect(conn, addr)
|
return DefaultClient.Connect(conn, addr)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Connector is responsible for connecting to the destination address
|
// Connector is responsible for connecting to the destination address.
|
||||||
type Connector interface {
|
type Connector interface {
|
||||||
Connect(conn net.Conn, addr string) (net.Conn, error)
|
Connect(conn net.Conn, addr string) (net.Conn, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Transporter is responsible for handshaking with the proxy server.
|
// Transporter is responsible for handshaking with the proxy server.
|
||||||
type Transporter interface {
|
type Transporter interface {
|
||||||
Network() string
|
Dial(addr string) (net.Conn, error)
|
||||||
Handshake(conn net.Conn) (net.Conn, error)
|
Handshake(conn net.Conn) (net.Conn, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
type tcpTransporter struct {
|
type tcpTransporter struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TCPTransporter creates a transporter for TCP proxy client.
|
||||||
func TCPTransporter() Transporter {
|
func TCPTransporter() Transporter {
|
||||||
return &tcpTransporter{}
|
return &tcpTransporter{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tr *tcpTransporter) Network() string {
|
func (tr *tcpTransporter) Dial(addr string) (net.Conn, error) {
|
||||||
return "tcp"
|
return net.Dial("tcp", addr)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tr *tcpTransporter) Handshake(conn net.Conn) (net.Conn, error) {
|
func (tr *tcpTransporter) Handshake(conn net.Conn) (net.Conn, error) {
|
||||||
|
18
gost/gost.go
18
gost/gost.go
@ -6,24 +6,30 @@ import (
|
|||||||
"github.com/go-log/log"
|
"github.com/go-log/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Version is the gost version.
|
||||||
const Version = "2.4-dev20170722"
|
const Version = "2.4-dev20170722"
|
||||||
|
|
||||||
|
// Debug is a flag that enables the debug log.
|
||||||
var Debug bool
|
var Debug bool
|
||||||
|
|
||||||
var (
|
var (
|
||||||
TinyBufferSize = 128
|
tinyBufferSize = 128
|
||||||
SmallBufferSize = 1 * 1024 // 1KB small buffer
|
smallBufferSize = 1 * 1024 // 1KB small buffer
|
||||||
MediumBufferSize = 8 * 1024 // 8KB medium buffer
|
mediumBufferSize = 8 * 1024 // 8KB medium buffer
|
||||||
LargeBufferSize = 32 * 1024 // 32KB large buffer
|
largeBufferSize = 32 * 1024 // 32KB large buffer
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
// KeepAliveTime is the keep alive time period for TCP connection.
|
||||||
KeepAliveTime = 180 * time.Second
|
KeepAliveTime = 180 * time.Second
|
||||||
|
// DialTimeout is the timeout of dial.
|
||||||
DialTimeout = 30 * time.Second
|
DialTimeout = 30 * time.Second
|
||||||
|
// ReadTimeout is the timeout for reading.
|
||||||
ReadTimeout = 90 * time.Second
|
ReadTimeout = 90 * time.Second
|
||||||
|
// WriteTimeout is the timeout for writing.
|
||||||
WriteTimeout = 90 * time.Second
|
WriteTimeout = 90 * time.Second
|
||||||
|
// default udp node TTL in second for udp port forwarding.
|
||||||
DefaultTTL = 60 // default udp node TTL in second for udp port forwarding
|
defaultTTL = 60
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
@ -6,30 +6,36 @@ import (
|
|||||||
"net/url"
|
"net/url"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Handler is a proxy server handler
|
||||||
type Handler interface {
|
type Handler interface {
|
||||||
Handle(net.Conn)
|
Handle(net.Conn)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// HandlerOptions describes the options for Handler.
|
||||||
type HandlerOptions struct {
|
type HandlerOptions struct {
|
||||||
Chain *Chain
|
Chain *Chain
|
||||||
Users []*url.Userinfo
|
Users []*url.Userinfo
|
||||||
TLSConfig *tls.Config
|
TLSConfig *tls.Config
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// HandlerOption allows a common way to set handler options.
|
||||||
type HandlerOption func(opts *HandlerOptions)
|
type HandlerOption func(opts *HandlerOptions)
|
||||||
|
|
||||||
|
// ChainHandlerOption sets the Chain option of HandlerOptions.
|
||||||
func ChainHandlerOption(chain *Chain) HandlerOption {
|
func ChainHandlerOption(chain *Chain) HandlerOption {
|
||||||
return func(opts *HandlerOptions) {
|
return func(opts *HandlerOptions) {
|
||||||
opts.Chain = chain
|
opts.Chain = chain
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UsersHandlerOption sets the Users option of HandlerOptions.
|
||||||
func UsersHandlerOption(users ...*url.Userinfo) HandlerOption {
|
func UsersHandlerOption(users ...*url.Userinfo) HandlerOption {
|
||||||
return func(opts *HandlerOptions) {
|
return func(opts *HandlerOptions) {
|
||||||
opts.Users = users
|
opts.Users = users
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TLSConfigHandlerOption sets the TLSConfig option of HandlerOptions.
|
||||||
func TLSConfigHandlerOption(config *tls.Config) HandlerOption {
|
func TLSConfigHandlerOption(config *tls.Config) HandlerOption {
|
||||||
return func(opts *HandlerOptions) {
|
return func(opts *HandlerOptions) {
|
||||||
opts.TLSConfig = config
|
opts.TLSConfig = config
|
||||||
|
@ -17,6 +17,8 @@ type httpConnector struct {
|
|||||||
User *url.Userinfo
|
User *url.Userinfo
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// HTTPConnector creates a Connector for HTTP proxy client.
|
||||||
|
// It accepts an optional auth info for HTTP Basic Authentication.
|
||||||
func HTTPConnector(user *url.Userinfo) Connector {
|
func HTTPConnector(user *url.Userinfo) Connector {
|
||||||
return &httpConnector{User: user}
|
return &httpConnector{User: user}
|
||||||
}
|
}
|
||||||
@ -71,6 +73,7 @@ type httpHandler struct {
|
|||||||
options *HandlerOptions
|
options *HandlerOptions
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// HTTPHandler creates a server Handler for HTTP proxy server.
|
||||||
func HTTPHandler(opts ...HandlerOption) Handler {
|
func HTTPHandler(opts ...HandlerOption) Handler {
|
||||||
h := &httpHandler{
|
h := &httpHandler{
|
||||||
options: &HandlerOptions{
|
options: &HandlerOptions{
|
||||||
|
472
gost/kcp.go
Normal file
472
gost/kcp.go
Normal file
@ -0,0 +1,472 @@
|
|||||||
|
package gost
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/sha1"
|
||||||
|
"encoding/csv"
|
||||||
|
"fmt"
|
||||||
|
"net"
|
||||||
|
"os"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"golang.org/x/crypto/pbkdf2"
|
||||||
|
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"github.com/go-log/log"
|
||||||
|
"github.com/klauspost/compress/snappy"
|
||||||
|
"gopkg.in/xtaci/kcp-go.v2"
|
||||||
|
"gopkg.in/xtaci/smux.v1"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
// SALT is the default salt for KCP cipher.
|
||||||
|
SALT = "kcp-go"
|
||||||
|
)
|
||||||
|
|
||||||
|
// KCPConfig describes the config for KCP.
|
||||||
|
type KCPConfig struct {
|
||||||
|
Key string `json:"key"`
|
||||||
|
Crypt string `json:"crypt"`
|
||||||
|
Mode string `json:"mode"`
|
||||||
|
MTU int `json:"mtu"`
|
||||||
|
SndWnd int `json:"sndwnd"`
|
||||||
|
RcvWnd int `json:"rcvwnd"`
|
||||||
|
DataShard int `json:"datashard"`
|
||||||
|
ParityShard int `json:"parityshard"`
|
||||||
|
DSCP int `json:"dscp"`
|
||||||
|
NoComp bool `json:"nocomp"`
|
||||||
|
AckNodelay bool `json:"acknodelay"`
|
||||||
|
NoDelay int `json:"nodelay"`
|
||||||
|
Interval int `json:"interval"`
|
||||||
|
Resend int `json:"resend"`
|
||||||
|
NoCongestion int `json:"nc"`
|
||||||
|
SockBuf int `json:"sockbuf"`
|
||||||
|
KeepAlive int `json:"keepalive"`
|
||||||
|
SnmpLog string `json:"snmplog"`
|
||||||
|
SnmpPeriod int `json:"snmpperiod"`
|
||||||
|
Signal bool `json:"signal"` // Signal enables the signal SIGUSR1 feature.
|
||||||
|
}
|
||||||
|
|
||||||
|
// Init initializes the KCP config.
|
||||||
|
func (c *KCPConfig) Init() {
|
||||||
|
switch c.Mode {
|
||||||
|
case "normal":
|
||||||
|
c.NoDelay, c.Interval, c.Resend, c.NoCongestion = 0, 50, 2, 1
|
||||||
|
case "fast2":
|
||||||
|
c.NoDelay, c.Interval, c.Resend, c.NoCongestion = 1, 30, 2, 1
|
||||||
|
case "fast3":
|
||||||
|
c.NoDelay, c.Interval, c.Resend, c.NoCongestion = 1, 20, 2, 1
|
||||||
|
case "fast":
|
||||||
|
fallthrough
|
||||||
|
default:
|
||||||
|
c.NoDelay, c.Interval, c.Resend, c.NoCongestion = 0, 40, 2, 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
// DefaultKCPConfig is the default KCP config.
|
||||||
|
DefaultKCPConfig = &KCPConfig{
|
||||||
|
Key: "it's a secrect",
|
||||||
|
Crypt: "aes",
|
||||||
|
Mode: "fast",
|
||||||
|
MTU: 1350,
|
||||||
|
SndWnd: 1024,
|
||||||
|
RcvWnd: 1024,
|
||||||
|
DataShard: 10,
|
||||||
|
ParityShard: 3,
|
||||||
|
DSCP: 0,
|
||||||
|
NoComp: false,
|
||||||
|
AckNodelay: false,
|
||||||
|
NoDelay: 0,
|
||||||
|
Interval: 50,
|
||||||
|
Resend: 0,
|
||||||
|
NoCongestion: 0,
|
||||||
|
SockBuf: 4194304,
|
||||||
|
KeepAlive: 10,
|
||||||
|
SnmpLog: "",
|
||||||
|
SnmpPeriod: 60,
|
||||||
|
Signal: false,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
type kcpConn struct {
|
||||||
|
conn net.Conn
|
||||||
|
stream *smux.Stream
|
||||||
|
}
|
||||||
|
|
||||||
|
func newKCPConn(conn net.Conn, stream *smux.Stream) *kcpConn {
|
||||||
|
return &kcpConn{conn: conn, stream: stream}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *kcpConn) Read(b []byte) (n int, err error) {
|
||||||
|
return c.stream.Read(b)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *kcpConn) Write(b []byte) (n int, err error) {
|
||||||
|
return c.stream.Write(b)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *kcpConn) Close() error {
|
||||||
|
return c.stream.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *kcpConn) LocalAddr() net.Addr {
|
||||||
|
return c.conn.LocalAddr()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *kcpConn) RemoteAddr() net.Addr {
|
||||||
|
return c.conn.RemoteAddr()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *kcpConn) SetDeadline(t time.Time) error {
|
||||||
|
return c.conn.SetDeadline(t)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *kcpConn) SetReadDeadline(t time.Time) error {
|
||||||
|
return c.conn.SetReadDeadline(t)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *kcpConn) SetWriteDeadline(t time.Time) error {
|
||||||
|
return c.conn.SetWriteDeadline(t)
|
||||||
|
}
|
||||||
|
|
||||||
|
type kcpSession struct {
|
||||||
|
conn net.Conn
|
||||||
|
session *smux.Session
|
||||||
|
}
|
||||||
|
|
||||||
|
func (session *kcpSession) GetConn() (*kcpConn, error) {
|
||||||
|
stream, err := session.session.OpenStream()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return newKCPConn(session.conn, stream), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (session *kcpSession) Close() error {
|
||||||
|
return session.session.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (session *kcpSession) IsClosed() bool {
|
||||||
|
return session.session.IsClosed()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (session *kcpSession) NumStreams() int {
|
||||||
|
return session.session.NumStreams()
|
||||||
|
}
|
||||||
|
|
||||||
|
type kcpTransporter struct {
|
||||||
|
sessions map[string]*kcpSession
|
||||||
|
sessionMutex sync.Mutex
|
||||||
|
config *KCPConfig
|
||||||
|
}
|
||||||
|
|
||||||
|
// KCPTransporter creates a Transporter that is used by KCP proxy client.
|
||||||
|
func KCPTransporter(config *KCPConfig) Transporter {
|
||||||
|
if config == nil {
|
||||||
|
config = DefaultKCPConfig
|
||||||
|
}
|
||||||
|
config.Init()
|
||||||
|
|
||||||
|
go snmpLogger(config.SnmpLog, config.SnmpPeriod)
|
||||||
|
if config.Signal {
|
||||||
|
go kcpSigHandler()
|
||||||
|
}
|
||||||
|
|
||||||
|
return &kcpTransporter{
|
||||||
|
config: config,
|
||||||
|
sessions: make(map[string]*kcpSession),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (tr *kcpTransporter) Dial(addr string) (conn net.Conn, err error) {
|
||||||
|
tr.sessionMutex.Lock()
|
||||||
|
session, ok := tr.sessions[addr]
|
||||||
|
if !ok {
|
||||||
|
session, err = tr.dial(addr, tr.config)
|
||||||
|
if err != nil {
|
||||||
|
tr.sessionMutex.Unlock()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
tr.sessions[addr] = session
|
||||||
|
}
|
||||||
|
tr.sessionMutex.Unlock()
|
||||||
|
|
||||||
|
conn, err = session.GetConn()
|
||||||
|
if err != nil {
|
||||||
|
tr.sessionMutex.Lock()
|
||||||
|
session.Close()
|
||||||
|
delete(tr.sessions, addr)
|
||||||
|
tr.sessionMutex.Unlock()
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (tr *kcpTransporter) dial(addr string, config *KCPConfig) (*kcpSession, error) {
|
||||||
|
kcpconn, err := kcp.DialWithOptions(addr,
|
||||||
|
blockCrypt(config.Key, config.Crypt, SALT), config.DataShard, config.ParityShard)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
kcpconn.SetStreamMode(true)
|
||||||
|
kcpconn.SetNoDelay(config.NoDelay, config.Interval, config.Resend, config.NoCongestion)
|
||||||
|
kcpconn.SetWindowSize(config.SndWnd, config.RcvWnd)
|
||||||
|
kcpconn.SetMtu(config.MTU)
|
||||||
|
kcpconn.SetACKNoDelay(config.AckNodelay)
|
||||||
|
kcpconn.SetKeepAlive(config.KeepAlive)
|
||||||
|
|
||||||
|
if err := kcpconn.SetDSCP(config.DSCP); err != nil {
|
||||||
|
log.Log("[kcp]", err)
|
||||||
|
}
|
||||||
|
if err := kcpconn.SetReadBuffer(config.SockBuf); err != nil {
|
||||||
|
log.Log("[kcp]", err)
|
||||||
|
}
|
||||||
|
if err := kcpconn.SetWriteBuffer(config.SockBuf); err != nil {
|
||||||
|
log.Log("[kcp]", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// stream multiplex
|
||||||
|
smuxConfig := smux.DefaultConfig()
|
||||||
|
smuxConfig.MaxReceiveBuffer = config.SockBuf
|
||||||
|
var conn net.Conn = kcpconn
|
||||||
|
if !config.NoComp {
|
||||||
|
conn = newCompStreamConn(kcpconn)
|
||||||
|
}
|
||||||
|
session, err := smux.Client(conn, smuxConfig)
|
||||||
|
if err != nil {
|
||||||
|
conn.Close()
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &kcpSession{conn: conn, session: session}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (tr *kcpTransporter) Handshake(conn net.Conn) (net.Conn, error) {
|
||||||
|
return conn, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type kcpListener struct {
|
||||||
|
config *KCPConfig
|
||||||
|
ln *kcp.Listener
|
||||||
|
connChan chan net.Conn
|
||||||
|
errChan chan error
|
||||||
|
}
|
||||||
|
|
||||||
|
// KCPListener creates a Listener for KCP proxy server.
|
||||||
|
func KCPListener(addr string, config *KCPConfig) (Listener, error) {
|
||||||
|
if config == nil {
|
||||||
|
config = DefaultKCPConfig
|
||||||
|
}
|
||||||
|
config.Init()
|
||||||
|
|
||||||
|
ln, err := kcp.ListenWithOptions(addr,
|
||||||
|
blockCrypt(config.Key, config.Crypt, SALT), config.DataShard, config.ParityShard)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if err = ln.SetDSCP(config.DSCP); err != nil {
|
||||||
|
log.Log("[kcp]", err)
|
||||||
|
}
|
||||||
|
if err = ln.SetReadBuffer(config.SockBuf); err != nil {
|
||||||
|
log.Log("[kcp]", err)
|
||||||
|
}
|
||||||
|
if err = ln.SetWriteBuffer(config.SockBuf); err != nil {
|
||||||
|
log.Log("[kcp]", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
go snmpLogger(config.SnmpLog, config.SnmpPeriod)
|
||||||
|
if config.Signal {
|
||||||
|
go kcpSigHandler()
|
||||||
|
}
|
||||||
|
|
||||||
|
l := &kcpListener{
|
||||||
|
config: config,
|
||||||
|
ln: ln,
|
||||||
|
connChan: make(chan net.Conn, 128),
|
||||||
|
errChan: make(chan error),
|
||||||
|
}
|
||||||
|
go l.acceptLoop()
|
||||||
|
|
||||||
|
return l, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *kcpListener) acceptLoop() {
|
||||||
|
for {
|
||||||
|
conn, err := l.ln.AcceptKCP()
|
||||||
|
if err != nil {
|
||||||
|
log.Log("[kcp] accept:", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
conn.SetStreamMode(true)
|
||||||
|
conn.SetNoDelay(l.config.NoDelay, l.config.Interval, l.config.Resend, l.config.NoCongestion)
|
||||||
|
conn.SetMtu(l.config.MTU)
|
||||||
|
conn.SetWindowSize(l.config.SndWnd, l.config.RcvWnd)
|
||||||
|
conn.SetACKNoDelay(l.config.AckNodelay)
|
||||||
|
conn.SetKeepAlive(l.config.KeepAlive)
|
||||||
|
go l.mux(conn)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *kcpListener) Accept() (conn net.Conn, err error) {
|
||||||
|
select {
|
||||||
|
case conn = <-l.connChan:
|
||||||
|
case err = <-l.errChan:
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *kcpListener) mux(conn net.Conn) {
|
||||||
|
smuxConfig := smux.DefaultConfig()
|
||||||
|
smuxConfig.MaxReceiveBuffer = l.config.SockBuf
|
||||||
|
|
||||||
|
log.Logf("[kcp] %s - %s", conn.RemoteAddr(), l.Addr())
|
||||||
|
|
||||||
|
if !l.config.NoComp {
|
||||||
|
conn = newCompStreamConn(conn)
|
||||||
|
}
|
||||||
|
|
||||||
|
mux, err := smux.Server(conn, smuxConfig)
|
||||||
|
if err != nil {
|
||||||
|
log.Log("[kcp]", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer mux.Close()
|
||||||
|
|
||||||
|
log.Logf("[kcp] %s <-> %s", conn.RemoteAddr(), l.Addr())
|
||||||
|
defer log.Logf("[kcp] %s >-< %s", conn.RemoteAddr(), l.Addr())
|
||||||
|
|
||||||
|
for {
|
||||||
|
stream, err := mux.AcceptStream()
|
||||||
|
if err != nil {
|
||||||
|
log.Log("[kcp] accept stream:", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
select {
|
||||||
|
case l.connChan <- newKCPConn(conn, stream):
|
||||||
|
default:
|
||||||
|
log.Logf("[kcp] %s - %s: connection queue is full", conn.RemoteAddr(), l.Addr())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *kcpListener) Addr() net.Addr {
|
||||||
|
return l.ln.Addr()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *kcpListener) Close() error {
|
||||||
|
return l.ln.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
func blockCrypt(key, crypt, salt string) (block kcp.BlockCrypt) {
|
||||||
|
pass := pbkdf2.Key([]byte(key), []byte(salt), 4096, 32, sha1.New)
|
||||||
|
|
||||||
|
switch crypt {
|
||||||
|
case "tea":
|
||||||
|
block, _ = kcp.NewTEABlockCrypt(pass[:16])
|
||||||
|
case "xor":
|
||||||
|
block, _ = kcp.NewSimpleXORBlockCrypt(pass)
|
||||||
|
case "none":
|
||||||
|
block, _ = kcp.NewNoneBlockCrypt(pass)
|
||||||
|
case "aes-128":
|
||||||
|
block, _ = kcp.NewAESBlockCrypt(pass[:16])
|
||||||
|
case "aes-192":
|
||||||
|
block, _ = kcp.NewAESBlockCrypt(pass[:24])
|
||||||
|
case "blowfish":
|
||||||
|
block, _ = kcp.NewBlowfishBlockCrypt(pass)
|
||||||
|
case "twofish":
|
||||||
|
block, _ = kcp.NewTwofishBlockCrypt(pass)
|
||||||
|
case "cast5":
|
||||||
|
block, _ = kcp.NewCast5BlockCrypt(pass[:16])
|
||||||
|
case "3des":
|
||||||
|
block, _ = kcp.NewTripleDESBlockCrypt(pass[:24])
|
||||||
|
case "xtea":
|
||||||
|
block, _ = kcp.NewXTEABlockCrypt(pass[:16])
|
||||||
|
case "salsa20":
|
||||||
|
block, _ = kcp.NewSalsa20BlockCrypt(pass)
|
||||||
|
case "aes":
|
||||||
|
fallthrough
|
||||||
|
default: // aes
|
||||||
|
block, _ = kcp.NewAESBlockCrypt(pass)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func snmpLogger(format string, interval int) {
|
||||||
|
if format == "" || interval == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ticker := time.NewTicker(time.Duration(interval) * time.Second)
|
||||||
|
defer ticker.Stop()
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case <-ticker.C:
|
||||||
|
f, err := os.OpenFile(time.Now().Format(format), os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
|
||||||
|
if err != nil {
|
||||||
|
log.Log("[kcp]", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
w := csv.NewWriter(f)
|
||||||
|
// write header in empty file
|
||||||
|
if stat, err := f.Stat(); err == nil && stat.Size() == 0 {
|
||||||
|
if err := w.Write(append([]string{"Unix"}, kcp.DefaultSnmp.Header()...)); err != nil {
|
||||||
|
log.Log("[kcp]", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if err := w.Write(append([]string{fmt.Sprint(time.Now().Unix())}, kcp.DefaultSnmp.ToSlice()...)); err != nil {
|
||||||
|
log.Log("[kcp]", err)
|
||||||
|
}
|
||||||
|
kcp.DefaultSnmp.Reset()
|
||||||
|
w.Flush()
|
||||||
|
f.Close()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type compStreamConn struct {
|
||||||
|
conn net.Conn
|
||||||
|
w *snappy.Writer
|
||||||
|
r *snappy.Reader
|
||||||
|
}
|
||||||
|
|
||||||
|
func newCompStreamConn(conn net.Conn) *compStreamConn {
|
||||||
|
c := new(compStreamConn)
|
||||||
|
c.conn = conn
|
||||||
|
c.w = snappy.NewBufferedWriter(conn)
|
||||||
|
c.r = snappy.NewReader(conn)
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *compStreamConn) Read(b []byte) (n int, err error) {
|
||||||
|
return c.r.Read(b)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *compStreamConn) Write(b []byte) (n int, err error) {
|
||||||
|
n, err = c.w.Write(b)
|
||||||
|
err = c.w.Flush()
|
||||||
|
return n, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *compStreamConn) Close() error {
|
||||||
|
return c.conn.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *compStreamConn) LocalAddr() net.Addr {
|
||||||
|
return c.conn.LocalAddr()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *compStreamConn) RemoteAddr() net.Addr {
|
||||||
|
return c.conn.RemoteAddr()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *compStreamConn) SetDeadline(t time.Time) error {
|
||||||
|
return c.conn.SetDeadline(t)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *compStreamConn) SetReadDeadline(t time.Time) error {
|
||||||
|
return c.conn.SetReadDeadline(t)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *compStreamConn) SetWriteDeadline(t time.Time) error {
|
||||||
|
return c.conn.SetWriteDeadline(t)
|
||||||
|
}
|
@ -1,6 +1,6 @@
|
|||||||
package gost
|
package gost
|
||||||
|
|
||||||
// Node is a proxy node, mainly used to construct a proxy chain
|
// Node is a proxy node, mainly used to construct a proxy chain.
|
||||||
type Node struct {
|
type Node struct {
|
||||||
Addr string
|
Addr string
|
||||||
Protocol string
|
Protocol string
|
||||||
|
@ -14,7 +14,7 @@ type Server struct {
|
|||||||
handler Handler
|
handler Handler
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle sets a handler for the server
|
// Handle sets a handler for the server.
|
||||||
func (s *Server) Handle(h Handler) {
|
func (s *Server) Handle(h Handler) {
|
||||||
s.handler = h
|
s.handler = h
|
||||||
}
|
}
|
||||||
@ -57,6 +57,7 @@ type tcpListener struct {
|
|||||||
net.Listener
|
net.Listener
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TCPListener creates a Listener for TCP proxy server.
|
||||||
func TCPListener(addr string) (Listener, error) {
|
func TCPListener(addr string) (Listener, error) {
|
||||||
ln, err := net.Listen("tcp", addr)
|
ln, err := net.Listen("tcp", addr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
5
gost/signal.go
Normal file
5
gost/signal.go
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
// +build windows
|
||||||
|
|
||||||
|
package gost
|
||||||
|
|
||||||
|
func kcpSigHandler() {}
|
24
gost/signal_unix.go
Normal file
24
gost/signal_unix.go
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
// +build !windows
|
||||||
|
|
||||||
|
package gost
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"os/signal"
|
||||||
|
"syscall"
|
||||||
|
|
||||||
|
"github.com/go-log/log"
|
||||||
|
"gopkg.in/xtaci/kcp-go.v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
func kcpSigHandler() {
|
||||||
|
ch := make(chan os.Signal, 1)
|
||||||
|
signal.Notify(ch, syscall.SIGUSR1)
|
||||||
|
|
||||||
|
for {
|
||||||
|
switch <-ch {
|
||||||
|
case syscall.SIGUSR1:
|
||||||
|
log.Logf("[kcp] SNMP: %+v", kcp.DefaultSnmp.Copy())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -18,12 +18,15 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
MethodTLS uint8 = 0x80 // extended method for tls
|
// MethodTLS is an extended SOCKS5 method for TLS.
|
||||||
MethodTLSAuth uint8 = 0x82 // extended method for tls+auth
|
MethodTLS uint8 = 0x80
|
||||||
|
// MethodTLSAuth is an extended SOCKS5 method for TLS+AUTH.
|
||||||
|
MethodTLSAuth uint8 = 0x82
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
CmdUdpTun uint8 = 0xF3 // extended method for udp over tcp
|
// CmdUDPTun is an extended SOCKS5 method for UDP over TCP.
|
||||||
|
CmdUDPTun uint8 = 0xF3
|
||||||
)
|
)
|
||||||
|
|
||||||
type clientSelector struct {
|
type clientSelector struct {
|
||||||
@ -189,6 +192,8 @@ type socks5Connector struct {
|
|||||||
User *url.Userinfo
|
User *url.Userinfo
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SOCKS5Connector creates a connector for SOCKS5 proxy client.
|
||||||
|
// It accepts an optional auth info for SOCKS5 Username/Password Authentication.
|
||||||
func SOCKS5Connector(user *url.Userinfo) Connector {
|
func SOCKS5Connector(user *url.Userinfo) Connector {
|
||||||
return &socks5Connector{User: user}
|
return &socks5Connector{User: user}
|
||||||
}
|
}
|
||||||
@ -246,6 +251,7 @@ func (c *socks5Connector) Connect(conn net.Conn, addr string) (net.Conn, error)
|
|||||||
|
|
||||||
type socks4Connector struct{}
|
type socks4Connector struct{}
|
||||||
|
|
||||||
|
// SOCKS4Connector creates a Connector for SOCKS4 proxy client.
|
||||||
func SOCKS4Connector() Connector {
|
func SOCKS4Connector() Connector {
|
||||||
return &socks4Connector{}
|
return &socks4Connector{}
|
||||||
}
|
}
|
||||||
@ -289,6 +295,7 @@ func (c *socks4Connector) Connect(conn net.Conn, addr string) (net.Conn, error)
|
|||||||
|
|
||||||
type socks4aConnector struct{}
|
type socks4aConnector struct{}
|
||||||
|
|
||||||
|
// SOCKS4AConnector creates a Connector for SOCKS4A proxy client.
|
||||||
func SOCKS4AConnector() Connector {
|
func SOCKS4AConnector() Connector {
|
||||||
return &socks4aConnector{}
|
return &socks4aConnector{}
|
||||||
}
|
}
|
||||||
@ -331,7 +338,7 @@ type socks5Handler struct {
|
|||||||
options *HandlerOptions
|
options *HandlerOptions
|
||||||
}
|
}
|
||||||
|
|
||||||
// SOCKS5Handler returns a SOCKS5 server handler
|
// SOCKS5Handler creates a server Handler for SOCKS5 proxy server.
|
||||||
func SOCKS5Handler(opts ...HandlerOption) Handler {
|
func SOCKS5Handler(opts ...HandlerOption) Handler {
|
||||||
options := &HandlerOptions{
|
options := &HandlerOptions{
|
||||||
Chain: new(Chain),
|
Chain: new(Chain),
|
||||||
@ -381,7 +388,7 @@ func (h *socks5Handler) Handle(conn net.Conn) {
|
|||||||
log.Logf("[socks5-udp] %s - %s", conn.RemoteAddr(), req.Addr)
|
log.Logf("[socks5-udp] %s - %s", conn.RemoteAddr(), req.Addr)
|
||||||
h.handleUDPRelay(conn, req)
|
h.handleUDPRelay(conn, req)
|
||||||
|
|
||||||
case CmdUdpTun:
|
case CmdUDPTun:
|
||||||
log.Logf("[socks5-rudp] %s - %s", conn.RemoteAddr(), req.Addr)
|
log.Logf("[socks5-rudp] %s - %s", conn.RemoteAddr(), req.Addr)
|
||||||
h.handleUDPTunnel(conn, req)
|
h.handleUDPTunnel(conn, req)
|
||||||
|
|
||||||
@ -613,7 +620,7 @@ func (h *socks5Handler) handleUDPRelay(conn net.Conn, req *gosocks5.Request) {
|
|||||||
defer cc.Close()
|
defer cc.Close()
|
||||||
|
|
||||||
cc.SetWriteDeadline(time.Now().Add(WriteTimeout))
|
cc.SetWriteDeadline(time.Now().Add(WriteTimeout))
|
||||||
r := gosocks5.NewRequest(CmdUdpTun, nil)
|
r := gosocks5.NewRequest(CmdUDPTun, nil)
|
||||||
if err := r.Write(cc); err != nil {
|
if err := r.Write(cc); err != nil {
|
||||||
log.Logf("[socks5-udp] %s -> %s : %s", conn.RemoteAddr(), cc.RemoteAddr(), err)
|
log.Logf("[socks5-udp] %s -> %s : %s", conn.RemoteAddr(), cc.RemoteAddr(), err)
|
||||||
return
|
return
|
||||||
@ -647,8 +654,8 @@ func (h *socks5Handler) handleUDPRelay(conn net.Conn, req *gosocks5.Request) {
|
|||||||
log.Logf("[socks5-udp] %s >-< %s", conn.RemoteAddr(), socksAddr)
|
log.Logf("[socks5-udp] %s >-< %s", conn.RemoteAddr(), socksAddr)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *socks5Handler) discardClientData(conn net.Conn) (err error) {
|
func (h *socks5Handler) discardClientData(conn net.Conn) (err error) {
|
||||||
b := make([]byte, TinyBufferSize)
|
b := make([]byte, tinyBufferSize)
|
||||||
n := 0
|
n := 0
|
||||||
for {
|
for {
|
||||||
n, err = conn.Read(b) // discard any data from tcp connection
|
n, err = conn.Read(b) // discard any data from tcp connection
|
||||||
@ -663,13 +670,13 @@ func (s *socks5Handler) discardClientData(conn net.Conn) (err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *socks5Handler) transportUDP(relay, peer *net.UDPConn) (err error) {
|
func (h *socks5Handler) transportUDP(relay, peer *net.UDPConn) (err error) {
|
||||||
errc := make(chan error, 2)
|
errc := make(chan error, 2)
|
||||||
|
|
||||||
var clientAddr *net.UDPAddr
|
var clientAddr *net.UDPAddr
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
b := make([]byte, LargeBufferSize)
|
b := make([]byte, largeBufferSize)
|
||||||
|
|
||||||
for {
|
for {
|
||||||
n, laddr, err := relay.ReadFromUDP(b)
|
n, laddr, err := relay.ReadFromUDP(b)
|
||||||
@ -701,7 +708,7 @@ func (s *socks5Handler) transportUDP(relay, peer *net.UDPConn) (err error) {
|
|||||||
}()
|
}()
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
b := make([]byte, LargeBufferSize)
|
b := make([]byte, largeBufferSize)
|
||||||
|
|
||||||
for {
|
for {
|
||||||
n, raddr, err := peer.ReadFromUDP(b)
|
n, raddr, err := peer.ReadFromUDP(b)
|
||||||
@ -739,7 +746,7 @@ func (h *socks5Handler) tunnelClientUDP(uc *net.UDPConn, cc net.Conn) (err error
|
|||||||
var clientAddr *net.UDPAddr
|
var clientAddr *net.UDPAddr
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
b := make([]byte, LargeBufferSize)
|
b := make([]byte, largeBufferSize)
|
||||||
|
|
||||||
for {
|
for {
|
||||||
n, addr, err := uc.ReadFromUDP(b)
|
n, addr, err := uc.ReadFromUDP(b)
|
||||||
@ -864,7 +871,7 @@ func (h *socks5Handler) tunnelServerUDP(cc net.Conn, uc *net.UDPConn) (err error
|
|||||||
errc := make(chan error, 2)
|
errc := make(chan error, 2)
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
b := make([]byte, LargeBufferSize)
|
b := make([]byte, largeBufferSize)
|
||||||
|
|
||||||
for {
|
for {
|
||||||
n, addr, err := uc.ReadFromUDP(b)
|
n, addr, err := uc.ReadFromUDP(b)
|
||||||
@ -939,7 +946,7 @@ type socks4Handler struct {
|
|||||||
options *HandlerOptions
|
options *HandlerOptions
|
||||||
}
|
}
|
||||||
|
|
||||||
// SOCKS4Handler returns a SOCKS4 server handler
|
// SOCKS4Handler creates a server Handler for SOCKS4(A) proxy server.
|
||||||
func SOCKS4Handler(opts ...HandlerOption) Handler {
|
func SOCKS4Handler(opts ...HandlerOption) Handler {
|
||||||
options := &HandlerOptions{
|
options := &HandlerOptions{
|
||||||
Chain: new(Chain),
|
Chain: new(Chain),
|
||||||
|
@ -30,6 +30,8 @@ func main() {
|
|||||||
go wsServer(&wg)
|
go wsServer(&wg)
|
||||||
wg.Add(1)
|
wg.Add(1)
|
||||||
go wssServer(&wg)
|
go wssServer(&wg)
|
||||||
|
wg.Add(1)
|
||||||
|
go kcpServer(&wg)
|
||||||
wg.Wait()
|
wg.Wait()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -131,3 +133,15 @@ func wssServer(wg *sync.WaitGroup) {
|
|||||||
}
|
}
|
||||||
log.Fatal(s.Serve(ln))
|
log.Fatal(s.Serve(ln))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func kcpServer(wg *sync.WaitGroup) {
|
||||||
|
defer wg.Done()
|
||||||
|
|
||||||
|
s := &gost.Server{}
|
||||||
|
s.Handle(gost.HTTPHandler())
|
||||||
|
ln, err := gost.KCPListener(":8388", nil)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
log.Fatal(s.Serve(ln))
|
||||||
|
}
|
||||||
|
@ -14,7 +14,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// Due to in/out byte length is inconsistent of the shadowsocks.Conn.Write,
|
// Due to in/out byte length is inconsistent of the shadowsocks.Conn.Write,
|
||||||
// we wrap around it to make io.Copy happy
|
// we wrap around it to make io.Copy happy.
|
||||||
type shadowConn struct {
|
type shadowConn struct {
|
||||||
conn net.Conn
|
conn net.Conn
|
||||||
}
|
}
|
||||||
@ -57,6 +57,9 @@ type shadowConnector struct {
|
|||||||
Cipher *url.Userinfo
|
Cipher *url.Userinfo
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ShadowConnector creates a Connector for shadowsocks proxy client.
|
||||||
|
// It accepts a cipher info for shadowsocks data encryption/decryption.
|
||||||
|
// The cipher must not be nil.
|
||||||
func ShadowConnector(cipher *url.Userinfo) Connector {
|
func ShadowConnector(cipher *url.Userinfo) Connector {
|
||||||
return &shadowConnector{Cipher: cipher}
|
return &shadowConnector{Cipher: cipher}
|
||||||
}
|
}
|
||||||
@ -89,6 +92,7 @@ type shadowHandler struct {
|
|||||||
options *HandlerOptions
|
options *HandlerOptions
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ShadowHandler creates a server Handler for shadowsocks proxy server.
|
||||||
func ShadowHandler(opts ...HandlerOption) Handler {
|
func ShadowHandler(opts ...HandlerOption) Handler {
|
||||||
h := &shadowHandler{
|
h := &shadowHandler{
|
||||||
options: &HandlerOptions{
|
options: &HandlerOptions{
|
||||||
@ -158,7 +162,7 @@ func (h *shadowHandler) getRequest(conn net.Conn) (host string, err error) {
|
|||||||
// buf size should at least have the same size with the largest possible
|
// buf size should at least have the same size with the largest possible
|
||||||
// request size (when addrType is 3, domain name has at most 256 bytes)
|
// request size (when addrType is 3, domain name has at most 256 bytes)
|
||||||
// 1(addrType) + 1(lenByte) + 256(max length address) + 2(port)
|
// 1(addrType) + 1(lenByte) + 256(max length address) + 2(port)
|
||||||
buf := make([]byte, SmallBufferSize)
|
buf := make([]byte, smallBufferSize)
|
||||||
|
|
||||||
// read till we get possible domain length field
|
// read till we get possible domain length field
|
||||||
conn.SetReadDeadline(time.Now().Add(30 * time.Second))
|
conn.SetReadDeadline(time.Now().Add(30 * time.Second))
|
||||||
|
@ -9,12 +9,14 @@ type tlsTransporter struct {
|
|||||||
TLSClientConfig *tls.Config
|
TLSClientConfig *tls.Config
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TLSTransporter creates a Transporter that is used by TLS proxy client.
|
||||||
|
// It accepts a TLS config for TLS handshake.
|
||||||
func TLSTransporter(cfg *tls.Config) Transporter {
|
func TLSTransporter(cfg *tls.Config) Transporter {
|
||||||
return &tlsTransporter{TLSClientConfig: cfg}
|
return &tlsTransporter{TLSClientConfig: cfg}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tr *tlsTransporter) Network() string {
|
func (tr *tlsTransporter) Dial(addr string) (net.Conn, error) {
|
||||||
return "tcp"
|
return net.Dial("tcp", addr)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tr *tlsTransporter) Handshake(conn net.Conn) (net.Conn, error) {
|
func (tr *tlsTransporter) Handshake(conn net.Conn) (net.Conn, error) {
|
||||||
@ -25,6 +27,7 @@ type tlsListener struct {
|
|||||||
net.Listener
|
net.Listener
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TLSListener creates a Listener for TLS proxy server.
|
||||||
func TLSListener(addr string, config *tls.Config) (Listener, error) {
|
func TLSListener(addr string, config *tls.Config) (Listener, error) {
|
||||||
ln, err := tls.Listen("tcp", addr, config)
|
ln, err := tls.Listen("tcp", addr, config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
30
gost/ws.go
30
gost/ws.go
@ -13,6 +13,7 @@ import (
|
|||||||
"gopkg.in/gorilla/websocket.v1"
|
"gopkg.in/gorilla/websocket.v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// WSOptions describes the options for websocket.
|
||||||
type WSOptions struct {
|
type WSOptions struct {
|
||||||
ReadBufferSize int
|
ReadBufferSize int
|
||||||
WriteBufferSize int
|
WriteBufferSize int
|
||||||
@ -82,11 +83,11 @@ func (c *websocketConn) RemoteAddr() net.Addr {
|
|||||||
return c.conn.RemoteAddr()
|
return c.conn.RemoteAddr()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (conn *websocketConn) SetDeadline(t time.Time) error {
|
func (c *websocketConn) SetDeadline(t time.Time) error {
|
||||||
if err := conn.SetReadDeadline(t); err != nil {
|
if err := c.SetReadDeadline(t); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return conn.SetWriteDeadline(t)
|
return c.SetWriteDeadline(t)
|
||||||
}
|
}
|
||||||
func (c *websocketConn) SetReadDeadline(t time.Time) error {
|
func (c *websocketConn) SetReadDeadline(t time.Time) error {
|
||||||
return c.conn.SetReadDeadline(t)
|
return c.conn.SetReadDeadline(t)
|
||||||
@ -101,6 +102,7 @@ type wsTransporter struct {
|
|||||||
options *WSOptions
|
options *WSOptions
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// WSTransporter creates a Transporter that is used by websocket proxy client.
|
||||||
func WSTransporter(addr string, opts *WSOptions) Transporter {
|
func WSTransporter(addr string, opts *WSOptions) Transporter {
|
||||||
return &wsTransporter{
|
return &wsTransporter{
|
||||||
addr: addr,
|
addr: addr,
|
||||||
@ -108,8 +110,9 @@ func WSTransporter(addr string, opts *WSOptions) Transporter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tr *wsTransporter) Network() string {
|
func (tr *wsTransporter) Dial(addr string) (net.Conn, error) {
|
||||||
return "tcp"
|
tr.addr = addr // NOTE: the addr must match the initial tr.addr
|
||||||
|
return net.Dial("tcp", addr)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tr *wsTransporter) Handshake(conn net.Conn) (net.Conn, error) {
|
func (tr *wsTransporter) Handshake(conn net.Conn) (net.Conn, error) {
|
||||||
@ -122,6 +125,7 @@ type wssTransporter struct {
|
|||||||
options *WSOptions
|
options *WSOptions
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// WSSTransporter creates a Transporter that is used by websocket secure proxy client.
|
||||||
func WSSTransporter(addr string, opts *WSOptions) Transporter {
|
func WSSTransporter(addr string, opts *WSOptions) Transporter {
|
||||||
return &wssTransporter{
|
return &wssTransporter{
|
||||||
addr: addr,
|
addr: addr,
|
||||||
@ -129,8 +133,8 @@ func WSSTransporter(addr string, opts *WSOptions) Transporter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tr *wssTransporter) Network() string {
|
func (tr *wssTransporter) Dial(addr string) (net.Conn, error) {
|
||||||
return "tcp"
|
return net.Dial("tcp", addr)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tr *wssTransporter) Handshake(conn net.Conn) (net.Conn, error) {
|
func (tr *wssTransporter) Handshake(conn net.Conn) (net.Conn, error) {
|
||||||
@ -146,6 +150,7 @@ type wsListener struct {
|
|||||||
errChan chan error
|
errChan chan error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// WSListener creates a Listener for websocket proxy server.
|
||||||
func WSListener(addr string, options *WSOptions) (Listener, error) {
|
func WSListener(addr string, options *WSOptions) (Listener, error) {
|
||||||
tcpAddr, err := net.ResolveTCPAddr("tcp", addr)
|
tcpAddr, err := net.ResolveTCPAddr("tcp", addr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -162,7 +167,7 @@ func WSListener(addr string, options *WSOptions) (Listener, error) {
|
|||||||
CheckOrigin: func(r *http.Request) bool { return true },
|
CheckOrigin: func(r *http.Request) bool { return true },
|
||||||
EnableCompression: options.EnableCompression,
|
EnableCompression: options.EnableCompression,
|
||||||
},
|
},
|
||||||
connChan: make(chan net.Conn, 32),
|
connChan: make(chan net.Conn, 128),
|
||||||
errChan: make(chan error, 1),
|
errChan: make(chan error, 1),
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -202,7 +207,11 @@ func (l *wsListener) upgrade(w http.ResponseWriter, r *http.Request) {
|
|||||||
log.Logf("[ws] %s - %s : %s", r.RemoteAddr, l.addr, err)
|
log.Logf("[ws] %s - %s : %s", r.RemoteAddr, l.addr, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
l.connChan <- websocketServerConn(conn)
|
select {
|
||||||
|
case l.connChan <- websocketServerConn(conn):
|
||||||
|
default:
|
||||||
|
log.Logf("[ws] %s - %s: connection queue is full", r.RemoteAddr, l.addr)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *wsListener) Accept() (conn net.Conn, err error) {
|
func (l *wsListener) Accept() (conn net.Conn, err error) {
|
||||||
@ -225,6 +234,7 @@ type wssListener struct {
|
|||||||
*wsListener
|
*wsListener
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// WSSListener creates a Listener for websocket secure proxy server.
|
||||||
func WSSListener(addr string, options *WSOptions) (Listener, error) {
|
func WSSListener(addr string, options *WSOptions) (Listener, error) {
|
||||||
tcpAddr, err := net.ResolveTCPAddr("tcp", addr)
|
tcpAddr, err := net.ResolveTCPAddr("tcp", addr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -242,7 +252,7 @@ func WSSListener(addr string, options *WSOptions) (Listener, error) {
|
|||||||
CheckOrigin: func(r *http.Request) bool { return true },
|
CheckOrigin: func(r *http.Request) bool { return true },
|
||||||
EnableCompression: options.EnableCompression,
|
EnableCompression: options.EnableCompression,
|
||||||
},
|
},
|
||||||
connChan: make(chan net.Conn, 32),
|
connChan: make(chan net.Conn, 128),
|
||||||
errChan: make(chan error, 1),
|
errChan: make(chan error, 1),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user