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