Skip to content

Commit

Permalink
Merge branch 'release/1.1.0'
Browse files Browse the repository at this point in the history
  • Loading branch information
mingcheng committed Jul 15, 2022
2 parents 7bdbf07 + d13ba77 commit 6c37893
Show file tree
Hide file tree
Showing 23 changed files with 761 additions and 597 deletions.
6 changes: 3 additions & 3 deletions .drone.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
# Author: Ming Cheng<mingcheng@outlook.com>
#
# Created Date: Monday, March 9th 2020, 5:11:52 pm
# Last Modified: Wednesday, July 6th 2022, 5:27:14 pm
# Last Modified: Friday, July 15th 2022, 5:38:32 pm
#
# http://www.opensource.org/licenses/MIT
###
Expand All @@ -21,7 +21,7 @@ steps:
- name: docker-sock
path: /var/run/docker.sock
commands:
- go build ./cmd/socks5lb
- make build
- ./socks5lb -h

- name: publish-to-ghcr
Expand All @@ -46,7 +46,7 @@ steps:
dockerfile: Dockerfile
tags:
- latest
- 1.0.0
- 1.1.0

volumes:
- name: docker-sock
Expand Down
1 change: 1 addition & 0 deletions .env
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
CGO_ENABLED=0
2 changes: 1 addition & 1 deletion .gitlab-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ compile:
image: golang:1.18
stage: build
script:
- go build ./cmd/socks5lb
- make build
- ./socks5lb -h
before_script:
- export GOPROXY="https://goproxy.cn"
Expand Down
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ ENV BUILD_DIR ${GOPATH}/src/${PACKAGE}
# Build
COPY . ${BUILD_DIR}
WORKDIR ${BUILD_DIR}
RUN go build ./cmd/socks5lb && mv ./socks5lb /usr/bin/socks5lb
RUN make build && mv ./socks5lb /usr/bin/socks5lb

# Stage2
FROM debian:bullseye
Expand Down
38 changes: 38 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
#https://gqlxj1987.github.io/2018/08/14/good-makefile-golang/
include .env

PROJECT=socks5lb
VERSION=$(shell date +%Y%m%d)
COMMIT_HASH=$(shell git rev-parse --short HEAD)
SRC=./cmd/$(PROJECT)
BINARY=$(PROJECT)
GO=$(shell which go)
GO_FLAGS=-ldflags="\
-X 'github.com/mingcheng/socks5lb.Version=$(VERSION)' \
-X 'github.com/mingcheng/socks5lb.BuildCommit=$(COMMIT_HASH)' \
-X 'github.com/mingcheng/socks5lb.BuildDate=$(shell date)'"



# Make is verbose in Linux. Make it silent.
MAKEFLAGS += --silent

all: build

build: $(SRC)
@$(GO) build $(GO_FLAGS) -o ${BINARY} $(SRC)

test:
@go test -v ./...

docker_image_build:
@docker-compose build

docker_image_push: docker_image_build
@docker-compose push

clean:
@$(GO) clean ./...
@rm $(BINARY)

.PHONY: install test clean docker_image_build docker_image_push
107 changes: 92 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,22 +1,25 @@
# socks5lb 非常简单的 Socks5 Proxy 负载均衡

## 更新记录

- `20220706` 完成针对 Linux 的透明网关功能
- `20220620` 完成基本功能
# socks5lb,简单的 Socks5 代理负载均衡

![socks5lb](./asserts/socks5lb.png)

我们在科学使用网络的时候经常会碰到 Socks5 Proxy 无法联通的情况,这有可能是因为网络或者线路的调整和波动,这时候往往需要我们自己手工的切换节点,非常的麻烦而且会中断网络请求
有时候我们在使用 Socks5 Proxy 无法联通的情况,这有可能是因为网络或者线路的调整和波动,这时候往往需要我们自己手工的切换节点,非常的麻烦

这个工具就是为了解决上述问题而编写的,它简单的说就是个针对 Socks5 Proxy 的前置负载均衡,能够提供经过检验的稳定可靠的 Socks Proxy 节点,如果是针对 Linux 系统下同时能够提供透明代理以及针对 Socks5
这个工具就是为了解决上述问题而编写的,它简单的说就是个针对 Socks5 Proxy 的前置负载均衡,能够提供经过检验的稳定可靠的 Socks Proxy 节点。

如果是针对 Linux 系统下同时能够提供透明代理以及针对 Socks5
协议的转换,而且方便搭配 ipset 以及 iptables 使用。

目前实现的部分特性有:

- 能够提供 Socks5 Proxy 的负载均衡(轮询机制)同时提供健康检查;
- 针对 Linux 提供[透明代理](https://www.kernel.org/doc/Documentation/networking/tproxy.txt)以及 Socks5 的协议转换;
- 使用 Golang 编写部署和配置方便。
- 使用 Golang 编写,跨平台部署(例如部署到各种路由器上)和配置方便。

## 更新记录

- `20220716` 修复部分链接的性能问题,增加 HTTP 管理接口
- `20220706` 完成针对 Linux 的透明网关功能
- `20220620` 完成基本功能

## 编译

Expand All @@ -27,8 +30,13 @@
首先是针对 socks5lb 的基本配置,例如以下的配置配置了三个 Socks5 Proxy 同时暴露到本地的 1080 端口,针对 Linux 的透明代理暴露在 8848 端口。

```yaml
socks5_listen: ":1080"
tproxy_listen: ":8848"
server:
http:
addr: ":8080"
socks5:
addr: ":1080"
tproxy:
addr: ":8848"
backends:
- addr: 192.168.100.254:1086
check_config:
Expand All @@ -49,8 +57,8 @@ backends:
#### 环境变量
- `SELECT_TIME_INTERVAL` 自动切换代理的时间,单位为秒(默认300秒,五分钟)
- `CHECK_TIME_INTERVAL` 健康检查的轮询时间,单位为秒(默认一分钟)
- `SELECT_TIME_INTERVAL` 自动切换代理的时间,单位为秒(默认 300 秒,五分钟)
- `CHECK_TIME_INTERVAL` 健康检查的轮询时间,单位为秒(默认一分钟、60 秒
- `DEBUG` 是否打开 debug 模式

### 部署
Expand All @@ -61,7 +69,7 @@ backends:
version: "3"
services:
socks5lb:
image: ghcr.io/mingcheng/socks5lb
image: ghcr.io/mingcheng/socks5lb:latest
restart: always
dns:
- 8.8.8.8
Expand All @@ -82,11 +90,80 @@ iptables -t nat -I PREROUTING -p tcp -m set --match-set redrock dst -j REDIRECT
iptables -t nat -I OUTPUT -p tcp -m set --match-set redrock dst -j REDIRECT --to-ports 8848
```

### Web 管理

自 1.1.0 版本实现了个简单的 Web 管理接口,用于动态的添加和删除代理服务器的配置,简单的说明如下:

#### GET `/version`

目前运行的版本、编译时间以及运行时间

#### GET `/api/all`

显示目前配置的代理服务器列表,如果加 `healthy=true` 参数,则只显示目前健康的代理节点

#### PUT `/api/add`

增加代理,这里说明下 Put 的 Body 为 JSON 数组,同时配置和代理的配置对应,例如

```json
[
{
"addr": "192.168.1.254:1086",
"check_config": {
"check_url": "https://www.taobao.com/robots.txt"
}
},
{
"addr": "192.168.1.254:1087",
"check_config": {
"initial_alive": true
}
}
]
```

然后返回的是已经加入的代理节点数量(整型数)。如果已经有配置的代理节点,则需要先删除以后再加入。

示例 CURL 如下:

```
curl -X "PUT" "<your-address>/api/add" \
-H 'Content-Type: text/plain; charset=utf-8' \
-d $'[
{
"addr": "192.168.1.1:1086",
"check_config": {
"check_url": "https://www.taobao.com/robots.txt"
}
}
]'
```

#### DELETE `/api/delete`

删除指定的代理地址,参数 `addr` 指定参数名称。

```
curl -X "DELETE" "http://localhost:8080/api/delete?addr=192.168.1.1:1086"
```

## 常见问题

### 如果我不想针对某个节点健康检查呢(强制使用)?

那么可以配置节点 `check_url` 参数为空,然后默认 `initial_alive``true` 即可,例如:

```yaml
backends:
- addr: 127.0.0.1:10860
check_config:
initial_alive: true
```
### 在其他非 Linux 系统下可以使用 tproxy_listen 这个配置吗?
不好意思,透明代理只针对 Linux 平台。
不好意思,透明代理只针对 Linux 平台,所以如果是非 Linux 平台,请留空对应的配置
### 有没有类似功能的项目?
Expand Down
51 changes: 29 additions & 22 deletions backend.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,28 +11,27 @@
package socks5lb

import (
log "github.com/sirupsen/logrus"
"golang.org/x/net/context"
"net"
"net/http"
"sync"
"time"

"github.com/txthinking/socks5"
)

type BackendCheckConfig struct {
CheckURL string `yaml:"check_url"`
InitialAlive bool `yaml:"initial_alive"`
Timeout uint `yaml:"timeout"`
CheckURL string `yaml:"check_url" json:"check_url"`
InitialAlive bool `yaml:"initial_alive" json:"initial_alive"`
Timeout uint `yaml:"timeout" json:"timeout"`
}

type Backend struct {
Addr string `yaml:"addr"`
Socks5UserName string `yaml:"username"`
Socks5Password string `yaml:"password"`
CheckConfig *BackendCheckConfig `yaml:"check_config"`
Addr string `yaml:"addr" json:"addr" binding:"required"`
UserName string `yaml:"username" json:"username"`
Password string `yaml:"password" json:"password"`
CheckConfig BackendCheckConfig `yaml:"check_config" json:"check_config"`

mux sync.RWMutex
alive bool
}

Expand All @@ -42,25 +41,30 @@ func (b *Backend) Alive() bool {
}

// Check function to check the node healthy by given url
func (b *Backend) Check() error {
b.mux.Lock()
defer b.mux.Unlock()

func (b *Backend) Check() (err error) {
if url := b.CheckConfig.CheckURL; url != "" {
client, err := b.httpProxyClient()
if err != nil {
return err
var (
client *http.Client
resp *http.Response
)

if client, err = b.httpProxyClient(); err != nil {
return
}

resp, err := client.Get(url)
resp, err = client.Get(url)
if err != nil || (resp != nil && resp.StatusCode != http.StatusOK) {
log.Error(err)
b.alive = false
return err
} else {
b.alive = true
}

return
}

b.alive = true
return nil
b.alive = b.CheckConfig.InitialAlive
return
}

// httpProxyClient to create http client with socks5 proxy
Expand All @@ -80,10 +84,12 @@ func (b *Backend) httpProxyClient() (*http.Client, error) {
}, nil
}

// socks5Client to create http client with socks5 proxy
func (b *Backend) socks5Client(timeout int) (*socks5.Client, error) {
return socks5.NewClient(b.Addr, b.Socks5UserName, b.Socks5Password, timeout, timeout)
return socks5.NewClient(string(b.Addr), b.UserName, b.Password, timeout, timeout)
}

// Socks5Conn to create a connection by specific params
func (b *Backend) Socks5Conn(network, addr string, timeout int) (cc net.Conn, err error) {
client, err := b.socks5Client(timeout)
if err != nil {
Expand All @@ -93,11 +99,12 @@ func (b *Backend) Socks5Conn(network, addr string, timeout int) (cc net.Conn, er
return client.Dial(network, addr)
}

// NewBackend creates a new Backend instance
func NewBackend(addr string, config BackendCheckConfig) (backend *Backend) {
backend = &Backend{
Addr: addr,
alive: config.InitialAlive,
CheckConfig: &config,
CheckConfig: config,
}

return
Expand Down
14 changes: 6 additions & 8 deletions cmd/socks5lb/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
* Author: Ming Cheng<mingcheng@outlook.com>
*
* Created Date: Wednesday, June 22nd 2022, 12:39:47 pm
* Last Modified: Thursday, July 7th 2022, 6:29:42 pm
* Last Modified: Friday, July 15th 2022, 5:53:09 pm
*
* http://www.opensource.org/licenses/MIT
*/
Expand All @@ -23,8 +23,6 @@ import (
"os"
)

const AppName = "socks5lb"

var (
config *socks5lb.Configure
err error
Expand All @@ -33,15 +31,14 @@ var (

func init() {
log.SetOutput(os.Stdout)
log.SetLevel(log.ErrorLevel)

isDebug := socks5lb.GetEnv("DEBUG", "")
if isDebug != "" {
if socks5lb.DebugMode {
log.SetLevel(log.TraceLevel)
} else {
log.SetLevel(log.InfoLevel)
log.Debug("debug mode is On, its makess more noise on terminal")
}

flag.StringVar(&cfgPath, "c", "/etc/"+AppName+".yml", "configure file cfgPath")
flag.StringVar(&cfgPath, "c", "/etc/"+socks5lb.AppName+".yml", "configure file cfgPath")
}

// NewConfig returns a new Config instance
Expand All @@ -62,6 +59,7 @@ func NewConfig(path string) (config *socks5lb.Configure, err error) {
}

func main() {
log.Infof("%s v%s(%s), build on %s", socks5lb.AppName, socks5lb.Version, socks5lb.BuildCommit, socks5lb.BuildDate)
flag.Parse()

// read the config if err != nil
Expand Down
Loading

0 comments on commit 6c37893

Please sign in to comment.