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 = Utils::LookupTable::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
ProcessDomain(Arg aArgs[])68 otError SrpServer::ProcessDomain(Arg aArgs[])
69 {
70 otError error = OT_ERROR_NONE;
71
72 if (aArgs[0].IsEmpty())
73 {
74 mInterpreter.OutputLine("%s", otSrpServerGetDomain(mInterpreter.mInstance));
75 }
76 else
77 {
78 error = otSrpServerSetDomain(mInterpreter.mInstance, aArgs[0].GetCString());
79 }
80
81 return error;
82 }
83
ProcessState(Arg aArgs[])84 otError SrpServer::ProcessState(Arg aArgs[])
85 {
86 OT_UNUSED_VARIABLE(aArgs);
87
88 switch (otSrpServerGetState(mInterpreter.mInstance))
89 {
90 case OT_SRP_SERVER_STATE_DISABLED:
91 mInterpreter.OutputLine("disabled");
92 break;
93 case OT_SRP_SERVER_STATE_RUNNING:
94 mInterpreter.OutputLine("running");
95 break;
96 case OT_SRP_SERVER_STATE_STOPPED:
97 mInterpreter.OutputLine("stopped");
98 break;
99 default:
100 mInterpreter.OutputLine("invalid state");
101 break;
102 }
103
104 return OT_ERROR_NONE;
105 }
106
ProcessEnable(Arg aArgs[])107 otError SrpServer::ProcessEnable(Arg aArgs[])
108 {
109 OT_UNUSED_VARIABLE(aArgs);
110
111 otSrpServerSetEnabled(mInterpreter.mInstance, /* aEnabled */ true);
112
113 return OT_ERROR_NONE;
114 }
115
ProcessDisable(Arg aArgs[])116 otError SrpServer::ProcessDisable(Arg aArgs[])
117 {
118 OT_UNUSED_VARIABLE(aArgs);
119
120 otSrpServerSetEnabled(mInterpreter.mInstance, /* aEnabled */ false);
121
122 return OT_ERROR_NONE;
123 }
124
ProcessLease(Arg aArgs[])125 otError SrpServer::ProcessLease(Arg aArgs[])
126 {
127 otError error = OT_ERROR_NONE;
128 otSrpServerLeaseConfig leaseConfig;
129
130 if (aArgs[0].IsEmpty())
131 {
132 otSrpServerGetLeaseConfig(mInterpreter.mInstance, &leaseConfig);
133 mInterpreter.OutputLine("min lease: %u", leaseConfig.mMinLease);
134 mInterpreter.OutputLine("max lease: %u", leaseConfig.mMaxLease);
135 mInterpreter.OutputLine("min key-lease: %u", leaseConfig.mMinKeyLease);
136 mInterpreter.OutputLine("max key-lease: %u", leaseConfig.mMaxKeyLease);
137 }
138 else
139 {
140 SuccessOrExit(error = aArgs[0].ParseAsUint32(leaseConfig.mMinLease));
141 SuccessOrExit(error = aArgs[1].ParseAsUint32(leaseConfig.mMaxLease));
142 SuccessOrExit(error = aArgs[2].ParseAsUint32(leaseConfig.mMinKeyLease));
143 SuccessOrExit(error = aArgs[3].ParseAsUint32(leaseConfig.mMaxKeyLease));
144 VerifyOrExit(aArgs[4].IsEmpty(), error = OT_ERROR_INVALID_ARGS);
145
146 error = otSrpServerSetLeaseConfig(mInterpreter.mInstance, &leaseConfig);
147 }
148
149 exit:
150 return error;
151 }
152
ProcessHost(Arg aArgs[])153 otError SrpServer::ProcessHost(Arg aArgs[])
154 {
155 otError error = OT_ERROR_NONE;
156 const otSrpServerHost *host;
157
158 VerifyOrExit(aArgs[0].IsEmpty(), error = OT_ERROR_INVALID_ARGS);
159
160 host = nullptr;
161 while ((host = otSrpServerGetNextHost(mInterpreter.mInstance, host)) != nullptr)
162 {
163 const otIp6Address *addresses;
164 uint8_t addressesNum;
165 bool isDeleted = otSrpServerHostIsDeleted(host);
166
167 mInterpreter.OutputLine("%s", otSrpServerHostGetFullName(host));
168 mInterpreter.OutputLine(Interpreter::kIndentSize, "deleted: %s", isDeleted ? "true" : "false");
169 if (isDeleted)
170 {
171 continue;
172 }
173
174 mInterpreter.OutputSpaces(Interpreter::kIndentSize);
175 mInterpreter.OutputFormat("addresses: [");
176
177 addresses = otSrpServerHostGetAddresses(host, &addressesNum);
178
179 for (uint8_t i = 0; i < addressesNum; ++i)
180 {
181 mInterpreter.OutputIp6Address(addresses[i]);
182 if (i < addressesNum - 1)
183 {
184 mInterpreter.OutputFormat(", ");
185 }
186 }
187
188 mInterpreter.OutputFormat("]\r\n");
189 }
190
191 exit:
192 return error;
193 }
194
OutputHostAddresses(const otSrpServerHost * aHost)195 void SrpServer::OutputHostAddresses(const otSrpServerHost *aHost)
196 {
197 const otIp6Address *addresses;
198 uint8_t addressesNum;
199
200 addresses = otSrpServerHostGetAddresses(aHost, &addressesNum);
201
202 mInterpreter.OutputFormat("[");
203 for (uint8_t i = 0; i < addressesNum; ++i)
204 {
205 if (i != 0)
206 {
207 mInterpreter.OutputFormat(", ");
208 }
209
210 mInterpreter.OutputIp6Address(addresses[i]);
211 }
212 mInterpreter.OutputFormat("]");
213 }
214
ProcessService(Arg aArgs[])215 otError SrpServer::ProcessService(Arg aArgs[])
216 {
217 static constexpr char *kAnyServiceName = nullptr;
218 static constexpr char *kAnyInstanceName = nullptr;
219
220 otError error = OT_ERROR_NONE;
221 const otSrpServerHost *host = nullptr;
222
223 VerifyOrExit(aArgs[0].IsEmpty(), error = OT_ERROR_INVALID_ARGS);
224
225 while ((host = otSrpServerGetNextHost(mInterpreter.mInstance, host)) != nullptr)
226 {
227 const otSrpServerService *service = nullptr;
228
229 while ((service = otSrpServerHostFindNextService(host, service, OT_SRP_SERVER_FLAGS_BASE_TYPE_SERVICE_ONLY,
230 kAnyServiceName, kAnyInstanceName)) != nullptr)
231 {
232 bool isDeleted = otSrpServerServiceIsDeleted(service);
233 const char * instanceName = otSrpServerServiceGetInstanceName(service);
234 const otSrpServerService *subService = nullptr;
235 const uint8_t * txtData;
236 uint16_t txtDataLength;
237 bool hasSubType = false;
238
239 mInterpreter.OutputLine("%s", instanceName);
240 mInterpreter.OutputLine(Interpreter::kIndentSize, "deleted: %s", isDeleted ? "true" : "false");
241
242 if (isDeleted)
243 {
244 continue;
245 }
246
247 mInterpreter.OutputFormat(Interpreter::kIndentSize, "subtypes: ");
248
249 while ((subService = otSrpServerHostFindNextService(
250 host, subService, (OT_SRP_SERVER_SERVICE_FLAG_SUB_TYPE | OT_SRP_SERVER_SERVICE_FLAG_ACTIVE),
251 kAnyServiceName, instanceName)) != nullptr)
252 {
253 char subLabel[OT_DNS_MAX_LABEL_SIZE];
254
255 IgnoreError(otSrpServerServiceGetServiceSubTypeLabel(subService, subLabel, sizeof(subLabel)));
256 mInterpreter.OutputFormat("%s%s", hasSubType ? "," : "", subLabel);
257 hasSubType = true;
258 }
259
260 mInterpreter.OutputLine(hasSubType ? "" : "(null)");
261
262 mInterpreter.OutputLine(Interpreter::kIndentSize, "port: %hu", otSrpServerServiceGetPort(service));
263 mInterpreter.OutputLine(Interpreter::kIndentSize, "priority: %hu", otSrpServerServiceGetPriority(service));
264 mInterpreter.OutputLine(Interpreter::kIndentSize, "weight: %hu", otSrpServerServiceGetWeight(service));
265
266 txtData = otSrpServerServiceGetTxtData(service, &txtDataLength);
267 mInterpreter.OutputFormat(Interpreter::kIndentSize, "TXT: ");
268 mInterpreter.OutputDnsTxtData(txtData, txtDataLength);
269 mInterpreter.OutputLine("");
270
271 mInterpreter.OutputLine(Interpreter::kIndentSize, "host: %s", otSrpServerHostGetFullName(host));
272
273 mInterpreter.OutputFormat(Interpreter::kIndentSize, "addresses: ");
274 OutputHostAddresses(host);
275 mInterpreter.OutputLine("");
276 }
277 }
278
279 exit:
280 return error;
281 }
282
ProcessHelp(Arg aArgs[])283 otError SrpServer::ProcessHelp(Arg aArgs[])
284 {
285 OT_UNUSED_VARIABLE(aArgs);
286
287 for (const Command &command : sCommands)
288 {
289 mInterpreter.OutputLine(command.mName);
290 }
291
292 return OT_ERROR_NONE;
293 }
294
295 } // namespace Cli
296 } // namespace ot
297
298 #endif // OPENTHREAD_CONFIG_SRP_SERVER_ENABLE
299