Merge branch 'dev'
This commit is contained in:
@ -1,4 +1,12 @@
|
|||||||
proxy更新日志
|
proxy更新日志
|
||||||
|
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代理智能判断,更加精确。
|
||||||
|
|||||||
89
Dockerfile
89
Dockerfile
@ -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}
|
||||||
69
README.md
69
README.md
@ -6,7 +6,18 @@ Proxy is a high performance HTTP, HTTPS, HTTPS, websocket, TCP, UDP, Socks5 prox
|
|||||||
|
|
||||||
[](https://github.com/snail007/goproxy/) []() [](https://github.com/snail007/goproxy/releases) [](https://github.com/snail007/goproxy/releases)
|
[](https://github.com/snail007/goproxy/) []() [](https://github.com/snail007/goproxy/releases) [](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
|
||||||
|
|||||||
42
README_ZH.md
42
README_ZH.md
@ -7,7 +7,17 @@ Proxy是golang实现的高性能http,https,websocket,tcp,udp,socks5代理服务
|
|||||||
|
|
||||||
[](https://github.com/snail007/goproxy/) []() [](https://github.com/snail007/goproxy/releases) [](https://github.com/snail007/goproxy/releases)
|
[](https://github.com/snail007/goproxy/) []() [](https://github.com/snail007/goproxy/releases) [](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.3手册,其他版本手册请点击[这里](docs/old-release.md)查看.
|
||||||
|
|
||||||
|
|
||||||
### 怎么找到组织?
|
### 怎么找到组织?
|
||||||
@ -149,7 +159,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.3/proxy-linux-amd64.tar.gz
|
||||||
```
|
```
|
||||||
#### **2.下载自动安装脚本**
|
#### **2.下载自动安装脚本**
|
||||||
```shell
|
```shell
|
||||||
@ -160,12 +170,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 +185,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. 查看日志:
|
||||||
```
|
```
|
||||||
@ -689,7 +699,14 @@ server连接到bridge的时候,如果同时有多个client连接到同一个brid
|
|||||||
`./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 +854,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 +1126,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 +1145,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"/>
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -198,8 +198,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()
|
||||||
@ -388,6 +386,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 +422,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
|
||||||
|
|||||||
@ -1,5 +1,7 @@
|
|||||||
# Old Versions of Proxy
|
# Old Versions of Proxy
|
||||||
|
|
||||||
|
- [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)
|
||||||
|
|||||||
@ -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.3/proxy-linux-amd64.tar.gz
|
||||||
|
|
||||||
# #install proxy
|
# #install proxy
|
||||||
tar zxvf proxy-linux-amd64.tar.gz
|
tar zxvf proxy-linux-amd64.tar.gz
|
||||||
|
|||||||
@ -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
|
|
||||||
2
main.go
2
main.go
@ -9,7 +9,7 @@ import (
|
|||||||
"github.com/snail007/goproxy/services"
|
"github.com/snail007/goproxy/services"
|
||||||
)
|
)
|
||||||
|
|
||||||
const APP_VERSION = "5.1"
|
const APP_VERSION = "5.3"
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
err := initConfig()
|
err := initConfig()
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
VER="5.1"
|
VER="5.3"
|
||||||
RELEASE="release-${VER}"
|
RELEASE="release-${VER}"
|
||||||
rm -rf .cert
|
rm -rf .cert
|
||||||
mkdir .cert
|
mkdir .cert
|
||||||
|
|||||||
@ -1,5 +1,13 @@
|
|||||||
SDK更新日志
|
SDK更新日志
|
||||||
|
|
||||||
|
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代理返回不合适的头部,导致浏览器不会弹框,个别代理插件无法认证的问题.
|
||||||
2.内网穿透切换smux到yamux.
|
2.内网穿透切换smux到yamux.
|
||||||
|
|||||||
@ -25,7 +25,7 @@ proxy使用gombile实现了一份go代码编译为android和ios平台下面可
|
|||||||
#### 1.导入包
|
#### 1.导入包
|
||||||
|
|
||||||
```java
|
```java
|
||||||
import snail007.proxy.Porxy
|
import snail007.proxy.Proxy
|
||||||
```
|
```
|
||||||
|
|
||||||
#### 2.启动一个服务
|
#### 2.启动一个服务
|
||||||
|
|||||||
@ -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)
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -23,12 +23,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 +57,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{}
|
||||||
@ -194,8 +213,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 +356,18 @@ 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 *logfile != "" {
|
||||||
if e != nil {
|
f, e := os.OpenFile(*logfile, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0600)
|
||||||
log.Fatal(e)
|
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
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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."
|
||||||
|
|||||||
@ -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
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -73,7 +73,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,7 +182,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
|
||||||
|
|||||||
@ -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
321
services/socks/udp.go
Normal 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
306
services/sps/socksudp.go
Normal 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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -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
|
||||||
}
|
}
|
||||||
|
|||||||
@ -74,7 +74,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
|
||||||
|
|||||||
@ -70,7 +70,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
|
||||||
|
|||||||
@ -70,7 +70,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
|
||||||
|
|||||||
@ -183,7 +183,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
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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,
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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}
|
||||||
|
|||||||
@ -17,7 +17,6 @@ import (
|
|||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
|
||||||
|
|
||||||
"github.com/snail007/goproxy/services/kcpcfg"
|
"github.com/snail007/goproxy/services/kcpcfg"
|
||||||
|
|
||||||
@ -26,10 +25,12 @@ import (
|
|||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
"context"
|
||||||
|
|
||||||
"github.com/snail007/goproxy/utils/id"
|
"github.com/snail007/goproxy/utils/id"
|
||||||
|
|
||||||
kcp "github.com/xtaci/kcp-go"
|
kcp "github.com/xtaci/kcp-go"
|
||||||
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func IoBind(dst io.ReadWriteCloser, src io.ReadWriteCloser, fn func(err interface{}), log *logger.Logger) {
|
func IoBind(dst io.ReadWriteCloser, src io.ReadWriteCloser, fn func(err interface{}), log *logger.Logger) {
|
||||||
@ -209,98 +210,6 @@ 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)
|
|
||||||
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) {
|
||||||
|
|
||||||
ifaces, err := net.Interfaces()
|
ifaces, err := net.Interfaces()
|
||||||
@ -590,7 +499,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 +634,26 @@ 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
|
||||||
|
}
|
||||||
|
|||||||
@ -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
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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')
|
||||||
|
|||||||
Reference in New Issue
Block a user