📄 fa_utils.c
字号:
/* $Id: fa_utils.c,v 1.89 2001/09/27 17:33:54 jm Exp $ * Foreign Agent - independent help routines * * Dynamic hierarchial IP tunnel * Copyright (C) 1998-2001, Dynamics group * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. See README and COPYING for * more details. */#ifdef HAVE_CONFIG_H#include <config.h>#endif#ifndef _GNU_SOURCE#define _GNU_SOURCE /* for snprintf() etc. */#endif#include <stdio.h>#include <stdlib.h>#include <string.h>#include <syslog.h>#include <errno.h>#include <unistd.h>#include <assert.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>#include <sys/un.h>#include "tunnel.h"#include "debug.h"#include "rsa_dyn.h"#include "dyn_ip.h"#include "fa.h"#include "fa_mn_addr.h"#include "fa_hash.h"#include "util.h"#include "proxyarp.h"#ifndef IP_PKTINFO#define IP_PKTINFO 8#endif#ifndef IP_RECVTTL#define IP_RECVTTL 12#endif#define PURGE_BINDING_TUNNELS 2extern struct interface_entry *up_interface;extern int fa_info_sock;extern struct sockaddr_un fa_info_addr;extern struct sockaddr_in upper_fa_addr;extern struct fa_config *config;/** * send_address_ok: * @to_addr: * * try to avoid looping messages to own addresses * * Returns: TRUE if the address is okay or FALSE if it is not */intsend_address_ok(struct in_addr to_addr){#ifndef DEBUG_SIMULATED_TEST char dev[IFNAMSIZ]; /* check that destionation interface != lo */ if (dyn_ip_route_get(to_addr, dev, IFNAMSIZ) == 0 && strcmp(dev, "lo") == 0) { LOG2(LOG_ALERT, "send_address_ok: destination to 'lo' " "interface - possible loop => refusing\n"); return FALSE; }#endif return TRUE;}/** * own_sendto: * @sock: * @to_addr: * @to_port: * @data: * @len: * * * * Returns: */intown_sendto(int sock, struct in_addr to_addr, unsigned int to_port, void *data, int len){ struct sockaddr_in sa; if (!send_address_ok(to_addr)) return -2; memset(&sa, 0, sizeof(sa)); sa.sin_family = AF_INET; sa.sin_addr = to_addr; sa.sin_port = to_port; return sendto(sock, data, len, 0, (struct sockaddr *) &sa, sizeof(sa));}/** * close_socket: * @fd: * * */voidclose_socket(int fd){ if (fd < 0) return; if (close(fd) == -1) DEBUG(DEBUG_FLAG, "close_socket(%i) - %s\n", fd, strerror(errno));}/** * free_unconfirmed_data: * @unc: * * */voidfree_unconfirmed_data(struct unconfirmed_request *unc){ struct unconfirmed_request *prev; while (unc != NULL) { prev = unc; unc = unc->next; if (prev->fa_pubkey != NULL) free(prev->fa_pubkey); if (prev->challenge != NULL) free(prev->challenge); free(prev); }}/** * free_binding: * @binding: the binding to be freed * @bcounters: binding counters (confirmed bindings, pending registrations) * * Frees the memory used by a binding and updates the binding and pending * registration counts. */static voidfree_binding(struct bindingentry *binding, struct binding_counters *bcounters){ struct tunnel_data *t_data; if (binding == NULL || binding->data == NULL) return; t_data = (struct tunnel_data *) binding->data; if (t_data->used_challenges != NULL) { int i; for (i = 0; i < 2 * config->challenge_window; i++) if (t_data->used_challenges[i] != NULL) free(t_data->used_challenges[i]); free(t_data->used_challenges); } if (t_data->fa_pubkey != NULL) free(t_data->fa_pubkey); if (t_data->last_sent_fa_pubkeyrep != NULL) free(t_data->last_sent_fa_pubkeyrep); if (t_data->last_recv_fa_pubkeyrep != NULL) free(t_data->last_recv_fa_pubkeyrep); if (t_data->last_challenge != NULL) free(t_data->last_challenge); free_unconfirmed_data(t_data->unc_req); if (bcounters != NULL) { if (t_data->confirmed) bcounters->bindingcount--; else bcounters->pendingcount--; } free(binding->data); free(binding);}static intelim_binding(struct node *node, void *data, int force){ struct bindingentry *binding; int type; struct tunnel_data *t_data; binding = (struct bindingentry *) node; t_data = (struct tunnel_data *) binding->data; if (t_data->arpentry) { DEBUG(DEBUG_FLAG, "Removing the ARP entry of the MN\n"); if (arp_del_permanent_item(t_data->arp_ipaddr, t_data->arp_dev) < 0) { LOG2(LOG_WARNING, "Could not remove permanent ARP " "entry (%s, %s)\n", inet_ntoa(t_data->arp_ipaddr), t_data->arp_dev); } else t_data->arpentry = 0; } if (t_data->confirmed) {#ifdef DYNAMICS_SET_MAIN_TABLE_MN_ROUTE if (t_data->fa_decapsulation && dyn_ip_route_del(binding->mn_addr, t_data->info.iface->dev) != 0) { LOG2(LOG_WARNING, "dyn_ip_route_del(%s,%s) failed\n", inet_ntoa(binding->mn_addr), t_data->info.iface->dev); }#endif /* DYNAMICS_SET_MAIN_TABLE_MN_ROUTE */ if (t_data->up_tunl && dyn_ip_rule_del_table(NULL, &binding->mn_addr, t_data->up_tunl->to_mn_table_id, "lo") != 0) { LOG2(LOG_WARNING, "Removal of routing rule for " "locally generated packets failed (mn_addr=%s, " "table=%i)\n", inet_ntoa(binding->mn_addr), t_data->up_tunl->to_mn_table_id); } if (tunnel_unconnect(t_data->up_tunl, t_data->down_tunl, binding->mn_addr, t_data->tunnel_mode == TUNNEL_MODE_REVERSE ? 1 : 0, force, t_data->force_route_dev, t_data->force_reverse_dev) < 0) { LOG2(LOG_WARNING, "tunnel unconnect failed " "(tun_dev=%s, dev=%s, encaps_delivery=%i)\n", binding->tun_dev, t_data->info.iface->dev, t_data->encaps_delivery); } if (tunnel_delete_ptr(t_data->down_tunl, force) == -1) { LOG2(LOG_WARNING, "tunnel down - tunnel_delete failed\n"); } if (tunnel_delete_ptr(t_data->up_tunl, force) == -1) { LOG2(LOG_WARNING, "tunnel up - tunnel_delete failed\n"); } } if (t_data->up_type == TUNNEL_IPIP) type = -1; else type = t_data->up_key; if (t_data->mn_addr_added) { if (mn_addr_remove(&binding->mn_addr, type) < 0) { LOG2(LOG_WARNING, "mn_addr_remove(%s,%i) failed\n", inet_ntoa(binding->mn_addr), type); } else { DEBUG(DEBUG_FLAG, "mn_addr - released addr=%s, " "type=%i\n", inet_ntoa(binding->mn_addr), type); } } binding_remove(binding); free_binding(binding, data); return TRUE;}/** * eliminate_binding_entry: * @node: * @data: * * * * Returns: */inteliminate_binding_entry(struct node *node, void *data){ return elim_binding(node, data, 0);}/** * eliminate_binding_entry_force: * @node: * @data: * * * * Returns: */inteliminate_binding_entry_force(struct node *node, void *data){ return elim_binding(node, data, 1);}/** * update_binding: * @hash: pointer to the binding hashtable * @binding: the binding to be updated * @count: confirmed bindings count * @pcount: pending registration count * * Updates the binding entry by removing the entry from the binding table and * adding it back. This needs to be done when the lifetime of the binding has * changed. * * Returns: 1 if successful, else 0 */intupdate_binding(struct bindingtable *hash, struct bindingentry *binding, struct binding_counters *bcounters){ if (!binding_update(hash, binding)) { LOG2(LOG_WARNING, "update_binding: binding_update failed\n"); free_binding(binding, bcounters); return 1; } return 0;}/** * make_new_binding: * @bhash: Table of all bindings. * @ext: Registation request extensions. * @max_lifetime: Maximum lifetime allowed for the binding. * * Create a binding and add it to the binding table @bhash. The * lifetime for the binding will the smaller value of @max_lifetime * and the requested lifetime in @ext. * * Returns: A pointer to the binding, or NULL on failure. */struct bindingentry *make_new_binding(struct bindingtable *bhash, struct msg_extensions *ext, int max_lifetime, struct binding_counters *bcounters){ struct bindingentry *binding; struct tunnel_data *t_data; int i; binding = (struct bindingentry *) malloc(sizeof(struct bindingentry)); if (binding == NULL) return NULL; t_data = (struct tunnel_data *) malloc(sizeof(struct tunnel_data)); if (t_data == NULL) { free(binding); return NULL; } memset(binding, 0, sizeof(struct bindingentry)); memset(t_data, 0, sizeof(struct tunnel_data)); t_data->used_challenges = (struct challenge_ext **) malloc(2 * config->challenge_window * sizeof(struct challenge_ext *)); if (t_data->used_challenges == NULL) { free(binding); free(t_data); return NULL; } for (i = 0; i < 2 * config->challenge_window; i++) t_data->used_challenges[i] = NULL; binding->data = t_data; time(&binding->create_time); time(&binding->mod_time); binding->mn_addr.s_addr = ext->req->home_addr.s_addr; binding->ha_addr.s_addr = ext->req->ha_addr.s_addr; if (ext->priv_ha != NULL) binding->priv_ha = ntohl(ext->priv_ha->priv_ha); else binding->priv_ha = 0; t_data->confirmed = FALSE;#ifdef INCLUDE_IPAY if (ext->mn_nai) { t_data->mn_nai.len = GET_MN_NAI_LEN(ext->mn_nai); t_data->mn_nai.nai = malloc(t_data->mn_nai.len); if (t_data->mn_nai.nai == NULL) { free(t_data); free(binding); return NULL; } memcpy(t_data->mn_nai.nai, MSG_MN_NAI_DATA(ext->mn_nai), t_data->mn_nai.len); }#endif /* add default values for upper tunnel - changed if needed */ t_data->up_type = TUNNEL_IPIP; t_data->up_key = 0; if (ntohs(ext->req->lifetime) < max_lifetime) binding->timeout = ntohs(ext->req->lifetime); else binding->timeout = max_lifetime; binding->exp_time = time(NULL) + binding->timeout; if (!binding_add(bhash, binding)) { free_binding(binding, NULL); return NULL; } bcounters->pendingcount++; return binding;}/** * equal_pubkey: * @key1: * @key2: * * Returns: non-zero if key1 and key2 are identical or zero if they differ */intequal_pubkey(struct msg_key *key1, struct msg_key *key2){ if (key1 == NULL && key2 == NULL) return 1; if (key1 == NULL || key2 == NULL) return 0; if (key1->type != key2->type || key1->length != key2->length || key1->spi != key2->spi) return 0; return memcmp(MSG_KEY_DATA(key1), MSG_KEY_DATA(key2), GET_KEY_LEN(key1)) == 0;}/** * do_rsa_decrypt: * @keyrep: * @sk: * @sk_len: * * * * Returns: */intdo_rsa_decrypt(struct msg_key *keyrep, unsigned char *sk, int sk_len){#ifndef NODEBUGMODE int i;#endif if (rsa_decrypt_session_key(MSG_KEY_DATA(keyrep), keyrep->length, sk, sk_len) != 0) { LOG2(LOG_WARNING, "Session key decryption failed!\n"); return 1; }#ifndef NODEBUGMODE DEBUG(DEBUG_FLAG, "Session key (RSA): "); for (i = 0; i < sk_len; i++) DEBUG(DEBUG_FLAG, "%02x", sk[i]); DEBUG(DEBUG_FLAG, "\n");#endif return 0;}static intcreate_tunnel_upwards(struct bindingentry *binding, struct hashtable *thash, int highest_FA){ struct tunnel_data *t_data; t_data = binding->data; DEBUG(DEBUG_FLAG, "create_tunnel_upwards: highest_FA=%i, " "t_data->up_type=%i, t_data->down_type=%i\n", highest_FA, t_data->up_type, t_data->down_type); assert(up_interface != NULL); t_data->up_tunl = tunnel_add(thash, highest_FA ? binding->ha_addr : upper_fa_addr.sin_addr, t_data->ha_tun_dev, up_interface->addr, 1, t_data->up_type, t_data->up_key); if (t_data->up_tunl == NULL) { LOG2(LOG_WARNING, "create_tunnel_upwards: tunnel add failed\n"); return -1; } if (!highest_FA) { /* don't remove tunnels to upper FAs */ tunnel_set_remove(t_data->up_tunl, 1); } if (tunnel_connect(t_data->up_tunl, t_data->down_tunl, binding->mn_addr, t_data->tunnel_mode == TUNNEL_MODE_REVERSE ? 1 : 0, (t_data->fa_decapsulation && t_data->encaps_delivery) ? t_data->info.iface->dev : NULL, (!t_data->fa_decapsulation && !t_data->encaps_delivery) ? t_data->info.iface->dev : NULL) < 0) { LOG2(LOG_WARNING, "create_tunnel_upwards: " "- tunnel connection failed\n"); return -1; } if (dyn_ip_rule_add_table(NULL, &binding->mn_addr, t_data->up_tunl->to_mn_table_id, "lo") != 0) { LOG2(LOG_WARNING, "Adding routing rule for " "locally generated packets failed (mn_addr=%s, " "table=%i)\n", inet_ntoa(binding->mn_addr), t_data->up_tunl->to_mn_table_id); } return 0;}/** * create_tunnels: * @binding: * @thash: hash of tunnels * @highest_FA: is this the highest FA? * * Called when reply received. Takes care of tunnels and routing * upwards. * * Returns: 0 if successful, else 1 or -1 */intcreate_tunnels(struct bindingentry *binding, struct hashtable *thash, int highest_FA){ struct tunnel_data *t_data; char *dev; t_data = binding->data; /* Tunnel downwards * The tunnel should be already made, but with reference count * zero as the lazy tunnel deletion keeps the tunnel up long * enough. Look in handle_request(). */ assert(t_data->info.iface != NULL); if (t_data->fa_decapsulation && !t_data->encaps_delivery) { DEBUG(DEBUG_FLAG, "create_tunnels: down_key - %i=>%i\n", t_data->down_key, t_data->info.iface->if_index); t_data->down_type = TUNNEL_NO_ENCAPS; /* use ifindex to make separate entries for each interface */ t_data->down_key = t_data->info.iface->if_index; } t_data->down_tunl = tunnel_add(thash, binding->lower_addr, binding->tun_dev, t_data->info.iface->addr, 1, t_data->down_type, t_data->down_key); if (t_data->down_tunl == NULL) { LOG2(LOG_WARNING, "create_tunnels: tunnel_add failed.\n"); return 1; } /* Lock the tunnel in use if it is to a lower FA (not to MN using * MN decapsulation) */ if (t_data->down_type != TUNNEL_NO_ENCAPS && fa_hash_check_next_hop(binding->lower_addr)) { /* don't remove tunnels to lower FAs */ tunnel_set_remove(t_data->down_tunl, 1); } dev = t_data->fa_decapsulation ? t_data->info.iface->dev : binding->tun_dev; if (t_data->down_type == TUNNEL_NO_ENCAPS) { dynamics_strlcpy(t_data->down_tunl->device, dev, IFNAMSIZ); } /* Add an ARP entry if this FA is directly connected to the MN * (i.e., LFA) */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -