diff --git a/server/dbdata/group.go b/server/dbdata/group.go index 252f3f8..1eed65f 100644 --- a/server/dbdata/group.go +++ b/server/dbdata/group.go @@ -4,6 +4,8 @@ import ( "errors" "fmt" "net" + "regexp" + "strings" "time" "github.com/bjdgyc/anylink/base" @@ -127,6 +129,20 @@ func SetGroup(g *Group) error { } } 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() if g.Id > 0 { @@ -149,3 +165,27 @@ func parseIpNet(s string) (string, *net.IPNet, error) { 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) +} diff --git a/server/dbdata/tables.go b/server/dbdata/tables.go index 48df52e..a0ffea2 100644 --- a/server/dbdata/tables.go +++ b/server/dbdata/tables.go @@ -6,18 +6,20 @@ import ( ) type Group struct { - Id int `json:"id" xorm:"pk autoincr not null"` - Name string `json:"name" xorm:"varchar(60) not null unique"` - Note string `json:"note" xorm:"varchar(255)"` - AllowLan bool `json:"allow_lan" xorm:"Bool"` - ClientDns []ValData `json:"client_dns" xorm:"Text"` - RouteInclude []ValData `json:"route_include" xorm:"Text"` - RouteExclude []ValData `json:"route_exclude" xorm:"Text"` - LinkAcl []GroupLinkAcl `json:"link_acl" xorm:"Text"` - Bandwidth int `json:"bandwidth" xorm:"Int"` // 带宽限制 - Status int8 `json:"status" xorm:"Int"` // 1正常 - CreatedAt time.Time `json:"created_at" xorm:"DateTime created"` - UpdatedAt time.Time `json:"updated_at" xorm:"DateTime updated"` + Id int `json:"id" xorm:"pk autoincr not null"` + Name string `json:"name" xorm:"varchar(60) not null unique"` + Note string `json:"note" xorm:"varchar(255)"` + AllowLan bool `json:"allow_lan" xorm:"Bool"` + ClientDns []ValData `json:"client_dns" xorm:"Text"` + RouteInclude []ValData `json:"route_include" 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"` + Bandwidth int `json:"bandwidth" xorm:"Int"` // 带宽限制 + Status int8 `json:"status" xorm:"Int"` // 1正常 + CreatedAt time.Time `json:"created_at" xorm:"DateTime created"` + UpdatedAt time.Time `json:"updated_at" xorm:"DateTime updated"` } type User struct { diff --git a/server/handler/link_tunnel.go b/server/handler/link_tunnel.go index a43cb5f..295a19c 100644 --- a/server/handler/link_tunnel.go +++ b/server/handler/link_tunnel.go @@ -8,6 +8,7 @@ import ( "net/http" "os" "strings" + "text/template" "github.com/bjdgyc/anylink/base" "github.com/bjdgyc/anylink/dbdata" @@ -118,7 +119,6 @@ func LinkTunnel(w http.ResponseWriter, r *http.Request) { for _, v := range cSess.Group.RouteExclude { 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-Session-Timeout", "none") 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-Client-Bypass-Protocol", "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) hClone := w.Header().Clone() @@ -187,3 +191,42 @@ func LinkTunnel(w http.ResponseWriter, r *http.Request) { 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 = ` + + + + + + {{if .DsExcludeDomains}} + + {{end}} + {{if .DsIncludeDomains}} + + {{end}} + + + + +` \ No newline at end of file diff --git a/web/src/pages/group/List.vue b/web/src/pages/group/List.vue index 2fbb4b3..77fa358 100644 --- a/web/src/pages/group/List.vue +++ b/web/src/pages/group/List.vue @@ -152,143 +152,155 @@ center> - - - + + + + + - - - + + + - - - + + + - - - - - - - - - + + + + + + + + + - - - 输入IP格式如: 192.168.0.10 - - - - - - - - - - - - - - - - + + + 输入IP格式如: 192.168.0.10 + + + + + + + + + + + + + + + + + + + 启用 + 停用 + + + - - - 输入CIDR格式如: 192.168.1.0/24 - - - - - - - - - - - - - - - - + + + + 输入CIDR格式如: 192.168.1.0/24 + + + + + + + + + + + + + + + + - - - 输入CIDR格式如: 192.168.2.0/24 - - - - - - - - - - - - - - - - + + + 输入CIDR格式如: 192.168.2.0/24 + + + + + + + + + + + + + + + + + + + + + 输入CIDR格式如: 192.168.3.0/24 端口0表示所有端口 + + + + - - - 输入CIDR格式如: 192.168.3.0/24 端口0表示所有端口 - - - - + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - 启用 - 停用 - - - - - - 保存 - 取消 - - + + + + + + + + + + 保存 + 取消 + + @@ -313,6 +325,7 @@ export default { page: 1, tableData: [], count: 10, + activeTab : "general", ruleForm: { bandwidth: 0,