diff options
Diffstat (limited to 'src/cmd/ip/snoopy/icmp6.c')
-rwxr-xr-x | src/cmd/ip/snoopy/icmp6.c | 428 |
1 files changed, 428 insertions, 0 deletions
diff --git a/src/cmd/ip/snoopy/icmp6.c b/src/cmd/ip/snoopy/icmp6.c new file mode 100755 index 00000000..9c154f88 --- /dev/null +++ b/src/cmd/ip/snoopy/icmp6.c @@ -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, +}; |