-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
6 changed files
with
991 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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), | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,159 @@ | ||
package main | ||
|
||
import ( | ||
"fmt" | ||
"net" | ||
"os" | ||
"strconv" | ||
"time" | ||
|
||
envChecks "git.ruekov.eu/ruakij/routingtabletowg/lib/environmentchecks" | ||
"git.ruekov.eu/ruakij/routingtabletowg/lib/wgchecks/netchecks" | ||
|
||
"github.com/vishvananda/netlink" | ||
"golang.zx2c4.com/wireguard/wgctrl" | ||
"golang.zx2c4.com/wireguard/wgctrl/wgtypes" | ||
) | ||
|
||
var envRequired = []string{ | ||
"INTERFACE", | ||
} | ||
var envDefaults = map[string]string{ | ||
"IPV6_FORMAT": "fc12::%02x%02x:%02x%02x/%d", | ||
"FILTER_PREFIX": "100.100", | ||
"RECHECK_INTERVAL": "300", | ||
} | ||
|
||
func main() { | ||
// Environment-vars | ||
err := envChecks.HandleRequired(envRequired) | ||
if(err != nil){ | ||
logger.Error.Fatal(err) | ||
} | ||
envChecks.HandleDefaults(envDefaults) | ||
|
||
// Get the network interface object | ||
iface := os.Getenv("INTERFACE") | ||
netInterface, err := netlink.LinkByName(iface) | ||
if err != nil { | ||
logger.Error.Fatal(err) | ||
} | ||
|
||
ipv6Format := os.Getenv("IPV6_FORMAT") | ||
ipv6TestStr := *convertIPv4ToIPv6(&ipv6Format, &net.IPNet{IP: net.IPv4(1,1,1,1), Mask: net.CIDRMask(24, net.IPv4len)}) | ||
_, err = netlink.ParseIPNet(ipv6TestStr) | ||
if err != nil { | ||
logger.Error.Fatalf("IPV6_FORMAT is invalid: %s", err) | ||
} | ||
|
||
filterPrefix := os.Getenv("FILTER_PREFIX") | ||
|
||
checkIntervalStr := os.Getenv("RECHECK_INTERVAL") | ||
checkIntervalSec, err := strconv.Atoi(checkIntervalStr) | ||
if err != nil { | ||
logger.Error.Fatalf("Couldn't read RECHECK_INTERVAL '%s': %s", checkIntervalStr, err) | ||
} | ||
checkInterval := time.Second * time.Duration(checkIntervalSec) | ||
|
||
// Get the IPv4 address of the interface | ||
addrs, err := netlink.AddrList(netInterface, netlink.FAMILY_V4) | ||
if err != nil { | ||
logger.Error.Fatal(err) | ||
} | ||
if(len(addrs) == 0){ | ||
logger.Error.Fatal("Interface doesnt have IPv4-Adresses") | ||
} | ||
|
||
// Add the IPv6 address to the interface | ||
ipv6Str := *convertIPv4ToIPv6(&ipv6Format, addrs[0].IPNet) | ||
ipv6, err := netlink.ParseAddr(ipv6Str) | ||
if err != nil { | ||
logger.Error.Fatal(err) | ||
} | ||
logger.Info.Printf("Adding converted %s -> %s to interface", addrs[0].IPNet.String(), ipv6Str) | ||
err = netlink.AddrAdd(netInterface, ipv6) | ||
if err != nil { | ||
switch { | ||
case os.IsExist(err): | ||
logger.Warn.Println("Address is already set on interface") | ||
default: | ||
logger.Error.Fatalf("Failed to set address on interface: %v", err) | ||
} | ||
} | ||
|
||
// Create a WireGuard client | ||
client, err := wgctrl.New() | ||
if err != nil { | ||
logger.Error.Fatal(err) | ||
} | ||
defer client.Close() | ||
|
||
// Loop indefinitely | ||
for { | ||
// Get the WireGuard peers on the interface | ||
wgDevice, err := client.Device(iface) | ||
if err != nil { | ||
logger.Error.Fatalf("getting WireGuard device from interface '%s' failed: %s", iface, err) | ||
} | ||
|
||
var wgConfig wgtypes.Config | ||
wgConfig.Peers = make([]wgtypes.PeerConfig, 0, len(wgDevice.Peers)) | ||
|
||
for _, peer := range wgDevice.Peers { | ||
// Create slice for 1 expected addition | ||
var addAllowedIPs = make([]net.IPNet, 0, 1) | ||
|
||
// Loop through the allowed-ips and add the ones starting with 100.100 | ||
for _, allowedIP := range peer.AllowedIPs { | ||
if allowedIP.String()[:len(filterPrefix)] == filterPrefix { | ||
// Convert the IPv4 allowed-ip to an IPv6 address | ||
ipv6Str := *convertIPv4ToIPv6(&ipv6Format, &allowedIP) | ||
logger.Info.Printf("AllowedIP %s -> %s to peer %s", allowedIP.String(), ipv6Str, peer.PublicKey) | ||
ipv6, err := netlink.ParseIPNet(ipv6Str) | ||
if err != nil { | ||
logger.Warn.Printf("Couldnt parse IPv6 address %s of peer %s: %s", ipv6Str, peer.PublicKey, err) | ||
continue | ||
} | ||
|
||
// Check if already set | ||
if i, _ := netchecks.IPNetIndexByIPNet(&peer.AllowedIPs, ipv6); i != -1 { | ||
continue | ||
} | ||
|
||
// Add the IPv6 allowed-ip to the peer | ||
addAllowedIPs = append(addAllowedIPs, *ipv6) | ||
} | ||
} | ||
|
||
if(len(addAllowedIPs) > 0){ | ||
// Create peer-config | ||
peerConfig := wgtypes.PeerConfig{ | ||
PublicKey: peer.PublicKey, | ||
AllowedIPs: append(peer.AllowedIPs, addAllowedIPs...), | ||
} | ||
|
||
// Add entry | ||
wgConfig.Peers = append(wgConfig.Peers, peerConfig) | ||
} | ||
} | ||
|
||
if(len(wgConfig.Peers) == 0){ | ||
logger.Info.Println("No changes, skipping") | ||
} else { | ||
err = client.ConfigureDevice(iface, wgConfig) | ||
if(err != nil){ | ||
logger.Error.Fatalf("Error configuring wg-device '%s': %s", iface, err) | ||
} | ||
} | ||
|
||
// Sleep for x seconds before running the loop again | ||
time.Sleep(checkInterval) | ||
} | ||
} | ||
|
||
func convertIPv4ToIPv6(ipv6Format *string, ipv4 *net.IPNet) (*string) { | ||
CIDR, _ := ipv4.Mask.Size() | ||
// Run format | ||
ipv6Str := fmt.Sprintf(*ipv6Format, (*ipv4).IP[0], (*ipv4).IP[1], (*ipv4).IP[2], (*ipv4).IP[3], net.IPv6len*8-(net.IPv4len*8-CIDR)) | ||
return &ipv6Str | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
module git.ruekov.eu/wg-ipv6-converter | ||
|
||
go 1.20 | ||
|
||
require golang.zx2c4.com/wireguard/wgctrl v0.0.0-20230215201556-9c5414ab4bde | ||
|
||
require github.com/vishvananda/netns v0.0.4 // indirect | ||
|
||
require ( | ||
git.ruekov.eu/ruakij/routingtabletowg v0.0.0-20230331142222-dcc0b6607b52 | ||
github.com/google/go-cmp v0.5.9 // indirect | ||
github.com/josharian/native v1.1.0 // indirect | ||
github.com/mdlayher/genetlink v1.3.1 // indirect | ||
github.com/mdlayher/netlink v1.7.1 // indirect | ||
github.com/mdlayher/socket v0.4.0 // indirect | ||
github.com/vishvananda/netlink v1.1.0 | ||
golang.org/x/crypto v0.7.0 // indirect | ||
golang.org/x/net v0.8.0 // indirect | ||
golang.org/x/sync v0.1.0 // indirect | ||
golang.org/x/sys v0.6.0 // indirect | ||
golang.zx2c4.com/wireguard v0.0.0-20230325221338-052af4a8072b // indirect | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
git.ruekov.eu/ruakij/routingtabletowg v0.0.0-20230331142222-dcc0b6607b52 h1:W7nF5Qxua2PDMoogjVXceWSEeboOfd8/HvpIY7HjMbM= | ||
git.ruekov.eu/ruakij/routingtabletowg v0.0.0-20230331142222-dcc0b6607b52/go.mod h1:wYEQNasQeg+oOxXqFBxavBjZfX5hY5qoGrV4K6sRaiI= | ||
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= | ||
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= | ||
github.com/josharian/native v1.1.0 h1:uuaP0hAbW7Y4l0ZRQ6C9zfb7Mg1mbFKry/xzDAfmtLA= | ||
github.com/josharian/native v1.1.0/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w= | ||
github.com/mdlayher/genetlink v1.3.1 h1:roBiPnual+eqtRkKX2Jb8UQN5ZPWnhDCGj/wR6Jlz2w= | ||
github.com/mdlayher/genetlink v1.3.1/go.mod h1:uaIPxkWmGk753VVIzDtROxQ8+T+dkHqOI0vB1NA9S/Q= | ||
github.com/mdlayher/netlink v1.7.1 h1:FdUaT/e33HjEXagwELR8R3/KL1Fq5x3G5jgHLp/BTmg= | ||
github.com/mdlayher/netlink v1.7.1/go.mod h1:nKO5CSjE/DJjVhk/TNp6vCE1ktVxEA8VEh8drhZzxsQ= | ||
github.com/mdlayher/socket v0.4.0 h1:280wsy40IC9M9q1uPGcLBwXpcTQDtoGwVt+BNoITxIw= | ||
github.com/mdlayher/socket v0.4.0/go.mod h1:xxFqz5GRCUN3UEOm9CZqEJsAbe1C8OwSK46NlmWuVoc= | ||
github.com/mikioh/ipaddr v0.0.0-20190404000644-d465c8ab6721 h1:RlZweED6sbSArvlE924+mUcZuXKLBHA35U7LN621Bws= | ||
github.com/vishvananda/netlink v1.1.0 h1:1iyaYNBLmP6L0220aDnYQpo1QEV4t4hJ+xEEhhJH8j0= | ||
github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE= | ||
github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU= | ||
github.com/vishvananda/netns v0.0.4 h1:Oeaw1EM2JMxD51g9uhtC0D7erkIjgmj8+JZc26m1YX8= | ||
github.com/vishvananda/netns v0.0.4/go.mod h1:SpkAiCQRtJ6TvvxPnOSyH3BMl6unz3xZlaprSwhNNJM= | ||
golang.org/x/crypto v0.7.0 h1:AvwMYaRytfdeVt3u6mLaxYtErKYjxA2OXjJ1HHq6t3A= | ||
golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= | ||
golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= | ||
golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= | ||
golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= | ||
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | ||
golang.org/x/sys v0.0.0-20190606203320-7fc4e5ec1444/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | ||
golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= | ||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | ||
golang.zx2c4.com/wireguard v0.0.0-20230325221338-052af4a8072b h1:J1CaxgLerRR5lgx3wnr6L04cJFbWoceSK9JWBdglINo= | ||
golang.zx2c4.com/wireguard v0.0.0-20230325221338-052af4a8072b/go.mod h1:tqur9LnfstdR9ep2LaJT4lFUl0EjlHtge+gAjmsHUG4= | ||
golang.zx2c4.com/wireguard/wgctrl v0.0.0-20230215201556-9c5414ab4bde h1:ybF7AMzIUikL9x4LgwEmzhXtzRpKNqngme1VGDWz+Nk= | ||
golang.zx2c4.com/wireguard/wgctrl v0.0.0-20230215201556-9c5414ab4bde/go.mod h1:mQqgjkW8GQQcJQsbBvK890TKqUK1DfKWkuBGbOkuMHQ= |