| #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[256] = |
| { |
| [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, |
| "%lud", |
| p_fields, |
| defaultframer |
| }; |