Exemple #1
0
void
replay_purge (void)
{
/*  Purges the replay hash of any expired credentials.
 */
    time_t  now;
    int     n;

    if (!replay_hash) {
        return;
    }
    if (time (&now) == (time_t) -1) {
        log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to query current time");
    }
    n = hash_delete_if (replay_hash, (hash_arg_f) replay_is_expired, &now);
    assert (n >= 0);
    if (n > 0) {
        log_msg (LOG_DEBUG, "Purged %d credential%s from replay hash",
            n, ((n == 1) ? "" : "s"));
    }
    if (timer_set_relative (
      (callback_f) replay_purge, NULL, MUNGE_REPLAY_PURGE_SECS * 1000) < 0) {
        log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to set replay purge timer");
    }
    return;
}
STATIC void
DHCPv6SocketCloseSocket(DHCPv6SocketRef sock)
{
    if (sock->fd_open == FALSE) {
	return;
    }
    if (S_globals->read_fd_refcount <= 0) {
	my_log(LOG_ERR, "DHCPv6SocketCloseSocket(%s): refcount %d",
	       if_name(sock->if_p), S_globals->read_fd_refcount);
	return;
    }
    S_globals->read_fd_refcount--;
    my_log(LOG_DEBUG, "DHCPv6SocketCloseSocket(%s): refcount %d",
	   if_name(sock->if_p), S_globals->read_fd_refcount);
    sock->fd_open = FALSE;
    if (S_globals->read_fd_refcount == 0) {
	struct timeval tv;

	my_log(LOG_DEBUG, 
	       "DHCPv6SocketCloseSocket(): scheduling delayed close");

	tv.tv_sec = 1; /* close it after 1 second of non-use */
	tv.tv_usec = 0;
	timer_set_relative(S_globals->timer_callout, tv,
			   DHCPv6SocketDelayedClose,
			   NULL, NULL, NULL);
    }
    return;
}
Exemple #3
0
void
replay_init (void)
{
/*  Initializes the replay detection engine.
 */
    hash_key_f keyf = (hash_key_f) replay_key_f;
    hash_cmp_f cmpf = (hash_cmp_f) replay_cmp_f;
    hash_del_f delf = (hash_del_f) replay_free;

    if (replay_hash != NULL) {
        return;
    }
    if (conf->got_benchmark) {
        log_msg (LOG_INFO, "Disabled replay hash");
        return;
    }
    if (!(replay_hash = hash_create (REPLAY_HASH_SIZE, keyf, cmpf, delf))) {
        log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to allocate replay hash");
    }
    if (timer_set_relative (
      (callback_f) replay_purge, NULL, MUNGE_REPLAY_PURGE_SECS * 1000) < 0) {
        log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to set replay purge timer");
    }
    return;
}
static void
manual_resolve_router_callback(ServiceRef service_p,
			       router_arp_status_t status)
{
    interface_t *	if_p = service_interface(service_p);
    Service_manual_t *	manual;
    struct timeval	tv;

    manual = (Service_manual_t *)ServiceGetPrivate(service_p);
    switch (status) {
    case router_arp_status_no_response_e:
	/* try again in 60 seconds */
	tv.tv_sec = 60;
	tv.tv_usec = 0;
	timer_set_relative(manual->timer, tv, 
			   (timer_func_t *)manual_resolve_router_retry,
			   service_p, NULL, NULL);
	if (manual->resolve_router_timed_out) {
	    break;
	}
	manual->resolve_router_timed_out = TRUE;
	/* publish what we have so far */
	ServicePublishSuccessIPv4(service_p, NULL);
	break;
    case router_arp_status_success_e:
	manual->resolve_router_timed_out = FALSE;
	ServicePublishSuccessIPv4(service_p, NULL);
	break;
    case router_arp_status_failed_e:
	my_log(LOG_ERR, "MANUAL %s: router arp resolution failed, %s", 
	       if_name(if_p), arp_client_errmsg(manual->arp));
	break;
    default:
	break;
    }
    return;
}
Exemple #5
0
static void
linklocal_allocate(ServiceRef service_p, IFEventID_t event_id,
                   void * event_data)
{
    interface_t *	  if_p = service_interface(service_p);
    Service_linklocal_t * linklocal;

    linklocal = (Service_linklocal_t *)ServiceGetPrivate(service_p);
    switch (event_id) {
    case IFEventID_start_e: {
        linklocal->enable_arp_collision_detection = FALSE;

        arp_linklocal_disable(if_name(if_p));

        /* clean-up anything that might have come before */
        linklocal_cancel_pending_events(service_p);

        linklocal->current = 1;
        if (linklocal->our_ip.s_addr) {
            /* try to keep the same address */
            linklocal->probe = linklocal->our_ip;
        }
        else {
            linklocal->probe.s_addr
                = htonl(LINKLOCAL_FIRST_USEABLE
                        + random_range(0, LINKLOCAL_RANGE));
        }
        my_log(LOG_DEBUG, "LINKLOCAL %s: probing " IP_FORMAT,
               if_name(if_p), IP_LIST(&linklocal->probe));
        arp_client_probe(linklocal->arp,
                         (arp_result_func_t *)linklocal_allocate, service_p,
                         (void *)IFEventID_arp_e, G_ip_zeroes,
                         linklocal->probe);
        /* wait for the results */
        return;
    }
    case IFEventID_arp_e: {
        arp_result_t *	result = (arp_result_t *)event_data;

        if (result->error) {
            my_log(LOG_DEBUG, "LINKLOCAL %s: ARP probe failed, %s",
                   if_name(if_p),
                   arp_client_errmsg(linklocal->arp));
            break;
        }
        if (result->in_use
                || service_is_using_ip(service_p, linklocal->probe)) {
            if (result->in_use) {
                my_log(LOG_DEBUG, "LINKLOCAL %s: IP address "
                       IP_FORMAT " is in use by " EA_FORMAT,
                       if_name(if_p),
                       IP_LIST(&linklocal->probe),
                       EA_LIST(result->addr.target_hardware));
            }
            else {
                my_log(LOG_DEBUG, "LINKLOCAL %s: IP address "
                       IP_FORMAT " is no longer unique",
                       if_name(if_p));
            }
            if (linklocal->our_ip.s_addr == linklocal->probe.s_addr) {
                linklocal->our_ip = G_ip_zeroes;
                (void)service_remove_address(service_p);
                service_publish_failure(service_p,
                                        ipconfig_status_address_in_use_e);
            }
        }
        else {
            link_status_t	   link_status = service_link_status(service_p);
            const struct in_addr linklocal_mask = { htonl(LINKLOCAL_MASK) };

            if (link_status.valid == TRUE
                    && link_status.active == FALSE) {
                linklocal_failed(service_p,
                                 ipconfig_status_media_inactive_e);
                break;
            }

            /* ad-hoc IP address is not in use, so use it */
            (void)service_set_address(service_p, linklocal->probe,
                                      linklocal_mask, G_ip_zeroes);
            linklocal_set_address(service_p, linklocal->probe);
            arp_linklocal_enable(if_name(if_p));
            linklocal_cancel_pending_events(service_p);
            linklocal->our_ip = linklocal->probe;
            ServicePublishSuccessIPv4(service_p, NULL);
            linklocal->enable_arp_collision_detection = TRUE;
            /* we're done */
            break; /* out of switch */
        }
        if (linklocal->current >= MAX_LINKLOCAL_INITIAL_TRIES) {
            struct timeval tv;
            /* initial tries threshold reached, try again after a timeout */
            tv.tv_sec = LINKLOCAL_RETRY_TIME_SECS;
            tv.tv_usec = 0;
            timer_set_relative(linklocal->timer, tv,
                               (timer_func_t *)linklocal_allocate,
                               service_p, (void *)IFEventID_timeout_e, NULL);
            /* don't fall through, wait for timer */
            break;
        }
        linklocal->current++;
    /* FALL THROUGH */
        case IFEventID_timeout_e:
            /* try the next address */
            linklocal->probe.s_addr
                = htonl(LINKLOCAL_FIRST_USEABLE
                        + random_range(0, LINKLOCAL_RANGE));
            arp_client_probe(linklocal->arp,
                             (arp_result_func_t *)linklocal_allocate, service_p,
                             (void *)IFEventID_arp_e, G_ip_zeroes,
                             linklocal->probe);
            my_log(LOG_DEBUG, "LINKLOCAL %s probing " IP_FORMAT,
                   if_name(if_p), IP_LIST(&linklocal->probe));
            /* wait for the results */
            break;
        }
    default:
        break;
    }

    return;
}
static void
manual_start(ServiceRef service_p, IFEventID_t evid, void * event_data)
{
    interface_t *	if_p = service_interface(service_p);
    Service_manual_t *	manual;

    manual = (Service_manual_t *)ServiceGetPrivate(service_p);
    switch (evid) {
      case IFEventID_start_e: {
	  if (manual->arp == NULL) {
	      link_status_t	link_status = service_link_status(service_p);

	      /* if the link is up, just assign the IP */
	      if (manual->ignore_link_status == FALSE
		  && link_status.valid == TRUE 
		  && link_status.active == FALSE) {
		  manual_inactive(service_p);
		  break;
	      }
	      (void)service_set_address(service_p,
					service_requested_ip_addr(service_p),
					service_requested_ip_mask(service_p),
					G_ip_zeroes);
	      ServicePublishSuccessIPv4(service_p, NULL);
	      break;
	  }
	  manual_cancel_pending_events(service_p);
	  arp_client_probe(manual->arp,
			   (arp_result_func_t *)manual_start, service_p,
			   (void *)IFEventID_arp_e, G_ip_zeroes,
			   service_requested_ip_addr(service_p));
	  break;
      }
      case IFEventID_arp_e: {
	  link_status_t		link_status;
	  arp_result_t *	result = (arp_result_t *)event_data;

	  if (result->error) {
	      my_log(LOG_ERR, "MANUAL %s: arp probe failed, %s", 
		     if_name(if_p), arp_client_errmsg(manual->arp));
	      break;
	  }
	  else {
	      if (result->in_use) {
		  char			msg[128];
		  struct in_addr	requested_ip;
		  struct timeval	tv;

		  requested_ip = service_requested_ip_addr(service_p);
		  snprintf(msg, sizeof(msg), 
			   IP_FORMAT " in use by " EA_FORMAT,
			   IP_LIST(&requested_ip),
			   EA_LIST(result->addr.target_hardware));
		  if (manual->user_warned == FALSE) {
		      manual->user_warned = TRUE;
		      ServiceReportIPv4AddressConflict(service_p,
						       requested_ip);
		  }
		  my_log(LOG_ERR, "MANUAL %s: %s", 
			 if_name(if_p), msg);
		  service_remove_address(service_p);
		  service_publish_failure(service_p, 
					  ipconfig_status_address_in_use_e);
		  if (G_manual_conflict_retry_interval_secs > 0) {
		      /* try again in a bit */
		      tv.tv_sec = G_manual_conflict_retry_interval_secs;
		      tv.tv_usec = 0;
		      timer_set_relative(manual->timer, tv, 
					 (timer_func_t *)manual_start,
					 service_p, IFEventID_start_e, NULL);
		  }
		  break;
	      }
	  }
	  link_status = service_link_status(service_p);
	  if (manual->ignore_link_status == FALSE
	      && link_status.valid == TRUE 
	      && link_status.active == FALSE) {
	      manual_inactive(service_p);
	      break;
	  }

	  /* set the new address */
	  (void)service_set_address(service_p,
				    service_requested_ip_addr(service_p),
				    service_requested_ip_mask(service_p),
				    G_ip_zeroes);
	  ServiceRemoveAddressConflict(service_p);
	  if (service_router_is_iaddr_valid(service_p)
	      && service_resolve_router(service_p, manual->arp,
					manual_resolve_router_callback,
					service_requested_ip_addr(service_p))) {
	      /* router ARP resolution started */
	      manual->resolve_router_timed_out = FALSE;
	  }
	  else {
	      ServicePublishSuccessIPv4(service_p, NULL);
	  }
	  break;
      }
      default: {
	  break;
      }
    }
    return;
}
ipconfig_status_t
failover_thread(ServiceRef service_p, IFEventID_t evid, void * event_data)
{
    interface_t *	if_p = service_interface(service_p);
    Service_failover_t *failover;
    ipconfig_status_t	status = ipconfig_status_success_e;

    failover = (Service_failover_t *)ServiceGetPrivate(service_p);
    switch (evid) {
      case IFEventID_start_e: {
	  ipconfig_method_data_t * method_data;

	  method_data = (ipconfig_method_data_t *)event_data;
	  if (failover != NULL) {
	      my_log(LOG_DEBUG, "FAILOVER %s: re-entering start state", 
		     if_name(if_p));
	      return (ipconfig_status_internal_error_e);
	  }
	  if (if_flags(if_p) & IFF_LOOPBACK) {
	      return (ipconfig_status_invalid_parameter_e);
	  }
	  failover = malloc(sizeof(*failover));
	  if (failover == NULL) {
	      my_log(LOG_ERR, "FAILOVER %s: malloc failed", 
		     if_name(if_p));
	      status = ipconfig_status_allocation_failed_e;
	      break;
	  }
	  ServiceSetPrivate(service_p, failover);
	  bzero(failover, sizeof(*failover));
	  service_set_requested_ip_addr(service_p, method_data->manual.addr);
	  service_set_requested_ip_mask(service_p, method_data->manual.mask);
	  failover->timer = timer_callout_init();
	  if (failover->timer == NULL) {
	      my_log(LOG_ERR, "FAILOVER %s: timer_callout_init failed", 
		     if_name(if_p));
	      status = ipconfig_status_allocation_failed_e;
	      goto stop;
	  }
	  failover->arp = arp_client_init(G_arp_session, if_p);
	  if (failover->arp == NULL) {
	      my_log(LOG_NOTICE, "FAILOVER %s: arp_client_init failed", 
		     if_name(if_p));
	      goto stop;
	  }
	  failover->address_timeout_secs = method_data->manual.failover_timeout;
	  my_log(LOG_DEBUG, "FAILOVER %s: starting", 
		 if_name(if_p));
	  failover_start(service_p, IFEventID_start_e, NULL);
	  break;
      }
      stop:
      case IFEventID_stop_e: {
	  my_log(LOG_DEBUG, "FAILOVER %s: stop", if_name(if_p));

	  if (failover == NULL) {
	      break;
	  }

	  /* remove IP address */
	  service_remove_address(service_p);

	  /* clean-up resources */
	  if (failover->arp) {
	      arp_client_free(&failover->arp);
	  }
	  if (failover->timer) {
	      timer_callout_free(&failover->timer);
	  }
	  if (failover) {
	      free(failover);
	  }
	  ServiceSetPrivate(service_p, NULL);
	  break;
      }
      case IFEventID_change_e: {
	  change_event_data_t *   	change_event;
	  ipconfig_method_data_t * 	method_data;

	  if (failover == NULL) {
	      my_log(LOG_DEBUG, "FAILOVER %s: private data is NULL", 
		     if_name(if_p));
	      status = ipconfig_status_internal_error_e;
	      break;
	  }
	  change_event = ((change_event_data_t *)event_data);
	  method_data = change_event->method_data;
	  change_event->needs_stop = FALSE;
	  if ((method_data->manual.addr.s_addr
	       != service_requested_ip_addr(service_p).s_addr)
	      || (method_data->manual.mask.s_addr
		  != service_requested_ip_mask(service_p).s_addr)) {
	      change_event->needs_stop = TRUE;
	  }
	  else {
	      failover->address_timeout_secs
		  = method_data->manual.failover_timeout;
	      if (service_is_address_set(service_p)
		  && failover->address_is_verified) {
		  if (failover->address_timeout_secs != 0) {
		      struct timeval	tv;

		      tv.tv_sec = failover->address_timeout_secs;
		      tv.tv_usec = 0;
		      timer_set_relative(failover->timer, tv, 
					 (timer_func_t *)failover_timed_out,
					 service_p, IFEventID_start_e, NULL);
		  }
		  else {
		      timer_cancel(failover->timer);
		  }
	      }
	      else {
		  failover_start(service_p, IFEventID_start_e, NULL);
	      }
	  }
	  break;
      }
      case IFEventID_arp_collision_e: {
	  arp_collision_data_t *	arpc;
	  char				msg[128];

	  arpc = (arp_collision_data_t *)event_data;

	  if (failover == NULL) {
	      return (ipconfig_status_internal_error_e);
	  }
	  if (arpc->ip_addr.s_addr 
	      != service_requested_ip_addr(service_p).s_addr) {
	      break;
	  }
	  snprintf(msg, sizeof(msg), 
		   IP_FORMAT " in use by " EA_FORMAT,
		   IP_LIST(&arpc->ip_addr), 
		   EA_LIST(arpc->hwaddr));
	  my_log(LOG_NOTICE, "FAILOVER %s: %s", 
		 if_name(if_p), msg);
	  service_remove_address(service_p);
	  service_publish_failure(service_p, 
				  ipconfig_status_address_in_use_e);
	  failover_start(service_p, IFEventID_start_e, NULL);
	  break;
      }
      case IFEventID_link_status_changed_e: {
	  link_status_t		link_status;

	  if (failover == NULL) {
	      return (ipconfig_status_internal_error_e);
	  }
	  link_status = service_link_status(service_p);
	  if (link_status.valid == TRUE) {
	      if (link_status.active == TRUE) {
		  failover_start(service_p, IFEventID_start_e, NULL);
	      }
	      else {
		  failover->address_is_verified = FALSE;
		  failover_cancel_pending_events(service_p);
	      }
	  }
	  break;
      }
      case IFEventID_link_timer_expired_e:
	  failover_inactive(service_p);
	  break;
      default:
	  break;
    } /* switch */

    return (status);
}
static void
failover_start(ServiceRef service_p, IFEventID_t evid, void * event_data)
{
    Service_failover_t * failover;
    interface_t *	if_p = service_interface(service_p);
    struct timeval	tv;

    failover = (Service_failover_t *)ServiceGetPrivate(service_p);
    switch (evid) {
      case IFEventID_start_e: {
	  failover->address_is_verified = FALSE;
	  failover_cancel_pending_events(service_p);
	  tv.tv_sec = random_range(0, 4);
	  tv.tv_usec = random_range(0, USECS_PER_SEC - 1);
	  timer_set_relative(failover->timer, tv, 
			     (timer_func_t *)failover_start,
			     service_p, (void *)IFEventID_timeout_e, NULL);
	  break;
      }
      case IFEventID_timeout_e: {
	  arp_client_probe(failover->arp, 
			   (arp_result_func_t *)failover_start, service_p,
			   (void *)IFEventID_arp_e, G_ip_zeroes,
			   service_requested_ip_addr(service_p));
	  break;
      }
      case IFEventID_arp_e: {
	  link_status_t		link_status;
	  arp_result_t *	result = (arp_result_t *)event_data;

	  if (result->error) {
	      my_log(LOG_ERR, "FAILOVER %s: arp probe failed, %s", 
		     if_name(if_p), arp_client_errmsg(failover->arp));
	      break;
	  }
	  else {
	      if (result->in_use) {
		  char			msg[128];
		  struct in_addr	requested_ip;

		  requested_ip = service_requested_ip_addr(service_p);
		  snprintf(msg, sizeof(msg), 
			   IP_FORMAT " in use by " EA_FORMAT,
			   IP_LIST(&requested_ip),
			   EA_LIST(result->addr.target_hardware));
		  my_log(LOG_NOTICE, "FAILOVER %s: %s", 
			 if_name(if_p), msg);
		  service_remove_address(service_p);
		  service_publish_failure(service_p, 
					  ipconfig_status_address_in_use_e);
		  tv.tv_sec = 10;
		  tv.tv_usec = 0;
		  timer_set_relative(failover->timer, tv, 
				     (timer_func_t *)failover_start,
				     service_p, IFEventID_start_e, NULL);
		  break;
	      }
	  }
	  link_status = service_link_status(service_p);
	  if (link_status.valid == TRUE 
	      && link_status.active == FALSE) {
	      failover_inactive(service_p);
	      break;
	  }

	  /* set the new address */
	  (void)service_set_address(service_p,
				    service_requested_ip_addr(service_p),
				    service_requested_ip_mask(service_p),
				    G_ip_zeroes);
	  ServicePublishSuccessIPv4(service_p, NULL);
	  failover->address_is_verified = TRUE;
	  if (failover->address_timeout_secs != 0) {
	      tv.tv_sec = failover->address_timeout_secs;
	      tv.tv_usec = 0;
	      timer_set_relative(failover->timer, tv, 
				 (timer_func_t *)failover_timed_out,
				 service_p, IFEventID_start_e, NULL);
	  }
	  break;
      }
      default: {
	  break;
      }
    }
    return;
}