Add libconnectivity_native

The library provides an interface to interface with the
ConnectivityNative service, and implement port blocking APIs.

Bug: 179733303
Test: atest connectivity_native_test
Change-Id: Iad1c84b5eeab835aca14a2db72a900e099aa3c1c
diff --git a/service/libconnectivity/Android.bp b/service/libconnectivity/Android.bp
new file mode 100644
index 0000000..391ceac
--- /dev/null
+++ b/service/libconnectivity/Android.bp
@@ -0,0 +1,57 @@
+//
+// Copyright (C) 2022 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.
+//
+
+package {
+    // See: http://go/android-license-faq
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+cc_library_shared {
+    name: "libcom.android.tethering.connectivity_native",
+    srcs: [
+        "src/**/*.cpp",
+    ],
+    min_sdk_version: "30",
+    static_libs: [
+        "connectivity_native_aidl_interface-V1-ndk",
+    ],
+    export_include_dirs: ["include"],
+    cflags: [
+        "-Wall",
+        "-Werror",
+        "-Wno-error=deprecated-declarations",
+    ],
+
+    shared_libs: [
+        "libbinder_ndk",
+    ],
+    llndk: {
+        symbol_file: "libconnectivity_native.map.txt",
+    },
+    stubs: {
+        symbol_file: "libconnectivity_native.map.txt",
+        versions: [
+            "current",
+        ],
+    },
+    header_abi_checker: {
+        enabled: true,
+        symbol_file: "libconnectivity_native.map.txt",
+    },
+    apex_available: [
+        "com.android.tethering",
+    ],
+}
diff --git a/service/libconnectivity/include/connectivity_native.h b/service/libconnectivity/include/connectivity_native.h
new file mode 100644
index 0000000..5a2509a
--- /dev/null
+++ b/service/libconnectivity/include/connectivity_native.h
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2022 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 LIBCONNECTIVITY_CONNECTIVITY_NATIVE_H_
+#define LIBCONNECTIVITY_CONNECTIVITY_NATIVE_H_
+
+#include <sys/cdefs.h>
+#include <netinet/in.h>
+
+// For branches that do not yet have __ANDROID_API_U__ defined, like module
+// release branches.
+#ifndef __ANDROID_API_U__
+#define __ANDROID_API_U__ 34
+#endif
+
+__BEGIN_DECLS
+
+/**
+ * Blocks a port from being assigned during bind(). The caller is responsible for updating
+ * /proc/sys/net/ipv4/ip_local_port_range with the port being blocked so that calls to connect()
+ * will not automatically assign one of the blocked ports.
+ * Will return success even if port was already blocked.
+ *
+ * Returns 0 on success, or a POSIX error code (see errno.h) on failure:
+ *  - EINVAL for invalid port number
+ *  - EPERM if the UID of the client doesn't have network stack permission
+ *  - Other errors as per https://man7.org/linux/man-pages/man2/bpf.2.html
+ *
+ * @param port Int corresponding to port number.
+ */
+int AConnectivityNative_blockPortForBind(in_port_t port) __INTRODUCED_IN(__ANDROID_API_U__);
+
+/**
+ * Unblocks a port that has previously been blocked.
+ * Will return success even if port was already unblocked.
+ *
+ * Returns 0 on success, or a POSIX error code (see errno.h) on failure:
+ *  - EINVAL for invalid port number
+ *  - EPERM if the UID of the client doesn't have network stack permission
+ *  - Other errors as per https://man7.org/linux/man-pages/man2/bpf.2.html
+ *
+ * @param port Int corresponding to port number.
+ */
+int AConnectivityNative_unblockPortForBind(in_port_t port) __INTRODUCED_IN(__ANDROID_API_U__);
+
+/**
+ * Unblocks all ports that have previously been blocked.
+ *
+ * Returns 0 on success, or a POSIX error code (see errno.h) on failure:
+ *  - EINVAL for invalid port number
+ *  - EPERM if the UID of the client doesn't have network stack permission
+ *  - Other errors as per https://man7.org/linux/man-pages/man2/bpf.2.html
+ */
+int AConnectivityNative_unblockAllPortsForBind() __INTRODUCED_IN(__ANDROID_API_U__);
+
+/**
+ * Gets the list of ports that have been blocked.
+ *
+ * Returns 0 on success, or a POSIX error code (see errno.h) on failure:
+ *  - EINVAL for invalid port number
+ *  - EPERM if the UID of the client doesn't have network stack permission
+ *  - Other errors as per https://man7.org/linux/man-pages/man2/bpf.2.html
+ *
+ * @param ports Array of ports that will be filled with the port numbers.
+ * @param count Pointer to the size of the ports array; the value will be set to the total number of
+ *              blocked ports, which may be larger than the ports array that was filled.
+ */
+int AConnectivityNative_getPortsBlockedForBind(in_port_t *ports, size_t *count)
+    __INTRODUCED_IN(__ANDROID_API_U__);
+
+__END_DECLS
+
+
+#endif
diff --git a/service/libconnectivity/libconnectivity_native.map.txt b/service/libconnectivity/libconnectivity_native.map.txt
new file mode 100644
index 0000000..19b1074
--- /dev/null
+++ b/service/libconnectivity/libconnectivity_native.map.txt
@@ -0,0 +1,24 @@
+#
+# Copyright (C) 2022 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.
+#
+LIBCONNECTIVITY_NATIVE {
+  global:
+    AConnectivityNative_blockPortForBind; # apex llndk
+    AConnectivityNative_getPortsBlockedForBind; # apex llndk
+    AConnectivityNative_unblockPortForBind; # apex llndk
+    AConnectivityNative_unblockAllPortsForBind; # apex llndk
+  local:
+    *;
+};
diff --git a/service/libconnectivity/src/connectivity_native.cpp b/service/libconnectivity/src/connectivity_native.cpp
new file mode 100644
index 0000000..9545ed1
--- /dev/null
+++ b/service/libconnectivity/src/connectivity_native.cpp
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+
+#include "connectivity_native.h"
+
+#include <android/binder_manager.h>
+#include <aidl/android/net/connectivity/aidl/ConnectivityNative.h>
+
+using aidl::android::net::connectivity::aidl::IConnectivityNative;
+
+
+static std::shared_ptr<IConnectivityNative> getBinder() {
+    static ndk::SpAIBinder sBinder = ndk::SpAIBinder(reinterpret_cast<AIBinder*>(
+        AServiceManager_getService("connectivity_native")));
+    return aidl::android::net::connectivity::aidl::IConnectivityNative::fromBinder(sBinder);
+}
+
+static int getErrno(const ::ndk::ScopedAStatus& status) {
+    switch (status.getExceptionCode()) {
+        case EX_NONE:
+            return 0;
+        case EX_ILLEGAL_ARGUMENT:
+            return EINVAL;
+        case EX_SECURITY:
+            return EPERM;
+        case EX_SERVICE_SPECIFIC:
+            return status.getServiceSpecificError();
+        default:
+            return EPROTO;
+    }
+}
+
+int AConnectivityNative_blockPortForBind(in_port_t port) {
+    std::shared_ptr<IConnectivityNative> c = getBinder();
+    return getErrno(c->blockPortForBind(port));
+}
+
+int AConnectivityNative_unblockPortForBind(in_port_t port) {
+    std::shared_ptr<IConnectivityNative> c = getBinder();
+    return getErrno(c->unblockPortForBind(port));
+}
+
+int AConnectivityNative_unblockAllPortsForBind() {
+    std::shared_ptr<IConnectivityNative> c = getBinder();
+    return getErrno(c->unblockAllPortsForBind());
+}
+
+int AConnectivityNative_getPortsBlockedForBind(in_port_t *ports, size_t *count) {
+    std::shared_ptr<IConnectivityNative> c = getBinder();
+    std::vector<int32_t> actualBlockedPorts;
+    int err = getErrno(c->getPortsBlockedForBind(&actualBlockedPorts));
+    if (err) {
+        return err;
+    }
+
+    for (int i = 0; i < *count && i < actualBlockedPorts.size(); i++) {
+        ports[i] = actualBlockedPorts[i];
+    }
+    *count = actualBlockedPorts.size();
+    return 0;
+}