1 /*
2 * Copyright (c) 2020, The OpenThread Authors.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * 3. Neither the name of the copyright holder nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 /**
30 * @file
31 * This file implements a simple CLI for the SRP server.
32 */
33
34 #include "cli_srp_server.hpp"
35
36 #include <inttypes.h>
37
38 #include "cli/cli.hpp"
39 #include "common/string.hpp"
40
41 #if OPENTHREAD_CONFIG_SRP_SERVER_ENABLE
42
43 namespace ot {
44 namespace Cli {
45
46 constexpr SrpServer::Command SrpServer::sCommands[];
47
Process(Arg aArgs[])48 otError SrpServer::Process(Arg aArgs[])
49 {
50 otError error = OT_ERROR_INVALID_COMMAND;
51 const Command *command;
52
53 if (aArgs[0].IsEmpty())
54 {
55 IgnoreError(ProcessHelp(aArgs));
56 ExitNow();
57 }
58
59 command = BinarySearch::Find(aArgs[0].GetCString(), sCommands);
60 VerifyOrExit(command != nullptr);
61
62 error = (this->*command->mHandler)(aArgs + 1);
63
64 exit:
65 return error;
66 }
67
ProcessAddrMode(Arg aArgs[])68 otError SrpServer::ProcessAddrMode(Arg aArgs[])
69 {
70 otError error = OT_ERROR_INVALID_ARGS;
71
72 if (aArgs[0].IsEmpty())
73 {
74 switch (otSrpServerGetAddressMode(GetInstancePtr()))
75 {
76 case OT_SRP_SERVER_ADDRESS_MODE_UNICAST:
77 OutputLine("unicast");
78 break;
79
80 case OT_SRP_SERVER_ADDRESS_MODE_ANYCAST:
81 OutputLine("anycast");
82 break;
83 }
84
85 error = OT_ERROR_NONE;
86 }
87 else if (aArgs[0] == "unicast")
88 {
89 error = otSrpServerSetAddressMode(GetInstancePtr(), OT_SRP_SERVER_ADDRESS_MODE_UNICAST);
90 }
91 else if (aArgs[0] == "anycast")
92 {
93 error = otSrpServerSetAddressMode(GetInstancePtr(), OT_SRP_SERVER_ADDRESS_MODE_ANYCAST);
94 }
95
96 return error;
97 }
98
ProcessDomain(Arg aArgs[])99 otError SrpServer::ProcessDomain(Arg aArgs[])
100 {
101 otError error = OT_ERROR_NONE;
102
103 if (aArgs[0].IsEmpty())
104 {
105 OutputLine("%s", otSrpServerGetDomain(GetInstancePtr()));
106 }
107 else
108 {
109 error = otSrpServerSetDomain(GetInstancePtr(), aArgs[0].GetCString());
110 }
111
112 return error;
113 }
114
ProcessState(Arg aArgs[])115 otError SrpServer::ProcessState(Arg aArgs[])
116 {
117 static const char *const kStateStrings[] = {
118 "disabled", // (0) OT_SRP_SERVER_STATE_DISABLED
119 "running", // (1) OT_SRP_SERVER_STATE_RUNNING
120 "stopped", // (2) OT_SRP_SERVER_STATE_STOPPED
121 };
122
123 OT_UNUSED_VARIABLE(aArgs);
124
125 static_assert(0 == OT_SRP_SERVER_STATE_DISABLED, "OT_SRP_SERVER_STATE_DISABLED value is incorrect");
126 static_assert(1 == OT_SRP_SERVER_STATE_RUNNING, "OT_SRP_SERVER_STATE_RUNNING value is incorrect");
127 static_assert(2 == OT_SRP_SERVER_STATE_STOPPED, "OT_SRP_SERVER_STATE_STOPPED value is incorrect");
128
129 OutputLine("%s", Stringify(otSrpServerGetState(GetInstancePtr()), kStateStrings));
130
131 return OT_ERROR_NONE;
132 }
133
ProcessEnable(Arg aArgs[])134 otError SrpServer::ProcessEnable(Arg aArgs[])
135 {
136 OT_UNUSED_VARIABLE(aArgs);
137
138 otSrpServerSetEnabled(GetInstancePtr(), /* aEnabled */ true);
139
140 return OT_ERROR_NONE;
141 }
142
ProcessDisable(Arg aArgs[])143 otError SrpServer::ProcessDisable(Arg aArgs[])
144 {
145 OT_UNUSED_VARIABLE(aArgs);
146
147 otSrpServerSetEnabled(GetInstancePtr(), /* aEnabled */ false);
148
149 return OT_ERROR_NONE;
150 }
151
ProcessTtl(Arg aArgs[])152 otError SrpServer::ProcessTtl(Arg aArgs[])
153 {
154 otError error = OT_ERROR_NONE;
155 otSrpServerTtlConfig ttlConfig;
156
157 if (aArgs[0].IsEmpty())
158 {
159 otSrpServerGetTtlConfig(GetInstancePtr(), &ttlConfig);
160 OutputLine("min ttl: %u", ttlConfig.mMinTtl);
161 OutputLine("max ttl: %u", ttlConfig.mMaxTtl);
162 }
163 else
164 {
165 SuccessOrExit(error = aArgs[0].ParseAsUint32(ttlConfig.mMinTtl));
166 SuccessOrExit(error = aArgs[1].ParseAsUint32(ttlConfig.mMaxTtl));
167 VerifyOrExit(aArgs[2].IsEmpty(), error = OT_ERROR_INVALID_ARGS);
168
169 error = otSrpServerSetTtlConfig(GetInstancePtr(), &ttlConfig);
170 }
171
172 exit:
173 return error;
174 }
175
ProcessLease(Arg aArgs[])176 otError SrpServer::ProcessLease(Arg aArgs[])
177 {
178 otError error = OT_ERROR_NONE;
179 otSrpServerLeaseConfig leaseConfig;
180
181 if (aArgs[0].IsEmpty())
182 {
183 otSrpServerGetLeaseConfig(GetInstancePtr(), &leaseConfig);
184 OutputLine("min lease: %u", leaseConfig.mMinLease);
185 OutputLine("max lease: %u", leaseConfig.mMaxLease);
186 OutputLine("min key-lease: %u", leaseConfig.mMinKeyLease);
187 OutputLine("max key-lease: %u", leaseConfig.mMaxKeyLease);
188 }
189 else
190 {
191 SuccessOrExit(error = aArgs[0].ParseAsUint32(leaseConfig.mMinLease));
192 SuccessOrExit(error = aArgs[1].ParseAsUint32(leaseConfig.mMaxLease));
193 SuccessOrExit(error = aArgs[2].ParseAsUint32(leaseConfig.mMinKeyLease));
194 SuccessOrExit(error = aArgs[3].ParseAsUint32(leaseConfig.mMaxKeyLease));
195 VerifyOrExit(aArgs[4].IsEmpty(), error = OT_ERROR_INVALID_ARGS);
196
197 error = otSrpServerSetLeaseConfig(GetInstancePtr(), &leaseConfig);
198 }
199
200 exit:
201 return error;
202 }
203
ProcessHost(Arg aArgs[])204 otError SrpServer::ProcessHost(Arg aArgs[])
205 {
206 otError error = OT_ERROR_NONE;
207 const otSrpServerHost *host;
208
209 VerifyOrExit(aArgs[0].IsEmpty(), error = OT_ERROR_INVALID_ARGS);
210
211 host = nullptr;
212 while ((host = otSrpServerGetNextHost(GetInstancePtr(), host)) != nullptr)
213 {
214 const otIp6Address *addresses;
215 uint8_t addressesNum;
216 bool isDeleted = otSrpServerHostIsDeleted(host);
217
218 OutputLine("%s", otSrpServerHostGetFullName(host));
219 OutputLine(kIndentSize, "deleted: %s", isDeleted ? "true" : "false");
220 if (isDeleted)
221 {
222 continue;
223 }
224
225 OutputSpaces(kIndentSize);
226 OutputFormat("addresses: [");
227
228 addresses = otSrpServerHostGetAddresses(host, &addressesNum);
229
230 for (uint8_t i = 0; i < addressesNum; ++i)
231 {
232 OutputIp6Address(addresses[i]);
233 if (i < addressesNum - 1)
234 {
235 OutputFormat(", ");
236 }
237 }
238
239 OutputLine("]");
240 }
241
242 exit:
243 return error;
244 }
245
OutputHostAddresses(const otSrpServerHost * aHost)246 void SrpServer::OutputHostAddresses(const otSrpServerHost *aHost)
247 {
248 const otIp6Address *addresses;
249 uint8_t addressesNum;
250
251 addresses = otSrpServerHostGetAddresses(aHost, &addressesNum);
252
253 OutputFormat("[");
254 for (uint8_t i = 0; i < addressesNum; ++i)
255 {
256 if (i != 0)
257 {
258 OutputFormat(", ");
259 }
260
261 OutputIp6Address(addresses[i]);
262 }
263 OutputFormat("]");
264 }
265
ProcessService(Arg aArgs[])266 otError SrpServer::ProcessService(Arg aArgs[])
267 {
268 static constexpr char *kAnyServiceName = nullptr;
269 static constexpr char *kAnyInstanceName = nullptr;
270
271 otError error = OT_ERROR_NONE;
272 const otSrpServerHost *host = nullptr;
273
274 VerifyOrExit(aArgs[0].IsEmpty(), error = OT_ERROR_INVALID_ARGS);
275
276 while ((host = otSrpServerGetNextHost(GetInstancePtr(), host)) != nullptr)
277 {
278 const otSrpServerService *service = nullptr;
279
280 while ((service = otSrpServerHostFindNextService(host, service, OT_SRP_SERVER_FLAGS_BASE_TYPE_SERVICE_ONLY,
281 kAnyServiceName, kAnyInstanceName)) != nullptr)
282 {
283 bool isDeleted = otSrpServerServiceIsDeleted(service);
284 const char * instanceName = otSrpServerServiceGetInstanceName(service);
285 const otSrpServerService *subService = nullptr;
286 const uint8_t * txtData;
287 uint16_t txtDataLength;
288 bool hasSubType = false;
289
290 OutputLine("%s", instanceName);
291 OutputLine(kIndentSize, "deleted: %s", isDeleted ? "true" : "false");
292
293 if (isDeleted)
294 {
295 continue;
296 }
297
298 OutputFormat(kIndentSize, "subtypes: ");
299
300 while ((subService = otSrpServerHostFindNextService(
301 host, subService, (OT_SRP_SERVER_SERVICE_FLAG_SUB_TYPE | OT_SRP_SERVER_SERVICE_FLAG_ACTIVE),
302 kAnyServiceName, instanceName)) != nullptr)
303 {
304 char subLabel[OT_DNS_MAX_LABEL_SIZE];
305
306 IgnoreError(otSrpServerServiceGetServiceSubTypeLabel(subService, subLabel, sizeof(subLabel)));
307 OutputFormat("%s%s", hasSubType ? "," : "", subLabel);
308 hasSubType = true;
309 }
310
311 OutputLine(hasSubType ? "" : "(null)");
312
313 OutputLine(kIndentSize, "port: %hu", otSrpServerServiceGetPort(service));
314 OutputLine(kIndentSize, "priority: %hu", otSrpServerServiceGetPriority(service));
315 OutputLine(kIndentSize, "weight: %hu", otSrpServerServiceGetWeight(service));
316 OutputLine(kIndentSize, "ttl: %hu", otSrpServerServiceGetTtl(service));
317
318 txtData = otSrpServerServiceGetTxtData(service, &txtDataLength);
319 OutputFormat(kIndentSize, "TXT: ");
320 OutputDnsTxtData(txtData, txtDataLength);
321 OutputLine("");
322
323 OutputLine(kIndentSize, "host: %s", otSrpServerHostGetFullName(host));
324
325 OutputFormat(kIndentSize, "addresses: ");
326 OutputHostAddresses(host);
327 OutputLine("");
328 }
329 }
330
331 exit:
332 return error;
333 }
334
ProcessSeqNum(Arg aArgs[])335 otError SrpServer::ProcessSeqNum(Arg aArgs[])
336 {
337 otError error = OT_ERROR_NONE;
338
339 if (aArgs[0].IsEmpty())
340 {
341 OutputLine("%u", otSrpServerGetAnycastModeSequenceNumber(GetInstancePtr()));
342 }
343 else
344 {
345 uint8_t sequenceNumber;
346
347 SuccessOrExit(error = aArgs[0].ParseAsUint8(sequenceNumber));
348 error = otSrpServerSetAnycastModeSequenceNumber(GetInstancePtr(), sequenceNumber);
349 }
350
351 exit:
352 return error;
353 }
354
ProcessHelp(Arg aArgs[])355 otError SrpServer::ProcessHelp(Arg aArgs[])
356 {
357 OT_UNUSED_VARIABLE(aArgs);
358
359 for (const Command &command : sCommands)
360 {
361 OutputLine(command.mName);
362 }
363
364 return OT_ERROR_NONE;
365 }
366
367 } // namespace Cli
368 } // namespace ot
369
370 #endif // OPENTHREAD_CONFIG_SRP_SERVER_ENABLE
371