1/* $KAME: ipsec_dump_policy.c,v 1.12 2001/11/13 12:38:47 jinmei Exp $ */ 2 3/* 4 * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. Neither the name of the project nor the names of its contributors 16 * may be used to endorse or promote products derived from this software 17 * without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 */ 31 32#include <sys/types.h> 33#include <sys/param.h> 34#include <sys/socket.h> 35 36#include <netinet/in.h> 37#include <netinet/ipsec.h> 38 39#include <arpa/inet.h> 40 41#include <stdio.h> 42#include <stdlib.h> 43#include <string.h> 44#include <netdb.h> 45 46#include "ipsec_strerror.h" 47#include "libpfkey.h" 48 49static const char *ipsp_dir_strs[] = { 50 "any", "in", "out", "fwd" 51}; 52 53static const char *ipsp_policy_strs[] = { 54 "discard", "none", "ipsec", "entrust", "bypass", 55}; 56 57static char *ipsec_dump_ipsecrequest __P((char *, size_t, 58 struct sadb_x_ipsecrequest *, size_t)); 59static int set_addresses __P((char *, size_t, struct sockaddr *, 60 struct sockaddr *)); 61static char *set_address __P((char *, size_t, struct sockaddr *)); 62 63/* 64 * policy is sadb_x_policy buffer. 65 * Must call free() later. 66 * When delimiter == NULL, alternatively ' '(space) is applied. 67 */ 68char * 69ipsec_dump_policy(policy, delimiter) 70 caddr_t policy; 71 char *delimiter; 72{ 73 struct sadb_x_policy *xpl = (struct sadb_x_policy *)policy; 74 struct sadb_x_ipsecrequest *xisr; 75 size_t off, buflen; 76 char *buf; 77 char isrbuf[1024]; 78 char *newbuf; 79 80 /* sanity check */ 81 if (policy == NULL) 82 return NULL; 83 if (xpl->sadb_x_policy_exttype != SADB_X_EXT_POLICY) { 84 __ipsec_errcode = EIPSEC_INVAL_EXTTYPE; 85 return NULL; 86 } 87 88 /* set delimiter */ 89 if (delimiter == NULL) 90 delimiter = " "; 91 92 switch (xpl->sadb_x_policy_dir) { 93 case IPSEC_DIR_ANY: 94 case IPSEC_DIR_INBOUND: 95 case IPSEC_DIR_OUTBOUND: 96 break; 97 default: 98 __ipsec_errcode = EIPSEC_INVAL_DIR; 99 return NULL; 100 } 101 102 switch (xpl->sadb_x_policy_type) { 103 case IPSEC_POLICY_DISCARD: 104 case IPSEC_POLICY_NONE: 105 case IPSEC_POLICY_IPSEC: 106 case IPSEC_POLICY_BYPASS: 107 case IPSEC_POLICY_ENTRUST: 108 break; 109 default: 110 __ipsec_errcode = EIPSEC_INVAL_POLICY; 111 return NULL; 112 } 113 114 buflen = strlen(ipsp_dir_strs[xpl->sadb_x_policy_dir]) 115 + 1 /* space */ 116 + strlen(ipsp_policy_strs[xpl->sadb_x_policy_type]) 117 + 1; /* NUL */ 118 119 if ((buf = malloc(buflen)) == NULL) { 120 __ipsec_errcode = EIPSEC_NO_BUFS; 121 return NULL; 122 } 123 snprintf(buf, buflen, "%s %s", ipsp_dir_strs[xpl->sadb_x_policy_dir], 124 ipsp_policy_strs[xpl->sadb_x_policy_type]); 125 126 if (xpl->sadb_x_policy_type != IPSEC_POLICY_IPSEC) { 127 __ipsec_errcode = EIPSEC_NO_ERROR; 128 return buf; 129 } 130 131 /* count length of buffer for use */ 132 off = sizeof(*xpl); 133 while (off < PFKEY_EXTLEN(xpl)) { 134 xisr = (struct sadb_x_ipsecrequest *)((caddr_t)xpl + off); 135 off += xisr->sadb_x_ipsecrequest_len; 136 } 137 138 /* validity check */ 139 if (off != PFKEY_EXTLEN(xpl)) { 140 __ipsec_errcode = EIPSEC_INVAL_SADBMSG; 141 free(buf); 142 return NULL; 143 } 144 145 off = sizeof(*xpl); 146 while (off < PFKEY_EXTLEN(xpl)) { 147 int offset; 148 xisr = (struct sadb_x_ipsecrequest *)((caddr_t)xpl + off); 149 150 if (ipsec_dump_ipsecrequest(isrbuf, sizeof(isrbuf), xisr, 151 PFKEY_EXTLEN(xpl) - off) == NULL) { 152 free(buf); 153 return NULL; 154 } 155 156 offset = strlen(buf); 157 buflen = offset + strlen(delimiter) + strlen(isrbuf) + 1; 158 newbuf = (char *)realloc(buf, buflen); 159 if (newbuf == NULL) { 160 __ipsec_errcode = EIPSEC_NO_BUFS; 161 free(buf); 162 return NULL; 163 } 164 buf = newbuf; 165 snprintf(buf+offset, buflen-offset, "%s%s", delimiter, isrbuf); 166 167 off += xisr->sadb_x_ipsecrequest_len; 168 } 169 170 __ipsec_errcode = EIPSEC_NO_ERROR; 171 return buf; 172} 173 174static char * 175ipsec_dump_ipsecrequest(buf, len, xisr, bound) 176 char *buf; 177 size_t len; 178 struct sadb_x_ipsecrequest *xisr; 179 size_t bound; /* boundary */ 180{ 181 const char *proto, *mode, *level; 182 char abuf[NI_MAXHOST * 2 + 2]; 183 184 if (xisr->sadb_x_ipsecrequest_len > bound) { 185 __ipsec_errcode = EIPSEC_INVAL_PROTO; 186 return NULL; 187 } 188 189 switch (xisr->sadb_x_ipsecrequest_proto) { 190 case IPPROTO_ESP: 191 proto = "esp"; 192 break; 193 case IPPROTO_AH: 194 proto = "ah"; 195 break; 196 case IPPROTO_COMP: 197 proto = "ipcomp"; 198 break; 199 default: 200 __ipsec_errcode = EIPSEC_INVAL_PROTO; 201 return NULL; 202 } 203 204 switch (xisr->sadb_x_ipsecrequest_mode) { 205 case IPSEC_MODE_ANY: 206 mode = "any"; 207 break; 208 case IPSEC_MODE_TRANSPORT: 209 mode = "transport"; 210 break; 211 case IPSEC_MODE_TUNNEL: 212 mode = "tunnel"; 213 break; 214 default: 215 __ipsec_errcode = EIPSEC_INVAL_MODE; 216 return NULL; 217 } 218 219 abuf[0] = '\0'; 220 if (xisr->sadb_x_ipsecrequest_len > sizeof(*xisr)) { 221 struct sockaddr *sa1, *sa2; 222 caddr_t p; 223 224 p = (caddr_t)(xisr + 1); 225 sa1 = (struct sockaddr *)p; 226 sa2 = (struct sockaddr *)(p + sysdep_sa_len(sa1)); 227 if (sizeof(*xisr) + sysdep_sa_len(sa1) + sysdep_sa_len(sa2) != 228 xisr->sadb_x_ipsecrequest_len) { 229 __ipsec_errcode = EIPSEC_INVAL_ADDRESS; 230 return NULL; 231 } 232 if (set_addresses(abuf, sizeof(abuf), sa1, sa2) != 0) { 233 __ipsec_errcode = EIPSEC_INVAL_ADDRESS; 234 return NULL; 235 } 236 } 237 238 switch (xisr->sadb_x_ipsecrequest_level) { 239 case IPSEC_LEVEL_DEFAULT: 240 level = "default"; 241 break; 242 case IPSEC_LEVEL_USE: 243 level = "use"; 244 break; 245 case IPSEC_LEVEL_REQUIRE: 246 level = "require"; 247 break; 248 case IPSEC_LEVEL_UNIQUE: 249 level = "unique"; 250 break; 251 default: 252 __ipsec_errcode = EIPSEC_INVAL_LEVEL; 253 return NULL; 254 } 255 256 if (xisr->sadb_x_ipsecrequest_reqid == 0) 257 snprintf(buf, len, "%s/%s/%s/%s", proto, mode, abuf, level); 258 else { 259 int ch; 260 261 if (xisr->sadb_x_ipsecrequest_reqid > IPSEC_MANUAL_REQID_MAX) 262 ch = '#'; 263 else 264 ch = ':'; 265 snprintf(buf, len, "%s/%s/%s/%s%c%d", proto, mode, abuf, level, 266 ch, xisr->sadb_x_ipsecrequest_reqid); 267 } 268 269 return buf; 270} 271 272static int 273set_addresses(buf, len, sa1, sa2) 274 char *buf; 275 size_t len; 276 struct sockaddr *sa1; 277 struct sockaddr *sa2; 278{ 279 char tmp1[NI_MAXHOST], tmp2[NI_MAXHOST]; 280 281 if (set_address(tmp1, sizeof(tmp1), sa1) == NULL || 282 set_address(tmp2, sizeof(tmp2), sa2) == NULL) 283 return -1; 284 if (strlen(tmp1) + 1 + strlen(tmp2) + 1 > len) 285 return -1; 286 snprintf(buf, len, "%s-%s", tmp1, tmp2); 287 return 0; 288} 289 290static char * 291set_address(buf, len, sa) 292 char *buf; 293 size_t len; 294 struct sockaddr *sa; 295{ 296 const int niflags = NI_NUMERICHOST; 297 298 if (len < 1) 299 return NULL; 300 buf[0] = '\0'; 301 if (getnameinfo(sa, sysdep_sa_len(sa), buf, len, NULL, 0, niflags) != 0) 302 return NULL; 303 return buf; 304} 305