main.c revision 81634
1/*- 2 * Copyright (c) 1996 - 2001 Brian Somers <brian@Awfulhak.org> 3 * based on work by Toshiharu OHNO <tony-o@iij.ad.jp> 4 * Internet Initiative Japan, Inc (IIJ) 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 * 28 * $FreeBSD: head/usr.sbin/ppp/main.c 81634 2001-08-14 16:05:52Z brian $ 29 */ 30 31#include <sys/param.h> 32#include <netinet/in.h> 33#include <netinet/in_systm.h> 34#include <netinet/ip.h> 35#include <sys/un.h> 36#include <sys/socket.h> 37#include <net/route.h> 38 39#include <errno.h> 40#include <fcntl.h> 41#include <paths.h> 42#include <signal.h> 43#include <stdio.h> 44#include <stdlib.h> 45#include <string.h> 46#include <sys/time.h> 47#include <termios.h> 48#include <unistd.h> 49#include <sys/stat.h> 50 51#ifndef NONAT 52#ifdef LOCALNAT 53#include "alias.h" 54#else 55#include <alias.h> 56#endif 57#endif 58 59#include "layer.h" 60#include "probe.h" 61#include "mbuf.h" 62#include "log.h" 63#include "defs.h" 64#include "id.h" 65#include "timer.h" 66#include "fsm.h" 67#include "lqr.h" 68#include "hdlc.h" 69#include "lcp.h" 70#include "ccp.h" 71#include "iplist.h" 72#include "throughput.h" 73#include "slcompress.h" 74#include "ncpaddr.h" 75#include "ip.h" 76#include "ipcp.h" 77#include "filter.h" 78#include "descriptor.h" 79#include "link.h" 80#include "mp.h" 81#ifndef NORADIUS 82#include "radius.h" 83#endif 84#include "ipv6cp.h" 85#include "ncp.h" 86#include "bundle.h" 87#include "auth.h" 88#include "systems.h" 89#include "sig.h" 90#include "main.h" 91#include "server.h" 92#include "prompt.h" 93#include "chat.h" 94#include "chap.h" 95#include "cbcp.h" 96#include "datalink.h" 97#include "iface.h" 98 99#ifndef O_NONBLOCK 100#ifdef O_NDELAY 101#define O_NONBLOCK O_NDELAY 102#endif 103#endif 104 105static void DoLoop(struct bundle *); 106static void TerminalStop(int); 107 108static struct bundle *SignalBundle; 109static struct prompt *SignalPrompt; 110 111void 112Cleanup(int excode) 113{ 114 SignalBundle->CleaningUp = 1; 115 bundle_Close(SignalBundle, NULL, CLOSE_STAYDOWN); 116} 117 118void 119AbortProgram(int excode) 120{ 121 server_Close(SignalBundle); 122 log_Printf(LogPHASE, "PPP Terminated (%s).\n", ex_desc(excode)); 123 bundle_Close(SignalBundle, NULL, CLOSE_STAYDOWN); 124 bundle_Destroy(SignalBundle); 125 log_Close(); 126 exit(excode); 127} 128 129static void 130CloseConnection(int signo) 131{ 132 /* NOTE, these are manual, we've done a setsid() */ 133 sig_signal(SIGINT, SIG_IGN); 134 log_Printf(LogPHASE, "Caught signal %d, abort connection(s)\n", signo); 135 bundle_Down(SignalBundle, CLOSE_STAYDOWN); 136 sig_signal(SIGINT, CloseConnection); 137} 138 139static void 140CloseSession(int signo) 141{ 142 log_Printf(LogPHASE, "Signal %d, terminate.\n", signo); 143 Cleanup(EX_TERM); 144} 145 146static pid_t BGPid = 0; 147 148static void 149KillChild(int signo) 150{ 151 signal(signo, SIG_IGN); 152 log_Printf(LogPHASE, "Parent: Signal %d\n", signo); 153 kill(BGPid, SIGINT); 154} 155 156static void 157TerminalCont(int signo) 158{ 159 signal(SIGCONT, SIG_DFL); 160 prompt_Continue(SignalPrompt); 161} 162 163static void 164TerminalStop(int signo) 165{ 166 prompt_Suspend(SignalPrompt); 167 signal(SIGCONT, TerminalCont); 168 raise(SIGSTOP); 169} 170 171static void 172BringDownServer(int signo) 173{ 174 /* Drops all child prompts too ! */ 175 if (server_Close(SignalBundle)) 176 log_Printf(LogPHASE, "Closed server socket\n"); 177} 178 179static void 180RestartServer(int signo) 181{ 182 /* Drops all child prompts and re-opens the socket */ 183 server_Reopen(SignalBundle); 184} 185 186static void 187Usage(void) 188{ 189 fprintf(stderr, "Usage: ppp [-auto | -foreground | -background | -direct |" 190 " -dedicated | -ddial | -interactive]" 191#ifndef NOALIAS 192 " [-nat]" 193#endif 194 " [-quiet] [-unit N] [system ...]\n"); 195 exit(EX_START); 196} 197 198struct switches { 199 unsigned nat : 1; 200 unsigned fg : 1; 201 unsigned quiet : 1; 202 int mode; 203 int unit; 204}; 205 206static int 207ProcessArgs(int argc, char **argv, struct switches *sw) 208{ 209 int optc, newmode, arg; 210 char *cp; 211 212 optc = 0; 213 memset(sw, '\0', sizeof *sw); 214 sw->mode = PHYS_INTERACTIVE; 215 sw->unit = -1; 216 217 for (arg = 1; arg < argc && *argv[arg] == '-'; arg++, optc++) { 218 cp = argv[arg] + 1; 219 newmode = Nam2mode(cp); 220 switch (newmode) { 221 case PHYS_NONE: 222 if (strcmp(cp, "nat") == 0) { 223#ifdef NONAT 224 log_Printf(LogWARN, "%s ignored: NAT is compiled out\n", argv[arg]); 225#else 226 sw->nat = 1; 227#endif 228 optc--; /* this option isn't exclusive */ 229 } else if (strcmp(cp, "alias") == 0) { 230#ifdef NONAT 231 log_Printf(LogWARN, "%s ignored: NAT is compiled out\n", argv[arg]); 232 fprintf(stderr, "%s ignored: NAT is compiled out\n", argv[arg]); 233#else 234 log_Printf(LogWARN, "%s is deprecated\n", argv[arg]); 235 fprintf(stderr, "%s is deprecated\n", argv[arg]); 236 sw->nat = 1; 237#endif 238 optc--; /* this option isn't exclusive */ 239 } else if (strncmp(cp, "unit", 4) == 0) { 240 optc--; /* this option isn't exclusive */ 241 if (cp[4] == '\0') { 242 optc--; /* nor is the argument */ 243 if (++arg == argc) { 244 fprintf(stderr, "-unit: Expected unit number\n"); 245 Usage(); 246 } else 247 sw->unit = atoi(argv[arg]); 248 } else 249 sw->unit = atoi(cp + 4); 250 } else if (strcmp(cp, "quiet") == 0) { 251 sw->quiet = 1; 252 optc--; /* this option isn't exclusive */ 253 } else 254 Usage(); 255 break; 256 257 case PHYS_ALL: 258 Usage(); 259 break; 260 261 default: 262 sw->mode = newmode; 263 if (newmode == PHYS_FOREGROUND) 264 sw->fg = 1; 265 } 266 } 267 268 if (optc > 1) { 269 fprintf(stderr, "You may specify only one mode.\n"); 270 exit(EX_START); 271 } 272 273 if (sw->mode == PHYS_AUTO && arg == argc) { 274 fprintf(stderr, "A system must be specified in auto mode.\n"); 275 exit(EX_START); 276 } 277 278 return arg; /* Don't SetLabel yet ! */ 279} 280 281static void 282CheckLabel(const char *label, struct prompt *prompt, int mode) 283{ 284 const char *err; 285 286 if ((err = system_IsValid(label, prompt, mode)) != NULL) { 287 fprintf(stderr, "%s: %s\n", label, err); 288 if (mode == PHYS_DIRECT) 289 log_Printf(LogWARN, "Label %s rejected -direct connection: %s\n", 290 label, err); 291 log_Close(); 292 exit(1); 293 } 294} 295 296 297int 298main(int argc, char **argv) 299{ 300 char *name; 301 const char *lastlabel; 302 int arg, f, holdfd[3], label; 303 struct bundle *bundle; 304 struct prompt *prompt; 305 struct switches sw; 306 307 /* 308 * We open 3 descriptors to ensure that STDIN_FILENO, STDOUT_FILENO and 309 * STDERR_FILENO are always open. These are closed before DoLoop(), 310 * but *after* we've avoided the possibility of erroneously closing 311 * an important descriptor with close(STD{IN,OUT,ERR}_FILENO). 312 */ 313 if ((holdfd[0] = open(_PATH_DEVNULL, O_RDWR)) == -1) { 314 fprintf(stderr, "Cannot open %s !\n", _PATH_DEVNULL); 315 return 2; 316 } 317 for (f = 1; f < sizeof holdfd / sizeof *holdfd; f++) 318 holdfd[f] = dup(holdfd[0]); 319 320 name = strrchr(argv[0], '/'); 321 log_Open(name ? name + 1 : argv[0]); 322 323#ifndef NONAT 324 PacketAliasInit(); 325#endif 326 label = ProcessArgs(argc, argv, &sw); 327 328 /* 329 * A FreeBSD & OpenBSD hack to dodge a bug in the tty driver that drops 330 * output occasionally.... I must find the real reason some time. To 331 * display the dodgy behaviour, comment out this bit, make yourself a large 332 * routing table and then run ppp in interactive mode. The `show route' 333 * command will drop chunks of data !!! 334 */ 335 if (sw.mode == PHYS_INTERACTIVE) { 336 close(STDIN_FILENO); 337 if (open(_PATH_TTY, O_RDONLY) != STDIN_FILENO) { 338 fprintf(stderr, "Cannot open %s for input !\n", _PATH_TTY); 339 return 2; 340 } 341 } 342 343 /* Allow output for the moment (except in direct mode) */ 344 if (sw.mode == PHYS_DIRECT) 345 prompt = NULL; 346 else 347 SignalPrompt = prompt = prompt_Create(NULL, NULL, PROMPT_STD); 348 349 ID0init(); 350 if (ID0realuid() != 0) { 351 char conf[200], *ptr; 352 353 snprintf(conf, sizeof conf, "%s/%s", PPP_CONFDIR, CONFFILE); 354 do { 355 struct stat sb; 356 357 if (stat(conf, &sb) == 0 && sb.st_mode & S_IWOTH) { 358 log_Printf(LogALERT, "ppp: Access violation: Please protect %s\n", 359 conf); 360 return -1; 361 } 362 ptr = conf + strlen(conf)-2; 363 while (ptr > conf && *ptr != '/') 364 *ptr-- = '\0'; 365 } while (ptr >= conf); 366 } 367 368 if (label < argc) 369 for (arg = label; arg < argc; arg++) 370 CheckLabel(argv[arg], prompt, sw.mode); 371 else 372 CheckLabel("default", prompt, sw.mode); 373 374 if (!sw.quiet) 375 prompt_Printf(prompt, "Working in %s mode\n", mode2Nam(sw.mode)); 376 377 if ((bundle = bundle_Create(TUN_PREFIX, sw.mode, sw.unit)) == NULL) 378 return EX_START; 379 380 /* NOTE: We may now have changed argv[1] via a ``set proctitle'' */ 381 382 if (prompt) { 383 prompt->bundle = bundle; /* couldn't do it earlier */ 384 if (!sw.quiet) 385 prompt_Printf(prompt, "Using interface: %s\n", bundle->iface->name); 386 } 387 SignalBundle = bundle; 388 bundle->NatEnabled = sw.nat; 389 if (sw.nat) 390 bundle->cfg.opt |= OPT_IFACEALIAS; 391 392 if (system_Select(bundle, "default", CONFFILE, prompt, NULL) < 0) 393 prompt_Printf(prompt, "Warning: No default entry found in config file.\n"); 394 395 sig_signal(SIGHUP, CloseSession); 396 sig_signal(SIGTERM, CloseSession); 397 sig_signal(SIGINT, CloseConnection); 398 sig_signal(SIGQUIT, CloseSession); 399 sig_signal(SIGALRM, SIG_IGN); 400 signal(SIGPIPE, SIG_IGN); 401 402 if (sw.mode == PHYS_INTERACTIVE) 403 sig_signal(SIGTSTP, TerminalStop); 404 405 sig_signal(SIGUSR1, RestartServer); 406 sig_signal(SIGUSR2, BringDownServer); 407 408 lastlabel = argv[argc - 1]; 409 for (arg = label; arg < argc; arg++) { 410 /* In case we use LABEL or ``set enddisc label'' */ 411 bundle_SetLabel(bundle, lastlabel); 412 system_Select(bundle, argv[arg], CONFFILE, prompt, NULL); 413 } 414 415 if (label < argc) 416 /* In case the last label did a ``load'' */ 417 bundle_SetLabel(bundle, lastlabel); 418 419 if (sw.mode == PHYS_AUTO && 420 ncprange_family(&bundle->ncp.ipcp.cfg.peer_range) == AF_UNSPEC) { 421 prompt_Printf(prompt, "You must ``set ifaddr'' with a peer address " 422 "in auto mode.\n"); 423 AbortProgram(EX_START); 424 } 425 426 if (sw.mode != PHYS_INTERACTIVE) { 427 if (sw.mode != PHYS_DIRECT) { 428 if (!sw.fg) { 429 int bgpipe[2]; 430 pid_t bgpid; 431 432 if (sw.mode == PHYS_BACKGROUND && pipe(bgpipe)) { 433 log_Printf(LogERROR, "pipe: %s\n", strerror(errno)); 434 AbortProgram(EX_SOCK); 435 } 436 437 bgpid = fork(); 438 if (bgpid == -1) { 439 log_Printf(LogERROR, "fork: %s\n", strerror(errno)); 440 AbortProgram(EX_SOCK); 441 } 442 443 if (bgpid) { 444 char c = EX_NORMAL; 445 int ret; 446 447 if (sw.mode == PHYS_BACKGROUND) { 448 close(bgpipe[1]); 449 BGPid = bgpid; 450 /* If we get a signal, kill the child */ 451 signal(SIGHUP, KillChild); 452 signal(SIGTERM, KillChild); 453 signal(SIGINT, KillChild); 454 signal(SIGQUIT, KillChild); 455 456 /* Wait for our child to close its pipe before we exit */ 457 while ((ret = read(bgpipe[0], &c, 1)) == 1) { 458 switch (c) { 459 case EX_NORMAL: 460 if (!sw.quiet) { 461 prompt_Printf(prompt, "PPP enabled\n"); 462 log_Printf(LogPHASE, "Parent: PPP enabled\n"); 463 } 464 break; 465 case EX_REDIAL: 466 if (!sw.quiet) 467 prompt_Printf(prompt, "Attempting redial\n"); 468 continue; 469 case EX_RECONNECT: 470 if (!sw.quiet) 471 prompt_Printf(prompt, "Attempting reconnect\n"); 472 continue; 473 default: 474 prompt_Printf(prompt, "Child failed (%s)\n", 475 ex_desc((int)c)); 476 log_Printf(LogPHASE, "Parent: Child failed (%s)\n", 477 ex_desc((int) c)); 478 } 479 break; 480 } 481 if (ret != 1) { 482 prompt_Printf(prompt, "Child exit, no status.\n"); 483 log_Printf(LogPHASE, "Parent: Child exit, no status.\n"); 484 } 485 close(bgpipe[0]); 486 } 487 return c; 488 } else if (sw.mode == PHYS_BACKGROUND) { 489 close(bgpipe[0]); 490 bundle->notify.fd = bgpipe[1]; 491 } 492 493 bundle_ChangedPID(bundle); 494 bundle_LockTun(bundle); /* we have a new pid */ 495 } 496 497 /* -auto, -dedicated, -ddial, -foreground & -background */ 498 prompt_Destroy(prompt, 0); 499 close(STDOUT_FILENO); 500 close(STDERR_FILENO); 501 close(STDIN_FILENO); 502 if (!sw.fg) 503 setsid(); 504 } else { 505 /* -direct - STDIN_FILENO gets used by physical_Open */ 506 prompt_TtyInit(NULL); 507 close(STDOUT_FILENO); 508 close(STDERR_FILENO); 509 } 510 } else { 511 /* -interactive */ 512 close(STDERR_FILENO); 513 prompt_TtyInit(prompt); 514 prompt_TtyCommandMode(prompt); 515 prompt_Required(prompt); 516 } 517 518 /* We can get rid of these now */ 519 for (f = 0; f < sizeof holdfd / sizeof *holdfd; f++) 520 close(holdfd[f]); 521 522 log_Printf(LogPHASE, "PPP Started (%s mode).\n", mode2Nam(sw.mode)); 523 DoLoop(bundle); 524 AbortProgram(EX_NORMAL); 525 526 return EX_NORMAL; 527} 528 529static void 530DoLoop(struct bundle *bundle) 531{ 532 fd_set *rfds, *wfds, *efds; 533 int i, nfds, nothing_done; 534 struct probe probe; 535 536 probe_Init(&probe); 537 538 if ((rfds = mkfdset()) == NULL) { 539 log_Printf(LogERROR, "DoLoop: Cannot create fd_set\n"); 540 return; 541 } 542 543 if ((wfds = mkfdset()) == NULL) { 544 log_Printf(LogERROR, "DoLoop: Cannot create fd_set\n"); 545 free(rfds); 546 return; 547 } 548 549 if ((efds = mkfdset()) == NULL) { 550 log_Printf(LogERROR, "DoLoop: Cannot create fd_set\n"); 551 free(rfds); 552 free(wfds); 553 return; 554 } 555 556 for (; !bundle_IsDead(bundle); bundle_CleanDatalinks(bundle)) { 557 nfds = 0; 558 zerofdset(rfds); 559 zerofdset(wfds); 560 zerofdset(efds); 561 562 /* All our datalinks, the tun device and the MP socket */ 563 descriptor_UpdateSet(&bundle->desc, rfds, wfds, efds, &nfds); 564 565 /* All our prompts and the diagnostic socket */ 566 descriptor_UpdateSet(&server.desc, rfds, NULL, NULL, &nfds); 567 568 bundle_CleanDatalinks(bundle); 569 if (bundle_IsDead(bundle)) 570 /* Don't select - we'll be here forever */ 571 break; 572 573 /* 574 * It's possible that we've had a signal since we last checked. If 575 * we don't check again before calling select(), we may end up stuck 576 * after having missed the event.... sig_Handle() tries to be as 577 * quick as possible if nothing is likely to have happened. 578 * This is only really likely if we block in open(... O_NONBLOCK) 579 * which will happen with a misconfigured device. 580 */ 581 if (sig_Handle()) 582 continue; 583 584 i = select(nfds, rfds, wfds, efds, NULL); 585 586 if (i < 0 && errno != EINTR) { 587 log_Printf(LogERROR, "DoLoop: select(): %s\n", strerror(errno)); 588 if (log_IsKept(LogTIMER)) { 589 struct timeval t; 590 591 for (i = 0; i <= nfds; i++) { 592 if (FD_ISSET(i, rfds)) { 593 log_Printf(LogTIMER, "Read set contains %d\n", i); 594 FD_CLR(i, rfds); 595 t.tv_sec = t.tv_usec = 0; 596 if (select(nfds, rfds, wfds, efds, &t) != -1) { 597 log_Printf(LogTIMER, "The culprit !\n"); 598 break; 599 } 600 } 601 if (FD_ISSET(i, wfds)) { 602 log_Printf(LogTIMER, "Write set contains %d\n", i); 603 FD_CLR(i, wfds); 604 t.tv_sec = t.tv_usec = 0; 605 if (select(nfds, rfds, wfds, efds, &t) != -1) { 606 log_Printf(LogTIMER, "The culprit !\n"); 607 break; 608 } 609 } 610 if (FD_ISSET(i, efds)) { 611 log_Printf(LogTIMER, "Error set contains %d\n", i); 612 FD_CLR(i, efds); 613 t.tv_sec = t.tv_usec = 0; 614 if (select(nfds, rfds, wfds, efds, &t) != -1) { 615 log_Printf(LogTIMER, "The culprit !\n"); 616 break; 617 } 618 } 619 } 620 } 621 break; 622 } 623 624 log_Printf(LogTIMER, "Select returns %d\n", i); 625 626 sig_Handle(); 627 628 if (i <= 0) 629 continue; 630 631 for (i = 0; i <= nfds; i++) 632 if (FD_ISSET(i, efds)) { 633 log_Printf(LogPHASE, "Exception detected on descriptor %d\n", i); 634 /* We deal gracefully with link descriptor exceptions */ 635 if (!bundle_Exception(bundle, i)) { 636 log_Printf(LogERROR, "Exception cannot be handled !\n"); 637 break; 638 } 639 } 640 641 if (i <= nfds) 642 break; 643 644 nothing_done = 1; 645 646 if (descriptor_IsSet(&server.desc, rfds)) { 647 descriptor_Read(&server.desc, bundle, rfds); 648 nothing_done = 0; 649 } 650 651 if (descriptor_IsSet(&bundle->desc, rfds)) { 652 descriptor_Read(&bundle->desc, bundle, rfds); 653 nothing_done = 0; 654 } 655 656 if (descriptor_IsSet(&bundle->desc, wfds)) 657 if (!descriptor_Write(&bundle->desc, bundle, wfds) && nothing_done) { 658 /* 659 * This is disasterous. The OS has told us that something is 660 * writable, and all our write()s have failed. Rather than 661 * going back immediately to do our UpdateSet()s and select(), 662 * we sleep for a bit to avoid gobbling up all cpu time. 663 */ 664 struct timeval t; 665 666 t.tv_sec = 0; 667 t.tv_usec = 100000; 668 select(0, NULL, NULL, NULL, &t); 669 } 670 } 671 672 log_Printf(LogDEBUG, "DoLoop done.\n"); 673} 674