diff options
author | Markus Friedl <markus@cvs.openbsd.org> | 2003-12-02 23:16:30 +0000 |
---|---|---|
committer | Markus Friedl <markus@cvs.openbsd.org> | 2003-12-02 23:16:30 +0000 |
commit | 7827007d3935fef762fc37ed47e44956982e543a (patch) | |
tree | 32503217eaf3f477211d64e2f795e83f59c1a618 | |
parent | efce987ff534832e2def76f49222eb98d59aefaa (diff) |
UDP encapsulation for ESP in transport mode (draft-ietf-ipsec-udp-encaps-XX.txt)
ok deraadt@
-rw-r--r-- | sbin/ipsecadm/ipsecadm.8 | 7 | ||||
-rw-r--r-- | sbin/ipsecadm/ipsecadm.c | 30 | ||||
-rw-r--r-- | sbin/ipsecadm/pfkdump.c | 12 | ||||
-rw-r--r-- | sbin/sysctl/sysctl.8 | 4 | ||||
-rw-r--r-- | sys/net/pfkeyv2.c | 29 | ||||
-rw-r--r-- | sys/net/pfkeyv2.h | 15 | ||||
-rw-r--r-- | sys/net/pfkeyv2_convert.c | 25 | ||||
-rw-r--r-- | sys/net/pfkeyv2_parsemessage.c | 18 | ||||
-rw-r--r-- | sys/netinet/ip_esp.h | 15 | ||||
-rw-r--r-- | sys/netinet/ip_ipsp.c | 9 | ||||
-rw-r--r-- | sys/netinet/ip_ipsp.h | 6 | ||||
-rw-r--r-- | sys/netinet/ipsec_input.c | 32 | ||||
-rw-r--r-- | sys/netinet/ipsec_output.c | 31 | ||||
-rw-r--r-- | sys/netinet/udp_usrreq.c | 43 | ||||
-rw-r--r-- | usr.bin/netstat/inet.c | 7 |
15 files changed, 250 insertions, 33 deletions
diff --git a/sbin/ipsecadm/ipsecadm.8 b/sbin/ipsecadm/ipsecadm.8 index 75a09c0fe88..948efd103d0 100644 --- a/sbin/ipsecadm/ipsecadm.8 +++ b/sbin/ipsecadm/ipsecadm.8 @@ -1,4 +1,4 @@ -.\" $OpenBSD: ipsecadm.8,v 1.62 2003/07/24 08:03:19 itojun Exp $ +.\" $OpenBSD: ipsecadm.8,v 1.63 2003/12/02 23:16:29 markus Exp $ .\" .\" Copyright 1997 Niels Provos <provos@physnet.uni-hamburg.de> .\" All rights reserved. @@ -90,6 +90,7 @@ modifiers are: .Fl authkey , .Fl authkeyfile , .Fl forcetunnel , +.Fl udpencap , .Fl key , and .Fl keyfile . @@ -382,6 +383,10 @@ and options. Notice that the IPsec stack will perform IP-inside-IP encapsulation when deemed necessary, even if this flag has not been set. +.It Fl udpencap +Enable ESP-inside-UDP encapsulation. +The UDP destination port must be specified on the command line. +This port will be used for sending encapsulated UDP packets. .It Fl enc The encryption algorithm to be used with the SA. Possible values are: diff --git a/sbin/ipsecadm/ipsecadm.c b/sbin/ipsecadm/ipsecadm.c index 08e24e36d67..f12c49e0896 100644 --- a/sbin/ipsecadm/ipsecadm.c +++ b/sbin/ipsecadm/ipsecadm.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ipsecadm.c,v 1.70 2003/09/23 18:09:20 itojun Exp $ */ +/* $OpenBSD: ipsecadm.c,v 1.71 2003/12/02 23:16:29 markus Exp $ */ /* * The authors of this code are John Ioannidis (ji@tla.org), * Angelos D. Keromytis (kermit@csd.uch.gr) and @@ -286,6 +286,7 @@ usage(void) "\t -src <ip>\t\t\tsource address to be used\n" "\t -halfiv\t\t\tuse 4-byte IV in old ESP\n" "\t -forcetunnel\t\t\tforce IP-in-IP encapsulation\n" + "\t -udpencap <port>\t\tenable ESP-in-UDP encapsulation\n" "\t -dst <ip>\t\t\tdestination address to be used\n" "\t -proto <val>\t\t\tsecurity protocol\n" "\t -proxy <ip>\t\t\tproxy address to be used\n" @@ -309,7 +310,7 @@ usage(void) "\t -dontacq\t\t\trequire, without using key mgmt.\n" "\t -in\t\t\t\tspecify incoming-packet policy\n" "\t -out\t\t\t\tspecify outgoing-packet policy\n" - "\t -[ah|esp|ip4|ipcomp]\t\t\tflush a particular protocol\n" + "\t -[ah|esp|ip4|ipcomp]\t\tflush a particular protocol\n" "\t -srcid\t\t\tsource identity for flows\n" "\t -dstid\t\t\tdestination identity for flows\n" "\t -srcid_type\t\t\tsource identity type\n" @@ -345,6 +346,7 @@ main(int argc, char *argv[]) struct sadb_ident sid1, sid2; struct sadb_key skey1, skey2; struct sadb_protocol sprotocol, sprotocol2; + struct sadb_x_udpencap udpencap; /* Peer UDP Port */ u_char realkey[8192], realakey[8192]; struct iovec iov[30]; struct addrinfo hints, *res; @@ -375,6 +377,7 @@ main(int argc, char *argv[]) memset(realakey, 0, sizeof(realakey)); memset(&sid1, 0, sizeof(sid1)); memset(&sid2, 0, sizeof(sid2)); + memset(&udpencap, 0, sizeof(udpencap)); src = (union sockaddr_union *) srcbuf; dst = (union sockaddr_union *) dstbuf; @@ -921,6 +924,24 @@ main(int argc, char *argv[]) sa.sadb_sa_flags |= SADB_X_SAFLAGS_TUNNEL; continue; } + if (!strcmp(argv[i] + 1, "udpencap") && + udpencap.sadb_x_udpencap_port == 0 && (i + 1 < argc)) { + if (!(mode & ESP_NEW)) { + fprintf(stderr, "%s: option udpencap can " + "be used only with new ESP\n", argv[0]); + exit(1); + } + sa.sadb_sa_flags |= SADB_X_SAFLAGS_UDPENCAP; + udpencap.sadb_x_udpencap_exttype = SADB_X_EXT_UDPENCAP; + udpencap.sadb_x_udpencap_len = sizeof(udpencap) / 8; + udpencap.sadb_x_udpencap_port = + strtoul(argv[i + 1], NULL, 10); + udpencap.sadb_x_udpencap_port = + htons(udpencap.sadb_x_udpencap_port); + udpencap.sadb_x_udpencap_reserved = 0; + i++; + continue; + } if (!strcmp(argv[i] + 1, "halfiv")) { if (!(mode & ESP_OLD)) { fprintf(stderr, @@ -1520,6 +1541,11 @@ argfail: skey2.sadb_key_bits = 8 * alen; smsg.sadb_msg_len += skey2.sadb_key_len; } + if (sa.sadb_sa_flags & SADB_X_SAFLAGS_UDPENCAP) { + iov[cnt].iov_base = &udpencap; + iov[cnt++].iov_len = sizeof(udpencap); + smsg.sadb_msg_len += udpencap.sadb_x_udpencap_len; + } } else { switch (mode & CMD_MASK) { case GRP_SPI: diff --git a/sbin/ipsecadm/pfkdump.c b/sbin/ipsecadm/pfkdump.c index 08853fe3655..3e9532a936a 100644 --- a/sbin/ipsecadm/pfkdump.c +++ b/sbin/ipsecadm/pfkdump.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pfkdump.c,v 1.8 2003/07/29 18:38:36 deraadt Exp $ */ +/* $OpenBSD: pfkdump.c,v 1.9 2003/12/02 23:16:29 markus Exp $ */ /* * Copyright (c) 2003 Markus Friedl. All rights reserved. @@ -52,6 +52,7 @@ void print_ident(struct sadb_ext *, struct sadb_msg *); void print_policy(struct sadb_ext *, struct sadb_msg *); void print_cred(struct sadb_ext *, struct sadb_msg *); void print_auth(struct sadb_ext *, struct sadb_msg *); +void print_udpenc(struct sadb_ext *, struct sadb_msg *); struct idname *lookup(struct idname [], u_int8_t); char *lookup_name(struct idname [], u_int8_t); @@ -104,6 +105,7 @@ struct idname ext_types[] = { { SADB_X_EXT_LOCAL_AUTH, "x_local_auth", print_auth }, { SADB_X_EXT_REMOTE_AUTH, "x_remote_auth", print_auth }, { SADB_X_EXT_SUPPORTED_COMP, "x_supported_comp", print_supp }, + { SADB_X_EXT_UDPENCAP, "x_udpencap", print_udpenc }, { 0, NULL, NULL } }; @@ -533,6 +535,14 @@ print_auth(struct sadb_ext *ext, struct sadb_msg *msg) } void +print_udpenc(struct sadb_ext *ext, struct sadb_msg *msg) +{ + struct sadb_x_udpencap *x_udpencap = (struct sadb_x_udpencap *) ext; + + printf("udpencap port %u\n", ntohs(x_udpencap->sadb_x_udpencap_port)); +} + +void msg_send(int pfkey, u_int8_t satype, u_int8_t mtype) { struct sadb_msg msg; diff --git a/sbin/sysctl/sysctl.8 b/sbin/sysctl/sysctl.8 index 32f748a6ee0..84737672388 100644 --- a/sbin/sysctl/sysctl.8 +++ b/sbin/sysctl/sysctl.8 @@ -1,4 +1,4 @@ -.\" $OpenBSD: sysctl.8,v 1.109 2003/10/17 21:04:57 mcbride Exp $ +.\" $OpenBSD: sysctl.8,v 1.110 2003/12/02 23:16:29 markus Exp $ .\" $NetBSD: sysctl.8,v 1.4 1995/09/30 07:12:49 thorpej Exp $ .\" .\" Copyright (c) 1993 @@ -240,6 +240,8 @@ privilege can change the value. .It net.inet.gre.allow integer yes .It net.inet.gre.wccp integer yes .It net.inet.esp.enable integer yes +.It net.inet.esp.udpencap integer yes +.It net.inet.esp.udpencap_port integer yes .It net.inet.ah.enable integer yes .It net.inet.mobileip.allow integer yes .It net.inet.etherip.allow integer yes diff --git a/sys/net/pfkeyv2.c b/sys/net/pfkeyv2.c index adb21e2f068..91ffab60299 100644 --- a/sys/net/pfkeyv2.c +++ b/sys/net/pfkeyv2.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pfkeyv2.c,v 1.89 2003/07/24 09:59:02 itojun Exp $ */ +/* $OpenBSD: pfkeyv2.c,v 1.90 2003/12/02 23:16:29 markus Exp $ */ /* * @(#)COPYRIGHT 1.1 (NRL) 17 January 1995 @@ -542,6 +542,9 @@ pfkeyv2_get(struct tdb *sa, void **headers, void **buffer) if (sa->tdb_emxkey) i+= PADUP(sa->tdb_emxkeylen) + sizeof(struct sadb_key); + if (sa->tdb_udpencap_port) + i+= sizeof(struct sadb_x_udpencap); + if (!(p = malloc(i, M_PFKEY, M_DONTWAIT))) { rval = ENOMEM; goto ret; @@ -630,6 +633,12 @@ pfkeyv2_get(struct tdb *sa, void **headers, void **buffer) export_key(&p, sa, PFKEYV2_ENCRYPTION_KEY); } + /* Export UDP encapsulation port, if present */ + if (sa->tdb_udpencap_port) { + headers[SADB_X_EXT_UDPENCAP] = p; + export_udpencap(&p, sa); + } + rval = 0; ret: @@ -895,6 +904,12 @@ pfkeyv2_send(struct socket *socket, void *message, int len) rval = EINVAL; goto ret; } + /* UDP encapsulation is only supported for ESP */ + if (smsg->sadb_msg_satype != SADB_SATYPE_ESP && + headers[SADB_X_EXT_UDPENCAP]) { + rval = EINVAL; + goto ret; + } s = spltdb(); @@ -965,6 +980,8 @@ pfkeyv2_send(struct socket *socket, void *message, int len) headers[SADB_X_EXT_DST_MASK], headers[SADB_X_EXT_PROTOCOL], headers[SADB_X_EXT_FLOW_TYPE]); + import_udpencap(newsa, + headers[SADB_X_EXT_UDPENCAP]); headers[SADB_EXT_KEY_AUTH] = NULL; headers[SADB_EXT_KEY_ENCRYPT] = NULL; @@ -1010,6 +1027,8 @@ pfkeyv2_send(struct socket *socket, void *message, int len) PFKEYV2_LIFETIME_SOFT); import_lifetime(sa2, headers[SADB_EXT_LIFETIME_HARD], PFKEYV2_LIFETIME_HARD); + import_udpencap(sa2, + headers[SADB_X_EXT_UDPENCAP]); } splx(s); @@ -1035,6 +1054,12 @@ pfkeyv2_send(struct socket *socket, void *message, int len) rval = EINVAL; goto ret; } + /* UDP encapsulation is only supported for ESP */ + if (smsg->sadb_msg_satype != SADB_SATYPE_ESP && + headers[SADB_X_EXT_UDPENCAP]) { + rval = EINVAL; + goto ret; + } s = spltdb(); @@ -1111,6 +1136,8 @@ pfkeyv2_send(struct socket *socket, void *message, int len) headers[SADB_X_EXT_DST_MASK], headers[SADB_X_EXT_PROTOCOL], headers[SADB_X_EXT_FLOW_TYPE]); + import_udpencap(newsa, + headers[SADB_X_EXT_UDPENCAP]); headers[SADB_EXT_KEY_AUTH] = NULL; headers[SADB_EXT_KEY_ENCRYPT] = NULL; diff --git a/sys/net/pfkeyv2.h b/sys/net/pfkeyv2.h index 152061fcc2b..91aed8ba4e5 100644 --- a/sys/net/pfkeyv2.h +++ b/sys/net/pfkeyv2.h @@ -1,4 +1,4 @@ -/* $OpenBSD: pfkeyv2.h,v 1.48 2003/07/24 09:59:02 itojun Exp $ */ +/* $OpenBSD: pfkeyv2.h,v 1.49 2003/12/02 23:16:29 markus Exp $ */ /* * @(#)COPYRIGHT 1.1 (NRL) January 1998 * @@ -205,6 +205,13 @@ struct sadb_x_cred { uint16_t sadb_x_cred_reserved; }; +struct sadb_x_udpencap { + uint16_t sadb_x_udpencap_len; + uint16_t sadb_x_udpencap_exttype; + uint16_t sadb_x_udpencap_port; + uint16_t sadb_x_udpencap_reserved; +}; + #ifdef _KERNEL #define SADB_X_GETSPROTO(x) \ ( (x) == SADB_SATYPE_AH ? IPPROTO_AH :\ @@ -243,7 +250,8 @@ struct sadb_x_cred { #define SADB_X_EXT_LOCAL_AUTH 28 #define SADB_X_EXT_REMOTE_AUTH 29 #define SADB_X_EXT_SUPPORTED_COMP 30 -#define SADB_EXT_MAX 30 +#define SADB_X_EXT_UDPENCAP 31 +#define SADB_EXT_MAX 31 /* Fix pfkeyv2.c struct pfkeyv2_socket if SATYPE_MAX > 31 */ #define SADB_SATYPE_UNSPEC 0 @@ -304,6 +312,7 @@ struct sadb_x_cred { #define SADB_X_SAFLAGS_CHAINDEL 0x008 /* Delete whole SA chain */ #define SADB_X_SAFLAGS_RANDOMPADDING 0x080 /* Random ESP padding */ #define SADB_X_SAFLAGS_NOREPLAY 0x100 /* No replay counter */ +#define SADB_X_SAFLAGS_UDPENCAP 0x200 /* ESP in UDP */ #define SADB_X_POLICYFLAGS_POLICY 0x0001 /* This is a static policy */ @@ -421,6 +430,7 @@ void export_credentials(void **, struct tdb *, int); void export_sa(void **, struct tdb *); void export_key(void **, struct tdb *, int); void export_auth(void **, struct tdb *, int); +void export_udpencap(void **, struct tdb *); void import_auth(struct tdb *, struct sadb_x_cred *, int); void import_address(struct sockaddr *, struct sadb_address *); @@ -432,5 +442,6 @@ void import_sa(struct tdb *, struct sadb_sa *, struct ipsecinit *); void import_flow(struct sockaddr_encap *, struct sockaddr_encap *, struct sadb_address *, struct sadb_address *, struct sadb_address *, struct sadb_address *, struct sadb_protocol *, struct sadb_protocol *); +void import_udpencap(struct tdb *, struct sadb_x_udpencap *); #endif /* _KERNEL */ #endif /* _NET_PFKEY_V2_H_ */ diff --git a/sys/net/pfkeyv2_convert.c b/sys/net/pfkeyv2_convert.c index b0026c9fd9a..14415c99eca 100644 --- a/sys/net/pfkeyv2_convert.c +++ b/sys/net/pfkeyv2_convert.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pfkeyv2_convert.c,v 1.17 2003/07/24 09:59:02 itojun Exp $ */ +/* $OpenBSD: pfkeyv2_convert.c,v 1.18 2003/12/02 23:16:29 markus Exp $ */ /* * The author of this code is Angelos D. Keromytis (angelos@keromytis.org) * @@ -135,6 +135,9 @@ import_sa(struct tdb *tdb, struct sadb_sa *sadb_sa, struct ipsecinit *ii) if (sadb_sa->sadb_sa_flags & SADB_X_SAFLAGS_NOREPLAY) tdb->tdb_flags |= TDBF_NOREPLAY; + + if (sadb_sa->sadb_sa_flags & SADB_X_SAFLAGS_UDPENCAP) + tdb->tdb_flags |= TDBF_UDPENCAP; } if (sadb_sa->sadb_sa_state != SADB_SASTATE_MATURE) @@ -794,3 +797,23 @@ export_key(void **p, struct tdb *tdb, int type) *p += PADUP(tdb->tdb_amxkeylen); } } + +/* Import/Export remote port for UDP Encapsulation */ +void +import_udpencap(struct tdb *tdb, struct sadb_x_udpencap *sadb_udpencap) +{ + if (sadb_udpencap) + tdb->tdb_udpencap_port = sadb_udpencap->sadb_x_udpencap_port; +} + +void +export_udpencap(void **p, struct tdb *tdb) +{ + struct sadb_x_udpencap *sadb_udpencap = (struct sadb_x_udpencap *) *p; + + sadb_udpencap->sadb_x_udpencap_port = tdb->tdb_udpencap_port; + sadb_udpencap->sadb_x_udpencap_reserved = 0; + sadb_udpencap->sadb_x_udpencap_len = + sizeof(struct sadb_x_udpencap) / sizeof(uint64_t); + *p += sizeof(struct sadb_x_udpencap); +} diff --git a/sys/net/pfkeyv2_parsemessage.c b/sys/net/pfkeyv2_parsemessage.c index 2659832b0d8..762d1159f75 100644 --- a/sys/net/pfkeyv2_parsemessage.c +++ b/sys/net/pfkeyv2_parsemessage.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pfkeyv2_parsemessage.c,v 1.36 2003/02/16 21:30:13 deraadt Exp $ */ +/* $OpenBSD: pfkeyv2_parsemessage.c,v 1.37 2003/12/02 23:16:29 markus Exp $ */ /* * @(#)COPYRIGHT 1.1 (NRL) 17 January 1995 @@ -121,6 +121,7 @@ extern int encdebug; #define BITMAP_X_CREDENTIALS (BITMAP_X_LOCAL_CREDENTIALS | BITMAP_X_REMOTE_CREDENTIALS | BITMAP_X_LOCAL_AUTH | BITMAP_X_REMOTE_AUTH) #define BITMAP_X_FLOW (BITMAP_X_SRC_MASK | BITMAP_X_DST_MASK | BITMAP_X_PROTOCOL | BITMAP_X_SRC_FLOW | BITMAP_X_DST_FLOW | BITMAP_X_FLOW_TYPE) #define BITMAP_X_SUPPORTED_COMP (1 << SADB_X_EXT_SUPPORTED_COMP) +#define BITMAP_X_UDPENCAP (1 << SADB_X_EXT_UDPENCAP) uint32_t sadb_exts_allowed_in[SADB_MAX+1] = { @@ -129,9 +130,9 @@ uint32_t sadb_exts_allowed_in[SADB_MAX+1] = /* GETSPI */ BITMAP_ADDRESS_SRC | BITMAP_ADDRESS_DST | BITMAP_SPIRANGE, /* UPDATE */ - BITMAP_SA | BITMAP_LIFETIME | BITMAP_ADDRESS | BITMAP_KEY | BITMAP_IDENTITY | BITMAP_X_CREDENTIALS | BITMAP_X_FLOW, + BITMAP_SA | BITMAP_LIFETIME | BITMAP_ADDRESS | BITMAP_KEY | BITMAP_IDENTITY | BITMAP_X_CREDENTIALS | BITMAP_X_FLOW | BITMAP_X_UDPENCAP, /* ADD */ - BITMAP_SA | BITMAP_LIFETIME | BITMAP_ADDRESS | BITMAP_KEY | BITMAP_IDENTITY | BITMAP_X_CREDENTIALS | BITMAP_X_FLOW, + BITMAP_SA | BITMAP_LIFETIME | BITMAP_ADDRESS | BITMAP_KEY | BITMAP_IDENTITY | BITMAP_X_CREDENTIALS | BITMAP_X_FLOW | BITMAP_X_UDPENCAP, /* DELETE */ BITMAP_SA | BITMAP_ADDRESS_SRC | BITMAP_ADDRESS_DST, /* GET */ @@ -201,9 +202,9 @@ uint32_t sadb_exts_allowed_out[SADB_MAX+1] = /* GETSPI */ BITMAP_SA | BITMAP_ADDRESS_SRC | BITMAP_ADDRESS_DST, /* UPDATE */ - BITMAP_SA | BITMAP_LIFETIME | BITMAP_ADDRESS | BITMAP_IDENTITY | BITMAP_X_CREDENTIALS | BITMAP_X_FLOW, + BITMAP_SA | BITMAP_LIFETIME | BITMAP_ADDRESS | BITMAP_IDENTITY | BITMAP_X_CREDENTIALS | BITMAP_X_FLOW | BITMAP_X_UDPENCAP, /* ADD */ - BITMAP_SA | BITMAP_LIFETIME | BITMAP_ADDRESS | BITMAP_IDENTITY | BITMAP_X_CREDENTIALS | BITMAP_X_FLOW, + BITMAP_SA | BITMAP_LIFETIME | BITMAP_ADDRESS | BITMAP_IDENTITY | BITMAP_X_CREDENTIALS | BITMAP_X_FLOW | BITMAP_X_UDPENCAP, /* DELETE */ BITMAP_SA | BITMAP_ADDRESS_SRC | BITMAP_ADDRESS_DST, /* GET */ @@ -919,6 +920,13 @@ pfkeyv2_parsemessage(void *p, int len, void **headers) } } break; + case SADB_X_EXT_UDPENCAP: + if (i != sizeof(struct sadb_x_udpencap)) { + DPRINTF(("pfkeyv2_parsemessage: bad UDPENCAP " + "header length\n")); + return (EINVAL); + } + break; default: DPRINTF(("pfkeyv2_parsemessage: unknown extension " "header type %d\n", diff --git a/sys/netinet/ip_esp.h b/sys/netinet/ip_esp.h index 6be3aafcf23..ba1098adaf7 100644 --- a/sys/netinet/ip_esp.h +++ b/sys/netinet/ip_esp.h @@ -1,4 +1,4 @@ -/* $OpenBSD: ip_esp.h,v 1.38 2003/02/12 14:41:07 jason Exp $ */ +/* $OpenBSD: ip_esp.h,v 1.39 2003/12/02 23:16:28 markus Exp $ */ /* * The authors of this code are John Ioannidis (ji@tla.org), * Angelos D. Keromytis (kermit@csd.uch.gr) and @@ -61,21 +61,30 @@ struct espstat u_int32_t esps_toobig; /* Packet got larger than IP_MAXPACKET */ u_int32_t esps_pdrops; /* Packet blocked due to policy */ u_int32_t esps_crypto; /* Crypto processing failure */ + u_int32_t esps_udpencin; /* Input ESP-in-UDP packets */ + u_int32_t esps_udpencout; /* Output ESP-in-UDP packets */ + u_int32_t esps_udpinval; /* Invalid input ESP-in-UDP packets */ }; /* * Names for ESP sysctl objects */ -#define ESPCTL_ENABLE 1 /* Enable ESP processing */ -#define ESPCTL_MAXID 2 +#define ESPCTL_ENABLE 1 /* Enable ESP processing */ +#define ESPCTL_UDPENCAP_ENABLE 2 /* Enable ESP over UDP */ +#define ESPCTL_UDPENCAP_PORT 3 /* UDP port for encapsulation */ +#define ESPCTL_MAXID 4 #define ESPCTL_NAMES { \ { 0, 0 }, \ { "enable", CTLTYPE_INT }, \ + { "udpencap", CTLTYPE_INT }, \ + { "udpencap_port", CTLTYPE_INT }, \ } #ifdef _KERNEL extern int esp_enable; +extern int udpencap_enable; +extern int udpencap_port; extern struct espstat espstat; #endif /* _KERNEL */ #endif /* _NETINET_IP_ESP_H_ */ diff --git a/sys/netinet/ip_ipsp.c b/sys/netinet/ip_ipsp.c index 74ce2e6af27..a8f7e85aea5 100644 --- a/sys/netinet/ip_ipsp.c +++ b/sys/netinet/ip_ipsp.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ip_ipsp.c,v 1.152 2003/05/09 14:59:19 deraadt Exp $ */ +/* $OpenBSD: ip_ipsp.c,v 1.153 2003/12/02 23:16:28 markus Exp $ */ /* * The authors of this code are John Ioannidis (ji@tla.org), * Angelos D. Keromytis (kermit@csd.uch.gr), @@ -860,6 +860,7 @@ ipsp_print_tdb(struct tdb *tdb, char *buffer, size_t buflen) { "random padding", TDBF_RANDOMPADDING }, { "skipcrypto", TDBF_SKIPCRYPTO }, { "usedtunnel", TDBF_USEDTUNNEL }, + { "udpencap", TDBF_UDPENCAP }, }; int l, i, k; @@ -946,6 +947,12 @@ ipsp_print_tdb(struct tdb *tdb, char *buffer, size_t buflen) "\tCrypto ID: %llu\n", tdb->tdb_cryptoid); l += strlen(buffer + l); + if (tdb->tdb_udpencap_port) { + snprintf(buffer + l, buflen - l, + "\tudpencap_port = <%u>\n", ntohs(tdb->tdb_udpencap_port)); + l += strlen(buffer + l); + } + if (tdb->tdb_xform) { snprintf(buffer + l, buflen - l, "\txform = <%s>\n", diff --git a/sys/netinet/ip_ipsp.h b/sys/netinet/ip_ipsp.h index dddb531052e..da6d442f186 100644 --- a/sys/netinet/ip_ipsp.h +++ b/sys/netinet/ip_ipsp.h @@ -1,4 +1,4 @@ -/* $OpenBSD: ip_ipsp.h,v 1.123 2003/07/24 08:03:20 itojun Exp $ */ +/* $OpenBSD: ip_ipsp.h,v 1.124 2003/12/02 23:16:29 markus Exp $ */ /* * The authors of this code are John Ioannidis (ji@tla.org), * Angelos D. Keromytis (kermit@csd.uch.gr), @@ -300,6 +300,7 @@ struct tdb { /* tunnel descriptor block */ #define TDBF_RANDOMPADDING 0x04000 /* Random data in the ESP padding */ #define TDBF_SKIPCRYPTO 0x08000 /* Skip actual crypto processing */ #define TDBF_USEDTUNNEL 0x10000 /* Appended a tunnel header in past */ +#define TDBF_UDPENCAP 0x20000 /* UDP encapsulation */ u_int32_t tdb_flags; /* Flags related to this TDB */ @@ -363,6 +364,8 @@ struct tdb { /* tunnel descriptor block */ u_int32_t tdb_mtu; /* MTU at this point in the chain */ u_int64_t tdb_mtutimeout; /* When to ignore this entry */ + u_int16_t tdb_udpencap_port; /* Peer UDP port */ + struct sockaddr_encap tdb_filter; /* What traffic is acceptable */ struct sockaddr_encap tdb_filtermask; /* And the mask */ @@ -646,6 +649,7 @@ extern struct tdb *ipsp_spd_lookup(struct mbuf *, int, int, int *, int, struct tdb *, struct inpcb *); extern struct tdb *ipsp_spd_inp(struct mbuf *, int, int, int *, int, struct tdb *, struct inpcb *, struct ipsec_policy *); +extern int ipsec_common_input(struct mbuf *, int, int, int, int, int); extern int ipsec_common_input_cb(struct mbuf *, struct tdb *, int, int, struct m_tag *); extern int ipsp_acquire_sa(struct ipsec_policy *, union sockaddr_union *, diff --git a/sys/netinet/ipsec_input.c b/sys/netinet/ipsec_input.c index d4282c826ab..39e7b157821 100644 --- a/sys/netinet/ipsec_input.c +++ b/sys/netinet/ipsec_input.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ipsec_input.c,v 1.69 2003/07/28 10:10:16 markus Exp $ */ +/* $OpenBSD: ipsec_input.c,v 1.70 2003/12/02 23:16:29 markus Exp $ */ /* * The authors of this code are John Ioannidis (ji@tla.org), * Angelos D. Keromytis (kermit@csd.uch.gr) and @@ -74,7 +74,6 @@ #include "bpfilter.h" -int ipsec_common_input(struct mbuf *, int, int, int, int); void *ipsec_common_ctlinput(int, struct sockaddr *, void *, int); #ifdef ENCDEBUG @@ -100,7 +99,8 @@ extern u_char ip6_protox[]; * filtering). */ int -ipsec_common_input(struct mbuf *m, int skip, int protoff, int af, int sproto) +ipsec_common_input(struct mbuf *m, int skip, int protoff, int af, int sproto, + int udpencap) { #define IPSEC_ISTAT(x,y,z) (sproto == IPPROTO_ESP ? (x)++ : \ sproto == IPPROTO_AH ? (y)++ : (z)++) @@ -210,6 +210,14 @@ ipsec_common_input(struct mbuf *m, int skip, int protoff, int af, int sproto) return EINVAL; } + if (udpencap && !(tdbp->tdb_flags & TDBF_UDPENCAP)) { + splx(s); + DPRINTF(("ipsec_common_input(): attempted to use non-udpencap SA %s/%08x/%u\n", ipsp_address(dst_address), ntohl(spi), tdbp->tdb_sproto)); + m_freem(m); + espstat.esps_udpinval++; + return EINVAL; + } + if (tdbp->tdb_xform == NULL) { splx(s); DPRINTF(("ipsec_common_input(): attempted to use uninitialized SA %s/%08x/%u\n", ipsp_address(dst_address), ntohl(spi), tdbp->tdb_sproto)); @@ -227,7 +235,7 @@ ipsec_common_input(struct mbuf *m, int skip, int protoff, int af, int sproto) */ m->m_pkthdr.rcvif = &encif[0].sc_if; } - + /* Register first use, setup expiration timer. */ if (tdbp->tdb_first_use == 0) { int pri; @@ -642,6 +650,10 @@ esp_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlen, void *newp, switch (name[0]) { case ESPCTL_ENABLE: return sysctl_int(oldp, oldlen, newp, newlen, &esp_enable); + case ESPCTL_UDPENCAP_ENABLE: + return sysctl_int(oldp, oldlen, newp, newlen, &udpencap_enable); + case ESPCTL_UDPENCAP_PORT: + return sysctl_int(oldp, oldlen, newp, newlen, &udpencap_port); default: return ENOPROTOOPT; } @@ -695,7 +707,7 @@ ah4_input(struct mbuf *m, ...) va_end(ap); ipsec_common_input(m, skip, offsetof(struct ip, ip_p), AF_INET, - IPPROTO_AH); + IPPROTO_AH, 0); return; } @@ -751,7 +763,7 @@ esp4_input(struct mbuf *m, ...) va_end(ap); ipsec_common_input(m, skip, offsetof(struct ip, ip_p), AF_INET, - IPPROTO_ESP); + IPPROTO_ESP, 0); } /* IPv4 ESP callback. */ @@ -793,7 +805,7 @@ ipcomp4_input(struct mbuf *m, ...) va_end(ap); ipsec_common_input(m, skip, offsetof(struct ip, ip_p), AF_INET, - IPPROTO_IPCOMP); + IPPROTO_IPCOMP, 0); } /* IPv4 IPCOMP callback */ @@ -940,7 +952,7 @@ ah6_input(struct mbuf **mp, int *offp, int proto) } protoff += offsetof(struct ip6_ext, ip6e_nxt); } - ipsec_common_input(*mp, *offp, protoff, AF_INET6, proto); + ipsec_common_input(*mp, *offp, protoff, AF_INET6, proto, 0); return IPPROTO_DONE; } @@ -1026,7 +1038,7 @@ esp6_input(struct mbuf **mp, int *offp, int proto) } protoff += offsetof(struct ip6_ext, ip6e_nxt); } - ipsec_common_input(*mp, *offp, protoff, AF_INET6, proto); + ipsec_common_input(*mp, *offp, protoff, AF_INET6, proto, 0); return IPPROTO_DONE; } @@ -1080,7 +1092,7 @@ ipcomp6_input(struct mbuf **mp, int *offp, int proto) protoff += offsetof(struct ip6_ext, ip6e_nxt); } - ipsec_common_input(*mp, *offp, protoff, AF_INET6, proto); + ipsec_common_input(*mp, *offp, protoff, AF_INET6, proto, 0); return IPPROTO_DONE; } diff --git a/sys/netinet/ipsec_output.c b/sys/netinet/ipsec_output.c index 95ea1b9a330..da7dcfb47b6 100644 --- a/sys/netinet/ipsec_output.c +++ b/sys/netinet/ipsec_output.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ipsec_output.c,v 1.27 2003/07/09 22:03:16 itojun Exp $ */ +/* $OpenBSD: ipsec_output.c,v 1.28 2003/12/02 23:16:29 markus Exp $ */ /* * The author of this code is Angelos D. Keromytis (angelos@cis.upenn.edu) * @@ -44,6 +44,7 @@ #include <netinet6/in6_var.h> #endif /* INET6 */ +#include <netinet/udp.h> #include <netinet/ip_ipsp.h> #include <netinet/ip_ah.h> #include <netinet/ip_esp.h> @@ -56,6 +57,9 @@ #define DPRINTF(x) #endif +int udpencap_enable = 0; /* disabled by default */ +int udpencap_port = 4500; /* triggers decapsulation */ + /* * Loop over a tdb chain, taking into consideration protocol tunneling. The * fourth argument is set if the first encapsulation header is already in @@ -336,12 +340,35 @@ ipsp_process_done(struct mbuf *m, struct tdb *tdb) tdb->tdb_last_used = time.tv_sec; + if (udpencap_enable && udpencap_port && + (tdb->tdb_flags & TDBF_UDPENCAP) != 0) { + struct mbuf *mi; + struct udphdr *uh; + + mi = m_inject(m, sizeof(struct ip), sizeof(struct udphdr), + M_DONTWAIT); + if (mi == NULL) { + m_freem(m); + return ENOMEM; + } + uh = mtod(mi, struct udphdr *); + uh->uh_sport = uh->uh_dport = htons(udpencap_port); + if (tdb->tdb_udpencap_port) + uh->uh_dport = tdb->tdb_udpencap_port; + + uh->uh_ulen = htons(m->m_pkthdr.len - sizeof(struct ip)); + uh->uh_sum = 0; + espstat.esps_udpencout++; + } + switch (tdb->tdb_dst.sa.sa_family) { #ifdef INET case AF_INET: /* Fix the header length, for AH processing. */ ip = mtod(m, struct ip *); ip->ip_len = htons(m->m_pkthdr.len); + if ((tdb->tdb_flags & TDBF_UDPENCAP) != 0) + ip->ip_p = IPPROTO_UDP; break; #endif /* INET */ @@ -359,6 +386,8 @@ ipsp_process_done(struct mbuf *m, struct tdb *tdb) } ip6 = mtod(m, struct ip6_hdr *); ip6->ip6_plen = htons(m->m_pkthdr.len - sizeof(*ip6)); + if ((tdb->tdb_flags & TDBF_UDPENCAP) != 0) + ip6->ip6_nxt = IPPROTO_UDP; break; #endif /* INET6 */ diff --git a/sys/netinet/udp_usrreq.c b/sys/netinet/udp_usrreq.c index 6a36106dafc..2d5aed4bbec 100644 --- a/sys/netinet/udp_usrreq.c +++ b/sys/netinet/udp_usrreq.c @@ -1,4 +1,4 @@ -/* $OpenBSD: udp_usrreq.c,v 1.92 2003/11/04 21:43:16 markus Exp $ */ +/* $OpenBSD: udp_usrreq.c,v 1.93 2003/12/02 23:16:29 markus Exp $ */ /* $NetBSD: udp_usrreq.c,v 1.28 1996/03/16 23:54:03 christos Exp $ */ /* @@ -89,6 +89,11 @@ #include <netinet/udp.h> #include <netinet/udp_var.h> +#ifdef IPSEC +#include <netinet/ip_ipsp.h> +#include <netinet/ip_esp.h> +#endif + #ifdef INET6 #ifndef INET #include <netinet/in.h> @@ -299,6 +304,42 @@ udp_input(struct mbuf *m, ...) } else udpstat.udps_nosum++; +#ifdef IPSEC + if (udpencap_enable && udpencap_port && + uh->uh_dport == htons(udpencap_port)) { + u_int32_t spi; + int skip = iphlen + sizeof(struct udphdr); + + if (m->m_pkthdr.len - skip < sizeof(u_int32_t)) { + /* packet too short */ + m_freem(m); + return; + } + m_copydata(m, skip, sizeof(u_int32_t), (caddr_t) &spi); + /* + * decapsulate if the SPI is not zero, otherwise pass + * to userland + */ + if (spi != 0) { + if ((m = m_pullup2(m, skip)) == NULL) { + udpstat.udps_hdrops++; + return; + } + + /* remove the UDP header */ + bcopy(mtod(m, u_char *), + mtod(m, u_char *) + sizeof(struct udphdr), iphlen); + m_adj(m, sizeof(struct udphdr)); + skip -= sizeof(struct udphdr); + + espstat.esps_udpencin++; + ipsec_common_input(m, skip, offsetof(struct ip, ip_p), + srcsa.sa.sa_family, IPPROTO_ESP, 1); + return; + } + } +#endif + switch (srcsa.sa.sa_family) { case AF_INET: bzero(&srcsa, sizeof(struct sockaddr_in)); diff --git a/usr.bin/netstat/inet.c b/usr.bin/netstat/inet.c index f21ac74069e..84b6ec9bd35 100644 --- a/usr.bin/netstat/inet.c +++ b/usr.bin/netstat/inet.c @@ -1,4 +1,4 @@ -/* $OpenBSD: inet.c,v 1.73 2003/11/07 23:38:48 mcbride Exp $ */ +/* $OpenBSD: inet.c,v 1.74 2003/12/02 23:16:29 markus Exp $ */ /* $NetBSD: inet.c,v 1.14 1995/10/03 21:42:37 thorpej Exp $ */ /* @@ -34,7 +34,7 @@ #if 0 static char sccsid[] = "from: @(#)inet.c 8.4 (Berkeley) 4/20/94"; #else -static char *rcsid = "$OpenBSD: inet.c,v 1.73 2003/11/07 23:38:48 mcbride Exp $"; +static char *rcsid = "$OpenBSD: inet.c,v 1.74 2003/12/02 23:16:29 markus Exp $"; #endif #endif /* not lint */ @@ -817,6 +817,9 @@ esp_stats(u_long off, char *name) p(esps_invalid, "\t%u packet%s attempted to use an invalid TDB\n"); p(esps_toobig, "\t%u packet%s got larger than max IP packet size\n"); p(esps_crypto, "\t%u packet%s that failed crypto processing\n"); + p(esps_udpencin, "\t%u input UDP encapsulated ESP packet%s\n"); + p(esps_udpencout, "\t%u output UDP encapsulated ESP packet%s\n"); + p(esps_udpinval, "\t%u UDP packet%s for non-encapsulating TDB received\n"); p(esps_ibytes, "\t%qu input byte%s\n"); p(esps_obytes, "\t%qu output byte%s\n"); |