diff --git a/lib/libipsec/pfkey.c b/lib/libipsec/pfkey.c index fe035a96fb87..6c7649c5844f 100644 --- a/lib/libipsec/pfkey.c +++ b/lib/libipsec/pfkey.c @@ -1,2199 +1,2065 @@ /* $KAME: pfkey.c,v 1.46 2003/08/26 03:37:06 itojun Exp $ */ /*- * SPDX-License-Identifier: BSD-3-Clause * * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the project nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include "ipsec_strerror.h" #include "libpfkey.h" #define CALLOC(size, cast) (cast)calloc(1, (size)) static int findsupportedmap(int); static int setsupportedmap(struct sadb_supported *); static struct sadb_alg *findsupportedalg(u_int, u_int); static int pfkey_send_x1(int, u_int, u_int, u_int, struct sockaddr *, struct sockaddr *, u_int32_t, u_int32_t, u_int, caddr_t, u_int, u_int, u_int, u_int, u_int, u_int32_t, u_int32_t, u_int32_t, u_int32_t, u_int32_t); static int pfkey_send_x2(int, u_int, u_int, u_int, struct sockaddr *, struct sockaddr *, u_int32_t); static int pfkey_send_x3(int, u_int, u_int); static int pfkey_send_x4(int, u_int, struct sockaddr *, u_int, struct sockaddr *, u_int, u_int, u_int64_t, u_int64_t, char *, int, u_int32_t); static int pfkey_send_x5(int, u_int, u_int32_t); static caddr_t pfkey_setsadbmsg(caddr_t, caddr_t, u_int, u_int, u_int, u_int32_t, pid_t); static caddr_t pfkey_setsadbsa(caddr_t, caddr_t, u_int32_t, u_int, u_int, u_int, u_int32_t); static caddr_t pfkey_setsadbxreplay(caddr_t, caddr_t, uint32_t); static caddr_t pfkey_setsadbaddr(caddr_t, caddr_t, u_int, struct sockaddr *, u_int, u_int); static caddr_t pfkey_setsadbkey(caddr_t, caddr_t, u_int, caddr_t, u_int); static caddr_t pfkey_setsadblifetime(caddr_t, caddr_t, u_int, u_int32_t, u_int32_t, u_int32_t, u_int32_t); static caddr_t pfkey_setsadbxsa2(caddr_t, caddr_t, u_int32_t, u_int32_t); /* * make and search supported algorithm structure. */ static struct sadb_supported *ipsec_supported[] = { NULL, NULL, NULL, NULL }; static int supported_map[] = { SADB_SATYPE_AH, SADB_SATYPE_ESP, SADB_X_SATYPE_IPCOMP, SADB_X_SATYPE_TCPSIGNATURE }; static int -findsupportedmap(satype) - int satype; +findsupportedmap(int satype) { int i; for (i = 0; i < sizeof(supported_map)/sizeof(supported_map[0]); i++) if (supported_map[i] == satype) return i; return -1; } static struct sadb_alg * -findsupportedalg(satype, alg_id) - u_int satype, alg_id; +findsupportedalg(u_int satype, u_int alg_id) { int algno; int tlen; caddr_t p; /* validity check */ algno = findsupportedmap(satype); if (algno == -1) { __ipsec_errcode = EIPSEC_INVAL_ARGUMENT; return NULL; } if (ipsec_supported[algno] == NULL) { __ipsec_errcode = EIPSEC_DO_GET_SUPP_LIST; return NULL; } tlen = ipsec_supported[algno]->sadb_supported_len - sizeof(struct sadb_supported); p = (caddr_t)(ipsec_supported[algno] + 1); while (tlen > 0) { if (tlen < sizeof(struct sadb_alg)) { /* invalid format */ break; } if (((struct sadb_alg *)p)->sadb_alg_id == alg_id) return (struct sadb_alg *)p; tlen -= sizeof(struct sadb_alg); p += sizeof(struct sadb_alg); } __ipsec_errcode = EIPSEC_NOT_SUPPORTED; return NULL; } static int -setsupportedmap(sup) - struct sadb_supported *sup; +setsupportedmap(struct sadb_supported *sup) { struct sadb_supported **ipsup; switch (sup->sadb_supported_exttype) { case SADB_EXT_SUPPORTED_AUTH: ipsup = &ipsec_supported[findsupportedmap(SADB_SATYPE_AH)]; break; case SADB_EXT_SUPPORTED_ENCRYPT: ipsup = &ipsec_supported[findsupportedmap(SADB_SATYPE_ESP)]; break; default: __ipsec_errcode = EIPSEC_INVAL_SATYPE; return -1; } if (*ipsup) free(*ipsup); *ipsup = malloc(sup->sadb_supported_len); if (!*ipsup) { __ipsec_set_strerror(strerror(errno)); return -1; } memcpy(*ipsup, sup, sup->sadb_supported_len); return 0; } /* * check key length against algorithm specified. * This function is called with SADB_EXT_SUPPORTED_{AUTH,ENCRYPT} as the * augument, and only calls to ipsec_check_keylen2(); * keylen is the unit of bit. * OUT: * -1: invalid. * 0: valid. */ int -ipsec_check_keylen(supported, alg_id, keylen) - u_int supported; - u_int alg_id; - u_int keylen; +ipsec_check_keylen(u_int supported, u_int alg_id, u_int keylen) { int satype; /* validity check */ switch (supported) { case SADB_EXT_SUPPORTED_AUTH: satype = SADB_SATYPE_AH; break; case SADB_EXT_SUPPORTED_ENCRYPT: satype = SADB_SATYPE_ESP; break; default: __ipsec_errcode = EIPSEC_INVAL_ARGUMENT; return -1; } return ipsec_check_keylen2(satype, alg_id, keylen); } /* * check key length against algorithm specified. * satype is one of satype defined at pfkeyv2.h. * keylen is the unit of bit. * OUT: * -1: invalid. * 0: valid. */ int -ipsec_check_keylen2(satype, alg_id, keylen) - u_int satype; - u_int alg_id; - u_int keylen; +ipsec_check_keylen2(u_int satype, u_int alg_id, u_int keylen) { struct sadb_alg *alg; alg = findsupportedalg(satype, alg_id); if (!alg) return -1; if (keylen < alg->sadb_alg_minbits || keylen > alg->sadb_alg_maxbits) { __ipsec_errcode = EIPSEC_INVAL_KEYLEN; return -1; } __ipsec_errcode = EIPSEC_NO_ERROR; return 0; } /* * get max/min key length against algorithm specified. * satype is one of satype defined at pfkeyv2.h. * keylen is the unit of bit. * OUT: * -1: invalid. * 0: valid. */ int -ipsec_get_keylen(supported, alg_id, alg0) - u_int supported, alg_id; - struct sadb_alg *alg0; +ipsec_get_keylen(u_int supported, u_int alg_id, struct sadb_alg *alg0) { struct sadb_alg *alg; u_int satype; /* validity check */ if (!alg0) { __ipsec_errcode = EIPSEC_INVAL_ARGUMENT; return -1; } switch (supported) { case SADB_EXT_SUPPORTED_AUTH: satype = SADB_SATYPE_AH; break; case SADB_EXT_SUPPORTED_ENCRYPT: satype = SADB_SATYPE_ESP; break; default: __ipsec_errcode = EIPSEC_INVAL_ARGUMENT; return -1; } alg = findsupportedalg(satype, alg_id); if (!alg) return -1; memcpy(alg0, alg, sizeof(*alg0)); __ipsec_errcode = EIPSEC_NO_ERROR; return 0; } /* * set the rate for SOFT lifetime against HARD one. * If rate is more than 100 or equal to zero, then set to 100. */ static u_int soft_lifetime_allocations_rate = PFKEY_SOFT_LIFETIME_RATE; static u_int soft_lifetime_bytes_rate = PFKEY_SOFT_LIFETIME_RATE; static u_int soft_lifetime_addtime_rate = PFKEY_SOFT_LIFETIME_RATE; static u_int soft_lifetime_usetime_rate = PFKEY_SOFT_LIFETIME_RATE; u_int -pfkey_set_softrate(type, rate) - u_int type, rate; +pfkey_set_softrate(u_int type, u_int rate) { __ipsec_errcode = EIPSEC_NO_ERROR; if (rate > 100 || rate == 0) rate = 100; switch (type) { case SADB_X_LIFETIME_ALLOCATIONS: soft_lifetime_allocations_rate = rate; return 0; case SADB_X_LIFETIME_BYTES: soft_lifetime_bytes_rate = rate; return 0; case SADB_X_LIFETIME_ADDTIME: soft_lifetime_addtime_rate = rate; return 0; case SADB_X_LIFETIME_USETIME: soft_lifetime_usetime_rate = rate; return 0; } __ipsec_errcode = EIPSEC_INVAL_ARGUMENT; return 1; } /* * get current rate for SOFT lifetime against HARD one. * ATTENTION: ~0 is returned if invalid type was passed. */ u_int -pfkey_get_softrate(type) - u_int type; +pfkey_get_softrate(u_int type) { switch (type) { case SADB_X_LIFETIME_ALLOCATIONS: return soft_lifetime_allocations_rate; case SADB_X_LIFETIME_BYTES: return soft_lifetime_bytes_rate; case SADB_X_LIFETIME_ADDTIME: return soft_lifetime_addtime_rate; case SADB_X_LIFETIME_USETIME: return soft_lifetime_usetime_rate; } return ~0; } /* * sending SADB_GETSPI message to the kernel. * OUT: * positive: success and return length sent. * -1 : error occurred, and set errno. */ int -pfkey_send_getspi(so, satype, mode, src, dst, min, max, reqid, seq) - int so; - u_int satype, mode; - struct sockaddr *src, *dst; - u_int32_t min, max, reqid, seq; +pfkey_send_getspi(int so, u_int satype, u_int mode, struct sockaddr *src, + struct sockaddr *dst, u_int32_t min, uint32_t max, uint32_t reqid, + uint32_t seq) { struct sadb_msg *newmsg; caddr_t ep; int len; int need_spirange = 0; caddr_t p; int plen; /* validity check */ if (src == NULL || dst == NULL) { __ipsec_errcode = EIPSEC_INVAL_ARGUMENT; return -1; } if (src->sa_family != dst->sa_family) { __ipsec_errcode = EIPSEC_FAMILY_MISMATCH; return -1; } if (min > max || (min > 0 && min <= 255)) { __ipsec_errcode = EIPSEC_INVAL_SPI; return -1; } switch (src->sa_family) { case AF_INET: plen = sizeof(struct in_addr) << 3; break; case AF_INET6: plen = sizeof(struct in6_addr) << 3; break; default: __ipsec_errcode = EIPSEC_INVAL_FAMILY; return -1; } /* create new sadb_msg to send. */ len = sizeof(struct sadb_msg) + sizeof(struct sadb_x_sa2) + sizeof(struct sadb_address) + PFKEY_ALIGN8(src->sa_len) + sizeof(struct sadb_address) + PFKEY_ALIGN8(dst->sa_len); if (min > 255 && max < ~0) { need_spirange++; len += sizeof(struct sadb_spirange); } if ((newmsg = CALLOC(len, struct sadb_msg *)) == NULL) { __ipsec_set_strerror(strerror(errno)); return -1; } ep = ((caddr_t)newmsg) + len; p = pfkey_setsadbmsg((caddr_t)newmsg, ep, SADB_GETSPI, len, satype, seq, getpid()); if (!p) { free(newmsg); return -1; } p = pfkey_setsadbxsa2(p, ep, mode, reqid); if (!p) { free(newmsg); return -1; } /* set sadb_address for source */ p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_SRC, src, plen, IPSEC_ULPROTO_ANY); if (!p) { free(newmsg); return -1; } /* set sadb_address for destination */ p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_DST, dst, plen, IPSEC_ULPROTO_ANY); if (!p) { free(newmsg); return -1; } /* processing spi range */ if (need_spirange) { struct sadb_spirange spirange; if (p + sizeof(spirange) > ep) { free(newmsg); return -1; } memset(&spirange, 0, sizeof(spirange)); spirange.sadb_spirange_len = PFKEY_UNIT64(sizeof(spirange)); spirange.sadb_spirange_exttype = SADB_EXT_SPIRANGE; spirange.sadb_spirange_min = min; spirange.sadb_spirange_max = max; memcpy(p, &spirange, sizeof(spirange)); p += sizeof(spirange); } if (p != ep) { free(newmsg); return -1; } /* send message */ len = pfkey_send(so, newmsg, len); free(newmsg); if (len < 0) return -1; __ipsec_errcode = EIPSEC_NO_ERROR; return len; } /* * sending SADB_UPDATE message to the kernel. * The length of key material is a_keylen + e_keylen. * OUT: * positive: success and return length sent. * -1 : error occurred, and set errno. */ int -pfkey_send_update(so, satype, mode, src, dst, spi, reqid, wsize, - keymat, e_type, e_keylen, a_type, a_keylen, flags, - l_alloc, l_bytes, l_addtime, l_usetime, seq) - int so; - u_int satype, mode, wsize; - struct sockaddr *src, *dst; - u_int32_t spi, reqid; - caddr_t keymat; - u_int e_type, e_keylen, a_type, a_keylen, flags; - u_int32_t l_alloc; - u_int64_t l_bytes, l_addtime, l_usetime; - u_int32_t seq; +pfkey_send_update(int so, u_int satype, u_int mode, struct sockaddr *src, + struct sockaddr *dst, u_int32_t spi, u_int32_t reqid, u_int wsize, + caddr_t keymat, u_int e_type, u_int e_keylen, u_int a_type, u_int a_keylen, + u_int flags, u_int32_t l_alloc, u_int64_t l_bytes, u_int64_t l_addtime, + u_int64_t l_usetime, u_int32_t seq) { int len; if ((len = pfkey_send_x1(so, SADB_UPDATE, satype, mode, src, dst, spi, reqid, wsize, keymat, e_type, e_keylen, a_type, a_keylen, flags, l_alloc, l_bytes, l_addtime, l_usetime, seq)) < 0) return -1; return len; } /* * sending SADB_ADD message to the kernel. * The length of key material is a_keylen + e_keylen. * OUT: * positive: success and return length sent. * -1 : error occurred, and set errno. */ int -pfkey_send_add(so, satype, mode, src, dst, spi, reqid, wsize, - keymat, e_type, e_keylen, a_type, a_keylen, flags, - l_alloc, l_bytes, l_addtime, l_usetime, seq) - int so; - u_int satype, mode, wsize; - struct sockaddr *src, *dst; - u_int32_t spi, reqid; - caddr_t keymat; - u_int e_type, e_keylen, a_type, a_keylen, flags; - u_int32_t l_alloc; - u_int64_t l_bytes, l_addtime, l_usetime; - u_int32_t seq; +pfkey_send_add(int so, u_int satype, u_int mode, struct sockaddr *src, + struct sockaddr *dst, u_int32_t spi, u_int32_t reqid, u_int wsize, + caddr_t keymat, u_int e_type, u_int e_keylen, u_int a_type, u_int a_keylen, + u_int flags, u_int32_t l_alloc, u_int64_t l_bytes, u_int64_t l_addtime, + u_int64_t l_usetime, u_int32_t seq) { int len; if ((len = pfkey_send_x1(so, SADB_ADD, satype, mode, src, dst, spi, reqid, wsize, keymat, e_type, e_keylen, a_type, a_keylen, flags, l_alloc, l_bytes, l_addtime, l_usetime, seq)) < 0) return -1; return len; } /* * sending SADB_DELETE message to the kernel. * OUT: * positive: success and return length sent. * -1 : error occurred, and set errno. */ int -pfkey_send_delete(so, satype, mode, src, dst, spi) - int so; - u_int satype, mode; - struct sockaddr *src, *dst; - u_int32_t spi; +pfkey_send_delete(int so, u_int satype, u_int mode, struct sockaddr *src, + struct sockaddr *dst, u_int32_t spi) { int len; if ((len = pfkey_send_x2(so, SADB_DELETE, satype, mode, src, dst, spi)) < 0) return -1; return len; } /* * sending SADB_DELETE without spi to the kernel. This is * the "delete all" request (an extension also present in * Solaris). * * OUT: * positive: success and return length sent * -1 : error occurred, and set errno */ int -pfkey_send_delete_all(so, satype, mode, src, dst) - int so; - u_int satype, mode; - struct sockaddr *src, *dst; +pfkey_send_delete_all(int so, u_int satype, u_int mode, struct sockaddr *src, + struct sockaddr *dst) { struct sadb_msg *newmsg; int len; caddr_t p; int plen; caddr_t ep; /* validity check */ if (src == NULL || dst == NULL) { __ipsec_errcode = EIPSEC_INVAL_ARGUMENT; return -1; } if (src->sa_family != dst->sa_family) { __ipsec_errcode = EIPSEC_FAMILY_MISMATCH; return -1; } switch (src->sa_family) { case AF_INET: plen = sizeof(struct in_addr) << 3; break; case AF_INET6: plen = sizeof(struct in6_addr) << 3; break; default: __ipsec_errcode = EIPSEC_INVAL_FAMILY; return -1; } /* create new sadb_msg to reply. */ len = sizeof(struct sadb_msg) + sizeof(struct sadb_address) + PFKEY_ALIGN8(src->sa_len) + sizeof(struct sadb_address) + PFKEY_ALIGN8(dst->sa_len); if ((newmsg = CALLOC(len, struct sadb_msg *)) == NULL) { __ipsec_set_strerror(strerror(errno)); return -1; } ep = ((caddr_t)newmsg) + len; p = pfkey_setsadbmsg((caddr_t)newmsg, ep, SADB_DELETE, len, satype, 0, getpid()); if (!p) { free(newmsg); return -1; } p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_SRC, src, plen, IPSEC_ULPROTO_ANY); if (!p) { free(newmsg); return -1; } p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_DST, dst, plen, IPSEC_ULPROTO_ANY); if (!p || p != ep) { free(newmsg); return -1; } /* send message */ len = pfkey_send(so, newmsg, len); free(newmsg); if (len < 0) return -1; __ipsec_errcode = EIPSEC_NO_ERROR; return len; } /* * sending SADB_GET message to the kernel. * OUT: * positive: success and return length sent. * -1 : error occurred, and set errno. */ int -pfkey_send_get(so, satype, mode, src, dst, spi) - int so; - u_int satype, mode; - struct sockaddr *src, *dst; - u_int32_t spi; +pfkey_send_get(int so, u_int satype, u_int mode, struct sockaddr *src, + struct sockaddr *dst, u_int32_t spi) { int len; if ((len = pfkey_send_x2(so, SADB_GET, satype, mode, src, dst, spi)) < 0) return -1; return len; } /* * sending SADB_REGISTER message to the kernel. * OUT: * positive: success and return length sent. * -1 : error occurred, and set errno. */ int -pfkey_send_register(so, satype) - int so; - u_int satype; +pfkey_send_register(int so, u_int satype) { int len, algno; if (satype == SADB_SATYPE_UNSPEC) { for (algno = 0; algno < sizeof(supported_map)/sizeof(supported_map[0]); algno++) { if (ipsec_supported[algno]) { free(ipsec_supported[algno]); ipsec_supported[algno] = NULL; } } } else { algno = findsupportedmap(satype); if (algno == -1) { __ipsec_errcode = EIPSEC_INVAL_ARGUMENT; return -1; } if (ipsec_supported[algno]) { free(ipsec_supported[algno]); ipsec_supported[algno] = NULL; } } if ((len = pfkey_send_x3(so, SADB_REGISTER, satype)) < 0) return -1; return len; } /* * receiving SADB_REGISTER message from the kernel, and copy buffer for * sadb_supported returned into ipsec_supported. * OUT: * 0: success and return length sent. * -1: error occurred, and set errno. */ int -pfkey_recv_register(so) - int so; +pfkey_recv_register(int so) { pid_t pid = getpid(); struct sadb_msg *newmsg; int error = -1; /* receive message */ for (;;) { if ((newmsg = pfkey_recv(so)) == NULL) return -1; if (newmsg->sadb_msg_type == SADB_REGISTER && newmsg->sadb_msg_pid == pid) break; free(newmsg); } /* check and fix */ newmsg->sadb_msg_len = PFKEY_UNUNIT64(newmsg->sadb_msg_len); error = pfkey_set_supported(newmsg, newmsg->sadb_msg_len); free(newmsg); if (error == 0) __ipsec_errcode = EIPSEC_NO_ERROR; return error; } /* * receiving SADB_REGISTER message from the kernel, and copy buffer for * sadb_supported returned into ipsec_supported. * NOTE: sadb_msg_len must be host order. * IN: * tlen: msg length, it's to makeing sure. * OUT: * 0: success and return length sent. * -1: error occurred, and set errno. */ int -pfkey_set_supported(msg, tlen) - struct sadb_msg *msg; - int tlen; +pfkey_set_supported(struct sadb_msg *msg, int tlen) { struct sadb_supported *sup; caddr_t p; caddr_t ep; /* validity */ if (msg->sadb_msg_len != tlen) { __ipsec_errcode = EIPSEC_INVAL_ARGUMENT; return -1; } p = (caddr_t)msg; ep = p + tlen; p += sizeof(struct sadb_msg); while (p < ep) { sup = (struct sadb_supported *)p; if (ep < p + sizeof(*sup) || PFKEY_EXTLEN(sup) < sizeof(*sup) || ep < p + sup->sadb_supported_len) { /* invalid format */ break; } switch (sup->sadb_supported_exttype) { case SADB_EXT_SUPPORTED_AUTH: case SADB_EXT_SUPPORTED_ENCRYPT: break; default: __ipsec_errcode = EIPSEC_INVAL_SATYPE; return -1; } /* fixed length */ sup->sadb_supported_len = PFKEY_EXTLEN(sup); /* set supported map */ if (setsupportedmap(sup) != 0) return -1; p += sup->sadb_supported_len; } if (p != ep) { __ipsec_errcode = EIPSEC_INVAL_SATYPE; return -1; } __ipsec_errcode = EIPSEC_NO_ERROR; return 0; } /* * sending SADB_FLUSH message to the kernel. * OUT: * positive: success and return length sent. * -1 : error occurred, and set errno. */ int -pfkey_send_flush(so, satype) - int so; - u_int satype; +pfkey_send_flush(int so, u_int satype) { int len; if ((len = pfkey_send_x3(so, SADB_FLUSH, satype)) < 0) return -1; return len; } /* * sending SADB_DUMP message to the kernel. * OUT: * positive: success and return length sent. * -1 : error occurred, and set errno. */ int -pfkey_send_dump(so, satype) - int so; - u_int satype; +pfkey_send_dump(int so, u_int satype) { int len; if ((len = pfkey_send_x3(so, SADB_DUMP, satype)) < 0) return -1; return len; } /* * sending SADB_X_PROMISC message to the kernel. * NOTE that this function handles promisc mode toggle only. * IN: * flag: set promisc off if zero, set promisc on if non-zero. * OUT: * positive: success and return length sent. * -1 : error occurred, and set errno. * 0 : error occurred, and set errno. * others: a pointer to new allocated buffer in which supported * algorithms is. */ int -pfkey_send_promisc_toggle(so, flag) - int so; - int flag; +pfkey_send_promisc_toggle(int so, int flag) { int len; if ((len = pfkey_send_x3(so, SADB_X_PROMISC, (flag ? 1 : 0))) < 0) return -1; return len; } /* * sending SADB_X_SPDADD message to the kernel. * OUT: * positive: success and return length sent. * -1 : error occurred, and set errno. */ int -pfkey_send_spdadd(so, src, prefs, dst, prefd, proto, policy, policylen, seq) - int so; - struct sockaddr *src, *dst; - u_int prefs, prefd, proto; - caddr_t policy; - int policylen; - u_int32_t seq; +pfkey_send_spdadd(int so, struct sockaddr *src, u_int prefs, + struct sockaddr *dst, u_int prefd, u_int proto, caddr_t policy, + int policylen, u_int32_t seq) { int len; if ((len = pfkey_send_x4(so, SADB_X_SPDADD, src, prefs, dst, prefd, proto, 0, 0, policy, policylen, seq)) < 0) return -1; return len; } /* * sending SADB_X_SPDADD message to the kernel. * OUT: * positive: success and return length sent. * -1 : error occurred, and set errno. */ int -pfkey_send_spdadd2(so, src, prefs, dst, prefd, proto, ltime, vtime, - policy, policylen, seq) - int so; - struct sockaddr *src, *dst; - u_int prefs, prefd, proto; - u_int64_t ltime, vtime; - caddr_t policy; - int policylen; - u_int32_t seq; +pfkey_send_spdadd2(int so, struct sockaddr *src, u_int prefs, + struct sockaddr *dst, u_int prefd, u_int proto, u_int64_t ltime, + u_int64_t vtime, caddr_t policy, int policylen, u_int32_t seq) { int len; if ((len = pfkey_send_x4(so, SADB_X_SPDADD, src, prefs, dst, prefd, proto, ltime, vtime, policy, policylen, seq)) < 0) return -1; return len; } /* * sending SADB_X_SPDUPDATE message to the kernel. * OUT: * positive: success and return length sent. * -1 : error occurred, and set errno. */ int -pfkey_send_spdupdate(so, src, prefs, dst, prefd, proto, policy, policylen, seq) - int so; - struct sockaddr *src, *dst; - u_int prefs, prefd, proto; - caddr_t policy; - int policylen; - u_int32_t seq; +pfkey_send_spdupdate(int so, struct sockaddr *src, u_int prefs, + struct sockaddr *dst, u_int prefd, u_int proto, caddr_t policy, + int policylen, u_int32_t seq) { int len; if ((len = pfkey_send_x4(so, SADB_X_SPDUPDATE, src, prefs, dst, prefd, proto, 0, 0, policy, policylen, seq)) < 0) return -1; return len; } /* * sending SADB_X_SPDUPDATE message to the kernel. * OUT: * positive: success and return length sent. * -1 : error occurred, and set errno. */ int -pfkey_send_spdupdate2(so, src, prefs, dst, prefd, proto, ltime, vtime, - policy, policylen, seq) - int so; - struct sockaddr *src, *dst; - u_int prefs, prefd, proto; - u_int64_t ltime, vtime; - caddr_t policy; - int policylen; - u_int32_t seq; +pfkey_send_spdupdate2(int so, struct sockaddr *src, u_int prefs, + struct sockaddr *dst, u_int prefd, u_int proto, u_int64_t ltime, + u_int64_t vtime, caddr_t policy, int policylen, u_int32_t seq) { int len; if ((len = pfkey_send_x4(so, SADB_X_SPDUPDATE, src, prefs, dst, prefd, proto, ltime, vtime, policy, policylen, seq)) < 0) return -1; return len; } /* * sending SADB_X_SPDDELETE message to the kernel. * OUT: * positive: success and return length sent. * -1 : error occurred, and set errno. */ int -pfkey_send_spddelete(so, src, prefs, dst, prefd, proto, policy, policylen, seq) - int so; - struct sockaddr *src, *dst; - u_int prefs, prefd, proto; - caddr_t policy; - int policylen; - u_int32_t seq; +pfkey_send_spddelete(int so, struct sockaddr *src, u_int prefs, + struct sockaddr *dst, u_int prefd, u_int proto, caddr_t policy, + int policylen, u_int32_t seq) { int len; if (policylen != sizeof(struct sadb_x_policy)) { __ipsec_errcode = EIPSEC_INVAL_ARGUMENT; return -1; } if ((len = pfkey_send_x4(so, SADB_X_SPDDELETE, src, prefs, dst, prefd, proto, 0, 0, policy, policylen, seq)) < 0) return -1; return len; } /* * sending SADB_X_SPDDELETE message to the kernel. * OUT: * positive: success and return length sent. * -1 : error occurred, and set errno. */ int -pfkey_send_spddelete2(so, spid) - int so; - u_int32_t spid; +pfkey_send_spddelete2(int so, u_int32_t spid) { int len; if ((len = pfkey_send_x5(so, SADB_X_SPDDELETE2, spid)) < 0) return -1; return len; } /* * sending SADB_X_SPDGET message to the kernel. * OUT: * positive: success and return length sent. * -1 : error occurred, and set errno. */ int -pfkey_send_spdget(so, spid) - int so; - u_int32_t spid; +pfkey_send_spdget(int so, u_int32_t spid) { int len; if ((len = pfkey_send_x5(so, SADB_X_SPDGET, spid)) < 0) return -1; return len; } /* * sending SADB_X_SPDSETIDX message to the kernel. * OUT: * positive: success and return length sent. * -1 : error occurred, and set errno. */ int -pfkey_send_spdsetidx(so, src, prefs, dst, prefd, proto, policy, policylen, seq) - int so; - struct sockaddr *src, *dst; - u_int prefs, prefd, proto; - caddr_t policy; - int policylen; - u_int32_t seq; +pfkey_send_spdsetidx(int so, struct sockaddr *src, u_int prefs, + struct sockaddr *dst, u_int prefd, u_int proto, caddr_t policy, + int policylen, u_int32_t seq) { int len; if (policylen != sizeof(struct sadb_x_policy)) { __ipsec_errcode = EIPSEC_INVAL_ARGUMENT; return -1; } if ((len = pfkey_send_x4(so, SADB_X_SPDSETIDX, src, prefs, dst, prefd, proto, 0, 0, policy, policylen, seq)) < 0) return -1; return len; } /* * sending SADB_SPDFLUSH message to the kernel. * OUT: * positive: success and return length sent. * -1 : error occurred, and set errno. */ int -pfkey_send_spdflush(so) - int so; +pfkey_send_spdflush(int so) { int len; if ((len = pfkey_send_x3(so, SADB_X_SPDFLUSH, SADB_SATYPE_UNSPEC)) < 0) return -1; return len; } /* * sending SADB_SPDDUMP message to the kernel. * OUT: * positive: success and return length sent. * -1 : error occurred, and set errno. */ int -pfkey_send_spddump(so) - int so; +pfkey_send_spddump(int so) { int len; if ((len = pfkey_send_x3(so, SADB_X_SPDDUMP, SADB_SATYPE_UNSPEC)) < 0) return -1; return len; } /* sending SADB_ADD or SADB_UPDATE message to the kernel */ static int -pfkey_send_x1(so, type, satype, mode, src, dst, spi, reqid, wsize, - keymat, e_type, e_keylen, a_type, a_keylen, flags, - l_alloc, l_bytes, l_addtime, l_usetime, seq) - int so; - u_int type, satype, mode; - struct sockaddr *src, *dst; - u_int32_t spi, reqid; - u_int wsize; - caddr_t keymat; - u_int e_type, e_keylen, a_type, a_keylen, flags; - u_int32_t l_alloc, l_bytes, l_addtime, l_usetime, seq; +pfkey_send_x1(int so, u_int type, u_int satype, u_int mode, + struct sockaddr *src, struct sockaddr *dst, u_int32_t spi, u_int32_t reqid, + u_int wsize, caddr_t keymat, u_int e_type, u_int e_keylen, u_int a_type, + u_int a_keylen, u_int flags, u_int32_t l_alloc, u_int32_t l_bytes, + u_int32_t l_addtime, u_int32_t l_usetime, u_int32_t seq) { struct sadb_msg *newmsg; int len; caddr_t p; int plen; caddr_t ep; /* validity check */ if (src == NULL || dst == NULL) { __ipsec_errcode = EIPSEC_INVAL_ARGUMENT; return -1; } if (src->sa_family != dst->sa_family) { __ipsec_errcode = EIPSEC_FAMILY_MISMATCH; return -1; } switch (src->sa_family) { case AF_INET: plen = sizeof(struct in_addr) << 3; break; case AF_INET6: plen = sizeof(struct in6_addr) << 3; break; default: __ipsec_errcode = EIPSEC_INVAL_FAMILY; return -1; } switch (satype) { case SADB_SATYPE_ESP: if (e_type == SADB_EALG_NONE) { __ipsec_errcode = EIPSEC_NO_ALGS; return -1; } break; case SADB_SATYPE_AH: if (e_type != SADB_EALG_NONE) { __ipsec_errcode = EIPSEC_INVAL_ALGS; return -1; } if (a_type == SADB_AALG_NONE) { __ipsec_errcode = EIPSEC_NO_ALGS; return -1; } break; case SADB_X_SATYPE_IPCOMP: if (e_type == SADB_X_CALG_NONE) { __ipsec_errcode = EIPSEC_INVAL_ALGS; return -1; } if (a_type != SADB_AALG_NONE) { __ipsec_errcode = EIPSEC_NO_ALGS; return -1; } break; case SADB_X_SATYPE_TCPSIGNATURE: if (e_type != SADB_EALG_NONE) { __ipsec_errcode = EIPSEC_INVAL_ALGS; return -1; } if (a_type != SADB_X_AALG_TCP_MD5) { __ipsec_errcode = EIPSEC_INVAL_ALGS; return -1; } break; default: __ipsec_errcode = EIPSEC_INVAL_SATYPE; return -1; } /* create new sadb_msg to reply. */ len = sizeof(struct sadb_msg) + sizeof(struct sadb_sa) + sizeof(struct sadb_x_sa2) + sizeof(struct sadb_address) + PFKEY_ALIGN8(src->sa_len) + sizeof(struct sadb_address) + PFKEY_ALIGN8(dst->sa_len) + sizeof(struct sadb_lifetime) + sizeof(struct sadb_lifetime); if (wsize > UINT8_MAX) { if (wsize > (UINT32_MAX - 32) >> 3) { __ipsec_errcode = EIPSEC_INVAL_ARGUMENT; return (-1); } len += sizeof(struct sadb_x_sa_replay); } if (e_type != SADB_EALG_NONE) len += (sizeof(struct sadb_key) + PFKEY_ALIGN8(e_keylen)); if (a_type != SADB_AALG_NONE) len += (sizeof(struct sadb_key) + PFKEY_ALIGN8(a_keylen)); if ((newmsg = CALLOC(len, struct sadb_msg *)) == NULL) { __ipsec_set_strerror(strerror(errno)); return -1; } ep = ((caddr_t)newmsg) + len; p = pfkey_setsadbmsg((caddr_t)newmsg, ep, type, len, satype, seq, getpid()); if (!p) { free(newmsg); return -1; } p = pfkey_setsadbsa(p, ep, spi, wsize, a_type, e_type, flags); if (!p) { free(newmsg); return -1; } p = pfkey_setsadbxsa2(p, ep, mode, reqid); if (!p) { free(newmsg); return -1; } if (wsize > UINT8_MAX) { p = pfkey_setsadbxreplay(p, ep, wsize); if (!p) { free(newmsg); return (-1); } } p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_SRC, src, plen, IPSEC_ULPROTO_ANY); if (!p) { free(newmsg); return -1; } p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_DST, dst, plen, IPSEC_ULPROTO_ANY); if (!p) { free(newmsg); return -1; } if (e_type != SADB_EALG_NONE) { p = pfkey_setsadbkey(p, ep, SADB_EXT_KEY_ENCRYPT, keymat, e_keylen); if (!p) { free(newmsg); return -1; } } if (a_type != SADB_AALG_NONE) { p = pfkey_setsadbkey(p, ep, SADB_EXT_KEY_AUTH, keymat + e_keylen, a_keylen); if (!p) { free(newmsg); return -1; } } /* set sadb_lifetime for destination */ p = pfkey_setsadblifetime(p, ep, SADB_EXT_LIFETIME_HARD, l_alloc, l_bytes, l_addtime, l_usetime); if (!p) { free(newmsg); return -1; } p = pfkey_setsadblifetime(p, ep, SADB_EXT_LIFETIME_SOFT, l_alloc, l_bytes, l_addtime, l_usetime); if (!p || p != ep) { free(newmsg); return -1; } /* send message */ len = pfkey_send(so, newmsg, len); free(newmsg); if (len < 0) return -1; __ipsec_errcode = EIPSEC_NO_ERROR; return len; } /* sending SADB_DELETE or SADB_GET message to the kernel */ static int -pfkey_send_x2(so, type, satype, mode, src, dst, spi) - int so; - u_int type, satype, mode; - struct sockaddr *src, *dst; - u_int32_t spi; +pfkey_send_x2(int so, u_int type, u_int satype, u_int mode, + struct sockaddr *src, struct sockaddr *dst, u_int32_t spi) { struct sadb_msg *newmsg; int len; caddr_t p; int plen; caddr_t ep; /* validity check */ if (src == NULL || dst == NULL) { __ipsec_errcode = EIPSEC_INVAL_ARGUMENT; return -1; } if (src->sa_family != dst->sa_family) { __ipsec_errcode = EIPSEC_FAMILY_MISMATCH; return -1; } switch (src->sa_family) { case AF_INET: plen = sizeof(struct in_addr) << 3; break; case AF_INET6: plen = sizeof(struct in6_addr) << 3; break; default: __ipsec_errcode = EIPSEC_INVAL_FAMILY; return -1; } /* create new sadb_msg to reply. */ len = sizeof(struct sadb_msg) + sizeof(struct sadb_sa) + sizeof(struct sadb_address) + PFKEY_ALIGN8(src->sa_len) + sizeof(struct sadb_address) + PFKEY_ALIGN8(dst->sa_len); if ((newmsg = CALLOC(len, struct sadb_msg *)) == NULL) { __ipsec_set_strerror(strerror(errno)); return -1; } ep = ((caddr_t)newmsg) + len; p = pfkey_setsadbmsg((caddr_t)newmsg, ep, type, len, satype, 0, getpid()); if (!p) { free(newmsg); return -1; } p = pfkey_setsadbsa(p, ep, spi, 0, 0, 0, 0); if (!p) { free(newmsg); return -1; } p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_SRC, src, plen, IPSEC_ULPROTO_ANY); if (!p) { free(newmsg); return -1; } p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_DST, dst, plen, IPSEC_ULPROTO_ANY); if (!p || p != ep) { free(newmsg); return -1; } /* send message */ len = pfkey_send(so, newmsg, len); free(newmsg); if (len < 0) return -1; __ipsec_errcode = EIPSEC_NO_ERROR; return len; } /* * sending SADB_REGISTER, SADB_FLUSH, SADB_DUMP or SADB_X_PROMISC message * to the kernel */ static int -pfkey_send_x3(so, type, satype) - int so; - u_int type, satype; +pfkey_send_x3(int so, u_int type, u_int satype) { struct sadb_msg *newmsg; int len; caddr_t p; caddr_t ep; /* validity check */ switch (type) { case SADB_X_PROMISC: if (satype != 0 && satype != 1) { __ipsec_errcode = EIPSEC_INVAL_SATYPE; return -1; } break; default: switch (satype) { case SADB_SATYPE_UNSPEC: case SADB_SATYPE_AH: case SADB_SATYPE_ESP: case SADB_X_SATYPE_IPCOMP: case SADB_X_SATYPE_TCPSIGNATURE: break; default: __ipsec_errcode = EIPSEC_INVAL_SATYPE; return -1; } } /* create new sadb_msg to send. */ len = sizeof(struct sadb_msg); if ((newmsg = CALLOC(len, struct sadb_msg *)) == NULL) { __ipsec_set_strerror(strerror(errno)); return -1; } ep = ((caddr_t)newmsg) + len; p = pfkey_setsadbmsg((caddr_t)newmsg, ep, type, len, satype, 0, getpid()); if (!p || p != ep) { free(newmsg); return -1; } /* send message */ len = pfkey_send(so, newmsg, len); free(newmsg); if (len < 0) return -1; __ipsec_errcode = EIPSEC_NO_ERROR; return len; } /* sending SADB_X_SPDADD message to the kernel */ static int -pfkey_send_x4(so, type, src, prefs, dst, prefd, proto, - ltime, vtime, policy, policylen, seq) - int so; - struct sockaddr *src, *dst; - u_int type, prefs, prefd, proto; - u_int64_t ltime, vtime; - char *policy; - int policylen; - u_int32_t seq; +pfkey_send_x4(int so, u_int type, struct sockaddr *src, u_int prefs, + struct sockaddr *dst, u_int prefd, u_int proto, u_int64_t ltime, + u_int64_t vtime, char *policy, int policylen, u_int32_t seq) { struct sadb_msg *newmsg; int len; caddr_t p; int plen; caddr_t ep; /* validity check */ if (src == NULL || dst == NULL) { __ipsec_errcode = EIPSEC_INVAL_ARGUMENT; return -1; } if (src->sa_family != dst->sa_family) { __ipsec_errcode = EIPSEC_FAMILY_MISMATCH; return -1; } switch (src->sa_family) { case AF_INET: plen = sizeof(struct in_addr) << 3; break; case AF_INET6: plen = sizeof(struct in6_addr) << 3; break; default: __ipsec_errcode = EIPSEC_INVAL_FAMILY; return -1; } if (prefs > plen || prefd > plen) { __ipsec_errcode = EIPSEC_INVAL_PREFIXLEN; return -1; } /* create new sadb_msg to reply. */ len = sizeof(struct sadb_msg) + sizeof(struct sadb_address) + PFKEY_ALIGN8(src->sa_len) + sizeof(struct sadb_address) + PFKEY_ALIGN8(src->sa_len) + sizeof(struct sadb_lifetime) + policylen; if ((newmsg = CALLOC(len, struct sadb_msg *)) == NULL) { __ipsec_set_strerror(strerror(errno)); return -1; } ep = ((caddr_t)newmsg) + len; p = pfkey_setsadbmsg((caddr_t)newmsg, ep, type, len, SADB_SATYPE_UNSPEC, seq, getpid()); if (!p) { free(newmsg); return -1; } p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_SRC, src, prefs, proto); if (!p) { free(newmsg); return -1; } p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_DST, dst, prefd, proto); if (!p) { free(newmsg); return -1; } p = pfkey_setsadblifetime(p, ep, SADB_EXT_LIFETIME_HARD, 0, 0, ltime, vtime); if (!p || p + policylen != ep) { free(newmsg); return -1; } memcpy(p, policy, policylen); /* send message */ len = pfkey_send(so, newmsg, len); free(newmsg); if (len < 0) return -1; __ipsec_errcode = EIPSEC_NO_ERROR; return len; } /* sending SADB_X_SPDGET or SADB_X_SPDDELETE message to the kernel */ static int -pfkey_send_x5(so, type, spid) - int so; - u_int type; - u_int32_t spid; +pfkey_send_x5(int so, u_int type, u_int32_t spid) { struct sadb_msg *newmsg; struct sadb_x_policy xpl; int len; caddr_t p; caddr_t ep; /* create new sadb_msg to reply. */ len = sizeof(struct sadb_msg) + sizeof(xpl); if ((newmsg = CALLOC(len, struct sadb_msg *)) == NULL) { __ipsec_set_strerror(strerror(errno)); return -1; } ep = ((caddr_t)newmsg) + len; p = pfkey_setsadbmsg((caddr_t)newmsg, ep, type, len, SADB_SATYPE_UNSPEC, 0, getpid()); if (!p) { free(newmsg); return -1; } if (p + sizeof(xpl) != ep) { free(newmsg); return -1; } memset(&xpl, 0, sizeof(xpl)); xpl.sadb_x_policy_len = PFKEY_UNIT64(sizeof(xpl)); xpl.sadb_x_policy_exttype = SADB_X_EXT_POLICY; xpl.sadb_x_policy_id = spid; memcpy(p, &xpl, sizeof(xpl)); /* send message */ len = pfkey_send(so, newmsg, len); free(newmsg); if (len < 0) return -1; __ipsec_errcode = EIPSEC_NO_ERROR; return len; } /* * open a socket. * OUT: * -1: fail. * others : success and return value of socket. */ int pfkey_open(void) { int so; int bufsiz_current, bufsiz_wanted; int ret; socklen_t len; if ((so = socket(PF_KEY, SOCK_RAW, PF_KEY_V2)) < 0) { __ipsec_set_strerror(strerror(errno)); return -1; } /* * This is a temporary workaround for KAME PR 154. * Don't really care even if it fails. */ /* Try to have 128k. If we have more, do not lower it. */ bufsiz_wanted = 128 * 1024; len = sizeof(bufsiz_current); ret = getsockopt(so, SOL_SOCKET, SO_SNDBUF, &bufsiz_current, &len); if ((ret < 0) || (bufsiz_current < bufsiz_wanted)) (void)setsockopt(so, SOL_SOCKET, SO_SNDBUF, &bufsiz_wanted, sizeof(bufsiz_wanted)); /* Try to have have at least 2MB. If we have more, do not lower it. */ bufsiz_wanted = 2 * 1024 * 1024; len = sizeof(bufsiz_current); ret = getsockopt(so, SOL_SOCKET, SO_RCVBUF, &bufsiz_current, &len); if (ret < 0) bufsiz_current = 128 * 1024; for (; bufsiz_wanted > bufsiz_current; bufsiz_wanted /= 2) { if (setsockopt(so, SOL_SOCKET, SO_RCVBUF, &bufsiz_wanted, sizeof(bufsiz_wanted)) == 0) break; } __ipsec_errcode = EIPSEC_NO_ERROR; return so; } /* * close a socket. * OUT: * 0: success. * -1: fail. */ void -pfkey_close(so) - int so; +pfkey_close(int so) { (void)close(so); __ipsec_errcode = EIPSEC_NO_ERROR; return; } /* * receive sadb_msg data, and return pointer to new buffer allocated. * Must free this buffer later. * OUT: * NULL : error occurred. * others : a pointer to sadb_msg structure. * * XXX should be rewritten to pass length explicitly */ struct sadb_msg * -pfkey_recv(so) - int so; +pfkey_recv(int so) { struct sadb_msg buf, *newmsg; int len, reallen; while ((len = recv(so, (caddr_t)&buf, sizeof(buf), MSG_PEEK)) < 0) { if (errno == EINTR) continue; __ipsec_set_strerror(strerror(errno)); return NULL; } if (len < sizeof(buf)) { recv(so, (caddr_t)&buf, sizeof(buf), 0); __ipsec_errcode = EIPSEC_MAX; return NULL; } /* read real message */ reallen = PFKEY_UNUNIT64(buf.sadb_msg_len); if ((newmsg = CALLOC(reallen, struct sadb_msg *)) == NULL) { __ipsec_set_strerror(strerror(errno)); return NULL; } while ((len = recv(so, (caddr_t)newmsg, reallen, 0)) < 0) { if (errno == EINTR) continue; __ipsec_set_strerror(strerror(errno)); free(newmsg); return NULL; } if (len != reallen) { __ipsec_errcode = EIPSEC_SYSTEM_ERROR; free(newmsg); return NULL; } /* don't trust what the kernel says, validate! */ if (PFKEY_UNUNIT64(newmsg->sadb_msg_len) != len) { __ipsec_errcode = EIPSEC_SYSTEM_ERROR; free(newmsg); return NULL; } __ipsec_errcode = EIPSEC_NO_ERROR; return newmsg; } /* * send message to a socket. * OUT: * others: success and return length sent. * -1 : fail. */ int -pfkey_send(so, msg, len) - int so; - struct sadb_msg *msg; - int len; +pfkey_send(int so, struct sadb_msg *msg, int len) { if ((len = send(so, (caddr_t)msg, len, 0)) < 0) { __ipsec_set_strerror(strerror(errno)); return -1; } __ipsec_errcode = EIPSEC_NO_ERROR; return len; } /* * %%% Utilities * NOTE: These functions are derived from netkey/key.c in KAME. */ /* * set the pointer to each header in this message buffer. * IN: msg: pointer to message buffer. * mhp: pointer to the buffer initialized like below: * caddr_t mhp[SADB_EXT_MAX + 1]; * OUT: -1: invalid. * 0: valid. * * XXX should be rewritten to obtain length explicitly */ int -pfkey_align(msg, mhp) - struct sadb_msg *msg; - caddr_t *mhp; +pfkey_align(struct sadb_msg *msg, caddr_t *mhp) { struct sadb_ext *ext; int i; caddr_t p; caddr_t ep; /* XXX should be passed from upper layer */ /* validity check */ if (msg == NULL || mhp == NULL) { __ipsec_errcode = EIPSEC_INVAL_ARGUMENT; return -1; } /* initialize */ for (i = 0; i < SADB_EXT_MAX + 1; i++) mhp[i] = NULL; mhp[0] = (caddr_t)msg; /* initialize */ p = (caddr_t) msg; ep = p + PFKEY_UNUNIT64(msg->sadb_msg_len); /* skip base header */ p += sizeof(struct sadb_msg); while (p < ep) { ext = (struct sadb_ext *)p; if (ep < p + sizeof(*ext) || PFKEY_EXTLEN(ext) < sizeof(*ext) || ep < p + PFKEY_EXTLEN(ext)) { /* invalid format */ break; } /* duplicate check */ /* XXX Are there duplication either KEY_AUTH or KEY_ENCRYPT ?*/ if (mhp[ext->sadb_ext_type] != NULL) { __ipsec_errcode = EIPSEC_INVAL_EXTTYPE; return -1; } /* set pointer */ switch (ext->sadb_ext_type) { case SADB_EXT_SA: case SADB_EXT_LIFETIME_CURRENT: case SADB_EXT_LIFETIME_HARD: case SADB_EXT_LIFETIME_SOFT: case SADB_EXT_ADDRESS_SRC: case SADB_EXT_ADDRESS_DST: case SADB_EXT_ADDRESS_PROXY: case SADB_EXT_KEY_AUTH: /* XXX should to be check weak keys. */ case SADB_EXT_KEY_ENCRYPT: /* XXX should to be check weak keys. */ case SADB_EXT_IDENTITY_SRC: case SADB_EXT_IDENTITY_DST: case SADB_EXT_SENSITIVITY: case SADB_EXT_PROPOSAL: case SADB_EXT_SUPPORTED_AUTH: case SADB_EXT_SUPPORTED_ENCRYPT: case SADB_EXT_SPIRANGE: case SADB_X_EXT_POLICY: case SADB_X_EXT_SA2: case SADB_X_EXT_NAT_T_TYPE: case SADB_X_EXT_NAT_T_SPORT: case SADB_X_EXT_NAT_T_DPORT: case SADB_X_EXT_NAT_T_OAI: case SADB_X_EXT_NAT_T_OAR: case SADB_X_EXT_NAT_T_FRAG: case SADB_X_EXT_SA_REPLAY: case SADB_X_EXT_NEW_ADDRESS_SRC: case SADB_X_EXT_NEW_ADDRESS_DST: mhp[ext->sadb_ext_type] = (caddr_t)ext; break; default: __ipsec_errcode = EIPSEC_INVAL_EXTTYPE; return -1; } p += PFKEY_EXTLEN(ext); } if (p != ep) { __ipsec_errcode = EIPSEC_INVAL_SADBMSG; return -1; } __ipsec_errcode = EIPSEC_NO_ERROR; return 0; } /* * check basic usage for sadb_msg, * NOTE: This routine is derived from netkey/key.c in KAME. * IN: msg: pointer to message buffer. * mhp: pointer to the buffer initialized like below: * * caddr_t mhp[SADB_EXT_MAX + 1]; * * OUT: -1: invalid. * 0: valid. */ int -pfkey_check(mhp) - caddr_t *mhp; +pfkey_check(caddr_t *mhp) { struct sadb_msg *msg; /* validity check */ if (mhp == NULL || mhp[0] == NULL) { __ipsec_errcode = EIPSEC_INVAL_ARGUMENT; return -1; } msg = (struct sadb_msg *)mhp[0]; /* check version */ if (msg->sadb_msg_version != PF_KEY_V2) { __ipsec_errcode = EIPSEC_INVAL_VERSION; return -1; } /* check type */ if (msg->sadb_msg_type > SADB_MAX) { __ipsec_errcode = EIPSEC_INVAL_MSGTYPE; return -1; } /* check SA type */ switch (msg->sadb_msg_satype) { case SADB_SATYPE_UNSPEC: switch (msg->sadb_msg_type) { case SADB_GETSPI: case SADB_UPDATE: case SADB_ADD: case SADB_DELETE: case SADB_GET: case SADB_ACQUIRE: case SADB_EXPIRE: __ipsec_errcode = EIPSEC_INVAL_SATYPE; return -1; } break; case SADB_SATYPE_ESP: case SADB_SATYPE_AH: case SADB_X_SATYPE_IPCOMP: case SADB_X_SATYPE_TCPSIGNATURE: switch (msg->sadb_msg_type) { case SADB_X_SPDADD: case SADB_X_SPDDELETE: case SADB_X_SPDGET: case SADB_X_SPDDUMP: case SADB_X_SPDFLUSH: __ipsec_errcode = EIPSEC_INVAL_SATYPE; return -1; } break; case SADB_SATYPE_RSVP: case SADB_SATYPE_OSPFV2: case SADB_SATYPE_RIPV2: case SADB_SATYPE_MIP: __ipsec_errcode = EIPSEC_NOT_SUPPORTED; return -1; case 1: /* XXX: What does it do ? */ if (msg->sadb_msg_type == SADB_X_PROMISC) break; /*FALLTHROUGH*/ default: __ipsec_errcode = EIPSEC_INVAL_SATYPE; return -1; } /* check field of upper layer protocol and address family */ if (mhp[SADB_EXT_ADDRESS_SRC] != NULL && mhp[SADB_EXT_ADDRESS_DST] != NULL) { struct sadb_address *src0, *dst0; src0 = (struct sadb_address *)(mhp[SADB_EXT_ADDRESS_SRC]); dst0 = (struct sadb_address *)(mhp[SADB_EXT_ADDRESS_DST]); if (src0->sadb_address_proto != dst0->sadb_address_proto) { __ipsec_errcode = EIPSEC_PROTO_MISMATCH; return -1; } if (PFKEY_ADDR_SADDR(src0)->sa_family != PFKEY_ADDR_SADDR(dst0)->sa_family) { __ipsec_errcode = EIPSEC_FAMILY_MISMATCH; return -1; } switch (PFKEY_ADDR_SADDR(src0)->sa_family) { case AF_INET: case AF_INET6: break; default: __ipsec_errcode = EIPSEC_INVAL_FAMILY; return -1; } /* * prefixlen == 0 is valid because there must be the case * all addresses are matched. */ } __ipsec_errcode = EIPSEC_NO_ERROR; return 0; } /* * set data into sadb_msg. * `buf' must has been allocated sufficiently. */ static caddr_t -pfkey_setsadbmsg(buf, lim, type, tlen, satype, seq, pid) - caddr_t buf; - caddr_t lim; - u_int type, satype; - u_int tlen; - u_int32_t seq; - pid_t pid; +pfkey_setsadbmsg(caddr_t buf, caddr_t lim, u_int type, u_int tlen, + u_int satype, u_int32_t seq, pid_t pid) { struct sadb_msg *p; u_int len; p = (struct sadb_msg *)buf; len = sizeof(struct sadb_msg); if (buf + len > lim) return NULL; memset(p, 0, len); p->sadb_msg_version = PF_KEY_V2; p->sadb_msg_type = type; p->sadb_msg_errno = 0; p->sadb_msg_satype = satype; p->sadb_msg_len = PFKEY_UNIT64(tlen); p->sadb_msg_reserved = 0; p->sadb_msg_seq = seq; p->sadb_msg_pid = (u_int32_t)pid; return(buf + len); } /* * copy secasvar data into sadb_address. * `buf' must has been allocated sufficiently. */ static caddr_t -pfkey_setsadbsa(buf, lim, spi, wsize, auth, enc, flags) - caddr_t buf; - caddr_t lim; - u_int32_t spi, flags; - u_int wsize, auth, enc; +pfkey_setsadbsa(caddr_t buf, caddr_t lim, u_int32_t spi, u_int wsize, + u_int auth, u_int enc, u_int32_t flags) { struct sadb_sa *p; u_int len; p = (struct sadb_sa *)buf; len = sizeof(struct sadb_sa); if (buf + len > lim) return NULL; memset(p, 0, len); p->sadb_sa_len = PFKEY_UNIT64(len); p->sadb_sa_exttype = SADB_EXT_SA; p->sadb_sa_spi = spi; p->sadb_sa_replay = wsize > UINT8_MAX ? UINT8_MAX: wsize; p->sadb_sa_state = SADB_SASTATE_LARVAL; p->sadb_sa_auth = auth; p->sadb_sa_encrypt = enc; p->sadb_sa_flags = flags; return(buf + len); } /* * Set data into sadb_x_sa_replay. * `buf' must has been allocated sufficiently. */ static caddr_t pfkey_setsadbxreplay(caddr_t buf, caddr_t lim, uint32_t wsize) { struct sadb_x_sa_replay *p; u_int len; p = (struct sadb_x_sa_replay *)buf; len = sizeof(struct sadb_x_sa_replay); if (buf + len > lim) return (NULL); memset(p, 0, len); p->sadb_x_sa_replay_len = PFKEY_UNIT64(len); p->sadb_x_sa_replay_exttype = SADB_X_EXT_SA_REPLAY; /* Convert wsize from bytes to number of packets. */ p->sadb_x_sa_replay_replay = wsize << 3; return (buf + len); } /* * set data into sadb_address. * `buf' must has been allocated sufficiently. * prefixlen is in bits. */ static caddr_t -pfkey_setsadbaddr(buf, lim, exttype, saddr, prefixlen, ul_proto) - caddr_t buf; - caddr_t lim; - u_int exttype; - struct sockaddr *saddr; - u_int prefixlen; - u_int ul_proto; +pfkey_setsadbaddr(caddr_t buf, caddr_t lim, u_int exttype, + struct sockaddr *saddr, u_int prefixlen, u_int ul_proto) { struct sadb_address *p; u_int len; p = (struct sadb_address *)buf; len = sizeof(struct sadb_address) + PFKEY_ALIGN8(saddr->sa_len); if (buf + len > lim) return NULL; memset(p, 0, len); p->sadb_address_len = PFKEY_UNIT64(len); p->sadb_address_exttype = exttype & 0xffff; p->sadb_address_proto = ul_proto & 0xff; p->sadb_address_prefixlen = prefixlen; p->sadb_address_reserved = 0; memcpy(p + 1, saddr, saddr->sa_len); return(buf + len); } /* * set sadb_key structure after clearing buffer with zero. * OUT: the pointer of buf + len. */ static caddr_t -pfkey_setsadbkey(buf, lim, type, key, keylen) - caddr_t buf; - caddr_t lim; - caddr_t key; - u_int type, keylen; +pfkey_setsadbkey(caddr_t buf, caddr_t lim, u_int type, caddr_t key, u_int keylen) { struct sadb_key *p; u_int len; p = (struct sadb_key *)buf; len = sizeof(struct sadb_key) + PFKEY_ALIGN8(keylen); if (buf + len > lim) return NULL; memset(p, 0, len); p->sadb_key_len = PFKEY_UNIT64(len); p->sadb_key_exttype = type; p->sadb_key_bits = keylen << 3; p->sadb_key_reserved = 0; memcpy(p + 1, key, keylen); return buf + len; } /* * set sadb_lifetime structure after clearing buffer with zero. * OUT: the pointer of buf + len. */ static caddr_t -pfkey_setsadblifetime(buf, lim, type, l_alloc, l_bytes, l_addtime, l_usetime) - caddr_t buf; - caddr_t lim; - u_int type; - u_int32_t l_alloc, l_bytes, l_addtime, l_usetime; +pfkey_setsadblifetime(caddr_t buf, caddr_t lim, u_int type, u_int32_t l_alloc, + u_int32_t l_bytes, u_int32_t l_addtime, u_int32_t l_usetime) { struct sadb_lifetime *p; u_int len; p = (struct sadb_lifetime *)buf; len = sizeof(struct sadb_lifetime); if (buf + len > lim) return NULL; memset(p, 0, len); p->sadb_lifetime_len = PFKEY_UNIT64(len); p->sadb_lifetime_exttype = type; switch (type) { case SADB_EXT_LIFETIME_SOFT: p->sadb_lifetime_allocations = (l_alloc * soft_lifetime_allocations_rate) /100; p->sadb_lifetime_bytes = (l_bytes * soft_lifetime_bytes_rate) /100; p->sadb_lifetime_addtime = (l_addtime * soft_lifetime_addtime_rate) /100; p->sadb_lifetime_usetime = (l_usetime * soft_lifetime_usetime_rate) /100; break; case SADB_EXT_LIFETIME_HARD: p->sadb_lifetime_allocations = l_alloc; p->sadb_lifetime_bytes = l_bytes; p->sadb_lifetime_addtime = l_addtime; p->sadb_lifetime_usetime = l_usetime; break; } return buf + len; } /* * copy secasvar data into sadb_address. * `buf' must has been allocated sufficiently. */ static caddr_t -pfkey_setsadbxsa2(buf, lim, mode0, reqid) - caddr_t buf; - caddr_t lim; - u_int32_t mode0; - u_int32_t reqid; +pfkey_setsadbxsa2(caddr_t buf, caddr_t lim, u_int32_t mode0, u_int32_t reqid) { struct sadb_x_sa2 *p; u_int8_t mode = mode0 & 0xff; u_int len; p = (struct sadb_x_sa2 *)buf; len = sizeof(struct sadb_x_sa2); if (buf + len > lim) return NULL; memset(p, 0, len); p->sadb_x_sa2_len = PFKEY_UNIT64(len); p->sadb_x_sa2_exttype = SADB_X_EXT_SA2; p->sadb_x_sa2_mode = mode; p->sadb_x_sa2_reqid = reqid; return(buf + len); } diff --git a/lib/libipsec/pfkey_dump.c b/lib/libipsec/pfkey_dump.c index 99a02ae24bc4..f91d00126cbc 100644 --- a/lib/libipsec/pfkey_dump.c +++ b/lib/libipsec/pfkey_dump.c @@ -1,663 +1,656 @@ /* $KAME: pfkey_dump.c,v 1.45 2003/09/08 10:14:56 itojun Exp $ */ /*- * SPDX-License-Identifier: BSD-3-Clause * * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the project nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "ipsec_strerror.h" #include "libpfkey.h" /* cope with old kame headers - ugly */ #ifndef SADB_X_AALG_NULL #define SADB_X_AALG_NULL SADB_AALG_NULL #endif #ifndef SADB_X_EALG_RC5CBC #ifdef SADB_EALG_RC5CBC #define SADB_X_EALG_RC5CBC SADB_EALG_RC5CBC #endif #endif #define GETMSGSTR(str, num) \ do { \ if (sizeof((str)[0]) == 0 \ || num >= sizeof(str)/sizeof((str)[0])) \ printf("%u ", (num)); \ else if (strlen((str)[(num)]) == 0) \ printf("%u ", (num)); \ else \ printf("%s ", (str)[(num)]); \ } while (0) #define GETMSGV2S(v2s, num) \ do { \ struct val2str *p; \ for (p = (v2s); p && p->str; p++) { \ if (p->val == (num)) \ break; \ } \ if (p && p->str) \ printf("%s ", p->str); \ else \ printf("%u ", (num)); \ } while (0) static char *str_ipaddr(struct sockaddr *); static char *str_prefport(u_int, u_int, u_int, u_int); static void str_upperspec(u_int, u_int, u_int); static char *str_time(time_t); static void str_lifetime_byte(struct sadb_lifetime *, char *); struct val2str { int val; const char *str; }; /* * Must to be re-written about following strings. */ static char *str_satype[] = { "unspec", "unknown", "ah", "esp", "unknown", "rsvp", "ospfv2", "ripv2", "mip", "ipcomp", "policy", "tcp" }; static char *str_mode[] = { "any", "transport", "tunnel", }; static char *str_state[] = { "larval", "mature", "dying", "dead", }; static struct val2str str_alg_auth[] = { { SADB_AALG_NONE, "none", }, { SADB_AALG_SHA1HMAC, "hmac-sha1", }, { SADB_X_AALG_NULL, "null", }, { SADB_X_AALG_TCP_MD5, "tcp-md5", }, #ifdef SADB_X_AALG_SHA2_256 { SADB_X_AALG_SHA2_256, "hmac-sha2-256", }, #endif #ifdef SADB_X_AALG_SHA2_384 { SADB_X_AALG_SHA2_384, "hmac-sha2-384", }, #endif #ifdef SADB_X_AALG_SHA2_512 { SADB_X_AALG_SHA2_512, "hmac-sha2-512", }, #endif #ifdef SADB_X_AALG_AES_XCBC_MAC { SADB_X_AALG_AES_XCBC_MAC, "aes-xcbc-mac", }, #endif #ifdef SADB_X_AALG_CHACHA20POLY1305 { SADB_X_AALG_CHACHA20POLY1305, "chacha20-poly1305", }, #endif { -1, NULL, }, }; static struct val2str str_alg_enc[] = { { SADB_EALG_NONE, "none", }, { SADB_EALG_NULL, "null", }, #ifdef SADB_X_EALG_RC5CBC { SADB_X_EALG_RC5CBC, "rc5-cbc", }, #endif #ifdef SADB_X_EALG_AESCBC { SADB_X_EALG_AESCBC, "aes-cbc", }, #endif #ifdef SADB_X_EALG_TWOFISHCBC { SADB_X_EALG_TWOFISHCBC, "twofish-cbc", }, #endif #ifdef SADB_X_EALG_AESCTR { SADB_X_EALG_AESCTR, "aes-ctr", }, #endif #ifdef SADB_X_EALG_AESGCM16 { SADB_X_EALG_AESGCM16, "aes-gcm-16", }, #endif #ifdef SADB_X_EALG_CHACHA20POLY1305 { SADB_X_EALG_CHACHA20POLY1305, "chacha20-poly1305", }, #endif { -1, NULL, }, }; static struct val2str str_alg_comp[] = { { SADB_X_CALG_NONE, "none", }, { SADB_X_CALG_OUI, "oui", }, { SADB_X_CALG_DEFLATE, "deflate", }, { SADB_X_CALG_LZS, "lzs", }, { -1, NULL, }, }; static struct val2str str_sp_scope[] = { { IPSEC_POLICYSCOPE_GLOBAL, "global" }, { IPSEC_POLICYSCOPE_IFNET, "ifnet" }, { IPSEC_POLICYSCOPE_PCB, "pcb"}, { -1, NULL }, }; /* * dump SADB_MSG formatted. For debugging, you should use kdebug_sadb(). */ void -pfkey_sadump(m) - struct sadb_msg *m; +pfkey_sadump(struct sadb_msg *m) { caddr_t mhp[SADB_EXT_MAX + 1]; struct sadb_sa *m_sa; struct sadb_x_sa2 *m_sa2; struct sadb_lifetime *m_lftc, *m_lfth, *m_lfts; struct sadb_address *m_saddr, *m_daddr, *m_paddr; struct sadb_key *m_auth, *m_enc; struct sadb_ident *m_sid, *m_did; struct sadb_sens *m_sens; struct sadb_x_sa_replay *m_sa_replay; struct sadb_x_nat_t_type *natt_type; struct sadb_x_nat_t_port *natt_sport, *natt_dport; struct sadb_address *natt_oai, *natt_oar; /* check pfkey message. */ if (pfkey_align(m, mhp)) { printf("%s\n", ipsec_strerror()); return; } if (pfkey_check(mhp)) { printf("%s\n", ipsec_strerror()); return; } m_sa = (struct sadb_sa *)mhp[SADB_EXT_SA]; m_sa2 = (struct sadb_x_sa2 *)mhp[SADB_X_EXT_SA2]; m_lftc = (struct sadb_lifetime *)mhp[SADB_EXT_LIFETIME_CURRENT]; m_lfth = (struct sadb_lifetime *)mhp[SADB_EXT_LIFETIME_HARD]; m_lfts = (struct sadb_lifetime *)mhp[SADB_EXT_LIFETIME_SOFT]; m_saddr = (struct sadb_address *)mhp[SADB_EXT_ADDRESS_SRC]; m_daddr = (struct sadb_address *)mhp[SADB_EXT_ADDRESS_DST]; m_paddr = (struct sadb_address *)mhp[SADB_EXT_ADDRESS_PROXY]; m_auth = (struct sadb_key *)mhp[SADB_EXT_KEY_AUTH]; m_enc = (struct sadb_key *)mhp[SADB_EXT_KEY_ENCRYPT]; m_sid = (struct sadb_ident *)mhp[SADB_EXT_IDENTITY_SRC]; m_did = (struct sadb_ident *)mhp[SADB_EXT_IDENTITY_DST]; m_sens = (struct sadb_sens *)mhp[SADB_EXT_SENSITIVITY]; m_sa_replay = (struct sadb_x_sa_replay *)mhp[SADB_X_EXT_SA_REPLAY]; natt_type = (struct sadb_x_nat_t_type *)mhp[SADB_X_EXT_NAT_T_TYPE]; natt_sport = (struct sadb_x_nat_t_port *)mhp[SADB_X_EXT_NAT_T_SPORT]; natt_dport = (struct sadb_x_nat_t_port *)mhp[SADB_X_EXT_NAT_T_DPORT]; natt_oai = (struct sadb_address *)mhp[SADB_X_EXT_NAT_T_OAI]; natt_oar = (struct sadb_address *)mhp[SADB_X_EXT_NAT_T_OAR]; /* source address */ if (m_saddr == NULL) { printf("no ADDRESS_SRC extension.\n"); return; } printf("%s", str_ipaddr((struct sockaddr *)(m_saddr + 1))); if (natt_type != NULL && natt_sport != NULL) printf("[%u]", ntohs(natt_sport->sadb_x_nat_t_port_port)); /* destination address */ if (m_daddr == NULL) { printf("\nno ADDRESS_DST extension.\n"); return; } printf(" %s", str_ipaddr((struct sockaddr *)(m_daddr + 1))); if (natt_type != NULL && natt_dport != NULL) printf("[%u]", ntohs(natt_dport->sadb_x_nat_t_port_port)); /* SA type */ if (m_sa == NULL) { printf("\nno SA extension.\n"); return; } if (m_sa2 == NULL) { printf("\nno SA2 extension.\n"); return; } printf("\n\t"); if (m->sadb_msg_satype == SADB_SATYPE_ESP && natt_type != NULL) printf("esp-udp "); else GETMSGSTR(str_satype, m->sadb_msg_satype); printf("mode="); GETMSGSTR(str_mode, m_sa2->sadb_x_sa2_mode); printf("spi=%u(0x%08x) reqid=%u(0x%08x)\n", (u_int32_t)ntohl(m_sa->sadb_sa_spi), (u_int32_t)ntohl(m_sa->sadb_sa_spi), (u_int32_t)m_sa2->sadb_x_sa2_reqid, (u_int32_t)m_sa2->sadb_x_sa2_reqid); /* other NAT-T information */ if (natt_type != NULL && (natt_oai != NULL || natt_oar != NULL)) { printf("\tNAT:"); if (natt_oai != NULL) printf(" OAI=%s", str_ipaddr((struct sockaddr *)(natt_oai + 1))); if (natt_oar != NULL) printf(" OAR=%s", str_ipaddr((struct sockaddr *)(natt_oar + 1))); printf("\n"); } /* encryption key */ if (m->sadb_msg_satype == SADB_X_SATYPE_IPCOMP) { printf("\tC: "); GETMSGV2S(str_alg_comp, m_sa->sadb_sa_encrypt); } else if (m->sadb_msg_satype == SADB_SATYPE_ESP) { if (m_enc != NULL) { printf("\tE: "); GETMSGV2S(str_alg_enc, m_sa->sadb_sa_encrypt); ipsec_hexdump((caddr_t)m_enc + sizeof(*m_enc), m_enc->sadb_key_bits / 8); printf("\n"); } } /* authentication key */ if (m_auth != NULL) { printf("\tA: "); GETMSGV2S(str_alg_auth, m_sa->sadb_sa_auth); ipsec_hexdump((caddr_t)m_auth + sizeof(*m_auth), m_auth->sadb_key_bits / 8); printf("\n"); } /* replay windoe size & flags */ printf("\tseq=0x%08x replay=%u flags=0x%08x ", m_sa2->sadb_x_sa2_sequence, m_sa_replay ? (m_sa_replay->sadb_x_sa_replay_replay >> 3) : m_sa->sadb_sa_replay, m_sa->sadb_sa_flags); /* state */ printf("state="); GETMSGSTR(str_state, m_sa->sadb_sa_state); printf("\n"); /* lifetime */ if (m_lftc != NULL) { time_t tmp_time = time(0); printf("\tcreated: %s", str_time(m_lftc->sadb_lifetime_addtime)); printf("\tcurrent: %s\n", str_time(tmp_time)); printf("\tdiff: %lu(s)", (u_long)(m_lftc->sadb_lifetime_addtime == 0 ? 0 : (tmp_time - m_lftc->sadb_lifetime_addtime))); printf("\thard: %lu(s)", (u_long)(m_lfth == NULL ? 0 : m_lfth->sadb_lifetime_addtime)); printf("\tsoft: %lu(s)\n", (u_long)(m_lfts == NULL ? 0 : m_lfts->sadb_lifetime_addtime)); printf("\tlast: %s", str_time(m_lftc->sadb_lifetime_usetime)); printf("\thard: %lu(s)", (u_long)(m_lfth == NULL ? 0 : m_lfth->sadb_lifetime_usetime)); printf("\tsoft: %lu(s)\n", (u_long)(m_lfts == NULL ? 0 : m_lfts->sadb_lifetime_usetime)); str_lifetime_byte(m_lftc, "current"); str_lifetime_byte(m_lfth, "hard"); str_lifetime_byte(m_lfts, "soft"); printf("\n"); printf("\tallocated: %lu", (unsigned long)m_lftc->sadb_lifetime_allocations); printf("\thard: %lu", (u_long)(m_lfth == NULL ? 0 : m_lfth->sadb_lifetime_allocations)); printf("\tsoft: %lu\n", (u_long)(m_lfts == NULL ? 0 : m_lfts->sadb_lifetime_allocations)); } printf("\tsadb_seq=%lu pid=%lu ", (u_long)m->sadb_msg_seq, (u_long)m->sadb_msg_pid); /* XXX DEBUG */ printf("refcnt=%u\n", m->sadb_msg_reserved); return; } void pfkey_spdump(struct sadb_msg *m) { char pbuf[NI_MAXSERV]; caddr_t mhp[SADB_EXT_MAX + 1]; struct sadb_address *m_saddr, *m_daddr; struct sadb_x_policy *m_xpl; struct sadb_lifetime *m_lftc = NULL, *m_lfth = NULL; struct sockaddr *sa; u_int16_t sport = 0, dport = 0; /* check pfkey message. */ if (pfkey_align(m, mhp)) { printf("%s\n", ipsec_strerror()); return; } if (pfkey_check(mhp)) { printf("%s\n", ipsec_strerror()); return; } m_saddr = (struct sadb_address *)mhp[SADB_EXT_ADDRESS_SRC]; m_daddr = (struct sadb_address *)mhp[SADB_EXT_ADDRESS_DST]; m_xpl = (struct sadb_x_policy *)mhp[SADB_X_EXT_POLICY]; m_lftc = (struct sadb_lifetime *)mhp[SADB_EXT_LIFETIME_CURRENT]; m_lfth = (struct sadb_lifetime *)mhp[SADB_EXT_LIFETIME_HARD]; if (m_saddr && m_daddr) { /* source address */ sa = (struct sockaddr *)(m_saddr + 1); switch (sa->sa_family) { case AF_INET: case AF_INET6: if (getnameinfo(sa, sa->sa_len, NULL, 0, pbuf, sizeof(pbuf), NI_NUMERICSERV) != 0) sport = 0; /*XXX*/ else sport = atoi(pbuf); printf("%s%s ", str_ipaddr(sa), str_prefport(sa->sa_family, m_saddr->sadb_address_prefixlen, sport, m_saddr->sadb_address_proto)); break; default: printf("unknown-af "); break; } /* destination address */ sa = (struct sockaddr *)(m_daddr + 1); switch (sa->sa_family) { case AF_INET: case AF_INET6: if (getnameinfo(sa, sa->sa_len, NULL, 0, pbuf, sizeof(pbuf), NI_NUMERICSERV) != 0) dport = 0; /*XXX*/ else dport = atoi(pbuf); printf("%s%s ", str_ipaddr(sa), str_prefport(sa->sa_family, m_daddr->sadb_address_prefixlen, dport, m_saddr->sadb_address_proto)); break; default: printf("unknown-af "); break; } /* upper layer protocol */ if (m_saddr->sadb_address_proto != m_daddr->sadb_address_proto) { printf("upper layer protocol mismatched.\n"); return; } str_upperspec(m_saddr->sadb_address_proto, sport, dport); } else printf("(no selector, probably per-socket policy) "); /* policy */ { char *d_xpl; if (m_xpl == NULL) { printf("no X_POLICY extension.\n"); return; } d_xpl = ipsec_dump_policy((char *)m_xpl, "\n\t"); /* dump SPD */ printf("\n\t%s\n", d_xpl); free(d_xpl); } /* lifetime */ if (m_lftc) { printf("\tcreated: %s ", str_time(m_lftc->sadb_lifetime_addtime)); printf("lastused: %s\n", str_time(m_lftc->sadb_lifetime_usetime)); } if (m_lfth) { printf("\tlifetime: %lu(s) ", (u_long)m_lfth->sadb_lifetime_addtime); printf("validtime: %lu(s)\n", (u_long)m_lfth->sadb_lifetime_usetime); } printf("\tspid=%ld seq=%ld pid=%ld scope=", (u_long)m_xpl->sadb_x_policy_id, (u_long)m->sadb_msg_seq, (u_long)m->sadb_msg_pid); GETMSGV2S(str_sp_scope, m_xpl->sadb_x_policy_scope); if (m_xpl->sadb_x_policy_scope == IPSEC_POLICYSCOPE_IFNET && if_indextoname(m_xpl->sadb_x_policy_ifindex, pbuf) != NULL) printf("ifname=%s", pbuf); printf("\n"); /* XXX TEST */ printf("\trefcnt=%u\n", m->sadb_msg_reserved); return; } /* * set "ipaddress" to buffer. */ static char * -str_ipaddr(sa) - struct sockaddr *sa; +str_ipaddr(struct sockaddr *sa) { static char buf[NI_MAXHOST]; const int niflag = NI_NUMERICHOST; if (sa == NULL) return ""; if (getnameinfo(sa, sa->sa_len, buf, sizeof(buf), NULL, 0, niflag) == 0) return buf; return NULL; } /* * set "/prefix[port number]" to buffer. */ static char * -str_prefport(family, pref, port, ulp) - u_int family, pref, port, ulp; +str_prefport(u_int family, u_int pref, u_int port, u_int ulp) { static char buf[128]; char prefbuf[128]; char portbuf[128]; int plen; switch (family) { case AF_INET: plen = sizeof(struct in_addr) << 3; break; case AF_INET6: plen = sizeof(struct in6_addr) << 3; break; default: return "?"; } if (pref == plen) prefbuf[0] = '\0'; else snprintf(prefbuf, sizeof(prefbuf), "/%u", pref); if (ulp == IPPROTO_ICMPV6) memset(portbuf, 0, sizeof(portbuf)); else { if (port == IPSEC_PORT_ANY) snprintf(portbuf, sizeof(portbuf), "[%s]", "any"); else snprintf(portbuf, sizeof(portbuf), "[%u]", port); } snprintf(buf, sizeof(buf), "%s%s", prefbuf, portbuf); return buf; } static void -str_upperspec(ulp, p1, p2) - u_int ulp, p1, p2; +str_upperspec(u_int ulp, u_int p1, u_int p2) { if (ulp == IPSEC_ULPROTO_ANY) printf("any"); else if (ulp == IPPROTO_ICMPV6) { printf("icmp6"); if (!(p1 == IPSEC_PORT_ANY && p2 == IPSEC_PORT_ANY)) printf(" %u,%u", p1, p2); } else { struct protoent *ent; switch (ulp) { case IPPROTO_IPV4: printf("ip4"); break; default: ent = getprotobynumber(ulp); if (ent) printf("%s", ent->p_name); else printf("%u", ulp); endprotoent(); break; } } } /* * set "Mon Day Time Year" to buffer */ static char * -str_time(t) - time_t t; +str_time(time_t t) { static char buf[128]; if (t == 0) { int i = 0; for (;i < 20;) buf[i++] = ' '; } else { char *t0; t0 = ctime(&t); memcpy(buf, t0 + 4, 20); } buf[20] = '\0'; return(buf); } static void -str_lifetime_byte(x, str) - struct sadb_lifetime *x; - char *str; +str_lifetime_byte(struct sadb_lifetime *x, char *str) { double y; char *unit; int w; if (x == NULL) { printf("\t%s: 0(bytes)", str); return; } #if 0 if ((x->sadb_lifetime_bytes) / 1024 / 1024) { y = (x->sadb_lifetime_bytes) * 1.0 / 1024 / 1024; unit = "M"; w = 1; } else if ((x->sadb_lifetime_bytes) / 1024) { y = (x->sadb_lifetime_bytes) * 1.0 / 1024; unit = "K"; w = 1; } else { y = (x->sadb_lifetime_bytes) * 1.0; unit = ""; w = 0; } #else y = (x->sadb_lifetime_bytes) * 1.0; unit = ""; w = 0; #endif printf("\t%s: %.*f(%sbytes)", str, w, y, unit); }