mirror of https://github.com/bjdgyc/anylink.git
Merge remote-tracking branch 'origin/dev' into dev
# Conflicts: # server/handler/pool_test.go
This commit is contained in:
commit
2a66df55b0
|
@ -18,7 +18,7 @@ COPY --from=builder_node /web/ui /anylink/server/ui
|
||||||
|
|
||||||
#TODO 本地打包时使用镜像
|
#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
|
RUN apk add --no-cache git gcc
|
||||||
RUN cd /anylink/server;go build -o anylink -ldflags "-X main.CommitId=$(git rev-parse HEAD)" \
|
RUN cd /anylink/server;go build -o anylink -ldflags "-X main.CommitId=$(git rev-parse HEAD)" \
|
||||||
&& /anylink/server/anylink tool -v
|
&& /anylink/server/anylink tool -v
|
||||||
|
|
||||||
|
|
50
README.md
50
README.md
|
@ -77,7 +77,7 @@ sudo ./anylink
|
||||||
|
|
||||||
## Config
|
## Config
|
||||||
|
|
||||||
> 默认配置文件内有详细的注释,根据注释填写配置即可。
|
> 示例配置文件内有详细的注释,根据注释填写配置即可。
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
# 生成后台密码
|
# 生成后台密码
|
||||||
|
@ -89,11 +89,11 @@ sudo ./anylink
|
||||||
|
|
||||||
> 数据库配置示例
|
> 数据库配置示例
|
||||||
|
|
||||||
| db_type | db_source |
|
| db_type | db_source |
|
||||||
| ---- | ---- |
|
| -------- | ------------------------------------------------------ |
|
||||||
| sqlite3 | ./conf/anylink.db |
|
| sqlite3 | ./conf/anylink.db |
|
||||||
| mysql | user:password@tcp(127.0.0.1:3306)/anylink?charset=utf8 |
|
| mysql | user:password@tcp(127.0.0.1:3306)/anylink?charset=utf8 |
|
||||||
| postgres | user:password@localhost/anylink?sslmode=verify-full |
|
| postgres | user:password@localhost/anylink?sslmode=verify-full |
|
||||||
|
|
||||||
> 示例配置文件
|
> 示例配置文件
|
||||||
>
|
>
|
||||||
|
@ -181,41 +181,48 @@ systemd 脚本放入:
|
||||||
docker pull bjdgyc/anylink:latest
|
docker pull bjdgyc/anylink:latest
|
||||||
```
|
```
|
||||||
|
|
||||||
2. 生成密码
|
2. 查看命令信息
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker run -it --rm bjdgyc/anylink -h
|
||||||
|
```
|
||||||
|
|
||||||
|
3. 生成密码
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
docker run -it --rm bjdgyc/anylink tool -p 123456
|
docker run -it --rm bjdgyc/anylink tool -p 123456
|
||||||
#Passwd:$2a$10$lCWTCcGmQdE/4Kb1wabbLelu4vY/cUwBwN64xIzvXcihFgRzUvH2a
|
#Passwd:$2a$10$lCWTCcGmQdE/4Kb1wabbLelu4vY/cUwBwN64xIzvXcihFgRzUvH2a
|
||||||
```
|
```
|
||||||
|
|
||||||
3. 生成jwt secret
|
4. 生成jwt secret
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
docker run -it --rm bjdgyc/anylink tool -s
|
docker run -it --rm bjdgyc/anylink tool -s
|
||||||
#Secret:9qXoIhY01jqhWIeIluGliOS4O_rhcXGGGu422uRZ1JjZxIZmh17WwzW36woEbA
|
#Secret:9qXoIhY01jqhWIeIluGliOS4O_rhcXGGGu422uRZ1JjZxIZmh17WwzW36woEbA
|
||||||
```
|
```
|
||||||
|
|
||||||
4. 启动容器
|
5. 启动容器
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
docker run -itd --name anylink --privileged \
|
docker run -itd --name anylink --privileged \
|
||||||
-p 443:443 -p 8800:8800 \
|
-p 443:443 -p 8800:8800 \
|
||||||
--restart=always \
|
--restart=always \
|
||||||
bjdgyc/anylink
|
bjdgyc/anylink
|
||||||
```
|
```
|
||||||
|
|
||||||
5. 使用自定义参数启动容器
|
6. 使用自定义参数启动容器
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
# 参数可以参考 -h 命令
|
||||||
docker run -itd --name anylink --privileged \
|
docker run -itd --name anylink --privileged \
|
||||||
-e IPV4_CIDR=192.168.10.0/24 \
|
-e IPV4_CIDR=192.168.10.0/24 \
|
||||||
-p 443:443 -p 8800:8800 \
|
-p 443:443 -p 8800:8800 \
|
||||||
--restart=always \
|
--restart=always \
|
||||||
bjdgyc/anylink \
|
bjdgyc/anylink \
|
||||||
-c=/etc/server.toml --admin_addr=:8080
|
-c=/etc/server.toml --ip_lease = 1209600 \ # IP地址租约时长
|
||||||
```
|
```
|
||||||
|
|
||||||
6. 构建镜像
|
7. 构建镜像
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
#获取仓库源码
|
#获取仓库源码
|
||||||
|
@ -247,6 +254,7 @@ QQ群共享文件有相关软件下载
|
||||||
<details>
|
<details>
|
||||||
<summary>展开查看</summary>
|
<summary>展开查看</summary>
|
||||||
|
|
||||||
|
|
||||||

|

|
||||||

|

|
||||||

|

|
||||||
|
@ -264,7 +272,3 @@ QQ群共享文件有相关软件下载
|
||||||
<a href="https://www.jetbrains.com">
|
<a href="https://www.jetbrains.com">
|
||||||
<img src="screenshot/jetbrains.png" width="200" height="200" alt="jetbrains.png" />
|
<img src="screenshot/jetbrains.png" width="200" height="200" alt="jetbrains.png" />
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
2
build.sh
2
build.sh
|
@ -25,6 +25,8 @@ echo "编译二进制文件"
|
||||||
cd $cpath/server
|
cd $cpath/server
|
||||||
rm -rf ui
|
rm -rf ui
|
||||||
cp -rf $cpath/web/ui .
|
cp -rf $cpath/web/ui .
|
||||||
|
#国内可替换源加快速度
|
||||||
|
export GOPROXY=https://goproxy.io
|
||||||
go build -v -o anylink -ldflags "-X main.CommitId=$(git rev-parse HEAD)"
|
go build -v -o anylink -ldflags "-X main.CommitId=$(git rev-parse HEAD)"
|
||||||
RETVAL $?
|
RETVAL $?
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"net/url"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"text/template"
|
"text/template"
|
||||||
|
@ -141,7 +142,7 @@ func UserOtpQr(w http.ResponseWriter, r *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
issuer := base.Cfg.Issuer
|
issuer := url.QueryEscape(base.Cfg.Issuer)
|
||||||
qrstr := fmt.Sprintf("otpauth://totp/%s:%s?issuer=%s&secret=%s", issuer, user.Email, issuer, user.OtpSecret)
|
qrstr := fmt.Sprintf("otpauth://totp/%s:%s?issuer=%s&secret=%s", issuer, user.Email, issuer, user.OtpSecret)
|
||||||
qr, _ := qrcode.New(qrstr, qrcode.High)
|
qr, _ := qrcode.New(qrstr, qrcode.High)
|
||||||
|
|
||||||
|
|
|
@ -58,7 +58,7 @@ func StartAdmin() {
|
||||||
r.HandleFunc("/debug/pprof/profile", pprof.Profile).Name("debug")
|
r.HandleFunc("/debug/pprof/profile", pprof.Profile).Name("debug")
|
||||||
r.HandleFunc("/debug/pprof/symbol", pprof.Symbol).Name("debug")
|
r.HandleFunc("/debug/pprof/symbol", pprof.Symbol).Name("debug")
|
||||||
r.HandleFunc("/debug/pprof/trace", pprof.Trace).Name("debug")
|
r.HandleFunc("/debug/pprof/trace", pprof.Trace).Name("debug")
|
||||||
r.HandleFunc("/debug/pprof", location("/debug/pprof/"))
|
r.HandleFunc("/debug/pprof", location("/debug/pprof/")).Name("debug")
|
||||||
r.PathPrefix("/debug/pprof/").HandlerFunc(pprof.Index).Name("debug")
|
r.PathPrefix("/debug/pprof/").HandlerFunc(pprof.Index).Name("debug")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,8 +5,6 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
|
||||||
"github.com/spf13/viper"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -31,6 +29,7 @@ var (
|
||||||
|
|
||||||
type ServerConfig struct {
|
type ServerConfig struct {
|
||||||
// LinkAddr string `json:"link_addr"`
|
// LinkAddr string `json:"link_addr"`
|
||||||
|
Conf string `json:"conf"`
|
||||||
ServerAddr string `json:"server_addr"`
|
ServerAddr string `json:"server_addr"`
|
||||||
ServerDTLSAddr string `json:"server_dtls_addr"`
|
ServerDTLSAddr string `json:"server_dtls_addr"`
|
||||||
ServerDTLS bool `json:"server_dtls"`
|
ServerDTLS bool `json:"server_dtls"`
|
||||||
|
@ -65,7 +64,7 @@ type ServerConfig struct {
|
||||||
MobileDpd int `json:"mobile_dpd"`
|
MobileDpd int `json:"mobile_dpd"`
|
||||||
|
|
||||||
SessionTimeout int `json:"session_timeout"` // in seconds
|
SessionTimeout int `json:"session_timeout"` // in seconds
|
||||||
AuthTimeout int `json:"auth_timeout"` // in seconds
|
// AuthTimeout int `json:"auth_timeout"` // in seconds
|
||||||
}
|
}
|
||||||
|
|
||||||
func initServerCfg() {
|
func initServerCfg() {
|
||||||
|
@ -82,6 +81,10 @@ func initServerCfg() {
|
||||||
// Cfg.FilesPath = getAbsPath(base, Cfg.FilesPath)
|
// Cfg.FilesPath = getAbsPath(base, Cfg.FilesPath)
|
||||||
// Cfg.LogPath = getAbsPath(base, Cfg.LogPath)
|
// Cfg.LogPath = getAbsPath(base, Cfg.LogPath)
|
||||||
|
|
||||||
|
if Cfg.AdminPass == defaultPwd {
|
||||||
|
fmt.Fprintln(os.Stderr, "=== 使用默认的admin_pass有安全风险,请设置新的admin_pass ===")
|
||||||
|
}
|
||||||
|
|
||||||
if Cfg.JwtSecret == defaultJwt {
|
if Cfg.JwtSecret == defaultJwt {
|
||||||
fmt.Fprintln(os.Stderr, "=== 使用默认的jwt_secret有安全风险,请设置新的jwt_secret ===")
|
fmt.Fprintln(os.Stderr, "=== 使用默认的jwt_secret有安全风险,请设置新的jwt_secret ===")
|
||||||
}
|
}
|
||||||
|
@ -115,13 +118,13 @@ func initCfg() {
|
||||||
for _, v := range configs {
|
for _, v := range configs {
|
||||||
if v.Name == tag {
|
if v.Name == tag {
|
||||||
if v.Typ == cfgStr {
|
if v.Typ == cfgStr {
|
||||||
value.SetString(viper.GetString(v.Name))
|
value.SetString(linkViper.GetString(v.Name))
|
||||||
}
|
}
|
||||||
if v.Typ == cfgInt {
|
if v.Typ == cfgInt {
|
||||||
value.SetInt(int64(viper.GetInt(v.Name)))
|
value.SetInt(int64(linkViper.GetInt(v.Name)))
|
||||||
}
|
}
|
||||||
if v.Typ == cfgBool {
|
if v.Typ == cfgBool {
|
||||||
value.SetBool(viper.GetBool(v.Name))
|
value.SetBool(linkViper.GetBool(v.Name))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -150,9 +153,6 @@ func ServerCfg2Slice() []SCfg {
|
||||||
value := s.Field(i)
|
value := s.Field(i)
|
||||||
tag := field.Tag.Get("json")
|
tag := field.Tag.Get("json")
|
||||||
usage, env := getUsageEnv(tag)
|
usage, env := getUsageEnv(tag)
|
||||||
if usage == "" {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
datas = append(datas, SCfg{Name: tag, Env: env, Info: usage, Data: value.Interface()})
|
datas = append(datas, SCfg{Name: tag, Env: env, Info: usage, Data: value.Interface()})
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
package base
|
package base
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
"reflect"
|
||||||
"runtime"
|
"runtime"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
@ -14,25 +16,26 @@ import (
|
||||||
var (
|
var (
|
||||||
// 提交id
|
// 提交id
|
||||||
CommitId string
|
CommitId string
|
||||||
// 配置文件
|
|
||||||
cfgFile string
|
|
||||||
// pass明文
|
// pass明文
|
||||||
passwd string
|
passwd string
|
||||||
// 生成密钥
|
// 生成密钥
|
||||||
secret bool
|
secret bool
|
||||||
// 显示版本信息
|
// 显示版本信息
|
||||||
rev bool
|
rev bool
|
||||||
// 获取env名称
|
// 输出debug信息
|
||||||
env bool
|
debug bool
|
||||||
|
|
||||||
// Used for flags.
|
// Used for flags.
|
||||||
runSrv bool
|
runSrv bool
|
||||||
|
|
||||||
rootCmd *cobra.Command
|
linkViper *viper.Viper
|
||||||
|
rootCmd *cobra.Command
|
||||||
)
|
)
|
||||||
|
|
||||||
// Execute executes the root command.
|
// Execute executes the root command.
|
||||||
func execute() {
|
func execute() {
|
||||||
|
initCmd()
|
||||||
|
|
||||||
err := rootCmd.Execute()
|
err := rootCmd.Execute()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
|
@ -40,13 +43,25 @@ func execute() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// viper.Debug()
|
// viper.Debug()
|
||||||
|
ref := reflect.ValueOf(linkViper)
|
||||||
|
s := ref.Elem()
|
||||||
|
ee := s.FieldByName("env")
|
||||||
|
if ee.Kind() != reflect.Map {
|
||||||
|
panic("Viper env is err")
|
||||||
|
}
|
||||||
|
rr := ee.MapRange()
|
||||||
|
for rr.Next() {
|
||||||
|
// fmt.Println(rr.Key(), rr.Value())
|
||||||
|
envs[rr.Key().String()] = rr.Value().String()
|
||||||
|
}
|
||||||
|
|
||||||
if !runSrv {
|
if !runSrv {
|
||||||
os.Exit(0)
|
os.Exit(0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func initCmd() {
|
||||||
|
linkViper = viper.New()
|
||||||
rootCmd = &cobra.Command{
|
rootCmd = &cobra.Command{
|
||||||
Use: "anylink",
|
Use: "anylink",
|
||||||
Short: "AnyLink VPN Server",
|
Short: "AnyLink VPN Server",
|
||||||
|
@ -57,43 +72,44 @@ func init() {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
cobra.OnInitialize(func() {
|
linkViper.SetEnvPrefix("link")
|
||||||
viper.SetConfigFile(cfgFile)
|
|
||||||
viper.AutomaticEnv()
|
|
||||||
|
|
||||||
if cfgFile == "" {
|
|
||||||
// 没有配置文件,不做处理
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
err := viper.ReadInConfig()
|
|
||||||
if err != nil {
|
|
||||||
fmt.Println("Using config file:", err)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
viper.SetEnvPrefix("link")
|
|
||||||
|
|
||||||
// 基础配置
|
// 基础配置
|
||||||
rootCmd.Flags().StringVarP(&cfgFile, "conf", "c", "", "config file")
|
|
||||||
|
|
||||||
for _, v := range configs {
|
for _, v := range configs {
|
||||||
if v.Typ == cfgStr {
|
if v.Typ == cfgStr {
|
||||||
rootCmd.Flags().String(v.Name, v.ValStr, v.Usage)
|
rootCmd.Flags().StringP(v.Name, v.Short, v.ValStr, v.Usage)
|
||||||
}
|
}
|
||||||
if v.Typ == cfgInt {
|
if v.Typ == cfgInt {
|
||||||
rootCmd.Flags().Int(v.Name, v.ValInt, v.Usage)
|
rootCmd.Flags().IntP(v.Name, v.Short, v.ValInt, v.Usage)
|
||||||
}
|
}
|
||||||
if v.Typ == cfgBool {
|
if v.Typ == cfgBool {
|
||||||
rootCmd.Flags().Bool(v.Name, v.ValBool, v.Usage)
|
rootCmd.Flags().BoolP(v.Name, v.Short, v.ValBool, v.Usage)
|
||||||
}
|
}
|
||||||
|
|
||||||
_ = viper.BindPFlag(v.Name, rootCmd.Flags().Lookup(v.Name))
|
_ = linkViper.BindPFlag(v.Name, rootCmd.Flags().Lookup(v.Name))
|
||||||
_ = viper.BindEnv(v.Name)
|
_ = linkViper.BindEnv(v.Name)
|
||||||
// viper.SetDefault(v.Name, v.Value)
|
// viper.SetDefault(v.Name, v.Value)
|
||||||
}
|
}
|
||||||
|
|
||||||
rootCmd.AddCommand(initToolCmd())
|
rootCmd.AddCommand(initToolCmd())
|
||||||
|
|
||||||
|
cobra.OnInitialize(func() {
|
||||||
|
linkViper.AutomaticEnv()
|
||||||
|
conf := linkViper.GetString("conf")
|
||||||
|
|
||||||
|
_, err := os.Stat(conf)
|
||||||
|
if errors.Is(err, os.ErrNotExist) {
|
||||||
|
// 没有配置文件,不做处理
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
linkViper.SetConfigFile(conf)
|
||||||
|
err = linkViper.ReadInConfig()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("Using config file:", err)
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func initToolCmd() *cobra.Command {
|
func initToolCmd() *cobra.Command {
|
||||||
|
@ -106,7 +122,7 @@ func initToolCmd() *cobra.Command {
|
||||||
toolCmd.Flags().BoolVarP(&rev, "version", "v", false, "display version info")
|
toolCmd.Flags().BoolVarP(&rev, "version", "v", false, "display version info")
|
||||||
toolCmd.Flags().BoolVarP(&secret, "secret", "s", false, "generate a random jwt secret")
|
toolCmd.Flags().BoolVarP(&secret, "secret", "s", false, "generate a random jwt secret")
|
||||||
toolCmd.Flags().StringVarP(&passwd, "passwd", "p", "", "convert the password plaintext")
|
toolCmd.Flags().StringVarP(&passwd, "passwd", "p", "", "convert the password plaintext")
|
||||||
toolCmd.Flags().BoolVarP(&env, "env", "e", false, "list the config name and env key")
|
toolCmd.Flags().BoolVarP(&debug, "debug", "d", false, "list the config viper.Debug() info")
|
||||||
|
|
||||||
toolCmd.Run = func(cmd *cobra.Command, args []string) {
|
toolCmd.Run = func(cmd *cobra.Command, args []string) {
|
||||||
switch {
|
switch {
|
||||||
|
@ -120,10 +136,8 @@ func initToolCmd() *cobra.Command {
|
||||||
case passwd != "":
|
case passwd != "":
|
||||||
pass, _ := utils.PasswordHash(passwd)
|
pass, _ := utils.PasswordHash(passwd)
|
||||||
fmt.Printf("Passwd:%s\n", pass)
|
fmt.Printf("Passwd:%s\n", pass)
|
||||||
case env:
|
case debug:
|
||||||
for k, v := range envs {
|
linkViper.Debug()
|
||||||
fmt.Printf("%s => %s\n", k, v)
|
|
||||||
}
|
|
||||||
default:
|
default:
|
||||||
fmt.Println("Using [anylink tool -h] for help")
|
fmt.Println("Using [anylink tool -h] for help")
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,11 +6,13 @@ const (
|
||||||
cfgBool
|
cfgBool
|
||||||
|
|
||||||
defaultJwt = "abcdef.0123456789.abcdef"
|
defaultJwt = "abcdef.0123456789.abcdef"
|
||||||
|
defaultPwd = "$2a$10$UQ7C.EoPifDeJh6d8.31TeSPQU7hM/NOM2nixmBucJpAuXDQNqNke"
|
||||||
)
|
)
|
||||||
|
|
||||||
type config struct {
|
type config struct {
|
||||||
Typ int
|
Typ int
|
||||||
Name string
|
Name string
|
||||||
|
Short string
|
||||||
Usage string
|
Usage string
|
||||||
ValStr string
|
ValStr string
|
||||||
ValInt int
|
ValInt int
|
||||||
|
@ -18,6 +20,7 @@ type config struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
var configs = []config{
|
var configs = []config{
|
||||||
|
{Typ: cfgStr, Name: "conf", Usage: "config file", ValStr: "./conf/server.toml", Short: "c"},
|
||||||
{Typ: cfgStr, Name: "server_addr", Usage: "服务监听地址", ValStr: ":443"},
|
{Typ: cfgStr, Name: "server_addr", Usage: "服务监听地址", ValStr: ":443"},
|
||||||
{Typ: cfgBool, Name: "server_dtls", Usage: "开启DTLS", ValBool: false},
|
{Typ: cfgBool, Name: "server_dtls", Usage: "开启DTLS", ValBool: false},
|
||||||
{Typ: cfgStr, Name: "server_dtls_addr", Usage: "DTLS监听地址", ValStr: ":4433"},
|
{Typ: cfgStr, Name: "server_dtls_addr", Usage: "DTLS监听地址", ValStr: ":4433"},
|
||||||
|
@ -33,7 +36,7 @@ var configs = []config{
|
||||||
{Typ: cfgBool, Name: "pprof", Usage: "开启pprof", ValBool: false},
|
{Typ: cfgBool, Name: "pprof", Usage: "开启pprof", ValBool: false},
|
||||||
{Typ: cfgStr, Name: "issuer", Usage: "系统名称", ValStr: "XX公司VPN"},
|
{Typ: cfgStr, Name: "issuer", Usage: "系统名称", ValStr: "XX公司VPN"},
|
||||||
{Typ: cfgStr, Name: "admin_user", Usage: "管理用户名", ValStr: "admin"},
|
{Typ: cfgStr, Name: "admin_user", Usage: "管理用户名", ValStr: "admin"},
|
||||||
{Typ: cfgStr, Name: "admin_pass", Usage: "管理用户密码", ValStr: "$2a$10$UQ7C.EoPifDeJh6d8.31TeSPQU7hM/NOM2nixmBucJpAuXDQNqNke"},
|
{Typ: cfgStr, Name: "admin_pass", Usage: "管理用户密码", ValStr: defaultPwd},
|
||||||
{Typ: cfgStr, Name: "jwt_secret", Usage: "JWT密钥", ValStr: defaultJwt},
|
{Typ: cfgStr, Name: "jwt_secret", Usage: "JWT密钥", ValStr: defaultJwt},
|
||||||
{Typ: cfgStr, Name: "link_mode", Usage: "虚拟网络类型", ValStr: "tun"},
|
{Typ: cfgStr, Name: "link_mode", Usage: "虚拟网络类型", ValStr: "tun"},
|
||||||
{Typ: cfgStr, Name: "ipv4_cidr", Usage: "ip地址网段", ValStr: "192.168.10.0/24"},
|
{Typ: cfgStr, Name: "ipv4_cidr", Usage: "ip地址网段", ValStr: "192.168.10.0/24"},
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
#服务配置信息
|
#示例配置信息
|
||||||
|
|
||||||
#其他配置文件,可以使用绝对路径
|
#其他配置文件,可以使用绝对路径
|
||||||
#或者相对于 anylink 二进制文件的路径
|
#或者相对于 anylink 二进制文件的路径
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
package dbdata
|
package dbdata
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
|
||||||
|
|
||||||
"github.com/bjdgyc/anylink/base"
|
"github.com/bjdgyc/anylink/base"
|
||||||
_ "github.com/go-sql-driver/mysql"
|
_ "github.com/go-sql-driver/mysql"
|
||||||
_ "github.com/lib/pq"
|
_ "github.com/lib/pq"
|
||||||
|
@ -41,17 +39,24 @@ func initData() {
|
||||||
)
|
)
|
||||||
|
|
||||||
// 判断是否初次使用
|
// 判断是否初次使用
|
||||||
s := &Setting{}
|
install := &SettingInstall{}
|
||||||
err = One("name", InstallName, s)
|
err = SettingGet(install)
|
||||||
if err == nil && s.Data == InstallData {
|
|
||||||
|
if err == nil && install.Installed {
|
||||||
// 已经安装过
|
// 已经安装过
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 发生错误
|
||||||
|
if err != ErrNotFound {
|
||||||
|
base.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
err = addInitData()
|
err = addInitData()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
base.Fatal(err)
|
base.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func addInitData() error {
|
func addInitData() error {
|
||||||
|
@ -74,9 +79,7 @@ func addInitData() error {
|
||||||
From: "vpn@xx.com",
|
From: "vpn@xx.com",
|
||||||
Encryption: "None",
|
Encryption: "None",
|
||||||
}
|
}
|
||||||
v, _ := json.Marshal(smtp)
|
err = SettingSessAdd(sess, smtp)
|
||||||
s := &Setting{Name: StructName(smtp), Data: string(v)}
|
|
||||||
_, err = sess.InsertOne(s)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -87,16 +90,14 @@ func addInitData() error {
|
||||||
Banner: "您已接入公司网络,请按照公司规定使用。\n请勿进行非工作下载及视频行为!",
|
Banner: "您已接入公司网络,请按照公司规定使用。\n请勿进行非工作下载及视频行为!",
|
||||||
AccountMail: accountMail,
|
AccountMail: accountMail,
|
||||||
}
|
}
|
||||||
v, _ = json.Marshal(other)
|
err = SettingSessAdd(sess, other)
|
||||||
s = &Setting{Name: StructName(other), Data: string(v)}
|
|
||||||
_, err = sess.InsertOne(s)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Install
|
// Install
|
||||||
install := &Setting{Name: InstallName, Data: InstallData}
|
install := &SettingInstall{Installed: true}
|
||||||
_, err = sess.InsertOne(install)
|
err = SettingSessAdd(sess, install)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,20 +29,20 @@ type ValData struct {
|
||||||
Note string `json:"note"`
|
Note string `json:"note"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type Group struct {
|
// type Group struct {
|
||||||
Id int `json:"id" xorm:"pk autoincr not null"`
|
// Id int `json:"id" xorm:"pk autoincr not null"`
|
||||||
Name string `json:"name" xorm:"not null unique"`
|
// Name string `json:"name" xorm:"not null unique"`
|
||||||
Note string `json:"note"`
|
// Note string `json:"note"`
|
||||||
AllowLan bool `json:"allow_lan"`
|
// AllowLan bool `json:"allow_lan"`
|
||||||
ClientDns []ValData `json:"client_dns"`
|
// ClientDns []ValData `json:"client_dns"`
|
||||||
RouteInclude []ValData `json:"route_include"`
|
// RouteInclude []ValData `json:"route_include"`
|
||||||
RouteExclude []ValData `json:"route_exclude"`
|
// RouteExclude []ValData `json:"route_exclude"`
|
||||||
LinkAcl []GroupLinkAcl `json:"link_acl"`
|
// LinkAcl []GroupLinkAcl `json:"link_acl"`
|
||||||
Bandwidth int `json:"bandwidth"` // 带宽限制
|
// Bandwidth int `json:"bandwidth"` // 带宽限制
|
||||||
Status int8 `json:"status"` // 1正常
|
// Status int8 `json:"status"` // 1正常
|
||||||
CreatedAt time.Time `json:"created_at"`
|
// CreatedAt time.Time `json:"created_at"`
|
||||||
UpdatedAt time.Time `json:"updated_at"`
|
// UpdatedAt time.Time `json:"updated_at"`
|
||||||
}
|
// }
|
||||||
|
|
||||||
func GetGroupNames() []string {
|
func GetGroupNames() []string {
|
||||||
var datas []Group
|
var datas []Group
|
||||||
|
|
|
@ -5,17 +5,17 @@ import (
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
type IpMap struct {
|
// type IpMap struct {
|
||||||
Id int `json:"id" xorm:"pk autoincr not null"`
|
// Id int `json:"id" xorm:"pk autoincr not null"`
|
||||||
IpAddr string `json:"ip_addr" xorm:"not null unique"`
|
// IpAddr string `json:"ip_addr" xorm:"not null unique"`
|
||||||
MacAddr string `json:"mac_addr" xorm:"not null unique"`
|
// MacAddr string `json:"mac_addr" xorm:"not null unique"`
|
||||||
Username string `json:"username"`
|
// Username string `json:"username"`
|
||||||
Keep bool `json:"keep"` // 保留 ip-mac 绑定
|
// Keep bool `json:"keep"` // 保留 ip-mac 绑定
|
||||||
KeepTime time.Time `json:"keep_time"`
|
// KeepTime time.Time `json:"keep_time"`
|
||||||
Note string `json:"note"` // 备注
|
// Note string `json:"note"` // 备注
|
||||||
LastLogin time.Time `json:"last_login"`
|
// LastLogin time.Time `json:"last_login"`
|
||||||
UpdatedAt time.Time `json:"updated_at"`
|
// UpdatedAt time.Time `json:"updated_at"`
|
||||||
}
|
// }
|
||||||
|
|
||||||
func SetIpMap(v *IpMap) error {
|
func SetIpMap(v *IpMap) error {
|
||||||
var err error
|
var err error
|
||||||
|
|
|
@ -3,17 +3,11 @@ package dbdata
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
"xorm.io/xorm"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
type SettingInstall struct {
|
||||||
InstallName = "Install"
|
Installed bool `json:"installed"`
|
||||||
InstallData = "OK"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Setting struct {
|
|
||||||
Id int `json:"id" xorm:"pk autoincr not null"`
|
|
||||||
Name string `json:"name" xorm:"not null unique"`
|
|
||||||
Data string `json:"data" xorm:"Text"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type SettingSmtp struct {
|
type SettingSmtp struct {
|
||||||
|
@ -42,29 +36,30 @@ func StructName(data interface{}) string {
|
||||||
return name
|
return name
|
||||||
}
|
}
|
||||||
|
|
||||||
func SettingAdd(data interface{}) error {
|
func SettingSessAdd(sess *xorm.Session, data interface{}) error {
|
||||||
name := StructName(data)
|
name := StructName(data)
|
||||||
v, _ := json.Marshal(data)
|
v, _ := json.Marshal(data)
|
||||||
s := Setting{Name: name, Data: string(v)}
|
s := &Setting{Name: name, Data: v}
|
||||||
err := Add(&s)
|
_, err := sess.InsertOne(s)
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func SettingSet(data interface{}) error {
|
func SettingSet(data interface{}) error {
|
||||||
name := StructName(data)
|
name := StructName(data)
|
||||||
v, _ := json.Marshal(data)
|
v, _ := json.Marshal(data)
|
||||||
s := Setting{Data: string(v)}
|
s := &Setting{Data: v}
|
||||||
err := Update("name", name, &s)
|
err := Update("name", name, s)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func SettingGet(data interface{}) error {
|
func SettingGet(data interface{}) error {
|
||||||
name := StructName(data)
|
name := StructName(data)
|
||||||
s := Setting{Name: name}
|
s := &Setting{Name: name}
|
||||||
err := One("name", name, &s)
|
err := One("name", name, s)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
err = json.Unmarshal([]byte(s.Data), data)
|
err = json.Unmarshal(s.Data, data)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,56 @@
|
||||||
|
package dbdata
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Group struct {
|
||||||
|
Id int `json:"id" xorm:"pk autoincr not null"`
|
||||||
|
Name string `json:"name" xorm:"varchar(60) not null unique"`
|
||||||
|
Note string `json:"note" xorm:"varchar(255)"`
|
||||||
|
AllowLan bool `json:"allow_lan" xorm:"Bool"`
|
||||||
|
ClientDns []ValData `json:"client_dns" xorm:"Text"`
|
||||||
|
RouteInclude []ValData `json:"route_include" xorm:"Text"`
|
||||||
|
RouteExclude []ValData `json:"route_exclude" xorm:"Text"`
|
||||||
|
LinkAcl []GroupLinkAcl `json:"link_acl" xorm:"Text"`
|
||||||
|
Bandwidth int `json:"bandwidth" xorm:"Int"` // 带宽限制
|
||||||
|
Status int8 `json:"status" xorm:"Int"` // 1正常
|
||||||
|
CreatedAt time.Time `json:"created_at" xorm:"DateTime created"`
|
||||||
|
UpdatedAt time.Time `json:"updated_at" xorm:"DateTime updated"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type User struct {
|
||||||
|
Id int `json:"id" xorm:"pk autoincr not null"`
|
||||||
|
Username string `json:"username" xorm:"varchar(60) not null unique"`
|
||||||
|
Nickname string `json:"nickname" xorm:"varchar(255)"`
|
||||||
|
Email string `json:"email" xorm:"varchar(255)"`
|
||||||
|
// Password string `json:"password"`
|
||||||
|
PinCode string `json:"pin_code" xorm:"varchar(32)"`
|
||||||
|
OtpSecret string `json:"otp_secret" xorm:"varchar(255)"`
|
||||||
|
DisableOtp bool `json:"disable_otp" xorm:"Bool"` // 禁用otp
|
||||||
|
Groups []string `json:"groups" xorm:"Text"`
|
||||||
|
Status int8 `json:"status" xorm:"Int"` // 1正常
|
||||||
|
SendEmail bool `json:"send_email" xorm:"Bool"`
|
||||||
|
CreatedAt time.Time `json:"created_at" xorm:"DateTime created"`
|
||||||
|
UpdatedAt time.Time `json:"updated_at" xorm:"DateTime updated"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type IpMap struct {
|
||||||
|
Id int `json:"id" xorm:"pk autoincr not null"`
|
||||||
|
IpAddr string `json:"ip_addr" xorm:"varchar(32) not null unique"`
|
||||||
|
MacAddr string `json:"mac_addr" xorm:"varchar(32) not null unique"`
|
||||||
|
Username string `json:"username" xorm:"varchar(60)"`
|
||||||
|
Keep bool `json:"keep" xorm:"Bool"` // 保留 ip-mac 绑定
|
||||||
|
KeepTime time.Time `json:"keep_time" xorm:"DateTime"`
|
||||||
|
Note string `json:"note" xorm:"varchar(255)"` // 备注
|
||||||
|
LastLogin time.Time `json:"last_login" xorm:"DateTime updated"`
|
||||||
|
UpdatedAt time.Time `json:"updated_at" xorm:"DateTime updated"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Setting struct {
|
||||||
|
Id int `json:"id" xorm:"pk autoincr not null"`
|
||||||
|
Name string `json:"name" xorm:"varchar(60) not null unique"`
|
||||||
|
Data json.RawMessage `json:"data" xorm:"Text"`
|
||||||
|
UpdatedAt time.Time `json:"updated_at" xorm:"DateTime updated"`
|
||||||
|
}
|
|
@ -10,21 +10,21 @@ import (
|
||||||
"github.com/xlzd/gotp"
|
"github.com/xlzd/gotp"
|
||||||
)
|
)
|
||||||
|
|
||||||
type User struct {
|
// type User struct {
|
||||||
Id int `json:"id" xorm:"pk autoincr not null"`
|
// Id int `json:"id" xorm:"pk autoincr not null"`
|
||||||
Username string `json:"username" storm:"not null unique"`
|
// Username string `json:"username" storm:"not null unique"`
|
||||||
Nickname string `json:"nickname"`
|
// Nickname string `json:"nickname"`
|
||||||
Email string `json:"email"`
|
// Email string `json:"email"`
|
||||||
// Password string `json:"password"`
|
// // Password string `json:"password"`
|
||||||
PinCode string `json:"pin_code"`
|
// PinCode string `json:"pin_code"`
|
||||||
OtpSecret string `json:"otp_secret"`
|
// OtpSecret string `json:"otp_secret"`
|
||||||
DisableOtp bool `json:"disable_otp"` // 禁用otp
|
// DisableOtp bool `json:"disable_otp"` // 禁用otp
|
||||||
Groups []string `json:"groups"`
|
// Groups []string `json:"groups"`
|
||||||
Status int8 `json:"status"` // 1正常
|
// Status int8 `json:"status"` // 1正常
|
||||||
SendEmail bool `json:"send_email"`
|
// SendEmail bool `json:"send_email"`
|
||||||
CreatedAt time.Time `json:"created_at"`
|
// CreatedAt time.Time `json:"created_at"`
|
||||||
UpdatedAt time.Time `json:"updated_at"`
|
// UpdatedAt time.Time `json:"updated_at"`
|
||||||
}
|
// }
|
||||||
|
|
||||||
func SetUser(v *User) error {
|
func SetUser(v *User) error {
|
||||||
var err error
|
var err error
|
||||||
|
|
|
@ -34,9 +34,8 @@ func LinkCstp(conn net.Conn, cSess *sessdata.ConnSession) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// hdata := make([]byte, BufferSize)
|
// hdata := make([]byte, BufferSize)
|
||||||
hb := getByteFull()
|
pl := getPayload()
|
||||||
hdata := *hb
|
n, err = conn.Read(pl.Data)
|
||||||
n, err = conn.Read(hdata)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
base.Error("read hdata: ", err)
|
base.Error("read hdata: ", err)
|
||||||
return
|
return
|
||||||
|
@ -48,7 +47,7 @@ func LinkCstp(conn net.Conn, cSess *sessdata.ConnSession) {
|
||||||
base.Error(err)
|
base.Error(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
switch hdata[6] {
|
switch pl.Data[6] {
|
||||||
case 0x07: // KEEPALIVE
|
case 0x07: // KEEPALIVE
|
||||||
// do nothing
|
// do nothing
|
||||||
// base.Debug("recv keepalive", cSess.IpAddr)
|
// base.Debug("recv keepalive", cSess.IpAddr)
|
||||||
|
@ -57,19 +56,24 @@ func LinkCstp(conn net.Conn, cSess *sessdata.ConnSession) {
|
||||||
return
|
return
|
||||||
case 0x03: // DPD-REQ
|
case 0x03: // DPD-REQ
|
||||||
// base.Debug("recv DPD-REQ", cSess.IpAddr)
|
// base.Debug("recv DPD-REQ", cSess.IpAddr)
|
||||||
if payloadOutCstp(cSess, sessdata.LTypeIPData, 0x04, nil) {
|
pl.PType = 0x04
|
||||||
|
if payloadOutCstp(cSess, pl) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
case 0x04:
|
case 0x04:
|
||||||
// log.Println("recv DPD-RESP")
|
// log.Println("recv DPD-RESP")
|
||||||
case 0x00: // DATA
|
case 0x00: // DATA
|
||||||
dataLen = binary.BigEndian.Uint16(hdata[4:6]) // 4,5
|
// 获取数据长度
|
||||||
if payloadIn(cSess, sessdata.LTypeIPData, 0x00, hdata[8:8+dataLen]) {
|
dataLen = binary.BigEndian.Uint16(pl.Data[4:6]) // 4,5
|
||||||
|
// 去除数据头
|
||||||
|
copy(pl.Data, pl.Data[8:8+dataLen])
|
||||||
|
// 更新切片长度
|
||||||
|
pl.Data = pl.Data[:dataLen]
|
||||||
|
// pl.Data = append(pl.Data[:0], pl.Data[8:8+dataLen]...)
|
||||||
|
if payloadIn(cSess, pl) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
putByte(hb)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -83,37 +87,44 @@ func cstpWrite(conn net.Conn, cSess *sessdata.ConnSession) {
|
||||||
var (
|
var (
|
||||||
err error
|
err error
|
||||||
n int
|
n int
|
||||||
// header []byte
|
pl *sessdata.Payload
|
||||||
payload *sessdata.Payload
|
|
||||||
)
|
)
|
||||||
|
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case payload = <-cSess.PayloadOutCstp:
|
case pl = <-cSess.PayloadOutCstp:
|
||||||
case <-cSess.CloseChan:
|
case <-cSess.CloseChan:
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if payload.LType != sessdata.LTypeIPData {
|
if pl.LType != sessdata.LTypeIPData {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
h := []byte{'S', 'T', 'F', 0x01, 0x00, 0x00, payload.PType, 0x00}
|
if pl.PType == 0x00 {
|
||||||
hb := getByteZero()
|
// 获取数据长度
|
||||||
header := *hb
|
l := len(pl.Data)
|
||||||
header = append(header, h...)
|
// 先扩容 +8
|
||||||
if payload.PType == 0x00 { // data
|
pl.Data = pl.Data[:l+8]
|
||||||
binary.BigEndian.PutUint16(header[4:6], uint16(len(payload.Data)))
|
// 数据后移
|
||||||
header = append(header, payload.Data...)
|
copy(pl.Data[8:], pl.Data)
|
||||||
|
// 添加头信息
|
||||||
|
copy(pl.Data[:8], plHeader)
|
||||||
|
// 更新头长度
|
||||||
|
binary.BigEndian.PutUint16(pl.Data[4:6], uint16(l))
|
||||||
|
} else {
|
||||||
|
pl.Data = append(pl.Data[:0], plHeader...)
|
||||||
|
// 设置头类型
|
||||||
|
pl.Data[6] = pl.PType
|
||||||
}
|
}
|
||||||
n, err = conn.Write(header)
|
|
||||||
|
n, err = conn.Write(pl.Data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
base.Error("write err", err)
|
base.Error("write err", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
putByte(hb)
|
putPayload(pl)
|
||||||
putPayload(payload)
|
|
||||||
|
|
||||||
// 限流设置
|
// 限流设置
|
||||||
err = cSess.RateLimit(n, false)
|
err = cSess.RateLimit(n, false)
|
||||||
|
|
|
@ -24,21 +24,22 @@ func LinkDtls(conn net.Conn, cSess *sessdata.ConnSession) {
|
||||||
}()
|
}()
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
err error
|
||||||
|
n int
|
||||||
dead = time.Duration(cSess.CstpDpd+5) * time.Second
|
dead = time.Duration(cSess.CstpDpd+5) * time.Second
|
||||||
)
|
)
|
||||||
|
|
||||||
go dtlsWrite(conn, dSess, cSess)
|
go dtlsWrite(conn, dSess, cSess)
|
||||||
|
|
||||||
for {
|
for {
|
||||||
err := conn.SetReadDeadline(time.Now().Add(dead))
|
err = conn.SetReadDeadline(time.Now().Add(dead))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
base.Error("SetDeadline: ", err)
|
base.Error("SetDeadline: ", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
hb := getByteFull()
|
pl := getPayload()
|
||||||
hdata := *hb
|
n, err = conn.Read(pl.Data)
|
||||||
n, err := conn.Read(hdata)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
base.Error("read hdata: ", err)
|
base.Error("read hdata: ", err)
|
||||||
return
|
return
|
||||||
|
@ -50,7 +51,7 @@ func LinkDtls(conn net.Conn, cSess *sessdata.ConnSession) {
|
||||||
base.Error(err)
|
base.Error(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
switch hdata[0] {
|
switch pl.Data[0] {
|
||||||
case 0x07: // KEEPALIVE
|
case 0x07: // KEEPALIVE
|
||||||
// do nothing
|
// do nothing
|
||||||
// base.Debug("recv keepalive", cSess.IpAddr)
|
// base.Debug("recv keepalive", cSess.IpAddr)
|
||||||
|
@ -59,18 +60,23 @@ func LinkDtls(conn net.Conn, cSess *sessdata.ConnSession) {
|
||||||
return
|
return
|
||||||
case 0x03: // DPD-REQ
|
case 0x03: // DPD-REQ
|
||||||
// base.Debug("recv DPD-REQ", cSess.IpAddr)
|
// base.Debug("recv DPD-REQ", cSess.IpAddr)
|
||||||
if payloadOutDtls(cSess, dSess, sessdata.LTypeIPData, 0x04, nil) {
|
pl.PType = 0x04
|
||||||
|
if payloadOutDtls(cSess, dSess, pl) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
case 0x04:
|
case 0x04:
|
||||||
// base.Debug("recv DPD-RESP", cSess.IpAddr)
|
// base.Debug("recv DPD-RESP", cSess.IpAddr)
|
||||||
case 0x00: // DATA
|
case 0x00: // DATA
|
||||||
if payloadIn(cSess, sessdata.LTypeIPData, 0x00, hdata[1:n]) {
|
// 去除数据头
|
||||||
|
// copy(pl.Data, pl.Data[1:n])
|
||||||
|
// 更新切片长度
|
||||||
|
// pl.Data = pl.Data[:n-1]
|
||||||
|
pl.Data = append(pl.Data[:0], pl.Data[1:n]...)
|
||||||
|
if payloadIn(cSess, pl) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
putByte(hb)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -82,37 +88,42 @@ func dtlsWrite(conn net.Conn, dSess *sessdata.DtlsSession, cSess *sessdata.ConnS
|
||||||
}()
|
}()
|
||||||
|
|
||||||
var (
|
var (
|
||||||
// header []byte
|
pl *sessdata.Payload
|
||||||
payload *sessdata.Payload
|
|
||||||
)
|
)
|
||||||
|
|
||||||
for {
|
for {
|
||||||
// dtls优先推送数据
|
// dtls优先推送数据
|
||||||
select {
|
select {
|
||||||
case payload = <-cSess.PayloadOutDtls:
|
case pl = <-cSess.PayloadOutDtls:
|
||||||
case <-dSess.CloseChan:
|
case <-dSess.CloseChan:
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if payload.LType != sessdata.LTypeIPData {
|
if pl.LType != sessdata.LTypeIPData {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
// header = []byte{payload.PType}
|
// header = []byte{payload.PType}
|
||||||
hb := getByteZero()
|
if pl.PType == 0x00 { // data
|
||||||
header := *hb
|
// 获取数据长度
|
||||||
header = append(header, payload.PType)
|
l := len(pl.Data)
|
||||||
if payload.PType == 0x00 { // data
|
// 先扩容 +1
|
||||||
header = append(header, payload.Data...)
|
pl.Data = pl.Data[:l+1]
|
||||||
|
// 数据后移
|
||||||
|
copy(pl.Data[1:], pl.Data)
|
||||||
|
// 添加头信息
|
||||||
|
pl.Data[0] = pl.PType
|
||||||
|
} else {
|
||||||
|
// 设置头类型
|
||||||
|
pl.Data = append(pl.Data[:0], pl.PType)
|
||||||
}
|
}
|
||||||
n, err := conn.Write(header)
|
n, err := conn.Write(pl.Data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
base.Error("write err", err)
|
base.Error("write err", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
putByte(hb)
|
putPayload(pl)
|
||||||
putPayload(payload)
|
|
||||||
|
|
||||||
// 限流设置
|
// 限流设置
|
||||||
err = cSess.RateLimit(n, false)
|
err = cSess.RateLimit(n, false)
|
||||||
|
|
|
@ -88,14 +88,14 @@ func tapWrite(ifce *water.Interface, cSess *sessdata.ConnSession) {
|
||||||
}()
|
}()
|
||||||
|
|
||||||
var (
|
var (
|
||||||
err error
|
err error
|
||||||
payload *sessdata.Payload
|
pl *sessdata.Payload
|
||||||
frame ethernet.Frame
|
frame ethernet.Frame
|
||||||
)
|
)
|
||||||
|
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case payload = <-cSess.PayloadIn:
|
case pl = <-cSess.PayloadIn:
|
||||||
case <-cSess.CloseChan:
|
case <-cSess.CloseChan:
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -103,17 +103,15 @@ func tapWrite(ifce *water.Interface, cSess *sessdata.ConnSession) {
|
||||||
// var frame ethernet.Frame
|
// var frame ethernet.Frame
|
||||||
fb := getByteFull()
|
fb := getByteFull()
|
||||||
frame = *fb
|
frame = *fb
|
||||||
switch payload.LType {
|
switch pl.LType {
|
||||||
default:
|
default:
|
||||||
// log.Println(payload)
|
// log.Println(payload)
|
||||||
case sessdata.LTypeEthernet:
|
case sessdata.LTypeEthernet:
|
||||||
copy(frame, payload.Data)
|
copy(frame, pl.Data)
|
||||||
frame = frame[:len(payload.Data)]
|
frame = frame[:len(pl.Data)]
|
||||||
case sessdata.LTypeIPData: // 需要转换成 Ethernet 数据
|
case sessdata.LTypeIPData: // 需要转换成 Ethernet 数据
|
||||||
data := payload.Data
|
ip_src := waterutil.IPv4Source(pl.Data)
|
||||||
|
if waterutil.IsIPv6(pl.Data) || !ip_src.Equal(cSess.IpAddr) {
|
||||||
ip_src := waterutil.IPv4Source(data)
|
|
||||||
if waterutil.IsIPv6(data) || !ip_src.Equal(cSess.IpAddr) {
|
|
||||||
// 过滤掉IPv6的数据
|
// 过滤掉IPv6的数据
|
||||||
// 非分配给客户端ip,直接丢弃
|
// 非分配给客户端ip,直接丢弃
|
||||||
continue
|
continue
|
||||||
|
@ -122,7 +120,7 @@ func tapWrite(ifce *water.Interface, cSess *sessdata.ConnSession) {
|
||||||
// packet := gopacket.NewPacket(data, layers.LayerTypeIPv4, gopacket.Default)
|
// packet := gopacket.NewPacket(data, layers.LayerTypeIPv4, gopacket.Default)
|
||||||
// fmt.Println("get:", packet)
|
// fmt.Println("get:", packet)
|
||||||
|
|
||||||
ip_dst := waterutil.IPv4Destination(data)
|
ip_dst := waterutil.IPv4Destination(pl.Data)
|
||||||
// fmt.Println("get:", ip_src, ip_dst)
|
// fmt.Println("get:", ip_src, ip_dst)
|
||||||
|
|
||||||
var dstHw net.HardwareAddr
|
var dstHw net.HardwareAddr
|
||||||
|
@ -142,8 +140,8 @@ func tapWrite(ifce *water.Interface, cSess *sessdata.ConnSession) {
|
||||||
}
|
}
|
||||||
// fmt.Println("Gateway", ip_dst, dstAddr.HardwareAddr)
|
// fmt.Println("Gateway", ip_dst, dstAddr.HardwareAddr)
|
||||||
|
|
||||||
frame.Prepare(dstHw, cSess.MacHw, ethernet.NotTagged, ethernet.IPv4, len(data))
|
frame.Prepare(dstHw, cSess.MacHw, ethernet.NotTagged, ethernet.IPv4, len(pl.Data))
|
||||||
copy(frame[12+2:], data)
|
copy(frame[12+2:], pl.Data)
|
||||||
}
|
}
|
||||||
|
|
||||||
// packet := gopacket.NewPacket(frame, layers.LayerTypeEthernet, gopacket.Default)
|
// packet := gopacket.NewPacket(frame, layers.LayerTypeEthernet, gopacket.Default)
|
||||||
|
@ -155,7 +153,7 @@ func tapWrite(ifce *water.Interface, cSess *sessdata.ConnSession) {
|
||||||
}
|
}
|
||||||
|
|
||||||
putByte(fb)
|
putByte(fb)
|
||||||
putPayload(payload)
|
putPayload(pl)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -168,7 +166,7 @@ func tapRead(ifce *water.Interface, cSess *sessdata.ConnSession) {
|
||||||
var (
|
var (
|
||||||
err error
|
err error
|
||||||
n int
|
n int
|
||||||
buf []byte
|
data []byte
|
||||||
frame ethernet.Frame
|
frame ethernet.Frame
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -193,7 +191,7 @@ func tapRead(ifce *water.Interface, cSess *sessdata.ConnSession) {
|
||||||
continue
|
continue
|
||||||
case ethernet.IPv4:
|
case ethernet.IPv4:
|
||||||
// 发送IP数据
|
// 发送IP数据
|
||||||
data := frame.Payload()
|
data = frame.Payload()
|
||||||
|
|
||||||
ip_dst := waterutil.IPv4Destination(data)
|
ip_dst := waterutil.IPv4Destination(data)
|
||||||
if !ip_dst.Equal(cSess.IpAddr) {
|
if !ip_dst.Equal(cSess.IpAddr) {
|
||||||
|
@ -205,7 +203,12 @@ func tapRead(ifce *water.Interface, cSess *sessdata.ConnSession) {
|
||||||
// packet := gopacket.NewPacket(data, layers.LayerTypeIPv4, gopacket.Default)
|
// packet := gopacket.NewPacket(data, layers.LayerTypeIPv4, gopacket.Default)
|
||||||
// fmt.Println("put:", packet)
|
// fmt.Println("put:", packet)
|
||||||
|
|
||||||
if payloadOut(cSess, sessdata.LTypeIPData, 0x00, data) {
|
pl := getPayload()
|
||||||
|
// 拷贝数据到pl
|
||||||
|
copy(pl.Data, data)
|
||||||
|
// 更新切片长度
|
||||||
|
pl.Data = pl.Data[:len(data)]
|
||||||
|
if payloadOut(cSess, pl) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -226,7 +229,7 @@ func tapRead(ifce *water.Interface, cSess *sessdata.ConnSession) {
|
||||||
// 返回ARP数据
|
// 返回ARP数据
|
||||||
src := &arpdis.Addr{IP: cSess.IpAddr, HardwareAddr: cSess.MacHw}
|
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: frame.Source()}
|
||||||
buf, err = arpdis.NewARPReply(src, dst)
|
data, err = arpdis.NewARPReply(src, dst)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
base.Error(err)
|
base.Error(err)
|
||||||
return
|
return
|
||||||
|
@ -243,7 +246,15 @@ func tapRead(ifce *water.Interface, cSess *sessdata.ConnSession) {
|
||||||
copy(addr.HardwareAddr, frame.Source())
|
copy(addr.HardwareAddr, frame.Source())
|
||||||
arpdis.Add(addr)
|
arpdis.Add(addr)
|
||||||
|
|
||||||
if payloadIn(cSess, sessdata.LTypeEthernet, 0x00, buf) {
|
pl := getPayload()
|
||||||
|
// 设置为二层数据类型
|
||||||
|
pl.LType = sessdata.LTypeEthernet
|
||||||
|
// 拷贝数据到pl
|
||||||
|
copy(pl.Data, data)
|
||||||
|
// 更新切片长度
|
||||||
|
pl.Data = pl.Data[:len(data)]
|
||||||
|
|
||||||
|
if payloadIn(cSess, pl) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -69,24 +69,24 @@ func tunWrite(ifce *water.Interface, cSess *sessdata.ConnSession) {
|
||||||
}()
|
}()
|
||||||
|
|
||||||
var (
|
var (
|
||||||
err error
|
err error
|
||||||
payload *sessdata.Payload
|
pl *sessdata.Payload
|
||||||
)
|
)
|
||||||
|
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case payload = <-cSess.PayloadIn:
|
case pl = <-cSess.PayloadIn:
|
||||||
case <-cSess.CloseChan:
|
case <-cSess.CloseChan:
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = ifce.Write(payload.Data)
|
_, err = ifce.Write(pl.Data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
base.Error("tun Write err", err)
|
base.Error("tun Write err", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
putPayload(payload)
|
putPayload(pl)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -102,14 +102,16 @@ func tunRead(ifce *water.Interface, cSess *sessdata.ConnSession) {
|
||||||
|
|
||||||
for {
|
for {
|
||||||
// data := make([]byte, BufferSize)
|
// data := make([]byte, BufferSize)
|
||||||
hb := getByteFull()
|
pl := getPayload()
|
||||||
data := *hb
|
n, err = ifce.Read(pl.Data)
|
||||||
n, err = ifce.Read(data)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
base.Error("tun Read err", n, err)
|
base.Error("tun Read err", n, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 更新数据长度
|
||||||
|
pl.Data = (pl.Data)[:n]
|
||||||
|
|
||||||
// data = data[:n]
|
// data = data[:n]
|
||||||
// ip_src := waterutil.IPv4Source(data)
|
// ip_src := waterutil.IPv4Source(data)
|
||||||
// ip_dst := waterutil.IPv4Destination(data)
|
// ip_dst := waterutil.IPv4Destination(data)
|
||||||
|
@ -118,10 +120,8 @@ func tunRead(ifce *water.Interface, cSess *sessdata.ConnSession) {
|
||||||
// packet := gopacket.NewPacket(data, layers.LayerTypeIPv4, gopacket.Default)
|
// packet := gopacket.NewPacket(data, layers.LayerTypeIPv4, gopacket.Default)
|
||||||
// fmt.Println("read:", packet)
|
// fmt.Println("read:", packet)
|
||||||
|
|
||||||
if payloadOut(cSess, sessdata.LTypeIPData, 0x00, data[:n]) {
|
if payloadOut(cSess, pl) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
putByte(hb)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,18 +6,9 @@ import (
|
||||||
"github.com/songgao/water/waterutil"
|
"github.com/songgao/water/waterutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
func payloadIn(cSess *sessdata.ConnSession, lType sessdata.LType, pType byte, data []byte) bool {
|
func payloadIn(cSess *sessdata.ConnSession, pl *sessdata.Payload) bool {
|
||||||
pl := getPayload()
|
|
||||||
pl.LType = lType
|
|
||||||
pl.PType = pType
|
|
||||||
pl.Data = append(pl.Data, data...)
|
|
||||||
|
|
||||||
return payloadInData(cSess, pl)
|
|
||||||
}
|
|
||||||
|
|
||||||
func payloadInData(cSess *sessdata.ConnSession, payload *sessdata.Payload) bool {
|
|
||||||
// 进行Acl规则判断
|
// 进行Acl规则判断
|
||||||
check := checkLinkAcl(cSess.Group, payload)
|
check := checkLinkAcl(cSess.Group, pl)
|
||||||
if !check {
|
if !check {
|
||||||
// 校验不通过直接丢弃
|
// 校验不通过直接丢弃
|
||||||
return false
|
return false
|
||||||
|
@ -25,7 +16,7 @@ func payloadInData(cSess *sessdata.ConnSession, payload *sessdata.Payload) bool
|
||||||
|
|
||||||
closed := false
|
closed := false
|
||||||
select {
|
select {
|
||||||
case cSess.PayloadIn <- payload:
|
case cSess.PayloadIn <- pl:
|
||||||
case <-cSess.CloseChan:
|
case <-cSess.CloseChan:
|
||||||
closed = true
|
closed = true
|
||||||
}
|
}
|
||||||
|
@ -33,21 +24,16 @@ func payloadInData(cSess *sessdata.ConnSession, payload *sessdata.Payload) bool
|
||||||
return closed
|
return closed
|
||||||
}
|
}
|
||||||
|
|
||||||
func payloadOut(cSess *sessdata.ConnSession, lType sessdata.LType, pType byte, data []byte) bool {
|
func payloadOut(cSess *sessdata.ConnSession, pl *sessdata.Payload) bool {
|
||||||
dSess := cSess.GetDtlsSession()
|
dSess := cSess.GetDtlsSession()
|
||||||
if dSess == nil {
|
if dSess == nil {
|
||||||
return payloadOutCstp(cSess, lType, pType, data)
|
return payloadOutCstp(cSess, pl)
|
||||||
} else {
|
} else {
|
||||||
return payloadOutDtls(cSess, dSess, lType, pType, data)
|
return payloadOutDtls(cSess, dSess, pl)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func payloadOutCstp(cSess *sessdata.ConnSession, lType sessdata.LType, pType byte, data []byte) bool {
|
func payloadOutCstp(cSess *sessdata.ConnSession, pl *sessdata.Payload) bool {
|
||||||
pl := getPayload()
|
|
||||||
pl.LType = lType
|
|
||||||
pl.PType = pType
|
|
||||||
pl.Data = append(pl.Data, data...)
|
|
||||||
|
|
||||||
closed := false
|
closed := false
|
||||||
|
|
||||||
select {
|
select {
|
||||||
|
@ -59,12 +45,7 @@ func payloadOutCstp(cSess *sessdata.ConnSession, lType sessdata.LType, pType byt
|
||||||
return closed
|
return closed
|
||||||
}
|
}
|
||||||
|
|
||||||
func payloadOutDtls(cSess *sessdata.ConnSession, dSess *sessdata.DtlsSession, lType sessdata.LType, pType byte, data []byte) bool {
|
func payloadOutDtls(cSess *sessdata.ConnSession, dSess *sessdata.DtlsSession, pl *sessdata.Payload) bool {
|
||||||
pl := getPayload()
|
|
||||||
pl.LType = lType
|
|
||||||
pl.PType = pType
|
|
||||||
pl.Data = append(pl.Data, data...)
|
|
||||||
|
|
||||||
select {
|
select {
|
||||||
case cSess.PayloadOutDtls <- pl:
|
case cSess.PayloadOutDtls <- pl:
|
||||||
case <-dSess.CloseChan:
|
case <-dSess.CloseChan:
|
||||||
|
@ -74,15 +55,16 @@ func payloadOutDtls(cSess *sessdata.ConnSession, dSess *sessdata.DtlsSession, lT
|
||||||
}
|
}
|
||||||
|
|
||||||
// Acl规则校验
|
// Acl规则校验
|
||||||
func checkLinkAcl(group *dbdata.Group, payload *sessdata.Payload) bool {
|
func checkLinkAcl(group *dbdata.Group, pl *sessdata.Payload) bool {
|
||||||
if payload.LType == sessdata.LTypeIPData && payload.PType == 0x00 && len(group.LinkAcl) > 0 {
|
if pl.LType == sessdata.LTypeIPData && pl.PType == 0x00 && len(group.LinkAcl) > 0 {
|
||||||
} else {
|
} else {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
ip_dst := waterutil.IPv4Destination(payload.Data)
|
data := pl.Data
|
||||||
ip_port := waterutil.IPv4DestinationPort(payload.Data)
|
ip_dst := waterutil.IPv4Destination(data)
|
||||||
ip_proto := waterutil.IPv4Protocol(payload.Data)
|
ip_port := waterutil.IPv4DestinationPort(data)
|
||||||
|
ip_proto := waterutil.IPv4Protocol(data)
|
||||||
// fmt.Println("sent:", ip_dst, ip_port)
|
// fmt.Println("sent:", ip_dst, ip_port)
|
||||||
|
|
||||||
// 优先放行dns端口
|
// 优先放行dns端口
|
||||||
|
|
|
@ -3,13 +3,21 @@ package handler
|
||||||
import (
|
import (
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
|
"github.com/bjdgyc/anylink/base"
|
||||||
"github.com/bjdgyc/anylink/sessdata"
|
"github.com/bjdgyc/anylink/sessdata"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// 不允许直接修改
|
||||||
|
// [6] => PType
|
||||||
|
var plHeader = []byte{'S', 'T', 'F', 0x01, 0x00, 0x00, 0x00, 0x00}
|
||||||
|
|
||||||
var plPool = sync.Pool{
|
var plPool = sync.Pool{
|
||||||
New: func() interface{} {
|
New: func() interface{} {
|
||||||
|
b := make([]byte, BufferSize)
|
||||||
pl := sessdata.Payload{
|
pl := sessdata.Payload{
|
||||||
Data: make([]byte, 0, BufferSize),
|
LType: sessdata.LTypeIPData,
|
||||||
|
PType: 0x00,
|
||||||
|
Data: b,
|
||||||
}
|
}
|
||||||
// fmt.Println("plPool-init", len(pl.Data), cap(pl.Data))
|
// fmt.Println("plPool-init", len(pl.Data), cap(pl.Data))
|
||||||
return &pl
|
return &pl
|
||||||
|
@ -22,15 +30,21 @@ func getPayload() *sessdata.Payload {
|
||||||
}
|
}
|
||||||
|
|
||||||
func putPayload(pl *sessdata.Payload) {
|
func putPayload(pl *sessdata.Payload) {
|
||||||
pl.LType = 0
|
// 错误数据丢弃
|
||||||
pl.PType = 0
|
if cap(pl.Data) != BufferSize {
|
||||||
pl.Data = pl.Data[:0]
|
base.Warn("payload cap is err", cap(pl.Data))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
pl.LType = sessdata.LTypeIPData
|
||||||
|
pl.PType = 0x00
|
||||||
|
pl.Data = pl.Data[:BufferSize]
|
||||||
plPool.Put(pl)
|
plPool.Put(pl)
|
||||||
}
|
}
|
||||||
|
|
||||||
var bytePool = sync.Pool{
|
var bytePool = sync.Pool{
|
||||||
New: func() interface{} {
|
New: func() interface{} {
|
||||||
b := make([]byte, 0, BufferSize)
|
b := make([]byte, BufferSize)
|
||||||
// fmt.Println("bytePool-init")
|
// fmt.Println("bytePool-init")
|
||||||
return &b
|
return &b
|
||||||
},
|
},
|
||||||
|
@ -38,15 +52,15 @@ var bytePool = sync.Pool{
|
||||||
|
|
||||||
func getByteZero() *[]byte {
|
func getByteZero() *[]byte {
|
||||||
b := bytePool.Get().(*[]byte)
|
b := bytePool.Get().(*[]byte)
|
||||||
|
*b = (*b)[:0]
|
||||||
return b
|
return b
|
||||||
}
|
}
|
||||||
|
|
||||||
func getByteFull() *[]byte {
|
func getByteFull() *[]byte {
|
||||||
b := bytePool.Get().(*[]byte)
|
b := bytePool.Get().(*[]byte)
|
||||||
*b = (*b)[:BufferSize]
|
|
||||||
return b
|
return b
|
||||||
}
|
}
|
||||||
func putByte(b *[]byte) {
|
func putByte(b *[]byte) {
|
||||||
*b = (*b)[:0]
|
*b = (*b)[:BufferSize]
|
||||||
bytePool.Put(b)
|
bytePool.Put(b)
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,8 +8,8 @@ const (
|
||||||
)
|
)
|
||||||
|
|
||||||
type Payload struct {
|
type Payload struct {
|
||||||
PType byte // payload types
|
|
||||||
LType LType // LinkType
|
LType LType // LinkType
|
||||||
|
PType byte // payload types
|
||||||
Data []byte
|
Data []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -181,18 +181,20 @@
|
||||||
<el-col :span="4">
|
<el-col :span="4">
|
||||||
<el-button size="mini" type="success" icon="el-icon-plus" circle
|
<el-button size="mini" type="success" icon="el-icon-plus" circle
|
||||||
@click.prevent="addDomain(ruleForm.client_dns)"></el-button>
|
@click.prevent="addDomain(ruleForm.client_dns)"></el-button>
|
||||||
<el-button size="mini" type="danger" icon="el-icon-minus" circle
|
|
||||||
@click.prevent="removeDomain(ruleForm.client_dns)"></el-button>
|
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
<el-row v-for="(item,index) in ruleForm.client_dns"
|
<el-row v-for="(item,index) in ruleForm.client_dns"
|
||||||
:key="index" style="margin-bottom: 5px" gutter="10">
|
:key="index" style="margin-bottom: 5px" :gutter="10">
|
||||||
<el-col :span="10">
|
<el-col :span="10">
|
||||||
<el-input v-model="item.val"></el-input>
|
<el-input v-model="item.val"></el-input>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="14">
|
<el-col :span="12">
|
||||||
<el-input v-model="item.note" placeholder="备注"></el-input>
|
<el-input v-model="item.note" placeholder="备注"></el-input>
|
||||||
</el-col>
|
</el-col>
|
||||||
|
<el-col :span="2">
|
||||||
|
<el-button size="mini" type="danger" icon="el-icon-minus" circle
|
||||||
|
@click.prevent="removeDomain(ruleForm.client_dns,index)"></el-button>
|
||||||
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
|
@ -202,18 +204,20 @@
|
||||||
<el-col :span="4">
|
<el-col :span="4">
|
||||||
<el-button size="mini" type="success" icon="el-icon-plus" circle
|
<el-button size="mini" type="success" icon="el-icon-plus" circle
|
||||||
@click.prevent="addDomain(ruleForm.route_include)"></el-button>
|
@click.prevent="addDomain(ruleForm.route_include)"></el-button>
|
||||||
<el-button size="mini" type="danger" icon="el-icon-minus" circle
|
|
||||||
@click.prevent="removeDomain(ruleForm.route_include)"></el-button>
|
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
<el-row v-for="(item,index) in ruleForm.route_include"
|
<el-row v-for="(item,index) in ruleForm.route_include"
|
||||||
:key="index" style="margin-bottom: 5px" gutter="10">
|
:key="index" style="margin-bottom: 5px" :gutter="10">
|
||||||
<el-col :span="10">
|
<el-col :span="10">
|
||||||
<el-input v-model="item.val"></el-input>
|
<el-input v-model="item.val"></el-input>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="14">
|
<el-col :span="12">
|
||||||
<el-input v-model="item.note" placeholder="备注"></el-input>
|
<el-input v-model="item.note" placeholder="备注"></el-input>
|
||||||
</el-col>
|
</el-col>
|
||||||
|
<el-col :span="2">
|
||||||
|
<el-button size="mini" type="danger" icon="el-icon-minus" circle
|
||||||
|
@click.prevent="removeDomain(ruleForm.route_include,index)"></el-button>
|
||||||
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
|
@ -223,18 +227,20 @@
|
||||||
<el-col :span="4">
|
<el-col :span="4">
|
||||||
<el-button size="mini" type="success" icon="el-icon-plus" circle
|
<el-button size="mini" type="success" icon="el-icon-plus" circle
|
||||||
@click.prevent="addDomain(ruleForm.route_exclude)"></el-button>
|
@click.prevent="addDomain(ruleForm.route_exclude)"></el-button>
|
||||||
<el-button size="mini" type="danger" icon="el-icon-minus" circle
|
|
||||||
@click.prevent="removeDomain(ruleForm.route_exclude)"></el-button>
|
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
<el-row v-for="(item,index) in ruleForm.route_exclude"
|
<el-row v-for="(item,index) in ruleForm.route_exclude"
|
||||||
:key="index" style="margin-bottom: 5px" gutter="10">
|
:key="index" style="margin-bottom: 5px" :gutter="10">
|
||||||
<el-col :span="10">
|
<el-col :span="10">
|
||||||
<el-input v-model="item.val"></el-input>
|
<el-input v-model="item.val"></el-input>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="14">
|
<el-col :span="12">
|
||||||
<el-input v-model="item.note" placeholder="备注"></el-input>
|
<el-input v-model="item.note" placeholder="备注"></el-input>
|
||||||
</el-col>
|
</el-col>
|
||||||
|
<el-col :span="2">
|
||||||
|
<el-button size="mini" type="danger" icon="el-icon-minus" circle
|
||||||
|
@click.prevent="removeDomain(ruleForm.route_exclude,index)"></el-button>
|
||||||
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
|
@ -244,13 +250,11 @@
|
||||||
<el-col :span="4">
|
<el-col :span="4">
|
||||||
<el-button size="mini" type="success" icon="el-icon-plus" circle
|
<el-button size="mini" type="success" icon="el-icon-plus" circle
|
||||||
@click.prevent="addDomain(ruleForm.link_acl)"></el-button>
|
@click.prevent="addDomain(ruleForm.link_acl)"></el-button>
|
||||||
<el-button size="mini" type="danger" icon="el-icon-minus" circle
|
|
||||||
@click.prevent="removeDomain(ruleForm.link_acl)"></el-button>
|
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
|
|
||||||
<el-row v-for="(item,index) in ruleForm.link_acl"
|
<el-row v-for="(item,index) in ruleForm.link_acl"
|
||||||
:key="index" style="margin-bottom: 5px" gutter="5">
|
:key="index" style="margin-bottom: 5px" :gutter="5">
|
||||||
<el-col :span="11">
|
<el-col :span="11">
|
||||||
<el-input placeholder="请输入CIDR地址" v-model="item.val">
|
<el-input placeholder="请输入CIDR地址" v-model="item.val">
|
||||||
<el-select v-model="item.action" slot="prepend">
|
<el-select v-model="item.action" slot="prepend">
|
||||||
|
@ -262,9 +266,13 @@
|
||||||
<el-col :span="3">
|
<el-col :span="3">
|
||||||
<el-input v-model.number="item.port" placeholder="端口"></el-input>
|
<el-input v-model.number="item.port" placeholder="端口"></el-input>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="10">
|
<el-col :span="8">
|
||||||
<el-input v-model="item.note" placeholder="备注"></el-input>
|
<el-input v-model="item.note" placeholder="备注"></el-input>
|
||||||
</el-col>
|
</el-col>
|
||||||
|
<el-col :span="2">
|
||||||
|
<el-button size="mini" type="danger" icon="el-icon-minus" circle
|
||||||
|
@click.prevent="removeDomain(ruleForm.link_acl,index)"></el-button>
|
||||||
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
|
@ -389,13 +397,16 @@ export default {
|
||||||
console.log(error);
|
console.log(error);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
removeDomain(arr, item) {
|
removeDomain(arr, index) {
|
||||||
console.log(item)
|
console.log(index)
|
||||||
|
if (index >= 0 && index < arr.length) {
|
||||||
|
arr.splice(index, 1)
|
||||||
|
}
|
||||||
// let index = arr.indexOf(item);
|
// let index = arr.indexOf(item);
|
||||||
// if (index !== -1 && arr.length > 1) {
|
// if (index !== -1 && arr.length > 1) {
|
||||||
// arr.splice(index, 1)
|
// arr.splice(index, 1)
|
||||||
// }
|
// }
|
||||||
arr.pop()
|
// arr.pop()
|
||||||
},
|
},
|
||||||
addDomain(arr) {
|
addDomain(arr) {
|
||||||
arr.push({val: "", action: "allow", port: 0});
|
arr.push({val: "", action: "allow", port: 0});
|
||||||
|
|
Loading…
Reference in New Issue