Subject: Re: PPP over telnet?
To: Anders Eriksson <aer@cdt.luth.se>
From: Michael Eriksson <Michael.Eriksson@era-t.ericsson.se>
List: netbsd-help
Date: 12/09/1997 20:03:17
First, you should tell whatever program you're using to create and
send your mails not to use lines longer than ~70 characters. Overlong
lines look just awful.

> I'd like to configure a ppp session over a telnet session between
> two NetBSD/i386 boxes. How di I do that? Somehow I have to convice
> pppd to use the pty (or whatever) which telenet creates to run the
> stuff over. So far my experiments haven't given anything in return.

You're lucky today! I just happened to be hacking on such a program
the other day. I've appended it at the end of this mail. It's a little
rough, but it should work. Compile with "cc foo.c -o foo -lutil". The
program opens two ptys; it runs a program of your choice on one of
them, and waits for you (i.e., pppd, kermit, ...) to connect to the
other. It then shuffles data between the two ptys. The program exits
when the program it started on the pty exits.

Start the program with

prompt> ./foo telnet host

to get a pty that's connected to `host' (you can changed "telnet host"
to whatever you like). The program will print out which pty it has
allocated. Use that as the tty device with pppd. Example:

prompt> ./foo telnet host
/dev/ttyp3
prompt> pppd ttyp3 connect connect-script ...

Please send further questions (or bugfixes :-)) to me.

Best regards,
Michael

--8<----------------------------------------------------------------

#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/uio.h>
#include <sys/wait.h>
#include <err.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <termios.h>
#include <unistd.h>
#include <util.h>


void reaper()
{
  int pid;
  union wait status;

  if ((pid = wait3((int *) &status, WNOHANG, 0)) > 0)
    exit(0);
}


void shuffle(int from, int to, char *name)
{
  int n, n2;
  char buf[BUFSIZ];

  while ((n = read(from, buf, sizeof buf)) > 0) {
#if 0
    printf("[%s: ", name);
    fwrite(buf, n, 1, stdout);
    printf("]\n");
    fflush(stdout);
#endif
    if ((n2 = write(to, buf, n)) != n)
      if (n2 < 0)
	err(1, "%s write", name);
      else
	err(1, "%s short write (%d < %d)", name, n2, n);
  }
  if (n < 0)
    err(1, "%s read", name);
}


int main(int argc, char **argv)
{
  int master1, slave1, master2, slave2;
  struct termios tt;
  struct winsize ws;
  char ptyname[1024];		/* XXX ? */

  if (argc < 2) {
    fprintf(stderr, "Usage: pty command [ param ... ]\n");
    exit(1);
  }

  /* open and set up ptys */
  if (tcgetattr(0, &tt) < 0)
    err(1, "tcgetattr");
  if (ioctl(0, TIOCGWINSZ, &ws) < 0)
    err(1, "ioctl(TIOCGWINSZ)");
  if (openpty(&master1, &slave1, ptyname, &tt, &ws) < 0 ||
      openpty(&master2, &slave2, 0, &tt, &ws) < 0)
    err(1, "openpty");
  if (tcsetattr(slave2, TCSAFLUSH, &tt) < 0)
    err(1, "tcsetattr");
  cfmakeraw(&tt);
  tt.c_lflag &= ~ECHO;
  if (tcsetattr(slave1, TCSAFLUSH, &tt) < 0)
    err(1, "tcsetattr");

  /* fork off... */
  signal(SIGCHLD, reaper);
  switch (fork()) {
  case -1:
    err(1, "fork");
  case 0:
    daemon(0, 0);
    switch (fork()) {
    case -1:
      err(1, "fork");
    case 0:
      switch (fork()) {
      case -1:
	err(1, "fork");
      case 0:
	/*
	 * Run program. This is "childmost", so the other processes can
	 * catch SIGCHLD.
	 */
	close(master1);
	close(slave1);
	close(master2);
	login_tty(slave2);
	execvp(argv[1], &argv[1]);
	err(1, "execvp %s", argv[1]);
      }
      /* shuffle data program -> pty */
      close(slave1);
      close(slave2);
      shuffle(master2, master1, "copyin");
      exit(0);
    }
    /* shuffle data pty -> program */
    close(slave2);
    shuffle(master1, master2, "copyout");
    exit(0);
  }
  puts(ptyname);
  return 0;
}