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