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