• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2008 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 // #define LOG_NDEBUG 0
18 
19 #include <stdlib.h>
20 #include <sys/socket.h>
21 #include <sys/types.h>
22 #include <netinet/in.h>
23 #include <arpa/inet.h>
24 #include <dirent.h>
25 #include <errno.h>
26 #include <string.h>
27 #include <linux/if.h>
28 #include <resolv_netid.h>
29 #include <resolv_params.h>
30 
31 #define __STDC_FORMAT_MACROS 1
32 #include <inttypes.h>
33 
34 #define LOG_TAG "CommandListener"
35 
36 #include <cutils/log.h>
37 #include <netutils/ifc.h>
38 #include <sysutils/SocketClient.h>
39 
40 #include "Controllers.h"
41 #include "CommandListener.h"
42 #include "ResponseCode.h"
43 #include "BandwidthController.h"
44 #include "IdletimerController.h"
45 #include "InterfaceController.h"
46 #include "oem_iptables_hook.h"
47 #include "NetdConstants.h"
48 #include "FirewallController.h"
49 #include "RouteController.h"
50 #include "UidRanges.h"
51 
52 #include <string>
53 #include <vector>
54 
55 using android::net::gCtls;
56 
57 namespace {
58 
59 const unsigned NUM_OEM_IDS = NetworkController::MAX_OEM_ID - NetworkController::MIN_OEM_ID + 1;
60 
stringToPermission(const char * arg)61 Permission stringToPermission(const char* arg) {
62     if (!strcmp(arg, "NETWORK")) {
63         return PERMISSION_NETWORK;
64     }
65     if (!strcmp(arg, "SYSTEM")) {
66         return PERMISSION_SYSTEM;
67     }
68     return PERMISSION_NONE;
69 }
70 
stringToNetId(const char * arg)71 unsigned stringToNetId(const char* arg) {
72     if (!strcmp(arg, "local")) {
73         return NetworkController::LOCAL_NET_ID;
74     }
75     // OEM NetIds are "oem1", "oem2", .., "oem50".
76     if (!strncmp(arg, "oem", 3)) {
77         unsigned n = strtoul(arg + 3, NULL, 0);
78         if (1 <= n && n <= NUM_OEM_IDS) {
79             return NetworkController::MIN_OEM_ID + n;
80         }
81         return NETID_UNSET;
82     }
83     // strtoul() returns 0 on errors, which is fine because 0 is an invalid netId.
84     return strtoul(arg, NULL, 0);
85 }
86 
87 class LockingFrameworkCommand : public FrameworkCommand {
88 public:
LockingFrameworkCommand(FrameworkCommand * wrappedCmd,android::RWLock & lock)89     LockingFrameworkCommand(FrameworkCommand *wrappedCmd, android::RWLock& lock) :
90             FrameworkCommand(wrappedCmd->getCommand()),
91             mWrappedCmd(wrappedCmd),
92             mLock(lock) {}
93 
runCommand(SocketClient * c,int argc,char ** argv)94     int runCommand(SocketClient *c, int argc, char **argv) {
95         android::RWLock::AutoWLock lock(mLock);
96         return mWrappedCmd->runCommand(c, argc, argv);
97     }
98 
99 private:
100     FrameworkCommand *mWrappedCmd;
101     android::RWLock& mLock;
102 };
103 
104 
105 }  // namespace
106 
107 /**
108  * List of module chains to be created, along with explicit ordering. ORDERING
109  * IS CRITICAL, AND SHOULD BE TRIPLE-CHECKED WITH EACH CHANGE.
110  */
111 static const char* FILTER_INPUT[] = {
112         // Bandwidth should always be early in input chain, to make sure we
113         // correctly count incoming traffic against data plan.
114         BandwidthController::LOCAL_INPUT,
115         FirewallController::LOCAL_INPUT,
116         NULL,
117 };
118 
119 static const char* FILTER_FORWARD[] = {
120         OEM_IPTABLES_FILTER_FORWARD,
121         FirewallController::LOCAL_FORWARD,
122         BandwidthController::LOCAL_FORWARD,
123         NatController::LOCAL_FORWARD,
124         NULL,
125 };
126 
127 static const char* FILTER_OUTPUT[] = {
128         OEM_IPTABLES_FILTER_OUTPUT,
129         FirewallController::LOCAL_OUTPUT,
130         StrictController::LOCAL_OUTPUT,
131         BandwidthController::LOCAL_OUTPUT,
132         NULL,
133 };
134 
135 static const char* RAW_PREROUTING[] = {
136         BandwidthController::LOCAL_RAW_PREROUTING,
137         IdletimerController::LOCAL_RAW_PREROUTING,
138         NatController::LOCAL_RAW_PREROUTING,
139         NULL,
140 };
141 
142 static const char* MANGLE_POSTROUTING[] = {
143         BandwidthController::LOCAL_MANGLE_POSTROUTING,
144         IdletimerController::LOCAL_MANGLE_POSTROUTING,
145         NULL,
146 };
147 
148 static const char* MANGLE_FORWARD[] = {
149         NatController::LOCAL_MANGLE_FORWARD,
150         NULL,
151 };
152 
153 static const char* NAT_PREROUTING[] = {
154         OEM_IPTABLES_NAT_PREROUTING,
155         NULL,
156 };
157 
158 static const char* NAT_POSTROUTING[] = {
159         NatController::LOCAL_NAT_POSTROUTING,
160         NULL,
161 };
162 
createChildChains(IptablesTarget target,const char * table,const char * parentChain,const char ** childChains)163 static void createChildChains(IptablesTarget target, const char* table, const char* parentChain,
164         const char** childChains) {
165     const char** childChain = childChains;
166     do {
167         // Order is important:
168         // -D to delete any pre-existing jump rule (removes references
169         //    that would prevent -X from working)
170         // -F to flush any existing chain
171         // -X to delete any existing chain
172         // -N to create the chain
173         // -A to append the chain to parent
174 
175         execIptablesSilently(target, "-t", table, "-D", parentChain, "-j", *childChain, NULL);
176         execIptablesSilently(target, "-t", table, "-F", *childChain, NULL);
177         execIptablesSilently(target, "-t", table, "-X", *childChain, NULL);
178         execIptables(target, "-t", table, "-N", *childChain, NULL);
179         execIptables(target, "-t", table, "-A", parentChain, "-j", *childChain, NULL);
180     } while (*(++childChain) != NULL);
181 }
182 
registerLockingCmd(FrameworkCommand * cmd,android::RWLock & lock)183 void CommandListener::registerLockingCmd(FrameworkCommand *cmd, android::RWLock& lock) {
184     registerCmd(new LockingFrameworkCommand(cmd, lock));
185 }
186 
CommandListener()187 CommandListener::CommandListener() :
188                  FrameworkListener("netd", true) {
189     registerLockingCmd(new InterfaceCmd());
190     registerLockingCmd(new IpFwdCmd());
191     registerLockingCmd(new TetherCmd());
192     registerLockingCmd(new NatCmd());
193     registerLockingCmd(new ListTtysCmd());
194     registerLockingCmd(new PppdCmd());
195     registerLockingCmd(new SoftapCmd());
196     registerLockingCmd(new BandwidthControlCmd(), gCtls->bandwidthCtrl.lock);
197     registerLockingCmd(new IdletimerControlCmd());
198     registerLockingCmd(new ResolverCmd());
199     registerLockingCmd(new FirewallCmd(), gCtls->firewallCtrl.lock);
200     registerLockingCmd(new ClatdCmd());
201     registerLockingCmd(new NetworkCommand());
202     registerLockingCmd(new StrictCmd());
203 
204     /*
205      * This is the only time we touch top-level chains in iptables; controllers
206      * should only mutate rules inside of their children chains, as created by
207      * the constants above.
208      *
209      * Modules should never ACCEPT packets (except in well-justified cases);
210      * they should instead defer to any remaining modules using RETURN, or
211      * otherwise DROP/REJECT.
212      */
213 
214     // Create chains for children modules
215     createChildChains(V4V6, "filter", "INPUT", FILTER_INPUT);
216     createChildChains(V4V6, "filter", "FORWARD", FILTER_FORWARD);
217     createChildChains(V4V6, "filter", "OUTPUT", FILTER_OUTPUT);
218     createChildChains(V4V6, "raw", "PREROUTING", RAW_PREROUTING);
219     createChildChains(V4V6, "mangle", "POSTROUTING", MANGLE_POSTROUTING);
220     createChildChains(V4V6, "mangle", "FORWARD", MANGLE_FORWARD);
221     createChildChains(V4, "nat", "PREROUTING", NAT_PREROUTING);
222     createChildChains(V4, "nat", "POSTROUTING", NAT_POSTROUTING);
223 
224     // Let each module setup their child chains
225     setupOemIptablesHook();
226 
227     /* When enabled, DROPs all packets except those matching rules. */
228     gCtls->firewallCtrl.setupIptablesHooks();
229 
230     /* Does DROPs in FORWARD by default */
231     gCtls->natCtrl.setupIptablesHooks();
232     /*
233      * Does REJECT in INPUT, OUTPUT. Does counting also.
234      * No DROP/REJECT allowed later in netfilter-flow hook order.
235      */
236     gCtls->bandwidthCtrl.setupIptablesHooks();
237     /*
238      * Counts in nat: PREROUTING, POSTROUTING.
239      * No DROP/REJECT allowed later in netfilter-flow hook order.
240      */
241     gCtls->idletimerCtrl.setupIptablesHooks();
242 
243     gCtls->bandwidthCtrl.enableBandwidthControl(false);
244 
245     if (int ret = RouteController::Init(NetworkController::LOCAL_NET_ID)) {
246         ALOGE("failed to initialize RouteController (%s)", strerror(-ret));
247     }
248 }
249 
InterfaceCmd()250 CommandListener::InterfaceCmd::InterfaceCmd() :
251                  NetdCommand("interface") {
252 }
253 
runCommand(SocketClient * cli,int argc,char ** argv)254 int CommandListener::InterfaceCmd::runCommand(SocketClient *cli,
255                                                       int argc, char **argv) {
256     if (argc < 2) {
257         cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
258         return 0;
259     }
260 
261     if (!strcmp(argv[1], "list")) {
262         DIR *d;
263         struct dirent *de;
264 
265         if (!(d = opendir("/sys/class/net"))) {
266             cli->sendMsg(ResponseCode::OperationFailed, "Failed to open sysfs dir", true);
267             return 0;
268         }
269 
270         while((de = readdir(d))) {
271             if (de->d_name[0] == '.')
272                 continue;
273             cli->sendMsg(ResponseCode::InterfaceListResult, de->d_name, false);
274         }
275         closedir(d);
276         cli->sendMsg(ResponseCode::CommandOkay, "Interface list completed", false);
277         return 0;
278     } else {
279         /*
280          * These commands take a minimum of 3 arguments
281          */
282         if (argc < 3) {
283             cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
284             return 0;
285         }
286 
287         if (!strcmp(argv[1], "getcfg")) {
288             struct in_addr addr;
289             int prefixLength;
290             unsigned char hwaddr[6];
291             unsigned flags = 0;
292 
293             ifc_init();
294             memset(hwaddr, 0, sizeof(hwaddr));
295 
296             if (ifc_get_info(argv[2], &addr.s_addr, &prefixLength, &flags)) {
297                 cli->sendMsg(ResponseCode::OperationFailed, "Interface not found", true);
298                 ifc_close();
299                 return 0;
300             }
301 
302             if (ifc_get_hwaddr(argv[2], (void *) hwaddr)) {
303                 ALOGW("Failed to retrieve HW addr for %s (%s)", argv[2], strerror(errno));
304             }
305 
306             char *addr_s = strdup(inet_ntoa(addr));
307             const char *updown, *brdcst, *loopbk, *ppp, *running, *multi;
308 
309             updown =  (flags & IFF_UP)           ? "up" : "down";
310             brdcst =  (flags & IFF_BROADCAST)    ? " broadcast" : "";
311             loopbk =  (flags & IFF_LOOPBACK)     ? " loopback" : "";
312             ppp =     (flags & IFF_POINTOPOINT)  ? " point-to-point" : "";
313             running = (flags & IFF_RUNNING)      ? " running" : "";
314             multi =   (flags & IFF_MULTICAST)    ? " multicast" : "";
315 
316             char *flag_s;
317 
318             asprintf(&flag_s, "%s%s%s%s%s%s", updown, brdcst, loopbk, ppp, running, multi);
319 
320             char *msg = NULL;
321             asprintf(&msg, "%.2x:%.2x:%.2x:%.2x:%.2x:%.2x %s %d %s",
322                      hwaddr[0], hwaddr[1], hwaddr[2], hwaddr[3], hwaddr[4], hwaddr[5],
323                      addr_s, prefixLength, flag_s);
324 
325             cli->sendMsg(ResponseCode::InterfaceGetCfgResult, msg, false);
326 
327             free(addr_s);
328             free(flag_s);
329             free(msg);
330 
331             ifc_close();
332             return 0;
333         } else if (!strcmp(argv[1], "setcfg")) {
334             // arglist: iface [addr prefixLength] flags
335             if (argc < 4) {
336                 cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
337                 return 0;
338             }
339             ALOGD("Setting iface cfg");
340 
341             struct in_addr addr;
342             int index = 5;
343 
344             ifc_init();
345 
346             if (!inet_aton(argv[3], &addr)) {
347                 // Handle flags only case
348                 index = 3;
349             } else {
350                 if (ifc_set_addr(argv[2], 0)) {
351                     cli->sendMsg(ResponseCode::OperationFailed, "Failed to clear address", true);
352                     ifc_close();
353                     return 0;
354                 }
355                 if (addr.s_addr != 0) {
356                     if (ifc_add_address(argv[2], argv[3], atoi(argv[4]))) {
357                         cli->sendMsg(ResponseCode::OperationFailed, "Failed to set address", true);
358                         ifc_close();
359                         return 0;
360                     }
361                 }
362             }
363 
364             /* Process flags */
365             for (int i = index; i < argc; i++) {
366                 char *flag = argv[i];
367                 if (!strcmp(flag, "up")) {
368                     ALOGD("Trying to bring up %s", argv[2]);
369                     if (ifc_up(argv[2])) {
370                         ALOGE("Error upping interface");
371                         cli->sendMsg(ResponseCode::OperationFailed, "Failed to up interface", true);
372                         ifc_close();
373                         return 0;
374                     }
375                 } else if (!strcmp(flag, "down")) {
376                     ALOGD("Trying to bring down %s", argv[2]);
377                     if (ifc_down(argv[2])) {
378                         ALOGE("Error downing interface");
379                         cli->sendMsg(ResponseCode::OperationFailed, "Failed to down interface", true);
380                         ifc_close();
381                         return 0;
382                     }
383                 } else if (!strcmp(flag, "broadcast")) {
384                     // currently ignored
385                 } else if (!strcmp(flag, "multicast")) {
386                     // currently ignored
387                 } else if (!strcmp(flag, "running")) {
388                     // currently ignored
389                 } else if (!strcmp(flag, "loopback")) {
390                     // currently ignored
391                 } else if (!strcmp(flag, "point-to-point")) {
392                     // currently ignored
393                 } else {
394                     cli->sendMsg(ResponseCode::CommandParameterError, "Flag unsupported", false);
395                     ifc_close();
396                     return 0;
397                 }
398             }
399 
400             cli->sendMsg(ResponseCode::CommandOkay, "Interface configuration set", false);
401             ifc_close();
402             return 0;
403         } else if (!strcmp(argv[1], "clearaddrs")) {
404             // arglist: iface
405             ALOGD("Clearing all IP addresses on %s", argv[2]);
406 
407             ifc_clear_addresses(argv[2]);
408 
409             cli->sendMsg(ResponseCode::CommandOkay, "Interface IP addresses cleared", false);
410             return 0;
411         } else if (!strcmp(argv[1], "ipv6privacyextensions")) {
412             if (argc != 4) {
413                 cli->sendMsg(ResponseCode::CommandSyntaxError,
414                         "Usage: interface ipv6privacyextensions <interface> <enable|disable>",
415                         false);
416                 return 0;
417             }
418             int enable = !strncmp(argv[3], "enable", 7);
419             if (InterfaceController::setIPv6PrivacyExtensions(argv[2], enable) == 0) {
420                 cli->sendMsg(ResponseCode::CommandOkay, "IPv6 privacy extensions changed", false);
421             } else {
422                 cli->sendMsg(ResponseCode::OperationFailed,
423                         "Failed to set ipv6 privacy extensions", true);
424             }
425             return 0;
426         } else if (!strcmp(argv[1], "ipv6")) {
427             if (argc != 4) {
428                 cli->sendMsg(ResponseCode::CommandSyntaxError,
429                         "Usage: interface ipv6 <interface> <enable|disable>",
430                         false);
431                 return 0;
432             }
433 
434             int enable = !strncmp(argv[3], "enable", 7);
435             if (InterfaceController::setEnableIPv6(argv[2], enable) == 0) {
436                 cli->sendMsg(ResponseCode::CommandOkay, "IPv6 state changed", false);
437             } else {
438                 cli->sendMsg(ResponseCode::OperationFailed,
439                         "Failed to change IPv6 state", true);
440             }
441             return 0;
442         } else if (!strcmp(argv[1], "ipv6ndoffload")) {
443             if (argc != 4) {
444                 cli->sendMsg(ResponseCode::CommandSyntaxError,
445                         "Usage: interface ipv6ndoffload <interface> <enable|disable>",
446                         false);
447                 return 0;
448             }
449             int enable = !strncmp(argv[3], "enable", 7);
450             if (InterfaceController::setIPv6NdOffload(argv[2], enable) == 0) {
451                 cli->sendMsg(ResponseCode::CommandOkay, "IPv6 ND offload changed", false);
452             } else {
453                 cli->sendMsg(ResponseCode::OperationFailed,
454                         "Failed to change IPv6 ND offload state", true);
455             }
456             return 0;
457         } else if (!strcmp(argv[1], "setmtu")) {
458             if (argc != 4) {
459                 cli->sendMsg(ResponseCode::CommandSyntaxError,
460                         "Usage: interface setmtu <interface> <val>", false);
461                 return 0;
462             }
463             if (InterfaceController::setMtu(argv[2], argv[3]) == 0) {
464                 cli->sendMsg(ResponseCode::CommandOkay, "MTU changed", false);
465             } else {
466                 cli->sendMsg(ResponseCode::OperationFailed,
467                         "Failed to set MTU", true);
468             }
469             return 0;
470         } else {
471             cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown interface cmd", false);
472             return 0;
473         }
474     }
475     return 0;
476 }
477 
478 
ListTtysCmd()479 CommandListener::ListTtysCmd::ListTtysCmd() :
480                  NetdCommand("list_ttys") {
481 }
482 
runCommand(SocketClient * cli,int,char **)483 int CommandListener::ListTtysCmd::runCommand(SocketClient *cli,
484                                              int /* argc */, char ** /* argv */) {
485     TtyCollection *tlist = gCtls->pppCtrl.getTtyList();
486     TtyCollection::iterator it;
487 
488     for (it = tlist->begin(); it != tlist->end(); ++it) {
489         cli->sendMsg(ResponseCode::TtyListResult, *it, false);
490     }
491 
492     cli->sendMsg(ResponseCode::CommandOkay, "Ttys listed.", false);
493     return 0;
494 }
495 
IpFwdCmd()496 CommandListener::IpFwdCmd::IpFwdCmd() :
497                  NetdCommand("ipfwd") {
498 }
499 
runCommand(SocketClient * cli,int argc,char ** argv)500 int CommandListener::IpFwdCmd::runCommand(SocketClient *cli, int argc, char **argv) {
501     bool matched = false;
502     bool success;
503 
504     if (argc == 2) {
505         //   0     1
506         // ipfwd status
507         if (!strcmp(argv[1], "status")) {
508             char *tmp = NULL;
509 
510             asprintf(&tmp, "Forwarding %s",
511                      ((gCtls->tetherCtrl.forwardingRequestCount() > 0) ? "enabled" : "disabled"));
512             cli->sendMsg(ResponseCode::IpFwdStatusResult, tmp, false);
513             free(tmp);
514             return 0;
515         }
516     } else if (argc == 3) {
517         //  0      1         2
518         // ipfwd enable  <requester>
519         // ipfwd disable <requester>
520         if (!strcmp(argv[1], "enable")) {
521             matched = true;
522             success = gCtls->tetherCtrl.enableForwarding(argv[2]);
523         } else if (!strcmp(argv[1], "disable")) {
524             matched = true;
525             success = gCtls->tetherCtrl.disableForwarding(argv[2]);
526         }
527     } else if (argc == 4) {
528         //  0      1      2     3
529         // ipfwd  add   wlan0 dummy0
530         // ipfwd remove wlan0 dummy0
531         int ret = 0;
532         if (!strcmp(argv[1], "add")) {
533             matched = true;
534             ret = RouteController::enableTethering(argv[2], argv[3]);
535         } else if (!strcmp(argv[1], "remove")) {
536             matched = true;
537             ret = RouteController::disableTethering(argv[2], argv[3]);
538         }
539         success = (ret == 0);
540         errno = -ret;
541     }
542 
543     if (!matched) {
544         cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown ipfwd cmd", false);
545         return 0;
546     }
547 
548     if (success) {
549         cli->sendMsg(ResponseCode::CommandOkay, "ipfwd operation succeeded", false);
550     } else {
551         cli->sendMsg(ResponseCode::OperationFailed, "ipfwd operation failed", true);
552     }
553     return 0;
554 }
555 
TetherCmd()556 CommandListener::TetherCmd::TetherCmd() :
557                  NetdCommand("tether") {
558 }
559 
runCommand(SocketClient * cli,int argc,char ** argv)560 int CommandListener::TetherCmd::runCommand(SocketClient *cli,
561                                                       int argc, char **argv) {
562     int rc = 0;
563 
564     if (argc < 2) {
565         cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
566         return 0;
567     }
568 
569     if (!strcmp(argv[1], "stop")) {
570         rc = gCtls->tetherCtrl.stopTethering();
571     } else if (!strcmp(argv[1], "status")) {
572         char *tmp = NULL;
573 
574         asprintf(&tmp, "Tethering services %s",
575                  (gCtls->tetherCtrl.isTetheringStarted() ? "started" : "stopped"));
576         cli->sendMsg(ResponseCode::TetherStatusResult, tmp, false);
577         free(tmp);
578         return 0;
579     } else if (argc == 3) {
580         if (!strcmp(argv[1], "interface") && !strcmp(argv[2], "list")) {
581             for (const auto &ifname : gCtls->tetherCtrl.getTetheredInterfaceList()) {
582                 cli->sendMsg(ResponseCode::TetherInterfaceListResult, ifname.c_str(), false);
583             }
584         } else if (!strcmp(argv[1], "dns") && !strcmp(argv[2], "list")) {
585             char netIdStr[UINT32_STRLEN];
586             snprintf(netIdStr, sizeof(netIdStr), "%u", gCtls->tetherCtrl.getDnsNetId());
587             cli->sendMsg(ResponseCode::TetherDnsFwdNetIdResult, netIdStr, false);
588 
589             for (const auto &fwdr : gCtls->tetherCtrl.getDnsForwarders()) {
590                 cli->sendMsg(ResponseCode::TetherDnsFwdTgtListResult, fwdr.c_str(), false);
591             }
592         }
593     } else {
594         /*
595          * These commands take a minimum of 4 arguments
596          */
597         if (argc < 4) {
598             cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
599             return 0;
600         }
601 
602         if (!strcmp(argv[1], "start")) {
603             if (argc % 2 == 1) {
604                 cli->sendMsg(ResponseCode::CommandSyntaxError, "Bad number of arguments", false);
605                 return 0;
606             }
607 
608             const int num_addrs = argc - 2;
609             // TODO: consider moving this validation into TetherController.
610             struct in_addr tmp_addr;
611             for (int arg_index = 2; arg_index < argc; arg_index++) {
612                 if (!inet_aton(argv[arg_index], &tmp_addr)) {
613                     cli->sendMsg(ResponseCode::CommandParameterError, "Invalid address", false);
614                     return 0;
615                 }
616             }
617 
618             rc = gCtls->tetherCtrl.startTethering(num_addrs, &(argv[2]));
619         } else if (!strcmp(argv[1], "interface")) {
620             if (!strcmp(argv[2], "add")) {
621                 rc = gCtls->tetherCtrl.tetherInterface(argv[3]);
622             } else if (!strcmp(argv[2], "remove")) {
623                 rc = gCtls->tetherCtrl.untetherInterface(argv[3]);
624             /* else if (!strcmp(argv[2], "list")) handled above */
625             } else {
626                 cli->sendMsg(ResponseCode::CommandParameterError,
627                              "Unknown tether interface operation", false);
628                 return 0;
629             }
630         } else if (!strcmp(argv[1], "dns")) {
631             if (!strcmp(argv[2], "set")) {
632                 if (argc < 5) {
633                     cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
634                     return 0;
635                 }
636                 unsigned netId = stringToNetId(argv[3]);
637                 rc = gCtls->tetherCtrl.setDnsForwarders(netId, &argv[4], argc - 4);
638             /* else if (!strcmp(argv[2], "list")) handled above */
639             } else {
640                 cli->sendMsg(ResponseCode::CommandParameterError,
641                              "Unknown tether interface operation", false);
642                 return 0;
643             }
644         } else {
645             cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown tether cmd", false);
646             return 0;
647         }
648     }
649 
650     if (!rc) {
651         cli->sendMsg(ResponseCode::CommandOkay, "Tether operation succeeded", false);
652     } else {
653         cli->sendMsg(ResponseCode::OperationFailed, "Tether operation failed", true);
654     }
655 
656     return 0;
657 }
658 
NatCmd()659 CommandListener::NatCmd::NatCmd() :
660                  NetdCommand("nat") {
661 }
662 
runCommand(SocketClient * cli,int argc,char ** argv)663 int CommandListener::NatCmd::runCommand(SocketClient *cli,
664                                                       int argc, char **argv) {
665     int rc = 0;
666 
667     if (argc < 5) {
668         cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
669         return 0;
670     }
671 
672     //  0     1       2        3
673     // nat  enable intiface extiface
674     // nat disable intiface extiface
675     if (!strcmp(argv[1], "enable") && argc >= 4) {
676         rc = gCtls->natCtrl.enableNat(argv[2], argv[3]);
677         if(!rc) {
678             /* Ignore ifaces for now. */
679             rc = gCtls->bandwidthCtrl.setGlobalAlertInForwardChain();
680         }
681     } else if (!strcmp(argv[1], "disable") && argc >= 4) {
682         /* Ignore ifaces for now. */
683         rc = gCtls->bandwidthCtrl.removeGlobalAlertInForwardChain();
684         rc |= gCtls->natCtrl.disableNat(argv[2], argv[3]);
685     } else {
686         cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown nat cmd", false);
687         return 0;
688     }
689 
690     if (!rc) {
691         cli->sendMsg(ResponseCode::CommandOkay, "Nat operation succeeded", false);
692     } else {
693         cli->sendMsg(ResponseCode::OperationFailed, "Nat operation failed", true);
694     }
695 
696     return 0;
697 }
698 
PppdCmd()699 CommandListener::PppdCmd::PppdCmd() :
700                  NetdCommand("pppd") {
701 }
702 
runCommand(SocketClient * cli,int argc,char ** argv)703 int CommandListener::PppdCmd::runCommand(SocketClient *cli,
704                                                       int argc, char **argv) {
705     int rc = 0;
706 
707     if (argc < 3) {
708         cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
709         return 0;
710     }
711 
712     if (!strcmp(argv[1], "attach")) {
713         struct in_addr l, r, dns1, dns2;
714 
715         memset(&dns1, 0, sizeof(struct in_addr));
716         memset(&dns2, 0, sizeof(struct in_addr));
717 
718         if (!inet_aton(argv[3], &l)) {
719             cli->sendMsg(ResponseCode::CommandParameterError, "Invalid local address", false);
720             return 0;
721         }
722         if (!inet_aton(argv[4], &r)) {
723             cli->sendMsg(ResponseCode::CommandParameterError, "Invalid remote address", false);
724             return 0;
725         }
726         if ((argc > 3) && (!inet_aton(argv[5], &dns1))) {
727             cli->sendMsg(ResponseCode::CommandParameterError, "Invalid dns1 address", false);
728             return 0;
729         }
730         if ((argc > 4) && (!inet_aton(argv[6], &dns2))) {
731             cli->sendMsg(ResponseCode::CommandParameterError, "Invalid dns2 address", false);
732             return 0;
733         }
734         rc = gCtls->pppCtrl.attachPppd(argv[2], l, r, dns1, dns2);
735     } else if (!strcmp(argv[1], "detach")) {
736         rc = gCtls->pppCtrl.detachPppd(argv[2]);
737     } else {
738         cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown pppd cmd", false);
739         return 0;
740     }
741 
742     if (!rc) {
743         cli->sendMsg(ResponseCode::CommandOkay, "Pppd operation succeeded", false);
744     } else {
745         cli->sendMsg(ResponseCode::OperationFailed, "Pppd operation failed", true);
746     }
747 
748     return 0;
749 }
750 
SoftapCmd()751 CommandListener::SoftapCmd::SoftapCmd() :
752                  NetdCommand("softap") {
753 }
754 
runCommand(SocketClient * cli,int argc,char ** argv)755 int CommandListener::SoftapCmd::runCommand(SocketClient *cli,
756                                         int argc, char **argv) {
757     int rc = ResponseCode::SoftapStatusResult;
758     char *retbuf = NULL;
759 
760     if (gCtls == nullptr) {
761       cli->sendMsg(ResponseCode::ServiceStartFailed, "SoftAP is not available", false);
762       return -1;
763     }
764     if (argc < 2) {
765         cli->sendMsg(ResponseCode::CommandSyntaxError,
766                      "Missing argument in a SoftAP command", false);
767         return 0;
768     }
769 
770     if (!strcmp(argv[1], "startap")) {
771         rc = gCtls->softapCtrl.startSoftap();
772     } else if (!strcmp(argv[1], "stopap")) {
773         rc = gCtls->softapCtrl.stopSoftap();
774     } else if (!strcmp(argv[1], "fwreload")) {
775         rc = gCtls->softapCtrl.fwReloadSoftap(argc, argv);
776     } else if (!strcmp(argv[1], "status")) {
777         asprintf(&retbuf, "Softap service %s running",
778                  (gCtls->softapCtrl.isSoftapStarted() ? "is" : "is not"));
779         cli->sendMsg(rc, retbuf, false);
780         free(retbuf);
781         return 0;
782     } else if (!strcmp(argv[1], "set")) {
783         rc = gCtls->softapCtrl.setSoftap(argc, argv);
784     } else {
785         cli->sendMsg(ResponseCode::CommandSyntaxError, "Unrecognized SoftAP command", false);
786         return 0;
787     }
788 
789     if (rc >= 400 && rc < 600)
790       cli->sendMsg(rc, "SoftAP command has failed", false);
791     else
792       cli->sendMsg(rc, "Ok", false);
793 
794     return 0;
795 }
796 
ResolverCmd()797 CommandListener::ResolverCmd::ResolverCmd() :
798         NetdCommand("resolver") {
799 }
800 
runCommand(SocketClient * cli,int argc,char ** margv)801 int CommandListener::ResolverCmd::runCommand(SocketClient *cli, int argc, char **margv) {
802     int rc = 0;
803     const char **argv = const_cast<const char **>(margv);
804 
805     if (argc < 3) {
806         cli->sendMsg(ResponseCode::CommandSyntaxError, "Resolver missing arguments", false);
807         return 0;
808     }
809 
810     unsigned netId = stringToNetId(argv[2]);
811     // TODO: Consider making NetworkController.isValidNetwork() public
812     // and making that check here.
813 
814     if (!strcmp(argv[1], "setnetdns")) {
815         if (!parseAndExecuteSetNetDns(netId, argc, argv)) {
816             cli->sendMsg(ResponseCode::CommandSyntaxError,
817                     "Wrong number of or invalid arguments to resolver setnetdns", false);
818             return 0;
819         }
820     } else if (!strcmp(argv[1], "clearnetdns")) { // "resolver clearnetdns <netId>"
821         if (argc == 3) {
822             rc = gCtls->resolverCtrl.clearDnsServers(netId);
823         } else {
824             cli->sendMsg(ResponseCode::CommandSyntaxError,
825                     "Wrong number of arguments to resolver clearnetdns", false);
826             return 0;
827         }
828     } else {
829         cli->sendMsg(ResponseCode::CommandSyntaxError,"Resolver unknown command", false);
830         return 0;
831     }
832 
833     if (!rc) {
834         cli->sendMsg(ResponseCode::CommandOkay, "Resolver command succeeded", false);
835     } else {
836         cli->sendMsg(ResponseCode::OperationFailed, "Resolver command failed", true);
837     }
838 
839     return 0;
840 }
841 
parseAndExecuteSetNetDns(int netId,int argc,const char ** argv)842 bool CommandListener::ResolverCmd::parseAndExecuteSetNetDns(int netId, int argc,
843         const char** argv) {
844     // "resolver setnetdns <netId> <domains> <dns1> [<dns2> ...] [--params <params>]"
845     // TODO: This code has to be replaced by a Binder call ASAP
846     if (argc < 5) {
847         return false;
848     }
849     int end = argc;
850     __res_params params;
851     const __res_params* paramsPtr = nullptr;
852     if (end > 6 && !strcmp(argv[end - 2], "--params")) {
853         const char* paramsStr = argv[end - 1];
854         end -= 2;
855         if (sscanf(paramsStr, "%hu %hhu %hhu %hhu", &params.sample_validity,
856                 &params.success_threshold, &params.min_samples, &params.max_samples) != 4) {
857             return false;
858         }
859         paramsPtr = &params;
860     }
861     return gCtls->resolverCtrl.setDnsServers(netId, argv[3], &argv[4], end - 4, paramsPtr) == 0;
862 }
863 
BandwidthControlCmd()864 CommandListener::BandwidthControlCmd::BandwidthControlCmd() :
865     NetdCommand("bandwidth") {
866 }
867 
sendGenericSyntaxError(SocketClient * cli,const char * usageMsg)868 void CommandListener::BandwidthControlCmd::sendGenericSyntaxError(SocketClient *cli, const char *usageMsg) {
869     char *msg;
870     asprintf(&msg, "Usage: bandwidth %s", usageMsg);
871     cli->sendMsg(ResponseCode::CommandSyntaxError, msg, false);
872     free(msg);
873 }
874 
sendGenericOkFail(SocketClient * cli,int cond)875 void CommandListener::BandwidthControlCmd::sendGenericOkFail(SocketClient *cli, int cond) {
876     if (!cond) {
877         cli->sendMsg(ResponseCode::CommandOkay, "Bandwidth command succeeeded", false);
878     } else {
879         cli->sendMsg(ResponseCode::OperationFailed, "Bandwidth command failed", false);
880     }
881 }
882 
sendGenericOpFailed(SocketClient * cli,const char * errMsg)883 void CommandListener::BandwidthControlCmd::sendGenericOpFailed(SocketClient *cli, const char *errMsg) {
884     cli->sendMsg(ResponseCode::OperationFailed, errMsg, false);
885 }
886 
runCommand(SocketClient * cli,int argc,char ** argv)887 int CommandListener::BandwidthControlCmd::runCommand(SocketClient *cli, int argc, char **argv) {
888     if (argc < 2) {
889         sendGenericSyntaxError(cli, "<cmds> <args...>");
890         return 0;
891     }
892 
893     ALOGV("bwctrlcmd: argc=%d %s %s ...", argc, argv[0], argv[1]);
894 
895     if (!strcmp(argv[1], "enable")) {
896         int rc = gCtls->bandwidthCtrl.enableBandwidthControl(true);
897         sendGenericOkFail(cli, rc);
898         return 0;
899 
900     }
901     if (!strcmp(argv[1], "disable")) {
902         int rc = gCtls->bandwidthCtrl.disableBandwidthControl();
903         sendGenericOkFail(cli, rc);
904         return 0;
905 
906     }
907     if (!strcmp(argv[1], "removequota") || !strcmp(argv[1], "rq")) {
908         if (argc != 3) {
909             sendGenericSyntaxError(cli, "removequota <interface>");
910             return 0;
911         }
912         int rc = gCtls->bandwidthCtrl.removeInterfaceSharedQuota(argv[2]);
913         sendGenericOkFail(cli, rc);
914         return 0;
915 
916     }
917     if (!strcmp(argv[1], "getquota") || !strcmp(argv[1], "gq")) {
918         int64_t bytes;
919         if (argc != 2) {
920             sendGenericSyntaxError(cli, "getquota");
921             return 0;
922         }
923         int rc = gCtls->bandwidthCtrl.getInterfaceSharedQuota(&bytes);
924         if (rc) {
925             sendGenericOpFailed(cli, "Failed to get quota");
926             return 0;
927         }
928 
929         char *msg;
930         asprintf(&msg, "%" PRId64, bytes);
931         cli->sendMsg(ResponseCode::QuotaCounterResult, msg, false);
932         free(msg);
933         return 0;
934 
935     }
936     if (!strcmp(argv[1], "getiquota") || !strcmp(argv[1], "giq")) {
937         int64_t bytes;
938         if (argc != 3) {
939             sendGenericSyntaxError(cli, "getiquota <iface>");
940             return 0;
941         }
942 
943         int rc = gCtls->bandwidthCtrl.getInterfaceQuota(argv[2], &bytes);
944         if (rc) {
945             sendGenericOpFailed(cli, "Failed to get quota");
946             return 0;
947         }
948         char *msg;
949         asprintf(&msg, "%" PRId64, bytes);
950         cli->sendMsg(ResponseCode::QuotaCounterResult, msg, false);
951         free(msg);
952         return 0;
953 
954     }
955     if (!strcmp(argv[1], "setquota") || !strcmp(argv[1], "sq")) {
956         if (argc != 4) {
957             sendGenericSyntaxError(cli, "setquota <interface> <bytes>");
958             return 0;
959         }
960         int rc = gCtls->bandwidthCtrl.setInterfaceSharedQuota(argv[2], atoll(argv[3]));
961         sendGenericOkFail(cli, rc);
962         return 0;
963     }
964     if (!strcmp(argv[1], "setquotas") || !strcmp(argv[1], "sqs")) {
965         int rc;
966         if (argc < 4) {
967             sendGenericSyntaxError(cli, "setquotas <bytes> <interface> ...");
968             return 0;
969         }
970 
971         for (int q = 3; argc >= 4; q++, argc--) {
972             rc = gCtls->bandwidthCtrl.setInterfaceSharedQuota(argv[q], atoll(argv[2]));
973             if (rc) {
974                 char *msg;
975                 asprintf(&msg, "bandwidth setquotas %s %s failed", argv[2], argv[q]);
976                 cli->sendMsg(ResponseCode::OperationFailed,
977                              msg, false);
978                 free(msg);
979                 return 0;
980             }
981         }
982         sendGenericOkFail(cli, rc);
983         return 0;
984 
985     }
986     if (!strcmp(argv[1], "removequotas") || !strcmp(argv[1], "rqs")) {
987         int rc;
988         if (argc < 3) {
989             sendGenericSyntaxError(cli, "removequotas <interface> ...");
990             return 0;
991         }
992 
993         for (int q = 2; argc >= 3; q++, argc--) {
994             rc = gCtls->bandwidthCtrl.removeInterfaceSharedQuota(argv[q]);
995             if (rc) {
996                 char *msg;
997                 asprintf(&msg, "bandwidth removequotas %s failed", argv[q]);
998                 cli->sendMsg(ResponseCode::OperationFailed,
999                              msg, false);
1000                 free(msg);
1001                 return 0;
1002             }
1003         }
1004         sendGenericOkFail(cli, rc);
1005         return 0;
1006 
1007     }
1008     if (!strcmp(argv[1], "removeiquota") || !strcmp(argv[1], "riq")) {
1009         if (argc != 3) {
1010             sendGenericSyntaxError(cli, "removeiquota <interface>");
1011             return 0;
1012         }
1013         int rc = gCtls->bandwidthCtrl.removeInterfaceQuota(argv[2]);
1014         sendGenericOkFail(cli, rc);
1015         return 0;
1016 
1017     }
1018     if (!strcmp(argv[1], "setiquota") || !strcmp(argv[1], "siq")) {
1019         if (argc != 4) {
1020             sendGenericSyntaxError(cli, "setiquota <interface> <bytes>");
1021             return 0;
1022         }
1023         int rc = gCtls->bandwidthCtrl.setInterfaceQuota(argv[2], atoll(argv[3]));
1024         sendGenericOkFail(cli, rc);
1025         return 0;
1026 
1027     }
1028     if (!strcmp(argv[1], "addnaughtyapps") || !strcmp(argv[1], "ana")) {
1029         if (argc < 3) {
1030             sendGenericSyntaxError(cli, "addnaughtyapps <appUid> ...");
1031             return 0;
1032         }
1033         int rc = gCtls->bandwidthCtrl.addNaughtyApps(argc - 2, argv + 2);
1034         sendGenericOkFail(cli, rc);
1035         return 0;
1036 
1037 
1038     }
1039     if (!strcmp(argv[1], "removenaughtyapps") || !strcmp(argv[1], "rna")) {
1040         if (argc < 3) {
1041             sendGenericSyntaxError(cli, "removenaughtyapps <appUid> ...");
1042             return 0;
1043         }
1044         int rc = gCtls->bandwidthCtrl.removeNaughtyApps(argc - 2, argv + 2);
1045         sendGenericOkFail(cli, rc);
1046         return 0;
1047     }
1048     if (!strcmp(argv[1], "addniceapps") || !strcmp(argv[1], "aha")) {
1049         if (argc < 3) {
1050             sendGenericSyntaxError(cli, "addniceapps <appUid> ...");
1051             return 0;
1052         }
1053         int rc = gCtls->bandwidthCtrl.addNiceApps(argc - 2, argv + 2);
1054         sendGenericOkFail(cli, rc);
1055         return 0;
1056     }
1057     if (!strcmp(argv[1], "removeniceapps") || !strcmp(argv[1], "rha")) {
1058         if (argc < 3) {
1059             sendGenericSyntaxError(cli, "removeniceapps <appUid> ...");
1060             return 0;
1061         }
1062         int rc = gCtls->bandwidthCtrl.removeNiceApps(argc - 2, argv + 2);
1063         sendGenericOkFail(cli, rc);
1064         return 0;
1065     }
1066     if (!strcmp(argv[1], "setglobalalert") || !strcmp(argv[1], "sga")) {
1067         if (argc != 3) {
1068             sendGenericSyntaxError(cli, "setglobalalert <bytes>");
1069             return 0;
1070         }
1071         int rc = gCtls->bandwidthCtrl.setGlobalAlert(atoll(argv[2]));
1072         sendGenericOkFail(cli, rc);
1073         return 0;
1074     }
1075     if (!strcmp(argv[1], "debugsettetherglobalalert") || !strcmp(argv[1], "dstga")) {
1076         if (argc != 4) {
1077             sendGenericSyntaxError(cli, "debugsettetherglobalalert <interface0> <interface1>");
1078             return 0;
1079         }
1080         /* We ignore the interfaces for now. */
1081         int rc = gCtls->bandwidthCtrl.setGlobalAlertInForwardChain();
1082         sendGenericOkFail(cli, rc);
1083         return 0;
1084 
1085     }
1086     if (!strcmp(argv[1], "removeglobalalert") || !strcmp(argv[1], "rga")) {
1087         if (argc != 2) {
1088             sendGenericSyntaxError(cli, "removeglobalalert");
1089             return 0;
1090         }
1091         int rc = gCtls->bandwidthCtrl.removeGlobalAlert();
1092         sendGenericOkFail(cli, rc);
1093         return 0;
1094 
1095     }
1096     if (!strcmp(argv[1], "debugremovetetherglobalalert") || !strcmp(argv[1], "drtga")) {
1097         if (argc != 4) {
1098             sendGenericSyntaxError(cli, "debugremovetetherglobalalert <interface0> <interface1>");
1099             return 0;
1100         }
1101         /* We ignore the interfaces for now. */
1102         int rc = gCtls->bandwidthCtrl.removeGlobalAlertInForwardChain();
1103         sendGenericOkFail(cli, rc);
1104         return 0;
1105 
1106     }
1107     if (!strcmp(argv[1], "setsharedalert") || !strcmp(argv[1], "ssa")) {
1108         if (argc != 3) {
1109             sendGenericSyntaxError(cli, "setsharedalert <bytes>");
1110             return 0;
1111         }
1112         int rc = gCtls->bandwidthCtrl.setSharedAlert(atoll(argv[2]));
1113         sendGenericOkFail(cli, rc);
1114         return 0;
1115 
1116     }
1117     if (!strcmp(argv[1], "removesharedalert") || !strcmp(argv[1], "rsa")) {
1118         if (argc != 2) {
1119             sendGenericSyntaxError(cli, "removesharedalert");
1120             return 0;
1121         }
1122         int rc = gCtls->bandwidthCtrl.removeSharedAlert();
1123         sendGenericOkFail(cli, rc);
1124         return 0;
1125 
1126     }
1127     if (!strcmp(argv[1], "setinterfacealert") || !strcmp(argv[1], "sia")) {
1128         if (argc != 4) {
1129             sendGenericSyntaxError(cli, "setinterfacealert <interface> <bytes>");
1130             return 0;
1131         }
1132         int rc = gCtls->bandwidthCtrl.setInterfaceAlert(argv[2], atoll(argv[3]));
1133         sendGenericOkFail(cli, rc);
1134         return 0;
1135 
1136     }
1137     if (!strcmp(argv[1], "removeinterfacealert") || !strcmp(argv[1], "ria")) {
1138         if (argc != 3) {
1139             sendGenericSyntaxError(cli, "removeinterfacealert <interface>");
1140             return 0;
1141         }
1142         int rc = gCtls->bandwidthCtrl.removeInterfaceAlert(argv[2]);
1143         sendGenericOkFail(cli, rc);
1144         return 0;
1145 
1146     }
1147     if (!strcmp(argv[1], "gettetherstats") || !strcmp(argv[1], "gts")) {
1148         BandwidthController::TetherStats tetherStats;
1149         std::string extraProcessingInfo = "";
1150         if (argc < 2 || argc > 4) {
1151             sendGenericSyntaxError(cli, "gettetherstats [<intInterface> <extInterface>]");
1152             return 0;
1153         }
1154         tetherStats.intIface = argc > 2 ? argv[2] : "";
1155         tetherStats.extIface = argc > 3 ? argv[3] : "";
1156         // No filtering requested and there are no interface pairs to lookup.
1157         if (argc <= 2 && gCtls->natCtrl.ifacePairList.empty()) {
1158             cli->sendMsg(ResponseCode::CommandOkay, "Tethering stats list completed", false);
1159             return 0;
1160         }
1161         int rc = gCtls->bandwidthCtrl.getTetherStats(cli, tetherStats, extraProcessingInfo);
1162         if (rc) {
1163                 extraProcessingInfo.insert(0, "Failed to get tethering stats.\n");
1164                 sendGenericOpFailed(cli, extraProcessingInfo.c_str());
1165                 return 0;
1166         }
1167         return 0;
1168 
1169     }
1170 
1171     cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown bandwidth cmd", false);
1172     return 0;
1173 }
1174 
IdletimerControlCmd()1175 CommandListener::IdletimerControlCmd::IdletimerControlCmd() :
1176     NetdCommand("idletimer") {
1177 }
1178 
runCommand(SocketClient * cli,int argc,char ** argv)1179 int CommandListener::IdletimerControlCmd::runCommand(SocketClient *cli, int argc, char **argv) {
1180   // TODO(ashish): Change the error statements
1181     if (argc < 2) {
1182         cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
1183         return 0;
1184     }
1185 
1186     ALOGV("idletimerctrlcmd: argc=%d %s %s ...", argc, argv[0], argv[1]);
1187 
1188     if (!strcmp(argv[1], "enable")) {
1189       if (0 != gCtls->idletimerCtrl.enableIdletimerControl()) {
1190         cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
1191       } else {
1192         cli->sendMsg(ResponseCode::CommandOkay, "Enable success", false);
1193       }
1194       return 0;
1195 
1196     }
1197     if (!strcmp(argv[1], "disable")) {
1198       if (0 != gCtls->idletimerCtrl.disableIdletimerControl()) {
1199         cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
1200       } else {
1201         cli->sendMsg(ResponseCode::CommandOkay, "Disable success", false);
1202       }
1203       return 0;
1204     }
1205     if (!strcmp(argv[1], "add")) {
1206         if (argc != 5) {
1207             cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
1208             return 0;
1209         }
1210         if(0 != gCtls->idletimerCtrl.addInterfaceIdletimer(
1211                                         argv[2], atoi(argv[3]), argv[4])) {
1212           cli->sendMsg(ResponseCode::OperationFailed, "Failed to add interface", false);
1213         } else {
1214           cli->sendMsg(ResponseCode::CommandOkay,  "Add success", false);
1215         }
1216         return 0;
1217     }
1218     if (!strcmp(argv[1], "remove")) {
1219         if (argc != 5) {
1220             cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
1221             return 0;
1222         }
1223         // ashish: fixme timeout
1224         if (0 != gCtls->idletimerCtrl.removeInterfaceIdletimer(
1225                                         argv[2], atoi(argv[3]), argv[4])) {
1226           cli->sendMsg(ResponseCode::OperationFailed, "Failed to remove interface", false);
1227         } else {
1228           cli->sendMsg(ResponseCode::CommandOkay, "Remove success", false);
1229         }
1230         return 0;
1231     }
1232 
1233     cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown idletimer cmd", false);
1234     return 0;
1235 }
1236 
FirewallCmd()1237 CommandListener::FirewallCmd::FirewallCmd() :
1238     NetdCommand("firewall") {
1239 }
1240 
sendGenericOkFail(SocketClient * cli,int cond)1241 int CommandListener::FirewallCmd::sendGenericOkFail(SocketClient *cli, int cond) {
1242     if (!cond) {
1243         cli->sendMsg(ResponseCode::CommandOkay, "Firewall command succeeded", false);
1244     } else {
1245         cli->sendMsg(ResponseCode::OperationFailed, "Firewall command failed", false);
1246     }
1247     return 0;
1248 }
1249 
parseRule(const char * arg)1250 FirewallRule CommandListener::FirewallCmd::parseRule(const char* arg) {
1251     if (!strcmp(arg, "allow")) {
1252         return ALLOW;
1253     } else if (!strcmp(arg, "deny")) {
1254         return DENY;
1255     } else {
1256         ALOGE("failed to parse uid rule (%s)", arg);
1257         return ALLOW;
1258     }
1259 }
1260 
parseFirewallType(const char * arg)1261 FirewallType CommandListener::FirewallCmd::parseFirewallType(const char* arg) {
1262     if (!strcmp(arg, "whitelist")) {
1263         return WHITELIST;
1264     } else if (!strcmp(arg, "blacklist")) {
1265         return BLACKLIST;
1266     } else {
1267         ALOGE("failed to parse firewall type (%s)", arg);
1268         return BLACKLIST;
1269     }
1270 }
1271 
parseChildChain(const char * arg)1272 ChildChain CommandListener::FirewallCmd::parseChildChain(const char* arg) {
1273     if (!strcmp(arg, "dozable")) {
1274         return DOZABLE;
1275     } else if (!strcmp(arg, "standby")) {
1276         return STANDBY;
1277     } else if (!strcmp(arg, "powersave")) {
1278         return POWERSAVE;
1279     } else if (!strcmp(arg, "none")) {
1280         return NONE;
1281     } else {
1282         ALOGE("failed to parse child firewall chain (%s)", arg);
1283         return INVALID_CHAIN;
1284     }
1285 }
1286 
runCommand(SocketClient * cli,int argc,char ** argv)1287 int CommandListener::FirewallCmd::runCommand(SocketClient *cli, int argc,
1288         char **argv) {
1289     if (argc < 2) {
1290         cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing command", false);
1291         return 0;
1292     }
1293 
1294     if (!strcmp(argv[1], "enable")) {
1295         if (argc != 3) {
1296             cli->sendMsg(ResponseCode::CommandSyntaxError,
1297                         "Usage: firewall enable <whitelist|blacklist>", false);
1298             return 0;
1299         }
1300         FirewallType firewallType = parseFirewallType(argv[2]);
1301 
1302         int res = gCtls->firewallCtrl.enableFirewall(firewallType);
1303         return sendGenericOkFail(cli, res);
1304     }
1305     if (!strcmp(argv[1], "disable")) {
1306         int res = gCtls->firewallCtrl.disableFirewall();
1307         return sendGenericOkFail(cli, res);
1308     }
1309     if (!strcmp(argv[1], "is_enabled")) {
1310         int res = gCtls->firewallCtrl.isFirewallEnabled();
1311         return sendGenericOkFail(cli, res);
1312     }
1313 
1314     if (!strcmp(argv[1], "set_interface_rule")) {
1315         if (argc != 4) {
1316             cli->sendMsg(ResponseCode::CommandSyntaxError,
1317                          "Usage: firewall set_interface_rule <rmnet0> <allow|deny>", false);
1318             return 0;
1319         }
1320 
1321         const char* iface = argv[2];
1322         FirewallRule rule = parseRule(argv[3]);
1323 
1324         int res = gCtls->firewallCtrl.setInterfaceRule(iface, rule);
1325         return sendGenericOkFail(cli, res);
1326     }
1327 
1328     if (!strcmp(argv[1], "set_egress_source_rule")) {
1329         if (argc != 4) {
1330             cli->sendMsg(ResponseCode::CommandSyntaxError,
1331                          "Usage: firewall set_egress_source_rule <192.168.0.1> <allow|deny>",
1332                          false);
1333             return 0;
1334         }
1335 
1336         const char* addr = argv[2];
1337         FirewallRule rule = parseRule(argv[3]);
1338 
1339         int res = gCtls->firewallCtrl.setEgressSourceRule(addr, rule);
1340         return sendGenericOkFail(cli, res);
1341     }
1342 
1343     if (!strcmp(argv[1], "set_egress_dest_rule")) {
1344         if (argc != 5) {
1345             cli->sendMsg(ResponseCode::CommandSyntaxError,
1346                          "Usage: firewall set_egress_dest_rule <192.168.0.1> <80> <allow|deny>",
1347                          false);
1348             return 0;
1349         }
1350 
1351         const char* addr = argv[2];
1352         int port = atoi(argv[3]);
1353         FirewallRule rule = parseRule(argv[4]);
1354 
1355         int res = 0;
1356         res |= gCtls->firewallCtrl.setEgressDestRule(addr, PROTOCOL_TCP, port, rule);
1357         res |= gCtls->firewallCtrl.setEgressDestRule(addr, PROTOCOL_UDP, port, rule);
1358         return sendGenericOkFail(cli, res);
1359     }
1360 
1361     if (!strcmp(argv[1], "set_uid_rule")) {
1362         if (argc != 5) {
1363             cli->sendMsg(ResponseCode::CommandSyntaxError,
1364                          "Usage: firewall set_uid_rule <dozable|standby|none> <1000> <allow|deny>",
1365                          false);
1366             return 0;
1367         }
1368 
1369         ChildChain childChain = parseChildChain(argv[2]);
1370         if (childChain == INVALID_CHAIN) {
1371             cli->sendMsg(ResponseCode::CommandSyntaxError,
1372                          "Invalid chain name. Valid names are: <dozable|standby|none>",
1373                          false);
1374             return 0;
1375         }
1376         int uid = atoi(argv[3]);
1377         FirewallRule rule = parseRule(argv[4]);
1378         int res = gCtls->firewallCtrl.setUidRule(childChain, uid, rule);
1379         return sendGenericOkFail(cli, res);
1380     }
1381 
1382     if (!strcmp(argv[1], "enable_chain")) {
1383         if (argc != 3) {
1384             cli->sendMsg(ResponseCode::CommandSyntaxError,
1385                          "Usage: firewall enable_chain <dozable|standby>",
1386                          false);
1387             return 0;
1388         }
1389 
1390         ChildChain childChain = parseChildChain(argv[2]);
1391         int res = gCtls->firewallCtrl.enableChildChains(childChain, true);
1392         return sendGenericOkFail(cli, res);
1393     }
1394 
1395     if (!strcmp(argv[1], "disable_chain")) {
1396         if (argc != 3) {
1397             cli->sendMsg(ResponseCode::CommandSyntaxError,
1398                          "Usage: firewall disable_chain <dozable|standby>",
1399                          false);
1400             return 0;
1401         }
1402 
1403         ChildChain childChain = parseChildChain(argv[2]);
1404         int res = gCtls->firewallCtrl.enableChildChains(childChain, false);
1405         return sendGenericOkFail(cli, res);
1406     }
1407 
1408     cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown command", false);
1409     return 0;
1410 }
1411 
ClatdCmd()1412 CommandListener::ClatdCmd::ClatdCmd() : NetdCommand("clatd") {
1413 }
1414 
runCommand(SocketClient * cli,int argc,char ** argv)1415 int CommandListener::ClatdCmd::runCommand(SocketClient *cli, int argc,
1416                                                             char **argv) {
1417     int rc = 0;
1418     if (argc < 3) {
1419         cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
1420         return 0;
1421     }
1422 
1423     if (!strcmp(argv[1], "stop")) {
1424         rc = gCtls->clatdCtrl.stopClatd(argv[2]);
1425     } else if (!strcmp(argv[1], "status")) {
1426         char *tmp = NULL;
1427         asprintf(&tmp, "Clatd status: %s", (gCtls->clatdCtrl.isClatdStarted(argv[2]) ?
1428                                             "started" : "stopped"));
1429         cli->sendMsg(ResponseCode::ClatdStatusResult, tmp, false);
1430         free(tmp);
1431         return 0;
1432     } else if (!strcmp(argv[1], "start")) {
1433         rc = gCtls->clatdCtrl.startClatd(argv[2]);
1434     } else {
1435         cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown clatd cmd", false);
1436         return 0;
1437     }
1438 
1439     if (!rc) {
1440         cli->sendMsg(ResponseCode::CommandOkay, "Clatd operation succeeded", false);
1441     } else {
1442         cli->sendMsg(ResponseCode::OperationFailed, "Clatd operation failed", false);
1443     }
1444 
1445     return 0;
1446 }
1447 
StrictCmd()1448 CommandListener::StrictCmd::StrictCmd() :
1449     NetdCommand("strict") {
1450 }
1451 
sendGenericOkFail(SocketClient * cli,int cond)1452 int CommandListener::StrictCmd::sendGenericOkFail(SocketClient *cli, int cond) {
1453     if (!cond) {
1454         cli->sendMsg(ResponseCode::CommandOkay, "Strict command succeeded", false);
1455     } else {
1456         cli->sendMsg(ResponseCode::OperationFailed, "Strict command failed", false);
1457     }
1458     return 0;
1459 }
1460 
parsePenalty(const char * arg)1461 StrictPenalty CommandListener::StrictCmd::parsePenalty(const char* arg) {
1462     if (!strcmp(arg, "reject")) {
1463         return REJECT;
1464     } else if (!strcmp(arg, "log")) {
1465         return LOG;
1466     } else if (!strcmp(arg, "accept")) {
1467         return ACCEPT;
1468     } else {
1469         return INVALID;
1470     }
1471 }
1472 
runCommand(SocketClient * cli,int argc,char ** argv)1473 int CommandListener::StrictCmd::runCommand(SocketClient *cli, int argc,
1474         char **argv) {
1475     if (argc < 2) {
1476         cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing command", false);
1477         return 0;
1478     }
1479 
1480     if (!strcmp(argv[1], "enable")) {
1481         int res = gCtls->strictCtrl.enableStrict();
1482         return sendGenericOkFail(cli, res);
1483     }
1484     if (!strcmp(argv[1], "disable")) {
1485         int res = gCtls->strictCtrl.disableStrict();
1486         return sendGenericOkFail(cli, res);
1487     }
1488 
1489     if (!strcmp(argv[1], "set_uid_cleartext_policy")) {
1490         if (argc != 4) {
1491             cli->sendMsg(ResponseCode::CommandSyntaxError,
1492                          "Usage: strict set_uid_cleartext_policy <uid> <accept|log|reject>",
1493                          false);
1494             return 0;
1495         }
1496 
1497         errno = 0;
1498         unsigned long int uid = strtoul(argv[2], NULL, 0);
1499         if (errno || uid > UID_MAX) {
1500             cli->sendMsg(ResponseCode::CommandSyntaxError, "Invalid UID", false);
1501             return 0;
1502         }
1503 
1504         StrictPenalty penalty = parsePenalty(argv[3]);
1505         if (penalty == INVALID) {
1506             cli->sendMsg(ResponseCode::CommandSyntaxError, "Invalid penalty argument", false);
1507             return 0;
1508         }
1509 
1510         int res = gCtls->strictCtrl.setUidCleartextPenalty((uid_t) uid, penalty);
1511         return sendGenericOkFail(cli, res);
1512     }
1513 
1514     cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown command", false);
1515     return 0;
1516 }
1517 
NetworkCommand()1518 CommandListener::NetworkCommand::NetworkCommand() : NetdCommand("network") {
1519 }
1520 
syntaxError(SocketClient * client,const char * message)1521 int CommandListener::NetworkCommand::syntaxError(SocketClient* client, const char* message) {
1522     client->sendMsg(ResponseCode::CommandSyntaxError, message, false);
1523     return 0;
1524 }
1525 
operationError(SocketClient * client,const char * message,int ret)1526 int CommandListener::NetworkCommand::operationError(SocketClient* client, const char* message,
1527                                                     int ret) {
1528     errno = -ret;
1529     client->sendMsg(ResponseCode::OperationFailed, message, true);
1530     return 0;
1531 }
1532 
success(SocketClient * client)1533 int CommandListener::NetworkCommand::success(SocketClient* client) {
1534     client->sendMsg(ResponseCode::CommandOkay, "success", false);
1535     return 0;
1536 }
1537 
runCommand(SocketClient * client,int argc,char ** argv)1538 int CommandListener::NetworkCommand::runCommand(SocketClient* client, int argc, char** argv) {
1539     if (argc < 2) {
1540         return syntaxError(client, "Missing argument");
1541     }
1542 
1543     //    0      1      2      3      4       5         6            7           8
1544     // network route [legacy <uid>]  add   <netId> <interface> <destination> [nexthop]
1545     // network route [legacy <uid>] remove <netId> <interface> <destination> [nexthop]
1546     //
1547     // nexthop may be either an IPv4/IPv6 address or one of "unreachable" or "throw".
1548     if (!strcmp(argv[1], "route")) {
1549         if (argc < 6 || argc > 9) {
1550             return syntaxError(client, "Incorrect number of arguments");
1551         }
1552 
1553         int nextArg = 2;
1554         bool legacy = false;
1555         uid_t uid = 0;
1556         if (!strcmp(argv[nextArg], "legacy")) {
1557             ++nextArg;
1558             legacy = true;
1559             uid = strtoul(argv[nextArg++], NULL, 0);
1560         }
1561 
1562         bool add = false;
1563         if (!strcmp(argv[nextArg], "add")) {
1564             add = true;
1565         } else if (strcmp(argv[nextArg], "remove")) {
1566             return syntaxError(client, "Unknown argument");
1567         }
1568         ++nextArg;
1569 
1570         if (argc < nextArg + 3 || argc > nextArg + 4) {
1571             return syntaxError(client, "Incorrect number of arguments");
1572         }
1573 
1574         unsigned netId = stringToNetId(argv[nextArg++]);
1575         const char* interface = argv[nextArg++];
1576         const char* destination = argv[nextArg++];
1577         const char* nexthop = argc > nextArg ? argv[nextArg] : NULL;
1578 
1579         int ret;
1580         if (add) {
1581             ret = gCtls->netCtrl.addRoute(netId, interface, destination, nexthop, legacy, uid);
1582         } else {
1583             ret = gCtls->netCtrl.removeRoute(netId, interface, destination, nexthop, legacy, uid);
1584         }
1585         if (ret) {
1586             return operationError(client, add ? "addRoute() failed" : "removeRoute() failed", ret);
1587         }
1588 
1589         return success(client);
1590     }
1591 
1592     //    0        1       2       3         4
1593     // network interface  add   <netId> <interface>
1594     // network interface remove <netId> <interface>
1595     if (!strcmp(argv[1], "interface")) {
1596         if (argc != 5) {
1597             return syntaxError(client, "Missing argument");
1598         }
1599         unsigned netId = stringToNetId(argv[3]);
1600         if (!strcmp(argv[2], "add")) {
1601             if (int ret = gCtls->netCtrl.addInterfaceToNetwork(netId, argv[4])) {
1602                 return operationError(client, "addInterfaceToNetwork() failed", ret);
1603             }
1604         } else if (!strcmp(argv[2], "remove")) {
1605             if (int ret = gCtls->netCtrl.removeInterfaceFromNetwork(netId, argv[4])) {
1606                 return operationError(client, "removeInterfaceFromNetwork() failed", ret);
1607             }
1608         } else {
1609             return syntaxError(client, "Unknown argument");
1610         }
1611         return success(client);
1612     }
1613 
1614     //    0      1       2         3
1615     // network create <netId> [permission]
1616     //
1617     //    0      1       2     3     4        5
1618     // network create <netId> vpn <hasDns> <secure>
1619     if (!strcmp(argv[1], "create")) {
1620         if (argc < 3) {
1621             return syntaxError(client, "Missing argument");
1622         }
1623         unsigned netId = stringToNetId(argv[2]);
1624         if (argc == 6 && !strcmp(argv[3], "vpn")) {
1625             bool hasDns = atoi(argv[4]);
1626             bool secure = atoi(argv[5]);
1627             if (int ret = gCtls->netCtrl.createVirtualNetwork(netId, hasDns, secure)) {
1628                 return operationError(client, "createVirtualNetwork() failed", ret);
1629             }
1630         } else if (argc > 4) {
1631             return syntaxError(client, "Unknown trailing argument(s)");
1632         } else {
1633             Permission permission = PERMISSION_NONE;
1634             if (argc == 4) {
1635                 permission = stringToPermission(argv[3]);
1636                 if (permission == PERMISSION_NONE) {
1637                     return syntaxError(client, "Unknown permission");
1638                 }
1639             }
1640             if (int ret = gCtls->netCtrl.createPhysicalNetwork(netId, permission)) {
1641                 return operationError(client, "createPhysicalNetwork() failed", ret);
1642             }
1643         }
1644         return success(client);
1645     }
1646 
1647     //    0       1       2
1648     // network destroy <netId>
1649     if (!strcmp(argv[1], "destroy")) {
1650         if (argc != 3) {
1651             return syntaxError(client, "Incorrect number of arguments");
1652         }
1653         unsigned netId = stringToNetId(argv[2]);
1654         if (int ret = gCtls->netCtrl.destroyNetwork(netId)) {
1655             return operationError(client, "destroyNetwork() failed", ret);
1656         }
1657         return success(client);
1658     }
1659 
1660     //    0       1      2      3
1661     // network default  set  <netId>
1662     // network default clear
1663     if (!strcmp(argv[1], "default")) {
1664         if (argc < 3) {
1665             return syntaxError(client, "Missing argument");
1666         }
1667         unsigned netId = NETID_UNSET;
1668         if (!strcmp(argv[2], "set")) {
1669             if (argc < 4) {
1670                 return syntaxError(client, "Missing netId");
1671             }
1672             netId = stringToNetId(argv[3]);
1673         } else if (strcmp(argv[2], "clear")) {
1674             return syntaxError(client, "Unknown argument");
1675         }
1676         if (int ret = gCtls->netCtrl.setDefaultNetwork(netId)) {
1677             return operationError(client, "setDefaultNetwork() failed", ret);
1678         }
1679         return success(client);
1680     }
1681 
1682     //    0        1         2      3        4          5
1683     // network permission   user   set  <permission>  <uid> ...
1684     // network permission   user  clear    <uid> ...
1685     // network permission network  set  <permission> <netId> ...
1686     // network permission network clear   <netId> ...
1687     if (!strcmp(argv[1], "permission")) {
1688         if (argc < 5) {
1689             return syntaxError(client, "Missing argument");
1690         }
1691         int nextArg = 4;
1692         Permission permission = PERMISSION_NONE;
1693         if (!strcmp(argv[3], "set")) {
1694             permission = stringToPermission(argv[4]);
1695             if (permission == PERMISSION_NONE) {
1696                 return syntaxError(client, "Unknown permission");
1697             }
1698             nextArg = 5;
1699         } else if (strcmp(argv[3], "clear")) {
1700             return syntaxError(client, "Unknown argument");
1701         }
1702         if (nextArg == argc) {
1703             return syntaxError(client, "Missing id");
1704         }
1705 
1706         bool userPermissions = !strcmp(argv[2], "user");
1707         bool networkPermissions = !strcmp(argv[2], "network");
1708         if (!userPermissions && !networkPermissions) {
1709             return syntaxError(client, "Unknown argument");
1710         }
1711 
1712         std::vector<unsigned> ids;
1713         for (; nextArg < argc; ++nextArg) {
1714             if (userPermissions) {
1715                 char* endPtr;
1716                 unsigned id = strtoul(argv[nextArg], &endPtr, 0);
1717                 if (!*argv[nextArg] || *endPtr) {
1718                     return syntaxError(client, "Invalid id");
1719                 }
1720                 ids.push_back(id);
1721             } else {
1722                 // networkPermissions
1723                 ids.push_back(stringToNetId(argv[nextArg]));
1724             }
1725         }
1726         if (userPermissions) {
1727             gCtls->netCtrl.setPermissionForUsers(permission, ids);
1728         } else {
1729             // networkPermissions
1730             if (int ret = gCtls->netCtrl.setPermissionForNetworks(permission, ids)) {
1731                 return operationError(client, "setPermissionForNetworks() failed", ret);
1732             }
1733         }
1734 
1735         return success(client);
1736     }
1737 
1738     //    0      1     2       3           4
1739     // network users  add   <netId> [<uid>[-<uid>]] ...
1740     // network users remove <netId> [<uid>[-<uid>]] ...
1741     if (!strcmp(argv[1], "users")) {
1742         if (argc < 4) {
1743             return syntaxError(client, "Missing argument");
1744         }
1745         unsigned netId = stringToNetId(argv[3]);
1746         UidRanges uidRanges;
1747         if (!uidRanges.parseFrom(argc - 4, argv + 4)) {
1748             return syntaxError(client, "Invalid UIDs");
1749         }
1750         if (!strcmp(argv[2], "add")) {
1751             if (int ret = gCtls->netCtrl.addUsersToNetwork(netId, uidRanges)) {
1752                 return operationError(client, "addUsersToNetwork() failed", ret);
1753             }
1754         } else if (!strcmp(argv[2], "remove")) {
1755             if (int ret = gCtls->netCtrl.removeUsersFromNetwork(netId, uidRanges)) {
1756                 return operationError(client, "removeUsersFromNetwork() failed", ret);
1757             }
1758         } else {
1759             return syntaxError(client, "Unknown argument");
1760         }
1761         return success(client);
1762     }
1763 
1764     //    0       1      2     3
1765     // network protect allow <uid> ...
1766     // network protect  deny <uid> ...
1767     if (!strcmp(argv[1], "protect")) {
1768         if (argc < 4) {
1769             return syntaxError(client, "Missing argument");
1770         }
1771         std::vector<uid_t> uids;
1772         for (int i = 3; i < argc; ++i) {
1773             uids.push_back(strtoul(argv[i], NULL, 0));
1774         }
1775         if (!strcmp(argv[2], "allow")) {
1776             gCtls->netCtrl.allowProtect(uids);
1777         } else if (!strcmp(argv[2], "deny")) {
1778             gCtls->netCtrl.denyProtect(uids);
1779         } else {
1780             return syntaxError(client, "Unknown argument");
1781         }
1782         return success(client);
1783     }
1784 
1785     return syntaxError(client, "Unknown argument");
1786 }
1787