libpeak: Mapping of IPv4 to IPv6 in C

Hi everyone,

this week I’m going to present you my little twist for coherent mapping of IPv4 to IPv6 in C. What this means: you don’t have to worry about branching your code, which makes it more clean and simple. The only drawback is that IPv4 addresses do waste a lot of space, but if you plan on working with IPv6 in the future, that argument is quickly rendered invalid. You can find the peak library code on GitHub, or take a look at the whole commit that’s about to be discussed (including a man page and a unit test).

struct netmap {
	union {
		uint8_t byte[16];
		uint16_t word[8];
		uint32_t dword[4];
		uint64_t qword[2];
	} u;
};

I’m using the union for struct netmap to make access in different types more easy. Normally, you won’t even have to bother. The only thing that matters is that the structure is 128 bits wide. What can we do with it? We can fit an IPv6 address perfectly. Let’s do just that with a function we’ll call netmap6.

static inline void
netmap6(struct netmap *in6, const void *ip)
{
	/* IPv6 is native, but don't tell anyone */
	bcopy(ip, in6, sizeof(*in6));
}

That’s the easy part. Now how about an IPv4 address? We could put it anywhere, but isn’t there an standardised way? Actually, there is: RFC 4291, Section 2.5.5.2. The IPv4’s 32 bits are embedded into the ::ffff:0:0/96 network. Luckily, that’s also easy for function netmap4:

static inline void
netmap4(struct netmap *in4, const uint32_t ip)
{
	static const struct netmap _in6 = {
		/* IPv4-mapped IPv6 address via ::ffff:0:0/96 */
		.u.word = {
			0x0, 0x0, 0x0, 0x0, 0x0, 0xffff, 0x0, 0x0,
		},
	};

	in4->u.qword[0] = _in6.u.qword[0];
	in4->u.qword[1] = _in6.u.qword[1];
	in4->u.dword[3] = ip;
}

So, what’s the use, you’re asking? Well, if you use struct netmap in your project, you can use a single compare function with an optimized memcmp call like so:

static inline int
netcmp(const struct netmap *x, const struct netmap *y)
{
	return (memcmp(x, y, sizeof(*x)));
}

Now, what you can do with netcmp is sorting arrays, binary search, building tree structures, and so forth. That’s all for today. I hope you enjoyed this one. If you have any questions just leave a comment. :)

4 thoughts on “libpeak: Mapping of IPv4 to IPv6 in C

  1. Georg

    Unless someone puts a packet on the wire with v4 mapped v6 addresses inside as part of an attack. Not sure if everybody drops such packets…

  2. Franco Post author

    Hi Georg, that’s true. One idea would be to reject such addresses before mapping them. Also, IPv6 has more than one way to wrap IPv4, as well as reserved address ranges that could be used. Assuming one doesn’t want to extend beyond 128 bit, there’s always a possibility of exploitation. However, the motivation behind picking ::ffff:0:0/96 was the possibility of mapping the same host to the same lookup structure, whether it’s raw IPv4 address or embedded into an IPv6 address. Sounds like that’s the attack scenario you are describing: a slightly more sophisticated version of IP spoofing? Not sure what the best way to deal with this would be…

  3. Franco Post author

    Interesting, thanks! The implementation should be used to construct lookup keys only, and if one can make sure mapped addresses are discarded before constructing those keys there shouldn’t be any problem — especially since there is no more ambiguity on the wire :)

Leave a Reply

Your email address will not be published. Required fields are marked *