ipv4.c 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. // SPDX-License-Identifier: GPL-3.0-or-later
  2. // Copyright © 2019 Ariadne Devos
  3. #include <stdbool.h>
  4. #include <stdio.h>
  5. #include <stdlib.h>
  6. #include <string.h>
  7. #include <sHT/logic/failbit.h>
  8. #include <sHT/lex/ipv4-addr.h>
  9. #define BADIP UINT32_C(0)
  10. #define success(a) sHT_success(size_t, a)
  11. #define failure(a) sHT_fail(size_t, a)
  12. static const struct testcase
  13. {
  14. uint8_t m[32];
  15. size_t length;
  16. sHT_with_failbit
  17. size_t end;
  18. uint32_t ip;
  19. } cases[] = {
  20. /* mappend, first digit, last digit*/
  21. { "_0.0.0.19", 8, success(8), UINT32_C(0x00000001) },
  22. { "_1.0.0.79", 8, success(8), UINT32_C(0x01000007) },
  23. { "_2.0.0.29", 8, success(8), UINT32_C(0x02000002) },
  24. { "_9.0.0.39", 8, success(8), UINT32_C(0x09000003) },
  25. /* large digits */
  26. { "_255.250.199.99", 15, success(16), UINT32_C(0xfffac763) },
  27. { "_99.255.250.199", 15, success(16), UINT32_C(0x63fffac7) },
  28. { "_199.99.255.250", 15, success(16), UINT32_C(0xc763fffa) },
  29. { "_199.99.99.2500", 15, success(15), UINT32_C(0xc763fffa) },
  30. { "_256.250.199.99", 15, failure(15), BADIP },
  31. { "_255.260.199.99", 15, failure(15), BADIP },
  32. { "_255.300.199.99", 15, failure(15), BADIP },
  33. { "_25@.250.199.99", 15, failure(3), BADIP },
  34. { "_255.250.199.@9", 15, failure(13), BADIP },
  35. { "_255@250.199.99", 15, failure(4), BADIP },
  36. /* leading zeroes */
  37. { "_01.23.23.23", 12, failure(12), BADIP },
  38. { "_10.023.23.23", 13, failure(13), BADIP },
  39. { "_10.003.23.23", 13, failure(13), BADIP },
  40. { "_10.000.23.23", 13, failure(13), BADIP },
  41. { "_10.0000.23.23", 14, failure(14), BADIP },
  42. /* overly many repetitions */
  43. { "_255.250.199.99.20", 18, success(16), UINT32_C(0xfffac763) },
  44. { "_99.255.250.199.20", 18, success(16), UINT32_C(0x63fffac7) },
  45. { "_199.99.255.250.20", 18, success(16), UINT32_C(0xc763fffa) },
  46. { "_199.99.99.2500.20", 18, success(15), UINT32_C(0xc763fffa) },
  47. { "_255.250.199.99@20", 18, success(16), UINT32_C(0xfffac763) },
  48. { "_99.255.250.199@20", 18, success(16), UINT32_C(0x63fffac7) },
  49. { "_199.99.255.250@20", 18, success(16), UINT32_C(0xc763fffa) },
  50. { "_199.99.99.2500@20", 18, success(15), UINT32_C(0xc763fffa) },
  51. /* off-by-one digit tests */
  52. { "_0.0.0.0", 8, success(8), UINT32_C(0x00000000) },
  53. { "_1.0.0.0", 8, success(8), UINT32_C(0x01000000) },
  54. { "_2.0.0.0", 8, success(8), UINT32_C(0x02000000) },
  55. { "_9.0.0.0", 8, success(8), UINT32_C(0x09000000) },
  56. { "_/.0.0.0", 8, failure(1), BADIP },
  57. { "_:.0.0.0", 8, failure(1), BADIP },
  58. { "_1/.0.0.0", 9, failure(2), BADIP },
  59. { "_1:.0.0.0", 9, failure(2), BADIP },
  60. { "_10/.0.0.0", 10, failure(3), BADIP },
  61. { "_10:.0.0.0", 10, failure(3), BADIP },
  62. /* Check 2 > length - i.
  63. (The trailing octet is not within specified bounds,
  64. so it may not be parsed, as is the leading '0')
  65. In case of 1 > length - i, the first digit of the last octet
  66. is accessed out-of-bounds, but that's ‘corrected’ by
  67. sHT_index_nospec to the first byte of the string*/
  68. { "01.2.3.", 7, failure(7), BADIP },
  69. { "01.2.30.", 7, failure(7), BADIP },
  70. { "01.2.30.", 7, failure(7), BADIP },
  71. { "010.2.3.", 8, failure(8), BADIP },
  72. { "010.2.30.", 8, failure(8), BADIP },
  73. { "010.20.3.", 9, failure(9), BADIP },
  74. { "010.20.30.", 9, failure(9), BADIP },
  75. { "010.20.25.", 10, failure(10), BADIP },
  76. { "010.20.255.", 10, failure(10), BADIP },
  77. { "010.20.254.", 11, failure(11), BADIP },
  78. { "010.20.255.", 11, failure(11), BADIP },
  79. { "010.20.256.", 11, failure(11), BADIP },
  80. /* too early EOF */
  81. { "_0.0.255.", 9, failure(10), BADIP },
  82. { "_0.0.20.", 8, failure(9), BADIP },
  83. { "_20.0.0.", 8, failure(9), BADIP },
  84. { "_0.10.255", 9, failure(10), BADIP },
  85. { "_0.10.20", 8, failure(9), BADIP },
  86. { "_20.10.0", 8, failure(9), BADIP },
  87. /* empty */
  88. { "0", 1, failure(1), BADIP },
  89. { "_", 1, failure(1), BADIP },
  90. { "_0", 2, failure(2), BADIP },
  91. { "_0.", 3, failure(3), BADIP },
  92. { "_0.1", 4, failure(4), BADIP },
  93. { "_0.12", 5, failure(5), BADIP },
  94. { "_0.12.", 6, failure(6), BADIP },
  95. { "_0.12.2", 7, failure(8), BADIP },
  96. };
  97. #define ARRAY_SIZE(a) ((sizeof(a) / sizeof(*(a))))
  98. _Noreturn void
  99. fail(size_t i)
  100. {
  101. if (printf("FAIL: ipv4 (%d)\n", (unsigned) i) < 0)
  102. exit(2);
  103. exit(1);
  104. }
  105. int
  106. main(void)
  107. {
  108. for (size_t i = 0; i < ARRAY_SIZE(cases); i++) {
  109. struct s2_ipv4_maybe ret;
  110. ret = s2_parse_ipv4(cases[i].length, cases[i].m);
  111. /* out-of-bounds */
  112. if (sHT_fail_value(size_t, ret.end) > cases[i].length)
  113. fail(i);
  114. if (sHT_bad(size_t, ret.end)) {
  115. if (sHT_good(size_t, cases[i].end))
  116. fail(i);
  117. /* (z): *at least* up to (>, not =) fail_value(ret.end), [0-9.] */
  118. if (sHT_fail_value(size_t, ret.end) > sHT_fail_value(size_t, cases[i].end))
  119. fail(i);
  120. goto compare_longer_inputs;
  121. }
  122. /* Synthetise input from output, check with reference input*/
  123. char ipcheck[32];
  124. if (sHT_fail_value(size_t, ret.end) - 1 != (size_t) sprintf(ipcheck, "%d.%d.%d.%d", ret.ip >> 24, (ret.ip >> 16) & 0xff, (ret.ip >> 8) & 0xff, ret.ip & 0xff))
  125. /* length does not agree */
  126. fail(i);
  127. if (memcmp(cases[i].m + 1, ipcheck, sHT_fail_value(size_t, ret.end) - 1)) {
  128. /* bytes do not agree */
  129. fail(i);
  130. }
  131. compare_longer_inputs:
  132. for (size_t d = sHT_fail_value(size_t, ret.end) + 1; d <= sHT_fail_value(size_t, cases[i].length); d++) {
  133. struct s2_ipv4_maybe alt = s2_parse_ipv4(d, cases[i].m);
  134. /* Check failbit for equality */
  135. if ((ret.end ^ alt.end) & sHT_failbit_limit(size_t))
  136. fail(i);
  137. /* Check parsing doesn't end too late */
  138. if (sHT_fail_value(size_t, alt.end) <= sHT_fail_value(size_t, cases[i].end))
  139. /* If at all, there is only one way to parse it. */
  140. if (sHT_good(size_t, ret.end) && (ret.end != alt.end))
  141. fail(i);
  142. /* Check numeric IPv4Address */
  143. if (sHT_good(size_t, ret.end) && (ret.ip != alt.ip))
  144. fail(i);
  145. }
  146. }
  147. if (printf("PASS: ipv4\n") < 2)
  148. exit(2);
  149. return 0;
  150. }