1 /*
2  * Copyright (C) 2019 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "NdcDispatcher.h"
18 
19 #include <arpa/inet.h>
20 #include <dirent.h>
21 #include <errno.h>
22 #include <linux/if.h>
23 #include <netinet/in.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <sys/socket.h>
27 #include <sys/types.h>
28 
29 #include <cinttypes>
30 #include <string>
31 #include <vector>
32 
33 #include <android-base/logging.h>
34 #include <android-base/parseint.h>
35 #include <android-base/stringprintf.h>
36 #include <android-base/strings.h>
37 #include <android/multinetwork.h>
38 #include <netdutils/ResponseCode.h>
39 #include <netdutils/Status.h>
40 #include <netdutils/StatusOr.h>
41 #include <netutils/ifc.h>
42 
43 #include "NetdConstants.h"
44 #include "NetworkController.h"
45 #include "Permission.h"
46 #include "UidRanges.h"
47 #include "netid_client.h"
48 
49 using android::base::Join;
50 using android::base::StringPrintf;
51 using android::binder::Status;
52 
53 #define PARSE_INT_RETURN_IF_FAIL(cli, label, intLabel, errMsg, addErrno)         \
54     do {                                                                         \
55         if (!android::base::ParseInt((label), &(intLabel))) {                    \
56             errno = EINVAL;                                                      \
57             (cli)->sendMsg(ResponseCode::OperationFailed, (errMsg), (addErrno)); \
58             return 0;                                                            \
59         }                                                                        \
60     } while (0)
61 
62 #define PARSE_UINT_RETURN_IF_FAIL(cli, label, intLabel, errMsg, addErrno)        \
63     do {                                                                         \
64         if (!android::base::ParseUint((label), &(intLabel))) {                   \
65             errno = EINVAL;                                                      \
66             (cli)->sendMsg(ResponseCode::OperationFailed, (errMsg), (addErrno)); \
67             return 0;                                                            \
68         }                                                                        \
69     } while (0)
70 
71 namespace android {
72 
73 using netdutils::ResponseCode;
74 
75 namespace net {
76 namespace {
77 
78 const unsigned NUM_OEM_IDS = NetworkController::MAX_OEM_ID - NetworkController::MIN_OEM_ID + 1;
79 
stringToNetId(const char * arg)80 unsigned stringToNetId(const char* arg) {
81     if (!strcmp(arg, "local")) {
82         return NetworkController::LOCAL_NET_ID;
83     }
84     // OEM NetIds are "oem1", "oem2", .., "oem50".
85     if (!strncmp(arg, "oem", 3)) {
86         unsigned n = strtoul(arg + 3, nullptr, 0);
87         if (1 <= n && n <= NUM_OEM_IDS) {
88             return NetworkController::MIN_OEM_ID + n;
89         }
90         return NETID_UNSET;
91     } else if (!strncmp(arg, "handle", 6)) {
92         unsigned n = netHandleToNetId((net_handle_t)strtoull(arg + 6, nullptr, 10));
93         if (NetworkController::MIN_OEM_ID <= n && n <= NetworkController::MAX_OEM_ID) {
94             return n;
95         }
96         return NETID_UNSET;
97     }
98     // strtoul() returns 0 on errors, which is fine because 0 is an invalid netId.
99     return strtoul(arg, nullptr, 0);
100 }
101 
toStdString(const String16 & s)102 std::string toStdString(const String16& s) {
103     return std::string(String8(s.string()));
104 }
105 
stringToINetdPermission(const char * arg)106 int stringToINetdPermission(const char* arg) {
107     if (!strcmp(arg, "NETWORK")) {
108         return INetd::PERMISSION_NETWORK;
109     }
110     if (!strcmp(arg, "SYSTEM")) {
111         return INetd::PERMISSION_SYSTEM;
112     }
113     return INetd::PERMISSION_NONE;
114 }
115 
116 }  // namespace
117 
118 sp<INetd> NdcDispatcher::mNetd;
119 sp<IDnsResolver> NdcDispatcher::mDnsResolver;
120 
NdcDispatcher()121 NdcDispatcher::NdcDispatcher() {
122     sp<IServiceManager> sm = defaultServiceManager();
123     sp<IBinder> binderNetd = sm->getService(String16("netd"));
124     sp<IBinder> binderDnsResolver = sm->getService(String16("dnsresolver"));
125     if ((binderNetd != nullptr) && (binderDnsResolver != nullptr)) {
126         NdcDispatcher::mNetd = interface_cast<INetd>(binderNetd);
127         NdcDispatcher::mDnsResolver = interface_cast<IDnsResolver>(binderDnsResolver);
128     } else {
129         LOG(LOGLEVEL) << "Unable to get binder service";
130         exit(1);
131     }
132     registerCmd(new InterfaceCmd());
133     registerCmd(new IpFwdCmd());
134     registerCmd(new TetherCmd());
135     registerCmd(new NatCmd());
136     registerCmd(new BandwidthControlCmd());
137     registerCmd(new IdletimerControlCmd());
138     registerCmd(new FirewallCmd());
139     registerCmd(new ClatdCmd());
140     registerCmd(new NetworkCommand());
141     registerCmd(new StrictCmd());
142 }
143 
registerCmd(NdcNetdCommand * cmd)144 void NdcDispatcher::registerCmd(NdcNetdCommand* cmd) {
145     mCommands.push_back(cmd);
146 }
147 
dispatchCommand(int argc,char ** argv)148 int NdcDispatcher::dispatchCommand(int argc, char** argv) {
149     if (argc >= CMD_ARGS_MAX) {
150         mNdc.sendMsg(500, "Command too long", false);
151     }
152 
153     for (const auto* c : mCommands) {
154         if (c->getCommand() == argv[0]) {
155             if (c->runCommand(&mNdc, argc, argv)) {
156                 mNdc.sendMsg(500, "Handler error", true);
157             }
158             return 0;
159         }
160     }
161     mNdc.sendMsg(500, "Command not recognized", false);
162     return 0;
163 }
164 
InterfaceCmd()165 NdcDispatcher::InterfaceCmd::InterfaceCmd() : NdcNetdCommand("interface") {}
166 
runCommand(NdcClient * cli,int argc,char ** argv) const167 int NdcDispatcher::InterfaceCmd::runCommand(NdcClient* cli, int argc, char** argv) const {
168     if (argc < 2) {
169         cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
170         return 0;
171     }
172 
173     if (!strcmp(argv[1], "list")) {
174         std::vector<std::string> interfaceGetList;
175         Status status = mNetd->interfaceGetList(&interfaceGetList);
176 
177         if (!status.isOk()) {
178             errno = status.serviceSpecificErrorCode();
179             cli->sendMsg(ResponseCode::OperationFailed, "Failed to get interface list", true);
180             return 0;
181         }
182         for (const auto& iface : interfaceGetList) {
183             cli->sendMsg(ResponseCode::InterfaceListResult, iface.c_str(), false);
184         }
185 
186         cli->sendMsg(ResponseCode::CommandOkay, "Interface list completed", false);
187         return 0;
188     } else {
189         /*
190          * These commands take a minimum of 3 arguments
191          */
192         if (argc < 3) {
193             cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
194             return 0;
195         }
196 
197         if (!strcmp(argv[1], "getcfg")) {
198             InterfaceConfigurationParcel interfaceCfgResult;
199             Status status = mNetd->interfaceGetCfg(std::string(argv[2]), &interfaceCfgResult);
200 
201             if (!status.isOk()) {
202                 errno = status.serviceSpecificErrorCode();
203                 cli->sendMsg(ResponseCode::OperationFailed, "Interface not found", true);
204                 return 0;
205             }
206 
207             std::string flags = Join(interfaceCfgResult.flags, " ");
208 
209             std::string msg = StringPrintf("%s %s %d %s", interfaceCfgResult.hwAddr.c_str(),
210                                            interfaceCfgResult.ipv4Addr.c_str(),
211                                            interfaceCfgResult.prefixLength, flags.c_str());
212 
213             cli->sendMsg(ResponseCode::InterfaceGetCfgResult, msg.c_str(), false);
214 
215             return 0;
216         } else if (!strcmp(argv[1], "setcfg")) {
217             // arglist: iface [addr prefixLength] flags
218             if (argc < 4) {
219                 cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
220                 return 0;
221             }
222             LOG(LOGLEVEL) << "Setting iface cfg";
223 
224             struct in_addr addr;
225             int index = 5;
226             InterfaceConfigurationParcel interfaceCfg;
227             interfaceCfg.ifName = argv[2];
228             interfaceCfg.hwAddr = "";
229 
230             if (!inet_aton(argv[3], &addr)) {
231                 // Handle flags only case
232                 index = 3;
233                 interfaceCfg.ipv4Addr = "";
234                 interfaceCfg.prefixLength = 0;
235             } else {
236                 if (addr.s_addr != 0) {
237                     interfaceCfg.ipv4Addr = argv[3];
238                     PARSE_INT_RETURN_IF_FAIL(cli, argv[4], interfaceCfg.prefixLength,
239                                              "Failed to set address", true);
240                     Status status = mNetd->interfaceSetCfg(interfaceCfg);
241                     if (!status.isOk()) {
242                         errno = status.serviceSpecificErrorCode();
243                         cli->sendMsg(ResponseCode::OperationFailed, "Failed to set address", true);
244                         return 0;
245                     }
246                 }
247             }
248 
249             /* Process flags */
250             for (int i = index; i < argc; i++) {
251                 char* flag = argv[i];
252                 if (!strcmp(flag, "up")) {
253                     LOG(LOGLEVEL) << "Trying to bring up " << argv[2];
254                     interfaceCfg.flags.push_back(toStdString(INetd::IF_STATE_UP()));
255                     Status status = mNetd->interfaceSetCfg(interfaceCfg);
256                     if (!status.isOk()) {
257                         LOG(LOGLEVEL) << "Error upping interface";
258                         errno = status.serviceSpecificErrorCode();
259                         cli->sendMsg(ResponseCode::OperationFailed, "Failed to up interface", true);
260                         ifc_close();
261                         return 0;
262                     }
263                 } else if (!strcmp(flag, "down")) {
264                     LOG(LOGLEVEL) << "Trying to bring down " << argv[2];
265                     interfaceCfg.flags.push_back(toStdString(INetd::IF_STATE_DOWN()));
266                     Status status = mNetd->interfaceSetCfg(interfaceCfg);
267                     if (!status.isOk()) {
268                         LOG(LOGLEVEL) << "Error downing interface";
269                         errno = status.serviceSpecificErrorCode();
270                         cli->sendMsg(ResponseCode::OperationFailed, "Failed to down interface",
271                                      true);
272                         return 0;
273                     }
274                 } else if (!strcmp(flag, "broadcast") || !strcmp(flag, "multicast") ||
275                            !strcmp(flag, "running") || !strcmp(flag, "loopback") ||
276                            !strcmp(flag, "point-to-point")) {
277                     // currently ignored
278                 } else {
279                     cli->sendMsg(ResponseCode::CommandParameterError, "Flag unsupported", false);
280                     return 0;
281                 }
282             }
283 
284             cli->sendMsg(ResponseCode::CommandOkay, "Interface configuration set", false);
285             return 0;
286         } else if (!strcmp(argv[1], "clearaddrs")) {
287             // arglist: iface
288             LOG(LOGLEVEL) << "Clearing all IP addresses on " << argv[2];
289 
290             mNetd->interfaceClearAddrs(std::string(argv[2]));
291 
292             cli->sendMsg(ResponseCode::CommandOkay, "Interface IP addresses cleared", false);
293             return 0;
294         } else if (!strcmp(argv[1], "ipv6privacyextensions")) {
295             if (argc != 4) {
296                 cli->sendMsg(ResponseCode::CommandSyntaxError,
297                              "Usage: interface ipv6privacyextensions <interface> <enable|disable>",
298                              false);
299                 return 0;
300             }
301             int enable = !strcmp(argv[3], "enable");
302             Status status = mNetd->interfaceSetIPv6PrivacyExtensions(std::string(argv[2]), enable);
303             if (status.isOk()) {
304                 cli->sendMsg(ResponseCode::CommandOkay, "IPv6 privacy extensions changed", false);
305             } else {
306                 errno = status.serviceSpecificErrorCode();
307                 cli->sendMsg(ResponseCode::OperationFailed, "Failed to set ipv6 privacy extensions",
308                              true);
309             }
310             return 0;
311         } else if (!strcmp(argv[1], "ipv6")) {
312             if (argc != 4) {
313                 cli->sendMsg(ResponseCode::CommandSyntaxError,
314                              "Usage: interface ipv6 <interface> <enable|disable>", false);
315                 return 0;
316             }
317 
318             int enable = !strcmp(argv[3], "enable");
319             Status status = mNetd->interfaceSetEnableIPv6(std::string(argv[2]), enable);
320             if (status.isOk()) {
321                 cli->sendMsg(ResponseCode::CommandOkay, "IPv6 state changed", false);
322             } else {
323                 errno = status.serviceSpecificErrorCode();
324                 cli->sendMsg(ResponseCode::OperationFailed, "Failed to change IPv6 state", true);
325             }
326             return 0;
327         } else if (!strcmp(argv[1], "setmtu")) {
328             if (argc != 4) {
329                 cli->sendMsg(ResponseCode::CommandSyntaxError,
330                              "Usage: interface setmtu <interface> <val>", false);
331                 return 0;
332             }
333 
334             int mtuValue = 0;
335             PARSE_INT_RETURN_IF_FAIL(cli, argv[3], mtuValue, "Failed to set MTU", true);
336             Status status = mNetd->interfaceSetMtu(std::string(argv[2]), mtuValue);
337             if (status.isOk()) {
338                 cli->sendMsg(ResponseCode::CommandOkay, "MTU changed", false);
339             } else {
340                 errno = status.serviceSpecificErrorCode();
341                 cli->sendMsg(ResponseCode::OperationFailed, "Failed to set MTU", true);
342             }
343             return 0;
344         } else {
345             cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown interface cmd", false);
346             return 0;
347         }
348     }
349     return 0;
350 }
351 
IpFwdCmd()352 NdcDispatcher::IpFwdCmd::IpFwdCmd() : NdcNetdCommand("ipfwd") {}
353 
runCommand(NdcClient * cli,int argc,char ** argv) const354 int NdcDispatcher::IpFwdCmd::runCommand(NdcClient* cli, int argc, char** argv) const {
355     bool matched = false;
356     Status status;
357 
358     if (argc == 2) {
359         //   0     1
360         // ipfwd status
361         if (!strcmp(argv[1], "status")) {
362             bool ipfwdEnabled;
363             mNetd->ipfwdEnabled(&ipfwdEnabled);
364             std::string msg = StringPrintf("Forwarding %s", ipfwdEnabled ? "enabled" : "disabled");
365             cli->sendMsg(ResponseCode::IpFwdStatusResult, msg.c_str(), false);
366             return 0;
367         }
368     } else if (argc == 3) {
369         //  0      1         2
370         // ipfwd enable  <requester>
371         // ipfwd disable <requester>
372         if (!strcmp(argv[1], "enable")) {
373             matched = true;
374             status = mNetd->ipfwdEnableForwarding(argv[2]);
375         } else if (!strcmp(argv[1], "disable")) {
376             matched = true;
377             status = mNetd->ipfwdDisableForwarding(argv[2]);
378         }
379     } else if (argc == 4) {
380         //  0      1      2     3
381         // ipfwd  add   wlan0 dummy0
382         // ipfwd remove wlan0 dummy0
383         if (!strcmp(argv[1], "add")) {
384             matched = true;
385             status = mNetd->ipfwdAddInterfaceForward(argv[2], argv[3]);
386         } else if (!strcmp(argv[1], "remove")) {
387             matched = true;
388             status = mNetd->ipfwdRemoveInterfaceForward(argv[2], argv[3]);
389         }
390     }
391 
392     if (!matched) {
393         cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown ipfwd cmd", false);
394         return 0;
395     }
396 
397     if (status.isOk()) {
398         cli->sendMsg(ResponseCode::CommandOkay, "ipfwd operation succeeded", false);
399     } else {
400         errno = status.serviceSpecificErrorCode();
401         cli->sendMsg(ResponseCode::OperationFailed, "ipfwd operation failed", true);
402     }
403     return 0;
404 }
405 
TetherCmd()406 NdcDispatcher::TetherCmd::TetherCmd() : NdcNetdCommand("tether") {}
407 
runCommand(NdcClient * cli,int argc,char ** argv) const408 int NdcDispatcher::TetherCmd::runCommand(NdcClient* cli, int argc, char** argv) const {
409     Status status;
410 
411     if (argc < 2) {
412         cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
413         return 0;
414     }
415 
416     if (!strcmp(argv[1], "stop")) {
417         status = mNetd->tetherStop();
418     } else if (!strcmp(argv[1], "status")) {
419         bool tetherEnabled;
420         mNetd->tetherIsEnabled(&tetherEnabled);
421         std::string msg =
422                 StringPrintf("Tethering services %s", tetherEnabled ? "started" : "stopped");
423         cli->sendMsg(ResponseCode::TetherStatusResult, msg.c_str(), false);
424         return 0;
425     } else if (argc == 3) {
426         if (!strcmp(argv[1], "interface") && !strcmp(argv[2], "list")) {
427             std::vector<std::string> ifList;
428             mNetd->tetherInterfaceList(&ifList);
429             for (const auto& ifname : ifList) {
430                 cli->sendMsg(ResponseCode::TetherInterfaceListResult, ifname.c_str(), false);
431             }
432         }
433     } else if (!strcmp(argv[1], "start")) {
434         if (argc % 2 == 1) {
435             cli->sendMsg(ResponseCode::CommandSyntaxError, "Bad number of arguments", false);
436             return 0;
437         }
438 
439         std::vector<std::string> dhcpRanges;
440         // We do the checking of the pairs & addr invalidation in binderService/tetherController.
441         for (int arg_index = 2; arg_index < argc; arg_index++) {
442             dhcpRanges.push_back(argv[arg_index]);
443         }
444 
445         status = mNetd->tetherStart(dhcpRanges);
446     } else {
447         /*
448          * These commands take a minimum of 4 arguments
449          */
450         if (argc < 4) {
451             cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
452             return 0;
453         }
454 
455         if (!strcmp(argv[1], "interface")) {
456             if (!strcmp(argv[2], "add")) {
457                 status = mNetd->tetherInterfaceAdd(argv[3]);
458             } else if (!strcmp(argv[2], "remove")) {
459                 status = mNetd->tetherInterfaceRemove(argv[3]);
460                 /* else if (!strcmp(argv[2], "list")) handled above */
461             } else {
462                 cli->sendMsg(ResponseCode::CommandParameterError,
463                              "Unknown tether interface operation", false);
464                 return 0;
465             }
466         } else if (!strcmp(argv[1], "dns")) {
467             if (!strcmp(argv[2], "set")) {
468                 if (argc < 5) {
469                     cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
470                     return 0;
471                 }
472                 std::vector<std::string> tetherDnsAddrs;
473                 unsigned netId = stringToNetId(argv[3]);
474                 for (int arg_index = 4; arg_index < argc; arg_index++) {
475                     tetherDnsAddrs.push_back(argv[arg_index]);
476                 }
477                 status = mNetd->tetherDnsSet(netId, tetherDnsAddrs);
478                 /* else if (!strcmp(argv[2], "list")) handled above */
479             } else {
480                 cli->sendMsg(ResponseCode::CommandParameterError,
481                              "Unknown tether interface operation", false);
482                 return 0;
483             }
484         } else {
485             cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown tether cmd", false);
486             return 0;
487         }
488     }
489 
490     if (status.isOk()) {
491         cli->sendMsg(ResponseCode::CommandOkay, "Tether operation succeeded", false);
492     } else {
493         errno = status.serviceSpecificErrorCode();
494         cli->sendMsg(ResponseCode::OperationFailed, "Tether operation failed", true);
495     }
496 
497     return 0;
498 }
499 
NatCmd()500 NdcDispatcher::NatCmd::NatCmd() : NdcNetdCommand("nat") {}
501 
runCommand(NdcClient * cli,int argc,char ** argv) const502 int NdcDispatcher::NatCmd::runCommand(NdcClient* cli, int argc, char** argv) const {
503     Status status;
504 
505     if (argc < 5) {
506         cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
507         return 0;
508     }
509 
510     //  0     1       2        3
511     // nat  enable intiface extiface
512     // nat disable intiface extiface
513     if (!strcmp(argv[1], "enable") && argc >= 4) {
514         status = mNetd->tetherAddForward(argv[2], argv[3]);
515     } else if (!strcmp(argv[1], "disable") && argc >= 4) {
516         status = mNetd->tetherRemoveForward(argv[2], argv[3]);
517     } else {
518         cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown nat cmd", false);
519         return 0;
520     }
521 
522     if (status.isOk()) {
523         cli->sendMsg(ResponseCode::CommandOkay, "Nat operation succeeded", false);
524     } else {
525         errno = status.serviceSpecificErrorCode();
526         cli->sendMsg(ResponseCode::OperationFailed, "Nat operation failed", true);
527     }
528 
529     return 0;
530 }
531 
BandwidthControlCmd()532 NdcDispatcher::BandwidthControlCmd::BandwidthControlCmd() : NdcNetdCommand("bandwidth") {}
533 
sendGenericSyntaxError(NdcClient * cli,const char * usageMsg) const534 void NdcDispatcher::BandwidthControlCmd::sendGenericSyntaxError(NdcClient* cli,
535                                                                 const char* usageMsg) const {
536     char* msg;
537     asprintf(&msg, "Usage: bandwidth %s", usageMsg);
538     cli->sendMsg(ResponseCode::CommandSyntaxError, msg, false);
539     free(msg);
540 }
541 
sendGenericOkFail(NdcClient * cli,int cond) const542 void NdcDispatcher::BandwidthControlCmd::sendGenericOkFail(NdcClient* cli, int cond) const {
543     if (!cond) {
544         cli->sendMsg(ResponseCode::CommandOkay, "Bandwidth command succeeeded", false);
545     } else {
546         cli->sendMsg(ResponseCode::OperationFailed, "Bandwidth command failed", false);
547     }
548 }
549 
sendGenericOpFailed(NdcClient * cli,const char * errMsg) const550 void NdcDispatcher::BandwidthControlCmd::sendGenericOpFailed(NdcClient* cli,
551                                                              const char* errMsg) const {
552     cli->sendMsg(ResponseCode::OperationFailed, errMsg, false);
553 }
554 
runCommand(NdcClient * cli,int argc,char ** argv) const555 int NdcDispatcher::BandwidthControlCmd::runCommand(NdcClient* cli, int argc, char** argv) const {
556     if (argc < 2) {
557         sendGenericSyntaxError(cli, "<cmds> <args...>");
558         return 0;
559     }
560 
561     LOG(LOGLEVEL) << StringPrintf("bwctrlcmd: argc=%d %s %s ...", argc, argv[0], argv[1]).c_str();
562 
563     if (!strcmp(argv[1], "removeiquota") || !strcmp(argv[1], "riq")) {
564         if (argc != 3) {
565             sendGenericSyntaxError(cli, "removeiquota <interface>");
566             return 0;
567         }
568         int rc = !mNetd->bandwidthRemoveInterfaceQuota(argv[2]).isOk();
569         sendGenericOkFail(cli, rc);
570         return 0;
571     }
572     if (!strcmp(argv[1], "setiquota") || !strcmp(argv[1], "siq")) {
573         if (argc != 4) {
574             sendGenericSyntaxError(cli, "setiquota <interface> <bytes>");
575             return 0;
576         }
577         int64_t bytes = 0;
578         PARSE_INT_RETURN_IF_FAIL(cli, argv[3], bytes, "Bandwidth command failed", false);
579         int rc = !mNetd->bandwidthSetInterfaceQuota(argv[2], bytes).isOk();
580         sendGenericOkFail(cli, rc);
581         return 0;
582     }
583     if (!strcmp(argv[1], "addnaughtyapps") || !strcmp(argv[1], "ana")) {
584         if (argc < 3) {
585             sendGenericSyntaxError(cli, "addnaughtyapps <appUid> ...");
586             return 0;
587         }
588         int rc = 0;
589         for (int arg_index = 2; arg_index < argc; arg_index++) {
590             uid_t uid = 0;
591             PARSE_UINT_RETURN_IF_FAIL(cli, argv[arg_index], uid, "Bandwidth command failed", false);
592             rc = !mNetd->bandwidthAddNaughtyApp(uid).isOk();
593             if (rc) break;
594         }
595         sendGenericOkFail(cli, rc);
596         return 0;
597     }
598     if (!strcmp(argv[1], "removenaughtyapps") || !strcmp(argv[1], "rna")) {
599         if (argc < 3) {
600             sendGenericSyntaxError(cli, "removenaughtyapps <appUid> ...");
601             return 0;
602         }
603         int rc = 0;
604         for (int arg_index = 2; arg_index < argc; arg_index++) {
605             uid_t uid = 0;
606             PARSE_UINT_RETURN_IF_FAIL(cli, argv[arg_index], uid, "Bandwidth command failed", false);
607             rc = !mNetd->bandwidthRemoveNaughtyApp(uid).isOk();
608             if (rc) break;
609         }
610         sendGenericOkFail(cli, rc);
611         return 0;
612     }
613     if (!strcmp(argv[1], "addniceapps") || !strcmp(argv[1], "aha")) {
614         if (argc < 3) {
615             sendGenericSyntaxError(cli, "addniceapps <appUid> ...");
616             return 0;
617         }
618         int rc = 0;
619         for (int arg_index = 2; arg_index < argc; arg_index++) {
620             uid_t uid = 0;
621             PARSE_UINT_RETURN_IF_FAIL(cli, argv[arg_index], uid, "Bandwidth command failed", false);
622             rc = !mNetd->bandwidthAddNiceApp(uid).isOk();
623             if (rc) break;
624         }
625         sendGenericOkFail(cli, rc);
626         return 0;
627     }
628     if (!strcmp(argv[1], "removeniceapps") || !strcmp(argv[1], "rha")) {
629         if (argc < 3) {
630             sendGenericSyntaxError(cli, "removeniceapps <appUid> ...");
631             return 0;
632         }
633         int rc = 0;
634         for (int arg_index = 2; arg_index < argc; arg_index++) {
635             uid_t uid = 0;
636             PARSE_UINT_RETURN_IF_FAIL(cli, argv[arg_index], uid, "Bandwidth command failed", false);
637             rc = !mNetd->bandwidthRemoveNiceApp(uid).isOk();
638             if (rc) break;
639         }
640         sendGenericOkFail(cli, rc);
641         return 0;
642     }
643     if (!strcmp(argv[1], "setglobalalert") || !strcmp(argv[1], "sga")) {
644         if (argc != 3) {
645             sendGenericSyntaxError(cli, "setglobalalert <bytes>");
646             return 0;
647         }
648         int64_t bytes = 0;
649         PARSE_INT_RETURN_IF_FAIL(cli, argv[2], bytes, "Bandwidth command failed", false);
650         int rc = !mNetd->bandwidthSetGlobalAlert(bytes).isOk();
651         sendGenericOkFail(cli, rc);
652         return 0;
653     }
654     if (!strcmp(argv[1], "setinterfacealert") || !strcmp(argv[1], "sia")) {
655         if (argc != 4) {
656             sendGenericSyntaxError(cli, "setinterfacealert <interface> <bytes>");
657             return 0;
658         }
659         int64_t bytes = 0;
660         PARSE_INT_RETURN_IF_FAIL(cli, argv[3], bytes, "Bandwidth command failed", false);
661         int rc = !mNetd->bandwidthSetInterfaceAlert(argv[2], bytes).isOk();
662         sendGenericOkFail(cli, rc);
663         return 0;
664     }
665     if (!strcmp(argv[1], "removeinterfacealert") || !strcmp(argv[1], "ria")) {
666         if (argc != 3) {
667             sendGenericSyntaxError(cli, "removeinterfacealert <interface>");
668             return 0;
669         }
670         int rc = !mNetd->bandwidthRemoveInterfaceAlert(argv[2]).isOk();
671         sendGenericOkFail(cli, rc);
672         return 0;
673     }
674 
675     cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown bandwidth cmd", false);
676     return 0;
677 }
678 
IdletimerControlCmd()679 NdcDispatcher::IdletimerControlCmd::IdletimerControlCmd() : NdcNetdCommand("idletimer") {}
680 
runCommand(NdcClient * cli,int argc,char ** argv) const681 int NdcDispatcher::IdletimerControlCmd::runCommand(NdcClient* cli, int argc, char** argv) const {
682     // TODO(ashish): Change the error statements
683     if (argc < 2) {
684         cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
685         return 0;
686     }
687 
688     LOG(LOGLEVEL)
689             << StringPrintf("idletimerctrlcmd: argc=%d %s %s ...", argc, argv[0], argv[1]).c_str();
690 
691     if (!strcmp(argv[1], "add")) {
692         if (argc != 5) {
693             cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
694             return 0;
695         }
696 
697         int timeout = 0;
698         PARSE_INT_RETURN_IF_FAIL(cli, argv[3], timeout, "Failed to add interface", false);
699         Status status = mNetd->idletimerAddInterface(argv[2], timeout, argv[4]);
700         if (!status.isOk()) {
701             cli->sendMsg(ResponseCode::OperationFailed, "Failed to add interface", false);
702         } else {
703             cli->sendMsg(ResponseCode::CommandOkay, "Add success", false);
704         }
705         return 0;
706     }
707     if (!strcmp(argv[1], "remove")) {
708         if (argc != 5) {
709             cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
710             return 0;
711         }
712         int timeout = 0;
713         PARSE_INT_RETURN_IF_FAIL(cli, argv[3], timeout, "Failed to remove interface", false);
714         Status status = mNetd->idletimerRemoveInterface(argv[2], timeout, argv[4]);
715         if (!status.isOk()) {
716             cli->sendMsg(ResponseCode::OperationFailed, "Failed to remove interface", false);
717         } else {
718             cli->sendMsg(ResponseCode::CommandOkay, "Remove success", false);
719         }
720         return 0;
721     }
722 
723     cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown idletimer cmd", false);
724     return 0;
725 }
726 
FirewallCmd()727 NdcDispatcher::FirewallCmd::FirewallCmd() : NdcNetdCommand("firewall") {}
728 
sendGenericOkFail(NdcClient * cli,int cond) const729 int NdcDispatcher::FirewallCmd::sendGenericOkFail(NdcClient* cli, int cond) const {
730     if (!cond) {
731         cli->sendMsg(ResponseCode::CommandOkay, "Firewall command succeeded", false);
732     } else {
733         cli->sendMsg(ResponseCode::OperationFailed, "Firewall command failed", false);
734     }
735     return 0;
736 }
737 
parseRule(const char * arg)738 int NdcDispatcher::FirewallCmd::parseRule(const char* arg) {
739     if (!strcmp(arg, "allow")) {
740         return INetd::FIREWALL_RULE_ALLOW;
741     } else if (!strcmp(arg, "deny")) {
742         return INetd::FIREWALL_RULE_DENY;
743     } else {
744         LOG(LOGLEVEL) << "failed to parse uid rule " << arg;
745         return INetd::FIREWALL_RULE_ALLOW;
746     }
747 }
748 
parseFirewallType(const char * arg)749 int NdcDispatcher::FirewallCmd::parseFirewallType(const char* arg) {
750     if (!strcmp(arg, "allowlist")) {
751         return INetd::FIREWALL_ALLOWLIST;
752     } else if (!strcmp(arg, "denylist")) {
753         return INetd::FIREWALL_DENYLIST;
754     } else {
755         LOG(LOGLEVEL) << "failed to parse firewall type " << arg;
756         return INetd::FIREWALL_DENYLIST;
757     }
758 }
759 
parseChildChain(const char * arg)760 int NdcDispatcher::FirewallCmd::parseChildChain(const char* arg) {
761     if (!strcmp(arg, "dozable")) {
762         return INetd::FIREWALL_CHAIN_DOZABLE;
763     } else if (!strcmp(arg, "standby")) {
764         return INetd::FIREWALL_CHAIN_STANDBY;
765     } else if (!strcmp(arg, "powersave")) {
766         return INetd::FIREWALL_CHAIN_POWERSAVE;
767     } else if (!strcmp(arg, "restricted")) {
768         return INetd::FIREWALL_CHAIN_RESTRICTED;
769     } else if (!strcmp(arg, "none")) {
770         return INetd::FIREWALL_CHAIN_NONE;
771     } else {
772         LOG(LOGLEVEL) << "failed to parse child firewall chain " << arg;
773         return -1;
774     }
775 }
776 
runCommand(NdcClient * cli,int argc,char ** argv) const777 int NdcDispatcher::FirewallCmd::runCommand(NdcClient* cli, int argc, char** argv) const {
778     if (argc < 2) {
779         cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing command", false);
780         return 0;
781     }
782 
783     if (!strcmp(argv[1], "enable")) {
784         if (argc != 3) {
785             cli->sendMsg(ResponseCode::CommandSyntaxError,
786                          "Usage: firewall enable <allowlist|denylist>", false);
787             return 0;
788         }
789         int res = !mNetd->firewallSetFirewallType(parseFirewallType(argv[2])).isOk();
790         return sendGenericOkFail(cli, res);
791     }
792 
793     if (!strcmp(argv[1], "set_interface_rule")) {
794         if (argc != 4) {
795             cli->sendMsg(ResponseCode::CommandSyntaxError,
796                          "Usage: firewall set_interface_rule <rmnet0> <allow|deny>", false);
797             return 0;
798         }
799         int res = !mNetd->firewallSetInterfaceRule(argv[2], parseRule(argv[3])).isOk();
800         return sendGenericOkFail(cli, res);
801     }
802 
803     if (!strcmp(argv[1], "set_uid_rule")) {
804         if (argc != 5) {
805             cli->sendMsg(ResponseCode::CommandSyntaxError,
806                          "Usage: firewall set_uid_rule <dozable|standby|none> <1000> <allow|deny>",
807                          false);
808             return 0;
809         }
810 
811         int childChain = parseChildChain(argv[2]);
812         if (childChain == -1) {
813             cli->sendMsg(ResponseCode::CommandSyntaxError,
814                          "Invalid chain name. Valid names are: <dozable|standby|none>", false);
815             return 0;
816         }
817         uid_t uid = 0;
818         PARSE_UINT_RETURN_IF_FAIL(cli, argv[3], uid, "Firewall command failed", false);
819         int res = !mNetd->firewallSetUidRule(childChain, uid, parseRule(argv[4])).isOk();
820         return sendGenericOkFail(cli, res);
821     }
822 
823     if (!strcmp(argv[1], "enable_chain")) {
824         if (argc != 3) {
825             cli->sendMsg(ResponseCode::CommandSyntaxError,
826                          "Usage: firewall enable_chain <dozable|standby>", false);
827             return 0;
828         }
829         int res = !mNetd->firewallEnableChildChain(parseChildChain(argv[2]), true).isOk();
830         return sendGenericOkFail(cli, res);
831     }
832 
833     if (!strcmp(argv[1], "disable_chain")) {
834         if (argc != 3) {
835             cli->sendMsg(ResponseCode::CommandSyntaxError,
836                          "Usage: firewall disable_chain <dozable|standby>", false);
837             return 0;
838         }
839         int res = !mNetd->firewallEnableChildChain(parseChildChain(argv[2]), false).isOk();
840         return sendGenericOkFail(cli, res);
841     }
842 
843     cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown command", false);
844     return 0;
845 }
846 
ClatdCmd()847 NdcDispatcher::ClatdCmd::ClatdCmd() : NdcNetdCommand("clatd") {}
848 
runCommand(NdcClient * cli,int argc,char ** argv) const849 int NdcDispatcher::ClatdCmd::runCommand(NdcClient* cli, int argc, char** argv) const {
850     int rc = 0;
851     if (argc < 3) {
852         cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
853         return 0;
854     }
855 
856     std::string v6Addr;
857 
858     if (!strcmp(argv[1], "stop")) {
859         rc = !mNetd->clatdStop(argv[2]).isOk();
860     } else if (!strcmp(argv[1], "start")) {
861         if (argc < 4) {
862             cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
863             return 0;
864         }
865         rc = !mNetd->clatdStart(argv[2], argv[3], &v6Addr).isOk();
866     } else {
867         cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown clatd cmd", false);
868         return 0;
869     }
870 
871     if (!rc) {
872         cli->sendMsg(ResponseCode::CommandOkay,
873                      std::string(("Clatd operation succeeded ") + v6Addr).c_str(), false);
874     } else {
875         cli->sendMsg(ResponseCode::OperationFailed, "Clatd operation failed", false);
876     }
877 
878     return 0;
879 }
880 
StrictCmd()881 NdcDispatcher::StrictCmd::StrictCmd() : NdcNetdCommand("strict") {}
882 
sendGenericOkFail(NdcClient * cli,int cond) const883 int NdcDispatcher::StrictCmd::sendGenericOkFail(NdcClient* cli, int cond) const {
884     if (!cond) {
885         cli->sendMsg(ResponseCode::CommandOkay, "Strict command succeeded", false);
886     } else {
887         cli->sendMsg(ResponseCode::OperationFailed, "Strict command failed", false);
888     }
889     return 0;
890 }
891 
parsePenalty(const char * arg)892 int NdcDispatcher::StrictCmd::parsePenalty(const char* arg) {
893     if (!strcmp(arg, "reject")) {
894         return INetd::PENALTY_POLICY_REJECT;
895     } else if (!strcmp(arg, "log")) {
896         return INetd::PENALTY_POLICY_LOG;
897     } else if (!strcmp(arg, "accept")) {
898         return INetd::PENALTY_POLICY_ACCEPT;
899     } else {
900         return -1;
901     }
902 }
903 
runCommand(NdcClient * cli,int argc,char ** argv) const904 int NdcDispatcher::StrictCmd::runCommand(NdcClient* cli, int argc, char** argv) const {
905     if (argc < 2) {
906         cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing command", false);
907         return 0;
908     }
909 
910     if (!strcmp(argv[1], "set_uid_cleartext_policy")) {
911         if (argc != 4) {
912             cli->sendMsg(ResponseCode::CommandSyntaxError,
913                          "Usage: strict set_uid_cleartext_policy <uid> <accept|log|reject>", false);
914             return 0;
915         }
916 
917         errno = 0;
918         uid_t uid = 0;
919         PARSE_UINT_RETURN_IF_FAIL(cli, argv[2], uid, "Invalid UID", false);
920         if (uid > UID_MAX) {
921             cli->sendMsg(ResponseCode::CommandSyntaxError, "Invalid UID", false);
922             return 0;
923         }
924 
925         int penalty = parsePenalty(argv[3]);
926         if (penalty == -1) {
927             cli->sendMsg(ResponseCode::CommandSyntaxError, "Invalid penalty argument", false);
928             return 0;
929         }
930 
931         int res = !mNetd->strictUidCleartextPenalty(uid, penalty).isOk();
932         return sendGenericOkFail(cli, res);
933     }
934 
935     cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown command", false);
936     return 0;
937 }
938 
NetworkCommand()939 NdcDispatcher::NetworkCommand::NetworkCommand() : NdcNetdCommand("network") {}
940 
syntaxError(NdcClient * cli,const char * message) const941 int NdcDispatcher::NetworkCommand::syntaxError(NdcClient* cli, const char* message) const {
942     cli->sendMsg(ResponseCode::CommandSyntaxError, message, false);
943     return 0;
944 }
945 
operationError(NdcClient * cli,const char * message,int ret) const946 int NdcDispatcher::NetworkCommand::operationError(NdcClient* cli, const char* message,
947                                                   int ret) const {
948     errno = ret;
949     cli->sendMsg(ResponseCode::OperationFailed, message, true);
950     return 0;
951 }
952 
success(NdcClient * cli) const953 int NdcDispatcher::NetworkCommand::success(NdcClient* cli) const {
954     cli->sendMsg(ResponseCode::CommandOkay, "success", false);
955     return 0;
956 }
957 
runCommand(NdcClient * cli,int argc,char ** argv) const958 int NdcDispatcher::NetworkCommand::runCommand(NdcClient* cli, int argc, char** argv) const {
959     if (argc < 2) {
960         return syntaxError(cli, "Missing argument");
961     }
962 
963     //    0      1      2      3      4       5         6            7           8
964     // network route [legacy <uid>]  add   <netId> <interface> <destination> [nexthop]
965     // network route [legacy <uid>] remove <netId> <interface> <destination> [nexthop]
966     //
967     // nexthop may be either an IPv4/IPv6 address or one of "unreachable" or "throw".
968     if (!strcmp(argv[1], "route")) {
969         if (argc < 6 || argc > 9) {
970             return syntaxError(cli, "Incorrect number of arguments");
971         }
972 
973         int nextArg = 2;
974         bool legacy = false;
975         uid_t uid = 0;
976         if (!strcmp(argv[nextArg], "legacy")) {
977             ++nextArg;
978             legacy = true;
979             PARSE_UINT_RETURN_IF_FAIL(cli, argv[nextArg++], uid, "Unknown argument", false);
980         }
981 
982         bool add = false;
983         if (!strcmp(argv[nextArg], "add")) {
984             add = true;
985         } else if (strcmp(argv[nextArg], "remove") != 0) {
986             return syntaxError(cli, "Unknown argument");
987         }
988         ++nextArg;
989 
990         if (argc < nextArg + 3 || argc > nextArg + 4) {
991             return syntaxError(cli, "Incorrect number of arguments");
992         }
993 
994         unsigned netId = stringToNetId(argv[nextArg++]);
995         const char* interface = argv[nextArg++];
996         const char* destination = argv[nextArg++];
997         const char* nexthop = argc > nextArg ? argv[nextArg] : "";
998 
999         Status status;
1000         if (legacy) {
1001             status = add ? mNetd->networkAddLegacyRoute(netId, interface, destination, nexthop, uid)
1002 
1003                          : mNetd->networkRemoveLegacyRoute(netId, interface, destination, nexthop,
1004                                                            uid);
1005         } else {
1006             status = add ? mNetd->networkAddRoute(netId, interface, destination, nexthop)
1007                          : mNetd->networkRemoveRoute(netId, interface, destination, nexthop);
1008         }
1009 
1010         if (!status.isOk()) {
1011             return operationError(cli, add ? "addRoute() failed" : "removeRoute() failed",
1012                                   status.serviceSpecificErrorCode());
1013         }
1014 
1015         return success(cli);
1016     }
1017 
1018     //    0        1       2       3         4
1019     // network interface  add   <netId> <interface>
1020     // network interface remove <netId> <interface>
1021     if (!strcmp(argv[1], "interface")) {
1022         if (argc != 5) {
1023             return syntaxError(cli, "Missing argument");
1024         }
1025         unsigned netId = stringToNetId(argv[3]);
1026         if (!strcmp(argv[2], "add")) {
1027             if (Status status = mNetd->networkAddInterface(netId, argv[4]); !status.isOk()) {
1028                 return operationError(cli, "addInterfaceToNetwork() failed",
1029                                       status.serviceSpecificErrorCode());
1030             }
1031         } else if (!strcmp(argv[2], "remove")) {
1032             if (Status status = mNetd->networkRemoveInterface(netId, argv[4]); !status.isOk()) {
1033                 return operationError(cli, "removeInterfaceFromNetwork() failed",
1034                                       status.serviceSpecificErrorCode());
1035             }
1036         } else {
1037             return syntaxError(cli, "Unknown argument");
1038         }
1039         return success(cli);
1040     }
1041 
1042     //    0      1       2         3
1043     // network create <netId> [permission]
1044     //
1045     //    0      1       2     3      4
1046     // network create <netId> vpn <secure>
1047     if (!strcmp(argv[1], "create")) {
1048         if (argc < 3) {
1049             return syntaxError(cli, "Missing argument");
1050         }
1051         unsigned netId = stringToNetId(argv[2]);
1052         if (argc == 5 && !strcmp(argv[3], "vpn")) {
1053             bool secure = strtol(argv[4], nullptr, 2);
1054 #pragma clang diagnostic push
1055 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
1056             if (Status status = mNetd->networkCreateVpn(netId, secure); !status.isOk()) {
1057 #pragma clang diagnostic pop
1058                 return operationError(cli, "createVirtualNetwork() failed",
1059                                       status.serviceSpecificErrorCode());
1060             }
1061         } else if (argc > 4) {
1062             return syntaxError(cli, "Unknown trailing argument(s)");
1063         } else {
1064             int permission = INetd::PERMISSION_NONE;
1065             if (argc == 4) {
1066                 permission = stringToINetdPermission(argv[3]);
1067                 if (permission == INetd::PERMISSION_NONE) {
1068                     return syntaxError(cli, "Unknown permission");
1069                 }
1070             }
1071 #pragma clang diagnostic push
1072 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
1073             if (Status status = mNetd->networkCreatePhysical(netId, permission); !status.isOk()) {
1074 #pragma clang diagnostic pop
1075                 return operationError(cli, "createPhysicalNetwork() failed",
1076                                       status.serviceSpecificErrorCode());
1077             }
1078         }
1079         return success(cli);
1080     }
1081 
1082     //    0       1       2
1083     // network destroy <netId>
1084     if (!strcmp(argv[1], "destroy")) {
1085         if (argc != 3) {
1086             return syntaxError(cli, "Incorrect number of arguments");
1087         }
1088         unsigned netId = stringToNetId(argv[2]);
1089         // Both of these functions manage their own locking internally.
1090         if (Status status = mNetd->networkDestroy(netId); !status.isOk()) {
1091             return operationError(cli, "destroyNetwork() failed",
1092                                   status.serviceSpecificErrorCode());
1093         }
1094         mDnsResolver->destroyNetworkCache(netId);
1095         return success(cli);
1096     }
1097 
1098     //    0       1      2      3
1099     // network default  set  <netId>
1100     // network default clear
1101     if (!strcmp(argv[1], "default")) {
1102         if (argc < 3) {
1103             return syntaxError(cli, "Missing argument");
1104         }
1105         unsigned netId = NETID_UNSET;
1106         if (!strcmp(argv[2], "set")) {
1107             if (argc < 4) {
1108                 return syntaxError(cli, "Missing netId");
1109             }
1110             netId = stringToNetId(argv[3]);
1111         } else if (strcmp(argv[2], "clear") != 0) {
1112             return syntaxError(cli, "Unknown argument");
1113         }
1114         if (Status status = mNetd->networkSetDefault(netId); !status.isOk()) {
1115             return operationError(cli, "setDefaultNetwork() failed",
1116                                   status.serviceSpecificErrorCode());
1117         }
1118         return success(cli);
1119     }
1120 
1121     //    0        1         2      3        4          5
1122     // network permission   user   set  <permission>  <uid> ...
1123     // network permission   user  clear    <uid> ...
1124     // network permission network  set  <permission> <netId> ...
1125     // network permission network clear   <netId> ...
1126     if (!strcmp(argv[1], "permission")) {
1127         if (argc < 5) {
1128             return syntaxError(cli, "Missing argument");
1129         }
1130         int nextArg = 4;
1131         int permission = INetd::PERMISSION_NONE;
1132         if (!strcmp(argv[3], "set")) {
1133             permission = stringToINetdPermission(argv[4]);
1134             if (permission == INetd::PERMISSION_NONE) {
1135                 return syntaxError(cli, "Unknown permission");
1136             }
1137             nextArg = 5;
1138         } else if (strcmp(argv[3], "clear") != 0) {
1139             return syntaxError(cli, "Unknown argument");
1140         }
1141         if (nextArg == argc) {
1142             return syntaxError(cli, "Missing id");
1143         }
1144 
1145         bool userPermissions = !strcmp(argv[2], "user");
1146         bool networkPermissions = !strcmp(argv[2], "network");
1147         if (!userPermissions && !networkPermissions) {
1148             return syntaxError(cli, "Unknown argument");
1149         }
1150 
1151         std::vector<int32_t> ids;
1152         for (; nextArg < argc; ++nextArg) {
1153             if (userPermissions) {
1154                 char* endPtr;
1155                 unsigned id = strtoul(argv[nextArg], &endPtr, 0);
1156                 if (!*argv[nextArg] || *endPtr) {
1157                     return syntaxError(cli, "Invalid id");
1158                 }
1159                 ids.push_back(id);
1160             } else {
1161                 // networkPermissions
1162                 ids.push_back(stringToNetId(argv[nextArg]));
1163             }
1164         }
1165         if (userPermissions) {
1166             mNetd->networkSetPermissionForUser(permission, ids);
1167         } else {
1168             // networkPermissions
1169             for (auto netId : ids) {
1170                 Status status = mNetd->networkSetPermissionForNetwork(netId, permission);
1171                 if (!status.isOk())
1172                     return operationError(cli, "setPermissionForNetworks() failed",
1173                                           status.serviceSpecificErrorCode());
1174             }
1175         }
1176 
1177         return success(cli);
1178     }
1179 
1180     //    0      1     2       3           4
1181     // network users  add   <netId> [<uid>[-<uid>]] ...
1182     // network users remove <netId> [<uid>[-<uid>]] ...
1183     if (!strcmp(argv[1], "users")) {
1184         if (argc < 4) {
1185             return syntaxError(cli, "Missing argument");
1186         }
1187         unsigned netId = stringToNetId(argv[3]);
1188         UidRanges uidRanges;
1189         if (!uidRanges.parseFrom(argc - 4, argv + 4)) {
1190             return syntaxError(cli, "Invalid UIDs");
1191         }
1192         if (!strcmp(argv[2], "add")) {
1193             if (Status status = mNetd->networkAddUidRanges(netId, uidRanges.getRanges());
1194                 !status.isOk()) {
1195                 return operationError(cli, "addUsersToNetwork() failed",
1196                                       status.serviceSpecificErrorCode());
1197             }
1198         } else if (!strcmp(argv[2], "remove")) {
1199             if (Status status = mNetd->networkRemoveUidRanges(netId, uidRanges.getRanges());
1200                 !status.isOk()) {
1201                 return operationError(cli, "removeUsersFromNetwork() failed",
1202                                       status.serviceSpecificErrorCode());
1203             }
1204         } else {
1205             return syntaxError(cli, "Unknown argument");
1206         }
1207         return success(cli);
1208     }
1209 
1210     //    0       1      2     3
1211     // network protect allow <uid> ...
1212     // network protect  deny <uid> ...
1213     if (!strcmp(argv[1], "protect")) {
1214         if (argc < 4) {
1215             return syntaxError(cli, "Missing argument");
1216         }
1217         std::vector<uid_t> uids;
1218         for (int i = 3; i < argc; ++i) {
1219             uid_t uid = 0;
1220             PARSE_UINT_RETURN_IF_FAIL(cli, argv[i], uid, "Unknown argument", false);
1221             uids.push_back(uid);
1222         }
1223         if (!strcmp(argv[2], "allow")) {
1224             for (auto uid : uids) {
1225                 mNetd->networkSetProtectAllow(uid);
1226             }
1227         } else if (!strcmp(argv[2], "deny")) {
1228             for (auto uid : uids) {
1229                 mNetd->networkSetProtectDeny(uid);
1230             }
1231         } else {
1232             return syntaxError(cli, "Unknown argument");
1233         }
1234         return success(cli);
1235     }
1236 
1237     return syntaxError(cli, "Unknown argument");
1238 }
1239 
1240 }  // namespace net
1241 }  // namespace android
1242