Пример #1
0
/**
 * Parses the hsts directives from given header like specified in RFC 6797 6.1
 */
static void parse_hsts_header(HSTSProvider *provider,
    const char *host, const char *header)
{
    GHashTable *directives = soup_header_parse_semi_param_list(header);
    HSTSEntry *entry;
    int max_age = G_MAXINT;
    gboolean include_sub_domains = false;
    GHashTableIter iter;
    gpointer key, value;
    gboolean success = true;

    HSTSProviderClass *klass = g_type_class_ref(HSTS_TYPE_PROVIDER);

    g_hash_table_iter_init(&iter, directives);
    while (g_hash_table_iter_next(&iter, &key, &value)) {
        /* parse the max-age directive */
        if (!g_ascii_strncasecmp(key, "max-age", 7)) {
            /* max age needs a value */
            if (value) {
                max_age = g_ascii_strtoll(value, NULL, 10);
                if (max_age < 0) {
                    success = false;
                    break;
                }
            } else {
                success = false;
                break;
            }
        } else if (g_ascii_strncasecmp(key, "includeSubDomains", 17)) {
            /* includeSubDomains must not have a value */
            if (!value) {
                include_sub_domains = true;
            } else {
                success = false;
                break;
            }
        }
    }
    soup_header_free_param_list(directives);
    g_type_class_unref(klass);

    if (success) {
        /* remove host if max-age = 0 RFC 6797 6.1.1 */
        if (max_age == 0) {
            remove_host_entry(provider, host);
        } else {
            entry = g_slice_new(HSTSEntry);
            entry->expires_at          = soup_date_new_from_now(max_age);
            entry->include_sub_domains = include_sub_domains;

            add_host_entry(provider, host, entry);
            add_host_entry_to_file(provider, host, entry);
        }
    }
}
Пример #2
0
/**
 * Reads the entries save in given file and store them in the whitelist.
 */
static void load_entries(HSTSProvider *provider, const char *file)
{
    char **lines, **parts, *host, *line;
    int i, len, partlen;
    gboolean include_sub_domains;
    SoupDate *date;
    HSTSEntry *entry;

    lines = util_get_lines(file);
    if (!(len = g_strv_length(lines))) {
        return;
    }

    for (i = len - 1; i >= 0; i--) {
        line = lines[i];
        /* skip empty or commented lines */
        if (!*line || *line == '#') {
            continue;
        }

        parts   = g_strsplit(line, "\t", 3);
        partlen = g_strv_length(parts);
        if (partlen == 3) {
            host = parts[0];
            if (g_hostname_is_ip_address(host)) {
                continue;
            }
            date = soup_date_new_from_string(parts[1]);
            if (!date) {
                continue;
            }
            include_sub_domains = (*parts[2] == 'y') ? true : false;

            /* built the new entry to add */
            entry = g_slice_new(HSTSEntry);
            entry->expires_at          = soup_date_new_from_string(parts[1]);
            entry->include_sub_domains = include_sub_domains;

            add_host_entry(provider, host, entry);
        } else {
            g_warning("could not parse hsts line '%s'", line);
        }
        g_strfreev(parts);
    }
    g_strfreev(lines);
}
Пример #3
0
/*
 * read_hosts_file
 * read the hosts file, resolve addresses, and put items into the main list
 * if it cannot resolve a name it fails
 */
static int read_hosts_file()
{
  FILE              *file;
  char               line[132], host[132];
  struct host_entry *cur = NULL;

  file = fopen(filename, "r");
  if(file == NULL)
    {
      printerror(errno, strerror, "could not open %s", filename);
      return 0;
    }

  /*
   * read all the items in the file and add an entry for each of them
   * in the list of hosts to be pinged
   */
  while(fgets(line,sizeof(line),file) != NULL)
    {
      line[sizeof(line)-1] = '\0';
      /* extract out the first word in the line */
      if(sscanf(line, "%s", host) != -1)
	{
	  /* see if the line is either blank or a comment */
	  if(!(host[0] == '\0' || host[0] == '#'))
	    {
	      /* if we get here, add a host entry for this name */
	      cur = add_host_entry(host, cur);
	      if(cur == NULL)
		{
		  fclose(file);
		  return 0;
		}
	    }
	}
    }

  fclose(file);
  return 1;
}
Пример #4
0
/*
 * Function: main
 * Purpose:  
 * Comments: 
 */
int main(int argc, char *argv[])
{
  int                i;
  struct sigaction   si_sa;
  int                euid, ruid;
  struct host_entry *cursor;

  /*
   * first things first
   * if anything goes wrong anywhere, we want to be super careful to release
   * any file descriptor we have on /dev/lkm, and it probably makes sense to
   * shutdown the raw socket we have too.
   */
  atexit(cleanup);

  /*
   * get the effective and the real user id's so we know if we are running
   * with elevated permissions or not
   */
  euid = geteuid();
  ruid = getuid();

  /* check for the command line arguments */
  if(check_options(argc,argv) == 0)
    {
      return -1;
    }

  /*
   * open the raw socket now.  i used to have this further down closer to
   * where it was needed, but because you can't change the euid/uid to and
   * from root (unless you're the superuser) i can only do this once
   */
  if(options & OPT_IPV4)
    {
      if(open_ipmp_sockets4() == 0) return -1; 
    }
  else if(options & OPT_IPV6)
    {
      if(open_ipmp_sockets6() == 0) return -1; 
    }
  else
    {
      if(open_ipmp_sockets4() == 0) return -1;
      if(open_ipmp_sockets6() == 0) return -1;
    }

  /*
   * revoke the permissions we requested as we only need them to open a raw
   * socket.  this is to reduce the impact of any buffer overflow exploits
   * that may be present
   */
  if(ruid != euid)
    {
      setreuid(ruid, ruid);
    }

  /*
   * we get the pid so we can identify incoming ipmp packets destined for
   * this instance of ipmp_ping
   */
  pid = getpid();

  /*
   * need to know about the addresses this host has
   */
  learn_localaddresses();

  /*
   * in FreeBSD, the actual ping is done by a kernel module that has a syscall
   * in it.  the kernel module allows the protocol to get a timestamp as close
   * to when the mbuf is actually sent to ip_output as possible
   */
#if defined(__FreeBSD__)
  if((options & OPT_RAW) == 0)
    {
      i = get_syscall("ipmp_ping", &syscall_num);
      if(i != 0)
        {
          printerror(i, strerror, "could not get the syscall for ipmp_ping");
          return -1;
        }
    }
#endif

  /*
   * the -n option means that the user has supplied a list of hosts to
   * ping, so we read those entries and put them in an list of hosts with
   * details regarding each host.  the task of putting hosts into the list
   * is handled by read_hosts_file
   *
   * if the -n option isnt specified, we create a list containing just the 
   * one host to ping.  this way, all the program logic can be used in a
   * multitude of situations.
   */
  if(options & OPT_NLANR)
    {
      /*
       * if something went wrong parsing the file, we quit.
       */
      if(read_hosts_file() == 0)
	{
	  return -1;
	}
    }
  else
    {
      /*
       * if the user didnt specify a host to ping, we bail, telling them
       * why first...
       */
      if(argc - optind != 1)
	{
	  usage(0);
          return -1;
	}

      /*
       * if we can't add a host entry for the host supplied on the command line
       * tell the user that it couldnt be parse and cleanup
       */
      if(add_host_entry(argv[optind], NULL) == 0)
	{
	  return -1;
	}
    }

  /*
   * we now put some handlers into action so if the user ctrl-c's us we have
   * the opportunity to tell them what we found out first
   * also, if the user specified a timeout, put an alarm in for that so we
   * can bail when they tell us to...
   */
  sigemptyset(&si_sa.sa_mask);
  si_sa.sa_flags = 0;
  si_sa.sa_handler = alarm_bells;
  if(sigaction(SIGINT, &si_sa, 0) == -1)
    {
      printerror(errno, strerror, "could not set sigaction for SIGINT");
      return -1;
    }
  if(options & OPT_TIMEOUT)
    {
      if(sigaction(SIGALRM, &si_sa, 0) == -1)
	{
	  printerror(errno, strerror, "could not set sigaction for SIGALRM");
	  return -1;
	}
    }

  /*
   * we loop for as long as we have not been told to finish up.
   * the finish_up loop will exit when
   *  - there has been an alarm set that goes off
   *  - a SIGINT is received (from e.g. Ctrl-C)
   *  - we have got_all_response()'s
   *
   * this is not an expensive loop in terms of cpu cycles, as the
   * recv_echo_response will sleep if there is nothing to recv until we have
   * told it to stop blocking - typically one second or whatever the between
   * timeout is.
   *
   * the loop does two things:
   *  - sends echo requests
   *  - receives echo responses
   *
   * the loop sends packets, pausing for however long the timeout is set for
   * between packets.  this pause is implemented in the recv_echo_response
   * function in a call to select(2).  if we cannot send a request to one of
   * them, we bail, as this probably means the syscall could not be called.
   *
   * the loop recv's the response and associates the packet with a host_entry
   * we then parse that response for the host entry, and then check if we have
   * now got all the responses we are looking for.  if we have, we exit the
   * loop by setting the finish_up flag
   */

  sent_all_requests = 0;
  i = 0;

  cursor = head;

  while(finish_up == 0)
    {
      while(sent_all_requests == 0)
	{
	  if(send_echo_request(cursor) != 0)
	    {
	      return -1;
	    }
	  cursor->tx++;

	  if(cursor->tx == count)
	    {
	      cursor = cursor->next;
	      if(cursor == NULL)
		{
		  sent_all_requests = 1;
		  alarm(timeout);
		  break;
		}
	    }

	  if(wait_between > 0)
	    {
	      gettimeofday(&wait_between_tv, &tz);
	      timeval_add(&wait_between_tv, wait_between);
	      break;
	    }
	}

      while(time_to_send_request() == 0 && finish_up == 0)
	{
	  if(recv_echo_responses() > 0)
	    {
	      if(got_all_responses() == 1)
		{
		  finish_up = 1;
		}
	    }
	}
    }

  /*
   * if we have been given a list of hosts to ping, we have to print out which
   * hosts did not give us a reply
   */
  if(options & OPT_NLANR)
    {
      show_loss();
    }

  return 0;
}