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 std::copy_n(buff.data() + slp::request::OFFSET_PR_LEN, 237 slp::request::SIZE_PRLIST, (uint8_t*)&prListLen); 238 239 auto pos = slp::request::OFFSET_PR_LEN + slp::request::SIZE_PRLIST; 240 241 prListLen = endian::from_network(prListLen); 242 243 req.body.srvrqst.prList.insert(0, (const char*)buff.data() + pos, 244 prListLen); 245 246 pos += prListLen; 247 248 /* 2) Parse the <service-type> string. */ 249 uint16_t srvTypeLen; 250 std::copy_n(buff.data() + pos, slp::request::SIZE_SERVICE_TYPE, 251 (uint8_t*)&srvTypeLen); 252 253 srvTypeLen = endian::from_network(srvTypeLen); 254 255 pos += slp::request::SIZE_SERVICE_TYPE; 256 257 req.body.srvrqst.srvType.insert(0, (const char*)buff.data() + pos, 258 srvTypeLen); 259 260 pos += srvTypeLen; 261 262 /* 3) Parse the <scope-list> string. */ 263 uint16_t scopeListLen; 264 std::copy_n(buff.data() + pos, slp::request::SIZE_SCOPE, 265 (uint8_t*)&scopeListLen); 266 267 scopeListLen = endian::from_network(scopeListLen); 268 269 pos += slp::request::SIZE_SCOPE; 270 271 req.body.srvrqst.scopeList.insert(0, (const char*)buff.data() + pos, 272 scopeListLen); 273 274 pos += scopeListLen; 275 276 /* 4) Parse the <predicate> string. */ 277 uint16_t predicateLen; 278 std::copy_n(buff.data() + pos, slp::request::SIZE_PREDICATE, 279 (uint8_t*)&predicateLen); 280 281 predicateLen = endian::from_network(predicateLen); 282 pos += slp::request::SIZE_PREDICATE; 283 284 req.body.srvrqst.predicate.insert(0, (const char*)buff.data() + pos, 285 predicateLen); 286 287 pos += predicateLen; 288 289 /* 5) Parse the <SLP SPI> string. */ 290 uint16_t spistrLen; 291 std::copy_n(buff.data() + pos, slp::request::SIZE_SLPI, 292 (uint8_t*)&spistrLen); 293 294 spistrLen = endian::from_network(spistrLen); 295 pos += slp::request::SIZE_SLPI; 296 297 req.body.srvrqst.spistr.insert(0, (const char*)buff.data() + pos, 298 spistrLen); 299 300 return slp::SUCCESS; 301 } 302 } // namespace internal 303 304 std::tuple<int, Message> parseBuffer(const buffer& buff) 305 { 306 Message req; 307 int rc = slp::SUCCESS; 308 /* parse the header first */ 309 std::tie(rc, req) = internal::parseHeader(buff); 310 if (!rc) 311 { 312 /* switch on the function id to parse the body */ 313 switch (req.header.functionID) 314 { 315 case (uint8_t)slp::FunctionType::SRVTYPERQST: 316 rc = internal::parseSrvTypeRqst(buff, req); 317 break; 318 case (uint8_t)slp::FunctionType::SRVRQST: 319 rc = internal::parseSrvRqst(buff, req); 320 break; 321 default: 322 rc = (int)slp::Error::MSG_NOT_SUPPORTED; 323 } 324 } 325 return std::make_tuple(rc, std::move(req)); 326 } 327 } // namespace parser 328 } // namespace slp 329