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