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 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 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 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 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