Subversion Repositories planix.SVN

Rev

Rev 2 | Blame | Compare with Previous | Last modification | View Log | RSS feed

#include <u.h>
#include <libc.h>
#include <bio.h>
#include <ip.h>
#include <ndb.h>
#include "arp.h"

typedef struct Rarp     Rarp;

struct Rarp
{
        uchar   edst[6];
        uchar   esrc[6];
        uchar   type[2];
        uchar   hrd[2];
        uchar   pro[2];
        uchar   hln;
        uchar   pln;
        uchar   op[2];
        uchar   sha[6];
        uchar   spa[4];
        uchar   tha[6];
        uchar   tpa[4];
};

uchar   myip[IPaddrlen];
uchar   myether[6];
char    rlog[] = "ipboot";
char    *device = "ether0";
int     debug;
Ndb     *db;

char*   lookup(char*, char*, char*, char*, int);

void
error(char *s)
{
        syslog(1, rlog, "error %s: %r", s);
        exits(s);
}

char net[32];

void
usage(void)
{
        fprint(2, "usage: %s [-e device] [-x netmtpt] [-f ndb-file] [-d]\n", argv0);
        exits("usage");
}

void
main(int argc, char *argv[])
{
        int edata, ectl;
        uchar buf[2048];
        long n;
        Rarp *rp;
        char ebuf[16];
        char ipbuf[64];
        char file[128];
        int arp;
        char *p, *ndbfile;

        ndbfile = nil;
        setnetmtpt(net, sizeof(net), nil);
        ARGBEGIN{
        case 'e':
                p = ARGF();
                if(p == nil)
                        usage();
                device = p;
                break;
        case 'd':
                debug = 1;
                break;
        case 'f':
                p = ARGF();
                if(p == nil)
                        usage();
                ndbfile = p;
                break;
        case 'x':
                p = ARGF();
                if(p == nil)
                        usage();
                setnetmtpt(net, sizeof(net), p);
                break;
        }ARGEND
        USED(argc, argv);

        fmtinstall('E', eipfmt);
        fmtinstall('I', eipfmt);
        fmtinstall('V', eipfmt);

        db = ndbopen(ndbfile);
        if(db == 0)
                error("can't open the database");

        edata = dial(netmkaddr("0x8035", device, 0), 0, 0, &ectl);
        if(edata < 0)
                error("can't open ethernet");

        if(myipaddr(myip, net) < 0)
                error("can't get my ip address");
        sprint(ebuf, "%s/%s", net, device);
        if(myetheraddr(myether, ebuf) < 0)
                error("can't get my ether address");

        snprint(file, sizeof(file), "%s/arp", net);
        if((arp = open(file, ORDWR)) < 0)
                fprint(2, "rarpd: can't open %s\n", file);

        switch(rfork(RFNOTEG|RFPROC|RFFDG)) {
        case -1:
                error("fork");
        case 0:
                break;
        default:
                exits(0);
        }

        for(;;){
                n = read(edata, buf, sizeof(buf));
                if(n <= 0)
                        error("reading");
                if(n < sizeof(Rarp)){
                        syslog(debug, rlog, "bad packet size %ld", n);
                        continue;
                }
                rp = (Rarp*)buf;
                if(rp->op[0]!=0 && rp->op[1]!=3){
                        syslog(debug, rlog, "bad op %d %d %E",
                                rp->op[1], rp->op[0], rp->esrc);
                        continue;
                }

                if(debug)
                        syslog(debug, rlog, "rcv se %E si %V te %E ti %V",
                                 rp->sha, rp->spa, rp->tha, rp->tpa);

                sprint(ebuf, "%E", rp->tha);
                if(lookup("ether", ebuf, "ip", ipbuf, sizeof ipbuf) == nil){
                        syslog(debug, rlog, "client lookup failed: %s", ebuf);
                        continue;
                }
                v4parseip(rp->tpa, ipbuf);

                memmove(rp->sha, myether, sizeof(rp->sha));
                v6tov4(rp->spa, myip);

                rp->op[0] = 0;
                rp->op[1] = 4;
                memmove(rp->edst, rp->esrc, sizeof(rp->edst));

                if(debug)
                        syslog(debug, rlog, "send se %E si %V te %E ti %V",
                                 rp->sha, rp->spa, rp->tha, rp->tpa);

                if(write(edata, buf, 60) != 60)
                        error("write failed");

                if(arp < 0)
                        continue;
                if(fprint(arp, "add %E %V", rp->esrc, rp->tpa) < 0)
                        fprint(2, "can't write arp entry\n");
        }
}

char*
lookup(char *sattr, char *sval, char *tattr, char *tval, int len)
{
        static Ndb *db;
        char *attrs[1];
        Ndbtuple *t;

        if(db == nil)
                db = ndbopen(0);
        if(db == nil)
                return nil;

        if(sattr == nil)
                sattr = ipattr(sval);

        attrs[0] = tattr;
        t = ndbipinfo(db, sattr, sval, attrs, 1);
        if(t == nil)
                return nil;
        strncpy(tval, t->val, len);
        tval[len-1] = 0;
        ndbfree(t);
        return tval;
}