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