1122107Sume/* $KAME: pfkey.c,v 1.46 2003/08/26 03:37:06 itojun Exp $ */ 262583Sitojun 355505Sshin/* 455505Sshin * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project. 555505Sshin * All rights reserved. 655505Sshin * 755505Sshin * Redistribution and use in source and binary forms, with or without 855505Sshin * modification, are permitted provided that the following conditions 955505Sshin * are met: 1055505Sshin * 1. Redistributions of source code must retain the above copyright 1155505Sshin * notice, this list of conditions and the following disclaimer. 1255505Sshin * 2. Redistributions in binary form must reproduce the above copyright 1355505Sshin * notice, this list of conditions and the following disclaimer in the 1455505Sshin * documentation and/or other materials provided with the distribution. 1555505Sshin * 3. Neither the name of the project nor the names of its contributors 1655505Sshin * may be used to endorse or promote products derived from this software 1755505Sshin * without specific prior written permission. 1855505Sshin * 1955505Sshin * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 2055505Sshin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2155505Sshin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2255505Sshin * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 2355505Sshin * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2455505Sshin * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2555505Sshin * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2655505Sshin * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2755505Sshin * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2855505Sshin * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2955505Sshin * SUCH DAMAGE. 3055505Sshin */ 3155505Sshin 3284208Sdillon#include <sys/cdefs.h> 3384208Sdillon__FBSDID("$FreeBSD$"); 3484208Sdillon 3555505Sshin#include <sys/types.h> 3655505Sshin#include <sys/param.h> 3755505Sshin#include <sys/socket.h> 3855505Sshin#include <net/pfkeyv2.h> 39171135Sgnn#include <netipsec/key_var.h> 4055505Sshin#include <netinet/in.h> 41171135Sgnn#include <netipsec/ipsec.h> 4255505Sshin 4355505Sshin#include <stdlib.h> 4455505Sshin#include <unistd.h> 4555505Sshin#include <string.h> 4655505Sshin#include <errno.h> 4755505Sshin 4855505Sshin#include "ipsec_strerror.h" 4962583Sitojun#include "libpfkey.h" 5055505Sshin 5162583Sitojun#define CALLOC(size, cast) (cast)calloc(1, (size)) 5255505Sshin 5392917Sobrienstatic int findsupportedmap(int); 5492917Sobrienstatic int setsupportedmap(struct sadb_supported *); 5592917Sobrienstatic struct sadb_alg *findsupportedalg(u_int, u_int); 5692941Sobrienstatic int pfkey_send_x1(int, u_int, u_int, u_int, struct sockaddr *, 5762583Sitojun struct sockaddr *, u_int32_t, u_int32_t, u_int, caddr_t, 5862583Sitojun u_int, u_int, u_int, u_int, u_int, u_int32_t, u_int32_t, 5992941Sobrien u_int32_t, u_int32_t, u_int32_t); 6092941Sobrienstatic int pfkey_send_x2(int, u_int, u_int, u_int, 6192941Sobrien struct sockaddr *, struct sockaddr *, u_int32_t); 6292917Sobrienstatic int pfkey_send_x3(int, u_int, u_int); 6392941Sobrienstatic int pfkey_send_x4(int, u_int, struct sockaddr *, u_int, 6478064Sume struct sockaddr *, u_int, u_int, u_int64_t, u_int64_t, 6592941Sobrien char *, int, u_int32_t); 6692917Sobrienstatic int pfkey_send_x5(int, u_int, u_int32_t); 6755505Sshin 6892941Sobrienstatic caddr_t pfkey_setsadbmsg(caddr_t, caddr_t, u_int, u_int, 6992941Sobrien u_int, u_int32_t, pid_t); 7092941Sobrienstatic caddr_t pfkey_setsadbsa(caddr_t, caddr_t, u_int32_t, u_int, 7192941Sobrien u_int, u_int, u_int32_t); 7292941Sobrienstatic caddr_t pfkey_setsadbaddr(caddr_t, caddr_t, u_int, 7392941Sobrien struct sockaddr *, u_int, u_int); 7492917Sobrienstatic caddr_t pfkey_setsadbkey(caddr_t, caddr_t, u_int, caddr_t, u_int); 7592941Sobrienstatic caddr_t pfkey_setsadblifetime(caddr_t, caddr_t, u_int, u_int32_t, 7692941Sobrien u_int32_t, u_int32_t, u_int32_t); 7792917Sobrienstatic caddr_t pfkey_setsadbxsa2(caddr_t, caddr_t, u_int32_t, u_int32_t); 7855505Sshin 7955505Sshin/* 8078064Sume * make and search supported algorithm structure. 8178064Sume */ 82125681Sbmsstatic struct sadb_supported *ipsec_supported[] = { NULL, NULL, NULL, NULL }; 8378064Sume 8478064Sumestatic int supported_map[] = { 8578064Sume SADB_SATYPE_AH, 8678064Sume SADB_SATYPE_ESP, 8778064Sume SADB_X_SATYPE_IPCOMP, 88125681Sbms SADB_X_SATYPE_TCPSIGNATURE 8978064Sume}; 9078064Sume 9178064Sumestatic int 9278064Sumefindsupportedmap(satype) 9378064Sume int satype; 9478064Sume{ 9578064Sume int i; 9678064Sume 9778064Sume for (i = 0; i < sizeof(supported_map)/sizeof(supported_map[0]); i++) 9878064Sume if (supported_map[i] == satype) 9978064Sume return i; 10078064Sume return -1; 10178064Sume} 10278064Sume 10378064Sumestatic struct sadb_alg * 10478064Sumefindsupportedalg(satype, alg_id) 10578064Sume u_int satype, alg_id; 10678064Sume{ 10778064Sume int algno; 10878064Sume int tlen; 10978064Sume caddr_t p; 11078064Sume 11178064Sume /* validity check */ 11278064Sume algno = findsupportedmap(satype); 11378064Sume if (algno == -1) { 11478064Sume __ipsec_errcode = EIPSEC_INVAL_ARGUMENT; 11578064Sume return NULL; 11678064Sume } 11778064Sume if (ipsec_supported[algno] == NULL) { 11878064Sume __ipsec_errcode = EIPSEC_DO_GET_SUPP_LIST; 11978064Sume return NULL; 12078064Sume } 12178064Sume 12278064Sume tlen = ipsec_supported[algno]->sadb_supported_len 12378064Sume - sizeof(struct sadb_supported); 12478064Sume p = (caddr_t)(ipsec_supported[algno] + 1); 12578064Sume while (tlen > 0) { 12678064Sume if (tlen < sizeof(struct sadb_alg)) { 12778064Sume /* invalid format */ 12878064Sume break; 12978064Sume } 13078064Sume if (((struct sadb_alg *)p)->sadb_alg_id == alg_id) 13178064Sume return (struct sadb_alg *)p; 13278064Sume 13378064Sume tlen -= sizeof(struct sadb_alg); 13478064Sume p += sizeof(struct sadb_alg); 13578064Sume } 13678064Sume 13778064Sume __ipsec_errcode = EIPSEC_NOT_SUPPORTED; 13878064Sume return NULL; 13978064Sume} 14078064Sume 14178064Sumestatic int 14278064Sumesetsupportedmap(sup) 14378064Sume struct sadb_supported *sup; 14478064Sume{ 14578064Sume struct sadb_supported **ipsup; 14678064Sume 14778064Sume switch (sup->sadb_supported_exttype) { 14878064Sume case SADB_EXT_SUPPORTED_AUTH: 14978064Sume ipsup = &ipsec_supported[findsupportedmap(SADB_SATYPE_AH)]; 15078064Sume break; 15178064Sume case SADB_EXT_SUPPORTED_ENCRYPT: 15278064Sume ipsup = &ipsec_supported[findsupportedmap(SADB_SATYPE_ESP)]; 15378064Sume break; 15478064Sume default: 15578064Sume __ipsec_errcode = EIPSEC_INVAL_SATYPE; 15678064Sume return -1; 15778064Sume } 15878064Sume 15978064Sume if (*ipsup) 16078064Sume free(*ipsup); 16178064Sume 16278064Sume *ipsup = malloc(sup->sadb_supported_len); 16378064Sume if (!*ipsup) { 16478064Sume __ipsec_set_strerror(strerror(errno)); 16578064Sume return -1; 16678064Sume } 16778064Sume memcpy(*ipsup, sup, sup->sadb_supported_len); 16878064Sume 16978064Sume return 0; 17078064Sume} 17178064Sume 17278064Sume/* 17355505Sshin * check key length against algorithm specified. 17478064Sume * This function is called with SADB_EXT_SUPPORTED_{AUTH,ENCRYPT} as the 17578064Sume * augument, and only calls to ipsec_check_keylen2(); 17655505Sshin * keylen is the unit of bit. 17755505Sshin * OUT: 17855505Sshin * -1: invalid. 17955505Sshin * 0: valid. 18055505Sshin */ 18155505Sshinint 18255505Sshinipsec_check_keylen(supported, alg_id, keylen) 18355505Sshin u_int supported; 18455505Sshin u_int alg_id; 18555505Sshin u_int keylen; 18655505Sshin{ 18778064Sume int satype; 18855505Sshin 18955505Sshin /* validity check */ 19055505Sshin switch (supported) { 19155505Sshin case SADB_EXT_SUPPORTED_AUTH: 19278064Sume satype = SADB_SATYPE_AH; 19378064Sume break; 19455505Sshin case SADB_EXT_SUPPORTED_ENCRYPT: 19578064Sume satype = SADB_SATYPE_ESP; 19655505Sshin break; 19755505Sshin default: 19862583Sitojun __ipsec_errcode = EIPSEC_INVAL_ARGUMENT; 19955505Sshin return -1; 20055505Sshin } 20155505Sshin 20278064Sume return ipsec_check_keylen2(satype, alg_id, keylen); 20378064Sume} 20455505Sshin 20578064Sume/* 20678064Sume * check key length against algorithm specified. 20778064Sume * satype is one of satype defined at pfkeyv2.h. 20878064Sume * keylen is the unit of bit. 20978064Sume * OUT: 21078064Sume * -1: invalid. 21178064Sume * 0: valid. 21278064Sume */ 21378064Sumeint 21478064Sumeipsec_check_keylen2(satype, alg_id, keylen) 21578064Sume u_int satype; 21678064Sume u_int alg_id; 21778064Sume u_int keylen; 21878064Sume{ 21978064Sume struct sadb_alg *alg; 22055505Sshin 22178064Sume alg = findsupportedalg(satype, alg_id); 22278064Sume if (!alg) 22378064Sume return -1; 22455505Sshin 22578064Sume if (keylen < alg->sadb_alg_minbits || keylen > alg->sadb_alg_maxbits) { 22678064Sume __ipsec_errcode = EIPSEC_INVAL_KEYLEN; 22778064Sume return -1; 22878064Sume } 22955505Sshin 23078064Sume __ipsec_errcode = EIPSEC_NO_ERROR; 23178064Sume return 0; 23278064Sume} 23355505Sshin 23478064Sume/* 23578064Sume * get max/min key length against algorithm specified. 23678064Sume * satype is one of satype defined at pfkeyv2.h. 23778064Sume * keylen is the unit of bit. 23878064Sume * OUT: 23978064Sume * -1: invalid. 24078064Sume * 0: valid. 24178064Sume */ 24278064Sumeint 24378064Sumeipsec_get_keylen(supported, alg_id, alg0) 24478064Sume u_int supported, alg_id; 24578064Sume struct sadb_alg *alg0; 24678064Sume{ 24778064Sume struct sadb_alg *alg; 24878064Sume u_int satype; 24955505Sshin 25078064Sume /* validity check */ 25178064Sume if (!alg0) { 25278064Sume __ipsec_errcode = EIPSEC_INVAL_ARGUMENT; 25378064Sume return -1; 25455505Sshin } 25555505Sshin 25678064Sume switch (supported) { 25778064Sume case SADB_EXT_SUPPORTED_AUTH: 25878064Sume satype = SADB_SATYPE_AH; 25978064Sume break; 26078064Sume case SADB_EXT_SUPPORTED_ENCRYPT: 26178064Sume satype = SADB_SATYPE_ESP; 26278064Sume break; 26378064Sume default: 26478064Sume __ipsec_errcode = EIPSEC_INVAL_ARGUMENT; 26555505Sshin return -1; 26655505Sshin } 26755505Sshin 26878064Sume alg = findsupportedalg(satype, alg_id); 26978064Sume if (!alg) 27078064Sume return -1; 27178064Sume 27278064Sume memcpy(alg0, alg, sizeof(*alg0)); 27378064Sume 27462583Sitojun __ipsec_errcode = EIPSEC_NO_ERROR; 27555505Sshin return 0; 27655505Sshin} 27755505Sshin 27855505Sshin/* 27955505Sshin * set the rate for SOFT lifetime against HARD one. 28055505Sshin * If rate is more than 100 or equal to zero, then set to 100. 28155505Sshin */ 28255505Sshinstatic u_int soft_lifetime_allocations_rate = PFKEY_SOFT_LIFETIME_RATE; 28355505Sshinstatic u_int soft_lifetime_bytes_rate = PFKEY_SOFT_LIFETIME_RATE; 28455505Sshinstatic u_int soft_lifetime_addtime_rate = PFKEY_SOFT_LIFETIME_RATE; 28555505Sshinstatic u_int soft_lifetime_usetime_rate = PFKEY_SOFT_LIFETIME_RATE; 28655505Sshin 28755505Sshinu_int 28855505Sshinpfkey_set_softrate(type, rate) 28955505Sshin u_int type, rate; 29055505Sshin{ 29162583Sitojun __ipsec_errcode = EIPSEC_NO_ERROR; 29255505Sshin 29355505Sshin if (rate > 100 || rate == 0) 29455505Sshin rate = 100; 29555505Sshin 29655505Sshin switch (type) { 29755505Sshin case SADB_X_LIFETIME_ALLOCATIONS: 29855505Sshin soft_lifetime_allocations_rate = rate; 29955505Sshin return 0; 30055505Sshin case SADB_X_LIFETIME_BYTES: 30155505Sshin soft_lifetime_bytes_rate = rate; 30255505Sshin return 0; 30355505Sshin case SADB_X_LIFETIME_ADDTIME: 30455505Sshin soft_lifetime_addtime_rate = rate; 30555505Sshin return 0; 30655505Sshin case SADB_X_LIFETIME_USETIME: 30755505Sshin soft_lifetime_usetime_rate = rate; 30855505Sshin return 0; 30955505Sshin } 31055505Sshin 31162583Sitojun __ipsec_errcode = EIPSEC_INVAL_ARGUMENT; 31255505Sshin return 1; 31355505Sshin} 31455505Sshin 31555505Sshin/* 31655505Sshin * get current rate for SOFT lifetime against HARD one. 31755505Sshin * ATTENTION: ~0 is returned if invalid type was passed. 31855505Sshin */ 31955505Sshinu_int 32055505Sshinpfkey_get_softrate(type) 32155505Sshin u_int type; 32255505Sshin{ 32355505Sshin switch (type) { 32455505Sshin case SADB_X_LIFETIME_ALLOCATIONS: 32555505Sshin return soft_lifetime_allocations_rate; 32655505Sshin case SADB_X_LIFETIME_BYTES: 32755505Sshin return soft_lifetime_bytes_rate; 32855505Sshin case SADB_X_LIFETIME_ADDTIME: 32955505Sshin return soft_lifetime_addtime_rate; 33055505Sshin case SADB_X_LIFETIME_USETIME: 33155505Sshin return soft_lifetime_usetime_rate; 33255505Sshin } 33355505Sshin 33455505Sshin return ~0; 33555505Sshin} 33655505Sshin 33755505Sshin/* 33855505Sshin * sending SADB_GETSPI message to the kernel. 33955505Sshin * OUT: 34055505Sshin * positive: success and return length sent. 34155505Sshin * -1 : error occured, and set errno. 34255505Sshin */ 34355505Sshinint 34462583Sitojunpfkey_send_getspi(so, satype, mode, src, dst, min, max, reqid, seq) 34555505Sshin int so; 34655505Sshin u_int satype, mode; 34755505Sshin struct sockaddr *src, *dst; 34862583Sitojun u_int32_t min, max, reqid, seq; 34955505Sshin{ 35055505Sshin struct sadb_msg *newmsg; 35178064Sume caddr_t ep; 35255505Sshin int len; 35355505Sshin int need_spirange = 0; 35455505Sshin caddr_t p; 35562583Sitojun int plen; 35655505Sshin 35755505Sshin /* validity check */ 35855505Sshin if (src == NULL || dst == NULL) { 35962583Sitojun __ipsec_errcode = EIPSEC_INVAL_ARGUMENT; 36055505Sshin return -1; 36155505Sshin } 36255505Sshin if (src->sa_family != dst->sa_family) { 36362583Sitojun __ipsec_errcode = EIPSEC_FAMILY_MISMATCH; 36455505Sshin return -1; 36555505Sshin } 36655505Sshin if (min > max || (min > 0 && min <= 255)) { 36762583Sitojun __ipsec_errcode = EIPSEC_INVAL_SPI; 36855505Sshin return -1; 36955505Sshin } 37062583Sitojun switch (src->sa_family) { 37162583Sitojun case AF_INET: 37262583Sitojun plen = sizeof(struct in_addr) << 3; 37362583Sitojun break; 37462583Sitojun case AF_INET6: 37562583Sitojun plen = sizeof(struct in6_addr) << 3; 37662583Sitojun break; 37762583Sitojun default: 37862583Sitojun __ipsec_errcode = EIPSEC_INVAL_FAMILY; 37962583Sitojun return -1; 38062583Sitojun } 38155505Sshin 38255505Sshin /* create new sadb_msg to send. */ 38355505Sshin len = sizeof(struct sadb_msg) 38462583Sitojun + sizeof(struct sadb_x_sa2) 38555505Sshin + sizeof(struct sadb_address) 38655505Sshin + PFKEY_ALIGN8(src->sa_len) 38755505Sshin + sizeof(struct sadb_address) 38855505Sshin + PFKEY_ALIGN8(dst->sa_len); 38955505Sshin 39055505Sshin if (min > 255 && max < ~0) { 39155505Sshin need_spirange++; 39255505Sshin len += sizeof(struct sadb_spirange); 39355505Sshin } 39455505Sshin 39555505Sshin if ((newmsg = CALLOC(len, struct sadb_msg *)) == NULL) { 39662583Sitojun __ipsec_set_strerror(strerror(errno)); 39755505Sshin return -1; 39855505Sshin } 39978064Sume ep = ((caddr_t)newmsg) + len; 40055505Sshin 40178064Sume p = pfkey_setsadbmsg((caddr_t)newmsg, ep, SADB_GETSPI, 40278064Sume len, satype, seq, getpid()); 40378064Sume if (!p) { 40478064Sume free(newmsg); 40578064Sume return -1; 40678064Sume } 40755505Sshin 40878064Sume p = pfkey_setsadbxsa2(p, ep, mode, reqid); 40978064Sume if (!p) { 41078064Sume free(newmsg); 41178064Sume return -1; 41278064Sume } 41362583Sitojun 41455505Sshin /* set sadb_address for source */ 41578064Sume p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_SRC, src, plen, 41662583Sitojun IPSEC_ULPROTO_ANY); 41778064Sume if (!p) { 41878064Sume free(newmsg); 41978064Sume return -1; 42078064Sume } 42155505Sshin 42255505Sshin /* set sadb_address for destination */ 42378064Sume p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_DST, dst, plen, 42462583Sitojun IPSEC_ULPROTO_ANY); 42578064Sume if (!p) { 42678064Sume free(newmsg); 42778064Sume return -1; 42878064Sume } 42955505Sshin 43055505Sshin /* proccessing spi range */ 43155505Sshin if (need_spirange) { 43278064Sume struct sadb_spirange spirange; 43355505Sshin 43478064Sume if (p + sizeof(spirange) > ep) { 43578064Sume free(newmsg); 43678064Sume return -1; 43778064Sume } 43878064Sume 43978064Sume memset(&spirange, 0, sizeof(spirange)); 44078064Sume spirange.sadb_spirange_len = PFKEY_UNIT64(sizeof(spirange)); 44178064Sume spirange.sadb_spirange_exttype = SADB_EXT_SPIRANGE; 44278064Sume spirange.sadb_spirange_min = min; 44378064Sume spirange.sadb_spirange_max = max; 44478064Sume 44578064Sume memcpy(p, &spirange, sizeof(spirange)); 44678064Sume 44778064Sume p += sizeof(spirange); 44855505Sshin } 44978064Sume if (p != ep) { 45078064Sume free(newmsg); 45178064Sume return -1; 45278064Sume } 45355505Sshin 45455505Sshin /* send message */ 45555505Sshin len = pfkey_send(so, newmsg, len); 45655505Sshin free(newmsg); 45755505Sshin 45855505Sshin if (len < 0) 45955505Sshin return -1; 46055505Sshin 46162583Sitojun __ipsec_errcode = EIPSEC_NO_ERROR; 46255505Sshin return len; 46355505Sshin} 46455505Sshin 46555505Sshin/* 46655505Sshin * sending SADB_UPDATE message to the kernel. 46755505Sshin * The length of key material is a_keylen + e_keylen. 46855505Sshin * OUT: 46955505Sshin * positive: success and return length sent. 47055505Sshin * -1 : error occured, and set errno. 47155505Sshin */ 47255505Sshinint 47362583Sitojunpfkey_send_update(so, satype, mode, src, dst, spi, reqid, wsize, 47455505Sshin keymat, e_type, e_keylen, a_type, a_keylen, flags, 47555505Sshin l_alloc, l_bytes, l_addtime, l_usetime, seq) 47655505Sshin int so; 47755505Sshin u_int satype, mode, wsize; 47855505Sshin struct sockaddr *src, *dst; 47962583Sitojun u_int32_t spi, reqid; 48055505Sshin caddr_t keymat; 48155505Sshin u_int e_type, e_keylen, a_type, a_keylen, flags; 48255505Sshin u_int32_t l_alloc; 48355505Sshin u_int64_t l_bytes, l_addtime, l_usetime; 48455505Sshin u_int32_t seq; 48555505Sshin{ 48655505Sshin int len; 48755505Sshin if ((len = pfkey_send_x1(so, SADB_UPDATE, satype, mode, src, dst, spi, 48862583Sitojun reqid, wsize, 48962583Sitojun keymat, e_type, e_keylen, a_type, a_keylen, flags, 49055505Sshin l_alloc, l_bytes, l_addtime, l_usetime, seq)) < 0) 49155505Sshin return -1; 49255505Sshin 49355505Sshin return len; 49455505Sshin} 49555505Sshin 49655505Sshin/* 49755505Sshin * sending SADB_ADD message to the kernel. 49855505Sshin * The length of key material is a_keylen + e_keylen. 49955505Sshin * OUT: 50055505Sshin * positive: success and return length sent. 50155505Sshin * -1 : error occured, and set errno. 50255505Sshin */ 50355505Sshinint 50462583Sitojunpfkey_send_add(so, satype, mode, src, dst, spi, reqid, wsize, 50555505Sshin keymat, e_type, e_keylen, a_type, a_keylen, flags, 50655505Sshin l_alloc, l_bytes, l_addtime, l_usetime, seq) 50755505Sshin int so; 50855505Sshin u_int satype, mode, wsize; 50955505Sshin struct sockaddr *src, *dst; 51062583Sitojun u_int32_t spi, reqid; 51155505Sshin caddr_t keymat; 51255505Sshin u_int e_type, e_keylen, a_type, a_keylen, flags; 51355505Sshin u_int32_t l_alloc; 51455505Sshin u_int64_t l_bytes, l_addtime, l_usetime; 51555505Sshin u_int32_t seq; 51655505Sshin{ 51755505Sshin int len; 51855505Sshin if ((len = pfkey_send_x1(so, SADB_ADD, satype, mode, src, dst, spi, 51962583Sitojun reqid, wsize, 52062583Sitojun keymat, e_type, e_keylen, a_type, a_keylen, flags, 52155505Sshin l_alloc, l_bytes, l_addtime, l_usetime, seq)) < 0) 52255505Sshin return -1; 52355505Sshin 52455505Sshin return len; 52555505Sshin} 52655505Sshin 52755505Sshin/* 52855505Sshin * sending SADB_DELETE message to the kernel. 52955505Sshin * OUT: 53055505Sshin * positive: success and return length sent. 53155505Sshin * -1 : error occured, and set errno. 53255505Sshin */ 53355505Sshinint 53455505Sshinpfkey_send_delete(so, satype, mode, src, dst, spi) 53555505Sshin int so; 53655505Sshin u_int satype, mode; 53755505Sshin struct sockaddr *src, *dst; 53855505Sshin u_int32_t spi; 53955505Sshin{ 54055505Sshin int len; 54155505Sshin if ((len = pfkey_send_x2(so, SADB_DELETE, satype, mode, src, dst, spi)) < 0) 54255505Sshin return -1; 54355505Sshin 54455505Sshin return len; 54555505Sshin} 54655505Sshin 54755505Sshin/* 54878064Sume * sending SADB_DELETE without spi to the kernel. This is 54978064Sume * the "delete all" request (an extension also present in 55078064Sume * Solaris). 55178064Sume * 55278064Sume * OUT: 55378064Sume * positive: success and return length sent 55478064Sume * -1 : error occured, and set errno 55578064Sume */ 55678064Sumeint 55778064Sumepfkey_send_delete_all(so, satype, mode, src, dst) 55878064Sume int so; 55978064Sume u_int satype, mode; 56078064Sume struct sockaddr *src, *dst; 56178064Sume{ 56278064Sume struct sadb_msg *newmsg; 56378064Sume int len; 56478064Sume caddr_t p; 56578064Sume int plen; 56678064Sume caddr_t ep; 56778064Sume 56878064Sume /* validity check */ 56978064Sume if (src == NULL || dst == NULL) { 57078064Sume __ipsec_errcode = EIPSEC_INVAL_ARGUMENT; 57178064Sume return -1; 57278064Sume } 57378064Sume if (src->sa_family != dst->sa_family) { 57478064Sume __ipsec_errcode = EIPSEC_FAMILY_MISMATCH; 57578064Sume return -1; 57678064Sume } 57778064Sume switch (src->sa_family) { 57878064Sume case AF_INET: 57978064Sume plen = sizeof(struct in_addr) << 3; 58078064Sume break; 58178064Sume case AF_INET6: 58278064Sume plen = sizeof(struct in6_addr) << 3; 58378064Sume break; 58478064Sume default: 58578064Sume __ipsec_errcode = EIPSEC_INVAL_FAMILY; 58678064Sume return -1; 58778064Sume } 58878064Sume 58978064Sume /* create new sadb_msg to reply. */ 59078064Sume len = sizeof(struct sadb_msg) 59178064Sume + sizeof(struct sadb_address) 59278064Sume + PFKEY_ALIGN8(src->sa_len) 59378064Sume + sizeof(struct sadb_address) 59478064Sume + PFKEY_ALIGN8(dst->sa_len); 59578064Sume 59678064Sume if ((newmsg = CALLOC(len, struct sadb_msg *)) == NULL) { 59778064Sume __ipsec_set_strerror(strerror(errno)); 59878064Sume return -1; 59978064Sume } 60078064Sume ep = ((caddr_t)newmsg) + len; 60178064Sume 60278064Sume p = pfkey_setsadbmsg((caddr_t)newmsg, ep, SADB_DELETE, len, satype, 0, 60378064Sume getpid()); 60478064Sume if (!p) { 60578064Sume free(newmsg); 60678064Sume return -1; 60778064Sume } 60878064Sume p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_SRC, src, plen, 60978064Sume IPSEC_ULPROTO_ANY); 61078064Sume if (!p) { 61178064Sume free(newmsg); 61278064Sume return -1; 61378064Sume } 61478064Sume p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_DST, dst, plen, 61578064Sume IPSEC_ULPROTO_ANY); 61678064Sume if (!p || p != ep) { 61778064Sume free(newmsg); 61878064Sume return -1; 61978064Sume } 62078064Sume 62178064Sume /* send message */ 62278064Sume len = pfkey_send(so, newmsg, len); 62378064Sume free(newmsg); 62478064Sume 62578064Sume if (len < 0) 62678064Sume return -1; 62778064Sume 62878064Sume __ipsec_errcode = EIPSEC_NO_ERROR; 62978064Sume return len; 63078064Sume} 63178064Sume 63278064Sume/* 63355505Sshin * sending SADB_GET message to the kernel. 63455505Sshin * OUT: 63555505Sshin * positive: success and return length sent. 63655505Sshin * -1 : error occured, and set errno. 63755505Sshin */ 63855505Sshinint 63955505Sshinpfkey_send_get(so, satype, mode, src, dst, spi) 64055505Sshin int so; 64155505Sshin u_int satype, mode; 64255505Sshin struct sockaddr *src, *dst; 64355505Sshin u_int32_t spi; 64455505Sshin{ 64555505Sshin int len; 64655505Sshin if ((len = pfkey_send_x2(so, SADB_GET, satype, mode, src, dst, spi)) < 0) 64755505Sshin return -1; 64855505Sshin 64955505Sshin return len; 65055505Sshin} 65155505Sshin 65255505Sshin/* 65355505Sshin * sending SADB_REGISTER message to the kernel. 65455505Sshin * OUT: 65555505Sshin * positive: success and return length sent. 65655505Sshin * -1 : error occured, and set errno. 65755505Sshin */ 65855505Sshinint 65955505Sshinpfkey_send_register(so, satype) 66055505Sshin int so; 66155505Sshin u_int satype; 66255505Sshin{ 66378064Sume int len, algno; 66455505Sshin 665231515Sbz if (satype == SADB_SATYPE_UNSPEC) { 66678064Sume for (algno = 0; 66778064Sume algno < sizeof(supported_map)/sizeof(supported_map[0]); 66878064Sume algno++) { 66978064Sume if (ipsec_supported[algno]) { 67078064Sume free(ipsec_supported[algno]); 67178064Sume ipsec_supported[algno] = NULL; 67278064Sume } 67378064Sume } 67478064Sume } else { 67578064Sume algno = findsupportedmap(satype); 67678064Sume if (algno == -1) { 67778064Sume __ipsec_errcode = EIPSEC_INVAL_ARGUMENT; 67878064Sume return -1; 67978064Sume } 68078064Sume 68178064Sume if (ipsec_supported[algno]) { 68278064Sume free(ipsec_supported[algno]); 68378064Sume ipsec_supported[algno] = NULL; 68478064Sume } 68578064Sume } 68678064Sume 68755505Sshin if ((len = pfkey_send_x3(so, SADB_REGISTER, satype)) < 0) 68855505Sshin return -1; 68955505Sshin 69055505Sshin return len; 69155505Sshin} 69255505Sshin 69355505Sshin/* 69455505Sshin * receiving SADB_REGISTER message from the kernel, and copy buffer for 69555505Sshin * sadb_supported returned into ipsec_supported. 69655505Sshin * OUT: 69755505Sshin * 0: success and return length sent. 69855505Sshin * -1: error occured, and set errno. 69955505Sshin */ 70055505Sshinint 70155505Sshinpfkey_recv_register(so) 70255505Sshin int so; 70355505Sshin{ 70455505Sshin pid_t pid = getpid(); 70555505Sshin struct sadb_msg *newmsg; 70678064Sume int error = -1; 70755505Sshin 70855505Sshin /* receive message */ 709122107Sume for (;;) { 71055505Sshin if ((newmsg = pfkey_recv(so)) == NULL) 71155505Sshin return -1; 712122107Sume if (newmsg->sadb_msg_type == SADB_REGISTER && 713122107Sume newmsg->sadb_msg_pid == pid) 714122107Sume break; 715122107Sume free(newmsg); 716122107Sume } 71755505Sshin 71855505Sshin /* check and fix */ 71955505Sshin newmsg->sadb_msg_len = PFKEY_UNUNIT64(newmsg->sadb_msg_len); 72055505Sshin 72178064Sume error = pfkey_set_supported(newmsg, newmsg->sadb_msg_len); 72278064Sume free(newmsg); 72378064Sume 72478064Sume if (error == 0) 72578064Sume __ipsec_errcode = EIPSEC_NO_ERROR; 72678064Sume 72778064Sume return error; 72878064Sume} 72978064Sume 73078064Sume/* 73178064Sume * receiving SADB_REGISTER message from the kernel, and copy buffer for 73278064Sume * sadb_supported returned into ipsec_supported. 73378064Sume * NOTE: sadb_msg_len must be host order. 73478064Sume * IN: 73578064Sume * tlen: msg length, it's to makeing sure. 73678064Sume * OUT: 73778064Sume * 0: success and return length sent. 73878064Sume * -1: error occured, and set errno. 73978064Sume */ 74078064Sumeint 74178064Sumepfkey_set_supported(msg, tlen) 74278064Sume struct sadb_msg *msg; 74378064Sume int tlen; 74478064Sume{ 74578064Sume struct sadb_supported *sup; 74678064Sume caddr_t p; 74778064Sume caddr_t ep; 74878064Sume 74978064Sume /* validity */ 75078064Sume if (msg->sadb_msg_len != tlen) { 75178064Sume __ipsec_errcode = EIPSEC_INVAL_ARGUMENT; 75278064Sume return -1; 75378064Sume } 75478064Sume 75578064Sume p = (caddr_t)msg; 75678064Sume ep = p + tlen; 75778064Sume 75878064Sume p += sizeof(struct sadb_msg); 75978064Sume 76078064Sume while (p < ep) { 76155505Sshin sup = (struct sadb_supported *)p; 76278064Sume if (ep < p + sizeof(*sup) || 76378064Sume PFKEY_EXTLEN(sup) < sizeof(*sup) || 76478064Sume ep < p + sup->sadb_supported_len) { 76578064Sume /* invalid format */ 76678064Sume break; 76778064Sume } 76878064Sume 76955505Sshin switch (sup->sadb_supported_exttype) { 77055505Sshin case SADB_EXT_SUPPORTED_AUTH: 77155505Sshin case SADB_EXT_SUPPORTED_ENCRYPT: 77255505Sshin break; 77355505Sshin default: 77462583Sitojun __ipsec_errcode = EIPSEC_INVAL_SATYPE; 77555505Sshin return -1; 77655505Sshin } 77755505Sshin 77878064Sume /* fixed length */ 77978064Sume sup->sadb_supported_len = PFKEY_EXTLEN(sup); 78078064Sume 78178064Sume /* set supported map */ 78278064Sume if (setsupportedmap(sup) != 0) 78378064Sume return -1; 78478064Sume 78555505Sshin p += sup->sadb_supported_len; 78655505Sshin } 78755505Sshin 78878064Sume if (p != ep) { 78962583Sitojun __ipsec_errcode = EIPSEC_INVAL_SATYPE; 79055505Sshin return -1; 79155505Sshin } 79255505Sshin 79378064Sume __ipsec_errcode = EIPSEC_NO_ERROR; 79455505Sshin 79555505Sshin return 0; 79655505Sshin} 79755505Sshin 79855505Sshin/* 79955505Sshin * sending SADB_FLUSH message to the kernel. 80055505Sshin * OUT: 80155505Sshin * positive: success and return length sent. 80255505Sshin * -1 : error occured, and set errno. 80355505Sshin */ 80455505Sshinint 80555505Sshinpfkey_send_flush(so, satype) 80655505Sshin int so; 80755505Sshin u_int satype; 80855505Sshin{ 80955505Sshin int len; 81055505Sshin 81155505Sshin if ((len = pfkey_send_x3(so, SADB_FLUSH, satype)) < 0) 81255505Sshin return -1; 81355505Sshin 81455505Sshin return len; 81555505Sshin} 81655505Sshin 81755505Sshin/* 81855505Sshin * sending SADB_DUMP message to the kernel. 81955505Sshin * OUT: 82055505Sshin * positive: success and return length sent. 82155505Sshin * -1 : error occured, and set errno. 82255505Sshin */ 82355505Sshinint 82455505Sshinpfkey_send_dump(so, satype) 82555505Sshin int so; 82655505Sshin u_int satype; 82755505Sshin{ 82855505Sshin int len; 82955505Sshin 83055505Sshin if ((len = pfkey_send_x3(so, SADB_DUMP, satype)) < 0) 83155505Sshin return -1; 83255505Sshin 83355505Sshin return len; 83455505Sshin} 83555505Sshin 83655505Sshin/* 83755505Sshin * sending SADB_X_PROMISC message to the kernel. 83855505Sshin * NOTE that this function handles promisc mode toggle only. 83955505Sshin * IN: 84055505Sshin * flag: set promisc off if zero, set promisc on if non-zero. 84155505Sshin * OUT: 84255505Sshin * positive: success and return length sent. 84355505Sshin * -1 : error occured, and set errno. 84455505Sshin * 0 : error occured, and set errno. 84555505Sshin * others: a pointer to new allocated buffer in which supported 84655505Sshin * algorithms is. 84755505Sshin */ 84855505Sshinint 84955505Sshinpfkey_send_promisc_toggle(so, flag) 85055505Sshin int so; 85155505Sshin int flag; 85255505Sshin{ 85355505Sshin int len; 85455505Sshin 85555505Sshin if ((len = pfkey_send_x3(so, SADB_X_PROMISC, (flag ? 1 : 0))) < 0) 85655505Sshin return -1; 85755505Sshin 85855505Sshin return len; 85955505Sshin} 86055505Sshin 86155505Sshin/* 86255505Sshin * sending SADB_X_SPDADD message to the kernel. 86355505Sshin * OUT: 86455505Sshin * positive: success and return length sent. 86555505Sshin * -1 : error occured, and set errno. 86655505Sshin */ 86755505Sshinint 86855505Sshinpfkey_send_spdadd(so, src, prefs, dst, prefd, proto, policy, policylen, seq) 86955505Sshin int so; 87055505Sshin struct sockaddr *src, *dst; 87155505Sshin u_int prefs, prefd, proto; 87262583Sitojun caddr_t policy; 87355505Sshin int policylen; 87455505Sshin u_int32_t seq; 87555505Sshin{ 87655505Sshin int len; 87755505Sshin 87862583Sitojun if ((len = pfkey_send_x4(so, SADB_X_SPDADD, 87962583Sitojun src, prefs, dst, prefd, proto, 88078064Sume 0, 0, 88162583Sitojun policy, policylen, seq)) < 0) 88255505Sshin return -1; 88355505Sshin 88462583Sitojun return len; 88562583Sitojun} 88655505Sshin 88762583Sitojun/* 88878064Sume * sending SADB_X_SPDADD message to the kernel. 88978064Sume * OUT: 89078064Sume * positive: success and return length sent. 89178064Sume * -1 : error occured, and set errno. 89278064Sume */ 89378064Sumeint 89478064Sumepfkey_send_spdadd2(so, src, prefs, dst, prefd, proto, ltime, vtime, 89578064Sume policy, policylen, seq) 89678064Sume int so; 89778064Sume struct sockaddr *src, *dst; 89878064Sume u_int prefs, prefd, proto; 89978064Sume u_int64_t ltime, vtime; 90078064Sume caddr_t policy; 90178064Sume int policylen; 90278064Sume u_int32_t seq; 90378064Sume{ 90478064Sume int len; 90578064Sume 90678064Sume if ((len = pfkey_send_x4(so, SADB_X_SPDADD, 90778064Sume src, prefs, dst, prefd, proto, 90878064Sume ltime, vtime, 90978064Sume policy, policylen, seq)) < 0) 91078064Sume return -1; 91178064Sume 91278064Sume return len; 91378064Sume} 91478064Sume 91578064Sume/* 91662583Sitojun * sending SADB_X_SPDUPDATE message to the kernel. 91762583Sitojun * OUT: 91862583Sitojun * positive: success and return length sent. 91962583Sitojun * -1 : error occured, and set errno. 92062583Sitojun */ 92162583Sitojunint 92262583Sitojunpfkey_send_spdupdate(so, src, prefs, dst, prefd, proto, policy, policylen, seq) 92362583Sitojun int so; 92462583Sitojun struct sockaddr *src, *dst; 92562583Sitojun u_int prefs, prefd, proto; 92662583Sitojun caddr_t policy; 92762583Sitojun int policylen; 92862583Sitojun u_int32_t seq; 92962583Sitojun{ 93062583Sitojun int len; 93155505Sshin 93262583Sitojun if ((len = pfkey_send_x4(so, SADB_X_SPDUPDATE, 93362583Sitojun src, prefs, dst, prefd, proto, 93478064Sume 0, 0, 93562583Sitojun policy, policylen, seq)) < 0) 93655505Sshin return -1; 93755505Sshin 93855505Sshin return len; 93955505Sshin} 94055505Sshin 94155505Sshin/* 94278064Sume * sending SADB_X_SPDUPDATE message to the kernel. 94378064Sume * OUT: 94478064Sume * positive: success and return length sent. 94578064Sume * -1 : error occured, and set errno. 94678064Sume */ 94778064Sumeint 94878064Sumepfkey_send_spdupdate2(so, src, prefs, dst, prefd, proto, ltime, vtime, 94978064Sume policy, policylen, seq) 95078064Sume int so; 95178064Sume struct sockaddr *src, *dst; 95278064Sume u_int prefs, prefd, proto; 95378064Sume u_int64_t ltime, vtime; 95478064Sume caddr_t policy; 95578064Sume int policylen; 95678064Sume u_int32_t seq; 95778064Sume{ 95878064Sume int len; 95978064Sume 96078064Sume if ((len = pfkey_send_x4(so, SADB_X_SPDUPDATE, 96178064Sume src, prefs, dst, prefd, proto, 96278064Sume ltime, vtime, 96378064Sume policy, policylen, seq)) < 0) 96478064Sume return -1; 96578064Sume 96678064Sume return len; 96778064Sume} 96878064Sume 96978064Sume/* 97055505Sshin * sending SADB_X_SPDDELETE message to the kernel. 97155505Sshin * OUT: 97255505Sshin * positive: success and return length sent. 97355505Sshin * -1 : error occured, and set errno. 97455505Sshin */ 97555505Sshinint 97662583Sitojunpfkey_send_spddelete(so, src, prefs, dst, prefd, proto, policy, policylen, seq) 97755505Sshin int so; 97855505Sshin struct sockaddr *src, *dst; 97955505Sshin u_int prefs, prefd, proto; 98062583Sitojun caddr_t policy; 98162583Sitojun int policylen; 98255505Sshin u_int32_t seq; 98355505Sshin{ 98455505Sshin int len; 98555505Sshin 98662583Sitojun if (policylen != sizeof(struct sadb_x_policy)) { 98762583Sitojun __ipsec_errcode = EIPSEC_INVAL_ARGUMENT; 98855505Sshin return -1; 98955505Sshin } 99062583Sitojun 99162583Sitojun if ((len = pfkey_send_x4(so, SADB_X_SPDDELETE, 99262583Sitojun src, prefs, dst, prefd, proto, 99378064Sume 0, 0, 99462583Sitojun policy, policylen, seq)) < 0) 99555505Sshin return -1; 99662583Sitojun 99762583Sitojun return len; 99862583Sitojun} 99962583Sitojun 100062583Sitojun/* 100162583Sitojun * sending SADB_X_SPDDELETE message to the kernel. 100262583Sitojun * OUT: 100362583Sitojun * positive: success and return length sent. 100462583Sitojun * -1 : error occured, and set errno. 100562583Sitojun */ 100662583Sitojunint 100762583Sitojunpfkey_send_spddelete2(so, spid) 100862583Sitojun int so; 100962583Sitojun u_int32_t spid; 101062583Sitojun{ 101162583Sitojun int len; 101262583Sitojun 101362583Sitojun if ((len = pfkey_send_x5(so, SADB_X_SPDDELETE2, spid)) < 0) 101455505Sshin return -1; 101555505Sshin 101662583Sitojun return len; 101762583Sitojun} 101855505Sshin 101962583Sitojun/* 102062583Sitojun * sending SADB_X_SPDGET message to the kernel. 102162583Sitojun * OUT: 102262583Sitojun * positive: success and return length sent. 102362583Sitojun * -1 : error occured, and set errno. 102462583Sitojun */ 102562583Sitojunint 102662583Sitojunpfkey_send_spdget(so, spid) 102762583Sitojun int so; 102862583Sitojun u_int32_t spid; 102962583Sitojun{ 103062583Sitojun int len; 103162583Sitojun 103262583Sitojun if ((len = pfkey_send_x5(so, SADB_X_SPDGET, spid)) < 0) 103355505Sshin return -1; 103455505Sshin 103562583Sitojun return len; 103662583Sitojun} 103755505Sshin 103862583Sitojun/* 103962583Sitojun * sending SADB_X_SPDSETIDX message to the kernel. 104062583Sitojun * OUT: 104162583Sitojun * positive: success and return length sent. 104262583Sitojun * -1 : error occured, and set errno. 104362583Sitojun */ 104462583Sitojunint 104562583Sitojunpfkey_send_spdsetidx(so, src, prefs, dst, prefd, proto, policy, policylen, seq) 104662583Sitojun int so; 104762583Sitojun struct sockaddr *src, *dst; 104862583Sitojun u_int prefs, prefd, proto; 104962583Sitojun caddr_t policy; 105062583Sitojun int policylen; 105162583Sitojun u_int32_t seq; 105262583Sitojun{ 105362583Sitojun int len; 105455505Sshin 105562583Sitojun if (policylen != sizeof(struct sadb_x_policy)) { 105662583Sitojun __ipsec_errcode = EIPSEC_INVAL_ARGUMENT; 105755505Sshin return -1; 105862583Sitojun } 105955505Sshin 106062583Sitojun if ((len = pfkey_send_x4(so, SADB_X_SPDSETIDX, 106162583Sitojun src, prefs, dst, prefd, proto, 106278064Sume 0, 0, 106362583Sitojun policy, policylen, seq)) < 0) 106462583Sitojun return -1; 106562583Sitojun 106655505Sshin return len; 106755505Sshin} 106855505Sshin 106955505Sshin/* 107055505Sshin * sending SADB_SPDFLUSH message to the kernel. 107155505Sshin * OUT: 107255505Sshin * positive: success and return length sent. 107355505Sshin * -1 : error occured, and set errno. 107455505Sshin */ 107555505Sshinint 107655505Sshinpfkey_send_spdflush(so) 107755505Sshin int so; 107855505Sshin{ 107955505Sshin int len; 108055505Sshin 108155505Sshin if ((len = pfkey_send_x3(so, SADB_X_SPDFLUSH, SADB_SATYPE_UNSPEC)) < 0) 108255505Sshin return -1; 108355505Sshin 108455505Sshin return len; 108555505Sshin} 108655505Sshin 108755505Sshin/* 108855505Sshin * sending SADB_SPDDUMP message to the kernel. 108955505Sshin * OUT: 109055505Sshin * positive: success and return length sent. 109155505Sshin * -1 : error occured, and set errno. 109255505Sshin */ 109355505Sshinint 109455505Sshinpfkey_send_spddump(so) 109555505Sshin int so; 109655505Sshin{ 109755505Sshin int len; 109855505Sshin 109955505Sshin if ((len = pfkey_send_x3(so, SADB_X_SPDDUMP, SADB_SATYPE_UNSPEC)) < 0) 110055505Sshin return -1; 110155505Sshin 110255505Sshin return len; 110355505Sshin} 110455505Sshin 110555505Sshin/* sending SADB_ADD or SADB_UPDATE message to the kernel */ 110655505Sshinstatic int 110762583Sitojunpfkey_send_x1(so, type, satype, mode, src, dst, spi, reqid, wsize, 110855505Sshin keymat, e_type, e_keylen, a_type, a_keylen, flags, 110955505Sshin l_alloc, l_bytes, l_addtime, l_usetime, seq) 111055505Sshin int so; 111155505Sshin u_int type, satype, mode; 111255505Sshin struct sockaddr *src, *dst; 111362583Sitojun u_int32_t spi, reqid; 111455505Sshin u_int wsize; 111555505Sshin caddr_t keymat; 111655505Sshin u_int e_type, e_keylen, a_type, a_keylen, flags; 111755505Sshin u_int32_t l_alloc, l_bytes, l_addtime, l_usetime, seq; 111855505Sshin{ 111955505Sshin struct sadb_msg *newmsg; 112055505Sshin int len; 112155505Sshin caddr_t p; 112262583Sitojun int plen; 112378064Sume caddr_t ep; 112455505Sshin 112555505Sshin /* validity check */ 112655505Sshin if (src == NULL || dst == NULL) { 112762583Sitojun __ipsec_errcode = EIPSEC_INVAL_ARGUMENT; 112855505Sshin return -1; 112955505Sshin } 113055505Sshin if (src->sa_family != dst->sa_family) { 113162583Sitojun __ipsec_errcode = EIPSEC_FAMILY_MISMATCH; 113255505Sshin return -1; 113355505Sshin } 113462583Sitojun switch (src->sa_family) { 113562583Sitojun case AF_INET: 113662583Sitojun plen = sizeof(struct in_addr) << 3; 113762583Sitojun break; 113862583Sitojun case AF_INET6: 113962583Sitojun plen = sizeof(struct in6_addr) << 3; 114062583Sitojun break; 114162583Sitojun default: 114262583Sitojun __ipsec_errcode = EIPSEC_INVAL_FAMILY; 114362583Sitojun return -1; 114462583Sitojun } 114555505Sshin 114655505Sshin switch (satype) { 114755505Sshin case SADB_SATYPE_ESP: 114855505Sshin if (e_type == SADB_EALG_NONE) { 114962583Sitojun __ipsec_errcode = EIPSEC_NO_ALGS; 115055505Sshin return -1; 115155505Sshin } 115255505Sshin break; 115355505Sshin case SADB_SATYPE_AH: 115455505Sshin if (e_type != SADB_EALG_NONE) { 115562583Sitojun __ipsec_errcode = EIPSEC_INVAL_ALGS; 115655505Sshin return -1; 115755505Sshin } 115855505Sshin if (a_type == SADB_AALG_NONE) { 115962583Sitojun __ipsec_errcode = EIPSEC_NO_ALGS; 116055505Sshin return -1; 116155505Sshin } 116255505Sshin break; 116355505Sshin case SADB_X_SATYPE_IPCOMP: 116478064Sume if (e_type == SADB_X_CALG_NONE) { 116578064Sume __ipsec_errcode = EIPSEC_INVAL_ALGS; 116678064Sume return -1; 116778064Sume } 116878064Sume if (a_type != SADB_AALG_NONE) { 116978064Sume __ipsec_errcode = EIPSEC_NO_ALGS; 117078064Sume return -1; 117178064Sume } 117255505Sshin break; 1173125681Sbms case SADB_X_SATYPE_TCPSIGNATURE: 1174125681Sbms if (e_type != SADB_EALG_NONE) { 1175125681Sbms __ipsec_errcode = EIPSEC_INVAL_ALGS; 1176125681Sbms return -1; 1177125681Sbms } 1178125681Sbms if (a_type != SADB_X_AALG_TCP_MD5) { 1179125681Sbms __ipsec_errcode = EIPSEC_INVAL_ALGS; 1180125681Sbms return -1; 1181125681Sbms } 1182125681Sbms break; 118355505Sshin default: 118462583Sitojun __ipsec_errcode = EIPSEC_INVAL_SATYPE; 118555505Sshin return -1; 118655505Sshin } 118755505Sshin 118855505Sshin /* create new sadb_msg to reply. */ 118955505Sshin len = sizeof(struct sadb_msg) 119055505Sshin + sizeof(struct sadb_sa) 119162583Sitojun + sizeof(struct sadb_x_sa2) 119255505Sshin + sizeof(struct sadb_address) 119355505Sshin + PFKEY_ALIGN8(src->sa_len) 119455505Sshin + sizeof(struct sadb_address) 119555505Sshin + PFKEY_ALIGN8(dst->sa_len) 119655505Sshin + sizeof(struct sadb_lifetime) 119755505Sshin + sizeof(struct sadb_lifetime); 119855505Sshin 119955505Sshin if (e_type != SADB_EALG_NONE) 120055505Sshin len += (sizeof(struct sadb_key) + PFKEY_ALIGN8(e_keylen)); 120155505Sshin if (a_type != SADB_AALG_NONE) 120255505Sshin len += (sizeof(struct sadb_key) + PFKEY_ALIGN8(a_keylen)); 120355505Sshin 120455505Sshin if ((newmsg = CALLOC(len, struct sadb_msg *)) == NULL) { 120562583Sitojun __ipsec_set_strerror(strerror(errno)); 120655505Sshin return -1; 120755505Sshin } 120878064Sume ep = ((caddr_t)newmsg) + len; 120955505Sshin 121078064Sume p = pfkey_setsadbmsg((caddr_t)newmsg, ep, type, len, 121162583Sitojun satype, seq, getpid()); 121278064Sume if (!p) { 121378064Sume free(newmsg); 121478064Sume return -1; 121578064Sume } 121678064Sume p = pfkey_setsadbsa(p, ep, spi, wsize, a_type, e_type, flags); 121778064Sume if (!p) { 121878064Sume free(newmsg); 121978064Sume return -1; 122078064Sume } 122178064Sume p = pfkey_setsadbxsa2(p, ep, mode, reqid); 122278064Sume if (!p) { 122378064Sume free(newmsg); 122478064Sume return -1; 122578064Sume } 122678064Sume p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_SRC, src, plen, 122762583Sitojun IPSEC_ULPROTO_ANY); 122878064Sume if (!p) { 122978064Sume free(newmsg); 123078064Sume return -1; 123178064Sume } 123278064Sume p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_DST, dst, plen, 123362583Sitojun IPSEC_ULPROTO_ANY); 123478064Sume if (!p) { 123578064Sume free(newmsg); 123678064Sume return -1; 123778064Sume } 123855505Sshin 123978064Sume if (e_type != SADB_EALG_NONE) { 124078064Sume p = pfkey_setsadbkey(p, ep, SADB_EXT_KEY_ENCRYPT, 124155505Sshin keymat, e_keylen); 124278064Sume if (!p) { 124378064Sume free(newmsg); 124478064Sume return -1; 124578064Sume } 124678064Sume } 124778064Sume if (a_type != SADB_AALG_NONE) { 124878064Sume p = pfkey_setsadbkey(p, ep, SADB_EXT_KEY_AUTH, 124955505Sshin keymat + e_keylen, a_keylen); 125078064Sume if (!p) { 125178064Sume free(newmsg); 125278064Sume return -1; 125378064Sume } 125478064Sume } 125555505Sshin 125655505Sshin /* set sadb_lifetime for destination */ 125778064Sume p = pfkey_setsadblifetime(p, ep, SADB_EXT_LIFETIME_HARD, 125855505Sshin l_alloc, l_bytes, l_addtime, l_usetime); 125978064Sume if (!p) { 126078064Sume free(newmsg); 126178064Sume return -1; 126278064Sume } 126378064Sume p = pfkey_setsadblifetime(p, ep, SADB_EXT_LIFETIME_SOFT, 126455505Sshin l_alloc, l_bytes, l_addtime, l_usetime); 126578064Sume if (!p || p != ep) { 126678064Sume free(newmsg); 126778064Sume return -1; 126878064Sume } 126955505Sshin 127055505Sshin /* send message */ 127155505Sshin len = pfkey_send(so, newmsg, len); 127255505Sshin free(newmsg); 127355505Sshin 127455505Sshin if (len < 0) 127555505Sshin return -1; 127655505Sshin 127762583Sitojun __ipsec_errcode = EIPSEC_NO_ERROR; 127855505Sshin return len; 127955505Sshin} 128055505Sshin 128155505Sshin/* sending SADB_DELETE or SADB_GET message to the kernel */ 128255505Sshinstatic int 128355505Sshinpfkey_send_x2(so, type, satype, mode, src, dst, spi) 128455505Sshin int so; 128555505Sshin u_int type, satype, mode; 128655505Sshin struct sockaddr *src, *dst; 128755505Sshin u_int32_t spi; 128855505Sshin{ 128955505Sshin struct sadb_msg *newmsg; 129055505Sshin int len; 129155505Sshin caddr_t p; 129262583Sitojun int plen; 129378064Sume caddr_t ep; 129455505Sshin 129555505Sshin /* validity check */ 129655505Sshin if (src == NULL || dst == NULL) { 129762583Sitojun __ipsec_errcode = EIPSEC_INVAL_ARGUMENT; 129855505Sshin return -1; 129955505Sshin } 130055505Sshin if (src->sa_family != dst->sa_family) { 130162583Sitojun __ipsec_errcode = EIPSEC_FAMILY_MISMATCH; 130255505Sshin return -1; 130355505Sshin } 130462583Sitojun switch (src->sa_family) { 130562583Sitojun case AF_INET: 130662583Sitojun plen = sizeof(struct in_addr) << 3; 130762583Sitojun break; 130862583Sitojun case AF_INET6: 130962583Sitojun plen = sizeof(struct in6_addr) << 3; 131062583Sitojun break; 131162583Sitojun default: 131262583Sitojun __ipsec_errcode = EIPSEC_INVAL_FAMILY; 131362583Sitojun return -1; 131462583Sitojun } 131555505Sshin 131655505Sshin /* create new sadb_msg to reply. */ 131755505Sshin len = sizeof(struct sadb_msg) 131855505Sshin + sizeof(struct sadb_sa) 131955505Sshin + sizeof(struct sadb_address) 132055505Sshin + PFKEY_ALIGN8(src->sa_len) 132155505Sshin + sizeof(struct sadb_address) 132255505Sshin + PFKEY_ALIGN8(dst->sa_len); 132355505Sshin 132455505Sshin if ((newmsg = CALLOC(len, struct sadb_msg *)) == NULL) { 132562583Sitojun __ipsec_set_strerror(strerror(errno)); 132655505Sshin return -1; 132755505Sshin } 132878064Sume ep = ((caddr_t)newmsg) + len; 132955505Sshin 133078064Sume p = pfkey_setsadbmsg((caddr_t)newmsg, ep, type, len, satype, 0, 133178064Sume getpid()); 133278064Sume if (!p) { 133378064Sume free(newmsg); 133478064Sume return -1; 133578064Sume } 133678064Sume p = pfkey_setsadbsa(p, ep, spi, 0, 0, 0, 0); 133778064Sume if (!p) { 133878064Sume free(newmsg); 133978064Sume return -1; 134078064Sume } 134178064Sume p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_SRC, src, plen, 134262583Sitojun IPSEC_ULPROTO_ANY); 134378064Sume if (!p) { 134478064Sume free(newmsg); 134578064Sume return -1; 134678064Sume } 134778064Sume p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_DST, dst, plen, 134862583Sitojun IPSEC_ULPROTO_ANY); 134978064Sume if (!p || p != ep) { 135078064Sume free(newmsg); 135178064Sume return -1; 135278064Sume } 135355505Sshin 135455505Sshin /* send message */ 135555505Sshin len = pfkey_send(so, newmsg, len); 135655505Sshin free(newmsg); 135755505Sshin 135855505Sshin if (len < 0) 135955505Sshin return -1; 136055505Sshin 136162583Sitojun __ipsec_errcode = EIPSEC_NO_ERROR; 136255505Sshin return len; 136355505Sshin} 136455505Sshin 136555505Sshin/* 136655505Sshin * sending SADB_REGISTER, SADB_FLUSH, SADB_DUMP or SADB_X_PROMISC message 136755505Sshin * to the kernel 136855505Sshin */ 136955505Sshinstatic int 137055505Sshinpfkey_send_x3(so, type, satype) 137155505Sshin int so; 137255505Sshin u_int type, satype; 137355505Sshin{ 137455505Sshin struct sadb_msg *newmsg; 137555505Sshin int len; 137678064Sume caddr_t p; 137778064Sume caddr_t ep; 137855505Sshin 137955505Sshin /* validity check */ 138055505Sshin switch (type) { 138155505Sshin case SADB_X_PROMISC: 138255505Sshin if (satype != 0 && satype != 1) { 138362583Sitojun __ipsec_errcode = EIPSEC_INVAL_SATYPE; 138455505Sshin return -1; 138555505Sshin } 138655505Sshin break; 138755505Sshin default: 138855505Sshin switch (satype) { 138955505Sshin case SADB_SATYPE_UNSPEC: 139055505Sshin case SADB_SATYPE_AH: 139155505Sshin case SADB_SATYPE_ESP: 139255505Sshin case SADB_X_SATYPE_IPCOMP: 1393125681Sbms case SADB_X_SATYPE_TCPSIGNATURE: 139455505Sshin break; 139555505Sshin default: 139662583Sitojun __ipsec_errcode = EIPSEC_INVAL_SATYPE; 139755505Sshin return -1; 139855505Sshin } 139955505Sshin } 140055505Sshin 140155505Sshin /* create new sadb_msg to send. */ 140255505Sshin len = sizeof(struct sadb_msg); 140355505Sshin 140455505Sshin if ((newmsg = CALLOC(len, struct sadb_msg *)) == NULL) { 140562583Sitojun __ipsec_set_strerror(strerror(errno)); 140655505Sshin return -1; 140755505Sshin } 140878064Sume ep = ((caddr_t)newmsg) + len; 140955505Sshin 141078064Sume p = pfkey_setsadbmsg((caddr_t)newmsg, ep, type, len, satype, 0, 141178064Sume getpid()); 141278064Sume if (!p || p != ep) { 141378064Sume free(newmsg); 141478064Sume return -1; 141578064Sume } 141655505Sshin 141755505Sshin /* send message */ 141855505Sshin len = pfkey_send(so, newmsg, len); 141955505Sshin free(newmsg); 142055505Sshin 142155505Sshin if (len < 0) 142255505Sshin return -1; 142355505Sshin 142462583Sitojun __ipsec_errcode = EIPSEC_NO_ERROR; 142555505Sshin return len; 142655505Sshin} 142755505Sshin 142862583Sitojun/* sending SADB_X_SPDADD message to the kernel */ 142962583Sitojunstatic int 143078064Sumepfkey_send_x4(so, type, src, prefs, dst, prefd, proto, 143178064Sume ltime, vtime, policy, policylen, seq) 143262583Sitojun int so; 143362583Sitojun struct sockaddr *src, *dst; 143462583Sitojun u_int type, prefs, prefd, proto; 143578064Sume u_int64_t ltime, vtime; 143662583Sitojun char *policy; 143762583Sitojun int policylen; 143862583Sitojun u_int32_t seq; 143962583Sitojun{ 144062583Sitojun struct sadb_msg *newmsg; 144162583Sitojun int len; 144262583Sitojun caddr_t p; 144362583Sitojun int plen; 144478064Sume caddr_t ep; 144562583Sitojun 144662583Sitojun /* validity check */ 144762583Sitojun if (src == NULL || dst == NULL) { 144862583Sitojun __ipsec_errcode = EIPSEC_INVAL_ARGUMENT; 144962583Sitojun return -1; 145062583Sitojun } 145162583Sitojun if (src->sa_family != dst->sa_family) { 145262583Sitojun __ipsec_errcode = EIPSEC_FAMILY_MISMATCH; 145362583Sitojun return -1; 145462583Sitojun } 145562583Sitojun 145662583Sitojun switch (src->sa_family) { 145762583Sitojun case AF_INET: 145862583Sitojun plen = sizeof(struct in_addr) << 3; 145962583Sitojun break; 146062583Sitojun case AF_INET6: 146162583Sitojun plen = sizeof(struct in6_addr) << 3; 146262583Sitojun break; 146362583Sitojun default: 146462583Sitojun __ipsec_errcode = EIPSEC_INVAL_FAMILY; 146562583Sitojun return -1; 146662583Sitojun } 146762583Sitojun if (prefs > plen || prefd > plen) { 146862583Sitojun __ipsec_errcode = EIPSEC_INVAL_PREFIXLEN; 146962583Sitojun return -1; 147062583Sitojun } 147162583Sitojun 147262583Sitojun /* create new sadb_msg to reply. */ 147362583Sitojun len = sizeof(struct sadb_msg) 147462583Sitojun + sizeof(struct sadb_address) 147562583Sitojun + PFKEY_ALIGN8(src->sa_len) 147662583Sitojun + sizeof(struct sadb_address) 147762583Sitojun + PFKEY_ALIGN8(src->sa_len) 147878064Sume + sizeof(struct sadb_lifetime) 147962583Sitojun + policylen; 148062583Sitojun 148162583Sitojun if ((newmsg = CALLOC(len, struct sadb_msg *)) == NULL) { 148262583Sitojun __ipsec_set_strerror(strerror(errno)); 148362583Sitojun return -1; 148462583Sitojun } 148578064Sume ep = ((caddr_t)newmsg) + len; 148662583Sitojun 148778064Sume p = pfkey_setsadbmsg((caddr_t)newmsg, ep, type, len, 148878064Sume SADB_SATYPE_UNSPEC, seq, getpid()); 148978064Sume if (!p) { 149078064Sume free(newmsg); 149178064Sume return -1; 149278064Sume } 149378064Sume p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_SRC, src, prefs, proto); 149478064Sume if (!p) { 149578064Sume free(newmsg); 149678064Sume return -1; 149778064Sume } 149878064Sume p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_DST, dst, prefd, proto); 149978064Sume if (!p) { 150078064Sume free(newmsg); 150178064Sume return -1; 150278064Sume } 150378064Sume p = pfkey_setsadblifetime(p, ep, SADB_EXT_LIFETIME_HARD, 150478064Sume 0, 0, ltime, vtime); 150578064Sume if (!p || p + policylen != ep) { 150678064Sume free(newmsg); 150778064Sume return -1; 150878064Sume } 150962583Sitojun memcpy(p, policy, policylen); 151062583Sitojun 151162583Sitojun /* send message */ 151262583Sitojun len = pfkey_send(so, newmsg, len); 151362583Sitojun free(newmsg); 151462583Sitojun 151562583Sitojun if (len < 0) 151662583Sitojun return -1; 151762583Sitojun 151862583Sitojun __ipsec_errcode = EIPSEC_NO_ERROR; 151962583Sitojun return len; 152062583Sitojun} 152162583Sitojun 152262583Sitojun/* sending SADB_X_SPDGET or SADB_X_SPDDELETE message to the kernel */ 152362583Sitojunstatic int 152462583Sitojunpfkey_send_x5(so, type, spid) 152562583Sitojun int so; 152662583Sitojun u_int type; 152762583Sitojun u_int32_t spid; 152862583Sitojun{ 152962583Sitojun struct sadb_msg *newmsg; 153062583Sitojun struct sadb_x_policy xpl; 153162583Sitojun int len; 153262583Sitojun caddr_t p; 153378064Sume caddr_t ep; 153462583Sitojun 153562583Sitojun /* create new sadb_msg to reply. */ 153662583Sitojun len = sizeof(struct sadb_msg) 153762583Sitojun + sizeof(xpl); 153862583Sitojun 153962583Sitojun if ((newmsg = CALLOC(len, struct sadb_msg *)) == NULL) { 154062583Sitojun __ipsec_set_strerror(strerror(errno)); 154162583Sitojun return -1; 154262583Sitojun } 154378064Sume ep = ((caddr_t)newmsg) + len; 154462583Sitojun 154578064Sume p = pfkey_setsadbmsg((caddr_t)newmsg, ep, type, len, 154678064Sume SADB_SATYPE_UNSPEC, 0, getpid()); 154778064Sume if (!p) { 154878064Sume free(newmsg); 154978064Sume return -1; 155078064Sume } 155162583Sitojun 155278064Sume if (p + sizeof(xpl) != ep) { 155378064Sume free(newmsg); 155478064Sume return -1; 155578064Sume } 155662583Sitojun memset(&xpl, 0, sizeof(xpl)); 1557122107Sume xpl.sadb_x_policy_len = PFKEY_UNIT64(sizeof(xpl)); 155862583Sitojun xpl.sadb_x_policy_exttype = SADB_X_EXT_POLICY; 155962583Sitojun xpl.sadb_x_policy_id = spid; 156062583Sitojun memcpy(p, &xpl, sizeof(xpl)); 156162583Sitojun 156262583Sitojun /* send message */ 156362583Sitojun len = pfkey_send(so, newmsg, len); 156462583Sitojun free(newmsg); 156562583Sitojun 156662583Sitojun if (len < 0) 156762583Sitojun return -1; 156862583Sitojun 156962583Sitojun __ipsec_errcode = EIPSEC_NO_ERROR; 157062583Sitojun return len; 157162583Sitojun} 157262583Sitojun 157355505Sshin/* 157455505Sshin * open a socket. 157555505Sshin * OUT: 157655505Sshin * -1: fail. 157755505Sshin * others : success and return value of socket. 157855505Sshin */ 157955505Sshinint 158055505Sshinpfkey_open() 158155505Sshin{ 158255505Sshin int so; 158355505Sshin const int bufsiz = 128 * 1024; /*is 128K enough?*/ 158455505Sshin 158555505Sshin if ((so = socket(PF_KEY, SOCK_RAW, PF_KEY_V2)) < 0) { 158662583Sitojun __ipsec_set_strerror(strerror(errno)); 158755505Sshin return -1; 158855505Sshin } 158955505Sshin 159055505Sshin /* 159155505Sshin * This is a temporary workaround for KAME PR 154. 159255505Sshin * Don't really care even if it fails. 159355505Sshin */ 159455505Sshin (void)setsockopt(so, SOL_SOCKET, SO_SNDBUF, &bufsiz, sizeof(bufsiz)); 159555505Sshin (void)setsockopt(so, SOL_SOCKET, SO_RCVBUF, &bufsiz, sizeof(bufsiz)); 159655505Sshin 159762583Sitojun __ipsec_errcode = EIPSEC_NO_ERROR; 159855505Sshin return so; 159955505Sshin} 160055505Sshin 160155505Sshin/* 160255505Sshin * close a socket. 160355505Sshin * OUT: 160455505Sshin * 0: success. 160555505Sshin * -1: fail. 160655505Sshin */ 160755505Sshinvoid 160855505Sshinpfkey_close(so) 160955505Sshin int so; 161055505Sshin{ 161155505Sshin (void)close(so); 161255505Sshin 161362583Sitojun __ipsec_errcode = EIPSEC_NO_ERROR; 161455505Sshin return; 161555505Sshin} 161655505Sshin 161755505Sshin/* 161855505Sshin * receive sadb_msg data, and return pointer to new buffer allocated. 161955505Sshin * Must free this buffer later. 162055505Sshin * OUT: 162155505Sshin * NULL : error occured. 162255505Sshin * others : a pointer to sadb_msg structure. 162378064Sume * 162478064Sume * XXX should be rewritten to pass length explicitly 162555505Sshin */ 162655505Sshinstruct sadb_msg * 162755505Sshinpfkey_recv(so) 162855505Sshin int so; 162955505Sshin{ 163055505Sshin struct sadb_msg buf, *newmsg; 163155505Sshin int len, reallen; 163255505Sshin 163355505Sshin while ((len = recv(so, (caddr_t)&buf, sizeof(buf), MSG_PEEK)) < 0) { 163478064Sume if (errno == EINTR) 163578064Sume continue; 163662583Sitojun __ipsec_set_strerror(strerror(errno)); 163755505Sshin return NULL; 163855505Sshin } 163955505Sshin 164055505Sshin if (len < sizeof(buf)) { 164155505Sshin recv(so, (caddr_t)&buf, sizeof(buf), 0); 164262583Sitojun __ipsec_errcode = EIPSEC_MAX; 164355505Sshin return NULL; 164455505Sshin } 164555505Sshin 164655505Sshin /* read real message */ 164755505Sshin reallen = PFKEY_UNUNIT64(buf.sadb_msg_len); 164855505Sshin if ((newmsg = CALLOC(reallen, struct sadb_msg *)) == 0) { 164962583Sitojun __ipsec_set_strerror(strerror(errno)); 165055505Sshin return NULL; 165155505Sshin } 165255505Sshin 165355505Sshin while ((len = recv(so, (caddr_t)newmsg, reallen, 0)) < 0) { 165478064Sume if (errno == EINTR) 165578064Sume continue; 165662583Sitojun __ipsec_set_strerror(strerror(errno)); 165755505Sshin free(newmsg); 165855505Sshin return NULL; 165955505Sshin } 166055505Sshin 166155505Sshin if (len != reallen) { 166262583Sitojun __ipsec_errcode = EIPSEC_SYSTEM_ERROR; 166355505Sshin free(newmsg); 166455505Sshin return NULL; 166555505Sshin } 166655505Sshin 166778064Sume /* don't trust what the kernel says, validate! */ 166878064Sume if (PFKEY_UNUNIT64(newmsg->sadb_msg_len) != len) { 166978064Sume __ipsec_errcode = EIPSEC_SYSTEM_ERROR; 167078064Sume free(newmsg); 167178064Sume return NULL; 167278064Sume } 167378064Sume 167462583Sitojun __ipsec_errcode = EIPSEC_NO_ERROR; 167555505Sshin return newmsg; 167655505Sshin} 167755505Sshin 167855505Sshin/* 167955505Sshin * send message to a socket. 168055505Sshin * OUT: 168155505Sshin * others: success and return length sent. 168255505Sshin * -1 : fail. 168355505Sshin */ 168455505Sshinint 168555505Sshinpfkey_send(so, msg, len) 168655505Sshin int so; 168755505Sshin struct sadb_msg *msg; 168855505Sshin int len; 168955505Sshin{ 169055505Sshin if ((len = send(so, (caddr_t)msg, len, 0)) < 0) { 169162583Sitojun __ipsec_set_strerror(strerror(errno)); 169255505Sshin return -1; 169355505Sshin } 169455505Sshin 169562583Sitojun __ipsec_errcode = EIPSEC_NO_ERROR; 169655505Sshin return len; 169755505Sshin} 169855505Sshin 169955505Sshin/* 170055505Sshin * %%% Utilities 170155505Sshin * NOTE: These functions are derived from netkey/key.c in KAME. 170255505Sshin */ 170355505Sshin/* 170455505Sshin * set the pointer to each header in this message buffer. 170555505Sshin * IN: msg: pointer to message buffer. 170655505Sshin * mhp: pointer to the buffer initialized like below: 170755505Sshin * caddr_t mhp[SADB_EXT_MAX + 1]; 170855505Sshin * OUT: -1: invalid. 170955505Sshin * 0: valid. 171078064Sume * 171178064Sume * XXX should be rewritten to obtain length explicitly 171255505Sshin */ 171355505Sshinint 171455505Sshinpfkey_align(msg, mhp) 171555505Sshin struct sadb_msg *msg; 171655505Sshin caddr_t *mhp; 171755505Sshin{ 171855505Sshin struct sadb_ext *ext; 171955505Sshin int i; 172078064Sume caddr_t p; 172178064Sume caddr_t ep; /* XXX should be passed from upper layer */ 172255505Sshin 172355505Sshin /* validity check */ 172455505Sshin if (msg == NULL || mhp == NULL) { 172562583Sitojun __ipsec_errcode = EIPSEC_INVAL_ARGUMENT; 172655505Sshin return -1; 172755505Sshin } 172855505Sshin 172955505Sshin /* initialize */ 173055505Sshin for (i = 0; i < SADB_EXT_MAX + 1; i++) 173155505Sshin mhp[i] = NULL; 173255505Sshin 173355505Sshin mhp[0] = (caddr_t)msg; 173455505Sshin 173578064Sume /* initialize */ 173678064Sume p = (caddr_t) msg; 173778064Sume ep = p + PFKEY_UNUNIT64(msg->sadb_msg_len); 173855505Sshin 173978064Sume /* skip base header */ 174078064Sume p += sizeof(struct sadb_msg); 174178064Sume 174278064Sume while (p < ep) { 174378064Sume ext = (struct sadb_ext *)p; 174478064Sume if (ep < p + sizeof(*ext) || PFKEY_EXTLEN(ext) < sizeof(*ext) || 174578064Sume ep < p + PFKEY_EXTLEN(ext)) { 174678064Sume /* invalid format */ 174778064Sume break; 174878064Sume } 174978064Sume 175055505Sshin /* duplicate check */ 175155505Sshin /* XXX Are there duplication either KEY_AUTH or KEY_ENCRYPT ?*/ 175255505Sshin if (mhp[ext->sadb_ext_type] != NULL) { 175362583Sitojun __ipsec_errcode = EIPSEC_INVAL_EXTTYPE; 175455505Sshin return -1; 175555505Sshin } 175655505Sshin 175755505Sshin /* set pointer */ 175855505Sshin switch (ext->sadb_ext_type) { 175955505Sshin case SADB_EXT_SA: 176055505Sshin case SADB_EXT_LIFETIME_CURRENT: 176155505Sshin case SADB_EXT_LIFETIME_HARD: 176255505Sshin case SADB_EXT_LIFETIME_SOFT: 176355505Sshin case SADB_EXT_ADDRESS_SRC: 176455505Sshin case SADB_EXT_ADDRESS_DST: 176555505Sshin case SADB_EXT_ADDRESS_PROXY: 176655505Sshin case SADB_EXT_KEY_AUTH: 176755505Sshin /* XXX should to be check weak keys. */ 176855505Sshin case SADB_EXT_KEY_ENCRYPT: 176955505Sshin /* XXX should to be check weak keys. */ 177055505Sshin case SADB_EXT_IDENTITY_SRC: 177155505Sshin case SADB_EXT_IDENTITY_DST: 177255505Sshin case SADB_EXT_SENSITIVITY: 177355505Sshin case SADB_EXT_PROPOSAL: 177455505Sshin case SADB_EXT_SUPPORTED_AUTH: 177555505Sshin case SADB_EXT_SUPPORTED_ENCRYPT: 177655505Sshin case SADB_EXT_SPIRANGE: 177755505Sshin case SADB_X_EXT_POLICY: 177862583Sitojun case SADB_X_EXT_SA2: 177955505Sshin mhp[ext->sadb_ext_type] = (caddr_t)ext; 178055505Sshin break; 1781231532Sbz case SADB_X_EXT_NAT_T_TYPE: 1782231532Sbz case SADB_X_EXT_NAT_T_SPORT: 1783231532Sbz case SADB_X_EXT_NAT_T_DPORT: 1784231532Sbz /* case SADB_X_EXT_NAT_T_OA: is OAI */ 1785231532Sbz case SADB_X_EXT_NAT_T_OAI: 1786231532Sbz case SADB_X_EXT_NAT_T_OAR: 1787231532Sbz case SADB_X_EXT_NAT_T_FRAG: 1788231532Sbz if (feature_present("ipsec_natt")) { 1789231532Sbz mhp[ext->sadb_ext_type] = (caddr_t)ext; 1790231532Sbz break; 1791231532Sbz } 1792231532Sbz /* FALLTHROUGH */ 179355505Sshin default: 179462583Sitojun __ipsec_errcode = EIPSEC_INVAL_EXTTYPE; 179555505Sshin return -1; 179655505Sshin } 179755505Sshin 179878064Sume p += PFKEY_EXTLEN(ext); 179955505Sshin } 180055505Sshin 180178064Sume if (p != ep) { 180278064Sume __ipsec_errcode = EIPSEC_INVAL_SADBMSG; 180378064Sume return -1; 180478064Sume } 180578064Sume 180662583Sitojun __ipsec_errcode = EIPSEC_NO_ERROR; 180755505Sshin return 0; 180855505Sshin} 180955505Sshin 181055505Sshin/* 181155505Sshin * check basic usage for sadb_msg, 181255505Sshin * NOTE: This routine is derived from netkey/key.c in KAME. 181355505Sshin * IN: msg: pointer to message buffer. 181455505Sshin * mhp: pointer to the buffer initialized like below: 181555505Sshin * 181655505Sshin * caddr_t mhp[SADB_EXT_MAX + 1]; 181755505Sshin * 181855505Sshin * OUT: -1: invalid. 181955505Sshin * 0: valid. 182055505Sshin */ 182155505Sshinint 182255505Sshinpfkey_check(mhp) 182355505Sshin caddr_t *mhp; 182455505Sshin{ 182555505Sshin struct sadb_msg *msg; 182655505Sshin 182755505Sshin /* validity check */ 182855505Sshin if (mhp == NULL || mhp[0] == NULL) { 182962583Sitojun __ipsec_errcode = EIPSEC_INVAL_ARGUMENT; 183055505Sshin return -1; 183155505Sshin } 183255505Sshin 183355505Sshin msg = (struct sadb_msg *)mhp[0]; 183455505Sshin 183555505Sshin /* check version */ 183655505Sshin if (msg->sadb_msg_version != PF_KEY_V2) { 183762583Sitojun __ipsec_errcode = EIPSEC_INVAL_VERSION; 183855505Sshin return -1; 183955505Sshin } 184055505Sshin 184155505Sshin /* check type */ 184255505Sshin if (msg->sadb_msg_type > SADB_MAX) { 184362583Sitojun __ipsec_errcode = EIPSEC_INVAL_MSGTYPE; 184455505Sshin return -1; 184555505Sshin } 184655505Sshin 184755505Sshin /* check SA type */ 184855505Sshin switch (msg->sadb_msg_satype) { 184955505Sshin case SADB_SATYPE_UNSPEC: 185055505Sshin switch (msg->sadb_msg_type) { 185155505Sshin case SADB_GETSPI: 185255505Sshin case SADB_UPDATE: 185355505Sshin case SADB_ADD: 185455505Sshin case SADB_DELETE: 185555505Sshin case SADB_GET: 185655505Sshin case SADB_ACQUIRE: 185755505Sshin case SADB_EXPIRE: 185862583Sitojun __ipsec_errcode = EIPSEC_INVAL_SATYPE; 185955505Sshin return -1; 186055505Sshin } 186155505Sshin break; 186255505Sshin case SADB_SATYPE_ESP: 186355505Sshin case SADB_SATYPE_AH: 186455505Sshin case SADB_X_SATYPE_IPCOMP: 1865125681Sbms case SADB_X_SATYPE_TCPSIGNATURE: 186655505Sshin switch (msg->sadb_msg_type) { 186755505Sshin case SADB_X_SPDADD: 186855505Sshin case SADB_X_SPDDELETE: 186955505Sshin case SADB_X_SPDGET: 187055505Sshin case SADB_X_SPDDUMP: 187155505Sshin case SADB_X_SPDFLUSH: 187262583Sitojun __ipsec_errcode = EIPSEC_INVAL_SATYPE; 187355505Sshin return -1; 187455505Sshin } 187555505Sshin break; 187655505Sshin case SADB_SATYPE_RSVP: 187755505Sshin case SADB_SATYPE_OSPFV2: 187855505Sshin case SADB_SATYPE_RIPV2: 187955505Sshin case SADB_SATYPE_MIP: 188062583Sitojun __ipsec_errcode = EIPSEC_NOT_SUPPORTED; 188155505Sshin return -1; 188255505Sshin case 1: /* XXX: What does it do ? */ 188355505Sshin if (msg->sadb_msg_type == SADB_X_PROMISC) 188455505Sshin break; 188555505Sshin /*FALLTHROUGH*/ 188655505Sshin default: 188762583Sitojun __ipsec_errcode = EIPSEC_INVAL_SATYPE; 188855505Sshin return -1; 188955505Sshin } 189055505Sshin 189155505Sshin /* check field of upper layer protocol and address family */ 189255505Sshin if (mhp[SADB_EXT_ADDRESS_SRC] != NULL 189355505Sshin && mhp[SADB_EXT_ADDRESS_DST] != NULL) { 189455505Sshin struct sadb_address *src0, *dst0; 189555505Sshin 189655505Sshin src0 = (struct sadb_address *)(mhp[SADB_EXT_ADDRESS_SRC]); 189755505Sshin dst0 = (struct sadb_address *)(mhp[SADB_EXT_ADDRESS_DST]); 189855505Sshin 189955505Sshin if (src0->sadb_address_proto != dst0->sadb_address_proto) { 190062583Sitojun __ipsec_errcode = EIPSEC_PROTO_MISMATCH; 190155505Sshin return -1; 190255505Sshin } 190355505Sshin 190455505Sshin if (PFKEY_ADDR_SADDR(src0)->sa_family 190555505Sshin != PFKEY_ADDR_SADDR(dst0)->sa_family) { 190662583Sitojun __ipsec_errcode = EIPSEC_FAMILY_MISMATCH; 190755505Sshin return -1; 190855505Sshin } 190955505Sshin 191055505Sshin switch (PFKEY_ADDR_SADDR(src0)->sa_family) { 191155505Sshin case AF_INET: 191255505Sshin case AF_INET6: 191355505Sshin break; 191455505Sshin default: 191562583Sitojun __ipsec_errcode = EIPSEC_INVAL_FAMILY; 191655505Sshin return -1; 191755505Sshin } 191855505Sshin 191955505Sshin /* 192055505Sshin * prefixlen == 0 is valid because there must be the case 192155505Sshin * all addresses are matched. 192255505Sshin */ 192355505Sshin } 192455505Sshin 192562583Sitojun __ipsec_errcode = EIPSEC_NO_ERROR; 192655505Sshin return 0; 192755505Sshin} 192855505Sshin 192955505Sshin/* 193055505Sshin * set data into sadb_msg. 193155505Sshin * `buf' must has been allocated sufficiently. 193255505Sshin */ 193355505Sshinstatic caddr_t 193478064Sumepfkey_setsadbmsg(buf, lim, type, tlen, satype, seq, pid) 193555505Sshin caddr_t buf; 193678064Sume caddr_t lim; 193762583Sitojun u_int type, satype; 193855505Sshin u_int tlen; 193955505Sshin u_int32_t seq; 194055505Sshin pid_t pid; 194155505Sshin{ 194255505Sshin struct sadb_msg *p; 194355505Sshin u_int len; 194455505Sshin 194555505Sshin p = (struct sadb_msg *)buf; 194662583Sitojun len = sizeof(struct sadb_msg); 194755505Sshin 194878064Sume if (buf + len > lim) 194978064Sume return NULL; 195078064Sume 195155505Sshin memset(p, 0, len); 195255505Sshin p->sadb_msg_version = PF_KEY_V2; 195355505Sshin p->sadb_msg_type = type; 195455505Sshin p->sadb_msg_errno = 0; 195555505Sshin p->sadb_msg_satype = satype; 195655505Sshin p->sadb_msg_len = PFKEY_UNIT64(tlen); 195755505Sshin p->sadb_msg_reserved = 0; 195855505Sshin p->sadb_msg_seq = seq; 195955505Sshin p->sadb_msg_pid = (u_int32_t)pid; 196055505Sshin 196155505Sshin return(buf + len); 196255505Sshin} 196355505Sshin 196455505Sshin/* 196555505Sshin * copy secasvar data into sadb_address. 196655505Sshin * `buf' must has been allocated sufficiently. 196755505Sshin */ 196855505Sshinstatic caddr_t 196978064Sumepfkey_setsadbsa(buf, lim, spi, wsize, auth, enc, flags) 197055505Sshin caddr_t buf; 197178064Sume caddr_t lim; 197255505Sshin u_int32_t spi, flags; 197355505Sshin u_int wsize, auth, enc; 197455505Sshin{ 197555505Sshin struct sadb_sa *p; 197655505Sshin u_int len; 197755505Sshin 197855505Sshin p = (struct sadb_sa *)buf; 197955505Sshin len = sizeof(struct sadb_sa); 198055505Sshin 198178064Sume if (buf + len > lim) 198278064Sume return NULL; 198378064Sume 198455505Sshin memset(p, 0, len); 198555505Sshin p->sadb_sa_len = PFKEY_UNIT64(len); 198655505Sshin p->sadb_sa_exttype = SADB_EXT_SA; 198755505Sshin p->sadb_sa_spi = spi; 198855505Sshin p->sadb_sa_replay = wsize; 198955505Sshin p->sadb_sa_state = SADB_SASTATE_LARVAL; 199055505Sshin p->sadb_sa_auth = auth; 199155505Sshin p->sadb_sa_encrypt = enc; 199255505Sshin p->sadb_sa_flags = flags; 199355505Sshin 199455505Sshin return(buf + len); 199555505Sshin} 199655505Sshin 199755505Sshin/* 199855505Sshin * set data into sadb_address. 199955505Sshin * `buf' must has been allocated sufficiently. 200055505Sshin * prefixlen is in bits. 200155505Sshin */ 200255505Sshinstatic caddr_t 200378064Sumepfkey_setsadbaddr(buf, lim, exttype, saddr, prefixlen, ul_proto) 200455505Sshin caddr_t buf; 200578064Sume caddr_t lim; 200655505Sshin u_int exttype; 200755505Sshin struct sockaddr *saddr; 200855505Sshin u_int prefixlen; 200955505Sshin u_int ul_proto; 201055505Sshin{ 201155505Sshin struct sadb_address *p; 201255505Sshin u_int len; 201355505Sshin 201455505Sshin p = (struct sadb_address *)buf; 201555505Sshin len = sizeof(struct sadb_address) + PFKEY_ALIGN8(saddr->sa_len); 201655505Sshin 201778064Sume if (buf + len > lim) 201878064Sume return NULL; 201978064Sume 202055505Sshin memset(p, 0, len); 202155505Sshin p->sadb_address_len = PFKEY_UNIT64(len); 202255505Sshin p->sadb_address_exttype = exttype & 0xffff; 202355505Sshin p->sadb_address_proto = ul_proto & 0xff; 202455505Sshin p->sadb_address_prefixlen = prefixlen; 202555505Sshin p->sadb_address_reserved = 0; 202655505Sshin 202755505Sshin memcpy(p + 1, saddr, saddr->sa_len); 202855505Sshin 202955505Sshin return(buf + len); 203055505Sshin} 203155505Sshin 203255505Sshin/* 203355505Sshin * set sadb_key structure after clearing buffer with zero. 203455505Sshin * OUT: the pointer of buf + len. 203555505Sshin */ 203655505Sshinstatic caddr_t 203778064Sumepfkey_setsadbkey(buf, lim, type, key, keylen) 203878064Sume caddr_t buf; 203978064Sume caddr_t lim; 204078064Sume caddr_t key; 204155505Sshin u_int type, keylen; 204255505Sshin{ 204355505Sshin struct sadb_key *p; 204455505Sshin u_int len; 204555505Sshin 204655505Sshin p = (struct sadb_key *)buf; 204755505Sshin len = sizeof(struct sadb_key) + PFKEY_ALIGN8(keylen); 204855505Sshin 204978064Sume if (buf + len > lim) 205078064Sume return NULL; 205178064Sume 205255505Sshin memset(p, 0, len); 205355505Sshin p->sadb_key_len = PFKEY_UNIT64(len); 205455505Sshin p->sadb_key_exttype = type; 205555505Sshin p->sadb_key_bits = keylen << 3; 205655505Sshin p->sadb_key_reserved = 0; 205755505Sshin 205855505Sshin memcpy(p + 1, key, keylen); 205955505Sshin 206055505Sshin return buf + len; 206155505Sshin} 206255505Sshin 206355505Sshin/* 206455505Sshin * set sadb_lifetime structure after clearing buffer with zero. 206555505Sshin * OUT: the pointer of buf + len. 206655505Sshin */ 206755505Sshinstatic caddr_t 206878064Sumepfkey_setsadblifetime(buf, lim, type, l_alloc, l_bytes, l_addtime, l_usetime) 206955505Sshin caddr_t buf; 207078064Sume caddr_t lim; 207155505Sshin u_int type; 207255505Sshin u_int32_t l_alloc, l_bytes, l_addtime, l_usetime; 207355505Sshin{ 207455505Sshin struct sadb_lifetime *p; 207555505Sshin u_int len; 207655505Sshin 207755505Sshin p = (struct sadb_lifetime *)buf; 207855505Sshin len = sizeof(struct sadb_lifetime); 207955505Sshin 208078064Sume if (buf + len > lim) 208178064Sume return NULL; 208278064Sume 208355505Sshin memset(p, 0, len); 208455505Sshin p->sadb_lifetime_len = PFKEY_UNIT64(len); 208555505Sshin p->sadb_lifetime_exttype = type; 208655505Sshin 208755505Sshin switch (type) { 208855505Sshin case SADB_EXT_LIFETIME_SOFT: 208955505Sshin p->sadb_lifetime_allocations 209055505Sshin = (l_alloc * soft_lifetime_allocations_rate) /100; 209155505Sshin p->sadb_lifetime_bytes 209262583Sitojun = (l_bytes * soft_lifetime_bytes_rate) /100; 209355505Sshin p->sadb_lifetime_addtime 209455505Sshin = (l_addtime * soft_lifetime_addtime_rate) /100; 209555505Sshin p->sadb_lifetime_usetime 209655505Sshin = (l_usetime * soft_lifetime_usetime_rate) /100; 209755505Sshin break; 209855505Sshin case SADB_EXT_LIFETIME_HARD: 209955505Sshin p->sadb_lifetime_allocations = l_alloc; 210062583Sitojun p->sadb_lifetime_bytes = l_bytes; 210155505Sshin p->sadb_lifetime_addtime = l_addtime; 210255505Sshin p->sadb_lifetime_usetime = l_usetime; 210355505Sshin break; 210455505Sshin } 210555505Sshin 210655505Sshin return buf + len; 210755505Sshin} 210855505Sshin 210962583Sitojun/* 211062583Sitojun * copy secasvar data into sadb_address. 211162583Sitojun * `buf' must has been allocated sufficiently. 211262583Sitojun */ 211362583Sitojunstatic caddr_t 211478064Sumepfkey_setsadbxsa2(buf, lim, mode0, reqid) 211562583Sitojun caddr_t buf; 211678064Sume caddr_t lim; 211762583Sitojun u_int32_t mode0; 211862583Sitojun u_int32_t reqid; 211962583Sitojun{ 212062583Sitojun struct sadb_x_sa2 *p; 212162583Sitojun u_int8_t mode = mode0 & 0xff; 212262583Sitojun u_int len; 212362583Sitojun 212462583Sitojun p = (struct sadb_x_sa2 *)buf; 212562583Sitojun len = sizeof(struct sadb_x_sa2); 212662583Sitojun 212778064Sume if (buf + len > lim) 212878064Sume return NULL; 212978064Sume 213062583Sitojun memset(p, 0, len); 213162583Sitojun p->sadb_x_sa2_len = PFKEY_UNIT64(len); 213262583Sitojun p->sadb_x_sa2_exttype = SADB_X_EXT_SA2; 213362583Sitojun p->sadb_x_sa2_mode = mode; 213462583Sitojun p->sadb_x_sa2_reqid = reqid; 213562583Sitojun 213662583Sitojun return(buf + len); 213762583Sitojun} 2138