1 /* $NetBSD: ipsec_dump_policy.c,v 1.9 2010/12/03 15:01:11 tteras Exp $ */ 2 3 /* Id: ipsec_dump_policy.c,v 1.10 2005/06/29 09:12:37 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 #include PATH_IPSEC_H 44 45 #include <arpa/inet.h> 46 47 #include <stdio.h> 48 #include <stdlib.h> 49 #include <string.h> 50 #include <netdb.h> 51 52 #include "ipsec_strerror.h" 53 #include "libpfkey.h" 54 55 static const char *ipsp_dir_strs[] = { 56 "any", "in", "out", "fwd", 57 #ifdef __linux__ 58 "in(socket)", "out(socket)" 59 #endif 60 }; 61 62 static const char *ipsp_policy_strs[] = { 63 "discard", "none", "ipsec", "entrust", "bypass", 64 }; 65 66 static char *ipsec_dump_ipsecrequest __P((char *, size_t, 67 struct sadb_x_ipsecrequest *, size_t, int)); 68 static char *ipsec_dump_policy1 __P((void *, const char *, int)); 69 static int set_addresses __P((char *, size_t, struct sockaddr *, 70 struct sockaddr *, int)); 71 static char *set_address __P((char *, size_t, struct sockaddr *, int)); 72 73 /* 74 * policy is sadb_x_policy buffer. 75 * Must call free() later. 76 * When delimiter == NULL, alternatively ' '(space) is applied. 77 */ 78 char * 79 ipsec_dump_policy(policy, delimiter) 80 ipsec_policy_t policy; 81 __ipsec_const char *delimiter; 82 { 83 return ipsec_dump_policy1(policy, delimiter, 0); 84 } 85 86 char * 87 ipsec_dump_policy_withports(policy, delimiter) 88 void *policy; 89 const char *delimiter; 90 { 91 return ipsec_dump_policy1(policy, delimiter, 1); 92 } 93 94 static char * 95 ipsec_dump_policy1(policy, delimiter, withports) 96 void *policy; 97 const char *delimiter; 98 int withports; 99 { 100 struct sadb_x_policy *xpl = policy; 101 struct sadb_x_ipsecrequest *xisr; 102 size_t off, buflen; 103 char *buf; 104 char isrbuf[1024]; 105 char *newbuf; 106 107 #ifdef HAVE_PFKEY_POLICY_PRIORITY 108 int32_t priority_offset; 109 char *priority_str; 110 char operator; 111 #endif 112 113 /* sanity check */ 114 if (policy == NULL) 115 return NULL; 116 if (xpl->sadb_x_policy_exttype != SADB_X_EXT_POLICY) { 117 __ipsec_errcode = EIPSEC_INVAL_EXTTYPE; 118 return NULL; 119 } 120 121 /* set delimiter */ 122 if (delimiter == NULL) 123 delimiter = " "; 124 125 #ifdef HAVE_PFKEY_POLICY_PRIORITY 126 if (xpl->sadb_x_policy_priority == 0) 127 { 128 priority_offset = 0; 129 priority_str = ""; 130 } 131 /* find which constant the priority is closest to */ 132 else if (xpl->sadb_x_policy_priority < 133 (u_int32_t) (PRIORITY_DEFAULT / 4) * 3) 134 { 135 priority_offset = xpl->sadb_x_policy_priority - PRIORITY_HIGH; 136 priority_str = "prio high"; 137 } 138 else if (xpl->sadb_x_policy_priority >= 139 (u_int32_t) (PRIORITY_DEFAULT / 4) * 3 && 140 xpl->sadb_x_policy_priority < 141 (u_int32_t) (PRIORITY_DEFAULT / 4) * 5) 142 { 143 priority_offset = xpl->sadb_x_policy_priority - PRIORITY_DEFAULT; 144 priority_str = "prio def"; 145 } 146 else 147 { 148 priority_offset = xpl->sadb_x_policy_priority - PRIORITY_LOW; 149 priority_str = "prio low"; 150 } 151 152 /* fix sign to match the way it is input */ 153 priority_offset *= -1; 154 if (priority_offset < 0) 155 { 156 operator = '-'; 157 priority_offset *= -1; 158 } 159 else 160 { 161 operator = '+'; 162 } 163 #endif 164 165 switch (xpl->sadb_x_policy_dir) { 166 case IPSEC_DIR_ANY: 167 case IPSEC_DIR_INBOUND: 168 case IPSEC_DIR_OUTBOUND: 169 #ifdef HAVE_POLICY_FWD 170 case IPSEC_DIR_FWD: 171 case IPSEC_DIR_FWD + 1: 172 case IPSEC_DIR_FWD + 2: 173 #endif 174 break; 175 default: 176 __ipsec_errcode = EIPSEC_INVAL_DIR; 177 return NULL; 178 } 179 180 switch (xpl->sadb_x_policy_type) { 181 case IPSEC_POLICY_DISCARD: 182 case IPSEC_POLICY_NONE: 183 case IPSEC_POLICY_IPSEC: 184 case IPSEC_POLICY_BYPASS: 185 case IPSEC_POLICY_ENTRUST: 186 break; 187 default: 188 __ipsec_errcode = EIPSEC_INVAL_POLICY; 189 return NULL; 190 } 191 192 buflen = strlen(ipsp_dir_strs[xpl->sadb_x_policy_dir]) 193 + 1 /* space */ 194 #ifdef HAVE_PFKEY_POLICY_PRIORITY 195 + strlen(priority_str) 196 + ((priority_offset != 0) ? 13 : 0) /* [space operator space int] */ 197 + ((strlen(priority_str) != 0) ? 1 : 0) /* space */ 198 #endif 199 + strlen(ipsp_policy_strs[xpl->sadb_x_policy_type]) 200 + 1; /* NUL */ 201 202 if ((buf = malloc(buflen)) == NULL) { 203 __ipsec_errcode = EIPSEC_NO_BUFS; 204 return NULL; 205 } 206 #ifdef HAVE_PFKEY_POLICY_PRIORITY 207 if (priority_offset != 0) 208 { 209 snprintf(buf, buflen, "%s %s %c %u %s", 210 ipsp_dir_strs[xpl->sadb_x_policy_dir], priority_str, operator, 211 priority_offset, ipsp_policy_strs[xpl->sadb_x_policy_type]); 212 } 213 else if (strlen (priority_str) != 0) 214 { 215 snprintf(buf, buflen, "%s %s %s", 216 ipsp_dir_strs[xpl->sadb_x_policy_dir], priority_str, 217 ipsp_policy_strs[xpl->sadb_x_policy_type]); 218 } 219 else 220 { 221 snprintf(buf, buflen, "%s %s", 222 ipsp_dir_strs[xpl->sadb_x_policy_dir], 223 ipsp_policy_strs[xpl->sadb_x_policy_type]); 224 } 225 #else 226 snprintf(buf, buflen, "%s %s", ipsp_dir_strs[xpl->sadb_x_policy_dir], 227 ipsp_policy_strs[xpl->sadb_x_policy_type]); 228 #endif 229 230 if (xpl->sadb_x_policy_type != IPSEC_POLICY_IPSEC) { 231 __ipsec_errcode = EIPSEC_NO_ERROR; 232 return buf; 233 } 234 235 /* count length of buffer for use */ 236 off = sizeof(*xpl); 237 while (off < PFKEY_EXTLEN(xpl)) { 238 xisr = (void *)((caddr_t)(void *)xpl + off); 239 off += xisr->sadb_x_ipsecrequest_len; 240 } 241 242 /* validity check */ 243 if (off != PFKEY_EXTLEN(xpl)) { 244 __ipsec_errcode = EIPSEC_INVAL_SADBMSG; 245 free(buf); 246 return NULL; 247 } 248 249 off = sizeof(*xpl); 250 while (off < PFKEY_EXTLEN(xpl)) { 251 int offset; 252 xisr = (void *)((caddr_t)(void *)xpl + off); 253 254 if (ipsec_dump_ipsecrequest(isrbuf, sizeof(isrbuf), xisr, 255 PFKEY_EXTLEN(xpl) - off, withports) == NULL) { 256 free(buf); 257 return NULL; 258 } 259 260 offset = strlen(buf); 261 buflen = offset + strlen(delimiter) + strlen(isrbuf) + 1; 262 newbuf = (char *)realloc(buf, buflen); 263 if (newbuf == NULL) { 264 __ipsec_errcode = EIPSEC_NO_BUFS; 265 free(buf); 266 return NULL; 267 } 268 buf = newbuf; 269 snprintf(buf+offset, buflen-offset, "%s%s", delimiter, isrbuf); 270 271 off += xisr->sadb_x_ipsecrequest_len; 272 } 273 274 __ipsec_errcode = EIPSEC_NO_ERROR; 275 return buf; 276 } 277 278 static char * 279 ipsec_dump_ipsecrequest(buf, len, xisr, bound, withports) 280 char *buf; 281 size_t len; 282 struct sadb_x_ipsecrequest *xisr; 283 size_t bound; /* boundary */ 284 int withports; 285 { 286 const char *proto, *mode, *level; 287 char abuf[NI_MAXHOST * 2 + 2]; 288 289 if (xisr->sadb_x_ipsecrequest_len > bound) { 290 __ipsec_errcode = EIPSEC_INVAL_PROTO; 291 return NULL; 292 } 293 294 switch (xisr->sadb_x_ipsecrequest_proto) { 295 case IPPROTO_ESP: 296 proto = "esp"; 297 break; 298 case IPPROTO_AH: 299 proto = "ah"; 300 break; 301 case IPPROTO_IPCOMP: 302 proto = "ipcomp"; 303 break; 304 default: 305 __ipsec_errcode = EIPSEC_INVAL_PROTO; 306 return NULL; 307 } 308 309 switch (xisr->sadb_x_ipsecrequest_mode) { 310 case IPSEC_MODE_ANY: 311 mode = "any"; 312 break; 313 case IPSEC_MODE_TRANSPORT: 314 mode = "transport"; 315 break; 316 case IPSEC_MODE_TUNNEL: 317 mode = "tunnel"; 318 break; 319 default: 320 __ipsec_errcode = EIPSEC_INVAL_MODE; 321 return NULL; 322 } 323 324 abuf[0] = '\0'; 325 if (xisr->sadb_x_ipsecrequest_len > sizeof(*xisr)) { 326 struct sockaddr *sa1, *sa2; 327 caddr_t p; 328 329 p = (void *)(xisr + 1); 330 sa1 = (void *)p; 331 sa2 = (void *)(p + sysdep_sa_len(sa1)); 332 if (sizeof(*xisr) + sysdep_sa_len(sa1) + sysdep_sa_len(sa2) != 333 xisr->sadb_x_ipsecrequest_len) { 334 __ipsec_errcode = EIPSEC_INVAL_ADDRESS; 335 return NULL; 336 } 337 if (set_addresses(abuf, sizeof(abuf), 338 sa1, sa2, withports) != 0) { 339 __ipsec_errcode = EIPSEC_INVAL_ADDRESS; 340 return NULL; 341 } 342 } 343 344 switch (xisr->sadb_x_ipsecrequest_level) { 345 case IPSEC_LEVEL_DEFAULT: 346 level = "default"; 347 break; 348 case IPSEC_LEVEL_USE: 349 level = "use"; 350 break; 351 case IPSEC_LEVEL_REQUIRE: 352 level = "require"; 353 break; 354 case IPSEC_LEVEL_UNIQUE: 355 level = "unique"; 356 break; 357 default: 358 __ipsec_errcode = EIPSEC_INVAL_LEVEL; 359 return NULL; 360 } 361 362 if (xisr->sadb_x_ipsecrequest_reqid == 0) 363 snprintf(buf, len, "%s/%s/%s/%s", proto, mode, abuf, level); 364 else { 365 int ch; 366 367 if (xisr->sadb_x_ipsecrequest_reqid > IPSEC_MANUAL_REQID_MAX) 368 ch = '#'; 369 else 370 ch = ':'; 371 snprintf(buf, len, "%s/%s/%s/%s%c%u", proto, mode, abuf, level, 372 ch, xisr->sadb_x_ipsecrequest_reqid); 373 } 374 375 return buf; 376 } 377 378 static int 379 set_addresses(buf, len, sa1, sa2, withports) 380 char *buf; 381 size_t len; 382 struct sockaddr *sa1; 383 struct sockaddr *sa2; 384 int withports; 385 { 386 char tmp1[NI_MAXHOST], tmp2[NI_MAXHOST]; 387 388 if (set_address(tmp1, sizeof(tmp1), sa1, withports) == NULL || 389 set_address(tmp2, sizeof(tmp2), sa2, withports) == NULL) 390 return -1; 391 if (strlen(tmp1) + 1 + strlen(tmp2) + 1 > len) 392 return -1; 393 snprintf(buf, len, "%s-%s", tmp1, tmp2); 394 return 0; 395 } 396 397 static char * 398 set_address(buf, len, sa, withports) 399 char *buf; 400 size_t len; 401 struct sockaddr *sa; 402 int withports; 403 { 404 const int niflags = NI_NUMERICHOST | NI_NUMERICSERV; 405 char host[NI_MAXHOST]; 406 char serv[NI_MAXSERV]; 407 408 if (len < 1) 409 return NULL; 410 buf[0] = '\0'; 411 if (getnameinfo(sa, (socklen_t)sysdep_sa_len(sa), host, sizeof(host), 412 serv, sizeof(serv), niflags) != 0) 413 return NULL; 414 415 if (withports) 416 snprintf(buf, len, "%s[%s]", host, serv); 417 else 418 snprintf(buf, len, "%s", host); 419 420 return buf; 421 } 422