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.c_str()));
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 NetworkCommand());
140     registerCmd(new StrictCmd());
141 }
142 
registerCmd(NdcNetdCommand * cmd)143 void NdcDispatcher::registerCmd(NdcNetdCommand* cmd) {
144     mCommands.push_back(cmd);
145 }
146 
dispatchCommand(int argc,char ** argv)147 int NdcDispatcher::dispatchCommand(int argc, char** argv) {
148     if (argc >= CMD_ARGS_MAX) {
149         mNdc.sendMsg(500, "Command too long", false);
150     }
151 
152     for (const auto* c : mCommands) {
153         if (c->getCommand() == argv[0]) {
154             if (c->runCommand(&mNdc, argc, argv)) {
155                 mNdc.sendMsg(500, "Handler error", true);
156             }
157             return 0;
158         }
159     }
160     mNdc.sendMsg(500, "Command not recognized", false);
161     return 0;
162 }
163 
InterfaceCmd()164 NdcDispatcher::InterfaceCmd::InterfaceCmd() : NdcNetdCommand("interface") {}
165 
runCommand(NdcClient * cli,int argc,char ** argv) const166 int NdcDispatcher::InterfaceCmd::runCommand(NdcClient* cli, int argc, char** argv) const {
167     if (argc < 2) {
168         cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
169         return 0;
170     }
171 
172     if (!strcmp(argv[1], "list")) {
173         std::vector<std::string> interfaceGetList;
174         Status status = mNetd->interfaceGetList(&interfaceGetList);
175 
176         if (!status.isOk()) {
177             errno = status.serviceSpecificErrorCode();
178             cli->sendMsg(ResponseCode::OperationFailed, "Failed to get interface list", true);
179             return 0;
180         }
181         for (const auto& iface : interfaceGetList) {
182             cli->sendMsg(ResponseCode::InterfaceListResult, iface.c_str(), false);
183         }
184 
185         cli->sendMsg(ResponseCode::CommandOkay, "Interface list completed", false);
186         return 0;
187     } else {
188         /*
189          * These commands take a minimum of 3 arguments
190          */
191         if (argc < 3) {
192             cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
193             return 0;
194         }
195 
196         if (!strcmp(argv[1], "getcfg")) {
197             InterfaceConfigurationParcel interfaceCfgResult;
198             Status status = mNetd->interfaceGetCfg(std::string(argv[2]), &interfaceCfgResult);
199 
200             if (!status.isOk()) {
201                 errno = status.serviceSpecificErrorCode();
202                 cli->sendMsg(ResponseCode::OperationFailed, "Interface not found", true);
203                 return 0;
204             }
205 
206             std::string flags = Join(interfaceCfgResult.flags, " ");
207 
208             std::string msg = StringPrintf("%s %s %d %s", interfaceCfgResult.hwAddr.c_str(),
209                                            interfaceCfgResult.ipv4Addr.c_str(),
210                                            interfaceCfgResult.prefixLength, flags.c_str());
211 
212             cli->sendMsg(ResponseCode::InterfaceGetCfgResult, msg.c_str(), false);
213 
214             return 0;
215         } else if (!strcmp(argv[1], "setcfg")) {
216             // arglist: iface [addr prefixLength] flags
217             if (argc < 4) {
218                 cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
219                 return 0;
220             }
221             LOG(LOGLEVEL) << "Setting iface cfg";
222 
223             struct in_addr addr;
224             int index = 5;
225             InterfaceConfigurationParcel interfaceCfg;
226             interfaceCfg.ifName = argv[2];
227             interfaceCfg.hwAddr = "";
228 
229             if (!inet_aton(argv[3], &addr)) {
230                 // Handle flags only case
231                 index = 3;
232                 interfaceCfg.ipv4Addr = "";
233                 interfaceCfg.prefixLength = 0;
234             } else {
235                 if (addr.s_addr != 0) {
236                     interfaceCfg.ipv4Addr = argv[3];
237                     PARSE_INT_RETURN_IF_FAIL(cli, argv[4], interfaceCfg.prefixLength,
238                                              "Failed to set address", true);
239                     Status status = mNetd->interfaceSetCfg(interfaceCfg);
240                     if (!status.isOk()) {
241                         errno = status.serviceSpecificErrorCode();
242                         cli->sendMsg(ResponseCode::OperationFailed, "Failed to set address", true);
243                         return 0;
244                     }
245                 }
246             }
247 
248             /* Process flags */
249             for (int i = index; i < argc; i++) {
250                 char* flag = argv[i];
251                 if (!strcmp(flag, "up")) {
252                     LOG(LOGLEVEL) << "Trying to bring up " << argv[2];
253                     interfaceCfg.flags.push_back(toStdString(INetd::IF_STATE_UP()));
254                     Status status = mNetd->interfaceSetCfg(interfaceCfg);
255                     if (!status.isOk()) {
256                         LOG(LOGLEVEL) << "Error upping interface";
257                         errno = status.serviceSpecificErrorCode();
258                         cli->sendMsg(ResponseCode::OperationFailed, "Failed to up interface", true);
259                         ifc_close();
260                         return 0;
261                     }
262                 } else if (!strcmp(flag, "down")) {
263                     LOG(LOGLEVEL) << "Trying to bring down " << argv[2];
264                     interfaceCfg.flags.push_back(toStdString(INetd::IF_STATE_DOWN()));
265                     Status status = mNetd->interfaceSetCfg(interfaceCfg);
266                     if (!status.isOk()) {
267                         LOG(LOGLEVEL) << "Error downing interface";
268                         errno = status.serviceSpecificErrorCode();
269                         cli->sendMsg(ResponseCode::OperationFailed, "Failed to down interface",
270                                      true);
271                         return 0;
272                     }
273                 } else if (!strcmp(flag, "broadcast") || !strcmp(flag, "multicast") ||
274                            !strcmp(flag, "running") || !strcmp(flag, "loopback") ||
275                            !strcmp(flag, "point-to-point")) {
276                     // currently ignored
277                 } else {
278                     cli->sendMsg(ResponseCode::CommandParameterError, "Flag unsupported", false);
279                     return 0;
280                 }
281             }
282 
283             cli->sendMsg(ResponseCode::CommandOkay, "Interface configuration set", false);
284             return 0;
285         } else if (!strcmp(argv[1], "clearaddrs")) {
286             // arglist: iface
287             LOG(LOGLEVEL) << "Clearing all IP addresses on " << argv[2];
288 
289             mNetd->interfaceClearAddrs(std::string(argv[2]));
290 
291             cli->sendMsg(ResponseCode::CommandOkay, "Interface IP addresses cleared", false);
292             return 0;
293         } else if (!strcmp(argv[1], "ipv6privacyextensions")) {
294             if (argc != 4) {
295                 cli->sendMsg(ResponseCode::CommandSyntaxError,
296                              "Usage: interface ipv6privacyextensions <interface> <enable|disable>",
297                              false);
298                 return 0;
299             }
300             int enable = !strcmp(argv[3], "enable");
301             Status status = mNetd->interfaceSetIPv6PrivacyExtensions(std::string(argv[2]), enable);
302             if (status.isOk()) {
303                 cli->sendMsg(ResponseCode::CommandOkay, "IPv6 privacy extensions changed", false);
304             } else {
305                 errno = status.serviceSpecificErrorCode();
306                 cli->sendMsg(ResponseCode::OperationFailed, "Failed to set ipv6 privacy extensions",
307                              true);
308             }
309             return 0;
310         } else if (!strcmp(argv[1], "ipv6")) {
311             if (argc != 4) {
312                 cli->sendMsg(ResponseCode::CommandSyntaxError,
313                              "Usage: interface ipv6 <interface> <enable|disable>", false);
314                 return 0;
315             }
316 
317             int enable = !strcmp(argv[3], "enable");
318             Status status = mNetd->interfaceSetEnableIPv6(std::string(argv[2]), enable);
319             if (status.isOk()) {
320                 cli->sendMsg(ResponseCode::CommandOkay, "IPv6 state changed", false);
321             } else {
322                 errno = status.serviceSpecificErrorCode();
323                 cli->sendMsg(ResponseCode::OperationFailed, "Failed to change IPv6 state", true);
324             }
325             return 0;
326         } else if (!strcmp(argv[1], "setmtu")) {
327             if (argc != 4) {
328                 cli->sendMsg(ResponseCode::CommandSyntaxError,
329                              "Usage: interface setmtu <interface> <val>", false);
330                 return 0;
331             }
332 
333             int mtuValue = 0;
334             PARSE_INT_RETURN_IF_FAIL(cli, argv[3], mtuValue, "Failed to set MTU", true);
335             Status status = mNetd->interfaceSetMtu(std::string(argv[2]), mtuValue);
336             if (status.isOk()) {
337                 cli->sendMsg(ResponseCode::CommandOkay, "MTU changed", false);
338             } else {
339                 errno = status.serviceSpecificErrorCode();
340                 cli->sendMsg(ResponseCode::OperationFailed, "Failed to set MTU", true);
341             }
342             return 0;
343         } else {
344             cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown interface cmd", false);
345             return 0;
346         }
347     }
348     return 0;
349 }
350 
IpFwdCmd()351 NdcDispatcher::IpFwdCmd::IpFwdCmd() : NdcNetdCommand("ipfwd") {}
352 
runCommand(NdcClient * cli,int argc,char ** argv) const353 int NdcDispatcher::IpFwdCmd::runCommand(NdcClient* cli, int argc, char** argv) const {
354     bool matched = false;
355     Status status;
356 
357     if (argc == 2) {
358         //   0     1
359         // ipfwd status
360         if (!strcmp(argv[1], "status")) {
361             bool ipfwdEnabled;
362             mNetd->ipfwdEnabled(&ipfwdEnabled);
363             std::string msg = StringPrintf("Forwarding %s", ipfwdEnabled ? "enabled" : "disabled");
364             cli->sendMsg(ResponseCode::IpFwdStatusResult, msg.c_str(), false);
365             return 0;
366         }
367     } else if (argc == 3) {
368         //  0      1         2
369         // ipfwd enable  <requester>
370         // ipfwd disable <requester>
371         if (!strcmp(argv[1], "enable")) {
372             matched = true;
373             status = mNetd->ipfwdEnableForwarding(argv[2]);
374         } else if (!strcmp(argv[1], "disable")) {
375             matched = true;
376             status = mNetd->ipfwdDisableForwarding(argv[2]);
377         }
378     } else if (argc == 4) {
379         //  0      1      2     3
380         // ipfwd  add   wlan0 dummy0
381         // ipfwd remove wlan0 dummy0
382         if (!strcmp(argv[1], "add")) {
383             matched = true;
384             status = mNetd->ipfwdAddInterfaceForward(argv[2], argv[3]);
385         } else if (!strcmp(argv[1], "remove")) {
386             matched = true;
387             status = mNetd->ipfwdRemoveInterfaceForward(argv[2], argv[3]);
388         }
389     }
390 
391     if (!matched) {
392         cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown ipfwd cmd", false);
393         return 0;
394     }
395 
396     if (status.isOk()) {
397         cli->sendMsg(ResponseCode::CommandOkay, "ipfwd operation succeeded", false);
398     } else {
399         errno = status.serviceSpecificErrorCode();
400         cli->sendMsg(ResponseCode::OperationFailed, "ipfwd operation failed", true);
401     }
402     return 0;
403 }
404 
TetherCmd()405 NdcDispatcher::TetherCmd::TetherCmd() : NdcNetdCommand("tether") {}
406 
runCommand(NdcClient * cli,int argc,char ** argv) const407 int NdcDispatcher::TetherCmd::runCommand(NdcClient* cli, int argc, char** argv) const {
408     Status status;
409 
410     if (argc < 2) {
411         cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
412         return 0;
413     }
414 
415     if (!strcmp(argv[1], "stop")) {
416         status = mNetd->tetherStop();
417     } else if (!strcmp(argv[1], "status")) {
418         bool tetherEnabled;
419         mNetd->tetherIsEnabled(&tetherEnabled);
420         std::string msg =
421                 StringPrintf("Tethering services %s", tetherEnabled ? "started" : "stopped");
422         cli->sendMsg(ResponseCode::TetherStatusResult, msg.c_str(), false);
423         return 0;
424     } else if (argc == 3) {
425         if (!strcmp(argv[1], "interface") && !strcmp(argv[2], "list")) {
426             std::vector<std::string> ifList;
427             mNetd->tetherInterfaceList(&ifList);
428             for (const auto& ifname : ifList) {
429                 cli->sendMsg(ResponseCode::TetherInterfaceListResult, ifname.c_str(), false);
430             }
431         }
432     } else if (!strcmp(argv[1], "start")) {
433         if (argc % 2 == 1) {
434             cli->sendMsg(ResponseCode::CommandSyntaxError, "Bad number of arguments", false);
435             return 0;
436         }
437 
438         std::vector<std::string> dhcpRanges;
439         // We do the checking of the pairs & addr invalidation in binderService/tetherController.
440         for (int arg_index = 2; arg_index < argc; arg_index++) {
441             dhcpRanges.push_back(argv[arg_index]);
442         }
443 
444         status = mNetd->tetherStart(dhcpRanges);
445     } else {
446         /*
447          * These commands take a minimum of 4 arguments
448          */
449         if (argc < 4) {
450             cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
451             return 0;
452         }
453 
454         if (!strcmp(argv[1], "interface")) {
455             if (!strcmp(argv[2], "add")) {
456                 status = mNetd->tetherInterfaceAdd(argv[3]);
457             } else if (!strcmp(argv[2], "remove")) {
458                 status = mNetd->tetherInterfaceRemove(argv[3]);
459                 /* else if (!strcmp(argv[2], "list")) handled above */
460             } else {
461                 cli->sendMsg(ResponseCode::CommandParameterError,
462                              "Unknown tether interface operation", false);
463                 return 0;
464             }
465         } else if (!strcmp(argv[1], "dns")) {
466             if (!strcmp(argv[2], "set")) {
467                 if (argc < 5) {
468                     cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
469                     return 0;
470                 }
471                 std::vector<std::string> tetherDnsAddrs;
472                 unsigned netId = stringToNetId(argv[3]);
473                 for (int arg_index = 4; arg_index < argc; arg_index++) {
474                     tetherDnsAddrs.push_back(argv[arg_index]);
475                 }
476                 status = mNetd->tetherDnsSet(netId, tetherDnsAddrs);
477                 /* else if (!strcmp(argv[2], "list")) handled above */
478             } else {
479                 cli->sendMsg(ResponseCode::CommandParameterError,
480                              "Unknown tether interface operation", false);
481                 return 0;
482             }
483         } else {
484             cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown tether cmd", false);
485             return 0;
486         }
487     }
488 
489     if (status.isOk()) {
490         cli->sendMsg(ResponseCode::CommandOkay, "Tether operation succeeded", false);
491     } else {
492         errno = status.serviceSpecificErrorCode();
493         cli->sendMsg(ResponseCode::OperationFailed, "Tether operation failed", true);
494     }
495 
496     return 0;
497 }
498 
NatCmd()499 NdcDispatcher::NatCmd::NatCmd() : NdcNetdCommand("nat") {}
500 
runCommand(NdcClient * cli,int argc,char ** argv) const501 int NdcDispatcher::NatCmd::runCommand(NdcClient* cli, int argc, char** argv) const {
502     Status status;
503 
504     if (argc < 5) {
505         cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
506         return 0;
507     }
508 
509     //  0     1       2        3
510     // nat  enable intiface extiface
511     // nat disable intiface extiface
512     if (!strcmp(argv[1], "enable") && argc >= 4) {
513         status = mNetd->tetherAddForward(argv[2], argv[3]);
514     } else if (!strcmp(argv[1], "disable") && argc >= 4) {
515         status = mNetd->tetherRemoveForward(argv[2], argv[3]);
516     } else {
517         cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown nat cmd", false);
518         return 0;
519     }
520 
521     if (status.isOk()) {
522         cli->sendMsg(ResponseCode::CommandOkay, "Nat operation succeeded", false);
523     } else {
524         errno = status.serviceSpecificErrorCode();
525         cli->sendMsg(ResponseCode::OperationFailed, "Nat operation failed", true);
526     }
527 
528     return 0;
529 }
530 
BandwidthControlCmd()531 NdcDispatcher::BandwidthControlCmd::BandwidthControlCmd() : NdcNetdCommand("bandwidth") {}
532 
sendGenericSyntaxError(NdcClient * cli,const char * usageMsg) const533 void NdcDispatcher::BandwidthControlCmd::sendGenericSyntaxError(NdcClient* cli,
534                                                                 const char* usageMsg) const {
535     char* msg;
536     asprintf(&msg, "Usage: bandwidth %s", usageMsg);
537     cli->sendMsg(ResponseCode::CommandSyntaxError, msg, false);
538     free(msg);
539 }
540 
sendGenericOkFail(NdcClient * cli,int cond) const541 void NdcDispatcher::BandwidthControlCmd::sendGenericOkFail(NdcClient* cli, int cond) const {
542     if (!cond) {
543         cli->sendMsg(ResponseCode::CommandOkay, "Bandwidth command succeeeded", false);
544     } else {
545         cli->sendMsg(ResponseCode::OperationFailed, "Bandwidth command failed", false);
546     }
547 }
548 
sendGenericOpFailed(NdcClient * cli,const char * errMsg) const549 void NdcDispatcher::BandwidthControlCmd::sendGenericOpFailed(NdcClient* cli,
550                                                              const char* errMsg) const {
551     cli->sendMsg(ResponseCode::OperationFailed, errMsg, false);
552 }
553 
runCommand(NdcClient * cli,int argc,char ** argv) const554 int NdcDispatcher::BandwidthControlCmd::runCommand(NdcClient* cli, int argc, char** argv) const {
555     if (argc < 2) {
556         sendGenericSyntaxError(cli, "<cmds> <args...>");
557         return 0;
558     }
559 
560     LOG(LOGLEVEL) << StringPrintf("bwctrlcmd: argc=%d %s %s ...", argc, argv[0], argv[1]).c_str();
561 
562     if (!strcmp(argv[1], "removeiquota") || !strcmp(argv[1], "riq")) {
563         if (argc != 3) {
564             sendGenericSyntaxError(cli, "removeiquota <interface>");
565             return 0;
566         }
567         int rc = !mNetd->bandwidthRemoveInterfaceQuota(argv[2]).isOk();
568         sendGenericOkFail(cli, rc);
569         return 0;
570     }
571     if (!strcmp(argv[1], "setiquota") || !strcmp(argv[1], "siq")) {
572         if (argc != 4) {
573             sendGenericSyntaxError(cli, "setiquota <interface> <bytes>");
574             return 0;
575         }
576         int64_t bytes = 0;
577         PARSE_INT_RETURN_IF_FAIL(cli, argv[3], bytes, "Bandwidth command failed", false);
578         int rc = !mNetd->bandwidthSetInterfaceQuota(argv[2], bytes).isOk();
579         sendGenericOkFail(cli, rc);
580         return 0;
581     }
582     if (!strcmp(argv[1], "addnaughtyapps") || !strcmp(argv[1], "ana")) {
583         if (argc < 3) {
584             sendGenericSyntaxError(cli, "addnaughtyapps <appUid> ...");
585             return 0;
586         }
587         int rc = 0;
588         for (int arg_index = 2; arg_index < argc; arg_index++) {
589             uid_t uid = 0;
590             PARSE_UINT_RETURN_IF_FAIL(cli, argv[arg_index], uid, "Bandwidth command failed", false);
591             rc = !mNetd->bandwidthAddNaughtyApp(uid).isOk();
592             if (rc) break;
593         }
594         sendGenericOkFail(cli, rc);
595         return 0;
596     }
597     if (!strcmp(argv[1], "removenaughtyapps") || !strcmp(argv[1], "rna")) {
598         if (argc < 3) {
599             sendGenericSyntaxError(cli, "removenaughtyapps <appUid> ...");
600             return 0;
601         }
602         int rc = 0;
603         for (int arg_index = 2; arg_index < argc; arg_index++) {
604             uid_t uid = 0;
605             PARSE_UINT_RETURN_IF_FAIL(cli, argv[arg_index], uid, "Bandwidth command failed", false);
606             rc = !mNetd->bandwidthRemoveNaughtyApp(uid).isOk();
607             if (rc) break;
608         }
609         sendGenericOkFail(cli, rc);
610         return 0;
611     }
612     if (!strcmp(argv[1], "addniceapps") || !strcmp(argv[1], "aha")) {
613         if (argc < 3) {
614             sendGenericSyntaxError(cli, "addniceapps <appUid> ...");
615             return 0;
616         }
617         int rc = 0;
618         for (int arg_index = 2; arg_index < argc; arg_index++) {
619             uid_t uid = 0;
620             PARSE_UINT_RETURN_IF_FAIL(cli, argv[arg_index], uid, "Bandwidth command failed", false);
621             rc = !mNetd->bandwidthAddNiceApp(uid).isOk();
622             if (rc) break;
623         }
624         sendGenericOkFail(cli, rc);
625         return 0;
626     }
627     if (!strcmp(argv[1], "removeniceapps") || !strcmp(argv[1], "rha")) {
628         if (argc < 3) {
629             sendGenericSyntaxError(cli, "removeniceapps <appUid> ...");
630             return 0;
631         }
632         int rc = 0;
633         for (int arg_index = 2; arg_index < argc; arg_index++) {
634             uid_t uid = 0;
635             PARSE_UINT_RETURN_IF_FAIL(cli, argv[arg_index], uid, "Bandwidth command failed", false);
636             rc = !mNetd->bandwidthRemoveNiceApp(uid).isOk();
637             if (rc) break;
638         }
639         sendGenericOkFail(cli, rc);
640         return 0;
641     }
642     if (!strcmp(argv[1], "setglobalalert") || !strcmp(argv[1], "sga")) {
643         if (argc != 3) {
644             sendGenericSyntaxError(cli, "setglobalalert <bytes>");
645             return 0;
646         }
647         int64_t bytes = 0;
648         PARSE_INT_RETURN_IF_FAIL(cli, argv[2], bytes, "Bandwidth command failed", false);
649         int rc = !mNetd->bandwidthSetGlobalAlert(bytes).isOk();
650         sendGenericOkFail(cli, rc);
651         return 0;
652     }
653     if (!strcmp(argv[1], "setinterfacealert") || !strcmp(argv[1], "sia")) {
654         if (argc != 4) {
655             sendGenericSyntaxError(cli, "setinterfacealert <interface> <bytes>");
656             return 0;
657         }
658         int64_t bytes = 0;
659         PARSE_INT_RETURN_IF_FAIL(cli, argv[3], bytes, "Bandwidth command failed", false);
660         int rc = !mNetd->bandwidthSetInterfaceAlert(argv[2], bytes).isOk();
661         sendGenericOkFail(cli, rc);
662         return 0;
663     }
664     if (!strcmp(argv[1], "removeinterfacealert") || !strcmp(argv[1], "ria")) {
665         if (argc != 3) {
666             sendGenericSyntaxError(cli, "removeinterfacealert <interface>");
667             return 0;
668         }
669         int rc = !mNetd->bandwidthRemoveInterfaceAlert(argv[2]).isOk();
670         sendGenericOkFail(cli, rc);
671         return 0;
672     }
673 
674     cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown bandwidth cmd", false);
675     return 0;
676 }
677 
IdletimerControlCmd()678 NdcDispatcher::IdletimerControlCmd::IdletimerControlCmd() : NdcNetdCommand("idletimer") {}
679 
runCommand(NdcClient * cli,int argc,char ** argv) const680 int NdcDispatcher::IdletimerControlCmd::runCommand(NdcClient* cli, int argc, char** argv) const {
681     // TODO(ashish): Change the error statements
682     if (argc < 2) {
683         cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
684         return 0;
685     }
686 
687     LOG(LOGLEVEL)
688             << StringPrintf("idletimerctrlcmd: argc=%d %s %s ...", argc, argv[0], argv[1]).c_str();
689 
690     if (!strcmp(argv[1], "add")) {
691         if (argc != 5) {
692             cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
693             return 0;
694         }
695 
696         int timeout = 0;
697         PARSE_INT_RETURN_IF_FAIL(cli, argv[3], timeout, "Failed to add interface", false);
698         Status status = mNetd->idletimerAddInterface(argv[2], timeout, argv[4]);
699         if (!status.isOk()) {
700             cli->sendMsg(ResponseCode::OperationFailed, "Failed to add interface", false);
701         } else {
702             cli->sendMsg(ResponseCode::CommandOkay, "Add success", false);
703         }
704         return 0;
705     }
706     if (!strcmp(argv[1], "remove")) {
707         if (argc != 5) {
708             cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
709             return 0;
710         }
711         int timeout = 0;
712         PARSE_INT_RETURN_IF_FAIL(cli, argv[3], timeout, "Failed to remove interface", false);
713         Status status = mNetd->idletimerRemoveInterface(argv[2], timeout, argv[4]);
714         if (!status.isOk()) {
715             cli->sendMsg(ResponseCode::OperationFailed, "Failed to remove interface", false);
716         } else {
717             cli->sendMsg(ResponseCode::CommandOkay, "Remove success", false);
718         }
719         return 0;
720     }
721 
722     cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown idletimer cmd", false);
723     return 0;
724 }
725 
FirewallCmd()726 NdcDispatcher::FirewallCmd::FirewallCmd() : NdcNetdCommand("firewall") {}
727 
sendGenericOkFail(NdcClient * cli,int cond) const728 int NdcDispatcher::FirewallCmd::sendGenericOkFail(NdcClient* cli, int cond) const {
729     if (!cond) {
730         cli->sendMsg(ResponseCode::CommandOkay, "Firewall command succeeded", false);
731     } else {
732         cli->sendMsg(ResponseCode::OperationFailed, "Firewall command failed", false);
733     }
734     return 0;
735 }
736 
parseRule(const char * arg)737 int NdcDispatcher::FirewallCmd::parseRule(const char* arg) {
738     if (!strcmp(arg, "allow")) {
739         return INetd::FIREWALL_RULE_ALLOW;
740     } else if (!strcmp(arg, "deny")) {
741         return INetd::FIREWALL_RULE_DENY;
742     } else {
743         LOG(LOGLEVEL) << "failed to parse uid rule " << arg;
744         return INetd::FIREWALL_RULE_ALLOW;
745     }
746 }
747 
parseFirewallType(const char * arg)748 int NdcDispatcher::FirewallCmd::parseFirewallType(const char* arg) {
749     if (!strcmp(arg, "allowlist")) {
750         return INetd::FIREWALL_ALLOWLIST;
751     } else if (!strcmp(arg, "denylist")) {
752         return INetd::FIREWALL_DENYLIST;
753     } else {
754         LOG(LOGLEVEL) << "failed to parse firewall type " << arg;
755         return INetd::FIREWALL_DENYLIST;
756     }
757 }
758 
parseChildChain(const char * arg)759 int NdcDispatcher::FirewallCmd::parseChildChain(const char* arg) {
760     if (!strcmp(arg, "dozable")) {
761         return INetd::FIREWALL_CHAIN_DOZABLE;
762     } else if (!strcmp(arg, "standby")) {
763         return INetd::FIREWALL_CHAIN_STANDBY;
764     } else if (!strcmp(arg, "powersave")) {
765         return INetd::FIREWALL_CHAIN_POWERSAVE;
766     } else if (!strcmp(arg, "restricted")) {
767         return INetd::FIREWALL_CHAIN_RESTRICTED;
768     } else if (!strcmp(arg, "none")) {
769         return INetd::FIREWALL_CHAIN_NONE;
770     } else {
771         LOG(LOGLEVEL) << "failed to parse child firewall chain " << arg;
772         return -1;
773     }
774 }
775 
runCommand(NdcClient * cli,int argc,char ** argv) const776 int NdcDispatcher::FirewallCmd::runCommand(NdcClient* cli, int argc, char** argv) const {
777     if (argc < 2) {
778         cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing command", false);
779         return 0;
780     }
781 
782     if (!strcmp(argv[1], "enable")) {
783         if (argc != 3) {
784             cli->sendMsg(ResponseCode::CommandSyntaxError,
785                          "Usage: firewall enable <allowlist|denylist>", false);
786             return 0;
787         }
788         int res = !mNetd->firewallSetFirewallType(parseFirewallType(argv[2])).isOk();
789         return sendGenericOkFail(cli, res);
790     }
791 
792     if (!strcmp(argv[1], "set_interface_rule")) {
793         if (argc != 4) {
794             cli->sendMsg(ResponseCode::CommandSyntaxError,
795                          "Usage: firewall set_interface_rule <rmnet0> <allow|deny>", false);
796             return 0;
797         }
798         int res = !mNetd->firewallSetInterfaceRule(argv[2], parseRule(argv[3])).isOk();
799         return sendGenericOkFail(cli, res);
800     }
801 
802     if (!strcmp(argv[1], "set_uid_rule")) {
803         if (argc != 5) {
804             cli->sendMsg(ResponseCode::CommandSyntaxError,
805                          "Usage: firewall set_uid_rule <dozable|standby|none> <1000> <allow|deny>",
806                          false);
807             return 0;
808         }
809 
810         int childChain = parseChildChain(argv[2]);
811         if (childChain == -1) {
812             cli->sendMsg(ResponseCode::CommandSyntaxError,
813                          "Invalid chain name. Valid names are: <dozable|standby|none>", false);
814             return 0;
815         }
816         uid_t uid = 0;
817         PARSE_UINT_RETURN_IF_FAIL(cli, argv[3], uid, "Firewall command failed", false);
818         int res = !mNetd->firewallSetUidRule(childChain, uid, parseRule(argv[4])).isOk();
819         return sendGenericOkFail(cli, res);
820     }
821 
822     if (!strcmp(argv[1], "enable_chain")) {
823         if (argc != 3) {
824             cli->sendMsg(ResponseCode::CommandSyntaxError,
825                          "Usage: firewall enable_chain <dozable|standby>", false);
826             return 0;
827         }
828         int res = !mNetd->firewallEnableChildChain(parseChildChain(argv[2]), true).isOk();
829         return sendGenericOkFail(cli, res);
830     }
831 
832     if (!strcmp(argv[1], "disable_chain")) {
833         if (argc != 3) {
834             cli->sendMsg(ResponseCode::CommandSyntaxError,
835                          "Usage: firewall disable_chain <dozable|standby>", false);
836             return 0;
837         }
838         int res = !mNetd->firewallEnableChildChain(parseChildChain(argv[2]), false).isOk();
839         return sendGenericOkFail(cli, res);
840     }
841 
842     cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown command", false);
843     return 0;
844 }
845 
StrictCmd()846 NdcDispatcher::StrictCmd::StrictCmd() : NdcNetdCommand("strict") {}
847 
sendGenericOkFail(NdcClient * cli,int cond) const848 int NdcDispatcher::StrictCmd::sendGenericOkFail(NdcClient* cli, int cond) const {
849     if (!cond) {
850         cli->sendMsg(ResponseCode::CommandOkay, "Strict command succeeded", false);
851     } else {
852         cli->sendMsg(ResponseCode::OperationFailed, "Strict command failed", false);
853     }
854     return 0;
855 }
856 
parsePenalty(const char * arg)857 int NdcDispatcher::StrictCmd::parsePenalty(const char* arg) {
858     if (!strcmp(arg, "reject")) {
859         return INetd::PENALTY_POLICY_REJECT;
860     } else if (!strcmp(arg, "log")) {
861         return INetd::PENALTY_POLICY_LOG;
862     } else if (!strcmp(arg, "accept")) {
863         return INetd::PENALTY_POLICY_ACCEPT;
864     } else {
865         return -1;
866     }
867 }
868 
runCommand(NdcClient * cli,int argc,char ** argv) const869 int NdcDispatcher::StrictCmd::runCommand(NdcClient* cli, int argc, char** argv) const {
870     if (argc < 2) {
871         cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing command", false);
872         return 0;
873     }
874 
875     if (!strcmp(argv[1], "set_uid_cleartext_policy")) {
876         if (argc != 4) {
877             cli->sendMsg(ResponseCode::CommandSyntaxError,
878                          "Usage: strict set_uid_cleartext_policy <uid> <accept|log|reject>", false);
879             return 0;
880         }
881 
882         errno = 0;
883         uid_t uid = 0;
884         PARSE_UINT_RETURN_IF_FAIL(cli, argv[2], uid, "Invalid UID", false);
885         if (uid > UID_MAX) {
886             cli->sendMsg(ResponseCode::CommandSyntaxError, "Invalid UID", false);
887             return 0;
888         }
889 
890         int penalty = parsePenalty(argv[3]);
891         if (penalty == -1) {
892             cli->sendMsg(ResponseCode::CommandSyntaxError, "Invalid penalty argument", false);
893             return 0;
894         }
895 
896         int res = !mNetd->strictUidCleartextPenalty(uid, penalty).isOk();
897         return sendGenericOkFail(cli, res);
898     }
899 
900     cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown command", false);
901     return 0;
902 }
903 
NetworkCommand()904 NdcDispatcher::NetworkCommand::NetworkCommand() : NdcNetdCommand("network") {}
905 
syntaxError(NdcClient * cli,const char * message) const906 int NdcDispatcher::NetworkCommand::syntaxError(NdcClient* cli, const char* message) const {
907     cli->sendMsg(ResponseCode::CommandSyntaxError, message, false);
908     return 0;
909 }
910 
operationError(NdcClient * cli,const char * message,int ret) const911 int NdcDispatcher::NetworkCommand::operationError(NdcClient* cli, const char* message,
912                                                   int ret) const {
913     errno = ret;
914     cli->sendMsg(ResponseCode::OperationFailed, message, true);
915     return 0;
916 }
917 
success(NdcClient * cli) const918 int NdcDispatcher::NetworkCommand::success(NdcClient* cli) const {
919     cli->sendMsg(ResponseCode::CommandOkay, "success", false);
920     return 0;
921 }
922 
runCommand(NdcClient * cli,int argc,char ** argv) const923 int NdcDispatcher::NetworkCommand::runCommand(NdcClient* cli, int argc, char** argv) const {
924     if (argc < 2) {
925         return syntaxError(cli, "Missing argument");
926     }
927 
928     //    0      1      2      3      4       5         6            7           8
929     // network route [legacy <uid>]  add   <netId> <interface> <destination> [nexthop]
930     // network route [legacy <uid>] remove <netId> <interface> <destination> [nexthop]
931     //
932     // nexthop may be either an IPv4/IPv6 address or one of "unreachable" or "throw".
933     if (!strcmp(argv[1], "route")) {
934         if (argc < 6 || argc > 9) {
935             return syntaxError(cli, "Incorrect number of arguments");
936         }
937 
938         int nextArg = 2;
939         bool legacy = false;
940         uid_t uid = 0;
941         if (!strcmp(argv[nextArg], "legacy")) {
942             ++nextArg;
943             legacy = true;
944             PARSE_UINT_RETURN_IF_FAIL(cli, argv[nextArg++], uid, "Unknown argument", false);
945         }
946 
947         bool add = false;
948         if (!strcmp(argv[nextArg], "add")) {
949             add = true;
950         } else if (strcmp(argv[nextArg], "remove") != 0) {
951             return syntaxError(cli, "Unknown argument");
952         }
953         ++nextArg;
954 
955         if (argc < nextArg + 3 || argc > nextArg + 4) {
956             return syntaxError(cli, "Incorrect number of arguments");
957         }
958 
959         unsigned netId = stringToNetId(argv[nextArg++]);
960         const char* interface = argv[nextArg++];
961         const char* destination = argv[nextArg++];
962         const char* nexthop = argc > nextArg ? argv[nextArg] : "";
963 
964         Status status;
965         if (legacy) {
966             status = add ? mNetd->networkAddLegacyRoute(netId, interface, destination, nexthop, uid)
967 
968                          : mNetd->networkRemoveLegacyRoute(netId, interface, destination, nexthop,
969                                                            uid);
970         } else {
971             status = add ? mNetd->networkAddRoute(netId, interface, destination, nexthop)
972                          : mNetd->networkRemoveRoute(netId, interface, destination, nexthop);
973         }
974 
975         if (!status.isOk()) {
976             return operationError(cli, add ? "addRoute() failed" : "removeRoute() failed",
977                                   status.serviceSpecificErrorCode());
978         }
979 
980         return success(cli);
981     }
982 
983     //    0        1       2       3         4
984     // network interface  add   <netId> <interface>
985     // network interface remove <netId> <interface>
986     if (!strcmp(argv[1], "interface")) {
987         if (argc != 5) {
988             return syntaxError(cli, "Missing argument");
989         }
990         unsigned netId = stringToNetId(argv[3]);
991         if (!strcmp(argv[2], "add")) {
992             if (Status status = mNetd->networkAddInterface(netId, argv[4]); !status.isOk()) {
993                 return operationError(cli, "addInterfaceToNetwork() failed",
994                                       status.serviceSpecificErrorCode());
995             }
996         } else if (!strcmp(argv[2], "remove")) {
997             if (Status status = mNetd->networkRemoveInterface(netId, argv[4]); !status.isOk()) {
998                 return operationError(cli, "removeInterfaceFromNetwork() failed",
999                                       status.serviceSpecificErrorCode());
1000             }
1001         } else {
1002             return syntaxError(cli, "Unknown argument");
1003         }
1004         return success(cli);
1005     }
1006 
1007     //    0      1       2         3
1008     // network create <netId> [permission]
1009     //
1010     //    0      1       2     3      4
1011     // network create <netId> vpn <secure>
1012     if (!strcmp(argv[1], "create")) {
1013         if (argc < 3) {
1014             return syntaxError(cli, "Missing argument");
1015         }
1016         unsigned netId = stringToNetId(argv[2]);
1017         if (argc == 5 && !strcmp(argv[3], "vpn")) {
1018             bool secure = strtol(argv[4], nullptr, 2);
1019 #pragma clang diagnostic push
1020 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
1021             if (Status status = mNetd->networkCreateVpn(netId, secure); !status.isOk()) {
1022 #pragma clang diagnostic pop
1023                 return operationError(cli, "createVirtualNetwork() failed",
1024                                       status.serviceSpecificErrorCode());
1025             }
1026         } else if (argc > 4) {
1027             return syntaxError(cli, "Unknown trailing argument(s)");
1028         } else {
1029             int permission = INetd::PERMISSION_NONE;
1030             if (argc == 4) {
1031                 permission = stringToINetdPermission(argv[3]);
1032                 if (permission == INetd::PERMISSION_NONE) {
1033                     return syntaxError(cli, "Unknown permission");
1034                 }
1035             }
1036 #pragma clang diagnostic push
1037 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
1038             if (Status status = mNetd->networkCreatePhysical(netId, permission); !status.isOk()) {
1039 #pragma clang diagnostic pop
1040                 return operationError(cli, "createPhysicalNetwork() failed",
1041                                       status.serviceSpecificErrorCode());
1042             }
1043         }
1044         return success(cli);
1045     }
1046 
1047     //    0       1       2
1048     // network destroy <netId>
1049     if (!strcmp(argv[1], "destroy")) {
1050         if (argc != 3) {
1051             return syntaxError(cli, "Incorrect number of arguments");
1052         }
1053         unsigned netId = stringToNetId(argv[2]);
1054         // Both of these functions manage their own locking internally.
1055         if (Status status = mNetd->networkDestroy(netId); !status.isOk()) {
1056             return operationError(cli, "destroyNetwork() failed",
1057                                   status.serviceSpecificErrorCode());
1058         }
1059         mDnsResolver->destroyNetworkCache(netId);
1060         return success(cli);
1061     }
1062 
1063     //    0       1      2      3
1064     // network default  set  <netId>
1065     // network default clear
1066     if (!strcmp(argv[1], "default")) {
1067         if (argc < 3) {
1068             return syntaxError(cli, "Missing argument");
1069         }
1070         unsigned netId = NETID_UNSET;
1071         if (!strcmp(argv[2], "set")) {
1072             if (argc < 4) {
1073                 return syntaxError(cli, "Missing netId");
1074             }
1075             netId = stringToNetId(argv[3]);
1076         } else if (strcmp(argv[2], "clear") != 0) {
1077             return syntaxError(cli, "Unknown argument");
1078         }
1079         if (Status status = mNetd->networkSetDefault(netId); !status.isOk()) {
1080             return operationError(cli, "setDefaultNetwork() failed",
1081                                   status.serviceSpecificErrorCode());
1082         }
1083         return success(cli);
1084     }
1085 
1086     //    0        1         2      3        4          5
1087     // network permission   user   set  <permission>  <uid> ...
1088     // network permission   user  clear    <uid> ...
1089     // network permission network  set  <permission> <netId> ...
1090     // network permission network clear   <netId> ...
1091     if (!strcmp(argv[1], "permission")) {
1092         if (argc < 5) {
1093             return syntaxError(cli, "Missing argument");
1094         }
1095         int nextArg = 4;
1096         int permission = INetd::PERMISSION_NONE;
1097         if (!strcmp(argv[3], "set")) {
1098             permission = stringToINetdPermission(argv[4]);
1099             if (permission == INetd::PERMISSION_NONE) {
1100                 return syntaxError(cli, "Unknown permission");
1101             }
1102             nextArg = 5;
1103         } else if (strcmp(argv[3], "clear") != 0) {
1104             return syntaxError(cli, "Unknown argument");
1105         }
1106         if (nextArg == argc) {
1107             return syntaxError(cli, "Missing id");
1108         }
1109 
1110         bool userPermissions = !strcmp(argv[2], "user");
1111         bool networkPermissions = !strcmp(argv[2], "network");
1112         if (!userPermissions && !networkPermissions) {
1113             return syntaxError(cli, "Unknown argument");
1114         }
1115 
1116         std::vector<int32_t> ids;
1117         for (; nextArg < argc; ++nextArg) {
1118             if (userPermissions) {
1119                 char* endPtr;
1120                 unsigned id = strtoul(argv[nextArg], &endPtr, 0);
1121                 if (!*argv[nextArg] || *endPtr) {
1122                     return syntaxError(cli, "Invalid id");
1123                 }
1124                 ids.push_back(id);
1125             } else {
1126                 // networkPermissions
1127                 ids.push_back(stringToNetId(argv[nextArg]));
1128             }
1129         }
1130         if (userPermissions) {
1131             mNetd->networkSetPermissionForUser(permission, ids);
1132         } else {
1133             // networkPermissions
1134             for (auto netId : ids) {
1135                 Status status = mNetd->networkSetPermissionForNetwork(netId, permission);
1136                 if (!status.isOk())
1137                     return operationError(cli, "setPermissionForNetworks() failed",
1138                                           status.serviceSpecificErrorCode());
1139             }
1140         }
1141 
1142         return success(cli);
1143     }
1144 
1145     //    0      1     2       3           4
1146     // network users  add   <netId> [<uid>[-<uid>]] ...
1147     // network users remove <netId> [<uid>[-<uid>]] ...
1148     if (!strcmp(argv[1], "users")) {
1149         if (argc < 4) {
1150             return syntaxError(cli, "Missing argument");
1151         }
1152         unsigned netId = stringToNetId(argv[3]);
1153         UidRanges uidRanges;
1154         if (!uidRanges.parseFrom(argc - 4, argv + 4)) {
1155             return syntaxError(cli, "Invalid UIDs");
1156         }
1157         if (!strcmp(argv[2], "add")) {
1158             if (Status status = mNetd->networkAddUidRanges(netId, uidRanges.getRanges());
1159                 !status.isOk()) {
1160                 return operationError(cli, "addUsersToNetwork() failed",
1161                                       status.serviceSpecificErrorCode());
1162             }
1163         } else if (!strcmp(argv[2], "remove")) {
1164             if (Status status = mNetd->networkRemoveUidRanges(netId, uidRanges.getRanges());
1165                 !status.isOk()) {
1166                 return operationError(cli, "removeUsersFromNetwork() failed",
1167                                       status.serviceSpecificErrorCode());
1168             }
1169         } else {
1170             return syntaxError(cli, "Unknown argument");
1171         }
1172         return success(cli);
1173     }
1174 
1175     //    0       1      2     3
1176     // network protect allow <uid> ...
1177     // network protect  deny <uid> ...
1178     if (!strcmp(argv[1], "protect")) {
1179         if (argc < 4) {
1180             return syntaxError(cli, "Missing argument");
1181         }
1182         std::vector<uid_t> uids;
1183         for (int i = 3; i < argc; ++i) {
1184             uid_t uid = 0;
1185             PARSE_UINT_RETURN_IF_FAIL(cli, argv[i], uid, "Unknown argument", false);
1186             uids.push_back(uid);
1187         }
1188         if (!strcmp(argv[2], "allow")) {
1189             for (auto uid : uids) {
1190                 mNetd->networkSetProtectAllow(uid);
1191             }
1192         } else if (!strcmp(argv[2], "deny")) {
1193             for (auto uid : uids) {
1194                 mNetd->networkSetProtectDeny(uid);
1195             }
1196         } else {
1197             return syntaxError(cli, "Unknown argument");
1198         }
1199         return success(cli);
1200     }
1201 
1202     return syntaxError(cli, "Unknown argument");
1203 }
1204 
1205 }  // namespace net
1206 }  // namespace android
1207