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; }
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; }
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; }