How to get Ip address in swift
As it turned out in the discussion, OP needs the interface address on a Mac and not on an iOS device as I thought initially. The code referenced in the question checks for the
interface name "en0", which is the WiFi interface on the iPhone. On a Mac it makes more
sense to check for any "up-and-running" interface instead.
Therefore I have rewritten the answer. It is now a Swift translation of the code in
Detect any connected network.
getifaddrs()
is defined in <ifaddrs.h>
, which is not included by default.
Therefore you have to create a bridging header and add
#include <ifaddrs.h>
The following function returns
an array with the names of all local "up-and-running" network interfaces.
func getIFAddresses() -> [String] {
var addresses = [String]()
// 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 {
defer { ptr = ptr.memory.ifa_next }
let flags = Int32(ptr.memory.ifa_flags)
let addr = ptr.memory.ifa_addr.memory
// 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) {
// Convert interface address to a human readable string:
var hostname = [CChar](count: Int(NI_MAXHOST), repeatedValue: 0)
if (getnameinfo(ptr.memory.ifa_addr, socklen_t(addr.sa_len), &hostname, socklen_t(hostname.count),
nil, socklen_t(0), NI_NUMERICHOST) == 0) {
if let address = String.fromCString(hostname) {
addresses.append(address)
}
}
}
}
}
freeifaddrs(ifaddr)
}
return addresses
}
Update for Swift 3: In addition to adopting the code to the
many changes in Swift 3,
iterating over all interfaces can now use the new generalizedsequence()
function:
func getIFAddresses() -> [String] {
var addresses = [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)
let 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) {
// Convert interface address to a human readable string:
var hostname = [CChar](repeating: 0, count: Int(NI_MAXHOST))
if (getnameinfo(ptr.pointee.ifa_addr, socklen_t(addr.sa_len), &hostname, socklen_t(hostname.count),
nil, socklen_t(0), NI_NUMERICHOST) == 0) {
let address = String(cString: hostname)
addresses.append(address)
}
}
}
}
freeifaddrs(ifaddr)
return addresses
}
Swift obtaining ip address from socket returns weird value
The main error is that inet_ntop()
takes the address of a struct in_addr
(or struct in_addr6
for IPv6), and not the address of a struct sockaddr
.
Another error is that the length argument to getpeername()
must be the length of
the passed socket address structure, you are passing the length of an Int32
.
Your current code passes AF_INET
to inet_ntop()
and is therefore limited
to IPv4 addresses. If that is sufficient for you, the following should work:
var addr = UnsafeMutablePointer<sockaddr_in>.alloc(1)
var len = socklen_t(sizeofValue(addr.memory))
if getpeername(sockfd, UnsafeMutablePointer(addr), &len) != -1 {
var ipAddressString = [CChar](count:Int(INET_ADDRSTRLEN), repeatedValue: 0)
inet_ntop(
AF_INET ,
&addr.memory.sin_addr, // <-- main difference here
&ipAddressString,
socklen_t(INET_ADDRSTRLEN))
println("socket \(sockfd) ip \(String.fromCString(ipAddressString)!)")
}
addr.dealloc(1)
Allocating the socket address structure makes casting between the different pointer
types a bit easier. I have also replaced the variable name socket
by sockfd
to
avoid confusion with the socket()
function.
The more "modern" function to convert socket addresses to strings isgetnameinfo()
. The following code demonstrates how to use it. It works for
both IPv4 and IPv6 addresses:
var addr = UnsafeMutablePointer<sockaddr_storage>.alloc(1)
var len = socklen_t(sizeofValue(addr.memory))
if getpeername(sockfd, UnsafeMutablePointer(addr), &len) != -1 {
var hostBuffer = [CChar](count: Int(NI_MAXHOST), repeatedValue: 0)
if (getnameinfo(UnsafeMutablePointer(addr), socklen_t(addr.memory.ss_len),
&hostBuffer, socklen_t(hostBuffer.count), nil, 0,
NI_NUMERICHOST) == 0) {
let host = String.fromCString(hostBuffer)!
println("socket \(sockfd) ip \(host)")
}
}
addr.dealloc(1)
Swift 2 update: First method:
var addr = sockaddr_in()
var len = socklen_t(sizeofValue(addr))
withUnsafeMutablePointer(&addr) {
if getpeername(sockfd, UnsafeMutablePointer($0), &len) != -1 {
var ipAddressString = [CChar](count:Int(INET_ADDRSTRLEN), repeatedValue: 0)
inet_ntop(
AF_INET ,
&addr.sin_addr, // <-- main difference here
&ipAddressString,
socklen_t(INET_ADDRSTRLEN))
print("socket \(sockfd) ip \(String.fromCString(ipAddressString)!)")
}
}
Second method:
var addr = sockaddr_storage()
var len = socklen_t(sizeofValue(addr))
withUnsafeMutablePointer(&addr) {
if getpeername(sockfd, UnsafeMutablePointer($0), &len) != -1 {
var hostBuffer = [CChar](count: Int(NI_MAXHOST), repeatedValue: 0)
if (getnameinfo(UnsafeMutablePointer($0), socklen_t(addr.ss_len),
&hostBuffer, socklen_t(hostBuffer.count), nil, 0,
NI_NUMERICHOST) == 0) {
let host = String.fromCString(hostBuffer)!
print("socket \(sockfd) ip \(host)")
}
}
}
Getting an IP address and port number from a sockaddr_in struct in Swift?
If you need the IP address and port as numbers then you can
access the corresponding fields of a sockaddr_in
directly, but
remember to convert the values from network byte (big endian) to host
byte order:
let saddr: sockAddr = ...
let port = in_port_t(bigEndian: sockAddr.sin_port)
let addr = in_addr_t(bigEndian: sockAddr.sin_addr.s_addr)
getnameinfo()
can be used to extract the IP address as a string
(in dotted-decimal notation), and optionally the port as well.
Casting a struct sockaddr_in
pointer to a struct sockaddr
pointer
is called "rebinding" in Swift, and done with withMemoryRebound()
:
var sockAddr: sockaddr_in = ...
var hostname = [CChar](repeating: 0, count: Int(NI_MAXHOST))
var service = [CChar](repeating: 0, count: Int(NI_MAXSERV))
withUnsafePointer(to: &sockAddr) {
$0.withMemoryRebound(to: sockaddr.self, capacity: 0) {
_ = getnameinfo($0, socklen_t($0.pointee.sa_len),
&hostname, socklen_t(hostname.count),
&service, socklen_t(service.count),
NI_NUMERICHOST | NI_NUMERICSERV)
}
}
print("addr:", hostname)
print("port:", service)
This works for both IPv4 and IPv6 socket address structures (sockaddr_in
and sockaddr_in6
).
For more information about "unsafe pointer conversions", see
SE-0107 UnsafeRawPointer API
and UnsafeRawPointer Migration. The latter page contains example code how to handle
socket addresses in Swift 3.
Related Topics
I Opened My App in Xcode 10 and Now I Have Errors in 9.4.1: Sdkapplicationdelegate (Facebookcore)
Dynamically Set Properties from Dictionary<String, Any> in Swift
Using Nsdate to Get Date for Easter
Appdelegate#Applicationdidfinishlaunching Not Called for Swift 4 Macos App Built from Command Line
Wrong Image Orientation After Displaytransform Call
On Demand Resources "0 Asset Packs"
Swift: Get The Compile Time Name of Variable (Referencing to a Class)
Using Font Awesome Dynamically in Swift
Update Widget When Appearance Changes
Swiftui App Crashes Every Time When Trying to Add Item to Grouped Items
Saving And/Or Querying User Display Names in Firebase Using Caseinsensitive
What Do Detached and Assigncurrentcontext Meaning
Print Not Working in Swift 3 Extensions
Stripe API Response: The Data Couldn't Be Read Because It Isn't in The Correct Format
Root Class of All Classes in Swift
Actions Assigned to Nsmenuitem Dont Seem to Work
How to Display an Alert Controller When Nsdate == to a Time (For Example 12:00 Am) in Swift
Using Scenekit for Hittesting Not Returning a Hit with Scnnode