| 1 |
/* $Id: inet_XtoX.c,v 1.1 2006/12/04 01:55:39 mjt Exp $ |
|---|
| 2 |
* Simple implementation of the following functions: |
|---|
| 3 |
* inet_ntop(), inet_ntoa(), inet_pton(), inet_aton(). |
|---|
| 4 |
* |
|---|
| 5 |
* Differences from traditional implementaitons: |
|---|
| 6 |
* o modifies destination buffers even on error return. |
|---|
| 7 |
* o no fancy (hex, or 1.2) input support in inet_aton() |
|---|
| 8 |
* o inet_aton() does not accept junk after an IP address. |
|---|
| 9 |
* o inet_ntop(AF_INET) requires at least 16 bytes in dest, |
|---|
| 10 |
* and inet_ntop(AF_INET6) at least 40 bytes |
|---|
| 11 |
* (traditional inet_ntop() will try to fit anyway) |
|---|
| 12 |
* |
|---|
| 13 |
* Compile with -Dinet_XtoX_prefix=pfx_ to have pfx_*() instead of inet_*() |
|---|
| 14 |
* Compile with -Dinet_XtoX_no_ntop or -Dinet_XtoX_no_pton |
|---|
| 15 |
* to disable net2str or str2net conversions. |
|---|
| 16 |
* |
|---|
| 17 |
* #define inet_XtoX_prototypes and #include "this_file.c" |
|---|
| 18 |
* to get function prototypes only (but not for inet_ntoa()). |
|---|
| 19 |
* #define inet_XtoX_decl to be `static' for static visibility, |
|---|
| 20 |
* or use __declspec(dllexport) or somesuch... |
|---|
| 21 |
* |
|---|
| 22 |
* Compile with -DTEST to test against stock implementation. |
|---|
| 23 |
* |
|---|
| 24 |
* Written by Michael Tokarev. Public domain. |
|---|
| 25 |
*/ |
|---|
| 26 |
|
|---|
| 27 |
#ifdef inet_XtoX_prototypes |
|---|
| 28 |
|
|---|
| 29 |
struct in_addr; |
|---|
| 30 |
|
|---|
| 31 |
#else |
|---|
| 32 |
|
|---|
| 33 |
#include <errno.h> |
|---|
| 34 |
|
|---|
| 35 |
#ifdef TEST |
|---|
| 36 |
|
|---|
| 37 |
# include <netinet/in.h> |
|---|
| 38 |
# include <sys/socket.h> |
|---|
| 39 |
# include <arpa/inet.h> |
|---|
| 40 |
# include <stdio.h> |
|---|
| 41 |
# include <stdlib.h> |
|---|
| 42 |
# include <unistd.h> |
|---|
| 43 |
# include <string.h> |
|---|
| 44 |
# undef inet_XtoX_prefix |
|---|
| 45 |
# define inet_XtoX_prefix mjt_inet_ |
|---|
| 46 |
# undef inet_XtoX_no_ntop |
|---|
| 47 |
# undef inet_XtoX_no_pton |
|---|
| 48 |
|
|---|
| 49 |
#else /* !TEST */ |
|---|
| 50 |
|
|---|
| 51 |
struct in_addr { /* declare it here to avoid messing with headers */ |
|---|
| 52 |
unsigned char x[4]; |
|---|
| 53 |
}; |
|---|
| 54 |
|
|---|
| 55 |
#endif /* TEST */ |
|---|
| 56 |
|
|---|
| 57 |
#endif /* inet_XtoX_prototypes */ |
|---|
| 58 |
|
|---|
| 59 |
#ifndef inet_XtoX_prefix |
|---|
| 60 |
# define inet_XtoX_prefix inet_ |
|---|
| 61 |
#endif |
|---|
| 62 |
#ifndef inet_XtoX_decl |
|---|
| 63 |
# define inet_XtoX_decl /*empty*/ |
|---|
| 64 |
#endif |
|---|
| 65 |
|
|---|
| 66 |
#define cc2_(x,y) cc2__(x,y) |
|---|
| 67 |
#define cc2__(x,y) x##y |
|---|
| 68 |
#define fn(x) cc2_(inet_XtoX_prefix,x) |
|---|
| 69 |
|
|---|
| 70 |
#ifndef inet_XtoX_no_ntop |
|---|
| 71 |
|
|---|
| 72 |
inet_XtoX_decl const char * |
|---|
| 73 |
fn(ntop)(int af, const void *src, char *dst, unsigned size); |
|---|
| 74 |
|
|---|
| 75 |
#ifndef inet_XtoX_prototypes |
|---|
| 76 |
|
|---|
| 77 |
static int mjt_ntop4(const void *_src, char *dst, int size) { |
|---|
| 78 |
unsigned i, x, r; |
|---|
| 79 |
char *p; |
|---|
| 80 |
const unsigned char *s = _src; |
|---|
| 81 |
if (size < 4*4) /* for simplicity, disallow non-max-size buffer */ |
|---|
| 82 |
return 0; |
|---|
| 83 |
for (i = 0, p = dst; i < 4; ++i) { |
|---|
| 84 |
if (i) *p++ = '.'; |
|---|
| 85 |
x = r = s[i]; |
|---|
| 86 |
if (x > 99) { *p++ = (char)(r / 100 + '0'); r %= 100; } |
|---|
| 87 |
if (x > 9) { *p++ = (char)(r / 10 + '0'); r %= 10; } |
|---|
| 88 |
*p++ = (char)(r + '0'); |
|---|
| 89 |
} |
|---|
| 90 |
*p = '\0'; |
|---|
| 91 |
return 1; |
|---|
| 92 |
} |
|---|
| 93 |
|
|---|
| 94 |
static char *hexc(char *p, unsigned x) { |
|---|
| 95 |
static char hex[16] = "0123456789abcdef"; |
|---|
| 96 |
if (x > 0x0fff) *p++ = hex[(x >>12) & 15]; |
|---|
| 97 |
if (x > 0x00ff) *p++ = hex[(x >> 8) & 15]; |
|---|
| 98 |
if (x > 0x000f) *p++ = hex[(x >> 4) & 15]; |
|---|
| 99 |
*p++ = hex[x & 15]; |
|---|
| 100 |
return p; |
|---|
| 101 |
} |
|---|
| 102 |
|
|---|
| 103 |
static int mjt_ntop6(const void *_src, char *dst, int size) { |
|---|
| 104 |
unsigned i; |
|---|
| 105 |
unsigned short w[8]; |
|---|
| 106 |
unsigned bs = 0, cs = 0; |
|---|
| 107 |
unsigned bl = 0, cl = 0; |
|---|
| 108 |
char *p; |
|---|
| 109 |
const unsigned char *s = _src; |
|---|
| 110 |
|
|---|
| 111 |
if (size < 40) /* for simplicity, disallow non-max-size buffer */ |
|---|
| 112 |
return 0; |
|---|
| 113 |
|
|---|
| 114 |
for(i = 0; i < 8; ++i, s += 2) { |
|---|
| 115 |
w[i] = (((unsigned short)(s[0])) << 8) | s[1]; |
|---|
| 116 |
if (!w[i]) { |
|---|
| 117 |
if (!cl++) cs = i; |
|---|
| 118 |
} |
|---|
| 119 |
else { |
|---|
| 120 |
if (cl > bl) bl = cl, bs = cs; |
|---|
| 121 |
} |
|---|
| 122 |
} |
|---|
| 123 |
if (cl > bl) bl = cl, bs = cs; |
|---|
| 124 |
p = dst; |
|---|
| 125 |
if (bl == 1) |
|---|
| 126 |
bl = 0; |
|---|
| 127 |
if (bl) { |
|---|
| 128 |
for(i = 0; i < bs; ++i) { |
|---|
| 129 |
if (i) *p++ = ':'; |
|---|
| 130 |
p = hexc(p, w[i]); |
|---|
| 131 |
} |
|---|
| 132 |
*p++ = ':'; |
|---|
| 133 |
i += bl; |
|---|
| 134 |
if (i == 8) |
|---|
| 135 |
*p++ = ':'; |
|---|
| 136 |
} |
|---|
| 137 |
else |
|---|
| 138 |
i = 0; |
|---|
| 139 |
for(; i < 8; ++i) { |
|---|
| 140 |
if (i) *p++ = ':'; |
|---|
| 141 |
if (i == 6 && !bs && (bl == 6 || (bl == 5 && w[5] == 0xffff))) |
|---|
| 142 |
return mjt_ntop4(s - 4, p, size - (p - dst)); |
|---|
| 143 |
p = hexc(p, w[i]); |
|---|
| 144 |
} |
|---|
| 145 |
*p = '\0'; |
|---|
| 146 |
return 1; |
|---|
| 147 |
} |
|---|
| 148 |
|
|---|
| 149 |
inet_XtoX_decl const char * |
|---|
| 150 |
fn(ntop)(int af, const void *src, char *dst, unsigned size) { |
|---|
| 151 |
switch(af) { |
|---|
| 152 |
/* don't use AF_*: don't mess with headers */ |
|---|
| 153 |
case 2: /* AF_INET */ if (mjt_ntop4(src, dst, size)) return dst; break; |
|---|
| 154 |
case 10: /* AF_INET6 */ if (mjt_ntop6(src, dst, size)) return dst; break; |
|---|
| 155 |
default: errno = EAFNOSUPPORT; return (char*)0; |
|---|
| 156 |
} |
|---|
| 157 |
errno = ENOSPC; |
|---|
| 158 |
return (char*)0; |
|---|
| 159 |
} |
|---|
| 160 |
|
|---|
| 161 |
inet_XtoX_decl const char * |
|---|
| 162 |
fn(ntoa)(struct in_addr addr) { |
|---|
| 163 |
static char buf[4*4]; |
|---|
| 164 |
mjt_ntop4(&addr, buf, sizeof(buf)); |
|---|
| 165 |
return buf; |
|---|
| 166 |
} |
|---|
| 167 |
|
|---|
| 168 |
#endif /* inet_XtoX_prototypes */ |
|---|
| 169 |
#endif /* inet_XtoX_no_ntop */ |
|---|
| 170 |
|
|---|
| 171 |
#ifndef inet_XtoX_no_pton |
|---|
| 172 |
|
|---|
| 173 |
inet_XtoX_decl int fn(pton)(int af, const char *src, void *dst); |
|---|
| 174 |
inet_XtoX_decl int fn(aton)(const char *src, struct in_addr *addr); |
|---|
| 175 |
|
|---|
| 176 |
#ifndef inet_XtoX_prototypes |
|---|
| 177 |
|
|---|
| 178 |
static int mjt_pton4(const char *c, void *dst) { |
|---|
| 179 |
unsigned char *a = dst; |
|---|
| 180 |
unsigned n, o; |
|---|
| 181 |
for (n = 0; n < 4; ++n) { |
|---|
| 182 |
if (*c < '0' || *c > '9') |
|---|
| 183 |
return 0; |
|---|
| 184 |
o = *c++ - '0'; |
|---|
| 185 |
while(*c >= '0' && *c <= '9') |
|---|
| 186 |
if ((o = o * 10 + (*c++ - '0')) > 255) |
|---|
| 187 |
return 0; |
|---|
| 188 |
if (*c++ != (n == 3 ? '\0' : '.')) |
|---|
| 189 |
return 0; |
|---|
| 190 |
*a++ = (unsigned char)o; |
|---|
| 191 |
} |
|---|
| 192 |
return 1; |
|---|
| 193 |
} |
|---|
| 194 |
|
|---|
| 195 |
static int mjt_pton6(const char *c, void *dst) { |
|---|
| 196 |
unsigned short w[8], *a = w, *z, *i; |
|---|
| 197 |
unsigned v, o; |
|---|
| 198 |
const char *sc; |
|---|
| 199 |
unsigned char *d = dst; |
|---|
| 200 |
if (*c != ':') z = (unsigned short*)0; |
|---|
| 201 |
else if (*++c != ':') return 0; |
|---|
| 202 |
else ++c, z = a; |
|---|
| 203 |
i = 0; |
|---|
| 204 |
for(;;) { |
|---|
| 205 |
v = 0; |
|---|
| 206 |
sc = c; |
|---|
| 207 |
for(;;) { |
|---|
| 208 |
if (*c >= '0' && *c <= '9') o = *c - '0'; |
|---|
| 209 |
else if (*c >= 'a' && *c <= 'f') o = *c - 'a' + 10; |
|---|
| 210 |
else if (*c >= 'A' && *c <= 'F') o = *c - 'A' + 10; |
|---|
| 211 |
else break; |
|---|
| 212 |
v = (v << 4) | o; |
|---|
| 213 |
if (v > 0xffff) return 0; |
|---|
| 214 |
++c; |
|---|
| 215 |
} |
|---|
| 216 |
if (sc == c) { |
|---|
| 217 |
if (z == a && !*c) |
|---|
| 218 |
break; |
|---|
| 219 |
else |
|---|
| 220 |
return 0; |
|---|
| 221 |
} |
|---|
| 222 |
if (*c == ':') { |
|---|
| 223 |
if (a >= w + 8) |
|---|
| 224 |
return 0; |
|---|
| 225 |
*a++ = v; |
|---|
| 226 |
if (*++c == ':') { |
|---|
| 227 |
if (z) |
|---|
| 228 |
return 0; |
|---|
| 229 |
z = a; |
|---|
| 230 |
if (!*++c) |
|---|
| 231 |
break; |
|---|
| 232 |
} |
|---|
| 233 |
} |
|---|
| 234 |
else if (!*c) { |
|---|
| 235 |
if (a >= w + 8) |
|---|
| 236 |
return 0; |
|---|
| 237 |
*a++ = v; |
|---|
| 238 |
break; |
|---|
| 239 |
} |
|---|
| 240 |
else if (*c == '.') { |
|---|
| 241 |
if (a > w + 6) |
|---|
| 242 |
return 0; |
|---|
| 243 |
if (!mjt_pton4(sc, d)) |
|---|
| 244 |
return 0; |
|---|
| 245 |
*a++ = ((unsigned)(d[0]) << 8) | d[1]; |
|---|
| 246 |
*a++ = ((unsigned)(d[2]) << 8) | d[3]; |
|---|
| 247 |
break; |
|---|
| 248 |
} |
|---|
| 249 |
else |
|---|
| 250 |
return 0; |
|---|
| 251 |
} |
|---|
| 252 |
v = w + 8 - a; |
|---|
| 253 |
if ((v && !z) || (!v && z)) |
|---|
| 254 |
return 0; |
|---|
| 255 |
for(i = w; ; ++i) { |
|---|
| 256 |
if (i == z) |
|---|
| 257 |
while(v--) { *d++ = '\0'; *d++ = '\0'; } |
|---|
| 258 |
if (i >= a) |
|---|
| 259 |
break; |
|---|
| 260 |
*d++ = (unsigned char)((*i >> 8) & 255); |
|---|
| 261 |
*d++ = (unsigned char)(*i & 255); |
|---|
| 262 |
} |
|---|
| 263 |
return 1; |
|---|
| 264 |
} |
|---|
| 265 |
|
|---|
| 266 |
inet_XtoX_decl int fn(pton)(int af, const char *src, void *dst) { |
|---|
| 267 |
switch(af) { |
|---|
| 268 |
/* don't use AF_*: don't mess with headers */ |
|---|
| 269 |
case 2 /* AF_INET */: return mjt_pton4(src, dst); |
|---|
| 270 |
case 10 /* AF_INET6 */: return mjt_pton6(src, dst); |
|---|
| 271 |
default: errno = EAFNOSUPPORT; return -1; |
|---|
| 272 |
} |
|---|
| 273 |
} |
|---|
| 274 |
|
|---|
| 275 |
inet_XtoX_decl int fn(aton)(const char *src, struct in_addr *addr) { |
|---|
| 276 |
return mjt_pton4(src, addr); |
|---|
| 277 |
} |
|---|
| 278 |
|
|---|
| 279 |
#endif /* inet_XtoX_prototypes */ |
|---|
| 280 |
|
|---|
| 281 |
#endif /* inet_XtoX_no_pton */ |
|---|
| 282 |
|
|---|
| 283 |
#ifdef TEST |
|---|
| 284 |
|
|---|
| 285 |
int main(int argc, char **argv) { |
|---|
| 286 |
int i; |
|---|
| 287 |
char n0[16], n1[16]; |
|---|
| 288 |
char p0[64], p1[64]; |
|---|
| 289 |
int af = AF_INET; |
|---|
| 290 |
int pl = sizeof(p0); |
|---|
| 291 |
int r0, r1; |
|---|
| 292 |
const char *s0, *s1; |
|---|
| 293 |
|
|---|
| 294 |
while((i = getopt(argc, argv, "46a:p:")) != EOF) switch(i) { |
|---|
| 295 |
case '4': af = AF_INET; break; |
|---|
| 296 |
case '6': af = AF_INET6; break; |
|---|
| 297 |
case 'a': case 'p': pl = atoi(optarg); break; |
|---|
| 298 |
default: return 1; |
|---|
| 299 |
} |
|---|
| 300 |
for(i = optind; i < argc; ++i) { |
|---|
| 301 |
char *a = argv[i]; |
|---|
| 302 |
|
|---|
| 303 |
printf("%s:\n", a); |
|---|
| 304 |
r0 = inet_pton(af, a, n0); |
|---|
| 305 |
printf(" p2n stock: %s\n", |
|---|
| 306 |
(r0 < 0 ? "(notsupp)" : !r0 ? "(inval)" : fn(ntop)(af,n0,p0,sizeof(p0)))); |
|---|
| 307 |
r1 = fn(pton)(af, a, n1); |
|---|
| 308 |
printf(" p2n this : %s\n", |
|---|
| 309 |
(r1 < 0 ? "(notsupp)" : !r1 ? "(inval)" : fn(ntop)(af,n1,p1,sizeof(p1)))); |
|---|
| 310 |
|
|---|
| 311 |
if ((r0 > 0) != (r1 > 0) || |
|---|
| 312 |
(r0 > 0 && r1 > 0 && memcmp(n0, n1, af == AF_INET ? 4 : 16) != 0)) |
|---|
| 313 |
printf(" DIFFER!\n"); |
|---|
| 314 |
|
|---|
| 315 |
s0 = inet_ntop(af, n1, p0, pl); |
|---|
| 316 |
printf(" n2p stock: %s\n", s0 ? s0 : "(inval)"); |
|---|
| 317 |
s1 = fn(ntop)(af, n1, p1, pl); |
|---|
| 318 |
printf(" n2p this : %s\n", s1 ? s1 : "(inval)"); |
|---|
| 319 |
if ((s0 != 0) != (s1 != 0) || |
|---|
| 320 |
(s0 && s1 && strcmp(s0, s1) != 0)) |
|---|
| 321 |
printf(" DIFFER!\n"); |
|---|
| 322 |
|
|---|
| 323 |
} |
|---|
| 324 |
return 0; |
|---|
| 325 |
} |
|---|
| 326 |
|
|---|
| 327 |
#endif /* TEST */ |
|---|