This commit is contained in:
rui.zheng 2015-03-31 10:42:22 +08:00
parent 158125d41d
commit c462a4df9d
7 changed files with 135 additions and 321 deletions

18
cert.pem Normal file
View File

@ -0,0 +1,18 @@
-----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-----

View File

@ -3,6 +3,7 @@ package main
import (
"bufio"
"bytes"
"crypto/tls"
"encoding/binary"
"fmt"
"github.com/ginuerzh/gosocks5"
@ -45,7 +46,7 @@ func handshake(conn net.Conn, methods ...uint8) (method uint8, err error) {
nm = 1
}
b := make([]byte, 2+nm)
b[0] = Ver5
b[0] = gosocks5.Ver5
b[1] = uint8(nm)
copy(b[2:], methods)
@ -57,7 +58,7 @@ func handshake(conn net.Conn, methods ...uint8) (method uint8, err error) {
return
}
if b[0] != Ver5 {
if b[0] != gosocks5.Ver5 {
err = gosocks5.ErrBadVersion
}
method = b[1]
@ -74,17 +75,31 @@ func cliHandle(conn net.Conn) {
}
defer sconn.Close()
method, err := handshake(sconn, MethodAES256, gosocks5.MethodNoAuth)
if err != nil || method == gosocks5.MethodNoAcceptable {
method := gosocks5.MethodNoAuth
for m, v := range Methods {
if Method == v {
method = m
}
}
method, err = handshake(sconn, method)
if err != nil {
return
}
if method == MethodAES256 {
cipher, _ := shadowsocks.NewCipher(Cipher, Password)
switch method {
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 {
cipher, _ := shadowsocks.NewCipher(Cipher, Password)
cipher, _ := shadowsocks.NewCipher(SMethod, SPassword)
conn = shadowsocks.NewConn(conn, cipher)
handleShadow(conn, sconn)
return
@ -157,7 +172,7 @@ func handleSocks5(conn net.Conn, sconn net.Conn) {
uconn, err := net.ListenUDP("udp", nil)
if err != nil {
log.Println(err)
gosocks5.NewReply(Failure, nil).Write(conn)
gosocks5.NewReply(gosocks5.Failure, nil).Write(conn)
return
}
defer uconn.Close()
@ -166,7 +181,7 @@ func handleSocks5(conn net.Conn, sconn net.Conn) {
addr.Host, _, _ = net.SplitHostPort(conn.LocalAddr().String())
//log.Println("udp:", addr)
rep = gosocks5.NewReply(Succeeded, addr)
rep = gosocks5.NewReply(gosocks5.Succeeded, addr)
if err := rep.Write(conn); err != nil {
log.Println(err)
return

27
key.pem Normal file
View File

@ -0,0 +1,27 @@
-----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-----

14
main.go
View File

@ -10,17 +10,22 @@ import (
var (
Laddr, Saddr, Proxy string
Shadows bool
Cipher, Password string
SMethod, SPassword string
Method, Password string
CertFile, KeyFile string
)
func init() {
flag.StringVar(&Proxy, "P", "", "proxy for forward")
flag.StringVar(&Saddr, "S", "", "the server that connecting to")
flag.StringVar(&Laddr, "L", ":8080", "listen address")
flag.StringVar(&Cipher, "cipher", "rc4-md5", "cipher method")
flag.StringVar(&Password, "password", "ginuerzh@gmail.com", "cipher password")
flag.StringVar(&Method, "m", "tls", "cipher method")
flag.StringVar(&Password, "p", "ginuerzh@gmail.com", "cipher password")
flag.StringVar(&CertFile, "cert", "cert.pem", "cert.pem file for tls")
flag.StringVar(&KeyFile, "key", "key.pem", "key.pem file for tls")
flag.BoolVar(&Shadows, "ss", false, "shadowsocks compatible")
flag.BoolVar(&Debug, "d", false, "debug option")
flag.StringVar(&SMethod, "sm", "rc4-md5", "shadowsocks cipher method")
flag.StringVar(&SPassword, "sp", "ginuerzh@gmail.com", "shadowsocks cipher password")
flag.Parse()
log.SetFlags(log.LstdFlags | log.Lshortfile)
@ -32,6 +37,7 @@ func main() {
srv := &gosocks5.Server{
Addr: Laddr,
SelectMethod: selectMethod,
MethodSelected: methodSelected,
Handle: srvHandle,
}
log.Fatal(srv.ListenAndServe())

View File

@ -5,37 +5,46 @@ import (
"github.com/shadowsocks/shadowsocks-go/shadowsocks"
"net"
//"strconv"
"crypto/tls"
"log"
)
const (
MethodAES256 uint8 = 0x88
)
func selectMethod(methods ...uint8) uint8 {
for _, method := range methods {
if method == MethodAES256 {
if _, ok := Methods[method]; ok {
return method
}
}
return gosocks5.MethodNoAuth
}
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)
func methodSelected(method uint8, conn net.Conn) (net.Conn, error) {
switch method {
case MethodTLS:
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
}
@ -96,7 +105,7 @@ func srvHandle(conn net.Conn, method uint8) {
uconn, err := net.ListenUDP("udp", nil)
if err != nil {
log.Println(err)
gosocks5.NewReply(Failure, nil).Write(conn)
gosocks5.NewReply(gosocks5.Failure, nil).Write(conn)
return
}
defer uconn.Close()
@ -104,7 +113,7 @@ func srvHandle(conn net.Conn, method uint8) {
addr := ToSocksAddr(uconn.LocalAddr())
addr.Host, _, _ = net.SplitHostPort(conn.LocalAddr().String())
//log.Println("udp:", addr)
rep := gosocks5.NewReply(Succeeded, addr)
rep := gosocks5.NewReply(gosocks5.Succeeded, addr)
if err := rep.Write(conn); err != nil {
log.Println(err)
return

287
socks5.go
View File

@ -1,287 +0,0 @@
package main
import (
"bytes"
"encoding/binary"
"errors"
"fmt"
"io"
//"log"
"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")
)
/*
+----+-----+-------+------+----------+----------+
|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 {
if len(addr) == 0 {
addr = "0.0.0.0"
}
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)
//log.Println(b[:n])
if err != nil {
//log.Println(err)
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+net.IPv4len]).String()
pos += net.IPv4len
case AddrIPv6:
if n != 22 {
return nil, ErrBadFormat
}
cmd.Addr = net.IP(b[pos : pos+net.IPv6len]).String()
pos += net.IPv6len
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:
pos += 4
}
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) String() string {
return fmt.Sprintf("5 %d 0 %d %s %d",
cmd.Cmd, cmd.AddrType, cmd.Addr, cmd.Port)
}
/*
+----+------+------+----------+----------+----------+
|RSV | FRAG | ATYP | DST.ADDR | DST.PORT | DATA |
+----+------+------+----------+----------+----------+
| 2 | 1 | 1 | Variable | 2 | Variable |
+----+------+------+----------+----------+----------+
*/
type UdpPayload struct {
Rsv uint16
Frag uint8
AddrType uint8
Addr string
Port uint16
Data []byte
}
func NewUdpPayload(rsv uint16, atype uint8, addr string, port uint16, data []byte) *UdpPayload {
if len(addr) == 0 {
addr = "0.0.0.0"
}
return &UdpPayload{
Rsv: rsv,
AddrType: atype,
Addr: addr,
Port: port,
Data: data,
}
}
func ReadUdpPayload(r io.Reader) (*UdpPayload, error) {
buf := make([]byte, 65797)
n, err := io.ReadAtLeast(r, buf, 5)
//log.Println("r", buf[:n])
if err != nil {
return nil, err
}
up := &UdpPayload{
Rsv: binary.BigEndian.Uint16(buf[:2]),
Frag: buf[2],
AddrType: buf[3],
}
dataIndex := 0
switch up.AddrType {
case AddrIPv4:
dataIndex = 10
case AddrIPv6:
dataIndex = 22
case AddrDomain:
dataIndex = 7 + int(buf[4])
default:
return nil, ErrBadAddrType
}
dataLen := int(up.Rsv)
if n < dataIndex+dataLen {
if _, err := io.ReadFull(r, buf[n:dataIndex+dataLen]); err != nil {
return nil, err
}
}
pos := 4
switch up.AddrType {
case AddrIPv4:
up.Addr = net.IP(buf[pos : pos+net.IPv4len]).String()
pos += net.IPv4len
case AddrIPv6:
up.Addr = net.IP(buf[pos : pos+net.IPv6len]).String()
pos += net.IPv6len
case AddrDomain:
length := int(buf[pos])
pos++
up.Addr = string(buf[pos : pos+length])
pos += length
}
up.Port = binary.BigEndian.Uint16(buf[pos:])
//log.Println(up.Addr, up.Port)
if dataLen > 0 {
up.Data = buf[dataIndex : dataIndex+dataLen]
} else {
up.Data = buf[dataIndex:n]
}
return up, nil
}
func (up *UdpPayload) Write(w io.Writer) error {
buffer := &bytes.Buffer{}
b := make([]byte, 2)
binary.BigEndian.PutUint16(b, up.Rsv)
buffer.Write(b)
buffer.WriteByte(up.Frag)
buffer.WriteByte(up.AddrType)
switch up.AddrType {
case AddrIPv4:
buffer.Write(net.ParseIP(up.Addr).To4())
case AddrDomain:
buffer.WriteByte(uint8(len(up.Addr)))
buffer.Write([]byte(up.Addr))
case AddrIPv6:
buffer.Write(net.ParseIP(up.Addr).To16())
}
binary.BigEndian.PutUint16(b, up.Port)
buffer.Write(b)
buffer.Write(up.Data)
_, err := w.Write(buffer.Bytes())
return err
}
func (up *UdpPayload) String() string {
return fmt.Sprintf("%d %d %d %s %d [%d]",
up.Rsv, up.Frag, up.AddrType, up.Addr, up.Port, len(up.Data))
}

28
util.go
View File

@ -13,12 +13,38 @@ import (
"strconv"
)
const (
MethodTLS uint8 = 0x80 + iota
MethodAES128
MethodAES192
MethodAES256
MethodDES
MethodBF
MethodCAST5
MethodRC4MD5
MethodRC4
MethodTable
)
var Methods = map[uint8]string{
MethodTLS: "tls", // 0x80
MethodAES128: "aes-128-cfb", // 0x81
MethodAES192: "aes-192-cfb", // 0x82
MethodAES256: "aes-256-cfb", // 0x83
MethodDES: "des-cfb", // 0x84
MethodBF: "bf-cfb", // 0x85
MethodCAST5: "cast5-cfb", // 0x86
MethodRC4MD5: "rc4-md5", // 8x87
MethodRC4: "rc4", // 0x88
MethodTable: "table", // 0x89
}
func ToSocksAddr(addr net.Addr) *gosocks5.Addr {
host, port, _ := net.SplitHostPort(addr.String())
p, _ := strconv.Atoi(port)
return &gosocks5.Addr{
Type: AddrIPv4,
Type: gosocks5.AddrIPv4,
Host: host,
Port: uint16(p),
}