new goodies
This commit is contained in:
parent
35d26aa321
commit
87a52e0485
44 changed files with 8723 additions and 0 deletions
151
src/cmd/ip/dhcp.h
Executable file
151
src/cmd/ip/dhcp.h
Executable 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
85
src/cmd/ip/dhcpd/dat.h
Executable 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
452
src/cmd/ip/dhcpd/db.c
Executable 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
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
43
src/cmd/ip/dhcpd/dhcpleases.c
Executable 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
22
src/cmd/ip/dhcpd/mkfile
Executable 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
318
src/cmd/ip/dhcpd/ndb.c
Executable 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
112
src/cmd/ip/dhcpd/ping.c
Executable 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
222
src/cmd/ip/dhcpd/testlook.c
Executable 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
168
src/cmd/ip/dhcpd/testlookup.c
Executable 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
22
src/cmd/ip/dhcpd/testping.c
Executable 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
58
src/cmd/ip/snoopy/Linux.c
Normal 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
128
src/cmd/ip/snoopy/arp.c
Executable 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
176
src/cmd/ip/snoopy/bootp.c
Executable 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
106
src/cmd/ip/snoopy/dat.h
Executable 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
483
src/cmd/ip/snoopy/dhcp.c
Executable 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
92
src/cmd/ip/snoopy/dump.c
Executable 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
121
src/cmd/ip/snoopy/ether.c
Executable 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
83
src/cmd/ip/snoopy/gre.c
Executable 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
174
src/cmd/ip/snoopy/hdlc.c
Executable 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
196
src/cmd/ip/snoopy/icmp.c
Executable 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
428
src/cmd/ip/snoopy/icmp6.c
Executable 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
146
src/cmd/ip/snoopy/il.c
Executable 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
236
src/cmd/ip/snoopy/ip.c
Executable 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
309
src/cmd/ip/snoopy/ip6.c
Executable 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
841
src/cmd/ip/snoopy/main.c
Executable 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 = ðer;
|
||||
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
69
src/cmd/ip/snoopy/mkfile
Executable 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
55
src/cmd/ip/snoopy/ninep.c
Executable 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
404
src/cmd/ip/snoopy/ospf.c
Executable 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
629
src/cmd/ip/snoopy/ppp.c
Executable 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
1
src/cmd/ip/snoopy/ppp_ccp.c
Executable file
|
|
@ -0,0 +1 @@
|
|||
/* place holder, this stuff is really in ppp.c */
|
||||
1
src/cmd/ip/snoopy/ppp_chap.c
Executable file
1
src/cmd/ip/snoopy/ppp_chap.c
Executable file
|
|
@ -0,0 +1 @@
|
|||
/* place holder, this stuff is really in ppp.c */
|
||||
1
src/cmd/ip/snoopy/ppp_comp.c
Executable file
1
src/cmd/ip/snoopy/ppp_comp.c
Executable file
|
|
@ -0,0 +1 @@
|
|||
/* place holder, this stuff is really in ppp.c */
|
||||
1
src/cmd/ip/snoopy/ppp_ipcp.c
Executable file
1
src/cmd/ip/snoopy/ppp_ipcp.c
Executable file
|
|
@ -0,0 +1 @@
|
|||
/* place holder, this stuff is really in ppp.c */
|
||||
1
src/cmd/ip/snoopy/ppp_lcp.c
Executable file
1
src/cmd/ip/snoopy/ppp_lcp.c
Executable file
|
|
@ -0,0 +1 @@
|
|||
/* place holder, this stuff is really in ppp.c */
|
||||
172
src/cmd/ip/snoopy/pppoe_disc.c
Executable file
172
src/cmd/ip/snoopy/pppoe_disc.c
Executable 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
1
src/cmd/ip/snoopy/pppoe_sess.c
Executable file
|
|
@ -0,0 +1 @@
|
|||
/* placeholder; see pppoe_disc.c */
|
||||
33
src/cmd/ip/snoopy/protos.c
Normal file
33
src/cmd/ip/snoopy/protos.c
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include "dat.h"
|
||||
#include "protos.h"
|
||||
Proto *protos[] =
|
||||
{
|
||||
ðer,
|
||||
&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,
|
||||
};
|
||||
25
src/cmd/ip/snoopy/protos.h
Normal file
25
src/cmd/ip/snoopy/protos.h
Normal 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
1
src/cmd/ip/snoopy/rarp.c
Executable file
|
|
@ -0,0 +1 @@
|
|||
/* place holder, this stuff is really in arp.c */
|
||||
97
src/cmd/ip/snoopy/rtcp.c
Executable file
97
src/cmd/ip/snoopy/rtcp.c
Executable 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
76
src/cmd/ip/snoopy/rtp.c
Executable 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
221
src/cmd/ip/snoopy/tcp.c
Executable 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
131
src/cmd/ip/snoopy/udp.c
Executable 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,
|
||||
};
|
||||
Loading…
Add table
Add a link
Reference in a new issue