ipv4.cpp 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304
  1. /*=============================================================================
  2. Copyright (c) 2002-2003 Joel de Guzman
  3. http://spirit.sourceforge.net/
  4. Use, modification and distribution is subject to the Boost Software
  5. License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
  6. http://www.boost.org/LICENSE_1_0.txt)
  7. =============================================================================*/
  8. #include <boost/spirit/include/classic_core.hpp>
  9. #include <boost/spirit/include/classic_push_back_actor.hpp>
  10. #include <boost/spirit/include/classic_if.hpp>
  11. #include <boost/spirit/include/classic_for.hpp>
  12. #include <boost/spirit/include/phoenix1.hpp>
  13. #include <iostream>
  14. #include <string>
  15. #include <vector>
  16. #include <algorithm>
  17. ///////////////////////////////////////////////////////////////////////////////
  18. //
  19. // Sample parser for binary data. This sample highlights the use of dynamic
  20. // parsing where the result of actions direct the actual parsing behavior.
  21. // We shall demonstrate 1) the use of phoenix to implement lambda (unnamed)
  22. // functions, 2) dynamic looping using for_p, 3) the push_back_a actor for
  23. // stuffing data into a vector, and 4) the if_p parser for choosing parser
  24. // branches based on semantic conditions.
  25. //
  26. // << Sample idea by Florian Weimer >>
  27. //
  28. // For simplicity, we shall use bytes as atoms (and not 16-bit quantities
  29. // in big-endian format or something similar, which would be more realistic)
  30. // and PASCAL strings.
  31. //
  32. // A packet is the literal octet with value 255, followed by a variable
  33. // octet N (denoting the total length of the packet), followed by N-2 octets
  34. // (the payload). The payload contains a variable-length header, followed
  35. // by zero or more elements.
  36. //
  37. // The header contains a single PASCAL string.
  38. //
  39. // An element is a PASCAL string (alternative: an element is an octet M,
  40. // followed by [M/8] bytes, i.e. the necessary number of bytes to store M
  41. // bits).
  42. //
  43. // (This data structure is inspired by the format of a BGP UPDATE message.)
  44. //
  45. // Packet layout:
  46. //
  47. // .-------------------.
  48. // | 0xff | ^
  49. // +-------------------+ |
  50. // | packet length | |
  51. // +-------------------+ | number of bytes indicated by packet length
  52. // : : |
  53. // : payload : |
  54. // | | v
  55. // `-------------------'
  56. //
  57. // Payload layout:
  58. //
  59. // .-------------------.
  60. // | header length |
  61. // +-------------------+
  62. // | header octets | ^
  63. // : : | number of octets given by header length
  64. // : : |
  65. // : : v
  66. // +-------------------+
  67. // | IPv4 prefix | ^
  68. // : : | IPv4 prefixes have variable length (see
  69. // +-------------------+ | below). The number of prefixes is
  70. // | IPv4 prefix | | determined by the packet length.
  71. // : : |
  72. // +-------------------+ |
  73. // : : |
  74. // : : v
  75. //
  76. //
  77. // IPv4 prefix layout comes in five variants, depending on the first
  78. // octet:
  79. //
  80. // .-------------------.
  81. // | 0x00 | single octet, corresponds to 0.0.0.0/0
  82. // `-------------------'
  83. //
  84. // .-------------------.
  85. // | 0x01 to 0x08 | two octets, prefix lengths up to /8.
  86. // +-------------------+
  87. // | MSB of network |
  88. // `-------------------'
  89. //
  90. // .-------------------.
  91. // | 0x09 to 0x10 | three octets, prefix lengths up to /16.
  92. // +-------------------+
  93. // | MSB of network |
  94. // +-------------------+
  95. // | next octet |
  96. // `-------------------'
  97. //
  98. // .-------------------.
  99. // | 0x11 to 0x18 | four octets, prefix lengths up to /24.
  100. // +-------------------+
  101. // | MSB of network |
  102. // +-------------------+
  103. // | next octet |
  104. // +-------------------+
  105. // | next octet |
  106. // `-------------------'
  107. //
  108. // .-------------------.
  109. // | 0x19 to 0x20 | five octets, prefix lengths up to /32.
  110. // +-------------------+
  111. // | MSB of network |
  112. // +-------------------+
  113. // | next octet |
  114. // +-------------------+
  115. // | next octet |
  116. // +-------------------+
  117. // | LSB of network |
  118. // `-------------------'
  119. //
  120. ///////////////////////////////////////////////////////////////////////////////
  121. using namespace std;
  122. using namespace BOOST_SPIRIT_CLASSIC_NS;
  123. using namespace phoenix;
  124. struct ipv4_prefix_data
  125. {
  126. char prefix_len, n0, n1, n2, n3;
  127. ipv4_prefix_data()
  128. : prefix_len(0),n0(0),n1(0),n2(0),n3(0) {}
  129. };
  130. struct ipv4_data
  131. {
  132. char packet_len, header_len;
  133. std::string header;
  134. std::vector<ipv4_prefix_data> prefixes;
  135. ipv4_data()
  136. : packet_len(0),header_len(0){}
  137. };
  138. struct ipv4 : public grammar<ipv4>
  139. {
  140. template <typename ScannerT>
  141. struct definition
  142. {
  143. definition(ipv4 const& self)
  144. {
  145. packet =
  146. '\xff'
  147. >> anychar_p[var(self.data.packet_len) = arg1]
  148. >> payload
  149. ;
  150. payload =
  151. anychar_p[var(self.data.header_len) = arg1]
  152. >> for_p(var(i) = 0, var(i) < var(self.data.header_len), ++var(i))
  153. [
  154. anychar_p[var(self.data.header) += arg1]
  155. ]
  156. >> *ipv4_prefix
  157. ;
  158. ipv4_prefix =
  159. anychar_p
  160. [
  161. var(temp.prefix_len) = arg1,
  162. var(temp.n0) = 0,
  163. var(temp.n1) = 0,
  164. var(temp.n2) = 0,
  165. var(temp.n3) = 0
  166. ]
  167. >> if_p(var(temp.prefix_len) > 0x00)
  168. [
  169. anychar_p[var(temp.n0) = arg1]
  170. >> if_p(var(temp.prefix_len) > 0x08)
  171. [
  172. anychar_p[var(temp.n1) = arg1]
  173. >> if_p(var(temp.prefix_len) > 0x10)
  174. [
  175. anychar_p[var(temp.n2) = arg1]
  176. >> if_p(var(temp.prefix_len) > 0x18)
  177. [
  178. anychar_p[var(temp.n3) = arg1]
  179. ]
  180. ]
  181. ]
  182. ]
  183. [
  184. push_back_a(self.data.prefixes, temp)
  185. ]
  186. ;
  187. }
  188. int i;
  189. ipv4_prefix_data temp;
  190. rule<ScannerT> packet, payload, ipv4_prefix;
  191. rule<ScannerT> const&
  192. start() const { return packet; }
  193. };
  194. ipv4(ipv4_data& data)
  195. : data(data) {}
  196. ipv4_data& data;
  197. };
  198. ////////////////////////////////////////////////////////////////////////////
  199. //
  200. // Main program
  201. //
  202. ////////////////////////////////////////////////////////////////////////////
  203. int
  204. as_byte(char n)
  205. {
  206. if (n < 0)
  207. return n + 256;
  208. return n;
  209. }
  210. void
  211. print_prefix(ipv4_prefix_data const& prefix)
  212. {
  213. cout << "prefix length = " << as_byte(prefix.prefix_len) << endl;
  214. cout << "n0 = " << as_byte(prefix.n0) << endl;
  215. cout << "n1 = " << as_byte(prefix.n1) << endl;
  216. cout << "n2 = " << as_byte(prefix.n2) << endl;
  217. cout << "n3 = " << as_byte(prefix.n3) << endl;
  218. }
  219. void
  220. parse_ipv4(char const* str, unsigned len)
  221. {
  222. ipv4_data data;
  223. ipv4 g(data);
  224. parse_info<> info = parse(str, str+len, g);
  225. if (info.full)
  226. {
  227. cout << "-------------------------\n";
  228. cout << "Parsing succeeded\n";
  229. cout << "packet length = " << as_byte(data.packet_len) << endl;
  230. cout << "header length = " << as_byte(data.header_len) << endl;
  231. cout << "header = " << data.header << endl;
  232. for_each(data.prefixes.begin(), data.prefixes.end(), print_prefix);
  233. cout << "-------------------------\n";
  234. }
  235. else
  236. {
  237. cout << "Parsing failed\n";
  238. cout << "stopped at:";
  239. for (char const* s = info.stop; s != str+len; ++s)
  240. cout << static_cast<int>(*s) << endl;
  241. }
  242. }
  243. // Test inputs:
  244. // The string in the header is "empty", the prefix list is empty.
  245. char const i1[8] =
  246. {
  247. 0xff,0x08,0x05,
  248. 'e','m','p','t','y'
  249. };
  250. // The string in the header is "default route", the prefix list
  251. // has just one element, 0.0.0.0/0.
  252. char const i2[17] =
  253. {
  254. 0xff,0x11,0x0d,
  255. 'd','e','f','a','u','l','t',' ',
  256. 'r','o','u','t','e',
  257. 0x00
  258. };
  259. // The string in the header is "private address space", the prefix list
  260. // has the elements 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16.
  261. char const i3[32] =
  262. {
  263. 0xff,0x20,0x15,
  264. 'p','r','i','v','a','t','e',' ',
  265. 'a','d','d','r','e','s','s',' ',
  266. 's','p','a','c','e',
  267. 0x08,0x0a,
  268. 0x0c,0xac,0x10,
  269. 0x10,0xc0,0xa8
  270. };
  271. int
  272. main()
  273. {
  274. parse_ipv4(i1, sizeof(i1));
  275. parse_ipv4(i2, sizeof(i2));
  276. parse_ipv4(i3, sizeof(i3));
  277. return 0;
  278. }