📄 fa_utils.c
字号:
if (t_data->is_lowest_fa && !t_data->arpentry) { struct sockaddr hwaddr; DEBUG(DEBUG_FLAG, "Adding ARP entry\n"); memset(&hwaddr, 0, sizeof(hwaddr)); hwaddr.sa_family = ARPHRD_ETHER; memcpy(hwaddr.sa_data, t_data->info.from.sll_addr, t_data->info.from.sll_halen); t_data->arp_ipaddr.s_addr = t_data->info.src.sin_addr.s_addr; memcpy(t_data->arp_dev, t_data->info.iface->dev, sizeof(t_data->arp_dev)); if (arp_add_permanent_item(t_data->arp_ipaddr, t_data->arp_dev, &hwaddr) < 0) { LOG2(LOG_WARNING, "Could not add ARP entry (%s, %s, %s)\n", inet_ntoa(t_data->arp_ipaddr), t_data->arp_dev, ether_hwtoa((unsigned char *) hwaddr.sa_data)); } else t_data->arpentry = 1; }#ifdef DYNAMICS_SET_MAIN_TABLE_MN_ROUTE /* add also a route entry to the main routing table to the LFA if * MN is using FA decaps */ /* Also this should have been done in handle request phase */ if (t_data->fa_decapsulation && dyn_ip_route_replace(binding->mn_addr, dev) == -1) { LOG2(LOG_WARNING, "create_tunnels: dyn_ip_route_replace " "failed.\n"); return -1; }#endif /* DYNAMICS_SET_MAIN_TABLE_MN_ROUTE */ /* Create tunnel upwards and connect the lower tunnel */ /* This is "new". In handle request phase only the downstream * is handled but here we take care of the upstream also. */ if (create_tunnel_upwards(binding, thash, highest_FA) < 0) { LOG2(LOG_WARNING, "create_tunnels: create_tunnel_upwards failed.\n"); return -1; } return 0;}/** * add_unconfirmed_data: * @bhash: * @bcounters: * @binding: * @ext: * @info: * @config: * * Allocates memory to an unconfirmed_request. * * Returns: Pointer to an unconfirmed_request, or NULL on error. */struct unconfirmed_request *add_unconfirmed_data(struct bindingtable *bhash, struct binding_counters *bcounters, struct bindingentry *binding, struct msg_extensions *ext, struct packet_from_info *info, struct fa_config *config){ struct tunnel_data *t_data; struct unconfirmed_request *unc; int maxlifetime; time_t now; DEBUG(DEBUG_FLAG, "Adding unconfirmed request data\n"); t_data = binding->data; time(&now); binding->mod_time = now; unc = (struct unconfirmed_request *) malloc(sizeof(struct unconfirmed_request)); if (unc == NULL) return NULL; memset(unc, 0, sizeof(struct unconfirmed_request)); memcpy(&unc->info, info, sizeof(*info)); memcpy(&unc->req, ext->req, sizeof(struct reg_req)); if (ext->challenge) { int n = GET_CHALLENGE_EXT_LEN(ext->challenge); unc->challenge = (struct challenge_ext *) malloc(n); if (unc->challenge == NULL) { DEBUG(DEBUG_FLAG, "\tmalloc for challenge failed\n"); free(unc); return NULL; } memcpy(unc->challenge, ext->challenge, n); } unc->next = t_data->unc_req; unc->created = now; unc->id[0] = ntohl(ext->req->id[0]); unc->id[1] = ntohl(ext->req->id[1]); if (ext->mh_auth != NULL) unc->spi = ntohl(ext->mh_auth->spi); unc->ha_addr = ext->req->ha_addr; unc->timeout = ntohs(ext->req->lifetime); if ((ext->req->opts & REGREQ_REVERSE_TUNNEL) != 0 || config->force_reverse_tunneling) unc->tunnel_mode = TUNNEL_MODE_REVERSE; else unc->tunnel_mode = TUNNEL_MODE_TRIANGLE; unc->is_lowest_fa = is_sender_mobile(ext); if (unc->is_lowest_fa) DEBUG(DEBUG_FLAG, "\tassuming lowest FA (i.e. request from MN)\n"); else DEBUG(DEBUG_FLAG, "\tassuming not lowest FA (i.e. request from FA)\n"); /* only use FA decapsulation if this is the lowest FA and MN * requests it */ unc->fa_decapsulation = unc->is_lowest_fa && (ext->req->opts & REGREQ_MN_DECAPS) == 0; unc->encaps_delivery = !unc->is_lowest_fa || ext->encaps_del != NULL; unc->old_if_index = info->iface->if_index; unc->mn_nai_included = ext->mn_nai != NULL; if (ext->fa_pubkey) { unc->fa_pubkey = (struct msg_key *) malloc(GET_KEY_EXT_LEN(ext->fa_pubkey)); if (unc->fa_pubkey != NULL) { memcpy(unc->fa_pubkey, ext->fa_pubkey, GET_KEY_EXT_LEN(ext->fa_pubkey)); } else { LOG2(LOG_ALERT, "add_unconfirmed_data - not enough " "memory\n"); if (unc->challenge) free(unc->challenge); free(unc); return NULL; } } else if (ext->fa_keyreq) { unc->fa_spi = ntohl(ext->fa_keyreq->spi); } if (ext->gre_key != NULL) { unc->tunnel_type = TUNNEL_GRE; unc->tunnel_key = ntohl(ext->gre_key->key); } else if (unc->fa_decapsulation && !unc->encaps_delivery) { unc->tunnel_type = TUNNEL_NO_ENCAPS; unc->tunnel_key = info->iface->if_index; } else { unc->tunnel_type = TUNNEL_IPIP; unc->tunnel_key = 0; } t_data->unc_req = unc; maxlifetime = ntohs(ext->req->lifetime); if (config->delete_pending_after > 0 && config->delete_pending_after < maxlifetime) maxlifetime = config->delete_pending_after;#ifdef SHORT_BINDING_DELAY_TIME /* for testing - update lifetime even if binding is confirmed */ if (#else if (!t_data->confirmed &&#endif binding->exp_time - now < maxlifetime) { /* update the unconfirmed binding timeout so that extra * requests will not cause unwanted timeouts */ DEBUG(DEBUG_FLAG, "\tupdated binding lifetime %i => %i\n", binding->timeout, maxlifetime); binding->timeout = maxlifetime; binding->exp_time = now + binding->timeout; if (update_binding(bhash, binding, bcounters) != 0) return NULL; } return unc;}/** * unconfirmed_to_binding: * @binding: * @unc: * * */voidunconfirmed_to_binding(struct bindingentry *binding, struct unconfirmed_request *unc){ struct tunnel_data *t_data = binding->data; binding->lower_addr = unc->info.src.sin_addr; binding->lower_port = unc->info.src.sin_port; memcpy(&t_data->info, &unc->info, sizeof(unc->info));#ifdef USE_TEARDOWN t_data->upper_id[0] = binding->id[0] = unc->id[0]; t_data->upper_id[1] = binding->id[1] = unc->id[1];#endif binding->spi = unc->spi; binding->fa_spi = unc->fa_spi; t_data->tunnel_mode = unc->tunnel_mode; t_data->fa_decapsulation = unc->fa_decapsulation; t_data->encaps_delivery = unc->encaps_delivery; t_data->is_lowest_fa = unc->is_lowest_fa; binding->ha_addr = unc->ha_addr; if (t_data->fa_pubkey != NULL) free(t_data->fa_pubkey); t_data->fa_pubkey = unc->fa_pubkey; unc->fa_pubkey = NULL; if (t_data->last_sent_fa_pubkeyrep != NULL) { free(t_data->last_sent_fa_pubkeyrep); t_data->last_sent_fa_pubkeyrep = NULL; } t_data->last_used_seq_num = 0; t_data->req_lifetime = unc->timeout; t_data->old_if_index = unc->old_if_index; setup_device_forcing(t_data); t_data->down_type = unc->tunnel_type; DEBUG(DEBUG_FLAG, "unconfirmed_to_binding: down_key - %i=>%i\n", t_data->down_key, unc->tunnel_key); t_data->down_key = unc->tunnel_key;}/** * check_unconfirmed_timeout: * @binding: * * check if given binding has unconfirmed requests that have timeouted * and remove them */voidcheck_unconfirmed_timeout(struct bindingentry *binding){ time_t now; struct tunnel_data *t_data; struct unconfirmed_request *unc, *prev; time(&now); t_data = binding->data; unc = t_data->unc_req; prev = NULL; while (unc != NULL) { if (now - unc->created > UNCONFIRMED_TIMEOUT) { DEBUG(DEBUG_FLAG, "Freeing unconfirmed requests that " "have timed out\n"); free_unconfirmed_data(unc); if (prev == NULL) t_data->unc_req = NULL; else prev->next = NULL; break; } prev = unc; unc = unc->next; }}/** * remove_binding_tunnels: * @binding: * @thash: * @bcounters: * * */voidremove_binding_tunnels(struct bindingentry *binding, struct hashtable *thash, struct binding_counters *bcounters){ struct tunnel_data *t_data; struct in_addr dst_addr, mn_addr, ha_addr; int up_type; __u32 up_key ; t_data = binding->data; up_type = t_data->up_type; up_key = t_data->up_key; if (t_data->up_tunl) dst_addr = t_data->up_tunl->dst_addr; else dst_addr.s_addr = 0; /* Remove possible tunnel upwards to HA also */ mn_addr.s_addr = binding->mn_addr.s_addr; ha_addr.s_addr = binding->ha_addr.s_addr; eliminate_binding_entry((struct node *) binding, bcounters);}/** * check_bindings: * @bhash: * @thash: * @bcounters: * * Check and remove expired bindings */voidcheck_bindings(struct bindingtable *bhash, struct hashtable *thash, struct binding_counters *bcounters){ static time_t prev_check; static int first = 1; struct bindingentry *binding; static time_t advance_expire_time; int diff; time_t time_check; time_t now; time(&now); if (first) { time(&prev_check); time(&advance_expire_time); first = 0; } /* don't check too frequently */ if (now - prev_check < 1) return; prev_check = now; time(&time_check); diff = time_check - advance_expire_time; advance_expire_time = time_check; if (diff < 0) { LOG2(LOG_WARNING, "check_bindings: diff(%i) < 0 - system time changed?\n", diff); diff = 0; } binding = binding_getexpired(bhash, diff); while (binding != NULL) { struct tunnel_data *t_data; struct exp_info_struct { struct in_addr mn_addr; struct in_addr ha_addr; } exp_info; t_data = (struct tunnel_data *) binding->data; DEBUG(DEBUG_FLAG, "check_bindings: binding expired\n"); DEBUG(DEBUG_FLAG, "\tdiff = %d, expiretime = %d\n", diff, binding->timeout); DEBUG(DEBUG_FLAG, "\tbinding->mn_addr = %s\n", inet_ntoa(binding->mn_addr)); DEBUG(DEBUG_FLAG, "\tbinding->lower_addr = %s\n", inet_ntoa(binding->lower_addr)); if (t_data->pending_request && t_data->unc_req != NULL) { struct msg_extensions ext; DEBUG(DEBUG_FLAG, "\tpending request timeout - " "informing MN\n"); memset(&ext, 0, sizeof(ext)); ext.req = &t_data->unc_req->req; send_failure_reply(REGREP_REGISTRATION_TIMEOUT_FA, &ext, &t_data->unc_req->info, NULL, 0); } exp_info.mn_addr = binding->mn_addr; exp_info.ha_addr = binding->ha_addr; remove_binding_tunnels(binding, thash, bcounters); binding = binding_getexpired(bhash, 0); info_send(FA_INFO_TIMEOUT, FA_INFO_OK, &exp_info, sizeof(exp_info)); }}/** * is_sender_mobile: * @ext: * * Determins if the sender of a request message is directly from a * mobile node based on the registration request extensions * * Returns: 1 if the sender is a mobile, else 0 */intis_sender_mobile(struct msg_extensions *ext){ /* FIX: this should probably be replaced with * ext->ff_auth == NULL */ if (ext->fa_pubkey != NULL || ext->fa_keyreq != NULL) return 0; return 1;}/** * info_send: * @type: * @status: * @data: * @len: * * * * Returns: */intinfo_send(int type, int status, void *data, int len){ void *buf; int n; if (fa_info_sock < 0) return -1; if (len > 0 && data == NULL) return -1; buf = malloc(sizeof(type) + sizeof(status) + len); if (buf == NULL) return -1; memcpy(buf, &type, sizeof(type)); memcpy((char *)buf + sizeof(type), &status, sizeof(status)); if (len > 0) memcpy((char *)buf + sizeof(type) + sizeof(status), data, len); n = sendto(fa_info_sock, buf, sizeof(type) + sizeof(status) + len, 0, (struct sockaddr *) &fa_info_addr, sizeof(fa_info_addr.sun_family) + strlen(fa_info_addr.sun_path)); free(buf); if (n < 0) DEBUG(DEBUG_FLAG, "info_send: %s\n", strerror(errno)); return n;}/** * create_challenge_ext: * @config: pointer to FA configuration data * @type: extension type (AGENT_ADV_CHALLENGE_EXT / MN_FA_CHALLENGE_EXT) * * Create a new challenge extension. This function allocates memory for the * challenge and it is up to the caller to release the memory. * * Returns: * pointer to the created challenge or %NULL on failure */struct challenge_ext *create_challenge_ext(struct fa_config *config, int type){ int left; struct challenge_ext *challenge; __u32 *pos, tmp; challenge = (struct challenge_ext *) malloc(sizeof(struct challenge_ext) + config->challenge_length); if (challenge == NULL) { DEBUG(DEBUG_FLAG, "malloc for challenge_ext failed\n"); return NULL; } left = config->challenge_length; challenge->type = type; challenge->length = config->challenge_length; pos = (__u32 *) MSG_CHALLENGE_EXT_DATA(challenge); while (left >= 4) { *pos++ = get_rand32(); left -= 4; } if (left > 0) { tmp = get_rand32(); memcpy(pos, &tmp, left); } return challenge;}/** * equal_challenge: * @c1: pointer to challenge extension 1 (or %NULL) * @c2: pointer to challenge extension 2 (or %NULL) * * Compare two challenges and return 1 only if both exist and are equal in * length and contents. * * Returns: * 1 if @c1 and @c2 are equal challenges or 0 if not */int equal_challenge(struct challenge_ext *c1, struct challenge_ext *c2){ int len1, len2; if (c1 == NULL || c2 == NULL) return 0; len1 = GET_CHALLENGE_LEN(c1); len2 = GET_CHALLENGE_LEN(c2); if (len1 != len2) return 0; if (memcmp(MSG_CHALLENGE_EXT_DATA(c1), MSG_CHALLENGE_EXT_DATA(c2), len1) == 0) return 1; return 0;}/** * setup_device_forcing: * @t_data: FA's binding data * * Setup device forcing for reverse tunneling. */void setup_device_forcing(struct tunnel_data *t_data){ /* When FA decapsulation is used with encapsulating delivery, * the down connection uses non-capsulated delivery to the MN, * but encapsulated delivery from the MN. */ if (t_data->fa_decapsulation && t_data->encaps_delivery) memcpy(t_data->force_route_dev, t_data->info.iface->dev, IFNAMSIZ); else memset(t_data->force_route_dev, 0, IFNAMSIZ); /* When MN decapsulation is used without encapsulating delivery, * the down connection uses encapsulated delivery to the MN, * but non-capsulated delivery from the MN. */ if (!t_data->fa_decapsulation && !t_data->encaps_delivery) memcpy(t_data->force_reverse_dev, t_data->info.iface->dev, IFNAMSIZ); else memset(t_data->force_reverse_dev, 0, IFNAMSIZ);}/** * packet_socket_send: * @dst: L2 & L3 destination (from the original registration request) * @msg: message to be sent (UDP payload) * @len: length of the buffer (UDP payload) in bytes * * Send a registration reply using a packet and the destination learned from * the corresponding registration request. This function generates the IP and * UDP headers and instructs kernel to attach a suitable L2 header. * * Returns: * -1 on failure or number of sent bytes when successful */int packet_socket_send(struct packet_from_info *dst, const unsigned char *msg, int len){ unsigned char *buf; struct iphdr *ip; struct udphdr *udp; int total_len, res; total_len = len + sizeof(*ip) + sizeof(*udp); buf = (unsigned char *) malloc(total_len); if (buf == NULL) { DEBUG(DEBUG_FLAG, "packet_socket_send: malloc failed\n"); return -1; } /* FIX: if packet is longer than MTU, it should be fragmented; since * the packet is send through a packet socket, the fragmentation is * left to us.. */ ip = (struct iphdr *) buf; memset(ip, 0, sizeof(*ip)); ip->ihl = 5; ip->version = 4; ip->ttl = 255; ip->protocol = IPPROTO_UDP; ip->daddr = dst->src.sin_addr.s_addr; ip->saddr = dst->dst_addr.s_addr; ip->tot_len = htons(total_len); ip->check = 0; ip->check = ip_checksum(buf, sizeof(*ip)); udp = (struct udphdr *) (ip + 1); udp->source = htons(434); udp->dest = dst->src.sin_port; udp->len = htons(sizeof(*udp) + len); memcpy(udp + 1, msg, len); udp->check = 0; udp->check = udp_checksum(ip, udp); res = sendto(dst->iface->udp_packet, buf, total_len, 0, (struct sockaddr *) &dst->from, sizeof(dst->from)); free(buf); if (res < 0) return res; return res - sizeof(*ip) - sizeof(*udp);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -