diff options
author | Angelos D. Keromytis <angelos@cvs.openbsd.org> | 1999-02-24 22:36:05 +0000 |
---|---|---|
committer | Angelos D. Keromytis <angelos@cvs.openbsd.org> | 1999-02-24 22:36:05 +0000 |
commit | 0532902b4468dd0077e53b22b3ccbf2f409ca26e (patch) | |
tree | 843d815a52c4d7879e3e51ad04bcd6e533b29c8e /sys/net | |
parent | ac584a07f76e50d29c32c02d92c215beb3185a8a (diff) |
PF_KEY_V2, with local extensions for SPD management.
Diffstat (limited to 'sys/net')
-rw-r--r-- | sys/net/pfkey.c | 308 | ||||
-rw-r--r-- | sys/net/pfkeyv2.c | 1507 | ||||
-rw-r--r-- | sys/net/pfkeyv2.h | 571 | ||||
-rw-r--r-- | sys/net/pfkeyv2_parsemessage.c | 550 |
4 files changed, 2612 insertions, 324 deletions
diff --git a/sys/net/pfkey.c b/sys/net/pfkey.c new file mode 100644 index 00000000000..e603d6a3bda --- /dev/null +++ b/sys/net/pfkey.c @@ -0,0 +1,308 @@ +/* +%%% copyright-nrl-97 +This software is Copyright 1997-1998 by Randall Atkinson, Ronald Lee, +Daniel McDonald, Bao Phan, and Chris Winters. All Rights Reserved. All +rights under this copyright have been assigned to the US Naval Research +Laboratory (NRL). The NRL Copyright Notice and License Agreement Version +1.1 (January 17, 1995) applies to this software. +You should have received a copy of the license with this software. If you +didn't get a copy, you may request one from <license@ipv6.nrl.navy.mil>. + +%%% copyright-cmetz-97 +This software is Copyright 1997-1998 by Craig Metz, All Rights Reserved. +The Inner Net License Version 2 applies to this software. +You should have received a copy of the license with this software. If +you didn't get a copy, you may request one from <license@inner.net>. + +*/ +#include <sys/osdep.h> +#include <sys/protosw.h> +#include <sys/domain.h> +#include <net/raw_cb.h> +#include <sys/sysctl.h> +#include <netinet/ip_ipsp.h> + +int pfkey_sysctl(int *, u_int, void *, size_t *, void *, size_t); +extern int encdebug; + +struct pfkey_version { + int protocol; + int (*create)(struct socket *socket); + int (*release)(struct socket *socket); + int (*send)(struct socket *socket, void *message, int len); +}; + +#define PFKEY_PROTOCOL_MAX 3 +static struct pfkey_version *pfkey_versions[PFKEY_PROTOCOL_MAX+1] = { NULL, NULL, NULL, NULL }; + +#define PFKEY_MSG_MAXSZ 4096 + +struct sockaddr pfkey_addr = { 2, PF_KEY, }; + +/* static struct domain pfkey_domain; */ +static int pfkey_usrreq(struct socket *socket, int req, struct mbuf *mbuf, + struct mbuf *nam, struct mbuf *control); +static int pfkey_output(struct mbuf *mbuf, struct socket *socket); + +int pfkey_register(struct pfkey_version *version); +int pfkey_unregister(struct pfkey_version *version); +int pfkey_sendup(struct socket *socket, struct mbuf *packet, int more); +int pfkeyv2_init(void); +void pfkey_init(void); +static int pfkey_buildprotosw(void); + +int +pfkey_register(struct pfkey_version *version) +{ + int rval; + + if ((version->protocol > PFKEY_PROTOCOL_MAX) || (version->protocol < 0)) + return OSDEP_ERROR(EPROTONOSUPPORT); + + if (pfkey_versions[version->protocol]) + return OSDEP_ERROR(EADDRINUSE); + + pfkey_versions[version->protocol] = version; + + if ((rval = pfkey_buildprotosw()) != 0) { + pfkey_versions[version->protocol] = NULL; + return rval; + } + + return 0; +} + +int +pfkey_unregister(struct pfkey_version *version) +{ + int rval; + + if ((rval = pfkey_buildprotosw()) != 0) + return rval; + + pfkey_versions[version->protocol] = NULL; + return 0; +} + +int +pfkey_sendup(struct socket *socket, struct mbuf *packet, int more) +{ + struct mbuf *packet2; + + if (more) { + if (!(packet2 = m_copym(packet, 0, M_COPYALL, M_DONTWAIT))) + return ENOMEM; + } else + packet2 = packet; + + if (!sbappendaddr(&socket->so_rcv, &pfkey_addr, packet2, NULL)) { + m_freem(packet2); + return 0; + } + + sorwakeup(socket); + return 0; +} + +static int +pfkey_output(struct mbuf *mbuf, struct socket *socket) +{ + void *message; + +#if DIAGNOSTIC + if (!mbuf || !(mbuf->m_flags & M_PKTHDR)) + return EINVAL; +#endif /* DIAGNOSTIC */ + + if (mbuf->m_pkthdr.len > PFKEY_MSG_MAXSZ) + return EMSGSIZE; + + if (!(message = malloc((unsigned long) mbuf->m_pkthdr.len, M_TEMP, + M_DONTWAIT))) + return ENOMEM; + + m_copydata(mbuf, 0, mbuf->m_pkthdr.len, message); + + return pfkey_versions[socket->so_proto->pr_protocol]->send(socket, message, mbuf->m_pkthdr.len); +} + +static int +pfkey_attach(struct socket *socket, struct mbuf *proto) +{ + int rval; + int s; + + if (!(socket->so_pcb = malloc(sizeof(struct rawcb), M_PCB, M_DONTWAIT))) + return ENOMEM; + bzero(socket->so_pcb, sizeof(struct rawcb)); + + s = splnet(); + rval = raw_usrreq(socket, PRU_ATTACH, NULL, proto, NULL); + splx(s); + if (rval) + goto ret; + + ((struct rawcb *)socket->so_pcb)->rcb_faddr = &pfkey_addr; + soisconnected(socket); + + socket->so_options |= SO_USELOOPBACK; + if ((rval = pfkey_versions[socket->so_proto->pr_protocol]->create(socket)) + != 0) + goto ret; + + return 0; + +ret: + free(socket->so_pcb, M_PCB); + return rval; +} + +static int +pfkey_detach(struct socket *socket) +{ + int rval, i, s; + + rval = pfkey_versions[socket->so_proto->pr_protocol]->release(socket); + s = splnet(); + i = raw_usrreq(socket, PRU_DETACH, NULL, NULL, NULL); + splx(s); + + if (!rval) + rval = i; + + return rval; +} + +static int +pfkey_usrreq(struct socket *socket, int req, struct mbuf *mbuf, + struct mbuf *nam, struct mbuf *control) +{ + int rval; + int s; + + if ((socket->so_proto->pr_protocol > PFKEY_PROTOCOL_MAX) || + (socket->so_proto->pr_protocol < 0) || + !pfkey_versions[socket->so_proto->pr_protocol]) + return EPROTONOSUPPORT; + + switch(req) { + case PRU_ATTACH: + return pfkey_attach(socket, nam); + + case PRU_DETACH: + return pfkey_detach(socket); + + default: + s = splnet(); + rval = raw_usrreq(socket, req, mbuf, nam, control); + splx(s); + } + + return rval; +} + +static struct domain pfkey_domain = { + PF_KEY, + "PF_KEY", + NULL, /* init */ + NULL, /* externalize */ + NULL, /* dispose */ + NULL, /* protosw */ + NULL, /* protoswNPROTOSW */ + NULL, /* dom_next */ + rn_inithead, /* dom_rtattach */ + 16, /* rtoffset */ + sizeof(struct sockaddr_encap) /* maxrtkey */ +}; + +static struct protosw pfkey_protosw_template = { + SOCK_RAW, + &pfkey_domain, + -1, /* protocol */ + PR_ATOMIC | PR_ADDR, + (void *) raw_input, + (void *) pfkey_output, + (void *) raw_ctlinput, + NULL, /* ctloutput */ + pfkey_usrreq, + NULL, /* init */ + NULL, /* fasttimo */ + NULL, /* slowtimo */ + NULL, /* drain */ + pfkey_sysctl, +}; + +/* XXX fix this so it's reachable */ +int +pfkey_sysctl(int *name, u_int namelen, void *oldp, size_t *oldplenp, + void *newp, size_t newlen) +{ + /* All sysctl names at this level are terminal */ + if (namelen != 1) + return ENOTDIR; + + switch (name[0]) + { + case PFKEYCTL_ENCDEBUG: + return (sysctl_int(oldp, oldplenp, newp, newlen, &encdebug)); + + default: + return ENOPROTOOPT; + } + /* Not reached */ +} + +static int +pfkey_buildprotosw(void) +{ + struct protosw *protosw, *p; + int i, j; + + for (i = j = 0; i <= PFKEY_PROTOCOL_MAX; i++) + if (pfkey_versions[i]) + j++; + + if (j) { + if (!(protosw = malloc(j * sizeof(struct protosw), M_TEMP, M_DONTWAIT))) + return ENOMEM; + + for (i = 0, p = protosw; i <= PFKEY_PROTOCOL_MAX; i++) + if (pfkey_versions[i]) { + bcopy(&pfkey_protosw_template, p, sizeof(struct protosw)); + p->pr_protocol = pfkey_versions[i]->protocol; + p++; + } + + if (pfkey_domain.dom_protosw) + free(pfkey_domain.dom_protosw, M_TEMP); + + pfkey_domain.dom_protosw = protosw; + pfkey_domain.dom_protoswNPROTOSW = p; + } else { + if (!(protosw = malloc(sizeof(struct protosw), M_TEMP, M_DONTWAIT))) + return ENOMEM; + + bcopy(&pfkey_protosw_template, protosw, sizeof(struct protosw)); + + if (pfkey_domain.dom_protosw) + free(pfkey_domain.dom_protosw, M_TEMP); + + pfkey_domain.dom_protosw = protosw; + pfkey_domain.dom_protoswNPROTOSW = protosw; + } + + return 0; +} + +void pfkey_init(void) +{ + if (pfkey_buildprotosw() != 0) + return; + + pfkey_domain.dom_next = domains; + domains = &pfkey_domain; + +#if KEY || CONFIG_PFKEY_V2 + pfkeyv2_init(); +#endif /* KEY || CONFIG_PFKEY_V2 */ +} diff --git a/sys/net/pfkeyv2.c b/sys/net/pfkeyv2.c new file mode 100644 index 00000000000..b8d9c448a49 --- /dev/null +++ b/sys/net/pfkeyv2.c @@ -0,0 +1,1507 @@ +/* +%%% copyright-nrl-97 +This software is Copyright 1997-1998 by Randall Atkinson, Ronald Lee, +Daniel McDonald, Bao Phan, and Chris Winters. All Rights Reserved. All +rights under this copyright have been assigned to the US Naval Research +Laboratory (NRL). The NRL Copyright Notice and License Agreement Version +1.1 (January 17, 1995) applies to this software. +You should have received a copy of the license with this software. If you +didn't get a copy, you may request one from <license@ipv6.nrl.navy.mil>. + +%%% copyright-cmetz-97 +This software is Copyright 1997-1998 by Craig Metz, All Rights Reserved. +The Inner Net License Version 2 applies to this software. +You should have received a copy of the license with this software. If +you didn't get a copy, you may request one from <license@inner.net>. + +*/ +#include <sys/osdep.h> +#include <net/pfkeyv2.h> +#include <netinet/ip_ipsp.h> + +#define PFKEYV2_PROTOCOL 2 +#define GETSPI_TRIES 10 + +struct pfkey_version { + int protocol; + int (*create)(OSDEP_SOCKET *socket); + int (*release)(OSDEP_SOCKET *socket); + int (*send)(OSDEP_SOCKET *socket, void *message, int len); +}; + +static struct pfkey_version pfkeyv2_version; + +#define PFKEYV2_SOCKETFLAGS_REGISTERED 1 +#define PFKEYV2_SOCKETFLAGS_PROMISC 2 + +#define PFKEYV2_SENDMESSAGE_UNICAST 1 +#define PFKEYV2_SENDMESSAGE_REGISTERED 2 +#define PFKEYV2_SENDMESSAGE_BROADCAST 3 + +struct pfkeyv2_socket { + struct pfkeyv2_socket *next; + OSDEP_SOCKET *socket; + int flags; + uint32_t pid; +}; + +static struct pfkeyv2_socket *pfkeyv2_sockets = NULL; + +#if 0 /* XXX */ +static uint32_t pfkeyv2_seq = 1; +#endif + +static int nregistered = 0; +static int npromisc = 0; + +static struct sadb_alg ealgs[] = { +{ SADB_EALG_DESCBC, 64, 64, 64 }, +{ SADB_EALG_3DESCBC, 64, 192, 192 }, +{ SADB_EALG_X_BLF, 64, 5, BLF_MAXKEYLEN}, +{ SADB_EALG_X_CAST, 64, 5, 16}, +{ SADB_EALG_X_SKIPJACK, 64, 10, 10}, +}; + +static struct sadb_alg aalgs[] = { +{ SADB_AALG_SHA1HMAC96, 0, 160, 160 }, +{ SADB_AALG_MD5HMAC96, 0, 128, 128 }, +{ SADB_AALG_X_RIPEMD160HMAC96, 0, 160, 160 } +}; + +extern int pfkey_register(struct pfkey_version *version); +int pfkey_unregister(struct pfkey_version *version); +int pfkey_sendup(OSDEP_SOCKET *socket, OSDEP_PACKET *packet, int more); +int pfkeyv2_parsemessage(void *p, int len, void **headers); +int pfkeyv2_acquire(void *); +int pfkeyv2_init(void); +int pfkeyv2_cleanup(void); +int pfkeyv2_expire(struct tdb *); + +#define EXTLEN(x) (((struct sadb_ext *)(x))->sadb_ext_len * sizeof(uint64_t)) +#define PADUP(x) (((x) + sizeof(uint64_t) - 1) & ~(sizeof(uint64_t) - 1)) + +static int +pfkeyv2_create(OSDEP_SOCKET *socket) +{ + struct pfkeyv2_socket *pfkeyv2_socket; + + if (!(pfkeyv2_socket = OSDEP_MALLOC(sizeof(struct pfkeyv2_socket)))) + return OSDEP_ERROR(ENOMEM); + + bzero(pfkeyv2_socket, sizeof(struct pfkeyv2_socket)); + pfkeyv2_socket->next = pfkeyv2_sockets; + pfkeyv2_socket->socket = socket; + pfkeyv2_socket->pid = OSDEP_CURRENTPID; + + pfkeyv2_sockets = pfkeyv2_socket; + + return 0; +} + +static int +pfkeyv2_release(OSDEP_SOCKET *socket) +{ + struct pfkeyv2_socket **pp; + + for (pp = &pfkeyv2_sockets; + *pp && ((*pp)->socket != socket); + pp = &((*pp)->next)) + ; + + if (*pp) { + struct pfkeyv2_socket *pfkeyv2_socket; + + pfkeyv2_socket = *pp; + *pp = (*pp)->next; + + if (pfkeyv2_socket->flags & PFKEYV2_SOCKETFLAGS_REGISTERED) + nregistered--; + + if (pfkeyv2_socket->flags & PFKEYV2_SOCKETFLAGS_PROMISC) + npromisc--; + + OSDEP_FREE(pfkeyv2_socket); + } + + return 0; +} + +static void +import_sa(struct tdb *tdb, struct sadb_sa *sadb_sa, struct ipsecinit *ii) +{ + if (!sadb_sa) + return; + + if (ii) + { + ii->ii_encalg = sadb_sa->sadb_sa_encrypt; + ii->ii_authalg = sadb_sa->sadb_sa_auth; + + tdb->tdb_spi = sadb_sa->sadb_sa_spi; + tdb->tdb_wnd = sadb_sa->sadb_sa_replay; + + if (sadb_sa->sadb_sa_flags & SADB_SAFLAGS_PFS) + tdb->tdb_flags |= TDBF_PFS; + + if (sadb_sa->sadb_sa_flags & SADB_SAFLAGS_X_HALFIV) + tdb->tdb_flags |= TDBF_HALFIV; + + if (sadb_sa->sadb_sa_flags & SADB_SAFLAGS_X_TUNNEL) + tdb->tdb_flags |= TDBF_TUNNELING; + } + + if (sadb_sa->sadb_sa_state != SADB_SASTATE_MATURE) + tdb->tdb_flags |= TDBF_INVALID; +} + +static void +export_sa(void **p, struct tdb *tdb) +{ + struct sadb_sa *sadb_sa = (struct sadb_sa *)*p; + + sadb_sa->sadb_sa_len = sizeof(struct sadb_sa) / sizeof(uint64_t); + + sadb_sa->sadb_sa_spi = tdb->tdb_spi; + sadb_sa->sadb_sa_replay = tdb->tdb_wnd; + + if (tdb->tdb_flags & TDBF_INVALID) + sadb_sa->sadb_sa_state = SADB_SASTATE_LARVAL; + + if (tdb->tdb_authalgxform) + sadb_sa->sadb_sa_auth = tdb->tdb_authalgxform->type; + + if (tdb->tdb_encalgxform) + sadb_sa->sadb_sa_encrypt = tdb->tdb_encalgxform->type; + + if (tdb->tdb_flags & TDBF_PFS) + sadb_sa->sadb_sa_flags |= SADB_SAFLAGS_PFS; + + if (tdb->tdb_flags & TDBF_HALFIV) + sadb_sa->sadb_sa_flags |= SADB_SAFLAGS_X_HALFIV; + + if (tdb->tdb_flags & TDBF_TUNNELING) + sadb_sa->sadb_sa_flags |= SADB_SAFLAGS_X_TUNNEL; + + *p += sizeof(struct sadb_sa); +} + +static void +import_lifetime(struct tdb *tdb, struct sadb_lifetime *sadb_lifetime, int type) +{ + struct expiration *exp; + + if (!sadb_lifetime) + return; + + switch (type) { + case 0: + if ((tdb->tdb_exp_allocations = + sadb_lifetime->sadb_lifetime_allocations) != 0) + tdb->tdb_flags |= TDBF_ALLOCATIONS; + else + tdb->tdb_flags &= ~TDBF_ALLOCATIONS; + + if ((tdb->tdb_exp_bytes = sadb_lifetime->sadb_lifetime_bytes) != 0) + tdb->tdb_flags |= TDBF_BYTES; + else + tdb->tdb_flags &= ~TDBF_BYTES; + + if ((tdb->tdb_exp_timeout = sadb_lifetime->sadb_lifetime_addtime) != 0) { + tdb->tdb_flags |= TDBF_TIMER; + tdb->tdb_exp_timeout += time.tv_sec; + exp = get_expiration(); + bcopy(&tdb->tdb_dst, &exp->exp_dst, SA_LEN(&tdb->tdb_dst.sa)); + exp->exp_spi = tdb->tdb_spi; + exp->exp_sproto = tdb->tdb_sproto; + exp->exp_timeout = tdb->tdb_exp_timeout; + put_expiration(exp); + } + else + tdb->tdb_flags &= ~TDBF_TIMER; + + if ((tdb->tdb_exp_first_use = sadb_lifetime->sadb_lifetime_usetime) != 0) + tdb->tdb_flags |= TDBF_FIRSTUSE; + else + tdb->tdb_flags &= ~TDBF_FIRSTUSE; + break; + + case 1: + if ((tdb->tdb_soft_allocations = + sadb_lifetime->sadb_lifetime_allocations) != 0) + tdb->tdb_flags |= TDBF_SOFT_ALLOCATIONS; + else + tdb->tdb_flags &= ~TDBF_SOFT_ALLOCATIONS; + + if ((tdb->tdb_soft_bytes = sadb_lifetime->sadb_lifetime_bytes) != 0) + tdb->tdb_flags |= TDBF_SOFT_BYTES; + else + tdb->tdb_flags &= ~TDBF_SOFT_BYTES; + + if ((tdb->tdb_soft_timeout = + sadb_lifetime->sadb_lifetime_addtime) != 0) { + tdb->tdb_flags |= TDBF_SOFT_TIMER; + tdb->tdb_soft_timeout += time.tv_sec; + exp = get_expiration(); + bcopy(&tdb->tdb_dst, &exp->exp_dst, SA_LEN(&tdb->tdb_dst.sa)); + exp->exp_spi = tdb->tdb_spi; + exp->exp_sproto = tdb->tdb_sproto; + exp->exp_timeout = tdb->tdb_soft_timeout; + put_expiration(exp); + } + else + tdb->tdb_flags &= ~TDBF_SOFT_TIMER; + + if ((tdb->tdb_soft_first_use = + sadb_lifetime->sadb_lifetime_usetime) != 0) + tdb->tdb_flags |= TDBF_SOFT_FIRSTUSE; + else + tdb->tdb_flags &= ~TDBF_SOFT_FIRSTUSE; + break; + + case 2: /* Nothing fancy here */ + tdb->tdb_cur_allocations = sadb_lifetime->sadb_lifetime_allocations; + tdb->tdb_cur_bytes = sadb_lifetime->sadb_lifetime_bytes; + tdb->tdb_established = sadb_lifetime->sadb_lifetime_addtime; + tdb->tdb_first_use = sadb_lifetime->sadb_lifetime_usetime; + } +} + +static void +export_lifetime(void **p, struct tdb *tdb, int type) +{ + struct sadb_lifetime *sadb_lifetime = (struct sadb_lifetime *)*p; + + sadb_lifetime->sadb_lifetime_len = sizeof(struct sadb_lifetime) / + sizeof(uint64_t); + + switch (type) { + case 0: + if (tdb->tdb_flags & TDBF_ALLOCATIONS) + sadb_lifetime->sadb_lifetime_allocations = tdb->tdb_exp_allocations; + + if (tdb->tdb_flags & TDBF_BYTES) + sadb_lifetime->sadb_lifetime_bytes = tdb->tdb_exp_bytes; + + if (tdb->tdb_flags & TDBF_TIMER) + sadb_lifetime->sadb_lifetime_addtime = tdb->tdb_exp_timeout - + tdb->tdb_established; + + if (tdb->tdb_flags & TDBF_FIRSTUSE) + sadb_lifetime->sadb_lifetime_usetime = tdb->tdb_exp_first_use - + tdb->tdb_first_use; + break; + + case 1: + if (tdb->tdb_flags & TDBF_SOFT_ALLOCATIONS) + sadb_lifetime->sadb_lifetime_allocations = tdb->tdb_soft_allocations; + + if (tdb->tdb_flags & TDBF_SOFT_BYTES) + sadb_lifetime->sadb_lifetime_bytes = tdb->tdb_soft_bytes; + + if (tdb->tdb_flags & TDBF_SOFT_TIMER) + sadb_lifetime->sadb_lifetime_addtime = tdb->tdb_soft_timeout - + tdb->tdb_established; + + if (tdb->tdb_flags & TDBF_SOFT_FIRSTUSE) + sadb_lifetime->sadb_lifetime_usetime = tdb->tdb_soft_first_use - + tdb->tdb_first_use; + break; + + case 2: + sadb_lifetime->sadb_lifetime_allocations = tdb->tdb_cur_allocations; + sadb_lifetime->sadb_lifetime_bytes = tdb->tdb_cur_bytes; + sadb_lifetime->sadb_lifetime_addtime = tdb->tdb_established; + sadb_lifetime->sadb_lifetime_usetime = tdb->tdb_first_use; + break; + } + + *p += sizeof(struct sadb_lifetime); +} + +static void +import_address(struct sockaddr *sa, struct sadb_address *sadb_address) +{ + int salen; + struct sockaddr *ssa = (struct sockaddr *)((void *) sadb_address + + sizeof(struct sadb_address)); + + if (!sadb_address) + return; + + if (ssa->sa_len) + salen = ssa->sa_len; + else + switch(ssa->sa_family) { + case AF_INET: + salen = sizeof(struct sockaddr_in); + break; +#if INET6 + case AF_INET6: + salen = sizeof(struct sockaddr_in6); + break; +#endif /* INET6 */ + default: + return; + } + + bcopy(ssa, sa, salen); + sa->sa_len = salen; +} + +static void +export_address(void **p, struct sockaddr *sa) +{ + struct sadb_address *sadb_address = (struct sadb_address *)*p; + + sadb_address->sadb_address_len = (sizeof(struct sadb_address) + + PADUP(SA_LEN(sa))) / sizeof(uint64_t); + + *p += sizeof(struct sadb_address); + + bcopy(sa, *p, SA_LEN(sa)); + +#if !OSDEP_SALEN + ((struct sockaddr *)*p)->sa_family = sa->sa_family; +#endif /* !OSDEP_SALEN */ + + *p += PADUP(SA_LEN(sa)); +} + +static void +import_identity(struct tdb *tdb, struct sadb_ident *sadb_ident, int type) +{ + if (!sadb_ident) + return; + + if (type == 0) { + tdb->tdb_srcid_len = EXTLEN(sadb_ident) - + sizeof(struct sadb_ident); + tdb->tdb_srcid_type = sadb_ident->sadb_ident_type; + MALLOC(tdb->tdb_srcid, u_int8_t *, tdb->tdb_srcid_len, M_XDATA, + M_WAITOK); + bcopy((void *)sadb_ident + sizeof(struct sadb_ident), + tdb->tdb_srcid, tdb->tdb_srcid_len); + } else { + tdb->tdb_dstid_len = EXTLEN(sadb_ident) - + sizeof(struct sadb_ident); + tdb->tdb_dstid_type = sadb_ident->sadb_ident_type; + MALLOC(tdb->tdb_dstid, u_int8_t *, tdb->tdb_dstid_len, M_XDATA, + M_WAITOK); + bcopy((void *)sadb_ident + sizeof(struct sadb_ident), + tdb->tdb_dstid, tdb->tdb_dstid_len); + } +} + +static void +export_identity(void **p, struct tdb *tdb, int type) +{ + struct sadb_ident *sadb_ident = (struct sadb_ident *)*p; + + if (type == 0) { + sadb_ident->sadb_ident_len = (sizeof(struct sadb_ident) + PADUP(tdb->tdb_srcid_len)) / sizeof(uint64_t); + sadb_ident->sadb_ident_type = tdb->tdb_srcid_type; + *p += sizeof(struct sadb_ident); + bcopy(tdb->tdb_srcid, *p, tdb->tdb_srcid_len); + *p += PADUP(tdb->tdb_srcid_len); + } else { + sadb_ident->sadb_ident_len = (sizeof(struct sadb_ident) + PADUP(tdb->tdb_dstid_len)) / sizeof(uint64_t); + sadb_ident->sadb_ident_type = tdb->tdb_dstid_type; + *p += sizeof(struct sadb_ident); + bcopy(tdb->tdb_dstid, *p, tdb->tdb_dstid_len); + *p += PADUP(tdb->tdb_dstid_len); + } +} + +static void +import_key(struct ipsecinit *ii, struct sadb_key *sadb_key, int type) +{ + if (!sadb_key) + return; + + if (type == 0) { /* Encryption key */ + ii->ii_enckeylen = sadb_key->sadb_key_bits / 8; + ii->ii_enckey = (void *)sadb_key + sizeof(struct sadb_key); + } else { + ii->ii_authkeylen = sadb_key->sadb_key_bits / 8; + ii->ii_authkey = (void *)sadb_key + sizeof(struct sadb_key); + } +} + +static int +pfkeyv2_sendmessage(void **headers, int mode, OSDEP_SOCKET *socket) +{ + int i, j, rval; + void *p, *buffer = NULL; + OSDEP_PACKET *packet; + struct pfkeyv2_socket *s; + + j = sizeof(struct sadb_msg); + + for (i = 1; i <= SADB_EXT_MAX; i++) + if (headers[i]) + j += ((struct sadb_ext *)headers[i])->sadb_ext_len * sizeof(uint64_t); + + if (!(buffer = OSDEP_MALLOC(j + sizeof(struct sadb_msg)))) { + rval = OSDEP_ERROR(ENOMEM); + goto ret; + } + + p = buffer + sizeof(struct sadb_msg); + bcopy(headers[0], p, sizeof(struct sadb_msg)); + ((struct sadb_msg *)p)->sadb_msg_len = j / sizeof(uint64_t); + p += sizeof(struct sadb_msg); + + for (i = 1; i <= SADB_EXT_MAX; i++) + if (headers[i]) { + ((struct sadb_ext *)headers[i])->sadb_ext_type = i; + bcopy(headers[i], p, EXTLEN(headers[i])); + p += EXTLEN(headers[i]); + } + + if ((rval = OSDEP_DATATOPACKET(buffer + sizeof(struct sadb_msg), + j, &packet)) != 0) + goto ret; + + switch(mode) { + case PFKEYV2_SENDMESSAGE_UNICAST: + pfkey_sendup(socket, packet, 0); + + bzero(buffer, sizeof(struct sadb_msg)); + ((struct sadb_msg *)buffer)->sadb_msg_version = PF_KEY_V2; + ((struct sadb_msg *)buffer)->sadb_msg_type = SADB_X_PROMISC; + ((struct sadb_msg *)buffer)->sadb_msg_len = + (sizeof(struct sadb_msg) + j) / sizeof(uint64_t); + ((struct sadb_msg *)buffer)->sadb_msg_seq = 0; + + if ((rval = OSDEP_DATATOPACKET(buffer, sizeof(struct sadb_msg) + j, + &packet)) != 0) + goto ret; + + for (s = pfkeyv2_sockets; s; s = s->next) + if ((s->flags & PFKEYV2_SOCKETFLAGS_PROMISC) && (s->socket != socket)) + pfkey_sendup(s->socket, packet, 1); + + OSDEP_ZEROPACKET(packet); + OSDEP_FREEPACKET(packet); + break; + + case PFKEYV2_SENDMESSAGE_REGISTERED: + for (s = pfkeyv2_sockets; s; s = s->next) + if (s->flags & PFKEYV2_SOCKETFLAGS_REGISTERED) + pfkey_sendup(s->socket, packet, 1); + + OSDEP_FREEPACKET(packet); + + bzero(buffer, sizeof(struct sadb_msg)); + ((struct sadb_msg *)buffer)->sadb_msg_version = PF_KEY_V2; + ((struct sadb_msg *)buffer)->sadb_msg_type = SADB_X_PROMISC; + ((struct sadb_msg *)buffer)->sadb_msg_len = + (sizeof(struct sadb_msg) + j) / sizeof(uint64_t); + ((struct sadb_msg *)buffer)->sadb_msg_seq = 0; + + if ((rval = OSDEP_DATATOPACKET(buffer, sizeof(struct sadb_msg) + j, + &packet)) != 0) + goto ret; + + for (s = pfkeyv2_sockets; s; s = s->next) + if ((s->flags & PFKEYV2_SOCKETFLAGS_PROMISC) && + (s->flags & PFKEYV2_SOCKETFLAGS_REGISTERED)) + pfkey_sendup(s->socket, packet, 1); + + OSDEP_FREEPACKET(packet); + break; + + case PFKEYV2_SENDMESSAGE_BROADCAST: + for (s = pfkeyv2_sockets; s; s = s->next) + pfkey_sendup(s->socket, packet, 1); + + OSDEP_FREEPACKET(packet); + break; + } + +ret: + bzero(buffer, j + sizeof(struct sadb_msg)); + OSDEP_FREE(buffer); + return rval; +} + +extern uint32_t sadb_exts_allowed_out[SADB_MAX+1]; +extern uint32_t sadb_exts_required_out[SADB_MAX+1]; + +static int +pfkeyv2_get(struct tdb *sa, void **headers, void **buffer) +{ + int rval, i; + void *p; + + i = sizeof(struct sadb_sa) + sizeof(struct sadb_lifetime); + + if (sa->tdb_soft_allocations || sa->tdb_soft_bytes || + sa->tdb_soft_timeout || sa->tdb_soft_first_use) + i += sizeof(struct sadb_lifetime); + + if (sa->tdb_exp_allocations || sa->tdb_exp_bytes || + sa->tdb_exp_timeout || sa->tdb_exp_first_use) + i += sizeof(struct sadb_lifetime); + + if (sa->tdb_src.sa.sa_family) + i += sizeof(struct sadb_address) + PADUP(SA_LEN(&sa->tdb_src.sa)); + + if (sa->tdb_dst.sa.sa_family) + i += sizeof(struct sadb_address) + PADUP(SA_LEN(&sa->tdb_dst.sa)); + + if (sa->tdb_proxy.sa.sa_family) + i += sizeof(struct sadb_address) + PADUP(SA_LEN(&sa->tdb_proxy.sa)); + + if (sa->tdb_srcid_len) + i += PADUP(sa->tdb_srcid_len) + sizeof(struct sadb_ident); + + if (sa->tdb_dstid_len) + i += PADUP(sa->tdb_dstid_len) + sizeof(struct sadb_ident); + + if (!(p = OSDEP_MALLOC(i))) { + rval = OSDEP_ERROR(ENOMEM); + goto ret; + } + + *buffer = p; + + bzero(p, i); + + headers[SADB_EXT_SA] = p; + export_sa(&p, sa); + + headers[SADB_EXT_LIFETIME_CURRENT] = p; + export_lifetime(&p, sa, 2); + + if (sa->tdb_soft_allocations || sa->tdb_soft_bytes || + sa->tdb_soft_first_use || sa->tdb_soft_timeout) { + headers[SADB_EXT_LIFETIME_SOFT] = p; + export_lifetime(&p, sa, 1); + } + + if (sa->tdb_exp_allocations || sa->tdb_exp_bytes || + sa->tdb_exp_first_use || sa->tdb_exp_timeout) { + headers[SADB_EXT_LIFETIME_HARD] = p; + export_lifetime(&p, sa, 0); + } + + headers[SADB_EXT_ADDRESS_SRC] = p; + export_address(&p, (struct sockaddr *)&sa->tdb_src); + + headers[SADB_EXT_ADDRESS_DST] = p; + export_address(&p, (struct sockaddr *)&sa->tdb_dst); + + if (SA_LEN(&sa->tdb_proxy.sa)) { + headers[SADB_EXT_ADDRESS_PROXY] = p; + export_address(&p, (struct sockaddr *)&sa->tdb_proxy); + } + + if (sa->tdb_srcid_len) { + headers[SADB_EXT_IDENTITY_SRC] = p; + export_identity(&p, sa, 0); + } + + if (sa->tdb_dstid_len) { + headers[SADB_EXT_IDENTITY_DST] = p; + export_identity(&p, sa, 1); + } + + rval = 0; + +ret: + return rval; +} + +struct dump_state { + struct sadb_msg *sadb_msg; + OSDEP_SOCKET *socket; +}; + +#if 0 /* XXX Need to add a tdb_walk routine for this to work */ +static int +pfkeyv2_dump_walker(struct tdb *sa, void *state) +{ + struct dump_state *dump_state = (struct dump_state *)state; + void *headers[SADB_EXT_MAX+1], *buffer; + int rval; + + if (!dump_state->sadb_msg->sadb_msg_satype || + (sa->tdb_satype == dump_state->sadb_msg->sadb_msg_satype)) { + bzero(headers, sizeof(headers)); + headers[0] = (void *)dump_state->sadb_msg; + if ((rval = pfkeyv2_get(sa, headers, &buffer)) != 0) + return rval; + rval = pfkeyv2_sendmessage(headers, PFKEYV2_SENDMESSAGE_UNICAST, + dump_state->socket); + OSDEP_FREE(buffer); + if (rval) + return rval; + } + + return 0; +} +#endif /* 0 */ + +static int +pfkeyv2_send(OSDEP_SOCKET *socket, void *message, int len) +{ + void *headers[SADB_EXT_MAX + 1]; + int i, j, rval = 0, mode = PFKEYV2_SENDMESSAGE_BROADCAST, delflag = 0; + struct pfkeyv2_socket *pfkeyv2_socket, *s = NULL; + void *freeme = NULL, *bckptr = NULL; + struct tdb sa, *sa2 = NULL; + + bzero(headers, sizeof(headers)); + + for (pfkeyv2_socket = pfkeyv2_sockets; + pfkeyv2_socket; + pfkeyv2_socket = pfkeyv2_socket->next) + if (pfkeyv2_socket->socket == socket) + break; + + if (!pfkeyv2_socket) { + rval = OSDEP_ERROR(EINVAL); + goto ret; + } + + if (npromisc) { + OSDEP_PACKET *packet; + + if (!(freeme = OSDEP_MALLOC(sizeof(struct sadb_msg) + len))) { + rval = OSDEP_ERROR(ENOMEM); + goto ret; + } + + bzero(freeme, sizeof(struct sadb_msg)); + ((struct sadb_msg *)freeme)->sadb_msg_version = PF_KEY_V2; + ((struct sadb_msg *)freeme)->sadb_msg_type = SADB_X_PROMISC; + ((struct sadb_msg *)freeme)->sadb_msg_len = + (sizeof(struct sadb_msg) + len) / sizeof(uint64_t); + ((struct sadb_msg *)freeme)->sadb_msg_seq = OSDEP_CURRENTPID; + + bcopy(message, freeme + sizeof(struct sadb_msg), len); + + if ((rval = OSDEP_DATATOPACKET(freeme, sizeof(struct sadb_msg) + len, + &packet)) != 0) + goto ret; + + for (s = pfkeyv2_sockets; s; s = s->next) + if (s->flags & PFKEYV2_SOCKETFLAGS_PROMISC) + pfkey_sendup(s->socket, packet, 1); + + OSDEP_ZEROPACKET(packet); + OSDEP_FREEPACKET(packet); + + bzero(freeme, sizeof(struct sadb_msg) + len); + OSDEP_FREE(freeme); + freeme = NULL; + } + + if ((rval = pfkeyv2_parsemessage(message, len, headers)) != 0) + goto ret; + + switch(((struct sadb_msg *)headers[0])->sadb_msg_type) { + case SADB_GETSPI: + bzero(&sa, sizeof(struct tdb)); + + switch (((struct sadb_msg *)headers[0])->sadb_msg_satype) { + case SADB_SATYPE_AH: + sa.tdb_sproto = IPPROTO_AH; + break; + + case SADB_SATYPE_ESP: + sa.tdb_sproto = IPPROTO_ESP; + break; + + case SADB_SATYPE_X_AH_OLD: + sa.tdb_sproto = IPPROTO_AH; + break; + + case SADB_SATYPE_X_ESP_OLD: + sa.tdb_sproto = IPPROTO_ESP; + break; + + case SADB_SATYPE_X_IPIP: + sa.tdb_sproto = IPPROTO_IPIP; + break; + + default: /* Nothing else supported */ + rval = EOPNOTSUPP; + goto ret; + } + + import_address((struct sockaddr *)&sa.tdb_src, + headers[SADB_EXT_ADDRESS_SRC]); + import_address((struct sockaddr *)&sa.tdb_dst, + headers[SADB_EXT_ADDRESS_DST]); + + sa.tdb_spi = reserve_spi(((struct sadb_spirange *)headers[SADB_EXT_SPIRANGE])->sadb_spirange_min, ((struct sadb_spirange *)headers[SADB_EXT_SPIRANGE])->sadb_spirange_max, &sa.tdb_src, &sa.tdb_dst, sa.tdb_sproto, &rval); + if (sa.tdb_spi == 0) + goto ret; + + if (!(freeme = OSDEP_MALLOC(sizeof(struct sadb_sa)))) { + rval = OSDEP_ERROR(ENOMEM); + goto ret; + } + + bzero(freeme, sizeof(struct sadb_sa)); + headers[SADB_EXT_SPIRANGE] = NULL; + headers[SADB_EXT_SA] = freeme; + bckptr = freeme; + export_sa((void **) &bckptr, &sa); + break; + + case SADB_UPDATE: + sa2 = gettdb(((struct sadb_sa *)headers[SADB_EXT_SA])->sadb_sa_spi, + (union sockaddr_union *)(headers[SADB_EXT_ADDRESS_DST] + + sizeof(struct sadb_address)), + SADB_GETSPROTO(((struct sadb_msg *)headers[0])->sadb_msg_satype)); + if (sa2 == NULL) { + rval = EEXIST; + goto ret; + } + + if (sa2->tdb_flags & TDBF_INVALID) { + MALLOC(freeme, struct tdb *, sizeof(struct tdb), M_TDB, M_WAITOK); + if (freeme == NULL) { + rval = ENOMEM; + goto ret; + } + + bzero(freeme, sizeof(struct tdb)); + + { + struct tdb *newsa = (struct tdb *)freeme; + struct ipsecinit ii; + int alg; + + bzero(&ii, sizeof(struct ipsecinit)); + switch (((struct sadb_msg *)headers[0])->sadb_msg_satype) { + case SADB_SATYPE_AH: + newsa->tdb_sproto = IPPROTO_AH; + alg = XF_NEW_AH; + break; + + case SADB_SATYPE_ESP: + newsa->tdb_sproto = IPPROTO_ESP; + alg = XF_NEW_ESP; + break; + + case SADB_SATYPE_X_AH_OLD: + newsa->tdb_sproto = IPPROTO_AH; + alg = XF_OLD_AH; + break; + + case SADB_SATYPE_X_ESP_OLD: + newsa->tdb_sproto = IPPROTO_ESP; + alg = XF_OLD_ESP; + break; + + case SADB_SATYPE_X_IPIP: + newsa->tdb_sproto = IPPROTO_IPIP; + alg = XF_IP4; + break; + + default: /* Nothing else supported */ + rval = EOPNOTSUPP; + goto ret; + } + + import_sa(newsa, headers[SADB_EXT_SA], &ii); + import_address((struct sockaddr *)&newsa->tdb_src, + headers[SADB_EXT_ADDRESS_SRC]); + import_address((struct sockaddr *)&newsa->tdb_dst, + headers[SADB_EXT_ADDRESS_DST]); + import_address((struct sockaddr *)&newsa->tdb_proxy, + headers[SADB_EXT_ADDRESS_PROXY]); + + import_lifetime(newsa, headers[SADB_EXT_LIFETIME_CURRENT], 2); + import_lifetime(newsa, headers[SADB_EXT_LIFETIME_SOFT], 1); + import_lifetime(newsa, headers[SADB_EXT_LIFETIME_HARD], 0); + import_key(&ii, headers[SADB_EXT_KEY_AUTH], 1); + import_key(&ii, headers[SADB_EXT_KEY_ENCRYPT], 0); + import_identity(newsa, headers[SADB_EXT_IDENTITY_SRC], 0); + import_identity(newsa, headers[SADB_EXT_IDENTITY_DST], 1); + + rval = tdb_init(newsa, alg, &ii); + if (rval) { + rval = OSDEP_ERROR(EINVAL); + tdb_delete(freeme, 0); + freeme = NULL; + goto ret; + } + } + + headers[SADB_EXT_KEY_AUTH] = NULL; + headers[SADB_EXT_KEY_ENCRYPT] = NULL; + + tdb_delete(sa2, 0); + puttdb((struct tdb *) freeme); + sa2 = freeme = NULL; + } else { + if (headers[SADB_EXT_ADDRESS_PROXY] || + headers[SADB_EXT_KEY_AUTH] || + headers[SADB_EXT_KEY_ENCRYPT] || + headers[SADB_EXT_IDENTITY_SRC] || + headers[SADB_EXT_IDENTITY_DST] || + headers[SADB_EXT_SENSITIVITY]) { + rval = OSDEP_ERROR(EINVAL); + goto ret; + } + + import_sa(sa2, headers[SADB_EXT_SA], NULL); + import_lifetime(sa2, headers[SADB_EXT_LIFETIME_CURRENT], 2); + import_lifetime(sa2, headers[SADB_EXT_LIFETIME_SOFT], 1); + import_lifetime(sa2, headers[SADB_EXT_LIFETIME_HARD], 0); + } + break; + + case SADB_ADD: + sa2 = gettdb(((struct sadb_sa *)headers[SADB_EXT_SA])->sadb_sa_spi, + (union sockaddr_union *)(headers[SADB_EXT_ADDRESS_DST] + + sizeof(struct sadb_address)), + SADB_GETSPROTO(((struct sadb_msg *)headers[0])->sadb_msg_satype)); + if (sa2 != NULL) { + rval = EEXIST; + goto ret; + } + + if (((struct sadb_sa *)headers[SADB_EXT_SA])->sadb_sa_state != + SADB_SASTATE_MATURE) { + rval = OSDEP_ERROR(EINVAL); + goto ret; + } + + MALLOC(freeme, struct tdb *, sizeof(struct tdb), M_TDB, M_WAITOK); + if (freeme == NULL) { + rval = ENOMEM; + goto ret; + } + + bzero(freeme, sizeof(struct tdb)); + + { + struct tdb *newsa = (struct tdb *) freeme; + struct ipsecinit ii; + int alg; + + bzero(&ii, sizeof(struct ipsecinit)); + switch (((struct sadb_msg *)headers[0])->sadb_msg_satype) { + case SADB_SATYPE_AH: + newsa->tdb_sproto = IPPROTO_AH; + alg = XF_NEW_AH; + break; + + case SADB_SATYPE_ESP: + newsa->tdb_sproto = IPPROTO_ESP; + alg = XF_NEW_ESP; + break; + + case SADB_SATYPE_X_AH_OLD: + newsa->tdb_sproto = IPPROTO_AH; + alg = XF_OLD_AH; + break; + + case SADB_SATYPE_X_ESP_OLD: + newsa->tdb_sproto = IPPROTO_ESP; + alg = XF_OLD_ESP; + break; + + case SADB_SATYPE_X_IPIP: + newsa->tdb_sproto = IPPROTO_IPIP; + alg = XF_IP4; + break; + + default: /* Nothing else supported */ + rval = EOPNOTSUPP; + goto ret; + } + + import_sa(newsa, headers[SADB_EXT_SA], &ii); + import_address((struct sockaddr *)&newsa->tdb_src, + headers[SADB_EXT_ADDRESS_SRC]); + import_address((struct sockaddr *)&newsa->tdb_dst, + headers[SADB_EXT_ADDRESS_DST]); + import_address((struct sockaddr *)&newsa->tdb_proxy, + headers[SADB_EXT_ADDRESS_PROXY]); + + import_lifetime(newsa, headers[SADB_EXT_LIFETIME_CURRENT], 2); + import_lifetime(newsa, headers[SADB_EXT_LIFETIME_SOFT], 1); + import_lifetime(newsa, headers[SADB_EXT_LIFETIME_HARD], 0); + import_key(&ii, headers[SADB_EXT_KEY_AUTH], 1); + import_key(&ii, headers[SADB_EXT_KEY_ENCRYPT], 0); + import_identity(newsa, headers[SADB_EXT_IDENTITY_SRC], 0); + import_identity(newsa, headers[SADB_EXT_IDENTITY_DST], 1); + + rval = tdb_init(newsa, alg, &ii); + if (rval) { + rval = OSDEP_ERROR(EINVAL); + tdb_delete(freeme, 0); + freeme = NULL; + goto ret; + } + } + + headers[SADB_EXT_KEY_AUTH] = NULL; + headers[SADB_EXT_KEY_ENCRYPT] = NULL; + + puttdb((struct tdb *)freeme); + freeme = NULL; + break; + + case SADB_DELETE: + sa2 = gettdb(((struct sadb_sa *)headers[SADB_EXT_SA])->sadb_sa_spi, + (union sockaddr_union *)(headers[SADB_EXT_ADDRESS_DST] + + sizeof(struct sadb_address)), + SADB_GETSPROTO(((struct sadb_msg *)headers[0])->sadb_msg_satype)); + if (sa2 == NULL) { + rval = EEXIST; + goto ret; + } + + tdb_delete(sa2, ((struct sadb_sa *)headers[SADB_EXT_SA])->sadb_sa_flags & SADB_SAFLAGS_X_CHAINDEL); + sa2 = NULL; + break; + + case SADB_GET: + sa2 = gettdb(((struct sadb_sa *)headers[SADB_EXT_SA])->sadb_sa_spi, + (union sockaddr_union *)(headers[SADB_EXT_ADDRESS_DST] + + sizeof(struct sadb_address)), + SADB_GETSPROTO(((struct sadb_msg *)headers[0])->sadb_msg_satype)); + if (sa2 == NULL) { + rval = EEXIST; + goto ret; + } + + rval = pfkeyv2_get(sa2, headers, &freeme); + if (rval) + mode = PFKEYV2_SENDMESSAGE_UNICAST; + break; + + case SADB_REGISTER: + pfkeyv2_socket->flags |= PFKEYV2_SOCKETFLAGS_REGISTERED; + nregistered++; + + i = sizeof(struct sadb_supported) + sizeof(ealgs) + sizeof(aalgs); + + if (!(freeme = OSDEP_MALLOC(i))) { + rval = OSDEP_ERROR(ENOMEM); + goto ret; + } + + bzero(freeme, i); + + ((struct sadb_supported *)freeme)->sadb_supported_len = + i / sizeof(uint64_t); + ((struct sadb_supported *)freeme)->sadb_supported_nauth = + sizeof(aalgs) / sizeof(struct sadb_alg); + ((struct sadb_supported *)freeme)->sadb_supported_nencrypt = + sizeof(ealgs) / sizeof(struct sadb_alg); + + { + void *p = freeme + sizeof(struct sadb_supported); + + bcopy(&aalgs[0], p, sizeof(aalgs)); + p += sizeof(aalgs); + bcopy(&ealgs[0], p, sizeof(ealgs)); + } + + headers[SADB_EXT_SUPPORTED] = freeme; + break; + + case SADB_ACQUIRE: + rval = 0; + break; + + case SADB_EXPIRE: + rval = 0; + break; + + case SADB_FLUSH: +/* XXX netsec_sadb_flush(((struct sadb_msg *)headers[0])->sadb_msg_satype); */ + rval = 0; + break; + + case SADB_DUMP: + { + struct dump_state dump_state; + dump_state.sadb_msg = (struct sadb_msg *)headers[0]; + dump_state.socket = socket; + +/** XXX + if (!(rval = netsec_sadb_walk(pfkeyv2_dump_walker, &dump_state, 1))) + goto realret; +*/ + if ((rval == OSDEP_ERROR(ENOMEM)) || (rval == OSDEP_ERROR(ENOBUFS))) + rval = 0; + } + break; + + + case SADB_X_DELFLOW: + delflag = 1; /* fall through */ + + case SADB_X_ADDFLOW: /* XXX This is highly INET dependent */ + { + struct sockaddr_encap encapdst, encapgw, encapnetmask; + struct flow *flow = NULL, *flow2 = NULL; + union sockaddr_union *src, *dst, *srcmask, *dstmask; + union sockaddr_union alts, altm; + u_int8_t sproto = 0, local = 0; + + if (!delflag) + { + sa2 = gettdb(((struct sadb_sa *)headers[SADB_EXT_SA])->sadb_sa_spi, (union sockaddr_union *)(headers[SADB_EXT_ADDRESS_DST] + sizeof(struct sadb_address)), SADB_GETSPROTO(((struct sadb_msg *)headers[0])->sadb_msg_satype)); + + if (sa2 == NULL) { + rval = EEXIST; + goto ret; + } + } + + local = ((struct sadb_sa *)headers[SADB_EXT_SA])->sadb_sa_flags & + SADB_SAFLAGS_X_LOCALFLOW; + bzero(&encapdst, sizeof(struct sockaddr_encap)); + bzero(&encapnetmask, sizeof(struct sockaddr_encap)); + bzero(&encapgw, sizeof(struct sockaddr_encap)); + bzero(&alts, sizeof(alts)); + bzero(&altm, sizeof(altm)); + + src = (union sockaddr_union *) (headers[SADB_EXT_X_SRC_FLOW] + sizeof(struct sadb_address)); + dst = (union sockaddr_union *) (headers[SADB_EXT_X_DST_FLOW] + sizeof(struct sadb_address)); + srcmask = (union sockaddr_union *) (headers[SADB_EXT_X_SRC_MASK] + sizeof(struct sadb_address)); + dstmask = (union sockaddr_union *) (headers[SADB_EXT_X_DST_MASK] + sizeof(struct sadb_address)); + + if (headers[SADB_EXT_X_PROTOCOL]) + sproto = ((struct sadb_protocol *) headers[SADB_EXT_X_PROTOCOL])->sadb_protocol_proto; + else + sproto = 0; + + src->sin.sin_addr.s_addr &= srcmask->sin.sin_addr.s_addr; + dst->sin.sin_addr.s_addr &= dstmask->sin.sin_addr.s_addr; + + flow = find_global_flow(src, srcmask, dst, dstmask, sproto); + if ((delflag && (flow == NULL)) || + (!delflag && (flow != NULL))) + { + rval = EEXIST; + goto ret; + } + + /* Check for 0.0.0.0/255.255.255.255 if the flow is local */ + if (local) + { + alts.sin.sin_family = altm.sin.sin_family = AF_INET; + alts.sin.sin_len = altm.sin.sin_len = sizeof(struct sockaddr_in); + alts.sin.sin_addr.s_addr = INADDR_ANY; + altm.sin.sin_addr.s_addr = INADDR_BROADCAST; + + flow2 = find_global_flow(&alts, &altm, dst, dstmask, sproto); + if ((delflag && (flow2 == NULL)) || + (!delflag && (flow2 != NULL))) + { + rval = EEXIST; + goto ret; + } + } + + if (!delflag) + { + flow = get_flow(); + bcopy(src, &flow->flow_src, src->sa.sa_len); + bcopy(dst, &flow->flow_dst, dst->sa.sa_len); + bcopy(srcmask, &flow->flow_srcmask, srcmask->sa.sa_len); + bcopy(dstmask, &flow->flow_dstmask, dstmask->sa.sa_len); + flow->flow_proto = sproto; + put_flow(flow, sa2); + + if (local) + { + flow2 = get_flow(); + bcopy(&alts, &flow2->flow_src, alts.sa.sa_len); + bcopy(dst, &flow2->flow_dst, dst->sa.sa_len); + bcopy(&altm, &flow2->flow_srcmask, altm.sa.sa_len); + bcopy(dstmask, &flow2->flow_dstmask, dstmask->sa.sa_len); + flow2->flow_proto = sproto; + put_flow(flow2, sa2); + } + } + + /* Setup the encap fields */ + encapdst.sen_len = SENT_IP4_LEN; + encapdst.sen_family = PF_KEY; + encapdst.sen_type = SENT_IP4; + encapdst.sen_ip_src = flow->flow_src.sin.sin_addr; + encapdst.sen_ip_dst = flow->flow_dst.sin.sin_addr; + encapdst.sen_proto = flow->flow_proto; + encapdst.sen_sport = flow->flow_src.sin.sin_port; + encapdst.sen_dport = flow->flow_dst.sin.sin_port; + + if (!delflag) + { + encapgw.sen_len = SENT_IPSP_LEN; + encapgw.sen_family = PF_KEY; + encapgw.sen_type = SENT_IPSP; + encapgw.sen_ipsp_dst = sa2->tdb_dst.sin.sin_addr; + encapgw.sen_ipsp_spi = sa2->tdb_spi; + encapgw.sen_ipsp_sproto = sa2->tdb_sproto; + } + + encapnetmask.sen_len = SENT_IP4_LEN; + encapnetmask.sen_family = PF_KEY; + encapnetmask.sen_type = SENT_IP4; + encapnetmask.sen_ip_src = flow->flow_srcmask.sin.sin_addr; + encapnetmask.sen_ip_dst = flow->flow_dstmask.sin.sin_addr; + + if (flow->flow_proto) + { + encapnetmask.sen_proto = 0xff; + + if (flow->flow_src.sin.sin_port) + encapnetmask.sen_sport = 0xffff; + + if (flow->flow_dst.sin.sin_port) + encapnetmask.sen_dport = 0xffff; + } + + /* Add the entry in the routing table */ + if (delflag) + { + rtrequest(RTM_DELETE, (struct sockaddr *) &encapdst, + (struct sockaddr *) 0, + (struct sockaddr *) &encapnetmask, + 0, (struct rtentry **) 0); + + delete_flow(flow, flow->flow_sa); + ipsec_in_use--; + } + else + { + rval = rtrequest(RTM_ADD, (struct sockaddr *) &encapdst, + (struct sockaddr *) &encapgw, + (struct sockaddr *) &encapnetmask, + RTF_UP | RTF_GATEWAY | RTF_STATIC, + (struct rtentry **) 0); + + if (rval) + { + delete_flow(flow, sa2); + if (flow2) + delete_flow(flow2, sa2); + goto ret; + } + + ipsec_in_use++; + } + + /* If this is a "local" packet flow */ + if (local) + { + encapdst.sen_ip_src.s_addr = INADDR_ANY; + encapnetmask.sen_ip_src.s_addr = INADDR_BROADCAST; + + if (delflag) + { + rtrequest(RTM_DELETE, (struct sockaddr *) &encapdst, + (struct sockaddr *) 0, + (struct sockaddr *) &encapnetmask, 0, + (struct rtentry **) 0); + + delete_flow(flow2, flow2->flow_sa); + ipsec_in_use--; + } + else + { + rval = rtrequest(RTM_ADD, (struct sockaddr *) &encapdst, + (struct sockaddr *) &encapgw, + (struct sockaddr *) &encapnetmask, + RTF_UP | RTF_GATEWAY | RTF_STATIC, + (struct rtentry **) 0); + + if (rval) + { + /* Delete the first entry inserted */ + encapdst.sen_ip_src = flow->flow_src.sin.sin_addr; + encapnetmask.sen_ip_src = flow->flow_srcmask.sin.sin_addr; + + rtrequest(RTM_DELETE, (struct sockaddr *) &encapdst, + (struct sockaddr *) 0, + (struct sockaddr *) &encapnetmask, 0, + (struct rtentry **) 0); + + delete_flow(flow, sa2); + delete_flow(flow2, sa2); + ipsec_in_use--; + goto ret; + } + + ipsec_in_use++; + } + } + } + + break; + + case SADB_X_GRPSPIS: + { + struct tdb *tdb1, *tdb2, *tdb3; + + tdb1 = gettdb(((struct sadb_sa *)headers[SADB_EXT_SA])->sadb_sa_spi, + (union sockaddr_union *)(headers[SADB_EXT_ADDRESS_DST] + + sizeof(struct sadb_address)), + SADB_GETSPROTO(((struct sadb_msg *)headers[0])->sadb_msg_satype)); + if (tdb1 == NULL) { + rval = EEXIST; + goto ret; + } + + tdb2 = gettdb(((struct sadb_sa *)headers[SADB_EXT_X_SA2])->sadb_sa_spi, + (union sockaddr_union *)(headers[SADB_EXT_X_DST2] + + sizeof(struct sadb_address)), + SADB_GETSPROTO(((struct sadb_protocol *)headers[SADB_EXT_X_PROTOCOL])->sadb_protocol_proto)); + + if (tdb2 == NULL) { + rval = EEXIST; + goto ret; + } + + /* Detect cycles */ + for (tdb3 = tdb2; tdb3; tdb3 = tdb3->tdb_onext) + if (tdb3 == tdb1) + { + rval = EINVAL; + goto ret; + } + + /* Maintenance */ + if ((tdb1->tdb_onext) && + (tdb1->tdb_onext->tdb_inext == tdb1)) + tdb1->tdb_onext->tdb_inext = NULL; + + /* Link them */ + tdb1->tdb_onext = tdb2; + tdb2->tdb_inext = tdb1; + } + + break; + + case SADB_X_PROMISC: + if (len >= 2 * sizeof(struct sadb_msg)) { + OSDEP_PACKET *packet; + + if ((rval = OSDEP_DATATOPACKET(message, len, &packet)) != 0) + goto ret; + + for (s = pfkeyv2_sockets; s; s = s->next) + if ((s != pfkeyv2_socket) && + (!((struct sadb_msg *)headers[0])->sadb_msg_seq || + (((struct sadb_msg *)headers[0])->sadb_msg_seq == + pfkeyv2_socket->pid))) + pfkey_sendup(s->socket, packet, 1); + + OSDEP_FREEPACKET(packet); + } else { + if (len != sizeof(struct sadb_msg)) { + rval = OSDEP_ERROR(EINVAL); + goto ret; + } + + i = (pfkeyv2_socket->flags & PFKEYV2_SOCKETFLAGS_PROMISC) ? 1 : 0; + j = ((struct sadb_msg *)headers[0])->sadb_msg_satype ? 1 : 0; + + if (i ^ j) { + if (j) { + pfkeyv2_socket->flags |= PFKEYV2_SOCKETFLAGS_PROMISC; + npromisc++; + } else { + pfkeyv2_socket->flags &= ~PFKEYV2_SOCKETFLAGS_PROMISC; + npromisc--; + } + } + } + break; + default: + rval = OSDEP_ERROR(EINVAL); + goto ret; + } + +ret: + if (rval < 0) { + if ((rval == OSDEP_ERROR(EINVAL)) || (rval == OSDEP_ERROR(ENOMEM)) || + (rval == OSDEP_ERROR(ENOBUFS))) + goto realret; + for (i = 1; i <= SADB_EXT_MAX; i++) + headers[i] = NULL; + ((struct sadb_msg *)headers[0])->sadb_msg_errno = -rval; + } else { + uint32_t seen = 0; + + for (i = 1; i <= SADB_EXT_MAX; i++) + if (headers[i]) + seen |= (1 << i); + + if ((seen & sadb_exts_allowed_out[((struct sadb_msg *)headers[0])->sadb_msg_type]) != seen) { + goto realret; + } + + if ((seen & sadb_exts_required_out[((struct sadb_msg *)headers[0])->sadb_msg_type]) != sadb_exts_required_out[((struct sadb_msg *)headers[0])->sadb_msg_type]) { + goto realret; + } + } + + rval = pfkeyv2_sendmessage(headers, mode, socket); + +realret: + if (freeme) + OSDEP_FREE(freeme); + OSDEP_FREE(message); + + return rval; +} + +int +pfkeyv2_acquire(void *os) +{ +#if 0 + int rval = 0; + int i, j; + void *p, *headers[SADB_EXT_MAX+1], *buffer; + + if (!nregistered) { + rval = OSDEP_ERROR(ESRCH); + goto ret; + } + + i = sizeof(struct sadb_msg) + sizeof(struct sadb_address) + + PADUP(SA_LEN(&os->src.sa)) + sizeof(struct sadb_address) + + PADUP(SA_LEN(&os->dst.sa)) + sizeof(struct sadb_prop) + + os->nproposals * sizeof(struct sadb_comb) + + 2 * sizeof(struct sadb_ident); + + if (os->rekeysa) + i += PADUP(os->rekeysa->srcident.bytes) + + PADUP(os->rekeysa->dstident.bytes); + + if (!(p = OSDEP_MALLOC(i))) { + rval = OSDEP_ERROR(ENOMEM); + goto ret; + } + + bzero(headers, sizeof(headers)); + + buffer = p; + bzero(p, i); + + headers[0] = p; + p += sizeof(struct sadb_msg); + ((struct sadb_msg *)headers[0])->sadb_msg_version = PF_KEY_V2; + ((struct sadb_msg *)headers[0])->sadb_msg_type = SADB_ACQUIRE; + ((struct sadb_msg *)headers[0])->sadb_msg_satype = os->satype; + ((struct sadb_msg *)headers[0])->sadb_msg_len = i / sizeof(uint64_t); + ((struct sadb_msg *)headers[0])->sadb_msg_seq = pfkeyv2_seq++; + + headers[SADB_EXT_ADDRESS_SRC] = p; + p += sizeof(struct sadb_address) + PADUP(SA_LEN(&os->src.sa)); + ((struct sadb_address *)headers[SADB_EXT_ADDRESS_SRC])->sadb_address_len = (sizeof(struct sadb_address) + SA_LEN(&os->src.sa) + sizeof(uint64_t) - 1) / sizeof(uint64_t); + bcopy(&os->src, headers[SADB_EXT_ADDRESS_SRC] + sizeof(struct sadb_address), + SA_LEN(&os->src.sa)); + + headers[SADB_EXT_ADDRESS_DST] = p; + p += sizeof(struct sadb_address) + PADUP(SA_LEN(&os->dst.sa)); + ((struct sadb_address *)headers[SADB_EXT_ADDRESS_DST])->sadb_address_len = (sizeof(struct sadb_address) + SA_LEN(&os->dst.sa) + sizeof(uint64_t) - 1) / sizeof(uint64_t); + bcopy(&os->dst, headers[SADB_EXT_ADDRESS_DST] + sizeof(struct sadb_address), + SA_LEN(&os->dst.sa)); + + headers[SADB_EXT_IDENTITY_SRC] = p; + p += sizeof(struct sadb_ident); + ((struct sadb_ident *)headers[SADB_EXT_IDENTITY_SRC])->sadb_ident_type = os->srcidenttype; + ((struct sadb_ident *)headers[SADB_EXT_IDENTITY_SRC])->sadb_ident_id = os->srcidentid; + if (os->rekeysa) { + ((struct sadb_ident *)headers[SADB_EXT_IDENTITY_SRC])->sadb_ident_len = (sizeof(struct sadb_ident) + PADUP(os->rekeysa->srcident.bytes)) / sizeof(uint64_t); + bcopy(os->rekeysa->srcident.data, p, os->rekeysa->srcident.bytes); + p += PADUP(os->rekeysa->srcident.bytes); + } else + ((struct sadb_ident *)headers[SADB_EXT_IDENTITY_SRC])->sadb_ident_len = (sizeof(struct sadb_ident)) / sizeof(uint64_t); + + headers[SADB_EXT_IDENTITY_DST] = p; + p += sizeof(struct sadb_ident); + ((struct sadb_ident *)headers[SADB_EXT_IDENTITY_SRC])->sadb_ident_type = os->dstidenttype; + ((struct sadb_ident *)headers[SADB_EXT_IDENTITY_SRC])->sadb_ident_id = os->dstidentid; + if (os->rekeysa) { + ((struct sadb_ident *)headers[SADB_EXT_IDENTITY_DST])->sadb_ident_len = (sizeof(struct sadb_ident) + PADUP(os->rekeysa->dstident.bytes)) / sizeof(uint64_t); + bcopy(os->rekeysa->dstident.data, p, os->rekeysa->dstident.bytes); + p += PADUP(os->rekeysa->srcident.bytes); + } else + ((struct sadb_ident *)headers[SADB_EXT_IDENTITY_DST])->sadb_ident_len = (sizeof(struct sadb_ident)) / sizeof(uint64_t); + + headers[SADB_EXT_PROPOSAL] = p; + p += sizeof(struct sadb_prop); + ((struct sadb_prop *)headers[SADB_EXT_PROPOSAL])->sadb_prop_len = (sizeof(struct sadb_prop) + sizeof(struct sadb_comb) * os->nproposals) / sizeof(uint64_t); + ((struct sadb_prop *)headers[SADB_EXT_PROPOSAL])->sadb_prop_num = os->nproposals; + + { + struct sadb_comb *sadb_comb = p; + struct netsec_sadb_proposal *proposal = os->proposals; + + for (j = 0; j < os->nproposals; j++) { + sadb_comb->sadb_comb_auth = proposal->auth; + sadb_comb->sadb_comb_encrypt = proposal->encrypt; + sadb_comb->sadb_comb_flags = proposal->flags; + sadb_comb->sadb_comb_auth_minbits = proposal->auth_minbits; + sadb_comb->sadb_comb_auth_maxbits = proposal->auth_maxbits; + sadb_comb->sadb_comb_encrypt_minbits = proposal->encrypt_minbits; + sadb_comb->sadb_comb_encrypt_maxbits = proposal->encrypt_maxbits; + sadb_comb->sadb_comb_soft_allocations = proposal->soft.allocations; + sadb_comb->sadb_comb_hard_allocations = proposal->hard.allocations; + sadb_comb->sadb_comb_soft_bytes = proposal->soft.bytes; + sadb_comb->sadb_comb_hard_bytes = proposal->hard.bytes; + sadb_comb->sadb_comb_soft_addtime = proposal->soft.addtime; + sadb_comb->sadb_comb_hard_addtime = proposal->hard.addtime; + sadb_comb->sadb_comb_soft_usetime = proposal->soft.usetime; + sadb_comb->sadb_comb_hard_usetime = proposal->hard.usetime; + sadb_comb++; + proposal++; + } + } + + if ((rval = pfkeyv2_sendmessage(headers, PFKEYV2_SENDMESSAGE_REGISTERED, + NULL))!= 0) + goto ret; + + rval = 0; + +ret: + return rval; +#endif + return 0; +} + +int +pfkeyv2_expire(struct tdb *sa) +{ + /* XXX missing */ + return 0; +} + +int +pfkeyv2_init(void) +{ + int rval; + + bzero(&pfkeyv2_version, sizeof(struct pfkey_version)); + pfkeyv2_version.protocol = PFKEYV2_PROTOCOL; + pfkeyv2_version.create = &pfkeyv2_create; + pfkeyv2_version.release = &pfkeyv2_release; + pfkeyv2_version.send = &pfkeyv2_send; + + rval = pfkey_register(&pfkeyv2_version); + return rval; +} + +int +pfkeyv2_cleanup(void) +{ + pfkey_unregister(&pfkeyv2_version); + return 0; +} diff --git a/sys/net/pfkeyv2.h b/sys/net/pfkeyv2.h index 8e6d0ce7d69..2f542ebfb9b 100644 --- a/sys/net/pfkeyv2.h +++ b/sys/net/pfkeyv2.h @@ -1,325 +1,248 @@ -/* $OpenBSD: pfkeyv2.h,v 1.4 1997/11/07 08:29:53 niklas Exp $ */ - /* - * The author of this code is Angelos D. Keromytis, angelos@openbsd.org - * (except when noted otherwise). - * - * Copyright (C) 1997, 1998, 1999 by John Ioannidis and Angelos D. Keromytis. - * - * Permission to use, copy, and modify this software without fee - * is hereby granted, provided that this entire notice is included in - * all copies of any software which is or includes a copy or - * modification of this software. - * - * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR - * IMPLIED WARRANTY. IN PARTICULAR, NEITHER AUTHOR MAKES ANY - * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE - * MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR - * PURPOSE. - */ - - -/* - * PF_KEYv2 definitions - */ - -#define PF_KEY_V2 0 - -struct pfkeycb -{ - LIST_ENTRY(pfkeycb) pfkey_list; - struct socket *pfkey_socket; - struct sockaddr *pfkey_faddr; - struct sockaddr *pfkey_laddr; - struct sockproto pfkey_proto; - u_int32_t pfkey_flags; -#define PFKEYv2_REGISTERED 0x1 -}; - -struct sadb_msg -{ - u_int8_t sadb_msg_version; /* Must be PF_KEY_V2 */ - u_int8_t sadb_msg_type; - u_int8_t sadb_msg_errno; /* Should be zero for messages to kernel */ - u_int8_t sadb_msg_sa_type; - u_int16_t sadb_msg_len; /* In 32-bit words, inclusive */ - u_int16_t sadb_msg_reserved; /* Set to zero */ - u_int32_t sadb_msg_seq; - u_int32_t sadb_msg_pid; /* PID of originating process, 0 if kernel */ -}; - - -struct sadb_hdr -{ - u_int16_t sadb_hdr_len; /* In 32-bit words, inclusive */ - u_int16_t sadb_hdr_hdrtype; /* 0 is reserved */ -}; - -struct sadb_sa -{ - u_int16_t sadb_sa_len; /* In 32-bit words, inclusive */ - u_int16_t sadb_sa_hdrtype; /* ASSOCIATION */ - u_int16_t sadb_sa_spi; /* Network byte order */ - u_int8_t sadb_sa_replay_window_len; /* Set to 0 if not in use */ - u_int8_t sadb_sa_state; /* Set to zero by sending process */ - u_int8_t sadb_sa_encrypt; /* Encryption algorithm */ - u_int8_t sadb_sa_auth; /* Authentication algorithm */ - u_int32_t sadb_sa_flags; /* Bitmask */ -}; - -struct sadb_lifetime -{ - u_int16_t sadb_lifetime_len; /* In 32-bit words, inclusive */ - u_int16_t sadb_lifetime_hdrtype; /* LIFETIME */ - u_int8_t sadb_lifetime_which; /* Bitmask */ - u_int8_t sadb_lifetime_reserved[3]; /* Padding */ -}; - -struct sadb_lifetime_val -{ - u_int8_t sadb_lifetime_val_which; /* Corresponds to lifetime_which */ - u_int8_t sadb_lifetime_val_reserved; - u_int16_t sadb_lifetime_val_allocations; /* How many "flows" to use for */ - u_int32_t sadb_lifetime_val_bytes; /* Number of bytes before expr */ - time_t sadb_lifetime_val_absolute; - time_t sadb_lifetime_val_updatetime; - time_t sadb_lifetime_val_usetime; -}; - -struct sadb_address -{ - u_int16_t sadb_address_len; /* In 32-bit words, inclusive */ - u_int16_t sadb_address_hdrtype; /* ADDRESS */ - u_int8_t sadb_address_which; /* Bitmask */ - u_int8_t sadb_address_reserved[3]; /* Padding */ - /* Followed by one or more sockaddr structures */ -}; - -struct sadb_keyblk -{ - u_int16_t sadb_keyblk_len; /* In 32-bit words, inclusive */ - u_int16_t sadb_keyblk_hdrtype; /* KEY */ - u_int8_t sadb_keyblk_which; /* Bitmask */ - u_int8_t sadb_keyblk_reserved[3]; /* Padding */ - /* Followed by sadb_key */ -}; - -struct sadb_key -{ - u_int16_t sadb_key_len; /* Length of key in bits */ - u_int16_t sadb_key_which; /* Corresponds to keyblk_which */ - u_int8_t sadb_key_type; /* 3DES, DES, HMAC-MD5, etc. */ - /* Actual key follows */ -}; - -struct sadb_id -{ - u_int16_t sadb_id_len; /* In 32-bit words, inclusive */ - u_int16_t sadb_id_hdrtype; /* IDENTITY */ - u_int8_t sadb_id_which; /* Bitmask */ - u_int8_t sadb_id_reserved[3]; /* Padding */ - /* Followed by one or more sadb_certids */ -}; - -struct sadb_certid -{ - u_int16_t sadb_certid_len; /* In 32-bit words, inclusive */ - u_int16_t sadb_certid_type; - /* Cert id. follows */ -}; - -struct sadb_sens -{ - u_int16_t sadb_sens_len; /* In 32-bit words, inclusive */ - u_int16_t sadb_sens_hdrtype; /* SENSITIVITY */ - u_int32_t sadb_sens_dpd; /* Protection Domain */ - u_int8_t sadb_sens_level; - u_int8_t sadb_sens_sens_bitmap_len; /* In 32-bit words */ - u_int8_t sadb_sens_integ_level; - u_int8_t sadb_sens_integ_bitmap_len; /* In 32-bit words */ - /* - * Followed by 2 u_int32_t arrays - * u_int32_t sadb_sens_bitmap[sens_bitmap_len]; - * u_int32_t integ_bitmap[integ_bitmap_len]; - */ -}; - -struct sadb_prop -{ - u_int16_t sadb_prop_len; /* In 32-bit words, inclusive */ - u_int16_t sadb_prop_hdrtype; /* PROPOSAL */ - u_int8_t sadb_prop_num; - u_int8_t sadb_prop_replay; /* Replay window size */ - u_int16_t sadb_prop_reserved; -}; - -struct sadb_comb -{ - u_int8_t sadb_comb_auth; - u_int8_t sadb_comb_encr; - u_int16_t sadb_comb_flags; - u_int16_t sadb_comb_auth_keylen_min; - u_int16_t sadb_comb_auth_keylen_max; - u_int16_t sadb_comb_encr_keylen_min; - u_int16_t sadb_comb_encr_keylen_max; -}; - -struct sadb_alg -{ - u_int16_t sadb_alg_len; /* In 32-bit words, inclusive */ - u_int16_t sadb_alg_hdrtype; /* SUPPORTED */ - u_int8_t sadb_alg_num_auth; /* Number of auth algorithms */ - u_int8_t sadb_alg_num_encrypt; - /* Followed by one or more sadb_algd */ -}; - -struct sadb_algd -{ - u_int8_t sadb_algd_type; /* Algorithm type */ - u_int8_t sadb_algd_ivlen; /* IV len, in bits */ - u_int16_t sadb_algd_minlen; /* Minimum key length, in bits */ - u_int16_t sadb_algd_maxlen; /* Maximum key length, in bits */ - u_int16_t sadb_algd_reserved; -}; - -struct sadb_spirange -{ - u_int16_t sadb_spirage_len; /* In 32-bit words, inclusive */ - u_int16_t sadb_spirage_hdrtype; /* SPI_RANGE */ - u_int32_t sadb_spirange_low; - u_int32_t sadb_spirange_hi; -}; - -/* Message types */ - -#define SADB_GETSPI 1 -#define SADB_UPDATE 2 -#define SADB_ADD 3 -#define SADB_DELETE 4 -#define SADB_GET 5 -#define SADB_ACQUIRE 6 -#define SADB_REGISTER 7 -#define SADB_EXPIRE 8 -#define SADB_FLUSH 9 - -#define SADB_DUMP 10 /* Not used normally */ - -#define SADB_MAX 10 - -/* Security association flags */ - -#define SA_USED 0x1 /* SA used/not used */ -#define SA_UNIQUE 0x2 /* SA unique/reusable */ -#define SA_INBOUND 0x4 /* SA for packets destined here */ -#define SA_OUTBOUND 0x8 /* SA for packets sourced here */ -#define SA_FORWARD 0x10 /* SA for packets forwarded through */ -#define SA_PFS 0x20 /* Perfect Forward Secrecy ? */ -#define SA_REPLAY 0x40 /* Replay protection ? */ - -/* Security association state */ - -#define SA_STATE_LARVAL 0 -#define SA_STATE_MATURE 1 -#define SA_STATE_DYING 2 -#define SA_STATE_DEAD 3 - -#define SA_STATE_MAX 3 - -/* Security association type */ - -#define SADB_SATYPE_NONE 0 -#define SADB_SATYPE_AH 1 /* RFC-1826 */ -#define SADB_SATYPE_ESP 2 /* RFC-1827 */ -#define SADB_SATYPE_RSVP 3 /* RVSP Authentication */ -#define SADB_SATYPE_OSPFV2 4 /* OSPFv2 Authentication */ -#define SADB_SATYPE_RIPV2 5 /* RIPv2 Authentication */ -#define SADB_SATYPE_MIPV4 6 /* Mobile IPv4 Authentication */ - -#define SADB_SATYPE_MAX 6 - -/* Algorithm types */ - -/* Authentication algorithms */ - -#define SADB_AALG_NONE 0 -#define SADB_AALG_MD5_HMAC 1 -#define SADB_AALG_SHA1_HMAC 2 - -#define SADB_AALG_MAX 2 - -/* Encryption algorithms */ - -#define SADB_EALG_NONE 0 -#define SADB_EALG_DES_CBC 1 -#define SADB_EALG_3DES 2 -#define SADB_EALG_RC5 3 - -#define SADB_EALG_MAX 3 - -/* Extension header values */ - -#define SA_EXT_ASSOCIATION 1 -#define SA_EXT_LIFETIME 2 -#define SA_EXT_ADDRESS 3 -#define SA_EXT_KEY 4 -#define SA_EXT_IDENTITY 5 -#define SA_EXT_SENSITIVITY 6 -#define SA_EXT_PROPOSAL 7 -#define SA_EXT_SUPPORTED 8 -#define SA_EXT_SPI_RANGE 9 - -#define SA_EXT_MAX 9 - -/* Address extension values */ - -#define SADB_ADDR_SRC 0x1 /* Source */ -#define SADB_ADDR_DST 0x2 /* Destination */ -#define SADB_ADDR_INNER_SRC 0x4 /* Inner-packet src */ -#define SADB_ADDR_INNER_DST 0x8 /* Inner-packet dst */ -#define SADB_ADDR_PROXY 0x10 /* Proxy address */ - -/* Lifetime extension values */ - -#define SADB_LIFETIME_HARD 0x1 /* Hard lifetime */ -#define SADB_LIFETIME_SOFT 0x2 /* Soft lifetime */ -#define SADB_LIFETIME_CURRENT 0x4 /* Current lifetime left */ - -/* Key extension values */ - -#define SADB_KEYBLK_AUTH 0x1 /* Authentication key */ -#define SADB_KEYBLK_ENCRYPT 0x2 /* Encryption key */ - -/* Identity extension values */ - -#define SADB_ID_SRC 0x1 -#define SADB_ID_DST 0x2 - -/* Identity type */ - -#define SADB_IDT_IPV4_ADDR 1 -#define SADB_IDT_IPV6_ADDR 2 -#define SADB_IDT_IPV4_RANGE 3 -#define SADB_IDT_IPV6_RANGE 4 -#define SADB_IDT_FQDN 5 -#define SADB_IDT_USER_FQDN 6 -#define SADB_IDT_IPV4_CONNID 7 -#define SADB_IDT_IPV6_CONNID 8 - -#define SADB_IDT_MAX 8 - -/* Sensitivity extension values */ - -#define SADB_DPD_NONE 0 -#define SADB_DPD_DOD_GENSER 1 -#define SADB_DPD_DOD_SCI 2 -#define SADB_DPD_DOE 3 -#define SADB_DPD_NATO 4 - -#define SADB_DPD_MAX 4 - -#define sotopfkeycb(so) ((structy pfkeycb *)(so)->so->pcb) - -#ifdef _KERNEL -LIST_HEAD(, pfkeycb) pfkeycb; /* head of list */ -#endif - +%%% copyright-nrl-98 +This software is Copyright 1998 by Randall Atkinson, Ronald Lee, +Daniel McDonald, Bao Phan, and Chris Winters. All Rights Reserved. All +rights under this copyright have been assigned to the US Naval Research +Laboratory (NRL). The NRL Copyright Notice and License Agreement Version +1.1 (January 17, 1995) applies to this software. +You should have received a copy of the license with this software. If you +didn't get a copy, you may request one from <license@ipv6.nrl.navy.mil>. + +*/ +#ifndef _NET_PFKEY_V2_H +#define _NET_PFKEY_V2_H 1 + +#define PF_KEY_V2 2 + +#define SADB_RESERVED 0 +#define SADB_GETSPI 1 +#define SADB_UPDATE 2 +#define SADB_ADD 3 +#define SADB_DELETE 4 +#define SADB_GET 5 +#define SADB_ACQUIRE 6 +#define SADB_REGISTER 7 +#define SADB_EXPIRE 8 +#define SADB_FLUSH 9 +#define SADB_DUMP 10 +#define SADB_X_PROMISC 11 +#define SADB_X_ADDFLOW 12 +#define SADB_X_DELFLOW 13 +#define SADB_X_GRPSPIS 14 +#define SADB_MAX 14 + +struct sadb_msg { + uint8_t sadb_msg_version; + uint8_t sadb_msg_type; + uint8_t sadb_msg_errno; + uint8_t sadb_msg_satype; + uint16_t sadb_msg_len; + uint16_t sadb_msg_reserved; + uint32_t sadb_msg_seq; + uint32_t sadb_msg_pid; +}; + +struct sadb_ext { + uint16_t sadb_ext_len; + uint16_t sadb_ext_type; +}; + +struct sadb_sa { + uint16_t sadb_sa_len; + uint16_t sadb_sa_exttype; + uint32_t sadb_sa_spi; + uint8_t sadb_sa_replay; + uint8_t sadb_sa_state; + uint8_t sadb_sa_auth; + uint8_t sadb_sa_encrypt; + uint32_t sadb_sa_flags; +}; + +struct sadb_lifetime { + uint16_t sadb_lifetime_len; + uint16_t sadb_lifetime_exttype; + uint32_t sadb_lifetime_allocations; + uint64_t sadb_lifetime_bytes; + uint64_t sadb_lifetime_addtime; + uint64_t sadb_lifetime_usetime; +}; + +struct sadb_address { + uint16_t sadb_address_len; + uint16_t sadb_address_exttype; + uint32_t sadb_address_reserved; +}; + +struct sadb_key { + uint16_t sadb_key_len; + uint16_t sadb_key_exttype; + uint16_t sadb_key_bits; + uint16_t sadb_key_reserved; +}; + +struct sadb_ident { + uint16_t sadb_ident_len; + uint16_t sadb_ident_exttype; + uint16_t sadb_ident_type; + uint16_t sadb_ident_reserved; + uint64_t sadb_ident_id; +}; + +struct sadb_sens { + uint16_t sadb_sens_len; + uint16_t sadb_sens_exttype; + uint32_t sadb_sens_dpd; + uint8_t sadb_sens_sens_level; + uint8_t sadb_sens_sens_len; + uint8_t sadb_sens_integ_level; + uint8_t sadb_sens_integ_len; + uint32_t sadb_sens_reserved; +}; + +struct sadb_prop { + uint16_t sadb_prop_len; + uint16_t sadb_prop_exttype; + uint8_t sadb_prop_num; + uint8_t sadb_prop_replay; + uint16_t sadb_prop_reserved; +}; + +struct sadb_comb { + uint8_t sadb_comb_auth; + uint8_t sadb_comb_encrypt; + uint16_t sadb_comb_flags; + uint16_t sadb_comb_auth_minbits; + uint16_t sadb_comb_auth_maxbits; + uint16_t sadb_comb_encrypt_minbits; + uint16_t sadb_comb_encrypt_maxbits; + uint32_t sadb_comb_reserved; + uint32_t sadb_comb_soft_allocations; + uint32_t sadb_comb_hard_allocations; + uint64_t sadb_comb_soft_bytes; + uint64_t sadb_comb_hard_bytes; + uint64_t sadb_comb_soft_addtime; + uint64_t sadb_comb_hard_addtime; + uint64_t sadb_comb_soft_usetime; + uint64_t sadb_comb_hard_usetime; +}; + +struct sadb_supported { + uint16_t sadb_supported_len; + uint16_t sadb_supported_exttype; + uint8_t sadb_supported_nauth; + uint8_t sadb_supported_nencrypt; + uint16_t sadb_supported_reserved; +}; + +struct sadb_alg { + uint8_t sadb_alg_type; + uint8_t sadb_alg_ivlen; + uint16_t sadb_alg_minbits; + uint16_t sadb_alg_maxbits; + uint16_t sadb_alg_reserved; +}; + +struct sadb_spirange { + uint16_t sadb_spirange_len; + uint16_t sadb_spirange_exttype; + uint32_t sadb_spirange_min; + uint32_t sadb_spirange_max; + uint32_t sadb_spirange_reserved; +}; + +struct sadb_protocol { + uint16_t sadb_protocol_len; + uint16_t sadb_protocol_exttype; + uint8_t sadb_protocol_proto; + uint8_t sadb_protocol_reserved1; + uint16_t sadb_protocol_reserved2; +}; + +#define SADB_GETSPROTO(x) ( (x) == SADB_SATYPE_AH ? IPPROTO_AH :\ + (x) == SADB_SATYPE_X_AH_OLD ? IPPROTO_AH :\ + (x) == SADB_SATYPE_ESP ? IPPROTO_ESP :\ + (x) == SADB_SATYPE_X_ESP_OLD ? IPPROTO_ESP :\ + IPPROTO_IPIP ) + +#define SADB_EXT_RESERVED 0 +#define SADB_EXT_SA 1 +#define SADB_EXT_LIFETIME_CURRENT 2 +#define SADB_EXT_LIFETIME_HARD 3 +#define SADB_EXT_LIFETIME_SOFT 4 +#define SADB_EXT_ADDRESS_SRC 5 +#define SADB_EXT_ADDRESS_DST 6 +#define SADB_EXT_ADDRESS_PROXY 7 +#define SADB_EXT_KEY_AUTH 8 +#define SADB_EXT_KEY_ENCRYPT 9 +#define SADB_EXT_IDENTITY_SRC 10 +#define SADB_EXT_IDENTITY_DST 11 +#define SADB_EXT_SENSITIVITY 12 +#define SADB_EXT_PROPOSAL 13 +#define SADB_EXT_SUPPORTED 14 +#define SADB_EXT_SPIRANGE 15 +#define SADB_EXT_X_SRC_MASK 16 +#define SADB_EXT_X_DST_MASK 17 +#define SADB_EXT_X_PROTOCOL 18 +#define SADB_EXT_X_SA2 19 +#define SADB_EXT_X_SRC_FLOW 20 +#define SADB_EXT_X_DST_FLOW 21 +#define SADB_EXT_X_DST2 22 +#define SADB_EXT_MAX 22 + +#define SADB_SATYPE_UNSPEC 0 +#define SADB_SATYPE_AH 1 +#define SADB_SATYPE_ESP 2 +#define SADB_SATYPE_RSVP 3 +#define SADB_SATYPE_OSPFV2 4 +#define SADB_SATYPE_RIPV2 5 +#define SADB_SATYPE_MIP 6 +#define SADB_SATYPE_X_AH_OLD 7 +#define SADB_SATYPE_X_ESP_OLD 8 +#define SADB_SATYPE_X_IPIP 9 +#define SADB_SATYPE_MAX 9 + +#define SADB_SASTATE_LARVAL 0 +#define SADB_SASTATE_MATURE 1 +#define SADB_SASTATE_DYING 2 +#define SADB_SASTATE_DEAD 3 +#define SADB_SASTATE_MAX 3 + +#define SADB_AALG_NONE 0 +#define SADB_AALG_MD5HMAC 1 +#define SADB_AALG_SHA1HMAC 2 +#define SADB_AALG_MD5HMAC96 3 +#define SADB_AALG_SHA1HMAC96 4 +#define SADB_AALG_X_RIPEMD160HMAC96 5 +#define SADB_AALG_X_MD5 6 +#define SADB_AALG_X_SHA1 7 +#define SADB_AALG_MAX 7 + +#define SADB_EALG_NONE 0 +#define SADB_EALG_DESCBC 1 +#define SADB_EALG_3DESCBC 2 +#define SADB_EALG_X_BLF 3 +#define SADB_EALG_X_CAST 4 +#define SADB_EALG_X_SKIPJACK 5 +#define SADB_EALG_MAX 5 + +#define SADB_SAFLAGS_PFS 0x01 /* perfect forward secrecy */ +#define SADB_SAFLAGS_X_HALFIV 0x02 /* Used for ESP-old */ +#define SADB_SAFLAGS_X_TUNNEL 0x04 /* Force tunneling */ +#define SADB_SAFLAGS_X_CHAINDEL 0x08 /* Delete whole SA chain */ +#define SADB_SAFLAGS_X_LOCALFLOW 0x10 /* Delete whole SA chain */ + +#define SADB_IDENTTYPE_RESERVED 0 +#define SADB_IDENTTYPE_PREFIX 1 +#define SADB_IDENTTYPE_FQDN 2 +#define SADB_IDENTTYPE_MBOX 3 +#define SADB_IDENTTYPE_CONNECTION 4 +#define SADB_IDENTTYPE_MAX 4 + +#define SADB_KEY_FLAGS_MAX 0 + +#ifdef KERNEL +int pfkeyv2_init(void); +int pfkeyv2_cleanup(void); +int pfkeyv2_parsemessage(void *p, int len, void **headers); +#endif /* KERNEL */ +#endif /* _NET_PFKEY_V2_H */ diff --git a/sys/net/pfkeyv2_parsemessage.c b/sys/net/pfkeyv2_parsemessage.c new file mode 100644 index 00000000000..8424a72b561 --- /dev/null +++ b/sys/net/pfkeyv2_parsemessage.c @@ -0,0 +1,550 @@ +/* +%%% copyright-nrl-97 +This software is Copyright 1997-1998 by Randall Atkinson, Ronald Lee, +Daniel McDonald, Bao Phan, and Chris Winters. All Rights Reserved. All +rights under this copyright have been assigned to the US Naval Research +Laboratory (NRL). The NRL Copyright Notice and License Agreement Version +1.1 (January 17, 1995) applies to this software. +You should have received a copy of the license with this software. If you +didn't get a copy, you may request one from <license@ipv6.nrl.navy.mil>. + +%%% copyright-cmetz-97 +This software is Copyright 1997-1998 by Craig Metz, All Rights Reserved. +The Inner Net License Version 2 applies to this software. +You should have received a copy of the license with this software. If +you didn't get a copy, you may request one from <license@inner.net>. + +*/ +#include <sys/osdep.h> +#include <net/pfkeyv2.h> + +#define BITMAP_SA (1 << SADB_EXT_SA) +#define BITMAP_LIFETIME_CURRENT (1 << SADB_EXT_LIFETIME_CURRENT) +#define BITMAP_LIFETIME_HARD (1 << SADB_EXT_LIFETIME_HARD) +#define BITMAP_LIFETIME_SOFT (1 << SADB_EXT_LIFETIME_SOFT) +#define BITMAP_ADDRESS_SRC (1 << SADB_EXT_ADDRESS_SRC) +#define BITMAP_ADDRESS_DST (1 << SADB_EXT_ADDRESS_DST) +#define BITMAP_ADDRESS_PROXY (1 << SADB_EXT_ADDRESS_PROXY) +#define BITMAP_KEY_AUTH (1 << SADB_EXT_KEY_AUTH) +#define BITMAP_KEY_ENCRYPT (1 << SADB_EXT_KEY_ENCRYPT) +#define BITMAP_IDENTITY_SRC (1 << SADB_EXT_IDENTITY_SRC) +#define BITMAP_IDENTITY_DST (1 << SADB_EXT_IDENTITY_DST) +#define BITMAP_SENSITIVITY (1 << SADB_EXT_SENSITIVITY) +#define BITMAP_PROPOSAL (1 << SADB_EXT_PROPOSAL) +#define BITMAP_SUPPORTED (1 << SADB_EXT_SUPPORTED) +#define BITMAP_SPIRANGE (1 << SADB_EXT_SPIRANGE) +#define BITMAP_LIFETIME (BITMAP_LIFETIME_CURRENT | BITMAP_LIFETIME_HARD | BITMAP_LIFETIME_SOFT) +#define BITMAP_ADDRESS (BITMAP_ADDRESS_SRC | BITMAP_ADDRESS_DST | BITMAP_ADDRESS_PROXY) +#define BITMAP_KEY (BITMAP_KEY_AUTH | BITMAP_KEY_ENCRYPT) +#define BITMAP_IDENTITY (BITMAP_IDENTITY_SRC | BITMAP_IDENTITY_DST) +#define BITMAP_MSG 1 +#define BITMAP_X_SRC_MASK (1 << SADB_EXT_X_SRC_MASK) +#define BITMAP_X_DST_MASK (1 << SADB_EXT_X_DST_MASK) +#define BITMAP_X_PROTOCOL (1 << SADB_EXT_X_PROTOCOL) +#define BITMAP_X_SA2 (1 << SADB_EXT_X_SA2) +#define BITMAP_X_SRC_FLOW (1 << SADB_EXT_X_SRC_FLOW) +#define BITMAP_X_DST_FLOW (1 << SADB_EXT_X_DST_FLOW) +#define BITMAP_X_DST2 (1 << SADB_EXT_X_DST2) + +uint32_t sadb_exts_allowed_in[SADB_MAX+1] = +{ + /* RESERVED */ + ~0, + /* GETSPI */ + BITMAP_ADDRESS_SRC | BITMAP_ADDRESS_DST | BITMAP_SPIRANGE, + /* UPDATE */ + BITMAP_SA | BITMAP_LIFETIME | BITMAP_ADDRESS | BITMAP_KEY | BITMAP_IDENTITY, + /* ADD */ + BITMAP_SA | BITMAP_LIFETIME | BITMAP_ADDRESS | BITMAP_KEY | BITMAP_IDENTITY, + /* DELETE */ + BITMAP_SA | BITMAP_ADDRESS_SRC | BITMAP_ADDRESS_DST, + /* GET */ + BITMAP_SA | BITMAP_ADDRESS_SRC | BITMAP_ADDRESS_DST, + /* ACQUIRE */ + BITMAP_ADDRESS_SRC | BITMAP_ADDRESS_DST | BITMAP_IDENTITY | BITMAP_PROPOSAL, + /* REGISTER */ + 0, + /* EXPIRE */ + BITMAP_SA | BITMAP_ADDRESS_SRC | BITMAP_ADDRESS_DST, + /* FLUSH */ + 0, + /* DUMP */ + 0, + /* X_PROMISC */ + 0, + /* X_ADDFLOW */ + BITMAP_ADDRESS_SRC | BITMAP_ADDRESS_DST | BITMAP_SA | BITMAP_X_SRC_MASK | BITMAP_X_DST_MASK | BITMAP_X_PROTOCOL | BITMAP_X_SRC_FLOW | BITMAP_X_DST_FLOW, + /* X_DELFLOW */ + BITMAP_X_SRC_MASK | BITMAP_X_DST_MASK | BITMAP_X_PROTOCOL | BITMAP_X_SRC_FLOW | BITMAP_X_DST_FLOW | BITMAP_SA, + /* X_GRPSPIS */ + BITMAP_SA | BITMAP_X_SA2 | BITMAP_X_DST2 | BITMAP_ADDRESS_DST | BITMAP_X_PROTOCOL +}; + +uint32_t sadb_exts_required_in[SADB_MAX+1] = +{ + /* RESERVED */ + 0, + /* GETSPI */ + BITMAP_ADDRESS_SRC | BITMAP_ADDRESS_DST | BITMAP_SPIRANGE, + /* UPDATE */ + BITMAP_SA | BITMAP_ADDRESS_SRC | BITMAP_ADDRESS_DST, + /* ADD */ + BITMAP_SA | BITMAP_ADDRESS_DST, + /* DELETE */ + BITMAP_SA | BITMAP_ADDRESS_DST, + /* GET */ + BITMAP_SA | BITMAP_ADDRESS_SRC | BITMAP_ADDRESS_DST, + /* ACQUIRE */ + 0, + /* REGISTER */ + 0, + /* EXPIRE */ + BITMAP_SA | BITMAP_ADDRESS_SRC | BITMAP_ADDRESS_DST, + /* FLUSH */ + 0, + /* DUMP */ + 0, + /* X_PROMISC */ + 0, + /* X_ADDFLOW */ + BITMAP_ADDRESS_DST | BITMAP_SA | BITMAP_X_SRC_MASK | BITMAP_X_DST_MASK | BITMAP_X_SRC_FLOW | BITMAP_X_DST_FLOW, + /* X_DELFLOW */ + BITMAP_SA | BITMAP_X_SRC_MASK | BITMAP_X_DST_MASK | BITMAP_X_SRC_FLOW | BITMAP_X_DST_FLOW, + /* X_GRPSPIS */ + BITMAP_SA | BITMAP_X_SA2 | BITMAP_X_DST2 | BITMAP_ADDRESS_DST | BITMAP_X_PROTOCOL +}; + +uint32_t sadb_exts_allowed_out[SADB_MAX+1] = +{ + /* RESERVED */ + ~0, + /* GETSPI */ + BITMAP_SA | BITMAP_ADDRESS_SRC | BITMAP_ADDRESS_DST, + /* UPDATE */ + BITMAP_SA | BITMAP_LIFETIME | BITMAP_ADDRESS | BITMAP_IDENTITY, + /* ADD */ + BITMAP_SA | BITMAP_LIFETIME | BITMAP_ADDRESS | BITMAP_IDENTITY, + /* DELETE */ + BITMAP_SA | BITMAP_ADDRESS_SRC | BITMAP_ADDRESS_DST, + /* GET */ + BITMAP_SA | BITMAP_LIFETIME | BITMAP_ADDRESS | BITMAP_KEY | BITMAP_IDENTITY, + /* ACQUIRE */ + BITMAP_ADDRESS_SRC | BITMAP_ADDRESS_DST | BITMAP_IDENTITY | BITMAP_PROPOSAL, + /* REGISTER */ + BITMAP_SUPPORTED, + /* EXPIRE */ + BITMAP_SA | BITMAP_LIFETIME | BITMAP_ADDRESS, + /* FLUSH */ + 0, + /* DUMP */ + BITMAP_SA | BITMAP_LIFETIME | BITMAP_ADDRESS | BITMAP_IDENTITY, + /* X_PROMISC */ + 0, + /* X_ADDFLOW */ + 0, + /* X_DELFLOW */ + 0, + /* X_GRPSPIS */ + 0 +}; + +uint32_t sadb_exts_required_out[SADB_MAX+1] = +{ + /* RESERVED */ + 0, + /* GETSPI */ + BITMAP_SA | BITMAP_ADDRESS_SRC | BITMAP_ADDRESS_DST, + /* UPDATE */ + BITMAP_SA | BITMAP_ADDRESS_SRC | BITMAP_ADDRESS_DST, + /* ADD */ + BITMAP_SA | BITMAP_ADDRESS_SRC | BITMAP_ADDRESS_DST, + /* DELETE */ + BITMAP_SA | BITMAP_ADDRESS_DST, + /* GET */ + BITMAP_SA | BITMAP_LIFETIME_CURRENT | BITMAP_ADDRESS_SRC | BITMAP_ADDRESS_DST, + /* ACQUIRE */ + 0, + /* REGISTER */ + BITMAP_SUPPORTED, + /* EXPIRE */ + BITMAP_SA | BITMAP_ADDRESS_SRC | BITMAP_ADDRESS_DST, + /* FLUSH */ + 0, + /* DUMP */ + 0, + /* X_PROMISC */ + 0, + /* X_ADDFLOW */ + 0, + /* X_DELFLOW */ + 0, + /* X_GRPSPIS */ + 0 +}; + +int pfkeyv2_parsemessage(void *, int, void **); + +#define RETURN_EINVAL(line) goto einval; + +int +pfkeyv2_parsemessage(void *p, int len, void **headers) +{ + struct sadb_ext *sadb_ext; + int i, left = len; + uint32_t allow, seen = 1; + struct sadb_msg *sadb_msg = (struct sadb_msg *) p; + + bzero(headers, (SADB_EXT_MAX + 1) * sizeof(void *)); + + if (left < sizeof(struct sadb_msg)) + return EINVAL; + + headers[0] = p; + + if (sadb_msg->sadb_msg_len * sizeof(uint64_t) != left) + return EINVAL; + + p += sizeof(struct sadb_msg); + left -= sizeof(struct sadb_msg); + + if (sadb_msg->sadb_msg_reserved) + return EINVAL; + + if (sadb_msg->sadb_msg_type > SADB_MAX) + return EINVAL; + + if (!sadb_msg->sadb_msg_type) + return EINVAL; + + if (sadb_msg->sadb_msg_pid != OSDEP_CURRENTPID) + return EINVAL; + + if (sadb_msg->sadb_msg_errno) { + if (left) + return EINVAL; + + return 0; + } + + if (sadb_msg->sadb_msg_type == SADB_X_PROMISC) + return 0; + + allow = sadb_exts_allowed_in[sadb_msg->sadb_msg_type]; + + while (left > 0) { + sadb_ext = (struct sadb_ext *)p; + if (left < sizeof(struct sadb_ext)) + return EINVAL; + + i = sadb_ext->sadb_ext_len * sizeof(uint64_t); + if (left < i) + return EINVAL; + + if (sadb_ext->sadb_ext_type > SADB_EXT_MAX) + return EINVAL; + + if (!sadb_ext->sadb_ext_type) + return EINVAL; + + if (!(allow & (1 << sadb_ext->sadb_ext_type))) + return EINVAL; + + if (headers[sadb_ext->sadb_ext_type]) + return EINVAL; + + seen |= (1 << sadb_ext->sadb_ext_type); + + switch (sadb_ext->sadb_ext_type) { + case SADB_EXT_X_SA2: + case SADB_EXT_SA: + { + struct sadb_sa *sadb_sa = (struct sadb_sa *)p; + + if (i != sizeof(struct sadb_sa)) + return EINVAL; + + if (sadb_sa->sadb_sa_state > SADB_SASTATE_MAX) + return EINVAL; + + if (sadb_sa->sadb_sa_state == SADB_SASTATE_DEAD) + return EINVAL; + + if (sadb_sa->sadb_sa_encrypt > SADB_EALG_MAX) + return EINVAL; + + if (sadb_sa->sadb_sa_auth > SADB_AALG_MAX) + return EINVAL; + } + break; + case SADB_EXT_X_PROTOCOL: + if (i != sizeof(struct sadb_protocol)) + return EINVAL; + break; + case SADB_EXT_LIFETIME_CURRENT: + case SADB_EXT_LIFETIME_HARD: + case SADB_EXT_LIFETIME_SOFT: + { + if (i != sizeof(struct sadb_lifetime)) + return EINVAL; + } + break; + case SADB_EXT_ADDRESS_SRC: + case SADB_EXT_ADDRESS_DST: + case SADB_EXT_X_DST2: + case SADB_EXT_X_SRC_MASK: + case SADB_EXT_X_DST_MASK: + case SADB_EXT_X_SRC_FLOW: + case SADB_EXT_X_DST_FLOW: + case SADB_EXT_ADDRESS_PROXY: + { + struct sadb_address *sadb_address = (struct sadb_address *)p; + struct sockaddr *sa = (struct sockaddr *)(p + sizeof(struct sadb_address)); + + if (i < sizeof(struct sadb_address) + sizeof(struct sockaddr)) + return EINVAL; + + if (sadb_address->sadb_address_reserved) + return EINVAL; + +#if SALEN + if (sa->sa_len && (i != sizeof(struct sadb_address) + sa->sa_len)) + return EINVAL; +#endif /* SALEN */ + + switch(sa->sa_family) { + case AF_INET: + if (sizeof(struct sadb_address) + sizeof(struct sockaddr_in) + != i) + return EINVAL; +#if SALEN + if (sa->sa_len != sizeof(struct sockaddr_in)) + return EINVAL; +#endif /* SALEN */ + + /* Only check the right pieces */ + switch (sadb_ext->sadb_ext_type) + { + case SADB_EXT_X_SRC_MASK: + case SADB_EXT_X_DST_MASK: + case SADB_EXT_X_SRC_FLOW: + case SADB_EXT_X_DST_FLOW: + break; + + default: + if (((struct sockaddr_in *)sa)->sin_port) + return EINVAL; + break; + } + + { + char zero[sizeof(((struct sockaddr_in *)sa)->sin_zero)]; + bzero(zero, sizeof(zero)); + + if (bcmp(&((struct sockaddr_in *)sa)->sin_zero, zero, + sizeof(zero))) + return EINVAL; + } + break; +#if INET6 + case AF_INET6: + if (i != sizeof(struct sadb_address) + + sizeof(struct sockaddr_in6)) + return EINVAL; + + if (sa->sa_len != sizeof(struct sockaddr_in6)) + return EINVAL; + + if (((struct sockaddr_in6 *)sa)->sin6_port) + return EINVAL; + + if (((struct sockaddr_in6 *)sa)->sin6_flowinfo) + return EINVAL; + + break; +#endif /* INET6 */ + default: + return EINVAL; + } + } + break; + case SADB_EXT_KEY_AUTH: + case SADB_EXT_KEY_ENCRYPT: + { + struct sadb_key *sadb_key = (struct sadb_key *)p; + + if (i < sizeof(struct sadb_key)) + return EINVAL; + + if (!sadb_key->sadb_key_bits) + return EINVAL; + + if (((sadb_key->sadb_key_bits + 63) / 64) * sizeof(uint64_t) != + i - sizeof(struct sadb_key)) + return EINVAL; + + if (sadb_key->sadb_key_reserved) + return EINVAL; + } + break; + case SADB_EXT_IDENTITY_SRC: + case SADB_EXT_IDENTITY_DST: + { + struct sadb_ident *sadb_ident = (struct sadb_ident *)p; + + if (i < sizeof(struct sadb_ident)) + return EINVAL; + + if (sadb_ident->sadb_ident_type > SADB_IDENTTYPE_MAX) + return EINVAL; + + if (sadb_ident->sadb_ident_reserved) + return EINVAL; + + if (i > sizeof(struct sadb_ident)) { + char *c = (char *)(p + sizeof(struct sadb_ident)); + int j; + + if (*(char *)(p + i - 1)) + return EINVAL; + + j = ((strlen(c) + sizeof(uint64_t) - 1) & ~(sizeof(uint64_t)-1)) + + sizeof(struct sadb_ident); + + if (i != j) + return EINVAL; + } + } + break; + case SADB_EXT_SENSITIVITY: + { + struct sadb_sens *sadb_sens = (struct sadb_sens *)p; + + if (i < sizeof(struct sadb_sens)) + return EINVAL; + + if (i != (sadb_sens->sadb_sens_sens_len + + sadb_sens->sadb_sens_integ_len) * sizeof(uint64_t) + + sizeof(struct sadb_sens)) + return EINVAL; + } + break; + case SADB_EXT_PROPOSAL: + { + struct sadb_prop *sadb_prop = (struct sadb_prop *)p; + + if (i < sizeof(struct sadb_prop)) + return EINVAL; + + if (sadb_prop->sadb_prop_reserved) + return EINVAL; + + if ((i - sizeof(struct sadb_prop)) % sizeof(struct sadb_comb)) + return EINVAL; + + { + struct sadb_comb *sadb_comb = (struct sadb_comb *)(p + sizeof(struct sadb_prop)); + int j; + + for (j = 0; + j < (i - sizeof(struct sadb_prop))/sizeof(struct sadb_comb); + j++) { + if (sadb_comb->sadb_comb_auth > SADB_AALG_MAX) + return EINVAL; + + if (sadb_comb->sadb_comb_encrypt > SADB_EALG_MAX) + return EINVAL; + + if (sadb_comb->sadb_comb_reserved) + return EINVAL; + + } + } + } + break; + case SADB_EXT_SUPPORTED: + { + struct sadb_supported *sadb_supported = (struct sadb_supported *)p; + int j; + + if (i < sizeof(struct sadb_supported)) + return EINVAL; + + if (sadb_supported->sadb_supported_reserved) + return EINVAL; + + if (i != ((sadb_supported->sadb_supported_nauth + + sadb_supported->sadb_supported_nencrypt) * + sizeof(struct sadb_alg)) + sizeof(struct sadb_supported)) + return EINVAL; + + { + struct sadb_alg *sadb_alg = (struct sadb_alg *)(p + sizeof(struct sadb_supported)); + for (j = 0; j < sadb_supported->sadb_supported_nauth; j++) { + if (sadb_alg->sadb_alg_type > SADB_AALG_MAX) + return EINVAL; + + if (sadb_alg->sadb_alg_reserved) + return EINVAL; + + sadb_alg++; + } + for (j = 0; j < sadb_supported->sadb_supported_nencrypt; j++) { + if (sadb_alg->sadb_alg_type > SADB_EALG_MAX) + return EINVAL; + + if (sadb_alg->sadb_alg_reserved) + return EINVAL; + + sadb_alg++; + } + } + } + break; + case SADB_EXT_SPIRANGE: + { + struct sadb_spirange *sadb_spirange = (struct sadb_spirange *)p; + + if (i != sizeof(struct sadb_spirange)) + return EINVAL; + + if (sadb_spirange->sadb_spirange_min > + sadb_spirange->sadb_spirange_max) + return EINVAL; + } + break; + default: + return EINVAL; + } + + headers[sadb_ext->sadb_ext_type] = p; + p += i; + left -= i; + } + + if (left) + return EINVAL; + + { + uint32_t required; + + required = sadb_exts_required_in[sadb_msg->sadb_msg_type]; + + if ((seen & required) != required) + return EINVAL; + } + + switch(((struct sadb_msg *)headers[0])->sadb_msg_type) { + case SADB_UPDATE: + if (((struct sadb_sa *)headers[SADB_EXT_SA])->sadb_sa_state != + SADB_SASTATE_MATURE) + return EINVAL; + break; + case SADB_ADD: + if (((struct sadb_sa *)headers[SADB_EXT_SA])->sadb_sa_state != + SADB_SASTATE_MATURE) + return EINVAL; + break; + } + + return 0; +} |