xref: /plan9/sys/src/cmd/ip/snoopy/icmp.c (revision e4556204f7a17d35312ca6493b4391646c5ea7a2)
1 #include <u.h>
2 #include <libc.h>
3 #include <ip.h>
4 #include "dat.h"
5 #include "protos.h"
6 
7 typedef struct Hdr	Hdr;
8 struct Hdr
9 {	uchar	type;
10 	uchar	code;
11 	uchar	cksum[2];	/* Checksum */
12 	uchar	data[1];
13 };
14 
15 enum
16 {
17 	ICMPLEN=	4,
18 };
19 
20 enum
21 {
22 	Ot,	/* type */
23 	Op,	/* next protocol */
24 };
25 
26 static Field p_fields[] =
27 {
28 	{"t",		Fnum,	Ot,	"type",	} ,
29 	{0}
30 };
31 
32 enum
33 {
34 	EchoRep=	0,
35 	Unreachable=	3,
36 	SrcQuench=	4,
37 	Redirect=	5,
38 	EchoReq=	8,
39 	TimeExceed=	11,
40 	ParamProb=	12,
41 	TSreq=		13,
42 	TSrep=		14,
43 	InfoReq=	15,
44 	InfoRep=	16,
45 };
46 
47 static Mux p_mux[] =
48 {
49 	{"ip",	Unreachable, },
50 	{"ip",	SrcQuench, },
51 	{"ip",	Redirect, },
52 	{"ip",	TimeExceed, },
53 	{"ip",	ParamProb, },
54 	{0},
55 };
56 
57 char *icmpmsg[256] =
58 {
59 [EchoRep]	"EchoRep",
60 [Unreachable]	"Unreachable",
61 [SrcQuench]	"SrcQuench",
62 [Redirect]	"Redirect",
63 [EchoReq]	"EchoReq",
64 [TimeExceed]	"TimeExceed",
65 [ParamProb]	"ParamProb",
66 [TSreq]		"TSreq",
67 [TSrep]		"TSrep",
68 [InfoReq]	"InfoReq",
69 [InfoRep]	"InfoRep",
70 };
71 
72 static void
p_compile(Filter * f)73 p_compile(Filter *f)
74 {
75 	if(f->op == '='){
76 		compile_cmp(icmp.name, f, p_fields);
77 		return;
78 	}
79 	if(strcmp(f->s, "ip") == 0){
80 		f->pr = p_mux->pr;
81 		f->subop = Op;
82 		return;
83 	}
84 	sysfatal("unknown icmp field or protocol: %s", f->s);
85 }
86 
87 static int
p_filter(Filter * f,Msg * m)88 p_filter(Filter *f, Msg *m)
89 {
90 	Hdr *h;
91 
92 	if(m->pe - m->ps < ICMPLEN)
93 		return 0;
94 
95 	h = (Hdr*)m->ps;
96 	m->ps += ICMPLEN;
97 
98 	switch(f->subop){
99 	case Ot:
100 		if(h->type == f->ulv)
101 			return 1;
102 		break;
103 	case Op:
104 		switch(h->type){
105 		case Unreachable:
106 		case TimeExceed:
107 		case SrcQuench:
108 		case Redirect:
109 		case ParamProb:
110 			m->ps += 4;
111 			return 1;
112 		}
113 	}
114 	return 0;
115 }
116 
117 static int
p_seprint(Msg * m)118 p_seprint(Msg *m)
119 {
120 	Hdr *h;
121 	char *tn;
122 	char *p = m->p;
123 	char *e = m->e;
124 	ushort cksum2, cksum;
125 
126 	h = (Hdr*)m->ps;
127 	m->ps += ICMPLEN;
128 	m->pr = &dump;
129 
130 	if(m->pe - m->ps < ICMPLEN)
131 		return -1;
132 
133 	tn = icmpmsg[h->type];
134 	if(tn == nil)
135 		p = seprint(p, e, "t=%ud c=%d ck=%4.4ux", h->type,
136 			h->code, (ushort)NetS(h->cksum));
137 	else
138 		p = seprint(p, e, "t=%s c=%d ck=%4.4ux", tn,
139 			h->code, (ushort)NetS(h->cksum));
140 	if(Cflag){
141 		cksum = NetS(h->cksum);
142 		h->cksum[0] = 0;
143 		h->cksum[1] = 0;
144 		cksum2 = ~ptclbsum((uchar*)h, m->pe - m->ps + ICMPLEN) & 0xffff;
145 		if(cksum != cksum2)
146 			p = seprint(p,e, " !ck=%4.4ux", cksum2);
147 	}
148 	switch(h->type){
149 	case EchoRep:
150 	case EchoReq:
151 		m->ps += 4;
152 		p = seprint(p, e, " id=%ux seq=%ux",
153 			NetS(h->data), NetS(h->data+2));
154 		break;
155 	case TSreq:
156 	case TSrep:
157 		m->ps += 12;
158 		p = seprint(p, e, " orig=%ud rcv=%ux xmt=%ux",
159 			NetL(h->data), NetL(h->data+4),
160 			NetL(h->data+8));
161 		m->pr = nil;
162 		break;
163 	case InfoReq:
164 	case InfoRep:
165 		break;
166 	case Unreachable:
167 	case TimeExceed:
168 	case SrcQuench:
169 		m->ps += 4;
170 		m->pr = &ip;
171 		break;
172 	case Redirect:
173 		m->ps += 4;
174 		m->pr = &ip;
175 		p = seprint(p, e, "gw=%V", h->data);
176 		break;
177 	case ParamProb:
178 		m->ps += 4;
179 		m->pr = &ip;
180 		p = seprint(p, e, "ptr=%2.2ux", h->data[0]);
181 		break;
182 	}
183 	m->p = p;
184 	return 0;
185 }
186 
187 Proto icmp =
188 {
189 	"icmp",
190 	p_compile,
191 	p_filter,
192 	p_seprint,
193 	p_mux,
194 	"%lud",
195 	p_fields,
196 	defaultframer,
197 };
198