Index: head/lib/libipsec/pfkey.c =================================================================== --- head/lib/libipsec/pfkey.c (revision 316758) +++ head/lib/libipsec/pfkey.c (revision 316759) @@ -1,2134 +1,2175 @@ /* $KAME: pfkey.c,v 1.46 2003/08/26 03:37:06 itojun Exp $ */ /* * 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; { 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; { 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; { 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; { 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; { 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; { 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; { __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; { 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 occured, 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; { 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; } /* proccessing 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 occured, 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; { 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 occured, 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; { 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 occured, 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; { 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 occured, and set errno */ int pfkey_send_delete_all(so, satype, mode, src, dst) int so; u_int satype, mode; struct sockaddr *src, *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 occured, 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; { 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 occured, and set errno. */ int pfkey_send_register(so, satype) 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 occured, and set errno. */ int pfkey_recv_register(so) 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 occured, and set errno. */ int pfkey_set_supported(msg, tlen) 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 occured, and set errno. */ int pfkey_send_flush(so, satype) 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 occured, and set errno. */ int pfkey_send_dump(so, satype) 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 occured, and set errno. * 0 : error occured, 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; { 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 occured, 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; { 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 occured, 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; { 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 occured, 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; { 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 occured, 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; { 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 occured, 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; { 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 occured, and set errno. */ int pfkey_send_spddelete2(so, spid) 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 occured, and set errno. */ int pfkey_send_spdget(so, spid) 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 occured, 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; { 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 occured, and set errno. */ int pfkey_send_spdflush(so) 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 occured, and set errno. */ int pfkey_send_spddump(so) 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; { 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; { 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; { 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; { 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; { 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() { int so; const int bufsiz = 128 * 1024; /*is 128K enough?*/ 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. */ (void)setsockopt(so, SOL_SOCKET, SO_SNDBUF, &bufsiz, sizeof(bufsiz)); (void)setsockopt(so, SOL_SOCKET, SO_RCVBUF, &bufsiz, sizeof(bufsiz)); __ipsec_errcode = EIPSEC_NO_ERROR; return so; } /* * close a socket. * OUT: * 0: success. * -1: fail. */ void pfkey_close(so) 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 occured. * others : a pointer to sadb_msg structure. * * XXX should be rewritten to pass length explicitly */ struct sadb_msg * pfkey_recv(so) 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; { 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; { 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; { 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; { 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; { 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; + 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; { 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; { 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; { 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; { 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); } Index: head/sbin/setkey/Makefile =================================================================== --- head/sbin/setkey/Makefile (revision 316758) +++ head/sbin/setkey/Makefile (revision 316759) @@ -1,68 +1,71 @@ # 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. # # $FreeBSD$ .include PACKAGE=runtime PROG= setkey MAN= setkey.8 SRCS= setkey.c parse.y token.l WARNS?= 1 CFLAGS+= -I${.CURDIR} -I${SRCTOP}/lib/libipsec YFLAGS= -d LIBADD= l y CLEANFILES= y.tab.c y.tab.h key_test.o keytest # libpfkey # ipsec_strerror.c is for avoiding shlib reference to non-exported function. .PATH: ${SRCTOP}/lib/libipsec ${SRCTOP}/sys/netipsec SRCS+= pfkey.c pfkey_dump.c key_debug.c ipsec_strerror.c CFLAGS+= -I${SRCTOP}/sys SRCS+= y.tab.h y.tab.h: parse.y CFLAGS+= -DIPSEC_DEBUG -DYY_NO_UNPUT +.if ${MK_INET_SUPPORT} != "no" +CFLAGS+= -DINET +.endif .if ${MK_INET6_SUPPORT} != "no" CFLAGS+= -DINET6 .endif CFLAGS+= -I. LIBADD+= ipsec CLEANFILES+= scriptdump y.tab.h #SCRIPTS= scriptdump LOCALPREFIX= /usr/local scriptdump: scriptdump.pl sed -e 's#@LOCALPREFIX@#${LOCALPREFIX}#' < $> > scriptdump .include Index: head/sbin/setkey/parse.y =================================================================== --- head/sbin/setkey/parse.y (revision 316758) +++ head/sbin/setkey/parse.y (revision 316759) @@ -1,1291 +1,1317 @@ /* $FreeBSD$ */ /* $KAME: parse.y,v 1.83 2004/05/18 08:48:23 sakane Exp $ */ /* * 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 #include #include #include #include #include #include #include #include #include #include #include +#include #include #include #include #include "libpfkey.h" #include "vchar.h" #define ATOX(c) \ (isdigit(c) ? (c - '0') : (isupper(c) ? (c - 'A' + 10) : (c - 'a' + 10))) u_int32_t p_spi; u_int p_ext, p_alg_enc, p_alg_auth, p_replay, p_mode; u_int32_t p_reqid; u_int p_key_enc_len, p_key_auth_len; caddr_t p_key_enc, p_key_auth; time_t p_lt_hard, p_lt_soft; static int p_aiflags = 0, p_aifamily = PF_UNSPEC; static struct addrinfo *parse_addr(char *, char *); static int fix_portstr(vchar_t *, vchar_t *, vchar_t *); static int setvarbuf(char *, int *, struct sadb_ext *, int, caddr_t, int); void parse_init(void); void free_buffer(void); int setkeymsg0(struct sadb_msg *, unsigned int, unsigned int, size_t); static int setkeymsg_spdaddr(unsigned int, unsigned int, vchar_t *, struct addrinfo *, int, struct addrinfo *, int); static int setkeymsg_addr(unsigned int, unsigned int, struct addrinfo *, struct addrinfo *, int); static int setkeymsg_add(unsigned int, unsigned int, struct addrinfo *, struct addrinfo *); extern int setkeymsg(char *, size_t *); extern int sendkeymsg(char *, size_t); extern int yylex(void); extern void yyfatal(const char *); extern void yyerror(const char *); %} %union { int num; unsigned long ulnum; vchar_t val; struct addrinfo *res; } %token EOT SLASH BLCL ELCL %token ADD GET DELETE DELETEALL FLUSH DUMP %token PR_ESP PR_AH PR_IPCOMP PR_TCP %token F_PROTOCOL F_AUTH F_ENC F_REPLAY F_COMP F_RAWCPI %token F_MODE MODE F_REQID %token F_EXT EXTENSION NOCYCLICSEQ %token ALG_AUTH ALG_AUTH_NOKEY %token ALG_ENC ALG_ENC_NOKEY ALG_ENC_DESDERIV ALG_ENC_DES32IV ALG_ENC_OLD %token ALG_ENC_SALT %token ALG_COMP %token F_LIFETIME_HARD F_LIFETIME_SOFT %token DECSTRING QUOTEDSTRING HEXSTRING STRING ANY /* SPD management */ %token SPDADD SPDDELETE SPDDUMP SPDFLUSH %token F_POLICY PL_REQUESTS %token F_AIFLAGS %token TAGGED %type prefix protocol_spec upper_spec %type ALG_ENC ALG_ENC_DESDERIV ALG_ENC_DES32IV ALG_ENC_OLD ALG_ENC_NOKEY %type ALG_ENC_SALT %type ALG_AUTH ALG_AUTH_NOKEY %type ALG_COMP %type PR_ESP PR_AH PR_IPCOMP PR_TCP %type EXTENSION MODE %type DECSTRING %type PL_REQUESTS portstr key_string %type policy_requests %type QUOTEDSTRING HEXSTRING STRING %type F_AIFLAGS %type upper_misc_spec policy_spec %type ipaddr %% commands : /*NOTHING*/ | commands command { free_buffer(); parse_init(); } ; command : add_command | get_command | delete_command | deleteall_command | flush_command | dump_command | spdadd_command | spddelete_command | spddump_command | spdflush_command ; /* commands concerned with management, there is in tail of this file. */ /* add command */ add_command : ADD ipaddropts ipaddr ipaddr protocol_spec spi extension_spec algorithm_spec EOT { int status; status = setkeymsg_add(SADB_ADD, $5, $3, $4); if (status < 0) return -1; } ; /* delete */ delete_command : DELETE ipaddropts ipaddr ipaddr protocol_spec spi extension_spec EOT { int status; if ($3->ai_next || $4->ai_next) { yyerror("multiple address specified"); return -1; } if (p_mode != IPSEC_MODE_ANY) yyerror("WARNING: mode is obsolete"); status = setkeymsg_addr(SADB_DELETE, $5, $3, $4, 0); if (status < 0) return -1; } ; /* deleteall command */ deleteall_command : DELETEALL ipaddropts ipaddr ipaddr protocol_spec EOT { int status; status = setkeymsg_addr(SADB_DELETE, $5, $3, $4, 1); if (status < 0) return -1; } ; /* get command */ get_command : GET ipaddropts ipaddr ipaddr protocol_spec spi extension_spec EOT { int status; if (p_mode != IPSEC_MODE_ANY) yyerror("WARNING: mode is obsolete"); status = setkeymsg_addr(SADB_GET, $5, $3, $4, 0); if (status < 0) return -1; } ; /* flush */ flush_command : FLUSH protocol_spec EOT { struct sadb_msg msg; setkeymsg0(&msg, SADB_FLUSH, $2, sizeof(msg)); sendkeymsg((char *)&msg, sizeof(msg)); } ; /* dump */ dump_command : DUMP protocol_spec EOT { struct sadb_msg msg; setkeymsg0(&msg, SADB_DUMP, $2, sizeof(msg)); sendkeymsg((char *)&msg, sizeof(msg)); } ; protocol_spec : /*NOTHING*/ { $$ = SADB_SATYPE_UNSPEC; } | PR_ESP { $$ = SADB_SATYPE_ESP; if ($1 == 1) p_ext |= SADB_X_EXT_OLD; else p_ext &= ~SADB_X_EXT_OLD; } | PR_AH { $$ = SADB_SATYPE_AH; if ($1 == 1) p_ext |= SADB_X_EXT_OLD; else p_ext &= ~SADB_X_EXT_OLD; } | PR_IPCOMP { $$ = SADB_X_SATYPE_IPCOMP; } | PR_TCP { $$ = SADB_X_SATYPE_TCPSIGNATURE; } ; spi : DECSTRING { p_spi = $1; } | HEXSTRING { char *ep; unsigned long v; ep = NULL; v = strtoul($1.buf, &ep, 16); if (!ep || *ep) { yyerror("invalid SPI"); return -1; } if (v & ~0xffffffff) { yyerror("SPI too big."); return -1; } p_spi = v; } ; algorithm_spec : esp_spec | ah_spec | ipcomp_spec ; esp_spec : F_ENC enc_alg F_AUTH auth_alg | F_ENC enc_alg ; ah_spec : F_AUTH auth_alg ; ipcomp_spec : F_COMP ALG_COMP { if ($2 < 0) { yyerror("unsupported algorithm"); return -1; } p_alg_enc = $2; } | F_COMP ALG_COMP F_RAWCPI { if ($2 < 0) { yyerror("unsupported algorithm"); return -1; } p_alg_enc = $2; p_ext |= SADB_X_EXT_RAWCPI; } ; enc_alg : ALG_ENC_NOKEY { if ($1 < 0) { yyerror("unsupported algorithm"); return -1; } p_alg_enc = $1; p_key_enc_len = 0; p_key_enc = NULL; if (ipsec_check_keylen(SADB_EXT_SUPPORTED_ENCRYPT, p_alg_enc, PFKEY_UNUNIT64(p_key_enc_len)) < 0) { yyerror(ipsec_strerror()); return -1; } } | ALG_ENC key_string { if ($1 < 0) { yyerror("unsupported algorithm"); return -1; } p_alg_enc = $1; p_key_enc_len = $2.len; p_key_enc = $2.buf; if (ipsec_check_keylen(SADB_EXT_SUPPORTED_ENCRYPT, p_alg_enc, PFKEY_UNUNIT64(p_key_enc_len)) < 0) { yyerror(ipsec_strerror()); return -1; } } | ALG_ENC_OLD { if ($1 < 0) { yyerror("unsupported algorithm"); return -1; } yyerror("WARNING: obsolete algorithm"); p_alg_enc = $1; p_key_enc_len = 0; p_key_enc = NULL; if (ipsec_check_keylen(SADB_EXT_SUPPORTED_ENCRYPT, p_alg_enc, PFKEY_UNUNIT64(p_key_enc_len)) < 0) { yyerror(ipsec_strerror()); return -1; } } | ALG_ENC_DESDERIV key_string { if ($1 < 0) { yyerror("unsupported algorithm"); return -1; } p_alg_enc = $1; if (p_ext & SADB_X_EXT_OLD) { yyerror("algorithm mismatched"); return -1; } p_ext |= SADB_X_EXT_DERIV; p_key_enc_len = $2.len; p_key_enc = $2.buf; if (ipsec_check_keylen(SADB_EXT_SUPPORTED_ENCRYPT, p_alg_enc, PFKEY_UNUNIT64(p_key_enc_len)) < 0) { yyerror(ipsec_strerror()); return -1; } } | ALG_ENC_DES32IV key_string { if ($1 < 0) { yyerror("unsupported algorithm"); return -1; } p_alg_enc = $1; if (!(p_ext & SADB_X_EXT_OLD)) { yyerror("algorithm mismatched"); return -1; } p_ext |= SADB_X_EXT_IV4B; p_key_enc_len = $2.len; p_key_enc = $2.buf; if (ipsec_check_keylen(SADB_EXT_SUPPORTED_ENCRYPT, p_alg_enc, PFKEY_UNUNIT64(p_key_enc_len)) < 0) { yyerror(ipsec_strerror()); return -1; } } | ALG_ENC_SALT key_string { if ($1 < 0) { yyerror("unsupported algorithm"); return -1; } p_alg_enc = $1; p_key_enc_len = $2.len; p_key_enc = $2.buf; /* * Salted keys include a 4 byte value that is * not part of the key. */ if (ipsec_check_keylen(SADB_EXT_SUPPORTED_ENCRYPT, p_alg_enc, PFKEY_UNUNIT64(p_key_enc_len - 4)) < 0) { yyerror(ipsec_strerror()); return -1; } } ; auth_alg : ALG_AUTH key_string { if ($1 < 0) { yyerror("unsupported algorithm"); return -1; } p_alg_auth = $1; p_key_auth_len = $2.len; p_key_auth = $2.buf; if (p_alg_auth == SADB_X_AALG_TCP_MD5) { if ((p_key_auth_len < 1) || (p_key_auth_len > 80)) return -1; } else if (ipsec_check_keylen(SADB_EXT_SUPPORTED_AUTH, p_alg_auth, PFKEY_UNUNIT64(p_key_auth_len)) < 0) { yyerror(ipsec_strerror()); return -1; } } | ALG_AUTH_NOKEY { if ($1 < 0) { yyerror("unsupported algorithm"); return -1; } p_alg_auth = $1; p_key_auth_len = 0; p_key_auth = NULL; } ; key_string : QUOTEDSTRING { $$ = $1; } | HEXSTRING { caddr_t pp_key; caddr_t bp; caddr_t yp = $1.buf; int l; l = strlen(yp) % 2 + strlen(yp) / 2; if ((pp_key = malloc(l)) == 0) { yyerror("not enough core"); return -1; } memset(pp_key, 0, l); bp = pp_key; if (strlen(yp) % 2) { *bp = ATOX(yp[0]); yp++, bp++; } while (*yp) { *bp = (ATOX(yp[0]) << 4) | ATOX(yp[1]); yp += 2, bp++; } $$.len = l; $$.buf = pp_key; } ; extension_spec : /*NOTHING*/ | extension_spec extension ; extension : F_EXT EXTENSION { p_ext |= $2; } | F_EXT NOCYCLICSEQ { p_ext &= ~SADB_X_EXT_CYCSEQ; } | F_MODE MODE { p_mode = $2; } | F_MODE ANY { p_mode = IPSEC_MODE_ANY; } | F_REQID DECSTRING { p_reqid = $2; } | F_REPLAY DECSTRING { if ((p_ext & SADB_X_EXT_OLD) != 0) { yyerror("replay prevention cannot be used with " "ah/esp-old"); return -1; } p_replay = $2; + if (p_replay > (UINT32_MAX - 32) >> 3) + yyerror("replay window is too large"); } | F_LIFETIME_HARD DECSTRING { p_lt_hard = $2; } | F_LIFETIME_SOFT DECSTRING { p_lt_soft = $2; } ; /* definition about command for SPD management */ /* spdadd */ spdadd_command : SPDADD ipaddropts STRING prefix portstr STRING prefix portstr upper_spec upper_misc_spec policy_spec EOT { int status; struct addrinfo *src, *dst; /* fixed port fields if ulp is icmpv6 */ if ($10.buf != NULL) { if ($9 != IPPROTO_ICMPV6) return -1; free($5.buf); free($8.buf); if (fix_portstr(&$10, &$5, &$8)) return -1; } src = parse_addr($3.buf, $5.buf); dst = parse_addr($6.buf, $8.buf); if (!src || !dst) { /* yyerror is already called */ return -1; } if (src->ai_next || dst->ai_next) { yyerror("multiple address specified"); freeaddrinfo(src); freeaddrinfo(dst); return -1; } status = setkeymsg_spdaddr(SADB_X_SPDADD, $9, &$11, src, $4, dst, $7); freeaddrinfo(src); freeaddrinfo(dst); if (status < 0) return -1; } | SPDADD TAGGED QUOTEDSTRING policy_spec EOT { return -1; } ; spddelete_command : SPDDELETE ipaddropts STRING prefix portstr STRING prefix portstr upper_spec upper_misc_spec policy_spec EOT { int status; struct addrinfo *src, *dst; /* fixed port fields if ulp is icmpv6 */ if ($10.buf != NULL) { if ($9 != IPPROTO_ICMPV6) return -1; free($5.buf); free($8.buf); if (fix_portstr(&$10, &$5, &$8)) return -1; } src = parse_addr($3.buf, $5.buf); dst = parse_addr($6.buf, $8.buf); if (!src || !dst) { /* yyerror is already called */ return -1; } if (src->ai_next || dst->ai_next) { yyerror("multiple address specified"); freeaddrinfo(src); freeaddrinfo(dst); return -1; } status = setkeymsg_spdaddr(SADB_X_SPDDELETE, $9, &$11, src, $4, dst, $7); freeaddrinfo(src); freeaddrinfo(dst); if (status < 0) return -1; } ; spddump_command: SPDDUMP EOT { struct sadb_msg msg; setkeymsg0(&msg, SADB_X_SPDDUMP, SADB_SATYPE_UNSPEC, sizeof(msg)); sendkeymsg((char *)&msg, sizeof(msg)); } ; spdflush_command: SPDFLUSH EOT { struct sadb_msg msg; setkeymsg0(&msg, SADB_X_SPDFLUSH, SADB_SATYPE_UNSPEC, sizeof(msg)); sendkeymsg((char *)&msg, sizeof(msg)); } ; ipaddropts : /* nothing */ | ipaddropts ipaddropt ; ipaddropt : F_AIFLAGS { char *p; for (p = $1.buf + 1; *p; p++) switch (*p) { case '4': p_aifamily = AF_INET; break; #ifdef INET6 case '6': p_aifamily = AF_INET6; break; #endif case 'n': p_aiflags = AI_NUMERICHOST; break; default: yyerror("invalid flag"); return -1; } } ; ipaddr : STRING { $$ = parse_addr($1.buf, NULL); if ($$ == NULL) { /* yyerror already called by parse_addr */ return -1; } } ; prefix : /*NOTHING*/ { $$ = -1; } | SLASH DECSTRING { $$ = $2; } ; portstr : /*NOTHING*/ { $$.buf = strdup("0"); if (!$$.buf) { yyerror("insufficient memory"); return -1; } $$.len = strlen($$.buf); } | BLCL ANY ELCL { $$.buf = strdup("0"); if (!$$.buf) { yyerror("insufficient memory"); return -1; } $$.len = strlen($$.buf); } | BLCL DECSTRING ELCL { char buf[20]; snprintf(buf, sizeof(buf), "%lu", $2); $$.buf = strdup(buf); if (!$$.buf) { yyerror("insufficient memory"); return -1; } $$.len = strlen($$.buf); } | BLCL STRING ELCL { $$ = $2; } ; upper_spec : DECSTRING { $$ = $1; } | ANY { $$ = IPSEC_ULPROTO_ANY; } | PR_TCP { $$ = IPPROTO_TCP; } | PR_ESP { $$ = IPPROTO_ESP; } | STRING { struct protoent *ent; ent = getprotobyname($1.buf); if (ent) $$ = ent->p_proto; else { if (strcmp("icmp6", $1.buf) == 0) { $$ = IPPROTO_ICMPV6; } else if(strcmp("ip4", $1.buf) == 0) { $$ = IPPROTO_IPV4; } else { yyerror("invalid upper layer protocol"); return -1; } } endprotoent(); } ; upper_misc_spec : /*NOTHING*/ { $$.buf = NULL; $$.len = 0; } | STRING { $$.buf = strdup($1.buf); if (!$$.buf) { yyerror("insufficient memory"); return -1; } $$.len = strlen($$.buf); } ; policy_spec : F_POLICY policy_requests { char *policy; policy = ipsec_set_policy($2.buf, $2.len); if (policy == NULL) { yyerror(ipsec_strerror()); return -1; } $$.buf = policy; $$.len = ipsec_get_policylen(policy); } ; policy_requests : PL_REQUESTS { $$ = $1; } ; %% int setkeymsg0(msg, type, satype, l) struct sadb_msg *msg; unsigned int type; unsigned int satype; size_t l; { msg->sadb_msg_version = PF_KEY_V2; msg->sadb_msg_type = type; msg->sadb_msg_errno = 0; msg->sadb_msg_satype = satype; msg->sadb_msg_reserved = 0; msg->sadb_msg_seq = 0; msg->sadb_msg_pid = getpid(); msg->sadb_msg_len = PFKEY_UNIT64(l); return 0; } /* XXX NO BUFFER OVERRUN CHECK! BAD BAD! */ static int setkeymsg_spdaddr(type, upper, policy, srcs, splen, dsts, dplen) unsigned int type; unsigned int upper; vchar_t *policy; struct addrinfo *srcs; int splen; struct addrinfo *dsts; int dplen; { struct sadb_msg *msg; char buf[BUFSIZ]; int l, l0; struct sadb_address m_addr; struct addrinfo *s, *d; int n; int plen; struct sockaddr *sa; int salen; msg = (struct sadb_msg *)buf; if (!srcs || !dsts) return -1; /* fix up length afterwards */ setkeymsg0(msg, type, SADB_SATYPE_UNSPEC, 0); l = sizeof(struct sadb_msg); memcpy(buf + l, policy->buf, policy->len); l += policy->len; l0 = l; n = 0; /* do it for all src/dst pairs */ for (s = srcs; s; s = s->ai_next) { for (d = dsts; d; d = d->ai_next) { /* rewind pointer */ l = l0; if (s->ai_addr->sa_family != d->ai_addr->sa_family) continue; switch (s->ai_addr->sa_family) { case AF_INET: plen = sizeof(struct in_addr) << 3; break; #ifdef INET6 case AF_INET6: plen = sizeof(struct in6_addr) << 3; break; #endif default: continue; } /* set src */ sa = s->ai_addr; salen = s->ai_addr->sa_len; m_addr.sadb_address_len = PFKEY_UNIT64(sizeof(m_addr) + PFKEY_ALIGN8(salen)); m_addr.sadb_address_exttype = SADB_EXT_ADDRESS_SRC; m_addr.sadb_address_proto = upper; m_addr.sadb_address_prefixlen = (splen >= 0 ? splen : plen); m_addr.sadb_address_reserved = 0; setvarbuf(buf, &l, (struct sadb_ext *)&m_addr, sizeof(m_addr), (caddr_t)sa, salen); /* set dst */ sa = d->ai_addr; salen = d->ai_addr->sa_len; m_addr.sadb_address_len = PFKEY_UNIT64(sizeof(m_addr) + PFKEY_ALIGN8(salen)); m_addr.sadb_address_exttype = SADB_EXT_ADDRESS_DST; m_addr.sadb_address_proto = upper; m_addr.sadb_address_prefixlen = (dplen >= 0 ? dplen : plen); m_addr.sadb_address_reserved = 0; setvarbuf(buf, &l, (struct sadb_ext *)&m_addr, sizeof(m_addr), (caddr_t)sa, salen); msg->sadb_msg_len = PFKEY_UNIT64(l); sendkeymsg(buf, l); n++; } } if (n == 0) return -1; else return 0; } /* XXX NO BUFFER OVERRUN CHECK! BAD BAD! */ static int setkeymsg_addr(type, satype, srcs, dsts, no_spi) unsigned int type; unsigned int satype; struct addrinfo *srcs; struct addrinfo *dsts; int no_spi; { struct sadb_msg *msg; char buf[BUFSIZ]; int l, l0, len; struct sadb_sa m_sa; struct sadb_x_sa2 m_sa2; + struct sadb_x_sa_replay m_replay; struct sadb_address m_addr; struct addrinfo *s, *d; int n; int plen; struct sockaddr *sa; int salen; msg = (struct sadb_msg *)buf; if (!srcs || !dsts) return -1; /* fix up length afterwards */ setkeymsg0(msg, type, satype, 0); l = sizeof(struct sadb_msg); if (!no_spi) { len = sizeof(struct sadb_sa); m_sa.sadb_sa_len = PFKEY_UNIT64(len); m_sa.sadb_sa_exttype = SADB_EXT_SA; m_sa.sadb_sa_spi = htonl(p_spi); - m_sa.sadb_sa_replay = p_replay; + m_sa.sadb_sa_replay = p_replay > UINT8_MAX ? UINT8_MAX: + p_replay; m_sa.sadb_sa_state = 0; m_sa.sadb_sa_auth = p_alg_auth; m_sa.sadb_sa_encrypt = p_alg_enc; m_sa.sadb_sa_flags = p_ext; memcpy(buf + l, &m_sa, len); l += len; len = sizeof(struct sadb_x_sa2); m_sa2.sadb_x_sa2_len = PFKEY_UNIT64(len); m_sa2.sadb_x_sa2_exttype = SADB_X_EXT_SA2; m_sa2.sadb_x_sa2_mode = p_mode; m_sa2.sadb_x_sa2_reqid = p_reqid; memcpy(buf + l, &m_sa2, len); l += len; + + if (p_replay > UINT8_MAX) { + len = sizeof(struct sadb_x_sa_replay); + m_replay.sadb_x_sa_replay_len = PFKEY_UNIT64(len); + m_replay.sadb_x_sa_replay_exttype = + SADB_X_EXT_SA_REPLAY; + m_replay.sadb_x_sa_replay_replay = p_replay << 3; + + memcpy(buf + l, &m_replay, len); + l += len; + } } l0 = l; n = 0; /* do it for all src/dst pairs */ for (s = srcs; s; s = s->ai_next) { for (d = dsts; d; d = d->ai_next) { /* rewind pointer */ l = l0; if (s->ai_addr->sa_family != d->ai_addr->sa_family) continue; switch (s->ai_addr->sa_family) { case AF_INET: plen = sizeof(struct in_addr) << 3; break; #ifdef INET6 case AF_INET6: plen = sizeof(struct in6_addr) << 3; break; #endif default: continue; } /* set src */ sa = s->ai_addr; salen = s->ai_addr->sa_len; m_addr.sadb_address_len = PFKEY_UNIT64(sizeof(m_addr) + PFKEY_ALIGN8(salen)); m_addr.sadb_address_exttype = SADB_EXT_ADDRESS_SRC; m_addr.sadb_address_proto = IPSEC_ULPROTO_ANY; m_addr.sadb_address_prefixlen = plen; m_addr.sadb_address_reserved = 0; setvarbuf(buf, &l, (struct sadb_ext *)&m_addr, sizeof(m_addr), (caddr_t)sa, salen); /* set dst */ sa = d->ai_addr; salen = d->ai_addr->sa_len; m_addr.sadb_address_len = PFKEY_UNIT64(sizeof(m_addr) + PFKEY_ALIGN8(salen)); m_addr.sadb_address_exttype = SADB_EXT_ADDRESS_DST; m_addr.sadb_address_proto = IPSEC_ULPROTO_ANY; m_addr.sadb_address_prefixlen = plen; m_addr.sadb_address_reserved = 0; setvarbuf(buf, &l, (struct sadb_ext *)&m_addr, sizeof(m_addr), (caddr_t)sa, salen); msg->sadb_msg_len = PFKEY_UNIT64(l); sendkeymsg(buf, l); n++; } } if (n == 0) return -1; else return 0; } /* XXX NO BUFFER OVERRUN CHECK! BAD BAD! */ static int setkeymsg_add(type, satype, srcs, dsts) unsigned int type; unsigned int satype; struct addrinfo *srcs; struct addrinfo *dsts; { struct sadb_msg *msg; char buf[BUFSIZ]; int l, l0, len; struct sadb_sa m_sa; struct sadb_x_sa2 m_sa2; struct sadb_address m_addr; + struct sadb_x_sa_replay m_replay; struct addrinfo *s, *d; int n; int plen; struct sockaddr *sa; int salen; msg = (struct sadb_msg *)buf; if (!srcs || !dsts) return -1; /* fix up length afterwards */ setkeymsg0(msg, type, satype, 0); l = sizeof(struct sadb_msg); /* set encryption algorithm, if present. */ if (satype != SADB_X_SATYPE_IPCOMP && p_key_enc) { struct sadb_key m_key; m_key.sadb_key_len = PFKEY_UNIT64(sizeof(m_key) + PFKEY_ALIGN8(p_key_enc_len)); m_key.sadb_key_exttype = SADB_EXT_KEY_ENCRYPT; m_key.sadb_key_bits = p_key_enc_len * 8; m_key.sadb_key_reserved = 0; setvarbuf(buf, &l, (struct sadb_ext *)&m_key, sizeof(m_key), (caddr_t)p_key_enc, p_key_enc_len); } /* set authentication algorithm, if present. */ if (p_key_auth) { struct sadb_key m_key; m_key.sadb_key_len = PFKEY_UNIT64(sizeof(m_key) + PFKEY_ALIGN8(p_key_auth_len)); m_key.sadb_key_exttype = SADB_EXT_KEY_AUTH; m_key.sadb_key_bits = p_key_auth_len * 8; m_key.sadb_key_reserved = 0; setvarbuf(buf, &l, (struct sadb_ext *)&m_key, sizeof(m_key), (caddr_t)p_key_auth, p_key_auth_len); } /* set lifetime for HARD */ if (p_lt_hard != 0) { struct sadb_lifetime m_lt; u_int slen = sizeof(struct sadb_lifetime); m_lt.sadb_lifetime_len = PFKEY_UNIT64(slen); m_lt.sadb_lifetime_exttype = SADB_EXT_LIFETIME_HARD; m_lt.sadb_lifetime_allocations = 0; m_lt.sadb_lifetime_bytes = 0; m_lt.sadb_lifetime_addtime = p_lt_hard; m_lt.sadb_lifetime_usetime = 0; memcpy(buf + l, &m_lt, slen); l += slen; } /* set lifetime for SOFT */ if (p_lt_soft != 0) { struct sadb_lifetime m_lt; u_int slen = sizeof(struct sadb_lifetime); m_lt.sadb_lifetime_len = PFKEY_UNIT64(slen); m_lt.sadb_lifetime_exttype = SADB_EXT_LIFETIME_SOFT; m_lt.sadb_lifetime_allocations = 0; m_lt.sadb_lifetime_bytes = 0; m_lt.sadb_lifetime_addtime = p_lt_soft; m_lt.sadb_lifetime_usetime = 0; memcpy(buf + l, &m_lt, slen); l += slen; } len = sizeof(struct sadb_sa); m_sa.sadb_sa_len = PFKEY_UNIT64(len); m_sa.sadb_sa_exttype = SADB_EXT_SA; m_sa.sadb_sa_spi = htonl(p_spi); - m_sa.sadb_sa_replay = p_replay; + m_sa.sadb_sa_replay = p_replay > UINT8_MAX ? UINT8_MAX: p_replay; m_sa.sadb_sa_state = 0; m_sa.sadb_sa_auth = p_alg_auth; m_sa.sadb_sa_encrypt = p_alg_enc; m_sa.sadb_sa_flags = p_ext; memcpy(buf + l, &m_sa, len); l += len; len = sizeof(struct sadb_x_sa2); m_sa2.sadb_x_sa2_len = PFKEY_UNIT64(len); m_sa2.sadb_x_sa2_exttype = SADB_X_EXT_SA2; m_sa2.sadb_x_sa2_mode = p_mode; m_sa2.sadb_x_sa2_reqid = p_reqid; memcpy(buf + l, &m_sa2, len); l += len; + if (p_replay > UINT8_MAX) { + len = sizeof(struct sadb_x_sa_replay); + m_replay.sadb_x_sa_replay_len = PFKEY_UNIT64(len); + m_replay.sadb_x_sa_replay_exttype = SADB_X_EXT_SA_REPLAY; + m_replay.sadb_x_sa_replay_replay = p_replay << 3; + + memcpy(buf + l, &m_replay, len); + l += len; + } l0 = l; n = 0; /* do it for all src/dst pairs */ for (s = srcs; s; s = s->ai_next) { for (d = dsts; d; d = d->ai_next) { /* rewind pointer */ l = l0; if (s->ai_addr->sa_family != d->ai_addr->sa_family) continue; switch (s->ai_addr->sa_family) { case AF_INET: plen = sizeof(struct in_addr) << 3; break; #ifdef INET6 case AF_INET6: plen = sizeof(struct in6_addr) << 3; break; #endif default: continue; } /* set src */ sa = s->ai_addr; salen = s->ai_addr->sa_len; m_addr.sadb_address_len = PFKEY_UNIT64(sizeof(m_addr) + PFKEY_ALIGN8(salen)); m_addr.sadb_address_exttype = SADB_EXT_ADDRESS_SRC; m_addr.sadb_address_proto = IPSEC_ULPROTO_ANY; m_addr.sadb_address_prefixlen = plen; m_addr.sadb_address_reserved = 0; setvarbuf(buf, &l, (struct sadb_ext *)&m_addr, sizeof(m_addr), (caddr_t)sa, salen); /* set dst */ sa = d->ai_addr; salen = d->ai_addr->sa_len; m_addr.sadb_address_len = PFKEY_UNIT64(sizeof(m_addr) + PFKEY_ALIGN8(salen)); m_addr.sadb_address_exttype = SADB_EXT_ADDRESS_DST; m_addr.sadb_address_proto = IPSEC_ULPROTO_ANY; m_addr.sadb_address_prefixlen = plen; m_addr.sadb_address_reserved = 0; setvarbuf(buf, &l, (struct sadb_ext *)&m_addr, sizeof(m_addr), (caddr_t)sa, salen); msg->sadb_msg_len = PFKEY_UNIT64(l); sendkeymsg(buf, l); n++; } } if (n == 0) return -1; else return 0; } static struct addrinfo * parse_addr(host, port) char *host; char *port; { struct addrinfo hints, *res = NULL; int error; memset(&hints, 0, sizeof(hints)); hints.ai_family = p_aifamily; hints.ai_socktype = SOCK_DGRAM; /*dummy*/ hints.ai_protocol = IPPROTO_UDP; /*dummy*/ hints.ai_flags = p_aiflags; error = getaddrinfo(host, port, &hints, &res); if (error != 0) { yyerror(gai_strerror(error)); return NULL; } return res; } static int fix_portstr(spec, sport, dport) vchar_t *spec, *sport, *dport; { char *p, *p2; u_int l; l = 0; for (p = spec->buf; *p != ',' && *p != '\0' && l < spec->len; p++, l++) ; if (*p == '\0') { p2 = "0"; } else { if (*p == ',') { *p = '\0'; p2 = ++p; } for (p = p2; *p != '\0' && l < spec->len; p++, l++) ; if (*p != '\0' || *p2 == '\0') { yyerror("invalid an upper layer protocol spec"); return -1; } } sport->buf = strdup(spec->buf); if (!sport->buf) { yyerror("insufficient memory"); return -1; } sport->len = strlen(sport->buf); dport->buf = strdup(p2); if (!dport->buf) { yyerror("insufficient memory"); return -1; } dport->len = strlen(dport->buf); return 0; } static int setvarbuf(buf, off, ebuf, elen, vbuf, vlen) char *buf; int *off; struct sadb_ext *ebuf; int elen; caddr_t vbuf; int vlen; { memset(buf + *off, 0, PFKEY_UNUNIT64(ebuf->sadb_ext_len)); memcpy(buf + *off, (caddr_t)ebuf, elen); memcpy(buf + *off + elen, vbuf, vlen); (*off) += PFKEY_ALIGN8(elen + vlen); return 0; } void parse_init() { p_spi = 0; p_ext = SADB_X_EXT_CYCSEQ; p_alg_enc = SADB_EALG_NONE; p_alg_auth = SADB_AALG_NONE; p_mode = IPSEC_MODE_ANY; p_reqid = 0; p_replay = 0; p_key_enc_len = p_key_auth_len = 0; p_key_enc = p_key_auth = 0; p_lt_hard = p_lt_soft = 0; p_aiflags = 0; p_aifamily = PF_UNSPEC; return; } void free_buffer() { /* we got tons of memory leaks in the parser anyways, leave them */ return; } Index: head/sys/netipsec/key_debug.c =================================================================== --- head/sys/netipsec/key_debug.c (revision 316758) +++ head/sys/netipsec/key_debug.c (revision 316759) @@ -1,915 +1,968 @@ /* $FreeBSD$ */ /* $KAME: key_debug.c,v 1.26 2001/06/27 10:46:50 sakane Exp $ */ /*- * Copyright (C) 1995, 1996, 1997, and 1998 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. */ #ifdef _KERNEL #include "opt_inet.h" #include "opt_inet6.h" #include "opt_ipsec.h" #endif #include #ifdef _KERNEL #include #include #include #include #include #include #endif #include #include #include #include #include #include #ifdef _KERNEL #include #include #endif #ifndef _KERNEL #include #include #include +#include #endif /* !_KERNEL */ static void kdebug_sadb_prop(struct sadb_ext *); static void kdebug_sadb_identity(struct sadb_ext *); static void kdebug_sadb_supported(struct sadb_ext *); static void kdebug_sadb_lifetime(struct sadb_ext *); static void kdebug_sadb_sa(struct sadb_ext *); static void kdebug_sadb_address(struct sadb_ext *); static void kdebug_sadb_key(struct sadb_ext *); static void kdebug_sadb_x_sa2(struct sadb_ext *); +static void kdebug_sadb_x_sa_replay(struct sadb_ext *); +static void kdebug_sadb_x_natt(struct sadb_ext *); #ifdef _KERNEL static void kdebug_secreplay(struct secreplay *); #endif #ifndef _KERNEL #define panic(fmt, ...) { printf(fmt, ## __VA_ARGS__); exit(-1); } #endif /* NOTE: host byte order */ /* %%%: about struct sadb_msg */ void kdebug_sadb(struct sadb_msg *base) { struct sadb_ext *ext; int tlen, extlen; /* sanity check */ if (base == NULL) panic("%s: NULL pointer was passed.\n", __func__); printf("sadb_msg{ version=%u type=%u errno=%u satype=%u\n", base->sadb_msg_version, base->sadb_msg_type, base->sadb_msg_errno, base->sadb_msg_satype); printf(" len=%u reserved=%u seq=%u pid=%u\n", base->sadb_msg_len, base->sadb_msg_reserved, base->sadb_msg_seq, base->sadb_msg_pid); tlen = PFKEY_UNUNIT64(base->sadb_msg_len) - sizeof(struct sadb_msg); ext = (struct sadb_ext *)((caddr_t)base + sizeof(struct sadb_msg)); while (tlen > 0) { printf("sadb_ext{ len=%u type=%u }\n", ext->sadb_ext_len, ext->sadb_ext_type); if (ext->sadb_ext_len == 0) { printf("%s: invalid ext_len=0 was passed.\n", __func__); return; } if (ext->sadb_ext_len > tlen) { printf("%s: ext_len too big (%u > %u).\n", __func__, ext->sadb_ext_len, tlen); return; } switch (ext->sadb_ext_type) { case SADB_EXT_SA: kdebug_sadb_sa(ext); break; case SADB_EXT_LIFETIME_CURRENT: case SADB_EXT_LIFETIME_HARD: case SADB_EXT_LIFETIME_SOFT: kdebug_sadb_lifetime(ext); break; case SADB_EXT_ADDRESS_SRC: case SADB_EXT_ADDRESS_DST: case SADB_EXT_ADDRESS_PROXY: + case SADB_X_EXT_NAT_T_OAI: + case SADB_X_EXT_NAT_T_OAR: + case SADB_X_EXT_NEW_ADDRESS_SRC: + case SADB_X_EXT_NEW_ADDRESS_DST: kdebug_sadb_address(ext); break; case SADB_EXT_KEY_AUTH: case SADB_EXT_KEY_ENCRYPT: kdebug_sadb_key(ext); break; case SADB_EXT_IDENTITY_SRC: case SADB_EXT_IDENTITY_DST: kdebug_sadb_identity(ext); break; case SADB_EXT_SENSITIVITY: break; case SADB_EXT_PROPOSAL: kdebug_sadb_prop(ext); break; case SADB_EXT_SUPPORTED_AUTH: case SADB_EXT_SUPPORTED_ENCRYPT: kdebug_sadb_supported(ext); break; case SADB_EXT_SPIRANGE: case SADB_X_EXT_KMPRIVATE: break; case SADB_X_EXT_POLICY: kdebug_sadb_x_policy(ext); break; case SADB_X_EXT_SA2: kdebug_sadb_x_sa2(ext); break; + case SADB_X_EXT_SA_REPLAY: + kdebug_sadb_x_sa_replay(ext); + break; + case SADB_X_EXT_NAT_T_TYPE: + case SADB_X_EXT_NAT_T_SPORT: + case SADB_X_EXT_NAT_T_DPORT: + kdebug_sadb_x_natt(ext); + break; default: printf("%s: invalid ext_type %u\n", __func__, ext->sadb_ext_type); return; } extlen = PFKEY_UNUNIT64(ext->sadb_ext_len); tlen -= extlen; ext = (struct sadb_ext *)((caddr_t)ext + extlen); } return; } static void kdebug_sadb_prop(struct sadb_ext *ext) { struct sadb_prop *prop = (struct sadb_prop *)ext; struct sadb_comb *comb; int len; /* sanity check */ if (ext == NULL) panic("%s: NULL pointer was passed.\n", __func__); len = (PFKEY_UNUNIT64(prop->sadb_prop_len) - sizeof(*prop)) / sizeof(*comb); comb = (struct sadb_comb *)(prop + 1); printf("sadb_prop{ replay=%u\n", prop->sadb_prop_replay); while (len--) { printf("sadb_comb{ auth=%u encrypt=%u " "flags=0x%04x reserved=0x%08x\n", comb->sadb_comb_auth, comb->sadb_comb_encrypt, comb->sadb_comb_flags, comb->sadb_comb_reserved); printf(" auth_minbits=%u auth_maxbits=%u " "encrypt_minbits=%u encrypt_maxbits=%u\n", comb->sadb_comb_auth_minbits, comb->sadb_comb_auth_maxbits, comb->sadb_comb_encrypt_minbits, comb->sadb_comb_encrypt_maxbits); printf(" soft_alloc=%u hard_alloc=%u " "soft_bytes=%lu hard_bytes=%lu\n", comb->sadb_comb_soft_allocations, comb->sadb_comb_hard_allocations, (unsigned long)comb->sadb_comb_soft_bytes, (unsigned long)comb->sadb_comb_hard_bytes); printf(" soft_alloc=%lu hard_alloc=%lu " "soft_bytes=%lu hard_bytes=%lu }\n", (unsigned long)comb->sadb_comb_soft_addtime, (unsigned long)comb->sadb_comb_hard_addtime, (unsigned long)comb->sadb_comb_soft_usetime, (unsigned long)comb->sadb_comb_hard_usetime); comb++; } printf("}\n"); return; } static void kdebug_sadb_identity(struct sadb_ext *ext) { struct sadb_ident *id = (struct sadb_ident *)ext; int len; /* sanity check */ if (ext == NULL) panic("%s: NULL pointer was passed.\n", __func__); len = PFKEY_UNUNIT64(id->sadb_ident_len) - sizeof(*id); printf("sadb_ident_%s{", id->sadb_ident_exttype == SADB_EXT_IDENTITY_SRC ? "src" : "dst"); switch (id->sadb_ident_type) { default: printf(" type=%d id=%lu", id->sadb_ident_type, (u_long)id->sadb_ident_id); if (len) { #ifdef _KERNEL ipsec_hexdump((caddr_t)(id + 1), len); /*XXX cast ?*/ #else char *p, *ep; printf("\n str=\""); p = (char *)(id + 1); ep = p + len; for (/*nothing*/; *p && p < ep; p++) { if (isprint(*p)) printf("%c", *p & 0xff); else printf("\\%03o", *p & 0xff); } #endif printf("\""); } break; } printf(" }\n"); return; } static void kdebug_sadb_supported(struct sadb_ext *ext) { struct sadb_supported *sup = (struct sadb_supported *)ext; struct sadb_alg *alg; int len; /* sanity check */ if (ext == NULL) panic("%s: NULL pointer was passed.\n", __func__); len = (PFKEY_UNUNIT64(sup->sadb_supported_len) - sizeof(*sup)) / sizeof(*alg); alg = (struct sadb_alg *)(sup + 1); printf("sadb_sup{\n"); while (len--) { printf(" { id=%d ivlen=%d min=%d max=%d }\n", alg->sadb_alg_id, alg->sadb_alg_ivlen, alg->sadb_alg_minbits, alg->sadb_alg_maxbits); alg++; } printf("}\n"); return; } static void kdebug_sadb_lifetime(struct sadb_ext *ext) { struct sadb_lifetime *lft = (struct sadb_lifetime *)ext; /* sanity check */ if (ext == NULL) panic("%s: NULL pointer was passed.\n", __func__); printf("sadb_lifetime{ alloc=%u, bytes=%u\n", lft->sadb_lifetime_allocations, (u_int32_t)lft->sadb_lifetime_bytes); printf(" addtime=%u, usetime=%u }\n", (u_int32_t)lft->sadb_lifetime_addtime, (u_int32_t)lft->sadb_lifetime_usetime); return; } static void kdebug_sadb_sa(struct sadb_ext *ext) { struct sadb_sa *sa = (struct sadb_sa *)ext; /* sanity check */ if (ext == NULL) panic("%s: NULL pointer was passed.\n", __func__); printf("sadb_sa{ spi=%u replay=%u state=%u\n", (u_int32_t)ntohl(sa->sadb_sa_spi), sa->sadb_sa_replay, sa->sadb_sa_state); printf(" auth=%u encrypt=%u flags=0x%08x }\n", sa->sadb_sa_auth, sa->sadb_sa_encrypt, sa->sadb_sa_flags); return; } static void kdebug_sadb_address(struct sadb_ext *ext) { struct sadb_address *addr = (struct sadb_address *)ext; /* sanity check */ if (ext == NULL) panic("%s: NULL pointer was passed.\n", __func__); printf("sadb_address{ proto=%u prefixlen=%u reserved=0x%02x%02x }\n", addr->sadb_address_proto, addr->sadb_address_prefixlen, ((u_char *)&addr->sadb_address_reserved)[0], ((u_char *)&addr->sadb_address_reserved)[1]); kdebug_sockaddr((struct sockaddr *)((caddr_t)ext + sizeof(*addr))); - - return; } static void kdebug_sadb_key(struct sadb_ext *ext) { struct sadb_key *key = (struct sadb_key *)ext; /* sanity check */ if (ext == NULL) panic("%s: NULL pointer was passed.\n", __func__); printf("sadb_key{ bits=%u reserved=%u\n", key->sadb_key_bits, key->sadb_key_reserved); printf(" key="); /* sanity check 2 */ if ((key->sadb_key_bits >> 3) > (PFKEY_UNUNIT64(key->sadb_key_len) - sizeof(struct sadb_key))) { printf("%s: key length mismatch, bit:%d len:%ld.\n", __func__, key->sadb_key_bits >> 3, (long)PFKEY_UNUNIT64(key->sadb_key_len) - sizeof(struct sadb_key)); } ipsec_hexdump((caddr_t)key + sizeof(struct sadb_key), key->sadb_key_bits >> 3); printf(" }\n"); return; } static void kdebug_sadb_x_sa2(struct sadb_ext *ext) { struct sadb_x_sa2 *sa2 = (struct sadb_x_sa2 *)ext; /* sanity check */ if (ext == NULL) panic("%s: NULL pointer was passed.\n", __func__); printf("sadb_x_sa2{ mode=%u reqid=%u\n", sa2->sadb_x_sa2_mode, sa2->sadb_x_sa2_reqid); printf(" reserved1=%u reserved2=%u sequence=%u }\n", sa2->sadb_x_sa2_reserved1, sa2->sadb_x_sa2_reserved2, sa2->sadb_x_sa2_sequence); return; } +static void +kdebug_sadb_x_sa_replay(struct sadb_ext *ext) +{ + struct sadb_x_sa_replay *replay; + + /* sanity check */ + if (ext == NULL) + panic("%s: NULL pointer was passed.\n", __func__); + + replay = (struct sadb_x_sa_replay *)ext; + printf("sadb_x_sa_replay{ replay=%u }\n", + replay->sadb_x_sa_replay_replay); +} + +static void +kdebug_sadb_x_natt(struct sadb_ext *ext) +{ + struct sadb_x_nat_t_type *type; + struct sadb_x_nat_t_port *port; + + /* sanity check */ + if (ext == NULL) + panic("%s: NULL pointer was passed.\n", __func__); + + if (ext->sadb_ext_type == SADB_X_EXT_NAT_T_TYPE) { + type = (struct sadb_x_nat_t_type *)ext; + printf("sadb_x_nat_t_type{ type=%u }\n", + type->sadb_x_nat_t_type_type); + } else { + port = (struct sadb_x_nat_t_port *)ext; + printf("sadb_x_nat_t_port{ port=%u }\n", + ntohs(port->sadb_x_nat_t_port_port)); + } +} + void kdebug_sadb_x_policy(struct sadb_ext *ext) { struct sadb_x_policy *xpl = (struct sadb_x_policy *)ext; struct sockaddr *addr; /* sanity check */ if (ext == NULL) panic("%s: NULL pointer was passed.\n", __func__); - printf("sadb_x_policy{ type=%u dir=%u id=%x }\n", + printf("sadb_x_policy{ type=%u dir=%u id=%x scope=%u %s=%u }\n", xpl->sadb_x_policy_type, xpl->sadb_x_policy_dir, - xpl->sadb_x_policy_id); + xpl->sadb_x_policy_id, xpl->sadb_x_policy_scope, + xpl->sadb_x_policy_scope == IPSEC_POLICYSCOPE_IFNET ? + "ifindex": "priority", xpl->sadb_x_policy_priority); if (xpl->sadb_x_policy_type == IPSEC_POLICY_IPSEC) { int tlen; struct sadb_x_ipsecrequest *xisr; tlen = PFKEY_UNUNIT64(xpl->sadb_x_policy_len) - sizeof(*xpl); xisr = (struct sadb_x_ipsecrequest *)(xpl + 1); while (tlen > 0) { printf(" { len=%u proto=%u mode=%u level=%u reqid=%u\n", xisr->sadb_x_ipsecrequest_len, xisr->sadb_x_ipsecrequest_proto, xisr->sadb_x_ipsecrequest_mode, xisr->sadb_x_ipsecrequest_level, xisr->sadb_x_ipsecrequest_reqid); if (xisr->sadb_x_ipsecrequest_len > sizeof(*xisr)) { addr = (struct sockaddr *)(xisr + 1); kdebug_sockaddr(addr); addr = (struct sockaddr *)((caddr_t)addr + addr->sa_len); kdebug_sockaddr(addr); } printf(" }\n"); /* prevent infinite loop */ if (xisr->sadb_x_ipsecrequest_len <= 0) { printf("%s: wrong policy struct.\n", __func__); return; } /* prevent overflow */ if (xisr->sadb_x_ipsecrequest_len > tlen) { printf("%s: invalid ipsec policy length " "(%u > %u)\n", __func__, xisr->sadb_x_ipsecrequest_len, tlen); return; } tlen -= xisr->sadb_x_ipsecrequest_len; xisr = (struct sadb_x_ipsecrequest *)((caddr_t)xisr + xisr->sadb_x_ipsecrequest_len); } if (tlen != 0) panic("%s: wrong policy struct.\n", __func__); } return; } #ifdef _KERNEL /* %%%: about SPD and SAD */ const char* kdebug_secpolicy_state(u_int state) { switch (state) { case IPSEC_SPSTATE_DEAD: return ("dead"); case IPSEC_SPSTATE_LARVAL: return ("larval"); case IPSEC_SPSTATE_ALIVE: return ("alive"); case IPSEC_SPSTATE_PCB: return ("pcb"); case IPSEC_SPSTATE_IFNET: return ("ifnet"); } return ("unknown"); } const char* kdebug_secpolicy_policy(u_int policy) { switch (policy) { case IPSEC_POLICY_DISCARD: return ("discard"); case IPSEC_POLICY_NONE: return ("none"); case IPSEC_POLICY_IPSEC: return ("ipsec"); case IPSEC_POLICY_ENTRUST: return ("entrust"); case IPSEC_POLICY_BYPASS: return ("bypass"); } return ("unknown"); } const char* kdebug_secpolicyindex_dir(u_int dir) { switch (dir) { case IPSEC_DIR_ANY: return ("any"); case IPSEC_DIR_INBOUND: return ("in"); case IPSEC_DIR_OUTBOUND: return ("out"); } return ("unknown"); } const char* kdebug_ipsecrequest_level(u_int level) { switch (level) { case IPSEC_LEVEL_DEFAULT: return ("default"); case IPSEC_LEVEL_USE: return ("use"); case IPSEC_LEVEL_REQUIRE: return ("require"); case IPSEC_LEVEL_UNIQUE: return ("unique"); } return ("unknown"); } const char* kdebug_secasindex_mode(u_int mode) { switch (mode) { case IPSEC_MODE_ANY: return ("any"); case IPSEC_MODE_TRANSPORT: return ("transport"); case IPSEC_MODE_TUNNEL: return ("tunnel"); case IPSEC_MODE_TCPMD5: return ("tcp-md5"); } return ("unknown"); } const char* kdebug_secasv_state(u_int state) { switch (state) { case SADB_SASTATE_LARVAL: return ("larval"); case SADB_SASTATE_MATURE: return ("mature"); case SADB_SASTATE_DYING: return ("dying"); case SADB_SASTATE_DEAD: return ("dead"); } return ("unknown"); } static char* kdebug_port2str(const struct sockaddr *sa, char *buf, size_t len) { uint16_t port; IPSEC_ASSERT(sa != NULL, ("null sa")); switch (sa->sa_family) { #ifdef INET case AF_INET: port = ntohs(((const struct sockaddr_in *)sa)->sin_port); break; #endif #ifdef INET6 case AF_INET6: port = ntohs(((const struct sockaddr_in6 *)sa)->sin6_port); break; #endif default: port = 0; } if (port == 0) return ("*"); snprintf(buf, len, "%u", port); return (buf); } void kdebug_secpolicy(struct secpolicy *sp) { u_int idx; IPSEC_ASSERT(sp != NULL, ("null sp")); printf("SP { refcnt=%u id=%u priority=%u state=%s policy=%s\n", sp->refcnt, sp->id, sp->priority, kdebug_secpolicy_state(sp->state), kdebug_secpolicy_policy(sp->policy)); kdebug_secpolicyindex(&sp->spidx, " "); for (idx = 0; idx < sp->tcount; idx++) { printf(" req[%u]{ level=%s ", idx, kdebug_ipsecrequest_level(sp->req[idx]->level)); kdebug_secasindex(&sp->req[idx]->saidx, NULL); printf(" }\n"); } printf("}\n"); } void kdebug_secpolicyindex(struct secpolicyindex *spidx, const char *indent) { char buf[IPSEC_ADDRSTRLEN]; IPSEC_ASSERT(spidx != NULL, ("null spidx")); if (indent != NULL) printf("%s", indent); printf("spidx { dir=%s ul_proto=", kdebug_secpolicyindex_dir(spidx->dir)); if (spidx->ul_proto == IPSEC_ULPROTO_ANY) printf("* "); else printf("%u ", spidx->ul_proto); printf("%s/%u -> ", ipsec_address(&spidx->src, buf, sizeof(buf)), spidx->prefs); printf("%s/%u }\n", ipsec_address(&spidx->dst, buf, sizeof(buf)), spidx->prefd); } void kdebug_secasindex(const struct secasindex *saidx, const char *indent) { char buf[IPSEC_ADDRSTRLEN], port[6]; IPSEC_ASSERT(saidx != NULL, ("null saidx")); if (indent != NULL) printf("%s", indent); printf("saidx { mode=%s proto=%u reqid=%u ", kdebug_secasindex_mode(saidx->mode), saidx->proto, saidx->reqid); printf("%s:%s -> ", ipsec_address(&saidx->src, buf, sizeof(buf)), kdebug_port2str(&saidx->src.sa, port, sizeof(port))); printf("%s:%s }\n", ipsec_address(&saidx->dst, buf, sizeof(buf)), kdebug_port2str(&saidx->dst.sa, port, sizeof(port))); } static void kdebug_sec_lifetime(struct seclifetime *lft, const char *indent) { IPSEC_ASSERT(lft != NULL, ("null lft")); if (indent != NULL) printf("%s", indent); printf("lifetime { alloc=%u, bytes=%ju addtime=%ju usetime=%ju }\n", lft->allocations, (uintmax_t)lft->bytes, (uintmax_t)lft->addtime, (uintmax_t)lft->usetime); } void kdebug_secash(struct secashead *sah, const char *indent) { IPSEC_ASSERT(sah != NULL, ("null sah")); if (indent != NULL) printf("%s", indent); printf("SAH { refcnt=%u state=%s\n", sah->refcnt, kdebug_secasv_state(sah->state)); if (indent != NULL) printf("%s", indent); kdebug_secasindex(&sah->saidx, indent); if (indent != NULL) printf("%s", indent); printf("}\n"); } static void kdebug_secreplay(struct secreplay *rpl) { int len, l; IPSEC_ASSERT(rpl != NULL, ("null rpl")); printf(" secreplay{ count=%u bitmap_size=%u wsize=%u seq=%u lastseq=%u", rpl->count, rpl->bitmap_size, rpl->wsize, rpl->seq, rpl->lastseq); if (rpl->bitmap == NULL) { printf(" }\n"); return; } printf("\n bitmap { "); for (len = 0; len < rpl->bitmap_size*4; len++) { for (l = 7; l >= 0; l--) printf("%u", (((rpl->bitmap)[len] >> l) & 1) ? 1 : 0); } printf(" }\n"); } static void kdebug_secnatt(struct secnatt *natt) { char buf[IPSEC_ADDRSTRLEN]; IPSEC_ASSERT(natt != NULL, ("null natt")); printf(" natt{ sport=%u dport=%u ", ntohs(natt->sport), ntohs(natt->dport)); if (natt->flags & IPSEC_NATT_F_OAI) printf("oai=%s ", ipsec_address(&natt->oai, buf, sizeof(buf))); if (natt->flags & IPSEC_NATT_F_OAR) printf("oar=%s ", ipsec_address(&natt->oar, buf, sizeof(buf))); printf("}\n"); } void kdebug_secasv(struct secasvar *sav) { struct seclifetime lft_c; IPSEC_ASSERT(sav != NULL, ("null sav")); printf("SA { refcnt=%u spi=%u seq=%u pid=%u flags=0x%x state=%s\n", sav->refcnt, ntohl(sav->spi), sav->seq, (uint32_t)sav->pid, sav->flags, kdebug_secasv_state(sav->state)); kdebug_secash(sav->sah, " "); lft_c.addtime = sav->created; lft_c.allocations = (uint32_t)counter_u64_fetch( sav->lft_c_allocations); lft_c.bytes = counter_u64_fetch(sav->lft_c_bytes); lft_c.usetime = sav->firstused; kdebug_sec_lifetime(&lft_c, " c_"); if (sav->lft_h != NULL) kdebug_sec_lifetime(sav->lft_h, " h_"); if (sav->lft_s != NULL) kdebug_sec_lifetime(sav->lft_s, " s_"); if (sav->tdb_authalgxform != NULL) printf(" alg_auth=%s\n", sav->tdb_authalgxform->name); if (sav->key_auth != NULL) KEYDBG(DUMP, kdebug_sadb_key((struct sadb_ext *)sav->key_auth)); if (sav->tdb_encalgxform != NULL) printf(" alg_enc=%s\n", sav->tdb_encalgxform->name); if (sav->key_enc != NULL) KEYDBG(DUMP, kdebug_sadb_key((struct sadb_ext *)sav->key_enc)); if (sav->natt != NULL) kdebug_secnatt(sav->natt); if (sav->replay != NULL) { KEYDBG(DUMP, SECASVAR_LOCK(sav); kdebug_secreplay(sav->replay); SECASVAR_UNLOCK(sav)); } printf("}\n"); } void kdebug_mbufhdr(const struct mbuf *m) { /* sanity check */ if (m == NULL) return; printf("mbuf(%p){ m_next:%p m_nextpkt:%p m_data:%p " "m_len:%d m_type:0x%02x m_flags:0x%02x }\n", m, m->m_next, m->m_nextpkt, m->m_data, m->m_len, m->m_type, m->m_flags); if (m->m_flags & M_PKTHDR) { printf(" m_pkthdr{ len:%d rcvif:%p }\n", m->m_pkthdr.len, m->m_pkthdr.rcvif); } if (m->m_flags & M_EXT) { printf(" m_ext{ ext_buf:%p ext_free:%p " "ext_size:%u ext_cnt:%p }\n", m->m_ext.ext_buf, m->m_ext.ext_free, m->m_ext.ext_size, m->m_ext.ext_cnt); } return; } void kdebug_mbuf(const struct mbuf *m0) { const struct mbuf *m = m0; int i, j; for (j = 0; m; m = m->m_next) { kdebug_mbufhdr(m); printf(" m_data:\n"); for (i = 0; i < m->m_len; i++) { if (i && i % 32 == 0) printf("\n"); if (i % 4 == 0) printf(" "); printf("%02x", mtod(m, const u_char *)[i]); j++; } printf("\n"); } return; } /* Return a printable string for the address. */ char * ipsec_address(const union sockaddr_union* sa, char *buf, socklen_t size) { switch (sa->sa.sa_family) { #ifdef INET case AF_INET: return (inet_ntop(AF_INET, &sa->sin.sin_addr, buf, size)); #endif /* INET */ #ifdef INET6 case AF_INET6: if (IN6_IS_SCOPE_LINKLOCAL(&sa->sin6.sin6_addr)) { snprintf(buf, size, "%s%%%u", inet_ntop(AF_INET6, &sa->sin6.sin6_addr, buf, size), sa->sin6.sin6_scope_id); return (buf); } else return (inet_ntop(AF_INET6, &sa->sin6.sin6_addr, buf, size)); #endif /* INET6 */ case 0: return ("*"); default: return ("(unknown address family)"); } } char * ipsec_sa2str(struct secasvar *sav, char *buf, size_t size) { char sbuf[IPSEC_ADDRSTRLEN], dbuf[IPSEC_ADDRSTRLEN]; snprintf(buf, size, "SA(SPI=%08lx src=%s dst=%s)", (u_long)ntohl(sav->spi), ipsec_address(&sav->sah->saidx.src, sbuf, sizeof(sbuf)), ipsec_address(&sav->sah->saidx.dst, dbuf, sizeof(dbuf))); return (buf); } #endif /* _KERNEL */ void kdebug_sockaddr(struct sockaddr *addr) { - struct sockaddr_in *sin4; -#ifdef INET6 - struct sockaddr_in6 *sin6; -#endif + char buf[IPSEC_ADDRSTRLEN]; /* sanity check */ if (addr == NULL) panic("%s: NULL pointer was passed.\n", __func__); - /* NOTE: We deal with port number as host byte order. */ - printf("sockaddr{ len=%u family=%u", addr->sa_len, addr->sa_family); - switch (addr->sa_family) { - case AF_INET: - sin4 = (struct sockaddr_in *)addr; - printf(" port=%u\n", ntohs(sin4->sin_port)); - ipsec_hexdump((caddr_t)&sin4->sin_addr, sizeof(sin4->sin_addr)); +#ifdef INET + case AF_INET: { + struct sockaddr_in *sin; + + sin = (struct sockaddr_in *)addr; + inet_ntop(AF_INET, &sin->sin_addr, buf, sizeof(buf)); break; + } +#endif #ifdef INET6 - case AF_INET6: + case AF_INET6: { + struct sockaddr_in6 *sin6; + sin6 = (struct sockaddr_in6 *)addr; - printf(" port=%u\n", ntohs(sin6->sin6_port)); - printf(" flowinfo=0x%08x, scope_id=0x%08x\n", - sin6->sin6_flowinfo, sin6->sin6_scope_id); - ipsec_hexdump((caddr_t)&sin6->sin6_addr, - sizeof(sin6->sin6_addr)); + if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) { + snprintf(buf, sizeof(buf), "%s%%%u", + inet_ntop(AF_INET6, &sin6->sin6_addr, buf, + sizeof(buf)), sin6->sin6_scope_id); + } else + inet_ntop(AF_INET6, &sin6->sin6_addr, buf, + sizeof(buf)); break; + } #endif + default: + sprintf(buf, "unknown"); } - - printf(" }\n"); - - return; + printf("sockaddr{ len=%u family=%u addr=%s }\n", addr->sa_len, + addr->sa_family, buf); } void ipsec_bindump(caddr_t buf, int len) { int i; for (i = 0; i < len; i++) printf("%c", (unsigned char)buf[i]); return; } void ipsec_hexdump(caddr_t buf, int len) { int i; for (i = 0; i < len; i++) { if (i != 0 && i % 32 == 0) printf("\n"); if (i % 4 == 0) printf(" "); printf("%02x", (unsigned char)buf[i]); } #if 0 if (i % 32 != 0) printf("\n"); #endif return; }