parseip.c 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  1. #include <u.h>
  2. #include <libc.h>
  3. #include <ctype.h>
  4. #include <ip.h>
  5. char*
  6. v4parseip(uchar *to, char *from)
  7. {
  8. int i;
  9. char *p;
  10. p = from;
  11. for(i = 0; i < 4 && *p; i++){
  12. to[i] = strtoul(p, &p, 0);
  13. if(*p == '.')
  14. p++;
  15. }
  16. switch(CLASS(to)){
  17. case 0: /* class A - 1 uchar net */
  18. case 1:
  19. if(i == 3){
  20. to[3] = to[2];
  21. to[2] = to[1];
  22. to[1] = 0;
  23. } else if (i == 2){
  24. to[3] = to[1];
  25. to[1] = 0;
  26. }
  27. break;
  28. case 2: /* class B - 2 uchar net */
  29. if(i == 3){
  30. to[3] = to[2];
  31. to[2] = 0;
  32. }
  33. break;
  34. }
  35. return p;
  36. }
  37. static int
  38. ipcharok(int c)
  39. {
  40. return c == '.' || c == ':' || isascii(c) && isxdigit(c);
  41. }
  42. static int
  43. delimchar(int c)
  44. {
  45. if(c == '\0')
  46. return 1;
  47. if(c == '.' || c == ':' || isascii(c) && isalnum(c))
  48. return 0;
  49. return 1;
  50. }
  51. /*
  52. * `from' may contain an address followed by other characters,
  53. * at least in /boot, so we permit whitespace (and more) after the address.
  54. * we do ensure that "delete" cannot be parsed as "de::".
  55. *
  56. * some callers don't check the return value for errors, so
  57. * set `to' to something distinctive in the case of a parse error.
  58. */
  59. vlong
  60. parseip(uchar *to, char *from)
  61. {
  62. int i, elipsis = 0, v4 = 1;
  63. ulong x;
  64. char *p, *op;
  65. memset(to, 0, IPaddrlen);
  66. p = from;
  67. for(i = 0; i < IPaddrlen && ipcharok(*p); i+=2){
  68. op = p;
  69. x = strtoul(p, &p, 16);
  70. if(*p == '.' || (*p == 0 && i == 0)){ /* ends with v4? */
  71. p = v4parseip(to+i, op);
  72. i += 4;
  73. break;
  74. }
  75. /* v6: at most 4 hex digits, followed by colon or delim */
  76. if(x != (ushort)x || *p != ':' && !delimchar(*p)) {
  77. memset(to, 0, IPaddrlen);
  78. return -1; /* parse error */
  79. }
  80. to[i] = x>>8;
  81. to[i+1] = x;
  82. if(*p == ':'){
  83. v4 = 0;
  84. if(*++p == ':'){ /* :: is elided zero short(s) */
  85. if (elipsis) {
  86. memset(to, 0, IPaddrlen);
  87. return -1; /* second :: */
  88. }
  89. elipsis = i+2;
  90. p++;
  91. }
  92. } else if (p == op) /* strtoul made no progress? */
  93. break;
  94. }
  95. if (p == from || !delimchar(*p)) {
  96. memset(to, 0, IPaddrlen);
  97. return -1; /* parse error */
  98. }
  99. if(i < IPaddrlen){
  100. memmove(&to[elipsis+IPaddrlen-i], &to[elipsis], i-elipsis);
  101. memset(&to[elipsis], 0, IPaddrlen-i);
  102. }
  103. if(v4){
  104. to[10] = to[11] = 0xff;
  105. return nhgetl(to + IPv4off);
  106. } else
  107. return 6;
  108. }
  109. /*
  110. * hack to allow ip v4 masks to be entered in the old
  111. * style
  112. */
  113. vlong
  114. parseipmask(uchar *to, char *from)
  115. {
  116. int i, w;
  117. vlong x;
  118. uchar *p;
  119. if(*from == '/'){
  120. /* as a number of prefix bits */
  121. i = atoi(from+1);
  122. if(i < 0)
  123. i = 0;
  124. if(i > 128)
  125. i = 128;
  126. w = i;
  127. memset(to, 0, IPaddrlen);
  128. for(p = to; i >= 8; i -= 8)
  129. *p++ = 0xff;
  130. if(i > 0)
  131. *p = ~((1<<(8-i))-1);
  132. x = nhgetl(to+IPv4off);
  133. /*
  134. * identify as ipv6 if the mask is inexpressible as a v4 mask
  135. * (because it has too few mask bits). Arguably, we could
  136. * always return 6 here.
  137. */
  138. if (w < 8*(IPaddrlen-IPv4addrlen))
  139. return 6;
  140. } else {
  141. /* as a straight v4 bit mask */
  142. x = parseip(to, from);
  143. if (x != -1)
  144. x = (ulong)nhgetl(to + IPv4off);
  145. if(memcmp(to, v4prefix, IPv4off) == 0)
  146. memset(to, 0xff, IPv4off);
  147. }
  148. return x;
  149. }
  150. /*
  151. * parse a v4 ip address/mask in cidr format
  152. */
  153. char*
  154. v4parsecidr(uchar *addr, uchar *mask, char *from)
  155. {
  156. int i;
  157. char *p;
  158. uchar *a;
  159. p = v4parseip(addr, from);
  160. if(*p == '/'){
  161. /* as a number of prefix bits */
  162. i = strtoul(p+1, &p, 0);
  163. if(i > 32)
  164. i = 32;
  165. memset(mask, 0, IPv4addrlen);
  166. for(a = mask; i >= 8; i -= 8)
  167. *a++ = 0xff;
  168. if(i > 0)
  169. *a = ~((1<<(8-i))-1);
  170. } else
  171. memcpy(mask, defmask(addr), IPv4addrlen);
  172. return p;
  173. }