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_WHITELIST;
752     } else if (!strcmp(arg, "denylist")) {
753         return INetd::FIREWALL_BLACKLIST;
754     } else {
755         LOG(LOGLEVEL) << "failed to parse firewall type " << arg;
756         return INetd::FIREWALL_BLACKLIST;
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, "none")) {
768         return INetd::FIREWALL_CHAIN_NONE;
769     } else {
770         LOG(LOGLEVEL) << "failed to parse child firewall chain " << arg;
771         return -1;
772     }
773 }
774 
runCommand(NdcClient * cli,int argc,char ** argv) const775 int NdcDispatcher::FirewallCmd::runCommand(NdcClient* cli, int argc, char** argv) const {
776     if (argc < 2) {
777         cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing command", false);
778         return 0;
779     }
780 
781     if (!strcmp(argv[1], "enable")) {
782         if (argc != 3) {
783             cli->sendMsg(ResponseCode::CommandSyntaxError,
784                          "Usage: firewall enable <allowlist|denylist>", false);
785             return 0;
786         }
787         int res = !mNetd->firewallSetFirewallType(parseFirewallType(argv[2])).isOk();
788         return sendGenericOkFail(cli, res);
789     }
790 
791     if (!strcmp(argv[1], "set_interface_rule")) {
792         if (argc != 4) {
793             cli->sendMsg(ResponseCode::CommandSyntaxError,
794                          "Usage: firewall set_interface_rule <rmnet0> <allow|deny>", false);
795             return 0;
796         }
797         int res = !mNetd->firewallSetInterfaceRule(argv[2], parseRule(argv[3])).isOk();
798         return sendGenericOkFail(cli, res);
799     }
800 
801     if (!strcmp(argv[1], "set_uid_rule")) {
802         if (argc != 5) {
803             cli->sendMsg(ResponseCode::CommandSyntaxError,
804                          "Usage: firewall set_uid_rule <dozable|standby|none> <1000> <allow|deny>",
805                          false);
806             return 0;
807         }
808 
809         int childChain = parseChildChain(argv[2]);
810         if (childChain == -1) {
811             cli->sendMsg(ResponseCode::CommandSyntaxError,
812                          "Invalid chain name. Valid names are: <dozable|standby|none>", false);
813             return 0;
814         }
815         uid_t uid = 0;
816         PARSE_UINT_RETURN_IF_FAIL(cli, argv[3], uid, "Firewall command failed", false);
817         int res = !mNetd->firewallSetUidRule(childChain, uid, parseRule(argv[4])).isOk();
818         return sendGenericOkFail(cli, res);
819     }
820 
821     if (!strcmp(argv[1], "enable_chain")) {
822         if (argc != 3) {
823             cli->sendMsg(ResponseCode::CommandSyntaxError,
824                          "Usage: firewall enable_chain <dozable|standby>", false);
825             return 0;
826         }
827         int res = !mNetd->firewallEnableChildChain(parseChildChain(argv[2]), true).isOk();
828         return sendGenericOkFail(cli, res);
829     }
830 
831     if (!strcmp(argv[1], "disable_chain")) {
832         if (argc != 3) {
833             cli->sendMsg(ResponseCode::CommandSyntaxError,
834                          "Usage: firewall disable_chain <dozable|standby>", false);
835             return 0;
836         }
837         int res = !mNetd->firewallEnableChildChain(parseChildChain(argv[2]), false).isOk();
838         return sendGenericOkFail(cli, res);
839     }
840 
841     cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown command", false);
842     return 0;
843 }
844 
ClatdCmd()845 NdcDispatcher::ClatdCmd::ClatdCmd() : NdcNetdCommand("clatd") {}
846 
runCommand(NdcClient * cli,int argc,char ** argv) const847 int NdcDispatcher::ClatdCmd::runCommand(NdcClient* cli, int argc, char** argv) const {
848     int rc = 0;
849     if (argc < 3) {
850         cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
851         return 0;
852     }
853 
854     std::string v6Addr;
855 
856     if (!strcmp(argv[1], "stop")) {
857         rc = !mNetd->clatdStop(argv[2]).isOk();
858     } else if (!strcmp(argv[1], "start")) {
859         if (argc < 4) {
860             cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
861             return 0;
862         }
863         rc = !mNetd->clatdStart(argv[2], argv[3], &v6Addr).isOk();
864     } else {
865         cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown clatd cmd", false);
866         return 0;
867     }
868 
869     if (!rc) {
870         cli->sendMsg(ResponseCode::CommandOkay,
871                      std::string(("Clatd operation succeeded ") + v6Addr).c_str(), false);
872     } else {
873         cli->sendMsg(ResponseCode::OperationFailed, "Clatd operation failed", false);
874     }
875 
876     return 0;
877 }
878 
StrictCmd()879 NdcDispatcher::StrictCmd::StrictCmd() : NdcNetdCommand("strict") {}
880 
sendGenericOkFail(NdcClient * cli,int cond) const881 int NdcDispatcher::StrictCmd::sendGenericOkFail(NdcClient* cli, int cond) const {
882     if (!cond) {
883         cli->sendMsg(ResponseCode::CommandOkay, "Strict command succeeded", false);
884     } else {
885         cli->sendMsg(ResponseCode::OperationFailed, "Strict command failed", false);
886     }
887     return 0;
888 }
889 
parsePenalty(const char * arg)890 int NdcDispatcher::StrictCmd::parsePenalty(const char* arg) {
891     if (!strcmp(arg, "reject")) {
892         return INetd::PENALTY_POLICY_REJECT;
893     } else if (!strcmp(arg, "log")) {
894         return INetd::PENALTY_POLICY_LOG;
895     } else if (!strcmp(arg, "accept")) {
896         return INetd::PENALTY_POLICY_ACCEPT;
897     } else {
898         return -1;
899     }
900 }
901 
runCommand(NdcClient * cli,int argc,char ** argv) const902 int NdcDispatcher::StrictCmd::runCommand(NdcClient* cli, int argc, char** argv) const {
903     if (argc < 2) {
904         cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing command", false);
905         return 0;
906     }
907 
908     if (!strcmp(argv[1], "set_uid_cleartext_policy")) {
909         if (argc != 4) {
910             cli->sendMsg(ResponseCode::CommandSyntaxError,
911                          "Usage: strict set_uid_cleartext_policy <uid> <accept|log|reject>", false);
912             return 0;
913         }
914 
915         errno = 0;
916         uid_t uid = 0;
917         PARSE_UINT_RETURN_IF_FAIL(cli, argv[2], uid, "Invalid UID", false);
918         if (uid > UID_MAX) {
919             cli->sendMsg(ResponseCode::CommandSyntaxError, "Invalid UID", false);
920             return 0;
921         }
922 
923         int penalty = parsePenalty(argv[3]);
924         if (penalty == -1) {
925             cli->sendMsg(ResponseCode::CommandSyntaxError, "Invalid penalty argument", false);
926             return 0;
927         }
928 
929         int res = !mNetd->strictUidCleartextPenalty(uid, penalty).isOk();
930         return sendGenericOkFail(cli, res);
931     }
932 
933     cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown command", false);
934     return 0;
935 }
936 
NetworkCommand()937 NdcDispatcher::NetworkCommand::NetworkCommand() : NdcNetdCommand("network") {}
938 
syntaxError(NdcClient * cli,const char * message) const939 int NdcDispatcher::NetworkCommand::syntaxError(NdcClient* cli, const char* message) const {
940     cli->sendMsg(ResponseCode::CommandSyntaxError, message, false);
941     return 0;
942 }
943 
operationError(NdcClient * cli,const char * message,int ret) const944 int NdcDispatcher::NetworkCommand::operationError(NdcClient* cli, const char* message,
945                                                   int ret) const {
946     errno = ret;
947     cli->sendMsg(ResponseCode::OperationFailed, message, true);
948     return 0;
949 }
950 
success(NdcClient * cli) const951 int NdcDispatcher::NetworkCommand::success(NdcClient* cli) const {
952     cli->sendMsg(ResponseCode::CommandOkay, "success", false);
953     return 0;
954 }
955 
runCommand(NdcClient * cli,int argc,char ** argv) const956 int NdcDispatcher::NetworkCommand::runCommand(NdcClient* cli, int argc, char** argv) const {
957     if (argc < 2) {
958         return syntaxError(cli, "Missing argument");
959     }
960 
961     //    0      1      2      3      4       5         6            7           8
962     // network route [legacy <uid>]  add   <netId> <interface> <destination> [nexthop]
963     // network route [legacy <uid>] remove <netId> <interface> <destination> [nexthop]
964     //
965     // nexthop may be either an IPv4/IPv6 address or one of "unreachable" or "throw".
966     if (!strcmp(argv[1], "route")) {
967         if (argc < 6 || argc > 9) {
968             return syntaxError(cli, "Incorrect number of arguments");
969         }
970 
971         int nextArg = 2;
972         bool legacy = false;
973         uid_t uid = 0;
974         if (!strcmp(argv[nextArg], "legacy")) {
975             ++nextArg;
976             legacy = true;
977             PARSE_UINT_RETURN_IF_FAIL(cli, argv[nextArg++], uid, "Unknown argument", false);
978         }
979 
980         bool add = false;
981         if (!strcmp(argv[nextArg], "add")) {
982             add = true;
983         } else if (strcmp(argv[nextArg], "remove") != 0) {
984             return syntaxError(cli, "Unknown argument");
985         }
986         ++nextArg;
987 
988         if (argc < nextArg + 3 || argc > nextArg + 4) {
989             return syntaxError(cli, "Incorrect number of arguments");
990         }
991 
992         unsigned netId = stringToNetId(argv[nextArg++]);
993         const char* interface = argv[nextArg++];
994         const char* destination = argv[nextArg++];
995         const char* nexthop = argc > nextArg ? argv[nextArg] : "";
996 
997         Status status;
998         if (legacy) {
999             status = add ? mNetd->networkAddLegacyRoute(netId, interface, destination, nexthop, uid)
1000 
1001                          : mNetd->networkRemoveLegacyRoute(netId, interface, destination, nexthop,
1002                                                            uid);
1003         } else {
1004             status = add ? mNetd->networkAddRoute(netId, interface, destination, nexthop)
1005                          : mNetd->networkRemoveRoute(netId, interface, destination, nexthop);
1006         }
1007 
1008         if (!status.isOk()) {
1009             return operationError(cli, add ? "addRoute() failed" : "removeRoute() failed",
1010                                   status.serviceSpecificErrorCode());
1011         }
1012 
1013         return success(cli);
1014     }
1015 
1016     //    0        1       2       3         4
1017     // network interface  add   <netId> <interface>
1018     // network interface remove <netId> <interface>
1019     if (!strcmp(argv[1], "interface")) {
1020         if (argc != 5) {
1021             return syntaxError(cli, "Missing argument");
1022         }
1023         unsigned netId = stringToNetId(argv[3]);
1024         if (!strcmp(argv[2], "add")) {
1025             if (Status status = mNetd->networkAddInterface(netId, argv[4]); !status.isOk()) {
1026                 return operationError(cli, "addInterfaceToNetwork() failed",
1027                                       status.serviceSpecificErrorCode());
1028             }
1029         } else if (!strcmp(argv[2], "remove")) {
1030             if (Status status = mNetd->networkRemoveInterface(netId, argv[4]); !status.isOk()) {
1031                 return operationError(cli, "removeInterfaceFromNetwork() failed",
1032                                       status.serviceSpecificErrorCode());
1033             }
1034         } else {
1035             return syntaxError(cli, "Unknown argument");
1036         }
1037         return success(cli);
1038     }
1039 
1040     //    0      1       2         3
1041     // network create <netId> [permission]
1042     //
1043     //    0      1       2     3      4
1044     // network create <netId> vpn <secure>
1045     if (!strcmp(argv[1], "create")) {
1046         if (argc < 3) {
1047             return syntaxError(cli, "Missing argument");
1048         }
1049         unsigned netId = stringToNetId(argv[2]);
1050         if (argc == 6 && !strcmp(argv[3], "vpn")) {
1051             bool secure = strtol(argv[4], nullptr, 2);
1052             if (Status status = mNetd->networkCreateVpn(netId, secure); !status.isOk()) {
1053                 return operationError(cli, "createVirtualNetwork() failed",
1054                                       status.serviceSpecificErrorCode());
1055             }
1056         } else if (argc > 4) {
1057             return syntaxError(cli, "Unknown trailing argument(s)");
1058         } else {
1059             int permission = INetd::PERMISSION_NONE;
1060             if (argc == 4) {
1061                 permission = stringToINetdPermission(argv[3]);
1062                 if (permission == INetd::PERMISSION_NONE) {
1063                     return syntaxError(cli, "Unknown permission");
1064                 }
1065             }
1066             if (Status status = mNetd->networkCreatePhysical(netId, permission); !status.isOk()) {
1067                 return operationError(cli, "createPhysicalNetwork() failed",
1068                                       status.serviceSpecificErrorCode());
1069             }
1070         }
1071         return success(cli);
1072     }
1073 
1074     //    0       1       2
1075     // network destroy <netId>
1076     if (!strcmp(argv[1], "destroy")) {
1077         if (argc != 3) {
1078             return syntaxError(cli, "Incorrect number of arguments");
1079         }
1080         unsigned netId = stringToNetId(argv[2]);
1081         // Both of these functions manage their own locking internally.
1082         if (Status status = mNetd->networkDestroy(netId); !status.isOk()) {
1083             return operationError(cli, "destroyNetwork() failed",
1084                                   status.serviceSpecificErrorCode());
1085         }
1086         mDnsResolver->destroyNetworkCache(netId);
1087         return success(cli);
1088     }
1089 
1090     //    0       1      2      3
1091     // network default  set  <netId>
1092     // network default clear
1093     if (!strcmp(argv[1], "default")) {
1094         if (argc < 3) {
1095             return syntaxError(cli, "Missing argument");
1096         }
1097         unsigned netId = NETID_UNSET;
1098         if (!strcmp(argv[2], "set")) {
1099             if (argc < 4) {
1100                 return syntaxError(cli, "Missing netId");
1101             }
1102             netId = stringToNetId(argv[3]);
1103         } else if (strcmp(argv[2], "clear") != 0) {
1104             return syntaxError(cli, "Unknown argument");
1105         }
1106         if (Status status = mNetd->networkSetDefault(netId); !status.isOk()) {
1107             return operationError(cli, "setDefaultNetwork() failed",
1108                                   status.serviceSpecificErrorCode());
1109         }
1110         return success(cli);
1111     }
1112 
1113     //    0        1         2      3        4          5
1114     // network permission   user   set  <permission>  <uid> ...
1115     // network permission   user  clear    <uid> ...
1116     // network permission network  set  <permission> <netId> ...
1117     // network permission network clear   <netId> ...
1118     if (!strcmp(argv[1], "permission")) {
1119         if (argc < 5) {
1120             return syntaxError(cli, "Missing argument");
1121         }
1122         int nextArg = 4;
1123         int permission = INetd::PERMISSION_NONE;
1124         if (!strcmp(argv[3], "set")) {
1125             permission = stringToINetdPermission(argv[4]);
1126             if (permission == INetd::PERMISSION_NONE) {
1127                 return syntaxError(cli, "Unknown permission");
1128             }
1129             nextArg = 5;
1130         } else if (strcmp(argv[3], "clear") != 0) {
1131             return syntaxError(cli, "Unknown argument");
1132         }
1133         if (nextArg == argc) {
1134             return syntaxError(cli, "Missing id");
1135         }
1136 
1137         bool userPermissions = !strcmp(argv[2], "user");
1138         bool networkPermissions = !strcmp(argv[2], "network");
1139         if (!userPermissions && !networkPermissions) {
1140             return syntaxError(cli, "Unknown argument");
1141         }
1142 
1143         std::vector<int32_t> ids;
1144         for (; nextArg < argc; ++nextArg) {
1145             if (userPermissions) {
1146                 char* endPtr;
1147                 unsigned id = strtoul(argv[nextArg], &endPtr, 0);
1148                 if (!*argv[nextArg] || *endPtr) {
1149                     return syntaxError(cli, "Invalid id");
1150                 }
1151                 ids.push_back(id);
1152             } else {
1153                 // networkPermissions
1154                 ids.push_back(stringToNetId(argv[nextArg]));
1155             }
1156         }
1157         if (userPermissions) {
1158             mNetd->networkSetPermissionForUser(permission, ids);
1159         } else {
1160             // networkPermissions
1161             for (auto netId : ids) {
1162                 Status status = mNetd->networkSetPermissionForNetwork(netId, permission);
1163                 if (!status.isOk())
1164                     return operationError(cli, "setPermissionForNetworks() failed",
1165                                           status.serviceSpecificErrorCode());
1166             }
1167         }
1168 
1169         return success(cli);
1170     }
1171 
1172     //    0      1     2       3           4
1173     // network users  add   <netId> [<uid>[-<uid>]] ...
1174     // network users remove <netId> [<uid>[-<uid>]] ...
1175     if (!strcmp(argv[1], "users")) {
1176         if (argc < 4) {
1177             return syntaxError(cli, "Missing argument");
1178         }
1179         unsigned netId = stringToNetId(argv[3]);
1180         UidRanges uidRanges;
1181         if (!uidRanges.parseFrom(argc - 4, argv + 4)) {
1182             return syntaxError(cli, "Invalid UIDs");
1183         }
1184         if (!strcmp(argv[2], "add")) {
1185             if (Status status = mNetd->networkAddUidRanges(netId, uidRanges.getRanges());
1186                 !status.isOk()) {
1187                 return operationError(cli, "addUsersToNetwork() failed",
1188                                       status.serviceSpecificErrorCode());
1189             }
1190         } else if (!strcmp(argv[2], "remove")) {
1191             if (Status status = mNetd->networkRemoveUidRanges(netId, uidRanges.getRanges());
1192                 !status.isOk()) {
1193                 return operationError(cli, "removeUsersFromNetwork() failed",
1194                                       status.serviceSpecificErrorCode());
1195             }
1196         } else {
1197             return syntaxError(cli, "Unknown argument");
1198         }
1199         return success(cli);
1200     }
1201 
1202     //    0       1      2     3
1203     // network protect allow <uid> ...
1204     // network protect  deny <uid> ...
1205     if (!strcmp(argv[1], "protect")) {
1206         if (argc < 4) {
1207             return syntaxError(cli, "Missing argument");
1208         }
1209         std::vector<uid_t> uids;
1210         for (int i = 3; i < argc; ++i) {
1211             uid_t uid = 0;
1212             PARSE_UINT_RETURN_IF_FAIL(cli, argv[i], uid, "Unknown argument", false);
1213             uids.push_back(uid);
1214         }
1215         if (!strcmp(argv[2], "allow")) {
1216             for (auto uid : uids) {
1217                 mNetd->networkSetProtectAllow(uid);
1218             }
1219         } else if (!strcmp(argv[2], "deny")) {
1220             for (auto uid : uids) {
1221                 mNetd->networkSetProtectDeny(uid);
1222             }
1223         } else {
1224             return syntaxError(cli, "Unknown argument");
1225         }
1226         return success(cli);
1227     }
1228 
1229     return syntaxError(cli, "Unknown argument");
1230 }
1231 
1232 }  // namespace net
1233 }  // namespace android
1234