LinuxTap, not test yet

This commit is contained in:
KusakabeSi 2021-08-24 08:43:55 +00:00
parent 26ba4dbe94
commit d717d35f64
32 changed files with 988 additions and 208 deletions

3
.vscode/launch.json vendored
View File

@ -10,7 +10,8 @@
"request": "launch",
"mode": "auto",
"program": "${workspaceFolder}",
"args":["-config","example_config/p2p_mode/n1.yaml","-mode","edge"/*,"-example"*/],
"env": {"CGO_CFLAGS":"-I/usr/include/memif"},
"args":["-config","example_config/static_mode/n1.yaml","-mode","edge"/*,"-example"*/],
}
]
}

View File

@ -5,15 +5,16 @@ import (
)
type EdgeConfig struct {
Interface InterfaceConf
NodeID Vertex
NodeName string
PrivKey string
ListenPort int
LogLevel LoggerInfo
DynamicRoute DynamicRouteInfo
NextHopTable NextHopTable
Peers []PeerInfo
Interface InterfaceConf
NodeID Vertex
NodeName string
PrivKey string
ListenPort int
LogLevel LoggerInfo
DynamicRoute DynamicRouteInfo
NextHopTable NextHopTable
ResetConnInterval float64
Peers []PeerInfo
}
type SuperConfig struct {
@ -28,15 +29,15 @@ type SuperConfig struct {
}
type InterfaceConf struct {
Itype string
Name string
VPPIfaceID uint32
VPPBridgeID uint32
MacAddr string
MTU int
RecvAddr string
SendAddr string
DevFriendly bool
Itype string
Name string
VPPIfaceID uint32
VPPBridgeID uint32
MacAddrPrefix string
MTU int
RecvAddr string
SendAddr string
L2HeaderMode string
}
type PeerInfo struct {

View File

@ -7,6 +7,7 @@ package device
import (
"encoding/base64"
"errors"
"runtime"
"sync"
"sync/atomic"
@ -69,9 +70,12 @@ type Device struct {
Peer_state [32]byte
}
event_tryendpoint chan struct{}
ResetConnInterval float64
EdgeConfigPath string
EdgeConfig *config.EdgeConfig
EdgeConfigPath string
EdgeConfig *config.EdgeConfig
SuperConfigPath string
SuperConfig *config.SuperConfig
Event_server_register chan path.RegisterMsg
Event_server_pong chan path.PongMsg
@ -304,7 +308,7 @@ func (device *Device) SetPrivateKey(sk NoisePrivateKey) error {
return nil
}
func NewDevice(tapDevice tap.Device, id config.Vertex, bind conn.Bind, logger *Logger, graph *path.IG, IsSuperNode bool, theconfigpath string, econfig *config.EdgeConfig, sconfig *config.SuperConfig, superevents *path.SUPER_Events) *Device {
func NewDevice(tapDevice tap.Device, id config.Vertex, bind conn.Bind, logger *Logger, graph *path.IG, IsSuperNode bool, configpath string, econfig *config.EdgeConfig, sconfig *config.SuperConfig, superevents *path.SUPER_Events) *Device {
device := new(Device)
device.state.state = uint32(deviceStateDown)
device.closed = make(chan struct{})
@ -333,9 +337,11 @@ func NewDevice(tapDevice tap.Device, id config.Vertex, bind conn.Bind, logger *L
device.Event_server_NhTable_changed = superevents.Event_server_NhTable_changed
device.LogTransit = sconfig.LogLevel.LogTransit
device.LogControl = sconfig.LogLevel.LogControl
device.SuperConfig = sconfig
device.SuperConfigPath = configpath
go device.RoutineRecalculateNhTable()
} else {
device.EdgeConfigPath = theconfigpath
device.EdgeConfigPath = configpath
device.EdgeConfig = econfig
device.DRoute = econfig.DynamicRoute
device.DupData = *fixed_time_cache.NewCache(path.S2TD(econfig.DynamicRoute.DupCheckTimeout), false, path.S2TD(60))
@ -343,11 +349,13 @@ func NewDevice(tapDevice tap.Device, id config.Vertex, bind conn.Bind, logger *L
device.Event_save_config = make(chan struct{}, 1<<5)
device.LogTransit = econfig.LogLevel.LogTransit
device.LogControl = econfig.LogLevel.LogControl
device.ResetConnInterval = device.EdgeConfig.ResetConnInterval
go device.RoutineSetEndpoint()
go device.RoutineRegister()
go device.RoutineSendPing()
go device.RoutineRecalculateNhTable()
go device.RoutineSpreadAllMyNeighbor()
go device.RoutineResetConn()
}
// create queues
@ -374,6 +382,29 @@ func NewDevice(tapDevice tap.Device, id config.Vertex, bind conn.Bind, logger *L
return device
}
func (device *Device) LookupPeerIDAtConfig(pk NoisePublicKey) (ID config.Vertex, err error) {
var peerlist []config.PeerInfo
if device.IsSuperNode {
if device.SuperConfig == nil {
return 0, errors.New("Superconfig is nil")
}
peerlist = device.SuperConfig.Peers
} else {
if device.EdgeConfig == nil {
return 0, errors.New("EdgeConfig is nil")
}
peerlist = device.EdgeConfig.Peers
}
pkstr := PubKey2Str(pk)
for _, peerinfo := range peerlist {
if peerinfo.PubKey == pkstr {
return peerinfo.NodeID, nil
}
}
return 0, errors.New("Peer not found in the config file.")
}
func (device *Device) LookupPeer(pk NoisePublicKey) *Peer {
device.peers.RLock()
defer device.peers.RUnlock()

View File

@ -36,6 +36,8 @@ type Peer struct {
ID config.Vertex
AskedForNeighbor bool
StaticConn bool //if true, this peer will not write to config file when roaming, and the endpoint will be reset periodically
ConnURL string
// These fields are accessed with atomic operations, which must be
// 64-bit aligned even on 32-bit platforms. Go guarantees that an
@ -330,15 +332,16 @@ func (device *Device) SaveToConfig(peer *Peer, endpoint conn.Endpoint) {
if device.IsSuperNode { //Can't in super mode
return
}
if peer.StaticConn == true { //static conn do not write new endpoint to config
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)

View File

@ -548,7 +548,7 @@ func (peer *Peer) RoutineSequentialReceiver() {
goto skip
}
src_macaddr := tap.GetSrcMacAddr(elem.packet[path.EgHeaderLen:])
if !tap.IsBoardCast(src_macaddr) {
if !tap.IsNotUnicast(src_macaddr) {
device.l2fib.Store(src_macaddr, src_nodeID) // Write to l2fib table
}
_, err = device.tap.device.Write(elem.buffer[:MessageTransportOffsetContent+len(elem.packet)], MessageTransportOffsetContent+path.EgHeaderLen)

View File

@ -142,7 +142,7 @@ func (device *Device) process_received(msg_type path.Usage, peer *Peer, body []b
}
case path.BoardcastPeer:
if content, err := path.ParseBoardcastPeerMsg(body); err == nil {
return device.process_BoardcastPeerMsg(content)
return device.process_BoardcastPeerMsg(peer, content)
}
default:
err = errors.New("Not a valid msg_type")
@ -245,7 +245,6 @@ func (device *Device) process_pong(peer *Peer, content path.PongMsg) error {
header.SetPacketLength(uint16(len(body)))
copy(buf[path.EgHeaderLen:], body)
device.SendPacket(peer, buf, MessageTransportOffsetContent)
peer.AskedForNeighbor = true
}
}
return nil
@ -434,12 +433,35 @@ func (device *Device) RoutineSpreadAllMyNeighbor() {
}
for {
device.process_RequestPeerMsg(path.QueryPeerMsg{
Request_ID: 0,
Request_ID: uint32(path.Boardcast),
})
time.Sleep(path.S2TD(device.DRoute.P2P.SendPeerInterval))
}
}
func (device *Device) RoutineResetConn() {
if device.ResetConnInterval <= 0.01 {
return
}
for {
for _, peer := range device.peers.keyMap {
if peer.StaticConn {
continue
}
if peer.ConnURL == "" {
continue
}
endpoint, err := device.Bind().ParseEndpoint(peer.ConnURL)
if err != nil {
device.log.Errorf("Failed to bind "+peer.ConnURL, err)
continue
}
peer.SetEndpointFromPacket(endpoint)
}
time.Sleep(time.Duration(device.ResetConnInterval))
}
}
func (device *Device) GeneratePingPacket(src_nodeID config.Vertex) ([]byte, error) {
body, err := path.GetByte(&path.PingMsg{
Src_nodeID: src_nodeID,
@ -531,9 +553,12 @@ func (device *Device) process_RequestPeerMsg(content path.QueryPeerMsg) error {
return nil
}
func (device *Device) process_BoardcastPeerMsg(content path.BoardcastPeerMsg) error {
func (device *Device) process_BoardcastPeerMsg(peer *Peer, content path.BoardcastPeerMsg) error {
if device.DRoute.P2P.UseP2P {
var sk NoisePublicKey
if content.Request_ID == uint32(device.ID) {
peer.AskedForNeighbor = true
}
if bytes.Equal(content.PubKey[:], device.staticIdentity.publicKey[:]) {
return nil
}

View File

@ -250,7 +250,7 @@ func (device *Device) RoutineReadFromTUN() {
dst_nodeID := EgBody.GetDst()
dstMacAddr := tap.GetDstMacAddr(elem.packet[path.EgHeaderLen:])
// lookup peer
if tap.IsBoardCast(dstMacAddr) {
if tap.IsNotUnicast(dstMacAddr) {
dst_nodeID = path.Boardcast
} else if val, ok := device.l2fib.Load(dstMacAddr); !ok { //Lookup failed
dst_nodeID = path.Boardcast

View File

@ -10,7 +10,6 @@ import (
"bytes"
"errors"
"fmt"
"hash/crc32"
"io"
"net"
"strconv"
@ -19,7 +18,6 @@ import (
"sync/atomic"
"time"
"github.com/KusakabeSi/EtherGuardVPN/config"
"github.com/KusakabeSi/EtherGuardVPN/ipc"
)
@ -268,8 +266,6 @@ func (device *Device) handlePublicKeyLine(peer *ipcSetPeer, value string) error
if err != nil {
return ipcErrorf(ipc.IpcErrorInvalid, "failed to get peer by public key: %w", err)
}
h := crc32.NewIEEE()
h.Write(publicKey[:])
// Ignore peer with the same public key as this device.
device.staticIdentity.RLock()
@ -284,7 +280,11 @@ func (device *Device) handlePublicKeyLine(peer *ipcSetPeer, value string) error
peer.created = peer.Peer == nil
if peer.created {
peer.Peer, err = device.NewPeer(publicKey, config.Vertex(h.Sum32()))
id, err := device.LookupPeerIDAtConfig(publicKey)
if err != nil {
return errors.New("Create new peer by UAPI is not implemented")
}
peer.Peer, err = device.NewPeer(publicKey, id)
if err != nil {
return ipcErrorf(ipc.IpcErrorInvalid, "failed to create new peer: %w", err)
}

View File

@ -1,18 +1,19 @@
interface:
itype: stdio
ifaceid: 1
name: tap1
macaddr: AA:BB:CC:DD:EE:01
vppifaceid: 1
vppbridgeid: 0
macaddrprefix: AA:BB:CC:DD:EE
mtu: 1400
recvaddr: 127.0.0.1:4001
sendaddr: 127.0.0.1:5001
devfriendly: true
l2headermode: kbdbg
nodeid: 1
nodename: Node01
privkey: aABzjKhWdkFfQ29ZuijtMp1h1TNJe66SDCwvfmvQznw=
listenport: 3001
loglevel:
loglevel: normal`
loglevel: normal
logtransit: true
logcontrol: true
dynamicroute:
@ -23,9 +24,9 @@ dynamicroute:
supernode:
usesupernode: false
connurlv4: 127.0.0.1:3000
pubkeyv4: j8i4dY1i7CUqd/ftaCSfCWosnURiztM+ExI7QRezU2Y=
pubkeyv4: LJ8KKacUcIoACTGB/9Ed9w0osrJ3WWeelzpL2u4oUic=
connurlv6: '[::1]:3000'
pubkeyv6: cCcPlZw0hVkPSi15G+jpJpKE3TdCVEtO1nSiaedukGw=
pubkeyv6: HCfL6YJtpJEGHTlJ2LgVXIWKB/K95P57LHTJ42ZG8VI=
apiurl: http://127.0.0.1:3000/api
supernodeinfotimeout: 40
p2p:
@ -93,9 +94,10 @@ nexthoptable:
3: 4
4: 4
5: 4
resetconninterval: 86400
peers:
- nodeid: 2
pubkey: csT+hco4Jpa7btMeC9subHk2ZqzxcljcBk/57V0cSEk=
pskey: ""
endpoint: 127.0.0.1:3002
static: true
static: true

View File

@ -1,12 +1,13 @@
interface:
itype: stdio
ifaceid: 2
name: tap2
macaddr: AA:BB:CC:DD:EE:02
vppifaceid: 2
vppbridgeid: 0
macaddrprefix: AA:BB:CC:DD:EE
mtu: 1400
recvaddr: 127.0.0.1:4002
sendaddr: 127.0.0.1:5002
devfriendly: true
l2headermode: kbdbg
nodeid: 2
nodename: Node02
privkey: UNZMzPX5fG/8yGC8edVj/ksF9N6ARRqdq7fqE/PD7ls=
@ -23,9 +24,9 @@ dynamicroute:
supernode:
usesupernode: false
connurlv4: 127.0.0.1:3000
pubkeyv4: j8i4dY1i7CUqd/ftaCSfCWosnURiztM+ExI7QRezU2Y=
pubkeyv4: LJ8KKacUcIoACTGB/9Ed9w0osrJ3WWeelzpL2u4oUic=
connurlv6: '[::1]:3000'
pubkeyv6: cCcPlZw0hVkPSi15G+jpJpKE3TdCVEtO1nSiaedukGw=
pubkeyv6: HCfL6YJtpJEGHTlJ2LgVXIWKB/K95P57LHTJ42ZG8VI=
apiurl: http://127.0.0.1:3000/api
supernodeinfotimeout: 40
p2p:
@ -93,6 +94,7 @@ nexthoptable:
3: 4
4: 4
5: 4
resetconninterval: 86400
peers:
- nodeid: 1
pubkey: CooSkIP7/wiC7Rh83UYnB2yPkJijkNFmhtorHtyYlzY=

View File

@ -1,12 +1,13 @@
interface:
itype: stdio
ifaceid: 3
name: tap3
macaddr: AA:BB:CC:DD:EE:03
vppifaceid: 3
vppbridgeid: 0
macaddrprefix: AA:BB:CC:DD:EE
mtu: 1400
recvaddr: 127.0.0.1:4003
sendaddr: 127.0.0.1:5003
devfriendly: true
l2headermode: kbdbg
nodeid: 3
nodename: Node03
privkey: gJy35nbsd8FuuxyWHjsefN+U+oM7RkuIB1EanNLSVHg=
@ -23,9 +24,9 @@ dynamicroute:
supernode:
usesupernode: false
connurlv4: 127.0.0.1:3000
pubkeyv4: j8i4dY1i7CUqd/ftaCSfCWosnURiztM+ExI7QRezU2Y=
pubkeyv4: LJ8KKacUcIoACTGB/9Ed9w0osrJ3WWeelzpL2u4oUic=
connurlv6: '[::1]:3000'
pubkeyv6: cCcPlZw0hVkPSi15G+jpJpKE3TdCVEtO1nSiaedukGw=
pubkeyv6: HCfL6YJtpJEGHTlJ2LgVXIWKB/K95P57LHTJ42ZG8VI=
apiurl: http://127.0.0.1:3000/api
supernodeinfotimeout: 40
p2p:
@ -93,6 +94,7 @@ nexthoptable:
3: 4
4: 4
5: 4
resetconninterval: 86400
peers:
- nodeid: 2
pubkey: csT+hco4Jpa7btMeC9subHk2ZqzxcljcBk/57V0cSEk=

View File

@ -1,12 +1,13 @@
interface:
itype: stdio
ifaceid: 4
name: tap4
macaddr: AA:BB:CC:DD:EE:04
vppifaceid: 4
vppbridgeid: 0
macaddrprefix: AA:BB:CC:DD:EE
mtu: 1400
recvaddr: 127.0.0.1:4004
sendaddr: 127.0.0.1:5004
devfriendly: true
l2headermode: kbdbg
nodeid: 4
nodename: Node04
privkey: wAdLgCk0SHiO11/aUf9944focD1BUCH5b6Pe+cRHHXQ=
@ -23,9 +24,9 @@ dynamicroute:
supernode:
usesupernode: false
connurlv4: 127.0.0.1:3000
pubkeyv4: j8i4dY1i7CUqd/ftaCSfCWosnURiztM+ExI7QRezU2Y=
pubkeyv4: LJ8KKacUcIoACTGB/9Ed9w0osrJ3WWeelzpL2u4oUic=
connurlv6: '[::1]:3000'
pubkeyv6: cCcPlZw0hVkPSi15G+jpJpKE3TdCVEtO1nSiaedukGw=
pubkeyv6: HCfL6YJtpJEGHTlJ2LgVXIWKB/K95P57LHTJ42ZG8VI=
apiurl: http://127.0.0.1:3000/api
supernodeinfotimeout: 40
p2p:
@ -93,6 +94,7 @@ nexthoptable:
3: 4
4: 4
5: 4
resetconninterval: 86400
peers:
- nodeid: 2
pubkey: csT+hco4Jpa7btMeC9subHk2ZqzxcljcBk/57V0cSEk=

View File

@ -1,12 +1,13 @@
interface:
itype: stdio
ifaceid: 5
name: tap5
macaddr: AA:BB:CC:DD:EE:05
vppifaceid: 5
vppbridgeid: 0
macaddrprefix: AA:BB:CC:DD:EE
mtu: 1400
recvaddr: 127.0.0.1:4005
sendaddr: 127.0.0.1:5005
devfriendly: true
l2headermode: kbdbg
nodeid: 5
nodename: Node05
privkey: gLmzeCbmN/hjiE+ehNXL9IxuG9hhWIYv2s16/DOW6FE=
@ -23,9 +24,9 @@ dynamicroute:
supernode:
usesupernode: false
connurlv4: 127.0.0.1:3000
pubkeyv4: j8i4dY1i7CUqd/ftaCSfCWosnURiztM+ExI7QRezU2Y=
pubkeyv4: LJ8KKacUcIoACTGB/9Ed9w0osrJ3WWeelzpL2u4oUic=
connurlv6: '[::1]:3000'
pubkeyv6: cCcPlZw0hVkPSi15G+jpJpKE3TdCVEtO1nSiaedukGw=
pubkeyv6: HCfL6YJtpJEGHTlJ2LgVXIWKB/K95P57LHTJ42ZG8VI=
apiurl: http://127.0.0.1:3000/api
supernodeinfotimeout: 40
p2p:
@ -93,6 +94,7 @@ nexthoptable:
3: 4
4: 4
5: 4
resetconninterval: 86400
peers:
- nodeid: 3
pubkey: 0meQ0pQCAkLZdpfyMqggpnk0k3UKG2M8jfIMlQjTRWs=

View File

@ -1,12 +1,13 @@
interface:
itype: stdio
ifaceid: 6
name: tap6
macaddr: AA:BB:CC:DD:EE:03
vppifaceid: 6
vppbridgeid: 0
macaddrprefix: AA:BB:CC:DD:EE
mtu: 1400
recvaddr: 127.0.0.1:4006
sendaddr: 127.0.0.1:5006
devfriendly: true
l2headermode: kbdbg
nodeid: 6
nodename: Node06
privkey: IIX5F6oWZUS2dlhxWFJ7TxdJtDCr5jzeuhxUB6YM7Us=
@ -23,9 +24,9 @@ dynamicroute:
supernode:
usesupernode: false
connurlv4: 127.0.0.1:3000
pubkeyv4: j8i4dY1i7CUqd/ftaCSfCWosnURiztM+ExI7QRezU2Y=
pubkeyv4: LJ8KKacUcIoACTGB/9Ed9w0osrJ3WWeelzpL2u4oUic=
connurlv6: '[::1]:3000'
pubkeyv6: cCcPlZw0hVkPSi15G+jpJpKE3TdCVEtO1nSiaedukGw=
pubkeyv6: HCfL6YJtpJEGHTlJ2LgVXIWKB/K95P57LHTJ42ZG8VI=
apiurl: http://127.0.0.1:3000/api
supernodeinfotimeout: 40
p2p:
@ -93,6 +94,7 @@ nexthoptable:
3: 4
4: 4
5: 4
resetconninterval: 86400
peers:
- nodeid: 4
pubkey: 2EfY85KF1S+3dZ3A55eZcyi0QU+sOzOyuADtJs2U2Ww=

View File

@ -1,31 +1,32 @@
interface:
itype: stdio
ifaceid: 1
name: tap1
macaddr: AA:BB:CC:DD:EE:01
vppifaceid: 1
vppbridgeid: 0
macaddrprefix: AA:BB:CC:DD:EE
mtu: 1400
recvaddr: 127.0.0.1:4001
sendaddr: 127.0.0.1:5001
devfriendly: true
l2headermode: kbdbg
nodeid: 1
nodename: Node01
privkey: aABzjKhWdkFfQ29ZuijtMp1h1TNJe66SDCwvfmvQznw=
listenport: 3001
loglevel:
loglevel: normal`
loglevel: normal
logtransit: true
logcontrol: true
dynamicroute:
sendpinginterval: 20
dupchecktimeout: 40
conntimeout: 30
savenewpeers: true
savenewpeers: false
supernode:
usesupernode: false
connurlv4: 127.0.0.1:3000
pubkeyv4: j8i4dY1i7CUqd/ftaCSfCWosnURiztM+ExI7QRezU2Y=
pubkeyv4: LJ8KKacUcIoACTGB/9Ed9w0osrJ3WWeelzpL2u4oUic=
connurlv6: '[::1]:3000'
pubkeyv6: cCcPlZw0hVkPSi15G+jpJpKE3TdCVEtO1nSiaedukGw=
pubkeyv6: HCfL6YJtpJEGHTlJ2LgVXIWKB/K95P57LHTJ42ZG8VI=
apiurl: http://127.0.0.1:3000/api
supernodeinfotimeout: 40
p2p:
@ -93,6 +94,7 @@ nexthoptable:
3: 4
4: 4
5: 4
resetconninterval: 86400
peers:
- nodeid: 2
pubkey: csT+hco4Jpa7btMeC9subHk2ZqzxcljcBk/57V0cSEk=

View File

@ -1,12 +1,13 @@
interface:
itype: stdio
ifaceid: 2
name: tap2
macaddr: AA:BB:CC:DD:EE:02
vppifaceid: 2
vppbridgeid: 0
macaddrprefix: AA:BB:CC:DD:EE
mtu: 1400
recvaddr: 127.0.0.1:4002
sendaddr: 127.0.0.1:5002
devfriendly: true
l2headermode: kbdbg
nodeid: 2
nodename: Node02
privkey: UNZMzPX5fG/8yGC8edVj/ksF9N6ARRqdq7fqE/PD7ls=
@ -19,13 +20,13 @@ dynamicroute:
sendpinginterval: 20
dupchecktimeout: 40
conntimeout: 30
savenewpeers: true
savenewpeers: false
supernode:
usesupernode: false
connurlv4: 127.0.0.1:3000
pubkeyv4: j8i4dY1i7CUqd/ftaCSfCWosnURiztM+ExI7QRezU2Y=
pubkeyv4: LJ8KKacUcIoACTGB/9Ed9w0osrJ3WWeelzpL2u4oUic=
connurlv6: '[::1]:3000'
pubkeyv6: cCcPlZw0hVkPSi15G+jpJpKE3TdCVEtO1nSiaedukGw=
pubkeyv6: HCfL6YJtpJEGHTlJ2LgVXIWKB/K95P57LHTJ42ZG8VI=
apiurl: http://127.0.0.1:3000/api
supernodeinfotimeout: 40
p2p:
@ -93,6 +94,7 @@ nexthoptable:
3: 4
4: 4
5: 4
resetconninterval: 86400
peers:
- nodeid: 1
pubkey: CooSkIP7/wiC7Rh83UYnB2yPkJijkNFmhtorHtyYlzY=

View File

@ -1,12 +1,13 @@
interface:
itype: stdio
ifaceid: 3
name: tap3
macaddr: AA:BB:CC:DD:EE:03
vppifaceid: 3
vppbridgeid: 0
macaddrprefix: AA:BB:CC:DD:EE
mtu: 1400
recvaddr: 127.0.0.1:4003
sendaddr: 127.0.0.1:5003
devfriendly: true
l2headermode: kbdbg
nodeid: 3
nodename: Node03
privkey: gJy35nbsd8FuuxyWHjsefN+U+oM7RkuIB1EanNLSVHg=
@ -19,13 +20,13 @@ dynamicroute:
sendpinginterval: 20
dupchecktimeout: 40
conntimeout: 30
savenewpeers: true
savenewpeers: false
supernode:
usesupernode: false
connurlv4: 127.0.0.1:3000
pubkeyv4: j8i4dY1i7CUqd/ftaCSfCWosnURiztM+ExI7QRezU2Y=
pubkeyv4: LJ8KKacUcIoACTGB/9Ed9w0osrJ3WWeelzpL2u4oUic=
connurlv6: '[::1]:3000'
pubkeyv6: cCcPlZw0hVkPSi15G+jpJpKE3TdCVEtO1nSiaedukGw=
pubkeyv6: HCfL6YJtpJEGHTlJ2LgVXIWKB/K95P57LHTJ42ZG8VI=
apiurl: http://127.0.0.1:3000/api
supernodeinfotimeout: 40
p2p:
@ -93,6 +94,7 @@ nexthoptable:
3: 4
4: 4
5: 4
resetconninterval: 86400
peers:
- nodeid: 2
pubkey: csT+hco4Jpa7btMeC9subHk2ZqzxcljcBk/57V0cSEk=

View File

@ -1,12 +1,13 @@
interface:
itype: stdio
ifaceid: 4
name: tap4
macaddr: AA:BB:CC:DD:EE:04
vppifaceid: 4
vppbridgeid: 0
macaddrprefix: AA:BB:CC:DD:EE
mtu: 1400
recvaddr: 127.0.0.1:4004
sendaddr: 127.0.0.1:5004
devfriendly: true
l2headermode: kbdbg
nodeid: 4
nodename: Node04
privkey: wAdLgCk0SHiO11/aUf9944focD1BUCH5b6Pe+cRHHXQ=
@ -19,13 +20,13 @@ dynamicroute:
sendpinginterval: 20
dupchecktimeout: 40
conntimeout: 30
savenewpeers: true
savenewpeers: false
supernode:
usesupernode: false
connurlv4: 127.0.0.1:3000
pubkeyv4: j8i4dY1i7CUqd/ftaCSfCWosnURiztM+ExI7QRezU2Y=
pubkeyv4: LJ8KKacUcIoACTGB/9Ed9w0osrJ3WWeelzpL2u4oUic=
connurlv6: '[::1]:3000'
pubkeyv6: cCcPlZw0hVkPSi15G+jpJpKE3TdCVEtO1nSiaedukGw=
pubkeyv6: HCfL6YJtpJEGHTlJ2LgVXIWKB/K95P57LHTJ42ZG8VI=
apiurl: http://127.0.0.1:3000/api
supernodeinfotimeout: 40
p2p:
@ -93,6 +94,7 @@ nexthoptable:
3: 4
4: 4
5: 4
resetconninterval: 86400
peers:
- nodeid: 2
pubkey: csT+hco4Jpa7btMeC9subHk2ZqzxcljcBk/57V0cSEk=

View File

@ -1,12 +1,13 @@
interface:
itype: stdio
ifaceid: 5
name: tap5
macaddr: AA:BB:CC:DD:EE:05
vppifaceid: 5
vppbridgeid: 0
macaddrprefix: AA:BB:CC:DD:EE
mtu: 1400
recvaddr: 127.0.0.1:4005
sendaddr: 127.0.0.1:5005
devfriendly: true
l2headermode: kbdbg
nodeid: 5
nodename: Node05
privkey: gLmzeCbmN/hjiE+ehNXL9IxuG9hhWIYv2s16/DOW6FE=
@ -19,13 +20,13 @@ dynamicroute:
sendpinginterval: 20
dupchecktimeout: 40
conntimeout: 30
savenewpeers: true
savenewpeers: false
supernode:
usesupernode: false
connurlv4: 127.0.0.1:3000
pubkeyv4: j8i4dY1i7CUqd/ftaCSfCWosnURiztM+ExI7QRezU2Y=
pubkeyv4: LJ8KKacUcIoACTGB/9Ed9w0osrJ3WWeelzpL2u4oUic=
connurlv6: '[::1]:3000'
pubkeyv6: cCcPlZw0hVkPSi15G+jpJpKE3TdCVEtO1nSiaedukGw=
pubkeyv6: HCfL6YJtpJEGHTlJ2LgVXIWKB/K95P57LHTJ42ZG8VI=
apiurl: http://127.0.0.1:3000/api
supernodeinfotimeout: 40
p2p:
@ -93,6 +94,7 @@ nexthoptable:
3: 4
4: 4
5: 4
resetconninterval: 86400
peers:
- nodeid: 3
pubkey: 0meQ0pQCAkLZdpfyMqggpnk0k3UKG2M8jfIMlQjTRWs=

View File

@ -1,12 +1,13 @@
interface:
itype: stdio
ifaceid: 6
name: tap6
macaddr: AA:BB:CC:DD:EE:03
vppifaceid: 6
vppbridgeid: 0
macaddrprefix: AA:BB:CC:DD:EE
mtu: 1400
recvaddr: 127.0.0.1:4006
sendaddr: 127.0.0.1:5006
devfriendly: true
l2headermode: kbdbg
nodeid: 6
nodename: Node06
privkey: IIX5F6oWZUS2dlhxWFJ7TxdJtDCr5jzeuhxUB6YM7Us=
@ -19,13 +20,13 @@ dynamicroute:
sendpinginterval: 20
dupchecktimeout: 40
conntimeout: 30
savenewpeers: true
savenewpeers: false
supernode:
usesupernode: false
connurlv4: 127.0.0.1:3000
pubkeyv4: j8i4dY1i7CUqd/ftaCSfCWosnURiztM+ExI7QRezU2Y=
pubkeyv4: LJ8KKacUcIoACTGB/9Ed9w0osrJ3WWeelzpL2u4oUic=
connurlv6: '[::1]:3000'
pubkeyv6: cCcPlZw0hVkPSi15G+jpJpKE3TdCVEtO1nSiaedukGw=
pubkeyv6: HCfL6YJtpJEGHTlJ2LgVXIWKB/K95P57LHTJ42ZG8VI=
apiurl: http://127.0.0.1:3000/api
supernodeinfotimeout: 40
p2p:
@ -93,6 +94,7 @@ nexthoptable:
3: 4
4: 4
5: 4
resetconninterval: 86400
peers:
- nodeid: 4
pubkey: 2EfY85KF1S+3dZ3A55eZcyi0QU+sOzOyuADtJs2U2Ww=

View File

@ -1,12 +1,13 @@
interface:
itype: stdio
ifaceid: 1
name: tap1
macaddr: AA:BB:CC:DD:EE:FF
vppifaceid: 1
vppbridgeid: 0
macaddrprefix: AA:BB:CC:DD:EE
mtu: 1400
recvaddr: 127.0.0.1:4001
sendaddr: 127.0.0.1:5001
devfriendly: true
l2headermode: kbdbg
nodeid: 1
nodename: Node01
privkey: 6GyDagZKhbm5WNqMiRHhkf43RlbMJ34IieTlIuvfJ1M=
@ -24,7 +25,7 @@ dynamicroute:
usesupernode: true
connurlv4: 127.0.0.1:3000
pubkeyv4: LJ8KKacUcIoACTGB/9Ed9w0osrJ3WWeelzpL2u4oUic=
connurlv6: '[::1]:2999'
connurlv6: '[::1]:3000'
pubkeyv6: HCfL6YJtpJEGHTlJ2LgVXIWKB/K95P57LHTJ42ZG8VI=
apiurl: http://127.0.0.1:3000/api
supernodeinfotimeout: 40
@ -57,4 +58,5 @@ dynamicroute:
- time.euro.apple.com
- time.windows.com
nexthoptable: {}
resetconninterval: 86400
peers: []

View File

@ -1,14 +1,15 @@
interface:
itype: stdio
ifaceid: 2
name: tap2
macaddr: AA:BB:CC:DD:EE:FF
vppifaceid: 2
vppbridgeid: 0
macaddrprefix: AA:BB:CC:DD:EE
mtu: 1400
recvaddr: 127.0.0.1:4002
sendaddr: 127.0.0.1:5002
devfriendly: true
nodeid: 2
nodename: Node02
l2headermode: kbdbg
nodeid: 1
nodename: Node01
privkey: OH8BsVUU2Rqzeu9B2J5GPG8PUmxWfX8uVvNFZKhVF3o=
listenport: 3002
loglevel:
@ -24,7 +25,7 @@ dynamicroute:
usesupernode: true
connurlv4: 127.0.0.1:3000
pubkeyv4: LJ8KKacUcIoACTGB/9Ed9w0osrJ3WWeelzpL2u4oUic=
connurlv6: '[::1]:2999'
connurlv6: '[::1]:3000'
pubkeyv6: HCfL6YJtpJEGHTlJ2LgVXIWKB/K95P57LHTJ42ZG8VI=
apiurl: http://127.0.0.1:3000/api
supernodeinfotimeout: 40
@ -57,4 +58,5 @@ dynamicroute:
- time.euro.apple.com
- time.windows.com
nexthoptable: {}
resetconninterval: 86400
peers: []

View File

@ -2,14 +2,14 @@ nodename: NodeSuper
privkeyv4: mL5IW0GuqbjgDeOJuPHBU2iJzBPNKhaNEXbIGwwYWWk=
privkeyv6: +EdOKIoBp/EvIusHDsvXhV1RJYbyN3Qr8nxlz35wl3I=
listenport: 3000
repushconfiginterval: 10
loglevel:
loglevel: normal
logtransit: true
logcontrol: true
repushconfiginterval: 30
graphrecalculatesetting:
jittertolerance: 20
jittertolerancemultiplier: 1.1
jittertolerance: 5
jittertolerancemultiplier: 1.01
nodereporttimeout: 40
recalculatecooldown: 5
peers:

15
main.go
View File

@ -25,8 +25,8 @@ const (
)
const (
ENV_WP_UAPI_FD = "WP_UAPI_FD"
ENV_WP_UAPI_DIR = "WP_UAPI_DIR"
ENV_EG_UAPI_FD = "EG_UAPI_FD"
ENV_EG_UAPI_DIR = "EG_UAPI_DIR"
)
func printUsage() {
@ -62,20 +62,25 @@ func main() {
return
}
uapiDir := os.Getenv(ENV_WP_UAPI_DIR)
uapiDir := os.Getenv(ENV_EG_UAPI_DIR)
if uapiDir != "" {
ipc.SetsocketDirectory(uapiDir)
}
var err error
switch *mode {
case "edge":
Edge(*tconfig, !*nouapi, *printExample)
err = Edge(*tconfig, !*nouapi, *printExample)
case "super":
Super(*tconfig, !*nouapi, *printExample)
err = Super(*tconfig, !*nouapi, *printExample)
case "path":
path.Solve()
default:
flag.Usage()
}
if err != nil {
fmt.Fprintf(os.Stderr, "Error :%v\n", err)
os.Exit(1)
}
return
}

View File

@ -29,13 +29,13 @@ func printExampleEdgeConf() {
tconfig := config.EdgeConfig{
Interface: config.InterfaceConf{
Itype: "stdio",
VPPIfaceID: 5,
VPPIfaceID: 5,
Name: "tap1",
MacAddr: "AA:BB:CC:DD:EE:FF",
MacAddrPrefix: "AA:BB:CC:DD:EE:FF",
MTU: 1400,
RecvAddr: "127.0.0.1:4001",
SendAddr: "127.0.0.1:5001",
DevFriendly: true,
L2HeaderMode: "nochg",
},
NodeID: 1,
NodeName: "Node01",
@ -44,6 +44,7 @@ func printExampleEdgeConf() {
LogLevel: config.LoggerInfo{
LogLevel: "normal",
LogTransit: true,
LogControl: true,
},
DynamicRoute: config.DynamicRouteInfo{
SendPingInterval: 20,
@ -53,9 +54,9 @@ func printExampleEdgeConf() {
SuperNode: config.SuperInfo{
UseSuperNode: true,
ConnURLV4: "127.0.0.1:3000",
PubKeyV4: "j8i4dY1i7CUqd/ftaCSfCWosnURiztM+ExI7QRezU2Y=",
PubKeyV4: "LJ8KKacUcIoACTGB/9Ed9w0osrJ3WWeelzpL2u4oUic=",
ConnURLV6: "[::1]:3000",
PubKeyV6: "cCcPlZw0hVkPSi15G+jpJpKE3TdCVEtO1nSiaedukGw=",
PubKeyV6: "HCfL6YJtpJEGHTlJ2LgVXIWKB/K95P57LHTJ42ZG8VI=",
APIUrl: "http://127.0.0.1:3000/api",
SuperNodeInfoTimeout: 40,
},
@ -90,7 +91,8 @@ func printExampleEdgeConf() {
"time.windows.com"},
},
},
NextHopTable: config.NextHopTable{},
NextHopTable: config.NextHopTable{},
ResetConnInterval: 86400,
Peers: []config.PeerInfo{
{
NodeID: 2,
@ -165,13 +167,17 @@ 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.DevFriendly)
tconfig.Interface.VPPIfaceID = uint32(tconfig.NodeID)
thetap, err = tap.CreateStdIOTAP(tconfig.Interface)
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.DevFriendly)
}
tconfig.Interface.VPPIfaceID = uint32(tconfig.NodeID)
lis, _ := net.ResolveUDPAddr("udp", tconfig.Interface.RecvAddr)
sen, _ := net.ResolveUDPAddr("udp", tconfig.Interface.SendAddr)
thetap, err = tap.CreateUDPSockTAP(tconfig.Interface, lis, sen)
case "vpp":
thetap, err = tap.CreateVppTAP(tconfig.Interface, tconfig.LogLevel.LogLevel)
default:
return errors.New("Unknow interface type:" + tconfig.Interface.Itype)
}
if err != nil {
logger.Errorf("Failed to create TAP device: %v", err)
@ -206,6 +212,8 @@ func Edge(configPath string, useUAPI bool, printExample bool) (err error) {
logger.Errorf("Failed to set endpoint %v: %w", peerconf.EndPoint, err)
return err
}
peer.StaticConn = peerconf.Static
peer.ConnURL = peerconf.EndPoint
peer.SetEndpointFromPacket(endpoint)
}
}
@ -222,6 +230,8 @@ func Edge(configPath string, useUAPI bool, printExample bool) (err error) {
if err != nil {
return err
}
peer.StaticConn = false
peer.ConnURL = tconfig.DynamicRoute.SuperNode.ConnURLV4
peer.SetEndpointFromPacket(endpoint)
}
if tconfig.DynamicRoute.SuperNode.ConnURLV6 != "" {
@ -235,6 +245,8 @@ func Edge(configPath string, useUAPI bool, printExample bool) (err error) {
if err != nil {
return err
}
peer.StaticConn = false
peer.ConnURL = tconfig.DynamicRoute.SuperNode.ConnURLV6
peer.SetEndpointFromPacket(endpoint)
}
}

View File

@ -34,13 +34,15 @@ import (
func printExampleSuperConf() {
sconfig := config.SuperConfig{
NodeName: "NodeSuper",
PrivKeyV4: "SM8pGjT0r8njy1/7ffN4wMwF7nnJ8UYSjGRWpCqo3ng=",
PrivKeyV6: "SM8pGjT0r8njy1/7ffN4wMwF7nnJ8UYSjGRWpCqo3ng=",
PrivKeyV4: "mL5IW0GuqbjgDeOJuPHBU2iJzBPNKhaNEXbIGwwYWWk=",
PrivKeyV6: "+EdOKIoBp/EvIusHDsvXhV1RJYbyN3Qr8nxlz35wl3I=",
ListenPort: 3000,
LogLevel: config.LoggerInfo{
LogLevel: "normal",
LogTransit: true,
LogControl: true,
},
RePushConfigInterval: 30,
Peers: []config.PeerInfo{
{
NodeID: 2,
@ -50,8 +52,8 @@ func printExampleSuperConf() {
},
},
GraphRecalculateSetting: config.GraphRecalculateSetting{
JitterTolerance: 20,
JitterToleranceMultiplier: 1.1,
JitterTolerance: 5,
JitterToleranceMultiplier: 1.01,
NodeReportTimeout: 40,
RecalculateCoolDown: 5,
},
@ -70,8 +72,7 @@ func Super(configPath string, useUAPI bool, printExample bool) (err error) {
var sconfig config.SuperConfig
err = readYaml(configPath, &sconfig)
if err != nil {
fmt.Printf("Error read config: %s :", configPath)
fmt.Print(err)
fmt.Printf("Error read config: %v\n", configPath)
return err
}
interfaceName := sconfig.NodeName
@ -107,21 +108,29 @@ func Super(configPath string, useUAPI bool, printExample bool) (err error) {
thetap, _ := tap.CreateDummyTAP()
http_graph = path.NewGraph(3, true, sconfig.GraphRecalculateSetting)
http_device4 = device.NewDevice(thetap, path.SuperNodeMessage, conn.NewCustomBind(true, false), logger4, http_graph, true, "", nil, &sconfig, &super_chains)
http_device6 = device.NewDevice(thetap, path.SuperNodeMessage, conn.NewCustomBind(false, true), logger6, http_graph, true, "", nil, &sconfig, &super_chains)
http_device4 = device.NewDevice(thetap, path.SuperNodeMessage, conn.NewCustomBind(true, false), logger4, http_graph, true, configPath, nil, &sconfig, &super_chains)
http_device6 = device.NewDevice(thetap, path.SuperNodeMessage, conn.NewCustomBind(false, true), logger6, http_graph, true, configPath, nil, &sconfig, &super_chains)
defer http_device4.Close()
defer http_device6.Close()
var sk [32]byte
sk_slice, _ := base64.StdEncoding.DecodeString(sconfig.PrivKeyV4)
sk_slice, err := base64.StdEncoding.DecodeString(sconfig.PrivKeyV4)
if err != nil {
fmt.Printf("Can't decode base64:%v\n", sconfig.PrivKeyV4)
return err
}
copy(sk[:], sk_slice)
http_device4.SetPrivateKey(sk)
sk_slice, _ = base64.StdEncoding.DecodeString(sconfig.PrivKeyV6)
sk_slice, err = base64.StdEncoding.DecodeString(sconfig.PrivKeyV6)
if err != nil {
fmt.Printf("Can't decode base64:%v\n", sconfig.PrivKeyV6)
return err
}
copy(sk[:], sk_slice)
http_device6.SetPrivateKey(sk)
http_device4.IpcSet("fwmark=0\n")
http_device6.IpcSet("fwmark=0\n")
http_device4.IpcSet("listen_port=" + strconv.Itoa(sconfig.ListenPort) + "\n")
http_device6.IpcSet("listen_port=" + strconv.Itoa(sconfig.ListenPort-1) + "\n")
http_device6.IpcSet("listen_port=" + strconv.Itoa(sconfig.ListenPort) + "\n")
http_device4.IpcSet("replace_peers=true\n")
http_device6.IpcSet("replace_peers=true\n")
@ -143,8 +152,20 @@ func Super(configPath string, useUAPI bool, printExample bool) (err error) {
PSKey: peerconf.PSKey,
Connurl: make(map[string]bool),
}
peer4, _ := http_device4.NewPeer(pk, peerconf.NodeID)
peer6, _ := http_device6.NewPeer(pk, peerconf.NodeID)
peer4, err := http_device4.NewPeer(pk, peerconf.NodeID)
if err != nil {
fmt.Printf("Error create peer id %v\n", peerconf.NodeID)
return err
}
peer4.StaticConn = true
peer4.ConnURL = peerconf.EndPoint
peer6, err := http_device6.NewPeer(pk, peerconf.NodeID)
if err != nil {
fmt.Printf("Error create peer id %v\n", peerconf.NodeID)
return err
}
peer6.StaticConn = true
peer6.ConnURL = peerconf.EndPoint
if peerconf.PSKey != "" {
var psk device.NoisePresharedKey
psk_slice, err := base64.StdEncoding.DecodeString(peerconf.PSKey)
@ -306,7 +327,7 @@ func PushUpdate() {
func startUAPI(interfaceName string, logger *device.Logger, the_device *device.Device, errs chan error) (net.Listener, error) {
fileUAPI, err := func() (*os.File, error) {
uapiFdStr := os.Getenv(ENV_WP_UAPI_FD)
uapiFdStr := os.Getenv(ENV_EG_UAPI_FD)
if uapiFdStr == "" {
return ipc.UAPIOpen(interfaceName)
}
@ -317,10 +338,14 @@ func startUAPI(interfaceName string, logger *device.Logger, the_device *device.D
}
return os.NewFile(uintptr(fd), ""), nil
}()
if err != nil {
fmt.Printf("Error create UAPI socket \n")
return nil, err
}
uapi, err := ipc.UAPIListen(interfaceName, fileUAPI)
if err != nil {
logger.Errorf("Failed to listen on uapi socket: %v", err)
os.Exit(ExitSetupFailed)
return nil, err
}
go func() {

View File

@ -79,22 +79,29 @@ func NewGraph(num_node int, IsSuperMode bool, theconfig config.GraphRecalculateS
return &g
}
func (g *IG) GetWeightType(x float64) float64 {
func (g *IG) GetWeightType(x float64) (y float64) {
x = math.Abs(x)
y := x
if g.JitterTolerance > 1 && g.JitterToleranceMultiplier > 0.001 {
r := g.JitterTolerance
m := g.JitterToleranceMultiplier
y = math.Pow(math.Ceil(math.Pow(x/m, 1/r)), r) * m
y = x
if g.JitterTolerance > 0.001 && g.JitterToleranceMultiplier > 1 {
t := g.JitterTolerance
r := g.JitterToleranceMultiplier
y = math.Pow(math.Ceil(math.Pow(x/t, 1/r)), r) * t
}
return y
}
func (g *IG) ShouldUpdate(u config.Vertex, v config.Vertex, newval float64) bool {
oldval := g.Weight(u, v) * 1000
newval *= 1000
oldval := math.Abs(g.Weight(u, v) * 1000)
newval = math.Abs(newval * 1000)
if g.IsSuperMode {
return (oldval-newval)*(oldval*g.JitterToleranceMultiplier) >= g.JitterTolerance
if g.JitterTolerance > 0.001 && g.JitterToleranceMultiplier >= 1 {
diff := math.Abs(newval - oldval)
x := math.Max(oldval, newval)
t := g.JitterTolerance
r := g.JitterToleranceMultiplier
return diff > t+x*(r-1) // https://www.desmos.com/calculator/raoti16r5n
}
return oldval == newval
} else {
return g.GetWeightType(oldval) == g.GetWeightType(newval)
}

View File

@ -6,7 +6,10 @@
package tap
import (
"bytes"
"encoding/binary"
"errors"
"strconv"
"strings"
)
type Event int
@ -22,13 +25,44 @@ func GetSrcMacAddr(packet []byte) (srcMacAddr MacAddress) {
return
}
func IsBoardCast(mac_in MacAddress) bool {
if bytes.Equal(mac_in[:], []byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff}) {
return true
} else if bytes.Equal(mac_in[0:2], []byte{0x33, 0x33}) {
return true
func GetMacAddr(prefix string, uid uint32) (mac MacAddress, err error) {
macprefix, _, err := prefixStr2prefix(prefix)
if err != nil {
return
}
return false
idbuf := make([]byte, 4)
binary.BigEndian.PutUint32(idbuf, uid)
copy(mac[2:], idbuf)
copy(mac[:], macprefix)
if IsNotUnicast(mac) {
err = errors.New("ERROR: MAC address can only set to unicast address")
return
}
return
}
func prefixStr2prefix(prefix string) ([]uint8, uint32, error) {
hexStrs := strings.Split(strings.ToLower(prefix), ":")
retprefix := make([]uint8, len(hexStrs))
maxID := uint32(1)<<((6-len(hexStrs))*8) - 1
if len(hexStrs) < 2 || len(hexStrs) > 6 {
return []uint8{}, 0, errors.New("Macaddr prefix length must between 2 and 6, " + prefix + " is " + strconv.Itoa(len(hexStrs)))
}
for index, hexstr := range hexStrs {
value, err := strconv.ParseInt(hexstr, 16, 16)
if err != nil {
return []uint8{}, 0, err
}
retprefix[index] = uint8(value)
}
return retprefix, maxID, nil
}
func IsNotUnicast(mac_in MacAddress) bool {
if mac_in[0]&1 == 0 { // Is unicast
return false
}
return true
}
const (

529
tap/tap_linux.go Normal file
View File

@ -0,0 +1,529 @@
/* SPDX-License-Identifier: MIT
*
* Copyright (C) 2017-2021 WireGuard LLC. All Rights Reserved.
*/
package tap
/* Implementation of the TUN device interface for linux
*/
import (
"bytes"
"encoding/binary"
"errors"
"fmt"
"os"
"sync"
"syscall"
"time"
"unsafe"
"golang.org/x/sys/unix"
"github.com/KusakabeSi/EtherGuardVPN/config"
"github.com/KusakabeSi/EtherGuardVPN/rwcancel"
)
const (
cloneDevicePath = "/dev/net/tun"
ifReqSize = unix.IFNAMSIZ + 64
)
type NativeTap struct {
tapFile *os.File
index int32 // if index
errors chan error // async error handling
events chan Event // device related events
nopi bool // the device was passed IFF_NO_PI
netlinkSock int
netlinkCancel *rwcancel.RWCancel
hackListenerClosed sync.Mutex
statusListenersShutdown chan struct{}
closeOnce sync.Once
nameOnce sync.Once // guards calling initNameCache, which sets following fields
nameCache string // name of interface
nameErr error
}
func (tap *NativeTap) File() *os.File {
return tap.tapFile
}
func (tap *NativeTap) routineHackListener() {
defer tap.hackListenerClosed.Unlock()
/* This is needed for the detection to work across network namespaces
* If you are reading this and know a better method, please get in touch.
*/
last := 0
const (
up = 1
down = 2
)
for {
sysconn, err := tap.tapFile.SyscallConn()
if err != nil {
return
}
err2 := sysconn.Control(func(fd uintptr) {
_, err = unix.Write(int(fd), nil)
})
if err2 != nil {
return
}
switch err {
case unix.EINVAL:
if last != up {
// If the tunnel is up, it reports that write() is
// allowed but we provided invalid data.
tap.events <- EventUp
last = up
}
case unix.EIO:
if last != down {
// If the tunnel is down, it reports that no I/O
// is possible, without checking our provided data.
tap.events <- EventDown
last = down
}
default:
return
}
select {
case <-time.After(time.Second):
// nothing
case <-tap.statusListenersShutdown:
return
}
}
}
func createNetlinkSocket() (int, error) {
sock, err := unix.Socket(unix.AF_NETLINK, unix.SOCK_RAW, unix.NETLINK_ROUTE)
if err != nil {
return -1, err
}
saddr := &unix.SockaddrNetlink{
Family: unix.AF_NETLINK,
Groups: unix.RTMGRP_LINK | unix.RTMGRP_IPV4_IFADDR | unix.RTMGRP_IPV6_IFADDR,
}
err = unix.Bind(sock, saddr)
if err != nil {
return -1, err
}
return sock, nil
}
func (tap *NativeTap) routineNetlinkListener() {
defer func() {
unix.Close(tap.netlinkSock)
tap.hackListenerClosed.Lock()
close(tap.events)
tap.netlinkCancel.Close()
}()
for msg := make([]byte, 1<<16); ; {
var err error
var msgn int
for {
msgn, _, _, _, err = unix.Recvmsg(tap.netlinkSock, msg[:], nil, 0)
if err == nil || !rwcancel.RetryAfterError(err) {
break
}
if !tap.netlinkCancel.ReadyRead() {
tap.errors <- fmt.Errorf("netlink socket closed: %w", err)
return
}
}
if err != nil {
tap.errors <- fmt.Errorf("failed to receive netlink message: %w", err)
return
}
select {
case <-tap.statusListenersShutdown:
return
default:
}
wasEverUp := false
for remain := msg[:msgn]; len(remain) >= unix.SizeofNlMsghdr; {
hdr := *(*unix.NlMsghdr)(unsafe.Pointer(&remain[0]))
if int(hdr.Len) > len(remain) {
break
}
switch hdr.Type {
case unix.NLMSG_DONE:
remain = []byte{}
case unix.RTM_NEWLINK:
info := *(*unix.IfInfomsg)(unsafe.Pointer(&remain[unix.SizeofNlMsghdr]))
remain = remain[hdr.Len:]
if info.Index != tap.index {
// not our interface
continue
}
if info.Flags&unix.IFF_RUNNING != 0 {
tap.events <- EventUp
wasEverUp = true
}
if info.Flags&unix.IFF_RUNNING == 0 {
// Don't emit EventDown before we've ever emitted EventUp.
// This avoids a startup race with HackListener, which
// might detect Up before we have finished reporting Down.
if wasEverUp {
tap.events <- EventDown
}
}
tap.events <- EventMTUUpdate
default:
remain = remain[hdr.Len:]
}
}
}
}
func (tap *NativeTap) setMacAddr(mac MacAddress) (err error) {
fd, err := unix.Socket(
unix.AF_INET,
unix.SOCK_DGRAM,
0,
)
if err != nil {
return err
}
defer unix.Close(fd)
var ifr [ifReqSize]byte
name, err := tap.Name()
if err != nil {
return err
}
/*
ifreq = struct.pack('16sH6B8x', self.name, AF_UNIX, *macbytes)
fcntl.ioctl(sockfd, SIOCSIFHWADDR, ifreq)
*/
copy(ifr[:16], name)
binary.BigEndian.PutUint16(ifr[16:18], unix.AF_UNIX)
copy(ifr[18:24], mac[:])
copy(ifr[24:32], make([]byte, 8))
_, _, err = unix.Syscall(
unix.SYS_IOCTL,
uintptr(fd),
uintptr(unix.SIOCSIFHWADDR),
uintptr(unsafe.Pointer(&ifr[0])),
)
return
}
func getIFIndex(name string) (int32, error) {
fd, err := unix.Socket(
unix.AF_INET,
unix.SOCK_DGRAM,
0,
)
if err != nil {
return 0, err
}
defer unix.Close(fd)
var ifr [ifReqSize]byte
copy(ifr[:], name)
_, _, errno := unix.Syscall(
unix.SYS_IOCTL,
uintptr(fd),
uintptr(unix.SIOCGIFINDEX),
uintptr(unsafe.Pointer(&ifr[0])),
)
if errno != 0 {
return 0, errno
}
return *(*int32)(unsafe.Pointer(&ifr[unix.IFNAMSIZ])), nil
}
func (tap *NativeTap) setMTU(n int) error {
name, err := tap.Name()
if err != nil {
return err
}
// open datagram socket
fd, err := unix.Socket(
unix.AF_INET,
unix.SOCK_DGRAM,
0,
)
if err != nil {
return err
}
defer unix.Close(fd)
// do ioctl call
var ifr [ifReqSize]byte
copy(ifr[:], name)
*(*uint32)(unsafe.Pointer(&ifr[unix.IFNAMSIZ])) = uint32(n)
_, _, errno := unix.Syscall(
unix.SYS_IOCTL,
uintptr(fd),
uintptr(unix.SIOCSIFMTU),
uintptr(unsafe.Pointer(&ifr[0])),
)
if errno != 0 {
return fmt.Errorf("failed to set MTU of TUN device: %w", errno)
}
return nil
}
func (tap *NativeTap) MTU() (int, error) {
name, err := tap.Name()
if err != nil {
return 0, err
}
// open datagram socket
fd, err := unix.Socket(
unix.AF_INET,
unix.SOCK_DGRAM,
0,
)
if err != nil {
return 0, err
}
defer unix.Close(fd)
// do ioctl call
var ifr [ifReqSize]byte
copy(ifr[:], name)
_, _, errno := unix.Syscall(
unix.SYS_IOCTL,
uintptr(fd),
uintptr(unix.SIOCGIFMTU),
uintptr(unsafe.Pointer(&ifr[0])),
)
if errno != 0 {
return 0, fmt.Errorf("failed to get MTU of TUN device: %w", errno)
}
return int(*(*int32)(unsafe.Pointer(&ifr[unix.IFNAMSIZ]))), nil
}
func (tap *NativeTap) Name() (string, error) {
tap.nameOnce.Do(tap.initNameCache)
return tap.nameCache, tap.nameErr
}
func (tap *NativeTap) initNameCache() {
tap.nameCache, tap.nameErr = tap.nameSlow()
}
func (tap *NativeTap) nameSlow() (string, error) {
sysconn, err := tap.tapFile.SyscallConn()
if err != nil {
return "", err
}
var ifr [ifReqSize]byte
var errno syscall.Errno
err = sysconn.Control(func(fd uintptr) {
_, _, errno = unix.Syscall(
unix.SYS_IOCTL,
fd,
uintptr(unix.TUNGETIFF),
uintptr(unsafe.Pointer(&ifr[0])),
)
})
if err != nil {
return "", fmt.Errorf("failed to get name of TUN device: %w", err)
}
if errno != 0 {
return "", fmt.Errorf("failed to get name of TUN device: %w", errno)
}
name := ifr[:]
if i := bytes.IndexByte(name, 0); i != -1 {
name = name[:i]
}
return string(name), nil
}
func (tap *NativeTap) Write(buf []byte, offset int) (int, error) {
buf = buf[offset:]
n, err := tap.tapFile.Write(buf)
if errors.Is(err, syscall.EBADFD) {
err = os.ErrClosed
}
return n, err
}
func (tap *NativeTap) Flush() error {
// TODO: can flushing be implemented by buffering and using sendmmsg?
return nil
}
func (tap *NativeTap) Read(buf []byte, offset int) (n int, err error) {
select {
case err = <-tap.errors:
default:
n, err = tap.tapFile.Read(buf[offset:])
if errors.Is(err, syscall.EBADFD) {
err = os.ErrClosed
}
}
return
}
func (tap *NativeTap) Events() chan Event {
return tap.events
}
func (tap *NativeTap) Close() error {
var err1, err2 error
tap.closeOnce.Do(func() {
if tap.statusListenersShutdown != nil {
close(tap.statusListenersShutdown)
if tap.netlinkCancel != nil {
err1 = tap.netlinkCancel.Cancel()
}
} else if tap.events != nil {
close(tap.events)
}
err2 = tap.tapFile.Close()
})
if err1 != nil {
return err1
}
return err2
}
func CreateTAP(iconfig config.InterfaceConf) (Device, error) {
nfd, err := unix.Open(cloneDevicePath, os.O_RDWR, 0)
if err != nil {
if os.IsNotExist(err) {
return nil, fmt.Errorf("CreateTAP(%q) failed; %s does not exist", iconfig.Name, cloneDevicePath)
}
return nil, err
}
var ifr [ifReqSize]byte
var flags uint16 = unix.IFF_TAP | unix.IFF_NO_PI // (disabled for TUN status hack)
if err != nil {
fmt.Println("ERROR: Failed parse mac address:", iconfig.MacAddrPrefix)
return nil, err
}
nameBytes := []byte(iconfig.Name)
if len(nameBytes) >= unix.IFNAMSIZ {
return nil, fmt.Errorf("interface name too long: %w", unix.ENAMETOOLONG)
}
copy(ifr[:], nameBytes)
*(*uint16)(unsafe.Pointer(&ifr[unix.IFNAMSIZ])) = flags
_, _, errno := unix.Syscall(
unix.SYS_IOCTL,
uintptr(nfd),
uintptr(unix.TUNSETIFF),
uintptr(unsafe.Pointer(&ifr[0])),
)
if errno != 0 {
return nil, errno
}
err = unix.SetNonblock(nfd, true)
// Note that the above -- open,ioctl,nonblock -- must happen prior to handing it to netpoll as below this line.
fd := os.NewFile(uintptr(nfd), cloneDevicePath)
if err != nil {
return nil, err
}
return CreateTAPFromFile(fd, iconfig)
}
func CreateTAPFromFile(file *os.File, iconfig config.InterfaceConf) (Device, error) {
tap := &NativeTap{
tapFile: file,
events: make(chan Event, 5),
errors: make(chan error, 5),
statusListenersShutdown: make(chan struct{}),
nopi: false,
}
name, err := tap.Name()
if err != nil {
return nil, err
}
// start event listener
tap.index, err = getIFIndex(name)
if err != nil {
return nil, err
}
tap.netlinkSock, err = createNetlinkSocket()
if err != nil {
return nil, err
}
tap.netlinkCancel, err = rwcancel.NewRWCancel(tap.netlinkSock)
if err != nil {
unix.Close(tap.netlinkSock)
return nil, err
}
tap.hackListenerClosed.Lock()
go tap.routineNetlinkListener()
go tap.routineHackListener() // cross namespace
err = tap.setMTU(iconfig.MTU)
if err != nil {
unix.Close(tap.netlinkSock)
return nil, err
}
IfMacAddr, err := GetMacAddr(iconfig.MacAddrPrefix, iconfig.VPPIfaceID)
if err != nil {
fmt.Println("ERROR: Failed parse mac address:", iconfig.MacAddrPrefix)
return nil, err
}
err = tap.setMacAddr(IfMacAddr)
if err != nil {
unix.Close(tap.netlinkSock)
return nil, err
}
return tap, nil
}
func CreateUnmonitoredTUNFromFD(fd int) (Device, string, error) {
err := unix.SetNonblock(fd, true)
if err != nil {
return nil, "", err
}
file := os.NewFile(uintptr(fd), "/dev/tap")
tap := &NativeTap{
tapFile: file,
events: make(chan Event, 5),
errors: make(chan error, 5),
nopi: true,
}
name, err := tap.Name()
if err != nil {
return nil, "", err
}
return tap, name, nil
}

View File

@ -3,42 +3,71 @@ package tap
import (
"fmt"
"os"
"github.com/KusakabeSi/EtherGuardVPN/config"
)
type L2MODE uint8
const (
NoChange L2MODE = iota
KeyboardDebug //Register to server
BoardcastAndNodeID
)
func GetL2Mode(mode string) L2MODE {
switch mode {
case "nochg":
return NoChange
case "kbdbg":
return KeyboardDebug
case "noL2":
return BoardcastAndNodeID
}
return NoChange
}
type StdIOTap struct {
name string
mtu int
HumanFriendly bool
events chan Event
name string
mtu int
macaddr MacAddress
L2mode L2MODE
events chan Event
}
func Charform2mac(b byte) MacAddress {
if b == 'b' {
return MacAddress{0xff, 0xff, 0xff, 0xff, 0xff, 0xff}
}
return MacAddress{0xff, 0xff, 0xff, 0xff, 0xff, b - 48}
return MacAddress{0x00, 0x11, 0xff, 0xff, 0xff, b - 48}
}
func Mac2charForm(m []byte) byte {
var M MacAddress
copy(M[:], m)
if IsBoardCast(M) {
if IsNotUnicast(M) {
return 'b'
}
return m[5] + 48
}
// New creates and returns a new TUN interface for the application.
func CreateStdIOTAP(interfaceName string, HumanFriendly bool) (tapdev Device, err error) {
func CreateStdIOTAP(iconfig config.InterfaceConf) (tapdev Device, err error) {
// Setup TUN Config
if err != nil {
fmt.Println(err.Error())
}
macaddr, err := GetMacAddr(iconfig.MacAddrPrefix, iconfig.VPPIfaceID)
if err != nil {
fmt.Println("ERROR: Failed parse mac address:", iconfig.MacAddrPrefix)
return nil, err
}
tapdev = &StdIOTap{
name: interfaceName,
mtu: 1500,
HumanFriendly: HumanFriendly,
events: make(chan Event, 1<<5),
name: iconfig.Name,
mtu: 1500,
macaddr: macaddr,
L2mode: GetL2Mode(iconfig.L2HeaderMode),
events: make(chan Event, 1<<5),
}
tapdev.Events() <- EventUp
return
@ -48,7 +77,8 @@ func CreateStdIOTAP(interfaceName string, HumanFriendly bool) (tapdev Device, er
// Packet on the interface.
func (tap *StdIOTap) Read(buf []byte, offset int) (int, error) {
if tap.HumanFriendly {
switch tap.L2mode {
case KeyboardDebug:
size, err := os.Stdin.Read(buf[offset+10:])
packet := buf[offset:]
src := Charform2mac(packet[11])
@ -56,22 +86,36 @@ func (tap *StdIOTap) Read(buf []byte, offset int) (int, error) {
copy(packet[0:6], dst[:])
copy(packet[6:12], src[:])
return size - 2 + 12, err
} else {
case BoardcastAndNodeID:
size, err := os.Stdin.Read(buf[offset+12:])
packet := buf[offset:]
src := tap.macaddr
dst := Charform2mac('b')
copy(packet[0:6], dst[:])
copy(packet[6:12], src[:])
return size + 12, err
default:
size, err := os.Stdin.Read(buf[offset:])
return size, err
}
} // read a packet from the device (without any additional headers)
func (tap *StdIOTap) Write(buf []byte, offset int) (size int, err error) {
packet := buf[offset:]
if tap.HumanFriendly {
switch tap.L2mode {
case KeyboardDebug:
src := Mac2charForm(packet[6:12])
dst := Mac2charForm(packet[0:6])
packet[10] = dst
packet[11] = src
packet = packet[10:]
size, err = os.Stdout.Write(packet[10:])
return
case BoardcastAndNodeID:
size, err = os.Stdout.Write(packet[12:])
return
default:
size, err = os.Stdout.Write(packet)
return
}
size, err = os.Stdout.Write(packet)
return
} // writes a packet to the device (without any additional headers)
func (tap *StdIOTap) Flush() error {
return nil

View File

@ -3,32 +3,41 @@ package tap
import (
"fmt"
"net"
"github.com/KusakabeSi/EtherGuardVPN/config"
)
type UdpSockTap struct {
name string
mtu int
recv *net.UDPConn
send *net.UDPAddr
HumanFriendly bool
events chan Event
name string
mtu int
recv *net.UDPConn
send *net.UDPAddr
L2mode L2MODE
macaddr MacAddress
events chan Event
}
// New creates and returns a new TUN interface for the application.
func CreateUDPSockTAP(interfaceName string, listenAddr *net.UDPAddr, sendAddr *net.UDPAddr, HumanFriendly bool) (tapdev Device, err error) {
func CreateUDPSockTAP(iconfig config.InterfaceConf, listenAddr *net.UDPAddr, sendAddr *net.UDPAddr) (tapdev Device, err error) {
// Setup TUN Config
listener, err := net.ListenUDP("udp", listenAddr)
if err != nil {
fmt.Println(err.Error())
}
macaddr, err := GetMacAddr(iconfig.MacAddrPrefix, iconfig.VPPIfaceID)
if err != nil {
fmt.Println("ERROR: Failed parse mac address:", iconfig.MacAddrPrefix)
return nil, err
}
tapdev = &UdpSockTap{
name: interfaceName,
mtu: 1500,
recv: listener,
send: sendAddr,
HumanFriendly: HumanFriendly,
events: make(chan Event, 1<<5),
name: iconfig.Name,
mtu: 1500,
recv: listener,
send: sendAddr,
macaddr: macaddr,
L2mode: GetL2Mode(iconfig.L2HeaderMode),
events: make(chan Event, 1<<5),
}
tapdev.Events() <- EventUp
return
@ -38,15 +47,24 @@ func CreateUDPSockTAP(interfaceName string, listenAddr *net.UDPAddr, sendAddr *n
// Packet on the interface.
func (tap *UdpSockTap) Read(buf []byte, offset int) (int, error) {
if tap.HumanFriendly {
switch tap.L2mode {
case KeyboardDebug:
size, _, err := tap.recv.ReadFromUDP(buf[offset+10:])
packet := buf[offset:]
src := Charform2mac(packet[11])
dst := Charform2mac(packet[10])
copy(packet[0:6], dst[:])
copy(packet[6:12], src[:])
return size - 2 + 12, err
} else {
return size + 10, err
case BoardcastAndNodeID:
size, _, err := tap.recv.ReadFromUDP(buf[offset+12:])
packet := buf[offset:]
src := tap.macaddr
dst := Charform2mac('b')
copy(packet[0:6], dst[:])
copy(packet[6:12], src[:])
return size + 12, err
default:
size, _, err := tap.recv.ReadFromUDP(buf[offset:])
return size, err
}
@ -54,16 +72,21 @@ func (tap *UdpSockTap) Read(buf []byte, offset int) (int, error) {
} // read a packet from the device (without any additional headers)
func (tap *UdpSockTap) Write(buf []byte, offset int) (size int, err error) {
packet := buf[offset:]
if tap.HumanFriendly {
switch tap.L2mode {
case KeyboardDebug:
src := Mac2charForm(packet[6:12])
dst := Mac2charForm(packet[0:6])
packet[10] = dst
packet[11] = src
size, err = tap.recv.WriteToUDP(packet[10:], tap.send)
return
case BoardcastAndNodeID:
size, err = tap.recv.WriteToUDP(packet[12:], tap.send)
return
default:
size, err = tap.recv.WriteToUDP(packet, tap.send)
return
}
size, err = tap.recv.WriteToUDP(packet, tap.send)
return
} // writes a packet to the device (without any additional headers)
func (tap *UdpSockTap) Flush() error {
return nil

View File

@ -2,6 +2,7 @@ package tap
import (
"context"
"path"
"errors"
"fmt"
@ -58,7 +59,7 @@ type VppTap struct {
}
// New creates and returns a new TUN interface for the application.
func CreateVppTAP(interfaceName string, iconfig config.InterfaceConf, loglevel string) (tapdev Device, err error) {
func CreateVppTAP(iconfig config.InterfaceConf, loglevel string) (tapdev Device, err error) {
// Setup TUN Config
// Set logger
log := logger.New()
@ -75,10 +76,20 @@ func CreateVppTAP(interfaceName string, iconfig config.InterfaceConf, loglevel s
return logger.ErrorLevel
}()
libmemif.SetLogger(log)
if os.Getenv(ENV_VPP_MEMIF_SOCKET_DIR) != "" {
vppMemifSocketDir = os.Getenv(ENV_VPP_MEMIF_SOCKET_DIR)
}
if os.Getenv(ENV_VPP_SOCKET_PATH) != "" {
vppApiSocketPath = os.Getenv(ENV_VPP_SOCKET_PATH)
}
if err := os.MkdirAll(vppMemifSocketDir, 0755); err != nil {
log.Fatalln("ERROR: Failed to create VPP memif socket folder " + vppMemifSocketDir)
return nil, err
}
// connect to VPP
conn, err := govpp.Connect(vppApiSocketPath)
if err != nil {
log.Fatalln("ERROR: connecting to VPP failed:", err)
log.Fatalln("ERROR: Connecting to VPP failed:", err)
return nil, err
}
defer conn.Disconnect()
@ -105,18 +116,19 @@ func CreateVppTAP(interfaceName string, iconfig config.InterfaceConf, loglevel s
l2service := l2.NewServiceClient(conn)
interfacservice := interfaces.NewServiceClient(conn)
vppIfMacAddr, err := ethernet_types.ParseMacAddress(iconfig.MacAddr)
IfMacAddr, err := GetMacAddr(iconfig.MacAddrPrefix, iconfig.VPPIfaceID)
if err != nil {
log.Fatalln("ERROR: Failed parse mac address:", iconfig.MacAddr)
log.Fatalln("ERROR: Failed parse mac address:", iconfig.MacAddrPrefix)
return nil, err
}
vppIfMacAddr := ethernet_types.MacAddress(IfMacAddr)
tap := &VppTap{
name: iconfig.Name,
mtu: iconfig.MTU,
ifuid: iconfig.VPPIfaceID,
SwIfIndex: 0,
memifSockPath: vppMemifSocketDir + "/" + iconfig.Name,
memifSockPath: path.Join(vppMemifSocketDir, iconfig.Name+".sock"),
secret: config.RandomStr(16, iconfig.Name),
logger: log,
errors: make(chan error, 1<<5),