From 26483533a904e39baca6680672ec6c65536135af Mon Sep 17 00:00:00 2001
From: bjdgyc
Date: Fri, 29 Mar 2024 10:04:15 +0800
Subject: [PATCH 1/2] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=20=E5=85=B3=E9=97=ADotp?=
=?UTF-8?q?=E6=97=B6,=E5=8F=91=E9=80=81=E9=82=AE=E4=BB=B6=E9=99=84?=
=?UTF-8?q?=E4=BB=B6=E7=9A=84=E9=97=AE=E9=A2=98?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
server/admin/api_user.go | 20 ++++++++++++++------
server/dbdata/db.go | 14 +++++++++-----
2 files changed, 23 insertions(+), 11 deletions(-)
diff --git a/server/admin/api_user.go b/server/admin/api_user.go
index c38214c..bad7d38 100644
--- a/server/admin/api_user.go
+++ b/server/admin/api_user.go
@@ -214,6 +214,7 @@ type userAccountMailData struct {
PinCode string
OtpImg string
OtpImgBase64 string
+ DisableOtp bool
}
func userAccountMail(user *dbdata.User) error {
@@ -265,6 +266,7 @@ func userAccountMail(user *dbdata.User) error {
PinCode: user.PinCode,
OtpImg: fmt.Sprintf("https://%s/otp_qr?id=%d&jwt=%s", setting.LinkAddr, user.Id, tokenString),
OtpImgBase64: "data:image/png;base64," + otpData,
+ DisableOtp: user.DisableOtp,
}
w := bytes.NewBufferString("")
t, _ := template.New("auth_complete").Parse(htmlBody)
@@ -273,12 +275,18 @@ func userAccountMail(user *dbdata.User) error {
return err
}
// fmt.Println(w.String())
- imgData, _ := userOtpQr(user.Id, false)
- attach := &mail.File{
- MimeType: "image/png",
- Name: "userOtpQr.png",
- Data: []byte(imgData),
- Inline: true,
+
+ var attach *mail.File
+ if user.DisableOtp {
+ attach = nil
+ } else {
+ imgData, _ := userOtpQr(user.Id, false)
+ attach = &mail.File{
+ MimeType: "image/png",
+ Name: "userOtpQr.png",
+ Data: []byte(imgData),
+ Inline: true,
+ }
}
return SendMail(base.Cfg.Issuer, user.Email, w.String(), attach)
diff --git a/server/dbdata/db.go b/server/dbdata/db.go
index 7d643a3..c59d661 100644
--- a/server/dbdata/db.go
+++ b/server/dbdata/db.go
@@ -174,6 +174,9 @@ func CheckErrNotFound(err error) bool {
return err == ErrNotFound
}
+// base64 图片
+// 用户动态码(请妥善保存):
+// 
const accountMail = `您好:
您的{{.Issuer}}账号已经审核开通。
@@ -181,17 +184,18 @@ const accountMail = `
您好:
用户组: {{.Group}}
用户名: {{.Username}}
用户PIN码: {{.PinCode}}
+ {{if .DisableOtp}}
+
+ {{else}}
+
用户动态码(请妥善保存):

+
+ {{end}}
使用说明:
From 5e804a348329db3e026f0ef6785047950f136640 Mon Sep 17 00:00:00 2001
From: bjdgyc
Date: Mon, 22 Apr 2024 14:40:03 +0800
Subject: [PATCH 2/2] =?UTF-8?q?=E6=94=AF=E6=8C=81=20=E7=A7=81=E6=9C=89?=
=?UTF-8?q?=E8=87=AA=E7=AD=BE=E8=AF=81=E4=B9=A6?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
README.md | 7 ++++---
server/admin/server.go | 6 ------
server/handler/link_auth.go | 10 +++++++---
server/handler/server.go | 16 ++++++++++++++++
web/src/pages/group/List.vue | 4 ++--
5 files changed, 29 insertions(+), 14 deletions(-)
diff --git a/README.md b/README.md
index b0fa7a6..ceb451f 100644
--- a/README.md
+++ b/README.md
@@ -23,7 +23,7 @@ AnyLink 是一个企业级远程办公 sslvpn 的软件,可以支持多人同
AnyLink 基于 [ietf-openconnect](https://tools.ietf.org/html/draft-mavrogiannopoulos-openconnect-02)
协议开发,并且借鉴了 [ocserv](http://ocserv.gitlab.io/www/index.html) 的开发思路,使其可以同时兼容 AnyConnect 客户端。
-AnyLink 使用 TLS/DTLS 进行数据加密,因此需要 RSA 或 ECC 证书,可以通过 Let's Encrypt 和 TrustAsia 申请免费的 SSL 证书。
+AnyLink 使用 TLS/DTLS 进行数据加密,因此需要 RSA 或 ECC 证书,可以使用私有自签证书,可以通过 Let's Encrypt 和 TrustAsia 申请免费的 SSL 证书。
AnyLink 服务端仅在 CentOS 7、CentOS 8、Ubuntu 18.04、Ubuntu 20.04 测试通过,如需要安装在其他系统,需要服务端支持 tun/tap
功能、ip 设置命令、iptables命令。
@@ -60,9 +60,9 @@ AnyLink 服务端仅在 CentOS 7、CentOS 8、Ubuntu 18.04、Ubuntu 20.04 测试
### 使用问题
-> 对于测试环境,可以使用 vpn.test.vqilu.cn 绑定host进行测试
+> 对于测试环境,可以直接进行测试,需要客户端取消勾选【阻止不受信任的服务器(Block connections to untrusted servers)】
>
-> 对于线上环境,必须申请安全的https证书(跟nginx使用的证书类型一致),不支持私有证书连接
+> 对于线上环境,尽量申请安全的https证书(跟nginx使用的pem证书类型一致)
>
> 群共享文件有相关客户端软件下载,其他版本没有测试过,不保证使用正常
>
@@ -133,6 +133,7 @@ sudo ./anylink
- [x] 流量压缩功能
- [x] 出口 IP 自动放行
- [x] 支持多服务的配置区分
+- [x] 支持私有自签证书
- [ ] 基于 ipvtap 设备的桥接访问模式
## Config
diff --git a/server/admin/server.go b/server/admin/server.go
index 9c25878..f38d0c0 100644
--- a/server/admin/server.go
+++ b/server/admin/server.go
@@ -111,12 +111,6 @@ func StartAdmin() {
selectedCipherSuites = append(selectedCipherSuites, s.ID)
}
- if tlscert, _, err := dbdata.ParseCert(); err != nil {
- base.Fatal("证书加载失败", err)
- } else {
- dbdata.LoadCertificate(tlscert)
- }
-
// 设置tls信息
tlsConfig := &tls.Config{
NextProtos: []string{"http/1.1"},
diff --git a/server/handler/link_auth.go b/server/handler/link_auth.go
index 43e4c02..328b3fe 100644
--- a/server/handler/link_auth.go
+++ b/server/handler/link_auth.go
@@ -17,7 +17,10 @@ import (
"github.com/bjdgyc/anylink/sessdata"
)
-var profileHash = ""
+var (
+ profileHash = ""
+ certHash = ""
+)
func LinkAuth(w http.ResponseWriter, r *http.Request) {
// TODO 调试信息输出
@@ -138,7 +141,7 @@ func LinkAuth(w http.ResponseWriter, r *http.Request) {
other := &dbdata.SettingOther{}
_ = dbdata.SettingGet(other)
rd := RequestData{SessionId: sess.Sid, SessionToken: sess.Sid + "@" + sess.Token,
- Banner: other.Banner, ProfileName: base.Cfg.ProfileName, ProfileHash: profileHash}
+ Banner: other.Banner, ProfileName: base.Cfg.ProfileName, ProfileHash: profileHash, CertHash: certHash}
w.WriteHeader(http.StatusOK)
tplRequest(tpl_complete, w, rd)
base.Info("login", cr.Auth.Username, userAgent)
@@ -178,6 +181,7 @@ type RequestData struct {
Banner string
ProfileName string
ProfileHash string
+ CertHash string
}
var auth_request = `
@@ -223,7 +227,7 @@ var auth_complete = `
- 240B97A685B2BFA66AD699B90AAC49EA66495D69
+ {{.CertHash}}
diff --git a/server/handler/server.go b/server/handler/server.go
index a378951..eadf549 100644
--- a/server/handler/server.go
+++ b/server/handler/server.go
@@ -1,13 +1,16 @@
package handler
import (
+ "crypto/sha1"
"crypto/tls"
+ "encoding/hex"
"fmt"
"io"
"net"
"net/http"
"net/http/httputil"
"os"
+ "strings"
"time"
"github.com/bjdgyc/anylink/base"
@@ -36,6 +39,19 @@ func startTls() {
// certs[0], err = tls.LoadX509KeyPair(certFile, keyFile)
// }
+ tlscert, _, err := dbdata.ParseCert()
+ if err != nil {
+ base.Fatal("证书加载失败", err)
+ }
+ dbdata.LoadCertificate(tlscert)
+
+ // 计算证书hash值
+ s1 := sha1.New()
+ s1.Write(tlscert.Certificate[0])
+ h2s := hex.EncodeToString(s1.Sum(nil))
+ certHash = strings.ToUpper(h2s)
+ base.Info("certHash", certHash)
+
// 修复 CVE-2016-2183
// https://segmentfault.com/a/1190000038486901
// nmap -sV --script ssl-enum-ciphers -p 443 www.example.com
diff --git a/web/src/pages/group/List.vue b/web/src/pages/group/List.vue
index cb28dce..0cca4dc 100644
--- a/web/src/pages/group/List.vue
+++ b/web/src/pages/group/List.vue
@@ -201,9 +201,9 @@
注:本地网络 指的是:
- 运行 anyconnect 客户端的PC 所在的的网络,既本地路由网段。
+ 运行 anyconnect 客户端的PC 所在的的网络,即本地路由网段。
开启后,PC本地路由网段的数据就不会走隧道链路转发数据了。
- 同时 anyconnect 客户端需要勾选本地网络(Local Lan)的开关,功能才能生效。
+ 同时 anyconnect 客户端需要勾选本地网络(Allow Local Lan)的开关,功能才能生效。