2 * Copyright (C) 2008 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 // #define LOG_NDEBUG 0
20 #include <sys/socket.h>
21 #include <sys/types.h>
22 #include <netinet/in.h>
23 #include <arpa/inet.h>
28 #include <resolv_netid.h>
30 #define __STDC_FORMAT_MACROS 1
33 #define LOG_TAG "CommandListener"
35 #include <cutils/log.h>
36 #include <netutils/ifc.h>
37 #include <sysutils/SocketClient.h>
39 #include "CommandListener.h"
40 #include "ResponseCode.h"
41 #include "BandwidthController.h"
42 #include "IdletimerController.h"
43 #include "SecondaryTableController.h"
44 #include "oem_iptables_hook.h"
45 #include "NetdConstants.h"
46 #include "FirewallController.h"
47 #include "RouteController.h"
48 #include "UidRanges.h"
55 Permission stringToPermission(const char* arg) {
56 if (!strcmp(arg, "android.permission.CHANGE_NETWORK_STATE")) {
57 return PERMISSION_NETWORK;
59 if (!strcmp(arg, "android.permission.CONNECTIVITY_INTERNAL")) {
60 return PERMISSION_SYSTEM;
62 return PERMISSION_NONE;
67 NetworkController *CommandListener::sNetCtrl = NULL;
68 TetherController *CommandListener::sTetherCtrl = NULL;
69 NatController *CommandListener::sNatCtrl = NULL;
70 PppController *CommandListener::sPppCtrl = NULL;
71 SoftapController *CommandListener::sSoftapCtrl = NULL;
72 BandwidthController * CommandListener::sBandwidthCtrl = NULL;
73 IdletimerController * CommandListener::sIdletimerCtrl = NULL;
74 InterfaceController *CommandListener::sInterfaceCtrl = NULL;
75 ResolverController *CommandListener::sResolverCtrl = NULL;
76 SecondaryTableController *CommandListener::sSecondaryTableCtrl = NULL;
77 FirewallController *CommandListener::sFirewallCtrl = NULL;
78 ClatdController *CommandListener::sClatdCtrl = NULL;
81 * List of module chains to be created, along with explicit ordering. ORDERING
82 * IS CRITICAL, AND SHOULD BE TRIPLE-CHECKED WITH EACH CHANGE.
84 static const char* FILTER_INPUT[] = {
85 // Bandwidth should always be early in input chain, to make sure we
86 // correctly count incoming traffic against data plan.
87 BandwidthController::LOCAL_INPUT,
88 FirewallController::LOCAL_INPUT,
92 static const char* FILTER_FORWARD[] = {
93 OEM_IPTABLES_FILTER_FORWARD,
94 FirewallController::LOCAL_FORWARD,
95 BandwidthController::LOCAL_FORWARD,
96 NatController::LOCAL_FORWARD,
100 static const char* FILTER_OUTPUT[] = {
101 OEM_IPTABLES_FILTER_OUTPUT,
102 FirewallController::LOCAL_OUTPUT,
103 BandwidthController::LOCAL_OUTPUT,
107 static const char* RAW_PREROUTING[] = {
108 BandwidthController::LOCAL_RAW_PREROUTING,
109 IdletimerController::LOCAL_RAW_PREROUTING,
113 static const char* MANGLE_POSTROUTING[] = {
114 BandwidthController::LOCAL_MANGLE_POSTROUTING,
115 IdletimerController::LOCAL_MANGLE_POSTROUTING,
116 SecondaryTableController::LOCAL_MANGLE_POSTROUTING,
120 static const char* MANGLE_OUTPUT[] = {
121 SecondaryTableController::LOCAL_MANGLE_OUTPUT,
125 static const char* NAT_PREROUTING[] = {
126 OEM_IPTABLES_NAT_PREROUTING,
130 static const char* NAT_POSTROUTING[] = {
131 NatController::LOCAL_NAT_POSTROUTING,
132 SecondaryTableController::LOCAL_NAT_POSTROUTING,
136 static void createChildChains(IptablesTarget target, const char* table, const char* parentChain,
137 const char** childChains) {
138 const char** childChain = childChains;
140 // Order is important:
141 // -D to delete any pre-existing jump rule (removes references
142 // that would prevent -X from working)
143 // -F to flush any existing chain
144 // -X to delete any existing chain
145 // -N to create the chain
146 // -A to append the chain to parent
148 execIptablesSilently(target, "-t", table, "-D", parentChain, "-j", *childChain, NULL);
149 execIptablesSilently(target, "-t", table, "-F", *childChain, NULL);
150 execIptablesSilently(target, "-t", table, "-X", *childChain, NULL);
151 execIptables(target, "-t", table, "-N", *childChain, NULL);
152 execIptables(target, "-t", table, "-A", parentChain, "-j", *childChain, NULL);
153 } while (*(++childChain) != NULL);
156 CommandListener::CommandListener() :
157 FrameworkListener("netd", true) {
158 registerCmd(new InterfaceCmd());
159 registerCmd(new IpFwdCmd());
160 registerCmd(new TetherCmd());
161 registerCmd(new NatCmd());
162 registerCmd(new ListTtysCmd());
163 registerCmd(new PppdCmd());
164 registerCmd(new SoftapCmd());
165 registerCmd(new BandwidthControlCmd());
166 registerCmd(new IdletimerControlCmd());
167 registerCmd(new ResolverCmd());
168 registerCmd(new FirewallCmd());
169 registerCmd(new ClatdCmd());
170 registerCmd(new NetworkCommand());
173 sNetCtrl = new NetworkController();
174 if (!sSecondaryTableCtrl)
175 sSecondaryTableCtrl = new SecondaryTableController(sNetCtrl);
177 sTetherCtrl = new TetherController(sNetCtrl);
179 sNatCtrl = new NatController(sNetCtrl);
181 sPppCtrl = new PppController();
183 sSoftapCtrl = new SoftapController();
185 sBandwidthCtrl = new BandwidthController();
187 sIdletimerCtrl = new IdletimerController();
189 sResolverCtrl = new ResolverController();
191 sFirewallCtrl = new FirewallController();
193 sInterfaceCtrl = new InterfaceController();
195 sClatdCtrl = new ClatdController(sNetCtrl);
198 * This is the only time we touch top-level chains in iptables; controllers
199 * should only mutate rules inside of their children chains, as created by
200 * the constants above.
202 * Modules should never ACCEPT packets (except in well-justified cases);
203 * they should instead defer to any remaining modules using RETURN, or
204 * otherwise DROP/REJECT.
207 // Create chains for children modules
208 createChildChains(V4V6, "filter", "INPUT", FILTER_INPUT);
209 createChildChains(V4V6, "filter", "FORWARD", FILTER_FORWARD);
210 createChildChains(V4V6, "filter", "OUTPUT", FILTER_OUTPUT);
211 createChildChains(V4V6, "raw", "PREROUTING", RAW_PREROUTING);
212 createChildChains(V4V6, "mangle", "POSTROUTING", MANGLE_POSTROUTING);
213 createChildChains(V4V6, "mangle", "OUTPUT", MANGLE_OUTPUT);
214 createChildChains(V4, "nat", "PREROUTING", NAT_PREROUTING);
215 createChildChains(V4, "nat", "POSTROUTING", NAT_POSTROUTING);
217 // Let each module setup their child chains
218 setupOemIptablesHook();
220 /* When enabled, DROPs all packets except those matching rules. */
221 sFirewallCtrl->setupIptablesHooks();
223 /* Does DROPs in FORWARD by default */
224 sNatCtrl->setupIptablesHooks();
226 * Does REJECT in INPUT, OUTPUT. Does counting also.
227 * No DROP/REJECT allowed later in netfilter-flow hook order.
229 sBandwidthCtrl->setupIptablesHooks();
231 * Counts in nat: PREROUTING, POSTROUTING.
232 * No DROP/REJECT allowed later in netfilter-flow hook order.
234 sIdletimerCtrl->setupIptablesHooks();
236 sBandwidthCtrl->enableBandwidthControl(false);
238 sSecondaryTableCtrl->setupIptablesHooks();
240 if (int ret = RouteController::Init()) {
241 ALOGE("failed to initialize RouteController (%s)", strerror(-ret));
245 CommandListener::InterfaceCmd::InterfaceCmd() :
246 NetdCommand("interface") {
249 int CommandListener::InterfaceCmd::runCommand(SocketClient *cli,
250 int argc, char **argv) {
252 cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
256 if (!strcmp(argv[1], "list")) {
260 if (!(d = opendir("/sys/class/net"))) {
261 cli->sendMsg(ResponseCode::OperationFailed, "Failed to open sysfs dir", true);
265 while((de = readdir(d))) {
266 if (de->d_name[0] == '.')
268 cli->sendMsg(ResponseCode::InterfaceListResult, de->d_name, false);
271 cli->sendMsg(ResponseCode::CommandOkay, "Interface list completed", false);
273 } else if (!strcmp(argv[1], "driver")) {
278 cli->sendMsg(ResponseCode::CommandSyntaxError,
279 "Usage: interface driver <interface> <cmd> <args>", false);
282 rc = sInterfaceCtrl->interfaceCommand(argc, argv, &rbuf);
284 cli->sendMsg(ResponseCode::OperationFailed, "Failed to execute command", true);
286 cli->sendMsg(ResponseCode::CommandOkay, rbuf, false);
291 * These commands take a minimum of 3 arguments
294 cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
299 // interface route add/remove iface default/secondary dest prefix gateway
300 // interface fwmark rule add/remove iface
301 // interface fwmark route add/remove iface dest prefix
302 // interface fwmark exempt add/remove dest
303 // interface fwmark get protect
304 // interface fwmark get mark uid
305 if (!strcmp(argv[1], "fwmark")) {
306 if (!strcmp(argv[2], "rule")) {
308 cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
311 if (!strcmp(argv[3], "add")) {
312 if (!sSecondaryTableCtrl->addFwmarkRule(argv[4])) {
313 cli->sendMsg(ResponseCode::CommandOkay,
314 "Fwmark rule successfully added", false);
316 cli->sendMsg(ResponseCode::OperationFailed, "Failed to add fwmark rule",
319 } else if (!strcmp(argv[3], "remove")) {
320 if (!sSecondaryTableCtrl->removeFwmarkRule(argv[4])) {
321 cli->sendMsg(ResponseCode::CommandOkay,
322 "Fwmark rule successfully removed", false);
324 cli->sendMsg(ResponseCode::OperationFailed,
325 "Failed to remove fwmark rule", true);
328 cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown fwmark rule cmd",
332 } else if (!strcmp(argv[2], "route")) {
334 cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
337 if (!strcmp(argv[3], "add")) {
338 if (!sSecondaryTableCtrl->addFwmarkRoute(argv[4], argv[5], atoi(argv[6]))) {
339 cli->sendMsg(ResponseCode::CommandOkay,
340 "Fwmark route successfully added", false);
342 cli->sendMsg(ResponseCode::OperationFailed,
343 "Failed to add fwmark route", true);
345 } else if (!strcmp(argv[3], "remove")) {
346 if (!sSecondaryTableCtrl->removeFwmarkRoute(argv[4], argv[5],
348 cli->sendMsg(ResponseCode::CommandOkay,
349 "Fwmark route successfully removed", false);
351 cli->sendMsg(ResponseCode::OperationFailed,
352 "Failed to remove fwmark route", true);
355 cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown fwmark route cmd",
359 } else if (!strcmp(argv[2], "exempt")) {
361 cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
364 if (!strcmp(argv[3], "add")) {
365 if (!sSecondaryTableCtrl->addHostExemption(argv[4])) {
366 cli->sendMsg(ResponseCode::CommandOkay, "exemption rule successfully added",
369 cli->sendMsg(ResponseCode::OperationFailed, "Failed to add exemption rule",
372 } else if (!strcmp(argv[3], "remove")) {
373 if (!sSecondaryTableCtrl->removeHostExemption(argv[4])) {
374 cli->sendMsg(ResponseCode::CommandOkay,
375 "exemption rule successfully removed", false);
377 cli->sendMsg(ResponseCode::OperationFailed,
378 "Failed to remove exemption rule", true);
381 cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown exemption cmd", false);
384 } else if (!strcmp(argv[2], "get")) {
386 cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
389 if (!strcmp(argv[3], "protect")) {
390 sSecondaryTableCtrl->getProtectMark(cli);
392 } else if (!strcmp(argv[3], "mark")) {
394 cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
397 sSecondaryTableCtrl->getUidMark(cli, atoi(argv[4]));
400 cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown fwmark get cmd", false);
404 cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown fwmark cmd", false);
408 if (!strcmp(argv[1], "route")) {
409 int prefix_length = 0;
411 cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
414 if (sscanf(argv[6], "%d", &prefix_length) != 1) {
415 cli->sendMsg(ResponseCode::CommandParameterError, "Invalid route prefix", false);
418 if (!strcmp(argv[2], "add")) {
419 if (!strcmp(argv[4], "default")) {
420 if (ifc_add_route(argv[3], argv[5], prefix_length, argv[7])) {
421 cli->sendMsg(ResponseCode::OperationFailed,
422 "Failed to add route to default table", true);
424 cli->sendMsg(ResponseCode::CommandOkay,
425 "Route added to default table", false);
427 } else if (!strcmp(argv[4], "secondary")) {
428 return sSecondaryTableCtrl->addRoute(cli, argv[3], argv[5],
429 prefix_length, argv[7]);
431 cli->sendMsg(ResponseCode::CommandParameterError,
432 "Invalid route type, expecting 'default' or 'secondary'", false);
435 } else if (!strcmp(argv[2], "remove")) {
436 if (!strcmp(argv[4], "default")) {
437 if (ifc_remove_route(argv[3], argv[5], prefix_length, argv[7])) {
438 cli->sendMsg(ResponseCode::OperationFailed,
439 "Failed to remove route from default table", true);
441 cli->sendMsg(ResponseCode::CommandOkay,
442 "Route removed from default table", false);
444 } else if (!strcmp(argv[4], "secondary")) {
445 return sSecondaryTableCtrl->removeRoute(cli, argv[3], argv[5],
446 prefix_length, argv[7]);
448 cli->sendMsg(ResponseCode::CommandParameterError,
449 "Invalid route type, expecting 'default' or 'secondary'", false);
453 cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown interface cmd", false);
458 if (!strcmp(argv[1], "getcfg")) {
461 unsigned char hwaddr[6];
465 memset(hwaddr, 0, sizeof(hwaddr));
467 if (ifc_get_info(argv[2], &addr.s_addr, &prefixLength, &flags)) {
468 cli->sendMsg(ResponseCode::OperationFailed, "Interface not found", true);
473 if (ifc_get_hwaddr(argv[2], (void *) hwaddr)) {
474 ALOGW("Failed to retrieve HW addr for %s (%s)", argv[2], strerror(errno));
477 char *addr_s = strdup(inet_ntoa(addr));
478 const char *updown, *brdcst, *loopbk, *ppp, *running, *multi;
480 updown = (flags & IFF_UP) ? "up" : "down";
481 brdcst = (flags & IFF_BROADCAST) ? " broadcast" : "";
482 loopbk = (flags & IFF_LOOPBACK) ? " loopback" : "";
483 ppp = (flags & IFF_POINTOPOINT) ? " point-to-point" : "";
484 running = (flags & IFF_RUNNING) ? " running" : "";
485 multi = (flags & IFF_MULTICAST) ? " multicast" : "";
489 asprintf(&flag_s, "%s%s%s%s%s%s", updown, brdcst, loopbk, ppp, running, multi);
492 asprintf(&msg, "%.2x:%.2x:%.2x:%.2x:%.2x:%.2x %s %d %s",
493 hwaddr[0], hwaddr[1], hwaddr[2], hwaddr[3], hwaddr[4], hwaddr[5],
494 addr_s, prefixLength, flag_s);
496 cli->sendMsg(ResponseCode::InterfaceGetCfgResult, msg, false);
504 } else if (!strcmp(argv[1], "setcfg")) {
505 // arglist: iface [addr prefixLength] flags
507 cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
510 ALOGD("Setting iface cfg");
517 if (!inet_aton(argv[3], &addr)) {
518 // Handle flags only case
521 if (ifc_set_addr(argv[2], addr.s_addr)) {
522 cli->sendMsg(ResponseCode::OperationFailed, "Failed to set address", true);
527 // Set prefix length on a non zero address
528 if (addr.s_addr != 0 && ifc_set_prefixLength(argv[2], atoi(argv[4]))) {
529 cli->sendMsg(ResponseCode::OperationFailed, "Failed to set prefixLength", true);
536 for (int i = index; i < argc; i++) {
537 char *flag = argv[i];
538 if (!strcmp(flag, "up")) {
539 ALOGD("Trying to bring up %s", argv[2]);
540 if (ifc_up(argv[2])) {
541 ALOGE("Error upping interface");
542 cli->sendMsg(ResponseCode::OperationFailed, "Failed to up interface", true);
546 } else if (!strcmp(flag, "down")) {
547 ALOGD("Trying to bring down %s", argv[2]);
548 if (ifc_down(argv[2])) {
549 ALOGE("Error downing interface");
550 cli->sendMsg(ResponseCode::OperationFailed, "Failed to down interface", true);
554 } else if (!strcmp(flag, "broadcast")) {
556 } else if (!strcmp(flag, "multicast")) {
558 } else if (!strcmp(flag, "running")) {
560 } else if (!strcmp(flag, "loopback")) {
562 } else if (!strcmp(flag, "point-to-point")) {
565 cli->sendMsg(ResponseCode::CommandParameterError, "Flag unsupported", false);
571 cli->sendMsg(ResponseCode::CommandOkay, "Interface configuration set", false);
574 } else if (!strcmp(argv[1], "clearaddrs")) {
576 ALOGD("Clearing all IP addresses on %s", argv[2]);
578 ifc_clear_addresses(argv[2]);
580 cli->sendMsg(ResponseCode::CommandOkay, "Interface IP addresses cleared", false);
582 } else if (!strcmp(argv[1], "ipv6privacyextensions")) {
584 cli->sendMsg(ResponseCode::CommandSyntaxError,
585 "Usage: interface ipv6privacyextensions <interface> <enable|disable>",
589 int enable = !strncmp(argv[3], "enable", 7);
590 if (sInterfaceCtrl->setIPv6PrivacyExtensions(argv[2], enable) == 0) {
591 cli->sendMsg(ResponseCode::CommandOkay, "IPv6 privacy extensions changed", false);
593 cli->sendMsg(ResponseCode::OperationFailed,
594 "Failed to set ipv6 privacy extensions", true);
597 } else if (!strcmp(argv[1], "ipv6")) {
599 cli->sendMsg(ResponseCode::CommandSyntaxError,
600 "Usage: interface ipv6 <interface> <enable|disable>",
605 int enable = !strncmp(argv[3], "enable", 7);
606 if (sInterfaceCtrl->setEnableIPv6(argv[2], enable) == 0) {
607 cli->sendMsg(ResponseCode::CommandOkay, "IPv6 state changed", false);
609 cli->sendMsg(ResponseCode::OperationFailed,
610 "Failed to change IPv6 state", true);
613 } else if (!strcmp(argv[1], "getmtu")) {
616 if (sInterfaceCtrl->getMtu(argv[2], &mtu) == 0) {
617 asprintf(&msg, "MTU = %d", mtu);
618 cli->sendMsg(ResponseCode::InterfaceGetMtuResult, msg, false);
621 cli->sendMsg(ResponseCode::OperationFailed,
622 "Failed to get MTU", true);
625 } else if (!strcmp(argv[1], "setmtu")) {
627 cli->sendMsg(ResponseCode::CommandSyntaxError,
628 "Usage: interface setmtu <interface> <val>", false);
631 if (sInterfaceCtrl->setMtu(argv[2], argv[3]) == 0) {
632 cli->sendMsg(ResponseCode::CommandOkay, "MTU changed", false);
634 cli->sendMsg(ResponseCode::OperationFailed,
635 "Failed to get MTU", true);
639 cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown interface cmd", false);
647 CommandListener::ListTtysCmd::ListTtysCmd() :
648 NetdCommand("list_ttys") {
651 int CommandListener::ListTtysCmd::runCommand(SocketClient *cli,
652 int /* argc */, char ** /* argv */) {
653 TtyCollection *tlist = sPppCtrl->getTtyList();
654 TtyCollection::iterator it;
656 for (it = tlist->begin(); it != tlist->end(); ++it) {
657 cli->sendMsg(ResponseCode::TtyListResult, *it, false);
660 cli->sendMsg(ResponseCode::CommandOkay, "Ttys listed.", false);
664 CommandListener::IpFwdCmd::IpFwdCmd() :
665 NetdCommand("ipfwd") {
668 int CommandListener::IpFwdCmd::runCommand(SocketClient *cli,
669 int argc, char **argv) {
673 cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
677 if (!strcmp(argv[1], "status")) {
680 asprintf(&tmp, "Forwarding %s", (sTetherCtrl->getIpFwdEnabled() ? "enabled" : "disabled"));
681 cli->sendMsg(ResponseCode::IpFwdStatusResult, tmp, false);
684 } else if (!strcmp(argv[1], "enable")) {
685 rc = sTetherCtrl->setIpFwdEnabled(true);
686 } else if (!strcmp(argv[1], "disable")) {
687 rc = sTetherCtrl->setIpFwdEnabled(false);
689 cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown ipfwd cmd", false);
694 cli->sendMsg(ResponseCode::CommandOkay, "ipfwd operation succeeded", false);
696 cli->sendMsg(ResponseCode::OperationFailed, "ipfwd operation failed", true);
702 CommandListener::TetherCmd::TetherCmd() :
703 NetdCommand("tether") {
706 int CommandListener::TetherCmd::runCommand(SocketClient *cli,
707 int argc, char **argv) {
711 cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
715 if (!strcmp(argv[1], "stop")) {
716 rc = sTetherCtrl->stopTethering();
717 } else if (!strcmp(argv[1], "status")) {
720 asprintf(&tmp, "Tethering services %s",
721 (sTetherCtrl->isTetheringStarted() ? "started" : "stopped"));
722 cli->sendMsg(ResponseCode::TetherStatusResult, tmp, false);
725 } else if (argc == 3) {
726 if (!strcmp(argv[1], "interface") && !strcmp(argv[2], "list")) {
727 InterfaceCollection *ilist = sTetherCtrl->getTetheredInterfaceList();
728 InterfaceCollection::iterator it;
729 for (it = ilist->begin(); it != ilist->end(); ++it) {
730 cli->sendMsg(ResponseCode::TetherInterfaceListResult, *it, false);
732 } else if (!strcmp(argv[1], "dns") && !strcmp(argv[2], "list")) {
733 NetAddressCollection *dlist = sTetherCtrl->getDnsForwarders();
734 NetAddressCollection::iterator it;
736 for (it = dlist->begin(); it != dlist->end(); ++it) {
737 cli->sendMsg(ResponseCode::TetherDnsFwdTgtListResult, inet_ntoa(*it), false);
742 * These commands take a minimum of 4 arguments
745 cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
749 if (!strcmp(argv[1], "start")) {
751 cli->sendMsg(ResponseCode::CommandSyntaxError, "Bad number of arguments", false);
755 int num_addrs = argc - 2;
758 in_addr *addrs = (in_addr *)malloc(sizeof(in_addr) * num_addrs);
759 while (array_index < num_addrs) {
760 if (!inet_aton(argv[arg_index++], &(addrs[array_index++]))) {
761 cli->sendMsg(ResponseCode::CommandParameterError, "Invalid address", false);
766 rc = sTetherCtrl->startTethering(num_addrs, addrs);
768 } else if (!strcmp(argv[1], "interface")) {
769 if (!strcmp(argv[2], "add")) {
770 rc = sTetherCtrl->tetherInterface(argv[3]);
771 } else if (!strcmp(argv[2], "remove")) {
772 rc = sTetherCtrl->untetherInterface(argv[3]);
773 /* else if (!strcmp(argv[2], "list")) handled above */
775 cli->sendMsg(ResponseCode::CommandParameterError,
776 "Unknown tether interface operation", false);
779 } else if (!strcmp(argv[1], "dns")) {
780 if (!strcmp(argv[2], "set")) {
781 rc = sTetherCtrl->setDnsForwarders(&argv[3], argc - 3);
782 /* else if (!strcmp(argv[2], "list")) handled above */
784 cli->sendMsg(ResponseCode::CommandParameterError,
785 "Unknown tether interface operation", false);
789 cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown tether cmd", false);
795 cli->sendMsg(ResponseCode::CommandOkay, "Tether operation succeeded", false);
797 cli->sendMsg(ResponseCode::OperationFailed, "Tether operation failed", true);
803 CommandListener::NatCmd::NatCmd() :
807 int CommandListener::NatCmd::runCommand(SocketClient *cli,
808 int argc, char **argv) {
812 cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
816 if (!strcmp(argv[1], "enable")) {
817 rc = sNatCtrl->enableNat(argc, argv);
819 /* Ignore ifaces for now. */
820 rc = sBandwidthCtrl->setGlobalAlertInForwardChain();
822 } else if (!strcmp(argv[1], "disable")) {
823 /* Ignore ifaces for now. */
824 rc = sBandwidthCtrl->removeGlobalAlertInForwardChain();
825 rc |= sNatCtrl->disableNat(argc, argv);
827 cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown nat cmd", false);
832 cli->sendMsg(ResponseCode::CommandOkay, "Nat operation succeeded", false);
834 cli->sendMsg(ResponseCode::OperationFailed, "Nat operation failed", true);
840 CommandListener::PppdCmd::PppdCmd() :
841 NetdCommand("pppd") {
844 int CommandListener::PppdCmd::runCommand(SocketClient *cli,
845 int argc, char **argv) {
849 cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
853 if (!strcmp(argv[1], "attach")) {
854 struct in_addr l, r, dns1, dns2;
856 memset(&dns1, 0, sizeof(struct in_addr));
857 memset(&dns2, 0, sizeof(struct in_addr));
859 if (!inet_aton(argv[3], &l)) {
860 cli->sendMsg(ResponseCode::CommandParameterError, "Invalid local address", false);
863 if (!inet_aton(argv[4], &r)) {
864 cli->sendMsg(ResponseCode::CommandParameterError, "Invalid remote address", false);
867 if ((argc > 3) && (!inet_aton(argv[5], &dns1))) {
868 cli->sendMsg(ResponseCode::CommandParameterError, "Invalid dns1 address", false);
871 if ((argc > 4) && (!inet_aton(argv[6], &dns2))) {
872 cli->sendMsg(ResponseCode::CommandParameterError, "Invalid dns2 address", false);
875 rc = sPppCtrl->attachPppd(argv[2], l, r, dns1, dns2);
876 } else if (!strcmp(argv[1], "detach")) {
877 rc = sPppCtrl->detachPppd(argv[2]);
879 cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown pppd cmd", false);
884 cli->sendMsg(ResponseCode::CommandOkay, "Pppd operation succeeded", false);
886 cli->sendMsg(ResponseCode::OperationFailed, "Pppd operation failed", true);
892 CommandListener::SoftapCmd::SoftapCmd() :
893 NetdCommand("softap") {
896 int CommandListener::SoftapCmd::runCommand(SocketClient *cli,
897 int argc, char **argv) {
898 int rc = ResponseCode::SoftapStatusResult;
901 if (sSoftapCtrl == NULL) {
902 cli->sendMsg(ResponseCode::ServiceStartFailed, "SoftAP is not available", false);
906 cli->sendMsg(ResponseCode::CommandSyntaxError,
907 "Missing argument in a SoftAP command", false);
911 if (!strcmp(argv[1], "startap")) {
912 rc = sSoftapCtrl->startSoftap();
913 } else if (!strcmp(argv[1], "stopap")) {
914 rc = sSoftapCtrl->stopSoftap();
915 } else if (!strcmp(argv[1], "fwreload")) {
916 rc = sSoftapCtrl->fwReloadSoftap(argc, argv);
917 } else if (!strcmp(argv[1], "status")) {
918 asprintf(&retbuf, "Softap service %s running",
919 (sSoftapCtrl->isSoftapStarted() ? "is" : "is not"));
920 cli->sendMsg(rc, retbuf, false);
923 } else if (!strcmp(argv[1], "set")) {
924 rc = sSoftapCtrl->setSoftap(argc, argv);
926 cli->sendMsg(ResponseCode::CommandSyntaxError, "Unrecognized SoftAP command", false);
930 if (rc >= 400 && rc < 600)
931 cli->sendMsg(rc, "SoftAP command has failed", false);
933 cli->sendMsg(rc, "Ok", false);
938 CommandListener::ResolverCmd::ResolverCmd() :
939 NetdCommand("resolver") {
942 int CommandListener::ResolverCmd::runCommand(SocketClient *cli, int argc, char **margv) {
944 const char **argv = const_cast<const char **>(margv);
947 cli->sendMsg(ResponseCode::CommandSyntaxError, "Resolver missing arguments", false);
951 if (!strcmp(argv[1], "setnetdns")) {
952 // "resolver setnetdns <netId> <domains> <dns1> <dns2> ..."
954 rc = sResolverCtrl->setDnsServers(strtoul(argv[2], NULL, 0), argv[3], &argv[4], argc - 4);
956 cli->sendMsg(ResponseCode::CommandSyntaxError,
957 "Wrong number of arguments to resolver setnetdns", false);
960 } else if (!strcmp(argv[1], "flushnet")) { // "resolver flushnet <netId>"
962 rc = sResolverCtrl->flushDnsCache(strtoul(argv[2], NULL, 0));
964 cli->sendMsg(ResponseCode::CommandSyntaxError,
965 "Wrong number of arguments to resolver flushnet", false);
969 cli->sendMsg(ResponseCode::CommandSyntaxError,"Resolver unknown command", false);
974 cli->sendMsg(ResponseCode::CommandOkay, "Resolver command succeeded", false);
976 cli->sendMsg(ResponseCode::OperationFailed, "Resolver command failed", true);
982 CommandListener::BandwidthControlCmd::BandwidthControlCmd() :
983 NetdCommand("bandwidth") {
986 void CommandListener::BandwidthControlCmd::sendGenericSyntaxError(SocketClient *cli, const char *usageMsg) {
988 asprintf(&msg, "Usage: bandwidth %s", usageMsg);
989 cli->sendMsg(ResponseCode::CommandSyntaxError, msg, false);
993 void CommandListener::BandwidthControlCmd::sendGenericOkFail(SocketClient *cli, int cond) {
995 cli->sendMsg(ResponseCode::CommandOkay, "Bandwidth command succeeeded", false);
997 cli->sendMsg(ResponseCode::OperationFailed, "Bandwidth command failed", false);
1001 void CommandListener::BandwidthControlCmd::sendGenericOpFailed(SocketClient *cli, const char *errMsg) {
1002 cli->sendMsg(ResponseCode::OperationFailed, errMsg, false);
1005 int CommandListener::BandwidthControlCmd::runCommand(SocketClient *cli, int argc, char **argv) {
1007 sendGenericSyntaxError(cli, "<cmds> <args...>");
1011 ALOGV("bwctrlcmd: argc=%d %s %s ...", argc, argv[0], argv[1]);
1013 if (!strcmp(argv[1], "enable")) {
1014 int rc = sBandwidthCtrl->enableBandwidthControl(true);
1015 sendGenericOkFail(cli, rc);
1019 if (!strcmp(argv[1], "disable")) {
1020 int rc = sBandwidthCtrl->disableBandwidthControl();
1021 sendGenericOkFail(cli, rc);
1025 if (!strcmp(argv[1], "removequota") || !strcmp(argv[1], "rq")) {
1027 sendGenericSyntaxError(cli, "removequota <interface>");
1030 int rc = sBandwidthCtrl->removeInterfaceSharedQuota(argv[2]);
1031 sendGenericOkFail(cli, rc);
1035 if (!strcmp(argv[1], "getquota") || !strcmp(argv[1], "gq")) {
1038 sendGenericSyntaxError(cli, "getquota");
1041 int rc = sBandwidthCtrl->getInterfaceSharedQuota(&bytes);
1043 sendGenericOpFailed(cli, "Failed to get quota");
1048 asprintf(&msg, "%" PRId64, bytes);
1049 cli->sendMsg(ResponseCode::QuotaCounterResult, msg, false);
1054 if (!strcmp(argv[1], "getiquota") || !strcmp(argv[1], "giq")) {
1057 sendGenericSyntaxError(cli, "getiquota <iface>");
1061 int rc = sBandwidthCtrl->getInterfaceQuota(argv[2], &bytes);
1063 sendGenericOpFailed(cli, "Failed to get quota");
1067 asprintf(&msg, "%" PRId64, bytes);
1068 cli->sendMsg(ResponseCode::QuotaCounterResult, msg, false);
1073 if (!strcmp(argv[1], "setquota") || !strcmp(argv[1], "sq")) {
1075 sendGenericSyntaxError(cli, "setquota <interface> <bytes>");
1078 int rc = sBandwidthCtrl->setInterfaceSharedQuota(argv[2], atoll(argv[3]));
1079 sendGenericOkFail(cli, rc);
1082 if (!strcmp(argv[1], "setquotas") || !strcmp(argv[1], "sqs")) {
1085 sendGenericSyntaxError(cli, "setquotas <bytes> <interface> ...");
1089 for (int q = 3; argc >= 4; q++, argc--) {
1090 rc = sBandwidthCtrl->setInterfaceSharedQuota(argv[q], atoll(argv[2]));
1093 asprintf(&msg, "bandwidth setquotas %s %s failed", argv[2], argv[q]);
1094 cli->sendMsg(ResponseCode::OperationFailed,
1100 sendGenericOkFail(cli, rc);
1104 if (!strcmp(argv[1], "removequotas") || !strcmp(argv[1], "rqs")) {
1107 sendGenericSyntaxError(cli, "removequotas <interface> ...");
1111 for (int q = 2; argc >= 3; q++, argc--) {
1112 rc = sBandwidthCtrl->removeInterfaceSharedQuota(argv[q]);
1115 asprintf(&msg, "bandwidth removequotas %s failed", argv[q]);
1116 cli->sendMsg(ResponseCode::OperationFailed,
1122 sendGenericOkFail(cli, rc);
1126 if (!strcmp(argv[1], "removeiquota") || !strcmp(argv[1], "riq")) {
1128 sendGenericSyntaxError(cli, "removeiquota <interface>");
1131 int rc = sBandwidthCtrl->removeInterfaceQuota(argv[2]);
1132 sendGenericOkFail(cli, rc);
1136 if (!strcmp(argv[1], "setiquota") || !strcmp(argv[1], "siq")) {
1138 sendGenericSyntaxError(cli, "setiquota <interface> <bytes>");
1141 int rc = sBandwidthCtrl->setInterfaceQuota(argv[2], atoll(argv[3]));
1142 sendGenericOkFail(cli, rc);
1146 if (!strcmp(argv[1], "addnaughtyapps") || !strcmp(argv[1], "ana")) {
1148 sendGenericSyntaxError(cli, "addnaughtyapps <appUid> ...");
1151 int rc = sBandwidthCtrl->addNaughtyApps(argc - 2, argv + 2);
1152 sendGenericOkFail(cli, rc);
1157 if (!strcmp(argv[1], "removenaughtyapps") || !strcmp(argv[1], "rna")) {
1159 sendGenericSyntaxError(cli, "removenaughtyapps <appUid> ...");
1162 int rc = sBandwidthCtrl->removeNaughtyApps(argc - 2, argv + 2);
1163 sendGenericOkFail(cli, rc);
1166 if (!strcmp(argv[1], "happybox")) {
1168 sendGenericSyntaxError(cli, "happybox (enable | disable)");
1171 if (!strcmp(argv[2], "enable")) {
1172 int rc = sBandwidthCtrl->enableHappyBox();
1173 sendGenericOkFail(cli, rc);
1177 if (!strcmp(argv[2], "disable")) {
1178 int rc = sBandwidthCtrl->disableHappyBox();
1179 sendGenericOkFail(cli, rc);
1182 sendGenericSyntaxError(cli, "happybox (enable | disable)");
1185 if (!strcmp(argv[1], "addniceapps") || !strcmp(argv[1], "aha")) {
1187 sendGenericSyntaxError(cli, "addniceapps <appUid> ...");
1190 int rc = sBandwidthCtrl->addNiceApps(argc - 2, argv + 2);
1191 sendGenericOkFail(cli, rc);
1194 if (!strcmp(argv[1], "removeniceapps") || !strcmp(argv[1], "rha")) {
1196 sendGenericSyntaxError(cli, "removeniceapps <appUid> ...");
1199 int rc = sBandwidthCtrl->removeNiceApps(argc - 2, argv + 2);
1200 sendGenericOkFail(cli, rc);
1203 if (!strcmp(argv[1], "setglobalalert") || !strcmp(argv[1], "sga")) {
1205 sendGenericSyntaxError(cli, "setglobalalert <bytes>");
1208 int rc = sBandwidthCtrl->setGlobalAlert(atoll(argv[2]));
1209 sendGenericOkFail(cli, rc);
1212 if (!strcmp(argv[1], "debugsettetherglobalalert") || !strcmp(argv[1], "dstga")) {
1214 sendGenericSyntaxError(cli, "debugsettetherglobalalert <interface0> <interface1>");
1217 /* We ignore the interfaces for now. */
1218 int rc = sBandwidthCtrl->setGlobalAlertInForwardChain();
1219 sendGenericOkFail(cli, rc);
1223 if (!strcmp(argv[1], "removeglobalalert") || !strcmp(argv[1], "rga")) {
1225 sendGenericSyntaxError(cli, "removeglobalalert");
1228 int rc = sBandwidthCtrl->removeGlobalAlert();
1229 sendGenericOkFail(cli, rc);
1233 if (!strcmp(argv[1], "debugremovetetherglobalalert") || !strcmp(argv[1], "drtga")) {
1235 sendGenericSyntaxError(cli, "debugremovetetherglobalalert <interface0> <interface1>");
1238 /* We ignore the interfaces for now. */
1239 int rc = sBandwidthCtrl->removeGlobalAlertInForwardChain();
1240 sendGenericOkFail(cli, rc);
1244 if (!strcmp(argv[1], "setsharedalert") || !strcmp(argv[1], "ssa")) {
1246 sendGenericSyntaxError(cli, "setsharedalert <bytes>");
1249 int rc = sBandwidthCtrl->setSharedAlert(atoll(argv[2]));
1250 sendGenericOkFail(cli, rc);
1254 if (!strcmp(argv[1], "removesharedalert") || !strcmp(argv[1], "rsa")) {
1256 sendGenericSyntaxError(cli, "removesharedalert");
1259 int rc = sBandwidthCtrl->removeSharedAlert();
1260 sendGenericOkFail(cli, rc);
1264 if (!strcmp(argv[1], "setinterfacealert") || !strcmp(argv[1], "sia")) {
1266 sendGenericSyntaxError(cli, "setinterfacealert <interface> <bytes>");
1269 int rc = sBandwidthCtrl->setInterfaceAlert(argv[2], atoll(argv[3]));
1270 sendGenericOkFail(cli, rc);
1274 if (!strcmp(argv[1], "removeinterfacealert") || !strcmp(argv[1], "ria")) {
1276 sendGenericSyntaxError(cli, "removeinterfacealert <interface>");
1279 int rc = sBandwidthCtrl->removeInterfaceAlert(argv[2]);
1280 sendGenericOkFail(cli, rc);
1284 if (!strcmp(argv[1], "gettetherstats") || !strcmp(argv[1], "gts")) {
1285 BandwidthController::TetherStats tetherStats;
1286 std::string extraProcessingInfo = "";
1287 if (argc < 2 || argc > 4) {
1288 sendGenericSyntaxError(cli, "gettetherstats [<intInterface> <extInterface>]");
1291 tetherStats.intIface = argc > 2 ? argv[2] : "";
1292 tetherStats.extIface = argc > 3 ? argv[3] : "";
1293 // No filtering requested and there are no interface pairs to lookup.
1294 if (argc <= 2 && sNatCtrl->ifacePairList.empty()) {
1295 cli->sendMsg(ResponseCode::CommandOkay, "Tethering stats list completed", false);
1298 int rc = sBandwidthCtrl->getTetherStats(cli, tetherStats, extraProcessingInfo);
1300 extraProcessingInfo.insert(0, "Failed to get tethering stats.\n");
1301 sendGenericOpFailed(cli, extraProcessingInfo.c_str());
1308 cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown bandwidth cmd", false);
1312 CommandListener::IdletimerControlCmd::IdletimerControlCmd() :
1313 NetdCommand("idletimer") {
1316 int CommandListener::IdletimerControlCmd::runCommand(SocketClient *cli, int argc, char **argv) {
1317 // TODO(ashish): Change the error statements
1319 cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
1323 ALOGV("idletimerctrlcmd: argc=%d %s %s ...", argc, argv[0], argv[1]);
1325 if (!strcmp(argv[1], "enable")) {
1326 if (0 != sIdletimerCtrl->enableIdletimerControl()) {
1327 cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
1329 cli->sendMsg(ResponseCode::CommandOkay, "Enable success", false);
1334 if (!strcmp(argv[1], "disable")) {
1335 if (0 != sIdletimerCtrl->disableIdletimerControl()) {
1336 cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
1338 cli->sendMsg(ResponseCode::CommandOkay, "Disable success", false);
1342 if (!strcmp(argv[1], "add")) {
1344 cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
1347 if(0 != sIdletimerCtrl->addInterfaceIdletimer(
1348 argv[2], atoi(argv[3]), argv[4])) {
1349 cli->sendMsg(ResponseCode::OperationFailed, "Failed to add interface", false);
1351 cli->sendMsg(ResponseCode::CommandOkay, "Add success", false);
1355 if (!strcmp(argv[1], "remove")) {
1357 cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
1360 // ashish: fixme timeout
1361 if (0 != sIdletimerCtrl->removeInterfaceIdletimer(
1362 argv[2], atoi(argv[3]), argv[4])) {
1363 cli->sendMsg(ResponseCode::OperationFailed, "Failed to remove interface", false);
1365 cli->sendMsg(ResponseCode::CommandOkay, "Remove success", false);
1370 cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown idletimer cmd", false);
1374 CommandListener::FirewallCmd::FirewallCmd() :
1375 NetdCommand("firewall") {
1378 int CommandListener::FirewallCmd::sendGenericOkFail(SocketClient *cli, int cond) {
1380 cli->sendMsg(ResponseCode::CommandOkay, "Firewall command succeeded", false);
1382 cli->sendMsg(ResponseCode::OperationFailed, "Firewall command failed", false);
1387 FirewallRule CommandListener::FirewallCmd::parseRule(const char* arg) {
1388 if (!strcmp(arg, "allow")) {
1395 int CommandListener::FirewallCmd::runCommand(SocketClient *cli, int argc,
1398 cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing command", false);
1402 if (!strcmp(argv[1], "enable")) {
1403 int res = sFirewallCtrl->enableFirewall();
1404 return sendGenericOkFail(cli, res);
1406 if (!strcmp(argv[1], "disable")) {
1407 int res = sFirewallCtrl->disableFirewall();
1408 return sendGenericOkFail(cli, res);
1410 if (!strcmp(argv[1], "is_enabled")) {
1411 int res = sFirewallCtrl->isFirewallEnabled();
1412 return sendGenericOkFail(cli, res);
1415 if (!strcmp(argv[1], "set_interface_rule")) {
1417 cli->sendMsg(ResponseCode::CommandSyntaxError,
1418 "Usage: firewall set_interface_rule <rmnet0> <allow|deny>", false);
1422 const char* iface = argv[2];
1423 FirewallRule rule = parseRule(argv[3]);
1425 int res = sFirewallCtrl->setInterfaceRule(iface, rule);
1426 return sendGenericOkFail(cli, res);
1429 if (!strcmp(argv[1], "set_egress_source_rule")) {
1431 cli->sendMsg(ResponseCode::CommandSyntaxError,
1432 "Usage: firewall set_egress_source_rule <192.168.0.1> <allow|deny>",
1437 const char* addr = argv[2];
1438 FirewallRule rule = parseRule(argv[3]);
1440 int res = sFirewallCtrl->setEgressSourceRule(addr, rule);
1441 return sendGenericOkFail(cli, res);
1444 if (!strcmp(argv[1], "set_egress_dest_rule")) {
1446 cli->sendMsg(ResponseCode::CommandSyntaxError,
1447 "Usage: firewall set_egress_dest_rule <192.168.0.1> <80> <allow|deny>",
1452 const char* addr = argv[2];
1453 int port = atoi(argv[3]);
1454 FirewallRule rule = parseRule(argv[4]);
1457 res |= sFirewallCtrl->setEgressDestRule(addr, PROTOCOL_TCP, port, rule);
1458 res |= sFirewallCtrl->setEgressDestRule(addr, PROTOCOL_UDP, port, rule);
1459 return sendGenericOkFail(cli, res);
1462 if (!strcmp(argv[1], "set_uid_rule")) {
1464 cli->sendMsg(ResponseCode::CommandSyntaxError,
1465 "Usage: firewall set_uid_rule <1000> <allow|deny>",
1470 int uid = atoi(argv[2]);
1471 FirewallRule rule = parseRule(argv[3]);
1473 int res = sFirewallCtrl->setUidRule(uid, rule);
1474 return sendGenericOkFail(cli, res);
1477 cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown command", false);
1481 CommandListener::ClatdCmd::ClatdCmd() : NetdCommand("clatd") {
1484 int CommandListener::ClatdCmd::runCommand(SocketClient *cli, int argc,
1488 cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
1492 if(!strcmp(argv[1], "stop")) {
1493 rc = sClatdCtrl->stopClatd();
1494 } else if (!strcmp(argv[1], "status")) {
1497 asprintf(&tmp, "Clatd status: %s", (sClatdCtrl->isClatdStarted() ?
1498 "started" : "stopped"));
1499 cli->sendMsg(ResponseCode::ClatdStatusResult, tmp, false);
1502 } else if(!strcmp(argv[1], "start")) {
1504 cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
1507 rc = sClatdCtrl->startClatd(argv[2]);
1509 cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown clatd cmd", false);
1514 cli->sendMsg(ResponseCode::CommandOkay, "Clatd operation succeeded", false);
1516 cli->sendMsg(ResponseCode::OperationFailed, "Clatd operation failed", false);
1522 CommandListener::NetworkCommand::NetworkCommand() : NetdCommand("network") {
1525 int CommandListener::NetworkCommand::syntaxError(SocketClient* client, const char* message) {
1526 client->sendMsg(ResponseCode::CommandSyntaxError, message, false);
1530 int CommandListener::NetworkCommand::operationError(SocketClient* client, const char* message,
1533 client->sendMsg(ResponseCode::OperationFailed, message, true);
1537 int CommandListener::NetworkCommand::success(SocketClient* client) {
1538 client->sendMsg(ResponseCode::CommandOkay, "success", false);
1542 int CommandListener::NetworkCommand::runCommand(SocketClient* client, int argc, char** argv) {
1544 return syntaxError(client, "Missing argument");
1547 // 0 1 2 3 4 5 6 7 8
1548 // network route [legacy <uid>] add <netId> <interface> <destination> [nexthop]
1549 // network route [legacy <uid>] remove <netId> <interface> <destination> [nexthop]
1550 if (!strcmp(argv[1], "route")) {
1551 if (argc < 6 || argc > 9) {
1552 return syntaxError(client, "Incorrect number of arguments");
1556 bool legacy = false;
1558 if (!strcmp(argv[nextArg], "legacy")) {
1561 uid = strtoul(argv[nextArg++], NULL, 0);
1565 if (!strcmp(argv[nextArg], "add")) {
1567 } else if (strcmp(argv[nextArg], "remove")) {
1568 return syntaxError(client, "Unknown argument");
1572 // strtoul() returns 0 on errors, which is fine because 0 is an invalid netId.
1573 unsigned netId = strtoul(argv[nextArg++], NULL, 0);
1574 const char* interface = argv[nextArg++];
1575 const char* destination = argv[nextArg++];
1576 const char* nexthop = argc > nextArg ? argv[nextArg] : NULL;
1580 ret = sNetCtrl->addRoute(netId, interface, destination, nexthop, legacy, uid);
1582 ret = sNetCtrl->removeRoute(netId, interface, destination, nexthop, legacy, uid);
1585 return operationError(client, add ? "addRoute() failed" : "removeRoute() failed", ret);
1588 return success(client);
1592 // network addiface <netId> <interface>
1593 // network removeiface <netId> <interface>
1594 if (!strcmp(argv[1], "addiface") || !strcmp(argv[1], "removeiface")) {
1596 return syntaxError(client, "Missing argument");
1598 // strtoul() returns 0 on errors, which is fine because 0 is an invalid netId.
1599 unsigned netId = strtoul(argv[2], NULL, 0);
1600 if (!strcmp(argv[1], "addiface")) {
1601 if (int ret = sNetCtrl->addInterfaceToNetwork(netId, argv[3])) {
1602 return operationError(client, "addInterfaceToNetwork() failed", ret);
1605 if (int ret = sNetCtrl->removeInterfaceFromNetwork(netId, argv[3])) {
1606 return operationError(client, "removeInterfaceFromNetwork() failed", ret);
1609 return success(client);
1613 // network create <netId> [permission]
1616 // network create <netId> vpn <hasDns>
1617 if (!strcmp(argv[1], "create")) {
1619 return syntaxError(client, "Missing argument");
1621 // strtoul() returns 0 on errors, which is fine because 0 is an invalid netId.
1622 unsigned netId = strtoul(argv[2], NULL, 0);
1623 if (argc == 5 && !strcmp(argv[3], "vpn")) {
1624 bool hasDns = atoi(argv[4]);
1625 if (int ret = sNetCtrl->createVirtualNetwork(netId, hasDns)) {
1626 return operationError(client, "createVirtualNetwork() failed", ret);
1628 } else if (argc > 4) {
1629 return syntaxError(client, "Unknown trailing argument(s)");
1631 Permission permission = PERMISSION_NONE;
1633 permission = stringToPermission(argv[3]);
1634 if (permission == PERMISSION_NONE) {
1635 return syntaxError(client, "Unknown permission");
1638 if (int ret = sNetCtrl->createPhysicalNetwork(netId, permission)) {
1639 return operationError(client, "createPhysicalNetwork() failed", ret);
1642 return success(client);
1646 // network destroy <netId>
1647 if (!strcmp(argv[1], "destroy")) {
1649 return syntaxError(client, "Incorrect number of arguments");
1651 // strtoul() returns 0 on errors, which is fine because 0 is an invalid netId.
1652 unsigned netId = strtoul(argv[2], NULL, 0);
1653 if (int ret = sNetCtrl->destroyNetwork(netId)) {
1654 return operationError(client, "destroyNetwork() failed", ret);
1656 return success(client);
1660 // network default set <netId>
1661 // network default clear
1662 if (!strcmp(argv[1], "default")) {
1664 return syntaxError(client, "Missing argument");
1666 unsigned netId = NETID_UNSET;
1667 if (!strcmp(argv[2], "set")) {
1669 return syntaxError(client, "Missing netId");
1671 // strtoul() returns 0 on errors, which is fine because 0 is an invalid netId.
1672 netId = strtoul(argv[3], NULL, 0);
1673 } else if (strcmp(argv[2], "clear")) {
1674 return syntaxError(client, "Unknown argument");
1676 if (int ret = sNetCtrl->setDefaultNetwork(netId)) {
1677 return operationError(client, "setDefaultNetwork() failed", ret);
1679 return success(client);
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")) {
1689 return syntaxError(client, "Missing argument");
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");
1699 } else if (strcmp(argv[3], "clear")) {
1700 return syntaxError(client, "Unknown argument");
1702 if (nextArg == argc) {
1703 return syntaxError(client, "Missing id");
1705 std::vector<unsigned> ids;
1706 for (; nextArg < argc; ++nextArg) {
1708 unsigned id = strtoul(argv[nextArg], &endPtr, 0);
1709 if (!*argv[nextArg] || *endPtr) {
1710 return syntaxError(client, "Invalid id");
1714 if (!strcmp(argv[2], "user")) {
1715 sNetCtrl->setPermissionForUsers(permission, ids);
1716 } else if (!strcmp(argv[2], "network")) {
1717 if (int ret = sNetCtrl->setPermissionForNetworks(permission, ids)) {
1718 return operationError(client, "setPermissionForNetworks() failed", ret);
1721 return syntaxError(client, "Unknown argument");
1723 return success(client);
1727 // network users add <netId> [<uid>[-<uid>]] ...
1728 // network users remove <netId> [<uid>[-<uid>]] ...
1729 if (!strcmp(argv[1], "users")) {
1731 return syntaxError(client, "Missing argument");
1733 // strtoul() returns 0 on errors, which is fine because 0 is an invalid netId.
1734 unsigned netId = strtoul(argv[3], NULL, 0);
1735 UidRanges uidRanges;
1736 if (!uidRanges.parseFrom(argc - 4, argv + 4)) {
1737 return syntaxError(client, "Invalid UIDs");
1739 if (!strcmp(argv[2], "add")) {
1740 if (int ret = sNetCtrl->addUsersToNetwork(netId, uidRanges)) {
1741 return operationError(client, "addUsersToNetwork() failed", ret);
1743 } else if (!strcmp(argv[2], "remove")) {
1744 if (int ret = sNetCtrl->removeUsersFromNetwork(netId, uidRanges)) {
1745 return operationError(client, "removeUsersFromNetwork() failed", ret);
1748 return syntaxError(client, "Unknown argument");
1750 return success(client);
1754 // network protect allow <uid> ...
1755 // network protect deny <uid> ...
1756 if (!strcmp(argv[1], "protect")) {
1758 return syntaxError(client, "Missing argument");
1760 std::vector<uid_t> uids;
1761 for (int i = 3; i < argc; ++i) {
1762 uids.push_back(strtoul(argv[i], NULL, 0));
1764 if (!strcmp(argv[2], "allow")) {
1765 sNetCtrl->allowProtect(uids);
1766 } else if (!strcmp(argv[2], "deny")) {
1767 sNetCtrl->denyProtect(uids);
1769 return syntaxError(client, "Unknown argument");
1771 return success(client);
1778 return syntaxError(client, "Unknown argument");