update
This commit is contained in:
parent
be75c8e182
commit
302767f68a
250
client.go
Normal file
250
client.go
Normal file
@ -0,0 +1,250 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"bytes"
|
||||||
|
"github.com/ginuerzh/gosocks5"
|
||||||
|
"github.com/shadowsocks/shadowsocks-go/shadowsocks"
|
||||||
|
"io"
|
||||||
|
"log"
|
||||||
|
"net"
|
||||||
|
"net/http"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
func listenAndServe(addr string, handler func(net.Conn)) error {
|
||||||
|
laddr, err := net.ResolveTCPAddr("tcp", addr)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
ln, err := net.ListenTCP("tcp", laddr)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer ln.Close()
|
||||||
|
|
||||||
|
for {
|
||||||
|
conn, err := ln.AcceptTCP()
|
||||||
|
if err != nil {
|
||||||
|
log.Println("accept:", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
//log.Println("accept", conn.RemoteAddr())
|
||||||
|
go handler(conn)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func handshake(conn net.Conn, methods ...uint8) (method uint8, err error) {
|
||||||
|
nm := len(methods)
|
||||||
|
if nm == 0 {
|
||||||
|
nm = 1
|
||||||
|
}
|
||||||
|
b := make([]byte, 2+nm)
|
||||||
|
b[0] = Ver5
|
||||||
|
b[1] = uint8(nm)
|
||||||
|
copy(b[2:], methods)
|
||||||
|
|
||||||
|
if _, err = conn.Write(b); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err = io.ReadFull(conn, b[:2]); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if b[0] != Ver5 {
|
||||||
|
err = gosocks5.ErrBadVersion
|
||||||
|
}
|
||||||
|
method = b[1]
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func cliHandle(conn net.Conn) {
|
||||||
|
defer conn.Close()
|
||||||
|
|
||||||
|
sconn, err := Connect(Saddr, Proxy)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer sconn.Close()
|
||||||
|
|
||||||
|
method, err := handshake(sconn, MethodAES256, gosocks5.MethodNoAuth)
|
||||||
|
if err != nil || method == gosocks5.MethodNoAcceptable {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if method == MethodAES256 {
|
||||||
|
cipher, _ := shadowsocks.NewCipher(Cipher, Password)
|
||||||
|
sconn = shadowsocks.NewConn(sconn, cipher)
|
||||||
|
}
|
||||||
|
|
||||||
|
b := make([]byte, 8192)
|
||||||
|
|
||||||
|
n, err := io.ReadAtLeast(conn, b, 2)
|
||||||
|
if err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if b[0] == gosocks5.Ver5 {
|
||||||
|
length := 2 + int(b[1])
|
||||||
|
if n < length {
|
||||||
|
if _, err := io.ReadFull(conn, b[n:length]); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := gosocks5.WriteMethod(gosocks5.MethodNoAuth, conn); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
handleSocks5(conn, sconn)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
for {
|
||||||
|
if bytes.HasSuffix(b[:n], []byte("\r\n\r\n")) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
nn, err := conn.Read(b[n:])
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
n += nn
|
||||||
|
}
|
||||||
|
|
||||||
|
req, err := http.ReadRequest(bufio.NewReader(bytes.NewReader(b[:n])))
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
handleHttp(req, conn, sconn)
|
||||||
|
}
|
||||||
|
|
||||||
|
func handleSocks5(conn net.Conn, sconn net.Conn) {
|
||||||
|
req, err := gosocks5.ReadRequest(conn)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
switch req.Cmd {
|
||||||
|
case gosocks5.CmdConnect, gosocks5.CmdBind:
|
||||||
|
if err := req.Write(sconn); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
Transport(conn, sconn)
|
||||||
|
case gosocks5.CmdUdp:
|
||||||
|
if err := req.Write(sconn); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
rep, err := gosocks5.ReadReply(sconn)
|
||||||
|
if err != nil || rep.Rep != gosocks5.Succeeded {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
uconn, err := net.ListenUDP("udp", nil)
|
||||||
|
if err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
gosocks5.NewReply(Failure, nil).Write(conn)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer uconn.Close()
|
||||||
|
|
||||||
|
addr := ToSocksAddr(uconn.LocalAddr())
|
||||||
|
addr.Host, _, _ = net.SplitHostPort(conn.LocalAddr().String())
|
||||||
|
log.Println("udp:", addr)
|
||||||
|
|
||||||
|
rep = gosocks5.NewReply(Succeeded, addr)
|
||||||
|
if err := rep.Write(conn); err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
addr.Port = req.Addr.Port
|
||||||
|
raddr, err := net.ResolveUDPAddr("udp", addr.String())
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
cliTunnelUDP(raddr, uconn, conn)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func cliTunnelUDP(raddr net.Addr, uconn *net.UDPConn, conn net.Conn) {
|
||||||
|
go func() {
|
||||||
|
udp, err := gosocks5.ReadUDPDatagram(uconn)
|
||||||
|
if err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
udp.Header.Rsv = uint16(len(udp.Data))
|
||||||
|
|
||||||
|
if err := udp.Write(conn); err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
for {
|
||||||
|
udp, err := gosocks5.ReadUDPDatagram(conn)
|
||||||
|
if err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
udp.Header.Rsv = 0
|
||||||
|
buf := &bytes.Buffer{}
|
||||||
|
udp.Write(buf)
|
||||||
|
|
||||||
|
if _, err := uconn.WriteTo(buf.Bytes(), raddr); err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func handleHttp(req *http.Request, conn net.Conn, sconn net.Conn) {
|
||||||
|
var host string
|
||||||
|
var port uint16
|
||||||
|
|
||||||
|
s := strings.Split(req.Host, ":")
|
||||||
|
host = s[0]
|
||||||
|
port = 80
|
||||||
|
if len(s) == 2 {
|
||||||
|
n, _ := strconv.ParseUint(s[1], 10, 16)
|
||||||
|
port = uint16(n)
|
||||||
|
}
|
||||||
|
|
||||||
|
addr := &gosocks5.Addr{
|
||||||
|
Type: gosocks5.AddrDomain,
|
||||||
|
Host: host,
|
||||||
|
Port: port,
|
||||||
|
}
|
||||||
|
r := gosocks5.NewRequest(gosocks5.CmdConnect, addr)
|
||||||
|
if err := r.Write(sconn); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
rep, err := gosocks5.ReadReply(sconn)
|
||||||
|
if err != nil || rep.Rep != gosocks5.Succeeded {
|
||||||
|
conn.Write([]byte("HTTP/1.1 503 Service unavailable\r\n" +
|
||||||
|
"Proxy-Agent: gost/1.0\r\n\r\n"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if req.Method == "CONNECT" {
|
||||||
|
if _, err = conn.Write(
|
||||||
|
[]byte("HTTP/1.1 200 Connection established\r\n" +
|
||||||
|
"Proxy-Agent: gost/2.0\r\n\r\n")); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if err := req.Write(sconn); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := Transport(conn, sconn); err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
}
|
||||||
|
}
|
115
gost.go
115
gost.go
@ -4,7 +4,7 @@ import (
|
|||||||
"bufio"
|
"bufio"
|
||||||
"bytes"
|
"bytes"
|
||||||
//"crypto/tls"
|
//"crypto/tls"
|
||||||
"errors"
|
//"errors"
|
||||||
"io"
|
"io"
|
||||||
//"io/ioutil"
|
//"io/ioutil"
|
||||||
"log"
|
"log"
|
||||||
@ -16,7 +16,7 @@ import (
|
|||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/shadowsocks/shadowsocks-go/shadowsocks"
|
"github.com/shadowsocks/shadowsocks-go/shadowsocks"
|
||||||
"net/url"
|
//"net/url"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -90,8 +90,8 @@ func (g *Gost) cli(conn net.Conn) {
|
|||||||
b := make([]byte, 8192)
|
b := make([]byte, 8192)
|
||||||
b[0] = 5
|
b[0] = 5
|
||||||
b[1] = 1
|
b[1] = 1
|
||||||
if gost.Cipher {
|
if len(Cipher) > 0 {
|
||||||
b[2] = 0x88
|
b[2] = MethodAES256
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err := sconn.Write(b[:3]); err != nil {
|
if _, err := sconn.Write(b[:3]); err != nil {
|
||||||
@ -107,7 +107,7 @@ func (g *Gost) cli(conn net.Conn) {
|
|||||||
}
|
}
|
||||||
lg.Logln("<<<|", b[:n])
|
lg.Logln("<<<|", b[:n])
|
||||||
|
|
||||||
if b[1] == 0x88 {
|
if b[1] == MethodAES256 {
|
||||||
cipher, _ := shadowsocks.NewCipher("aes-256-cfb", "gost")
|
cipher, _ := shadowsocks.NewCipher("aes-256-cfb", "gost")
|
||||||
sconn = shadowsocks.NewConn(sconn, cipher)
|
sconn = shadowsocks.NewConn(sconn, cipher)
|
||||||
}
|
}
|
||||||
@ -174,7 +174,7 @@ func (g *Gost) srv(conn net.Conn) {
|
|||||||
}
|
}
|
||||||
lg.Logln("|<<<", []byte{5, method})
|
lg.Logln("|<<<", []byte{5, method})
|
||||||
|
|
||||||
if method == 0x88 {
|
if method == MethodAES256 {
|
||||||
cipher, _ := shadowsocks.NewCipher("aes-256-cfb", "gost")
|
cipher, _ := shadowsocks.NewCipher("aes-256-cfb", "gost")
|
||||||
conn = shadowsocks.NewConn(conn, cipher)
|
conn = shadowsocks.NewConn(conn, cipher)
|
||||||
}
|
}
|
||||||
@ -610,109 +610,6 @@ func shadowTransfer(conn, sconn net.Conn, lg *BufferedLog) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func Connect(addr, proxy string) (net.Conn, error) {
|
|
||||||
if len(proxy) == 0 {
|
|
||||||
taddr, err := net.ResolveTCPAddr("tcp", addr)
|
|
||||||
if err != nil {
|
|
||||||
log.Println(err)
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return net.DialTCP("tcp", nil, taddr)
|
|
||||||
}
|
|
||||||
|
|
||||||
paddr, err := net.ResolveTCPAddr("tcp", proxy)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
pconn, err := net.DialTCP("tcp", nil, paddr)
|
|
||||||
if err != nil {
|
|
||||||
log.Println(err)
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
header := http.Header{}
|
|
||||||
header.Set("Proxy-Connection", "keep-alive")
|
|
||||||
req := &http.Request{
|
|
||||||
Method: "CONNECT",
|
|
||||||
URL: &url.URL{Host: addr},
|
|
||||||
Host: addr,
|
|
||||||
Header: header,
|
|
||||||
}
|
|
||||||
if err := req.Write(pconn); err != nil {
|
|
||||||
log.Println(err)
|
|
||||||
pconn.Close()
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
resp, err := http.ReadResponse(bufio.NewReader(pconn), req)
|
|
||||||
if err != nil {
|
|
||||||
log.Println(err)
|
|
||||||
pconn.Close()
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if resp.StatusCode != http.StatusOK {
|
|
||||||
pconn.Close()
|
|
||||||
return nil, errors.New(resp.Status)
|
|
||||||
}
|
|
||||||
|
|
||||||
return pconn, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func Copy(dst io.Writer, src io.Reader) (written int64, err error) {
|
|
||||||
buf := make([]byte, 32*1024)
|
|
||||||
for {
|
|
||||||
nr, er := src.Read(buf)
|
|
||||||
//log.Println("cp r", nr, er)
|
|
||||||
if nr > 0 {
|
|
||||||
nw, ew := dst.Write(buf[:nr])
|
|
||||||
//log.Println("cp w", nw, ew)
|
|
||||||
if nw > 0 {
|
|
||||||
written += int64(nw)
|
|
||||||
}
|
|
||||||
if ew != nil {
|
|
||||||
err = ew
|
|
||||||
break
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
if nr != nw {
|
|
||||||
err = io.ErrShortWrite
|
|
||||||
break
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
if er == io.EOF {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
if er != nil {
|
|
||||||
err = er
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func Pipe(src io.Reader, dst io.Writer, c chan<- error) {
|
|
||||||
_, err := Copy(dst, src)
|
|
||||||
c <- err
|
|
||||||
}
|
|
||||||
|
|
||||||
func Transport(conn, conn2 net.Conn) (err error) {
|
|
||||||
rChan := make(chan error, 1)
|
|
||||||
wChan := make(chan error, 1)
|
|
||||||
|
|
||||||
go Pipe(conn, conn2, wChan)
|
|
||||||
go Pipe(conn2, conn, rChan)
|
|
||||||
|
|
||||||
select {
|
|
||||||
case err = <-wChan:
|
|
||||||
//log.Println("w exit", err)
|
|
||||||
case err = <-rChan:
|
|
||||||
//log.Println("r exit", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func getRequest(conn net.Conn) (addrType uint8, addr string, port uint16, extra []byte, err error) {
|
func getRequest(conn net.Conn) (addrType uint8, addr string, port uint16, extra []byte, err error) {
|
||||||
const (
|
const (
|
||||||
idType = 0 // address type index
|
idType = 0 // address type index
|
||||||
|
31
main.go
31
main.go
@ -3,17 +3,23 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"flag"
|
"flag"
|
||||||
|
"github.com/ginuerzh/gosocks5"
|
||||||
"log"
|
"log"
|
||||||
)
|
)
|
||||||
|
|
||||||
var gost Gost
|
var (
|
||||||
|
Laddr, Saddr, Proxy string
|
||||||
|
Shadows bool
|
||||||
|
Cipher, Password string
|
||||||
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
flag.StringVar(&gost.Proxy, "P", "", "proxy for forward")
|
flag.StringVar(&Proxy, "P", "", "proxy for forward")
|
||||||
flag.StringVar(&gost.Saddr, "S", "", "the server that connecting to")
|
flag.StringVar(&Saddr, "S", "", "the server that connecting to")
|
||||||
flag.StringVar(&gost.Laddr, "L", ":8080", "listen address")
|
flag.StringVar(&Laddr, "L", ":8080", "listen address")
|
||||||
flag.BoolVar(&gost.Cipher, "cipher", true, "cipher transfer data")
|
flag.StringVar(&Cipher, "cipher", "rc4-md5", "cipher method")
|
||||||
flag.BoolVar(&gost.Shadows, "ss", false, "shadowsocks compatible")
|
flag.StringVar(&Password, "password", "20150327", "cipher password")
|
||||||
|
flag.BoolVar(&Shadows, "ss", false, "shadowsocks compatible")
|
||||||
flag.BoolVar(&Debug, "d", false, "debug option")
|
flag.BoolVar(&Debug, "d", false, "debug option")
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
|
|
||||||
@ -21,5 +27,16 @@ func init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
log.Fatal(gost.Run())
|
//log.Fatal(gost.Run())
|
||||||
|
if len(Saddr) == 0 {
|
||||||
|
srv := &gosocks5.Server{
|
||||||
|
Addr: Laddr,
|
||||||
|
SelectMethod: selectMethod,
|
||||||
|
Handle: srvHandle,
|
||||||
|
}
|
||||||
|
log.Fatal(srv.ListenAndServe())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Fatal(listenAndServe(Laddr, cliHandle))
|
||||||
}
|
}
|
||||||
|
150
server.go
Normal file
150
server.go
Normal file
@ -0,0 +1,150 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/ginuerzh/gosocks5"
|
||||||
|
"github.com/shadowsocks/shadowsocks-go/shadowsocks"
|
||||||
|
"net"
|
||||||
|
//"strconv"
|
||||||
|
"log"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
MethodAES256 uint8 = 0x88
|
||||||
|
)
|
||||||
|
|
||||||
|
func selectMethod(methods ...uint8) uint8 {
|
||||||
|
for _, method := range methods {
|
||||||
|
if method == MethodAES256 {
|
||||||
|
return method
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return gosocks5.MethodNoAcceptable
|
||||||
|
}
|
||||||
|
|
||||||
|
func srvHandle(conn net.Conn, method uint8) {
|
||||||
|
defer conn.Close()
|
||||||
|
|
||||||
|
if method == gosocks5.MethodNoAcceptable {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if method == MethodAES256 {
|
||||||
|
cipher, _ := shadowsocks.NewCipher(Cipher, Password)
|
||||||
|
conn = shadowsocks.NewConn(conn, cipher)
|
||||||
|
}
|
||||||
|
|
||||||
|
req, err := gosocks5.ReadRequest(conn)
|
||||||
|
if err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
switch req.Cmd {
|
||||||
|
case gosocks5.CmdConnect:
|
||||||
|
log.Println("connect", req.Addr.String())
|
||||||
|
tconn, err := Connect(req.Addr.String(), Proxy)
|
||||||
|
if err != nil {
|
||||||
|
gosocks5.NewReply(gosocks5.HostUnreachable, nil).Write(conn)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer tconn.Close()
|
||||||
|
|
||||||
|
rep := gosocks5.NewReply(gosocks5.Succeeded, nil)
|
||||||
|
if err := rep.Write(conn); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := Transport(conn, tconn); err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
}
|
||||||
|
case gosocks5.CmdBind:
|
||||||
|
l, err := net.ListenTCP("tcp", nil)
|
||||||
|
if err != nil {
|
||||||
|
gosocks5.NewReply(gosocks5.Failure, nil).Write(conn)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
addr := ToSocksAddr(l.Addr())
|
||||||
|
addr.Host, _, _ = net.SplitHostPort(conn.LocalAddr().String())
|
||||||
|
log.Println("bind:", addr)
|
||||||
|
rep := gosocks5.NewReply(gosocks5.Succeeded, addr)
|
||||||
|
if err := rep.Write(conn); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
tconn, err := l.AcceptTCP()
|
||||||
|
if err != nil {
|
||||||
|
log.Println("accept:", err)
|
||||||
|
gosocks5.NewReply(gosocks5.Failure, nil).Write(conn)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer tconn.Close()
|
||||||
|
l.Close()
|
||||||
|
|
||||||
|
addr = ToSocksAddr(tconn.RemoteAddr())
|
||||||
|
rep = gosocks5.NewReply(gosocks5.Succeeded, addr)
|
||||||
|
if err := rep.Write(conn); err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := Transport(conn, tconn); err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
}
|
||||||
|
case gosocks5.CmdUdp:
|
||||||
|
uconn, err := net.ListenUDP("udp", nil)
|
||||||
|
if err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
gosocks5.NewReply(Failure, nil).Write(conn)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer uconn.Close()
|
||||||
|
|
||||||
|
addr := ToSocksAddr(uconn.LocalAddr())
|
||||||
|
addr.Host, _, _ = net.SplitHostPort(conn.LocalAddr().String())
|
||||||
|
log.Println("udp:", addr)
|
||||||
|
rep := gosocks5.NewReply(Succeeded, addr)
|
||||||
|
if err := rep.Write(conn); err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
srvTunnelUDP(conn, uconn)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func srvTunnelUDP(conn net.Conn, uconn *net.UDPConn) {
|
||||||
|
go func() {
|
||||||
|
b := make([]byte, 65535)
|
||||||
|
n, addr, err := uconn.ReadFromUDP(b)
|
||||||
|
if err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
udp := gosocks5.NewUDPDatagram(
|
||||||
|
gosocks5.NewUDPHeader(uint16(n), 0, ToSocksAddr(addr)), b[:n])
|
||||||
|
if err := udp.Write(conn); err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
for {
|
||||||
|
ud, err := gosocks5.ReadUDPDatagram(conn)
|
||||||
|
if err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
addr, err := net.ResolveUDPAddr("udp", ud.Header.Addr.String())
|
||||||
|
if err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
continue // drop silently
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err := uconn.WriteToUDP(ud.Data, addr); err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
11
socks5.go
11
socks5.go
@ -52,17 +52,6 @@ var (
|
|||||||
ErrBadFormat = errors.New("Bad format")
|
ErrBadFormat = errors.New("Bad format")
|
||||||
ErrBadAddrType = errors.New("Bad address type")
|
ErrBadAddrType = errors.New("Bad address type")
|
||||||
ErrShortBuffer = errors.New("Short buffer")
|
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"),
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
129
util.go
Normal file
129
util.go
Normal file
@ -0,0 +1,129 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
//"bytes"
|
||||||
|
"errors"
|
||||||
|
"github.com/ginuerzh/gosocks5"
|
||||||
|
"io"
|
||||||
|
"log"
|
||||||
|
"net"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"strconv"
|
||||||
|
)
|
||||||
|
|
||||||
|
func ToSocksAddr(addr net.Addr) *gosocks5.Addr {
|
||||||
|
host, port, _ := net.SplitHostPort(addr.String())
|
||||||
|
p, _ := strconv.Atoi(port)
|
||||||
|
|
||||||
|
return &gosocks5.Addr{
|
||||||
|
Type: AddrIPv4,
|
||||||
|
Host: host,
|
||||||
|
Port: uint16(p),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Connect(addr, proxy string) (net.Conn, error) {
|
||||||
|
if len(proxy) == 0 {
|
||||||
|
taddr, err := net.ResolveTCPAddr("tcp", addr)
|
||||||
|
if err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return net.DialTCP("tcp", nil, taddr)
|
||||||
|
}
|
||||||
|
|
||||||
|
paddr, err := net.ResolveTCPAddr("tcp", proxy)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
pconn, err := net.DialTCP("tcp", nil, paddr)
|
||||||
|
if err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
header := http.Header{}
|
||||||
|
header.Set("Proxy-Connection", "keep-alive")
|
||||||
|
req := &http.Request{
|
||||||
|
Method: "CONNECT",
|
||||||
|
URL: &url.URL{Host: addr},
|
||||||
|
Host: addr,
|
||||||
|
Header: header,
|
||||||
|
}
|
||||||
|
if err := req.Write(pconn); err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
pconn.Close()
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := http.ReadResponse(bufio.NewReader(pconn), req)
|
||||||
|
if err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
pconn.Close()
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if resp.StatusCode != http.StatusOK {
|
||||||
|
pconn.Close()
|
||||||
|
return nil, errors.New(resp.Status)
|
||||||
|
}
|
||||||
|
|
||||||
|
return pconn, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// based on io.Copy
|
||||||
|
func Copy(dst io.Writer, src io.Reader) (written int64, err error) {
|
||||||
|
buf := make([]byte, 32*1024)
|
||||||
|
for {
|
||||||
|
nr, er := src.Read(buf)
|
||||||
|
//log.Println("cp r", nr, er)
|
||||||
|
if nr > 0 {
|
||||||
|
nw, ew := dst.Write(buf[:nr])
|
||||||
|
//log.Println("cp w", nw, ew)
|
||||||
|
if nw > 0 {
|
||||||
|
written += int64(nw)
|
||||||
|
}
|
||||||
|
if ew != nil {
|
||||||
|
err = ew
|
||||||
|
break
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
if nr != nw {
|
||||||
|
err = io.ErrShortWrite
|
||||||
|
break
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
if er == io.EOF {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if er != nil {
|
||||||
|
err = er
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func Pipe(src io.Reader, dst io.Writer, c chan<- error) {
|
||||||
|
_, err := Copy(dst, src)
|
||||||
|
c <- err
|
||||||
|
}
|
||||||
|
|
||||||
|
func Transport(conn, conn2 net.Conn) (err error) {
|
||||||
|
rChan := make(chan error, 1)
|
||||||
|
wChan := make(chan error, 1)
|
||||||
|
|
||||||
|
go Pipe(conn, conn2, wChan)
|
||||||
|
go Pipe(conn2, conn, rChan)
|
||||||
|
|
||||||
|
select {
|
||||||
|
case err = <-wChan:
|
||||||
|
//log.Println("w exit", err)
|
||||||
|
case err = <-rChan:
|
||||||
|
//log.Println("r exit", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user