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