mirror of https://github.com/ginuerzh/gost
commit
2502ef306f
4 changed files with 306 additions and 0 deletions
@ -0,0 +1,117 @@ |
|||||
|
package main |
||||
|
|
||||
|
import ( |
||||
|
//"bufio"
|
||||
|
//"bytes"
|
||||
|
//"crypto/tls"
|
||||
|
//"errors"
|
||||
|
"io" |
||||
|
//"io/ioutil"
|
||||
|
"log" |
||||
|
"net" |
||||
|
//"net/http"
|
||||
|
//"strconv"
|
||||
|
//"strings"
|
||||
|
//"sync/atomic"
|
||||
|
"time" |
||||
|
) |
||||
|
|
||||
|
const ( |
||||
|
readWait = 300 * time.Second |
||||
|
writeWait = 300 * time.Second |
||||
|
) |
||||
|
|
||||
|
type Gost struct { |
||||
|
Laddr, Saddr, Proxy string |
||||
|
} |
||||
|
|
||||
|
func (g *Gost) Run() error { |
||||
|
addr, err := net.ResolveTCPAddr("tcp", g.Laddr) |
||||
|
if err != nil { |
||||
|
return err |
||||
|
} |
||||
|
|
||||
|
ln, err := net.ListenTCP("tcp", addr) |
||||
|
if err != nil { |
||||
|
return err |
||||
|
} |
||||
|
|
||||
|
for { |
||||
|
conn, err := ln.AcceptTCP() |
||||
|
if err != nil { |
||||
|
log.Println("accept:", err) |
||||
|
continue |
||||
|
} |
||||
|
go g.serve(conn) |
||||
|
} |
||||
|
|
||||
|
return ln.Close() |
||||
|
} |
||||
|
|
||||
|
func (g *Gost) serve(conn net.Conn) error { |
||||
|
var pconn net.Conn |
||||
|
defer conn.Close() |
||||
|
|
||||
|
paddr, err := net.ResolveTCPAddr("tcp", g.Proxy) |
||||
|
if err != nil { |
||||
|
log.Println(err) |
||||
|
} |
||||
|
if paddr != nil { |
||||
|
pconn, err = net.DialTCP("tcp", nil, paddr) |
||||
|
if err != nil { |
||||
|
return err |
||||
|
} |
||||
|
return g.foward(conn, pconn) |
||||
|
} |
||||
|
|
||||
|
saddr, err := net.ResolveTCPAddr("tcp", g.Saddr) |
||||
|
if err != nil { |
||||
|
log.Println(err) |
||||
|
} |
||||
|
if saddr != nil { |
||||
|
sconn, err := net.DialTCP("tcp", nil, saddr) |
||||
|
if err != nil { |
||||
|
return err |
||||
|
} |
||||
|
defer sconn.Close() |
||||
|
|
||||
|
return g.transport(conn, sconn) |
||||
|
} |
||||
|
|
||||
|
return nil |
||||
|
} |
||||
|
|
||||
|
func (g *Gost) foward(conn, pconn net.Conn) error { |
||||
|
defer pconn.Close() |
||||
|
|
||||
|
saddr, err := net.ResolveTCPAddr("tcp", g.Saddr) |
||||
|
if err != nil { |
||||
|
log.Println(err) |
||||
|
} |
||||
|
|
||||
|
if saddr != nil { |
||||
|
|
||||
|
} |
||||
|
|
||||
|
return nil |
||||
|
} |
||||
|
|
||||
|
func (g *Gost) pipe(src io.Reader, dst io.Writer, c chan<- error) { |
||||
|
_, err := io.Copy(dst, src) |
||||
|
c <- err |
||||
|
} |
||||
|
|
||||
|
func (g *Gost) transport(conn net.Conn, conn2 net.Conn) (err error) { |
||||
|
rChan := make(chan error, 1) |
||||
|
wChan := make(chan error, 1) |
||||
|
|
||||
|
go g.pipe(conn, conn2, wChan) |
||||
|
go g.pipe(conn2, conn, rChan) |
||||
|
|
||||
|
select { |
||||
|
case err = <-wChan: |
||||
|
case err = <-rChan: |
||||
|
} |
||||
|
|
||||
|
return |
||||
|
} |
||||
Binary file not shown.
@ -0,0 +1,22 @@ |
|||||
|
// main
|
||||
|
package main |
||||
|
|
||||
|
import ( |
||||
|
"flag" |
||||
|
"log" |
||||
|
) |
||||
|
|
||||
|
var gost Gost |
||||
|
|
||||
|
func init() { |
||||
|
flag.StringVar(&gost.Proxy, "P", "", "proxy for forward") |
||||
|
flag.StringVar(&gost.Saddr, "S", "", "the server that connecting to") |
||||
|
flag.StringVar(&gost.Laddr, "L", ":8080", "listen address") |
||||
|
flag.Parse() |
||||
|
|
||||
|
log.SetFlags(log.LstdFlags | log.Lshortfile) |
||||
|
} |
||||
|
|
||||
|
func main() { |
||||
|
log.Fatal(gost.Run()) |
||||
|
} |
||||
@ -0,0 +1,167 @@ |
|||||
|
package main |
||||
|
|
||||
|
import ( |
||||
|
"encoding/binary" |
||||
|
"errors" |
||||
|
"io" |
||||
|
"net" |
||||
|
) |
||||
|
|
||||
|
const ( |
||||
|
Ver5 = 5 |
||||
|
) |
||||
|
|
||||
|
const ( |
||||
|
MethodNoAuth uint8 = iota |
||||
|
MethodGSSAPI |
||||
|
MethodUserPass |
||||
|
// X'03' to X'7F' IANA ASSIGNED
|
||||
|
// X'80' to X'FE' RESERVED FOR PRIVATE METHODS
|
||||
|
MethodNoAcceptable = 0xFF |
||||
|
) |
||||
|
|
||||
|
const ( |
||||
|
CmdConnect uint8 = 1 |
||||
|
CmdBind = 2 |
||||
|
CmdUdp = 3 |
||||
|
) |
||||
|
|
||||
|
const ( |
||||
|
AddrIPv4 uint8 = 1 |
||||
|
AddrDomain = 3 |
||||
|
AddrIPv6 = 4 |
||||
|
) |
||||
|
|
||||
|
const ( |
||||
|
Succeeded uint8 = iota |
||||
|
Failure |
||||
|
NotAllowed |
||||
|
NetUnreachable |
||||
|
HostUnreachable |
||||
|
ConnRefused |
||||
|
TTLExpired |
||||
|
CmdUnsupported |
||||
|
AddrUnsupported |
||||
|
) |
||||
|
|
||||
|
var ( |
||||
|
ErrBadVersion = errors.New("Bad version") |
||||
|
ErrBadFormat = errors.New("Bad format") |
||||
|
ErrBadAddrType = errors.New("Bad address type") |
||||
|
ErrShortBuffer = errors.New("Short buffer") |
||||
|
|
||||
|
cmdErrMap = map[uint8]error{ |
||||
|
Failure: errors.New("General SOCKS server failure"), |
||||
|
NotAllowed: errors.New("Connection not allowed by ruleset"), |
||||
|
NetUnreachable: errors.New("Network unreachable"), |
||||
|
HostUnreachable: errors.New("Host unreachable"), |
||||
|
ConnRefused: errors.New("Connection refused"), |
||||
|
TTLExpired: errors.New("TTL expired"), |
||||
|
CmdUnsupported: errors.New("Command not supported"), |
||||
|
AddrUnsupported: errors.New("Address type not supported"), |
||||
|
} |
||||
|
) |
||||
|
|
||||
|
/* |
||||
|
+----+-----+-------+------+----------+----------+ |
||||
|
|VER | CMD | RSV | ATYP | DST.ADDR | DST.PORT | |
||||
|
+----+-----+-------+------+----------+----------+ |
||||
|
| 1 | 1 | X'00' | 1 | Variable | 2 | |
||||
|
+----+-----+-------+------+----------+----------+ |
||||
|
*/ |
||||
|
type Cmd struct { |
||||
|
Cmd uint8 |
||||
|
AddrType uint8 |
||||
|
Addr string |
||||
|
Port uint16 |
||||
|
} |
||||
|
|
||||
|
func NewCmd(cmd uint8, atype uint8, addr string, port uint16) *Cmd { |
||||
|
return &Cmd{ |
||||
|
Cmd: cmd, |
||||
|
AddrType: atype, |
||||
|
Addr: addr, |
||||
|
Port: port, |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
func ReadCmd(r io.Reader) (*Cmd, error) { |
||||
|
b := make([]byte, 256) |
||||
|
n, err := r.Read(b) |
||||
|
if err != nil { |
||||
|
return nil, err |
||||
|
} |
||||
|
if n < 10 { |
||||
|
return nil, ErrBadFormat |
||||
|
} |
||||
|
if b[0] != Ver5 { |
||||
|
return nil, ErrBadVersion |
||||
|
} |
||||
|
|
||||
|
cmd := &Cmd{ |
||||
|
Cmd: b[1], |
||||
|
AddrType: b[3], |
||||
|
} |
||||
|
|
||||
|
pos := 4 |
||||
|
|
||||
|
switch cmd.AddrType { |
||||
|
case AddrIPv4: |
||||
|
if n != 10 { |
||||
|
return nil, ErrBadFormat |
||||
|
} |
||||
|
cmd.Addr = net.IP(b[pos : pos+4]).String() |
||||
|
pos += 4 |
||||
|
case AddrIPv6: |
||||
|
if n != 22 { |
||||
|
return nil, ErrBadFormat |
||||
|
} |
||||
|
cmd.Addr = net.IP(b[pos : pos+16]).String() |
||||
|
pos += 16 |
||||
|
case AddrDomain: |
||||
|
length := int(b[pos]) |
||||
|
if n != 4+1+length+2 { |
||||
|
return nil, ErrBadFormat |
||||
|
} |
||||
|
|
||||
|
pos++ |
||||
|
cmd.Addr = string(b[pos : pos+length]) |
||||
|
pos += length |
||||
|
default: |
||||
|
return nil, ErrBadAddrType |
||||
|
} |
||||
|
|
||||
|
cmd.Port = binary.BigEndian.Uint16(b[pos:]) |
||||
|
|
||||
|
return cmd, nil |
||||
|
} |
||||
|
|
||||
|
func (cmd *Cmd) Write(w io.Writer) (err error) { |
||||
|
b := make([]byte, 256) |
||||
|
|
||||
|
b[0] = Ver5 |
||||
|
b[1] = cmd.Cmd |
||||
|
b[3] = cmd.AddrType |
||||
|
pos := 4 |
||||
|
|
||||
|
switch cmd.AddrType { |
||||
|
case AddrIPv4: |
||||
|
pos += copy(b[pos:], net.ParseIP(cmd.Addr).To4()) |
||||
|
case AddrDomain: |
||||
|
b[pos] = byte(len(cmd.Addr)) |
||||
|
pos++ |
||||
|
pos += copy(b[pos:], []byte(cmd.Addr)) |
||||
|
case AddrIPv6: |
||||
|
pos += copy(b[pos:], net.ParseIP(cmd.Addr).To16()) |
||||
|
} |
||||
|
binary.BigEndian.PutUint16(b[pos:], cmd.Port) |
||||
|
pos += 2 |
||||
|
|
||||
|
_, err = w.Write(b[:pos]) |
||||
|
|
||||
|
return |
||||
|
} |
||||
|
|
||||
|
func (cmd *Cmd) GetError() error { |
||||
|
return cmdErrMap[cmd.Cmd] |
||||
|
} |
||||
Loading…
Reference in new issue