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