📄 sha_reply.c
字号:
/* $Id: sha_reply.c,v 1.8 2001/08/23 17:00:47 jm Exp $ * Surrogate Home Agent - reply handling * * Dynamic hierarchial IP tunnel * Copyright (C) 2000-2001, Jouni Malinen * * 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#include <stdlib.h>#include <stdio.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>#include <errno.h>#include <syslog.h>#include <string.h>#include <assert.h>#include "agent_utils.h"#include "debug.h"#include "dyn_ip.h"#include "tunnel.h"#include "sha_config.h"#include "sha.h"#include "sha_utils.h"extern int sha_sock;extern struct hashtable *tunnels_hash;extern struct bindingtable *bindings_hash;extern struct sha_config *config;extern int bindingcount;static struct unconfirmed_request*find_matching_request(struct bindingentry *binding, __u32 id){ struct unconfirmed_request *unc; struct tunnel_data *t_data; t_data = (struct tunnel_data *) binding->data; /* check the unconfirmed request list for id match */ unc = t_data->unc_req; while (unc != NULL) { if (unc->id[1] == id) { DEBUG(DEBUG_FLAG, "Reply to unconfirmed data\n"); return unc; } unc = unc->next; } return NULL;}static voidunconfirmed_to_binding(struct bindingentry *binding, struct unconfirmed_request *unc){ struct tunnel_data *t_data = binding->data; binding->lower_addr = unc->lower_addr; binding->lower_port = unc->lower_port; binding->spi = unc->spi; binding->fa_spi = unc->fa_spi; binding->ha_addr = unc->ha_addr; t_data->down_type = unc->tunnel_type; t_data->down_key = unc->tunnel_key;}static intcreate_tunnels(struct bindingentry *binding, struct sha_spi_entry *spi){ struct tunnel_data *t_data = binding->data; char dev[IFNAMSIZ]; struct in_addr addr; t_data->down_tunl = tunnel_add(tunnels_hash, binding->lower_addr, binding->tun_dev, config->sha_addr, 1, t_data->down_type, t_data->down_key); if (t_data->down_tunl == NULL) { LOG2(LOG_WARNING, "create_tunnels: tunnel_add(down) failed\n"); return -1; } addr = config->sha_addr; if (dyn_ip_route_get(spi->addr, dev, IFNAMSIZ) < 0 || dyn_ip_get_ifaddr(dev, &addr) < 0) { LOG2(LOG_WARNING, "create_tunnels: could not get interface " "address towards private HA %s\n", inet_ntoa(spi->addr)); } t_data->up_tunl = tunnel_add(tunnels_hash, spi->addr, t_data->ha_tun_dev, addr, 1, t_data->up_type, t_data->up_key); if (t_data->up_tunl == NULL) { LOG2(LOG_WARNING, "create_tunnels: tunnel_add(up) failed\n"); return -1; } if (tunnel_connect(t_data->up_tunl, t_data->down_tunl, binding->mn_addr, 1, NULL, NULL) < 0) { LOG2(LOG_WARNING, "create_tunnels - tunnel_connect failed\n"); } return 0;}static voidforward_reply(struct msg_extensions *ext, struct bindingentry *binding, struct unconfirmed_request *unc, struct sha_spi_entry *ha_spi){ char buf[MAXMSG]; int res, len; struct sockaddr_in dst; struct sha_spi_entry *spi; unsigned char *sk = NULL; int sk_len; assert(ext != NULL && binding != NULL && unc != NULL && ha_spi != NULL); if (ext->rep == NULL || ext->mh_auth == NULL) { LOG2(LOG_WARNING, "forward_reply: not rep or mh_auth\n"); return; } /* copy the MAC protected area directly from the received message */ len = (__u8 *) ext->mh_auth - (__u8 *) ext->rep + GET_AUTH_EXT_LEN(ext->mh_auth); if (len < sizeof(struct reg_req) + GET_AUTH_EXT_LEN(ext->mh_auth) || len > MAXMSG) { LOG2(LOG_WARNING, "forward_request: invalid length %i\n", len); return; } memcpy(buf, ext->rep, len); DEBUG(DEBUG_FLAG, " * copying up to and including mh_auth " "(len ==> %i)\n", len); if (ext->fa_keyrep != NULL) { sk = auth_decrypt(ha_spi->alg, ha_spi->shared_secret, ha_spi->shared_secret_len, ext->fa_keyrep, ext->rep, &sk_len); if (sk_len < 0 || sk_len > MAX_SK_LEN) { DEBUG(DEBUG_FLAG, "Could not decrypt fa_keyrep\n"); if (sk != NULL) free(sk); return; } } spi = get_sha_spi(0, unc->lower_addr, 0); if (sk != NULL && unc->fa_pubkey != NULL) { struct msg_key *pubrep; DEBUG(DEBUG_FLAG, " * adding fa_pubkeyrep\n"); pubrep = dynamics_do_rsa_encrypt(sk, sk_len, unc->fa_pubkey); if (pubrep == NULL) { DEBUG(DEBUG_FLAG, "Could not encrypt with pubkey\n"); if (sk != NULL) free(sk); return; } if (len + GET_KEY_EXT_LEN(pubrep) > MAXMSG) { DEBUG(DEBUG_FLAG, "Message overflow\n"); if (sk != NULL) free(sk); return; } memcpy(&buf[len], pubrep, GET_KEY_EXT_LEN(pubrep)); free(pubrep); } else if (sk != NULL && unc->fa_spi != 0 && spi != NULL) { struct msg_key *key; DEBUG(DEBUG_FLAG, " * adding fa_keyrep\n"); key = (struct msg_key *) &buf[len]; len += auth_encrypt(spi->alg, spi->shared_secret, spi->shared_secret_len, sk, key, (struct reg_rep *) buf, VENDOR_EXT_DYNAMICS_FA_KEYREP, htonl(spi->spi)); } if (sk != NULL) { free(sk); sk = NULL; } /* Add SHA-FA ext. auth. */ if (spi != NULL) { if (len + sizeof(struct msg_auth) + MAX_SK_LEN > MAXMSG) { DEBUG(DEBUG_FLAG, "\tnot enough space for the " "message\n"); return; } len += auth_add(spi->alg, spi->shared_secret, spi->shared_secret_len, (unsigned char *) buf, (struct msg_auth *) &buf[len], FH_AUTH, htonl(spi->spi)); } memset(&dst, 0, sizeof(dst)); dst.sin_family = AF_INET; dst.sin_addr = unc->lower_addr; dst.sin_port = unc->lower_port; DEBUG(DEBUG_FLAG, "\tforwarding reply to %s:%i\n", inet_ntoa(dst.sin_addr), dst.sin_port); if (!send_address_ok(dst.sin_addr)) { DEBUG(DEBUG_FLAG, "\tinvalid address\n"); return; } res = sendto(sha_sock, buf, len, 0, (struct sockaddr *) &dst, sizeof(dst)); if (res < 0) { DEBUG(DEBUG_FLAG, "\tsendto: %s\n", strerror(errno)); }}static voidswitch_tunnels(struct bindingentry *binding, struct unconfirmed_request *unc){ struct tunnel *old_tunl; struct tunnel_data *t_data = binding->data; if (unc->tunnel_type == t_data->down_type && unc->tunnel_key == t_data->down_key && unc->lower_addr.s_addr == binding->lower_addr.s_addr) return; DEBUG(DEBUG_FLAG, "Switching tunnels: %s (%i,%i) => ", inet_ntoa(binding->lower_addr), t_data->down_type, t_data->down_key); DEBUG(DEBUG_FLAG, "%s (%i,%i)\n", inet_ntoa(unc->lower_addr), unc->tunnel_type, unc->tunnel_key); old_tunl = t_data->down_tunl; t_data->down_type = unc->tunnel_type; t_data->down_key = unc->tunnel_key; binding->lower_addr = unc->lower_addr; t_data->down_tunl = tunnel_add(tunnels_hash, binding->lower_addr, binding->tun_dev, config->sha_addr, 1, t_data->down_type, t_data->down_key); if (tunnel_unconnect(t_data->up_tunl, old_tunl, binding->mn_addr, 1, 0, NULL, NULL) < 0) { LOG2(LOG_WARNING, "switch_tunnels - tunnel_unconnect " "failed\n"); } if (tunnel_connect(t_data->up_tunl, t_data->down_tunl, binding->mn_addr, 1, NULL, NULL) < 0) { LOG2(LOG_WARNING, "switch_tunnels - tunnel_connect failed\n"); } if (tunnel_delete_ptr(old_tunl, 0)) { LOG2(LOG_WARNING, "switch_tunnels - tunnel_delete_ptr " "failed\n"); }}voidhandle_reply(char *msg, int len, struct msg_extensions *ext, struct sockaddr_in *addr){ struct bindingentry *binding; struct bindingkey bkey; struct tunnel_data *t_data; struct unconfirmed_request *unc; struct sha_spi_entry *spi; struct in_addr tmpaddr; DEBUG(DEBUG_FLAG, "Handling reply to MN %s", inet_ntoa(ext->rep->home_addr)); DEBUG(DEBUG_FLAG, " (%s:%d)\n", inet_ntoa(addr->sin_addr), ntohs(addr->sin_port)); if (ext->nonce == NULL) { DEBUG(DEBUG_FLAG, "\tno nonce ext\n"); return; } if (ext->priv_ha == NULL) { DEBUG(DEBUG_FLAG, "\tno priv_ha ext\n"); return; } if (ntohl(ext->priv_ha->priv_ha) == 0) { DEBUG(DEBUG_FLAG, "\tpriv_ha=0\n"); return; } /* Check SHA-HA auth. ext */ tmpaddr.s_addr = 0; spi = get_sha_spi(0, tmpaddr, ntohl(ext->priv_ha->priv_ha)); if (spi == NULL) { DEBUG(DEBUG_FLAG, "\tprivate HA ID %u not found\n", ntohl(ext->priv_ha->priv_ha)); return; } if (ext->sha_ha_auth == NULL) { DEBUG(DEBUG_FLAG, "\tno SHA-HA auth. ext.\n"); return; } if (!auth_check_vendor(spi->alg, spi->shared_secret, spi->shared_secret_len, (unsigned char *) msg, ext->sha_ha_auth)) { DEBUG(DEBUG_FLAG, "\tinvalid SHA-HA auth. ext.\n"); return; } memcpy(&bkey.mn_addr, &(ext->rep->home_addr), sizeof(bkey.mn_addr)); memcpy(&bkey.ha_addr, &(ext->rep->ha_addr), sizeof(bkey.ha_addr)); bkey.priv_ha = ntohl(ext->priv_ha->priv_ha); binding = binding_fetch(bindings_hash, &bkey); if (binding == NULL) { DEBUG(DEBUG_FLAG, "\tno binding found (MN=%s, ", inet_ntoa(bkey.mn_addr)); DEBUG(DEBUG_FLAG, "HA=%s, priv_ha=%i)\n", inet_ntoa(bkey.ha_addr), bkey.priv_ha); return; } t_data = (struct tunnel_data *) binding->data; unc = find_matching_request(binding, ntohl(ext->rep->id[1])); if (unc == NULL) { DEBUG(DEBUG_FLAG, "\tcould not found a matching request for " "the reply - dropping it\n"); return; } if (ntohl(ext->nonce->nonce) != unc->nonce) { DEBUG(DEBUG_FLAG, "\tinvalid nonce: expected 0x%08x, got " "0x%08x\n", unc->nonce, ntohl(ext->nonce->nonce)); return; } if (IS_REGREP_ACCEPTED(ext->rep->code)) { if (ntohs(ext->rep->lifetime) == 0) { if (binding->timeout > 2) { DEBUG(DEBUG_FLAG, "Deregistration reply - " "setting tunnel lifetime to 2 secs\n"); binding->timeout = 2; } } else { if (t_data->confirmed) { switch_tunnels(binding, unc); } unconfirmed_to_binding(binding, unc); if (!t_data->confirmed) { if (create_tunnels(binding, spi) < 0) { DEBUG(DEBUG_FLAG, "create_tunnels failed\n"); return; } t_data->confirmed = 1; } binding->timeout = ntohs(ext->rep->lifetime); if (binding->timeout > config->max_lifetime) binding->timeout = config->max_lifetime; binding->timeout++; } binding->exp_time = time(NULL) + binding->timeout; if (update_binding(bindings_hash, binding, &bindingcount) != 0) LOG2(LOG_WARNING, "update_binding failed\n"); } forward_reply(ext, binding, unc, spi);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -