add socks4/5 server handlers
This commit is contained in:
parent
7402fb2407
commit
684ccca252
@ -1,25 +1,80 @@
|
||||
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,16 +18,48 @@ 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(),
|
||||
),
|
||||
},
|
||||
*/
|
||||
|
||||
// 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(),
|
||||
),
|
||||
},
|
||||
*/
|
||||
|
||||
/*
|
||||
// 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",
|
||||
@ -41,15 +71,6 @@ func main() {
|
||||
),
|
||||
),
|
||||
},
|
||||
/*
|
||||
// http+tcp
|
||||
gost.Node{
|
||||
Addr: "127.0.0.1:1080",
|
||||
Client: gost.NewClient(
|
||||
gost.HTTPConnector(url.UserPassword("admin", "123456")),
|
||||
gost.TCPTransporter(),
|
||||
),
|
||||
},
|
||||
*/
|
||||
|
||||
/*
|
||||
@ -62,18 +83,8 @@ func main() {
|
||||
),
|
||||
},
|
||||
*/
|
||||
|
||||
/*
|
||||
// ss+tcp
|
||||
gost.Node{
|
||||
Addr: "127.0.0.1:8338",
|
||||
Client: gost.NewClient(
|
||||
gost.ShadowConnector(url.UserPassword("chacha20", "123456")),
|
||||
gost.TCPTransporter(),
|
||||
),
|
||||
},
|
||||
*/
|
||||
)
|
||||
|
||||
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)
|
||||
|
12
gost/gost.go
12
gost/gost.go
@ -1,6 +1,8 @@
|
||||
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{}
|
||||
}
|
||||
|
37
gost/handler.go
Normal file
37
gost/handler.go
Normal file
@ -0,0 +1,37 @@
|
||||
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
|
||||
}
|
||||
}
|
@ -1,5 +1,6 @@
|
||||
package gost
|
||||
|
||||
// Node is a proxy node, mainly used to construct a proxy chain
|
||||
type Node struct {
|
||||
Addr string
|
||||
Protocol string
|
||||
|
@ -1,25 +1,25 @@
|
||||
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 tcpKeepAliveListener struct {
|
||||
*net.TCPListener
|
||||
}
|
||||
|
||||
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
|
||||
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
|
||||
}
|
||||
|
627
gost/socks.go
627
gost/socks.go
@ -1,12 +1,16 @@
|
||||
package gost
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/tls"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"io"
|
||||
|
||||
"github.com/ginuerzh/gosocks4"
|
||||
"github.com/ginuerzh/gosocks5"
|
||||
@ -327,6 +331,7 @@ type socks5Handler struct {
|
||||
options *HandlerOptions
|
||||
}
|
||||
|
||||
// SOCKS5Handler returns a SOCKS5 server handler
|
||||
func SOCKS5Handler(opts ...HandlerOption) Handler {
|
||||
options := &HandlerOptions{
|
||||
Chain: new(Chain),
|
||||
@ -374,11 +379,11 @@ func (h *socks5Handler) Handle(conn net.Conn) {
|
||||
|
||||
case gosocks5.CmdUdp:
|
||||
log.Logf("[socks5-udp] %s - %s", conn.RemoteAddr(), req.Addr)
|
||||
//s.handleUDPRelay(req)
|
||||
h.handleUDPRelay(conn, req)
|
||||
|
||||
case CmdUdpTun:
|
||||
log.Logf("[socks5-rudp] %s - %s", conn.RemoteAddr(), req.Addr)
|
||||
//s.handleUDPTunnel(req)
|
||||
h.handleUDPTunnel(conn, req)
|
||||
|
||||
default:
|
||||
log.Log("[socks5] Unrecognized request:", req.Cmd)
|
||||
@ -421,5 +426,621 @@ func (h *socks5Handler) handleConnect(conn net.Conn, req *gosocks5.Request) {
|
||||
}
|
||||
|
||||
func (h *socks5Handler) handleBind(conn net.Conn, req *gosocks5.Request) {
|
||||
// TODO: socks5 bind
|
||||
if h.options.Chain.IsEmpty() {
|
||||
|
||||
//! if !s.Base.Node.Can("rtcp", addr) {
|
||||
//! glog.Errorf("Unauthorized to tcp bind to %s", addr)
|
||||
//! return
|
||||
//! }
|
||||
|
||||
h.bindOn(conn, req.Addr.String())
|
||||
return
|
||||
}
|
||||
|
||||
cc, err := h.options.Chain.Conn()
|
||||
if err != nil {
|
||||
log.Logf("[socks5-bind] %s <- %s : %s", conn.RemoteAddr(), req.Addr, err)
|
||||
reply := gosocks5.NewReply(gosocks5.Failure, nil)
|
||||
reply.Write(conn)
|
||||
if Debug {
|
||||
log.Logf("[socks5-bind] %s <- %s\n%s", conn.RemoteAddr(), req.Addr, reply)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// forward request
|
||||
// note: this type of request forwarding is defined when starting server,
|
||||
// so we don't need to authenticate it, as it's as explicit as whitelisting
|
||||
defer cc.Close()
|
||||
req.Write(cc)
|
||||
log.Logf("[socks5-bind] %s <-> %s", conn.RemoteAddr(), cc.RemoteAddr())
|
||||
transport(conn, cc)
|
||||
log.Logf("[socks5-bind] %s >-< %s", conn.RemoteAddr(), cc.RemoteAddr())
|
||||
}
|
||||
|
||||
func (h *socks5Handler) bindOn(conn net.Conn, addr string) {
|
||||
bindAddr, _ := net.ResolveTCPAddr("tcp", addr)
|
||||
ln, err := net.ListenTCP("tcp", bindAddr) // strict mode: if the port already in use, it will return error
|
||||
if err != nil {
|
||||
log.Logf("[socks5-bind] %s -> %s : %s", conn.RemoteAddr(), addr, err)
|
||||
gosocks5.NewReply(gosocks5.Failure, nil).Write(conn)
|
||||
return
|
||||
}
|
||||
|
||||
socksAddr := toSocksAddr(ln.Addr())
|
||||
// Issue: may not reachable when host has multi-interface
|
||||
socksAddr.Host, _, _ = net.SplitHostPort(conn.LocalAddr().String())
|
||||
reply := gosocks5.NewReply(gosocks5.Succeeded, socksAddr)
|
||||
if err := reply.Write(conn); err != nil {
|
||||
log.Logf("[socks5-bind] %s <- %s : %s", conn.RemoteAddr(), addr, err)
|
||||
ln.Close()
|
||||
return
|
||||
}
|
||||
if Debug {
|
||||
log.Logf("[socks5-bind] %s <- %s\n%s", conn.RemoteAddr(), addr, reply)
|
||||
}
|
||||
log.Logf("[socks5-bind] %s - %s BIND ON %s OK", conn.RemoteAddr(), addr, socksAddr)
|
||||
|
||||
var pconn net.Conn
|
||||
accept := func() <-chan error {
|
||||
errc := make(chan error, 1)
|
||||
|
||||
go func() {
|
||||
defer close(errc)
|
||||
defer ln.Close()
|
||||
|
||||
c, err := ln.AcceptTCP()
|
||||
if err != nil {
|
||||
errc <- err
|
||||
return
|
||||
}
|
||||
pconn = c
|
||||
}()
|
||||
|
||||
return errc
|
||||
}
|
||||
|
||||
pc1, pc2 := net.Pipe()
|
||||
pipe := func() <-chan error {
|
||||
errc := make(chan error, 1)
|
||||
|
||||
go func() {
|
||||
defer close(errc)
|
||||
defer pc1.Close()
|
||||
|
||||
errc <- transport(conn, pc1)
|
||||
}()
|
||||
|
||||
return errc
|
||||
}
|
||||
|
||||
defer pc2.Close()
|
||||
|
||||
for {
|
||||
select {
|
||||
case err := <-accept():
|
||||
if err != nil || pconn == nil {
|
||||
log.Logf("[socks5-bind] %s <- %s : %v", conn.RemoteAddr(), addr, err)
|
||||
return
|
||||
}
|
||||
defer pconn.Close()
|
||||
|
||||
reply := gosocks5.NewReply(gosocks5.Succeeded, toSocksAddr(pconn.RemoteAddr()))
|
||||
if err := reply.Write(pc2); err != nil {
|
||||
log.Logf("[socks5-bind] %s <- %s : %v", conn.RemoteAddr(), addr, err)
|
||||
}
|
||||
if Debug {
|
||||
log.Logf("[socks5-bind] %s <- %s\n%s", conn.RemoteAddr(), addr, reply)
|
||||
}
|
||||
log.Logf("[socks5-bind] %s <- %s PEER %s ACCEPTED", conn.RemoteAddr(), socksAddr, pconn.RemoteAddr())
|
||||
|
||||
log.Logf("[socks5-bind] %s <-> %s", conn.RemoteAddr(), pconn.RemoteAddr())
|
||||
if err = transport(pc2, pconn); err != nil {
|
||||
log.Logf("[socks5-bind] %s - %s : %v", conn.RemoteAddr(), pconn.RemoteAddr(), err)
|
||||
}
|
||||
log.Logf("[socks5-bind] %s >-< %s", conn.RemoteAddr(), pconn.RemoteAddr())
|
||||
return
|
||||
case err := <-pipe():
|
||||
if err != nil {
|
||||
log.Logf("[socks5-bind] %s -> %s : %v", conn.RemoteAddr(), addr, err)
|
||||
}
|
||||
ln.Close()
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (h *socks5Handler) handleUDPRelay(conn net.Conn, req *gosocks5.Request) {
|
||||
//! addr := req.Addr.String()
|
||||
//!
|
||||
//! if !s.Base.Node.Can("udp", addr) {
|
||||
//! glog.Errorf("Unauthorized to udp connect to %s", addr)
|
||||
//! rep := gosocks5.NewReply(gosocks5.NotAllowed, nil)
|
||||
//! rep.Write(s.conn)
|
||||
//! return
|
||||
//! }
|
||||
|
||||
relay, err := net.ListenUDP("udp", nil)
|
||||
if err != nil {
|
||||
log.Logf("[socks5-udp] %s -> %s : %s", conn.RemoteAddr(), relay.LocalAddr(), err)
|
||||
reply := gosocks5.NewReply(gosocks5.Failure, nil)
|
||||
reply.Write(conn)
|
||||
if Debug {
|
||||
log.Logf("[socks5-udp] %s <- %s\n%s", conn.RemoteAddr(), relay.LocalAddr(), reply)
|
||||
}
|
||||
return
|
||||
}
|
||||
defer relay.Close()
|
||||
|
||||
socksAddr := toSocksAddr(relay.LocalAddr())
|
||||
socksAddr.Host, _, _ = net.SplitHostPort(conn.LocalAddr().String()) // replace the IP to the out-going interface's
|
||||
reply := gosocks5.NewReply(gosocks5.Succeeded, socksAddr)
|
||||
if err := reply.Write(conn); err != nil {
|
||||
log.Logf("[socks5-udp] %s <- %s : %s", conn.RemoteAddr(), relay.LocalAddr(), err)
|
||||
return
|
||||
}
|
||||
if Debug {
|
||||
log.Logf("[socks5-udp] %s <- %s\n%s", conn.RemoteAddr(), reply.Addr, reply)
|
||||
}
|
||||
log.Logf("[socks5-udp] %s - %s BIND ON %s OK", conn.RemoteAddr(), relay.LocalAddr(), socksAddr)
|
||||
|
||||
// serve as standard socks5 udp relay local <-> remote
|
||||
if h.options.Chain.IsEmpty() {
|
||||
peer, er := net.ListenUDP("udp", nil)
|
||||
if er != nil {
|
||||
log.Logf("[socks5-udp] %s -> %s : %s", conn.RemoteAddr(), socksAddr, er)
|
||||
return
|
||||
}
|
||||
defer peer.Close()
|
||||
|
||||
go h.transportUDP(relay, peer)
|
||||
log.Logf("[socks5-udp] %s <-> %s", conn.RemoteAddr(), socksAddr)
|
||||
if err := h.discardClientData(conn); err != nil {
|
||||
log.Logf("[socks5-udp] %s - %s : %s", conn.RemoteAddr(), socksAddr, err)
|
||||
}
|
||||
log.Logf("[socks5-udp] %s >-< %s", conn.RemoteAddr(), socksAddr)
|
||||
return
|
||||
}
|
||||
|
||||
cc, err := h.options.Chain.Conn()
|
||||
// connection error
|
||||
if err != nil {
|
||||
log.Logf("[socks5-udp] %s -> %s : %s", conn.RemoteAddr(), socksAddr, err)
|
||||
return
|
||||
}
|
||||
|
||||
// forward udp local <-> tunnel
|
||||
defer cc.Close()
|
||||
|
||||
cc.SetWriteDeadline(time.Now().Add(WriteTimeout))
|
||||
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
|
||||
}
|
||||
cc.SetWriteDeadline(time.Time{})
|
||||
if Debug {
|
||||
log.Logf("[socks5-udp] %s -> %s\n%s", conn.RemoteAddr(), cc.RemoteAddr(), r)
|
||||
}
|
||||
cc.SetReadDeadline(time.Now().Add(ReadTimeout))
|
||||
reply, err = gosocks5.ReadReply(cc)
|
||||
if err != nil {
|
||||
log.Logf("[socks5-udp] %s -> %s : %s", conn.RemoteAddr(), cc.RemoteAddr(), err)
|
||||
return
|
||||
}
|
||||
if Debug {
|
||||
log.Logf("[socks5-udp] %s <- %s\n%s", conn.RemoteAddr(), cc.RemoteAddr(), reply)
|
||||
}
|
||||
|
||||
if reply.Rep != gosocks5.Succeeded {
|
||||
log.Logf("[socks5-udp] %s <- %s : udp associate failed", conn.RemoteAddr(), cc.RemoteAddr())
|
||||
return
|
||||
}
|
||||
cc.SetReadDeadline(time.Time{})
|
||||
log.Logf("[socks5-udp] %s <-> %s [tun: %s]", conn.RemoteAddr(), socksAddr, reply.Addr)
|
||||
|
||||
go h.tunnelClientUDP(relay, cc)
|
||||
log.Logf("[socks5-udp] %s <-> %s", conn.RemoteAddr(), socksAddr)
|
||||
if err := h.discardClientData(conn); err != nil {
|
||||
log.Logf("[socks5-udp] %s - %s : %s", conn.RemoteAddr(), socksAddr, err)
|
||||
}
|
||||
log.Logf("[socks5-udp] %s >-< %s", conn.RemoteAddr(), socksAddr)
|
||||
}
|
||||
|
||||
func (s *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
|
||||
if err != nil {
|
||||
if err == io.EOF { // disconnect normally
|
||||
err = nil
|
||||
}
|
||||
break // client disconnected
|
||||
}
|
||||
log.Logf("[socks5-udp] read %d UNEXPECTED TCP data from client", n)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (s *socks5Handler) transportUDP(relay, peer *net.UDPConn) (err error) {
|
||||
errc := make(chan error, 2)
|
||||
|
||||
var clientAddr *net.UDPAddr
|
||||
|
||||
go func() {
|
||||
b := make([]byte, LargeBufferSize)
|
||||
|
||||
for {
|
||||
n, laddr, err := relay.ReadFromUDP(b)
|
||||
if err != nil {
|
||||
errc <- err
|
||||
return
|
||||
}
|
||||
if clientAddr == nil {
|
||||
clientAddr = laddr
|
||||
}
|
||||
dgram, err := gosocks5.ReadUDPDatagram(bytes.NewReader(b[:n]))
|
||||
if err != nil {
|
||||
errc <- err
|
||||
return
|
||||
}
|
||||
|
||||
raddr, err := net.ResolveUDPAddr("udp", dgram.Header.Addr.String())
|
||||
if err != nil {
|
||||
continue // drop silently
|
||||
}
|
||||
if _, err := peer.WriteToUDP(dgram.Data, raddr); err != nil {
|
||||
errc <- err
|
||||
return
|
||||
}
|
||||
if Debug {
|
||||
log.Logf("[socks5-udp] %s >>> %s length: %d", relay.LocalAddr(), raddr, len(dgram.Data))
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
go func() {
|
||||
b := make([]byte, LargeBufferSize)
|
||||
|
||||
for {
|
||||
n, raddr, err := peer.ReadFromUDP(b)
|
||||
if err != nil {
|
||||
errc <- err
|
||||
return
|
||||
}
|
||||
if clientAddr == nil {
|
||||
continue
|
||||
}
|
||||
buf := bytes.Buffer{}
|
||||
dgram := gosocks5.NewUDPDatagram(gosocks5.NewUDPHeader(0, 0, toSocksAddr(raddr)), b[:n])
|
||||
dgram.Write(&buf)
|
||||
if _, err := relay.WriteToUDP(buf.Bytes(), clientAddr); err != nil {
|
||||
errc <- err
|
||||
return
|
||||
}
|
||||
if Debug {
|
||||
log.Logf("[socks5-udp] %s <<< %s length: %d", relay.LocalAddr(), raddr, len(dgram.Data))
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
select {
|
||||
case err = <-errc:
|
||||
//log.Println("w exit", err)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (h *socks5Handler) tunnelClientUDP(uc *net.UDPConn, cc net.Conn) (err error) {
|
||||
errc := make(chan error, 2)
|
||||
|
||||
var clientAddr *net.UDPAddr
|
||||
|
||||
go func() {
|
||||
b := make([]byte, LargeBufferSize)
|
||||
|
||||
for {
|
||||
n, addr, err := uc.ReadFromUDP(b)
|
||||
if err != nil {
|
||||
log.Logf("[udp-tun] %s <- %s : %s", cc.RemoteAddr(), addr, err)
|
||||
errc <- err
|
||||
return
|
||||
}
|
||||
|
||||
// glog.V(LDEBUG).Infof("read udp %d, % #x", n, b[:n])
|
||||
// pipe from relay to tunnel
|
||||
dgram, err := gosocks5.ReadUDPDatagram(bytes.NewReader(b[:n]))
|
||||
if err != nil {
|
||||
errc <- err
|
||||
return
|
||||
}
|
||||
if clientAddr == nil {
|
||||
clientAddr = addr
|
||||
}
|
||||
dgram.Header.Rsv = uint16(len(dgram.Data))
|
||||
if err := dgram.Write(cc); err != nil {
|
||||
errc <- err
|
||||
return
|
||||
}
|
||||
if Debug {
|
||||
log.Logf("[udp-tun] %s >>> %s length: %d", uc.LocalAddr(), dgram.Header.Addr, len(dgram.Data))
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
go func() {
|
||||
for {
|
||||
dgram, err := gosocks5.ReadUDPDatagram(cc)
|
||||
if err != nil {
|
||||
log.Logf("[udp-tun] %s -> 0 : %s", cc.RemoteAddr(), err)
|
||||
errc <- err
|
||||
return
|
||||
}
|
||||
|
||||
// pipe from tunnel to relay
|
||||
if clientAddr == nil {
|
||||
continue
|
||||
}
|
||||
dgram.Header.Rsv = 0
|
||||
|
||||
buf := bytes.Buffer{}
|
||||
dgram.Write(&buf)
|
||||
if _, err := uc.WriteToUDP(buf.Bytes(), clientAddr); err != nil {
|
||||
errc <- err
|
||||
return
|
||||
}
|
||||
if Debug {
|
||||
log.Logf("[udp-tun] %s <<< %s length: %d", uc.LocalAddr(), dgram.Header.Addr, len(dgram.Data))
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
select {
|
||||
case err = <-errc:
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (h *socks5Handler) handleUDPTunnel(conn net.Conn, req *gosocks5.Request) {
|
||||
// serve tunnel udp, tunnel <-> remote, handle tunnel udp request
|
||||
if h.options.Chain.IsEmpty() {
|
||||
addr := req.Addr.String()
|
||||
|
||||
//! if !s.Base.Node.Can("rudp", addr) {
|
||||
//! glog.Errorf("Unauthorized to udp bind to %s", addr)
|
||||
//! return
|
||||
//! }
|
||||
|
||||
bindAddr, _ := net.ResolveUDPAddr("udp", addr)
|
||||
uc, err := net.ListenUDP("udp", bindAddr)
|
||||
if err != nil {
|
||||
log.Logf("[socks5-rudp] %s -> %s : %s", conn.RemoteAddr(), req.Addr, err)
|
||||
return
|
||||
}
|
||||
defer uc.Close()
|
||||
|
||||
socksAddr := toSocksAddr(uc.LocalAddr())
|
||||
socksAddr.Host, _, _ = net.SplitHostPort(conn.LocalAddr().String())
|
||||
reply := gosocks5.NewReply(gosocks5.Succeeded, socksAddr)
|
||||
if err := reply.Write(conn); err != nil {
|
||||
log.Logf("[socks5-rudp] %s <- %s : %s", conn.RemoteAddr(), socksAddr, err)
|
||||
return
|
||||
}
|
||||
if Debug {
|
||||
log.Logf("[socks5-rudp] %s <- %s\n%s", conn.RemoteAddr(), socksAddr, reply)
|
||||
}
|
||||
log.Logf("[socks5-rudp] %s <-> %s", conn.RemoteAddr(), socksAddr)
|
||||
h.tunnelServerUDP(conn, uc)
|
||||
log.Logf("[socks5-rudp] %s >-< %s", conn.RemoteAddr(), socksAddr)
|
||||
return
|
||||
}
|
||||
|
||||
cc, err := h.options.Chain.Conn()
|
||||
// connection error
|
||||
if err != nil {
|
||||
log.Logf("[socks5-rudp] %s -> %s : %s", conn.RemoteAddr(), req.Addr, err)
|
||||
reply := gosocks5.NewReply(gosocks5.Failure, nil)
|
||||
reply.Write(conn)
|
||||
log.Logf("[socks5-rudp] %s -> %s\n%s", conn.RemoteAddr(), req.Addr, reply)
|
||||
return
|
||||
}
|
||||
|
||||
defer cc.Close()
|
||||
|
||||
// tunnel <-> tunnel, direct forwarding
|
||||
// note: this type of request forwarding is defined when starting server
|
||||
// so we don't need to authenticate it, as it's as explicit as whitelisting
|
||||
req.Write(cc)
|
||||
|
||||
log.Logf("[socks5-rudp] %s <-> %s [tun]", conn.RemoteAddr(), cc.RemoteAddr())
|
||||
transport(conn, cc)
|
||||
log.Logf("[socks5-rudp] %s >-< %s [tun]", conn.RemoteAddr(), cc.RemoteAddr())
|
||||
}
|
||||
|
||||
func (h *socks5Handler) tunnelServerUDP(cc net.Conn, uc *net.UDPConn) (err error) {
|
||||
errc := make(chan error, 2)
|
||||
|
||||
go func() {
|
||||
b := make([]byte, LargeBufferSize)
|
||||
|
||||
for {
|
||||
n, addr, err := uc.ReadFromUDP(b)
|
||||
if err != nil {
|
||||
log.Logf("[udp-tun] %s <- %s : %s", cc.RemoteAddr(), addr, err)
|
||||
errc <- err
|
||||
return
|
||||
}
|
||||
|
||||
// pipe from peer to tunnel
|
||||
dgram := gosocks5.NewUDPDatagram(
|
||||
gosocks5.NewUDPHeader(uint16(n), 0, toSocksAddr(addr)), b[:n])
|
||||
if err := dgram.Write(cc); err != nil {
|
||||
log.Logf("[udp-tun] %s <- %s : %s", cc.RemoteAddr(), dgram.Header.Addr, err)
|
||||
errc <- err
|
||||
return
|
||||
}
|
||||
if Debug {
|
||||
log.Logf("[udp-tun] %s <<< %s length: %d", cc.RemoteAddr(), dgram.Header.Addr, len(dgram.Data))
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
go func() {
|
||||
for {
|
||||
dgram, err := gosocks5.ReadUDPDatagram(cc)
|
||||
if err != nil {
|
||||
log.Logf("[udp-tun] %s -> 0 : %s", cc.RemoteAddr(), err)
|
||||
errc <- err
|
||||
return
|
||||
}
|
||||
|
||||
// pipe from tunnel to peer
|
||||
addr, err := net.ResolveUDPAddr("udp", dgram.Header.Addr.String())
|
||||
if err != nil {
|
||||
continue // drop silently
|
||||
}
|
||||
if _, err := uc.WriteToUDP(dgram.Data, addr); err != nil {
|
||||
log.Logf("[udp-tun] %s -> %s : %s", cc.RemoteAddr(), addr, err)
|
||||
errc <- err
|
||||
return
|
||||
}
|
||||
if Debug {
|
||||
log.Logf("[udp-tun] %s >>> %s length: %d", cc.RemoteAddr(), addr, len(dgram.Data))
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
select {
|
||||
case err = <-errc:
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func toSocksAddr(addr net.Addr) *gosocks5.Addr {
|
||||
host := "0.0.0.0"
|
||||
port := 0
|
||||
if addr != nil {
|
||||
h, p, _ := net.SplitHostPort(addr.String())
|
||||
host = h
|
||||
port, _ = strconv.Atoi(p)
|
||||
}
|
||||
return &gosocks5.Addr{
|
||||
Type: gosocks5.AddrIPv4,
|
||||
Host: host,
|
||||
Port: uint16(port),
|
||||
}
|
||||
}
|
||||
|
||||
type socks4Handler struct {
|
||||
options *HandlerOptions
|
||||
}
|
||||
|
||||
// SOCKS4Handler returns a SOCKS4 server handler
|
||||
func SOCKS4Handler(opts ...HandlerOption) Handler {
|
||||
options := &HandlerOptions{
|
||||
Chain: new(Chain),
|
||||
}
|
||||
for _, opt := range opts {
|
||||
opt(options)
|
||||
}
|
||||
return &socks4Handler{
|
||||
options: options,
|
||||
}
|
||||
}
|
||||
|
||||
func (h *socks4Handler) Handle(conn net.Conn) {
|
||||
req, err := gosocks4.ReadRequest(conn)
|
||||
if err != nil {
|
||||
log.Log("[socks4]", err)
|
||||
return
|
||||
}
|
||||
|
||||
if Debug {
|
||||
log.Logf("[socks4] %s -> %s\n%s", conn.RemoteAddr(), req.Addr, req)
|
||||
}
|
||||
|
||||
switch req.Cmd {
|
||||
case gosocks4.CmdConnect:
|
||||
log.Logf("[socks4-connect] %s -> %s", conn.RemoteAddr(), req.Addr)
|
||||
h.handleConnect(conn, req)
|
||||
|
||||
case gosocks4.CmdBind:
|
||||
log.Logf("[socks4-bind] %s - %s", conn.RemoteAddr(), req.Addr)
|
||||
h.handleBind(conn, req)
|
||||
|
||||
default:
|
||||
log.Logf("[socks4] Unrecognized request: %d", req.Cmd)
|
||||
}
|
||||
}
|
||||
|
||||
func (h *socks4Handler) handleConnect(conn net.Conn, req *gosocks4.Request) {
|
||||
addr := req.Addr.String()
|
||||
|
||||
//! if !s.Base.Node.Can("tcp", addr) {
|
||||
//! glog.Errorf("Unauthorized to tcp connect to %s", addr)
|
||||
//! rep := gosocks5.NewReply(gosocks4.Rejected, nil)
|
||||
//! rep.Write(s.conn)
|
||||
//! return
|
||||
//! }
|
||||
|
||||
cc, err := h.options.Chain.Dial(addr)
|
||||
if err != nil {
|
||||
log.Logf("[socks4-connect] %s -> %s : %s", conn.RemoteAddr(), req.Addr, err)
|
||||
rep := gosocks4.NewReply(gosocks4.Failed, nil)
|
||||
rep.Write(conn)
|
||||
if Debug {
|
||||
log.Logf("[socks4-connect] %s <- %s\n%s", conn.RemoteAddr(), req.Addr, rep)
|
||||
}
|
||||
return
|
||||
}
|
||||
defer cc.Close()
|
||||
|
||||
rep := gosocks4.NewReply(gosocks4.Granted, nil)
|
||||
if err := rep.Write(conn); err != nil {
|
||||
log.Logf("[socks4-connect] %s <- %s : %s", conn.RemoteAddr(), req.Addr, err)
|
||||
return
|
||||
}
|
||||
if Debug {
|
||||
log.Logf("[socks4-connect] %s <- %s\n%s", conn.RemoteAddr(), req.Addr, rep)
|
||||
}
|
||||
|
||||
log.Logf("[socks4-connect] %s <-> %s", conn.RemoteAddr(), req.Addr)
|
||||
transport(conn, cc)
|
||||
log.Logf("[socks4-connect] %s >-< %s", conn.RemoteAddr(), req.Addr)
|
||||
}
|
||||
|
||||
func (h *socks4Handler) handleBind(conn net.Conn, req *gosocks4.Request) {
|
||||
// TODO: serve socks4 bind
|
||||
if h.options.Chain.IsEmpty() {
|
||||
reply := gosocks4.NewReply(gosocks4.Rejected, nil)
|
||||
reply.Write(conn)
|
||||
if Debug {
|
||||
log.Logf("[socks4-bind] %s <- %s\n%s", conn.RemoteAddr(), req.Addr, reply)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
cc, err := h.options.Chain.Conn()
|
||||
// connection error
|
||||
if err != nil && err != ErrEmptyChain {
|
||||
log.Logf("[socks4-bind] %s <- %s : %s", conn.RemoteAddr(), req.Addr, err)
|
||||
reply := gosocks4.NewReply(gosocks4.Failed, nil)
|
||||
reply.Write(conn)
|
||||
if Debug {
|
||||
log.Logf("[socks4-bind] %s <- %s\n%s", conn.RemoteAddr(), req.Addr, reply)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
defer cc.Close()
|
||||
// forward request
|
||||
req.Write(cc)
|
||||
|
||||
log.Logf("[socks4-bind] %s <-> %s", conn.RemoteAddr(), cc.RemoteAddr())
|
||||
transport(conn, cc)
|
||||
log.Logf("[socks4-bind] %s >-< %s", conn.RemoteAddr(), cc.RemoteAddr())
|
||||
}
|
||||
|
@ -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))
|
||||
}
|
||||
|
@ -1,41 +0,0 @@
|
||||
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)
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user