Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WireGuard Tunnel: Ensure AllowedIPs doesn't overlap with 0.0.0.0/8 #516

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
- Avoid using cached token endpoints from OIDAuthState #487
- macOS: Point the user to the OS' please-enable-notification prompt #474
- Improve error alerts #489
- Fixes excluded routes usage with WireGuard #475

## 3.0.6

Expand Down
84 changes: 83 additions & 1 deletion TunnelExtension/WireGuard/WireGuardAdapterInterface.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ class WireGuardAdapterInterface: TunnelAdapterInterface {
}

init(configuration: WireGuardKit.TunnelConfiguration, logger: Logger) {
self.configuration = configuration
self.configuration = configuration.badAllowedIPsRemoved(logger: logger)
self.logger = logger
}

Expand Down Expand Up @@ -72,3 +72,85 @@ class WireGuardAdapterInterface: TunnelAdapterInterface {
return configuration.interface.addresses.map { "\($0.address)" }
}
}

private extension TunnelConfiguration {

// badAllowedIPsRemoved():
// When an IPv4 address in AllowedIPs overlaps with 0.0.0.0/8, the tunnel doesn't work.
// Not sure why. As a workaround, we replace those IPs such that there's no such overlap.
// It's anyway not valid to have a source / destination address in 0.0.0.0/8, so we
// exclude that range.
// For example, "0.0.0.0/6" shall be replaced with ["2.0.0.0/7", "1.0.0.0/8"].

func badAllowedIPsRemoved(logger: Logger) -> TunnelConfiguration {
guard hasBadAllowedIPs() else {
return self
}

let replacementIPv4AddressRanges = [
IPAddressRange(from: "64.0.0.0/2"), // 01XXXXXX.X.X.X
IPAddressRange(from: "32.0.0.0/3"), // 001XXXXX.X.X.X
IPAddressRange(from: "16.0.0.0/4"), // 0001XXXX.X.X.X
IPAddressRange(from: "8.0.0.0/5"), // 00001XXX.X.X.X
IPAddressRange(from: "4.0.0.0/6"), // 000001XX.X.X.X
IPAddressRange(from: "2.0.0.0/7"), // 0000001X.X.X.X
IPAddressRange(from: "1.0.0.0/8") // 00000001.X.X.X
]

let peers: [PeerConfiguration] = self.peers.map { originalPeer in
var allowedIPs: [IPAddressRange] = []
for ipAddressRange in originalPeer.allowedIPs {
if let ipv4Address = ipAddressRange.address as? IPv4Address {
if ipv4Address == Self.allZeroIPv4Address &&
ipAddressRange.networkPrefixLength > 0 {

if ipAddressRange.networkPrefixLength < 8 {
let index = Int(ipAddressRange.networkPrefixLength - 1)
replacementIPv4AddressRanges[index...].forEach { replacementAddressRange in
if let replacementAddressRange = replacementAddressRange {
allowedIPs.append(replacementAddressRange)
}
}
} else {
// We ignore IPv4 ranges that are 0.0.0.0/N, where N >= 8
// because they cannot be valid source or destination addresses
}

} else {
allowedIPs.append(ipAddressRange)
}
} else {
allowedIPs.append(ipAddressRange)
}
}

logger.log("Original AllowedIPs was: \(originalPeer.allowedIPs.map { $0.stringRepresentation }.joined(separator: ", "))")
logger.log("Rewriting AllowedIPs as: \(allowedIPs.map { $0.stringRepresentation }.joined(separator: ", "))")

var peer = PeerConfiguration(publicKey: originalPeer.publicKey)
peer.preSharedKey = originalPeer.preSharedKey
peer.allowedIPs = allowedIPs
peer.endpoint = originalPeer.endpoint
peer.persistentKeepAlive = originalPeer.persistentKeepAlive
return peer
}

return TunnelConfiguration(name: self.name, interface: self.interface, peers: peers)
}

static let allZeroIPv4Address = IPv4Address("0.0.0.0")

func hasBadAllowedIPs() -> Bool {
for peer in peers {
for ipAddressRange in peer.allowedIPs {
if let ipv4Address = ipAddressRange.address as? IPv4Address {
if ipv4Address == Self.allZeroIPv4Address &&
ipAddressRange.networkPrefixLength > 0 {
return true
}
}
}
}
return false
}
}