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