1/* 2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. Please obtain a copy of the License at 10 * http://www.opensource.apple.com/apsl/ and read it before using this 11 * file. 12 * 13 * The Original Code and all software distributed under the License are 14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 * Please see the License for the specific language governing rights and 19 * limitations under the License. 20 * 21 * @APPLE_LICENSE_HEADER_END@ 22 */ 23 24 25#include <stdio.h> 26#include <string.h> 27#include <stdlib.h> 28#include <netdb.h> 29#include <sys/param.h> 30#include <sys/types.h> 31#include <sys/socket.h> 32#include <netinet/in.h> 33#include <arpa/inet.h> 34#include <net/route.h> 35#include <net/if_types.h> 36#include <unistd.h> 37#include <netinet/ip.h> 38#include <netinet/bootp.h> 39#include "pppd.h" 40#include "fsm.h" 41#include "pathnames.h" 42#include "acsp.h" 43#include "acscp.h" 44#include "acscp_plugin.h" 45#include <net/if.h> // required for if_ppp.h 46#include "../../Family/if_ppp.h" 47#include "../vpnd/RASSchemaDefinitions.h" 48#include <CoreFoundation/CoreFoundation.h> 49#include <SystemConfiguration/SystemConfiguration.h> 50#include <SystemConfiguration/SCSchemaDefinitions.h> 51 52#define ACSP_TIMEOUT_VALUE 3 /* seconds */ 53 54static acsp_ext *ext_list; // list of acsp_ext structs - one for each option type 55//static struct acsp_plugin *plugin_list; // list of plugin channels - not currently used 56static bool acsp_plugin_installed = false; //To check ACSP status externally 57 58extern bool acsp_no_routes; 59extern bool acsp_no_domains; 60 61extern bool acsp_use_dhcp; 62extern bool acsp_intercept_dhcp; 63 64 65extern char *serverid; // defined in sys-MacOSX.c 66extern char *serviceid; // defined in sys-MacOSX.c 67 68 69static void acsp_start_plugin(acsp_ext *ext, int mtu); 70static void acsp_stop_plugin(acsp_ext *ext); 71static void acsp_output(acsp_ext *ext); 72static void acsp_timeout(void *arg); 73static void acsp_ipdata_input(int unit, u_char *pkt, int len, u_int32_t ouraddr, u_int32_t hisaddr); 74static void acsp_ipdata_up(int unit, u_int32_t ouraddr, u_int32_t hisaddr); 75static void acsp_ipdata_down(int unit); 76static void acsp_ipdata_timeout(void *arg); 77static int acsp_ipdata_print(u_char *, int, void (*) __P((void *, char *, ...)), void *); 78 79// ACSP plugin channel functions - will eventually be called thru acsp_channel 80static void acsp_plugin_check_options(void); 81static int acsp_plugin_get_type_count(void); 82static int acsp_plugin_init_type(acsp_ext *ext, int type_index); 83 84 85//------------------------------------------------------------ 86//------------------------------------------------------------ 87// ACSP Protocol Functions 88//------------------------------------------------------------ 89//------------------------------------------------------------ 90 91//------------------------------------------------------------ 92// acsp_init_plugins 93//------------------------------------------------------------ 94void 95acsp_init_plugins(void *arg, uintptr_t phase) 96{ 97 acsp_ext *ext; 98 int i, option_count; 99 100 ext_list = 0; 101 102 remove_notifier(&phasechange, acsp_init_plugins, 0); 103 104 // load each plugin here and call start - is this the right place ??? 105 106 // for each plugin 107 108 acsp_plugin_check_options(); 109 110 // call get_type_count 111 option_count = acsp_plugin_get_type_count(); 112 113 // for each option the plugin supports - get the ext struct initialized 114 for (i = 0; i < option_count; i++) { 115 if ((ext = (acsp_ext*)malloc(sizeof(acsp_ext))) == 0) { 116 error("acscp unable allocate plugin structures\n"); 117 acscp_protent.enabled_flag = 0; 118 return; 119 } 120 121 if (acsp_plugin_init_type(ext, i)) { 122 error("error initializing acsp plugin type\n"); 123 free(ext); 124 continue; 125 } 126 127 ext->next = 0; 128 ext->timer_state = ACSP_TIMERSTATE_STOPPED; 129 ext->in.size = sizeof(ACSP_Input); 130 ext->in.mtu = 0; 131 ext->in.log_debug = 0; 132 ext->in.log_error = 0; 133 ext->out.size = sizeof(ACSP_Output); 134 135 // add the ext struct to the list 136 ext->next = ext_list; 137 ext_list = ext; 138 } 139 140 // add hook for dhcp/ipdata 141 // will use route and domain information from acsp 142 ipdata_input_hook = acsp_ipdata_input; 143 ipdata_up_hook = acsp_ipdata_up; 144 ipdata_down_hook = acsp_ipdata_down; 145 ipdata_print_hook = acsp_ipdata_print; 146 147} 148 149//------------------------------------------------------------ 150// acsp_start_plugin 151//------------------------------------------------------------ 152void 153acsp_start(int mtu) 154{ 155 acsp_ext *ext; 156 157 // acscp is negotiated, stop dhcp 158 acsp_ipdata_down(0); 159 160 // let the plugins do their thing 161 ext = ext_list; 162 while (ext) { 163 acsp_start_plugin(ext, mtu); 164 ext = ext->next; 165 } 166 167} 168 169//------------------------------------------------------------ 170// acsp_start_plugin 171//------------------------------------------------------------ 172void 173acsp_stop(void) 174{ 175 acsp_ext *ext; 176 177 // stop the plugins 178 ext = ext_list; 179 while (ext) { 180 acsp_stop_plugin(ext); 181 ext = ext->next; 182 } 183} 184 185//------------------------------------------------------------ 186// acsp_start_plugin 187//------------------------------------------------------------ 188static void 189acsp_start_plugin(acsp_ext *ext, int mtu) 190{ 191 ext->in.mtu = mtu; 192 ext->in.notification = ACSP_NOTIFICATION_START; 193 ext->in.data_len = 0; 194 ext->in.data = 0; 195 ext->out.action = ACSP_ACTION_NONE; 196 ext->out.data_len = 0; 197 ext->out.data = 0; 198 ext->process(ext->context, &ext->in, &ext->out); 199 200 acsp_output(ext); 201} 202 203//------------------------------------------------------------ 204// acsp_stop_plugin 205//------------------------------------------------------------ 206static void 207acsp_stop_plugin(acsp_ext *ext) 208{ 209 if (ext->timer_state != ACSP_TIMERSTATE_STOPPED) { 210 UNTIMEOUT(acsp_timeout, ext); 211 ext->timer_state = ACSP_TIMERSTATE_STOPPED; 212 } 213 ext->in.notification = ACSP_NOTIFICATION_STOP; 214 ext->in.data_len = 0; 215 ext->in.data = 0; 216 ext->out.action = ACSP_ACTION_NONE; 217 ext->out.data_len = 0; 218 ext->out.data = 0; 219 ext->process(ext->context, &ext->in, &ext->out); 220} 221 222/* Wcast-align fix - The input and output buffers used by pppd are aligned(4) 223 * which makes them still aligned(4) after the 4 byte ppp header is removed. 224 * These routines expect the packet buffer to have such alignment. 225 */ 226 227//------------------------------------------------------------ 228// acsp_data_input 229//------------------------------------------------------------ 230void 231acsp_data_input(int unit, u_char *packet, int len) 232{ 233 234 acsp_ext *ext; 235 acsp_packet *pkt = ALIGNED_CAST(acsp_packet*)packet; 236 237 if (len < ACSP_HDR_SIZE) { 238 error("ACSP packet received was too short\n"); 239 return; // discard the packet 240 } 241 242 // find the option struct and plugin for this packet 243 for (ext = ext_list; ext != 0; ext = ext->next) 244 if (ext->type == pkt->type) 245 break; 246 247 if (ext == 0) { 248 error("ACSP packet received with invalid type\n"); 249 return; 250 } 251 252 if (ntohs(pkt->flags) & ACSP_FLAG_ACK && ext->timer_state == ACSP_TIMERSTATE_PACKET && pkt->seq == ext->last_seq) { 253 UNTIMEOUT(acsp_timeout, ext); 254 ext->timer_state = ACSP_TIMERSTATE_STOPPED; 255 } 256 ext->in.notification = ACSP_NOTIFICATION_PACKET; 257 ext->in.data = pkt; 258 ext->in.data_len = len; 259 ext->out.data = 0; 260 ext->out.data_len = 0; 261 ext->out.action = ACSP_ACTION_NONE; 262 263 ext->process(ext->context, &ext->in, &ext->out); 264 acsp_output(ext); 265} 266 267//------------------------------------------------------------ 268// acsp_output 269//------------------------------------------------------------ 270static void 271acsp_output(acsp_ext *ext) 272{ 273 int done = 0; 274 u_int8_t *ptr; 275 276 while (!done) { 277 done = 1; 278 switch (ext->out.action) { 279 case ACSP_ACTION_NONE: 280 break; 281 282 case ACSP_ACTION_SEND: 283 case ACSP_ACTION_SEND_WITH_TIMEOUT: 284 if (ext->out.data_len > ext->in.mtu || ext->out.data_len < ACSP_HDR_SIZE) { 285 error("ACSP plugin for option # %d trying to send packet of invalid length\n", ext->type); 286 ext->in.notification = ACSP_NOTIFICATION_ERROR; 287 ext->in.data = 0; 288 ext->in.data_len = 0; 289 ext->out.data = 0; 290 ext->out.data_len = 0; 291 ext->out.action = ACSP_ACTION_NONE; 292 done = 0; 293 ext->process(ext->context, &ext->in, &ext->out); 294 } else { 295 ptr = ext->out.data; // add address, control, and proto 296 *ptr++ = 0xff; 297 *ptr++ = 0x03; 298 *(ALIGNED_CAST(u_int16_t*)ptr) = htons(PPP_ACSP); 299 ptr += 2; 300 301 if (ext->out.action == ACSP_ACTION_SEND_WITH_TIMEOUT) { 302 if (ext->timer_state != ACSP_TIMERSTATE_STOPPED) 303 UNTIMEOUT(acsp_timeout, ext); 304 ext->timer_state = ACSP_TIMERSTATE_PACKET; 305 ext->last_seq = (ALIGNED_CAST(acsp_packet*)ptr)->seq; 306 TIMEOUT(acsp_timeout, ext, ACSP_TIMEOUT_VALUE); 307 } 308 output(0, ext->out.data, ext->out.data_len); 309 if (ext->free) 310 ext->free(ext->context, &ext->out); 311 312 } 313 break; 314 315 case ACSP_ACTION_INVOKE_UI: 316 error("ACSP plugin for option # %d attempted to invoke UI - not supported\n", ext->type); 317 ext->in.notification = ACSP_NOTIFICATION_ERROR; 318 ext->in.data = 0; 319 ext->in.data_len = 0; 320 ext->out.data = 0; 321 ext->out.data_len = 0; 322 ext->out.action = ACSP_ACTION_NONE; 323 done = 0; 324 ext->process(ext->context, &ext->in, &ext->out); 325 break; 326 327 case ACSP_ACTION_SET_TIMEOUT: 328 if (ext->out.data_len != 4) { 329 error("ACSP plugin for option # %d attempted timeout action with invalid time value\n", ext->type); 330 ext->in.notification = ACSP_NOTIFICATION_ERROR; 331 ext->in.data = 0; 332 ext->in.data_len = 0; 333 ext->out.data = 0; 334 ext->out.data_len = 0; 335 ext->out.action = ACSP_ACTION_NONE; 336 done = 0; 337 ext->process(ext->context, &ext->in, &ext->out); 338 } else { 339 ext->timer_state = ACSP_TIMERSTATE_GENERAL; 340 TIMEOUT(acsp_timeout, ext, *((int*)ext->out.data)); 341 } 342 break; 343 344 case ACSP_ACTION_CANCEL_TIMEOUT: 345 if (ext->timer_state != ACSP_TIMERSTATE_STOPPED) { 346 UNTIMEOUT(acsp_timeout, ext); 347 ext->timer_state = ACSP_TIMERSTATE_STOPPED; 348 } 349 break; 350 351 default: 352 error("ACSP plugin for option # %d trying to perform invalid action\n", ext->type); 353 ext->in.notification = ACSP_NOTIFICATION_ERROR; 354 ext->in.data = 0; 355 ext->in.data_len = 0; 356 ext->out.data = 0; 357 ext->out.data_len = 0; 358 ext->out.action = ACSP_ACTION_NONE; 359 done = 0; 360 ext->process(ext->context, &ext->in, &ext->out); 361 break; 362 } // switch 363 } // while 364} 365 366 367//------------------------------------------------------------ 368// acsp_timeout 369//------------------------------------------------------------ 370static void 371acsp_timeout(void *arg) 372{ 373 acsp_ext *ext = (acsp_ext*)arg; 374 375 ext->timer_state = ACSP_TIMERSTATE_STOPPED; 376 ext->in.notification = ACSP_NOTIFICATION_TIMEOUT; 377 ext->in.data_len = 0; 378 ext->in.data = 0; 379 ext->out.action = ACSP_ACTION_NONE; 380 ext->out.data_len = 0; 381 ext->out.data = 0; 382 ext->process(ext->context, &ext->in, &ext->out); 383 384 acsp_output(ext); 385} 386 387//------------------------------------------------------------ 388//------------------------------------------------------------ 389// Plugin stuff - to be moved to plugin eventually 390//------------------------------------------------------------ 391//------------------------------------------------------------ 392 393#define STR_BUFSIZE 1024 394#define ACSP_PLUGIN_MAX_RETRIES 10 395 396// 397// plugin state 398// 399#define PLUGIN_STATE_NONE 0 /* no state set */ 400#define PLUGIN_STATE_INITIAL 1 /* setup but not started - ACSP not up */ 401#define PLUGIN_RCVSTATE_LISTEN 2 /* listening for incomming data */ 402#define PLUGIN_RCVSTATE_WAITING_PKT 3 /* waiting for more data - partial data recvd */ 403#define PLUGIN_SENDSTATE_WAITING_ACK 4 /* waiting for ack for last packet sent */ 404#define PLUGIN_STATE_DONE 5 /* done sending */ 405 406// 407// modes to indicate sending or receiving 408// 409#define PLUGIN_MODE_NONE 0 410#define PLUGIN_MODE_RCV 1 411#define PLUGIN_MODE_SEND 2 412 413#define ACSP_ROUTEFLAGS_PRIVATE 0x0001 414#define ACSP_ROUTEFLAGS_PUBLIC 0x0002 415 416// 417// route struct to hold 1 route for sending or 418// a route received to be installed 419// 420typedef struct acsp_route { 421 struct acsp_route *next; 422 struct in_addr address; 423 struct in_addr mask; 424 struct in_addr router; 425 u_int16_t flags; 426 int installed; 427} acsp_route; 428 429// structure of route data in a packet 430typedef struct acsp_route_data { 431 u_int32_t address; 432 u_int32_t mask; 433 u_int16_t flags; 434 u_int16_t reserved; 435} acsp_route_data; 436 437// 438// domain struct to hold 1 domain name for sending or 439// a domain name recieved to be installed 440// 441typedef struct acsp_domain { 442 struct acsp_domain *next; 443 struct in_addr server; 444 char *name; 445} acsp_domain; 446 447// structure of domain data in a packet 448#define ACSP_DOMAIN_DATA_HDRSIZE 6 449typedef struct acsp_domain_data { 450 u_int32_t server; 451 u_int16_t len; 452 char name[1]; 453} acsp_domain_data; 454 455// 456// plugin context - holds all state for a particular 457// option type 458// 459typedef struct acsp_plugin_context { 460 u_int8_t type; 461 int mode; // indicates client or server side 462 int state; 463 u_int8_t next_seq; 464 int ip_up; 465 // the following is used only by the server side 466 int retry_count; 467 void *next_to_send; 468 char *buf; 469 u_int16_t buf_size; 470 u_int16_t last_pkt_len; 471 void *list; 472 int config_installed; 473} acsp_plugin_context; 474 475typedef struct acsp_dhcp_context { 476 int state; 477 int retry_count; 478 void *route; 479 char *domain; 480 struct in_addr netmask; 481 int config_installed; 482 int unit; 483 struct in_addr ouraddr; 484 struct in_addr hisaddr; 485} acsp_dhcp_context; 486 487// 488// globals 489// 490 491// lists of routes and domains read from the config file 492// these lists are placed in the context for the accociated 493// option type when the context is created and intialized 494static acsp_route *routes_list = 0; 495static acsp_domain *domains_list = 0; 496static struct in_addr primary_router = { 0 }; // address of primary router (before PPP connection) 497static u_int32_t subnet_mask = 0; 498 499static acsp_dhcp_context *dhcp_context = 0; 500 501extern CFStringRef serviceidRef; 502extern SCDynamicStoreRef cfgCache; 503extern int publish_dns_wins_entry(CFStringRef entity, CFStringRef property1, CFTypeRef ref1, CFTypeRef ref1a, 504 CFStringRef property2, CFTypeRef ref2, 505 CFStringRef property3, CFTypeRef ref3, int clean); 506extern int route_interface(int cmd, struct in_addr host, struct in_addr mask, char iftype, char *ifname, int is_host); 507extern int route_gateway(int cmd, struct in_addr dest, struct in_addr mask, struct in_addr gateway, int use_gway_flag); 508 509// 510// funtion prototypes 511// 512static void acsp_plugin_ip_up(void *arg, uintptr_t phase); 513static void acsp_plugin_ip_down(void *arg, uintptr_t phase); 514static void acsp_plugin_install_config(acsp_plugin_context *context); 515static void acsp_plugin_remove_config(acsp_plugin_context *context); 516static void acsp_plugin_read_routes(CFPropertyListRef serverRef); 517static void acsp_plugin_read_domains(CFPropertyListRef serverRef); 518static void acsp_plugin_read_domain_from_store(void); 519static int acsp_plugin_alloc_context(acsp_ext *ext, u_int8_t type); 520static void acsp_plugin_send(acsp_plugin_context* context, ACSP_Input* acsp_in, ACSP_Output* acsp_out); 521static void acsp_plugin_resend(acsp_plugin_context* context, ACSP_Input* acsp_in, ACSP_Output* acsp_out); 522static void acsp_plugin_send_ack(acsp_plugin_context* context, ACSP_Input* acsp_in, ACSP_Output* acsp_out); 523static int acsp_plugin_read(acsp_plugin_context* context, ACSP_Input* acsp_in); 524static void acsp_plugin_clear_list(acsp_plugin_context* context); 525static void acsp_plugin_dispose __P((void *context)); 526static void acsp_plugin_process __P((void *context, ACSP_Input *acsp_in, ACSP_Output *acsp_out)); 527static void acsp_plugin_print_packet __P((void (*printer)(void *, char *, ...), void *arg, u_char code, char *inbuf, int insize)); 528 529static void acsp_plugin_add_routes(acsp_route *route); 530static void acsp_plugin_add_domains(acsp_domain *domain); 531static void acsp_plugin_remove_routes(acsp_route *route); 532 533//------------------------------------------------------------ 534// *** Plugin functions called thru Plugin Channel *** 535// Used to init the plugin and init the ext structs 536// for each option type supported 537//------------------------------------------------------------ 538 539//------------------------------------------------------------ 540// acsp_plugin_check_options 541// read options from the config file 542//------------------------------------------------------------ 543static void acsp_plugin_check_options(void) 544{ 545 546 SCPreferencesRef prefs; 547 CFPropertyListRef ref; 548 CFStringRef idRef; 549 char sopt[32]; 550 CFTypeRef dictRef; 551 CFStringRef key; 552 CFDataRef strRef; 553 CFPropertyListRef servers_list; 554 555 556 routes_list = 0; 557 domains_list = 0; 558 559 if (serverid == 0) { // client side 560 if (acsp_no_routes == 0) // command line disable ? 561 acscp_wantoptions[0].neg_routes = 1; // default setting for client 562 if (acsp_no_domains == 0) // command line disable ? 563 acscp_wantoptions[0].neg_domains = 1; // default setting for client 564 565 // get the primary interface router address 566 sopt[0] = 0; 567 key = SCDynamicStoreKeyCreateNetworkGlobalEntity(0, kSCDynamicStoreDomainState, kSCEntNetIPv4); 568 if (key) { 569 if ((dictRef = SCDynamicStoreCopyValue(cfgCache, key))) { 570 strRef = CFDictionaryGetValue(dictRef, kSCPropNetIPv4Router); 571 if (strRef && (CFGetTypeID(strRef) == CFStringGetTypeID())) { 572 CFStringGetCString((CFStringRef)strRef, sopt, 32, kCFStringEncodingUTF8); 573 } 574 CFRelease(dictRef); 575 } 576 CFRelease(key); 577 } 578 if (sopt[0]) 579 inet_aton(sopt, &primary_router); 580 else 581 primary_router.s_addr = 0; 582 } else { 583 /* open the prefs file */ 584 if ((prefs = SCPreferencesCreate(0, CFSTR("pppd"), kRASServerPrefsFileName)) != 0) { 585 // get servers list from the plist 586 if ((servers_list = SCPreferencesGetValue(prefs, kRASServers)) != 0) { 587 if ((idRef = CFStringCreateWithCString(0, serverid , kCFStringEncodingMacRoman)) != 0) { 588 if ((ref = CFDictionaryGetValue(servers_list, idRef)) != 0) { 589 if (acsp_no_routes == 0) 590 acsp_plugin_read_routes(ref); // get routes option configuration 591 if (acsp_no_domains == 0) 592 acsp_plugin_read_domains(ref); // get domains option configuration 593 } 594 CFRelease(idRef); 595 } 596 CFRelease(prefs); 597 } 598 } 599 } 600} 601 602//------------------------------------------------------------ 603// acsp_plugin_read_routes 604// read routes option configuration 605//------------------------------------------------------------ 606static void acsp_plugin_read_routes(CFPropertyListRef serverRef) 607{ 608 609 CFDictionaryRef dict; 610 CFStringRef stringRef; 611 CFArrayRef addrArrayRef, maskArrayRef, typeArrayRef; 612 int addrCount, maskCount, typeCount, i; 613 char addrStr[STR_BUFSIZE], maskStr[STR_BUFSIZE]; 614 acsp_route *route; 615 struct in_addr outAddr, outMask; 616 u_int32_t flags; 617 618 // routes option parameters 619 dict = CFDictionaryGetValue(serverRef, kRASEntIPv4); 620 if (dict && CFGetTypeID(dict) == CFDictionaryGetTypeID()) { 621 // get the route address array 622 addrArrayRef = CFDictionaryGetValue(dict, kRASPropIPv4OfferedRouteAddresses); 623 if (addrArrayRef && CFGetTypeID(addrArrayRef) == CFArrayGetTypeID()) { 624 addrCount = CFArrayGetCount(addrArrayRef); 625 // get subnet mask array 626 maskArrayRef = CFDictionaryGetValue(dict, kRASPropIPv4OfferedRouteMasks); 627 if (maskArrayRef && CFGetTypeID(maskArrayRef) == CFArrayGetTypeID()) { 628 maskCount = CFArrayGetCount(addrArrayRef); 629 // get route type array 630 typeArrayRef = CFDictionaryGetValue(dict, kRASPropIPv4OfferedRouteTypes); 631 if (typeArrayRef && CFGetTypeID(typeArrayRef) == CFArrayGetTypeID()) { 632 typeCount = CFArrayGetCount(typeArrayRef); 633 634 if (addrCount != maskCount || addrCount != typeCount) { 635 error("ACSP plugin: while reading prefs - route address, mask, and type counts not equal\n"); 636 return; 637 } 638 acscp_allowoptions[0].neg_routes = 1; // found routes - set negotiate flag 639 640 // get address and mask for each route 641 for (i = 0; i < addrCount; i++) { 642 stringRef = CFArrayGetValueAtIndex(addrArrayRef, i); 643 addrStr[0] = 0; 644 CFStringGetCString(stringRef, addrStr, STR_BUFSIZE, kCFStringEncodingUTF8); 645 // get mask 646 stringRef = CFArrayGetValueAtIndex(maskArrayRef, i); 647 maskStr[0] = 0; 648 CFStringGetCString(stringRef, maskStr, STR_BUFSIZE, kCFStringEncodingUTF8); 649 // get route type 650 stringRef = CFArrayGetValueAtIndex(typeArrayRef, i); 651 if (CFStringCompare(stringRef, kRASValIPv4OfferedRouteTypesPrivate, 0) == kCFCompareEqualTo) 652 flags = ACSP_ROUTEFLAGS_PRIVATE; 653 else if(CFStringCompare(stringRef, kRASValIPv4OfferedRouteTypesPublic, 0) == kCFCompareEqualTo) 654 flags = ACSP_ROUTEFLAGS_PUBLIC; 655 else { 656 error("ACSP plugin: invalid route type specified\n"); 657 acscp_allowoptions[0].neg_routes = 0; 658 break; 659 } 660 // allocate the structure 661 if ((route = (acsp_route*)malloc(sizeof(acsp_route))) == 0) { 662 error("ACSP plugin: no memory\n"); 663 acscp_allowoptions[0].neg_routes = 0; 664 break; 665 } 666 bzero(route, sizeof(acsp_route)); 667 // convert 668 if (inet_aton(addrStr, &outAddr) == 0 || inet_aton(maskStr, &outMask) == 0) { 669 error("ACSP plugin: invalid ip address or mask specified\n"); 670 free(route); 671 acscp_allowoptions[0].neg_routes = 0; 672 return; 673 } 674 route->address = outAddr; 675 route->mask = outMask; 676 route->flags = flags; 677 route->installed = 0; 678 679 route->next = routes_list; 680 routes_list = route; 681 } 682 // check if we really have something to send 683 if (routes_list == 0) 684 acscp_allowoptions[0].neg_routes = 0; 685 } 686 } 687 } 688 } 689} 690 691//------------------------------------------------------------ 692// acsp_plugin_read_domains 693// read the domains option configuration 694//------------------------------------------------------------ 695static void acsp_plugin_read_domains(CFPropertyListRef serverRef) 696{ 697 CFDictionaryRef dict; 698 CFStringRef stringRef; 699 CFArrayRef nameArrayRef, serverArrayRef; 700 int nameCount, serverCount, outlen, i; 701 char str[STR_BUFSIZE]; 702 acsp_domain *domain; 703 struct in_addr outAddr; 704 705 // domains option parameters 706 dict = CFDictionaryGetValue(serverRef, kRASEntDNS); 707 if (dict && CFGetTypeID(dict) == CFDictionaryGetTypeID()) { 708 // get the domain names aray 709 nameArrayRef = CFDictionaryGetValue(dict, kRASPropDNSOfferedSearchDomains); 710 if (nameArrayRef && CFGetTypeID(nameArrayRef) == CFArrayGetTypeID()) { 711 nameCount = CFArrayGetCount(nameArrayRef); 712 // get the search domain server addresses if present 713 serverArrayRef = CFDictionaryGetValue(dict, kRASPropDNSOfferedSearchDomainServers); 714 if (serverArrayRef && CFGetTypeID(serverArrayRef) == CFArrayGetTypeID()) { 715 serverCount = CFArrayGetCount(serverArrayRef); 716 if (serverArrayRef && (serverCount != nameCount)) { 717 error("ACSP plugin: search domain count not equal to search domain server count\n"); 718 return; 719 } 720 } else 721 serverCount = 0; 722 723 acscp_allowoptions[0].neg_domains = 1; // enable negotiation of this option 724 if (nameCount == 0) 725 acsp_plugin_read_domain_from_store(); 726 else { 727 for (i = 0; i < nameCount; i++) { 728 stringRef = CFArrayGetValueAtIndex(nameArrayRef, i); 729 str[0] = 0; 730 CFStringGetCString(stringRef, str, STR_BUFSIZE, kCFStringEncodingUTF8); 731 outlen = strlen(str); 732 if (outlen) { 733 if ((domain = (acsp_domain*)malloc(sizeof(acsp_domain))) == 0) { 734 error("ACSP plugin: no memory\n"); 735 acscp_allowoptions[0].neg_domains = 0; 736 break; 737 } 738 if ((domain->name = malloc(outlen + 1)) == 0) { 739 error("ACSP plugin: no memory\n"); 740 acscp_allowoptions[0].neg_domains = 0; 741 free(domain); 742 break; 743 } 744 memcpy(domain->name, str, outlen + 1); 745 if (serverCount) { 746 stringRef = CFArrayGetValueAtIndex(serverArrayRef, i); 747 str[0] = 0; 748 CFStringGetCString(stringRef, str, STR_BUFSIZE, kCFStringEncodingUTF8); 749 if (inet_aton(str, &outAddr) == 0) { 750 error("ACSP plugin: invalid ip address specified for DNS server\n"); 751 free(domain); 752 acscp_allowoptions[0].neg_domains = 0; 753 return; 754 } 755 domain->server = outAddr; 756 } else 757 domain->server.s_addr = 0; 758 domain->next = domains_list; 759 domains_list = domain; 760 } 761 } 762 } 763 // check if we really have something to send 764 if (domains_list == 0) 765 acscp_allowoptions[0].neg_domains = 0; 766 } 767 } 768} 769 770//------------------------------------------------------------ 771// acsp_plugin_get_type_count 772// returns the number of types supported by the plugin 773//------------------------------------------------------------ 774static void acsp_plugin_read_domain_from_store(void) 775{ 776 SCDynamicStoreRef storeRef; 777 CFPropertyListRef ref = 0; 778 CFStringRef key = 0; 779 CFStringRef stringRef; 780 char str[STR_BUFSIZE]; 781 int len; 782 acsp_domain *domain; 783 784 storeRef = SCDynamicStoreCreate(0, CFSTR("pppd"), 0, 0); 785 if (storeRef) { 786 key = SCDynamicStoreKeyCreateNetworkGlobalEntity(0, kSCDynamicStoreDomainState, kSCEntNetDNS); 787 if (key) { 788 ref = SCDynamicStoreCopyValue(storeRef, key); 789 if (ref && CFGetTypeID(ref) == CFDictionaryGetTypeID()) { 790 stringRef = CFDictionaryGetValue(ref, kSCPropNetDNSDomainName); 791 if (stringRef && CFGetTypeID(stringRef) == CFStringGetTypeID()) { 792 str[0] = 0; 793 CFStringGetCString(stringRef, str, STR_BUFSIZE, kCFStringEncodingUTF8); 794 len = strlen(str); 795 if (len) { 796 if ((domain = (acsp_domain*)malloc(sizeof(acsp_domain))) == 0) { 797 error("ACSP plugin: no memory\n"); 798 } else if ((domain->name = malloc(len + 1)) == 0) { 799 error("ACSP plugin: no memory\n"); 800 free(domain); 801 } else { 802 memcpy(domain->name, str, len + 1); 803 domain->server.s_addr = 0; 804 domain->next = domains_list; 805 domains_list = domain; 806 } 807 } 808 } 809 } 810 CFRelease(key); 811 if (ref) 812 CFRelease(ref); 813 } 814 CFRelease(storeRef); 815 } 816} 817 818//------------------------------------------------------------ 819// acsp_plugin_get_type_count 820// returns the number of types supported by the plugin 821//------------------------------------------------------------ 822static int acsp_plugin_get_type_count(void) 823{ 824 return 2; 825} 826 827//------------------------------------------------------------ 828// acsp_plugin_init_type 829// init the ext struct for an option type 830// the option being inited is determined by the index 831// the function get_type_count() is used to get the 832// number of option types the plugin supports 833//------------------------------------------------------------ 834static int acsp_plugin_init_type(acsp_ext *ext, int type_index) 835{ 836 if (type_index == 0) { 837 ext->type = CI_ROUTES; 838 if (acsp_plugin_alloc_context(ext, CI_ROUTES) != 0) 839 return -1; 840 ((acsp_plugin_context*)(ext->context))->list = routes_list; // save the list read from prefs into the context 841 } else if (type_index == 1) { 842 ext->type = CI_DOMAINS; 843 if (acsp_plugin_alloc_context(ext, CI_DOMAINS) != 0) 844 return -1; 845 ((acsp_plugin_context*)(ext->context))->list = domains_list; // save the list read from prefs into the context 846 } else 847 return -1; // bad index 848 849 // we want the routes notifier to fire first, then the domains 850 if (ext->type == CI_DOMAINS) 851 add_notifier_last(&ip_up_notify, acsp_plugin_ip_up, ext->context); 852 else 853 add_notifier(&ip_up_notify, acsp_plugin_ip_up, ext->context); 854 add_notifier(&ip_down_notify, acsp_plugin_ip_down, ext->context); 855 856 return 0; 857} 858 859//------------------------------------------------------------ 860// acsp_plugin_alloc_context 861// allocate a context for the specified type 862//------------------------------------------------------------ 863static int acsp_plugin_alloc_context(acsp_ext *ext, u_int8_t type) 864{ 865 acsp_plugin_context* context; 866 867 if ((context = (acsp_plugin_context*)malloc(sizeof(acsp_plugin_context))) == 0) { 868 error("ACSP plugin: no memory\n"); 869 return -1; 870 } 871 // allocte buffer using max mtu since nothing has been negotiated yet 872 if ((context->buf = malloc(PPP_MTU)) == 0) { 873 error("ACSP plugin: no memory\n"); 874 free(context); 875 return -1; 876 } 877 context->buf_size = PPP_MTU; 878 context->type = type; 879 context->mode = PLUGIN_MODE_NONE; 880 context->state = PLUGIN_STATE_INITIAL; 881 context->ip_up = 0; 882 context->retry_count = 0; 883 context->next_seq = 0; 884 context->last_pkt_len = 0; 885 context->list = 0; 886 context->config_installed = 0; 887 ext->context = context; 888 889 // setup funtions pointers 890 ext->dispose = acsp_plugin_dispose; 891 ext->free = 0; 892 ext->interactive_ui = 0; 893 ext->process = acsp_plugin_process; 894 ext->print_packet = acsp_plugin_print_packet; 895 896 return 0; 897} 898 899//------------------------------------------------------------ 900// *** Plugin functions called thru the ext struct *** 901// Called for a particular option type 902//------------------------------------------------------------ 903 904//------------------------------------------------------------ 905// acsp_plugin_dispose 906// clean up 907//------------------------------------------------------------ 908static void acsp_plugin_dispose(void *context) 909{ 910 acsp_plugin_clear_list((acsp_plugin_context*)context); 911} 912 913//------------------------------------------------------------ 914// acsp_plugin_process 915// handle an event 916//------------------------------------------------------------ 917static void acsp_plugin_process(void *context, ACSP_Input *acsp_in, ACSP_Output *acsp_out) 918{ 919 acsp_packet *pkt = (acsp_packet*)acsp_in->data; 920 acsp_plugin_context* theContext = (acsp_plugin_context*)context; 921 922 switch (acsp_in->notification) { 923 case ACSP_NOTIFICATION_NONE: 924 break; 925 926 case ACSP_NOTIFICATION_DATA_FROM_UI: 927 error("ACSP plugin: unexpected notification received\n"); 928 break; 929 930 case ACSP_NOTIFICATION_START: 931 // get negotiated values and setup modes in context 932 if (theContext->type == CI_ROUTES) { 933 if (acscp_gotoptions[0].neg_routes) 934 theContext->mode = PLUGIN_MODE_RCV; 935 else if (acscp_hisoptions[0].neg_routes) 936 theContext->mode = PLUGIN_MODE_SEND; 937 else 938 theContext->mode = PLUGIN_MODE_NONE; 939 } else { 940 if (acscp_gotoptions[0].neg_domains) 941 theContext->mode = PLUGIN_MODE_RCV; 942 else if (acscp_hisoptions[0].neg_domains) 943 theContext->mode = PLUGIN_MODE_SEND; 944 else 945 theContext->mode = PLUGIN_MODE_NONE; 946 } 947 // setup the context and send if required 948 theContext->next_seq = 0; 949 theContext->retry_count = 0; 950 951 if (theContext->mode == PLUGIN_MODE_SEND) { 952 acsp_plugin_send(theContext, acsp_in, acsp_out); 953 theContext->next_seq++; 954 theContext->state = PLUGIN_SENDSTATE_WAITING_ACK; 955 } 956 else if (theContext->mode == PLUGIN_MODE_RCV) 957 theContext->state = PLUGIN_RCVSTATE_LISTEN; 958 break; 959 960 case ACSP_NOTIFICATION_STOP: 961 switch (theContext->state) { 962 case PLUGIN_SENDSTATE_WAITING_ACK: 963 acsp_out->action = ACSP_ACTION_CANCEL_TIMEOUT; 964 // fall thru 965 966 case PLUGIN_STATE_DONE: 967 if (theContext->config_installed) { 968 theContext->config_installed = 0; 969 if (theContext->type == CI_ROUTES) 970 acsp_plugin_remove_config(theContext); 971 } 972 break; 973 } 974 // if client side - clear the list of received data 975 if (theContext->mode == PLUGIN_MODE_RCV) 976 acsp_plugin_clear_list(theContext); 977 theContext->state = PLUGIN_STATE_INITIAL; 978 break; 979 980 case ACSP_NOTIFICATION_PACKET: 981 switch (theContext->state) { 982 case PLUGIN_RCVSTATE_LISTEN: 983 if ((ntohs(pkt->flags) & ACSP_FLAG_START) == 0) { 984 error("ACSP plugin: received first packet with no start flag\n"); 985 break; 986 } else 987 theContext->state = PLUGIN_RCVSTATE_WAITING_PKT; 988 // fall thru 989 990 case PLUGIN_RCVSTATE_WAITING_PKT: 991 // copy route data 992 if (pkt->seq == theContext->next_seq) { 993 if (acsp_plugin_read(theContext, acsp_in) == 0) { 994 theContext->next_seq++; 995 if (ntohs(pkt->flags) & ACSP_FLAG_END) { 996 theContext->state = PLUGIN_STATE_DONE; 997 if (theContext->ip_up) 998 acsp_plugin_install_config(theContext); 999 else 1000 notify(acspdhcpready_notifier, 0); 1001 } 1002 } else 1003 break; // bad packet or error - send no ack 1004 } 1005 1006 if (ntohs(pkt->flags) & ACSP_FLAG_REQUIRE_ACK) 1007 acsp_plugin_send_ack(theContext, acsp_in, acsp_out); 1008 break; 1009 1010 case PLUGIN_SENDSTATE_WAITING_ACK: 1011 if (ntohs(pkt->flags) & ACSP_FLAG_ACK) { // if ack - process it - otherwise drop the packet 1012 if (theContext->next_to_send) { 1013 acsp_plugin_send(theContext, acsp_in, acsp_out); 1014 theContext->next_seq++; 1015 } 1016 else { 1017 theContext->state = PLUGIN_STATE_DONE; 1018 notify(acspdhcpready_notifier, 0); 1019 } 1020 } 1021 break; 1022 } 1023 break; 1024 1025 case ACSP_NOTIFICATION_TIMEOUT: 1026 if (theContext->state == PLUGIN_SENDSTATE_WAITING_ACK) { 1027 if (theContext->retry_count++ < ACSP_PLUGIN_MAX_RETRIES) 1028 acsp_plugin_resend(theContext, acsp_in, acsp_out); 1029 else { 1030 error("ACSP plugin: no acknowlegement from peer\n"); 1031 theContext->state = PLUGIN_STATE_DONE; 1032 notify(acspdhcpready_notifier, 0); 1033 } 1034 } else 1035 error("ACSP plugin: received unexpected timeout\n"); 1036 break; 1037 1038 case ACSP_NOTIFICATION_ERROR: 1039 error("ACSP plugin: error notificationr received\n"); 1040 if (theContext->state == PLUGIN_SENDSTATE_WAITING_ACK) 1041 acsp_out->action = ACSP_ACTION_CANCEL_TIMEOUT; 1042 theContext->state = PLUGIN_STATE_DONE; 1043 notify(acspdhcpready_notifier, 0); 1044 break; 1045 1046 default: 1047 break; 1048 } 1049} 1050 1051//------------------------------------------------------------ 1052// acsp_plugin_print_packet 1053//------------------------------------------------------------ 1054static void acsp_plugin_print_packet(void (*printer)(void *, char *, ...), void *arg, u_char code, char *inbuf, int insize) 1055{ 1056} 1057 1058//------------------------------------------------------------ 1059// acsp_plugin_send 1060// send a data packet 1061//------------------------------------------------------------ 1062static void acsp_plugin_send(acsp_plugin_context* context, ACSP_Input* acsp_in, ACSP_Output* acsp_out) 1063{ 1064 1065 acsp_packet *pkt; 1066 u_int16_t space, len; 1067 int slen; 1068 acsp_route_data *route_data; 1069 acsp_domain_data domain_data; 1070 u_int8_t *outPtr; 1071 1072 1073 pkt = ALIGNED_CAST(acsp_packet*)(context->buf + 4); // leave space for address, control, and protocol 1074 space = MIN(context->buf_size, acsp_in->mtu) - 4; 1075 1076 if (context->state == PLUGIN_STATE_INITIAL) { 1077 pkt->flags = htons(ACSP_FLAG_START); 1078 context->next_to_send = context->list; 1079 } else 1080 pkt->flags = 0; 1081 1082 pkt->type = context->type; 1083 pkt->seq = context->next_seq; 1084 pkt->flags = htons(ntohs(pkt->flags) | ACSP_FLAG_REQUIRE_ACK); 1085 pkt->reserved = 0; 1086 len = ACSP_HDR_SIZE; 1087 1088 switch (context->type) { 1089 case CI_ROUTES: 1090 route_data = ALIGNED_CAST(acsp_route_data*)pkt->data; 1091 while (context->next_to_send && space >= len + sizeof(acsp_route_data)) { 1092 route_data->address = ((acsp_route*)context->next_to_send)->address.s_addr; 1093 route_data->mask = ((acsp_route*)context->next_to_send)->mask.s_addr; 1094 route_data->flags = htons(((acsp_route*)context->next_to_send)->flags); 1095 route_data->reserved = htons(0); 1096 len += sizeof(acsp_route_data); 1097 context->next_to_send = ((acsp_route*)(context->next_to_send))->next; 1098 route_data++; 1099 } 1100 break; 1101 case CI_DOMAINS: 1102 // WCast-align fix - use memcpy for unaligned access 1103 outPtr = pkt->data; 1104 while (context->next_to_send && space >= (len + (slen = strlen(((acsp_domain*)(context->next_to_send))->name)) + 6)) { 1105 domain_data.server = ((acsp_domain*)(context->next_to_send))->server.s_addr; 1106 domain_data.len = htons(slen); 1107 memcpy(outPtr, &domain_data, ACSP_DOMAIN_DATA_HDRSIZE); 1108 memcpy(outPtr + ACSP_DOMAIN_DATA_HDRSIZE, ((acsp_domain*)(context->next_to_send))->name, slen); 1109 len += (slen + ACSP_DOMAIN_DATA_HDRSIZE); 1110 context->next_to_send = ((acsp_domain*)(context->next_to_send))->next; 1111 outPtr += (ACSP_DOMAIN_DATA_HDRSIZE + slen); 1112 } 1113 break; 1114 } 1115 1116 if (context->next_to_send == 0) 1117 pkt->flags = htons(ntohs(pkt->flags) | ACSP_FLAG_END); 1118 acsp_out->action = ACSP_ACTION_SEND_WITH_TIMEOUT; 1119 context->last_pkt_len = len; 1120 pkt->len = htons(len); 1121 acsp_out->data_len = len + 4; 1122 acsp_out->data = context->buf; 1123} 1124 1125//------------------------------------------------------------ 1126// acsp_plugin_resend 1127// re-send a data packet 1128//------------------------------------------------------------ 1129static void acsp_plugin_resend(acsp_plugin_context* context, ACSP_Input* acsp_in, ACSP_Output* acsp_out) 1130{ 1131 // resent the packet; 1132 acsp_out->data = context->buf; 1133 acsp_out->data_len = context->last_pkt_len + 4; 1134 acsp_out->action = ACSP_ACTION_SEND_WITH_TIMEOUT; 1135} 1136 1137//------------------------------------------------------------ 1138// acsp_plugin_send_ack 1139// send an ack 1140//------------------------------------------------------------ 1141static void acsp_plugin_send_ack(acsp_plugin_context* context, ACSP_Input* acsp_in, ACSP_Output* acsp_out) 1142{ 1143 acsp_packet *inPkt, *outPkt; 1144 1145 inPkt = (acsp_packet*)acsp_in->data; 1146 outPkt = ALIGNED_CAST(acsp_packet*)(context->buf + 4); // leave space for address, control, and protocol 1147 outPkt->type = context->type; 1148 outPkt->seq = inPkt->seq; 1149 outPkt->flags = htons(ACSP_FLAG_ACK); 1150 outPkt->len = htons(ACSP_HDR_SIZE); 1151 outPkt->reserved = 0; 1152 1153 acsp_out->action = ACSP_ACTION_SEND; 1154 acsp_out->data_len = ACSP_HDR_SIZE + 4; 1155 acsp_out->data = context->buf; 1156} 1157 1158//------------------------------------------------------------ 1159// acsp_plugin_read 1160// process an incomming data packet 1161//------------------------------------------------------------ 1162static int acsp_plugin_read(acsp_plugin_context* context, ACSP_Input* acsp_in) 1163{ 1164 acsp_packet *pkt; 1165 acsp_route *route; 1166 acsp_domain *domain; 1167 int len, domain_len; 1168 acsp_route_data *route_data; 1169 acsp_domain_data domain_data; 1170 u_int8_t *inPtr; 1171 1172 len = acsp_in->data_len - ACSP_HDR_SIZE; 1173 pkt = acsp_in->data; 1174 1175 switch (context->type) { 1176 case CI_ROUTES: 1177 if (len % 4 != 0) { 1178 error("ACSP plugin: received packet with invalid len\n"); 1179 return -1; 1180 } 1181 route_data = ALIGNED_CAST(acsp_route_data*)pkt->data; 1182 while (len > 4) { 1183 if ((route = (acsp_route*)malloc(sizeof(acsp_route))) == 0) { 1184 error("ACSP plugin: no memory\n"); 1185 return -1; 1186 } 1187 bzero(route, sizeof(acsp_route)); 1188 route->address.s_addr = route_data->address & route_data->mask; 1189 route->mask.s_addr = route_data->mask; 1190 route->flags = ntohs(route_data->flags); 1191 route->installed = 0; 1192 route->next = (acsp_route*)context->list; 1193 context->list = route; 1194 len -= sizeof(acsp_route_data); 1195 route_data++; 1196 } 1197 break; 1198 1199 case CI_DOMAINS: 1200 // WCast-align fix - this routine changed to use memcpy for unaligned access 1201 inPtr = pkt->data; 1202 while (len > 2) { 1203 memcpy(&domain_data, inPtr, ACSP_DOMAIN_DATA_HDRSIZE); 1204 if ((domain = (acsp_domain*)malloc(sizeof(acsp_domain))) == 0) { 1205 error("ACSP plugin: no memory\n"); 1206 return -1; 1207 } 1208 domain_len = ntohs(domain_data.len); 1209 if ((domain->name = malloc(domain_len + 1)) == 0) { 1210 error("ACSP plugin: no memory\n"); 1211 free(domain); 1212 return -1; 1213 } 1214 domain->server.s_addr = domain_data.server; 1215 memcpy(domain->name, inPtr + ACSP_DOMAIN_DATA_HDRSIZE, domain_len); 1216 *(domain->name + domain_len) = 0; // zero terminate 1217 domain->next = (acsp_domain*)context->list; 1218 context->list = domain; 1219 len -= (domain_len + ACSP_DOMAIN_DATA_HDRSIZE); 1220 inPtr += (ACSP_DOMAIN_DATA_HDRSIZE + domain_len); 1221 } 1222 break; 1223 1224 default: 1225 return -1; 1226 break; 1227 } 1228 return 0; 1229} 1230 1231//------------------------------------------------------------ 1232// acsp_plugin_clear_list 1233// clear the route or domain list in the context 1234//------------------------------------------------------------ 1235static void acsp_plugin_clear_list(acsp_plugin_context* context) 1236{ 1237 void* temp = context->list; 1238 1239 while (temp) { 1240 if (context->type == CI_ROUTES) 1241 context->list = ((acsp_route*)temp)->next; 1242 else { 1243 free(((acsp_domain*)temp)->name); 1244 context->list = ((acsp_domain*)temp)->next; 1245 } 1246 free(temp); 1247 temp = context->list; 1248 } 1249} 1250 1251//------------------------------------------------------------ 1252// acsp_ip_up 1253// called when ipcp comes up 1254//------------------------------------------------------------ 1255static void acsp_plugin_ip_up(void *arg, uintptr_t phase) 1256{ 1257 acsp_plugin_context* context = (acsp_plugin_context*)arg; 1258 1259 context->ip_up = 1; 1260 if (context->mode == PLUGIN_MODE_RCV 1261 && context->state == PLUGIN_STATE_DONE 1262 && context->config_installed == 0) 1263 acsp_plugin_install_config(context); 1264 else 1265 notify(acspdhcpready_notifier, 0); 1266} 1267 1268//------------------------------------------------------------ 1269// acsp_ip_down 1270// called when ipcp goes down 1271//------------------------------------------------------------ 1272static void acsp_plugin_ip_down(void *arg, uintptr_t phase) 1273{ 1274 acsp_plugin_context* context = (acsp_plugin_context*)arg; 1275 1276 context->ip_up = 0; 1277 if (context->mode == PLUGIN_MODE_RCV && context->config_installed) 1278 acsp_plugin_remove_config(context); 1279 1280} 1281 1282//------------------------------------------------------------ 1283// acsp_install_config 1284// called do add the config for the option 1285// specified by the context 1286//------------------------------------------------------------ 1287static void acsp_plugin_install_config(acsp_plugin_context *context) 1288{ 1289 if (context->type == CI_ROUTES) 1290 acsp_plugin_add_routes(context->list); 1291 else 1292 acsp_plugin_add_domains(context->list); 1293 context->config_installed = 1; 1294 acsp_plugin_installed = true; 1295 1296 /* Signal that acsp info is ready */ 1297 notify(acspdhcpready_notifier, 0); 1298} 1299 1300//------------------------------------------------------------ 1301// acsp_remove_config 1302// called do remove the config for the option 1303// specified by the context 1304//------------------------------------------------------------ 1305static void acsp_plugin_remove_config(acsp_plugin_context *context) 1306{ 1307 // we don't remove anything - pppd will cleanup the dynamic store 1308 if (context->type == CI_ROUTES) 1309 acsp_plugin_remove_routes(context->list); 1310 acsp_plugin_installed = false; 1311 context->config_installed = 0; 1312} 1313 1314//------------------------------------------------------------ 1315// acsp_plugin_add_routes 1316// install routes 1317//------------------------------------------------------------ 1318static void acsp_plugin_add_routes(acsp_route *route) 1319{ 1320 char route_str[INET_ADDRSTRLEN]; 1321 char mask_str[INET_ADDRSTRLEN]; 1322 char gateway_str[INET_ADDRSTRLEN]; 1323 struct in_addr addr; 1324 int err; 1325 1326 if (route) { // only if routes are present 1327 sleep(1); 1328 addr.s_addr = 0; 1329 1330 // remove current default route 1331 cifdefaultroute(0, 0, 0); 1332 cifroute(); 1333#if 0 1334 if (route_gateway(RTM_DELETE, addr, addr, addr, 1) == 0) 1335 error("ACSP plugin: error removing default route\n"); 1336 // add new default route on previous primary interface 1337 if (route_gateway(RTM_ADD, addr, addr, primary_router, 1) == 0) { 1338 error("ACSP plugin: error adding default route\n"); 1339 return; 1340 } 1341#endif 1342 1343 while (route) { 1344 route->installed = 1; 1345 if (route->flags & ACSP_ROUTEFLAGS_PRIVATE) { 1346 if (route->address.s_addr == 0) 1347 sifdefaultroute(0, 0, 0); 1348 else { 1349 //if (route->router.s_addr) 1350 // err = route_gateway(RTM_ADD, route->address, route->mask, route->router, 1); 1351 //else 1352 err = route_interface(RTM_ADD, route->address, route->mask, IFT_PPP, ifname, 0); 1353 if (err == 0) { 1354 error("ACSP plugin: error installing private net route. (%s/%s).", 1355 addr2ascii(AF_INET, &route->address, sizeof(route->address), route_str), 1356 addr2ascii(AF_INET, &route->mask, sizeof(route->mask), mask_str)); 1357 route->installed = 0; 1358 } 1359 } 1360 } else if (route->flags & ACSP_ROUTEFLAGS_PUBLIC) { 1361 if (route->address.s_addr == 0) 1362 cifdefaultroute(0, 0, 0); 1363 else { 1364 if (route_gateway(RTM_ADD, route->address, route->mask, primary_router, 1) == 0) { 1365 error("ACSP plugin: error installing public net route. (%s/%s -> %s).", 1366 addr2ascii(AF_INET, &route->address, sizeof(route->address), route_str), 1367 addr2ascii(AF_INET, &route->mask, sizeof(route->mask), mask_str), 1368 addr2ascii(AF_INET, &primary_router, sizeof(primary_router), gateway_str)); 1369 route->installed = 0; 1370 } 1371 } 1372 } 1373 route = route->next; 1374 } 1375 } 1376} 1377 1378//------------------------------------------------------------ 1379// acsp_plugin_remove_routes 1380// remove routes 1381//------------------------------------------------------------ 1382static void acsp_plugin_remove_routes(acsp_route *route) 1383{ 1384 char route_str[INET_ADDRSTRLEN]; 1385 char mask_str[INET_ADDRSTRLEN]; 1386 char gateway_str[INET_ADDRSTRLEN]; 1387 1388 while (route) { 1389 if (route->installed) { 1390 route->installed = 0; 1391 if (route->flags & ACSP_ROUTEFLAGS_PRIVATE) { 1392 if (route->address.s_addr == 0) 1393 cifdefaultroute(0, 0, 0); 1394 else { 1395 if (route_interface(RTM_DELETE, route->address, route->mask, IFT_PPP, ifname, 0) == 0) { 1396 error("ACSP plugin: error removing private net route. (%s/%s).", 1397 addr2ascii(AF_INET, &route->address, sizeof(route->address), route_str), 1398 addr2ascii(AF_INET, &route->mask, sizeof(route->mask), mask_str)); 1399 route->installed = 1; 1400 } 1401 } 1402 } else if (route->flags & ACSP_ROUTEFLAGS_PUBLIC) { 1403 if (route->address.s_addr == 0) { 1404 // nothing to do 1405 } 1406 else { 1407 if (route_gateway(RTM_DELETE, route->address, route->mask, primary_router, 0) == 0) { 1408 error("ACSP plugin: error removing public net route. (%s/%s -> %s).", 1409 addr2ascii(AF_INET, &route->address, sizeof(route->address), route_str), 1410 addr2ascii(AF_INET, &route->mask, sizeof(route->mask), mask_str), 1411 addr2ascii(AF_INET, &primary_router, sizeof(primary_router), gateway_str)); 1412 route->installed = 1; 1413 } 1414 } 1415 } 1416 } 1417 route = route->next; 1418 } 1419} 1420 1421//------------------------------------------------------------ 1422// acsp_plugin_add_domains 1423// install search domains 1424//------------------------------------------------------------ 1425static void acsp_plugin_add_domains(acsp_domain *domain) 1426{ 1427 CFStringRef str; 1428 int err, clean = 1; 1429 long order = 100000; 1430 CFNumberRef num; 1431 1432 num = CFNumberCreate(NULL, kCFNumberLongType, &order); 1433 if (num == 0) { 1434 error("ACSP plugin: error adding domain name - could not create CFNumber\n"); 1435 return; 1436 } 1437 1438 while (domain) { 1439 if ((str = CFStringCreateWithCString(NULL, domain->name, kCFStringEncodingUTF8))) { 1440 err = publish_dns_wins_entry(kSCEntNetDNS, kSCPropNetDNSSearchDomains, str, 0, kSCPropNetDNSSupplementalMatchDomains, str, kSCPropNetDNSSupplementalMatchOrders, num, clean); 1441#ifndef kSCPropNetProxiesSupplementalMatchDomains 1442#define kSCPropNetProxiesSupplementalMatchDomains kSCPropNetDNSSupplementalMatchDomains 1443#define kSCPropNetProxiesSupplementalMatchOrders kSCPropNetDNSSupplementalMatchOrders 1444#endif 1445 if (err) publish_dns_wins_entry(kSCEntNetProxies, kSCPropNetProxiesSupplementalMatchDomains, str, 0, kSCPropNetProxiesSupplementalMatchOrders, num, 0, 0, clean); 1446 CFRelease(str); 1447 if (err == 0) { 1448 error("ACSP plugin: error adding domain name\n"); 1449 goto end; 1450 } 1451 } else { 1452 error("ACSP plugin: error adding domain name - could not create CFString\n"); 1453 goto end; 1454 } 1455 domain = domain->next; 1456 clean = 0; 1457 } 1458 1459end: 1460 CFRelease(num); 1461} 1462 1463#pragma - 1464 1465/* 1466 code to act as a DHCP client and server 1467*/ 1468 1469struct pseudo_udphdr { 1470 struct in_addr src_addr; /* source address */ 1471 struct in_addr dst_addr; /* source address */ 1472 u_int8_t zero; /* just zero */ 1473 u_int8_t proto; /* destination port */ 1474 u_int16_t len; /* packet len */ 1475}; 1476 1477struct dhcp { 1478 u_char dp_op; /* packet opcode type */ 1479 u_char dp_htype; /* hardware addr type */ 1480 u_char dp_hlen; /* hardware addr length */ 1481 u_char dp_hops; /* gateway hops */ 1482 u_int32_t dp_xid; /* transaction ID */ 1483 u_int16_t dp_secs; /* seconds since boot began */ 1484 u_int16_t dp_flags; /* flags */ 1485 struct in_addr dp_ciaddr; /* client IP address */ 1486 struct in_addr dp_yiaddr; /* 'your' IP address */ 1487 struct in_addr dp_siaddr; /* server IP address */ 1488 struct in_addr dp_giaddr; /* gateway IP address */ 1489 u_char dp_chaddr[16]; /* client hardware address */ 1490 u_char dp_sname[64]; /* server host name */ 1491 u_char dp_file[128]; /* boot file name */ 1492 u_char dp_options[0]; /* variable-length options field */ 1493}; 1494 1495struct dhcp_packet { 1496 struct ip ip; 1497 struct udphdr udp; 1498 struct dhcp dhcp; 1499}; 1500#define DHCP_COOKIE 0x63825363 1501 1502#define DHCP_OPTION_END 255 1503 1504#define DHCP_OPTION_LEASE_TIME 51 1505#define DHCP_OPTION_MSG_TYPE 53 1506#define DHCP_OPTION_HOST_NAME 12 1507#define DHCP_OPTION_SERVER_ID 54 1508#define DHCP_OPTION_PARAM_REQUEST_LIST 55 1509#define DHCP_OPTION_VENDOR_CLASS_ID 60 1510#define DHCP_OPTION_CLIENT_ID 61 1511 1512#define DHCP_OPTION_MSG_TYPE_ACK 5 1513#define DHCP_OPTION_MSG_TYPE_INFORM 8 1514 1515#define DHCP_OPTION_SUBNET_MASK 1 1516#define DHCP_OPTION_DNS 6 1517#define DHCP_OPTION_DOMAIN_NAME 15 1518#define DHCP_OPTION_WINS 43 1519#define DHCP_OPTION_NETBIOS 44 1520#define DHCP_OPTION_STATIC_ROUTE 249 1521 1522#define DHCP_TIMEOUT_VALUE 3 /* seconds */ 1523#define DHCP_MAX_RETRIES 4 1524 1525//------------------------------------------------------------ 1526// cksum 1527//------------------------------------------------------------ 1528static unsigned short 1529cksum(unsigned char *data, int len) 1530{ 1531 long sum = 0; 1532 1533 while (len > 1) { 1534 sum += *(ALIGNED_CAST(unsigned short *)data); 1535 data += sizeof(unsigned short); 1536 if (sum & 0x80000000) 1537 sum = (sum & 0xFFFF) + (sum >> 16); 1538 len -= 2; 1539 } 1540 if (len) 1541 sum += (unsigned short)*data; 1542 while (sum >> 16) 1543 sum = (sum & 0xFFFF) + (sum >> 16); 1544 1545 return ~sum; 1546} 1547 1548//------------------------------------------------------------ 1549// log_dhcp 1550//------------------------------------------------------------ 1551static void 1552log_dhcp(u_char *pkt, int len, char *text) 1553{ 1554#if 0 1555 u_char *p; 1556 int i; 1557 u_int32_t cookie; 1558 struct dhcp *dp; 1559 struct dhcp_packet *packet; 1560 u_int32_t masklen, addrlen, addr, mask; 1561 char str[2048]; 1562 char str2[16]; 1563 1564 /* log only if debug level is super verbose */ 1565 if (debug <= 1) 1566 return; 1567 1568 packet = (struct dhcp_packet *)pkt; 1569 dp = (struct dhcp *)&packet->dhcp; 1570 1571 dbglog("%s\n", text); 1572 dbglog(" op = %s\n", dp->dp_op == BOOTREQUEST ? "BOOTREQUEST" : dp->dp_op == BOOTREPLY ? "BOOTREPLY" : "UNKNOWN"); 1573 dbglog(" htype = %d\n", dp->dp_htype); 1574 dbglog(" hlen = %d\n", dp->dp_hlen); 1575 dbglog(" hops = %d\n", dp->dp_hops); 1576 dbglog(" xid = %d\n", dp->dp_xid); 1577 dbglog(" flags = %d\n", dp->dp_flags); 1578 dbglog(" client address = %s\n", inet_ntoa(dp->dp_ciaddr)); 1579 dbglog(" your address = %s\n", inet_ntoa(dp->dp_yiaddr)); 1580 dbglog(" server address = %s\n", inet_ntoa(dp->dp_siaddr)); 1581 dbglog(" gateway address = %s\n", inet_ntoa(dp->dp_giaddr)); 1582 1583 dbglog(" hardware address = %X:%X:%X:%X:%X:%X\n", dp->dp_chaddr[0], dp->dp_chaddr[1], dp->dp_chaddr[2], dp->dp_chaddr[3], dp->dp_chaddr[4], dp->dp_chaddr[5]); 1584 dbglog(" hardware address = %X:%X:%X:%X:%X:%X\n", dp->dp_chaddr[6], dp->dp_chaddr[7], dp->dp_chaddr[8], dp->dp_chaddr[9], dp->dp_chaddr[10], dp->dp_chaddr[11]); 1585 dbglog(" hardware address = %X:%X:%X:%X\n", dp->dp_chaddr[12], dp->dp_chaddr[13], dp->dp_chaddr[14], dp->dp_chaddr[15]); 1586 dbglog(" server host name = %s\n", dp->dp_sname); 1587 dbglog(" boot file name = %s\n", dp->dp_file); 1588 1589 p = dp->dp_options; 1590 cookie = ntohl(*(u_int32_t *)p); 1591 if (ntohl(*(u_int32_t *)p) != DHCP_COOKIE) { 1592 dbglog(" >>> incorrect cookie = %d.%d.%d.%d\n", cookie >> 24, cookie >> 16 & 0xFF, cookie >> 8 & 0xFF,cookie & 0xFF); 1593 return; 1594 } 1595 p+=4; 1596 1597 if (*p++ != DHCP_OPTION_MSG_TYPE || *p++ != 1 || (*p != DHCP_OPTION_MSG_TYPE_INFORM && *p != DHCP_OPTION_MSG_TYPE_ACK)) { 1598 dbglog(" >>> incorrect message type = %d\n", *p); 1599 return; 1600 } 1601 dbglog(" dhcp option msg type = %s\n", *p == DHCP_OPTION_MSG_TYPE_INFORM ? "INFORM" : "ACK"); 1602 p++; 1603 1604 len -= sizeof(struct dhcp_packet) + 7; 1605 while (*p != DHCP_OPTION_END && len > 0) { 1606 u_int8_t optcode, optlen; 1607 1608 optcode = *p++; 1609 // check for pad option 1610 if (optcode == 0) { 1611 len--; 1612 continue; 1613 } 1614 1615 optlen = *p++; 1616 len-=2; 1617 if (len == 0) { 1618 warning(">>> incorrect message option\n"); 1619 return; 1620 } 1621 1622 str[0] = 0; 1623 switch (optcode) { 1624 case DHCP_OPTION_HOST_NAME: 1625 memcpy(str, p, optlen); 1626 str[optlen] = 0; 1627 dbglog(" dhcp option host name = %s\n", str); 1628 break; 1629 case DHCP_OPTION_VENDOR_CLASS_ID: 1630 memcpy(str, p, optlen); 1631 str[optlen] = 0; 1632 dbglog(" dhcp option vendor class id = %s\n", str); 1633 break; 1634 case DHCP_OPTION_CLIENT_ID: 1635 for (i = 0; i < optlen; i++) { 1636 snprintf(str2, sizeof(str2), "0x%x ", p[i]); 1637 strlcat(str, str2, sizeof(str)); 1638 } 1639 dbglog(" dhcp option client id = %s\n", str); 1640 break; 1641 case DHCP_OPTION_SERVER_ID: 1642 for (i = 0; i < optlen; i++) { 1643 snprintf(str2, sizeof(str2), "0x%x ", p[i]); 1644 strlcat(str, str2, sizeof(str)); 1645 } 1646 dbglog(" dhcp option server id = %s\n", str); 1647 break; 1648 case DHCP_OPTION_LEASE_TIME: 1649 dbglog(" dhcp option lease time = %d\n", ntohl(*(u_int32_t*)p)); 1650 break; 1651 case DHCP_OPTION_SUBNET_MASK: 1652 dbglog(" dhcp option subnet mask = %d.%d.%d.%d\n", p[0], p[1], p[2], p[3]); 1653 break; 1654 case DHCP_OPTION_DOMAIN_NAME: 1655 memcpy(str, p, optlen); 1656 str[optlen] = 0; 1657 dbglog(" dhcp option domain name = %s\n", str); 1658 break; 1659 case DHCP_OPTION_STATIC_ROUTE: 1660 dbglog(" dhcp option parameter static routes = \n"); 1661 i = 0; 1662 while (i < optlen) { 1663 masklen = p[i]; 1664 mask = 0xFFFFFFFF << (32 - masklen); 1665 addrlen = (masklen / 8); 1666 if (masklen % 8) 1667 addrlen++; 1668 addr = ntohl(*(u_int32_t*)(&p[i+1])) & mask; 1669 router = ntohl(*(u_int32_t*)(&p[i+1+addrlen])); 1670 i += addrlen + 1 + sizeof(in_addr_t); 1671 dbglog(" route %d.%d.%d.%d mask %d.%d.%d.%d router %d.%d.%d.%d\n", 1672 (addr >> 24) & 0xFF, (addr >> 16) & 0xFF, (addr >> 8) & 0xFF, addr & 0xFF, 1673 (mask >> 24) & 0xFF, (mask >> 16) & 0xFF, (mask >> 8) & 0xFF, mask & 0xFF, 1674 (router >> 24) & 0xFF, (router >> 16) & 0xFF, (router >> 8) & 0xFF, router & 0xFF); 1675 } 1676/* 1677 for (i = 0; i < optlen; i++) { 1678 // UNSAFE! Don't use sprintf. 1679 sprintf(str+strlen(str), "0x%x ", p[i]); 1680 } 1681 dbglog(" dhcp option parameter static routes = %s \n", str); 1682*/ 1683 break; 1684 case DHCP_OPTION_PARAM_REQUEST_LIST: 1685 for (i = 0; i < optlen; i++) { 1686 snprintf(str2, sizeof(str2), "0x%x ", p[i]); 1687 strlcat(str, str2, sizeof(str)); 1688 } 1689 dbglog(" dhcp option parameter request list = %s \n", str); 1690 break; 1691 1692 default: 1693 dbglog(" dhcp option code = %d, len = %d\n", optcode, optlen); 1694 break; 1695 } 1696 1697 p+=optlen; 1698 len-=optlen; 1699 } 1700 dbglog(" end of options\n"); 1701#endif 1702} 1703 1704//------------------------------------------------------------ 1705// acsp_ipdata_send_packet 1706//------------------------------------------------------------ 1707static void 1708acsp_ipdata_send_packet(int unit, u_char *data, int len, u_int32_t srcaddr, u_int16_t srcport, u_int32_t dstaddr, u_int16_t dstport, char *text) 1709{ 1710 u_char *outp; 1711 u_int16_t checksum; 1712static u_int16_t dhcp_ip_id = 1; 1713 1714 // build a udp pseudo header for checksum calculation 1715 outp = data + PPP_HDRLEN + sizeof(struct ip) - sizeof(struct pseudo_udphdr); 1716 PUTLONG(srcaddr, outp); // source address 1717 PUTLONG(dstaddr, outp); // destination address 1718 PUTCHAR(0, outp); // zero 1719 PUTCHAR(IPPROTO_UDP, outp); // protocol 1720 PUTSHORT(len - PPP_HDRLEN - sizeof(struct ip), outp); // total length (udp data + udp header) 1721 1722 // build udp header 1723 outp = data + PPP_HDRLEN + sizeof(struct ip); 1724 PUTSHORT(srcport, outp); // source port 1725 PUTSHORT(dstport, outp); // dest port 1726 PUTSHORT(len - PPP_HDRLEN - sizeof(struct ip), outp); // total length (udp data + udp header) 1727 PUTSHORT(0, outp); // cksum 1728 checksum = cksum(data + PPP_HDRLEN + sizeof(struct ip) - sizeof(struct pseudo_udphdr), 1729 len - PPP_HDRLEN - sizeof(struct ip) + sizeof(struct pseudo_udphdr)); 1730 if (checksum == 0) 1731 checksum =0xffff; 1732 outp -= 2; // back to cksum 1733 PUTSHORT(0, outp); // cksum 1734 1735 // build ip header 1736 outp = data + PPP_HDRLEN; 1737 PUTSHORT(0x4500, outp); // hdr len and service type 1738 PUTSHORT(len - PPP_HDRLEN, outp); // total length 1739 PUTSHORT(dhcp_ip_id++, outp); // identification 1740 PUTSHORT(0, outp); // flags and fragment offset 1741 PUTCHAR(0x40, outp); // ttl 1742 PUTCHAR(IPPROTO_UDP, outp); // protocol 1743 PUTSHORT(0, outp); // cksum 1744 PUTLONG(srcaddr, outp); // source address 1745 PUTLONG(dstaddr, outp); // destination address 1746 checksum = cksum(data + PPP_HDRLEN, sizeof(struct ip)); 1747 outp -= 10; // back to cksum 1748 PUTSHORT(ntohs(checksum), outp); // header checksum 1749 1750 // log the packet 1751 log_dhcp(data + PPP_HDRLEN, len - PPP_HDRLEN, text); 1752 1753 // now it's time to send it... 1754 output(unit, data, len); 1755} 1756 1757//------------------------------------------------------------ 1758// acsp_ipdata_input_server 1759//------------------------------------------------------------ 1760static void 1761acsp_ipdata_input_server(int unit, u_char *pkt, int len, u_int32_t ouraddr, u_int32_t hisaddr) 1762{ 1763 struct dhcp_packet *dp; 1764 struct in_addr src; 1765 u_char *p, *outp; 1766 char str[2048]; 1767 int i, outlen, pad; 1768 int need_subnet_mask = 0, need_domain_name = 0, need_static_route = 0; 1769 struct dhcp reply; 1770 u_int32_t l; 1771 1772 dp = ALIGNED_CAST(struct dhcp_packet *)pkt; 1773 1774 /* basic length sanity check */ 1775 if (len < (sizeof(struct dhcp_packet) + 7)) { // dhcp packet + cookie + inform 1776 warning("DHCP packet received with incorrect length\n"); 1777 return; 1778 } 1779 1780 log_dhcp(pkt, len, "DHCP packet received"); 1781 1782 src.s_addr = dp->dhcp.dp_ciaddr.s_addr; 1783 1784 p = dp->dhcp.dp_options; 1785 GETLONG(l, p); 1786 if (l != DHCP_COOKIE) { 1787 warning("DHCP packet received with incorrect cookie\n"); 1788 return; 1789 } 1790 1791 if (*p++ != DHCP_OPTION_MSG_TYPE || *p++ != 1 || *p++ != DHCP_OPTION_MSG_TYPE_INFORM) { 1792 warning("DHCP packet received with incorrect message type\n"); 1793 return; 1794 } 1795 1796 len -= sizeof(struct dhcp_packet) + 7; 1797 while (*p != DHCP_OPTION_END && len > 0) { 1798 u_int8_t optcode, optlen; 1799 1800 optcode = *p++; 1801 // check for pad option 1802 if (optcode == 0) { 1803 len--; 1804 continue; 1805 } 1806 1807 optlen = *p++; 1808 len-=2; 1809 if (optlen >= len) { 1810 warning("DHCP packet received with incorrect message option\n"); 1811 return; 1812 } 1813 1814 str[0] = 0; 1815 switch (optcode) { 1816 case DHCP_OPTION_PARAM_REQUEST_LIST: 1817 for (i = 0; i < optlen; i++) { 1818 if ((p[i] == DHCP_OPTION_SUBNET_MASK) && subnet_mask) 1819 need_subnet_mask = 1; 1820 else if ((p[i] == DHCP_OPTION_DOMAIN_NAME) && domains_list) 1821 need_domain_name = 1; 1822 else if ((p[i] == DHCP_OPTION_STATIC_ROUTE) && routes_list) 1823 need_static_route = 1; 1824 } 1825 break; 1826 1827 default: 1828 break; 1829 } 1830 1831 p+=optlen; 1832 len-=optlen; 1833 } 1834 1835 /* build reply dhcp packet */ 1836 if (need_subnet_mask || need_domain_name || need_static_route) { 1837 1838 outp = outpacket_buf; 1839 1840 // ppp 1841 MAKEHEADER(outp, PPP_IP); 1842 outlen = PPP_HDRLEN; 1843 1844 // ip 1845 bzero(outp, sizeof(struct ip)); 1846 outp += sizeof(struct ip); 1847 outlen += sizeof(struct ip); 1848 1849 // udp 1850 bzero(outp, sizeof(struct udphdr)); 1851 outp += sizeof(struct udphdr); 1852 outlen += sizeof(struct udphdr); 1853 1854 // bootp 1855 memcpy(&reply, &dp->dhcp, sizeof(struct dhcp)); 1856 reply.dp_op = BOOTREPLY; 1857 reply.dp_htype = 1; 1858 reply.dp_secs = 0; 1859 memcpy(outp, &reply, sizeof(struct dhcp)); 1860 outlen += sizeof(struct dhcp); 1861 outp += sizeof(struct dhcp); 1862 1863 // dhcp options 1864 PUTLONG(DHCP_COOKIE, outp); // dhcp cookie 1865 outlen += 4; 1866 1867 PUTCHAR(DHCP_OPTION_MSG_TYPE, outp); // dhcp message type 1868 PUTCHAR(1, outp); // dhcp message type len 1869 PUTCHAR(DHCP_OPTION_MSG_TYPE_ACK, outp); // dhcp message type ack 1870 outlen += 3; 1871 1872 PUTCHAR(DHCP_OPTION_SERVER_ID, outp); // dhcp server id 1873 PUTCHAR(4, outp); // dhcp server id len 1874 l = ntohl(ouraddr); 1875 PUTLONG(l, outp); // server id is our source address 1876 outlen += 6; 1877 1878 if (need_subnet_mask) { 1879 PUTCHAR(DHCP_OPTION_SUBNET_MASK, outp); // dhcp subnet mask 1880 PUTCHAR(4, outp); // dhcp subnet mask len 1881 PUTLONG(subnet_mask, outp); // server mask 1882 outlen += 6; 1883 } 1884 1885 if (need_domain_name) { 1886 int len; 1887 acsp_domain *list = domains_list; 1888 // domain are reversed in the list use last one. 1889 while (list->next) list = list->next; 1890 1891 PUTCHAR(DHCP_OPTION_DOMAIN_NAME, outp); // dhcp domain name 1892 len = strlen(list->name); 1893 if (outlen + len + 2 >= sizeof(outpacket_buf)) { 1894 warning("Domain name too large for DHCP\n"); 1895 return; 1896 } 1897 PUTCHAR(len, outp); // domain name len 1898 memcpy(outp, list->name, len); // the domain 1899 outp += len; 1900 outlen += len + 2; 1901 } 1902 1903 if (need_static_route) { 1904 acsp_route *list = routes_list; 1905 u_int32_t mask, addr, masklen, addrlen, totlen = 0; 1906 int opdone = 0; 1907 1908 while (list) { 1909 if (list->flags & ACSP_ROUTEFLAGS_PRIVATE) { 1910 if (!opdone) { 1911 if (outlen + 2 >= sizeof(outpacket_buf)) { 1912 warning("No space for DHCP routes\n"); 1913 return; 1914 } 1915 PUTCHAR(DHCP_OPTION_STATIC_ROUTE, outp); // dhcp static route 1916 PUTCHAR(0, outp); // dhcp static route total len 1917 opdone = 1; 1918 } 1919 mask = ntohl(list->mask.s_addr); 1920 addr = ntohl(list->address.s_addr) & mask; 1921 1922 for ( masklen = 32; masklen && (mask& 1) == 0; mask = mask >> 1, masklen--); 1923 addrlen = (masklen / 8); 1924 if (masklen % 8) 1925 addrlen++; 1926 1927 if (outlen + addrlen + 1 + 4 >= sizeof(outpacket_buf)) { 1928 warning("Static routes list too large DHCP\n"); 1929 return; 1930 } 1931 PUTCHAR(masklen, outp); // route mask 1932 PUTLONG(addr, outp); // route address 1933 outp -= 4 - addrlen; // move pointer back according to addr len. 1934 l = ntohl(hisaddr); 1935 PUTLONG(l, outp); // router address 1936 totlen += addrlen + 1 + 4; 1937 } 1938 list = list->next; 1939 } 1940 if (opdone) { 1941 outp -= totlen + 1; 1942 PUTCHAR(totlen, outp); // move back to update option len 1943 outp += totlen; 1944 outlen += totlen + 2; 1945 } 1946 } 1947 1948 PUTCHAR(DHCP_OPTION_END, outp); // end of options 1949 outlen ++; 1950 1951 pad = outlen%4; 1952 for (i = 0; i < pad && outlen < sizeof(outpacket_buf); i++) { 1953 PUTCHAR(0, outp); // byte padding 1954 outlen ++; 1955 } 1956 1957 // build ip/udp header and send it... 1958 acsp_ipdata_send_packet(unit, outpacket_buf, outlen, ntohl(ouraddr), IPPORT_BOOTPS, ntohl(src.s_addr), IPPORT_BOOTPC, "DHCP packet replied"); 1959 } 1960} 1961 1962//------------------------------------------------------------ 1963// acsp_ipdata_input_client 1964//------------------------------------------------------------ 1965static void 1966acsp_ipdata_input_client(int unit, u_char *pkt, int len, u_int32_t ouraddr, u_int32_t hisaddr) 1967{ 1968 struct dhcp_packet *dp; 1969 struct in_addr src; 1970 u_char *p; 1971 u_int32_t masklen, addrlen, i, mask, l; 1972 char str[2048]; 1973 acsp_route *route; 1974 acsp_domain *domain_list = NULL, *domain; 1975 char *str_p, *tok, *delim; 1976 1977 dp = ALIGNED_CAST(struct dhcp_packet *)pkt; 1978 1979 /* basic length sanity check */ 1980 if (len < (sizeof(struct dhcp_packet) + 7)) { // dhcp packet + cookie + inform 1981 warning("DHCP packet received with incorrect length\n"); 1982 return; 1983 } 1984 1985 log_dhcp(pkt, len, "DHCP packet received"); 1986 1987 if (!dhcp_context) { 1988 // we didn't start DHCP or already closed it 1989 return; 1990 } 1991 1992 src.s_addr = ntohl(dp->dhcp.dp_ciaddr.s_addr); 1993 1994 p = dp->dhcp.dp_options; 1995 GETLONG(l, p); 1996 if (l != DHCP_COOKIE) { 1997 warning("DHCP packet received with incorrect cookie\n"); 1998 return; 1999 } 2000 2001 if (*p++ != DHCP_OPTION_MSG_TYPE || *p++ != 1 || *p++ != DHCP_OPTION_MSG_TYPE_ACK) { 2002 warning("DHCP packet received with incorrect message type\n"); 2003 return; 2004 } 2005 2006 len -= sizeof(struct dhcp_packet) + 7; 2007 while (*p != DHCP_OPTION_END && len > 0) { 2008 u_int8_t optcode, optlen; 2009 2010 optcode = *p++; 2011 // check for pad option 2012 if (optcode == 0) { 2013 len--; 2014 continue; 2015 } 2016 2017 optlen = *p++; 2018 len-=2; 2019 if (optlen >= len) { 2020 warning("DHCP packet received with incorrect message option\n"); 2021 return; 2022 } 2023 2024 switch (optcode) { 2025 case DHCP_OPTION_SUBNET_MASK: 2026 memcpy(&mask, p, sizeof(u_int32_t)); // Wcast-align fix - memcpy for unaligned access 2027 if (mask && 2028 dhcp_context->ouraddr.s_addr == ouraddr && 2029 dhcp_context->netmask.s_addr != mask) { 2030 dhcp_context->netmask.s_addr = mask; 2031 if (!uifaddr(unit, dhcp_context->ouraddr.s_addr, dhcp_context->hisaddr.s_addr, dhcp_context->netmask.s_addr)) { 2032 notice("failed to configure dhcp option 'subnet mask' = %d.%d.%d.%d, our %x, his %x\n", p[0], p[1], p[2], p[3], ntohl(dhcp_context->ouraddr.s_addr), ntohl(dhcp_context->hisaddr.s_addr)); 2033 } 2034 } else { 2035 info("ignoring dhcp option 'subnet mask' = %d.%d.%d.%d, current addr %x, current mask %x\n", p[0], p[1], p[2], p[3], ntohl(dhcp_context->ouraddr.s_addr), ntohl(dhcp_context->netmask.s_addr)); 2036 } 2037 break; 2038 case DHCP_OPTION_DOMAIN_NAME: 2039 2040 if (domain_list) { 2041 notice("ignoring dhcp option 'domain name', option already processed.\n"); 2042 break; 2043 } 2044 2045 memcpy(str, p, optlen); 2046 str[optlen] = 0; 2047 str_p = str; 2048 // check if domain is tokenized by a variety of delimiters 2049 GET_SPLITDNS_DELIM(str, delim); 2050 tok = strsep(&str_p, delim); 2051 do { 2052 if (!tok || *tok != '\0') { 2053 // tok may be NULL the first time through here. 2054 if((domain = (__typeof__(domain))malloc(sizeof(*domain))) == NULL) { 2055 error("failed to allocate domain from DHCP packet\n"); 2056 break; 2057 } 2058 bzero(domain, sizeof(*domain)); 2059 domain->next = domain_list; 2060 domain_list = domain; 2061 if (!tok) { 2062 domain->name = str; 2063 break; 2064 } else { 2065 domain->name = tok; 2066 } 2067 } 2068 tok = strsep(&str_p, delim); 2069 } while (tok != NULL); 2070 break; 2071 case DHCP_OPTION_STATIC_ROUTE: 2072 i = 0; 2073 while (i < optlen) { 2074 if ((route = (acsp_route*)malloc(sizeof(acsp_route))) == 0) { 2075 error("DHCP: no memory\n"); 2076 return; 2077 } 2078 2079 bzero(route, sizeof(acsp_route)); 2080 masklen = p[i]; 2081 route->mask.s_addr = htonl(0xFFFFFFFF << (32 - masklen)); 2082 addrlen = (masklen / 8); 2083 if (masklen % 8) 2084 addrlen++; 2085 2086 memcpy(&route->address.s_addr, &p[i+1], sizeof(route->address.s_addr)); // Wcast-align fix - memcpy for unaligned access 2087 route->address.s_addr &= route->mask.s_addr; 2088 memcpy(&route->router.s_addr, &p[i+1+addrlen], sizeof(route->router.s_addr)); 2089 route->flags = ACSP_ROUTEFLAGS_PRIVATE; 2090 route->installed = 0; 2091 route->next = (acsp_route*)dhcp_context->route; 2092 dhcp_context->route = route; 2093 i += addrlen + 1 + sizeof(in_addr_t); 2094 } 2095 acsp_plugin_add_routes(dhcp_context->route); 2096 break; 2097 2098 default: 2099 break; 2100 } 2101 2102 p+=optlen; 2103 len-=optlen; 2104 } 2105 2106 if (domain_list) { 2107 acsp_plugin_add_domains(domain_list); 2108 while (domain_list) { 2109 domain = domain_list; 2110 domain_list = domain_list->next; 2111 free(domain); 2112 } 2113 } 2114 2115 /* dhcp is done */ 2116 UNTIMEOUT(acsp_ipdata_timeout, dhcp_context); 2117 dhcp_context->state = PLUGIN_STATE_DONE; 2118 2119 /* Signal that dhcp info is ready */ 2120 notify(acspdhcpready_notifier, 0); 2121} 2122 2123//------------------------------------------------------------ 2124// acsp_ipdata_start_dhcp_client 2125//------------------------------------------------------------ 2126static void 2127acsp_ipdata_start_dhcp_client(int unit, u_int32_t ouraddr, u_int32_t hisaddr) 2128{ 2129 u_char *outp; 2130 int i, outlen, pad; 2131static u_int16_t dhcp_ip_client_xid = 1; 2132 u_int32_t l, clientid = 1; // ?? 2133 2134 outp = outpacket_buf; 2135 2136 // ppp 2137 MAKEHEADER(outp, PPP_IP); 2138 outlen = PPP_HDRLEN; 2139 2140 // ip 2141 bzero(outp, sizeof(struct ip)); 2142 outp += sizeof(struct ip); 2143 outlen += sizeof(struct ip); 2144 2145 // udp 2146 bzero(outp, sizeof(struct udphdr)); 2147 outp += sizeof(struct udphdr); 2148 outlen += sizeof(struct udphdr); 2149 2150 // bootp 2151 bzero(outp, sizeof(struct dhcp)); 2152 PUTCHAR(BOOTREQUEST, outp); // dp_op 2153 PUTCHAR(8, outp); // dp_htype 2154 PUTCHAR(6, outp); // dp_hlen 2155 PUTCHAR(0, outp); // dp_hops 2156 PUTLONG(dhcp_ip_client_xid++, outp); // dp_xid 2157 PUTSHORT(0, outp); // dp_secs 2158 PUTSHORT(0, outp); // dp_flags 2159 l = ntohl(ouraddr); 2160 PUTLONG(l, outp); // dp_ciaddr 2161 PUTLONG(0, outp); // dp_yiaddr 2162 PUTLONG(0, outp); // dp_siaddr 2163 PUTLONG(0, outp); // dp_giaddr 2164 PUTLONG(clientid, outp); // dp_chaddr[0..3] 2165 PUTLONG(0, outp); // dp_chaddr[4..7] 2166 PUTLONG(0, outp); // dp_chaddr[8..11] 2167 PUTLONG(1, outp); // dp_chaddr[12..15] 2168 outp += 64; // dp_sname 2169 outp += 128; // dp_file 2170 outlen += sizeof(struct dhcp); 2171 2172 // dhcp options 2173 PUTLONG(DHCP_COOKIE, outp); // dhcp cookie 2174 outlen += 4; 2175 2176 PUTCHAR(DHCP_OPTION_MSG_TYPE, outp); // dhcp message type 2177 PUTCHAR(1, outp); // dhcp message type len 2178 PUTCHAR(DHCP_OPTION_MSG_TYPE_INFORM, outp); // dhcp message type inform 2179 outlen += 3; 2180 2181 PUTCHAR(DHCP_OPTION_CLIENT_ID, outp); // dhcp client id 2182 PUTCHAR(7, outp); // dhcp client id len 2183 PUTCHAR(8, outp); // htype 2184 PUTLONG(clientid, outp); // client id 2185 PUTSHORT(0, outp); // client id end 2186 outlen += 9; 2187 2188 PUTCHAR(DHCP_OPTION_PARAM_REQUEST_LIST, outp); // dhcp param request list 2189 PUTCHAR(6, outp); // dhcp param request list len 2190 PUTCHAR(DHCP_OPTION_DNS, outp); 2191 PUTCHAR(DHCP_OPTION_NETBIOS, outp); 2192 PUTCHAR(DHCP_OPTION_WINS, outp); 2193 PUTCHAR(DHCP_OPTION_SUBNET_MASK, outp); 2194 PUTCHAR(DHCP_OPTION_STATIC_ROUTE, outp); 2195 PUTCHAR(DHCP_OPTION_DOMAIN_NAME, outp); 2196 outlen += 8; 2197 2198 PUTCHAR(DHCP_OPTION_END, outp); // end of options 2199 outlen ++; 2200 2201 pad = outlen%4; 2202 for (i = 0; i < pad && outlen < sizeof(outpacket_buf); i++) { 2203 PUTCHAR(0, outp); // byte padding 2204 outlen ++; 2205 } 2206 2207 // build ip/udp header and send it... 2208 acsp_ipdata_send_packet(unit, outpacket_buf, outlen, ntohl(ouraddr), IPPORT_BOOTPC, INADDR_BROADCAST, IPPORT_BOOTPS, "DHCP packet inform"); 2209 2210 dhcp_context->state = PLUGIN_SENDSTATE_WAITING_ACK; 2211 TIMEOUT(acsp_ipdata_timeout, dhcp_context, DHCP_TIMEOUT_VALUE); 2212} 2213 2214//------------------------------------------------------------ 2215// acsp_ipdata_input 2216//------------------------------------------------------------ 2217static void 2218acsp_ipdata_input(int unit, u_char *pkt, int len, u_int32_t ouraddr, u_int32_t hisaddr) 2219{ 2220 struct dhcp_packet *dp; 2221 2222 dp = ALIGNED_CAST(struct dhcp_packet *)pkt; 2223 2224 /* check if we received a DHCP broadcast from a client */ 2225 if (acsp_intercept_dhcp 2226 && ntohl(dp->ip.ip_dst.s_addr) == INADDR_BROADCAST 2227 && ntohs(dp->udp.uh_sport) == IPPORT_BOOTPC 2228 && ntohs(dp->udp.uh_dport) == IPPORT_BOOTPS) { 2229 acsp_ipdata_input_server(unit, pkt, len, ouraddr, hisaddr); 2230 return; 2231 } 2232 2233 /* check if we received a DHCP reply from a server */ 2234 if (acsp_use_dhcp 2235 && dp->ip.ip_dst.s_addr == ouraddr 2236 && ntohs(dp->udp.uh_sport) == IPPORT_BOOTPS 2237 && ntohs(dp->udp.uh_dport) == IPPORT_BOOTPC) { 2238 acsp_ipdata_input_client(unit, pkt, len, ouraddr, hisaddr); 2239 return; 2240 } 2241} 2242 2243#define DHCP_NOTIFY_STORE_ON_TIMEOUT_COUNT 2 2244//------------------------------------------------------------ 2245// acsp_ipdatre_timeout 2246//------------------------------------------------------------ 2247static void 2248acsp_ipdata_timeout(void *arg) 2249{ 2250 acsp_dhcp_context *context = (acsp_dhcp_context*)arg; 2251 2252 if (context->state == PLUGIN_SENDSTATE_WAITING_ACK) { 2253 if (context->retry_count++ < DHCP_MAX_RETRIES) 2254 acsp_ipdata_start_dhcp_client(context->unit, context->ouraddr.s_addr, context->hisaddr.s_addr); 2255 else { 2256 dbglog("No DHCP server replied\n"); 2257 context->state = PLUGIN_STATE_DONE; 2258 } 2259 2260 if (context->retry_count == DHCP_NOTIFY_STORE_ON_TIMEOUT_COUNT) { 2261 notify(acspdhcpready_notifier, 0); 2262 } 2263 } 2264} 2265 2266//------------------------------------------------------------ 2267// acsp_ipdata_up 2268//------------------------------------------------------------ 2269static void 2270acsp_ipdata_up(int unit, u_int32_t ouraddr, u_int32_t hisaddr) 2271{ 2272 2273 /* check if dhcp is enabled and acsp not running */ 2274 if (acsp_use_dhcp && (acscp_protent.state(unit) != OPENED)) { 2275 /* 2276 allocate dhcp routes context 2277 we don't need to keep a context for the domain 2278 */ 2279 if ((dhcp_context = (acsp_dhcp_context*)malloc(sizeof(acsp_dhcp_context))) == 0) { 2280 error("ACSP plugin: no memory to allocate DHCP routes context\n"); 2281 return; 2282 } 2283 bzero(dhcp_context, sizeof(acsp_dhcp_context)); 2284 dhcp_context->unit = unit; 2285 dhcp_context->ouraddr.s_addr = ouraddr; 2286 dhcp_context->hisaddr.s_addr = hisaddr; 2287 dhcp_context->state = PLUGIN_STATE_INITIAL; 2288 2289 /* start dhcp client */ 2290 acsp_ipdata_start_dhcp_client(unit, ouraddr, hisaddr); 2291 } 2292} 2293 2294//------------------------------------------------------------ 2295// acsp_ipdata_down 2296//------------------------------------------------------------ 2297static void 2298acsp_ipdata_down(int unit) 2299{ 2300 if (acsp_use_dhcp) { 2301 /* cleanup route */ 2302 if (dhcp_context) { 2303 acsp_plugin_remove_routes(dhcp_context->route); 2304 UNTIMEOUT(acsp_ipdata_timeout, dhcp_context); 2305 free(dhcp_context); 2306 dhcp_context = NULL; 2307 } 2308 2309 } 2310} 2311 2312//------------------------------------------------------------ 2313// acsp_ipdata_print 2314//------------------------------------------------------------ 2315static int 2316acsp_ipdata_print(pkt, plen, printer, arg) 2317 u_char *pkt; 2318 int plen; 2319 void (*printer) __P((void *, char *, ...)); 2320 void *arg; 2321{ 2322 u_char *p; 2323 int i, isbootp = 0, len = plen; 2324 struct dhcp *dp; 2325 struct dhcp_packet *packet; 2326 u_int32_t masklen, addrlen, addr, router, mask, l; 2327 char str[2048]; 2328 u_int32_t cookie; 2329 char str2[16]; 2330 2331 packet = ALIGNED_CAST(struct dhcp_packet *)pkt; 2332 2333 /* check if we received a DHCP broadcast from a client */ 2334 isbootp = 2335 (ntohs(packet->udp.uh_sport) == IPPORT_BOOTPC || ntohs(packet->udp.uh_sport) == IPPORT_BOOTPS) 2336 && (ntohs(packet->udp.uh_dport) == IPPORT_BOOTPS || ntohs(packet->udp.uh_dport) == IPPORT_BOOTPC); 2337 2338 if (!isbootp) 2339 return 0; 2340 2341 dp = (struct dhcp *)&packet->dhcp; 2342 2343 printer(arg, " <src addr %s>", inet_ntoa(packet->ip.ip_src)); 2344 printer(arg, " <dst addr %s>", inet_ntoa(packet->ip.ip_dst)); 2345 2346 if (dp->dp_op != BOOTREPLY && dp->dp_op != BOOTREQUEST) { 2347 printer(arg, " <bootp code invalid!>"); 2348 return 0; 2349 } 2350 2351 printer(arg, " <BOOTP %s>", dp->dp_op == BOOTREQUEST ? "Request" : "Reply"); 2352 2353 /* if superverbose debug, perform additional decoding onm the packet */ 2354 if (debug > 1) { 2355 printer(arg, " <htype %d>", dp->dp_htype); 2356 printer(arg, " <hlen %d>", dp->dp_hlen); 2357 printer(arg, " <hops %d>", dp->dp_hops); 2358 printer(arg, " <xid %d>", dp->dp_xid); 2359 printer(arg, " <flags %d>", dp->dp_flags); 2360 printer(arg, " <client address %s>", inet_ntoa(dp->dp_ciaddr)); 2361 printer(arg, " <your address %s>", inet_ntoa(dp->dp_yiaddr)); 2362 printer(arg, " <server address %s>", inet_ntoa(dp->dp_siaddr)); 2363 printer(arg, " <gateway address %s>", inet_ntoa(dp->dp_giaddr)); 2364 2365 p = &dp->dp_chaddr[0]; 2366 snprintf(str, sizeof(str), "%02x", p[0]); 2367 for (i = 1; i < 16; i++) { 2368 snprintf(str2, sizeof(str2), ":%02x", p[i]); 2369 strlcat(str, str2, sizeof(str)); 2370 } 2371 printer(arg, " <hardware address %s>", str); 2372 printer(arg, " <server host name \"%s\">", dp->dp_sname); 2373 printer(arg, " <boot file name \"%s\">", dp->dp_file); 2374 } 2375 2376 p = dp->dp_options; 2377 GETLONG(l, p); 2378 cookie = l; 2379 if (cookie != DHCP_COOKIE) { 2380 printer(arg, " <cookie invalid!>"); 2381 return 0; 2382 } 2383 if (debug > 1) 2384 printer(arg, " <cookie 0x%x>", DHCP_COOKIE); 2385 2386 if (*p++ != DHCP_OPTION_MSG_TYPE || *p++ != 1 || (*p != DHCP_OPTION_MSG_TYPE_INFORM && *p != DHCP_OPTION_MSG_TYPE_ACK)) { 2387 printer(arg, " <type invalid!>"); 2388 return 0; 2389 } 2390 2391 printer(arg, " <type %s>", *p == DHCP_OPTION_MSG_TYPE_INFORM ? "INFORM" : "ACK"); 2392 p++; 2393 2394 len = plen - sizeof(struct dhcp_packet) - 7; 2395 while (*p != DHCP_OPTION_END && len > 0) { 2396 u_int8_t optcode, optlen; 2397 2398 optcode = *p++; 2399 // check for pad option 2400 if (optcode == 0) { 2401 len--; 2402 continue; 2403 } 2404 2405 optlen = *p++; 2406 len-=2; 2407 if (len == 0) { 2408 printer(arg, " <option %d zero len!>", optcode); 2409 return 0; 2410 } 2411 2412 str[0] = 0; 2413 switch (optcode) { 2414 case DHCP_OPTION_HOST_NAME: 2415 memcpy(str, p, optlen); 2416 str[optlen] = 0; 2417 printer(arg, " <host name \"%s\">", str); 2418 break; 2419 case DHCP_OPTION_VENDOR_CLASS_ID: 2420 memcpy(str, p, optlen); 2421 str[optlen] = 0; 2422 printer(arg, " <vendor class id \"%s\">", str); 2423 break; 2424 case DHCP_OPTION_CLIENT_ID: 2425 snprintf(str, sizeof(str), "0x"); 2426 for (i = 0; i < optlen; i++) { 2427 snprintf(str2, sizeof(str2), "%02x", p[i]); 2428 strlcat(str, str2, sizeof(str)); 2429 } 2430 printer(arg, " <client id %s>", str); 2431 break; 2432 case DHCP_OPTION_SERVER_ID: 2433 snprintf(str, sizeof(str), "0x"); 2434 for (i = 0; i < optlen; i++) { 2435 snprintf(str2, sizeof(str2), "%02x", p[i]); 2436 strlcat(str, str2, sizeof(str)); 2437 } 2438 printer(arg, " <server id %s>", str); 2439 break; 2440 case DHCP_OPTION_LEASE_TIME: 2441 GETLONG(l, p); // Wcast-align fix - unaligned access 2442 printer(arg, " <lease time %d sec>", l); 2443 p -= 4; 2444 break; 2445 case DHCP_OPTION_SUBNET_MASK: 2446 printer(arg, " <subnet mask %d.%d.%d.%d>", p[0], p[1], p[2], p[3]); 2447 break; 2448 case DHCP_OPTION_DOMAIN_NAME: 2449 memcpy(str, p, optlen); 2450 str[optlen] = 0; 2451 printer(arg, " <domain name \"%s\">", str); 2452 break; 2453 case DHCP_OPTION_STATIC_ROUTE: 2454 printer(arg, " <static routes"); 2455 i = 0; 2456 while (i < optlen) { 2457 masklen = p[i]; 2458 mask = 0xFFFFFFFF << (32 - masklen); 2459 addrlen = (masklen / 8); 2460 if (masklen % 8) 2461 addrlen++; 2462 // Wcast-align fix - memcpy for unaligned access 2463 memcpy(&l, &p[i+1], sizeof(l)); 2464 addr = ntohl(l) & mask; 2465 memcpy(&l, &p[i+1+addrlen], sizeof(l)); 2466 router = ntohl(l); 2467 i += addrlen + 1 + sizeof(in_addr_t); 2468 printer(arg, " %d.%d.%d.%d/%d.%d.%d.%d/%d.%d.%d.%d", 2469 (addr >> 24) & 0xFF, (addr >> 16) & 0xFF, (addr >> 8) & 0xFF, addr & 0xFF, 2470 (mask >> 24) & 0xFF, (mask >> 16) & 0xFF, (mask >> 8) & 0xFF, mask & 0xFF, 2471 (router >> 24) & 0xFF, (router >> 16) & 0xFF, (router >> 8) & 0xFF, router & 0xFF); 2472 } 2473 printer(arg, ">"); 2474 break; 2475 case DHCP_OPTION_PARAM_REQUEST_LIST: 2476 for (i = 0; i < optlen; i++) { 2477 snprintf(str2, sizeof(str2), " 0x%x", p[i]); 2478 strlcat(str, str2, sizeof(str)); 2479 } 2480 printer(arg, " <parameters =%s>", str); 2481 break; 2482 2483 default: 2484 printer(arg, " <option %d>", optcode); 2485 break; 2486 } 2487 2488 p+=optlen; 2489 len-=optlen; 2490 } 2491 2492 /* if debug is superverbose, dump raw packet as well */ 2493 if (debug > 1) 2494 return 0; 2495 2496 return plen; 2497} 2498 2499int 2500acsp_printpkt(p, plen, printer, arg) 2501u_char *p; 2502int plen; 2503void (*printer) __P((void *, char *, ...)); 2504void *arg; 2505{ 2506 int len; 2507 u_int16_t flags; 2508 int slen; 2509 u_char *pstart = p; 2510 acsp_packet *pkt = ALIGNED_CAST(acsp_packet *)p; 2511 acsp_route_data *route_data; 2512 uint16_t route_flags; 2513 u_int8_t *ptr; 2514 acsp_domain_data domain_data_aligned; 2515 int domain_name_len; 2516 char addr_str[INET_ADDRSTRLEN]; 2517 char mask_str[INET_ADDRSTRLEN]; 2518 char domain_name[255 + 1]; // plus null-termination 2519 2520 if(pkt && plen >= ACSP_HDR_SIZE) { 2521 len = ntohs(pkt->len); 2522 if (len < ACSP_HDR_SIZE) 2523 len = 0; 2524 else 2525 len -= ACSP_HDR_SIZE; 2526 2527 flags = ntohs(pkt->flags); 2528 2529 if (pkt->type == CI_ROUTES) { 2530 route_data = ALIGNED_CAST(__typeof__(route_data))pkt->data; 2531 ACSP_PRINTPKT_PAYLOAD("CI_ROUTES"); 2532 while (len >= sizeof(*route_data)) { 2533 route_flags = ntohs(route_data->flags); 2534 printer(arg, "\n <route: address %s, mask %s, flags:%s%s>", 2535 addr2ascii(AF_INET, &route_data->address, sizeof(route_data->address), addr_str), 2536 addr2ascii(AF_INET, &route_data->mask, sizeof(route_data->mask), mask_str), 2537 ((route_flags & ACSP_ROUTEFLAGS_PRIVATE) != 0)? " PRIVATE" : "", 2538 ((route_flags & ACSP_ROUTEFLAGS_PUBLIC) != 0)? " PUBLIC" : ""); 2539 len -= sizeof(*route_data); 2540 route_data++; 2541 } 2542 p = (__typeof__(p))route_data; 2543 } else if (pkt->type == CI_DOMAINS) { 2544 ptr = pkt->data; 2545 ACSP_PRINTPKT_PAYLOAD("CI_DOMAINS"); 2546 while (len >= sizeof(acsp_domain_data)) { 2547 memcpy(&domain_data_aligned, ptr, sizeof(acsp_domain_data)); // Wcast-align fix - memcpy for unaligned move 2548 slen = ntohs(domain_data_aligned.len); 2549 domain_name_len = MIN(slen, sizeof(domain_name)); 2550 if (slen) { 2551 memcpy(domain_name, ((acsp_domain_data *)(void*)ptr)->name, domain_name_len); 2552 } 2553 domain_name[domain_name_len] = 0; 2554 if (domain_data_aligned.server) { 2555 printer(arg, "\n <domain: name %s, server %s>", 2556 domain_name, 2557 addr2ascii(AF_INET, &domain_data_aligned.server, sizeof(domain_data_aligned.server), addr_str)); 2558 } else { 2559 printer(arg, "\n <domain: name %s>", 2560 domain_name); 2561 } 2562 len -= (ACSP_DOMAIN_DATA_HDRSIZE + slen); 2563 ptr += (ACSP_DOMAIN_DATA_HDRSIZE + slen); 2564 } 2565 p = (__typeof__(p))ptr; 2566 } else { 2567 ACSP_PRINTPKT_PAYLOAD(NULL); 2568 p = pkt->data; 2569 } 2570 return (p - pstart); 2571 } 2572 return 0; 2573} 2574 2575