2021-06-08 20:45:26 +08:00
|
|
|
|
package dbdata
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"errors"
|
|
|
|
|
"fmt"
|
|
|
|
|
"net"
|
2022-07-04 15:03:22 +08:00
|
|
|
|
"regexp"
|
|
|
|
|
"strings"
|
2021-06-08 20:45:26 +08:00
|
|
|
|
"time"
|
|
|
|
|
|
|
|
|
|
"github.com/bjdgyc/anylink/base"
|
2022-11-10 15:53:48 +08:00
|
|
|
|
"golang.org/x/text/language"
|
|
|
|
|
"golang.org/x/text/message"
|
2021-06-08 20:45:26 +08:00
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
const (
|
|
|
|
|
Allow = "allow"
|
|
|
|
|
Deny = "deny"
|
2022-02-16 14:23:17 +08:00
|
|
|
|
All = "all"
|
2021-06-08 20:45:26 +08:00
|
|
|
|
)
|
|
|
|
|
|
2022-11-10 15:53:48 +08:00
|
|
|
|
// 域名分流最大字符2万
|
|
|
|
|
const DsMaxLen = 20000
|
|
|
|
|
|
2021-06-08 20:45:26 +08:00
|
|
|
|
type GroupLinkAcl struct {
|
|
|
|
|
// 自上而下匹配 默认 allow * *
|
|
|
|
|
Action string `json:"action"` // allow、deny
|
|
|
|
|
Val string `json:"val"`
|
|
|
|
|
Port uint16 `json:"port"`
|
|
|
|
|
IpNet *net.IPNet `json:"ip_net"`
|
|
|
|
|
Note string `json:"note"`
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type ValData struct {
|
|
|
|
|
Val string `json:"val"`
|
|
|
|
|
IpMask string `json:"ip_mask"`
|
|
|
|
|
Note string `json:"note"`
|
|
|
|
|
}
|
|
|
|
|
|
2022-11-10 15:53:48 +08:00
|
|
|
|
type GroupNameId struct {
|
|
|
|
|
Id int `json:"id"`
|
|
|
|
|
Name string `json:"name"`
|
|
|
|
|
}
|
|
|
|
|
|
2021-08-02 20:41:35 +08:00
|
|
|
|
// type Group struct {
|
2022-07-04 15:03:22 +08:00
|
|
|
|
// 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"` // 带宽限制
|
|
|
|
|
// Auth map[string]interface{} `json:"auth" xorm:"not null default '{}' varchar(255)"` // 认证方式
|
|
|
|
|
// 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"`
|
2021-08-02 20:41:35 +08:00
|
|
|
|
// }
|
2021-06-08 20:45:26 +08:00
|
|
|
|
|
|
|
|
|
func GetGroupNames() []string {
|
|
|
|
|
var datas []Group
|
2021-08-02 20:41:35 +08:00
|
|
|
|
err := Find(&datas, 0, 0)
|
2021-06-08 20:45:26 +08:00
|
|
|
|
if err != nil {
|
|
|
|
|
base.Error(err)
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
var names []string
|
|
|
|
|
for _, v := range datas {
|
|
|
|
|
names = append(names, v.Name)
|
|
|
|
|
}
|
|
|
|
|
return names
|
|
|
|
|
}
|
|
|
|
|
|
2023-04-26 22:17:10 +08:00
|
|
|
|
func GetGroupNamesNormal() []string {
|
|
|
|
|
var datas []Group
|
|
|
|
|
err := FindWhere(&datas, 0, 0, "status=1")
|
|
|
|
|
if err != nil {
|
|
|
|
|
base.Error(err)
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
var names []string
|
|
|
|
|
for _, v := range datas {
|
|
|
|
|
names = append(names, v.Name)
|
|
|
|
|
}
|
|
|
|
|
return names
|
|
|
|
|
}
|
|
|
|
|
|
2022-11-10 15:53:48 +08:00
|
|
|
|
func GetGroupNamesIds() []GroupNameId {
|
|
|
|
|
var datas []Group
|
|
|
|
|
err := Find(&datas, 0, 0)
|
|
|
|
|
if err != nil {
|
|
|
|
|
base.Error(err)
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
var names []GroupNameId
|
|
|
|
|
for _, v := range datas {
|
|
|
|
|
names = append(names, GroupNameId{Id: v.Id, Name: v.Name})
|
|
|
|
|
}
|
|
|
|
|
return names
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-08 20:45:26 +08:00
|
|
|
|
func SetGroup(g *Group) error {
|
|
|
|
|
var err error
|
|
|
|
|
if g.Name == "" {
|
|
|
|
|
return errors.New("用户组名错误")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 判断数据
|
|
|
|
|
routeInclude := []ValData{}
|
|
|
|
|
for _, v := range g.RouteInclude {
|
|
|
|
|
if v.Val != "" {
|
2022-02-16 14:23:17 +08:00
|
|
|
|
if v.Val == All {
|
2021-08-26 23:09:52 +08:00
|
|
|
|
routeInclude = append(routeInclude, v)
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-08 20:45:26 +08:00
|
|
|
|
ipMask, _, err := parseIpNet(v.Val)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return errors.New("RouteInclude 错误" + err.Error())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
v.IpMask = ipMask
|
|
|
|
|
routeInclude = append(routeInclude, v)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
g.RouteInclude = routeInclude
|
|
|
|
|
routeExclude := []ValData{}
|
|
|
|
|
for _, v := range g.RouteExclude {
|
|
|
|
|
if v.Val != "" {
|
|
|
|
|
ipMask, _, err := parseIpNet(v.Val)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return errors.New("RouteExclude 错误" + err.Error())
|
|
|
|
|
}
|
|
|
|
|
v.IpMask = ipMask
|
|
|
|
|
routeExclude = append(routeExclude, v)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
g.RouteExclude = routeExclude
|
|
|
|
|
// 转换数据
|
|
|
|
|
linkAcl := []GroupLinkAcl{}
|
|
|
|
|
for _, v := range g.LinkAcl {
|
|
|
|
|
if v.Val != "" {
|
|
|
|
|
_, ipNet, err := parseIpNet(v.Val)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return errors.New("GroupLinkAcl 错误" + err.Error())
|
|
|
|
|
}
|
|
|
|
|
v.IpNet = ipNet
|
|
|
|
|
linkAcl = append(linkAcl, v)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
g.LinkAcl = linkAcl
|
|
|
|
|
|
2022-02-16 14:23:17 +08:00
|
|
|
|
// 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)
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-11-10 15:53:48 +08:00
|
|
|
|
// 是否默认路由
|
|
|
|
|
isDefRoute := len(routeInclude) == 0 || (len(routeInclude) == 1 && routeInclude[0].Val == "all")
|
|
|
|
|
if isDefRoute && len(clientDns) == 0 {
|
|
|
|
|
return errors.New("默认路由,必须设置一个DNS")
|
2022-02-16 14:23:17 +08:00
|
|
|
|
}
|
|
|
|
|
g.ClientDns = clientDns
|
2022-07-04 15:03:22 +08:00
|
|
|
|
// 域名拆分隧道,不能同时填写
|
|
|
|
|
g.DsIncludeDomains = strings.TrimSpace(g.DsIncludeDomains)
|
|
|
|
|
g.DsExcludeDomains = strings.TrimSpace(g.DsExcludeDomains)
|
|
|
|
|
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())
|
|
|
|
|
}
|
2022-11-10 15:53:48 +08:00
|
|
|
|
if isDefRoute && g.DsIncludeDomains != "" {
|
|
|
|
|
return errors.New("默认路由, 不允许设置\"包含域名\", 请重新配置")
|
|
|
|
|
}
|
2022-07-04 15:03:22 +08:00
|
|
|
|
// 处理登入方式的逻辑
|
|
|
|
|
defAuth := map[string]interface{}{
|
|
|
|
|
"type": "local",
|
|
|
|
|
}
|
|
|
|
|
if len(g.Auth) == 0 {
|
|
|
|
|
g.Auth = defAuth
|
|
|
|
|
}
|
|
|
|
|
authType := g.Auth["type"].(string)
|
|
|
|
|
if authType == "local" {
|
|
|
|
|
g.Auth = defAuth
|
|
|
|
|
} else {
|
2022-11-10 15:53:48 +08:00
|
|
|
|
if _, ok := authRegistry[authType]; !ok {
|
2022-07-04 15:03:22 +08:00
|
|
|
|
return errors.New("未知的认证方式: " + authType)
|
|
|
|
|
}
|
|
|
|
|
auth := makeInstance(authType).(IUserAuth)
|
|
|
|
|
err = auth.checkData(g.Auth)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
2022-11-10 15:53:48 +08:00
|
|
|
|
// 重置Auth, 删除多余的key
|
|
|
|
|
g.Auth = map[string]interface{}{
|
|
|
|
|
"type": authType,
|
|
|
|
|
authType: g.Auth[authType],
|
|
|
|
|
}
|
2022-07-04 15:03:22 +08:00
|
|
|
|
}
|
2022-02-16 14:23:17 +08:00
|
|
|
|
|
2021-06-08 20:45:26 +08:00
|
|
|
|
g.UpdatedAt = time.Now()
|
2021-08-02 20:41:35 +08:00
|
|
|
|
if g.Id > 0 {
|
|
|
|
|
err = Set(g)
|
|
|
|
|
} else {
|
|
|
|
|
err = Add(g)
|
|
|
|
|
}
|
2021-06-08 20:45:26 +08:00
|
|
|
|
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
2023-04-26 22:17:10 +08:00
|
|
|
|
func GroupAuthLogin(name, pwd string, authData map[string]interface{}) error {
|
|
|
|
|
g := &Group{Auth: authData}
|
|
|
|
|
authType := g.Auth["type"].(string)
|
|
|
|
|
if _, ok := authRegistry[authType]; !ok {
|
|
|
|
|
return errors.New("未知的认证方式: " + authType)
|
|
|
|
|
}
|
|
|
|
|
auth := makeInstance(authType).(IUserAuth)
|
|
|
|
|
err := auth.checkData(g.Auth)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
err = auth.checkUser(name, pwd, g)
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-08 20:45:26 +08:00
|
|
|
|
func parseIpNet(s string) (string, *net.IPNet, error) {
|
|
|
|
|
ip, ipNet, err := net.ParseCIDR(s)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return "", nil, err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
mask := net.IP(ipNet.Mask)
|
|
|
|
|
ipMask := fmt.Sprintf("%s/%s", ip, mask)
|
|
|
|
|
|
|
|
|
|
return ipMask, ipNet, nil
|
|
|
|
|
}
|
2022-07-04 15:03:22 +08:00
|
|
|
|
|
|
|
|
|
func CheckDomainNames(domains string) error {
|
|
|
|
|
if domains == "" {
|
|
|
|
|
return nil
|
|
|
|
|
}
|
2022-11-10 15:53:48 +08:00
|
|
|
|
strLen := 0
|
2022-07-04 15:03:22 +08:00
|
|
|
|
str_slice := strings.Split(domains, ",")
|
|
|
|
|
for _, val := range str_slice {
|
|
|
|
|
if val == "" {
|
|
|
|
|
return errors.New(val + " 请以逗号分隔域名")
|
|
|
|
|
}
|
|
|
|
|
if !ValidateDomainName(val) {
|
|
|
|
|
return errors.New(val + " 域名有误")
|
|
|
|
|
}
|
2022-11-10 15:53:48 +08:00
|
|
|
|
strLen += len(val)
|
|
|
|
|
}
|
|
|
|
|
if strLen > DsMaxLen {
|
|
|
|
|
p := message.NewPrinter(language.English)
|
|
|
|
|
return fmt.Errorf("字符长度超出限制,最大%s个(不包含逗号), 请删减一些域名", p.Sprintf("%d", DsMaxLen))
|
2022-07-04 15:03:22 +08:00
|
|
|
|
}
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func ValidateDomainName(domain string) bool {
|
|
|
|
|
RegExp := regexp.MustCompile(`^([a-zA-Z0-9][-a-zA-Z0-9]{0,62}\.)+[A-Za-z]{2,18}$`)
|
|
|
|
|
return RegExp.MatchString(domain)
|
|
|
|
|
}
|