|  | @@ -33,6 +33,8 @@
 | 
	
		
			
				|  |  |  #include "util.h"
 | 
	
		
			
				|  |  |  #include "tor_queue.h"
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +#include "ht.h"
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  #define DEBUGGING_CLOSE
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  #if defined(USE_LIBSECCOMP)
 | 
	
	
		
			
				|  | @@ -93,8 +95,6 @@
 | 
	
		
			
				|  |  |  static int sandbox_active = 0;
 | 
	
		
			
				|  |  |  /** Holds the parameter list configuration for the sandbox.*/
 | 
	
		
			
				|  |  |  static sandbox_cfg_t *filter_dynamic = NULL;
 | 
	
		
			
				|  |  | -/** Holds a list of pre-recorded results from getaddrinfo().*/
 | 
	
		
			
				|  |  | -static sb_addr_info_t *sb_addr_info = NULL;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  #undef SCMP_CMP
 | 
	
		
			
				|  |  |  #define SCMP_CMP(a,b,c) ((struct scmp_arg_cmp){(a),(b),(c),0})
 | 
	
	
		
			
				|  | @@ -1332,73 +1332,153 @@ sandbox_cfg_allow_execve_array(sandbox_cfg_t **cfg, ...)
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  #endif
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +/** Cache entry for getaddrinfo results; used when sandboxing is implemented
 | 
	
		
			
				|  |  | + * so that we can consult the cache when the sandbox prevents us from doing
 | 
	
		
			
				|  |  | + * getaddrinfo.
 | 
	
		
			
				|  |  | + *
 | 
	
		
			
				|  |  | + * We support only a limited range of getaddrinfo calls, where servname is null
 | 
	
		
			
				|  |  | + * and hints contains only socktype=SOCK_STREAM, family in INET,INET6,UNSPEC.
 | 
	
		
			
				|  |  | + */
 | 
	
		
			
				|  |  | +typedef struct cached_getaddrinfo_item_t {
 | 
	
		
			
				|  |  | +  HT_ENTRY(cached_getaddrinfo_item_t) node;
 | 
	
		
			
				|  |  | +  char *name;
 | 
	
		
			
				|  |  | +  int family;
 | 
	
		
			
				|  |  | +  /** set if no error; otherwise NULL */
 | 
	
		
			
				|  |  | +  struct addrinfo *res;
 | 
	
		
			
				|  |  | +  /** 0 for no error; otherwise an EAI_* value */
 | 
	
		
			
				|  |  | +  int err;
 | 
	
		
			
				|  |  | +} cached_getaddrinfo_item_t;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +static unsigned
 | 
	
		
			
				|  |  | +cached_getaddrinfo_item_hash(const cached_getaddrinfo_item_t *item)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +  return siphash24g(item->name, strlen(item->name)) + item->family;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +static unsigned
 | 
	
		
			
				|  |  | +cached_getaddrinfo_items_eq(const cached_getaddrinfo_item_t *a,
 | 
	
		
			
				|  |  | +                            const cached_getaddrinfo_item_t *b)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +  return (a->family == b->family) && 0 == strcmp(a->name, b->name);
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +static void
 | 
	
		
			
				|  |  | +cached_getaddrinfo_item_free(cached_getaddrinfo_item_t *item)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +  if (item == NULL)
 | 
	
		
			
				|  |  | +    return;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  tor_free(item->name);
 | 
	
		
			
				|  |  | +  if (item->res)
 | 
	
		
			
				|  |  | +    freeaddrinfo(item->res);
 | 
	
		
			
				|  |  | +  tor_free(item);
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +static HT_HEAD(getaddrinfo_cache, cached_getaddrinfo_item_t)
 | 
	
		
			
				|  |  | +     getaddrinfo_cache = HT_INITIALIZER();
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +HT_PROTOTYPE(getaddrinfo_cache, cached_getaddrinfo_item_t, node,
 | 
	
		
			
				|  |  | +             cached_getaddrinfo_item_hash,
 | 
	
		
			
				|  |  | +             cached_getaddrinfo_items_eq);
 | 
	
		
			
				|  |  | +HT_GENERATE(getaddrinfo_cache, cached_getaddrinfo_item_t, node,
 | 
	
		
			
				|  |  | +            cached_getaddrinfo_item_hash,
 | 
	
		
			
				|  |  | +            cached_getaddrinfo_items_eq,
 | 
	
		
			
				|  |  | +            0.6, tor_malloc_, tor_realloc_, tor_free_);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  int
 | 
	
		
			
				|  |  |  sandbox_getaddrinfo(const char *name, const char *servname,
 | 
	
		
			
				|  |  |                      const struct addrinfo *hints,
 | 
	
		
			
				|  |  |                      struct addrinfo **res)
 | 
	
		
			
				|  |  |  {
 | 
	
		
			
				|  |  | -  sb_addr_info_t *el;
 | 
	
		
			
				|  |  | +  int err;
 | 
	
		
			
				|  |  | +  struct cached_getaddrinfo_item_t search, *item;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  if (servname != NULL)
 | 
	
		
			
				|  |  | -    return -1;
 | 
	
		
			
				|  |  | +  if (servname != NULL) {
 | 
	
		
			
				|  |  | +    log_warn(LD_BUG, "called with non-NULL servname");
 | 
	
		
			
				|  |  | +    return EAI_NONAME;
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +  if (name == NULL) {
 | 
	
		
			
				|  |  | +    log_warn(LD_BUG, "called with NULL name");
 | 
	
		
			
				|  |  | +    return EAI_NONAME;
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    *res = NULL;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  for (el = sb_addr_info; el; el = el->next) {
 | 
	
		
			
				|  |  | -    if (!strcmp(el->name, name)) {
 | 
	
		
			
				|  |  | -      *res = tor_malloc(sizeof(struct addrinfo));
 | 
	
		
			
				|  |  | +  memset(&search, 0, sizeof(search));
 | 
	
		
			
				|  |  | +  search.name = (char *) name;
 | 
	
		
			
				|  |  | +  search.family = hints ? hints->ai_family : AF_UNSPEC;
 | 
	
		
			
				|  |  | +  item = HT_FIND(getaddrinfo_cache, &getaddrinfo_cache, &search);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -      memcpy(*res, el->info, sizeof(struct addrinfo));
 | 
	
		
			
				|  |  | -      /* XXXX What if there are multiple items in the list? */
 | 
	
		
			
				|  |  | -      return 0;
 | 
	
		
			
				|  |  | +  if (! sandbox_is_active()) {
 | 
	
		
			
				|  |  | +    /* If the sandbox is not turned on yet, then getaddrinfo and store the
 | 
	
		
			
				|  |  | +       result. */
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    err = getaddrinfo(name, NULL, hints, res);
 | 
	
		
			
				|  |  | +    log_info(LD_NET,"(Sandbox) getaddrinfo %s.", err ? "failed" : "succeeded");
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    if (! item) {
 | 
	
		
			
				|  |  | +      item = tor_malloc_zero(sizeof(*item));
 | 
	
		
			
				|  |  | +      item->name = tor_strdup(name);
 | 
	
		
			
				|  |  | +      item->family = hints ? hints->ai_family : AF_UNSPEC;
 | 
	
		
			
				|  |  | +      HT_INSERT(getaddrinfo_cache, &getaddrinfo_cache, item);
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  if (!sandbox_active) {
 | 
	
		
			
				|  |  | -    if (getaddrinfo(name, NULL, hints, res)) {
 | 
	
		
			
				|  |  | -      log_err(LD_BUG,"(Sandbox) getaddrinfo failed!");
 | 
	
		
			
				|  |  | -      return -1;
 | 
	
		
			
				|  |  | +    if (item->res) {
 | 
	
		
			
				|  |  | +      freeaddrinfo(item->res);
 | 
	
		
			
				|  |  | +      item->res = NULL;
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  | +    item->res = *res;
 | 
	
		
			
				|  |  | +    item->err = err;
 | 
	
		
			
				|  |  | +    return err;
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -    return 0;
 | 
	
		
			
				|  |  | +  /* Otherwise, the sanbox is on.  If we have an item, yield its cached
 | 
	
		
			
				|  |  | +     result. */
 | 
	
		
			
				|  |  | +  if (item) {
 | 
	
		
			
				|  |  | +    *res = item->res;
 | 
	
		
			
				|  |  | +    return item->err;
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  // getting here means something went wrong
 | 
	
		
			
				|  |  | +  /* getting here means something went wrong */
 | 
	
		
			
				|  |  |    log_err(LD_BUG,"(Sandbox) failed to get address %s!", name);
 | 
	
		
			
				|  |  | -  if (*res) {
 | 
	
		
			
				|  |  | -    tor_free(*res);
 | 
	
		
			
				|  |  | -    res = NULL;
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -  return -1;
 | 
	
		
			
				|  |  | +  return EAI_NONAME;
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  int
 | 
	
		
			
				|  |  | -sandbox_add_addrinfo(const char* name)
 | 
	
		
			
				|  |  | +sandbox_add_addrinfo(const char *name)
 | 
	
		
			
				|  |  |  {
 | 
	
		
			
				|  |  | -  int ret;
 | 
	
		
			
				|  |  | +  struct addrinfo *res;
 | 
	
		
			
				|  |  |    struct addrinfo hints;
 | 
	
		
			
				|  |  | -  sb_addr_info_t *el = NULL;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  el = tor_malloc(sizeof(sb_addr_info_t));
 | 
	
		
			
				|  |  | +  int i;
 | 
	
		
			
				|  |  | +  static const int families[] = { AF_INET, AF_INET6, AF_UNSPEC };
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    memset(&hints, 0, sizeof(hints));
 | 
	
		
			
				|  |  | -  hints.ai_family = AF_INET;
 | 
	
		
			
				|  |  |    hints.ai_socktype = SOCK_STREAM;
 | 
	
		
			
				|  |  | +  for (i = 0; i < 3; ++i) {
 | 
	
		
			
				|  |  | +    hints.ai_family = families[i];
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  ret = getaddrinfo(name, NULL, &hints, &(el->info));
 | 
	
		
			
				|  |  | -  if (ret) {
 | 
	
		
			
				|  |  | -    log_err(LD_BUG,"(Sandbox) failed to getaddrinfo");
 | 
	
		
			
				|  |  | -    ret = -2;
 | 
	
		
			
				|  |  | -    tor_free(el);
 | 
	
		
			
				|  |  | -    goto out;
 | 
	
		
			
				|  |  | +    res = NULL;
 | 
	
		
			
				|  |  | +    (void) sandbox_getaddrinfo(name, NULL, &hints, &res);
 | 
	
		
			
				|  |  | +    if (res)
 | 
	
		
			
				|  |  | +      sandbox_freeaddrinfo(res);
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  el->name = tor_strdup(name);
 | 
	
		
			
				|  |  | -  el->next = sb_addr_info;
 | 
	
		
			
				|  |  | -  sb_addr_info = el;
 | 
	
		
			
				|  |  | +  return 0;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | - out:
 | 
	
		
			
				|  |  | -  return ret;
 | 
	
		
			
				|  |  | +void
 | 
	
		
			
				|  |  | +sandbox_free_getaddrinfo_cache(void)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +  cached_getaddrinfo_item_t **next, **item;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  for (item = HT_START(getaddrinfo_cache, &getaddrinfo_cache);
 | 
	
		
			
				|  |  | +       item;
 | 
	
		
			
				|  |  | +       item = next) {
 | 
	
		
			
				|  |  | +    next = HT_NEXT_RMV(getaddrinfo_cache, &getaddrinfo_cache, item);
 | 
	
		
			
				|  |  | +    cached_getaddrinfo_item_free(*item);
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  HT_CLEAR(getaddrinfo_cache, &getaddrinfo_cache);
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  /**
 |