Swift Get IP address of current device in wifi and cellular - swift

func getIPAddress() -> String {
var address: String?
var ifaddr: UnsafeMutablePointer<ifaddrs>? = nil
if getifaddrs(&ifaddr) == 0 {
var ptr = ifaddr
while ptr != nil {
defer { ptr = ptr?.pointee.ifa_next }
let interface = ptr?.pointee
let addrFamily = interface?.ifa_addr.pointee.sa_family
if addrFamily == UInt8(AF_INET) || addrFamily == UInt8(AF_INET6) {
// wifi = ["en0"]
// wired = ["en2", "en3", "en4"]
// cellular = ["pdp_ip0","pdp_ip1","pdp_ip2","pdp_ip3"]
let name: String = String(cString: (interface!.ifa_name))
if name == "en0" || name == "en2" || name == "en3" || name == "en4" || name == "pdp_ip0" || name == "pdp_ip1" || name == "pdp_ip2" || name == "pdp_ip3" {
var hostname = [CChar](repeating: 0, count: Int(NI_MAXHOST))
getnameinfo(interface?.ifa_addr, socklen_t((interface?.ifa_addr.pointee.sa_len)!), &hostname, socklen_t(hostname.count), nil, socklen_t(0), NI_NUMERICHOST)
address = String(cString: hostname)
}
}
}
freeifaddrs(ifaddr)
}
return address ?? ""
}
I have use this one and run the program in iOS simulator its giving nil value. I have added the Bridging-Header file and #include in it.
for retrieve the value I have used
let stringIPAddress : String = self.getIPAddress()
can I know is that possible to get IP address with simulator

Code works for Swift 5+ and iOS 13+
To get IPAddress of device on turning Wifi or Wired or Mobile data ON, use below method :
func getIPAddress() -> String? {
var address : String?
// Get list of all interfaces on the local machine:
var ifaddr : UnsafeMutablePointer<ifaddrs>?
guard getifaddrs(&ifaddr) == 0 else { return nil }
guard let firstAddr = ifaddr else { return nil }
// For each interface ...
for ifptr in sequence(first: firstAddr, next: { $0.pointee.ifa_next }) {
let interface = ifptr.pointee
// Check for IPv4 or IPv6 interface:
let addrFamily = interface.ifa_addr.pointee.sa_family
if addrFamily == UInt8(AF_INET) || addrFamily == UInt8(AF_INET6) {
// Check interface name:
// wifi = ["en0"]
// wired = ["en2", "en3", "en4"]
// cellular = ["pdp_ip0","pdp_ip1","pdp_ip2","pdp_ip3"]
let name = String(cString: interface.ifa_name)
if name == "en0" || name == "en2" || name == "en3" || name == "en4" || name == "pdp_ip0" || name == "pdp_ip1" || name == "pdp_ip2" || name == "pdp_ip3" {
// Convert interface address to a human readable string:
var hostname = [CChar](repeating: 0, count: Int(NI_MAXHOST))
getnameinfo(interface.ifa_addr, socklen_t(interface.ifa_addr.pointee.sa_len),
&hostname, socklen_t(hostname.count),
nil, socklen_t(0), NI_NUMERICHOST)
address = String(cString: hostname)
}
}
}
freeifaddrs(ifaddr)
return address
}
Here, code/checks works for Wifi, Wired and Mobile data is:
if name == "en0" || name == "en2" || name == "en3" || name == "en4" || name == "pdp_ip0" || name == "pdp_ip1" || name == "pdp_ip2" || name == "pdp_ip3"
Hope will be helping! :)

I've been using this code, which has worked in simulator as well as playgrounds:
public class EnumerateNetworkInterfaces {
public struct NetworkInterfaceInfo {
let name: String
let ip: String
let netmask: String
}
public static func enumerate() -> [NetworkInterfaceInfo] {
var interfaces = [NetworkInterfaceInfo]()
// Get list of all interfaces on the local machine:
var ifaddr : UnsafeMutablePointer<ifaddrs>? = nil
if getifaddrs(&ifaddr) == 0 {
// For each interface ...
var ptr = ifaddr
while( ptr != nil) {
let flags = Int32(ptr!.pointee.ifa_flags)
var addr = ptr!.pointee.ifa_addr.pointee
// Check for running IPv4, IPv6 interfaces. Skip the loopback interface.
if (flags & (IFF_UP|IFF_RUNNING|IFF_LOOPBACK)) == (IFF_UP|IFF_RUNNING) {
if addr.sa_family == UInt8(AF_INET) || addr.sa_family == UInt8(AF_INET6) {
var mask = ptr!.pointee.ifa_netmask.pointee
// Convert interface address to a human readable string:
let zero = CChar(0)
var hostname = [CChar](repeating: zero, count: Int(NI_MAXHOST))
var netmask = [CChar](repeating: zero, count: Int(NI_MAXHOST))
if (getnameinfo(&addr, socklen_t(addr.sa_len), &hostname, socklen_t(hostname.count),
nil, socklen_t(0), NI_NUMERICHOST) == 0) {
let address = String(cString: hostname)
let name = ptr!.pointee.ifa_name!
let ifname = String(cString: name)
if (getnameinfo(&mask, socklen_t(mask.sa_len), &netmask, socklen_t(netmask.count),
nil, socklen_t(0), NI_NUMERICHOST) == 0) {
let netmaskIP = String(cString: netmask)
let info = NetworkInterfaceInfo(name: ifname,
ip: address,
netmask: netmaskIP)
interfaces.append(info)
}
}
}
}
ptr = ptr!.pointee.ifa_next
}
freeifaddrs(ifaddr)
}
return interfaces
}
}
And then you can do something like this:
for interface in EnumerateNetworkInterfaces.enumerate() {
print("\(interface.name): \(interface.ip)")
}

Related

Cocoa: How to get broadcast IP address in Swift?

Hi I am able to get local network IP address using this solution. I tried to use this solution to get broadcast IP address by using this Objective-C solution.
static func getBroadCastAddress() -> String? {
var address: String?
var ifaddr: UnsafeMutablePointer<ifaddrs>? = nil
if getifaddrs(&ifaddr) == 0 {
var ptr = ifaddr
while ptr != nil {
defer { ptr = ptr?.pointee.ifa_next }
guard let interface = ptr?.pointee else { return "" }
let addrFamily = interface.ifa_addr.pointee.sa_family
if addrFamily == UInt8(AF_INET) || addrFamily == UInt8(AF_INET6) {
let name: String = String(cString: (interface.ifa_name))
if name == "en0" || name == "en2" || name == "en3" || name == "en4" || name == "pdp_ip0" || name == "pdp_ip1" || name == "pdp_ip2" || name == "pdp_ip3" {
var hostname = [CChar](repeating: 0, count: Int(NI_MAXHOST))
getnameinfo(interface.ifa_addr, socklen_t((interface.ifa_addr.pointee.sa_len)), &hostname, socklen_t(hostname.count), nil, socklen_t(0), NI_NUMERICHOST)
// inet_ntoa(((struct sockaddr_in *)temp_addr->ifa_dstaddr)->sin_addr)
if let sinAddress = (interface.ifa_dstaddr as? sockaddr_in)?.sin_addr{ //=> It's always fail
address = String(utf8String: inet_ntoa(sinAddress))
}
}
}
}
freeifaddrs(ifaddr)
}
return address ?? ""
}
The problem is that I can't get sin_addr from interface like inet_ntoa(((struct sockaddr_in *)temp_addr->ifa_dstaddr)->sin_addr) in objective c code.
Can anyone help me to get broadcast IP address in Cocoa using Swift? Thank you for your time.
let acceptedInterfaces = ["en0", "en2", "en3", "en4", "pdp_ip0", "pdp_ip1", "pdp_ip2", "pdp_ip3"]
func getBroadCastAddress() {
var interfaceAddresses : [String : String] = [:]
var ifaddr: UnsafeMutablePointer<ifaddrs>? = nil
if getifaddrs(&ifaddr) == 0 {
defer { freeifaddrs(ifaddr) }
var currentInterface = ifaddr
while currentInterface != nil {
defer { currentInterface = currentInterface!.pointee.ifa_next }
let interface = currentInterface!.pointee
let addrFamily = interface.ifa_addr.pointee.sa_family
guard addrFamily == UInt8(AF_INET) || addrFamily == UInt8(AF_INET6) else { continue }
let interfaceName = String(cString: interface.ifa_name)
if acceptedInterfaces.contains(interfaceName) {
currentInterface!.withMemoryRebound(to: sockaddr_in.self, capacity: 1) {
sockaddr in
if let addressCString = inet_ntoa(sockaddr.pointee.sin_addr) {
interfaceAddresses[interfaceName] = String(cString: addressCString)
}
}
}
}
}
debugPrint(interfaceAddresses)
}
it prints:
["en0": "194.127.0.0"]

Get IP address of Apple Watch

How to access IP address of Apple Watch programatically? I have used UIDevice extension in iOS for finding IP. This is an extension of UIDevice but which is not supported in watchOS what could be the other option?
extension UIDevice {
private struct InterfaceNames {
static let wifi = ["en0"]
static let wired = ["en2", "en3", "en4"]
static let cellular = ["pdp_ip0","pdp_ip1","pdp_ip2","pdp_ip3"]
static let supported = wifi + wired + cellular
}
func ipAddress() -> String? {
var ipAddress: String?
var ifaddr: UnsafeMutablePointer<ifaddrs>?
if getifaddrs(&ifaddr) == 0 {
var pointer = ifaddr
while pointer != nil {
defer { pointer = pointer?.pointee.ifa_next }
guard
let interface = pointer?.pointee,
interface.ifa_addr.pointee.sa_family == UInt8(AF_INET) || interface.ifa_addr.pointee.sa_family == UInt8(AF_INET6),
let interfaceName = interface.ifa_name,
let interfaceNameFormatted = String(cString: interfaceName, encoding: .utf8),
InterfaceNames.supported.contains(interfaceNameFormatted)
else { continue }
var hostname = [CChar](repeating: 0, count: Int(NI_MAXHOST))
getnameinfo(interface.ifa_addr,
socklen_t(interface.ifa_addr.pointee.sa_len),
&hostname,
socklen_t(hostname.count),
nil,
socklen_t(0),
NI_NUMERICHOST)
guard
let formattedIpAddress = String(cString: hostname, encoding: .utf8),
!formattedIpAddress.isEmpty
else { continue }
ipAddress = formattedIpAddress
break
}
freeifaddrs(ifaddr)
}
return ipAddress
}
}
UIDevice.current.ipAddress()
How is this possible in watchOS

How to detect if the internet connection is over WiFi or Ethernet?

Is there a way to open network settings programmatically? Closest thing I know is opening the main settings page:
let settingsURL = NSURL(string: UIApplicationOpenSettingsURLString)!
UIApplication.sharedApplication().openURL(settingsURL)
I want to be able to detect if the internet connection is over WiFi or Ethernet.
The way to detect this is to look at the name of the network interfaces. For Mac and Apple TV, en0 and en1 refer to the wired and wireless interfaces respectively.
Add this to your bridging header (or create one if needed):
#include <ifaddrs.h>
#include <net/if_dl.h>
Then use this Swift code to get the information you need:
struct Networking {
enum NetworkInterfaceType: String, CustomStringConvertible {
case Ethernet = "en0"
case Wifi = "en1"
case Unknown = ""
var description: String {
switch self {
case .Ethernet:
return "Ethernet"
case .Wifi:
return "Wifi"
case .Unknown:
return "Unknown"
}
}
}
static var networkInterfaceType: NetworkInterfaceType {
if let name = Networking().getInterfaces().first?.name, let type = NetworkInterfaceType(rawValue: name) {
return type
}
return .Unknown
}
static var isConnectedByEthernet: Bool {
let networking = Networking()
for addr in networking.getInterfaces() {
if addr.name == NetworkInterfaceType.Ethernet.rawValue {
return true
}
}
return false
}
static var isConnectedByWiFi: Bool {
let networking = Networking()
for addr in networking.getInterfaces() {
if addr.name == NetworkInterfaceType.Wifi.rawValue {
return true
}
}
return false
}
// Credit to Martin R http://stackoverflow.com/a/34016247/600753 for this lovely code
// New Swift 3 implementation needed upated to replace unsafepointer calls with .withMemoryRebound
func getInterfaces() -> [(name : String, addr: String, mac : String)] {
var addresses = [(name : String, addr: String, mac : String)]()
var nameToMac = [ String: String ]()
// Get list of all interfaces on the local machine:
var ifaddr : UnsafeMutablePointer<ifaddrs>?
guard getifaddrs(&ifaddr) == 0 else { return [] }
guard let firstAddr = ifaddr else { return [] }
// For each interface ...
for ptr in sequence(first: firstAddr, next: { $0.pointee.ifa_next }) {
let flags = Int32(ptr.pointee.ifa_flags)
if var addr = ptr.pointee.ifa_addr {
let name = String(cString: ptr.pointee.ifa_name)
// Check for running IPv4, IPv6 interfaces. Skip the loopback interface.
if (flags & (IFF_UP|IFF_RUNNING|IFF_LOOPBACK)) == (IFF_UP|IFF_RUNNING) {
switch Int32(addr.pointee.sa_family) {
case AF_LINK:
nameToMac[name] = withUnsafePointer(to: &addr) { unsafeAddr in
unsafeAddr.withMemoryRebound(to: sockaddr_dl.self, capacity: 1) { dl in
dl.withMemoryRebound(to: Int8.self, capacity: 1) { dll in
let lladdr = UnsafeRawBufferPointer(start: dll + 8 + Int(dl.pointee.sdl_nlen), count: Int(dl.pointee.sdl_alen))
if lladdr.count == 6 {
return lladdr.map { String(format:"%02hhx", $0)}.joined(separator: ":")
} else {
return nil
}
}
}
}
case AF_INET, AF_INET6:
// Convert interface address to a human readable string:
var hostname = [CChar](repeating: 0, count: Int(NI_MAXHOST))
if (getnameinfo(addr, socklen_t(addr.pointee.sa_len),
&hostname, socklen_t(hostname.count),
nil, socklen_t(0), NI_NUMERICHOST) == 0) {
let address = String(cString: hostname)
addresses.append( (name: name, addr: address, mac : "") )
}
default:
break
}
}
}
}
freeifaddrs(ifaddr)
// Now add the mac address to the tuples:
for (i, addr) in addresses.enumerated() {
if let mac = nameToMac[addr.name] {
addresses[i] = (name: addr.name, addr: addr.addr, mac : mac)
}
}
return addresses
}
}
Usage is:
debugPrint(Networking.networkInterfaceType)
Or:
switch Networking.networkInterfaceType {
case .Ethernet:
// do something
break
case .Wifi:
// do something else
break
default:
break
}
For iOS 12.0+, tvOS 12.0+, macOS 10.14+ and watchOS 5.0+ apps you can use NWPathMonitor to solve the problem that you described in your question. Add this code to your application(_:didFinishLaunchingWithOptions:) implementation (Swift 5.1.3/Xcode 11.3.1):
let pathMonitor = NWPathMonitor()
pathMonitor.pathUpdateHandler = { path in
if path.status == .satisfied {
if path.usesInterfaceType(.wifi) {
print("wifi")
} else if path.usesInterfaceType(.cellular) {
print("cellular")
} else if path.usesInterfaceType(.wiredEthernet) {
print("wiredEthernet")
} else if path.usesInterfaceType(.loopback) {
print("loopback")
} else if path.usesInterfaceType(.other) {
print("other")
}
} else {
print("not connected")
}
}
pathMonitor.start(queue: .global(qos: .background))
And don't forget to add import Network to the top of the file.
You can use Reachability API.
let reachability: Reachability = Reachability.reachabilityForInternetConnection()
(reachability.currentReachabilityStatus().value == ReachableViaWiFi.value) // For WiFi
(reachability.currentReachabilityStatus().value == ReachableViaWWAN.value) // For WWAN
(reachability.currentReachabilityStatus().value == NotReachable.value) // For No Internet

How to check dictionary value is empty or not

i am new to swift and facing little issue and i not understanding how to check dictionary value.
func doValidate(data:Dictionary<String,AnyObject>,isEmail : String) -> Bool {
if(isEmail=="signup"){
if( data["last_name"] == nil || data["email"] == nil || data["password"] == nil || data["first_name"] == nil){
return false;
}
else{
return true;
}
}
}
Dictionary key is always constant and every time dictionary key exists but how i can check
value of data["last_name"] is empty or not?
if i used loop then its working but why single value not work?
for( myKey,myValue ) in data {
if(myValue as! String == ""){ // Work Perfect
return false;
}
}
For checking the value use objectForKey()
Here is modified code
func doValidate(data:Dictionary<String,AnyObject>,isEmail : String) -> Bool {
if(isEmail=="signup"){
if( data.objectForKey("last_name") == nil || data.objectForKey("email") == nil || data.objectForKey("password") == nil || data.objectForKey("first_name") == nil){
return false;
}
else{
return true;
}
}
}
You could consider the syntax introduced with Swift 1.2 inverting your if logic, obtaining something like this:
func doValidate(data:Dictionary<String,AnyObject>,isEmail : String) -> Bool {
if(isEmail == "signup"){
if let lastName = data["last_name"] as? String,
let email = data["email"] as? String,
let password = data["password"] as? String,
let firstName = data["first_name"] as? String
where
!lastName.isEmpty &&
!email.isEmpty &&
!password.isEmpty &&
!firstName.isEmpty {
return true
}
}
return false
}
Check length if you wanna check your string value. for example
func doValidate(data:Dictionary<String,AnyObject>,isEmail : String) -> Bool {
if(isEmail=="signup"){
if( data["last_name"]?.length == 0 || data["email"]?.length == 0 || data["password"]?.length == 0 || data["first_name"]?.length == 0){
return false;
}
else{
return true;
}
}
}

How can I get a real IP address from DNS query in Swift?

I want to get the IP address (like 192.168.0.1 or 87.12.56.50) from DNS query in Swift. I tried 100 times with 100 different methods ... Nothing helped me, so I'll have to ask for help.
This is my code so far:
let host = CFHostCreateWithName(nil,"subdomain.of.stackoverflow.com").takeUnretainedValue();
CFHostStartInfoResolution(host, .Addresses, nil);
var success: Boolean = 0;
let addresses = CFHostGetAddressing(host, &success).takeUnretainedValue() as NSArray;
if(addresses.count > 0){
let theAddress = addresses[0] as NSData;
println(theAddress);
}
OK ... These are the links for the code I tried to implement without success:
https://gist.github.com/mikeash/bca3a341db74221625f5
How to perform DNS query on iOS
Create an Array in Swift from an NSData Object
Does CFHostGetAddressing() support ipv6 DNS entries?
Do a simple DNS lookup in Swift
Your code retrieves the address as a "socket address" structure.
getnameinfo() can be used to convert the address into a numerical IP string
(code recycled from https://stackoverflow.com/a/25627545/1187415,
now updated to Swift 2):
let host = CFHostCreateWithName(nil,"www.google.com").takeRetainedValue()
CFHostStartInfoResolution(host, .Addresses, nil)
var success: DarwinBoolean = false
if let addresses = CFHostGetAddressing(host, &success)?.takeUnretainedValue() as NSArray?,
let theAddress = addresses.firstObject as? NSData {
var hostname = [CChar](count: Int(NI_MAXHOST), repeatedValue: 0)
if getnameinfo(UnsafePointer(theAddress.bytes), socklen_t(theAddress.length),
&hostname, socklen_t(hostname.count), nil, 0, NI_NUMERICHOST) == 0 {
if let numAddress = String.fromCString(hostname) {
print(numAddress)
}
}
}
Output (example): 173.194.112.147
Note also the usage of takeRetainedValue() in the first line, because
CFHostCreateWithName() has "Create" in its name the therefore returns a (+1) retained
object.
Update for Swift 3/Xcode 8:
let host = CFHostCreateWithName(nil,"www.google.com" as CFString).takeRetainedValue()
CFHostStartInfoResolution(host, .addresses, nil)
var success: DarwinBoolean = false
if let addresses = CFHostGetAddressing(host, &success)?.takeUnretainedValue() as NSArray?,
let theAddress = addresses.firstObject as? NSData {
var hostname = [CChar](repeating: 0, count: Int(NI_MAXHOST))
if getnameinfo(theAddress.bytes.assumingMemoryBound(to: sockaddr.self), socklen_t(theAddress.length),
&hostname, socklen_t(hostname.count), nil, 0, NI_NUMERICHOST) == 0 {
let numAddress = String(cString: hostname)
print(numAddress)
}
}
Or, to get all IP addresses for the host:
let host = CFHostCreateWithName(nil,"www.google.com" as CFString).takeRetainedValue()
CFHostStartInfoResolution(host, .addresses, nil)
var success: DarwinBoolean = false
if let addresses = CFHostGetAddressing(host, &success)?.takeUnretainedValue() as NSArray? {
for case let theAddress as NSData in addresses {
var hostname = [CChar](repeating: 0, count: Int(NI_MAXHOST))
if getnameinfo(theAddress.bytes.assumingMemoryBound(to: sockaddr.self), socklen_t(theAddress.length),
&hostname, socklen_t(hostname.count), nil, 0, NI_NUMERICHOST) == 0 {
let numAddress = String(cString: hostname)
print(numAddress)
}
}
}
Refer to the following Swift code to get DNS resolution for a website. One method uses CFHostStartInfoResolution whereas other one uses gethostbyname.
Both these APIs support all/multiple IP address resolution.
private func urlToIP_cfHostResolution(_ url: String) -> [String] {
var ipList: [String] = []
let host = CFHostCreateWithName(nil,url as CFString).takeRetainedValue()
CFHostStartInfoResolution(host, .addresses, nil)
var success: DarwinBoolean = false
if let addresses = CFHostGetAddressing(host, &success)?.takeUnretainedValue() as NSArray? {
for case let theAddress as NSData in addresses {
var hostname = [CChar](repeating: 0, count: Int(NI_MAXHOST))
if getnameinfo(theAddress.bytes.assumingMemoryBound(to: sockaddr.self), socklen_t(theAddress.length),
&hostname, socklen_t(hostname.count), nil, 0, NI_NUMERICHOST) == 0 {
ipList.append(String(cString: hostname))
}
}
}
return ipList
}
This method returns ["151.101.129.69", "151.101.1.69", "151.101.193.69", "151.101.65.69"] for www.stackoverflow.com
private func urlToIP_gethostbyname(_ url: URL) -> [String] {
var ipList: [String] = []
guard let hostname = url.host else {
return ipList
}
guard let host = hostname.withCString({gethostbyname($0)}) else {
return ipList
}
guard host.pointee.h_length > 0 else {
return ipList
}
var index = 0
while host.pointee.h_addr_list[index] != nil {
var addr: in_addr = in_addr()
memcpy(&addr.s_addr, host.pointee.h_addr_list[index], Int(host.pointee.h_length))
guard let remoteIPAsC = inet_ntoa(addr) else {
return ipList
}
ipList.append(String.init(cString: remoteIPAsC))
index += 1
}
return ipList
}
This method also returns ["151.101.129.69", "151.101.1.69", "151.101.193.69", "151.101.65.69"] for www.stackoverflow.com
Hope this helps.
A number of the answers are using the deprecated bytes to retrieve the sockaddr to supply to getnameinfo. We’d use address.withUnsafeBytes now. For example, in Swift 5:
/// Returns the string representation of the supplied address.
///
/// - parameter address: Contains a `(struct sockaddr)` with the address to render.
///
/// - returns: A string representation of that address.
func stringRepresentation(forAddress address: Data) -> String? {
address.withUnsafeBytes { pointer in
var hostStr = [Int8](repeating: 0, count: Int(NI_MAXHOST))
let result = getnameinfo(
pointer.baseAddress?.assumingMemoryBound(to: sockaddr.self),
socklen_t(address.count),
&hostStr,
socklen_t(hostStr.count),
nil,
0,
NI_NUMERICHOST
)
guard result == 0 else { return nil }
return String(cString: hostStr)
}
}