Skip to content
Draft
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
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ class MainActivity: FlutterActivity() {
"stopSite" -> stopSite()

"active.listHostmap" -> activeListHostmap(call, result)
"active.listIndexes" -> activeListIndexes(call, result)
"active.listPendingHostmap" -> activeListPendingHostmap(call, result)
"active.getHostInfo" -> activeGetHostInfo(call, result)
"active.setRemoteForTunnel" -> activeSetRemoteForTunnel(call, result)
Expand Down Expand Up @@ -301,6 +302,26 @@ class MainActivity: FlutterActivity() {
outMessenger?.send(msg)
}

private fun activeListIndexes(call: MethodCall, result: MethodChannel.Result) {
val id = call.argument<String>("id")
if (id == "") {
return result.error("required_argument", "id is a required argument", null)
}

if (outMessenger == null || activeSiteId == null || activeSiteId != id) {
return result.success(null)
}

val msg = Message.obtain()
msg.what = NebulaVpnService.MSG_LIST_INDEXES
msg.replyTo = Messenger(object: Handler(Looper.getMainLooper()) {
override fun handleMessage(msg: Message) {
result.success(msg.data.getString("data"))
}
})
outMessenger?.send(msg)
}

private fun activeListPendingHostmap(call: MethodCall, result: MethodChannel.Result) {
val id = call.argument<String>("id")
if (id == "") {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ class NebulaVpnService : VpnService() {
const val MSG_UNREGISTER_CLIENT = 2
const val MSG_IS_RUNNING = 3
const val MSG_LIST_HOSTMAP = 4
const val MSG_LIST_INDEXES = 10
const val MSG_LIST_PENDING_HOSTMAP = 5
const val MSG_GET_HOSTINFO = 6
const val MSG_SET_REMOTE_FOR_TUNNEL = 7
Expand Down Expand Up @@ -92,27 +93,40 @@ class NebulaVpnService : VpnService() {
workManager!!.enqueue(workRequest)

// We don't actually start here. In order to properly capture boot errors we wait until an IPC connection is made

return super.onStartCommand(intent, flags, startId)
}

private fun startVpn() {
val ipNet: CIDR

try {
ipNet = mobileNebula.MobileNebula.parseCIDR(site!!.cert!!.cert.details.ips[0])
} catch (err: Exception) {
return announceExit(site!!.id, err.message ?: "$err")
}

val builder = Builder()
.addAddress(ipNet.ip, ipNet.maskSize.toInt())
.addRoute(ipNet.network, ipNet.maskSize.toInt())
.setMtu(site!!.mtu)
.setSession(TAG)
.allowFamily(OsConstants.AF_INET)
.allowFamily(OsConstants.AF_INET6)

try {
site!!.cert!!.cert.networks.forEach { network ->
val cidr = mobileNebula.MobileNebula.parseCIDR(network)
builder.addAddress(cidr.address, cidr.prefixLength.toInt())
builder.addRoute(cidr.maskedAddress, cidr.prefixLength.toInt())
}
} catch (err: Exception) {
Log.e(TAG, "Got an error setting up vpn networks $err")
announceExit(site!!.id, err.message)
return stopSelf()
}

// Add our unsafe routes
try {
site!!.unsafeRoutes.forEach { unsafeRoute ->
val unsafeCidr = mobileNebula.MobileNebula.parseCIDR(unsafeRoute.route)
builder.addRoute(unsafeCidr.maskedAddress, unsafeCidr.prefixLength.toInt())
}
} catch (err: Exception) {
Log.e(TAG, "Got an error setting up unsafe routes $err")
announceExit(site!!.id, err.message)
return stopSelf()
}

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
builder.setMetered(false)
}
Expand All @@ -129,12 +143,6 @@ class NebulaVpnService : VpnService() {
// RCS / Jibe
disallowApp(builder, "com.google.android.apps.messaging")

// Add our unsafe routes
site!!.unsafeRoutes.forEach { unsafeRoute ->
val unsafeIPNet = mobileNebula.MobileNebula.parseCIDR(unsafeRoute.route)
builder.addRoute(unsafeIPNet.network, unsafeIPNet.maskSize.toInt())
}

try {
vpnInterface = builder.establish()
nebula = mobileNebula.MobileNebula.newNebula(site!!.config, site!!.getKey(this), site!!.logFile, vpnInterface!!.detachFd().toLong())
Expand Down Expand Up @@ -214,7 +222,7 @@ class NebulaVpnService : VpnService() {
}

private fun registerReloadReceiver() {
ContextCompat.registerReceiver(this, reloadReceiver, IntentFilter(ACTION_RELOAD), RECEIVER_NOT_EXPORTED)
ContextCompat.registerReceiver(this, reloadReceiver, IntentFilter(ACTION_RELOAD), ContextCompat.RECEIVER_NOT_EXPORTED)
}

private fun unregisterReloadReceiver() {
Expand Down Expand Up @@ -285,6 +293,7 @@ class NebulaVpnService : VpnService() {
MSG_UNREGISTER_CLIENT -> mClients.remove(msg.replyTo)
MSG_IS_RUNNING -> isRunning()
MSG_LIST_HOSTMAP -> listHostmap(msg)
MSG_LIST_INDEXES -> listIndexes(msg)
MSG_LIST_PENDING_HOSTMAP -> listHostmap(msg)
MSG_GET_HOSTINFO -> getHostInfo(msg)
MSG_CLOSE_TUNNEL -> closeTunnel(msg)
Expand Down Expand Up @@ -322,6 +331,15 @@ class NebulaVpnService : VpnService() {
msg.replyTo.send(m)
}

private fun listIndexes(msg: Message) {
if (protect(msg)) { return }

val res = nebula!!.listIndexes(false)
val m = Message.obtain(null, msg.what)
m.data.putString("data", res)
msg.replyTo.send(m)
}

private fun getHostInfo(msg: Message) {
if (protect(msg)) { return }

Expand Down
20 changes: 9 additions & 11 deletions android/app/src/main/kotlin/net/defined/mobile_nebula/Sites.kt
Original file line number Diff line number Diff line change
Expand Up @@ -154,21 +154,19 @@ data class CertificateInfo(
)

data class Certificate(
val fingerprint: String,
val signature: String,
val details: CertificateDetails
)

data class CertificateDetails(
val version: Int,
val name: String,
val networks: List<String>,
val unsafeNetworks: List<String>,
val groups: List<String>,
val isCa: Boolean,
val notBefore: String,
val notAfter: String,
val issuer: String,
val publicKey: String,
val groups: List<String>,
val ips: List<String>,
val subnets: List<String>,
val isCa: Boolean,
val issuer: String
val curve: String,
val fingerprint: String,
val signature: String,
)

data class CertificateValidity(
Expand Down
112 changes: 90 additions & 22 deletions ios/NebulaNetworkExtension/PacketTunnelProvider.swift
Original file line number Diff line number Diff line change
Expand Up @@ -85,28 +85,14 @@ class PacketTunnelProvider: NEPacketTunnelProvider {
// This is set to 127.0.0.1 because it has to be something..
let tunnelNetworkSettings = NEPacketTunnelNetworkSettings(tunnelRemoteAddress: "127.0.0.1")

// Make sure our ip is routed to the tun device
var err: NSError?
let ipNet = MobileNebulaParseCIDR(_site.cert!.cert.details.ips[0], &err)
if err != nil {
throw err!
}
tunnelNetworkSettings.ipv4Settings = NEIPv4Settings(
addresses: [ipNet!.ip], subnetMasks: [ipNet!.maskCIDR])
var routes: [NEIPv4Route] = [
NEIPv4Route(destinationAddress: ipNet!.network, subnetMask: ipNet!.maskCIDR)
]

// Add our unsafe routes
try _site.unsafeRoutes.forEach { unsafeRoute in
let ipNet = MobileNebulaParseCIDR(unsafeRoute.route, &err)
if err != nil {
throw err!
}
routes.append(NEIPv4Route(destinationAddress: ipNet!.network, subnetMask: ipNet!.maskCIDR))
}

tunnelNetworkSettings.ipv4Settings!.includedRoutes = routes
// Set up all ipv4/6 networks and unsafe routes
let (v4Settings, v6Settings) = try getNetworkAddressesAndRoutes(
networks: _site.cert!.cert.networks,
unsafeRoutes: _site.unsafeRoutes
)

tunnelNetworkSettings.ipv4Settings = v4Settings
tunnelNetworkSettings.ipv6Settings = v6Settings
tunnelNetworkSettings.mtu = _site.mtu as NSNumber

try await self.setTunnelNetworkSettings(tunnelNetworkSettings)
Expand All @@ -124,6 +110,81 @@ class PacketTunnelProvider: NEPacketTunnelProvider {
self.dnUpdater.updateSingleLoop(site: self.site!, onUpdate: self.handleDNUpdate)
}

private func getNetworkAddressesAndRoutes(networks: [String], unsafeRoutes: [UnsafeRoute]) throws
-> (NEIPv4Settings, NEIPv6Settings)
{
var err: NSError?
var v4Addresses: [String] = []
var v4Netmasks: [String] = []
var v4Routes: [NEIPv4Route] = []

var v6Addresses: [String] = []
var v6PrefixLengths: [NSNumber] = []
var v6Routes: [NEIPv6Route] = []

for rawNetwork in networks {
let network = MobileNebulaParseCIDR(rawNetwork, &err)
if err != nil {
throw err!
}

if network!.ipLen == 4 {
v4Addresses.append(network!.address)
v4Netmasks.append(network!.subnetMask)
v4Routes.append(
NEIPv4Route(
destinationAddress: network!.maskedAddress,
subnetMask: network!.subnetMask
)
)
} else {
v6Addresses.append(network!.address)
v6PrefixLengths.append(network!.prefixLength as NSNumber)
v6Routes.append(
NEIPv6Route(
destinationAddress: network!.maskedAddress,
networkPrefixLength: network!.prefixLength as NSNumber
)
)
}
}

for unsafeRoute in unsafeRoutes {
let network = MobileNebulaParseCIDR(unsafeRoute.route, &err)
if err != nil {
throw err!
}

if network!.ipLen == 4 {
v4Addresses.append(network!.address)
v4Netmasks.append(network!.subnetMask)
v4Routes.append(
NEIPv4Route(
destinationAddress: network!.maskedAddress,
subnetMask: network!.subnetMask
)
)
} else {
v6Addresses.append(network!.address)
v6PrefixLengths.append(network!.prefixLength as NSNumber)
v6Routes.append(
NEIPv6Route(
destinationAddress: network!.maskedAddress,
networkPrefixLength: network!.prefixLength as NSNumber
)
)
}
}

let v4Settings = NEIPv4Settings(addresses: v4Addresses, subnetMasks: v4Netmasks)
v4Settings.includedRoutes = v4Routes

let v6Settings = NEIPv6Settings(addresses: v6Addresses, networkPrefixLengths: v6PrefixLengths)
v6Settings.includedRoutes = v6Routes

return (v4Settings, v6Settings)
}

private func handleDNUpdate(newSite: Site) {
do {
self.site = newSite
Expand Down Expand Up @@ -246,6 +307,7 @@ class PacketTunnelProvider: NEPacketTunnelProvider {
//TODO: try catch over all this
switch call.command {
case "listHostmap": (data, error) = listHostmap(pending: false)
case "listIndexes": (data, error) = listIndexes(pending: false)
case "listPendingHostmap": (data, error) = listHostmap(pending: true)
case "getHostInfo": (data, error) = getHostInfo(args: call.arguments!)
case "setRemoteForTunnel": (data, error) = setRemoteForTunnel(args: call.arguments!)
Expand All @@ -270,6 +332,12 @@ class PacketTunnelProvider: NEPacketTunnelProvider {
return (JSON(res), err)
}

private func listIndexes(pending: Bool) -> (JSON?, (any Error)?) {
var err: NSError?
let res = nebula!.listIndexes(pending, error: &err)
return (JSON(res), err)
}

private func getHostInfo(args: JSON) -> (JSON?, (any Error)?) {
var err: NSError?
let res = nebula!.getHostInfo(
Expand Down
39 changes: 17 additions & 22 deletions ios/NebulaNetworkExtension/Site.swift
Original file line number Diff line number Diff line change
Expand Up @@ -84,40 +84,35 @@ struct CertificateInfo: Codable {
}

struct Certificate: Codable {
var fingerprint: String
var signature: String
var details: CertificateDetails

/// An empty initializer to make error reporting easier
init() {
fingerprint = ""
signature = ""
details = CertificateDetails()
}
}

struct CertificateDetails: Codable {
var version: Int
var name: String
var notBefore: String
var notAfter: String
var publicKey: String
var networks: [String]
var unsafeNetworks: [String]
var groups: [String]
var ips: [String]
var subnets: [String]
var isCa: Bool
var notBefore: String
var notAfter: String
var issuer: String
var publicKey: String
var curve: String
var fingerprint: String
var signature: String

/// An empty initializer to make error reporting easier
init() {
version = 0
name = ""
networks = ["ERROR"]
unsafeNetworks = []
groups = []
notBefore = ""
notAfter = ""
issuer = ""
publicKey = ""
groups = []
ips = ["ERROR"]
subnets = []
curve = ""
isCa = false
issuer = ""
fingerprint = ""
signature = ""
}
}

Expand Down
2 changes: 1 addition & 1 deletion ios/Runner.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -288,7 +288,7 @@
attributes = {
BuildIndependentTargetsInParallel = YES;
LastSwiftUpdateCheck = 1140;
LastUpgradeCheck = 1600;
LastUpgradeCheck = 1510;
ORGANIZATIONNAME = "The Chromium Authors";
TargetAttributes = {
43AA89532444DA6500EDC39C = {
Expand Down
3 changes: 2 additions & 1 deletion ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1600"
LastUpgradeVersion = "1510"
version = "1.7">
<BuildAction
parallelizeBuildables = "YES"
Expand Down Expand Up @@ -66,6 +66,7 @@
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
enableGPUValidationMode = "1"
allowLocationSimulation = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
Expand Down
Loading
Loading