#include #include #include #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; 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) { int i; // ushort cksum2, cksum; char *tn; char *p = m->p; char *e = m->e; uchar *a; Hdr *h; 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, "%lud", p_fields, defaultframer, };