diff --git a/network/command.go b/network/command.go index b62093b..33e3811 100644 --- a/network/command.go +++ b/network/command.go @@ -3,6 +3,8 @@ package network import ( "bytes" "encoding/gob" + "fmt" + "log" "net" ) @@ -63,14 +65,19 @@ func (v *VPNCommandMsg) ToDetailMsg(msg interface{}) error { return decoder.Decode(msg) } -func ReadCommand(conn *net.Conn) (msg *VPNCommandMsg, err error) { +func ReadCommand(conn net.Conn) (msg *VPNCommandMsg, err error) { msg = new(VPNCommandMsg) - err = gob.NewDecoder(*conn).Decode(msg) + err = gob.NewDecoder(conn).Decode(msg) + log.Println("Read Data From " + conn.RemoteAddr().String() + ":") + log.Println(fmt.Sprintf("%+v", msg)) return } -func WriteCommand(conn *net.Conn, msg *VPNCommandMsg) (err error) { - err = gob.NewEncoder(*conn).Encode(msg) +func WriteCommand(conn net.Conn, msg *VPNCommandMsg) (err error) { + err = gob.NewEncoder(conn).Encode(msg) + log.Println("Write Data To" + + " " + conn.RemoteAddr().String() + ":") + log.Println(fmt.Sprintf("%+v", msg)) return } @@ -95,11 +102,17 @@ type ClientUnRegisterResponseMsg struct { } type ClientQueryOthersRequestMsg struct { - Ok bool +} + +type ClientInfo struct { + Ip string + Mac string + Mask string + Addr net.Addr } type ClientQueryOthersResponseMsg struct { - Ok bool + Clients []ClientInfo } type ClientConnectToRequestMsg struct { diff --git a/network/ice-conn.go b/network/p2p-conn.go similarity index 100% rename from network/ice-conn.go rename to network/p2p-conn.go diff --git a/ntVPN-client/ntVPN-client.go b/ntVPN-client/ntVPN-client.go index 1379386..1993bae 100644 --- a/ntVPN-client/ntVPN-client.go +++ b/ntVPN-client/ntVPN-client.go @@ -2,46 +2,121 @@ package main import ( "crypto/sha1" + "encoding/gob" "flag" "fmt" "github.com/joshuafc/ntVPN/network" "github.com/xtaci/kcp-go" "golang.org/x/crypto/pbkdf2" + "log" + "math/rand" "net" "strconv" + "time" ) func main() { + gob.Register(&net.UDPAddr{}) + serverAddress := flag.String("server", "127.0.0.1", "specify ntVPN server IP address") serverPort := flag.Int("port", 3455, "specify ntVPN server port") encryptKey := flag.String("encry_key", "password", "specify ntVPN transfer encrypt password") + + vpnIP := flag.String("vpn_ip", "192.168.101.2", "specify vpn node ip address") + vpnMask := flag.String("vpn_mask", "255.255.255.0", "specify vpn node mask") + vpnMac := flag.String("vpn_mac", "", "specify vpn node mac address") + + readChan := make(chan *network.VPNCommandMsg, 5) + writeChan := make(chan *network.VPNCommandMsg, 5) + flag.Parse() + if len(*vpnMac) == 0 { + buf := make([]byte, 6) + _, err := rand.Read(buf) + if err != nil { + fmt.Println("error:", err) + return + } + // Set the local bit + buf[0] |= 2 + *vpnMac = fmt.Sprintf("%02x:%02x:%02x:%02x:%02x:%02x", buf[0], buf[1], buf[2], buf[3], buf[4], buf[5]) + } + key := pbkdf2.Key([]byte(*encryptKey), []byte(*encryptKey), 1024, 32, sha1.New) block, _ := kcp.NewAESBlockCrypt(key) if sess, err := kcp.DialWithOptions(*serverAddress+":"+strconv.Itoa(*serverPort), block, 10, 3); err == nil { var conn net.Conn conn = sess + defer conn.Close() - var msg network.ClientRegisterRequestMsg - msg.Ip = "192.168.100.4" - network.WriteCommand(&conn, network.FromDetailMsg(network.ClientRegisterRequest, &msg)) - handleServer(conn) - } -} + go func() { + for { + msg, err := network.ReadCommand(conn) + if err != nil { + break + } + readChan <- msg + } + }() -func handleServer(s net.Conn) { - for { - cmd, err := network.ReadCommand(&s) - if err != nil { - return - } - switch { - case cmd.CommandType == network.ClientRegisterRequest: - var detailMsg network.ClientRegisterRequestMsg - err = cmd.ToDetailMsg(detailMsg) - fmt.Println("%+v", detailMsg) + go func() { + for { + select { + case cmd, ok := <-writeChan: + if !ok { + break + } + err := network.WriteCommand(conn, cmd) + if err != nil { + break + } + } + } + }() + + timer1 := time.NewTimer(0) + defer timer1.Stop() + go func() { + for range timer1.C { + var msg network.ClientRegisterRequestMsg + msg.Ip = *vpnIP + msg.Mac = *vpnMac + msg.Mask = *vpnMask + writeChan <- network.FromDetailMsg(network.ClientRegisterRequest, msg) + timer1.Reset(time.Second * 30) + } + }() + + timer2 := time.NewTimer(time.Second * 2) + defer timer2.Stop() + for { + select { + case cmd, ok := <-readChan: + if !ok { + return + } + switch { + case cmd.CommandType == network.ClientRegisterResponse: + var detailMsg network.ClientRegisterResponseMsg + err = cmd.ToDetailMsg(&detailMsg) + if !detailMsg.Ok { + log.Print("Register Failed!") + } + log.Println(fmt.Sprintf("%+v", detailMsg)) + case cmd.CommandType == network.ClientQueryOthersResponse: + var detailMsg network.ClientQueryOthersResponseMsg + err = cmd.ToDetailMsg(&detailMsg) + log.Println(fmt.Sprintf("%+v", detailMsg)) + default: + log.Print("Data Not Process.") + } + case <-timer2.C: + timer2.Reset(time.Second * 2) + var msg network.ClientQueryOthersRequestMsg + writeChan <- network.FromDetailMsg(network.ClientQueryOthersRequest, &msg) + } } } } diff --git a/ntVPN-server/ntVPN-server.go b/ntVPN-server/ntVPN-server.go index a0f56ea..b0fff7b 100644 --- a/ntVPN-server/ntVPN-server.go +++ b/ntVPN-server/ntVPN-server.go @@ -1,18 +1,29 @@ package main import ( + "context" "crypto/sha1" + "encoding/gob" + "errors" "flag" - "fmt" "github.com/joshuafc/ntVPN/network" "github.com/xtaci/kcp-go" "golang.org/x/crypto/pbkdf2" "log" "net" "strconv" + "sync" ) func main() { + gob.Register(&net.UDPAddr{}) + serverContext, serverQuit := context.WithCancel(context.Background()) + defer serverQuit() + var clientManager ClientManager + clientManager.ConnMap = make(map[net.Addr]*ClientItem) + clientManager.IpMap = make(map[string]*ClientItem) + clientManager.MacMap = make(map[string]*ClientItem) + clientManager.mutex = new(sync.Mutex) serverPort := flag.Int("port", 3455, "specify ntVPN server port") encryptKey := flag.String("encry_key", "password", "specify ntVPN transfer encrypt password") flag.Parse() @@ -25,24 +36,191 @@ func main() { if err != nil { log.Fatal(err) } - go handleClient(s) + go clientManager.handleConnection(serverContext, s) } } else { log.Fatal(err) } } -func handleClient(s net.Conn) { - for { - cmd, err := network.ReadCommand(&s) - if err != nil { - return +type ClientItem struct { + conn net.Conn + writeLock *sync.Mutex + clientContext context.Context + clientContextCancelFunc func() + clientInfo network.ClientRegisterRequestMsg + readChan chan *network.VPNCommandMsg + writeChan chan *network.VPNCommandMsg +} + +func (clientItem *ClientItem) ProcessMsg(msg *network.VPNCommandMsg) error { + return nil +} + +type ClientManager struct { + ConnMap map[net.Addr]*ClientItem + IpMap map[string]*ClientItem + MacMap map[string]*ClientItem + mutex *sync.Mutex +} + +func (clientManager *ClientManager) P2PRequest(toClientItem *ClientItem) error { + clientManager.mutex.Lock() + defer clientManager.mutex.Unlock() + + return nil +} + +func (clientManager *ClientManager) P2PResponse(toClientItem *ClientItem) error { + clientManager.mutex.Lock() + defer clientManager.mutex.Unlock() + return nil +} + +func (clientManager *ClientManager) AddClient(clientItem *ClientItem) error { + clientManager.mutex.Lock() + defer clientManager.mutex.Unlock() + clientManager.ConnMap[clientItem.conn.RemoteAddr()] = clientItem + return nil +} + +func (clientManager *ClientManager) UpdateClient(clientItem *ClientItem) error { + clientManager.mutex.Lock() + defer clientManager.mutex.Unlock() + + ip_val, ip_ok := clientManager.IpMap[clientItem.clientInfo.Ip] + mac_val, mac_ok := clientManager.MacMap[clientItem.clientInfo.Mac] + + if ip_ok && ip_val.conn.RemoteAddr() != clientItem.conn.RemoteAddr() { + return errors.New("Error: Ip addr Used!") + } + + if mac_ok && mac_val.conn.RemoteAddr() != clientItem.conn.RemoteAddr() { + return errors.New("Error: Mac addr Used!") + } + + clientManager.IpMap[clientItem.clientInfo.Ip] = clientItem + clientManager.MacMap[clientItem.clientInfo.Mac] = clientItem + return nil +} + +func (clientManager *ClientManager) DeleteClient(clientItem *ClientItem) error { + clientManager.mutex.Lock() + defer clientManager.mutex.Unlock() + if clientItem.clientInfo.Ip != "" { + delete(clientManager.IpMap, clientItem.clientInfo.Ip) + } + if clientItem.clientInfo.Mac != "" { + delete(clientManager.MacMap, clientItem.clientInfo.Mac) + } + delete(clientManager.ConnMap, clientItem.conn.RemoteAddr()) + return nil +} + +func (clientManager *ClientManager) GetClients(selfAddr net.Addr) (clientInfo []network.ClientInfo) { + clientInfo = make([]network.ClientInfo, 0) + clientManager.mutex.Lock() + defer clientManager.mutex.Unlock() + for k, v := range clientManager.ConnMap { + if k == selfAddr { + continue } - switch { - case cmd.CommandType == network.ClientRegisterRequest: - var detailMsg network.ClientRegisterRequestMsg - err = cmd.ToDetailMsg(&detailMsg) - fmt.Println("%+v", detailMsg) + clientInfo = append(clientInfo, network.ClientInfo{ + Ip: v.clientInfo.Ip, + Mac: v.clientInfo.Mac, + Mask: v.clientInfo.Mask, + Addr: k, + }) + } + return +} + +func (clientManager *ClientManager) handleConnection(serverContext context.Context, s net.Conn) { + var clientItem ClientItem + clientItem.writeLock = new(sync.Mutex) + clientItem.clientContext, clientItem.clientContextCancelFunc = context.WithCancel(serverContext) + clientItem.conn = s + + clientManager.AddClient(&clientItem) + + clientItem.readChan = make(chan *network.VPNCommandMsg, 5) + clientItem.writeChan = make(chan *network.VPNCommandMsg, 5) + + defer func() { + clientItem.clientContextCancelFunc() + clientManager.DeleteClient(&clientItem) + close(clientItem.writeChan) + }() + + go func() { + for { + msg, err := network.ReadCommand(s) + if err != nil && clientItem.clientContext.Err() != nil { + close(clientItem.readChan) + break + } + clientItem.readChan <- msg + } + }() + + go func() { + for { + select { + case cmd, ok := <-clientItem.writeChan: + if !ok { + break + } + err := network.WriteCommand(s, cmd) + if err != nil { + s.Close() + break + } + } + } + }() + +Exit: + for { + select { + case cmd, ok := <-clientItem.readChan: + if !ok { + break + } + switch true { + case cmd.CommandType == network.ClientRegisterRequest: + err := cmd.ToDetailMsg(&clientItem.clientInfo) + if err != nil { + break + } + err1 := clientManager.UpdateClient(&clientItem) + var response network.ClientRegisterResponseMsg + response.Ok = err1 == nil + clientItem.writeChan <- network.FromDetailMsg(network.ClientRegisterResponse, &response) + if !response.Ok { + break Exit + } + case cmd.CommandType == network.ClientUnRegisterRequest: + err := cmd.ToDetailMsg(&clientItem.clientInfo) + if err != nil { + break + } + clientManager.DeleteClient(&clientItem) + var response network.ClientUnRegisterResponseMsg + response.Ok = true + clientItem.writeChan <- network.FromDetailMsg(network.ClientUnRegisterResponse, &response) + + case cmd.CommandType == network.ClientQueryOthersRequest: + var response network.ClientQueryOthersResponseMsg + response.Clients = clientManager.GetClients(s.RemoteAddr()) + clientItem.writeChan <- network.FromDetailMsg(network.ClientQueryOthersResponse, &response) + default: + err := clientItem.ProcessMsg(cmd) + if err != nil { + break + } + } + case <-clientItem.clientContext.Done(): + break } } } diff --git a/tuntap/tuntap_windows.go b/tuntap/tuntap_windows.go index 0daff0b..792dc2a 100644 --- a/tuntap/tuntap_windows.go +++ b/tuntap/tuntap_windows.go @@ -68,6 +68,7 @@ func lookup_adapter_reg_path(deviceRegistry string) string { } func CreateTapDevice(deviceName string) (TapDevice, error) { + deviceName = "" // ignore deviceName on Windows key, ok := r.OpenKey(r.LOCAL_MACHINE, NETWORK_CONNECTIONS_KEY, r.READ) if ok != nil { println(ok.Error())