From 71da41451212389bea25d67bc5da696b6d194bff Mon Sep 17 00:00:00 2001 From: Othmar Gsenger Date: Sun, 25 May 2008 09:50:42 +0000 Subject: moved keyexchange to http://anytun.org/svn/keyexchange --- keyexchange/isakmpd-20041012/virtual.c | 722 --------------------------------- 1 file changed, 722 deletions(-) delete mode 100644 keyexchange/isakmpd-20041012/virtual.c (limited to 'keyexchange/isakmpd-20041012/virtual.c') diff --git a/keyexchange/isakmpd-20041012/virtual.c b/keyexchange/isakmpd-20041012/virtual.c deleted file mode 100644 index d6132fe..0000000 --- a/keyexchange/isakmpd-20041012/virtual.c +++ /dev/null @@ -1,722 +0,0 @@ -/* $OpenBSD: virtual.c,v 1.9 2004/09/20 21:36:50 hshoexer Exp $ */ - -/* - * Copyright (c) 2004 Håkan Olsson. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include -#include -#include -#ifndef linux -#include -#endif -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "conf.h" -#include "if.h" -#include "exchange.h" -#include "log.h" -#include "transport.h" -#include "virtual.h" -#include "udp.h" -#include "util.h" - -#if defined (USE_NAT_TRAVERSAL) -#include "udp_encap.h" -#endif - -static struct transport *virtual_bind(const struct sockaddr *); -static struct transport *virtual_bind_ADDR_ANY(sa_family_t); -static int virtual_bind_if(char *, struct sockaddr *, void *); -static struct transport *virtual_clone(struct transport *, struct sockaddr *); -static struct transport *virtual_create(char *); -static char *virtual_decode_ids (struct transport *); -static void virtual_get_dst(struct transport *, - struct sockaddr **); -static struct msg_head *virtual_get_queue(struct message *); -static void virtual_get_src(struct transport *, - struct sockaddr **); -static void virtual_handle_message(struct transport *); -static void virtual_reinit(void); -static void virtual_remove(struct transport *); -static void virtual_report(struct transport *); -static int virtual_send_message(struct message *, - struct transport *); - -static struct transport_vtbl virtual_transport_vtbl = { - { 0 }, "udp", - virtual_create, - virtual_reinit, - virtual_remove, - virtual_report, - 0, - 0, - virtual_handle_message, - virtual_send_message, - virtual_get_dst, - virtual_get_src, - virtual_decode_ids, - virtual_clone, - virtual_get_queue -}; - -static LIST_HEAD (virtual_listen_list, virtual_transport) virtual_listen_list; -static struct transport *default_transport, *default_transport6; - -void -virtual_init(void) -{ - struct conf_list *listen_on; - - LIST_INIT(&virtual_listen_list); - - transport_method_add(&virtual_transport_vtbl); - - /* Bind the ISAKMP port(s) on all network interfaces we have. */ - if (if_map(virtual_bind_if, 0) == -1) - log_fatal("virtual_init: " - "could not bind the ISAKMP port(s) on all interfaces"); - - /* Only listen to the specified address if Listen-on is configured */ - listen_on = conf_get_list("General", "Listen-on"); - if (listen_on) { - LOG_DBG((LOG_TRANSPORT, 50, - "virtual_init: not binding ISAKMP port(s) to ADDR_ANY")); - conf_free_list(listen_on); - return; - } - - /* - * Bind to INADDR_ANY in case of new addresses popping up. - * Packet reception on this transport is taken as a hint to reprobe the - * interface list. - */ - if (!bind_family || (bind_family & BIND_FAMILY_INET4)) { - default_transport = virtual_bind_ADDR_ANY(AF_INET); - if (!default_transport) - return; - LIST_INSERT_HEAD(&virtual_listen_list, - (struct virtual_transport *)default_transport, link); - transport_reference(default_transport); - } - - if (!bind_family || (bind_family & BIND_FAMILY_INET6)) { - default_transport6 = virtual_bind_ADDR_ANY(AF_INET6); - if (!default_transport6) - return; - LIST_INSERT_HEAD(&virtual_listen_list, - (struct virtual_transport *)default_transport6, link); - transport_reference(default_transport6); - } - - return; -} - -struct virtual_transport * -virtual_get_default(sa_family_t af) -{ - switch (af) { - case AF_INET: - return (struct virtual_transport *)default_transport; - case AF_INET6: - return (struct virtual_transport *)default_transport6; - default: - return 0; - } -} - -/* - * Probe the interface list and determine what new interfaces have - * appeared. - * - * At the same time, we try to determine whether existing interfaces have - * been rendered invalid; we do this by marking all virtual transports before - * we call virtual_bind_if () through if_map (), and then releasing those - * transports that have not been unmarked. - */ -void -virtual_reinit(void) -{ - struct virtual_transport *v, *v2; - - /* Mark all UDP transports, except the default ones. */ - for (v = LIST_FIRST(&virtual_listen_list); v; v = LIST_NEXT(v, link)) - if (&v->transport != default_transport - && &v->transport != default_transport6) - v->transport.flags |= TRANSPORT_MARK; - - /* Re-probe interface list. */ - if (if_map(virtual_bind_if, 0) == -1) - log_print("virtual_init: " - "could not bind the ISAKMP port(s) on all interfaces"); - - /* - * Release listening transports for local addresses that no - * longer exist. virtual_bind_if () will have left those still marked. - */ - v = LIST_FIRST(&virtual_listen_list); - while (v) { - v2 = LIST_NEXT(v, link); - if (v->transport.flags & TRANSPORT_MARK) { - LIST_REMOVE(v, link); - transport_release(&v->transport); - } - v = v2; - } -} - -struct virtual_transport * -virtual_listen_lookup(struct sockaddr *addr) -{ - struct virtual_transport *v; - struct udp_transport *u; - - for (v = LIST_FIRST(&virtual_listen_list); v; - v = LIST_NEXT(v, link)) { - if (!(u = (struct udp_transport *)v->main)) - if (!(u = (struct udp_transport *)v->encap)) { - log_print("virtual_listen_lookup: " - "virtual %p has no low-level transports", - v); - continue; - } - - if (u->src->sa_family == addr->sa_family - && sockaddr_addrlen(u->src) == sockaddr_addrlen(addr) - && memcmp(sockaddr_addrdata (u->src), - sockaddr_addrdata(addr), - sockaddr_addrlen(addr)) == 0) - return v; - } - - LOG_DBG((LOG_TRANSPORT, 40, "virtual_listen_lookup: no match")); - return 0; -} - -/* - * Initialize an object of the VIRTUAL transport class. - */ -static struct transport * -virtual_bind(const struct sockaddr *addr) -{ - struct virtual_transport *v; - struct sockaddr_storage tmp_sa; - char *port; - char *ep; - long lport; - - v = (struct virtual_transport *)calloc(1, sizeof *v); - if (!v) { - log_error("virtual_bind: calloc(1, %lu) failed", - (unsigned long)sizeof *v); - return 0; - } - - v->transport.vtbl = &virtual_transport_vtbl; - - memcpy(&tmp_sa, addr, sysdep_sa_len((struct sockaddr *)addr)); - - /* - * Get port. - * XXX Use getservbyname too. - */ - port = udp_default_port ? udp_default_port : UDP_DEFAULT_PORT_STR; - lport = strtol(port, &ep, 10); - if (*ep != '\0' || lport < 0 || lport > (long)USHRT_MAX) { - log_print("virtual_bind: " - "port string \"%s\" not convertible to in_port_t", port); - free(v); - return 0; - } - - sockaddr_set_port((struct sockaddr *)&tmp_sa, (in_port_t)lport); - v->main = udp_bind((struct sockaddr *)&tmp_sa); - if (!v->main) { - free(v); - return 0; - } - ((struct transport *)v->main)->virtual = (struct transport *)v; - -#if defined (USE_NAT_TRAVERSAL) - memcpy(&tmp_sa, addr, sysdep_sa_len((struct sockaddr *)addr)); - - /* - * Get port. - * XXX Use getservbyname too. - */ - port = udp_encap_default_port - ? udp_encap_default_port : UDP_ENCAP_DEFAULT_PORT_STR; - lport = strtol(port, &ep, 10); - if (*ep != '\0' || lport < 0 || lport > (long)USHRT_MAX) { - log_print("virtual_bind: " - "port string \"%s\" not convertible to in_port_t", port); - v->main->vtbl->remove(v->main); - free(v); - return 0; - } - - sockaddr_set_port((struct sockaddr *)&tmp_sa, (in_port_t)lport); - v->encap = udp_encap_bind((struct sockaddr *)&tmp_sa); - if (!v->encap) { - v->main->vtbl->remove(v->main); - free(v); - return 0; - } - ((struct transport *)v->encap)->virtual = (struct transport *)v; -#endif - v->encap_is_active = 0; - - transport_setup(&v->transport, 1); - v->transport.flags |= TRANSPORT_LISTEN; - - return (struct transport *)v; -} - -static struct transport * -virtual_bind_ADDR_ANY(sa_family_t af) -{ - struct sockaddr_storage dflt_stor; - struct sockaddr_in *d4 = (struct sockaddr_in *)&dflt_stor; - struct sockaddr_in6 *d6 = (struct sockaddr_in6 *)&dflt_stor; - struct transport *t; - struct in6_addr in6addr_any = IN6ADDR_ANY_INIT; - - memset(&dflt_stor, 0, sizeof dflt_stor); - switch (af) { - case AF_INET: - d4->sin_family = af; -#if !defined (LINUX_IPSEC) - d4->sin_len = sizeof(struct sockaddr_in); -#endif - d4->sin_addr.s_addr = INADDR_ANY; - break; - - case AF_INET6: - d6->sin6_family = af; -#if !defined (LINUX_IPSEC) - d6->sin6_len = sizeof(struct sockaddr_in6); -#endif - memcpy(&d6->sin6_addr.s6_addr, &in6addr_any, - sizeof in6addr_any); - break; - } - - t = virtual_bind((struct sockaddr *)&dflt_stor); - if (!t) - log_error("virtual_bind_ADDR_ANY: " - "could not allocate default IPv%s ISAKMP port(s)", - af == AF_INET ? "4" : "6"); - return t; -} - -static int -virtual_bind_if(char *ifname, struct sockaddr *if_addr, void *arg) -{ - struct conf_list *listen_on; - struct virtual_transport *v; - struct conf_list_node *address; - struct sockaddr *addr; - struct transport *t; - struct ifreq flags_ifr; - char *addr_str; - int s, error; - -#if defined (USE_DEBUG) - if (sockaddr2text(if_addr, &addr_str, 0)) - addr_str = 0; - - LOG_DBG((LOG_TRANSPORT, 90, - "virtual_bind_if: interface %s family %s address %s", - ifname ? ifname : "", - if_addr->sa_family == AF_INET ? "v4" : - (if_addr->sa_family == AF_INET6 ? "v6" : ""), - addr_str ? addr_str : "")); - if (addr_str) - free(addr_str); -#endif - - /* - * Drop non-Internet stuff. - */ - if ((if_addr->sa_family != AF_INET - || sysdep_sa_len(if_addr) != sizeof (struct sockaddr_in)) - && (if_addr->sa_family != AF_INET6 - || sysdep_sa_len(if_addr) != sizeof (struct sockaddr_in6))) - return 0; - - /* - * Only create sockets for families we should listen to. - */ - if (bind_family) - switch (if_addr->sa_family) { - case AF_INET: - if ((bind_family & BIND_FAMILY_INET4) == 0) - return 0; - break; - case AF_INET6: - if ((bind_family & BIND_FAMILY_INET6) == 0) - return 0; - break; - default: - return 0; - } - - /* - * These special addresses are not useable as they have special meaning - * in the IP stack. - */ - if (if_addr->sa_family == AF_INET - && (((struct sockaddr_in *)if_addr)->sin_addr.s_addr == INADDR_ANY - || (((struct sockaddr_in *)if_addr)->sin_addr.s_addr - == INADDR_NONE))) - return 0; - - /* - * Go through the list of transports and see if we already have this - * address bound. If so, unmark the transport and skip it; this allows - * us to call this function when we suspect a new address has appeared. - */ - if ((v = virtual_listen_lookup(if_addr)) != 0) { - LOG_DBG ((LOG_TRANSPORT, 90, "virtual_bind_if: " - "already bound")); - v->transport.flags &= ~TRANSPORT_MARK; - return 0; - } - - /* - * Don't bother with interfaces that are down. - * Note: This socket is only used to collect the interface status. - */ - s = socket(if_addr->sa_family, SOCK_DGRAM, 0); - if (s == -1) { - log_error("virtual_bind_if: " - "socket (%d, SOCK_DGRAM, 0) failed", if_addr->sa_family); - return -1; - } - strlcpy(flags_ifr.ifr_name, ifname, sizeof flags_ifr.ifr_name); - if (ioctl(s, SIOCGIFFLAGS, (caddr_t)&flags_ifr) == -1) { - log_error("virtual_bind_if: " - "ioctl (%d, SIOCGIFFLAGS, ...) failed", s); - close(s); - return -1; - } - close(s); - if (!(flags_ifr.ifr_flags & IFF_UP)) - return 0; - - /* Set the port number to zero. */ - switch (if_addr->sa_family) { - case AF_INET: - ((struct sockaddr_in *)if_addr)->sin_port = htons(0); - break; - case AF_INET6: - ((struct sockaddr_in6 *)if_addr)->sin6_port = htons(0); - break; - default: - log_print("virtual_bind_if: unsupported protocol family %d", - if_addr->sa_family); - break; - } - - /* - * If we are explicit about what addresses we can listen to, be sure - * to respect that option. - * This is quite wasteful redoing the list-run for every interface, - * but who cares? This is not an operation that needs to be fast. - */ - listen_on = conf_get_list("General", "Listen-on"); - if (listen_on) { - for (address = TAILQ_FIRST(&listen_on->fields); address; - address = TAILQ_NEXT(address, link)) { - if (text2sockaddr(address->field, 0, &addr)) { - log_print("virtual_bind_if: " - "invalid address %s in \"Listen-on\"", - address->field); - continue; - } - - /* If found, take the easy way out. */ - if (memcmp(addr, if_addr, - sysdep_sa_len(addr)) == 0) { - free(addr); - break; - } - free(addr); - } - conf_free_list(listen_on); - - /* - * If address is zero then we did not find the address among - * the ones we should listen to. - * XXX We do not discover if we do not find our listen - * addresses. Maybe this should be the other way round. - */ - if (!address) - return 0; - } - - t = virtual_bind(if_addr); - if (!t) { - error = sockaddr2text(if_addr, &addr_str, 0); - log_print("virtual_bind_if: failed to create a socket on %s", - error ? "unknown" : addr_str); - if (!error) - free(addr_str); - return -1; - } - LIST_INSERT_HEAD(&virtual_listen_list, (struct virtual_transport *)t, - link); - transport_reference(t); - return 0; -} - -static struct transport * -virtual_clone(struct transport *vt, struct sockaddr *raddr) -{ - struct virtual_transport *v = (struct virtual_transport *)vt; - struct virtual_transport *v2; - struct transport *t; - - t = malloc(sizeof *v); - if (!t) { - log_error("virtual_clone: malloc(%lu) failed", - (unsigned long)sizeof *v); - return 0; - } - v2 = (struct virtual_transport *)t; - - memcpy(v2, v, sizeof *v); - /* Remove the copy's links into virtual_listen_list. */ - v2->link.le_next = 0; - v2->link.le_prev = 0; - - if (v->encap_is_active) - v2->main = 0; /* No need to clone this. */ - else { - v2->main = v->main->vtbl->clone(v->main, raddr); - v2->main->virtual = (struct transport *)v2; - } -#if defined (USE_NAT_TRAVERSAL) - /* XXX fix strtol() call */ - sockaddr_set_port(raddr, udp_encap_default_port ? - strtol(udp_encap_default_port, NULL, 10) : UDP_ENCAP_DEFAULT_PORT); - v2->encap = v->encap->vtbl->clone(v->encap, raddr); - v2->encap->virtual = (struct transport *)v2; -#endif - LOG_DBG((LOG_TRANSPORT, 50, "virtual_clone: old %p new %p (%s is %p)", - v, t, v->encap_is_active ? "encap" : "main", - v->encap_is_active ? v2->encap : v2->main)); - - t->flags &= ~TRANSPORT_LISTEN; - transport_setup(t, 1); - return t; -} - -static struct transport * -virtual_create(char *name) -{ - struct virtual_transport *v; - struct transport *t, *t2; - - t = transport_create("udp_physical", name); - if (!t) - return 0; - -#if defined (USE_NAT_TRAVERSAL) - t2 = transport_create("udp_encap", name); - if (!t2) { - t->vtbl->remove(t); - return 0; - } -#else - t2 = 0; -#endif - - v = (struct virtual_transport *)calloc(1, sizeof *v); - if (!v) { - log_error("virtual_create: calloc(1, %lu) failed", - (unsigned long)sizeof *v); - t->vtbl->remove(t); - if (t2) - t2->vtbl->remove(t2); - return 0; - } - - memcpy(v, t, sizeof *t); - v->transport.virtual = 0; - v->main = t; - v->encap = t2; - v->transport.vtbl = &virtual_transport_vtbl; - t->virtual = (struct transport *)v; - if (t2) - t2->virtual = (struct transport *)v; - transport_setup(&v->transport, 1); - return (struct transport *)v; -} - -static void -virtual_remove(struct transport *t) -{ - struct virtual_transport *v = (struct virtual_transport *)t; - - if (v->encap) - v->encap->vtbl->remove(v->encap); - if (v->main) - v->main->vtbl->remove(v->main); - if (v->link.le_prev) - LIST_REMOVE(v, link); - - LOG_DBG((LOG_TRANSPORT, 90, "virtual_remove: removed %p", v)); - free(t); -} - -static void -virtual_report(struct transport *t) -{ - return; -} - -static void -virtual_handle_message(struct transport *t) -{ - if (t->virtual == default_transport || - t->virtual == default_transport6) { - /* XXX drain pending message. See udp_handle_message(). */ - - virtual_reinit(); - - /* - * As we don't know the actual destination address of the - * packet, we can't really deal with it. So, just ignore it - * and hope we catch the retransmission. - */ - return; - } - - /* - * As per the NAT-T draft, in case we have already switched ports, - * any messages recieved on the old (500) port SHOULD be discarded. - * (Actually, while phase 1 messages should be discarded, - * informational exchanges MAY be processed normally. For now, we - * discard them all.) - */ - if (((struct virtual_transport *)t->virtual)->encap_is_active && - ((struct virtual_transport *)t->virtual)->main == t) { - LOG_DBG((LOG_MESSAGE, 10, "virtual_handle_message: " - "message on old port discarded")); - return; - } - - t->vtbl->handle_message(t); -} - -static int -virtual_send_message(struct message *msg, struct transport *t) -{ - struct virtual_transport *v = - (struct virtual_transport *)msg->transport; -#if defined (USE_NAT_TRAVERSAL) - struct sockaddr *dst; - in_port_t port; - - /* - * Activate NAT-T Encapsulation if - * - the exchange says we can, and - * - in ID_PROT, after step 4 (draft-ietf-ipsec-nat-t-ike-03), or - * - in other exchange (Aggressive, ), asap - * XXX ISAKMP_EXCH_BASE etc? - */ - if (v->encap_is_active == 0 && - (msg->exchange->flags & EXCHANGE_FLAG_NAT_T_ENABLE) && - (msg->exchange->type != ISAKMP_EXCH_ID_PROT || - msg->exchange->step > 4)) { - LOG_DBG((LOG_MESSAGE, 10, "virtual_send_message: " - "enabling NAT-T encapsulation for this exchange")); - v->encap_is_active++; - - /* Copy destination port if it is translated (NAT). */ - v->main->vtbl->get_dst(v->main, &dst); - port = ntohs(sockaddr_port(dst)); - if (port != UDP_DEFAULT_PORT) { - v->main->vtbl->get_dst(v->encap, &dst); - sockaddr_set_port(dst, port); - } - } -#endif /* USE_NAT_TRAVERSAL */ - - if (v->encap_is_active) - return v->encap->vtbl->send_message(msg, v->encap); - else - return v->main->vtbl->send_message(msg, v->main); -} - -static void -virtual_get_src(struct transport *t, struct sockaddr **s) -{ - struct virtual_transport *v = (struct virtual_transport *)t; - - if (v->encap_is_active) - v->encap->vtbl->get_src(v->encap, s); - else - v->main->vtbl->get_src(v->main, s); -} - -static void -virtual_get_dst(struct transport *t, struct sockaddr **s) -{ - struct virtual_transport *v = (struct virtual_transport *)t; - - if (v->encap_is_active) - v->encap->vtbl->get_dst(v->encap, s); - else - v->main->vtbl->get_dst(v->main, s); -} - -static char * -virtual_decode_ids(struct transport *t) -{ - struct virtual_transport *v = (struct virtual_transport *)t; - - if (v->encap_is_active) - return v->encap->vtbl->decode_ids(t); - else - return v->main->vtbl->decode_ids(t); -} - -static struct msg_head * -virtual_get_queue(struct message *msg) -{ - if (msg->flags & MSG_PRIORITIZED) - return &msg->transport->prio_sendq; - else - return &msg->transport->sendq; -} -- cgit v1.2.3