1 #include "endian.hpp"
2 #include "slp.hpp"
3 #include "slp_meta.hpp"
4
5 #include <string.h>
6
7 #include <algorithm>
8 #include <string>
9
10 namespace slp
11 {
12
13 namespace parser
14 {
15
16 namespace internal
17 {
18
parseHeader(const buffer & buff)19 std::tuple<int, Message> parseHeader(const buffer& buff)
20 {
21 /* 0 1 2 3
22 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
23 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
24 | Version | Function-ID | Length |
25 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
26 | Length, contd.|O|F|R| reserved |Next Ext Offset|
27 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
28 | Next Extension Offset, contd.| XID |
29 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
30 | Language Tag Length | Language Tag \
31 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */
32
33 Message req{};
34 int rc = slp::SUCCESS;
35
36 if (buff.size() < slp::header::MIN_LEN)
37 {
38 std::cerr << "Invalid msg size: " << buff.size() << std::endl;
39 rc = static_cast<int>(slp::Error::PARSE_ERROR);
40 }
41 else
42 {
43 std::copy_n(buff.data(), slp::header::SIZE_VERSION,
44 &req.header.version);
45
46 std::copy_n(buff.data() + slp::header::OFFSET_FUNCTION,
47 slp::header::SIZE_VERSION, &req.header.functionID);
48
49 std::copy_n(buff.data() + slp::header::OFFSET_LENGTH,
50 slp::header::SIZE_LENGTH, req.header.length.data());
51
52 std::copy_n(buff.data() + slp::header::OFFSET_FLAGS,
53 slp::header::SIZE_FLAGS, (uint8_t*)&req.header.flags);
54
55 req.header.flags = endian::from_network(req.header.flags);
56 std::copy_n(buff.data() + slp::header::OFFSET_EXT,
57 slp::header::SIZE_EXT, req.header.extOffset.data());
58
59 std::copy_n(buff.data() + slp::header::OFFSET_XID,
60 slp::header::SIZE_XID, (uint8_t*)&req.header.xid);
61
62 req.header.xid = endian::from_network(req.header.xid);
63
64 uint16_t langtagLen;
65
66 std::copy_n(buff.data() + slp::header::OFFSET_LANG_LEN,
67 slp::header::SIZE_LANG, (uint8_t*)&langtagLen);
68
69 langtagLen = endian::from_network(langtagLen);
70
71 // Enforce language tag size limits
72 if ((slp::header::OFFSET_LANG + langtagLen) > buff.size())
73 {
74 std::cerr << "Invalid Language Tag Length: " << langtagLen
75 << std::endl;
76 rc = static_cast<int>(slp::Error::PARSE_ERROR);
77 }
78 else
79 {
80 req.header.langtagLen = langtagLen;
81 req.header.langtag.insert(
82 0, (const char*)buff.data() + slp::header::OFFSET_LANG,
83 langtagLen);
84
85 /* check for the validity of the function */
86 if (req.header.functionID <
87 static_cast<uint8_t>(slp::FunctionType::SRVRQST) ||
88 req.header.functionID >
89 static_cast<uint8_t>(slp::FunctionType::SAADV))
90 {
91 std::cerr << "Invalid function ID: " << req.header.functionID
92 << std::endl;
93 rc = static_cast<int>(slp::Error::PARSE_ERROR);
94 }
95 }
96 }
97
98 return std::make_tuple(rc, std::move(req));
99 }
100
parseSrvTypeRqst(const buffer & buff,Message & req)101 int parseSrvTypeRqst(const buffer& buff, Message& req)
102 {
103 /* 0 1 2 3
104 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
105 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
106 | length of PRList | <PRList> String \
107 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
108 | length of Naming Authority | <Naming Authority String> \
109 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
110 | length of <scope-list> | <scope-list> String \
111 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */
112
113 /* Enforce SLPv2 service type request size limits. */
114 if (buff.size() < slp::request::MIN_SRVTYPE_LEN)
115 {
116 return (int)slp::Error::PARSE_ERROR;
117 }
118
119 /* Parse the PRList. */
120 uint16_t prListLen;
121 uint32_t pos = slp::header::MIN_LEN + req.header.langtagLen;
122 if ((pos + slp::request::SIZE_PRLIST) > buff.size())
123 {
124 std::cerr << "PRList length field is greater than input buffer: "
125 << (pos + slp::request::SIZE_PRLIST) << " / " << buff.size()
126 << std::endl;
127 return (int)slp::Error::PARSE_ERROR;
128 }
129 std::copy_n(buff.data() + pos, slp::request::SIZE_PRLIST,
130 (uint8_t*)&prListLen);
131
132 pos += slp::request::SIZE_PRLIST;
133 prListLen = endian::from_network(prListLen);
134
135 if ((pos + prListLen) > buff.size())
136 {
137 std::cerr << "Length of PRList is greater than input buffer: "
138 << (slp::request::OFFSET_PR + prListLen) << " / "
139 << buff.size() << std::endl;
140 return (int)slp::Error::PARSE_ERROR;
141 }
142
143 req.body.srvtyperqst.prList.insert(0, (const char*)buff.data() + pos,
144 prListLen);
145
146 pos += prListLen;
147
148 /* Parse the Naming Authority. */
149 uint16_t namingAuthLen;
150 if ((pos + slp::request::SIZE_NAMING) > buff.size())
151 {
152 std::cerr << "Naming auth length field is greater than input buffer: "
153 << (pos + slp::request::SIZE_NAMING) << " / " << buff.size()
154 << std::endl;
155 return (int)slp::Error::PARSE_ERROR;
156 }
157 std::copy_n(buff.data() + pos, slp::request::SIZE_NAMING,
158 (uint8_t*)&namingAuthLen);
159
160 pos += slp::request::SIZE_NAMING;
161
162 namingAuthLen = endian::from_network(namingAuthLen);
163 if (namingAuthLen == 0 || namingAuthLen == 0xffff)
164 {
165 req.body.srvtyperqst.namingAuth = "";
166 // If it's the special 0xffff, treat like 0 size
167 namingAuthLen = 0;
168 }
169 else
170 {
171 if ((pos + namingAuthLen) > buff.size())
172 {
173 std::cerr << "Length of Naming Size is greater than input buffer: "
174 << (pos + namingAuthLen) << " / " << buff.size()
175 << std::endl;
176 return (int)slp::Error::PARSE_ERROR;
177 }
178 req.body.srvtyperqst.namingAuth.insert(
179 0, (const char*)buff.data() + pos, namingAuthLen);
180 }
181
182 pos += namingAuthLen;
183
184 /* Parse the <scope-list>. */
185 uint16_t scopeListLen;
186 if ((pos + slp::request::SIZE_SCOPE) > buff.size())
187 {
188 std::cerr << "Length of Scope size is greater than input buffer: "
189 << (pos + slp::request::SIZE_SCOPE) << " / " << buff.size()
190 << std::endl;
191 return (int)slp::Error::PARSE_ERROR;
192 }
193 std::copy_n(buff.data() + pos, slp::request::SIZE_SCOPE,
194 (uint8_t*)&scopeListLen);
195
196 pos += slp::request::SIZE_SCOPE;
197
198 scopeListLen = endian::from_network(scopeListLen);
199 if ((pos + scopeListLen) > buff.size())
200 {
201 std::cerr << "Length of Scope List is greater than input buffer: "
202 << (pos + scopeListLen) << " / " << buff.size() << std::endl;
203 return (int)slp::Error::PARSE_ERROR;
204 }
205
206 req.body.srvtyperqst.scopeList.insert(0, (const char*)buff.data() + pos,
207 scopeListLen);
208
209 return slp::SUCCESS;
210 }
211
parseSrvRqst(const buffer & buff,Message & req)212 int parseSrvRqst(const buffer& buff, Message& req)
213 {
214 /* 0 1 2 3
215 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
216 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
217 | length of <PRList> | <PRList> String \
218 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
219 | length of <service-type> | <service-type> String \
220 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
221 | length of <scope-list> | <scope-list> String \
222 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
223 | length of predicate string | Service Request <predicate> \
224 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
225 | length of <SLP SPI> string | <SLP SPI> String \
226 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */
227
228 /* Enforce v2 service request size limits. */
229 if (buff.size() < slp::request::MIN_SRV_LEN)
230 {
231 return (int)slp::Error::PARSE_ERROR;
232 }
233
234 /* 1) Parse the PRList. */
235 uint16_t prListLen;
236 uint32_t pos = slp::header::MIN_LEN + req.header.langtagLen;
237 if ((pos + slp::request::SIZE_PRLIST) > buff.size())
238 {
239 std::cerr << "PRList length field is greater then input buffer: "
240 << (pos + slp::request::SIZE_PRLIST) << " / " << buff.size()
241 << std::endl;
242 return (int)slp::Error::PARSE_ERROR;
243 }
244 std::copy_n(buff.data() + pos, slp::request::SIZE_PRLIST,
245 (uint8_t*)&prListLen);
246
247 pos += slp::request::SIZE_PRLIST;
248
249 prListLen = endian::from_network(prListLen);
250 if ((pos + prListLen) > buff.size())
251 {
252 std::cerr << "Length of PRList is greater then input buffer: "
253 << (slp::request::OFFSET_PR + prListLen) << " / "
254 << buff.size() << std::endl;
255 return (int)slp::Error::PARSE_ERROR;
256 }
257 req.body.srvrqst.prList.insert(0, (const char*)buff.data() + pos,
258 prListLen);
259
260 pos += prListLen;
261
262 /* 2) Parse the <service-type> string. */
263 uint16_t srvTypeLen;
264 if ((pos + slp::request::SIZE_SERVICE_TYPE) > buff.size())
265 {
266 std::cerr << "SrvType length field is greater then input buffer: "
267 << (pos + slp::request::SIZE_SERVICE_TYPE) << " / "
268 << buff.size() << std::endl;
269 return (int)slp::Error::PARSE_ERROR;
270 }
271 std::copy_n(buff.data() + pos, slp::request::SIZE_SERVICE_TYPE,
272 (uint8_t*)&srvTypeLen);
273
274 srvTypeLen = endian::from_network(srvTypeLen);
275
276 pos += slp::request::SIZE_SERVICE_TYPE;
277
278 if ((pos + srvTypeLen) > buff.size())
279 {
280 std::cerr << "Length of SrvType is greater then input buffer: "
281 << (pos + srvTypeLen) << " / " << buff.size() << std::endl;
282 return (int)slp::Error::PARSE_ERROR;
283 }
284 req.body.srvrqst.srvType.insert(0, (const char*)buff.data() + pos,
285 srvTypeLen);
286
287 pos += srvTypeLen;
288
289 /* 3) Parse the <scope-list> string. */
290 uint16_t scopeListLen;
291 if ((pos + slp::request::SIZE_SCOPE) > buff.size())
292 {
293 std::cerr << "Scope List length field is greater then input buffer: "
294 << (pos + slp::request::SIZE_SCOPE) << " / " << buff.size()
295 << std::endl;
296 return (int)slp::Error::PARSE_ERROR;
297 }
298 std::copy_n(buff.data() + pos, slp::request::SIZE_SCOPE,
299 (uint8_t*)&scopeListLen);
300
301 scopeListLen = endian::from_network(scopeListLen);
302
303 pos += slp::request::SIZE_SCOPE;
304
305 if ((pos + scopeListLen) > buff.size())
306 {
307 std::cerr << "Length of Scope List is greater then input buffer: "
308 << (pos + scopeListLen) << " / " << buff.size() << std::endl;
309 return (int)slp::Error::PARSE_ERROR;
310 }
311 req.body.srvrqst.scopeList.insert(0, (const char*)buff.data() + pos,
312 scopeListLen);
313
314 pos += scopeListLen;
315
316 /* 4) Parse the <predicate> string. */
317 uint16_t predicateLen;
318 if ((pos + slp::request::SIZE_PREDICATE) > buff.size())
319 {
320 std::cerr << "Predicate length field is greater then input buffer: "
321 << (pos + slp::request::SIZE_PREDICATE) << " / "
322 << buff.size() << std::endl;
323 return (int)slp::Error::PARSE_ERROR;
324 }
325 std::copy_n(buff.data() + pos, slp::request::SIZE_PREDICATE,
326 (uint8_t*)&predicateLen);
327
328 predicateLen = endian::from_network(predicateLen);
329 pos += slp::request::SIZE_PREDICATE;
330
331 if ((pos + predicateLen) > buff.size())
332 {
333 std::cerr << "Length of Predicate is greater then input buffer: "
334 << (pos + predicateLen) << " / " << buff.size() << std::endl;
335 return (int)slp::Error::PARSE_ERROR;
336 }
337 req.body.srvrqst.predicate.insert(0, (const char*)buff.data() + pos,
338 predicateLen);
339
340 pos += predicateLen;
341
342 /* 5) Parse the <SLP SPI> string. */
343 uint16_t spistrLen;
344 if ((pos + slp::request::SIZE_SLPI) > buff.size())
345 {
346 std::cerr << "SLP SPI length field is greater then input buffer: "
347 << (pos + slp::request::SIZE_SLPI) << " / " << buff.size()
348 << std::endl;
349 return (int)slp::Error::PARSE_ERROR;
350 }
351 std::copy_n(buff.data() + pos, slp::request::SIZE_SLPI,
352 (uint8_t*)&spistrLen);
353
354 spistrLen = endian::from_network(spistrLen);
355 pos += slp::request::SIZE_SLPI;
356
357 if ((pos + spistrLen) > buff.size())
358 {
359 std::cerr << "Length of SLP SPI is greater then input buffer: "
360 << (pos + spistrLen) << " / " << buff.size() << std::endl;
361 return (int)slp::Error::PARSE_ERROR;
362 }
363 req.body.srvrqst.spistr.insert(0, (const char*)buff.data() + pos,
364 spistrLen);
365
366 return slp::SUCCESS;
367 }
368 } // namespace internal
369
parseBuffer(const buffer & buff)370 std::tuple<int, Message> parseBuffer(const buffer& buff)
371 {
372 Message req;
373 int rc = slp::SUCCESS;
374 /* parse the header first */
375 std::tie(rc, req) = internal::parseHeader(buff);
376 if (!rc)
377 {
378 /* switch on the function id to parse the body */
379 switch (req.header.functionID)
380 {
381 case (uint8_t)slp::FunctionType::SRVTYPERQST:
382 rc = internal::parseSrvTypeRqst(buff, req);
383 break;
384 case (uint8_t)slp::FunctionType::SRVRQST:
385 rc = internal::parseSrvRqst(buff, req);
386 break;
387 default:
388 rc = (int)slp::Error::MSG_NOT_SUPPORTED;
389 }
390 }
391 return std::make_tuple(rc, std::move(req));
392 }
393 } // namespace parser
394 } // namespace slp
395