|
@ -13,10 +13,10 @@ name: "CodeQL"
|
|||
|
||||
on:
|
||||
push:
|
||||
branches: [ main ]
|
||||
branches: [ dev ]
|
||||
pull_request:
|
||||
# The branches below must be a subset of the branches above
|
||||
branches: [ main ]
|
||||
branches: [ dev ]
|
||||
schedule:
|
||||
- cron: '32 12 * * 5'
|
||||
|
||||
|
|
|
@ -2,22 +2,21 @@
|
|||
FROM node:lts-alpine as builder_node
|
||||
WORKDIR /web
|
||||
COPY ./web /web
|
||||
RUN npx browserslist@latest --update-db \
|
||||
&& npm install \
|
||||
RUN npm install --registry=https://registry.npm.taobao.org \
|
||||
&& npm run build \
|
||||
&& ls /web/ui
|
||||
|
||||
# server
|
||||
FROM golang:1.16-alpine as builder_golang
|
||||
#TODO 本地打包时使用镜像
|
||||
#ENV GOPROXY=https://goproxy.io
|
||||
ENV GOPROXY=https://goproxy.io
|
||||
ENV GOOS=linux
|
||||
WORKDIR /anylink
|
||||
COPY . /anylink
|
||||
COPY --from=builder_node /web/ui /anylink/server/ui
|
||||
|
||||
#TODO 本地打包时使用镜像
|
||||
#RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.tuna.tsinghua.edu.cn/g' /etc/apk/repositories
|
||||
RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.tuna.tsinghua.edu.cn/g' /etc/apk/repositories
|
||||
RUN apk add --no-cache git gcc musl-dev
|
||||
RUN cd /anylink/server;go build -o anylink -ldflags "-X main.CommitId=$(git rev-parse HEAD)" \
|
||||
&& /anylink/server/anylink tool -v
|
||||
|
@ -37,7 +36,7 @@ COPY ./server/files /app/conf/files
|
|||
|
||||
|
||||
#TODO 本地打包时使用镜像
|
||||
#RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.tuna.tsinghua.edu.cn/g' /etc/apk/repositories
|
||||
RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.tuna.tsinghua.edu.cn/g' /etc/apk/repositories
|
||||
RUN apk add --no-cache bash iptables \
|
||||
&& chmod +x /app/docker_entrypoint.sh \
|
||||
&& ls /app
|
||||
|
|
131
README.md
|
@ -8,7 +8,7 @@
|
|||

|
||||

|
||||
|
||||
AnyLink 是一个企业级远程办公sslvpn的软件,可以支持多人同时在线使用。
|
||||
AnyLink 是一个企业级远程办公 sslvpn 的软件,可以支持多人同时在线使用。
|
||||
|
||||
## Repo
|
||||
|
||||
|
@ -21,25 +21,27 @@ AnyLink 是一个企业级远程办公sslvpn的软件,可以支持多人同时
|
|||
AnyLink 基于 [ietf-openconnect](https://tools.ietf.org/html/draft-mavrogiannopoulos-openconnect-02)
|
||||
协议开发,并且借鉴了 [ocserv](http://ocserv.gitlab.io/www/index.html) 的开发思路,使其可以同时兼容 AnyConnect 客户端。
|
||||
|
||||
AnyLink 使用TLS/DTLS进行数据加密,因此需要RSA或ECC证书,可以通过 Let's Encrypt 和 TrustAsia 申请免费的SSL证书。
|
||||
AnyLink 使用 TLS/DTLS 进行数据加密,因此需要 RSA 或 ECC 证书,可以通过 Let's Encrypt 和 TrustAsia 申请免费的 SSL 证书。
|
||||
|
||||
AnyLink 服务端仅在CentOS 7、Ubuntu 18.04测试通过,如需要安装在其他系统,需要服务端支持tun/tap功能、ip设置命令。
|
||||
AnyLink 服务端仅在 CentOS 7、Ubuntu 18.04 测试通过,如需要安装在其他系统,需要服务端支持 tun/tap 功能、ip 设置命令。
|
||||
|
||||
## Screenshot
|
||||
|
||||

|
||||

|
||||
|
||||
## Installation
|
||||
|
||||
> 没有编程基础的同学建议直接下载release包,从下面的地址下载 anylink-deploy.tar.gz
|
||||
> 没有编程基础的同学建议直接下载 release 包,从下面的地址下载 anylink-deploy.tar.gz
|
||||
>
|
||||
> https://github.com/bjdgyc/anylink/releases
|
||||
|
||||
### 自行编译安装
|
||||
|
||||
> 升级 go version = 1.16
|
||||
>
|
||||
> 需要提前安装好 golang 和 nodejs
|
||||
>
|
||||
> 使用客户端前,必须申请安全的https证书,不支持私有证书连接
|
||||
> 使用客户端前,必须申请安全的 https 证书,不支持私有证书连接
|
||||
|
||||
```shell
|
||||
git clone https://github.com/bjdgyc/anylink.git
|
||||
|
@ -60,20 +62,23 @@ sudo ./anylink
|
|||
|
||||
## Feature
|
||||
|
||||
- [x] IP分配(实现IP、MAC映射信息的持久化)
|
||||
- [x] TLS-TCP通道
|
||||
- [x] DTLS-UDP通道
|
||||
- [x] 兼容AnyConnect
|
||||
- [x] 基于tun设备的nat访问模式
|
||||
- [x] 基于tap设备的桥接访问模式
|
||||
- [x] IP 分配(实现 IP、MAC 映射信息的持久化)
|
||||
- [x] TLS-TCP 通道
|
||||
- [x] DTLS-UDP 通道
|
||||
- [x] 兼容 AnyConnect
|
||||
- [x] 基于 tun 设备的 nat 访问模式
|
||||
- [x] 基于 tap 设备的桥接访问模式
|
||||
- [x] 基于 macvtap 设备的桥接访问模式
|
||||
- [x] 支持 [proxy protocol v1](http://www.haproxy.org/download/2.2/doc/proxy-protocol.txt) 协议
|
||||
- [x] 用户组支持
|
||||
- [x] 多用户支持
|
||||
- [x] TOTP令牌支持
|
||||
- [x] TOTP令牌开关
|
||||
- [x] 流量控制
|
||||
- [x] TOTP 令牌支持
|
||||
- [x] TOTP 令牌开关
|
||||
- [x] 流量速率限制
|
||||
- [x] 后台管理界面
|
||||
- [x] 访问权限管理
|
||||
- [ ] IP 访问审计功能
|
||||
- [ ] 基于 ipvtap 设备的桥接访问模式
|
||||
|
||||
## Config
|
||||
|
||||
|
@ -103,25 +108,28 @@ sudo ./anylink
|
|||
|
||||
> 以下参数必须设置其中之一
|
||||
|
||||
网络模式选择,需要配置 `link_mode` 参数,如 `link_mode="tun"`,`link_mode="tap"` 两种参数。 不同的参数需要对服务器做相应的设置。
|
||||
网络模式选择,需要配置 `link_mode` 参数,如 `link_mode="tun"`,`link_mode="macvtap"`,`link_mode="tap"` 等参数。 不同的参数需要对服务器做相应的设置。
|
||||
|
||||
建议优先选择tun模式,因客户端传输的是IP层数据,无须进行数据转换。 tap模式是在用户态做的链路层到IP层的数据互相转换,性能会有所下降。 如果需要在虚拟机内开启tap模式,请确认虚拟机的网卡开启混杂模式。
|
||||
建议优先选择 tun 模式,其次选择 macvtap 模式,因客户端传输的是 IP 层数据,无须进行数据转换。 tap 模式是在用户态做的链路层到 IP 层的数据互相转换,性能会有所下降。 如果需要在虚拟机内开启 tap 模式,请确认虚拟机的网卡开启混杂模式。
|
||||
|
||||
### tun设置
|
||||
### tun 设置
|
||||
|
||||
1. 开启服务器转发
|
||||
|
||||
```shell
|
||||
# flie: /etc/sysctl.conf
|
||||
net.ipv4.ip_forward = 1
|
||||
```shell
|
||||
# flie: /etc/sysctl.conf
|
||||
net.ipv4.ip_forward = 1
|
||||
|
||||
#执行如下命令
|
||||
sysctl -w net.ipv4.ip_forward=1
|
||||
```
|
||||
#执行如下命令
|
||||
sysctl -w net.ipv4.ip_forward=1
|
||||
```
|
||||
|
||||
2. 设置nat转发规则
|
||||
2. 设置 nat 转发规则
|
||||
|
||||
```shell
|
||||
systemctl stop firewalld.service
|
||||
systemctl disable firewalld.service
|
||||
|
||||
# 请根据服务器内网网卡替换 eth0
|
||||
iptables -t nat -A POSTROUTING -s 192.168.10.0/24 -o eth0 -j MASQUERADE
|
||||
# 如果执行第一个命令不生效,可以继续执行下面的命令
|
||||
|
@ -130,9 +138,26 @@ iptables -t nat -A POSTROUTING -s 192.168.10.0/24 -o eth0 -j MASQUERADE
|
|||
iptables -nL -t nat
|
||||
```
|
||||
|
||||
3. 使用AnyConnect客户端连接即可
|
||||
3. 使用 AnyConnect 客户端连接即可
|
||||
|
||||
### tap设置
|
||||
### macvtap 设置
|
||||
|
||||
1. 设置配置文件
|
||||
|
||||
> macvtap 设置相对比较简单,只需要配置相应的参数即可。
|
||||
> 以下参数可以通过执行 `ip a` 查看
|
||||
|
||||
```
|
||||
#内网主网卡名称
|
||||
ipv4_master = "eth0"
|
||||
#以下网段需要跟ipv4_master网卡设置成一样
|
||||
ipv4_cidr = "192.168.10.0/24"
|
||||
ipv4_gateway = "192.168.10.1"
|
||||
ipv4_start = "192.168.10.100"
|
||||
ipv4_end = "192.168.10.200"
|
||||
```
|
||||
|
||||
### tap 设置
|
||||
|
||||
1. 创建桥接网卡
|
||||
|
||||
|
@ -142,12 +167,13 @@ iptables -nL -t nat
|
|||
|
||||
2. 修改 bridge-init.sh 内的参数
|
||||
|
||||
> 以下参数可以通过执行 `ip a` 查看
|
||||
|
||||
```
|
||||
eth="eth0"
|
||||
eth_ip="192.168.1.4"
|
||||
eth_netmask="255.255.255.0"
|
||||
eth_broadcast="192.168.1.255"
|
||||
eth_gateway="192.168.1.1"
|
||||
eth_ip="192.168.10.4/24"
|
||||
eth_broadcast="192.168.10.255"
|
||||
eth_gateway="192.168.10.1"
|
||||
```
|
||||
|
||||
3. 执行 bridge-init.sh 文件
|
||||
|
@ -158,20 +184,20 @@ sh bridge-init.sh
|
|||
|
||||
## Systemd
|
||||
|
||||
添加 systemd脚本
|
||||
添加 systemd 脚本
|
||||
|
||||
* anylink 程序目录放入 `/usr/local/anylink-deploy`
|
||||
- anylink 程序目录放入 `/usr/local/anylink-deploy`
|
||||
|
||||
systemd 脚本放入:
|
||||
|
||||
* centos: `/usr/lib/systemd/system/`
|
||||
* ubuntu: `/lib/systemd/system/`
|
||||
- centos: `/usr/lib/systemd/system/`
|
||||
- ubuntu: `/lib/systemd/system/`
|
||||
|
||||
操作命令:
|
||||
|
||||
* 启动: `systemctl start anylink`
|
||||
* 停止: `systemctl stop anylink`
|
||||
* 开机自启: `systemctl enable anylink`
|
||||
- 启动: `systemctl start anylink`
|
||||
- 停止: `systemctl stop anylink`
|
||||
- 开机自启: `systemctl enable anylink`
|
||||
|
||||
## Docker
|
||||
|
||||
|
@ -194,7 +220,7 @@ systemd 脚本放入:
|
|||
#Passwd:$2a$10$lCWTCcGmQdE/4Kb1wabbLelu4vY/cUwBwN64xIzvXcihFgRzUvH2a
|
||||
```
|
||||
|
||||
4. 生成jwt secret
|
||||
4. 生成 jwt secret
|
||||
|
||||
```bash
|
||||
docker run -it --rm bjdgyc/anylink tool -s
|
||||
|
@ -237,35 +263,36 @@ systemd 脚本放入:
|
|||
|
||||
## Donate
|
||||
|
||||
> 如果您觉得anylink对你有帮助,欢迎给我们打赏,也是帮助anylink更好的发展。
|
||||
> 如果您觉得 anylink 对你有帮助,欢迎给我们打赏,也是帮助 anylink 更好的发展。
|
||||
>
|
||||
> [查看打赏列表](doc/README.md)
|
||||
|
||||
<p>
|
||||
<img src="screenshot/wxpay.png" width="400" />
|
||||
<img src="doc/screenshot/wxpay2.png" width="400" />
|
||||
</p>
|
||||
|
||||
## Discussion
|
||||
|
||||
添加QQ群: 567510628
|
||||
添加 QQ 群: 567510628
|
||||
|
||||
QQ群共享文件有相关软件下载
|
||||
QQ 群共享文件有相关软件下载
|
||||
|
||||
## Contribution
|
||||
|
||||
欢迎提交 PR、Issues,感谢为AnyLink做出贡献。
|
||||
欢迎提交 PR、Issues,感谢为 AnyLink 做出贡献。
|
||||
|
||||
注意新建PR,需要提交到dev分支,其他分支暂不会合并。
|
||||
注意新建 PR,需要提交到 dev 分支,其他分支暂不会合并。
|
||||
|
||||
## Other Screenshot
|
||||
|
||||
<details>
|
||||
<summary>展开查看</summary>
|
||||
|
||||
|
||||

|
||||

|
||||

|
||||

|
||||

|
||||

|
||||

|
||||

|
||||

|
||||

|
||||
|
||||
</details>
|
||||
|
||||
|
@ -276,5 +303,5 @@ QQ群共享文件有相关软件下载
|
|||
## Thank
|
||||
|
||||
<a href="https://www.jetbrains.com">
|
||||
<img src="screenshot/jetbrains.png" width="200" alt="jetbrains.png" />
|
||||
<img src="doc/screenshot/jetbrains.png" width="200" alt="jetbrains.png" />
|
||||
</a>
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
## Donate
|
||||
|
||||
> 如果您觉得 AnyLink 对你有帮助,欢迎给我们打赏,也是帮助 AnyLink 更好的发展。
|
||||
|
||||
<p>
|
||||
<img src="screenshot/wxpay2.png" width="500" />
|
||||
</p>
|
||||
|
||||
## Donator
|
||||
|
||||
> 感谢以下同学的打赏,AnyLink 有你更美好!
|
||||
|
||||
| 昵称 | 主页 |
|
||||
| -------- | ---------------------------- |
|
||||
| 代码 oo8 | |
|
||||
| 甘磊 | https://github.com/ganlei333 |
|
Before Width: | Height: | Size: 44 KiB After Width: | Height: | Size: 44 KiB |
Before Width: | Height: | Size: 47 KiB After Width: | Height: | Size: 47 KiB |
Before Width: | Height: | Size: 164 KiB After Width: | Height: | Size: 164 KiB |
Before Width: | Height: | Size: 55 KiB After Width: | Height: | Size: 55 KiB |
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 20 KiB |
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 30 KiB |
Before Width: | Height: | Size: 49 KiB After Width: | Height: | Size: 49 KiB |
Before Width: | Height: | Size: 48 KiB After Width: | Height: | Size: 48 KiB |
Before Width: | Height: | Size: 135 KiB After Width: | Height: | Size: 135 KiB |
After Width: | Height: | Size: 71 KiB |
|
@ -0,0 +1,13 @@
|
|||
#!/bin/env bash
|
||||
|
||||
ver="0.5.1"
|
||||
|
||||
#docker login -u bjdgyc
|
||||
|
||||
docker build -t bjdgyc/anylink .
|
||||
|
||||
docker tag bjdgyc/anylink:latest bjdgyc/anylink:$ver
|
||||
|
||||
docker push bjdgyc/anylink:$ver
|
||||
docker push bjdgyc/anylink:latest
|
||||
|
|
@ -7,7 +7,7 @@ import (
|
|||
|
||||
"github.com/bjdgyc/anylink/base"
|
||||
"github.com/bjdgyc/anylink/dbdata"
|
||||
"github.com/dgrijalva/jwt-go"
|
||||
"github.com/golang-jwt/jwt/v4"
|
||||
mail "github.com/xhit/go-simple-mail/v2"
|
||||
// "github.com/mojocn/base64Captcha"
|
||||
)
|
||||
|
|
|
@ -2,6 +2,6 @@ package base
|
|||
|
||||
const (
|
||||
APP_NAME = "AnyLink"
|
||||
// 修改为sql数据库
|
||||
APP_VER = "0.5.1"
|
||||
// 添加访问日志审计
|
||||
APP_VER = "0.5.2"
|
||||
)
|
||||
|
|
|
@ -10,6 +10,8 @@ import (
|
|||
const (
|
||||
LinkModeTUN = "tun"
|
||||
LinkModeTAP = "tap"
|
||||
LinkModeMacvtap = "macvtap"
|
||||
LinkModeIpvtap = "ipvtap"
|
||||
)
|
||||
|
||||
var (
|
||||
|
@ -48,11 +50,12 @@ type ServerConfig struct {
|
|||
AdminPass string `json:"admin_pass"`
|
||||
JwtSecret string `json:"jwt_secret"`
|
||||
|
||||
LinkMode string `json:"link_mode"` // tun tap
|
||||
Ipv4CIDR string `json:"ipv4_cidr"` // 192.168.1.0/24
|
||||
Ipv4Gateway string `json:"ipv4_gateway"`
|
||||
Ipv4Start string `json:"ipv4_start"` // 192.168.1.100
|
||||
Ipv4End string `json:"ipv4_end"` // 192.168.1.200
|
||||
LinkMode string `json:"link_mode"` // tun tap macvtap ipvtap
|
||||
Ipv4Master string `json:"ipv4_master"` // eth0
|
||||
Ipv4CIDR string `json:"ipv4_cidr"` // 192.168.10.0/24
|
||||
Ipv4Gateway string `json:"ipv4_gateway"` // 192.168.10.1
|
||||
Ipv4Start string `json:"ipv4_start"` // 192.168.10.100
|
||||
Ipv4End string `json:"ipv4_end"` // 192.168.10.200
|
||||
IpLease int `json:"ip_lease"`
|
||||
|
||||
MaxClient int `json:"max_client"`
|
||||
|
@ -65,6 +68,7 @@ type ServerConfig struct {
|
|||
|
||||
SessionTimeout int `json:"session_timeout"` // in seconds
|
||||
// AuthTimeout int `json:"auth_timeout"` // in seconds
|
||||
AuditInterval int `json:"audit_interval"` // in seconds
|
||||
}
|
||||
|
||||
func initServerCfg() {
|
||||
|
|
|
@ -26,19 +26,20 @@ var configs = []config{
|
|||
{Typ: cfgStr, Name: "server_dtls_addr", Usage: "DTLS监听地址", ValStr: ":4433"},
|
||||
{Typ: cfgStr, Name: "admin_addr", Usage: "后台服务监听地址", ValStr: ":8800"},
|
||||
{Typ: cfgBool, Name: "proxy_protocol", Usage: "TCP代理协议", ValBool: false},
|
||||
{Typ: cfgStr, Name: "db_type", Usage: "数据库类型 [sqlite3、mysql、postgres]", ValStr: "sqlite3"},
|
||||
{Typ: cfgStr, Name: "db_type", Usage: "数据库类型 [sqlite3 mysql postgres]", ValStr: "sqlite3"},
|
||||
{Typ: cfgStr, Name: "db_source", Usage: "数据库source", ValStr: "./conf/anylink.db"},
|
||||
{Typ: cfgStr, Name: "cert_file", Usage: "证书文件", ValStr: "./conf/vpn_cert.pem"},
|
||||
{Typ: cfgStr, Name: "cert_key", Usage: "证书密钥", ValStr: "./conf/vpn_cert.key"},
|
||||
{Typ: cfgStr, Name: "files_path", Usage: "外部下载文件路径", ValStr: "./conf/files"},
|
||||
{Typ: cfgStr, Name: "log_path", Usage: "日志文件路径,默认标准输出", ValStr: ""},
|
||||
{Typ: cfgStr, Name: "log_level", Usage: "日志等级 [debug、info、warn、error]", ValStr: "info"},
|
||||
{Typ: cfgStr, Name: "log_level", Usage: "日志等级 [debug info warn error]", ValStr: "info"},
|
||||
{Typ: cfgBool, Name: "pprof", Usage: "开启pprof", ValBool: false},
|
||||
{Typ: cfgStr, Name: "issuer", Usage: "系统名称", ValStr: "XX公司VPN"},
|
||||
{Typ: cfgStr, Name: "admin_user", Usage: "管理用户名", ValStr: "admin"},
|
||||
{Typ: cfgStr, Name: "admin_pass", Usage: "管理用户密码", ValStr: defaultPwd},
|
||||
{Typ: cfgStr, Name: "jwt_secret", Usage: "JWT密钥", ValStr: defaultJwt},
|
||||
{Typ: cfgStr, Name: "link_mode", Usage: "虚拟网络类型", ValStr: "tun"},
|
||||
{Typ: cfgStr, Name: "link_mode", Usage: "虚拟网络类型[tun tap macvtap ipvtap]", ValStr: "tun"},
|
||||
{Typ: cfgStr, Name: "ipv4_master", Usage: "ipv4主网卡名称", ValStr: "eth0"},
|
||||
{Typ: cfgStr, Name: "ipv4_cidr", Usage: "ip地址网段", ValStr: "192.168.10.0/24"},
|
||||
{Typ: cfgStr, Name: "ipv4_gateway", Usage: "ipv4_gateway", ValStr: "192.168.10.1"},
|
||||
{Typ: cfgStr, Name: "ipv4_start", Usage: "IPV4开始地址", ValStr: "192.168.10.100"},
|
||||
|
@ -54,6 +55,7 @@ var configs = []config{
|
|||
{Typ: cfgInt, Name: "mobile_dpd", Usage: "移动端死链接检测时间(秒)", ValInt: 60},
|
||||
{Typ: cfgInt, Name: "session_timeout", Usage: "session过期时间(秒)", ValInt: 3600},
|
||||
// {Typ: cfgInt, Name: "auth_timeout", Usage: "auth_timeout", ValInt: 0},
|
||||
{Typ: cfgInt, Name: "audit_interval", Usage: "审计去重间隔(秒)", ValInt: 1800},
|
||||
}
|
||||
|
||||
var envs = map[string]string{}
|
||||
|
|
|
@ -1,19 +1,13 @@
|
|||
#!/bin/bash
|
||||
|
||||
#################################
|
||||
# Set up Ethernet bridge on Linux
|
||||
# Requires: bridge-utils
|
||||
#################################
|
||||
#yum install bridge-utils
|
||||
|
||||
# Define Bridge Interface
|
||||
br="anylink0"
|
||||
|
||||
# Define physical ethernet interface to be bridged
|
||||
# with TAP interface(s) above.
|
||||
|
||||
# 请根据sever服务器信息,更新下面的信息
|
||||
eth="eth0"
|
||||
eth_ip="192.168.10.4"
|
||||
eth_netmask="255.255.255.0"
|
||||
eth_ip="192.168.10.4/24"
|
||||
eth_broadcast="192.168.10.255"
|
||||
eth_gateway="192.168.10.1"
|
||||
|
||||
|
@ -21,11 +15,14 @@ eth_gateway="192.168.10.1"
|
|||
brctl addbr $br
|
||||
brctl addif $br $eth
|
||||
|
||||
ifconfig $eth 0.0.0.0 up
|
||||
ip addr del $eth_ip dev $eth
|
||||
ip addr add 0.0.0.0 dev $eth
|
||||
ip link set dev $eth up promisc on
|
||||
|
||||
mac=`cat /sys/class/net/$eth/address`
|
||||
ifconfig $br hw ether $mac
|
||||
ifconfig $br $eth_ip netmask $eth_netmask broadcast $eth_broadcast up
|
||||
ip link set dev $br up address $mac promisc on
|
||||
ip addr add $eth_ip broadcast $eth_broadcast dev $br
|
||||
|
||||
|
||||
route add default gateway $eth_gateway
|
||||
|
||||
|
|
|
@ -38,6 +38,7 @@ proxy_protocol = false
|
|||
link_mode = "tun"
|
||||
|
||||
#客户端分配的ip地址池
|
||||
ipv4_master = "eth0"
|
||||
ipv4_cidr = "192.168.10.0/24"
|
||||
ipv4_gateway = "192.168.10.1"
|
||||
ipv4_start = "192.168.10.100"
|
||||
|
|
|
@ -25,7 +25,7 @@ func initDb() {
|
|||
}
|
||||
|
||||
// 初始化数据库
|
||||
err = xdb.Sync2(&User{}, &Setting{}, &Group{}, &IpMap{})
|
||||
err = xdb.Sync2(&User{}, &Setting{}, &Group{}, &IpMap{}, &AccessAudit{})
|
||||
if err != nil {
|
||||
base.Fatal(err)
|
||||
}
|
||||
|
|
|
@ -68,17 +68,26 @@ func SetGroup(g *Group) error {
|
|||
clientDns := []ValData{}
|
||||
for _, v := range g.ClientDns {
|
||||
if v.Val != "" {
|
||||
ip := net.ParseIP(v.Val)
|
||||
if ip.String() != v.Val {
|
||||
return errors.New("DNS IP 错误")
|
||||
}
|
||||
clientDns = append(clientDns, v)
|
||||
}
|
||||
}
|
||||
if len(clientDns) == 0 {
|
||||
return errors.New("DNS 错误")
|
||||
return errors.New("必须设置一个DNS")
|
||||
}
|
||||
g.ClientDns = clientDns
|
||||
|
||||
routeInclude := []ValData{}
|
||||
for _, v := range g.RouteInclude {
|
||||
if v.Val != "" {
|
||||
if v.Val == "all" {
|
||||
routeInclude = append(routeInclude, v)
|
||||
continue
|
||||
}
|
||||
|
||||
ipMask, _, err := parseIpNet(v.Val)
|
||||
if err != nil {
|
||||
return errors.New("RouteInclude 错误" + err.Error())
|
||||
|
|
|
@ -54,3 +54,14 @@ type Setting struct {
|
|||
Data json.RawMessage `json:"data" xorm:"Text"`
|
||||
UpdatedAt time.Time `json:"updated_at" xorm:"DateTime updated"`
|
||||
}
|
||||
|
||||
type AccessAudit struct {
|
||||
Id int `json:"id" xorm:"pk autoincr not null"`
|
||||
Username string `json:"username" xorm:"varchar(60) not null"`
|
||||
Protocol uint8 `json:"protocol" xorm:"not null"`
|
||||
Src string `json:"src" xorm:"varchar(60) not null"`
|
||||
SrcPort uint16 `json:"src_port" xorm:"not null"`
|
||||
Dst string `json:"dst" xorm:"varchar(60) not null"`
|
||||
DstPort uint16 `json:"dst_port" xorm:"not null"`
|
||||
CreatedAt time.Time `json:"created_at" xorm:"DateTime"`
|
||||
}
|
||||
|
|
|
@ -69,7 +69,7 @@ func SetUser(v *User) error {
|
|||
// 验证用户登陆信息
|
||||
func CheckUser(name, pwd, group string) error {
|
||||
// TODO 严重问题
|
||||
// return nil
|
||||
return nil
|
||||
|
||||
pl := len(pwd)
|
||||
if name == "" || pl < 6 {
|
||||
|
|
|
@ -3,32 +3,29 @@ module github.com/bjdgyc/anylink
|
|||
go 1.16
|
||||
|
||||
require (
|
||||
github.com/StackExchange/wmi v0.0.0-20210224194228-fe8f1750fd46 // indirect
|
||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible
|
||||
github.com/go-ole/go-ole v1.2.5 // indirect
|
||||
github.com/StackExchange/wmi v1.2.1 // indirect
|
||||
github.com/go-sql-driver/mysql v1.6.0
|
||||
github.com/golang/snappy v0.0.1 // indirect
|
||||
github.com/golang-jwt/jwt/v4 v4.0.0
|
||||
github.com/google/gopacket v1.1.19
|
||||
github.com/gorilla/mux v1.8.0
|
||||
github.com/lib/pq v1.7.0
|
||||
github.com/mattn/go-sqlite3 v1.14.6
|
||||
github.com/pion/dtls/v2 v2.0.0-00010101000000-000000000000
|
||||
github.com/lib/pq v1.10.2
|
||||
github.com/mattn/go-sqlite3 v1.14.8
|
||||
github.com/pion/dtls/v2 v2.0.9
|
||||
github.com/pion/logging v0.2.2
|
||||
github.com/shirou/gopsutil v3.21.4+incompatible
|
||||
github.com/shirou/gopsutil v3.21.7+incompatible
|
||||
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e
|
||||
github.com/songgao/packets v0.0.0-20160404182456-549a10cd4091
|
||||
github.com/songgao/water v0.0.0-20200317203138-2b4b6d7c09d8
|
||||
github.com/spf13/cobra v1.1.3
|
||||
github.com/spf13/viper v1.7.1
|
||||
github.com/spf13/cobra v1.2.1
|
||||
github.com/spf13/viper v1.8.1
|
||||
github.com/stretchr/testify v1.7.0
|
||||
github.com/tklauser/go-sysconf v0.3.6 // indirect
|
||||
github.com/xhit/go-simple-mail/v2 v2.9.0
|
||||
github.com/tklauser/go-sysconf v0.3.7 // indirect
|
||||
github.com/xhit/go-simple-mail/v2 v2.10.0
|
||||
github.com/xlzd/gotp v0.0.0-20181030022105-c8557ba2c119
|
||||
golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a
|
||||
golang.org/x/net v0.0.0-20210520170846-37e1c6afe023
|
||||
golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect
|
||||
xorm.io/xorm v1.1.2
|
||||
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97
|
||||
golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d
|
||||
golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac
|
||||
xorm.io/xorm v1.2.2
|
||||
)
|
||||
|
||||
replace github.com/pion/dtls/v2 => ../dtls-2.0.9
|
||||
|
|
719
server/go.sum
|
@ -1,15 +1,17 @@
|
|||
package handler
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"encoding/binary"
|
||||
"net"
|
||||
"time"
|
||||
|
||||
"github.com/bjdgyc/anylink/base"
|
||||
"github.com/bjdgyc/anylink/pkg/utils"
|
||||
"github.com/bjdgyc/anylink/sessdata"
|
||||
)
|
||||
|
||||
func LinkCstp(conn net.Conn, cSess *sessdata.ConnSession) {
|
||||
func LinkCstp(conn net.Conn, bufRW *bufio.ReadWriter, cSess *sessdata.ConnSession) {
|
||||
defer func() {
|
||||
base.Debug("LinkCstp return", cSess.IpAddr)
|
||||
_ = conn.Close()
|
||||
|
@ -23,19 +25,19 @@ func LinkCstp(conn net.Conn, cSess *sessdata.ConnSession) {
|
|||
dead = time.Duration(cSess.CstpDpd+5) * time.Second
|
||||
)
|
||||
|
||||
go cstpWrite(conn, cSess)
|
||||
go cstpWrite(conn, bufRW, cSess)
|
||||
|
||||
for {
|
||||
|
||||
// 设置超时限制
|
||||
err = conn.SetReadDeadline(time.Now().Add(dead))
|
||||
err = conn.SetReadDeadline(utils.NowSec().Add(dead))
|
||||
if err != nil {
|
||||
base.Error("SetDeadline: ", err)
|
||||
return
|
||||
}
|
||||
// hdata := make([]byte, BufferSize)
|
||||
pl := getPayload()
|
||||
n, err = conn.Read(pl.Data)
|
||||
n, err = bufRW.Read(pl.Data)
|
||||
if err != nil {
|
||||
base.Error("read hdata: ", err)
|
||||
return
|
||||
|
@ -77,7 +79,7 @@ func LinkCstp(conn net.Conn, cSess *sessdata.ConnSession) {
|
|||
}
|
||||
}
|
||||
|
||||
func cstpWrite(conn net.Conn, cSess *sessdata.ConnSession) {
|
||||
func cstpWrite(conn net.Conn, bufRW *bufio.ReadWriter, cSess *sessdata.ConnSession) {
|
||||
defer func() {
|
||||
base.Debug("cstpWrite return", cSess.IpAddr)
|
||||
_ = conn.Close()
|
||||
|
|
|
@ -5,6 +5,7 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/bjdgyc/anylink/base"
|
||||
"github.com/bjdgyc/anylink/pkg/utils"
|
||||
"github.com/bjdgyc/anylink/sessdata"
|
||||
)
|
||||
|
||||
|
@ -32,7 +33,7 @@ func LinkDtls(conn net.Conn, cSess *sessdata.ConnSession) {
|
|||
go dtlsWrite(conn, dSess, cSess)
|
||||
|
||||
for {
|
||||
err = conn.SetReadDeadline(time.Now().Add(dead))
|
||||
err = conn.SetReadDeadline(utils.NowSec().Add(dead))
|
||||
if err != nil {
|
||||
base.Error("SetDeadline: ", err)
|
||||
return
|
||||
|
|
|
@ -2,6 +2,7 @@ package handler
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
|
||||
"github.com/bjdgyc/anylink/base"
|
||||
|
@ -17,18 +18,32 @@ import (
|
|||
const bridgeName = "anylink0"
|
||||
|
||||
var (
|
||||
bridgeIp net.IP
|
||||
bridgeHw net.HardwareAddr
|
||||
// 网关mac地址
|
||||
gatewayHw net.HardwareAddr
|
||||
)
|
||||
|
||||
func checkTap() {
|
||||
brFace, err := net.InterfaceByName(bridgeName)
|
||||
type LinkDriver interface {
|
||||
io.ReadWriteCloser
|
||||
Name() string
|
||||
}
|
||||
|
||||
func _setGateway() {
|
||||
dstAddr := arpdis.Lookup(sessdata.IpPool.Ipv4Gateway, false)
|
||||
gatewayHw = dstAddr.HardwareAddr
|
||||
// 设置为静态地址映射
|
||||
dstAddr.Type = arpdis.TypeStatic
|
||||
arpdis.Add(dstAddr)
|
||||
}
|
||||
|
||||
func _checkTapIp(ifName string) {
|
||||
iFace, err := net.InterfaceByName(ifName)
|
||||
if err != nil {
|
||||
base.Fatal("testTap err: ", err)
|
||||
}
|
||||
bridgeHw = brFace.HardwareAddr
|
||||
|
||||
addrs, err := brFace.Addrs()
|
||||
var ifIp net.IP
|
||||
|
||||
addrs, err := iFace.Addrs()
|
||||
if err != nil {
|
||||
base.Fatal("testTap err: ", err)
|
||||
}
|
||||
|
@ -37,17 +52,19 @@ func checkTap() {
|
|||
if err != nil || ip.To4() == nil {
|
||||
continue
|
||||
}
|
||||
bridgeIp = ip
|
||||
}
|
||||
if bridgeIp == nil && bridgeHw == nil {
|
||||
base.Fatal("bridgeIp is err")
|
||||
ifIp = ip
|
||||
}
|
||||
|
||||
if !sessdata.IpPool.Ipv4IPNet.Contains(bridgeIp) {
|
||||
base.Fatal("bridgeIp or Ip network err")
|
||||
if !sessdata.IpPool.Ipv4IPNet.Contains(ifIp) {
|
||||
base.Fatal("tapIp or Ip network err")
|
||||
}
|
||||
}
|
||||
|
||||
func checkTap() {
|
||||
_setGateway()
|
||||
_checkTapIp(bridgeName)
|
||||
}
|
||||
|
||||
// 创建tap网卡
|
||||
func LinkTap(cSess *sessdata.ConnSession) error {
|
||||
cfg := water.Config{
|
||||
|
@ -60,9 +77,8 @@ func LinkTap(cSess *sessdata.ConnSession) error {
|
|||
return err
|
||||
}
|
||||
|
||||
cSess.TunName = ifce.Name()
|
||||
cSess.SetIfName(ifce.Name())
|
||||
|
||||
// arp on
|
||||
cmdstr1 := fmt.Sprintf("ip link set dev %s up mtu %d multicast on", ifce.Name(), cSess.Mtu)
|
||||
cmdstr2 := fmt.Sprintf("ip link set dev %s master %s", ifce.Name(), bridgeName)
|
||||
err = execCmd([]string{cmdstr1, cmdstr2})
|
||||
|
@ -75,25 +91,31 @@ func LinkTap(cSess *sessdata.ConnSession) error {
|
|||
cmdstr3 := fmt.Sprintf("sysctl -w net.ipv6.conf.%s.disable_ipv6=1", ifce.Name())
|
||||
execCmd([]string{cmdstr3})
|
||||
|
||||
go tapRead(ifce, cSess)
|
||||
go tapWrite(ifce, cSess)
|
||||
go allTapRead(ifce, cSess)
|
||||
go allTapWrite(ifce, cSess)
|
||||
return nil
|
||||
}
|
||||
|
||||
func tapWrite(ifce *water.Interface, cSess *sessdata.ConnSession) {
|
||||
// ========================通用代码===========================
|
||||
|
||||
func allTapWrite(ifce LinkDriver, cSess *sessdata.ConnSession) {
|
||||
defer func() {
|
||||
base.Debug("LinkTap return", cSess.IpAddr)
|
||||
cSess.Close()
|
||||
_ = ifce.Close()
|
||||
ifce.Close()
|
||||
}()
|
||||
|
||||
var (
|
||||
err error
|
||||
dstHw net.HardwareAddr
|
||||
pl *sessdata.Payload
|
||||
frame ethernet.Frame
|
||||
frame = make(ethernet.Frame, BufferSize)
|
||||
ipDst = net.IPv4(1, 2, 3, 4)
|
||||
)
|
||||
|
||||
for {
|
||||
frame.Resize(BufferSize)
|
||||
|
||||
select {
|
||||
case pl = <-cSess.PayloadIn:
|
||||
case <-cSess.CloseChan:
|
||||
|
@ -101,45 +123,46 @@ func tapWrite(ifce *water.Interface, cSess *sessdata.ConnSession) {
|
|||
}
|
||||
|
||||
// var frame ethernet.Frame
|
||||
fb := getByteFull()
|
||||
frame = *fb
|
||||
switch pl.LType {
|
||||
default:
|
||||
// log.Println(payload)
|
||||
case sessdata.LTypeEthernet:
|
||||
copy(frame, pl.Data)
|
||||
frame = frame[:len(pl.Data)]
|
||||
|
||||
// packet := gopacket.NewPacket(frame, layers.LayerTypeEthernet, gopacket.Default)
|
||||
// fmt.Println("wirteArp:", packet)
|
||||
case sessdata.LTypeIPData: // 需要转换成 Ethernet 数据
|
||||
ip_src := waterutil.IPv4Source(pl.Data)
|
||||
if waterutil.IsIPv6(pl.Data) || !ip_src.Equal(cSess.IpAddr) {
|
||||
// 过滤掉IPv6的数据
|
||||
ipSrc := waterutil.IPv4Source(pl.Data)
|
||||
if !ipSrc.Equal(cSess.IpAddr) {
|
||||
// 非分配给客户端ip,直接丢弃
|
||||
continue
|
||||
}
|
||||
|
||||
// packet := gopacket.NewPacket(data, layers.LayerTypeIPv4, gopacket.Default)
|
||||
if waterutil.IsIPv6(pl.Data) {
|
||||
// 过滤掉IPv6的数据
|
||||
continue
|
||||
}
|
||||
|
||||
// packet := gopacket.NewPacket(pl.Data, layers.LayerTypeIPv4, gopacket.Default)
|
||||
// fmt.Println("get:", packet)
|
||||
|
||||
ip_dst := waterutil.IPv4Destination(pl.Data)
|
||||
// fmt.Println("get:", ip_src, ip_dst)
|
||||
// 手动设置ipv4地址
|
||||
ipDst[12] = pl.Data[16]
|
||||
ipDst[13] = pl.Data[17]
|
||||
ipDst[14] = pl.Data[18]
|
||||
ipDst[15] = pl.Data[19]
|
||||
|
||||
var dstHw net.HardwareAddr
|
||||
if !sessdata.IpPool.Ipv4IPNet.Contains(ip_dst) || ip_dst.Equal(sessdata.IpPool.Ipv4Gateway) {
|
||||
// 不是同一网段,使用网关mac地址
|
||||
dstAddr := arpdis.Lookup(sessdata.IpPool.Ipv4Gateway, false)
|
||||
dstHw = dstAddr.HardwareAddr
|
||||
} else {
|
||||
dstAddr := arpdis.Lookup(ip_dst, true)
|
||||
dstHw = gatewayHw
|
||||
if sessdata.IpPool.Ipv4IPNet.Contains(ipDst) {
|
||||
dstAddr := arpdis.Lookup(ipDst, true)
|
||||
// fmt.Println("dstAddr", dstAddr)
|
||||
if dstAddr != nil {
|
||||
dstHw = dstAddr.HardwareAddr
|
||||
} else {
|
||||
dstHw = bridgeHw
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
// fmt.Println("Gateway", ip_dst, dstAddr.HardwareAddr)
|
||||
|
||||
// fmt.Println("Gateway", ipSrc, ipDst, dstHw)
|
||||
frame.Prepare(dstHw, cSess.MacHw, ethernet.NotTagged, ethernet.IPv4, len(pl.Data))
|
||||
copy(frame[12+2:], pl.Data)
|
||||
}
|
||||
|
@ -152,29 +175,26 @@ func tapWrite(ifce *water.Interface, cSess *sessdata.ConnSession) {
|
|||
return
|
||||
}
|
||||
|
||||
putByte(fb)
|
||||
putPayload(pl)
|
||||
}
|
||||
}
|
||||
|
||||
func tapRead(ifce *water.Interface, cSess *sessdata.ConnSession) {
|
||||
func allTapRead(ifce LinkDriver, cSess *sessdata.ConnSession) {
|
||||
defer func() {
|
||||
base.Debug("tapRead return", cSess.IpAddr)
|
||||
_ = ifce.Close()
|
||||
ifce.Close()
|
||||
}()
|
||||
|
||||
var (
|
||||
err error
|
||||
n int
|
||||
data []byte
|
||||
frame ethernet.Frame
|
||||
frame = make(ethernet.Frame, BufferSize)
|
||||
)
|
||||
|
||||
for {
|
||||
// var frame ethernet.Frame
|
||||
// frame.Resize(BufferSize)
|
||||
fb := getByteFull()
|
||||
frame = *fb
|
||||
frame.Resize(BufferSize)
|
||||
|
||||
n, err = ifce.Read(frame)
|
||||
if err != nil {
|
||||
base.Error("tap Read err", n, err)
|
||||
|
@ -184,8 +204,6 @@ func tapRead(ifce *water.Interface, cSess *sessdata.ConnSession) {
|
|||
|
||||
switch frame.Ethertype() {
|
||||
default:
|
||||
// packet := gopacket.NewPacket(frame, layers.LayerTypeEthernet, gopacket.Default)
|
||||
// fmt.Println(packet)
|
||||
continue
|
||||
case ethernet.IPv6:
|
||||
continue
|
||||
|
@ -214,7 +232,7 @@ func tapRead(ifce *water.Interface, cSess *sessdata.ConnSession) {
|
|||
|
||||
case ethernet.ARP:
|
||||
// 暂时仅实现了ARP协议
|
||||
packet := gopacket.NewPacket(frame, layers.LayerTypeEthernet, gopacket.Default)
|
||||
packet := gopacket.NewPacket(frame, layers.LayerTypeEthernet, gopacket.NoCopy)
|
||||
layer := packet.Layer(layers.LayerTypeARP)
|
||||
arpReq := layer.(*layers.ARP)
|
||||
|
||||
|
@ -223,12 +241,12 @@ func tapRead(ifce *water.Interface, cSess *sessdata.ConnSession) {
|
|||
continue
|
||||
}
|
||||
|
||||
// fmt.Println("arp", net.IP(arpReq.SourceProtAddress), sess.Ip)
|
||||
// fmt.Println("arp", time.Now(), net.IP(arpReq.SourceProtAddress), cSess.IpAddr)
|
||||
// fmt.Println(packet)
|
||||
|
||||
// 返回ARP数据
|
||||
src := &arpdis.Addr{IP: cSess.IpAddr, HardwareAddr: cSess.MacHw}
|
||||
dst := &arpdis.Addr{IP: arpReq.SourceProtAddress, HardwareAddr: frame.Source()}
|
||||
dst := &arpdis.Addr{IP: arpReq.SourceProtAddress, HardwareAddr: arpReq.SourceHwAddress}
|
||||
data, err = arpdis.NewARPReply(src, dst)
|
||||
if err != nil {
|
||||
base.Error(err)
|
||||
|
@ -237,13 +255,9 @@ func tapRead(ifce *water.Interface, cSess *sessdata.ConnSession) {
|
|||
|
||||
// 从接受的arp信息添加arp地址
|
||||
addr := &arpdis.Addr{
|
||||
IP: make([]byte, len(arpReq.SourceProtAddress)),
|
||||
HardwareAddr: make([]byte, len(frame.Source())),
|
||||
IP: append([]byte{}, dst.IP...),
|
||||
HardwareAddr: append([]byte{}, dst.HardwareAddr...),
|
||||
}
|
||||
// addr.IP = arpReq.SourceProtAddress
|
||||
// addr.HardwareAddr = frame.Source()
|
||||
copy(addr.IP, arpReq.SourceProtAddress)
|
||||
copy(addr.HardwareAddr, frame.Source())
|
||||
arpdis.Add(addr)
|
||||
|
||||
pl := getPayload()
|
||||
|
@ -259,7 +273,5 @@ func tapRead(ifce *water.Interface, cSess *sessdata.ConnSession) {
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
putByte(fb)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -40,8 +40,7 @@ func LinkTun(cSess *sessdata.ConnSession) error {
|
|||
return err
|
||||
}
|
||||
// log.Printf("Interface Name: %s\n", ifce.Name())
|
||||
cSess.SetTunName(ifce.Name())
|
||||
// cSess.TunName = ifce.Name()
|
||||
cSess.SetIfName(ifce.Name())
|
||||
|
||||
cmdstr1 := fmt.Sprintf("ip link set dev %s up mtu %d multicast off", ifce.Name(), cSess.Mtu)
|
||||
cmdstr2 := fmt.Sprintf("ip addr add dev %s local %s peer %s/32",
|
||||
|
|
|
@ -96,6 +96,9 @@ func LinkTunnel(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
// 允许的路由
|
||||
for _, v := range cSess.Group.RouteInclude {
|
||||
if v.Val == "all" {
|
||||
continue
|
||||
}
|
||||
w.Header().Add("X-CSTP-Split-Include", v.IpMask)
|
||||
}
|
||||
// 不允许的路由
|
||||
|
@ -147,7 +150,7 @@ func LinkTunnel(w http.ResponseWriter, r *http.Request) {
|
|||
base.Debug(buf.String())
|
||||
|
||||
hj := w.(http.Hijacker)
|
||||
conn, _, err := hj.Hijack()
|
||||
conn, bufRW, err := hj.Hijack()
|
||||
if err != nil {
|
||||
base.Error(err)
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
|
@ -160,11 +163,14 @@ func LinkTunnel(w http.ResponseWriter, r *http.Request) {
|
|||
err = LinkTun(cSess)
|
||||
case base.LinkModeTAP:
|
||||
err = LinkTap(cSess)
|
||||
case base.LinkModeMacvtap:
|
||||
err = LinkMacvtap(cSess)
|
||||
}
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
conn.Close()
|
||||
base.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
go LinkCstp(conn, cSess)
|
||||
go LinkCstp(conn, bufRW, cSess)
|
||||
}
|
||||
|
|
|
@ -0,0 +1,137 @@
|
|||
package handler
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"os"
|
||||
"strings"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
|
||||
"github.com/bjdgyc/anylink/base"
|
||||
"github.com/bjdgyc/anylink/pkg/utils"
|
||||
"github.com/bjdgyc/anylink/sessdata"
|
||||
)
|
||||
|
||||
// link vtap
|
||||
const vTapPrefix = "lvtap"
|
||||
|
||||
type Vtap struct {
|
||||
*os.File
|
||||
ifName string
|
||||
}
|
||||
|
||||
func (v *Vtap) Close() error {
|
||||
v.File.Close()
|
||||
cmdstr := fmt.Sprintf("ip link del %s", v.ifName)
|
||||
return execCmd([]string{cmdstr})
|
||||
}
|
||||
|
||||
func checkMacvtap() {
|
||||
_setGateway()
|
||||
_checkTapIp(base.Cfg.Ipv4Master)
|
||||
|
||||
ifName := "anylinkMacvtap"
|
||||
// 加载 macvtap
|
||||
cmdstr0 := fmt.Sprintf("modprobe -i macvtap")
|
||||
// 开启主网卡混杂模式
|
||||
cmdstr1 := fmt.Sprintf("ip link set dev %s promisc on", base.Cfg.Ipv4Master)
|
||||
// 测试 macvtap 功能
|
||||
cmdstr2 := fmt.Sprintf("ip link add link %s name %s type macvtap mode bridge", base.Cfg.Ipv4Master, ifName)
|
||||
cmdstr3 := fmt.Sprintf("ip link del %s", ifName)
|
||||
err := execCmd([]string{cmdstr0, cmdstr1, cmdstr2, cmdstr3})
|
||||
if err != nil {
|
||||
base.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
// 创建 Macvtap 网卡
|
||||
func LinkMacvtap(cSess *sessdata.ConnSession) error {
|
||||
capL := sessdata.IpPool.IpLongMax - sessdata.IpPool.IpLongMin
|
||||
ipN := utils.Ip2long(cSess.IpAddr) % capL
|
||||
ifName := fmt.Sprintf("%s%d", vTapPrefix, ipN)
|
||||
|
||||
cSess.SetIfName(ifName)
|
||||
|
||||
cmdstr1 := fmt.Sprintf("ip link add link %s name %s type macvtap mode bridge", base.Cfg.Ipv4Master, ifName)
|
||||
cmdstr2 := fmt.Sprintf("ip link set dev %s up mtu %d address %s", ifName, cSess.Mtu, cSess.MacHw)
|
||||
err := execCmd([]string{cmdstr1, cmdstr2})
|
||||
if err != nil {
|
||||
base.Error(err)
|
||||
return err
|
||||
}
|
||||
cmdstr3 := fmt.Sprintf("sysctl -w net.ipv6.conf.%s.disable_ipv6=1", ifName)
|
||||
execCmd([]string{cmdstr3})
|
||||
|
||||
return createVtap(cSess, ifName)
|
||||
}
|
||||
|
||||
func checkIpvtap() {
|
||||
|
||||
}
|
||||
|
||||
// 创建 Ipvtap 网卡
|
||||
func LinkIpvtap(cSess *sessdata.ConnSession) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
type ifReq struct {
|
||||
Name [0x10]byte
|
||||
Flags uint16
|
||||
pad [0x28 - 0x10 - 2]byte
|
||||
}
|
||||
|
||||
func createVtap(cSess *sessdata.ConnSession, ifName string) error {
|
||||
// 初始化 ifName
|
||||
inf, err := net.InterfaceByName(ifName)
|
||||
if err != nil {
|
||||
base.Error(err)
|
||||
return err
|
||||
}
|
||||
|
||||
tName := fmt.Sprintf("/dev/tap%d", inf.Index)
|
||||
|
||||
var fdInt int
|
||||
|
||||
fdInt, err = syscall.Open(tName, syscall.O_RDWR|syscall.O_NONBLOCK, 0)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var flags uint16 = syscall.IFF_TAP | syscall.IFF_NO_PI
|
||||
var req ifReq
|
||||
req.Flags = flags
|
||||
|
||||
_, _, errno := syscall.Syscall(
|
||||
syscall.SYS_IOCTL,
|
||||
uintptr(fdInt),
|
||||
uintptr(syscall.TUNSETIFF),
|
||||
uintptr(unsafe.Pointer(&req)),
|
||||
)
|
||||
if errno != 0 {
|
||||
return os.NewSyscallError("ioctl", errno)
|
||||
}
|
||||
|
||||
file := os.NewFile(uintptr(fdInt), tName)
|
||||
ifce := &Vtap{file, ifName}
|
||||
|
||||
go allTapRead(ifce, cSess)
|
||||
go allTapWrite(ifce, cSess)
|
||||
return nil
|
||||
}
|
||||
|
||||
// 销毁未关闭的vtap
|
||||
func destroyVtap() {
|
||||
its, err := net.Interfaces()
|
||||
if err != nil {
|
||||
base.Error(err)
|
||||
return
|
||||
}
|
||||
for _, v := range its {
|
||||
if strings.HasPrefix(v.Name, vTapPrefix) {
|
||||
// 删除原来的网卡
|
||||
cmdstr := fmt.Sprintf("ip link del %s", v.Name)
|
||||
execCmd([]string{cmdstr})
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,12 +1,17 @@
|
|||
package handler
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
|
||||
"github.com/bjdgyc/anylink/base"
|
||||
"github.com/bjdgyc/anylink/dbdata"
|
||||
"github.com/bjdgyc/anylink/pkg/utils"
|
||||
"github.com/bjdgyc/anylink/sessdata"
|
||||
"github.com/songgao/water/waterutil"
|
||||
)
|
||||
|
||||
func payloadIn(cSess *sessdata.ConnSession, pl *sessdata.Payload) bool {
|
||||
if pl.LType == sessdata.LTypeIPData && pl.PType == 0x00 {
|
||||
// 进行Acl规则判断
|
||||
check := checkLinkAcl(cSess.Group, pl)
|
||||
if !check {
|
||||
|
@ -14,6 +19,9 @@ func payloadIn(cSess *sessdata.ConnSession, pl *sessdata.Payload) bool {
|
|||
return false
|
||||
}
|
||||
|
||||
logAudit(cSess, pl)
|
||||
}
|
||||
|
||||
closed := false
|
||||
select {
|
||||
case cSess.PayloadIn <- pl:
|
||||
|
@ -61,24 +69,23 @@ func checkLinkAcl(group *dbdata.Group, pl *sessdata.Payload) bool {
|
|||
return true
|
||||
}
|
||||
|
||||
data := pl.Data
|
||||
ip_dst := waterutil.IPv4Destination(data)
|
||||
ip_port := waterutil.IPv4DestinationPort(data)
|
||||
ip_proto := waterutil.IPv4Protocol(data)
|
||||
ipDst := waterutil.IPv4Destination(pl.Data)
|
||||
ipPort := waterutil.IPv4DestinationPort(pl.Data)
|
||||
ipProto := waterutil.IPv4Protocol(pl.Data)
|
||||
// fmt.Println("sent:", ip_dst, ip_port)
|
||||
|
||||
// 优先放行dns端口
|
||||
for _, v := range group.ClientDns {
|
||||
if v.Val == ip_dst.String() && ip_port == 53 {
|
||||
if v.Val == ipDst.String() && ipPort == 53 {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
for _, v := range group.LinkAcl {
|
||||
// 循环判断ip和端口
|
||||
if v.IpNet.Contains(ip_dst) {
|
||||
if v.IpNet.Contains(ipDst) {
|
||||
// 放行允许ip的ping
|
||||
if v.Port == ip_port || v.Port == 0 || ip_proto == waterutil.ICMP {
|
||||
if v.Port == ipPort || v.Port == 0 || ipProto == waterutil.ICMP {
|
||||
if v.Action == dbdata.Allow {
|
||||
return true
|
||||
} else {
|
||||
|
@ -90,3 +97,49 @@ func checkLinkAcl(group *dbdata.Group, pl *sessdata.Payload) bool {
|
|||
|
||||
return false
|
||||
}
|
||||
|
||||
// 访问日志审计
|
||||
func logAudit(cSess *sessdata.ConnSession, pl *sessdata.Payload) {
|
||||
ipSrc := waterutil.IPv4Source(pl.Data)
|
||||
ipDst := waterutil.IPv4Destination(pl.Data)
|
||||
ipPort := waterutil.IPv4DestinationPort(pl.Data)
|
||||
ipProto := waterutil.IPv4Protocol(pl.Data)
|
||||
|
||||
// 只统计 tcp和udp 的访问
|
||||
switch ipProto {
|
||||
case waterutil.TCP:
|
||||
case waterutil.UDP:
|
||||
default:
|
||||
return
|
||||
}
|
||||
|
||||
b := getByte34()
|
||||
key := *b
|
||||
copy(key[:16], ipSrc)
|
||||
copy(key[16:32], ipDst)
|
||||
binary.BigEndian.PutUint16(key[32:34], ipPort)
|
||||
|
||||
s := utils.BytesToString(key)
|
||||
nu := utils.NowSec().Unix()
|
||||
|
||||
// 判断已经存在,并且没有过期
|
||||
v, ok := cSess.IpAuditMap[s]
|
||||
if ok && nu-v < int64(base.Cfg.AuditInterval) {
|
||||
// 回收byte对象
|
||||
putByte34(b)
|
||||
return
|
||||
}
|
||||
|
||||
cSess.IpAuditMap[s] = nu
|
||||
|
||||
audit := dbdata.AccessAudit{
|
||||
Username: cSess.Sess.Username,
|
||||
Protocol: uint8(ipProto),
|
||||
Src: ipSrc.String(),
|
||||
Dst: ipDst.String(),
|
||||
DstPort: ipPort,
|
||||
CreatedAt: utils.NowSec(),
|
||||
}
|
||||
|
||||
_ = dbdata.Add(audit)
|
||||
}
|
||||
|
|
|
@ -9,7 +9,12 @@ import (
|
|||
|
||||
// 不允许直接修改
|
||||
// [6] => PType
|
||||
var plHeader = []byte{'S', 'T', 'F', 0x01, 0x00, 0x00, 0x00, 0x00}
|
||||
var plHeader = []byte{
|
||||
'S', 'T', 'F', 1,
|
||||
0x00, 0x00, /* Length */
|
||||
0x00, /* Type */
|
||||
0x00, /* Unknown */
|
||||
}
|
||||
|
||||
var plPool = sync.Pool{
|
||||
New: func() interface{} {
|
||||
|
@ -64,3 +69,21 @@ func putByte(b *[]byte) {
|
|||
*b = (*b)[:BufferSize]
|
||||
bytePool.Put(b)
|
||||
}
|
||||
|
||||
// 长度 34 小对象
|
||||
var byte34Pool = sync.Pool{
|
||||
New: func() interface{} {
|
||||
b := make([]byte, 34)
|
||||
return &b
|
||||
},
|
||||
}
|
||||
|
||||
func getByte34() *[]byte {
|
||||
b := byte34Pool.Get().(*[]byte)
|
||||
return b
|
||||
}
|
||||
|
||||
func putByte34(b *[]byte) {
|
||||
*b = (*b)[:34]
|
||||
byte34Pool.Put(b)
|
||||
}
|
||||
|
|
|
@ -10,11 +10,10 @@ import (
|
|||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/pion/dtls/v2/pkg/crypto/selfsign"
|
||||
|
||||
"github.com/bjdgyc/anylink/base"
|
||||
"github.com/bjdgyc/anylink/pkg/proxyproto"
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/pion/dtls/v2/pkg/crypto/selfsign"
|
||||
)
|
||||
|
||||
func startTls() {
|
||||
|
@ -47,8 +46,8 @@ func startTls() {
|
|||
tlsConfig := &tls.Config{
|
||||
NextProtos: []string{"http/1.1"},
|
||||
MinVersion: tls.VersionTLS12,
|
||||
InsecureSkipVerify: true,
|
||||
Certificates: certs,
|
||||
// InsecureSkipVerify: true,
|
||||
}
|
||||
srv := &http.Server{
|
||||
Addr: addr,
|
||||
|
|
|
@ -11,10 +11,17 @@ func Start() {
|
|||
dbdata.Start()
|
||||
sessdata.Start()
|
||||
|
||||
switch base.Cfg.LinkMode {
|
||||
case base.LinkModeTUN:
|
||||
checkTun()
|
||||
if base.Cfg.LinkMode == base.LinkModeTAP {
|
||||
case base.LinkModeTAP:
|
||||
checkTap()
|
||||
case base.LinkModeMacvtap:
|
||||
checkMacvtap()
|
||||
default:
|
||||
base.Fatal("LinkMode is err")
|
||||
}
|
||||
|
||||
go admin.StartAdmin()
|
||||
go startTls()
|
||||
go startDtls()
|
||||
|
@ -22,4 +29,5 @@ func Start() {
|
|||
|
||||
func Stop() {
|
||||
_ = dbdata.Stop()
|
||||
destroyVtap()
|
||||
}
|
||||
|
|
|
@ -11,7 +11,6 @@ import (
|
|||
"syscall"
|
||||
|
||||
"github.com/bjdgyc/anylink/admin"
|
||||
|
||||
"github.com/bjdgyc/anylink/base"
|
||||
"github.com/bjdgyc/anylink/handler"
|
||||
)
|
||||
|
|
|
@ -4,6 +4,8 @@ import (
|
|||
"net"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/bjdgyc/anylink/pkg/utils"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -16,7 +18,7 @@ const (
|
|||
)
|
||||
|
||||
var (
|
||||
table = make(map[string]*Addr)
|
||||
table = make(map[string]*Addr, 128)
|
||||
tableMu sync.RWMutex
|
||||
)
|
||||
|
||||
|
@ -40,25 +42,25 @@ func Lookup(ip net.IP, onlyTable bool) *Addr {
|
|||
|
||||
// Add adds a IP-MAC map to a runtime ARP table.
|
||||
func tableLookup(ip net.IP) *Addr {
|
||||
tableMu.Lock()
|
||||
tableMu.RLock()
|
||||
addr := table[ip.To4().String()]
|
||||
tableMu.Unlock()
|
||||
tableMu.RUnlock()
|
||||
if addr == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
// 判断老化过期时间
|
||||
tsub := time.Since(addr.disTime)
|
||||
tSub := utils.NowSec().Sub(addr.disTime)
|
||||
switch addr.Type {
|
||||
case TypeStatic:
|
||||
case TypeNormal:
|
||||
if tsub > StaleTimeNormal {
|
||||
if tSub > StaleTimeNormal {
|
||||
return nil
|
||||
}
|
||||
case TypeUnreachable:
|
||||
if tsub > StaleTimeUnreachable {
|
||||
if tSub > StaleTimeUnreachable {
|
||||
return nil
|
||||
}
|
||||
case TypeStatic:
|
||||
}
|
||||
|
||||
return addr
|
||||
|
@ -70,7 +72,7 @@ func Add(addr *Addr) {
|
|||
return
|
||||
}
|
||||
if addr.disTime.IsZero() {
|
||||
addr.disTime = time.Now()
|
||||
addr.disTime = utils.NowSec()
|
||||
}
|
||||
ip := addr.IP.To4().String()
|
||||
tableMu.Lock()
|
||||
|
|
|
@ -19,7 +19,8 @@ func doLookup(ip net.IP) *Addr {
|
|||
err := doPing(ip.String())
|
||||
if err != nil {
|
||||
// log.Println(err)
|
||||
addr := &Addr{IP: ip, Type: TypeUnreachable}
|
||||
addr := &Addr{IP: net.IPv4(1, 2, 3, 4), Type: TypeUnreachable}
|
||||
copy(addr.IP, ip)
|
||||
return addr
|
||||
}
|
||||
|
||||
|
@ -50,7 +51,9 @@ func doArpShow(ip net.IP) *Addr {
|
|||
return nil
|
||||
}
|
||||
|
||||
return &Addr{IP: ip, HardwareAddr: mac}
|
||||
addr := &Addr{IP: net.IPv4(1, 2, 3, 4), HardwareAddr: mac}
|
||||
copy(addr.IP, ip)
|
||||
return addr
|
||||
}
|
||||
|
||||
// IP address HW type Flags HW address Mask Device
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
package utils
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"net"
|
||||
)
|
||||
|
||||
func Long2ip(i uint32) net.IP {
|
||||
ip := make([]byte, 4)
|
||||
binary.BigEndian.PutUint32(ip, i)
|
||||
return ip
|
||||
}
|
||||
|
||||
func Ip2long(ip net.IP) uint32 {
|
||||
ip = ip.To4()
|
||||
return binary.BigEndian.Uint32(ip)
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
package utils
|
||||
|
||||
import (
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// BytesToString converts byte slice to string.
|
||||
func BytesToString(b []byte) string {
|
||||
return *(*string)(unsafe.Pointer(&b))
|
||||
}
|
||||
|
||||
// StringToBytes converts string to byte slice.
|
||||
func StringToBytes(s string) []byte {
|
||||
return *(*[]byte)(unsafe.Pointer(
|
||||
&struct {
|
||||
string
|
||||
Cap int
|
||||
}{s, len(s)},
|
||||
))
|
||||
}
|
|
@ -3,11 +3,30 @@ package utils
|
|||
import (
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
)
|
||||
|
||||
var (
|
||||
// 每秒时间缓存
|
||||
timeNowSec = &atomic.Value{}
|
||||
)
|
||||
|
||||
func init() {
|
||||
rand.Seed(time.Now().UnixNano())
|
||||
|
||||
timeNowSec.Store(time.Now())
|
||||
go func() {
|
||||
tick := time.NewTicker(time.Second * 1)
|
||||
for c := range tick.C {
|
||||
timeNowSec.Store(c)
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
func NowSec() time.Time {
|
||||
t := timeNowSec.Load()
|
||||
return t.(time.Time)
|
||||
}
|
||||
|
||||
func InArrStr(arr []string, str string) bool {
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
package sessdata
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"net"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/bjdgyc/anylink/base"
|
||||
"github.com/bjdgyc/anylink/dbdata"
|
||||
"github.com/bjdgyc/anylink/pkg/utils"
|
||||
)
|
||||
|
||||
var (
|
||||
|
@ -43,19 +43,8 @@ func initIpPool() {
|
|||
// max := min | uint32(math.Pow(2, float64(32-one))-1)
|
||||
|
||||
// ip地址池
|
||||
IpPool.IpLongMin = ip2long(net.ParseIP(base.Cfg.Ipv4Start))
|
||||
IpPool.IpLongMax = ip2long(net.ParseIP(base.Cfg.Ipv4End))
|
||||
}
|
||||
|
||||
func long2ip(i uint32) net.IP {
|
||||
ip := make([]byte, 4)
|
||||
binary.BigEndian.PutUint32(ip, i)
|
||||
return ip
|
||||
}
|
||||
|
||||
func ip2long(ip net.IP) uint32 {
|
||||
ip = ip.To4()
|
||||
return binary.BigEndian.Uint32(ip)
|
||||
IpPool.IpLongMin = utils.Ip2long(net.ParseIP(base.Cfg.Ipv4Start))
|
||||
IpPool.IpLongMax = utils.Ip2long(net.ParseIP(base.Cfg.Ipv4End))
|
||||
}
|
||||
|
||||
// AcquireIp 获取动态ip
|
||||
|
@ -90,7 +79,7 @@ func AcquireIp(username, macAddr string) net.IP {
|
|||
farIp := &dbdata.IpMap{LastLogin: tNow}
|
||||
// 全局遍历超过租期ip
|
||||
for i := IpPool.IpLongMin; i <= IpPool.IpLongMax; i++ {
|
||||
ip := long2ip(i)
|
||||
ip := utils.Long2ip(i)
|
||||
ipStr := ip.String()
|
||||
|
||||
// 跳过活跃连接
|
||||
|
|
|
@ -54,13 +54,13 @@ func OnlineSess() []Online {
|
|||
Group: v.Group,
|
||||
MacAddr: v.MacAddr,
|
||||
RemoteAddr: v.CSess.RemoteAddr,
|
||||
TunName: v.CSess.TunName,
|
||||
TunName: v.CSess.IfName,
|
||||
Mtu: v.CSess.Mtu,
|
||||
Client: v.CSess.Client,
|
||||
BandwidthUp: utils.HumanByte(atomic.LoadUint32(&v.CSess.BandwidthUpPeriod)) + "/s",
|
||||
BandwidthDown: utils.HumanByte(atomic.LoadUint32(&v.CSess.BandwidthDownPeriod)) + "/s",
|
||||
BandwidthUpAll: utils.HumanByte(atomic.LoadUint32(&v.CSess.BandwidthUpAll)),
|
||||
BandwidthDownAll: utils.HumanByte(atomic.LoadUint32(&v.CSess.BandwidthDownAll)),
|
||||
BandwidthUpAll: utils.HumanByte(atomic.LoadUint64(&v.CSess.BandwidthUpAll)),
|
||||
BandwidthDownAll: utils.HumanByte(atomic.LoadUint64(&v.CSess.BandwidthDownAll)),
|
||||
LastLogin: v.LastLogin,
|
||||
}
|
||||
datas = append(datas, val)
|
||||
|
|
|
@ -32,7 +32,7 @@ type ConnSession struct {
|
|||
MacHw net.HardwareAddr // 客户端mac地址,从Session取出
|
||||
RemoteAddr string
|
||||
Mtu int
|
||||
TunName string
|
||||
IfName string
|
||||
Client string // 客户端 mobile pc
|
||||
CstpDpd int
|
||||
Group *dbdata.Group
|
||||
|
@ -41,14 +41,14 @@ type ConnSession struct {
|
|||
BandwidthDown uint32 // 使用下行带宽 Byte
|
||||
BandwidthUpPeriod uint32 // 前一周期的总量
|
||||
BandwidthDownPeriod uint32
|
||||
BandwidthUpAll uint32 // 使用上行带宽总量
|
||||
BandwidthDownAll uint32 // 使用下行带宽总量
|
||||
BandwidthUpAll uint64 // 使用上行带宽总量
|
||||
BandwidthDownAll uint64 // 使用下行带宽总量
|
||||
closeOnce sync.Once
|
||||
CloseChan chan struct{}
|
||||
PayloadIn chan *Payload
|
||||
// PayloadOut chan *Payload // 公共ip数据
|
||||
PayloadOutCstp chan *Payload // Cstp的数据
|
||||
PayloadOutDtls chan *Payload // Dtls的数据
|
||||
IpAuditMap map[string]int64 // 审计的ip数据
|
||||
|
||||
// dSess *DtlsSession
|
||||
dSess *atomic.Value
|
||||
|
@ -111,9 +111,9 @@ func checkSession() {
|
|||
|
||||
func GenToken() string {
|
||||
// 生成32位的 token
|
||||
btoken := make([]byte, 32)
|
||||
rand.Read(btoken)
|
||||
return fmt.Sprintf("%x", btoken)
|
||||
bToken := make([]byte, 32)
|
||||
rand.Read(bToken)
|
||||
return fmt.Sprintf("%x", bToken)
|
||||
}
|
||||
|
||||
func NewSession(token string) *Session {
|
||||
|
@ -186,6 +186,7 @@ func (s *Session) NewConn() *ConnSession {
|
|||
PayloadIn: make(chan *Payload, 64),
|
||||
PayloadOutCstp: make(chan *Payload, 64),
|
||||
PayloadOutDtls: make(chan *Payload, 64),
|
||||
IpAuditMap: make(map[string]int64, 512),
|
||||
dSess: &atomic.Value{},
|
||||
}
|
||||
|
||||
|
@ -284,8 +285,8 @@ func (cs *ConnSession) ratePeriod() {
|
|||
atomic.SwapUint32(&cs.BandwidthUpPeriod, rtUp/BandwidthPeriodSec)
|
||||
atomic.SwapUint32(&cs.BandwidthDownPeriod, rtDown/BandwidthPeriodSec)
|
||||
// 累加所有流量
|
||||
atomic.AddUint32(&cs.BandwidthUpAll, rtUp)
|
||||
atomic.AddUint32(&cs.BandwidthDownAll, rtDown)
|
||||
atomic.AddUint64(&cs.BandwidthUpAll, uint64(rtUp))
|
||||
atomic.AddUint64(&cs.BandwidthDownAll, uint64(rtDown))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -304,10 +305,10 @@ func (cs *ConnSession) SetMtu(mtu string) {
|
|||
}
|
||||
}
|
||||
|
||||
func (cs *ConnSession) SetTunName(name string) {
|
||||
func (cs *ConnSession) SetIfName(name string) {
|
||||
cs.Sess.mux.Lock()
|
||||
defer cs.Sess.mux.Unlock()
|
||||
cs.TunName = name
|
||||
cs.IfName = name
|
||||
}
|
||||
|
||||
func (cs *ConnSession) RateLimit(byt int, isUp bool) error {
|
||||
|
|
|
@ -1,13 +1,15 @@
|
|||
[Unit]
|
||||
Description=VPN Server Service
|
||||
After=network.target
|
||||
Description=AnyLink Server Service
|
||||
Documentation=https://github.com/bjdgyc/anylink
|
||||
After=network-online.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
User=root
|
||||
WorkingDirectory= /usr/local/anylink-deploy
|
||||
WorkingDirectory=/usr/local/anylink-deploy
|
||||
Restart=on-failure
|
||||
RestartSec=5s
|
||||
ExecStart=/usr/local/anylink-deploy/anylink --conf=conf/server.toml
|
||||
ExecStart=/usr/local/anylink-deploy/anylink --conf=./conf/server.toml
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
"eslint": "^6.7.2",
|
||||
"eslint-plugin-vue": "^6.2.2",
|
||||
"vue-cli-plugin-element": "~1.0.1",
|
||||
"vue-template-compiler": "^2.6.11"
|
||||
"vue-template-compiler": "^2.6.11",
|
||||
"path-parse": "1.0.7"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -319,7 +319,7 @@ export default {
|
|||
status: 1,
|
||||
allow_lan: true,
|
||||
client_dns: [{val: '114.114.114.114'}],
|
||||
route_include: [],
|
||||
route_include: [{val: 'all', note: '默认全局代理'}],
|
||||
route_exclude: [],
|
||||
link_acl: [],
|
||||
},
|
||||
|
|