Add method to partition a subnet

This commit is contained in:
Davide De Rosa 2019-05-01 17:07:38 +02:00
parent 03a1eb2203
commit 13cae06a49
3 changed files with 66 additions and 2 deletions

View File

@ -41,6 +41,7 @@ NS_ASSUME_NONNULL_BEGIN
- (BOOL)isDefault;
- (BOOL)matchesDestination:(NSString *)destination;
- (NSArray<RoutingTableEntry *> *)partitioned;
@end

View File

@ -40,8 +40,8 @@ typedef union {
u_short u_data[128];
} sa_u;
static inline uint32_t RoutingTableEntryAddress4(NSString *string);
static inline NSData *RoutingTableEntryAddress6(NSString *string);
static uint32_t RoutingTableEntryAddress4(NSString *string);
static NSData *RoutingTableEntryAddress6(NSString *string);
static NSString *RoutingTableEntryName(struct sockaddr *sa, struct sockaddr *mask, int flags);
#pragma mark -
@ -238,6 +238,48 @@ static NSString *RoutingTableEntryName(struct sockaddr *sa, struct sockaddr *mas
}
}
- (NSArray<RoutingTableEntry *> *)partitioned
{
NSMutableArray<RoutingTableEntry *> *segments = [[NSMutableArray alloc] init];
const int halfPrefix = (int)(self.prefix + 1);
if (self.isIPv6) {
struct in6_addr saddr1, saddr2;
char addr[INET6_ADDRSTRLEN];
NSData *addressData = RoutingTableEntryAddress6(self.network);
memcpy(&saddr1, addressData.bytes, addressData.length);
NSMutableData *addressData2 = [addressData mutableCopy];
uint8_t *addressBytes2 = (uint8_t *)addressData2.bytes;
const uint8_t mask2 = 1 << (8 - halfPrefix % 8);
addressBytes2[halfPrefix / 8] |= mask2;
memcpy(&saddr2, addressData2.bytes, addressData2.length);
inet_ntop(AF_INET6, &saddr1, addr, INET6_ADDRSTRLEN);
NSString *network1 = [NSString stringWithFormat:@"%s/%d", addr, halfPrefix];
inet_ntop(AF_INET6, &saddr2, addr, INET6_ADDRSTRLEN);
NSString *network2 = [NSString stringWithFormat:@"%s/%d", addr, halfPrefix];
[segments addObject:[[RoutingTableEntry alloc] initWithIPv6Network:network1 gateway:self.gateway networkInterface:self.networkInterface]];
[segments addObject:[[RoutingTableEntry alloc] initWithIPv6Network:network2 gateway:self.gateway networkInterface:self.networkInterface]];
} else {
struct in_addr saddr1, saddr2;
const uint32_t address = RoutingTableEntryAddress4(self.network);
saddr1.s_addr = htonl(address);
saddr2.s_addr = htonl(address | (1 << (32 - halfPrefix)));
// XXX: inet_ntoa returns pointer to static variable, copy before next call
const char *address1 = inet_ntoa(saddr1);
NSString *network1 = [NSString stringWithFormat:@"%s/%d", address1, halfPrefix];
const char *address2 = inet_ntoa(saddr2);
NSString *network2 = [NSString stringWithFormat:@"%s/%d", address2, halfPrefix];
[segments addObject:[[RoutingTableEntry alloc] initWithIPv4Network:network1 gateway:self.gateway networkInterface:self.networkInterface]];
[segments addObject:[[RoutingTableEntry alloc] initWithIPv4Network:network2 gateway:self.gateway networkInterface:self.networkInterface]];
}
return segments;
}
- (NSString *)description
{
return [NSString stringWithFormat:@"{%@/%ld -> %@ via %@}", self.network, self.prefix, self.gateway ?: @"nil", self.networkInterface];

View File

@ -95,4 +95,25 @@ class RoutingTests: XCTestCase {
}
}
}
func testPartitioning() {
let v4 = RoutingTableEntry(iPv4Network: "192.168.1.0/24", gateway: nil, networkInterface: "en0")
let v6 = RoutingTableEntry(iPv6Network: "abcd:efef:120::/46", gateway: nil, networkInterface: "en0")
let v4parts = v4.partitioned()
let v4parts1 = v4parts[0]
let v4parts2 = v4parts[1]
XCTAssertEqual(v4parts1.network(), "192.168.1.0")
XCTAssertEqual(v4parts1.prefix(), 25)
XCTAssertEqual(v4parts2.network(), "192.168.1.128")
XCTAssertEqual(v4parts2.prefix(), 25)
let v6parts = v6.partitioned()
let v6parts1 = v6parts[0]
let v6parts2 = v6parts[1]
XCTAssertEqual(v6parts1.network(), "abcd:efef:120::")
XCTAssertEqual(v6parts1.prefix(), 47)
XCTAssertEqual(v6parts2.network(), "abcd:efef:122::")
XCTAssertEqual(v6parts2.prefix(), 47)
}
}