DO NOT MERGE ANYWHERE - bionic: resolver: exclude a range of ports from random_bind in DNS

Add a new API to set a range of ports which the DNS resolver should
never try to bind

Bug: 20127213
Change-Id: Ie3fca0ec2ee2523625816edd9417a0b5d5f91614
diff --git a/libc/dns/include/resolv_netid.h b/libc/dns/include/resolv_netid.h
index e5521b8..3f174be 100644
--- a/libc/dns/include/resolv_netid.h
+++ b/libc/dns/include/resolv_netid.h
@@ -75,6 +75,9 @@
 /* delete the cache associated with a certain network */
 extern void _resolv_delete_cache_for_net(unsigned netid);
 
+/* set a port range for exclusion in the random_bind */
+int _resolv_set_port_exclusion_range(in_port_t min, in_port_t max) __used_in_netd;
+
 __END_DECLS
 
 #endif /* _RESOLV_NETID_H */
diff --git a/libc/dns/resolv/res_send.c b/libc/dns/resolv/res_send.c
index a8da3ac..d9feedb 100644
--- a/libc/dns/resolv/res_send.c
+++ b/libc/dns/resolv/res_send.c
@@ -137,6 +137,10 @@
 #define EXT(res) ((res)->_u._ext)
 #define DBG 0
 
+#define MAX_PORT (1 << (sizeof(in_port_t)*8))-1
+#define DNS_MIN_PORT (IPPORT_RESERVED+1)
+#define DNS_MAX_EXCLUDED_PORTS 5000
+
 static const int highestFD = FD_SETSIZE - 1;
 
 /* Forward. */
@@ -164,6 +168,27 @@
 			const struct timespec *finish);
 
 /* BIONIC-BEGIN: implement source port randomization */
+static volatile in_port_t exclusion_min = 0;
+static volatile in_port_t exclusion_max = 0;
+
+int _resolv_set_port_exclusion_range(in_port_t min, in_port_t max)
+{
+    if (min == 0 && max == 0) {
+        exclusion_min = exclusion_max = 0;
+        return 0;
+    }
+
+    if (min < DNS_MIN_PORT || min > max
+            || (max - min > DNS_MAX_EXCLUDED_PORTS)) {
+        errno = ERANGE;
+        return -1;
+    }
+
+    exclusion_min = min;
+    exclusion_max = max;
+    return 0;
+}
+
 typedef union {
     struct sockaddr      sa;
     struct sockaddr_in   sin;
@@ -197,7 +222,13 @@
     /* first try to bind to a random source port a few times */
     for (j = 0; j < 10; j++) {
         /* find a random port between 1025 .. 65534 */
-        int  port = 1025 + (res_randomid() % (65535-1025));
+        in_port_t port;
+        do {
+            port = DNS_MIN_PORT + (res_randomid() % (MAX_PORT - DNS_MIN_PORT));
+        } while (exclusion_min
+                && exclusion_max
+                && port >= exclusion_min && port <= exclusion_max);
+
         if (family == AF_INET)
             u.sin.sin_port = htons(port);
         else