Commit 684ccca2 authored by rui.zheng's avatar rui.zheng

add socks4/5 server handlers

parent 7402fb24
package gost
import (
"errors"
"net"
)
var (
// ErrEmptyChain is an error that implies the chain is empty
ErrEmptyChain = errors.New("empty chain")
)
// Chain is a proxy chain that holds a list of proxy nodes.
type Chain struct {
Nodes []Node
nodes []Node
}
// NewChain creates a proxy chain with proxy nodes nodes.
func NewChain(nodes ...Node) *Chain {
return &Chain{
Nodes: nodes,
nodes: nodes,
}
}
// Nodes returns the proxy nodes that the chain holds.
func (c *Chain) Nodes() []Node {
return c.nodes
}
// LastNode returns the last node of the node list.
// If the chain is empty, an empty node is returns.
func (c *Chain) LastNode() Node {
if c.IsEmpty() {
return Node{}
}
return c.nodes[len(c.nodes)-1]
}
// AddNode appends the node(s) to the chain.
func (c *Chain) AddNode(nodes ...Node) {
c.nodes = append(c.nodes, nodes...)
}
// IsEmpty checks if the chain is empty.
// An empty chain means that there is no proxy node in the chain.
func (c *Chain) IsEmpty() bool {
return len(c.nodes) == 0
}
// Dial connects to the target address addr through the chain.
// If the chain is empty, it will use the net.Dial directly.
func (c *Chain) Dial(addr string) (net.Conn, error) {
if len(c.Nodes) == 0 {
if c.IsEmpty() {
return net.Dial("tcp", addr)
}
nodes := c.Nodes
conn, err := c.Conn()
if err != nil {
return nil, err
}
cc, err := c.LastNode().Client.Connect(conn, addr)
if err != nil {
conn.Close()
return nil, err
}
return cc, nil
}
// Conn obtains a handshaked connection to the last node of the chain.
// If the chain is empty, it returns an ErrEmptyChain error.
func (c *Chain) Conn() (net.Conn, error) {
if c.IsEmpty() {
return nil, ErrEmptyChain
}
nodes := c.nodes
conn, err := nodes[0].Client.Dial(nodes[0].Addr)
if err != nil {
return nil, err
......@@ -46,14 +101,7 @@ func (c *Chain) Dial(addr string) (net.Conn, error) {
conn.Close()
return nil, err
}
conn = cc
}
cc, err := nodes[len(nodes)-1].Client.Connect( conn, addr)
if err != nil {
conn.Close()
return nil, err
}
return cc, nil
return conn, nil
}
......@@ -2,11 +2,9 @@ package main
import (
"bufio"
"crypto/tls"
"log"
"net/http"
"net/http/httputil"
"net/url"
"github.com/ginuerzh/gost/gost"
......@@ -20,60 +18,73 @@ func init() {
func main() {
chain := gost.NewChain(
/*
// http+ws
// http+tcp
gost.Node{
Addr: "127.0.0.1:8000",
Addr: "127.0.0.1:8080",
Client: gost.NewClient(
gost.HTTPConnector(url.UserPassword("admin", "123456")),
gost.WSTransporter("127.0.0.1:8000", nil),
gost.TCPTransporter(),
),
},
*/
// http+wss
// socks5+tcp
gost.Node{
Addr: "127.0.0.1:8443",
Addr: "127.0.0.1:1080",
Client: gost.NewClient(
gost.HTTPConnector(url.UserPassword("admin", "123456")),
gost.WSSTransporter(
"127.0.0.1:8443",
&gost.WSOptions{TLSConfig: &tls.Config{InsecureSkipVerify: true}},
),
gost.SOCKS5Connector(url.UserPassword("admin", "123456")),
gost.TCPTransporter(),
),
},
/*
// http+tcp
// ss+tcp
gost.Node{
Addr: "127.0.0.1:1080",
Addr: "127.0.0.1:8338",
Client: gost.NewClient(
gost.HTTPConnector(url.UserPassword("admin", "123456")),
gost.ShadowConnector(url.UserPassword("chacha20", "123456")),
gost.TCPTransporter(),
),
},
*/
/*
// http+tls
// http+ws
gost.Node{
Addr: "127.0.0.1:1443",
Addr: "127.0.0.1:8000",
Client: gost.NewClient(
gost.HTTPConnector(url.UserPassword("admin", "123456")),
gost.TLSTransporter(&tls.Config{InsecureSkipVerify: true}),
gost.WSTransporter("127.0.0.1:8000", nil),
),
},
*/
/*
// ss+tcp
// http+wss
gost.Node{
Addr: "127.0.0.1:8338",
Addr: "127.0.0.1:8443",
Client: gost.NewClient(
gost.ShadowConnector(url.UserPassword("chacha20", "123456")),
gost.TCPTransporter(),
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}),
),
},
*/
)
conn, err := chain.Dial("localhost:10000")
if err != nil {
log.Fatal(err)
......
......@@ -4,11 +4,16 @@ import (
"net"
)
// Client is a proxy client.
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,10 +26,14 @@ func (c *Client) Dial(addr string) (net.Conn, error) {
return net.Dial(c.Transporter.Network(), addr)
}
// Handshake performs a handshake with the proxy.
// The conn should be an connection to this proxy.
func (c *Client) Handshake(conn net.Conn) (net.Conn, error) {
return c.Transporter.Handshake(conn)
}
// Connect connects to the address addr via the proxy.
// The conn should be an connection to this proxy.
func (c *Client) Connect(conn net.Conn, addr string) (net.Conn, error) {
return c.Connector.Connect(conn, addr)
}
......@@ -32,22 +41,27 @@ func (c *Client) Connect(conn net.Conn, addr string) (net.Conn, error) {
// DefaultClient is a standard HTTP proxy client
var DefaultClient = NewClient(HTTPConnector(nil), TCPTransporter())
// Dial connects to the address addr via the DefaultClient.
func Dial(addr string) (net.Conn, error) {
return DefaultClient.Dial(addr)
}
// Handshake performs a handshake via the DefaultClient
func Handshake(conn net.Conn) (net.Conn, error) {
return DefaultClient.Handshake(conn)
}
// Connect connects to the address addr via the DefaultClient.
func Connect(conn net.Conn, addr string) (net.Conn, error) {
return DefaultClient.Connect(conn, addr)
}
// 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
Handshake(conn net.Conn) (net.Conn, error)
......
package gost
import (
"time"
"github.com/go-log/log"
)
......@@ -9,11 +11,21 @@ const Version = "2.4-dev20170722"
var Debug bool
var (
TinyBufferSize = 128
SmallBufferSize = 1 * 1024 // 1KB small buffer
MediumBufferSize = 8 * 1024 // 8KB medium buffer
LargeBufferSize = 32 * 1024 // 32KB large buffer
)
var (
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
)
func init() {
log.DefaultLogger = &logger{}
}
package gost
import (
"crypto/tls"
"net"
"net/url"
)
type Handler interface {
Handle(net.Conn)
}
type HandlerOptions struct {
Chain *Chain
Users []*url.Userinfo
TLSConfig *tls.Config
}
type HandlerOption func(opts *HandlerOptions)
func ChainHandlerOption(chain *Chain) HandlerOption {
return func(opts *HandlerOptions) {
opts.Chain = chain
}
}
func UsersHandlerOption(users ...*url.Userinfo) HandlerOption {
return func(opts *HandlerOptions) {
opts.Users = users
}
}
func TLSConfigHandlerOption(config *tls.Config) HandlerOption {
return func(opts *HandlerOptions) {
opts.TLSConfig = config
}
}
package gost
// Node is a proxy node, mainly used to construct a proxy chain
type Node struct {
Addr string
Protocol string
......
package gost
import (
"crypto/tls"
"io"
"net"
"time"
"net/url"
"github.com/go-log/log"
)
// Server is a proxy server.
type Server struct {
l net.Listener
handler Handler
}
// Handle sets a handler for the server
func (s *Server) Handle(h Handler) {
s.handler = h
}
// Serve serves as a proxy server.
func (s *Server) Serve(l net.Listener) error {
defer l.Close()
......@@ -48,6 +48,7 @@ func (s *Server) Serve(l net.Listener) error {
}
// Listener is a proxy server listener, just like a net.Listener.
type Listener interface {
net.Listener
}
......@@ -64,34 +65,18 @@ func TCPListener(addr string) (Listener, error) {
return &tcpListener{Listener: &tcpKeepAliveListener{ln.(*net.TCPListener)}}, nil
}
type Handler interface {
Handle(net.Conn)
}
type HandlerOptions struct {
Chain *Chain
Users []*url.Userinfo
TLSConfig *tls.Config
}
type HandlerOption func(opts *HandlerOptions)
func ChainHandlerOption(chain *Chain) HandlerOption {
return func(opts *HandlerOptions) {
opts.Chain = chain
}
}
func UsersHandlerOption(users ...*url.Userinfo) HandlerOption {
return func(opts *HandlerOptions) {
opts.Users = users
}
type tcpKeepAliveListener struct {
*net.TCPListener
}
func TLSConfigHandlerOption(config *tls.Config) HandlerOption {
return func(opts *HandlerOptions) {
opts.TLSConfig = config
func (ln tcpKeepAliveListener) Accept() (c net.Conn, err error) {
tc, err := ln.AcceptTCP()
if err != nil {
return
}
tc.SetKeepAlive(true)
tc.SetKeepAlivePeriod(KeepAliveTime)
return tc, nil
}
func transport(rw1, rw2 io.ReadWriter) error {
......@@ -106,23 +91,9 @@ func transport(rw1, rw2 io.ReadWriter) error {
errc <- err
}()
return <-errc
}
// tcpKeepAliveListener sets TCP keep-alive timeouts on accepted
// connections. It's used by ListenAndServe and ListenAndServeTLS so
// dead TCP connections (e.g. closing laptop mid-download) eventually
// go away.
type tcpKeepAliveListener struct {
*net.TCPListener
}
func (ln tcpKeepAliveListener) Accept() (c net.Conn, err error) {
tc, err := ln.AcceptTCP()
if err != nil {
return
err := <-errc
if err != nil && err == io.EOF {
err = nil
}
tc.SetKeepAlive(true)
tc.SetKeepAlivePeriod(3 * time.Minute)
return tc, nil
return err
}
This diff is collapsed.
......@@ -21,6 +21,8 @@ func main() {
wg.Add(1)
go httpServer(&wg)
wg.Add(1)
go socks5Server(&wg)
wg.Add(1)
go tlsServer(&wg)
wg.Add(1)
go shadowServer(&wg)
......@@ -38,6 +40,26 @@ func httpServer(wg *sync.WaitGroup) {
s.Handle(gost.HTTPHandler(
gost.UsersHandlerOption(url.UserPassword("admin", "123456")),
))
ln, err := gost.TCPListener(":8080")
if err != nil {
log.Fatal(err)
}
log.Fatal(s.Serve(ln))
}
func socks5Server(wg *sync.WaitGroup) {
defer wg.Done()
cert, err := tls.LoadX509KeyPair("cert.pem", "key.pem")
if err != nil {
log.Fatal(err)
}
s := &gost.Server{}
s.Handle(gost.SOCKS5Handler(
gost.UsersHandlerOption(url.UserPassword("admin", "123456")),
gost.TLSConfigHandlerOption(&tls.Config{Certificates: []tls.Certificate{cert}}),
))
ln, err := gost.TCPListener(":1080")
if err != nil {
log.Fatal(err)
......@@ -45,6 +67,20 @@ func httpServer(wg *sync.WaitGroup) {
log.Fatal(s.Serve(ln))
}
func shadowServer(wg *sync.WaitGroup) {
defer wg.Done()
s := &gost.Server{}
s.Handle(gost.ShadowHandler(
gost.UsersHandlerOption(url.UserPassword("chacha20", "123456")),
))
ln, err := gost.TCPListener(":8338")
if err != nil {
log.Fatal(err)
}
log.Fatal(s.Serve(ln))
}
func tlsServer(wg *sync.WaitGroup) {
defer wg.Done()
......@@ -95,17 +131,3 @@ func wssServer(wg *sync.WaitGroup) {
}
log.Fatal(s.Serve(ln))
}
func shadowServer(wg *sync.WaitGroup) {
defer wg.Done()
s := &gost.Server{}
s.Handle(gost.ShadowHandler(
gost.UsersHandlerOption(url.UserPassword("chacha20", "123456")),
))
ln, err := gost.TCPListener(":8338")
if err != nil {
log.Fatal(err)
}
log.Fatal(s.Serve(ln))
}
package tcp
import (
"net"
"github.com/ginuerzh/gost"
"github.com/ginuerzh/gost/server"
)
type nodeServer struct {
options *server.Server
}
func (s *nodeServer) Init(opts ...server.Option) {
for _, opt := range opts {
opt(s.options)
}
}
func (s *nodeServer) Options() *server.Options {
return s.options
}
func (s *nodeServer) Run() error {
ln, err := net.Listen("tcp", s.options.Addr)
if err != nil {
return err
}
defer ln.Close()
for {
conn, err := ln.Accept()
if err != nil {
return err
}
go func(c net.Conn) {
defer c.Close()
gost.DefaultHandler(s).Handle(conn)
}(conn)
}
}
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