diff --git a/server/dbdata/tables.go b/server/dbdata/tables.go index bdd446b..eeb8cb4 100644 --- a/server/dbdata/tables.go +++ b/server/dbdata/tables.go @@ -60,6 +60,7 @@ type IpMap struct { Id int `json:"id" xorm:"pk autoincr not null"` IpAddr string `json:"ip_addr" xorm:"varchar(32) not null unique"` MacAddr string `json:"mac_addr" xorm:"varchar(32) not null unique"` + UniqueMac bool `json:"unique_mac" xorm:"Bool index"` Username string `json:"username" xorm:"varchar(60)"` Keep bool `json:"keep" xorm:"Bool"` // 保留 ip-mac 绑定 KeepTime time.Time `json:"keep_time" xorm:"DateTime"` diff --git a/server/handler/link_auth.go b/server/handler/link_auth.go index 63f8023..fee85b0 100644 --- a/server/handler/link_auth.go +++ b/server/handler/link_auth.go @@ -18,6 +18,10 @@ import ( var profileHash = "" func LinkAuth(w http.ResponseWriter, r *http.Request) { + // TODO 调试信息输出 + //hd, _ := httputil.DumpRequest(r, true) + //base.Debug("DumpRequest: ", string(hd)) + // 判断anyconnect客户端 userAgent := strings.ToLower(r.UserAgent()) xAggregateAuth := r.Header.Get("X-Aggregate-Auth") @@ -106,6 +110,7 @@ func LinkAuth(w http.ResponseWriter, r *http.Request) { sess.PlatformVersion = ua.PlatformVersion sess.RemoteAddr = r.RemoteAddr // 获取客户端mac地址 + sess.UniqueMac = true macHw, err := net.ParseMAC(sess.MacAddr) if err != nil { var sum [16]byte @@ -113,6 +118,7 @@ func LinkAuth(w http.ResponseWriter, r *http.Request) { sum = md5.Sum([]byte(sess.UniqueIdGlobal)) } else { sum = md5.Sum([]byte(sess.Token)) + sess.UniqueMac = false } macHw = sum[0:5] // 5个byte macHw = append([]byte{0x02}, macHw...) diff --git a/server/handler/link_tunnel.go b/server/handler/link_tunnel.go index bcefe18..7128a4c 100644 --- a/server/handler/link_tunnel.go +++ b/server/handler/link_tunnel.go @@ -34,9 +34,8 @@ func HttpAddHeader(w http.ResponseWriter, key string, value string) { func LinkTunnel(w http.ResponseWriter, r *http.Request) { // TODO 调试信息输出 - // hd, _ := httputil.DumpRequest(r, true) - // fmt.Println("DumpRequest: ", string(hd)) - // fmt.Println("LinkTunnel", r.RemoteAddr) + //hd, _ := httputil.DumpRequest(r, true) + //base.Debug("DumpRequest: ", string(hd)) // 判断session-token的值 cookie, err := r.Cookie("webvpn") diff --git a/server/handler/server.go b/server/handler/server.go index 356d7a7..c4c4cee 100644 --- a/server/handler/server.go +++ b/server/handler/server.go @@ -66,7 +66,7 @@ func startTls() { if base.Cfg.ProxyProtocol { ln = &proxyproto.Listener{ Listener: ln, - ReadHeaderTimeout: 20 * time.Second, + ReadHeaderTimeout: 40 * time.Second, } } diff --git a/server/sessdata/ip_pool.go b/server/sessdata/ip_pool.go index 1ab5ae2..170d58b 100644 --- a/server/sessdata/ip_pool.go +++ b/server/sessdata/ip_pool.go @@ -64,7 +64,8 @@ func getIpLease() { xdb := dbdata.GetXdb() keepIpMaps := []dbdata.IpMap{} sNow := time.Now().Add(-1 * time.Duration(base.Cfg.IpLease) * time.Second) - err := xdb.Cols("ip_addr").Where("keep=?", true).Or("last_login>?", sNow).Find(&keepIpMaps) + err := xdb.Cols("ip_addr").Where("keep=?", true). + Or("unique_mac=? and last_login>?", true, sNow).Find(&keepIpMaps) if err != nil { base.Error(err) } @@ -78,33 +79,71 @@ func getIpLease() { } // AcquireIp 获取动态ip -func AcquireIp(username, macAddr string) net.IP { +func AcquireIp(username, macAddr string, uniqueMac bool) net.IP { ipPoolMux.Lock() defer ipPoolMux.Unlock() - tNow := time.Now() + var ( + err error + tNow = time.Now() + sNow = time.Now().Add(-1 * time.Duration(base.Cfg.IpLease) * time.Second) + ) - // 判断是否已经分配过 - mi := &dbdata.IpMap{} - err := dbdata.One("mac_addr", macAddr, mi) - // 存在ip记录 - if err == nil { - ipStr := mi.IpAddr - ip := net.ParseIP(ipStr) - // 跳过活跃连接 - _, ok := ipActive[ipStr] - // 检测原有ip是否在新的ip池内 - if IpPool.Ipv4IPNet.Contains(ip) && !ok && - utils.Ip2long(ip) >= IpPool.IpLongMin && - utils.Ip2long(ip) <= IpPool.IpLongMax { - mi.Username = username - mi.LastLogin = tNow - // 回写db数据 - _ = dbdata.Set(mi) - ipActive[ipStr] = true - return ip + if uniqueMac { + // 判断是否已经分配过 + mi := &dbdata.IpMap{} + err = dbdata.One("mac_addr", macAddr, mi) + // 存在ip记录 + if err == nil { + ipStr := mi.IpAddr + ip := net.ParseIP(ipStr) + // 跳过活跃连接 + _, ok := ipActive[ipStr] + // 检测原有ip是否在新的ip池内 + if IpPool.Ipv4IPNet.Contains(ip) && !ok && + utils.Ip2long(ip) >= IpPool.IpLongMin && + utils.Ip2long(ip) <= IpPool.IpLongMax { + mi.Username = username + mi.LastLogin = tNow + mi.UniqueMac = uniqueMac + // 回写db数据 + _ = dbdata.Set(mi) + ipActive[ipStr] = true + return ip + } + _ = dbdata.Del(mi) + } + } else { + ipMaps := []dbdata.IpMap{} + err = dbdata.FindWhere(&ipMaps, 50, 1, "username=? and unique_mac=?", username, false) + if err == nil { + //遍历mac记录 + for _, mi := range ipMaps { + ipStr := mi.IpAddr + ip := net.ParseIP(ipStr) + + // 跳过活跃连接 + if _, ok := ipActive[ipStr]; ok { + continue + } + // 跳过ip租期内数据 + if _, ok := ipLease[ipStr]; ok { + continue + } + + if IpPool.Ipv4IPNet.Contains(ip) && + utils.Ip2long(ip) >= IpPool.IpLongMin && + utils.Ip2long(ip) <= IpPool.IpLongMax { + mi.LastLogin = tNow + mi.MacAddr = macAddr + mi.UniqueMac = uniqueMac + // 回写db数据 + _ = dbdata.Set(mi) + ipActive[ipStr] = true + return ip + } + } } - _ = dbdata.Del(mi) } // 全局遍历超过租期和未保留的ip @@ -121,16 +160,22 @@ func AcquireIp(username, macAddr string) net.IP { continue } - v := &dbdata.IpMap{} - err = dbdata.One("ip_addr", ipStr, v) - if err == nil { - // 存在记录直接跳过 - continue + mi := &dbdata.IpMap{} + err = dbdata.One("ip_addr", ipStr, mi) + if err == nil && mi.LastLogin.Before(sNow) { + // 存在记录,说明已经超过租期,可以直接使用 + mi.LastLogin = tNow + mi.MacAddr = macAddr + mi.UniqueMac = uniqueMac + // 回写db数据 + _ = dbdata.Set(mi) + ipActive[ipStr] = true + return ip } if dbdata.CheckErrNotFound(err) { // 该ip没有被使用 - mi = &dbdata.IpMap{IpAddr: ipStr, MacAddr: macAddr, Username: username, LastLogin: tNow} + mi := &dbdata.IpMap{IpAddr: ipStr, MacAddr: macAddr, UniqueMac: uniqueMac, Username: username, LastLogin: tNow} _ = dbdata.Add(mi) ipActive[ipStr] = true return ip diff --git a/server/sessdata/online.go b/server/sessdata/online.go index e8dff7a..7ac526d 100644 --- a/server/sessdata/online.go +++ b/server/sessdata/online.go @@ -14,6 +14,7 @@ type Online struct { Username string `json:"username"` Group string `json:"group"` MacAddr string `json:"mac_addr"` + UniqueMac bool `json:"unique_mac"` Ip net.IP `json:"ip"` RemoteAddr string `json:"remote_addr"` TunName string `json:"tun_name"` @@ -52,6 +53,7 @@ func OnlineSess() []Online { Username: v.Username, Group: v.Group, MacAddr: v.MacAddr, + UniqueMac: v.UniqueMac, RemoteAddr: v.CSess.RemoteAddr, TunName: v.CSess.IfName, Mtu: v.CSess.Mtu, diff --git a/server/sessdata/session.go b/server/sessdata/session.go index 6af9bc5..b60675f 100644 --- a/server/sessdata/session.go +++ b/server/sessdata/session.go @@ -71,6 +71,7 @@ type Session struct { MacAddr string // 客户端mac地址 UniqueIdGlobal string // 客户端唯一标示 MacHw net.HardwareAddr + UniqueMac bool // 客户端获取到真实设备mac Username string // 用户名 Group string AuthStep string @@ -178,6 +179,7 @@ func (s *Session) NewConn() *ConnSession { macAddr := s.MacAddr macHw := s.MacHw username := s.Username + uniqueMac := s.UniqueMac s.mux.RUnlock() if active { s.CSess.Close() @@ -187,7 +189,7 @@ func (s *Session) NewConn() *ConnSession { if !limit { return nil } - ip := AcquireIp(username, macAddr) + ip := AcquireIp(username, macAddr, uniqueMac) if ip == nil { LimitClient(username, true) return nil diff --git a/web/src/pages/user/IpMap.vue b/web/src/pages/user/IpMap.vue index b6f6076..d4f7275 100644 --- a/web/src/pages/user/IpMap.vue +++ b/web/src/pages/user/IpMap.vue @@ -35,6 +35,14 @@ label="MAC地址"> </el-table-column> + <el-table-column + prop="unique_mac" + label="唯一MAC"> + <template slot-scope="scope"> + <el-tag v-if="scope.row.unique_mac" type="success">是</el-tag> + </template> + </el-table-column> + <el-table-column prop="username" label="用户名"> diff --git a/web/src/pages/user/Online.vue b/web/src/pages/user/Online.vue index f9041cb..9b4f141 100644 --- a/web/src/pages/user/Online.vue +++ b/web/src/pages/user/Online.vue @@ -27,6 +27,15 @@ prop="mac_addr" label="MAC地址"> </el-table-column> + + <el-table-column + prop="unique_mac" + label="唯一MAC"> + <template slot-scope="scope"> + <el-tag v-if="scope.row.unique_mac" type="success">是</el-tag> + </template> + </el-table-column> + <el-table-column prop="ip" label="IP地址"