xref: /openbsd-src/sys/netinet/inet_nat64.c (revision 21dab745d772244ad59a415114e48be2888cfbc8)
1 /*	$OpenBSD: inet_nat64.c,v 1.2 2015/03/14 03:38:51 jsg 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 #else
25 #include <errno.h>
26 #endif
27 
28 union inet_nat64_addr {
29 	u_int32_t	 u32[4];
30 	u_int8_t	 u8[16];
31 };
32 
33 u_int32_t inet_nat64_mask(u_int32_t, u_int32_t, u_int8_t);
34 
35 int	  inet_nat64(int, const void *, void *, const void *, u_int8_t);
36 int	  inet_nat64_inet(const void *, void *, const void *, u_int8_t);
37 int	  inet_nat64_inet6(const void *, void *, const void *, u_int8_t);
38 
39 int	  inet_nat46(int, const void *, void *, const void *, u_int8_t);
40 int	  inet_nat46_inet(const void *, void *, const void *, u_int8_t);
41 int	  inet_nat46_inet6(const void *, void *, const void *, u_int8_t);
42 
43 u_int32_t
inet_nat64_mask(u_int32_t src,u_int32_t pfx,u_int8_t pfxlen)44 inet_nat64_mask(u_int32_t src, u_int32_t pfx, u_int8_t pfxlen)
45 {
46 	u_int32_t	u32;
47 	if (pfxlen == 0)
48 		return (src);
49 	else if (pfxlen > 32)
50 		pfxlen = 32;
51 	u32 =
52 	    (src & ~htonl(0xffffffff << (32 - pfxlen))) |
53 	    (pfx & htonl(0xffffffff << (32 - pfxlen)));
54 	return (u32);
55 
56 }
57 
58 int
inet_nat64(int af,const void * src,void * dst,const void * pfx,u_int8_t pfxlen)59 inet_nat64(int af, const void *src, void *dst,
60     const void *pfx, u_int8_t pfxlen)
61 {
62 	switch (af) {
63 	case AF_INET:
64 		return (inet_nat64_inet(src, dst, pfx, pfxlen));
65 	case AF_INET6:
66 		return (inet_nat64_inet6(src, dst, pfx, pfxlen));
67 	default:
68 #ifndef _KERNEL
69 		errno = EAFNOSUPPORT;
70 #endif
71 		return (-1);
72 	}
73 	/* NOTREACHED */
74 }
75 
76 int
inet_nat64_inet(const void * src,void * dst,const void * pfx,u_int8_t pfxlen)77 inet_nat64_inet(const void *src, void *dst, const void *pfx, u_int8_t pfxlen)
78 {
79 	const union inet_nat64_addr	*s = src;
80 	const union inet_nat64_addr	*p = pfx;
81 	union inet_nat64_addr		*d = dst;
82 	int				 i, j;
83 
84 	switch (pfxlen) {
85 	case 32:
86 	case 40:
87 	case 48:
88 	case 56:
89 	case 64:
90 	case 96:
91 		i = pfxlen / 8;
92 		break;
93 	default:
94 		if (pfxlen < 96 || pfxlen > 128) {
95 #ifndef _KERNEL
96 			errno = EINVAL;
97 #endif
98 			return (-1);
99 		}
100 
101 		/* as an extension, mask out any other bits */
102 		d->u32[0] = inet_nat64_mask(s->u32[3], p->u32[3],
103 		    (u_int8_t)(32 - (128 - pfxlen)));
104 		return (0);
105 	}
106 
107 	/* fill the octets with the source and skip reserved octet 8 */
108 	for (j = 0; j < 4; j++) {
109 		if (i == 8)
110 			i++;
111 		d->u8[j] = s->u8[i++];
112 	}
113 
114 	return (0);
115 }
116 
117 int
inet_nat64_inet6(const void * src,void * dst,const void * pfx,u_int8_t pfxlen)118 inet_nat64_inet6(const void *src, void *dst, const void *pfx, u_int8_t pfxlen)
119 {
120 	const union inet_nat64_addr	*s = src;
121 	const union inet_nat64_addr	*p = pfx;
122 	union inet_nat64_addr		*d = dst;
123 	int				 i, j;
124 
125 	/* first copy the prefix octets to the destination */
126 	*d = *p;
127 
128 	switch (pfxlen) {
129 	case 32:
130 	case 40:
131 	case 48:
132 	case 56:
133 	case 64:
134 	case 96:
135 		i = pfxlen / 8;
136 		break;
137 	default:
138 		if (pfxlen < 96 || pfxlen > 128) {
139 #ifndef _KERNEL
140 			errno = EINVAL;
141 #endif
142 			return (-1);
143 		}
144 
145 		/* as an extension, mask out any other bits */
146 		d->u32[3] = inet_nat64_mask(s->u32[0], p->u32[3],
147 		    (u_int8_t)(32 - (128 - pfxlen)));
148 		return (0);
149 	}
150 
151 	/* octet 8 is reserved and must be set to zero */
152 	d->u8[8] = 0;
153 
154 	/* fill the other octets with the source and skip octet 8 */
155 	for (j = 0; j < 4; j++) {
156 		if (i == 8)
157 			i++;
158 		d->u8[i++] = s->u8[j];
159 	}
160 
161 	return (0);
162 }
163 
164 int
inet_nat46(int af,const void * src,void * dst,const void * pfx,u_int8_t pfxlen)165 inet_nat46(int af, const void *src, void *dst,
166     const void *pfx, u_int8_t pfxlen)
167 {
168 	if (pfxlen > 32) {
169 #ifndef _KERNEL
170 		errno = EINVAL;
171 #endif
172 		return (-1);
173 	}
174 
175 	switch (af) {
176 	case AF_INET:
177 		return (inet_nat46_inet(src, dst, pfx, pfxlen));
178 	case AF_INET6:
179 		return (inet_nat46_inet6(src, dst, pfx, pfxlen));
180 	default:
181 #ifndef _KERNEL
182 		errno = EAFNOSUPPORT;
183 #endif
184 		return (-1);
185 	}
186 	/* NOTREACHED */
187 }
188 
189 int
inet_nat46_inet(const void * src,void * dst,const void * pfx,u_int8_t pfxlen)190 inet_nat46_inet(const void *src, void *dst, const void *pfx, u_int8_t pfxlen)
191 {
192 	const union inet_nat64_addr	*s = src;
193 	const union inet_nat64_addr	*p = pfx;
194 	union inet_nat64_addr		*d = dst;
195 
196 	/* set the remaining bits to the source */
197 	d->u32[0] = inet_nat64_mask(s->u32[3], p->u32[0], pfxlen);
198 
199 	return (0);
200 }
201 
202 int
inet_nat46_inet6(const void * src,void * dst,const void * pfx,u_int8_t pfxlen)203 inet_nat46_inet6(const void *src, void *dst, const void *pfx, u_int8_t pfxlen)
204 {
205 	const union inet_nat64_addr	*s = src;
206 	const union inet_nat64_addr	*p = pfx;
207 	union inet_nat64_addr		*d = dst;
208 
209 	/* set the initial octets to zero */
210 	d->u32[0] = d->u32[1] = d->u32[2] = 0;
211 
212 	/* now set the remaining bits to the source */
213 	d->u32[3] = inet_nat64_mask(s->u32[0], p->u32[0], pfxlen);
214 
215 	return (0);
216 }
217