291 lines
7.8 KiB
Go
291 lines
7.8 KiB
Go
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 {
|
|
m := gosocks5.MethodNoAuth
|
|
|
|
for _, method := range methods {
|
|
if _, ok := Methods[method]; ok {
|
|
m = method
|
|
}
|
|
}
|
|
|
|
if len(Method) == 0 || Methods[m] == Method {
|
|
return m
|
|
}
|
|
|
|
return gosocks5.MethodNoAcceptable
|
|
}
|
|
|
|
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 {
|
|
return nil, err
|
|
}
|
|
conn = tls.Server(conn, &tls.Config{Certificates: []tls.Certificate{cert}})
|
|
if err := svrTLSAuth(conn); err != nil {
|
|
return nil, err
|
|
}
|
|
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 svrTLSAuth(conn net.Conn) error {
|
|
req, err := gosocks5.ReadUserPassRequest(conn)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if len(Password) > 0 && req.Password != Password {
|
|
if err := gosocks5.NewUserPassResponse(
|
|
gosocks5.UserPassVer, gosocks5.Failure).Write(conn); err != nil {
|
|
return err
|
|
}
|
|
return gosocks5.ErrAuthFailure
|
|
}
|
|
|
|
if err := gosocks5.NewUserPassResponse(
|
|
gosocks5.UserPassVer, gosocks5.Succeeded).Write(conn); err != nil {
|
|
return err
|
|
}
|
|
|
|
return 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 := ConnectProxy(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
|
|
}
|
|
}
|
|
}
|