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