mirror of
				https://github.com/bjdgyc/anylink.git
				synced 2025-11-01 00:59:34 +08:00 
			
		
		
		
	升级go version 1.16,ui文件嵌入go二进制内
This commit is contained in:
		
							
								
								
									
										2
									
								
								.github/workflows/go.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.github/workflows/go.yml
									
									
									
									
										vendored
									
									
								
							| @@ -16,7 +16,7 @@ jobs: | |||||||
|     - name: Set up Go 1.x |     - name: Set up Go 1.x | ||||||
|       uses: actions/setup-go@v2 |       uses: actions/setup-go@v2 | ||||||
|       with: |       with: | ||||||
|         go-version: ^1.14 |         go-version: ^1.16 | ||||||
|       id: go |       id: go | ||||||
|  |  | ||||||
|     - name: Check out code into the Go module directory |     - name: Check out code into the Go module directory | ||||||
|   | |||||||
							
								
								
									
										82
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										82
									
								
								README.md
									
									
									
									
									
								
							| @@ -21,11 +21,13 @@ AnyLink 服务端仅在CentOS7测试通过,如需要安装在其他系统, | |||||||
|  |  | ||||||
| ## Screenshot | ## Screenshot | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| ## Installation | ## Installation | ||||||
|  |  | ||||||
| ``` | > 升级 go version >= 1.16 | ||||||
|  |  | ||||||
|  | ```shell | ||||||
| rootPath=`pwd` | rootPath=`pwd` | ||||||
|  |  | ||||||
| git clone https://github.com/bjdgyc/anylink.git | git clone https://github.com/bjdgyc/anylink.git | ||||||
| @@ -36,12 +38,13 @@ npm install | |||||||
| npm run build | npm run build | ||||||
|  |  | ||||||
| cd $rootPath/anylink | cd $rootPath/anylink | ||||||
|  | cp -r $rootPath/anylink-web/ui . | ||||||
| go build -o anylink -ldflags "-X main.COMMIT_ID=`git rev-parse HEAD`" | go build -o anylink -ldflags "-X main.COMMIT_ID=`git rev-parse HEAD`" | ||||||
|  |  | ||||||
| #整理部署文件 | #整理部署文件 | ||||||
| mkdir $rootPath/anylink-deploy | mkdir $rootPath/anylink-deploy | ||||||
| cd $rootPath/anylink-deploy | cd $rootPath/anylink-deploy | ||||||
| cp -r $rootPath/anylink-web/ui . |  | ||||||
| cp -r $rootPath/anylink/anylink . | cp -r $rootPath/anylink/anylink . | ||||||
| cp -r $rootPath/anylink/conf . | cp -r $rootPath/anylink/conf . | ||||||
| cp -r $rootPath/anylink/downfiles . | cp -r $rootPath/anylink/downfiles . | ||||||
| @@ -71,7 +74,15 @@ sudo ./anylink -conf="conf/server.toml" | |||||||
|  |  | ||||||
| 默认配置文件内有详细的注释,根据注释填写配置即可。 | 默认配置文件内有详细的注释,根据注释填写配置即可。 | ||||||
|  |  | ||||||
| - [conf/server.toml](https://github.com/bjdgyc/anylink/blob/master/conf/server.toml) | ```shell | ||||||
|  | # 生成后台密码 | ||||||
|  | ./anylink -passwd 123456 | ||||||
|  |  | ||||||
|  | # 生成jwt密钥 | ||||||
|  | ./anylink -secret | ||||||
|  | ``` | ||||||
|  |  | ||||||
|  | [conf/server.toml](https://github.com/bjdgyc/anylink/blob/master/conf/server.toml) | ||||||
|  |  | ||||||
| ## Setting | ## Setting | ||||||
|  |  | ||||||
| @@ -82,43 +93,48 @@ sudo ./anylink -conf="conf/server.toml" | |||||||
| ### tun设置 | ### tun设置 | ||||||
|  |  | ||||||
| 1. 开启服务器转发 | 1. 开启服务器转发 | ||||||
|     ``` |  | ||||||
|     # flie: /etc/sysctl.conf |  | ||||||
|     net.ipv4.ip_forward = 1 |  | ||||||
|  |  | ||||||
|     #执行如下命令 |  ```shell | ||||||
|     sysctl -w net.ipv4.ip_forward=1 |  # flie: /etc/sysctl.conf | ||||||
|     ``` |  net.ipv4.ip_forward = 1 | ||||||
|  |  | ||||||
|  |  #执行如下命令 | ||||||
|  |  sysctl -w net.ipv4.ip_forward=1 | ||||||
|  |  ``` | ||||||
|  |  | ||||||
| 2. 设置nat转发规则 | 2. 设置nat转发规则 | ||||||
|     ``` |  | ||||||
|     # eth0为服务器内网网卡 | ```shell | ||||||
|     iptables -t nat -A POSTROUTING -s 192.168.10.0/255.255.255.0 -o eth0 -j MASQUERADE | # eth0为服务器内网网卡 | ||||||
|     ``` | iptables -t nat -A POSTROUTING -s 192.168.10.0/255.255.255.0 -o eth0 -j MASQUERADE | ||||||
|  | ``` | ||||||
|  |  | ||||||
| 3. 使用AnyConnect客户端连接即可 | 3. 使用AnyConnect客户端连接即可 | ||||||
|  |  | ||||||
| ### tap设置 | ### tap设置 | ||||||
|  |  | ||||||
| 1. 创建桥接网卡 | 1. 创建桥接网卡 | ||||||
|     ``` |  | ||||||
|     注意 server.toml 的ip参数,需要与 bridge.sh 的配置参数一致 | ``` | ||||||
|     ``` | 注意 server.toml 的ip参数,需要与 bridge.sh 的配置参数一致 | ||||||
|  | ``` | ||||||
|  |  | ||||||
| 2. 修改 bridge.sh 内的参数 | 2. 修改 bridge.sh 内的参数 | ||||||
|     ``` |  | ||||||
|     # file: ./bridge.sh | ``` | ||||||
|     eth="eth0" | # file: ./bridge.sh | ||||||
|     eth_ip="192.168.1.4" | eth="eth0" | ||||||
|     eth_netmask="255.255.255.0" | eth_ip="192.168.1.4" | ||||||
|     eth_broadcast="192.168.1.255" | eth_netmask="255.255.255.0" | ||||||
|     eth_gateway="192.168.1.1" | eth_broadcast="192.168.1.255" | ||||||
|     ``` | eth_gateway="192.168.1.1" | ||||||
|  | ``` | ||||||
|  |  | ||||||
| 3. 执行 bridge.sh 文件 | 3. 执行 bridge.sh 文件 | ||||||
|     ``` |  | ||||||
|     sh bridge.sh | ``` | ||||||
|     ``` | sh bridge.sh | ||||||
|  | ``` | ||||||
|  |  | ||||||
| ## Soft | ## Soft | ||||||
|  |  | ||||||
| @@ -126,11 +142,11 @@ sudo ./anylink -conf="conf/server.toml" | |||||||
|  |  | ||||||
| ## Other Screenshot | ## Other Screenshot | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| ## License | ## License | ||||||
|  |  | ||||||
|   | |||||||
| @@ -5,9 +5,8 @@ import ( | |||||||
| 	"net/http" | 	"net/http" | ||||||
| 	"time" | 	"time" | ||||||
|  |  | ||||||
| 	"github.com/bjdgyc/anylink/pkg/utils" |  | ||||||
|  |  | ||||||
| 	"github.com/bjdgyc/anylink/base" | 	"github.com/bjdgyc/anylink/base" | ||||||
|  | 	"github.com/bjdgyc/anylink/pkg/utils" | ||||||
| 	"github.com/gorilla/mux" | 	"github.com/gorilla/mux" | ||||||
| ) | ) | ||||||
|  |  | ||||||
|   | |||||||
| @@ -2,6 +2,7 @@ | |||||||
| package admin | package admin | ||||||
|  |  | ||||||
| import ( | import ( | ||||||
|  | 	"embed" | ||||||
| 	"net/http" | 	"net/http" | ||||||
| 	"net/http/pprof" | 	"net/http/pprof" | ||||||
|  |  | ||||||
| @@ -9,11 +10,20 @@ import ( | |||||||
| 	"github.com/gorilla/mux" | 	"github.com/gorilla/mux" | ||||||
| ) | ) | ||||||
|  |  | ||||||
|  | var UiPath embed.FS | ||||||
|  |  | ||||||
| // 开启服务 | // 开启服务 | ||||||
| func StartAdmin() { | func StartAdmin() { | ||||||
|  |  | ||||||
| 	r := mux.NewRouter() | 	r := mux.NewRouter() | ||||||
| 	r.Use(authMiddleware) | 	r.Use(authMiddleware) | ||||||
|  |  | ||||||
|  | 	r.Handle("/", http.RedirectHandler("/ui/", http.StatusFound)). | ||||||
|  | 		Name("static") | ||||||
|  | 	r.PathPrefix("/ui/").Handler(http.FileServer( | ||||||
|  | 		http.FS(UiPath), | ||||||
|  | 	)).Name("static") | ||||||
|  |  | ||||||
| 	r.HandleFunc("/base/login", Login).Name("login") | 	r.HandleFunc("/base/login", Login).Name("login") | ||||||
| 	r.HandleFunc("/set/home", SetHome) | 	r.HandleFunc("/set/home", SetHome) | ||||||
| 	r.HandleFunc("/set/system", SetSystem) | 	r.HandleFunc("/set/system", SetSystem) | ||||||
| @@ -49,8 +59,6 @@ func StartAdmin() { | |||||||
| 	r.HandleFunc("/debug/pprof", location("/debug/pprof/")) | 	r.HandleFunc("/debug/pprof", location("/debug/pprof/")) | ||||||
| 	r.PathPrefix("/debug/pprof/").HandlerFunc(pprof.Index) | 	r.PathPrefix("/debug/pprof/").HandlerFunc(pprof.Index) | ||||||
|  |  | ||||||
| 	r.PathPrefix("/").Handler(http.FileServer(http.Dir(base.Cfg.UiPath))).Name("static") |  | ||||||
|  |  | ||||||
| 	base.Info("Listen admin", base.Cfg.AdminAddr) | 	base.Info("Listen admin", base.Cfg.AdminAddr) | ||||||
| 	err := http.ListenAndServe(base.Cfg.AdminAddr, r) | 	err := http.ListenAndServe(base.Cfg.AdminAddr, r) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
|   | |||||||
| @@ -3,6 +3,7 @@ package base | |||||||
| import ( | import ( | ||||||
| 	"fmt" | 	"fmt" | ||||||
| 	"io/ioutil" | 	"io/ioutil" | ||||||
|  | 	"os" | ||||||
| 	"path/filepath" | 	"path/filepath" | ||||||
| 	"reflect" | 	"reflect" | ||||||
| 	"strings" | 	"strings" | ||||||
| @@ -38,8 +39,7 @@ type ServerConfig struct { | |||||||
| 	DbFile        string `toml:"db_file" info:"数据库地址"` | 	DbFile        string `toml:"db_file" info:"数据库地址"` | ||||||
| 	CertFile      string `toml:"cert_file" info:"证书文件"` | 	CertFile      string `toml:"cert_file" info:"证书文件"` | ||||||
| 	CertKey       string `toml:"cert_key" info:"证书密钥"` | 	CertKey       string `toml:"cert_key" info:"证书密钥"` | ||||||
| 	UiPath        string `toml:"ui_path" info:"ui文件路径"` | 	DownFilesPath string `json:"down_files_path" info:"外部下载文件路径"` | ||||||
| 	FilesPath     string `toml:"files_path" info:"外部下载文件路径"` |  | ||||||
| 	LogLevel      string `toml:"log_level" info:"日志等级"` | 	LogLevel      string `toml:"log_level" info:"日志等级"` | ||||||
| 	Issuer        string `toml:"issuer" info:"系统名称"` | 	Issuer        string `toml:"issuer" info:"系统名称"` | ||||||
| 	AdminUser     string `toml:"admin_user" info:"管理用户名"` | 	AdminUser     string `toml:"admin_user" info:"管理用户名"` | ||||||
| @@ -82,8 +82,12 @@ func initServerCfg() { | |||||||
| 	Cfg.DbFile = getAbsPath(base, Cfg.DbFile) | 	Cfg.DbFile = getAbsPath(base, Cfg.DbFile) | ||||||
| 	Cfg.CertFile = getAbsPath(base, Cfg.CertFile) | 	Cfg.CertFile = getAbsPath(base, Cfg.CertFile) | ||||||
| 	Cfg.CertKey = getAbsPath(base, Cfg.CertKey) | 	Cfg.CertKey = getAbsPath(base, Cfg.CertKey) | ||||||
| 	Cfg.UiPath = getAbsPath(base, Cfg.UiPath) | 	Cfg.DownFilesPath = getAbsPath(base, Cfg.DownFilesPath) | ||||||
| 	Cfg.FilesPath = getAbsPath(base, Cfg.FilesPath) |  | ||||||
|  | 	if len(Cfg.JwtSecret) < 20 { | ||||||
|  | 		fmt.Println("请设置 jwt_secret 长度20位以上") | ||||||
|  | 		os.Exit(0) | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	fmt.Printf("ServerCfg: %+v \n", Cfg) | 	fmt.Printf("ServerCfg: %+v \n", Cfg) | ||||||
| } | } | ||||||
|   | |||||||
							
								
								
									
										16
									
								
								base/flag.go
									
									
									
									
									
								
							
							
						
						
									
										16
									
								
								base/flag.go
									
									
									
									
									
								
							| @@ -3,8 +3,11 @@ package base | |||||||
| import ( | import ( | ||||||
| 	"flag" | 	"flag" | ||||||
| 	"fmt" | 	"fmt" | ||||||
|  | 	"math/rand" | ||||||
| 	"os" | 	"os" | ||||||
| 	"runtime" | 	"runtime" | ||||||
|  | 	"strings" | ||||||
|  | 	"time" | ||||||
|  |  | ||||||
| 	"github.com/bjdgyc/anylink/pkg/utils" | 	"github.com/bjdgyc/anylink/pkg/utils" | ||||||
| ) | ) | ||||||
| @@ -16,13 +19,16 @@ var ( | |||||||
| 	serverFile string | 	serverFile string | ||||||
| 	// pass明文 | 	// pass明文 | ||||||
| 	passwd string | 	passwd string | ||||||
|  | 	// 生成密钥 | ||||||
|  | 	secret bool | ||||||
| 	// 显示版本信息 | 	// 显示版本信息 | ||||||
| 	rev bool | 	rev bool | ||||||
| ) | ) | ||||||
|  |  | ||||||
| func initFlag() { | func initFlag() { | ||||||
| 	flag.StringVar(&serverFile, "conf", "./conf/server.toml", "server config file path") | 	flag.StringVar(&serverFile, "conf", "./conf/server.toml", "server config file path") | ||||||
| 	flag.StringVar(&passwd, "passwd", "", "the password plaintext") | 	flag.StringVar(&passwd, "passwd", "", "convert the password plaintext") | ||||||
|  | 	flag.BoolVar(&secret, "secret", false, "generate a random jwt secret") | ||||||
| 	flag.BoolVar(&rev, "rev", false, "display version info") | 	flag.BoolVar(&rev, "rev", false, "display version info") | ||||||
| 	flag.Parse() | 	flag.Parse() | ||||||
|  |  | ||||||
| @@ -32,6 +38,14 @@ func initFlag() { | |||||||
| 		os.Exit(0) | 		os.Exit(0) | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	if secret { | ||||||
|  | 		rand.Seed(time.Now().UnixNano()) | ||||||
|  | 		s, _ := utils.RandSecret(40, 60) | ||||||
|  | 		s = strings.Trim(s, "=") | ||||||
|  | 		fmt.Printf("Secret:%s\n", s) | ||||||
|  | 		os.Exit(0) | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	if rev { | 	if rev { | ||||||
| 		fmt.Printf("%s v%s build on %s [%s, %s] commit_id(%s) \n", | 		fmt.Printf("%s v%s build on %s [%s, %s] commit_id(%s) \n", | ||||||
| 			APP_NAME, APP_VER, runtime.Version(), runtime.GOOS, runtime.GOARCH, CommitId) | 			APP_NAME, APP_VER, runtime.Version(), runtime.GOOS, runtime.GOARCH, CommitId) | ||||||
|   | |||||||
| @@ -18,7 +18,7 @@ const ( | |||||||
| var ( | var ( | ||||||
| 	baseLog   *log.Logger | 	baseLog   *log.Logger | ||||||
| 	baseLevel int | 	baseLevel int | ||||||
| 	level     map[int]string | 	levels    map[int]string | ||||||
| ) | ) | ||||||
|  |  | ||||||
| func initLog() { | func initLog() { | ||||||
| @@ -27,7 +27,7 @@ func initLog() { | |||||||
| } | } | ||||||
|  |  | ||||||
| func logLevel2Int(l string) int { | func logLevel2Int(l string) int { | ||||||
| 	level = map[int]string{ | 	levels = map[int]string{ | ||||||
| 		_Debug: "Debug", | 		_Debug: "Debug", | ||||||
| 		_Info:  "Info", | 		_Info:  "Info", | ||||||
| 		_Warn:  "Warn", | 		_Warn:  "Warn", | ||||||
| @@ -35,7 +35,7 @@ func logLevel2Int(l string) int { | |||||||
| 		_Fatal: "Fatal", | 		_Fatal: "Fatal", | ||||||
| 	} | 	} | ||||||
| 	lvl := _Info | 	lvl := _Info | ||||||
| 	for k, v := range level { | 	for k, v := range levels { | ||||||
| 		if strings.ToLower(l) == strings.ToLower(v) { | 		if strings.ToLower(l) == strings.ToLower(v) { | ||||||
| 			lvl = k | 			lvl = k | ||||||
| 		} | 		} | ||||||
| @@ -44,7 +44,7 @@ func logLevel2Int(l string) int { | |||||||
| } | } | ||||||
|  |  | ||||||
| func output(l int, s ...interface{}) { | func output(l int, s ...interface{}) { | ||||||
| 	lvl := fmt.Sprintf("[%s] ", level[l]) | 	lvl := fmt.Sprintf("[%s] ", levels[l]) | ||||||
| 	baseLog.Output(3, lvl+fmt.Sprintln(s...)) | 	baseLog.Output(3, lvl+fmt.Sprintln(s...)) | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -8,8 +8,7 @@ db_file = "./data.db" | |||||||
| #证书文件 | #证书文件 | ||||||
| cert_file = "./vpn_cert.pem" | cert_file = "./vpn_cert.pem" | ||||||
| cert_key = "./vpn_cert.key" | cert_key = "./vpn_cert.key" | ||||||
| ui_path = "../ui" | down_files_path = "../down_files" | ||||||
| files_path = "../downfiles" |  | ||||||
|  |  | ||||||
| log_level = "info" | log_level = "info" | ||||||
|  |  | ||||||
| @@ -19,7 +18,7 @@ issuer = "XX公司VPN" | |||||||
| admin_user = "admin" | admin_user = "admin" | ||||||
| #pass 123456 | #pass 123456 | ||||||
| admin_pass = "$2a$10$UQ7C.EoPifDeJh6d8.31TeSPQU7hM/NOM2nixmBucJpAuXDQNqNke" | admin_pass = "$2a$10$UQ7C.EoPifDeJh6d8.31TeSPQU7hM/NOM2nixmBucJpAuXDQNqNke" | ||||||
| jwt_secret = "7IrsKW3JuDJ68TPPrdsfweDFYJrO1Xg7JcdsfasMv3P3" | jwt_secret = "" | ||||||
|  |  | ||||||
|  |  | ||||||
| #vpn服务对外地址 | #vpn服务对外地址 | ||||||
|   | |||||||
| @@ -69,6 +69,9 @@ func SetGroup(g *Group) error { | |||||||
| 			clientDns = append(clientDns, v) | 			clientDns = append(clientDns, v) | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  | 	if len(clientDns) == 0 { | ||||||
|  | 		return errors.New("DNS错误") | ||||||
|  | 	} | ||||||
| 	g.ClientDns = clientDns | 	g.ClientDns = clientDns | ||||||
|  |  | ||||||
| 	routeInclude := []ValData{} | 	routeInclude := []ValData{} | ||||||
|   | |||||||
							
								
								
									
										121
									
								
								dbdata/user.go
									
									
									
									
									
								
							
							
						
						
									
										121
									
								
								dbdata/user.go
									
									
									
									
									
								
							| @@ -2,6 +2,8 @@ package dbdata | |||||||
|  |  | ||||||
| import ( | import ( | ||||||
| 	"errors" | 	"errors" | ||||||
|  | 	"fmt" | ||||||
|  | 	"sync" | ||||||
| 	"time" | 	"time" | ||||||
|  |  | ||||||
| 	"github.com/bjdgyc/anylink/pkg/utils" | 	"github.com/bjdgyc/anylink/pkg/utils" | ||||||
| @@ -23,44 +25,6 @@ type User struct { | |||||||
| 	UpdatedAt time.Time `json:"updated_at"` | 	UpdatedAt time.Time `json:"updated_at"` | ||||||
| } | } | ||||||
|  |  | ||||||
| // 验证用户登陆信息 |  | ||||||
| func CheckUser(name, pwd, group string) error { |  | ||||||
| 	// return nil |  | ||||||
|  |  | ||||||
| 	pl := len(pwd) |  | ||||||
| 	if name == "" || pl < 6 { |  | ||||||
| 		return errors.New("密码错误") |  | ||||||
| 	} |  | ||||||
| 	v := &User{} |  | ||||||
| 	err := One("Username", name, v) |  | ||||||
| 	if err != nil || v.Status != 1 { |  | ||||||
| 		return errors.New("用户名错误") |  | ||||||
| 	} |  | ||||||
| 	pass := pwd[:pl-6] |  | ||||||
| 	// if !utils.PasswordVerify(pass, v.Password) { |  | ||||||
| 	if pass != v.PinCode { |  | ||||||
| 		return errors.New("密码错误") |  | ||||||
| 	} |  | ||||||
| 	otp := pwd[pl-6:] |  | ||||||
| 	totp := gotp.NewDefaultTOTP(v.OtpSecret) |  | ||||||
| 	unix := time.Now().Unix() |  | ||||||
| 	verify := totp.Verify(otp, int(unix)) |  | ||||||
| 	if !verify { |  | ||||||
| 		return errors.New("动态码错误") |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	// 判断用户组信息 |  | ||||||
| 	if !utils.InArrStr(v.Groups, group) { |  | ||||||
| 		return errors.New("用户组错误") |  | ||||||
| 	} |  | ||||||
| 	groupData := &Group{} |  | ||||||
| 	err = One("Name", group, groupData) |  | ||||||
| 	if err != nil || groupData.Status != 1 { |  | ||||||
| 		return errors.New("用户组错误") |  | ||||||
| 	} |  | ||||||
| 	return nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func SetUser(v *User) error { | func SetUser(v *User) error { | ||||||
| 	var err error | 	var err error | ||||||
| 	if v.Username == "" || len(v.Groups) == 0 { | 	if v.Username == "" || len(v.Groups) == 0 { | ||||||
| @@ -96,3 +60,84 @@ func SetUser(v *User) error { | |||||||
|  |  | ||||||
| 	return err | 	return err | ||||||
| } | } | ||||||
|  |  | ||||||
|  | // 验证用户登陆信息 | ||||||
|  | func CheckUser(name, pwd, group string) error { | ||||||
|  | 	// return nil | ||||||
|  |  | ||||||
|  | 	pl := len(pwd) | ||||||
|  | 	if name == "" || pl < 6 { | ||||||
|  | 		return fmt.Errorf("%s %s", name, "密码错误") | ||||||
|  | 	} | ||||||
|  | 	v := &User{} | ||||||
|  | 	err := One("Username", name, v) | ||||||
|  | 	if err != nil || v.Status != 1 { | ||||||
|  | 		return fmt.Errorf("%s %s", name, "用户名错误") | ||||||
|  | 	} | ||||||
|  | 	// 判断用户组信息 | ||||||
|  | 	if !utils.InArrStr(v.Groups, group) { | ||||||
|  | 		return fmt.Errorf("%s %s", name, "用户组错误") | ||||||
|  | 	} | ||||||
|  | 	groupData := &Group{} | ||||||
|  | 	err = One("Name", group, groupData) | ||||||
|  | 	if err != nil || groupData.Status != 1 { | ||||||
|  | 		return fmt.Errorf("%s %s", name, "用户组错误") | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// 判断otp信息 | ||||||
|  | 	otp := pwd[pl-6:] | ||||||
|  | 	if !checkOtp(name, otp) { | ||||||
|  | 		return fmt.Errorf("%s %s", name, "动态码错误") | ||||||
|  | 	} | ||||||
|  | 	totp := gotp.NewDefaultTOTP(v.OtpSecret) | ||||||
|  | 	unix := time.Now().Unix() | ||||||
|  | 	verify := totp.Verify(otp, int(unix)) | ||||||
|  | 	if !verify { | ||||||
|  | 		return fmt.Errorf("%s %s", name, "动态码错误") | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	pinCode := pwd[:pl-6] | ||||||
|  | 	if pinCode != v.PinCode { | ||||||
|  | 		return fmt.Errorf("%s %s", name, "密码错误") | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | var ( | ||||||
|  | 	userOtpMux = sync.Mutex{} | ||||||
|  | 	userOtp    = map[string]time.Time{} | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | func init() { | ||||||
|  | 	go func() { | ||||||
|  | 		expire := time.Second * 60 | ||||||
|  |  | ||||||
|  | 		for range time.Tick(time.Second * 10) { | ||||||
|  | 			tnow := time.Now() | ||||||
|  | 			userOtpMux.Lock() | ||||||
|  | 			for k, v := range userOtp { | ||||||
|  | 				if tnow.After(v.Add(expire)) { | ||||||
|  | 					delete(userOtp, k) | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 			userOtpMux.Unlock() | ||||||
|  | 		} | ||||||
|  | 	}() | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // 令牌只能使用一次 | ||||||
|  | func checkOtp(username, otp string) bool { | ||||||
|  | 	key := fmt.Sprintf("%s:%s", username, otp) | ||||||
|  |  | ||||||
|  | 	userOtpMux.Lock() | ||||||
|  | 	defer userOtpMux.Unlock() | ||||||
|  |  | ||||||
|  | 	if _, ok := userOtp[key]; ok { | ||||||
|  | 		// 已经存在 | ||||||
|  | 		return false | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	userOtp[key] = time.Now() | ||||||
|  | 	return true | ||||||
|  | } | ||||||
|   | |||||||
							
								
								
									
										1
									
								
								downfiles/.gitignore → down_files/.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								downfiles/.gitignore → down_files/.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -2,3 +2,4 @@ | |||||||
| 
 | 
 | ||||||
| * | * | ||||||
| !.gitignore | !.gitignore | ||||||
|  | !index.html | ||||||
							
								
								
									
										10
									
								
								down_files/index.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								down_files/index.html
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,10 @@ | |||||||
|  | <!DOCTYPE html> | ||||||
|  | <html lang="en"> | ||||||
|  | <head> | ||||||
|  |     <meta charset="UTF-8"> | ||||||
|  |     <title>Title</title> | ||||||
|  | </head> | ||||||
|  | <body> | ||||||
|  |  | ||||||
|  | </body> | ||||||
|  | </html> | ||||||
							
								
								
									
										1
									
								
								go.mod
									
									
									
									
									
								
							
							
						
						
									
										1
									
								
								go.mod
									
									
									
									
									
								
							| @@ -22,4 +22,5 @@ require ( | |||||||
| 	golang.org/x/crypto v0.0.0-20201208171446-5f87f3452ae9 | 	golang.org/x/crypto v0.0.0-20201208171446-5f87f3452ae9 | ||||||
| 	golang.org/x/net v0.0.0-20201209123823-ac852fbbde11 | 	golang.org/x/net v0.0.0-20201209123823-ac852fbbde11 | ||||||
| 	golang.org/x/time v0.0.0-20201208040808-7e3f01d25324 | 	golang.org/x/time v0.0.0-20201208040808-7e3f01d25324 | ||||||
|  | 	golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 | ||||||
| ) | ) | ||||||
|   | |||||||
							
								
								
									
										2
									
								
								go.sum
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								go.sum
									
									
									
									
									
								
							| @@ -87,6 +87,8 @@ golang.org/x/time v0.0.0-20201208040808-7e3f01d25324/go.mod h1:tRJNPiyCQ0inRvYxb | |||||||
| golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= | ||||||
| golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= | golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= | ||||||
| golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= | golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= | ||||||
|  | golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= | ||||||
|  | golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= | ||||||
| google.golang.org/appengine v1.6.5 h1:tycE03LOZYQNhDpS27tcQdAzLCVMaj7QT2SXxebnpCM= | google.golang.org/appengine v1.6.5 h1:tycE03LOZYQNhDpS27tcQdAzLCVMaj7QT2SXxebnpCM= | ||||||
| google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= | google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= | ||||||
| gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= | ||||||
|   | |||||||
| @@ -2,6 +2,7 @@ package handler | |||||||
|  |  | ||||||
| import ( | import ( | ||||||
| 	"encoding/xml" | 	"encoding/xml" | ||||||
|  | 	"fmt" | ||||||
| 	"io" | 	"io" | ||||||
| 	"io/ioutil" | 	"io/ioutil" | ||||||
| 	"net/http" | 	"net/http" | ||||||
| @@ -14,6 +15,17 @@ import ( | |||||||
| ) | ) | ||||||
|  |  | ||||||
| func LinkAuth(w http.ResponseWriter, r *http.Request) { | func LinkAuth(w http.ResponseWriter, r *http.Request) { | ||||||
|  | 	// 判断anyconnect客户端 | ||||||
|  | 	userAgent := strings.ToLower(r.UserAgent()) | ||||||
|  | 	x_Aggregate_Auth := r.Header.Get("X-Aggregate-Auth") | ||||||
|  | 	x_Transcend_Version := r.Header.Get("X-Transcend-Version") | ||||||
|  | 	if !(strings.Contains(userAgent, "anyconnect") && | ||||||
|  | 		x_Aggregate_Auth == "1" && x_Transcend_Version == "1") { | ||||||
|  | 		w.WriteHeader(http.StatusForbidden) | ||||||
|  | 		fmt.Fprintf(w, "error request") | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	body, err := ioutil.ReadAll(r.Body) | 	body, err := ioutil.ReadAll(r.Body) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		w.WriteHeader(http.StatusBadRequest) | 		w.WriteHeader(http.StatusBadRequest) | ||||||
|   | |||||||
| @@ -20,7 +20,7 @@ func LinkCstp(conn net.Conn, cSess *sessdata.ConnSession) { | |||||||
| 		err     error | 		err     error | ||||||
| 		n       int | 		n       int | ||||||
| 		dataLen uint16 | 		dataLen uint16 | ||||||
| 		dead    = time.Duration(cSess.CstpDpd*2) * time.Second | 		dead    = time.Duration(cSess.CstpDpd+5) * time.Second | ||||||
| 	) | 	) | ||||||
|  |  | ||||||
| 	go cstpWrite(conn, cSess) | 	go cstpWrite(conn, cSess) | ||||||
|   | |||||||
| @@ -8,7 +8,6 @@ import ( | |||||||
| 	"os" | 	"os" | ||||||
|  |  | ||||||
| 	"github.com/bjdgyc/anylink/base" | 	"github.com/bjdgyc/anylink/base" | ||||||
| 	"github.com/bjdgyc/anylink/dbdata" |  | ||||||
| 	"github.com/bjdgyc/anylink/sessdata" | 	"github.com/bjdgyc/anylink/sessdata" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| @@ -51,7 +50,7 @@ func LinkTunnel(w http.ResponseWriter, r *http.Request) { | |||||||
| 	masterSecret := r.Header.Get("X-DTLS-Master-Secret") | 	masterSecret := r.Header.Get("X-DTLS-Master-Secret") | ||||||
| 	localIp := r.Header.Get("X-Cstp-Local-Address-Ip4") | 	localIp := r.Header.Get("X-Cstp-Local-Address-Ip4") | ||||||
| 	mobile := r.Header.Get("X-Cstp-License") | 	mobile := r.Header.Get("X-Cstp-License") | ||||||
| 	platform := r.Header.Get("X-AnyConnect-Identifier-Platform") |  | ||||||
| 	cSess.SetMtu(cstpMtu) | 	cSess.SetMtu(cstpMtu) | ||||||
| 	cSess.MasterSecret = masterSecret | 	cSess.MasterSecret = masterSecret | ||||||
| 	cSess.RemoteAddr = r.RemoteAddr | 	cSess.RemoteAddr = r.RemoteAddr | ||||||
| @@ -67,12 +66,6 @@ func LinkTunnel(w http.ResponseWriter, r *http.Request) { | |||||||
| 	} | 	} | ||||||
| 	cSess.CstpDpd = cstpDpd | 	cSess.CstpDpd = cstpDpd | ||||||
|  |  | ||||||
| 	// iPhone手机需要最少一个dns |  | ||||||
| 	if platform == "apple-ios" && len(cSess.Group.ClientDns) == 0 { |  | ||||||
| 		dnsVal := dbdata.ValData{Val: "114.114.114.114"} |  | ||||||
| 		cSess.Group.ClientDns = append(cSess.Group.ClientDns, dnsVal) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	base.Debug(cSess.IpAddr, cSess.MacHw, sess.Username, mobile) | 	base.Debug(cSess.IpAddr, cSess.MacHw, sess.Username, mobile) | ||||||
|  |  | ||||||
| 	// 返回客户端数据 | 	// 返回客户端数据 | ||||||
|   | |||||||
| @@ -6,6 +6,7 @@ import ( | |||||||
| 	"log" | 	"log" | ||||||
| 	"net" | 	"net" | ||||||
| 	"net/http" | 	"net/http" | ||||||
|  | 	"os" | ||||||
| 	"time" | 	"time" | ||||||
|  |  | ||||||
| 	"github.com/bjdgyc/anylink/base" | 	"github.com/bjdgyc/anylink/base" | ||||||
| @@ -18,6 +19,7 @@ func startTls() { | |||||||
| 	certFile := base.Cfg.CertFile | 	certFile := base.Cfg.CertFile | ||||||
| 	keyFile := base.Cfg.CertKey | 	keyFile := base.Cfg.CertKey | ||||||
|  |  | ||||||
|  | 	logger := log.New(os.Stdout, "[SERVER]", log.Lshortfile|log.Ldate) | ||||||
| 	// 设置tls信息 | 	// 设置tls信息 | ||||||
| 	tlsConfig := &tls.Config{ | 	tlsConfig := &tls.Config{ | ||||||
| 		NextProtos: []string{"http/1.1"}, | 		NextProtos: []string{"http/1.1"}, | ||||||
| @@ -27,6 +29,7 @@ func startTls() { | |||||||
| 		Addr:      addr, | 		Addr:      addr, | ||||||
| 		Handler:   initRoute(), | 		Handler:   initRoute(), | ||||||
| 		TLSConfig: tlsConfig, | 		TLSConfig: tlsConfig, | ||||||
|  | 		ErrorLog:  logger, | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	var ln net.Listener | 	var ln net.Listener | ||||||
| @@ -50,13 +53,13 @@ func startTls() { | |||||||
|  |  | ||||||
| func initRoute() http.Handler { | func initRoute() http.Handler { | ||||||
| 	r := mux.NewRouter() | 	r := mux.NewRouter() | ||||||
| 	// r.HandleFunc("/", checkLinkClient(LinkHome)).Methods(http.MethodGet) | 	r.HandleFunc("/", LinkHome).Methods(http.MethodGet) | ||||||
| 	r.HandleFunc("/", checkLinkClient(LinkAuth)).Methods(http.MethodPost) | 	r.HandleFunc("/", LinkAuth).Methods(http.MethodPost) | ||||||
| 	r.HandleFunc("/CSCOSSLC/tunnel", LinkTunnel).Methods(http.MethodConnect) | 	r.HandleFunc("/CSCOSSLC/tunnel", LinkTunnel).Methods(http.MethodConnect) | ||||||
| 	r.HandleFunc("/otp_qr", LinkOtpQr).Methods(http.MethodGet) | 	r.HandleFunc("/otp_qr", LinkOtpQr).Methods(http.MethodGet) | ||||||
| 	r.PathPrefix("/files/").Handler( | 	r.PathPrefix("/down_files/").Handler( | ||||||
| 		http.StripPrefix("/files/", | 		http.StripPrefix("/down_files/", | ||||||
| 			http.FileServer(http.Dir(base.Cfg.FilesPath)), | 			http.FileServer(http.Dir(base.Cfg.DownFilesPath)), | ||||||
| 		), | 		), | ||||||
| 	) | 	) | ||||||
| 	r.NotFoundHandler = http.HandlerFunc(notFound) | 	r.NotFoundHandler = http.HandlerFunc(notFound) | ||||||
|   | |||||||
							
								
								
									
										8
									
								
								main.go
									
									
									
									
									
								
							
							
						
						
									
										8
									
								
								main.go
									
									
									
									
									
								
							| @@ -2,21 +2,29 @@ | |||||||
| package main | package main | ||||||
|  |  | ||||||
| import ( | import ( | ||||||
|  | 	"embed" | ||||||
| 	"os" | 	"os" | ||||||
| 	"os/signal" | 	"os/signal" | ||||||
| 	"syscall" | 	"syscall" | ||||||
|  |  | ||||||
|  | 	"github.com/bjdgyc/anylink/admin" | ||||||
| 	"github.com/bjdgyc/anylink/base" | 	"github.com/bjdgyc/anylink/base" | ||||||
| 	"github.com/bjdgyc/anylink/handler" | 	"github.com/bjdgyc/anylink/handler" | ||||||
| ) | ) | ||||||
|  |  | ||||||
|  | //go:embed ui/* | ||||||
|  | var UiPath embed.FS | ||||||
|  |  | ||||||
| // 程序版本 | // 程序版本 | ||||||
| var COMMIT_ID string | var COMMIT_ID string | ||||||
|  |  | ||||||
| func main() { | func main() { | ||||||
| 	base.CommitId = COMMIT_ID | 	base.CommitId = COMMIT_ID | ||||||
|  | 	admin.UiPath = UiPath | ||||||
|  |  | ||||||
| 	base.Start() | 	base.Start() | ||||||
| 	handler.Start() | 	handler.Start() | ||||||
|  |  | ||||||
| 	signalWatch() | 	signalWatch() | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -25,8 +25,8 @@ const ( | |||||||
| 	delmiter = "$" | 	delmiter = "$" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| func saltSecret() (string, error) { | func RandSecret(min int, max int) (string, error) { | ||||||
| 	rb := make([]byte, randInt(10, 100)) | 	rb := make([]byte, randInt(min, max)) | ||||||
| 	_, err := rand.Read(rb) | 	_, err := rand.Read(rb) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return "", err | 		return "", err | ||||||
|   | |||||||
| @@ -145,8 +145,8 @@ func (s *Session) NewConn() *ConnSession { | |||||||
| 	macHw, err := net.ParseMAC(macAddr) | 	macHw, err := net.ParseMAC(macAddr) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		sum := md5.Sum([]byte(s.UniqueIdGlobal)) | 		sum := md5.Sum([]byte(s.UniqueIdGlobal)) | ||||||
| 		macHw = sum[8:13] // 5个byte | 		macHw = sum[0:5] // 5个byte | ||||||
| 		macHw = append([]byte{0x00}, macHw...) | 		macHw = append([]byte{0x02}, macHw...) | ||||||
| 		macAddr = macHw.String() | 		macAddr = macHw.String() | ||||||
| 	} | 	} | ||||||
| 	ip := AcquireIp(username, macAddr) | 	ip := AcquireIp(username, macAddr) | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user