diff options
Diffstat (limited to 'sbin/photurisd/kernel.c')
-rw-r--r-- | sbin/photurisd/kernel.c | 1210 |
1 files changed, 916 insertions, 294 deletions
diff --git a/sbin/photurisd/kernel.c b/sbin/photurisd/kernel.c index 60398e5fec7..69e3c1b79de 100644 --- a/sbin/photurisd/kernel.c +++ b/sbin/photurisd/kernel.c @@ -39,18 +39,20 @@ */ #ifndef lint -static char rcsid[] = "$Id: kernel.c,v 1.1 1998/11/14 23:37:25 deraadt Exp $"; +static char rcsid[] = "$Id: kernel.c,v 1.2 1999/03/27 21:18:01 provos Exp $"; #endif #include <time.h> #include <sys/time.h> +#include <sys/types.h> #include <sys/param.h> #include <sys/file.h> #include <sys/socket.h> #include <sys/ioctl.h> #include <sys/mbuf.h> #include <sys/sysctl.h> +#include <sys/uio.h> #include <net/if.h> #include <net/route.h> @@ -70,7 +72,7 @@ static char rcsid[] = "$Id: kernel.c,v 1.1 1998/11/14 23:37:25 deraadt Exp $"; #include <string.h> #include <paths.h> #define INET /* Needed for setting ipsec routes */ -#include <net/encap.h> +#include <net/pfkeyv2.h> #include <netinet/ip_ipsp.h> #include <netinet/ip_esp.h> #include <netinet/ip_ah.h> @@ -96,7 +98,13 @@ time_t now; #define kernel_debug(x) #endif -static int sd; +#define SPITOINT(x) (((x)[0]<<24) + ((x)[1]<<16) + ((x)[2]<<8) + (x)[3]) +#define KERNEL_XF_SET(x) kernel_xf_set(sd, buffer, BUFFER_SIZE, iov, cnt, x) + +static int sd; /* normal PFKEY socket */ +static int regsd; /* PFKEY socket for Register and Acquire */ +static int pfkey_seq; +static pid_t pfkey_pid; /* * Translate a Photuris ID into a data structure for the @@ -114,10 +122,33 @@ kernel_get_transform(int id) return NULL; } +/* + * Mark a transform as supported by the kernel + */ + +void +kernel_transform_seen(int id, int type) +{ + int i; + + for (i=sizeof(xf)/sizeof(transform)-1; i >= 0; i--) + if (xf[i].kernel_id == id && (xf[i].flags & type)) { + xf[i].flags |= XF_SUP; + return; + } +} + +/* + * See if we know about this transform and if it is supported + * by the kernel. + */ + int kernel_known_transform(int id) { - return kernel_get_transform(id) == NULL ? -1 : 0; + transform *xf = kernel_get_transform(id); + + return (xf == NULL || !(xf->flags & XF_SUP)) ? -1 : 0; } /* @@ -177,15 +208,24 @@ kernel_valid_auth(attrib_t *auth, u_int8_t *flag, u_int16_t size) int init_kernel(void) { - if ((sd = socket(AF_ENCAP, SOCK_RAW, AF_UNSPEC)) < 0) - crit_error(1, "socket() for IPSec in init_kernel()"); + if ((sd = socket(PF_KEY, SOCK_RAW, PF_KEY_V2)) == -1) + crit_error(1, "socket(PF_KEY) for IPSec keyengine in init_kernel()"); + if ((regsd = socket(PF_KEY, SOCK_RAW, PF_KEY_V2)) == -1) + crit_error(1, "socket() for PFKEY register in init_kernel()"); + + pfkey_seq = 0; + pfkey_pid = getpid(); + + if (kernel_register(regsd) == -1) + crit_error(0, "PFKEY socket registration failed in init_kernel()"); + return 1; } int kernel_get_socket(void) { - return sd; + return regsd; } void @@ -211,30 +251,136 @@ kernel_set_socket_policy(int sd) } int -kernel_xf_set(struct encap_msghdr *em) +kernel_xf_set(int sd, char *buffer, int blen, struct iovec *iov, + int cnt, int len) { - if (write(sd, (char *)em, em->em_msglen) != em->em_msglen) + struct sadb_msg *sres; + int seq; + + sres = (struct sadb_msg *)iov[0].iov_base; + seq = sres->sadb_msg_seq; + + if (writev(sd, iov, cnt) != len) { + perror("writev() in kernel_xf_set()"); return 0; + } + + if (buffer) + return kernel_xf_read(sd, buffer, blen, seq); return 1; } int -kernel_xf_read(struct encap_msghdr *em, int msglen) +kernel_xf_read(int sd, char *buffer, int blen, int seq) { - if (read(sd, (char *)em, msglen) != msglen) { - log_error(1, "read() in kernel_xf_read()"); + struct sadb_msg *sres = (struct sadb_msg *)buffer; + int len; + + /* + * Read in response from the kernel. If seq number and/or PID are + * given, we need to check PID and sequence number to see if it + * really is a message for us. + */ + do { + if (recv(sd, sres, sizeof(*sres), MSG_PEEK) != sizeof(*sres)) { + perror("read() in kernel_xf_read()"); + return 0; + } + len = sres->sadb_msg_len * 8; + if (len >= BUFFER_SIZE) { + log_error(0, "PFKEYV2 message len %d too big in kernel_xf_read()", len); + return 0; + } + if (read(sd, sres, len) != len) { + perror("read() in kernel_xf_read()"); + return 0; + } + } while ((seq && sres->sadb_msg_seq != seq) || + (sres->sadb_msg_pid && sres->sadb_msg_pid != pfkey_pid)); + if (sres->sadb_msg_errno) { + log_error(0, "kernel_xf_read: PFKEYV2 result: %s", + strerror(sres->sadb_msg_errno)); return 0; } return 1; } +int +kernel_register(int sd) +{ + struct sadb_msg smsg, *sres; + struct sadb_supported *ssup; + struct sadb_alg *salg; + int len; + struct iovec iov[1]; + int cnt = 0; + + kernel_debug(("kernel_register: fd %d\n", sd)); + + bzero(&smsg, sizeof(smsg)); + + smsg.sadb_msg_len = sizeof(smsg) / 8; + smsg.sadb_msg_version = PF_KEY_V2; + smsg.sadb_msg_seq = pfkey_seq++; + smsg.sadb_msg_pid = pfkey_pid; + smsg.sadb_msg_type = SADB_REGISTER; + iov[cnt].iov_base = &smsg; + iov[cnt++].iov_len = sizeof(smsg); + + /* Register for AH */ + smsg.sadb_msg_satype = SADB_SATYPE_ESP; + if (!kernel_xf_set(regsd, buffer, BUFFER_SIZE, iov, cnt, + smsg.sadb_msg_len*8)) { + log_error(1, "kernel_xf_set() in kernel_reserve_single_spi()"); + return -1; + } + + /* Register for ESP */ + smsg.sadb_msg_satype = SADB_SATYPE_AH; + smsg.sadb_msg_seq = pfkey_seq++; + if (!kernel_xf_set(regsd, buffer, BUFFER_SIZE, iov, cnt, + smsg.sadb_msg_len*8)) { + log_error(1, "kernel_xf_set() in kernel_reserve_single_spi()"); + return -1; + } + + /* + * XXX - this might need changing in the case that the response + * to register only includes the transforms matching the satype + * in the message. + */ + sres = (struct sadb_msg *)buffer; + ssup = (struct sadb_supported *)(sres + 1); + if (ssup->sadb_supported_exttype != SADB_EXT_SUPPORTED) { + log_error(0, "SADB_REGISTER did not return a SADB_EXT_SUPORTED " + "struct: %d in kernel_register()", + ssup->sadb_supported_exttype); + return -1; + } + + len = ssup->sadb_supported_len * 8 - sizeof(*ssup); + if (len != (ssup->sadb_supported_nauth + ssup->sadb_supported_nencrypt) * + sizeof(struct sadb_alg)) { + log_error(0, "SADB_SUPPORTED length mismatch in kernel_register()"); + return -1; + } + + salg = (struct sadb_alg *)(ssup + 1); + for (cnt = 0; cnt < ssup->sadb_supported_nauth; cnt++, salg++) + kernel_transform_seen(salg->sadb_alg_type, XF_AUTH); + for (cnt = 0; cnt < ssup->sadb_supported_nencrypt; cnt++, salg++) + kernel_transform_seen(salg->sadb_alg_type, XF_ENC); + + return 0; +} + u_int32_t -kernel_reserve_spi(char *srcaddress, int options) +kernel_reserve_spi(char *src, char *dst, int options) { u_int32_t spi; int proto; - kernel_debug(("kernel_reserve_spi: %s\n", srcaddress)); + kernel_debug(("kernel_reserve_spi: %s\n", src)); if ((options & (IPSEC_OPT_ENC|IPSEC_OPT_AUTH)) != (IPSEC_OPT_ENC|IPSEC_OPT_AUTH)) { @@ -244,16 +390,16 @@ kernel_reserve_spi(char *srcaddress, int options) default: proto = IPPROTO_AH; } - return kernel_reserve_single_spi(srcaddress, 0, proto); + return kernel_reserve_single_spi(src, dst, 0, proto); } - if (!(spi = kernel_reserve_single_spi(srcaddress, 0, IPPROTO_ESP))) + if (!(spi = kernel_reserve_single_spi(src, dst, 0, IPPROTO_ESP))) return spi; /* Try to get the same spi for ah and esp */ - while (!kernel_reserve_single_spi(srcaddress, spi, IPPROTO_AH)) { - kernel_delete_spi(srcaddress, (u_int8_t *)&spi, IPPROTO_ESP); - if (!(spi = kernel_reserve_single_spi(srcaddress, 0, IPPROTO_ESP))) + while (!kernel_reserve_single_spi(src, dst, spi, IPPROTO_AH)) { + kernel_delete_spi(src, spi, IPPROTO_ESP); + if (!(spi = kernel_reserve_single_spi(src, dst, 0, IPPROTO_ESP))) return spi; } @@ -261,102 +407,207 @@ kernel_reserve_spi(char *srcaddress, int options) } u_int32_t -kernel_reserve_single_spi(char *srcaddress, u_int32_t spi, int proto) +kernel_reserve_single_spi(char *srcaddress, char *dstaddress, u_int32_t spi, + int proto) { - struct encap_msghdr *em; + struct sadb_msg smsg, *sres; + struct sadb_address sad1, sad2; /* src and dst */ + struct sadb_spirange sspi; + struct sadb_sa *ssa; + union sockaddr_union src, dst; + struct iovec iov[6]; + int cnt = 0; kernel_debug(("kernel_reserve_single_spi: %s, %08x\n", srcaddress, spi)); - bzero(buffer, EMT_RESERVESPI_FLEN); - - em = (struct encap_msghdr *)buffer; + bzero(&src, sizeof(union sockaddr_union)); + bzero(&dst, sizeof(union sockaddr_union)); + bzero(iov, sizeof(iov)); + + bzero(&smsg, sizeof(smsg)); + bzero(&sad1, sizeof(sad1)); + bzero(&sad2, sizeof(sad2)); + bzero(&sspi, sizeof(sspi)); + + smsg.sadb_msg_len = sizeof(smsg) / 8; + smsg.sadb_msg_version = PF_KEY_V2; + smsg.sadb_msg_seq = pfkey_seq++; + smsg.sadb_msg_pid = pfkey_pid; + smsg.sadb_msg_type = SADB_GETSPI; + smsg.sadb_msg_satype = proto == IPPROTO_AH ? + SADB_SATYPE_AH : SADB_SATYPE_ESP; + iov[cnt].iov_base = &smsg; + iov[cnt++].iov_len = sizeof(smsg); + + /* Source Address */ + sad1.sadb_address_exttype = SADB_EXT_ADDRESS_SRC; + sad1.sadb_address_len = (sizeof(sad1) + sizeof(struct sockaddr_in)) / 8; + iov[cnt].iov_base = &sad1; + iov[cnt++].iov_len = sizeof(sad1); + + src.sin.sin_family = AF_INET; + src.sin.sin_len = sizeof(struct sockaddr_in); + src.sin.sin_addr.s_addr = inet_addr(dstaddress); + + iov[cnt].iov_base = &src; + iov[cnt++].iov_len = sizeof(struct sockaddr_in); + smsg.sadb_msg_len += sad1.sadb_address_len; + + /* Destination Address */ + sad2.sadb_address_exttype = SADB_EXT_ADDRESS_DST; + sad2.sadb_address_len = (sizeof(sad2) + sizeof(struct sockaddr_in)) / 8; + + iov[cnt].iov_base = &sad2; + iov[cnt++].iov_len = sizeof(sad2); + + dst.sin.sin_family = AF_INET; + dst.sin.sin_len = sizeof(struct sockaddr_in); + dst.sin.sin_addr.s_addr = inet_addr(srcaddress); + + iov[cnt].iov_base = &dst; + iov[cnt++].iov_len = sizeof(struct sockaddr_in); + smsg.sadb_msg_len += sad2.sadb_address_len; + + sspi.sadb_spirange_exttype = SADB_EXT_SPIRANGE; + sspi.sadb_spirange_len = sizeof(sspi) / 8; + if (spi) { + sspi.sadb_spirange_min = spi; + sspi.sadb_spirange_max = spi; + } else { + sspi.sadb_spirange_min = 0x100; + sspi.sadb_spirange_max = -1; + } + iov[cnt].iov_base = &sspi; + iov[cnt++].iov_len = sizeof(sspi); + smsg.sadb_msg_len += sspi.sadb_spirange_len; - em->em_msglen = EMT_RESERVESPI_FLEN; - em->em_version = PFENCAP_VERSION_1; - em->em_type = EMT_RESERVESPI; + /* get back SADB_EXT_SA */ - em->em_gen_spi = spi; - em->em_gen_dst.s_addr = inet_addr(srcaddress); - em->em_gen_sproto = proto; - - if (!kernel_xf_set(em)) { + if (!KERNEL_XF_SET(smsg.sadb_msg_len*8)) { log_error(1, "kernel_xf_set() in kernel_reserve_single_spi()"); return 0; } - if (!kernel_xf_read(em, EMT_RESERVESPI_FLEN)) + sres = (struct sadb_msg *)buffer; + ssa = (struct sadb_sa *)(sres + 1); + if (ssa->sadb_sa_exttype != SADB_EXT_SA) { + log_error(0, "SADB_GETSPI did not return a SADB_EXT_SA struct: %d", + ssa->sadb_sa_exttype); return 0; + } - return em->em_gen_spi; + return ntohl(ssa->sadb_sa_spi); } int kernel_ah(attrib_t *ob, struct spiob *SPI, u_int8_t *secrets, int hmac) { - struct encap_msghdr *em; - struct ah_old_xencap *xdo; - struct ah_new_xencap *xdn; + struct sadb_msg sa; + struct sadb_address sad1; + struct sadb_address sad2; + struct sadb_sa sr; + struct sadb_lifetime sl; + struct sadb_key sk; + struct sockaddr_in src; + struct sockaddr_in dst; + struct iovec iov[20]; + int len, cnt = 0; transform *xf = kernel_get_transform(ob->id); + time_t now = time(NULL); if (xf == NULL || !(xf->flags & XF_AUTH)) { log_error(0, "%d is not an auth transform in kernel_ah()", ob->id); return -1; } - em = (struct encap_msghdr *)buffer; - - if (!hmac) { - bzero(buffer, EMT_SETSPI_FLEN + 4 + ob->klen); - - em->em_msglen = EMT_SETSPI_FLEN + AH_OLD_XENCAP_LEN + ob->klen; - - em->em_alg = XF_OLD_AH; - - xdo = (struct ah_old_xencap *)(em->em_dat); - - xdo->amx_hash_algorithm = xf->kernel_id; - xdo->amx_keylen = ob->klen; - - bcopy(secrets, xdo->amx_key, ob->klen); - - } else { - bzero(buffer, EMT_SETSPI_FLEN + AH_NEW_XENCAP_LEN + ob->klen); - - em->em_msglen = EMT_SETSPI_FLEN + AH_NEW_XENCAP_LEN + ob->klen; - - em->em_alg = XF_NEW_AH; - - xdn = (struct ah_new_xencap *)(em->em_dat); - - xdn->amx_hash_algorithm = xf->kernel_id; - xdn->amx_wnd = 16; - xdn->amx_keylen = ob->klen; - - bcopy(secrets, xdn->amx_key, ob->klen); - } - - em->em_version = PFENCAP_VERSION_1; - em->em_type = EMT_SETSPI; - em->em_spi = htonl((SPI->SPI[0]<<24) + (SPI->SPI[1]<<16) + - (SPI->SPI[2]<<8) + SPI->SPI[3]); - em->em_src.s_addr = inet_addr(SPI->flags & SPI_OWNER ? - SPI->address : SPI->local_address); - em->em_dst.s_addr = inet_addr(SPI->flags & SPI_OWNER ? - SPI->local_address : SPI->address); - - if (SPI->flags & SPI_TUNNEL) { - em->em_osrc.s_addr = inet_addr(SPI->flags & SPI_OWNER ? - SPI->address : SPI->local_address); - em->em_odst.s_addr = inet_addr(SPI->flags & SPI_OWNER ? - SPI->local_address : SPI->address); - } - em->em_sproto = IPPROTO_AH; + bzero(&sa, sizeof(sa)); + bzero(&sad1, sizeof(sad1)); + bzero(&sad2, sizeof(sad2)); + bzero(&sr, sizeof(sr)); + bzero(&sk, sizeof(sk)); + bzero(&sl, sizeof(sl)); + bzero(&src, sizeof(src)); + bzero(&dst, sizeof(dst)); + + sa.sadb_msg_len = sizeof(sa) / 8; + sa.sadb_msg_version = PF_KEY_V2; + sa.sadb_msg_type = SPI->flags & SPI_OWNER ? + SADB_UPDATE : SADB_ADD; + sa.sadb_msg_satype = !hmac ? + SADB_SATYPE_X_AH_OLD : SADB_SATYPE_AH; + sa.sadb_msg_seq = pfkey_seq++; + sa.sadb_msg_pid = pfkey_pid; + iov[cnt].iov_base = &sa; + len = iov[cnt++].iov_len = sizeof(sa); + + /* Source Address */ + sad1.sadb_address_len = 1 + sizeof(struct sockaddr_in) / 8; + sad1.sadb_address_exttype = SADB_EXT_ADDRESS_SRC; + src.sin_family = AF_INET; + src.sin_len = sizeof(struct sockaddr_in); + src.sin_addr.s_addr = inet_addr(SPI->flags & SPI_OWNER ? + SPI->address : SPI->local_address); + sa.sadb_msg_len += sad1.sadb_address_len; + + iov[cnt].iov_base = &sad1; + len += iov[cnt++].iov_len = sizeof(sad1); + iov[cnt].iov_base = &src; + len += iov[cnt++].iov_len = sizeof(struct sockaddr); + + /* Destination Address */ + sad2.sadb_address_len = 1 + sizeof(struct sockaddr_in) / 8; + sad2.sadb_address_exttype = SADB_EXT_ADDRESS_DST; + dst.sin_family = AF_INET; + dst.sin_len = sizeof(struct sockaddr_in); + dst.sin_addr.s_addr = inet_addr(SPI->flags & SPI_OWNER ? + SPI->local_address : SPI->address); + sa.sadb_msg_len += sad2.sadb_address_len; + + iov[cnt].iov_base = &sad2; + len += iov[cnt++].iov_len = sizeof(sad2); + iov[cnt].iov_base = &dst; + len += iov[cnt++].iov_len = sizeof(struct sockaddr); + + sr.sadb_sa_len = sizeof(sr) / 8; + sr.sadb_sa_exttype = SADB_EXT_SA; + sr.sadb_sa_spi = htonl(SPITOINT(SPI->SPI)); + sr.sadb_sa_replay = !hmac ? 0 : 32; + sr.sadb_sa_state = SADB_SASTATE_MATURE; + sr.sadb_sa_auth = xf->kernel_id; + sr.sadb_sa_encrypt = 0; + if (SPI->flags & SPI_TUNNEL) + sr.sadb_sa_flags |= SADB_SAFLAGS_X_TUNNEL; + sa.sadb_msg_len += sr.sadb_sa_len; + + iov[cnt].iov_base = &sr; + len += iov[cnt++].iov_len = sizeof(sr); + + sl.sadb_lifetime_len = sizeof(sl) / 8; + sl.sadb_lifetime_exttype = SADB_EXT_LIFETIME_HARD; + sl.sadb_lifetime_allocations = 10; /* 10 flows */ + sl.sadb_lifetime_bytes = 1000000000; /* lots of bytes */ + sl.sadb_lifetime_addtime = SPI->lifetime + 60 - now; + sl.sadb_lifetime_usetime = SPI->lifetime - now; /* first use */ + sa.sadb_msg_len += sl.sadb_lifetime_len; + + iov[cnt].iov_base = &sl; + len += iov[cnt++].iov_len = sizeof(sl); + + sk.sadb_key_len = (sizeof(sk) + ob->klen + 7) / 8; + sk.sadb_key_exttype = SADB_EXT_KEY_AUTH; + sk.sadb_key_bits = ob->klen * 8; + sa.sadb_msg_len += sk.sadb_key_len; + + iov[cnt].iov_base = &sk; + len += iov[cnt++].iov_len = sizeof(sk); + iov[cnt].iov_base = secrets; + len += iov[cnt++].iov_len = ((ob->klen + 7) / 8) * 8; kernel_debug(("kernel_ah: %08x. %s-Mode\n", - em->em_spi, + ntohl(sr.sadb_sa_spi), SPI->flags & SPI_TUNNEL ? "Tunnel" : "Transport")); - if (!kernel_xf_set(em)) { + if (!KERNEL_XF_SET(len)) { log_error(1, "kernel_xf_set() in kernel_ah()"); return -1; } @@ -366,12 +617,21 @@ kernel_ah(attrib_t *ob, struct spiob *SPI, u_int8_t *secrets, int hmac) int kernel_esp(attrib_t *ob, attrib_t *ob2, struct spiob *SPI, u_int8_t *secrets) { - struct encap_msghdr *em; - struct esp_old_xencap *xdo; - struct esp_new_xencap *xdn; + struct sadb_msg sa; + struct sadb_address sad1; + struct sadb_address sad2; + struct sadb_sa sr; + struct sadb_lifetime sl; + struct sadb_key sk1; + struct sadb_key sk2; + struct sockaddr_in src; + struct sockaddr_in dst; + struct iovec iov[20]; attrib_t *attenc, *attauth = NULL; u_int8_t *sec1, *sec2 = NULL; - transform *xf_enc, *xf_auth; + transform *xf_enc, *xf_auth = NULL; + int cnt = 0; + time_t now = time(NULL); if (ob->type & AT_AUTH) { if (ob2 == NULL || ob2->type != AT_ENC) { @@ -403,70 +663,109 @@ kernel_esp(attrib_t *ob, attrib_t *ob2, struct spiob *SPI, u_int8_t *secrets) if (attauth != NULL) xf_auth = kernel_get_transform(attauth->id); - em = (struct encap_msghdr *)buffer; - - if (xf_enc->flags & ESP_OLD) { - bzero(buffer, EMT_SETSPI_FLEN + ESP_OLD_XENCAP_LEN +4+attenc->klen); - - em->em_msglen = EMT_SETSPI_FLEN + ESP_OLD_XENCAP_LEN +4+attenc->klen; - - em->em_alg = XF_OLD_ESP; - - xdo = (struct esp_old_xencap *)(em->em_dat); - - xdo->edx_enc_algorithm = xf_enc->kernel_id; - xdo->edx_ivlen = 4; - xdo->edx_keylen = attenc->klen; - - bcopy(SPI->SPI, xdo->edx_data, 4); - bcopy(sec1, xdo->edx_data+4, attenc->klen); - } else { - bzero(buffer, EMT_SETSPI_FLEN + ESP_NEW_XENCAP_LEN + attenc->klen + - (attauth ? attauth->klen : 0)); - - em->em_msglen = EMT_SETSPI_FLEN + ESP_NEW_XENCAP_LEN + - attenc->klen + (attauth ? attauth->klen : 0); - - em->em_alg = XF_NEW_ESP; - - xdn = (struct esp_new_xencap *)(em->em_dat); - - xdn->edx_enc_algorithm = xf_enc->kernel_id; - xdn->edx_hash_algorithm = attauth ? xf_auth->kernel_id : 0; - xdn->edx_ivlen = 0; - xdn->edx_confkeylen = attenc->klen; - xdn->edx_authkeylen = attauth ? attauth->klen : 0; - xdn->edx_wnd = 16; - xdn->edx_flags = attauth ? ESP_NEW_FLAG_AUTH : 0; - - bcopy(sec1, xdn->edx_data, attenc->klen); - if (attauth != NULL) - bcopy(sec2, xdn->edx_data + attenc->klen, attauth->klen); - } - /* Common settings shared by ESP_OLD and ESP_NEW */ - - em->em_version = PFENCAP_VERSION_1; - em->em_type = EMT_SETSPI; - em->em_spi = htonl((SPI->SPI[0]<<24) + (SPI->SPI[1]<<16) + - (SPI->SPI[2]<<8) + SPI->SPI[3]); - em->em_src.s_addr = inet_addr(SPI->flags & SPI_OWNER ? - SPI->address : SPI->local_address); - em->em_dst.s_addr = inet_addr(SPI->flags & SPI_OWNER ? - SPI->local_address : SPI->address); - em->em_sproto = IPPROTO_ESP; - - if (SPI->flags & SPI_TUNNEL) { - em->em_osrc.s_addr = inet_addr(SPI->flags & SPI_OWNER ? - SPI->address : SPI->local_address); - em->em_odst.s_addr = inet_addr(SPI->flags & SPI_OWNER ? - SPI->local_address : SPI->address); + bzero(&sa, sizeof(sa)); + bzero(&sad1, sizeof(sad1)); + bzero(&sad2, sizeof(sad2)); + bzero(&sr, sizeof(sr)); + bzero(&sk1, sizeof(sk1)); + bzero(&sk2, sizeof(sk2)); + bzero(&sl, sizeof(sl)); + bzero(&src, sizeof(src)); + bzero(&dst, sizeof(dst)); + + sa.sadb_msg_len = sizeof(sa) / 8; + sa.sadb_msg_version = PF_KEY_V2; + sa.sadb_msg_type = SPI->flags & SPI_OWNER ? + SADB_UPDATE : SADB_ADD; + sa.sadb_msg_satype = xf_enc->flags & ESP_OLD ? + SADB_SATYPE_X_ESP_OLD : SADB_SATYPE_ESP; + sa.sadb_msg_seq = pfkey_seq++; + sa.sadb_msg_pid = pfkey_pid; + iov[cnt].iov_base = &sa; + iov[cnt++].iov_len = sizeof(sa); + + sr.sadb_sa_len = sizeof(sr) / 8; + sr.sadb_sa_exttype = SADB_EXT_SA; + sr.sadb_sa_spi = htonl(SPITOINT(SPI->SPI)); + sr.sadb_sa_replay = xf_enc->flags & ESP_OLD ? 0 : 32; + sr.sadb_sa_state = SADB_SASTATE_MATURE; + sr.sadb_sa_auth = attauth ? xf_auth->kernel_id : 0; + sr.sadb_sa_encrypt = xf_enc->kernel_id; + if (xf_enc->flags & ESP_OLD) + sr.sadb_sa_flags |= SADB_SAFLAGS_X_HALFIV; + if (SPI->flags & SPI_TUNNEL) + sr.sadb_sa_flags |= SADB_SAFLAGS_X_TUNNEL; + sa.sadb_msg_len += sr.sadb_sa_len; + + iov[cnt].iov_base = &sr; + iov[cnt++].iov_len = sizeof(sr); + + /* Source Address */ + sad1.sadb_address_len = 1 + sizeof(struct sockaddr_in) / 8; + sad1.sadb_address_exttype = SADB_EXT_ADDRESS_SRC; + src.sin_family = AF_INET; + src.sin_len = sizeof(struct sockaddr_in); + src.sin_addr.s_addr = inet_addr(SPI->flags & SPI_OWNER ? + SPI->address : SPI->local_address); + sa.sadb_msg_len += sad1.sadb_address_len; + + iov[cnt].iov_base = &sad1; + iov[cnt++].iov_len = sizeof(sad1); + iov[cnt].iov_base = &src; + iov[cnt++].iov_len = sizeof(struct sockaddr); + + /* Destination Address */ + sad2.sadb_address_len = 1 + sizeof(struct sockaddr_in) / 8; + sad2.sadb_address_exttype = SADB_EXT_ADDRESS_DST; + dst.sin_family = AF_INET; + dst.sin_len = sizeof(struct sockaddr_in); + dst.sin_addr.s_addr = inet_addr(SPI->flags & SPI_OWNER ? + SPI->local_address : SPI->address); + sa.sadb_msg_len += sad2.sadb_address_len; + + iov[cnt].iov_base = &sad2; + iov[cnt++].iov_len = sizeof(sad2); + iov[cnt].iov_base = &dst; + iov[cnt++].iov_len = sizeof(struct sockaddr); + + sl.sadb_lifetime_len = sizeof(sl) / 8; + sl.sadb_lifetime_exttype = SADB_EXT_LIFETIME_HARD; + sl.sadb_lifetime_allocations = 10; /* 10 flows */ + sl.sadb_lifetime_bytes = 1000000000; /* lots of bytes */ + sl.sadb_lifetime_addtime = SPI->lifetime + 60 - now; + sl.sadb_lifetime_usetime = SPI->lifetime - now; /* first use */ + sa.sadb_msg_len += sl.sadb_lifetime_len; + + iov[cnt].iov_base = &sl; + iov[cnt++].iov_len = sizeof(sl); + + sk1.sadb_key_len = (sizeof(sk1) + attenc->klen + 7) / 8; + sk1.sadb_key_exttype = SADB_EXT_KEY_ENCRYPT; + sk1.sadb_key_bits = attenc->klen * 8; + sa.sadb_msg_len += sk1.sadb_key_len; + + iov[cnt].iov_base = &sk1; + iov[cnt++].iov_len = sizeof(sk1); + iov[cnt].iov_base = sec1; + iov[cnt++].iov_len = ((attenc->klen + 7) / 8) * 8; + + if (attauth != NULL) { + sk2.sadb_key_len = (sizeof(sk2) + attauth->klen + 7) / 8; + sk2.sadb_key_exttype = SADB_EXT_KEY_AUTH; + sk2.sadb_key_bits = attauth->klen * 8; + sa.sadb_msg_len += sk2.sadb_key_len; + + iov[cnt].iov_base = &sk2; + iov[cnt++].iov_len = sizeof(sk2); + iov[cnt].iov_base = sec2; + iov[cnt++].iov_len = ((attauth->klen + 7) / 8) * 8; } kernel_debug(("kernel_esp: %08x. %s-Mode\n", - em->em_spi, + ntohl(sr.sadb_sa_spi), SPI->flags & SPI_TUNNEL ? "Tunnel" : "Transport")); - - if (!kernel_xf_set(em)) { + + if (!KERNEL_XF_SET(sa.sadb_msg_len * 8)) { log_error(1, "kernel_xf_set() in kernel_esp()"); return -1; } @@ -479,33 +778,177 @@ kernel_esp(attrib_t *ob, attrib_t *ob2, struct spiob *SPI, u_int8_t *secrets) int kernel_group_spi(char *address, u_int8_t *spi) { - struct encap_msghdr *em; - in_addr_t addr; + struct sadb_msg smsg; + struct sadb_sa sa, sa2; + struct sadb_address sad1, sad2; + struct sadb_protocol sproto; + union sockaddr_union dst1, dst2; + struct iovec iov[8]; + int cnt = 0; u_int32_t SPI; - SPI = (spi[0]<<24) + (spi[1]<<16) + (spi[2]<<8) + spi[3]; + SPI = SPITOINT(spi); + + bzero(&smsg, sizeof(smsg)); + bzero(&sa, sizeof(sa)); + bzero(&sa2, sizeof(sa2)); + bzero(&sad1, sizeof(sad1)); + bzero(&sad2, sizeof(sad2)); + bzero(&dst1, sizeof(dst1)); + bzero(&dst2, sizeof(dst2)); + + smsg.sadb_msg_version = PF_KEY_V2; + smsg.sadb_msg_seq = pfkey_seq++; + smsg.sadb_msg_pid = pfkey_pid; + smsg.sadb_msg_type = SADB_X_GRPSPIS; + smsg.sadb_msg_satype = SADB_SATYPE_ESP; + smsg.sadb_msg_len = sizeof(smsg) / 8; + + iov[cnt].iov_base = &smsg; + iov[cnt++].iov_len = sizeof(smsg); + + sa.sadb_sa_len = sizeof(sa) / 8; + sa.sadb_sa_exttype = SADB_EXT_SA; + sa.sadb_sa_spi = htonl(SPI); + sa.sadb_sa_state = SADB_SASTATE_MATURE; + smsg.sadb_msg_len += sa.sadb_sa_len; + + iov[cnt].iov_base = &sa; + iov[cnt++].iov_len = sizeof(sa); + + sa2.sadb_sa_len = sizeof(sa2) / 8; + sa2.sadb_sa_exttype = SADB_EXT_X_SA2; + sa2.sadb_sa_spi = htonl(SPI); + sa2.sadb_sa_state = SADB_SASTATE_MATURE; + smsg.sadb_msg_len += sa2.sadb_sa_len; + + iov[cnt].iov_base = &sa2; + iov[cnt++].iov_len = sizeof(sa2); + + sad1.sadb_address_len = (sizeof(sad1) + sizeof(struct sockaddr_in)) / 8; + sad1.sadb_address_exttype = SADB_EXT_ADDRESS_DST; + iov[cnt].iov_base = &sad1; + iov[cnt++].iov_len = sizeof(sad1); + dst1.sin.sin_family = AF_INET; + dst1.sin.sin_len = sizeof(struct sockaddr_in); + dst1.sin.sin_addr.s_addr = inet_addr(address); + smsg.sadb_msg_len += sad1.sadb_address_len; + iov[cnt].iov_base = &dst1; + iov[cnt++].iov_len = sizeof(struct sockaddr_in); + + sad2.sadb_address_len = (sizeof(sad2) + sizeof(struct sockaddr_in)) / 8; + sad2.sadb_address_exttype = SADB_EXT_X_DST2; + iov[cnt].iov_base = &sad2; + iov[cnt++].iov_len = sizeof(sad2); + dst2.sin.sin_family = AF_INET; + dst2.sin.sin_len = sizeof(struct sockaddr_in); + dst2.sin.sin_addr.s_addr = inet_addr(address); + smsg.sadb_msg_len += sad2.sadb_address_len; + iov[cnt].iov_base = &dst2; + iov[cnt++].iov_len = sizeof(struct sockaddr_in); + + sproto.sadb_protocol_len = sizeof(sproto) / 8; + sproto.sadb_protocol_exttype = SADB_EXT_X_PROTOCOL; + sproto.sadb_protocol_proto = SADB_SATYPE_AH; + smsg.sadb_msg_len += sproto.sadb_protocol_len; + iov[cnt].iov_base = &sproto; + iov[cnt++].iov_len = sizeof(sproto); kernel_debug(("kernel_group_spi: %s, %08x\n", address, SPI)); - addr = inet_addr(address); + if (!KERNEL_XF_SET(smsg.sadb_msg_len*8)) { + log_error(1, "kernel_xf_set() in kernel_group_spi()"); + return -1; + } - bzero(buffer, EMT_GRPSPIS_FLEN); + return 1; +} - em = (struct encap_msghdr *)buffer; - - em->em_msglen = EMT_GRPSPIS_FLEN; - em->em_version = PFENCAP_VERSION_1; - em->em_type = EMT_GRPSPIS; - - em->em_rel_spi = htonl(SPI); - em->em_rel_dst.s_addr = addr; - em->em_rel_sproto = IPPROTO_ESP; - em->em_rel_spi2 = htonl(SPI); - em->em_rel_dst2.s_addr = addr; - em->em_rel_sproto2 = IPPROTO_AH; - - if (!kernel_xf_set(em)) { - log_error(1, "kernel_xf_set() in kernel_group_spi()"); +int +kernel_bind_spis(struct spiob *spi1, struct spiob *spi2) +{ + struct sadb_msg smsg; + struct sadb_sa sa, sa2; + struct sadb_address sad1, sad2; + struct sadb_protocol sproto; + union sockaddr_union dst1, dst2; + struct iovec iov[8]; + int cnt = 0; + u_int32_t inspi = SPITOINT(spi1->SPI); + u_int32_t outspi = SPITOINT(spi2->SPI); + + bzero(&smsg, sizeof(smsg)); + bzero(&sa, sizeof(sa)); + bzero(&sa2, sizeof(sa2)); + bzero(&sad1, sizeof(sad1)); + bzero(&sad2, sizeof(sad2)); + bzero(&dst1, sizeof(dst1)); + bzero(&dst2, sizeof(dst2)); + + smsg.sadb_msg_version = PF_KEY_V2; + smsg.sadb_msg_seq = pfkey_seq++; + smsg.sadb_msg_pid = pfkey_pid; + smsg.sadb_msg_type = SADB_X_BINDSA; + smsg.sadb_msg_satype = spi1->flags & SPI_ESP ? + SADB_SATYPE_ESP : SADB_SATYPE_AH; + smsg.sadb_msg_len = sizeof(smsg) / 8; + + iov[cnt].iov_base = &smsg; + iov[cnt++].iov_len = sizeof(smsg); + + sa.sadb_sa_len = sizeof(sa) / 8; + sa.sadb_sa_exttype = SADB_EXT_SA; + sa.sadb_sa_spi = htonl(inspi); + sa.sadb_sa_state = SADB_SASTATE_MATURE; + smsg.sadb_msg_len += sa.sadb_sa_len; + + iov[cnt].iov_base = &sa; + iov[cnt++].iov_len = sizeof(sa); + + sa2.sadb_sa_len = sizeof(sa2) / 8; + sa2.sadb_sa_exttype = SADB_EXT_X_SA2; + sa2.sadb_sa_spi = htonl(outspi); + sa2.sadb_sa_state = SADB_SASTATE_MATURE; + smsg.sadb_msg_len += sa2.sadb_sa_len; + + iov[cnt].iov_base = &sa2; + iov[cnt++].iov_len = sizeof(sa2); + + sad1.sadb_address_len = (sizeof(sad1) + sizeof(struct sockaddr_in)) / 8; + sad1.sadb_address_exttype = SADB_EXT_ADDRESS_DST; + iov[cnt].iov_base = &sad1; + iov[cnt++].iov_len = sizeof(sad1); + dst1.sin.sin_family = AF_INET; + dst1.sin.sin_len = sizeof(struct sockaddr_in); + dst1.sin.sin_addr.s_addr = inet_addr(spi1->local_address); + smsg.sadb_msg_len += sad1.sadb_address_len; + iov[cnt].iov_base = &dst1; + iov[cnt++].iov_len = sizeof(struct sockaddr_in); + + sad2.sadb_address_len = (sizeof(sad2) + sizeof(struct sockaddr_in)) / 8; + sad2.sadb_address_exttype = SADB_EXT_X_DST2; + iov[cnt].iov_base = &sad2; + iov[cnt++].iov_len = sizeof(sad2); + dst2.sin.sin_family = AF_INET; + dst2.sin.sin_len = sizeof(struct sockaddr_in); + dst2.sin.sin_addr.s_addr = inet_addr(spi2->address); + smsg.sadb_msg_len += sad2.sadb_address_len; + iov[cnt].iov_base = &dst2; + iov[cnt++].iov_len = sizeof(struct sockaddr_in); + + sproto.sadb_protocol_len = sizeof(sproto) / 8; + sproto.sadb_protocol_exttype = SADB_EXT_X_PROTOCOL; + sproto.sadb_protocol_proto = spi2->flags & SPI_ESP ? + SADB_SATYPE_ESP : SADB_SATYPE_AH; + smsg.sadb_msg_len += sproto.sadb_protocol_len; + iov[cnt].iov_base = &sproto; + iov[cnt++].iov_len = sizeof(sproto); + + kernel_debug(("kernel_bind_spi: <%s, %08x> -> <%s, %08x>\n", + spi1->local_address, inspi, spi2->address, outspi)); + + if (!KERNEL_XF_SET(smsg.sadb_msg_len*8)) { + log_error(1, "kernel_xf_set() in kernel_bind_spi()"); return -1; } @@ -517,32 +960,104 @@ kernel_enable_spi(in_addr_t isrc, in_addr_t ismask, in_addr_t idst, in_addr_t idmask, char *address, u_int8_t *spi, int proto, int flags) { - struct encap_msghdr *em; + struct sadb_msg smsg; + struct sadb_sa sa; + struct sadb_address sad, sad1, sad2, sad3, sad4; + union sockaddr_union dst, osrc, osmask, odst, odmask; + struct iovec iov[12]; u_int32_t SPI; - - SPI = (spi[0]<<24) + (spi[1]<<16) + (spi[2]<<8) + spi[3]; - - kernel_debug(("kernel_enable_spi: %08x\n", SPI)); - - bzero(buffer, EMT_ENABLESPI_FLEN); - - em = (struct encap_msghdr *)buffer; + int cnt = 0; + SPI = SPITOINT(spi); + + bzero(&smsg, sizeof(smsg)); + bzero(&sa, sizeof(sa)); + bzero(&sad, sizeof(sad)); + bzero(&sad1, sizeof(sad1)); + bzero(&sad2, sizeof(sad2)); + bzero(&sad3, sizeof(sad3)); + bzero(&sad4, sizeof(sad4)); + bzero(&dst, sizeof(dst)); + bzero(&osrc, sizeof(osrc)); + bzero(&osmask, sizeof(osmask)); + bzero(&odst, sizeof(odst)); + bzero(&odmask, sizeof(odmask)); - em->em_msglen = EMT_ENABLESPI_FLEN; - em->em_version = PFENCAP_VERSION_1; - em->em_type = EMT_ENABLESPI; - - em->em_ena_isrc.s_addr = isrc; - em->em_ena_ismask.s_addr = ismask; - em->em_ena_idst.s_addr = idst; - em->em_ena_idmask.s_addr = idmask; + smsg.sadb_msg_len = sizeof(smsg) / 8; + smsg.sadb_msg_version = PF_KEY_V2; + smsg.sadb_msg_seq = pfkey_seq++; + smsg.sadb_msg_pid = pfkey_pid; + smsg.sadb_msg_type = SADB_X_ADDFLOW; + smsg.sadb_msg_satype = proto == IPPROTO_ESP ? + SADB_SATYPE_ESP : SADB_SATYPE_AH; + iov[cnt].iov_base = &smsg; + iov[cnt++].iov_len = sizeof(smsg); + + sa.sadb_sa_len = sizeof(sa) / 8; + sa.sadb_sa_exttype = SADB_EXT_SA; + sa.sadb_sa_state = SADB_SASTATE_MATURE; + sa.sadb_sa_spi = htonl(SPI); + sa.sadb_sa_flags = flags; + smsg.sadb_msg_len += sa.sadb_sa_len; + iov[cnt].iov_base = &sa; + iov[cnt++].iov_len = sizeof(sa); + + sad.sadb_address_len = (sizeof(sad) + sizeof(struct sockaddr_in)) / 8; + sad.sadb_address_exttype = SADB_EXT_ADDRESS_DST; + smsg.sadb_msg_len += sad.sadb_address_len; + iov[cnt].iov_base = &sad; + iov[cnt++].iov_len = sizeof(sad); + + dst.sin.sin_family = AF_INET; + dst.sin.sin_len = sizeof(struct sockaddr_in); + dst.sin.sin_addr.s_addr = inet_addr(address); + iov[cnt].iov_base = &dst; + iov[cnt++].iov_len = sizeof(struct sockaddr_in); + + sad1.sadb_address_exttype = SADB_EXT_X_SRC_FLOW; + sad2.sadb_address_exttype = SADB_EXT_X_SRC_MASK; + sad3.sadb_address_exttype = SADB_EXT_X_DST_FLOW; + sad4.sadb_address_exttype = SADB_EXT_X_DST_MASK; + + sad1.sadb_address_len = (sizeof(sad1) + sizeof(struct sockaddr_in)) / 8; + sad2.sadb_address_len = (sizeof(sad2) + sizeof(struct sockaddr_in)) / 8; + sad3.sadb_address_len = (sizeof(sad3) + sizeof(struct sockaddr_in)) / 8; + sad4.sadb_address_len = (sizeof(sad4) + sizeof(struct sockaddr_in)) / 8; + + osrc.sin.sin_family = odst.sin.sin_family = AF_INET; + osmask.sin.sin_family = odmask.sin.sin_family = AF_INET; + osrc.sin.sin_len = odst.sin.sin_len = sizeof(struct sockaddr_in); + osmask.sin.sin_len = sizeof(struct sockaddr_in); + odmask.sin.sin_len = sizeof(struct sockaddr_in); + + osrc.sin.sin_addr.s_addr = isrc; + osmask.sin.sin_addr.s_addr = ismask; + odst.sin.sin_addr.s_addr = idst; + odmask.sin.sin_addr.s_addr = idmask; + smsg.sadb_msg_len += sad1.sadb_address_len * 4; + + iov[cnt].iov_base = &sad1; + iov[cnt++].iov_len = sizeof(sad1); + iov[cnt].iov_base = &osrc; + iov[cnt++].iov_len = sizeof(struct sockaddr_in); + + iov[cnt].iov_base = &sad2; + iov[cnt++].iov_len = sizeof(sad2); + iov[cnt].iov_base = &osmask; + iov[cnt++].iov_len = sizeof(struct sockaddr_in); + + iov[cnt].iov_base = &sad3; + iov[cnt++].iov_len = sizeof(sad3); + iov[cnt].iov_base = &odst; + iov[cnt++].iov_len = sizeof(struct sockaddr_in); + + iov[cnt].iov_base = &sad4; + iov[cnt++].iov_len = sizeof(sad4); + iov[cnt].iov_base = &odmask; + iov[cnt++].iov_len = sizeof(struct sockaddr_in); - em->em_ena_dst.s_addr = inet_addr(address); - em->em_ena_spi = htonl(SPI); - em->em_ena_sproto = proto; - em->em_ena_flags = flags; + kernel_debug(("kernel_enable_spi: %08x\n", SPI)); - if (!kernel_xf_set(em)) { + if (!KERNEL_XF_SET(smsg.sadb_msg_len*8)) { log_error(1, "kernel_xf_set() in kernel_enable_spi()"); return -1; } @@ -555,32 +1070,90 @@ kernel_disable_spi(in_addr_t isrc, in_addr_t ismask, in_addr_t idst, in_addr_t idmask, char *address, u_int8_t *spi, int proto, int flags) { - struct encap_msghdr *em; + struct sadb_msg smsg; + struct sadb_sa sa; + struct sadb_address sad1, sad2, sad3, sad4; + union sockaddr_union osrc, osmask, odst, odmask; + struct iovec iov[12]; u_int32_t SPI; - - SPI = (spi[0]<<24) + (spi[1]<<16) + (spi[2]<<8) + spi[3]; + int cnt = 0; + SPI = SPITOINT(spi); + + bzero(&smsg, sizeof(smsg)); + bzero(&sa, sizeof(sa)); + bzero(&sad1, sizeof(sad1)); + bzero(&sad2, sizeof(sad2)); + bzero(&sad3, sizeof(sad3)); + bzero(&sad4, sizeof(sad4)); + bzero(&osrc, sizeof(osrc)); + bzero(&osmask, sizeof(osmask)); + bzero(&odst, sizeof(odst)); + bzero(&odmask, sizeof(odmask)); + + smsg.sadb_msg_len = sizeof(smsg) / 8; + smsg.sadb_msg_version = PF_KEY_V2; + smsg.sadb_msg_seq = pfkey_seq++; + smsg.sadb_msg_pid = pfkey_pid; + smsg.sadb_msg_type = SADB_X_DELFLOW; + smsg.sadb_msg_satype = proto == IPPROTO_ESP ? + SADB_SATYPE_ESP : SADB_SATYPE_AH; + iov[cnt].iov_base = &smsg; + iov[cnt++].iov_len = sizeof(smsg); + + sa.sadb_sa_len = sizeof(sa) / 8; + sa.sadb_sa_exttype = SADB_EXT_SA; + sa.sadb_sa_state = SADB_SASTATE_MATURE; + sa.sadb_sa_spi = htonl(SPI); + sa.sadb_sa_flags = flags; + smsg.sadb_msg_len += sa.sadb_sa_len; + iov[cnt].iov_base = &sa; + iov[cnt++].iov_len = sizeof(sa); + + sad1.sadb_address_exttype = SADB_EXT_X_SRC_FLOW; + sad2.sadb_address_exttype = SADB_EXT_X_SRC_MASK; + sad3.sadb_address_exttype = SADB_EXT_X_DST_FLOW; + sad4.sadb_address_exttype = SADB_EXT_X_DST_MASK; + + sad1.sadb_address_len = (sizeof(sad1) + sizeof(struct sockaddr_in)) / 8; + sad2.sadb_address_len = (sizeof(sad2) + sizeof(struct sockaddr_in)) / 8; + sad3.sadb_address_len = (sizeof(sad3) + sizeof(struct sockaddr_in)) / 8; + sad4.sadb_address_len = (sizeof(sad4) + sizeof(struct sockaddr_in)) / 8; + + osrc.sin.sin_family = odst.sin.sin_family = AF_INET; + osmask.sin.sin_family = odmask.sin.sin_family = AF_INET; + osrc.sin.sin_len = odst.sin.sin_len = sizeof(struct sockaddr_in); + osmask.sin.sin_len = sizeof(struct sockaddr_in); + odmask.sin.sin_len = sizeof(struct sockaddr_in); + + osrc.sin.sin_addr.s_addr = isrc; + osmask.sin.sin_addr.s_addr = ismask; + odst.sin.sin_addr.s_addr = idst; + odmask.sin.sin_addr.s_addr = idmask; + smsg.sadb_msg_len += sad1.sadb_address_len * 4; + + iov[cnt].iov_base = &sad1; + iov[cnt++].iov_len = sizeof(sad1); + iov[cnt].iov_base = &osrc; + iov[cnt++].iov_len = sizeof(struct sockaddr_in); + + iov[cnt].iov_base = &sad2; + iov[cnt++].iov_len = sizeof(sad2); + iov[cnt].iov_base = &osmask; + iov[cnt++].iov_len = sizeof(struct sockaddr_in); + + iov[cnt].iov_base = &sad3; + iov[cnt++].iov_len = sizeof(sad3); + iov[cnt].iov_base = &odst; + iov[cnt++].iov_len = sizeof(struct sockaddr_in); + + iov[cnt].iov_base = &sad4; + iov[cnt++].iov_len = sizeof(sad4); + iov[cnt].iov_base = &odmask; + iov[cnt++].iov_len = sizeof(struct sockaddr_in); kernel_debug(("kernel_disable_spi: %08x\n", SPI)); - bzero(buffer, EMT_DISABLESPI_FLEN); - - em = (struct encap_msghdr *)buffer; - - em->em_msglen = EMT_DISABLESPI_FLEN; - em->em_version = PFENCAP_VERSION_1; - em->em_type = EMT_DISABLESPI; - - em->em_ena_isrc.s_addr = isrc; - em->em_ena_ismask.s_addr = ismask; - em->em_ena_idst.s_addr = idst; - em->em_ena_idmask.s_addr = idmask; - - em->em_ena_dst.s_addr = inet_addr(address); - em->em_ena_spi = htonl(SPI); - em->em_ena_sproto = proto; - em->em_ena_flags = flags; - - if (!kernel_xf_set(em) && errno != ENOENT) { + if (!KERNEL_XF_SET(smsg.sadb_msg_len*8)) { log_error(1, "kernel_xf_set() in kernel_disable_spi()"); return -1; } @@ -593,30 +1166,74 @@ kernel_disable_spi(in_addr_t isrc, in_addr_t ismask, */ int -kernel_delete_spi(char *address, u_int8_t *spi, int proto) +kernel_delete_spi(char *address, u_int32_t spi, int proto) { - struct encap_msghdr *em; - - bzero(buffer, EMT_DELSPI_FLEN); - - em = (struct encap_msghdr *)buffer; - - em->em_msglen = EMT_DELSPI_FLEN; - em->em_version = PFENCAP_VERSION_1; - em->em_type = EMT_DELSPI; - em->em_gen_spi = htonl((spi[0]<<24) + (spi[1]<<16) + - (spi[2]<<8) + spi[3]); - em->em_gen_dst.s_addr = inet_addr(address); - em->em_gen_sproto = proto; - - kernel_debug(("kernel_delete_spi: %08x\n", em->em_gen_spi)); - - if (!kernel_xf_set(em)) { - log_error(1, "kernel_xf_set() in kernel_delete_spi()"); - return -1; - } + struct sadb_msg sa; + struct sadb_sa sr; + struct sadb_address sad1; + struct sadb_address sad2; + union sockaddr_union src, dst; + struct iovec iov[10]; + int cnt = 0; + + bzero(&sa, sizeof(sa)); + bzero(&sad1, sizeof(sad1)); + bzero(&sad2, sizeof(sad2)); + bzero(&sr, sizeof(sr)); + bzero(&src, sizeof(src)); + bzero(&dst, sizeof(dst)); + + sa.sadb_msg_version = PF_KEY_V2; + sa.sadb_msg_type = SADB_DELETE; + sa.sadb_msg_satype = proto == IPPROTO_ESP ? + SADB_SATYPE_ESP : SADB_SATYPE_AH; + sa.sadb_msg_seq = pfkey_seq++; + sa.sadb_msg_pid = pfkey_pid; + + /* Source Address */ + sad1.sadb_address_len = 1 + sizeof(struct sockaddr_in) / 8; + sad1.sadb_address_exttype = SADB_EXT_ADDRESS_SRC; + + src.sin.sin_family = AF_INET; + src.sin.sin_len = sizeof(struct sockaddr_in); + + /* Destination Address */ + sad2.sadb_address_len = 1 + sizeof(struct sockaddr_in) / 8; + sad2.sadb_address_exttype = SADB_EXT_ADDRESS_DST; + + dst.sin.sin_family = AF_INET; + dst.sin.sin_len = sizeof(struct sockaddr_in); + dst.sin.sin_addr.s_addr = inet_addr(address); + + sr.sadb_sa_exttype = SADB_EXT_SA; + sr.sadb_sa_spi = htonl(spi); + sr.sadb_sa_len = sizeof(sr) / 8; + + sa.sadb_msg_len = 2 + sr.sadb_sa_len + sad2.sadb_address_len + + sad1.sadb_address_len; + + iov[cnt].iov_base = &sa; + iov[cnt++].iov_len = sizeof(sa); + iov[cnt].iov_base = &sad1; + iov[cnt++].iov_len = sizeof(sad1); + iov[cnt].iov_base = &src; + iov[cnt++].iov_len = sizeof(struct sockaddr); + iov[cnt].iov_base = &sad2; + iov[cnt++].iov_len = sizeof(sad2); + iov[cnt].iov_base = &dst; + iov[cnt++].iov_len = sizeof(struct sockaddr); + iov[cnt].iov_base = &sr; + iov[cnt++].iov_len = sizeof(sr); + + + kernel_debug(("kernel_delete_spi: %08x\n", spi)); + + if (!KERNEL_XF_SET(sa.sadb_msg_len * 8)) { + log_error(1, "kernel_xf_set() in kernel_delete_spi()"); + return -1; + } - return 1; + return 1; } /* @@ -632,6 +1249,7 @@ kernel_insert_spi(struct stateob *st, struct spiob *SPI) u_int8_t *attributes; u_int16_t attribsize, ahsize, espsize; u_int8_t *secrets, *ah, *esp; + struct spiob *spi2; attrib_t *attprop; int offset, proto = 0; @@ -663,7 +1281,7 @@ kernel_insert_spi(struct stateob *st, struct spiob *SPI) count += esp[count+1]+2; } if (atesp == NULL) { - log_error(0, "No encryption attribute in ESP section for SA(%08x, %s->%s) in kernel_insert()", (SPI->SPI[0] << 24) + (SPI->SPI[1] << 16) + (SPI->SPI[2] << 8) + SPI->SPI[3], SPI->local_address, SPI->address); + log_error(0, "No encryption attribute in ESP section for SA(%08x, %s->%s) in kernel_insert()", SPITOINT(SPI->SPI), SPI->local_address, SPI->address); return -1; } @@ -702,7 +1320,7 @@ kernel_insert_spi(struct stateob *st, struct spiob *SPI) } if (atah == NULL) { - log_error(0, "No authentication attribute in AH section for SA(%08x, %s->%s) in kernel_insert()", (SPI->SPI[0] << 24) + (SPI->SPI[1] << 16) + (SPI->SPI[2] << 8) + SPI->SPI[3], SPI->local_address, SPI->address); + log_error(0, "No authentication attribute in AH section for SA(%08x, %s->%s) in kernel_insert()", SPITOINT(SPI->SPI), SPI->local_address, SPI->address); return -1; } @@ -717,10 +1335,13 @@ kernel_insert_spi(struct stateob *st, struct spiob *SPI) secrets += offset; } - if (esp != NULL) + if (esp != NULL) { proto = IPPROTO_ESP; - else + SPI->flags |= SPI_ESP; + } else { proto = IPPROTO_AH; + SPI->flags &= ~SPI_ESP; + } /* Group the SPIs for User */ if (!(SPI->flags & SPI_OWNER) && ah != NULL && esp != NULL) { @@ -728,26 +1349,43 @@ kernel_insert_spi(struct stateob *st, struct spiob *SPI) log_error(0, "kernel_group_spi() in kernel_insert_spi()"); } - if (!(SPI->flags & SPI_OWNER)) + if (!(SPI->flags & SPI_OWNER)) { if (!(SPI->flags & SPI_NOTIFY) || vpn_mode) { if (kernel_enable_spi(SPI->isrc, SPI->ismask, SPI->idst, SPI->idmask, SPI->address, spi, proto, - ENABLE_FLAG_REPLACE|ENABLE_FLAG_LOCAL | - (vpn_mode ? ENABLE_FLAG_MODIFY : 0)) == -1) + /* ENABLE_FLAG_REPLACE|*/ SADB_SAFLAGS_X_LOCALFLOW | + (vpn_mode ? /*ENABLE_FLAG_MODIFY*/ : 0)) == -1) log_error(0, "kernel_enable_spi() in kernel_insert_spi()"); } else { /* * Inform the kernel that we obtained the requested SA */ - kernel_notify_result(st, SPI, proto); + kernel_notify_result(st, SPI, proto); } + } /* Is this what people call perfect forward security ? */ bzero(SPI->sessionkey, SPI->sessionkeysize); free(SPI->sessionkey); SPI->sessionkey = NULL; SPI->sessionkeysize = 0; + /* Bind the pair of SPI in the state object */ + if (SPI->flags & SPI_OWNER) + spi2 = spi_find(SPI->address, st->uSPI); + else + spi2 = spi_find(SPI->local_address, st->oSPI); + + if (!spi2) { + log_error(0, "kernel_insert_spi(): can not find second SPI"); + return 0; + } + + if (SPI->flags & SPI_OWNER) + kernel_bind_spis(SPI, spi2); + else + kernel_bind_spis(spi2, SPI); + return 1; } @@ -762,9 +1400,6 @@ kernel_insert_spi(struct stateob *st, struct spiob *SPI) int kernel_unlink_spi(struct spiob *ospi) { - int n, proto = 0; - attrib_t *attprop; - u_int32_t spi; u_int8_t *p, *ah, *esp; u_int16_t ahsize, espsize; @@ -777,9 +1412,9 @@ kernel_unlink_spi(struct spiob *ospi) AT_ESP_ATTRIB); get_attrib_section(ospi->attributes, ospi->attribsize, &ah, &ahsize, AT_AH_ATTRIB); - + if (esp != NULL) { - int flag = (vpn_mode ? ENABLE_FLAG_MODIFY : 0) | ENABLE_FLAG_LOCAL; + int flag = (vpn_mode ? /*ENABLE_FLAG_MODIFY*/ : 0) | SADB_SAFLAGS_X_LOCALFLOW; if (!(ospi->flags & SPI_OWNER) && kernel_disable_spi(ospi->isrc, ospi->ismask, ospi->idst, ospi->idmask, @@ -787,14 +1422,14 @@ kernel_unlink_spi(struct spiob *ospi) IPPROTO_ESP, flag) == -1) log_error(0, "kernel_disable_spi() in kernel_unlink_spi()"); - if (kernel_delete_spi(p, ospi->SPI, IPPROTO_ESP) == -1) + if (kernel_delete_spi(p, SPITOINT(ospi->SPI), IPPROTO_ESP) == -1) log_error(0, "kernel_delete_spi() in kernel_unlink_spi()"); } if (ah != NULL) { if (esp == NULL) { - int flag = (vpn_mode ? ENABLE_FLAG_MODIFY : 0) | - ENABLE_FLAG_LOCAL; + int flag = (vpn_mode ? /*ENABLE_FLAG_MODIFY*/ : 0) | + SADB_SAFLAGS_X_LOCALFLOW; if (!(ospi->flags & SPI_OWNER) && kernel_disable_spi(ospi->isrc, ospi->ismask, ospi->idst, ospi->idmask, @@ -803,7 +1438,7 @@ kernel_unlink_spi(struct spiob *ospi) log_error(0, "kernel_disable_spi() in kernel_unlink_spi()"); } - if (kernel_delete_spi(p, ospi->SPI, IPPROTO_AH) == -1) + if (kernel_delete_spi(p, SPITOINT(ospi->SPI), IPPROTO_AH) == -1) log_error(0, "kernel_delete_spi() in kernel_unlink_spi()"); } @@ -818,44 +1453,29 @@ kernel_unlink_spi(struct spiob *ospi) void kernel_handle_notify(int sd) { - struct encap_msghdr em; - int msglen; + struct sadb_msg *sres = (struct sadb_msg *)buffer; - if ((msglen = recvfrom(sd, (char *)&em, sizeof(em),0, NULL,0)) == -1) { - log_error(1, "recvfrom() in kernel_handle_notify()"); + if (!kernel_xf_read(regsd, buffer, BUFFER_SIZE, 0)) return; - } - - if (msglen != em.em_msglen) { - log_error(0, "message length incorrect in kernel_handle_notify(): got %d where it should be %d", msglen, em.em_msglen); - return; - } - - if (em.em_type != EMT_NOTIFY) { - log_error(0, "message type is not notify in kernel_handle_notify()"); - return; - } #ifdef DEBUG - printf("Received EMT_NOTIFY message: subtype %d\n", em.em_not_type); + kernel_debug(("Got PFKEYV2 message: type %d\n", sres->sadb_msg_type)); #endif - switch (em.em_not_type) { - case NOTIFY_SOFT_EXPIRE: - case NOTIFY_HARD_EXPIRE: - log_error(0, "Notify is an SA Expiration - not yet supported.\n"); + switch (sres->sadb_msg_type) { + case SADB_EXPIRE: + log_error(0, "PFKEYV2 SA Expiration - not yet supported.\n"); return; - case NOTIFY_REQUEST_SA: + case SADB_ACQUIRE: #ifdef DEBUG - printf("Notify SA Request for IP: %s, require %d\n", - inet_ntoa(em.em_not_dst), em.em_not_satype); + kernel_debug(("Got Notify SA Request (SADB_ACQUIRE)\n")); #endif - kernel_request_sa(&em); + kernel_request_sa(sres); break; default: - log_error(0, "Unknown notify message in kernel_handle_notify"); - return; - } + /* discard silently */ + return; + } } /* @@ -864,13 +1484,13 @@ kernel_handle_notify(int sd) */ int -kernel_request_sa(struct encap_msghdr *em) +kernel_request_sa(void *em /*struct encap_msghdr *em*/) { - struct stateob *st; +/* struct stateob *st; time_t tm; char *address = inet_ntoa(em->em_not_dst); - /* Try to find an already established exchange which is still valid */ + /#* Try to find an already established exchange which is still valid *#/ st = state_find(address); tm = time(NULL); @@ -878,34 +1498,34 @@ kernel_request_sa(struct encap_msghdr *em) st = state_find_next(st, address); if (st == NULL) { - /* No established exchange found, start a new one */ + /#* No established exchange found, start a new one *#/ if ((st = state_new()) == NULL) { log_error(0, "state_new() failed in kernel_request_sa() for remote ip %s", address); return (-1); } - /* Set up the state information */ + /#* Set up the state information *#/ strncpy(st->address, address, sizeof(st->address)-1); st->port = global_port; st->sport = em->em_not_sport; st->dport = em->em_not_dport; st->protocol = em->em_not_protocol; - /* + /#* * For states which were created by kernel notifies we wont * set up routes since other keying daemons might habe beaten * us in establishing SAs. The kernel has to decide which SA * will actually be routed. - */ + *#/ st->flags = IPSEC_NOTIFY; if (em->em_not_satype & NOTIFY_SATYPE_CONF) st->flags |= IPSEC_OPT_ENC; if (em->em_not_satype & NOTIFY_SATYPE_AUTH) st->flags |= IPSEC_OPT_AUTH; - /* XXX - handling of tunnel requests missing */ + /#* XXX - handling of tunnel requests missing *#/ if (start_exchange(global_socket, st, st->address, st->port) == -1) { log_error(0, "start_exchange() in kernel_request_sa() - informing kernel of failure"); - /* Inform kernel of our failure */ + /#* Inform kernel of our failure *#/ kernel_notify_result(st, NULL, 0); state_value_reset(st); free(st); @@ -913,11 +1533,12 @@ kernel_request_sa(struct encap_msghdr *em) } else state_insert(st); } else { - /* + /#* * We need different attributes for this exchange, send * an SPI_NEEDED message. - */ + *#/ } +*/ } /* @@ -929,7 +1550,8 @@ kernel_request_sa(struct encap_msghdr *em) void kernel_notify_result(struct stateob *st, struct spiob *spi, int proto) { - struct encap_msghdr em; + + /* struct encap_msghdr em; bzero((char *)&em, sizeof(em)); em.em_type = EMT_NOTIFY; @@ -951,5 +1573,5 @@ kernel_notify_result(struct stateob *st, struct spiob *spi, int proto) } if (!kernel_xf_set(&em)) - log_error(1, "kernel_xf_set() in kernel_notify_result()"); + log_error(1, "kernel_xf_set() in kernel_notify_result()"); */ } |