增加管理后台

This commit is contained in:
bjd
2020-12-16 16:36:56 +08:00
parent 31b1f12dbe
commit a9584000c6
68 changed files with 2408 additions and 1281 deletions

View File

@@ -8,7 +8,8 @@ import (
"strings"
"text/template"
"github.com/bjdgyc/anylink/common"
"github.com/bjdgyc/anylink/base"
"github.com/bjdgyc/anylink/dbdata"
"github.com/bjdgyc/anylink/sessdata"
)
@@ -40,7 +41,7 @@ func LinkAuth(w http.ResponseWriter, r *http.Request) {
if cr.Type == "init" {
w.WriteHeader(http.StatusOK)
data := RequestData{Group: cr.GroupSelect, Groups: common.ServerCfg.UserGroups}
data := RequestData{Group: cr.GroupSelect, Groups: dbdata.GetGroupNames()}
tplRequest(tpl_request, w, data)
return
}
@@ -52,22 +53,33 @@ func LinkAuth(w http.ResponseWriter, r *http.Request) {
}
// TODO 用户密码校验
if !CheckUser(cr.Auth.Username, cr.Auth.Password, cr.GroupSelect) {
err = dbdata.CheckUser(cr.Auth.Username, cr.Auth.Password, cr.GroupSelect)
if err != nil {
base.Info(err)
w.WriteHeader(http.StatusOK)
data := RequestData{Group: cr.GroupSelect, Groups: common.ServerCfg.UserGroups, Error: true}
data := RequestData{Group: cr.GroupSelect, Groups: dbdata.GetGroupNames(), Error: "用户名或密码错误"}
tplRequest(tpl_request, w, data)
return
}
// if !ok {
// w.WriteHeader(http.StatusOK)
// data := RequestData{Group: cr.GroupSelect, Groups: base.Cfg.UserGroups, Error: "请先激活用户"}
// tplRequest(tpl_request, w, data)
// return
// }
// 创建新的session信息
sess := sessdata.NewSession()
sess.UserName = cr.Auth.Username
sess := sessdata.NewSession("")
sess.Username = cr.Auth.Username
sess.Group = cr.GroupSelect
sess.MacAddr = strings.ToLower(cr.MacAddressList.MacAddress)
sess.UniqueIdGlobal = cr.DeviceId.UniqueIdGlobal
cd := RequestData{SessionId: sess.Sid, SessionToken: sess.Sid + "@" + sess.Token,
Banner: common.ServerCfg.Banner}
other := &dbdata.SettingOther{}
dbdata.SettingGet(other)
rd := RequestData{SessionId: sess.Sid, SessionToken: sess.Sid + "@" + sess.Token,
Banner: other.Banner}
w.WriteHeader(http.StatusOK)
tplRequest(tpl_complete, w, cd)
tplRequest(tpl_complete, w, rd)
}
const (
@@ -94,7 +106,8 @@ func tplRequest(typ int, w io.Writer, data RequestData) {
type RequestData struct {
Groups []string
Group string
Error bool
Error string
// complete
SessionId string
SessionToken string
@@ -116,7 +129,7 @@ var auth_request = `<?xml version="1.0" encoding="UTF-8"?>
<message>请输入你的用户名和密码</message>
<banner></banner>
{{if .Error}}
<error id="88" param1="用户名或密码错误" param2="">登陆失败: %s</error>
<error id="88" param1="{{.Error}}" param2="">登陆失败: %s</error>
{{end}}
<form>
<input type="text" name="username" label="Username:"></input>

View File

@@ -2,72 +2,67 @@ package handler
import (
"encoding/binary"
"log"
"net"
"time"
"github.com/bjdgyc/anylink/common"
"github.com/bjdgyc/anylink/base"
"github.com/bjdgyc/anylink/sessdata"
)
func LinkCstp(conn net.Conn, sess *sessdata.ConnSession) {
log.Println("HandlerCstp")
sessdata.Sess = sess
func LinkCstp(conn net.Conn, cSess *sessdata.ConnSession) {
defer func() {
log.Println("LinkCstp return")
// log.Println("LinkCstp return")
conn.Close()
sess.Close()
cSess.Close()
}()
var (
err error
n int
dataLen uint16
dead = time.Duration(common.ServerCfg.CstpDpd+2) * time.Second
dead = time.Duration(cSess.CstpDpd*2) * time.Second
)
go cstpWrite(conn, sess)
go cstpWrite(conn, cSess)
for {
// 设置超时限制
err = conn.SetReadDeadline(time.Now().Add(dead))
if err != nil {
log.Println("SetDeadline: ", err)
base.Error("SetDeadline: ", err)
return
}
hdata := make([]byte, BufferSize)
n, err = conn.Read(hdata)
if err != nil {
log.Println("read hdata: ", err)
base.Error("read hdata: ", err)
return
}
// 限流设置
err = sess.RateLimit(n, true)
err = cSess.RateLimit(n, true)
if err != nil {
log.Println(err)
base.Error(err)
}
switch hdata[6] {
case 0x07: // KEEPALIVE
// do nothing
// log.Println("recv keepalive")
base.Debug("recv keepalive", cSess.IpAddr)
case 0x05: // DISCONNECT
// log.Println("DISCONNECT")
base.Debug("DISCONNECT", cSess.IpAddr)
return
case 0x03: // DPD-REQ
// log.Println("recv DPD-REQ")
if payloadOut(sess, sessdata.LTypeIPData, 0x04, nil) {
base.Debug("recv DPD-REQ", cSess.IpAddr)
if payloadOut(cSess, sessdata.LTypeIPData, 0x04, nil) {
return
}
case 0x04:
// log.Println("recv DPD-RESP")
case 0x00: // DATA
dataLen = binary.BigEndian.Uint16(hdata[4:6]) // 4,5
data := hdata[8 : 8+dataLen]
if payloadIn(sess, sessdata.LTypeIPData, 0x00, data) {
if payloadIn(cSess, sessdata.LTypeIPData, 0x00, hdata[8:8+dataLen]) {
return
}
@@ -75,11 +70,11 @@ func LinkCstp(conn net.Conn, sess *sessdata.ConnSession) {
}
}
func cstpWrite(conn net.Conn, sess *sessdata.ConnSession) {
func cstpWrite(conn net.Conn, cSess *sessdata.ConnSession) {
defer func() {
log.Println("cstpWrite return")
// log.Println("cstpWrite return")
conn.Close()
sess.Close()
cSess.Close()
}()
var (
@@ -91,8 +86,8 @@ func cstpWrite(conn net.Conn, sess *sessdata.ConnSession) {
for {
select {
case payload = <-sess.PayloadOut:
case <-sess.CloseChan:
case payload = <-cSess.PayloadOut:
case <-cSess.CloseChan:
return
}
@@ -107,14 +102,14 @@ func cstpWrite(conn net.Conn, sess *sessdata.ConnSession) {
}
n, err = conn.Write(header)
if err != nil {
log.Println("write err", err)
base.Error("write err", err)
return
}
// 限流设置
err = sess.RateLimit(n, false)
err = cSess.RateLimit(n, false)
if err != nil {
log.Println(err)
base.Error(err)
}
}
}

View File

@@ -3,14 +3,15 @@ package handler
import (
"fmt"
"net/http"
"net/http/httputil"
"strings"
"github.com/bjdgyc/anylink/admin"
)
func LinkHome(w http.ResponseWriter, r *http.Request) {
hu, _ := httputil.DumpRequest(r, true)
fmt.Println("DumpHome: ", string(hu))
fmt.Println(r.RemoteAddr)
// fmt.Println(r.RemoteAddr)
// hu, _ := httputil.DumpRequest(r, true)
// fmt.Println("DumpHome: ", string(hu))
connection := strings.ToLower(r.Header.Get("Connection"))
userAgent := strings.ToLower(r.UserAgent())
@@ -23,3 +24,16 @@ func LinkHome(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
fmt.Fprintln(w, "hello world")
}
func LinkOtpQr(w http.ResponseWriter, r *http.Request) {
r.ParseForm()
idS := r.FormValue("id")
jwtToken := r.FormValue("jwt")
data, err := admin.GetJwtData(jwtToken)
if err != nil || idS != fmt.Sprint(data["id"]) {
w.WriteHeader(http.StatusForbidden)
return
}
admin.UserOtpQr(w, r)
}

View File

@@ -2,10 +2,10 @@ package handler
import (
"fmt"
"log"
"net"
"github.com/bjdgyc/anylink/arpdis"
"github.com/bjdgyc/anylink/base"
"github.com/bjdgyc/anylink/pkg/arpdis"
"github.com/bjdgyc/anylink/sessdata"
"github.com/google/gopacket"
"github.com/google/gopacket/layers"
@@ -16,13 +16,18 @@ import (
const bridgeName = "anylink0"
var (
bridgeIp net.IP
bridgeHw net.HardwareAddr
)
func checkTap() {
brFace, err := net.InterfaceByName(bridgeName)
if err != nil {
log.Fatal("testTap err: ", err)
base.Fatal("testTap err: ", err)
}
bridgeHw := brFace.HardwareAddr
var bridgeIp net.IP
bridgeHw = brFace.HardwareAddr
addrs, err := brFace.Addrs()
for _, addr := range addrs {
ip, _, err := net.ParseCIDR(addr.String())
@@ -32,112 +37,104 @@ func checkTap() {
bridgeIp = ip
}
if bridgeIp == nil && bridgeHw == nil {
log.Fatalln("bridgeIp is err")
base.Fatal("bridgeIp is err")
}
if !sessdata.IpPool.Ipv4IPNet.Contains(bridgeIp) {
log.Fatalln("bridgeIp or Ip network err")
base.Fatal("bridgeIp or Ip network err")
}
// 设置本机ip arp为静态
addr := &arpdis.Addr{IP: bridgeIp.To4(), HardwareAddr: bridgeHw, Type: arpdis.TypeStatic}
arpdis.Add(addr)
}
// 创建tap网卡
func LinkTap(sess *sessdata.ConnSession) {
defer func() {
log.Println("LinkTap return")
sess.Close()
}()
func LinkTap(cSess *sessdata.ConnSession) error {
cfg := water.Config{
DeviceType: water.TAP,
}
ifce, err := water.New(cfg)
if err != nil {
log.Println(err)
return
base.Error(err)
return err
}
sess.TunName = ifce.Name()
defer ifce.Close()
cSess.TunName = ifce.Name()
// arp on
cmdstr1 := fmt.Sprintf("ip link set dev %s up mtu %d multicast on", ifce.Name(), sess.Mtu)
cmdstr1 := fmt.Sprintf("ip link set dev %s up mtu %d multicast on", ifce.Name(), cSess.Mtu)
cmdstr2 := fmt.Sprintf("sysctl -w net.ipv6.conf.%s.disable_ipv6=1", ifce.Name())
cmdstr3 := fmt.Sprintf("ip link set dev %s master %s", ifce.Name(), bridgeName)
cmdStrs := []string{cmdstr1, cmdstr2, cmdstr3}
err = execCmd(cmdStrs)
if err != nil {
return
base.Error(err)
ifce.Close()
return err
}
// TODO 测试
// sess.MacHw, _ = net.ParseMAC("3c:8c:40:a0:6a:3d")
go tapRead(ifce, cSess)
go tapWrite(ifce, cSess)
return nil
}
go loopArp(sess)
go tapRead(ifce, sess)
func tapWrite(ifce *water.Interface, cSess *sessdata.ConnSession) {
defer func() {
// log.Println("LinkTap return")
cSess.Close()
ifce.Close()
}()
var (
err error
payload *sessdata.Payload
)
for {
select {
case payload = <-sess.PayloadIn:
case <-sess.CloseChan:
case payload = <-cSess.PayloadIn:
case <-cSess.CloseChan:
return
}
var frame ethernet.Frame
switch payload.LType {
default:
log.Println(payload)
// log.Println(payload)
case sessdata.LTypeEthernet:
frame = payload.Data
case sessdata.LTypeIPData: // 需要转换成 Ethernet 数据
data := payload.Data
ip_src := waterutil.IPv4Source(data)
if waterutil.IsIPv6(data) || !ip_src.Equal(sess.Ip) {
if waterutil.IsIPv6(data) || !ip_src.Equal(cSess.IpAddr) {
// 过滤掉IPv6的数据
// 非分配给客户端ip直接丢弃
continue
}
// packet := gopacket.NewPacket(data, layers.LayerTypeIPv4, gopacket.Default)
// fmt.Println("get:", packet)
ip_dst := waterutil.IPv4Destination(data)
// fmt.Println("get:", ip_src, ip_dst)
var dstAddr *arpdis.Addr
var dstHw net.HardwareAddr
if !sessdata.IpPool.Ipv4IPNet.Contains(ip_dst) || ip_dst.Equal(sessdata.IpPool.Ipv4Gateway) {
// 不是同一网段使用网关mac地址
ip_dst = sessdata.IpPool.Ipv4Gateway
dstAddr = arpdis.Lookup(ip_dst, false)
if dstAddr == nil {
log.Println("Ipv4Gateway mac err", ip_dst)
return
}
// fmt.Println("Gateway", ip_dst, dstAddr.HardwareAddr)
dstAddr := arpdis.Lookup(sessdata.IpPool.Ipv4Gateway, false)
dstHw = dstAddr.HardwareAddr
} else {
// 同一网段内的其他主机
dstAddr = arpdis.Lookup(ip_dst, true)
// fmt.Println("other", ip_src, ip_dst, dstAddr)
if dstAddr == nil || dstAddr.Type == arpdis.TypeUnreachable {
// 异步检测发送数据包
select {
case sess.PayloadArp <- payload:
case <-sess.CloseChan:
return
default:
// PayloadArp 容量已经满了
log.Println("PayloadArp is full", sess.Ip, ip_dst)
}
continue
dstAddr := arpdis.Lookup(ip_dst, true)
// fmt.Println("dstAddr", dstAddr)
if dstAddr != nil {
dstHw = dstAddr.HardwareAddr
} else {
dstHw = bridgeHw
}
}
frame.Prepare(dstAddr.HardwareAddr, sess.MacHw, ethernet.NotTagged, ethernet.IPv4, len(data))
}
// fmt.Println("Gateway", ip_dst, dstAddr.HardwareAddr)
frame.Prepare(dstHw, cSess.MacHw, ethernet.NotTagged, ethernet.IPv4, len(data))
copy(frame[12+2:], data)
}
@@ -145,52 +142,15 @@ func LinkTap(sess *sessdata.ConnSession) {
// fmt.Println("write:", packet)
_, err = ifce.Write(frame)
if err != nil {
log.Println("tap Write err", err)
base.Error("tap Write err", err)
return
}
}
}
// 异步处理获取ip对应的mac地址的数据
func loopArp(sess *sessdata.ConnSession) {
func tapRead(ifce *water.Interface, cSess *sessdata.ConnSession) {
defer func() {
log.Println("loopArp return")
}()
var (
payload *sessdata.Payload
dstAddr *arpdis.Addr
ip_dst net.IP
)
for {
select {
case payload = <-sess.PayloadArp:
case <-sess.CloseChan:
return
}
ip_dst = waterutil.IPv4Destination(payload.Data)
dstAddr = arpdis.Lookup(ip_dst, false)
// 不可达数据包
if dstAddr == nil || dstAddr.Type == arpdis.TypeUnreachable {
// 直接丢弃数据
// fmt.Println("Lookup", ip_dst)
continue
}
// 正常获取mac地址
if payloadInData(sess, payload) {
return
}
}
}
func tapRead(ifce *water.Interface, sess *sessdata.ConnSession) {
defer func() {
log.Println("tapRead return")
// log.Println("tapRead return")
ifce.Close()
}()
@@ -199,14 +159,13 @@ func tapRead(ifce *water.Interface, sess *sessdata.ConnSession) {
n int
buf []byte
)
fmt.Println(sess.MacHw)
for {
var frame ethernet.Frame
frame.Resize(BufferSize)
n, err = ifce.Read(frame)
if err != nil {
log.Println("tap Read err", n, err)
base.Error("tap Read err", n, err)
return
}
frame = frame[:n]
@@ -223,47 +182,54 @@ func tapRead(ifce *water.Interface, sess *sessdata.ConnSession) {
data := frame.Payload()
ip_dst := waterutil.IPv4Destination(data)
if !ip_dst.Equal(sess.Ip) {
if !ip_dst.Equal(cSess.IpAddr) {
// 过滤非本机地址
// log.Println(ip_dst, sess.Ip)
continue
}
if payloadOut(sess, sessdata.LTypeIPData, 0x00, data) {
// packet := gopacket.NewPacket(data, layers.LayerTypeIPv4, gopacket.Default)
// fmt.Println("put:", packet)
if payloadOut(cSess, sessdata.LTypeIPData, 0x00, data) {
return
}
case ethernet.ARP:
// 暂时仅实现了ARP协议
packet := gopacket.NewPacket(frame, layers.LayerTypeEthernet, gopacket.NoCopy)
packet := gopacket.NewPacket(frame, layers.LayerTypeEthernet, gopacket.Default)
layer := packet.Layer(layers.LayerTypeARP)
arpReq := layer.(*layers.ARP)
// fmt.Println("arp", net.IP(arpReq.SourceProtAddress), sess.Ip)
if !sess.Ip.Equal(arpReq.DstProtAddress) {
if !cSess.IpAddr.Equal(arpReq.DstProtAddress) {
// 过滤非本机地址
continue
}
// fmt.Println("arp", arpReq.SourceProtAddress, sess.Ip)
// fmt.Println("arp", net.IP(arpReq.SourceProtAddress), sess.Ip)
// fmt.Println(packet)
// 返回ARP数据
src := &arpdis.Addr{IP: sess.Ip, HardwareAddr: sess.MacHw}
src := &arpdis.Addr{IP: cSess.IpAddr, HardwareAddr: cSess.MacHw}
dst := &arpdis.Addr{IP: arpReq.SourceProtAddress, HardwareAddr: frame.Source()}
buf, err = arpdis.NewARPReply(src, dst)
if err != nil {
log.Println(err)
base.Error(err)
return
}
// 从接受的arp信息添加arp地址
addr := &arpdis.Addr{}
addr := &arpdis.Addr{
IP: make([]byte, len(arpReq.SourceProtAddress)),
HardwareAddr: make([]byte, len(frame.Source())),
}
// addr.IP = arpReq.SourceProtAddress
// addr.HardwareAddr = frame.Source()
copy(addr.IP, arpReq.SourceProtAddress)
copy(addr.HardwareAddr, frame.Source())
arpdis.Add(addr)
if payloadIn(sess, sessdata.LTypeEthernet, 0x00, buf) {
if payloadIn(cSess, sessdata.LTypeEthernet, 0x00, buf) {
return
}

View File

@@ -2,9 +2,8 @@ package handler
import (
"fmt"
"log"
"github.com/bjdgyc/anylink/common"
"github.com/bjdgyc/anylink/base"
"github.com/bjdgyc/anylink/sessdata"
"github.com/songgao/water"
)
@@ -17,7 +16,7 @@ func checkTun() {
ifce, err := water.New(cfg)
if err != nil {
log.Fatal("open tun err: ", err)
base.Fatal("open tun err: ", err)
}
defer ifce.Close()
@@ -25,63 +24,72 @@ func checkTun() {
cmdstr := fmt.Sprintf("ip link set dev %s up mtu %s multicast off", ifce.Name(), "1399")
err = execCmd([]string{cmdstr})
if err != nil {
log.Fatal("testTun err: ", err)
base.Fatal("testTun err: ", err)
}
}
// 创建tun网卡
func LinkTun(sess *sessdata.ConnSession) {
defer func() {
log.Println("LinkTun return")
sess.Close()
}()
func LinkTun(cSess *sessdata.ConnSession) error {
cfg := water.Config{
DeviceType: water.TUN,
}
ifce, err := water.New(cfg)
if err != nil {
log.Println(err)
return
base.Error(err)
return err
}
// log.Printf("Interface Name: %s\n", ifce.Name())
sess.TunName = ifce.Name()
defer ifce.Close()
cSess.SetTunName(ifce.Name())
// cSess.TunName = ifce.Name()
cmdstr1 := fmt.Sprintf("ip link set dev %s up mtu %d multicast off", ifce.Name(), sess.Mtu)
cmdstr1 := fmt.Sprintf("ip link set dev %s up mtu %d multicast off", ifce.Name(), cSess.Mtu)
cmdstr2 := fmt.Sprintf("ip addr add dev %s local %s peer %s/32",
ifce.Name(), common.ServerCfg.Ipv4Gateway, sess.Ip)
ifce.Name(), base.Cfg.Ipv4Gateway, cSess.IpAddr)
cmdstr3 := fmt.Sprintf("sysctl -w net.ipv6.conf.%s.disable_ipv6=1", ifce.Name())
cmdStrs := []string{cmdstr1, cmdstr2, cmdstr3}
err = execCmd(cmdStrs)
if err != nil {
return
base.Error(err)
ifce.Close()
return err
}
go tunRead(ifce, sess)
go tunRead(ifce, cSess)
go tunWrite(ifce, cSess)
return nil
}
var payload *sessdata.Payload
func tunWrite(ifce *water.Interface, cSess *sessdata.ConnSession) {
defer func() {
// log.Println("LinkTun return")
cSess.Close()
ifce.Close()
}()
var (
err error
payload *sessdata.Payload
)
for {
select {
case payload = <-sess.PayloadIn:
case <-sess.CloseChan:
case payload = <-cSess.PayloadIn:
case <-cSess.CloseChan:
return
}
_, err = ifce.Write(payload.Data)
if err != nil {
log.Println("tun Write err", err)
base.Error("tun Write err", err)
return
}
}
}
func tunRead(ifce *water.Interface, sess *sessdata.ConnSession) {
func tunRead(ifce *water.Interface, cSess *sessdata.ConnSession) {
defer func() {
log.Println("tunRead return")
// log.Println("tunRead return")
ifce.Close()
}()
var (
@@ -93,7 +101,7 @@ func tunRead(ifce *water.Interface, sess *sessdata.ConnSession) {
data := make([]byte, BufferSize)
n, err = ifce.Read(data)
if err != nil {
log.Println("tun Read err", n, err)
base.Error("tun Read err", n, err)
return
}
@@ -106,7 +114,7 @@ func tunRead(ifce *water.Interface, sess *sessdata.ConnSession) {
// packet := gopacket.NewPacket(data, layers.LayerTypeIPv4, gopacket.Default)
// fmt.Println("read:", packet)
if payloadOut(sess, sessdata.LTypeIPData, 0x00, data) {
if payloadOut(cSess, sessdata.LTypeIPData, 0x00, data) {
return
}

View File

@@ -7,7 +7,8 @@ import (
"net/http"
"os"
"github.com/bjdgyc/anylink/common"
"github.com/bjdgyc/anylink/base"
"github.com/bjdgyc/anylink/dbdata"
"github.com/bjdgyc/anylink/sessdata"
)
@@ -44,49 +45,62 @@ func LinkTunnel(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusBadRequest)
return
}
fmt.Println(cSess.Ip, cSess.MacHw)
// 客户端信息
cstp_mtu := r.Header.Get("X-CSTP-MTU")
master_Secret := r.Header.Get("X-DTLS-Master-Secret")
local_ip := r.Header.Get("X-Cstp-Local-Address-Ip4")
cstpMtu := r.Header.Get("X-CSTP-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(cstp_mtu)
cSess.MasterSecret = master_Secret
platform := r.Header.Get("X-AnyConnect-Identifier-Platform")
cSess.SetMtu(cstpMtu)
cSess.MasterSecret = masterSecret
cSess.RemoteAddr = r.RemoteAddr
cSess.LocalIp = net.ParseIP(local_ip)
cstpDpd := common.ServerCfg.CstpDpd
cSess.LocalIp = net.ParseIP(localIp)
cstpKeepalive := base.Cfg.CstpKeepalive
cstpDpd := base.Cfg.CstpDpd
cSess.Client = "pc"
if mobile == "mobile" {
// 手机客户端
cstpDpd = common.ServerCfg.MobileDpd
cstpKeepalive = base.Cfg.MobileKeepalive
cstpDpd = base.Cfg.MobileDpd
cSess.Client = "mobile"
}
cSess.CstpDpd = cstpDpd
// iPhone手机需要最少一个dns
if platform == "apple-ios" && len(cSess.Group.ClientDns) == 0 {
dnsVal := dbdata.ValData{Val: "114.114.114.114"}
cSess.Group.ClientDns = append(cSess.Group.ClientDns, dnsVal)
}
base.Debug(cSess.IpAddr, cSess.MacHw, sess.Username, mobile)
// 返回客户端数据
w.Header().Set("Server", fmt.Sprintf("%s %s", common.APP_NAME, common.APP_VER))
w.Header().Set("Server", fmt.Sprintf("%s %s", base.APP_NAME, base.APP_VER))
w.Header().Set("X-CSTP-Version", "1")
w.Header().Set("X-CSTP-Protocol", "Copyright (c) 2004 Cisco Systems, Inc.")
w.Header().Set("X-CSTP-Address", cSess.Ip.String()) // 分配的ip地址
w.Header().Set("X-CSTP-Netmask", common.ServerCfg.Ipv4Netmask) // 子网掩码
w.Header().Set("X-CSTP-Hostname", hn) // 机器名称
for _, v := range common.ServerCfg.ClientDns {
w.Header().Add("X-CSTP-DNS", v) // dns地址
}
w.Header().Set("X-CSTP-Address", cSess.IpAddr.String()) // 分配的ip地址
w.Header().Set("X-CSTP-Netmask", base.Cfg.Ipv4Netmask) // 子网掩码
w.Header().Set("X-CSTP-Hostname", hn) // 机器名称
// 允许本地LAN访问vpn网络必须放在路由的第一个
if common.ServerCfg.AllowLan {
if cSess.Group.AllowLan {
w.Header().Set("X-CSTP-Split-Exclude", "0.0.0.0/255.255.255.255")
}
// dns地址
for _, v := range cSess.Group.ClientDns {
w.Header().Add("X-CSTP-DNS", v.Val)
}
// 允许的路由
for _, v := range common.ServerCfg.Include {
w.Header().Add("X-CSTP-Split-Include", v)
for _, v := range cSess.Group.RouteInclude {
w.Header().Add("X-CSTP-Split-Include", v.Val)
}
// 不允许的路由
for _, v := range common.ServerCfg.Exclude {
w.Header().Add("X-CSTP-Split-Exclude", v)
for _, v := range cSess.Group.RouteExclude {
w.Header().Add("X-CSTP-Split-Exclude", v.Val)
}
// w.Header().Add("X-CSTP-Split-Include", "192.168.0.0/255.255.0.0")
// w.Header().Add("X-CSTP-Split-Exclude", "10.1.5.2/255.255.255.255")
w.Header().Set("X-CSTP-Lease-Duration", fmt.Sprintf("%d", sessdata.IpLease)) // ip地址租期
w.Header().Set("X-CSTP-Lease-Duration", fmt.Sprintf("%d", base.Cfg.IpLease)) // ip地址租期
w.Header().Set("X-CSTP-Session-Timeout", "none")
w.Header().Set("X-CSTP-Session-Timeout-Alert-Interval", "60")
w.Header().Set("X-CSTP-Session-Timeout-Remaining", "none")
@@ -98,9 +112,9 @@ func LinkTunnel(w http.ResponseWriter, r *http.Request) {
w.Header().Set("X-CSTP-Rekey-Time", "172800")
w.Header().Set("X-CSTP-Rekey-Method", "new-tunnel")
w.Header().Set("X-CSTP-DPD", fmt.Sprintf("%d", cstpDpd)) // 30 Dead peer detection in seconds
w.Header().Set("X-CSTP-Keepalive", fmt.Sprintf("%d", common.ServerCfg.CstpKeepalive)) // 20
w.Header().Set("X-CSTP-Banner", common.ServerCfg.Banner) // urlencode
w.Header().Set("X-CSTP-DPD", fmt.Sprintf("%d", cstpDpd))
w.Header().Set("X-CSTP-Keepalive", fmt.Sprintf("%d", cstpKeepalive))
// w.Header().Set("X-CSTP-Banner", banner.Banner)
w.Header().Set("X-CSTP-MSIE-Proxy-Lockdown", "true")
w.Header().Set("X-CSTP-Smartcard-Removal-Disconnect", "true")
@@ -109,7 +123,7 @@ func LinkTunnel(w http.ResponseWriter, r *http.Request) {
w.Header().Set("X-DTLS-Session-ID", sess.DtlsSid)
w.Header().Set("X-DTLS-Port", "4433")
w.Header().Set("X-DTLS-Keepalive", fmt.Sprintf("%d", common.ServerCfg.CstpKeepalive))
w.Header().Set("X-DTLS-Keepalive", fmt.Sprintf("%d", base.Cfg.CstpKeepalive))
w.Header().Set("X-DTLS-Rekey-Time", "5400")
w.Header().Set("X-DTLS12-CipherSuite", "ECDHE-ECDSA-AES128-GCM-SHA256")
// w.Header().Set("X-DTLS12-CipherSuite", "ECDHE-RSA-AES128-GCM-SHA256")
@@ -123,6 +137,9 @@ func LinkTunnel(w http.ResponseWriter, r *http.Request) {
// w.Header().Set("X-CSTP-Post-Auth-XML", ``)
w.WriteHeader(http.StatusOK)
// h := w.Header().Clone()
// h.Write(os.Stdout)
hj := w.(http.Hijacker)
conn, _, err := hj.Hijack()
if err != nil {
@@ -131,11 +148,15 @@ func LinkTunnel(w http.ResponseWriter, r *http.Request) {
}
// 开始数据处理
switch common.ServerCfg.LinkMode {
case common.LinkModeTUN:
go LinkTun(cSess)
case common.LinkModeTAP:
go LinkTap(cSess)
switch base.Cfg.LinkMode {
case base.LinkModeTUN:
err = LinkTun(cSess)
case base.LinkModeTAP:
err = LinkTap(cSess)
}
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
return
}
go LinkCstp(conn, cSess)

View File

@@ -2,44 +2,44 @@ package handler
import "github.com/bjdgyc/anylink/sessdata"
func payloadIn(sess *sessdata.ConnSession, lType sessdata.LType, pType byte, data []byte) bool {
func payloadIn(cSess *sessdata.ConnSession, lType sessdata.LType, pType byte, data []byte) bool {
payload := &sessdata.Payload{
LType: lType,
PType: pType,
Data: data,
}
return payloadInData(sess, payload)
return payloadInData(cSess, payload)
}
func payloadInData(sess *sessdata.ConnSession, payload *sessdata.Payload) bool {
func payloadInData(cSess *sessdata.ConnSession, payload *sessdata.Payload) bool {
closed := false
select {
case sess.PayloadIn <- payload:
case <-sess.CloseChan:
case cSess.PayloadIn <- payload:
case <-cSess.CloseChan:
closed = true
}
return closed
}
func payloadOut(sess *sessdata.ConnSession, lType sessdata.LType, pType byte, data []byte) bool {
func payloadOut(cSess *sessdata.ConnSession, lType sessdata.LType, pType byte, data []byte) bool {
payload := &sessdata.Payload{
LType: lType,
PType: pType,
Data: data,
}
return payloadOutData(sess, payload)
return payloadOutData(cSess, payload)
}
func payloadOutData(sess *sessdata.ConnSession, payload *sessdata.Payload) bool {
func payloadOutData(cSess *sessdata.ConnSession, payload *sessdata.Payload) bool {
closed := false
select {
case sess.PayloadOut <- payload:
case <-sess.CloseChan:
case cSess.PayloadOut <- payload:
case <-cSess.CloseChan:
closed = true
}

View File

@@ -6,35 +6,17 @@ import (
"log"
"net"
"net/http"
"net/http/pprof"
"time"
"github.com/bjdgyc/anylink/common"
"github.com/bjdgyc/anylink/proxyproto"
"github.com/bjdgyc/anylink/router"
"github.com/bjdgyc/anylink/base"
"github.com/bjdgyc/anylink/pkg/proxyproto"
"github.com/gorilla/mux"
)
func startAdmin() {
mux := router.NewHttpMux()
mux.HandleFunc(router.ANY, "/", notFound)
// mux.ServeFile(router.ANY, "/static/*", http.Dir("./static"))
// pprof
mux.HandleFunc(router.ANY, "/debug/pprof/*", pprof.Index)
mux.HandleFunc(router.ANY, "/debug/pprof/cmdline", pprof.Cmdline)
mux.HandleFunc(router.ANY, "/debug/pprof/profile", pprof.Profile)
mux.HandleFunc(router.ANY, "/debug/pprof/symbol", pprof.Symbol)
mux.HandleFunc(router.ANY, "/debug/pprof/trace", pprof.Trace)
fmt.Println("Listen admin", common.ServerCfg.AdminAddr)
err := http.ListenAndServe(common.ServerCfg.AdminAddr, mux)
fmt.Println(err)
}
func startTls() {
addr := common.ServerCfg.ServerAddr
certFile := common.ServerCfg.CertFile
keyFile := common.ServerCfg.CertKey
addr := base.Cfg.ServerAddr
certFile := base.Cfg.CertFile
keyFile := base.Cfg.CertKey
// 设置tls信息
tlsConfig := &tls.Config{
@@ -55,24 +37,30 @@ func startTls() {
}
defer ln.Close()
if common.ServerCfg.ProxyProtocol {
if base.Cfg.ProxyProtocol {
ln = &proxyproto.Listener{Listener: ln, ProxyHeaderTimeout: time.Second * 5}
}
fmt.Println("listen ", addr)
base.Info("listen server", addr)
err = srv.ServeTLS(ln, certFile, keyFile)
if err != nil {
log.Fatal(err)
base.Fatal(err)
}
}
func initRoute() http.Handler {
mux := router.NewHttpMux()
mux.HandleFunc("GET", "/", checkLinkClient(LinkHome))
mux.HandleFunc("POST", "/", checkLinkClient(LinkAuth))
mux.HandleFunc("CONNECT", "/CSCOSSLC/tunnel", LinkTunnel)
mux.SetNotFound(http.HandlerFunc(notFound))
return mux
r := mux.NewRouter()
// r.HandleFunc("/", checkLinkClient(LinkHome)).Methods(http.MethodGet)
r.HandleFunc("/", checkLinkClient(LinkAuth)).Methods(http.MethodPost)
r.HandleFunc("/CSCOSSLC/tunnel", LinkTunnel).Methods(http.MethodConnect)
r.HandleFunc("/otp_qr", LinkOtpQr).Methods(http.MethodGet)
r.PathPrefix("/files/").Handler(
http.StripPrefix("/files/",
http.FileServer(http.Dir(base.Cfg.FilesPath)),
),
)
r.NotFoundHandler = http.HandlerFunc(notFound)
return r
}
func notFound(w http.ResponseWriter, r *http.Request) {

View File

@@ -1,7 +1,8 @@
package handler
import (
"github.com/bjdgyc/anylink/common"
"github.com/bjdgyc/anylink/admin"
"github.com/bjdgyc/anylink/base"
"github.com/bjdgyc/anylink/dbdata"
"github.com/bjdgyc/anylink/sessdata"
)
@@ -11,10 +12,10 @@ func Start() {
sessdata.Start()
checkTun()
if common.ServerCfg.LinkMode == common.LinkModeTAP {
if base.Cfg.LinkMode == base.LinkModeTAP {
checkTap()
}
go startAdmin()
go admin.StartAdmin()
go startTls()
go startDtls()
}

View File

@@ -1,71 +0,0 @@
package handler
import (
"crypto/sha1"
"fmt"
"os"
"time"
"github.com/bjdgyc/anylink/common"
"github.com/bjdgyc/anylink/dbdata"
"github.com/xlzd/gotp"
)
func CheckUser(name, pwd, group string) bool {
return true
pl := len(pwd)
if name == "" || pl < 6 {
return false
}
v := &dbdata.User{}
err := dbdata.Get(dbdata.BucketUser, name, v)
if err != nil {
return false
}
if !common.InArrStr(v.Group, group) {
return false
}
pass := pwd[:pl-6]
pwdHash := hashPass(pass)
if v.Password != pwdHash {
return false
}
otp := pwd[pl-6:]
totp := gotp.NewDefaultTOTP(v.OtpSecret)
unix := time.Now().Unix()
verify := totp.Verify(otp, int(unix))
if !verify {
return false
}
return true
}
func UserAdd(name, pwd string, group []string) dbdata.User {
v := dbdata.User{
Id: dbdata.NextId(dbdata.BucketUser),
Username: name,
Password: hashPass(pwd),
OtpSecret: gotp.RandomSecret(32),
Group: group,
UpdatedAt: time.Now(),
}
fmt.Println(v)
secret := "WHH7WA6POOGGEYVIQYXLZU75QLM7YLUX"
totp := gotp.NewDefaultTOTP(secret)
s := totp.ProvisioningUri("bjdtest", "bjdpro")
fmt.Println(s)
// qr, _ := qrcode.New(s, qrcode.Medium)
// a := qr.ToSmallString(false)
// fmt.Println(a)
// qr.WriteFile(512, "a.png")
os.Exit(0)
return v
}
func hashPass(pwd string) string {
sum := sha1.Sum([]byte(pwd))
return fmt.Sprintf("%x", sum)
}