mirror of
https://github.com/lucheng0127/virtuallan.git
synced 2025-09-26 20:51:11 +08:00
Fix client ip by get client ip base on username hash
Count username hash, get client ip base on it, it will make ip fixed base on client login username.
This commit is contained in:
@@ -175,14 +175,14 @@ func (svc *Server) OfferIPToClient(conn *net.UDPConn, ip string, raddr *net.UDPA
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (svc *Server) CreateClientForAddr(addr *net.UDPAddr, conn *net.UDPConn) (*UClient, error) {
|
func (svc *Server) CreateClientForAddr(addr *net.UDPAddr, conn *net.UDPConn, username string) (*UClient, error) {
|
||||||
iface, err := utils.NewTap(svc.Bridge)
|
iface, err := utils.NewTap(svc.Bridge)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pop a ip for client
|
// Pop a ip for client
|
||||||
ip, err := svc.PopIPFromPool()
|
ip, err := svc.IPForUser(username)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -199,6 +199,8 @@ func (svc *Server) CreateClientForAddr(addr *net.UDPAddr, conn *net.UDPConn) (*U
|
|||||||
client.Svc = svc
|
client.Svc = svc
|
||||||
client.IP = ip
|
client.IP = ip
|
||||||
|
|
||||||
|
log.Infof("new client remote addr %s ip %s login at %s\n", client.RAddr.String(), client.IP.String(), client.Login)
|
||||||
|
|
||||||
UPool[addr.String()] = client
|
UPool[addr.String()] = client
|
||||||
|
|
||||||
// Monitor client heartbeat
|
// Monitor client heartbeat
|
||||||
@@ -276,7 +278,7 @@ func (svc *Server) ListenAndServe() error {
|
|||||||
log.Infof("client %s login to %s succeed\n", addr.String(), u)
|
log.Infof("client %s login to %s succeed\n", addr.String(), u)
|
||||||
|
|
||||||
// Create client for authed addr
|
// Create client for authed addr
|
||||||
client, err := svc.CreateClientForAddr(addr, ln)
|
client, err := svc.CreateClientForAddr(addr, ln, u)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("create authed client %s\n", err.Error())
|
log.Errorf("create authed client %s\n", err.Error())
|
||||||
svc.SendResponse(ln, packet.RSP_INTERNAL_ERR, addr)
|
svc.SendResponse(ln, packet.RSP_INTERNAL_ERR, addr)
|
||||||
|
@@ -57,7 +57,43 @@ func (svc *Server) IdxFromIP(ip net.IP) int {
|
|||||||
return int(ipInt - ipStartInt)
|
return int(ipInt - ipStartInt)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(shawnlu): Implement it with hash map, username as input to count hash
|
func (svc *Server) IPForUser(username string) (net.IP, error) {
|
||||||
|
idx := utils.IdxFromString(svc.IPCount, username)
|
||||||
|
idxEnd := idx - 1
|
||||||
|
|
||||||
|
for idx < svc.IPCount {
|
||||||
|
if idx == idxEnd {
|
||||||
|
// Checked the last idx
|
||||||
|
if svc.IPIdxInPool(idx) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
svc.MLock.Lock()
|
||||||
|
svc.UsedIP = append(svc.UsedIP, idx)
|
||||||
|
svc.MLock.Unlock()
|
||||||
|
return svc.IPFromIdx(idx), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if svc.IPIdxInPool(idx) {
|
||||||
|
idx += 1
|
||||||
|
|
||||||
|
if idx == svc.IPCount {
|
||||||
|
// Check from zero
|
||||||
|
idx = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
svc.MLock.Lock()
|
||||||
|
svc.UsedIP = append(svc.UsedIP, idx)
|
||||||
|
svc.MLock.Unlock()
|
||||||
|
return svc.IPFromIdx(idx), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, errors.New("run out of ip")
|
||||||
|
}
|
||||||
|
|
||||||
func (svc *Server) PopIPFromPool() (net.IP, error) {
|
func (svc *Server) PopIPFromPool() (net.IP, error) {
|
||||||
for idx := 0; idx < svc.IPCount; idx++ {
|
for idx := 0; idx < svc.IPCount; idx++ {
|
||||||
if svc.IPIdxInPool(idx) {
|
if svc.IPIdxInPool(idx) {
|
||||||
|
84
pkg/server/ipmgr_linux_test.go
Normal file
84
pkg/server/ipmgr_linux_test.go
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
package server
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net"
|
||||||
|
"reflect"
|
||||||
|
"sync"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"bou.ke/monkey"
|
||||||
|
"github.com/lucheng0127/virtuallan/pkg/utils"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestServer_IPForUser(t *testing.T) {
|
||||||
|
type args struct {
|
||||||
|
username string
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
args args
|
||||||
|
want net.IP
|
||||||
|
wantErr bool
|
||||||
|
patchFunc interface{}
|
||||||
|
targetFunc interface{}
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "idx 1-1",
|
||||||
|
args: args{username: "whocares"},
|
||||||
|
want: net.ParseIP("192.168.123.101").To4(),
|
||||||
|
wantErr: false,
|
||||||
|
patchFunc: utils.IdxFromString,
|
||||||
|
targetFunc: func(int, string) int { return 1 },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "idx 1-2",
|
||||||
|
args: args{username: "whocares"},
|
||||||
|
want: net.ParseIP("192.168.123.102").To4(),
|
||||||
|
wantErr: false,
|
||||||
|
patchFunc: utils.IdxFromString,
|
||||||
|
targetFunc: func(int, string) int { return 1 },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "idx 1-3",
|
||||||
|
args: args{username: "whocares"},
|
||||||
|
want: net.ParseIP("192.168.123.100").To4(),
|
||||||
|
wantErr: false,
|
||||||
|
patchFunc: utils.IdxFromString,
|
||||||
|
targetFunc: func(int, string) int { return 1 },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "idx 1-4",
|
||||||
|
args: args{username: "whocares"},
|
||||||
|
want: nil,
|
||||||
|
wantErr: true,
|
||||||
|
patchFunc: utils.IdxFromString,
|
||||||
|
targetFunc: func(int, string) int { return 1 },
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
ipStart := net.ParseIP("192.168.123.100").To4()
|
||||||
|
svc := &Server{
|
||||||
|
UsedIP: make([]int, 0),
|
||||||
|
IPStart: ipStart,
|
||||||
|
IPCount: 3,
|
||||||
|
MLock: sync.Mutex{},
|
||||||
|
Routes: make(map[string]string),
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
if tt.targetFunc != nil {
|
||||||
|
monkey.Patch(tt.patchFunc, tt.targetFunc)
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
got, err := svc.IPForUser(tt.args.username)
|
||||||
|
if (err != nil) != tt.wantErr {
|
||||||
|
t.Errorf("Server.IPForUser() error = %v, wantErr %v", err, tt.wantErr)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !reflect.DeepEqual(got, tt.want) {
|
||||||
|
t.Errorf("Server.IPForUser() = %v, want %v", got, tt.want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
12
pkg/utils/hash.go
Normal file
12
pkg/utils/hash.go
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
package utils
|
||||||
|
|
||||||
|
import (
|
||||||
|
"hash/fnv"
|
||||||
|
)
|
||||||
|
|
||||||
|
func IdxFromString(step int, str string) int {
|
||||||
|
h := fnv.New32a()
|
||||||
|
h.Write([]byte(str))
|
||||||
|
|
||||||
|
return int(h.Sum32() % uint32(step))
|
||||||
|
}
|
55
pkg/utils/hash_test.go
Normal file
55
pkg/utils/hash_test.go
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
package utils
|
||||||
|
|
||||||
|
import "testing"
|
||||||
|
|
||||||
|
func TestIdxFromString(t *testing.T) {
|
||||||
|
type args struct {
|
||||||
|
step int
|
||||||
|
str string
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
args args
|
||||||
|
want int
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "step 100 user1",
|
||||||
|
want: 32,
|
||||||
|
args: args{
|
||||||
|
step: 100,
|
||||||
|
str: "shawn",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "step 100 user2",
|
||||||
|
want: 59,
|
||||||
|
args: args{
|
||||||
|
step: 100,
|
||||||
|
str: "guest",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "step 30 user1",
|
||||||
|
want: 2,
|
||||||
|
args: args{
|
||||||
|
step: 30,
|
||||||
|
str: "shawn",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "step 30 user2",
|
||||||
|
want: 9,
|
||||||
|
args: args{
|
||||||
|
step: 30,
|
||||||
|
str: "guest",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
if got := IdxFromString(tt.args.step, tt.args.str); got != tt.want {
|
||||||
|
t.Errorf("IdxFromString() = %v, want %v", got, tt.want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user