1 /* -*- Mode: C; tab-width: 4 -*- 2 * 3 * Copyright (c) 2006-2010 Apple Inc. All rights reserved. 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18 %{ 19 #include <stdio.h> 20 #include <stdlib.h> 21 #include <string.h> 22 #include "mDNSEmbeddedAPI.h" 23 #include "DebugServices.h" 24 #include "dnsextd.h" 25 26 void yyerror( const char* error ); 27 int yylex(void); 28 29 30 typedef struct StringListElem 31 { 32 char * string; 33 struct StringListElem * next; 34 } StringListElem; 35 36 37 typedef struct OptionsInfo 38 { 39 char server_address[ 256 ]; 40 int server_port; 41 char source_address[ 256 ]; 42 int source_port; 43 int private_port; 44 int llq_port; 45 } OptionsInfo; 46 47 48 typedef struct ZoneInfo 49 { 50 char name[ 256 ]; 51 char certificate_name[ 256 ]; 52 char allow_clients_file[ 256 ]; 53 char allow_clients[ 256 ]; 54 char key[ 256 ]; 55 } ZoneInfo; 56 57 58 typedef struct KeySpec 59 { 60 char name[ 256 ]; 61 char algorithm[ 256 ]; 62 char secret[ 256 ]; 63 struct KeySpec * next; 64 } KeySpec; 65 66 67 typedef struct ZoneSpec 68 { 69 char name[ 256 ]; 70 DNSZoneSpecType type; 71 StringListElem * allowUpdate; 72 StringListElem * allowQuery; 73 char key[ 256 ]; 74 struct ZoneSpec * next; 75 } ZoneSpec; 76 77 78 static StringListElem * g_stringList = NULL; 79 static StringListElem * g_addrList = NULL; 80 static KeySpec * g_keys; 81 static ZoneSpec * g_zones; 82 static ZoneSpec g_zoneSpec; 83 static const char * g_filename; 84 85 #define YYPARSE_PARAM context 86 87 void 88 SetupOptions 89 ( 90 OptionsInfo * info, 91 void * context 92 ); 93 94 %} 95 96 %union 97 { 98 int number; 99 char * string; 100 } 101 102 %token OPTIONS 103 %token LISTEN_ON 104 %token NAMESERVER 105 %token PORT 106 %token ADDRESS 107 %token LLQ 108 %token PUBLIC 109 %token PRIVATE 110 %token ALLOWUPDATE 111 %token ALLOWQUERY 112 %token KEY 113 %token ALGORITHM 114 %token SECRET 115 %token ISSUER 116 %token SERIAL 117 %token ZONE 118 %token TYPE 119 %token ALLOW 120 %token OBRACE 121 %token EBRACE 122 %token SEMICOLON 123 %token IN 124 %token <string> DOTTED_DECIMAL_ADDRESS 125 %token <string> WILDCARD 126 %token <string> DOMAINNAME 127 %token <string> HOSTNAME 128 %token <string> QUOTEDSTRING 129 %token <number> NUMBER 130 131 %type <string> addressstatement 132 %type <string> networkaddress 133 134 %% 135 136 commands: 137 | 138 commands command SEMICOLON 139 ; 140 141 142 command: 143 options_set 144 | 145 zone_set 146 | 147 key_set 148 ; 149 150 151 options_set: 152 OPTIONS optionscontent 153 { 154 // SetupOptions( &g_optionsInfo, context ); 155 } 156 ; 157 158 optionscontent: 159 OBRACE optionsstatements EBRACE 160 ; 161 162 optionsstatements: 163 | 164 optionsstatements optionsstatement SEMICOLON 165 ; 166 167 168 optionsstatement: 169 statements 170 | 171 LISTEN_ON addresscontent 172 { 173 } 174 | 175 LISTEN_ON PORT NUMBER addresscontent 176 { 177 mDNSIPPort listen_port = mDNSOpaque16fromIntVal( $3 ); 178 DaemonInfo* d = ( DaemonInfo* ) context; 179 d->addr.sin_port = ( listen_port.NotAnInteger) ? listen_port.NotAnInteger : UnicastDNSPort.NotAnInteger; 180 StringListElem* addr = g_addrList; 181 while (addr != NULL) 182 { 183 StringListElem* next; 184 // The first ipv4 address in {,} is used; the rest are ignored. 185 if (inet_pton( AF_INET, addr->string, &d->addr.sin_addr ) == 0) { 186 inet_pton( AF_INET, "127.0.0.1", &d->ns_addr.sin_addr ); 187 LogMsg("LISTEN_ON: An invalid ipv4 address, %s, detected.", addr->string); 188 } 189 next = addr->next; 190 free(addr); 191 addr = next; 192 } 193 } 194 | 195 NAMESERVER ADDRESS networkaddress 196 { 197 } 198 | 199 NAMESERVER ADDRESS networkaddress PORT NUMBER 200 { 201 } 202 | 203 PRIVATE PORT NUMBER 204 { 205 ( ( DaemonInfo* ) context )->private_port = mDNSOpaque16fromIntVal( $3 ); 206 } 207 | 208 LLQ PORT NUMBER 209 { 210 ( ( DaemonInfo* ) context )->llq_port = mDNSOpaque16fromIntVal( $3 ); 211 } 212 ; 213 214 key_set: 215 KEY QUOTEDSTRING OBRACE SECRET QUOTEDSTRING SEMICOLON EBRACE 216 { 217 KeySpec * keySpec; 218 219 keySpec = ( KeySpec* ) malloc( sizeof( KeySpec ) ); 220 221 if ( !keySpec ) 222 { 223 LogMsg("ERROR: memory allocation failure"); 224 YYABORT; 225 } 226 227 strncpy( keySpec->name, $2, sizeof( keySpec->name ) ); 228 strncpy( keySpec->secret, $5, sizeof( keySpec->secret ) ); 229 230 keySpec->next = g_keys; 231 g_keys = keySpec; 232 } 233 ; 234 235 zone_set: 236 ZONE QUOTEDSTRING zonecontent 237 { 238 ZoneSpec * zoneSpec; 239 240 zoneSpec = ( ZoneSpec* ) malloc( sizeof( ZoneSpec ) ); 241 242 if ( !zoneSpec ) 243 { 244 LogMsg("ERROR: memory allocation failure"); 245 YYABORT; 246 } 247 248 strncpy( zoneSpec->name, $2, sizeof( zoneSpec->name ) ); 249 zoneSpec->type = g_zoneSpec.type; 250 strcpy( zoneSpec->key, g_zoneSpec.key ); 251 zoneSpec->allowUpdate = g_zoneSpec.allowUpdate; 252 zoneSpec->allowQuery = g_zoneSpec.allowQuery; 253 254 zoneSpec->next = g_zones; 255 g_zones = zoneSpec; 256 } 257 | 258 ZONE QUOTEDSTRING IN zonecontent 259 { 260 ZoneSpec * zoneSpec; 261 262 zoneSpec = ( ZoneSpec* ) malloc( sizeof( ZoneSpec ) ); 263 264 if ( !zoneSpec ) 265 { 266 LogMsg("ERROR: memory allocation failure"); 267 YYABORT; 268 } 269 270 strncpy( zoneSpec->name, $2, sizeof( zoneSpec->name ) ); 271 zoneSpec->type = g_zoneSpec.type; 272 strcpy( zoneSpec->key, g_zoneSpec.key ); 273 zoneSpec->allowUpdate = g_zoneSpec.allowUpdate; 274 zoneSpec->allowQuery = g_zoneSpec.allowQuery; 275 276 zoneSpec->next = g_zones; 277 g_zones = zoneSpec; 278 } 279 ; 280 281 zonecontent: 282 OBRACE zonestatements EBRACE 283 284 zonestatements: 285 | 286 zonestatements zonestatement SEMICOLON 287 ; 288 289 zonestatement: 290 TYPE PUBLIC 291 { 292 g_zoneSpec.type = kDNSZonePublic; 293 } 294 | 295 TYPE PRIVATE 296 { 297 g_zoneSpec.type = kDNSZonePrivate; 298 } 299 | 300 ALLOWUPDATE keycontent 301 { 302 g_zoneSpec.allowUpdate = g_stringList; 303 g_stringList = NULL; 304 } 305 | 306 ALLOWQUERY keycontent 307 { 308 g_zoneSpec.allowQuery = g_stringList; 309 g_stringList = NULL; 310 } 311 ; 312 313 addresscontent: 314 OBRACE addressstatements EBRACE 315 { 316 } 317 318 addressstatements: 319 | 320 addressstatements addressstatement SEMICOLON 321 { 322 } 323 ; 324 325 addressstatement: 326 DOTTED_DECIMAL_ADDRESS 327 { 328 StringListElem * elem; 329 330 elem = ( StringListElem* ) malloc( sizeof( StringListElem ) ); 331 332 if ( !elem ) 333 { 334 LogMsg("ERROR: memory allocation failure"); 335 YYABORT; 336 } 337 338 elem->string = $1; 339 340 elem->next = g_addrList; 341 g_addrList = elem; 342 } 343 ; 344 345 346 keycontent: 347 OBRACE keystatements EBRACE 348 { 349 } 350 351 keystatements: 352 | 353 keystatements keystatement SEMICOLON 354 { 355 } 356 ; 357 358 keystatement: 359 KEY DOMAINNAME 360 { 361 StringListElem * elem; 362 363 elem = ( StringListElem* ) malloc( sizeof( StringListElem ) ); 364 365 if ( !elem ) 366 { 367 LogMsg("ERROR: memory allocation failure"); 368 YYABORT; 369 } 370 371 elem->string = $2; 372 373 elem->next = g_stringList; 374 g_stringList = elem; 375 } 376 ; 377 378 379 networkaddress: 380 DOTTED_DECIMAL_ADDRESS 381 | 382 HOSTNAME 383 | 384 WILDCARD 385 ; 386 387 block: 388 OBRACE zonestatements EBRACE SEMICOLON 389 ; 390 391 statements: 392 | 393 statements statement 394 ; 395 396 statement: 397 block 398 { 399 $<string>$ = NULL; 400 } 401 | 402 QUOTEDSTRING 403 { 404 $<string>$ = $1; 405 } 406 %% 407 408 int yywrap(void); 409 410 extern int yylineno; 411 412 void yyerror( const char *str ) 413 { 414 fprintf( stderr,"%s:%d: error: %s\n", g_filename, yylineno, str ); 415 } 416 417 int yywrap() 418 { 419 return 1; 420 } 421 422 423 int 424 ParseConfig 425 ( 426 DaemonInfo * d, 427 const char * file 428 ) 429 { 430 extern FILE * yyin; 431 DNSZone * zone; 432 DomainAuthInfo * key; 433 KeySpec * keySpec; 434 ZoneSpec * zoneSpec; 435 int err = 0; 436 437 g_filename = file; 438 439 // Tear down the current zone specifiers 440 441 zone = d->zones; 442 443 while ( zone ) 444 { 445 DNSZone * next = zone->next; 446 447 key = zone->updateKeys; 448 449 while ( key ) 450 { 451 DomainAuthInfo * nextKey = key->next; 452 453 free( key ); 454 455 key = nextKey; 456 } 457 458 key = zone->queryKeys; 459 460 while ( key ) 461 { 462 DomainAuthInfo * nextKey = key->next; 463 464 free( key ); 465 466 key = nextKey; 467 } 468 469 free( zone ); 470 471 zone = next; 472 } 473 474 d->zones = NULL; 475 476 yyin = fopen( file, "r" ); 477 require_action( yyin, exit, err = 0 ); 478 479 err = yyparse( ( void* ) d ); 480 require_action( !err, exit, err = 1 ); 481 482 for ( zoneSpec = g_zones; zoneSpec; zoneSpec = zoneSpec->next ) 483 { 484 StringListElem * elem; 485 mDNSu8 * ok; 486 487 zone = ( DNSZone* ) malloc( sizeof( DNSZone ) ); 488 require_action( zone, exit, err = 1 ); 489 memset( zone, 0, sizeof( DNSZone ) ); 490 491 zone->next = d->zones; 492 d->zones = zone; 493 494 // Fill in the domainname 495 496 ok = MakeDomainNameFromDNSNameString( &zone->name, zoneSpec->name ); 497 require_action( ok, exit, err = 1 ); 498 499 // Fill in the type 500 501 zone->type = zoneSpec->type; 502 503 // Fill in the allow-update keys 504 505 for ( elem = zoneSpec->allowUpdate; elem; elem = elem->next ) 506 { 507 mDNSBool found = mDNSfalse; 508 509 for ( keySpec = g_keys; keySpec; keySpec = keySpec->next ) 510 { 511 if ( strcmp( elem->string, keySpec->name ) == 0 ) 512 { 513 DomainAuthInfo * authInfo = malloc( sizeof( DomainAuthInfo ) ); 514 mDNSs32 keylen; 515 require_action( authInfo, exit, err = 1 ); 516 memset( authInfo, 0, sizeof( DomainAuthInfo ) ); 517 518 ok = MakeDomainNameFromDNSNameString( &authInfo->keyname, keySpec->name ); 519 if (!ok) { free(authInfo); err = 1; goto exit; } 520 521 keylen = DNSDigest_ConstructHMACKeyfromBase64( authInfo, keySpec->secret ); 522 if (keylen < 0) { free(authInfo); err = 1; goto exit; } 523 524 authInfo->next = zone->updateKeys; 525 zone->updateKeys = authInfo; 526 527 found = mDNStrue; 528 529 break; 530 } 531 } 532 533 // Log this 534 require_action( found, exit, err = 1 ); 535 } 536 537 // Fill in the allow-query keys 538 539 for ( elem = zoneSpec->allowQuery; elem; elem = elem->next ) 540 { 541 mDNSBool found = mDNSfalse; 542 543 for ( keySpec = g_keys; keySpec; keySpec = keySpec->next ) 544 { 545 if ( strcmp( elem->string, keySpec->name ) == 0 ) 546 { 547 DomainAuthInfo * authInfo = malloc( sizeof( DomainAuthInfo ) ); 548 mDNSs32 keylen; 549 require_action( authInfo, exit, err = 1 ); 550 memset( authInfo, 0, sizeof( DomainAuthInfo ) ); 551 552 ok = MakeDomainNameFromDNSNameString( &authInfo->keyname, keySpec->name ); 553 if (!ok) { free(authInfo); err = 1; goto exit; } 554 555 keylen = DNSDigest_ConstructHMACKeyfromBase64( authInfo, keySpec->secret ); 556 if (keylen < 0) { free(authInfo); err = 1; goto exit; } 557 558 authInfo->next = zone->queryKeys; 559 zone->queryKeys = authInfo; 560 561 found = mDNStrue; 562 563 break; 564 } 565 } 566 567 // Log this 568 require_action( found, exit, err = 1 ); 569 } 570 } 571 572 exit: 573 574 return err; 575 } 576 577 578 void 579 SetupOptions 580 ( 581 OptionsInfo * info, 582 void * context 583 ) 584 { 585 DaemonInfo * d = ( DaemonInfo* ) context; 586 587 if ( strlen( info->source_address ) ) 588 { 589 inet_pton( AF_INET, info->source_address, &d->addr.sin_addr ); 590 } 591 592 if ( info->source_port ) 593 { 594 d->addr.sin_port = htons( ( mDNSu16 ) info->source_port ); 595 } 596 597 if ( strlen( info->server_address ) ) 598 { 599 inet_pton( AF_INET, info->server_address, &d->ns_addr.sin_addr ); 600 } 601 602 if ( info->server_port ) 603 { 604 d->ns_addr.sin_port = htons( ( mDNSu16 ) info->server_port ); 605 } 606 607 if ( info->private_port ) 608 { 609 d->private_port = mDNSOpaque16fromIntVal( info->private_port ); 610 } 611 612 if ( info->llq_port ) 613 { 614 d->llq_port = mDNSOpaque16fromIntVal( info->llq_port ); 615 } 616 } 617