NeXT slirp router

I was also rather interested in using a 3.3 system as NAT box.  I would
have thought it would be possible to use something like `slirp' to do
this, which is a user-level thing, rather than a kernel thing.

I intend to try this out (slirp did seem to compile with a few trivial
hacks on 3.3), and will post results.  It looks like it should work,
provided the NeXT can *forward* packets.

Slirp may not give you everything that full NAT does, but it comes
pretty close.  Available at:

    <http://www.glue.umd.edu/~tygris/slirp/>


From the slirp documentation:


9. Connecting a LAN over Slirp
===============================================================================

From the very beginning, Slirp was designed to allow more than one host
access the 'Net at once.  And doing so is *very* easy.

First, you need to setup the LAN (Local Area Network) as if it was really
going to connect to the Internet.  That is, you must give them each a unique
IP (unique relative to each other, not globally unique. E.g., you could give
them all an IP address in the 10.0.2.xxx class of addresses).  You also must
tell each host on the LAN to route it's IP packets to the host that is
connected to the Internet via Slirp.

Here's a diagram:

                           [Ethernet]
        -------------------------------------------------
           |         |         |         |         |
        [Host A]  [Host B]  [Host C]  [Host D]  [Host E]
           |                                       |
           |                                       |
           | <- Slirp link                         | <- SLIP link
           |                                       |
           |                                       |
      [Remote Host]                           [Another LAN]
           |
          ... to the Internet


Now, in this diagram, Host A is the Slirp-connected host.  Host's B through
to E can also access the 'Net by simply using Host A as the gateway.  Host A
also must be told to "forward" IP packets (using Remote Host as the gateway)
so that it will send any IP packets not destined for itself to Slirp, and
vice versa (route all packets sent by Slirp, not destined for itself, back
to their respective host's IP).

In other words, the Slirp link is just like a real SLIP/PPP link, which is
what I've been telling you all this time! :)

Note that it is possible to hook up many LAN's to the 'Net by simply
following the normal Internet conventions, and route the packets properly.
In this case "Another LAN" would use Host E as a gateway to the 'Net, Host E,
provided it can forward IP packets, will send them to it's gateway, Host A,
which will send it over Slirp, etc.  In theory, you could connect another
whole Global Internet to the current Internet with no IP address clashes.
Not recommended though :)


----


I thought I'd followup to my own post to provide a progress report.  I
have managed to connect my PC to the net using the NeXT as a router
successfully via slirp.
It doesn't quite work the way I described it below.  You only need to
run a standard PPP daemon on the NeXT.  You then dialup and telnet (or
rlogin) into a UNIX system at the other end (this may preclude the use
of many ISPs who don't give you a shell), and type `slirp'.  The PPP
link comes up (slirp looks like another ppp daemon as far as the NeXT
is concerned).  You should have a working ppp link (it defaults to the
private address range of 10.0.2.x).

You should then be able to point the other systems on your LAN at the
NeXT (via a default route) and they should now also be able to access
the net.  The nice thing about this is that (like NAT/IP-MASQ), your
LAN is basically invisible to the rest of the world.

This arrangement may not suit some since it requires a shell account
via an 8-bit clean telnet/rlogin and does not support all protocols
(but does support many).  You also need to ensure ip-forwarding is
enabled in your NeXT kernel.  Thanks to Timm Wetzel
for pointing this out to me and finding a small bit of code (from
Deja) that does the job (below).

This would seem to be one way to use the NeXT as router reasonably
effectively.


/* For OS4.2, compile with: cc -o ipforwarding -O -bsd -fno-builtin -no-precomp ipforwarding.c  */

#include <stdio.h>
#include <strings.h>
#ifdef NX_COMPILER_RELEASE_3_0
#ifndef __STRICT_BSD__
#error Compile with  cc -o ipforwarding -s -object -O -bsd -fno-builtin -no-precomp ipforwarding.c
#endif
#include <mach-o/nlist.h>
#include <bsd/libc.h>
#include <bsd/sys/fcntl.h>
#else
#ifndef __STRICT_BSD__
#error Compile with  cc -o ipforwarding -s -object -O -bsd ipforwarding.c
#endif
#include <nlist.h>
#include <libc.h>
#include <sys/fcntl.h>
#endif

struct nlist nl[]={
    { { "_ipforwarding" } },
    { { (char *)NULL } }
};

int ipforwarding;

main(argc, argv)
     int argc;
     char *argv[];
{
    register int s;
    int k;
    char *KERNEL, *KMEM;

    switch (argc) {
      case 1:
        break;
      case 2:
        if (!strcmp(argv[1], "off")) break;
        if (!strcmp(argv[1], "on")) {
            ipforwarding=1;
            break;
        }
        if ((argv[1][0]>='0'&&argv[1][0]<='9')||argv[1][0]=='-') {
            ipforwarding=atoi(argv[1]);
            break;
        }
        /*FALL THROUGH*/
      default:
        (void)fprintf(stderr, "Usage: %s [on|off]\n", *argv);
        exit(1);
    }
    if (!(KERNEL=getenv("KERNEL")))
#ifdef i386
      KERNEL="/mach_kernel";
#else
    KERNEL="/mach";
#endif
    if (!(KMEM=getenv("KMEM"))) KMEM="/dev/kmem";
    s=nlist(KERNEL, nl);
    if (s<0) {
        perror(KERNEL);
        exit(1);
    }
    if (s!=0) {
        (void)fprintf(stderr, "%s: nlist failed\n", *argv);
        exit(1);
    }
    if ((k=open(KMEM, argc>1 ? O_RDWR : O_RDONLY))<0) {
        perror(KMEM);
        exit(1);
    }
    if (lseek(k, (long)nl[0].n_value, 0)<0L) {
        perror("lseek");
        exit(1);
    }
    if (argc<=1) {
        if (read(k, (char *)&ipforwarding, sizeof ipforwarding)!=
            sizeof ipforwarding) {
            perror("read");
            exit(1);
        }
        (void)fputs("ipforwarding is ", stdout);
        switch (ipforwarding) {
          case 0:
            (void)fputs("off\n", stdout);
            break;
          case 1:
            (void)fputs("on\n", stdout);
            break;
          default:
            (void)printf("%d\n", ipforwarding);
            break;
        }
    }
    else if (write(k, (char *)&ipforwarding, sizeof ipforwarding)!=
             sizeof ipforwarding) {
        perror("write");
        exit(1);
    }
    (void)close(k);
    exit(0);
}