1 /* $NetBSD: ipsec_dump_policy.c,v 1.6 2005/11/21 14:20:28 manu Exp $ */ 2 3 /* Id: ipsec_dump_policy.c,v 1.7.4.2 2005/06/29 13:01:27 manubsd Exp */ 4 5 /* 6 * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project. 7 * All rights reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. Neither the name of the project nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 */ 33 34 #ifdef HAVE_CONFIG_H 35 #include "config.h" 36 #endif 37 38 #include <sys/types.h> 39 #include <sys/param.h> 40 #include <sys/socket.h> 41 42 #include <netinet/in.h> 43 #ifdef HAVE_NETINET6_IPSEC 44 # include <netinet6/ipsec.h> 45 #else 46 # include <netinet/ipsec.h> 47 #endif 48 49 #include <arpa/inet.h> 50 51 #include <stdio.h> 52 #include <stdlib.h> 53 #include <string.h> 54 #include <netdb.h> 55 56 #include "ipsec_strerror.h" 57 #include "libpfkey.h" 58 59 static const char *ipsp_dir_strs[] = { 60 "any", "in", "out", "fwd" 61 }; 62 63 static const char *ipsp_policy_strs[] = { 64 "discard", "none", "ipsec", "entrust", "bypass", 65 }; 66 67 static char *ipsec_dump_ipsecrequest __P((char *, size_t, 68 struct sadb_x_ipsecrequest *, size_t, int)); 69 static char *ipsec_dump_policy1 __P((void *, const char *, int)); 70 static int set_addresses __P((char *, size_t, struct sockaddr *, 71 struct sockaddr *, int)); 72 static char *set_address __P((char *, size_t, struct sockaddr *, int)); 73 74 /* 75 * policy is sadb_x_policy buffer. 76 * Must call free() later. 77 * When delimiter == NULL, alternatively ' '(space) is applied. 78 */ 79 char * 80 ipsec_dump_policy(policy, delimiter) 81 ipsec_policy_t policy; 82 __ipsec_const char *delimiter; 83 { 84 return ipsec_dump_policy1(policy, delimiter, 0); 85 } 86 87 char * 88 ipsec_dump_policy_withports(policy, delimiter) 89 void *policy; 90 const char *delimiter; 91 { 92 return ipsec_dump_policy1(policy, delimiter, 1); 93 } 94 95 static char * 96 ipsec_dump_policy1(policy, delimiter, withports) 97 void *policy; 98 const char *delimiter; 99 int withports; 100 { 101 struct sadb_x_policy *xpl = policy; 102 struct sadb_x_ipsecrequest *xisr; 103 size_t off, buflen; 104 char *buf; 105 char isrbuf[1024]; 106 char *newbuf; 107 108 #ifdef HAVE_PFKEY_POLICY_PRIORITY 109 int32_t priority_offset; 110 char *priority_str; 111 char operator; 112 #endif 113 114 /* sanity check */ 115 if (policy == NULL) 116 return NULL; 117 if (xpl->sadb_x_policy_exttype != SADB_X_EXT_POLICY) { 118 __ipsec_errcode = EIPSEC_INVAL_EXTTYPE; 119 return NULL; 120 } 121 122 /* set delimiter */ 123 if (delimiter == NULL) 124 delimiter = " "; 125 126 #ifdef HAVE_PFKEY_POLICY_PRIORITY 127 if (xpl->sadb_x_policy_priority == 0) 128 { 129 priority_offset = 0; 130 priority_str = ""; 131 } 132 /* find which constant the priority is closest to */ 133 else if (xpl->sadb_x_policy_priority < 134 (u_int32_t) (PRIORITY_DEFAULT / 4) * 3) 135 { 136 priority_offset = xpl->sadb_x_policy_priority - PRIORITY_HIGH; 137 priority_str = "prio high"; 138 } 139 else if (xpl->sadb_x_policy_priority >= 140 (u_int32_t) (PRIORITY_DEFAULT / 4) * 3 && 141 xpl->sadb_x_policy_priority < 142 (u_int32_t) (PRIORITY_DEFAULT / 4) * 5) 143 { 144 priority_offset = xpl->sadb_x_policy_priority - PRIORITY_DEFAULT; 145 priority_str = "prio def"; 146 } 147 else 148 { 149 priority_offset = xpl->sadb_x_policy_priority - PRIORITY_LOW; 150 priority_str = "prio low"; 151 } 152 153 /* fix sign to match the way it is input */ 154 priority_offset *= -1; 155 if (priority_offset < 0) 156 { 157 operator = '-'; 158 priority_offset *= -1; 159 } 160 else 161 { 162 operator = '+'; 163 } 164 #endif 165 166 switch (xpl->sadb_x_policy_dir) { 167 case IPSEC_DIR_ANY: 168 case IPSEC_DIR_INBOUND: 169 case IPSEC_DIR_OUTBOUND: 170 #ifdef HAVE_POLICY_FWD 171 case IPSEC_DIR_FWD: 172 #endif 173 break; 174 default: 175 __ipsec_errcode = EIPSEC_INVAL_DIR; 176 return NULL; 177 } 178 179 switch (xpl->sadb_x_policy_type) { 180 case IPSEC_POLICY_DISCARD: 181 case IPSEC_POLICY_NONE: 182 case IPSEC_POLICY_IPSEC: 183 case IPSEC_POLICY_BYPASS: 184 case IPSEC_POLICY_ENTRUST: 185 break; 186 default: 187 __ipsec_errcode = EIPSEC_INVAL_POLICY; 188 return NULL; 189 } 190 191 buflen = strlen(ipsp_dir_strs[xpl->sadb_x_policy_dir]) 192 + 1 /* space */ 193 #ifdef HAVE_PFKEY_POLICY_PRIORITY 194 + strlen(priority_str) 195 + ((priority_offset != 0) ? 13 : 0) /* [space operator space int] */ 196 + ((strlen(priority_str) != 0) ? 1 : 0) /* space */ 197 #endif 198 + strlen(ipsp_policy_strs[xpl->sadb_x_policy_type]) 199 + 1; /* NUL */ 200 201 if ((buf = malloc(buflen)) == NULL) { 202 __ipsec_errcode = EIPSEC_NO_BUFS; 203 return NULL; 204 } 205 #ifdef HAVE_PFKEY_POLICY_PRIORITY 206 if (priority_offset != 0) 207 { 208 snprintf(buf, buflen, "%s %s %c %u %s", 209 ipsp_dir_strs[xpl->sadb_x_policy_dir], priority_str, operator, 210 priority_offset, ipsp_policy_strs[xpl->sadb_x_policy_type]); 211 } 212 else if (strlen (priority_str) != 0) 213 { 214 snprintf(buf, buflen, "%s %s %s", 215 ipsp_dir_strs[xpl->sadb_x_policy_dir], priority_str, 216 ipsp_policy_strs[xpl->sadb_x_policy_type]); 217 } 218 else 219 { 220 snprintf(buf, buflen, "%s %s", 221 ipsp_dir_strs[xpl->sadb_x_policy_dir], 222 ipsp_policy_strs[xpl->sadb_x_policy_type]); 223 } 224 #else 225 snprintf(buf, buflen, "%s %s", ipsp_dir_strs[xpl->sadb_x_policy_dir], 226 ipsp_policy_strs[xpl->sadb_x_policy_type]); 227 #endif 228 229 if (xpl->sadb_x_policy_type != IPSEC_POLICY_IPSEC) { 230 __ipsec_errcode = EIPSEC_NO_ERROR; 231 return buf; 232 } 233 234 /* count length of buffer for use */ 235 off = sizeof(*xpl); 236 while (off < PFKEY_EXTLEN(xpl)) { 237 xisr = (void *)((caddr_t)(void *)xpl + off); 238 off += xisr->sadb_x_ipsecrequest_len; 239 } 240 241 /* validity check */ 242 if (off != PFKEY_EXTLEN(xpl)) { 243 __ipsec_errcode = EIPSEC_INVAL_SADBMSG; 244 free(buf); 245 return NULL; 246 } 247 248 off = sizeof(*xpl); 249 while (off < PFKEY_EXTLEN(xpl)) { 250 int offset; 251 xisr = (void *)((caddr_t)(void *)xpl + off); 252 253 if (ipsec_dump_ipsecrequest(isrbuf, sizeof(isrbuf), xisr, 254 PFKEY_EXTLEN(xpl) - off, withports) == NULL) { 255 free(buf); 256 return NULL; 257 } 258 259 offset = strlen(buf); 260 buflen = offset + strlen(delimiter) + strlen(isrbuf) + 1; 261 newbuf = (char *)realloc(buf, buflen); 262 if (newbuf == NULL) { 263 __ipsec_errcode = EIPSEC_NO_BUFS; 264 free(buf); 265 return NULL; 266 } 267 buf = newbuf; 268 snprintf(buf+offset, buflen-offset, "%s%s", delimiter, isrbuf); 269 270 off += xisr->sadb_x_ipsecrequest_len; 271 } 272 273 __ipsec_errcode = EIPSEC_NO_ERROR; 274 return buf; 275 } 276 277 static char * 278 ipsec_dump_ipsecrequest(buf, len, xisr, bound, withports) 279 char *buf; 280 size_t len; 281 struct sadb_x_ipsecrequest *xisr; 282 size_t bound; /* boundary */ 283 int withports; 284 { 285 const char *proto, *mode, *level; 286 char abuf[NI_MAXHOST * 2 + 2]; 287 288 if (xisr->sadb_x_ipsecrequest_len > bound) { 289 __ipsec_errcode = EIPSEC_INVAL_PROTO; 290 return NULL; 291 } 292 293 switch (xisr->sadb_x_ipsecrequest_proto) { 294 case IPPROTO_ESP: 295 proto = "esp"; 296 break; 297 case IPPROTO_AH: 298 proto = "ah"; 299 break; 300 case IPPROTO_IPCOMP: 301 proto = "ipcomp"; 302 break; 303 default: 304 __ipsec_errcode = EIPSEC_INVAL_PROTO; 305 return NULL; 306 } 307 308 switch (xisr->sadb_x_ipsecrequest_mode) { 309 case IPSEC_MODE_ANY: 310 mode = "any"; 311 break; 312 case IPSEC_MODE_TRANSPORT: 313 mode = "transport"; 314 break; 315 case IPSEC_MODE_TUNNEL: 316 mode = "tunnel"; 317 break; 318 default: 319 __ipsec_errcode = EIPSEC_INVAL_MODE; 320 return NULL; 321 } 322 323 abuf[0] = '\0'; 324 if (xisr->sadb_x_ipsecrequest_len > sizeof(*xisr)) { 325 struct sockaddr *sa1, *sa2; 326 caddr_t p; 327 328 p = (void *)(xisr + 1); 329 sa1 = (void *)p; 330 sa2 = (void *)(p + sysdep_sa_len(sa1)); 331 if (sizeof(*xisr) + sysdep_sa_len(sa1) + sysdep_sa_len(sa2) != 332 xisr->sadb_x_ipsecrequest_len) { 333 __ipsec_errcode = EIPSEC_INVAL_ADDRESS; 334 return NULL; 335 } 336 if (set_addresses(abuf, sizeof(abuf), 337 sa1, sa2, withports) != 0) { 338 __ipsec_errcode = EIPSEC_INVAL_ADDRESS; 339 return NULL; 340 } 341 } 342 343 switch (xisr->sadb_x_ipsecrequest_level) { 344 case IPSEC_LEVEL_DEFAULT: 345 level = "default"; 346 break; 347 case IPSEC_LEVEL_USE: 348 level = "use"; 349 break; 350 case IPSEC_LEVEL_REQUIRE: 351 level = "require"; 352 break; 353 case IPSEC_LEVEL_UNIQUE: 354 level = "unique"; 355 break; 356 default: 357 __ipsec_errcode = EIPSEC_INVAL_LEVEL; 358 return NULL; 359 } 360 361 if (xisr->sadb_x_ipsecrequest_reqid == 0) 362 snprintf(buf, len, "%s/%s/%s/%s", proto, mode, abuf, level); 363 else { 364 int ch; 365 366 if (xisr->sadb_x_ipsecrequest_reqid > IPSEC_MANUAL_REQID_MAX) 367 ch = '#'; 368 else 369 ch = ':'; 370 snprintf(buf, len, "%s/%s/%s/%s%c%u", proto, mode, abuf, level, 371 ch, xisr->sadb_x_ipsecrequest_reqid); 372 } 373 374 return buf; 375 } 376 377 static int 378 set_addresses(buf, len, sa1, sa2, withports) 379 char *buf; 380 size_t len; 381 struct sockaddr *sa1; 382 struct sockaddr *sa2; 383 int withports; 384 { 385 char tmp1[NI_MAXHOST], tmp2[NI_MAXHOST]; 386 387 if (set_address(tmp1, sizeof(tmp1), sa1, withports) == NULL || 388 set_address(tmp2, sizeof(tmp2), sa2, withports) == NULL) 389 return -1; 390 if (strlen(tmp1) + 1 + strlen(tmp2) + 1 > len) 391 return -1; 392 snprintf(buf, len, "%s-%s", tmp1, tmp2); 393 return 0; 394 } 395 396 static char * 397 set_address(buf, len, sa, withports) 398 char *buf; 399 size_t len; 400 struct sockaddr *sa; 401 int withports; 402 { 403 const int niflags = NI_NUMERICHOST | NI_NUMERICSERV; 404 char host[NI_MAXHOST]; 405 char serv[NI_MAXSERV]; 406 407 if (len < 1) 408 return NULL; 409 buf[0] = '\0'; 410 if (getnameinfo(sa, (socklen_t)sysdep_sa_len(sa), host, sizeof(host), 411 serv, sizeof(serv), niflags) != 0) 412 return NULL; 413 414 if (withports) 415 snprintf(buf, len, "%s[%s]", host, serv); 416 else 417 snprintf(buf, len, "%s", host); 418 419 return buf; 420 } 421