1/* 2 * Copyright (c) 2003 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 * sys-bsd.c - System-dependent procedures for setting up 25 * PPP interfaces on bsd-4.4-ish systems (including 386BSD, NetBSD, etc.) 26 * 27 * Copyright (c) 1989 Carnegie Mellon University. 28 * Copyright (c) 1995 The Australian National University. 29 * All rights reserved. 30 * 31 * Redistribution and use in source and binary forms are permitted 32 * provided that the above copyright notice and this paragraph are 33 * duplicated in all such forms and that any documentation, 34 * advertising materials, and other materials related to such 35 * distribution and use acknowledge that the software was developed 36 * by Carnegie Mellon University and The Australian National University. 37 * The names of the Universities may not be used to endorse or promote 38 * products derived from this software without specific prior written 39 * permission. 40 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 41 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 42 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 43 */ 44 45#define RCSID "$Id: sys-MacOSX.c,v 1.40 2006/02/16 01:47:04 lindak Exp $" 46 47/* ----------------------------------------------------------------------------- 48 Includes 49----------------------------------------------------------------------------- */ 50 51#include <stdio.h> 52#include <string.h> 53#include <stdlib.h> 54#include <unistd.h> 55#include <errno.h> 56#include <fcntl.h> 57#include <termios.h> 58#include <signal.h> 59#include <util.h> 60#include <sys/ioctl.h> 61#include <sys/types.h> 62#include <sys/socket.h> 63#include <sys/sockio.h> 64#include <sys/time.h> 65#include <sys/stat.h> 66#include <sys/param.h> 67#include <sys/wait.h> 68#include <sys/un.h> 69#include <sys/ucred.h> 70#import "acsp.h" 71#ifdef PPP_FILTER 72#include <net/bpf.h> 73#endif 74#include <net/if.h> 75#include <net/if_types.h> 76#include <mach-o/dyld.h> 77#include <dirent.h> 78#include <NSSystemDirectories.h> 79#include <mach/mach_time.h> 80#include <SystemConfiguration/SystemConfiguration.h> 81#include <SystemConfiguration/SCPrivate.h> 82#include <CoreFoundation/CFBundle.h> 83#include <ppp_defs.h> 84#include <ppp_domain.h> 85#include <ppp_msg.h> 86#include <ppp_privmsg.h> 87#include <if_ppp.h> 88#include <net/route.h> 89#include <net/if_dl.h> 90#include <netinet/in.h> 91#include <netinet/in_var.h> 92#include <netinet6/nd6.h> 93#include <netinet/if_ether.h> 94#include <syslog.h> 95#include <sys/un.h> 96#include <pthread.h> 97#include <notify.h> 98#include <IOKit/IOKitLib.h> 99#include <IOKit/network/IOEthernetInterface.h> 100#include <IOKit/network/IONetworkInterface.h> 101#include <IOKit/network/IOEthernetController.h> 102#include <servers/bootstrap.h> 103#include <arpa/inet.h> 104#include <bsm/libbsm.h> 105#include <ifaddrs.h> 106#include <netinet/ip.h> 107#include <netinet/ip_icmp.h> 108 109#include "pppcontroller.h" 110#include <ppp/pppcontroller_types.h> 111 112#include "../vpnd/RASSchemaDefinitions.h" 113 114 115#include "pppd.h" 116#include "fsm.h" 117#include "ipcp.h" 118#include "lcp.h" 119#include "eap.h" 120#include "../vpnd/RASSchemaDefinitions.h" 121 122#include "acscp.h" 123 124/* ----------------------------------------------------------------------------- 125 Definitions 126----------------------------------------------------------------------------- */ 127 128#define IP_FORMAT "%d.%d.%d.%d" 129#define IP_CH(ip) ((u_char *)(ip)) 130#define IP_LIST(ip) IP_CH(ip)[0],IP_CH(ip)[1],IP_CH(ip)[2],IP_CH(ip)[3] 131 132#define PPP_NKE_PATH "/System/Library/Extensions/PPP.kext" 133#define PPP_NKE_ID "com.apple.nke.ppp" 134 135/* We can get an EIO error on an ioctl if the modem has hung up */ 136#define ok_error(num) ((num)==EIO) 137 138#ifndef N_SYNC_PPP 139#define N_SYNC_PPP 14 140#endif 141 142/* 143 * If PPP_DRV_NAME is not defined, use the default "ppp" as the device name. 144 */ 145#if !defined(PPP_DRV_NAME) 146#define PPP_DRV_NAME "ppp" 147#endif /* !defined(PPP_DRV_NAME) */ 148 149/* ----------------------------------------------------------------------------- 150 Forward declarations 151----------------------------------------------------------------------------- */ 152 153static int get_flags (int fd); 154static void set_flags (int fd, int flags); 155static int set_kdebugflag(int level); 156static int make_ppp_unit(void); 157/* Prototypes for procedures local to this file. */ 158static int get_ether_addr __P((u_int32_t, struct sockaddr_dl *)); 159static int connect_pfppp(); 160//static void sys_pidchange(void *arg, int pid); 161static void sys_phasechange(void *arg, uintptr_t phase); 162static void sys_exitnotify(void *arg, uintptr_t exitcode); 163int publish_keyentry(CFStringRef key, CFStringRef entry, CFTypeRef value); 164int publish_dictnumentry(CFStringRef dict, CFStringRef entry, int val); 165int publish_dictstrentry(CFStringRef dict, CFStringRef entry, char *str, int encoding); 166int unpublish_keyentry(CFStringRef key, CFStringRef entry); 167int unpublish_dict(CFStringRef dict); 168int publish_dns_wins_entry(CFStringRef entity, CFStringRef property1, CFTypeRef ref1, CFTypeRef ref1a, 169 CFStringRef property2, CFTypeRef ref2, 170 CFStringRef property3, CFTypeRef ref3, int clean); 171int unpublish_dictentry(CFStringRef dict, CFStringRef entry); 172static void sys_eventnotify(void *param, uintptr_t code); 173static void sys_timeremaining(void *param, uintptr_t info); 174static void sys_authpeersuccessnotify(void *param, uintptr_t info); 175static int update_stateaddr(u_int32_t o, u_int32_t h, u_int32_t m); 176int publish_stateaddr(u_int32_t o, u_int32_t h, u_int32_t m); 177int route_interface(int cmd, struct in_addr host, struct in_addr mask, char iftype, char *ifname, int is_host); 178int route_gateway(int cmd, struct in_addr dest, struct in_addr mask, struct in_addr gateway, int use_gway_flag); 179static void ppp_ip_probe_timeout (void *arg); 180static void republish_dict(); 181static int commit_publish_dict(); 182 183/* ----------------------------------------------------------------------------- 184 Globals 185----------------------------------------------------------------------------- */ 186#ifndef lint 187static const char rcsid[] = RCSID; 188#endif 189 190static int ttydisc = TTYDISC; /* The default tty discipline */ 191static int pppdisc = PPPDISC; /* The PPP sync or async discipline */ 192 193static int initfdflags = -1; /* Initial file descriptor flags for ppp_fd */ 194static int ppp_fd = -1; /* fd which is set to PPP discipline */ 195static int rtm_seq; 196 197static int restore_term; /* 1 => we've munged the terminal */ 198static struct termios inittermios; /* Initial TTY termios */ 199static struct winsize wsinfo; /* Initial window size info */ 200 201static int ip_sockfd; /* socket for doing interface ioctls */ 202 203static fd_set in_fds; /* set of fds that wait_input waits for */ 204static fd_set ready_fds; /* set of fds currently ready (out of select) */ 205static int max_in_fd; /* highest fd set in in_fds */ 206 207static int if_is_up; /* the interface is currently up */ 208static int ipv4_plumbed = 0; /* is ipv4 plumbed on the interface ? */ 209static u_int32_t ifaddrs[2]; /* local and remote addresses we set */ 210static u_int32_t default_route_gateway; /* gateway addr for default route */ 211static u_int32_t proxy_arp_addr; /* remote addr for proxy arp */ 212SCDynamicStoreRef cfgCache = 0; /* configd session */ 213CFRunLoopSourceRef rls = 0; /* runloop source */ 214CFStringRef serviceidRef = 0; /* service id ref */ 215CFStringRef serveridRef = 0; /* server id ref */ 216 217extern u_char inpacket_buf[]; /* borrowed from main.c */ 218 219static u_int32_t connecttime; /* time when connection occured */ 220int looped; /* 1 if using loop */ 221int ppp_sockfd = -1; /* fd for PF_PPP socket */ 222char *serviceid = NULL; /* configuration service ID to publish */ 223char *serverid = NULL; /* server ID that spwaned this service */ 224static CFStringRef server_peer = NULL; /* remote peer address for server */ 225static char *network_signature = NULL; /* network signature */ 226bool noload = 0; /* don't load the kernel extension */ 227bool looplocal = 0; /* Don't loop local traffic destined to the local address some applications rely on this default behavior */ 228bool addifroute = 0; /* install route for the netmask of the interface */ 229bool noipv6override = 0; /* don't override IPv6 traffic if IPv4 is primary */ 230 231static struct in_addr ifroute_address; 232static struct in_addr ifroute_mask; 233static int ifroute_installed = 0; 234 235double timeScaleSeconds; /* scale factor for machine absolute time to seconds */ 236double timeScaleMicroSeconds; /* scale factor for machine absolute time to microseconds */ 237 238CFPropertyListRef userOptions = NULL; 239CFPropertyListRef systemOptions = NULL; 240 241CFMutableDictionaryRef publish_dict = NULL; 242 243option_t sys_options[] = { 244 { "serviceid", o_string, &serviceid, 245 "Service ID to publish"}, 246 { "serverid", o_string, &serverid, 247 "Server ID that spawned this service."}, 248 { "nopppload", o_bool, &noload, 249 "Don't try to load PPP NKE", 1}, 250 { "looplocal", o_bool, &looplocal, 251 "Loop local traffic destined to the local address", 1}, 252 { "noifroute", o_bool, &addifroute, 253 "Don't install route for the interface", 0}, 254 { "addifroute", o_bool, &addifroute, 255 "Install route for the interface", 1}, 256 { "nolooplocal", o_bool, &looplocal, 257 "Don't loop local traffic destined to the local address", 0}, 258 { "noipv6override", o_bool, &noipv6override, 259 "Don't override other IPv6 interfaces if ppp is default for IPv4", 1}, 260 { NULL } 261}; 262 263ppp_session_t *session = NULL; 264static int ppp_auxiliary_probe_echos_pending = 0; 265static int ppp_auxiliary_probe_success = 0; 266static int ppp_auxiliary_probe_ip_notify_init = 0; 267static int ppp_auxiliary_probe_ip = 0; 268 269static int override_primary = 0; 270static int wait_port_mapping_changed = 0; 271 272extern int kill_link; 273 274extern bool acsp_use_dhcp; // To check if we need to wait for DHCP information 275/* These booleans are meant to be set when the notifiers respond. */ 276static bool protocols_ready = false; 277static bool acspdhcp_ready = false; 278 279/* ----------------------------------------------------------------------------- 280----------------------------------------------------------------------------- */ 281void closeall() 282{ 283 int i; 284 285 for (i = getdtablesize() - 1; i >= 0; i--) close(i); 286 open("/dev/null", O_RDWR, 0); 287 dup(0); 288 dup(0); 289 return; 290} 291 292/* ----------------------------------------------------------------------------- 293close all file descriptor above 'from' 294----------------------------------------------------------------------------- */ 295void closeallfrom(int from) 296{ 297 int fd; 298 struct dirent entry, *entryp; 299 300 DIR *dirp = opendir("/dev/fd"); 301 if (dirp == NULL) { 302 /* perhaps fall back on getdtablesize method */ ; 303 for (fd = from; fd < getdtablesize(); ++fd) close(fd); 304 return; 305 } 306 307 while (readdir_r(dirp, &entry, &entryp) == 0 && entryp != NULL) { 308 fd = atoi(entryp->d_name); 309 if (fd >= from && fd != dirp->__dd_fd) 310 close(fd); 311 } 312 closedir(dirp); 313} 314 315/* ----------------------------------------------------------------------------- 316----------------------------------------------------------------------------- */ 317u_long load_kext(char *kext, int byBundleID) 318{ 319 int pid; 320 321 if ((pid = fork()) < 0) 322 return 1; 323 324 if (pid == 0) { 325 closeall(); 326 // PPP kernel extension not loaded, try load it... 327 if (byBundleID) 328 execle("/sbin/kextload", "kextload", "-b", kext, (char *)0, (char *)0); 329 else 330 execle("/sbin/kextload", "kextload", kext, (char *)0, (char *)0); 331 exit(1); 332 } 333 334 while (waitpid(pid, 0, 0) < 0) { 335 if (errno == EINTR) 336 continue; 337 return 1; 338 } 339 return 0; 340} 341 342/* ----------------------------------------------------------------------------- 343preinitialize options, called before sysinit 344----------------------------------------------------------------------------- */ 345void sys_install_options() 346{ 347 add_options(sys_options); 348} 349 350/* ----------------------------------------------------------------------------- 351----------------------------------------------------------------------------- */ 352int sys_check_controller() 353{ 354 mach_port_t server; 355 kern_return_t status; 356 int result; 357 audit_token_t audit_token; 358 uid_t euid; 359 360 status = bootstrap_look_up(bootstrap_port, PPPCONTROLLER_SERVER_PRIV, &server); 361 switch (status) { 362 case BOOTSTRAP_SUCCESS : 363 /* service currently registered, "a good thing" (tm) */ 364 break; 365 case BOOTSTRAP_UNKNOWN_SERVICE : 366 /* service not currently registered, try again later */ 367 return 0; 368 default : 369 return 0; 370 } 371 372 status = pppcontroller_iscontrolled(server, &result, &audit_token); 373 374 if (status == KERN_SUCCESS) { 375 audit_token_to_au32(audit_token, 376 NULL, // auidp 377 &euid, // euid 378 NULL, // egid 379 NULL, // ruid 380 NULL, // rgid 381 NULL, // pid 382 NULL, // asid 383 NULL); // tid 384 385 return ((result == kSCStatusOK) && (euid == 0)); 386 } 387 388 return 0; 389} 390 391/* ------------------------------------------------------------------------------------------- 392------------------------------------------------------------------------------------------- */ 393CFPropertyListRef Unserialize(void *data, u_int32_t dataLen) 394{ 395 CFDataRef xml; 396 CFPropertyListRef ref = 0; 397 398 xml = CFDataCreate(NULL, data, dataLen); 399 if (xml) { 400 ref = CFPropertyListCreateFromXMLData(NULL, 401 xml, kCFPropertyListImmutable, NULL); 402 CFRelease(xml); 403 } 404 405 return ref; 406} 407 408/* ----------------------------------------------------------------------------- 409----------------------------------------------------------------------------- */ 410void CopyControllerData() 411{ 412 mach_port_t server; 413 kern_return_t status; 414 void *data = NULL; 415 unsigned int datalen; 416 int result = kSCStatusFailed; 417 audit_token_t audit_token; 418 uid_t euid; 419 420 status = bootstrap_look_up(bootstrap_port, PPPCONTROLLER_SERVER_PRIV, &server); 421 switch (status) { 422 case BOOTSTRAP_SUCCESS : 423 /* service currently registered, "a good thing" (tm) */ 424 break; 425 case BOOTSTRAP_UNKNOWN_SERVICE : 426 /* service not currently registered, try again later */ 427 return ; 428 default : 429 return; 430 } 431 432 status = pppcontroller_copyprivoptions(server, 0, (xmlDataOut_t *)&data, &datalen, &result, &audit_token); 433 434 if (status != KERN_SUCCESS 435 || result != kSCStatusOK) { 436 error("cannot get private system options from controller\n"); 437 return; 438 } 439 audit_token_to_au32(audit_token, 440 NULL, // auidp 441 &euid, // euid 442 NULL, // egid 443 NULL, // ruid 444 NULL, // rgid 445 NULL, // pid 446 NULL, // asid 447 NULL); // tid 448 if (euid != 0) { 449 error("cannot authenticate private system options from controller\n"); 450 return; 451 } 452 453 systemOptions = Unserialize(data, datalen); 454 455 status = pppcontroller_copyprivoptions(server, 1, (xmlDataOut_t *)&data, &datalen, &result, &audit_token); 456 457 if (status != KERN_SUCCESS 458 || result != kSCStatusOK) { 459 error("cannot get private user options from controller\n"); 460 return; 461 } 462 audit_token_to_au32(audit_token, 463 NULL, // auidp 464 &euid, // euid 465 NULL, // egid 466 NULL, // ruid 467 NULL, // rgid 468 NULL, // pid 469 NULL, // asid 470 NULL); // tid 471 if (euid != 0) { 472 error("cannot authenticate private user options from controller\n"); 473 return; 474 } 475 476 userOptions = Unserialize(data, datalen); 477} 478 479/* ----------------------------------------------------------------------------- 480----------------------------------------------------------------------------- */ 481void CopyServerData() 482{ 483 SCPreferencesRef prefs = 0; 484 CFPropertyListRef servers_list; 485 486 // open the prefs file 487 prefs = SCPreferencesCreate(0, CFSTR("pppd"), kRASServerPrefsFileName); 488 if (prefs == NULL) { 489 fatal("Cannot open servers plist\n"); 490 return; 491 } 492 493 // get servers list from the plist 494 servers_list = SCPreferencesGetValue(prefs, kRASServers); 495 if (servers_list == NULL) { 496 fatal("No servers found in servers plist\n"); 497 CFRelease(prefs); 498 return; 499 } 500 501 systemOptions = CFDictionaryGetValue(servers_list, serveridRef); 502 if (!systemOptions || CFGetTypeID(systemOptions) != CFDictionaryGetTypeID()) { 503 fatal("Server ID '%s' not found in servers plist\n", serverid); 504 systemOptions = 0; 505 CFRelease(prefs); 506 return; 507 } 508 509 CFRetain(systemOptions); 510 CFRelease(prefs); 511} 512 513/* ----------------------------------------------------------------------------- 514 ----------------------------------------------------------------------------- */ 515void sys_protocolsreadynotify(void *param, uintptr_t info) 516{ 517 protocols_ready = true; 518 dbglog("Received protocol dictionaries\n"); 519 commit_publish_dict(); 520} 521 522/* ----------------------------------------------------------------------------- 523 ----------------------------------------------------------------------------- */ 524void sys_acspdhcpreadynotify(void *param, uintptr_t info) 525{ 526 acspdhcp_ready = true; 527 dbglog("Received acsp/dhcp dictionaries\n"); 528 commit_publish_dict(); 529} 530 531/************************************************************************** 532 To be called whenever we are potentially ready to update system config. 533 Particularly, these times are: 534 - Move into RUNNING state 535 - Receive DHCP or ACSP info 536 - Republish dictionary 537*************************************************************************/ 538static int commit_publish_dict() 539{ 540 /* Only publish one-at-a-time for demand mode */ 541 if (demand) { 542 goto fail; 543 } 544 545 /* Check if we are RUNNING, there are NO WAITING protocols, and NO WAITING DHCP info */ 546 int result = 1; 547 548 /* Make sure we're RUNNING */ 549 if (phase != PHASE_RUNNING) { 550 goto fail; 551 } 552 553 /* Make sure all protocols ready */ 554 if (!protocols_ready) { 555 goto fail; 556 } 557 558 /* Make sure all DHCP info acquired */ 559 if ((acsp_use_dhcp || acscp_protent.enabled_flag) && !acspdhcp_ready) { 560 goto fail; 561 } 562 563 /* Publish! */ 564 if (publish_dict) { 565 notice("Committed PPP store\n"); 566 if (!SCDynamicStoreSetMultiple(cfgCache, publish_dict, NULL, NULL)) 567 result = 0; 568 } 569 570 return result; 571 572fail: 573 return 0; 574} 575 576/* ----------------------------------------------------------------------------- 577 Change dictionary to be published 578 ----------------------------------------------------------------------------- */ 579static int update_publish_dict(CFStringRef key, CFMutableDictionaryRef dict) 580{ 581 int result = 1; 582 583 if (demand) { 584 if (SCDynamicStoreSetValue(cfgCache, key, dict) == 0) 585 result = 0; 586 } 587 588 if (publish_dict) { 589 CFDictionarySetValue(publish_dict, key, dict); 590 } else { 591 result = 0; 592 } 593 594 return result; 595} 596 597/* ----------------------------------------------------------------------------- 598System-dependent initialization 599----------------------------------------------------------------------------- */ 600void sys_init() 601{ 602 int flags; 603 mach_timebase_info_data_t timebaseInfo; 604 605 openlog("pppd", LOG_PID | LOG_NDELAY, LOG_PPP); 606 setlogmask(LOG_UPTO(LOG_INFO)); 607 if (debug) 608 setlogmask(LOG_UPTO(LOG_DEBUG)); 609 610 // establish pppd as session leader 611 // if started via terminal, setsid will fail, which doesn't matter 612 // if started via configd, setsid will succeed and will allow reception of SIGHUP 613 setsid(); 614 615 // open a socket to the PF_PPP protocol 616 ppp_sockfd = connect_pfppp(); 617 if (ppp_sockfd < 0) 618 fatal("Couldn't open PF_PPP: %m"); 619 620 flags = fcntl(ppp_sockfd, F_GETFL); 621 if (flags == -1 622 || fcntl(ppp_sockfd, F_SETFL, flags | O_NONBLOCK) == -1) 623 warning("Couldn't set PF_PPP to nonblock: %m"); 624 625 // Get an internet socket for doing socket ioctls 626 ip_sockfd = socket(AF_INET, SOCK_DGRAM, 0); 627 if (ip_sockfd < 0) 628 fatal("Couldn't create IP socket: %m(%d)", errno); 629 630 // serviceid is required if we want pppd to publish information into the cache 631 if (!serviceid) { 632 CFUUIDRef uuid; 633 CFStringRef strref; 634 char str[100]; 635 636 uuid = CFUUIDCreate(NULL); 637 strref = CFUUIDCreateString(NULL, uuid); 638 CFStringGetCString(strref, str, sizeof(str), kCFStringEncodingUTF8); 639 640 if ((serviceid = strdup(str)) == NULL) 641 fatal("Couldn't allocate memory to create temporary service id: %m(%d)", errno); 642 643 CFRelease(strref); 644 CFRelease(uuid); 645 } 646 647 serviceidRef = CFStringCreateWithFormat(NULL, NULL, CFSTR("%s"), serviceid); 648 if (!serviceidRef) 649 fatal("Couldn't allocate memory to create service id reference: %m(%d)", errno); 650 651 /* if started as a client by PPPController 652 copy user and system options from the controller */ 653 if (controlled) { 654 CopyControllerData(); 655 } 656 657 //sys_pidchange(0, getpid()); 658 cfgCache = SCDynamicStoreCreate(0, CFSTR("pppd"), 0, 0); 659 if (cfgCache == 0) 660 fatal("SCDynamicStoreCreate failed: %s", SCErrorString(SCError())); 661 // if we are going to detach, wait to publish pid 662 if (nodetach) 663 publish_dictnumentry(kSCEntNetPPP, CFSTR("pid"), getpid()); 664 665 publish_dictnumentry(kSCEntNetPPP, kSCPropNetPPPStatus, phase); 666 if (serverid) { 667 serveridRef = CFStringCreateWithFormat(NULL, NULL, CFSTR("%s"), serverid); 668 if (!serveridRef) 669 fatal("Couldn't allocate memory to create server id reference: %m(%d)", errno); 670 /* copy system options from the server plist */ 671 CopyServerData(); 672 publish_dictstrentry(kSCEntNetInterface, CFSTR("ServerID"), serverid, kCFStringEncodingMacRoman); 673 } 674 675 publish_dict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); 676 if (!controlled && publish_dict){ 677 rls = SCDynamicStoreCreateRunLoopSource(kCFAllocatorDefault, cfgCache, 0); 678 if ( rls == NULL ){ 679 notice("SCDynamicStoreCreateRunLoopSource FAILED %s", SCErrorString(SCError())); 680 } else { 681 CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode); 682 } 683 SCDynamicStoreSetDisconnectCallBack(cfgCache, republish_dict); 684 } 685 686 687 //add_notifier(&pidchange, sys_pidchange, 0); 688 add_notifier(&phasechange, sys_phasechange, 0); 689 add_notifier(&exitnotify, sys_exitnotify, 0); 690 691 // only send event if started when we are started by the PPPController 692 if (statusfd != -1) { 693 694 add_notifier(&ip_up_notify, sys_eventnotify, (void*)PPP_EVT_IPCP_UP); 695 add_notifier(&ip_down_notify, sys_eventnotify, (void*)PPP_EVT_IPCP_DOWN); 696 add_notifier(&lcp_up_notify, sys_eventnotify, (void*)PPP_EVT_LCP_UP); 697 add_notifier(&lcp_down_notify, sys_eventnotify, (void*)PPP_EVT_LCP_DOWN); 698 add_notifier(&lcp_lowerup_notify, sys_eventnotify, (void*)PPP_EVT_LOWERLAYER_UP); 699 add_notifier(&lcp_lowerdown_notify, sys_eventnotify, (void*)PPP_EVT_LOWERLAYER_DOWN); 700 add_notifier(&auth_start_notify, sys_eventnotify, (void*)PPP_EVT_AUTH_STARTED); 701 add_notifier(&auth_withpeer_fail_notify, sys_eventnotify, (void*)PPP_EVT_AUTH_FAILED); 702 add_notifier(&auth_withpeer_success_notify, sys_eventnotify, (void*)PPP_EVT_AUTH_SUCCEDED); 703 add_notifier(&connectscript_started_notify, sys_eventnotify, (void*)PPP_EVT_CONNSCRIPT_STARTED); 704 add_notifier(&connectscript_finished_notify, sys_eventnotify, (void*)PPP_EVT_CONNSCRIPT_FINISHED); 705 add_notifier(&terminalscript_started_notify, sys_eventnotify, (void*)PPP_EVT_TERMSCRIPT_STARTED); 706 add_notifier(&terminalscript_finished_notify, sys_eventnotify, (void*)PPP_EVT_TERMSCRIPT_FINISHED); 707 add_notifier(&connect_started_notify, sys_eventnotify, (void*)PPP_EVT_CONN_STARTED); 708 add_notifier(&connect_success_notify, sys_eventnotify, (void*)PPP_EVT_CONN_SUCCEDED); 709 add_notifier(&connect_fail_notify, sys_eventnotify, (void*)PPP_EVT_CONN_FAILED); 710 add_notifier(&disconnect_started_notify, sys_eventnotify, (void*)PPP_EVT_DISC_STARTED); 711 add_notifier(&disconnect_done_notify, sys_eventnotify, (void*)PPP_EVT_DISC_FINISHED); 712 add_notifier(&stop_notify, sys_eventnotify, (void*)PPP_EVT_STOPPED); 713 add_notifier(&cont_notify, sys_eventnotify, (void*)PPP_EVT_CONTINUED); 714 } 715 716 add_notifier(&lcp_timeremaining_notify, sys_timeremaining, 0); 717 add_notifier(&auth_peer_success_notify, sys_authpeersuccessnotify, 0); 718 719 add_notifier(&protocolsready_notifier, sys_protocolsreadynotify, 0); 720 add_notifier(&acspdhcpready_notifier, sys_acspdhcpreadynotify, 0); 721 722 if (mach_timebase_info(&timebaseInfo) == KERN_SUCCESS) { // returns scale factor for ns 723 timeScaleMicroSeconds = ((double) timebaseInfo.numer / (double) timebaseInfo.denom) / 1000; 724 timeScaleSeconds = timeScaleMicroSeconds / 1000000; 725 } 726 727 FD_ZERO(&in_fds); 728 FD_ZERO(&ready_fds); 729 max_in_fd = 0; 730} 731 732/* ----------------------------------------------------------------------------- 733 sys_cleanup - restore any system state we modified before exiting: 734 mark the interface down, delete default route and/or proxy arp entry. 735 This should call die() because it's called from die() 736----------------------------------------------------------------------------- */ 737void sys_cleanup() 738{ 739 struct ifreq ifr; 740 741 if (!controlled && rls) { 742 CFRunLoopRemoveSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode); 743 CFRunLoopSourceInvalidate(rls); 744 CFRelease(rls); 745 rls = NULL; 746 } 747 748 cifroute(); 749 750 if (if_is_up) { 751 strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); 752 if (ioctl(ip_sockfd, SIOCGIFFLAGS, &ifr) >= 0 753 && ((ifr.ifr_flags & IFF_UP) != 0)) { 754 ifr.ifr_flags &= ~IFF_UP; 755 ioctl(ip_sockfd, SIOCSIFFLAGS, &ifr); 756 } 757 } 758 759 if (ifaddrs[0] != 0) 760 cifaddr(0, ifaddrs[0], ifaddrs[1]); 761 762 if (default_route_gateway) 763 cifdefaultroute(0, 0, default_route_gateway); 764 if (proxy_arp_addr) 765 cifproxyarp(0, proxy_arp_addr); 766} 767 768/* ----------------------------------------------------------------------------- 769 sys_runloop - called from main loop 770----------------------------------------------------------------------------- */ 771void sys_runloop() 772{ 773 if (!controlled && rls) { 774 if (kill_link) 775 CFRunLoopStop(CFRunLoopGetCurrent()); 776 else 777 CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0, true); 778 } 779} 780 781/* ----------------------------------------------------------------------------- 782----------------------------------------------------------------------------- */ 783void set_network_signature(char *key1, char *val1, char *key2, char *val2) 784{ 785 int len = 0; 786 787 if (network_signature) { 788 free(network_signature); 789 network_signature = 0; 790 } 791 792 if (key1) 793 len += strlen(key1) + strlen(val1) + 1; 794 if (key2) { 795 if (key1) len++; // add separator ";" 796 len += strlen(key2) + strlen(val2) + 1; 797 } 798 799 if (len) { 800 network_signature = malloc(len + 1); 801 if (!network_signature) { 802 warning("no memory to create network signature"); 803 return; 804 } 805 network_signature[0] = 0; 806 if (key1) { 807 strlcat(network_signature, key1, len + 1); 808 strlcat(network_signature, "=", len + 1); 809 strlcat(network_signature, val1, len + 1); 810 } 811 if (key2) { 812 if (key1) strlcat(network_signature, ";", len + 1); 813 strlcat(network_signature, key2, len + 1); 814 strlcat(network_signature, "=", len + 1); 815 strlcat(network_signature, val2, len + 1); 816 } 817 } 818} 819 820 821/* ----------------------------------------------------------------------------- 822 ----------------------------------------------------------------------------- */ 823void set_server_peer(struct in_addr peer) 824{ 825 if (server_peer) { 826 CFRelease(server_peer); 827 server_peer = NULL; 828 } 829 830 server_peer = CFStringCreateWithCString(NULL, inet_ntoa(peer), kCFStringEncodingASCII); 831} 832 833 834/* ----------------------------------------------------------------------------- 835----------------------------------------------------------------------------- */ 836void sys_close() 837{ 838 if (ip_sockfd != -1) { 839 close(ip_sockfd); 840 ip_sockfd = -1; 841 } 842 if (ppp_sockfd != -1) { 843 close(ppp_sockfd); 844 ppp_sockfd = -1; 845 } 846} 847 848/* ----------------------------------------------------------------------------- 849 Functions to read and set the flags value in the device driver 850----------------------------------------------------------------------------- */ 851static int get_flags (int fd) 852{ 853 int flags; 854 855 if (ioctl(fd, PPPIOCGFLAGS, (caddr_t) &flags) < 0) { 856 if ( ok_error (errno) ) 857 flags = 0; 858 else 859 fatal("ioctl(PPPIOCGFLAGS): %m"); 860 } 861 862 SYSDEBUG ((LOG_DEBUG, "get flags = %x\n", flags)); 863 return flags; 864} 865 866/* ----------------------------------------------------------------------------- 867----------------------------------------------------------------------------- */ 868static void set_flags (int fd, int flags) 869{ 870 SYSDEBUG ((LOG_DEBUG, "set flags = %x\n", flags)); 871 872 if (ioctl(fd, PPPIOCSFLAGS, (caddr_t) &flags) < 0) { 873 if (! ok_error (errno) ) 874 fatal("ioctl(PPPIOCSFLAGS, %x): %m", flags, errno); 875 } 876} 877 878/* ----------------------------------------------------------------------------- 879----------------------------------------------------------------------------- */ 880void sys_notify(u_int32_t message, uintptr_t code1, uintptr_t code2) 881{ 882 struct ppp_msg_hdr *hdr; 883 int servlen, totlen; 884 u_char *p, *msg; 885 886 if (statusfd == -1) 887 return; 888 889 servlen = strlen(serviceid); 890 totlen = sizeof(struct ppp_msg_hdr) + servlen + 8; 891 892 msg = malloc(totlen); 893 if (!msg) { 894 warning("no memory to send event to PPPController"); 895 return; 896 } 897 898 p = msg; 899 bzero(p, totlen); 900 hdr = ALIGNED_CAST(struct ppp_msg_hdr *)p; 901 hdr->m_type = message; 902 hdr->m_len = 8; 903 hdr->m_flags |= USE_SERVICEID; 904 hdr->m_link = servlen; 905 906 p += sizeof(struct ppp_msg_hdr); 907 bcopy(serviceid, p, servlen); 908 p += servlen; 909 bcopy((u_char*)&code1, p, 4); 910 p += 4; 911 bcopy((u_char*)&code2, p, 4); 912 913 if (write(statusfd, msg, totlen) != totlen) { 914 warning("can't talk to PPPController : %m"); 915 } 916 free(msg); 917} 918 919/* ----------------------------------------------------------------------------- 920we installed the notifier with the event as the parameter 921----------------------------------------------------------------------------- */ 922void sys_eventnotify(void *param, uintptr_t code) 923{ 924 925 if (param == (void*)PPP_EVT_CONN_FAILED) 926 code = EXIT_CONNECT_FAILED; 927 928 sys_notify(PPPD_EVENT, (uintptr_t)param, code); 929} 930 931/* ----------------------------------------------------------------------------- 932send status notification to the controller 933----------------------------------------------------------------------------- */ 934void sys_statusnotify() 935{ 936 937 sys_notify(PPPD_STATUS, status, devstatus); 938} 939 940 941/* ----------------------------------------------------------------------------- 942check the options that the user specified 943----------------------------------------------------------------------------- */ 944int sys_check_options() 945{ 946#ifndef CDTRCTS 947 if (crtscts == 2) { 948 warning("DTR/CTS flow control is not supported on this system"); 949 return 0; 950 } 951#endif 952 return 1; 953} 954 955/* ----------------------------------------------------------------------------- 956check if the kernel supports PPP 957----------------------------------------------------------------------------- */ 958int ppp_available() 959{ 960 int s; 961 extern char *no_ppp_msg; 962 963 no_ppp_msg = "\ 964Mac OS X lacks kernel support for PPP. \n\ 965To include PPP support in the kernel, please follow \n\ 966the steps detailed in the README.MacOSX file.\n"; 967 968 // open to socket to the PF_PPP family 969 // if that works, the kernel extension is loaded. 970 if ((s = socket(PF_PPP, SOCK_RAW, PPPPROTO_CTL)) < 0) { 971 972#if !TARGET_OS_EMBEDDED 973 if (!noload && !load_kext(PPP_NKE_PATH, 0)) 974#else 975 if (!noload && !load_kext(PPP_NKE_ID, 1)) 976#endif 977 s = socket(PF_PPP, SOCK_RAW, PPPPROTO_CTL); 978 979 if (s < 0) 980 return 0; 981 } 982 983 // could be smarter and get the version of the ppp family, 984 // using get option or ioctl 985 986 close(s); 987 988 return 1; 989} 990 991/* ----------------------------------------------------------------------------- 992----------------------------------------------------------------------------- */ 993static int still_ppp(void) 994{ 995 996 return !hungup && ppp_fd >= 0; 997} 998 999/* ----------------------------------------------------------------------------- 1000Define the debugging level for the kernel 1001----------------------------------------------------------------------------- */ 1002static int set_kdebugflag (int requested_level) 1003{ 1004 if (ifunit < 0) 1005 return 1; 1006 if (ioctl(ppp_sockfd, PPPIOCSDEBUG, &requested_level) < 0) { 1007 if ( ! ok_error (errno) ) 1008 error("ioctl(PPPIOCSDEBUG): %m"); 1009 return (0); 1010 } 1011 SYSDEBUG ((LOG_INFO, "set kernel debugging level to %d", 1012 requested_level)); 1013 return (1); 1014} 1015 1016/* ----------------------------------------------------------------------------- 1017make a new ppp unit for ppp_sockfd 1018----------------------------------------------------------------------------- */ 1019static int make_ppp_unit() 1020{ 1021 int x; 1022 char name[32]; 1023 1024 ifunit = req_unit; 1025 x = ioctl(ppp_sockfd, PPPIOCNEWUNIT, &ifunit); 1026 if (x < 0 && req_unit >= 0 && errno == EEXIST) { 1027 warning("Couldn't allocate PPP unit %d as it is already in use"); 1028 ifunit = -1; 1029 x = ioctl(ppp_sockfd, PPPIOCNEWUNIT, &ifunit); 1030 1031 1032 } 1033 if (x < 0) 1034 error("Couldn't create new ppp unit: %m"); 1035 else { 1036 slprintf(name, sizeof(name), "%s%d", PPP_DRV_NAME, ifunit); 1037 publish_dictstrentry(kSCEntNetPPP, kSCPropInterfaceName, name, kCFStringEncodingMacRoman); 1038 } 1039 1040 return x; 1041} 1042 1043/* ----------------------------------------------------------------------------- 1044coen a socket to the PF_PPP protocol 1045----------------------------------------------------------------------------- */ 1046int connect_pfppp() 1047{ 1048 int fd = -1; 1049 struct sockaddr_ppp pppaddr; 1050 1051 // open a PF_PPP socket 1052 fd = socket(PF_PPP, SOCK_RAW, PPPPROTO_CTL); 1053 if (fd < 0) { 1054 error("Couldn't open PF_PPP: %m"); 1055 return -1; 1056 } 1057 // need to connect to the PPP protocol 1058 pppaddr.ppp_len = sizeof(struct sockaddr_ppp); 1059 pppaddr.ppp_family = AF_PPP; 1060 pppaddr.ppp_proto = PPPPROTO_CTL; 1061 pppaddr.ppp_cookie = 0; 1062 if (connect(fd, (struct sockaddr *)&pppaddr, sizeof(struct sockaddr_ppp)) < 0) { 1063 error("Couldn't connect to PF_PPP: %m"); 1064 close(fd); 1065 return -1; 1066 } 1067 return fd; 1068} 1069 1070 1071/* ----------------------------------------------------------------------------- 1072Turn the serial port into a ppp interface 1073----------------------------------------------------------------------------- */ 1074int tty_establish_ppp (int tty_fd) 1075{ 1076 int new_fd; 1077 1078 // First, turn the device into ppp link 1079 1080 /* Ensure that the tty device is in exclusive mode. */ 1081 ioctl(tty_fd, TIOCEXCL, 0); 1082 1083 // Set the current tty to the PPP discpline 1084 pppdisc = sync_serial ? N_SYNC_PPP: PPPDISC; 1085 if (ioctl(tty_fd, TIOCSETD, &pppdisc) < 0) { 1086 if ( ! ok_error (errno) ) { 1087 error("Couldn't set tty to PPP discipline: %m"); 1088 return -1; 1089 } 1090 } 1091 1092 // Then, then do the generic link work, and get a generic fd back 1093 1094 new_fd = generic_establish_ppp(tty_fd, NULL); 1095 if (new_fd == -1) { 1096 // Restore the previous line discipline 1097 if (ioctl(tty_fd, TIOCSETD, &ttydisc) < 0) 1098 if ( ! ok_error (errno)) 1099 error("ioctl(TIOCSETD, TTYDISC): %m"); 1100 return -1; 1101 } 1102 1103 set_flags(new_fd, get_flags(ppp_fd) & ~(SC_RCV_B7_0 | SC_RCV_B7_1 | SC_RCV_EVNP | SC_RCV_ODDP)); 1104 1105 return new_fd; 1106} 1107 1108/* ----------------------------------------------------------------------------- 1109Restore the serial port to normal operation. 1110This shouldn't call die() because it's called from die() 1111----------------------------------------------------------------------------- */ 1112void tty_disestablish_ppp(int tty_fd) 1113{ 1114 1115 if (!hungup) { 1116 1117 // Flush the tty output buffer so that the TIOCSETD doesn't hang. 1118 //if (tcflush(tty_fd, TCIOFLUSH) < 0) 1119 // warning("tcflush failed: %m"); 1120 1121 // Restore the previous line discipline 1122 if (ioctl(tty_fd, TIOCSETD, &ttydisc) < 0) { 1123 if ( ! ok_error (errno)) 1124 error("ioctl(TIOCSETD, TTYDISC): %m"); 1125 } 1126 1127 if (ioctl(tty_fd, TIOCNXCL, 0) < 0) { 1128 if ( ! ok_error (errno)) 1129 warning("ioctl(TIOCNXCL): %m(%d)", errno); 1130 } 1131 1132 // Reset non-blocking mode on fd 1133 if (initfdflags != -1 && fcntl(tty_fd, F_SETFL, initfdflags) < 0) { 1134 if ( ! ok_error (errno)) 1135 warning("Couldn't restore device fd flags: %m"); 1136 } 1137 } 1138 1139 initfdflags = -1; 1140 1141 generic_disestablish_ppp(tty_fd); 1142} 1143 1144/* ----------------------------------------------------------------------------- 1145generic code to establish ppp interface 1146----------------------------------------------------------------------------- */ 1147int generic_establish_ppp (int fd, UInt8 *delegate) 1148{ 1149 int flags, s = -1, link = 0; 1150 1151 // Open another instance of the ppp socket and connect the link to it 1152 if (ioctl(fd, PPPIOCGCHAN, &link) == -1) { 1153 error("Couldn't get link number: %m"); 1154 goto err; 1155 } 1156 1157 dbglog("using link %d", link); 1158 1159 // open a socket to the PPP protocol 1160 s = connect_pfppp(); 1161 if (s < 0) { 1162 error("Couldn't reopen PF_PPP: %m"); 1163 goto err; 1164 } 1165 1166 if (ioctl(s, PPPIOCATTCHAN, &link) < 0) { 1167 error("Couldn't attach to the ppp link %d: %m", link); 1168 goto err_close; 1169 } 1170 1171 flags = fcntl(s, F_GETFL); 1172 if (flags == -1 || fcntl(s, F_SETFL, flags | O_NONBLOCK) == -1) 1173 warning("Couldn't set ppp socket link to nonblock: %m"); 1174 1175 /* set the ppp_fd socket now */ 1176 ppp_fd = s; 1177 1178 if (!looped) 1179 ifunit = -1; 1180 if (!looped && !multilink) { 1181 // Create a new PPP unit. 1182 if (make_ppp_unit() < 0) 1183 goto err_close; 1184 } 1185 1186 // set the delegate interface 1187 if (delegate) { 1188 if (ioctl(ppp_sockfd, PPPIOCSDELEGATE, delegate) < 0) { 1189 error("Couldn't set the delegate interface: %m"); 1190 goto err_close; 1191 } 1192 } 1193 1194 if (looped) { 1195 set_flags(ppp_sockfd, get_flags(ppp_sockfd) & ~SC_LOOP_TRAFFIC); 1196 looped = 0; 1197 } 1198 1199 if (!multilink) { 1200 add_fd(ppp_sockfd); 1201 if (ioctl(s, PPPIOCCONNECT, &ifunit) < 0) { 1202 error("Couldn't attach to PPP unit %d: %m", ifunit); 1203 goto err_close; 1204 } 1205 } 1206 1207 // Enable debug in the driver if requested. 1208 set_kdebugflag (kdebugflag); 1209 1210 return ppp_fd; 1211 1212 err_close: 1213 close(s); 1214 1215 err: 1216 return -1; 1217} 1218 1219/* ----------------------------------------------------------------------------- 1220Restore the serial port to normal operation. 1221This shouldn't call die() because it's called from die() 1222fd is the file descriptor of the device 1223----------------------------------------------------------------------------- */ 1224void generic_disestablish_ppp(int fd) 1225{ 1226 int x; 1227 1228 close(ppp_fd); 1229 ppp_fd = -1; 1230 if (demand) { 1231 looped = 1; 1232 set_flags(ppp_sockfd, get_flags(ppp_sockfd) | SC_LOOP_TRAFFIC); 1233 } 1234 else { 1235 unpublish_dictentry(kSCEntNetPPP, kSCPropInterfaceName); 1236 if (ifunit >= 0 && ioctl(ppp_sockfd, PPPIOCDETACH, &x) < 0) 1237 error("Couldn't release PPP unit ppp_sockfd %d: %m", ppp_sockfd); 1238 } 1239 if (!multilink) 1240 remove_fd(ppp_sockfd); 1241} 1242 1243/* ----------------------------------------------------------------------------- 1244Check whether the link seems not to be 8-bit clean 1245----------------------------------------------------------------------------- */ 1246void clean_check() 1247{ 1248 int x; 1249 char *s; 1250 1251 if (!still_ppp()) 1252 return; 1253 1254 if (ioctl(ppp_fd, PPPIOCGFLAGS, (caddr_t) &x) == 0) { 1255 s = NULL; 1256 switch (~x & (SC_RCV_B7_0|SC_RCV_B7_1|SC_RCV_EVNP|SC_RCV_ODDP)) { 1257 case SC_RCV_B7_0: 1258 s = "bit 7 set to 1"; 1259 break; 1260 case SC_RCV_B7_1: 1261 s = "bit 7 set to 0"; 1262 break; 1263 case SC_RCV_EVNP: 1264 s = "odd parity"; 1265 break; 1266 case SC_RCV_ODDP: 1267 s = "even parity"; 1268 break; 1269 } 1270 if (s != NULL) { 1271 warning("Serial link is not 8-bit clean:"); 1272 warning("All received characters had %s", s); 1273 } 1274 } 1275} 1276 1277/* ----------------------------------------------------------------------------- 1278Set up the serial port on `fd' for 8 bits, no parity, 1279 * at the requested speed, etc. If `local' is true, set CLOCAL 1280 * regardless of whether the modem option was specified. 1281 * 1282 * For *BSD, we assume that speed_t values numerically equal bits/second 1283----------------------------------------------------------------------------- */ 1284void set_up_tty(int fd, int local) 1285{ 1286 struct termios tios; 1287 1288 // set the file descriptor as the controlling terminal, in order to receive SIGHUP 1289 if (ioctl(fd, TIOCSCTTY, (char *)NULL) == -1) 1290 error("set_up_tty, can't set controlling terminal: %m"); 1291 1292 if (tcgetattr(fd, &tios) < 0) { 1293 error("tcgetattr: %m"); 1294 return; 1295 } 1296 1297 if (!restore_term) { 1298 inittermios = tios; 1299 ioctl(fd, TIOCGWINSZ, &wsinfo); 1300 } 1301 1302 tios.c_cflag &= ~(CSIZE | CSTOPB | PARENB | CLOCAL); 1303 if (crtscts > 0 && !local) { 1304 if (crtscts == 2) { 1305#ifdef CDTRCTS 1306 tios.c_cflag |= CDTRCTS; 1307#endif 1308 } else 1309 tios.c_cflag |= CRTSCTS; 1310 } else if (crtscts < 0) { 1311 tios.c_cflag &= ~CRTSCTS; 1312#ifdef CDTRCTS 1313 tios.c_cflag &= ~CDTRCTS; 1314#endif 1315 } 1316 1317 tios.c_cflag |= CS8 | CREAD | HUPCL; 1318 if (local || !modem) 1319 tios.c_cflag |= CLOCAL; 1320 tios.c_iflag = IGNBRK | IGNPAR; 1321 tios.c_oflag = 0; 1322 tios.c_lflag = 0; 1323 tios.c_cc[VMIN] = 1; 1324 tios.c_cc[VTIME] = 0; 1325 1326 if (crtscts == -2) { 1327 tios.c_iflag |= IXON | IXOFF; 1328 tios.c_cc[VSTOP] = 0x13; /* DC3 = XOFF = ^S */ 1329 tios.c_cc[VSTART] = 0x11; /* DC1 = XON = ^Q */ 1330 } 1331 1332 if (inspeed) { 1333 cfsetospeed(&tios, inspeed); 1334 cfsetispeed(&tios, inspeed); 1335 } else { 1336 inspeed = cfgetospeed(&tios); 1337 /* 1338 * We can't proceed if the serial port speed is 0, 1339 * since that implies that the serial port is disabled. 1340 */ 1341 if (inspeed == 0) 1342 fatal("Baud rate for %s is 0; need explicit baud rate", devnam); 1343 } 1344 1345 baud_rate = inspeed; 1346 if (tcsetattr(fd, TCSAFLUSH, &tios) < 0) 1347 fatal("tcsetattr: %m"); 1348 1349 restore_term = 1; 1350} 1351 1352 1353/* ----------------------------------------------------------------------------- 1354Set up the serial port 1355 * If `local' is true, set CLOCAL 1356 * regardless of whether the modem option was specified. 1357 * other parameter (speed, start/stop bits, parity) may have been changed by the CCL 1358----------------------------------------------------------------------------- */ 1359void set_up_tty_local(int fd, int local) 1360{ 1361 struct termios tios; 1362 1363 if (tcgetattr(fd, &tios) < 0) { 1364 error("tcgetattr: %m"); 1365 return; 1366 } 1367 1368 tios.c_cc[VMIN] = 1; 1369 tios.c_cc[VTIME] = 0; 1370 1371 tios.c_cflag &= ~CLOCAL; 1372 if (local || !modem) 1373 tios.c_cflag |= CLOCAL; 1374 1375 if (tcsetattr(fd, TCSANOW, &tios) < 0) 1376 fatal("tcsetattr: %m"); 1377} 1378 1379/* ----------------------------------------------------------------------------- 1380restore the terminal to the saved settings 1381----------------------------------------------------------------------------- */ 1382void restore_tty(int fd) 1383{ 1384 if (restore_term) { 1385 if (!default_device) { 1386 /* 1387 * Turn off echoing, because otherwise we can get into 1388 * a loop with the tty and the modem echoing to each other. 1389 * We presume we are the sole user of this tty device, so 1390 * when we close it, it will revert to its defaults anyway. 1391 */ 1392 inittermios.c_lflag &= ~(ECHO | ECHONL); 1393 } 1394 if (!hungup) { 1395 if (tcsetattr(fd, TCSAFLUSH, &inittermios) < 0) 1396 if (errno != ENXIO) 1397 warning("tcsetattr: %m"); 1398 ioctl(fd, TIOCSWINSZ, &wsinfo); 1399 } 1400 restore_term = 0; 1401 } 1402} 1403 1404/* ----------------------------------------------------------------------------- 1405control the DTR line on the serial port. 1406 * This is called from die(), so it shouldn't call die() 1407----------------------------------------------------------------------------- */ 1408void setdtr(int fd, int on) 1409{ 1410 int modembits = TIOCM_DTR; 1411 1412 ioctl(fd, (on? TIOCMBIS: TIOCMBIC), &modembits); 1413} 1414 1415/* ----------------------------------------------------------------------------- 1416get a pty master/slave pair and chown the slave side 1417 * to the uid given. Assumes slave_name points to >= 12 bytes of space 1418----------------------------------------------------------------------------- */ 1419int get_pty(int *master_fdp, int *slave_fdp, char *slave_name, int uid) 1420{ 1421 struct termios tios; 1422 1423 if (openpty(master_fdp, slave_fdp, slave_name, NULL, NULL) < 0) 1424 return 0; 1425 1426 fchown(*slave_fdp, uid, -1); 1427 fchmod(*slave_fdp, S_IRUSR | S_IWUSR); 1428 if (tcgetattr(*slave_fdp, &tios) == 0) { 1429 tios.c_cflag &= ~(CSIZE | CSTOPB | PARENB); 1430 tios.c_cflag |= CS8 | CREAD; 1431 tios.c_iflag = IGNPAR | CLOCAL; 1432 tios.c_oflag = 0; 1433 tios.c_lflag = 0; 1434 if (tcsetattr(*slave_fdp, TCSAFLUSH, &tios) < 0) 1435 warning("couldn't set attributes on pty: %m"); 1436 } else 1437 warning("couldn't get attributes on pty: %m"); 1438 1439 return 1; 1440} 1441 1442/* ----------------------------------------------------------------------------- 1443create the ppp interface and configure it in loopback mode. 1444----------------------------------------------------------------------------- */ 1445int open_ppp_loopback() 1446{ 1447 looped = 1; 1448 /* allocate ourselves a ppp unit */ 1449 if (make_ppp_unit() < 0) 1450 die(1); 1451 set_flags(ppp_sockfd, SC_LOOP_TRAFFIC); 1452 set_kdebugflag(kdebugflag); 1453 ppp_fd = -1; 1454 return ppp_sockfd; 1455} 1456 1457/* ----------------------------------------------------------------------------- 1458Output PPP packet 1459----------------------------------------------------------------------------- */ 1460void output(int unit, u_char *p, int len) 1461{ 1462 1463 dump_packet("sent", p, len); 1464 1465 // don't write FF03 1466 len -= 2; 1467 p += 2; 1468 1469 // link protocol are sent to the link 1470 // other protocols are send to the bundle 1471 /* test was changed because compiler strangeness for embedded os */ 1472// if (write((ntohs(*(u_short*)p) >= 0xC000) ? ppp_fd : ppp_sockfd, p, len) < 0) { 1473 if (write((p[0] >= 0xC0) ? ppp_fd : ppp_sockfd, p, len) < 0) { 1474 if (errno != EIO) 1475 error("write: %m"); 1476 } 1477} 1478 1479/* ----------------------------------------------------------------------------- 1480wait until there is data available, for the length of time specified by *timo 1481(indefinite if timo is NULL) 1482----------------------------------------------------------------------------- */ 1483void wait_input(struct timeval *timo) 1484{ 1485 int n; 1486 1487 ready_fds = in_fds; 1488 n = select(max_in_fd + 1, &ready_fds, NULL, NULL, timo); 1489 if (n < 0 && errno != EINTR) 1490 fatal("select: %m"); 1491 1492 if (n < 0) { 1493 FD_ZERO(&ready_fds); 1494 } 1495} 1496 1497/* ----------------------------------------------------------------------------- 1498wait on fd until there is data available, for the delay in milliseconds 1499return 0 if timeout expires, < 0 if error, otherwise > 0 1500----------------------------------------------------------------------------- */ 1501int wait_input_fd(int fd, int delay) 1502{ 1503 fd_set ready; 1504 int n; 1505 struct timeval t; 1506 1507 t.tv_sec = delay / 1000; 1508 t.tv_usec = delay % 1000; 1509 1510 FD_ZERO(&ready); 1511 FD_SET(fd, &ready); 1512 1513 do { 1514 n = select(fd + 1, &ready, NULL, &ready, &t); 1515 } while (n < 0 && errno == EINTR); 1516 1517 if (n > 0) 1518 if (ioctl(fd, FIONREAD, &n) == -1) 1519 n = -1; 1520 1521 return n; 1522} 1523 1524 1525/* ----------------------------------------------------------------------------- 1526add an fd to the set that wait_input waits for 1527----------------------------------------------------------------------------- */ 1528void add_fd(int fd) 1529{ 1530 FD_SET(fd, &in_fds); 1531 if (fd > max_in_fd) 1532 max_in_fd = fd; 1533} 1534 1535/* ----------------------------------------------------------------------------- 1536remove an fd from the set that wait_input waits for 1537----------------------------------------------------------------------------- */ 1538void remove_fd(int fd) 1539{ 1540 FD_CLR(fd, &in_fds); 1541} 1542 1543/* ----------------------------------------------------------------------------- 1544return 1 is fd is set (i.e. select returned with this file descriptor set) 1545----------------------------------------------------------------------------- */ 1546bool is_ready_fd(int fd) 1547{ 1548 return (FD_ISSET(fd, &ready_fds) != 0); 1549} 1550 1551/* ----------------------------------------------------------------------------- 1552get a PPP packet from the serial device 1553----------------------------------------------------------------------------- */ 1554int read_packet(u_char *buf) 1555{ 1556 int len = -1; 1557 1558 // FF03 are not read 1559 *buf++ = PPP_ALLSTATIONS; 1560 *buf++ = PPP_UI; 1561 1562 // read first the socket attached to the link 1563 if (ppp_fd >= 0) { 1564 if ((len = read(ppp_fd, buf, PPP_MRU + PPP_HDRLEN - 2)) < 0) { 1565 if (errno != EWOULDBLOCK && errno != EINTR) 1566 error("read from socket link: %m"); 1567 } 1568 } 1569 1570 // then, if nothing, link the socket attached to the bundle 1571 if (len < 0 && ifunit >= 0) { 1572 if ((len = read(ppp_sockfd, buf, PPP_MRU + PPP_HDRLEN - 2)) < 0) { 1573 if (errno != EWOULDBLOCK && errno != EINTR) 1574 error("read from socket bundle: %m"); 1575 } 1576 } 1577 return (len <= 0 ? len : len + 2); 1578} 1579 1580/* ----------------------------------------------------------------------------- 1581 read characters from the loopback, form them 1582 * into frames, and detect when we want to bring the real link up. 1583 * Return value is 1 if we need to bring up the link, 0 otherwise 1584----------------------------------------------------------------------------- */ 1585int get_loop_output() 1586{ 1587 int rv = 0; 1588 int n; 1589 1590 while ((n = read_packet(inpacket_buf)) > 0) 1591 if (loop_frame(inpacket_buf, n)) 1592 rv = 1; 1593 return rv; 1594} 1595 1596/* ----------------------------------------------------------------------------- 1597configure the transmit characteristics of the ppp interface 1598 ----------------------------------------------------------------------------- */ 1599void tty_send_config(int mtu, u_int32_t asyncmap, int pcomp, int accomp) 1600{ 1601 u_int x; 1602 1603 if (!still_ppp()) 1604 return; 1605 1606 if (ioctl(ppp_fd, PPPIOCSASYNCMAP, (caddr_t) &asyncmap) < 0) 1607 fatal("ioctl(PPPIOCSASYNCMAP): %m"); 1608 1609 if (ioctl(ppp_fd, PPPIOCGFLAGS, (caddr_t) &x) < 0) 1610 fatal("ioctl (PPPIOCGFLAGS): %m"); 1611 x = pcomp? x | SC_COMP_PROT: x &~ SC_COMP_PROT; 1612 x = accomp? x | SC_COMP_AC: x &~ SC_COMP_AC; 1613 x = sync_serial ? x | SC_SYNC : x & ~SC_SYNC; 1614 if (ioctl(ppp_fd, PPPIOCSFLAGS, (caddr_t) &x) < 0) 1615 fatal("ioctl(PPPIOCSFLAGS): %m"); 1616 1617 publish_dictnumentry(kSCEntNetPPP, kSCPropNetPPPLCPCompressionPField, pcomp); 1618 publish_dictnumentry(kSCEntNetPPP, kSCPropNetPPPLCPCompressionACField, accomp); 1619 publish_dictnumentry(kSCEntNetPPP, kSCPropNetPPPLCPTransmitACCM, asyncmap); 1620} 1621 1622/* ----------------------------------------------------------------------------- 1623configure the transmit characteristics of the ppp interface 1624function used for synchronous links, asyncmap is irrelevant 1625 ----------------------------------------------------------------------------- */ 1626void generic_send_config(int mtu, u_int32_t asyncmap, int pcomp, int accomp) 1627{ 1628 u_int x; 1629 1630 if (!still_ppp()) 1631 return; 1632 1633 if (ioctl(ppp_fd, PPPIOCGFLAGS, (caddr_t) &x) < 0) 1634 fatal("ioctl (PPPIOCGFLAGS): %m"); 1635 x = pcomp? x | SC_COMP_PROT: x &~ SC_COMP_PROT; 1636 x = accomp? x | SC_COMP_AC: x &~ SC_COMP_AC; 1637 if (ioctl(ppp_fd, PPPIOCSFLAGS, (caddr_t) &x) < 0) 1638 fatal("ioctl(PPPIOCSFLAGS): %m"); 1639 1640 publish_dictnumentry(kSCEntNetPPP, kSCPropNetPPPLCPCompressionPField, pcomp); 1641 publish_dictnumentry(kSCEntNetPPP, kSCPropNetPPPLCPCompressionACField, accomp); 1642} 1643 1644/* ----------------------------------------------------------------------------- 1645set the MTU on the PPP network interface 1646----------------------------------------------------------------------------- */ 1647void netif_set_mtu(int unit, int mtu) 1648{ 1649 struct ifreq ifr; 1650 1651 strlcpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name)); 1652 ifr.ifr_mtu = mtu; 1653 if (ioctl(ip_sockfd, SIOCSIFMTU, (caddr_t) &ifr) < 0) 1654 error("ioctl (SIOCSIFMTU): %m"); 1655 1656 publish_dictnumentry(kSCEntNetPPP, kSCPropNetPPPLCPMTU, mtu); 1657} 1658 1659/* ----------------------------------------------------------------------------- 1660get the MTU on the PPP network interface 1661----------------------------------------------------------------------------- */ 1662int netif_get_mtu(int unit) 1663{ 1664 struct ifreq ifr; 1665 1666 strlcpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name)); 1667 if (ioctl(ip_sockfd, SIOCGIFMTU, (caddr_t) &ifr) < 0) { 1668 error("ioctl (SIOCGIFMTU): %m"); 1669 return 0; 1670 } 1671 return ifr.ifr_mtu; 1672} 1673 1674 1675/* ----------------------------------------------------------------------------- 1676stop traffic on this link 1677 ----------------------------------------------------------------------------- */ 1678void ppp_hold(int unit) 1679{ 1680 u_int x; 1681 1682 if (ioctl(ppp_fd, PPPIOCGFLAGS, (caddr_t) &x) < 0) { 1683 warning("ioctl (PPPIOCGFLAGS): %m"); 1684 return; 1685 } 1686 x |= SC_HOLD; 1687 if (ioctl(ppp_fd, PPPIOCSFLAGS, (caddr_t) &x) < 0) 1688 warning("ioctl(PPPIOCSFLAGS): %m"); 1689} 1690 1691/* ----------------------------------------------------------------------------- 1692resume traffic on this link 1693 ----------------------------------------------------------------------------- */ 1694void ppp_cont(int unit) 1695{ 1696 u_int x; 1697 1698 if (ioctl(ppp_fd, PPPIOCGFLAGS, (caddr_t) &x) < 0) { 1699 warning("ioctl (PPPIOCGFLAGS): %m"); 1700 return; 1701 } 1702 x &= ~SC_HOLD; 1703 if (ioctl(ppp_fd, PPPIOCSFLAGS, (caddr_t) &x) < 0) 1704 warning("ioctl(PPPIOCSFLAGS): %m"); 1705} 1706 1707/* ----------------------------------------------------------------------------- 1708set the extended transmit ACCM for the interface 1709----------------------------------------------------------------------------- */ 1710void tty_set_xaccm(ext_accm accm) 1711{ 1712 if (!still_ppp()) 1713 return; 1714 if (ioctl(ppp_fd, PPPIOCSXASYNCMAP, accm) < 0 && errno != ENOTTY) 1715 warning("ioctl(set extended ACCM): %m"); 1716} 1717 1718/* ----------------------------------------------------------------------------- 1719configure the receive-side characteristics of the ppp interface. 1720----------------------------------------------------------------------------- */ 1721void tty_recv_config(int mru, u_int32_t asyncmap, int pcomp, int accomp) 1722{ 1723 int x; 1724 1725 if (!still_ppp()) 1726 return; 1727 1728 if (ioctl(ppp_fd, PPPIOCSMRU, (caddr_t) &mru) < 0) 1729 fatal("ioctl(PPPIOCSMRU): %m"); 1730 if (ioctl(ppp_fd, PPPIOCSRASYNCMAP, (caddr_t) &asyncmap) < 0) 1731 fatal("ioctl(PPPIOCSRASYNCMAP): %m"); 1732 if (ioctl(ppp_fd, PPPIOCGFLAGS, (caddr_t) &x) < 0) 1733 fatal("ioctl (PPPIOCGFLAGS): %m"); 1734 x = !accomp? x | SC_REJ_COMP_AC: x &~ SC_REJ_COMP_AC; 1735 if (ioctl(ppp_fd, PPPIOCSFLAGS, (caddr_t) &x) < 0) 1736 fatal("ioctl(PPPIOCSFLAGS): %m"); 1737 1738 publish_dictnumentry(kSCEntNetPPP, kSCPropNetPPPLCPMRU, mru); 1739 publish_dictnumentry(kSCEntNetPPP, kSCPropNetPPPLCPReceiveACCM, asyncmap); 1740} 1741 1742/* ----------------------------------------------------------------------------- 1743configure the receive-side characteristics of the ppp interface. 1744function used for synchronous links, asyncmap is irrelevant 1745----------------------------------------------------------------------------- */ 1746void generic_recv_config(int mru, u_int32_t asyncmap, int pcomp, int accomp) 1747{ 1748 int x; 1749 1750 if (!still_ppp()) 1751 return; 1752 1753 if (ioctl(ppp_fd, PPPIOCSMRU, (caddr_t) &mru) < 0) 1754 fatal("ioctl(PPPIOCSMRU): %m"); 1755 if (ioctl(ppp_fd, PPPIOCGFLAGS, (caddr_t) &x) < 0) 1756 fatal("ioctl (PPPIOCGFLAGS): %m"); 1757 x = !accomp? x | SC_REJ_COMP_AC: x &~ SC_REJ_COMP_AC; 1758 if (ioctl(ppp_fd, PPPIOCSFLAGS, (caddr_t) &x) < 0) 1759 fatal("ioctl(PPPIOCSFLAGS): %m"); 1760 1761 publish_dictnumentry(kSCEntNetPPP, kSCPropNetPPPLCPMRU, mru); 1762} 1763 1764/* ----------------------------------------------------------------------------- 1765ask kernel whether a given compression method 1766 * is acceptable for use. Returns 1 if the method and parameters 1767 * are OK, 0 if the method is known but the parameters are not OK 1768 * (e.g. code size should be reduced), or -1 if the method is unknown 1769 ----------------------------------------------------------------------------- */ 1770int ccp_test(int unit, u_char * opt_ptr, int opt_len, int for_transmit) 1771{ 1772 struct ppp_option_data data; 1773 1774 data.ptr = opt_ptr; 1775 data.length = opt_len; 1776 data.transmit = for_transmit; 1777 if (ioctl(ppp_sockfd, PPPIOCSCOMPRESS, (caddr_t) &data) >= 0) 1778 return 1; 1779 return (errno == ENOBUFS)? 0: -1; 1780} 1781 1782/* ----------------------------------------------------------------------------- 1783inform kernel about the current state of CCP 1784----------------------------------------------------------------------------- */ 1785void ccp_flags_set(int unit, int isopen, int isup) 1786{ 1787 int x; 1788 1789 if (!still_ppp()) 1790 return; 1791 1792 if (ioctl(ppp_sockfd, PPPIOCGFLAGS, (caddr_t) &x) < 0) { 1793 error("ioctl (PPPIOCGFLAGS): %m"); 1794 return; 1795 } 1796 1797 x = isopen? x | SC_CCP_OPEN: x &~ SC_CCP_OPEN; 1798 x = isup? x | SC_CCP_UP: x &~ SC_CCP_UP; 1799 if (ioctl(ppp_sockfd, PPPIOCSFLAGS, (caddr_t) &x) < 0) 1800 error("ioctl(PPPIOCSFLAGS): %m"); 1801} 1802 1803/* ----------------------------------------------------------------------------- 1804returns 1 if decompression was disabled as a 1805 * result of an error detected after decompression of a packet, 1806 * 0 otherwise. This is necessary because of patent nonsense 1807 ----------------------------------------------------------------------------- */ 1808int ccp_fatal_error(int unit) 1809{ 1810 int x; 1811 1812 if (ioctl(ppp_fd, PPPIOCGFLAGS, (caddr_t) &x) < 0) { 1813 error("ioctl(PPPIOCGFLAGS): %m"); 1814 return 0; 1815 } 1816 return x & SC_DC_FERROR; 1817} 1818 1819/* ----------------------------------------------------------------------------- 1820return how long the link has been idle 1821----------------------------------------------------------------------------- */ 1822int get_idle_time(int u, struct ppp_idle *ip) 1823{ 1824 return ioctl(ppp_sockfd, PPPIOCGIDLE, ip) >= 0; 1825} 1826 1827/* ----------------------------------------------------------------------------- 1828return statistics for the link 1829----------------------------------------------------------------------------- */ 1830int get_ppp_stats(int u, struct pppd_stats *stats) 1831{ 1832 struct ifpppstatsreq req; 1833 1834 memset (&req, 0, sizeof (req)); 1835 strlcpy(req.ifr_name, ifname, sizeof(req.ifr_name)); 1836 if (ioctl(ip_sockfd, SIOCGPPPSTATS, &req) < 0) { 1837 error("Couldn't get PPP statistics: %m"); 1838 return 0; 1839 } 1840 stats->bytes_in = req.stats.p.ppp_ibytes; 1841 stats->bytes_out = req.stats.p.ppp_obytes; 1842 stats->pkts_in = req.stats.p.ppp_ipackets; 1843 stats->pkts_out = req.stats.p.ppp_opackets; 1844 return 1; 1845} 1846 1847 1848#ifdef PPP_FILTER 1849/* ----------------------------------------------------------------------------- 1850transfer the pass and active filters to the kernel 1851----------------------------------------------------------------------------- */ 1852int set_filters(struct bpf_program *pass, struct bpf_program *active) 1853{ 1854 int ret = 1; 1855 1856 if (pass->bf_len > 0) { 1857 if (ioctl(ppp_fd, PPPIOCSPASS, pass) < 0) { 1858 error("Couldn't set pass-filter in kernel: %m"); 1859 ret = 0; 1860 } 1861 } 1862 if (active->bf_len > 0) { 1863 if (ioctl(ppp_fd, PPPIOCSACTIVE, active) < 0) { 1864 error("Couldn't set active-filter in kernel: %m"); 1865 ret = 0; 1866 } 1867 } 1868 return ret; 1869} 1870#endif 1871 1872/* ----------------------------------------------------------------------------- 1873config tcp header compression 1874----------------------------------------------------------------------------- */ 1875int sifvjcomp(int u, int vjcomp, int cidcomp, int maxcid) 1876{ 1877 u_int x; 1878 1879 if (ioctl(ppp_sockfd, PPPIOCGFLAGS, (caddr_t) &x) < 0) { 1880 error("ioctl (PPPIOCGFLAGS): %m"); 1881 return 0; 1882 } 1883 x = vjcomp ? x | SC_COMP_TCP: x &~ SC_COMP_TCP; 1884 x = cidcomp? x & ~SC_NO_TCP_CCID: x | SC_NO_TCP_CCID; 1885 if (ioctl(ppp_sockfd, PPPIOCSFLAGS, (caddr_t) &x) < 0) { 1886 error("ioctl(PPPIOCSFLAGS): %m"); 1887 return 0; 1888 } 1889 if (vjcomp && ioctl(ppp_sockfd, PPPIOCSMAXCID, (caddr_t) &maxcid) < 0) { 1890 error("ioctl(PPPIOCSMAXCID): %m"); 1891 return 0; 1892 } 1893 publish_dictnumentry(kSCEntNetPPP, kSCPropNetPPPIPCPCompressionVJ, vjcomp); 1894 return 1; 1895} 1896 1897/* ----------------------------------------------------------------------------- 1898Config the interface up and enable IP packets to pass 1899----------------------------------------------------------------------------- */ 1900int sifup(int u) 1901{ 1902 struct ifreq ifr; 1903 1904 strlcpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name)); 1905 if (ioctl(ip_sockfd, SIOCGIFFLAGS, (caddr_t) &ifr) < 0) { 1906 error("ioctl (SIOCGIFFLAGS): %m"); 1907 return 0; 1908 } 1909 ifr.ifr_flags |= IFF_UP; 1910 if (ioctl(ip_sockfd, SIOCSIFFLAGS, (caddr_t) &ifr) < 0) { 1911 error("ioctl(SIOCSIFFLAGS): %m"); 1912 return 0; 1913 } 1914 if_is_up = 1; 1915 return 1; 1916} 1917 1918/* ----------------------------------------------------------------------------- 1919Set the mode for handling packets for a given NP 1920----------------------------------------------------------------------------- */ 1921int sifnpmode(int u, int proto, enum NPmode mode) 1922{ 1923 struct npioctl npi; 1924 1925 npi.protocol = proto; 1926 npi.mode = mode; 1927 if (ioctl(ppp_sockfd, PPPIOCSNPMODE, &npi) < 0) { 1928 error("ioctl(set NP %d mode to %d): %m", proto, mode); 1929 return 0; 1930 } 1931 return 1; 1932} 1933 1934/* ----------------------------------------------------------------------------- 1935Set the mode for filtering protocol addresses 1936----------------------------------------------------------------------------- */ 1937int sifnpafmode(int u, int proto, enum NPAFmode mode) 1938{ 1939 struct npafioctl npi; 1940 1941 npi.protocol = proto; 1942 npi.mode = mode; 1943 if (ioctl(ppp_sockfd, PPPIOCSNPAFMODE, &npi) < 0) { 1944 error("ioctl(set NPAF %d mode to %d): %m", proto, mode); 1945 return 0; 1946 } 1947 return 1; 1948} 1949 1950/* ----------------------------------------------------------------------------- 1951Config the interface down 1952----------------------------------------------------------------------------- */ 1953int sifdown(int u) 1954{ 1955 struct ifreq ifr; 1956 int rv; 1957 struct npioctl npi; 1958 1959 npi.protocol = PPP_IP; 1960 if ((ioctl(ppp_sockfd, PPPIOCGNPMODE, (caddr_t) &npi) == 0) 1961 && (npi.mode != NPMODE_DROP)) { 1962 return 0; 1963 } 1964 1965 npi.protocol = PPP_IPV6; 1966 if ((ioctl(ppp_sockfd, PPPIOCGNPMODE, (caddr_t) &npi) == 0) 1967 && (npi.mode != NPMODE_DROP)) { 1968 return 0; 1969 } 1970 1971 /* ipv4 and ipv4 are both down. take the interface down now */ 1972 1973 rv = 1; 1974 1975 strlcpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name)); 1976 if (ioctl(ip_sockfd, SIOCGIFFLAGS, (caddr_t) &ifr) < 0) { 1977 error("ioctl (SIOCGIFFLAGS): %m"); 1978 rv = 0; 1979 } else { 1980 ifr.ifr_flags &= ~IFF_UP; 1981 if (ioctl(ip_sockfd, SIOCSIFFLAGS, (caddr_t) &ifr) < 0) { 1982 error("ioctl(SIOCSIFFLAGS): %m"); 1983 rv = 0; 1984 } else 1985 if_is_up = 0; 1986 } 1987 return rv; 1988} 1989 1990 1991/* ----------------------------------------------------------------------------- 1992set the route for the interface. 1993----------------------------------------------------------------------------- */ 1994int sifroute(int u, u_int32_t o, u_int32_t h, u_int32_t m) 1995{ 1996 if (addifroute && m != 0xFFFFFFFF) { 1997 ifroute_address.s_addr = o & m; 1998 ifroute_mask.s_addr = m; 1999 ifroute_installed = route_interface(RTM_ADD, ifroute_address, ifroute_mask, IFT_PPP, ifname, 0); 2000 } 2001 2002 return 1; 2003} 2004 2005/* ----------------------------------------------------------------------------- 2006clear the route for the interface. 2007----------------------------------------------------------------------------- */ 2008int cifroute() 2009{ 2010 if (addifroute && ifroute_installed) { 2011 route_interface(RTM_DELETE, ifroute_address, ifroute_mask, IFT_PPP, ifname, 0); 2012 ifroute_installed = 0; 2013 } 2014 2015 return 1; 2016} 2017 2018/* ----------------------------------------------------------------------------- 2019set the sa_family field of a struct sockaddr, if it exists. 2020----------------------------------------------------------------------------- */ 2021#define SET_SA_FAMILY(addr, family) \ 2022 BZERO((char *) &(addr), sizeof(addr)); \ 2023 addr.sa_family = (family); \ 2024 addr.sa_len = sizeof(addr); 2025 2026/* ----------------------------------------------------------------------------- 2027Config the interface IP addresses and netmask 2028----------------------------------------------------------------------------- */ 2029int sifaddr(int u, u_int32_t o, u_int32_t h, u_int32_t m) 2030{ 2031 struct ifaliasreq ifra __attribute__ ((aligned (4))); // Wcast-align fix - force alignment 2032 struct ifreq ifr; 2033 2034// XXX from sys/sockio.h 2035#define SIOCPROTOATTACH _IOWR('i', 80, struct ifreq) /* attach proto to interface */ 2036#define SIOCPROTODETACH _IOWR('i', 81, struct ifreq) /* detach proto from interface */ 2037 2038 // first plumb ip over ppp 2039 if (ipv4_plumbed == 0) { 2040 strlcpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name)); 2041 if (ioctl(ip_sockfd, SIOCPROTOATTACH, (caddr_t) &ifr) < 0) { 2042 error("Couldn't plumb IP to the interface: %d %m", errno); 2043 //return 0; 2044 } 2045 ipv4_plumbed = 1; 2046 } 2047 2048 strlcpy(ifra.ifra_name, ifname, sizeof(ifra.ifra_name)); 2049 SET_SA_FAMILY(ifra.ifra_addr, AF_INET); 2050 (ALIGNED_CAST(struct sockaddr_in *) &ifra.ifra_addr)->sin_addr.s_addr = o; 2051 SET_SA_FAMILY(ifra.ifra_broadaddr, AF_INET); 2052 (ALIGNED_CAST(struct sockaddr_in *) &ifra.ifra_broadaddr)->sin_addr.s_addr = h; 2053 if (m != 0) { 2054 SET_SA_FAMILY(ifra.ifra_mask, AF_INET); 2055 (ALIGNED_CAST(struct sockaddr_in *) &ifra.ifra_mask)->sin_addr.s_addr = m; 2056 } else 2057 BZERO(&ifra.ifra_mask, sizeof(ifra.ifra_mask)); 2058 BZERO(&ifr, sizeof(ifr)); 2059 strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); 2060 if (ioctl(ip_sockfd, SIOCDIFADDR, (caddr_t) &ifr) < 0) { 2061 if (errno != EADDRNOTAVAIL) 2062 warning("Couldn't remove interface address: %m"); 2063 } 2064 if (ioctl(ip_sockfd, SIOCAIFADDR, (caddr_t) &ifra) < 0) { 2065 if (errno != EEXIST) { 2066 error("Couldn't set interface address: %m"); 2067 return 0; 2068 } 2069 warning("Couldn't set interface address: Address %I already exists", o); 2070 } 2071 ifaddrs[0] = o; 2072 ifaddrs[1] = h; 2073 2074 if (looplocal) { 2075 struct in_addr o1; 2076 struct in_addr mask; 2077 2078 set_flags(ppp_sockfd, get_flags(ppp_sockfd) | SC_LOOP_LOCAL); 2079 // add a route for our local address via our interface 2080 o1.s_addr = o; 2081 mask.s_addr = 0; 2082 route_interface(RTM_ADD, o1, mask, IFT_PPP, ifname, 1); 2083 } 2084 2085 sifroute(u, o, h, m); 2086 2087 publish_stateaddr(o, h, m); 2088 2089 return 1; 2090} 2091 2092/* ----------------------------------------------------------------------------- 2093 Update the interface IP addresses and netmask 2094 ----------------------------------------------------------------------------- */ 2095int uifaddr(int u, u_int32_t o, u_int32_t h, u_int32_t m) 2096{ 2097 struct ifaliasreq ifra __attribute__ ((aligned (4))); // Wcast-align fix - force alignment 2098 struct ifreq ifr; 2099 2100 cifroute(); 2101 2102 // XXX from sys/sockio.h 2103#define SIOCPROTOATTACH _IOWR('i', 80, struct ifreq) /* attach proto to interface */ 2104#define SIOCPROTODETACH _IOWR('i', 81, struct ifreq) /* detach proto from interface */ 2105 2106 // first plumb ip over ppp 2107 if (ipv4_plumbed == 0) { 2108 error("Interface should have been plumbed already"); 2109 return -1; 2110 } 2111 2112 strlcpy(ifra.ifra_name, ifname, sizeof(ifra.ifra_name)); 2113 SET_SA_FAMILY(ifra.ifra_addr, AF_INET); 2114 (ALIGNED_CAST(struct sockaddr_in *) &ifra.ifra_addr)->sin_addr.s_addr = o; 2115 SET_SA_FAMILY(ifra.ifra_broadaddr, AF_INET); 2116 (ALIGNED_CAST(struct sockaddr_in *) &ifra.ifra_broadaddr)->sin_addr.s_addr = h; 2117 if (m != 0) { 2118 SET_SA_FAMILY(ifra.ifra_mask, AF_INET); 2119 (ALIGNED_CAST(struct sockaddr_in *) &ifra.ifra_mask)->sin_addr.s_addr = m; 2120 } else 2121 BZERO(&ifra.ifra_mask, sizeof(ifra.ifra_mask)); 2122 BZERO(&ifr, sizeof(ifr)); 2123 strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); 2124 if (ioctl(ip_sockfd, SIOCDIFADDR, (caddr_t) &ifr) < 0) { 2125 if (errno != EADDRNOTAVAIL) 2126 warning("Couldn't remove interface address: %m"); 2127 } 2128 if (ioctl(ip_sockfd, SIOCAIFADDR, (caddr_t) &ifra) < 0) { 2129 if (errno != EEXIST) { 2130 error("Couldn't set interface address: %m"); 2131 return 0; 2132 } 2133 warning("Couldn't set interface address: Address %I already exists", o); 2134 } 2135 ifaddrs[0] = o; 2136 ifaddrs[1] = h; 2137 2138 sifroute(u, o, h, m); 2139 2140 update_stateaddr(o, h, m); 2141 2142 return 1; 2143} 2144 2145/* ----------------------------------------------------------------------------- 2146Clear the interface IP addresses, and delete routes 2147 * through the interface if possible 2148 ----------------------------------------------------------------------------- */ 2149int cifaddr(int u, u_int32_t o, u_int32_t h) 2150{ 2151 //struct ifreq ifr; 2152 struct ifaliasreq ifra __attribute__ ((aligned (4))); // Wcast-align fix - force alignment 2153 2154// XXX from sys/sockio.h 2155#define SIOCPROTOATTACH _IOWR('i', 80, struct ifreq) /* attach proto to interface */ 2156#define SIOCPROTODETACH _IOWR('i', 81, struct ifreq) /* detach proto from interface */ 2157 2158 cifroute(); 2159 2160 ifaddrs[0] = 0; 2161 strlcpy(ifra.ifra_name, ifname, sizeof(ifra.ifra_name)); 2162 SET_SA_FAMILY(ifra.ifra_addr, AF_INET); 2163 (ALIGNED_CAST(struct sockaddr_in *) &ifra.ifra_addr)->sin_addr.s_addr = o; 2164 SET_SA_FAMILY(ifra.ifra_broadaddr, AF_INET); 2165 (ALIGNED_CAST(struct sockaddr_in *) &ifra.ifra_broadaddr)->sin_addr.s_addr = h; 2166 BZERO(&ifra.ifra_mask, sizeof(ifra.ifra_mask)); 2167 if (ioctl(ip_sockfd, SIOCDIFADDR, (caddr_t) &ifra) < 0) { 2168 if (errno != EADDRNOTAVAIL) 2169 warning("Couldn't delete interface address: %m"); 2170 return 0; 2171 } 2172 2173#if 0 2174 // unplumb ip from ppp 2175 strlcpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name)); 2176 if (ioctl(ip_sockfd, SIOCPROTODETACH, (caddr_t) &ifr) < 0) { 2177 error("Couldn't unplumb IP from the interface: %m"); 2178 return 0; 2179 } 2180#endif 2181 2182 unpublish_dict(kSCEntNetIPv4); 2183 2184 return 1; 2185} 2186 2187#ifdef INET6 2188/* ----------------------------------------------------------------------------- 2189Config the interface IPv6 addresses 2190----------------------------------------------------------------------------- */ 2191int sif6addr (int unit, eui64_t our_eui64, eui64_t his_eui64) 2192{ 2193 int ifindex, s; 2194 struct in6_ifreq ifr6; 2195 struct in6_aliasreq addreq6 __attribute__ ((aligned (4))); // Wcast-align fix - force alignment 2196 2197// XXX from sys/sockio.h 2198#define SIOCPROTOATTACH_IN6 _IOWR('i', 110, struct in6_aliasreq) /* attach proto to interface */ 2199#define SIOCPROTODETACH_IN6 _IOWR('i', 111, struct in6_ifreq) /* detach proto from interface */ 2200#define SIOCPROTOATTACH _IOWR('i', 80, struct ifreq) /* attach proto to interface */ 2201#define SIOCPROTODETACH _IOWR('i', 81, struct ifreq) /* detach proto from interface */ 2202#define SIOCLL_START _IOWR('i', 130, struct in6_aliasreq) /* start aquiring linklocal on interface */ 2203#define SIOCLL_STOP _IOWR('i', 131, struct in6_ifreq) /* deconfigure linklocal from interface */ 2204 2205 s = socket(AF_INET6, SOCK_DGRAM, 0); 2206 if (s < 0) { 2207 error("Can't create IPv6 socket: %m"); 2208 return 0; 2209 } 2210 2211 /* actually, this part is not kame local - RFC2553 conformant */ 2212 ifindex = if_nametoindex(ifname); 2213 if (ifindex == 0) { 2214 error("sifaddr6: no interface %s", ifname); 2215 return 0; 2216 } 2217 2218 strlcpy(ifr6.ifr_name, ifname, sizeof(ifr6.ifr_name)); 2219 if (ioctl(s, SIOCPROTOATTACH_IN6, &ifr6) < 0) { 2220 error("sif6addr: can't attach IPv6 protocol: %m"); 2221 close(s); 2222 return 0; 2223 } 2224 2225 memset(&addreq6, 0, sizeof(addreq6)); 2226 strlcpy(addreq6.ifra_name, ifname, sizeof(addreq6.ifra_name)); 2227 2228 /* my addr */ 2229 addreq6.ifra_addr.sin6_family = AF_INET6; 2230 addreq6.ifra_addr.sin6_len = sizeof(struct sockaddr_in6); 2231 addreq6.ifra_addr.sin6_addr.s6_addr[0] = 0xfe; 2232 addreq6.ifra_addr.sin6_addr.s6_addr[1] = 0x80; 2233 memcpy(&addreq6.ifra_addr.sin6_addr.s6_addr[8], &our_eui64, 2234 sizeof(our_eui64)); 2235 /* KAME ifindex hack */ 2236 *ALIGNED_CAST(u_int16_t *)&addreq6.ifra_addr.sin6_addr.s6_addr[2] = htons(ifindex); 2237 2238 /* his addr */ 2239 addreq6.ifra_dstaddr.sin6_family = AF_INET6; 2240 addreq6.ifra_dstaddr.sin6_len = sizeof(struct sockaddr_in6); 2241 addreq6.ifra_dstaddr.sin6_addr.s6_addr[0] = 0xfe; 2242 addreq6.ifra_dstaddr.sin6_addr.s6_addr[1] = 0x80; 2243 memcpy(&addreq6.ifra_dstaddr.sin6_addr.s6_addr[8], &his_eui64, 2244 sizeof(our_eui64)); 2245 /* KAME ifindex hack */ 2246 *ALIGNED_CAST(u_int16_t *)&addreq6.ifra_dstaddr.sin6_addr.s6_addr[2] = htons(ifindex); 2247 2248 /* prefix mask: 128bit */ 2249 addreq6.ifra_prefixmask.sin6_family = AF_INET6; 2250 addreq6.ifra_prefixmask.sin6_len = sizeof(struct sockaddr_in6); 2251 memset(&addreq6.ifra_prefixmask.sin6_addr, 0xff, 2252 sizeof(addreq6.ifra_prefixmask.sin6_addr)); 2253 2254 /* address lifetime (infty) */ 2255 addreq6.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME; 2256 addreq6.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME; 2257 2258 if (ioctl(s, SIOCLL_START, &addreq6) < 0) { 2259 error("sif6addr: can't set LL address: %m"); 2260 close(s); 2261 return 0; 2262 } 2263 2264 close(s); 2265 2266 return 1; 2267} 2268 2269/* ----------------------------------------------------------------------------- 2270Clear the interface IPv6 addresses 2271 ----------------------------------------------------------------------------- */ 2272int cif6addr (int unit, eui64_t our_eui64, eui64_t his_eui64) 2273{ 2274 int s; 2275 struct ifreq ifr; 2276 struct in6_ifreq ifr6; 2277 2278// XXX from sys/sockio.h 2279#define SIOCPROTOATTACH_IN6 _IOWR('i', 110, struct in6_aliasreq) /* attach proto to interface */ 2280#define SIOCPROTODETACH_IN6 _IOWR('i', 111, struct in6_ifreq) /* detach proto from interface */ 2281#define SIOCPROTOATTACH _IOWR('i', 80, struct ifreq) /* attach proto to interface */ 2282#define SIOCPROTODETACH _IOWR('i', 81, struct ifreq) /* detach proto from interface */ 2283#define SIOCLL_START _IOWR('i', 130, struct in6_aliasreq) /* start aquiring linklocal on interface */ 2284#define SIOCLL_STOP _IOWR('i', 131, struct in6_ifreq) /* deconfigure linklocal from interface */ 2285 2286 s = socket(AF_INET6, SOCK_DGRAM, 0); 2287 if (s < 0) { 2288 error("Can't create IPv6 socket: %m"); 2289 return 0; 2290 } 2291 2292 /* first try old ioctl */ 2293 strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); 2294 if (ioctl(s, SIOCPROTODETACH, &ifr) < 0) { 2295 /* then new ioctl */ 2296 strlcpy(ifr6.ifr_name, ifname, sizeof(ifr6.ifr_name)); 2297 if (ioctl(s, SIOCLL_STOP, &ifr6) < 0) { 2298 warning("Can't stop LL address: %m"); 2299 } 2300 strlcpy(ifr6.ifr_name, ifname, sizeof(ifr6.ifr_name)); 2301 if (ioctl(s, SIOCPROTODETACH_IN6, &ifr6) < 0) { 2302 warning("Can't detach IPv6 protocol: %m"); 2303 } 2304 2305 close(s); 2306 return 0; 2307 } 2308 2309 close(s); 2310 2311 return 1; 2312} 2313 2314/* ----------------------------------------------------------------------------- 2315Returns an iterator containing the primary (built-in) Ethernet interface. 2316The caller is responsible for releasing the iterator after the caller is done with it. 2317 ----------------------------------------------------------------------------- */ 2318static kern_return_t FindPrimaryEthernetInterfaces(io_iterator_t *matchingServices) 2319{ 2320 kern_return_t kernResult; 2321 CFMutableDictionaryRef matchingDict; 2322 CFMutableDictionaryRef propertyMatchDict; 2323 2324 // Ethernet interfaces are instances of class kIOEthernetInterfaceClass. 2325 // IOServiceMatching is a convenience function to create a dictionary with the key kIOProviderClassKey and 2326 // the specified value. 2327 matchingDict = IOServiceMatching(kIOEthernetInterfaceClass); 2328 if (matchingDict) { 2329 2330 // Each IONetworkInterface object has a Boolean property with the key kIOPrimaryInterface. Only the 2331 // primary (built-in) interface has this property set to TRUE. 2332 2333 // IOServiceGetMatchingServices uses the default matching criteria defined by IOService. This considers 2334 // only the following properties plus any family-specific matching in this order of precedence 2335 // (see IOService::passiveMatch): 2336 // 2337 // kIOProviderClassKey (IOServiceMatching) 2338 // kIONameMatchKey (IOServiceNameMatching) 2339 // kIOPropertyMatchKey 2340 // kIOPathMatchKey 2341 // kIOMatchedServiceCountKey 2342 // family-specific matching 2343 // kIOBSDNameKey (IOBSDNameMatching) 2344 // kIOLocationMatchKey 2345 2346 // The IONetworkingFamily does not define any family-specific matching. This means that in 2347 // order to have IOServiceGetMatchingServices consider the kIOPrimaryInterface property, we must 2348 // add that property to a separate dictionary and then add that to our matching dictionary 2349 // specifying kIOPropertyMatchKey. 2350 2351 propertyMatchDict = CFDictionaryCreateMutable( kCFAllocatorDefault, 0, 2352 &kCFTypeDictionaryKeyCallBacks, 2353 &kCFTypeDictionaryValueCallBacks); 2354 if (propertyMatchDict) { 2355 2356 // Set the value in the dictionary of the property with the given key, or add the key 2357 // to the dictionary if it doesn't exist. This call retains the value object passed in. 2358 CFDictionarySetValue(propertyMatchDict, CFSTR(kIOPrimaryInterface), kCFBooleanTrue); 2359 2360 // Now add the dictionary containing the matching value for kIOPrimaryInterface to our main 2361 // matching dictionary. This call will retain propertyMatchDict, so we can release our reference 2362 // on propertyMatchDict after adding it to matchingDict. 2363 CFDictionarySetValue(matchingDict, CFSTR(kIOPropertyMatchKey), propertyMatchDict); 2364 CFRelease(propertyMatchDict); 2365 } 2366 } 2367 2368 // IOServiceGetMatchingServices retains the returned iterator, so release the iterator when we're done with it. 2369 // IOServiceGetMatchingServices also consumes a reference on the matching dictionary so we don't need to release 2370 // the dictionary explicitly. 2371 kernResult = IOServiceGetMatchingServices(kIOMasterPortDefault, matchingDict, matchingServices); 2372 2373 return kernResult; 2374} 2375 2376/* ----------------------------------------------------------------------------- 2377Get the mac address of the primary interface 2378----------------------------------------------------------------------------- */ 2379static kern_return_t GetPrimaryMACAddress(UInt8 *MACAddress) 2380{ 2381 io_object_t intfService; 2382 io_object_t controllerService; 2383 kern_return_t kernResult = KERN_FAILURE; 2384 io_iterator_t intfIterator; 2385 2386 kernResult = FindPrimaryEthernetInterfaces(&intfIterator); 2387 if (kernResult != KERN_SUCCESS) 2388 return kernResult; 2389 2390 // Initialize the returned address 2391 bzero(MACAddress, kIOEthernetAddressSize); 2392 2393 // IOIteratorNext retains the returned object, so release it when we're done with it. 2394 while ((intfService = IOIteratorNext(intfIterator))) { 2395 2396 CFTypeRef MACAddressAsCFData; 2397 2398 // IONetworkControllers can't be found directly by the IOServiceGetMatchingServices call, 2399 // since they are hardware nubs and do not participate in driver matching. In other words, 2400 // registerService() is never called on them. So we've found the IONetworkInterface and will 2401 // get its parent controller by asking for it specifically. 2402 2403 // IORegistryEntryGetParentEntry retains the returned object, so release it when we're done with it. 2404 kernResult = IORegistryEntryGetParentEntry( intfService, 2405 kIOServicePlane, 2406 &controllerService ); 2407 2408 if (kernResult == KERN_SUCCESS) { 2409 2410 // Retrieve the MAC address property from the I/O Registry in the form of a CFData 2411 MACAddressAsCFData = IORegistryEntryCreateCFProperty( controllerService, 2412 CFSTR(kIOMACAddress), 2413 kCFAllocatorDefault, 0); 2414 if (MACAddressAsCFData) { 2415 // Get the raw bytes of the MAC address from the CFData 2416 CFDataGetBytes(MACAddressAsCFData, CFRangeMake(0, kIOEthernetAddressSize), MACAddress); 2417 CFRelease(MACAddressAsCFData); 2418 } 2419 2420 // Done with the parent Ethernet controller object so we release it. 2421 IOObjectRelease(controllerService); 2422 } 2423 2424 // Done with the Ethernet interface object so we release it. 2425 IOObjectRelease(intfService); 2426 } 2427 2428 IOObjectRelease(intfIterator); 2429 2430 return kernResult; 2431} 2432 2433/* ----------------------------------------------------------------------------- 2434Convert 48-bit Ethernet address into 64-bit EUI 2435 ----------------------------------------------------------------------------- */ 2436int 2437ether_to_eui64(eui64_t *p_eui64) 2438{ 2439 static u_int8_t allzero[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; 2440 static u_int8_t allone[8] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; 2441 kern_return_t err; 2442 UInt8 addr[kIOEthernetAddressSize]; 2443 2444 err = GetPrimaryMACAddress(addr); 2445 if (err != KERN_SUCCESS) { 2446 warning("Can't get hardware interface address for en0 (error = %d)\n", err); 2447 return 0; 2448 } 2449 2450 /* check for invalid MAC address */ 2451 if (bcmp(addr, allzero, ETHER_ADDR_LEN) == 0) 2452 return 0; 2453 if (bcmp(addr, allone, ETHER_ADDR_LEN) == 0) 2454 return 0; 2455 2456 /* And convert the EUI-48 into EUI-64, per RFC 2472 [sec 4.1] */ 2457 p_eui64->e8[0] = addr[0] | 0x02; 2458 p_eui64->e8[1] = addr[1]; 2459 p_eui64->e8[2] = addr[2]; 2460 p_eui64->e8[3] = 0xFF; 2461 p_eui64->e8[4] = 0xFE; 2462 p_eui64->e8[5] = addr[3]; 2463 p_eui64->e8[6] = addr[4]; 2464 p_eui64->e8[7] = addr[5]; 2465 2466 return 1; 2467} 2468 2469#endif 2470 2471/* ---------------------------------------------------------------------------- 2472 Create a "NULL Service" primary IPv6 dictionary for the dynamic store. This 2473 prevents any other service from becoming primary on IPv6. 2474 ----------------------------------------------------------------------------- */ 2475#ifndef kIsNULL 2476#define kIsNULL CFSTR("IsNULL") /* CFBoolean */ 2477#endif 2478void ppp_create_ipv6_dummy_primary(Boolean uninstall) 2479{ 2480 CFMutableArrayRef array; 2481 CFMutableDictionaryRef ipv6_dict; 2482 int isprimary = 1; 2483 CFStringRef key; 2484 CFNumberRef num; 2485 CFStringRef str; 2486 2487 if (noipv6override || cfgCache == NULL || serviceidRef == NULL) 2488 return; 2489 2490 if ((key = SCDynamicStoreKeyCreateNetworkServiceEntity(0, kSCDynamicStoreDomainState, serviceidRef, kSCEntNetIPv6))) { 2491 if (uninstall) { 2492 unpublish_dict(key); 2493 } else { 2494 /* create the IPv6 dictionnary */ 2495 if ((ipv6_dict = CFDictionaryCreateMutable(0, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks))) { 2496 if ((array = CFArrayCreateMutable(0, 1, &kCFTypeArrayCallBacks))) { 2497 CFArrayAppendValue(array, CFSTR("::1")); 2498 CFDictionarySetValue(ipv6_dict, kSCPropNetIPv6Addresses, array); 2499 CFRelease(array); 2500 } 2501 2502 CFDictionarySetValue(ipv6_dict, kSCPropNetIPv6Router, CFSTR("::1")); 2503 2504 num = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &isprimary); 2505 if (num) { 2506 CFDictionarySetValue(ipv6_dict, kSCPropNetOverridePrimary, num); 2507 CFRelease(num); 2508 } 2509 2510 CFDictionarySetValue(ipv6_dict, kIsNULL, kCFBooleanTrue); 2511 2512 if (ifname) { 2513 if ((str = CFStringCreateWithFormat(NULL, NULL, CFSTR("%s"), ifname))) { 2514 CFDictionarySetValue(ipv6_dict, kSCPropInterfaceName, str); 2515 CFRelease(str); 2516 } 2517 } 2518 2519 update_publish_dict(key, ipv6_dict); 2520 CFRelease(ipv6_dict); 2521 } 2522 } 2523 2524 CFRelease(key); 2525 } 2526 2527 return; 2528} 2529 2530/* ----------------------------------------------------------------------------- 2531assign a default route through the address given 2532----------------------------------------------------------------------------- */ 2533int sifdefaultroute(int u, u_int32_t l, u_int32_t g) 2534{ 2535 override_primary = 1; 2536 ppp_create_ipv6_dummy_primary(FALSE); 2537 return publish_dictnumentry(kSCEntNetIPv4, kSCPropNetOverridePrimary, 1); 2538} 2539 2540/* ----------------------------------------------------------------------------- 2541delete a default route through the address given 2542----------------------------------------------------------------------------- */ 2543int cifdefaultroute(int u, u_int32_t l, u_int32_t g) 2544{ 2545 override_primary = 0; 2546 ppp_create_ipv6_dummy_primary(TRUE); 2547 return unpublish_dictentry(kSCEntNetIPv4, kSCPropNetOverridePrimary); 2548} 2549 2550/* ---------------------------------------------------------------------------- 2551 update ip addresses using configd cache mechanism 2552 use new state information model 2553 ----------------------------------------------------------------------------- */ 2554static int update_stateaddr(u_int32_t o, u_int32_t h, u_int32_t m) 2555{ 2556 struct in_addr addr; 2557 CFMutableArrayRef array; 2558 CFMutableDictionaryRef ipv4_dict; 2559 CFStringRef str; 2560 CFStringRef key; 2561 2562 // ppp daemons without services are not published in the cache 2563 if (cfgCache == NULL) 2564 return 0; 2565 2566 /* update the store now */ 2567 if ((key = SCDynamicStoreKeyCreateNetworkServiceEntity(0, kSCDynamicStoreDomainState, serviceidRef, kSCEntNetIPv4))) { 2568 CFPropertyListRef ref; 2569 if ((ref = SCDynamicStoreCopyValue(cfgCache, key)) == NULL || 2570 CFGetTypeID(ref) != CFDictionaryGetTypeID()) { 2571 warning("SCDynamicStoreCopyValue IP %s failed: %s\n", ifname, SCErrorString(SCError())); 2572 if (ref) { 2573 CFRelease(ref); 2574 } 2575 CFRelease(key); 2576 return 0; 2577 } 2578 ipv4_dict = CFDictionaryCreateMutableCopy(NULL, 0, ref); 2579 CFRelease(ref); 2580 if (!ipv4_dict || CFGetTypeID(ipv4_dict) != CFDictionaryGetTypeID()) { 2581 warning("CFDictionaryCreateMutableCopy IP %s failed: %s\n", ifname, SCErrorString(SCError())); 2582 if (ipv4_dict) { 2583 CFRelease(ipv4_dict); 2584 } 2585 CFRelease(key); 2586 return 0; 2587 } 2588 } else { 2589 return 0; 2590 } 2591 2592 /* set the ip address src and dest arrays */ 2593 if ((array = CFArrayCreateMutable(0, 1, &kCFTypeArrayCallBacks))) { 2594 addr.s_addr = o; 2595 if ((str = CFStringCreateWithFormat(0, 0, CFSTR(IP_FORMAT), IP_LIST(&addr.s_addr)))) { 2596 CFArrayAppendValue(array, str); 2597 CFRelease(str); 2598 CFDictionarySetValue(ipv4_dict, kSCPropNetIPv4Addresses, array); 2599 } 2600 CFRelease(array); 2601 } 2602 2603 if ((array = CFArrayCreateMutable(0, 1, &kCFTypeArrayCallBacks))) { 2604 addr.s_addr = h; 2605 if ((str = CFStringCreateWithFormat(NULL, NULL, CFSTR(IP_FORMAT), IP_LIST(&addr.s_addr)))) { 2606 CFArrayAppendValue(array, str); 2607 CFRelease(str); 2608 CFDictionarySetValue(ipv4_dict, kSCPropNetIPv4DestAddresses, array); 2609 } 2610 CFRelease(array); 2611 } 2612 2613 /* set the router */ 2614 addr.s_addr = h; 2615 if ((str = CFStringCreateWithFormat(NULL, NULL, CFSTR(IP_FORMAT), IP_LIST(&addr.s_addr)))) { 2616 CFDictionarySetValue(ipv4_dict, kSCPropNetIPv4Router, str); 2617 CFRelease(str); 2618 } 2619 2620 /* add the interface name */ 2621 if ((str = CFStringCreateWithFormat(NULL, NULL, CFSTR("%s"), ifname))) { 2622 CFDictionarySetValue(ipv4_dict, kSCPropInterfaceName, str); 2623 CFRelease(str); 2624 } 2625 2626 /* add the network signature */ 2627 if (network_signature) { 2628 if ((str = CFStringCreateWithFormat(NULL, NULL, CFSTR("%s"), network_signature))) { 2629 CFDictionarySetValue(ipv4_dict, CFSTR("NetworkSignature"), str); 2630 CFRelease(str); 2631 } 2632 } 2633 2634 /* add the remote server peer address */ 2635 if (server_peer) { 2636 CFDictionarySetValue(ipv4_dict, CFSTR("ServerAddress"), server_peer); 2637 } 2638 2639 2640 if (update_publish_dict(key, ipv4_dict) == 0) 2641 warning("SCDynamicStoreSetValue IP %s failed: %s\n", ifname, SCErrorString(SCError())); 2642 2643 CFRelease(ipv4_dict); 2644 CFRelease(key); 2645 return 1; 2646} 2647 2648/* ---------------------------------------------------------------------------- 2649publish ip addresses using configd cache mechanism 2650use new state information model 2651----------------------------------------------------------------------------- */ 2652int publish_stateaddr(u_int32_t o, u_int32_t h, u_int32_t m) 2653{ 2654 struct in_addr addr; 2655 CFMutableArrayRef array; 2656 CFMutableDictionaryRef ipv4_dict; 2657 CFStringRef str; 2658 2659 // ppp daemons without services are not published in the cache 2660 if (cfgCache == NULL) 2661 return 0; 2662 2663 /* create the IPV4 dictionnary */ 2664 if ((ipv4_dict = CFDictionaryCreateMutable(0, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks)) == 0) 2665 return 0; 2666 2667 /* set the ip address src and dest arrays */ 2668 if ((array = CFArrayCreateMutable(0, 1, &kCFTypeArrayCallBacks))) { 2669 addr.s_addr = o; 2670 if ((str = CFStringCreateWithFormat(0, 0, CFSTR(IP_FORMAT), IP_LIST(&addr.s_addr)))) { 2671 CFArrayAppendValue(array, str); 2672 CFRelease(str); 2673 CFDictionarySetValue(ipv4_dict, kSCPropNetIPv4Addresses, array); 2674 } 2675 CFRelease(array); 2676 } 2677 2678 if ((array = CFArrayCreateMutable(0, 1, &kCFTypeArrayCallBacks))) { 2679 addr.s_addr = h; 2680 if ((str = CFStringCreateWithFormat(NULL, NULL, CFSTR(IP_FORMAT), IP_LIST(&addr.s_addr)))) { 2681 CFArrayAppendValue(array, str); 2682 CFRelease(str); 2683 CFDictionarySetValue(ipv4_dict, kSCPropNetIPv4DestAddresses, array); 2684 } 2685 CFRelease(array); 2686 } 2687 2688 /* set the router */ 2689 addr.s_addr = h; 2690 if ((str = CFStringCreateWithFormat(NULL, NULL, CFSTR(IP_FORMAT), IP_LIST(&addr.s_addr)))) { 2691 CFDictionarySetValue(ipv4_dict, kSCPropNetIPv4Router, str); 2692 CFRelease(str); 2693 } 2694 2695 /* add the interface name */ 2696 if ((str = CFStringCreateWithFormat(NULL, NULL, CFSTR("%s"), ifname))) { 2697 CFDictionarySetValue(ipv4_dict, kSCPropInterfaceName, str); 2698 CFRelease(str); 2699 } 2700 2701 /* add the network signature */ 2702 if (network_signature) { 2703 if ((str = CFStringCreateWithFormat(NULL, NULL, CFSTR("%s"), network_signature))) { 2704 CFDictionarySetValue(ipv4_dict, CFSTR("NetworkSignature"), str); 2705 CFRelease(str); 2706 } 2707 } 2708 2709 /* add the remote server peer address */ 2710 if (server_peer) { 2711 CFDictionarySetValue(ipv4_dict, CFSTR("ServerAddress"), server_peer); 2712 } 2713 2714 /* update the store now */ 2715 if ((str = SCDynamicStoreKeyCreateNetworkServiceEntity(0, kSCDynamicStoreDomainState, serviceidRef, kSCEntNetIPv4))) { 2716 2717 if (update_publish_dict(str, ipv4_dict) == 0) 2718 warning("SCDynamicStoreSetValue IP %s failed: %s\n", ifname, SCErrorString(SCError())); 2719 2720 CFRelease(str); 2721 } 2722 2723 CFRelease(ipv4_dict); 2724 return 1; 2725} 2726 2727/* ----------------------------------------------------------------------------- 2728 add a search domain, using configd cache mechanism. 2729----------------------------------------------------------------------------- */ 2730int publish_dns_wins_entry(CFStringRef entity, CFStringRef property1, CFTypeRef ref1, CFTypeRef ref1a, 2731 CFStringRef property2, CFTypeRef ref2, 2732 CFStringRef property3, CFTypeRef ref3, int clean) 2733{ 2734 CFMutableArrayRef mutable_array; 2735 CFArrayRef array = NULL; 2736 CFMutableDictionaryRef dict = NULL; 2737 CFStringRef key = NULL; 2738 CFPropertyListRef ref; 2739 int ret = 0; 2740 2741 if (publish_dict == NULL && cfgCache == NULL) 2742 return 0; 2743 2744 key = SCDynamicStoreKeyCreateNetworkServiceEntity(0, kSCDynamicStoreDomainState, serviceidRef, entity); 2745 if (!key) 2746 goto end; 2747 2748 if (publish_dict) { 2749 if ((ref = CFDictionaryGetValue(publish_dict, key))) { 2750 dict = CFDictionaryCreateMutableCopy(0, 0, ref); 2751 } 2752 else 2753 dict = CFDictionaryCreateMutable(0, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); 2754 } 2755 else if ((ref = SCDynamicStoreCopyValue(cfgCache, key))) { 2756 dict = CFDictionaryCreateMutableCopy(0, 0, ref); 2757 CFRelease(ref); 2758 } else 2759 dict = CFDictionaryCreateMutable(0, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); 2760 2761 if (!dict || (CFGetTypeID(dict) != CFDictionaryGetTypeID())) 2762 goto end; 2763 2764 if (!clean) 2765 array = CFDictionaryGetValue(dict, property1); 2766 if (array && (CFGetTypeID(array) == CFArrayGetTypeID())) 2767 mutable_array = CFArrayCreateMutableCopy(NULL, CFArrayGetCount(array) + 1, array); 2768 else 2769 mutable_array = CFArrayCreateMutable(NULL, 1, &kCFTypeArrayCallBacks); 2770 2771 if (!mutable_array) 2772 goto end; 2773 2774 CFArrayAppendValue(mutable_array, ref1); 2775 if (ref1a) 2776 CFArrayAppendValue(mutable_array, ref1a); 2777 CFDictionarySetValue(dict, property1, mutable_array); 2778 CFRelease(mutable_array); 2779 2780 if (property2) { 2781 if (!clean) 2782 array = CFDictionaryGetValue(dict, property2); 2783 if (array && (CFGetTypeID(array) == CFArrayGetTypeID())) 2784 mutable_array = CFArrayCreateMutableCopy(NULL, CFArrayGetCount(array) + 1, array); 2785 else 2786 mutable_array = CFArrayCreateMutable(NULL, 1, &kCFTypeArrayCallBacks); 2787 2788 if (!mutable_array) 2789 goto end; 2790 2791 CFArrayAppendValue(mutable_array, ref2); 2792 CFDictionarySetValue(dict, property2, mutable_array); 2793 CFRelease(mutable_array); 2794 } 2795 2796 if (property3) { 2797 if (!clean) 2798 array = CFDictionaryGetValue(dict, property3); 2799 if (array && (CFGetTypeID(array) == CFArrayGetTypeID())) 2800 mutable_array = CFArrayCreateMutableCopy(NULL, CFArrayGetCount(array) + 1, array); 2801 else 2802 mutable_array = CFArrayCreateMutable(NULL, 1, &kCFTypeArrayCallBacks); 2803 2804 if (!mutable_array) 2805 goto end; 2806 2807 CFArrayAppendValue(mutable_array, ref3); 2808 CFDictionarySetValue(dict, property3, mutable_array); 2809 CFRelease(mutable_array); 2810 } 2811 2812 if (update_publish_dict(key,dict)) 2813 ret = 1; 2814 else 2815 warning("SCDynamicStoreSetValue DNS/WINS %s failed: %s\n", ifname, SCErrorString(SCError())); 2816 2817end: 2818 if (key) 2819 CFRelease(key); 2820 if (dict) 2821 CFRelease(dict); 2822 return ret; 2823} 2824 2825 2826/* ----------------------------------------------------------------------------- 2827set dns information 2828----------------------------------------------------------------------------- */ 2829int sifdns(u_int32_t dns1, u_int32_t dns2) 2830{ 2831 CFStringRef str1 = 0, str2 = 0, strname = 0; 2832 int result = 0, clean = 1; 2833 long order = 100000; 2834 CFNumberRef num = 0; 2835 2836 num = CFNumberCreate(NULL, kCFNumberLongType, &order); 2837 if (!num) 2838 goto done; 2839 2840 strname = CFStringCreateWithCString(NULL, "", kCFStringEncodingUTF8); 2841 if (!strname) 2842 goto done; 2843 2844 /* warn lookupd of upcoming change */ 2845 notify_post("com.apple.system.dns.delay"); 2846 2847 if (dns1) 2848 str1 = CFStringCreateWithFormat(NULL, NULL, CFSTR(IP_FORMAT), IP_LIST(&dns1)); 2849 if (!str1) 2850 goto done; 2851 2852 if (dns2 && (dns2!=dns1)) 2853 str2 = CFStringCreateWithFormat(NULL, NULL, CFSTR(IP_FORMAT), IP_LIST(&dns2)); 2854 2855 result = publish_dns_wins_entry(kSCEntNetDNS, kSCPropNetDNSServerAddresses, str1, str2, kSCPropNetDNSSupplementalMatchDomains, strname, kSCPropNetDNSSupplementalMatchOrders, num, clean); 2856#ifndef kSCPropNetProxiesSupplementalMatchDomains 2857#define kSCPropNetProxiesSupplementalMatchDomains kSCPropNetDNSSupplementalMatchDomains 2858#define kSCPropNetProxiesSupplementalMatchOrders kSCPropNetDNSSupplementalMatchOrders 2859#endif 2860 if (result) publish_dns_wins_entry(kSCEntNetProxies, kSCPropNetProxiesSupplementalMatchDomains, strname, 0, kSCPropNetProxiesSupplementalMatchOrders, num, 0, 0, clean); 2861 2862done: 2863 if (num) 2864 CFRelease(num); 2865 if (str1) 2866 CFRelease(str1); 2867 if (str2) 2868 CFRelease(str2); 2869 if (strname) 2870 CFRelease(strname); 2871 2872 return result; 2873} 2874 2875/* ----------------------------------------------------------------------------- 2876set wins information 2877----------------------------------------------------------------------------- */ 2878int sifwins(u_int32_t wins1, u_int32_t wins2) 2879{ 2880#if !TARGET_OS_EMBEDDED 2881 CFStringRef str1 = 0, str2 = 0; 2882 int result = 0, clean = 1; 2883 2884 if (wins1) 2885 str1 = CFStringCreateWithFormat(NULL, NULL, CFSTR(IP_FORMAT), IP_LIST(&wins1)); 2886 if (!str1) 2887 goto done; 2888 2889 if (wins2) 2890 str2 = CFStringCreateWithFormat(NULL, NULL, CFSTR(IP_FORMAT), IP_LIST(&wins2)); 2891 2892 result = publish_dns_wins_entry(kSCEntNetSMB, kSCPropNetSMBWINSAddresses, str1, str2, 0, 0, 0, 0, clean); 2893 2894done: 2895 if (str1) 2896 CFRelease(str1); 2897 if (str2) 2898 CFRelease(str2); 2899 2900 return result; 2901#else 2902 return 0; 2903#endif 2904} 2905 2906static struct { 2907 struct rt_msghdr hdr; 2908 struct sockaddr_inarp dst; 2909 struct sockaddr_dl hwa; 2910 char extra[128]; 2911} arpmsg; 2912 2913static int arpmsg_valid; 2914 2915/* ----------------------------------------------------------------------------- 2916Make a proxy ARP entry for the peer 2917----------------------------------------------------------------------------- */ 2918int sifproxyarp(int unit, u_int32_t hisaddr) 2919{ 2920 int routes; 2921 2922 /* 2923 * Get the hardware address of an interface on the same subnet 2924 * as our local address. 2925 */ 2926 memset(&arpmsg, 0, sizeof(arpmsg)); 2927 if (!get_ether_addr(hisaddr, &arpmsg.hwa)) { 2928 error("Cannot determine ethernet address for proxy ARP"); 2929 return 0; 2930 } 2931 2932 if ((routes = socket(PF_ROUTE, SOCK_RAW, PF_ROUTE)) < 0) { 2933 error("Couldn't add proxy arp entry: socket: %m"); 2934 return 0; 2935 } 2936 2937 arpmsg.hdr.rtm_type = RTM_ADD; 2938 arpmsg.hdr.rtm_flags = RTF_ANNOUNCE | RTF_HOST | RTF_STATIC; 2939 arpmsg.hdr.rtm_version = RTM_VERSION; 2940 arpmsg.hdr.rtm_seq = ++rtm_seq; 2941 arpmsg.hdr.rtm_addrs = RTA_DST | RTA_GATEWAY; 2942 arpmsg.hdr.rtm_inits = RTV_EXPIRE; 2943 arpmsg.dst.sin_len = sizeof(struct sockaddr_inarp); 2944 arpmsg.dst.sin_family = AF_INET; 2945 arpmsg.dst.sin_addr.s_addr = hisaddr; 2946 arpmsg.dst.sin_other = SIN_PROXY; 2947 2948 arpmsg.hdr.rtm_msglen = (char *) &arpmsg.hwa - (char *) &arpmsg 2949 + arpmsg.hwa.sdl_len; 2950 if (write(routes, &arpmsg, arpmsg.hdr.rtm_msglen) < 0) { 2951 error("Couldn't add proxy arp entry: %m"); 2952 close(routes); 2953 return 0; 2954 } 2955 2956 close(routes); 2957 arpmsg_valid = 1; 2958 proxy_arp_addr = hisaddr; 2959 return 1; 2960} 2961 2962/* ----------------------------------------------------------------------------- 2963Delete the proxy ARP entry for the peer 2964----------------------------------------------------------------------------- */ 2965int cifproxyarp(int unit, u_int32_t hisaddr) 2966{ 2967 int routes; 2968 2969 if (!arpmsg_valid) 2970 return 0; 2971 arpmsg_valid = 0; 2972 2973 arpmsg.hdr.rtm_type = RTM_DELETE; 2974 arpmsg.hdr.rtm_seq = ++rtm_seq; 2975 2976 if ((routes = socket(PF_ROUTE, SOCK_RAW, PF_ROUTE)) < 0) { 2977 error("Couldn't delete proxy arp entry: socket: %m"); 2978 return 0; 2979 } 2980 2981 if (write(routes, &arpmsg, arpmsg.hdr.rtm_msglen) < 0) { 2982 error("Couldn't delete proxy arp entry: %m"); 2983 close(routes); 2984 return 0; 2985 } 2986 2987 close(routes); 2988 proxy_arp_addr = 0; 2989 return 1; 2990} 2991 2992#define MAX_IFS 32 2993 2994/* ----------------------------------------------------------------------------- 2995get the hardware address of an interface on the 2996 * the same subnet as ipaddr. 2997----------------------------------------------------------------------------- */ 2998static int get_ether_addr(u_int32_t ipaddr, struct sockaddr_dl *hwaddr) 2999{ 3000 struct ifreq *ifr, *ifend, *ifp; 3001 u_int32_t ina, mask; 3002 struct sockaddr_dl *dla; 3003 struct ifreq ifreq; 3004 struct ifconf ifc; 3005 struct ifreq ifs[MAX_IFS]; 3006 3007 ifc.ifc_len = sizeof(ifs); 3008 ifc.ifc_req = ifs; 3009 if (ioctl(ip_sockfd, SIOCGIFCONF, &ifc) < 0) { 3010 error("ioctl(SIOCGIFCONF): %m"); 3011 return 0; 3012 } 3013 3014 /* 3015 * Scan through looking for an interface with an Internet 3016 * address on the same subnet as `ipaddr'. 3017 */ 3018 ifend = ALIGNED_CAST(struct ifreq *) (ifc.ifc_buf + ifc.ifc_len); 3019 for (ifr = ifc.ifc_req; ifr < ifend; ifr = ALIGNED_CAST(struct ifreq *) 3020 ((char *)&ifr->ifr_addr + ifr->ifr_addr.sa_len)) { 3021 if (ifr->ifr_addr.sa_family == AF_INET) { 3022 ina = (ALIGNED_CAST(struct sockaddr_in *) &ifr->ifr_addr)->sin_addr.s_addr; 3023 strlcpy(ifreq.ifr_name, ifr->ifr_name, sizeof(ifreq.ifr_name)); 3024 /* 3025 * Check that the interface is up, and not point-to-point 3026 * or loopback. 3027 */ 3028 if (ioctl(ip_sockfd, SIOCGIFFLAGS, &ifreq) < 0) 3029 continue; 3030 if ((ifreq.ifr_flags & 3031 (IFF_UP|IFF_BROADCAST|IFF_POINTOPOINT|IFF_LOOPBACK|IFF_NOARP)) 3032 != (IFF_UP|IFF_BROADCAST)) 3033 continue; 3034 /* 3035 * Get its netmask and check that it's on the right subnet. 3036 */ 3037 if (ioctl(ip_sockfd, SIOCGIFNETMASK, &ifreq) < 0) 3038 continue; 3039 mask = (ALIGNED_CAST(struct sockaddr_in *) &ifreq.ifr_addr)->sin_addr.s_addr; 3040 if ((ipaddr & mask) != (ina & mask)) 3041 continue; 3042 3043 break; 3044 } 3045 } 3046 3047 if (ifr >= ifend) 3048 return 0; 3049 info("found interface %s for proxy arp", ifr->ifr_name); 3050 3051 /* 3052 * Now scan through again looking for a link-level address 3053 * for this interface. 3054 */ 3055 ifp = ifr; 3056 for (ifr = ifc.ifc_req; ifr < ifend; ) { 3057 if (strcmp(ifp->ifr_name, ifr->ifr_name) == 0 3058 && ifr->ifr_addr.sa_family == AF_LINK) { 3059 /* 3060 * Found the link-level address - copy it out 3061 */ 3062 dla = ALIGNED_CAST(struct sockaddr_dl *) &ifr->ifr_addr; 3063 BCOPY(dla, hwaddr, dla->sdl_len); 3064 return 1; 3065 } 3066 ifr = ALIGNED_CAST(struct ifreq *) ((char *)&ifr->ifr_addr + ifr->ifr_addr.sa_len); 3067 } 3068 3069 return 0; 3070} 3071 3072/* ----------------------------------------------------------------------------- 3073 * Return user specified netmask, modified by any mask we might determine 3074 * for address `addr' (in network byte order). 3075 * Here we scan through the system's list of interfaces, looking for 3076 * any non-point-to-point interfaces which might appear to be on the same 3077 * network as `addr'. If we find any, we OR in their netmask to the 3078 * user-specified netmask. 3079----------------------------------------------------------------------------- */ 3080u_int32_t GetMask(u_int32_t addr) 3081{ 3082 u_int32_t mask, nmask, ina; 3083 struct ifreq *ifr, *ifend, ifreq; 3084 struct ifconf ifc; 3085 struct ifreq ifs[MAX_IFS]; 3086 3087 addr = ntohl(addr); 3088 if (IN_CLASSA(addr)) /* determine network mask for address class */ 3089 nmask = IN_CLASSA_NET; 3090 else if (IN_CLASSB(addr)) 3091 nmask = IN_CLASSB_NET; 3092 else 3093 nmask = IN_CLASSC_NET; 3094 /* class D nets are disallowed by bad_ip_adrs */ 3095 mask = netmask | htonl(nmask); 3096 3097 /* 3098 * Scan through the system's network interfaces. 3099 */ 3100 ifc.ifc_len = sizeof(ifs); 3101 ifc.ifc_req = ifs; 3102 if (ioctl(ip_sockfd, SIOCGIFCONF, &ifc) < 0) { 3103 warning("ioctl(SIOCGIFCONF): %m"); 3104 return mask; 3105 } 3106 ifend = ALIGNED_CAST(struct ifreq *) (ifc.ifc_buf + ifc.ifc_len); 3107 for (ifr = ifc.ifc_req; ifr < ifend; ifr = ALIGNED_CAST(struct ifreq *) 3108 ((char *)&ifr->ifr_addr + ifr->ifr_addr.sa_len)) { 3109 /* 3110 * Check the interface's internet address. 3111 */ 3112 if (ifr->ifr_addr.sa_family != AF_INET) 3113 continue; 3114 ina = (ALIGNED_CAST(struct sockaddr_in *) &ifr->ifr_addr)->sin_addr.s_addr; 3115 if ((ntohl(ina) & nmask) != (addr & nmask)) 3116 continue; 3117 /* 3118 * Check that the interface is up, and not point-to-point or loopback. 3119 */ 3120 strlcpy(ifreq.ifr_name, ifr->ifr_name, sizeof(ifreq.ifr_name)); 3121 if (ioctl(ip_sockfd, SIOCGIFFLAGS, &ifreq) < 0) 3122 continue; 3123 if ((ifreq.ifr_flags & (IFF_UP|IFF_POINTOPOINT|IFF_LOOPBACK)) 3124 != IFF_UP) 3125 continue; 3126 /* 3127 * Get its netmask and OR it into our mask. 3128 */ 3129 if (ioctl(ip_sockfd, SIOCGIFNETMASK, &ifreq) < 0) 3130 continue; 3131 mask |= (ALIGNED_CAST(struct sockaddr_in *)&ifreq.ifr_addr)->sin_addr.s_addr; 3132 } 3133 3134 return mask; 3135} 3136 3137/* ----------------------------------------------------------------------------- 3138determine if the system has any route to 3139 * a given IP address. 3140 * For demand mode to work properly, we have to ignore routes 3141 * through our own interface. 3142 ----------------------------------------------------------------------------- */ 3143int have_route_to(u_int32_t addr) 3144{ 3145 return -1; 3146} 3147 3148/* ----------------------------------------------------------------------------- 3149Use the hostid as part of the random number seed 3150----------------------------------------------------------------------------- */ 3151int get_host_seed() 3152{ 3153 return gethostid(); 3154} 3155 3156 3157#if 0 3158 3159#define LOCK_PREFIX "/var/spool/lock/LCK.." 3160 3161static char *lock_file; /* name of lock file created */ 3162 3163/* ----------------------------------------------------------------------------- 3164create a lock file for the named lock device 3165----------------------------------------------------------------------------- */ 3166int lock(char *dev) 3167{ 3168 char hdb_lock_buffer[12]; 3169 int fd, pid, n; 3170 char *p; 3171 size_t l; 3172 3173 if ((p = strrchr(dev, '/')) != NULL) 3174 dev = p + 1; 3175 l = strlen(LOCK_PREFIX) + strlen(dev) + 1; 3176 lock_file = malloc(l); 3177 if (lock_file == NULL) 3178 novm("lock file name"); 3179 slprintf(lock_file, l, "%s%s", LOCK_PREFIX, dev); 3180 3181 while ((fd = open(lock_file, O_EXCL | O_CREAT | O_RDWR, 0644)) < 0) { 3182 if (errno == EEXIST 3183 && (fd = open(lock_file, O_RDONLY, 0)) >= 0) { 3184 /* Read the lock file to find out who has the device locked */ 3185 n = read(fd, hdb_lock_buffer, 11); 3186 if (n <= 0) { 3187 error("Can't read pid from lock file %s", lock_file); 3188 close(fd); 3189 } else { 3190 hdb_lock_buffer[n] = 0; 3191 pid = atoi(hdb_lock_buffer); 3192 if (kill(pid, 0) == -1 && errno == ESRCH) { 3193 /* pid no longer exists - remove the lock file */ 3194 if (unlink(lock_file) == 0) { 3195 close(fd); 3196 notice("Removed stale lock on %s (pid %d)", 3197 dev, pid); 3198 continue; 3199 } else 3200 warning("Couldn't remove stale lock on %s", 3201 dev); 3202 } else 3203 notice("Device %s is locked by pid %d", 3204 dev, pid); 3205 } 3206 close(fd); 3207 } else 3208 error("Can't create lock file %s: %m", lock_file); 3209 free(lock_file); 3210 lock_file = NULL; 3211 return -1; 3212 } 3213 3214 slprintf(hdb_lock_buffer, sizeof(hdb_lock_buffer), "%10d\n", getpid()); 3215 write(fd, hdb_lock_buffer, 11); 3216 3217 close(fd); 3218 return 0; 3219} 3220 3221/* ----------------------------------------------------------------------------- 3222remove our lockfile 3223----------------------------------------------------------------------------- */ 3224void unlock() 3225{ 3226 if (lock_file) { 3227 unlink(lock_file); 3228 free(lock_file); 3229 lock_file = NULL; 3230 } 3231} 3232#endif 3233 3234/* ----------------------------------------------------------------------------- 3235----------------------------------------------------------------------------- */ 3236int sys_loadplugin(char *arg) 3237{ 3238 char path[MAXPATHLEN]; 3239 int ret = -1; 3240 CFBundleRef bundle; 3241 CFURLRef url; 3242 int (*start)(CFBundleRef); 3243 3244 3245 if (arg[0] == '/') { 3246 strlcpy(path, arg, sizeof(path)); 3247 } 3248 else { 3249 strlcpy(path, "/System/Library/Extensions/", sizeof(path)); 3250 strlcat(path, arg, sizeof(path)); 3251 } 3252 3253 url = CFURLCreateFromFileSystemRepresentation(NULL, (const UInt8 *)path, strlen(path), TRUE); 3254 if (url) { 3255 bundle = CFBundleCreate(NULL, url); 3256 if (bundle) { 3257 3258 if (CFBundleLoadExecutable(bundle) 3259 && (start = CFBundleGetFunctionPointerForName(bundle, CFSTR("start")))) { 3260 3261 ret = (*start)(bundle); 3262 } 3263 3264 CFRelease(bundle); 3265 } 3266 CFRelease(url); 3267 } 3268 return ret; 3269} 3270 3271/* ----------------------------------------------------------------------------- 3272----------------------------------------------------------------------------- */ 3273int sys_eaploadplugin(char *arg, eap_ext *eap) 3274{ 3275 char path[MAXPATHLEN]; 3276 int ret = -1; 3277 CFBundleRef bundle; 3278 CFURLRef url; 3279 CFDictionaryRef dict; 3280 3281 if (arg[0] == '/') { 3282 strlcpy(path, arg, sizeof(path)); 3283 } 3284 else { 3285 strlcpy(path, "/System/Library/Extensions/", sizeof(path)); 3286 strlcat(path, arg, sizeof(path)); 3287 } 3288 3289 url = CFURLCreateFromFileSystemRepresentation(NULL, (const UInt8 *)path, strlen(path), TRUE); 3290 if (url) { 3291 3292 dict = CFBundleCopyInfoDictionaryForURL(url); 3293 if (dict) { 3294 CFNumberRef num; 3295 CFStringRef str; 3296 int i; 3297 3298 bzero(eap, sizeof(eap_ext)); 3299 num = CFDictionaryGetValue(dict, CFSTR("EAPType")); 3300 if (num && (CFGetTypeID(num) == CFNumberGetTypeID())) { 3301 CFNumberGetValue(num, kCFNumberSInt32Type, &i); 3302 eap->type = i; 3303 } 3304 3305 str = CFDictionaryGetValue(dict, CFSTR("EAPName")); 3306 if (str && (CFGetTypeID(str) == CFStringGetTypeID())) { 3307 eap->name = malloc(CFStringGetLength(str) + 1); 3308 if (eap->name) 3309 CFStringGetCString((CFStringRef)str, eap->name, CFStringGetLength(str) + 1, kCFStringEncodingUTF8); 3310 } 3311 CFRelease(dict); 3312 3313 bundle = CFBundleCreate(NULL, url); 3314 if (bundle) { 3315 3316 if (CFBundleLoadExecutable(bundle)) { 3317 3318 eap->init = CFBundleGetFunctionPointerForName(bundle, CFSTR("Init")); 3319 eap->dispose = CFBundleGetFunctionPointerForName(bundle, CFSTR("Dispose")); 3320 eap->process = CFBundleGetFunctionPointerForName(bundle, CFSTR("Process")); 3321 eap->free = CFBundleGetFunctionPointerForName(bundle, CFSTR("Free")); 3322 eap->attribute = CFBundleGetFunctionPointerForName(bundle, CFSTR("GetAttribute")); 3323 eap->interactive_ui = CFBundleGetFunctionPointerForName(bundle, CFSTR("InteractiveUI")); 3324 eap->print_packet = CFBundleGetFunctionPointerForName(bundle, CFSTR("PrintPacket")); 3325 eap->identity = CFBundleGetFunctionPointerForName(bundle, CFSTR("Identity")); 3326 3327 // keep a ref to release later 3328 eap->plugin = bundle; 3329 3330 ret = 0; 3331 } 3332 3333 if (ret) 3334 CFRelease(bundle); 3335 } 3336 } 3337 CFRelease(url); 3338 } 3339 return ret; 3340} 3341 3342/* ----------------------------------------------------------------------------- 3343publish a dictionnary entry in the cache, given a key 3344----------------------------------------------------------------------------- */ 3345int publish_keyentry(CFStringRef key, CFStringRef entry, CFTypeRef value) 3346{ 3347 CFMutableDictionaryRef dict; 3348 CFPropertyListRef ref; 3349 3350 // ppp daemons without services are not published in the cache 3351 if (cfgCache == NULL) 3352 return 0; 3353 3354 if (publish_dict && key && CFDictionaryContainsKey(publish_dict, key) && (ref = CFDictionaryGetValue(publish_dict, key))) { 3355 dict = CFDictionaryCreateMutableCopy(0, 0, ref); 3356 } else { 3357 dict = CFDictionaryCreateMutable(0, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); 3358 } 3359 3360 if (dict == 0) 3361 return 0; 3362 3363 CFDictionarySetValue(dict, entry, value); 3364 if (update_publish_dict(key,dict) == 0) 3365 warning("publish_entry SCDSet() failed: %s\n", SCErrorString(SCError())); 3366 CFRelease(dict); 3367 3368 return 1; 3369 } 3370 3371/* ----------------------------------------------------------------------------- 3372publish a numerical entry in the cache, given a dictionary 3373----------------------------------------------------------------------------- */ 3374int publish_dictnumentry(CFStringRef dict, CFStringRef entry, int val) 3375{ 3376 int ret = ENOMEM; 3377 CFNumberRef num; 3378 CFStringRef key; 3379 3380 key = SCDynamicStoreKeyCreateNetworkServiceEntity(0, kSCDynamicStoreDomainState, serviceidRef, dict); 3381 if (key) { 3382 num = CFNumberCreate(NULL, kCFNumberIntType, &val); 3383 if (num) { 3384 ret = publish_keyentry(key, entry, num); 3385 CFRelease(num); 3386 ret = 0; 3387 } 3388 CFRelease(key); 3389 } 3390 return ret; 3391} 3392 3393/* ----------------------------------------------------------------------------- 3394publish a string entry in the cache, given a dictionary 3395----------------------------------------------------------------------------- */ 3396int publish_dictstrentry(CFStringRef dict, CFStringRef entry, char *str, int encoding) 3397{ 3398 3399 int ret = ENOMEM; 3400 CFStringRef ref; 3401 CFStringRef key; 3402 3403 key = SCDynamicStoreKeyCreateNetworkServiceEntity(0, kSCDynamicStoreDomainState, serviceidRef, dict); 3404 if (key) { 3405 ref = CFStringCreateWithCString(NULL, str, encoding); 3406 if (ref) { 3407 ret = publish_keyentry(key, entry, ref); 3408 CFRelease(ref); 3409 ret = 0; 3410 } 3411 CFRelease(key); 3412 } 3413 return ret; 3414} 3415 3416/* ----------------------------------------------------------------------------- 3417 republish Dynamic store 3418 ----------------------------------------------------------------------------- */ 3419static void 3420republish_dict(SCDynamicStoreRef store __unused, void *info __unused) 3421{ 3422 int count; 3423 3424 dbglog("DynamicStore Server has reconnected, republish keys"); 3425 if (publish_dict == NULL) 3426 return; 3427 3428 count = CFDictionaryGetCount(publish_dict); 3429 if ( count ){ 3430 CFRelease(cfgCache); 3431 cfgCache = SCDynamicStoreCreate(0, CFSTR("pppd"), 0, 0); /* create new ref with server */ 3432 if (cfgCache == 0){ 3433 fatal("republish_dict SCDynamicStoreCreate failed: %s", SCErrorString(SCError())); 3434 return; 3435 } 3436 3437 dbglog("republish_dict: processing %d keys", count); 3438 if (demand) { /* Republish directly for demand mode */ 3439 if (publish_dict) { 3440 SCDynamicStoreSetMultiple(cfgCache, publish_dict, NULL, NULL); 3441 } 3442 } else if (!commit_publish_dict()) { 3443 warning("republish_dict SCDynamicStoreSetMultiple failed key: %s\n", SCErrorString(SCError())); 3444 } 3445 } 3446} 3447 3448/* ----------------------------------------------------------------------------- 3449unpublish a dictionnary entry from the cache, given the dict key 3450----------------------------------------------------------------------------- */ 3451int unpublish_keyentry(CFStringRef key, CFStringRef entry) 3452{ 3453 CFMutableDictionaryRef dict; 3454 CFPropertyListRef ref; 3455 3456 // ppp daemons without services are not published in the cache 3457 if (cfgCache == NULL) 3458 return 0; 3459 3460 if (publish_dict && key && CFDictionaryContainsKey(publish_dict, key) && (ref = CFDictionaryGetValue(publish_dict, key))) { 3461 if ((dict = CFDictionaryCreateMutableCopy(0, 0, ref))) { 3462 CFDictionaryRemoveValue(dict, entry); 3463 if (update_publish_dict(key, dict) == 0) 3464 warning("unpublish_keyentry SCDSet() failed: %s\n", SCErrorString(SCError())); 3465 CFRelease(dict); 3466 } 3467 } 3468 3469 return 0; 3470} 3471 3472/* ----------------------------------------------------------------------------- 3473unpublish a complete dictionnary from the cache 3474----------------------------------------------------------------------------- */ 3475int unpublish_dict(CFStringRef dict) 3476{ 3477 int ret = ENOMEM; 3478 CFStringRef key; 3479 3480 if (cfgCache == NULL) 3481 return 0; 3482 3483 key = SCDynamicStoreKeyCreateNetworkServiceEntity(0, kSCDynamicStoreDomainState, serviceidRef, dict); 3484 if (key) { 3485 if (publish_dict){ 3486 CFDictionaryRemoveValue(publish_dict, key); 3487 } 3488 ret = !SCDynamicStoreRemoveValue(cfgCache, key); 3489 CFRelease(key); 3490 } 3491 return ret; 3492} 3493 3494/* ----------------------------------------------------------------------------- 3495unpublish a dictionnary entry from the cache, given the dict name 3496----------------------------------------------------------------------------- */ 3497int unpublish_dictentry(CFStringRef dict, CFStringRef entry) 3498{ 3499 int ret = ENOMEM; 3500 CFStringRef key; 3501 3502 key = SCDynamicStoreKeyCreateNetworkServiceEntity(0, kSCDynamicStoreDomainState, serviceidRef, dict); 3503 if (key) { 3504 ret = unpublish_keyentry(key, entry); 3505 CFRelease(key); 3506 ret = 0; 3507 } 3508 return ret; 3509} 3510 3511/* ----------------------------------------------------------------------------- 3512get mach asbolute time, for timeout purpose independent of date changes 3513----------------------------------------------------------------------------- */ 3514int getabsolutetime(struct timeval *timenow) 3515{ 3516 double now; 3517 3518 if (timeScaleSeconds == 0) 3519 return -1; 3520 3521 now = mach_absolute_time(); 3522 timenow->tv_sec = now * timeScaleSeconds; 3523 timenow->tv_usec = (now * timeScaleMicroSeconds) - ((double)timenow->tv_sec * 1000000); 3524 return 0; 3525} 3526 3527/* ----------------------------------------------------------------------------- 3528our new phase hook 3529----------------------------------------------------------------------------- */ 3530void sys_phasechange(void *arg, uintptr_t p) 3531{ 3532 3533 publish_dictnumentry(kSCEntNetPPP, kSCPropNetPPPStatus, p); 3534 3535 switch (p) { 3536 3537 case PHASE_ESTABLISH: 3538 connecttime = mach_absolute_time() * timeScaleSeconds; 3539 publish_dictnumentry(kSCEntNetPPP, kSCPropNetPPPConnectTime, connecttime); 3540 if (maxconnect) 3541 publish_dictnumentry(kSCEntNetPPP, kSCPropNetPPPDisconnectTime, connecttime + maxconnect); 3542 break; 3543 3544 case PHASE_SERIALCONN: 3545 unpublish_dictentry(kSCEntNetPPP, kSCPropNetPPPRetryConnectTime); 3546 break; 3547 3548 case PHASE_WAITONBUSY: 3549 publish_dictnumentry(kSCEntNetPPP, kSCPropNetPPPRetryConnectTime, redialtimer + (mach_absolute_time() * timeScaleSeconds)); 3550 break; 3551 3552 case PHASE_RUNNING: 3553 break; 3554 3555 case PHASE_DORMANT: 3556 case PHASE_HOLDOFF: 3557 case PHASE_DEAD: 3558 sys_eventnotify((void*)PPP_EVT_DISCONNECTED, status); 3559 break; 3560 3561 case PHASE_DISCONNECT: 3562 unpublish_dictentry(kSCEntNetPPP, CFSTR("AuthPeerName") /*kSCPropNetPPPAuthPeerName*/); 3563 unpublish_dictentry(kSCEntNetPPP, kSCPropNetPPPCommRemoteAddress); 3564 unpublish_dictentry(kSCEntNetPPP, kSCPropNetPPPConnectTime); 3565 unpublish_dictentry(kSCEntNetPPP, kSCPropNetPPPDisconnectTime); 3566 break; 3567 } 3568 3569 /* send phase notification to the controller */ 3570 if (phase != PHASE_DEAD) 3571 sys_notify(PPPD_PHASE, phase, ifunit); 3572} 3573 3574 3575/* ----------------------------------------------------------------------------- 3576----------------------------------------------------------------------------- */ 3577void sys_authpeersuccessnotify(void *param, uintptr_t info) 3578{ 3579 struct auth_peer_success_info *peerinfo = (struct auth_peer_success_info *)info; 3580 3581 publish_dictstrentry(kSCEntNetPPP, CFSTR("AuthPeerName") /*kSCPropNetPPPAuthPeerName*/, peerinfo->name, kCFStringEncodingUTF8); 3582} 3583 3584/* ----------------------------------------------------------------------------- 3585----------------------------------------------------------------------------- */ 3586void sys_timeremaining(void *param, uintptr_t info) 3587{ 3588 struct lcp_timeremaining_info *timeinfo = (struct lcp_timeremaining_info *)info; 3589 u_int32_t val = 0, curtime = mach_absolute_time() * timeScaleSeconds; 3590 3591 if (timeinfo->time == 0xFFFFFFFF) { 3592 // infinite timer from the server, restore our maxconnect time if any 3593 if (maxconnect) 3594 val = connecttime + maxconnect; 3595 } 3596 else { 3597 // valid timer from the server, the disconnect time will be the min between 3598 // our setup and what says the server. 3599 if (maxconnect) 3600 val = MIN(curtime + timeinfo->time, connecttime + maxconnect); 3601 else 3602 val = curtime + timeinfo->time; 3603 } 3604 3605 if (val) 3606 publish_dictnumentry(kSCEntNetPPP, kSCPropNetPPPDisconnectTime, val); 3607 else 3608 unpublish_dictentry(kSCEntNetPPP, kSCPropNetPPPDisconnectTime); 3609 3610} 3611 3612/* ----------------------------------------------------------------------------- 3613----------------------------------------------------------------------------- */ 3614void sys_publish_remoteaddress(char *addr) 3615{ 3616 3617 if (addr) 3618 publish_dictstrentry(kSCEntNetPPP, kSCPropNetPPPCommRemoteAddress, addr, kCFStringEncodingUTF8); 3619} 3620 3621/* ----------------------------------------------------------------------------- 3622our pid has changed, reinit things 3623----------------------------------------------------------------------------- */ 3624void sys_reinit() 3625{ 3626 3627 cfgCache = SCDynamicStoreCreate(0, CFSTR("pppd"), 0, 0); 3628 if (cfgCache == 0) 3629 fatal("SCDynamicStoreCreate failed: %s", SCErrorString(SCError())); 3630 3631 publish_dictnumentry(kSCEntNetPPP, CFSTR("pid"), getpid()); 3632} 3633 3634/* ----------------------------------------------------------------------------- 3635we are exiting 3636----------------------------------------------------------------------------- */ 3637void sys_exitnotify(void *arg, uintptr_t exitcode) 3638{ 3639 3640 // unpublish the various info about the connection 3641 unpublish_dict(kSCEntNetPPP); 3642 unpublish_dict(kSCEntNetDNS); 3643 unpublish_dict(kSCEntNetProxies); 3644#if !TARGET_OS_EMBEDDED 3645 unpublish_dict(kSCEntNetSMB); 3646#endif 3647 unpublish_dict(kSCEntNetInterface); 3648 3649 sys_eventnotify((void*)PPP_EVT_DISCONNECTED, exitcode); 3650 3651 if (cfgCache) { 3652 CFRelease(cfgCache); 3653 cfgCache = 0; 3654 } 3655 3656 if (publish_dict){ 3657 CFRelease(publish_dict); 3658 publish_dict = NULL; 3659 } 3660} 3661 3662/* ----------------------------------------------------------------------------- 3663add/remove a route via an interface 3664----------------------------------------------------------------------------- */ 3665int 3666route_interface(int cmd, struct in_addr host, struct in_addr addr_mask, char iftype, char *ifname, int is_host) 3667{ 3668 int len, iflen; 3669 int rtm_seq = 0; 3670 struct { 3671 struct rt_msghdr hdr; 3672 struct sockaddr_in dst; 3673 struct sockaddr_dl iface; 3674 struct sockaddr_in mask; 3675 } rtmsg; 3676 3677 char host_str[INET_ADDRSTRLEN]; 3678 char mask_str[INET_ADDRSTRLEN]; 3679 int sockfd = -1; 3680 3681 if ((sockfd = socket(PF_ROUTE, SOCK_RAW, PF_ROUTE)) < 0) { 3682 error("route_interface: open routing socket failed, %m. (address %s, mask %s, interface %s, host %d).", 3683 addr2ascii(AF_INET, &host, sizeof(host), host_str), 3684 addr2ascii(AF_INET, &addr_mask, sizeof(addr_mask), mask_str), 3685 ifname, 3686 is_host); 3687 return (0); 3688 } 3689 3690 memset(&rtmsg, 0, sizeof(rtmsg)); 3691 rtmsg.hdr.rtm_type = cmd; 3692 rtmsg.hdr.rtm_flags = RTF_UP | RTF_STATIC; 3693 if (is_host) 3694 rtmsg.hdr.rtm_flags |= RTF_HOST; 3695 rtmsg.hdr.rtm_version = RTM_VERSION; 3696 rtmsg.hdr.rtm_seq = ++rtm_seq; 3697 rtmsg.hdr.rtm_addrs = RTA_DST | RTA_GATEWAY; 3698 rtmsg.dst.sin_len = sizeof(rtmsg.dst); 3699 rtmsg.dst.sin_family = AF_INET; 3700 rtmsg.dst.sin_addr = host; 3701 iflen = MIN(strlen(ifname), sizeof(rtmsg.iface.sdl_data)); 3702 rtmsg.iface.sdl_len = sizeof(rtmsg.iface); 3703 rtmsg.iface.sdl_family = AF_LINK; 3704 rtmsg.iface.sdl_type = iftype; 3705 rtmsg.iface.sdl_nlen = iflen; 3706 strncpy(rtmsg.iface.sdl_data, ifname, iflen); 3707 3708 // if addr_mask non-zero add it 3709 if (addr_mask.s_addr != 0) { 3710 rtmsg.hdr.rtm_addrs |= RTA_NETMASK; 3711 rtmsg.mask.sin_len = sizeof(rtmsg.mask); 3712 rtmsg.mask.sin_family = AF_INET; 3713 rtmsg.mask.sin_addr = addr_mask; 3714 } 3715 3716 len = sizeof(rtmsg); 3717 rtmsg.hdr.rtm_msglen = len; 3718 if (write(sockfd, &rtmsg, len) < 0) { 3719 syslog((cmd == RTM_DELETE)? LOG_DEBUG : LOG_ERR, "route_interface: write routing socket failed, %s. (address %s, mask %s, interface %s, host %d).", 3720 strerror(errno), 3721 addr2ascii(AF_INET, &host, sizeof(host), host_str), 3722 addr2ascii(AF_INET, &addr_mask, sizeof(addr_mask), mask_str), 3723 ifname, 3724 is_host); 3725 close(sockfd); 3726 return (0); 3727 } 3728 3729 close(sockfd); 3730 return (1); 3731} 3732 3733/* ----------------------------------------------------------------------------- 3734 add/remove a route via a gateway 3735----------------------------------------------------------------------------- */ 3736int 3737route_gateway(int cmd, struct in_addr dest, struct in_addr mask, struct in_addr gateway, int use_gway_flag) 3738{ 3739 char dest_str[INET_ADDRSTRLEN]; 3740 char mask_str[INET_ADDRSTRLEN]; 3741 char gateway_str[INET_ADDRSTRLEN]; 3742 int len; 3743 int rtm_seq = 0; 3744 3745 struct { 3746 struct rt_msghdr hdr; 3747 struct sockaddr_in dst; 3748 struct sockaddr_in gway; 3749 struct sockaddr_in mask; 3750 } rtmsg; 3751 3752 int sockfd = -1; 3753 3754 if ((sockfd = socket(PF_ROUTE, SOCK_RAW, PF_ROUTE)) < 0) { 3755 syslog(LOG_INFO, "host_gateway: open routing socket failed, %s. (address %s, mask %s, gateway %s, use-gateway %d).", 3756 strerror(errno), 3757 addr2ascii(AF_INET, &dest, sizeof(dest), dest_str), 3758 addr2ascii(AF_INET, &mask, sizeof(mask), mask_str), 3759 addr2ascii(AF_INET, &gateway, sizeof(gateway), gateway_str), 3760 use_gway_flag); 3761 return (0); 3762 } 3763 3764 memset(&rtmsg, 0, sizeof(rtmsg)); 3765 rtmsg.hdr.rtm_type = cmd; 3766 rtmsg.hdr.rtm_flags = RTF_UP | RTF_STATIC; 3767 if (use_gway_flag) 3768 rtmsg.hdr.rtm_flags |= RTF_GATEWAY; 3769 rtmsg.hdr.rtm_version = RTM_VERSION; 3770 rtmsg.hdr.rtm_seq = ++rtm_seq; 3771 rtmsg.hdr.rtm_addrs = RTA_DST | RTA_NETMASK | RTA_GATEWAY; 3772 rtmsg.dst.sin_len = sizeof(rtmsg.dst); 3773 rtmsg.dst.sin_family = AF_INET; 3774 rtmsg.dst.sin_addr = dest; 3775 rtmsg.gway.sin_len = sizeof(rtmsg.gway); 3776 rtmsg.gway.sin_family = AF_INET; 3777 rtmsg.gway.sin_addr = gateway; 3778 rtmsg.mask.sin_len = sizeof(rtmsg.mask); 3779 rtmsg.mask.sin_family = AF_INET; 3780 rtmsg.mask.sin_addr = mask; 3781 3782 len = sizeof(rtmsg); 3783 rtmsg.hdr.rtm_msglen = len; 3784 if (write(sockfd, &rtmsg, len) < 0) { 3785 syslog((cmd == RTM_DELETE)? LOG_DEBUG : LOG_ERR, "host_gateway: write routing socket failed, %s. (address %s, mask %s, gateway %s, use-gateway %d).", 3786 strerror(errno), 3787 addr2ascii(AF_INET, &dest, sizeof(dest), dest_str), 3788 addr2ascii(AF_INET, &mask, sizeof(mask), mask_str), 3789 addr2ascii(AF_INET, &gateway, sizeof(gateway), gateway_str), 3790 use_gway_flag); 3791 close(sockfd); 3792 return (0); 3793 } 3794 3795 close(sockfd); 3796 return (1); 3797} 3798 3799// Here stealing the in_cksum function which computes checksum from original ping. 3800static int 3801in_cksum(u_short *addr, int len) 3802{ 3803 register int nleft = len; 3804 register u_short *w = addr; 3805 register int sum = 0; 3806 u_short answer = 0; 3807 3808 // Our algorithm is simple, using a 32 bit accumulator (sum), we add 3809 // sequential 16 bit words to it, and at the end, fold back all the 3810 // carry bits from the top 16 bits into the lower 16 bits. 3811 3812 while (nleft > 1) { 3813 sum += *w++; 3814 nleft -= 2; 3815 } 3816 3817 /* mop up an odd byte, if necessary */ 3818 if (nleft == 1) { 3819 *(u_char *)(&answer) = *(u_char *)w; 3820 sum += answer; 3821 } 3822 3823 // Add back carry outs from top 16 bits to low 16 bits 3824 sum = (sum >> 16) + (sum & 0xffff); // Add hi 16 to low 16 3825 sum += (sum >> 16); // Add carry 3826 answer = ~sum; // Truncate to 16 bits 3827 3828 return answer; 3829} 3830 3831static int 3832ppp_scoped_ping (int s, 3833 unsigned int ifscope, 3834 struct sockaddr_in *dst, 3835 int ntransmit) 3836{ 3837 int i; 3838 int hold; 3839 struct icmp *icp; 3840 u_char *packet; 3841 u_char outpack[IP_MAXPACKET] __attribute__ ((aligned(4))); // Wcast-align fix - force alignment 3842 3843 if (s < 0) { 3844 s = socket(AF_INET, SOCK_DGRAM, IPPROTO_ICMP); 3845 if (s < 0) { 3846 return -1; 3847 } 3848 if (ifscope) { 3849 if (setsockopt(s, IPPROTO_IP, IP_BOUND_IF, (char *)&ifscope, sizeof(ifscope)) != 0) { 3850 close(s); 3851 return -1; 3852 } 3853 } 3854 3855 hold = IP_MAXPACKET + 128; 3856 (void)setsockopt(s, SOL_SOCKET, SO_RCVBUF, (char *)&hold, sizeof(hold)); 3857 } 3858 3859 packet = outpack; 3860 icp = ALIGNED_CAST(struct icmp *)outpack; 3861 icp->icmp_type = ICMP_ECHO; 3862 icp->icmp_code = 0; 3863 icp->icmp_cksum = 0; 3864 icp->icmp_seq = htons(ntransmit); 3865 icp->icmp_id = getpid() & 0xFFFF; 3866 icp->icmp_cksum = in_cksum((u_short *)icp, ICMP_MINLEN); 3867 if ((i = sendto(s, (char *)packet, ICMP_MINLEN, 0, (struct sockaddr *)dst, sizeof(*dst))) != ICMP_MINLEN) { 3868 close(s); 3869 return -1; 3870 } 3871 return s; 3872} 3873 3874int 3875ppp_ip_probe_send (void *arg) 3876{ 3877 int scope; 3878 int i = 0; 3879 3880 dbglog("%s: starting", __FUNCTION__); 3881 3882 if (!session || !session->valid) { 3883 return -1; 3884 } 3885 3886 scope = if_nametoindex(session->interface_name); 3887 3888 session->probe_success = 0; 3889 3890 // first probe to goog-dns 3891 if ((session->probe_addrs[GOOG_DNS_PROBE].sin_family == AF_INET) && 3892 session->probe_addrs[GOOG_DNS_PROBE].sin_addr.s_addr) { 3893 dbglog("%s: found goog-dns address", __FUNCTION__); 3894 if ((session->probe_fds[GOOG_DNS_PROBE] = ppp_scoped_ping(session->probe_fds[GOOG_DNS_PROBE], 3895 scope, 3896 &session->probe_addrs[GOOG_DNS_PROBE], 3897 session->probe_ntransmit)) != -1) { 3898 add_fd(session->probe_fds[GOOG_DNS_PROBE]); 3899 dbglog("%s: sent to goog-dns over scope %d", __FUNCTION__, scope); 3900 i++; 3901 } 3902 } else { 3903 info("%s: no goog-dns address", __FUNCTION__); 3904 } 3905 // next probes to server and alternate server 3906 if ((session->probe_addrs[PEER_ADDR_PROBE].sin_family == AF_INET) && 3907 session->probe_addrs[PEER_ADDR_PROBE].sin_addr.s_addr) { 3908 dbglog("%s: found peer address", __FUNCTION__); 3909 // current vpn server 3910 if ((session->probe_fds[PEER_ADDR_PROBE] = ppp_scoped_ping(session->probe_fds[PEER_ADDR_PROBE], 3911 scope, 3912 &session->probe_addrs[PEER_ADDR_PROBE], 3913 session->probe_ntransmit)) != -1) { 3914 add_fd(session->probe_fds[PEER_ADDR_PROBE]); 3915 dbglog("%s: sent to peer over scope %d", __FUNCTION__, scope); 3916 i++; 3917 } 3918 3919 if ((session->probe_addrs[ALT_PEER_ADDR_PROBE].sin_family == AF_INET) && 3920 session->probe_addrs[ALT_PEER_ADDR_PROBE].sin_addr.s_addr) { 3921 dbglog("%s: found alternate peer address", __FUNCTION__); 3922 // alternate vpn server 3923 if ((session->probe_fds[ALT_PEER_ADDR_PROBE] = ppp_scoped_ping(session->probe_fds[ALT_PEER_ADDR_PROBE], 3924 scope, 3925 &session->probe_addrs[ALT_PEER_ADDR_PROBE], 3926 session->probe_ntransmit)) != -1) { 3927 add_fd(session->probe_fds[ALT_PEER_ADDR_PROBE]); 3928 info("%s: sent to alternate peer over scope %d", __FUNCTION__, scope); 3929 i++; 3930 } 3931 } else { 3932 dbglog("%s: no alternate peer address", __FUNCTION__); 3933 } 3934 } else { 3935 dbglog("%s: no peer address", __FUNCTION__); 3936 } 3937 if (i) { 3938 dbglog("%s: %d probes sent", __FUNCTION__, i); 3939 session->probe_tries++; 3940 if (!session->probe_timer_running) { 3941 session->probe_timer_running = 1; 3942 TIMEOUT(ppp_ip_probe_timeout, 0, 3); 3943 } 3944 return 0; 3945 } 3946 return -1; 3947} 3948 3949int 3950ppp_ip_probe_stop (void *arg) 3951{ 3952 int i; 3953 3954 if (!session || !session->valid) { 3955 return -1; 3956 } 3957 3958 if (session->probe_timer_running) { 3959 session->probe_timer_running = 0; 3960 UNTIMEOUT(ppp_ip_probe_timeout, 0); 3961 dbglog("ppp_auxiliary_probe stopped"); 3962 } 3963 3964 for (i = 0; i < MAX_PROBE_ADDRS; i++) { 3965 if (session->probe_fds[i] > 0) { 3966 remove_fd(session->probe_fds[i]); 3967 close(session->probe_fds[i]); 3968 session->probe_fds[i] = -1; 3969 } 3970 } 3971 session->probe_tries = 0; 3972 session->probe_success = 0; 3973 return 0; 3974} 3975 3976static void 3977ppp_ip_probe_timeout (void *arg) 3978{ 3979 if (!session || !session->valid) { 3980 return; 3981 } 3982 3983 if (session->probe_tries < 15) { 3984 if (!ppp_ip_probe_send(arg)) { 3985 return; 3986 } 3987 } 3988 error("ppp_auxiliary_probe timed out"); 3989} 3990 3991void ppp_session_clear (ppp_session_t *sess) 3992{ 3993 int i; 3994 3995 if (sess) { 3996 bzero(sess, sizeof(*sess)); 3997 for (i = 0; i < MAX_PROBE_ADDRS; i++) { 3998 sess->probe_fds[i] = -1; 3999 } 4000 } 4001} 4002 4003int 4004ppp_variable_echo_is_off (void) 4005{ 4006 if (!session || !session->valid) { 4007 return 1; 4008 } 4009 return(!wait_underlying_interface_up); 4010} 4011 4012void 4013ppp_variable_echo_start (void) 4014{ 4015 if (!session || !session->valid) { 4016 return; 4017 } 4018 if (wait_underlying_interface_up || wait_port_mapping_changed) { 4019 // speed up LCP echos 4020 if (!lcp_echos_hastened) { 4021 dbglog("ppp_variable_echo_start"); 4022 lcp_echo_interval_slow = lcp_echo_interval; 4023 lcp_echo_interval = 1; 4024 lcp_echo_fails_slow = lcp_echo_fails; 4025 if (lcp_echo_fails > 10) { 4026 lcp_echo_fails = 10; // max of 10 secs 4027 } 4028 lcp_echos_hastened = 1; 4029 lcp_echo_restart(0); 4030 } 4031 } 4032} 4033 4034void 4035ppp_variable_echo_stop (void) 4036{ 4037 if (!session || !session->valid) { 4038 return; 4039 } 4040 if (wait_underlying_interface_up || wait_port_mapping_changed) { 4041 dbglog("received echo-reply, ppp_variable_echo_stop!"); 4042 wait_underlying_interface_up = 0; 4043 wait_port_mapping_changed = 0; 4044 if (lcp_echos_hastened) { 4045 lcp_echo_interval = lcp_echo_interval_slow; 4046 lcp_echo_fails = lcp_echo_fails_slow; 4047 lcp_echos_hastened = 0; 4048 } 4049 } 4050} 4051 4052void ppp_auxiliary_probe_ip_up(void *arg, uintptr_t p) 4053{ 4054 ppp_auxiliary_probe_ip = 1; 4055} 4056 4057void ppp_auxiliary_probe_ip_down(void *arg, uintptr_t p) 4058{ 4059 ppp_auxiliary_probe_ip = 0; 4060} 4061 4062void 4063ppp_auxiliary_probe_init (void) 4064{ 4065 ppp_auxiliary_probe_echos_pending = 0; 4066 ppp_auxiliary_probe_success = 0; 4067 if (!ppp_auxiliary_probe_ip_notify_init) { 4068 add_notifier(&ip_up_notify, ppp_auxiliary_probe_ip_up, 0); 4069 add_notifier(&ip_down_notify, ppp_auxiliary_probe_ip_down, 0); 4070 ppp_auxiliary_probe_ip_notify_init= 1; 4071 } 4072} 4073 4074void 4075ppp_auxiliary_probe_stop (void) 4076{ 4077 ppp_ip_probe_stop(session); 4078 ppp_auxiliary_probe_echos_pending = 0; 4079 ppp_auxiliary_probe_success = 0; 4080} 4081 4082void 4083ppp_auxiliary_probe_check (int echos_pending, 4084 probe_disconnect_func disconnect_func, 4085 fsm *f) 4086{ 4087 if (ppp_auxiliary_probe_ip && 4088 !wait_underlying_interface_up && 4089 !wait_port_mapping_changed && 4090 echos_pending > 1){ 4091 // more than 2 echo responses pending: try probing the network 4092 if (!ppp_auxiliary_probe_echos_pending) { 4093 // probe hasn't been started 4094 error("no echo-reply, start ppp_auxiliary_probe!"); 4095 ppp_ip_probe_send(session); 4096 ppp_auxiliary_probe_echos_pending = 1; 4097 ppp_auxiliary_probe_success = 0; 4098 } else if (++ppp_auxiliary_probe_echos_pending > 1 && 4099 ppp_auxiliary_probe_success) { 4100 // we have more than 3 pending echo responses, while the network 4101 // probe succeeded... disconnect 4102 error("no echo-reply, despite successful ppp_auxiliary_probe!"); 4103 // network probe succeeded but no echo replies, disconnect 4104 if (disconnect_func) { 4105 disconnect_func(f); 4106 } 4107 } 4108 } 4109} 4110 4111void 4112ppp_process_auxiliary_probe_input (void) 4113{ 4114 int i, j, result; 4115 4116 if (!session || !session->valid) { 4117 return; 4118 } 4119 4120 for (i = 0, j = 0; i < MAX_PROBE_ADDRS; i++) { 4121 if (session->probe_fds[i] > 0 && is_ready_fd(session->probe_fds[i])) { 4122 result = 0; 4123 read(session->probe_fds[i], &result, 1); 4124 remove_fd(session->probe_fds[i]); 4125 if (result > 0) { 4126 // assume success for now. TODO: log and ignore alt-peer success 4127 session->probe_success++; 4128 j++; 4129 dbglog("ppp_auxiliary_probe[%d] response!", i); 4130 } 4131 close(session->probe_fds[i]); 4132 session->probe_fds[i] = -1; 4133 } 4134 } 4135 if (j) { 4136 if (session->probe_timer_running) { 4137 session->probe_timer_running = 0; 4138 UNTIMEOUT(ppp_ip_probe_timeout, 0); 4139 } 4140 if (ppp_auxiliary_probe_echos_pending) { 4141 ppp_auxiliary_probe_success++; 4142 } 4143 } 4144} 4145 4146#if !TARGET_OS_EMBEDDED 4147static void 4148ppp_clear_one_nat_port_mapping (mdns_nat_mapping_t *mapping) 4149{ 4150 if (mapping) { 4151 // what about mapping->mDNSRef_fd? 4152 if (mapping->mDNSRef != NULL) { 4153 if (mapping->mDNSRef_fd) 4154 remove_fd(mapping->mDNSRef_fd); 4155 DNSServiceRefDeallocate(mapping->mDNSRef); 4156 } 4157 bzero(mapping, sizeof(*mapping)); 4158 } 4159} 4160 4161static int 4162ppp_ignore_nat_port_mapping_update (DNSServiceRef sdRef, 4163 char *sd_name, 4164 char *if_name, 4165 uint32_t if_name_siz, 4166 uint32_t interfaceIndex, 4167 uint32_t publicAddress, 4168 DNSServiceProtocol protocol, 4169 uint16_t privatePort, 4170 uint16_t publicPort) 4171{ 4172 int i = 0, vpn = 0, found = 0; 4173 struct ifaddrs *ifap = NULL; 4174 char interfaceName[32]; 4175 4176 /* check if address still exist */ 4177 if (getifaddrs(&ifap) == 0) { 4178 struct ifaddrs *ifa; 4179 for (ifa = ifap; ifa; ifa = ifa->ifa_next) { 4180 if (ifa->ifa_name 4181 && ifa->ifa_addr 4182 && (!strncmp(ifa->ifa_name, "utun", 4) || !strncmp(ifa->ifa_name, "ppp", 3)) 4183 && ifa->ifa_addr->sa_family == AF_INET 4184 && ((struct sockaddr_in *)ifa->ifa_addr)->sin_addr.s_addr == htonl(publicAddress)) { 4185 notice("%s port-mapping update for %s ignored: related to VPN interface. Public Address: %x, Protocol: %s, Private Port: %d, Public Port: %d\n", 4186 sd_name, 4187 ifa->ifa_name, 4188 publicAddress, 4189 (protocol == 0)? "None":((protocol == kDNSServiceProtocol_UDP)? "UDP":"TCP"), 4190 privatePort, 4191 publicPort); 4192 vpn = 1; 4193 } 4194 if (ifa->ifa_name 4195 && ifa->ifa_addr 4196 && !strncmp(ifa->ifa_name, if_name, if_name_siz) 4197 && ifa->ifa_addr->sa_family == AF_INET 4198 && ((struct sockaddr_in *)ifa->ifa_addr)->sin_addr.s_addr == session->interface_address.s_addr) { 4199 found = 1; 4200 } 4201 } 4202 freeifaddrs(ifap); 4203 } else { 4204 error("%s port-mapping update for %s ignored: failed to get interface list", 4205 sd_name, 4206 if_name); 4207 return 1; 4208 } 4209 4210 if (vpn) { 4211 return 1; 4212 } 4213 bzero(interfaceName, sizeof(interfaceName)); 4214 if_indextoname(interfaceIndex, (char *)interfaceName); 4215 if (!strncmp(interfaceName, if_name, if_name_siz)) { 4216 if (strstr(if_name, "ppp") || strstr(if_name, "utun")) { 4217 // change on PPP interface... we don't care 4218 notice("%s port-mapping update for %s ignored: underlying interface is PPP/VPN. Public Address: %x, Protocol: %s, Private Port: %d, Public Port: %d\n", 4219 sd_name, 4220 if_name, 4221 publicAddress, 4222 (protocol == 0)? "None":((protocol == kDNSServiceProtocol_UDP)? "UDP":"TCP"), 4223 privatePort, 4224 publicPort); 4225 return 1; 4226 } else { 4227 /* check if address still exist */ 4228 if (found) { 4229 return 0; 4230 } else { 4231 if (!publicAddress || (!publicPort && privatePort)) { 4232 notice("%s port-mapping update for %s ignored: underlying interface down. Public Address: %x, Protocol: %s, Private Port: %d, Public Port: %d\n", 4233 sd_name, 4234 if_name, 4235 publicAddress, 4236 (protocol == 0)? "None":((protocol == kDNSServiceProtocol_UDP)? "UDP":"TCP"), 4237 privatePort, 4238 publicPort); 4239 for (i = 0; i < session->nat_mapping_cnt && i < MDNS_NAT_MAPPING_MAX; i++) { 4240 if (session->nat_mapping[i].mDNSRef_tmp == sdRef) { 4241 session->nat_mapping[i].up = 0; 4242 notice("%s port-mapping for %s flagged down because of no connectivity\n", sd_name, if_name); 4243 } 4244 } 4245 return 1; 4246 } 4247 notice("%s port-mapping update for %s ignored: underlying interface's address changed. Public Address: %x, Protocol: %s, Private Port: %d, Public Port: %d\n", 4248 sd_name, 4249 if_name, 4250 publicAddress, 4251 (protocol == 0)? "None":((protocol == kDNSServiceProtocol_UDP)? "UDP":"TCP"), 4252 privatePort, 4253 publicPort); 4254 return 1; 4255 } 4256 } 4257 } else if (publicAddress && !publicPort && !privatePort && !protocol) { 4258 // an update on the NAT's public IP 4259 return 0; 4260 } else { 4261 // public interface disappeared? 4262 if (!publicAddress && !publicPort && !privatePort && !protocol) { 4263 return 0; 4264 } 4265 /* check if address still exist */ 4266 if (session->interface_address.s_addr == htonl(publicAddress) && found) { 4267 return 0; 4268 } 4269 // change due to another interface, ignore for now 4270 notice("%s port-mapping update for %s ignored: not for interface %s. Public Address: %x, Protocol: %s, Private Port: %d, Public Port: %d\n", 4271 sd_name, 4272 interfaceName, 4273 if_name, 4274 publicAddress, 4275 (protocol == 0)? "None":((protocol == kDNSServiceProtocol_UDP)? "UDP":"TCP"), 4276 privatePort, 4277 publicPort); 4278 return 1; 4279 } 4280} 4281#endif 4282 4283static void 4284ppp_public_nat_port_mapping_timeout (void *arg) 4285{ 4286 if (!session || !session->valid) { 4287 return; 4288 } 4289 4290 if (session->nat_mapping_timer_running) { 4291 session->nat_mapping_timer_running = 0; 4292 syslog(LOG_ERR, "NAT's public interface down for more than %d secs... starting faster probe.\n", 4293 PUBLIC_NAT_PORT_MAPPING_TIMEOUT); 4294 // our public interface didn't come back... start faster probe 4295 if (session->failure_func) { 4296 wait_port_mapping_changed = 1; 4297 session->failure_func(); 4298 } 4299 } 4300} 4301 4302void 4303ppp_start_public_nat_port_mapping_timer (void) 4304{ 4305 if (!session || !session->valid) { 4306 return; 4307 } 4308 4309 if (session->nat_mapping_timer_blocked) { 4310 return; 4311 } 4312 4313 if (session->nat_mapping_timer_running) { 4314 return; 4315 } 4316 4317 notice("starting wait-port-mapping timer for %s: %d secs", session->sd_name, PUBLIC_NAT_PORT_MAPPING_TIMEOUT); 4318 TIMEOUT (ppp_public_nat_port_mapping_timeout, 0, PUBLIC_NAT_PORT_MAPPING_TIMEOUT); 4319 session->nat_mapping_timer_running = 1; 4320} 4321 4322void 4323ppp_stop_public_nat_port_mapping_timer (void) 4324{ 4325 if (!session || !session->valid) { 4326 return; 4327 } 4328 4329 if (session->nat_mapping_timer_running) { 4330 UNTIMEOUT (ppp_public_nat_port_mapping_timeout, 0); 4331 session->nat_mapping_timer_running = 0; 4332 } 4333} 4334 4335void 4336ppp_block_public_nat_port_mapping_timer (void) 4337{ 4338 if (!session || !session->valid) { 4339 return; 4340 } 4341 4342 ppp_stop_public_nat_port_mapping_timer(); 4343 session->nat_mapping_timer_blocked = 1; 4344} 4345 4346void 4347ppp_unblock_public_nat_port_mapping_timer (void) 4348{ 4349 if (!session || !session->valid) { 4350 return; 4351 } 4352 4353 session->nat_mapping_timer_blocked = 0; 4354} 4355 4356#if !TARGET_OS_EMBEDDED 4357 4358static void ppp_clear_nat_port_mapping(void); 4359 4360static void 4361ppp_set_nat_port_mapping_callback (DNSServiceRef sdRef, 4362 DNSServiceFlags flags, 4363 uint32_t interfaceIndex, 4364 DNSServiceErrorType errorCode, 4365 uint32_t nPublicAddress, /* four byte IPv4 address in network byte order */ 4366 DNSServiceProtocol protocol, 4367 uint16_t nPrivatePort, 4368 uint16_t nPublicPort, /* may be different than the requested port */ 4369 uint32_t ttl, /* may be different than the requested ttl */ 4370 void *context) 4371{ 4372 uint32_t publicAddress = ntohl(nPublicAddress); 4373 uint16_t privatePort = ntohs(nPrivatePort); 4374 uint16_t publicPort = ntohs(nPublicPort); 4375 int i; 4376 char *sd_name = session->sd_name; 4377 int is_connected = session->valid; 4378 char *if_name = session->interface_name; 4379 uint32_t if_name_siz = session->interface_name_siz; 4380 4381 if (!session || !session->valid) { 4382 return; 4383 } 4384 4385 if (override_primary) { 4386 info("%s port-mapping update for %s ignored: VPN is the Primary interface. Public Address: %x, Protocol: %s, Private Port: %d, Public Port: %d\n", 4387 sd_name, 4388 if_name, 4389 publicAddress, 4390 (protocol == 0)? "None":((protocol == kDNSServiceProtocol_UDP)? "UDP":"TCP"), 4391 privatePort, 4392 publicPort); 4393 ppp_clear_nat_port_mapping(); 4394 return; 4395 } 4396 4397 if (errorCode != kDNSServiceErr_NoError && errorCode != kDNSServiceErr_DoubleNAT) { 4398 error("%s failed to set port-mapping for %s, errorCode: %d\n", sd_name, if_name, errorCode); 4399 if (errorCode == kDNSServiceErr_NATPortMappingUnsupported || errorCode == kDNSServiceErr_NATPortMappingDisabled) { 4400 for (i = 0; i < session->nat_mapping_cnt && i < MDNS_NAT_MAPPING_MAX; i++) { 4401 if (session->nat_mapping[i].mDNSRef_tmp == sdRef) { 4402 error("%s port-mapping for %s became invalid. is Connected: %d, Protocol: %s, Private Port: %d, Previous publicAddress: (%x), Previous publicPort: (%d)\n", 4403 sd_name, 4404 if_name, 4405 is_connected, 4406 (protocol == 0)? "None":((protocol == kDNSServiceProtocol_UDP)? "UDP":"TCP"), 4407 privatePort, 4408 session->nat_mapping[i].reflexive.addr, 4409 session->nat_mapping[i].reflexive.port); 4410 if (session->nat_mapping[i].up && is_connected && session->failure_func) { 4411 notice("%s public port-mapping for %s changed... starting faster probe.\n", sd_name, if_name); 4412 wait_port_mapping_changed = 1; 4413 session->failure_func(); 4414 } else { 4415 ppp_clear_nat_port_mapping(); 4416 } 4417 return; 4418 } 4419 } 4420 } else if (errorCode == kDNSServiceErr_ServiceNotRunning) { 4421 ppp_clear_nat_port_mapping(); 4422 } 4423 return; 4424 } 4425 4426 if (ppp_ignore_nat_port_mapping_update(sdRef, sd_name, if_name, if_name_siz, interfaceIndex, publicAddress, protocol, privatePort, publicPort)) { 4427 return; 4428 } 4429 4430 info("%s port-mapping for %s, interfaceIndex: %d, Protocol: %s, Private Port: %d, Public Address: %x, Public Port: %d, TTL: %d%s\n", 4431 sd_name, 4432 if_name, 4433 interfaceIndex, 4434 (protocol == 0)? "None":((protocol == kDNSServiceProtocol_UDP)? "UDP":"TCP"), 4435 privatePort, 4436 publicAddress, 4437 publicPort, 4438 ttl, 4439 (errorCode == kDNSServiceErr_DoubleNAT)? " (Double NAT)" : "."); 4440 4441 // generate a disconnect if we were already connected and we just detected a change in publicAddress or publicPort 4442 for (i = 0; i < session->nat_mapping_cnt && i < MDNS_NAT_MAPPING_MAX; i++) { 4443 if (session->nat_mapping[i].mDNSRef_tmp == sdRef) { 4444 if (session->nat_mapping[i].up && !publicAddress && !publicPort) { 4445 notice("%s port-mapping for %s indicates public interface down. Public Address: %x, Protocol: %s, Private Port: %d, Public Port: %d\n", 4446 sd_name, 4447 if_name, 4448 publicAddress, 4449 (protocol == 0)? "None":((protocol == kDNSServiceProtocol_UDP)? "UDP":"TCP"), 4450 privatePort, 4451 publicPort); 4452 // start timer 4453 ppp_start_public_nat_port_mapping_timer(); 4454 return; 4455 } else if (session->nat_mapping[i].up) { 4456 ppp_stop_public_nat_port_mapping_timer(); 4457 } 4458 4459 if (session->interface_address.s_addr == htonl(publicAddress) && privatePort == publicPort) { 4460 notice("%s port-mapping update for %s indicates no NAT. Public Address: %x, Protocol: %s, Private Port: %d, Public Port: %d\n", 4461 sd_name, 4462 if_name, 4463 publicAddress, 4464 (protocol == 0)? "None":((protocol == kDNSServiceProtocol_UDP)? "UDP":"TCP"), 4465 privatePort, 4466 publicPort); 4467 } 4468 4469 if (session->nat_mapping[i].interfaceIndex == interfaceIndex && 4470 session->nat_mapping[i].protocol == protocol && 4471 session->nat_mapping[i].privatePort == privatePort) { 4472 info("%s port-mapping for %s consistent. is Connected: %d, interface: %d, protocol: %d, privatePort: %d\n", 4473 sd_name, if_name, is_connected, interfaceIndex, protocol, privatePort); 4474 } else { 4475 // inconsistency (mostly because of mdns api only works for the primary interface): TODO revise 4476 if (session->nat_mapping[i].interfaceIndex != interfaceIndex) { 4477 info("%s port-mapping for %s inconsistent. is Connected: %d, Previous interface: %d, Current interface %d\n", 4478 sd_name, if_name, is_connected, session->nat_mapping[i].interfaceIndex, interfaceIndex); 4479 session->nat_mapping[i].interfaceIndex = interfaceIndex; 4480 } 4481 if (session->nat_mapping[i].protocol != protocol) { 4482 info("%s port-mapping for %s inconsistent. is Connected: %d, Previous protocol: %x, Current protocol %x\n", 4483 sd_name, if_name, is_connected, session->nat_mapping[i].protocol, protocol); 4484 session->nat_mapping[i].protocol = protocol; 4485 } 4486 if (session->nat_mapping[i].privatePort != privatePort) { 4487 info("%s port-mapping for %s inconsistent. is Connected: %d, Previous privatePort: %d, Current privatePort %d\n", 4488 sd_name, if_name, session->nat_mapping[i].privatePort, privatePort); 4489 session->nat_mapping[i].privatePort = privatePort; 4490 } 4491 } 4492 // is mapping up? 4493 if (!session->nat_mapping[i].up) { 4494 if (session->nat_mapping[i].reflexive.addr != publicAddress) { 4495 info("%s port-mapping for %s initialized. is Connected: %d, Previous publicAddress: (%d), Current publicAddress %x\n", 4496 sd_name, if_name, is_connected, session->nat_mapping[i].reflexive.addr, publicAddress); 4497 session->nat_mapping[i].reflexive.addr = publicAddress; 4498 } 4499 if (session->nat_mapping[i].reflexive.port != publicPort) { 4500 info("%s port-mapping for %s initialized. is Connected: %d, Previous publicPort: (%d), Current publicPort %d\n", 4501 sd_name, if_name, is_connected, session->nat_mapping[i].reflexive.port, publicPort); 4502 session->nat_mapping[i].reflexive.port = publicPort; 4503 } 4504 if (session->nat_mapping[i].reflexive.addr && 4505 ((!privatePort && !session->nat_mapping[i].reflexive.port) || (session->nat_mapping[i].reflexive.port))) { 4506 // flag up mapping 4507 session->nat_mapping[i].up = 1; 4508 info("%s port-mapping for %s fully initialized. Flagging up\n", sd_name, if_name); 4509 } 4510 return; 4511 } 4512 4513 if (session->nat_mapping[i].reflexive.addr != publicAddress) { 4514 error("%s port-mapping for %s changed. is Connected: %d, Previous publicAddress: (%x), Current publicAddress %x\n", 4515 sd_name, if_name, is_connected, session->nat_mapping[i].reflexive.addr, publicAddress); 4516 if (is_connected) { 4517 if (!privatePort || publicAddress) { 4518 syslog(LOG_ERR, "NAT's public address down or changed... starting faster probe.\n"); 4519 if (session->failure_func) { 4520 wait_port_mapping_changed = 1; 4521 session->failure_func(); 4522 } 4523 return; 4524 } 4525 // let function that handles (KEV_INET_NEW_ADDR || KEV_INET_CHANGED_ADDR || KEV_INET_ADDR_DELETED) deal with the connection 4526 return; 4527 } 4528 session->nat_mapping[i].reflexive.addr = publicAddress; 4529 return; 4530 } 4531 if (session->nat_mapping[i].reflexive.port != publicPort) { 4532 error("%s port-mapping for %s changed. is Connected: %d, Previous publicPort: (%d), Current publicPort %d\n", 4533 sd_name, if_name, is_connected, session->nat_mapping[i].reflexive.port, publicPort); 4534 if (is_connected) { 4535 if (!privatePort || publicPort) { 4536 syslog(LOG_ERR, "NAT's public port down or changed... starting faster probe.\n"); 4537 if (session->failure_func) { 4538 wait_port_mapping_changed = 1; 4539 session->failure_func(); 4540 } 4541 return; 4542 } 4543 // let function that handles (KEV_INET_NEW_ADDR || KEV_INET_CHANGED_ADDR || KEV_INET_ADDR_DELETED) deal with the connection 4544 return; 4545 } 4546 session->nat_mapping[i].reflexive.port = publicPort; 4547 return; 4548 } 4549 if (errorCode == kDNSServiceErr_DoubleNAT) { 4550 error("%s port-mapping for %s hasn't changed, however there's a Double NAT. is Connected: %d\n", 4551 sd_name, if_name, is_connected); 4552 } 4553 return; 4554 } 4555 } 4556 return; 4557} 4558 4559static void 4560ppp_clear_nat_port_mapping (void) 4561{ 4562 int i; 4563 4564 if (!session || !session->valid) 4565 return; 4566 4567 info("%s clearing port-mapping for %s\n", session->sd_name, session->interface_name); 4568 4569 ppp_stop_public_nat_port_mapping_timer(); 4570 4571 for (i = 0; i < session->nat_mapping_cnt && i < MDNS_NAT_MAPPING_MAX; i++) { 4572 ppp_clear_one_nat_port_mapping(&session->nat_mapping[i]); 4573 } 4574 session->nat_mapping_cnt = 0; 4575} 4576 4577static int 4578ppp_set_nat_port_mapping (mdns_nat_mapping_t *mapping, 4579 DNSServiceProtocol protocol, 4580 uint16_t privatePort, 4581 int probe_only) 4582{ 4583 DNSServiceErrorType err = kDNSServiceErr_NoError; 4584 uint16_t publicPort; 4585 uint32_t ttl; 4586 char *sd_name = session->sd_name; 4587 char *if_name = session->interface_name; 4588 uint32_t interfaceIndex = if_nametoindex(session->interface_name); 4589 4590 if (!probe_only) { 4591 publicPort = 0; 4592 ttl = 2 * 3600; // 2 hours 4593 } else { 4594 publicPort = 0; 4595 ttl = 0; 4596 protocol = 0; 4597 privatePort = 0; 4598 } 4599 4600 if (mapping == NULL) { 4601 error("%s invalid mapping pointer for %s\n", sd_name, if_name); 4602 return -1; 4603 } 4604 4605 if (mapping->mDNSRef == NULL) { 4606 err = DNSServiceCreateConnection(&mapping->mDNSRef); 4607 if (err != kDNSServiceErr_NoError || mapping->mDNSRef == NULL) { 4608 error("%s Error calling DNSServiceCreateConnection for %s, error: %d\n", sd_name, if_name, err); 4609 ppp_clear_one_nat_port_mapping(mapping); 4610 return -1; 4611 } 4612 mapping->mDNSRef_fd = DNSServiceRefSockFD(mapping->mDNSRef); 4613 add_fd(mapping->mDNSRef_fd); 4614 } 4615 mapping->mDNSRef_tmp = mapping->mDNSRef; 4616 err = DNSServiceNATPortMappingCreate(&mapping->mDNSRef_tmp, kDNSServiceFlagsShareConnection, interfaceIndex, protocol, htons(privatePort), publicPort, ttl, ppp_set_nat_port_mapping_callback, session); 4617 if (err != kDNSServiceErr_NoError) { 4618 error("%s Error calling DNSServiceNATPortMappingCreate for %s, error: %d\n", sd_name, if_name, err); 4619 ppp_clear_one_nat_port_mapping(mapping); 4620 return -1; 4621 } 4622 mapping->interfaceIndex = interfaceIndex; 4623 mapping->protocol = protocol; 4624 mapping->privatePort = privatePort; 4625 bzero(&mapping->reflexive, sizeof(mapping->reflexive)); 4626 4627 info("%s set port-mapping for %s, interface: %d, protocol: %d, privatePort: %d\n", sd_name, if_name, interfaceIndex, protocol, privatePort); 4628 return 0; 4629} 4630 4631static void 4632l2tp_ipsec_set_nat_port_mapping (void) 4633{ 4634 if (ppp_set_nat_port_mapping(&session->nat_mapping[0], 0, 0, 1) == 0) { 4635 session->nat_mapping_cnt++; 4636 } 4637#if 0 // <rdar://problem/8001582> 4638 if (ppp_set_nat_port_mapping(&session->nat_mapping[1], kDNSServiceProtocol_UDP, (u_int16_t)500, 0) == 0) { 4639 session->nat_mapping_cnt++; 4640 } 4641 if (ppp_set_nat_port_mapping(&session->nat_mapping[2], kDNSServiceProtocol_UDP, (u_int16_t)4500, 0) == 0) { 4642 session->nat_mapping_cnt++; 4643 } 4644#endif 4645} 4646#endif 4647 4648void 4649l2tp_set_nat_port_mapping (void) 4650{ 4651#if !TARGET_OS_EMBEDDED 4652 if (!session || !session->valid) { 4653 return; 4654 } 4655 4656 if (override_primary) { 4657 info("%s port-mapping API for %s ignored: VPN is the Primary interface.\n", 4658 session->sd_name, 4659 session->interface_name); 4660 return; 4661 } 4662 4663 // exit early if interface is PPP/VPN 4664 if (strstr(session->interface_name, "ppp") || strstr(session->interface_name, "utun")) { 4665 return; 4666 } 4667 4668 if (!session->opt_noipsec) { 4669 // we always tranport l2tp over ipsec 4670 l2tp_ipsec_set_nat_port_mapping(); 4671 } else { 4672 if (ppp_set_nat_port_mapping(&session->nat_mapping[0], 0, 0, 1) == 0) { 4673 session->nat_mapping_cnt++; 4674 } 4675#if 0 // <rdar://problem/8001582> 4676 if (ppp_set_nat_port_mapping(&session->nat_mapping[1], kDNSServiceProtocol_UDP, (u_int16_t)1701, 0) == 0) { 4677 session->nat_mapping_cnt++; 4678 } 4679#endif 4680 } 4681#endif // TARGET_OS_EMBEDDED 4682} 4683 4684void 4685l2tp_clear_nat_port_mapping (void) 4686{ 4687#if !TARGET_OS_EMBEDDED 4688 ppp_clear_nat_port_mapping(); 4689#endif // TARGET_OS_EMBEDDED 4690} 4691 4692void 4693pptp_set_nat_port_mapping (void) 4694{ 4695#if !TARGET_OS_EMBEDDED 4696 if (!session || !session->valid) { 4697 return; 4698 } 4699 4700 if (override_primary) { 4701 info("%s port-mapping API for %s ignored: VPN is the Primary interface.\n", 4702 session->sd_name, 4703 session->interface_name); 4704 return; 4705 } 4706 4707 // exit early if interface is PPP/VPN 4708 if (strstr(session->interface_name, "ppp") || strstr(session->interface_name, "utun")) { 4709 return; 4710 } 4711 4712 if (ppp_set_nat_port_mapping(&session->nat_mapping[0], 0, 0, 1) == 0) { 4713 session->nat_mapping_cnt++; 4714 } 4715#if 0 // <rdar://problem/8001582> 4716 if (ppp_set_nat_port_mapping(&session->nat_mapping[1], kDNSServiceProtocol_TCP, (u_int16_t)1723, 0) == 0) { 4717 session->nat_mapping_cnt++; 4718 } 4719#endif 4720#endif // TARGET_OS_EMBEDDED 4721} 4722 4723void 4724pptp_clear_nat_port_mapping (void) 4725{ 4726#if !TARGET_OS_EMBEDDED 4727 ppp_clear_nat_port_mapping(); 4728#endif // TARGET_OS_EMBEDDED 4729} 4730 4731void 4732ppp_process_nat_port_mapping_events (void) 4733{ 4734#if !TARGET_OS_EMBEDDED 4735 int i = 0; 4736 DNSServiceErrorType ret; 4737 4738 for (i = 0; session && session->valid && i < session->nat_mapping_cnt && i < MDNS_NAT_MAPPING_MAX; i++) { 4739 if (session->nat_mapping[i].mDNSRef && is_ready_fd(session->nat_mapping[i].mDNSRef_fd)) { 4740 ret = DNSServiceProcessResult(session->nat_mapping[i].mDNSRef); 4741 if (ret != kDNSServiceErr_NoError && ret != kDNSServiceErr_Transient) { 4742 error("Error calling DNSServiceProcessResult, error: %d\n", ret); 4743 if (ret == kDNSServiceErr_ServiceNotRunning) { 4744 ppp_clear_nat_port_mapping(); 4745 } 4746 } 4747 // the connection may have been disconnected... hence session may be invalidated after DNSServiceProcessResult. 4748 } 4749 } 4750#endif // TARGET_OS_EMBEDDED 4751} 4752