01-ip.cpp 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245
  1. #include "limbo/ip/state.hpp"
  2. #include "test-utils.h"
  3. using namespace limbo;
  4. uint8_t example_raw[]{
  5. 0x45, 0x00, 0x00, 0x38, 0x82, 0xde, 0x00, 0x00, 0x01, 0x11, 0x2c, 0x60,
  6. 0x0a, 0x00, 0x1f, 0x7c, 0xe0, 0x00, 0x00, 0xfb, 0x14, 0xe9, 0x14, 0xe9,
  7. 0x00, 0x24, 0xb6, 0xaa, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
  8. 0x00, 0x00, 0x00, 0x00, 0x04, 0x77, 0x70, 0x61, 0x64, 0x05, 0x6c, 0x6f,
  9. 0x63, 0x61, 0x6c, 0x00, 0x00, 0x01, 0x00, 0x01};
  10. auto example_chunk = Chunk(example_raw, sizeof(example_raw));
  11. uint8_t payload[] = {0x14, 0xe9, 0x14, 0xe9, 0x00, 0x24, 0xb6, 0xaa, 0x00,
  12. 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
  13. 0x00, 0x00, 0x04, 0x77, 0x70, 0x61, 0x64, 0x05, 0x6c,
  14. 0x6f, 0x63, 0x61, 0x6c, 0x00, 0x00, 0x01, 0x00, 0x01};
  15. auto payload_chunk = Chunk(payload, sizeof(payload));
  16. auto src = make_address("10.0.31.124");
  17. auto dst = make_address("224.0.0.251");
  18. using State = ip::State<void, ip::Opts::calculate_checksum>;
  19. using Context = typename State::Context;
  20. using Packet = typename State::Packet;
  21. TEST_CASE("send", "[ip]") {
  22. char buff[sizeof(example_raw)];
  23. auto buff_chunk = Chunk(buff, sizeof(example_raw));
  24. auto ctx = Context{src, dst, 1, ip::Proto::udp, 0, 0, nullptr};
  25. auto state = State();
  26. state.init(0x82DD);
  27. SECTION("no enough space") {
  28. auto zero_chunk = Chunk(buff, 0);
  29. SECTION("with content") {
  30. auto result = Packet::send(state, ctx, zero_chunk, payload_chunk);
  31. REQUIRE(!result);
  32. CHECK(result.state() == &state);
  33. CHECK(result.error_code() == (uint32_t)Errc::no_enough_space);
  34. }
  35. SECTION("without content") {
  36. auto result = Packet::send<false>(state, ctx, zero_chunk, payload_chunk);
  37. REQUIRE(!result);
  38. CHECK(result.state() == &state);
  39. CHECK(result.error_code() == (uint32_t)Errc::no_enough_space);
  40. }
  41. }
  42. SECTION("with content") {
  43. auto result = Packet::send(state, ctx, buff_chunk, payload_chunk);
  44. REQUIRE(result);
  45. auto res_buff = result.consumed();
  46. CHECK((void *)res_buff.data() == (void *)buff);
  47. CHECK(res_buff.size() == example_chunk.size());
  48. CHECK(res_buff == example_chunk);
  49. }
  50. SECTION("without content") {
  51. auto result = Packet::send<false>(state, ctx, buff_chunk, payload_chunk);
  52. REQUIRE(result);
  53. auto res_buff = result.consumed();
  54. CHECK((void *)res_buff.data() == (void *)buff);
  55. CHECK(res_buff.size() == 20);
  56. CHECK(res_buff == Chunk(example_raw, 20));
  57. }
  58. }
  59. TEST_CASE("send (no checksum)", "[ip]") {
  60. using State = ip::State<void>;
  61. using Context = typename State::Context;
  62. using Packet = typename State::Packet;
  63. uint8_t example_modified[sizeof(example_raw)];
  64. memcpy(example_modified, example_raw, sizeof(example_raw));
  65. auto example_chunk = Chunk(example_modified, sizeof(example_modified));
  66. /* zero checksum */
  67. example_modified[10] = 0;
  68. example_modified[11] = 0;
  69. char buff[sizeof(example_raw)];
  70. auto buff_chunk = Chunk(buff, sizeof(example_raw));
  71. auto ctx = Context{src, dst, 1, ip::Proto::udp, 0, 0, nullptr};
  72. auto state = State();
  73. state.init(0x82DD);
  74. SECTION("with content") {
  75. auto result = Packet::send(state, ctx, buff_chunk, payload_chunk);
  76. REQUIRE(result);
  77. auto res_buff = result.consumed();
  78. CHECK((void *)res_buff.data() == (void *)buff);
  79. CHECK(res_buff.size() == example_chunk.size());
  80. CHECK(res_buff == example_chunk);
  81. }
  82. SECTION("without content") {
  83. auto result = Packet::send<false>(state, ctx, buff_chunk, payload_chunk);
  84. REQUIRE(result);
  85. auto res_buff = result.consumed();
  86. CHECK((void *)res_buff.data() == (void *)buff);
  87. CHECK(res_buff.size() == 20);
  88. CHECK(res_buff == Chunk(example_modified, 20));
  89. }
  90. }
  91. TEST_CASE("recv/success", "[ip]") {
  92. auto state = State();
  93. auto result = state.recv(example_chunk, nullptr);
  94. CHECK(result);
  95. CHECK(result.consumed() == example_chunk);
  96. CHECK(result.state() == &state);
  97. auto &packet = state.get_parsed();
  98. CHECK(packet.ver == 4);
  99. CHECK(packet.header_length == 5);
  100. CHECK(packet.tos == 0);
  101. CHECK(packet.length == example_chunk.size());
  102. CHECK(packet.id == 0x82DE);
  103. CHECK(packet.flag == 0);
  104. CHECK(packet.frag_offset == 0);
  105. CHECK(packet.ttl == 1);
  106. CHECK(packet.proto == (uint8_t)ip::Proto::udp);
  107. CHECK(packet.checksum == 0x2C60);
  108. CHECK(packet.source == src);
  109. CHECK(packet.destination == dst);
  110. CHECK(packet.options == Chunk(example_raw, 0));
  111. CHECK(packet.payload == payload_chunk);
  112. CHECK(packet.packet_start == example_chunk.data());
  113. }
  114. TEST_CASE("recv/incomplete", "[ip]") {
  115. auto state = State();
  116. auto empty_chunk = Chunk(example_raw, 0);
  117. SECTION("less then header sz") {
  118. auto result = state.recv(Chunk(example_raw, 18), nullptr);
  119. CHECK(result);
  120. CHECK(result.consumed() == empty_chunk);
  121. CHECK(result.demand() == 2);
  122. }
  123. SECTION("incomplete payload") {
  124. auto chunk = Chunk(example_raw, example_chunk.size() - 1);
  125. auto result = state.recv(chunk, nullptr);
  126. CHECK(result);
  127. CHECK(result.consumed() == empty_chunk);
  128. CHECK(result.demand() == 1);
  129. }
  130. }
  131. TEST_CASE("recv/options", "[ip]") {
  132. uint8_t example_raw[]{
  133. 0x46, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x01, 0x11, 0x84, 0x8c,
  134. 0x0a, 0x00, 0x1f, 0x7c, 0xe0, 0x00, 0x00, 0xfb, 0x14, 0xe9, 0x14, 0xe9,
  135. };
  136. auto example_chunk = Chunk(example_raw, sizeof(example_raw));
  137. auto state = State();
  138. SECTION("success") {
  139. auto result = state.recv(example_chunk, nullptr);
  140. CHECK(result);
  141. CHECK(result.consumed() == example_chunk);
  142. auto &packet = state.get_parsed();
  143. CHECK(packet.ver == 4);
  144. CHECK(packet.header_length == 6);
  145. CHECK(packet.options == Chunk(example_raw + 20, 4));
  146. }
  147. SECTION("incomplete") {
  148. auto chunk = Chunk(example_raw, 21);
  149. auto result = state.recv(chunk, nullptr);
  150. auto empty_chunk = Chunk(example_raw, 0);
  151. CHECK(result);
  152. CHECK(result.consumed() == empty_chunk);
  153. CHECK(result.demand() == 3);
  154. }
  155. }
  156. TEST_CASE("recv/failures", "[ip]") {
  157. using State = ip::State<void, ip::Opts::validate_checksum>;
  158. auto state = State();
  159. uint8_t raw[sizeof(example_raw)];
  160. memcpy(raw, example_raw, sizeof(raw));
  161. auto raw_chunk = Chunk(raw, sizeof(raw));
  162. SECTION("wrong checksum") {
  163. ++raw[20 - 9];
  164. auto result = state.recv(raw_chunk, nullptr);
  165. CHECK(!result);
  166. CHECK(result.state() == &state);
  167. CHECK(result.error_code() == (uint32_t)Errc::ip_checksum_mismatch);
  168. CHECK(result.consumed() == raw_chunk);
  169. SECTION("ignore checksum") {
  170. using State = ip::State<void>;
  171. auto state = State();
  172. auto result = state.recv(raw_chunk, nullptr);
  173. CHECK(result);
  174. }
  175. }
  176. SECTION("wrong version") {
  177. raw[0] = 0;
  178. auto result = state.recv(raw_chunk, nullptr);
  179. CHECK(!result);
  180. CHECK(result.state() == &state);
  181. CHECK(result.error_code() == (uint32_t)Errc::ip_unsupported_version);
  182. CHECK(result.consumed() == Chunk(raw, 1));
  183. }
  184. SECTION("wrong header_sz") {
  185. raw[0] = 0x41;
  186. auto result = state.recv(raw_chunk, nullptr);
  187. CHECK(!result);
  188. CHECK(result.state() == &state);
  189. CHECK(result.error_code() == (uint32_t)Errc::ip_header_missized);
  190. CHECK(result.consumed() == Chunk(raw, 1));
  191. }
  192. }
  193. TEST_CASE("send & recv with checksum", "[ip]") {
  194. using O = ip::Opts;
  195. constexpr auto opts = O::calculate_checksum | O::validate_checksum;
  196. using State = ip::State<void, opts>;
  197. using Context = typename State::Context;
  198. using Packet = typename State::Packet;
  199. char buff[sizeof(example_raw)];
  200. auto buff_chunk = Chunk(buff, sizeof(example_raw));
  201. auto ctx = Context{src, dst, 1, ip::Proto::udp, 0, 0, nullptr};
  202. auto state = State();
  203. state.init(0x82DD);
  204. auto result = Packet::send(state, ctx, buff_chunk, payload_chunk);
  205. REQUIRE(result);
  206. auto res_buff = result.consumed();
  207. result = state.recv(res_buff, nullptr);
  208. CHECK(result);
  209. CHECK(result.state() == &state);
  210. CHECK(!result.demand());
  211. }