mirror of
https://github.com/bjdgyc/anylink.git
synced 2025-08-10 22:56:11 +08:00
增加管理后台
This commit is contained in:
@@ -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>
|
||||
|
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -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)
|
||||
}
|
||||
|
@@ -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
|
||||
}
|
||||
|
||||
|
@@ -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
|
||||
}
|
||||
|
||||
|
@@ -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)
|
||||
|
@@ -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
|
||||
}
|
||||
|
||||
|
@@ -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) {
|
||||
|
@@ -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()
|
||||
}
|
||||
|
@@ -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)
|
||||
}
|
Reference in New Issue
Block a user