dockerfiles/anylink/server/handler/link_tunnel.go

254 lines
7.4 KiB
Go
Raw Normal View History

2021-06-08 20:45:26 +08:00
package handler
import (
"bytes"
"fmt"
"log"
"net"
"net/http"
2023-04-26 22:17:10 +08:00
"net/http/httputil"
2021-06-08 20:45:26 +08:00
"os"
"strings"
2022-07-04 15:03:22 +08:00
"text/template"
2021-06-08 20:45:26 +08:00
"github.com/bjdgyc/anylink/base"
2022-02-16 14:23:17 +08:00
"github.com/bjdgyc/anylink/dbdata"
2021-06-08 20:45:26 +08:00
"github.com/bjdgyc/anylink/sessdata"
)
var (
hn string
)
func init() {
// 获取主机名称
hn, _ = os.Hostname()
}
2021-12-29 11:43:26 +08:00
func HttpSetHeader(w http.ResponseWriter, key string, value string) {
2022-02-16 14:23:17 +08:00
w.Header()[key] = []string{value}
2021-12-29 11:43:26 +08:00
}
func HttpAddHeader(w http.ResponseWriter, key string, value string) {
2022-02-16 14:23:17 +08:00
w.Header()[key] = append(w.Header()[key], value)
2021-12-29 11:43:26 +08:00
}
2021-06-08 20:45:26 +08:00
func LinkTunnel(w http.ResponseWriter, r *http.Request) {
// TODO 调试信息输出
2023-04-26 22:17:10 +08:00
if base.GetLogLevel() == base.LogLevelTrace {
hd, _ := httputil.DumpRequest(r, true)
base.Trace("LinkTunnel: ", string(hd))
}
2021-06-08 20:45:26 +08:00
// 判断session-token的值
cookie, err := r.Cookie("webvpn")
if err != nil || cookie.Value == "" {
w.WriteHeader(http.StatusBadRequest)
return
}
sess := sessdata.SToken2Sess(cookie.Value)
if sess == nil {
w.WriteHeader(http.StatusBadRequest)
return
}
// 开启link
cSess := sess.NewConn()
if cSess == nil {
log.Println(err)
w.WriteHeader(http.StatusBadRequest)
return
}
// 客户端信息
cstpMtu := r.Header.Get("X-CSTP-MTU")
2021-12-29 11:43:26 +08:00
cstpBaseMtu := r.Header.Get("X-CSTP-Base-MTU")
2021-06-08 20:45:26 +08:00
masterSecret := r.Header.Get("X-DTLS-Master-Secret")
localIp := r.Header.Get("X-Cstp-Local-Address-Ip4")
mobile := r.Header.Get("X-Cstp-License")
cSess.SetMtu(cstpMtu)
cSess.MasterSecret = masterSecret
cSess.RemoteAddr = r.RemoteAddr
2023-04-26 22:17:10 +08:00
cSess.UserAgent = strings.ToLower(r.UserAgent())
2021-06-08 20:45:26 +08:00
cSess.LocalIp = net.ParseIP(localIp)
cstpKeepalive := base.Cfg.CstpKeepalive
cstpDpd := base.Cfg.CstpDpd
cSess.Client = "pc"
if mobile == "mobile" {
// 手机客户端
cstpKeepalive = base.Cfg.MobileKeepalive
cstpDpd = base.Cfg.MobileDpd
cSess.Client = "mobile"
}
cSess.CstpDpd = cstpDpd
dtlsPort := "4433"
if strings.Contains(base.Cfg.ServerDTLSAddr, ":") {
ss := strings.Split(base.Cfg.ServerDTLSAddr, ":")
dtlsPort = ss[1]
}
base.Debug(cSess.IpAddr, cSess.MacHw, sess.Username, mobile)
2023-04-26 22:17:10 +08:00
// 压缩
if cmpName, ok := cSess.SetPickCmp("cstp", r.Header.Get("X-Cstp-Accept-Encoding")); ok {
HttpSetHeader(w, "X-CSTP-Content-Encoding", cmpName)
}
if cmpName, ok := cSess.SetPickCmp("dtls", r.Header.Get("X-Dtls-Accept-Encoding")); ok {
HttpSetHeader(w, "X-DTLS-Content-Encoding", cmpName)
}
2021-06-08 20:45:26 +08:00
// 返回客户端数据
2021-12-29 11:43:26 +08:00
HttpSetHeader(w, "Server", fmt.Sprintf("%s %s", base.APP_NAME, base.APP_VER))
HttpSetHeader(w, "X-CSTP-Version", "1")
HttpSetHeader(w, "X-CSTP-Server-Name", fmt.Sprintf("%s %s", base.APP_NAME, base.APP_VER))
HttpSetHeader(w, "X-CSTP-Protocol", "Copyright (c) 2004 Cisco Systems, Inc.")
HttpSetHeader(w, "X-CSTP-Address", cSess.IpAddr.String()) // 分配的ip地址
HttpSetHeader(w, "X-CSTP-Netmask", sessdata.IpPool.Ipv4Mask.String()) // 子网掩码
HttpSetHeader(w, "X-CSTP-Hostname", hn) // 机器名称
HttpSetHeader(w, "X-CSTP-Base-MTU", cstpBaseMtu)
2022-11-10 15:53:48 +08:00
// 要发布的默认域
if base.Cfg.DefaultDomain != "" {
HttpSetHeader(w, "X-CSTP-Default-Domain", base.Cfg.DefaultDomain)
}
2021-06-08 20:45:26 +08:00
2022-07-04 15:03:22 +08:00
// 设置用户策略
2022-11-10 15:53:48 +08:00
SetUserPolicy(cSess.Username, cSess.Group)
2022-07-04 15:03:22 +08:00
2021-06-08 20:45:26 +08:00
// 允许本地LAN访问vpn网络必须放在路由的第一个
if cSess.Group.AllowLan {
2021-12-29 11:43:26 +08:00
HttpSetHeader(w, "X-CSTP-Split-Exclude", "0.0.0.0/255.255.255.255")
2021-06-08 20:45:26 +08:00
}
// dns地址
for _, v := range cSess.Group.ClientDns {
2021-12-29 11:43:26 +08:00
HttpAddHeader(w, "X-CSTP-DNS", v.Val)
2021-06-08 20:45:26 +08:00
}
// 允许的路由
for _, v := range cSess.Group.RouteInclude {
2022-02-16 14:23:17 +08:00
if v.Val == dbdata.All {
2021-08-26 23:09:52 +08:00
continue
}
2021-12-29 11:43:26 +08:00
HttpAddHeader(w, "X-CSTP-Split-Include", v.IpMask)
2021-06-08 20:45:26 +08:00
}
// 不允许的路由
for _, v := range cSess.Group.RouteExclude {
2021-12-29 11:43:26 +08:00
HttpAddHeader(w, "X-CSTP-Split-Exclude", v.IpMask)
2021-06-08 20:45:26 +08:00
}
2023-04-26 22:17:10 +08:00
HttpSetHeader(w, "X-CSTP-Lease-Duration", "1209600") // ip地址租期
2021-12-29 11:43:26 +08:00
HttpSetHeader(w, "X-CSTP-Session-Timeout", "none")
HttpSetHeader(w, "X-CSTP-Session-Timeout-Alert-Interval", "60")
HttpSetHeader(w, "X-CSTP-Session-Timeout-Remaining", "none")
HttpSetHeader(w, "X-CSTP-Idle-Timeout", "18000")
HttpSetHeader(w, "X-CSTP-Disconnected-Timeout", "18000")
HttpSetHeader(w, "X-CSTP-Keep", "true")
HttpSetHeader(w, "X-CSTP-Tunnel-All-DNS", "false")
2023-04-26 22:17:10 +08:00
HttpSetHeader(w, "X-CSTP-Rekey-Time", "43200") // 172800
2021-12-29 11:43:26 +08:00
HttpSetHeader(w, "X-CSTP-Rekey-Method", "new-tunnel")
2023-04-26 22:17:10 +08:00
HttpSetHeader(w, "X-DTLS-Rekey-Time", "43200")
HttpSetHeader(w, "X-DTLS-Rekey-Method", "new-tunnel")
2021-12-29 11:43:26 +08:00
HttpSetHeader(w, "X-CSTP-DPD", fmt.Sprintf("%d", cstpDpd))
HttpSetHeader(w, "X-CSTP-Keepalive", fmt.Sprintf("%d", cstpKeepalive))
// HttpSetHeader(w, "X-CSTP-Banner", banner.Banner)
HttpSetHeader(w, "X-CSTP-MSIE-Proxy-Lockdown", "true")
HttpSetHeader(w, "X-CSTP-Smartcard-Removal-Disconnect", "true")
HttpSetHeader(w, "X-CSTP-MTU", fmt.Sprintf("%d", cSess.Mtu)) // 1399
HttpSetHeader(w, "X-DTLS-MTU", fmt.Sprintf("%d", cSess.Mtu))
HttpSetHeader(w, "X-DTLS-Session-ID", sess.DtlsSid)
HttpSetHeader(w, "X-DTLS-Port", dtlsPort)
HttpSetHeader(w, "X-DTLS-DPD", fmt.Sprintf("%d", cstpDpd))
HttpSetHeader(w, "X-DTLS-Keepalive", fmt.Sprintf("%d", cstpKeepalive))
HttpSetHeader(w, "X-DTLS12-CipherSuite", "ECDHE-ECDSA-AES128-GCM-SHA256")
HttpSetHeader(w, "X-CSTP-License", "accept")
HttpSetHeader(w, "X-CSTP-Routing-Filtering-Ignore", "false")
HttpSetHeader(w, "X-CSTP-Quarantine", "false")
HttpSetHeader(w, "X-CSTP-Disable-Always-On-VPN", "false")
HttpSetHeader(w, "X-CSTP-Client-Bypass-Protocol", "false")
HttpSetHeader(w, "X-CSTP-TCP-Keepalive", "false")
2022-07-04 15:03:22 +08:00
// 设置域名拆分隧道(移动端不支持)
if mobile != "mobile" {
SetPostAuthXml(cSess.Group, w)
}
2021-06-08 20:45:26 +08:00
w.WriteHeader(http.StatusOK)
hClone := w.Header().Clone()
headers := make([]byte, 0)
buf := bytes.NewBuffer(headers)
_ = hClone.Write(buf)
base.Debug(buf.String())
hj := w.(http.Hijacker)
2021-08-26 23:09:52 +08:00
conn, bufRW, err := hj.Hijack()
2021-06-08 20:45:26 +08:00
if err != nil {
base.Error(err)
w.WriteHeader(http.StatusInternalServerError)
return
}
// 开始数据处理
switch base.Cfg.LinkMode {
case base.LinkModeTUN:
err = LinkTun(cSess)
case base.LinkModeTAP:
err = LinkTap(cSess)
2021-08-26 23:09:52 +08:00
case base.LinkModeMacvtap:
err = LinkMacvtap(cSess)
2021-06-08 20:45:26 +08:00
}
if err != nil {
2021-08-26 23:09:52 +08:00
conn.Close()
base.Error(err)
2021-06-08 20:45:26 +08:00
return
}
2023-04-26 22:17:10 +08:00
dbdata.UserActLogIns.Add(dbdata.UserActLog{
Username: sess.Username,
GroupName: sess.Group,
IpAddr: cSess.IpAddr.String(),
RemoteAddr: cSess.RemoteAddr,
DeviceType: sess.DeviceType,
PlatformVersion: sess.PlatformVersion,
Status: dbdata.UserConnected,
}, cSess.UserAgent)
2021-06-08 20:45:26 +08:00
2021-08-26 23:09:52 +08:00
go LinkCstp(conn, bufRW, cSess)
2021-06-08 20:45:26 +08:00
}
2022-07-04 15:03:22 +08:00
// 设置域名拆分隧道
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
err = tmpl.Execute(&result, g)
if err != nil {
return err
}
HttpSetHeader(w, "X-CSTP-Post-Auth-XML", result.String())
return nil
}
// 设置用户策略, 覆盖Group的属性值
func SetUserPolicy(username string, g *dbdata.Group) {
userPolicy := dbdata.GetPolicy(username)
if userPolicy.Id != 0 && userPolicy.Status == 1 {
base.Debug(username + " use UserPolicy")
g.AllowLan = userPolicy.AllowLan
g.ClientDns = userPolicy.ClientDns
g.RouteInclude = userPolicy.RouteInclude
g.RouteExclude = userPolicy.RouteExclude
g.DsExcludeDomains = userPolicy.DsExcludeDomains
g.DsIncludeDomains = userPolicy.DsIncludeDomains
}
}