Skip to content

Instantly share code, notes, and snippets.

@njh
Created June 30, 2016 21:17
Show Gist options
  • Save njh/84125c8ededdeb74ec5cc80a4003f308 to your computer and use it in GitHub Desktop.
Save njh/84125c8ededdeb74ec5cc80a4003f308 to your computer and use it in GitHub Desktop.
Minimal C++ class to store, parse and print an IPv6 Address
#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;
}
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