Add project

This commit is contained in:
2022-11-15 18:12:16 +01:00
parent b250277bab
commit 5d40cde0c8
11 changed files with 538 additions and 10 deletions

18
cmd/app/filter.go Normal file
View File

@@ -0,0 +1,18 @@
package main
import (
"github.com/vishvananda/netlink"
)
type FilterOptions struct {
Table int
Protocol int
}
func CheckFilter(options FilterOptions, route netlink.Route) bool {
if (options.Table != -1 && options.Table != route.Table) ||
(options.Protocol != -1 && options.Protocol != route.Protocol) {
return false
}
return true
}

17
cmd/app/logger.go Normal file
View File

@@ -0,0 +1,17 @@
package main
import (
"log"
"os"
)
type Log struct {
Info log.Logger
Warn log.Logger
Error log.Logger
}
var logger Log = Log{
Info: *log.New(os.Stdout, "[INFO]\t", log.Ltime|log.Lshortfile),
Warn: *log.New(os.Stderr, "[WARN]\t", log.Ltime|log.Lshortfile),
Error: *log.New(os.Stderr, "[ERROR]\t", log.Ltime|log.Lshortfile),
}

214
cmd/app/main.go Normal file
View File

@@ -0,0 +1,214 @@
package main
import (
"net"
"os"
envChecks "git.ruekov.eu/ruakij/routingtabletowg/lib/environmentchecks"
ip2Map "git.ruekov.eu/ruakij/routingtabletowg/lib/iproute2mapping"
"git.ruekov.eu/ruakij/routingtabletowg/lib/wgchecks"
"github.com/vishvananda/netlink"
"golang.org/x/sys/unix"
"golang.zx2c4.com/wireguard/wgctrl"
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
)
var envRequired = []string{
"INTERFACE",
}
var envDefaults = map[string]string{
"INTERFACE": "wg0",
//"MANAGE_ALL": "true",
"FILTER_PROTOCOL": "-1",
"FILTER_TABLE": "-1",
}
func main() {
// Environment-vars
err := envChecks.HandleRequired(envRequired)
if(err != nil){
logger.Error.Fatal(err)
}
envChecks.HandleDefaults(envDefaults)
iface := os.Getenv("INTERFACE")
//MANAGE_ALL = os.Getenv("MANAGE_ALL")
// Parse filter-env-vars
filterProtocolStr := os.Getenv("FILTER_PROTOCOL")
filterProtocol, err := ip2Map.TryGetId(ip2Map.PROTOCOL, filterProtocolStr)
if err != nil {
logger.Error.Fatalf("Couldn't read FILTER_PROTOCOL '%s': %s", filterProtocolStr, err)
}
filterTableStr := os.Getenv("FILTER_TABLE")
filterTable, err := ip2Map.TryGetId(ip2Map.TABLE, filterTableStr)
if err != nil {
logger.Error.Fatalf("Couldn't read FILTER_TABLE '%s': %s", filterTableStr, err)
}
// Create filter
filterOptions := FilterOptions{
Table: filterTable,
Protocol: filterProtocol,
}
// Get Link-Device
link, err := netlink.LinkByName(iface)
if err != nil {
logger.Error.Fatalf("Couldn't get interface '%s': %s", iface, err)
}
// Test getting wg-client
client, err := wgctrl.New()
if err != nil {
logger.Error.Fatalf("Couldn't create wgctl-client: %s", err)
}
// Test getting wg-device
_, err = client.Device(iface)
if err != nil {
logger.Error.Fatalf("Couldn't get wg-interface '%s': %s", iface, err)
}
// Subscribe to route-change events
routeSubChan, routeSubDoneChan := make(chan netlink.RouteUpdate), make(chan struct{})
netlink.RouteSubscribe(routeSubChan, routeSubDoneChan)
go handleRouteEvents(routeSubChan, filterOptions, iface)
//# Initial Route-setup
// Get routing-table entries from device
routeList, err := netlink.RouteList(link, netlink.FAMILY_ALL)
if err != nil {
logger.Error.Fatalf("Couldn't get route-entries: %s", err)
}
logger.Info.Printf("Initially setting all current routes")
for _, route := range routeList {
// Ignore routes with empty gateway
if(route.Gw == nil){
continue
}
// Send current routes to handler
routeSubChan <- netlink.RouteUpdate{
Type: unix.RTM_NEWROUTE,
Route: route,
}
}
select {}
}
var routeUpdateTypeMapFromId = map[uint16]string{
unix.RTM_NEWROUTE: "+",
unix.RTM_DELROUTE: "-",
}
// TODO: Add proxy to apply filter in channels rather than.. this mess
func handleRouteEvents(routeSubChan <-chan netlink.RouteUpdate, filterOptions FilterOptions, iface string) {
// Create wg-client
client, err := wgctrl.New()
if err != nil {
logger.Error.Fatalf("Couldn't create wgctl-client: %s", err)
}
for {
// Receive Route-Updates
routeUpdate := <-routeSubChan
route := routeUpdate.Route
// Check filter
if(!CheckFilter(filterOptions, routeUpdate.Route)){
continue
}
// Special case for default-route
if route.Dst == nil{
if route.Gw.To4() != nil { // IPv4
route.Dst = &net.IPNet{
IP: net.IPv4zero,
Mask: net.CIDRMask(0, 32),
}
} else { // IPv6
route.Dst = &net.IPNet{
IP: net.IPv6zero,
Mask: net.CIDRMask(0, 128),
}
}
}
logger.Info.Printf("Route-Update: [%s] %s via %s", routeUpdateTypeMapFromId[routeUpdate.Type], route.Dst, route.Gw)
// Get wgDevice
wgDevice, err := client.Device(iface)
if err != nil {
logger.Error.Fatalf("Couldn't get wg-interface '%s' while running: %s", iface, err)
}
// Empty config for filling in switch
var wgConfig wgtypes.Config
switch routeUpdate.Type{
case unix.RTM_NEWROUTE:
// Check if gateway is set
if route.Gw == nil{
logger.Warn.Printf("Gateway unset, ignoring")
continue
}
// Check if other peer already has exact same dst
if peer, err := wgChecks.PeerByIPNet(wgDevice.Peers, *route.Dst); err == nil {
logger.Warn.Printf("dst-IPNet already set for Peer '%s', ignoring", peer.PublicKey)
continue
}
// Get peer containing gateway-addr
peer, err := wgChecks.PeerByIP(wgDevice.Peers, route.Gw)
if(err != nil){
logger.Warn.Printf("No peer found containing gw-IP '%s', ignoring", route.Gw)
continue
}
// Set peerConfig, this will override set values for that peer
wgConfig.Peers = []wgtypes.PeerConfig{
{
PublicKey: peer.PublicKey,
AllowedIPs: append(peer.AllowedIPs, *route.Dst),
},
}
case unix.RTM_DELROUTE:
// Get peer containing dst-NetIP
peerIndex, ipNetIndex, err := wgChecks.PeerIndexByIPNet(wgDevice.Peers, *route.Dst)
if(err != nil){
logger.Warn.Printf("No peer found having dst-IPNet '%s', ignoring", route.Dst)
continue
}
peer := wgDevice.Peers[peerIndex]
// Delete dstNet from allowedIPs
peer.AllowedIPs[ipNetIndex] = peer.AllowedIPs[len(peer.AllowedIPs)-1]
peer.AllowedIPs = peer.AllowedIPs[:len(peer.AllowedIPs)-1]
// Set peerConfig, this will override set values for that peer
wgConfig.Peers = []wgtypes.PeerConfig{
{
PublicKey: peer.PublicKey,
UpdateOnly: true,
ReplaceAllowedIPs: true,
AllowedIPs: peer.AllowedIPs,
},
}
}
err = client.ConfigureDevice(iface, wgConfig)
if(err != nil){
logger.Error.Fatalf("Error configuring wg-device '%s': %s", iface, err)
}
}
}