mirror of
https://github.com/fosrl/olm.git
synced 2026-02-08 05:56:41 +00:00
Merge branch 'main' into holepunch
This commit is contained in:
109
main.go
109
main.go
@@ -8,12 +8,13 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
"os"
|
"os"
|
||||||
|
"os/exec"
|
||||||
"os/signal"
|
"os/signal"
|
||||||
|
"regexp"
|
||||||
"runtime"
|
"runtime"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"syscall"
|
"syscall"
|
||||||
"unsafe"
|
|
||||||
|
|
||||||
"github.com/fosrl/newt/logger"
|
"github.com/fosrl/newt/logger"
|
||||||
"github.com/fosrl/olm/websocket"
|
"github.com/fosrl/olm/websocket"
|
||||||
@@ -146,7 +147,10 @@ func resolveDomain(domain string) (string, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ConfigureInterface configures a network interface with an IP address and brings it up
|
// ConfigureInterface configures a network interface with an IP address and brings it up
|
||||||
func ConfigureInterface(interfaceName string, ipAddr string) error {
|
func ConfigureInterface(interfaceName string, wgData WgData) error {
|
||||||
|
var ipAddr string = wgData.TunnelIP
|
||||||
|
var destIP string = wgData.ServerIP
|
||||||
|
|
||||||
// Parse the IP address and network
|
// Parse the IP address and network
|
||||||
ip, ipNet, err := net.ParseCIDR(ipAddr)
|
ip, ipNet, err := net.ParseCIDR(ipAddr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -157,69 +161,53 @@ func ConfigureInterface(interfaceName string, ipAddr string) error {
|
|||||||
case "linux":
|
case "linux":
|
||||||
return configureLinux(interfaceName, ip, ipNet)
|
return configureLinux(interfaceName, ip, ipNet)
|
||||||
case "darwin":
|
case "darwin":
|
||||||
return configureDarwin(interfaceName, ip, ipNet)
|
return configureDarwin(interfaceName, ip, destIP)
|
||||||
default:
|
default:
|
||||||
return fmt.Errorf("unsupported operating system: %s", runtime.GOOS)
|
return fmt.Errorf("unsupported operating system: %s", runtime.GOOS)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func configureDarwin(interfaceName string, ip net.IP, ipNet *net.IPNet) error {
|
func findUnusedUTUN() (string, error) {
|
||||||
// Get interface by name
|
ifaces, err := net.Interfaces()
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("failed to list interfaces: %v", err)
|
||||||
|
}
|
||||||
|
used := make(map[int]bool)
|
||||||
|
re := regexp.MustCompile(`^utun(\d+)$`)
|
||||||
|
for _, iface := range ifaces {
|
||||||
|
if matches := re.FindStringSubmatch(iface.Name); len(matches) == 2 {
|
||||||
|
if num, err := strconv.Atoi(matches[1]); err == nil {
|
||||||
|
used[num] = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Try utun0 up to utun255.
|
||||||
|
for i := 0; i < 256; i++ {
|
||||||
|
if !used[i] {
|
||||||
|
return fmt.Sprintf("utun%d", i), nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "", fmt.Errorf("no unused utun interface found")
|
||||||
|
}
|
||||||
|
|
||||||
|
func configureDarwin(interfaceName string, ip net.IP, destIp string) error {
|
||||||
|
logger.Info("Configuring darwin interface: %s", interfaceName)
|
||||||
|
|
||||||
iface, err := net.InterfaceByName(interfaceName)
|
iface, err := net.InterfaceByName(interfaceName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to get interface %s: %v", interfaceName, err)
|
return fmt.Errorf("failed to get interface %s: %v", interfaceName, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// print something using the iface
|
|
||||||
logger.Info("Interface %s: %v", interfaceName, iface)
|
logger.Info("Interface %s: %v", interfaceName, iface)
|
||||||
|
|
||||||
// Create socket
|
ipStr := ip.String()
|
||||||
fd, err := syscall.Socket(syscall.AF_INET, syscall.SOCK_DGRAM, 0)
|
|
||||||
|
cmd := exec.Command("ifconfig", interfaceName, ipStr+"/24", destIp, "up")
|
||||||
|
// print the command used
|
||||||
|
logger.Info("Running command: %v", cmd)
|
||||||
|
|
||||||
|
out, err := cmd.CombinedOutput()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to create socket: %v", err)
|
return fmt.Errorf("ifconfig command failed: %v, output: %s", err, out)
|
||||||
}
|
|
||||||
defer syscall.Close(fd)
|
|
||||||
|
|
||||||
// Prepare interface request structure
|
|
||||||
ifr := struct {
|
|
||||||
Name [16]byte
|
|
||||||
Flags uint16
|
|
||||||
}{}
|
|
||||||
copy(ifr.Name[:], interfaceName)
|
|
||||||
|
|
||||||
// Get current flags
|
|
||||||
if err := ioctl(fd, syscall.SIOCGIFFLAGS, uintptr(unsafe.Pointer(&ifr))); err != nil {
|
|
||||||
return fmt.Errorf("failed to get interface flags: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set interface up
|
|
||||||
ifr.Flags |= syscall.IFF_UP | syscall.IFF_RUNNING
|
|
||||||
if err := ioctl(fd, syscall.SIOCSIFFLAGS, uintptr(unsafe.Pointer(&ifr))); err != nil {
|
|
||||||
return fmt.Errorf("failed to set interface up: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Prepare address structure
|
|
||||||
var addr syscall.SockaddrInet4
|
|
||||||
copy(addr.Addr[:], ip.To4())
|
|
||||||
|
|
||||||
// Create interface address request
|
|
||||||
ifra := struct {
|
|
||||||
Name [16]byte
|
|
||||||
Addr syscall.RawSockaddrInet4
|
|
||||||
Mask syscall.RawSockaddrInet4
|
|
||||||
}{}
|
|
||||||
copy(ifra.Name[:], interfaceName)
|
|
||||||
copy(ifra.Addr.Addr[:], ip.To4())
|
|
||||||
copy(ifra.Mask.Addr[:], ipNet.Mask)
|
|
||||||
|
|
||||||
// Set IP address
|
|
||||||
if err := ioctl(fd, syscall.SIOCSIFADDR, uintptr(unsafe.Pointer(&ifra))); err != nil {
|
|
||||||
return fmt.Errorf("failed to set interface address: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set netmask
|
|
||||||
if err := ioctl(fd, syscall.SIOCSIFNETMASK, uintptr(unsafe.Pointer(&ifra))); err != nil {
|
|
||||||
return fmt.Errorf("failed to set interface netmask: %v", err)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@@ -352,7 +340,7 @@ func main() {
|
|||||||
reachableAt = os.Getenv("REACHABLE_AT")
|
reachableAt = os.Getenv("REACHABLE_AT")
|
||||||
|
|
||||||
if endpoint == "" {
|
if endpoint == "" {
|
||||||
flag.StringVar(&endpoint, "endpoint", "", "Endpoint of your pangolin server")
|
flag.StringVar(&endpoint, "endpoint", "", "Endpoint of your Pangolin server")
|
||||||
}
|
}
|
||||||
if id == "" {
|
if id == "" {
|
||||||
flag.StringVar(&id, "id", "", "Olm ID")
|
flag.StringVar(&id, "id", "", "Olm ID")
|
||||||
@@ -440,8 +428,19 @@ func main() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NEED TO DETERMINE AVAILABLE TUN DEVICE HERE
|
||||||
tdev, err := func() (tun.Device, error) {
|
tdev, err := func() (tun.Device, error) {
|
||||||
tunFdStr := os.Getenv(ENV_WG_TUN_FD)
|
tunFdStr := os.Getenv(ENV_WG_TUN_FD)
|
||||||
|
|
||||||
|
// if on macOS, call findUnusedUTUN to get a new utun device
|
||||||
|
if runtime.GOOS == "darwin" {
|
||||||
|
interfaceName, err := findUnusedUTUN()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return tun.CreateTUN(interfaceName, mtuInt)
|
||||||
|
}
|
||||||
|
|
||||||
if tunFdStr == "" {
|
if tunFdStr == "" {
|
||||||
return tun.CreateTUN(interfaceName, mtuInt)
|
return tun.CreateTUN(interfaceName, mtuInt)
|
||||||
}
|
}
|
||||||
@@ -546,7 +545,7 @@ persistent_keepalive_interval=5`, fixKey(privateKey.String()), fixKey(wgData.Pub
|
|||||||
}
|
}
|
||||||
|
|
||||||
// configure the interface
|
// configure the interface
|
||||||
err = ConfigureInterface(realInterfaceName, wgData.TunnelIP)
|
err = ConfigureInterface(realInterfaceName, wgData)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error("Failed to configure interface: %v", err)
|
logger.Error("Failed to configure interface: %v", err)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user