Created
June 30, 2016 21:17
-
-
Save njh/84125c8ededdeb74ec5cc80a4003f308 to your computer and use it in GitHub Desktop.
Minimal C++ class to store, parse and print an IPv6 Address
This file contains hidden or 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
#include <stdio.h> | |
#include <stdint.h> | |
#include <string.h> | |
class IPv6Address { | |
public: | |
IPv6Address(); | |
bool fromString(const char *addrstr); | |
void print(); | |
private: | |
unsigned char _address[16]; | |
} __attribute__((__packed__)); | |
IPv6Address::IPv6Address() | |
{ | |
memset(_address, 0, sizeof(_address)); | |
} | |
#define MAX_IPV6_ADDRESS_STR_LEN 39 | |
static int8_t asciiToHex(char c) | |
{ | |
c |= 0x20; | |
if (c >= '0' && c <= '9') { | |
return c - '0'; | |
} else if (c >= 'a' && c <= 'f') { | |
return (c - 'a') + 10; | |
} else { | |
return -1; | |
} | |
} | |
bool IPv6Address::fromString(const char *addrstr) | |
{ | |
uint16_t accumulator = 0; | |
uint8_t colon_count = 0; | |
uint8_t pos = 0; | |
memset(_address, 0, sizeof(_address)); | |
// Step 1: look for position of ::, and count colons after it | |
for(uint8_t i=1; i <= MAX_IPV6_ADDRESS_STR_LEN; i++) { | |
if (addrstr[i] == ':') { | |
if (addrstr[i-1] == ':') { | |
// Double colon! | |
colon_count = 14; | |
} else if (colon_count) { | |
// Count backwards the number of colons after the :: | |
colon_count -= 2; | |
} | |
} else if (addrstr[i] == '\0') { | |
break; | |
} | |
} | |
// Step 2: convert from ascii to binary | |
for(uint8_t i=0; i <= MAX_IPV6_ADDRESS_STR_LEN && pos < 16; i++) { | |
if (addrstr[i] == ':' || addrstr[i] == '\0') { | |
_address[pos] = accumulator >> 8; | |
_address[pos+1] = accumulator; | |
accumulator = 0; | |
if (colon_count && i && addrstr[i-1] == ':') { | |
pos = colon_count; | |
} else { | |
pos += 2; | |
} | |
} else { | |
int8_t val = asciiToHex(addrstr[i]); | |
if (val == -1) { | |
// Not hex or colon: fail | |
return 0; | |
} else { | |
accumulator <<= 4; | |
accumulator |= val; | |
} | |
} | |
if (addrstr[i] == '\0') | |
break; | |
} | |
// Success | |
return 1; | |
} | |
static void printPaddedHex(uint8_t byte) | |
{ | |
char str[2]; | |
str[0] = (byte >> 4) & 0x0f; | |
str[1] = byte & 0x0f; | |
for (int i=0; i<2; i++) { | |
// base for converting single digit numbers to ASCII is 48 | |
// base for 10-16 to become lower-case characters a-f is 87 | |
if (str[i] > 9) str[i] += 39; | |
str[i] += 48; | |
printf("%c", str[i]); | |
} | |
} | |
void IPv6Address::print() | |
{ | |
for (int i = 0; i < 16; ++i) { | |
printPaddedHex(_address[i]); | |
if (i % 2 == 1 && i < 15) | |
printf(":"); | |
} | |
printf("\n"); | |
} | |
int main() { | |
IPv6Address addr; | |
printf("[parse-test]\n"); | |
printf("sizeof(IPv6Address)=%lu\n", sizeof(IPv6Address)); | |
addr.fromString("2606:2800:220:1:248:1893:25c8:1946"); | |
addr.print(); | |
addr.fromString("2001:41c0::645:a65e:60ff:feda:589d"); | |
addr.print(); | |
addr.fromString("2001:0db8::1:0:0:1"); | |
addr.print(); | |
addr.fromString("2001:41c0::1"); | |
addr.print(); | |
addr.fromString("2606::1"); | |
addr.print(); | |
addr.fromString("1000::1"); | |
addr.print(); | |
addr.fromString("::1"); | |
addr.print(); | |
addr.fromString("::"); | |
addr.print(); | |
return 0; | |
} |
This file contains hidden or 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
test: ipv6-parse-test | |
./ipv6-parse-test | |
ipv6-parse-test: | |
$(CC) -o ipv6-parse-test ipv6-parse-test.cpp | |
clean: | |
rm -f ipv6-parse-test | |
.PHONY: clean |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment