New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
IPv6 support #22
Merged
Merged
IPv6 support #22
Changes from 26 commits
Commits
Show all changes
33 commits
Select commit
Hold shift + click to select a range
ae95476
Extending Types, Bytes and Address data types in order to support IPv…
MatthiasKreileder a20ec37
Adding IPv6 hexadecimal representation to colon separated string repr…
MatthiasKreileder e27a7b6
Removing false Cocoa dependency
MatthiasKreileder 213f00d
Starting to build a IPv6/IPv4 capable TCP socket
MatthiasKreileder 9d6f10a
Merge branch 'master' into addIPv6Support
MatthiasKreileder eb62931
Adding test for name resolution
MatthiasKreileder 9eac4bb
Simplifying getaddrinfo argument creation(still not working though)
MatthiasKreileder 4ae18f0
work in progress... trying to make successful calls to getaddrinfo()
MatthiasKreileder 92ddc05
Use typealias to refer to a type instead of a variable
czechboy0 945afd0
Removing depricated cast method
MatthiasKreileder 2a26df1
Adding SocketConfig struct. Enables application code to guide the nam…
MatthiasKreileder ea2d414
Finished first version of TCP Client with IPv4/IPv6 support
MatthiasKreileder 628f711
Adding comments
MatthiasKreileder 66af97f
Adding comments for code review
MatthiasKreileder 4e9b7e1
Changing Internet Address representation, Name to Address resolving, …
MatthiasKreileder c37a511
Adding KclInternetSocket class as a prototype for an IPv4/IPv6 capabl…
MatthiasKreileder 93b2154
Supporting IPv6 on the Server side
MatthiasKreileder c1fcbf3
Completing IPv6 support for SocksCore
MatthiasKreileder a0b37e6
Updating swift version
MatthiasKreileder 12e6d3f
Updating Sources/Socks, Tests and Examples to IPv6 support modifications
MatthiasKreileder 07be0bb
Removing deprecated conversion function
MatthiasKreileder bf0badd
Adding manual casting for Linux
MatthiasKreileder af83c46
Adding manual casting for Linux Part 2 :)
MatthiasKreileder 8fd0536
Adding comments, removing deprecated code
MatthiasKreileder 520149a
Removing code that is no longer needed
MatthiasKreileder 21e4539
Merge branch 'master' into addIPv6Support
MatthiasKreileder 715890b
Renaming Internet_Address to InternetAddress
MatthiasKreileder dcec368
Incorporating requested changes that were made after the pull request…
MatthiasKreileder bb23498
Moving Address Family resolution for SocketConfig from RawSocket to I…
MatthiasKreileder 73ae0d6
Cleaning up: Removing SocketFactory.swift, removing wrong whitespace …
MatthiasKreileder ad298b4
Adding static functions to SocketConfig for "easy initialising". Chan…
MatthiasKreileder 8482ffb
Changing the "Created by" comment in the two files which contain the …
MatthiasKreileder 9c70732
Cosmetic changes before merging
czechboy0 File filter
Filter by extension
Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
// | ||
// SocketFactory.swift | ||
// Socks | ||
// | ||
// Created by Matthias Kreileder on 28/03/2016. | ||
// | ||
// | ||
|
||
import Foundation | ||
import SocksCore | ||
|
||
#if os(Linux) | ||
import Glibc | ||
typealias socket_addrinfo = Glibc.addrinfo | ||
private let socket_connect = Glibc.connect | ||
#else | ||
import Darwin | ||
typealias socket_addrinfo = Darwin.addrinfo | ||
private let socket_connect = Darwin.connect | ||
#endif | ||
|
||
// DEPRECATED | ||
/* | ||
public class SocketFactory { | ||
|
||
|
||
} | ||
*/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -8,55 +8,128 @@ | |
|
||
#if os(Linux) | ||
import Glibc | ||
typealias socket_addrinfo = Glibc.addrinfo | ||
#else | ||
import Darwin | ||
typealias socket_addrinfo = Darwin.addrinfo | ||
#endif | ||
|
||
//Pretty types -> C types | ||
|
||
protocol InternetAddressResolver { | ||
func resolve(internetAddress : Internet_Address) -> Array<ResolvedInternetAddress> | ||
} | ||
|
||
extension InternetAddress { | ||
public struct Resolver : InternetAddressResolver{ | ||
private let config : SocketConfig | ||
public init(config : SocketConfig){ | ||
self.config = config | ||
} | ||
|
||
func toCType() throws -> sockaddr { | ||
|
||
var addr = sockaddr_in() | ||
|
||
switch self.address { | ||
case .Hostname(let hostname): | ||
//hostname must be converted to ip | ||
addr.sin_addr = try InternetAddress.getAddressFromHostname(hostname: hostname) | ||
case .IPv4(let ipBytes4): | ||
//we got an IP, validate it | ||
let str = ipBytes4.toArray().periodSeparatedString() | ||
guard inet_pton(AF_INET, str, &addr.sin_addr) == 1 else { | ||
throw Error(ErrorReason.IPAddressValidationFailed) | ||
} | ||
} | ||
|
||
addr.sin_family = sa_family_t(AF_INET) | ||
addr.sin_port = in_port_t(htons(value: in_port_t(self.port))) | ||
addr.sin_zero = (0, 0, 0, 0, 0, 0, 0, 0) | ||
|
||
let res = sockaddr_cast(p: &addr).pointee | ||
return res | ||
public func resolve(internetAddress : Internet_Address) -> Array<ResolvedInternetAddress>{ | ||
let resolvedInternetAddressesArray = try!resolveHostnameAndServiceToIPAddresses(socketConfig: self.config, internetAddress: internetAddress) | ||
// | ||
// TODO: Consider try and catch or other tests (if array contains 0 elements or something like that) | ||
// | ||
return resolvedInternetAddressesArray | ||
} | ||
|
||
private static func getAddressFromHostname(hostname: String) throws -> in_addr { | ||
private func resolveHostnameAndServiceToIPAddresses(socketConfig : SocketConfig, | ||
internetAddress : Internet_Address) throws | ||
-> Array<ResolvedInternetAddress> | ||
{ | ||
// | ||
// Narrowing down the results we will get from the getaddrinfo call | ||
// | ||
var addressCriteria = socket_addrinfo.init() | ||
// IPv4 or IPv6 | ||
addressCriteria.ai_family = socketConfig.addressFamily.toCType() | ||
addressCriteria.ai_flags = AI_PASSIVE | ||
addressCriteria.ai_socktype = socketConfig.socketType.toCType() | ||
addressCriteria.ai_protocol = socketConfig.protocolType.toCType() | ||
|
||
// The list of addresses that correspond to the hostname/service pair. | ||
// servinfo is the first node in a linked list of addresses that is empty | ||
// at this line | ||
var servinfo = UnsafeMutablePointer<socket_addrinfo>.init(nil) | ||
// perform resolution | ||
let getaddrinfoReturnValue = getaddrinfo(internetAddress.hostname, internetAddress.port.toString(), &addressCriteria, &servinfo) | ||
guard getaddrinfoReturnValue == 0 else { throw Error(.IPAddressValidationFailed) } | ||
|
||
// Wrap linked list into array of ResolvedInternetAddress | ||
|
||
// we need to remember the head of the linked list to clean up the consumed memory on the head | ||
let head = servinfo | ||
|
||
let _hostInfo = gethostbyname(hostname) | ||
guard _hostInfo != nil else { | ||
throw Error(.FailedToGetIPFromHostname(hostname)) | ||
} | ||
let hostInfo = _hostInfo.pointee | ||
guard hostInfo.h_addrtype == AF_INET else { | ||
throw Error(.FailedToGetIPFromHostname("No IPv4 address")) | ||
} | ||
guard hostInfo.h_addr_list != nil else { | ||
throw Error(.FailedToGetIPFromHostname("List is empty")) | ||
} | ||
var resolvedInternetAddressesArray = Array<ResolvedInternetAddress>() | ||
while(servinfo != nil){ | ||
let singleAddress = ResolvedInternetAddress(internetAddress: internetAddress, resolvedCTypeAddress: (servinfo?.pointee)!) | ||
resolvedInternetAddressesArray.append(singleAddress) | ||
servinfo = servinfo?.pointee.ai_next | ||
} | ||
|
||
// | ||
// FIXME: The dynamically allocated linked list of socket_addrinfo objects | ||
// should be deleted from the heap in order to prevent memory leaks | ||
// However, when I [Matthias Kreileder] uncomment the line 'freeaddrinfo(head)' | ||
// my code crashes at runtime :( | ||
// In the code above I tried to COPY the socket_addrinfo into an array | ||
// so that I can (in theory) safely free the memory allocated on the heap. | ||
// | ||
// Prevent memory leaks: getaddrinfo creates an unmanaged linked list on the heap | ||
//freeaddrinfo(head) | ||
|
||
let addrStruct = sockadd_list_cast(p: hostInfo.h_addr_list)[0].pointee | ||
return addrStruct | ||
return resolvedInternetAddressesArray | ||
} | ||
|
||
} | ||
|
||
// Brief: Given given a hostname and a service this methods return a list of | ||
// IP and Port adresses that where obtained during the name resolution | ||
// e.g. "localhost" and "echo" as arguments will result in a list of | ||
// IP addresses of the machine that runs the program and port set to 7 | ||
// | ||
// socketConfig - the provided SocketConfig object guides the name resolution | ||
// the socketType_ and protocolType_ fields control which kind | ||
// kind of socket you want to create. | ||
// E.g. set them to .STREAM .TCP to obtain address for a TCP Stream socket | ||
// - Set the addressFamily_ field to .UNSPECIFIED if you don't care if the | ||
// name resolution leads to IPv4 or IPv6 addresses. | ||
// | ||
// hostname - e.g. "www.google.com" or "localhost" | ||
// | ||
// service - can be a service string e.g. "echo" or a well-know port e.g. "7" | ||
|
||
// Return Array of ResolvedInternetAddress | ||
|
||
// Resolver guts | ||
public func resolveHostnameAndServiceToIPAddresses(socketConfig : SocketConfig, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Probably can be removed |
||
hostname : String, | ||
service : String)throws | ||
-> UnsafeMutablePointer<addrinfo> | ||
{ | ||
// | ||
// Narrowing down the results we will get from the getaddrinfo call | ||
// | ||
var addressCriteria = socket_addrinfo.init() | ||
// IPv4 or IPv6 | ||
addressCriteria.ai_family = socketConfig.addressFamily.toCType() | ||
addressCriteria.ai_flags = AI_PASSIVE | ||
addressCriteria.ai_socktype = socketConfig.socketType.toCType() | ||
addressCriteria.ai_protocol = socketConfig.protocolType.toCType() | ||
|
||
// The list of addresses that correspond to the hostname/service pair. | ||
var servinfo = UnsafeMutablePointer<socket_addrinfo>.init(nil) | ||
|
||
let getaddrinfoReturnValue = getaddrinfo(hostname, service, &addressCriteria, &servinfo) | ||
guard getaddrinfoReturnValue == 0 else { throw Error(.IPAddressValidationFailed) } | ||
|
||
// Wrap linked list into array of ResolvedInternetAddress | ||
|
||
// Prevent memory leaks: getaddrinfo creates an unmanaged linked list on the heap | ||
// freeaddrinfo(servinfo) | ||
|
||
return servinfo! | ||
} | ||
|
||
//Pointer casting | ||
|
@@ -65,6 +138,8 @@ func sockaddr_cast(p: UnsafeMutablePointer<Void>) -> UnsafeMutablePointer<sockad | |
return UnsafeMutablePointer<sockaddr>(p) | ||
} | ||
|
||
func sockadd_list_cast(p: UnsafeMutablePointer<UnsafeMutablePointer<Int8>?>) -> UnsafeMutablePointer<UnsafeMutablePointer<in_addr>> { | ||
return UnsafeMutablePointer<UnsafeMutablePointer<in_addr>>(p) | ||
func sockaddr_storage_cast(p : UnsafeMutablePointer<Void>) -> UnsafeMutablePointer<sockaddr> { | ||
return UnsafeMutablePointer<sockaddr>(p) | ||
} | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Array<ResolvedInternetAddress>
->[ResolvedInternetAddress]