support websocket
This commit is contained in:
parent
c10cbe438f
commit
9ef10b90a9
124
client.go
124
client.go
@ -7,9 +7,11 @@ import (
|
|||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/ginuerzh/gosocks5"
|
"github.com/ginuerzh/gosocks5"
|
||||||
|
"github.com/gorilla/websocket"
|
||||||
"github.com/shadowsocks/shadowsocks-go/shadowsocks"
|
"github.com/shadowsocks/shadowsocks-go/shadowsocks"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
"net/url"
|
||||||
"log"
|
"log"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
@ -18,7 +20,12 @@ import (
|
|||||||
//"sync/atomic"
|
//"sync/atomic"
|
||||||
)
|
)
|
||||||
|
|
||||||
var sessionCount int64
|
var (
|
||||||
|
sessionCount int64
|
||||||
|
clientConfig = &gosocks5.Config{
|
||||||
|
MethodSelected: clientMethodSelected,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
func listenAndServe(addr string, handler func(net.Conn)) error {
|
func listenAndServe(addr string, handler func(net.Conn)) error {
|
||||||
laddr, err := net.ResolveTCPAddr("tcp", addr)
|
laddr, err := net.ResolveTCPAddr("tcp", addr)
|
||||||
@ -32,6 +39,12 @@ func listenAndServe(addr string, handler func(net.Conn)) error {
|
|||||||
}
|
}
|
||||||
defer ln.Close()
|
defer ln.Close()
|
||||||
|
|
||||||
|
for m, v := range Methods {
|
||||||
|
if Method == v {
|
||||||
|
clientConfig.Methods = []uint8{m}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for {
|
for {
|
||||||
conn, err := ln.AcceptTCP()
|
conn, err := ln.AcceptTCP()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -43,33 +56,21 @@ func listenAndServe(addr string, handler func(net.Conn)) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func handshake(conn net.Conn, methods ...uint8) (method uint8, err error) {
|
func clientMethodSelected(method uint8, conn net.Conn) (net.Conn, error) {
|
||||||
nm := len(methods)
|
switch method {
|
||||||
if nm == 0 {
|
case MethodTLS:
|
||||||
nm = 1
|
conn = tls.Client(conn, &tls.Config{InsecureSkipVerify: true})
|
||||||
}
|
case MethodAES128, MethodAES192, MethodAES256,
|
||||||
b := spool.Take()
|
MethodDES, MethodBF, MethodCAST5, MethodRC4MD5, MethodRC4, MethodTable:
|
||||||
defer spool.put(b)
|
cipher, _ := shadowsocks.NewCipher(Methods[method], Password)
|
||||||
|
conn = shadowsocks.NewConn(conn, cipher)
|
||||||
b = b[:2+nm]
|
case gosocks5.MethodNoAcceptable:
|
||||||
b[0] = gosocks5.Ver5
|
fallthrough
|
||||||
b[1] = uint8(nm)
|
default:
|
||||||
copy(b[2:], methods)
|
return nil, gosocks5.ErrBadMethod
|
||||||
|
|
||||||
if _, err = conn.Write(b); err != nil {
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err = io.ReadFull(conn, b[:2]); err != nil {
|
return conn, nil
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if b[0] != gosocks5.Ver5 {
|
|
||||||
err = gosocks5.ErrBadVersion
|
|
||||||
}
|
|
||||||
method = b[1]
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func cliHandle(conn net.Conn) {
|
func cliHandle(conn net.Conn) {
|
||||||
@ -80,40 +81,59 @@ func cliHandle(conn net.Conn) {
|
|||||||
fmt.Println("session end", atomic.AddInt64(&sessionCount, -1))
|
fmt.Println("session end", atomic.AddInt64(&sessionCount, -1))
|
||||||
}()
|
}()
|
||||||
*/
|
*/
|
||||||
|
addr := Saddr
|
||||||
sconn, err := Connect(Saddr, Proxy)
|
if strings.HasPrefix(addr, "http://") {
|
||||||
if err != nil {
|
u, err := url.Parse(addr)
|
||||||
return
|
if err != nil {
|
||||||
}
|
log.Println(err)
|
||||||
defer sconn.Close()
|
return
|
||||||
|
}
|
||||||
method := gosocks5.MethodNoAuth
|
addr = u.Host
|
||||||
for m, v := range Methods {
|
if !strings.Contains(addr, ":") {
|
||||||
if Method == v {
|
addr += ":80"
|
||||||
method = m
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if strings.HasPrefix(addr, "https://") {
|
||||||
method, err = handshake(sconn, method)
|
u, err := url.Parse(addr)
|
||||||
|
if err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
addr = u.Host
|
||||||
|
if !strings.Contains(addr, ":") {
|
||||||
|
addr += ":443"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
log.Println("connect:", addr)
|
||||||
|
c, err := Connect(addr, Proxy)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
log.Println(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
defer c.Close()
|
||||||
|
|
||||||
|
if Websocket {
|
||||||
|
u, err := url.Parse(addr)
|
||||||
|
if err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ws, resp, err := websocket.NewClient(c, u, nil, 8192, 8192)
|
||||||
|
if err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
resp.Body.Close()
|
||||||
|
|
||||||
|
c = NewWSConn(ws)
|
||||||
|
}
|
||||||
|
|
||||||
switch method {
|
c = gosocks5.ClientConn(c, clientConfig)
|
||||||
case MethodTLS:
|
|
||||||
sconn = tls.Client(sconn, &tls.Config{InsecureSkipVerify: true})
|
|
||||||
case MethodAES128, MethodAES192, MethodAES256,
|
|
||||||
MethodDES, MethodBF, MethodCAST5, MethodRC4MD5, MethodRC4, MethodTable:
|
|
||||||
cipher, _ := shadowsocks.NewCipher(Methods[method], Password)
|
|
||||||
sconn = shadowsocks.NewConn(sconn, cipher)
|
|
||||||
case gosocks5.MethodNoAcceptable:
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if Shadows {
|
if Shadows {
|
||||||
cipher, _ := shadowsocks.NewCipher(SMethod, SPassword)
|
cipher, _ := shadowsocks.NewCipher(SMethod, SPassword)
|
||||||
conn = shadowsocks.NewConn(conn, cipher)
|
conn = shadowsocks.NewConn(conn, cipher)
|
||||||
handleShadow(conn, sconn)
|
handleShadow(conn, c)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -138,7 +158,7 @@ func cliHandle(conn net.Conn) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
handleSocks5(conn, sconn)
|
handleSocks5(conn, c)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -158,7 +178,7 @@ func cliHandle(conn net.Conn) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
handleHttp(req, conn, sconn)
|
handleHttp(req, conn, c)
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleSocks5(conn net.Conn, sconn net.Conn) {
|
func handleSocks5(conn net.Conn, sconn net.Conn) {
|
||||||
|
16
main.go
16
main.go
@ -3,13 +3,14 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"flag"
|
"flag"
|
||||||
"github.com/ginuerzh/gosocks5"
|
//"github.com/ginuerzh/gosocks5"
|
||||||
"log"
|
"log"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
Laddr, Saddr, Proxy string
|
Laddr, Saddr, Proxy string
|
||||||
|
Websocket bool
|
||||||
Shadows bool
|
Shadows bool
|
||||||
SMethod, SPassword string
|
SMethod, SPassword string
|
||||||
Method, Password string
|
Method, Password string
|
||||||
@ -25,6 +26,7 @@ func init() {
|
|||||||
flag.StringVar(&CertFile, "cert", "", "cert file for tls")
|
flag.StringVar(&CertFile, "cert", "", "cert file for tls")
|
||||||
flag.StringVar(&KeyFile, "key", "", "key file for tls")
|
flag.StringVar(&KeyFile, "key", "", "key file for tls")
|
||||||
flag.BoolVar(&Shadows, "ss", false, "run as shadowsocks server")
|
flag.BoolVar(&Shadows, "ss", false, "run as shadowsocks server")
|
||||||
|
flag.BoolVar(&Websocket, "ws", false, "use websocket for tunnel")
|
||||||
flag.StringVar(&SMethod, "sm", "rc4-md5", "shadowsocks cipher method")
|
flag.StringVar(&SMethod, "sm", "rc4-md5", "shadowsocks cipher method")
|
||||||
flag.StringVar(&SPassword, "sp", "ginuerzh@gmail.com", "shadowsocks cipher password")
|
flag.StringVar(&SPassword, "sp", "ginuerzh@gmail.com", "shadowsocks cipher password")
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
@ -41,13 +43,13 @@ var (
|
|||||||
func main() {
|
func main() {
|
||||||
//log.Fatal(gost.Run())
|
//log.Fatal(gost.Run())
|
||||||
if len(Saddr) == 0 {
|
if len(Saddr) == 0 {
|
||||||
srv := &gosocks5.Server{
|
var server Server
|
||||||
Addr: Laddr,
|
if Websocket {
|
||||||
SelectMethod: selectMethod,
|
server = &WSServer{Addr: Laddr}
|
||||||
MethodSelected: methodSelected,
|
} else {
|
||||||
Handle: srvHandle,
|
server = &Socks5Server{Addr: Laddr}
|
||||||
}
|
}
|
||||||
log.Fatal(srv.ListenAndServe())
|
log.Fatal(server.ListenAndServe())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
221
server.go
221
server.go
@ -1,223 +1,6 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
type Server interface {
|
||||||
"github.com/ginuerzh/gosocks5"
|
ListenAndServe() error
|
||||||
"github.com/shadowsocks/shadowsocks-go/shadowsocks"
|
|
||||||
"net"
|
|
||||||
//"strconv"
|
|
||||||
"crypto/tls"
|
|
||||||
"log"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
rawCert = `-----BEGIN CERTIFICATE-----
|
|
||||||
MIIC5jCCAdCgAwIBAgIBADALBgkqhkiG9w0BAQUwEjEQMA4GA1UEChMHQWNtZSBD
|
|
||||||
bzAeFw0xNDAzMTcwNjIwNTFaFw0xNTAzMTcwNjIwNTFaMBIxEDAOBgNVBAoTB0Fj
|
|
||||||
bWUgQ28wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDccNO1xmd4lWSf
|
|
||||||
d/0/QS3E93cYIWHw831i/IKxigdRD/XMZonLdEHywW6lOiXazaP8e6CqPGSmnl0x
|
|
||||||
5k/3dvGCMj2JCVxM6+z7NpL+AiwvXmvkj/TOciCgwqssCwYS2CiVwjfazRjx1ZUJ
|
|
||||||
VDC5qiyRsfktQ2fVHrpnJGVSRagmiQgwGWBilVG9B8QvRtpQKN/GQGq17oIQm8aK
|
|
||||||
kOdPt93g93ojMIg7YJpgDgOirvVz/hDn7YD4ryrtPos9CMafFkJprymKpRHyvz7P
|
|
||||||
8a3+OkuPjFjPnwOHQ5u1U3+8vC44vfb1ExWzDLoT8Xp8Gndx39k0f7MVOol3GnYu
|
|
||||||
MN/dvNUdAgMBAAGjSzBJMA4GA1UdDwEB/wQEAwIAoDATBgNVHSUEDDAKBggrBgEF
|
|
||||||
BQcDATAMBgNVHRMBAf8EAjAAMBQGA1UdEQQNMAuCCWxvY2FsaG9zdDALBgkqhkiG
|
|
||||||
9w0BAQUDggEBAIG8CJqvTIgJnNOK+i5/IUc/3yF/mSCWuG8qP+Fmo2t6T0PVOtc0
|
|
||||||
8wiWH5iWtCAhjn0MRY9l/hIjWm6gUZGHCGuEgsOPpJDYGoNLjH9Xwokm4y3LFNRK
|
|
||||||
UBrrrDbKRNibApBHCapPf6gC5sXcjOwx7P2/kiHDgY7YH47jfcRhtAPNsM4gjsEO
|
|
||||||
RmwENY+hRUFHIRfQTyalqND+x6PWhRo3K6hpHs4DQEYPq4P2kFPqUqSBymH+Ny5/
|
|
||||||
BcQ3wdMNmC6Bm/oiL1QV0M+/InOsAgQk/EDd0kmoU1ZT2lYHQduGmP099bOlHNpS
|
|
||||||
uqO3vXF3q8SPPr/A9TqSs7BKkBQbe0+cdsA=
|
|
||||||
-----END CERTIFICATE-----`
|
|
||||||
|
|
||||||
rawKey = `-----BEGIN RSA PRIVATE KEY-----
|
|
||||||
MIIEowIBAAKCAQEA3HDTtcZneJVkn3f9P0EtxPd3GCFh8PN9YvyCsYoHUQ/1zGaJ
|
|
||||||
y3RB8sFupTol2s2j/Hugqjxkpp5dMeZP93bxgjI9iQlcTOvs+zaS/gIsL15r5I/0
|
|
||||||
znIgoMKrLAsGEtgolcI32s0Y8dWVCVQwuaoskbH5LUNn1R66ZyRlUkWoJokIMBlg
|
|
||||||
YpVRvQfEL0baUCjfxkBqte6CEJvGipDnT7fd4Pd6IzCIO2CaYA4Doq71c/4Q5+2A
|
|
||||||
+K8q7T6LPQjGnxZCaa8piqUR8r8+z/Gt/jpLj4xYz58Dh0ObtVN/vLwuOL329RMV
|
|
||||||
swy6E/F6fBp3cd/ZNH+zFTqJdxp2LjDf3bzVHQIDAQABAoIBAHal26147nQ+pHwY
|
|
||||||
jxwers3XDCjWvup7g79lfcqlKi79UiUEA6KYHm7UogMYewt7p4nb2KwH+XycvDiB
|
|
||||||
aAUf5flXpTs+6IkWauUDiLZi4PlV7uiEexUq5FjirlL0U/6MjbudX4bK4WQ4uxDc
|
|
||||||
WaV07Kw2iJFOOHLDKT0en9JaX5jtJNc4ZnE9efFoQ5jfypPWtRw65G1rULEg6nvc
|
|
||||||
GDh+1ce+4foCkpLRC9c24xAwJONZG6x3UqrSS9qfAsb73nWRQrTfUcO3nhoN8VvL
|
|
||||||
kL9skn1+S06NyUN0KoEtyRBp+RcpXSsBWAo6qZmo/WqhB/gjzWrxVwn20+yJSm35
|
|
||||||
ZsMc6QECgYEA8GS+Mp9xfB2szWHz6YTOO1Uu4lHM1ccZMwS1G+dL0KO3uGAiPdvp
|
|
||||||
woVot6v6w88t7onXsLo5pgz7SYug0CpkF3K/MRd1Ar4lH7PK7IBQ6rFr9ppVxDbx
|
|
||||||
AEWRswUoPbKCr7W6HU8LbQHDavsDlEIwc6+DiwnL4BzlKjb7RpgQEz0CgYEA6sB5
|
|
||||||
uHvx3Y5FDcGk1n73leQSAcq14l3ZLNpjrs8msoREDil/j5WmuSN58/7PGMiMgHEi
|
|
||||||
1vLm3H796JmvGr9OBvspOjHyk07ui2/We/j9Hoxm1VWhyi8HkLNDj70HKalTTFMz
|
|
||||||
RHO4O+0xCva+h9mKZrRMVktXr2jjdFn/0MYIZ2ECgYAIIsC1IeRLWQ3CHbCNlKsO
|
|
||||||
IwHlMvOFwKk/qsceXKOaOhA7szU1dr3gkXdL0Aw6mEZrrkqYdpUA46uVf54/rU+Z
|
|
||||||
445I8QxKvXiwK/uQKX+TkdGflPWWIG3jnnch4ejMvb/ihnn4B/bRB6A/fKNQXzUY
|
|
||||||
lTYUfI5j1VaEKTwz1W2l2QKBgByFCcSp+jZqhGUpc3dDsZyaOr3Q/Mvlju7uEVI5
|
|
||||||
hIAHpaT60a6GBd1UPAqymEJwivFHzW3D0NxU6VAK68UaHMaoWNfjHY9b9YsnKS2i
|
|
||||||
kE3XzN56Ks+/avHfdYPO+UHMenw5V28nh+hv5pdoZrlmanQTz3pkaOC8o3WNQZEB
|
|
||||||
nh/BAoGBAMY5z2f1pmMhrvtPDSlEVjgjELbaInxFaxPLR4Pdyzn83gtIIU14+R8X
|
|
||||||
2LPs6PPwrNjWnIgrUSVXncIFL3pa45B+Mx1pYCpOAB1+nCZjIBQmpeo4Y0dwA/XH
|
|
||||||
85EthKPvoszm+OPbyI16OcePV5ocX7lupRYuAo0pek7bomhmHWHz
|
|
||||||
-----END RSA PRIVATE KEY-----`
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
func selectMethod(methods ...uint8) uint8 {
|
|
||||||
for _, method := range methods {
|
|
||||||
if _, ok := Methods[method]; ok {
|
|
||||||
return method
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return gosocks5.MethodNoAuth
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func methodSelected(method uint8, conn net.Conn) (net.Conn, error) {
|
|
||||||
switch method {
|
|
||||||
case MethodTLS:
|
|
||||||
var cert tls.Certificate
|
|
||||||
var err error
|
|
||||||
|
|
||||||
if len(CertFile) == 0 || len(KeyFile) == 0 {
|
|
||||||
cert, err = tls.X509KeyPair([]byte(rawCert), []byte(rawKey))
|
|
||||||
} else {
|
|
||||||
cert, err = tls.LoadX509KeyPair(CertFile, KeyFile)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
log.Println(err)
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
conn = tls.Server(conn, &tls.Config{Certificates: []tls.Certificate{cert}})
|
|
||||||
case MethodAES128, MethodAES192, MethodAES256,
|
|
||||||
MethodDES, MethodBF, MethodCAST5, MethodRC4MD5, MethodRC4, MethodTable:
|
|
||||||
cipher, err := shadowsocks.NewCipher(Methods[method], Password)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
conn = shadowsocks.NewConn(conn, cipher)
|
|
||||||
case gosocks5.MethodNoAcceptable:
|
|
||||||
return nil, gosocks5.ErrBadMethod
|
|
||||||
}
|
|
||||||
|
|
||||||
return conn, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func srvHandle(conn net.Conn) {
|
|
||||||
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())
|
|
||||||
log.Println("accept peer:", addr.String())
|
|
||||||
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(gosocks5.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(gosocks5.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 := lpool.Take()
|
|
||||||
defer lpool.put(b)
|
|
||||||
|
|
||||||
for {
|
|
||||||
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])
|
|
||||||
//log.Println("r", udp.Header)
|
|
||||||
if err := udp.Write(conn); err != nil {
|
|
||||||
log.Println(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
for {
|
|
||||||
udp, err := gosocks5.ReadUDPDatagram(conn)
|
|
||||||
if err != nil {
|
|
||||||
log.Println(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
//log.Println("w", udp.Header)
|
|
||||||
addr, err := net.ResolveUDPAddr("udp", udp.Header.Addr.String())
|
|
||||||
if err != nil {
|
|
||||||
log.Println(err)
|
|
||||||
continue // drop silently
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, err := uconn.WriteToUDP(udp.Data, addr); err != nil {
|
|
||||||
log.Println(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
261
socks5.go
Normal file
261
socks5.go
Normal file
@ -0,0 +1,261 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/ginuerzh/gosocks5"
|
||||||
|
"github.com/shadowsocks/shadowsocks-go/shadowsocks"
|
||||||
|
"net"
|
||||||
|
//"strconv"
|
||||||
|
"crypto/tls"
|
||||||
|
"log"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
rawCert = `-----BEGIN CERTIFICATE-----
|
||||||
|
MIIC5jCCAdCgAwIBAgIBADALBgkqhkiG9w0BAQUwEjEQMA4GA1UEChMHQWNtZSBD
|
||||||
|
bzAeFw0xNDAzMTcwNjIwNTFaFw0xNTAzMTcwNjIwNTFaMBIxEDAOBgNVBAoTB0Fj
|
||||||
|
bWUgQ28wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDccNO1xmd4lWSf
|
||||||
|
d/0/QS3E93cYIWHw831i/IKxigdRD/XMZonLdEHywW6lOiXazaP8e6CqPGSmnl0x
|
||||||
|
5k/3dvGCMj2JCVxM6+z7NpL+AiwvXmvkj/TOciCgwqssCwYS2CiVwjfazRjx1ZUJ
|
||||||
|
VDC5qiyRsfktQ2fVHrpnJGVSRagmiQgwGWBilVG9B8QvRtpQKN/GQGq17oIQm8aK
|
||||||
|
kOdPt93g93ojMIg7YJpgDgOirvVz/hDn7YD4ryrtPos9CMafFkJprymKpRHyvz7P
|
||||||
|
8a3+OkuPjFjPnwOHQ5u1U3+8vC44vfb1ExWzDLoT8Xp8Gndx39k0f7MVOol3GnYu
|
||||||
|
MN/dvNUdAgMBAAGjSzBJMA4GA1UdDwEB/wQEAwIAoDATBgNVHSUEDDAKBggrBgEF
|
||||||
|
BQcDATAMBgNVHRMBAf8EAjAAMBQGA1UdEQQNMAuCCWxvY2FsaG9zdDALBgkqhkiG
|
||||||
|
9w0BAQUDggEBAIG8CJqvTIgJnNOK+i5/IUc/3yF/mSCWuG8qP+Fmo2t6T0PVOtc0
|
||||||
|
8wiWH5iWtCAhjn0MRY9l/hIjWm6gUZGHCGuEgsOPpJDYGoNLjH9Xwokm4y3LFNRK
|
||||||
|
UBrrrDbKRNibApBHCapPf6gC5sXcjOwx7P2/kiHDgY7YH47jfcRhtAPNsM4gjsEO
|
||||||
|
RmwENY+hRUFHIRfQTyalqND+x6PWhRo3K6hpHs4DQEYPq4P2kFPqUqSBymH+Ny5/
|
||||||
|
BcQ3wdMNmC6Bm/oiL1QV0M+/InOsAgQk/EDd0kmoU1ZT2lYHQduGmP099bOlHNpS
|
||||||
|
uqO3vXF3q8SPPr/A9TqSs7BKkBQbe0+cdsA=
|
||||||
|
-----END CERTIFICATE-----`
|
||||||
|
|
||||||
|
rawKey = `-----BEGIN RSA PRIVATE KEY-----
|
||||||
|
MIIEowIBAAKCAQEA3HDTtcZneJVkn3f9P0EtxPd3GCFh8PN9YvyCsYoHUQ/1zGaJ
|
||||||
|
y3RB8sFupTol2s2j/Hugqjxkpp5dMeZP93bxgjI9iQlcTOvs+zaS/gIsL15r5I/0
|
||||||
|
znIgoMKrLAsGEtgolcI32s0Y8dWVCVQwuaoskbH5LUNn1R66ZyRlUkWoJokIMBlg
|
||||||
|
YpVRvQfEL0baUCjfxkBqte6CEJvGipDnT7fd4Pd6IzCIO2CaYA4Doq71c/4Q5+2A
|
||||||
|
+K8q7T6LPQjGnxZCaa8piqUR8r8+z/Gt/jpLj4xYz58Dh0ObtVN/vLwuOL329RMV
|
||||||
|
swy6E/F6fBp3cd/ZNH+zFTqJdxp2LjDf3bzVHQIDAQABAoIBAHal26147nQ+pHwY
|
||||||
|
jxwers3XDCjWvup7g79lfcqlKi79UiUEA6KYHm7UogMYewt7p4nb2KwH+XycvDiB
|
||||||
|
aAUf5flXpTs+6IkWauUDiLZi4PlV7uiEexUq5FjirlL0U/6MjbudX4bK4WQ4uxDc
|
||||||
|
WaV07Kw2iJFOOHLDKT0en9JaX5jtJNc4ZnE9efFoQ5jfypPWtRw65G1rULEg6nvc
|
||||||
|
GDh+1ce+4foCkpLRC9c24xAwJONZG6x3UqrSS9qfAsb73nWRQrTfUcO3nhoN8VvL
|
||||||
|
kL9skn1+S06NyUN0KoEtyRBp+RcpXSsBWAo6qZmo/WqhB/gjzWrxVwn20+yJSm35
|
||||||
|
ZsMc6QECgYEA8GS+Mp9xfB2szWHz6YTOO1Uu4lHM1ccZMwS1G+dL0KO3uGAiPdvp
|
||||||
|
woVot6v6w88t7onXsLo5pgz7SYug0CpkF3K/MRd1Ar4lH7PK7IBQ6rFr9ppVxDbx
|
||||||
|
AEWRswUoPbKCr7W6HU8LbQHDavsDlEIwc6+DiwnL4BzlKjb7RpgQEz0CgYEA6sB5
|
||||||
|
uHvx3Y5FDcGk1n73leQSAcq14l3ZLNpjrs8msoREDil/j5WmuSN58/7PGMiMgHEi
|
||||||
|
1vLm3H796JmvGr9OBvspOjHyk07ui2/We/j9Hoxm1VWhyi8HkLNDj70HKalTTFMz
|
||||||
|
RHO4O+0xCva+h9mKZrRMVktXr2jjdFn/0MYIZ2ECgYAIIsC1IeRLWQ3CHbCNlKsO
|
||||||
|
IwHlMvOFwKk/qsceXKOaOhA7szU1dr3gkXdL0Aw6mEZrrkqYdpUA46uVf54/rU+Z
|
||||||
|
445I8QxKvXiwK/uQKX+TkdGflPWWIG3jnnch4ejMvb/ihnn4B/bRB6A/fKNQXzUY
|
||||||
|
lTYUfI5j1VaEKTwz1W2l2QKBgByFCcSp+jZqhGUpc3dDsZyaOr3Q/Mvlju7uEVI5
|
||||||
|
hIAHpaT60a6GBd1UPAqymEJwivFHzW3D0NxU6VAK68UaHMaoWNfjHY9b9YsnKS2i
|
||||||
|
kE3XzN56Ks+/avHfdYPO+UHMenw5V28nh+hv5pdoZrlmanQTz3pkaOC8o3WNQZEB
|
||||||
|
nh/BAoGBAMY5z2f1pmMhrvtPDSlEVjgjELbaInxFaxPLR4Pdyzn83gtIIU14+R8X
|
||||||
|
2LPs6PPwrNjWnIgrUSVXncIFL3pa45B+Mx1pYCpOAB1+nCZjIBQmpeo4Y0dwA/XH
|
||||||
|
85EthKPvoszm+OPbyI16OcePV5ocX7lupRYuAo0pek7bomhmHWHz
|
||||||
|
-----END RSA PRIVATE KEY-----`
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
serverConfig = &gosocks5.Config{
|
||||||
|
SelectMethod: serverSelectMethod,
|
||||||
|
MethodSelected: serverMethodSelected,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
type Socks5Server struct {
|
||||||
|
Addr string // TCP address to listen on
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
func (s *Socks5Server) ListenAndServe() error {
|
||||||
|
addr, err := net.ResolveTCPAddr("tcp", s.Addr)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
ln, err := net.ListenTCP("tcp", addr)
|
||||||
|
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 socks5Handle(gosocks5.ServerConn(conn, serverConfig))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
func serverSelectMethod(methods ...uint8) uint8 {
|
||||||
|
for _, method := range methods {
|
||||||
|
if _, ok := Methods[method]; ok {
|
||||||
|
return method
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return gosocks5.MethodNoAuth
|
||||||
|
}
|
||||||
|
|
||||||
|
func serverMethodSelected(method uint8, conn net.Conn) (net.Conn, error) {
|
||||||
|
switch method {
|
||||||
|
case MethodTLS:
|
||||||
|
var cert tls.Certificate
|
||||||
|
var err error
|
||||||
|
|
||||||
|
if len(CertFile) == 0 || len(KeyFile) == 0 {
|
||||||
|
cert, err = tls.X509KeyPair([]byte(rawCert), []byte(rawKey))
|
||||||
|
} else {
|
||||||
|
cert, err = tls.LoadX509KeyPair(CertFile, KeyFile)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
conn = tls.Server(conn, &tls.Config{Certificates: []tls.Certificate{cert}})
|
||||||
|
case MethodAES128, MethodAES192, MethodAES256,
|
||||||
|
MethodDES, MethodBF, MethodCAST5, MethodRC4MD5, MethodRC4, MethodTable:
|
||||||
|
cipher, err := shadowsocks.NewCipher(Methods[method], Password)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
conn = shadowsocks.NewConn(conn, cipher)
|
||||||
|
case gosocks5.MethodNoAcceptable:
|
||||||
|
return nil, gosocks5.ErrBadMethod
|
||||||
|
}
|
||||||
|
|
||||||
|
return conn, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func socks5Handle(conn net.Conn) {
|
||||||
|
defer conn.Close()
|
||||||
|
|
||||||
|
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())
|
||||||
|
log.Println("accept peer:", addr.String())
|
||||||
|
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(gosocks5.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(gosocks5.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 := lpool.Take()
|
||||||
|
defer lpool.put(b)
|
||||||
|
|
||||||
|
for {
|
||||||
|
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])
|
||||||
|
//log.Println("r", udp.Header)
|
||||||
|
if err := udp.Write(conn); err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
for {
|
||||||
|
udp, err := gosocks5.ReadUDPDatagram(conn)
|
||||||
|
if err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
//log.Println("w", udp.Header)
|
||||||
|
addr, err := net.ResolveUDPAddr("udp", udp.Header.Addr.String())
|
||||||
|
if err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
continue // drop silently
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err := uconn.WriteToUDP(udp.Data, addr); err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
69
ws.go
Normal file
69
ws.go
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/gorilla/websocket"
|
||||||
|
"net/http"
|
||||||
|
"log"
|
||||||
|
"time"
|
||||||
|
"github.com/ginuerzh/gosocks5"
|
||||||
|
)
|
||||||
|
|
||||||
|
type WSConn struct {
|
||||||
|
*websocket.Conn
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewWSConn(conn *websocket.Conn) *WSConn {
|
||||||
|
c := &WSConn{}
|
||||||
|
c.Conn = conn
|
||||||
|
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
func (conn *WSConn) Read(b []byte) (n int, err error) {
|
||||||
|
_, b, err = conn.ReadMessage()
|
||||||
|
n = len(b)
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (conn *WSConn) Write(b []byte) (n int, err error) {
|
||||||
|
n = len(b)
|
||||||
|
err = conn.WriteMessage(websocket.BinaryMessage, b)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (conn *WSConn) SetDeadline(t time.Time) error {
|
||||||
|
if err := conn.SetReadDeadline(t); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return conn.SetWriteDeadline(t)
|
||||||
|
}
|
||||||
|
|
||||||
|
type WSServer struct {
|
||||||
|
Addr string
|
||||||
|
}
|
||||||
|
|
||||||
|
var upgrader = websocket.Upgrader{
|
||||||
|
ReadBufferSize: 8192,
|
||||||
|
WriteBufferSize: 8192,
|
||||||
|
CheckOrigin: func(r *http.Request) bool{ return true;},
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
func (s *WSServer) handle(w http.ResponseWriter, r *http.Request) {
|
||||||
|
conn, err := upgrader.Upgrade(w, r, nil)
|
||||||
|
if err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer conn.Close()
|
||||||
|
|
||||||
|
c := NewWSConn(conn)
|
||||||
|
|
||||||
|
socks5Handle(gosocks5.ServerConn(c, serverConfig))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *WSServer) ListenAndServe() error {
|
||||||
|
http.HandleFunc("/", s.handle)
|
||||||
|
return http.ListenAndServe(s.Addr, nil)
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user