├── core ├── doc.go ├── packet.go ├── stream.go └── cipher.go ├── go.mod ├── README.md ├── .github └── workflows │ ├── build.yml │ └── release.yml ├── nfutil ├── socketcall_linux_other.go ├── socketcall_linux_386.go └── nf_linux.go ├── go.sum ├── listen ├── socks.go ├── pf_darwin.go ├── listen.go └── nf_linux.go ├── dialer.go ├── shadowaead ├── doc.go ├── cipher.go ├── packet.go └── stream.go ├── pfutil └── pf_darwin.go ├── Makefile ├── config.go ├── speeddial └── dial.go ├── tcp.go ├── main.go ├── socks └── socks.go ├── udp.go └── LICENSE /core/doc.go: -------------------------------------------------------------------------------- 1 | // Package core implements essential parts of Shadowsocks 2 | package core 3 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/riobard/go-shadowsocks2 2 | 3 | go 1.15 4 | 5 | require golang.org/x/crypto v0.0.0-20200128174031-69ecbb4d6d5d 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | This repo is experimental. No support is provided. Use at your own risk. 2 | 3 | You should use the stable fork at https://github.com/shadowsocks/go-shadowsocks2 instead. -------------------------------------------------------------------------------- /core/packet.go: -------------------------------------------------------------------------------- 1 | package core 2 | 3 | import "net" 4 | 5 | func ListenPacket(network, address string, ciph PacketConnCipher) (net.PacketConn, error) { 6 | c, err := net.ListenPacket(network, address) 7 | return ciph.PacketConn(c), err 8 | } 9 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Build and test 2 | on: [push] 3 | jobs: 4 | build: 5 | runs-on: ubuntu-latest 6 | steps: 7 | - uses: actions/setup-go@v1 8 | with: 9 | go-version: 1.15 10 | - uses: actions/checkout@v2 11 | - run: make -j all 12 | - run: make -j test 13 | -------------------------------------------------------------------------------- /nfutil/socketcall_linux_other.go: -------------------------------------------------------------------------------- 1 | // +build linux,!386 2 | 3 | package nfutil 4 | 5 | import "syscall" 6 | 7 | const GETSOCKOPT = syscall.SYS_GETSOCKOPT 8 | 9 | func socketcall(call, a0, a1, a2, a3, a4, a5 uintptr) error { 10 | if _, _, errno := syscall.Syscall6(call, a0, a1, a2, a3, a4, a5); errno != 0 { 11 | return errno 12 | } 13 | return nil 14 | } 15 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Build and upload release binaries 2 | on: 3 | release: 4 | types: [published] 5 | jobs: 6 | build: 7 | runs-on: ubuntu-latest 8 | steps: 9 | - uses: actions/checkout@v2 10 | - uses: actions/setup-go@v1 11 | with: 12 | go-version: 1.15 13 | - run: make -j upload 14 | env: 15 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 16 | GITHUB_RELEASE_UPLOAD_URL: ${{ github.event.release.upload_url }} 17 | -------------------------------------------------------------------------------- /nfutil/socketcall_linux_386.go: -------------------------------------------------------------------------------- 1 | package nfutil 2 | 3 | import ( 4 | "syscall" 5 | "unsafe" 6 | ) 7 | 8 | const GETSOCKOPT = 15 // https://golang.org/src/syscall/syscall_linux_386.go#L183 9 | 10 | func socketcall(call, a0, a1, a2, a3, a4, a5 uintptr) error { 11 | var a [6]uintptr 12 | a[0], a[1], a[2], a[3], a[4], a[5] = a0, a1, a2, a3, a4, a5 13 | if _, _, errno := syscall.Syscall6(syscall.SYS_SOCKETCALL, call, uintptr(unsafe.Pointer(&a)), 0, 0, 0, 0); errno != 0 { 14 | return errno 15 | } 16 | return nil 17 | } 18 | -------------------------------------------------------------------------------- /core/stream.go: -------------------------------------------------------------------------------- 1 | package core 2 | 3 | import "net" 4 | 5 | type listener struct { 6 | net.Listener 7 | StreamConnCipher 8 | } 9 | 10 | func Listen(network, address string, ciph StreamConnCipher) (net.Listener, error) { 11 | l, err := net.Listen(network, address) 12 | return &listener{l, ciph}, err 13 | } 14 | 15 | func (l *listener) Accept() (net.Conn, error) { 16 | c, err := l.Listener.Accept() 17 | return l.StreamConn(c), err 18 | } 19 | 20 | func Dial(network, address string, ciph StreamConnCipher) (net.Conn, error) { 21 | c, err := net.Dial(network, address) 22 | return ciph.StreamConn(c), err 23 | } 24 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 2 | golang.org/x/crypto v0.0.0-20200128174031-69ecbb4d6d5d h1:9FCpayM9Egr1baVnV1SX0H87m+XB0B8S0hAMi99X/3U= 3 | golang.org/x/crypto v0.0.0-20200128174031-69ecbb4d6d5d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= 4 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 5 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 6 | golang.org/x/sys v0.0.0-20190412213103-97732733099d h1:+R4KGOnez64A81RvjARKc4UT5/tI9ujCIVX+P5KiHuI= 7 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 8 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 9 | -------------------------------------------------------------------------------- /listen/socks.go: -------------------------------------------------------------------------------- 1 | package listen 2 | 3 | import ( 4 | "net" 5 | 6 | "github.com/riobard/go-shadowsocks2/socks" 7 | ) 8 | 9 | func init() { 10 | listeners["socks"] = socksListen 11 | } 12 | 13 | type socksConn struct{ net.Conn } 14 | 15 | func (sc socksConn) LocalAddr() net.Addr { 16 | addr, err := socks.Handshake(sc.Conn) 17 | if err != nil { 18 | return nil 19 | } 20 | return strAddr(addr.String()) 21 | } 22 | 23 | type socksListener struct{ net.Listener } 24 | 25 | func (l *socksListener) Accept() (net.Conn, error) { 26 | c, err := l.Listener.Accept() 27 | if err != nil { 28 | return nil, err 29 | } 30 | return socksConn{c}, nil 31 | } 32 | 33 | func socksListen(network, addr string) (net.Listener, error) { 34 | l, err := net.Listen(network, addr) 35 | if err != nil { 36 | return nil, err 37 | } 38 | return &socksListener{l}, nil 39 | } 40 | -------------------------------------------------------------------------------- /listen/pf_darwin.go: -------------------------------------------------------------------------------- 1 | package listen 2 | 3 | import ( 4 | "net" 5 | 6 | "github.com/riobard/go-shadowsocks2/pfutil" 7 | ) 8 | 9 | func init() { 10 | listeners["redir"] = pfListen 11 | } 12 | 13 | type pfConn struct{ net.Conn } 14 | 15 | func (c *pfConn) LocalAddr() net.Addr { 16 | tc, ok := c.Conn.(*net.TCPConn) 17 | if !ok { 18 | return nil 19 | } 20 | addr, err := pfutil.NatLookup(tc) 21 | if err != nil { 22 | return nil 23 | } 24 | return addr 25 | } 26 | 27 | type pfListener struct{ net.Listener } 28 | 29 | func (l *pfListener) Accept() (net.Conn, error) { 30 | c, err := l.Listener.Accept() 31 | if err != nil { 32 | return nil, err 33 | } 34 | return &pfConn{c}, nil 35 | } 36 | 37 | func pfListen(network, address string) (net.Listener, error) { 38 | l, err := net.Listen(network, address) 39 | if err != nil { 40 | return nil, err 41 | } 42 | return &pfListener{l}, nil 43 | } 44 | -------------------------------------------------------------------------------- /listen/listen.go: -------------------------------------------------------------------------------- 1 | package listen 2 | 3 | import ( 4 | "errors" 5 | "net" 6 | ) 7 | 8 | var listeners = make(map[string]func(network, address string) (net.Listener, error)) 9 | 10 | var ErrUnsupported = errors.New("unsupported") 11 | 12 | func Listen(kind, network, address string) (net.Listener, error) { 13 | f, ok := listeners[kind] 14 | if ok { 15 | return f(network, address) 16 | } 17 | return nil, ErrUnsupported 18 | } 19 | 20 | type strAddr string 21 | 22 | func (a strAddr) Network() string { return "tcp" } 23 | func (a strAddr) String() string { return string(a) } 24 | 25 | type targetConn struct { 26 | net.Conn 27 | target net.Addr 28 | } 29 | 30 | func (c *targetConn) LocalAddr() net.Addr { return c.target } 31 | 32 | type targetListener struct { 33 | net.Listener 34 | target net.Addr 35 | } 36 | 37 | func ListenTo(network, address, target string) (net.Listener, error) { 38 | l, err := net.Listen(network, address) 39 | if err != nil { 40 | return nil, err 41 | } 42 | return &targetListener{l, strAddr(target)}, err 43 | } 44 | 45 | func (l *targetListener) Accept() (net.Conn, error) { 46 | c, err := l.Listener.Accept() 47 | if err != nil { 48 | return nil, err 49 | } 50 | return &targetConn{c, l.target}, nil 51 | } 52 | -------------------------------------------------------------------------------- /dialer.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "errors" 5 | "net" 6 | 7 | "github.com/riobard/go-shadowsocks2/core" 8 | "github.com/riobard/go-shadowsocks2/socks" 9 | "github.com/riobard/go-shadowsocks2/speeddial" 10 | ) 11 | 12 | type Dialer interface { 13 | Dial(network, address string) (net.Conn, error) 14 | } 15 | 16 | type dialer struct { 17 | *speeddial.Dialer 18 | } 19 | 20 | func (d dialer) Dial(network, address string) (net.Conn, error) { 21 | if network != "tcp" { 22 | return nil, errors.New("only TCP network is supported") 23 | } 24 | c, err := d.Dialer.Dial() 25 | if err != nil { 26 | return c, err 27 | } 28 | _, err = c.Write(socks.ParseAddr(address)) 29 | if err != nil { 30 | c.Close() 31 | } 32 | return c, err 33 | } 34 | 35 | func fastdialer(u ...string) (*dialer, error) { 36 | rs := make([]speeddial.Dial, len(u)) 37 | for i := range u { 38 | addr, cipher, password, err := parseURL(u[i]) 39 | if err != nil { 40 | return nil, err 41 | } 42 | 43 | ciph, err := core.PickCipher(cipher, nil, password) 44 | if err != nil { 45 | return nil, err 46 | } 47 | 48 | rs[i] = func() (net.Conn, error) { 49 | c, err := net.Dial("tcp", addr) 50 | if err != nil { 51 | return c, err 52 | } 53 | c = ciph.StreamConn(c) 54 | return c, nil 55 | } 56 | } 57 | return &dialer{speeddial.New(rs...)}, nil 58 | } 59 | -------------------------------------------------------------------------------- /listen/nf_linux.go: -------------------------------------------------------------------------------- 1 | package listen 2 | 3 | import ( 4 | "context" 5 | "net" 6 | "syscall" 7 | 8 | "github.com/riobard/go-shadowsocks2/nfutil" 9 | ) 10 | 11 | func init() { 12 | listeners["redir"] = nfListen 13 | listeners["tproxy"] = tproxyListen 14 | } 15 | 16 | type nfConn struct{ net.Conn } 17 | 18 | func (c *nfConn) LocalAddr() net.Addr { 19 | tc, ok := c.Conn.(*net.TCPConn) 20 | if !ok { 21 | return nil 22 | } 23 | addr, err := nfutil.GetOrigDst(tc, false) // TODO: detect if c is ipv6 24 | if err != nil { 25 | return nil 26 | } 27 | return addr 28 | } 29 | 30 | type nfListener struct{ net.Listener } 31 | 32 | func (l *nfListener) Accept() (net.Conn, error) { 33 | c, err := l.Listener.Accept() 34 | if err != nil { 35 | return nil, err 36 | } 37 | return &nfConn{c}, nil 38 | } 39 | 40 | func nfListen(network, address string) (net.Listener, error) { 41 | l, err := net.Listen(network, address) 42 | if err != nil { 43 | return nil, err 44 | } 45 | return &nfListener{l}, nil 46 | } 47 | 48 | func tproxyListen(network, address string) (net.Listener, error) { 49 | lcfg := net.ListenConfig{Control: func(network, address string, rc syscall.RawConn) error { 50 | var err1, err2 error 51 | err2 = rc.Control(func(fd uintptr) { err1 = syscall.SetsockoptInt(int(fd), syscall.SOL_IP, syscall.IP_TRANSPARENT, 1) }) 52 | if err1 != nil { 53 | return err1 54 | } 55 | return err2 56 | }} 57 | return lcfg.Listen(context.Background(), network, address) 58 | } 59 | -------------------------------------------------------------------------------- /shadowaead/doc.go: -------------------------------------------------------------------------------- 1 | /* 2 | Package shadowaead implements a simple AEAD-protected secure protocol. 3 | 4 | In general, there are two types of connections: stream-oriented and packet-oriented. 5 | Stream-oriented connections (e.g. TCP) assume reliable and orderly delivery of bytes. 6 | Packet-oriented connections (e.g. UDP) assume unreliable and out-of-order delivery of packets, 7 | where each packet is either delivered intact or lost. 8 | 9 | An encrypted stream starts with a random salt to derive a session key, followed by any number of 10 | encrypted records. Each encrypted record has the following structure: 11 | 12 | [encrypted payload length] 13 | [payload length tag] 14 | [encrypted payload] 15 | [payload tag] 16 | 17 | Payload length is 2-byte unsigned big-endian integer capped at 0x3FFF (16383). 18 | The higher 2 bits are reserved and must be set to zero. The first AEAD encrypt/decrypt 19 | operation uses a counting nonce starting from 0. After each encrypt/decrypt operation, 20 | the nonce is incremented by one as if it were an unsigned little-endian integer. 21 | 22 | 23 | Each encrypted packet transmitted on a packet-oriented connection has the following structure: 24 | 25 | [random salt] 26 | [encrypted payload] 27 | [payload tag] 28 | 29 | The salt is used to derive a subkey to initiate an AEAD. Packets are encrypted/decrypted independently 30 | using zero nonce. 31 | 32 | In both stream-oriented and packet-oriented connections, length of nonce and tag varies 33 | depending on which AEAD is used. Salt should be at least 16-byte long. 34 | */ 35 | package shadowaead 36 | -------------------------------------------------------------------------------- /pfutil/pf_darwin.go: -------------------------------------------------------------------------------- 1 | package pfutil 2 | 3 | import ( 4 | "net" 5 | "syscall" 6 | "unsafe" 7 | ) 8 | 9 | func NatLookup(c *net.TCPConn) (*net.TCPAddr, error) { 10 | const ( 11 | PF_INOUT = 0 12 | PF_IN = 1 13 | PF_OUT = 2 14 | IOC_OUT = 0x40000000 15 | IOC_IN = 0x80000000 16 | IOC_INOUT = IOC_IN | IOC_OUT 17 | IOCPARM_MASK = 0x1FFF 18 | LEN = 4*16 + 4*4 + 4*1 19 | // #define _IOC(inout,group,num,len) (inout | ((len & IOCPARM_MASK) << 16) | ((group) << 8) | (num)) 20 | // #define _IOWR(g,n,t) _IOC(IOC_INOUT, (g), (n), sizeof(t)) 21 | // #define DIOCNATLOOK _IOWR('D', 23, struct pfioc_natlook) 22 | DIOCNATLOOK = IOC_INOUT | ((LEN & IOCPARM_MASK) << 16) | ('D' << 8) | 23 23 | ) 24 | fd, err := syscall.Open("/dev/pf", 0, syscall.O_RDONLY) 25 | if err != nil { 26 | return nil, err 27 | } 28 | defer syscall.Close(fd) 29 | nl := struct { // struct pfioc_natlook 30 | saddr, daddr, rsaddr, rdaddr [16]byte 31 | sxport, dxport, rsxport, rdxport [4]byte 32 | af, proto, protoVariant, direction uint8 33 | }{ 34 | af: syscall.AF_INET, 35 | proto: syscall.IPPROTO_TCP, 36 | direction: PF_OUT, 37 | } 38 | saddr := c.RemoteAddr().(*net.TCPAddr) 39 | daddr := c.LocalAddr().(*net.TCPAddr) 40 | copy(nl.saddr[:], saddr.IP) 41 | copy(nl.daddr[:], daddr.IP) 42 | nl.sxport[0], nl.sxport[1] = byte(saddr.Port>>8), byte(saddr.Port) 43 | nl.dxport[0], nl.dxport[1] = byte(daddr.Port>>8), byte(daddr.Port) 44 | if _, _, errno := syscall.Syscall(syscall.SYS_IOCTL, uintptr(fd), DIOCNATLOOK, uintptr(unsafe.Pointer(&nl))); errno != 0 { 45 | return nil, errno 46 | } 47 | var addr net.TCPAddr 48 | addr.IP = nl.rdaddr[:4] 49 | addr.Port = int(nl.rdxport[0])<<8 | int(nl.rdxport[1]) 50 | return &addr, nil 51 | } 52 | -------------------------------------------------------------------------------- /nfutil/nf_linux.go: -------------------------------------------------------------------------------- 1 | package nfutil 2 | 3 | import ( 4 | "net" 5 | "syscall" 6 | "unsafe" 7 | ) 8 | 9 | // Get the original destination of a TCP connection redirected by Netfilter. 10 | func GetOrigDst(c *net.TCPConn, ipv6 bool) (*net.TCPAddr, error) { 11 | rc, err := c.SyscallConn() 12 | if err != nil { 13 | return nil, err 14 | } 15 | var addr *net.TCPAddr 16 | rc.Control(func(fd uintptr) { 17 | if ipv6 { 18 | addr, err = ipv6_getorigdst(fd) 19 | } else { 20 | addr, err = getorigdst(fd) 21 | } 22 | }) 23 | return addr, err 24 | } 25 | 26 | // Call getorigdst() from linux/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c 27 | func getorigdst(fd uintptr) (*net.TCPAddr, error) { 28 | const _SO_ORIGINAL_DST = 80 // from linux/include/uapi/linux/netfilter_ipv4.h 29 | var raw syscall.RawSockaddrInet4 30 | siz := unsafe.Sizeof(raw) 31 | if err := socketcall(GETSOCKOPT, fd, syscall.IPPROTO_IP, _SO_ORIGINAL_DST, uintptr(unsafe.Pointer(&raw)), uintptr(unsafe.Pointer(&siz)), 0); err != nil { 32 | return nil, err 33 | } 34 | var addr net.TCPAddr 35 | addr.IP = raw.Addr[:] 36 | port := (*[2]byte)(unsafe.Pointer(&raw.Port)) // raw.Port is big-endian 37 | addr.Port = int(port[0])<<8 | int(port[1]) 38 | return &addr, nil 39 | } 40 | 41 | // Call ipv6_getorigdst() from linux/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c 42 | // NOTE: I haven't tried yet but it should work since Linux 3.8. 43 | func ipv6_getorigdst(fd uintptr) (*net.TCPAddr, error) { 44 | const _IP6T_SO_ORIGINAL_DST = 80 // from linux/include/uapi/linux/netfilter_ipv6/ip6_tables.h 45 | var raw syscall.RawSockaddrInet6 46 | siz := unsafe.Sizeof(raw) 47 | if err := socketcall(GETSOCKOPT, fd, syscall.IPPROTO_IPV6, _IP6T_SO_ORIGINAL_DST, uintptr(unsafe.Pointer(&raw)), uintptr(unsafe.Pointer(&siz)), 0); err != nil { 48 | return nil, err 49 | } 50 | var addr net.TCPAddr 51 | addr.IP = raw.Addr[:] 52 | port := (*[2]byte)(unsafe.Pointer(&raw.Port)) // raw.Port is big-endian 53 | addr.Port = int(port[0])<<8 | int(port[1]) 54 | return &addr, nil 55 | } 56 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | NAME=shadowsocks2 2 | BINDIR=bin 3 | GOBUILD=CGO_ENABLED=0 go build -ldflags '-w -s' 4 | # The -w and -s flags reduce binary sizes by excluding unnecessary symbols and debug info 5 | 6 | all: linux macos win64 win32 7 | 8 | linux: 9 | GOARCH=amd64 GOOS=linux $(GOBUILD) -o $(BINDIR)/$(NAME)-$@ 10 | 11 | macos: 12 | GOARCH=amd64 GOOS=darwin $(GOBUILD) -o $(BINDIR)/$(NAME)-$@ 13 | 14 | win64: 15 | GOARCH=amd64 GOOS=windows $(GOBUILD) -o $(BINDIR)/$(NAME)-$@.exe 16 | 17 | win32: 18 | GOARCH=386 GOOS=windows $(GOBUILD) -o $(BINDIR)/$(NAME)-$@.exe 19 | 20 | 21 | test: test-linux test-macos test-win64 test-win32 22 | 23 | test-linux: 24 | GOARCH=amd64 GOOS=linux go test 25 | 26 | test-macos: 27 | GOARCH=amd64 GOOS=darwin go test 28 | 29 | test-win64: 30 | GOARCH=amd64 GOOS=windows go test 31 | 32 | test-win32: 33 | GOARCH=386 GOOS=windows go test 34 | 35 | releases: linux macos win64 win32 36 | chmod +x $(BINDIR)/$(NAME)-* 37 | gzip $(BINDIR)/$(NAME)-linux 38 | gzip $(BINDIR)/$(NAME)-macos 39 | zip -m -j $(BINDIR)/$(NAME)-win32.zip $(BINDIR)/$(NAME)-win32.exe 40 | zip -m -j $(BINDIR)/$(NAME)-win64.zip $(BINDIR)/$(NAME)-win64.exe 41 | 42 | clean: 43 | rm $(BINDIR)/* 44 | 45 | # Remove trailing {} from the release upload url 46 | GITHUB_UPLOAD_URL=$(shell echo $${GITHUB_RELEASE_UPLOAD_URL%\{*}) 47 | 48 | upload: releases 49 | curl -H "Authorization: token $(GITHUB_TOKEN)" -H "Content-Type: application/gzip" --data-binary @$(BINDIR)/$(NAME)-linux.gz "$(GITHUB_UPLOAD_URL)?name=$(NAME)-linux.gz" 50 | curl -H "Authorization: token $(GITHUB_TOKEN)" -H "Content-Type: application/gzip" --data-binary @$(BINDIR)/$(NAME)-macos.gz "$(GITHUB_UPLOAD_URL)?name=$(NAME)-macos.gz" 51 | curl -H "Authorization: token $(GITHUB_TOKEN)" -H "Content-Type: application/zip" --data-binary @$(BINDIR)/$(NAME)-win64.zip "$(GITHUB_UPLOAD_URL)?name=$(NAME)-win64.zip" 52 | curl -H "Authorization: token $(GITHUB_TOKEN)" -H "Content-Type: application/zip" --data-binary @$(BINDIR)/$(NAME)-win32.zip "$(GITHUB_UPLOAD_URL)?name=$(NAME)-win32.zip" 53 | -------------------------------------------------------------------------------- /config.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "flag" 5 | "net/url" 6 | "strings" 7 | "time" 8 | ) 9 | 10 | var config struct { 11 | Verbose bool 12 | UDP bool 13 | UDPTimeout time.Duration 14 | Client SpaceSeparatedList 15 | Server SpaceSeparatedList 16 | TCPTun PairList 17 | UDPTun PairList 18 | Socks string 19 | RedirTCP string 20 | TproxyTCP string 21 | } 22 | 23 | func init() { 24 | flag.BoolVar(&config.Verbose, "verbose", false, "verbose mode") 25 | flag.Var(&config.Server, "s", "server listen url") 26 | flag.Var(&config.Client, "c", "client connect url") 27 | flag.Var(&config.TCPTun, "tcptun", "(client-only) TCP tunnel (laddr1=raddr1,laddr2=raddr2,...)") 28 | flag.Var(&config.UDPTun, "udptun", "(client-only) UDP tunnel (laddr1=raddr1,laddr2=raddr2,...)") 29 | flag.StringVar(&config.Socks, "socks", "", "(client-only) SOCKS listen address") 30 | flag.StringVar(&config.RedirTCP, "redir", "", "(client-only) redirect TCP from this address") 31 | flag.StringVar(&config.TproxyTCP, "tproxytcp", "", "(Linux client-only) TPROXY TCP listen address") 32 | flag.BoolVar(&config.UDP, "udp", false, "(server-only) UDP support") 33 | flag.DurationVar(&config.UDPTimeout, "udptimeout", 120*time.Second, "UDP tunnel timeout") 34 | } 35 | 36 | func parseURL(s string) (addr, cipher, password string, err error) { 37 | u, err := url.Parse(s) 38 | if err != nil { 39 | return 40 | } 41 | 42 | addr = u.Host 43 | if u.User != nil { 44 | cipher = u.User.Username() 45 | password, _ = u.User.Password() 46 | } 47 | return 48 | } 49 | 50 | type PairList [][2]string // key1=val1,key2=val2,... 51 | 52 | func (l PairList) String() string { 53 | s := make([]string, len(l)) 54 | for i, pair := range l { 55 | s[i] = pair[0] + "=" + pair[1] 56 | } 57 | return strings.Join(s, ",") 58 | } 59 | func (l *PairList) Set(s string) error { 60 | for _, item := range strings.Split(s, ",") { 61 | pair := strings.Split(item, "=") 62 | if len(pair) != 2 { 63 | return nil 64 | } 65 | *l = append(*l, [2]string{pair[0], pair[1]}) 66 | } 67 | return nil 68 | } 69 | 70 | type SpaceSeparatedList []string 71 | 72 | func (l SpaceSeparatedList) String() string { return strings.Join(l, " ") } 73 | func (l *SpaceSeparatedList) Set(s string) error { 74 | *l = strings.Split(s, " ") 75 | return nil 76 | } 77 | -------------------------------------------------------------------------------- /shadowaead/cipher.go: -------------------------------------------------------------------------------- 1 | package shadowaead 2 | 3 | import ( 4 | "crypto/aes" 5 | "crypto/cipher" 6 | "crypto/sha1" 7 | "io" 8 | "strconv" 9 | 10 | "golang.org/x/crypto/chacha20poly1305" 11 | "golang.org/x/crypto/hkdf" 12 | ) 13 | 14 | type Cipher interface { 15 | KeySize() int 16 | SaltSize() int 17 | Encrypter(salt []byte) (cipher.AEAD, error) 18 | Decrypter(salt []byte) (cipher.AEAD, error) 19 | } 20 | 21 | type KeySizeError int 22 | 23 | func (e KeySizeError) Error() string { 24 | return "key size error: need " + strconv.Itoa(int(e)) + " bytes" 25 | } 26 | 27 | func hkdfSHA1(secret, salt, info, outkey []byte) { 28 | r := hkdf.New(sha1.New, secret, salt, info) 29 | if _, err := io.ReadFull(r, outkey); err != nil { 30 | panic(err) // should never happen 31 | } 32 | } 33 | 34 | type metaCipher struct { 35 | psk []byte 36 | makeAEAD func(key []byte) (cipher.AEAD, error) 37 | } 38 | 39 | func (a *metaCipher) KeySize() int { return len(a.psk) } 40 | func (a *metaCipher) SaltSize() int { 41 | if ks := a.KeySize(); ks > 16 { 42 | return ks 43 | } 44 | return 16 45 | } 46 | func (a *metaCipher) Encrypter(salt []byte) (cipher.AEAD, error) { 47 | subkey := make([]byte, a.KeySize()) 48 | hkdfSHA1(a.psk, salt, []byte("ss-subkey"), subkey) 49 | return a.makeAEAD(subkey) 50 | } 51 | func (a *metaCipher) Decrypter(salt []byte) (cipher.AEAD, error) { 52 | subkey := make([]byte, a.KeySize()) 53 | hkdfSHA1(a.psk, salt, []byte("ss-subkey"), subkey) 54 | return a.makeAEAD(subkey) 55 | } 56 | 57 | func aesGCM(key []byte) (cipher.AEAD, error) { 58 | blk, err := aes.NewCipher(key) 59 | if err != nil { 60 | return nil, err 61 | } 62 | return cipher.NewGCM(blk) 63 | } 64 | 65 | // AESGCM creates a new Cipher with a pre-shared key. len(psk) must be 66 | // one of 16, 24, or 32 to select AES-128/196/256-GCM. 67 | func AESGCM(psk []byte) (Cipher, error) { 68 | switch l := len(psk); l { 69 | case 16, 24, 32: // AES 128/196/256 70 | default: 71 | return nil, aes.KeySizeError(l) 72 | } 73 | return &metaCipher{psk: psk, makeAEAD: aesGCM}, nil 74 | } 75 | 76 | // Chacha20Poly1305 creates a new Cipher with a pre-shared key. len(psk) 77 | // must be 32. 78 | func Chacha20Poly1305(psk []byte) (Cipher, error) { 79 | if len(psk) != chacha20poly1305.KeySize { 80 | return nil, KeySizeError(chacha20poly1305.KeySize) 81 | } 82 | return &metaCipher{psk: psk, makeAEAD: chacha20poly1305.New}, nil 83 | } 84 | -------------------------------------------------------------------------------- /speeddial/dial.go: -------------------------------------------------------------------------------- 1 | package speeddial 2 | 3 | import ( 4 | "log" 5 | "net" 6 | "sync/atomic" 7 | "time" 8 | ) 9 | 10 | var epoch = time.Now() 11 | 12 | const weight = 4 13 | const penalty = 2 * time.Second 14 | 15 | const _Debug = false 16 | 17 | func logf(format string, v ...interface{}) { 18 | if _Debug { 19 | log.Printf(format, v...) 20 | } 21 | } 22 | 23 | type Dial func() (net.Conn, error) 24 | 25 | type target struct { 26 | last int64 // last dial since epoch 27 | latency int64 // exponetially smoothed 28 | inflight int32 // number of inflight dial 29 | dial Dial 30 | } 31 | 32 | func (t *target) Dial() (net.Conn, error) { 33 | atomic.AddInt32(&t.inflight, 1) 34 | defer atomic.AddInt32(&t.inflight, -1) 35 | t0 := time.Now() 36 | if old, new := atomic.LoadInt64(&t.last), t0.Sub(epoch).Nanoseconds(); old < new { 37 | atomic.CompareAndSwapInt64(&t.last, old, new) 38 | } 39 | c, err := t.dial() 40 | latency := time.Since(t0).Nanoseconds() 41 | if err != nil { 42 | latency = int64(penalty) 43 | } 44 | old := atomic.LoadInt64(&t.latency) 45 | if old > 0 { 46 | latency = (weight*old + latency) / (weight + 1) // exponentially weighted moving average 47 | } 48 | atomic.CompareAndSwapInt64(&t.latency, old, latency) 49 | return c, err 50 | } 51 | 52 | type Dialer struct { 53 | targets []target 54 | Cooldown time.Duration // default 10 seconds 55 | } 56 | 57 | func New(ds ...Dial) *Dialer { 58 | tgts := make([]target, len(ds)) 59 | for i := range ds { 60 | tgts[i].dial = ds[i] 61 | } 62 | return &Dialer{targets: tgts, Cooldown: 10 * time.Second} 63 | } 64 | 65 | func (d *Dialer) Dial() (net.Conn, error) { 66 | min := int64(1<<63 - 1) 67 | var best int 68 | for i := range d.targets { 69 | if l := atomic.LoadInt64(&d.targets[i].latency); 0 < l && l < min { 70 | best, min = i, l 71 | } 72 | } 73 | 74 | logf("Best #%d [%dms]", best, min/1e6) 75 | 76 | for i := range d.targets { 77 | if i == best { 78 | continue 79 | } 80 | tgt := &d.targets[i] 81 | if t := atomic.LoadInt64(&tgt.last); t > 0 && time.Since(epoch.Add(time.Duration(t))) < d.Cooldown { 82 | logf("Cool down #%d", i) 83 | continue 84 | } 85 | if n := atomic.LoadInt32(&tgt.inflight); n > 0 { 86 | logf("Inflight #%d [%d]", i, n) 87 | continue 88 | } 89 | go func(i int) { 90 | c, err := tgt.Dial() 91 | if err == nil { 92 | c.Close() 93 | } 94 | logf("Latency #%d [%dms]", i, tgt.latency/1e6) 95 | }(i) 96 | } 97 | 98 | return d.targets[best].Dial() 99 | } 100 | -------------------------------------------------------------------------------- /tcp.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "errors" 5 | "io" 6 | "net" 7 | "os" 8 | "sync" 9 | "time" 10 | 11 | "github.com/riobard/go-shadowsocks2/socks" 12 | ) 13 | 14 | func tcpLocal(l net.Listener, d Dialer) { 15 | for { 16 | c, err := l.Accept() 17 | if err != nil { 18 | logf("failed to accept: %v", err) 19 | continue 20 | } 21 | go func() { 22 | defer c.Close() 23 | laddr := c.LocalAddr() 24 | if laddr == nil { 25 | logf("failed to determine target address") 26 | return 27 | } 28 | rc, err := d.Dial(laddr.Network(), laddr.String()) 29 | if err != nil { 30 | logf("failed to connect: %v", err) 31 | return 32 | } 33 | defer rc.Close() 34 | logf("proxy %s <--[%s]--> %s", c.RemoteAddr(), rc.RemoteAddr(), laddr) 35 | if err = relay(rc, c); err != nil { 36 | logf("relay error: %v", err) 37 | } 38 | }() 39 | } 40 | } 41 | 42 | // Listen on addr for incoming connections. 43 | func tcpRemote(addr string, shadow func(net.Conn) net.Conn) { 44 | l, err := net.Listen("tcp", addr) 45 | if err != nil { 46 | logf("failed to listen on %s: %v", addr, err) 47 | return 48 | } 49 | 50 | logf("listening TCP on %s", addr) 51 | for { 52 | c, err := l.Accept() 53 | if err != nil { 54 | logf("failed to accept: %v", err) 55 | continue 56 | } 57 | 58 | go func() { 59 | defer c.Close() 60 | c = shadow(c) 61 | 62 | tgt, err := socks.ReadAddr(c) 63 | if err != nil { 64 | logf("failed to get target address from %v: %v", c.RemoteAddr(), err) 65 | return 66 | } 67 | 68 | rc, err := net.Dial("tcp", tgt.String()) 69 | if err != nil { 70 | logf("failed to connect to target: %v", err) 71 | return 72 | } 73 | defer rc.Close() 74 | 75 | logf("proxy %s <-> %s", c.RemoteAddr(), tgt) 76 | if err = relay(c, rc); err != nil { 77 | logf("relay error: %v", err) 78 | } 79 | }() 80 | } 81 | } 82 | 83 | // relay copies between left and right bidirectionally 84 | func relay(left, right net.Conn) error { 85 | var err, err1 error 86 | var wg sync.WaitGroup 87 | wg.Add(1) 88 | go func() { 89 | defer wg.Done() 90 | _, err1 = io.Copy(right, left) 91 | right.SetReadDeadline(time.Now()) // unblock read on right 92 | }() 93 | _, err = io.Copy(left, right) 94 | left.SetReadDeadline(time.Now()) // unblock read on left 95 | wg.Wait() 96 | if err1 != nil && !errors.Is(err1, os.ErrDeadlineExceeded) { // requires Go 1.15+ 97 | return err1 98 | } 99 | if err != nil && !errors.Is(err, os.ErrDeadlineExceeded) { 100 | return err 101 | } 102 | return nil 103 | } 104 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "flag" 5 | "log" 6 | "strings" 7 | 8 | "github.com/riobard/go-shadowsocks2/core" 9 | "github.com/riobard/go-shadowsocks2/listen" 10 | ) 11 | 12 | func main() { 13 | listCiphers := flag.Bool("cipher", false, "List supported ciphers") 14 | flag.Parse() 15 | 16 | if *listCiphers { 17 | println(strings.Join(core.ListCipher(), " ")) 18 | return 19 | } 20 | 21 | if len(config.Client) == 0 && len(config.Server) == 0 { 22 | flag.Usage() 23 | return 24 | } 25 | 26 | if len(config.Client) > 0 { 27 | client() 28 | } 29 | 30 | if len(config.Server) > 0 { 31 | server() 32 | } 33 | 34 | select {} 35 | } 36 | 37 | func client() { 38 | if len(config.UDPTun) > 0 { // use first server for UDP 39 | addr, cipher, password, err := parseURL(config.Client[0]) 40 | if err != nil { 41 | log.Fatal(err) 42 | } 43 | 44 | ciph, err := core.PickCipher(cipher, nil, password) 45 | if err != nil { 46 | log.Fatal(err) 47 | } 48 | for _, p := range config.UDPTun { 49 | go udpLocal(p[0], addr, p[1], ciph.PacketConn) 50 | } 51 | } 52 | 53 | d, err := fastdialer(config.Client...) 54 | if err != nil { 55 | log.Fatalf("failed to create dialer: %v", err) 56 | } 57 | 58 | if len(config.TCPTun) > 0 { 59 | for _, p := range config.TCPTun { 60 | l, err := listen.ListenTo("tcp", p[0], p[1]) 61 | if err != nil { 62 | log.Fatal(err) 63 | } 64 | logf("tcptun %v --> %v", p[0], p[1]) 65 | go tcpLocal(l, d) 66 | } 67 | } 68 | 69 | if config.Socks != "" { 70 | l, err := listen.Listen("socks", "tcp", config.Socks) 71 | if err != nil { 72 | log.Fatal(err) 73 | } 74 | logf("socks %v", config.Socks) 75 | go tcpLocal(l, d) 76 | } 77 | 78 | if config.RedirTCP != "" { 79 | l, err := listen.Listen("redir", "tcp", config.RedirTCP) 80 | if err != nil { 81 | log.Fatal(err) 82 | } 83 | logf("redir tcp %v", config.RedirTCP) 84 | go tcpLocal(l, d) 85 | } 86 | 87 | if config.TproxyTCP != "" { 88 | l, err := listen.Listen("tproxy", "tcp", config.TproxyTCP) 89 | if err != nil { 90 | log.Fatal(err) 91 | } 92 | logf("tproxy tcp %v", config.TproxyTCP) 93 | go tcpLocal(l, d) 94 | } 95 | } 96 | 97 | func server() { 98 | for _, each := range config.Server { 99 | addr, cipher, password, err := parseURL(each) 100 | if err != nil { 101 | log.Fatal(err) 102 | } 103 | 104 | ciph, err := core.PickCipher(cipher, nil, password) 105 | if err != nil { 106 | log.Fatal(err) 107 | } 108 | 109 | if config.UDP { 110 | go udpRemote(addr, ciph.PacketConn) 111 | } 112 | go tcpRemote(addr, ciph.StreamConn) 113 | } 114 | } 115 | 116 | func logf(f string, v ...interface{}) { 117 | if config.Verbose { 118 | log.Printf(f, v...) 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /core/cipher.go: -------------------------------------------------------------------------------- 1 | package core 2 | 3 | import ( 4 | "crypto/md5" 5 | "errors" 6 | "net" 7 | "sort" 8 | "strings" 9 | 10 | "github.com/riobard/go-shadowsocks2/shadowaead" 11 | ) 12 | 13 | type Cipher interface { 14 | StreamConnCipher 15 | PacketConnCipher 16 | } 17 | 18 | type StreamConnCipher interface { 19 | StreamConn(net.Conn) net.Conn 20 | } 21 | 22 | type PacketConnCipher interface { 23 | PacketConn(net.PacketConn) net.PacketConn 24 | } 25 | 26 | // ErrCipherNotSupported occurs when a cipher is not supported (likely because of security concerns). 27 | var ErrCipherNotSupported = errors.New("cipher not supported") 28 | 29 | // List of AEAD ciphers: key size in bytes and constructor 30 | var aeadList = map[string]struct { 31 | KeySize int 32 | New func([]byte) (shadowaead.Cipher, error) 33 | }{ 34 | "AEAD_AES_128_GCM": {16, shadowaead.AESGCM}, 35 | "AEAD_AES_256_GCM": {32, shadowaead.AESGCM}, 36 | "AEAD_CHACHA20_POLY1305": {32, shadowaead.Chacha20Poly1305}, 37 | } 38 | 39 | // ListCipher returns a list of available cipher names sorted alphabetically. 40 | func ListCipher() []string { 41 | var l []string 42 | for k := range aeadList { 43 | l = append(l, k) 44 | } 45 | sort.Strings(l) 46 | return l 47 | } 48 | 49 | // PickCipher returns a Cipher of the given name. Derive key from password if given key is empty. 50 | func PickCipher(name string, key []byte, password string) (Cipher, error) { 51 | name = strings.ToUpper(name) 52 | 53 | switch name { 54 | case "DUMMY": 55 | return &dummy{}, nil 56 | case "CHACHA20-IETF-POLY1305": 57 | name = "AEAD_CHACHA20_POLY1305" 58 | case "AES-128-GCM": 59 | name = "AEAD_AES_128_GCM" 60 | case "AES-256-GCM": 61 | name = "AEAD_AES_256_GCM" 62 | } 63 | 64 | if choice, ok := aeadList[name]; ok { 65 | if len(key) == 0 { 66 | key = kdf(password, choice.KeySize) 67 | } 68 | if len(key) != choice.KeySize { 69 | return nil, shadowaead.KeySizeError(choice.KeySize) 70 | } 71 | aead, err := choice.New(key) 72 | return &aeadCipher{aead}, err 73 | } 74 | 75 | return nil, ErrCipherNotSupported 76 | } 77 | 78 | type aeadCipher struct{ shadowaead.Cipher } 79 | 80 | func (aead *aeadCipher) StreamConn(c net.Conn) net.Conn { return shadowaead.NewConn(c, aead) } 81 | func (aead *aeadCipher) PacketConn(c net.PacketConn) net.PacketConn { 82 | return shadowaead.NewPacketConn(c, aead) 83 | } 84 | 85 | // dummy cipher does not encrypt 86 | 87 | type dummy struct{} 88 | 89 | func (dummy) StreamConn(c net.Conn) net.Conn { return c } 90 | func (dummy) PacketConn(c net.PacketConn) net.PacketConn { return c } 91 | 92 | // key-derivation function from original Shadowsocks 93 | func kdf(password string, keyLen int) []byte { 94 | var b, prev []byte 95 | h := md5.New() 96 | for len(b) < keyLen { 97 | h.Write(prev) 98 | h.Write([]byte(password)) 99 | b = h.Sum(b) 100 | prev = b[len(b)-h.Size():] 101 | h.Reset() 102 | } 103 | return b[:keyLen] 104 | } 105 | -------------------------------------------------------------------------------- /shadowaead/packet.go: -------------------------------------------------------------------------------- 1 | package shadowaead 2 | 3 | import ( 4 | "crypto/rand" 5 | "errors" 6 | "io" 7 | "net" 8 | "sync" 9 | ) 10 | 11 | // ErrShortPacket means that the packet is too short for a valid encrypted packet. 12 | var ErrShortPacket = errors.New("short packet") 13 | 14 | var _zerononce [128]byte // read-only. 128 bytes is more than enough. 15 | 16 | // Pack encrypts plaintext using Cipher with a randomly generated salt and 17 | // returns a slice of dst containing the encrypted packet and any error occurred. 18 | // Ensure len(dst) >= ciph.SaltSize() + len(plaintext) + aead.Overhead(). 19 | func Pack(dst, plaintext []byte, ciph Cipher) ([]byte, error) { 20 | saltSize := ciph.SaltSize() 21 | salt := dst[:saltSize] 22 | if _, err := rand.Read(salt); err != nil { 23 | return nil, err 24 | } 25 | aead, err := ciph.Encrypter(salt) 26 | if err != nil { 27 | return nil, err 28 | } 29 | if len(dst) < saltSize+len(plaintext)+aead.Overhead() { 30 | return nil, io.ErrShortBuffer 31 | } 32 | b := aead.Seal(dst[saltSize:saltSize], _zerononce[:aead.NonceSize()], plaintext, nil) 33 | return dst[:saltSize+len(b)], nil 34 | } 35 | 36 | // Unpack decrypts pkt using Cipher and returns a slice of dst containing the decrypted payload and any error occurred. 37 | // Ensure len(dst) >= len(pkt) - aead.SaltSize() - aead.Overhead(). 38 | func Unpack(dst, pkt []byte, ciph Cipher) ([]byte, error) { 39 | saltSize := ciph.SaltSize() 40 | if len(pkt) < saltSize { 41 | return nil, ErrShortPacket 42 | } 43 | salt := pkt[:saltSize] 44 | aead, err := ciph.Decrypter(salt) 45 | if err != nil { 46 | return nil, err 47 | } 48 | if len(pkt) < saltSize+aead.Overhead() { 49 | return nil, ErrShortPacket 50 | } 51 | if saltSize+len(dst)+aead.Overhead() < len(pkt) { 52 | return nil, io.ErrShortBuffer 53 | } 54 | b, err := aead.Open(dst[:0], _zerononce[:aead.NonceSize()], pkt[saltSize:], nil) 55 | return b, err 56 | } 57 | 58 | type PacketConn struct { 59 | net.PacketConn 60 | Cipher 61 | } 62 | 63 | const maxPacketSize = 64 * 1024 64 | 65 | var bufferPool = sync.Pool{New: func() interface{} { return make([]byte, maxPacketSize) }} 66 | 67 | // NewPacketConn wraps a net.PacketConn with cipher 68 | func NewPacketConn(c net.PacketConn, ciph Cipher) *PacketConn { 69 | return &PacketConn{PacketConn: c, Cipher: ciph} 70 | } 71 | 72 | // WriteTo encrypts b and write to addr using the embedded PacketConn. 73 | func (c *PacketConn) WriteTo(b []byte, addr net.Addr) (int, error) { 74 | buf := bufferPool.Get().([]byte) 75 | defer bufferPool.Put(buf) 76 | buf, err := Pack(buf, b, c) 77 | if err != nil { 78 | return 0, err 79 | } 80 | _, err = c.PacketConn.WriteTo(buf, addr) 81 | return len(b), err 82 | } 83 | 84 | // ReadFrom reads from the embedded PacketConn and decrypts into b. 85 | func (c *PacketConn) ReadFrom(b []byte) (int, net.Addr, error) { 86 | n, addr, err := c.PacketConn.ReadFrom(b) 87 | if err != nil { 88 | return n, addr, err 89 | } 90 | bb, err := Unpack(b[c.Cipher.SaltSize():], b[:n], c) 91 | if err != nil { 92 | return n, addr, err 93 | } 94 | copy(b, bb) 95 | return len(bb), addr, err 96 | } 97 | -------------------------------------------------------------------------------- /socks/socks.go: -------------------------------------------------------------------------------- 1 | // Package socks implements essential parts of SOCKS protocol. 2 | package socks 3 | 4 | import ( 5 | "io" 6 | "net" 7 | "strconv" 8 | ) 9 | 10 | // SOCKS request commands as defined in RFC 1928 section 4. 11 | const ( 12 | CmdConnect = 1 13 | CmdBind = 2 14 | CmdUDPAssociate = 3 15 | ) 16 | 17 | // SOCKS address types as defined in RFC 1928 section 5. 18 | const ( 19 | AtypIPv4 = 1 20 | AtypDomainName = 3 21 | AtypIPv6 = 4 22 | ) 23 | 24 | // Error represents a SOCKS error 25 | type Error byte 26 | 27 | func (err Error) Error() string { 28 | return "SOCKS error: " + strconv.Itoa(int(err)) 29 | } 30 | 31 | // SOCKS errors as defined in RFC 1928 section 6. 32 | const ( 33 | ErrGeneralFailure = Error(1) 34 | ErrConnectionNotAllowed = Error(2) 35 | ErrNetworkUnreachable = Error(3) 36 | ErrHostUnreachable = Error(4) 37 | ErrConnectionRefused = Error(5) 38 | ErrTTLExpired = Error(6) 39 | ErrCommandNotSupported = Error(7) 40 | ErrAddressNotSupported = Error(8) 41 | ) 42 | 43 | // MaxAddrLen is the maximum size of SOCKS address in bytes. 44 | const MaxAddrLen = 1 + 1 + 255 + 2 45 | 46 | // Addr represents a SOCKS address as defined in RFC 1928 section 5. 47 | type Addr []byte 48 | 49 | // String serializes SOCKS address a to string form. 50 | func (a Addr) String() string { 51 | var host, port string 52 | 53 | switch a[0] { // address type 54 | case AtypDomainName: 55 | host = string(a[2 : 2+a[1]]) 56 | port = strconv.Itoa((int(a[2+a[1]]) << 8) | int(a[2+a[1]+1])) 57 | case AtypIPv4: 58 | host = net.IP(a[1 : 1+net.IPv4len]).String() 59 | port = strconv.Itoa((int(a[1+net.IPv4len]) << 8) | int(a[1+net.IPv4len+1])) 60 | case AtypIPv6: 61 | host = net.IP(a[1 : 1+net.IPv6len]).String() 62 | port = strconv.Itoa((int(a[1+net.IPv6len]) << 8) | int(a[1+net.IPv6len+1])) 63 | } 64 | 65 | return net.JoinHostPort(host, port) 66 | } 67 | 68 | func readAddr(r io.Reader, b []byte) (Addr, error) { 69 | if len(b) < MaxAddrLen { 70 | return nil, io.ErrShortBuffer 71 | } 72 | _, err := io.ReadFull(r, b[:1]) // read 1st byte for address type 73 | if err != nil { 74 | return nil, err 75 | } 76 | 77 | switch b[0] { 78 | case AtypDomainName: 79 | _, err = io.ReadFull(r, b[1:2]) // read 2nd byte for domain length 80 | if err != nil { 81 | return nil, err 82 | } 83 | _, err = io.ReadFull(r, b[2:2+b[1]+2]) 84 | return b[:1+1+b[1]+2], err 85 | case AtypIPv4: 86 | _, err = io.ReadFull(r, b[1:1+net.IPv4len+2]) 87 | return b[:1+net.IPv4len+2], err 88 | case AtypIPv6: 89 | _, err = io.ReadFull(r, b[1:1+net.IPv6len+2]) 90 | return b[:1+net.IPv6len+2], err 91 | } 92 | 93 | return nil, ErrAddressNotSupported 94 | } 95 | 96 | // ReadAddr reads just enough bytes from r to get a valid Addr. 97 | func ReadAddr(r io.Reader) (Addr, error) { 98 | return readAddr(r, make([]byte, MaxAddrLen)) 99 | } 100 | 101 | // SplitAddr slices a SOCKS address from beginning of b. Returns nil if failed. 102 | func SplitAddr(b []byte) Addr { 103 | addrLen := 1 104 | if len(b) < addrLen { 105 | return nil 106 | } 107 | 108 | switch b[0] { 109 | case AtypDomainName: 110 | if len(b) < 2 { 111 | return nil 112 | } 113 | addrLen = 1 + 1 + int(b[1]) + 2 114 | case AtypIPv4: 115 | addrLen = 1 + net.IPv4len + 2 116 | case AtypIPv6: 117 | addrLen = 1 + net.IPv6len + 2 118 | default: 119 | return nil 120 | 121 | } 122 | 123 | if len(b) < addrLen { 124 | return nil 125 | } 126 | 127 | return b[:addrLen] 128 | } 129 | 130 | // ParseAddr parses the address in string s. Returns nil if failed. 131 | func ParseAddr(s string) Addr { 132 | var addr Addr 133 | host, port, err := net.SplitHostPort(s) 134 | if err != nil { 135 | return nil 136 | } 137 | if ip := net.ParseIP(host); ip != nil { 138 | if ip4 := ip.To4(); ip4 != nil { 139 | addr = make([]byte, 1+net.IPv4len+2) 140 | addr[0] = AtypIPv4 141 | copy(addr[1:], ip4) 142 | } else { 143 | addr = make([]byte, 1+net.IPv6len+2) 144 | addr[0] = AtypIPv6 145 | copy(addr[1:], ip) 146 | } 147 | } else { 148 | if len(host) > 255 { 149 | return nil 150 | } 151 | addr = make([]byte, 1+1+len(host)+2) 152 | addr[0] = AtypDomainName 153 | addr[1] = byte(len(host)) 154 | copy(addr[2:], host) 155 | } 156 | 157 | portnum, err := strconv.ParseUint(port, 10, 16) 158 | if err != nil { 159 | return nil 160 | } 161 | 162 | addr[len(addr)-2], addr[len(addr)-1] = byte(portnum>>8), byte(portnum) 163 | 164 | return addr 165 | } 166 | 167 | // Handshake fast-tracks SOCKS initialization to get target address to connect. 168 | func Handshake(rw io.ReadWriter) (Addr, error) { 169 | // Read RFC 1928 for request and reply structure and sizes. 170 | buf := make([]byte, MaxAddrLen) 171 | // read VER, NMETHODS, METHODS 172 | if _, err := io.ReadFull(rw, buf[:2]); err != nil { 173 | return nil, err 174 | } 175 | nmethods := buf[1] 176 | if _, err := io.ReadFull(rw, buf[:nmethods]); err != nil { 177 | return nil, err 178 | } 179 | // write VER METHOD 180 | if _, err := rw.Write([]byte{5, 0}); err != nil { 181 | return nil, err 182 | } 183 | // read VER CMD RSV ATYP DST.ADDR DST.PORT 184 | if _, err := io.ReadFull(rw, buf[:3]); err != nil { 185 | return nil, err 186 | } 187 | if buf[1] != CmdConnect { 188 | return nil, ErrCommandNotSupported 189 | } 190 | addr, err := readAddr(rw, buf) 191 | if err != nil { 192 | return nil, err 193 | } 194 | // write VER REP RSV ATYP BND.ADDR BND.PORT 195 | _, err = rw.Write([]byte{5, 0, 0, 1, 0, 0, 0, 0, 0, 0}) 196 | return addr, err 197 | } 198 | -------------------------------------------------------------------------------- /udp.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "net" 6 | "sync" 7 | "time" 8 | 9 | "github.com/riobard/go-shadowsocks2/socks" 10 | ) 11 | 12 | const udpBufSize = 64 * 1024 13 | 14 | var bufPool = sync.Pool{New: func() interface{} { return make([]byte, udpBufSize) }} 15 | 16 | // Listen on laddr for UDP packets, encrypt and send to server to reach target. 17 | func udpLocal(laddr, server, target string, shadow func(net.PacketConn) net.PacketConn) { 18 | srvAddr, err := net.ResolveUDPAddr("udp", server) 19 | if err != nil { 20 | logf("UDP server address error: %v", err) 21 | return 22 | } 23 | 24 | tgt := socks.ParseAddr(target) 25 | if tgt == nil { 26 | err = fmt.Errorf("invalid target address: %q", target) 27 | logf("UDP target address error: %v", err) 28 | return 29 | } 30 | 31 | c, err := net.ListenPacket("udp", laddr) 32 | if err != nil { 33 | logf("UDP local listen error: %v", err) 34 | return 35 | } 36 | defer c.Close() 37 | 38 | m := make(map[string]chan []byte) 39 | var lock sync.Mutex 40 | 41 | logf("UDP tunnel %s <-> %s <-> %s", laddr, server, target) 42 | for { 43 | buf := bufPool.Get().([]byte) 44 | copy(buf, tgt) 45 | n, raddr, err := c.ReadFrom(buf[len(tgt):]) 46 | if err != nil { 47 | logf("UDP local read error: %v", err) 48 | continue 49 | } 50 | 51 | lock.Lock() 52 | k := raddr.String() 53 | ch := m[k] 54 | if ch == nil { 55 | pc, err := net.ListenPacket("udp", "") 56 | if err != nil { 57 | logf("failed to create UDP socket: %v", err) 58 | goto Unlock 59 | } 60 | pc = shadow(pc) 61 | ch = make(chan []byte, 1) // must use buffered chan 62 | m[k] = ch 63 | 64 | go func() { // recv from user and send to udpRemote 65 | for buf := range ch { 66 | pc.SetReadDeadline(time.Now().Add(config.UDPTimeout)) // extend read timeout 67 | if _, err := pc.WriteTo(buf, srvAddr); err != nil { 68 | logf("UDP local write error: %v", err) 69 | } 70 | bufPool.Put(buf[:cap(buf)]) 71 | } 72 | }() 73 | 74 | go func() { // recv from udpRemote and send to user 75 | if err := timedCopy(raddr, c, pc, config.UDPTimeout, false); err != nil { 76 | if err, ok := err.(net.Error); ok && err.Timeout() { 77 | // ignore i/o timeout 78 | } else { 79 | logf("timedCopy error: %v", err) 80 | } 81 | } 82 | pc.Close() 83 | lock.Lock() 84 | if ch := m[k]; ch != nil { 85 | close(ch) 86 | } 87 | delete(m, k) 88 | lock.Unlock() 89 | }() 90 | } 91 | Unlock: 92 | lock.Unlock() 93 | 94 | select { 95 | case ch <- buf[:len(tgt)+n]: // send 96 | default: // drop 97 | bufPool.Put(buf) 98 | } 99 | } 100 | } 101 | 102 | // Listen on addr for encrypted packets and basically do UDP NAT. 103 | func udpRemote(addr string, shadow func(net.PacketConn) net.PacketConn) { 104 | c, err := net.ListenPacket("udp", addr) 105 | if err != nil { 106 | logf("UDP remote listen error: %v", err) 107 | return 108 | } 109 | defer c.Close() 110 | c = shadow(c) 111 | 112 | m := make(map[string]chan []byte) 113 | var lock sync.Mutex 114 | 115 | logf("listening UDP on %s", addr) 116 | for { 117 | buf := bufPool.Get().([]byte) 118 | n, raddr, err := c.ReadFrom(buf) 119 | if err != nil { 120 | logf("UDP remote read error: %v", err) 121 | continue 122 | } 123 | 124 | lock.Lock() 125 | k := raddr.String() 126 | ch := m[k] 127 | if ch == nil { 128 | pc, err := net.ListenPacket("udp", "") 129 | if err != nil { 130 | logf("failed to create UDP socket: %v", err) 131 | goto Unlock 132 | } 133 | ch = make(chan []byte, 1) // must use buffered chan 134 | m[k] = ch 135 | 136 | go func() { // receive from udpLocal and send to target 137 | var tgtUDPAddr *net.UDPAddr 138 | var err error 139 | 140 | for buf := range ch { 141 | tgtAddr := socks.SplitAddr(buf) 142 | if tgtAddr == nil { 143 | logf("failed to split target address from packet: %q", buf) 144 | goto End 145 | } 146 | tgtUDPAddr, err = net.ResolveUDPAddr("udp", tgtAddr.String()) 147 | if err != nil { 148 | logf("failed to resolve target UDP address: %v", err) 149 | goto End 150 | } 151 | pc.SetReadDeadline(time.Now().Add(config.UDPTimeout)) 152 | if _, err = pc.WriteTo(buf[len(tgtAddr):], tgtUDPAddr); err != nil { 153 | logf("UDP remote write error: %v", err) 154 | goto End 155 | } 156 | End: 157 | bufPool.Put(buf[:cap(buf)]) 158 | } 159 | }() 160 | 161 | go func() { // receive from udpLocal and send to client 162 | if err := timedCopy(raddr, c, pc, config.UDPTimeout, true); err != nil { 163 | if err, ok := err.(net.Error); ok && err.Timeout() { 164 | // ignore i/o timeout 165 | } else { 166 | logf("timedCopy error: %v", err) 167 | } 168 | } 169 | pc.Close() 170 | lock.Lock() 171 | if ch := m[k]; ch != nil { 172 | close(ch) 173 | } 174 | delete(m, k) 175 | lock.Unlock() 176 | }() 177 | } 178 | Unlock: 179 | lock.Unlock() 180 | 181 | select { 182 | case ch <- buf[:n]: // sent 183 | default: // drop 184 | bufPool.Put(buf) 185 | } 186 | } 187 | } 188 | 189 | // copy from src to dst at target with read timeout 190 | func timedCopy(target net.Addr, dst, src net.PacketConn, timeout time.Duration, prependSrcAddr bool) error { 191 | buf := bufPool.Get().([]byte) 192 | defer bufPool.Put(buf) 193 | 194 | for { 195 | src.SetReadDeadline(time.Now().Add(timeout)) 196 | n, raddr, err := src.ReadFrom(buf) 197 | if err != nil { 198 | return err 199 | } 200 | 201 | if prependSrcAddr { // server -> client: prepend original packet source address 202 | srcAddr := socks.ParseAddr(raddr.String()) 203 | copy(buf[len(srcAddr):], buf[:n]) 204 | copy(buf, srcAddr) 205 | if _, err = dst.WriteTo(buf[:len(srcAddr)+n], target); err != nil { 206 | return err 207 | } 208 | } else { // client -> user: strip original packet source address 209 | srcAddr := socks.SplitAddr(buf[:n]) 210 | if _, err = dst.WriteTo(buf[len(srcAddr):n], target); err != nil { 211 | return err 212 | } 213 | } 214 | } 215 | } 216 | -------------------------------------------------------------------------------- /shadowaead/stream.go: -------------------------------------------------------------------------------- 1 | package shadowaead 2 | 3 | import ( 4 | "crypto/cipher" 5 | "crypto/rand" 6 | "io" 7 | "net" 8 | "sync" 9 | ) 10 | 11 | const ( 12 | // payloadSizeMask is the maximum size of payload in bytes. 13 | payloadSizeMask = 0x3FFF // 16*1024 - 1 14 | bufSize = 17 * 1024 // >= 2+aead.Overhead()+payloadSizeMask+aead.Overhead() 15 | ) 16 | 17 | var bufPool = sync.Pool{New: func() interface{} { return make([]byte, bufSize) }} 18 | 19 | type Writer struct { 20 | io.Writer 21 | cipher.AEAD 22 | nonce [32]byte // should be sufficient for most nonce sizes 23 | } 24 | 25 | // NewWriter wraps an io.Writer with authenticated encryption. 26 | func NewWriter(w io.Writer, aead cipher.AEAD) *Writer { return &Writer{Writer: w, AEAD: aead} } 27 | 28 | // Write encrypts p and writes to the embedded io.Writer. 29 | func (w *Writer) Write(p []byte) (n int, err error) { 30 | buf := bufPool.Get().([]byte) 31 | defer bufPool.Put(buf) 32 | nonce := w.nonce[:w.NonceSize()] 33 | tag := w.Overhead() 34 | off := 2 + tag 35 | for nr := payloadSizeMask; n < len(p); n += nr { // write piecemeal in max payload size chunks 36 | if tail := len(p) - n; tail < payloadSizeMask { 37 | nr = tail 38 | } 39 | buf[0], buf[1] = byte(nr>>8), byte(nr) // big-endian payload size 40 | w.Seal(buf[:0], nonce, buf[:2], nil) 41 | increment(nonce) 42 | w.Seal(buf[:off], nonce, p[n:n+nr], nil) 43 | increment(nonce) 44 | if _, err = w.Writer.Write(buf[:off+nr+tag]); err != nil { 45 | return 46 | } 47 | } 48 | return 49 | } 50 | 51 | // ReadFrom reads from the given io.Reader until EOF or error, encrypts and 52 | // writes to the embedded io.Writer. Returns number of bytes read from r and 53 | // any error encountered. 54 | func (w *Writer) ReadFrom(r io.Reader) (n int64, err error) { 55 | buf := bufPool.Get().([]byte) 56 | defer bufPool.Put(buf) 57 | nonce := w.nonce[:w.NonceSize()] 58 | tag := w.Overhead() 59 | off := 2 + tag 60 | for { 61 | nr, er := r.Read(buf[off : off+payloadSizeMask]) 62 | n += int64(nr) 63 | buf[0], buf[1] = byte(nr>>8), byte(nr) 64 | w.Seal(buf[:0], nonce, buf[:2], nil) 65 | increment(nonce) 66 | w.Seal(buf[:off], nonce, buf[off:off+nr], nil) 67 | increment(nonce) 68 | if _, ew := w.Writer.Write(buf[:off+nr+tag]); ew != nil { 69 | err = ew 70 | return 71 | } 72 | if er != nil { 73 | if er != io.EOF { // ignore EOF as per io.ReaderFrom contract 74 | err = er 75 | } 76 | return 77 | } 78 | } 79 | } 80 | 81 | type Reader struct { 82 | io.Reader 83 | cipher.AEAD 84 | nonce [32]byte // should be sufficient for most nonce sizes 85 | buf []byte // to be put back into bufPool 86 | off int // offset to unconsumed part of buf 87 | } 88 | 89 | // NewReader wraps an io.Reader with authenticated decryption. 90 | func NewReader(r io.Reader, aead cipher.AEAD) *Reader { return &Reader{Reader: r, AEAD: aead} } 91 | 92 | // Read and decrypt a record into p. len(p) >= max payload size + AEAD overhead. 93 | func (r *Reader) read(p []byte) (int, error) { 94 | nonce := r.nonce[:r.NonceSize()] 95 | tag := r.Overhead() 96 | 97 | // decrypt payload size 98 | p = p[:2+tag] 99 | if _, err := io.ReadFull(r.Reader, p); err != nil { 100 | return 0, err 101 | } 102 | _, err := r.Open(p[:0], nonce, p, nil) 103 | increment(nonce) 104 | if err != nil { 105 | return 0, err 106 | } 107 | 108 | // decrypt payload 109 | size := (int(p[0])<<8 + int(p[1])) & payloadSizeMask 110 | p = p[:size+tag] 111 | if _, err := io.ReadFull(r.Reader, p); err != nil { 112 | return 0, err 113 | } 114 | _, err = r.Open(p[:0], nonce, p, nil) 115 | increment(nonce) 116 | if err != nil { 117 | return 0, err 118 | } 119 | return size, nil 120 | } 121 | 122 | // Read reads from the embedded io.Reader, decrypts and writes to p. 123 | func (r *Reader) Read(p []byte) (int, error) { 124 | if r.buf == nil { 125 | if len(p) >= payloadSizeMask+r.Overhead() { 126 | return r.read(p) 127 | } 128 | b := bufPool.Get().([]byte) 129 | n, err := r.read(b) 130 | if err != nil { 131 | return 0, err 132 | } 133 | r.buf = b[:n] 134 | r.off = 0 135 | } 136 | 137 | n := copy(p, r.buf[r.off:]) 138 | r.off += n 139 | if r.off == len(r.buf) { 140 | bufPool.Put(r.buf[:cap(r.buf)]) 141 | r.buf = nil 142 | } 143 | return n, nil 144 | } 145 | 146 | // WriteTo reads from the embedded io.Reader, decrypts and writes to w until 147 | // there's no more data to write or when an error occurs. Return number of 148 | // bytes written to w and any error encountered. 149 | func (r *Reader) WriteTo(w io.Writer) (n int64, err error) { 150 | if r.buf == nil { 151 | r.buf = bufPool.Get().([]byte) 152 | r.off = len(r.buf) 153 | } 154 | 155 | for { 156 | for r.off < len(r.buf) { 157 | nw, ew := w.Write(r.buf[r.off:]) 158 | r.off += nw 159 | n += int64(nw) 160 | if ew != nil { 161 | if r.off == len(r.buf) { 162 | bufPool.Put(r.buf[:cap(r.buf)]) 163 | r.buf = nil 164 | } 165 | err = ew 166 | return 167 | } 168 | } 169 | 170 | nr, er := r.read(r.buf) 171 | if er != nil { 172 | if er != io.EOF { 173 | err = er 174 | } 175 | return 176 | } 177 | r.buf = r.buf[:nr] 178 | r.off = 0 179 | } 180 | } 181 | 182 | // increment little-endian encoded unsigned integer b. Wrap around on overflow. 183 | func increment(b []byte) { 184 | for i := range b { 185 | b[i]++ 186 | if b[i] != 0 { 187 | return 188 | } 189 | } 190 | } 191 | 192 | type Conn struct { 193 | net.Conn 194 | Cipher 195 | r *Reader 196 | w *Writer 197 | } 198 | 199 | // NewConn wraps a stream-oriented net.Conn with cipher. 200 | func NewConn(c net.Conn, ciph Cipher) *Conn { return &Conn{Conn: c, Cipher: ciph} } 201 | 202 | func (c *Conn) initReader() error { 203 | salt := make([]byte, c.SaltSize()) 204 | if _, err := io.ReadFull(c.Conn, salt); err != nil { 205 | return err 206 | } 207 | 208 | aead, err := c.Decrypter(salt) 209 | if err != nil { 210 | return err 211 | } 212 | 213 | c.r = NewReader(c.Conn, aead) 214 | return nil 215 | } 216 | 217 | func (c *Conn) Read(b []byte) (int, error) { 218 | if c.r == nil { 219 | if err := c.initReader(); err != nil { 220 | return 0, err 221 | } 222 | } 223 | return c.r.Read(b) 224 | } 225 | 226 | func (c *Conn) WriteTo(w io.Writer) (int64, error) { 227 | if c.r == nil { 228 | if err := c.initReader(); err != nil { 229 | return 0, err 230 | } 231 | } 232 | return c.r.WriteTo(w) 233 | } 234 | 235 | func (c *Conn) initWriter() error { 236 | salt := make([]byte, c.SaltSize()) 237 | if _, err := rand.Read(salt); err != nil { 238 | return err 239 | } 240 | aead, err := c.Encrypter(salt) 241 | if err != nil { 242 | return err 243 | } 244 | _, err = c.Conn.Write(salt) 245 | if err != nil { 246 | return err 247 | } 248 | c.w = NewWriter(c.Conn, aead) 249 | return nil 250 | } 251 | 252 | func (c *Conn) Write(b []byte) (int, error) { 253 | if c.w == nil { 254 | if err := c.initWriter(); err != nil { 255 | return 0, err 256 | } 257 | } 258 | return c.w.Write(b) 259 | } 260 | 261 | func (c *Conn) ReadFrom(r io.Reader) (int64, error) { 262 | if c.w == nil { 263 | if err := c.initWriter(); err != nil { 264 | return 0, err 265 | } 266 | } 267 | return c.w.ReadFrom(r) 268 | } 269 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | --------------------------------------------------------------------------------