fastgen static config, update readme

This commit is contained in:
Kusakabe Si 2021-12-09 20:23:02 +00:00
parent d555963227
commit 17fe0cdae3
36 changed files with 719 additions and 540 deletions

View File

@ -82,8 +82,6 @@ VPN起來以後自己手動加ip也行
$ ./etherguard-go -mode gencfg -cfgmode super -config example_config/super_mode/gensuper.yaml
```
把一個super2個edge分別搬去三台機器
或是2台機器super和edge可以是同一台

View File

@ -154,7 +154,7 @@ type Peer struct {
LastPacketReceivedAdd1Sec atomic.Value // *time.Time
SingleWayLatency float64
SingleWayLatency atomic.Value
stopping sync.WaitGroup // routines pending stop
ID mtypes.Vertex
@ -245,7 +245,7 @@ func (device *Device) NewPeer(pk NoisePublicKey, id mtypes.Vertex, isSuper bool,
peer.cookieGenerator.Init(pk)
peer.device = device
peer.endpoint_trylist = NewEndpoint_trylist(peer, mtypes.S2TD(device.EdgeConfig.DynamicRoute.PeerAliveTimeout))
peer.SingleWayLatency = mtypes.Infinity
peer.SingleWayLatency.Store(mtypes.Infinity)
peer.queue.outbound = newAutodrainingOutboundQueue(device)
peer.queue.inbound = newAutodrainingInboundQueue(device)
peer.queue.staged = make(chan *QueueOutboundElement, QueueStagedSize)

View File

@ -470,39 +470,76 @@ func (peer *Peer) RoutineSequentialReceiver() {
packet_type = elem.Type
if device.IsSuperNode {
switch dst_nodeID {
case mtypes.NodeID_AllPeer:
if packet_type.IsControl_Edge2Super() {
should_process = true
} else {
device.log.Errorf("received unsupported packet_type %v from %v %v", packet_type, src_nodeID, peer.endpoint.DstToString())
goto skip
}
switch dst_nodeID {
case mtypes.NodeID_SuperNode:
should_process = true
default:
device.log.Errorf("Invalid dst_nodeID received. Check your code for bug")
device.log.Errorf("received invalid dst_nodeID %v from %v %v", dst_nodeID, src_nodeID, peer.endpoint.DstToString())
goto skip
}
} else {
// Set should_receive and should_process
if packet_type.IsNormal() {
switch dst_nodeID {
case mtypes.NodeID_Boardcast:
case device.ID:
should_receive = true
should_transfer = true
case mtypes.NodeID_SuperNode:
case mtypes.NodeID_Broadcast:
should_receive = true
case mtypes.NodeID_AllPeer:
should_receive = true
}
}
if packet_type.IsControl_Edge2Edge() {
switch dst_nodeID {
case device.ID:
should_process = true
case mtypes.NodeID_Broadcast:
should_process = true
case mtypes.NodeID_AllPeer:
packet := elem.packet[path.EgHeaderLen:] //true packet
if device.CheckNoDup(packet) {
should_process = true
}
}
if packet_type.IsControl_Super2Edge() {
if peer.ID == mtypes.NodeID_SuperNode {
switch dst_nodeID {
case device.ID:
should_process = true
case mtypes.NodeID_SuperNode:
should_process = true
}
} else {
device.log.Errorf("received ServerUpdate packet from non supernode %v %v", src_nodeID, peer.endpoint.DstToString())
goto skip
}
}
// Set should_transfer
switch dst_nodeID {
case mtypes.NodeID_Broadcast:
should_transfer = true
case mtypes.NodeID_AllPeer:
packet := elem.packet[path.EgHeaderLen:] //packet body
if device.CheckNoDup(packet) {
should_transfer = true
} else {
should_process = false
should_transfer = false
if device.LogLevel.LogTransit {
fmt.Printf("Transit: Duplicate packet received from %d through %d , src_nodeID = %d . Dropeed.\n", peer.ID, device.ID, src_nodeID)
fmt.Printf("Transit: Duplicate packet received from %d through %d , src_nodeID = %d . Dropped.\n", peer.ID, device.ID, src_nodeID)
}
goto skip
}
case device.ID:
if packet_type == path.NormalPacket {
should_receive = true
} else {
should_process = true
}
should_transfer = false
case mtypes.NodeID_SuperNode:
should_transfer = false
case mtypes.NodeID_Invalid:
should_transfer = false
default:
if device.graph.Next(device.ID, dst_nodeID) != mtypes.NodeID_Invalid {
should_transfer = true
@ -517,7 +554,7 @@ func (peer *Peer) RoutineSequentialReceiver() {
device.log.Verbosef("TTL is 0 %v", dst_nodeID)
} else {
EgHeader.SetTTL(l2ttl - 1)
if dst_nodeID == mtypes.NodeID_Boardcast { //Regular transfer algorithm
if dst_nodeID == mtypes.NodeID_Broadcast { //Regular transfer algorithm
device.TransitBoardcastPacket(src_nodeID, peer.ID, elem.Type, elem.packet, MessageTransportOffsetContent)
} else if dst_nodeID == mtypes.NodeID_AllPeer { // Control Message will try send to every know node regardless the connectivity
skip_list := make(map[mtypes.Vertex]bool)
@ -534,7 +571,7 @@ func (peer *Peer) RoutineSequentialReceiver() {
if device.LogLevel.LogTransit {
fmt.Printf("Transit: Transfer packet from %d through %d to %d\n", peer.ID, device.ID, peer_out.ID)
}
device.SendPacket(peer_out, elem.Type, elem.packet, MessageTransportOffsetContent)
go device.SendPacket(peer_out, elem.Type, elem.packet, MessageTransportOffsetContent)
}
}
}

View File

@ -309,17 +309,20 @@ func (device *Device) server_process_Pong(peer *Peer, content mtypes.PongMsg) er
func (device *Device) process_ping(peer *Peer, content mtypes.PingMsg) error {
Timediff := device.graph.GetCurrentTime().Sub(content.Time).Seconds()
peer.SingleWayLatency = Timediff
NewTimediff := peer.SingleWayLatency.Load().(float64)
DR := NewTimediff * device.EdgeConfig.DynamicRoute.P2P.GraphRecalculateSetting.DampingResistance
NewTimediff = NewTimediff*DR + Timediff*(1-DR)
peer.SingleWayLatency.Store(NewTimediff)
PongMSG := mtypes.PongMsg{
Src_nodeID: content.Src_nodeID,
Dst_nodeID: device.ID,
Timediff: Timediff,
Timediff: NewTimediff,
TimeToAlive: device.EdgeConfig.DynamicRoute.PeerAliveTimeout,
AdditionalCost: device.EdgeConfig.DynamicRoute.AdditionalCost,
}
if device.EdgeConfig.DynamicRoute.P2P.UseP2P && time.Now().After(device.graph.NhTableExpire) {
device.graph.UpdateLatency(content.Src_nodeID, device.ID, PongMSG.Timediff, device.EdgeConfig.DynamicRoute.PeerAliveTimeout, device.EdgeConfig.DynamicRoute.AdditionalCost, true, false)
device.graph.UpdateLatencyMulti([]mtypes.PongMsg{PongMSG}, true, false)
}
body, err := mtypes.GetByte(&PongMSG)
if err != nil {
@ -887,7 +890,7 @@ func (device *Device) RoutinePostPeerInfo(startchan <-chan struct{}) {
RequestID: 0,
Src_nodeID: device.ID,
Dst_nodeID: id,
Timediff: peer.SingleWayLatency,
Timediff: peer.SingleWayLatency.Load().(float64),
TimeToAlive: time.Since(*peer.LastPacketReceivedAdd1Sec.Load().(*time.Time)).Seconds() + device.EdgeConfig.DynamicRoute.PeerAliveTimeout,
}
pongs = append(pongs, pong)
@ -989,7 +992,7 @@ func (device *Device) RoutineSpreadAllMyNeighbor() {
timeout := mtypes.S2TD(device.EdgeConfig.DynamicRoute.P2P.SendPeerInterval)
for {
device.process_RequestPeerMsg(mtypes.QueryPeerMsg{
Request_ID: uint32(mtypes.NodeID_Boardcast),
Request_ID: uint32(mtypes.NodeID_Broadcast),
})
time.Sleep(timeout)
}

View File

@ -256,9 +256,9 @@ func (device *Device) RoutineReadFromTUN() {
dstMacAddr := tap.GetDstMacAddr(elem.packet[path.EgHeaderLen:])
// lookup peer
if tap.IsNotUnicast(dstMacAddr) {
dst_nodeID = mtypes.NodeID_Boardcast
dst_nodeID = mtypes.NodeID_Broadcast
} else if val, ok := device.l2fib.Load(dstMacAddr); !ok { //Lookup failed
dst_nodeID = mtypes.NodeID_Boardcast
dst_nodeID = mtypes.NodeID_Broadcast
} else {
dst_nodeID = val.(*IdAndTime).ID
}
@ -275,7 +275,7 @@ func (device *Device) RoutineReadFromTUN() {
continue
}
if dst_nodeID != mtypes.NodeID_Boardcast {
if dst_nodeID != mtypes.NodeID_Broadcast {
var peer *Peer
next_id := device.graph.Next(device.ID, dst_nodeID)
if next_id != mtypes.NodeID_Invalid {

View File

@ -3,7 +3,7 @@ Interface:
Name: tap1
VPPIFaceID: 1
VPPBridgeID: 4242
MacAddrPrefix: 8E:AA:C8:4B
MacAddrPrefix: DA:21:10:81
IPv4CIDR: 192.168.76.0/24
IPv6CIDR: fd95:71cb:a3df:e586::/64
IPv6LLPrefix: fe80::a3df:0/112
@ -12,17 +12,17 @@ Interface:
SendAddr: 127.0.0.1:5001
L2HeaderMode: kbdbg
NodeID: 1
NodeName: Node1
NodeName: EgNet1
PostScript: ""
DefaultTTL: 200
L2FIBTimeout: 3600
PrivKey: Fe9Q6K5L6xTVbx/zFc07tnQuo+pkeyrhfoTQ3BF5GRM=
PrivKey: LFFQqPBQ84x2AQ9BCI+0wG8nr+Y6yXHqhXkMCb4HCmg=
ListenPort: 3001
LogLevel:
LogLevel: error
LogTransit: true
LogControl: true
LogNormal: true
LogControl: true
LogInternal: true
LogNTP: true
DynamicRoute:
@ -100,8 +100,8 @@ NextHopTable:
ResetConnInterval: 86400
Peers:
- NodeID: 2
PubKey: MC8dHNj8u/RrK9iL6ln+AaGZWkMrDl+8aUoyxbsBZC4=
PSKey: kWDwCaC11UvYjfiXBMwYpR6Pujo1vaVW8JTusp1Kkrw=
PubKey: 0r2o9Hb36gYVgD3VSKCH18MVOZw0BvzcJ6TOTo6Cc1g=
PSKey: lFq67qp9LXL3PtlEJ3SGg3c/6++Ljy2I8i/k0Xcibvk=
EndPoint: 127.0.0.1:3002
PersistentKeepalive: 30
PersistentKeepalive: 0
Static: true

View File

@ -3,7 +3,7 @@ Interface:
Name: tap1
VPPIFaceID: 1
VPPBridgeID: 4242
MacAddrPrefix: 8E:AA:C8:4B
MacAddrPrefix: DA:21:10:81
IPv4CIDR: 192.168.76.0/24
IPv6CIDR: fd95:71cb:a3df:e586::/64
IPv6LLPrefix: fe80::a3df:0/112
@ -12,17 +12,17 @@ Interface:
SendAddr: 127.0.0.1:5001
L2HeaderMode: kbdbg
NodeID: 2
NodeName: Node2
NodeName: EgNet2
PostScript: ""
DefaultTTL: 200
L2FIBTimeout: 3600
PrivKey: WaeR98bFhy0rxw7unsaTo7aR2RmySo9l185IZqPWl1c=
PrivKey: M8SxYCTHCPES/yPqcKP4mr+AoMAx9sgUmk64FCJIv6k=
ListenPort: 3002
LogLevel:
LogLevel: error
LogTransit: true
LogControl: true
LogNormal: true
LogControl: true
LogInternal: true
LogNTP: true
DynamicRoute:
@ -100,20 +100,20 @@ NextHopTable:
ResetConnInterval: 86400
Peers:
- NodeID: 1
PubKey: iDhQA9pgL01Gb0MrPzbiV80P4Uv3+uY/s+wNTQye0Qo=
PSKey: kWDwCaC11UvYjfiXBMwYpR6Pujo1vaVW8JTusp1Kkrw=
PubKey: fnc7bfFTf7B23hwtARPpX14tCeZwNfDhGCJctBpMfA8=
PSKey: lFq67qp9LXL3PtlEJ3SGg3c/6++Ljy2I8i/k0Xcibvk=
EndPoint: 127.0.0.1:3001
PersistentKeepalive: 0
Static: true
- NodeID: 3
PubKey: 1vg9bSyqjDL8oUdqpKXn/RR96cjTHPCBga0vaw86WzU=
PSKey: f2/34zUTLx8RP9cYisESoQlxz55oGZlTemqxv25VVa8=
PubKey: ymNpm430tiph3rMSVnQzDAxmK9+3jdcRFi6e96xmQUI=
PSKey: Y86PZY1ldgoyzPJxEqei5Vg5zlzkJkoO77LJfxV8alE=
EndPoint: 127.0.0.1:3003
PersistentKeepalive: 0
Static: true
- NodeID: 4
PubKey: WkBYMUcQwWwUlDYh7uLu4YefiH1yXb3Tkf3wGEtE6HY=
PSKey: zkG1ywPqS4MiGofuWmxHHBs8YBlnYd04B4T9IhkbXYM=
PubKey: 9YSIkihv/+aeukOaWwsR9EKvO1DM9+5kN53a/osTpmA=
PSKey: QHyrrls0KT2dvBKtoWkZvq5NQ+Xyjm0YgbMUzCCRw34=
EndPoint: 127.0.0.1:3004
PersistentKeepalive: 30
PersistentKeepalive: 0
Static: true

View File

@ -3,7 +3,7 @@ Interface:
Name: tap1
VPPIFaceID: 1
VPPBridgeID: 4242
MacAddrPrefix: 8E:AA:C8:4B
MacAddrPrefix: DA:21:10:81
IPv4CIDR: 192.168.76.0/24
IPv6CIDR: fd95:71cb:a3df:e586::/64
IPv6LLPrefix: fe80::a3df:0/112
@ -12,17 +12,17 @@ Interface:
SendAddr: 127.0.0.1:5001
L2HeaderMode: kbdbg
NodeID: 3
NodeName: Node3
NodeName: EgNet3
PostScript: ""
DefaultTTL: 200
L2FIBTimeout: 3600
PrivKey: vNUFWbZXySk2dTl5R9UEG73p+4IQmywvC1uQStf0vao=
PrivKey: cTO/GUSYHoj5mKczCyQu/ckPiDMEygkUbXcY3RafGEE=
ListenPort: 3003
LogLevel:
LogLevel: error
LogTransit: true
LogControl: true
LogNormal: true
LogControl: true
LogInternal: true
LogNTP: true
DynamicRoute:
@ -99,21 +99,21 @@ NextHopTable:
5: 4
ResetConnInterval: 86400
Peers:
- NodeID: 5
PubKey: AarP7cL6TVmFyHRZLXuxFGr5uQghsp57ydsJdj+lGzs=
PSKey: +TU8Zi8dr/UBqNyW/MYMgJiqkLnRbHW4ExQYQ2eNEag=
EndPoint: 127.0.0.1:3005
PersistentKeepalive: 0
Static: true
- NodeID: 2
PubKey: MC8dHNj8u/RrK9iL6ln+AaGZWkMrDl+8aUoyxbsBZC4=
PSKey: f2/34zUTLx8RP9cYisESoQlxz55oGZlTemqxv25VVa8=
PubKey: 0r2o9Hb36gYVgD3VSKCH18MVOZw0BvzcJ6TOTo6Cc1g=
PSKey: Y86PZY1ldgoyzPJxEqei5Vg5zlzkJkoO77LJfxV8alE=
EndPoint: 127.0.0.1:3002
PersistentKeepalive: 0
Static: true
- NodeID: 4
PubKey: WkBYMUcQwWwUlDYh7uLu4YefiH1yXb3Tkf3wGEtE6HY=
PSKey: 8HN+PBGDKmBFCDlWIyNUFFYS4X6ONGXI32AIKXSnUqU=
PubKey: 9YSIkihv/+aeukOaWwsR9EKvO1DM9+5kN53a/osTpmA=
PSKey: SQyLomXDeknBIFezUKardOviAmNS+YZ1XTvZtYVlOtE=
EndPoint: 127.0.0.1:3004
PersistentKeepalive: 30
PersistentKeepalive: 0
Static: true
- NodeID: 5
PubKey: x66hOjYXoZjL1FI3OVtf/CWittsnvmezKV6sW0v5FXQ=
PSKey: ChWBQurfGNZE5xIlhi9EUvZrQPBvkFsfrPaD6tyqSYg=
EndPoint: 127.0.0.1:3005
PersistentKeepalive: 0
Static: true

View File

@ -3,7 +3,7 @@ Interface:
Name: tap1
VPPIFaceID: 1
VPPBridgeID: 4242
MacAddrPrefix: 8E:AA:C8:4B
MacAddrPrefix: DA:21:10:81
IPv4CIDR: 192.168.76.0/24
IPv6CIDR: fd95:71cb:a3df:e586::/64
IPv6LLPrefix: fe80::a3df:0/112
@ -12,17 +12,17 @@ Interface:
SendAddr: 127.0.0.1:5001
L2HeaderMode: kbdbg
NodeID: 4
NodeName: Node4
NodeName: EgNet4
PostScript: ""
DefaultTTL: 200
L2FIBTimeout: 3600
PrivKey: sn0BUwyNxfmgePYi6O6a8pFDKiLaCz6jk3ws+covRTA=
PrivKey: ai9XXdezwamYHf7EvzmLGlMp7mUg+hZwoqLefzwHWVM=
ListenPort: 3004
LogLevel:
LogLevel: error
LogTransit: true
LogControl: true
LogNormal: true
LogControl: true
LogInternal: true
LogNTP: true
DynamicRoute:
@ -100,20 +100,20 @@ NextHopTable:
ResetConnInterval: 86400
Peers:
- NodeID: 2
PubKey: MC8dHNj8u/RrK9iL6ln+AaGZWkMrDl+8aUoyxbsBZC4=
PSKey: zkG1ywPqS4MiGofuWmxHHBs8YBlnYd04B4T9IhkbXYM=
PubKey: 0r2o9Hb36gYVgD3VSKCH18MVOZw0BvzcJ6TOTo6Cc1g=
PSKey: QHyrrls0KT2dvBKtoWkZvq5NQ+Xyjm0YgbMUzCCRw34=
EndPoint: 127.0.0.1:3002
PersistentKeepalive: 0
Static: true
- NodeID: 3
PubKey: 1vg9bSyqjDL8oUdqpKXn/RR96cjTHPCBga0vaw86WzU=
PSKey: 8HN+PBGDKmBFCDlWIyNUFFYS4X6ONGXI32AIKXSnUqU=
PubKey: ymNpm430tiph3rMSVnQzDAxmK9+3jdcRFi6e96xmQUI=
PSKey: SQyLomXDeknBIFezUKardOviAmNS+YZ1XTvZtYVlOtE=
EndPoint: 127.0.0.1:3003
PersistentKeepalive: 0
Static: true
- NodeID: 6
PubKey: GH6ra6xhDezskkJrr/DXPi93vtmhi96DFBJ3s8U20EA=
PSKey: f50pI53AQ6RoTGEnTSjl5YJhuMS/xiJjwtPuiP0xMUM=
PubKey: f6kHXq3qPLocdM0CZEkoumOHevrabzqOBFG5vg9cjDc=
PSKey: crsb9pbTY/Bei7TugjPNtg4dVKVzjwC/A6AjlSVoqbQ=
EndPoint: 127.0.0.1:3006
PersistentKeepalive: 30
PersistentKeepalive: 0
Static: true

View File

@ -3,7 +3,7 @@ Interface:
Name: tap1
VPPIFaceID: 1
VPPBridgeID: 4242
MacAddrPrefix: 8E:AA:C8:4B
MacAddrPrefix: DA:21:10:81
IPv4CIDR: 192.168.76.0/24
IPv6CIDR: fd95:71cb:a3df:e586::/64
IPv6LLPrefix: fe80::a3df:0/112
@ -12,17 +12,17 @@ Interface:
SendAddr: 127.0.0.1:5001
L2HeaderMode: kbdbg
NodeID: 5
NodeName: Node5
NodeName: EgNet5
PostScript: ""
DefaultTTL: 200
L2FIBTimeout: 3600
PrivKey: Blk9f1+NiC2fVCZpUBG34G9hrcLThemk/1Zd/dET6AA=
PrivKey: hBNK6Wu/Cl2MOXVA/F8yZsqIQ5eeIYCKPJeLu7i/190=
ListenPort: 3005
LogLevel:
LogLevel: error
LogTransit: true
LogControl: true
LogNormal: true
LogControl: true
LogInternal: true
LogNTP: true
DynamicRoute:
@ -100,8 +100,8 @@ NextHopTable:
ResetConnInterval: 86400
Peers:
- NodeID: 3
PubKey: 1vg9bSyqjDL8oUdqpKXn/RR96cjTHPCBga0vaw86WzU=
PSKey: +TU8Zi8dr/UBqNyW/MYMgJiqkLnRbHW4ExQYQ2eNEag=
PubKey: ymNpm430tiph3rMSVnQzDAxmK9+3jdcRFi6e96xmQUI=
PSKey: ChWBQurfGNZE5xIlhi9EUvZrQPBvkFsfrPaD6tyqSYg=
EndPoint: 127.0.0.1:3003
PersistentKeepalive: 30
PersistentKeepalive: 0
Static: true

View File

@ -3,7 +3,7 @@ Interface:
Name: tap1
VPPIFaceID: 1
VPPBridgeID: 4242
MacAddrPrefix: 8E:AA:C8:4B
MacAddrPrefix: DA:21:10:81
IPv4CIDR: 192.168.76.0/24
IPv6CIDR: fd95:71cb:a3df:e586::/64
IPv6LLPrefix: fe80::a3df:0/112
@ -12,17 +12,17 @@ Interface:
SendAddr: 127.0.0.1:5001
L2HeaderMode: kbdbg
NodeID: 6
NodeName: Node6
NodeName: EgNet6
PostScript: ""
DefaultTTL: 200
L2FIBTimeout: 3600
PrivKey: h03OJ1d8cVGF8TemiWWTla7RCIMtInhUnjs2CBb8AT8=
PrivKey: ao6wfUYOG3FBYYPlb+VtXk2ZiK6j/6ac75Y9VuKd2Vs=
ListenPort: 3006
LogLevel:
LogLevel: error
LogTransit: true
LogControl: true
LogNormal: true
LogControl: true
LogInternal: true
LogNTP: true
DynamicRoute:
@ -100,8 +100,8 @@ NextHopTable:
ResetConnInterval: 86400
Peers:
- NodeID: 4
PubKey: WkBYMUcQwWwUlDYh7uLu4YefiH1yXb3Tkf3wGEtE6HY=
PSKey: f50pI53AQ6RoTGEnTSjl5YJhuMS/xiJjwtPuiP0xMUM=
PubKey: 9YSIkihv/+aeukOaWwsR9EKvO1DM9+5kN53a/osTpmA=
PSKey: crsb9pbTY/Bei7TugjPNtg4dVKVzjwC/A6AjlSVoqbQ=
EndPoint: 127.0.0.1:3004
PersistentKeepalive: 30
PersistentKeepalive: 0
Static: true

View File

@ -1,84 +1,105 @@
# Etherguard
[English](README.md)
Static Mode的[範例配置檔](./)的說明文件
[English](README.md) | [中文](#)
## Static Mode
沒有自動選路,沒有握手伺服器
類似原本的wireguard一切都要提前配置好
設定檔裡面的`NextHopTable`部分,只有此模式會生效
十分類似原本的wireguard一切都要提前配置好
但是除了peer以外還要額外配置轉發表所有人共用一份轉發表
設定檔裡面的`nexthoptable`部分,只有此模式會生效
這個模式下不存在任何的Control Message斷線偵測甚麼的也不會有
這個模式下不存在任何的Control Message斷線偵測什麼的也不會有
請務必保持提前定義好的拓樸。不然如果存在中轉,中轉節點斷了,部分連線就會中斷
## Quick Start
首先,按照需求修改`genstatic.yaml`
```yaml
Config output dir: /tmp/eg_gen_static # 設定檔輸出位置
ConfigTemplate for edge node: "" # 設定檔Template
Network name: "EgNet"
Edge Node:
MacAddress prefix: "" # 留空隨機產生
IPv4 range: 192.168.76.0/24 # 順帶一提IP的部分可以直接省略沒關係
IPv6 range: fd95:71cb:a3df:e586::/64 # 這個欄位唯一的目的只是在啟動以後調用ip命令幫tap接口加個ip
IPv6 LL range: fe80::a3df:0/112 # 和VPN本身運作完全無關
Edge Nodes: # 所有的節點相關設定
1:
Endpoint(optional): 127.0.0.1:3001
2:
Endpoint(optional): 127.0.0.1:3002
3:
Endpoint(optional): 127.0.0.1:3003
4:
Endpoint(optional): 127.0.0.1:3004
5:
Endpoint(optional): 127.0.0.1:3005
6:
Endpoint(optional): 127.0.0.1:3006
Distance matrix for all nodes: |- # 左邊是起點上面是終點Inf代表此二節點不相連 ,數值代表相連。數值大小代表通過成本(通常是延遲)
X 1 2 3 4 5 6
1 0 1.0 Inf Inf Inf Inf
2 1.0 0 1.0 1.0 Inf Inf
3 Inf 1.0 0 1 1.0 Inf
4 Inf 1.0 1.0 0 Inf 1.0
5 Inf Inf 1.0 Inf 1.0 Inf
6 Inf Inf Inf 1.0 Inf 1.0
```
接著執行這個,就會生成所需設定檔了。
```
./etherguard-go -mode gencfg -cfgmode static -config example_config/static_mode/genstatic.yaml
```
把這些設定檔不捨去對應節點,然後再執行
```
./etherguard-go -config [設定檔位置] -mode edge
```
就可以了
確認運作以後可以關閉不必要的log增加性能
## Documentation
Static Mode的說明文件
這份[範例配置檔](./)的網路拓樸如圖所示
!["Topology"](https://raw.githubusercontent.com/KusakabeSi/EtherGuard-VPN/master/example_config/static_mode/Example_static.png)
發出封包時會設定起始ID=自己的Node ID終點ID則是看Dst Mac Address。
如果Dst MacAddr是廣播地址或是不在自己的對應表裡面就會設定終點=Boardcast
如果Dst MacAddr是廣播地址或是不在自己的對應表裡面就會設定終點=Broadcast
收到封包的時候,如果`dst==自己ID`,就會收下,不轉給任何人。
同時還會看它的 Src Mac Address 和 Src NodeID ,並加入對應表
這樣下次傳給他就可以直接傳給目標,而不用廣播給全節點了
所以設定檔中的轉發表如下表。格式是yaml的巢狀dictionary
轉發/發送封包時,直接查詢 `NhTable[起點][終點]=下一跳`
轉發/發送封包時,直接查詢`NhTable`
就知道下面一個封包要轉給誰了
NextHopTable 是長這樣的資料結構,`NhTable[起點][終點]=下一跳`
```yaml
nexthoptable:
NextHopTable:
1:
2: 2
3: 2
4: 2
5: 2
6: 2
2:
1: 1
3: 3
4: 4
5: 3
6: 4
3:
1: 2
2: 2
4: 4
5: 5
6: 4
4:
1: 2
2: 2
3: 3
5: 3
6: 6
5:
1: 3
2: 3
3: 3
4: 3
6: 3
6:
1: 4
2: 4
3: 4
4: 4
5: 4
```
### Boardcast
比較特別的是`終點ID=Boardcast`的情況。
### Broadcast
比較特別的是`終點ID=Broadcast`的情況。
假設今天的狀況:我是4號我收到`起點ID = 1終點ID=boardcast`的封包
假設今天的狀況:我是4號我收到`起點ID = 1終點ID=Broadcast`的封包
我應該只轉給6號就好而不會轉給3號。
因為3號會收到來自2號的封包自己就不用重複遞送了
因此我有設計,如果`終點ID = Boardcast`就會檢查Src到自己的所有鄰居會不會經過自己
因此我有設計,如果`終點ID = Broadcast`就會檢查Src到自己的所有鄰居會不會經過自己
**1 -> 6** 會經過自己: [1 2 4 6]
**1 -> 3** 不會: [1 2 3]
2號是封包來源跳過檢查
@ -94,189 +115,97 @@ nexthoptable:
```
X 1 2 3 4 5 6
1 0 0.5 Inf Inf Inf Inf
2 0.5 0 0.5 0.5 Inf Inf
3 Inf 0.5 0 0.5 0.5 Inf
4 Inf 0.5 0.5 0 Inf 0.5
5 Inf Inf 0.5 Inf 0 Inf
6 Inf Inf Inf 0.5 Inf 0
1 0 1.0 Inf Inf Inf Inf
2 1.0 0 1.0 1.0 Inf Inf
3 Inf 1.0 0 1 1.0 Inf
4 Inf 1.0 1.0 0 Inf 1.0
5 Inf Inf 1.0 Inf 1.0 Inf
6 Inf Inf Inf 1.0 Inf 1.0
```
之後用這個指令就能輸出用Floyd Warshall算好的轉發表了填入設定檔即可
```
./etherguard-go -config example_config/static_mode/path.txt -mode slove
NextHopTable:
1:
2: 2
3: 2
4: 2
5: 2
6: 2
2:
1: 1
3: 3
4: 4
5: 3
6: 4
3:
1: 2
2: 2
4: 4
5: 5
6: 4
4:
1: 2
2: 2
3: 3
5: 3
6: 6
5:
1: 3
2: 3
3: 3
4: 3
6: 3
6:
1: 4
2: 4
3: 4
4: 4
5: 4
```
### EdgeNode Config Parameter
程式還會額外輸出一些資訊,像是路徑表。
會標示所有的起點終點組合的封包路徑,還有行經距離
```
Human readable:
src dist path
1 -> 2 0.500000 [1 2]
1 -> 3 1.000000 [1 2 3]
1 -> 4 1.000000 [1 2 4]
1 -> 5 1.500000 [1 2 3 5]
1 -> 6 1.500000 [1 2 4 6]
2 -> 1 0.500000 [2 1]
2 -> 3 0.500000 [2 3]
2 -> 4 0.500000 [2 4]
2 -> 5 1.000000 [2 3 5]
2 -> 6 1.000000 [2 4 6]
3 -> 1 1.000000 [3 2 1]
3 -> 2 0.500000 [3 2]
3 -> 4 0.500000 [3 4]
3 -> 5 0.500000 [3 5]
3 -> 6 1.000000 [3 4 6]
4 -> 1 1.000000 [4 2 1]
4 -> 2 0.500000 [4 2]
4 -> 3 0.500000 [4 3]
4 -> 5 1.000000 [4 3 5]
4 -> 6 0.500000 [4 6]
5 -> 1 1.500000 [5 3 2 1]
5 -> 2 1.000000 [5 3 2]
5 -> 3 0.500000 [5 3]
5 -> 4 1.000000 [5 3 4]
5 -> 6 1.500000 [5 3 4 6]
6 -> 1 1.500000 [6 4 2 1]
6 -> 2 1.000000 [6 4 2]
6 -> 3 1.000000 [6 4 3]
6 -> 4 0.500000 [6 4]
6 -> 5 1.500000 [6 4 3 5]
```
Key | Description
-------------- |:-----
[Interface](#Interface)| 接口相關設定。VPN有兩端一端是VPN網路另一端則是本地接口
NodeID | 節點ID。節點之間辨識身分用的同一網路內節點ID不能重複
NodeName | 節點名稱
PostScript | 初始化完畢之後要跑的腳本
DefaultTTL | TTLetherguard層使用和乙太層不共通
L2FIBTimeout | MacAddr-> NodeID 查找表的 timeout(秒) 類似ARP table
PrivKey | 私鑰和wireguard規格一樣
ListenPort | 監聽的udp埠
[LogLevel](#LogLevel)| 紀錄log
[DynamicRoute](../super_mode/README_zh.md#DynamicRoute) | 動態路由相關設定Static模式用不到
NextHopTable | 轉發表, 下一跳 = `NhTable[起點][終點]`
ResetConnInterval | 如果對方是動態ip就要用這個。每隔一段時間就會重置連線重新解析域名
[Peers](#Peers) | 鄰居節點和wireguard相同
有些設定檔對應某些運作模式,這邊針對共同部分的設定做說明
<a name="Interface"></a>Interface | Description
---------------|:-----
[IType](#IType)| 接口類型意味著從VPN網路收到的封包要丟去哪邊
Name | 裝置名稱
VPPIFaceID | VPP 的 interface ID。同一個VPP runtime內不能重複
VPPBridgeID | VPP 的網橋ID。不使用VPP網橋功能的話填0
MacAddrPrefix | MAC地址前綴。真正的 MAC 地址=[前綴]:[NodeID]
IPv4CIDR | 啟動以後調用ip命令幫tap接口加個ip。僅限tap有效
IPv4CIDR | 啟動以後調用ip命令幫tap接口加個ip。僅限tap有效
IPv6LLPrefix | 啟動以後調用ip命令幫tap接口加個ip。僅限tap有效
MTU | 裝置MTU僅限`tap` , `vpp` 模式有效
RecvAddr | listen地址收到的東西丟去 VPN 網路。僅限`*sock`生效
SendAddr | 連線地址VPN網路收到的東西丟去這個地址。僅限`*sock`生效
[L2HeaderMode](#L2HeaderMode) | 僅限 `stdio` 生效。debug用途有三種模式
### Edge config
<a name="IType"></a>IType | Description
-----------|:-----
dummy | 收到的封包直接丟棄,但幫忙轉發。作為中繼節點,本身不加入網路使用
stdio | 收到的封包丟stdoutstdin進來的資料丟入vpn網路debug用途<br>需要參數: `MacAddrPrefix` && `L2HeaderMode`
udpsock | 收到的封包丟去一個udp socket<br>需要參數: `RecvAddr` && `SendAddr`
tcpsock | 收到的封包丟去一個tcp socket<br>需要參數: `RecvAddr` \|\| `SendAddr`
unixsock | 收到的封包丟去一個unix socket(SOCK_STREAM 模式)<br>需要參數: `RecvAddr` \|\| `SendAddr`
udpsock | 收到的封包丟去一個unix socket(SOCK_DGRAM 模式)<br>需要參數: `RecvAddr` \|\| `SendAddr`
udpsock | 收到的封包丟去一個unix socket(SOCK_SEQPACKET 模式)<br>需要參數: `RecvAddr` \|\| `SendAddr`
fd | 收到的封包丟去一個特定的file descriptor<br>需要參數: 無. 但是使用環境變數 `EG_FD_RX` && `EG_FD_TX` 來指定
vpp | 使用libmemif使vpp加入VPN網路<br>需要參數: `Name` && `VPPIFaceID` && `VPPBridgeID` && `MacAddrPrefix` && `MTU`
tap | Linux的tap設備。讓linux加入VPN網路<br>需要參數: `Name` && `MacAddrPrefix` && `MTU`<br>可選參數:`IPv4CIDR` , `IPv6CIDR` , `IPv6LLPrefix`
1. `interface`
1. `itype`: 裝置類型意味著從VPN網路收到的封包要丟去哪個硬體
1. `dummy`: 收到的封包直接丟棄,也不發出任何封包。作為中繼節點使用
2. `stdio`: 收到的封包丟stdoutstdin進來的資料丟入vpn網路
需要參數: `macaddrprefix`,`l2headermode`
3. `udpsock`: 把VPN網路收到的layer2封包讀寫去一個udp socket.
Paramaters: `recvaddr`,`sendaddr`
3. `tcpsock`: 把VPN網路收到的layer2封包讀寫去一個tcp socket.
Paramaters: `recvaddr`,`sendaddr`
3. `unixsock`: 把VPN網路收到的layer2封包讀寫去一個unix socket(SOCK_STREAM 模式).
Paramaters: `recvaddr`,`sendaddr`
3. `unixgramsock`: 把VPN網路收到的layer2封包讀寫去一個unix socket(SOCK_DGRAM 模式).
Paramaters: `recvaddr`,`sendaddr`
3. `unixpacketsock`: 把VPN網路收到的layer2封包讀寫去一個unix socket(SOCK_SEQPACKET 模式).
Paramaters: `recvaddr`,`sendaddr`
3. `fd`: 把VPN網路收到的layer2封包讀寫去一個特定的file descriptor.
Paramaters: 無. 但是使用環境變數 `EG_FD_RX``EG_FD_TX` 來指定
4. `vpp`: 使用libmemif使vpp加入VPN網路
需要參數: `name`,`vppifaceid`,`vppbridgeid`,`macaddrprefix`,`mtu`
5. `tap`: Linux的tap設備。讓linux加入VPN網路
需要參數: `name`,`macaddrprefix`,`mtu`
2. `name` : 裝置名稱
3. `vppifaceid`: VPP 的 interface ID。一個VPP runtime內不能重複
4. `vppbridgeid`: VPP 的網橋ID。不使用VPP網橋功能的話填0
5. `macaddrprefix`: MAC地址前綴。真正的 MAC 地址=[前綴]:[NodeID]。
如果這邊填了完整6格長度就忽略`NodeID`
6. `recvaddr`: 僅限`XXXsock`生效。listen地址收到的東西丟去 VPN 網路
7. `sendaddr`: 僅限`XXXsock`生效。連線地址VPN網路收到的東西丟去這個地址
8. `l2headermode`: 僅限 `stdio` 生效。debug用途有三種模式:
1. `nochg`: 從 VPN 網路收到什麼就往tap裝置發送什麼。不對封包作任何更動
2. `kbdbg`: 鍵盤bebug模式。搭配 `stdio` 模式,讓我 debug 用
因為前 12 byte 會用來做選路判斷但是只是要debug構造完整的封包就不是很方便
這個模式下如果輸入b2content就會幫你把b轉換成`FF:FF:FF:FF:FF:FF` `2` 轉換成 `AA:BB:CC:DD:EE:02` 。封包內容變成 `b"0xffffffffffffaabbccddee02content"`
用鍵盤就能輕鬆產生L2 header查看選路的行為
3. `noL2`: 拔掉L2 Header的模式。
但是本VPN會查詢L2用作選路所以會變成一律廣播
2. `nodeid`: 節點ID。節點之間辨識身分用的同一網路內節點ID不能重複
3. `postscript`: etherguard初始化完畢之後要跑的腳本.
3. `nodename`: 節點名稱
4. `defaultttl`: 預設ttl(etherguard層使用和乙太層不共通)
5. `l2fibtimeout`: MacAddr-> NodeID 查找表的 timeout(秒)
5. `privkey`: 私鑰和wireguard規格一樣
5. `listenport`: 監聽的udp埠
6. `loglevel`: 紀錄log
1. `loglevel`: wireguard原本的log紀錄器的loglevel。
有`debug`,`error`,`slient`三種程度
2. `logtransit`: 轉送封包,也就是起點/終點都不是自己的封包的log
3. `logcontrol`: Control Message的log
4. `lognormal`: 收發普通封包起點是自己or終點是自己的log
5. `logntp`: NTP 同步時鐘相關的log
7. `dynamicroute`: 動態路由相關的設定。時間類設定單位都是秒
1. `sendpinginterval`: 發送Ping訊息的間隔
2. `dupchecktimeout`: 重複封包檢查的timeout。完全相同的封包收第二次會被丟棄
1. `peeralivetimeout`: 每次收到封包就重置超過時間沒收到就標記該peer離線
3. `conntimeout`: 檢查peer離線的間格如果標記離線就切換下一個endpoint(supernode可能傳了多個endpoint過來)
4. `savenewpeers`: 是否把下載來的鄰居資訊存到本地設定檔裡面
5. `supernode`: 參見[Super模式](example_config/super_mode/README_zh.md)
6. `p2p` 參見 [P2P模式](example_config/p2p_mode/README_zh.md)
7. `ntpconfig`: NTP 相關的設定
1. `usentp`: 是否使用ntp同步時鐘
2. `maxserveruse`: 一次對多連線幾個NTP伺服器
第一次會全部連一遍測延遲之後每次都取延遲前n低的來用
3. `synctimeinterval`: 多久同步一次
4. `ntptimeout`: 多久算是超時
5. `servers`: NTP伺服器列表
8. `nexthoptable`: 轉發表。只有Static模式會用到參見 [Static模式](example_config/super_mode/README_zh.md)
9. `resetconninterval`: 如果對方是動態ip就要用這個。每隔一段時間就會重新解析domain。
10. `peers`: 和wireguard一樣的peer資訊
1. `nodeid`: 對方的節點ID
2. `pubkey`: 對方的公鑰
3. `pskey`: 對方的預共享金鑰。但是目前沒用(因為不能設定自己的),之後會加
4. `endpoint`: 對方的連線地址。如果roaming會覆寫設定檔
5. `static`: 設定成true的話每隔`resetconninterval`秒就會重新解析一次domain與此同時也不會被roaming覆寫
<a name="L2HeaderMode"></a>L2HeaderMode | Description
---------------|:-----
nochg | 收到的封包丟stdoutstdin進來的資料丟入vpn網路不對封包作任何更動
kbdbg | 前 12byte 會用來做選路判斷<br>但是stdio模式下使用鍵盤輸入一個Ethernet frame不太方便<br>此模式讓我快速產生Ethernet framedebug更方便<br>`b`轉換成`FF:FF:FF:FF:FF:FF`<br>`2`轉換成 `AA:BB:CC:DD:EE:02`<br>輸入`b2aaaaa`就會變成`b"0xffffffffffffaabbccddee02aaaaa"`
noL2 | 讀取時拔掉L2 Header的模式<br>寫入時時一律使用廣播MacAddress
### Super config
<a name="LogLevel"></a>LogLevel | Description
------------|:-----
LogLevel | wireguard原本的log紀錄器的loglevel<br>接受參數: `debug`,`error`,`slient`
LogTransit | 轉送封包,也就是起點/終點都不是自己的封包的log
LogNormal | 收發普通封包起點是自己or終點是自己的log
LogControl | Control Message的log
LogInternal | 一些內部事件的log
LogNTP | NTP 同步時鐘相關的log
參見 [example_config/super_mode/README_zh.md](example_config/super_mode/README_zh.md)
### Quick start
<a name="Peers"></a>Peers | Description
--------------------|:-----
NodeID | 對方的節點ID
PubKey | 對方的公鑰
PSKey | 對方的預共享金鑰
EndPoint | 對方的連線地址。如果漫遊,而且`Static=false`會覆寫設定檔
PersistentKeepalive | wireguard的PersistentKeepalive參數
Static | 關閉漫遊功能,每隔`ResetConnInterval`秒重置回初始ip
#### Run example config
在**不同terminal**分別執行以下命令
```
./etherguard-go -config example_config/super_mode/n1.yaml -mode edge
./etherguard-go -config example_config/super_mode/n2.yaml -mode edge
./etherguard-go -config example_config/super_mode/n3.yaml -mode edge
./etherguard-go -config example_config/super_mode/n4.yaml -mode edge
./etherguard-go -config example_config/super_mode/n5.yaml -mode edge
./etherguard-go -config example_config/super_mode/n6.yaml -mode edge
./etherguard-go -config example_config/super_mode/EgNet_edge1.yaml -mode edge
./etherguard-go -config example_config/super_mode/EgNet_edge2.yaml -mode edge
./etherguard-go -config example_config/super_mode/EgNet_edge3.yaml -mode edge
./etherguard-go -config example_config/super_mode/EgNet_edge4.yaml -mode edge
./etherguard-go -config example_config/super_mode/EgNet_edge5.yaml -mode edge
./etherguard-go -config example_config/super_mode/EgNet_edge6.yaml -mode edge
```
因為本範例配置是stdio的kbdbg模式stdin會讀入VPN網路
@ -284,12 +213,7 @@ src dist path
```
b1message
```
因為`l2headermode`是`kbdbg`所以b1會被轉換成 12byte 的layer 2 headerb是廣播地址`FF:FF:FF:FF:FF:FF`1是普通地址`AA:BB:CC:DD:EE:01`message是後面的payload然後再丟入VPN
因為`L2HeaderMode`是`kbdbg`所以b1會被轉換成 12byte 的layer 2 headerb是廣播地址`FF:FF:FF:FF:FF:FF`1是普通地址`AA:BB:CC:DD:EE:01`message是後面的payload然後再丟入VPN
此時應該要能夠在另一個視窗上看見字串b1message。前12byte被轉換回來了
#### Run your own etherguard
要正式使用請將itype改成`tap`,並且修改各節點的公鑰私鑰和連線地址
再關閉不必要的log增加性能最後部屬到不同節點即可
## 下一篇: [Super Mode的運作](../super_mode/README_zh.md)

View File

@ -1,6 +1,6 @@
Config output dir: /tmp/eg_gen_static
ConfigTemplate for edge node: "n1.yaml"
Network name: "Node"
ConfigTemplate for edge node: "" # "EgNet_edge1.yaml"
Network name: "EgNet"
Edge Node:
MacAddress prefix: ""
IPv4 range: 192.168.76.0/24
@ -9,27 +9,21 @@ Edge Node:
Edge Nodes:
1:
Endpoint(optional): 127.0.0.1:3001
PersistentKeepalive: 30
2:
Endpoint(optional): 127.0.0.1:3002
PersistentKeepalive: 30
3:
Endpoint(optional): 127.0.0.1:3003
PersistentKeepalive: 30
4:
Endpoint(optional): 127.0.0.1:3004
PersistentKeepalive: 30
5:
Endpoint(optional): 127.0.0.1:3005
PersistentKeepalive: 30
6:
Endpoint(optional): 127.0.0.1:3006
PersistentKeepalive: 30
Distance matrix for all nodes: |-
X 1 2 3 4 5 6
1 0 1 Inf Inf Inf Inf
2 1 0 1 1 Inf Inf
3 Inf 1 0 1 1 Inf
4 Inf 1 1 0 Inf 1
5 Inf Inf 1 Inf 0 Inf
6 Inf Inf Inf 1 Inf 0
1 0 1.0 Inf Inf Inf Inf
2 1.0 0 1.0 1.0 Inf Inf
3 Inf 1.0 0 1 1.0 Inf
4 Inf 1.0 1.0 0 Inf 1.0
5 Inf Inf 1.0 Inf 1.0 Inf
6 Inf Inf Inf 1.0 Inf 1.0

Binary file not shown.

Before

Width:  |  Height:  |  Size: 46 KiB

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

View File

@ -1,28 +1,28 @@
Interface:
IType: stdio
Name: tap1
Name: Node001
VPPIFaceID: 1
VPPBridgeID: 4242
MacAddrPrefix: AA:BB:CC:DD
IPv4CIDR: ""
IPv6CIDR: ""
IPv6LLPrefix: ""
MacAddrPrefix: CE:51:BA:B4
IPv4CIDR: 192.168.76.0/24
IPv6CIDR: fd95:71cb:a3df:e586::/64
IPv6LLPrefix: fe80::a3df:0/112
MTU: 1416
RecvAddr: 127.0.0.1:4001
SendAddr: 127.0.0.1:5001
L2HeaderMode: kbdbg
NodeID: 1
NodeName: Node01
NodeName: Node001
PostScript: ""
DefaultTTL: 200
L2FIBTimeout: 3600
PrivKey: 6GyDagZKhbm5WNqMiRHhkf43RlbMJ34IieTlIuvfJ1M=
ListenPort: 0
PrivKey: C0SXvffZh8nDqXYNzG4UqUJtSCiRMEj3ehX5o7QiJz0=
ListenPort: 3001
LogLevel:
LogLevel: error
LogTransit: true
LogTransit: false
LogControl: true
LogNormal: true
LogNormal: false
LogInternal: true
LogNTP: true
DynamicRoute:
@ -35,12 +35,12 @@ DynamicRoute:
SaveNewPeers: true
SuperNode:
UseSuperNode: true
PSKey: iPM8FXfnHVzwjguZHRW9bLNY+h7+B1O2oTJtktptQkI=
EndpointV4: 127.0.0.1:3000
PubKeyV4: LJ8KKacUcIoACTGB/9Ed9w0osrJ3WWeelzpL2u4oUic=
EndpointV6: '[::1]:3000'
PubKeyV6: HCfL6YJtpJEGHTlJ2LgVXIWKB/K95P57LHTJ42ZG8VI=
EndpointEdgeAPIUrl: http://127.0.0.1:3000/eg_api
PSKey: j2f9Fhdhw2O2zLqUqfL5nTFStjVWPnEXpw7Iqz6VX9M=
EndpointV4: 127.0.0.1:3456
PubKeyV4: Id/VoZ6HmTU3FSqhxBUswfuHHB0mQxfzcbdoJNGBRzQ=
EndpointV6: :3456
PubKeyV6: 40tADRhJTvaortwE5Ur4qNXhP+SOMX7ZuSvl251Yxnc=
EndpointEdgeAPIUrl: http://127.0.0.1:3456/eg_net/eg_api
SkipLocalIP: false
SuperNodeInfoTimeout: 50
P2P:
@ -48,8 +48,10 @@ DynamicRoute:
SendPeerInterval: 20
GraphRecalculateSetting:
StaticMode: false
JitterTolerance: 20
ManualLatency: {}
JitterTolerance: 50
JitterToleranceMultiplier: 1.1
DampingResistance: 0
TimeoutCheckInterval: 5
RecalculateCoolDown: 5
NTPConfig:

View File

@ -1,28 +1,28 @@
Interface:
IType: stdio
Name: tap1
VPPIFaceID: 2
Name: Node002
VPPIFaceID: 1
VPPBridgeID: 4242
MacAddrPrefix: AA:BB:CC:DD
IPv4CIDR: ""
IPv6CIDR: ""
IPv6LLPrefix: ""
MacAddrPrefix: CE:51:BA:B4
IPv4CIDR: 192.168.76.0/24
IPv6CIDR: fd95:71cb:a3df:e586::/64
IPv6LLPrefix: fe80::a3df:0/112
MTU: 1416
RecvAddr: 127.0.0.1:4002
SendAddr: 127.0.0.1:5002
L2HeaderMode: kbdbg
NodeID: 2
NodeName: Node02
NodeName: Node002
PostScript: ""
DefaultTTL: 200
L2FIBTimeout: 3600
PrivKey: OH8BsVUU2Rqzeu9B2J5GPG8PUmxWfX8uVvNFZKhVF3o=
ListenPort: 0
PrivKey: AErxhLXdZvidPZVXRYgD+84fa2qYWG9ft4MRuCbAtt8=
ListenPort: 3002
LogLevel:
LogLevel: error
LogTransit: true
LogTransit: false
LogControl: true
LogNormal: true
LogNormal: false
LogInternal: true
LogNTP: true
DynamicRoute:
@ -35,12 +35,12 @@ DynamicRoute:
SaveNewPeers: true
SuperNode:
UseSuperNode: true
PSKey: juJMQaGAaeSy8aDsXSKNsPZv/nFiPj4h/1G70tGYygs=
EndpointV4: 127.0.0.1:3000
PubKeyV4: LJ8KKacUcIoACTGB/9Ed9w0osrJ3WWeelzpL2u4oUic=
EndpointV6: '[::1]:3000'
PubKeyV6: HCfL6YJtpJEGHTlJ2LgVXIWKB/K95P57LHTJ42ZG8VI=
EndpointEdgeAPIUrl: http://127.0.0.1:3000/eg_api
PSKey: iCw096jsW2aWyMwPyzVEvL8C3XXqMpB+jOeWqDC34uU=
EndpointV4: 127.0.0.1:3456
PubKeyV4: Id/VoZ6HmTU3FSqhxBUswfuHHB0mQxfzcbdoJNGBRzQ=
EndpointV6: :3456
PubKeyV6: 40tADRhJTvaortwE5Ur4qNXhP+SOMX7ZuSvl251Yxnc=
EndpointEdgeAPIUrl: http://127.0.0.1:3456/eg_net/eg_api
SkipLocalIP: false
SuperNodeInfoTimeout: 50
P2P:
@ -48,8 +48,10 @@ DynamicRoute:
SendPeerInterval: 20
GraphRecalculateSetting:
StaticMode: false
JitterTolerance: 20
ManualLatency: {}
JitterTolerance: 50
JitterToleranceMultiplier: 1.1
DampingResistance: 0
TimeoutCheckInterval: 5
RecalculateCoolDown: 5
NTPConfig:

View File

@ -1,12 +1,12 @@
Interface:
IType: stdio
Name: tap1
VPPIFaceID: 100
Name: Node100
VPPIFaceID: 1
VPPBridgeID: 4242
MacAddrPrefix: AA:BB:CC:DD
IPv4CIDR: ""
IPv6CIDR: ""
IPv6LLPrefix: ""
MacAddrPrefix: CE:51:BA:B4
IPv4CIDR: 192.168.76.0/24
IPv6CIDR: fd95:71cb:a3df:e586::/64
IPv6LLPrefix: fe80::a3df:0/112
MTU: 1416
RecvAddr: 127.0.0.1:4100
SendAddr: 127.0.0.1:5100
@ -16,13 +16,13 @@ NodeName: Node100
PostScript: ""
DefaultTTL: 200
L2FIBTimeout: 3600
PrivKey: IJtpnkm9ytbuCukx4VBMENJKuLngo9KSsS1D60BqonQ=
ListenPort: 0
PrivKey: a04BVvT+YbrX1ejjvMQVI6k5VRFlBkEX8tuLGWNyNrY=
ListenPort: 3100
LogLevel:
LogLevel: error
LogTransit: true
LogTransit: false
LogControl: true
LogNormal: true
LogNormal: false
LogInternal: true
LogNTP: true
DynamicRoute:
@ -35,12 +35,12 @@ DynamicRoute:
SaveNewPeers: true
SuperNode:
UseSuperNode: true
PSKey: j9dS/lYvL16svSeC5lh+ldlq2iZX2MWwZfM3NNWpULI=
EndpointV4: 127.0.0.1:3000
PubKeyV4: LJ8KKacUcIoACTGB/9Ed9w0osrJ3WWeelzpL2u4oUic=
EndpointV6: '[::1]:3000'
PubKeyV6: HCfL6YJtpJEGHTlJ2LgVXIWKB/K95P57LHTJ42ZG8VI=
EndpointEdgeAPIUrl: http://127.0.0.1:3000/eg_api
PSKey: Gfp2RkPNrKTeGKrCJNEvSyiBqYYRmzVnVG6CBuUKUNc=
EndpointV4: 127.0.0.1:3456
PubKeyV4: Id/VoZ6HmTU3FSqhxBUswfuHHB0mQxfzcbdoJNGBRzQ=
EndpointV6: :3456
PubKeyV6: 40tADRhJTvaortwE5Ur4qNXhP+SOMX7ZuSvl251Yxnc=
EndpointEdgeAPIUrl: http://127.0.0.1:3456/eg_net/eg_api
SkipLocalIP: false
SuperNodeInfoTimeout: 50
P2P:
@ -48,8 +48,10 @@ DynamicRoute:
SendPeerInterval: 20
GraphRecalculateSetting:
StaticMode: false
JitterTolerance: 20
ManualLatency: {}
JitterTolerance: 50
JitterToleranceMultiplier: 1.1
DampingResistance: 0
TimeoutCheckInterval: 5
RecalculateCoolDown: 5
NTPConfig:

View File

@ -0,0 +1,55 @@
NodeName: NodeSP
PostScript: ""
PrivKeyV4: 2P0mV5RkpFFyg+aLPK841sml5RobQGrxAV5ld4En9Kk=
PrivKeyV6: 9JrdnAk1ljXUTn9VFb1uFyey20tQEQuzJJtVueM4vsw=
ListenPort: 3456
ListenPort_EdgeAPI: "3456"
ListenPort_ManageAPI: "3456"
API_Prefix: /eg_net/eg_api
RePushConfigInterval: 30
HttpPostInterval: 50
PeerAliveTimeout: 70
SendPingInterval: 15
LogLevel:
LogLevel: normal
LogTransit: false
LogNormal: false
LogControl: true
LogInternal: true
LogNTP: true
Passwords:
ShowState: passwd_showstate
AddPeer: passwd_addpeer
DelPeer: passwd_delpeer
UpdatePeer: passwd_updatepeer
UpdateSuper: passwd_updatesuper
GraphRecalculateSetting:
StaticMode: false
ManualLatency: {}
JitterTolerance: 30
JitterToleranceMultiplier: 1.01
DampingResistance: 0.9
TimeoutCheckInterval: 5
RecalculateCoolDown: 5
NextHopTable: {}
EdgeTemplate: ""
UsePSKForInterEdge: true
Peers:
- NodeID: 1
Name: Node001
PubKey: awnuKYQOgCywkJbHAynqMzKi5QEGsG0w4iBy2Ja1MDQ=
PSKey: j2f9Fhdhw2O2zLqUqfL5nTFStjVWPnEXpw7Iqz6VX9M=
AdditionalCost: 10
SkipLocalIP: false
- NodeID: 2
Name: Node002
PubKey: WUyblc/DZzPNU5sOQQS2lS0aP53zFEVNjqCHjkhkdzE=
PSKey: iCw096jsW2aWyMwPyzVEvL8C3XXqMpB+jOeWqDC34uU=
AdditionalCost: 10
SkipLocalIP: false
- NodeID: 100
Name: Node_100
PubKey: Bax6wOJpisSVJtrU92ujn8D/2oGUyhyPrKTXkHbGamM=
PSKey: Gfp2RkPNrKTeGKrCJNEvSyiBqYYRmzVnVG6CBuUKUNc=
AdditionalCost: 1000
SkipLocalIP: false

View File

@ -1,42 +1,81 @@
# Etherguard
[English](README.md)
Super Mode的[範例配置檔](./)的說明文件
在了解Super Mode的運作之前建議您先閱讀[Static Mode的運作](../static_mode/README_zh.md)方法,再閱讀本篇會比較好
[English](README.md) | [中文](#)
## Super Mode
Super Mode是受到[n2n](https://github.com/ntop/n2n)的啟發
分為super node和edge node兩種節點
分為SuperNode和EdgeNode兩種節點
全部節點都會和supernode建立連線
藉由supernode交換其他節點的資訊以及udp打洞
supernode執行[Floyd-Warshall演算法](https://zh.wikipedia.org/zh-tw/Floyd-Warshall算法)並把計算結果分發給全部edge node
全部節點都會和SuperNode建立連線
藉由SuperNode交換其他節點的資訊以及udp打洞
SuperNode執行[Floyd-Warshall演算法](https://zh.wikipedia.org/zh-tw/Floyd-Warshall算法)並把計算結果分發給全部edge node
在edge node的super模式下設定檔裡面的`nexthoptable`以及`peers`是無效的。
這些資訊都是從super node上面下載
同時supernode會幫每個連線生成Preshared Key分發給edge使用(如果`usepskforinteredge`有啟用的話)。
```golang
psk = shs256("PubkeyPeerA" + "PubkeyPeerB" + "主廚特調當季精選海鹽")[:32]
## Quick start
首先按需求修改`gensuper.yaml`
```yaml
Config output dir: /tmp/eg_gen
ConfigTemplate for super node: ""
ConfigTemplate for edge node: ""
Network name: eg_net
Super Node:
Listen port: 3456
EdgeAPI prefix: /eg_net/eg_api
Endpoint(IPv4)(optional): example.com
Endpoint(IPv6)(optional): example.com
Endpoint(EdgeAPI): http://example.com:3456/eg_net/eg_api
Edge Node:
Node IDs: "[1~10,11,19,23,29,31,55~66,88~99]"
MacAddress prefix: "" # 留空隨機產生
IPv4 range: 192.168.76.0/24 # IP的部分可以直接省略沒關係
IPv6 range: fd95:71cb:a3df:e586::/64 # 這個欄位唯一的目的只是在啟動以後調用ip命令幫tap接口加個ip
IPv6 LL range: fe80::a3df:0/112 # 和VPN本身運作完全無關
```
接著執行這個,就會生成所需設定檔了。
```
$ ./etherguard-go -mode gencfg -cfgmode super -config example_config/super_mode/gensuper.yaml
```
把一個super2個edge分別搬去三台機器
或是2台機器super和edge可以是同一台
在Supernode執行
```
./etherguard-go -config [設定檔位置] -mode super
```
在EdgeNode執行
```
./etherguard-go -config [設定檔位置] -mode edge
```
## Documentation
在了解Super Mode的運作之前建議您先閱讀[Static Mode的運作](../static_mode/README_zh.md)方法,再閱讀本篇會比較好
在EdgeNode的SuperMode下設定檔裡面的`NextHopTable`以及`Peers`是無效的。
這些資訊都是從SuperNode上面下載
同時SuperNode會幫每個連線生成pre-shared key分發給edge使用(如果啟用`UsePSKForInterEdge`的話)。
### SuperMsg
但是比起Static modeSuper mode引入了一種新的 `終點ID` 叫做 `SuperMsg`
所有送往Super node的封包都會是這種類型。
這種封包不會在edge node之間傳播收到也會不會轉給任何人如同`終點ID == 自己`一般
但是比起StaticModeSuperMode引入了一種新的 `終點ID` 叫做 `NodeID_SuperNode`。
所有送往SuperNode的封包都會是這種類型。
這種封包不會在EdgeNode之間傳播收到也會不會轉給任何人如同`終點ID == 自己`一般
## Control Message
從Super mode開始我們有了Static mode不存在的Control Message。他會控制EtherGuard一些行為
在Super mode下我們不會轉發任何控制消息。 我們只會直接接收或發送給目標。
從SuperMode開始我們有了StaticMode不存在的Control Message。他會控制EtherGuard一些行為
在SuperMode下我們不會轉發任何控制消息。 我們只會直接接收或發送給目標。
下面列出Super Mode會出現的Control message
### Register
具體運作方式類似這張圖
![Register運作流程](https://raw.githubusercontent.com/KusakabeSi/EtherGuard-VPN/master/example_config/super_mode/EGS01.png)
1. edge node發送`Register`給super node
2. super node收到以後就知道這個edge的endpoint IP和埠號。
1. EdgeNode發送`Register`給sSuperNode
2. SuperNode收到以後就知道這個EdgeNode的Endpoint IP和Port number
3. 更新進資料庫以後發布`UpdatePeerMsg`。
4. 其他edge node收到以後就用HTTP API去下載完整的peer list。並且把自己沒有的peer通通加到本地
4. 其他edge node收到以後就用HTTP EdgeAPI去下載完整的peer list。並且把自己沒有的peer通通加到本地
### Ping/Pong
有了peer list以後接下來的運作方式類似這張圖
@ -46,18 +85,58 @@ Edge node 會嘗試向其他所有peer發送`Ping`,裡面會攜帶節點自己
收到`Ping`,就會產生一個`Pong`,並攜帶時間差。這個時間就是單向延遲
但是他不會把`Pong`送回給原節點而是送給Super node
### <a name="AdditionalCost"></a>AdditionalCost
有了各個節點的延遲以後,還不會立刻計算`Floyd-Warshall`,而是要先加上`AdditionalCost`
以這張圖片的情境為例:
![EGS08](https://raw.githubusercontent.com/KusakabeSi/EtherGuard-VPN/master/example_config/super_mode/EGS08.png)
Path | Latency |Cost|Win
--------|:--------|:---|:--
A->B->C | 3ms | 3 |
A->C | 4ms | 4 | O
但是這個情境3ms 4ms 只相差1ms
為了這1ms而多繞一趟實在浪費而且轉發本身也要時間
每個節點有了`AdditionalCost`參數,就能設定經過這個節點轉發,所需額外增加的成本
假如ABC全部設定了`AdditionalCost=10`
Path | Latency |AdditionalCost|Cost|Win
--------|:--------|:-------------|:---|:--
A->B->C | 3ms | 20 | 23 |
A->C | 4ms | 10 | 14 | O
A->C 就換選擇直連不會為了省下1ms而繞路
這邊`AdditionalCost=10`可以解釋為: 必須能省下10ms才會繞這條路
這個參數也有別的用途
針對流量比較貴的節點,可以設定`AdditionalCost=10000`
別人就不會走他中轉了,而是盡量繞別的路,或是直連
除非別條路線全掛只剩這挑Cost 10000的路線
還有一個用法,全部節點都設定`AdditionalCost=10000`
無視延遲,全節點都盡量直連,打動失敗才繞路
### UpdateNhTable
Super node收到節點們傳來的Pong以後就知道他們的單向延遲了。接下來的運作方式類似這張圖
![image](https://raw.githubusercontent.com/KusakabeSi/EtherGuard-VPN/master/example_config/super_mode/EGS03.png)
Super node收到Pong以後就會更新它裡面的`Distance matrix`,並且重新計算轉發表
如果有變動,就發布`UpdateNhTableMsg`
其他edge node收到以後就用HTTP API去下載完整的轉發表
其他edge node收到以後就用HTTP EdgeAPI去下載完整的轉發表
### UpdateError
通知edges有錯誤發生關閉egde端程式
發生在版本號不匹被該edge的NodeID配置錯誤還有該Edge被刪除時觸發
### ServerUpdate
通知EdgeNode有事情發生
1. 關閉EdgeNode程式
* 版本號不匹配
* 該edge的NodeID配置錯誤
* 該Edge被刪除
2. 通知EdgeNode有更新
* UpdateNhTable
* UpdatePeer
* UpdateSuperParams
### HTTP API
## HTTP EdgeAPI
為什麼要用HTTP額外下載呢?直接`UpdateXXX`夾帶資訊不好嗎?
因為udp是不可靠協議能攜帶的內容量也有上限。
但是peer list包含了全部的peer資訊長度不是固定的可能超過
@ -68,12 +147,15 @@ Super node收到Pong以後就會更新它裡面的`Distance matrix`,並且
這樣super node收到HTTP API看到`state hash`就知道這個edge node確實有收到`UpdateXXX`了。
不然每隔一段時間就會重新發送`UpdateXXX`給該節點
預設配置是走HTTP。但為**了你的安全著想建議使用nginx反代理成https**
有想過SuperNode開發成直接支援https但是證書動態更新太麻煩就沒有做了
## HTTP Manage API
HTTP還有一些個API給前端使用幫助管理整個網路
HTTP還有5個Manage API給前端使用幫助管理整個網路
### super/state
```bash
curl "http://127.0.0.1:3000/eg_api/manage/super/state?Password=passwd_showstate"
curl "http://127.0.0.1:3456/eg_net/eg_api/manage/super/state?Password=passwd_showstate"
```
可以給前端看的,用來顯示現在各節點之間的單向延遲狀況
之後可以用來畫力導向圖。
@ -145,10 +227,10 @@ curl "http://127.0.0.1:3000/eg_api/manage/super/state?Password=passwd_showstate"
再來是新增peer可以不用重啟Supernode就新增Peer
範例:
```
curl -X POST "http://127.0.0.1:3000/eg_api/manage/peer/add?Password=passwd_addpeer" \
```bash
curl -X POST "http://127.0.0.1:3456/eg_net/eg_api/manage/peer/add?Password=passwd_addpeer" \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "NodeID=100&Name=Node_100&PubKey=6SuqwPH9pxGigtZDNp3PABZYfSEzDaBSwuThsUUAcyM=&AdditionalCost=1000&PSKey=j9dS%2FlYvL16svSeC5lh%2Bldlq2iZX2MWwZfM3NNWpULI%3D&SkipLocalIP=false"
-d "NodeID=100&Name=Node_100&PubKey=Bax6wOJpisSVJtrU92ujn8D%2F2oGUyhyPrKTXkHbGamM%3D&AdditionalCost=1000&PSKey=Gfp2RkPNrKTeGKrCJNEvSyiBqYYRmzVnVG6CBuUKUNc%3D&SkipLocalIP=false"
```
參數:
1. URL query: Password: 新增peer用的密碼在設定檔配置
@ -172,13 +254,13 @@ curl -X POST "http://127.0.0.1:3000/eg_api/manage/peer/add?Password=passwd_addpe
設計上分別是給管理員使用,或是給加入網路的人,想離開網路使用
使用Password刪除可以刪除任意節點以上面新增的節點為例使用這個API即可刪除剛剛新增的節點
```
curl "http://127.0.0.1:3000/eg_api/manage/peer/del?Password=passwd_delpeer&NodeID=100"
```bash
curl "http://127.0.0.1:3456/eg_net/eg_api/manage/peer/del?Password=passwd_delpeer&NodeID=100"
```
也可以使用privkey刪除同上但是只要附上privkey參數就好
```
curl "http://127.0.0.1:3000/eg_api/manage/peer/del?PrivKey=IJtpnkm9ytbuCukx4VBMENJKuLngo9KSsS1D60BqonQ="
```bash
curl "http://127.0.0.1:3456/eg_net/eg_api/manage/peer/del?PrivKey=a04BVvT%2BYbrX1ejjvMQVI6k5VRFlBkEX8tuLGWNyNrY%3D"
```
參數:
@ -193,65 +275,121 @@ curl "http://127.0.0.1:3000/eg_api/manage/peer/del?PrivKey=IJtpnkm9ytbuCukx4VBME
### peer/update
更新節點的一些參數
```
curl -X POST "http://127.0.0.1:12369/eg_net/eg_api/manage/peer/update?Password=e05znou1_updatepeer&NodeID=1" \
```bash
curl -X POST "http://127.0.0.1:3456/eg_net/eg_api/eg_api/manage/peer/update?Password=e05znou1_updatepeer&NodeID=1" \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "AdditionalCost=10&SkipLocalIP=false"
```
### super/update
更新SuperNode的一些參數
```
curl -X POST "http://127.0.0.1:12369/eg_net/eg_api/manage/super/update?Password=e05znou1_updatesuper" \
```bash
curl -X POST "http://127.0.0.1:3456/eg_net/eg_api/eg_api/manage/super/update?Password=e05znou1_updatesuper" \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "SendPingInterval=15&HttpPostInterval=60&PeerAliveTimeout=70"
```
### SuperNode Config Parameter
## Config Parameters
Key | Description
-------------- |:-----
NodeName| 節點名稱
PostScript | 初始化完畢之後要跑的腳本
PrivKeyV4 | IPv4通訊使用的私鑰
PrivKeyV6 | IPv6通訊使用的私鑰
ListenPort | udp監聽埠
ListenPort_EdgeAPI | HTTP EdgeAPI 的監聽埠
ListenPort_ManageAPI| HTTP ManageAPI 的監聽埠
API_Prefix | HTTP API prefix
RePushConfigInterval| 重新push`UpdateXXX`的間格
HttpPostInterval | EdgeNode 使用EdgeAPI回報狀態的頻率
PeerAliveTimeout | 判定斷線Timeout
SendPingInterval | EdgeNode 之間使用Ping/Pong測量延遲的間格
[LogLevel](../static_mode/README_zh.md#LogLevel)| 紀錄log
[Passwords](#Passwords) | HTTP ManageAPI 的密碼5個API密碼是獨立的
[GraphRecalculateSetting](#GraphRecalculateSetting) | 一些和[Floyd-Warshall演算法](https://zh.wikipedia.org/zh-tw/Floyd-Warshall算法)相關的參數
[NextHopTable](../static_mode/README_zh.md#NextHopTable) | StaticMode 模式下使用的轉發表
EdgeTemplate | HTTP ManageAPI `peer/add` 返回的edge的參考設定檔
UsePSKForInterEdge | 幫Edge生成PreSharedKey供edge之間直接連線使用
[Peers](#EdgeNodes) | EdgeNode資訊
### Super mode的edge node有幾個參數
1. `usesupernode`: 是否啟用Super mode
1. `pskey`: 和supernode建立連線用的Pre shared Key
1. `connurlv4`: Super node的IPv4連線地址
1. `pubkeyv4`: Super node的IPv4工鑰
1. `connurlv6`: Super node的IPv6連線地址
1. `pubkeyv6`: Super node的IPv6工鑰
1. `apiurl`: Super node的HTTP(S) API連線地址
1. `supernodeinfotimeout`: Supernode Timeout
1. `httppostinterval`: 15
1. `skiplocalip`: 打洞時一律使用supernode蒐集到的外部ip不使用edge自行回報的local ip
<a name="Passwords"></a>Passwords | Description
--------------------|:-----
ShowState | HTTP ManageAPI `super/state` 的密碼
AddPeer | HTTP ManageAPI `peer/add` 的密碼
DelPeer | HTTP ManageAPI `peer/del` 的密碼
UpdatePeer | HTTP ManageAPI `peer/update` 的密碼
UpdateSuper | HTTP ManageAPI `super/update` 的密碼
### Super node本身的設定檔
<a name="GraphRecalculateSetting"></a>GraphRecalculateSetting | Description
--------------------|:-----
StaticMode | 關閉`Floyd-Warshall`演算法只使用設定檔提供的NextHopTable`。SuperNode單純用來輔助打洞
ManualLatency | 手動設定延遲不採用EdgeNode回報的延遲(單位: 毫秒)
JitterTolerance | 抖動容許誤差收到Pong以後一個37ms一個39ms不會觸發重新計算<br>比較對象是上次更新使用的值。如果37 37 41 43 .. 100 ,每次變動一點點,總變動量超過域值還是會更新
JitterToleranceMultiplier | 抖動容許誤差的放大係數高ping的話允許更多誤差<br>https://www.desmos.com/calculator/raoti16r5n
DampingResistance | 防抖阻尼系數,`latency = latency_old * resistance + latency_in * (1-resistance)`
TimeoutCheckInterval | 週期性檢查節點的連線狀況,是否斷線需要重新規劃線路
RecalculateCoolDown | Floyd-Warshal是O(n^3)時間複雜度,不能太常算。<br>設個冷卻時間<br>有節點加入/斷線觸發的重新計算無視這個CoolDown
1. nodename: 節點名稱
1. privkeyv4: ipv4用的私鑰
1. privkeyv6: ipv6用的私鑰
1. listenport: 監聽udp埠號
1. loglevel: 參考 [README_zh.md](../README_zh.md)
1. repushconfiginterval: 重新push`UpdateXXX`的間格
1. passwords: HTTP API 密碼
1. showstate: 節點資訊
1. addpeer: 新增peer
1. delpeer: 刪除peer
1. graphrecalculatesetting: 一些和[Floyd-Warshall演算法](https://zh.wikipedia.org/zh-tw/Floyd-Warshall算法)相關的參數
1. staticmode: 關閉Floyd-Warshall演算法只使用一開始載入的nexthoptable。Supernode單純用來輔助打洞
1. recalculatecooldown: Floyd-Warshal是O(n^3)時間複雜度,不能太常算。設個冷卻時間
1. jittertolerance: 抖動容許誤差收到Pong以後一個37ms一個39ms不會觸發重新計算
1. jittertolerancemultiplier: 一樣是抖動容許誤差但是高ping的話允許更多誤差
https://www.desmos.com/calculator/raoti16r5n
1. nodereporttimeout: 收到的`Pong`封包的有效期限。太久沒收到就變回Infinity
1. timeoutcheckinterval: 固定間格檢查有沒有人的Pong封包超過有效期限要重算轉發表
1. nexthoptable: 僅在`staticmode==true` 有效手動設定的nexthoptable
1. edgetemplate: 給`addpeer`API用的。參考這個設定檔顯示一個範例設定檔給edge
1. usepskforinteredge: 是否啟用edge間pre shares key通信。若啟用則幫edge們自動生成PSK
1. peers: Peer列表參考 [README_zh.md](../README_zh.md)
1. nodeid: Peer的節點ID
1. name: Peer名稱(顯示在前端)
1. pubkey: peer 公鑰
1. pskey: preshared key 該peer和本Supernode連線的PSK
1. additionalcost: 此節點進行封包轉發的額外成本。單位: 毫秒
<a name="EdgeNodes"></a>Peers | Description
--------------------|:-----
NodeID | 節點ID
PubKey | 公鑰
PSKey | 預共享金鑰
[AdditionalCost](#AdditionalCost) | 繞路成本(單位: 毫秒)<br>設定-1代表使用EdgeNode自身設定
SkipLocalIP | 打洞時不使用EdgeNode回報的本地IP僅使用SuperNode蒐集到的外部IP
### EdgeNode Config Parameter
Key | Description
-------------- |:-----
[Interface](../static_mode/README_zh.md#Interface)| 接口相關設定。VPN有兩端一端是VPN網路另一端則是本地接口
NodeID | 節點ID。節點之間辨識身分用的同一網路內節點ID不能重複
NodeName | 節點名稱
PostScript | 初始化完畢之後要跑的腳本
DefaultTTL | TTLetherguard層使用和乙太層不共通
L2FIBTimeout | MacAddr-> NodeID 查找表的 timeout(秒) 類似ARP table
PrivKey | 私鑰和wireguard規格一樣
ListenPort | 監聽的udp埠
[LogLevel](../static_mode/README_zh.md#LogLevel)| 紀錄log
[DynamicRoute](#DynamicRoute) | 動態路由相關設定
NextHopTable | 轉發表, SuperMode由SuperNode計算EdgeNode用不到
ResetConnInterval | 如果對方是動態ip就要用這個。每隔一段時間就會重置連線重新解析域名
[Peers](#Peers) | 鄰居節點SuperMode從SuperNode計算EdgeNode用不到
<a name="DynamicRoute"></a>DynamicRoute | Description
--------------------|:-----
SendPingInterval | 發送Ping訊息的間隔(秒)
PeerAliveTimeout | 每次收到封包就重置,超過時間(秒)沒收到就標記該peer離線
DupCheckTimeout | 重複封包檢查的timeout(秒)<br>完全相同的封包收第二次會被丟棄
ConnTimeOut | 檢查peer離線的時間間格<br>如果標記離線就切換下一個endpoint<br>SuperNode可能傳了多個endpoint過來
ConnNextTry | 切換下一個endpoint的間隔
[AdditionalCost](#AdditionalCost) | 繞路成本(毫秒)。僅限SuperNode設定-1時生效
SaveNewPeers | 是否把下載來的鄰居資訊存到本地設定檔裡面
[SuperNode](#SuperNode) | SuperNode相關設定
P2P | P2P相關設定SuperMode用不到
[NTPConfig](#NTPConfig) | NTP時間同步相關設定
<a name="SuperNode"></a>SuperNode | Description
---------------------|:-----
UseSuperNode | 是否啟用SuperNode
PSKey | 和SuperNode通訊用的PreShared Key
EndpointV4 | SuperNode的IPv4 Endpoint
PubKeyV4 | SuperNode的IPv4公鑰
EndpointV6 | SuperNode的IPv6 Endpoint
PubKeyV6 | SuperNode的IPv6公鑰
EndpointEdgeAPIUrl | SuperNode的EdgeAPI存取路徑
SkipLocalIP | 不回報本地IP避免和其他Edge內網直連
SuperNodeInfoTimeout | 實驗性選項SuperNode離線超時切換成P2P模式<br>需先打開P2P模式<br>`UseP2P=false`本選項無效<br>P2P模式尚未測試穩定性未知不推薦使用
<a name="NTPConfig"></a>NTPConfig | Description
--------------------|:-----
UseNTP | 是否使用NTP同步時間
MaxServerUse | 向多少NTP伺服器發送請求
SyncTimeInterval | 多久同步一次時間
NTPTimeout | NTP伺服器連線Timeout
Servers | NTP伺服器列表
## V4 V6 兩個公鑰
為什麼要分開IPv4和IPv6呢?
@ -284,12 +422,14 @@ Relay node其實也是一個edge node只不過被設定成為interface=dummy
因為如果用127.0.0.1連接supernodesupernode看到封包的src IP就是127.0.0.1就會把127.0.0.1分發給`Node_1`和`Node_2`
`Node_1`和`Node_2`看到`Node_R`的連線地址是`127.0.0.1`,就連不上了
## Quick start
執行此範例設定檔(請開三個terminal):
#### Run example config
在**不同terminal**分別執行以下命令
```bash
./etherguard-go -config example_config/super_mode/s1.yaml -mode super
./etherguard-go -config example_config/super_mode/n1.yaml -mode edge
./etherguard-go -config example_config/super_mode/n2.yaml -mode edge
./etherguard-go -config example_config/super_mode/Node_super.yaml -mode super
./etherguard-go -config example_config/super_mode/Node_edge001.yaml -mode edge
./etherguard-go -config example_config/super_mode/Node_edge002.yaml -mode edge
```
因為是stdio模式stdin會讀入VPN網路
請在其中一個edge視窗中鍵入

View File

@ -1,15 +1,15 @@
Config output dir: /tmp/eg_gen
Config output dir: /tmp/eg_gen_super
ConfigTemplate for super node: ""
ConfigTemplate for edge node: ""
Network name: eg_net
Network name: EgNet
Super Node:
Listen port: 3456
EdgeAPI prefix: /eg_net/eg_api
Endpoint(IPv4)(optional): example.com
Endpoint(IPv6)(optional): example.com
Endpoint(EdgeAPI): http://example.com:3456/eg_net/eg_api
Endpoint(IPv4)(optional): 127.0.0.1
Endpoint(IPv6)(optional):
Endpoint(EdgeAPI): http://127.0.0.1:3456/eg_net/eg_api
Edge Node:
Node IDs: "[1~10,11,19,23,29,31,55~66,88~99]"
Node IDs: "[1~2,100]"
MacAddress prefix: ""
IPv4 range: 192.168.76.0/24
IPv6 range: fd95:71cb:a3df:e586::/64

View File

@ -1,47 +0,0 @@
NodeName: NodeSuper
PostScript: ""
PrivKeyV4: mL5IW0GuqbjgDeOJuPHBU2iJzBPNKhaNEXbIGwwYWWk=
PrivKeyV6: +EdOKIoBp/EvIusHDsvXhV1RJYbyN3Qr8nxlz35wl3I=
ListenPort: 3000
ListenPort_EdgeAPI: "3000"
ListenPort_ManageAPI: "3000"
API_Prefix: /eg_api
RePushConfigInterval: 30
HttpPostInterval: 50
PeerAliveTimeout: 70
SendPingInterval: 15
LogLevel:
LogLevel: normal
LogTransit: true
LogControl: true
LogNormal: false
LogInternal: true
LogNTP: false
Passwords:
ShowState: passwd_showstate
AddPeer: passwd_addpeer
DelPeer: passwd_delpeer
UpdatePeer: passwd_updatepeer
UpdateSuper: passwd_updatesuper
GraphRecalculateSetting:
StaticMode: false
JitterTolerance: 5
JitterToleranceMultiplier: 1.01
TimeoutCheckInterval: 5
RecalculateCoolDown: 5
NextHopTable: {}
EdgeTemplate: example_config/super_mode/n1.yaml
UsePSKForInterEdge: true
Peers:
- NodeID: 1
Name: Node_01
PubKey: ZqzLVSbXzjppERslwbf2QziWruW3V/UIx9oqwU8Fn3I=
PSKey: iPM8FXfnHVzwjguZHRW9bLNY+h7+B1O2oTJtktptQkI=
AdditionalCost: 10
SkipLocalIP: false
- NodeID: 2
Name: Node_02
PubKey: dHeWQtlTPQGy87WdbUARS4CtwVaR2y7IQ1qcX4GKSXk=
PSKey: juJMQaGAaeSy8aDsXSKNsPZv/nFiPj4h/1G70tGYygs=
AdditionalCost: 10
SkipLocalIP: false

View File

@ -92,16 +92,17 @@ func GenNMCfg(NMCinfigPath string, printExample bool) (err error) {
if !all_verts[NodeID] {
return fmt.Errorf("duplicate definition: NodeID %v ", NodeID)
}
if endpoint != "" {
_, err = conn.LookupIP(endpoint, 0)
if err != nil {
return err
}
}
pri, pub := device.RandomKeyPair()
edge_infos[NodeID] = edge_info{
Endpoint: endpoint,
PrivKey: pri.ToString(),
PubKey: pub.ToString(),
PersistentKeepalive: edgeinfo.PersistentKeepalive,
ConnectedEdge: make(map[mtypes.Vertex]bool),
}
all_verts[NodeID] = false
@ -118,7 +119,7 @@ func GenNMCfg(NMCinfigPath string, printExample bool) (err error) {
s := edge.Src_nodeID
d := edge.Dst_nodeID
if len(edge_infos[s].Endpoint)+len(edge_infos[d].Endpoint) == 0 {
return fmt.Errorf("there are an edge between node %v and %v, but non of them have endpoint", s, d)
return fmt.Errorf("there are an edge between node [%v , %v], but non of them have endpoint", s, d)
}
edge_infos[s].ConnectedEdge[d] = true
edge_infos[d].ConnectedEdge[s] = true
@ -132,7 +133,7 @@ func GenNMCfg(NMCinfigPath string, printExample bool) (err error) {
pbyte := mtypes.RandomBytes(4, []byte{0xaa, 0xbb, 0xcc, 0xdd})
pbyte[0] &^= 0b00000001
pbyte[0] |= 0b00000010
NMCfg.EdgeNode.MacPrefix = fmt.Sprintf("%X:%X:%X:%X", pbyte[0], pbyte[1], pbyte[2], pbyte[3])
NMCfg.EdgeNode.MacPrefix = fmt.Sprintf("%02X:%02X:%02X:%02X", pbyte[0], pbyte[1], pbyte[2], pbyte[3])
}
dist, next, err := g.FloydWarshall(false)
@ -177,6 +178,8 @@ func GenNMCfg(NMCinfigPath string, printExample bool) (err error) {
econfig.NodeID = NodeID
idstr := fmt.Sprintf("%0"+strconv.Itoa(len(MaxNodeID.ToString()))+"d", NodeID)
econfig.NodeName = NMCfg.NetworkName + idstr
PersistentKeepalive := uint32(30)
econfig.ListenPort = 0
if Edge.Endpoint != "" {
ps := strings.Split(Edge.Endpoint, ":")
pss := ps[len(ps)-1]
@ -185,6 +188,7 @@ func GenNMCfg(NMCinfigPath string, printExample bool) (err error) {
return err
}
econfig.ListenPort = int(port)
PersistentKeepalive = 0
}
econfig.Peers = make([]mtypes.PeerInfo, 0)
for CNodeID, _ := range Edge.ConnectedEdge {
@ -193,7 +197,7 @@ func GenNMCfg(NMCinfigPath string, printExample bool) (err error) {
PubKey: edge_infos[CNodeID].PubKey,
PSKey: pskdb.GetPSK(NodeID, CNodeID).ToString(),
EndPoint: edge_infos[CNodeID].Endpoint,
PersistentKeepalive: Edge.PersistentKeepalive,
PersistentKeepalive: PersistentKeepalive,
Static: true,
})
}

View File

@ -220,7 +220,7 @@ func GenSuperCfg(SMCinfigPath string, printExample bool) (err error) {
pbyte := mtypes.RandomBytes(4, []byte{0xaa, 0xbb, 0xcc, 0xdd})
pbyte[0] &^= 0b00000001
pbyte[0] |= 0b00000010
MacPrefix = fmt.Sprintf("%X:%X:%X:%X", pbyte[0], pbyte[1], pbyte[2], pbyte[3])
MacPrefix = fmt.Sprintf("%02X:%02X:%02X:%02X", pbyte[0], pbyte[1], pbyte[2], pbyte[3])
}
IPv4Block := SMCfg.EdgeNode.IPv4Range
@ -264,6 +264,7 @@ func GenSuperCfg(SMCinfigPath string, printExample bool) (err error) {
peerceconf.DynamicRoute.SuperNode.EndpointV4 = EndpointV4 + ":" + ListenPort
peerceconf.DynamicRoute.SuperNode.EndpointV6 = EndpointV6 + ":" + ListenPort
peerceconf.DynamicRoute.SuperNode.EndpointEdgeAPIUrl = EndpointEdgeAPIUrl
peerceconf.DynamicRoute.P2P.GraphRecalculateSetting.DampingResistance = 0
peerceconf.Interface.MacAddrPrefix = MacPrefix
peerceconf.Interface.IPv4CIDR = IPv4Block
peerceconf.Interface.IPv6CIDR = IPv6Block

View File

@ -68,5 +68,4 @@ type edge_info struct {
ConnectedEdge map[mtypes.Vertex]bool
PrivKey string
PubKey string
PersistentKeepalive uint32
}

View File

@ -51,6 +51,9 @@ func Edge(configPath string, useUAPI bool, printExample bool, bindmode string) (
if len(NodeName) > 32 {
return errors.New("Node name can't longer than 32 :" + NodeName)
}
if econfig.DynamicRoute.P2P.GraphRecalculateSetting.DampingResistance < 0 || econfig.DynamicRoute.P2P.GraphRecalculateSetting.DampingResistance >= 1 {
return fmt.Errorf("DampingResistance must in range [0,1) : %v", econfig.DynamicRoute.P2P.GraphRecalculateSetting.DampingResistance)
}
var logLevel int
switch econfig.LogLevel.LogLevel {
case "verbose", "debug":

View File

@ -684,7 +684,7 @@ func manage_peeradd(w http.ResponseWriter, r *http.Request) {
func manage_peerupdate(w http.ResponseWriter, r *http.Request) {
params := r.URL.Query()
toUpdate := mtypes.NodeID_Boardcast
toUpdate := mtypes.NodeID_Broadcast
var err error
var NodeID mtypes.Vertex
@ -856,7 +856,7 @@ func manage_superupdate(w http.ResponseWriter, r *http.Request) {
func manage_peerdel(w http.ResponseWriter, r *http.Request) {
params := r.URL.Query()
toDelete := mtypes.NodeID_Boardcast
toDelete := mtypes.NodeID_Broadcast
var err error
var NodeID mtypes.Vertex
@ -900,7 +900,7 @@ func manage_peerdel(w http.ResponseWriter, r *http.Request) {
toDelete = peerinfo.NodeID
}
}
if toDelete == mtypes.NodeID_Boardcast {
if toDelete == mtypes.NodeID_Broadcast {
w.WriteHeader(http.StatusNotFound)
w.Write([]byte(fmt.Sprintf("Paramater PrivKey: \"%v\" not found", PubKey)))
return

View File

@ -100,6 +100,9 @@ func Super(configPath string, useUAPI bool, printExample bool, bindmode string)
if sconfig.RePushConfigInterval <= 0 {
return fmt.Errorf("RePushConfigInterval must > 0 : %v", sconfig.RePushConfigInterval)
}
if sconfig.GraphRecalculateSetting.DampingResistance < 0 || sconfig.GraphRecalculateSetting.DampingResistance >= 1 {
return fmt.Errorf("DampingResistance must in range [0,1) : %v", sconfig.GraphRecalculateSetting.DampingResistance)
}
var logLevel int
switch sconfig.LogLevel.LogLevel {

View File

@ -10,7 +10,7 @@ import (
type Vertex uint16
const (
NodeID_Boardcast Vertex = math.MaxUint16 - iota // Normal boardcast, boardcast with route table
NodeID_Broadcast Vertex = math.MaxUint16 - iota // Normal boardcast, boardcast with route table
NodeID_AllPeer Vertex = math.MaxUint16 - iota // p2p mode: boardcast to every know peer and prevent dup. super mode: send to supernode
NodeID_SuperNode Vertex = math.MaxUint16 - iota
NodeID_Invalid Vertex = math.MaxUint16 - iota
@ -99,15 +99,15 @@ type SuperPeerInfo struct {
type LoggerInfo struct {
LogLevel string `yaml:"LogLevel"`
LogTransit bool `yaml:"LogTransit"`
LogControl bool `yaml:"LogControl"`
LogNormal bool `yaml:"LogNormal"`
LogControl bool `yaml:"LogControl"`
LogInternal bool `yaml:"LogInternal"`
LogNTP bool `yaml:"LogNTP"`
}
func (v *Vertex) ToString() string {
switch *v {
case NodeID_Boardcast:
case NodeID_Broadcast:
return "Boardcast"
case NodeID_AllPeer:
return "Control"

View File

@ -32,6 +32,64 @@ const (
BroadcastPeer
)
func (v Usage) IsNormal() bool {
return v == NormalPacket
}
func (v Usage) IsControl() bool {
switch v {
case Register:
return true
case ServerUpdate:
return true
case PingPacket:
return true
case PongPacket:
return true
case QueryPeer:
return true
case BroadcastPeer:
return true
default:
return false
}
}
func (v Usage) IsControl_Super2Edge() bool {
switch v {
case ServerUpdate:
return true
default:
return false
}
}
func (v Usage) IsControl_Edge2Super() bool {
switch v {
case Register:
return true
case PongPacket:
return true
default:
return false
}
}
func (v Usage) IsControl_Edge2Edge() bool {
switch v {
case PingPacket:
return true
case PongPacket:
return true
case QueryPeer:
return true
case BroadcastPeer:
return true
default:
return false
}
}
func NewEgHeader(pac []byte) (e EgHeader, err error) {
if len(pac) != EgHeaderLen {
err = errors.New("invalid packet size")

View File

@ -189,7 +189,7 @@ func (g *IG) UpdateLatencyMulti(pong_info []mtypes.PongMsg, recalculate bool, ch
newval := pong_msg.Timediff
if _, ok := g.gsetting.ManualLatency[u]; ok {
if _, ok := g.gsetting.ManualLatency[u][v]; ok {
newval = g.gsetting.ManualLatency[u][v]
newval = g.gsetting.ManualLatency[u][v] / 1000 // s to ms
}
}
w := newval
@ -206,7 +206,7 @@ func (g *IG) UpdateLatencyMulti(pong_info []mtypes.PongMsg, recalculate bool, ch
g.edgelock.Unlock()
oldval := g.OldWeight(u, v, false)
g.edgelock.Lock()
if oldval != mtypes.Infinity {
if oldval != mtypes.Infinity && g.IsSuperMode && g.gsetting.DampingResistance > 0 {
w = oldval*g.gsetting.DampingResistance + newval*(1-g.gsetting.DampingResistance)
}
should_update = should_update || g.ShouldUpdate(oldval, w, false)

View File

@ -100,10 +100,11 @@ func (tap *StdIOTap) Read(buf []byte, offset int) (int, error) {
}
} // read a packet from the device (without any additional headers)
func (tap *StdIOTap) Write(buf []byte, offset int) (size int, err error) {
packet := make([]byte, len(buf[offset:]))
copy(packet, buf[offset:])
packet := buf[offset:]
switch tap.L2mode {
case KeyboardDebug:
packet = make([]byte, len(buf[offset:]))
copy(packet, buf[offset:])
src := Mac2charForm(packet[6:12])
dst := Mac2charForm(packet[0:6])
packet[10] = dst