EtherGuard-VPN/main_edge.go

356 lines
10 KiB
Go
Raw Normal View History

2021-08-16 20:58:15 +02:00
// +build !windows
/* SPDX-License-Identifier: MIT
*
* Copyright (C) 2017-2021 WireGuard LLC. All Rights Reserved.
*/
package main
import (
2021-08-20 19:32:50 +02:00
"errors"
2021-08-16 20:58:15 +02:00
"fmt"
"os"
2021-11-06 10:47:06 +01:00
"os/exec"
2021-08-16 20:58:15 +02:00
"os/signal"
"strconv"
"syscall"
2021-11-06 10:47:06 +01:00
"github.com/google/shlex"
2021-08-20 19:32:50 +02:00
"github.com/KusakabeSi/EtherGuardVPN/config"
2021-08-16 20:58:15 +02:00
"github.com/KusakabeSi/EtherGuardVPN/conn"
"github.com/KusakabeSi/EtherGuardVPN/device"
"github.com/KusakabeSi/EtherGuardVPN/path"
"github.com/KusakabeSi/EtherGuardVPN/tap"
yaml "gopkg.in/yaml.v2"
)
2021-08-20 19:32:50 +02:00
func printExampleEdgeConf() {
v1 := config.Vertex(1)
v2 := config.Vertex(2)
2021-08-20 19:32:50 +02:00
tconfig := config.EdgeConfig{
Interface: config.InterfaceConf{
Itype: "stdio",
Name: "tap1",
VPPIfaceID: 5,
VPPBridgeID: 4242,
MacAddrPrefix: "AA:BB:CC:DD",
MTU: 1416,
2021-08-20 19:32:50 +02:00
RecvAddr: "127.0.0.1:4001",
SendAddr: "127.0.0.1:5001",
2021-08-24 10:43:55 +02:00
L2HeaderMode: "nochg",
2021-08-20 19:32:50 +02:00
},
2021-10-27 03:02:44 +02:00
NodeID: 1,
NodeName: "Node01",
2021-11-06 10:47:06 +01:00
PostScript: "",
2021-10-27 03:02:44 +02:00
DefaultTTL: 200,
L2FIBTimeout: 3600,
PrivKey: "6GyDagZKhbm5WNqMiRHhkf43RlbMJ34IieTlIuvfJ1M=",
ListenPort: 3001,
2021-08-20 19:32:50 +02:00
LogLevel: config.LoggerInfo{
2021-10-09 12:22:27 +02:00
LogLevel: "error",
LogTransit: true,
LogControl: true,
LogNormal: true,
LogInternal: true,
LogNTP: false,
2021-08-20 19:32:50 +02:00
},
DynamicRoute: config.DynamicRouteInfo{
SendPingInterval: 20,
PeerAliveTimeout: 30,
2021-08-20 19:32:50 +02:00
DupCheckTimeout: 40,
ConnTimeOut: 30,
ConnNextTry: 5,
2021-08-20 19:32:50 +02:00
SaveNewPeers: true,
SuperNode: config.SuperInfo{
UseSuperNode: true,
PSKey: "iPM8FXfnHVzwjguZHRW9bLNY+h7+B1O2oTJtktptQkI=",
2021-08-20 19:32:50 +02:00
ConnURLV4: "127.0.0.1:3000",
2021-08-24 10:43:55 +02:00
PubKeyV4: "LJ8KKacUcIoACTGB/9Ed9w0osrJ3WWeelzpL2u4oUic=",
2021-08-20 19:32:50 +02:00
ConnURLV6: "[::1]:3000",
2021-08-24 10:43:55 +02:00
PubKeyV6: "HCfL6YJtpJEGHTlJ2LgVXIWKB/K95P57LHTJ42ZG8VI=",
2021-08-20 19:32:50 +02:00
APIUrl: "http://127.0.0.1:3000/api",
SuperNodeInfoTimeout: 50,
2021-08-20 19:32:50 +02:00
},
P2P: config.P2Pinfo{
UseP2P: true,
SendPeerInterval: 20,
GraphRecalculateSetting: config.GraphRecalculateSetting{
2021-10-01 10:56:42 +02:00
StaticMode: false,
2021-08-20 19:32:50 +02:00
JitterTolerance: 20,
JitterToleranceMultiplier: 1.1,
NodeReportTimeout: 40,
2021-10-27 03:02:44 +02:00
TimeoutCheckInterval: 5,
2021-08-20 19:32:50 +02:00
RecalculateCoolDown: 5,
},
},
NTPconfig: config.NTPinfo{
2021-08-25 13:54:13 +02:00
UseNTP: true,
MaxServerUse: 5,
SyncTimeInterval: 3600,
NTPTimeout: 3,
2021-08-20 19:32:50 +02:00
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{
config.Vertex(1): {
config.Vertex(2): &v2,
},
config.Vertex(2): {
config.Vertex(1): &v1,
},
},
2021-08-24 10:43:55 +02:00
ResetConnInterval: 86400,
2021-08-20 19:32:50 +02:00
Peers: []config.PeerInfo{
2021-08-26 21:06:15 +02:00
{
NodeID: 2,
PubKey: "dHeWQtlTPQGy87WdbUARS4CtwVaR2y7IQ1qcX4GKSXk=",
PSKey: "juJMQaGAaeSy8aDsXSKNsPZv/nFiPj4h/1G70tGYygs=",
2021-08-20 19:32:50 +02:00
EndPoint: "127.0.0.1:3002",
Static: true,
},
},
}
2021-10-12 10:05:23 +02:00
g := path.NewGraph(3, false, tconfig.DynamicRoute.P2P.GraphRecalculateSetting, tconfig.DynamicRoute.NTPconfig, tconfig.LogLevel)
2021-08-16 20:58:15 +02:00
2021-10-27 03:02:44 +02:00
g.UpdateLatency(1, 2, path.S2TD(0.5), 0, false, false)
g.UpdateLatency(2, 1, path.S2TD(0.5), 0, false, false)
g.UpdateLatency(2, 3, path.S2TD(0.5), 0, false, false)
g.UpdateLatency(3, 2, path.S2TD(0.5), 0, false, false)
g.UpdateLatency(2, 4, path.S2TD(0.5), 0, false, false)
g.UpdateLatency(4, 2, path.S2TD(0.5), 0, false, false)
g.UpdateLatency(3, 4, path.S2TD(0.5), 0, false, false)
g.UpdateLatency(4, 3, path.S2TD(0.5), 0, false, false)
g.UpdateLatency(5, 3, path.S2TD(0.5), 0, false, false)
g.UpdateLatency(3, 5, path.S2TD(0.5), 0, false, false)
g.UpdateLatency(6, 4, path.S2TD(0.5), 0, false, false)
g.UpdateLatency(4, 6, path.S2TD(0.5), 0, false, false)
2021-10-12 10:05:23 +02:00
_, next, _ := g.FloydWarshall(false)
2021-08-20 19:32:50 +02:00
tconfig.NextHopTable = next
toprint, _ := yaml.Marshal(tconfig)
fmt.Print(string(toprint))
2021-08-16 20:58:15 +02:00
return
}
func Edge(configPath string, useUAPI bool, printExample bool, bindmode string) (err error) {
2021-08-20 19:32:50 +02:00
if printExample {
printExampleEdgeConf()
return nil
}
2021-09-20 22:20:00 +02:00
var econfig config.EdgeConfig
2021-08-16 20:58:15 +02:00
//printExampleConf()
//return
2021-09-20 22:20:00 +02:00
err = readYaml(configPath, &econfig)
2021-08-16 20:58:15 +02:00
if err != nil {
2021-09-21 22:03:11 +02:00
fmt.Printf("Error read config: %v\t%v\n", configPath, err)
2021-08-16 20:58:15 +02:00
return err
}
2021-09-20 22:20:00 +02:00
NodeName := econfig.NodeName
2021-08-25 13:54:13 +02:00
if len(NodeName) > 32 {
return errors.New("Node name can't longer than 32 :" + NodeName)
}
2021-08-16 20:58:15 +02:00
var logLevel int
2021-09-20 22:20:00 +02:00
switch econfig.LogLevel.LogLevel {
2021-08-16 20:58:15 +02:00
case "verbose", "debug":
logLevel = device.LogLevelVerbose
case "error":
logLevel = device.LogLevelError
case "silent":
logLevel = device.LogLevelSilent
2021-08-26 11:06:40 +02:00
default:
logLevel = device.LogLevelError
2021-08-16 20:58:15 +02:00
}
logger := device.NewLogger(
logLevel,
2021-08-25 13:54:13 +02:00
fmt.Sprintf("(%s) ", NodeName),
2021-08-16 20:58:15 +02:00
)
if err != nil {
logger.Errorf("UAPI listen error: %v", err)
os.Exit(ExitSetupFailed)
return
}
var thetap tap.Device
// open TUN device (or use supplied fd)
2021-09-20 22:20:00 +02:00
switch econfig.Interface.Itype {
2021-08-16 20:58:15 +02:00
case "dummy":
thetap, err = tap.CreateDummyTAP()
case "stdio":
2021-09-20 22:20:00 +02:00
thetap, err = tap.CreateStdIOTAP(econfig.Interface, econfig.NodeID)
2021-08-16 20:58:15 +02:00
case "udpsock":
thetap, err = tap.CreateUDPSockTAP(econfig.Interface, econfig.NodeID)
case "tcpsock":
2021-10-09 12:22:27 +02:00
thetap, err = tap.CreateSockTAP(econfig.Interface, "tcp", econfig.NodeID, econfig.LogLevel)
case "unixsock":
2021-10-09 12:22:27 +02:00
thetap, err = tap.CreateSockTAP(econfig.Interface, "unix", econfig.NodeID, econfig.LogLevel)
case "unixgramsock":
thetap, err = tap.CreateSockTAP(econfig.Interface, "unixgram", econfig.NodeID, econfig.LogLevel)
case "unixpacketsock":
thetap, err = tap.CreateSockTAP(econfig.Interface, "unixpacket", econfig.NodeID, econfig.LogLevel)
case "fd":
thetap, err = tap.CreateFdTAP(econfig.Interface, econfig.NodeID)
2021-08-24 10:43:55 +02:00
case "vpp":
2021-09-20 22:20:00 +02:00
thetap, err = tap.CreateVppTAP(econfig.Interface, econfig.NodeID, econfig.LogLevel.LogLevel)
2021-08-24 15:26:20 +02:00
case "tap":
2021-09-20 22:20:00 +02:00
thetap, err = tap.CreateTAP(econfig.Interface, econfig.NodeID)
2021-08-24 10:43:55 +02:00
default:
2021-09-20 22:20:00 +02:00
return errors.New("Unknow interface type:" + econfig.Interface.Itype)
2021-08-16 20:58:15 +02:00
}
if err != nil {
2021-08-20 19:32:50 +02:00
logger.Errorf("Failed to create TAP device: %v", err)
2021-08-16 20:58:15 +02:00
os.Exit(ExitSetupFailed)
}
2021-09-20 22:20:00 +02:00
if econfig.DefaultTTL <= 0 {
return errors.New("DefaultTTL must > 0")
}
2021-08-16 20:58:15 +02:00
////////////////////////////////////////////////////
// Config
2021-09-20 22:20:00 +02:00
if econfig.DynamicRoute.P2P.UseP2P == false && econfig.DynamicRoute.SuperNode.UseSuperNode == false {
econfig.LogLevel.LogNTP = false // NTP in static mode is useless
2021-08-25 13:54:13 +02:00
}
2021-10-12 10:05:23 +02:00
graph := path.NewGraph(3, false, econfig.DynamicRoute.P2P.GraphRecalculateSetting, econfig.DynamicRoute.NTPconfig, econfig.LogLevel)
2021-09-20 22:20:00 +02:00
graph.SetNHTable(econfig.NextHopTable, [32]byte{})
2021-08-20 19:32:50 +02:00
the_device := device.NewDevice(thetap, econfig.NodeID, conn.NewDefaultBind(true, true, bindmode), logger, graph, false, configPath, &econfig, nil, nil, Version)
2021-08-16 20:58:15 +02:00
defer the_device.Close()
2021-09-21 03:15:23 +02:00
pk, err := device.Str2PriKey(econfig.PrivKey)
if err != nil {
fmt.Println("Error decode base64 ", err)
return err
}
the_device.SetPrivateKey(pk)
2021-08-16 20:58:15 +02:00
the_device.IpcSet("fwmark=0\n")
2021-09-20 22:20:00 +02:00
the_device.IpcSet("listen_port=" + strconv.Itoa(econfig.ListenPort) + "\n")
2021-08-16 20:58:15 +02:00
the_device.IpcSet("replace_peers=true\n")
2021-09-20 22:20:00 +02:00
for _, peerconf := range econfig.Peers {
2021-09-21 03:15:23 +02:00
pk, err := device.Str2PubKey(peerconf.PubKey)
if err != nil {
fmt.Println("Error decode base64 ", err)
return err
}
2021-09-21 22:03:11 +02:00
the_device.NewPeer(pk, peerconf.NodeID, false)
2021-08-16 20:58:15 +02:00
if peerconf.EndPoint != "" {
2021-09-21 03:15:23 +02:00
peer := the_device.LookupPeer(pk)
err = peer.SetEndpointFromConnURL(peerconf.EndPoint, 0, peerconf.Static)
2021-08-16 20:58:15 +02:00
if err != nil {
logger.Errorf("Failed to set endpoint %v: %w", peerconf.EndPoint, err)
return err
}
}
}
2021-09-20 22:20:00 +02:00
if econfig.DynamicRoute.SuperNode.UseSuperNode {
S4 := true
S6 := true
2021-09-20 22:20:00 +02:00
if econfig.DynamicRoute.SuperNode.ConnURLV4 != "" {
2021-09-21 03:15:23 +02:00
pk, err := device.Str2PubKey(econfig.DynamicRoute.SuperNode.PubKeyV4)
if err != nil {
fmt.Println("Error decode base64 ", err)
return err
}
psk, err := device.Str2PSKey(econfig.DynamicRoute.SuperNode.PSKey)
2021-08-20 19:32:50 +02:00
if err != nil {
fmt.Println("Error decode base64 ", err)
2021-08-20 19:32:50 +02:00
return err
}
2021-09-21 22:03:11 +02:00
peer, err := the_device.NewPeer(pk, config.SuperNodeMessage, true)
2021-08-20 19:32:50 +02:00
if err != nil {
return err
}
peer.SetPSK(psk)
err = peer.SetEndpointFromConnURL(econfig.DynamicRoute.SuperNode.ConnURLV4, 4, false)
if err != nil {
logger.Errorf("Failed to set endpoint for supernode v4 %v: %v", econfig.DynamicRoute.SuperNode.ConnURLV4, err)
S4 = false
}
2021-08-20 19:32:50 +02:00
}
2021-09-20 22:20:00 +02:00
if econfig.DynamicRoute.SuperNode.ConnURLV6 != "" {
2021-09-21 03:15:23 +02:00
pk, err := device.Str2PubKey(econfig.DynamicRoute.SuperNode.PubKeyV6)
if err != nil {
fmt.Println("Error decode base64 ", err)
}
psk, err := device.Str2PSKey(econfig.DynamicRoute.SuperNode.PSKey)
2021-08-20 19:32:50 +02:00
if err != nil {
fmt.Println("Error decode base64 ", err)
2021-08-20 19:32:50 +02:00
return err
}
2021-09-21 22:03:11 +02:00
peer, err := the_device.NewPeer(pk, config.SuperNodeMessage, true)
2021-08-20 19:32:50 +02:00
if err != nil {
return err
}
peer.SetPSK(psk)
2021-08-24 10:43:55 +02:00
peer.StaticConn = false
2021-09-20 22:20:00 +02:00
peer.ConnURL = econfig.DynamicRoute.SuperNode.ConnURLV6
err = peer.SetEndpointFromConnURL(econfig.DynamicRoute.SuperNode.ConnURLV6, 6, false)
if err != nil {
logger.Errorf("Failed to set endpoint for supernode v6 %v: %v", econfig.DynamicRoute.SuperNode.ConnURLV6, err)
S6 = false
}
if !(S4 || S6) {
return errors.New("Failed to connect to supernode.")
}
2021-08-20 19:32:50 +02:00
}
2021-08-25 10:13:53 +02:00
the_device.Event_Supernode_OK <- struct{}{}
2021-08-20 19:32:50 +02:00
}
2021-08-16 20:58:15 +02:00
logger.Verbosef("Device started")
errs := make(chan error)
term := make(chan os.Signal, 1)
if useUAPI {
2021-08-25 13:54:13 +02:00
startUAPI(NodeName, logger, the_device, errs)
2021-08-16 20:58:15 +02:00
}
2021-11-06 10:47:06 +01:00
if econfig.PostScript != "" {
cmdarg, err := shlex.Split(econfig.PostScript)
if err != nil {
return fmt.Errorf("Error parse PostScript %v\n", err)
}
if econfig.LogLevel.LogInternal {
fmt.Printf("PostScript: exec.Command(%v)\n", cmdarg)
}
cmd := exec.Command(cmdarg[0], cmdarg[1:]...)
out, err := cmd.CombinedOutput()
if err != nil {
return fmt.Errorf("exec.Command(%v) failed with %v\n", cmdarg, err)
}
if econfig.LogLevel.LogInternal {
fmt.Printf("PostScript output: %s\n", string(out))
}
}
2021-08-16 20:58:15 +02:00
2021-11-06 10:47:06 +01:00
// wait for program to terminate
2021-08-16 20:58:15 +02:00
signal.Notify(term, syscall.SIGTERM)
signal.Notify(term, os.Interrupt)
select {
case <-term:
case <-errs:
case <-the_device.Wait():
}
logger.Verbosef("Shutting down")
return
}