Not test yet

This commit is contained in:
KusakabeSi
2021-08-20 17:32:50 +00:00
parent 87a62f873b
commit 4939f9f0c4
18 changed files with 1577 additions and 465 deletions

1
.gitignore vendored
View File

@ -1,2 +1,3 @@
go.sum go.sum
etherguard-go etherguard-go
.ipynb_checkpoints

2
.vscode/launch.json vendored
View File

@ -10,7 +10,7 @@
"request": "launch", "request": "launch",
"mode": "auto", "mode": "auto",
"program": "${workspaceFolder}", "program": "${workspaceFolder}",
"args":["-config","example_config/n1.yaml","-mode","edge"], "args":["-config","example_config/n1.yaml","-mode","super", "--example"],
} }
] ]
} }

103
config/config.go Normal file
View File

@ -0,0 +1,103 @@
package config
type EdgeConfig struct {
Interface InterfaceConf
NodeID Vertex
NodeName string
PrivKey string
ListenPort int
LogLevel LoggerInfo
DynamicRoute DynamicRouteInfo
NextHopTable NextHopTable
Peers []PeerInfo
}
type SuperConfig struct {
NodeName string
PrivKeyV4 string
PrivKeyV6 string
ListenPort int
LogLevel LoggerInfo
GraphRecalculateSetting GraphRecalculateSetting
Peers []PeerInfo
}
type InterfaceConf struct {
Itype string
IfaceID int
Name string
MacAddr string
MTU int
RecvAddr string
SendAddr string
HumanFriendly bool
}
type PeerInfo struct {
NodeID Vertex
PubKey string
EndPoint string
Static bool
}
type LoggerInfo struct {
LogLevel string
LogTransit bool
}
// Nonnegative integer ID of vertex
type Vertex uint32
type DynamicRouteInfo struct {
SendPingInterval float64
DupCheckTimeout float64
ConnTimeOut float64
SaveNewPeers bool
SuperNode SuperInfo
P2P P2Pinfo
NTPconfig NTPinfo
}
type NTPinfo struct {
UseNTP bool
MaxServerUse int
Servers []string
}
type SuperInfo struct {
UseSuperNode bool
ConnURLV4 string
PubKeyV4 string
ConnURLV6 string
PubKeyV6 string
APIUrl string
SuperNodeInfoTimeout float64
}
type P2Pinfo struct {
UseP2P bool
SendPeerInterval float64
PeerAliveTimeout float64
GraphRecalculateSetting GraphRecalculateSetting
}
type GraphRecalculateSetting struct {
JitterTolerance float64
JitterToleranceMultiplier float64
NodeReportTimeout float64
RecalculateCoolDown float64
}
type DistTable map[Vertex]map[Vertex]float64
type NextHopTable map[Vertex]map[Vertex]*Vertex
type HTTP_Peerinfo struct {
NodeID Vertex
PubKey string
PSKey string
Connurl map[string]bool
}
type HTTP_Peers struct {
Peers map[string]HTTP_Peerinfo
}

View File

@ -6,16 +6,19 @@
package device package device
import ( import (
"encoding/base64"
"runtime" "runtime"
"sync" "sync"
"sync/atomic" "sync/atomic"
"time" "time"
"github.com/KusakabeSi/EtherGuardVPN/config"
"github.com/KusakabeSi/EtherGuardVPN/conn" "github.com/KusakabeSi/EtherGuardVPN/conn"
"github.com/KusakabeSi/EtherGuardVPN/path" "github.com/KusakabeSi/EtherGuardVPN/path"
"github.com/KusakabeSi/EtherGuardVPN/ratelimiter" "github.com/KusakabeSi/EtherGuardVPN/ratelimiter"
"github.com/KusakabeSi/EtherGuardVPN/rwcancel" "github.com/KusakabeSi/EtherGuardVPN/rwcancel"
"github.com/KusakabeSi/EtherGuardVPN/tap" "github.com/KusakabeSi/EtherGuardVPN/tap"
fixed_time_cache "github.com/KusakabeSi/go-cache"
) )
type Device struct { type Device struct {
@ -61,16 +64,30 @@ type Device struct {
peers struct { peers struct {
sync.RWMutex // protects keyMap sync.RWMutex // protects keyMap
keyMap map[NoisePublicKey]*Peer keyMap map[NoisePublicKey]*Peer
IDMap map[path.Vertex]*Peer IDMap map[config.Vertex]*Peer
SuperPeer map[NoisePublicKey]*Peer
Peer_state [32]byte
} }
event_tryendpoint chan struct{}
EdgeConfigPath string
EdgeConfig *config.EdgeConfig
Event_server_register chan path.RegisterMsg
Event_server_pong chan path.PongMsg
Event_server_NhTable_changed chan struct{}
Event_save_config chan struct{}
indexTable IndexTable indexTable IndexTable
cookieChecker CookieChecker cookieChecker CookieChecker
ID path.Vertex IsSuperNode bool
NhTable path.NextHopTable ID config.Vertex
l2fib map[tap.MacAddress]path.Vertex graph *path.IG
LogTransit bool l2fib map[tap.MacAddress]config.Vertex
LogTransit bool
DRoute config.DynamicRouteInfo
DupData fixed_time_cache.Cache
pool struct { pool struct {
messageBuffers *WaitPool messageBuffers *WaitPool
@ -135,7 +152,13 @@ func removePeerLocked(device *Device, peer *Peer, key NoisePublicKey) {
peer.Stop() peer.Stop()
// remove from peer map // remove from peer map
id := peer.ID
delete(device.peers.keyMap, key) delete(device.peers.keyMap, key)
if id == path.SuperNodeMessage {
delete(device.peers.SuperPeer, key)
} else {
delete(device.peers.IDMap, id)
}
} }
// changeState attempts to change the device state to match want. // changeState attempts to change the device state to match want.
@ -279,7 +302,7 @@ func (device *Device) SetPrivateKey(sk NoisePrivateKey) error {
return nil return nil
} }
func NewDevice(tapDevice tap.Device, id path.Vertex, bind conn.Bind, logger *Logger) *Device { func NewDevice(tapDevice tap.Device, id config.Vertex, bind conn.Bind, logger *Logger, graph *path.IG, IsSuperNode bool, theconfigpath string, theconfig *config.EdgeConfig, superevents *path.SUPER_Events) *Device {
device := new(Device) device := new(Device)
device.state.state = uint32(deviceStateDown) device.state.state = uint32(deviceStateDown)
device.closed = make(chan struct{}) device.closed = make(chan struct{})
@ -293,13 +316,32 @@ func NewDevice(tapDevice tap.Device, id path.Vertex, bind conn.Bind, logger *Log
} }
device.tap.mtu = int32(mtu) device.tap.mtu = int32(mtu)
device.peers.keyMap = make(map[NoisePublicKey]*Peer) device.peers.keyMap = make(map[NoisePublicKey]*Peer)
device.peers.IDMap = make(map[path.Vertex]*Peer) device.peers.IDMap = make(map[config.Vertex]*Peer)
device.IsSuperNode = IsSuperNode
device.ID = id device.ID = id
device.l2fib = make(map[tap.MacAddress]path.Vertex) device.graph = graph
device.l2fib = make(map[tap.MacAddress]config.Vertex)
device.rate.limiter.Init() device.rate.limiter.Init()
device.indexTable.Init() device.indexTable.Init()
device.PopulatePools() device.PopulatePools()
if IsSuperNode {
device.Event_server_pong = superevents.Event_server_pong
device.Event_server_register = superevents.Event_server_register
device.Event_server_NhTable_changed = superevents.Event_server_NhTable_changed
go device.RoutineRecalculateNhTable()
} else {
device.EdgeConfigPath = theconfigpath
device.EdgeConfig = theconfig
device.DRoute = theconfig.DynamicRoute
device.DupData = *fixed_time_cache.NewCache(path.S2TD(theconfig.DynamicRoute.DupCheckTimeout))
device.event_tryendpoint = make(chan struct{}, 1<<6)
device.Event_save_config = make(chan struct{}, 1<<5)
go device.RoutineSetEndpoint()
go device.RoutineRegister()
go device.RoutineSendPing()
go device.RoutineRecalculateNhTable()
}
// create queues // create queues
device.queue.handshake = newHandshakeQueue() device.queue.handshake = newHandshakeQueue()
@ -332,6 +374,49 @@ func (device *Device) LookupPeer(pk NoisePublicKey) *Peer {
return device.peers.keyMap[pk] return device.peers.keyMap[pk]
} }
func (device *Device) LookupPeerByStr(pks string) *Peer {
var pk NoisePublicKey
sk_slice, _ := base64.StdEncoding.DecodeString(pks)
copy(pk[:], sk_slice)
return device.LookupPeer(pk)
}
func PubKey2Str(pk NoisePublicKey) (result string) {
result = string(base64.StdEncoding.EncodeToString(pk[:]))
return
}
func PriKey2Str(pk NoisePrivateKey) (result string) {
result = string(base64.StdEncoding.EncodeToString(pk[:]))
return
}
func PSKeyStr(pk NoisePresharedKey) (result string) {
result = string(base64.StdEncoding.EncodeToString(pk[:]))
return
}
func Str2PubKey(k string) (pk NoisePublicKey) {
sk_slice, _ := base64.StdEncoding.DecodeString(k)
copy(pk[:], sk_slice)
return
}
func Str2PriKey(k string) (pk NoisePrivateKey) {
sk_slice, _ := base64.StdEncoding.DecodeString(k)
copy(pk[:], sk_slice)
return
}
func Str2PSKey(k string) (pk NoisePresharedKey) {
sk_slice, _ := base64.StdEncoding.DecodeString(k)
copy(pk[:], sk_slice)
return
}
func (device *Device) GetIPMap() map[config.Vertex]*Peer {
return device.peers.IDMap
}
func (device *Device) RemovePeer(key NoisePublicKey) { func (device *Device) RemovePeer(key NoisePublicKey) {
device.peers.Lock() device.peers.Lock()
defer device.peers.Unlock() defer device.peers.Unlock()
@ -352,7 +437,7 @@ func (device *Device) RemoveAllPeers() {
} }
device.peers.keyMap = make(map[NoisePublicKey]*Peer) device.peers.keyMap = make(map[NoisePublicKey]*Peer)
device.peers.IDMap = make(map[path.Vertex]*Peer) device.peers.IDMap = make(map[config.Vertex]*Peer)
} }
func (device *Device) Close() { func (device *Device) Close() {

View File

@ -13,20 +13,23 @@ import (
"sync/atomic" "sync/atomic"
"time" "time"
"github.com/KusakabeSi/EtherGuardVPN/config"
"github.com/KusakabeSi/EtherGuardVPN/conn" "github.com/KusakabeSi/EtherGuardVPN/conn"
"github.com/KusakabeSi/EtherGuardVPN/path" "github.com/KusakabeSi/EtherGuardVPN/path"
) )
type Peer struct { type Peer struct {
isRunning AtomicBool isRunning AtomicBool
sync.RWMutex // Mostly protects endpoint, but is generally taken whenever we modify peer sync.RWMutex // Mostly protects endpoint, but is generally taken whenever we modify peer
keypairs Keypairs keypairs Keypairs
handshake Handshake handshake Handshake
device *Device device *Device
endpoint conn.Endpoint endpoint conn.Endpoint
stopping sync.WaitGroup // routines pending stop endpoint_trylist map[string]time.Time
LastPingReceived time.Time
stopping sync.WaitGroup // routines pending stop
ID path.Vertex ID config.Vertex
// These fields are accessed with atomic operations, which must be // These fields are accessed with atomic operations, which must be
// 64-bit aligned even on 32-bit platforms. Go guarantees that an // 64-bit aligned even on 32-bit platforms. Go guarantees that an
@ -67,7 +70,7 @@ type Peer struct {
persistentKeepaliveInterval uint32 // accessed atomically persistentKeepaliveInterval uint32 // accessed atomically
} }
func (device *Device) NewPeer(pk NoisePublicKey, id path.Vertex) (*Peer, error) { func (device *Device) NewPeer(pk NoisePublicKey, id config.Vertex) (*Peer, error) {
if device.isClosed() { if device.isClosed() {
return nil, errors.New("device closed") return nil, errors.New("device closed")
} }
@ -117,8 +120,13 @@ func (device *Device) NewPeer(pk NoisePublicKey, id path.Vertex) (*Peer, error)
peer.endpoint = nil peer.endpoint = nil
// add // add
device.peers.keyMap[pk] = peer if id == path.SuperNodeMessage { // To communicate with supernode
device.peers.IDMap[id] = peer device.peers.SuperPeer[pk] = peer
} else { // Regular peer, other edgenodes
_, ok = device.peers.IDMap[id]
device.peers.keyMap[pk] = peer
device.peers.IDMap[id] = peer
}
// start peer // start peer
peer.timersInit() peer.timersInit()
@ -288,3 +296,11 @@ func (peer *Peer) SetEndpointFromPacket(endpoint conn.Endpoint) {
peer.endpoint = endpoint peer.endpoint = endpoint
peer.Unlock() peer.Unlock()
} }
func (peer *Peer) GetEndpointSrcStr() string {
return peer.endpoint.SrcToString()
}
func (peer *Peer) GetEndpointDstStr() string {
return peer.endpoint.DstToString()
}

View File

@ -17,6 +17,7 @@ import (
"golang.org/x/crypto/chacha20poly1305" "golang.org/x/crypto/chacha20poly1305"
"github.com/KusakabeSi/EtherGuardVPN/config"
"github.com/KusakabeSi/EtherGuardVPN/conn" "github.com/KusakabeSi/EtherGuardVPN/conn"
"github.com/KusakabeSi/EtherGuardVPN/path" "github.com/KusakabeSi/EtherGuardVPN/path"
"github.com/KusakabeSi/EtherGuardVPN/tap" "github.com/KusakabeSi/EtherGuardVPN/tap"
@ -411,8 +412,10 @@ func (peer *Peer) RoutineSequentialReceiver() {
} }
var EgBody path.EgHeader var EgBody path.EgHeader
var err error var err error
var src_nodeID path.Vertex var src_nodeID config.Vertex
var dst_nodeID path.Vertex var dst_nodeID config.Vertex
var packet_type path.Usage
should_process := false
should_receive := false should_receive := false
should_transfer := false should_transfer := false
elem.Lock() elem.Lock()
@ -445,57 +448,99 @@ func (peer *Peer) RoutineSequentialReceiver() {
EgBody, err = path.NewEgHeader(elem.packet[0:path.EgHeaderLen]) EgBody, err = path.NewEgHeader(elem.packet[0:path.EgHeaderLen])
src_nodeID = EgBody.GetSrc() src_nodeID = EgBody.GetSrc()
dst_nodeID = EgBody.GetDst() dst_nodeID = EgBody.GetDst()
//elem.packet = elem.packet[:EgBody.GetPacketLength()] elem.packet = elem.packet[:EgBody.GetPacketLength()]
packet_type = EgBody.GetUsage()
if dst_nodeID == device.ID { if device.IsSuperNode {
should_receive = true peer.LastPingReceived = time.Now()
} else if dst_nodeID == path.Boardcast { switch dst_nodeID {
should_receive = true case path.ControlMessage:
should_transfer = true should_process = true
} else if device.NhTable[device.ID][dst_nodeID] != nil { case path.SuperNodeMessage:
should_transfer = true should_process = true
default:
device.log.Errorf("Invalid dst_nodeID received. Check your code for bug")
}
} else { } else {
device.log.Verbosef("No route to peer ID %v", dst_nodeID) switch dst_nodeID {
goto skip case path.Boardcast:
should_receive = true
should_transfer = true
case path.PingMessage:
peer.LastPingReceived = time.Now()
should_process = true
case path.SuperNodeMessage:
should_process = true
case path.ControlMessage:
packet := elem.packet[path.EgHeaderLen:]
if device.CheckNoDup(packet) {
should_process = true
should_transfer = true
} else {
should_process = false
should_transfer = false
if device.LogTransit {
fmt.Printf("Duplicate packet received from %d through %d , src_nodeID = %d . Dropeed.\n", peer.ID, device.ID, src_nodeID)
}
}
case device.ID:
if packet_type == path.NornalPacket {
should_receive = true
} else {
should_process = true
}
default:
if _, ok := device.graph.NhTable[device.ID][dst_nodeID]; ok {
should_transfer = true
} else {
device.log.Verbosef("No route to peer ID %v", dst_nodeID)
}
}
} }
if should_transfer {
if should_transfer { //Send to another peer
l2ttl := EgBody.GetTTL() l2ttl := EgBody.GetTTL()
if l2ttl == 0 { if l2ttl == 0 {
device.log.Verbosef("TTL is 0 %v", dst_nodeID) device.log.Verbosef("TTL is 0 %v", dst_nodeID)
} else { } else {
EgBody.SetTTL(l2ttl - 1) EgBody.SetTTL(l2ttl - 1)
if dst_nodeID != path.Boardcast { if dst_nodeID == path.Boardcast { //Regular transfer algorithm
next_id := *device.NhTable[device.ID][dst_nodeID] device.TransitBoardcastPacket(src_nodeID, peer.ID, elem.packet, MessageTransportOffsetContent)
} else if dst_nodeID == path.ControlMessage { // Control Message will try send to every know node regardless the connectivity
skip_list := make(map[config.Vertex]bool)
skip_list[src_nodeID] = true //Don't send to conimg peer and source peer
skip_list[peer.ID] = true
device.SpreadPacket(skip_list, elem.packet, MessageTransportOffsetContent)
} else {
next_id := *device.graph.NhTable[device.ID][dst_nodeID]
peer_out = device.peers.IDMap[next_id] peer_out = device.peers.IDMap[next_id]
if device.LogTransit { if device.LogTransit {
fmt.Printf("Transfer packet from %d through %d to %d\n", peer.ID, device.ID, peer_out.ID) fmt.Printf("Transfer packet from %d through %d to %d\n", peer.ID, device.ID, peer_out.ID)
} }
device.SendPacket(peer_out, elem.packet, MessageTransportOffsetContent) device.SendPacket(peer_out, elem.packet, MessageTransportOffsetContent)
} else {
node_boardcast_list := path.GetBoardcastThroughList(device.ID, src_nodeID, device.NhTable)
for peer_id := range node_boardcast_list {
peer_out = device.peers.IDMap[peer_id]
if device.LogTransit {
fmt.Printf("Transfer packet from %d through %d to %d\n", peer.ID, device.ID, peer_out.ID)
}
device.SendPacket(peer_out, elem.packet, MessageTransportOffsetContent)
}
} }
} }
} }
if should_receive { if should_process {
src_macaddr := tap.GetSrcMacAddr(elem.packet[path.EgHeaderLen:]) if packet_type != path.NornalPacket {
device.l2fib[src_macaddr] = src_nodeID // Write to l2fib table device.process_received(packet_type, elem.packet[path.EgHeaderLen:])
_, err = device.tap.device.Write(elem.buffer[:MessageTransportOffsetContent+len(elem.packet)], MessageTransportOffsetContent+path.EgHeaderLen)
if err != nil && !device.isClosed() {
device.log.Errorf("Failed to write packet to TUN device: %v", err)
} }
if len(peer.queue.inbound.c) == 0 { }
err = device.tap.device.Flush()
if err != nil { if should_receive { // Write message to tap device
peer.device.log.Errorf("Unable to flush packets: %v", err) if packet_type == path.NornalPacket {
src_macaddr := tap.GetSrcMacAddr(elem.packet[path.EgHeaderLen:])
device.l2fib[src_macaddr] = src_nodeID // Write to l2fib table
_, err = device.tap.device.Write(elem.buffer[:MessageTransportOffsetContent+len(elem.packet)], MessageTransportOffsetContent+path.EgHeaderLen)
if err != nil && !device.isClosed() {
device.log.Errorf("Failed to write packet to TUN device: %v", err)
}
if len(peer.queue.inbound.c) == 0 {
err = device.tap.device.Flush()
if err != nil {
peer.device.log.Errorf("Unable to flush packets: %v", err)
}
} }
} }
} }

460
device/receivesendproc.go Normal file
View File

@ -0,0 +1,460 @@
package device
import (
"bytes"
"encoding/json"
"errors"
"fmt"
"hash/crc32"
"io/ioutil"
"net/http"
"time"
"github.com/KusakabeSi/EtherGuardVPN/config"
"github.com/KusakabeSi/EtherGuardVPN/path"
"gopkg.in/yaml.v2"
)
func (device *Device) SendPacket(peer *Peer, packet []byte, offset int) {
if peer == nil {
return
}
var elem *QueueOutboundElement
elem = device.NewOutboundElement()
copy(elem.buffer[offset:offset+len(packet)], packet)
elem.packet = elem.buffer[offset : offset+len(packet)]
if peer.isRunning.Get() {
peer.StagePacket(elem)
elem = nil
peer.SendStagedPackets()
}
}
func (device *Device) BoardcastPacket(skip_list map[config.Vertex]bool, packet []byte, offset int) { // Send packet to all connected peers
send_list := device.graph.GetBoardcastList(device.ID)
for node_id, _ := range skip_list {
send_list[node_id] = false
}
for node_id, should_send := range send_list {
if should_send {
device.SendPacket(device.peers.IDMap[node_id], packet, offset)
}
}
}
func (device *Device) SpreadPacket(skip_list map[config.Vertex]bool, packet []byte, offset int) { // Send packet to all peers no matter it is alive
for peer_id, peer_out := range device.peers.IDMap {
if _, ok := skip_list[peer_id]; ok {
if device.LogTransit {
fmt.Printf("Skipped Spread Packet packet through %d to %d\n", device.ID, peer_out.ID)
}
continue
}
if device.LogTransit {
fmt.Printf("Spread Packet packet through %d to %d\n", device.ID, peer_out.ID)
}
device.SendPacket(peer_out, packet, MessageTransportOffsetContent)
}
}
func (device *Device) TransitBoardcastPacket(src_nodeID config.Vertex, in_id config.Vertex, packet []byte, offset int) {
node_boardcast_list := device.graph.GetBoardcastThroughList(device.ID, in_id, src_nodeID)
for peer_id := range node_boardcast_list {
peer_out := device.peers.IDMap[peer_id]
if device.LogTransit {
fmt.Printf("Transfer packet from %d through %d to %d\n", in_id, device.ID, peer_out.ID)
}
device.SendPacket(peer_out, packet, offset)
}
}
func (device *Device) Send2Super(packet []byte, offset int) {
if device.DRoute.SuperNode.UseSuperNode {
for _, peer_out := range device.peers.SuperPeer {
if device.LogTransit {
fmt.Printf("Send to supernode %s\n", peer_out.endpoint.DstToString())
}
device.SendPacket(peer_out, packet, offset)
}
}
}
func (device *Device) CheckNoDup(packet []byte) bool {
hasher := crc32.New(crc32.MakeTable(crc32.Castagnoli))
hasher.Write(packet)
crc32result := hasher.Sum32()
_, ok := device.DupData.Get(crc32result)
device.DupData.Set(crc32result, true)
return !ok
}
func (device *Device) process_received(msg_type path.Usage, body []byte) (err error) {
if device.IsSuperNode {
switch msg_type {
case path.Register:
if content, err := path.ParseRegisterMsg(body); err == nil {
return device.server_process_RegisterMsg(content)
}
case path.PongPacket:
if content, err := path.ParsePongMsg(body); err == nil {
return device.server_process_Pong(content)
}
default:
err = errors.New("Not a valid msg_type")
}
} else {
switch msg_type {
case path.UpdatePeer:
if content, err := path.ParseUpdatePeerMsg(body); err == nil {
go device.process_UpdatePeerMsg(content)
}
case path.UpdateNhTable:
if content, err := path.ParseUpdateNhTableMsg(body); err == nil {
go device.process_UpdateNhTableMsg(content)
}
case path.PingPacket:
if content, err := path.ParsePingMsg(body); err == nil {
return device.process_ping(content)
}
case path.PongPacket:
if content, err := path.ParsePongMsg(body); err == nil {
return device.process_pong(content)
}
case path.RequestPeer:
if content, err := path.ParseRequestPeerMsg(body); err == nil {
return device.process_RequestPeerMsg(content)
}
case path.BoardcastPeer:
if content, err := path.ParseBoardcastPeerMsg(body); err == nil {
return device.process_BoardcastPeerMsg(content)
}
default:
err = errors.New("Not a valid msg_type")
}
}
return
}
func (device *Device) server_process_RegisterMsg(content path.RegisterMsg) error {
device.Event_server_register <- content
return nil
}
func (device *Device) server_process_Pong(content path.PongMsg) error {
device.Event_server_pong <- content
return nil
}
func (device *Device) process_ping(content path.PingMsg) error {
PongMSG := path.PongMsg{
Src_nodeID: content.Src_nodeID,
Dst_nodeID: device.ID,
Timediff: device.graph.GetCurrentTime().Sub(content.Time),
}
body, err := path.GetByte(&PongMSG)
if err != nil {
return err
}
buf := make([]byte, path.EgHeaderLen+len(body))
header, err := path.NewEgHeader(buf[:path.EgHeaderLen])
header.SetSrc(device.ID)
header.SetTTL(200)
header.SetUsage(path.PongPacket)
header.SetPacketLength(uint16(len(body)))
if device.DRoute.SuperNode.UseSuperNode {
header.SetDst(path.SuperNodeMessage)
device.Send2Super(buf, MessageTransportOffsetContent)
}
if device.DRoute.P2P.UseP2P {
header.SetDst(path.ControlMessage)
device.SpreadPacket(make(map[config.Vertex]bool), buf, MessageTransportOffsetContent)
}
return nil
}
func (device *Device) process_pong(content path.PongMsg) error {
if device.DRoute.P2P.UseP2P {
device.graph.UpdateLentancy(content.Src_nodeID, content.Dst_nodeID, content.Timediff, false)
}
return nil
}
func (device *Device) process_UpdatePeerMsg(content path.UpdatePeerMsg) error {
var send_signal bool
if device.DRoute.SuperNode.UseSuperNode {
var peer_infos config.HTTP_Peers
if bytes.Equal(device.peers.Peer_state[:], content.State_hash[:]) {
return nil
}
resp, err := http.Get(device.DRoute.SuperNode.APIUrl + "/peerinfo?PubKey=" + PubKey2Str(device.staticIdentity.publicKey) + "?State=" + string(content.State_hash[:]))
if err != nil {
return err
}
defer resp.Body.Close()
allbytes, err := ioutil.ReadAll(resp.Body)
if err != nil {
return err
}
if err := json.Unmarshal(allbytes, &peer_infos); err != nil {
return err
}
for pubkey, peerinfo := range peer_infos.Peers {
if len(peerinfo.Connurl) == 0 {
return nil
}
sk := Str2PubKey(pubkey)
if bytes.Equal(sk[:], device.staticIdentity.publicKey[:]) {
continue
}
thepeer := device.LookupPeer(sk)
if thepeer == nil { //not exist in local
if device.graph.Weight(device.ID, peerinfo.NodeID) == path.Infinity { // add node to graph
device.graph.UpdateLentancy(device.ID, peerinfo.NodeID, path.S2TD(path.Infinity), false)
}
if device.graph.Weight(peerinfo.NodeID, device.ID) == path.Infinity { // add node to graph
device.graph.UpdateLentancy(peerinfo.NodeID, device.ID, path.S2TD(path.Infinity), false)
}
device.NewPeer(sk, peerinfo.NodeID)
thepeer = device.LookupPeer(sk)
if peerinfo.PSKey != "" {
pk := Str2PSKey(peerinfo.PSKey)
thepeer.handshake.presharedKey = pk
}
}
if thepeer.LastPingReceived.Add(path.S2TD(device.DRoute.P2P.PeerAliveTimeout)).Before(time.Now()) {
//Peer died, try to switch to this new endpoint
for url, _ := range peerinfo.Connurl {
thepeer.endpoint_trylist[url] = time.Time{} //another gorouting will process it
send_signal = true
}
}
}
device.peers.Peer_state = content.State_hash
if send_signal {
device.event_tryendpoint <- struct{}{}
}
}
return nil
}
func (device *Device) RoutineSetEndpoint() {
if !(device.DRoute.P2P.UseP2P || device.DRoute.SuperNode.UseSuperNode) {
return
}
for {
NextRun := false
<-device.event_tryendpoint
for _, thepeer := range device.peers.IDMap {
if thepeer.LastPingReceived.Add(path.S2TD(device.DRoute.P2P.PeerAliveTimeout)).After(time.Now()) {
//Peer alives
for url := range thepeer.endpoint_trylist {
delete(thepeer.endpoint_trylist, url)
}
} else {
//Peer died, try to switch to this new endpoint
for url, trytime := range thepeer.endpoint_trylist {
if trytime.Sub(time.Time{}) != time.Duration(0) && time.Now().Sub(trytime) > path.S2TD(device.DRoute.ConnTimeOut) {
delete(thepeer.endpoint_trylist, url)
} else {
endpoint, err := device.Bind().ParseEndpoint(url) //trying to bind first url in the list and wait device.DRoute.P2P.PeerAliveTimeout seconds
if err != nil {
device.log.Errorf("Can't bind " + url)
delete(thepeer.endpoint_trylist, url)
}
thepeer.SetEndpointFromPacket(endpoint)
NextRun = true
thepeer.endpoint_trylist[url] = time.Now()
//Send Ping message to it
packet, err := device.GeneratePingPacket(device.ID)
device.SendPacket(thepeer, packet, MessageTransportOffsetContent)
break
}
}
}
}
ClearChanLoop:
for {
select {
case <-device.event_tryendpoint:
default:
break ClearChanLoop
}
}
time.Sleep(path.S2TD(device.DRoute.P2P.PeerAliveTimeout))
if NextRun {
go device.SaveConfig()
device.event_tryendpoint <- struct{}{}
}
}
}
func (device *Device) SaveConfig() {
if device.DRoute.SaveNewPeers {
configbytes, _ := yaml.Marshal(device.EdgeConfig)
ioutil.WriteFile(device.EdgeConfigPath, configbytes, 0666)
}
}
func (device *Device) RoutineSendPing() {
if !(device.DRoute.P2P.UseP2P || device.DRoute.SuperNode.UseSuperNode) {
return
}
for {
packet, _ := device.GeneratePingPacket(device.ID)
device.SpreadPacket(make(map[config.Vertex]bool), packet, MessageTransportOffsetContent)
time.Sleep(path.S2TD(device.DRoute.SendPingInterval))
}
}
func (device *Device) RoutineRegister() {
if !(device.DRoute.SuperNode.UseSuperNode) {
return
}
for {
body, _ := path.GetByte(path.RegisterMsg{
Node_id: device.ID,
})
buf := make([]byte, path.EgHeaderLen+len(body))
header, _ := path.NewEgHeader(buf[0:path.EgHeaderLen])
header.SetDst(path.SuperNodeMessage)
header.SetTTL(0)
header.SetSrc(device.ID)
header.SetUsage(path.Register)
header.SetPacketLength(uint16(len(body)))
copy(buf[path.EgHeaderLen:], body)
device.Send2Super(buf, MessageTransportOffsetContent)
time.Sleep(path.S2TD(device.DRoute.SendPingInterval))
}
}
func (device *Device) RoutineRecalculateNhTable() {
if device.IsSuperNode {
for {
changed := device.graph.RecalculateNhTable(true)
if changed {
device.Event_server_NhTable_changed <- struct{}{}
}
time.Sleep(device.graph.NodeReportTimeout)
}
} else {
if !device.DRoute.P2P.UseP2P {
return
}
for {
device.graph.RecalculateNhTable(false)
time.Sleep(device.graph.NodeReportTimeout)
}
}
}
func (device *Device) GeneratePingPacket(src_nodeID config.Vertex) ([]byte, error) {
body, err := path.GetByte(&path.PingMsg{
Src_nodeID: src_nodeID,
Time: device.graph.GetCurrentTime(),
})
if err != nil {
return nil, err
}
buf := make([]byte, path.EgHeaderLen+len(body))
header, _ := path.NewEgHeader(buf[0:path.EgHeaderLen])
if err != nil {
return nil, err
}
header.SetDst(path.PingMessage)
header.SetTTL(0)
header.SetSrc(device.ID)
header.SetUsage(path.PingPacket)
header.SetPacketLength(uint16(len(body)))
copy(buf[path.EgHeaderLen:], body)
return buf, nil
}
func (device *Device) process_UpdateNhTableMsg(content path.UpdateNhTableMsg) error {
if device.DRoute.SuperNode.UseSuperNode {
if bytes.Equal(device.graph.NhTableHash[:], content.State_hash[:]) {
return nil
}
var NhTable config.NextHopTable
if bytes.Equal(device.graph.NhTableHash[:], content.State_hash[:]) {
return nil
}
resp, err := http.Get(device.DRoute.SuperNode.APIUrl + "/nhtable?PubKey=" + PubKey2Str(device.staticIdentity.publicKey) + "?State=" + string(content.State_hash[:]))
if err != nil {
return err
}
defer resp.Body.Close()
allbytes, err := ioutil.ReadAll(resp.Body)
if err != nil {
return err
}
if err := json.Unmarshal(allbytes, &NhTable); err != nil {
return err
}
device.graph.SetNHTable(NhTable, content.State_hash)
}
return nil
}
func (device *Device) process_RequestPeerMsg(content path.RequestPeerMsg) error {
if device.DRoute.P2P.UseP2P {
for pubkey, peer := range device.peers.keyMap {
if peer.ID >= path.Special_NodeID {
continue
}
response := path.BoardcastPeerMsg{
RequestID: content.Request_ID,
NodeID: peer.ID,
PubKey: pubkey,
PSKey: peer.handshake.presharedKey,
ConnURL: peer.endpoint.DstToString(),
}
body, err := path.GetByte(response)
if err != nil {
device.log.Errorf("Error at receivesendproc.go line221: ", err)
continue
}
buf := make([]byte, path.EgHeaderLen+len(body))
header, _ := path.NewEgHeader(buf[0:path.EgHeaderLen])
header.SetDst(path.ControlMessage)
header.SetTTL(200)
header.SetSrc(device.ID)
header.SetUsage(path.BoardcastPeer)
header.SetPacketLength(uint16(len(body)))
copy(buf[path.EgHeaderLen:], body)
device.SpreadPacket(make(map[config.Vertex]bool), buf, MessageTransportOffsetContent)
}
}
return nil
}
func (device *Device) process_BoardcastPeerMsg(content path.BoardcastPeerMsg) error {
if device.DRoute.P2P.UseP2P {
var sk NoisePublicKey
copy(sk[:], content.PubKey[:])
thepeer := device.LookupPeer(sk)
if thepeer == nil { //not exist in local
if device.graph.Weight(device.ID, content.NodeID) == path.Infinity { // add node to graph
device.graph.UpdateLentancy(device.ID, content.NodeID, path.S2TD(path.Infinity), false)
}
if device.graph.Weight(content.NodeID, device.ID) == path.Infinity { // add node to graph
device.graph.UpdateLentancy(content.NodeID, device.ID, path.S2TD(path.Infinity), false)
}
device.NewPeer(sk, content.NodeID)
thepeer = device.LookupPeer(sk)
var pk NoisePresharedKey
copy(pk[:], content.PSKey[:])
thepeer.handshake.presharedKey = pk
}
if thepeer.LastPingReceived.Add(path.S2TD(device.DRoute.P2P.PeerAliveTimeout)).Before(time.Now()) {
//Peer died, try to switch to this new endpoint
thepeer.endpoint_trylist[content.ConnURL] = time.Time{} //another gorouting will process it
}
}
return nil
}

View File

@ -14,6 +14,7 @@ import (
"sync/atomic" "sync/atomic"
"time" "time"
"github.com/KusakabeSi/EtherGuardVPN/config"
"github.com/KusakabeSi/EtherGuardVPN/path" "github.com/KusakabeSi/EtherGuardVPN/path"
"github.com/KusakabeSi/EtherGuardVPN/tap" "github.com/KusakabeSi/EtherGuardVPN/tap"
"golang.org/x/crypto/chacha20poly1305" "golang.org/x/crypto/chacha20poly1305"
@ -258,12 +259,13 @@ func (device *Device) RoutineReadFromTUN() {
} }
EgBody.SetSrc(device.ID) EgBody.SetSrc(device.ID)
EgBody.SetDst(dst_nodeID) EgBody.SetDst(dst_nodeID)
//EgBody.SetPacketLength(uint16(len(elem.packet))) EgBody.SetPacketLength(uint16(len(elem.packet)))
EgBody.SetTTL(200) EgBody.SetTTL(200)
EgBody.SetUsage(path.NornalPacket)
if dst_nodeID != path.Boardcast { if dst_nodeID != path.Boardcast {
var peer_out *Peer var peer_out *Peer
next_id := *device.NhTable[device.ID][dst_nodeID] next_id := *device.graph.NhTable[device.ID][dst_nodeID]
peer_out = device.peers.IDMap[next_id] peer_out = device.peers.IDMap[next_id]
if peer_out == nil { if peer_out == nil {
continue continue
@ -274,29 +276,12 @@ func (device *Device) RoutineReadFromTUN() {
peer_out.SendStagedPackets() peer_out.SendStagedPackets()
} }
} else { } else {
for key, _ := range path.GetBoardcastList(device.ID, device.NhTable) { device.BoardcastPacket(make(map[config.Vertex]bool, 0), elem.packet, offset)
device.SendPacket(device.peers.IDMap[key], elem.packet, offset)
}
} }
} }
} }
func (device *Device) SendPacket(peer *Peer, packet []byte, offset int) {
if peer == nil {
return
}
var elem *QueueOutboundElement
elem = device.NewOutboundElement()
copy(elem.buffer[offset:offset+len(packet)], packet)
elem.packet = elem.buffer[offset : offset+len(packet)]
if peer.isRunning.Get() {
peer.StagePacket(elem)
elem = nil
peer.SendStagedPackets()
}
}
func (peer *Peer) StagePacket(elem *QueueOutboundElement) { func (peer *Peer) StagePacket(elem *QueueOutboundElement) {
for { for {
select { select {

View File

@ -19,8 +19,8 @@ import (
"sync/atomic" "sync/atomic"
"time" "time"
"github.com/KusakabeSi/EtherGuardVPN/config"
"github.com/KusakabeSi/EtherGuardVPN/ipc" "github.com/KusakabeSi/EtherGuardVPN/ipc"
"github.com/KusakabeSi/EtherGuardVPN/path"
) )
type IPCError struct { type IPCError struct {
@ -284,7 +284,7 @@ func (device *Device) handlePublicKeyLine(peer *ipcSetPeer, value string) error
peer.created = peer.Peer == nil peer.created = peer.Peer == nil
if peer.created { if peer.created {
peer.Peer, err = device.NewPeer(publicKey, path.Vertex(h.Sum32())) peer.Peer, err = device.NewPeer(publicKey, config.Vertex(h.Sum32()))
if err != nil { if err != nil {
return ipcErrorf(ipc.IpcErrorInvalid, "failed to create new peer: %w", err) return ipcErrorf(ipc.IpcErrorInvalid, "failed to create new peer: %w", err)
} }

1
go.mod
View File

@ -3,6 +3,7 @@ module github.com/KusakabeSi/EtherGuardVPN
go 1.16 go 1.16
require ( require (
github.com/KusakabeSi/go-cache v0.0.0-20210817164551-57817be43e28
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2 golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2
golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57 golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57
gopkg.in/yaml.v2 v2.4.0 gopkg.in/yaml.v2 v2.4.0

20
main.go
View File

@ -43,18 +43,14 @@ func readYaml(filePath string, out interface{}) (err error) {
} }
var ( var (
config = flag.String("config", "", "Config path for the interface.") tconfig = flag.String("config", "", "Config path for the interface.")
mode = flag.String("mode", "edge", "Running mode. [super|edge]") mode = flag.String("mode", "edge", "Running mode. [super|edge]")
version = flag.Bool("version", false, "Show version") printExample = flag.Bool("example", false, "Print example config")
help = flag.Bool("help", false, "Show this help") nouapi = flag.Bool("no-uapi", false, "Do not use UAPI")
nouapi = flag.Bool("no-uapi", false, "Do not use UAPI") version = flag.Bool("version", false, "Show version")
help = flag.Bool("help", false, "Show this help")
) )
type LoggerInfo struct {
LogLevel string
LogTransit bool
}
func main() { func main() {
flag.Parse() flag.Parse()
if *version == true { if *version == true {
@ -73,9 +69,9 @@ func main() {
switch *mode { switch *mode {
case "edge": case "edge":
Edge(*config, !*nouapi) Edge(*tconfig, !*nouapi, *printExample)
case "super": case "super":
Super(*config, !*nouapi) Super(*tconfig, !*nouapi, *printExample)
case "path": case "path":
path.Solve() path.Solve()
default: default:

View File

@ -9,6 +9,7 @@ package main
import ( import (
"encoding/base64" "encoding/base64"
"errors"
"fmt" "fmt"
"net" "net"
"os" "os"
@ -16,93 +17,130 @@ import (
"strconv" "strconv"
"syscall" "syscall"
"github.com/KusakabeSi/EtherGuardVPN/config"
"github.com/KusakabeSi/EtherGuardVPN/conn" "github.com/KusakabeSi/EtherGuardVPN/conn"
"github.com/KusakabeSi/EtherGuardVPN/device" "github.com/KusakabeSi/EtherGuardVPN/device"
"github.com/KusakabeSi/EtherGuardVPN/ipc"
"github.com/KusakabeSi/EtherGuardVPN/path" "github.com/KusakabeSi/EtherGuardVPN/path"
"github.com/KusakabeSi/EtherGuardVPN/tap" "github.com/KusakabeSi/EtherGuardVPN/tap"
yaml "gopkg.in/yaml.v2" yaml "gopkg.in/yaml.v2"
) )
type edgeConfig struct { func printExampleEdgeConf() {
Interface InterfaceConf tconfig := config.EdgeConfig{
NodeID path.Vertex Interface: config.InterfaceConf{
NodeName string Itype: "stdio",
PrivKey string IfaceID: 5,
ListenPort int Name: "tap1",
LogLevel LoggerInfo MacAddr: "AA:BB:CC:DD:EE:FF",
SuperNode SuperInfo MTU: 1400,
NextHopTable path.NextHopTable RecvAddr: "127.0.0.1:4001",
Peers []PeerInfo SendAddr: "127.0.0.1:5001",
} HumanFriendly: true,
},
NodeID: 1,
NodeName: "Node01",
PrivKey: "SM8pGjT0r8njy1/7ffN4wMwF7nnJ8UYSjGRWpCqo3ng=",
ListenPort: 3001,
LogLevel: config.LoggerInfo{
LogLevel: "normal",
LogTransit: true,
},
DynamicRoute: config.DynamicRouteInfo{
SendPingInterval: 20,
DupCheckTimeout: 40,
ConnTimeOut: 30,
SaveNewPeers: true,
SuperNode: config.SuperInfo{
UseSuperNode: true,
ConnURLV4: "127.0.0.1:3000",
PubKeyV4: "j8i4dY1i7CUqd/ftaCSfCWosnURiztM+ExI7QRezU2Y=",
ConnURLV6: "[::1]:3000",
PubKeyV6: "cCcPlZw0hVkPSi15G+jpJpKE3TdCVEtO1nSiaedukGw=",
APIUrl: "http://127.0.0.1:3000/api",
SuperNodeInfoTimeout: 40,
},
P2P: config.P2Pinfo{
UseP2P: true,
SendPeerInterval: 20,
PeerAliveTimeout: 30,
GraphRecalculateSetting: config.GraphRecalculateSetting{
JitterTolerance: 20,
JitterToleranceMultiplier: 1.1,
NodeReportTimeout: 40,
RecalculateCoolDown: 5,
},
},
NTPconfig: config.NTPinfo{
UseNTP: true,
MaxServerUse: 5,
Servers: []string{"time.google.com",
"time1.google.com",
"time2.google.com",
"time3.google.com",
"time4.google.com",
"time1.facebook.com",
"time2.facebook.com",
"time3.facebook.com",
"time4.facebook.com",
"time5.facebook.com",
"time.cloudflare.com",
"time.apple.com",
"time.asia.apple.com",
"time.euro.apple.com",
"time.windows.com"},
},
},
NextHopTable: config.NextHopTable{},
Peers: []config.PeerInfo{
{
NodeID: 2,
PubKey: "NuYJ/3Ght+C4HovFq5Te/BrIazo6zwDJ8Bdu4rQCz0o=",
EndPoint: "127.0.0.1:3002",
Static: true,
},
},
}
g := path.NewGraph(3, false, tconfig.DynamicRoute.P2P.GraphRecalculateSetting)
type InterfaceConf struct { g.UpdateLentancy(1, 2, path.S2TD(0.5), false)
Itype string g.UpdateLentancy(2, 1, path.S2TD(0.5), false)
IfaceID int g.UpdateLentancy(2, 3, path.S2TD(0.5), false)
Name string g.UpdateLentancy(3, 2, path.S2TD(0.5), false)
MacAddr string g.UpdateLentancy(2, 4, path.S2TD(0.5), false)
MTU int g.UpdateLentancy(4, 2, path.S2TD(0.5), false)
RecvAddr string g.UpdateLentancy(3, 4, path.S2TD(0.5), false)
SendAddr string g.UpdateLentancy(4, 3, path.S2TD(0.5), false)
HumanFriendly bool g.UpdateLentancy(5, 3, path.S2TD(0.5), false)
} g.UpdateLentancy(3, 5, path.S2TD(0.5), false)
g.UpdateLentancy(6, 4, path.S2TD(0.5), false)
type SuperInfo struct { g.UpdateLentancy(4, 6, path.S2TD(0.5), false)
Enable bool
PubKeyV4 string
PubKeyV6 string
RegURLV4 string
RegURLV6 string
APIUrl string
}
type PeerInfo struct {
NodeID path.Vertex
PubKey string
EndPoint string
}
func printExampleConf() {
var config edgeConfig
config.Peers = make([]PeerInfo, 3)
var g path.IG
g.Init(4)
g.Edge(1, 2, 0.5)
g.Edge(2, 1, 0.5)
g.Edge(2, 3, 0.5)
g.Edge(3, 2, 0.5)
g.Edge(2, 4, 0.5)
g.Edge(4, 2, 0.5)
g.Edge(3, 4, 0.5)
g.Edge(4, 3, 0.5)
g.Edge(5, 3, 0.5)
g.Edge(3, 5, 0.5)
g.Edge(6, 4, 0.5)
g.Edge(4, 6, 0.5)
_, next := path.FloydWarshall(g) _, next := path.FloydWarshall(g)
config.NextHopTable = next tconfig.NextHopTable = next
test, _ := yaml.Marshal(config) toprint, _ := yaml.Marshal(tconfig)
fmt.Print(string(test)) fmt.Print(string(toprint))
return return
} }
func Edge(configPath string, useUAPI bool) (err error) { func Edge(configPath string, useUAPI bool, printExample bool) (err error) {
if printExample {
var config edgeConfig printExampleEdgeConf()
return nil
}
var tconfig config.EdgeConfig
//printExampleConf() //printExampleConf()
//return //return
err = readYaml(configPath, &config) err = readYaml(configPath, &tconfig)
if err != nil { if err != nil {
fmt.Printf("Error read config: %s :", configPath) fmt.Printf("Error read config: %s :", configPath)
fmt.Print(err) fmt.Print(err)
return err return err
} }
interfaceName := config.NodeName interfaceName := tconfig.NodeName
var logLevel int var logLevel int
switch config.LogLevel.LogLevel { switch tconfig.LogLevel.LogLevel {
case "verbose", "debug": case "verbose", "debug":
logLevel = device.LogLevelVerbose logLevel = device.LogLevelVerbose
case "error": case "error":
@ -110,14 +148,11 @@ func Edge(configPath string, useUAPI bool) (err error) {
case "silent": case "silent":
logLevel = device.LogLevelSilent logLevel = device.LogLevelSilent
} }
logger := device.NewLogger( logger := device.NewLogger(
logLevel, logLevel,
fmt.Sprintf("(%s) ", interfaceName), fmt.Sprintf("(%s) ", interfaceName),
) )
logger.Verbosef("Starting wireguard-go version %s", Version)
if err != nil { if err != nil {
logger.Errorf("UAPI listen error: %v", err) logger.Errorf("UAPI listen error: %v", err)
os.Exit(ExitSetupFailed) os.Exit(ExitSetupFailed)
@ -126,40 +161,44 @@ func Edge(configPath string, useUAPI bool) (err error) {
var thetap tap.Device var thetap tap.Device
// open TUN device (or use supplied fd) // open TUN device (or use supplied fd)
switch config.Interface.Itype { switch tconfig.Interface.Itype {
case "dummy": case "dummy":
thetap, err = tap.CreateDummyTAP() thetap, err = tap.CreateDummyTAP()
case "stdio": case "stdio":
thetap, err = tap.CreateStdIOTAP(config.Interface.Name, config.Interface.HumanFriendly) thetap, err = tap.CreateStdIOTAP(tconfig.Interface.Name, tconfig.Interface.HumanFriendly)
case "udpsock": case "udpsock":
{ {
lis, _ := net.ResolveUDPAddr("udp", config.Interface.RecvAddr) lis, _ := net.ResolveUDPAddr("udp", tconfig.Interface.RecvAddr)
sen, _ := net.ResolveUDPAddr("udp", config.Interface.SendAddr) sen, _ := net.ResolveUDPAddr("udp", tconfig.Interface.SendAddr)
thetap, err = tap.CreateUDPSockTAP(config.Interface.Name, lis, sen, config.Interface.HumanFriendly) thetap, err = tap.CreateUDPSockTAP(tconfig.Interface.Name, lis, sen, tconfig.Interface.HumanFriendly)
} }
} }
if err != nil { if err != nil {
logger.Errorf("Failed to create TUN device: %v", err) logger.Errorf("Failed to create TAP device: %v", err)
os.Exit(ExitSetupFailed) os.Exit(ExitSetupFailed)
} }
//////////////////////////////////////////////////// ////////////////////////////////////////////////////
// Config // Config
the_device := device.NewDevice(thetap, config.NodeID, conn.NewDefaultBind(), logger) graph := path.NewGraph(3, false, tconfig.DynamicRoute.P2P.GraphRecalculateSetting)
the_device.LogTransit = config.LogLevel.LogTransit graph.SetNHTable(tconfig.NextHopTable, [32]byte{})
the_device.NhTable = config.NextHopTable
the_device := device.NewDevice(thetap, tconfig.NodeID, conn.NewDefaultBind(), logger, &graph, false, configPath, &tconfig, nil)
the_device.LogTransit = tconfig.LogLevel.LogTransit
defer the_device.Close() defer the_device.Close()
var sk [32]byte var sk [32]byte
sk_slice, _ := base64.StdEncoding.DecodeString(config.PrivKey) sk_slice, _ := base64.StdEncoding.DecodeString(tconfig.PrivKey)
copy(sk[:], sk_slice) copy(sk[:], sk_slice)
the_device.SetPrivateKey(sk) the_device.SetPrivateKey(sk)
the_device.IpcSet("fwmark=0\n") the_device.IpcSet("fwmark=0\n")
the_device.IpcSet("listen_port=" + strconv.Itoa(config.ListenPort) + "\n") the_device.IpcSet("listen_port=" + strconv.Itoa(tconfig.ListenPort) + "\n")
the_device.IpcSet("replace_peers=true\n") the_device.IpcSet("replace_peers=true\n")
for _, peerconf := range config.Peers { for _, peerconf := range tconfig.Peers {
sk_slice, _ = base64.StdEncoding.DecodeString(peerconf.PubKey) sk_slice, _ = base64.StdEncoding.DecodeString(peerconf.PubKey)
copy(sk[:], sk_slice) copy(sk[:], sk_slice)
if peerconf.NodeID >= path.SuperNodeMessage {
return errors.New(fmt.Sprintf("Invalid Node_id at peer %s\n", peerconf.PubKey))
}
the_device.NewPeer(sk, peerconf.NodeID) the_device.NewPeer(sk, peerconf.NodeID)
if peerconf.EndPoint != "" { if peerconf.EndPoint != "" {
peer := the_device.LookupPeer(sk) peer := the_device.LookupPeer(sk)
@ -172,45 +211,42 @@ func Edge(configPath string, useUAPI bool) (err error) {
} }
} }
if tconfig.DynamicRoute.SuperNode.UseSuperNode {
if tconfig.DynamicRoute.SuperNode.ConnURLV4 != "" {
sk_slice, _ = base64.StdEncoding.DecodeString(tconfig.DynamicRoute.SuperNode.PubKeyV4)
copy(sk[:], sk_slice)
endpoint, err := the_device.Bind().ParseEndpoint(tconfig.DynamicRoute.SuperNode.ConnURLV4)
if err != nil {
return err
}
peer, err := the_device.NewPeer(sk, path.SuperNodeMessage)
if err != nil {
return err
}
peer.SetEndpointFromPacket(endpoint)
}
if tconfig.DynamicRoute.SuperNode.ConnURLV6 != "" {
sk_slice, _ = base64.StdEncoding.DecodeString(tconfig.DynamicRoute.SuperNode.PubKeyV6)
copy(sk[:], sk_slice)
endpoint, err := the_device.Bind().ParseEndpoint(tconfig.DynamicRoute.SuperNode.ConnURLV6)
if err != nil {
return err
}
peer, err := the_device.NewPeer(sk, path.SuperNodeMessage)
if err != nil {
return err
}
peer.SetEndpointFromPacket(endpoint)
}
}
logger.Verbosef("Device started") logger.Verbosef("Device started")
errs := make(chan error) errs := make(chan error)
term := make(chan os.Signal, 1) term := make(chan os.Signal, 1)
if useUAPI { if useUAPI {
startUAPI(interfaceName, logger, the_device, errs)
fileUAPI, err := func() (*os.File, error) {
uapiFdStr := os.Getenv(ENV_WP_UAPI_FD)
if uapiFdStr == "" {
return ipc.UAPIOpen(interfaceName)
}
// use supplied fd
fd, err := strconv.ParseUint(uapiFdStr, 10, 32)
if err != nil {
return nil, err
}
return os.NewFile(uintptr(fd), ""), nil
}()
uapi, err := ipc.UAPIListen(interfaceName, fileUAPI)
if err != nil {
logger.Errorf("Failed to listen on uapi socket: %v", err)
os.Exit(ExitSetupFailed)
}
go func() {
for {
conn, err := uapi.Accept()
if err != nil {
errs <- err
return
}
go the_device.IpcHandle(conn)
}
}()
defer uapi.Close()
logger.Verbosef("UAPI listener started")
} }
// wait for program to terminate // wait for program to terminate

72
main_httpserver.go Normal file
View File

@ -0,0 +1,72 @@
package main
import (
"net"
"strconv"
"net/http"
"github.com/KusakabeSi/EtherGuardVPN/config"
"github.com/KusakabeSi/EtherGuardVPN/device"
"github.com/KusakabeSi/EtherGuardVPN/path"
)
var (
http_graph *path.IG
http_device4 *device.Device
http_device6 *device.Device
http_NhTable_Hash string
http_PeerInfo_hash string
http_NhTableStr []byte
http_PeerInfoStr []byte
http_PeerState map[string]*PeerState
http_PeerID2Map map[config.Vertex]string
http_PeerInfos config.HTTP_Peers
)
type PeerState struct {
NhTableState string
PeerInfoState string
}
type client struct {
ConnV4 net.Addr
ConnV6 net.Addr
InterV4 []net.Addr
InterV6 []net.Addr
notify4 string
notify6 string
}
func get_peerinfo(w http.ResponseWriter, r *http.Request) {
params := r.URL.Query()
PubKey, _ := params["PubKey"]
State, _ := params["State"]
if state := http_PeerState[PubKey[0]]; state != nil {
http_PeerState[PubKey[0]].PeerInfoState = State[0]
}
w.WriteHeader(http.StatusOK)
w.Write([]byte(http_PeerInfoStr))
}
func get_nhtable(w http.ResponseWriter, r *http.Request) {
params := r.URL.Query()
PubKey, _ := params["PubKey"]
State, _ := params["State"]
if state := http_PeerState[PubKey[0]]; state != nil {
http_PeerState[PubKey[0]].NhTableState = State[0]
}
w.WriteHeader(http.StatusOK)
w.Write([]byte(http_NhTableStr))
}
func HttpServer(http_port int, apiprefix string, graph *path.IG, device4 *device.Device, device6 *device.Device) {
http_graph = graph
http_device4 = device4
http_device6 = device6
http_PeerState = make(map[string]*PeerState)
mux := http.NewServeMux()
mux.HandleFunc("/"+apiprefix+"/peerinfo", get_peerinfo)
mux.HandleFunc("/"+apiprefix+"/nhtable", get_nhtable)
go http.ListenAndServe(":"+strconv.Itoa(http_port), mux)
}

View File

@ -7,6 +7,278 @@
package main package main
func Super(configPath string, useUAPI bool) { import (
"crypto/md5"
"encoding/base64"
"encoding/hex"
"encoding/json"
"errors"
"fmt"
"net"
"os"
"os/signal"
"strconv"
"syscall"
"github.com/KusakabeSi/EtherGuardVPN/config"
"github.com/KusakabeSi/EtherGuardVPN/conn"
"github.com/KusakabeSi/EtherGuardVPN/device"
"github.com/KusakabeSi/EtherGuardVPN/ipc"
"github.com/KusakabeSi/EtherGuardVPN/path"
"github.com/KusakabeSi/EtherGuardVPN/tap"
yaml "gopkg.in/yaml.v2"
)
func printExampleSuperConf() {
sconfig := config.SuperConfig{
NodeName: "NodeSuper",
PrivKeyV4: "SM8pGjT0r8njy1/7ffN4wMwF7nnJ8UYSjGRWpCqo3ng=",
PrivKeyV6: "SM8pGjT0r8njy1/7ffN4wMwF7nnJ8UYSjGRWpCqo3ng=",
ListenPort: 3000,
LogLevel: config.LoggerInfo{
LogLevel: "normal",
LogTransit: true,
},
Peers: []config.PeerInfo{
{
NodeID: 2,
PubKey: "NuYJ/3Ght+C4HovFq5Te/BrIazo6zwDJ8Bdu4rQCz0o=",
EndPoint: "127.0.0.1:3002",
Static: true,
},
},
GraphRecalculateSetting: config.GraphRecalculateSetting{
JitterTolerance: 20,
JitterToleranceMultiplier: 1.1,
NodeReportTimeout: 40,
RecalculateCoolDown: 5,
},
}
soprint, _ := yaml.Marshal(sconfig)
fmt.Print(string(soprint))
return
}
func Super(configPath string, useUAPI bool, printExample bool) (err error) {
if printExample {
printExampleSuperConf()
return nil
}
var sconfig config.SuperConfig
err = readYaml(configPath, &sconfig)
if err != nil {
fmt.Printf("Error read config: %s :", configPath)
fmt.Print(err)
return err
}
interfaceName := sconfig.NodeName
var logLevel int
switch sconfig.LogLevel.LogLevel {
case "verbose", "debug":
logLevel = device.LogLevelVerbose
case "error":
logLevel = device.LogLevelError
case "silent":
logLevel = device.LogLevelSilent
}
logger4 := device.NewLogger(
logLevel,
fmt.Sprintf("(%s) ", interfaceName+"_v4"),
)
logger6 := device.NewLogger(
logLevel,
fmt.Sprintf("(%s) ", interfaceName+"_v6"),
)
super_chains := path.SUPER_Events{
Event_server_pong: make(chan path.PongMsg, 1<<5),
Event_server_register: make(chan path.RegisterMsg, 1<<5),
Event_server_NhTable_changed: make(chan struct{}, 1<<4),
}
thetap, _ := tap.CreateDummyTAP()
graph := path.NewGraph(3, true, sconfig.GraphRecalculateSetting)
device_v4 := device.NewDevice(thetap, path.SuperNodeMessage, conn.NewCustomBind(true, false), logger4, &graph, true, "", nil, &super_chains)
device_v6 := device.NewDevice(thetap, path.SuperNodeMessage, conn.NewCustomBind(false, true), logger6, &graph, true, "", nil, &super_chains)
defer device_v4.Close()
defer device_v6.Close()
var sk [32]byte
sk_slice, _ := base64.StdEncoding.DecodeString(sconfig.PrivKeyV4)
copy(sk[:], sk_slice)
device_v4.SetPrivateKey(sk)
sk_slice, _ = base64.StdEncoding.DecodeString(sconfig.PrivKeyV6)
copy(sk[:], sk_slice)
device_v6.SetPrivateKey(sk)
device_v4.IpcSet("listen_port=" + strconv.Itoa(sconfig.ListenPort) + "\n")
device_v6.IpcSet("listen_port=" + strconv.Itoa(sconfig.ListenPort) + "\n")
device_v4.IpcSet("replace_peers=true\n")
device_v6.IpcSet("listen_port=" + strconv.Itoa(sconfig.ListenPort) + "\n")
for _, peerconf := range sconfig.Peers {
sk_slice, _ = base64.StdEncoding.DecodeString(peerconf.PubKey)
copy(sk[:], sk_slice)
if peerconf.NodeID >= path.SuperNodeMessage {
return errors.New(fmt.Sprintf("Invalid Node_id at peer %s\n", peerconf.PubKey))
}
device_v4.NewPeer(sk, peerconf.NodeID)
device_v6.NewPeer(sk, peerconf.NodeID)
http_PeerState[peerconf.PubKey] = &PeerState{}
}
logger4.Verbosef("Device started")
errs := make(chan error, 1<<3)
term := make(chan os.Signal, 1)
if useUAPI {
uapi4, err := startUAPI(interfaceName+"_v4", logger4, device_v4, errs)
if err != nil {
return err
}
defer uapi4.Close()
uapi6, err := startUAPI(interfaceName+"_v6", logger6, device_v6, errs)
if err != nil {
return err
}
defer uapi6.Close()
}
signal.Notify(term, syscall.SIGTERM)
signal.Notify(term, os.Interrupt)
select {
case <-term:
case <-errs:
case <-device_v4.Wait():
case <-device_v6.Wait():
}
logger4.Verbosef("Shutting down")
return
}
func Event_server_pong_hendler(graph path.IG, events path.SUPER_Events) {
for {
pongmsg := <-events.Event_server_pong
changed := graph.UpdateLentancy(pongmsg.Src_nodeID, pongmsg.Dst_nodeID, pongmsg.Timediff, true)
if changed {
NhTable := graph.GetNHTable(false)
NhTablestr, _ := json.Marshal(NhTable)
md5_hash_raw := md5.Sum(http_NhTableStr)
new_hash := hex.EncodeToString(md5_hash_raw[:])
if http_NhTable_Hash != new_hash {
http_NhTable_Hash = new_hash
http_NhTableStr = NhTablestr
NhTable_Hash_fixbyte := [32]byte{}
copy(NhTable_Hash_fixbyte[:], []byte(http_NhTable_Hash))
body, err := path.GetByte(path.UpdateNhTableMsg{
State_hash: NhTable_Hash_fixbyte,
})
if err != nil {
fmt.Println("Error get byte")
continue
}
buf := make([]byte, path.EgHeaderLen+len(body))
header, _ := path.NewEgHeader(buf[:path.EgHeaderLen])
header.SetDst(path.SuperNodeMessage)
header.SetPacketLength(uint16(len(body)))
header.SetSrc(path.SuperNodeMessage)
header.SetTTL(0)
header.SetUsage(path.UpdateNhTable)
copy(buf[path.EgHeaderLen:], body)
for pkstr, peerstate := range http_PeerState {
if peerstate.NhTableState != http_NhTable_Hash {
if peer := http_device4.LookupPeerByStr(pkstr); peer != nil {
http_device4.SendPacket(peer, buf, device.MessageTransportOffsetContent)
}
if peer := http_device6.LookupPeerByStr(pkstr); peer != nil {
http_device6.SendPacket(peer, buf, device.MessageTransportOffsetContent)
}
}
}
}
}
}
}
func Event_server_register_hendler(raph path.IG, events path.SUPER_Events) {
for {
reg_msg := <-events.Event_server_register
PubKey := http_PeerID2Map[reg_msg.Node_id]
if peer := http_device4.LookupPeerByStr(PubKey); peer != nil {
if connstr := peer.GetEndpointDstStr(); connstr != "" {
http_PeerInfos.Peers[PubKey].Connurl[connstr] = true
}
}
if peer := http_device6.LookupPeerByStr(PubKey); peer != nil {
if connstr := peer.GetEndpointDstStr(); connstr != "" {
http_PeerInfos.Peers[PubKey].Connurl[connstr] = true
}
}
http_PeerInfoStr, _ = json.Marshal(&http_PeerInfos)
PeerInfo_hash_raw := md5.Sum(http_PeerInfoStr)
PeerInfo_hash := hex.EncodeToString(PeerInfo_hash_raw[:])
http_PeerInfo_hash_fixbyte := [32]byte{}
copy(http_PeerInfo_hash_fixbyte[:], []byte(PeerInfo_hash))
if http_PeerInfo_hash != PeerInfo_hash {
http_PeerInfo_hash = PeerInfo_hash
body, err := path.GetByte(path.UpdatePeerMsg{
State_hash: http_PeerInfo_hash_fixbyte,
})
if err != nil {
fmt.Println("Error get byte")
continue
}
buf := make([]byte, path.EgHeaderLen+len(body))
header, _ := path.NewEgHeader(buf[:path.EgHeaderLen])
header.SetDst(path.SuperNodeMessage)
header.SetPacketLength(uint16(len(body)))
header.SetSrc(path.SuperNodeMessage)
header.SetTTL(0)
header.SetUsage(path.UpdatePeer)
copy(buf[path.EgHeaderLen:], body)
for pkstr, peerstate := range http_PeerState {
if peerstate.PeerInfoState != PeerInfo_hash {
if peer := http_device4.LookupPeerByStr(pkstr); peer != nil {
http_device4.SendPacket(peer, buf, device.MessageTransportOffsetContent)
}
if peer := http_device6.LookupPeerByStr(pkstr); peer != nil {
http_device6.SendPacket(peer, buf, device.MessageTransportOffsetContent)
}
}
}
}
}
}
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)
if uapiFdStr == "" {
return ipc.UAPIOpen(interfaceName)
}
// use supplied fd
fd, err := strconv.ParseUint(uapiFdStr, 10, 32)
if err != nil {
return nil, err
}
return os.NewFile(uintptr(fd), ""), nil
}()
uapi, err := ipc.UAPIListen(interfaceName, fileUAPI)
if err != nil {
logger.Errorf("Failed to listen on uapi socket: %v", err)
os.Exit(ExitSetupFailed)
}
go func() {
for {
conn, err := uapi.Accept()
if err != nil {
errs <- err
return
}
go the_device.IpcHandle(conn)
}
}()
logger.Verbosef("UAPI listener started")
return uapi, err
} }

View File

@ -3,9 +3,11 @@ package path
import ( import (
"encoding/binary" "encoding/binary"
"errors" "errors"
"github.com/KusakabeSi/EtherGuardVPN/config"
) )
const EgHeaderLen = 10 const EgHeaderLen = 12
type EgHeader struct { type EgHeader struct {
buf []byte buf []byte
@ -15,8 +17,15 @@ type Usage uint8
const ( const (
NornalPacket Usage = iota NornalPacket Usage = iota
PingSingleWay Register //Register to server
PingDualWay
UpdatePeer //Comes from server
UpdateNhTable
PingPacket //Comes from other peer
PongPacket //Send to everyone, include server
RequestPeer
BoardcastPeer
) )
func NewEgHeader(pac []byte) (e EgHeader, err error) { func NewEgHeader(pac []byte) (e EgHeader, err error) {
@ -28,17 +37,17 @@ func NewEgHeader(pac []byte) (e EgHeader, err error) {
return return
} }
func (e EgHeader) GetDst() Vertex { func (e EgHeader) GetDst() config.Vertex {
return Vertex(binary.BigEndian.Uint32(e.buf[0:4])) return config.Vertex(binary.BigEndian.Uint32(e.buf[0:4]))
} }
func (e EgHeader) SetDst(node_ID Vertex) { func (e EgHeader) SetDst(node_ID config.Vertex) {
binary.BigEndian.PutUint32(e.buf[0:4], uint32(node_ID)) binary.BigEndian.PutUint32(e.buf[0:4], uint32(node_ID))
} }
func (e EgHeader) GetSrc() Vertex { func (e EgHeader) GetSrc() config.Vertex {
return Vertex(binary.BigEndian.Uint32(e.buf[4:8])) return config.Vertex(binary.BigEndian.Uint32(e.buf[4:8]))
} }
func (e EgHeader) SetSrc(node_ID Vertex) { func (e EgHeader) SetSrc(node_ID config.Vertex) {
binary.BigEndian.PutUint32(e.buf[4:8], uint32(node_ID)) binary.BigEndian.PutUint32(e.buf[4:8], uint32(node_ID))
} }
@ -50,18 +59,16 @@ func (e EgHeader) SetTTL(ttl uint8) {
e.buf[8] = ttl e.buf[8] = ttl
} }
func (e EgHeader) GetUsage() uint8 { func (e EgHeader) GetUsage() Usage {
return e.buf[9] return Usage(e.buf[9])
} }
func (e EgHeader) SetUsage(usage uint8) { func (e EgHeader) SetUsage(usage Usage) {
e.buf[9] = usage e.buf[9] = uint8(usage)
} }
/*
func (e EgHeader) GetPacketLength() uint16 { func (e EgHeader) GetPacketLength() uint16 {
return binary.BigEndian.Uint16(e.buf[10:12]) return binary.BigEndian.Uint16(e.buf[10:12])
} }
func (e EgHeader) SetPacketLength(length uint16) { func (e EgHeader) SetPacketLength(length uint16) {
binary.BigEndian.PutUint16(e.buf[10:12], length) binary.BigEndian.PutUint16(e.buf[10:12], length)
} }
*/

116
path/metamessage.go Normal file
View File

@ -0,0 +1,116 @@
package path
import (
"bytes"
"encoding/gob"
"time"
"github.com/KusakabeSi/EtherGuardVPN/config"
)
func GetByte(structIn interface{}) (bb []byte, err error) {
var b bytes.Buffer
e := gob.NewEncoder(&b)
if err := e.Encode(structIn); err != nil {
panic(err)
}
bb = b.Bytes()
return
}
type RegisterMsg struct {
Node_id config.Vertex
}
func ParseRegisterMsg(bin []byte) (RegisterMsg, error) {
var StructPlace RegisterMsg
var b bytes.Buffer
d := gob.NewDecoder(&b)
err := d.Decode(&StructPlace)
return StructPlace, err
}
type UpdatePeerMsg struct {
State_hash [32]byte
}
func ParseUpdatePeerMsg(bin []byte) (UpdatePeerMsg, error) {
var StructPlace UpdatePeerMsg
var b bytes.Buffer
d := gob.NewDecoder(&b)
err := d.Decode(&StructPlace)
return StructPlace, err
}
type UpdateNhTableMsg struct {
State_hash [32]byte
}
func ParseUpdateNhTableMsg(bin []byte) (UpdateNhTableMsg, error) {
var StructPlace UpdateNhTableMsg
var b bytes.Buffer
d := gob.NewDecoder(&b)
err := d.Decode(&StructPlace)
return StructPlace, err
}
type PingMsg struct {
Src_nodeID config.Vertex
Time time.Time
}
func ParsePingMsg(bin []byte) (PingMsg, error) {
var StructPlace PingMsg
var b bytes.Buffer
d := gob.NewDecoder(&b)
err := d.Decode(&StructPlace)
return StructPlace, err
}
type PongMsg struct {
Src_nodeID config.Vertex
Dst_nodeID config.Vertex
Timediff time.Duration
}
func ParsePongMsg(bin []byte) (PongMsg, error) {
var StructPlace PongMsg
var b bytes.Buffer
d := gob.NewDecoder(&b)
err := d.Decode(&StructPlace)
return StructPlace, err
}
type RequestPeerMsg struct {
Request_ID uint32
}
func ParseRequestPeerMsg(bin []byte) (RequestPeerMsg, error) {
var StructPlace RequestPeerMsg
var b bytes.Buffer
d := gob.NewDecoder(&b)
err := d.Decode(&StructPlace)
return StructPlace, err
}
type BoardcastPeerMsg struct {
RequestID uint32
NodeID config.Vertex
PubKey [32]byte
PSKey [32]byte
ConnURL string
}
func ParseBoardcastPeerMsg(bin []byte) (BoardcastPeerMsg, error) {
var StructPlace BoardcastPeerMsg
var b bytes.Buffer
d := gob.NewDecoder(&b)
err := d.Decode(&StructPlace)
return StructPlace, err
}
type SUPER_Events struct {
Event_server_pong chan PongMsg
Event_server_register chan RegisterMsg
Event_server_NhTable_changed chan struct{}
}

View File

@ -5,85 +5,179 @@ import (
"math" "math"
"time" "time"
"github.com/KusakabeSi/EtherGuardVPN/config"
yaml "gopkg.in/yaml.v2" yaml "gopkg.in/yaml.v2"
) )
var ( const Infinity = float64(99999)
timeout = time.Second * 3
const (
Boardcast config.Vertex = math.MaxUint32 - iota // Normal boardcast, boardcast with route table
ControlMessage config.Vertex = math.MaxUint32 - iota // p2p mode: boardcast to every know keer and prevent dup/ super mode: send to supernode
PingMessage config.Vertex = math.MaxUint32 - iota // boardsact to every know peer but don't transit
SuperNodeMessage config.Vertex = math.MaxUint32 - iota
Special_NodeID config.Vertex = SuperNodeMessage
) )
func (g *IG) GetCurrentTime() time.Time {
return time.Now()
}
// A Graph is the interface implemented by graphs that // A Graph is the interface implemented by graphs that
// this algorithm can run on. // this algorithm can run on.
type Graph interface { type Graph interface {
Vertices() map[Vertex]bool Vertices() map[config.Vertex]bool
Neighbors(v Vertex) []Vertex Neighbors(v config.Vertex) []config.Vertex
Weight(u, v Vertex) float64 Weight(u, v config.Vertex) float64
} }
// Nonnegative integer ID of vertex
type Vertex uint32
const Infinity = 99999
var Boardcast = Vertex(math.MaxUint32)
type Latency struct { type Latency struct {
ping float64 ping float64
time time.Time time time.Time
} }
type DistTable map[Vertex]map[Vertex]float64
type NextHopTable map[Vertex]map[Vertex]*Vertex
type Fullroute struct { type Fullroute struct {
Dist DistTable `json:"total distance"` Dist config.DistTable `json:"total distance"`
Next NextHopTable `json:"next hop"` Next config.NextHopTable `json:"next hop"`
} }
// IG is a graph of integers that satisfies the Graph interface. // IG is a graph of integers that satisfies the Graph interface.
type IG struct { type IG struct {
Vert map[Vertex]bool Vert map[config.Vertex]bool
Edges map[Vertex]map[Vertex]Latency Edges map[config.Vertex]map[config.Vertex]Latency
JitterTolerance float64
JitterToleranceMultiplier float64
NodeReportTimeout time.Duration
SuperNodeInfoTimeout time.Duration
RecalculateCoolDown time.Duration
RecalculateTime time.Time
dlTable config.DistTable
NhTable config.NextHopTable
NhTableHash [32]byte
nhTableExpire time.Time
IsSuperMode bool
} }
func (g *IG) Init(num_node int) error { func S2TD(secs float64) time.Duration {
g.Vert = make(map[Vertex]bool, num_node) return time.Duration(secs * float64(time.Second))
g.Edges = make(map[Vertex]map[Vertex]Latency, num_node)
return nil
} }
func (g *IG) Edge(u, v Vertex, w float64) { func NewGraph(num_node int, IsSuperMode bool, theconfig config.GraphRecalculateSetting) IG {
g := IG{
JitterTolerance: theconfig.JitterTolerance,
JitterToleranceMultiplier: theconfig.JitterToleranceMultiplier,
NodeReportTimeout: S2TD(theconfig.NodeReportTimeout),
RecalculateCoolDown: S2TD(theconfig.RecalculateCoolDown),
}
g.Vert = make(map[config.Vertex]bool, num_node)
g.Edges = make(map[config.Vertex]map[config.Vertex]Latency, num_node)
g.IsSuperMode = IsSuperMode
return g
}
func (g *IG) GetWeightType(x float64) 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
}
return y
}
func (g *IG) ShouldUpdate(u config.Vertex, v config.Vertex, newval float64) bool {
oldval := g.Weight(u, v) * 1000
newval *= 1000
if g.IsSuperMode {
return (oldval-newval)*(oldval*g.JitterToleranceMultiplier) <= g.JitterTolerance
} else {
return g.GetWeightType(oldval) == g.GetWeightType(newval)
}
}
func (g *IG) RecalculateNhTable(checkchange bool) (changed bool) {
if g.RecalculateTime.Add(g.RecalculateCoolDown).Before(time.Now()) {
dist, next := FloydWarshall(g)
if checkchange {
CheckLoop:
for src, dsts := range next {
for dst, cost := range dsts {
nexthop := g.Next(src, dst)
if nexthop != nil {
changed = cost == nexthop
if changed {
break CheckLoop
}
}
}
}
}
g.dlTable, g.NhTable = dist, next
g.nhTableExpire = time.Now().Add(g.NodeReportTimeout)
g.RecalculateTime = time.Now()
}
return
}
func (g *IG) UpdateLentancy(u, v config.Vertex, dt time.Duration, checkchange bool) (changed bool) {
g.Vert[u] = true g.Vert[u] = true
g.Vert[v] = true g.Vert[v] = true
w := float64(dt) / float64(time.Second)
if _, ok := g.Edges[u]; !ok { if _, ok := g.Edges[u]; !ok {
g.Edges[u] = make(map[Vertex]Latency) g.Edges[u] = make(map[config.Vertex]Latency)
}
if g.ShouldUpdate(u, v, w) {
changed = g.RecalculateNhTable(checkchange)
} }
g.Edges[u][v] = Latency{ g.Edges[u][v] = Latency{
ping: w, ping: w,
time: time.Now(), time: time.Now(),
} }
return
} }
func (g IG) Vertices() map[Vertex]bool { return g.Vert } func (g IG) Vertices() map[config.Vertex]bool {
func (g IG) Neighbors(v Vertex) (vs []Vertex) { return g.Vert
}
func (g IG) Neighbors(v config.Vertex) (vs []config.Vertex) {
for k := range g.Edges[v] { for k := range g.Edges[v] {
vs = append(vs, k) vs = append(vs, k)
} }
return vs return vs
} }
func (g IG) Weight(u, v Vertex) float64 {
if time.Now().Sub(g.Edges[u][v].time) < timeout { func (g IG) Next(u, v config.Vertex) *config.Vertex {
return g.Edges[u][v].ping if _, ok := g.NhTable[u]; !ok {
return nil
} }
return Infinity if _, ok := g.NhTable[u][v]; !ok {
return nil
}
return g.NhTable[u][v]
} }
func FloydWarshall(g Graph) (dist DistTable, next NextHopTable) { func (g IG) Weight(u, v config.Vertex) float64 {
if _, ok := g.Edges[u]; !ok {
g.Edges[u] = make(map[config.Vertex]Latency)
return Infinity
}
if _, ok := g.Edges[u][v]; !ok {
return Infinity
}
if time.Now().After(g.Edges[u][v].time.Add(g.NodeReportTimeout)) {
return Infinity
}
return g.Edges[u][v].ping
}
func FloydWarshall(g Graph) (dist config.DistTable, next config.NextHopTable) {
vert := g.Vertices() vert := g.Vertices()
dist = make(DistTable) dist = make(config.DistTable)
next = make(NextHopTable) next = make(config.NextHopTable)
for u, _ := range vert { for u, _ := range vert {
dist[u] = make(map[Vertex]float64) dist[u] = make(map[config.Vertex]float64)
next[u] = make(map[Vertex]*Vertex) next[u] = make(map[config.Vertex]*config.Vertex)
for v, _ := range vert { for v, _ := range vert {
dist[u][v] = Infinity dist[u][v] = Infinity
} }
@ -112,11 +206,11 @@ func FloydWarshall(g Graph) (dist DistTable, next NextHopTable) {
return dist, next return dist, next
} }
func Path(u, v Vertex, next NextHopTable) (path []Vertex) { func Path(u, v config.Vertex, next config.NextHopTable) (path []config.Vertex) {
if next[u][v] == nil { if next[u][v] == nil {
return []Vertex{} return []config.Vertex{}
} }
path = []Vertex{u} path = []config.Vertex{u}
for u != v { for u != v {
u = *next[u][v] u = *next[u][v]
path = append(path, u) path = append(path, u)
@ -124,19 +218,32 @@ func Path(u, v Vertex, next NextHopTable) (path []Vertex) {
return path return path
} }
func GetBoardcastList(id Vertex, nh NextHopTable) (tosend map[Vertex]bool) { func (g *IG) SetNHTable(nh config.NextHopTable, table_hash [32]byte) { // set nhTable from supernode
tosend = make(map[Vertex]bool) g.NhTable = nh
for _, element := range nh[id] { g.NhTableHash = table_hash
g.nhTableExpire = time.Now().Add(g.SuperNodeInfoTimeout)
}
func (g *IG) GetNHTable(checkChange bool) config.NextHopTable {
if time.Now().After(g.nhTableExpire) {
g.RecalculateNhTable(checkChange)
}
return g.NhTable
}
func (g *IG) GetBoardcastList(id config.Vertex) (tosend map[config.Vertex]bool) {
tosend = make(map[config.Vertex]bool)
for _, element := range g.NhTable[id] {
tosend[*element] = true tosend[*element] = true
} }
return return
} }
func GetBoardcastThroughList(id Vertex, src Vertex, nh NextHopTable) (tosend map[Vertex]bool) { func (g *IG) GetBoardcastThroughList(self_id config.Vertex, in_id config.Vertex, src_id config.Vertex) (tosend map[config.Vertex]bool) {
tosend = make(map[Vertex]bool) tosend = make(map[config.Vertex]bool)
for check_id, _ := range GetBoardcastList(id, nh) { for check_id, _ := range g.GetBoardcastList(self_id) {
for _, path_node := range Path(src, check_id, nh) { for _, path_node := range Path(src_id, check_id, g.NhTable) {
if path_node == id { if path_node == self_id && check_id != in_id {
tosend[check_id] = true tosend[check_id] = true
continue continue
} }
@ -147,13 +254,13 @@ func GetBoardcastThroughList(id Vertex, src Vertex, nh NextHopTable) (tosend map
func Solve() { func Solve() {
var g IG var g IG
g.Init(4) //g.Init()
g.Edge(1, 2, 0.5) g.UpdateLentancy(1, 2, S2TD(0.5), false)
g.Edge(2, 1, 0.5) g.UpdateLentancy(2, 1, S2TD(0.5), false)
g.Edge(2, 3, 2) g.UpdateLentancy(2, 3, S2TD(2), false)
g.Edge(3, 2, 2) g.UpdateLentancy(3, 2, S2TD(2), false)
g.Edge(2, 4, 0.7) g.UpdateLentancy(2, 4, S2TD(0.7), false)
g.Edge(4, 2, 2) g.UpdateLentancy(4, 2, S2TD(2), false)
dist, next := FloydWarshall(g) dist, next := FloydWarshall(g)
fmt.Println("pair\tdist\tpath") fmt.Println("pair\tdist\tpath")
for u, m := range dist { for u, m := range dist {

190
server.go
View File

@ -1,190 +0,0 @@
package main
import (
"encoding/json"
"fmt"
"net"
"strconv"
"net/http"
"github.com/KusakabeSi/EtherGuardVPN/path"
)
type client struct {
ConnV4 net.Addr
ConnV6 net.Addr
InterV4 []net.Addr
InterV6 []net.Addr
notify4 string
notify6 string
}
type action struct {
Action string `json:"a"`
Node_ID int `json:"id"`
Name string `json:"n"`
}
type serverConf struct {
UDP_port int `json:"port"`
CONN_url string `json:"url"`
USE_Oneway bool `json:"use_oneway"`
}
type pathLentancy struct {
NodeID_S int `json:"src"`
NodeID_E int `json:"dst"`
Latency float64 `json:"ping"`
Is_Oneway bool `json:"oneway"`
}
var (
clients = []client{}
graph = path.IG{}
node_num = 10
udp_port = 9595
http_port = 9595
)
func (c *client) hasV4() bool {
return c.ConnV4.String() == ""
}
func (c *client) hasV6() bool {
return c.ConnV6.String() == ""
}
func (c *client) online() bool {
return c.hasV4() || c.hasV6()
}
func serv(conn net.Conn, version int) {
buffer := make([]byte, 1024)
_, err := conn.Read(buffer)
if err != nil {
fmt.Println(err)
}
incoming := string(buffer)
fmt.Println("[INCOMING]", conn.RemoteAddr(), incoming)
theaction := action{}
err = json.Unmarshal(buffer, &theaction)
if err != nil {
fmt.Println("[Error]", err)
return
}
if theaction.Action != "register" {
fmt.Println("[Error]", "Unknow action", theaction.Action)
return
}
if version == 4 {
clients[theaction.Node_ID].ConnV4 = conn.RemoteAddr()
} else if version == 6 {
clients[theaction.Node_ID].ConnV6 = conn.RemoteAddr()
}
conn.Write([]byte("OK"))
err = conn.Close()
if err != nil {
fmt.Println("[Error]", err)
fmt.Println(err)
}
}
func accept(listener net.Listener, version int) {
for {
conn, err := listener.Accept()
if err != nil {
fmt.Println(err)
continue
}
serv(conn, version)
}
}
// Server --
func RegisterServer() {
/*
graph.Init(node_num)
clients = make([]client, node_num)
addr4 := &net.UDPAddr{
IP: net.IPv4zero,
Port: udp_port,
}
addr6 := &net.UDPAddr{
IP: net.IPv6zero,
Port: udp_port,
}
// Connect to a DTLS server
listener4, err4 := dtls.Listen("udp4", addr4)
if err4 != nil {
fmt.Println(err)
}
defer listener4.Close()
listener6, err6 := dtls.Listen("udp6", addr6)
if err6 != nil {
fmt.Println(err)
}
defer listener6.Close()
if err4 != nil && err6 != nil {
fmt.Println("udp4 and udp6 both failed!")
return
}
go accept(listener4, 4)
go accept(listener6, 6)*/
}
func get_config(w http.ResponseWriter, r *http.Request) {
rr, _ := json.Marshal(serverConf{
UDP_port: udp_port,
CONN_url: "https://example.com",
})
w.WriteHeader(http.StatusOK)
w.Write(rr)
}
func get_neighbor(w http.ResponseWriter, r *http.Request) {
rr, _ := json.Marshal(clients)
w.WriteHeader(http.StatusOK)
w.Write(rr)
}
func get_route(w http.ResponseWriter, r *http.Request) {
dist, next := path.FloydWarshall(graph)
rr, _ := json.Marshal(path.Fullroute{
Dist: dist,
Next: next,
})
w.WriteHeader(http.StatusOK)
w.Write(rr)
}
func post_latency(w http.ResponseWriter, r *http.Request) {
body := make([]byte, r.ContentLength)
info := pathLentancy{}
err := json.Unmarshal(body, &info)
if err != nil {
w.WriteHeader(http.StatusBadRequest)
w.Write([]byte(fmt.Sprint(err)))
return
}
if info.Is_Oneway {
graph.Edge(path.Vertex(info.NodeID_S), path.Vertex(info.NodeID_E), info.Latency)
} else {
graph.Edge(path.Vertex(info.NodeID_S), path.Vertex(info.NodeID_E), info.Latency/2)
graph.Edge(path.Vertex(info.NodeID_E), path.Vertex(info.NodeID_S), info.Latency/2)
}
w.WriteHeader(http.StatusOK)
w.Write([]byte("OK"))
}
func HttpServer() {
mux := http.NewServeMux()
mux.HandleFunc("/api/neighbor/", get_neighbor)
mux.HandleFunc("/api/route/", get_route)
mux.HandleFunc("/api/latency/", post_latency)
go http.ListenAndServe(":"+strconv.Itoa(http_port), mux)
}