mirror of https://github.com/bjdgyc/anylink.git
新增域名动态拆分隧道(域名路由功能)
This commit is contained in:
parent
ccce143f85
commit
522be82a31
|
@ -4,6 +4,8 @@ import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
|
"regexp"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/bjdgyc/anylink/base"
|
"github.com/bjdgyc/anylink/base"
|
||||||
|
@ -127,6 +129,20 @@ func SetGroup(g *Group) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
g.ClientDns = clientDns
|
g.ClientDns = clientDns
|
||||||
|
// 域名拆分隧道,不能同时填写
|
||||||
|
if g.DsIncludeDomains != "" && g.DsExcludeDomains != "" {
|
||||||
|
return errors.New("包含/排除域名不能同时填写")
|
||||||
|
}
|
||||||
|
// 校验包含域名的格式
|
||||||
|
err = CheckDomainNames(g.DsIncludeDomains)
|
||||||
|
if err != nil {
|
||||||
|
return errors.New("包含域名有误:" + err.Error())
|
||||||
|
}
|
||||||
|
// 校验排除域名的格式
|
||||||
|
err = CheckDomainNames(g.DsExcludeDomains)
|
||||||
|
if err != nil {
|
||||||
|
return errors.New("排除域名有误:" + err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
g.UpdatedAt = time.Now()
|
g.UpdatedAt = time.Now()
|
||||||
if g.Id > 0 {
|
if g.Id > 0 {
|
||||||
|
@ -149,3 +165,27 @@ func parseIpNet(s string) (string, *net.IPNet, error) {
|
||||||
|
|
||||||
return ipMask, ipNet, nil
|
return ipMask, ipNet, nil
|
||||||
}
|
}
|
||||||
|
func CheckDomainNames(domains string) error {
|
||||||
|
if domains == "" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
str_slice := strings.Split(domains, ",")
|
||||||
|
for _, val := range str_slice {
|
||||||
|
if val == "" {
|
||||||
|
return errors.New(val + " 请以逗号分隔域名")
|
||||||
|
}
|
||||||
|
if !ValidateDomainName(val) {
|
||||||
|
return errors.New(val + " 域名有误")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func ValidateDomainName(domain string) bool {
|
||||||
|
pos := strings.LastIndex(domain, ".")
|
||||||
|
if pos != -1 && len(domain[pos+1:]) < 2 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
RegExp := regexp.MustCompile(`^[a-zA-Z0-9][-a-zA-Z0-9]{0,62}(\.[a-zA-Z0-9][-a-zA-Z0-9]{0,62})+$`)
|
||||||
|
return RegExp.MatchString(domain)
|
||||||
|
}
|
||||||
|
|
|
@ -13,6 +13,8 @@ type Group struct {
|
||||||
ClientDns []ValData `json:"client_dns" xorm:"Text"`
|
ClientDns []ValData `json:"client_dns" xorm:"Text"`
|
||||||
RouteInclude []ValData `json:"route_include" xorm:"Text"`
|
RouteInclude []ValData `json:"route_include" xorm:"Text"`
|
||||||
RouteExclude []ValData `json:"route_exclude" xorm:"Text"`
|
RouteExclude []ValData `json:"route_exclude" xorm:"Text"`
|
||||||
|
DsExcludeDomains string `json:"ds_exclude_domains" xorm:"Text"`
|
||||||
|
DsIncludeDomains string `json:"ds_include_domains" xorm:"Text"`
|
||||||
LinkAcl []GroupLinkAcl `json:"link_acl" xorm:"Text"`
|
LinkAcl []GroupLinkAcl `json:"link_acl" xorm:"Text"`
|
||||||
Bandwidth int `json:"bandwidth" xorm:"Int"` // 带宽限制
|
Bandwidth int `json:"bandwidth" xorm:"Int"` // 带宽限制
|
||||||
Status int8 `json:"status" xorm:"Int"` // 1正常
|
Status int8 `json:"status" xorm:"Int"` // 1正常
|
||||||
|
|
|
@ -8,6 +8,7 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
|
"text/template"
|
||||||
|
|
||||||
"github.com/bjdgyc/anylink/base"
|
"github.com/bjdgyc/anylink/base"
|
||||||
"github.com/bjdgyc/anylink/dbdata"
|
"github.com/bjdgyc/anylink/dbdata"
|
||||||
|
@ -118,7 +119,6 @@ func LinkTunnel(w http.ResponseWriter, r *http.Request) {
|
||||||
for _, v := range cSess.Group.RouteExclude {
|
for _, v := range cSess.Group.RouteExclude {
|
||||||
HttpAddHeader(w, "X-CSTP-Split-Exclude", v.IpMask)
|
HttpAddHeader(w, "X-CSTP-Split-Exclude", v.IpMask)
|
||||||
}
|
}
|
||||||
|
|
||||||
HttpSetHeader(w, "X-CSTP-Lease-Duration", fmt.Sprintf("%d", base.Cfg.IpLease)) // ip地址租期
|
HttpSetHeader(w, "X-CSTP-Lease-Duration", fmt.Sprintf("%d", base.Cfg.IpLease)) // ip地址租期
|
||||||
HttpSetHeader(w, "X-CSTP-Session-Timeout", "none")
|
HttpSetHeader(w, "X-CSTP-Session-Timeout", "none")
|
||||||
HttpSetHeader(w, "X-CSTP-Session-Timeout-Alert-Interval", "60")
|
HttpSetHeader(w, "X-CSTP-Session-Timeout-Alert-Interval", "60")
|
||||||
|
@ -153,7 +153,11 @@ func LinkTunnel(w http.ResponseWriter, r *http.Request) {
|
||||||
HttpSetHeader(w, "X-CSTP-Disable-Always-On-VPN", "false")
|
HttpSetHeader(w, "X-CSTP-Disable-Always-On-VPN", "false")
|
||||||
HttpSetHeader(w, "X-CSTP-Client-Bypass-Protocol", "false")
|
HttpSetHeader(w, "X-CSTP-Client-Bypass-Protocol", "false")
|
||||||
HttpSetHeader(w, "X-CSTP-TCP-Keepalive", "false")
|
HttpSetHeader(w, "X-CSTP-TCP-Keepalive", "false")
|
||||||
// HttpSetHeader(w, "X-CSTP-Post-Auth-XML", ``)
|
// 设置域名拆分隧道(移动端不支持)
|
||||||
|
if mobile != "mobile" {
|
||||||
|
SetPostAuthXml(cSess.Group, w)
|
||||||
|
}
|
||||||
|
|
||||||
w.WriteHeader(http.StatusOK)
|
w.WriteHeader(http.StatusOK)
|
||||||
|
|
||||||
hClone := w.Header().Clone()
|
hClone := w.Header().Clone()
|
||||||
|
@ -187,3 +191,42 @@ func LinkTunnel(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
go LinkCstp(conn, bufRW, cSess)
|
go LinkCstp(conn, bufRW, cSess)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 设置域名拆分隧道
|
||||||
|
func SetPostAuthXml(g *dbdata.Group, w http.ResponseWriter) error {
|
||||||
|
if g.DsExcludeDomains == "" && g.DsIncludeDomains == "" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
tmpl, err := template.New("post_auth_xml").Parse(ds_domains_xml)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
var result bytes.Buffer
|
||||||
|
_ = tmpl.Execute(&result, g)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if result.String() != "" {
|
||||||
|
HttpSetHeader(w, "X-CSTP-Post-Auth-XML", result.String())
|
||||||
|
base.Info(result.String())
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var ds_domains_xml = `
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<config-auth client="vpn" type="complete" aggregate-auth-version="2">
|
||||||
|
<config client="vpn" type="private">
|
||||||
|
<opaque is-for="vpn-client">
|
||||||
|
<custom-attr>
|
||||||
|
{{if .DsExcludeDomains}}
|
||||||
|
<dynamic-split-exclude-domains><![CDATA[{{.DsExcludeDomains}},]]></dynamic-split-exclude-domains>
|
||||||
|
{{end}}
|
||||||
|
{{if .DsIncludeDomains}}
|
||||||
|
<dynamic-split-include-domains><![CDATA[{{.DsIncludeDomains}}]]></dynamic-split-include-domains>
|
||||||
|
{{end}}
|
||||||
|
</custom-attr>
|
||||||
|
</opaque>
|
||||||
|
</config>
|
||||||
|
</config-auth>
|
||||||
|
`
|
|
@ -152,6 +152,8 @@
|
||||||
center>
|
center>
|
||||||
|
|
||||||
<el-form :model="ruleForm" :rules="rules" ref="ruleForm" label-width="100px" class="ruleForm">
|
<el-form :model="ruleForm" :rules="rules" ref="ruleForm" label-width="100px" class="ruleForm">
|
||||||
|
<el-tabs v-model="activeTab">
|
||||||
|
<el-tab-pane label="通用" name="general">
|
||||||
<el-form-item label="用户组ID" prop="id">
|
<el-form-item label="用户组ID" prop="id">
|
||||||
<el-input v-model="ruleForm.id" disabled></el-input>
|
<el-input v-model="ruleForm.id" disabled></el-input>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
@ -197,7 +199,15 @@
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
<el-form-item label="状态" prop="status">
|
||||||
|
<el-radio-group v-model="ruleForm.status">
|
||||||
|
<el-radio :label="1" border>启用</el-radio>
|
||||||
|
<el-radio :label="0" border>停用</el-radio>
|
||||||
|
</el-radio-group>
|
||||||
|
</el-form-item>
|
||||||
|
</el-tab-pane>
|
||||||
|
|
||||||
|
<el-tab-pane label="路由设置" name="route">
|
||||||
<el-form-item label="包含路由" prop="route_include">
|
<el-form-item label="包含路由" prop="route_include">
|
||||||
<el-row class="msg-info">
|
<el-row class="msg-info">
|
||||||
<el-col :span="20">输入CIDR格式如: 192.168.1.0/24</el-col>
|
<el-col :span="20">输入CIDR格式如: 192.168.1.0/24</el-col>
|
||||||
|
@ -243,7 +253,8 @@
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
</el-tab-pane>
|
||||||
|
<el-tab-pane label="权限控制" name="link_acl">
|
||||||
<el-form-item label="权限控制" prop="link_acl">
|
<el-form-item label="权限控制" prop="link_acl">
|
||||||
<el-row class="msg-info">
|
<el-row class="msg-info">
|
||||||
<el-col :span="20">输入CIDR格式如: 192.168.3.0/24 端口0表示所有端口</el-col>
|
<el-col :span="20">输入CIDR格式如: 192.168.3.0/24 端口0表示所有端口</el-col>
|
||||||
|
@ -275,15 +286,16 @@
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
</el-tab-pane>
|
||||||
|
|
||||||
<el-form-item label="状态" prop="status">
|
<el-tab-pane label="域名拆分隧道" name="ds_domains">
|
||||||
<el-radio-group v-model="ruleForm.status">
|
<el-form-item label="包含域名" prop="ds_include_domains">
|
||||||
<el-radio :label="1" border>启用</el-radio>
|
<el-input type="textarea" :rows="5" v-model="ruleForm.ds_include_domains" placeholder="输入域名用,号分隔,默认匹配所有子域名, 如baidu.com,163.com"></el-input>
|
||||||
<el-radio :label="0" border>停用</el-radio>
|
|
||||||
</el-radio-group>
|
|
||||||
|
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
<el-form-item label="排除域名" prop="ds_exclude_domains">
|
||||||
|
<el-input type="textarea" :rows="5" v-model="ruleForm.ds_exclude_domains" placeholder="输入域名用,号分隔,默认匹配所有子域名, 如baidu.com,163.com"></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
</el-tab-pane>
|
||||||
<el-form-item>
|
<el-form-item>
|
||||||
<el-button type="primary" @click="submitForm('ruleForm')">保存</el-button>
|
<el-button type="primary" @click="submitForm('ruleForm')">保存</el-button>
|
||||||
<el-button @click="disVisible">取消</el-button>
|
<el-button @click="disVisible">取消</el-button>
|
||||||
|
@ -313,6 +325,7 @@ export default {
|
||||||
page: 1,
|
page: 1,
|
||||||
tableData: [],
|
tableData: [],
|
||||||
count: 10,
|
count: 10,
|
||||||
|
activeTab : "general",
|
||||||
|
|
||||||
ruleForm: {
|
ruleForm: {
|
||||||
bandwidth: 0,
|
bandwidth: 0,
|
||||||
|
|
Loading…
Reference in New Issue