28 Commits

Author SHA1 Message Date
bjdgyc
ccce143f85 Merge pull request #92 from bjdgyc/dev
Dev
2022-04-07 16:16:06 +08:00
bjdgyc
01431b2230 修复 CVE-2016-2183 2022-04-07 16:12:59 +08:00
bjdgyc
7a92aa8dff 前端更改为yarn编译 2022-04-07 15:58:26 +08:00
bjdgyc
2b580067a2 修复 CVE-2016-2183 2022-04-07 15:11:14 +08:00
bjdgyc
500a11612c 修改默认路由信息 2022-02-25 16:47:49 +08:00
bjdgyc
64fc4d082e Merge pull request #83 from bjdgyc/dev
Dev
2022-02-21 15:13:34 +08:00
bjdgyc
cf507d204b 修改readme 2022-02-16 16:25:11 +08:00
bjdgyc
fd7242dbba fix 2022-02-15 18:41:00 +08:00
bjdgyc
9a712ca489 Merge pull request #81 from bjdgyc/dev
Dev
2022-02-15 15:44:31 +08:00
bjdgyc
e44e1dcf2a 修改版本号 2022-02-15 15:42:38 +08:00
bjdgyc
fce96753c5 修改默认路由 10.0.0.0/8 2022-02-15 15:39:58 +08:00
bjdgyc
77efe7583d Merge pull request #77 from bjdgyc/dependabot/npm_and_yarn/web/follow-redirects-1.14.8
Bump follow-redirects from 1.14.2 to 1.14.8 in /web
2022-02-15 14:59:24 +08:00
bjdgyc
1cbe9bfc30 Merge pull request #78 from bjdgyc/dev
Dev
2022-02-15 14:58:59 +08:00
bjdgyc
2e7afa9c35 修改后台https 2022-02-15 14:37:20 +08:00
dependabot[bot]
a58507f5a6 Bump follow-redirects from 1.14.2 to 1.14.8 in /web
Bumps [follow-redirects](https://github.com/follow-redirects/follow-redirects) from 1.14.2 to 1.14.8.
- [Release notes](https://github.com/follow-redirects/follow-redirects/releases)
- [Commits](https://github.com/follow-redirects/follow-redirects/compare/v1.14.2...v1.14.8)

---
updated-dependencies:
- dependency-name: follow-redirects
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-02-15 03:33:11 +00:00
bjdgyc
1989b235fe Merge pull request #76 from itviewer/dialog
操作成功,弹窗自动关闭
2022-02-09 10:38:36 +08:00
Xinjun Ma
21b047b307 操作成功,弹窗自动关闭 2022-01-25 19:42:52 +08:00
bjdgyc
2daad88159 Merge pull request #75 from itviewer/ssl
管理后台使用 https
2022-01-13 10:29:53 +08:00
Xinjun Ma
7c86513b0c 管理后台使用 https 2022-01-12 21:07:44 +08:00
bjdgyc
4b41e6c5b9 Update README.md 2022-01-11 13:40:44 +08:00
bjdgyc
684fea69d0 优化细节 2021-12-31 21:37:21 +08:00
bjdgyc
85e2ba0b0f 修改证书名称 2021-12-31 20:37:40 +08:00
bjdgyc
3fff44dde5 添加docker pulls 2021-12-31 18:38:28 +08:00
bjdgyc
8b2b058450 Merge pull request #70 from bjdgyc/dev
Dev
2021-12-31 18:14:22 +08:00
bjdgyc
f0305415ae 修改版本号 2021-12-31 17:32:25 +08:00
bjdgyc
ea84a29350 修改profile.xml自动获取hash 2021-12-31 16:38:34 +08:00
bjdgyc
6c5969c5ea 修改profile.xml自动获取hash 2021-12-31 16:35:33 +08:00
bjdgyc
e780afe18c 优化docker信息 2021-12-28 03:48:37 +08:00
24 changed files with 8815 additions and 27653 deletions

View File

@@ -2,12 +2,12 @@
FROM node:lts-alpine as builder_node
WORKDIR /web
COPY ./web /web
RUN npm install --registry=https://registry.npm.taobao.org \
&& npm run build \
RUN yarn install \
&& yarn run build \
&& ls /web/ui
# server
FROM golang:1.16-alpine as builder_golang
FROM golang:1.17-alpine as builder_golang
#TODO 本地打包时使用镜像
ENV GOPROXY=https://goproxy.io
ENV GOOS=linux
@@ -33,7 +33,7 @@ COPY docker_entrypoint.sh /app/
COPY ./server/bridge-init.sh /app/
COPY ./server/conf /app/conf
#COPY ./server/files /app/conf/files
COPY ./LICENSE /app/LICENSE
#TODO 本地打包时使用镜像

View File

@@ -6,6 +6,7 @@
[![codecov](https://codecov.io/gh/bjdgyc/anylink/branch/master/graph/badge.svg?token=JTFLIIIBQ0)](https://codecov.io/gh/bjdgyc/anylink)
![GitHub release](https://img.shields.io/github/v/release/bjdgyc/anylink)
![GitHub downloads)](https://img.shields.io/github/downloads/bjdgyc/anylink/total)
[![Docker pulls)](https://img.shields.io/docker/pulls/bjdgyc/anylink.svg)](https://hub.docker.com/r/bjdgyc/anylink)
![LICENSE](https://img.shields.io/github/license/bjdgyc/anylink)
AnyLink 是一个企业级远程办公 sslvpn 的软件,可以支持多人同时在线使用。
@@ -36,6 +37,7 @@ AnyLink 服务端仅在 CentOS 7、Ubuntu 18.04 测试通过,如需要安装
> https://github.com/bjdgyc/anylink/releases
### 使用问题
> 对于测试环境,可以使用 vpn.test.vqilu.cn 绑定host进行测试
>
> 对于线上环境,必须申请安全的 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
git clone https://github.com/bjdgyc/anylink.git
@@ -57,7 +59,7 @@ cd anylink-deploy
sudo ./anylink
# 默认管理后台访问地址
# http://host:8800
# https://host:8800
# 默认账号 密码
# admin 123456
@@ -69,6 +71,7 @@ sudo ./anylink
- [x] TLS-TCP 通道
- [x] DTLS-UDP 通道
- [x] 兼容 AnyConnect
- [x] 兼容 OpenConnect
- [x] 基于 tun 设备的 nat 访问模式
- [x] 基于 tap 设备的桥接访问模式
- [x] 基于 macvtap 设备的桥接访问模式
@@ -113,7 +116,8 @@ sudo ./anylink
网络模式选择,需要配置 `link_mode` 参数,如 `link_mode="tun"`,`link_mode="macvtap"`,`link_mode="tap"(不推荐)` 等参数。 不同的参数需要对服务器做相应的设置。
建议优先选择 tun 模式,其次选择 macvtap 模式,因客户端传输的是 IP 层数据,无须进行数据转换。 tap 模式是在用户态做的链路层到 IP 层的数据互相转换,性能会有所下降。 如果需要在虚拟机内开启 tap 模式,请确认虚拟机的网卡开启混杂模式。
建议优先选择 tun 模式,其次选择 macvtap 模式,因客户端传输的是 IP 层数据,无须进行数据转换。 tap 模式是在用户态做的链路层到 IP 层的数据互相转换,性能会有所下降。 如果需要在虚拟机内开启 tap
模式,请确认虚拟机的网卡开启混杂模式。
### tun 设置
@@ -125,6 +129,9 @@ net.ipv4.ip_forward = 1
#执行如下命令
sysctl -w net.ipv4.ip_forward=1
# 查看设置是否生效
cat /proc/sys/net/ipv4/ip_forward
```
2. 设置 nat 转发规则
@@ -233,14 +240,15 @@ sh bridge-init.sh
5. 启动容器
```bash
# -e IPV4_CIDR=192.168.10.0/24 这个参数要与配置文件内的网段一致
docker run -itd --name anylink --privileged \
-e IPV4_CIDR=192.168.10.0/24
-p 443:443 -p 8800:8800 \
--restart=always \
bjdgyc/anylink
```
6. 使用自定义参数启动容器
```bash
# 参数可以参考 -h 命令
docker run -itd --name anylink --privileged \
@@ -260,10 +268,6 @@ sh bridge-init.sh
docker build -t anylink .
```
## 常见问题
请前往 [问题地址](doc/question.md) 查看具体信息
## Donate
> 如果您觉得 anylink 对你有帮助,欢迎给我们打赏,也是帮助 anylink 更好的发展。
@@ -274,6 +278,10 @@ sh bridge-init.sh
<img src="doc/screenshot/wxpay2.png" width="400" />
</p>
## 常见问题
请前往 [问题地址](doc/question.md) 查看具体信息
## Discussion
添加 QQ 群: 567510628

View File

@@ -16,9 +16,13 @@ echo "编译前端项目"
cd $cpath/web
#国内可替换源加快速度
#npx browserslist@latest --update-db
npm install --registry=https://registry.npm.taobao.org
#npm install --registry=https://registry.npm.taobao.org
#npm install
npm run build
#npm run build
yarn install
yarn run build
RETVAL $?
echo "编译二进制文件"
@@ -42,6 +46,7 @@ cp -r server/bridge-init.sh $deploy
cp -r server/conf $deploy
cp -r systemd $deploy
cp -r LICENSE $deploy
tar zcvf ${deploy}.tar.gz $deploy

View File

@@ -18,6 +18,6 @@ case $var1 in
iptables -t nat -A POSTROUTING -s "${IPV4_CIDR}" -o eth0+ -j MASQUERADE
iptables -nL -t nat
/app/anylink "$@"
exec /app/anylink "$@"
;;
esac

View File

@@ -2,6 +2,7 @@
package admin
import (
"crypto/tls"
"embed"
"net/http"
"net/http/pprof"
@@ -18,6 +19,11 @@ func StartAdmin() {
r := mux.NewRouter()
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.PathPrefix("/ui/").Handler(
// http.StripPrefix("/ui/", http.FileServer(http.Dir(base.Cfg.UiPath))),
@@ -64,7 +70,25 @@ func StartAdmin() {
}
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 {
base.Fatal(err)
}

View File

@@ -2,6 +2,6 @@ package base
const (
APP_NAME = "AnyLink"
// 修复前端bug
APP_VER = "0.7.1"
// 修复 CVE-2016-2183
APP_VER = "0.7.4"
)

View File

@@ -32,6 +32,7 @@ var (
type ServerConfig struct {
// LinkAddr string `json:"link_addr"`
Conf string `json:"conf"`
Profile string `json:"profile"`
ServerAddr string `json:"server_addr"`
ServerDTLSAddr string `json:"server_dtls_addr"`
ServerDTLS bool `json:"server_dtls"`

View File

@@ -21,6 +21,7 @@ type config struct {
var configs = []config{
{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: cfgBool, Name: "server_dtls", Usage: "开启DTLS", ValBool: false},
{Typ: cfgStr, Name: "server_dtls_addr", Usage: "DTLS监听地址", ValStr: ":4433"},

View File

@@ -6,10 +6,11 @@
#数据文件
db_type = "sqlite3"
db_source = "./conf/anylink.db"
#证书文件
cert_file = "./conf/vpn_cert.pem"
#证书文件 使用跟nginx一样的证书即可
cert_file = "./conf/vpn_cert.crt"
cert_key = "./conf/vpn_cert.key"
files_path = "./conf/files"
profile = "./conf/profile.xml"
#日志目录,为空写入标准输出
#log_path = "./log"
log_path = ""

View File

@@ -7,9 +7,10 @@
db_type = "sqlite3"
db_source = "./conf/anylink.db"
#证书文件
cert_file = "./conf/vpn_cert.pem"
cert_file = "./conf/vpn_cert.crt"
cert_key = "./conf/vpn_cert.key"
files_path = "./conf/files"
log_level = "debug"
#系统名称
issuer = "XX公司VPN"

View File

@@ -102,7 +102,23 @@ func addInitData() error {
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 {

View File

@@ -12,6 +12,7 @@ import (
const (
Allow = "allow"
Deny = "deny"
All = "all"
)
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{}
for _, v := range g.RouteInclude {
if v.Val != "" {
if v.Val == "all" {
if v.Val == All {
routeInclude = append(routeInclude, v)
continue
}
@@ -124,6 +110,24 @@ func SetGroup(g *Group) error {
}
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()
if g.Id > 0 {
err = Set(g)

View File

@@ -14,6 +14,8 @@ import (
"github.com/bjdgyc/anylink/sessdata"
)
var profileHash = ""
func LinkAuth(w http.ResponseWriter, r *http.Request) {
// 判断anyconnect客户端
userAgent := strings.ToLower(r.UserAgent())
@@ -89,7 +91,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}
Banner: other.Banner, ProfileHash: profileHash}
w.WriteHeader(http.StatusOK)
tplRequest(tpl_complete, w, rd)
base.Debug("login", cr.Auth.Username)
@@ -125,6 +127,7 @@ type RequestData struct {
SessionId string
SessionToken string
Banner string
ProfileHash string
}
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 rev="1.0">
<file type="profile" service-type="user">
<uri>/files/profile.xml</uri>
<hash type="sha1">A8B0B07FBA93D06E8501E40AB807AEE2464E73B7</hash>
<uri>/profile.xml</uri>
<hash type="sha1">{{.ProfileHash}}</hash>
</file>
</vpn>
</vpn-profile-manifest>

View File

@@ -10,6 +10,7 @@ import (
"strings"
"github.com/bjdgyc/anylink/base"
"github.com/bjdgyc/anylink/dbdata"
"github.com/bjdgyc/anylink/sessdata"
)
@@ -108,7 +109,7 @@ func LinkTunnel(w http.ResponseWriter, r *http.Request) {
}
// 允许的路由
for _, v := range cSess.Group.RouteInclude {
if v.Val == "all" {
if v.Val == dbdata.All {
continue
}
HttpAddHeader(w, "X-CSTP-Split-Include", v.IpMask)

View File

@@ -6,6 +6,7 @@ import (
"log"
"net"
"net/http"
"os"
"time"
"github.com/bjdgyc/anylink/base"
@@ -19,9 +20,6 @@ func startTls() {
err error
addr = base.Cfg.ServerAddr
certFile = base.Cfg.CertFile
keyFile = base.Cfg.CertKey
certs = make([]tls.Certificate, 1)
ln net.Listener
)
@@ -35,16 +33,20 @@ func startTls() {
// certs[0], err = tls.LoadX509KeyPair(certFile, keyFile)
// }
certs[0], err = tls.LoadX509KeyPair(certFile, keyFile)
if err != nil {
panic(err)
// 修复 CVE-2016-2183
// https://segmentfault.com/a/1190000038486901
// 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信息
tlsConfig := &tls.Config{
NextProtos: []string{"http/1.1"},
MinVersion: tls.VersionTLS12,
Certificates: certs,
CipherSuites: selectedCipherSuites,
// InsecureSkipVerify: true,
}
srv := &http.Server{
@@ -65,7 +67,7 @@ func startTls() {
}
base.Info("listen server", addr)
err = srv.ServeTLS(ln, "", "")
err = srv.ServeTLS(ln, base.Cfg.CertFile, base.Cfg.CertKey)
if err != nil {
base.Fatal(err)
}
@@ -77,9 +79,10 @@ func initRoute() http.Handler {
r.HandleFunc("/", LinkAuth).Methods(http.MethodPost)
r.HandleFunc("/CSCOSSLC/tunnel", LinkTunnel).Methods(http.MethodConnect)
r.HandleFunc("/otp_qr", LinkOtpQr).Methods(http.MethodGet)
// r.HandleFunc("/profile.xml", func(w http.ResponseWriter, r *http.Request) {
// w.Write([]byte(auth_profile))
// }).Methods(http.MethodGet)
r.HandleFunc("/profile.xml", func(w http.ResponseWriter, r *http.Request) {
b, _ := os.ReadFile(base.Cfg.Profile)
w.Write(b)
}).Methods(http.MethodGet)
r.PathPrefix("/files/").Handler(
http.StripPrefix("/files/",
http.FileServer(http.Dir(base.Cfg.FilesPath)),

View File

@@ -1,6 +1,10 @@
package handler
import (
"crypto/sha1"
"encoding/hex"
"os"
"github.com/bjdgyc/anylink/admin"
"github.com/bjdgyc/anylink/base"
"github.com/bjdgyc/anylink/dbdata"
@@ -22,6 +26,14 @@ func Start() {
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 startTls()
go startDtls()

View File

@@ -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
+---------------------+---------------------------------------------+

27581
web/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -423,6 +423,7 @@ export default {
if (rdata.code === 0) {
this.$message.success(rdata.msg);
this.getData(1);
this.user_edit_dialog = false
} else {
this.$message.error(rdata.msg);
}

View File

@@ -388,6 +388,7 @@ export default {
if (data.code === 0) {
this.$message.success(data.msg);
this.getData(1);
this.user_edit_dialog = false
} else {
this.$message.error(data.msg);
}

8661
web/yarn.lock Normal file

File diff suppressed because it is too large Load Diff