ipv4.c 5.6 KB

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