blob: b0e0cdd9fa688982d71b6db332e7882d41f8555d [file] [log] [blame]
Patrick Venture537ff142018-11-01 16:37:09 -07001#include "endian.hpp"
Ratan Gupta07c462a2016-12-14 00:40:30 +05302#include "slp.hpp"
Patrick Venture537ff142018-11-01 16:37:09 -07003#include "slp_meta.hpp"
Ratan Gupta07c462a2016-12-14 00:40:30 +05304
5#include <arpa/inet.h>
Ratan Guptaead7a3c2017-01-05 15:45:09 +05306#include <dirent.h>
Ratan Gupta07c462a2016-12-14 00:40:30 +05307#include <ifaddrs.h>
8#include <net/if.h>
9#include <string.h>
10
11#include <algorithm>
12
Ratan Gupta07c462a2016-12-14 00:40:30 +053013namespace slp
14{
15namespace handler
16{
17
18namespace internal
19{
20
Patrick Williamsf93142e2023-04-04 20:06:36 -050021static constexpr auto SERVICE_DIR = "/etc/slp/services/";
22
Ratan Gupta07c462a2016-12-14 00:40:30 +053023buffer prepareHeader(const Message& req)
24{
Patrick Venture537ff142018-11-01 16:37:09 -070025 uint8_t length =
26 slp::header::MIN_LEN + /* 14 bytes for header */
27 req.header.langtag.length() + /* Actual length of lang tag */
28 slp::response::SIZE_ERROR; /* 2 bytes for error code */
Ratan Gupta07c462a2016-12-14 00:40:30 +053029
30 buffer buff(length, 0);
31
32 buff[slp::header::OFFSET_VERSION] = req.header.version;
33
Patrick Venture537ff142018-11-01 16:37:09 -070034 // will increment the function id from 1 as reply
Ratan Gupta07c462a2016-12-14 00:40:30 +053035 buff[slp::header::OFFSET_FUNCTION] = req.header.functionID + 1;
36
37 std::copy_n(&length, slp::header::SIZE_LENGTH,
Patrick Venture537ff142018-11-01 16:37:09 -070038 buff.data() + slp::header::OFFSET_LENGTH);
Ratan Gupta07c462a2016-12-14 00:40:30 +053039
40 auto flags = endian::to_network(req.header.flags);
41
42 std::copy_n((uint8_t*)&flags, slp::header::SIZE_FLAGS,
Patrick Venture537ff142018-11-01 16:37:09 -070043 buff.data() + slp::header::OFFSET_FLAGS);
Ratan Gupta07c462a2016-12-14 00:40:30 +053044
45 std::copy_n(req.header.extOffset.data(), slp::header::SIZE_EXT,
Patrick Venture537ff142018-11-01 16:37:09 -070046 buff.data() + slp::header::OFFSET_EXT);
Ratan Gupta07c462a2016-12-14 00:40:30 +053047
48 auto xid = endian::to_network(req.header.xid);
49
50 std::copy_n((uint8_t*)&xid, slp::header::SIZE_XID,
Patrick Venture537ff142018-11-01 16:37:09 -070051 buff.data() + slp::header::OFFSET_XID);
Ratan Gupta07c462a2016-12-14 00:40:30 +053052
53 uint16_t langtagLen = req.header.langtag.length();
54 langtagLen = endian::to_network(langtagLen);
55 std::copy_n((uint8_t*)&langtagLen, slp::header::SIZE_LANG,
Patrick Venture537ff142018-11-01 16:37:09 -070056 buff.data() + slp::header::OFFSET_LANG_LEN);
Ratan Gupta07c462a2016-12-14 00:40:30 +053057
Patrick Venture537ff142018-11-01 16:37:09 -070058 std::copy_n((uint8_t*)req.header.langtag.c_str(),
59 req.header.langtag.length(),
60 buff.data() + slp::header::OFFSET_LANG);
Ratan Gupta07c462a2016-12-14 00:40:30 +053061 return buff;
Ratan Gupta07c462a2016-12-14 00:40:30 +053062}
63
Patrick Venture537ff142018-11-01 16:37:09 -070064std::tuple<int, buffer> processSrvTypeRequest(const Message& req)
Ratan Gupta07c462a2016-12-14 00:40:30 +053065{
Ratan Gupta07c462a2016-12-14 00:40:30 +053066 /*
67 0 1 2 3
68 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
69 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
70 | Service Location header (function = SrvTypeRply = 10) |
71 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
72 | Error Code | length of <srvType-list> |
73 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
74 | <srvtype--list> \
75 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
76 */
77
78 buffer buff;
79
Patrick Venture537ff142018-11-01 16:37:09 -070080 // read the slp service info from conf and create the service type string
Ratan Gupta07c462a2016-12-14 00:40:30 +053081 slp::handler::internal::ServiceList svcList =
Ratan Guptaead7a3c2017-01-05 15:45:09 +053082 slp::handler::internal::readSLPServiceInfo();
Ratan Gupta07c462a2016-12-14 00:40:30 +053083 if (svcList.size() <= 0)
84 {
85 buff.resize(0);
Ratan Gupta0d3e9e32017-02-10 22:27:12 +053086 std::cerr << "SLP unable to read the service info\n";
Ratan Gupta07c462a2016-12-14 00:40:30 +053087 return std::make_tuple((int)slp::Error::INTERNAL_ERROR, buff);
88 }
89
90 std::string service;
91 bool firstIteration = true;
92 for_each(svcList.cbegin(), svcList.cend(),
Patrick Venture537ff142018-11-01 16:37:09 -070093 [&service, &firstIteration](const auto& svc) {
Patrick Williamsaa902c62023-04-04 19:59:51 -050094 if (firstIteration == true)
95 {
96 service = svc.first;
97 firstIteration = false;
98 }
99 else
100 {
101 service += ",";
102 service += svc.first;
103 }
104 });
Ratan Gupta07c462a2016-12-14 00:40:30 +0530105
106 buff = prepareHeader(req);
107
108 /* Need to modify the length and the function type field of the header
109 * as it is dependent on the handler of the service */
110
111 std::cout << "service=" << service.c_str() << "\n";
112
Andrew Geisslereebd0812024-05-24 10:05:27 -0500113 // See if total response size exceeds our max
114 uint32_t totalLength =
115 buff.size() + /* 14 bytes header + length of langtag */
116 slp::response::SIZE_ERROR + /* 2 byte err code */
117 slp::response::SIZE_SERVICE + /* 2 byte srvtype len */
118 service.length();
119 if (totalLength > slp::MAX_LEN)
120 {
121 std::cerr << "Message response size exceeds maximum allowed: "
122 << totalLength << " / " << slp::MAX_LEN << std::endl;
123 buff.resize(0);
124 return std::make_tuple((int)slp::Error::PARSE_ERROR, buff);
125 }
126
Patrick Venture537ff142018-11-01 16:37:09 -0700127 uint8_t length = buff.size() + /* 14 bytes header + length of langtag */
128 slp::response::SIZE_ERROR + /* 2 byte err code */
129 slp::response::SIZE_SERVICE + /* 2 byte srvtype len */
130 service.length();
Ratan Gupta07c462a2016-12-14 00:40:30 +0530131
132 buff.resize(length);
133
134 std::copy_n(&length, slp::header::SIZE_LENGTH,
Patrick Venture537ff142018-11-01 16:37:09 -0700135 buff.data() + slp::header::OFFSET_LENGTH);
Ratan Gupta07c462a2016-12-14 00:40:30 +0530136
137 /* error code is already set to 0 moving to service type len */
138
139 uint16_t serviceTypeLen = service.length();
140 serviceTypeLen = endian::to_network(serviceTypeLen);
141
142 std::copy_n((uint8_t*)&serviceTypeLen, slp::response::SIZE_SERVICE,
Patrick Venture537ff142018-11-01 16:37:09 -0700143 buff.data() + slp::response::OFFSET_SERVICE_LEN);
Ratan Gupta07c462a2016-12-14 00:40:30 +0530144
145 /* service type data */
146 std::copy_n((uint8_t*)service.c_str(), service.length(),
Patrick Venture537ff142018-11-01 16:37:09 -0700147 (buff.data() + slp::response::OFFSET_SERVICE));
Ratan Gupta07c462a2016-12-14 00:40:30 +0530148
149 return std::make_tuple(slp::SUCCESS, buff);
150}
151
Patrick Venture537ff142018-11-01 16:37:09 -0700152std::tuple<int, buffer> processSrvRequest(const Message& req)
Ratan Gupta07c462a2016-12-14 00:40:30 +0530153{
Ratan Gupta07c462a2016-12-14 00:40:30 +0530154 /*
155 Service Reply
156 0 1 2 3
157 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
158 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
159 | Service Location header (function = SrvRply = 2) |
160 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
161 | Error Code | URL Entry count |
162 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
163 | <URL Entry 1> ... <URL Entry N> \
164 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
165
166 URL Entry
167 0 1 2 3
168 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
169 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
170 | Reserved | Lifetime | URL Length |
171 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
172 |URL len, contd.| URL (variable length) \
173 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
174 |# of URL auths | Auth. blocks (if any) \
175 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
176 */
177
178 buffer buff;
Patrick Venture537ff142018-11-01 16:37:09 -0700179 // Get all the services which are registered
Ratan Gupta07c462a2016-12-14 00:40:30 +0530180 slp::handler::internal::ServiceList svcList =
Ratan Guptaead7a3c2017-01-05 15:45:09 +0530181 slp::handler::internal::readSLPServiceInfo();
Ratan Gupta07c462a2016-12-14 00:40:30 +0530182 if (svcList.size() <= 0)
183 {
184 buff.resize(0);
Ratan Gupta0d3e9e32017-02-10 22:27:12 +0530185 std::cerr << "SLP unable to read the service info\n";
Ratan Gupta07c462a2016-12-14 00:40:30 +0530186 return std::make_tuple((int)slp::Error::INTERNAL_ERROR, buff);
187 }
188
Patrick Venture537ff142018-11-01 16:37:09 -0700189 // return error if serice type doesn't match
Ratan Gupta07c462a2016-12-14 00:40:30 +0530190 auto& svcName = req.body.srvrqst.srvType;
191 auto svcIt = svcList.find(svcName);
192 if (svcIt == svcList.end())
193 {
194 buff.resize(0);
Ratan Gupta0d3e9e32017-02-10 22:27:12 +0530195 std::cerr << "SLP unable to find the service=" << svcName << "\n";
Ratan Gupta07c462a2016-12-14 00:40:30 +0530196 return std::make_tuple((int)slp::Error::INTERNAL_ERROR, buff);
197 }
Patrick Venture537ff142018-11-01 16:37:09 -0700198 // Get all the interface address
Ratan Gupta07c462a2016-12-14 00:40:30 +0530199 auto ifaddrList = slp::handler::internal::getIntfAddrs();
200 if (ifaddrList.size() <= 0)
201 {
202 buff.resize(0);
Ratan Gupta0d3e9e32017-02-10 22:27:12 +0530203 std::cerr << "SLP unable to read the interface address\n";
Ratan Gupta07c462a2016-12-14 00:40:30 +0530204 return std::make_tuple((int)slp::Error::INTERNAL_ERROR, buff);
205 }
206
207 buff = prepareHeader(req);
Patrick Venture537ff142018-11-01 16:37:09 -0700208 // Calculate the length and resize the buffer
209 uint8_t length = buff.size() + /* 14 bytes header + length of langtag */
210 slp::response::SIZE_ERROR + /* 2 bytes error code */
211 slp::response::SIZE_URL_COUNT; /* 2 bytes srvtype len */
Ratan Gupta07c462a2016-12-14 00:40:30 +0530212
213 buff.resize(length);
214
Patrick Venture537ff142018-11-01 16:37:09 -0700215 // Populate the url count
Ratan Gupta07c462a2016-12-14 00:40:30 +0530216 uint16_t urlCount = ifaddrList.size();
217 urlCount = endian::to_network(urlCount);
218
219 std::copy_n((uint8_t*)&urlCount, slp::response::SIZE_URL_COUNT,
Patrick Venture537ff142018-11-01 16:37:09 -0700220 buff.data() + slp::response::OFFSET_URL_ENTRY);
Ratan Gupta07c462a2016-12-14 00:40:30 +0530221
Patrick Venture537ff142018-11-01 16:37:09 -0700222 // Find the service
Ratan Gupta07c462a2016-12-14 00:40:30 +0530223 const slp::ConfigData& svc = svcIt->second;
Patrick Venture537ff142018-11-01 16:37:09 -0700224 // Populate the URL Entries
Ratan Gupta07c462a2016-12-14 00:40:30 +0530225 auto pos = slp::response::OFFSET_URL_ENTRY + slp::response::SIZE_URL_COUNT;
226 for (const auto& addr : ifaddrList)
227 {
Patrick Williamsaa902c62023-04-04 19:59:51 -0500228 std::string url = svc.name + ':' + svc.type + "//" + addr + ',' +
229 svc.port;
Ratan Gupta07c462a2016-12-14 00:40:30 +0530230
Andrew Geisslereebd0812024-05-24 10:05:27 -0500231 // See if total response size exceeds our max
232 uint32_t totalLength = buff.size() + slp::response::SIZE_URL_ENTRY +
233 url.length();
234 if (totalLength > slp::MAX_LEN)
235 {
236 std::cerr << "Message response size exceeds maximum allowed: "
237 << totalLength << " / " << slp::MAX_LEN << std::endl;
238 buff.resize(0);
239 return std::make_tuple((int)slp::Error::PARSE_ERROR, buff);
240 }
241
Patrick Venture537ff142018-11-01 16:37:09 -0700242 buff.resize(buff.size() + slp::response::SIZE_URL_ENTRY + url.length());
Ratan Gupta07c462a2016-12-14 00:40:30 +0530243
244 uint8_t reserved = 0;
245 uint16_t auth = 0;
246 uint16_t lifetime = endian::to_network<uint16_t>(slp::LIFETIME);
247 uint16_t urlLength = url.length();
248
249 std::copy_n((uint8_t*)&reserved, slp::response::SIZE_RESERVED,
250 buff.data() + pos);
251
252 pos += slp::response::SIZE_RESERVED;
253
Ratan Gupta07c462a2016-12-14 00:40:30 +0530254 std::copy_n((uint8_t*)&lifetime, slp::response::SIZE_LIFETIME,
255 buff.data() + pos);
256
257 pos += slp::response::SIZE_LIFETIME;
258
259 urlLength = endian::to_network(urlLength);
260 std::copy_n((uint8_t*)&urlLength, slp::response::SIZE_URLLENGTH,
261 buff.data() + pos);
262 pos += slp::response::SIZE_URLLENGTH;
263
Patrick Venture537ff142018-11-01 16:37:09 -0700264 std::copy_n((uint8_t*)url.c_str(), url.length(), buff.data() + pos);
Ratan Gupta07c462a2016-12-14 00:40:30 +0530265 pos += url.length();
266
267 std::copy_n((uint8_t*)&auth, slp::response::SIZE_AUTH,
268 buff.data() + pos);
269 pos += slp::response::SIZE_AUTH;
270 }
271 uint8_t packetLength = buff.size();
272 std::copy_n((uint8_t*)&packetLength, slp::header::SIZE_VERSION,
Patrick Venture537ff142018-11-01 16:37:09 -0700273 buff.data() + slp::header::OFFSET_LENGTH);
Ratan Gupta07c462a2016-12-14 00:40:30 +0530274
275 return std::make_tuple((int)slp::SUCCESS, buff);
276}
277
278std::list<std::string> getIntfAddrs()
279{
280 std::list<std::string> addrList;
281
282 struct ifaddrs* ifaddr;
283 // attempt to fill struct with ifaddrs
284 if (getifaddrs(&ifaddr) == -1)
285 {
286 return addrList;
287 }
288
Patrick Venture537ff142018-11-01 16:37:09 -0700289 slp::deleted_unique_ptr<ifaddrs> ifaddrPtr(
290 ifaddr, [](ifaddrs* addr) { freeifaddrs(addr); });
Ratan Gupta07c462a2016-12-14 00:40:30 +0530291
292 ifaddr = nullptr;
293
294 for (ifaddrs* ifa = ifaddrPtr.get(); ifa != nullptr; ifa = ifa->ifa_next)
295 {
296 // walk interfaces
297 if (ifa->ifa_addr == nullptr)
298 {
299 continue;
300 }
301
302 // get only INET interfaces not ipv6
303 if (ifa->ifa_addr->sa_family == AF_INET)
304 {
305 // if loopback, or not running ignore
306 if ((ifa->ifa_flags & IFF_LOOPBACK) ||
307 !(ifa->ifa_flags & IFF_RUNNING))
308 {
309 continue;
310 }
311
Patrick Venture537ff142018-11-01 16:37:09 -0700312 char tmp[INET_ADDRSTRLEN] = {0};
Ratan Gupta07c462a2016-12-14 00:40:30 +0530313
314 inet_ntop(AF_INET,
Patrick Venture537ff142018-11-01 16:37:09 -0700315 &(((struct sockaddr_in*)(ifa->ifa_addr))->sin_addr), tmp,
Ratan Gupta07c462a2016-12-14 00:40:30 +0530316 sizeof(tmp));
317 addrList.emplace_back(tmp);
318 }
319 }
320
321 return addrList;
322}
323
Patrick Venture537ff142018-11-01 16:37:09 -0700324slp::handler::internal::ServiceList readSLPServiceInfo()
Ratan Gupta07c462a2016-12-14 00:40:30 +0530325{
326 using namespace std::string_literals;
Ratan Gupta07c462a2016-12-14 00:40:30 +0530327 slp::handler::internal::ServiceList svcLst;
Ratan Gupta07c462a2016-12-14 00:40:30 +0530328 slp::ConfigData service;
Ratan Guptaead7a3c2017-01-05 15:45:09 +0530329 struct dirent* dent = nullptr;
Ratan Gupta07c462a2016-12-14 00:40:30 +0530330
Ratan Guptaead7a3c2017-01-05 15:45:09 +0530331 // Open the services dir and get the service info
332 // from service files.
333 // Service File format would be "ServiceName serviceType Port"
334 DIR* dir = opendir(SERVICE_DIR);
335 // wrap the pointer into smart pointer.
Patrick Venture537ff142018-11-01 16:37:09 -0700336 slp::deleted_unique_ptr<DIR> dirPtr(dir, [](DIR* dir) {
Ratan Guptaead7a3c2017-01-05 15:45:09 +0530337 if (!dir)
338 {
339 closedir(dir);
340 }
341 });
342 dir = nullptr;
343
344 if (dirPtr.get())
345 {
346 while ((dent = readdir(dirPtr.get())) != NULL)
347 {
Patrick Venture537ff142018-11-01 16:37:09 -0700348 if (dent->d_type == DT_REG) // regular file
Ratan Guptaead7a3c2017-01-05 15:45:09 +0530349 {
350 auto absFileName = std::string(SERVICE_DIR) + dent->d_name;
351 std::ifstream readFile(absFileName);
352 readFile >> service;
353 service.name = "service:"s + service.name;
354 svcLst.emplace(service.name, service);
355 }
356 }
Ratan Guptaead7a3c2017-01-05 15:45:09 +0530357 }
Ratan Gupta07c462a2016-12-14 00:40:30 +0530358 return svcLst;
359}
Patrick Venture537ff142018-11-01 16:37:09 -0700360} // namespace internal
Ratan Gupta07c462a2016-12-14 00:40:30 +0530361
Patrick Venture537ff142018-11-01 16:37:09 -0700362std::tuple<int, buffer> processRequest(const Message& msg)
Ratan Gupta07c462a2016-12-14 00:40:30 +0530363{
364 int rc = slp::SUCCESS;
365 buffer resp(0);
Patrick Venture537ff142018-11-01 16:37:09 -0700366 std::cout << "SLP Processing Request=" << msg.header.functionID << "\n";
Brad Bishopb5e632a2018-02-23 15:22:12 -0500367
Ratan Gupta07c462a2016-12-14 00:40:30 +0530368 switch (msg.header.functionID)
369 {
Ratan Gupta07c462a2016-12-14 00:40:30 +0530370 case (uint8_t)slp::FunctionType::SRVTYPERQST:
Patrick Williamsaa902c62023-04-04 19:59:51 -0500371 std::tie(rc,
372 resp) = slp::handler::internal::processSrvTypeRequest(msg);
Ratan Gupta07c462a2016-12-14 00:40:30 +0530373 break;
374 case (uint8_t)slp::FunctionType::SRVRQST:
375 std::tie(rc, resp) = slp::handler::internal::processSrvRequest(msg);
376 break;
377 default:
378 rc = (uint8_t)slp::Error::MSG_NOT_SUPPORTED;
379 }
380 return std::make_tuple(rc, resp);
381}
382
Patrick Venture537ff142018-11-01 16:37:09 -0700383buffer processError(const Message& req, uint8_t err)
Ratan Gupta07c462a2016-12-14 00:40:30 +0530384{
385 buffer buff;
386 buff = slp::handler::internal::prepareHeader(req);
387
Patrick Williamsedf88cb2023-04-04 20:16:37 -0500388 static_assert(sizeof(err) == 1, "Errors should be 1 byte.");
389
390 // Since this is network order, the err should go in the 2nd byte of the
391 // error field. This is immediately after the langtag.
392 buff[slp::header::MIN_LEN + req.header.langtag.length() + 1] = err;
393
Ratan Gupta07c462a2016-12-14 00:40:30 +0530394 return buff;
Ratan Gupta07c462a2016-12-14 00:40:30 +0530395}
Patrick Venture537ff142018-11-01 16:37:09 -0700396} // namespace handler
397} // namespace slp