new goodies

This commit is contained in:
rsc 2005-12-26 04:48:52 +00:00
parent 35d26aa321
commit 87a52e0485
44 changed files with 8723 additions and 0 deletions

151
src/cmd/ip/dhcp.h Executable file
View file

@ -0,0 +1,151 @@
enum
{
OfferTimeout= 60, /* when an offer times out */
MaxLease= 60*60, /* longest lease for dynamic binding */
MinLease= 15*60, /* shortest lease for dynamic binding */
StaticLease= 30*60, /* lease for static binding */
IPUDPHDRSIZE= 28, /* size of an IP plus UDP header */
MINSUPPORTED= 576, /* biggest IP message the client must support */
/* lengths of some bootp fields */
Maxhwlen= 16,
Maxfilelen= 128,
Maxoptlen= 312-4,
/* bootp types */
Bootrequest= 1,
Bootreply= 2,
/* bootp flags */
Fbroadcast= 1<<15,
/* dhcp types */
Discover= 1,
Offer= 2,
Request= 3,
Decline= 4,
Ack= 5,
Nak= 6,
Release= 7,
Inform= 8,
/* bootp option types */
OBend= 255,
OBpad= 0,
OBmask= 1,
OBtimeoff= 2,
OBrouter= 3,
OBtimeserver= 4,
OBnameserver= 5,
OBdnserver= 6,
OBlogserver= 7,
OBcookieserver= 8,
OBlprserver= 9,
OBimpressserver= 10,
OBrlserver= 11,
OBhostname= 12, /* 0xc0 */
OBbflen= 13,
OBdumpfile= 14,
OBdomainname= 15,
OBswapserver= 16, /* 0x10 */
OBrootpath= 17,
OBextpath= 18,
OBipforward= 19,
OBnonlocal= 20,
OBpolicyfilter= 21,
OBmaxdatagram= 22,
OBttl= 23,
OBpathtimeout= 24,
OBpathplateau= 25,
OBmtu= 26,
OBsubnetslocal= 27,
OBbaddr= 28,
OBdiscovermask= 29,
OBsupplymask= 30,
OBdiscoverrouter= 31,
OBrsserver= 32, /* 0x20 */
OBstaticroutes= 33,
OBtrailerencap= 34,
OBarptimeout= 35,
OBetherencap= 36,
OBtcpttl= 37,
OBtcpka= 38,
OBtcpkag= 39,
OBnisdomain= 40,
OBniserver= 41,
OBntpserver= 42,
OBvendorinfo= 43, /* 0x2b */
OBnetbiosns= 44,
OBnetbiosdds= 45,
OBnetbiostype= 46,
OBnetbiosscope= 47,
OBxfontserver= 48, /* 0x30 */
OBxdispmanager= 49,
OBnisplusdomain= 64, /* 0x40 */
OBnisplusserver= 65,
OBhomeagent= 68,
OBsmtpserver= 69,
OBpop3server= 70,
OBnntpserver= 71,
OBwwwserver= 72,
OBfingerserver= 73,
OBircserver= 74,
OBstserver= 75,
OBstdaserver= 76,
/* dhcp options */
ODipaddr= 50, /* 0x32 */
ODlease= 51,
ODoverload= 52,
ODtype= 53, /* 0x35 */
ODserverid= 54, /* 0x36 */
ODparams= 55, /* 0x37 */
ODmessage= 56,
ODmaxmsg= 57,
ODrenewaltime= 58,
ODrebindingtime= 59,
ODvendorclass= 60,
ODclientid= 61, /* 0x3d */
ODtftpserver= 66,
ODbootfile= 67,
/* plan9 vendor info options */
OP9fs= 128, // plan9 file servers
OP9auth= 129, // plan9 auth servers
};
/* a lease that never expires */
#define Lforever 0xffffffffU
/* dhcp states */
enum {
Sinit,
Sselecting,
Srequesting,
Sbound,
Srenewing,
Srebinding,
};
typedef struct Bootp Bootp;
struct Bootp
{
uchar op; /* opcode */
uchar htype; /* hardware type */
uchar hlen; /* hardware address len */
uchar hops; /* hops */
uchar xid[4]; /* a random number */
uchar secs[2]; /* elapsed since client started booting */
uchar flags[2];
uchar ciaddr[IPv4addrlen]; /* client IP address (client tells server) */
uchar yiaddr[IPv4addrlen]; /* client IP address (server tells client) */
uchar siaddr[IPv4addrlen]; /* server IP address */
uchar giaddr[IPv4addrlen]; /* gateway IP address */
uchar chaddr[Maxhwlen]; /* client hardware address */
char sname[64]; /* server host name (optional) */
char file[Maxfilelen]; /* boot file name */
uchar optmagic[4];
uchar optdata[Maxoptlen];
};

85
src/cmd/ip/dhcpd/dat.h Executable file
View file

@ -0,0 +1,85 @@
#include "../dhcp.h"
enum
{
Maxstr= 256,
};
typedef struct Binding Binding;
struct Binding
{
Binding *next;
uchar ip[IPaddrlen];
char *boundto; /* id last bound to */
char *offeredto; /* id we've offered this to */
long lease; /* absolute time at which binding expires */
long expoffer; /* absolute time at which offer times out */
long offer; /* lease offered */
long lasttouched; /* time this entry last assigned/unassigned */
long lastcomplained; /* last time we complained about a used but not leased */
long tried; /* last time we tried this entry */
Qid q; /* qid at the last syncbinding */
};
typedef struct Info Info;
struct Info
{
int indb; /* true if found in database */
char domain[Maxstr]; /* system domain name */
char bootf[Maxstr]; /* boot file */
char bootf2[Maxstr]; /* alternative boot file */
uchar tftp[NDB_IPlen]; /* ip addr of tftp server */
uchar tftp2[NDB_IPlen]; /* ip addr of alternate server */
uchar ipaddr[NDB_IPlen]; /* ip address of system */
uchar ipmask[NDB_IPlen]; /* ip network mask */
uchar ipnet[NDB_IPlen]; /* ip network address (ipaddr & ipmask) */
uchar etheraddr[6]; /* ethernet address */
uchar gwip[NDB_IPlen]; /* gateway ip address */
uchar fsip[NDB_IPlen]; /* file system ip address */
uchar auip[NDB_IPlen]; /* authentication server ip address */
char rootpath[Maxstr]; /* rootfs for diskless nfs clients */
char dhcpgroup[Maxstr];
char vendor[Maxstr]; /* vendor info */
};
/* from dhcp.c */
extern int validip(uchar*);
extern void warning(int, char*, ...);
extern int minlease;
/* from db.c */
extern char* tohex(char*, uchar*, int);
extern char* toid(uchar*, int);
extern void initbinding(uchar*, int);
extern Binding* iptobinding(uchar*, int);
extern Binding* idtobinding(char*, Info*, int);
extern Binding* idtooffer(char*, Info*);
extern int commitbinding(Binding*);
extern int releasebinding(Binding*, char*);
extern int samenet(uchar *ip, Info *iip);
extern void mkoffer(Binding*, char*, long);
extern int syncbinding(Binding*, int);
/* from ndb.c */
extern int lookup(Bootp*, Info*, Info*);
extern int lookupip(uchar*, Info*, int);
extern void lookupname(char*, Ndbtuple*);
extern Iplifc* findlifc(uchar*);
extern int forme(uchar*);
extern int lookupserver(char*, uchar**, Ndbtuple *t);
extern Ndbtuple* lookupinfo(uchar *ipaddr, char **attr, int n);
/* from icmp.c */
extern int icmpecho(uchar*);
extern char *binddir;
extern int debug;
extern char *blog;
extern Ipifc *ipifcs;
extern long now;
extern char *ndbfile;

452
src/cmd/ip/dhcpd/db.c Executable file
View file

@ -0,0 +1,452 @@
#include <u.h>
#include <libc.h>
#include <ip.h>
#include <bio.h>
#include <ndb.h>
#include <ctype.h>
#include "dat.h"
/*
* format of a binding entry:
* char ipaddr[32];
* char id[32];
* char hwa[32];
* char otime[10];
*/
Binding *bcache;
uchar bfirst[IPaddrlen];
char *binddir = nil;
char *xbinddir = "#9/ndb/dhcp";
/*
* convert a byte array to hex
*/
static char
hex(int x)
{
if(x < 10)
return x + '0';
return x - 10 + 'a';
}
extern char*
tohex(char *hdr, uchar *p, int len)
{
char *s, *sp;
int hlen;
hlen = strlen(hdr);
s = malloc(hlen + 2*len + 1);
sp = s;
strcpy(sp, hdr);
sp += hlen;
for(; len > 0; len--){
*sp++ = hex(*p>>4);
*sp++ = hex(*p & 0xf);
p++;
}
*sp = 0;
return s;
}
/*
* convert a client id to a string. If it's already
* ascii, leave it be. Otherwise, convert it to hex.
*/
extern char*
toid(uchar *p, int n)
{
int i;
char *s;
for(i = 0; i < n; i++)
if(!isprint(p[i]))
return tohex("id", p, n);
s = malloc(n + 1);
memmove(s, p, n);
s[n] = 0;
return s;
}
/*
* increment an ip address
*/
static void
incip(uchar *ip)
{
int i, x;
for(i = IPaddrlen-1; i >= 0; i--){
x = ip[i];
x++;
ip[i] = x;
if((x & 0x100) == 0)
break;
}
}
/*
* find a binding for an id or hardware address
*/
static int
lockopen(char *file)
{
char err[ERRMAX];
int fd, tries;
for(tries = 0; tries < 5; tries++){
fd = open(file, OLOCK|ORDWR);
if(fd >= 0)
return fd;
print("open %s: %r\n", file);
errstr(err, sizeof err);
if(strstr(err, "lock")){
/* wait for other process to let go of lock */
sleep(250);
/* try again */
continue;
}
if(strstr(err, "exist") || strstr(err, "No such")){
/* no file, create an exclusive access file */
fd = create(file, ORDWR, DMEXCL|0666);
chmod(file, 0666);
if(fd >= 0)
return fd;
}
}
return -1;
}
void
setbinding(Binding *b, char *id, long t)
{
if(b->boundto)
free(b->boundto);
b->boundto = strdup(id);
b->lease = t;
}
static void
parsebinding(Binding *b, char *buf)
{
long t;
char *id, *p;
/* parse */
t = atoi(buf);
id = strchr(buf, '\n');
if(id){
*id++ = 0;
p = strchr(id, '\n');
if(p)
*p = 0;
} else
id = "";
/* replace any past info */
setbinding(b, id, t);
}
static int
writebinding(int fd, Binding *b)
{
Dir *d;
seek(fd, 0, 0);
if(fprint(fd, "%ld\n%s\n", b->lease, b->boundto) < 0)
return -1;
d = dirfstat(fd);
if(d == nil)
return -1;
b->q.type = d->qid.type;
b->q.path = d->qid.path;
b->q.vers = d->qid.vers;
free(d);
return 0;
}
/*
* synchronize cached binding with file. the file always wins.
*/
int
syncbinding(Binding *b, int returnfd)
{
char buf[512];
int i, fd;
Dir *d;
if(binddir == nil)
binddir = unsharp(xbinddir);
snprint(buf, sizeof(buf), "%s/%I", binddir, b->ip);
fd = lockopen(buf);
if(fd < 0){
/* assume someone else is using it */
b->lease = time(0) + OfferTimeout;
return -1;
}
/* reread if changed */
d = dirfstat(fd);
if(d != nil) /* BUG? */
if(d->qid.type != b->q.type || d->qid.path != b->q.path || d->qid.vers != b->q.vers){
i = read(fd, buf, sizeof(buf)-1);
if(i < 0)
i = 0;
buf[i] = 0;
parsebinding(b, buf);
b->lasttouched = d->mtime;
b->q.path = d->qid.path;
b->q.vers = d->qid.vers;
}
free(d);
if(returnfd)
return fd;
close(fd);
return 0;
}
extern int
samenet(uchar *ip, Info *iip)
{
uchar x[IPaddrlen];
maskip(iip->ipmask, ip, x);
return ipcmp(x, iip->ipnet) == 0;
}
/*
* create a record for each binding
*/
extern void
initbinding(uchar *first, int n)
{
while(n-- > 0){
iptobinding(first, 1);
incip(first);
}
}
/*
* find a binding for a specific ip address
*/
extern Binding*
iptobinding(uchar *ip, int mk)
{
Binding *b;
for(b = bcache; b; b = b->next){
if(ipcmp(b->ip, ip) == 0){
syncbinding(b, 0);
return b;
}
}
if(mk == 0)
return 0;
b = malloc(sizeof(*b));
memset(b, 0, sizeof(*b));
ipmove(b->ip, ip);
b->next = bcache;
bcache = b;
syncbinding(b, 0);
return b;
}
static void
lognolease(Binding *b)
{
/* renew the old binding, and hope it eventually goes away */
b->offer = 5*60;
commitbinding(b);
/* complain if we haven't in the last 5 minutes */
if(now - b->lastcomplained < 5*60)
return;
syslog(0, blog, "dhcp: lease for %I to %s ended at %ld but still in use\n",
b->ip, b->boundto != nil ? b->boundto : "?", b->lease);
b->lastcomplained = now;
}
/*
* find a free binding for a hw addr or id on the same network as iip
*/
extern Binding*
idtobinding(char *id, Info *iip, int ping)
{
Binding *b, *oldest;
int oldesttime;
/*
* first look for an old binding that matches. that way
* clients will tend to keep the same ip addresses.
*/
for(b = bcache; b; b = b->next){
if(b->boundto && strcmp(b->boundto, id) == 0){
if(!samenet(b->ip, iip))
continue;
/* check with the other servers */
syncbinding(b, 0);
if(strcmp(b->boundto, id) == 0)
return b;
}
}
print("looking for old for %I\n", iip->ipnet);
/*
* look for oldest binding that we think is unused
*/
for(;;){
oldest = nil;
oldesttime = 0;
for(b = bcache; b; b = b->next){
print("tried %d now %d lease %d exp %d %I\n", b->tried, now, b->lease, b->expoffer, b->ip);
if(b->tried != now)
if(b->lease < now && b->expoffer < now && samenet(b->ip, iip))
if(oldest == nil || b->lasttouched < oldesttime){
/* sync and check again */
syncbinding(b, 0);
if(b->lease < now && b->expoffer < now && samenet(b->ip, iip))
if(oldest == nil || b->lasttouched < oldesttime){
oldest = b;
print("have oldest\n");
oldesttime = b->lasttouched;
}
}
}
if(oldest == nil)
break;
/* make sure noone is still using it */
oldest->tried = now;
print("return oldest\n");
if(ping == 0 || icmpecho(oldest->ip) == 0)
return oldest;
lognolease(oldest); /* sets lastcomplained */
}
/* try all bindings */
for(b = bcache; b; b = b->next){
syncbinding(b, 0);
if(b->tried != now)
if(b->lease < now && b->expoffer < now && samenet(b->ip, iip)){
b->tried = now;
if(ping == 0 || icmpecho(b->ip) == 0)
return b;
lognolease(b);
}
}
/* nothing worked, give up */
return 0;
}
/*
* create an offer
*/
extern void
mkoffer(Binding *b, char *id, long leasetime)
{
if(leasetime <= 0){
if(b->lease > now + minlease)
leasetime = b->lease - now;
else
leasetime = minlease;
}
if(b->offeredto)
free(b->offeredto);
b->offeredto = strdup(id);
b->offer = leasetime;
b->expoffer = now + OfferTimeout;
}
/*
* find an offer for this id
*/
extern Binding*
idtooffer(char *id, Info *iip)
{
Binding *b;
/* look for an offer to this id */
for(b = bcache; b; b = b->next){
print("%I %I ? offeredto %s id %s\n", b->ip, iip->ipnet, b->offeredto, id);
if(b->offeredto && strcmp(b->offeredto, id) == 0 && samenet(b->ip, iip)){
/* make sure some other system hasn't stolen it */
syncbinding(b, 0);
print("b->lease %d now %d boundto %s offered %s\n", b->lease, now, b->boundto, b->offeredto);
if(b->lease < now
|| (b->boundto && strcmp(b->boundto, b->offeredto) == 0))
return b;
}
}
return 0;
}
/*
* commit a lease, this could fail
*/
extern int
commitbinding(Binding *b)
{
int fd;
long now;
now = time(0);
if(b->offeredto == 0)
return -1;
fd = syncbinding(b, 1);
if(fd < 0)
return -1;
if(b->lease > now && b->boundto && strcmp(b->boundto, b->offeredto) != 0){
close(fd);
return -1;
}
setbinding(b, b->offeredto, now + b->offer);
b->lasttouched = now;
if(writebinding(fd, b) < 0){
close(fd);
return -1;
}
close(fd);
return 0;
}
/*
* commit a lease, this could fail
*/
extern int
releasebinding(Binding *b, char *id)
{
int fd;
long now;
now = time(0);
fd = syncbinding(b, 1);
if(fd < 0)
return -1;
if(b->lease > now && b->boundto && strcmp(b->boundto, id) != 0){
close(fd);
return -1;
}
b->lease = 0;
b->expoffer = 0;
if(writebinding(fd, b) < 0){
close(fd);
return -1;
}
close(fd);
return 0;
}

1632
src/cmd/ip/dhcpd/dhcpd.c Executable file

File diff suppressed because it is too large Load diff

43
src/cmd/ip/dhcpd/dhcpleases.c Executable file
View file

@ -0,0 +1,43 @@
#include <u.h>
#include <libc.h>
#include <bio.h>
#include <ndb.h>
#include <ip.h>
#include "dat.h"
extern char *binddir;
long now;
char *blog = "ipboot";
int minlease = MinLease;
void
main(void)
{
Dir *all;
int i, nall, fd;
Binding b;
fmtinstall('E', eipfmt);
fmtinstall('I', eipfmt);
fmtinstall('V', eipfmt);
fmtinstall('M', eipfmt);
fd = open(binddir, OREAD);
if(fd < 0)
sysfatal("opening %s: %r", binddir);
nall = dirreadall(fd, &all);
if(nall < 0)
sysfatal("reading %s: %r", binddir);
close(fd);
b.boundto = 0;
b.lease = b.offer = 0;
now = time(0);
for(i = 0; i < nall; i++){
parseip(b.ip, all[i].name);
if(syncbinding(&b, 0) < 0)
continue;
if(b.lease > now)
print("%I leased by %s until %s", b.ip, b.boundto, ctime(b.lease));
}
}

22
src/cmd/ip/dhcpd/mkfile Executable file
View file

@ -0,0 +1,22 @@
<$PLAN9/src/mkhdr
TARG=dhcpd\
dhcpleases\
DOFILES=\
db.$O\
ndb.$O\
ping.$O\
IOFILES=\
db.$O\
ping.$O\
HFILES=dat.h ../dhcp.h
<$PLAN9/src/mkmany
$O.dhcpd: $DOFILES
$O.dhcpleases: $IOFILES
$O.testping: ping.$O

318
src/cmd/ip/dhcpd/ndb.c Executable file
View file

@ -0,0 +1,318 @@
/*
* this currently only works for ethernet bootp's -- presotto
*/
#include <u.h>
#include <libc.h>
#include <ip.h>
#include <bio.h>
#include <ndb.h>
#include "dat.h"
static void check72(Info *iip);
Ndb *db;
char *ndbfile;
Iplifc*
findlifc(uchar *ip)
{
uchar x[IPaddrlen];
Ipifc *ifc;
Iplifc *lifc;
for(ifc = ipifcs; ifc; ifc = ifc->next){
for(lifc = ifc->lifc; lifc != nil; lifc = lifc->next){
if(lifc->net[0] == 0)
continue;
maskip(ip, lifc->mask, x);
if(memcmp(x, lifc->net, IPaddrlen) == 0)
return lifc;
}
}
return nil;
}
int
forme(uchar *ip)
{
Ipifc *ifc;
Iplifc *lifc;
extern uchar xmyipaddr[IPaddrlen];
if(memcmp(ip, xmyipaddr, IPaddrlen) == 0)
return 1;
for(ifc = ipifcs; ifc; ifc = ifc->next){
for(lifc = ifc->lifc; lifc != nil; lifc = lifc->next)
if(memcmp(ip, lifc->ip, IPaddrlen) == 0)
return 1;
}
return 0;
}
uchar noetheraddr[6];
static void
setipaddr(uchar *addr, char *ip)
{
if(ipcmp(addr, IPnoaddr) == 0)
parseip(addr, ip);
}
static void
setipmask(uchar *mask, char *ip)
{
if(ipcmp(mask, IPnoaddr) == 0)
parseipmask(mask, ip);
}
/*
* do an ipinfo with defaults
*/
int
lookupip(uchar *ipaddr, Info *iip, int gate)
{
char ip[32];
Ndbtuple *t, *nt;
char *attrs[32], **p;
if(db == 0)
db = ndbopen(ndbfile);
if(db == 0){
fprint(2, "can't open db\n");
return -1;
}
p = attrs;
*p++ = "ip";
*p++ = "ipmask";
*p++ = "@ipgw";
if(!gate){
*p++ = "bootf";
*p++ = "bootf2";
*p++ = "@tftp";
*p++ = "@tftp2";
*p++ = "rootpath";
*p++ = "dhcp";
*p++ = "vendorclass";
*p++ = "ether";
*p++ = "dom";
*p++ = "@fs";
*p++ = "@auth";
}
*p = 0;
memset(iip, 0, sizeof(*iip));
snprint(ip, sizeof(ip), "%I", ipaddr);
t = ndbipinfo(db, "ip", ip, attrs, p - attrs);
if(t == nil)
return -1;
for(nt = t; nt != nil; nt = nt->entry){
if(strcmp(nt->attr, "ip") == 0)
setipaddr(iip->ipaddr, nt->val);
else
if(strcmp(nt->attr, "ipmask") == 0)
setipmask(iip->ipmask, nt->val);
else
if(strcmp(nt->attr, "fs") == 0)
setipaddr(iip->fsip, nt->val);
else
if(strcmp(nt->attr, "auth") == 0)
setipaddr(iip->auip, nt->val);
else
if(strcmp(nt->attr, "tftp") == 0)
setipaddr(iip->tftp, nt->val);
else
if(strcmp(nt->attr, "tftp2") == 0)
setipaddr(iip->tftp2, nt->val);
else
if(strcmp(nt->attr, "ipgw") == 0)
setipaddr(iip->gwip, nt->val);
else
if(strcmp(nt->attr, "ether") == 0){
if(memcmp(iip->etheraddr, noetheraddr, 6) == 0)
parseether(iip->etheraddr, nt->val);
iip->indb = 1;
}
else
if(strcmp(nt->attr, "dhcp") == 0){
if(iip->dhcpgroup[0] == 0)
strcpy(iip->dhcpgroup, nt->val);
}
else
if(strcmp(nt->attr, "bootf") == 0){
if(iip->bootf[0] == 0)
strcpy(iip->bootf, nt->val);
}
else
if(strcmp(nt->attr, "bootf2") == 0){
if(iip->bootf2[0] == 0)
strcpy(iip->bootf2, nt->val);
}
else
if(strcmp(nt->attr, "vendor") == 0){
if(iip->vendor[0] == 0)
strcpy(iip->vendor, nt->val);
}
else
if(strcmp(nt->attr, "dom") == 0){
if(iip->domain[0] == 0)
strcpy(iip->domain, nt->val);
}
else
if(strcmp(nt->attr, "rootpath") == 0){
if(iip->rootpath[0] == 0)
strcpy(iip->rootpath, nt->val);
}
}
ndbfree(t);
maskip(iip->ipaddr, iip->ipmask, iip->ipnet);
return 0;
}
static uchar zeroes[6];
/*
* lookup info about a client in the database. Find an address on the
* same net as riip.
*/
int
lookup(Bootp *bp, Info *iip, Info *riip)
{
Ndbtuple *t, *nt;
Ndbs s;
char *hwattr;
char *hwval, hwbuf[33];
uchar ciaddr[IPaddrlen];
if(db == 0)
db = ndbopen(ndbfile);
if(db == 0){
fprint(2, "can't open db\n");
return -1;
}
memset(iip, 0, sizeof(*iip));
/* client knows its address? */
v4tov6(ciaddr, bp->ciaddr);
if(validip(ciaddr)){
if(lookupip(ciaddr, iip, 0) < 0)
return -1; /* don't know anything about it */
check72(iip);
if(!samenet(riip->ipaddr, iip)){
warning(0, "%I not on %I", ciaddr, riip->ipnet);
return -1;
}
/*
* see if this is a masquerade, i.e., if the ether
* address doesn't match what we expected it to be.
*/
if(memcmp(iip->etheraddr, zeroes, 6) != 0)
if(memcmp(bp->chaddr, iip->etheraddr, 6) != 0)
warning(0, "ciaddr %I rcvd from %E instead of %E",
ciaddr, bp->chaddr, iip->etheraddr);
return 0;
}
if(bp->hlen > Maxhwlen)
return -1;
switch(bp->htype){
case 1:
hwattr = "ether";
hwval = hwbuf;
snprint(hwbuf, sizeof(hwbuf), "%E", bp->chaddr);
break;
default:
syslog(0, blog, "not ethernet %E, htype %d, hlen %d",
bp->chaddr, bp->htype, bp->hlen);
return -1;
}
/*
* use hardware address to find an ip address on
* same net as riip
*/
t = ndbsearch(db, &s, hwattr, hwval);
while(t){
for(nt = t; nt; nt = nt->entry){
if(strcmp(nt->attr, "ip") != 0)
continue;
parseip(ciaddr, nt->val);
if(lookupip(ciaddr, iip, 0) < 0)
continue;
if(samenet(riip->ipaddr, iip)){
ndbfree(t);
return 0;
}
}
ndbfree(t);
t = ndbsnext(&s, hwattr, hwval);
}
return -1;
}
/*
* interface to ndbipinfo
*/
Ndbtuple*
lookupinfo(uchar *ipaddr, char **attr, int n)
{
char ip[32];
sprint(ip, "%I", ipaddr);
return ndbipinfo(db, "ip", ip, attr, n);
}
/*
* return the ip addresses for a type of server for system ip
*/
int
lookupserver(char *attr, uchar **ipaddrs, Ndbtuple *t)
{
Ndbtuple *nt;
int rv = 0;
for(nt = t; rv < 2 && nt != nil; nt = nt->entry)
if(strcmp(nt->attr, attr) == 0){
parseip(ipaddrs[rv], nt->val);
rv++;
}
return rv;
}
/*
* just lookup the name
*/
void
lookupname(char *val, Ndbtuple *t)
{
Ndbtuple *nt;
for(nt = t; nt != nil; nt = nt->entry)
if(strcmp(nt->attr, "dom") == 0){
strcpy(val, nt->val);
break;
}
}
uchar slash120[IPaddrlen] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0 };
uchar net72[IPaddrlen] = { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0xff, 0xff, 135, 104, 72, 0 };
static void
check72(Info *iip)
{
uchar net[IPaddrlen];
maskip(iip->ipaddr, slash120, net);
if(ipcmp(net, net72) == 0)
syslog(0, blog, "check72 %I %M gw %I", iip->ipaddr, iip->ipmask, iip->gwip);
}

112
src/cmd/ip/dhcpd/ping.c Executable file
View file

@ -0,0 +1,112 @@
#include <u.h>
#include <libc.h>
#include <ip.h>
typedef struct Icmp Icmp;
struct Icmp
{
uchar vihl; /* Version and header length */
uchar tos; /* Type of service */
uchar length[2]; /* packet length */
uchar id[2]; /* Identification */
uchar frag[2]; /* Fragment information */
uchar ttl; /* Time to live */
uchar proto; /* Protocol */
uchar ipcksum[2]; /* Header checksum */
uchar src[4]; /* Ip source */
uchar dst[4]; /* Ip destination */
uchar type;
uchar code;
uchar cksum[2];
uchar icmpid[2];
uchar seq[2];
uchar data[1];
};
enum
{ /* Packet Types */
EchoReply = 0,
Unreachable = 3,
SrcQuench = 4,
EchoRequest = 8,
TimeExceed = 11,
Timestamp = 13,
TimestampReply = 14,
InfoRequest = 15,
InfoReply = 16,
ICMP_IPSIZE = 20,
ICMP_HDRSIZE = 8,
};
static void
catch(void *a, char *msg)
{
USED(a);
if(strstr(msg, "alarm"))
noted(NCONT);
else
noted(NDFLT);
}
#define MSG "dhcp probe"
/*
* make sure noone is using the address
*/
int
icmpecho(uchar *a)
{
int fd;
char buf[512];
Icmp *ip;
int i, n, len;
ushort sseq, x;
int rv;
return 0;
rv = 0;
sprint(buf, "%I", a);
fd = dial(netmkaddr(buf, "icmp", "1"), 0, 0, 0);
if(fd < 0){
return 0;
}
sseq = getpid()*time(0);
ip = (Icmp*)buf;
notify(catch);
for(i = 0; i < 3; i++){
ip->type = EchoRequest;
ip->code = 0;
strcpy((char*)ip->data, MSG);
ip->seq[0] = sseq;
ip->seq[1] = sseq>>8;
len = ICMP_IPSIZE+ICMP_HDRSIZE+sizeof(MSG);
/* send a request */
if(write(fd, buf, len) < len)
break;
/* wait 1/10th second for a reply and try again */
alarm(100);
n = read(fd, buf, sizeof(buf));
alarm(0);
if(n <= 0)
continue;
/* an answer to our echo request? */
x = (ip->seq[1]<<8)|ip->seq[0];
if(n >= len)
if(ip->type == EchoReply)
if(x == sseq)
if(strcmp((char*)ip->data, MSG) == 0){
rv = 1;
break;
}
}
close(fd);
return rv;
}

222
src/cmd/ip/dhcpd/testlook.c Executable file
View file

@ -0,0 +1,222 @@
#include <u.h>
#include <libc.h>
#include <ip.h>
#include <bio.h>
#include <ndb.h>
static uchar noether[6];
/*
* Look for a pair with the given attribute. look first on the same line,
* then in the whole entry.
*/
static Ndbtuple*
lookval(Ndbtuple *entry, Ndbtuple *line, char *attr, char *to)
{
Ndbtuple *nt;
/* first look on same line (closer binding) */
for(nt = line;;){
if(strcmp(attr, nt->attr) == 0){
strncpy(to, nt->val, Ndbvlen);
return nt;
}
nt = nt->line;
if(nt == line)
break;
}
/* search whole tuple */
for(nt = entry; nt; nt = nt->entry)
if(strcmp(attr, nt->attr) == 0){
strncpy(to, nt->val, Ndbvlen);
return nt;
}
return 0;
}
/*
* lookup an ip address
*/
static uchar*
lookupip(Ndb *db, char *name, uchar *to, Ipinfo *iip)
{
Ndbtuple *t, *nt;
char buf[Ndbvlen];
uchar subnet[IPaddrlen];
Ndbs s;
char *attr;
attr = ipattr(name);
if(strcmp(attr, "ip") == 0){
parseip(to, name);
return to;
}
t = ndbgetval(db, &s, attr, name, "ip", buf);
if(t){
/* first look for match on same subnet */
for(nt = t; nt; nt = nt->entry){
if(strcmp(nt->attr, "ip") != 0)
continue;
parseip(to, nt->val);
maskip(to, iip->ipmask, subnet);
if(memcmp(subnet, iip->ipnet, sizeof(subnet)) == 0)
return to;
}
/* otherwise, just take what we have */
ndbfree(t);
parseip(to, buf);
return to;
}
return 0;
}
/*
* lookup a subnet and fill in anything we can
*/
static void
recursesubnet(Ndb *db, uchar *mask, Ipinfo *iip, char *fs, char *gw, char *au)
{
Ndbs s;
Ndbtuple *t;
uchar submask[IPaddrlen];
char ip[Ndbvlen];
memmove(iip->ipmask, mask, 4);
maskip(iip->ipaddr, iip->ipmask, iip->ipnet);
sprint(ip, "%I", iip->ipnet);
t = ndbsearch(db, &s, "ip", ip);
print("%s->", ip);
if(t){
/* look for a further subnet */
if(lookval(t, s.t, "ipmask", ip)){
parseip(submask, ip);
/* recurse only if it has changed */
if(!equivip(submask, mask))
recursesubnet(db, submask, iip, fs, gw, au);
}
/* fill in what we don't have */
if(gw[0] == 0)
lookval(t, s.t, "ipgw", gw);
if(fs[0] == 0)
lookval(t, s.t, "fs", fs);
if(au[0] == 0)
lookval(t, s.t, "auth", au);
ndbfree(t);
}
}
#ifdef foo
/*
* find out everything we can about a system from what has been
* specified.
*/
int
ipinfo(Ndb *db, char *etherin, char *ipin, char *name, Ipinfo *iip)
{
Ndbtuple *t;
Ndbs s;
char ether[Ndbvlen];
char ip[Ndbvlen];
char fsname[Ndbvlen];
char gwname[Ndbvlen];
char auname[Ndbvlen];
memset(iip, 0, sizeof(Ipinfo));
fsname[0] = 0;
gwname[0] = 0;
auname[0] = 0;
/*
* look for a matching entry
*/
t = 0;
if(etherin)
t = ndbgetval(db, &s, "ether", etherin, "ip", ip);
if(t == 0 && ipin)
t = ndbsearch(db, &s, "ip", ipin);
if(t == 0 && name)
t = ndbgetval(db, &s, ipattr(name), name, "ip", ip);
if(t){
/*
* copy in addresses and name
*/
if(lookval(t, s.t, "ip", ip))
parseip(iip->ipaddr, ip);
if(lookval(t, s.t, "ether", ether))
parseether(iip->etheraddr, ether);
lookval(t, s.t, "dom", iip->domain);
/*
* Look for bootfile, fs, and gateway.
* If necessary, search through all entries for
* this ip address.
*/
while(t){
if(iip->bootf[0] == 0)
lookval(t, s.t, "bootf", iip->bootf);
if(fsname[0] == 0)
lookval(t, s.t, "fs", fsname);
if(gwname[0] == 0)
lookval(t, s.t, "ipgw", gwname);
if(auname[0] == 0)
lookval(t, s.t, "auth", auname);
ndbfree(t);
if(iip->bootf[0] && fsname[0] && gwname[0] && auname[0])
break;
t = ndbsnext(&s, "ether", ether);
}
} else if(ipin) {
/*
* copy in addresses (all we know)
*/
parseip(iip->ipaddr, ipin);
if(etherin)
parseether(iip->etheraddr, etherin);
} else
return -1;
/*
* Look up the client's network and find a subnet mask for it.
* Fill in from the subnet (or net) entry anything we can't figure
* out from the client record.
*/
recursesubnet(db, classmask[CLASS(iip->ipaddr)], iip, fsname, gwname, auname);
/* lookup fs's and gw's ip addresses */
if(fsname[0])
lookupip(db, fsname, iip->fsip, iip);
if(gwname[0])
lookupip(db, gwname, iip->gwip, iip);
if(auname[0])
lookupip(db, auname, iip->auip, iip);
return 0;
}
#endif
void
main(int argc, char **argv)
{
Ipinfo ii;
Ndb *db;
db = ndbopen(0);
fmtinstall('E', eipconv);
fmtinstall('I', eipconv);
if(argc < 2)
exits(0);
if(strchr(argv[1], '.')){
if(ipinfo(db, 0, argv[1], 0, &ii) < 0)
exits(0);
} else {
if(ipinfo(db, argv[1], 0, 0, &ii) < 0)
exits(0);
}
fprint(2, "a %I m %I n %I f %s e %E\n", ii.ipaddr,
ii.ipmask, ii.ipnet, ii.bootf, ii.etheraddr);
}

168
src/cmd/ip/dhcpd/testlookup.c Executable file
View file

@ -0,0 +1,168 @@
#include <u.h>
#include <libc.h>
#include <ip.h>
#include <bio.h>
#include <ndb.h>
static uchar noether[6];
Ndb *db;
static void
recursesubnet(Ndb *db, uchar *addr, uchar *mask, char *attr, char *name, char *name1)
{
Ndbs s;
Ndbtuple *t, *nt;
uchar submask[IPaddrlen], net[IPaddrlen];
char ip[Ndbvlen];
int found;
maskip(addr, mask, net);
sprint(ip, "%I", net);
t = ndbsearch(db, &s, "ip", ip);
if(t == 0)
return;
for(nt = t; nt; nt = nt->entry){
if(strcmp(nt->attr, "ipmask") == 0){
parseip(submask, nt->val);
if(memcmp(submask, mask, IPaddrlen) != 0)
recursesubnet(db, addr, submask, attr, name, name1);
break;
}
}
if(name[0] == 0){
found = 0;
for(nt = t; nt; nt = nt->entry){
if(strcmp(nt->attr, attr) == 0){
if(found){
strcpy(name, nt->val);
name1[0] = 0;
found = 1;
} else {
strcpy(name1, nt->val);
break;
}
}
}
}
ndbfree(t);
}
/*
* lookup an ip address
*/
static int
getipaddr(Ndb *db, char *name, uchar *to, Ipinfo *iip)
{
Ndbtuple *t, *nt;
char buf[Ndbvlen];
uchar subnet[IPaddrlen];
Ndbs s;
char *attr;
attr = ipattr(name);
if(strcmp(attr, "ip") == 0){
parseip(to, name);
return 1;
}
t = ndbgetval(db, &s, attr, name, "ip", buf);
if(t){
/* first look for match on same subnet */
for(nt = t; nt; nt = nt->entry){
if(strcmp(nt->attr, "ip") != 0)
continue;
parseip(to, nt->val);
maskip(to, iip->ipmask, subnet);
if(memcmp(subnet, iip->ipnet, sizeof(subnet)) == 0)
return 1;
}
/* otherwise, just take what we have */
ndbfree(t);
parseip(to, buf);
return 1;
}
return 0;
}
/*
* return the ip addresses for a type of server for system ip
*/
int
lookupserver(char *attr, uchar ipaddrs[2][IPaddrlen], Ipinfo *iip)
{
Ndbtuple *t, *nt;
Ndbs s;
char ip[32];
char name[Ndbvlen];
char name1[Ndbvlen];
int i;
name[0] = name1[0] = 0;
snprint(ip, sizeof(ip), "%I", iip->ipaddr);
t = ndbsearch(db, &s, "ip", ip);
while(t){
for(nt = t; nt; nt = nt->entry){
if(strcmp(attr, nt->attr) == 0){
if(*name == 0)
strcpy(name, nt->val);
else {
strcpy(name1, nt->val);
break;
}
}
}
if(name[0])
break;
t = ndbsnext(&s, "ip", ip);
}
if(name[0] == 0)
recursesubnet(db, iip->ipaddr, classmask[CLASS(iip->ipaddr)], attr, name, name1);
i = 0;
if(name[0] && getipaddr(db, name, *ipaddrs, iip) == 1){
ipaddrs++;
i++;
}
if(name1[0] && getipaddr(db, name1, *ipaddrs, iip) == 1)
i++;
return i;
}
void
main(int argc, char **argv)
{
Ipinfo ii;
uchar addrs[2][IPaddrlen];
int i, j;
db = ndbopen(0);
fmtinstall('E', eipconv);
fmtinstall('I', eipconv);
if(argc < 2)
exits(0);
if(strchr(argv[1], '.')){
if(ipinfo(db, 0, argv[1], 0, &ii) < 0)
exits(0);
} else {
if(ipinfo(db, argv[1], 0, 0, &ii) < 0)
exits(0);
}
print("a %I m %I n %I f %s e %E a %I\n", ii.ipaddr,
ii.ipmask, ii.ipnet, ii.bootf, ii.etheraddr, ii.auip);
i = lookupserver("auth", addrs, &ii);
print("lookupserver returns %d\n", i);
for(j = 0; j < i; j++)
print("%I\n", addrs[j]);
i = lookupserver("dns", addrs, &ii);
print("lookupserver returns %d\n", i);
for(j = 0; j < i; j++)
print("%I\n", addrs[j]);
}

22
src/cmd/ip/dhcpd/testping.c Executable file
View file

@ -0,0 +1,22 @@
#include <u.h>
#include <libc.h>
#include <ip.h>
#include <bio.h>
#include <ndb.h>
#include "dat.h"
char *blog = "ipboot";
void
main(int argc, char **argv)
{
fmtinstall('E', eipconv);
fmtinstall('I', eipconv);
if(argc < 2)
exits(0);
if(icmpecho(argv[1]))
fprint(2, "%s live\n", argv[1]);
else
fprint(2, "%s doesn't answer\n", argv[1]);
}

58
src/cmd/ip/snoopy/Linux.c Normal file
View file

@ -0,0 +1,58 @@
#include <u.h>
#include <sys/socket.h>
#include <net/if.h>
#include <netpacket/packet.h>
#include <net/ethernet.h>
#include <netinet/in.h>
#include <sys/ioctl.h>
#include <libc.h>
#include <ip.h>
#include <bio.h>
#include <fcall.h>
#include <libsec.h>
#include "dat.h"
#include "protos.h"
#include "y.tab.h"
int
opendevice(char *dev, int promisc)
{
int fd;
struct ifreq ifr;
struct sockaddr_ll sa;
if((fd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL))) < 0)
return -1;
if(dev){
memset(&ifr, 0, sizeof ifr);
strncpy(ifr.ifr_name, dev, sizeof ifr.ifr_name);
if(ioctl(fd, SIOCGIFINDEX, &ifr) < 0){
close(fd);
return -1;
}
memset(&sa, 0, sizeof sa);
sa.sll_family = AF_PACKET;
sa.sll_protocol = htons(ETH_P_ALL);
sa.sll_ifindex = ifr.ifr_ifindex;
if(bind(fd, (struct sockaddr*)&sa, sizeof sa) < 0){
close(fd);
return -1;
}
}
if(promisc){
memset(&ifr, 0, sizeof ifr);
strncpy(ifr.ifr_name, dev, sizeof ifr.ifr_name);
if(ioctl(fd, SIOCGIFFLAGS, &ifr) < 0){
close(fd);
return -1;
}
ifr.ifr_flags |= IFF_PROMISC;
if(ioctl(fd, SIOCSIFFLAGS, &ifr) < 0){
close(fd);
return -1;
}
}
return fd;
}

128
src/cmd/ip/snoopy/arp.c Executable file
View file

@ -0,0 +1,128 @@
#include <u.h>
#include <libc.h>
#include <ip.h>
#include "dat.h"
#include "protos.h"
typedef struct Hdr Hdr;
struct Hdr
{
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];
};
enum
{
ARPLEN= 28,
};
enum
{
Ospa,
Otpa,
Ostpa,
Osha,
Otha,
Ostha,
Opa,
};
static Field p_fields[] =
{
{"spa", Fv4ip, Ospa, "protocol source", } ,
{"tpa", Fv4ip, Otpa, "protocol target", } ,
{"a", Fv4ip, Ostpa, "protocol source/target", } ,
{"sha", Fba, Osha, "hardware source", } ,
{"tha", Fba, Otha, "hardware target", } ,
{"ah", Fba, Ostha, "hardware source/target", } ,
{0}
};
static void
p_compile(Filter *f)
{
if(f->op == '='){
compile_cmp(arp.name, f, p_fields);
return;
}
sysfatal("unknown arp field: %s", f->s);
}
static int
p_filter(Filter *f, Msg *m)
{
Hdr *h;
if(m->pe - m->ps < ARPLEN)
return 0;
h = (Hdr*)m->ps;
m->ps += ARPLEN;
switch(f->subop){
case Ospa:
return h->pln == 4 && NetL(h->spa) == f->ulv;
case Otpa:
return h->pln == 4 && NetL(h->tpa) == f->ulv;
case Ostpa:
return h->pln == 4 && (NetL(h->tpa) == f->ulv ||
NetL(h->spa) == f->ulv);
case Osha:
return memcmp(h->sha, f->a, h->hln) == 0;
case Otha:
return memcmp(h->tha, f->a, h->hln) == 0;
case Ostha:
return memcmp(h->sha, f->a, h->hln)==0
||memcmp(h->tha, f->a, h->hln)==0;
}
return 0;
}
static int
p_seprint(Msg *m)
{
Hdr *h;
if(m->pe - m->ps < ARPLEN)
return -1;
h = (Hdr*)m->ps;
m->ps += ARPLEN;
/* no next protocol */
m->pr = nil;
m->p = seprint(m->p, m->e, "op=%1d len=%1d/%1d spa=%V sha=%E tpa=%V tha=%E",
NetS(h->op), h->pln, h->hln,
h->spa, h->sha, h->tpa, h->tha);
return 0;
}
Proto arp =
{
"arp",
p_compile,
p_filter,
p_seprint,
nil,
p_fields,
defaultframer,
};
Proto rarp =
{
"rarp",
p_compile,
p_filter,
p_seprint,
nil,
p_fields,
defaultframer,
};

176
src/cmd/ip/snoopy/bootp.c Executable file
View file

@ -0,0 +1,176 @@
#include <u.h>
#include <libc.h>
#include <ip.h>
#include "dat.h"
#include "protos.h"
enum
{
OfferTimeout= 60, /* when an offer times out */
MaxLease= 60*60, /* longest lease for dynamic binding */
MinLease= 15*60, /* shortest lease for dynamic binding */
StaticLease= 30*60, /* lease for static binding */
IPUDPHDRSIZE= 28, /* size of an IP plus UDP header */
MINSUPPORTED= 576, /* biggest IP message the client must support */
/* lengths of some bootp fields */
Maxhwlen= 16,
Maxfilelen= 128,
Maxoptlen= 312-4,
/* bootp types */
Bootrequest= 1,
Bootreply= 2,
/* bootp flags */
Fbroadcast= 1<<15,
};
typedef struct Hdr Hdr;
struct Hdr
{
uchar op; /* opcode */
uchar htype; /* hardware type */
uchar hlen; /* hardware address len */
uchar hops; /* hops */
uchar xid[4]; /* a random number */
uchar secs[2]; /* elapsed since client started booting */
uchar flags[2];
uchar ciaddr[IPv4addrlen]; /* client IP address (client tells server) */
uchar yiaddr[IPv4addrlen]; /* client IP address (server tells client) */
uchar siaddr[IPv4addrlen]; /* server IP address */
uchar giaddr[IPv4addrlen]; /* gateway IP address */
uchar chaddr[Maxhwlen]; /* client hardware address */
char sname[64]; /* server host name (optional) */
char file[Maxfilelen]; /* boot file name */
uchar optmagic[4];
uchar optdata[Maxoptlen];
};
enum
{
Oca,
Osa,
Ot,
};
static Field p_fields[] =
{
{"ca", Fv4ip, Oca, "client IP addr", } ,
{"sa", Fv4ip, Osa, "server IP addr", } ,
{0}
};
#define plan9opt ((ulong)(('p'<<24) | ('9'<<16) | (' '<<8) | ' '))
#define genericopt (0x63825363UL)
static Mux p_mux[] =
{
{"dhcp", genericopt,},
{"plan9bootp", plan9opt,},
{"dump", 0,},
{0}
};
static void
p_compile(Filter *f)
{
Mux *m;
if(f->op == '='){
compile_cmp(arp.name, f, p_fields);
return;
}
for(m = p_mux; m->name != nil; m++)
if(strcmp(f->s, m->name) == 0){
f->pr = m->pr;
f->ulv = m->val;
f->subop = Ot;
return;
}
sysfatal("unknown bootp field: %s", f->s);
}
static int
p_filter(Filter *f, Msg *m)
{
Hdr *h;
h = (Hdr*)m->ps;
if(m->pe < (uchar*)h->sname)
return 0;
m->ps = h->optdata;
switch(f->subop){
case Oca:
return NetL(h->ciaddr) == f->ulv || NetL(h->yiaddr) == f->ulv;
case Osa:
return NetL(h->siaddr) == f->ulv;
case Ot:
return NetL(h->optmagic) == f->ulv;
}
return 0;
}
static char*
op(int i)
{
static char x[20];
switch(i){
case Bootrequest:
return "Req";
case Bootreply:
return "Rep";
default:
sprint(x, "%d", i);
return x;
}
}
static int
p_seprint(Msg *m)
{
Hdr *h;
ulong x;
h = (Hdr*)m->ps;
if(m->pe < (uchar*)h->sname)
return -1;
/* point past data */
m->ps = h->optdata;
/* next protocol */
m->pr = nil;
if(m->pe >= (uchar*)h->optdata){
x = NetL(h->optmagic);
demux(p_mux, x, x, m, &dump);
}
m->p = seprint(m->p, m->e, "t=%s ht=%d hl=%d hp=%d xid=%ux sec=%d fl=%4.4ux ca=%V ya=%V sa=%V ga=%V cha=%E magic=%lux",
op(h->op), h->htype, h->hlen, h->hops,
NetL(h->xid), NetS(h->secs), NetS(h->flags),
h->ciaddr, h->yiaddr, h->siaddr, h->giaddr, h->chaddr,
(ulong)NetL(h->optmagic));
if(m->pe > (uchar*)h->sname && *h->sname)
m->p = seprint(m->p, m->e, " snam=%s", h->sname);
if(m->pe > (uchar*)h->file && *h->file)
m->p = seprint(m->p, m->e, " file=%s", h->file);
return 0;
}
Proto bootp =
{
"bootp",
p_compile,
p_filter,
p_seprint,
p_mux,
p_fields,
defaultframer,
};

106
src/cmd/ip/snoopy/dat.h Executable file
View file

@ -0,0 +1,106 @@
typedef struct Field Field;
typedef struct Filter Filter;
typedef struct Msg Msg;
typedef struct Mux Mux;
typedef struct Proto Proto;
#define NetS(x) ((((uchar*)x)[0]<<8) | ((uchar*)x)[1])
#define Net3(x) ((((uchar*)x)[0]<<16) | (((uchar*)x)[1]<<8) | ((uchar*)x)[2])
#define NetL(x) ((((uchar*)x)[0]<<24) | (((uchar*)x)[1]<<16) | (((uchar*)x)[2]<<8) | ((uchar*)x)[3])
/*
* one per protocol module
*/
struct Proto
{
char* name;
void (*compile)(Filter*);
int (*filter)(Filter*, Msg*);
int (*seprint)(Msg*);
Mux* mux;
Field* field;
int (*framer)(int, uchar*, int);
};
extern Proto *protos[];
/*
* one per protocol module, pointed to by Proto.mux
*/
struct Mux
{
char* name;
ulong val;
Proto* pr;
};
/*
* a field defining a comparison filter
*/
struct Field
{
char* name;
int ftype;
int subop;
char* help;
};
/*
* the status of the current message walk
*/
struct Msg
{
uchar *ps; /* packet ptr */
uchar *pe; /* packet end */
char *p; /* buffer start */
char *e; /* buffer end */
int needroot; /* pr is root, need to see in expression */
Proto *pr; /* current/next protocol */
};
enum
{
Fnum, /* just a number */
Fether, /* ethernet address */
Fv4ip, /* v4 ip address */
Fv6ip, /* v6 ip address */
Fba, /* byte array */
};
/*
* a node in the filter tree
*/
struct Filter {
int op; /* token type */
char *s; /* string */
Filter *l;
Filter *r;
Proto *pr; /* next protocol;
/* protocol specific */
int subop;
ulong param;
union {
ulong ulv;
vlong vlv;
uchar a[32];
};
};
extern void yyinit(char*);
extern int yyparse(void);
extern Filter* newfilter(void);
extern void compile_cmp(char*, Filter*, Field*);
extern void demux(Mux*, ulong, ulong, Msg*, Proto*);
extern int defaultframer(int, uchar*, int);
extern int opendevice(char*, int);
extern int Nflag;
extern int dflag;
extern int Cflag;
typedef Filter *Filterptr;
#define YYSTYPE Filterptr
extern Filter *filter;

483
src/cmd/ip/snoopy/dhcp.c Executable file
View file

@ -0,0 +1,483 @@
#include <u.h>
#include <libc.h>
#include <ip.h>
#include "dat.h"
#include "protos.h"
enum
{
Maxoptlen= 312-4,
/* dhcp types */
Discover= 1,
Offer= 2,
Request= 3,
Decline= 4,
Ack= 5,
Nak= 6,
Release= 7,
Inform= 8,
/* bootp option types */
OBend= 255,
OBpad= 0,
OBmask= 1,
OBtimeoff= 2,
OBrouter= 3,
OBtimeserver= 4,
OBnameserver= 5,
OBdnserver= 6,
OBlogserver= 7,
OBcookieserver= 8,
OBlprserver= 9,
OBimpressserver= 10,
OBrlserver= 11,
OBhostname= 12, /* 0xc0 */
OBbflen= 13,
OBdumpfile= 14,
OBdomainname= 15,
OBswapserver= 16, /* 0x10 */
OBrootpath= 17,
OBextpath= 18,
OBipforward= 19,
OBnonlocal= 20,
OBpolicyfilter= 21,
OBmaxdatagram= 22,
OBttl= 23,
OBpathtimeout= 24,
OBpathplateau= 25,
OBmtu= 26,
OBsubnetslocal= 27,
OBbaddr= 28,
OBdiscovermask= 29,
OBsupplymask= 30,
OBdiscoverrouter= 31,
OBrsserver= 32, /* 0x20 */
OBstaticroutes= 33,
OBtrailerencap= 34,
OBarptimeout= 35,
OBetherencap= 36,
OBtcpttl= 37,
OBtcpka= 38,
OBtcpkag= 39,
OBnisdomain= 40,
OBniserver= 41,
OBntpserver= 42,
OBvendorinfo= 43, /* 0x2b */
OBnetbiosns= 44,
OBnetbiosdds= 45,
OBnetbiostype= 46,
OBnetbiosscope= 47,
OBxfontserver= 48, /* 0x30 */
OBxdispmanager= 49,
OBnisplusdomain= 64, /* 0x40 */
OBnisplusserver= 65,
OBhomeagent= 68,
OBsmtpserver= 69,
OBpop3server= 70,
OBnntpserver= 71,
OBwwwserver= 72,
OBfingerserver= 73,
OBircserver= 74,
OBstserver= 75,
OBstdaserver= 76,
/* dhcp options */
ODipaddr= 50, /* 0x32 */
ODlease= 51,
ODoverload= 52,
ODtype= 53, /* 0x35 */
ODserverid= 54, /* 0x36 */
ODparams= 55, /* 0x37 */
ODmessage= 56,
ODmaxmsg= 57,
ODrenewaltime= 58,
ODrebindingtime= 59,
ODvendorclass= 60,
ODclientid= 61, /* 0x3d */
ODtftpserver= 66,
ODbootfile= 67,
/* plan9 vendor info options */
OP9fs= 128, // plan9 file servers
OP9auth= 129, // plan9 auth servers
};
static void
p_compile(Filter *f)
{
sysfatal("unknown bootp field: %s", f->s);
}
static int
p_filter(Filter *f, Msg *m)
{
USED(f);
USED(m);
return 0;
}
/*
* convert a byte array to hex
*/
static char
hex(int x)
{
if(x < 10)
return x + '0';
return x - 10 + 'a';
}
static char*
phex(char *p, char *e, char *tag, uchar *o, int n)
{
p = seprint(p, e, "%s=", tag);
for(; p+2 < e && n > 0; n--){
*p++ = hex(*o>>4);
*p++ = hex(*o & 0xf);
o++;
}
return p;
}
static char*
pstring(char *p, char *e, char *tag, uchar *o, int n)
{
char msg[256];
if(n > sizeof msg - 1)
n = sizeof msg - 1;
memmove(msg, o, n);
msg[n] = 0;
return seprint(p, e, "%s=%s", tag, msg);
}
static char*
pint(char *p, char *e, char *tag, uchar *o, int n)
{
int x;
x = *(char*)o++;
for(; n > 1; n--)
x = (x<<8)|*o++;
return seprint(p, e, "%s=%d", tag, x);
}
static char*
puint(char *p, char *e, char *tag, uchar *o, int n)
{
uint x;
x = *o++;
for(; n > 1; n--)
x = (x<<8)|*o++;
return seprint(p, e, "%s=%ud", tag, x);
}
static char*
pserver(char *p, char *e, char *tag, uchar *o, int n)
{
p = seprint(p, e, "%s=(", tag);
while(n >= 4){
p = seprint(p, e, " %V", o);
n -= 4;
o += 4;
}
p = seprint(p, e, ")");
return p;
}
static char *dhcptype[256] =
{
[Discover] "Discover",
[Offer] "Offer",
[Request] "Request",
[Decline] "Decline",
[Ack] "Ack",
[Nak] "Nak",
[Release] "Release",
[Inform] "Inform",
};
static char*
ptype(char *p, char *e, uchar val)
{
char *x;
x = dhcptype[val];
if(x != nil)
return seprint(p, e, "t=%s", x);
else
return seprint(p, e, "t=%d", val);
}
static int
p_seprint(Msg *m)
{
int i, n, code;
uchar *o, *ps;
char *p, *e;
char msg[64];
/* no next proto */
m->pr = nil;
p = m->p;
e = m->e;
ps = m->ps;
while(ps < m->pe){
code = *ps++;
if(code == 255)
break;
if(code == 0)
continue;
/* ignore anything that's too long */
n = *ps++;
o = ps;
ps += n;
if(ps > m->pe)
break;
switch(code){
case ODipaddr: /* requested ip address */
p = pserver(p, e, "ipaddr", o, n);
break;
case ODlease: /* requested lease time */
p = pint(p, e, "lease", o, n);
break;
case ODtype:
p = ptype(p, e, *o);
break;
case ODserverid:
p = pserver(p, e, "serverid", o, n);
break;
case ODmessage:
p = pstring(p, e, "message", o, n);
break;
case ODmaxmsg:
p = puint(p, e, "maxmsg", o, n);
break;
case ODclientid:
p = phex(p, e, "clientid", o, n);
break;
case ODparams:
p = seprint(p, e, " requested=(");
for(i = 0; i < n; i++){
if(i != 0)
p = seprint(p, e, " ");
p = seprint(p, e, "%ud", o[i]);
}
p = seprint(p, e, ")");
break;
case ODvendorclass:
p = pstring(p, e, "vendorclass", o, n);
break;
case OBmask:
p = pserver(p, e, "mask", o, n);
break;
case OBtimeoff:
p = pint(p, e, "timeoff", o, n);
break;
case OBrouter:
p = pserver(p, e, "router", o, n);
break;
case OBtimeserver:
p = pserver(p, e, "timesrv", o, n);
break;
case OBnameserver:
p = pserver(p, e, "namesrv", o, n);
break;
case OBdnserver:
p = pserver(p, e, "dnssrv", o, n);
break;
case OBlogserver:
p = pserver(p, e, "logsrv", o, n);
break;
case OBcookieserver:
p = pserver(p, e, "cookiesrv", o, n);
break;
case OBlprserver:
p = pserver(p, e, "lprsrv", o, n);
break;
case OBimpressserver:
p = pserver(p, e, "impresssrv", o, n);
break;
case OBrlserver:
p = pserver(p, e, "rlsrv", o, n);
break;
case OBhostname:
p = pstring(p, e, "hostname", o, n);
break;
case OBbflen:
break;
case OBdumpfile:
p = pstring(p, e, "dumpfile", o, n);
break;
case OBdomainname:
p = pstring(p, e, "domname", o, n);
break;
case OBswapserver:
p = pserver(p, e, "swapsrv", o, n);
break;
case OBrootpath:
p = pstring(p, e, "rootpath", o, n);
break;
case OBextpath:
p = pstring(p, e, "extpath", o, n);
break;
case OBipforward:
p = phex(p, e, "ipforward", o, n);
break;
case OBnonlocal:
p = phex(p, e, "nonlocal", o, n);
break;
case OBpolicyfilter:
p = phex(p, e, "policyfilter", o, n);
break;
case OBmaxdatagram:
p = phex(p, e, "maxdatagram", o, n);
break;
case OBttl:
p = puint(p, e, "ttl", o, n);
break;
case OBpathtimeout:
p = puint(p, e, "pathtimeout", o, n);
break;
case OBpathplateau:
p = phex(p, e, "pathplateau", o, n);
break;
case OBmtu:
p = puint(p, e, "mtu", o, n);
break;
case OBsubnetslocal:
p = pserver(p, e, "subnet", o, n);
break;
case OBbaddr:
p = pserver(p, e, "baddr", o, n);
break;
case OBdiscovermask:
p = pserver(p, e, "discovermsak", o, n);
break;
case OBsupplymask:
p = pserver(p, e, "rousupplymaskter", o, n);
break;
case OBdiscoverrouter:
p = pserver(p, e, "discoverrouter", o, n);
break;
case OBrsserver:
p = pserver(p, e, "rsrouter", o, n);
break;
case OBstaticroutes:
p = phex(p, e, "staticroutes", o, n);
break;
case OBtrailerencap:
p = phex(p, e, "trailerencap", o, n);
break;
case OBarptimeout:
p = puint(p, e, "arptimeout", o, n);
break;
case OBetherencap:
p = phex(p, e, "etherencap", o, n);
break;
case OBtcpttl:
p = puint(p, e, "tcpttl", o, n);
break;
case OBtcpka:
p = puint(p, e, "tcpka", o, n);
break;
case OBtcpkag:
p = phex(p, e, "tcpkag", o, n);
break;
case OBnisdomain:
p = pstring(p, e, "nisdomain", o, n);
break;
case OBniserver:
p = pserver(p, e, "nisrv", o, n);
break;
case OBntpserver:
p = pserver(p, e, "ntpsrv", o, n);
break;
case OBvendorinfo:
p = phex(p, e, "vendorinfo", o, n);
break;
case OBnetbiosns:
p = pserver(p, e, "biosns", o, n);
break;
case OBnetbiosdds:
p = phex(p, e, "biosdds", o, n);
break;
case OBnetbiostype:
p = phex(p, e, "biostype", o, n);
break;
case OBnetbiosscope:
p = phex(p, e, "biosscope", o, n);
break;
case OBxfontserver:
p = pserver(p, e, "fontsrv", o, n);
break;
case OBxdispmanager:
p = pserver(p, e, "xdispmgr", o, n);
break;
case OBnisplusdomain:
p = pstring(p, e, "nisplusdomain", o, n);
break;
case OBnisplusserver:
p = pserver(p, e, "nisplussrv", o, n);
break;
case OBhomeagent:
p = pserver(p, e, "homeagent", o, n);
break;
case OBsmtpserver:
p = pserver(p, e, "smtpsrv", o, n);
break;
case OBpop3server:
p = pserver(p, e, "pop3srv", o, n);
break;
case OBnntpserver:
p = pserver(p, e, "ntpsrv", o, n);
break;
case OBwwwserver:
p = pserver(p, e, "wwwsrv", o, n);
break;
case OBfingerserver:
p = pserver(p, e, "fingersrv", o, n);
break;
case OBircserver:
p = pserver(p, e, "ircsrv", o, n);
break;
case OBstserver:
p = pserver(p, e, "stsrv", o, n);
break;
case OBstdaserver:
p = pserver(p, e, "stdasrv", o, n);
break;
case OBend:
goto out;
default:
snprint(msg, sizeof msg, " T%ud", code);
p = phex(p, e, msg, o, n);
break;
}
if(*ps != OBend)
p = seprint(p, e, " ");
}
out:
m->p = p;
m->ps = ps;
return 0;
}
Proto dhcp =
{
"dhcp",
p_compile,
p_filter,
p_seprint,
nil,
nil,
defaultframer,
};

92
src/cmd/ip/snoopy/dump.c Executable file
View file

@ -0,0 +1,92 @@
#include <u.h>
#include <libc.h>
#include <ip.h>
#include <ctype.h>
#include "dat.h"
#include "protos.h"
static void
p_compile(Filter *f)
{
USED(f);
}
static int
p_filter(Filter *f, Msg *m)
{
USED(f);
USED(m);
return 0;
}
static char tohex[16] = {
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'a', 'b', 'c', 'd', 'e', 'f'
};
static int
p_seprint(Msg *m)
{
int c, i, n, isstring;
uchar *ps = m->ps;
char *p = m->p;
char *e = m->e;
n = m->pe - ps;
if(n > Nflag)
n = Nflag;
isstring = 1;
for(i = 0; i < n; i++){
c = ps[i];
if(!isprint(c) && !isspace(c)){
isstring = 0;
break;
}
}
if(isstring){
for(i = 0; i < n && p+1<e; i++){
c = ps[i];
switch(c){
case '\t':
*p++ = '\\';
*p++ = 't';
break;
case '\r':
*p++ = '\\';
*p++ = 'r';
break;
case '\n':
*p++ = '\\';
*p++ = 'n';
break;
default:
*p++ = c;
}
}
} else {
for(i = 0; i < n && p+1<e; i++){
c = ps[i];
*p++ = tohex[c>>4];
*p++ = tohex[c&0xf];
}
}
m->pr = nil;
m->p = p;
m->ps = ps;
return 0;
}
Proto dump =
{
"dump",
p_compile,
p_filter,
p_seprint,
nil,
nil,
defaultframer,
};

121
src/cmd/ip/snoopy/ether.c Executable file
View file

@ -0,0 +1,121 @@
#include <u.h>
#include <libc.h>
#include <ip.h>
#include "dat.h"
#include "protos.h"
typedef struct Hdr Hdr;
struct Hdr {
uchar d[6];
uchar s[6];
uchar type[2];
char data[1500];
};
#define ETHERMINTU 60 /* minimum transmit size */
#define ETHERMAXTU 1514 /* maximum transmit size */
#define ETHERHDRSIZE 14 /* size of an ethernet header */
static Mux p_mux[] =
{
{"ip", 0x0800, } ,
{"arp", 0x0806, } ,
{"rarp", 0x0806, } ,
{"ip6", 0x86dd, } ,
{"pppoe_disc", 0x8863, },
{"pppoe_sess", 0x8864, },
{0}
};
enum
{
Os, // source
Od, // destination
Oa, // source or destination
Ot, // type
};
static Field p_fields[] =
{
{"s", Fether, Os, "source address", } ,
{"d", Fether, Od, "destination address", } ,
{"a", Fether, Oa, "source|destination address" } ,
{"sd", Fether, Oa, "source|destination address" } ,
{"t", Fnum, Ot, "type" } ,
{0}
};
static void
p_compile(Filter *f)
{
Mux *m;
if(f->op == '='){
compile_cmp(ether.name, f, p_fields);
return;
}
for(m = p_mux; m->name != nil; m++)
if(strcmp(f->s, m->name) == 0){
f->pr = m->pr;
f->ulv = m->val;
f->subop = Ot;
return;
}
sysfatal("unknown ethernet field or protocol: %s", f->s);
}
static int
p_filter(Filter *f, Msg *m)
{
Hdr *h;
if(m->pe - m->ps < ETHERHDRSIZE)
return 0;
h = (Hdr*)m->ps;
m->ps += ETHERHDRSIZE;
switch(f->subop){
case Os:
return !memcmp(h->s, f->a, 6);
case Od:
return !memcmp(h->d, f->a, 6);
case Oa:
return memcmp(h->s, f->a, 6) == 0 || memcmp(h->d, f->a, 6) == 0;
case Ot:
return NetS(h->type) == f->ulv;
}
return 0;
}
static int
p_seprint(Msg *m)
{
Hdr *h;
uint t;
int len;
len = m->pe - m->ps;
if(len < ETHERHDRSIZE)
return -1;
h = (Hdr*)m->ps;
m->ps += ETHERHDRSIZE;
t = NetS(h->type);
demux(p_mux, t, t, m, &dump);
m->p = seprint(m->p, m->e, "s=%E d=%E pr=%4.4ux ln=%d", h->s, h->d,
t, len);
return 0;
}
Proto ether =
{
"ether",
p_compile,
p_filter,
p_seprint,
p_mux,
p_fields,
defaultframer
};

83
src/cmd/ip/snoopy/gre.c Executable file
View file

@ -0,0 +1,83 @@
/* GRE flag bits */
enum {
GRE_chksum = (1<<15),
GRE_routing = (1<<14),
GRE_key = (1<<13),
GRE_seq = (1<<12),
GRE_srcrt = (1<<11),
GRE_recur = (7<<8),
GRE_ack = (1<<7),
GRE_ver = 0x7,
};
/* GRE protocols */
enum {
GRE_sna = 0x0004,
GRE_osi = 0x00fe,
GRE_pup = 0x0200,
GRE_xns = 0x0600,
GRE_ip = 0x0800,
GRE_chaos = 0x0804,
GRE_rfc826 = 0x0806,
GRE_frarp = 0x0808,
GRE_vines = 0x0bad,
GRE_vinesecho = 0x0bae,
GRE_vinesloop = 0x0baf,
GRE_decnetIV = 0x6003,
GRE_ppp = 0x880b,
};
int
sprintgre(void *a, char *buf, int len)
{
int flag, prot, chksum, offset, key, seq, ack;
int n;
uchar *p = a;
chksum = offset = key = seq = ack = 0;
flag = NetS(p);
prot = NetS(p+2);
p += 4; len -= 4;
if(flag & (GRE_chksum|GRE_routing)){
chksum = NetS(p);
offset = NetS(p+2);
p += 4; len -= 4;
}
if(flag&GRE_key){
key = NetL(p);
p += 4; len -= 4;
}
if(flag&GRE_seq){
seq = NetL(p);
p += 4; len -= 4;
}
if(flag&GRE_ack){
ack = NetL(p);
p += 4; len -= 4;
}
/* skip routing if present */
if(flag&GRE_routing) {
while(len >= 4 && (n=p[3]) != 0) {
len -= n;
p += n;
}
}
USED(offset);
USED(chksum);
n = sprint(buf, "GRE(f %4.4ux p %ux k %ux", flag, prot, key);
if(flag&GRE_seq)
n += sprint(buf+n, " s %ux", seq);
if(flag&GRE_ack)
n += sprint(buf+n, " a %ux", ack);
n += sprint(buf+n, " len = %d/%d) ", len, key>>16);
if(prot == GRE_ppp && len > 0)
n += sprintppp(p, buf+n, len);
else
n += sprintx(p, buf+n, len);
return n;
}

174
src/cmd/ip/snoopy/hdlc.c Executable file
View file

@ -0,0 +1,174 @@
#include <u.h>
#include <libc.h>
#include <ip.h>
#include "dat.h"
#include "protos.h"
enum {
HDLC_frame= 0x7e,
HDLC_esc= 0x7d,
/* PPP frame fields */
PPP_addr= 0xff,
PPP_ctl= 0x3,
PPP_initfcs= 0xffff,
PPP_goodfcs= 0xf0b8,
};
/*
* Calculate FCS - rfc 1331
*/
ushort fcstab[256] =
{
0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
};
static uchar inbuf[16*1024];
static int inlen;
static Mux p_mux[] =
{
{"ppp", (PPP_addr<<8)|PPP_ctl, } ,
{0}
};
enum
{
Ot = 1
};
static void
p_compile(Filter *f)
{
Mux *m;
for(m = p_mux; m->name != nil; m++)
if(strcmp(f->s, m->name) == 0){
f->pr = m->pr;
f->ulv = m->val;
f->subop = Ot;
return;
}
sysfatal("unknown ethernet field or protocol: %s", f->s);
}
static int
p_filter(Filter *f, Msg *m)
{
ulong t;
if(m->pe-m->ps < 2)
return 0;
switch(f->subop){
case Ot:
t = (m->ps[0]<<8)|m->ps[1];
if(t != f->ulv)
return 0;
break;
}
return 1;
}
static int
p_seprint(Msg *m)
{
ulong t;
if(m->pe-m->ps < 2)
return -1;
t = (m->ps[0]<<8)|m->ps[1];
m->ps += 2;
demux(p_mux, t, t, m, &dump);
return 0;
}
static int
p_framer(int fd, uchar *pkt, int pktlen)
{
ushort fcs;
uchar *from, *efrom, *to, *eto;
int n;
ulong c;
eto = pkt+pktlen;
for(;;){
efrom = memchr(inbuf, HDLC_frame, inlen);
if(efrom == nil){
if(inlen >= sizeof(inbuf))
inlen = 0;
n = read(fd, inbuf+inlen, sizeof(inbuf)-inlen);
if(n <= 0)
break;
inlen += n;
continue;
}
/* checksum and unescape the frame */
fcs = PPP_initfcs;
to = pkt;
for(from = inbuf; from < efrom;){
c = *from++;
if(c == HDLC_esc)
c = (*from++) ^ 0x20;
if(to < eto)
*to++ = c;
fcs = (fcs >> 8) ^ fcstab[(fcs ^ c) & 0xff];
}
/* move down anything that's left */
inlen -= efrom+1-inbuf;
memmove(inbuf, efrom+1, inlen);
/* accept if this is a good packet */
if(fcs != PPP_goodfcs)
print("bad frame %ld %2.2ux %2.2ux!\n", to-pkt, pkt[0], pkt[1]);
else
return to-pkt;
}
return -1;
}
Proto hdlc =
{
"hdlc",
p_compile,
p_filter,
p_seprint,
p_mux,
nil,
p_framer,
};

196
src/cmd/ip/snoopy/icmp.c Executable file
View file

@ -0,0 +1,196 @@
#include <u.h>
#include <libc.h>
#include <ip.h>
#include "dat.h"
#include "protos.h"
typedef struct Hdr Hdr;
struct Hdr
{ uchar type;
uchar code;
uchar cksum[2]; /* Checksum */
uchar data[1];
};
enum
{
ICMPLEN= 4,
};
enum
{
Ot, /* type */
Op, /* next protocol */
};
static Field p_fields[] =
{
{"t", Fnum, Ot, "type", } ,
{0}
};
enum
{
EchoRep= 0,
Unreachable= 3,
SrcQuench= 4,
Redirect= 5,
EchoReq= 8,
TimeExceed= 11,
ParamProb= 12,
TSreq= 13,
TSrep= 14,
InfoReq= 15,
InfoRep= 16,
};
static Mux p_mux[] =
{
{"ip", Unreachable, },
{"ip", SrcQuench, },
{"ip", Redirect, },
{"ip", TimeExceed, },
{"ip", ParamProb, },
{0},
};
char *icmpmsg[236] =
{
[EchoRep] "EchoRep",
[Unreachable] "Unreachable",
[SrcQuench] "SrcQuench",
[Redirect] "Redirect",
[EchoReq] "EchoReq",
[TimeExceed] "TimeExceed",
[ParamProb] "ParamProb",
[TSreq] "TSreq",
[TSrep] "TSrep",
[InfoReq] "InfoReq",
[InfoRep] "InfoRep",
};
static void
p_compile(Filter *f)
{
if(f->op == '='){
compile_cmp(udp.name, f, p_fields);
return;
}
if(strcmp(f->s, "ip") == 0){
f->pr = p_mux->pr;
f->subop = Op;
return;
}
sysfatal("unknown icmp field or protocol: %s", f->s);
}
static int
p_filter(Filter *f, Msg *m)
{
Hdr *h;
if(m->pe - m->ps < ICMPLEN)
return 0;
h = (Hdr*)m->ps;
m->ps += ICMPLEN;
switch(f->subop){
case Ot:
if(h->type == f->ulv)
return 1;
break;
case Op:
switch(h->type){
case Unreachable:
case TimeExceed:
case SrcQuench:
case Redirect:
case ParamProb:
m->ps += 4;
return 1;
}
}
return 0;
}
static int
p_seprint(Msg *m)
{
Hdr *h;
char *tn;
char *p = m->p;
char *e = m->e;
ushort cksum2, cksum;
h = (Hdr*)m->ps;
m->ps += ICMPLEN;
m->pr = &dump;
if(m->pe - m->ps < ICMPLEN)
return -1;
tn = icmpmsg[h->type];
if(tn == nil)
p = seprint(p, e, "t=%ud c=%d ck=%4.4ux", h->type,
h->code, (ushort)NetS(h->cksum));
else
p = seprint(p, e, "t=%s c=%d ck=%4.4ux", tn,
h->code, (ushort)NetS(h->cksum));
if(Cflag){
cksum = NetS(h->cksum);
h->cksum[0] = 0;
h->cksum[1] = 0;
cksum2 = ~ptclbsum((uchar*)h, m->pe - m->ps + ICMPLEN) & 0xffff;
if(cksum != cksum2)
p = seprint(p,e, " !ck=%4.4ux", cksum2);
}
switch(h->type){
case EchoRep:
case EchoReq:
m->ps += 4;
p = seprint(p, e, " id=%ux seq=%ux",
NetS(h->data), NetS(h->data+2));
break;
case TSreq:
case TSrep:
m->ps += 12;
p = seprint(p, e, " orig=%ud rcv=%ux xmt=%ux",
NetL(h->data), NetL(h->data+4),
NetL(h->data+8));
m->pr = nil;
break;
case InfoReq:
case InfoRep:
break;
case Unreachable:
case TimeExceed:
case SrcQuench:
m->ps += 4;
m->pr = &ip;
break;
case Redirect:
m->ps += 4;
m->pr = &ip;
p = seprint(p, e, "gw=%V", h->data);
break;
case ParamProb:
m->ps += 4;
m->pr = &ip;
p = seprint(p, e, "ptr=%2.2ux", h->data[0]);
break;
}
m->p = p;
return 0;
}
Proto icmp =
{
"icmp",
p_compile,
p_filter,
p_seprint,
p_mux,
p_fields,
defaultframer,
};

428
src/cmd/ip/snoopy/icmp6.c Executable file
View file

@ -0,0 +1,428 @@
#include <u.h>
#include <libc.h>
#include <ip.h>
#include "dat.h"
#include "protos.h"
typedef struct Hdr Hdr;
struct Hdr
{ uchar type;
uchar code;
uchar cksum[2]; /* Checksum */
uchar data[1];
};
enum
{
ICMP6LEN= 4,
};
enum
{
Ot, /* type */
Op, /* next protocol */};
static Field p_fields[] =
{
{"t", Fnum, Ot, "type", } ,
{0}
};
enum
{
// ICMPv6 types
EchoReply = 0,
UnreachableV6 = 1,
PacketTooBigV6 = 2,
TimeExceedV6 = 3,
ParamProblemV6 = 4,
Redirect = 5,
EchoRequest = 8,
TimeExceed = 11,
InParmProblem = 12,
Timestamp = 13,
TimestampReply = 14,
InfoRequest = 15,
InfoReply = 16,
AddrMaskRequest = 17,
AddrMaskReply = 18,
EchoRequestV6 = 128,
EchoReplyV6 = 129,
RouterSolicit = 133,
RouterAdvert = 134,
NbrSolicit = 135,
NbrAdvert = 136,
RedirectV6 = 137,
Maxtype6 = 137,
};
static Mux p_mux[] =
{
{"ip6", UnreachableV6, },
{"ip6", RedirectV6, },
{"ip6", TimeExceedV6, },
{0},
};
char *icmpmsg6[256] =
{
[EchoReply] "EchoReply",
[UnreachableV6] "UnreachableV6",
[PacketTooBigV6] "PacketTooBigV6",
[TimeExceedV6] "TimeExceedV6",
[Redirect] "Redirect",
[EchoRequest] "EchoRequest",
[TimeExceed] "TimeExceed",
[InParmProblem] "InParmProblem",
[Timestamp] "Timestamp",
[TimestampReply] "TimestampReply",
[InfoRequest] "InfoRequest",
[InfoReply] "InfoReply",
[AddrMaskRequest] "AddrMaskRequest",
[AddrMaskReply] "AddrMaskReply",
[EchoRequestV6] "EchoRequestV6",
[EchoReplyV6] "EchoReplyV6",
[RouterSolicit] "RouterSolicit",
[RouterAdvert] "RouterAdvert",
[NbrSolicit] "NbrSolicit",
[NbrAdvert] "NbrAdvert",
[RedirectV6] "RedirectV6",
};
static char *unreachcode[] =
{
[0] "no route to destination",
[1] "comm with destination administratively prohibited",
[2] "icmp unreachable: unassigned error code (2)",
[3] "address unreachable",
[4] "port unreachable",
[5] "icmp unreachable: unknown code",
};
static char *timexcode[] =
{
[0] "hop limit exc",
[1] "reassmbl time exc",
[2] "icmp time exc: unknown code",
};
static char *parpcode[] =
{
[0] "erroneous header field encountered",
[1] "unrecognized Next Header type encountered",
[2] "unrecognized IPv6 option encountered",
[3] "icmp par prob: unknown code",
};
enum
{
sll = 1,
tll = 2,
pref = 3,
redir = 4,
mtu = 5,
};
static char *icmp6opts[256] =
{
[0] "unknown opt",
[1] "sll_addr",
[2] "tll_addr",
[3] "pref_opt",
[4] "redirect",
[5] "mtu_opt",
};
static void
p_compile(Filter *f)
{
if(f->op == '='){
compile_cmp(icmp6.name, f, p_fields);
return;
}
if(strcmp(f->s, "ip6") == 0){
f->pr = p_mux->pr;
f->subop = Op;
return;
}
sysfatal("unknown icmp field or protocol: %s", f->s);
}
static int
p_filter(Filter *f, Msg *m)
{
Hdr *h;
if(m->pe - m->ps < ICMP6LEN)
return 0;
h = (Hdr*)m->ps;
m->ps += ICMP6LEN;
switch(f->subop){
case Ot:
if(h->type == f->ulv)
return 1;
break;
case Op:
switch(h->type){
case UnreachableV6:
case RedirectV6:
case TimeExceedV6:
m->ps += 4;
return 1;
}
}
return 0;
}
static char*
opt_seprint(Msg *m)
{
int otype, osz, pktsz;
uchar *a;
char *p = m->p;
char *e = m->e;
char *opt;
char optbuf[12];
pktsz = m->pe - m->ps;
a = m->ps;
while (pktsz > 0) {
otype = *a;
opt = icmp6opts[otype];
if(opt == nil){
sprint(optbuf, "0x%ux", otype);
opt = optbuf;
}
osz = (*(a+1)) * 8;
switch (otype) {
default:
p = seprint(p, e, "\n option=%s ", opt);
m->pr = &dump;
return p;
case sll:
case tll:
if ((pktsz < osz) || (osz != 8)) {
p = seprint(p, e, "\n option=%s bad size=%d", opt, osz);
m->pr = &dump;
return p;
}
p = seprint(p, e, "\n option=%s maddr=%E", opt, a+2);
pktsz -= osz;
a += osz;
break;
case pref:
if ((pktsz < osz) || (osz != 32)) {
p = seprint(p, e, "\n option=%s: bad size=%d", opt, osz);
m->pr = &dump;
return p;
}
p = seprint(p, e, "\n option=%s pref=%I preflen=%3.3d lflag=%1.1d aflag=%1.1d unused1=%1.1d validlt=%d preflt=%d unused2=%1.1d",
opt,
a+16,
(int) (*(a+2)),
(*(a+3) & (1 << 7))!=0,
(*(a+3) & (1 << 6))!=0,
(*(a+3) & 63) != 0,
NetL(a+4),
NetL(a+8),
NetL(a+12)!=0);
pktsz -= osz;
a += osz;
break;
case redir:
if (pktsz < osz) {
p = seprint(p, e, "\n option=%s: bad size=%d", opt, osz);
m->pr = &dump;
return p;
}
p = seprint(p, e, "\n option=%s len %d", opt, osz);
a += osz;
m->ps = a;
return p;
break;
case mtu:
if ((pktsz < osz) || (osz != 8)) {
p = seprint(p, e, "\n option=%s: bad size=%d", opt, osz);
m->pr = &dump;
return p;
}
p = seprint(p, e, "\n option=%s unused=%1.1d mtu=%d", opt, NetL(a+2)!=0, NetL(a+4));
pktsz -= osz;
a += osz;
break;
}
}
m->ps = a;
return p;
}
static int
p_seprint(Msg *m)
{
Hdr *h;
char *tn;
char *p = m->p;
char *e = m->e;
int i;
uchar *a;
// ushort cksum2, cksum;
h = (Hdr*)m->ps;
m->ps += ICMP6LEN;
m->pr = &dump;
a = m->ps;
if(m->pe - m->ps < ICMP6LEN)
return -1;
tn = icmpmsg6[h->type];
if(tn == nil)
p = seprint(p, e, "t=%ud c=%d ck=%4.4ux", h->type,
h->code, (ushort)NetS(h->cksum));
else
p = seprint(p, e, "t=%s c=%d ck=%4.4ux", tn,
h->code, (ushort)NetS(h->cksum));
/*
if(Cflag){
cksum = NetS(h->cksum);
h->cksum[0] = 0;
h->cksum[1] = 0;
cksum2 = ~ptclbsum((uchar*)h, m->pe - m->ps + ICMP6LEN) & 0xffff;
if(cksum != cksum2)
p = seprint(p,e, " !ck=%4.4ux", cksum2);
}
*/
switch(h->type){
case UnreachableV6:
m->ps += 4;
m->pr = &ip6;
if (h->code >= nelem(unreachcode))
i = nelem(unreachcode)-1;
else
i = h->code;
p = seprint(p, e, " code=%s unused=%1.1d ", unreachcode[i], NetL(a)!=0);
break;
case PacketTooBigV6:
m->ps += 4;
m->pr = &ip6;
p = seprint(p, e, " mtu=%4.4d ", NetL(a));
break;
case TimeExceedV6:
m->ps += 4;
m->pr = &ip6;
if (h->code >= nelem(timexcode))
i = nelem(timexcode)-1;
else
i = h->code;
p = seprint(p, e, " code=%s unused=%1.1d ", timexcode[i], NetL(a)!=0);
break;
case ParamProblemV6:
m->ps += 4;
m->pr = &ip6;
if (h->code > nelem(parpcode))
i = nelem(parpcode)-1;
else
i = h->code;
p = seprint(p, e, " code=%s ptr=%2.2ux", parpcode[i], h->data[0]);
break;
case EchoReplyV6:
case EchoRequestV6:
m->ps += 4;
p = seprint(p, e, " id=%ux seq=%ux",
NetS(h->data), NetS(h->data+2));
break;
case RouterSolicit:
m->ps += 4;
m->pr = nil;
m->p = seprint(p, e, " unused=%1.1d ", NetL(a)!=0);
p = opt_seprint(m);
break;
case RouterAdvert:
m->ps += 12;
m->pr = nil;
m->p = seprint(p, e, " hoplim=%3.3d mflag=%1.1d oflag=%1.1d unused=%1.1d routerlt=%8.8d reachtime=%d rxmtimer=%d",
(int) *a,
(*(a+1) & (1 << 7)) != 0,
(*(a+1) & (1 << 6)) != 0,
(*(a+1) & 63) != 0,
NetS(a+2),
NetL(a+4),
NetL(a+8));
p = opt_seprint(m);
break;
case NbrSolicit:
m->ps += 20;
m->pr = nil;
m->p = seprint(p, e, " unused=%1.1d targ %I", NetL(a)!=0, a+4);
p = opt_seprint(m);
break;
case NbrAdvert:
m->ps += 20;
m->pr = nil;
m->p = seprint(p, e, " rflag=%1.1d sflag=%1.1d oflag=%1.1d targ=%I",
(*a & (1 << 7)) != 0,
(*a & (1 << 6)) != 0,
(*a & (1 << 5)) != 0,
a+4);
p = opt_seprint(m);
break;
case RedirectV6:
m->ps += 36;
m->pr = &ip6;
m->p = seprint(p, e, " unused=%1.1d targ=%I dest=%I", NetL(a)!=0, a+4, a+20);
p = opt_seprint(m);
break;
case Timestamp:
case TimestampReply:
m->ps += 12;
p = seprint(p, e, " orig=%ud rcv=%ux xmt=%ux",
NetL(h->data), NetL(h->data+4),
NetL(h->data+8));
m->pr = nil;
break;
case InfoRequest:
case InfoReply:
break;
}
m->p = p;
return 0;
}
Proto icmp6 =
{
"icmp6",
p_compile,
p_filter,
p_seprint,
p_mux,
p_fields,
defaultframer,
};

146
src/cmd/ip/snoopy/il.c Executable file
View file

@ -0,0 +1,146 @@
#include <u.h>
#include <libc.h>
#include <ip.h>
#include "dat.h"
#include "protos.h"
typedef struct Hdr Hdr;
struct Hdr
{
uchar sum[2]; /* Checksum including header */
uchar len[2]; /* Packet length */
uchar type; /* Packet type */
uchar spec; /* Special */
uchar sport[2]; /* Src port */
uchar dport[2]; /* Dst port */
uchar id[4]; /* Sequence id */
uchar ack[4]; /* Acked sequence */
};
enum
{
ILLEN= 18,
};
enum
{
Os,
Od,
Osd,
};
static Field p_fields[] =
{
{"s", Fnum, Os, "source port", } ,
{"d", Fnum, Od, "dest port", } ,
{"a", Fnum, Osd, "source/dest port", } ,
{"sd", Fnum, Osd, "source/dest port", } ,
{0}
};
static Mux p_mux[] =
{
{"ninep", 17007, }, /* exportfs */
{"ninep", 17008, }, /* 9fs */
{"ninep", 17005, }, /* ocpu */
{"ninep", 17010, }, /* ncpu */
{"ninep", 17013, }, /* cpu */
{0},
};
static void
p_compile(Filter *f)
{
Mux *m;
if(f->op == '='){
compile_cmp(udp.name, f, p_fields);
return;
}
for(m = p_mux; m->name != nil; m++)
if(strcmp(f->s, m->name) == 0){
f->pr = m->pr;
f->ulv = m->val;
f->subop = Osd;
return;
}
sysfatal("unknown il field or protocol: %s", f->s);
}
static int
p_filter(Filter *f, Msg *m)
{
Hdr *h;
if(m->pe - m->ps < ILLEN)
return 0;
h = (Hdr*)m->ps;
m->ps += ILLEN;
switch(f->subop){
case Os:
return NetS(h->sport) == f->ulv;
case Od:
return NetS(h->dport) == f->ulv;
case Osd:
return NetS(h->sport) == f->ulv || NetS(h->dport) == f->ulv;
}
return 0;
}
char *pktnames[] =
{
"Sync",
"Data",
"Dataquery",
"Ack",
"Query",
"State",
"Close"
};
static char*
pkttype(int t)
{
static char b[10];
if(t > 6){
sprint(b, "%d", t);
return b;
}
return pktnames[t];
}
static int
p_seprint(Msg *m)
{
Hdr *h;
int dport, sport;
if(m->pe - m->ps < ILLEN)
return -1;
h = (Hdr*)m->ps;
m->ps += ILLEN;
dport = NetS(h->dport);
sport = NetS(h->sport);
demux(p_mux, sport, dport, m, &dump);
m->p = seprint(m->p, m->e, "s=%d d=%d t=%s id=%lud ack=%lud spec=%d ck=%4.4ux ln=%d",
sport, dport, pkttype(h->type),
(ulong)NetL(h->id), (ulong)NetL(h->ack),
h->spec,
NetS(h->sum), NetS(h->len));
return 0;
}
Proto il =
{
"il",
p_compile,
p_filter,
p_seprint,
p_mux,
p_fields,
defaultframer,
};

236
src/cmd/ip/snoopy/ip.c Executable file
View file

@ -0,0 +1,236 @@
#include <u.h>
#include <libc.h>
#include <ip.h>
#include "dat.h"
#include "protos.h"
typedef struct Hdr Hdr;
struct Hdr
{
uchar vihl; /* Version and header length */
uchar tos; /* Type of service */
uchar length[2]; /* packet length */
uchar id[2]; /* ip->identification */
uchar frag[2]; /* Fragment information */
uchar ttl; /* Time to live */
uchar proto; /* Protocol */
uchar cksum[2]; /* Header checksum */
uchar src[4]; /* IP source */
uchar dst[4]; /* IP destination */
};
enum
{
IPHDR = 20, /* sizeof(Iphdr) */
IP_VER = 0x40, /* Using IP version 4 */
IP_DF = 0x4000, /* Don't fragment */
IP_MF = 0x2000, /* More fragments */
};
static Mux p_mux[] =
{
{ "icmp", 1, },
{ "igmp", 2, },
{ "ggp", 3, },
{ "ip", 4, },
{ "st", 5, },
{ "tcp", 6, },
{ "ucl", 7, },
{ "egp", 8, },
{ "igp", 9, },
{ "bbn-rcc-mon", 10, },
{ "nvp-ii", 11, },
{ "pup", 12, },
{ "argus", 13, },
{ "emcon", 14, },
{ "xnet", 15, },
{ "chaos", 16, },
{ "udp", 17, },
{ "mux", 18, },
{ "dcn-meas", 19, },
{ "hmp", 20, },
{ "prm", 21, },
{ "xns-idp", 22, },
{ "trunk-1", 23, },
{ "trunk-2", 24, },
{ "leaf-1", 25, },
{ "leaf-2", 26, },
{ "rdp", 27, },
{ "irtp", 28, },
{ "iso-tp4", 29, },
{ "netblt", 30, },
{ "mfe-nsp", 31, },
{ "merit-inp", 32, },
{ "sep", 33, },
{ "3pc", 34, },
{ "idpr", 35, },
{ "xtp", 36, },
{ "ddp", 37, },
{ "idpr-cmtp", 38, },
{ "tp++", 39, },
{ "il", 40, },
{ "sip", 41, },
{ "sdrp", 42, },
{ "sip-sr", 43, },
{ "sip-frag", 44, },
{ "idrp", 45, },
{ "rsvp", 46, },
{ "gre", 47, },
{ "mhrp", 48, },
{ "bna", 49, },
{ "sipp-esp", 50, },
{ "sipp-ah", 51, },
{ "i-nlsp", 52, },
{ "swipe", 53, },
{ "nhrp", 54, },
{ "any", 61, },
{ "cftp", 62, },
{ "any", 63, },
{ "sat-expak", 64, },
{ "kryptolan", 65, },
{ "rvd", 66, },
{ "ippc", 67, },
{ "any", 68, },
{ "sat-mon", 69, },
{ "visa", 70, },
{ "ipcv", 71, },
{ "cpnx", 72, },
{ "cphb", 73, },
{ "wsn", 74, },
{ "pvp", 75, },
{ "br-sat-mon", 76, },
{ "sun-nd", 77, },
{ "wb-mon", 78, },
{ "wb-expak", 79, },
{ "iso-ip", 80, },
{ "vmtp", 81, },
{ "secure-vmtp", 82, },
{ "vines", 83, },
{ "ttp", 84, },
{ "nsfnet-igp", 85, },
{ "dgp", 86, },
{ "tcf", 87, },
{ "igrp", 88, },
{ "ospf", 89, },
{ "sprite-rpc", 90, },
{ "larp", 91, },
{ "mtp", 92, },
{ "ax.25", 93, },
{ "ipip", 94, },
{ "micp", 95, },
{ "scc-sp", 96, },
{ "etherip", 97, },
{ "encap", 98, },
{ "any", 99, },
{ "gmtp", 100, },
{ "rudp", 254, },
{ 0 }
};
enum
{
Os, // source
Od, // destination
Osd, // source or destination
Ot, // type
};
static Field p_fields[] =
{
{"s", Fv4ip, Os, "source address", } ,
{"d", Fv4ip, Od, "destination address", } ,
{"a", Fv4ip, Osd, "source|destination address",} ,
{"sd", Fv4ip, Osd, "source|destination address",} ,
{"t", Fnum, Ot, "sub protocol number", } ,
{0}
};
static void
p_compile(Filter *f)
{
Mux *m;
if(f->op == '='){
compile_cmp(ip.name, f, p_fields);
return;
}
for(m = p_mux; m->name != nil; m++)
if(strcmp(f->s, m->name) == 0){
f->pr = m->pr;
f->ulv = m->val;
f->subop = Ot;
return;
}
sysfatal("unknown ip field or protocol: %s", f->s);
}
static int
p_filter(Filter *f, Msg *m)
{
Hdr *h;
if(m->pe - m->ps < IPHDR)
return 0;
h = (Hdr*)m->ps;
m->ps += ((h->vihl&0xf)<<2);
switch(f->subop){
case Os:
return NetL(h->src) == f->ulv;
case Od:
return NetL(h->dst) == f->ulv;
case Osd:
return NetL(h->src) == f->ulv || NetL(h->dst) == f->ulv;
case Ot:
return h->proto == f->ulv;
}
return 0;
}
static int
p_seprint(Msg *m)
{
Hdr *h;
int f;
int len;
if(m->pe - m->ps < IPHDR)
return -1;
h = (Hdr*)m->ps;
/* next protocol, just dump unless this is the first fragment */
m->pr = &dump;
f = NetS(h->frag);
if((f & ~(IP_DF|IP_MF)) == 0)
demux(p_mux, h->proto, h->proto, m, &dump);
/* truncate the message if there's extra */
len = NetS(h->length);
if(len < m->pe - m->ps)
m->pe = m->ps + len;
/* next header */
m->ps += ((h->vihl&0xf)<<2);
m->p = seprint(m->p, m->e, "s=%V d=%V id=%4.4ux frag=%4.4ux ttl=%3d pr=%d ln=%d",
h->src, h->dst,
NetS(h->id),
NetS(h->frag),
h->ttl,
h->proto,
NetS(h->length)
);
return 0;
}
Proto ip =
{
"ip",
p_compile,
p_filter,
p_seprint,
p_mux,
p_fields,
defaultframer,
};

309
src/cmd/ip/snoopy/ip6.c Executable file
View file

@ -0,0 +1,309 @@
#include <u.h>
#include <libc.h>
#include <ip.h>
#include "dat.h"
#include "protos.h"
typedef struct Hdr Hdr;
struct Hdr
{
uchar vcf[4]; /* Version and header length */
uchar length[2]; /* packet length */
uchar proto; /* Protocol */
uchar ttl; /* Time to live */
uchar src[IPaddrlen]; /* IP source */
uchar dst[IPaddrlen]; /* IP destination */
};
enum
{
IP6HDR = 40, /* sizeof(Iphdr) */
IP_VER = 0x60, /* Using IP version 4 */
HBH_HDR = 0,
ROUT_HDR = 43,
FRAG_HDR = 44,
FRAG_HSZ = 8, /* in bytes */
DEST_HDR = 60,
};
static Mux p_mux[] =
{
{ "igmp", 2, },
{ "ggp", 3, },
{ "ip", 4, },
{ "st", 5, },
{ "tcp", 6, },
{ "ucl", 7, },
{ "egp", 8, },
{ "igp", 9, },
{ "bbn-rcc-mon", 10, },
{ "nvp-ii", 11, },
{ "pup", 12, },
{ "argus", 13, },
{ "emcon", 14, },
{ "xnet", 15, },
{ "chaos", 16, },
{ "udp", 17, },
{ "mux", 18, },
{ "dcn-meas", 19, },
{ "hmp", 20, },
{ "prm", 21, },
{ "xns-idp", 22, },
{ "trunk-1", 23, },
{ "trunk-2", 24, },
{ "leaf-1", 25, },
{ "leaf-2", 26, },
{ "rdp", 27, },
{ "irtp", 28, },
{ "iso-tp4", 29, },
{ "netblt", 30, },
{ "mfe-nsp", 31, },
{ "merit-inp", 32, },
{ "sep", 33, },
{ "3pc", 34, },
{ "idpr", 35, },
{ "xtp", 36, },
{ "ddp", 37, },
{ "idpr-cmtp", 38, },
{ "tp++", 39, },
{ "il", 40, },
{ "sip", 41, },
{ "sdrp", 42, },
{ "idrp", 45, },
{ "rsvp", 46, },
{ "gre", 47, },
{ "mhrp", 48, },
{ "bna", 49, },
{ "sipp-esp", 50, },
{ "sipp-ah", 51, },
{ "i-nlsp", 52, },
{ "swipe", 53, },
{ "nhrp", 54, },
{ "icmp6", 58, },
{ "any", 61, },
{ "cftp", 62, },
{ "any", 63, },
{ "sat-expak", 64, },
{ "kryptolan", 65, },
{ "rvd", 66, },
{ "ippc", 67, },
{ "any", 68, },
{ "sat-mon", 69, },
{ "visa", 70, },
{ "ipcv", 71, },
{ "cpnx", 72, },
{ "cphb", 73, },
{ "wsn", 74, },
{ "pvp", 75, },
{ "br-sat-mon", 76, },
{ "sun-nd", 77, },
{ "wb-mon", 78, },
{ "wb-expak", 79, },
{ "iso-ip", 80, },
{ "vmtp", 81, },
{ "secure-vmtp", 82, },
{ "vines", 83, },
{ "ttp", 84, },
{ "nsfnet-igp", 85, },
{ "dgp", 86, },
{ "tcf", 87, },
{ "igrp", 88, },
{ "ospf", 89, },
{ "sprite-rpc", 90, },
{ "larp", 91, },
{ "mtp", 92, },
{ "ax.25", 93, },
{ "ipip", 94, },
{ "micp", 95, },
{ "scc-sp", 96, },
{ "etherip", 97, },
{ "encap", 98, },
{ "any", 99, },
{ "gmtp", 100, },
{ "rudp", 254, },
{ 0 }
};
enum
{
Os, // source
Od, // destination
Osd, // source or destination
Ot, // type
};
static Field p_fields[] =
{
{"s", Fv6ip, Os, "source address", } ,
{"d", Fv6ip, Od, "destination address", } ,
{"a", Fv6ip, Osd, "source|destination address",} ,
{"t", Fnum, Ot, "sub protocol number", } ,
{0}
};
static void
p_compile(Filter *f)
{
Mux *m;
if(f->op == '='){
compile_cmp(ip6.name, f, p_fields);
return;
}
for(m = p_mux; m->name != nil; m++)
if(strcmp(f->s, m->name) == 0){
f->pr = m->pr;
f->ulv = m->val;
f->subop = Ot;
return;
}
sysfatal("unknown ip6 field or protocol: %s", f->s);
}
static int
v6hdrlen(Hdr *h)
{
int plen, len = IP6HDR;
int pktlen = IP6HDR + NetS(h->length);
uchar nexthdr = h->proto;
uchar *pkt = (uchar*) h;
pkt += len;
plen = len;
while ( (nexthdr == HBH_HDR) || (nexthdr == ROUT_HDR) ||
(nexthdr == FRAG_HDR) || (nexthdr == DEST_HDR) ) {
if (nexthdr == FRAG_HDR)
len = FRAG_HSZ;
else
len = ( ((int) *(pkt+1)) + 1) * 8;
if (plen + len > pktlen)
return -1;
pkt += len;
nexthdr = *pkt;
plen += len;
}
return plen;
}
static int
p_filter(Filter *f, Msg *m)
{
Hdr *h;
int hlen;
if(m->pe - m->ps < IP6HDR)
return 0;
h = (Hdr*)m->ps;
if ((hlen = v6hdrlen(h)) < 0)
return 0;
else
m->ps += hlen;
switch(f->subop){
case Os:
return !memcmp(h->src, f->a, IPaddrlen);
case Od:
return !memcmp(h->dst, f->a, IPaddrlen);
case Osd:
return !memcmp(h->src, f->a, IPaddrlen) || !memcmp(h->dst, f->a, IPaddrlen);
case Ot:
return h->proto == f->ulv;
}
return 0;
}
static int
v6hdr_seprint(Msg *m)
{
int len = IP6HDR;
uchar *pkt = m->ps;
Hdr *h = (Hdr *) pkt;
int pktlen = IP6HDR + NetS(h->length);
uchar nexthdr = h->proto;
int plen;
pkt += len;
plen = len;
while ( (nexthdr == HBH_HDR) || (nexthdr == ROUT_HDR) ||
(nexthdr == FRAG_HDR) || (nexthdr == DEST_HDR) ) {
switch (nexthdr) {
case FRAG_HDR:
m->p = seprint(m->p, m->e, "\n xthdr=frag id=%d offset=%d pr=%d more=%d res1=%d res2=%d",
NetL(pkt+4),
NetS(pkt+2) & ~7,
(int) (*pkt),
(int) (*(pkt+3) & 0x1),
(int) *(pkt+1),
(int) (*(pkt+3) & 0x6)
);
len = FRAG_HSZ;
break;
case HBH_HDR:
case ROUT_HDR:
case DEST_HDR:
len = ( ((int) *(pkt+1)) + 1) * 8;
break;
}
if (plen + len > pktlen) {
m->p = seprint(m->p, m->e, "bad pkt");
m->pr = &dump;
return -1;
}
plen += len;
pkt += len;
nexthdr = *pkt;
}
m->ps = pkt;
return 1;
}
static int
p_seprint(Msg *m)
{
Hdr *h;
int len;
if(m->pe - m->ps < IP6HDR)
return -1;
h = (Hdr*)m->ps;
demux(p_mux, h->proto, h->proto, m, &dump);
/* truncate the message if there's extra */
len = NetS(h->length) + IP6HDR;
if(len < m->pe - m->ps)
m->pe = m->ps + len;
m->p = seprint(m->p, m->e, "s=%I d=%I ttl=%3d pr=%d ln=%d",
h->src, h->dst,
h->ttl,
h->proto,
NetS(h->length)
);
v6hdr_seprint(m);
return 0;
}
Proto ip6 =
{
"ip6",
p_compile,
p_filter,
p_seprint,
p_mux,
p_fields,
defaultframer,
};

841
src/cmd/ip/snoopy/main.c Executable file
View file

@ -0,0 +1,841 @@
#include <u.h>
#include <libc.h>
#include <ip.h>
#include <bio.h>
#include <fcall.h>
#include <libsec.h>
#include "dat.h"
#include "protos.h"
#include "y.tab.h"
int Cflag;
int pflag;
int Nflag;
int sflag;
int tiflag;
int toflag;
char *prom = "promiscuous";
enum
{
Pktlen= 64*1024,
Blen= 16*1024,
};
Filter *filter;
Proto *root;
Biobuf out;
vlong starttime, pkttime;
int pcap;
int filterpkt(Filter *f, uchar *ps, uchar *pe, Proto *pr, int);
void printpkt(char *p, char *e, uchar *ps, uchar *pe);
void mkprotograph(void);
Proto* findproto(char *name);
Filter* compile(Filter *f);
void printfilter(Filter *f, char *tag);
void printhelp(void);
void tracepkt(uchar*, int);
void pcaphdr(void);
void
usage(void)
{
fprint(2, "usage: %s [-std?] [-c] [-N n] [-f filter] [-h first-header] path", argv0);
exits("usage");
}
void
main(int argc, char **argv)
{
uchar *pkt;
char *buf, *file, *p, *e;
int fd;
int n;
Binit(&out, 1, OWRITE);
fmtinstall('E', eipfmt);
fmtinstall('V', eipfmt);
fmtinstall('I', eipfmt);
fmtinstall('H', encodefmt);
fmtinstall('F', fcallfmt);
pkt = malloc(Pktlen+16);
pkt += 16;
buf = malloc(Blen);
e = buf+Blen-1;
pflag = 1;
Nflag = 32;
sflag = 0;
mkprotograph();
ARGBEGIN{
case '?':
printhelp();
exits(0);
break;
case 'N':
p = ARGF();
if(p == nil)
usage();
Nflag = atoi(p);
break;
case 'f':
p = ARGF();
if(p == nil)
usage();
yyinit(p);
yyparse();
break;
case 's':
sflag = 1;
break;
case 'h':
p = ARGF();
if(p == nil)
usage();
root = findproto(p);
if(root == nil)
sysfatal("unknown protocol: %s", p);
break;
case 'd':
toflag = 1;
break;
case 'D':
toflag = 1;
pcap = 1;
break;
case 't':
tiflag = 1;
break;
case 'C':
Cflag = 1;
break;
case 'p':
pflag = 0;
break;
}ARGEND;
if(pcap)
pcaphdr();
if(argc == 0)
file = nil;
else
file = argv[0];
if(tiflag){
fd = open(file, OREAD);
if(fd < 0)
sysfatal("opening %s: %r", file);
}else{
fd = opendevice(file, pflag);
if(fd < 0)
sysfatal("opening device %s: %r", file ? file : "(all)");
}
if(root == nil)
root = &ether;
filter = compile(filter);
if(tiflag){
/* read a trace file */
for(;;){
n = read(fd, pkt, 10);
if(n != 10)
break;
pkttime = NetL(pkt+2);
pkttime = (pkttime<<32) | NetL(pkt+6);
if(starttime == 0LL)
starttime = pkttime;
n = NetS(pkt);
if(readn(fd, pkt, n) != n)
break;
if(filterpkt(filter, pkt, pkt+n, root, 1))
if(toflag)
tracepkt(pkt, n);
else
printpkt(buf, e, pkt, pkt+n);
}
} else {
/* read a real time stream */
starttime = nsec();
for(;;){
n = root->framer(fd, pkt, Pktlen);
if(n <= 0)
break;
pkttime = nsec();
if(filterpkt(filter, pkt, pkt+n, root, 1))
if(toflag)
tracepkt(pkt, n);
else
printpkt(buf, e, pkt, pkt+n);
}
}
}
/* create a new filter node */
Filter*
newfilter(void)
{
Filter *f;
f = mallocz(sizeof(*f), 1);
if(f == nil)
sysfatal("newfilter: %r");
return f;
}
/*
* apply filter to packet
*/
int
_filterpkt(Filter *f, Msg *m)
{
Msg ma;
if(f == nil)
return 1;
switch(f->op){
case '!':
return !_filterpkt(f->l, m);
case LAND:
ma = *m;
return _filterpkt(f->l, &ma) && _filterpkt(f->r, m);
case LOR:
ma = *m;
return _filterpkt(f->l, &ma) || _filterpkt(f->r, m);
case WORD:
if(m->needroot){
if(m->pr != f->pr)
return 0;
m->needroot = 0;
}else{
if(m->pr != nil && !(m->pr->filter)(f, m))
return 0;
}
if(f->l == nil)
return 1;
m->pr = f->pr;
return _filterpkt(f->l, m);
}
sysfatal("internal error: filterpkt op: %d", f->op);
return 0;
}
int
filterpkt(Filter *f, uchar *ps, uchar *pe, Proto *pr, int needroot)
{
Msg m;
if(f == nil)
return 1;
m.needroot = needroot;
m.ps = ps;
m.pe = pe;
m.pr = pr;
return _filterpkt(f, &m);
}
/*
* from the Unix world
*/
#define PCAP_VERSION_MAJOR 2
#define PCAP_VERSION_MINOR 4
#define TCPDUMP_MAGIC 0xa1b2c3d4
struct pcap_file_header {
ulong magic;
ushort version_major;
ushort version_minor;
long thiszone; /* gmt to local correction */
ulong sigfigs; /* accuracy of timestamps */
ulong snaplen; /* max length saved portion of each pkt */
ulong linktype; /* data link type (DLT_*) */
};
struct pcap_pkthdr {
uvlong ts; /* time stamp */
ulong caplen; /* length of portion present */
ulong len; /* length this packet (off wire) */
};
/*
* pcap trace header
*/
void
pcaphdr(void)
{
struct pcap_file_header hdr;
hdr.magic = TCPDUMP_MAGIC;
hdr.version_major = PCAP_VERSION_MAJOR;
hdr.version_minor = PCAP_VERSION_MINOR;
hdr.thiszone = 0;
hdr.snaplen = 1500;
hdr.sigfigs = 0;
hdr.linktype = 1;
write(1, &hdr, sizeof(hdr));
}
/*
* write out a packet trace
*/
void
tracepkt(uchar *ps, int len)
{
struct pcap_pkthdr *goo;
if(pcap){
goo = (struct pcap_pkthdr*)(ps-16);
goo->ts = pkttime;
goo->caplen = len;
goo->len = len;
write(1, goo, len+16);
} else {
hnputs(ps-10, len);
hnputl(ps-8, pkttime>>32);
hnputl(ps-4, pkttime);
write(1, ps-10, len+10);
}
}
/*
* format and print a packet
*/
void
printpkt(char *p, char *e, uchar *ps, uchar *pe)
{
Msg m;
uvlong dt;
Tm tm;
tm = *localtime(pkttime/1000000000LL);
m.p = seprint(p, e, "%02d/%02d/%04d %02d:%02d:%02d.%09lld",
tm.mon+1, tm.mday, tm.year+1900, tm.hour, tm.min, tm.sec,
pkttime%1000000000LL);
m.ps = ps;
m.pe = pe;
m.e = e;
m.pr = root;
while(m.p < m.e){
if(!sflag)
m.p = seprint(m.p, m.e, "\n\t");
m.p = seprint(m.p, m.e, "%s(", m.pr->name);
if((*m.pr->seprint)(&m) < 0){
m.p = seprint(m.p, m.e, "TOO SHORT");
m.ps = m.pe;
}
m.p = seprint(m.p, m.e, ")");
if(m.pr == nil || m.ps >= m.pe)
break;
}
*m.p++ = '\n';
if(write(1, p, m.p - p) < 0)
sysfatal("stdout: %r");
}
Proto **xprotos;
int nprotos;
/* look up a protocol by its name */
Proto*
findproto(char *name)
{
int i;
for(i = 0; i < nprotos; i++)
if(strcmp(xprotos[i]->name, name) == 0)
return xprotos[i];
return nil;
}
/*
* add an undefined protocol to protos[]
*/
Proto*
addproto(char *name)
{
Proto *pr;
xprotos = realloc(xprotos, (nprotos+1)*sizeof(Proto*));
pr = malloc(sizeof *pr);
*pr = dump;
pr->name = name;
xprotos[nprotos++] = pr;
return pr;
}
/*
* build a graph of protocols, this could easily be circular. This
* links together all the multiplexing in the protocol modules.
*/
void
mkprotograph(void)
{
Proto **l;
Proto *pr;
Mux *m;
/* copy protos into a reallocable area */
for(nprotos = 0; protos[nprotos] != nil; nprotos++)
;
xprotos = malloc(nprotos*sizeof(Proto*));
memmove(xprotos, protos, nprotos*sizeof(Proto*));
for(l = protos; *l != nil; l++){
pr = *l;
for(m = pr->mux; m != nil && m->name != nil; m++){
m->pr = findproto(m->name);
if(m->pr == nil)
m->pr = addproto(m->name);
}
}
}
/*
* add in a protocol node
*/
static Filter*
addnode(Filter *f, Proto *pr)
{
Filter *nf;
nf = newfilter();
nf->pr = pr;
nf->s = pr->name;
nf->l = f;
nf->op = WORD;
return nf;
}
/*
* recurse through the protocol graph adding missing nodes
* to the filter if we reach the filter's protocol
*/
static Filter*
_fillin(Filter *f, Proto *last, int depth)
{
Mux *m;
Filter *nf;
if(depth-- <= 0)
return nil;
for(m = last->mux; m != nil && m->name != nil; m++){
if(m->pr == nil)
continue;
if(f->pr == m->pr)
return f;
nf = _fillin(f, m->pr, depth);
if(nf != nil)
return addnode(nf, m->pr);
}
return nil;
}
static Filter*
fillin(Filter *f, Proto *last)
{
int i;
Filter *nf;
/* hack to make sure top level node is the root */
if(last == nil){
if(f->pr == root)
return f;
f = fillin(f, root);
if(f == nil)
return nil;
return addnode(f, root);
}
/* breadth first search though the protocol graph */
nf = f;
for(i = 1; i < 20; i++){
nf = _fillin(f, last, i);
if(nf != nil)
break;
}
return nf;
}
/*
* massage tree so that all paths from the root to a leaf
* contain a filter node for each header.
*
* also, set f->pr where possible
*/
Filter*
complete(Filter *f, Proto *last)
{
Proto *pr;
if(f == nil)
return f;
/* do a depth first traversal of the filter tree */
switch(f->op){
case '!':
f->l = complete(f->l, last);
break;
case LAND:
case LOR:
f->l = complete(f->l, last);
f->r = complete(f->r, last);
break;
case '=':
break;
case WORD:
pr = findproto(f->s);
f->pr = pr;
if(pr == nil){
if(f->l != nil){
fprint(2, "%s unknown proto, ignoring params\n",
f->s);
f->l = nil;
}
} else {
f->l = complete(f->l, pr);
f = fillin(f, last);
if(f == nil)
sysfatal("internal error: can't get to %s", pr->name);
}
break;
}
return f;
}
/*
* merge common nodes under | and & moving the merged node
* above the | or &.
*
* do some constant foldong, e.g. `true & x' becomes x and
* 'true | x' becomes true.
*/
static int changed;
static Filter*
_optimize(Filter *f)
{
Filter *l;
if(f == nil)
return f;
switch(f->op){
case '!':
/* is child also a not */
if(f->l->op == '!'){
changed = 1;
return f->l->l;
}
break;
case LOR:
/* are two children the same protocol? */
if(f->l->op != f->r->op || f->r->op != WORD
|| f->l->pr != f->r->pr || f->l->pr == nil)
break; /* no optimization */
changed = 1;
/* constant folding */
/* if either child is childless, just return that */
if(f->l->l == nil)
return f->l;
else if(f->r->l == nil)
return f->r;
/* move the common node up, thow away one node */
l = f->l;
f->l = l->l;
f->r = f->r->l;
l->l = f;
return l;
case LAND:
/* are two children the same protocol? */
if(f->l->op != f->r->op || f->r->op != WORD
|| f->l->pr != f->r->pr || f->l->pr == nil)
break; /* no optimization */
changed = 1;
/* constant folding */
/* if either child is childless, ignore it */
if(f->l->l == nil)
return f->r;
else if(f->r->l == nil)
return f->l;
/* move the common node up, thow away one node */
l = f->l;
f->l = _optimize(l->l);
f->r = _optimize(f->r->l);
l->l = f;
return l;
}
f->l = _optimize(f->l);
f->r = _optimize(f->r);
return f;
}
Filter*
optimize(Filter *f)
{
do{
changed = 0;
f = _optimize(f);
}while(changed);
return f;
}
/*
* find any top level nodes that aren't the root
*/
int
findbogus(Filter *f)
{
int rv;
if(f->op != WORD){
rv = findbogus(f->l);
if(f->r)
rv |= findbogus(f->r);
return rv;
} else if(f->pr != root){
fprint(2, "bad top-level protocol: %s\n", f->s);
return 1;
}
return 0;
}
/*
* compile the filter
*/
static void
_compile(Filter *f, Proto *last)
{
if(f == nil)
return;
switch(f->op){
case '!':
_compile(f->l, last);
break;
case LOR:
case LAND:
_compile(f->l, last);
_compile(f->r, last);
break;
case WORD:
if(last != nil)
(*last->compile)(f);
if(f->l)
_compile(f->l, f->pr);
break;
case '=':
if(last == nil)
sysfatal("internal error: compilewalk: badly formed tree");
(*last->compile)(f);
break;
default:
sysfatal("internal error: compilewalk op: %d", f->op);
}
}
Filter*
compile(Filter *f)
{
if(f == nil)
return f;
/* fill in the missing header filters */
f = complete(f, nil);
/* constant folding */
f = optimize(f);
if(!toflag)
printfilter(f, "after optimize");
/* protocol specific compilations */
_compile(f, nil);
/* at this point, the root had better be the root proto */
if(findbogus(f)){
fprint(2, "bogus filter\n");
exits("bad filter");
}
return f;
}
/*
* parse a byte array
*/
int
parseba(uchar *to, char *from)
{
char nip[4];
char *p;
int i;
p = from;
for(i = 0; i < 16; i++){
if(*p == 0)
return -1;
nip[0] = *p++;
if(*p == 0)
return -1;
nip[1] = *p++;
nip[2] = 0;
to[i] = strtoul(nip, 0, 16);
}
return i;
}
/*
* compile WORD = WORD, becomes a single node with a subop
*/
void
compile_cmp(char *proto, Filter *f, Field *fld)
{
uchar x[IPaddrlen];
if(f->op != '=')
sysfatal("internal error: compile_cmp %s: not a cmp", proto);
for(; fld->name != nil; fld++){
if(strcmp(f->l->s, fld->name) == 0){
f->op = WORD;
f->subop = fld->subop;
switch(fld->ftype){
case Fnum:
f->ulv = atoi(f->r->s);
break;
case Fether:
parseether(f->a, f->r->s);
break;
case Fv4ip:
f->ulv = parseip(x, f->r->s);
break;
case Fv6ip:
parseip(f->a, f->r->s);
break;
case Fba:
parseba(f->a, f->r->s);
break;
default:
sysfatal("internal error: compile_cmp %s: %d",
proto, fld->ftype);
}
f->l = f->r = nil;
return;
}
}
sysfatal("unknown %s field in: %s = %s", proto, f->l->s, f->r->s);
}
void
_pf(Filter *f)
{
char *s;
if(f == nil)
return;
s = nil;
switch(f->op){
case '!':
fprint(2, "!");
_pf(f->l);
break;
case WORD:
fprint(2, "%s", f->s);
if(f->l != nil){
fprint(2, "( ");
_pf(f->l);
fprint(2, " )");
}
break;
case LAND:
s = "&&";
goto print;
case LOR:
s = "||";
goto print;
case '=':
print:
_pf(f->l);
if(s)
fprint(2, " %s ", s);
else
fprint(2, " %c ", f->op);
_pf(f->r);
break;
default:
fprint(2, "???");
break;
}
}
void
printfilter(Filter *f, char *tag)
{
fprint(2, "%s: ", tag);
_pf(f);
fprint(2, "\n");
}
void
printhelp(void)
{
Proto *pr, **l;
Mux *m;
Field *f;
for(l = protos; *l != nil; l++){
pr = *l;
if(pr->field != nil){
print("%s's filter attr:\n", pr->name);
for(f = pr->field; f->name != nil; f++)
print("\t%s\t- %s\n", f->name, f->help);
}
if(pr->mux != nil){
print("%s's subprotos:\n", pr->name);
for(m = pr->mux; m->name != nil; m++)
print("\t%s\n", m->name);
}
}
}
/*
* demultiplex to next prototol header
*/
void
demux(Mux *mx, ulong val1, ulong val2, Msg *m, Proto *def)
{
m->pr = def;
for(mx = mx; mx->name != nil; mx++){
if(val1 == mx->val || val2 == mx->val){
m->pr = mx->pr;
break;
}
}
}
/*
* default framer just assumes the input packet is
* a single read
*/
int
defaultframer(int fd, uchar *pkt, int pktlen)
{
return read(fd, pkt, pktlen);
}

69
src/cmd/ip/snoopy/mkfile Executable file
View file

@ -0,0 +1,69 @@
<$PLAN9/src/mkhdr
TARG=snoopy
PROTOS=\
ether\
ip\
ip6\
dump\
arp\
rarp\
udp\
bootp\
dhcp\
hdlc\
rtp\
rtcp\
tcp\
il\
icmp\
icmp6\
ninep\
ospf\
ppp\
ppp_ccp\
ppp_lcp\
ppp_chap\
ppp_ipcp\
pppoe_sess\
pppoe_disc\
POBJS=${PROTOS:%=%.$O}
OFILES= main.$O\
y.tab.$O\
protos.$O\
$SYSNAME.$O\
$POBJS
HFILES=dat.h\
protos.h\
y.tab.h\
<$PLAN9/src/mkone
protos.h: mkfile
(
for i in $PROTOS
do
echo extern Proto $i';'
done
) > protos.h
protos.c: mkfile
(
echo '#include <u.h>'
echo '#include <libc.h>'
echo '#include "dat.h"'
echo '#include "protos.h"'
echo 'Proto *protos[] ='
echo '{'
for i in $PROTOS
do
echo ' &'$i','
done
echo ' 0,'
echo '};'
) > protos.c
y.tab.c: filter.y

55
src/cmd/ip/snoopy/ninep.c Executable file
View file

@ -0,0 +1,55 @@
#include <u.h>
#include <libc.h>
#include <ip.h>
#include <fcall.h>
#include "dat.h"
#include "protos.h"
static void
p_compile(Filter *f)
{
sysfatal("unknown ninep field: %s", f->s);
}
static int
p_filter(Filter *f, Msg *m)
{
USED(f);
USED(m);
return 0;
}
static int
p_seprint(Msg *m)
{
Fcall f;
char *p;
memset(&f, 0, sizeof(f));
f.type = 0;
f.data = 0; /* protection for %F */
if(convM2S(m->ps, m->pe-m->ps, &f)){
p = m->p;
m->p = seprint(m->p, m->e, "%F", &f);
while(p < m->p){
p = strchr(p, '\n');
if(p == nil)
break;
*p = '\\';
}
} else
dump.seprint(m);
m->pr = nil;
return 0;
}
Proto ninep =
{
"ninep",
p_compile,
p_filter,
p_seprint,
nil,
nil,
defaultframer,
};

404
src/cmd/ip/snoopy/ospf.c Executable file
View file

@ -0,0 +1,404 @@
#include <u.h>
#include <libc.h>
#include <ip.h>
#include <libsec.h>
#include "dat.h"
#include "protos.h"
/*
* OSPF packets
*/
typedef struct Ospfpkt Ospfpkt;
struct Ospfpkt
{
uchar version;
uchar type;
uchar length[2];
uchar router[4];
uchar area[4];
uchar sum[2];
uchar autype[2];
uchar auth[8];
uchar data[1];
};
#define OSPF_HDRSIZE 24
enum
{
OSPFhello= 1,
OSPFdd= 2,
OSPFlsrequest= 3,
OSPFlsupdate= 4,
OSPFlsack= 5,
};
char *ospftype[] = {
[OSPFhello] "hello",
[OSPFdd] "data definition",
[OSPFlsrequest] "link state request",
[OSPFlsupdate] "link state update",
[OSPFlsack] "link state ack",
};
char*
ospfpkttype(int x)
{
static char type[16];
if(x > 0 && x <= OSPFlsack)
return ospftype[x];
sprint(type, "type %d", x);
return type;
}
char*
ospfauth(Ospfpkt *ospf)
{
static char auth[100];
switch(ospf->type){
case 0:
return "no authentication";
case 1:
sprint(auth, "password(%8.8ux %8.8ux)", NetL(ospf->auth),
NetL(ospf->auth+4));
break;
case 2:
sprint(auth, "crypto(plen %d id %d dlen %d)", NetS(ospf->auth),
ospf->auth[2], ospf->auth[3]);
break;
default:
sprint(auth, "auth%d(%8.8ux %8.8ux)", NetS(ospf->autype), NetL(ospf->auth),
NetL(ospf->auth+4));
}
return auth;
}
typedef struct Ospfhello Ospfhello;
struct Ospfhello
{
uchar mask[4];
uchar interval[2];
uchar options;
uchar pri;
uchar deadint[4];
uchar designated[4];
uchar bdesignated[4];
uchar neighbor[1];
};
char*
seprintospfhello(char *p, char *e, void *a, int x)
{
Ospfhello *h = a;
USED(x);
return seprint(p, e, "%s(mask %V interval %d opt %ux pri %ux deadt %d designated %V bdesignated %V)",
ospftype[OSPFhello],
h->mask, NetS(h->interval), h->options, h->pri,
NetL(h->deadint), h->designated, h->bdesignated);
}
enum
{
LSARouter= 1,
LSANetwork= 2,
LSASummN= 3,
LSASummR= 4,
LSAASext= 5
};
char *lsatype[] = {
[LSARouter] "Router LSA",
[LSANetwork] "Network LSA",
[LSASummN] "Summary LSA (Network)",
[LSASummR] "Summary LSA (Router)",
[LSAASext] "LSA AS external",
};
char*
lsapkttype(int x)
{
static char type[16];
if(x > 0 && x <= LSAASext)
return lsatype[x];
sprint(type, "type %d", x);
return type;
}
/* OSPF Link State Advertisement Header */
/* rfc2178 section 12.1 */
/* data of Ospfpkt point to a 4-uchar value that is the # of LSAs */
struct OspfLSAhdr {
uchar lsage[2];
uchar options; /* 0x2=stub area, 0x1=TOS routing capable */
uchar lstype; /* 1=Router-LSAs
* 2=Network-LSAs
* 3=Summary-LSAs (to network)
* 4=Summary-LSAs (to AS boundary routers)
* 5=AS-External-LSAs
*/
uchar lsid[4];
uchar advtrt[4];
uchar lsseqno[4];
uchar lscksum[2];
uchar lsalen[2]; /* includes the 20 byte lsa header */
};
struct Ospfrt {
uchar linkid[4];
uchar linkdata[4];
uchar typ;
uchar numtos;
uchar metric[2];
};
struct OspfrtLSA {
struct OspfLSAhdr hdr;
uchar netmask[4];
};
struct OspfntLSA {
struct OspfLSAhdr hdr;
uchar netmask[4];
uchar attrt[4];
};
/* Summary Link State Advertisement info */
struct Ospfsumm {
uchar flag; /* always zero */
uchar metric[3];
};
struct OspfsummLSA {
struct OspfLSAhdr hdr;
uchar netmask[4];
struct Ospfsumm lsa;
};
/* AS external Link State Advertisement info */
struct OspfASext {
uchar flag; /* external */
uchar metric[3];
uchar fwdaddr[4];
uchar exrttag[4];
};
struct OspfASextLSA {
struct OspfLSAhdr hdr;
uchar netmask[4];
struct OspfASext lsa;
};
/* OSPF Link State Update Packet */
struct OspfLSupdpkt {
uchar lsacnt[4];
union {
uchar hdr[1];
struct OspfrtLSA rt[1];
struct OspfntLSA nt[1];
struct OspfsummLSA sum[1];
struct OspfASextLSA as[1];
};
};
char*
seprintospflsaheader(char *p, char *e, struct OspfLSAhdr *h)
{
return seprint(p, e, "age %d opt %ux type %ux lsid %V adv_rt %V seqno %ux c %4.4ux l %d",
NetS(h->lsage), h->options&0xff, h->lstype,
h->lsid, h->advtrt, NetL(h->lsseqno), NetS(h->lscksum),
NetS(h->lsalen));
}
/* OSPF Database Description Packet */
struct OspfDDpkt {
uchar intMTU[2];
uchar options;
uchar bits;
uchar DDseqno[4];
struct OspfLSAhdr hdr[1]; /* LSA headers... */
};
char*
seprintospfdatadesc(char *p, char *e, void *a, int len)
{
int nlsa, i;
struct OspfDDpkt *g;
g = (struct OspfDDpkt *)a;
nlsa = len/sizeof(struct OspfLSAhdr);
for (i=0; i<nlsa; i++) {
p = seprint(p, e, "lsa%d(", i);
p = seprintospflsaheader(p, e, &(g->hdr[i]));
p = seprint(p, e, ")");
}
return seprint(p, e, ")");
}
char*
seprintospflsupdate(char *p, char *e, void *a, int len)
{
int nlsa, i;
struct OspfLSupdpkt *g;
struct OspfLSAhdr *h;
g = (struct OspfLSupdpkt *)a;
nlsa = NetL(g->lsacnt);
h = (struct OspfLSAhdr *)(g->hdr);
p = seprint(p, e, "%d-%s(", nlsa, ospfpkttype(OSPFlsupdate));
switch(h->lstype) {
case LSARouter:
{
/* struct OspfrtLSA *h;
*/
}
break;
case LSANetwork:
{
struct OspfntLSA *h;
for (i=0; i<nlsa; i++) {
h = &(g->nt[i]);
p = seprint(p, e, "lsa%d(", i);
p = seprintospflsaheader(p, e, &(h->hdr));
p = seprint(p, e, " mask %V attrt %V)",
h->netmask, h->attrt);
}
}
break;
case LSASummN:
case LSASummR:
{
struct OspfsummLSA *h;
for (i=0; i<nlsa; i++) {
h = &(g->sum[i]);
p = seprint(p, e, "lsa%d(", i);
p = seprintospflsaheader(p, e, &(h->hdr));
p = seprint(p, e, " mask %V met %d)",
h->netmask, Net3(h->lsa.metric));
}
}
break;
case LSAASext:
{
struct OspfASextLSA *h;
for (i=0; i<nlsa; i++) {
h = &(g->as[i]);
p = seprint(p, e, " lsa%d(", i);
p = seprintospflsaheader(p, e, &(h->hdr));
p = seprint(p, e, " mask %V extflg %1.1ux met %d fwdaddr %V extrtflg %ux)",
h->netmask, h->lsa.flag, Net3(h->lsa.metric),
h->lsa.fwdaddr, NetL(h->lsa.exrttag));
}
}
break;
default:
p = seprint(p, e, "Not an LS update, lstype %d ", h->lstype);
p = seprint(p, e, " %.*H", len>64?64:len, a);
break;
}
return seprint(p, e, ")");
}
char*
seprintospflsack(char *p, char *e, void *a, int len)
{
int nlsa, i;
struct OspfLSAhdr *h;
h = (struct OspfLSAhdr *)a;
nlsa = len/sizeof(struct OspfLSAhdr);
p = seprint(p, e, "%d-%s(", nlsa, ospfpkttype(OSPFlsack));
for (i=0; i<nlsa; i++) {
p = seprint(p, e, " lsa%d(", i);
p = seprintospflsaheader(p, e, &(h[i]));
p = seprint(p, e, ")");
}
return seprint(p, e, ")");
}
static void
p_compile(Filter *f)
{
sysfatal("unknown ospf field: %s", f->s);
}
static int
p_filter(Filter *f, Msg *m)
{
USED(f);
USED(m);
return 0;
}
int
p_seprint(Msg *m)
{
Ospfpkt *ospf;
int len, x;
char *p, *e;
len = m->pe - m->ps;
if(len < OSPF_HDRSIZE)
return -1;
p = m->p;
e = m->e;
/* adjust packet size */
ospf = (Ospfpkt*)m->ps;
x = NetS(ospf->length);
if(x < len)
return -1;
x -= OSPF_HDRSIZE;
p = seprint(p, e, "ver=%d type=%d len=%d r=%V a=%V c=%4.4ux %s ",
ospf->version, ospf->type, x,
ospf->router, ospf->area, NetS(ospf->sum),
ospfauth(ospf));
switch (ospf->type) {
case OSPFhello:
p = seprintospfhello(p, e, ospf->data, x);
break;
case OSPFdd:
p = seprintospfdatadesc(p, e, ospf->data, x);
break;
case OSPFlsrequest:
p = seprint(p, e, " %s->", ospfpkttype(ospf->type));
goto Default;
case OSPFlsupdate:
p = seprintospflsupdate(p, e, ospf->data, x);
break;
case OSPFlsack:
p = seprintospflsack(p, e, ospf->data, x);
break;
default:
Default:
p = seprint(p, e, " data=%.*H", x>64?64:x, ospf->data);
}
m->p = p;
m->pr = nil;
return 0;
}
Proto ospf =
{
"ospf",
p_compile,
p_filter,
p_seprint,
nil,
nil,
defaultframer,
};

629
src/cmd/ip/snoopy/ppp.c Executable file
View file

@ -0,0 +1,629 @@
#include <u.h>
#include <libc.h>
#include <ip.h>
#include <libsec.h>
#include "dat.h"
#include "protos.h"
/* PPP stuff */
enum {
PPP_addr= 0xff,
PPP_ctl= 0x3,
PPP_period= 3*1000, /* period of retransmit process (in ms) */
};
/* PPP protocols */
enum {
PPP_ip= 0x21, /* internet */
PPP_vjctcp= 0x2d, /* compressing van jacobson tcp */
PPP_vjutcp= 0x2f, /* uncompressing van jacobson tcp */
PPP_ml= 0x3d, /* multi link */
PPP_comp= 0xfd, /* compressed packets */
PPP_ipcp= 0x8021, /* ip control */
PPP_ccp= 0x80fd, /* compression control */
PPP_passwd= 0xc023, /* passwd authentication */
PPP_lcp= 0xc021, /* link control */
PPP_lqm= 0xc025, /* link quality monitoring */
PPP_chap= 0xc223, /* challenge/response */
};
/* LCP protocol (and IPCP) */
typedef struct Lcppkt Lcppkt;
struct Lcppkt
{
uchar code;
uchar id;
uchar len[2];
uchar data[1];
};
typedef struct Lcpopt Lcpopt;
struct Lcpopt
{
uchar type;
uchar len;
uchar data[1];
};
enum
{
/* LCP codes */
Lconfreq= 1,
Lconfack= 2,
Lconfnak= 3,
Lconfrej= 4,
Ltermreq= 5,
Ltermack= 6,
Lcoderej= 7,
Lprotorej= 8,
Lechoreq= 9,
Lechoack= 10,
Ldiscard= 11,
Lresetreq= 14, /* for ccp only */
Lresetack= 15, /* for ccp only */
/* Lcp configure options */
Omtu= 1,
Octlmap= 2,
Oauth= 3,
Oquality= 4,
Omagic= 5,
Opc= 7,
Oac= 8,
/* authentication protocols */
APmd5= 5,
APmschap= 128,
/* Chap codes */
Cchallenge= 1,
Cresponse= 2,
Csuccess= 3,
Cfailure= 4,
/* ipcp configure options */
Oipaddrs= 1,
Oipcompress= 2,
Oipaddr= 3,
Oipdns= 129,
Oipwins= 130,
Oipdns2= 131,
Oipwins2= 132,
};
char *
lcpcode[] = {
0,
"confreq",
"confack",
"confnak",
"confrej",
"termreq",
"termack",
"coderej",
"protorej",
"echoreq",
"echoack",
"discard",
"id",
"timeremain",
"resetreq",
"resetack",
};
static Mux p_mux[] =
{
{"ip", PPP_ip, },
{"ppp_vjctcp", PPP_vjctcp, },
{"ppp_vjutcp", PPP_vjutcp, },
{"ppp_ml", PPP_ml, },
{"ppp_comp", PPP_comp, },
{"ppp_ipcp", PPP_ipcp, },
{"ppp_ccp", PPP_ccp, },
{"ppp_passwd", PPP_passwd, },
{"ppp_lcp", PPP_lcp, },
{"ppp_lqm", PPP_lqm, },
{"ppp_chap", PPP_chap, },
{0},
};
enum
{
OOproto,
};
static void
p_compile(Filter *f)
{
Mux *m;
for(m = p_mux; m->name != nil; m++)
if(strcmp(f->s, m->name) == 0){
f->pr = m->pr;
f->ulv = m->val;
f->subop = OOproto;
return;
}
sysfatal("unknown ppp field or protocol: %s", f->s);
}
static int
p_filter(Filter *f, Msg *m)
{
int proto;
int len;
if(f->subop != OOproto)
return 0;
len = m->pe - m->ps;
if(len < 3)
return -1;
if(m->ps[0] == PPP_addr && m->ps[1] == PPP_ctl)
m->ps += 2;
proto = *m->ps++;
if((proto&1) == 0)
proto = (proto<<8) | *m->ps++;
if(proto == f->ulv)
return 1;
return 0;
}
static int
p_seprint(Msg *m)
{
int proto;
int len;
len = m->pe - m->ps;
if(len < 3)
return -1;
if(m->ps[0] == PPP_addr && m->ps[1] == PPP_ctl)
m->ps += 2;
proto = *m->ps++;
if((proto&1) == 0)
proto = (proto<<8) | *m->ps++;
m->p = seprint(m->p, m->e, "pr=%ud len=%d", proto, len);
demux(p_mux, proto, proto, m, &dump);
return 0;
}
static int
p_seprintchap(Msg *m)
{
Lcppkt *lcp;
char *p, *e;
int len;
if(m->pe-m->ps < 4)
return -1;
p = m->p;
e = m->e;
m->pr = nil;
/* resize packet */
lcp = (Lcppkt*)m->ps;
len = NetS(lcp->len);
if(m->ps+len < m->pe)
m->pe = m->ps+len;
else if(m->ps+len > m->pe)
return -1;
p = seprint(p, e, "id=%d code=%d", lcp->id, lcp->code);
switch(lcp->code) {
default:
p = seprint(p, e, " data=%.*H", len>64?64:len, lcp->data);
break;
case 1:
case 2:
if(lcp->data[0] > len-4){
p = seprint(p, e, "%.*H", len-4, lcp->data);
} else {
p = seprint(p, e, " %s=", lcp->code==1?"challenge ":"response ");
p = seprint(p, e, "%.*H", lcp->data[0], lcp->data+1);
p = seprint(p, e, " name=");
p = seprint(p, e, "%.*H", len-4-lcp->data[0]-1, lcp->data+lcp->data[0]+1);
}
break;
case 3:
case 4:
if(len > 64)
len = 64;
p = seprint(p, e, " %s=%.*H", lcp->code==3?"success ":"failure",
len>64?64:len, lcp->data);
break;
}
m->p = seprint(p, e, " len=%d", len);
return 0;
}
static char*
seprintlcpopt(char *p, char *e, void *a, int len)
{
Lcpopt *o;
int proto, x, period;
uchar *cp, *ecp;
cp = a;
ecp = cp+len;
for(; cp < ecp; cp += o->len){
o = (Lcpopt*)cp;
if(cp + o->len > ecp || o->len == 0){
p = seprint(p, e, " bad-opt-len=%d", o->len);
return p;
}
switch(o->type){
default:
p = seprint(p, e, " (type=%d len=%d)", o->type, o->len);
break;
case Omtu:
p = seprint(p, e, " mtu=%d", NetS(o->data));
break;
case Octlmap:
p = seprint(p, e, " ctlmap=%ux", NetL(o->data));
break;
case Oauth:
proto = NetS(o->data);
switch(proto) {
default:
p = seprint(p, e, " auth=%d", proto);
break;
case PPP_passwd:
p = seprint(p, e, " auth=passwd");
break;
case PPP_chap:
p = seprint(p, e, " (auth=chap data=%2.2ux)", o->data[2]);
break;
}
break;
case Oquality:
proto = NetS(o->data);
switch(proto) {
default:
p = seprint(p, e, " qproto=%d", proto);
break;
case PPP_lqm:
x = NetL(o->data+2)*10;
period = (x+(PPP_period-1))/PPP_period;
p = seprint(p, e, " (qproto=lqm period=%d)", period);
break;
}
case Omagic:
p = seprint(p, e, " magic=%ux", NetL(o->data));
break;
case Opc:
p = seprint(p, e, " protocol-compress");
break;
case Oac:
p = seprint(p, e, " addr-compress");
break;
}
}
return p;
}
static int
p_seprintlcp(Msg *m)
{
Lcppkt *lcp;
char *p, *e;
int len;
if(m->pe-m->ps < 4)
return -1;
p = m->p;
e = m->e;
m->pr = nil;
lcp = (Lcppkt*)m->ps;
len = NetS(lcp->len);
if(m->ps+len < m->pe)
m->pe = m->ps+len;
else if(m->ps+len > m->pe)
return -1;
p = seprint(p, e, "id=%d code=%d", lcp->id, lcp->code);
switch(lcp->code) {
default:
p = seprint(p, e, " data=%.*H", len>64?64:len, lcp->data);
break;
case Lconfreq:
case Lconfack:
case Lconfnak:
case Lconfrej:
p = seprint(p, e, "=%s", lcpcode[lcp->code]);
p = seprintlcpopt(p, e, lcp->data, len-4);
break;
case Ltermreq:
case Ltermack:
case Lcoderej:
case Lprotorej:
case Lechoreq:
case Lechoack:
case Ldiscard:
p = seprint(p, e, "=%s", lcpcode[lcp->code]);
break;
}
m->p = seprint(p, e, " len=%d", len);
return 0;
}
static char*
seprintipcpopt(char *p, char *e, void *a, int len)
{
Lcpopt *o;
uchar *cp, *ecp;
cp = a;
ecp = cp+len;
for(; cp < ecp; cp += o->len){
o = (Lcpopt*)cp;
if(cp + o->len > ecp){
p = seprint(p, e, " bad opt len %ux", o->type);
return p;
}
switch(o->type){
default:
p = seprint(p, e, " (type=%d len=%d)", o->type, o->len);
break;
case Oipaddrs:
p = seprint(p, e, " ipaddrs(deprecated)");
break;
case Oipcompress:
p = seprint(p, e, " ipcompress");
break;
case Oipaddr:
p = seprint(p, e, " ipaddr=%V", o->data);
break;
case Oipdns:
p = seprint(p, e, " dnsaddr=%V", o->data);
break;
case Oipwins:
p = seprint(p, e, " winsaddr=%V", o->data);
break;
case Oipdns2:
p = seprint(p, e, " dns2addr=%V", o->data);
break;
case Oipwins2:
p = seprint(p, e, " wins2addr=%V", o->data);
break;
}
}
return p;
}
static int
p_seprintipcp(Msg *m)
{
Lcppkt *lcp;
char *p, *e;
int len;
if(m->pe-m->ps < 4)
return -1;
p = m->p;
e = m->e;
m->pr = nil;
lcp = (Lcppkt*)m->ps;
len = NetS(lcp->len);
if(m->ps+len < m->pe)
m->pe = m->ps+len;
else if(m->ps+len > m->pe)
return -1;
p = seprint(p, e, "id=%d code=%d", lcp->id, lcp->code);
switch(lcp->code) {
default:
p = seprint(p, e, " data=%.*H", len>64?64:len, lcp->data);
break;
case Lconfreq:
case Lconfack:
case Lconfnak:
case Lconfrej:
p = seprint(p, e, "=%s", lcpcode[lcp->code]);
p = seprintipcpopt(p, e, lcp->data, len-4);
break;
case Ltermreq:
case Ltermack:
p = seprint(p, e, "=%s", lcpcode[lcp->code]);
break;
}
m->p = seprint(p, e, " len=%d", len);
return 0;
}
static char*
seprintccpopt(char *p, char *e, void *a, int len)
{
Lcpopt *o;
uchar *cp, *ecp;
cp = a;
ecp = cp+len;
for(; cp < ecp; cp += o->len){
o = (Lcpopt*)cp;
if(cp + o->len > ecp){
p = seprint(p, e, " bad opt len %ux", o->type);
return p;
}
switch(o->type){
default:
p = seprint(p, e, " type=%d ", o->type);
break;
case 0:
p = seprint(p, e, " OUI=(%d %.2ux%.2ux%.2ux) ", o->type,
o->data[0], o->data[1], o->data[2]);
break;
case 17:
p = seprint(p, e, " Stac-LZS");
break;
case 18:
p = seprint(p, e, " Microsoft-PPC=%ux", NetL(o->data));
break;
}
}
return p;
}
static int
p_seprintccp(Msg *m)
{
Lcppkt *lcp;
char *p, *e;
int len;
if(m->pe-m->ps < 4)
return -1;
p = m->p;
e = m->e;
m->pr = nil;
lcp = (Lcppkt*)m->ps;
len = NetS(lcp->len);
if(m->ps+len < m->pe)
m->pe = m->ps+len;
else if(m->ps+len > m->pe)
return -1;
p = seprint(p, e, "id=%d code=%d", lcp->id, lcp->code);
switch(lcp->code) {
default:
p = seprint(p, e, " data=%.*H", len>64?64:len, lcp->data);
break;
case Lconfreq:
case Lconfack:
case Lconfnak:
case Lconfrej:
p = seprint(p, e, "=%s", lcpcode[lcp->code]);
p = seprintccpopt(p, e, lcp->data, len-4);
break;
case Ltermreq:
case Ltermack:
case Lresetreq:
case Lresetack:
p = seprint(p, e, "=%s", lcpcode[lcp->code]);
break;
}
m->p = seprint(p, e, " len=%d", len);
return 0;
}
static int
p_seprintcomp(Msg *m)
{
char compflag[5];
ushort x;
int i;
int len;
len = m->pe-m->ps;
if(len < 2)
return -1;
x = NetS(m->ps);
m->ps += 2;
i = 0;
if(x & (1<<15))
compflag[i++] = 'r';
if(x & (1<<14))
compflag[i++] = 'f';
if(x & (1<<13))
compflag[i++] = 'c';
if(x & (1<<12))
compflag[i++] = 'e';
compflag[i] = 0;
m->p = seprint(m->p, m->e, "flag=%s count=%.3ux", compflag, x&0xfff);
m->p = seprint(m->p, m->e, " data=%.*H", len>64?64:len, m->ps);
m->pr = nil;
return 0;
}
Proto ppp =
{
"ppp",
p_compile,
p_filter,
p_seprint,
p_mux,
nil,
defaultframer,
};
Proto ppp_ipcp =
{
"ppp_ipcp",
p_compile,
p_filter,
p_seprintipcp,
nil,
nil,
defaultframer,
};
Proto ppp_lcp =
{
"ppp_lcp",
p_compile,
p_filter,
p_seprintlcp,
nil,
nil,
defaultframer,
};
Proto ppp_ccp =
{
"ppp_ccp",
p_compile,
p_filter,
p_seprintccp,
nil,
nil,
defaultframer,
};
Proto ppp_chap =
{
"ppp_chap",
p_compile,
p_filter,
p_seprintchap,
nil,
nil,
defaultframer,
};
Proto ppp_comp =
{
"ppp_comp",
p_compile,
p_filter,
p_seprintcomp,
nil,
nil,
defaultframer,
};

1
src/cmd/ip/snoopy/ppp_ccp.c Executable file
View file

@ -0,0 +1 @@
/* place holder, this stuff is really in ppp.c */

1
src/cmd/ip/snoopy/ppp_chap.c Executable file
View file

@ -0,0 +1 @@
/* place holder, this stuff is really in ppp.c */

1
src/cmd/ip/snoopy/ppp_comp.c Executable file
View file

@ -0,0 +1 @@
/* place holder, this stuff is really in ppp.c */

1
src/cmd/ip/snoopy/ppp_ipcp.c Executable file
View file

@ -0,0 +1 @@
/* place holder, this stuff is really in ppp.c */

1
src/cmd/ip/snoopy/ppp_lcp.c Executable file
View file

@ -0,0 +1 @@
/* place holder, this stuff is really in ppp.c */

172
src/cmd/ip/snoopy/pppoe_disc.c Executable file
View file

@ -0,0 +1,172 @@
#include <u.h>
#include <libc.h>
#include <ip.h>
#include "dat.h"
#include "protos.h"
typedef struct Hdr Hdr;
struct Hdr {
uchar verstype;
uchar code;
uchar sessid[2];
uchar length[2]; /* of payload */
};
enum
{
HDRSIZE = 1+1+2+2
};
static Mux p_mux[] =
{
{"ppp", 0, } ,
{0}
};
enum
{
Overs,
Otype,
Ocode,
Osess,
};
static Field p_fields[] =
{
{"v", Fnum, Overs, "version", } ,
{"t", Fnum, Otype, "type", } ,
{"c", Fnum, Ocode, "code" } ,
{"s", Fnum, Osess, "sessid" } ,
{0}
};
static void
p_compilesess(Filter *f)
{
// Mux *m;
if(f->op == '='){
compile_cmp(pppoe_sess.name, f, p_fields);
return;
}
/*
for(m = p_mux; m->name != nil; m++)
if(strcmp(f->s, m->name) == 0){
f->pr = m->pr;
f->ulv = m->val;
f->subop = Ot;
return;
}
*/
sysfatal("unknown pppoe field or protocol: %s", f->s);
}
static void
p_compiledisc(Filter *f)
{
// Mux *m;
if(f->op == '='){
compile_cmp(pppoe_disc.name, f, p_fields);
return;
}
/*
for(m = p_mux; m->name != nil; m++)
if(strcmp(f->s, m->name) == 0){
f->pr = m->pr;
f->ulv = m->val;
f->subop = Ot;
return;
}
*/
sysfatal("unknown pppoe field or protocol: %s", f->s);
}
static int
p_filter(Filter *f, Msg *m)
{
Hdr *h;
if(m->pe - m->ps < HDRSIZE)
return 0;
h = (Hdr*)m->ps;
m->ps += HDRSIZE;
switch(f->subop){
case Overs:
return (h->verstype>>4) == f->ulv;
case Otype:
return (h->verstype&0xF) == f->ulv;
case Ocode:
return h->code == f->ulv;
case Osess:
return NetS(h->sessid) == f->ulv;
}
return 0;
}
/* BUG: print all the discovery types */
static int
p_seprintdisc(Msg *m)
{
Hdr *h;
int len;
len = m->pe - m->ps;
if(len < HDRSIZE)
return -1;
h = (Hdr*)m->ps;
m->ps += HDRSIZE;
m->pr = nil;
m->p = seprint(m->p, m->e, "v=%d t=%d c=0x%x s=0x%ux, len=%d",
h->verstype>>4, h->verstype&0xF, h->code, NetS(h->sessid), NetS(h->length));
return 0;
}
static int
p_seprintsess(Msg *m)
{
Hdr *h;
int len;
len = m->pe - m->ps;
if(len < HDRSIZE)
return -1;
h = (Hdr*)m->ps;
m->ps += HDRSIZE;
/* this will call ppp for me */
demux(p_mux, 0, 0, m, &dump);
m->p = seprint(m->p, m->e, "v=%d t=%d c=0x%x s=0x%ux, len=%d",
h->verstype>>4, h->verstype&0xF, h->code, NetS(h->sessid), NetS(h->length));
return 0;
}
Proto pppoe_disc =
{
"pppoe_disc",
p_compiledisc,
p_filter,
p_seprintdisc,
p_mux,
p_fields,
defaultframer
};
Proto pppoe_sess =
{
"pppoe_sess",
p_compilesess,
p_filter,
p_seprintsess,
p_mux,
p_fields,
defaultframer
};

1
src/cmd/ip/snoopy/pppoe_sess.c Executable file
View file

@ -0,0 +1 @@
/* placeholder; see pppoe_disc.c */

View file

@ -0,0 +1,33 @@
#include <u.h>
#include <libc.h>
#include "dat.h"
#include "protos.h"
Proto *protos[] =
{
&ether,
&ip,
&ip6,
&dump,
&arp,
&rarp,
&udp,
&bootp,
&dhcp,
&hdlc,
&rtp,
&rtcp,
&tcp,
&il,
&icmp,
&icmp6,
&ninep,
&ospf,
&ppp,
&ppp_ccp,
&ppp_lcp,
&ppp_chap,
&ppp_ipcp,
&pppoe_sess,
&pppoe_disc,
0,
};

View file

@ -0,0 +1,25 @@
extern Proto ether;
extern Proto ip;
extern Proto ip6;
extern Proto dump;
extern Proto arp;
extern Proto rarp;
extern Proto udp;
extern Proto bootp;
extern Proto dhcp;
extern Proto hdlc;
extern Proto rtp;
extern Proto rtcp;
extern Proto tcp;
extern Proto il;
extern Proto icmp;
extern Proto icmp6;
extern Proto ninep;
extern Proto ospf;
extern Proto ppp;
extern Proto ppp_ccp;
extern Proto ppp_lcp;
extern Proto ppp_chap;
extern Proto ppp_ipcp;
extern Proto pppoe_sess;
extern Proto pppoe_disc;

1
src/cmd/ip/snoopy/rarp.c Executable file
View file

@ -0,0 +1 @@
/* place holder, this stuff is really in arp.c */

97
src/cmd/ip/snoopy/rtcp.c Executable file
View file

@ -0,0 +1,97 @@
#include <u.h>
#include <libc.h>
#include <ip.h>
#include "dat.h"
#include "protos.h"
typedef struct Hdr Hdr;
struct Hdr {
uchar hdr; // RTCP header
uchar pt; // Packet type
uchar len[2]; // Report length
uchar ssrc[4]; // Synchronization source identifier
uchar ntp[8]; // NTP time stamp
uchar rtp[4]; // RTP time stamp
uchar pktc[4]; // Sender's packet count
uchar octc[4]; // Sender's octect count
};
typedef struct Report Report;
struct Report {
uchar ssrc[4]; // SSRC identifier
uchar lost[4]; // Fraction + cumu lost
uchar seqhi[4]; // Highest seq number received
uchar jitter[4]; // Interarrival jitter
uchar lsr[4]; // Last SR
uchar dlsr[4]; // Delay since last SR
};
enum{
RTCPLEN = 28, // Minimum size of an RTCP header
REPORTLEN = 24,
};
static void
p_compile(Filter *f)
{
sysfatal("unknown rtcp field: %s", f->s);
}
static int
p_filter(Filter *f, Msg *m)
{
USED(f);
USED(m);
return 0;
}
static int
p_seprint(Msg *m)
{
Hdr*h;
Report*r;
int rc, i, frac;
float dlsr;
if(m->pe - m->ps < RTCPLEN)
return -1;
h = (Hdr*)m->ps;
if(m->pe - m->ps < (NetS(h->len) + 1) * 4)
return -1;
rc = h->hdr & 0x1f;
m->ps += RTCPLEN;
m->p = seprint(m->p, m->e, "version=%d rc=%d tp=%d ssrc=%8ux ntp=%d.%.10ud rtp=%d pktc=%d octc=%d hlen=%d",
(h->hdr >> 6) & 3, rc, h->pt, NetL(h->ssrc),
NetL(h->ntp), (uint)NetL(&h->ntp[4]), NetL(h->rtp),
NetL(h->pktc), NetL(h->octc),
(NetS(h->len) + 1) * 4);
for(i = 0; i < rc; i++){
r = (Report*)m->ps;
m->ps += REPORTLEN;
frac = (int)(((float)r->lost[0] * 100.) / 256.);
r->lost[0] = 0;
dlsr = (float)NetL(r->dlsr) / 65536.;
m->p = seprint(m->p, m->e, "\n\trr(csrc=%8ux frac=%3d%% cumu=%10d seqhi=%10ud jitter=%10d lsr=%8ux dlsr=%f)",
NetL(r->ssrc), frac, NetL(r->lost), NetL(r->seqhi),
NetL(r->jitter), NetL(r->lsr),
dlsr);
}
m->pr = nil;
return 0;
}
Proto rtcp = {
"rtcp",
p_compile,
p_filter,
p_seprint,
nil,
nil,
defaultframer,
};

76
src/cmd/ip/snoopy/rtp.c Executable file
View file

@ -0,0 +1,76 @@
#include <u.h>
#include <libc.h>
#include <ip.h>
#include "dat.h"
#include "protos.h"
typedef struct Hdr Hdr;
struct Hdr {
uchar hdr; // RTP header
uchar marker; // Payload and marker
uchar seq[2]; // Sequence number
uchar ts[4]; // Time stamp
uchar ssrc[4]; // Synchronization source identifier
};
enum{
RTPLEN = 12, // Minimum size of an RTP header
};
static void
p_compile(Filter *f)
{
sysfatal("unknown rtp field: %s", f->s);
}
static int
p_filter(Filter *f, Msg *m)
{
USED(f);
USED(m);
return 0;
}
static int
p_seprint(Msg *m)
{
Hdr*h;
ushort seq;
ulong ssrc, ts;
int cc, i;
if(m->pe - m->ps < RTPLEN)
return -1;
h = (Hdr*)m->ps;
cc = h->hdr & 0xf;
if(m->pe - m->ps < RTPLEN + cc * 4)
return -1;
m->ps += RTPLEN;
seq = NetS(h->seq);
ts = NetL(h->ts);
ssrc = NetL(h->ssrc);
m->p = seprint(m->p, m->e, "version=%d x=%d cc=%d seq=%d ts=%ld ssrc=%ulx",
(h->hdr >> 6) & 3, (h->hdr >> 4) & 1, cc, seq, ts, ssrc);
for(i = 0; i < cc; i++){
m->p = seprint(m->p, m->e, " csrc[%d]=%d",
i, NetL(m->ps));
m->ps += 4;
}
m->pr = nil;
return 0;
}
Proto rtp = {
"rtp",
p_compile,
p_filter,
p_seprint,
nil,
nil,
defaultframer,
};

221
src/cmd/ip/snoopy/tcp.c Executable file
View file

@ -0,0 +1,221 @@
#include <u.h>
#include <libc.h>
#include <ip.h>
#include "dat.h"
#include "protos.h"
typedef struct Hdr Hdr;
struct Hdr
{
uchar sport[2];
uchar dport[2];
uchar seq[4];
uchar ack[4];
uchar flag[2];
uchar win[2];
uchar cksum[2];
uchar urg[2];
uchar opt[1];
};
typedef struct PseudoHdr{
uchar src[4];
uchar dst[4];
uchar zero;
uchar proto;
uchar length[2];
uchar hdrdata[1580];
} PseudoHdr;
enum
{
TCPLEN= 20,
};
enum
{
Os,
Od,
Osd,
};
static Field p_fields[] =
{
{"s", Fnum, Os, "source port", } ,
{"d", Fnum, Od, "dest port", } ,
{"a", Fnum, Osd, "source/dest port", } ,
{"sd", Fnum, Osd, "source/dest port", } ,
{0}
};
static Mux p_mux[] =
{
{"ninep", 17007, }, /* exportfs */
{"ninep", 564, }, /* 9fs */
{"ninep", 17005, }, /* ocpu */
{"ninep", 17010, }, /* ncpu */
{"ninep", 17013, }, /* cpu */
{0},
};
enum
{
EOLOPT = 0,
NOOPOPT = 1,
MSSOPT = 2,
MSS_LENGTH = 4, /* Mean segment size */
WSOPT = 3,
WS_LENGTH = 3, /* Bits to scale window size by */
};
static void
p_compile(Filter *f)
{
Mux *m;
if(f->op == '='){
compile_cmp(udp.name, f, p_fields);
return;
}
for(m = p_mux; m->name != nil; m++)
if(strcmp(f->s, m->name) == 0){
f->pr = m->pr;
f->ulv = m->val;
f->subop = Osd;
return;
}
sysfatal("unknown tcp field or protocol: %s", f->s);
}
static int
p_filter(Filter *f, Msg *m)
{
Hdr *h;
if(m->pe - m->ps < TCPLEN)
return 0;
h = (Hdr*)m->ps;
m->ps += ((NetS(h->flag)>>10)&0x3f);
switch(f->subop){
case Os:
return NetS(h->sport) == f->ulv;
case Od:
return NetS(h->dport) == f->ulv;
case Osd:
return NetS(h->sport) == f->ulv || NetS(h->dport) == f->ulv;
}
return 0;
}
enum
{
URG = 0x20, /* Data marked urgent */
ACK = 0x10, /* Aknowledge is valid */
PSH = 0x08, /* Whole data pipe is pushed */
RST = 0x04, /* Reset connection */
SYN = 0x02, /* Pkt. is synchronise */
FIN = 0x01, /* Start close down */
};
static char*
flags(int f)
{
static char fl[20];
char *p;
p = fl;
if(f & URG)
*p++ = 'U';
if(f & ACK)
*p++ = 'A';
if(f & PSH)
*p++ = 'P';
if(f & RST)
*p++ = 'R';
if(f & SYN)
*p++ = 'S';
if(f & FIN)
*p++ = 'F';
*p = 0;
return fl;
}
static int
p_seprint(Msg *m)
{
Hdr *h;
int dport, sport;
int len, flag, optlen;
uchar *optr;
if(m->pe - m->ps < TCPLEN)
return -1;
h = (Hdr*)m->ps;
/* get tcp header length */
flag = NetS(h->flag);
len = (flag>>10)&~3;
flag &= 0x3ff;
m->ps += len;
/* next protocol */
dport = NetS(h->dport);
sport = NetS(h->sport);
demux(p_mux, sport, dport, m, &dump);
m->p = seprint(m->p, m->e, "s=%d d=%d seq=%lud ack=%lud fl=%s win=%d ck=%4.4ux",
NetS(h->sport), dport,
(ulong)NetL(h->seq), (ulong)NetL(h->ack),
flags(flag), NetS(h->win),
NetS(h->cksum));
/* tcp options */
len -= TCPLEN;
optr = h->opt;
while(len > 0) {
if(*optr == EOLOPT){
m->p = seprint(m->p, m->e, " opt=EOL");
break;
}
if(*optr == NOOPOPT) {
m->p = seprint(m->p, m->e, " opt=NOOP");
len--;
optr++;
continue;
}
optlen = optr[1];
if(optlen < 2 || optlen > len)
break;
switch(*optr) {
case MSSOPT:
m->p = seprint(m->p, m->e, " opt%d=(mss %ud)", optlen, nhgets(optr+2));
break;
case WSOPT:
m->p = seprint(m->p, m->e, " opt%d=(wscale %ud)", optlen, *(optr+2));
break;
default:
m->p = seprint(m->p, m->e, " opt%d=(%ud %.*H)", optlen, *optr, optlen-2,optr+2);
}
len -= optlen;
optr += optlen;
}
if(Cflag){
// editing in progress by ehg
}
return 0;
}
Proto tcp =
{
"tcp",
p_compile,
p_filter,
p_seprint,
p_mux,
p_fields,
defaultframer,
};

131
src/cmd/ip/snoopy/udp.c Executable file
View file

@ -0,0 +1,131 @@
#include <u.h>
#include <libc.h>
#include <ip.h>
#include "dat.h"
#include "protos.h"
typedef struct Hdr Hdr;
struct Hdr
{
uchar sport[2]; /* Source port */
uchar dport[2]; /* Destination port */
uchar len[2]; /* data length */
uchar cksum[2]; /* Checksum */
};
enum
{
UDPLEN= 8,
};
enum
{
Os,
Od,
Osd,
Osetport,
};
static Field p_fields[] =
{
{"s", Fnum, Os, "source port", } ,
{"d", Fnum, Od, "dest port", } ,
{"a", Fnum, Osd, "source/dest port", } ,
{"sd", Fnum, Osd, "source/dest port", } ,
{0}
};
#define ANYPORT ~0UL
static Mux p_mux[] =
{
{"bootp", 67, },
{"ninep", 6346, }, /* tvs */
{"rtp", ANYPORT, },
{"rtcp", ANYPORT, },
{0},
};
/* default next protocol, can be changed by p_filter, reset by p_compile */
static Proto *defproto = &dump;
static void
p_compile(Filter *f)
{
Mux *m;
if(f->op == '='){
compile_cmp(udp.name, f, p_fields);
return;
}
for(m = p_mux; m->name != nil; m++)
if(strcmp(f->s, m->name) == 0){
f->pr = m->pr;
f->ulv = m->val;
f->subop = Osd;
return;
}
sysfatal("unknown udp field or protocol: %s", f->s);
}
static int
p_filter(Filter *f, Msg *m)
{
Hdr *h;
if(m->pe - m->ps < UDPLEN)
return 0;
h = (Hdr*)m->ps;
m->ps += UDPLEN;
switch(f->subop){
case Os:
return NetS(h->sport) == f->ulv;
case Od:
return NetS(h->dport) == f->ulv;
case Osd:
if(f->ulv == ANYPORT){
defproto = f->pr;
return 1;
}
return NetS(h->sport) == f->ulv || NetS(h->dport) == f->ulv;
}
return 0;
}
static int
p_seprint(Msg *m)
{
Hdr *h;
int dport, sport;
if(m->pe - m->ps < UDPLEN)
return -1;
h = (Hdr*)m->ps;
m->ps += UDPLEN;
/* next protocol */
sport = NetS(h->sport);
dport = NetS(h->dport);
demux(p_mux, sport, dport, m, defproto);
defproto = &dump;
m->p = seprint(m->p, m->e, "s=%d d=%d ck=%4.4ux ln=%4d",
NetS(h->sport), dport,
NetS(h->cksum), NetS(h->len));
return 0;
}
Proto udp =
{
"udp",
p_compile,
p_filter,
p_seprint,
p_mux,
p_fields,
defaultframer,
};