mirror of
https://github.com/fosrl/newt.git
synced 2026-02-08 05:56:40 +00:00
Merge branch 'dev' into msg-delivery
This commit is contained in:
6
.github/workflows/cicd.yml
vendored
6
.github/workflows/cicd.yml
vendored
@@ -11,7 +11,9 @@ permissions:
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- "*"
|
||||
- "[0-9]+.[0-9]+.[0-9]+"
|
||||
- "[0-9]+.[0-9]+.[0-9]+-rc.[0-9]+"
|
||||
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
version:
|
||||
@@ -273,7 +275,7 @@ jobs:
|
||||
tags: |
|
||||
type=semver,pattern={{version}},value=${{ env.TAG }}
|
||||
type=semver,pattern={{major}}.{{minor}},value=${{ env.TAG }},enable=${{ env.PUBLISH_MINOR == 'true' && env.IS_RC != 'true' }}
|
||||
type=raw,value=latest,enable=${{ env.PUBLISH_LATEST == 'true' && env.IS_RC != 'true' }}
|
||||
type=raw,value=latest,enable=${{ env.IS_RC != 'true' }}
|
||||
flavor: |
|
||||
latest=false
|
||||
labels: |
|
||||
|
||||
23
.github/workflows/nix-build.yml
vendored
Normal file
23
.github/workflows/nix-build.yml
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
name: Build Nix package
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
pull_request:
|
||||
paths:
|
||||
- go.mod
|
||||
- go.sum
|
||||
|
||||
jobs:
|
||||
nix-build:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Install Nix
|
||||
uses: DeterminateSystems/nix-installer-action@main
|
||||
|
||||
- name: Build flake package
|
||||
run: |
|
||||
nix build .#pangolin-newt -L
|
||||
48
.github/workflows/nix-dependabot-update-hash.yml
vendored
Normal file
48
.github/workflows/nix-dependabot-update-hash.yml
vendored
Normal file
@@ -0,0 +1,48 @@
|
||||
name: Update Nix Package Hash On Dependabot PRs
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types: [opened, synchronize]
|
||||
branches:
|
||||
- main
|
||||
|
||||
jobs:
|
||||
nix-update:
|
||||
if: github.actor == 'dependabot[bot]'
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
ref: ${{ github.head_ref }}
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Install Nix
|
||||
uses: DeterminateSystems/nix-installer-action@main
|
||||
|
||||
- name: Run nix-update
|
||||
run: |
|
||||
nix run nixpkgs#nix-update -- --flake pangolin-newt --no-src --version skip
|
||||
|
||||
- name: Check for changes
|
||||
id: changes
|
||||
run: |
|
||||
if git diff --quiet; then
|
||||
echo "changed=false" >> "$GITHUB_OUTPUT"
|
||||
else
|
||||
echo "changed=true" >> "$GITHUB_OUTPUT"
|
||||
fi
|
||||
|
||||
- name: Commit and push changes
|
||||
if: steps.changes.outputs.changed == 'true'
|
||||
run: |
|
||||
git config user.name "dependabot[bot]"
|
||||
git config user.email "dependabot[bot]@users.noreply.github.com"
|
||||
|
||||
git add .
|
||||
git commit -m "chore(nix): fix hash for updated go dependencies"
|
||||
git push
|
||||
4
.gitignore
vendored
4
.gitignore
vendored
@@ -5,4 +5,6 @@ nohup.out
|
||||
*.iml
|
||||
certs/
|
||||
newt_arm64
|
||||
key
|
||||
key
|
||||
/.direnv/
|
||||
/result*
|
||||
|
||||
@@ -523,7 +523,7 @@ func (b *SharedBind) receiveIPv4Simple(conn *net.UDPConn, bufs [][]byte, sizes [
|
||||
func (b *SharedBind) handleMagicPacket(data []byte, addr *net.UDPAddr) bool {
|
||||
// Check if this is a test request packet
|
||||
if len(data) >= MagicTestRequestLen && bytes.HasPrefix(data, MagicTestRequest) {
|
||||
logger.Debug("Received magic test REQUEST from %s, sending response", addr.String())
|
||||
// logger.Debug("Received magic test REQUEST from %s, sending response", addr.String())
|
||||
// Extract the random data portion to echo back
|
||||
echoData := data[len(MagicTestRequest) : len(MagicTestRequest)+MagicPacketDataLen]
|
||||
|
||||
@@ -546,7 +546,7 @@ func (b *SharedBind) handleMagicPacket(data []byte, addr *net.UDPAddr) bool {
|
||||
|
||||
// Check if this is a test response packet
|
||||
if len(data) >= MagicTestResponseLen && bytes.HasPrefix(data, MagicTestResponse) {
|
||||
logger.Debug("Received magic test RESPONSE from %s", addr.String())
|
||||
// logger.Debug("Received magic test RESPONSE from %s", addr.String())
|
||||
// Extract the echoed data
|
||||
echoData := data[len(MagicTestResponse) : len(MagicTestResponse)+MagicPacketDataLen]
|
||||
|
||||
|
||||
8
clients/permissions/permissions_android.go
Normal file
8
clients/permissions/permissions_android.go
Normal file
@@ -0,0 +1,8 @@
|
||||
//go:build android
|
||||
|
||||
package permissions
|
||||
|
||||
// CheckNativeInterfacePermissions always allows permission on Android.
|
||||
func CheckNativeInterfacePermissions() error {
|
||||
return nil
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
//go:build darwin
|
||||
//go:build darwin && !ios
|
||||
|
||||
package permissions
|
||||
|
||||
|
||||
8
clients/permissions/permissions_ios.go
Normal file
8
clients/permissions/permissions_ios.go
Normal file
@@ -0,0 +1,8 @@
|
||||
//go:build ios
|
||||
|
||||
package permissions
|
||||
|
||||
// CheckNativeInterfacePermissions always allows permission on iOS.
|
||||
func CheckNativeInterfacePermissions() error {
|
||||
return nil
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
//go:build linux
|
||||
//go:build linux && !android
|
||||
|
||||
package permissions
|
||||
|
||||
|
||||
15
flake.nix
15
flake.nix
@@ -25,7 +25,7 @@
|
||||
inherit (pkgs) lib;
|
||||
|
||||
# Update version when releasing
|
||||
version = "1.7.0";
|
||||
version = "1.8.0";
|
||||
in
|
||||
{
|
||||
default = self.packages.${system}.pangolin-newt;
|
||||
@@ -37,14 +37,26 @@
|
||||
|
||||
vendorHash = "sha256-5Xr6mwPtsqEliKeKv2rhhp6JC7u3coP4nnhIxGMqccU=";
|
||||
|
||||
nativeInstallCheckInputs = [ pkgs.versionCheckHook ];
|
||||
|
||||
env = {
|
||||
CGO_ENABLED = 0;
|
||||
};
|
||||
|
||||
ldflags = [
|
||||
"-s"
|
||||
"-w"
|
||||
"-X main.newtVersion=${version}"
|
||||
];
|
||||
|
||||
# Tests are broken due to a lack of Internet.
|
||||
# Disable running `go test`, and instead do
|
||||
# a simple version check instead.
|
||||
doCheck = false;
|
||||
doInstallCheck = true;
|
||||
|
||||
versionCheckProgramArg = [ "-version" ];
|
||||
|
||||
meta = {
|
||||
description = "A tunneling client for Pangolin";
|
||||
homepage = "https://github.com/fosrl/newt";
|
||||
@@ -52,6 +64,7 @@
|
||||
maintainers = [
|
||||
lib.maintainers.water-sucks
|
||||
];
|
||||
mainProgram = "newt";
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
@@ -61,6 +61,7 @@ type Target struct {
|
||||
timer *time.Timer
|
||||
ctx context.Context
|
||||
cancel context.CancelFunc
|
||||
client *http.Client
|
||||
}
|
||||
|
||||
// StatusChangeCallback is called when any target's status changes
|
||||
@@ -185,6 +186,16 @@ func (m *Monitor) addTargetUnsafe(config Config) error {
|
||||
Status: StatusUnknown,
|
||||
ctx: ctx,
|
||||
cancel: cancel,
|
||||
client: &http.Client{
|
||||
Transport: &http.Transport{
|
||||
TLSClientConfig: &tls.Config{
|
||||
// Configure TLS settings based on certificate enforcement
|
||||
InsecureSkipVerify: !m.enforceCert,
|
||||
// Use SNI TLS header if present
|
||||
ServerName: config.TLSServerName,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
m.targets[config.ID] = target
|
||||
@@ -378,17 +389,6 @@ func (m *Monitor) performHealthCheck(target *Target) {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), time.Duration(target.Config.Timeout)*time.Second)
|
||||
defer cancel()
|
||||
|
||||
client := &http.Client{
|
||||
Transport: &http.Transport{
|
||||
TLSClientConfig: &tls.Config{
|
||||
// Configure TLS settings based on certificate enforcement
|
||||
InsecureSkipVerify: !m.enforceCert,
|
||||
// Use SNI TLS header if present
|
||||
ServerName: target.Config.TLSServerName,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
req, err := http.NewRequestWithContext(ctx, target.Config.Method, url, nil)
|
||||
if err != nil {
|
||||
target.Status = StatusUnhealthy
|
||||
@@ -408,7 +408,7 @@ func (m *Monitor) performHealthCheck(target *Target) {
|
||||
}
|
||||
|
||||
// Perform request
|
||||
resp, err := client.Do(req)
|
||||
resp, err := target.client.Do(req)
|
||||
if err != nil {
|
||||
target.Status = StatusUnhealthy
|
||||
target.LastError = fmt.Sprintf("request failed: %v", err)
|
||||
|
||||
@@ -38,21 +38,29 @@ type Manager struct {
|
||||
exitNodes map[string]ExitNode // key is endpoint
|
||||
updateChan chan struct{} // signals the goroutine to refresh exit nodes
|
||||
|
||||
sendHolepunchInterval time.Duration
|
||||
sendHolepunchInterval time.Duration
|
||||
sendHolepunchIntervalMin time.Duration
|
||||
sendHolepunchIntervalMax time.Duration
|
||||
defaultIntervalMin time.Duration
|
||||
defaultIntervalMax time.Duration
|
||||
}
|
||||
|
||||
const sendHolepunchIntervalMax = 60 * time.Second
|
||||
const sendHolepunchIntervalMin = 1 * time.Second
|
||||
const defaultSendHolepunchIntervalMax = 60 * time.Second
|
||||
const defaultSendHolepunchIntervalMin = 1 * time.Second
|
||||
|
||||
// NewManager creates a new hole punch manager
|
||||
func NewManager(sharedBind *bind.SharedBind, ID string, clientType string, publicKey string) *Manager {
|
||||
return &Manager{
|
||||
sharedBind: sharedBind,
|
||||
ID: ID,
|
||||
clientType: clientType,
|
||||
publicKey: publicKey,
|
||||
exitNodes: make(map[string]ExitNode),
|
||||
sendHolepunchInterval: sendHolepunchIntervalMin,
|
||||
sharedBind: sharedBind,
|
||||
ID: ID,
|
||||
clientType: clientType,
|
||||
publicKey: publicKey,
|
||||
exitNodes: make(map[string]ExitNode),
|
||||
sendHolepunchInterval: defaultSendHolepunchIntervalMin,
|
||||
sendHolepunchIntervalMin: defaultSendHolepunchIntervalMin,
|
||||
sendHolepunchIntervalMax: defaultSendHolepunchIntervalMax,
|
||||
defaultIntervalMin: defaultSendHolepunchIntervalMin,
|
||||
defaultIntervalMax: defaultSendHolepunchIntervalMax,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -200,17 +208,46 @@ func (m *Manager) GetExitNodes() []ExitNode {
|
||||
return nodes
|
||||
}
|
||||
|
||||
// ResetInterval resets the hole punch interval back to the minimum value,
|
||||
// allowing it to climb back up through exponential backoff.
|
||||
// This is useful when network conditions change or connectivity is restored.
|
||||
func (m *Manager) ResetInterval() {
|
||||
// SetServerHolepunchInterval sets custom min and max intervals for hole punching.
|
||||
// This is useful for low power mode where longer intervals are desired.
|
||||
func (m *Manager) SetServerHolepunchInterval(min, max time.Duration) {
|
||||
m.mu.Lock()
|
||||
defer m.mu.Unlock()
|
||||
|
||||
if m.sendHolepunchInterval != sendHolepunchIntervalMin {
|
||||
m.sendHolepunchInterval = sendHolepunchIntervalMin
|
||||
logger.Info("Reset hole punch interval to minimum (%v)", sendHolepunchIntervalMin)
|
||||
m.sendHolepunchIntervalMin = min
|
||||
m.sendHolepunchIntervalMax = max
|
||||
m.sendHolepunchInterval = min
|
||||
|
||||
logger.Info("Set hole punch intervals: min=%v, max=%v", min, max)
|
||||
|
||||
// Signal the goroutine to apply the new interval if running
|
||||
if m.running && m.updateChan != nil {
|
||||
select {
|
||||
case m.updateChan <- struct{}{}:
|
||||
default:
|
||||
// Channel full or closed, skip
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// GetInterval returns the current min and max intervals
|
||||
func (m *Manager) GetServerHolepunchInterval() (min, max time.Duration) {
|
||||
m.mu.Lock()
|
||||
defer m.mu.Unlock()
|
||||
return m.sendHolepunchIntervalMin, m.sendHolepunchIntervalMax
|
||||
}
|
||||
|
||||
// ResetServerHolepunchInterval resets the hole punch interval back to the default values.
|
||||
// This restores normal operation after low power mode or other custom settings.
|
||||
func (m *Manager) ResetServerHolepunchInterval() {
|
||||
m.mu.Lock()
|
||||
defer m.mu.Unlock()
|
||||
|
||||
m.sendHolepunchIntervalMin = m.defaultIntervalMin
|
||||
m.sendHolepunchIntervalMax = m.defaultIntervalMax
|
||||
m.sendHolepunchInterval = m.defaultIntervalMin
|
||||
|
||||
logger.Info("Reset hole punch intervals to defaults: min=%v, max=%v", m.defaultIntervalMin, m.defaultIntervalMax)
|
||||
|
||||
// Signal the goroutine to apply the new interval if running
|
||||
if m.running && m.updateChan != nil {
|
||||
@@ -393,7 +430,7 @@ func (m *Manager) runMultipleExitNodes() {
|
||||
|
||||
// Start with minimum interval
|
||||
m.mu.Lock()
|
||||
m.sendHolepunchInterval = sendHolepunchIntervalMin
|
||||
m.sendHolepunchInterval = m.sendHolepunchIntervalMin
|
||||
m.mu.Unlock()
|
||||
|
||||
ticker := time.NewTicker(m.sendHolepunchInterval)
|
||||
@@ -415,7 +452,7 @@ func (m *Manager) runMultipleExitNodes() {
|
||||
}
|
||||
// Reset interval to minimum on update
|
||||
m.mu.Lock()
|
||||
m.sendHolepunchInterval = sendHolepunchIntervalMin
|
||||
m.sendHolepunchInterval = m.sendHolepunchIntervalMin
|
||||
m.mu.Unlock()
|
||||
ticker.Reset(m.sendHolepunchInterval)
|
||||
// Send immediate hole punch to newly resolved nodes
|
||||
@@ -435,8 +472,8 @@ func (m *Manager) runMultipleExitNodes() {
|
||||
// Exponential backoff: double the interval up to max
|
||||
m.mu.Lock()
|
||||
newInterval := m.sendHolepunchInterval * 2
|
||||
if newInterval > sendHolepunchIntervalMax {
|
||||
newInterval = sendHolepunchIntervalMax
|
||||
if newInterval > m.sendHolepunchIntervalMax {
|
||||
newInterval = m.sendHolepunchIntervalMax
|
||||
}
|
||||
if newInterval != m.sendHolepunchInterval {
|
||||
m.sendHolepunchInterval = newInterval
|
||||
|
||||
@@ -41,6 +41,12 @@ func DefaultTestOptions() TestConnectionOptions {
|
||||
}
|
||||
}
|
||||
|
||||
// cachedAddr holds a cached resolved UDP address
|
||||
type cachedAddr struct {
|
||||
addr *net.UDPAddr
|
||||
resolvedAt time.Time
|
||||
}
|
||||
|
||||
// HolepunchTester monitors holepunch connectivity using magic packets
|
||||
type HolepunchTester struct {
|
||||
sharedBind *bind.SharedBind
|
||||
@@ -53,6 +59,11 @@ type HolepunchTester struct {
|
||||
|
||||
// Callback when connection status changes
|
||||
callback HolepunchStatusCallback
|
||||
|
||||
// Address cache to avoid repeated DNS/UDP resolution
|
||||
addrCache map[string]*cachedAddr
|
||||
addrCacheMu sync.RWMutex
|
||||
addrCacheTTL time.Duration // How long cached addresses are valid
|
||||
}
|
||||
|
||||
// HolepunchStatus represents the status of a holepunch connection
|
||||
@@ -75,7 +86,9 @@ type pendingRequest struct {
|
||||
// NewHolepunchTester creates a new holepunch tester using the given SharedBind
|
||||
func NewHolepunchTester(sharedBind *bind.SharedBind) *HolepunchTester {
|
||||
return &HolepunchTester{
|
||||
sharedBind: sharedBind,
|
||||
sharedBind: sharedBind,
|
||||
addrCache: make(map[string]*cachedAddr),
|
||||
addrCacheTTL: 5 * time.Minute, // Cache addresses for 5 minutes
|
||||
}
|
||||
}
|
||||
|
||||
@@ -135,12 +148,70 @@ func (t *HolepunchTester) Stop() {
|
||||
return true
|
||||
})
|
||||
|
||||
// Clear address cache
|
||||
t.addrCacheMu.Lock()
|
||||
t.addrCache = make(map[string]*cachedAddr)
|
||||
t.addrCacheMu.Unlock()
|
||||
|
||||
logger.Debug("HolepunchTester stopped")
|
||||
}
|
||||
|
||||
// resolveEndpoint resolves an endpoint to a UDP address, using cache when possible
|
||||
func (t *HolepunchTester) resolveEndpoint(endpoint string) (*net.UDPAddr, error) {
|
||||
// Check cache first
|
||||
t.addrCacheMu.RLock()
|
||||
cached, ok := t.addrCache[endpoint]
|
||||
ttl := t.addrCacheTTL
|
||||
t.addrCacheMu.RUnlock()
|
||||
|
||||
if ok && time.Since(cached.resolvedAt) < ttl {
|
||||
return cached.addr, nil
|
||||
}
|
||||
|
||||
// Resolve the endpoint
|
||||
host, err := util.ResolveDomain(endpoint)
|
||||
if err != nil {
|
||||
host = endpoint
|
||||
}
|
||||
|
||||
_, _, err = net.SplitHostPort(host)
|
||||
if err != nil {
|
||||
host = net.JoinHostPort(host, "21820")
|
||||
}
|
||||
|
||||
remoteAddr, err := net.ResolveUDPAddr("udp", host)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to resolve UDP address %s: %w", host, err)
|
||||
}
|
||||
|
||||
// Cache the result
|
||||
t.addrCacheMu.Lock()
|
||||
t.addrCache[endpoint] = &cachedAddr{
|
||||
addr: remoteAddr,
|
||||
resolvedAt: time.Now(),
|
||||
}
|
||||
t.addrCacheMu.Unlock()
|
||||
|
||||
return remoteAddr, nil
|
||||
}
|
||||
|
||||
// InvalidateCache removes a specific endpoint from the address cache
|
||||
func (t *HolepunchTester) InvalidateCache(endpoint string) {
|
||||
t.addrCacheMu.Lock()
|
||||
delete(t.addrCache, endpoint)
|
||||
t.addrCacheMu.Unlock()
|
||||
}
|
||||
|
||||
// ClearCache clears all cached addresses
|
||||
func (t *HolepunchTester) ClearCache() {
|
||||
t.addrCacheMu.Lock()
|
||||
t.addrCache = make(map[string]*cachedAddr)
|
||||
t.addrCacheMu.Unlock()
|
||||
}
|
||||
|
||||
// handleResponse is called by SharedBind when a magic response is received
|
||||
func (t *HolepunchTester) handleResponse(addr netip.AddrPort, echoData []byte) {
|
||||
logger.Debug("Received magic response from %s", addr.String())
|
||||
// logger.Debug("Received magic response from %s", addr.String())
|
||||
key := string(echoData)
|
||||
|
||||
value, ok := t.pendingRequests.LoadAndDelete(key)
|
||||
@@ -152,7 +223,7 @@ func (t *HolepunchTester) handleResponse(addr netip.AddrPort, echoData []byte) {
|
||||
|
||||
req := value.(*pendingRequest)
|
||||
rtt := time.Since(req.sentAt)
|
||||
logger.Debug("Magic response matched pending request for %s (RTT: %v)", req.endpoint, rtt)
|
||||
// logger.Debug("Magic response matched pending request for %s (RTT: %v)", req.endpoint, rtt)
|
||||
|
||||
// Send RTT to the waiting goroutine (non-blocking)
|
||||
select {
|
||||
@@ -183,20 +254,10 @@ func (t *HolepunchTester) TestEndpoint(endpoint string, timeout time.Duration) T
|
||||
return result
|
||||
}
|
||||
|
||||
// Resolve the endpoint
|
||||
host, err := util.ResolveDomain(endpoint)
|
||||
// Resolve the endpoint (using cache)
|
||||
remoteAddr, err := t.resolveEndpoint(endpoint)
|
||||
if err != nil {
|
||||
host = endpoint
|
||||
}
|
||||
|
||||
_, _, err = net.SplitHostPort(host)
|
||||
if err != nil {
|
||||
host = net.JoinHostPort(host, "21820")
|
||||
}
|
||||
|
||||
remoteAddr, err := net.ResolveUDPAddr("udp", host)
|
||||
if err != nil {
|
||||
result.Error = fmt.Errorf("failed to resolve UDP address %s: %w", host, err)
|
||||
result.Error = err
|
||||
return result
|
||||
}
|
||||
|
||||
|
||||
@@ -44,9 +44,13 @@ func ConfigureInterface(interfaceName string, tunnelIp string, mtu int) error {
|
||||
return configureDarwin(interfaceName, ip, ipNet)
|
||||
case "windows":
|
||||
return configureWindows(interfaceName, ip, ipNet)
|
||||
default:
|
||||
return fmt.Errorf("unsupported operating system: %s", runtime.GOOS)
|
||||
case "android":
|
||||
return nil
|
||||
case "ios":
|
||||
return nil
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// waitForInterfaceUp polls the network interface until it's up or times out
|
||||
|
||||
@@ -126,13 +126,14 @@ func LinuxRemoveRoute(destination string) error {
|
||||
|
||||
// addRouteForServerIP adds an OS-specific route for the server IP
|
||||
func AddRouteForServerIP(serverIP, interfaceName string) error {
|
||||
if err := AddRouteForNetworkConfig(serverIP); err != nil {
|
||||
return err
|
||||
}
|
||||
if interfaceName == "" {
|
||||
return nil
|
||||
}
|
||||
if runtime.GOOS == "darwin" {
|
||||
// TODO: does this also need to be ios?
|
||||
if runtime.GOOS == "darwin" { // macos requires routes for each peer to be added but this messes with other platforms
|
||||
if err := AddRouteForNetworkConfig(serverIP); err != nil {
|
||||
return err
|
||||
}
|
||||
return DarwinAddRoute(serverIP, "", interfaceName)
|
||||
}
|
||||
// else if runtime.GOOS == "windows" {
|
||||
@@ -145,13 +146,14 @@ func AddRouteForServerIP(serverIP, interfaceName string) error {
|
||||
|
||||
// removeRouteForServerIP removes an OS-specific route for the server IP
|
||||
func RemoveRouteForServerIP(serverIP string, interfaceName string) error {
|
||||
if err := RemoveRouteForNetworkConfig(serverIP); err != nil {
|
||||
return err
|
||||
}
|
||||
if interfaceName == "" {
|
||||
return nil
|
||||
}
|
||||
if runtime.GOOS == "darwin" {
|
||||
// TODO: does this also need to be ios?
|
||||
if runtime.GOOS == "darwin" { // macos requires routes for each peer to be added but this messes with other platforms
|
||||
if err := RemoveRouteForNetworkConfig(serverIP); err != nil {
|
||||
return err
|
||||
}
|
||||
return DarwinRemoveRoute(serverIP)
|
||||
}
|
||||
// else if runtime.GOOS == "windows" {
|
||||
@@ -217,21 +219,22 @@ func AddRoutes(remoteSubnets []string, interfaceName string) error {
|
||||
continue
|
||||
}
|
||||
|
||||
if runtime.GOOS == "darwin" {
|
||||
switch runtime.GOOS {
|
||||
case "darwin":
|
||||
if err := DarwinAddRoute(subnet, "", interfaceName); err != nil {
|
||||
logger.Error("Failed to add Darwin route for subnet %s: %v", subnet, err)
|
||||
return err
|
||||
}
|
||||
} else if runtime.GOOS == "windows" {
|
||||
case "windows":
|
||||
if err := WindowsAddRoute(subnet, "", interfaceName); err != nil {
|
||||
logger.Error("Failed to add Windows route for subnet %s: %v", subnet, err)
|
||||
return err
|
||||
}
|
||||
} else if runtime.GOOS == "linux" {
|
||||
case "linux":
|
||||
if err := LinuxAddRoute(subnet, "", interfaceName); err != nil {
|
||||
logger.Error("Failed to add Linux route for subnet %s: %v", subnet, err)
|
||||
return err
|
||||
}
|
||||
case "android", "ios":
|
||||
// Routes handled by the OS/VPN service
|
||||
continue
|
||||
}
|
||||
|
||||
logger.Info("Added route for remote subnet: %s", subnet)
|
||||
@@ -258,21 +261,22 @@ func RemoveRoutes(remoteSubnets []string) error {
|
||||
}
|
||||
|
||||
// Remove route based on operating system
|
||||
if runtime.GOOS == "darwin" {
|
||||
switch runtime.GOOS {
|
||||
case "darwin":
|
||||
if err := DarwinRemoveRoute(subnet); err != nil {
|
||||
logger.Error("Failed to remove Darwin route for subnet %s: %v", subnet, err)
|
||||
return err
|
||||
}
|
||||
} else if runtime.GOOS == "windows" {
|
||||
case "windows":
|
||||
if err := WindowsRemoveRoute(subnet); err != nil {
|
||||
logger.Error("Failed to remove Windows route for subnet %s: %v", subnet, err)
|
||||
return err
|
||||
}
|
||||
} else if runtime.GOOS == "linux" {
|
||||
case "linux":
|
||||
if err := LinuxRemoveRoute(subnet); err != nil {
|
||||
logger.Error("Failed to remove Linux route for subnet %s: %v", subnet, err)
|
||||
return err
|
||||
}
|
||||
case "android", "ios":
|
||||
// Routes handled by the OS/VPN service
|
||||
continue
|
||||
}
|
||||
|
||||
logger.Info("Removed route for remote subnet: %s", subnet)
|
||||
|
||||
@@ -115,7 +115,7 @@ func RemoveIPv4IncludedRoute(route IPv4Route) {
|
||||
if r == route {
|
||||
networkSettings.IPv4IncludedRoutes = append(routes[:i], routes[i+1:]...)
|
||||
logger.Info("Removed IPv4 included route: %+v", route)
|
||||
return
|
||||
break
|
||||
}
|
||||
}
|
||||
incrementor++
|
||||
|
||||
Reference in New Issue
Block a user