Exemplo n.º 1
0
int
main(int argc, char **argv)
{
  char *name;
  const char *lastlabel;
  int arg, f, holdfd[3], label;
  struct bundle *bundle;
  struct prompt *prompt;
  struct switches sw;

  probe_Init();

  /*
   * We open 3 descriptors to ensure that STDIN_FILENO, STDOUT_FILENO and
   * STDERR_FILENO are always open.  These are closed before DoLoop(),
   * but *after* we've avoided the possibility of erroneously closing
   * an important descriptor with close(STD{IN,OUT,ERR}_FILENO).
   */
  if ((holdfd[0] = open(_PATH_DEVNULL, O_RDWR)) == -1) {
    fprintf(stderr, "Cannot open %s !\n", _PATH_DEVNULL);
    return 2;
  }
  for (f = 1; f < sizeof holdfd / sizeof *holdfd; f++)
    holdfd[f] = dup(holdfd[0]);

  name = strrchr(argv[0], '/');
  log_Open(name ? name + 1 : argv[0]);

#ifndef NONAT
  PacketAliasInit();
#endif
  label = ProcessArgs(argc, argv, &sw);

  /*
   * A FreeBSD & OpenBSD hack to dodge a bug in the tty driver that drops
   * output occasionally.... I must find the real reason some time.  To
   * display the dodgy behaviour, comment out this bit, make yourself a large
   * routing table and then run ppp in interactive mode.  The `show route'
   * command will drop chunks of data !!!
   */
  if (sw.mode == PHYS_INTERACTIVE) {
    close(STDIN_FILENO);
    if (open(_PATH_TTY, O_RDONLY) != STDIN_FILENO) {
      fprintf(stderr, "Cannot open %s for input !\n", _PATH_TTY);
      return 2;
    }
  }

  /* Allow output for the moment (except in direct mode) */
  if (sw.mode == PHYS_DIRECT)
    prompt = NULL;
  else
    SignalPrompt = prompt = prompt_Create(NULL, NULL, PROMPT_STD);

  ID0init();
  if (ID0realuid() != 0) {
    char conf[200], *ptr;

    snprintf(conf, sizeof conf, "%s/%s", PPP_CONFDIR, CONFFILE);
    do {
      struct stat sb;

      if (stat(conf, &sb) == 0 && sb.st_mode & S_IWOTH) {
        log_Printf(LogALERT, "ppp: Access violation: Please protect %s\n",
                   conf);
        return -1;
      }
      ptr = conf + strlen(conf)-2;
      while (ptr > conf && *ptr != '/')
        *ptr-- = '\0';
    } while (ptr >= conf);
  }

  if (label < argc)
    for (arg = label; arg < argc; arg++)
      CheckLabel(argv[arg], prompt, sw.mode);
  else
    CheckLabel("default", prompt, sw.mode);

  if (!sw.quiet)
    prompt_Printf(prompt, "Working in %s mode\n", mode2Nam(sw.mode));

  if ((bundle = bundle_Create(TUN_PREFIX, sw.mode, sw.unit)) == NULL)
    return EX_START;

  /* NOTE:  We may now have changed argv[1] via a ``set proctitle'' */

  if (prompt) {
    prompt->bundle = bundle;	/* couldn't do it earlier */
    if (!sw.quiet)
      prompt_Printf(prompt, "Using interface: %s\n", bundle->iface->name);
  }
  SignalBundle = bundle;
  bundle->NatEnabled = sw.nat;
  if (sw.nat)
    opt_enable(bundle, OPT_IFACEALIAS);

  if (system_Select(bundle, "default", CONFFILE, prompt, NULL) < 0)
    prompt_Printf(prompt, "Warning: No default entry found in config file.\n");

  sig_signal(SIGHUP, CloseSession);
  sig_signal(SIGTERM, CloseSession);
  sig_signal(SIGINT, CloseConnection);
  sig_signal(SIGQUIT, CloseSession);
  sig_signal(SIGALRM, SIG_IGN);
  signal(SIGPIPE, SIG_IGN);

  if (sw.mode == PHYS_INTERACTIVE)
    sig_signal(SIGTSTP, TerminalStop);

  sig_signal(SIGUSR1, RestartServer);
  sig_signal(SIGUSR2, BringDownServer);

  lastlabel = argv[argc - 1];
  for (arg = label; arg < argc; arg++) {
    /* In case we use LABEL or ``set enddisc label'' */
    bundle_SetLabel(bundle, lastlabel);
    system_Select(bundle, argv[arg], CONFFILE, prompt, NULL);
  }

  if (label < argc)
    /* In case the last label did a ``load'' */
    bundle_SetLabel(bundle, lastlabel);

  if (sw.mode == PHYS_AUTO &&
      ncprange_family(&bundle->ncp.ipcp.cfg.peer_range) == AF_UNSPEC) {
    prompt_Printf(prompt, "You must ``set ifaddr'' with a peer address "
                  "in auto mode.\n");
    AbortProgram(EX_START);
  }

  if (sw.mode != PHYS_INTERACTIVE) {
    if (sw.mode != PHYS_DIRECT) {
      if (!sw.fg) {
        int bgpipe[2];
        pid_t bgpid;

        if (sw.mode == PHYS_BACKGROUND && pipe(bgpipe)) {
          log_Printf(LogERROR, "pipe: %s\n", strerror(errno));
	  AbortProgram(EX_SOCK);
        }

        bgpid = fork();
        if (bgpid == -1) {
	  log_Printf(LogERROR, "fork: %s\n", strerror(errno));
	  AbortProgram(EX_SOCK);
        }

        if (bgpid) {
	  char c = EX_NORMAL;
          int ret;

	  if (sw.mode == PHYS_BACKGROUND) {
	    close(bgpipe[1]);
	    BGPid = bgpid;
            /* If we get a signal, kill the child */
            signal(SIGHUP, KillChild);
            signal(SIGTERM, KillChild);
            signal(SIGINT, KillChild);
            signal(SIGQUIT, KillChild);

	    /* Wait for our child to close its pipe before we exit */
            while ((ret = read(bgpipe[0], &c, 1)) == 1) {
              switch (c) {
                case EX_NORMAL:
                  if (!sw.quiet) {
	            prompt_Printf(prompt, "PPP enabled\n");
	            log_Printf(LogPHASE, "Parent: PPP enabled\n");
                  }
	          break;
                case EX_REDIAL:
                  if (!sw.quiet)
	            prompt_Printf(prompt, "Attempting redial\n");
                  continue;
                case EX_RECONNECT:
                  if (!sw.quiet)
	            prompt_Printf(prompt, "Attempting reconnect\n");
                  continue;
	        default:
	          prompt_Printf(prompt, "Child failed (%s)\n",
                                ex_desc((int)c));
	          log_Printf(LogPHASE, "Parent: Child failed (%s)\n",
		             ex_desc((int) c));
	      }
	      break;
            }
            if (ret != 1) {
	      prompt_Printf(prompt, "Child exit, no status.\n");
	      log_Printf(LogPHASE, "Parent: Child exit, no status.\n");
	    }
	    close(bgpipe[0]);
	  }
	  return c;
        } else if (sw.mode == PHYS_BACKGROUND) {
	  close(bgpipe[0]);
          bundle->notify.fd = bgpipe[1];
        }

        bundle_ChangedPID(bundle);
        bundle_LockTun(bundle);	/* we have a new pid */
      }

      /* -auto, -dedicated, -ddial, -foreground & -background */
      prompt_Destroy(prompt, 0);
      close(STDOUT_FILENO);
      close(STDERR_FILENO);
      close(STDIN_FILENO);
      if (!sw.fg)
        setsid();
    } else {
      /* -direct - STDIN_FILENO gets used by physical_Open */
      prompt_TtyInit(NULL);
      close(STDOUT_FILENO);
      close(STDERR_FILENO);
    }
  } else {
    /* -interactive */
    close(STDERR_FILENO);
    prompt_TtyInit(prompt);
    prompt_TtyCommandMode(prompt);
    prompt_Required(prompt);
  }

  /* We can get rid of these now */
  for (f = 0; f < sizeof holdfd / sizeof *holdfd; f++)
    close(holdfd[f]);

  log_Printf(LogPHASE, "PPP Started (%s mode).\n", mode2Nam(sw.mode));
  DoLoop(bundle);
  AbortProgram(EX_NORMAL);

  return EX_NORMAL;
}
Exemplo n.º 2
0
int main (int argc, char** argv)
{
	int			divertIn;
	int			divertOut;
	int			divertInOut;
	int			routeSock;
	struct sockaddr_in	addr;
	fd_set			readMask;
	fd_set			writeMask;
	int			fdMax;
/* 
 * Initialize packet aliasing software.
 * Done already here to be able to alter option bits
 * during command line and configuration file processing.
 */
	PacketAliasInit ();
/*
 * Parse options.
 */
	inPort			= 0;
	outPort			= 0;
	verbose 		= 0;
	inOutPort		= 0;
	ifName			= NULL;
	ifMTU			= -1;
	background		= 0;
	running			= 1;
	assignAliasAddr		= 0;
	aliasAddr.s_addr	= INADDR_NONE;
	aliasOverhead		= 12;
	dynamicMode		= 0;
 	logDropped		= 0;
 	logFacility		= LOG_DAEMON;
/*
 * Mark packet buffer empty.
 */
	packetSock		= -1;
	packetDirection		= DONT_KNOW;

	ParseArgs (argc, argv);
/*
 * Open syslog channel.
 */
	openlog ("natd", LOG_CONS | LOG_PID | (verbose ? LOG_PERROR : 0),
		 logFacility);
/*
 * Check that valid aliasing address has been given.
 */
	if (aliasAddr.s_addr == INADDR_NONE && ifName == NULL)
		errx (1, "aliasing address not given");

	if (aliasAddr.s_addr != INADDR_NONE && ifName != NULL)
		errx (1, "both alias address and interface "
			 "name are not allowed");
/*
 * Check that valid port number is known.
 */
	if (inPort != 0 || outPort != 0)
		if (inPort == 0 || outPort == 0)
			errx (1, "both input and output ports are required");

	if (inPort == 0 && outPort == 0 && inOutPort == 0)
		ParseOption ("port", DEFAULT_SERVICE);

/*
 * Check if ignored packets should be dropped.
 */
	dropIgnoredIncoming = PacketAliasSetMode (0, 0);
	dropIgnoredIncoming &= PKT_ALIAS_DENY_INCOMING;
/*
 * Create divert sockets. Use only one socket if -p was specified
 * on command line. Otherwise, create separate sockets for
 * outgoing and incoming connnections.
 */
	if (inOutPort) {

		divertInOut = socket (PF_INET, SOCK_RAW, IPPROTO_DIVERT);
		if (divertInOut == -1)
			Quit ("Unable to create divert socket.");

		divertIn  = -1;
		divertOut = -1;
/*
 * Bind socket.
 */

		addr.sin_family		= AF_INET;
		addr.sin_addr.s_addr	= INADDR_ANY;
		addr.sin_port		= inOutPort;

		if (bind (divertInOut,
			  (struct sockaddr*) &addr,
			  sizeof addr) == -1)
			Quit ("Unable to bind divert socket.");
	}
	else {

		divertIn = socket (PF_INET, SOCK_RAW, IPPROTO_DIVERT);
		if (divertIn == -1)
			Quit ("Unable to create incoming divert socket.");

		divertOut = socket (PF_INET, SOCK_RAW, IPPROTO_DIVERT);
		if (divertOut == -1)
			Quit ("Unable to create outgoing divert socket.");

		divertInOut = -1;

/*
 * Bind divert sockets.
 */

		addr.sin_family		= AF_INET;
		addr.sin_addr.s_addr	= INADDR_ANY;
		addr.sin_port		= inPort;

		if (bind (divertIn,
			  (struct sockaddr*) &addr,
			  sizeof addr) == -1)
			Quit ("Unable to bind incoming divert socket.");

		addr.sin_family		= AF_INET;
		addr.sin_addr.s_addr	= INADDR_ANY;
		addr.sin_port		= outPort;

		if (bind (divertOut,
			  (struct sockaddr*) &addr,
			  sizeof addr) == -1)
			Quit ("Unable to bind outgoing divert socket.");
	}
/*
 * Create routing socket if interface name specified and in dynamic mode.
 */
	routeSock = -1;
	if (ifName) {
		if (dynamicMode) {

			routeSock = socket (PF_ROUTE, SOCK_RAW, 0);
			if (routeSock == -1)
				Quit ("Unable to create routing info socket.");

			assignAliasAddr = 1;
		}
		else
			SetAliasAddressFromIfName (ifName);
	}
/*
 * Create socket for sending ICMP messages.
 */
	icmpSock = socket (AF_INET, SOCK_RAW, IPPROTO_ICMP);
	if (icmpSock == -1)
		Quit ("Unable to create ICMP socket.");

/*
 * And disable reads for the socket, otherwise it slowly fills
 * up with received icmps which we do not use.
 */
	shutdown(icmpSock, SHUT_RD);

/*
 * Become a daemon unless verbose mode was requested.
 */
	if (!verbose)
		DaemonMode ();
/*
 * Catch signals to manage shutdown and
 * refresh of interface address.
 */
	siginterrupt(SIGTERM, 1);
	siginterrupt(SIGHUP, 1);
	signal (SIGTERM, InitiateShutdown);
	signal (SIGHUP, RefreshAddr);
/*
 * Set alias address if it has been given.
 */
	if (aliasAddr.s_addr != INADDR_NONE)
		PacketAliasSetAddress (aliasAddr);
/*
 * We need largest descriptor number for select.
 */

	fdMax = -1;

	if (divertIn > fdMax)
		fdMax = divertIn;

	if (divertOut > fdMax)
		fdMax = divertOut;

	if (divertInOut > fdMax)
		fdMax = divertInOut;

	if (routeSock > fdMax)
		fdMax = routeSock;

	while (running) {

		if (divertInOut != -1 && !ifName && packetSock == -1) {
/*
 * When using only one socket, just call 
 * DoAliasing repeatedly to process packets.
 */
			DoAliasing (divertInOut, DONT_KNOW);
			continue;
		}
/* 
 * Build read mask from socket descriptors to select.
 */
		FD_ZERO (&readMask);
		FD_ZERO (&writeMask);

/*
 * If there is unsent packet in buffer, use select
 * to check when socket comes writable again.
 */
		if (packetSock != -1) {

			FD_SET (packetSock, &writeMask);
		}
		else {
/*
 * No unsent packet exists - safe to check if
 * new ones are available.
 */
			if (divertIn != -1)
				FD_SET (divertIn, &readMask);

			if (divertOut != -1)
				FD_SET (divertOut, &readMask);

			if (divertInOut != -1)
				FD_SET (divertInOut, &readMask);
		}
/*
 * Routing info is processed always.
 */
		if (routeSock != -1)
			FD_SET (routeSock, &readMask);

		if (select (fdMax + 1,
			    &readMask,
			    &writeMask,
			    NULL,
			    NULL) == -1) {

			if (errno == EINTR)
				continue;

			Quit ("Select failed.");
		}

		if (packetSock != -1)
			if (FD_ISSET (packetSock, &writeMask))
				FlushPacketBuffer (packetSock);

		if (divertIn != -1)
			if (FD_ISSET (divertIn, &readMask))
				DoAliasing (divertIn, INPUT);

		if (divertOut != -1)
			if (FD_ISSET (divertOut, &readMask))
				DoAliasing (divertOut, OUTPUT);

		if (divertInOut != -1) 
			if (FD_ISSET (divertInOut, &readMask))
				DoAliasing (divertInOut, DONT_KNOW);

		if (routeSock != -1)
			if (FD_ISSET (routeSock, &readMask))
				HandleRoutingInfo (routeSock);
	}

	if (background)
		unlink (PIDFILE);

	return 0;
}