xref: /openbsd-src/sys/netinet/inet_nat64.c (revision 50b7afb2c2c0993b0894d4e34bf857cb13ed9c80)
1 /*	$OpenBSD: inet_nat64.c,v 1.1 2011/10/13 18:23:40 claudio Exp $	*/
2 /*	$vantronix: inet_nat64.c,v 1.2 2011/02/28 14:57:58 mike Exp $	*/
3 
4 /*
5  * Copyright (c) 2011 Reyk Floeter <reyk@vantronix.net>
6  *
7  * Permission to use, copy, modify, and distribute this software for any
8  * purpose with or without fee is hereby granted, provided that the above
9  * copyright notice and this permission notice appear in all copies.
10  *
11  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18  */
19 
20 #include <sys/param.h>
21 #include <sys/socket.h>
22 #ifdef _KERNEL
23 #include <sys/mbuf.h>
24 #include <netinet/in.h>
25 #else
26 #include <netinet/in.h>
27 #include <errno.h>
28 #endif
29 
30 union inet_nat64_addr {
31 	u_int32_t	 u32[4];
32 	u_int8_t	 u8[16];
33 };
34 
35 u_int32_t inet_nat64_mask(u_int32_t, u_int32_t, u_int8_t);
36 
37 int	  inet_nat64(int, const void *, void *, const void *, u_int8_t);
38 int	  inet_nat64_inet(const void *, void *, const void *, u_int8_t);
39 int	  inet_nat64_inet6(const void *, void *, const void *, u_int8_t);
40 
41 int	  inet_nat46(int, const void *, void *, const void *, u_int8_t);
42 int	  inet_nat46_inet(const void *, void *, const void *, u_int8_t);
43 int	  inet_nat46_inet6(const void *, void *, const void *, u_int8_t);
44 
45 u_int32_t
46 inet_nat64_mask(u_int32_t src, u_int32_t pfx, u_int8_t pfxlen)
47 {
48 	u_int32_t	u32;
49 	if (pfxlen == 0)
50 		return (src);
51 	else if (pfxlen > 32)
52 		pfxlen = 32;
53 	u32 =
54 	    (src & ~htonl(0xffffffff << (32 - pfxlen))) |
55 	    (pfx & htonl(0xffffffff << (32 - pfxlen)));
56 	return (u32);
57 
58 }
59 
60 int
61 inet_nat64(int af, const void *src, void *dst,
62     const void *pfx, u_int8_t pfxlen)
63 {
64 	switch (af) {
65 	case AF_INET:
66 		return (inet_nat64_inet(src, dst, pfx, pfxlen));
67 	case AF_INET6:
68 		return (inet_nat64_inet6(src, dst, pfx, pfxlen));
69 	default:
70 #ifndef _KERNEL
71 		errno = EAFNOSUPPORT;
72 #endif
73 		return (-1);
74 	}
75 	/* NOTREACHED */
76 }
77 
78 int
79 inet_nat64_inet(const void *src, void *dst, const void *pfx, u_int8_t pfxlen)
80 {
81 	const union inet_nat64_addr	*s = src;
82 	const union inet_nat64_addr	*p = pfx;
83 	union inet_nat64_addr		*d = dst;
84 	int				 i, j;
85 
86 	switch (pfxlen) {
87 	case 32:
88 	case 40:
89 	case 48:
90 	case 56:
91 	case 64:
92 	case 96:
93 		i = pfxlen / 8;
94 		break;
95 	default:
96 		if (pfxlen < 96 || pfxlen > 128) {
97 #ifndef _KERNEL
98 			errno = EINVAL;
99 #endif
100 			return (-1);
101 		}
102 
103 		/* as an extension, mask out any other bits */
104 		d->u32[0] = inet_nat64_mask(s->u32[3], p->u32[3],
105 		    (u_int8_t)(32 - (128 - pfxlen)));
106 		return (0);
107 	}
108 
109 	/* fill the octets with the source and skip reserved octet 8 */
110 	for (j = 0; j < 4; j++) {
111 		if (i == 8)
112 			i++;
113 		d->u8[j] = s->u8[i++];
114 	}
115 
116 	return (0);
117 }
118 
119 int
120 inet_nat64_inet6(const void *src, void *dst, const void *pfx, u_int8_t pfxlen)
121 {
122 	const union inet_nat64_addr	*s = src;
123 	const union inet_nat64_addr	*p = pfx;
124 	union inet_nat64_addr		*d = dst;
125 	int				 i, j;
126 
127 	/* first copy the prefix octets to the destination */
128 	*d = *p;
129 
130 	switch (pfxlen) {
131 	case 32:
132 	case 40:
133 	case 48:
134 	case 56:
135 	case 64:
136 	case 96:
137 		i = pfxlen / 8;
138 		break;
139 	default:
140 		if (pfxlen < 96 || pfxlen > 128) {
141 #ifndef _KERNEL
142 			errno = EINVAL;
143 #endif
144 			return (-1);
145 		}
146 
147 		/* as an extension, mask out any other bits */
148 		d->u32[3] = inet_nat64_mask(s->u32[0], p->u32[3],
149 		    (u_int8_t)(32 - (128 - pfxlen)));
150 		return (0);
151 	}
152 
153 	/* octet 8 is reserved and must be set to zero */
154 	d->u8[8] = 0;
155 
156 	/* fill the other octets with the source and skip octet 8 */
157 	for (j = 0; j < 4; j++) {
158 		if (i == 8)
159 			i++;
160 		d->u8[i++] = s->u8[j];
161 	}
162 
163 	return (0);
164 }
165 
166 int
167 inet_nat46(int af, const void *src, void *dst,
168     const void *pfx, u_int8_t pfxlen)
169 {
170 	if (pfxlen > 32) {
171 #ifndef _KERNEL
172 		errno = EINVAL;
173 #endif
174 		return (-1);
175 	}
176 
177 	switch (af) {
178 	case AF_INET:
179 		return (inet_nat46_inet(src, dst, pfx, pfxlen));
180 	case AF_INET6:
181 		return (inet_nat46_inet6(src, dst, pfx, pfxlen));
182 	default:
183 #ifndef _KERNEL
184 		errno = EAFNOSUPPORT;
185 #endif
186 		return (-1);
187 	}
188 	/* NOTREACHED */
189 }
190 
191 int
192 inet_nat46_inet(const void *src, void *dst, const void *pfx, u_int8_t pfxlen)
193 {
194 	const union inet_nat64_addr	*s = src;
195 	const union inet_nat64_addr	*p = pfx;
196 	union inet_nat64_addr		*d = dst;
197 
198 	/* set the remaining bits to the source */
199 	d->u32[0] = inet_nat64_mask(s->u32[3], p->u32[0], pfxlen);
200 
201 	return (0);
202 }
203 
204 int
205 inet_nat46_inet6(const void *src, void *dst, const void *pfx, u_int8_t pfxlen)
206 {
207 	const union inet_nat64_addr	*s = src;
208 	const union inet_nat64_addr	*p = pfx;
209 	union inet_nat64_addr		*d = dst;
210 
211 	/* set the initial octets to zero */
212 	d->u32[0] = d->u32[1] = d->u32[2] = 0;
213 
214 	/* now set the remaining bits to the source */
215 	d->u32[3] = inet_nat64_mask(s->u32[0], p->u32[0], pfxlen);
216 
217 	return (0);
218 }
219