Files
anylink/server/handler/link_tunnel.go
7357657 3cb22172b1 兼容 OpenConnect 客户端
因为OpenConnect 客户端对大小写 敏感,w.Header().Set("X-CSTP-Version", "1") 这个操作会把键的首字母转换成大写,其它字母转换成小写,如: X-CSTP-Version  就会转换成 X-Cstp-Version
2021-10-30 15:27:31 +08:00

189 lines
5.5 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package handler
import (
"bytes"
"fmt"
"log"
"net"
"net/http"
"os"
"strings"
"github.com/bjdgyc/anylink/base"
"github.com/bjdgyc/anylink/sessdata"
)
var (
hn string
)
func init() {
// 获取主机名称
hn, _ = os.Hostname()
}
func HttpSetHeader(w http.ResponseWriter, key string, value string) {
w.Header()[key] = []string{value}
}
func HttpAddHeader(w http.ResponseWriter, key string, value string) {
w.Header()[key] = append(w.Header()[key], value)
}
func LinkTunnel(w http.ResponseWriter, r *http.Request) {
// TODO 调试信息输出
// hd, _ := httputil.DumpRequest(r, true)
// fmt.Println("DumpRequest: ", string(hd))
// fmt.Println("LinkTunnel", r.RemoteAddr)
// 判断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")
cstpBaseMtu := r.Header.Get("X-CSTP-Base-MTU")
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
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)
// 返回客户端数据
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-Default-Domain", cSess.LocalIp)
HttpSetHeader(w, "X-CSTP-Base-MTU", cstpBaseMtu)
// 允许本地LAN访问vpn网络必须放在路由的第一个
if cSess.Group.AllowLan {
HttpSetHeader(w, "X-CSTP-Split-Exclude", "0.0.0.0/255.255.255.255")
}
// dns地址
for _, v := range cSess.Group.ClientDns {
HttpAddHeader(w, "X-CSTP-DNS", v.Val)
}
// 允许的路由
for _, v := range cSess.Group.RouteInclude {
if v.Val == "all" {
continue
}
HttpAddHeader(w, "X-CSTP-Split-Include", v.IpMask)
}
// 不允许的路由
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")
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")
HttpSetHeader(w, "X-CSTP-Rekey-Time", "172800")
HttpSetHeader(w, "X-CSTP-Rekey-Method", "new-tunnel")
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-DTLS-Rekey-Time", "5400")
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")
// HttpSetHeader(w, "X-CSTP-Post-Auth-XML", ``)
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)
conn, bufRW, err := hj.Hijack()
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)
case base.LinkModeMacvtap:
err = LinkMacvtap(cSess)
}
if err != nil {
conn.Close()
base.Error(err)
return
}
go LinkCstp(conn, bufRW, cSess)
}