Commit 9b2bd7a8 authored by rui.zheng's avatar rui.zheng

add KCP support

parent 684ccca2
......@@ -6,7 +6,7 @@ import (
)
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")
)
......
......@@ -5,7 +5,6 @@ import (
"log"
"net/http"
"net/http/httputil"
"net/url"
"github.com/ginuerzh/gost/gost"
)
......@@ -28,61 +27,72 @@ func main() {
},
*/
// socks5+tcp
gost.Node{
Addr: "127.0.0.1:1080",
Client: gost.NewClient(
gost.SOCKS5Connector(url.UserPassword("admin", "123456")),
gost.TCPTransporter(),
),
},
/*
// socks5+tcp
gost.Node{
Addr: "127.0.0.1:1080",
Client: gost.NewClient(
gost.SOCKS5Connector(url.UserPassword("admin", "123456")),
gost.TCPTransporter(),
),
},
*/
/*
// ss+tcp
gost.Node{
Addr: "127.0.0.1:8338",
Client: gost.NewClient(
gost.ShadowConnector(url.UserPassword("chacha20", "123456")),
gost.TCPTransporter(),
),
},
*/
/*
// ss+tcp
gost.Node{
Addr: "127.0.0.1:8338",
Client: gost.NewClient(
gost.ShadowConnector(url.UserPassword("chacha20", "123456")),
gost.TCPTransporter(),
),
},
*/
/*
// http+ws
gost.Node{
Addr: "127.0.0.1:8000",
Client: gost.NewClient(
gost.HTTPConnector(url.UserPassword("admin", "123456")),
gost.WSTransporter("127.0.0.1:8000", nil),
),
},
*/
/*
// http+ws
gost.Node{
Addr: "127.0.0.1:8000",
Client: gost.NewClient(
gost.HTTPConnector(url.UserPassword("admin", "123456")),
gost.WSTransporter("127.0.0.1:8000", nil),
),
},
*/
/*
// http+wss
gost.Node{
Addr: "127.0.0.1:8443",
Client: gost.NewClient(
gost.HTTPConnector(url.UserPassword("admin", "123456")),
gost.WSSTransporter(
"127.0.0.1:8443",
&gost.WSOptions{TLSConfig: &tls.Config{InsecureSkipVerify: true}},
/*
// http+wss
gost.Node{
Addr: "127.0.0.1:8443",
Client: gost.NewClient(
gost.HTTPConnector(url.UserPassword("admin", "123456")),
gost.WSSTransporter(
"127.0.0.1:8443",
&gost.WSOptions{TLSConfig: &tls.Config{InsecureSkipVerify: true}},
),
),
),
},
*/
},
*/
/*
// http+tls
gost.Node{
Addr: "127.0.0.1:1443",
Client: gost.NewClient(
gost.HTTPConnector(url.UserPassword("admin", "123456")),
gost.TLSTransporter(&tls.Config{InsecureSkipVerify: true}),
),
},
*/
/*
// http+tls
// http+kcp
gost.Node{
Addr: "127.0.0.1:1443",
Addr: "127.0.0.1:8388",
Client: gost.NewClient(
gost.HTTPConnector(url.UserPassword("admin", "123456")),
gost.TLSTransporter(&tls.Config{InsecureSkipVerify: true}),
gost.HTTPConnector(nil),
gost.KCPTransporter(nil),
),
},
*/
)
conn, err := chain.Dial("localhost:10000")
......
......@@ -5,15 +5,15 @@ import (
)
// 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 {
Connector Connector
Transporter Transporter
}
// 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 {
return &Client{
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) {
return net.Dial(c.Transporter.Network(), addr)
return c.Transporter.Dial(addr)
}
// 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)
}
// DefaultClient is a standard HTTP proxy client
// DefaultClient is a standard HTTP proxy client.
var DefaultClient = NewClient(HTTPConnector(nil), TCPTransporter())
// Dial connects to the address addr via the DefaultClient.
......@@ -46,7 +46,7 @@ func Dial(addr string) (net.Conn, error) {
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) {
return DefaultClient.Handshake(conn)
}
......@@ -56,26 +56,27 @@ func Connect(conn net.Conn, addr string) (net.Conn, error) {
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 {
Connect(conn net.Conn, addr string) (net.Conn, error)
}
// Transporter is responsible for handshaking with the proxy server.
type Transporter interface {
Network() string
Dial(addr string) (net.Conn, error)
Handshake(conn net.Conn) (net.Conn, error)
}
type tcpTransporter struct {
}
// TCPTransporter creates a transporter for TCP proxy client.
func TCPTransporter() Transporter {
return &tcpTransporter{}
}
func (tr *tcpTransporter) Network() string {
return "tcp"
func (tr *tcpTransporter) Dial(addr string) (net.Conn, error) {
return net.Dial("tcp", addr)
}
func (tr *tcpTransporter) Handshake(conn net.Conn) (net.Conn, error) {
......
......@@ -6,24 +6,30 @@ import (
"github.com/go-log/log"
)
// Version is the gost version.
const Version = "2.4-dev20170722"
// Debug is a flag that enables the debug log.
var Debug bool
var (
TinyBufferSize = 128
SmallBufferSize = 1 * 1024 // 1KB small buffer
MediumBufferSize = 8 * 1024 // 8KB medium buffer
LargeBufferSize = 32 * 1024 // 32KB large buffer
tinyBufferSize = 128
smallBufferSize = 1 * 1024 // 1KB small buffer
mediumBufferSize = 8 * 1024 // 8KB medium buffer
largeBufferSize = 32 * 1024 // 32KB large buffer
)
var (
// KeepAliveTime is the keep alive time period for TCP connection.
KeepAliveTime = 180 * time.Second
DialTimeout = 30 * time.Second
ReadTimeout = 90 * time.Second
WriteTimeout = 90 * time.Second
DefaultTTL = 60 // default udp node TTL in second for udp port forwarding
// DialTimeout is the timeout of dial.
DialTimeout = 30 * time.Second
// ReadTimeout is the timeout for reading.
ReadTimeout = 90 * time.Second
// WriteTimeout is the timeout for writing.
WriteTimeout = 90 * time.Second
// default udp node TTL in second for udp port forwarding.
defaultTTL = 60
)
func init() {
......
......@@ -6,30 +6,36 @@ import (
"net/url"
)
// Handler is a proxy server handler
type Handler interface {
Handle(net.Conn)
}
// HandlerOptions describes the options for Handler.
type HandlerOptions struct {
Chain *Chain
Users []*url.Userinfo
TLSConfig *tls.Config
}
// HandlerOption allows a common way to set handler options.
type HandlerOption func(opts *HandlerOptions)
// ChainHandlerOption sets the Chain option of HandlerOptions.
func ChainHandlerOption(chain *Chain) HandlerOption {
return func(opts *HandlerOptions) {
opts.Chain = chain
}
}
// UsersHandlerOption sets the Users option of HandlerOptions.
func UsersHandlerOption(users ...*url.Userinfo) HandlerOption {
return func(opts *HandlerOptions) {
opts.Users = users
}
}
// TLSConfigHandlerOption sets the TLSConfig option of HandlerOptions.
func TLSConfigHandlerOption(config *tls.Config) HandlerOption {
return func(opts *HandlerOptions) {
opts.TLSConfig = config
......
......@@ -17,6 +17,8 @@ type httpConnector struct {
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 {
return &httpConnector{User: user}
}
......@@ -71,6 +73,7 @@ type httpHandler struct {
options *HandlerOptions
}
// HTTPHandler creates a server Handler for HTTP proxy server.
func HTTPHandler(opts ...HandlerOption) Handler {
h := &httpHandler{
options: &HandlerOptions{
......
This diff is collapsed.
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 {
Addr string
Protocol string
......
......@@ -14,7 +14,7 @@ type Server struct {
handler Handler
}
// Handle sets a handler for the server
// Handle sets a handler for the server.
func (s *Server) Handle(h Handler) {
s.handler = h
}
......@@ -57,6 +57,7 @@ type tcpListener struct {
net.Listener
}
// TCPListener creates a Listener for TCP proxy server.
func TCPListener(addr string) (Listener, error) {
ln, err := net.Listen("tcp", addr)
if err != nil {
......
// +build windows
package gost
func kcpSigHandler() {}
// +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 (
MethodTLS uint8 = 0x80 // extended method for tls
MethodTLSAuth uint8 = 0x82 // extended method for tls+auth
// MethodTLS is an extended SOCKS5 method for TLS.
MethodTLS uint8 = 0x80
// MethodTLSAuth is an extended SOCKS5 method for TLS+AUTH.
MethodTLSAuth uint8 = 0x82
)
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 {
......@@ -189,6 +192,8 @@ type socks5Connector struct {
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 {
return &socks5Connector{User: user}
}
......@@ -246,6 +251,7 @@ func (c *socks5Connector) Connect(conn net.Conn, addr string) (net.Conn, error)
type socks4Connector struct{}
// SOCKS4Connector creates a Connector for SOCKS4 proxy client.
func SOCKS4Connector() Connector {
return &socks4Connector{}
}
......@@ -289,6 +295,7 @@ func (c *socks4Connector) Connect(conn net.Conn, addr string) (net.Conn, error)
type socks4aConnector struct{}
// SOCKS4AConnector creates a Connector for SOCKS4A proxy client.
func SOCKS4AConnector() Connector {
return &socks4aConnector{}
}
......@@ -331,7 +338,7 @@ type socks5Handler struct {
options *HandlerOptions
}
// SOCKS5Handler returns a SOCKS5 server handler
// SOCKS5Handler creates a server Handler for SOCKS5 proxy server.
func SOCKS5Handler(opts ...HandlerOption) Handler {
options := &HandlerOptions{
Chain: new(Chain),
......@@ -381,7 +388,7 @@ func (h *socks5Handler) Handle(conn net.Conn) {
log.Logf("[socks5-udp] %s - %s", conn.RemoteAddr(), req.Addr)
h.handleUDPRelay(conn, req)
case CmdUdpTun:
case CmdUDPTun:
log.Logf("[socks5-rudp] %s - %s", conn.RemoteAddr(), req.Addr)
h.handleUDPTunnel(conn, req)
......@@ -613,7 +620,7 @@ func (h *socks5Handler) handleUDPRelay(conn net.Conn, req *gosocks5.Request) {
defer cc.Close()
cc.SetWriteDeadline(time.Now().Add(WriteTimeout))
r := gosocks5.NewRequest(CmdUdpTun, nil)
r := gosocks5.NewRequest(CmdUDPTun, nil)
if err := r.Write(cc); err != nil {
log.Logf("[socks5-udp] %s -> %s : %s", conn.RemoteAddr(), cc.RemoteAddr(), err)
return
......@@ -647,8 +654,8 @@ func (h *socks5Handler) handleUDPRelay(conn net.Conn, req *gosocks5.Request) {
log.Logf("[socks5-udp] %s >-< %s", conn.RemoteAddr(), socksAddr)
}
func (s *socks5Handler) discardClientData(conn net.Conn) (err error) {
b := make([]byte, TinyBufferSize)
func (h *socks5Handler) discardClientData(conn net.Conn) (err error) {
b := make([]byte, tinyBufferSize)
n := 0
for {
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
}
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)
var clientAddr *net.UDPAddr
go func() {
b := make([]byte, LargeBufferSize)
b := make([]byte, largeBufferSize)
for {
n, laddr, err := relay.ReadFromUDP(b)
......@@ -701,7 +708,7 @@ func (s *socks5Handler) transportUDP(relay, peer *net.UDPConn) (err error) {
}()
go func() {
b := make([]byte, LargeBufferSize)
b := make([]byte, largeBufferSize)
for {
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
go func() {
b := make([]byte, LargeBufferSize)
b := make([]byte, largeBufferSize)
for {
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)
go func() {
b := make([]byte, LargeBufferSize)
b := make([]byte, largeBufferSize)
for {
n, addr, err := uc.ReadFromUDP(b)
......@@ -939,7 +946,7 @@ type socks4Handler struct {
options *HandlerOptions
}
// SOCKS4Handler returns a SOCKS4 server handler
// SOCKS4Handler creates a server Handler for SOCKS4(A) proxy server.
func SOCKS4Handler(opts ...HandlerOption) Handler {
options := &HandlerOptions{
Chain: new(Chain),
......
......@@ -30,6 +30,8 @@ func main() {
go wsServer(&wg)
wg.Add(1)
go wssServer(&wg)
wg.Add(1)
go kcpServer(&wg)
wg.Wait()
}
......@@ -131,3 +133,15 @@ func wssServer(wg *sync.WaitGroup) {
}
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,
// we wrap around it to make io.Copy happy
// we wrap around it to make io.Copy happy.
type shadowConn struct {
conn net.Conn
}
......@@ -57,6 +57,9 @@ type shadowConnector struct {
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 {
return &shadowConnector{Cipher: cipher}
}
......@@ -89,6 +92,7 @@ type shadowHandler struct {
options *HandlerOptions
}
// ShadowHandler creates a server Handler for shadowsocks proxy server.
func ShadowHandler(opts ...HandlerOption) Handler {
h := &shadowHandler{
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
// request size (when addrType is 3, domain name has at most 256 bytes)
// 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
conn.SetReadDeadline(time.Now().Add(30 * time.Second))
......
......@@ -9,12 +9,14 @@ type tlsTransporter struct {
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 {
return &tlsTransporter{TLSClientConfig: cfg}
}
func (tr *tlsTransporter) Network() string {
return "tcp"
func (tr *tlsTransporter) Dial(addr string) (net.Conn, error) {
return net.Dial("tcp", addr)
}
func (tr *tlsTransporter) Handshake(conn net.Conn) (net.Conn, error) {
......@@ -25,6 +27,7 @@ type tlsListener struct {
net.Listener
}
// TLSListener creates a Listener for TLS proxy server.
func TLSListener(addr string, config *tls.Config) (Listener, error) {
ln, err := tls.Listen("tcp", addr, config)
if err != nil {
......
......@@ -13,6 +13,7 @@ import (
"gopkg.in/gorilla/websocket.v1"
)
// WSOptions describes the options for websocket.
type WSOptions struct {
ReadBufferSize int
WriteBufferSize int
......@@ -82,11 +83,11 @@ func (c *websocketConn) RemoteAddr() net.Addr {
return c.conn.RemoteAddr()
}
func (conn *websocketConn) SetDeadline(t time.Time) error {
if err := conn.SetReadDeadline(t); err != nil {
func (c *websocketConn) SetDeadline(t time.Time) error {
if err := c.SetReadDeadline(t); err != nil {
return err
}
return conn.SetWriteDeadline(t)
return c.SetWriteDeadline(t)
}
func (c *websocketConn) SetReadDeadline(t time.Time) error {
return c.conn.SetReadDeadline(t)
......@@ -101,6 +102,7 @@ type wsTransporter struct {
options *WSOptions
}
// WSTransporter creates a Transporter that is used by websocket proxy client.
func WSTransporter(addr string, opts *WSOptions) Transporter {
return &wsTransporter{
addr: addr,
......@@ -108,8 +110,9 @@ func WSTransporter(addr string, opts *WSOptions) Transporter {
}
}
func (tr *wsTransporter) Network() string {
return "tcp"
func (tr *wsTransporter) Dial(addr string) (net.Conn, error) {
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) {
......@@ -122,6 +125,7 @@ type wssTransporter struct {
options *WSOptions
}
// WSSTransporter creates a Transporter that is used by websocket secure proxy client.
func WSSTransporter(addr string, opts *WSOptions) Transporter {
return &wssTransporter{
addr: addr,
......@@ -129,8 +133,8 @@ func WSSTransporter(addr string, opts *WSOptions) Transporter {
}
}
func (tr *wssTransporter) Network() string {
return "tcp"
func (tr *wssTransporter) Dial(addr string) (net.Conn, error) {
return net.Dial("tcp", addr)
}
func (tr *wssTransporter) Handshake(conn net.Conn) (net.Conn, error) {
......@@ -146,6 +150,7 @@ type wsListener struct {
errChan chan error
}
// WSListener creates a Listener for websocket proxy server.
func WSListener(addr string, options *WSOptions) (Listener, error) {
tcpAddr, err := net.ResolveTCPAddr("tcp", addr)
if err != nil {
......@@ -162,7 +167,7 @@ func WSListener(addr string, options *WSOptions) (Listener, error) {
CheckOrigin: func(r *http.Request) bool { return true },
EnableCompression: options.EnableCompression,
},
connChan: make(chan net.Conn, 32),
connChan: make(chan net.Conn, 128),
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)
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) {
......@@ -225,6 +234,7 @@ type wssListener struct {
*wsListener
}
// WSSListener creates a Listener for websocket secure proxy server.
func WSSListener(addr string, options *WSOptions) (Listener, error) {
tcpAddr, err := net.ResolveTCPAddr("tcp", addr)
if err != nil {
......@@ -242,7 +252,7 @@ func WSSListener(addr string, options *WSOptions) (Listener, error) {
CheckOrigin: func(r *http.Request) bool { return true },
EnableCompression: options.EnableCompression,
},
connChan: make(chan net.Conn, 32),
connChan: make(chan net.Conn, 128),
errChan: make(chan error, 1),
},
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment