Notice: Due to size constraints and loading performance considerations, scripts referenced in blog posts are not attached directly. To request access, please complete the following form: Script Request Form Note: A Google account is required to access the form.
Disclaimer: I do not accept responsibility for any issues arising from scripts being run without adequate understanding. It is the user's responsibility to review and assess any code before execution. More information

Implementing Dialogue Box Network Blocking in iOS Apps

As mobile security becomes increasingly critical for enterprise applications, I recently explored whether it's possible to restrict iOS app usage to specific network locations. This blog post documents my journey creating a proof-of-concept app called "LockedApp" that validates corporate network connections before allowing access.

The Challenge

The requirement was straightforward: ensure that our internal iOS applications can only be used when employees are connected to the corporate network or VPN. Simply checking if a VPN client like Twingate is installed isn't sufficient—the app needs to verify that the VPN is actively routing traffic through corporate infrastructure.

The solution I developed checks the device's external IP address and validates it against predefined corporate IP ranges. If the device isn't routing through approved networks, the app blocks access with a clear error message.

Visual Results

These visuals assume you are using iOS 26 as that is what I have been testing with, First, let’s look at the error that happens if you’re not using the right VPN connection, if you click retry until you are using the correct details, the box will continue to reappear:


If you visit this from the correct IP address you no longer get the warning:

Creating the Test Application

I started by creating a new SwiftUI project in Xcode to test this concept. Here's how I built the foundation:

Step 1: Project Setup

First, I created a new iOS project in Xcode:

  • Product Name: LockedApp
  • Interface: SwiftUI
  • Language: Swift

Step 2: Building the Welcome Screen

I designed a professional welcome screen that would serve as the main interface. The app features A6N Networks branding with smooth animations and corporate styling.

The main app structure in LockedAppApp.swift:

@main
struct LockedAppApp: App {
    @UIApplicationDelegateAdaptor(AppDelegate.self) var delegate
    
    var body: some Scene {
        WindowGroup {
            ContentView()
                .preferredColorScheme(.dark)
        }
    }
}

The welcome screen includes animated elements, status indicators, and company branding, all wrapped in a ScrollViewto ensure compatibility across different device sizes.

Step 3: Implementing Network Validation

The core functionality resides in a dedicated CorporateNetworkValidator.swift file. This class handles the IP validation logic:

class CorporateNetworkValidator {
    private let corporateIPRanges = [
        "203.0.113",      // Example corporate range
        "198.51.100",     // Another corporate range
        "10.0.0",         // Internal corporate range
        "172.16"          // Additional corporate range
    ]
    
    func validateCorporateConnection() async -> Bool {
        guard let publicIP = await getPublicIPAddress() else {
            return false
        }
        
        return isIPInCorporateRange(ip: publicIP)
    }
}

The validator uses the ipify.org API to retrieve the device's external IP address:

private func getPublicIPAddress() async -> String? {
    do {
        let url = URL(string: "https://api.ipify.org")!
        let (data, _) = try await URLSession.shared.data(from: url)
        return String(data: data, encoding: .utf8)?.trimmingCharacters(in: .whitespacesAndNewlines)
    } catch {
        print("Failed to get IP address: \(error)")
        return nil
    }
}

Step 4: Integrating Access Control

The AppDelegate class orchestrates the network validation:

class AppDelegate: NSObject, UIApplicationDelegate {
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
        checkCorporateNetworkConnection()
        return true
    }
    
    func applicationDidBecomeActive(_ application: UIApplication) {
        checkCorporateNetworkConnection()
    }
    
    private func checkCorporateNetworkConnection() {
        Task {
            let validator = CorporateNetworkValidator()
            let isOnCorporateNetwork = await validator.validateCorporateConnection()
            
            await MainActor.run {
                if !isOnCorporateNetwork {
                    showCorporateConnectionError()
                }
            }
        }
    }
}

Configuration Requirements

The most critical aspect of implementation is correctly configuring your corporate IP ranges. To determine your organization's external IP addresses:

  1. Connect to your corporate network or VPN
  2. Visit https://api.ipify.org in a browser
  3. Note the displayed IP address
  4. Update the corporateIPRanges array with the appropriate prefixes

For example, if your corporate IP is 203.145.67.123, you would add "203.145.67" to the validation array.

Testing the Implementation

During testing, I verified several scenarios:

  • Corporate WiFi: App launches normally when connected to office network
  • Home WiFi: App blocks access and displays error message
  • Cellular Data: App blocks access unless corporate VPN is active
  • VPN Connection: App allows access when Twingate or corporate VPN routes traffic

The validation occurs both at app launch and when the app becomes active, ensuring continuous compliance.

Adding to Existing Applications

Once I validated the concept with LockedApp, I developed a method to integrate this functionality into existing iOS applications without disrupting current code.

For New Integration

Create the CorporateNetworkValidator.swift file in your existing project with the complete implementation:

import Foundation
import UIKit

class CorporateNetworkValidator {
    
    // REPLACE THESE WITH YOUR ACTUAL CORPORATE IP RANGES
    private let corporateIPRanges = [
        "203.0.113",      // Example: 203.0.113.x
        "198.51.100",     // Example: 198.51.100.x
        "10.0.0",         // Example: 10.0.0.x
        "172.16"          // Example: 172.16.x.x
    ]
    
    static func validateAndBlockIfNeeded() {
        let validator = CorporateNetworkValidator()
        Task {
            let isOnCorporateNetwork = await validator.validateCorporateConnection()
            
            await MainActor.run {
                if !isOnCorporateNetwork {
                    validator.showCorporateConnectionError()
                }
            }
        }
    }
    
    func validateCorporateConnection() async -> Bool {
        guard let publicIP = await getPublicIPAddress() else {
            return false
        }
        
        return isIPInCorporateRange(ip: publicIP)
    }
    
    private func getPublicIPAddress() async -> String? {
        do {
            let url = URL(string: "https://api.ipify.org")!
            let (data, _) = try await URLSession.shared.data(from: url)
            return String(data: data, encoding: .utf8)?.trimmingCharacters(in: .whitespacesAndNewlines)
        } catch {
            print("Failed to get IP address: \(error)")
            return nil
        }
    }
    
    private func isIPInCorporateRange(ip: String) -> Bool {
        for range in corporateIPRanges {
            if ip.hasPrefix(range) {
                return true
            }
        }
        return false
    }
    
    private func showCorporateConnectionError() {
        guard let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene,
              let window = windowScene.windows.first,
              let rootViewController = window.rootViewController else { return }
        
        let alert = UIAlertController(
            title: "Corporate Connection Required",
            message: "Unfortunately, you are not using your company's corporate connection. Please connect to the corporate VPN.",
            preferredStyle: .alert
        )
        
        alert.addAction(UIAlertAction(title: "Retry", style: .default) { _ in
            CorporateNetworkValidator.validateAndBlockIfNeeded()
        })
        
        alert.addAction(UIAlertAction(title: "Exit", style: .destructive) { _ in
            exit(0)
        })
        
        rootViewController.present(alert, animated: true)
    }
}

The validator includes a static method for easy integration and contains the complete IP validation logic. 

Remember to update the corporateIPRanges array with your actual corporate IP prefixes.

UIKit Integration

For existing UIKit applications, add these lines to your AppDelegate.swift:

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
    // Your existing code remains unchanged
    
    // Add this single line
    CorporateNetworkValidator.validateAndBlockIfNeeded()
    
    return true
}

func applicationDidBecomeActive(_ application: UIApplication) {
    // Your existing code remains unchanged
    
    // Add this single line
    CorporateNetworkValidator.validateAndBlockIfNeeded()
}

SwiftUI Integration

For SwiftUI applications, modify your main App struct:

@main
struct YourExistingApp: App {
    var body: some Scene {
        WindowGroup {
            YourExistingContentView()
                .onAppear {
                    CorporateNetworkValidator.validateAndBlockIfNeeded()
                }
                .onReceive(NotificationCenter.default.publisher(for: UIApplication.didBecomeActiveNotification)) { _ in
                    CorporateNetworkValidator.validateAndBlockIfNeeded()
                }
        }
    }
}

Security Considerations

While this approach provides effective access control for typical use cases, it's important to understand its limitations:

  • VPN Spoofing: Technically sophisticated users could potentially spoof IP addresses
  • Network Dependencies: The validation requires internet connectivity to function

For most enterprise scenarios, these limitations are acceptable given the significant security improvement this provides over unrestricted access.

Conclusion

The LockedApp project successfully demonstrated that iOS applications can effectively validate corporate network connections through external IP verification. This approach provides a practical security layer for enterprise applications while maintaining a smooth user experience for authorized users.

The implementation is straightforward to integrate into existing applications and requires minimal code changes. By validating network connectivity at both app launch and when returning from background, the solution ensures continuous compliance with corporate security policies.

Previous Post Next Post

نموذج الاتصال