From 081db840befec895fb86e709ae95832ade2d065c Mon Sep 17 00:00:00 2001 From: Chad Brubaker Date: Fri, 21 Feb 2014 10:39:41 -0800 Subject: [PATCH] Allow overlap in resolv uid => DNS iface mapping When multiple rules exist covering a given uid the one added most recently will be used. This allows us to handle the simultaneous tuns case where a new tun is coming online for an already running VPN. _resolv_clear_iface_for_uid_range now also takes the iface and removes only that matching (iface, uid range) entry. Bug: 12134439 Change-Id: I9b9cfcfae2f38c409022a8c76ccadad7e2babd78 --- libc/netbsd/resolv/res_cache.c | 60 +++++++++++----------------------- libc/private/resolv_iface.h | 10 +++--- 2 files changed, 24 insertions(+), 46 deletions(-) diff --git a/libc/netbsd/resolv/res_cache.c b/libc/netbsd/resolv/res_cache.c index 8a6dc83ac..1a0c40c25 100644 --- a/libc/netbsd/resolv/res_cache.c +++ b/libc/netbsd/resolv/res_cache.c @@ -1852,9 +1852,7 @@ static void _remove_pidiface_info_locked(int pid); static struct resolv_pidiface_info* _get_pid_iface_info_locked(int pid); /* remove a resolv_pidiface_info structure from _res_uidiface_list */ -static int _remove_uidiface_info_locked(int uid_start, int uid_end); -/* check if a range [low,high] overlaps with any already existing ranges in the uid=>iface map*/ -static int _resolv_check_uid_range_overlap_locked(int uid_start, int uid_end); +static int _remove_uidiface_info_locked(const char* iface, int uid_start, int uid_end); /* get a resolv_uidiface_info structure from _res_uidiface_list with a certain uid */ static struct resolv_uidiface_info* _get_uid_iface_info_locked(int uid); @@ -2433,11 +2431,11 @@ _resolv_get_pids_associated_interface(int pid, char* buff, int buffLen) } static int -_remove_uidiface_info_locked(int uid_start, int uid_end) { +_remove_uidiface_info_locked(const char* ifname, int uid_start, int uid_end) { struct resolv_uidiface_info* result = _res_uidiface_list.next; struct resolv_uidiface_info* prev = &_res_uidiface_list; - - while (result != NULL && result->uid_start != uid_start && result->uid_end != uid_end) { + while (result != NULL && !(result->uid_start == uid_start && result->uid_end == uid_end && + !strcmp(result->ifname, ifname))) { prev = result; result = result->next; } @@ -2461,19 +2459,6 @@ _get_uid_iface_info_locked(int uid) return result; } -static int -_resolv_check_uid_range_overlap_locked(int uid_start, int uid_end) -{ - struct resolv_uidiface_info* cur = _res_uidiface_list.next; - while (cur != NULL) { - if (cur->uid_start <= uid_end && cur->uid_end >= uid_start) { - return -1; - } - cur = cur->next; - } - return 0; -} - void _resolv_clear_iface_uid_range_mapping() { @@ -2518,28 +2503,21 @@ _resolv_set_iface_for_uid_range(const char* ifname, int uid_start, int uid_end) return -1; } pthread_mutex_lock(&_res_uidiface_list_lock); - //check that we aren't adding an overlapping range - if (!_resolv_check_uid_range_overlap_locked(uid_start, uid_end)) { - uidiface_info = calloc(sizeof(*uidiface_info), 1); - if (uidiface_info) { - uidiface_info->uid_start = uid_start; - uidiface_info->uid_end = uid_end; - int len = sizeof(uidiface_info->ifname); - strncpy(uidiface_info->ifname, ifname, len - 1); - uidiface_info->ifname[len - 1] = '\0'; + uidiface_info = calloc(sizeof(*uidiface_info), 1); + if (uidiface_info) { + uidiface_info->uid_start = uid_start; + uidiface_info->uid_end = uid_end; + int len = sizeof(uidiface_info->ifname); + strncpy(uidiface_info->ifname, ifname, len - 1); + uidiface_info->ifname[len - 1] = '\0'; - uidiface_info->next = _res_uidiface_list.next; - _res_uidiface_list.next = uidiface_info; + uidiface_info->next = _res_uidiface_list.next; + _res_uidiface_list.next = uidiface_info; - XLOG("_resolv_set_iface_for_uid_range: [%d,%d], iface %s\n", uid_start, uid_end, - ifname); - } else { - XLOG("_resolv_set_iface_for_uid_range failing calloc\n"); - rv = -1; - errno = EINVAL; - } + XLOG("_resolv_set_iface_for_uid_range: [%d,%d], iface %s\n", uid_start, uid_end, + ifname); } else { - XLOG("_resolv_set_iface_for_uid_range range [%d,%d] overlaps\n", uid_start, uid_end); + XLOG("_resolv_set_iface_for_uid_range failing calloc\n"); rv = -1; errno = EINVAL; } @@ -2549,14 +2527,14 @@ _resolv_set_iface_for_uid_range(const char* ifname, int uid_start, int uid_end) } int -_resolv_clear_iface_for_uid_range(int uid_start, int uid_end) +_resolv_clear_iface_for_uid_range(const char* ifname, int uid_start, int uid_end) { pthread_once(&_res_cache_once, _res_cache_init); pthread_mutex_lock(&_res_uidiface_list_lock); - int rv = _remove_uidiface_info_locked(uid_start, uid_end); + int rv = _remove_uidiface_info_locked(ifname, uid_start, uid_end); - XLOG("_resolv_clear_iface_for_uid_range: [%d,%d]\n", uid_start, uid_end); + XLOG("_resolv_clear_iface_for_uid_range: [%d,%d] iface %s\n", uid_start, uid_end, ifname); pthread_mutex_unlock(&_res_uidiface_list_lock); diff --git a/libc/private/resolv_iface.h b/libc/private/resolv_iface.h index ad427930b..5d24124d0 100644 --- a/libc/private/resolv_iface.h +++ b/libc/private/resolv_iface.h @@ -79,13 +79,12 @@ extern void _resolv_clear_iface_pid_mapping(); extern int _resolv_get_pids_associated_interface(int pid, char* buff, int buffLen); -/** set a uid range to use the name servers of the specified interface - * If [low,high] overlaps with an already existing rule -1 is returned */ +/** set a uid range to use the name servers of the specified interface */ extern int _resolv_set_iface_for_uid_range(const char* ifname, int uid_start, int uid_end); -/* clear a uid range from being associated with an interface - * If the range given is not mapped -1 is returned. */ -extern int _resolv_clear_iface_for_uid_range(int uid_start, int uid_end); +/** Remove a mapping added by _resolv_set_iface_for_uid_range. + * If no such rule exists -1 is returned. */ +extern int _resolv_clear_iface_for_uid_range(const char* ifname, int uid_start, int uid_end); /* clear the entire mapping of uid ranges to interfaces. */ extern void _resolv_clear_iface_uid_range_mapping(); @@ -94,6 +93,7 @@ extern void _resolv_clear_iface_uid_range_mapping(); * On error, -1 is returned. * If no interface is found, 0 is returned and buff is set to empty ('\0'). * If an interface is found, the name is copied to buff and the length of the name is returned. + * If there are multiple rules covering uid the most recently added rule will be returned. * Arguments: uid The uid to find an interface for * buff A buffer to copy the result to * buffLen Length of buff. An interface is at most IF_NAMESIZE in length */