1121572Sume/* $KAME: ipsec_dump_policy.c,v 1.13 2002/06/27 14:35:11 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: releng/11.0/lib/libipsec/ipsec_dump_policy.c 264585 2014-04-17 10:27:18Z brueffer $"); 3484208Sdillon 3555505Sshin#include <sys/types.h> 3655505Sshin#include <sys/param.h> 3755505Sshin#include <sys/socket.h> 3855505Sshin 39171135Sgnn#include <netipsec/key_var.h> 4055505Sshin#include <netinet/in.h> 41171135Sgnn#include <netipsec/ipsec.h> 4255505Sshin 4355505Sshin#include <arpa/inet.h> 4455505Sshin 4562583Sitojun#include <stdio.h> 4655505Sshin#include <stdlib.h> 4755505Sshin#include <string.h> 4855505Sshin#include <netdb.h> 4955505Sshin 5055505Sshin#include "ipsec_strerror.h" 5155505Sshin 5255505Sshinstatic const char *ipsp_dir_strs[] = { 5355505Sshin "any", "in", "out", 5455505Sshin}; 5555505Sshin 5655505Sshinstatic const char *ipsp_policy_strs[] = { 5755505Sshin "discard", "none", "ipsec", "entrust", "bypass", 5855505Sshin}; 5955505Sshin 6092941Sobrienstatic char *ipsec_dump_ipsecrequest(char *, size_t, 6192941Sobrien struct sadb_x_ipsecrequest *, size_t); 6292941Sobrienstatic int set_addresses(char *, size_t, struct sockaddr *, struct sockaddr *); 6392917Sobrienstatic char *set_address(char *, size_t, struct sockaddr *); 6455505Sshin 6555505Sshin/* 6655505Sshin * policy is sadb_x_policy buffer. 6755505Sshin * Must call free() later. 6855505Sshin * When delimiter == NULL, alternatively ' '(space) is applied. 6955505Sshin */ 7055505Sshinchar * 7155505Sshinipsec_dump_policy(policy, delimiter) 7255505Sshin caddr_t policy; 7355505Sshin char *delimiter; 7455505Sshin{ 7555505Sshin struct sadb_x_policy *xpl = (struct sadb_x_policy *)policy; 7655505Sshin struct sadb_x_ipsecrequest *xisr; 7762583Sitojun size_t off, buflen; 7855505Sshin char *buf; 7962583Sitojun char isrbuf[1024]; 8062583Sitojun char *newbuf; 8155505Sshin 8255505Sshin /* sanity check */ 8355505Sshin if (policy == NULL) 8455505Sshin return NULL; 8555505Sshin if (xpl->sadb_x_policy_exttype != SADB_X_EXT_POLICY) { 8662583Sitojun __ipsec_errcode = EIPSEC_INVAL_EXTTYPE; 8755505Sshin return NULL; 8855505Sshin } 8955505Sshin 9055505Sshin /* set delimiter */ 9155505Sshin if (delimiter == NULL) 9255505Sshin delimiter = " "; 9355505Sshin 9455505Sshin switch (xpl->sadb_x_policy_dir) { 9555505Sshin case IPSEC_DIR_ANY: 9655505Sshin case IPSEC_DIR_INBOUND: 9755505Sshin case IPSEC_DIR_OUTBOUND: 9855505Sshin break; 9955505Sshin default: 10062583Sitojun __ipsec_errcode = EIPSEC_INVAL_DIR; 10155505Sshin return NULL; 10255505Sshin } 10355505Sshin 10455505Sshin switch (xpl->sadb_x_policy_type) { 10555505Sshin case IPSEC_POLICY_DISCARD: 10655505Sshin case IPSEC_POLICY_NONE: 10755505Sshin case IPSEC_POLICY_IPSEC: 10855505Sshin case IPSEC_POLICY_BYPASS: 10955505Sshin case IPSEC_POLICY_ENTRUST: 11055505Sshin break; 11155505Sshin default: 11262583Sitojun __ipsec_errcode = EIPSEC_INVAL_POLICY; 11355505Sshin return NULL; 11455505Sshin } 11555505Sshin 11655505Sshin buflen = strlen(ipsp_dir_strs[xpl->sadb_x_policy_dir]) 11755505Sshin + 1 /* space */ 11855505Sshin + strlen(ipsp_policy_strs[xpl->sadb_x_policy_type]) 11955505Sshin + 1; /* NUL */ 12055505Sshin 12155505Sshin if ((buf = malloc(buflen)) == NULL) { 12262583Sitojun __ipsec_errcode = EIPSEC_NO_BUFS; 12355505Sshin return NULL; 12455505Sshin } 12562583Sitojun snprintf(buf, buflen, "%s %s", ipsp_dir_strs[xpl->sadb_x_policy_dir], 12662583Sitojun ipsp_policy_strs[xpl->sadb_x_policy_type]); 12755505Sshin 12855505Sshin if (xpl->sadb_x_policy_type != IPSEC_POLICY_IPSEC) { 12962583Sitojun __ipsec_errcode = EIPSEC_NO_ERROR; 13055505Sshin return buf; 13155505Sshin } 13255505Sshin 13355505Sshin /* count length of buffer for use */ 13462583Sitojun off = sizeof(*xpl); 13562583Sitojun while (off < PFKEY_EXTLEN(xpl)) { 13662583Sitojun xisr = (struct sadb_x_ipsecrequest *)((caddr_t)xpl + off); 13762583Sitojun off += xisr->sadb_x_ipsecrequest_len; 13855505Sshin } 13955505Sshin 14055505Sshin /* validity check */ 14162583Sitojun if (off != PFKEY_EXTLEN(xpl)) { 14262583Sitojun __ipsec_errcode = EIPSEC_INVAL_SADBMSG; 14355505Sshin free(buf); 14455505Sshin return NULL; 14555505Sshin } 14655505Sshin 14762583Sitojun off = sizeof(*xpl); 14862583Sitojun while (off < PFKEY_EXTLEN(xpl)) { 14962583Sitojun xisr = (struct sadb_x_ipsecrequest *)((caddr_t)xpl + off); 15055505Sshin 15162583Sitojun if (ipsec_dump_ipsecrequest(isrbuf, sizeof(isrbuf), xisr, 15262583Sitojun PFKEY_EXTLEN(xpl) - off) == NULL) { 15355505Sshin free(buf); 15455505Sshin return NULL; 15555505Sshin } 15655505Sshin 15762583Sitojun buflen = strlen(buf) + strlen(delimiter) + strlen(isrbuf) + 1; 15862583Sitojun newbuf = (char *)realloc(buf, buflen); 15962583Sitojun if (newbuf == NULL) { 16062583Sitojun __ipsec_errcode = EIPSEC_NO_BUFS; 16155505Sshin free(buf); 16255505Sshin return NULL; 16355505Sshin } 16462583Sitojun buf = newbuf; 165216369Skevlo snprintf(buf + strlen(buf), buflen - strlen(buf), 166216369Skevlo "%s%s", delimiter, isrbuf); 16755505Sshin 16862583Sitojun off += xisr->sadb_x_ipsecrequest_len; 16962583Sitojun } 17055505Sshin 17162583Sitojun __ipsec_errcode = EIPSEC_NO_ERROR; 17262583Sitojun return buf; 17362583Sitojun} 17455505Sshin 17562583Sitojunstatic char * 17662583Sitojunipsec_dump_ipsecrequest(buf, len, xisr, bound) 17762583Sitojun char *buf; 17862583Sitojun size_t len; 17962583Sitojun struct sadb_x_ipsecrequest *xisr; 18062583Sitojun size_t bound; /* boundary */ 18162583Sitojun{ 18262583Sitojun const char *proto, *mode, *level; 18362583Sitojun char abuf[NI_MAXHOST * 2 + 2]; 18462583Sitojun 18562583Sitojun if (xisr->sadb_x_ipsecrequest_len > bound) { 18662583Sitojun __ipsec_errcode = EIPSEC_INVAL_PROTO; 18762583Sitojun return NULL; 18862583Sitojun } 18962583Sitojun 19062583Sitojun switch (xisr->sadb_x_ipsecrequest_proto) { 19162583Sitojun case IPPROTO_ESP: 19262583Sitojun proto = "esp"; 19362583Sitojun break; 19462583Sitojun case IPPROTO_AH: 19562583Sitojun proto = "ah"; 19662583Sitojun break; 19762583Sitojun case IPPROTO_IPCOMP: 19862583Sitojun proto = "ipcomp"; 19962583Sitojun break; 200125681Sbms case IPPROTO_TCP: 201125681Sbms proto = "tcp"; 202264585Sbrueffer break; 20362583Sitojun default: 20462583Sitojun __ipsec_errcode = EIPSEC_INVAL_PROTO; 20562583Sitojun return NULL; 20662583Sitojun } 20762583Sitojun 20862583Sitojun switch (xisr->sadb_x_ipsecrequest_mode) { 20962583Sitojun case IPSEC_MODE_ANY: 21062583Sitojun mode = "any"; 21162583Sitojun break; 21262583Sitojun case IPSEC_MODE_TRANSPORT: 21362583Sitojun mode = "transport"; 21462583Sitojun break; 21562583Sitojun case IPSEC_MODE_TUNNEL: 21662583Sitojun mode = "tunnel"; 21762583Sitojun break; 21862583Sitojun default: 21962583Sitojun __ipsec_errcode = EIPSEC_INVAL_MODE; 22062583Sitojun return NULL; 22162583Sitojun } 22262583Sitojun 22362583Sitojun abuf[0] = '\0'; 22462583Sitojun if (xisr->sadb_x_ipsecrequest_len > sizeof(*xisr)) { 22562583Sitojun struct sockaddr *sa1, *sa2; 22662583Sitojun caddr_t p; 22762583Sitojun 22862583Sitojun p = (caddr_t)(xisr + 1); 22962583Sitojun sa1 = (struct sockaddr *)p; 23062583Sitojun sa2 = (struct sockaddr *)(p + sa1->sa_len); 23162583Sitojun if (sizeof(*xisr) + sa1->sa_len + sa2->sa_len != 23262583Sitojun xisr->sadb_x_ipsecrequest_len) { 23362583Sitojun __ipsec_errcode = EIPSEC_INVAL_ADDRESS; 23455505Sshin return NULL; 23555505Sshin } 23662583Sitojun if (set_addresses(abuf, sizeof(abuf), sa1, sa2) != 0) { 23762583Sitojun __ipsec_errcode = EIPSEC_INVAL_ADDRESS; 23862583Sitojun return NULL; 23962583Sitojun } 24062583Sitojun } 24155505Sshin 24262583Sitojun switch (xisr->sadb_x_ipsecrequest_level) { 24362583Sitojun case IPSEC_LEVEL_DEFAULT: 24462583Sitojun level = "default"; 24562583Sitojun break; 24662583Sitojun case IPSEC_LEVEL_USE: 24762583Sitojun level = "use"; 24862583Sitojun break; 24962583Sitojun case IPSEC_LEVEL_REQUIRE: 25062583Sitojun level = "require"; 25162583Sitojun break; 25262583Sitojun case IPSEC_LEVEL_UNIQUE: 25362583Sitojun level = "unique"; 25462583Sitojun break; 25562583Sitojun default: 25662583Sitojun __ipsec_errcode = EIPSEC_INVAL_LEVEL; 25762583Sitojun return NULL; 25855505Sshin } 25955505Sshin 26062583Sitojun if (xisr->sadb_x_ipsecrequest_reqid == 0) 26162583Sitojun snprintf(buf, len, "%s/%s/%s/%s", proto, mode, abuf, level); 26262583Sitojun else { 26362583Sitojun int ch; 26462583Sitojun 26562583Sitojun if (xisr->sadb_x_ipsecrequest_reqid > IPSEC_MANUAL_REQID_MAX) 26662583Sitojun ch = '#'; 26762583Sitojun else 26862583Sitojun ch = ':'; 269121572Sume snprintf(buf, len, "%s/%s/%s/%s%c%u", proto, mode, abuf, level, 27062583Sitojun ch, xisr->sadb_x_ipsecrequest_reqid); 27162583Sitojun } 27262583Sitojun 27355505Sshin return buf; 27455505Sshin} 27555505Sshin 27655505Sshinstatic int 27762583Sitojunset_addresses(buf, len, sa1, sa2) 27855505Sshin char *buf; 27962583Sitojun size_t len; 28062583Sitojun struct sockaddr *sa1; 28162583Sitojun struct sockaddr *sa2; 28255505Sshin{ 28362583Sitojun char tmp1[NI_MAXHOST], tmp2[NI_MAXHOST]; 28455505Sshin 28562583Sitojun if (set_address(tmp1, sizeof(tmp1), sa1) == NULL || 28662583Sitojun set_address(tmp2, sizeof(tmp2), sa2) == NULL) 28762583Sitojun return -1; 28862583Sitojun if (strlen(tmp1) + 1 + strlen(tmp2) + 1 > len) 28962583Sitojun return -1; 29062583Sitojun snprintf(buf, len, "%s-%s", tmp1, tmp2); 29162583Sitojun return 0; 29262583Sitojun} 29355505Sshin 29462583Sitojunstatic char * 29562583Sitojunset_address(buf, len, sa) 29662583Sitojun char *buf; 29762583Sitojun size_t len; 29862583Sitojun struct sockaddr *sa; 29962583Sitojun{ 30062583Sitojun const int niflags = NI_NUMERICHOST; 30155505Sshin 30262583Sitojun if (len < 1) 30362583Sitojun return NULL; 30462583Sitojun buf[0] = '\0'; 30562583Sitojun if (getnameinfo(sa, sa->sa_len, buf, len, NULL, 0, niflags) != 0) 30662583Sitojun return NULL; 30762583Sitojun return buf; 30855505Sshin} 309