How to use swift convert string to ipv6 addr - swift

I have a ipv6 string,how to use Swift convert to in6_addr
let ipString = "2001:0b28:f23f:f005:0000:0000:0000:000a"

You can use inet_pton()
similarly as you would in a C program:
let ipString = "2001:0b28:f23f:f005:0000:0000:0000:000a"
var addr = in6_addr()
let retval = withUnsafeMutablePointer(&addr) {
inet_pton(AF_INET6, ipString, UnsafeMutablePointer($0))
}
if retval == 0 {
print("Invalid address")
} else if retval == -1 {
print("Failed:", String.fromCString(strerror(errno)) ?? "\(errno)")
// For Swift 3, replace the last line by
// print("Failed:", String(cString: strerror(errno)))
} else {
// Success, `addr` contains the result.
}
withUnsafeMutablePointer() is necessary to pass the address of
the addr variable to inet_pton().

Swift 5 & Network
You can use IPv6Address from Network to work with IPv6 addresses. It is useful for working with local or remote endpoints NWEndpoints, for validating string IPv6 addresses, shortening etc.
There is a extension of IPv6Address that implements helper functions for in6_addr:
import Network
extension IPv6Address {
var address: in6_addr {
rawValue.withUnsafeBytes {
$0.load(as: in6_addr.self)
}
}
var stringValue: String { debugDescription }
init(_ address: in6_addr) {
var addr = address
let data = withUnsafeBytes(of: &addr) { Data($0) }
self.init(data)!
}
}
How to use:
let ipString = "2001:0b28:f23f:f005:0000:0000:0000:000a"
// Create IPv6Address from string
if let ipv6 = IPv6Address(ipString) {
// Get in6_addr from IPv6Address
let addr = ipv6.address
print(addr) // in6_addr(__u6_addr: __C.in6_addr.__Unnamed_union___u6_addr())
// Create IPv6Address from in6_addr
let ipv6 = IPv6Address(addr)
print(ipv6.stringValue) // 2001:b28:f23f:f005::a
}

Related

How to find a free local port using Swift?

For a local server I need to specify a port, which must not be in use. There's a really neat solution in Python to get a free port. However, such a socket library is not available in Swift. So I tried Using BSD Sockets in Swift, but that actually wants a port to be specified upfront and I cannot get the bind command to work. Here's the code I tried:
let socketFD = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if socketFD == -1 {
print("Error creating BSD Socket")
return
}
var hints = addrinfo(
ai_flags: AI_PASSIVE, // Assign the address of the local host to the socket structures
ai_family: AF_UNSPEC, // Either IPv4 or IPv6
ai_socktype: SOCK_STREAM, // TCP
ai_protocol: 0,
ai_addrlen: 0,
ai_canonname: nil,
ai_addr: nil,
ai_next: nil)
var servinfo: UnsafeMutablePointer<addrinfo>? = nil
let addrInfoResult = getaddrinfo(
nil, // Any interface
"8000", // The port on which will be listenend
&hints, // Protocol configuration as per above
&servinfo);
if addrInfoResult != 0 {
print("Error getting address info: \(errno)")
return
}
let bindResult = Darwin.bind(socketFD, servinfo!.pointee.ai_addr, socklen_t(servinfo!.pointee.ai_addrlen));
if bindResult == -1 {
print("Error binding socket to Address: \(errno)")
return
}
let listenResult = Darwin.listen(socketFD, 1);
if listenResult == -1 {
print("Error setting our socket to listen")
return
}
let port = Darwin.getsockname(socketFD, nil, nil);
The bind call always returns -1 and since I want to get a free port it makes no sense to specify one in getaddrinfo. What's the correct way here?
Here's a working solution:
func findFreePort() -> UInt16 {
var port: UInt16 = 8000;
let socketFD = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if socketFD == -1 {
//print("Error creating socket: \(errno)")
return port;
}
var hints = addrinfo(
ai_flags: AI_PASSIVE,
ai_family: AF_INET,
ai_socktype: SOCK_STREAM,
ai_protocol: 0,
ai_addrlen: 0,
ai_canonname: nil,
ai_addr: nil,
ai_next: nil
);
var addressInfo: UnsafeMutablePointer<addrinfo>? = nil;
var result = getaddrinfo(nil, "0", &hints, &addressInfo);
if result != 0 {
//print("Error getting address info: \(errno)")
close(socketFD);
return port;
}
result = Darwin.bind(socketFD, addressInfo!.pointee.ai_addr, socklen_t(addressInfo!.pointee.ai_addrlen));
if result == -1 {
//print("Error binding socket to an address: \(errno)")
close(socketFD);
return port;
}
result = Darwin.listen(socketFD, 1);
if result == -1 {
//print("Error setting socket to listen: \(errno)")
close(socketFD);
return port;
}
var addr_in = sockaddr_in();
addr_in.sin_len = UInt8(MemoryLayout.size(ofValue: addr_in));
addr_in.sin_family = sa_family_t(AF_INET);
var len = socklen_t(addr_in.sin_len);
result = withUnsafeMutablePointer(to: &addr_in, {
$0.withMemoryRebound(to: sockaddr.self, capacity: 1) {
return Darwin.getsockname(socketFD, $0, &len);
}
});
if result == 0 {
port = addr_in.sin_port;
}
Darwin.shutdown(socketFD, SHUT_RDWR);
close(socketFD);
return port;
}

Swift Building IP 4 address class for a iOS project

I was trying to create my own class for IP Address. I want to use this for a iOS project. I'm trying to figure out were to put the code to put the range between 0 to 255. The separator isn't working correctly. I want it to hold a ip address like 192.168.0.1 if I enter 400.168.0.1 it should return a error or say please type a real ip address as one of the output that that something wrong. I trying to create a class that when you input a ip address it should hold in the class itself. I want make a iOS app later on that will help people figure how to distribute IP address for cisco routers and switches. basically want to make a app that helps people with CIDR ip address notations like this webpage program that I found online, but I can barely use without internet connection. http://jodies.de/ipcalc if I could program a mobile application that can do what this website would be great for my line of work in networking.
import UIKit
class IP4 {
var ipA: Int?
var ipB: Int?
var ipC: Int?
var ipD: Int?
func fullIP() -> Int {
var parts: [Int] = []
if let ipA = self.ipA {
parts += [ipA]
}
if let ipB = self.ipB {
parts += [ipB]
}
if let ipC = self.ipC {
parts += [ipC]
}
if let ipD = self.ipD {
parts += [ipD]
}
return parts.joined(separator: ".")
}
}
let ipaddress = IP4()
ipaddress.ipA = 223
ipaddress.ipB = 9
ipaddress.ipC = 50
ipaddress.ipD = 60
This is an example, which can be tested on the Playground. (Tested on Xcode 9.4.1.)
import Foundation
struct IPv4: CustomStringConvertible, Equatable, Hashable {
enum Errors: Error {
case invalidFormat
case octetOutOfRange
}
var ipA: UInt8
var ipB: UInt8
var ipC: UInt8
var ipD: UInt8
init() {
ipA = 0
ipB = 0
ipC = 0
ipD = 0
}
init(_ ipA: UInt8, _ ipB: UInt8, _ ipC: UInt8, _ ipD: UInt8) {
self.ipA = ipA
self.ipB = ipB
self.ipC = ipC
self.ipD = ipD
}
private static let parsingRegex = try! NSRegularExpression(pattern: "^([0-9]{1,3})\\.([0-9]{1,3})\\.([0-9]{1,3})\\.([0-9]{1,3})$")
init(_ ipString: String) throws {
guard let match = IPv4.parsingRegex.firstMatch(in: ipString, range: NSRange(0..<ipString.utf16.count)) else {
throw Errors.invalidFormat
}
let strA = ipString[Range(match.range(at: 1), in: ipString)!]
let strB = ipString[Range(match.range(at: 2), in: ipString)!]
let strC = ipString[Range(match.range(at: 3), in: ipString)!]
let strD = ipString[Range(match.range(at: 4), in: ipString)!]
guard
let ipA = UInt8(strA),
let ipB = UInt8(strB),
let ipC = UInt8(strC),
let ipD = UInt8(strD)
else {throw Errors.octetOutOfRange}
self.ipA = ipA
self.ipB = ipB
self.ipC = ipC
self.ipD = ipD
}
var description: String {
return "\(ipA).\(ipB).\(ipC).\(ipD)"
}
var networkBytes: Data {
return Data(bytes: [ipA, ipB, ipC, ipD])
}
var hostWord: UInt32 {
return UInt32(ipA) << 24 + UInt32(ipB) << 16 + UInt32(ipC) << 8 + UInt32(ipD)
}
}
let ip = IPv4(223, 9, 50, 60)
print(ip) //->223.9.50.60
do {
let ip = try IPv4("400.168.0.1")
print(ip)
} catch {
print(error) //->octetOutOfRange
}
Better use struct than class. As its equality should be judged by its contents, not by its address in the heap.
IPv4 address is made of 4 octets. You should better use UInt8, non-Optional. No parts can be nil.
There's no numeric type which can hold 3-decimal points. If you want to generate a notation like 192.168.0.1, it needs to be a String.
I have prepared 3 types of outputs. Think carefully which one you want.
Also find which part of my code is implementing if I enter 400.168.0.1 it should return a error.
I show you some extensions for my struct, which may be some help to make similar functionalities shown in the linked site.
To make binary representation:
extension UInt8 {
var fixedBinaryDescription: String {
let binStr = String(self, radix: 2)
return String(repeating: "0", count: 8-binStr.count) + binStr
}
}
extension IPv4 {
var binaryDescription: String {
return "\(ipA.fixedBinaryDescription).\(ipB.fixedBinaryDescription).\(ipC.fixedBinaryDescription).\(ipD.fixedBinaryDescription)"
}
}
print(ip.binaryDescription) //->11011111.00001001.00110010.00111100
To work with masks:
extension IPv4 {
init(maskOfLength len: Int) {
let highBits: [UInt8] = [
0b10000000,
0b11000000,
0b11100000,
0b11110000,
0b11111000,
0b11111100,
0b11111110,
0b11111111,
]
switch len {
case 0:
self = IPv4(0, 0, 0, 0)
case 1...8:
self = IPv4(highBits[len-1], 0, 0, 0)
case 9...16:
self = IPv4(0b11111111, highBits[len-9], 0, 0)
case 17...24:
self = IPv4(0b11111111, 0b11111111, highBits[len-17], 0)
case 25...32:
self = IPv4(0b11111111, 0b11111111, 0b11111111, highBits[len-25])
default:
fatalError()
}
}
func masked(by mask: IPv4) -> IPv4 {
return IPv4(self.ipA & mask.ipA, self.ipB & mask.ipB, self.ipC & mask.ipC, self.ipD & mask.ipD)
}
}
let mask = IPv4(maskOfLength: 24)
print(mask.binaryDescription) //->11111111.11111111.11111111.00000000
print(ip.masked(by: mask).binaryDescription) //->11011111.00001001.00110010.00000000
An extension to get address class of IP v4.
enum IPv4AddressClass {
case a
case b
case c
case d
case e
}
extension IPv4 {
var addressClass: IPv4AddressClass {
if ipA & 0b1_0000000 == 0b0_0000000 {
return .a
} else if ipA & 0b11_000000 == 0b10_000000 {
return .b
} else if ipA & 0b111_00000 == 0b110_00000 {
return .c
} else if ipA & 0b1111_0000 == 0b1110_0000 {
return .d
} else {
return .e
}
}
}
print(ip.addressClass) //->c

Get NetworkIp in Swift 3

Any one help me to get Network IP (i.e 103.62.238.190) in Swift 3
I tried below code for it, but this function get System Ip.
I tried so many time to find the solution but still i didn't get any exact function for it.
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)
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) {
// Convert interface address to a human readable string:
var hostname = [CChar](repeating: 0, 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)
addresses.append(address)
}
}
}
}
freeifaddrs(ifaddr)
return addresses
}

Get the currently active network adapter in Swift

I am using the following code to get the network adapters of my macOS System:
private func getAdapters() -> [Adapter]
{
var adapters: [Adapter] = []
var addresses: UnsafeMutablePointer<ifaddrs>?
guard getifaddrs(&addresses) == 0 else { return adapters }
guard let firstAddr = addresses else { return adapters }
for ptr in sequence(first: firstAddr, next: { $0.pointee.ifa_next })
{
let address = ptr.pointee
let rawData = address.ifa_data
let name = address.ifa_name
let socket: sockaddr = address.ifa_addr.pointee
// Set up some filters
let loopback = (address.ifa_flags & UInt32(IFF_LOOPBACK)) != 0
let up = (address.ifa_flags & UInt32(IFF_UP)) != 0
let p2p = (address.ifa_flags & UInt32(IFF_POINTOPOINT)) != 0
if rawData != nil && name != nil && socket.sa_family == UInt8(AF_LINK) && !loopback && up && !p2p
{
let adapterName = String(utf8String: UnsafePointer<CChar>(name!))
let adapter = Adapter(name: adapterName!)
adapters.append(adapter)
}
}
freeifaddrs(addresses)
return adapters
}
Now I am looking for a way to figure out, which of those adapters is the "active" one, i.e. which one is connected to the internet.
I want to get the adapter that has the "green dot" in the network settings. How can I get this information?
Regards,
Sascha

Display all available WIFI connections with Swift in OS X

I'm trying to display all available WIFI connections. It doesn't work. Here is my code:
import Foundation
import CoreWLAN
var cwInterface = CWInterface()
do {
let routers = try cwInterface.scanForNetworksWithSSID(nil)
print(routers)
} catch let error as NSError {
print("Error: \(error.localizedDescription)")
}
I don't get any result. What I'm doing wrong?
It works if you initialize CWInterface with an interface name, like "en1".
But it's better to not use harcoded names, so we'll also use CWWiFiClient.sharedWiFiClient().interface() which returns the default WIFI interface.
Example of a class to manage all this:
class Discovery {
var currentInterface: CWInterface
var interfacesNames: [String] = []
var networks: Set<CWNetwork> = []
// Failable init using default interface
init?() {
if let defaultInterface = CWWiFiClient.sharedWiFiClient().interface(),
name = defaultInterface.interfaceName {
self.currentInterface = defaultInterface
self.interfacesNames.append(name)
self.findNetworks()
} else {
return nil
}
}
// Init with the literal interface name, like "en1"
init(interfaceWithName name: String) {
self.currentInterface = CWInterface(interfaceName: name)
self.interfacesNames.append(name)
self.findNetworks()
}
// Fetch detectable WIFI networks
func findNetworks() {
do {
self.networks = try currentInterface.scanForNetworksWithSSID(nil)
} catch let error as NSError {
print("Error: \(error.localizedDescription)")
}
}
}
Call it with the default interface:
if let discovery = Discovery() {
print(discovery.networks)
for network in discovery.networks {
print(network.ssid!)
}
}
Or with an interface name:
let discovery = Discovery(interfaceWithName: "en1")
let results = discovery.networks
Results contains all the scanned networks:
[<CWNetwork: 0x608000001bd0> [ssid=SomeNetworkName, bssid=xxxx, security=WPA Enterprise, rssi=xx, channel=<CWChannel: 0x600000004fb0> [channelNumber=11(2GHz), channelWidth={20MHz}], ibss=0], etc]