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