Skip to content
Merged
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
16 changes: 16 additions & 0 deletions Multiplex/Models/ViewportReach.swift
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ enum ViewportReach: Equatable {
if host == "localhost" || host.hasSuffix(".localhost") { return true }
if host == "0.0.0.0" || host == "::" || host == "::1" { return true }
if let octets = ipv4Octets(host) { return octets[0] == 127 }
if let octets = ipv4MappedOctets(host) { return octets[0] == 127 }
return false
}

Expand All @@ -67,6 +68,13 @@ enum ViewportReach: Equatable {
if octets[0] == 169, octets[1] == 254 { return true }
return false
}
if let octets = ipv4MappedOctets(host) {
if octets[0] == 10 { return true }
if octets[0] == 192, octets[1] == 168 { return true }
if octets[0] == 172, (16...31).contains(octets[1]) { return true }
if octets[0] == 169, octets[1] == 254 { return true }
return false
}
// IPv6 unique-local (fc00::/7) and link-local (fe80::/10).
if host.hasPrefix("fc") || host.hasPrefix("fd") || host.hasPrefix("fe80:") {
return host.contains(":")
Expand All @@ -78,6 +86,14 @@ enum ViewportReach: Equatable {
return false
}

/// The IPv4 payload of the common `::ffff:w.x.y.z` mapped form, or nil.
private static func ipv4MappedOctets(_ host: String) -> [Int]? {
guard let separator = host.lastIndex(of: ":"),
host[..<separator] == "::ffff"
else { return nil }
return ipv4Octets(String(host[host.index(after: separator)...]))
}

/// The four octets of a dotted-quad IPv4 literal, or nil for anything
/// else (names, IPv6, malformed quads).
private static func ipv4Octets(_ host: String) -> [Int]? {
Expand Down
7 changes: 7 additions & 0 deletions MultiplexTests/ViewportReachTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,13 @@ final class ViewportReachTests: XCTestCase {
}
}

func testIPv4MappedPrivateAddressesKeepTheirIPv4Reach() {
XCTAssertEqual(classify("http://[::ffff:192.168.1.68]:5173/"), .lan)
XCTAssertEqual(classify("http://[::ffff:10.0.0.5]/"), .lan)
XCTAssertEqual(classify("http://[::ffff:127.0.0.1]:8080/"), .remoteLoopback)
XCTAssertEqual(classify("http://[::ffff:8.8.8.8]/"), .internet)
}

func testUnqualifiedSingleLabelIsLAN() {
// A bare machine name resolves through the local network's search
// domains — LAN by construction.
Expand Down
8 changes: 7 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,13 @@ Some features require Multiplex Pro; see [`docs/store-metadata.md`](docs/store-m

## Building

Requires Xcode with the visionOS SDK and [XcodeGen](https://github.com/yonaskolb/XcodeGen). The project is generated, so edit `project.yml`, not the `.xcodeproj`.
Requires Xcode with the visionOS SDK and [XcodeGen](https://github.com/yonaskolb/XcodeGen). Install the command-line prerequisites with [Homebrew](https://brew.sh/):

```sh
brew install xcodegen swiftlint
```

The Xcode project is generated, so edit `project.yml`, not the `.xcodeproj`. Regenerate it after project configuration changes:

```sh
xcodegen generate
Expand Down
Loading