ipaddrparse.c 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220
  1. /*
  2. * Part of Very Secure FTPd
  3. * Licence: GPL v2
  4. * Author: Chris Evans
  5. * ipaddrparse.c
  6. *
  7. * A routine to parse ip addresses. I'm paranoid and don't want to use
  8. * inet_pton.
  9. */
  10. #include "ipaddrparse.h"
  11. #include "sysutil.h"
  12. #include "str.h"
  13. static int ipv6_parse_main(struct mystr* p_out_str,
  14. const struct mystr* p_in_str);
  15. static int ipv6_parse_hex(struct mystr* p_out_str,
  16. const struct mystr* p_in_str);
  17. static int ipv4_parse_dotquad(struct mystr* p_out_str,
  18. const struct mystr* p_in_str);
  19. const unsigned char*
  20. vsf_sysutil_parse_ipv6(const struct mystr* p_str)
  21. {
  22. static struct mystr s_ret;
  23. static struct mystr s_rhs_ret;
  24. static struct mystr s_lhs_str;
  25. static struct mystr s_rhs_str;
  26. unsigned int lhs_len;
  27. unsigned int rhs_len;
  28. str_empty(&s_ret);
  29. str_empty(&s_rhs_ret);
  30. str_copy(&s_lhs_str, p_str);
  31. str_split_text(&s_lhs_str, &s_rhs_str, "::");
  32. if (!ipv6_parse_main(&s_ret, &s_lhs_str))
  33. {
  34. return 0;
  35. }
  36. if (!ipv6_parse_main(&s_rhs_ret, &s_rhs_str))
  37. {
  38. return 0;
  39. }
  40. lhs_len = str_getlen(&s_ret);
  41. rhs_len = str_getlen(&s_rhs_ret);
  42. if (lhs_len + rhs_len > 16)
  43. {
  44. return 0;
  45. }
  46. if (rhs_len > 0)
  47. {
  48. unsigned int add_nulls = 16 - (lhs_len + rhs_len);
  49. while (add_nulls--)
  50. {
  51. str_append_char(&s_ret, '\0');
  52. }
  53. str_append_str(&s_ret, &s_rhs_ret);
  54. }
  55. return (const unsigned char*) str_getbuf(&s_ret);
  56. }
  57. const unsigned char*
  58. vsf_sysutil_parse_ipv4(const struct mystr* p_str)
  59. {
  60. static unsigned char items[4];
  61. return vsf_sysutil_parse_uchar_string_sep(p_str, '.', items, sizeof(items));
  62. }
  63. const unsigned char*
  64. vsf_sysutil_parse_uchar_string_sep(
  65. const struct mystr* p_str, char sep, unsigned char* p_items,
  66. unsigned int items)
  67. {
  68. static struct mystr s_tmp_str;
  69. unsigned int i;
  70. str_copy(&s_tmp_str, p_str);
  71. for (i=0; i<items; i++)
  72. {
  73. static struct mystr s_rhs_sep_str;
  74. int this_number;
  75. /* This puts a single separator delimited field in tmp_str */
  76. str_split_char(&s_tmp_str, &s_rhs_sep_str, sep);
  77. /* Sanity - check for too many or two few dots! */
  78. if ( (i < (items-1) && str_isempty(&s_rhs_sep_str)) ||
  79. (i == (items-1) && !str_isempty(&s_rhs_sep_str)))
  80. {
  81. return 0;
  82. }
  83. this_number = str_atoi(&s_tmp_str);
  84. if (this_number < 0 || this_number > 255)
  85. {
  86. return 0;
  87. }
  88. /* If this truncates from int to uchar, we don't care */
  89. p_items[i] = (unsigned char) this_number;
  90. /* The right hand side of the comma now becomes the new string to
  91. * breakdown
  92. */
  93. str_copy(&s_tmp_str, &s_rhs_sep_str);
  94. }
  95. return p_items;
  96. }
  97. static int
  98. ipv6_parse_main(struct mystr* p_out_str, const struct mystr* p_in_str)
  99. {
  100. static struct mystr s_lhs_str;
  101. static struct mystr s_rhs_str;
  102. struct str_locate_result loc_ret;
  103. str_copy(&s_lhs_str, p_in_str);
  104. while (!str_isempty(&s_lhs_str))
  105. {
  106. str_split_char(&s_lhs_str, &s_rhs_str, ':');
  107. if (str_isempty(&s_lhs_str))
  108. {
  109. return 0;
  110. }
  111. loc_ret = str_locate_char(&s_lhs_str, '.');
  112. if (loc_ret.found)
  113. {
  114. if (!ipv4_parse_dotquad(p_out_str, &s_lhs_str))
  115. {
  116. return 0;
  117. }
  118. }
  119. else if (!ipv6_parse_hex(p_out_str, &s_lhs_str))
  120. {
  121. return 0;
  122. }
  123. str_copy(&s_lhs_str, &s_rhs_str);
  124. }
  125. return 1;
  126. }
  127. static int
  128. ipv6_parse_hex(struct mystr* p_out_str, const struct mystr* p_in_str)
  129. {
  130. unsigned int len = str_getlen(p_in_str);
  131. unsigned int i;
  132. unsigned int val = 0;
  133. for (i=0; i<len; ++i)
  134. {
  135. int ch = vsf_sysutil_toupper(str_get_char_at(p_in_str, i));
  136. if (ch >= '0' && ch <= '9')
  137. {
  138. ch -= '0';
  139. }
  140. else if (ch >= 'A' && ch <= 'F')
  141. {
  142. ch -= 'A';
  143. ch += 10;
  144. }
  145. else
  146. {
  147. return 0;
  148. }
  149. val <<= 4;
  150. val |= ch;
  151. if (val > 0xFFFF)
  152. {
  153. return 0;
  154. }
  155. }
  156. str_append_char(p_out_str, (val >> 8));
  157. str_append_char(p_out_str, (val & 0xFF));
  158. return 1;
  159. }
  160. static int
  161. ipv4_parse_dotquad(struct mystr* p_out_str, const struct mystr* p_in_str)
  162. {
  163. unsigned int len = str_getlen(p_in_str);
  164. unsigned int i;
  165. unsigned int val = 0;
  166. unsigned int final_val = 0;
  167. int seen_char = 0;
  168. int dots = 0;
  169. for (i=0; i<len; ++i)
  170. {
  171. int ch = str_get_char_at(p_in_str, i);
  172. if (ch == '.')
  173. {
  174. if (!seen_char || dots == 3)
  175. {
  176. return 0;
  177. }
  178. seen_char = 0;
  179. dots++;
  180. final_val <<= 8;
  181. final_val |= val;
  182. val = 0;
  183. }
  184. else if (ch >= '0' && ch <= '9')
  185. {
  186. ch -= '0';
  187. val *= 10;
  188. val += ch;
  189. if (val > 255)
  190. {
  191. return 0;
  192. }
  193. seen_char = 1;
  194. }
  195. else
  196. {
  197. return 0;
  198. }
  199. }
  200. if (dots != 3 || !seen_char)
  201. {
  202. return 0;
  203. }
  204. final_val <<= 8;
  205. final_val |= val;
  206. str_append_char(p_out_str, (final_val >> 24));
  207. str_append_char(p_out_str, ((final_val >> 16) & 0xFF));
  208. str_append_char(p_out_str, ((final_val >> 8) & 0xFF));
  209. str_append_char(p_out_str, (final_val & 0xFF));
  210. return 1;
  211. }