NDC migration to binder ver.

Make ndc communicating with netd via binder

Bug: 65862741
Test: built, flashed, booted
      system/netd/tests/runtests.sh pass
      manual test ndc commands
Change-Id: I9edfda61d8c3a4d7b404a428e7dbb4d08eff62a9
diff --git a/server/Android.bp b/server/Android.bp
index 5f2f373..bd30f47 100644
--- a/server/Android.bp
+++ b/server/Android.bp
@@ -138,7 +138,6 @@
         "libnetd_resolv_headers",
     ],
     srcs: [
-        "CommandListener.cpp",
         "DummyNetwork.cpp",
         "EventReporter.cpp",
         "FwmarkServer.cpp",
@@ -163,8 +162,28 @@
 cc_binary {
     name: "ndc",
     defaults: ["netd_defaults"],
-    shared_libs: ["libcutils"],
-    srcs: ["ndc.cpp"],
+    include_dirs: [
+        "system/netd/include",
+    ],
+    header_libs: [
+        "libnetd_client_headers",
+    ],
+    shared_libs: [
+        "libbase",
+        "libnetdutils",
+        "libnetutils",
+        "libcutils",
+        "liblog",
+        "libutils",
+        "libbinder",
+        "dnsresolver_aidl_interface-cpp",
+        "netd_aidl_interface-cpp",
+    ],
+    srcs: [
+        "ndc.cpp",
+        "UidRanges.cpp",
+        "NdcDispatcher.cpp",
+    ],
 }
 
 cc_test {
diff --git a/server/CommandListener.h b/server/CommandListener.h
deleted file mode 100644
index d0e8c7e..0000000
--- a/server/CommandListener.h
+++ /dev/null
@@ -1,136 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef _COMMANDLISTENER_H__
-#define _COMMANDLISTENER_H__
-
-#include <mutex>
-
-#include <android/net/INetd.h>
-#include <sysutils/FrameworkListener.h>
-#include "binder/IServiceManager.h"
-
-#include "BandwidthController.h"
-#include "ClatdController.h"
-#include "FirewallController.h"
-#include "IdletimerController.h"
-#include "InterfaceController.h"
-#include "NetdCommand.h"
-#include "NetdConstants.h"
-
-namespace android {
-namespace net {
-
-class CommandListener : public FrameworkListener {
-  public:
-    CommandListener();
-    virtual ~CommandListener() {}
-
-    static constexpr const char* SOCKET_NAME = "netd";
-    static sp<INetd> mNetd;
-
-  private:
-    class InterfaceCmd : public NetdCommand {
-    public:
-        InterfaceCmd();
-        virtual ~InterfaceCmd() {}
-        int runCommand(SocketClient *c, int argc, char ** argv);
-    };
-
-    class IpFwdCmd : public NetdCommand {
-    public:
-        IpFwdCmd();
-        virtual ~IpFwdCmd() {}
-        int runCommand(SocketClient *c, int argc, char ** argv);
-    };
-
-    class TetherCmd : public NetdCommand {
-    public:
-        TetherCmd();
-        virtual ~TetherCmd() {}
-        int runCommand(SocketClient *c, int argc, char ** argv);
-    };
-
-    class NatCmd : public NetdCommand {
-    public:
-        NatCmd();
-        virtual ~NatCmd() {}
-        int runCommand(SocketClient *c, int argc, char ** argv);
-    };
-
-    class BandwidthControlCmd : public NetdCommand {
-    public:
-        BandwidthControlCmd();
-        virtual ~BandwidthControlCmd() {}
-        int runCommand(SocketClient *c, int argc, char ** argv);
-    protected:
-        void sendGenericOkFail(SocketClient *cli, int cond);
-        void sendGenericOpFailed(SocketClient *cli, const char *errMsg);
-        void sendGenericSyntaxError(SocketClient *cli, const char *usageMsg);
-    };
-
-    class IdletimerControlCmd : public NetdCommand {
-    public:
-        IdletimerControlCmd();
-        virtual ~IdletimerControlCmd() {}
-        int runCommand(SocketClient *c, int argc, char ** argv);
-    };
-
-    class FirewallCmd: public NetdCommand {
-    public:
-        FirewallCmd();
-        virtual ~FirewallCmd() {}
-        int runCommand(SocketClient *c, int argc, char ** argv);
-    protected:
-        int sendGenericOkFail(SocketClient *cli, int cond);
-        static int parseRule(const char* arg);
-        static int parseFirewallType(const char* arg);
-        static int parseChildChain(const char* arg);
-    };
-
-    class ClatdCmd : public NetdCommand {
-    public:
-        ClatdCmd();
-        virtual ~ClatdCmd() {}
-        int runCommand(SocketClient *c, int argc, char ** argv);
-    };
-
-    class StrictCmd : public NetdCommand {
-    public:
-        StrictCmd();
-        virtual ~StrictCmd() {}
-        int runCommand(SocketClient *c, int argc, char ** argv);
-    protected:
-        int sendGenericOkFail(SocketClient *cli, int cond);
-        static int parsePenalty(const char* arg);
-    };
-
-    class NetworkCommand : public NetdCommand {
-    public:
-        NetworkCommand();
-        virtual ~NetworkCommand() {}
-        int runCommand(SocketClient* client, int argc, char** argv);
-    private:
-        int syntaxError(SocketClient* cli, const char* message);
-        int operationError(SocketClient* cli, const char* message, int ret);
-        int success(SocketClient* cli);
-    };
-};
-
-}  // namespace net
-}  // namespace android
-
-#endif
diff --git a/server/CommandListener.cpp b/server/NdcDispatcher.cpp
similarity index 80%
rename from server/CommandListener.cpp
rename to server/NdcDispatcher.cpp
index dbda674..51cc384 100644
--- a/server/CommandListener.cpp
+++ b/server/NdcDispatcher.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2008 The Android Open Source Project
+ * Copyright (C) 2019 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,43 +14,38 @@
  * limitations under the License.
  */
 
-// #define LOG_NDEBUG 0
+#include "NdcDispatcher.h"
 
-#include <stdlib.h>
-#include <sys/socket.h>
-#include <sys/types.h>
-#include <netinet/in.h>
 #include <arpa/inet.h>
 #include <dirent.h>
 #include <errno.h>
-#include <string.h>
 #include <linux/if.h>
+#include <netinet/in.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/types.h>
 
-#define __STDC_FORMAT_MACROS 1
-#include <inttypes.h>
+#include <cinttypes>
+#include <string>
+#include <vector>
 
-#define LOG_TAG "CommandListener"
-
+#include <android-base/logging.h>
 #include <android-base/parseint.h>
+#include <android-base/stringprintf.h>
 #include <android-base/strings.h>
-#include <log/log.h>
-#include <netd_resolv/params.h>
+#include <android/multinetwork.h>
 #include <netdutils/ResponseCode.h>
 #include <netdutils/Status.h>
 #include <netdutils/StatusOr.h>
 #include <netutils/ifc.h>
-#include <sysutils/SocketClient.h>
 
-#include "CommandListener.h"
-#include "Controllers.h"
 #include "NetdConstants.h"
-
+#include "NetworkController.h"
+#include "Permission.h"
 #include "UidRanges.h"
 #include "netid_client.h"
 
-#include <string>
-#include <vector>
-
 using android::base::Join;
 using android::base::StringPrintf;
 using android::binder::Status;
@@ -120,15 +115,18 @@
 
 }  // namespace
 
-sp<INetd> CommandListener::mNetd;
+sp<INetd> NdcDispatcher::mNetd;
+sp<IDnsResolver> NdcDispatcher::mDnsResolver;
 
-CommandListener::CommandListener() : FrameworkListener(SOCKET_NAME, true) {
+NdcDispatcher::NdcDispatcher() {
     sp<IServiceManager> sm = defaultServiceManager();
-    sp<IBinder> binder = sm->getService(String16("netd"));
-    if (binder != nullptr) {
-        CommandListener::mNetd = interface_cast<INetd>(binder);
+    sp<IBinder> binderNetd = sm->getService(String16("netd"));
+    sp<IBinder> binderDnsResolver = sm->getService(String16("dnsresolver"));
+    if ((binderNetd != nullptr) && (binderDnsResolver != nullptr)) {
+        NdcDispatcher::mNetd = interface_cast<INetd>(binderNetd);
+        NdcDispatcher::mDnsResolver = interface_cast<IDnsResolver>(binderDnsResolver);
     } else {
-        ALOGE("Unable to get INetd service");
+        LOG(LOGLEVEL) << "Unable to get binder service";
         exit(1);
     }
     registerCmd(new InterfaceCmd());
@@ -143,12 +141,30 @@
     registerCmd(new StrictCmd());
 }
 
-CommandListener::InterfaceCmd::InterfaceCmd() :
-                 NetdCommand("interface") {
+void NdcDispatcher::registerCmd(NdcNetdCommand* cmd) {
+    mCommands.push_back(cmd);
 }
 
-int CommandListener::InterfaceCmd::runCommand(SocketClient *cli,
-                                                      int argc, char **argv) {
+int NdcDispatcher::dispatchCommand(int argc, char** argv) {
+    if (argc >= CMD_ARGS_MAX) {
+        mNdc.sendMsg(500, "Command too long", false);
+    }
+
+    for (const auto* c : mCommands) {
+        if (c->getCommand() == argv[0]) {
+            if (c->runCommand(&mNdc, argc, argv)) {
+                mNdc.sendMsg(500, "Handler error", true);
+            }
+            return 0;
+        }
+    }
+    mNdc.sendMsg(500, "Command not recognized", false);
+    return 0;
+}
+
+NdcDispatcher::InterfaceCmd::InterfaceCmd() : NdcNetdCommand("interface") {}
+
+int NdcDispatcher::InterfaceCmd::runCommand(NdcClient* cli, int argc, char** argv) const {
     if (argc < 2) {
         cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
         return 0;
@@ -203,7 +219,7 @@
                 cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
                 return 0;
             }
-            ALOGD("Setting iface cfg");
+            LOG(LOGLEVEL) << "Setting iface cfg";
 
             struct in_addr addr;
             int index = 5;
@@ -232,26 +248,27 @@
 
             /* Process flags */
             for (int i = index; i < argc; i++) {
-                char *flag = argv[i];
+                char* flag = argv[i];
                 if (!strcmp(flag, "up")) {
-                    ALOGD("Trying to bring up %s", argv[2]);
+                    LOG(LOGLEVEL) << "Trying to bring up " << argv[2];
                     interfaceCfg.flags.push_back(toStdString(INetd::IF_STATE_UP()));
                     Status status = mNetd->interfaceSetCfg(interfaceCfg);
                     if (!status.isOk()) {
-                        ALOGE("Error upping interface");
+                        LOG(LOGLEVEL) << "Error upping interface";
                         errno = status.serviceSpecificErrorCode();
                         cli->sendMsg(ResponseCode::OperationFailed, "Failed to up interface", true);
                         ifc_close();
                         return 0;
                     }
                 } else if (!strcmp(flag, "down")) {
-                    ALOGD("Trying to bring down %s", argv[2]);
+                    LOG(LOGLEVEL) << "Trying to bring down " << argv[2];
                     interfaceCfg.flags.push_back(toStdString(INetd::IF_STATE_DOWN()));
                     Status status = mNetd->interfaceSetCfg(interfaceCfg);
                     if (!status.isOk()) {
-                        ALOGE("Error downing interface");
+                        LOG(LOGLEVEL) << "Error downing interface";
                         errno = status.serviceSpecificErrorCode();
-                        cli->sendMsg(ResponseCode::OperationFailed, "Failed to down interface", true);
+                        cli->sendMsg(ResponseCode::OperationFailed, "Failed to down interface",
+                                     true);
                         return 0;
                     }
                 } else if (!strcmp(flag, "broadcast")) {
@@ -274,7 +291,7 @@
             return 0;
         } else if (!strcmp(argv[1], "clearaddrs")) {
             // arglist: iface
-            ALOGD("Clearing all IP addresses on %s", argv[2]);
+            LOG(LOGLEVEL) << "Clearing all IP addresses on " << argv[2];
 
             mNetd->interfaceClearAddrs(std::string(argv[2]));
 
@@ -283,8 +300,8 @@
         } else if (!strcmp(argv[1], "ipv6privacyextensions")) {
             if (argc != 4) {
                 cli->sendMsg(ResponseCode::CommandSyntaxError,
-                        "Usage: interface ipv6privacyextensions <interface> <enable|disable>",
-                        false);
+                             "Usage: interface ipv6privacyextensions <interface> <enable|disable>",
+                             false);
                 return 0;
             }
             int enable = !strncmp(argv[3], "enable", 7);
@@ -293,15 +310,14 @@
                 cli->sendMsg(ResponseCode::CommandOkay, "IPv6 privacy extensions changed", false);
             } else {
                 errno = status.serviceSpecificErrorCode();
-                cli->sendMsg(ResponseCode::OperationFailed,
-                        "Failed to set ipv6 privacy extensions", true);
+                cli->sendMsg(ResponseCode::OperationFailed, "Failed to set ipv6 privacy extensions",
+                             true);
             }
             return 0;
         } else if (!strcmp(argv[1], "ipv6")) {
             if (argc != 4) {
                 cli->sendMsg(ResponseCode::CommandSyntaxError,
-                        "Usage: interface ipv6 <interface> <enable|disable>",
-                        false);
+                             "Usage: interface ipv6 <interface> <enable|disable>", false);
                 return 0;
             }
 
@@ -311,14 +327,13 @@
                 cli->sendMsg(ResponseCode::CommandOkay, "IPv6 state changed", false);
             } else {
                 errno = status.serviceSpecificErrorCode();
-                cli->sendMsg(ResponseCode::OperationFailed,
-                        "Failed to change IPv6 state", true);
+                cli->sendMsg(ResponseCode::OperationFailed, "Failed to change IPv6 state", true);
             }
             return 0;
         } else if (!strcmp(argv[1], "setmtu")) {
             if (argc != 4) {
                 cli->sendMsg(ResponseCode::CommandSyntaxError,
-                        "Usage: interface setmtu <interface> <val>", false);
+                             "Usage: interface setmtu <interface> <val>", false);
                 return 0;
             }
 
@@ -329,8 +344,7 @@
                 cli->sendMsg(ResponseCode::CommandOkay, "MTU changed", false);
             } else {
                 errno = status.serviceSpecificErrorCode();
-                cli->sendMsg(ResponseCode::OperationFailed,
-                        "Failed to set MTU", true);
+                cli->sendMsg(ResponseCode::OperationFailed, "Failed to set MTU", true);
             }
             return 0;
         } else {
@@ -341,11 +355,9 @@
     return 0;
 }
 
-CommandListener::IpFwdCmd::IpFwdCmd() :
-                 NetdCommand("ipfwd") {
-}
+NdcDispatcher::IpFwdCmd::IpFwdCmd() : NdcNetdCommand("ipfwd") {}
 
-int CommandListener::IpFwdCmd::runCommand(SocketClient *cli, int argc, char **argv) {
+int NdcDispatcher::IpFwdCmd::runCommand(NdcClient* cli, int argc, char** argv) const {
     bool matched = false;
     Status status;
 
@@ -397,12 +409,9 @@
     return 0;
 }
 
-CommandListener::TetherCmd::TetherCmd() :
-                 NetdCommand("tether") {
-}
+NdcDispatcher::TetherCmd::TetherCmd() : NdcNetdCommand("tether") {}
 
-int CommandListener::TetherCmd::runCommand(SocketClient *cli,
-                                                      int argc, char **argv) {
+int NdcDispatcher::TetherCmd::runCommand(NdcClient* cli, int argc, char** argv) const {
     Status status;
 
     if (argc < 2) {
@@ -426,18 +435,6 @@
             for (const auto& ifname : ifList) {
                 cli->sendMsg(ResponseCode::TetherInterfaceListResult, ifname.c_str(), false);
             }
-        } else if (!strcmp(argv[1], "dns") && !strcmp(argv[2], "list")) {
-            // It is not supported in binder currently since NMS doesn't need DnsNetId.
-            // TODO: Fix it after migrate to ndc.
-            char netIdStr[UINT32_STRLEN];
-            snprintf(netIdStr, sizeof(netIdStr), "%u", gCtls->tetherCtrl.getDnsNetId());
-            cli->sendMsg(ResponseCode::TetherDnsFwdNetIdResult, netIdStr, false);
-
-            std::vector<std::string> dnsList;
-            mNetd->tetherDnsList(&dnsList);
-            for (const auto& fwdr : dnsList) {
-                cli->sendMsg(ResponseCode::TetherDnsFwdTgtListResult, fwdr.c_str(), false);
-            }
         }
     } else if (!strcmp(argv[1], "start")) {
         if (argc % 2 == 1) {
@@ -506,12 +503,9 @@
     return 0;
 }
 
-CommandListener::NatCmd::NatCmd() :
-                 NetdCommand("nat") {
-}
+NdcDispatcher::NatCmd::NatCmd() : NdcNetdCommand("nat") {}
 
-int CommandListener::NatCmd::runCommand(SocketClient *cli,
-                                                      int argc, char **argv) {
+int NdcDispatcher::NatCmd::runCommand(NdcClient* cli, int argc, char** argv) const {
     Status status;
 
     if (argc < 5) {
@@ -541,18 +535,17 @@
     return 0;
 }
 
-CommandListener::BandwidthControlCmd::BandwidthControlCmd() :
-    NetdCommand("bandwidth") {
-}
+NdcDispatcher::BandwidthControlCmd::BandwidthControlCmd() : NdcNetdCommand("bandwidth") {}
 
-void CommandListener::BandwidthControlCmd::sendGenericSyntaxError(SocketClient *cli, const char *usageMsg) {
-    char *msg;
+void NdcDispatcher::BandwidthControlCmd::sendGenericSyntaxError(NdcClient* cli,
+                                                                const char* usageMsg) const {
+    char* msg;
     asprintf(&msg, "Usage: bandwidth %s", usageMsg);
     cli->sendMsg(ResponseCode::CommandSyntaxError, msg, false);
     free(msg);
 }
 
-void CommandListener::BandwidthControlCmd::sendGenericOkFail(SocketClient *cli, int cond) {
+void NdcDispatcher::BandwidthControlCmd::sendGenericOkFail(NdcClient* cli, int cond) const {
     if (!cond) {
         cli->sendMsg(ResponseCode::CommandOkay, "Bandwidth command succeeeded", false);
     } else {
@@ -560,17 +553,18 @@
     }
 }
 
-void CommandListener::BandwidthControlCmd::sendGenericOpFailed(SocketClient *cli, const char *errMsg) {
+void NdcDispatcher::BandwidthControlCmd::sendGenericOpFailed(NdcClient* cli,
+                                                             const char* errMsg) const {
     cli->sendMsg(ResponseCode::OperationFailed, errMsg, false);
 }
 
-int CommandListener::BandwidthControlCmd::runCommand(SocketClient *cli, int argc, char **argv) {
+int NdcDispatcher::BandwidthControlCmd::runCommand(NdcClient* cli, int argc, char** argv) const {
     if (argc < 2) {
         sendGenericSyntaxError(cli, "<cmds> <args...>");
         return 0;
     }
 
-    ALOGV("bwctrlcmd: argc=%d %s %s ...", argc, argv[0], argv[1]);
+    LOG(LOGLEVEL) << StringPrintf("bwctrlcmd: argc=%d %s %s ...", argc, argv[0], argv[1]).c_str();
 
     if (!strcmp(argv[1], "removeiquota") || !strcmp(argv[1], "riq")) {
         if (argc != 3) {
@@ -580,7 +574,6 @@
         int rc = !mNetd->bandwidthRemoveInterfaceQuota(argv[2]).isOk();
         sendGenericOkFail(cli, rc);
         return 0;
-
     }
     if (!strcmp(argv[1], "setiquota") || !strcmp(argv[1], "siq")) {
         if (argc != 4) {
@@ -592,7 +585,6 @@
         int rc = !mNetd->bandwidthSetInterfaceQuota(argv[2], bytes).isOk();
         sendGenericOkFail(cli, rc);
         return 0;
-
     }
     if (!strcmp(argv[1], "addnaughtyapps") || !strcmp(argv[1], "ana")) {
         if (argc < 3) {
@@ -675,7 +667,6 @@
         int rc = !mNetd->bandwidthSetInterfaceAlert(argv[2], bytes).isOk();
         sendGenericOkFail(cli, rc);
         return 0;
-
     }
     if (!strcmp(argv[1], "removeinterfacealert") || !strcmp(argv[1], "ria")) {
         if (argc != 3) {
@@ -685,25 +676,23 @@
         int rc = !mNetd->bandwidthRemoveInterfaceAlert(argv[2]).isOk();
         sendGenericOkFail(cli, rc);
         return 0;
-
     }
 
     cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown bandwidth cmd", false);
     return 0;
 }
 
-CommandListener::IdletimerControlCmd::IdletimerControlCmd() :
-    NetdCommand("idletimer") {
-}
+NdcDispatcher::IdletimerControlCmd::IdletimerControlCmd() : NdcNetdCommand("idletimer") {}
 
-int CommandListener::IdletimerControlCmd::runCommand(SocketClient *cli, int argc, char **argv) {
-  // TODO(ashish): Change the error statements
+int NdcDispatcher::IdletimerControlCmd::runCommand(NdcClient* cli, int argc, char** argv) const {
+    // TODO(ashish): Change the error statements
     if (argc < 2) {
         cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
         return 0;
     }
 
-    ALOGV("idletimerctrlcmd: argc=%d %s %s ...", argc, argv[0], argv[1]);
+    LOG(LOGLEVEL)
+            << StringPrintf("idletimerctrlcmd: argc=%d %s %s ...", argc, argv[0], argv[1]).c_str();
 
     if (!strcmp(argv[1], "add")) {
         if (argc != 5) {
@@ -717,7 +706,7 @@
         if (!status.isOk()) {
             cli->sendMsg(ResponseCode::OperationFailed, "Failed to add interface", false);
         } else {
-          cli->sendMsg(ResponseCode::CommandOkay,  "Add success", false);
+            cli->sendMsg(ResponseCode::CommandOkay, "Add success", false);
         }
         return 0;
     }
@@ -732,7 +721,7 @@
         if (!status.isOk()) {
             cli->sendMsg(ResponseCode::OperationFailed, "Failed to remove interface", false);
         } else {
-          cli->sendMsg(ResponseCode::CommandOkay, "Remove success", false);
+            cli->sendMsg(ResponseCode::CommandOkay, "Remove success", false);
         }
         return 0;
     }
@@ -741,11 +730,9 @@
     return 0;
 }
 
-CommandListener::FirewallCmd::FirewallCmd() :
-    NetdCommand("firewall") {
-}
+NdcDispatcher::FirewallCmd::FirewallCmd() : NdcNetdCommand("firewall") {}
 
-int CommandListener::FirewallCmd::sendGenericOkFail(SocketClient *cli, int cond) {
+int NdcDispatcher::FirewallCmd::sendGenericOkFail(NdcClient* cli, int cond) const {
     if (!cond) {
         cli->sendMsg(ResponseCode::CommandOkay, "Firewall command succeeded", false);
     } else {
@@ -754,29 +741,29 @@
     return 0;
 }
 
-int CommandListener::FirewallCmd::parseRule(const char* arg) {
+int NdcDispatcher::FirewallCmd::parseRule(const char* arg) {
     if (!strcmp(arg, "allow")) {
         return INetd::FIREWALL_RULE_ALLOW;
     } else if (!strcmp(arg, "deny")) {
         return INetd::FIREWALL_RULE_DENY;
     } else {
-        ALOGE("failed to parse uid rule (%s)", arg);
+        LOG(LOGLEVEL) << "failed to parse uid rule " << arg;
         return INetd::FIREWALL_RULE_ALLOW;
     }
 }
 
-int CommandListener::FirewallCmd::parseFirewallType(const char* arg) {
+int NdcDispatcher::FirewallCmd::parseFirewallType(const char* arg) {
     if (!strcmp(arg, "whitelist")) {
         return INetd::FIREWALL_WHITELIST;
     } else if (!strcmp(arg, "blacklist")) {
         return INetd::FIREWALL_BLACKLIST;
     } else {
-        ALOGE("failed to parse firewall type (%s)", arg);
+        LOG(LOGLEVEL) << "failed to parse firewall type " << arg;
         return INetd::FIREWALL_BLACKLIST;
     }
 }
 
-int CommandListener::FirewallCmd::parseChildChain(const char* arg) {
+int NdcDispatcher::FirewallCmd::parseChildChain(const char* arg) {
     if (!strcmp(arg, "dozable")) {
         return INetd::FIREWALL_CHAIN_DOZABLE;
     } else if (!strcmp(arg, "standby")) {
@@ -786,13 +773,12 @@
     } else if (!strcmp(arg, "none")) {
         return INetd::FIREWALL_CHAIN_NONE;
     } else {
-        ALOGE("failed to parse child firewall chain (%s)", arg);
+        LOG(LOGLEVEL) << "failed to parse child firewall chain " << arg;
         return -1;
     }
 }
 
-int CommandListener::FirewallCmd::runCommand(SocketClient *cli, int argc,
-        char **argv) {
+int NdcDispatcher::FirewallCmd::runCommand(NdcClient* cli, int argc, char** argv) const {
     if (argc < 2) {
         cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing command", false);
         return 0;
@@ -801,7 +787,7 @@
     if (!strcmp(argv[1], "enable")) {
         if (argc != 3) {
             cli->sendMsg(ResponseCode::CommandSyntaxError,
-                        "Usage: firewall enable <whitelist|blacklist>", false);
+                         "Usage: firewall enable <whitelist|blacklist>", false);
             return 0;
         }
         int res = !mNetd->firewallSetFirewallType(parseFirewallType(argv[2])).isOk();
@@ -829,8 +815,7 @@
         int childChain = parseChildChain(argv[2]);
         if (childChain == -1) {
             cli->sendMsg(ResponseCode::CommandSyntaxError,
-                         "Invalid chain name. Valid names are: <dozable|standby|none>",
-                         false);
+                         "Invalid chain name. Valid names are: <dozable|standby|none>", false);
             return 0;
         }
         uid_t uid = 0;
@@ -842,8 +827,7 @@
     if (!strcmp(argv[1], "enable_chain")) {
         if (argc != 3) {
             cli->sendMsg(ResponseCode::CommandSyntaxError,
-                         "Usage: firewall enable_chain <dozable|standby>",
-                         false);
+                         "Usage: firewall enable_chain <dozable|standby>", false);
             return 0;
         }
         int res = !mNetd->firewallEnableChildChain(parseChildChain(argv[2]), true).isOk();
@@ -853,8 +837,7 @@
     if (!strcmp(argv[1], "disable_chain")) {
         if (argc != 3) {
             cli->sendMsg(ResponseCode::CommandSyntaxError,
-                         "Usage: firewall disable_chain <dozable|standby>",
-                         false);
+                         "Usage: firewall disable_chain <dozable|standby>", false);
             return 0;
         }
         int res = !mNetd->firewallEnableChildChain(parseChildChain(argv[2]), false).isOk();
@@ -865,10 +848,9 @@
     return 0;
 }
 
-CommandListener::ClatdCmd::ClatdCmd() : NetdCommand("clatd") {
-}
+NdcDispatcher::ClatdCmd::ClatdCmd() : NdcNetdCommand("clatd") {}
 
-int CommandListener::ClatdCmd::runCommand(SocketClient* cli, int argc, char** argv) {
+int NdcDispatcher::ClatdCmd::runCommand(NdcClient* cli, int argc, char** argv) const {
     int rc = 0;
     if (argc < 3) {
         cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
@@ -900,11 +882,9 @@
     return 0;
 }
 
-CommandListener::StrictCmd::StrictCmd() :
-    NetdCommand("strict") {
-}
+NdcDispatcher::StrictCmd::StrictCmd() : NdcNetdCommand("strict") {}
 
-int CommandListener::StrictCmd::sendGenericOkFail(SocketClient *cli, int cond) {
+int NdcDispatcher::StrictCmd::sendGenericOkFail(NdcClient* cli, int cond) const {
     if (!cond) {
         cli->sendMsg(ResponseCode::CommandOkay, "Strict command succeeded", false);
     } else {
@@ -913,7 +893,7 @@
     return 0;
 }
 
-int CommandListener::StrictCmd::parsePenalty(const char* arg) {
+int NdcDispatcher::StrictCmd::parsePenalty(const char* arg) {
     if (!strcmp(arg, "reject")) {
         return INetd::PENALTY_POLICY_REJECT;
     } else if (!strcmp(arg, "log")) {
@@ -925,8 +905,7 @@
     }
 }
 
-int CommandListener::StrictCmd::runCommand(SocketClient *cli, int argc,
-        char **argv) {
+int NdcDispatcher::StrictCmd::runCommand(NdcClient* cli, int argc, char** argv) const {
     if (argc < 2) {
         cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing command", false);
         return 0;
@@ -935,8 +914,7 @@
     if (!strcmp(argv[1], "set_uid_cleartext_policy")) {
         if (argc != 4) {
             cli->sendMsg(ResponseCode::CommandSyntaxError,
-                         "Usage: strict set_uid_cleartext_policy <uid> <accept|log|reject>",
-                         false);
+                         "Usage: strict set_uid_cleartext_policy <uid> <accept|log|reject>", false);
             return 0;
         }
 
@@ -962,29 +940,28 @@
     return 0;
 }
 
-CommandListener::NetworkCommand::NetworkCommand() : NetdCommand("network") {
-}
+NdcDispatcher::NetworkCommand::NetworkCommand() : NdcNetdCommand("network") {}
 
-int CommandListener::NetworkCommand::syntaxError(SocketClient* client, const char* message) {
-    client->sendMsg(ResponseCode::CommandSyntaxError, message, false);
+int NdcDispatcher::NetworkCommand::syntaxError(NdcClient* cli, const char* message) const {
+    cli->sendMsg(ResponseCode::CommandSyntaxError, message, false);
     return 0;
 }
 
-int CommandListener::NetworkCommand::operationError(SocketClient* client, const char* message,
-                                                    int ret) {
+int NdcDispatcher::NetworkCommand::operationError(NdcClient* cli, const char* message,
+                                                  int ret) const {
     errno = ret;
-    client->sendMsg(ResponseCode::OperationFailed, message, true);
+    cli->sendMsg(ResponseCode::OperationFailed, message, true);
     return 0;
 }
 
-int CommandListener::NetworkCommand::success(SocketClient* client) {
-    client->sendMsg(ResponseCode::CommandOkay, "success", false);
+int NdcDispatcher::NetworkCommand::success(NdcClient* cli) const {
+    cli->sendMsg(ResponseCode::CommandOkay, "success", false);
     return 0;
 }
 
-int CommandListener::NetworkCommand::runCommand(SocketClient* client, int argc, char** argv) {
+int NdcDispatcher::NetworkCommand::runCommand(NdcClient* cli, int argc, char** argv) const {
     if (argc < 2) {
-        return syntaxError(client, "Missing argument");
+        return syntaxError(cli, "Missing argument");
     }
 
     //    0      1      2      3      4       5         6            7           8
@@ -994,7 +971,7 @@
     // nexthop may be either an IPv4/IPv6 address or one of "unreachable" or "throw".
     if (!strcmp(argv[1], "route")) {
         if (argc < 6 || argc > 9) {
-            return syntaxError(client, "Incorrect number of arguments");
+            return syntaxError(cli, "Incorrect number of arguments");
         }
 
         int nextArg = 2;
@@ -1003,19 +980,19 @@
         if (!strcmp(argv[nextArg], "legacy")) {
             ++nextArg;
             legacy = true;
-            PARSE_UINT_RETURN_IF_FAIL(client, argv[nextArg++], uid, "Unknown argument", false);
+            PARSE_UINT_RETURN_IF_FAIL(cli, argv[nextArg++], uid, "Unknown argument", false);
         }
 
         bool add = false;
         if (!strcmp(argv[nextArg], "add")) {
             add = true;
         } else if (strcmp(argv[nextArg], "remove")) {
-            return syntaxError(client, "Unknown argument");
+            return syntaxError(cli, "Unknown argument");
         }
         ++nextArg;
 
         if (argc < nextArg + 3 || argc > nextArg + 4) {
-            return syntaxError(client, "Incorrect number of arguments");
+            return syntaxError(cli, "Incorrect number of arguments");
         }
 
         unsigned netId = stringToNetId(argv[nextArg++]);
@@ -1035,11 +1012,11 @@
         }
 
         if (!status.isOk()) {
-            return operationError(client, add ? "addRoute() failed" : "removeRoute() failed",
+            return operationError(cli, add ? "addRoute() failed" : "removeRoute() failed",
                                   status.serviceSpecificErrorCode());
         }
 
-        return success(client);
+        return success(cli);
     }
 
     //    0        1       2       3         4
@@ -1047,23 +1024,23 @@
     // network interface remove <netId> <interface>
     if (!strcmp(argv[1], "interface")) {
         if (argc != 5) {
-            return syntaxError(client, "Missing argument");
+            return syntaxError(cli, "Missing argument");
         }
         unsigned netId = stringToNetId(argv[3]);
         if (!strcmp(argv[2], "add")) {
             if (Status status = mNetd->networkAddInterface(netId, argv[4]); !status.isOk()) {
-                return operationError(client, "addInterfaceToNetwork() failed",
+                return operationError(cli, "addInterfaceToNetwork() failed",
                                       status.serviceSpecificErrorCode());
             }
         } else if (!strcmp(argv[2], "remove")) {
             if (Status status = mNetd->networkRemoveInterface(netId, argv[4]); !status.isOk()) {
-                return operationError(client, "removeInterfaceFromNetwork() failed",
+                return operationError(cli, "removeInterfaceFromNetwork() failed",
                                       status.serviceSpecificErrorCode());
             }
         } else {
-            return syntaxError(client, "Unknown argument");
+            return syntaxError(cli, "Unknown argument");
         }
-        return success(client);
+        return success(cli);
     }
 
     //    0      1       2         3
@@ -1073,47 +1050,47 @@
     // network create <netId> vpn <secure>
     if (!strcmp(argv[1], "create")) {
         if (argc < 3) {
-            return syntaxError(client, "Missing argument");
+            return syntaxError(cli, "Missing argument");
         }
         unsigned netId = stringToNetId(argv[2]);
         if (argc == 6 && !strcmp(argv[3], "vpn")) {
             bool secure = strtol(argv[4], nullptr, 2);
             if (Status status = mNetd->networkCreateVpn(netId, secure); !status.isOk()) {
-                return operationError(client, "createVirtualNetwork() failed",
+                return operationError(cli, "createVirtualNetwork() failed",
                                       status.serviceSpecificErrorCode());
             }
         } else if (argc > 4) {
-            return syntaxError(client, "Unknown trailing argument(s)");
+            return syntaxError(cli, "Unknown trailing argument(s)");
         } else {
             int permission = INetd::PERMISSION_NONE;
             if (argc == 4) {
                 permission = stringToINetdPermission(argv[3]);
                 if (permission == INetd::PERMISSION_NONE) {
-                    return syntaxError(client, "Unknown permission");
+                    return syntaxError(cli, "Unknown permission");
                 }
             }
             if (Status status = mNetd->networkCreatePhysical(netId, permission); !status.isOk()) {
-                return operationError(client, "createPhysicalNetwork() failed",
+                return operationError(cli, "createPhysicalNetwork() failed",
                                       status.serviceSpecificErrorCode());
             }
         }
-        return success(client);
+        return success(cli);
     }
 
     //    0       1       2
     // network destroy <netId>
     if (!strcmp(argv[1], "destroy")) {
         if (argc != 3) {
-            return syntaxError(client, "Incorrect number of arguments");
+            return syntaxError(cli, "Incorrect number of arguments");
         }
         unsigned netId = stringToNetId(argv[2]);
         // Both of these functions manage their own locking internally.
         if (Status status = mNetd->networkDestroy(netId); !status.isOk()) {
-            return operationError(client, "destroyNetwork() failed",
+            return operationError(cli, "destroyNetwork() failed",
                                   status.serviceSpecificErrorCode());
         }
-        // TODO: add clearing DNS back after NDC migrating to binder ver.
-        return success(client);
+        mDnsResolver->clearResolverConfiguration(netId);
+        return success(cli);
     }
 
     //    0       1      2      3
@@ -1121,22 +1098,22 @@
     // network default clear
     if (!strcmp(argv[1], "default")) {
         if (argc < 3) {
-            return syntaxError(client, "Missing argument");
+            return syntaxError(cli, "Missing argument");
         }
         unsigned netId = NETID_UNSET;
         if (!strcmp(argv[2], "set")) {
             if (argc < 4) {
-                return syntaxError(client, "Missing netId");
+                return syntaxError(cli, "Missing netId");
             }
             netId = stringToNetId(argv[3]);
         } else if (strcmp(argv[2], "clear")) {
-            return syntaxError(client, "Unknown argument");
+            return syntaxError(cli, "Unknown argument");
         }
         if (Status status = mNetd->networkSetDefault(netId); status.isOk()) {
-            return operationError(client, "setDefaultNetwork() failed",
+            return operationError(cli, "setDefaultNetwork() failed",
                                   status.serviceSpecificErrorCode());
         }
-        return success(client);
+        return success(cli);
     }
 
     //    0        1         2      3        4          5
@@ -1146,27 +1123,27 @@
     // network permission network clear   <netId> ...
     if (!strcmp(argv[1], "permission")) {
         if (argc < 5) {
-            return syntaxError(client, "Missing argument");
+            return syntaxError(cli, "Missing argument");
         }
         int nextArg = 4;
         int permission = INetd::PERMISSION_NONE;
         if (!strcmp(argv[3], "set")) {
             permission = stringToINetdPermission(argv[4]);
             if (permission == INetd::PERMISSION_NONE) {
-                return syntaxError(client, "Unknown permission");
+                return syntaxError(cli, "Unknown permission");
             }
             nextArg = 5;
         } else if (strcmp(argv[3], "clear")) {
-            return syntaxError(client, "Unknown argument");
+            return syntaxError(cli, "Unknown argument");
         }
         if (nextArg == argc) {
-            return syntaxError(client, "Missing id");
+            return syntaxError(cli, "Missing id");
         }
 
         bool userPermissions = !strcmp(argv[2], "user");
         bool networkPermissions = !strcmp(argv[2], "network");
         if (!userPermissions && !networkPermissions) {
-            return syntaxError(client, "Unknown argument");
+            return syntaxError(cli, "Unknown argument");
         }
 
         std::vector<int32_t> ids;
@@ -1175,7 +1152,7 @@
                 char* endPtr;
                 unsigned id = strtoul(argv[nextArg], &endPtr, 0);
                 if (!*argv[nextArg] || *endPtr) {
-                    return syntaxError(client, "Invalid id");
+                    return syntaxError(cli, "Invalid id");
                 }
                 ids.push_back(id);
             } else {
@@ -1190,12 +1167,12 @@
             for (auto netId : ids) {
                 Status status = mNetd->networkSetPermissionForNetwork(netId, permission);
                 if (!status.isOk())
-                    return operationError(client, "setPermissionForNetworks() failed",
+                    return operationError(cli, "setPermissionForNetworks() failed",
                                           status.serviceSpecificErrorCode());
             }
         }
 
-        return success(client);
+        return success(cli);
     }
 
     //    0      1     2       3           4
@@ -1203,29 +1180,29 @@
     // network users remove <netId> [<uid>[-<uid>]] ...
     if (!strcmp(argv[1], "users")) {
         if (argc < 4) {
-            return syntaxError(client, "Missing argument");
+            return syntaxError(cli, "Missing argument");
         }
         unsigned netId = stringToNetId(argv[3]);
         UidRanges uidRanges;
         if (!uidRanges.parseFrom(argc - 4, argv + 4)) {
-            return syntaxError(client, "Invalid UIDs");
+            return syntaxError(cli, "Invalid UIDs");
         }
         if (!strcmp(argv[2], "add")) {
             if (Status status = mNetd->networkAddUidRanges(netId, uidRanges.getRanges());
                 !status.isOk()) {
-                return operationError(client, "addUsersToNetwork() failed",
+                return operationError(cli, "addUsersToNetwork() failed",
                                       status.serviceSpecificErrorCode());
             }
         } else if (!strcmp(argv[2], "remove")) {
             if (Status status = mNetd->networkRemoveUidRanges(netId, uidRanges.getRanges());
                 !status.isOk()) {
-                return operationError(client, "removeUsersFromNetwork() failed",
+                return operationError(cli, "removeUsersFromNetwork() failed",
                                       status.serviceSpecificErrorCode());
             }
         } else {
-            return syntaxError(client, "Unknown argument");
+            return syntaxError(cli, "Unknown argument");
         }
-        return success(client);
+        return success(cli);
     }
 
     //    0       1      2     3
@@ -1233,12 +1210,12 @@
     // network protect  deny <uid> ...
     if (!strcmp(argv[1], "protect")) {
         if (argc < 4) {
-            return syntaxError(client, "Missing argument");
+            return syntaxError(cli, "Missing argument");
         }
         std::vector<uid_t> uids;
         for (int i = 3; i < argc; ++i) {
             uid_t uid = 0;
-            PARSE_UINT_RETURN_IF_FAIL(client, argv[i], uid, "Unknown argument", false);
+            PARSE_UINT_RETURN_IF_FAIL(cli, argv[i], uid, "Unknown argument", false);
             uids.push_back(uid);
         }
         if (!strcmp(argv[2], "allow")) {
@@ -1250,12 +1227,12 @@
                 mNetd->networkSetProtectDeny(uid);
             }
         } else {
-            return syntaxError(client, "Unknown argument");
+            return syntaxError(cli, "Unknown argument");
         }
-        return success(client);
+        return success(cli);
     }
 
-    return syntaxError(client, "Unknown argument");
+    return syntaxError(cli, "Unknown argument");
 }
 
 }  // namespace net
diff --git a/server/NdcDispatcher.h b/server/NdcDispatcher.h
new file mode 100644
index 0000000..5732e22
--- /dev/null
+++ b/server/NdcDispatcher.h
@@ -0,0 +1,174 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _NDC_DISPATCHER_H__
+#define _NDC_DISPATCHER_H__
+
+#include <string>
+
+#include <android-base/logging.h>
+#include <android/net/IDnsResolver.h>
+#include <android/net/INetd.h>
+#include "binder/IServiceManager.h"
+
+#include "NetdConstants.h"
+
+namespace android {
+namespace net {
+
+class NdcClient {
+  public:
+    NdcClient() = default;
+    ~NdcClient() = default;
+
+    int sendMsg(int code, const char* msg, bool addErrno) {
+        if (addErrno) {
+            printf("%d 0 %s (%s)\n", code, msg, strerror(errno));
+        } else {
+            printf("%d 0 %s\n", code, msg);
+        }
+        return 0;
+    }
+};
+
+class NdcNetdCommand {
+  public:
+    NdcNetdCommand(std::string cmd) : mCommand(std::move(cmd)) {}
+    virtual ~NdcNetdCommand() {}
+
+    virtual int runCommand(NdcClient* c, int argc, char** argv) const = 0;
+
+    const std::string& getCommand() const { return mCommand; }
+
+  private:
+    std::string mCommand;
+};
+
+class NdcDispatcher {
+  public:
+    // Matches the restrictions previously imposed by CommandListener.cpp.
+    static const int CMD_ARGS_MAX = 26;
+    // Default log level is set to minimum one.
+    static const android::base::LogSeverity LOGLEVEL = android::base::VERBOSE;
+
+    NdcDispatcher();
+    ~NdcDispatcher() = default;
+
+    static sp<INetd> mNetd;
+    static sp<IDnsResolver> mDnsResolver;
+    NdcClient mNdc;
+
+    int dispatchCommand(int argc, char** argv);
+    void registerCmd(NdcNetdCommand* cmd);
+
+  private:
+    std::vector<NdcNetdCommand*> mCommands;
+
+    class InterfaceCmd : public NdcNetdCommand {
+      public:
+        InterfaceCmd();
+        virtual ~InterfaceCmd() {}
+        int runCommand(NdcClient* cli, int argc, char** argv) const;
+    };
+
+    class IpFwdCmd : public NdcNetdCommand {
+      public:
+        IpFwdCmd();
+        virtual ~IpFwdCmd() {}
+        int runCommand(NdcClient* cli, int argc, char** argv) const;
+    };
+
+    class TetherCmd : public NdcNetdCommand {
+      public:
+        TetherCmd();
+        virtual ~TetherCmd() {}
+        int runCommand(NdcClient* cli, int argc, char** argv) const;
+    };
+
+    class NatCmd : public NdcNetdCommand {
+      public:
+        NatCmd();
+        virtual ~NatCmd() {}
+        int runCommand(NdcClient* cli, int argc, char** argv) const;
+    };
+
+    class BandwidthControlCmd : public NdcNetdCommand {
+      public:
+        BandwidthControlCmd();
+        virtual ~BandwidthControlCmd() {}
+        int runCommand(NdcClient* cli, int argc, char** argv) const;
+
+      protected:
+        void sendGenericOkFail(NdcClient* cli, int cond) const;
+        void sendGenericOpFailed(NdcClient* cli, const char* errMsg) const;
+        void sendGenericSyntaxError(NdcClient* cli, const char* usageMsg) const;
+    };
+
+    class IdletimerControlCmd : public NdcNetdCommand {
+      public:
+        IdletimerControlCmd();
+        virtual ~IdletimerControlCmd() {}
+        int runCommand(NdcClient* cli, int argc, char** argv) const;
+    };
+
+    class FirewallCmd : public NdcNetdCommand {
+      public:
+        FirewallCmd();
+        virtual ~FirewallCmd() {}
+        int runCommand(NdcClient* cli, int argc, char** argv) const;
+
+      protected:
+        int sendGenericOkFail(NdcClient* cli, int cond) const;
+        static int parseRule(const char* arg);
+        static int parseFirewallType(const char* arg);
+        static int parseChildChain(const char* arg);
+    };
+
+    class ClatdCmd : public NdcNetdCommand {
+      public:
+        ClatdCmd();
+        virtual ~ClatdCmd() {}
+        int runCommand(NdcClient* cli, int argc, char** argv) const;
+    };
+
+    class StrictCmd : public NdcNetdCommand {
+      public:
+        StrictCmd();
+        virtual ~StrictCmd() {}
+        int runCommand(NdcClient* cli, int argc, char** argv) const;
+
+      protected:
+        int sendGenericOkFail(NdcClient* cli, int cond) const;
+        static int parsePenalty(const char* arg);
+    };
+
+    class NetworkCommand : public NdcNetdCommand {
+      public:
+        NetworkCommand();
+        virtual ~NetworkCommand() {}
+        int runCommand(NdcClient* cli, int argc, char** argv) const;
+
+      private:
+        int syntaxError(NdcClient* cli, const char* message) const;
+        int operationError(NdcClient* cli, const char* message, int ret) const;
+        int success(NdcClient* cli) const;
+    };
+};
+
+}  // namespace net
+}  // namespace android
+
+#endif
diff --git a/server/NetworkController.cpp b/server/NetworkController.cpp
index 9fc2c66..f7cb8dd 100644
--- a/server/NetworkController.cpp
+++ b/server/NetworkController.cpp
@@ -23,16 +23,15 @@
 // acquiring the lock. Private functions in this file should call xxxLocked() methods and access
 // internal state directly.
 
-#include "NetworkController.h"
-
 #define LOG_TAG "Netd"
-#include "log/log.h"
+
+#include "NetworkController.h"
 
 #include <android-base/strings.h>
 #include <cutils/misc.h>  // FIRST_APPLICATION_UID
 #include <netd_resolv/resolv.h>
 #include <netd_resolv/resolv_stub.h>
-#include "android/net/INetd.h"
+#include "log/log.h"
 
 #include "Controllers.h"
 #include "DummyNetwork.h"
@@ -59,12 +58,6 @@
 
 }  // namespace
 
-const unsigned NetworkController::MIN_OEM_ID   =  1;
-const unsigned NetworkController::MAX_OEM_ID   = 50;
-const unsigned NetworkController::DUMMY_NET_ID = 51;
-// NetIds 52..98 are reserved for future use.
-const unsigned NetworkController::LOCAL_NET_ID = INetd::LOCAL_NET_ID;
-
 // All calls to methods here are made while holding a write lock on mRWLock.
 // They are mostly not called directly from this class, but from methods in PhysicalNetwork.cpp.
 // However, we're the only user of that class, so all calls to those methods come from here and are
diff --git a/server/NetworkController.h b/server/NetworkController.h
index d765ae7..0522b6d 100644
--- a/server/NetworkController.h
+++ b/server/NetworkController.h
@@ -17,12 +17,13 @@
 #ifndef NETD_SERVER_NETWORK_CONTROLLER_H
 #define NETD_SERVER_NETWORK_CONTROLLER_H
 
-
 #include <android-base/thread_annotations.h>
 #include <android/multinetwork.h>
 
+
 #include "NetdConstants.h"
 #include "Permission.h"
+#include "android/net/INetd.h"
 #include "netdutils/DumpWriter.h"
 
 #include <sys/types.h>
@@ -83,10 +84,11 @@
  */
 class NetworkController {
 public:
-    static const unsigned MIN_OEM_ID;
-    static const unsigned MAX_OEM_ID;
-    static const unsigned LOCAL_NET_ID;
-    static const unsigned DUMMY_NET_ID;
+    // NetIds 52..98 are reserved for future use.
+    static const unsigned MIN_OEM_ID = 1;
+    static const unsigned MAX_OEM_ID = 50;
+    static const unsigned LOCAL_NET_ID = INetd::LOCAL_NET_ID;
+    static const unsigned DUMMY_NET_ID = 51;
 
     NetworkController();
 
diff --git a/server/main.cpp b/server/main.cpp
index 45b968d..b783ce5 100644
--- a/server/main.cpp
+++ b/server/main.cpp
@@ -37,7 +37,6 @@
 #include <binder/IServiceManager.h>
 #include <netdutils/Stopwatch.h>
 
-#include "CommandListener.h"
 #include "Controllers.h"
 #include "FwmarkServer.h"
 #include "MDnsSdListener.h"
@@ -54,7 +53,6 @@
 using android::IPCThreadState;
 using android::status_t;
 using android::String16;
-using android::net::CommandListener;
 using android::net::FwmarkServer;
 using android::net::gCtls;
 using android::net::gLog;
@@ -105,10 +103,8 @@
     // Before we do anything that could fork, mark CLOEXEC the UNIX sockets that we get from init.
     // FrameworkListener does this on initialization as well, but we only initialize these
     // components after having initialized other subsystems that can fork.
-    for (const auto& sock : { CommandListener::SOCKET_NAME,
-                              DNSPROXYLISTENER_SOCKET_NAME,
-                              FwmarkServer::SOCKET_NAME,
-                              MDnsSdListener::SOCKET_NAME }) {
+    for (const auto& sock :
+         {DNSPROXYLISTENER_SOCKET_NAME, FwmarkServer::SOCKET_NAME, MDnsSdListener::SOCKET_NAME}) {
         setCloseOnExec(sock);
     }
 
@@ -130,20 +126,6 @@
     gCtls = new android::net::Controllers();
     gCtls->init();
 
-    // NetdNativeService must start before CommandListener.
-    // TODO: put NetdNativeService starting back after subsystems started
-    // after migrating CommandListener to NDC, aosp/929861.
-    Stopwatch subTime;
-    status_t ret;
-    if ((ret = NetdNativeService::start()) != android::OK) {
-        ALOGE("Unable to start NetdNativeService: %d", ret);
-        exit(1);
-    }
-    gLog.info("Registering NetdNativeService: %.1fms", subTime.getTimeAndReset());
-
-    CommandListener cl;
-    nm->setBroadcaster((SocketListener *) &cl);
-
     if (nm->start()) {
         ALOGE("Unable to start NetlinkManager (%s)", strerror(errno));
         exit(1);
@@ -187,15 +169,13 @@
         exit(1);
     }
 
-    /*
-     * Now that we're up, we can respond to commands. Starting the listener also tells
-     * NetworkManagementService that we are up and that our binder interface is ready.
-     */
-    if (cl.startListener()) {
-        ALOGE("Unable to start CommandListener (%s)", strerror(errno));
+    Stopwatch subTime;
+    status_t ret;
+    if ((ret = NetdNativeService::start()) != android::OK) {
+        ALOGE("Unable to start NetdNativeService: %d", ret);
         exit(1);
     }
-    gLog.info("Starting CommandListener: %.1fms", subTime.getTimeAndReset());
+    gLog.info("Registering NetdNativeService: %.1fms", subTime.getTimeAndReset());
 
     android::net::process::ScopedPidFile pidFile(PID_FILE_PATH);
 
diff --git a/server/ndc.cpp b/server/ndc.cpp
index ec59637..dbf6458 100644
--- a/server/ndc.cpp
+++ b/server/ndc.cpp
@@ -16,165 +16,23 @@
 
 #include <stdio.h>
 #include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
-#include <signal.h>
-#include <errno.h>
-#include <fcntl.h>
 
-#include <sys/poll.h>
-#include <sys/socket.h>
-#include <sys/time.h>
-#include <sys/types.h>
-#include <sys/un.h>
+#include "NdcDispatcher.h"
 
-#include <cutils/sockets.h>
-#include <private/android_filesystem_config.h>
+namespace {
 
-static void usage(char *progname);
-static int do_monitor(int sock, int stop_after_cmd);
-static int do_cmd(int sock, int argc, char **argv);
-
-int main(int argc, char **argv) {
-    int sock;
-    int cmdOffset = 0;
-
-    if (argc < 2)
-        usage(argv[0]);
-
-    // try interpreting the first arg as the socket name - if it fails go back to netd
-
-    if ((sock = socket_local_client(argv[1],
-                                     ANDROID_SOCKET_NAMESPACE_RESERVED,
-                                     SOCK_STREAM)) < 0) {
-        if ((sock = socket_local_client("netd",
-                                         ANDROID_SOCKET_NAMESPACE_RESERVED,
-                                         SOCK_STREAM)) < 0) {
-            fprintf(stderr, "Error connecting (%s)\n", strerror(errno));
-            exit(4);
-        }
-    } else {
-        if (argc < 3) usage(argv[0]);
-        printf("Using alt socket %s\n", argv[1]);
-        cmdOffset = 1;
-    }
-
-    if (!strcmp(argv[1+cmdOffset], "monitor"))
-        exit(do_monitor(sock, 0));
-    exit(do_cmd(sock, argc-cmdOffset, &(argv[cmdOffset])));
-}
-
-static int do_cmd(int sock, int argc, char **argv) {
-    char *final_cmd;
-    char *conv_ptr;
-    int i;
-
-    /* Check if 1st arg is cmd sequence number */ 
-    strtol(argv[1], &conv_ptr, 10);
-    if (conv_ptr == argv[1]) {
-        final_cmd = strdup("0 ");
-    } else {
-        final_cmd = strdup("");
-    }
-    if (final_cmd == nullptr) {
-        int res = errno;
-        perror("strdup failed");
-        return res;
-    }
-
-    for (i = 1; i < argc; i++) {
-        if (strchr(argv[i], '"')) {
-            perror("argument with embedded quotes not allowed");
-            free(final_cmd);
-            return 1;
-        }
-        bool needs_quoting = strchr(argv[i], ' ');
-        const char *format = needs_quoting ? "%s\"%s\"%s" : "%s%s%s";
-        char *tmp_final_cmd;
-
-        if (asprintf(&tmp_final_cmd, format, final_cmd, argv[i],
-                     (i == (argc - 1)) ? "" : " ") < 0) {
-            int res = errno;
-            perror("failed asprintf");
-            free(final_cmd);
-            return res;
-        }
-        free(final_cmd);
-        final_cmd = tmp_final_cmd;
-    }
-
-    if (write(sock, final_cmd, strlen(final_cmd) + 1) < 0) {
-        int res = errno;
-        perror("write");
-        free(final_cmd);
-        return res;
-    }
-    free(final_cmd);
-
-    return do_monitor(sock, 1);
-}
-
-static int do_monitor(int sock, int stop_after_cmd) {
-    char *buffer = (char *)malloc(4096);
-
-    if (!stop_after_cmd)
-        printf("[Connected to Netd]\n");
-
-    while(1) {
-        int rc = 0;
-        struct pollfd fds = { .fd = sock, .events = POLLIN };
-        const int timeout_msecs = 10 * 1000;
-        rc = TEMP_FAILURE_RETRY(poll(&fds, 1, timeout_msecs));
-        if (rc < 0) {
-            int res = errno;
-            fprintf(stderr, "Error in poll(): %s\n", strerror(res));
-            free(buffer);
-            return res;
-        }
-        if (rc == 0) {
-            continue;
-        }
-        if (!(fds.revents & (POLLIN | POLLERR))) {
-            continue;
-        }
-
-        memset(buffer, 0, 4096);
-        if ((rc = read(sock, buffer, 4096)) <= 0) {
-            int res = errno;
-            if (rc == 0)
-                fprintf(stderr, "Lost connection to Netd - did it crash?\n");
-            else
-                fprintf(stderr, "Error reading data (%s)\n", strerror(res));
-            free(buffer);
-            if (rc == 0)
-                return ECONNRESET;
-            return res;
-        }
-
-        int offset = 0;
-        int i = 0;
-
-        for (i = 0; i < rc; i++) {
-            if (buffer[i] == '\0') {
-                char tmp[4];
-                strncpy(tmp, buffer + offset, 3);
-                tmp[3] = '\0';
-                long code = strtol(tmp, nullptr, 10);
-
-                printf("%s\n", buffer + offset);
-                if (stop_after_cmd) {
-                    if (code >= 200 && code < 600)
-                        return 0;
-                }
-                offset = i + 1;
-            }
-        }
-    }
-    free(buffer);
-    return 0;
-}
-
-static void usage(char *progname) {
-    fprintf(stderr, "Usage: %s [<sockname>] ([monitor] | ([<cmd_seq_num>] <cmd> [arg ...]))\n", progname);
+void usage(char* progname) {
+    fprintf(stderr, "Usage: %s (<cmd> [arg ...])\n", progname);
     exit(1);
 }
+
+}  // namespace
+
+int main(int argc, char** argv) {
+    if (argc < 2) {
+        usage(argv[0]);
+    }
+
+    android::net::NdcDispatcher nd;
+    exit(nd.dispatchCommand(argc - 1, argv + 1));
+}