pax_global_header00006660000000000000000000000064136646405140014523gustar00rootroot0000000000000052 comment=b9717056b251747149cacb44458fe02e420b9d9b v2ray-plugin-1.3.1/000077500000000000000000000000001366464051400140645ustar00rootroot00000000000000v2ray-plugin-1.3.1/.circleci/000077500000000000000000000000001366464051400157175ustar00rootroot00000000000000v2ray-plugin-1.3.1/.circleci/config.yml000066400000000000000000000007321366464051400177110ustar00rootroot00000000000000version: 2 jobs: build: docker: - image: circleci/golang:1.13 working_directory: ~/code steps: - checkout - run: sudo apt-get update && sudo apt-get install -y upx - restore_cache: key: go-pkg-{{ checksum "go.sum" }} - run: ./build-release.sh - save_cache: paths: - /go/pkg key: go-pkg-{{ checksum "go.sum" }} - store_artifacts: path: bin destination: bin v2ray-plugin-1.3.1/.gitignore000066400000000000000000000000341366464051400160510ustar00rootroot00000000000000v2ray-plugin* /bin/ /.idea/ v2ray-plugin-1.3.1/LICENSE000066400000000000000000000022041366464051400150670ustar00rootroot00000000000000MIT License Copyright (c) 2019 by Max Lv Copyright (C) 2019 by Mygod Studio Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. v2ray-plugin-1.3.1/README.md000066400000000000000000000047411366464051400153510ustar00rootroot00000000000000# Yet another SIP003 plugin for shadowsocks, based on v2ray [![CircleCI](https://circleci.com/gh/shadowsocks/v2ray-plugin.svg?style=shield)](https://circleci.com/gh/shadowsocks/v2ray-plugin) [![Releases](https://img.shields.io/github/downloads/shadowsocks/v2ray-plugin/total.svg)](https://github.com/shadowsocks/v2ray-plugin/releases) [![Language: Go](https://img.shields.io/badge/go-1.12+-blue.svg)](https://github.com/shadowsocks/v2ray-plugin/search?l=go) [![Go Report Card](https://goreportcard.com/badge/github.com/shadowsocks/v2ray-plugin)](https://goreportcard.com/report/github.com/shadowsocks/v2ray-plugin) [![License](https://img.shields.io/github/license/shadowsocks/v2ray-plugin.svg)](LICENSE) ## Build * `go build` * Alternatively, you can grab the latest nightly from Circle CI by logging into Circle CI or adding `#artifacts` at the end of URL like such: https://circleci.com/gh/shadowsocks/v2ray-plugin/20#artifacts ## Usage See command line args for advanced usages. ### Shadowsocks over websocket (HTTP) On your server ```sh ss-server -c config.json -p 80 --plugin v2ray-plugin --plugin-opts "server" ``` On your client ```sh ss-local -c config.json -p 80 --plugin v2ray-plugin ``` ### Shadowsocks over websocket (HTTPS) On your server ```sh ss-server -c config.json -p 443 --plugin v2ray-plugin --plugin-opts "server;tls;host=mydomain.me" ``` On your client ```sh ss-local -c config.json -p 443 --plugin v2ray-plugin --plugin-opts "tls;host=mydomain.me" ``` ### Shadowsocks over quic On your server ```sh ss-server -c config.json -p 443 --plugin v2ray-plugin --plugin-opts "server;mode=quic;host=mydomain.me" ``` On your client ```sh ss-local -c config.json -p 443 --plugin v2ray-plugin --plugin-opts "mode=quic;host=mydomain.me" ``` ### Issue a cert for TLS and QUIC v2ray-plugin will look for TLS certificates signed by [acme.sh](https://github.com/Neilpang/acme.sh) by default. Here's some sample commands for issuing a certificate using CloudFlare. You can find commands for issuing certificates for other DNS providers at acme.sh. ```sh curl https://get.acme.sh | sh ~/.acme.sh/acme.sh --issue --dns dns_cf -d mydomain.me ``` Alternatively, you can specify path to your certificates using option `cert` and `key`. ### Use `certRaw` to pass certificate Instead of using `cert` to pass the certificate file, `certRaw` could be used to pass in PEM format certificate, that is the content between `-----BEGIN CERTIFICATE-----` and `-----END CERTIFICATE-----` without the line breaks. v2ray-plugin-1.3.1/SECURITY.md000066400000000000000000000003601366464051400156540ustar00rootroot00000000000000# Security Policy ## Supported Versions | Version | Supported | | ------- | ------------------ | | latest | :white_check_mark: | | else | :x: | ## Reporting a Vulnerability Please email to repo owner: Max Lv v2ray-plugin-1.3.1/args.go000066400000000000000000000107571366464051400153610ustar00rootroot00000000000000package main import ( "bytes" "fmt" "net" "os" "sort" "strings" ) func isIPv6(str string) bool { ip := net.ParseIP(str) return ip != nil && strings.Contains(str, ":") } // Key–value mappings for the representation of client and server options. // Args maps a string key to a list of values. It is similar to url.Values. type Args map[string][]string // Get the first value associated with the given key. If there are any values // associated with the key, the value return has the value and ok is set to // true. If there are no values for the given key, value is "" and ok is false. // If you need access to multiple values, use the map directly. func (args Args) Get(key string) (value string, ok bool) { if args == nil { return "", false } vals, ok := args[key] if !ok || len(vals) == 0 { return "", false } return vals[0], true } // Append value to the list of values for key. func (args Args) Add(key, value string) { args[key] = append(args[key], value) } // Return the index of the next unescaped byte in s that is in the term set, or // else the length of the string if no terminators appear. Additionally return // the unescaped string up to the returned index. func indexUnescaped(s string, term []byte) (int, string, error) { var i int unesc := make([]byte, 0) for i = 0; i < len(s); i++ { b := s[i] // A terminator byte? if bytes.IndexByte(term, b) != -1 { break } if b == '\\' { i++ if i >= len(s) { return 0, "", fmt.Errorf("nothing following final escape in %q", s) } b = s[i] } unesc = append(unesc, b) } return i, string(unesc), nil } // Parse SS_PLUGIN options from environment variables func parseEnv() (opts Args, err error) { opts = make(Args) ss_remote_host := os.Getenv("SS_REMOTE_HOST") ss_remote_port := os.Getenv("SS_REMOTE_PORT") ss_local_host := os.Getenv("SS_LOCAL_HOST") ss_local_port := os.Getenv("SS_LOCAL_PORT") if len(ss_remote_host) == 0 { return } if len(ss_remote_port) == 0 { return } if len(ss_local_host) == 0 { return } if len(ss_local_host) == 0 { return } opts.Add("remoteAddr", ss_remote_host) opts.Add("remotePort", ss_remote_port) opts.Add("localAddr", ss_local_host) opts.Add("localPort", ss_local_port) ss_plugin_options := os.Getenv("SS_PLUGIN_OPTIONS") if len(ss_plugin_options) > 0 { other_opts, err := parsePluginOptions(ss_plugin_options) if err != nil { return nil, err } for k, v := range other_opts { opts[k] = v } } return opts, nil } // Parse a name–value mapping as from SS_PLUGIN_OPTIONS. // // " is a k=v string value with options that are to be passed to the // transport. semicolons, equal signs and backslashes must be escaped // with a backslash." // Example: secret=nou;cache=/tmp/cache;secret=yes func parsePluginOptions(s string) (opts Args, err error) { opts = make(Args) if len(s) == 0 { return } i := 0 for { var key, value string var offset, begin int if i >= len(s) { break } begin = i // Read the key. offset, key, err = indexUnescaped(s[i:], []byte{'=', ';'}) if err != nil { return } if len(key) == 0 { err = fmt.Errorf("empty key in %q", s[begin:i]) return } i += offset // End of string or no equals sign? if i >= len(s) || s[i] != '=' { opts.Add(key, "1") // Skip the semicolon. i++ continue } // Skip the equals sign. i++ // Read the value. offset, value, err = indexUnescaped(s[i:], []byte{';'}) if err != nil { return } i += offset opts.Add(key, value) // Skip the semicolon. i++ } return opts, nil } // Escape backslashes and all the bytes that are in set. func backslashEscape(s string, set []byte) string { var buf bytes.Buffer for _, b := range []byte(s) { if b == '\\' || bytes.IndexByte(set, b) != -1 { buf.WriteByte('\\') } buf.WriteByte(b) } return buf.String() } // Encode a name–value mapping so that it is suitable to go in the ARGS option // of an SMETHOD line. The output is sorted by key. The "ARGS:" prefix is not // added. // // "Equal signs and commas [and backslashes] must be escaped with a backslash." func encodeSmethodArgs(args Args) string { if args == nil { return "" } keys := make([]string, 0, len(args)) for key := range args { keys = append(keys, key) } sort.Strings(keys) escape := func(s string) string { return backslashEscape(s, []byte{'=', ','}) } var pairs []string for _, key := range keys { for _, value := range args[key] { pairs = append(pairs, escape(key)+"="+escape(value)) } } return strings.Join(pairs, ",") } v2ray-plugin-1.3.1/build-release.sh000077500000000000000000000040451366464051400171430ustar00rootroot00000000000000#!/bin/bash sum="sha1sum" if ! hash sha1sum 2>/dev/null; then if ! hash shasum 2>/dev/null; then echo "I can't see 'sha1sum' or 'shasum'" echo "Please install one of them!" exit fi sum="shasum" fi [[ -z $upx ]] && upx="echo pending" if [[ $upx == "echo pending" ]] && hash upx 2>/dev/null; then upx="upx -9" fi VERSION=$(git describe --tags) LDFLAGS="-X main.VERSION=$VERSION -s -w" GCFLAGS="" OSES=(linux darwin windows freebsd) ARCHS=(amd64 386) mkdir bin for os in ${OSES[@]}; do for arch in ${ARCHS[@]}; do suffix="" if [ "$os" == "windows" ] then suffix=".exe" fi env CGO_ENABLED=0 GOOS=$os GOARCH=$arch go build -v -ldflags "$LDFLAGS" -gcflags "$GCFLAGS" -o v2ray-plugin_${os}_${arch}${suffix} $upx v2ray-plugin_${os}_${arch}${suffix} >/dev/null tar -zcf bin/v2ray-plugin-${os}-${arch}-$VERSION.tar.gz v2ray-plugin_${os}_${arch}${suffix} $sum bin/v2ray-plugin-${os}-${arch}-$VERSION.tar.gz done done # ARM ARMS=(5 6 7) for v in ${ARMS[@]}; do env CGO_ENABLED=0 GOOS=linux GOARCH=arm GOARM=$v go build -v -ldflags "$LDFLAGS" -gcflags "$GCFLAGS" -o v2ray-plugin_linux_arm$v done $upx v2ray-plugin_linux_arm* >/dev/null tar -zcf bin/v2ray-plugin-linux-arm-$VERSION.tar.gz v2ray-plugin_linux_arm* $sum bin/v2ray-plugin-linux-arm-$VERSION.tar.gz # ARM64 (ARMv8 or aarch64) env CGO_ENABLED=0 GOOS=linux GOARCH=arm64 go build -v -ldflags "$LDFLAGS" -gcflags "$GCFLAGS" -o v2ray-plugin_linux_arm64 $upx v2ray-plugin_linux_arm64 >/dev/null tar -zcf bin/v2ray-plugin-linux-arm64-$VERSION.tar.gz v2ray-plugin_linux_arm64 $sum bin/v2ray-plugin-linux-arm64-$VERSION.tar.gz # MIPS MIPSS=(mips mipsle) for v in ${MIPSS[@]}; do env CGO_ENABLED=0 GOOS=linux GOARCH=$v go build -v -ldflags "$LDFLAGS" -gcflags "$GCFLAGS" -o v2ray-plugin_linux_$v env CGO_ENABLED=0 GOOS=linux GOARCH=$v GOMIPS=softfloat go build -ldflags "$LDFLAGS" -gcflags "$GCFLAGS" -o v2ray-plugin_linux_${v}_sf done $upx v2ray-plugin_linux_mips* >/dev/null tar -zcf bin/v2ray-plugin-linux-mips-$VERSION.tar.gz v2ray-plugin_linux_mips* $sum bin/v2ray-plugin-linux-mips-$VERSION.tar.gz v2ray-plugin-1.3.1/errors.generated.go000066400000000000000000000003121366464051400176600ustar00rootroot00000000000000package main import "v2ray.com/core/common/errors" type errPathObjHolder struct{} func newError(values ...interface{}) *errors.Error { return errors.New(values...).WithPathObj(errPathObjHolder{}) } v2ray-plugin-1.3.1/go.mod000066400000000000000000000012161366464051400151720ustar00rootroot00000000000000module github.com/shadowsocks/v2ray-plugin require ( github.com/golang/mock v1.3.1 // indirect github.com/golang/protobuf v1.3.2 github.com/google/go-cmp v0.3.0 // indirect github.com/miekg/dns v1.1.14 // indirect golang.org/x/crypto v0.0.0-20190618222545-ea8f1a30c443 // indirect golang.org/x/net v0.0.0-20190619014844-b5b0513f8c1b // indirect golang.org/x/sys v0.0.0-20190619223125-e40ef342dc56 // indirect golang.org/x/text v0.3.2 // indirect google.golang.org/genproto v0.0.0-20190611190212-a7e196e89fd3 // indirect v2ray.com/core v4.19.1+incompatible ) replace v2ray.com/core => github.com/v2ray/v2ray-core v4.23.2+incompatible go 1.13 v2ray-plugin-1.3.1/go.sum000066400000000000000000000200301366464051400152120ustar00rootroot00000000000000cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/mock v1.1.1 h1:G5FRp8JnTd7RQH5kemVNlMeyXQAztQ3mOWV95KxsXH8= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.2.0 h1:28o5sBqPkBsMGnC6b4MvE2TzSr5/AT4c/1fLqVGIwlk= github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.3.1 h1:qGJ6qTW+x6xX/my+8YUVl4WNpX9B7+/l2tRsHGZ7f2s= github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1 h1:YF8+flBXS5eO826T4nzqPrxfhQThhXl0YzfuUPu4SBg= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/google/go-cmp v0.2.0 h1:+dTQ8DZQJz0Mb/HjFlkptS1FeQ4cWSnN941F8aEG4SQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0 h1:crn/baboCvb5fXaQ0IJ1SGTsTVrWpDsCWC8EGETZijY= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/gorilla/websocket v1.4.1 h1:q7AeDBpnBk8AogcD4DSag/Ukw/KV+YhzLj2bP5HvKCM= github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/miekg/dns v1.1.4/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= github.com/miekg/dns v1.1.14 h1:wkQWn9wIp4mZbwW8XV6Km6owkvRPbOiV004ZM2CkGvA= github.com/miekg/dns v1.1.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= github.com/refraction-networking/utls v0.0.0-20190909200633-43c36d3c1f57 h1:SL1K0QAuC1b54KoY1pjPWe6kSlsFHwK9/oC960fKrTY= github.com/refraction-networking/utls v0.0.0-20190909200633-43c36d3c1f57/go.mod h1:tz9gX959MEFfFN5whTIocCLUG57WiILqtdVxI8c6Wj0= github.com/v2ray/v2ray-core v4.23.2+incompatible h1:kAz3OdOM+R2ApJZu+SsC2iwaK3YGbG3CAXcZ80f3DEw= github.com/v2ray/v2ray-core v4.23.2+incompatible/go.mod h1:LtoljHM69/Tx4Niy/2vqWP8R2HPqS64NiaJaGkktn+Q= go.starlark.net v0.0.0-20190919145610-979af19b165c h1:WR7X1xgXJlXhQBdorVc9Db3RhwG+J/kp6bLuMyJjfVw= go.starlark.net v0.0.0-20190919145610-979af19b165c/go.mod h1:c1/X6cHgvdXj6pUlmWKMkuqRnW4K8x2vwt6JAaaircg= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190618222545-ea8f1a30c443 h1:IcSOAf4PyMp3U3XbIEj1/xJ2BjNN2jWv7JoyOsMxXUU= golang.org/x/crypto v0.0.0-20190618222545-ea8f1a30c443/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd h1:HuTn7WObtcDo9uEEU7rEqL0jYthdXAmZ6PP+meazmaU= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190619014844-b5b0513f8c1b h1:lkjdUzSyJ5P1+eal9fxXX9Xg2BTfswsonKUse48C0uE= golang.org/x/net v0.0.0-20190619014844-b5b0513f8c1b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f h1:wMNYb4v58l5UBM7MYRLPG6ZhfOqbKu7X5eyFl8ZhKvA= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58 h1:8gQV6CLnAEikrhgkHFbMAEhagSSnXWGV915qUMm9mrU= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522 h1:Ve1ORMCxvRmSXBwJK+t3Oy+V2vRW2OetUQBq4rJIkZE= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a h1:1BGLXjeY4akVXGgbC9HugT3Jv3hCI0z56oJR5vAMgBU= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190619223125-e40ef342dc56 h1:ILS6H+uzQt3ErlXg4LhN4hgHWQAHsaa+W+fYbf2SeMY= golang.org/x/sys v0.0.0-20190619223125-e40ef342dc56/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8 h1:Nw54tB0rB7hY/N0NQvRW8DG4Yk3Q6T9cu9RcFQDu1tc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20180831171423-11092d34479b h1:lohp5blsw53GBXtLyLNaTXPXS9pJ1tiTw61ZHUoE9Qw= google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190611190212-a7e196e89fd3 h1:0LGHEA/u5XLibPOx6D7D8FBT/ax6wT57vNKY0QckCwo= google.golang.org/genproto v0.0.0-20190611190212-a7e196e89fd3/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.24.0 h1:vb/1TCsVn3DcJlQ0Gs1yB1pKI6Do2/QNwxdKqmc/b0s= google.golang.org/grpc v1.24.0/go.mod h1:XDChyiUovWa60DnaeDeZmSW86xtLtjtZbwvSiRnRtcA= h12.io/socks v1.0.0/go.mod h1:MdYbo5/eB9ka7u5dzW2Qh0iSyJENwB3KI5H5ngenFGA= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= v2ray-plugin-1.3.1/log.go000066400000000000000000000006111366464051400151720ustar00rootroot00000000000000// Copyright 2014 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // +build !android package main import "log" func logInit() { } func logFatal(v ...interface{}) { log.Println(v...) } func logWarn(v ...interface{}) { log.Println(v...) } func logInfo(v ...interface{}) { log.Println(v...) } v2ray-plugin-1.3.1/log_android.go000066400000000000000000000032221366464051400166730ustar00rootroot00000000000000// +build android package main /* #cgo LDFLAGS: -landroid -llog #include #include #include */ import "C" import ( "fmt" "unsafe" alog "v2ray.com/core/app/log" "v2ray.com/core/common" "v2ray.com/core/common/log" "v2ray.com/core/common/serial" ) var ( ctag = C.CString("v2ray") ) type androidLogger struct {} func (l *androidLogger) Handle(msg log.Message) { var priority = C.ANDROID_LOG_FATAL // this value should never be used in client mode var message string switch msg := msg.(type) { case *log.GeneralMessage: switch msg.Severity { case log.Severity_Error: priority = C.ANDROID_LOG_ERROR case log.Severity_Warning: priority = C.ANDROID_LOG_WARN case log.Severity_Info: priority = C.ANDROID_LOG_INFO case log.Severity_Debug: priority = C.ANDROID_LOG_DEBUG } message = serial.ToString(msg.Content) default: message = msg.String() } cstr := C.CString(message) defer C.free(unsafe.Pointer(cstr)) C.__android_log_write(C.int(priority), ctag, cstr) } func logInit() { common.Must(alog.RegisterHandlerCreator(alog.LogType_Console, func(_ alog.LogType, _ alog.HandlerCreatorOptions) (log.Handler, error) { return &androidLogger{}, nil })) } func logFatal(v ...interface{}) { cstr := C.CString(fmt.Sprintln(v...)) defer C.free(unsafe.Pointer(cstr)) C.__android_log_write(C.ANDROID_LOG_FATAL, ctag, cstr) } func logWarn(v ...interface{}) { (&androidLogger{}).Handle(&log.GeneralMessage{Severity: log.Severity_Warning, Content: fmt.Sprintln(v...)}) } func logInfo(v ...interface{}) { (&androidLogger{}).Handle(&log.GeneralMessage{Severity: log.Severity_Info, Content: fmt.Sprintln(v...)}) } v2ray-plugin-1.3.1/main.go000066400000000000000000000244621366464051400153470ustar00rootroot00000000000000package main //go:generate errorgen import ( "flag" "fmt" "os" "os/signal" "os/user" "runtime" "strconv" "strings" "syscall" "github.com/golang/protobuf/proto" "v2ray.com/core" "v2ray.com/core/app/dispatcher" "v2ray.com/core/app/proxyman" _ "v2ray.com/core/app/proxyman/inbound" _ "v2ray.com/core/app/proxyman/outbound" "v2ray.com/core/common/net" "v2ray.com/core/common/protocol" "v2ray.com/core/common/serial" "v2ray.com/core/proxy/dokodemo" "v2ray.com/core/proxy/freedom" "v2ray.com/core/transport/internet" "v2ray.com/core/transport/internet/quic" "v2ray.com/core/transport/internet/tls" "v2ray.com/core/transport/internet/websocket" vlog "v2ray.com/core/app/log" clog "v2ray.com/core/common/log" "v2ray.com/core/common/platform/filesystem" ) var ( VERSION = "custom" ) var ( vpn = flag.Bool("V", false, "Run in VPN mode.") fastOpen = flag.Bool("fast-open", false, "Enable TCP fast open.") localAddr = flag.String("localAddr", "127.0.0.1", "local address to listen on.") localPort = flag.String("localPort", "1984", "local port to listen on.") remoteAddr = flag.String("remoteAddr", "127.0.0.1", "remote address to forward.") remotePort = flag.String("remotePort", "1080", "remote port to forward.") path = flag.String("path", "/", "URL path for websocket.") host = flag.String("host", "cloudfront.com", "Hostname for server.") tlsEnabled = flag.Bool("tls", false, "Enable TLS.") cert = flag.String("cert", "", "Path to TLS certificate file. Overrides certRaw. Default: ~/.acme.sh/{host}/fullchain.cer") certRaw = flag.String("certRaw", "", "Raw TLS certificate content. Intended only for Android.") key = flag.String("key", "", "(server) Path to TLS key file. Default: ~/.acme.sh/{host}/{host}.key") mode = flag.String("mode", "websocket", "Transport mode: websocket, quic (enforced tls).") mux = flag.Int("mux", 1, "Concurrent multiplexed connections (websocket client mode only).") server = flag.Bool("server", false, "Run in server mode") logLevel = flag.String("loglevel", "", "loglevel for v2ray: debug, info, warning (default), error, none.") version = flag.Bool("version", false, "Show current version of v2ray-plugin") ) func homeDir() string { usr, err := user.Current() if err != nil { logFatal(err) os.Exit(1) } return usr.HomeDir } func readCertificate() ([]byte, error) { if *cert != "" { return filesystem.ReadFile(*cert) } if *certRaw != "" { certHead := "-----BEGIN CERTIFICATE-----" certTail := "-----END CERTIFICATE-----" fixedCert := certHead + "\n" + *certRaw + "\n" + certTail return []byte(fixedCert), nil } panic("thou shalt not reach hear") } func logConfig(logLevel string) *vlog.Config { config := &vlog.Config{ ErrorLogLevel: clog.Severity_Warning, ErrorLogType: vlog.LogType_Console, AccessLogType: vlog.LogType_Console, } level := strings.ToLower(logLevel) switch level { case "debug": config.ErrorLogLevel = clog.Severity_Debug case "info": config.ErrorLogLevel = clog.Severity_Info case "error": config.ErrorLogLevel = clog.Severity_Error case "none": config.ErrorLogType = vlog.LogType_None config.AccessLogType = vlog.LogType_None } return config } func parseLocalAddr(localAddr string) []string { return strings.Split(localAddr, "|") } func generateConfig() (*core.Config, error) { lport, err := net.PortFromString(*localPort) if err != nil { return nil, newError("invalid localPort:", *localPort).Base(err) } rport, err := strconv.ParseUint(*remotePort, 10, 32) if err != nil { return nil, newError("invalid remotePort:", *remotePort).Base(err) } outboundProxy := serial.ToTypedMessage(&freedom.Config{ DestinationOverride: &freedom.DestinationOverride{ Server: &protocol.ServerEndpoint{ Address: net.NewIPOrDomain(net.ParseAddress(*remoteAddr)), Port: uint32(rport), }, }, }) var transportSettings proto.Message var connectionReuse bool switch *mode { case "websocket": transportSettings = &websocket.Config{ Path: *path, Header: []*websocket.Header{ {Key: "Host", Value: *host}, }, } if *mux != 0 { connectionReuse = true } case "quic": transportSettings = &quic.Config{ Security: &protocol.SecurityConfig{Type: protocol.SecurityType_NONE}, } *tlsEnabled = true default: return nil, newError("unsupported mode:", *mode) } streamConfig := internet.StreamConfig{ ProtocolName: *mode, TransportSettings: []*internet.TransportConfig{{ ProtocolName: *mode, Settings: serial.ToTypedMessage(transportSettings), }}, } if *fastOpen { streamConfig.SocketSettings = &internet.SocketConfig{Tfo: internet.SocketConfig_Enable} } if *tlsEnabled { tlsConfig := tls.Config{ServerName: *host} if *server { certificate := tls.Certificate{} if *cert == "" && *certRaw == "" { *cert = fmt.Sprintf("%s/.acme.sh/%s/fullchain.cer", homeDir(), *host) logWarn("No TLS cert specified, trying", *cert) } certificate.Certificate, err = readCertificate() if err != nil { return nil, newError("failed to read cert").Base(err) } if *key == "" { *key = fmt.Sprintf("%[1]s/.acme.sh/%[2]s/%[2]s.key", homeDir(), *host) logWarn("No TLS key specified, trying", *key) } certificate.Key, err = filesystem.ReadFile(*key) if err != nil { return nil, newError("failed to read key file").Base(err) } tlsConfig.Certificate = []*tls.Certificate{&certificate} } else if *cert != "" || *certRaw != "" { certificate := tls.Certificate{Usage: tls.Certificate_AUTHORITY_VERIFY} certificate.Certificate, err = readCertificate() if err != nil { return nil, newError("failed to read cert").Base(err) } tlsConfig.Certificate = []*tls.Certificate{&certificate} } streamConfig.SecurityType = serial.GetMessageType(&tlsConfig) streamConfig.SecuritySettings = []*serial.TypedMessage{serial.ToTypedMessage(&tlsConfig)} } apps := []*serial.TypedMessage{ serial.ToTypedMessage(&dispatcher.Config{}), serial.ToTypedMessage(&proxyman.InboundConfig{}), serial.ToTypedMessage(&proxyman.OutboundConfig{}), serial.ToTypedMessage(logConfig(*logLevel)), } if *server { proxyAddress := net.LocalHostIP if connectionReuse { // This address is required when mux is used on client. // dokodemo is not aware of mux connections by itself. proxyAddress = net.ParseAddress("v1.mux.cool") } localAddrs := parseLocalAddr(*localAddr) inbounds := make([]*core.InboundHandlerConfig, len(localAddrs)) for i := 0; i < len(localAddrs); i++ { inbounds[i] = &core.InboundHandlerConfig{ ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{ PortRange: net.SinglePortRange(lport), Listen: net.NewIPOrDomain(net.ParseAddress(localAddrs[i])), StreamSettings: &streamConfig, }), ProxySettings: serial.ToTypedMessage(&dokodemo.Config{ Address: net.NewIPOrDomain(proxyAddress), Networks: []net.Network{net.Network_TCP}, }), } } return &core.Config{ Inbound: inbounds, Outbound: []*core.OutboundHandlerConfig{{ ProxySettings: outboundProxy, }}, App: apps, }, nil } else { senderConfig := proxyman.SenderConfig{StreamSettings: &streamConfig} if connectionReuse { senderConfig.MultiplexSettings = &proxyman.MultiplexingConfig{Enabled: true, Concurrency: uint32(*mux)} } return &core.Config{ Inbound: []*core.InboundHandlerConfig{{ ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{ PortRange: net.SinglePortRange(lport), Listen: net.NewIPOrDomain(net.ParseAddress(*localAddr)), }), ProxySettings: serial.ToTypedMessage(&dokodemo.Config{ Address: net.NewIPOrDomain(net.LocalHostIP), Networks: []net.Network{net.Network_TCP}, }), }}, Outbound: []*core.OutboundHandlerConfig{{ SenderSettings: serial.ToTypedMessage(&senderConfig), ProxySettings: outboundProxy, }}, App: apps, }, nil } } func startV2Ray() (core.Server, error) { opts, err := parseEnv() if err == nil { if c, b := opts.Get("mode"); b { *mode = c } if c, b := opts.Get("mux"); b { if i, err := strconv.Atoi(c); err == nil { *mux = i } else { logWarn("failed to parse mux, use default value") } } if _, b := opts.Get("tls"); b { *tlsEnabled = true } if c, b := opts.Get("host"); b { *host = c } if c, b := opts.Get("path"); b { *path = c } if c, b := opts.Get("cert"); b { *cert = c } if c, b := opts.Get("certRaw"); b { *certRaw = c } if c, b := opts.Get("key"); b { *key = c } if c, b := opts.Get("loglevel"); b { *logLevel = c } if _, b := opts.Get("server"); b { *server = true } if c, b := opts.Get("localAddr"); b { if *server { *remoteAddr = c } else { *localAddr = c } } if c, b := opts.Get("localPort"); b { if *server { *remotePort = c } else { *localPort = c } } if c, b := opts.Get("remoteAddr"); b { if *server { *localAddr = c } else { *remoteAddr = c } } if c, b := opts.Get("remotePort"); b { if *server { *localPort = c } else { *remotePort = c } } if _, b := opts.Get("fastOpen"); b { *fastOpen = true } if _, b := opts.Get("vpn"); b { *vpn = true } if *vpn { registerControlFunc() } } config, err := generateConfig() if err != nil { return nil, newError("failed to parse config").Base(err) } instance, err := core.New(config) if err != nil { return nil, newError("failed to create v2ray instance").Base(err) } return instance, nil } func printCoreVersion() { version := core.VersionStatement() for _, s := range version { logInfo(s) } } func printVersion() { fmt.Println("v2ray-plugin", VERSION) fmt.Println("Go version", runtime.Version()) fmt.Println("Yet another SIP003 plugin for shadowsocks") } func main() { flag.Parse() if *version { printVersion() return } logInit() printCoreVersion() server, err := startV2Ray() if err != nil { logFatal(err.Error()) // Configuration error. Exit with a special value to prevent systemd from restarting. os.Exit(23) } if err := server.Start(); err != nil { logFatal("failed to start server:", err.Error()) os.Exit(1) } defer func() { err := server.Close() if err != nil { logWarn(err.Error()) } }() { osSignals := make(chan os.Signal, 1) signal.Notify(osSignals, os.Interrupt, os.Kill, syscall.SIGTERM) <-osSignals } } v2ray-plugin-1.3.1/utils.go000066400000000000000000000001011366464051400155430ustar00rootroot00000000000000// +build !android package main func registerControlFunc() { } v2ray-plugin-1.3.1/utils_android.go000066400000000000000000000045371366464051400172640ustar00rootroot00000000000000// +build android package main /* #include #include #include #include #include #include #include #include #define ANCIL_FD_BUFFER(n) \ struct { \ struct cmsghdr h; \ int fd[n]; \ } int ancil_send_fds_with_buffer(int sock, const int *fds, unsigned n_fds, void *buffer) { struct msghdr msghdr; char nothing = '!'; struct iovec nothing_ptr; struct cmsghdr *cmsg; int i; nothing_ptr.iov_base = ¬hing; nothing_ptr.iov_len = 1; msghdr.msg_name = NULL; msghdr.msg_namelen = 0; msghdr.msg_iov = ¬hing_ptr; msghdr.msg_iovlen = 1; msghdr.msg_flags = 0; msghdr.msg_control = buffer; msghdr.msg_controllen = sizeof(struct cmsghdr) + sizeof(int) * n_fds; cmsg = CMSG_FIRSTHDR(&msghdr); cmsg->cmsg_len = msghdr.msg_controllen; cmsg->cmsg_level = SOL_SOCKET; cmsg->cmsg_type = SCM_RIGHTS; for(i = 0; i < n_fds; i++) ((int *)CMSG_DATA(cmsg))[i] = fds[i]; return(sendmsg(sock, &msghdr, 0) >= 0 ? 0 : -1); } int ancil_send_fd(int sock, int fd) { ANCIL_FD_BUFFER(1) buffer; return(ancil_send_fds_with_buffer(sock, &fd, 1, &buffer)); } void set_timeout(int sock) { struct timeval tv; tv.tv_sec = 3; tv.tv_usec = 0; setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof(struct timeval)); setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, (char *)&tv, sizeof(struct timeval)); } */ import "C" import ( "log" "syscall" vinternet "v2ray.com/core/transport/internet" ) func ControlOnConnSetup(network string, address string, s uintptr) error { fd := int(s) path := "protect_path" socket, err := syscall.Socket(syscall.AF_UNIX, syscall.SOCK_STREAM, 0) if err != nil { log.Println(err) return err } defer syscall.Close(socket) C.set_timeout(C.int(socket)) err = syscall.Connect(socket, &syscall.SockaddrUnix{Name: path}) if err != nil { log.Println(err) return err } C.ancil_send_fd(C.int(socket), C.int(fd)) dummy := []byte{1} n, err := syscall.Read(socket, dummy) if err != nil { log.Println(err) return err } if n != 1 { log.Println("Failed to protect fd: ", fd) } return nil } func registerControlFunc() { vinternet.RegisterDialerController(ControlOnConnSetup) vinternet.RegisterListenerController(ControlOnConnSetup) }