mirror of https://github.com/bjdgyc/anylink.git
commit
1cbe9bfc30
23
README.md
23
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 证书,不支持私有证书连接
|
||||||
|
@ -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 转发规则
|
||||||
|
@ -189,18 +196,18 @@ sh bridge-init.sh
|
||||||
|
|
||||||
1. 添加 anylink 程序
|
1. 添加 anylink 程序
|
||||||
|
|
||||||
- anylink 程序目录放入 `/usr/local/anylink-deploy`
|
- anylink 程序目录放入 `/usr/local/anylink-deploy`
|
||||||
|
|
||||||
2. systemd/anylink.service 脚本放入:
|
2. systemd/anylink.service 脚本放入:
|
||||||
|
|
||||||
- centos: `/usr/lib/systemd/system/`
|
- centos: `/usr/lib/systemd/system/`
|
||||||
- ubuntu: `/lib/systemd/system/`
|
- ubuntu: `/lib/systemd/system/`
|
||||||
|
|
||||||
3. 操作命令:
|
3. 操作命令:
|
||||||
|
|
||||||
- 启动: `systemctl start anylink`
|
- 启动: `systemctl start anylink`
|
||||||
- 停止: `systemctl stop anylink`
|
- 停止: `systemctl stop anylink`
|
||||||
- 开机自启: `systemctl enable anylink`
|
- 开机自启: `systemctl enable anylink`
|
||||||
|
|
||||||
## Docker
|
## Docker
|
||||||
|
|
||||||
|
|
|
@ -69,7 +69,7 @@ func StartAdmin() {
|
||||||
}
|
}
|
||||||
|
|
||||||
base.Info("Listen admin", base.Cfg.AdminAddr)
|
base.Info("Listen admin", base.Cfg.AdminAddr)
|
||||||
err := http.ListenAndServe(base.Cfg.AdminAddr, r)
|
err := http.ListenAndServeTLS(base.Cfg.AdminAddr, base.Cfg.CertFile, base.Cfg.CertKey, r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
base.Fatal(err)
|
base.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
db_type = "sqlite3"
|
db_type = "sqlite3"
|
||||||
db_source = "./conf/anylink.db"
|
db_source = "./conf/anylink.db"
|
||||||
#证书文件 使用跟nginx一样的证书即可
|
#证书文件 使用跟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"
|
profile = "./conf/profile.xml"
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -23,11 +24,11 @@ func init() {
|
||||||
}
|
}
|
||||||
|
|
||||||
func HttpSetHeader(w http.ResponseWriter, key string, value string) {
|
func HttpSetHeader(w http.ResponseWriter, key string, value string) {
|
||||||
w.Header()[key] = []string{value}
|
w.Header()[key] = []string{value}
|
||||||
}
|
}
|
||||||
|
|
||||||
func HttpAddHeader(w http.ResponseWriter, key string, value string) {
|
func HttpAddHeader(w http.ResponseWriter, key string, value string) {
|
||||||
w.Header()[key] = append(w.Header()[key], value)
|
w.Header()[key] = append(w.Header()[key], value)
|
||||||
}
|
}
|
||||||
|
|
||||||
func LinkTunnel(w http.ResponseWriter, r *http.Request) {
|
func LinkTunnel(w http.ResponseWriter, r *http.Request) {
|
||||||
|
@ -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)
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue