diff --git a/CHANGELOG b/CHANGELOG index 14178b4..765b587 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,7 +1,8 @@ proxy更新日志: v3.1 -1.优化了内网穿透功能,client只需要启动一个即可,server端启动的时候可以指定client端要暴露的端口。 -2. +1.优化了内网穿透功能,bridge,client和server只需要启动一个即可. + server端启动的时候可以指定client端要暴露的一个或者多个端口。 +2.此次更新,tserver模式部分参数不兼容3.0。 v3.0 1.此次更新不兼容2.x版本,重构了全部代码,架构更合理,利于功能模块的增加与维护。 diff --git a/README.md b/README.md index 5861a9e..eb9242c 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,12 @@ Proxy是golang实现的高性能http,https,websocket,tcp,udp代理服务器,支 - 以前只能在局域网玩的,现在可以在任何地方玩. - 替代圣剑内网通,显IP内网通,花生壳之类的工具. - ...   - + +### 手册目录 +本页是最新v3.1手册,其他手册请点击下面链接查看. +- [v3.0手册](https://github.com/snail007/goproxy/tree/v3.0) +- [v2.x手册](https://github.com/snail007/goproxy/tree/v2.2) + ### Fast Start 提示:所有操作需要root权限. **0.如果你的VPS是linux64位的系统,那么只需要执行下面一句,就可以完成自动安装和配置.** @@ -45,7 +50,7 @@ wget https://github.com/reddec/monexec/releases/download/v0.1.1/monexec_0.1.1_li 下载地址:https://github.com/snail007/goproxy/releases ```shell cd /root/proxy/ -wget https://github.com/snail007/goproxy/releases/download/v2.0/proxy-linux-amd64.tar.gz +wget https://github.com/snail007/goproxy/releases/download/v3.1/proxy-linux-amd64.tar.gz ``` **3.下载自动安装脚本** ```shell diff --git a/config.go b/config.go index b1afb47..2ec38b8 100755 --- a/config.go +++ b/config.go @@ -78,8 +78,9 @@ func initConfig() (err error) { tunnelServerArgs.Timeout = tunnelServer.Flag("timeout", "tcp timeout with milliseconds").Short('t').Default("2000").Int() tunnelServerArgs.IsUDP = tunnelServer.Flag("udp", "proxy on udp tunnel server mode").Default("false").Bool() tunnelServerArgs.Key = tunnelServer.Flag("k", "client key").Default("default").String() - tunnelServerArgs.Remote = tunnelServer.Flag("remote", "client's network host:port").Short('r').Default("").String() - tunnelServerArgs.Local = tunnelServer.Flag("local", "local ip:port to listen").Short('p').Default(":33080").String() + //tunnelServerArgs.Remote = tunnelServer.Flag("remote", "client's network host:port").Short('R').Default("").String() + //tunnelServerArgs.Local = tunnelServer.Flag("local", "local ip:port to listen").Short('p').Default(":33080").String() + tunnelServerArgs.Route = tunnelServer.Flag("route", "local route to client's network, such as :localip:localport@clienthost:clientport").Short('r').Default("").Strings() //########tunnel-client######### tunnelClient := app.Command("tclient", "proxy on tunnel client mode") @@ -104,6 +105,7 @@ func initConfig() (err error) { tunnelBridgeArgs.Args = args tunnelClientArgs.Args = args tunnelServerArgs.Args = args + *tunnelServerArgs.Route = []string{} poster() //regist services and run service @@ -111,9 +113,10 @@ func initConfig() (err error) { services.Regist("http", services.NewHTTP(), httpArgs) services.Regist("tcp", services.NewTCP(), tcpArgs) services.Regist("udp", services.NewUDP(), udpArgs) - services.Regist("tserver", services.NewTunnelServer(), tunnelServerArgs) + services.Regist("tserver", services.NewTunnelServerManager(), tunnelServerArgs) services.Regist("tclient", services.NewTunnelClient(), tunnelClientArgs) services.Regist("tbridge", services.NewTunnelBridge(), tunnelBridgeArgs) + service, err = services.Run(serviceName) if err != nil { log.Fatalf("run service [%s] fail, ERR:%s", service, err) diff --git a/install_auto.sh b/install_auto.sh index 4fa322c..c176a37 100755 --- a/install_auto.sh +++ b/install_auto.sh @@ -6,7 +6,7 @@ fi mkdir /tmp/proxy cd /tmp/proxy wget https://github.com/reddec/monexec/releases/download/v0.1.1/monexec_0.1.1_linux_amd64.tar.gz -wget https://github.com/snail007/goproxy/releases/download/v3.0/proxy-linux-amd64.tar.gz +wget https://github.com/snail007/goproxy/releases/download/v3.1/proxy-linux-amd64.tar.gz # install monexec tar zxvf monexec_0.1.1_linux_amd64.tar.gz diff --git a/services/args.go b/services/args.go index 7a370cc..3052977 100644 --- a/services/args.go +++ b/services/args.go @@ -25,6 +25,7 @@ type TunnelServerArgs struct { Key *string Remote *string Timeout *int + Route *[]string } type TunnelClientArgs struct { Args diff --git a/services/service.go b/services/service.go index 285a504..de280af 100644 --- a/services/service.go +++ b/services/service.go @@ -25,7 +25,7 @@ func Regist(name string, s Service, args interface{}) { Name: name, } } -func Run(name string) (service *ServiceItem, err error) { +func Run(name string, args ...interface{}) (service *ServiceItem, err error) { service, ok := servicesMap[name] if ok { go func() { @@ -35,7 +35,11 @@ func Run(name string) (service *ServiceItem, err error) { log.Fatalf("%s servcie crashed, ERR: %s\ntrace:%s", name, err, string(debug.Stack())) } }() - err := service.S.Start(service.Args) + if len(args) == 1 { + err = service.S.Start(args[0]) + } else { + err = service.S.Start(service.Args) + } if err != nil { log.Fatalf("%s servcie fail, ERR: %s", name, err) } diff --git a/services/tunnel_server.go b/services/tunnel_server.go index 9b5556a..996d371 100644 --- a/services/tunnel_server.go +++ b/services/tunnel_server.go @@ -20,6 +20,44 @@ type TunnelServer struct { sc utils.ServerChannel } +type TunnelServerManager struct { + cfg TunnelServerArgs + udpChn chan UDPItem + sc utils.ServerChannel +} + +func NewTunnelServerManager() Service { + return &TunnelServerManager{ + cfg: TunnelServerArgs{}, + udpChn: make(chan UDPItem, 50000), + } +} +func (s *TunnelServerManager) Start(args interface{}) (err error) { + s.cfg = args.(TunnelServerArgs) + if *s.cfg.Parent != "" { + log.Printf("use tls parent %s", *s.cfg.Parent) + } else { + log.Fatalf("parent required") + } + for _, info := range *s.cfg.Route { + _routeInfo := strings.Split(info, "@") + server := NewTunnelServer() + local := _routeInfo[0] + remote := _routeInfo[1] + server.Start(TunnelServerArgs{ + Args: s.cfg.Args, + Local: &local, + IsUDP: s.cfg.IsUDP, + Remote: &remote, + Key: s.cfg.Key, + Timeout: s.cfg.Timeout, + }) + } + return +} +func (s *TunnelServerManager) Clean() { + +} func NewTunnelServer() Service { return &TunnelServer{ cfg: TunnelServerArgs{}, @@ -37,11 +75,6 @@ func (s *TunnelServer) InitService() { s.UDPConnDeamon() } func (s *TunnelServer) Check() { - if *s.cfg.Parent != "" { - log.Printf("use tls parent %s", *s.cfg.Parent) - } else { - log.Fatalf("parent required") - } if *s.cfg.Remote == "" { log.Fatalf("remote required") } @@ -122,7 +155,7 @@ func (s *TunnelServer) GetOutConn(id string) (outConn net.Conn, ID string, err e } keyBytes := []byte(*s.cfg.Key) keyLength := uint16(len(keyBytes)) - ID = utils.NewUniqueID().String() + ID = utils.Uniqueid() IDBytes := []byte(ID) if id != "" { ID = id diff --git a/utils/functions.go b/utils/functions.go index a214ca0..4788262 100755 --- a/utils/functions.go +++ b/utils/functions.go @@ -10,6 +10,7 @@ import ( "fmt" "io" "log" + "math/rand" "net" "net/http" "os" @@ -305,6 +306,11 @@ func ReadUDPPacket(_reader io.Reader) (srcAddr string, packet []byte, err error) } return } +func Uniqueid() string { + var src = rand.NewSource(time.Now().UnixNano()) + s := fmt.Sprintf("%d", src.Int63()) + return s[len(s)-5:len(s)-1] + fmt.Sprintf("%d", uint64(time.Now().UnixNano()))[8:] +} // type sockaddr struct { // family uint16 diff --git a/utils/id.go b/utils/id.go deleted file mode 100644 index 5ab9425..0000000 --- a/utils/id.go +++ /dev/null @@ -1,264 +0,0 @@ -// Package xid is a globally unique id generator suited for web scale -// -// Xid is using Mongo Object ID algorithm to generate globally unique ids: -// https://docs.mongodb.org/manual/reference/object-id/ -// -// - 4-byte value representing the seconds since the Unix epoch, -// - 3-byte machine identifier, -// - 2-byte process id, and -// - 3-byte counter, starting with a random value. -// -// The binary representation of the id is compatible with Mongo 12 bytes Object IDs. -// The string representation is using base32 hex (w/o padding) for better space efficiency -// when stored in that form (20 bytes). The hex variant of base32 is used to retain the -// sortable property of the id. -// -// Xid doesn't use base64 because case sensitivity and the 2 non alphanum chars may be an -// issue when transported as a string between various systems. Base36 wasn't retained either -// because 1/ it's not standard 2/ the resulting size is not predictable (not bit aligned) -// and 3/ it would not remain sortable. To validate a base32 `xid`, expect a 20 chars long, -// all lowercase sequence of `a` to `v` letters and `0` to `9` numbers (`[0-9a-v]{20}`). -// -// UUID is 16 bytes (128 bits), snowflake is 8 bytes (64 bits), xid stands in between -// with 12 bytes with a more compact string representation ready for the web and no -// required configuration or central generation server. -// -// Features: -// -// - Size: 12 bytes (96 bits), smaller than UUID, larger than snowflake -// - Base32 hex encoded by default (16 bytes storage when transported as printable string) -// - Non configured, you don't need set a unique machine and/or data center id -// - K-ordered -// - Embedded time with 1 second precision -// - Unicity guaranted for 16,777,216 (24 bits) unique ids per second and per host/process -// -// Best used with xlog's RequestIDHandler (https://godoc.org/github.com/rs/xlog#RequestIDHandler). -// -// References: -// -// - http://www.slideshare.net/davegardnerisme/unique-id-generation-in-distributed-systems -// - https://en.wikipedia.org/wiki/Universally_unique_identifier -// - https://blog.twitter.com/2010/announcing-snowflake -package utils - -import ( - "crypto/md5" - "crypto/rand" - "database/sql/driver" - "encoding/binary" - "errors" - "fmt" - "os" - "sync/atomic" - "time" -) - -// Code inspired from mgo/bson ObjectId - -// ID represents a unique request id -type ID [rawLen]byte - -const ( - encodedLen = 20 // string encoded len - decodedLen = 15 // len after base32 decoding with the padded data - rawLen = 12 // binary raw len - - // encoding stores a custom version of the base32 encoding with lower case - // letters. - encoding = "0123456789abcdefghijklmnopqrstuv" -) - -// ErrInvalidID is returned when trying to unmarshal an invalid ID -var ErrInvalidID = errors.New("xid: invalid ID") - -// objectIDCounter is atomically incremented when generating a new ObjectId -// using NewObjectId() function. It's used as a counter part of an id. -// This id is initialized with a random value. -var objectIDCounter = randInt() - -// machineId stores machine id generated once and used in subsequent calls -// to NewObjectId function. -var machineID = readMachineID() - -// pid stores the current process id -var pid = os.Getpid() - -// dec is the decoding map for base32 encoding -var dec [256]byte - -func init() { - for i := 0; i < len(dec); i++ { - dec[i] = 0xFF - } - for i := 0; i < len(encoding); i++ { - dec[encoding[i]] = byte(i) - } -} - -// readMachineId generates machine id and puts it into the machineId global -// variable. If this function fails to get the hostname, it will cause -// a runtime error. -func readMachineID() []byte { - id := make([]byte, 3) - if hostname, err := os.Hostname(); err == nil { - hw := md5.New() - hw.Write([]byte(hostname)) - copy(id, hw.Sum(nil)) - } else { - // Fallback to rand number if machine id can't be gathered - if _, randErr := rand.Reader.Read(id); randErr != nil { - panic(fmt.Errorf("xid: cannot get hostname nor generate a random number: %v; %v", err, randErr)) - } - } - return id -} - -// randInt generates a random uint32 -func randInt() uint32 { - b := make([]byte, 3) - if _, err := rand.Reader.Read(b); err != nil { - panic(fmt.Errorf("xid: cannot generate random number: %v;", err)) - } - return uint32(b[0])<<16 | uint32(b[1])<<8 | uint32(b[2]) -} - -// NewUniqueID generates a globaly unique ID -func NewUniqueID() ID { - var id ID - // Timestamp, 4 bytes, big endian - binary.BigEndian.PutUint32(id[:], uint32(time.Now().Unix())) - // Machine, first 3 bytes of md5(hostname) - id[4] = machineID[0] - id[5] = machineID[1] - id[6] = machineID[2] - // Pid, 2 bytes, specs don't specify endianness, but we use big endian. - id[7] = byte(pid >> 8) - id[8] = byte(pid) - // Increment, 3 bytes, big endian - i := atomic.AddUint32(&objectIDCounter, 1) - id[9] = byte(i >> 16) - id[10] = byte(i >> 8) - id[11] = byte(i) - return id -} - -// FromString reads an ID from its string representation -func FromString(id string) (ID, error) { - i := &ID{} - err := i.UnmarshalText([]byte(id)) - return *i, err -} - -// String returns a base32 hex lowercased with no padding representation of the id (char set is 0-9, a-v). -func (id ID) String() string { - text := make([]byte, encodedLen) - encode(text, id[:]) - return string(text) -} - -// MarshalText implements encoding/text TextMarshaler interface -func (id ID) MarshalText() ([]byte, error) { - text := make([]byte, encodedLen) - encode(text, id[:]) - return text, nil -} - -// encode by unrolling the stdlib base32 algorithm + removing all safe checks -func encode(dst, id []byte) { - dst[0] = encoding[id[0]>>3] - dst[1] = encoding[(id[1]>>6)&0x1F|(id[0]<<2)&0x1F] - dst[2] = encoding[(id[1]>>1)&0x1F] - dst[3] = encoding[(id[2]>>4)&0x1F|(id[1]<<4)&0x1F] - dst[4] = encoding[id[3]>>7|(id[2]<<1)&0x1F] - dst[5] = encoding[(id[3]>>2)&0x1F] - dst[6] = encoding[id[4]>>5|(id[3]<<3)&0x1F] - dst[7] = encoding[id[4]&0x1F] - dst[8] = encoding[id[5]>>3] - dst[9] = encoding[(id[6]>>6)&0x1F|(id[5]<<2)&0x1F] - dst[10] = encoding[(id[6]>>1)&0x1F] - dst[11] = encoding[(id[7]>>4)&0x1F|(id[6]<<4)&0x1F] - dst[12] = encoding[id[8]>>7|(id[7]<<1)&0x1F] - dst[13] = encoding[(id[8]>>2)&0x1F] - dst[14] = encoding[(id[9]>>5)|(id[8]<<3)&0x1F] - dst[15] = encoding[id[9]&0x1F] - dst[16] = encoding[id[10]>>3] - dst[17] = encoding[(id[11]>>6)&0x1F|(id[10]<<2)&0x1F] - dst[18] = encoding[(id[11]>>1)&0x1F] - dst[19] = encoding[(id[11]<<4)&0x1F] -} - -// UnmarshalText implements encoding/text TextUnmarshaler interface -func (id *ID) UnmarshalText(text []byte) error { - if len(text) != encodedLen { - return ErrInvalidID - } - for _, c := range text { - if dec[c] == 0xFF { - return ErrInvalidID - } - } - decode(id, text) - return nil -} - -// decode by unrolling the stdlib base32 algorithm + removing all safe checks -func decode(id *ID, src []byte) { - id[0] = dec[src[0]]<<3 | dec[src[1]]>>2 - id[1] = dec[src[1]]<<6 | dec[src[2]]<<1 | dec[src[3]]>>4 - id[2] = dec[src[3]]<<4 | dec[src[4]]>>1 - id[3] = dec[src[4]]<<7 | dec[src[5]]<<2 | dec[src[6]]>>3 - id[4] = dec[src[6]]<<5 | dec[src[7]] - id[5] = dec[src[8]]<<3 | dec[src[9]]>>2 - id[6] = dec[src[9]]<<6 | dec[src[10]]<<1 | dec[src[11]]>>4 - id[7] = dec[src[11]]<<4 | dec[src[12]]>>1 - id[8] = dec[src[12]]<<7 | dec[src[13]]<<2 | dec[src[14]]>>3 - id[9] = dec[src[14]]<<5 | dec[src[15]] - id[10] = dec[src[16]]<<3 | dec[src[17]]>>2 - id[11] = dec[src[17]]<<6 | dec[src[18]]<<1 | dec[src[19]]>>4 -} - -// Time returns the timestamp part of the id. -// It's a runtime error to call this method with an invalid id. -func (id ID) Time() time.Time { - // First 4 bytes of ObjectId is 32-bit big-endian seconds from epoch. - secs := int64(binary.BigEndian.Uint32(id[0:4])) - return time.Unix(secs, 0) -} - -// Machine returns the 3-byte machine id part of the id. -// It's a runtime error to call this method with an invalid id. -func (id ID) Machine() []byte { - return id[4:7] -} - -// Pid returns the process id part of the id. -// It's a runtime error to call this method with an invalid id. -func (id ID) Pid() uint16 { - return binary.BigEndian.Uint16(id[7:9]) -} - -// Counter returns the incrementing value part of the id. -// It's a runtime error to call this method with an invalid id. -func (id ID) Counter() int32 { - b := id[9:12] - // Counter is stored as big-endian 3-byte value - return int32(uint32(b[0])<<16 | uint32(b[1])<<8 | uint32(b[2])) -} - -// Value implements the driver.Valuer interface. -func (id ID) Value() (driver.Value, error) { - b, err := id.MarshalText() - return string(b), err -} - -// Scan implements the sql.Scanner interface. -func (id *ID) Scan(value interface{}) (err error) { - switch val := value.(type) { - case string: - return id.UnmarshalText([]byte(val)) - case []byte: - return id.UnmarshalText(val) - default: - return fmt.Errorf("xid: scanning unsupported type: %T", value) - } -}