1 /* 2 * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. Neither the name of the project nor the names of its contributors 14 * may be used to endorse or promote products derived from this software 15 * without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 * 29 * $FreeBSD$ 30 */ 31 /* KAME $Id: policy_parse.y,v 1.1 1999/10/20 01:26:41 sakane Exp $ */ 32 33 /* 34 * IN/OUT bound policy configuration take place such below: 35 * in <policy> 36 * out <policy> 37 * 38 * <policy> is one of following: 39 * "discard", "none", "ipsec <requests>", "entrust", "bypass", 40 * 41 * The following requests are accepted as <requests>: 42 * 43 * protocol/mode/src-dst/level 44 * protocol/mode/src-dst parsed as protocol/mode/src-dst/default 45 * protocol/mode/src-dst/ parsed as protocol/mode/src-dst/default 46 * protocol/transport parsed as protocol/mode/any-any/default 47 * protocol/transport//level parsed as protocol/mode/any-any/level 48 * 49 * You can concatenate these requests with either ' '(single space) or '\n'. 50 */ 51 52 %{ 53 #include <sys/types.h> 54 #include <sys/param.h> 55 #include <sys/socket.h> 56 57 #include <netinet/in.h> 58 #include <netinet6/ipsec.h> 59 60 #include <stdlib.h> 61 #include <stdio.h> 62 #include <errno.h> 63 #include <string.h> 64 #include <netdb.h> 65 66 #include "ipsec_strerror.h" 67 68 #define ATOX(c) \ 69 (isdigit(c) ? (c - '0') : (isupper(c) ? (c - 'A' + 10) : (c - 'a' + 10) )) 70 71 static caddr_t pbuf = NULL; /* sadb_x_policy buffer */ 72 static int tlen = 0; /* total length of pbuf */ 73 static int offset = 0; /* offset of pbuf */ 74 static int p_dir, p_type, p_protocol, p_mode, p_level; 75 static struct sockaddr *p_src = NULL; 76 static struct sockaddr *p_dst = NULL; 77 78 extern void yyerror __P((char *msg)); 79 static struct sockaddr *parse_sockaddr __P((/*struct _val *buf*/)); 80 static int rule_check __P((void)); 81 static int init_x_policy __P((void)); 82 static int set_x_request __P((struct sockaddr *src, struct sockaddr *dst)); 83 static int set_sockaddr __P((struct sockaddr *addr)); 84 static void policy_parse_request_init __P((void)); 85 static caddr_t policy_parse __P((char *msg, int msglen)); 86 87 extern void __policy__strbuffer__init__ __P((char *msg)); 88 extern int yyparse(); 89 extern int yylex(); 90 91 %} 92 93 %union { 94 u_int num; 95 struct _val { 96 int len; 97 char *buf; 98 } val; 99 } 100 101 %token DIR ACTION PROTOCOL MODE LEVEL 102 %token IPADDRESS 103 %token ME ANY 104 %token SLASH HYPHEN 105 %type <num> DIR ACTION PROTOCOL MODE LEVEL 106 %type <val> IPADDRESS 107 108 %% 109 policy_spec 110 : DIR ACTION 111 { 112 p_dir = $1; 113 p_type = $2; 114 115 if (init_x_policy()) 116 return -1; 117 } 118 rules 119 ; 120 121 rules 122 : /*NOTHING*/ 123 | rules rule { 124 if (rule_check() < 0) 125 return -1; 126 127 if (set_x_request(p_src, p_dst) < 0) 128 return -1; 129 130 policy_parse_request_init(); 131 } 132 ; 133 134 rule 135 : protocol SLASH mode SLASH addresses SLASH level 136 | protocol SLASH mode SLASH addresses SLASH 137 | protocol SLASH mode SLASH addresses 138 | protocol SLASH mode SLASH 139 | protocol SLASH mode SLASH SLASH level 140 | protocol SLASH mode 141 | protocol SLASH { 142 ipsec_errcode = EIPSEC_FEW_ARGUMENTS; 143 return -1; 144 } 145 | protocol { 146 ipsec_errcode = EIPSEC_FEW_ARGUMENTS; 147 return -1; 148 } 149 ; 150 151 protocol 152 : PROTOCOL { p_protocol = $1; } 153 ; 154 155 mode 156 : MODE { p_mode = $1; } 157 ; 158 159 level 160 : LEVEL { p_level = $1; } 161 ; 162 163 addresses 164 : IPADDRESS { 165 p_src = parse_sockaddr(&$1); 166 if (p_src == NULL) 167 return -1; 168 } 169 HYPHEN 170 IPADDRESS { 171 p_dst = parse_sockaddr(&$4); 172 if (p_dst == NULL) 173 return -1; 174 } 175 | ME HYPHEN ANY { 176 if (p_dir != IPSEC_DIR_OUTBOUND) { 177 ipsec_errcode = EIPSEC_INVAL_DIR; 178 return -1; 179 } 180 } 181 | ANY HYPHEN ME { 182 if (p_dir != IPSEC_DIR_INBOUND) { 183 ipsec_errcode = EIPSEC_INVAL_DIR; 184 return -1; 185 } 186 } 187 /* 188 | ME HYPHEN ME 189 */ 190 ; 191 192 %% 193 194 void 195 yyerror(msg) 196 char *msg; 197 { 198 fprintf(stderr, "%s\n", msg); 199 200 return; 201 } 202 203 static struct sockaddr * 204 parse_sockaddr(buf) 205 struct _val *buf; 206 { 207 struct addrinfo hints, *res; 208 char *serv = NULL; 209 int error; 210 struct sockaddr *newaddr = NULL; 211 212 memset(&hints, 0, sizeof(hints)); 213 hints.ai_family = PF_UNSPEC; 214 hints.ai_flags = AI_NUMERICHOST; 215 error = getaddrinfo(buf->buf, serv, &hints, &res); 216 if (error != 0 || res->ai_addr == NULL) { 217 ipsec_set_strerror(error == EAI_SYSTEM ? 218 gai_strerror(error) : strerror(errno)); 219 return NULL; 220 } 221 222 if (res->ai_addr == NULL) { 223 ipsec_set_strerror(gai_strerror(error)); 224 return NULL; 225 } 226 227 newaddr = malloc(res->ai_addr->sa_len); 228 if (newaddr == NULL) { 229 ipsec_errcode = EIPSEC_NO_BUFS; 230 freeaddrinfo(res); 231 return NULL; 232 } 233 memcpy(newaddr, res->ai_addr, res->ai_addr->sa_len); 234 235 /* 236 * XXX: If the scope of the destination is link-local, 237 * embed the scope-id(in this case, interface index) 238 * into the address. 239 */ 240 if (newaddr->sa_family == AF_INET6) { 241 struct sockaddr_in6 *sin6; 242 243 sin6 = (struct sockaddr_in6 *)newaddr; 244 if(IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr) && 245 sin6->sin6_scope_id != 0) 246 *(u_short *)&sin6->sin6_addr.s6_addr[2] = 247 htons(sin6->sin6_scope_id & 0xffff); 248 } 249 250 freeaddrinfo(res); 251 252 ipsec_errcode = EIPSEC_NO_ERROR; 253 return newaddr; 254 } 255 256 static int 257 rule_check() 258 { 259 if (p_type == IPSEC_POLICY_IPSEC) { 260 if (p_protocol == IPPROTO_IP) { 261 ipsec_errcode = EIPSEC_NO_PROTO; 262 return -1; 263 } 264 265 if (p_mode != IPSEC_MODE_TRANSPORT 266 && p_mode != IPSEC_MODE_TUNNEL) { 267 ipsec_errcode = EIPSEC_INVAL_MODE; 268 return -1; 269 } 270 271 if (p_src == NULL && p_dst == NULL) { 272 if (p_mode != IPSEC_MODE_TRANSPORT) { 273 ipsec_errcode = EIPSEC_INVAL_ADDRESS; 274 return -1; 275 } 276 } 277 else if (p_src->sa_family != p_dst->sa_family) { 278 ipsec_errcode = EIPSEC_FAMILY_MISMATCH; 279 return -1; 280 } 281 } 282 283 ipsec_errcode = EIPSEC_NO_ERROR; 284 return 0; 285 } 286 287 static int 288 init_x_policy() 289 { 290 struct sadb_x_policy *p; 291 292 tlen = sizeof(struct sadb_x_policy); 293 294 pbuf = malloc(tlen); 295 if (pbuf == NULL) { 296 ipsec_errcode = EIPSEC_NO_BUFS; 297 return -1; 298 } 299 p = (struct sadb_x_policy *)pbuf; 300 p->sadb_x_policy_len = 0; /* must update later */ 301 p->sadb_x_policy_exttype = SADB_X_EXT_POLICY; 302 p->sadb_x_policy_type = p_type; 303 p->sadb_x_policy_dir = p_dir; 304 p->sadb_x_policy_reserved = 0; 305 offset = tlen; 306 307 ipsec_errcode = EIPSEC_NO_ERROR; 308 return 0; 309 } 310 311 static int 312 set_x_request(src, dst) 313 struct sockaddr *src, *dst; 314 { 315 struct sadb_x_ipsecrequest *p; 316 int reqlen; 317 318 reqlen = sizeof(*p) 319 + (src ? src->sa_len : 0) 320 + (dst ? dst->sa_len : 0); 321 tlen += reqlen; /* increment to total length */ 322 323 pbuf = realloc(pbuf, tlen); 324 if (pbuf == NULL) { 325 ipsec_errcode = EIPSEC_NO_BUFS; 326 return -1; 327 } 328 p = (struct sadb_x_ipsecrequest *)&pbuf[offset]; 329 p->sadb_x_ipsecrequest_len = reqlen; 330 p->sadb_x_ipsecrequest_proto = p_protocol; 331 p->sadb_x_ipsecrequest_mode = p_mode; 332 p->sadb_x_ipsecrequest_level = p_level; 333 offset += sizeof(*p); 334 335 if (set_sockaddr(src) || set_sockaddr(dst)) 336 return -1; 337 338 ipsec_errcode = EIPSEC_NO_ERROR; 339 return 0; 340 } 341 342 static int 343 set_sockaddr(addr) 344 struct sockaddr *addr; 345 { 346 if (addr == NULL) { 347 ipsec_errcode = EIPSEC_NO_ERROR; 348 return 0; 349 } 350 351 /* tlen has already incremented */ 352 353 memcpy(&pbuf[offset], addr, addr->sa_len); 354 355 offset += addr->sa_len; 356 357 ipsec_errcode = EIPSEC_NO_ERROR; 358 return 0; 359 } 360 361 static void 362 policy_parse_request_init() 363 { 364 p_protocol = IPPROTO_IP; 365 p_mode = IPSEC_MODE_ANY; 366 p_level = IPSEC_LEVEL_DEFAULT; 367 if (p_src != NULL) { 368 free(p_src); 369 p_src = NULL; 370 } 371 if (p_dst != NULL) { 372 free(p_dst); 373 p_dst = NULL; 374 } 375 376 return; 377 } 378 379 static caddr_t 380 policy_parse(msg, msglen) 381 char *msg; 382 int msglen; 383 { 384 int error; 385 pbuf = NULL; 386 tlen = 0; 387 388 /* initialize */ 389 p_dir = IPSEC_DIR_INVALID; 390 p_type = IPSEC_POLICY_DISCARD; 391 policy_parse_request_init(); 392 __policy__strbuffer__init__(msg); 393 394 error = yyparse(); /* it must be set errcode. */ 395 if (error) { 396 if (pbuf != NULL) 397 free(pbuf); 398 return NULL; 399 } 400 401 /* update total length */ 402 ((struct sadb_x_policy *)pbuf)->sadb_x_policy_len = PFKEY_UNIT64(tlen); 403 404 ipsec_errcode = EIPSEC_NO_ERROR; 405 406 return pbuf; 407 } 408 409 caddr_t 410 ipsec_set_policy(msg, msglen) 411 char *msg; 412 int msglen; 413 { 414 caddr_t policy; 415 416 policy = policy_parse(msg, msglen); 417 if (policy == NULL) { 418 if (ipsec_errcode == EIPSEC_NO_ERROR) 419 ipsec_errcode = EIPSEC_INVAL_ARGUMENT; 420 return NULL; 421 } 422 423 ipsec_errcode = EIPSEC_NO_ERROR; 424 return policy; 425 } 426 427