mirror of
https://github.com/bjdgyc/anylink.git
synced 2025-09-29 00:19:36 +08:00
Compare commits
28 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
ccce143f85 | ||
|
01431b2230 | ||
|
7a92aa8dff | ||
|
2b580067a2 | ||
|
500a11612c | ||
|
64fc4d082e | ||
|
cf507d204b | ||
|
fd7242dbba | ||
|
9a712ca489 | ||
|
e44e1dcf2a | ||
|
fce96753c5 | ||
|
77efe7583d | ||
|
1cbe9bfc30 | ||
|
2e7afa9c35 | ||
|
a58507f5a6 | ||
|
1989b235fe | ||
|
21b047b307 | ||
|
2daad88159 | ||
|
7c86513b0c | ||
|
4b41e6c5b9 | ||
|
684fea69d0 | ||
|
85e2ba0b0f | ||
|
3fff44dde5 | ||
|
8b2b058450 | ||
|
f0305415ae | ||
|
ea84a29350 | ||
|
6c5969c5ea | ||
|
e780afe18c |
@@ -2,12 +2,12 @@
|
|||||||
FROM node:lts-alpine as builder_node
|
FROM node:lts-alpine as builder_node
|
||||||
WORKDIR /web
|
WORKDIR /web
|
||||||
COPY ./web /web
|
COPY ./web /web
|
||||||
RUN npm install --registry=https://registry.npm.taobao.org \
|
RUN yarn install \
|
||||||
&& npm run build \
|
&& yarn run build \
|
||||||
&& ls /web/ui
|
&& ls /web/ui
|
||||||
|
|
||||||
# server
|
# server
|
||||||
FROM golang:1.16-alpine as builder_golang
|
FROM golang:1.17-alpine as builder_golang
|
||||||
#TODO 本地打包时使用镜像
|
#TODO 本地打包时使用镜像
|
||||||
ENV GOPROXY=https://goproxy.io
|
ENV GOPROXY=https://goproxy.io
|
||||||
ENV GOOS=linux
|
ENV GOOS=linux
|
||||||
@@ -33,7 +33,7 @@ COPY docker_entrypoint.sh /app/
|
|||||||
|
|
||||||
COPY ./server/bridge-init.sh /app/
|
COPY ./server/bridge-init.sh /app/
|
||||||
COPY ./server/conf /app/conf
|
COPY ./server/conf /app/conf
|
||||||
#COPY ./server/files /app/conf/files
|
COPY ./LICENSE /app/LICENSE
|
||||||
|
|
||||||
|
|
||||||
#TODO 本地打包时使用镜像
|
#TODO 本地打包时使用镜像
|
||||||
|
24
README.md
24
README.md
@@ -6,6 +6,7 @@
|
|||||||
[](https://codecov.io/gh/bjdgyc/anylink)
|
[](https://codecov.io/gh/bjdgyc/anylink)
|
||||||

|

|
||||||

|

|
||||||
|
[](https://hub.docker.com/r/bjdgyc/anylink)
|
||||||

|

|
||||||
|
|
||||||
AnyLink 是一个企业级远程办公 sslvpn 的软件,可以支持多人同时在线使用。
|
AnyLink 是一个企业级远程办公 sslvpn 的软件,可以支持多人同时在线使用。
|
||||||
@@ -36,6 +37,7 @@ AnyLink 服务端仅在 CentOS 7、Ubuntu 18.04 测试通过,如需要安装
|
|||||||
> https://github.com/bjdgyc/anylink/releases
|
> https://github.com/bjdgyc/anylink/releases
|
||||||
|
|
||||||
### 使用问题
|
### 使用问题
|
||||||
|
|
||||||
> 对于测试环境,可以使用 vpn.test.vqilu.cn 绑定host进行测试
|
> 对于测试环境,可以使用 vpn.test.vqilu.cn 绑定host进行测试
|
||||||
>
|
>
|
||||||
> 对于线上环境,必须申请安全的 https 证书,不支持私有证书连接
|
> 对于线上环境,必须申请安全的 https 证书,不支持私有证书连接
|
||||||
@@ -44,7 +46,7 @@ AnyLink 服务端仅在 CentOS 7、Ubuntu 18.04 测试通过,如需要安装
|
|||||||
|
|
||||||
### 自行编译安装
|
### 自行编译安装
|
||||||
|
|
||||||
> 需要提前安装好 golang >= 1.16 和 nodejs >= 14.x
|
> 需要提前安装好 golang >= 1.17 和 nodejs >= 14.x 和 yarn >= v1.22.x
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
git clone https://github.com/bjdgyc/anylink.git
|
git clone https://github.com/bjdgyc/anylink.git
|
||||||
@@ -57,7 +59,7 @@ cd anylink-deploy
|
|||||||
sudo ./anylink
|
sudo ./anylink
|
||||||
|
|
||||||
# 默认管理后台访问地址
|
# 默认管理后台访问地址
|
||||||
# http://host:8800
|
# https://host:8800
|
||||||
# 默认账号 密码
|
# 默认账号 密码
|
||||||
# admin 123456
|
# admin 123456
|
||||||
|
|
||||||
@@ -69,6 +71,7 @@ sudo ./anylink
|
|||||||
- [x] TLS-TCP 通道
|
- [x] TLS-TCP 通道
|
||||||
- [x] DTLS-UDP 通道
|
- [x] DTLS-UDP 通道
|
||||||
- [x] 兼容 AnyConnect
|
- [x] 兼容 AnyConnect
|
||||||
|
- [x] 兼容 OpenConnect
|
||||||
- [x] 基于 tun 设备的 nat 访问模式
|
- [x] 基于 tun 设备的 nat 访问模式
|
||||||
- [x] 基于 tap 设备的桥接访问模式
|
- [x] 基于 tap 设备的桥接访问模式
|
||||||
- [x] 基于 macvtap 设备的桥接访问模式
|
- [x] 基于 macvtap 设备的桥接访问模式
|
||||||
@@ -113,7 +116,8 @@ sudo ./anylink
|
|||||||
|
|
||||||
网络模式选择,需要配置 `link_mode` 参数,如 `link_mode="tun"`,`link_mode="macvtap"`,`link_mode="tap"(不推荐)` 等参数。 不同的参数需要对服务器做相应的设置。
|
网络模式选择,需要配置 `link_mode` 参数,如 `link_mode="tun"`,`link_mode="macvtap"`,`link_mode="tap"(不推荐)` 等参数。 不同的参数需要对服务器做相应的设置。
|
||||||
|
|
||||||
建议优先选择 tun 模式,其次选择 macvtap 模式,因客户端传输的是 IP 层数据,无须进行数据转换。 tap 模式是在用户态做的链路层到 IP 层的数据互相转换,性能会有所下降。 如果需要在虚拟机内开启 tap 模式,请确认虚拟机的网卡开启混杂模式。
|
建议优先选择 tun 模式,其次选择 macvtap 模式,因客户端传输的是 IP 层数据,无须进行数据转换。 tap 模式是在用户态做的链路层到 IP 层的数据互相转换,性能会有所下降。 如果需要在虚拟机内开启 tap
|
||||||
|
模式,请确认虚拟机的网卡开启混杂模式。
|
||||||
|
|
||||||
### tun 设置
|
### tun 设置
|
||||||
|
|
||||||
@@ -125,6 +129,9 @@ net.ipv4.ip_forward = 1
|
|||||||
|
|
||||||
#执行如下命令
|
#执行如下命令
|
||||||
sysctl -w net.ipv4.ip_forward=1
|
sysctl -w net.ipv4.ip_forward=1
|
||||||
|
|
||||||
|
# 查看设置是否生效
|
||||||
|
cat /proc/sys/net/ipv4/ip_forward
|
||||||
```
|
```
|
||||||
|
|
||||||
2. 设置 nat 转发规则
|
2. 设置 nat 转发规则
|
||||||
@@ -233,14 +240,15 @@ sh bridge-init.sh
|
|||||||
5. 启动容器
|
5. 启动容器
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
# -e IPV4_CIDR=192.168.10.0/24 这个参数要与配置文件内的网段一致
|
||||||
docker run -itd --name anylink --privileged \
|
docker run -itd --name anylink --privileged \
|
||||||
|
-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
|
||||||
```
|
```
|
||||||
|
|
||||||
6. 使用自定义参数启动容器
|
6. 使用自定义参数启动容器
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# 参数可以参考 -h 命令
|
# 参数可以参考 -h 命令
|
||||||
docker run -itd --name anylink --privileged \
|
docker run -itd --name anylink --privileged \
|
||||||
@@ -260,10 +268,6 @@ sh bridge-init.sh
|
|||||||
docker build -t anylink .
|
docker build -t anylink .
|
||||||
```
|
```
|
||||||
|
|
||||||
## 常见问题
|
|
||||||
|
|
||||||
请前往 [问题地址](doc/question.md) 查看具体信息
|
|
||||||
|
|
||||||
## Donate
|
## Donate
|
||||||
|
|
||||||
> 如果您觉得 anylink 对你有帮助,欢迎给我们打赏,也是帮助 anylink 更好的发展。
|
> 如果您觉得 anylink 对你有帮助,欢迎给我们打赏,也是帮助 anylink 更好的发展。
|
||||||
@@ -274,6 +278,10 @@ sh bridge-init.sh
|
|||||||
<img src="doc/screenshot/wxpay2.png" width="400" />
|
<img src="doc/screenshot/wxpay2.png" width="400" />
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
## 常见问题
|
||||||
|
|
||||||
|
请前往 [问题地址](doc/question.md) 查看具体信息
|
||||||
|
|
||||||
## Discussion
|
## Discussion
|
||||||
|
|
||||||
添加 QQ 群: 567510628
|
添加 QQ 群: 567510628
|
||||||
|
9
build.sh
9
build.sh
@@ -16,9 +16,13 @@ echo "编译前端项目"
|
|||||||
cd $cpath/web
|
cd $cpath/web
|
||||||
#国内可替换源加快速度
|
#国内可替换源加快速度
|
||||||
#npx browserslist@latest --update-db
|
#npx browserslist@latest --update-db
|
||||||
npm install --registry=https://registry.npm.taobao.org
|
#npm install --registry=https://registry.npm.taobao.org
|
||||||
#npm install
|
#npm install
|
||||||
npm run build
|
#npm run build
|
||||||
|
|
||||||
|
yarn install
|
||||||
|
yarn run build
|
||||||
|
|
||||||
RETVAL $?
|
RETVAL $?
|
||||||
|
|
||||||
echo "编译二进制文件"
|
echo "编译二进制文件"
|
||||||
@@ -42,6 +46,7 @@ cp -r server/bridge-init.sh $deploy
|
|||||||
cp -r server/conf $deploy
|
cp -r server/conf $deploy
|
||||||
|
|
||||||
cp -r systemd $deploy
|
cp -r systemd $deploy
|
||||||
|
cp -r LICENSE $deploy
|
||||||
|
|
||||||
tar zcvf ${deploy}.tar.gz $deploy
|
tar zcvf ${deploy}.tar.gz $deploy
|
||||||
|
|
||||||
|
@@ -18,6 +18,6 @@ case $var1 in
|
|||||||
iptables -t nat -A POSTROUTING -s "${IPV4_CIDR}" -o eth0+ -j MASQUERADE
|
iptables -t nat -A POSTROUTING -s "${IPV4_CIDR}" -o eth0+ -j MASQUERADE
|
||||||
iptables -nL -t nat
|
iptables -nL -t nat
|
||||||
|
|
||||||
/app/anylink "$@"
|
exec /app/anylink "$@"
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
@@ -2,6 +2,7 @@
|
|||||||
package admin
|
package admin
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"crypto/tls"
|
||||||
"embed"
|
"embed"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/pprof"
|
"net/http/pprof"
|
||||||
@@ -18,6 +19,11 @@ func StartAdmin() {
|
|||||||
r := mux.NewRouter()
|
r := mux.NewRouter()
|
||||||
r.Use(authMiddleware)
|
r.Use(authMiddleware)
|
||||||
|
|
||||||
|
// 监控检测
|
||||||
|
r.HandleFunc("/status.html", func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
w.Write([]byte("ok"))
|
||||||
|
}).Name("index")
|
||||||
|
|
||||||
r.Handle("/", http.RedirectHandler("/ui/", http.StatusFound)).Name("index")
|
r.Handle("/", http.RedirectHandler("/ui/", http.StatusFound)).Name("index")
|
||||||
r.PathPrefix("/ui/").Handler(
|
r.PathPrefix("/ui/").Handler(
|
||||||
// http.StripPrefix("/ui/", http.FileServer(http.Dir(base.Cfg.UiPath))),
|
// http.StripPrefix("/ui/", http.FileServer(http.Dir(base.Cfg.UiPath))),
|
||||||
@@ -64,7 +70,25 @@ func StartAdmin() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
base.Info("Listen admin", base.Cfg.AdminAddr)
|
base.Info("Listen admin", base.Cfg.AdminAddr)
|
||||||
err := http.ListenAndServe(base.Cfg.AdminAddr, r)
|
|
||||||
|
// 修复 CVE-2016-2183
|
||||||
|
cipherSuites := tls.CipherSuites()
|
||||||
|
selectedCipherSuites := make([]uint16, 0, len(cipherSuites))
|
||||||
|
for _, s := range cipherSuites {
|
||||||
|
selectedCipherSuites = append(selectedCipherSuites, s.ID)
|
||||||
|
}
|
||||||
|
// 设置tls信息
|
||||||
|
tlsConfig := &tls.Config{
|
||||||
|
NextProtos: []string{"http/1.1"},
|
||||||
|
MinVersion: tls.VersionTLS12,
|
||||||
|
CipherSuites: selectedCipherSuites,
|
||||||
|
}
|
||||||
|
srv := &http.Server{
|
||||||
|
Addr: base.Cfg.AdminAddr,
|
||||||
|
Handler: r,
|
||||||
|
TLSConfig: tlsConfig,
|
||||||
|
}
|
||||||
|
err := srv.ListenAndServeTLS(base.Cfg.CertFile, base.Cfg.CertKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
base.Fatal(err)
|
base.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@@ -2,6 +2,6 @@ package base
|
|||||||
|
|
||||||
const (
|
const (
|
||||||
APP_NAME = "AnyLink"
|
APP_NAME = "AnyLink"
|
||||||
// 修复前端bug
|
// 修复 CVE-2016-2183
|
||||||
APP_VER = "0.7.1"
|
APP_VER = "0.7.4"
|
||||||
)
|
)
|
||||||
|
@@ -32,6 +32,7 @@ var (
|
|||||||
type ServerConfig struct {
|
type ServerConfig struct {
|
||||||
// LinkAddr string `json:"link_addr"`
|
// LinkAddr string `json:"link_addr"`
|
||||||
Conf string `json:"conf"`
|
Conf string `json:"conf"`
|
||||||
|
Profile string `json:"profile"`
|
||||||
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"`
|
||||||
|
@@ -21,6 +21,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: "conf", Usage: "config file", ValStr: "./conf/server.toml", Short: "c"},
|
||||||
|
{Typ: cfgStr, Name: "profile", Usage: "profile.xml file", ValStr: "./conf/profile.xml"},
|
||||||
{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"},
|
||||||
|
@@ -6,10 +6,11 @@
|
|||||||
#数据文件
|
#数据文件
|
||||||
db_type = "sqlite3"
|
db_type = "sqlite3"
|
||||||
db_source = "./conf/anylink.db"
|
db_source = "./conf/anylink.db"
|
||||||
#证书文件
|
#证书文件 使用跟nginx一样的证书即可
|
||||||
cert_file = "./conf/vpn_cert.pem"
|
cert_file = "./conf/vpn_cert.crt"
|
||||||
cert_key = "./conf/vpn_cert.key"
|
cert_key = "./conf/vpn_cert.key"
|
||||||
files_path = "./conf/files"
|
files_path = "./conf/files"
|
||||||
|
profile = "./conf/profile.xml"
|
||||||
#日志目录,为空写入标准输出
|
#日志目录,为空写入标准输出
|
||||||
#log_path = "./log"
|
#log_path = "./log"
|
||||||
log_path = ""
|
log_path = ""
|
||||||
|
@@ -7,9 +7,10 @@
|
|||||||
db_type = "sqlite3"
|
db_type = "sqlite3"
|
||||||
db_source = "./conf/anylink.db"
|
db_source = "./conf/anylink.db"
|
||||||
#证书文件
|
#证书文件
|
||||||
cert_file = "./conf/vpn_cert.pem"
|
cert_file = "./conf/vpn_cert.crt"
|
||||||
cert_key = "./conf/vpn_cert.key"
|
cert_key = "./conf/vpn_cert.key"
|
||||||
files_path = "./conf/files"
|
files_path = "./conf/files"
|
||||||
|
log_level = "debug"
|
||||||
|
|
||||||
#系统名称
|
#系统名称
|
||||||
issuer = "XX公司VPN"
|
issuer = "XX公司VPN"
|
||||||
|
@@ -102,7 +102,23 @@ func addInitData() error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return sess.Commit()
|
err = sess.Commit()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
g1 := Group{
|
||||||
|
Name: "ops",
|
||||||
|
AllowLan: true,
|
||||||
|
ClientDns: []ValData{{Val: "114.114.114.114"}},
|
||||||
|
RouteInclude: []ValData{{Val: All}},
|
||||||
|
}
|
||||||
|
err = SetGroup(&g1)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func CheckErrNotFound(err error) bool {
|
func CheckErrNotFound(err error) bool {
|
||||||
|
@@ -12,6 +12,7 @@ import (
|
|||||||
const (
|
const (
|
||||||
Allow = "allow"
|
Allow = "allow"
|
||||||
Deny = "deny"
|
Deny = "deny"
|
||||||
|
All = "all"
|
||||||
)
|
)
|
||||||
|
|
||||||
type GroupLinkAcl struct {
|
type GroupLinkAcl struct {
|
||||||
@@ -65,25 +66,10 @@ func SetGroup(g *Group) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 判断数据
|
// 判断数据
|
||||||
clientDns := []ValData{}
|
|
||||||
for _, v := range g.ClientDns {
|
|
||||||
if v.Val != "" {
|
|
||||||
ip := net.ParseIP(v.Val)
|
|
||||||
if ip.String() != v.Val {
|
|
||||||
return errors.New("DNS IP 错误")
|
|
||||||
}
|
|
||||||
clientDns = append(clientDns, v)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if len(clientDns) == 0 {
|
|
||||||
return errors.New("必须设置一个DNS")
|
|
||||||
}
|
|
||||||
g.ClientDns = clientDns
|
|
||||||
|
|
||||||
routeInclude := []ValData{}
|
routeInclude := []ValData{}
|
||||||
for _, v := range g.RouteInclude {
|
for _, v := range g.RouteInclude {
|
||||||
if v.Val != "" {
|
if v.Val != "" {
|
||||||
if v.Val == "all" {
|
if v.Val == All {
|
||||||
routeInclude = append(routeInclude, v)
|
routeInclude = append(routeInclude, v)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@@ -124,6 +110,24 @@ func SetGroup(g *Group) error {
|
|||||||
}
|
}
|
||||||
g.LinkAcl = linkAcl
|
g.LinkAcl = linkAcl
|
||||||
|
|
||||||
|
// DNS 判断
|
||||||
|
clientDns := []ValData{}
|
||||||
|
for _, v := range g.ClientDns {
|
||||||
|
if v.Val != "" {
|
||||||
|
ip := net.ParseIP(v.Val)
|
||||||
|
if ip.String() != v.Val {
|
||||||
|
return errors.New("DNS IP 错误")
|
||||||
|
}
|
||||||
|
clientDns = append(clientDns, v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(routeInclude) == 0 || (len(routeInclude) == 1 && routeInclude[0].Val == "all") {
|
||||||
|
if len(clientDns) == 0 {
|
||||||
|
return errors.New("默认路由,必须设置一个DNS")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
g.ClientDns = clientDns
|
||||||
|
|
||||||
g.UpdatedAt = time.Now()
|
g.UpdatedAt = time.Now()
|
||||||
if g.Id > 0 {
|
if g.Id > 0 {
|
||||||
err = Set(g)
|
err = Set(g)
|
||||||
|
@@ -14,6 +14,8 @@ import (
|
|||||||
"github.com/bjdgyc/anylink/sessdata"
|
"github.com/bjdgyc/anylink/sessdata"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var profileHash = ""
|
||||||
|
|
||||||
func LinkAuth(w http.ResponseWriter, r *http.Request) {
|
func LinkAuth(w http.ResponseWriter, r *http.Request) {
|
||||||
// 判断anyconnect客户端
|
// 判断anyconnect客户端
|
||||||
userAgent := strings.ToLower(r.UserAgent())
|
userAgent := strings.ToLower(r.UserAgent())
|
||||||
@@ -89,7 +91,7 @@ func LinkAuth(w http.ResponseWriter, r *http.Request) {
|
|||||||
other := &dbdata.SettingOther{}
|
other := &dbdata.SettingOther{}
|
||||||
_ = dbdata.SettingGet(other)
|
_ = dbdata.SettingGet(other)
|
||||||
rd := RequestData{SessionId: sess.Sid, SessionToken: sess.Sid + "@" + sess.Token,
|
rd := RequestData{SessionId: sess.Sid, SessionToken: sess.Sid + "@" + sess.Token,
|
||||||
Banner: other.Banner}
|
Banner: other.Banner, ProfileHash: profileHash}
|
||||||
w.WriteHeader(http.StatusOK)
|
w.WriteHeader(http.StatusOK)
|
||||||
tplRequest(tpl_complete, w, rd)
|
tplRequest(tpl_complete, w, rd)
|
||||||
base.Debug("login", cr.Auth.Username)
|
base.Debug("login", cr.Auth.Username)
|
||||||
@@ -125,6 +127,7 @@ type RequestData struct {
|
|||||||
SessionId string
|
SessionId string
|
||||||
SessionToken string
|
SessionToken string
|
||||||
Banner string
|
Banner string
|
||||||
|
ProfileHash string
|
||||||
}
|
}
|
||||||
|
|
||||||
var auth_request = `<?xml version="1.0" encoding="UTF-8"?>
|
var auth_request = `<?xml version="1.0" encoding="UTF-8"?>
|
||||||
@@ -176,8 +179,8 @@ var auth_complete = `<?xml version="1.0" encoding="UTF-8"?>
|
|||||||
<vpn-profile-manifest>
|
<vpn-profile-manifest>
|
||||||
<vpn rev="1.0">
|
<vpn rev="1.0">
|
||||||
<file type="profile" service-type="user">
|
<file type="profile" service-type="user">
|
||||||
<uri>/files/profile.xml</uri>
|
<uri>/profile.xml</uri>
|
||||||
<hash type="sha1">A8B0B07FBA93D06E8501E40AB807AEE2464E73B7</hash>
|
<hash type="sha1">{{.ProfileHash}}</hash>
|
||||||
</file>
|
</file>
|
||||||
</vpn>
|
</vpn>
|
||||||
</vpn-profile-manifest>
|
</vpn-profile-manifest>
|
||||||
|
@@ -10,6 +10,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"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"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -108,7 +109,7 @@ func LinkTunnel(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
// 允许的路由
|
// 允许的路由
|
||||||
for _, v := range cSess.Group.RouteInclude {
|
for _, v := range cSess.Group.RouteInclude {
|
||||||
if v.Val == "all" {
|
if v.Val == dbdata.All {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
HttpAddHeader(w, "X-CSTP-Split-Include", v.IpMask)
|
HttpAddHeader(w, "X-CSTP-Split-Include", v.IpMask)
|
||||||
|
@@ -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"
|
||||||
@@ -19,32 +20,33 @@ func startTls() {
|
|||||||
err error
|
err error
|
||||||
|
|
||||||
addr = base.Cfg.ServerAddr
|
addr = base.Cfg.ServerAddr
|
||||||
certFile = base.Cfg.CertFile
|
|
||||||
keyFile = base.Cfg.CertKey
|
|
||||||
certs = make([]tls.Certificate, 1)
|
|
||||||
ln net.Listener
|
ln net.Listener
|
||||||
)
|
)
|
||||||
|
|
||||||
// 判断证书文件
|
// 判断证书文件
|
||||||
//_, err = os.Stat(certFile)
|
// _, err = os.Stat(certFile)
|
||||||
//if errors.Is(err, os.ErrNotExist) {
|
// if errors.Is(err, os.ErrNotExist) {
|
||||||
// // 自动生成证书
|
// // 自动生成证书
|
||||||
// certs[0], err = selfsign.GenerateSelfSignedWithDNS("vpn.anylink")
|
// certs[0], err = selfsign.GenerateSelfSignedWithDNS("vpn.anylink")
|
||||||
//} else {
|
// } else {
|
||||||
// // 使用自定义证书
|
// // 使用自定义证书
|
||||||
// certs[0], err = tls.LoadX509KeyPair(certFile, keyFile)
|
// certs[0], err = tls.LoadX509KeyPair(certFile, keyFile)
|
||||||
//}
|
// }
|
||||||
|
|
||||||
certs[0], err = tls.LoadX509KeyPair(certFile, keyFile)
|
// 修复 CVE-2016-2183
|
||||||
if err != nil {
|
// https://segmentfault.com/a/1190000038486901
|
||||||
panic(err)
|
// nmap -sV --script ssl-enum-ciphers -p 443 www.example.com
|
||||||
|
cipherSuites := tls.CipherSuites()
|
||||||
|
selectedCipherSuites := make([]uint16, 0, len(cipherSuites))
|
||||||
|
for _, s := range cipherSuites {
|
||||||
|
selectedCipherSuites = append(selectedCipherSuites, s.ID)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 设置tls信息
|
// 设置tls信息
|
||||||
tlsConfig := &tls.Config{
|
tlsConfig := &tls.Config{
|
||||||
NextProtos: []string{"http/1.1"},
|
NextProtos: []string{"http/1.1"},
|
||||||
MinVersion: tls.VersionTLS12,
|
MinVersion: tls.VersionTLS12,
|
||||||
Certificates: certs,
|
CipherSuites: selectedCipherSuites,
|
||||||
// InsecureSkipVerify: true,
|
// InsecureSkipVerify: true,
|
||||||
}
|
}
|
||||||
srv := &http.Server{
|
srv := &http.Server{
|
||||||
@@ -65,7 +67,7 @@ func startTls() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
base.Info("listen server", addr)
|
base.Info("listen server", addr)
|
||||||
err = srv.ServeTLS(ln, "", "")
|
err = srv.ServeTLS(ln, base.Cfg.CertFile, base.Cfg.CertKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
base.Fatal(err)
|
base.Fatal(err)
|
||||||
}
|
}
|
||||||
@@ -77,9 +79,10 @@ func initRoute() http.Handler {
|
|||||||
r.HandleFunc("/", 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.HandleFunc("/profile.xml", func(w http.ResponseWriter, r *http.Request) {
|
r.HandleFunc("/profile.xml", func(w http.ResponseWriter, r *http.Request) {
|
||||||
// w.Write([]byte(auth_profile))
|
b, _ := os.ReadFile(base.Cfg.Profile)
|
||||||
// }).Methods(http.MethodGet)
|
w.Write(b)
|
||||||
|
}).Methods(http.MethodGet)
|
||||||
r.PathPrefix("/files/").Handler(
|
r.PathPrefix("/files/").Handler(
|
||||||
http.StripPrefix("/files/",
|
http.StripPrefix("/files/",
|
||||||
http.FileServer(http.Dir(base.Cfg.FilesPath)),
|
http.FileServer(http.Dir(base.Cfg.FilesPath)),
|
||||||
|
@@ -1,6 +1,10 @@
|
|||||||
package handler
|
package handler
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"crypto/sha1"
|
||||||
|
"encoding/hex"
|
||||||
|
"os"
|
||||||
|
|
||||||
"github.com/bjdgyc/anylink/admin"
|
"github.com/bjdgyc/anylink/admin"
|
||||||
"github.com/bjdgyc/anylink/base"
|
"github.com/bjdgyc/anylink/base"
|
||||||
"github.com/bjdgyc/anylink/dbdata"
|
"github.com/bjdgyc/anylink/dbdata"
|
||||||
@@ -22,6 +26,14 @@ func Start() {
|
|||||||
base.Fatal("LinkMode is err")
|
base.Fatal("LinkMode is err")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 计算profile.xml的hash
|
||||||
|
b, err := os.ReadFile(base.Cfg.Profile)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
ha := sha1.Sum(b)
|
||||||
|
profileHash = hex.EncodeToString(ha[:])
|
||||||
|
|
||||||
go admin.StartAdmin()
|
go admin.StartAdmin()
|
||||||
go startTls()
|
go startTls()
|
||||||
go startDtls()
|
go startDtls()
|
||||||
|
@@ -14,7 +14,7 @@ type Payload struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
var header = []byte{'S', 'T', 'F', 0x01, 0, 0, 0x00, 0}
|
var header = []byte{'S', 'T', 'F', 0x01, 0, 0, 0x07, 0}
|
||||||
https://tools.ietf.org/html/draft-mavrogiannopoulos-openconnect-02#section-2.2
|
https://tools.ietf.org/html/draft-mavrogiannopoulos-openconnect-02#section-2.2
|
||||||
|
|
||||||
+---------------------+---------------------------------------------+
|
+---------------------+---------------------------------------------+
|
||||||
|
27581
web/package-lock.json
generated
27581
web/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -423,6 +423,7 @@ export default {
|
|||||||
if (rdata.code === 0) {
|
if (rdata.code === 0) {
|
||||||
this.$message.success(rdata.msg);
|
this.$message.success(rdata.msg);
|
||||||
this.getData(1);
|
this.getData(1);
|
||||||
|
this.user_edit_dialog = false
|
||||||
} else {
|
} else {
|
||||||
this.$message.error(rdata.msg);
|
this.$message.error(rdata.msg);
|
||||||
}
|
}
|
||||||
|
@@ -388,6 +388,7 @@ export default {
|
|||||||
if (data.code === 0) {
|
if (data.code === 0) {
|
||||||
this.$message.success(data.msg);
|
this.$message.success(data.msg);
|
||||||
this.getData(1);
|
this.getData(1);
|
||||||
|
this.user_edit_dialog = false
|
||||||
} else {
|
} else {
|
||||||
this.$message.error(data.msg);
|
this.$message.error(data.msg);
|
||||||
}
|
}
|
||||||
|
8661
web/yarn.lock
Normal file
8661
web/yarn.lock
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user