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

3
.gitignore vendored
View File

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

2
.vscode/launch.json vendored
View File

@ -10,7 +10,7 @@
"request": "launch",
"mode": "auto",
"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
import (
"encoding/base64"
"runtime"
"sync"
"sync/atomic"
"time"
"github.com/KusakabeSi/EtherGuardVPN/config"
"github.com/KusakabeSi/EtherGuardVPN/conn"
"github.com/KusakabeSi/EtherGuardVPN/path"
"github.com/KusakabeSi/EtherGuardVPN/ratelimiter"
"github.com/KusakabeSi/EtherGuardVPN/rwcancel"
"github.com/KusakabeSi/EtherGuardVPN/tap"
fixed_time_cache "github.com/KusakabeSi/go-cache"
)
type Device struct {
@ -61,16 +64,30 @@ type Device struct {
peers struct {
sync.RWMutex // protects keyMap
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
cookieChecker CookieChecker
ID path.Vertex
NhTable path.NextHopTable
l2fib map[tap.MacAddress]path.Vertex
LogTransit bool
IsSuperNode bool
ID config.Vertex
graph *path.IG
l2fib map[tap.MacAddress]config.Vertex
LogTransit bool
DRoute config.DynamicRouteInfo
DupData fixed_time_cache.Cache
pool struct {
messageBuffers *WaitPool
@ -135,7 +152,13 @@ func removePeerLocked(device *Device, peer *Peer, key NoisePublicKey) {
peer.Stop()
// remove from peer map
id := peer.ID
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.
@ -279,7 +302,7 @@ func (device *Device) SetPrivateKey(sk NoisePrivateKey) error {
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.state.state = uint32(deviceStateDown)
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.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.l2fib = make(map[tap.MacAddress]path.Vertex)
device.graph = graph
device.l2fib = make(map[tap.MacAddress]config.Vertex)
device.rate.limiter.Init()
device.indexTable.Init()
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
device.queue.handshake = newHandshakeQueue()
@ -332,6 +374,49 @@ func (device *Device) LookupPeer(pk NoisePublicKey) *Peer {
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) {
device.peers.Lock()
defer device.peers.Unlock()
@ -352,7 +437,7 @@ func (device *Device) RemoveAllPeers() {
}
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() {

View File

@ -13,20 +13,23 @@ import (
"sync/atomic"
"time"
"github.com/KusakabeSi/EtherGuardVPN/config"
"github.com/KusakabeSi/EtherGuardVPN/conn"
"github.com/KusakabeSi/EtherGuardVPN/path"
)
type Peer struct {
isRunning AtomicBool
sync.RWMutex // Mostly protects endpoint, but is generally taken whenever we modify peer
keypairs Keypairs
handshake Handshake
device *Device
endpoint conn.Endpoint
stopping sync.WaitGroup // routines pending stop
isRunning AtomicBool
sync.RWMutex // Mostly protects endpoint, but is generally taken whenever we modify peer
keypairs Keypairs
handshake Handshake
device *Device
endpoint conn.Endpoint
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
// 64-bit aligned even on 32-bit platforms. Go guarantees that an
@ -67,7 +70,7 @@ type Peer struct {
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() {
return nil, errors.New("device closed")
}
@ -117,8 +120,13 @@ func (device *Device) NewPeer(pk NoisePublicKey, id path.Vertex) (*Peer, error)
peer.endpoint = nil
// add
device.peers.keyMap[pk] = peer
device.peers.IDMap[id] = peer
if id == path.SuperNodeMessage { // To communicate with supernode
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
peer.timersInit()
@ -288,3 +296,11 @@ func (peer *Peer) SetEndpointFromPacket(endpoint conn.Endpoint) {
peer.endpoint = endpoint
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"
"github.com/KusakabeSi/EtherGuardVPN/config"
"github.com/KusakabeSi/EtherGuardVPN/conn"
"github.com/KusakabeSi/EtherGuardVPN/path"
"github.com/KusakabeSi/EtherGuardVPN/tap"
@ -411,8 +412,10 @@ func (peer *Peer) RoutineSequentialReceiver() {
}
var EgBody path.EgHeader
var err error
var src_nodeID path.Vertex
var dst_nodeID path.Vertex
var src_nodeID config.Vertex
var dst_nodeID config.Vertex
var packet_type path.Usage
should_process := false
should_receive := false
should_transfer := false
elem.Lock()
@ -445,57 +448,99 @@ func (peer *Peer) RoutineSequentialReceiver() {
EgBody, err = path.NewEgHeader(elem.packet[0:path.EgHeaderLen])
src_nodeID = EgBody.GetSrc()
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 {
should_receive = true
} else if dst_nodeID == path.Boardcast {
should_receive = true
should_transfer = true
} else if device.NhTable[device.ID][dst_nodeID] != nil {
should_transfer = true
if device.IsSuperNode {
peer.LastPingReceived = time.Now()
switch dst_nodeID {
case path.ControlMessage:
should_process = true
case path.SuperNodeMessage:
should_process = true
default:
device.log.Errorf("Invalid dst_nodeID received. Check your code for bug")
}
} else {
device.log.Verbosef("No route to peer ID %v", dst_nodeID)
goto skip
switch dst_nodeID {
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 { //Send to another peer
if should_transfer {
l2ttl := EgBody.GetTTL()
if l2ttl == 0 {
device.log.Verbosef("TTL is 0 %v", dst_nodeID)
} else {
EgBody.SetTTL(l2ttl - 1)
if dst_nodeID != path.Boardcast {
next_id := *device.NhTable[device.ID][dst_nodeID]
if dst_nodeID == path.Boardcast { //Regular transfer algorithm
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]
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)
} 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 {
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 should_process {
if packet_type != path.NornalPacket {
device.process_received(packet_type, elem.packet[path.EgHeaderLen:])
}
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)
}
if should_receive { // Write message to tap device
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"
"time"
"github.com/KusakabeSi/EtherGuardVPN/config"
"github.com/KusakabeSi/EtherGuardVPN/path"
"github.com/KusakabeSi/EtherGuardVPN/tap"
"golang.org/x/crypto/chacha20poly1305"
@ -258,12 +259,13 @@ func (device *Device) RoutineReadFromTUN() {
}
EgBody.SetSrc(device.ID)
EgBody.SetDst(dst_nodeID)
//EgBody.SetPacketLength(uint16(len(elem.packet)))
EgBody.SetPacketLength(uint16(len(elem.packet)))
EgBody.SetTTL(200)
EgBody.SetUsage(path.NornalPacket)
if dst_nodeID != path.Boardcast {
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]
if peer_out == nil {
continue
@ -274,29 +276,12 @@ func (device *Device) RoutineReadFromTUN() {
peer_out.SendStagedPackets()
}
} else {
for key, _ := range path.GetBoardcastList(device.ID, device.NhTable) {
device.SendPacket(device.peers.IDMap[key], elem.packet, offset)
}
device.BoardcastPacket(make(map[config.Vertex]bool, 0), 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) {
for {
select {

View File

@ -19,8 +19,8 @@ import (
"sync/atomic"
"time"
"github.com/KusakabeSi/EtherGuardVPN/config"
"github.com/KusakabeSi/EtherGuardVPN/ipc"
"github.com/KusakabeSi/EtherGuardVPN/path"
)
type IPCError struct {
@ -284,7 +284,7 @@ func (device *Device) handlePublicKeyLine(peer *ipcSetPeer, value string) error
peer.created = peer.Peer == nil
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 {
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
require (
github.com/KusakabeSi/go-cache v0.0.0-20210817164551-57817be43e28
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2
golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57
gopkg.in/yaml.v2 v2.4.0

20
main.go
View File

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

View File

@ -9,6 +9,7 @@ package main
import (
"encoding/base64"
"errors"
"fmt"
"net"
"os"
@ -16,93 +17,130 @@ import (
"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"
)
type edgeConfig struct {
Interface InterfaceConf
NodeID path.Vertex
NodeName string
PrivKey string
ListenPort int
LogLevel LoggerInfo
SuperNode SuperInfo
NextHopTable path.NextHopTable
Peers []PeerInfo
}
func printExampleEdgeConf() {
tconfig := config.EdgeConfig{
Interface: config.InterfaceConf{
Itype: "stdio",
IfaceID: 5,
Name: "tap1",
MacAddr: "AA:BB:CC:DD:EE:FF",
MTU: 1400,
RecvAddr: "127.0.0.1:4001",
SendAddr: "127.0.0.1:5001",
HumanFriendly: true,
},
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 {
Itype string
IfaceID int
Name string
MacAddr string
MTU int
RecvAddr string
SendAddr string
HumanFriendly bool
}
type SuperInfo struct {
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)
g.UpdateLentancy(1, 2, path.S2TD(0.5), false)
g.UpdateLentancy(2, 1, path.S2TD(0.5), false)
g.UpdateLentancy(2, 3, path.S2TD(0.5), false)
g.UpdateLentancy(3, 2, path.S2TD(0.5), false)
g.UpdateLentancy(2, 4, path.S2TD(0.5), false)
g.UpdateLentancy(4, 2, path.S2TD(0.5), false)
g.UpdateLentancy(3, 4, path.S2TD(0.5), false)
g.UpdateLentancy(4, 3, path.S2TD(0.5), false)
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)
g.UpdateLentancy(4, 6, path.S2TD(0.5), false)
_, next := path.FloydWarshall(g)
config.NextHopTable = next
test, _ := yaml.Marshal(config)
fmt.Print(string(test))
tconfig.NextHopTable = next
toprint, _ := yaml.Marshal(tconfig)
fmt.Print(string(toprint))
return
}
func Edge(configPath string, useUAPI bool) (err error) {
var config edgeConfig
func Edge(configPath string, useUAPI bool, printExample bool) (err error) {
if printExample {
printExampleEdgeConf()
return nil
}
var tconfig config.EdgeConfig
//printExampleConf()
//return
err = readYaml(configPath, &config)
err = readYaml(configPath, &tconfig)
if err != nil {
fmt.Printf("Error read config: %s :", configPath)
fmt.Print(err)
return err
}
interfaceName := config.NodeName
interfaceName := tconfig.NodeName
var logLevel int
switch config.LogLevel.LogLevel {
switch tconfig.LogLevel.LogLevel {
case "verbose", "debug":
logLevel = device.LogLevelVerbose
case "error":
@ -110,14 +148,11 @@ func Edge(configPath string, useUAPI bool) (err error) {
case "silent":
logLevel = device.LogLevelSilent
}
logger := device.NewLogger(
logLevel,
fmt.Sprintf("(%s) ", interfaceName),
)
logger.Verbosef("Starting wireguard-go version %s", Version)
if err != nil {
logger.Errorf("UAPI listen error: %v", err)
os.Exit(ExitSetupFailed)
@ -126,40 +161,44 @@ func Edge(configPath string, useUAPI bool) (err error) {
var thetap tap.Device
// open TUN device (or use supplied fd)
switch config.Interface.Itype {
switch tconfig.Interface.Itype {
case "dummy":
thetap, err = tap.CreateDummyTAP()
case "stdio":
thetap, err = tap.CreateStdIOTAP(config.Interface.Name, config.Interface.HumanFriendly)
thetap, err = tap.CreateStdIOTAP(tconfig.Interface.Name, tconfig.Interface.HumanFriendly)
case "udpsock":
{
lis, _ := net.ResolveUDPAddr("udp", config.Interface.RecvAddr)
sen, _ := net.ResolveUDPAddr("udp", config.Interface.SendAddr)
thetap, err = tap.CreateUDPSockTAP(config.Interface.Name, lis, sen, config.Interface.HumanFriendly)
lis, _ := net.ResolveUDPAddr("udp", tconfig.Interface.RecvAddr)
sen, _ := net.ResolveUDPAddr("udp", tconfig.Interface.SendAddr)
thetap, err = tap.CreateUDPSockTAP(tconfig.Interface.Name, lis, sen, tconfig.Interface.HumanFriendly)
}
}
if err != nil {
logger.Errorf("Failed to create TUN device: %v", err)
logger.Errorf("Failed to create TAP device: %v", err)
os.Exit(ExitSetupFailed)
}
////////////////////////////////////////////////////
// Config
the_device := device.NewDevice(thetap, config.NodeID, conn.NewDefaultBind(), logger)
the_device.LogTransit = config.LogLevel.LogTransit
the_device.NhTable = config.NextHopTable
graph := path.NewGraph(3, false, tconfig.DynamicRoute.P2P.GraphRecalculateSetting)
graph.SetNHTable(tconfig.NextHopTable, [32]byte{})
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()
var sk [32]byte
sk_slice, _ := base64.StdEncoding.DecodeString(config.PrivKey)
sk_slice, _ := base64.StdEncoding.DecodeString(tconfig.PrivKey)
copy(sk[:], sk_slice)
the_device.SetPrivateKey(sk)
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")
for _, peerconf := range config.Peers {
for _, peerconf := range tconfig.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))
}
the_device.NewPeer(sk, peerconf.NodeID)
if peerconf.EndPoint != "" {
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")
errs := make(chan error)
term := make(chan os.Signal, 1)
if useUAPI {
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")
startUAPI(interfaceName, logger, the_device, errs)
}
// 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
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 (
"encoding/binary"
"errors"
"github.com/KusakabeSi/EtherGuardVPN/config"
)
const EgHeaderLen = 10
const EgHeaderLen = 12
type EgHeader struct {
buf []byte
@ -15,8 +17,15 @@ type Usage uint8
const (
NornalPacket Usage = iota
PingSingleWay
PingDualWay
Register //Register to server
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) {
@ -28,17 +37,17 @@ func NewEgHeader(pac []byte) (e EgHeader, err error) {
return
}
func (e EgHeader) GetDst() Vertex {
return Vertex(binary.BigEndian.Uint32(e.buf[0:4]))
func (e EgHeader) GetDst() config.Vertex {
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))
}
func (e EgHeader) GetSrc() Vertex {
return Vertex(binary.BigEndian.Uint32(e.buf[4:8]))
func (e EgHeader) GetSrc() config.Vertex {
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))
}
@ -50,18 +59,16 @@ func (e EgHeader) SetTTL(ttl uint8) {
e.buf[8] = ttl
}
func (e EgHeader) GetUsage() uint8 {
return e.buf[9]
func (e EgHeader) GetUsage() Usage {
return Usage(e.buf[9])
}
func (e EgHeader) SetUsage(usage uint8) {
e.buf[9] = usage
func (e EgHeader) SetUsage(usage Usage) {
e.buf[9] = uint8(usage)
}
/*
func (e EgHeader) GetPacketLength() uint16 {
return binary.BigEndian.Uint16(e.buf[10:12])
}
func (e EgHeader) SetPacketLength(length uint16) {
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"
"time"
"github.com/KusakabeSi/EtherGuardVPN/config"
yaml "gopkg.in/yaml.v2"
)
var (
timeout = time.Second * 3
const Infinity = float64(99999)
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
// this algorithm can run on.
type Graph interface {
Vertices() map[Vertex]bool
Neighbors(v Vertex) []Vertex
Weight(u, v Vertex) float64
Vertices() map[config.Vertex]bool
Neighbors(v config.Vertex) []config.Vertex
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 {
ping float64
time time.Time
}
type DistTable map[Vertex]map[Vertex]float64
type NextHopTable map[Vertex]map[Vertex]*Vertex
type Fullroute struct {
Dist DistTable `json:"total distance"`
Next NextHopTable `json:"next hop"`
Dist config.DistTable `json:"total distance"`
Next config.NextHopTable `json:"next hop"`
}
// IG is a graph of integers that satisfies the Graph interface.
type IG struct {
Vert map[Vertex]bool
Edges map[Vertex]map[Vertex]Latency
Vert map[config.Vertex]bool
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 {
g.Vert = make(map[Vertex]bool, num_node)
g.Edges = make(map[Vertex]map[Vertex]Latency, num_node)
return nil
func S2TD(secs float64) time.Duration {
return time.Duration(secs * float64(time.Second))
}
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[v] = true
w := float64(dt) / float64(time.Second)
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{
ping: w,
time: time.Now(),
}
return
}
func (g IG) Vertices() map[Vertex]bool { return g.Vert }
func (g IG) Neighbors(v Vertex) (vs []Vertex) {
func (g IG) Vertices() map[config.Vertex]bool {
return g.Vert
}
func (g IG) Neighbors(v config.Vertex) (vs []config.Vertex) {
for k := range g.Edges[v] {
vs = append(vs, k)
}
return vs
}
func (g IG) Weight(u, v Vertex) float64 {
if time.Now().Sub(g.Edges[u][v].time) < timeout {
return g.Edges[u][v].ping
func (g IG) Next(u, v config.Vertex) *config.Vertex {
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()
dist = make(DistTable)
next = make(NextHopTable)
dist = make(config.DistTable)
next = make(config.NextHopTable)
for u, _ := range vert {
dist[u] = make(map[Vertex]float64)
next[u] = make(map[Vertex]*Vertex)
dist[u] = make(map[config.Vertex]float64)
next[u] = make(map[config.Vertex]*config.Vertex)
for v, _ := range vert {
dist[u][v] = Infinity
}
@ -112,11 +206,11 @@ func FloydWarshall(g Graph) (dist DistTable, next NextHopTable) {
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 {
return []Vertex{}
return []config.Vertex{}
}
path = []Vertex{u}
path = []config.Vertex{u}
for u != v {
u = *next[u][v]
path = append(path, u)
@ -124,19 +218,32 @@ func Path(u, v Vertex, next NextHopTable) (path []Vertex) {
return path
}
func GetBoardcastList(id Vertex, nh NextHopTable) (tosend map[Vertex]bool) {
tosend = make(map[Vertex]bool)
for _, element := range nh[id] {
func (g *IG) SetNHTable(nh config.NextHopTable, table_hash [32]byte) { // set nhTable from supernode
g.NhTable = nh
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
}
return
}
func GetBoardcastThroughList(id Vertex, src Vertex, nh NextHopTable) (tosend map[Vertex]bool) {
tosend = make(map[Vertex]bool)
for check_id, _ := range GetBoardcastList(id, nh) {
for _, path_node := range Path(src, check_id, nh) {
if path_node == id {
func (g *IG) GetBoardcastThroughList(self_id config.Vertex, in_id config.Vertex, src_id config.Vertex) (tosend map[config.Vertex]bool) {
tosend = make(map[config.Vertex]bool)
for check_id, _ := range g.GetBoardcastList(self_id) {
for _, path_node := range Path(src_id, check_id, g.NhTable) {
if path_node == self_id && check_id != in_id {
tosend[check_id] = true
continue
}
@ -147,13 +254,13 @@ func GetBoardcastThroughList(id Vertex, src Vertex, nh NextHopTable) (tosend map
func Solve() {
var g IG
g.Init(4)
g.Edge(1, 2, 0.5)
g.Edge(2, 1, 0.5)
g.Edge(2, 3, 2)
g.Edge(3, 2, 2)
g.Edge(2, 4, 0.7)
g.Edge(4, 2, 2)
//g.Init()
g.UpdateLentancy(1, 2, S2TD(0.5), false)
g.UpdateLentancy(2, 1, S2TD(0.5), false)
g.UpdateLentancy(2, 3, S2TD(2), false)
g.UpdateLentancy(3, 2, S2TD(2), false)
g.UpdateLentancy(2, 4, S2TD(0.7), false)
g.UpdateLentancy(4, 2, S2TD(2), false)
dist, next := FloydWarshall(g)
fmt.Println("pair\tdist\tpath")
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)
}