You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

327 lines
7.8 KiB

  1. /* inet_XtoX.c
  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. #ifdef inet_XtoX_prototypes
  27. struct in_addr;
  28. #else
  29. #include <errno.h>
  30. #ifdef TEST
  31. # include <netinet/in.h>
  32. # include <sys/socket.h>
  33. # include <arpa/inet.h>
  34. # include <stdio.h>
  35. # include <stdlib.h>
  36. # include <unistd.h>
  37. # include <string.h>
  38. # undef inet_XtoX_prefix
  39. # define inet_XtoX_prefix mjt_inet_
  40. # undef inet_XtoX_no_ntop
  41. # undef inet_XtoX_no_pton
  42. #else /* !TEST */
  43. struct in_addr { /* declare it here to avoid messing with headers */
  44. unsigned char x[4];
  45. };
  46. #endif /* TEST */
  47. #endif /* inet_XtoX_prototypes */
  48. #ifndef inet_XtoX_prefix
  49. # define inet_XtoX_prefix inet_
  50. #endif
  51. #ifndef inet_XtoX_decl
  52. # define inet_XtoX_decl /*empty*/
  53. #endif
  54. #define cc2_(x,y) cc2__(x,y)
  55. #define cc2__(x,y) x##y
  56. #define fn(x) cc2_(inet_XtoX_prefix,x)
  57. #ifndef inet_XtoX_no_ntop
  58. inet_XtoX_decl const char *
  59. fn(ntop)(int af, const void *src, char *dst, unsigned size);
  60. #ifndef inet_XtoX_prototypes
  61. static int mjt_ntop4(const void *_src, char *dst, int size) {
  62. unsigned i, x, r;
  63. char *p;
  64. const unsigned char *s = _src;
  65. if (size < 4*4) /* for simplicity, disallow non-max-size buffer */
  66. return 0;
  67. for (i = 0, p = dst; i < 4; ++i) {
  68. if (i) *p++ = '.';
  69. x = r = s[i];
  70. if (x > 99) { *p++ = (char)(r / 100 + '0'); r %= 100; }
  71. if (x > 9) { *p++ = (char)(r / 10 + '0'); r %= 10; }
  72. *p++ = (char)(r + '0');
  73. }
  74. *p = '\0';
  75. return 1;
  76. }
  77. static char *hexc(char *p, unsigned x) {
  78. static char hex[16] = "0123456789abcdef";
  79. if (x > 0x0fff) *p++ = hex[(x >>12) & 15];
  80. if (x > 0x00ff) *p++ = hex[(x >> 8) & 15];
  81. if (x > 0x000f) *p++ = hex[(x >> 4) & 15];
  82. *p++ = hex[x & 15];
  83. return p;
  84. }
  85. static int mjt_ntop6(const void *_src, char *dst, int size) {
  86. unsigned i;
  87. unsigned short w[8];
  88. unsigned bs = 0, cs = 0;
  89. unsigned bl = 0, cl = 0;
  90. char *p;
  91. const unsigned char *s = _src;
  92. if (size < 40) /* for simplicity, disallow non-max-size buffer */
  93. return 0;
  94. for(i = 0; i < 8; ++i, s += 2) {
  95. w[i] = (((unsigned short)(s[0])) << 8) | s[1];
  96. if (!w[i]) {
  97. if (!cl++) cs = i;
  98. }
  99. else {
  100. if (cl > bl) bl = cl, bs = cs;
  101. }
  102. }
  103. if (cl > bl) bl = cl, bs = cs;
  104. p = dst;
  105. if (bl == 1)
  106. bl = 0;
  107. if (bl) {
  108. for(i = 0; i < bs; ++i) {
  109. if (i) *p++ = ':';
  110. p = hexc(p, w[i]);
  111. }
  112. *p++ = ':';
  113. i += bl;
  114. if (i == 8)
  115. *p++ = ':';
  116. }
  117. else
  118. i = 0;
  119. for(; i < 8; ++i) {
  120. if (i) *p++ = ':';
  121. if (i == 6 && !bs && (bl == 6 || (bl == 5 && w[5] == 0xffff)))
  122. return mjt_ntop4(s - 4, p, size - (p - dst));
  123. p = hexc(p, w[i]);
  124. }
  125. *p = '\0';
  126. return 1;
  127. }
  128. inet_XtoX_decl const char *
  129. fn(ntop)(int af, const void *src, char *dst, unsigned size) {
  130. switch(af) {
  131. /* don't use AF_*: don't mess with headers */
  132. case 2: /* AF_INET */ if (mjt_ntop4(src, dst, size)) return dst; break;
  133. case 10: /* AF_INET6 */ if (mjt_ntop6(src, dst, size)) return dst; break;
  134. default: errno = EAFNOSUPPORT; return (char*)0;
  135. }
  136. errno = ENOSPC;
  137. return (char*)0;
  138. }
  139. inet_XtoX_decl const char *
  140. fn(ntoa)(struct in_addr addr) {
  141. static char buf[4*4];
  142. mjt_ntop4(&addr, buf, sizeof(buf));
  143. return buf;
  144. }
  145. #endif /* inet_XtoX_prototypes */
  146. #endif /* inet_XtoX_no_ntop */
  147. #ifndef inet_XtoX_no_pton
  148. inet_XtoX_decl int fn(pton)(int af, const char *src, void *dst);
  149. inet_XtoX_decl int fn(aton)(const char *src, struct in_addr *addr);
  150. #ifndef inet_XtoX_prototypes
  151. static int mjt_pton4(const char *c, void *dst) {
  152. unsigned char *a = dst;
  153. unsigned n, o;
  154. for (n = 0; n < 4; ++n) {
  155. if (*c < '0' || *c > '9')
  156. return 0;
  157. o = *c++ - '0';
  158. while(*c >= '0' && *c <= '9')
  159. if ((o = o * 10 + (*c++ - '0')) > 255)
  160. return 0;
  161. if (*c++ != (n == 3 ? '\0' : '.'))
  162. return 0;
  163. *a++ = (unsigned char)o;
  164. }
  165. return 1;
  166. }
  167. static int mjt_pton6(const char *c, void *dst) {
  168. unsigned short w[8], *a = w, *z, *i;
  169. unsigned v, o;
  170. const char *sc;
  171. unsigned char *d = dst;
  172. if (*c != ':') z = (unsigned short*)0;
  173. else if (*++c != ':') return 0;
  174. else ++c, z = a;
  175. i = 0;
  176. for(;;) {
  177. v = 0;
  178. sc = c;
  179. for(;;) {
  180. if (*c >= '0' && *c <= '9') o = *c - '0';
  181. else if (*c >= 'a' && *c <= 'f') o = *c - 'a' + 10;
  182. else if (*c >= 'A' && *c <= 'F') o = *c - 'A' + 10;
  183. else break;
  184. v = (v << 4) | o;
  185. if (v > 0xffff) return 0;
  186. ++c;
  187. }
  188. if (sc == c) {
  189. if (z == a && !*c)
  190. break;
  191. else
  192. return 0;
  193. }
  194. if (*c == ':') {
  195. if (a >= w + 8)
  196. return 0;
  197. *a++ = v;
  198. if (*++c == ':') {
  199. if (z)
  200. return 0;
  201. z = a;
  202. if (!*++c)
  203. break;
  204. }
  205. }
  206. else if (!*c) {
  207. if (a >= w + 8)
  208. return 0;
  209. *a++ = v;
  210. break;
  211. }
  212. else if (*c == '.') {
  213. if (a > w + 6)
  214. return 0;
  215. if (!mjt_pton4(sc, d))
  216. return 0;
  217. *a++ = ((unsigned)(d[0]) << 8) | d[1];
  218. *a++ = ((unsigned)(d[2]) << 8) | d[3];
  219. break;
  220. }
  221. else
  222. return 0;
  223. }
  224. v = w + 8 - a;
  225. if ((v && !z) || (!v && z))
  226. return 0;
  227. for(i = w; ; ++i) {
  228. if (i == z)
  229. while(v--) { *d++ = '\0'; *d++ = '\0'; }
  230. if (i >= a)
  231. break;
  232. *d++ = (unsigned char)((*i >> 8) & 255);
  233. *d++ = (unsigned char)(*i & 255);
  234. }
  235. return 1;
  236. }
  237. inet_XtoX_decl int fn(pton)(int af, const char *src, void *dst) {
  238. switch(af) {
  239. /* don't use AF_*: don't mess with headers */
  240. case 2 /* AF_INET */: return mjt_pton4(src, dst);
  241. case 10 /* AF_INET6 */: return mjt_pton6(src, dst);
  242. default: errno = EAFNOSUPPORT; return -1;
  243. }
  244. }
  245. inet_XtoX_decl int fn(aton)(const char *src, struct in_addr *addr) {
  246. return mjt_pton4(src, addr);
  247. }
  248. #endif /* inet_XtoX_prototypes */
  249. #endif /* inet_XtoX_no_pton */
  250. #ifdef TEST
  251. int main(int argc, char **argv) {
  252. int i;
  253. char n0[16], n1[16];
  254. char p0[64], p1[64];
  255. int af = AF_INET;
  256. int pl = sizeof(p0);
  257. int r0, r1;
  258. const char *s0, *s1;
  259. while((i = getopt(argc, argv, "46a:p:")) != EOF) switch(i) {
  260. case '4': af = AF_INET; break;
  261. case '6': af = AF_INET6; break;
  262. case 'a': case 'p': pl = atoi(optarg); break;
  263. default: return 1;
  264. }
  265. for(i = optind; i < argc; ++i) {
  266. char *a = argv[i];
  267. printf("%s:\n", a);
  268. r0 = inet_pton(af, a, n0);
  269. printf(" p2n stock: %s\n",
  270. (r0 < 0 ? "(notsupp)" : !r0 ? "(inval)" : fn(ntop)(af,n0,p0,sizeof(p0))));
  271. r1 = fn(pton)(af, a, n1);
  272. printf(" p2n this : %s\n",
  273. (r1 < 0 ? "(notsupp)" : !r1 ? "(inval)" : fn(ntop)(af,n1,p1,sizeof(p1))));
  274. if ((r0 > 0) != (r1 > 0) ||
  275. (r0 > 0 && r1 > 0 && memcmp(n0, n1, af == AF_INET ? 4 : 16) != 0))
  276. printf(" DIFFER!\n");
  277. s0 = inet_ntop(af, n1, p0, pl);
  278. printf(" n2p stock: %s\n", s0 ? s0 : "(inval)");
  279. s1 = fn(ntop)(af, n1, p1, pl);
  280. printf(" n2p this : %s\n", s1 ? s1 : "(inval)");
  281. if ((s0 != 0) != (s1 != 0) ||
  282. (s0 && s1 && strcmp(s0, s1) != 0))
  283. printf(" DIFFER!\n");
  284. }
  285. return 0;
  286. }
  287. #endif /* TEST */