VPPTap, not test yet

This commit is contained in:
KusakabeSi
2021-08-23 19:11:01 +00:00
parent 2beb19c224
commit 26ba4dbe94
28 changed files with 521 additions and 187 deletions

View File

@@ -1,77 +1,9 @@
# Go Implementation of [WireGuard](https://www.wireguard.com/) ### Build
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:
``` ```
$ wireguard-go wg0 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
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. 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"
To run wireguard-go without forking to the background, pass `-f` or `--foreground`: make
```
```
$ 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.

View File

@@ -1,5 +1,9 @@
package config package config
import (
"crypto/rand"
)
type EdgeConfig struct { type EdgeConfig struct {
Interface InterfaceConf Interface InterfaceConf
NodeID Vertex NodeID Vertex
@@ -24,14 +28,15 @@ type SuperConfig struct {
} }
type InterfaceConf struct { type InterfaceConf struct {
Itype string Itype string
IfaceID int Name string
Name string VPPIfaceID uint32
MacAddr string VPPBridgeID uint32
MTU int MacAddr string
RecvAddr string MTU int
SendAddr string RecvAddr string
HumanFriendly bool SendAddr string
DevFriendly bool
} }
type PeerInfo struct { type PeerInfo struct {
@@ -103,3 +108,19 @@ type HTTP_Peerinfo struct {
type HTTP_Peers struct { type HTTP_Peers struct {
Peers map[string]HTTP_Peerinfo 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)
}

View File

@@ -6,10 +6,12 @@
package device package device
import ( import (
"bytes"
"container/list" "container/list"
"encoding/base64" "encoding/base64"
"errors" "errors"
"fmt" "fmt"
"io/ioutil"
"strconv" "strconv"
"sync" "sync"
"sync/atomic" "sync/atomic"
@@ -18,6 +20,7 @@ import (
"github.com/KusakabeSi/EtherGuardVPN/config" "github.com/KusakabeSi/EtherGuardVPN/config"
"github.com/KusakabeSi/EtherGuardVPN/conn" "github.com/KusakabeSi/EtherGuardVPN/conn"
"github.com/KusakabeSi/EtherGuardVPN/path" "github.com/KusakabeSi/EtherGuardVPN/path"
"gopkg.in/yaml.v2"
) )
type Peer struct { type Peer struct {
@@ -304,7 +307,7 @@ func (peer *Peer) SetEndpointFromPacket(endpoint conn.Endpoint) {
return return
} }
peer.Lock() peer.Lock()
peer.device.SaveToConfig(peer, endpoint.DstToString()) peer.device.SaveToConfig(peer, endpoint)
peer.endpoint = endpoint peer.endpoint = endpoint
peer.Unlock() peer.Unlock()
} }
@@ -322,3 +325,52 @@ func (peer *Peer) GetEndpointDstStr() string {
} }
return peer.endpoint.DstToString() 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)
}
}

View File

@@ -14,7 +14,6 @@ import (
"github.com/KusakabeSi/EtherGuardVPN/config" "github.com/KusakabeSi/EtherGuardVPN/config"
"github.com/KusakabeSi/EtherGuardVPN/path" "github.com/KusakabeSi/EtherGuardVPN/path"
"gopkg.in/yaml.v2"
) )
func (device *Device) SendPacket(peer *Peer, packet []byte, offset int) { 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() { func (device *Device) RoutineSendPing() {
if !(device.DRoute.P2P.UseP2P || device.DRoute.SuperNode.UseSuperNode) { if !(device.DRoute.P2P.UseP2P || device.DRoute.SuperNode.UseSuperNode) {
return return
@@ -430,11 +389,11 @@ func (device *Device) RoutineRegister() {
if !(device.DRoute.SuperNode.UseSuperNode) { if !(device.DRoute.SuperNode.UseSuperNode) {
return return
} }
first := true
for { for {
body, _ := path.GetByte(path.RegisterMsg{ body, _ := path.GetByte(path.RegisterMsg{
Node_id: device.ID, Node_id: device.ID,
Init: first, PeerStateHash: device.peers.Peer_state,
NhStateHash: device.graph.NhTableHash,
}) })
buf := make([]byte, path.EgHeaderLen+len(body)) buf := make([]byte, path.EgHeaderLen+len(body))
header, _ := path.NewEgHeader(buf[0:path.EgHeaderLen]) header, _ := path.NewEgHeader(buf[0:path.EgHeaderLen])
@@ -446,7 +405,6 @@ func (device *Device) RoutineRegister() {
copy(buf[path.EgHeaderLen:], body) copy(buf[path.EgHeaderLen:], body)
device.Send2Super(buf, MessageTransportOffsetContent) device.Send2Super(buf, MessageTransportOffsetContent)
time.Sleep(path.S2TD(device.DRoute.SendPingInterval)) time.Sleep(path.S2TD(device.DRoute.SendPingInterval))
first = false
} }
} }

View File

@@ -6,7 +6,7 @@ interface:
mtu: 1400 mtu: 1400
recvaddr: 127.0.0.1:4001 recvaddr: 127.0.0.1:4001
sendaddr: 127.0.0.1:5001 sendaddr: 127.0.0.1:5001
humanfriendly: true devfriendly: true
nodeid: 1 nodeid: 1
nodename: Node01 nodename: Node01
privkey: aABzjKhWdkFfQ29ZuijtMp1h1TNJe66SDCwvfmvQznw= privkey: aABzjKhWdkFfQ29ZuijtMp1h1TNJe66SDCwvfmvQznw=

View File

@@ -6,7 +6,7 @@ interface:
mtu: 1400 mtu: 1400
recvaddr: 127.0.0.1:4002 recvaddr: 127.0.0.1:4002
sendaddr: 127.0.0.1:5002 sendaddr: 127.0.0.1:5002
humanfriendly: true devfriendly: true
nodeid: 2 nodeid: 2
nodename: Node02 nodename: Node02
privkey: UNZMzPX5fG/8yGC8edVj/ksF9N6ARRqdq7fqE/PD7ls= privkey: UNZMzPX5fG/8yGC8edVj/ksF9N6ARRqdq7fqE/PD7ls=

View File

@@ -6,7 +6,7 @@ interface:
mtu: 1400 mtu: 1400
recvaddr: 127.0.0.1:4003 recvaddr: 127.0.0.1:4003
sendaddr: 127.0.0.1:5003 sendaddr: 127.0.0.1:5003
humanfriendly: true devfriendly: true
nodeid: 3 nodeid: 3
nodename: Node03 nodename: Node03
privkey: gJy35nbsd8FuuxyWHjsefN+U+oM7RkuIB1EanNLSVHg= privkey: gJy35nbsd8FuuxyWHjsefN+U+oM7RkuIB1EanNLSVHg=

View File

@@ -6,7 +6,7 @@ interface:
mtu: 1400 mtu: 1400
recvaddr: 127.0.0.1:4004 recvaddr: 127.0.0.1:4004
sendaddr: 127.0.0.1:5004 sendaddr: 127.0.0.1:5004
humanfriendly: true devfriendly: true
nodeid: 4 nodeid: 4
nodename: Node04 nodename: Node04
privkey: wAdLgCk0SHiO11/aUf9944focD1BUCH5b6Pe+cRHHXQ= privkey: wAdLgCk0SHiO11/aUf9944focD1BUCH5b6Pe+cRHHXQ=

View File

@@ -6,7 +6,7 @@ interface:
mtu: 1400 mtu: 1400
recvaddr: 127.0.0.1:4005 recvaddr: 127.0.0.1:4005
sendaddr: 127.0.0.1:5005 sendaddr: 127.0.0.1:5005
humanfriendly: true devfriendly: true
nodeid: 5 nodeid: 5
nodename: Node05 nodename: Node05
privkey: gLmzeCbmN/hjiE+ehNXL9IxuG9hhWIYv2s16/DOW6FE= privkey: gLmzeCbmN/hjiE+ehNXL9IxuG9hhWIYv2s16/DOW6FE=

View File

@@ -6,7 +6,7 @@ interface:
mtu: 1400 mtu: 1400
recvaddr: 127.0.0.1:4006 recvaddr: 127.0.0.1:4006
sendaddr: 127.0.0.1:5006 sendaddr: 127.0.0.1:5006
humanfriendly: true devfriendly: true
nodeid: 6 nodeid: 6
nodename: Node06 nodename: Node06
privkey: IIX5F6oWZUS2dlhxWFJ7TxdJtDCr5jzeuhxUB6YM7Us= privkey: IIX5F6oWZUS2dlhxWFJ7TxdJtDCr5jzeuhxUB6YM7Us=

View File

@@ -6,7 +6,7 @@ interface:
mtu: 1400 mtu: 1400
recvaddr: 127.0.0.1:4001 recvaddr: 127.0.0.1:4001
sendaddr: 127.0.0.1:5001 sendaddr: 127.0.0.1:5001
humanfriendly: true devfriendly: true
nodeid: 1 nodeid: 1
nodename: Node01 nodename: Node01
privkey: aABzjKhWdkFfQ29ZuijtMp1h1TNJe66SDCwvfmvQznw= privkey: aABzjKhWdkFfQ29ZuijtMp1h1TNJe66SDCwvfmvQznw=

View File

@@ -6,7 +6,7 @@ interface:
mtu: 1400 mtu: 1400
recvaddr: 127.0.0.1:4002 recvaddr: 127.0.0.1:4002
sendaddr: 127.0.0.1:5002 sendaddr: 127.0.0.1:5002
humanfriendly: true devfriendly: true
nodeid: 2 nodeid: 2
nodename: Node02 nodename: Node02
privkey: UNZMzPX5fG/8yGC8edVj/ksF9N6ARRqdq7fqE/PD7ls= privkey: UNZMzPX5fG/8yGC8edVj/ksF9N6ARRqdq7fqE/PD7ls=

View File

@@ -6,7 +6,7 @@ interface:
mtu: 1400 mtu: 1400
recvaddr: 127.0.0.1:4003 recvaddr: 127.0.0.1:4003
sendaddr: 127.0.0.1:5003 sendaddr: 127.0.0.1:5003
humanfriendly: true devfriendly: true
nodeid: 3 nodeid: 3
nodename: Node03 nodename: Node03
privkey: gJy35nbsd8FuuxyWHjsefN+U+oM7RkuIB1EanNLSVHg= privkey: gJy35nbsd8FuuxyWHjsefN+U+oM7RkuIB1EanNLSVHg=

View File

@@ -6,7 +6,7 @@ interface:
mtu: 1400 mtu: 1400
recvaddr: 127.0.0.1:4004 recvaddr: 127.0.0.1:4004
sendaddr: 127.0.0.1:5004 sendaddr: 127.0.0.1:5004
humanfriendly: true devfriendly: true
nodeid: 4 nodeid: 4
nodename: Node04 nodename: Node04
privkey: wAdLgCk0SHiO11/aUf9944focD1BUCH5b6Pe+cRHHXQ= privkey: wAdLgCk0SHiO11/aUf9944focD1BUCH5b6Pe+cRHHXQ=

View File

@@ -6,7 +6,7 @@ interface:
mtu: 1400 mtu: 1400
recvaddr: 127.0.0.1:4005 recvaddr: 127.0.0.1:4005
sendaddr: 127.0.0.1:5005 sendaddr: 127.0.0.1:5005
humanfriendly: true devfriendly: true
nodeid: 5 nodeid: 5
nodename: Node05 nodename: Node05
privkey: gLmzeCbmN/hjiE+ehNXL9IxuG9hhWIYv2s16/DOW6FE= privkey: gLmzeCbmN/hjiE+ehNXL9IxuG9hhWIYv2s16/DOW6FE=

View File

@@ -6,7 +6,7 @@ interface:
mtu: 1400 mtu: 1400
recvaddr: 127.0.0.1:4006 recvaddr: 127.0.0.1:4006
sendaddr: 127.0.0.1:5006 sendaddr: 127.0.0.1:5006
humanfriendly: true devfriendly: true
nodeid: 6 nodeid: 6
nodename: Node06 nodename: Node06
privkey: IIX5F6oWZUS2dlhxWFJ7TxdJtDCr5jzeuhxUB6YM7Us= privkey: IIX5F6oWZUS2dlhxWFJ7TxdJtDCr5jzeuhxUB6YM7Us=

View File

@@ -6,7 +6,7 @@ interface:
mtu: 1400 mtu: 1400
recvaddr: 127.0.0.1:4001 recvaddr: 127.0.0.1:4001
sendaddr: 127.0.0.1:5001 sendaddr: 127.0.0.1:5001
humanfriendly: true devfriendly: true
nodeid: 1 nodeid: 1
nodename: Node01 nodename: Node01
privkey: 6GyDagZKhbm5WNqMiRHhkf43RlbMJ34IieTlIuvfJ1M= privkey: 6GyDagZKhbm5WNqMiRHhkf43RlbMJ34IieTlIuvfJ1M=

View File

@@ -6,7 +6,7 @@ interface:
mtu: 1400 mtu: 1400
recvaddr: 127.0.0.1:4002 recvaddr: 127.0.0.1:4002
sendaddr: 127.0.0.1:5002 sendaddr: 127.0.0.1:5002
humanfriendly: true devfriendly: true
nodeid: 2 nodeid: 2
nodename: Node02 nodename: Node02
privkey: OH8BsVUU2Rqzeu9B2J5GPG8PUmxWfX8uVvNFZKhVF3o= privkey: OH8BsVUU2Rqzeu9B2J5GPG8PUmxWfX8uVvNFZKhVF3o=

3
go.mod
View File

@@ -3,7 +3,10 @@ module github.com/KusakabeSi/EtherGuardVPN
go 1.16 go 1.16
require ( 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/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/crypto v0.0.0-20210322153248-0c34fe9e7dc2
golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57 golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57
gopkg.in/yaml.v2 v2.4.0 gopkg.in/yaml.v2 v2.4.0

View File

@@ -29,13 +29,13 @@ func printExampleEdgeConf() {
tconfig := config.EdgeConfig{ tconfig := config.EdgeConfig{
Interface: config.InterfaceConf{ Interface: config.InterfaceConf{
Itype: "stdio", Itype: "stdio",
IfaceID: 5, VPPIfaceID: 5,
Name: "tap1", Name: "tap1",
MacAddr: "AA:BB:CC:DD:EE:FF", MacAddr: "AA:BB:CC:DD:EE:FF",
MTU: 1400, MTU: 1400,
RecvAddr: "127.0.0.1:4001", RecvAddr: "127.0.0.1:4001",
SendAddr: "127.0.0.1:5001", SendAddr: "127.0.0.1:5001",
HumanFriendly: true, DevFriendly: true,
}, },
NodeID: 1, NodeID: 1,
NodeName: "Node01", NodeName: "Node01",
@@ -165,12 +165,12 @@ func Edge(configPath string, useUAPI bool, printExample bool) (err error) {
case "dummy": case "dummy":
thetap, err = tap.CreateDummyTAP() thetap, err = tap.CreateDummyTAP()
case "stdio": case "stdio":
thetap, err = tap.CreateStdIOTAP(tconfig.Interface.Name, tconfig.Interface.HumanFriendly) thetap, err = tap.CreateStdIOTAP(tconfig.Interface.Name, tconfig.Interface.DevFriendly)
case "udpsock": case "udpsock":
{ {
lis, _ := net.ResolveUDPAddr("udp", tconfig.Interface.RecvAddr) lis, _ := net.ResolveUDPAddr("udp", tconfig.Interface.RecvAddr)
sen, _ := net.ResolveUDPAddr("udp", tconfig.Interface.SendAddr) 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 { if err != nil {

View File

@@ -1,6 +1,7 @@
package main package main
import ( import (
"bytes"
"net" "net"
"strconv" "strconv"
@@ -15,6 +16,7 @@ var (
http_graph *path.IG http_graph *path.IG
http_device4 *device.Device http_device4 *device.Device
http_device6 *device.Device http_device6 *device.Device
http_HashSalt []byte
http_NhTable_Hash [32]byte http_NhTable_Hash [32]byte
http_PeerInfo_hash [32]byte http_PeerInfo_hash [32]byte
http_NhTableStr []byte http_NhTableStr []byte
@@ -40,24 +42,58 @@ type client struct {
func get_peerinfo(w http.ResponseWriter, r *http.Request) { func get_peerinfo(w http.ResponseWriter, r *http.Request) {
params := r.URL.Query() params := r.URL.Query()
PubKey, _ := params["PubKey"] PubKeyA, has := params["PubKey"]
State, _ := params["State"] if !has {
if state := http_PeerState[PubKey[0]]; state != nil { w.WriteHeader(http.StatusNotFound)
copy(http_PeerState[PubKey[0]].PeerInfoState[:], State[0]) w.Write([]byte("Not found"))
return
} }
w.WriteHeader(http.StatusOK) StateA, has := params["State"]
w.Write([]byte(http_PeerInfoStr)) 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) { func get_nhtable(w http.ResponseWriter, r *http.Request) {
params := r.URL.Query() params := r.URL.Query()
PubKey, _ := params["PubKey"] PubKeyA, has := params["PubKey"]
State, _ := params["State"] if !has {
if state := http_PeerState[PubKey[0]]; state != nil { w.WriteHeader(http.StatusNotFound)
copy(http_PeerState[PubKey[0]].NhTableState[:], State[0]) w.Write([]byte("Not found"))
return
} }
w.WriteHeader(http.StatusOK) StateA, has := params["State"]
w.Write([]byte(http_NhTableStr)) 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) { func HttpServer(http_port int, apiprefix string) {

View File

@@ -97,6 +97,7 @@ func Super(configPath string, useUAPI bool, printExample bool) (err error) {
http_PeerState = make(map[string]*PeerState) http_PeerState = make(map[string]*PeerState)
http_PeerID2Map = make(map[config.Vertex]string) http_PeerID2Map = make(map[config.Vertex]string)
http_PeerInfos.Peers = make(map[string]config.HTTP_Peerinfo) http_PeerInfos.Peers = make(map[string]config.HTTP_Peerinfo)
http_HashSalt = []byte(config.RandomStr(32, "Salt generate failed"))
super_chains := path.SUPER_Events{ super_chains := path.SUPER_Events{
Event_server_pong: make(chan path.PongMsg, 1<<5), 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 { for {
select { select {
case reg_msg := <-events.Event_server_register: case reg_msg := <-events.Event_server_register:
if reg_msg.Init == true { copy(http_PeerState[http_PeerID2Map[reg_msg.Node_id]].NhTableState[:], reg_msg.NhStateHash[:])
copy(http_PeerState[http_PeerID2Map[reg_msg.Node_id]].NhTableState[:], make([]byte, 32)) copy(http_PeerState[http_PeerID2Map[reg_msg.Node_id]].PeerInfoState[:], reg_msg.PeerStateHash[:])
copy(http_PeerState[http_PeerID2Map[reg_msg.Node_id]].PeerInfoState[:], make([]byte, 32))
}
PubKey := http_PeerID2Map[reg_msg.Node_id] PubKey := http_PeerID2Map[reg_msg.Node_id]
if peer := http_device4.LookupPeerByStr(PubKey); peer != nil { if peer := http_device4.LookupPeerByStr(PubKey); peer != nil {
if connstr := peer.GetEndpointDstStr(); connstr != "" { 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) 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 := hex.EncodeToString(PeerInfo_hash_raw[:])
PeerInfo_hash_str_byte := []byte(PeerInfo_hash_str) PeerInfo_hash_str_byte := []byte(PeerInfo_hash_str)
if bytes.Equal(http_PeerInfo_hash[:], PeerInfo_hash_str_byte) == false { 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 { if changed {
NhTable := graph.GetNHTable(false) NhTable := graph.GetNHTable(false)
NhTablestr, _ := json.Marshal(NhTable) 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 := hex.EncodeToString(md5_hash_raw[:])
new_hash_str_byte := []byte(new_hash_str) new_hash_str_byte := []byte(new_hash_str)
copy(http_NhTable_Hash[:], new_hash_str_byte) copy(http_NhTable_Hash[:], new_hash_str_byte)

View File

@@ -21,7 +21,8 @@ func GetByte(structIn interface{}) (bb []byte, err error) {
type RegisterMsg struct { type RegisterMsg struct {
Node_id config.Vertex `struc:"uint32"` Node_id config.Vertex `struc:"uint32"`
Init bool PeerStateHash [32]byte
NhStateHash [32]byte
} }
func (c *RegisterMsg) ToString() string { func (c *RegisterMsg) ToString() string {

View File

@@ -7,7 +7,6 @@ package tap
import ( import (
"bytes" "bytes"
"os"
) )
type Event int type Event int
@@ -39,7 +38,6 @@ const (
) )
type Device interface { 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) 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) Write([]byte, int) (int, error) // writes a packet to the device (without any additional headers)
Flush() error // flush all previous writes to the device Flush() error // flush all previous writes to the device

View File

@@ -1,9 +1,5 @@
package tap package tap
import (
"os"
)
type DummyTap struct { type DummyTap struct {
stopRead chan struct{} stopRead chan struct{}
events chan Event events chan Event
@@ -23,10 +19,6 @@ func CreateDummyTAP() (tapdev Device, err error) {
// SetMTU sets the Maximum Tansmission Unit Size for a // SetMTU sets the Maximum Tansmission Unit Size for a
// Packet on the interface. // 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) { func (tap *DummyTap) Read([]byte, int) (int, error) {
_ = <-tap.stopRead _ = <-tap.stopRead
return 0, nil return 0, nil

View File

@@ -47,10 +47,6 @@ func CreateStdIOTAP(interfaceName string, HumanFriendly bool) (tapdev Device, er
// SetMTU sets the Maximum Tansmission Unit Size for a // SetMTU sets the Maximum Tansmission Unit Size for a
// Packet on the interface. // 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) { func (tap *StdIOTap) Read(buf []byte, offset int) (int, error) {
if tap.HumanFriendly { if tap.HumanFriendly {
size, err := os.Stdin.Read(buf[offset+10:]) size, err := os.Stdin.Read(buf[offset+10:])

View File

@@ -3,7 +3,6 @@ package tap
import ( import (
"fmt" "fmt"
"net" "net"
"os"
) )
type UdpSockTap struct { 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 // SetMTU sets the Maximum Tansmission Unit Size for a
// Packet on the interface. // 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) { func (tap *UdpSockTap) Read(buf []byte, offset int) (int, error) {
if tap.HumanFriendly { if tap.HumanFriendly {
size, _, err := tap.recv.ReadFromUDP(buf[offset+10:]) size, _, err := tap.recv.ReadFromUDP(buf[offset+10:])

352
tap/tap_vpp.go Normal file
View File

@@ -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))
}