From 26ba4dbe94a54cb549172f632f915469edc5658f Mon Sep 17 00:00:00 2001 From: KusakabeSi Date: Mon, 23 Aug 2021 19:11:01 +0000 Subject: [PATCH] VPPTap, not test yet --- README.md | 84 +------ config/config.go | 37 ++- device/peer.go | 54 ++++- device/receivesendproc.go | 48 +--- example_config/p2p_mode/n1.yaml | 2 +- example_config/p2p_mode/n2.yaml | 2 +- example_config/p2p_mode/n3.yaml | 2 +- example_config/p2p_mode/n4.yaml | 2 +- example_config/p2p_mode/n5.yaml | 2 +- example_config/p2p_mode/n6.yaml | 2 +- example_config/static_mode/n1.yaml | 2 +- example_config/static_mode/n2.yaml | 2 +- example_config/static_mode/n3.yaml | 2 +- example_config/static_mode/n4.yaml | 2 +- example_config/static_mode/n5.yaml | 2 +- example_config/static_mode/n6.yaml | 2 +- example_config/super_mode/n1.yaml | 2 +- example_config/super_mode/n2.yaml | 2 +- go.mod | 3 + main_edge.go | 8 +- main_httpserver.go | 60 ++++- main_super.go | 11 +- path/metamessage.go | 3 +- tap/tap.go | 2 - tap/tap_dummy.go | 8 - tap/tap_stdio.go | 4 - tap/tap_udpsock.go | 6 - tap/tap_vpp.go | 352 +++++++++++++++++++++++++++++ 28 files changed, 521 insertions(+), 187 deletions(-) create mode 100644 tap/tap_vpp.go diff --git a/README.md b/README.md index 9e01081..157fede 100644 --- a/README.md +++ b/README.md @@ -1,77 +1,9 @@ -# Go Implementation of [WireGuard](https://www.wireguard.com/) - -This is an implementation of WireGuard in Go. - -## Usage - -Most Linux kernel WireGuard users are used to adding an interface with `ip link add wg0 type wireguard`. With wireguard-go, instead simply run: - +### Build ``` -$ wireguard-go wg0 -``` - -This will create an interface and fork into the background. To remove the interface, use the usual `ip link del wg0`, or if your system does not support removing interfaces directly, you may instead remove the control socket via `rm -f /var/run/wireguard/wg0.sock`, which will result in wireguard-go shutting down. - -To run wireguard-go without forking to the background, pass `-f` or `--foreground`: - -``` -$ wireguard-go -f wg0 -``` - -When an interface is running, you may use [`wg(8)`](https://git.zx2c4.com/wireguard-tools/about/src/man/wg.8) to configure it, as well as the usual `ip(8)` and `ifconfig(8)` commands. - -To run with more logging you may set the environment variable `LOG_LEVEL=debug`. - -## Platforms - -### Linux - -This will run on Linux; however you should instead use the kernel module, which is faster and better integrated into the OS. See the [installation page](https://www.wireguard.com/install/) for instructions. - -### macOS - -This runs on macOS using the utun driver. It does not yet support sticky sockets, and won't support fwmarks because of Darwin limitations. Since the utun driver cannot have arbitrary interface names, you must either use `utun[0-9]+` for an explicit interface name or `utun` to have the kernel select one for you. If you choose `utun` as the interface name, and the environment variable `WG_TUN_NAME_FILE` is defined, then the actual name of the interface chosen by the kernel is written to the file specified by that variable. - -### Windows - -This runs on Windows, but you should instead use it from the more [fully featured Windows app](https://git.zx2c4.com/wireguard-windows/about/), which uses this as a module. - -### FreeBSD - -This will run on FreeBSD. It does not yet support sticky sockets. Fwmark is mapped to `SO_USER_COOKIE`. - -### OpenBSD - -This will run on OpenBSD. It does not yet support sticky sockets. Fwmark is mapped to `SO_RTABLE`. Since the tun driver cannot have arbitrary interface names, you must either use `tun[0-9]+` for an explicit interface name or `tun` to have the program select one for you. If you choose `tun` as the interface name, and the environment variable `WG_TUN_NAME_FILE` is defined, then the actual name of the interface chosen by the kernel is written to the file specified by that variable. - -## Building - -This requires an installation of [go](https://golang.org) ≥ 1.16. - -``` -$ git clone https://git.zx2c4.com/wireguard-go -$ cd wireguard-go -$ make -``` - -## License - - Copyright (C) 2017-2021 WireGuard LLC. All Rights Reserved. - - Permission is hereby granted, free of charge, to any person obtaining a copy of - this software and associated documentation files (the "Software"), to deal in - the Software without restriction, including without limitation the rights to - use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies - of the Software, and to permit persons to whom the Software is furnished to do - so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in all - copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. +echo "deb [trusted=yes] https://packagecloud.io/fdio/release/ubuntu focal main" > /etc/apt/sources.list.d/99fd.io.list +curl -L https://packagecloud.io/fdio/release/gpgkey | sudo apt-key add - +apt-get update +apt-get install vpp vpp-plugin-core python3-vpp-api vpp-dbg vpp-dev libmemif libmemif-dev wireguard-tools +export CGO_CFLAGS="-I/usr/include/memif" +make +``` \ No newline at end of file diff --git a/config/config.go b/config/config.go index c5bc7fc..e7e7fae 100644 --- a/config/config.go +++ b/config/config.go @@ -1,5 +1,9 @@ package config +import ( + "crypto/rand" +) + type EdgeConfig struct { Interface InterfaceConf NodeID Vertex @@ -24,14 +28,15 @@ type SuperConfig struct { } type InterfaceConf struct { - Itype string - IfaceID int - Name string - MacAddr string - MTU int - RecvAddr string - SendAddr string - HumanFriendly bool + Itype string + Name string + VPPIfaceID uint32 + VPPBridgeID uint32 + MacAddr string + MTU int + RecvAddr string + SendAddr string + DevFriendly bool } type PeerInfo struct { @@ -103,3 +108,19 @@ type HTTP_Peerinfo struct { type HTTP_Peers struct { Peers map[string]HTTP_Peerinfo } + +const chars = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" + +func RandomStr(length int, defaults string) string { + bytes := make([]byte, length) + + if _, err := rand.Read(bytes); err != nil { + return defaults + } + + for i, b := range bytes { + bytes[i] = chars[b%byte(len(chars))] + } + + return string(bytes) +} diff --git a/device/peer.go b/device/peer.go index c776487..45db886 100644 --- a/device/peer.go +++ b/device/peer.go @@ -6,10 +6,12 @@ package device import ( + "bytes" "container/list" "encoding/base64" "errors" "fmt" + "io/ioutil" "strconv" "sync" "sync/atomic" @@ -18,6 +20,7 @@ import ( "github.com/KusakabeSi/EtherGuardVPN/config" "github.com/KusakabeSi/EtherGuardVPN/conn" "github.com/KusakabeSi/EtherGuardVPN/path" + "gopkg.in/yaml.v2" ) type Peer struct { @@ -304,7 +307,7 @@ func (peer *Peer) SetEndpointFromPacket(endpoint conn.Endpoint) { return } peer.Lock() - peer.device.SaveToConfig(peer, endpoint.DstToString()) + peer.device.SaveToConfig(peer, endpoint) peer.endpoint = endpoint peer.Unlock() } @@ -322,3 +325,52 @@ func (peer *Peer) GetEndpointDstStr() string { } return peer.endpoint.DstToString() } + +func (device *Device) SaveToConfig(peer *Peer, endpoint conn.Endpoint) { + if device.IsSuperNode { //Can't in super mode + return + } + if !device.DRoute.P2P.UseP2P { //Must in p2p mode + return + } + if peer.endpoint != nil && peer.endpoint.DstIP().Equal(endpoint.DstIP()) { //endpoint changed + return + } + if peer.LastPingReceived.Add(path.S2TD(device.DRoute.P2P.PeerAliveTimeout)).After(time.Now()) { //Peer alives + return + } + url := endpoint.DstToString() + foundInFile := false + pubkeystr := PubKey2Str(peer.handshake.remoteStatic) + pskstr := PSKeyStr(peer.handshake.presharedKey) + if bytes.Equal(peer.handshake.presharedKey[:], make([]byte, 32)) { + pskstr = "" + } + for _, peerfile := range device.EdgeConfig.Peers { + if peerfile.NodeID == peer.ID && peerfile.PubKey == pubkeystr { + foundInFile = true + if peerfile.Static == false { + peerfile.EndPoint = url + } + } else if peerfile.NodeID == peer.ID || peerfile.PubKey == pubkeystr { + panic("Found NodeID match " + strconv.Itoa(int(peer.ID)) + ", but PubKey Not match %s enrties in config file" + pubkeystr) + } + } + if !foundInFile { + device.EdgeConfig.Peers = append(device.EdgeConfig.Peers, config.PeerInfo{ + NodeID: peer.ID, + PubKey: pubkeystr, + PSKey: pskstr, + EndPoint: url, + Static: false, + }) + } + go device.SaveConfig() +} + +func (device *Device) SaveConfig() { + if device.DRoute.SaveNewPeers { + configbytes, _ := yaml.Marshal(device.EdgeConfig) + ioutil.WriteFile(device.EdgeConfigPath, configbytes, 0666) + } +} diff --git a/device/receivesendproc.go b/device/receivesendproc.go index 1c9b61d..154b693 100644 --- a/device/receivesendproc.go +++ b/device/receivesendproc.go @@ -14,7 +14,6 @@ import ( "github.com/KusakabeSi/EtherGuardVPN/config" "github.com/KusakabeSi/EtherGuardVPN/path" - "gopkg.in/yaml.v2" ) func (device *Device) SendPacket(peer *Peer, packet []byte, offset int) { @@ -375,46 +374,6 @@ func (device *Device) RoutineSetEndpoint() { } } -func (device *Device) SaveToConfig(thepeer *Peer, url string) { - if thepeer.LastPingReceived.Add(path.S2TD(device.DRoute.P2P.PeerAliveTimeout)).After(time.Now()) { - //Peer alives - return - } - foundInFile := false - pubkeystr := PubKey2Str(thepeer.handshake.remoteStatic) - pskstr := PSKeyStr(thepeer.handshake.presharedKey) - if bytes.Equal(thepeer.handshake.presharedKey[:], make([]byte, 32)) { - pskstr = "" - } - for _, peerfile := range device.EdgeConfig.Peers { - if peerfile.NodeID == thepeer.ID && peerfile.PubKey == pubkeystr { - foundInFile = true - if peerfile.Static == false { - peerfile.EndPoint = url - } - } else if peerfile.NodeID == thepeer.ID || peerfile.PubKey == pubkeystr { - panic("Found NodeID match " + strconv.Itoa(int(thepeer.ID)) + ", but PubKey Not match %s enrties in config file" + pubkeystr) - } - } - if !foundInFile { - device.EdgeConfig.Peers = append(device.EdgeConfig.Peers, config.PeerInfo{ - NodeID: thepeer.ID, - PubKey: pubkeystr, - PSKey: pskstr, - EndPoint: url, - Static: false, - }) - } - go device.SaveConfig() -} - -func (device *Device) SaveConfig() { - if device.DRoute.SaveNewPeers { - configbytes, _ := yaml.Marshal(device.EdgeConfig) - ioutil.WriteFile(device.EdgeConfigPath, configbytes, 0666) - } -} - func (device *Device) RoutineSendPing() { if !(device.DRoute.P2P.UseP2P || device.DRoute.SuperNode.UseSuperNode) { return @@ -430,11 +389,11 @@ func (device *Device) RoutineRegister() { if !(device.DRoute.SuperNode.UseSuperNode) { return } - first := true for { body, _ := path.GetByte(path.RegisterMsg{ - Node_id: device.ID, - Init: first, + Node_id: device.ID, + PeerStateHash: device.peers.Peer_state, + NhStateHash: device.graph.NhTableHash, }) buf := make([]byte, path.EgHeaderLen+len(body)) header, _ := path.NewEgHeader(buf[0:path.EgHeaderLen]) @@ -446,7 +405,6 @@ func (device *Device) RoutineRegister() { copy(buf[path.EgHeaderLen:], body) device.Send2Super(buf, MessageTransportOffsetContent) time.Sleep(path.S2TD(device.DRoute.SendPingInterval)) - first = false } } diff --git a/example_config/p2p_mode/n1.yaml b/example_config/p2p_mode/n1.yaml index 29ba4fe..c7e5707 100644 --- a/example_config/p2p_mode/n1.yaml +++ b/example_config/p2p_mode/n1.yaml @@ -6,7 +6,7 @@ interface: mtu: 1400 recvaddr: 127.0.0.1:4001 sendaddr: 127.0.0.1:5001 - humanfriendly: true + devfriendly: true nodeid: 1 nodename: Node01 privkey: aABzjKhWdkFfQ29ZuijtMp1h1TNJe66SDCwvfmvQznw= diff --git a/example_config/p2p_mode/n2.yaml b/example_config/p2p_mode/n2.yaml index f08c80e..d017b4e 100644 --- a/example_config/p2p_mode/n2.yaml +++ b/example_config/p2p_mode/n2.yaml @@ -6,7 +6,7 @@ interface: mtu: 1400 recvaddr: 127.0.0.1:4002 sendaddr: 127.0.0.1:5002 - humanfriendly: true + devfriendly: true nodeid: 2 nodename: Node02 privkey: UNZMzPX5fG/8yGC8edVj/ksF9N6ARRqdq7fqE/PD7ls= diff --git a/example_config/p2p_mode/n3.yaml b/example_config/p2p_mode/n3.yaml index 869ac9b..646d308 100644 --- a/example_config/p2p_mode/n3.yaml +++ b/example_config/p2p_mode/n3.yaml @@ -6,7 +6,7 @@ interface: mtu: 1400 recvaddr: 127.0.0.1:4003 sendaddr: 127.0.0.1:5003 - humanfriendly: true + devfriendly: true nodeid: 3 nodename: Node03 privkey: gJy35nbsd8FuuxyWHjsefN+U+oM7RkuIB1EanNLSVHg= diff --git a/example_config/p2p_mode/n4.yaml b/example_config/p2p_mode/n4.yaml index 41df1ba..1290614 100644 --- a/example_config/p2p_mode/n4.yaml +++ b/example_config/p2p_mode/n4.yaml @@ -6,7 +6,7 @@ interface: mtu: 1400 recvaddr: 127.0.0.1:4004 sendaddr: 127.0.0.1:5004 - humanfriendly: true + devfriendly: true nodeid: 4 nodename: Node04 privkey: wAdLgCk0SHiO11/aUf9944focD1BUCH5b6Pe+cRHHXQ= diff --git a/example_config/p2p_mode/n5.yaml b/example_config/p2p_mode/n5.yaml index 26aacf6..cbb2fa8 100644 --- a/example_config/p2p_mode/n5.yaml +++ b/example_config/p2p_mode/n5.yaml @@ -6,7 +6,7 @@ interface: mtu: 1400 recvaddr: 127.0.0.1:4005 sendaddr: 127.0.0.1:5005 - humanfriendly: true + devfriendly: true nodeid: 5 nodename: Node05 privkey: gLmzeCbmN/hjiE+ehNXL9IxuG9hhWIYv2s16/DOW6FE= diff --git a/example_config/p2p_mode/n6.yaml b/example_config/p2p_mode/n6.yaml index daf6f9a..fb36bbe 100644 --- a/example_config/p2p_mode/n6.yaml +++ b/example_config/p2p_mode/n6.yaml @@ -6,7 +6,7 @@ interface: mtu: 1400 recvaddr: 127.0.0.1:4006 sendaddr: 127.0.0.1:5006 - humanfriendly: true + devfriendly: true nodeid: 6 nodename: Node06 privkey: IIX5F6oWZUS2dlhxWFJ7TxdJtDCr5jzeuhxUB6YM7Us= diff --git a/example_config/static_mode/n1.yaml b/example_config/static_mode/n1.yaml index fd86ecc..5efe3a4 100644 --- a/example_config/static_mode/n1.yaml +++ b/example_config/static_mode/n1.yaml @@ -6,7 +6,7 @@ interface: mtu: 1400 recvaddr: 127.0.0.1:4001 sendaddr: 127.0.0.1:5001 - humanfriendly: true + devfriendly: true nodeid: 1 nodename: Node01 privkey: aABzjKhWdkFfQ29ZuijtMp1h1TNJe66SDCwvfmvQznw= diff --git a/example_config/static_mode/n2.yaml b/example_config/static_mode/n2.yaml index e5dbcc0..c88b4b8 100644 --- a/example_config/static_mode/n2.yaml +++ b/example_config/static_mode/n2.yaml @@ -6,7 +6,7 @@ interface: mtu: 1400 recvaddr: 127.0.0.1:4002 sendaddr: 127.0.0.1:5002 - humanfriendly: true + devfriendly: true nodeid: 2 nodename: Node02 privkey: UNZMzPX5fG/8yGC8edVj/ksF9N6ARRqdq7fqE/PD7ls= diff --git a/example_config/static_mode/n3.yaml b/example_config/static_mode/n3.yaml index 19d8274..1563c37 100644 --- a/example_config/static_mode/n3.yaml +++ b/example_config/static_mode/n3.yaml @@ -6,7 +6,7 @@ interface: mtu: 1400 recvaddr: 127.0.0.1:4003 sendaddr: 127.0.0.1:5003 - humanfriendly: true + devfriendly: true nodeid: 3 nodename: Node03 privkey: gJy35nbsd8FuuxyWHjsefN+U+oM7RkuIB1EanNLSVHg= diff --git a/example_config/static_mode/n4.yaml b/example_config/static_mode/n4.yaml index 6710b57..1f458ff 100644 --- a/example_config/static_mode/n4.yaml +++ b/example_config/static_mode/n4.yaml @@ -6,7 +6,7 @@ interface: mtu: 1400 recvaddr: 127.0.0.1:4004 sendaddr: 127.0.0.1:5004 - humanfriendly: true + devfriendly: true nodeid: 4 nodename: Node04 privkey: wAdLgCk0SHiO11/aUf9944focD1BUCH5b6Pe+cRHHXQ= diff --git a/example_config/static_mode/n5.yaml b/example_config/static_mode/n5.yaml index 7154ef9..7dff132 100644 --- a/example_config/static_mode/n5.yaml +++ b/example_config/static_mode/n5.yaml @@ -6,7 +6,7 @@ interface: mtu: 1400 recvaddr: 127.0.0.1:4005 sendaddr: 127.0.0.1:5005 - humanfriendly: true + devfriendly: true nodeid: 5 nodename: Node05 privkey: gLmzeCbmN/hjiE+ehNXL9IxuG9hhWIYv2s16/DOW6FE= diff --git a/example_config/static_mode/n6.yaml b/example_config/static_mode/n6.yaml index 6b3fcdb..aa3b3bf 100644 --- a/example_config/static_mode/n6.yaml +++ b/example_config/static_mode/n6.yaml @@ -6,7 +6,7 @@ interface: mtu: 1400 recvaddr: 127.0.0.1:4006 sendaddr: 127.0.0.1:5006 - humanfriendly: true + devfriendly: true nodeid: 6 nodename: Node06 privkey: IIX5F6oWZUS2dlhxWFJ7TxdJtDCr5jzeuhxUB6YM7Us= diff --git a/example_config/super_mode/n1.yaml b/example_config/super_mode/n1.yaml index f4a704f..940c940 100644 --- a/example_config/super_mode/n1.yaml +++ b/example_config/super_mode/n1.yaml @@ -6,7 +6,7 @@ interface: mtu: 1400 recvaddr: 127.0.0.1:4001 sendaddr: 127.0.0.1:5001 - humanfriendly: true + devfriendly: true nodeid: 1 nodename: Node01 privkey: 6GyDagZKhbm5WNqMiRHhkf43RlbMJ34IieTlIuvfJ1M= diff --git a/example_config/super_mode/n2.yaml b/example_config/super_mode/n2.yaml index 2993271..e810a26 100644 --- a/example_config/super_mode/n2.yaml +++ b/example_config/super_mode/n2.yaml @@ -6,7 +6,7 @@ interface: mtu: 1400 recvaddr: 127.0.0.1:4002 sendaddr: 127.0.0.1:5002 - humanfriendly: true + devfriendly: true nodeid: 2 nodename: Node02 privkey: OH8BsVUU2Rqzeu9B2J5GPG8PUmxWfX8uVvNFZKhVF3o= diff --git a/go.mod b/go.mod index 9af1242..ce0b457 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,10 @@ module github.com/KusakabeSi/EtherGuardVPN go 1.16 require ( + git.fd.io/govpp.git v0.3.6-0.20210810100027-c0da1f2999a6 + git.fd.io/govpp.git/extras v0.0.0-20210810100027-c0da1f2999a6 github.com/KusakabeSi/go-cache v0.0.0-20210823132304-22b5b1d22b41 + github.com/sirupsen/logrus v1.8.1 golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2 golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57 gopkg.in/yaml.v2 v2.4.0 diff --git a/main_edge.go b/main_edge.go index 8976e44..e1e65e4 100644 --- a/main_edge.go +++ b/main_edge.go @@ -29,13 +29,13 @@ func printExampleEdgeConf() { tconfig := config.EdgeConfig{ Interface: config.InterfaceConf{ Itype: "stdio", - IfaceID: 5, + VPPIfaceID: 5, Name: "tap1", MacAddr: "AA:BB:CC:DD:EE:FF", MTU: 1400, RecvAddr: "127.0.0.1:4001", SendAddr: "127.0.0.1:5001", - HumanFriendly: true, + DevFriendly: true, }, NodeID: 1, NodeName: "Node01", @@ -165,12 +165,12 @@ func Edge(configPath string, useUAPI bool, printExample bool) (err error) { case "dummy": thetap, err = tap.CreateDummyTAP() case "stdio": - thetap, err = tap.CreateStdIOTAP(tconfig.Interface.Name, tconfig.Interface.HumanFriendly) + thetap, err = tap.CreateStdIOTAP(tconfig.Interface.Name, tconfig.Interface.DevFriendly) case "udpsock": { lis, _ := net.ResolveUDPAddr("udp", tconfig.Interface.RecvAddr) sen, _ := net.ResolveUDPAddr("udp", tconfig.Interface.SendAddr) - thetap, err = tap.CreateUDPSockTAP(tconfig.Interface.Name, lis, sen, tconfig.Interface.HumanFriendly) + thetap, err = tap.CreateUDPSockTAP(tconfig.Interface.Name, lis, sen, tconfig.Interface.DevFriendly) } } if err != nil { diff --git a/main_httpserver.go b/main_httpserver.go index 32147b5..fc3500b 100644 --- a/main_httpserver.go +++ b/main_httpserver.go @@ -1,6 +1,7 @@ package main import ( + "bytes" "net" "strconv" @@ -15,6 +16,7 @@ var ( http_graph *path.IG http_device4 *device.Device http_device6 *device.Device + http_HashSalt []byte http_NhTable_Hash [32]byte http_PeerInfo_hash [32]byte http_NhTableStr []byte @@ -40,24 +42,58 @@ type client struct { func get_peerinfo(w http.ResponseWriter, r *http.Request) { params := r.URL.Query() - PubKey, _ := params["PubKey"] - State, _ := params["State"] - if state := http_PeerState[PubKey[0]]; state != nil { - copy(http_PeerState[PubKey[0]].PeerInfoState[:], State[0]) + PubKeyA, has := params["PubKey"] + if !has { + w.WriteHeader(http.StatusNotFound) + w.Write([]byte("Not found")) + return } - w.WriteHeader(http.StatusOK) - w.Write([]byte(http_PeerInfoStr)) + StateA, has := params["State"] + if !has { + w.WriteHeader(http.StatusNotFound) + w.Write([]byte("Not found")) + return + } + PubKey := PubKeyA[0] + State := StateA[0] + if bytes.Equal(http_PeerInfo_hash[:], []byte(State)) { + if state := http_PeerState[PubKey]; state != nil { + copy(http_PeerState[PubKey].PeerInfoState[:], State) + w.WriteHeader(http.StatusOK) + w.Write([]byte(http_PeerInfoStr)) + return + } + } + w.WriteHeader(http.StatusNotFound) + w.Write([]byte("Not found")) } func get_nhtable(w http.ResponseWriter, r *http.Request) { params := r.URL.Query() - PubKey, _ := params["PubKey"] - State, _ := params["State"] - if state := http_PeerState[PubKey[0]]; state != nil { - copy(http_PeerState[PubKey[0]].NhTableState[:], State[0]) + PubKeyA, has := params["PubKey"] + if !has { + w.WriteHeader(http.StatusNotFound) + w.Write([]byte("Not found")) + return } - w.WriteHeader(http.StatusOK) - w.Write([]byte(http_NhTableStr)) + StateA, has := params["State"] + if !has { + w.WriteHeader(http.StatusNotFound) + w.Write([]byte("Not found")) + return + } + PubKey := PubKeyA[0] + State := StateA[0] + if bytes.Equal(http_NhTable_Hash[:], []byte(State)) { + if state := http_PeerState[PubKey]; state != nil { + copy(http_PeerState[PubKey].NhTableState[:], State) + w.WriteHeader(http.StatusOK) + w.Write([]byte(http_NhTableStr)) + return + } + } + w.WriteHeader(http.StatusNotFound) + w.Write([]byte("Not found")) } func HttpServer(http_port int, apiprefix string) { diff --git a/main_super.go b/main_super.go index 04f7dbd..c1af782 100644 --- a/main_super.go +++ b/main_super.go @@ -97,6 +97,7 @@ func Super(configPath string, useUAPI bool, printExample bool) (err error) { http_PeerState = make(map[string]*PeerState) http_PeerID2Map = make(map[config.Vertex]string) http_PeerInfos.Peers = make(map[string]config.HTTP_Peerinfo) + http_HashSalt = []byte(config.RandomStr(32, "Salt generate failed")) super_chains := path.SUPER_Events{ Event_server_pong: make(chan path.PongMsg, 1<<5), @@ -193,10 +194,8 @@ func Event_server_event_hendler(graph *path.IG, events path.SUPER_Events) { for { select { case reg_msg := <-events.Event_server_register: - if reg_msg.Init == true { - copy(http_PeerState[http_PeerID2Map[reg_msg.Node_id]].NhTableState[:], make([]byte, 32)) - copy(http_PeerState[http_PeerID2Map[reg_msg.Node_id]].PeerInfoState[:], make([]byte, 32)) - } + copy(http_PeerState[http_PeerID2Map[reg_msg.Node_id]].NhTableState[:], reg_msg.NhStateHash[:]) + copy(http_PeerState[http_PeerID2Map[reg_msg.Node_id]].PeerInfoState[:], reg_msg.PeerStateHash[:]) PubKey := http_PeerID2Map[reg_msg.Node_id] if peer := http_device4.LookupPeerByStr(PubKey); peer != nil { if connstr := peer.GetEndpointDstStr(); connstr != "" { @@ -209,7 +208,7 @@ func Event_server_event_hendler(graph *path.IG, events path.SUPER_Events) { } } http_PeerInfoStr, _ = json.Marshal(&http_PeerInfos) - PeerInfo_hash_raw := md5.Sum(http_PeerInfoStr) + PeerInfo_hash_raw := md5.Sum(append(http_PeerInfoStr, http_HashSalt...)) PeerInfo_hash_str := hex.EncodeToString(PeerInfo_hash_raw[:]) PeerInfo_hash_str_byte := []byte(PeerInfo_hash_str) if bytes.Equal(http_PeerInfo_hash[:], PeerInfo_hash_str_byte) == false { @@ -230,7 +229,7 @@ func Event_server_event_hendler(graph *path.IG, events path.SUPER_Events) { if changed { NhTable := graph.GetNHTable(false) NhTablestr, _ := json.Marshal(NhTable) - md5_hash_raw := md5.Sum(http_NhTableStr) + md5_hash_raw := md5.Sum(append(http_NhTableStr, http_HashSalt...)) new_hash_str := hex.EncodeToString(md5_hash_raw[:]) new_hash_str_byte := []byte(new_hash_str) copy(http_NhTable_Hash[:], new_hash_str_byte) diff --git a/path/metamessage.go b/path/metamessage.go index 35dd1d4..2e21525 100644 --- a/path/metamessage.go +++ b/path/metamessage.go @@ -21,7 +21,8 @@ func GetByte(structIn interface{}) (bb []byte, err error) { type RegisterMsg struct { Node_id config.Vertex `struc:"uint32"` - Init bool + PeerStateHash [32]byte + NhStateHash [32]byte } func (c *RegisterMsg) ToString() string { diff --git a/tap/tap.go b/tap/tap.go index 45fcc68..288cafe 100644 --- a/tap/tap.go +++ b/tap/tap.go @@ -7,7 +7,6 @@ package tap import ( "bytes" - "os" ) type Event int @@ -39,7 +38,6 @@ const ( ) type Device interface { - File() *os.File // returns the file descriptor of the device Read([]byte, int) (int, error) // read a packet from the device (without any additional headers) Write([]byte, int) (int, error) // writes a packet to the device (without any additional headers) Flush() error // flush all previous writes to the device diff --git a/tap/tap_dummy.go b/tap/tap_dummy.go index 7cfa0fb..cdb53c3 100644 --- a/tap/tap_dummy.go +++ b/tap/tap_dummy.go @@ -1,9 +1,5 @@ package tap -import ( - "os" -) - type DummyTap struct { stopRead chan struct{} events chan Event @@ -23,10 +19,6 @@ func CreateDummyTAP() (tapdev Device, err error) { // SetMTU sets the Maximum Tansmission Unit Size for a // Packet on the interface. -func (tap *DummyTap) File() *os.File { - var tapFile *os.File - return tapFile -} // returns the file descriptor of the device func (tap *DummyTap) Read([]byte, int) (int, error) { _ = <-tap.stopRead return 0, nil diff --git a/tap/tap_stdio.go b/tap/tap_stdio.go index 7f71590..81caeb8 100644 --- a/tap/tap_stdio.go +++ b/tap/tap_stdio.go @@ -47,10 +47,6 @@ func CreateStdIOTAP(interfaceName string, HumanFriendly bool) (tapdev Device, er // SetMTU sets the Maximum Tansmission Unit Size for a // Packet on the interface. -func (tap *StdIOTap) File() *os.File { - var tapFile *os.File - return tapFile -} // returns the file descriptor of the device func (tap *StdIOTap) Read(buf []byte, offset int) (int, error) { if tap.HumanFriendly { size, err := os.Stdin.Read(buf[offset+10:]) diff --git a/tap/tap_udpsock.go b/tap/tap_udpsock.go index bd4056e..c2f8f6d 100644 --- a/tap/tap_udpsock.go +++ b/tap/tap_udpsock.go @@ -3,7 +3,6 @@ package tap import ( "fmt" "net" - "os" ) type UdpSockTap struct { @@ -38,11 +37,6 @@ func CreateUDPSockTAP(interfaceName string, listenAddr *net.UDPAddr, sendAddr *n // SetMTU sets the Maximum Tansmission Unit Size for a // Packet on the interface. - -func (tap *UdpSockTap) File() *os.File { - var tapFile *os.File - return tapFile -} // returns the file descriptor of the device func (tap *UdpSockTap) Read(buf []byte, offset int) (int, error) { if tap.HumanFriendly { size, _, err := tap.recv.ReadFromUDP(buf[offset+10:]) diff --git a/tap/tap_vpp.go b/tap/tap_vpp.go new file mode 100644 index 0000000..0eb5d8b --- /dev/null +++ b/tap/tap_vpp.go @@ -0,0 +1,352 @@ +package tap + +import ( + "context" + + "errors" + "fmt" + "log" + "os" + "sync" + + "git.fd.io/govpp.git" + "git.fd.io/govpp.git/adapter/socketclient" + "git.fd.io/govpp.git/binapi/ethernet_types" + interfaces "git.fd.io/govpp.git/binapi/interface" + "git.fd.io/govpp.git/binapi/interface_types" + "git.fd.io/govpp.git/binapi/l2" + "git.fd.io/govpp.git/binapi/memif" + "git.fd.io/govpp.git/extras/libmemif" + + "github.com/KusakabeSi/EtherGuardVPN/config" + logger "github.com/sirupsen/logrus" +) + +const ( + ENV_VPP_MEMIF_SOCKET_DIR = "VPP_MEMIF_SOCKET_DIR" + ENV_VPP_SOCKET_PATH = "VPP_API_SOCKET_PATH" +) + +var ( + //read from env + vppMemifSocketDir = "/var/run/eggo-vpp" + vppApiSocketPath = socketclient.DefaultSocketName // Path to VPP binary API socket file, default is /run/vpp/api. + + //internal + NumQueues = uint8(1) + onConnectWg sync.WaitGroup + tunErrorChannel chan error +) + +type VppTap struct { + name string + mtu int + ifuid uint32 + memifSockPath string + SwIfIndex interface_types.InterfaceIndex + secret string + memif *libmemif.Memif + RxQueues int + RxintCh <-chan uint8 + RxintChNext chan uint8 + RxintErrCh <-chan error + TxQueues int + TxCount uint + logger *logger.Logger + errors chan error // async error handling + events chan Event +} + +// New creates and returns a new TUN interface for the application. +func CreateVppTAP(interfaceName string, iconfig config.InterfaceConf, loglevel string) (tapdev Device, err error) { + // Setup TUN Config + // Set logger + log := logger.New() + log.Out = os.Stdout + log.Level = func() logger.Level { + switch loglevel { + case "verbose", "debug": + return logger.DebugLevel + case "error": + return logger.ErrorLevel + case "silent": + return logger.PanicLevel + } + return logger.ErrorLevel + }() + libmemif.SetLogger(log) + // connect to VPP + conn, err := govpp.Connect(vppApiSocketPath) + if err != nil { + log.Fatalln("ERROR: connecting to VPP failed:", err) + return nil, err + } + defer conn.Disconnect() + + // create a channel + ch, err := conn.NewAPIChannel() + if err != nil { + log.Fatalln("ERROR: creating channel failed:", err) + return nil, err + } + defer ch.Close() + + if err := ch.CheckCompatiblity(&memif.MemifSocketFilenameAddDel{}, &memif.MemifCreate{}, &memif.MemifDelete{}); err != nil { + return nil, err + } + if err := ch.CheckCompatiblity(&interfaces.SwInterfaceSetFlags{}, &interfaces.SwInterfaceSetMtu{}); err != nil { + return nil, err + } + if err := ch.CheckCompatiblity(&l2.L2fibAddDel{}, &l2.SwInterfaceSetL2Bridge{}); err != nil { + return nil, err + } + + memifservice := memif.NewServiceClient(conn) + l2service := l2.NewServiceClient(conn) + interfacservice := interfaces.NewServiceClient(conn) + + vppIfMacAddr, err := ethernet_types.ParseMacAddress(iconfig.MacAddr) + if err != nil { + log.Fatalln("ERROR: Failed parse mac address:", iconfig.MacAddr) + return nil, err + } + + tap := &VppTap{ + name: iconfig.Name, + mtu: iconfig.MTU, + ifuid: iconfig.VPPIfaceID, + SwIfIndex: 0, + memifSockPath: vppMemifSocketDir + "/" + iconfig.Name, + secret: config.RandomStr(16, iconfig.Name), + logger: log, + errors: make(chan error, 1<<5), + events: make(chan Event, 1<<4), + } + // create memif socket id 1 filename /tmp/icmp-responder-example + + _, err = memifservice.MemifSocketFilenameAddDel(context.Background(), &memif.MemifSocketFilenameAddDel{ + IsAdd: true, + SocketID: iconfig.VPPIfaceID, + SocketFilename: tap.memifSockPath, + }) + if err != nil { + return nil, err + } + + // create interface memif id 1 socket-id 1 slave secret secret no-zero-copy + + memifCreateReply, err := memifservice.MemifCreate(context.Background(), &memif.MemifCreate{ + Role: memif.MEMIF_ROLE_API_SLAVE, + Mode: memif.MEMIF_MODE_API_ETHERNET, + RxQueues: NumQueues, // MEMIF_DEFAULT_RX_QUEUES + TxQueues: NumQueues, // MEMIF_DEFAULT_TX_QUEUES + ID: tap.ifuid, + SocketID: tap.ifuid, + RingSize: 1024, // MEMIF_DEFAULT_RING_SIZE + BufferSize: 2048, // MEMIF_DEFAULT_BUFFER_SIZE 2048 + NoZeroCopy: true, + HwAddr: vppIfMacAddr, + Secret: tap.secret, + }) + if err != nil { + return nil, err + } + + tap.SwIfIndex = memifCreateReply.SwIfIndex + + // set int state memif1/1 up + + _, err = interfacservice.SwInterfaceSetFlags(context.Background(), &interfaces.SwInterfaceSetFlags{ + SwIfIndex: tap.SwIfIndex, + Flags: interface_types.IF_STATUS_API_FLAG_ADMIN_UP, + }) + if err != nil { + return nil, err + } + + //set interface l2 bridge memif1/1 4242 + _, err = l2service.SwInterfaceSetL2Bridge(context.Background(), &l2.SwInterfaceSetL2Bridge{ + RxSwIfIndex: tap.SwIfIndex, + BdID: iconfig.VPPBridgeID, + PortType: l2.L2_API_PORT_TYPE_NORMAL, + Shg: 0, + Enable: true, + }) + if err != nil { + return nil, err + } + //init libmemif + libmemif.Init(tap.name) + onConnectWg.Add(1) + memifCallbacks := &libmemif.MemifCallbacks{ + OnConnect: OnConnect, + OnDisconnect: OnDisconnect, + } + // Prepare memif1 configuration. + memifConfig := &libmemif.MemifConfig{ + MemifMeta: libmemif.MemifMeta{ + IfName: tap.name, + ConnID: tap.ifuid, + SocketFilename: tap.memifSockPath, + Secret: tap.secret, + IsMaster: true, + Mode: libmemif.IfModeEthernet, + }, + MemifShmSpecs: libmemif.MemifShmSpecs{ + NumRxQueues: NumQueues, + NumTxQueues: NumQueues, + BufferSize: 2048, + Log2RingSize: 10, + }, + } + // Create memif1 interface. + memif, err := libmemif.CreateInterface(memifConfig, memifCallbacks) + if err != nil { + tap.logger.Errorf("libmemif.CreateInterface() error: %v\n", err) + return nil, err + } + onConnectWg.Wait() + _, err = interfacservice.SwInterfaceSetMtu(context.Background(), &interfaces.SwInterfaceSetMtu{ + SwIfIndex: tap.SwIfIndex, + Mtu: []uint32{uint32(tap.mtu)}, + }) + if err != nil { + return nil, err + } + tap.memif = memif + details, err := memif.GetDetails() + tap.RxQueues = len(details.RxQueues) + tap.RxintCh = memif.GetInterruptChan() + tap.RxintErrCh = memif.GetInterruptErrorChan() + tap.TxQueues = len(details.TxQueues) + tapdev.Events() <- EventUp + return +} + +// SetMTU sets the Maximum Tansmission Unit Size for a +// Packet on the interface. + +func (tap *VppTap) Read(buf []byte, offset int) (n int, err error) { + select { + case err = <-tap.RxintErrCh: + tap.logger.Errorf("libmemif.Memif.RxintErr() error: %v\n", err) + return 0, err + case err = <-tap.errors: + if err == nil { + err = errors.New("Device closed") + } + tap.logger.Errorf("tun error: %v\n", err) + return 0, err + case queueID := <-tap.RxintCh: + select { + case tap.RxintChNext <- queueID: + { + // Use non-blocking write to prevent program stuck + } + default: + tap.logger.Debugln("Buffer full") + } + + case queueID := <-tap.RxintChNext: + packets, err := tap.memif.RxBurst(queueID, 1) + if err != nil { + tap.logger.Errorf("libmemif.Memif.RxBurst() error: %v\n", err) + return 0, err + } + if len(packets) == 0 { + // No more packets to read until the next interrupt. + return 0, nil + } + for _, packetData := range packets { + select { + case tap.RxintChNext <- queueID: + { + // Use non-blocking write to prevent program stuck + // repeatedly call RxBurst() until returns an empty slice of packets + } + default: + tap.logger.Debugln("Buffer full") + } + n = copy(buf[offset:], packetData) + } + } + return +} // read a packet from the device (without any additional headers) +func (tap *VppTap) Write(buf []byte, offset int) (size int, err error) { + queueID := tap.getTxQueueID() + buf = buf[offset:] + n, err := tap.memif.TxBurst(queueID, []libmemif.RawPacketData{buf}) + return len(buf) * int(n), err +} // writes a packet to the device (without any additional headers) +func (tap *VppTap) Flush() error { + return nil +} // flush all previous writes to the device +func (tap *VppTap) MTU() (int, error) { + return tap.mtu, nil +} // returns the MTU of the device +func (tap *VppTap) Name() (string, error) { + return tap.name, nil +} // fetches and returns the current name +func (tap *VppTap) Events() chan Event { + return tap.events +} // returns a constant channel of events related to the device +func (tap *VppTap) Close() error { + // connect to VPP + conn, err := govpp.Connect(vppApiSocketPath) + if err != nil { + log.Fatalln("ERROR: connecting to VPP failed:", err) + } + defer conn.Disconnect() + + // create a channel + ch, err := conn.NewAPIChannel() + if err != nil { + log.Fatalln("ERROR: creating channel failed:", err) + } + defer ch.Close() + + memifservice := memif.NewServiceClient(conn) + + tap.memif.Close() + libmemif.Cleanup() + // delete interface memif memif1/1 + _, err = memifservice.MemifDelete(context.Background(), &memif.MemifDelete{ + SwIfIndex: tap.SwIfIndex, + }) + // delete memif socket id 1 + _, err = memifservice.MemifSocketFilenameAddDel(context.Background(), &memif.MemifSocketFilenameAddDel{ + IsAdd: false, + SocketID: tap.ifuid, + SocketFilename: tap.memifSockPath, + }) + tap.events <- EventDown + close(tap.events) + return nil +} // stops the device and closes the event channel + +// OnConnect is called when a memif connection gets established. +func OnConnect(memif *libmemif.Memif) (err error) { + details, err := memif.GetDetails() + if err != nil { + fmt.Printf("libmemif.GetDetails() error: %v\n", err) + } + fmt.Printf("memif %s has been connected: %+v\n", memif.IfName, details) + + onConnectWg.Done() + + return nil +} + +// OnDisconnect is called when a memif connection is lost. +func OnDisconnect(memif *libmemif.Memif) (err error) { + tunErrorChannel <- errors.New(fmt.Sprintf("memif %s has been disconnected", memif.IfName)) + return nil +} + +func (tun *VppTap) getTxQueueID() uint8 { + if tun.TxQueues == 1 { + return 0 + } + tun.TxCount++ + return uint8(tun.TxCount % uint(tun.TxQueues)) +}