Skip to content

Commit 092c7a6

Browse files
Steve TreaseSteve Trease
authored andcommitted
Startup
1 parent 328c88e commit 092c7a6

File tree

3 files changed

+248
-3
lines changed

3 files changed

+248
-3
lines changed

IP Address.xcodeproj/project.pbxproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
AAE235251F91223400FB8E69 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = AAE235231F91223400FB8E69 /* Main.storyboard */; };
1313
AAE235271F91223400FB8E69 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = AAE235261F91223400FB8E69 /* Assets.xcassets */; };
1414
AAE2352A1F91223400FB8E69 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = AAE235281F91223400FB8E69 /* LaunchScreen.storyboard */; };
15+
AAE235341F91254800FB8E69 /* Interface.swift in Sources */ = {isa = PBXBuildFile; fileRef = AAE235331F91254800FB8E69 /* Interface.swift */; };
1516
/* End PBXBuildFile section */
1617

1718
/* Begin PBXFileReference section */
@@ -22,6 +23,7 @@
2223
AAE235261F91223400FB8E69 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
2324
AAE235291F91223400FB8E69 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
2425
AAE2352B1F91223400FB8E69 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
26+
AAE235331F91254800FB8E69 /* Interface.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Interface.swift; sourceTree = "<group>"; };
2527
/* End PBXFileReference section */
2628

2729
/* Begin PBXFrameworksBuildPhase section */
@@ -56,6 +58,7 @@
5658
children = (
5759
AAE2351F1F91223400FB8E69 /* AppDelegate.swift */,
5860
AAE235211F91223400FB8E69 /* ViewController.swift */,
61+
AAE235331F91254800FB8E69 /* Interface.swift */,
5962
AAE235231F91223400FB8E69 /* Main.storyboard */,
6063
AAE235261F91223400FB8E69 /* Assets.xcassets */,
6164
AAE235281F91223400FB8E69 /* LaunchScreen.storyboard */,
@@ -138,6 +141,7 @@
138141
files = (
139142
AAE235221F91223400FB8E69 /* ViewController.swift in Sources */,
140143
AAE235201F91223400FB8E69 /* AppDelegate.swift in Sources */,
144+
AAE235341F91254800FB8E69 /* Interface.swift in Sources */,
141145
);
142146
runOnlyForDeploymentPostprocessing = 0;
143147
};

IP Address/Interface.swift

Lines changed: 235 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,235 @@
1+
//
2+
// Interface.swift
3+
// IP Address
4+
//
5+
// https://github.com/svdo/swift-netutils/blob/master/NetUtils/Interface.swift
6+
//
7+
// Copyright (c) 2015 Stefan van den Oord. All rights reserved.
8+
9+
import Foundation
10+
#if swift(>=3.2)
11+
import Darwin
12+
#else
13+
import ifaddrs
14+
#endif
15+
16+
/**
17+
* This class represents a network interface in your system. For example, `en0` with a certain IP address.
18+
* It is a wrapper around the `getifaddrs` system call.
19+
*
20+
* Typical use of this class is to first call `Interface.allInterfaces()` and then use the properties of the interface(s) that you need.
21+
*
22+
* - See: `/usr/include/ifaddrs.h`
23+
*/
24+
public class Interface : CustomStringConvertible, CustomDebugStringConvertible {
25+
26+
/// The network interface family (IPv4 or IPv6).
27+
public enum Family : Int {
28+
/// IPv4.
29+
case ipv4
30+
31+
/// IPv6.
32+
case ipv6
33+
34+
/// Used in case of errors.
35+
case other
36+
37+
/// String representation of the address family.
38+
public func toString() -> String {
39+
switch (self) {
40+
case .ipv4: return "IPv4"
41+
case .ipv6: return "IPv6"
42+
default: return "other"
43+
}
44+
}
45+
}
46+
47+
/**
48+
* Returns all network interfaces in your system. If you have an interface name (e.g. `en0`) that has
49+
* multiple IP addresses (e.g. one IPv4 address and a few IPv6 addresses), then they will be returned
50+
* as separate instances of Interface.
51+
* - Returns: An array containing all network interfaces in your system.
52+
*/
53+
open static func allInterfaces() -> [Interface] {
54+
var interfaces : [Interface] = []
55+
56+
var ifaddrsPtr : UnsafeMutablePointer<ifaddrs>? = nil
57+
if getifaddrs(&ifaddrsPtr) == 0 {
58+
var ifaddrPtr = ifaddrsPtr
59+
while ifaddrPtr != nil {
60+
let addr = ifaddrPtr?.pointee.ifa_addr.pointee
61+
if addr?.sa_family == UInt8(AF_INET) || addr?.sa_family == UInt8(AF_INET6) {
62+
interfaces.append(Interface(data: (ifaddrPtr?.pointee)!))
63+
}
64+
ifaddrPtr = ifaddrPtr?.pointee.ifa_next
65+
}
66+
freeifaddrs(ifaddrsPtr)
67+
}
68+
69+
return interfaces
70+
}
71+
72+
/**
73+
* Returns a new Interface instance that does not represent a real network interface, but can be used for (unit) testing.
74+
* - Returns: An instance of Interface that does *not* represent a real network interface.
75+
*/
76+
open static func createTestDummy(_ name:String, family:Family, address:String, multicastSupported:Bool, broadcastAddress:String?) -> Interface
77+
{
78+
return Interface(name: name, family: family, address: address, netmask: nil, running: true, up: true, loopback: false, multicastSupported: multicastSupported, broadcastAddress: broadcastAddress)
79+
}
80+
81+
/**
82+
* Initialize a new Interface with the given properties.
83+
*/
84+
public init(name:String, family:Family, address:String?, netmask:String?, running:Bool, up:Bool, loopback:Bool, multicastSupported:Bool, broadcastAddress:String?) {
85+
self.name = name
86+
self.family = family
87+
self.address = address
88+
self.netmask = netmask
89+
self.running = running
90+
self.up = up
91+
self.loopback = loopback
92+
self.multicastSupported = multicastSupported
93+
self.broadcastAddress = broadcastAddress
94+
}
95+
96+
convenience init(data:ifaddrs) {
97+
let flags = Int32(data.ifa_flags)
98+
let broadcastValid : Bool = ((flags & IFF_BROADCAST) == IFF_BROADCAST)
99+
self.init(name: String(cString: data.ifa_name),
100+
family: Interface.extractFamily(data),
101+
address: Interface.extractAddress(data.ifa_addr.pointee),
102+
netmask: Interface.extractAddress(data.ifa_netmask.pointee),
103+
running: ((flags & IFF_RUNNING) == IFF_RUNNING),
104+
up: ((flags & IFF_UP) == IFF_UP),
105+
loopback: ((flags & IFF_LOOPBACK) == IFF_LOOPBACK),
106+
multicastSupported: ((flags & IFF_MULTICAST) == IFF_MULTICAST),
107+
broadcastAddress: ((broadcastValid && data.ifa_dstaddr != nil) ? Interface.extractAddress(data.ifa_dstaddr.pointee) : nil))
108+
}
109+
110+
fileprivate static func extractFamily(_ data:ifaddrs) -> Family {
111+
var family : Family = .other
112+
let addr = data.ifa_addr.pointee
113+
if addr.sa_family == UInt8(AF_INET) {
114+
family = .ipv4
115+
}
116+
else if addr.sa_family == UInt8(AF_INET6) {
117+
family = .ipv6
118+
}
119+
else {
120+
family = .other
121+
}
122+
return family
123+
}
124+
125+
fileprivate static func extractAddress(_ address:sockaddr) -> String? {
126+
if (address.sa_family == sa_family_t(AF_INET)) {
127+
return extractAddress_ipv4(address)
128+
}
129+
else if (address.sa_family == sa_family_t(AF_INET6)) {
130+
return extractAddress_ipv6(address)
131+
}
132+
else {
133+
return nil
134+
}
135+
}
136+
137+
fileprivate static func extractAddress_ipv4(_ address:sockaddr) -> String? {
138+
var addr = address
139+
var address : String? = nil
140+
var hostname = [CChar](repeating: 0, count: Int(2049))
141+
if (getnameinfo(&addr, socklen_t(addr.sa_len), &hostname,
142+
socklen_t(hostname.count), nil, socklen_t(0), NI_NUMERICHOST) == 0) {
143+
address = String(cString: hostname)
144+
}
145+
else {
146+
// var error = String.fromCString(gai_strerror(errno))!
147+
// println("ERROR: \(error)")
148+
}
149+
return address
150+
}
151+
152+
fileprivate static func extractAddress_ipv6(_ address:sockaddr) -> String? {
153+
var addr = address
154+
var ip : [Int8] = [Int8](repeating: Int8(0), count: Int(INET6_ADDRSTRLEN))
155+
return inetNtoP(&addr, ip: &ip)
156+
}
157+
158+
fileprivate static func inetNtoP(_ addr:UnsafeMutablePointer<sockaddr>, ip:UnsafeMutablePointer<Int8>) -> String? {
159+
return addr.withMemoryRebound(to: sockaddr_in6.self, capacity: 1) { (addr6) -> String? in
160+
let conversion:UnsafePointer<CChar> = inet_ntop(AF_INET6, &addr6.pointee.sin6_addr, ip, socklen_t(INET6_ADDRSTRLEN))
161+
return String(cString: conversion)
162+
}
163+
}
164+
165+
/**
166+
* Creates the network format representation of the interface's IP address. Wraps `inet_pton`.
167+
*/
168+
open var addressBytes: [UInt8]? {
169+
guard let addr = address else { return nil }
170+
171+
let af:Int32
172+
let len:Int
173+
switch family {
174+
case .ipv4:
175+
af = AF_INET
176+
len = 4
177+
case .ipv6:
178+
af = AF_INET6
179+
len = 16
180+
default:
181+
return nil
182+
}
183+
var bytes = [UInt8](repeating: 0, count: len)
184+
let result = inet_pton(af, addr, &bytes)
185+
return ( result == 1 ) ? bytes : nil
186+
}
187+
188+
/// `IFF_RUNNING` flag of `ifaddrs->ifa_flags`.
189+
open var isRunning: Bool { return running }
190+
191+
/// `IFF_UP` flag of `ifaddrs->ifa_flags`.
192+
open var isUp: Bool { return up }
193+
194+
/// `IFF_LOOPBACK` flag of `ifaddrs->ifa_flags`.
195+
open var isLoopback: Bool { return loopback }
196+
197+
/// `IFF_MULTICAST` flag of `ifaddrs->ifa_flags`.
198+
open var supportsMulticast: Bool { return multicastSupported }
199+
200+
/// Field `ifaddrs->ifa_name`.
201+
open let name : String
202+
203+
/// Field `ifaddrs->ifa_addr->sa_family`.
204+
open let family : Family
205+
206+
/// Extracted from `ifaddrs->ifa_addr`, supports both IPv4 and IPv6.
207+
open let address : String?
208+
209+
/// Extracted from `ifaddrs->ifa_netmask`, supports both IPv4 and IPv6.
210+
open let netmask : String?
211+
212+
/// Extracted from `ifaddrs->ifa_dstaddr`. Not applicable for IPv6.
213+
open let broadcastAddress : String?
214+
215+
fileprivate let running : Bool
216+
fileprivate let up : Bool
217+
fileprivate let loopback : Bool
218+
fileprivate let multicastSupported : Bool
219+
220+
/// Returns the interface name.
221+
open var description: String { return name }
222+
223+
/// Returns a string containing a few properties of the Interface.
224+
open var debugDescription: String {
225+
var s = "Interface name:\(name) family:\(family)"
226+
if let ip = address {
227+
s += " ip:\(ip)"
228+
}
229+
s += isUp ? " (up)" : " (down)"
230+
s += isRunning ? " (running)" : "(not running)"
231+
return s
232+
}
233+
}
234+
235+

IP Address/ViewController.swift

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,18 +8,24 @@
88

99
import UIKit
1010

11+
1112
class ViewController: UIViewController {
1213

1314
override func viewDidLoad() {
1415
super.viewDidLoad()
16+
17+
let interfaces = Interface.allInterfaces()
18+
print (interfaces.count)
19+
20+
for interface in interfaces {
21+
print (interface.description, interface.address)
22+
}
23+
1524
// Do any additional setup after loading the view, typically from a nib.
1625
}
1726

1827
override func didReceiveMemoryWarning() {
1928
super.didReceiveMemoryWarning()
2029
// Dispose of any resources that can be recreated.
2130
}
22-
23-
2431
}
25-

0 commit comments

Comments
 (0)