#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,
"%#.4lux",
nil,
defaultframer,
};
Proto ppp_ipcp =
{
"ppp_ipcp",
p_compile,
p_filter,
p_seprintipcp,
nil,
nil,
nil,
defaultframer,
};
Proto ppp_lcp =
{
"ppp_lcp",
p_compile,
p_filter,
p_seprintlcp,
nil,
nil,
nil,
defaultframer,
};
Proto ppp_ccp =
{
"ppp_ccp",
p_compile,
p_filter,
p_seprintccp,
nil,
nil,
nil,
defaultframer,
};
Proto ppp_chap =
{
"ppp_chap",
p_compile,
p_filter,
p_seprintchap,
nil,
nil,
nil,
defaultframer,
};
Proto ppp_comp =
{
"ppp_comp",
p_compile,
p_filter,
p_seprintcomp,
nil,
nil,
nil,
defaultframer,
};
|