diff options
author | Ryan Thomas McBride <mcbride@cvs.openbsd.org> | 2004-12-14 10:17:29 +0000 |
---|---|---|
committer | Ryan Thomas McBride <mcbride@cvs.openbsd.org> | 2004-12-14 10:17:29 +0000 |
commit | 1ab553d24519e0dfba8905c63f981e6757231552 (patch) | |
tree | b50c2061406d11c5e3a5dc13a468c68357f64a4b /sbin | |
parent | 7bd191da600d6d33c1d70abf3d41c55537ed9646 (diff) |
Allow the Address, Network, or Netmask values of the <IPsec-ID> to be
specified with an interface name (in which case the first address is used)
or the keyword 'default' (in which case the address is selected based on the
default route). eg:
[roadwarrior-ip]
ID-type= IPV4_ADDR
Address= default
ok ho@ hshoexer@
Diffstat (limited to 'sbin')
-rw-r--r-- | sbin/isakmpd/conf.c | 4 | ||||
-rw-r--r-- | sbin/isakmpd/ike_phase_1.c | 28 | ||||
-rw-r--r-- | sbin/isakmpd/ipsec.c | 19 | ||||
-rw-r--r-- | sbin/isakmpd/isakmpd.conf.5 | 32 | ||||
-rw-r--r-- | sbin/isakmpd/regress/util/utiltest.c | 4 | ||||
-rw-r--r-- | sbin/isakmpd/sysdep/openbsd/Makefile.sysdep | 4 | ||||
-rw-r--r-- | sbin/isakmpd/udp.c | 9 | ||||
-rw-r--r-- | sbin/isakmpd/udp_encap.c | 8 | ||||
-rw-r--r-- | sbin/isakmpd/util.c | 154 | ||||
-rw-r--r-- | sbin/isakmpd/util.h | 5 | ||||
-rw-r--r-- | sbin/isakmpd/virtual.c | 4 |
11 files changed, 231 insertions, 40 deletions
diff --git a/sbin/isakmpd/conf.c b/sbin/isakmpd/conf.c index 0eaa1e9ed01..eb3f504837d 100644 --- a/sbin/isakmpd/conf.c +++ b/sbin/isakmpd/conf.c @@ -1,4 +1,4 @@ -/* $OpenBSD: conf.c,v 1.73 2004/08/08 19:11:06 deraadt Exp $ */ +/* $OpenBSD: conf.c,v 1.74 2004/12/14 10:17:28 mcbride Exp $ */ /* $EOM: conf.c,v 1.48 2000/12/04 02:04:29 angelos Exp $ */ /* @@ -648,7 +648,7 @@ conf_get_address(char *section, char *tag) if (!value) return 0; - if (text2sockaddr(value, 0, &sa) == -1) + if (text2sockaddr(value, 0, &sa, 0, 0) == -1) return 0; return sa; } diff --git a/sbin/isakmpd/ike_phase_1.c b/sbin/isakmpd/ike_phase_1.c index 3630d2ec579..a035a4fadef 100644 --- a/sbin/isakmpd/ike_phase_1.c +++ b/sbin/isakmpd/ike_phase_1.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ike_phase_1.c,v 1.56 2004/08/08 19:11:06 deraadt Exp $ */ +/* $OpenBSD: ike_phase_1.c,v 1.57 2004/12/14 10:17:28 mcbride Exp $ */ /* $EOM: ike_phase_1.c,v 1.31 2000/12/11 23:47:56 niklas Exp $ */ /* @@ -802,6 +802,7 @@ ike_phase_1_send_ID(struct message *msg) size_t *id_len; char *my_id = 0, *data; u_int8_t id_type; + sa_family_t af = 0; /* Choose the right fields to fill-in. */ id = initiator ? &exchange->id_i : &exchange->id_r; @@ -831,6 +832,16 @@ ike_phase_1_send_ID(struct message *msg) SET_ISAKMP_ID_TYPE(buf, id_type); switch (id_type) { case IPSEC_ID_IPV4_ADDR: + case IPSEC_ID_IPV4_ADDR_SUBNET: + af = AF_INET; + break; + case IPSEC_ID_IPV6_ADDR: + case IPSEC_ID_IPV6_ADDR_SUBNET: + af = AF_INET6; + break; + } + switch (id_type) { + case IPSEC_ID_IPV4_ADDR: case IPSEC_ID_IPV6_ADDR: /* Already in network byteorder. */ memcpy(buf + ISAKMP_ID_DATA_OFF, @@ -846,7 +857,7 @@ ike_phase_1_send_ID(struct message *msg) "has no \"Network\" tag", my_id); return -1; } - if (text2sockaddr(data, NULL, &src)) { + if (text2sockaddr(data, NULL, &src, af, 0)) { log_error("ike_phase_1_send_ID: " "text2sockaddr() failed"); return -1; @@ -861,7 +872,7 @@ ike_phase_1_send_ID(struct message *msg) "has no \"Netmask\" tag", my_id); return -1; } - if (text2sockaddr(data, NULL, &src)) { + if (text2sockaddr(data, NULL, &src, af, 1)) { log_error("ike_phase_1_send_ID: " "text2sockaddr() failed"); return -1; @@ -968,6 +979,7 @@ ike_phase_1_recv_ID(struct message *msg) size_t *id_len; ssize_t sz; struct sockaddr *sa; + sa_family_t af = 0; payload = payload_first(msg, ISAKMP_PAYLOAD_ID); @@ -989,6 +1001,14 @@ ike_phase_1_recv_ID(struct message *msg) } switch (id_type) { case IPSEC_ID_IPV4_ADDR: + af = AF_INET; + break; + case IPSEC_ID_IPV6_ADDR: + af = AF_INET6; + break; + } + switch (id_type) { + case IPSEC_ID_IPV4_ADDR: case IPSEC_ID_IPV6_ADDR: p = conf_get_str(rs, "Address"); if (!p) { @@ -997,7 +1017,7 @@ ike_phase_1_recv_ID(struct message *msg) free(rid); return -1; } - if (text2sockaddr(p, 0, &sa) == -1) { + if (text2sockaddr(p, 0, &sa, af, 0) == -1) { log_print("ike_phase_1_recv_ID: " "failed to parse address %s", p); free(rid); diff --git a/sbin/isakmpd/ipsec.c b/sbin/isakmpd/ipsec.c index 1eda79a6f40..080de6f6e8d 100644 --- a/sbin/isakmpd/ipsec.c +++ b/sbin/isakmpd/ipsec.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ipsec.c,v 1.104 2004/09/17 13:53:08 ho Exp $ */ +/* $OpenBSD: ipsec.c,v 1.105 2004/12/14 10:17:28 mcbride Exp $ */ /* $EOM: ipsec.c,v 1.143 2000/12/11 23:57:42 niklas Exp $ */ /* @@ -1838,6 +1838,7 @@ ipsec_get_id(char *section, int *id, struct sockaddr **addr, struct sockaddr **mask, u_int8_t *tproto, u_int16_t *port) { char *type, *address, *netmask; + sa_family_t af = 0; type = conf_get_str(section, "ID-type"); if (!type) { @@ -1848,6 +1849,16 @@ ipsec_get_id(char *section, int *id, struct sockaddr **addr, *id = constant_value(ipsec_id_cst, type); switch (*id) { case IPSEC_ID_IPV4_ADDR: + case IPSEC_ID_IPV4_ADDR_SUBNET: + af = AF_INET; + break; + case IPSEC_ID_IPV6_ADDR: + case IPSEC_ID_IPV6_ADDR_SUBNET: + af = AF_INET6; + break; + } + switch (*id) { + case IPSEC_ID_IPV4_ADDR: case IPSEC_ID_IPV6_ADDR: { int ret; @@ -1857,7 +1868,7 @@ ipsec_get_id(char *section, int *id, struct sockaddr **addr, "\"Address\" tag", section); return -1; } - if (text2sockaddr(address, NULL, addr)) { + if (text2sockaddr(address, NULL, addr, af, 0)) { log_print("ipsec_get_id: invalid address %s in " "section %s", address, section); return -1; @@ -1887,7 +1898,7 @@ ipsec_get_id(char *section, int *id, struct sockaddr **addr, "\"Network\" tag", section); return -1; } - if (text2sockaddr(address, NULL, addr)) { + if (text2sockaddr(address, NULL, addr, af, 0)) { log_print("ipsec_get_id: invalid section %s " "network %s", section, address); return -1; @@ -1899,7 +1910,7 @@ ipsec_get_id(char *section, int *id, struct sockaddr **addr, free(*addr); return -1; } - if (text2sockaddr(netmask, NULL, mask)) { + if (text2sockaddr(netmask, NULL, mask, af, 1)) { log_print("ipsec_id_build: invalid section %s " "network %s", section, netmask); free(*addr); diff --git a/sbin/isakmpd/isakmpd.conf.5 b/sbin/isakmpd/isakmpd.conf.5 index db3dd7869df..9eadfba2d64 100644 --- a/sbin/isakmpd/isakmpd.conf.5 +++ b/sbin/isakmpd/isakmpd.conf.5 @@ -1,4 +1,4 @@ -.\" $OpenBSD: isakmpd.conf.5,v 1.94 2004/08/10 15:59:10 ho Exp $ +.\" $OpenBSD: isakmpd.conf.5,v 1.95 2004/12/14 10:17:28 mcbride Exp $ .\" $EOM: isakmpd.conf.5,v 1.57 2000/12/21 14:43:17 ho Exp $ .\" .\" Copyright (c) 1998, 1999, 2000 Niklas Hallqvist. All rights reserved. @@ -644,21 +644,43 @@ If the ID-type is .Li IPV4_ADDR or .Li IPV6_ADDR -this tag should exist and be an IP-address. +this tag should exist and be an IP-address, an interface name, or the +.Em default +keyword. +If an interface is used, the first address of the appropriate +family will be used. +The +.Em default +keyword uses the interface associated with the default route. +In the case of IPv6 link-local addresses will be skipped if +addresses which are not link-local exist. +If the address on the interface changes +.Em isakmpd +will not track the change. +The configuration must be reloaded to learn the new address. .It Em Network If the ID-type is .Li IPV4_ADDR_SUBNET or .Li IPV6_ADDR_SUBNET -this tag should exist and -be a network address. +this tag should exist and be a network address, an interface, or the +.Em default +keyword. +When an interface is specified the network is selected as with the +.Em Address +tag. .It Em Netmask If the ID-type is .Li IPV4_ADDR_SUBNET or .Li IPV6_ADDR_SUBNET this tag should exist and -be a network subnet mask. +be a network subnet mask or an interface. +When an interface is specified the netmask is the mask associated with the +.Em Network . +The +.Em default +keyword uses the interface associated with the default route. .It Em Protocol If the ID-type is .Li IPV4_ADDR , diff --git a/sbin/isakmpd/regress/util/utiltest.c b/sbin/isakmpd/regress/util/utiltest.c index 89d86156a24..3b4a8016c0e 100644 --- a/sbin/isakmpd/regress/util/utiltest.c +++ b/sbin/isakmpd/regress/util/utiltest.c @@ -1,4 +1,4 @@ -/* $OpenBSD: utiltest.c,v 1.3 2003/06/03 14:39:51 ho Exp $ */ +/* $OpenBSD: utiltest.c,v 1.4 2004/12/14 10:17:28 mcbride Exp $ */ /* * Copyright (c) 2001 Niklas Hallqvist. All rights reserved. @@ -60,7 +60,7 @@ int test_1 (char *address, char *port, int ok) int rv; printf ("test_1 (\"%s\", \"%s\") ", address, port); - rv = text2sockaddr (address, port, &sa) == ok; + rv = text2sockaddr (address, port, &sa, 0, 0) == ok; printf (rv ? "OK" : "FAIL"); printf ("\n"); diff --git a/sbin/isakmpd/sysdep/openbsd/Makefile.sysdep b/sbin/isakmpd/sysdep/openbsd/Makefile.sysdep index 86688bdb9fd..da3dc976840 100644 --- a/sbin/isakmpd/sysdep/openbsd/Makefile.sysdep +++ b/sbin/isakmpd/sysdep/openbsd/Makefile.sysdep @@ -1,4 +1,4 @@ -# $OpenBSD: Makefile.sysdep,v 1.24 2004/06/26 03:40:57 mcbride Exp $ +# $OpenBSD: Makefile.sysdep,v 1.25 2004/12/14 10:17:28 mcbride Exp $ # $EOM: Makefile.sysdep,v 1.18 2001/01/26 10:55:22 niklas Exp $ # @@ -30,7 +30,7 @@ # IPSEC_SRCS= pf_key_v2.c -IPSEC_CFLAGS= -DUSE_PF_KEY_V2 +IPSEC_CFLAGS= -DUSE_PF_KEY_V2 -DUSE_DEFAULT_ROUTE CFLAGS+= -DHAVE_GETIFADDRS -DHAVE_PCAP CFLAGS+= -DHAVE_CLOSEFROM diff --git a/sbin/isakmpd/udp.c b/sbin/isakmpd/udp.c index 090297b7b42..b0bb5f7a1d6 100644 --- a/sbin/isakmpd/udp.c +++ b/sbin/isakmpd/udp.c @@ -1,4 +1,4 @@ -/* $OpenBSD: udp.c,v 1.79 2004/08/08 19:11:06 deraadt Exp $ */ +/* $OpenBSD: udp.c,v 1.80 2004/12/14 10:17:28 mcbride Exp $ */ /* $EOM: udp.c,v 1.57 2001/01/26 10:09:57 niklas Exp $ */ /* @@ -295,7 +295,7 @@ udp_create(char *name) name); return 0; } - if (text2sockaddr(addr_str, port_str, &dst)) { + if (text2sockaddr(addr_str, port_str, &dst, 0, 0)) { log_print("udp_create: address \"%s\" not understood", addr_str); return 0; @@ -322,7 +322,8 @@ udp_create(char *name) if (addr_list) { for (addr_node = TAILQ_FIRST(&addr_list->fields); addr_node; addr_node = TAILQ_NEXT(addr_node, link)) - if (text2sockaddr(addr_node->field, port_str, &addr) + if (text2sockaddr(addr_node->field, + port_str, &addr, 0, 0) == 0) { v = virtual_listen_lookup(addr); free(addr); @@ -337,7 +338,7 @@ udp_create(char *name) goto ret; } } - if (text2sockaddr(addr_str, port_str, &addr)) { + if (text2sockaddr(addr_str, port_str, &addr, 0, 0)) { log_print("udp_create: address \"%s\" not understood", addr_str); rv = 0; diff --git a/sbin/isakmpd/udp_encap.c b/sbin/isakmpd/udp_encap.c index 747fdc852bb..c3d5cfc77bf 100644 --- a/sbin/isakmpd/udp_encap.c +++ b/sbin/isakmpd/udp_encap.c @@ -1,4 +1,4 @@ -/* $OpenBSD: udp_encap.c,v 1.9 2004/10/20 15:00:45 hshoexer Exp $ */ +/* $OpenBSD: udp_encap.c,v 1.10 2004/12/14 10:17:28 mcbride Exp $ */ /* * Copyright (c) 1998, 1999, 2001 Niklas Hallqvist. All rights reserved. @@ -252,7 +252,7 @@ udp_encap_create(char *name) "for \"%s\"", name); return 0; } - if (text2sockaddr(addr_str, port_str, &dst)) { + if (text2sockaddr(addr_str, port_str, &dst, 0, 0)) { log_print("udp_encap_create: address \"%s\" not understood", addr_str); return 0; @@ -281,7 +281,7 @@ udp_encap_create(char *name) for (addr_node = TAILQ_FIRST(&addr_list->fields); addr_node; addr_node = TAILQ_NEXT(addr_node, link)) if (text2sockaddr(addr_node->field, port_str, - &addr) == 0) { + &addr, 0, 0) == 0) { v = virtual_listen_lookup(addr); free(addr); if (v) { @@ -296,7 +296,7 @@ udp_encap_create(char *name) goto ret; } } - if (text2sockaddr(addr_str, port_str, &addr)) { + if (text2sockaddr(addr_str, port_str, &addr, 0, 0)) { log_print("udp_encap_create: " "address \"%s\" not understood", addr_str); rv = 0; diff --git a/sbin/isakmpd/util.c b/sbin/isakmpd/util.c index 6504cb225c1..50a95b5a768 100644 --- a/sbin/isakmpd/util.c +++ b/sbin/isakmpd/util.c @@ -1,4 +1,4 @@ -/* $OpenBSD: util.c,v 1.48 2004/08/08 19:11:06 deraadt Exp $ */ +/* $OpenBSD: util.c,v 1.49 2004/12/14 10:17:28 mcbride Exp $ */ /* $EOM: util.c,v 1.23 2000/11/23 12:22:08 niklas Exp $ */ /* @@ -41,6 +41,9 @@ #include <string.h> #include <unistd.h> #include <errno.h> +#include <ifaddrs.h> +#include <net/route.h> +#include <net/if.h> #include "sysdep.h" @@ -240,9 +243,23 @@ hex2raw(char *s, u_int8_t *buf, size_t sz) } int -text2sockaddr(char *address, char *port, struct sockaddr **sa) +text2sockaddr(char *address, char *port, struct sockaddr **sa, sa_family_t af, + int netmask) { struct addrinfo *ai, hints; + struct sockaddr_storage tmp_sas; + struct ifaddrs *ifap, *ifa = NULL, *llifa = NULL; + char *np = address; +#ifdef USE_DEFAULT_ROUTE + char ifname[IFNAMSIZ]; + u_char buf[BUFSIZ]; + struct rt_msghdr *rtm; + struct sockaddr *sa2; + struct sockaddr_in *sin; + struct sockaddr_in6 *sin6; + int fd = 0, seq, len, b; + pid_t pid; +#endif /* USE_DEFAULT_ROUTE */ memset(&hints, 0, sizeof hints); if (!allow_name_lookups) @@ -251,17 +268,136 @@ text2sockaddr(char *address, char *port, struct sockaddr **sa) hints.ai_socktype = SOCK_DGRAM; hints.ai_protocol = IPPROTO_UDP; - if (getaddrinfo(address, port, &hints, &ai)) - return -1; + if (getaddrinfo(address, port, &hints, &ai)) { +#ifdef USE_DEFAULT_ROUTE + /* + * If the 'default' keyword is used, do a route lookup for + * the default route, and use the interface associated with + * it to select a source address. + */ + if (!strcmp(address, "default")) { + fd = socket(PF_ROUTE, SOCK_RAW, af); + + memset(buf, 0, sizeof(buf)); + + rtm = (struct rt_msghdr *)buf; + rtm->rtm_version = RTM_VERSION; + rtm->rtm_type = RTM_GET; + rtm->rtm_flags = RTF_UP; + rtm->rtm_addrs = RTA_DST; + rtm->rtm_seq = seq = arc4random(); + + /* default destination */ + sa2 = (struct sockaddr *)(rtm + 1); + switch (af) { + case AF_INET: { + sin = (struct sockaddr_in *)sa2; + sin->sin_len = sizeof(*sin); + sin->sin_family = af; + break; + } + case AF_INET6: { + sin6 = (struct sockaddr_in6 *)sa2; + sin6->sin6_len = sizeof(*sin6); + sin6->sin6_family = af; + break; + } + default: + close(fd); + return (-1); + } + rtm->rtm_addrs |= RTA_NETMASK|RTA_IFP|RTA_IFA; + rtm->rtm_msglen = sizeof(*rtm) + sizeof(*sa2); + + if ((b = write(fd, buf, rtm->rtm_msglen)) < 0) { + close(fd); + return (-1); + } + + pid = getpid(); - *sa = malloc(sysdep_sa_len(ai->ai_addr)); - if (!*sa) { + while ((len = read(fd, buf, sizeof(buf))) > 0) { + if (len < sizeof(*rtm)) { + close(fd); + return (-1); + } + + if (rtm->rtm_type == RTM_GET && + rtm->rtm_pid == pid && + rtm->rtm_seq == seq) { + if (rtm->rtm_errno) { + close(fd); + return (-1); + } + break; + } + } + close(fd); + + if ((rtm->rtm_addrs & (RTA_DST|RTA_GATEWAY)) == + (RTA_DST|RTA_GATEWAY)) { + np = if_indextoname(rtm->rtm_index, ifname); + if (np == NULL) + return (-1); + } + } +#endif /* USE_DEFAULT_ROUTE */ + + if (getifaddrs(&ifap) != 0) + return (-1); + + switch (af) { + default: + case AF_INET: + for (ifa = ifap; ifa; ifa = ifa->ifa_next) + if (!strcmp(ifa->ifa_name, np) && + ifa->ifa_addr != NULL && + ifa->ifa_addr->sa_family == AF_INET) + break; + break; + case AF_INET6: + for (ifa = ifap; ifa; ifa = ifa->ifa_next) { + if (!strcmp(ifa->ifa_name, np) && + ifa->ifa_addr != NULL && + ifa->ifa_addr->sa_family == AF_INET6) { + if (IN6_IS_ADDR_LINKLOCAL( + &((struct sockaddr_in6 *) + ifa->ifa_addr)->sin6_addr) && + llifa == NULL) + llifa = ifa; + else + break; + } + } + if (ifa == NULL) { + ifa = llifa; + } + break; + } + + if (ifa) { + if (netmask) + memcpy(&tmp_sas, ifa->ifa_netmask, + sysdep_sa_len(ifa->ifa_netmask)); + + else + memcpy(&tmp_sas, ifa->ifa_addr, + sysdep_sa_len(ifa->ifa_addr)); + freeifaddrs(ifap); + } else { + freeifaddrs(ifap); + return -1; + } + } else { + memcpy(&tmp_sas, ai->ai_addr, sysdep_sa_len(ai->ai_addr)); freeaddrinfo(ai); - return -1; } - memcpy(*sa, ai->ai_addr, sysdep_sa_len(ai->ai_addr)); - freeaddrinfo(ai); + *sa = malloc(sysdep_sa_len((struct sockaddr *)&tmp_sas)); + if (!*sa) + return -1; + + memcpy(*sa, &tmp_sas, sysdep_sa_len((struct sockaddr *)&tmp_sas)); return 0; } diff --git a/sbin/isakmpd/util.h b/sbin/isakmpd/util.h index b370ff26c18..db2564eddbc 100644 --- a/sbin/isakmpd/util.h +++ b/sbin/isakmpd/util.h @@ -1,4 +1,4 @@ -/* $OpenBSD: util.h,v 1.21 2004/06/23 03:01:53 hshoexer Exp $ */ +/* $OpenBSD: util.h,v 1.22 2004/12/14 10:17:28 mcbride Exp $ */ /* $EOM: util.h,v 1.10 2000/10/24 13:33:39 niklas Exp $ */ /* @@ -63,7 +63,8 @@ extern u_int8_t *sockaddr_addrdata(struct sockaddr *); extern int sockaddr_addrlen(struct sockaddr *); extern in_port_t sockaddr_port(struct sockaddr *); extern void sockaddr_set_port(struct sockaddr *, in_port_t); -extern int text2sockaddr(char *, char *, struct sockaddr **); +extern int text2sockaddr(char *, char *, struct sockaddr **, + sa_family_t, int); extern void util_ntoa(char **, int, u_int8_t *); extern int zero_test(const u_int8_t *, size_t); diff --git a/sbin/isakmpd/virtual.c b/sbin/isakmpd/virtual.c index d6132fe7932..dbf5635dbea 100644 --- a/sbin/isakmpd/virtual.c +++ b/sbin/isakmpd/virtual.c @@ -1,4 +1,4 @@ -/* $OpenBSD: virtual.c,v 1.9 2004/09/20 21:36:50 hshoexer Exp $ */ +/* $OpenBSD: virtual.c,v 1.10 2004/12/14 10:17:28 mcbride Exp $ */ /* * Copyright (c) 2004 Håkan Olsson. All rights reserved. @@ -457,7 +457,7 @@ virtual_bind_if(char *ifname, struct sockaddr *if_addr, void *arg) if (listen_on) { for (address = TAILQ_FIRST(&listen_on->fields); address; address = TAILQ_NEXT(address, link)) { - if (text2sockaddr(address->field, 0, &addr)) { + if (text2sockaddr(address->field, 0, &addr, 0, 0)) { log_print("virtual_bind_if: " "invalid address %s in \"Listen-on\"", address->field); |