📄 ha.c
字号:
*/static intnew_session_key(struct bindingentry *binding, struct spi_entry *mn_spi){#ifndef NODEBUGMODE int i;#endif /* remove the (possibly) cached previous key reply using FA's public * key, because the session key changes */ if (binding->last_sent_fa_pubkeyrep) free(binding->last_sent_fa_pubkeyrep); binding->last_sent_fa_pubkeyrep = NULL; /* generate a new session key */ binding->keylen = generate_session_key(mn_spi->auth_alg, mn_spi->shared_secret, mn_spi->shared_secret_len, binding->key); if (binding->keylen == -1) { LOG2(LOG_ERR, "Could not generate session key\n"); return -1; }#ifndef NODEBUGMODE DEBUG(DEBUG_FLAG, "Session key: "); for (i = 0; i < binding->keylen; i++) DEBUG(DEBUG_FLAG, "%02x", binding->key[i]); DEBUG(DEBUG_FLAG, "\n");#endif return 0;}struct gratuitous_arp_data { struct gratuitous_arp_data *next; struct timeval tv; struct in_addr addr; char interface[IFNAMSIZ + 1];};static struct gratuitous_arp_data *gratuitous_arp_queue = NULL;/** * send_gratuitous_arp: * @addr: IP address for the ARP packet * @interface: interface to which the packet is sent * * Send a gratuitous ARP for an MN. */static voidsend_gratuitous_arp(struct in_addr addr, char *interface){ struct gratuitous_arp_data *arp2, *arp3, *arp; /* HW broadcast is not usually guaranteed, so the gratuitous ARP is * transmitted a small number of times (see RFC2002, sec. 4.6) */ /* send first packet immediately */ proxyarp_gratuitous(addr, interface); arp2 = (struct gratuitous_arp_data *) malloc(sizeof(struct gratuitous_arp_data)); arp3 = (struct gratuitous_arp_data *) malloc(sizeof(struct gratuitous_arp_data)); if (arp2 == NULL || arp3 == NULL) { DEBUG(DEBUG_FLAG, "send_gratuitous_arp: malloc() failed\n"); if (arp2 != NULL) free(arp2); if (arp3 != NULL) free(arp3); return; } /* send second packet after 100 ms delay */ memset(arp2, 0, sizeof(struct gratuitous_arp_data)); gettimeofday(&arp2->tv, NULL); add_usecs(&arp2->tv, 100000); arp2->addr.s_addr = addr.s_addr; dynamics_strlcpy(arp2->interface, interface, sizeof(arp2->interface)); /* send third packet after 200 ms delay */ memcpy(arp3, arp2, sizeof(struct gratuitous_arp_data)); add_usecs(&arp3->tv, 100000); DEBUG(DEBUG_FLAG, "send_gratuitous_arp - adding packet to queue at " "%li.%06li and %li.%06li\n", arp2->tv.tv_sec, arp2->tv.tv_usec, arp3->tv.tv_sec, arp3->tv.tv_usec); if (gratuitous_arp_queue == NULL) { /* empty queue - make new queue of the new items */ gratuitous_arp_queue = arp2; arp2->next = arp3; arp3->next = NULL; return; } if (cmp_timeval(&gratuitous_arp_queue->tv, &arp2->tv) > 0) { /* arp2 goes before the old head of the queue */ arp2->next = gratuitous_arp_queue; gratuitous_arp_queue = arp2; } else { /* insert arp2 into queue */ arp = gratuitous_arp_queue; while (arp->next != NULL && cmp_timeval(&arp->next->tv, &arp2->tv) <= 0) arp = arp->next; arp2->next = arp->next; arp->next = arp2; } /* insert arp3 into queue */ arp = arp2; while (arp->next != NULL && cmp_timeval(&arp->next->tv, &arp3->tv) <= 0) arp = arp->next; arp3->next = arp->next; arp->next = arp3;}/** * check_queued_gratuitous_arp: * * Send any pending gratuitous ARP packets from the queue. */static voidcheck_queued_gratuitous_arp(void){ struct timeval now; struct gratuitous_arp_data *arp; if (gratuitous_arp_queue == NULL) return; gettimeofday(&now, NULL); while (gratuitous_arp_queue != NULL && cmp_timeval(&gratuitous_arp_queue->tv, &now) <= 0) { arp = gratuitous_arp_queue; DEBUG(DEBUG_FLAG, "Sending queued gratuitous ARP " "(tv=%li.%06li addr=%s interface=%s)\n", arp->tv.tv_sec, arp->tv.tv_usec, inet_ntoa(arp->addr), arp->interface); proxyarp_gratuitous(arp->addr, arp->interface); gratuitous_arp_queue = arp->next; free(arp); } if (gratuitous_arp_queue == NULL) DEBUG(DEBUG_FLAG, "Gratuitous ARP queue empty.\n"); else DEBUG(DEBUG_FLAG, "Entries remaining in gratuitous ARP queue " "(next at %li.%06li)\n", gratuitous_arp_queue->tv.tv_sec, gratuitous_arp_queue->tv.tv_usec);}/** * create_binding: * @ext: parsed registration request extensions * @mn_spi: pointer to SPI entry for the MN * @create_tunnels: 1=create tunnels, 0=create only binding data * * Creates a binding matching the given request. * * Returns: * On success, a memory for the binding entry is allocated and a * pointer to it returned. On failure, %NULL is returned. */static struct bindingentry *create_binding(struct msg_extensions *ext, struct spi_entry *mn_spi, int create_tunnels){ struct bindingentry *binding; struct ha_tunnel_data *t_data; char mn_addrstr[17]; char co_addrstr[17]; int ok = TRUE; DEBUG(DEBUG_FLAG, "Creating a new binding for MN\n"); ASSERT(ext != NULL && ext->req != NULL); ASSERT(mn_spi != NULL); if (bindingcount >= config.max_bindings) { LOG2(LOG_WARNING, "max bindings reached\n"); return NULL; } /* create the binding */ binding = malloc(sizeof(struct bindingentry)); if (binding == NULL) { LOG2(LOG_ERR, "malloc[binding] - %s\n", strerror(errno)); return NULL; } memset(binding, 0, sizeof(struct bindingentry)); binding->data = malloc(sizeof(struct ha_tunnel_data)); if (binding->data == NULL) { LOG2(LOG_ERR, "malloc[ha_tunnel_data] - %s\n", strerror(errno)); free(binding); return NULL; } memset(binding->data, 0, sizeof(struct ha_tunnel_data)); t_data = (struct ha_tunnel_data *) binding->data; binding->spi = mn_spi->spi; if ((ext->fa_keyreq || ext->fa_pubkey || ext->mn_keyreq) && new_session_key(binding, mn_spi) < 0) ok = FALSE; binding->mn_addr.s_addr = ext->req->home_addr.s_addr; binding->ha_addr.s_addr = ext->req->ha_addr.s_addr; binding->priv_ha = config.priv_ha; binding->lower_addr.s_addr = config.sha_addr.s_addr != 0 ? config.sha_addr.s_addr : ext->req->co_addr.s_addr; dynamics_strlcpy(mn_addrstr, inet_ntoa(ext->req->home_addr), sizeof(mn_addrstr)); dynamics_strlcpy(co_addrstr, inet_ntoa(ext->req->co_addr), sizeof(co_addrstr)); memcpy(&binding->id, ext->req->id, REG_REQ_ID_LEN); binding->create_time = time(NULL); if (ok && create_tunnels && tunnel_add(tunnels, binding->lower_addr, binding->tun_dev, ext->req->ha_addr, 1, TUNNEL_IPIP, 0) == NULL) { LOG2(LOG_ERR, "Could not add tunnel to FA %s (COA=%s) for " "MN %s\n", inet_ntoa(binding->lower_addr), co_addrstr, mn_addrstr); ok = FALSE; } if (ok && create_tunnels && dyn_ip_route_get(binding->mn_addr, t_data->arp_if, IFNAMSIZ) != 0) { LOG2(LOG_ERR, "Could not get arp interface for MN %s\n", mn_addrstr); ok = FALSE; } if (ok && create_tunnels && dyn_ip_route_replace(binding->mn_addr, binding->tun_dev) != 0) { LOG2(LOG_ERR, "Could not add route to MN %s\n", mn_addrstr); ok = FALSE; } if (!ok) { free(binding->data); free(binding); return NULL; } if (create_tunnels) { DEBUG(DEBUG_FLAG, "tunnel_add => tun_dev=[%s]\n", binding->tun_dev); DEBUG(DEBUG_FLAG, "dyn_ip_route_get: %s => %s\n", inet_ntoa(binding->mn_addr), t_data->arp_if); proxyarp_add_item(binding->mn_addr, t_data->arp_if); send_gratuitous_arp(binding->mn_addr, t_data->arp_if); } bindingcount++; return binding;}/** * remove_tunnel: * @binding: bindingentry whose tunnel is to be removed * * Removes the route, tunnel, and proxy ARP entry for the @binding that were * created in create_binding() and possibly updated with switch_tunnel(). */static voidremove_tunnel(struct bindingentry *binding){ struct ha_tunnel_data *t_data; ASSERT(binding != NULL && binding->data != NULL); t_data = (struct ha_tunnel_data *) binding->data; if (dyn_ip_route_del(binding->mn_addr, binding->tun_dev) < 0) LOG2(LOG_WARNING, "remove_tunnel: dyn_ip_route_del failed\n"); if (tunnel_delete(tunnels, binding->lower_addr, 0, TUNNEL_IPIP, 0) < 0) LOG2(LOG_WARNING, "remove_tunnel: tunnel_delete failed\n"); if (proxyarp_del_item(binding->mn_addr, t_data->arp_if) < 0) LOG2(LOG_WARNING, "remove_tunnel: proxyarp_del_item failed\n");}/** * switch_tunnel: * @binding: the bindingentry to be updated * @ext: parsed registration request extensions * @mn_spi: pointer to SPI entry for the MN * * Switch the tunnel, i.e., do optimized remove_tunnel() and create_binding(). * * Returns: * 0 on success or -1 on failure */static intswitch_tunnel(struct bindingentry *binding, struct msg_extensions *ext, struct spi_entry *mn_spi){ char mn_addrstr[17]; char co_addrstr[17]; char old_lower_tunl[IFNAMSIZ]; ASSERT(binding != NULL && ext != NULL && ext->req != NULL); dynamics_strlcpy(mn_addrstr, inet_ntoa(ext->req->home_addr), sizeof(mn_addrstr)); dynamics_strlcpy(co_addrstr, inet_ntoa(ext->req->co_addr), sizeof(co_addrstr)); memcpy(old_lower_tunl, binding->tun_dev, IFNAMSIZ); /* remove old tunnel (delayed deletion) */ if (tunnel_delete(tunnels, binding->lower_addr, 0, TUNNEL_IPIP, 0) < 0) { LOG2(LOG_ERR, "Could not delete old tunnel to FA %s for MN %s\n", co_addrstr, mn_addrstr); } binding->lower_addr = config.sha_addr.s_addr != 0 ? config.sha_addr : ext->req->co_addr; /* add the new tunnel */ if (tunnel_add(tunnels, binding->lower_addr, binding->tun_dev, ext->req->ha_addr, 1, TUNNEL_IPIP, 0) == NULL) { LOG2(LOG_ERR, "Could not add tunnel to FA %s (COA=%s) for " "MN %s\n", inet_ntoa(binding->lower_addr), co_addrstr, mn_addrstr); destroy_binding(binding); return -1; } DEBUG(DEBUG_FLAG, "tunnel_add => tun_dev=[%s]\n", binding->tun_dev); if (dyn_ip_route_replace(binding->mn_addr, binding->tun_dev) != 0) { LOG2(LOG_WARNING, "Route replace failed (COA=%s, MN=%s, dev=%s)\n", co_addrstr, mn_addrstr, binding->tun_dev) } if ((ext->fa_keyreq || ext->fa_pubkey || ext->mn_keyreq) && new_session_key(binding, mn_spi) < 0) { destroy_binding(binding); return -1; } return 0;}/** * destroy_binding: * @binding: the bindingentry to be freed * * Frees the associated memory for a binding. * remove_tunnel() should be called before this function. */static voiddestroy_binding(struct bindingentry *binding){ if (binding->data) /* ccmalloc needs this */ free(binding->data); if (binding->fa_pubkey) free(binding->fa_pubkey); if (binding->last_sent_fa_pubkeyrep) free(binding->last_sent_fa_pubkeyrep); free(binding); bindingcount--;}/** * check_bindings: * * Checks if any bindings have expired since the last call to the function. * Any expired bindings will be removed. */static voidcheck_bindings(void){ struct bindingentry *binding; time_t diff; static int first_time = 1; static time_t advance_expire_time; time_t time2; if (first_time) { advance_expire_time = time(NULL); first_time = 0; } time2 = time(NULL); diff = time2 - advance_expire_time; advance_expire_time = time2; if (diff < 0) { DEBUG(DEBUG_FLAG, "check_bindings: diff(%li) < 0 - system time changed?\n", diff); diff = 0; } binding = binding_getexpired(bindings, diff); while (binding != NULL) { DEBUG(DEBUG_FLAG, "Binding to MN %s expired\n", inet_ntoa(binding->mn_addr)); remove_tunnel(binding); destroy_binding(binding); binding = binding_getexpired(bindings, 0); }}/** * get_fa_spi: * @spi: security parameter index * @addr: IP address of the FA * * Fetches SPI structure for an FA using key (@spi,@addr). If @spi is zero, * any item with a matching IP address is returned regardless of the configured * SPI value. * * Returns: * pointer to the SPI structure or %NULL if requested item not found */static struct fa_spi_entry *get_fa_spi(int spi, struct in_addr addr){ struct fa_spi_entry *s; struct node *node; for (node = list_get_first(&config.fa_spi_list); node != NULL; node = list_get_next(node)) { s = (struct fa_spi_entry *) node; if ((spi == 0 || s->spi == spi) && s->addr.s_addr == addr.s_addr) { return s; } }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -