68 Commits
v5.1 ... v5.4

Author SHA1 Message Date
arraykeys@gmail.com
a3eb0bfde9 Merge branch 'dev' 2018-08-30 16:10:28 +08:00
arraykeys@gmail.com
33e665631d v5.4 2018-08-30 16:09:58 +08:00
arraykeys@gmail.com
375eb9aa66 v5.4 2018-08-30 15:34:13 +08:00
arraykeys@gmail.com
889ce76676 优化sdk,支持并发启动/关闭操作 2018-08-24 11:41:15 +08:00
arraykeys@gmail.com
abdcae31c9 优化sdk,支持并发启动/关闭操作 2018-08-24 11:40:36 +08:00
arraykeys@gmail.com
c9f8f6c6fb fix GetAllInterfaceAddr cpu high 2018-08-21 10:52:18 +08:00
arraykeys@gmail.com
aab899397e fix GetAllInterfaceAddr cpu high 2018-08-21 10:29:51 +08:00
arraykeys@gmail.com
a933322ef7 Merge branch 'dev' 2018-08-06 16:07:24 +08:00
arraykeys@gmail.com
b9f054c495 v5.3 2018-08-06 16:06:43 +08:00
arraykeys@gmail.com
5c2e6fd109 a 2018-07-24 17:25:04 +08:00
arraykeys@gmail.com
e427263ccf a 2018-07-24 12:10:24 +08:00
arraykeys@gmail.com
a1a2c3f985 sdk5.3 2018-07-24 11:31:16 +08:00
arraykeys@gmail.com
84458a10e4 Merge remote-tracking branch 'origin/dev' into dev 2018-07-18 11:01:46 +08:00
snail007
9dd7bf80c5 Merge pull request #114 from schmich/fix-typo
Fix typo
2018-07-18 09:09:59 +08:00
Chris Schmich
317d0113fb Fix typo: 'stoped' -> 'stopped'. 2018-07-17 14:02:38 -07:00
arraykeys@gmail.com
53153da2e6 a 2018-07-17 17:55:54 +08:00
arraykeys@gmail.com
747a94a1c8 fix #113 2018-07-17 16:00:48 +08:00
arraykeys@gmail.com
df94ca5601 a 2018-07-16 18:32:53 +08:00
arraykeys@gmail.com
3cf7788f34 a 2018-07-16 18:10:21 +08:00
arraykeys@gmail.com
af91921070 a 2018-07-16 16:18:34 +08:00
arraykeys@gmail.com
7fc5c30f60 fix docker file 2018-07-16 15:54:55 +08:00
arraykeys@gmail.com
c4a7f0fbb0 Merge remote-tracking branch 'origin/dev' into dev 2018-07-12 13:34:18 +08:00
arraykeys@gmail.com
f656773858 优化智能检查的初始化时机 2018-07-12 13:32:46 +08:00
snail007
e208ccee18 Merge pull request #110 from boboanvip/dev
net.LookupIP may cause  deadlock in windows
2018-07-12 12:38:20 +08:00
boboan
5980fee788 net.LookupIP may cause deadlock in windows 2018-07-12 10:31:54 +08:00
boboanvip
61f791e77d Merge branch 'dev' into dev 2018-07-12 10:28:32 +08:00
boboan
907dec42e0 net.LookupIP may cause deadlock in windows
https://github.com/golang/go/issues/24178
2018-07-12 10:21:28 +08:00
arraykeys
8dce99fec6 a 2018-07-11 21:35:02 +08:00
snail007
db13b83f44 Merge pull request #109 from boboanvip/master
fix net.LookupIP may cause  deadlock in windows
2018-07-11 20:50:58 +08:00
boboan
dd8d7dd0d4 net.LookupIP may cause deadlock in windows
https://github.com/golang/go/issues/24178
2018-07-11 17:45:35 +08:00
arraykeys@gmail.com
dd355b5d98 fix socks client check port range 2018-07-10 16:26:26 +08:00
arraykeys@gmail.com
1e1999dede a 2018-07-10 13:37:00 +08:00
snail007
bb933cfb6e Merge pull request #108 from snail007/dev
docs
2018-07-09 20:33:31 +08:00
arraykeys
2603802dd9 no message 2018-07-09 20:18:30 +08:00
snail007
68ad904772 Merge pull request #106 from snail007/dev
docs
2018-07-09 17:27:49 +08:00
arraykeys@gmail.com
af19e5d25b docs 2018-07-09 17:25:58 +08:00
snail007
62907efe0c Merge pull request #105 from snail007/dev
v5.2
2018-07-09 17:24:16 +08:00
arraykeys@gmail.com
29e4cdf4e2 v5.2 2018-07-09 17:22:10 +08:00
arraykeys@gmail.com
3a4a9a3a27 a 2018-07-09 16:41:48 +08:00
arraykeys@gmail.com
04ef338807 add secure IP check for socks udp 2018-07-09 16:32:04 +08:00
arraykeys@gmail.com
3c070a7da3 Merge remote-tracking branch 'github_https/dev' into dev 2018-07-09 12:47:56 +08:00
snail007
c34f7db239 Merge pull request #104 from admpub/master
修复bridge服务bug
2018-07-09 00:21:36 +08:00
Wenhui Shen
1f655808c6 bugfixed 2018-07-08 19:52:46 +08:00
arraykeys
0226d2cde3 add sps : socks->udp support 2018-07-07 23:56:56 +08:00
arraykeys@gmail.com
61bb2d8ca0 Merge branch 'dev' of https://github.com/snail007/goproxy.git into dev 2018-07-06 18:24:55 +08:00
arraykeys@gmail.com
f5d09b878b fix socks udp reply wrong dst addr
Signed-off-by: arraykeys@gmail.com <arraykeys@gmail.com>
2018-07-06 18:24:12 +08:00
arraykeys
6b4ee97f05 no message 2018-07-05 20:18:12 +08:00
arraykeys@gmail.com
12dd591c58 add fully socks5 UDP support
Signed-off-by: arraykeys@gmail.com <arraykeys@gmail.com>
2018-07-05 15:56:26 +08:00
arraykeys
3b49f17e01 no message 2018-07-05 01:56:18 +08:00
arraykeys
cb8d0c0b42 no message 2018-07-05 01:03:37 +08:00
arraykeys
e92375f6a9 no message 2018-07-05 00:03:46 +08:00
arraykeys
c20e19d74f no message 2018-07-04 23:58:09 +08:00
arraykeys
50886bd69a no message 2018-07-04 21:51:59 +08:00
arraykeys
eaf836eff3 no message 2018-07-04 21:43:30 +08:00
arraykeys@gmail.com
bf72325fc0 Signed-off-by: arraykeys@gmail.com <arraykeys@gmail.com> 2018-07-04 17:44:24 +08:00
arraykeys
846956a9fe no message 2018-07-03 21:38:35 +08:00
arraykeys@gmail.com
20c31b0c68 Signed-off-by: arraykeys@gmail.com <arraykeys@gmail.com> 2018-07-03 17:37:17 +08:00
arraykeys@gmail.com
d84a4bec86 Signed-off-by: arraykeys@gmail.com <arraykeys@gmail.com> 2018-07-03 17:35:05 +08:00
arraykeys@gmail.com
05d2f16777 Signed-off-by: arraykeys@gmail.com <arraykeys@gmail.com> 2018-06-29 19:21:04 +08:00
arraykeys@gmail.com
9fa1c4932b Signed-off-by: arraykeys@gmail.com <arraykeys@gmail.com> 2018-06-29 18:55:18 +08:00
arraykeys@gmail.com
0932aecff3 Signed-off-by: arraykeys@gmail.com <arraykeys@gmail.com> 2018-06-29 18:54:24 +08:00
arraykeys@gmail.com
a9f8acd98d Merge branch 'dev' of https://github.com/snail007/goproxy.git into dev 2018-06-29 17:56:04 +08:00
arraykeys@gmail.com
2336e77ac4 Signed-off-by: arraykeys@gmail.com <arraykeys@gmail.com> 2018-06-29 17:55:19 +08:00
snail007
1ef8d7c82a Merge pull request #101 from snail007/dev
update docs
2018-06-29 09:13:28 +08:00
snail007
24d54725df Merge pull request #100 from yincongcyincong/dev
Update README.md
2018-06-29 09:12:23 +08:00
arraykeys
9b430b5ba4 fix create root certificate 2018-06-28 23:05:48 +08:00
yincongcyincong
0ee7abbd6a Update README.md 2018-06-28 18:07:48 +08:00
arraykeys@gmail.com
361215fb6f Signed-off-by: arraykeys@gmail.com <arraykeys@gmail.com> 2018-06-28 17:28:42 +08:00
40 changed files with 1482 additions and 594 deletions

View File

@ -1,4 +1,20 @@
proxy更新日志 proxy更新日志
v5.4
1.优化了获取本地IP信息导致CPU过高的问题.
2.所有服务都增加了--nolog参数,可以关闭日志输出,节省CPU.
3.优化sdk,支持并发启动/关闭操作.
4.修复了多连接版本的内网穿透,tserver连接不能正确释放的bug.
5.内网穿透增加了client/tclient和server/tserver使用代理连接bridge/tbridge的功能,详细内容参考手册.
6.TCP端口映射(TCP代理)增加了使用代理连接上级的功能,详细内容参考手册.
v5.3
1.优化了socks_client握手端口判断,避免了sstap测试UDP失败的问题.
v5.2
1.修复了HTTP(S)\SPS反向代理无法正常工作的问题.
2.优化了智能判断,减少不必要的DNS解析.
3.重构了SOCKS和SPS的UDP功能,基于UDP的游戏加速嗖嗖的.
v5.1 v5.1
1.优化了kcp默认mtu配置,调整为450. 1.优化了kcp默认mtu配置,调整为450.
2.优化了HTTP(S)\SOCKS5代理智能判断更加精确。 2.优化了HTTP(S)\SOCKS5代理智能判断更加精确。

View File

@ -1,9 +1,82 @@
FROM golang:1.10.3-alpine as builder FROM alpine:3.7 AS builder
RUN apk add --no-cache \
ca-certificates
# set up nsswitch.conf for Go's "netgo" implementation
# - https://github.com/golang/go/blob/go1.9.1/src/net/conf.go#L194-L275
# - docker run --rm debian:stretch grep '^hosts:' /etc/nsswitch.conf
RUN [ ! -e /etc/nsswitch.conf ] && echo 'hosts: files dns' > /etc/nsswitch.conf
ENV GOLANG_VERSION 1.10.3
# make-sure-R0-is-zero-before-main-on-ppc64le.patch: https://github.com/golang/go/commit/9aea0e89b6df032c29d0add8d69ba2c95f1106d9 (Go 1.9)
#COPY *.patch /go-alpine-patches/
RUN set -eux; \
apk add --no-cache --virtual .build-deps \
bash \
gcc \
musl-dev \
openssl \
go \
; \
export \
# set GOROOT_BOOTSTRAP such that we can actually build Go
GOROOT_BOOTSTRAP="$(go env GOROOT)" \
# ... and set "cross-building" related vars to the installed system's values so that we create a build targeting the proper arch
# (for example, if our build host is GOARCH=amd64, but our build env/image is GOARCH=386, our build needs GOARCH=386)
GOOS="$(go env GOOS)" \
GOARCH="$(go env GOARCH)" \
GOHOSTOS="$(go env GOHOSTOS)" \
GOHOSTARCH="$(go env GOHOSTARCH)" \
; \
# also explicitly set GO386 and GOARM if appropriate
# https://github.com/docker-library/golang/issues/184
apkArch="$(apk --print-arch)"; \
case "$apkArch" in \
armhf) export GOARM='6' ;; \
x86) export GO386='387' ;; \
esac; \
\
wget -O go.tgz "https://golang.org/dl/go$GOLANG_VERSION.src.tar.gz"; \
echo '567b1cc66c9704d1c019c50bef946272e911ec6baf244310f87f4e678be155f2 *go.tgz' | sha256sum -c -; \
tar -C /usr/local -xzf go.tgz; \
rm go.tgz; \
\
cd /usr/local/go/src; \
for p in /go-alpine-patches/*.patch; do \
[ -f "$p" ] || continue; \
patch -p2 -i "$p"; \
done; \
./make.bash; \
\
rm -rf /go-alpine-patches; \
apk del .build-deps; \
\
export PATH="/usr/local/go/bin:$PATH"; \
go version
ENV GOPATH /go
ENV PATH $GOPATH/bin:/usr/local/go/bin:$PATH
RUN mkdir -p "$GOPATH/src" "$GOPATH/bin" && chmod -R 777 "$GOPATH"
WORKDIR $GOPATH
ARG GOPROXY_VERSION=master ARG GOPROXY_VERSION=master
RUN apk update && apk upgrade && \ RUN apk update; apk upgrade; \
apk add --no-cache git && cd /go/src/ && git clone https://github.com/snail007/goproxy && \ apk add --no-cache git; \
cd goproxy && git checkout ${GOPROXY_VERSION} && \ cd /go/src/; \
go get && CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o proxy mkdir github.com; \
FROM alpine:3.7 mkdir github.com/snail007; \
COPY --from=builder /go/src/goproxy/proxy / cd github.com/snail007; \
CMD /proxy ${OPTS} git clone https://github.com/snail007/goproxy.git; \
cd goproxy; \
git checkout ${GOPROXY_VERSION}; \
CGO_ENABLED=0 GOOS=linux go build -ldflags "-s -w" -a -installsuffix cgo -o proxy; \
chmod 0777 proxy
FROM 1.10.3-stretch
RUN mkdir /proxy && chmod 0777 /proxy
COPY --from=builder builder /go/src/github.com/snail007/goproxy/proxy /proxy/
CMD cd /proxy && /proxy ${OPTS}

View File

@ -6,7 +6,18 @@ Proxy is a high performance HTTP, HTTPS, HTTPS, websocket, TCP, UDP, Socks5 prox
[![stable](https://img.shields.io/badge/stable-stable-green.svg)](https://github.com/snail007/goproxy/) [![license](https://img.shields.io/github/license/snail007/goproxy.svg?style=plastic)]() [![download_count](https://img.shields.io/github/downloads/snail007/goproxy/total.svg?style=plastic)](https://github.com/snail007/goproxy/releases) [![download](https://img.shields.io/github/release/snail007/goproxy.svg?style=plastic)](https://github.com/snail007/goproxy/releases) [![stable](https://img.shields.io/badge/stable-stable-green.svg)](https://github.com/snail007/goproxy/) [![license](https://img.shields.io/github/license/snail007/goproxy.svg?style=plastic)]() [![download_count](https://img.shields.io/github/downloads/snail007/goproxy/total.svg?style=plastic)](https://github.com/snail007/goproxy/releases) [![download](https://img.shields.io/github/release/snail007/goproxy.svg?style=plastic)](https://github.com/snail007/goproxy/releases)
[中文手册](/README_ZH.md) **[全平台GUI版本](/gui/README.md)** **[全平台SDK](/sdk/README.md)** **[中文手册](/README_ZH.md)**
**[全平台图形界面版本](/gui/README.md)**
**[全平台SDK](/sdk/README.md)**
### How to contribute to the code (Pull Request)?
Pull Request is welcomed.
First, you need to clone the project to your account, and then modify the code on the dev branch.
Finally, Pull Request to dev branch of goproxy project, and contribute code for efficiency.
PR needs to explain what changes have been made and why you change them.
### Features ### Features
- chain-style proxy: the program itself can be a primary proxy, and if a parent proxy is set, it can be used as a second level proxy or even a N level proxy. - chain-style proxy: the program itself can be a primary proxy, and if a parent proxy is set, it can be used as a second level proxy or even a N level proxy.
@ -37,26 +48,7 @@ Proxy is a high performance HTTP, HTTPS, HTTPS, websocket, TCP, UDP, Socks5 prox
- ...   - ...  
This page is the v5.0 manual, and the other version of the manual can be checked by the following link. This page is the v5.3 manual, and the other version of the manual can be checked by the following [link](docs/old-release.md).
- [v4.9 manual](https://github.com/snail007/goproxy/tree/v4.9)
- [v4.8 manual](https://github.com/snail007/goproxy/tree/v4.8)
- [v4.7 manual](https://github.com/snail007/goproxy/tree/v4.7)
- [v4.6 manual](https://github.com/snail007/goproxy/tree/v4.6)
- [v4.5 manual](https://github.com/snail007/goproxy/tree/v4.5)
- [v4.4 manual](https://github.com/snail007/goproxy/tree/v4.4)
- [v4.3 manual](https://github.com/snail007/goproxy/tree/v4.3)
- [v4.2 manual](https://github.com/snail007/goproxy/tree/v4.2)
- [v4.0-4.1 manual](https://github.com/snail007/goproxy/tree/v4.1)
- [v3.9 manual](https://github.com/snail007/goproxy/tree/v3.9)
- [v3.8 manual](https://github.com/snail007/goproxy/tree/v3.8)
- [v3.6-v3.7 manual](https://github.com/snail007/goproxy/tree/v3.6)
- [v3.5 manual](https://github.com/snail007/goproxy/tree/v3.5)
- [v3.4 manual](https://github.com/snail007/goproxy/tree/v3.4)
- [v3.3 manual](https://github.com/snail007/goproxy/tree/v3.3)
- [v3.2 manual](https://github.com/snail007/goproxy/tree/v3.2)
- [v3.1 manual](https://github.com/snail007/goproxy/tree/v3.1)
- [v3.0 manual](https://github.com/snail007/goproxy/tree/v3.0)
- [v2.x manual](https://github.com/snail007/goproxy/tree/v2.2)
### How to find the organization? ### How to find the organization?
[Click to join the proxy group of gitter](https://gitter.im/go-proxy/Lobby?utm_source=share-link&utm_medium=link&utm_campaign=share-link)   [Click to join the proxy group of gitter](https://gitter.im/go-proxy/Lobby?utm_source=share-link&utm_medium=link&utm_campaign=share-link)  
@ -169,7 +161,7 @@ If the installation fails or your VPS is not a linux64 system, please follow the
Download address: https://github.com/snail007/goproxy/releases Download address: https://github.com/snail007/goproxy/releases
```shell ```shell
cd /root/proxy/ cd /root/proxy/
wget https://github.com/snail007/goproxy/releases/download/v5.0/proxy-linux-amd64.tar.gz wget https://github.com/snail007/goproxy/releases/download/v5.3/proxy-linux-amd64.tar.gz
``` ```
#### **2.Download the automatic installation script** #### **2.Download the automatic installation script**
```shell ```shell
@ -181,12 +173,12 @@ chmod +x install.sh
#### Docker installation #### Docker installation
Dockerfile root of project uses multistage build and alpine project to comply with best practices. Uses golang 1.10.3 for building as noted in the project README.md and will be pretty small image. total extracted size will be 17.3MB for goproxy version 5.0. Dockerfile root of project uses multistage build and alpine project to comply with best practices. Uses golang 1.10.3 for building as noted in the project README.md and will be pretty small image. total extracted size will be 17.3MB for goproxy latest version.
The default build process builds the master branch (latest commits/ cutting edge), and it can be configured to build specific version, just edit Dockerfile before build, following builds release version 4.7: The default build process builds the master branch (latest commits/ cutting edge), and it can be configured to build specific version, just edit Dockerfile before build, following builds release version 5.3:
``` ```
ARG GOPROXY_VERSION=v5.0 ARG GOPROXY_VERSION=v5.3
``` ```
To Run: To Run:
@ -196,12 +188,12 @@ sudo docker build .
``` ```
2. Tag the image: 2. Tag the image:
``` ```
sudo docker tag <id from previous step> goproxy/goproxy:latest sudo docker tag <id from previous step> snail007/goproxy:latest
``` ```
3. Run! 3. Run!
Just put your arguments to proxy binary in the OPTS environmental variable (this is just a sample http proxy): Just put your arguments to proxy binary in the OPTS environmental variable (this is just a sample http proxy):
``` ```
sudo docker run -d --restart=always --name goproxy -e OPTS="http -p :33080" -p 33080:33080 goproxy/goproxy:latest sudo docker run -d --restart=always --name goproxy -e OPTS="http -p :33080" -p 33080:33080 snail007/goproxy:latest
``` ```
4. View logs: 4. View logs:
``` ```
@ -235,9 +227,18 @@ for example, --log proxy.log, The log will be exported to proxy.log file which i
### **Generating a communication certificate file** ### **Generating a communication certificate file**
HTTP, TCP, UDP proxy process will communicate with parent proxy. In order to secure, we use encrypted communication. Of course, we can choose not to encrypted communication. All communication with parent proxy in this tutorial is encrypted, requiring certificate files. HTTP, TCP, UDP proxy process will communicate with parent proxy. In order to secure, we use encrypted communication. Of course, we can choose not to encrypted communication. All communication with parent proxy in this tutorial is encrypted, requiring certificate files.
The OpenSSL command is installed on the Linux and encrypted certificate can be generated directly through the following command.
`./proxy keygen` 1.Generate signed certificates and key files through the following commands.
By default, the certificate file proxy.crt and the key file proxy.key are generated under the current program directory. `./proxy keygen -C proxy`
The certificate file proxy.crt and key file proxy.key will be generated under the current directory.
2.Through the following commands, use the signed certificate proxy.crt and key file proxy.key to issue new certificates: goproxy.crt and goproxy.key.
`./proxy keygen -s -C proxy -c goproxy`
The certificate file goproxy.crt and key file goproxy.key will be generated under the current program directory.
3.By default, the domain name in the certificate is a random domain and can be specified using the `-n test.com` parameter.
4.More usage:`proxy keygen --help`
### **Daemon mode** ### **Daemon mode**
After the default execution of proxy, if you want to keep proxy running, you can't close the command line. After the default execution of proxy, if you want to keep proxy running, you can't close the command line.
@ -831,7 +832,7 @@ through this way, When you visits the website by local proxy 8080, it visits the
### **6.Proxy protocol conversion** ### **6.Proxy protocol conversion**
#### **6.1.Functional introduction** #### **6.1.Functional introduction**
The proxy protocol conversion use the SPS subcommand (abbreviation of socks+https), SPS itself does not provide the proxy function, just accept the proxy request and then converse protocol and forwarded to the existing HTTP (s) or Socks5 proxy. SPS can use existing HTTP (s) or Socks5 proxy converse to support HTTP (s) and Socks5 HTTP (s) proxy at the same time by one port, and proxy supports forward and reverse proxy (SNI), SOCKS5 proxy which is conversed does not support UDP. in addition to the existing HTTP or Socks5 proxy, which supports TLS, TCP, KCP three modes and chain-style connection. That is more than one SPS node connection can build encryption channel. The proxy protocol conversion use the SPS subcommand (abbreviation of socks+https), SPS itself does not provide the proxy function, just accept the proxy request and then converse protocol and forwarded to the existing HTTP (s) or Socks5 proxy. SPS can use existing HTTP (s) or Socks5 proxy converse to support HTTP (s) and Socks5 HTTP (s) proxy at the same time by one port, and proxy supports forward and reverse proxy (SNI), SOCKS5 proxy which is also does support UDP when parent is Socks5. in addition to the existing HTTP or Socks5 proxy, which supports TLS, TCP, KCP three modes and chain-style connection. That is more than one SPS node connection can build encryption channel.
#### **6.2.HTTP(S) to HTTP(S) + SOCKS5** #### **6.2.HTTP(S) to HTTP(S) + SOCKS5**
Suppose there is a common HTTP (s) proxy: 127.0.0.1:8080. Now we turn it into a common proxy that supports HTTP (s) and Socks5 at the same time. The local port after transformation is 18080. Suppose there is a common HTTP (s) proxy: 127.0.0.1:8080. Now we turn it into a common proxy that supports HTTP (s) and Socks5 at the same time. The local port after transformation is 18080.
@ -1073,12 +1074,8 @@ Then the local UDP port 53 provides a security and anti pollution DNS analysis.
- HTTP (s) proxy support PAC? - HTTP (s) proxy support PAC?
- Welcome joining group feedback... - Welcome joining group feedback...
### How to contribute to the code (Pull Request)?
First, you need to clone the project to your account, and then modify the code on the dev branch.
Finally, Pull Request to dev branch of goproxy project, and contribute code for efficiency.
PR needs to explain what changes have been made and why you change them.
### How to use the source code? ### How to use the source code?
Recommend go1.10.1. Recommend go1.10.1.
`go get github.com/snail007/goproxy` `go get github.com/snail007/goproxy`
use command cd to enter your go SRC directory use command cd to enter your go SRC directory

View File

@ -7,7 +7,17 @@ Proxy是golang实现的高性能http,https,websocket,tcp,udp,socks5代理服务
[![stable](https://img.shields.io/badge/stable-stable-green.svg)](https://github.com/snail007/goproxy/) [![license](https://img.shields.io/github/license/snail007/goproxy.svg?style=plastic)]() [![download_count](https://img.shields.io/github/downloads/snail007/goproxy/total.svg?style=plastic)](https://github.com/snail007/goproxy/releases) [![download](https://img.shields.io/github/release/snail007/goproxy.svg?style=plastic)](https://github.com/snail007/goproxy/releases) [![stable](https://img.shields.io/badge/stable-stable-green.svg)](https://github.com/snail007/goproxy/) [![license](https://img.shields.io/github/license/snail007/goproxy.svg?style=plastic)]() [![download_count](https://img.shields.io/github/downloads/snail007/goproxy/total.svg?style=plastic)](https://github.com/snail007/goproxy/releases) [![download](https://img.shields.io/github/release/snail007/goproxy.svg?style=plastic)](https://github.com/snail007/goproxy/releases)
**[English Manual](/README.md)** **[全平台GUI版本](/gui/README.md)** **[全平台SDK](/sdk/README.md)** **[English Manual](/README.md)**
**[全平台图形界面版本](/gui/README.md)**
**[全平台SDK](/sdk/README.md)**
### 如何贡献代码(Pull Request)?
欢迎加入一起发展壮大proxy.首先需要clone本项目到自己的帐号下面,
然后在dev分支上面修改代码,最后发Pull Request到goproxy项目的dev分支即可,
为了高效贡献代码,pr的时候需要说明做了什么变更,原因是什么.
### Features ### Features
- 链式代理,程序本身可以作为一级代理,如果设置了上级代理那么可以作为二级代理,乃至N级代理. - 链式代理,程序本身可以作为一级代理,如果设置了上级代理那么可以作为二级代理,乃至N级代理.
@ -38,7 +48,7 @@ Proxy是golang实现的高性能http,https,websocket,tcp,udp,socks5代理服务
- ... - ...
本页是v5.1手册,其他版本手册请点击[这里](docs/old-release.md)查看. 本页是v5.4手册,其他版本手册请点击[这里](docs/old-release.md)查看.
### 怎么找到组织? ### 怎么找到组织?
@ -77,14 +87,15 @@ Proxy是golang实现的高性能http,https,websocket,tcp,udp,socks5代理服务
- [1.12 自定义加密](#112-自定义加密) - [1.12 自定义加密](#112-自定义加密)
- [1.13 压缩传输](#113-压缩传输) - [1.13 压缩传输](#113-压缩传输)
- [1.14 查看帮助](#114-查看帮助) - [1.14 查看帮助](#114-查看帮助)
- [2. TCP代理](#2tcp代理) - [2. TCP代理(端口映射)](#2tcp代理)
- [2.1 普通一级TCP代理](#21普通一级tcp代理) - [2.1 普通一级TCP代理](#21普通一级tcp代理)
- [2.2 普通二级TCP代理](#22普通二级tcp代理) - [2.2 普通二级TCP代理](#22普通二级tcp代理)
- [2.3 普通三级TCP代理](#23普通三级tcp代理) - [2.3 普通三级TCP代理](#23普通三级tcp代理)
- [2.4 加密二级TCP代理](#24加密二级tcp代理) - [2.4 加密二级TCP代理](#24加密二级tcp代理)
- [2.5 加密三级TCP代理](#25加密三级tcp代理) - [2.5 加密三级TCP代理](#25加密三级tcp代理)
- [2.6 查看帮助](#26查看帮助) - [2.6 通过代理连接上级](#26通过代理连接上级)
- [3. UDP代理](#3udp代理) - [2.7 查看帮助](#27查看帮助)
- [3. UDP代理(端口映射)](#3udp代理)
- [3.1 普通一级UDP代理](#31普通一级udp代理) - [3.1 普通一级UDP代理](#31普通一级udp代理)
- [3.2 普通二级UDP代理](#32普通二级udp代理) - [3.2 普通二级UDP代理](#32普通二级udp代理)
- [3.3 普通三级UDP代理](#33普通三级udp代理) - [3.3 普通三级UDP代理](#33普通三级udp代理)
@ -99,7 +110,8 @@ Proxy是golang实现的高性能http,https,websocket,tcp,udp,socks5代理服务
- [4.5 高级用法一](#45高级用法一) - [4.5 高级用法一](#45高级用法一)
- [4.6 高级用法一](#46高级用法二) - [4.6 高级用法一](#46高级用法二)
- [4.7 server的-r参数](#47server的-r参数) - [4.7 server的-r参数](#47server的-r参数)
- [4.8 查看帮助](#48查看帮助) - [4.8 server和client通过代理连接bridge](#48server和client通过代理连接bridge)
- [4.9 查看帮助](#49查看帮助)
- [5. SOCKS5代理](#5socks5代理) - [5. SOCKS5代理](#5socks5代理)
- [5.1 普通SOCKS5代理](#51普通socks5代理) - [5.1 普通SOCKS5代理](#51普通socks5代理)
- [5.2 普通二级SOCKS5代理](#52普通二级socks5代理) - [5.2 普通二级SOCKS5代理](#52普通二级socks5代理)
@ -149,7 +161,7 @@ curl -L https://raw.githubusercontent.com/snail007/goproxy/master/install_auto.s
下载地址:https://github.com/snail007/goproxy/releases 下载地址:https://github.com/snail007/goproxy/releases
```shell ```shell
cd /root/proxy/ cd /root/proxy/
wget https://github.com/snail007/goproxy/releases/download/v5.1/proxy-linux-amd64.tar.gz wget https://github.com/snail007/goproxy/releases/download/v5.4/proxy-linux-amd64.tar.gz
``` ```
#### **2.下载自动安装脚本** #### **2.下载自动安装脚本**
```shell ```shell
@ -160,12 +172,12 @@ chmod +x install.sh
``` ```
#### Docker安装 #### Docker安装
项目根目录的Dockerfile文件用来构建,使用golang 1.10.3,构建基于goproxy v5.1, 项目根目录的Dockerfile文件用来构建,使用golang 1.10.3,构建基于goproxy的master分支最新版本,
全部大小17.3MB,默认情况下使用master分支,不过可以通过修改配置文件Dockerfile 全部大小17.3MB,默认情况下使用master分支,不过可以通过修改配置文件Dockerfile
或者使用参数GOPROXY_VERSION指定构建的goproxy版本. 或者使用参数GOPROXY_VERSION指定构建的goproxy版本.
``` ```
ARG GOPROXY_VERSION=v5.1 ARG GOPROXY_VERSION=v5.3
``` ```
步骤: 步骤:
@ -175,14 +187,14 @@ sudo docker build .
``` ```
2. 镜像打标签: 2. 镜像打标签:
``` ```
sudo docker tag <上一步的结果ID> goproxy/goproxy:latest sudo docker tag <上一步的结果ID> snail007/goproxy:latest
``` ```
3. 运行 3. 运行
参数OPTS的值就是传递给proxy的所有参数 参数OPTS的值就是传递给proxy的所有参数
比如下面的例子启动了一个http服务: 比如下面的例子启动了一个http服务:
``` ```
sudo docker run -d --restart=always --name goproxy -e OPTS="http -p :33080" -p 33080:33080 goproxy/goproxy:latest sudo docker run -d --restart=always --name goproxy -e OPTS="http -p :33080" -p 33080:33080 snail007/goproxy:latest
``` ```
4. 查看日志: 4. 查看日志:
``` ```
@ -496,7 +508,27 @@ VPS(IP:22.22.22.33)执行:
`./proxy tcp -p ":8080" -T tls -P "33.33.33.33:28080" -C proxy.crt -K proxy.key` `./proxy tcp -p ":8080" -T tls -P "33.33.33.33:28080" -C proxy.crt -K proxy.key`
那么访问本地8080端口就是通过加密TCP隧道访问66.66.66.66的8080端口. 那么访问本地8080端口就是通过加密TCP隧道访问66.66.66.66的8080端口.
#### **2.6.查看帮助** #### **2.6.通过代理连接上级**
有时候proxy所在的网络不能直接访问外网,需要通过一个https或者socks5代理才能上网,那么这个时候
-J参数就可以帮助你让proxy的tcp端口映射的时候通过https或者socks5代理去连接上级-P,将外部端口映射到本地.
-J参数格式如下:
https代理写法:
代理需要认证,用户名:username 密码:password
https://username:password@host:port
代理不需要认证
https://host:port
socks5代理写法:
代理需要认证,用户名:username 密码:password
socks5://username:password@host:port
代理不需要认证
socks5://host:port
host:代理的IP或者域名
port:代理的端口
#### **2.7.查看帮助**
`./proxy help tcp` `./proxy help tcp`
### **3.UDP代理** ### **3.UDP代理**
@ -683,13 +715,40 @@ server连接到bridge的时候,如果同时有多个client连接到同一个brid
4.7.3.LOCAL_IP为空默认是:`0.0.0.0`,CLIENT_LOCAL_HOST为空默认是:`127.0.0.1`; 4.7.3.LOCAL_IP为空默认是:`0.0.0.0`,CLIENT_LOCAL_HOST为空默认是:`127.0.0.1`;
#### **4.8.查看帮助** #### **4.8.server和client通过代理连接bridge**
有时候server或者client所在的网络不能直接访问外网,需要通过一个https或者socks5代理才能上网,那么这个时候
-J参数就可以帮助你让server或者client通过https或者socks5代理去连接bridge.
-J参数格式如下:
https代理写法:
代理需要认证,用户名:username 密码:password
https://username:password@host:port
代理不需要认证
https://host:port
socks5代理写法:
代理需要认证,用户名:username 密码:password
socks5://username:password@host:port
代理不需要认证
socks5://host:port
host:代理的IP或者域名
port:代理的端口
#### **4.9.查看帮助**
`./proxy help bridge` `./proxy help bridge`
`./proxy help server` `./proxy help server`
`./proxy help client` `./proxy help client`
### **5.SOCKS5代理** ### **5.SOCKS5代理**
提示:SOCKS5代理,支持CONNECT,UDP协议,不支持BIND,支持用户名密码认证. 提示:
SOCKS5代理,支持CONNECT,UDP协议,不支持BIND,支持用户名密码认证.
***如果你的VPS是阿里云腾讯云这种VPS就是ifconfig看不见你的公网IP只能看见内网IP***
***那么需要加上`-g VPS公网IP`参数SOCKS5代理的UDP功能才能正常工作。***
#### **5.1.普通SOCKS5代理** #### **5.1.普通SOCKS5代理**
`./proxy socks -t tcp -p "0.0.0.0:38080"` `./proxy socks -t tcp -p "0.0.0.0:38080"`
@ -837,7 +896,7 @@ proxy的socks代理在tcp之上可以通过自定义加密和tls标准加密以
### **6.代理协议转换** ### **6.代理协议转换**
#### **6.1 功能介绍** #### **6.1 功能介绍**
代理协议转换使用的是sps子命令(socks+https的缩写)sps本身不提供代理功能只是接受代理请求"转换并转发"给已经存在的http(s)代理或者socks5代理sps可以把已经存在的http(s)代理或者socks5代理转换为一个端口同时支持http(s)和socks5代理而且http(s)代理支持正向代理和反向代理(SNI)转换后的SOCKS5代理支持UDP功能另外对于已经存在的http(s)代理或者socks5代理支持tls、tcp、kcp三种模式支持链式连接也就是可以多个sps结点层级连接构建加密通道。 代理协议转换使用的是sps子命令(socks+https的缩写)sps本身不提供代理功能只是接受代理请求"转换并转发"给已经存在的http(s)代理或者socks5代理sps可以把已经存在的http(s)代理或者socks5代理转换为一个端口同时支持http(s)和socks5代理而且http(s)代理支持正向代理和反向代理(SNI)转换后的SOCKS5代理当上级是SOCKS5时仍然支持UDP功能另外对于已经存在的http(s)代理或者socks5代理支持tls、tcp、kcp三种模式支持链式连接也就是可以多个sps结点层级连接构建加密通道。
#### **6.2 HTTP(S)转HTTP(S)+SOCKS5** #### **6.2 HTTP(S)转HTTP(S)+SOCKS5**
假设已经存在一个普通的http(s)代理127.0.0.1:8080,现在我们把它转为同时支持http(s)和socks5的普通代理,转换后的本地端口为18080。 假设已经存在一个普通的http(s)代理127.0.0.1:8080,现在我们把它转为同时支持http(s)和socks5的普通代理,转换后的本地端口为18080。
@ -1109,11 +1168,6 @@ fast3`--nodelay=1 --interval=10 --resend=2 --nc=1`
- http(s)代理增加pac支持? - http(s)代理增加pac支持?
- 欢迎加群反馈... - 欢迎加群反馈...
### 如何贡献代码(Pull Request)?
首先需要clone本项目到自己的帐号下面,然后在dev分支上面修改代码,
最后发Pull Request到goproxy项目的dev分支即可,为了高效贡献代码,
pr的时候需要说明做了什么变更,原因是什么.
### 如何使用源码? ### 如何使用源码?
建议go1.10.1. 建议go1.10.1.
`go get github.com/snail007/goproxy` `go get github.com/snail007/goproxy`
@ -1133,5 +1187,3 @@ QQ交流群:189618940
如果proxy帮助你解决了很多问题,你可以通过下面的捐赠更好的支持proxy. 如果proxy帮助你解决了很多问题,你可以通过下面的捐赠更好的支持proxy.
<img src="https://github.com/snail007/goproxy/blob/master/docs/images/alipay.jpg?raw=true" width="200"/> <img src="https://github.com/snail007/goproxy/blob/master/docs/images/alipay.jpg?raw=true" width="200"/>
<img src="https://github.com/snail007/goproxy/blob/master/docs/images/wxpay.jpg?raw=true" width="200"/> <img src="https://github.com/snail007/goproxy/blob/master/docs/images/wxpay.jpg?raw=true" width="200"/>

View File

@ -4,6 +4,7 @@ import (
"bufio" "bufio"
"crypto/sha1" "crypto/sha1"
"fmt" "fmt"
"io/ioutil"
logger "log" logger "log"
"os" "os"
"os/exec" "os/exec"
@ -62,6 +63,7 @@ func initConfig() (err error) {
daemon := app.Flag("daemon", "run proxy in background").Default("false").Bool() daemon := app.Flag("daemon", "run proxy in background").Default("false").Bool()
forever := app.Flag("forever", "run proxy in forever,fail and retry").Default("false").Bool() forever := app.Flag("forever", "run proxy in forever,fail and retry").Default("false").Bool()
logfile := app.Flag("log", "log file path").Default("").String() logfile := app.Flag("log", "log file path").Default("").String()
nolog := app.Flag("nolog", "turn off logging").Default("false").Bool()
kcpArgs.Key = app.Flag("kcp-key", "pre-shared secret between client and server").Default("secrect").String() kcpArgs.Key = app.Flag("kcp-key", "pre-shared secret between client and server").Default("secrect").String()
kcpArgs.Crypt = app.Flag("kcp-method", "encrypt/decrypt method, can be: aes, aes-128, aes-192, salsa20, blowfish, twofish, cast5, 3des, tea, xtea, xor, sm4, none").Default("aes").Enum("aes", "aes-128", "aes-192", "salsa20", "blowfish", "twofish", "cast5", "3des", "tea", "xtea", "xor", "sm4", "none") kcpArgs.Crypt = app.Flag("kcp-method", "encrypt/decrypt method, can be: aes, aes-128, aes-192, salsa20, blowfish, twofish, cast5, 3des, tea, xtea, xor, sm4, none").Default("aes").Enum("aes", "aes-128", "aes-192", "salsa20", "blowfish", "twofish", "cast5", "3des", "tea", "xtea", "xor", "sm4", "none")
kcpArgs.Mode = app.Flag("kcp-mode", "profiles: fast3, fast2, fast, normal, manual").Default("fast").Enum("fast3", "fast2", "fast", "normal", "manual") kcpArgs.Mode = app.Flag("kcp-mode", "profiles: fast3, fast2, fast, normal, manual").Default("fast").Enum("fast3", "fast2", "fast", "normal", "manual")
@ -122,8 +124,8 @@ func initConfig() (err error) {
tcpArgs.Timeout = tcp.Flag("timeout", "tcp timeout milliseconds when connect to real server or parent proxy").Short('e').Default("2000").Int() tcpArgs.Timeout = tcp.Flag("timeout", "tcp timeout milliseconds when connect to real server or parent proxy").Short('e').Default("2000").Int()
tcpArgs.ParentType = tcp.Flag("parent-type", "parent protocol type <tls|tcp|kcp|udp>").Short('T').Enum("tls", "tcp", "udp", "kcp") tcpArgs.ParentType = tcp.Flag("parent-type", "parent protocol type <tls|tcp|kcp|udp>").Short('T').Enum("tls", "tcp", "udp", "kcp")
tcpArgs.LocalType = tcp.Flag("local-type", "local protocol type <tls|tcp|kcp>").Default("tcp").Short('t').Enum("tls", "tcp", "kcp") tcpArgs.LocalType = tcp.Flag("local-type", "local protocol type <tls|tcp|kcp>").Default("tcp").Short('t').Enum("tls", "tcp", "kcp")
tcpArgs.CheckParentInterval = tcp.Flag("check-parent-interval", "check if proxy is okay every interval seconds,zero: means no check").Short('I').Default("3").Int()
tcpArgs.Local = tcp.Flag("local", "local ip:port to listen").Short('p').Default(":33080").String() tcpArgs.Local = tcp.Flag("local", "local ip:port to listen").Short('p').Default(":33080").String()
tcpArgs.Jumper = tcp.Flag("jumper", "https or socks5 proxies used when connecting to parent, only worked of -T is tls or tcp, format is https://username:password@host:port https://host:port or socks5://username:password@host:port socks5://host:port").Short('J').Default("").String()
//########udp######### //########udp#########
udp := app.Command("udp", "proxy on udp mode") udp := app.Command("udp", "proxy on udp mode")
@ -147,6 +149,7 @@ func initConfig() (err error) {
muxServerArgs.Route = muxServer.Flag("route", "local route to client's network, such as: PROTOCOL://LOCAL_IP:LOCAL_PORT@[CLIENT_KEY]CLIENT_LOCAL_HOST:CLIENT_LOCAL_PORT").Short('r').Default("").Strings() muxServerArgs.Route = muxServer.Flag("route", "local route to client's network, such as: PROTOCOL://LOCAL_IP:LOCAL_PORT@[CLIENT_KEY]CLIENT_LOCAL_HOST:CLIENT_LOCAL_PORT").Short('r').Default("").Strings()
muxServerArgs.IsCompress = muxServer.Flag("c", "compress data when tcp|tls mode").Default("false").Bool() muxServerArgs.IsCompress = muxServer.Flag("c", "compress data when tcp|tls mode").Default("false").Bool()
muxServerArgs.SessionCount = muxServer.Flag("session-count", "session count which connect to bridge").Short('n').Default("10").Int() muxServerArgs.SessionCount = muxServer.Flag("session-count", "session count which connect to bridge").Short('n').Default("10").Int()
muxServerArgs.Jumper = muxServer.Flag("jumper", "https or socks5 proxies used when connecting to parent, only worked of -T is tls or tcp, format is https://username:password@host:port https://host:port or socks5://username:password@host:port socks5://host:port").Short('J').Default("").String()
//########mux-client######### //########mux-client#########
muxClient := app.Command("client", "proxy on mux client mode") muxClient := app.Command("client", "proxy on mux client mode")
@ -158,6 +161,7 @@ func initConfig() (err error) {
muxClientArgs.Key = muxClient.Flag("k", "key same with server").Default("default").String() muxClientArgs.Key = muxClient.Flag("k", "key same with server").Default("default").String()
muxClientArgs.IsCompress = muxClient.Flag("c", "compress data when tcp|tls mode").Default("false").Bool() muxClientArgs.IsCompress = muxClient.Flag("c", "compress data when tcp|tls mode").Default("false").Bool()
muxClientArgs.SessionCount = muxClient.Flag("session-count", "session count which connect to bridge").Short('n').Default("10").Int() muxClientArgs.SessionCount = muxClient.Flag("session-count", "session count which connect to bridge").Short('n').Default("10").Int()
muxClientArgs.Jumper = muxClient.Flag("jumper", "https or socks5 proxies used when connecting to parent, only worked of -T is tls or tcp, format is https://username:password@host:port https://host:port or socks5://username:password@host:port socks5://host:port").Short('J').Default("").String()
//########mux-bridge######### //########mux-bridge#########
muxBridge := app.Command("bridge", "proxy on mux bridge mode") muxBridge := app.Command("bridge", "proxy on mux bridge mode")
@ -176,6 +180,7 @@ func initConfig() (err error) {
tunnelServerArgs.IsUDP = tunnelServer.Flag("udp", "proxy on udp tunnel server mode").Default("false").Bool() tunnelServerArgs.IsUDP = tunnelServer.Flag("udp", "proxy on udp tunnel server mode").Default("false").Bool()
tunnelServerArgs.Key = tunnelServer.Flag("k", "client key").Default("default").String() tunnelServerArgs.Key = tunnelServer.Flag("k", "client key").Default("default").String()
tunnelServerArgs.Route = tunnelServer.Flag("route", "local route to client's network, such as: PROTOCOL://LOCAL_IP:LOCAL_PORT@[CLIENT_KEY]CLIENT_LOCAL_HOST:CLIENT_LOCAL_PORT").Short('r').Default("").Strings() tunnelServerArgs.Route = tunnelServer.Flag("route", "local route to client's network, such as: PROTOCOL://LOCAL_IP:LOCAL_PORT@[CLIENT_KEY]CLIENT_LOCAL_HOST:CLIENT_LOCAL_PORT").Short('r').Default("").Strings()
tunnelServerArgs.Jumper = tunnelServer.Flag("jumper", "https or socks5 proxies used when connecting to parent, only worked of -T is tls or tcp, format is https://username:password@host:port https://host:port or socks5://username:password@host:port socks5://host:port").Short('J').Default("").String()
//########tunnel-client######### //########tunnel-client#########
tunnelClient := app.Command("tclient", "proxy on tunnel client mode") tunnelClient := app.Command("tclient", "proxy on tunnel client mode")
@ -184,6 +189,7 @@ func initConfig() (err error) {
tunnelClientArgs.KeyFile = tunnelClient.Flag("key", "key file for tls").Short('K').Default("proxy.key").String() tunnelClientArgs.KeyFile = tunnelClient.Flag("key", "key file for tls").Short('K').Default("proxy.key").String()
tunnelClientArgs.Timeout = tunnelClient.Flag("timeout", "tcp timeout with milliseconds").Short('t').Default("2000").Int() tunnelClientArgs.Timeout = tunnelClient.Flag("timeout", "tcp timeout with milliseconds").Short('t').Default("2000").Int()
tunnelClientArgs.Key = tunnelClient.Flag("k", "key same with server").Default("default").String() tunnelClientArgs.Key = tunnelClient.Flag("k", "key same with server").Default("default").String()
tunnelClientArgs.Jumper = tunnelClient.Flag("jumper", "https or socks5 proxies used when connecting to parent, only worked of -T is tls or tcp, format is https://username:password@host:port https://host:port or socks5://username:password@host:port socks5://host:port").Short('J').Default("").String()
//########tunnel-bridge######### //########tunnel-bridge#########
tunnelBridge := app.Command("tbridge", "proxy on tunnel bridge mode") tunnelBridge := app.Command("tbridge", "proxy on tunnel bridge mode")
@ -198,8 +204,6 @@ func initConfig() (err error) {
socksArgs.ParentType = socks.Flag("parent-type", "parent protocol type <tls|tcp|kcp|ssh>").Default("tcp").Short('T').Enum("tls", "tcp", "kcp", "ssh") socksArgs.ParentType = socks.Flag("parent-type", "parent protocol type <tls|tcp|kcp|ssh>").Default("tcp").Short('T').Enum("tls", "tcp", "kcp", "ssh")
socksArgs.LocalType = socks.Flag("local-type", "local protocol type <tls|tcp|kcp>").Default("tcp").Short('t').Enum("tls", "tcp", "kcp") socksArgs.LocalType = socks.Flag("local-type", "local protocol type <tls|tcp|kcp>").Default("tcp").Short('t').Enum("tls", "tcp", "kcp")
socksArgs.Local = socks.Flag("local", "local ip:port to listen").Short('p').Default(":33080").String() socksArgs.Local = socks.Flag("local", "local ip:port to listen").Short('p').Default(":33080").String()
socksArgs.UDPParent = socks.Flag("udp-parent", "udp parent address, such as: \"23.32.32.19:33090\"").Default("").Short('X').String()
socksArgs.UDPLocal = socks.Flag("udp-local", "udp local ip:port to listen").Short('x').Default(":33090").String()
socksArgs.CertFile = socks.Flag("cert", "cert file for tls").Short('C').Default("proxy.crt").String() socksArgs.CertFile = socks.Flag("cert", "cert file for tls").Short('C').Default("proxy.crt").String()
socksArgs.CaCertFile = socks.Flag("ca", "ca cert file for tls").Default("").String() socksArgs.CaCertFile = socks.Flag("ca", "ca cert file for tls").Default("").String()
socksArgs.KeyFile = socks.Flag("key", "key file for tls").Short('K').Default("proxy.key").String() socksArgs.KeyFile = socks.Flag("key", "key file for tls").Short('K').Default("proxy.key").String()
@ -354,7 +358,9 @@ func initConfig() (err error) {
} }
log.SetFlags(flags) log.SetFlags(flags)
if *logfile != "" { if *nolog {
log.SetOutput(ioutil.Discard)
} else if *logfile != "" {
f, e := os.OpenFile(*logfile, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0600) f, e := os.OpenFile(*logfile, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0600)
if e != nil { if e != nil {
log.Fatal(e) log.Fatal(e)
@ -388,6 +394,7 @@ func initConfig() (err error) {
for { for {
if cmd != nil { if cmd != nil {
cmd.Process.Kill() cmd.Process.Kill()
time.Sleep(time.Second * 5)
} }
cmd = exec.Command(os.Args[0], args...) cmd = exec.Command(os.Args[0], args...)
cmdReaderStderr, err := cmd.StderrPipe() cmdReaderStderr, err := cmd.StderrPipe()
@ -423,7 +430,6 @@ func initConfig() (err error) {
continue continue
} }
log.Printf("worker %s [PID] %d unexpected exited, restarting...\n", os.Args[0], pid) log.Printf("worker %s [PID] %d unexpected exited, restarting...\n", os.Args[0], pid)
time.Sleep(time.Second * 5)
} }
}() }()
return return

View File

@ -1,5 +1,8 @@
# Old Versions of Proxy # Old Versions of Proxy
- [v5.3手册](https://github.com/snail007/goproxy/tree/v5.3)
- [v5.2手册](https://github.com/snail007/goproxy/tree/v5.2)
- [v5.1手册](https://github.com/snail007/goproxy/tree/v5.1)
- [v5.0手册](https://github.com/snail007/goproxy/tree/v5.0) - [v5.0手册](https://github.com/snail007/goproxy/tree/v5.0)
- [v4.9手册](https://github.com/snail007/goproxy/tree/v4.9) - [v4.9手册](https://github.com/snail007/goproxy/tree/v4.9)
- [v4.8手册](https://github.com/snail007/goproxy/tree/v4.8) - [v4.8手册](https://github.com/snail007/goproxy/tree/v4.8)

View File

@ -5,7 +5,7 @@ if [ -e /tmp/proxy ]; then
fi fi
mkdir /tmp/proxy mkdir /tmp/proxy
cd /tmp/proxy cd /tmp/proxy
wget https://github.com/snail007/goproxy/releases/download/v5.1/proxy-linux-amd64.tar.gz wget https://github.com/snail007/goproxy/releases/download/v5.4/proxy-linux-amd64.tar.gz
# #install proxy # #install proxy
tar zxvf proxy-linux-amd64.tar.gz tar zxvf proxy-linux-amd64.tar.gz
@ -19,7 +19,7 @@ fi
if [ ! -e /etc/proxy/proxy.crt ]; then if [ ! -e /etc/proxy/proxy.crt ]; then
cd /etc/proxy/ cd /etc/proxy/
proxy keygen >/dev/null 2>&1 proxy keygen -C proxy >/dev/null 2>&1
fi fi
rm -rf /tmp/proxy rm -rf /tmp/proxy
echo "install done" echo "install done"

View File

@ -1,3 +0,0 @@
#!/bin/bash
openssl genrsa -out proxy.key 2048
openssl req -new -key proxy.key -x509 -days 3650 -out proxy.crt -subj /C=CN/ST=BJ/O="Localhost Ltd"/CN=proxy

View File

@ -9,7 +9,7 @@ import (
"github.com/snail007/goproxy/services" "github.com/snail007/goproxy/services"
) )
const APP_VERSION = "5.1" const APP_VERSION = "5.4"
func main() { func main() {
err := initConfig() err := initConfig()

View File

@ -1,5 +1,5 @@
#!/bin/bash #!/bin/bash
VER="5.1" VER="5.4"
RELEASE="release-${VER}" RELEASE="release-${VER}"
rm -rf .cert rm -rf .cert
mkdir .cert mkdir .cert
@ -60,12 +60,12 @@ CGO_ENABLED=0 GOOS=plan9 GOARCH=arm go build -o proxy && tar zcfv "${RELEASE}/pr
#solaris #solaris
CGO_ENABLED=0 GOOS=solaris GOARCH=amd64 go build -o proxy && tar zcfv "${RELEASE}/proxy-solaris-amd64.tar.gz" proxy direct blocked CGO_ENABLED=0 GOOS=solaris GOARCH=amd64 go build -o proxy && tar zcfv "${RELEASE}/proxy-solaris-amd64.tar.gz" proxy direct blocked
#windows #windows
CGO_ENABLED=0 GOOS=windows GOARCH=386 go build -ldflags="-H=windowsgui" -o proxy-wingui.exe CGO_ENABLED=0 GOOS=windows GOARCH=386 go build -ldflags="-H=windowsgui" -o proxy-noconsole.exe
CGO_ENABLED=0 GOOS=windows GOARCH=386 go build -o proxy.exe && tar zcfv "${RELEASE}/proxy-windows-386.tar.gz" proxy.exe proxy-wingui.exe direct blocked .cert/proxy.crt .cert/proxy.key CGO_ENABLED=0 GOOS=windows GOARCH=386 go build -o proxy.exe && tar zcfv "${RELEASE}/proxy-windows-386.tar.gz" proxy.exe proxy-noconsole.exe direct blocked .cert/proxy.crt .cert/proxy.key
CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build -ldflags="-H=windowsgui" -o proxy-wingui.exe CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build -ldflags="-H=windowsgui" -o proxy-noconsole.exe
CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build -o proxy.exe && tar zcfv "${RELEASE}/proxy-windows-amd64.tar.gz" proxy.exe proxy-wingui.exe direct blocked .cert/proxy.crt .cert/proxy.key CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build -o proxy.exe && tar zcfv "${RELEASE}/proxy-windows-amd64.tar.gz" proxy.exe proxy-noconsole.exe direct blocked .cert/proxy.crt .cert/proxy.key
rm -rf proxy proxy.exe proxy-wingui.exe .cert rm -rf proxy proxy.exe proxy-noconsole.exe .cert
#todo #todo
#1.release.sh VER="xxx" #1.release.sh VER="xxx"

View File

@ -1,4 +1,15 @@
SDK更新日志 SDK更新日志
v5.4
1.去掉了无用参数
v5.3
1.增加了支持日志输出回调的方法:
StartWithLog(serviceID, serviceArgsStr string, loggerCallback LogCallback)
2.优化了socks_client握手端口判断,避免了sstap测试UDP失败的问题..
3.修复了HTTP(S)\SPS反向代理无法正常工作的问题.
4.优化了智能判断,减少不必要的DNS解析.
5.重构了SOCKS和SPS的UDP功能,基于UDP的游戏加速嗖嗖的.
v4.9 v4.9
1.修复了HTTP Basic代理返回不合适的头部,导致浏览器不会弹框,个别代理插件无法认证的问题. 1.修复了HTTP Basic代理返回不合适的头部,导致浏览器不会弹框,个别代理插件无法认证的问题.

View File

@ -25,7 +25,7 @@ proxy使用gombile实现了一份go代码编译为android和ios平台下面可
#### 1.导入包 #### 1.导入包
```java ```java
import snail007.proxy.Porxy import snail007.proxy.Proxy
``` ```
#### 2.启动一个服务 #### 2.启动一个服务

View File

@ -76,7 +76,7 @@ func (s *DNS) InitService() (err error) {
nil, nil,
&net.Dialer{ &net.Dialer{
Timeout: 5 * time.Second, Timeout: 5 * time.Second,
KeepAlive: 5 * time.Second, KeepAlive: 2 * time.Second,
}, },
) )
if err != nil { if err != nil {
@ -117,7 +117,7 @@ func (s *DNS) StopService() {
if e != nil { if e != nil {
s.log.Printf("stop dns service crashed,%s", e) s.log.Printf("stop dns service crashed,%s", e)
} else { } else {
s.log.Printf("service dns stoped") s.log.Printf("service dns stopped")
} }
}() }()
Stop(s.serviceKey) Stop(s.serviceKey)

View File

@ -1,5 +1,5 @@
#/bin/bash #/bin/bash
VER="v5.0" VER="v5.3"
rm -rf sdk-android-*.tar.gz rm -rf sdk-android-*.tar.gz
rm -rf android rm -rf android
mkdir android mkdir android

View File

@ -1,5 +1,5 @@
#/bin/bash #/bin/bash
VER="v5.0" VER="v5.3"
rm -rf sdk-ios-*.tar.gz rm -rf sdk-ios-*.tar.gz
rm -rf ios rm -rf ios
mkdir ios mkdir ios

View File

@ -3,6 +3,7 @@ package proxy
import ( import (
"crypto/sha1" "crypto/sha1"
"fmt" "fmt"
"io/ioutil"
logger "log" logger "log"
"os" "os"
"path" "path"
@ -23,12 +24,31 @@ import (
kingpin "gopkg.in/alecthomas/kingpin.v2" kingpin "gopkg.in/alecthomas/kingpin.v2"
) )
const SDK_VERSION = "5.0" const SDK_VERSION = "5.3"
var ( var (
app *kingpin.Application app *kingpin.Application
) )
type LogCallback interface {
Write(line string)
}
type logCallback interface {
Write(line string)
}
type logWriter struct {
callback LogCallback
}
func (s *logWriter) Write(p []byte) (n int, err error) {
s.callback.Write(string(p))
return
}
func Start(serviceID, serviceArgsStr string) (errStr string) {
return StartWithLog(serviceID, serviceArgsStr, nil)
}
//Start //Start
//serviceID : is service identify id,different service's id should be difference //serviceID : is service identify id,different service's id should be difference
//serviceArgsStr: is the whole command line args string //serviceArgsStr: is the whole command line args string
@ -38,7 +58,7 @@ var (
//and so on. //and so on.
//if an error occured , errStr will be the error reason //if an error occured , errStr will be the error reason
//if start success, errStr is empty. //if start success, errStr is empty.
func Start(serviceID, serviceArgsStr string) (errStr string) { func StartWithLog(serviceID, serviceArgsStr string, loggerCallback LogCallback) (errStr string) {
//define args //define args
tcpArgs := tcpx.TCPArgs{} tcpArgs := tcpx.TCPArgs{}
httpArgs := httpx.HTTPArgs{} httpArgs := httpx.HTTPArgs{}
@ -58,6 +78,7 @@ func Start(serviceID, serviceArgsStr string) (errStr string) {
app.Author("snail").Version(SDK_VERSION) app.Author("snail").Version(SDK_VERSION)
debug := app.Flag("debug", "debug log output").Default("false").Bool() debug := app.Flag("debug", "debug log output").Default("false").Bool()
logfile := app.Flag("log", "log file path").Default("").String() logfile := app.Flag("log", "log file path").Default("").String()
nolog := app.Flag("nolog", "turn off logging").Default("false").Bool()
kcpArgs.Key = app.Flag("kcp-key", "pre-shared secret between client and server").Default("secrect").String() kcpArgs.Key = app.Flag("kcp-key", "pre-shared secret between client and server").Default("secrect").String()
kcpArgs.Crypt = app.Flag("kcp-method", "encrypt/decrypt method, can be: aes, aes-128, aes-192, salsa20, blowfish, twofish, cast5, 3des, tea, xtea, xor, sm4, none").Default("aes").Enum("aes", "aes-128", "aes-192", "salsa20", "blowfish", "twofish", "cast5", "3des", "tea", "xtea", "xor", "sm4", "none") kcpArgs.Crypt = app.Flag("kcp-method", "encrypt/decrypt method, can be: aes, aes-128, aes-192, salsa20, blowfish, twofish, cast5, 3des, tea, xtea, xor, sm4, none").Default("aes").Enum("aes", "aes-128", "aes-192", "salsa20", "blowfish", "twofish", "cast5", "3des", "tea", "xtea", "xor", "sm4", "none")
kcpArgs.Mode = app.Flag("kcp-mode", "profiles: fast3, fast2, fast, normal, manual").Default("fast3").Enum("fast3", "fast2", "fast", "normal", "manual") kcpArgs.Mode = app.Flag("kcp-mode", "profiles: fast3, fast2, fast, normal, manual").Default("fast3").Enum("fast3", "fast2", "fast", "normal", "manual")
@ -118,8 +139,8 @@ func Start(serviceID, serviceArgsStr string) (errStr string) {
tcpArgs.Timeout = tcp.Flag("timeout", "tcp timeout milliseconds when connect to real server or parent proxy").Short('e').Default("2000").Int() tcpArgs.Timeout = tcp.Flag("timeout", "tcp timeout milliseconds when connect to real server or parent proxy").Short('e').Default("2000").Int()
tcpArgs.ParentType = tcp.Flag("parent-type", "parent protocol type <tls|tcp|kcp|udp>").Short('T').Enum("tls", "tcp", "udp", "kcp") tcpArgs.ParentType = tcp.Flag("parent-type", "parent protocol type <tls|tcp|kcp|udp>").Short('T').Enum("tls", "tcp", "udp", "kcp")
tcpArgs.LocalType = tcp.Flag("local-type", "local protocol type <tls|tcp|kcp>").Default("tcp").Short('t').Enum("tls", "tcp", "kcp") tcpArgs.LocalType = tcp.Flag("local-type", "local protocol type <tls|tcp|kcp>").Default("tcp").Short('t').Enum("tls", "tcp", "kcp")
tcpArgs.CheckParentInterval = tcp.Flag("check-parent-interval", "check if proxy is okay every interval seconds,zero: means no check").Short('I').Default("3").Int()
tcpArgs.Local = tcp.Flag("local", "local ip:port to listen").Short('p').Default(":33080").String() tcpArgs.Local = tcp.Flag("local", "local ip:port to listen").Short('p').Default(":33080").String()
tcpArgs.Jumper = tcp.Flag("jumper", "https or socks5 proxies used when connecting to parent, only worked of -T is tls or tcp, format is https://username:password@host:port https://host:port or socks5://username:password@host:port socks5://host:port").Short('J').Default("").String()
//########udp######### //########udp#########
udp := app.Command("udp", "proxy on udp mode") udp := app.Command("udp", "proxy on udp mode")
@ -143,6 +164,7 @@ func Start(serviceID, serviceArgsStr string) (errStr string) {
muxServerArgs.Route = muxServer.Flag("route", "local route to client's network, such as: PROTOCOL://LOCAL_IP:LOCAL_PORT@[CLIENT_KEY]CLIENT_LOCAL_HOST:CLIENT_LOCAL_PORT").Short('r').Default("").Strings() muxServerArgs.Route = muxServer.Flag("route", "local route to client's network, such as: PROTOCOL://LOCAL_IP:LOCAL_PORT@[CLIENT_KEY]CLIENT_LOCAL_HOST:CLIENT_LOCAL_PORT").Short('r').Default("").Strings()
muxServerArgs.IsCompress = muxServer.Flag("c", "compress data when tcp|tls mode").Default("false").Bool() muxServerArgs.IsCompress = muxServer.Flag("c", "compress data when tcp|tls mode").Default("false").Bool()
muxServerArgs.SessionCount = muxServer.Flag("session-count", "session count which connect to bridge").Short('n').Default("10").Int() muxServerArgs.SessionCount = muxServer.Flag("session-count", "session count which connect to bridge").Short('n').Default("10").Int()
muxServerArgs.Jumper = muxServer.Flag("jumper", "https or socks5 proxies used when connecting to parent, only worked of -T is tls or tcp, format is https://username:password@host:port https://host:port or socks5://username:password@host:port socks5://host:port").Short('J').Default("").String()
//########mux-client######### //########mux-client#########
muxClient := app.Command("client", "proxy on mux client mode") muxClient := app.Command("client", "proxy on mux client mode")
@ -154,6 +176,7 @@ func Start(serviceID, serviceArgsStr string) (errStr string) {
muxClientArgs.Key = muxClient.Flag("k", "key same with server").Default("default").String() muxClientArgs.Key = muxClient.Flag("k", "key same with server").Default("default").String()
muxClientArgs.IsCompress = muxClient.Flag("c", "compress data when tcp|tls mode").Default("false").Bool() muxClientArgs.IsCompress = muxClient.Flag("c", "compress data when tcp|tls mode").Default("false").Bool()
muxClientArgs.SessionCount = muxClient.Flag("session-count", "session count which connect to bridge").Short('n').Default("10").Int() muxClientArgs.SessionCount = muxClient.Flag("session-count", "session count which connect to bridge").Short('n').Default("10").Int()
muxClientArgs.Jumper = muxClient.Flag("jumper", "https or socks5 proxies used when connecting to parent, only worked of -T is tls or tcp, format is https://username:password@host:port https://host:port or socks5://username:password@host:port socks5://host:port").Short('J').Default("").String()
//########mux-bridge######### //########mux-bridge#########
muxBridge := app.Command("bridge", "proxy on mux bridge mode") muxBridge := app.Command("bridge", "proxy on mux bridge mode")
@ -172,6 +195,7 @@ func Start(serviceID, serviceArgsStr string) (errStr string) {
tunnelServerArgs.IsUDP = tunnelServer.Flag("udp", "proxy on udp tunnel server mode").Default("false").Bool() tunnelServerArgs.IsUDP = tunnelServer.Flag("udp", "proxy on udp tunnel server mode").Default("false").Bool()
tunnelServerArgs.Key = tunnelServer.Flag("k", "client key").Default("default").String() tunnelServerArgs.Key = tunnelServer.Flag("k", "client key").Default("default").String()
tunnelServerArgs.Route = tunnelServer.Flag("route", "local route to client's network, such as: PROTOCOL://LOCAL_IP:LOCAL_PORT@[CLIENT_KEY]CLIENT_LOCAL_HOST:CLIENT_LOCAL_PORT").Short('r').Default("").Strings() tunnelServerArgs.Route = tunnelServer.Flag("route", "local route to client's network, such as: PROTOCOL://LOCAL_IP:LOCAL_PORT@[CLIENT_KEY]CLIENT_LOCAL_HOST:CLIENT_LOCAL_PORT").Short('r').Default("").Strings()
tunnelServerArgs.Jumper = tunnelServer.Flag("jumper", "https or socks5 proxies used when connecting to parent, only worked of -T is tls or tcp, format is https://username:password@host:port https://host:port or socks5://username:password@host:port socks5://host:port").Short('J').Default("").String()
//########tunnel-client######### //########tunnel-client#########
tunnelClient := app.Command("tclient", "proxy on tunnel client mode") tunnelClient := app.Command("tclient", "proxy on tunnel client mode")
@ -180,6 +204,7 @@ func Start(serviceID, serviceArgsStr string) (errStr string) {
tunnelClientArgs.KeyFile = tunnelClient.Flag("key", "key file for tls").Short('K').Default("proxy.key").String() tunnelClientArgs.KeyFile = tunnelClient.Flag("key", "key file for tls").Short('K').Default("proxy.key").String()
tunnelClientArgs.Timeout = tunnelClient.Flag("timeout", "tcp timeout with milliseconds").Short('t').Default("2000").Int() tunnelClientArgs.Timeout = tunnelClient.Flag("timeout", "tcp timeout with milliseconds").Short('t').Default("2000").Int()
tunnelClientArgs.Key = tunnelClient.Flag("k", "key same with server").Default("default").String() tunnelClientArgs.Key = tunnelClient.Flag("k", "key same with server").Default("default").String()
tunnelClientArgs.Jumper = tunnelClient.Flag("jumper", "https or socks5 proxies used when connecting to parent, only worked of -T is tls or tcp, format is https://username:password@host:port https://host:port or socks5://username:password@host:port socks5://host:port").Short('J').Default("").String()
//########tunnel-bridge######### //########tunnel-bridge#########
tunnelBridge := app.Command("tbridge", "proxy on tunnel bridge mode") tunnelBridge := app.Command("tbridge", "proxy on tunnel bridge mode")
@ -194,8 +219,6 @@ func Start(serviceID, serviceArgsStr string) (errStr string) {
socksArgs.ParentType = socks.Flag("parent-type", "parent protocol type <tls|tcp|kcp|ssh>").Default("tcp").Short('T').Enum("tls", "tcp", "kcp", "ssh") socksArgs.ParentType = socks.Flag("parent-type", "parent protocol type <tls|tcp|kcp|ssh>").Default("tcp").Short('T').Enum("tls", "tcp", "kcp", "ssh")
socksArgs.LocalType = socks.Flag("local-type", "local protocol type <tls|tcp|kcp>").Default("tcp").Short('t').Enum("tls", "tcp", "kcp") socksArgs.LocalType = socks.Flag("local-type", "local protocol type <tls|tcp|kcp>").Default("tcp").Short('t').Enum("tls", "tcp", "kcp")
socksArgs.Local = socks.Flag("local", "local ip:port to listen").Short('p').Default(":33080").String() socksArgs.Local = socks.Flag("local", "local ip:port to listen").Short('p').Default(":33080").String()
socksArgs.UDPParent = socks.Flag("udp-parent", "udp parent address, such as: \"23.32.32.19:33090\"").Default("").Short('X').String()
socksArgs.UDPLocal = socks.Flag("udp-local", "udp local ip:port to listen").Short('x').Default(":33090").String()
socksArgs.CertFile = socks.Flag("cert", "cert file for tls").Short('C').Default("proxy.crt").String() socksArgs.CertFile = socks.Flag("cert", "cert file for tls").Short('C').Default("proxy.crt").String()
socksArgs.CaCertFile = socks.Flag("ca", "ca cert file for tls").Default("").String() socksArgs.CaCertFile = socks.Flag("ca", "ca cert file for tls").Default("").String()
socksArgs.KeyFile = socks.Flag("key", "key file for tls").Short('K').Default("proxy.key").String() socksArgs.KeyFile = socks.Flag("key", "key file for tls").Short('K').Default("proxy.key").String()
@ -339,12 +362,20 @@ func Start(serviceID, serviceArgsStr string) (errStr string) {
} }
log.SetFlags(flags) log.SetFlags(flags)
if *logfile != "" { if loggerCallback == nil {
f, e := os.OpenFile(*logfile, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0600) if *nolog {
if e != nil { log.SetOutput(ioutil.Discard)
log.Fatal(e) } else if *logfile != "" {
f, e := os.OpenFile(*logfile, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0600)
if e != nil {
log.Fatal(e)
}
log.SetOutput(f)
} }
log.SetOutput(f) } else {
log.SetOutput(&logWriter{
callback: loggerCallback,
})
} }
//regist services and run service //regist services and run service

View File

@ -1,5 +1,5 @@
#/bin/bash #/bin/bash
VER="v5.0" VER="v5.3"
rm -rf sdk-linux-*.tar.gz rm -rf sdk-linux-*.tar.gz
rm -rf README.md libproxy-sdk.so libproxy-sdk.h libproxy-sdk.a rm -rf README.md libproxy-sdk.so libproxy-sdk.h libproxy-sdk.a

View File

@ -1,5 +1,5 @@
#/bin/bash #/bin/bash
VER="v5.0" VER="v5.3"
rm -rf *.tar.gz rm -rf *.tar.gz
rm -rf README.md libproxy-sdk.dylib libproxy-sdk.h rm -rf README.md libproxy-sdk.dylib libproxy-sdk.h

View File

@ -1,8 +1,8 @@
#/bin/bash #/bin/bash
VER="v5.0" VER="v5.3"
sudo rm /usr/local/go #sudo rm /usr/local/go
sudo ln -s /usr/local/go1.10.1 /usr/local/go #sudo ln -s /usr/local/go1.10.1 /usr/local/go
rm -rf sdk-windows-*.tar.gz rm -rf sdk-windows-*.tar.gz
rm -rf README.md proxy-sdk.h proxy-sdk.dll rm -rf README.md proxy-sdk.h proxy-sdk.dll
@ -22,7 +22,7 @@ cp ../README.md .
tar zcf sdk-windows-32bit-${VER}.tar.gz README.md proxy-sdk.dll proxy-sdk.h ieshims.dll tar zcf sdk-windows-32bit-${VER}.tar.gz README.md proxy-sdk.dll proxy-sdk.h ieshims.dll
rm -rf README.md proxy-sdk.h proxy-sdk.dll rm -rf README.md proxy-sdk.h proxy-sdk.dll
sudo rm /usr/local/go #sudo rm /usr/local/go
sudo ln -s /usr/local/go1.8.5 /usr/local/go #sudo ln -s /usr/local/go1.8.5 /usr/local/go
echo "done." echo "done."

View File

@ -185,11 +185,13 @@ func (s *HTTP) StopService() {
if e != nil { if e != nil {
s.log.Printf("stop http(s) service crashed,%s", e) s.log.Printf("stop http(s) service crashed,%s", e)
} else { } else {
s.log.Printf("service http(s) stoped") s.log.Printf("service http(s) stopped")
} }
}() }()
s.isStop = true s.isStop = true
s.checker.Stop() if *s.cfg.Parent != "" {
s.checker.Stop()
}
if s.sshClient != nil { if s.sshClient != nil {
s.sshClient.Close() s.sshClient.Close()
} }
@ -277,10 +279,11 @@ func (s *HTTP) callback(inConn net.Conn) {
} else if *s.cfg.Always { } else if *s.cfg.Always {
useProxy = true useProxy = true
} else { } else {
k := s.Resolve(address) var isInMap bool
s.checker.Add(address, k) useProxy, isInMap, _, _ = s.checker.IsBlocked(address)
//var n, m uint if !isInMap {
useProxy, _, _ = s.checker.IsBlocked(k) s.checker.Add(address, s.Resolve(address))
}
//s.log.Printf("blocked ? : %v, %s , fail:%d ,success:%d", useProxy, address, n, m) //s.log.Printf("blocked ? : %v, %s , fail:%d ,success:%d", useProxy, address, n, m)
} }
} }
@ -344,7 +347,6 @@ func (s *HTTP) OutToTCP(useProxy bool, address string, inConn *net.Conn, req *ut
Password: *s.cfg.ParentKey, Password: *s.cfg.ParentKey,
}) })
} }
outAddr := outConn.RemoteAddr().String() outAddr := outConn.RemoteAddr().String()
//outLocalAddr := outConn.LocalAddr().String() //outLocalAddr := outConn.LocalAddr().String()
if req.IsHTTPS() && (!useProxy || *s.cfg.ParentType == "ssh") { if req.IsHTTPS() && (!useProxy || *s.cfg.ParentType == "ssh") {
@ -353,8 +355,8 @@ func (s *HTTP) OutToTCP(useProxy bool, address string, inConn *net.Conn, req *ut
} else { } else {
//https或者http,上级是代理,proxy需要转发 //https或者http,上级是代理,proxy需要转发
outConn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout))) outConn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
//直连目标或上级非代理,清理HTTP头部的代理头信息 //直连目标或上级非代理或非SNI,清理HTTP头部的代理头信息.
if !useProxy || *s.cfg.ParentType == "ssh" { if (!useProxy || *s.cfg.ParentType == "ssh") && !req.IsSNI {
_, err = outConn.Write(utils.RemoveProxyHeaders(req.HeadBuf)) _, err = outConn.Write(utils.RemoveProxyHeaders(req.HeadBuf))
} else { } else {
_, err = outConn.Write(req.HeadBuf) _, err = outConn.Write(req.HeadBuf)
@ -492,7 +494,7 @@ func (s *HTTP) IsDeadLoop(inLocalAddr string, host string) bool {
if *s.cfg.DNSAddress != "" { if *s.cfg.DNSAddress != "" {
outIPs = []net.IP{net.ParseIP(s.Resolve(outDomain))} outIPs = []net.IP{net.ParseIP(s.Resolve(outDomain))}
} else { } else {
outIPs, err = net.LookupIP(outDomain) outIPs, err = utils.MyLookupIP(outDomain)
} }
if err == nil { if err == nil {
for _, ip := range outIPs { for _, ip := range outIPs {
@ -524,6 +526,7 @@ func (s *HTTP) Resolve(address string) string {
ip, err := s.domainResolver.Resolve(address) ip, err := s.domainResolver.Resolve(address)
if err != nil { if err != nil {
s.log.Printf("dns error %s , ERR:%s", address, err) s.log.Printf("dns error %s , ERR:%s", address, err)
return address
} }
return ip return ip
} }

View File

@ -80,7 +80,7 @@ func (s *MuxBridge) StopService() {
if e != nil { if e != nil {
s.log.Printf("stop bridge service crashed,%s", e) s.log.Printf("stop bridge service crashed,%s", e)
} else { } else {
s.log.Printf("service bridge stoped") s.log.Printf("service bridge stopped")
} }
}() }()
s.isStop = true s.isStop = true
@ -88,7 +88,7 @@ func (s *MuxBridge) StopService() {
(*(*s.sc).Listener).Close() (*(*s.sc).Listener).Close()
} }
for _, g := range s.clientControlConns.Items() { for _, g := range s.clientControlConns.Items() {
for _, session := range g.(utils.ConcurrentMap).Items() { for _, session := range g.(*utils.ConcurrentMap).Items() {
(session.(*smux.Session)).Close() (session.(*smux.Session)).Close()
} }
} }

View File

@ -12,6 +12,7 @@ import (
"github.com/snail007/goproxy/services" "github.com/snail007/goproxy/services"
"github.com/snail007/goproxy/services/kcpcfg" "github.com/snail007/goproxy/services/kcpcfg"
"github.com/snail007/goproxy/utils" "github.com/snail007/goproxy/utils"
"github.com/snail007/goproxy/utils/jumper"
//"github.com/xtaci/smux" //"github.com/xtaci/smux"
smux "github.com/hashicorp/yamux" smux "github.com/hashicorp/yamux"
) )
@ -28,12 +29,14 @@ type MuxClientArgs struct {
IsCompress *bool IsCompress *bool
SessionCount *int SessionCount *int
KCP kcpcfg.KCPConfigArgs KCP kcpcfg.KCPConfigArgs
Jumper *string
} }
type MuxClient struct { type MuxClient struct {
cfg MuxClientArgs cfg MuxClientArgs
isStop bool isStop bool
sessions utils.ConcurrentMap sessions utils.ConcurrentMap
log *logger.Logger log *logger.Logger
jumper *jumper.Jumper
} }
func NewMuxClient() services.Service { func NewMuxClient() services.Service {
@ -65,6 +68,19 @@ func (s *MuxClient) CheckArgs() (err error) {
return return
} }
} }
if *s.cfg.Jumper != "" {
if *s.cfg.ParentType != "tls" && *s.cfg.ParentType != "tcp" {
err = fmt.Errorf("jumper only worked of -T is tls or tcp")
return
}
var j jumper.Jumper
j, err = jumper.New(*s.cfg.Jumper, time.Millisecond*time.Duration(*s.cfg.Timeout))
if err != nil {
err = fmt.Errorf("parse jumper fail, err %s", err)
return
}
s.jumper = &j
}
return return
} }
func (s *MuxClient) StopService() { func (s *MuxClient) StopService() {
@ -73,7 +89,7 @@ func (s *MuxClient) StopService() {
if e != nil { if e != nil {
s.log.Printf("stop client service crashed,%s", e) s.log.Printf("stop client service crashed,%s", e)
} else { } else {
s.log.Printf("service client stoped") s.log.Printf("service client stopped")
} }
}() }()
s.isStop = true s.isStop = true
@ -182,15 +198,32 @@ func (s *MuxClient) Clean() {
} }
func (s *MuxClient) getParentConn() (conn net.Conn, err error) { func (s *MuxClient) getParentConn() (conn net.Conn, err error) {
if *s.cfg.ParentType == "tls" { if *s.cfg.ParentType == "tls" {
var _conn tls.Conn if s.jumper == nil {
_conn, err = utils.TlsConnectHost(*s.cfg.Parent, *s.cfg.Timeout, s.cfg.CertBytes, s.cfg.KeyBytes, nil) var _conn tls.Conn
if err == nil { _conn, err = utils.TlsConnectHost(*s.cfg.Parent, *s.cfg.Timeout, s.cfg.CertBytes, s.cfg.KeyBytes, nil)
conn = net.Conn(&_conn) if err == nil {
conn = net.Conn(&_conn)
}
} else {
conf, err := utils.TlsConfig(s.cfg.CertBytes, s.cfg.KeyBytes, nil)
if err != nil {
return nil, err
}
var _c net.Conn
_c, err = s.jumper.Dial(*s.cfg.Parent, time.Millisecond*time.Duration(*s.cfg.Timeout))
if err == nil {
conn = net.Conn(tls.Client(_c, conf))
}
} }
} else if *s.cfg.ParentType == "kcp" { } else if *s.cfg.ParentType == "kcp" {
conn, err = utils.ConnectKCPHost(*s.cfg.Parent, s.cfg.KCP) conn, err = utils.ConnectKCPHost(*s.cfg.Parent, s.cfg.KCP)
} else { } else {
conn, err = utils.ConnectHost(*s.cfg.Parent, *s.cfg.Timeout) if s.jumper == nil {
conn, err = utils.ConnectHost(*s.cfg.Parent, *s.cfg.Timeout)
} else {
conn, err = s.jumper.Dial(*s.cfg.Parent, time.Millisecond*time.Duration(*s.cfg.Timeout))
}
} }
return return
} }

View File

@ -15,6 +15,7 @@ import (
"github.com/snail007/goproxy/services" "github.com/snail007/goproxy/services"
"github.com/snail007/goproxy/services/kcpcfg" "github.com/snail007/goproxy/services/kcpcfg"
"github.com/snail007/goproxy/utils" "github.com/snail007/goproxy/utils"
"github.com/snail007/goproxy/utils/jumper"
"github.com/golang/snappy" "github.com/golang/snappy"
//"github.com/xtaci/smux" //"github.com/xtaci/smux"
@ -38,6 +39,7 @@ type MuxServerArgs struct {
IsCompress *bool IsCompress *bool
SessionCount *int SessionCount *int
KCP kcpcfg.KCPConfigArgs KCP kcpcfg.KCPConfigArgs
Jumper *string
} }
type MuxUDPItem struct { type MuxUDPItem struct {
@ -121,6 +123,7 @@ func (s *MuxServerManager) Start(args interface{}, log *logger.Logger) (err erro
SessionCount: s.cfg.SessionCount, SessionCount: s.cfg.SessionCount,
KCP: s.cfg.KCP, KCP: s.cfg.KCP,
ParentType: s.cfg.ParentType, ParentType: s.cfg.ParentType,
Jumper: s.cfg.Jumper,
}, log) }, log)
if err != nil { if err != nil {
@ -164,6 +167,7 @@ type MuxServer struct {
isStop bool isStop bool
udpConn *net.Conn udpConn *net.Conn
log *logger.Logger log *logger.Logger
jumper *jumper.Jumper
} }
func NewMuxServer() services.Service { func NewMuxServer() services.Service {
@ -182,7 +186,7 @@ func (s *MuxServer) StopService() {
if e != nil { if e != nil {
s.log.Printf("stop server service crashed,%s", e) s.log.Printf("stop server service crashed,%s", e)
} else { } else {
s.log.Printf("service server stoped") s.log.Printf("service server stopped")
} }
}() }()
s.isStop = true s.isStop = true
@ -208,6 +212,19 @@ func (s *MuxServer) CheckArgs() (err error) {
err = fmt.Errorf("remote required") err = fmt.Errorf("remote required")
return return
} }
if *s.cfg.Jumper != "" {
if *s.cfg.ParentType != "tls" && *s.cfg.ParentType != "tcp" {
err = fmt.Errorf("jumper only worked of -T is tls or tcp")
return
}
var j jumper.Jumper
j, err = jumper.New(*s.cfg.Jumper, time.Millisecond*time.Duration(*s.cfg.Timeout))
if err != nil {
err = fmt.Errorf("parse jumper fail, err %s", err)
return
}
s.jumper = &j
}
return return
} }
@ -378,15 +395,32 @@ func (s *MuxServer) GetConn(index string) (conn net.Conn, err error) {
} }
func (s *MuxServer) getParentConn() (conn net.Conn, err error) { func (s *MuxServer) getParentConn() (conn net.Conn, err error) {
if *s.cfg.ParentType == "tls" { if *s.cfg.ParentType == "tls" {
var _conn tls.Conn if s.jumper == nil {
_conn, err = utils.TlsConnectHost(*s.cfg.Parent, *s.cfg.Timeout, s.cfg.CertBytes, s.cfg.KeyBytes, nil) var _conn tls.Conn
if err == nil { _conn, err = utils.TlsConnectHost(*s.cfg.Parent, *s.cfg.Timeout, s.cfg.CertBytes, s.cfg.KeyBytes, nil)
conn = net.Conn(&_conn) if err == nil {
conn = net.Conn(&_conn)
}
} else {
conf, err := utils.TlsConfig(s.cfg.CertBytes, s.cfg.KeyBytes, nil)
if err != nil {
return nil, err
}
var _c net.Conn
_c, err = s.jumper.Dial(*s.cfg.Parent, time.Millisecond*time.Duration(*s.cfg.Timeout))
if err == nil {
conn = net.Conn(tls.Client(_c, conf))
}
} }
} else if *s.cfg.ParentType == "kcp" { } else if *s.cfg.ParentType == "kcp" {
conn, err = utils.ConnectKCPHost(*s.cfg.Parent, s.cfg.KCP) conn, err = utils.ConnectKCPHost(*s.cfg.Parent, s.cfg.KCP)
} else { } else {
conn, err = utils.ConnectHost(*s.cfg.Parent, *s.cfg.Timeout) if s.jumper == nil {
conn, err = utils.ConnectHost(*s.cfg.Parent, *s.cfg.Timeout)
} else {
conn, err = s.jumper.Dial(*s.cfg.Parent, time.Millisecond*time.Duration(*s.cfg.Timeout))
}
} }
return return
} }

View File

@ -4,6 +4,7 @@ import (
"fmt" "fmt"
logger "log" logger "log"
"runtime/debug" "runtime/debug"
"sync"
) )
type Service interface { type Service interface {
@ -17,31 +18,31 @@ type ServiceItem struct {
Log *logger.Logger Log *logger.Logger
} }
var servicesMap = map[string]*ServiceItem{} var servicesMap = sync.Map{}
func Regist(name string, s Service, args interface{}, log *logger.Logger) { func Regist(name string, s Service, args interface{}, log *logger.Logger) {
Stop(name) Stop(name)
servicesMap[name] = &ServiceItem{ servicesMap.Store(name, &ServiceItem{
S: s, S: s,
Args: args, Args: args,
Name: name, Name: name,
Log: log, Log: log,
} })
} }
func GetService(name string) *ServiceItem { func GetService(name string) *ServiceItem {
if s, ok := servicesMap[name]; ok && s.S != nil { if s, ok := servicesMap.Load(name); ok && s.(*ServiceItem).S != nil {
return s return s.(*ServiceItem)
} }
return nil return nil
} }
func Stop(name string) { func Stop(name string) {
if s, ok := servicesMap[name]; ok && s.S != nil { if s, ok := servicesMap.Load(name); ok && s.(*ServiceItem).S != nil {
s.S.Clean() s.(*ServiceItem).S.Clean()
} }
} }
func Run(name string, args interface{}) (service *ServiceItem, err error) { func Run(name string, args interface{}) (service *ServiceItem, err error) {
service, ok := servicesMap[name] _service, ok := servicesMap.Load(name)
if ok { if ok {
defer func() { defer func() {
e := recover() e := recover()
@ -49,6 +50,7 @@ func Run(name string, args interface{}) (service *ServiceItem, err error) {
err = fmt.Errorf("%s servcie crashed, ERR: %s\ntrace:%s", name, e, string(debug.Stack())) err = fmt.Errorf("%s servcie crashed, ERR: %s\ntrace:%s", name, e, string(debug.Stack()))
} }
}() }()
service = _service.(*ServiceItem)
if args != nil { if args != nil {
err = service.S.Start(args, service.Log) err = service.S.Start(args, service.Log)
} else { } else {

View File

@ -3,6 +3,7 @@ package socks
import ( import (
"crypto/tls" "crypto/tls"
"fmt" "fmt"
"io"
"io/ioutil" "io/ioutil"
logger "log" logger "log"
"net" "net"
@ -13,7 +14,6 @@ import (
"github.com/snail007/goproxy/services" "github.com/snail007/goproxy/services"
"github.com/snail007/goproxy/services/kcpcfg" "github.com/snail007/goproxy/services/kcpcfg"
"github.com/snail007/goproxy/utils" "github.com/snail007/goproxy/utils"
"github.com/snail007/goproxy/utils/aes"
"github.com/snail007/goproxy/utils/conncrypt" "github.com/snail007/goproxy/utils/conncrypt"
"github.com/snail007/goproxy/utils/socks" "github.com/snail007/goproxy/utils/socks"
"golang.org/x/crypto/ssh" "golang.org/x/crypto/ssh"
@ -48,8 +48,6 @@ type SocksArgs struct {
AuthURLTimeout *int AuthURLTimeout *int
AuthURLRetry *int AuthURLRetry *int
KCP kcpcfg.KCPConfigArgs KCP kcpcfg.KCPConfigArgs
UDPParent *string
UDPLocal *string
LocalIPS *[]string LocalIPS *[]string
DNSAddress *string DNSAddress *string
DNSTTL *int DNSTTL *int
@ -59,27 +57,31 @@ type SocksArgs struct {
ParentCompress *bool ParentCompress *bool
} }
type Socks struct { type Socks struct {
cfg SocksArgs cfg SocksArgs
checker utils.Checker checker utils.Checker
basicAuth utils.BasicAuth basicAuth utils.BasicAuth
sshClient *ssh.Client sshClient *ssh.Client
lockChn chan bool lockChn chan bool
udpSC utils.ServerChannel udpSC utils.ServerChannel
sc *utils.ServerChannel sc *utils.ServerChannel
domainResolver utils.DomainResolver domainResolver utils.DomainResolver
isStop bool isStop bool
userConns utils.ConcurrentMap userConns utils.ConcurrentMap
log *logger.Logger log *logger.Logger
udpRelatedPacketConns utils.ConcurrentMap
udpLocalKey []byte
udpParentKey []byte
} }
func NewSocks() services.Service { func NewSocks() services.Service {
return &Socks{ return &Socks{
cfg: SocksArgs{}, cfg: SocksArgs{},
checker: utils.Checker{}, checker: utils.Checker{},
basicAuth: utils.BasicAuth{}, basicAuth: utils.BasicAuth{},
lockChn: make(chan bool, 1), lockChn: make(chan bool, 1),
isStop: false, isStop: false,
userConns: utils.NewConcurrentMap(), userConns: utils.NewConcurrentMap(),
udpRelatedPacketConns: utils.NewConcurrentMap(),
} }
} }
@ -103,17 +105,6 @@ func (s *Socks) CheckArgs() (err error) {
err = fmt.Errorf("parent type unkown,use -T <tls|tcp|ssh|kcp>") err = fmt.Errorf("parent type unkown,use -T <tls|tcp|ssh|kcp>")
return return
} }
host, _, e := net.SplitHostPort(*s.cfg.Parent)
if e != nil {
err = fmt.Errorf("parent format error : %s", e)
return
}
if *s.cfg.UDPParent == "" {
*s.cfg.UDPParent = net.JoinHostPort(host, "33090")
}
if strings.HasPrefix(*s.cfg.UDPParent, ":") {
*s.cfg.UDPParent = net.JoinHostPort(host, strings.TrimLeft(*s.cfg.UDPParent, ":"))
}
if *s.cfg.ParentType == "ssh" { if *s.cfg.ParentType == "ssh" {
if *s.cfg.SSHUser == "" { if *s.cfg.SSHUser == "" {
err = fmt.Errorf("ssh user required") err = fmt.Errorf("ssh user required")
@ -145,6 +136,9 @@ func (s *Socks) CheckArgs() (err error) {
} }
} }
} }
s.udpLocalKey = s.LocalUDPKey()
s.udpParentKey = s.ParentUDPKey()
//s.log.Printf("udpLocalKey : %v , udpParentKey : %v", s.udpLocalKey, s.udpParentKey)
return return
} }
func (s *Socks) InitService() (err error) { func (s *Socks) InitService() (err error) {
@ -152,7 +146,9 @@ func (s *Socks) InitService() (err error) {
if *s.cfg.DNSAddress != "" { if *s.cfg.DNSAddress != "" {
(*s).domainResolver = utils.NewDomainResolver(*s.cfg.DNSAddress, *s.cfg.DNSTTL, s.log) (*s).domainResolver = utils.NewDomainResolver(*s.cfg.DNSAddress, *s.cfg.DNSTTL, s.log)
} }
s.checker = utils.NewChecker(*s.cfg.Timeout, int64(*s.cfg.Interval), *s.cfg.Blocked, *s.cfg.Direct, s.log) if *s.cfg.Parent != "" {
s.checker = utils.NewChecker(*s.cfg.Timeout, int64(*s.cfg.Interval), *s.cfg.Blocked, *s.cfg.Direct, s.log)
}
if *s.cfg.ParentType == "ssh" { if *s.cfg.ParentType == "ssh" {
e := s.ConnectSSH() e := s.ConnectSSH()
if e != nil { if e != nil {
@ -186,14 +182,6 @@ func (s *Socks) InitService() (err error) {
} }
if *s.cfg.ParentType == "ssh" { if *s.cfg.ParentType == "ssh" {
s.log.Printf("warn: socks udp not suppored for ssh") s.log.Printf("warn: socks udp not suppored for ssh")
} else {
s.udpSC = utils.NewServerChannelHost(*s.cfg.UDPLocal, s.log)
e := s.udpSC.ListenUDP(s.udpCallback)
if e != nil {
err = fmt.Errorf("init udp service fail, ERR: %s", e)
return
}
s.log.Printf("udp socks proxy on %s", s.udpSC.UDPListener.LocalAddr())
} }
return return
} }
@ -203,11 +191,13 @@ func (s *Socks) StopService() {
if e != nil { if e != nil {
s.log.Printf("stop socks service crashed,%s", e) s.log.Printf("stop socks service crashed,%s", e)
} else { } else {
s.log.Printf("service socks stoped") s.log.Printf("service socks stopped")
} }
}() }()
s.isStop = true s.isStop = true
s.checker.Stop() if *s.cfg.Parent != "" {
s.checker.Stop()
}
if s.sshClient != nil { if s.sshClient != nil {
s.sshClient.Close() s.sshClient.Close()
} }
@ -220,6 +210,9 @@ func (s *Socks) StopService() {
for _, c := range s.userConns.Items() { for _, c := range s.userConns.Items() {
(*c.(*net.Conn)).Close() (*c.(*net.Conn)).Close()
} }
for _, c := range s.udpRelatedPacketConns.Items() {
(*c.(*net.UDPConn)).Close()
}
} }
func (s *Socks) Start(args interface{}, log *logger.Logger) (err error) { func (s *Socks) Start(args interface{}, log *logger.Logger) (err error) {
s.log = log s.log = log
@ -234,9 +227,6 @@ func (s *Socks) Start(args interface{}, log *logger.Logger) (err error) {
if *s.cfg.Parent != "" { if *s.cfg.Parent != "" {
s.log.Printf("use %s parent %s", *s.cfg.ParentType, *s.cfg.Parent) s.log.Printf("use %s parent %s", *s.cfg.ParentType, *s.cfg.Parent)
} }
if *s.cfg.UDPParent != "" {
s.log.Printf("use socks udp parent %s", *s.cfg.UDPParent)
}
sc := utils.NewServerChannelHost(*s.cfg.Local, s.log) sc := utils.NewServerChannelHost(*s.cfg.Local, s.log)
if *s.cfg.LocalType == "tcp" { if *s.cfg.LocalType == "tcp" {
err = sc.ListenTCP(s.socksConnCallback) err = sc.ListenTCP(s.socksConnCallback)
@ -255,165 +245,7 @@ func (s *Socks) Start(args interface{}, log *logger.Logger) (err error) {
func (s *Socks) Clean() { func (s *Socks) Clean() {
s.StopService() s.StopService()
} }
func (s *Socks) UDPKey() []byte {
return s.cfg.KeyBytes[:32]
}
func (s *Socks) udpCallback(b []byte, localAddr, srcAddr *net.UDPAddr) {
rawB := b
var err error
if *s.cfg.LocalType == "tls" {
//decode b
rawB, err = goaes.Decrypt(s.UDPKey(), b)
if err != nil {
s.log.Printf("decrypt udp packet fail from %s", srcAddr.String())
return
}
}
p, err := socks.ParseUDPPacket(rawB)
s.log.Printf("udp revecived:%v", len(p.Data()))
if err != nil {
s.log.Printf("parse udp packet fail, ERR:%s", err)
return
}
//防止死循环
if s.IsDeadLoop((*localAddr).String(), p.Host()) {
s.log.Printf("dead loop detected , %s", p.Host())
return
}
//s.log.Printf("##########udp to -> %s:%s###########", p.Host(), p.Port())
if *s.cfg.Parent != "" {
//有上级代理,转发给上级
if *s.cfg.ParentType == "tls" {
//encode b
rawB, err = goaes.Encrypt(s.UDPKey(), rawB)
if err != nil {
s.log.Printf("encrypt udp data fail to %s", *s.cfg.Parent)
return
}
}
parent := *s.cfg.UDPParent
if parent == "" {
parent = *s.cfg.Parent
}
dstAddr, err := net.ResolveUDPAddr("udp", s.Resolve(parent))
if err != nil {
s.log.Printf("can't resolve address: %s", err)
return
}
clientSrcAddr := &net.UDPAddr{IP: net.IPv4zero, Port: 0}
conn, err := net.DialUDP("udp", clientSrcAddr, dstAddr)
if err != nil {
s.log.Printf("connect to udp %s fail,ERR:%s", dstAddr.String(), err)
return
}
conn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout*5)))
_, err = conn.Write(rawB)
conn.SetDeadline(time.Time{})
s.log.Printf("udp request:%v", len(rawB))
if err != nil {
s.log.Printf("send udp packet to %s fail,ERR:%s", dstAddr.String(), err)
conn.Close()
return
}
//s.log.Printf("send udp packet to %s success", dstAddr.String())
buf := make([]byte, 10*1024)
conn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
length, _, err := conn.ReadFromUDP(buf)
conn.SetDeadline(time.Time{})
if err != nil {
s.log.Printf("read udp response from %s fail ,ERR:%s", dstAddr.String(), err)
conn.Close()
return
}
respBody := buf[0:length]
s.log.Printf("udp response:%v", len(respBody))
//s.log.Printf("revecived udp packet from %s", dstAddr.String())
if *s.cfg.ParentType == "tls" {
//decode b
respBody, err = goaes.Decrypt(s.UDPKey(), respBody)
if err != nil {
s.log.Printf("encrypt udp data fail to %s", *s.cfg.Parent)
conn.Close()
return
}
}
if *s.cfg.LocalType == "tls" {
d, err := goaes.Encrypt(s.UDPKey(), respBody)
if err != nil {
s.log.Printf("encrypt udp data fail from %s", dstAddr.String())
conn.Close()
return
}
s.udpSC.UDPListener.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
s.udpSC.UDPListener.WriteToUDP(d, srcAddr)
s.udpSC.UDPListener.SetDeadline(time.Time{})
s.log.Printf("udp reply:%v", len(d))
d = nil
} else {
s.udpSC.UDPListener.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
s.udpSC.UDPListener.WriteToUDP(respBody, srcAddr)
s.udpSC.UDPListener.SetDeadline(time.Time{})
s.log.Printf("udp reply:%v", len(respBody))
}
} else {
//本地代理
dstAddr, err := net.ResolveUDPAddr("udp", net.JoinHostPort(s.Resolve(p.Host()), p.Port()))
if err != nil {
s.log.Printf("can't resolve address: %s", err)
return
}
clientSrcAddr := &net.UDPAddr{IP: net.IPv4zero, Port: 0}
conn, err := net.DialUDP("udp", clientSrcAddr, dstAddr)
if err != nil {
s.log.Printf("connect to udp %s fail,ERR:%s", dstAddr.String(), err)
return
}
conn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout*3)))
_, err = conn.Write(p.Data())
conn.SetDeadline(time.Time{})
s.log.Printf("udp send:%v", len(p.Data()))
if err != nil {
s.log.Printf("send udp packet to %s fail,ERR:%s", dstAddr.String(), err)
conn.Close()
return
}
//s.log.Printf("send udp packet to %s success", dstAddr.String())
buf := make([]byte, 10*1024)
conn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
length, _, err := conn.ReadFromUDP(buf)
conn.SetDeadline(time.Time{})
if err != nil {
s.log.Printf("read udp response from %s fail ,ERR:%s", dstAddr.String(), err)
conn.Close()
return
}
respBody := buf[0:length]
//封装来自真实服务器的数据,返回给访问者
respPacket := p.NewReply(respBody)
//s.log.Printf("revecived udp packet from %s", dstAddr.String())
if *s.cfg.LocalType == "tls" {
d, err := goaes.Encrypt(s.UDPKey(), respPacket)
if err != nil {
s.log.Printf("encrypt udp data fail from %s", dstAddr.String())
conn.Close()
return
}
s.udpSC.UDPListener.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
s.udpSC.UDPListener.WriteToUDP(d, srcAddr)
s.udpSC.UDPListener.SetDeadline(time.Time{})
d = nil
} else {
s.udpSC.UDPListener.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
s.udpSC.UDPListener.WriteToUDP(respPacket, srcAddr)
s.udpSC.UDPListener.SetDeadline(time.Time{})
}
s.log.Printf("udp reply:%v", len(respPacket))
}
}
func (s *Socks) socksConnCallback(inConn net.Conn) { func (s *Socks) socksConnCallback(inConn net.Conn) {
defer func() { defer func() {
if err := recover(); err != nil { if err := recover(); err != nil {
@ -438,7 +270,9 @@ func (s *Socks) socksConnCallback(inConn net.Conn) {
if err != nil { if err != nil {
methodReq.Reply(socks.Method_NONE_ACCEPTABLE) methodReq.Reply(socks.Method_NONE_ACCEPTABLE)
utils.CloseConn(&inConn) utils.CloseConn(&inConn)
s.log.Printf("new methods request fail,ERR: %s", err) if err != io.EOF {
s.log.Printf("new methods request fail,ERR: %s", err)
}
return return
} }
@ -526,16 +360,7 @@ func (s *Socks) socksConnCallback(inConn net.Conn) {
} }
} }
func (s *Socks) proxyUDP(inConn *net.Conn, methodReq socks.MethodsRequest, request socks.Request) {
if *s.cfg.ParentType == "ssh" {
utils.CloseConn(inConn)
return
}
host, _, _ := net.SplitHostPort((*inConn).LocalAddr().String())
_, port, _ := net.SplitHostPort(s.udpSC.UDPListener.LocalAddr().String())
s.log.Printf("proxy udp on %s", net.JoinHostPort(host, port))
request.UDPReply(socks.REP_SUCCESS, net.JoinHostPort(host, port))
}
func (s *Socks) proxyTCP(inConn *net.Conn, methodReq socks.MethodsRequest, request socks.Request) { func (s *Socks) proxyTCP(inConn *net.Conn, methodReq socks.MethodsRequest, request socks.Request) {
var outConn net.Conn var outConn net.Conn
var err interface{} var err interface{}
@ -554,7 +379,7 @@ func (s *Socks) proxyTCP(inConn *net.Conn, methodReq socks.MethodsRequest, reque
return return
} }
if *s.cfg.Always { if *s.cfg.Always {
outConn, err = s.getOutConn(methodReq.Bytes(), request.Bytes(), request.Addr()) outConn, err = s.getOutConn(methodReq.Bytes(), request.Bytes(), request.Addr(), true)
} else { } else {
if *s.cfg.Parent != "" { if *s.cfg.Parent != "" {
host, _, _ := net.SplitHostPort(request.Addr()) host, _, _ := net.SplitHostPort(request.Addr())
@ -562,12 +387,14 @@ func (s *Socks) proxyTCP(inConn *net.Conn, methodReq socks.MethodsRequest, reque
if utils.IsIternalIP(host, *s.cfg.Always) { if utils.IsIternalIP(host, *s.cfg.Always) {
useProxy = false useProxy = false
} else { } else {
k := s.Resolve(request.Addr()) var isInMap bool
s.checker.Add(request.Addr(), k) useProxy, isInMap, _, _ = s.checker.IsBlocked(request.Addr())
useProxy, _, _ = s.checker.IsBlocked(k) if !isInMap {
s.checker.Add(request.Addr(), s.Resolve(request.Addr()))
}
} }
if useProxy { if useProxy {
outConn, err = s.getOutConn(methodReq.Bytes(), request.Bytes(), request.Addr()) outConn, err = s.getOutConn(methodReq.Bytes(), request.Bytes(), request.Addr(), true)
} else { } else {
outConn, err = utils.ConnectHost(s.Resolve(request.Addr()), *s.cfg.Timeout) outConn, err = utils.ConnectHost(s.Resolve(request.Addr()), *s.cfg.Timeout)
} }
@ -607,7 +434,7 @@ func (s *Socks) proxyTCP(inConn *net.Conn, methodReq socks.MethodsRequest, reque
} }
s.userConns.Set(inAddr, inConn) s.userConns.Set(inAddr, inConn)
} }
func (s *Socks) getOutConn(methodBytes, reqBytes []byte, host string) (outConn net.Conn, err interface{}) { func (s *Socks) getOutConn(methodBytes, reqBytes []byte, host string, handshake bool) (outConn net.Conn, err interface{}) {
switch *s.cfg.ParentType { switch *s.cfg.ParentType {
case "kcp": case "kcp":
fallthrough fallthrough
@ -635,6 +462,9 @@ func (s *Socks) getOutConn(methodBytes, reqBytes []byte, host string) (outConn n
Password: *s.cfg.ParentKey, Password: *s.cfg.ParentKey,
}) })
} }
if !handshake {
return
}
var buf = make([]byte, 1024) var buf = make([]byte, 1024)
//var n int //var n int
outConn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout))) outConn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
@ -772,7 +602,7 @@ func (s *Socks) IsDeadLoop(inLocalAddr string, host string) bool {
if *s.cfg.DNSAddress != "" { if *s.cfg.DNSAddress != "" {
outIPs = []net.IP{net.ParseIP(s.Resolve(outDomain))} outIPs = []net.IP{net.ParseIP(s.Resolve(outDomain))}
} else { } else {
outIPs, err = net.LookupIP(outDomain) outIPs, err = utils.MyLookupIP(outDomain)
} }
if err == nil { if err == nil {
for _, ip := range outIPs { for _, ip := range outIPs {
@ -804,6 +634,7 @@ func (s *Socks) Resolve(address string) string {
ip, err := s.domainResolver.Resolve(address) ip, err := s.domainResolver.Resolve(address)
if err != nil { if err != nil {
s.log.Printf("dns error %s , ERR:%s", address, err) s.log.Printf("dns error %s , ERR:%s", address, err)
return address
} }
return ip return ip
} }

321
services/socks/udp.go Normal file
View File

@ -0,0 +1,321 @@
package socks
import (
"crypto/md5"
"fmt"
"net"
"runtime/debug"
"strconv"
"strings"
"time"
"github.com/snail007/goproxy/utils"
goaes "github.com/snail007/goproxy/utils/aes"
"github.com/snail007/goproxy/utils/socks"
)
func (s *Socks) ParentUDPKey() (key []byte) {
switch *s.cfg.ParentType {
case "tcp":
if *s.cfg.ParentKey != "" {
v := fmt.Sprintf("%x", md5.Sum([]byte(*s.cfg.ParentKey)))
return []byte(v)[:24]
}
case "tls":
return s.cfg.KeyBytes[:24]
case "kcp":
v := fmt.Sprintf("%x", md5.Sum([]byte(*s.cfg.KCP.Key)))
return []byte(v)[:24]
}
return
}
func (s *Socks) LocalUDPKey() (key []byte) {
switch *s.cfg.LocalType {
case "tcp":
if *s.cfg.LocalKey != "" {
v := fmt.Sprintf("%x", md5.Sum([]byte(*s.cfg.LocalKey)))
return []byte(v)[:24]
}
case "tls":
return s.cfg.KeyBytes[:24]
case "kcp":
v := fmt.Sprintf("%x", md5.Sum([]byte(*s.cfg.KCP.Key)))
return []byte(v)[:24]
}
return
}
func (s *Socks) proxyUDP(inConn *net.Conn, methodReq socks.MethodsRequest, request socks.Request) {
defer func() {
if e := recover(); e != nil {
s.log.Printf("udp local->out io copy crashed:\n%s\n%s", e, string(debug.Stack()))
}
}()
if *s.cfg.ParentType == "ssh" {
utils.CloseConn(inConn)
return
}
srcIP, _, _ := net.SplitHostPort((*inConn).RemoteAddr().String())
inconnRemoteAddr := (*inConn).RemoteAddr().String()
localAddr := &net.UDPAddr{IP: net.IPv4zero, Port: 0}
udpListener, err := net.ListenUDP("udp", localAddr)
if err != nil {
(*inConn).Close()
udpListener.Close()
s.log.Printf("udp bind fail , %s", err)
return
}
host, _, _ := net.SplitHostPort((*inConn).LocalAddr().String())
_, port, _ := net.SplitHostPort(udpListener.LocalAddr().String())
if len(*s.cfg.LocalIPS) > 0 {
host = (*s.cfg.LocalIPS)[0]
}
s.log.Printf("proxy udp on %s , for %s", net.JoinHostPort(host, port), inconnRemoteAddr)
request.UDPReply(socks.REP_SUCCESS, net.JoinHostPort(host, port))
s.userConns.Set(inconnRemoteAddr, inConn)
var (
outUDPConn *net.UDPConn
outconn net.Conn
outconnLocalAddr string
isClosedErr = func(err error) bool {
return err != nil && strings.Contains(err.Error(), "use of closed network connection")
}
destAddr *net.UDPAddr
)
var clean = func(msg, err string) {
raddr := ""
if outUDPConn != nil {
raddr = outUDPConn.RemoteAddr().String()
outUDPConn.Close()
}
if msg != "" {
if raddr != "" {
s.log.Printf("%s , %s , %s -> %s", msg, err, inconnRemoteAddr, raddr)
} else {
s.log.Printf("%s , %s , from : %s", msg, err, inconnRemoteAddr)
}
}
(*inConn).Close()
udpListener.Close()
s.userConns.Remove(inconnRemoteAddr)
if outconn != nil {
outconn.Close()
}
if outconnLocalAddr != "" {
s.userConns.Remove(outconnLocalAddr)
}
}
defer clean("", "")
go func() {
defer func() {
if e := recover(); e != nil {
s.log.Printf("udp related client tcp conn read crashed:\n%s\n%s", e, string(debug.Stack()))
}
}()
buf := make([]byte, 1)
(*inConn).SetReadDeadline(time.Time{})
if _, err := (*inConn).Read(buf); err != nil {
clean("udp related tcp conn disconnected with read", err.Error())
}
}()
go func() {
defer func() {
if e := recover(); e != nil {
s.log.Printf("udp related client tcp conn write crashed:\n%s\n%s", e, string(debug.Stack()))
}
}()
for {
(*inConn).SetWriteDeadline(time.Now().Add(time.Second * 5))
if _, err := (*inConn).Write([]byte{0x00}); err != nil {
clean("udp related tcp conn disconnected with write", err.Error())
return
}
(*inConn).SetWriteDeadline(time.Time{})
time.Sleep(time.Second * 5)
}
}()
useProxy := true
if *s.cfg.Parent != "" {
dstHost, _, _ := net.SplitHostPort(request.Addr())
if utils.IsIternalIP(dstHost, *s.cfg.Always) {
useProxy = false
} else {
var isInMap bool
useProxy, isInMap, _, _ = s.checker.IsBlocked(request.Addr())
if !isInMap {
s.checker.Add(request.Addr(), s.Resolve(request.Addr()))
}
}
} else {
useProxy = false
}
if useProxy {
//parent proxy
outconn, err := s.getOutConn(nil, nil, "", false)
if err != nil {
clean("connnect fail", fmt.Sprintf("%s", err))
return
}
client := socks.NewClientConn(&outconn, "udp", request.Addr(), time.Millisecond*time.Duration(*s.cfg.Timeout), nil, nil)
if err = client.Handshake(); err != nil {
clean("handshake fail", fmt.Sprintf("%s", err))
return
}
//outconnRemoteAddr := outconn.RemoteAddr().String()
outconnLocalAddr = outconn.LocalAddr().String()
s.userConns.Set(outconnLocalAddr, &outconn)
go func() {
defer func() {
if e := recover(); e != nil {
s.log.Printf("udp related parent tcp conn read crashed:\n%s\n%s", e, string(debug.Stack()))
}
}()
buf := make([]byte, 1)
outconn.SetReadDeadline(time.Time{})
if _, err := outconn.Read(buf); err != nil {
clean("udp parent tcp conn disconnected", fmt.Sprintf("%s", err))
}
}()
//forward to parent udp
//s.log.Printf("parent udp address %s", client.UDPAddr)
destAddr, _ = net.ResolveUDPAddr("udp", client.UDPAddr)
}
s.log.Printf("use proxy %v : udp %s", useProxy, request.Addr())
//relay
for {
buf := utils.LeakyBuffer.Get()
defer utils.LeakyBuffer.Put(buf)
n, srcAddr, err := udpListener.ReadFromUDP(buf)
if err != nil {
s.log.Printf("udp listener read fail, %s", err.Error())
if isClosedErr(err) {
return
}
continue
}
srcIP0, _, _ := net.SplitHostPort(srcAddr.String())
//IP not match drop it
if srcIP != srcIP0 {
continue
}
p := socks.NewPacketUDP()
//convert data to raw
if len(s.udpLocalKey) > 0 {
var v []byte
v, err = goaes.Decrypt(s.udpLocalKey, buf[:n])
if err == nil {
err = p.Parse(v)
}
} else {
err = p.Parse(buf[:n])
}
//err = p.Parse(buf[:n])
if err != nil {
s.log.Printf("udp listener parse packet fail, %s", err.Error())
continue
}
port, _ := strconv.Atoi(p.Port())
if v, ok := s.udpRelatedPacketConns.Get(srcAddr.String()); !ok {
if destAddr == nil {
destAddr = &net.UDPAddr{IP: net.ParseIP(p.Host()), Port: port}
}
outUDPConn, err = net.DialUDP("udp", localAddr, destAddr)
if err != nil {
s.log.Printf("create out udp conn fail , %s , from : %s", err, srcAddr)
continue
}
s.udpRelatedPacketConns.Set(srcAddr.String(), outUDPConn)
go func() {
defer func() {
if e := recover(); e != nil {
s.log.Printf("udp out->local io copy crashed:\n%s\n%s", e, string(debug.Stack()))
}
}()
defer s.udpRelatedPacketConns.Remove(srcAddr.String())
//out->local io copy
buf := utils.LeakyBuffer.Get()
defer utils.LeakyBuffer.Put(buf)
for {
n, err := outUDPConn.Read(buf)
if err != nil {
s.log.Printf("read out udp data fail , %s , from : %s", err, srcAddr)
if isClosedErr(err) {
return
}
continue
}
//var dlen = n
if useProxy {
//forward to local
var v []byte
//convert parent data to raw
if len(s.udpParentKey) > 0 {
v, err = goaes.Decrypt(s.udpParentKey, buf[:n])
if err != nil {
s.log.Printf("udp outconn parse packet fail, %s", err.Error())
continue
}
} else {
v = buf[:n]
}
//now v is raw, try convert v to local
if len(s.udpLocalKey) > 0 {
v, _ = goaes.Encrypt(s.udpLocalKey, v)
}
_, err = udpListener.WriteTo(v, srcAddr)
// _, err = udpListener.WriteTo(buf[:n], srcAddr)
} else {
rp := socks.NewPacketUDP()
rp.Build(destAddr.String(), buf[:n])
v := rp.Bytes()
//dlen = len(v)
//rp.Bytes() v is raw, try convert to local
if len(s.udpLocalKey) > 0 {
v, _ = goaes.Encrypt(s.udpLocalKey, v)
}
_, err = udpListener.WriteTo(v, srcAddr)
}
if err != nil {
s.udpRelatedPacketConns.Remove(srcAddr.String())
s.log.Printf("write out data to local fail , %s , from : %s", err, srcAddr)
if isClosedErr(err) {
return
}
continue
} else {
//s.log.Printf("send udp data to local success , len %d, for : %s", dlen, srcAddr)
}
}
}()
} else {
outUDPConn = v.(*net.UDPConn)
}
//local->out io copy
if useProxy {
//forward to parent
//p is raw, now convert it to parent
var v []byte
if len(s.udpParentKey) > 0 {
v, _ = goaes.Encrypt(s.udpParentKey, p.Bytes())
} else {
v = p.Bytes()
}
_, err = outUDPConn.Write(v)
// _, err = outUDPConn.Write(p.Bytes())
} else {
_, err = outUDPConn.Write(p.Data())
}
if err != nil {
if isClosedErr(err) {
return
}
s.log.Printf("send out udp data fail , %s , from : %s", err, srcAddr)
continue
} else {
//s.log.Printf("send udp data to remote success , len %d, for : %s", len(p.Data()), srcAddr)
}
}
}

306
services/sps/socksudp.go Normal file
View File

@ -0,0 +1,306 @@
package sps
import (
"crypto/md5"
"fmt"
"net"
"runtime/debug"
"strconv"
"strings"
"time"
"github.com/snail007/goproxy/utils"
goaes "github.com/snail007/goproxy/utils/aes"
"github.com/snail007/goproxy/utils/conncrypt"
"github.com/snail007/goproxy/utils/socks"
)
func (s *SPS) ParentUDPKey() (key []byte) {
switch *s.cfg.ParentType {
case "tcp":
if *s.cfg.ParentKey != "" {
v := fmt.Sprintf("%x", md5.Sum([]byte(*s.cfg.ParentKey)))
return []byte(v)[:24]
}
case "tls":
return s.cfg.KeyBytes[:24]
case "kcp":
v := fmt.Sprintf("%x", md5.Sum([]byte(*s.cfg.KCP.Key)))
return []byte(v)[:24]
}
return
}
func (s *SPS) LocalUDPKey() (key []byte) {
switch *s.cfg.LocalType {
case "tcp":
if *s.cfg.LocalKey != "" {
v := fmt.Sprintf("%x", md5.Sum([]byte(*s.cfg.LocalKey)))
return []byte(v)[:24]
}
case "tls":
return s.cfg.KeyBytes[:24]
case "kcp":
v := fmt.Sprintf("%x", md5.Sum([]byte(*s.cfg.KCP.Key)))
return []byte(v)[:24]
}
return
}
func (s *SPS) proxyUDP(inConn *net.Conn, serverConn *socks.ServerConn) {
defer func() {
if e := recover(); e != nil {
s.log.Printf("udp local->out io copy crashed:\n%s\n%s", e, string(debug.Stack()))
}
}()
if *s.cfg.ParentType == "ssh" {
utils.CloseConn(inConn)
return
}
srcIP, _, _ := net.SplitHostPort((*inConn).RemoteAddr().String())
inconnRemoteAddr := (*inConn).RemoteAddr().String()
localAddr := &net.UDPAddr{IP: net.IPv4zero, Port: 0}
udpListener := serverConn.UDPConnListener
s.log.Printf("proxy udp on %s , for %s", udpListener.LocalAddr(), inconnRemoteAddr)
s.userConns.Set(inconnRemoteAddr, inConn)
var (
outUDPConn *net.UDPConn
outconn net.Conn
outconnLocalAddr string
isClosedErr = func(err error) bool {
return err != nil && strings.Contains(err.Error(), "use of closed network connection")
}
destAddr *net.UDPAddr
)
var clean = func(msg, err string) {
raddr := ""
if outUDPConn != nil {
raddr = outUDPConn.RemoteAddr().String()
outUDPConn.Close()
}
if msg != "" {
if raddr != "" {
s.log.Printf("%s , %s , %s -> %s", msg, err, inconnRemoteAddr, raddr)
} else {
s.log.Printf("%s , %s , from : %s", msg, err, inconnRemoteAddr)
}
}
(*inConn).Close()
udpListener.Close()
s.userConns.Remove(inconnRemoteAddr)
if outconn != nil {
outconn.Close()
}
if outconnLocalAddr != "" {
s.userConns.Remove(outconnLocalAddr)
}
}
defer clean("", "")
go func() {
defer func() {
if e := recover(); e != nil {
s.log.Printf("udp related client tcp conn read crashed:\n%s\n%s", e, string(debug.Stack()))
}
}()
buf := make([]byte, 1)
(*inConn).SetReadDeadline(time.Time{})
if _, err := (*inConn).Read(buf); err != nil {
clean("udp related tcp conn disconnected with read", err.Error())
}
}()
go func() {
defer func() {
if e := recover(); e != nil {
s.log.Printf("udp related client tcp conn write crashed:\n%s\n%s", e, string(debug.Stack()))
}
}()
for {
(*inConn).SetWriteDeadline(time.Now().Add(time.Second * 5))
if _, err := (*inConn).Write([]byte{0x00}); err != nil {
clean("udp related tcp conn disconnected with write", err.Error())
return
}
(*inConn).SetWriteDeadline(time.Time{})
time.Sleep(time.Second * 5)
}
}()
//parent proxy
outconn, err := s.outPool.Get()
//outconn, err := s.GetParentConn(nil, nil, "", false)
if err != nil {
clean("connnect fail", fmt.Sprintf("%s", err))
return
}
if *s.cfg.ParentCompress {
outconn = utils.NewCompConn(outconn)
}
if *s.cfg.ParentKey != "" {
outconn = conncrypt.New(outconn, &conncrypt.Config{
Password: *s.cfg.ParentKey,
})
}
s.log.Printf("connect %s for udp", serverConn.Target())
//socks client
var client *socks.ClientConn
auth := serverConn.AuthData()
if *s.cfg.ParentAuth != "" {
a := strings.Split(*s.cfg.ParentAuth, ":")
if len(a) != 2 {
err = fmt.Errorf("parent auth data format error")
return
}
client = socks.NewClientConn(&outconn, "udp", serverConn.Target(), time.Millisecond*time.Duration(*s.cfg.Timeout), &socks.Auth{User: a[0], Password: a[1]}, nil)
} else {
if !s.IsBasicAuth() && auth.Password != "" && auth.User != "" {
client = socks.NewClientConn(&outconn, "udp", serverConn.Target(), time.Millisecond*time.Duration(*s.cfg.Timeout), &auth, nil)
} else {
client = socks.NewClientConn(&outconn, "udp", serverConn.Target(), time.Millisecond*time.Duration(*s.cfg.Timeout), nil, nil)
}
}
if err = client.Handshake(); err != nil {
clean("handshake fail", fmt.Sprintf("%s", err))
return
}
//outconnRemoteAddr := outconn.RemoteAddr().String()
outconnLocalAddr = outconn.LocalAddr().String()
s.userConns.Set(outconnLocalAddr, &outconn)
go func() {
defer func() {
if e := recover(); e != nil {
s.log.Printf("udp related parent tcp conn read crashed:\n%s\n%s", e, string(debug.Stack()))
}
}()
buf := make([]byte, 1)
outconn.SetReadDeadline(time.Time{})
if _, err := outconn.Read(buf); err != nil {
clean("udp parent tcp conn disconnected", fmt.Sprintf("%s", err))
}
}()
//forward to parent udp
//s.log.Printf("parent udp address %s", client.UDPAddr)
destAddr, _ = net.ResolveUDPAddr("udp", client.UDPAddr)
//relay
buf := utils.LeakyBuffer.Get()
defer utils.LeakyBuffer.Put(buf)
for {
n, srcAddr, err := udpListener.ReadFromUDP(buf)
if err != nil {
s.log.Printf("udp listener read fail, %s", err.Error())
if isClosedErr(err) {
return
}
continue
}
srcIP0, _, _ := net.SplitHostPort(srcAddr.String())
//IP not match drop it
if srcIP != srcIP0 {
continue
}
p := socks.NewPacketUDP()
//convert data to raw
if len(s.udpLocalKey) > 0 {
var v []byte
v, err = goaes.Decrypt(s.udpLocalKey, buf[:n])
if err == nil {
err = p.Parse(v)
}
} else {
err = p.Parse(buf[:n])
}
if err != nil {
s.log.Printf("udp listener parse packet fail, %s", err.Error())
continue
}
port, _ := strconv.Atoi(p.Port())
if v, ok := s.udpRelatedPacketConns.Get(srcAddr.String()); !ok {
if destAddr == nil {
destAddr = &net.UDPAddr{IP: net.ParseIP(p.Host()), Port: port}
}
outUDPConn, err = net.DialUDP("udp", localAddr, destAddr)
if err != nil {
s.log.Printf("create out udp conn fail , %s , from : %s", err, srcAddr)
continue
}
s.udpRelatedPacketConns.Set(srcAddr.String(), outUDPConn)
go func() {
defer func() {
if e := recover(); e != nil {
s.log.Printf("udp out->local io copy crashed:\n%s\n%s", e, string(debug.Stack()))
}
}()
defer s.udpRelatedPacketConns.Remove(srcAddr.String())
//out->local io copy
buf := utils.LeakyBuffer.Get()
defer utils.LeakyBuffer.Put(buf)
for {
outUDPConn.SetReadDeadline(time.Now().Add(time.Second * 5))
n, err := outUDPConn.Read(buf)
outUDPConn.SetReadDeadline(time.Time{})
if err != nil {
s.log.Printf("read out udp data fail , %s , from : %s", err, srcAddr)
if isClosedErr(err) {
return
}
continue
}
//var dlen = n
//forward to local
var v []byte
//convert parent data to raw
if len(s.udpParentKey) > 0 {
v, err = goaes.Decrypt(s.udpParentKey, buf[:n])
if err != nil {
s.log.Printf("udp outconn parse packet fail, %s", err.Error())
continue
}
} else {
v = buf[:n]
}
//now v is raw, try convert v to local
if len(s.udpLocalKey) > 0 {
v, _ = goaes.Encrypt(s.udpLocalKey, v)
}
_, err = udpListener.WriteTo(v, srcAddr)
// _, err = udpListener.WriteTo(buf[:n], srcAddr)
if err != nil {
s.udpRelatedPacketConns.Remove(srcAddr.String())
s.log.Printf("write out data to local fail , %s , from : %s", err, srcAddr)
if isClosedErr(err) {
return
}
continue
} else {
//s.log.Printf("send udp data to local success , len %d, for : %s", dlen, srcAddr)
}
}
}()
} else {
outUDPConn = v.(*net.UDPConn)
}
//local->out io copy
//forward to parent
//p is raw, now convert it to parent
var v []byte
if len(s.udpParentKey) > 0 {
v, _ = goaes.Encrypt(s.udpParentKey, p.Bytes())
} else {
v = p.Bytes()
}
_, err = outUDPConn.Write(v)
// _, err = outUDPConn.Write(p.Bytes())
if err != nil {
if isClosedErr(err) {
return
}
s.log.Printf("send out udp data fail , %s , from : %s", err, srcAddr)
continue
} else {
//s.log.Printf("send udp data to remote success , len %d, for : %s", len(p.Data()), srcAddr)
}
}
}

View File

@ -17,6 +17,7 @@ import (
"github.com/snail007/goproxy/services/kcpcfg" "github.com/snail007/goproxy/services/kcpcfg"
"github.com/snail007/goproxy/utils" "github.com/snail007/goproxy/utils"
"github.com/snail007/goproxy/utils/conncrypt" "github.com/snail007/goproxy/utils/conncrypt"
"github.com/snail007/goproxy/utils/sni"
"github.com/snail007/goproxy/utils/socks" "github.com/snail007/goproxy/utils/socks"
) )
@ -52,22 +53,26 @@ type SPSArgs struct {
DisableSocks5 *bool DisableSocks5 *bool
} }
type SPS struct { type SPS struct {
outPool utils.OutConn outPool utils.OutConn
cfg SPSArgs cfg SPSArgs
domainResolver utils.DomainResolver domainResolver utils.DomainResolver
basicAuth utils.BasicAuth basicAuth utils.BasicAuth
serverChannels []*utils.ServerChannel serverChannels []*utils.ServerChannel
userConns utils.ConcurrentMap userConns utils.ConcurrentMap
log *logger.Logger log *logger.Logger
udpRelatedPacketConns utils.ConcurrentMap
udpLocalKey []byte
udpParentKey []byte
} }
func NewSPS() services.Service { func NewSPS() services.Service {
return &SPS{ return &SPS{
outPool: utils.OutConn{}, outPool: utils.OutConn{},
cfg: SPSArgs{}, cfg: SPSArgs{},
basicAuth: utils.BasicAuth{}, basicAuth: utils.BasicAuth{},
serverChannels: []*utils.ServerChannel{}, serverChannels: []*utils.ServerChannel{},
userConns: utils.NewConcurrentMap(), userConns: utils.NewConcurrentMap(),
udpRelatedPacketConns: utils.NewConcurrentMap(),
} }
} }
func (s *SPS) CheckArgs() (err error) { func (s *SPS) CheckArgs() (err error) {
@ -92,6 +97,8 @@ func (s *SPS) CheckArgs() (err error) {
} }
} }
} }
s.udpLocalKey = s.LocalUDPKey()
s.udpParentKey = s.ParentUDPKey()
return return
} }
func (s *SPS) InitService() (err error) { func (s *SPS) InitService() (err error) {
@ -123,7 +130,7 @@ func (s *SPS) StopService() {
if e != nil { if e != nil {
s.log.Printf("stop sps service crashed,%s", e) s.log.Printf("stop sps service crashed,%s", e)
} else { } else {
s.log.Printf("service sps stoped") s.log.Printf("service sps stopped")
} }
}() }()
for _, sc := range s.serverChannels { for _, sc := range s.serverChannels {
@ -209,6 +216,11 @@ func (s *SPS) callback(inConn net.Conn) {
} }
} }
func (s *SPS) OutToTCP(inConn *net.Conn) (err error) { func (s *SPS) OutToTCP(inConn *net.Conn) (err error) {
enableUDP := *s.cfg.ParentServiceType == "socks"
udpIP, _, _ := net.SplitHostPort((*inConn).LocalAddr().String())
if len(*s.cfg.LocalIPS) > 0 {
udpIP = (*s.cfg.LocalIPS)[0]
}
bInConn := utils.NewBufferedConn(*inConn) bInConn := utils.NewBufferedConn(*inConn)
//important //important
//action read will regist read event to system, //action read will regist read event to system,
@ -218,7 +230,7 @@ func (s *SPS) OutToTCP(inConn *net.Conn) (err error) {
bInConn.ReadByte() bInConn.ReadByte()
bInConn.UnreadByte() bInConn.UnreadByte()
n := 8 n := 2048
if n > bInConn.Buffered() { if n > bInConn.Buffered() {
n = bInConn.Buffered() n = bInConn.Buffered()
} }
@ -228,12 +240,12 @@ func (s *SPS) OutToTCP(inConn *net.Conn) (err error) {
(*inConn).Close() (*inConn).Close()
return return
} }
isSNI, _ := sni.ServerNameFromBytes(h)
*inConn = bInConn *inConn = bInConn
address := "" address := ""
var auth socks.Auth var auth socks.Auth
var forwardBytes []byte var forwardBytes []byte
//fmt.Printf("%v", header) //fmt.Printf("%v", h)
if utils.IsSocks5(h) { if utils.IsSocks5(h) {
if *s.cfg.DisableSocks5 { if *s.cfg.DisableSocks5 {
(*inConn).Close() (*inConn).Close()
@ -242,16 +254,20 @@ func (s *SPS) OutToTCP(inConn *net.Conn) (err error) {
//socks5 server //socks5 server
var serverConn *socks.ServerConn var serverConn *socks.ServerConn
if s.IsBasicAuth() { if s.IsBasicAuth() {
serverConn = socks.NewServerConn(inConn, time.Millisecond*time.Duration(*s.cfg.Timeout), &s.basicAuth, "", nil) serverConn = socks.NewServerConn(inConn, time.Millisecond*time.Duration(*s.cfg.Timeout), &s.basicAuth, enableUDP, udpIP, nil)
} else { } else {
serverConn = socks.NewServerConn(inConn, time.Millisecond*time.Duration(*s.cfg.Timeout), nil, "", nil) serverConn = socks.NewServerConn(inConn, time.Millisecond*time.Duration(*s.cfg.Timeout), nil, enableUDP, udpIP, nil)
} }
if err = serverConn.Handshake(); err != nil { if err = serverConn.Handshake(); err != nil {
return return
} }
address = serverConn.Target() address = serverConn.Target()
auth = serverConn.AuthData() auth = serverConn.AuthData()
} else if utils.IsHTTP(h) { if serverConn.IsUDP() {
s.proxyUDP(inConn, serverConn)
return
}
} else if utils.IsHTTP(h) || isSNI != "" {
if *s.cfg.DisableHTTP { if *s.cfg.DisableHTTP {
(*inConn).Close() (*inConn).Close()
return return
@ -495,6 +511,7 @@ func (s *SPS) Resolve(address string) string {
ip, err := s.domainResolver.Resolve(address) ip, err := s.domainResolver.Resolve(address)
if err != nil { if err != nil {
s.log.Printf("dns error %s , ERR:%s", address, err) s.log.Printf("dns error %s , ERR:%s", address, err)
return address
} }
return ip return ip
} }

View File

@ -2,6 +2,7 @@ package tcp
import ( import (
"bufio" "bufio"
"crypto/tls"
"fmt" "fmt"
"io" "io"
logger "log" logger "log"
@ -12,36 +13,36 @@ import (
"github.com/snail007/goproxy/services" "github.com/snail007/goproxy/services"
"github.com/snail007/goproxy/services/kcpcfg" "github.com/snail007/goproxy/services/kcpcfg"
"github.com/snail007/goproxy/utils" "github.com/snail007/goproxy/utils"
"github.com/snail007/goproxy/utils/jumper"
"strconv" "strconv"
) )
type TCPArgs struct { type TCPArgs struct {
Parent *string Parent *string
CertFile *string CertFile *string
KeyFile *string KeyFile *string
CertBytes []byte CertBytes []byte
KeyBytes []byte KeyBytes []byte
Local *string Local *string
ParentType *string ParentType *string
LocalType *string LocalType *string
Timeout *int Timeout *int
CheckParentInterval *int KCP kcpcfg.KCPConfigArgs
KCP kcpcfg.KCPConfigArgs Jumper *string
} }
type TCP struct { type TCP struct {
outPool utils.OutConn
cfg TCPArgs cfg TCPArgs
sc *utils.ServerChannel sc *utils.ServerChannel
isStop bool isStop bool
userConns utils.ConcurrentMap userConns utils.ConcurrentMap
log *logger.Logger log *logger.Logger
jumper *jumper.Jumper
} }
func NewTCP() services.Service { func NewTCP() services.Service {
return &TCP{ return &TCP{
outPool: utils.OutConn{},
cfg: TCPArgs{}, cfg: TCPArgs{},
isStop: false, isStop: false,
userConns: utils.NewConcurrentMap(), userConns: utils.NewConcurrentMap(),
@ -62,10 +63,23 @@ func (s *TCP) CheckArgs() (err error) {
return return
} }
} }
if *s.cfg.Jumper != "" {
if *s.cfg.ParentType != "tls" && *s.cfg.ParentType != "tcp" {
err = fmt.Errorf("jumper only worked of -T is tls or tcp")
return
}
var j jumper.Jumper
j, err = jumper.New(*s.cfg.Jumper, time.Millisecond*time.Duration(*s.cfg.Timeout))
if err != nil {
err = fmt.Errorf("parse jumper fail, err %s", err)
return
}
s.jumper = &j
}
return return
} }
func (s *TCP) InitService() (err error) { func (s *TCP) InitService() (err error) {
s.InitOutConnPool()
return return
} }
func (s *TCP) StopService() { func (s *TCP) StopService() {
@ -74,7 +88,7 @@ func (s *TCP) StopService() {
if e != nil { if e != nil {
s.log.Printf("stop tcp service crashed,%s", e) s.log.Printf("stop tcp service crashed,%s", e)
} else { } else {
s.log.Printf("service tcp stoped") s.log.Printf("service tcp stopped")
} }
}() }()
s.isStop = true s.isStop = true
@ -146,7 +160,7 @@ func (s *TCP) callback(inConn net.Conn) {
} }
func (s *TCP) OutToTCP(inConn *net.Conn) (err error) { func (s *TCP) OutToTCP(inConn *net.Conn) (err error) {
var outConn net.Conn var outConn net.Conn
outConn, err = s.outPool.Get() outConn, err = s.GetParentConn()
if err != nil { if err != nil {
s.log.Printf("connect to %s , err:%s", *s.cfg.Parent, err) s.log.Printf("connect to %s , err:%s", *s.cfg.Parent, err)
utils.CloseConn(inConn) utils.CloseConn(inConn)
@ -219,17 +233,34 @@ func (s *TCP) OutToUDP(inConn *net.Conn) (err error) {
return return
} }
func (s *TCP) InitOutConnPool() { func (s *TCP) GetParentConn() (conn net.Conn, err error) {
if *s.cfg.ParentType == "tls" || *s.cfg.ParentType == "tcp" || *s.cfg.ParentType == "kcp" { if *s.cfg.ParentType == "tls" {
//dur int, isTLS bool, certBytes, keyBytes []byte, if s.jumper == nil {
//parent string, timeout int, InitialCap int, MaxCap int var _conn tls.Conn
s.outPool = utils.NewOutConn( _conn, err = utils.TlsConnectHost(*s.cfg.Parent, *s.cfg.Timeout, s.cfg.CertBytes, s.cfg.KeyBytes, nil)
*s.cfg.CheckParentInterval, if err == nil {
*s.cfg.ParentType, conn = net.Conn(&_conn)
s.cfg.KCP, }
s.cfg.CertBytes, s.cfg.KeyBytes, nil, } else {
*s.cfg.Parent, conf, err := utils.TlsConfig(s.cfg.CertBytes, s.cfg.KeyBytes, nil)
*s.cfg.Timeout, if err != nil {
) return nil, err
}
var _c net.Conn
_c, err = s.jumper.Dial(*s.cfg.Parent, time.Millisecond*time.Duration(*s.cfg.Timeout))
if err == nil {
conn = net.Conn(tls.Client(_c, conf))
}
}
} else if *s.cfg.ParentType == "kcp" {
conn, err = utils.ConnectKCPHost(*s.cfg.Parent, s.cfg.KCP)
} else {
if s.jumper == nil {
conn, err = utils.ConnectHost(*s.cfg.Parent, *s.cfg.Timeout)
} else {
conn, err = s.jumper.Dial(*s.cfg.Parent, time.Millisecond*time.Duration(*s.cfg.Timeout))
}
} }
return
} }

View File

@ -30,7 +30,6 @@ type TunnelBridgeArgs struct {
KeyBytes []byte KeyBytes []byte
Local *string Local *string
Timeout *int Timeout *int
Mux *bool
} }
type ServerConn struct { type ServerConn struct {
//ClientLocalAddr string //tcp:2.2.22:333@ID //ClientLocalAddr string //tcp:2.2.22:333@ID
@ -70,7 +69,7 @@ func (s *TunnelBridge) StopService() {
if e != nil { if e != nil {
s.log.Printf("stop tbridge service crashed,%s", e) s.log.Printf("stop tbridge service crashed,%s", e)
} else { } else {
s.log.Printf("service tbridge stoped") s.log.Printf("service tbridge stopped")
} }
}() }()
s.isStop = true s.isStop = true

View File

@ -11,6 +11,7 @@ import (
"github.com/snail007/goproxy/services" "github.com/snail007/goproxy/services"
"github.com/snail007/goproxy/utils" "github.com/snail007/goproxy/utils"
"github.com/snail007/goproxy/utils/jumper"
//"github.com/xtaci/smux" //"github.com/xtaci/smux"
smux "github.com/hashicorp/yamux" smux "github.com/hashicorp/yamux"
) )
@ -28,7 +29,7 @@ type TunnelClientArgs struct {
KeyBytes []byte KeyBytes []byte
Key *string Key *string
Timeout *int Timeout *int
Mux *bool Jumper *string
} }
type TunnelClient struct { type TunnelClient struct {
cfg TunnelClientArgs cfg TunnelClientArgs
@ -36,6 +37,7 @@ type TunnelClient struct {
isStop bool isStop bool
userConns utils.ConcurrentMap userConns utils.ConcurrentMap
log *logger.Logger log *logger.Logger
jumper *jumper.Jumper
} }
func NewTunnelClient() services.Service { func NewTunnelClient() services.Service {
@ -62,6 +64,18 @@ func (s *TunnelClient) CheckArgs() (err error) {
return return
} }
s.cfg.CertBytes, s.cfg.KeyBytes, err = utils.TlsBytes(*s.cfg.CertFile, *s.cfg.KeyFile) s.cfg.CertBytes, s.cfg.KeyBytes, err = utils.TlsBytes(*s.cfg.CertFile, *s.cfg.KeyFile)
if err != nil {
return
}
if *s.cfg.Jumper != "" {
var j jumper.Jumper
j, err = jumper.New(*s.cfg.Jumper, time.Millisecond*time.Duration(*s.cfg.Timeout))
if err != nil {
err = fmt.Errorf("parse jumper fail, err %s", err)
return
}
s.jumper = &j
}
return return
} }
func (s *TunnelClient) StopService() { func (s *TunnelClient) StopService() {
@ -70,7 +84,7 @@ func (s *TunnelClient) StopService() {
if e != nil { if e != nil {
s.log.Printf("stop tclient service crashed,%s", e) s.log.Printf("stop tclient service crashed,%s", e)
} else { } else {
s.log.Printf("service tclient stoped") s.log.Printf("service tclient stopped")
} }
}() }()
s.isStop = true s.isStop = true
@ -151,10 +165,24 @@ func (s *TunnelClient) GetInConn(typ uint8, data ...string) (outConn net.Conn, e
return return
} }
func (s *TunnelClient) GetConn() (conn net.Conn, err error) { func (s *TunnelClient) GetConn() (conn net.Conn, err error) {
var _conn tls.Conn if s.jumper == nil {
_conn, err = utils.TlsConnectHost(*s.cfg.Parent, *s.cfg.Timeout, s.cfg.CertBytes, s.cfg.KeyBytes, nil) var _conn tls.Conn
_conn, err = utils.TlsConnectHost(*s.cfg.Parent, *s.cfg.Timeout, s.cfg.CertBytes, s.cfg.KeyBytes, nil)
if err == nil {
conn = net.Conn(&_conn)
}
} else {
conf, err := utils.TlsConfig(s.cfg.CertBytes, s.cfg.KeyBytes, nil)
if err != nil {
return nil, err
}
var _c net.Conn
_c, err = s.jumper.Dial(*s.cfg.Parent, time.Millisecond*time.Duration(*s.cfg.Timeout))
if err == nil {
conn = net.Conn(tls.Client(_c, conf))
}
}
if err == nil { if err == nil {
conn = net.Conn(&_conn)
c, e := smux.Client(conn, &smux.Config{ c, e := smux.Client(conn, &smux.Config{
AcceptBacklog: 256, AcceptBacklog: 256,
EnableKeepAlive: true, EnableKeepAlive: true,

View File

@ -14,6 +14,7 @@ import (
"github.com/snail007/goproxy/services" "github.com/snail007/goproxy/services"
"github.com/snail007/goproxy/utils" "github.com/snail007/goproxy/utils"
"github.com/snail007/goproxy/utils/jumper"
//"github.com/xtaci/smux" //"github.com/xtaci/smux"
smux "github.com/hashicorp/yamux" smux "github.com/hashicorp/yamux"
@ -32,7 +33,7 @@ type TunnelServerArgs struct {
Timeout *int Timeout *int
Route *[]string Route *[]string
Mgr *TunnelServerManager Mgr *TunnelServerManager
Mux *bool Jumper *string
} }
type UDPItem struct { type UDPItem struct {
packet *[]byte packet *[]byte
@ -105,6 +106,7 @@ func (s *TunnelServerManager) Start(args interface{}, log *logger.Logger) (err e
Key: &KEY, Key: &KEY,
Timeout: s.cfg.Timeout, Timeout: s.cfg.Timeout,
Mgr: s, Mgr: s,
Jumper: s.cfg.Jumper,
}, log) }, log)
if err != nil { if err != nil {
@ -134,30 +136,6 @@ func (s *TunnelServerManager) InitService() (err error) {
return return
} }
func (s *TunnelServerManager) GetOutConn(typ uint8) (outConn net.Conn, ID string, err error) {
outConn, err = s.GetConn()
if err != nil {
s.log.Printf("connection err: %s", err)
return
}
ID = s.serverID
_, err = outConn.Write(utils.BuildPacket(typ, s.serverID))
if err != nil {
s.log.Printf("write connection data err: %s ,retrying...", err)
utils.CloseConn(&outConn)
return
}
return
}
func (s *TunnelServerManager) GetConn() (conn net.Conn, err error) {
var _conn tls.Conn
_conn, err = utils.TlsConnectHost(*s.cfg.Parent, *s.cfg.Timeout, s.cfg.CertBytes, s.cfg.KeyBytes, nil)
if err == nil {
conn = net.Conn(&_conn)
}
return
}
type TunnelServer struct { type TunnelServer struct {
cfg TunnelServerArgs cfg TunnelServerArgs
udpChn chan UDPItem udpChn chan UDPItem
@ -166,6 +144,7 @@ type TunnelServer struct {
udpConn *net.Conn udpConn *net.Conn
userConns utils.ConcurrentMap userConns utils.ConcurrentMap
log *logger.Logger log *logger.Logger
jumper *jumper.Jumper
} }
func NewTunnelServer() services.Service { func NewTunnelServer() services.Service {
@ -183,7 +162,7 @@ func (s *TunnelServer) StopService() {
if e != nil { if e != nil {
s.log.Printf("stop server service crashed,%s", e) s.log.Printf("stop server service crashed,%s", e)
} else { } else {
s.log.Printf("service server stoped") s.log.Printf("service server stopped")
} }
}() }()
s.isStop = true s.isStop = true
@ -210,6 +189,15 @@ func (s *TunnelServer) CheckArgs() (err error) {
err = fmt.Errorf("remote required") err = fmt.Errorf("remote required")
return return
} }
if *s.cfg.Jumper != "" {
var j jumper.Jumper
j, err = jumper.New(*s.cfg.Jumper, time.Millisecond*time.Duration(*s.cfg.Timeout))
if err != nil {
err = fmt.Errorf("parse jumper fail, err %s", err)
return
}
s.jumper = &j
}
return return
} }
@ -301,11 +289,26 @@ func (s *TunnelServer) GetOutConn(typ uint8) (outConn net.Conn, ID string, err e
return return
} }
func (s *TunnelServer) GetConn() (conn net.Conn, err error) { func (s *TunnelServer) GetConn() (conn net.Conn, err error) {
var _conn tls.Conn var dconn net.Conn
_conn, err = utils.TlsConnectHost(*s.cfg.Parent, *s.cfg.Timeout, s.cfg.CertBytes, s.cfg.KeyBytes, nil) if s.jumper == nil {
var _conn tls.Conn
_conn, err = utils.TlsConnectHost(*s.cfg.Parent, *s.cfg.Timeout, s.cfg.CertBytes, s.cfg.KeyBytes, nil)
if err == nil {
dconn = net.Conn(&_conn)
}
} else {
conf, err := utils.TlsConfig(s.cfg.CertBytes, s.cfg.KeyBytes, nil)
if err != nil {
return nil, err
}
var _c net.Conn
_c, err = s.jumper.Dial(*s.cfg.Parent, time.Millisecond*time.Duration(*s.cfg.Timeout))
if err == nil {
dconn = net.Conn(tls.Client(_c, conf))
}
}
if err == nil { if err == nil {
conn = net.Conn(&_conn) sess, e := smux.Client(dconn, &smux.Config{
c, e := smux.Client(conn, &smux.Config{
AcceptBacklog: 256, AcceptBacklog: 256,
EnableKeepAlive: true, EnableKeepAlive: true,
KeepAliveInterval: 9 * time.Second, KeepAliveInterval: 9 * time.Second,
@ -316,14 +319,30 @@ func (s *TunnelServer) GetConn() (conn net.Conn, err error) {
if e != nil { if e != nil {
s.log.Printf("new mux client conn error,ERR:%s", e) s.log.Printf("new mux client conn error,ERR:%s", e)
err = e err = e
dconn.Close()
return return
} }
conn, e = c.OpenStream() conn, e = sess.OpenStream()
if e != nil { if e != nil {
s.log.Printf("mux client conn open stream error,ERR:%s", e) s.log.Printf("mux client conn open stream error,ERR:%s", e)
err = e err = e
dconn.Close()
return return
} }
go func() {
defer func() {
_ = recover()
}()
timer := time.NewTicker(time.Second * 3)
for {
<-timer.C
if sess.NumStreams() == 0 {
sess.Close()
timer.Stop()
return
}
}
}()
} }
return return
} }

View File

@ -73,7 +73,7 @@ func (s *UDP) StopService() {
if e != nil { if e != nil {
s.log.Printf("stop udp service crashed,%s", e) s.log.Printf("stop udp service crashed,%s", e)
} else { } else {
s.log.Printf("service udp stoped") s.log.Printf("service udp stopped")
} }
}() }()
s.isStop = true s.isStop = true

View File

@ -73,7 +73,7 @@ func CreateSignCert(rootCa *x509.Certificate, rootKey *rsa.PrivateKey, domainOrI
buf := x509.MarshalPKCS1PrivateKey(priKey) buf := x509.MarshalPKCS1PrivateKey(priKey)
keyPem := &pem.Block{ keyPem := &pem.Block{
Type: "PRIVATE KEY", Type: "RSA PRIVATE KEY",
Bytes: buf, Bytes: buf,
} }
keyBytes = pem.EncodeToMemory(keyPem) keyBytes = pem.EncodeToMemory(keyPem)
@ -109,7 +109,7 @@ func CreateCa(organization string, expireDays int) (certBytes []byte, keyBytes [
NotAfter: time.Now().Add(time.Hour * 24 * time.Duration(expireDays)), NotAfter: time.Now().Add(time.Hour * 24 * time.Duration(expireDays)),
KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign, KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign,
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}, ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth, x509.ExtKeyUsageClientAuth},
BasicConstraintsValid: true, BasicConstraintsValid: true,
IsCA: true, IsCA: true,
} }

View File

@ -12,8 +12,8 @@ import (
) )
//Confg defaults //Confg defaults
const DefaultIterations = 2048 const DefaultIterations = 1024
const DefaultKeySize = 32 //256bits const DefaultKeySize = 24 //256bits
var DefaultHashFunc = sha256.New var DefaultHashFunc = sha256.New
var DefaultSalt = []byte(` var DefaultSalt = []byte(`
(;QUHj.BQ?RXzYSO]ifkXp/G!kFmWyXyEV6Nt!d|@bo+N$L9+<d$|g6e26T} (;QUHj.BQ?RXzYSO]ifkXp/G!kFmWyXyEV6Nt!d|@bo+N$L9+<d$|g6e26T}

View File

@ -17,12 +17,12 @@ import (
"net" "net"
"net/http" "net/http"
"os" "os"
"os/exec"
"github.com/snail007/goproxy/services/kcpcfg" "github.com/snail007/goproxy/services/kcpcfg"
"golang.org/x/crypto/pbkdf2" "golang.org/x/crypto/pbkdf2"
"context"
"strconv" "strconv"
"strings" "strings"
"time" "time"
@ -108,6 +108,9 @@ func TlsConnect(host string, port, timeout int, certBytes, keyBytes, caCertBytes
} }
return *tls.Client(_conn, conf), err return *tls.Client(_conn, conf), err
} }
func TlsConfig(certBytes, keyBytes, caCertBytes []byte) (conf *tls.Config, err error) {
return getRequestTlsConfig(certBytes, keyBytes, caCertBytes)
}
func getRequestTlsConfig(certBytes, keyBytes, caCertBytes []byte) (conf *tls.Config, err error) { func getRequestTlsConfig(certBytes, keyBytes, caCertBytes []byte) (conf *tls.Config, err error) {
var cert tls.Certificate var cert tls.Certificate
@ -209,100 +212,13 @@ func CloseConn(conn *net.Conn) {
(*conn).Close() (*conn).Close()
} }
} }
func Keygen() (err error) {
CList := []string{"AD", "AE", "AF", "AG", "AI", "AL", "AM", "AO", "AR", "AT", "AU", "AZ", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BJ", "BL", "BM", "BN", "BO", "BR", "BS", "BW", "BY", "BZ", "CA", "CF", "CG", "CH", "CK", "CL", "CM", "CN", "CO", "CR", "CS", "CU", "CY", "CZ", "DE", "DJ", "DK", "DO", "DZ", "EC", "EE", "EG", "ES", "ET", "FI", "FJ", "FR", "GA", "GB", "GD", "GE", "GF", "GH", "GI", "GM", "GN", "GR", "GT", "GU", "GY", "HK", "HN", "HT", "HU", "ID", "IE", "IL", "IN", "IQ", "IR", "IS", "IT", "JM", "JO", "JP", "KE", "KG", "KH", "KP", "KR", "KT", "KW", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "LY", "MA", "MC", "MD", "MG", "ML", "MM", "MN", "MO", "MS", "MT", "MU", "MV", "MW", "MX", "MY", "MZ", "NA", "NE", "NG", "NI", "NL", "NO", "NP", "NR", "NZ", "OM", "PA", "PE", "PF", "PG", "PH", "PK", "PL", "PR", "PT", "PY", "QA", "RO", "RU", "SA", "SB", "SC", "SD", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "SO", "SR", "ST", "SV", "SY", "SZ", "TD", "TG", "TH", "TJ", "TM", "TN", "TO", "TR", "TT", "TW", "TZ", "UA", "UG", "US", "UY", "UZ", "VC", "VE", "VN", "YE", "YU", "ZA", "ZM", "ZR", "ZW"}
domainSubfixList := []string{".com", ".edu", ".gov", ".int", ".mil", ".net", ".org", ".biz", ".info", ".pro", ".name", ".museum", ".coop", ".aero", ".xxx", ".idv", ".ac", ".ad", ".ae", ".af", ".ag", ".ai", ".al", ".am", ".an", ".ao", ".aq", ".ar", ".as", ".at", ".au", ".aw", ".az", ".ba", ".bb", ".bd", ".be", ".bf", ".bg", ".bh", ".bi", ".bj", ".bm", ".bn", ".bo", ".br", ".bs", ".bt", ".bv", ".bw", ".by", ".bz", ".ca", ".cc", ".cd", ".cf", ".cg", ".ch", ".ci", ".ck", ".cl", ".cm", ".cn", ".co", ".cr", ".cu", ".cv", ".cx", ".cy", ".cz", ".de", ".dj", ".dk", ".dm", ".do", ".dz", ".ec", ".ee", ".eg", ".eh", ".er", ".es", ".et", ".eu", ".fi", ".fj", ".fk", ".fm", ".fo", ".fr", ".ga", ".gd", ".ge", ".gf", ".gg", ".gh", ".gi", ".gl", ".gm", ".gn", ".gp", ".gq", ".gr", ".gs", ".gt", ".gu", ".gw", ".gy", ".hk", ".hm", ".hn", ".hr", ".ht", ".hu", ".id", ".ie", ".il", ".im", ".in", ".io", ".iq", ".ir", ".is", ".it", ".je", ".jm", ".jo", ".jp", ".ke", ".kg", ".kh", ".ki", ".km", ".kn", ".kp", ".kr", ".kw", ".ky", ".kz", ".la", ".lb", ".lc", ".li", ".lk", ".lr", ".ls", ".lt", ".lu", ".lv", ".ly", ".ma", ".mc", ".md", ".mg", ".mh", ".mk", ".ml", ".mm", ".mn", ".mo", ".mp", ".mq", ".mr", ".ms", ".mt", ".mu", ".mv", ".mw", ".mx", ".my", ".mz", ".na", ".nc", ".ne", ".nf", ".ng", ".ni", ".nl", ".no", ".np", ".nr", ".nu", ".nz", ".om", ".pa", ".pe", ".pf", ".pg", ".ph", ".pk", ".pl", ".pm", ".pn", ".pr", ".ps", ".pt", ".pw", ".py", ".qa", ".re", ".ro", ".ru", ".rw", ".sa", ".sb", ".sc", ".sd", ".se", ".sg", ".sh", ".si", ".sj", ".sk", ".sl", ".sm", ".sn", ".so", ".sr", ".st", ".sv", ".sy", ".sz", ".tc", ".td", ".tf", ".tg", ".th", ".tj", ".tk", ".tl", ".tm", ".tn", ".to", ".tp", ".tr", ".tt", ".tv", ".tw", ".tz", ".ua", ".ug", ".uk", ".um", ".us", ".uy", ".uz", ".va", ".vc", ".ve", ".vg", ".vi", ".vn", ".vu", ".wf", ".ws", ".ye", ".yt", ".yu", ".yr", ".za", ".zm", ".zw"}
C := CList[int(RandInt(4))%len(CList)]
ST := RandString(int(RandInt(4) % 10))
O := RandString(int(RandInt(4) % 10))
CN := strings.ToLower(RandString(int(RandInt(4)%10)) + domainSubfixList[int(RandInt(4))%len(domainSubfixList)])
//log.Printf("C: %s, ST: %s, O: %s, CN: %s", C, ST, O, CN)
var out []byte
if len(os.Args) == 3 && os.Args[2] == "ca" {
cmd := exec.Command("sh", "-c", "openssl genrsa -out ca.key 2048")
out, err = cmd.CombinedOutput()
if err != nil {
logger.Printf("err:%s", err)
return
}
fmt.Println(string(out))
cmdStr := fmt.Sprintf("openssl req -new -key ca.key -x509 -days 36500 -out ca.crt -subj /C=%s/ST=%s/O=%s/CN=%s", C, ST, O, "*."+CN) var allInterfaceAddrCache []net.IP
cmd = exec.Command("sh", "-c", cmdStr)
out, err = cmd.CombinedOutput()
if err != nil {
logger.Printf("err:%s", err)
return
}
fmt.Println(string(out))
} else if len(os.Args) == 5 && os.Args[2] == "ca" && os.Args[3] != "" && os.Args[4] != "" {
certBytes, _ := ioutil.ReadFile("ca.crt")
block, _ := pem.Decode(certBytes)
if block == nil || certBytes == nil {
panic("failed to parse ca certificate PEM")
}
x509Cert, _ := x509.ParseCertificate(block.Bytes)
if x509Cert == nil {
panic("failed to parse block")
}
name := os.Args[3]
days := os.Args[4]
cmd := exec.Command("sh", "-c", "openssl genrsa -out "+name+".key 2048")
out, err = cmd.CombinedOutput()
if err != nil {
logger.Printf("err:%s", err)
return
}
fmt.Println(string(out))
cmdStr := fmt.Sprintf("openssl req -new -key %s.key -out %s.csr -subj /C=%s/ST=%s/O=%s/CN=%s", name, name, C, ST, O, CN)
fmt.Printf("%s", cmdStr)
cmd = exec.Command("sh", "-c", cmdStr)
out, err = cmd.CombinedOutput()
if err != nil {
logger.Printf("err:%s", err)
return
}
fmt.Println(string(out))
cmdStr = fmt.Sprintf("openssl x509 -req -days %s -in %s.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out %s.crt", days, name, name)
fmt.Printf("%s", cmdStr)
cmd = exec.Command("sh", "-c", cmdStr)
out, err = cmd.CombinedOutput()
if err != nil {
logger.Printf("err:%s", err)
return
}
fmt.Println(string(out))
} else if len(os.Args) == 3 && os.Args[2] == "usage" {
fmt.Println(`proxy keygen //generate proxy.crt and proxy.key
proxy keygen ca //generate ca.crt and ca.key
proxy keygen ca client0 30 //generate client0.crt client0.key and use ca.crt sign it with 30 days
`)
} else if len(os.Args) == 2 {
cmd := exec.Command("sh", "-c", "openssl genrsa -out proxy.key 2048")
out, err = cmd.CombinedOutput()
if err != nil {
logger.Printf("err:%s", err)
return
}
fmt.Println(string(out))
cmdStr := fmt.Sprintf("openssl req -new -key proxy.key -x509 -days 36500 -out proxy.crt -subj /C=%s/ST=%s/O=%s/CN=%s", C, ST, O, CN)
cmd = exec.Command("sh", "-c", cmdStr)
out, err = cmd.CombinedOutput()
if err != nil {
logger.Printf("err:%s", err)
return
}
fmt.Println(string(out))
}
return
}
func GetAllInterfaceAddr() ([]net.IP, error) { func GetAllInterfaceAddr() ([]net.IP, error) {
if allInterfaceAddrCache != nil {
return allInterfaceAddrCache, nil
}
ifaces, err := net.Interfaces() ifaces, err := net.Interfaces()
if err != nil { if err != nil {
return nil, err return nil, err
@ -343,6 +259,7 @@ func GetAllInterfaceAddr() ([]net.IP, error) {
return nil, fmt.Errorf("no address Found, net.InterfaceAddrs: %v", addresses) return nil, fmt.Errorf("no address Found, net.InterfaceAddrs: %v", addresses)
} }
//only need first //only need first
allInterfaceAddrCache = addresses
return addresses, nil return addresses, nil
} }
func UDPPacket(srcAddr string, packet []byte) []byte { func UDPPacket(srcAddr string, packet []byte) []byte {
@ -590,7 +507,7 @@ func IsIternalIP(domainOrIP string, always bool) bool {
} }
if isDomain { if isDomain {
outIPs, err = net.LookupIP(domainOrIP) outIPs, err = MyLookupIP(domainOrIP)
} else { } else {
outIPs = []net.IP{net.ParseIP(domainOrIP)} outIPs = []net.IP{net.ParseIP(domainOrIP)}
} }
@ -725,3 +642,25 @@ func InsertProxyHeaders(head []byte, headers string) []byte {
// } // }
// return // return
// } // }
/*
net.LookupIP may cause deadlock in windows
https://github.com/golang/go/issues/24178
*/
func MyLookupIP(host string) ([]net.IP, error) {
ctx, cancel := context.WithTimeout(context.Background(), time.Second*time.Duration(3))
defer func() {
cancel()
//ctx.Done()
}()
addrs, err := net.DefaultResolver.LookupIPAddr(ctx, host)
if err != nil {
return nil, err
}
ips := make([]net.IP, len(addrs))
for i, ia := range addrs {
ips[i] = ia.IP
}
return ips, nil
}

100
utils/jumper/jumper.go Normal file
View File

@ -0,0 +1,100 @@
package jumper
import (
"bytes"
"encoding/base64"
"fmt"
"net"
"net/url"
"time"
"golang.org/x/net/proxy"
)
type Jumper struct {
proxyURL *url.URL
timeout time.Duration
}
type socks5Dialer struct {
timeout time.Duration
}
func (s socks5Dialer) Dial(network, addr string) (net.Conn, error) {
return net.DialTimeout(network, addr, s.timeout)
}
func New(proxyURL string, timeout time.Duration) (j Jumper, err error) {
u, err := url.Parse(proxyURL)
if err != nil {
return
}
j = Jumper{
proxyURL: u,
timeout: timeout,
}
return
}
func (j *Jumper) Dial(address string, timeout time.Duration) (conn net.Conn, err error) {
switch j.proxyURL.Scheme {
case "https":
return j.dialHTTPS(address, timeout)
case "socks5":
return j.dialSOCKS5(address, timeout)
default:
return nil, fmt.Errorf("unkown scheme of %s", j.proxyURL.String())
}
}
func (j *Jumper) dialHTTPS(address string, timeout time.Duration) (conn net.Conn, err error) {
conn, err = net.DialTimeout("tcp", j.proxyURL.Host, timeout)
if err != nil {
return
}
pb := new(bytes.Buffer)
pb.Write([]byte(fmt.Sprintf("CONNECT %s HTTP/1.1\r\n", address)))
pb.WriteString("Proxy-Connection: Keep-Alive\r\n")
if j.proxyURL.User != nil {
p, _ := j.proxyURL.User.Password()
u := fmt.Sprintf("%s:%s", j.proxyURL.User.Username(), p)
pb.Write([]byte(fmt.Sprintf("Proxy-Authorization: Basic %s\r\n", base64.StdEncoding.EncodeToString([]byte(u)))))
}
pb.Write([]byte("\r\n"))
_, err = conn.Write(pb.Bytes())
if err != nil {
conn.Close()
conn = nil
err = fmt.Errorf("error connecting to proxy: %s", err)
return
}
reply := make([]byte, 1024)
conn.SetDeadline(time.Now().Add(timeout))
n, err := conn.Read(reply)
conn.SetDeadline(time.Time{})
if err != nil {
err = fmt.Errorf("error read reply from proxy: %s", err)
conn.Close()
conn = nil
return
}
if bytes.Index(reply[:n], []byte("200")) == -1 {
err = fmt.Errorf("error greeting to proxy, response: %s", string(reply[:n]))
conn.Close()
conn = nil
return
}
return
}
func (j *Jumper) dialSOCKS5(address string, timeout time.Duration) (conn net.Conn, err error) {
auth := &proxy.Auth{}
if j.proxyURL.User != nil {
auth.User = j.proxyURL.User.Username()
auth.Password, _ = j.proxyURL.User.Password()
} else {
auth = nil
}
dialSocksProxy, err := proxy.SOCKS5("tcp", j.proxyURL.Host, auth, socks5Dialer{timeout: timeout})
if err != nil {
err = fmt.Errorf("error connecting to proxy: %s", err)
return
}
return dialSocksProxy.Dial("tcp", address)
}

View File

@ -33,7 +33,7 @@ type ClientConn struct {
timeout time.Duration timeout time.Duration
addr string addr string
network string network string
udpAddr string UDPAddr string
} }
// SOCKS5 returns a Dialer that makes SOCKSv5 connections to the given address // SOCKS5 returns a Dialer that makes SOCKSv5 connections to the given address
@ -72,7 +72,7 @@ func (s *ClientConn) Handshake() error {
if err != nil { if err != nil {
return errors.New("proxy: failed to parse port number: " + portStr) return errors.New("proxy: failed to parse port number: " + portStr)
} }
if port < 1 || port > 0xffff { if s.network == "tcp" && (port < 1 || port > 0xffff) {
return errors.New("proxy: port number out of range: " + portStr) return errors.New("proxy: port number out of range: " + portStr)
} }
@ -168,14 +168,14 @@ func (s *ClientConn) Handshake() error {
} }
p := binary.BigEndian.Uint16([]byte{buf[0], buf[1]}) p := binary.BigEndian.Uint16([]byte{buf[0], buf[1]})
//log.Printf("%v", p) //log.Printf("%v", p)
s.udpAddr = net.JoinHostPort(ipStr, fmt.Sprintf("%d", p)) s.UDPAddr = net.JoinHostPort(ipStr, fmt.Sprintf("%d", p))
//log.Printf("%v", s.udpAddr) //log.Printf("%v", s.udpAddr)
(*s.conn).SetDeadline(time.Time{}) (*s.conn).SetDeadline(time.Time{})
return nil return nil
} }
func (s *ClientConn) SendUDP(data []byte, addr string) (respData []byte, err error) { func (s *ClientConn) SendUDP(data []byte, addr string) (respData []byte, err error) {
c, err := net.DialTimeout("udp", s.udpAddr, s.timeout) c, err := net.DialTimeout("udp", s.UDPAddr, s.timeout)
if err != nil { if err != nil {
return return
} }

View File

@ -2,10 +2,11 @@ package socks
import ( import (
"fmt" "fmt"
"github.com/snail007/goproxy/utils"
"net" "net"
"strings" "strings"
"time" "time"
"github.com/snail007/goproxy/utils"
) )
const ( const (
@ -54,26 +55,27 @@ type ServerConn struct {
methods []uint8 methods []uint8
method uint8 method uint8
//request //request
cmd uint8 cmd uint8
reserve uint8 reserve uint8
addressType uint8 addressType uint8
dstAddr string dstAddr string
dstPort string dstPort string
dstHost string dstHost string
udpAddress string UDPConnListener *net.UDPConn
enableUDP bool
udpIP string
} }
func NewServerConn(conn *net.Conn, timeout time.Duration, auth *utils.BasicAuth, udpAddress string, header []byte) *ServerConn { func NewServerConn(conn *net.Conn, timeout time.Duration, auth *utils.BasicAuth, enableUDP bool, udpHost string, header []byte) *ServerConn {
if udpAddress == "" {
udpAddress = "0.0.0.0:16666"
}
s := &ServerConn{ s := &ServerConn{
conn: conn, conn: conn,
timeout: timeout, timeout: timeout,
auth: auth, auth: auth,
header: header, header: header,
ver: VERSION_V5, ver: VERSION_V5,
udpAddress: udpAddress, enableUDP: enableUDP,
udpIP: udpHost,
} }
return s return s
@ -84,6 +86,12 @@ func (s *ServerConn) Close() {
func (s *ServerConn) AuthData() Auth { func (s *ServerConn) AuthData() Auth {
return Auth{s.user, s.password} return Auth{s.user, s.password}
} }
func (s *ServerConn) IsUDP() bool {
return s.cmd == CMD_ASSOCIATE
}
func (s *ServerConn) IsTCP() bool {
return s.cmd == CMD_CONNECT
}
func (s *ServerConn) Method() uint8 { func (s *ServerConn) Method() uint8 {
return s.method return s.method
} }
@ -205,11 +213,29 @@ func (s *ServerConn) Handshake() (err error) {
return return
} }
case CMD_ASSOCIATE: case CMD_ASSOCIATE:
err = request.UDPReply(REP_SUCCESS, s.udpAddress) if !s.enableUDP {
request.UDPReply(REP_UNKNOWN, "0.0.0.0:0")
if err != nil {
err = fmt.Errorf("UDPReply REP_UNKNOWN to %s fail,ERR: %s", remoteAddr, err)
return
}
err = fmt.Errorf("cmd associate not supported, form: %s", remoteAddr)
return
}
a, _ := net.ResolveUDPAddr("udp", ":0")
s.UDPConnListener, err = net.ListenUDP("udp", a)
if err != nil {
request.UDPReply(REP_UNKNOWN, "0.0.0.0:0")
err = fmt.Errorf("udp bind fail,ERR: %s , for %s", err, remoteAddr)
return
}
_, port, _ := net.SplitHostPort(s.UDPConnListener.LocalAddr().String())
err = request.UDPReply(REP_SUCCESS, net.JoinHostPort(s.udpIP, port))
if err != nil { if err != nil {
err = fmt.Errorf("UDPReply REP_SUCCESS to %s fail,ERR: %s", remoteAddr, err) err = fmt.Errorf("UDPReply REP_SUCCESS to %s fail,ERR: %s", remoteAddr, err)
return return
} }
} }
//fill socks info //fill socks info

View File

@ -33,15 +33,11 @@ type Checker struct {
log *logger.Logger log *logger.Logger
} }
type CheckerItem struct { type CheckerItem struct {
IsHTTPS bool
Method string
URL string
Domain string Domain string
Host string Address string
Data []byte
SuccessCount uint SuccessCount uint
FailCount uint FailCount uint
Key string Lasttime int64
} }
//NewChecker args: //NewChecker args:
@ -101,17 +97,23 @@ func (c *Checker) start() {
//log.Printf("check %s", item.Host) //log.Printf("check %s", item.Host)
var conn net.Conn var conn net.Conn
var err error var err error
conn, err = ConnectHost(item.Host, c.timeout) var now = time.Now().Unix()
conn, err = ConnectHost(item.Address, c.timeout)
if err == nil { if err == nil {
conn.SetDeadline(time.Now().Add(time.Millisecond)) conn.SetDeadline(time.Now().Add(time.Millisecond))
conn.Close() conn.Close()
} }
if now-item.Lasttime > 1800 {
item.FailCount = 0
item.SuccessCount = 0
}
if err != nil { if err != nil {
item.FailCount = item.FailCount + 1 item.FailCount = item.FailCount + 1
} else { } else {
item.SuccessCount = item.SuccessCount + 1 item.SuccessCount = item.SuccessCount + 1
} }
c.data.Set(item.Host, item) item.Lasttime = now
c.data.Set(item.Domain, item)
} }
}(v.(CheckerItem)) }(v.(CheckerItem))
} }
@ -124,32 +126,37 @@ func (c *Checker) start() {
} }
func (c *Checker) isNeedCheck(item CheckerItem) bool { func (c *Checker) isNeedCheck(item CheckerItem) bool {
var minCount uint = 5 var minCount uint = 5
if (item.SuccessCount >= minCount && item.SuccessCount > item.FailCount) || var now = time.Now().Unix()
(item.FailCount >= minCount && item.SuccessCount > item.FailCount) || if (item.SuccessCount >= minCount && item.SuccessCount > item.FailCount && now-item.Lasttime < 1800) ||
c.domainIsInMap(item.Host, false) || (item.FailCount >= minCount && item.SuccessCount > item.FailCount && now-item.Lasttime < 1800) ||
c.domainIsInMap(item.Host, true) { c.domainIsInMap(item.Domain, false) ||
c.domainIsInMap(item.Domain, true) {
return false return false
} }
return true return true
} }
func (c *Checker) IsBlocked(address string) (blocked bool, failN, successN uint) { func (c *Checker) IsBlocked(domain string) (blocked, isInMap bool, failN, successN uint) {
if c.domainIsInMap(address, true) { h, _, _ := net.SplitHostPort(domain)
//log.Printf("%s in blocked ? true", address) if h != "" {
return true, 0, 0 domain = h
} }
if c.domainIsInMap(address, false) { if c.domainIsInMap(domain, true) {
//log.Printf("%s in blocked ? true", address)
return true, true, 0, 0
}
if c.domainIsInMap(domain, false) {
//log.Printf("%s in direct ? true", address) //log.Printf("%s in direct ? true", address)
return false, 0, 0 return false, true, 0, 0
} }
_item, ok := c.data.Get(address) _item, ok := c.data.Get(domain)
if !ok { if !ok {
//log.Printf("%s not in map, blocked true", address) //log.Printf("%s not in map, blocked true", address)
return true, 0, 0 return true, false, 0, 0
} }
item := _item.(CheckerItem) item := _item.(CheckerItem)
return item.FailCount >= item.SuccessCount, item.FailCount, item.SuccessCount return (item.FailCount >= item.SuccessCount) && (time.Now().Unix()-item.Lasttime < 1800), true, item.FailCount, item.SuccessCount
} }
func (c *Checker) domainIsInMap(address string, blockedMap bool) bool { func (c *Checker) domainIsInMap(address string, blockedMap bool) bool {
u, err := url.Parse("http://" + address) u, err := url.Parse("http://" + address)
@ -174,16 +181,20 @@ func (c *Checker) domainIsInMap(address string, blockedMap bool) bool {
} }
return false return false
} }
func (c *Checker) Add(key, address string) { func (c *Checker) Add(domain, address string) {
if c.domainIsInMap(key, false) || c.domainIsInMap(key, true) { h, _, _ := net.SplitHostPort(domain)
if h != "" {
domain = h
}
if c.domainIsInMap(domain, false) || c.domainIsInMap(domain, true) {
return return
} }
var item CheckerItem var item CheckerItem
item = CheckerItem{ item = CheckerItem{
Host: address, Domain: domain,
Key: key, Address: address,
} }
c.data.SetIfAbsent(item.Host, item) c.data.SetIfAbsent(item.Domain, item)
} }
type BasicAuth struct { type BasicAuth struct {
@ -329,6 +340,7 @@ type HTTPRequest struct {
isBasicAuth bool isBasicAuth bool
basicAuth *BasicAuth basicAuth *BasicAuth
log *logger.Logger log *logger.Logger
IsSNI bool
} }
func NewHTTPRequest(inConn *net.Conn, bufSize int, isBasicAuth bool, basicAuth *BasicAuth, log *logger.Logger, header ...[]byte) (req HTTPRequest, err error) { func NewHTTPRequest(inConn *net.Conn, bufSize int, isBasicAuth bool, basicAuth *BasicAuth, log *logger.Logger, header ...[]byte) (req HTTPRequest, err error) {
@ -360,6 +372,7 @@ func NewHTTPRequest(inConn *net.Conn, bufSize int, isBasicAuth bool, basicAuth *
//sni success //sni success
req.Method = "SNI" req.Method = "SNI"
req.hostOrURL = "https://" + serverName + ":443" req.hostOrURL = "https://" + serverName + ":443"
req.IsSNI = true
} else { } else {
//sni fail , try http //sni fail , try http
index := bytes.IndexByte(req.HeadBuf, '\n') index := bytes.IndexByte(req.HeadBuf, '\n')