Add oif rules that allow UID 0 to bypass the VPN.

This is needed for wifi calling so that the kernel (which does
not set marks) can tee packets towards the modem. It also fixes
things like not being able to reply to DHCP requests from
tethered clients when a VPN is up.

System apps can already bypass the VPN using explicit marks, so
allowing UID 0 to do so does not create additional bypass VPN
issues.

Bug: 19500693
Change-Id: Ie324026893637e9bd8e7aa65a37579569390e7b7
diff --git a/server/RouteController.cpp b/server/RouteController.cpp
index 6a6a470..4073405 100644
--- a/server/RouteController.cpp
+++ b/server/RouteController.cpp
@@ -38,6 +38,7 @@
 // BEGIN CONSTANTS --------------------------------------------------------------------------------
 
 const uint32_t RULE_PRIORITY_VPN_OVERRIDE_SYSTEM = 10000;
+const uint32_t RULE_PRIORITY_VPN_OVERRIDE_OIF    = 10500;
 const uint32_t RULE_PRIORITY_VPN_OUTPUT_TO_LOCAL = 11000;
 const uint32_t RULE_PRIORITY_SECURE_VPN          = 12000;
 const uint32_t RULE_PRIORITY_EXPLICIT_NETWORK    = 13000;
@@ -539,15 +540,25 @@
 //
 // Supports apps that use SO_BINDTODEVICE or IP_PKTINFO options and the kernel that already knows
 // the outgoing interface (typically for link-local communications).
-WARN_UNUSED_RESULT int modifyOutputInterfaceRule(const char* interface, uint32_t table,
-                                                 Permission permission, uid_t uidStart,
-                                                 uid_t uidEnd, bool add) {
+WARN_UNUSED_RESULT int modifyOutputInterfaceRules(const char* interface, uint32_t table,
+                                                  Permission permission, uid_t uidStart,
+                                                  uid_t uidEnd, bool add) {
     Fwmark fwmark;
     Fwmark mask;
 
     fwmark.permission = permission;
     mask.permission = permission;
 
+    // If this rule does not specify a UID range, then also add a corresponding high-priority rule
+    // for UID. This covers forwarded packets and system daemons such as the tethering DHCP server.
+    if (uidStart == INVALID_UID && uidEnd == INVALID_UID) {
+        if (int ret = modifyIpRule(add ? RTM_NEWRULE : RTM_DELRULE, RULE_PRIORITY_VPN_OVERRIDE_OIF,
+                                   table, fwmark.intValue, mask.intValue, IIF_NONE, interface,
+                                   UID_ROOT, UID_ROOT)) {
+            return ret;
+        }
+    }
+
     return modifyIpRule(add ? RTM_NEWRULE : RTM_DELRULE, RULE_PRIORITY_OUTPUT_INTERFACE, table,
                         fwmark.intValue, mask.intValue, IIF_NONE, interface, uidStart, uidEnd);
 }
@@ -663,9 +674,9 @@
         return -errno;
     }
 
-    if ((ret = modifyOutputInterfaceRule(interface, table, PERMISSION_NONE,
-                                         INVALID_UID, INVALID_UID, ACTION_ADD))) {
-        ALOGE("Can't create oif rule for %s: %s", interface, strerror(-ret));
+    if ((ret = modifyOutputInterfaceRules(interface, table, PERMISSION_NONE,
+                                          INVALID_UID, INVALID_UID, ACTION_ADD))) {
+        ALOGE("Can't create oif rules for %s: %s", interface, strerror(-ret));
         return ret;
     }
 
@@ -711,8 +722,8 @@
     if (int ret = modifyIncomingPacketMark(netId, interface, PERMISSION_NONE, add)) {
         return ret;
     }
-    return modifyOutputInterfaceRule(interface, ROUTE_TABLE_LOCAL_NETWORK, PERMISSION_NONE,
-                                     INVALID_UID, INVALID_UID, add);
+    return modifyOutputInterfaceRules(interface, ROUTE_TABLE_LOCAL_NETWORK, PERMISSION_NONE,
+                                      INVALID_UID, INVALID_UID, add);
 }
 
 WARN_UNUSED_RESULT int modifyPhysicalNetwork(unsigned netId, const char* interface,
@@ -729,7 +740,7 @@
                                             add)) {
         return ret;
     }
-    if (int ret = modifyOutputInterfaceRule(interface, table, permission, INVALID_UID, INVALID_UID,
+    if (int ret = modifyOutputInterfaceRules(interface, table, permission, INVALID_UID, INVALID_UID,
                                             add)) {
         return ret;
     }
@@ -752,8 +763,8 @@
                                                 range.second, add)) {
             return ret;
         }
-        if (int ret = modifyOutputInterfaceRule(interface, table, PERMISSION_NONE, range.first,
-                                                range.second, add)) {
+        if (int ret = modifyOutputInterfaceRules(interface, table, PERMISSION_NONE, range.first,
+                                                 range.second, add)) {
             return ret;
         }
     }