Branch data Line data Source code
1 : : // $Id: ICMP.cc 6219 2008-10-01 05:39:07Z vern $
2 : : //
3 : : // See the file "COPYING" in the main distribution directory for copyright.
4 : :
5 : : #include "config.h"
6 : :
7 : : #include "Net.h"
8 : : #include "NetVar.h"
9 : : #include "Event.h"
10 : : #include "ICMP.h"
11 : :
12 : 5 : ICMP_Analyzer::ICMP_Analyzer(Connection* c)
13 : 5 : : TransportLayerAnalyzer(AnalyzerTag::ICMP, c)
14 : : {
15 : 5 : icmp_conn_val = 0;
16 : 5 : c->SetInactivityTimeout(icmp_inactivity_timeout);
17 : 5 : request_len = reply_len = -1;
18 : 5 : }
19 : :
20 : 0 : ICMP_Analyzer::ICMP_Analyzer(AnalyzerTag::Tag tag, Connection* c)
21 : 0 : : TransportLayerAnalyzer(tag, c)
22 : : {
23 : 0 : icmp_conn_val = 0;
24 : 0 : c->SetInactivityTimeout(icmp_inactivity_timeout);
25 : 0 : request_len = reply_len = -1;
26 : 0 : }
27 : :
28 : 5 : void ICMP_Analyzer::Done()
29 : : {
30 : 5 : TransportLayerAnalyzer::Done();
31 : 5 : Unref(icmp_conn_val);
32 : 5 : matcher_state.FinishEndpointMatcher();
33 : 5 : }
34 : :
35 : : void ICMP_Analyzer::DeliverPacket(int arg_len, const u_char* data,
36 : 31 : bool is_orig, int seq, const IP_Hdr* ip, int caplen)
37 : : {
38 [ - + ]: 31 : assert(ip);
39 : :
40 : 31 : TransportLayerAnalyzer::DeliverPacket(len, data, is_orig, seq, ip, caplen);
41 : :
42 : : // We need the min() here because Ethernet frame padding can lead to
43 : : // caplen > len.
44 [ - + ]: 31 : if ( packet_contents )
45 : : // Subtract off the common part of ICMP header.
46 : 0 : PacketContents(data + 8, min(len, caplen) - 8);
47 : :
48 : 31 : const struct icmp* icmpp = (const struct icmp*) data;
49 : 31 : len = arg_len;
50 : :
51 [ + - ][ + - ]: 31 : if ( ! ignore_checksums && caplen >= len &&
[ - + ][ - + ]
52 : : icmp_checksum(icmpp, len) != 0xffff )
53 : : {
54 : 0 : Weird("bad_ICMP_checksum");
55 : 0 : return;
56 : : }
57 : :
58 : 31 : Conn()->SetLastTime(current_timestamp);
59 : :
60 [ - + ]: 31 : if ( rule_matcher )
61 : : {
62 [ # # ]: 0 : if ( ! matcher_state.MatcherInitialized(is_orig) )
63 : 0 : matcher_state.InitEndpointMatcher(this, ip, len, is_orig, 0);
64 : : }
65 : :
66 : 31 : type = icmpp->icmp_type;
67 : 31 : code = icmpp->icmp_code;
68 : :
69 : : // Move past common portion of ICMP header.
70 : 31 : data += 8;
71 : 31 : caplen -= 8;
72 : 31 : len -= 8;
73 : :
74 [ + - ]: 31 : int& len_stat = is_orig ? request_len : reply_len;
75 [ + + ]: 31 : if ( len_stat < 0 )
76 : 5 : len_stat = len;
77 : : else
78 : 26 : len_stat += len;
79 : :
80 : 31 : NextICMP(current_timestamp, icmpp, len, caplen, data);
81 : :
82 [ - + ]: 31 : if ( rule_matcher )
83 : : matcher_state.Match(Rule::PAYLOAD, data, len, is_orig,
84 : 31 : false, false, true);
85 : : }
86 : :
87 : : void ICMP_Analyzer::NextICMP(double /* t */, const struct icmp* /* icmpp */,
88 : : int /* len */, int /* caplen */,
89 : 31 : const u_char*& /* data */)
90 : : {
91 : 31 : ICMPEvent(icmp_sent);
92 : 31 : }
93 : :
94 : 31 : void ICMP_Analyzer::ICMPEvent(EventHandlerPtr f)
95 : : {
96 [ - + ]: 31 : if ( ! f )
97 : 31 : return;
98 : :
99 : 0 : val_list* vl = new val_list;
100 : 0 : vl->append(BuildConnVal());
101 : 0 : vl->append(BuildICMPVal());
102 : :
103 : 0 : ConnectionEvent(f, vl);
104 : : }
105 : :
106 : 0 : RecordVal* ICMP_Analyzer::BuildICMPVal()
107 : : {
108 [ # # ]: 0 : if ( ! icmp_conn_val )
109 : : {
110 : 0 : icmp_conn_val = new RecordVal(icmp_conn);
111 : :
112 : 0 : icmp_conn_val->Assign(0, new AddrVal(Conn()->OrigAddr()));
113 : 0 : icmp_conn_val->Assign(1, new AddrVal(Conn()->RespAddr()));
114 : 0 : icmp_conn_val->Assign(2, new Val(type, TYPE_COUNT));
115 : 0 : icmp_conn_val->Assign(3, new Val(code, TYPE_COUNT));
116 : 0 : icmp_conn_val->Assign(4, new Val(len, TYPE_COUNT));
117 : : }
118 : :
119 : 0 : Ref(icmp_conn_val);
120 : :
121 : 0 : return icmp_conn_val;
122 : : }
123 : :
124 : 0 : RecordVal* ICMP_Analyzer::ExtractICMPContext(int len, const u_char*& data)
125 : : {
126 : 0 : const struct ip* ip = (const struct ip *) data;
127 : 0 : uint32 ip_hdr_len = ip->ip_hl * 4;
128 : :
129 : : uint32 ip_len, frag_offset;
130 : 0 : TransportProto proto = TRANSPORT_UNKNOWN;
131 : : int DF, MF, bad_hdr_len, bad_checksum;
132 : : uint32 src_addr, dst_addr;
133 : : uint32 src_port, dst_port;
134 : :
135 [ # # ][ # # ]: 0 : if ( ip_hdr_len < sizeof(struct ip) || ip_hdr_len > uint32(len) )
136 : : { // We don't have an entire IP header.
137 : 0 : bad_hdr_len = 1;
138 : 0 : ip_len = frag_offset = 0;
139 : 0 : DF = MF = bad_checksum = 0;
140 : 0 : src_addr = dst_addr = 0;
141 : 0 : src_port = dst_port = 0;
142 : : }
143 : :
144 : : else
145 : : {
146 : 0 : bad_hdr_len = 0;
147 : 0 : ip_len = ntohs(ip->ip_len);
148 : 0 : bad_checksum = ones_complement_checksum((void*) ip, ip_hdr_len, 0) != 0xffff;
149 : :
150 : 0 : src_addr = uint32(ip->ip_src.s_addr);
151 : 0 : dst_addr = uint32(ip->ip_dst.s_addr);
152 : :
153 [ # # # # ]: 0 : switch ( ip->ip_p ) {
154 : 0 : case 1: proto = TRANSPORT_ICMP; break;
155 : 0 : case 6: proto = TRANSPORT_TCP; break;
156 : 0 : case 17: proto = TRANSPORT_UDP; break;
157 : :
158 : : // Default uses TRANSPORT_UNKNOWN, per initialization above.
159 : : }
160 : :
161 : 0 : uint32 frag_field = ntohs(ip->ip_off);
162 : 0 : DF = frag_field & 0x4000;
163 : 0 : MF = frag_field & 0x2000;
164 : 0 : frag_offset = frag_field & /* IP_OFFMASK not portable */ 0x1fff;
165 : 0 : const u_char* transport_hdr = ((u_char *) ip + ip_hdr_len);
166 : :
167 [ # # ]: 0 : if ( uint32(len) < ip_hdr_len + 4 )
168 : : {
169 : : // 4 above is the magic number meaning that both
170 : : // port numbers are included in the ICMP.
171 : 0 : bad_hdr_len = 1;
172 : 0 : src_port = dst_port = 0;
173 : : }
174 : :
175 [ # # # # ]: 0 : switch ( proto ) {
176 : : case TRANSPORT_ICMP:
177 : : {
178 : : const struct icmp* icmpp =
179 : 0 : (const struct icmp *) transport_hdr;
180 : : bool is_one_way; // dummy
181 : 0 : src_port = ntohs(icmpp->icmp_type);
182 : 0 : dst_port = ntohs(ICMP_counterpart(icmpp->icmp_type,
183 : : icmpp->icmp_code,
184 : : is_one_way));
185 : : }
186 : 0 : break;
187 : :
188 : : case TRANSPORT_TCP:
189 : : {
190 : : const struct tcphdr* tp =
191 : 0 : (const struct tcphdr *) transport_hdr;
192 : 0 : src_port = ntohs(tp->th_sport);
193 : 0 : dst_port = ntohs(tp->th_dport);
194 : : }
195 : 0 : break;
196 : :
197 : : case TRANSPORT_UDP:
198 : : {
199 : : const struct udphdr* up =
200 : 0 : (const struct udphdr *) transport_hdr;
201 : 0 : src_port = ntohs(up->uh_sport);
202 : 0 : dst_port = ntohs(up->uh_dport);
203 : : }
204 : 0 : break;
205 : :
206 : : default:
207 : 0 : src_port = dst_port = ntohs(0);
208 : : }
209 : : }
210 : :
211 : 0 : RecordVal* iprec = new RecordVal(icmp_context);
212 : 0 : RecordVal* id_val = new RecordVal(conn_id);
213 : :
214 : 0 : id_val->Assign(0, new AddrVal(src_addr));
215 : 0 : id_val->Assign(1, new PortVal(src_port, proto));
216 : 0 : id_val->Assign(2, new AddrVal(dst_addr));
217 : 0 : id_val->Assign(3, new PortVal(dst_port, proto));
218 : 0 : iprec->Assign(0, id_val);
219 : :
220 : 0 : iprec->Assign(1, new Val(ip_len, TYPE_COUNT));
221 : 0 : iprec->Assign(2, new Val(proto, TYPE_COUNT));
222 : 0 : iprec->Assign(3, new Val(frag_offset, TYPE_COUNT));
223 : 0 : iprec->Assign(4, new Val(bad_hdr_len, TYPE_BOOL));
224 : 0 : iprec->Assign(5, new Val(bad_checksum, TYPE_BOOL));
225 : 0 : iprec->Assign(6, new Val(MF, TYPE_BOOL));
226 : 0 : iprec->Assign(7, new Val(DF, TYPE_BOOL));
227 : :
228 : 0 : return iprec;
229 : : }
230 : :
231 : 26 : bool ICMP_Analyzer::IsReuse(double /* t */, const u_char* /* pkt */)
232 : : {
233 : 26 : return 0;
234 : : }
235 : :
236 : 0 : void ICMP_Analyzer::Describe(ODesc* d) const
237 : : {
238 : 0 : d->Add(Conn()->StartTime());
239 : 0 : d->Add("(");
240 : 0 : d->Add(Conn()->LastTime());
241 : 0 : d->AddSP(")");
242 : :
243 : 0 : d->Add(dotted_addr(Conn()->OrigAddr()));
244 : 0 : d->Add(".");
245 : 0 : d->Add(type);
246 : 0 : d->Add(".");
247 : 0 : d->Add(code);
248 : :
249 : 0 : d->SP();
250 : 0 : d->AddSP("->");
251 : :
252 : 0 : d->Add(dotted_addr(Conn()->RespAddr()));
253 : 0 : }
254 : :
255 : 20 : void ICMP_Analyzer::UpdateEndpointVal(RecordVal* endp, int is_orig)
256 : : {
257 : 20 : Conn()->EnableStatusUpdateTimer();
258 : :
259 [ + + ]: 20 : int size = is_orig ? request_len : reply_len;
260 [ + + ]: 20 : if ( size < 0 )
261 : : {
262 : 15 : endp->Assign(0, new Val(0, TYPE_COUNT));
263 : 15 : endp->Assign(1, new Val(int(ICMP_INACTIVE), TYPE_COUNT));
264 : : }
265 : :
266 : : else
267 : : {
268 : 5 : endp->Assign(0, new Val(size, TYPE_COUNT));
269 : 5 : endp->Assign(1, new Val(int(ICMP_ACTIVE), TYPE_COUNT));
270 : : }
271 : 20 : }
272 : :
273 : 0 : unsigned int ICMP_Analyzer::MemoryAllocation() const
274 : : {
275 : : return Analyzer::MemoryAllocation()
276 : : + padded_sizeof(*this) - padded_sizeof(Connection)
277 [ # # ]: 0 : + (icmp_conn_val ? icmp_conn_val->MemoryAllocation() : 0);
278 : : }
279 : :
280 : 0 : ICMP_Echo_Analyzer::ICMP_Echo_Analyzer(Connection* c)
281 : 0 : : ICMP_Analyzer(AnalyzerTag::ICMP_Echo, c)
282 : : {
283 : 0 : }
284 : :
285 : : void ICMP_Echo_Analyzer::NextICMP(double t, const struct icmp* icmpp, int len,
286 : 0 : int caplen, const u_char*& data)
287 : : {
288 [ # # ]: 0 : EventHandlerPtr f = type == ICMP_ECHO ? icmp_echo_request : icmp_echo_reply;
289 [ # # ]: 0 : if ( ! f )
290 : 0 : return;
291 : :
292 : 0 : int iid = ntohs(icmpp->icmp_hun.ih_idseq.icd_id);
293 : 0 : int iseq = ntohs(icmpp->icmp_hun.ih_idseq.icd_seq);
294 : :
295 : 0 : BroString* payload = new BroString(data, caplen, 0);
296 : :
297 : 0 : val_list* vl = new val_list;
298 : 0 : vl->append(BuildConnVal());
299 : 0 : vl->append(BuildICMPVal());
300 : 0 : vl->append(new Val(iid, TYPE_COUNT));
301 : 0 : vl->append(new Val(iseq, TYPE_COUNT));
302 : 0 : vl->append(new StringVal(payload));
303 : :
304 : 0 : ConnectionEvent(f, vl);
305 : : }
306 : :
307 : :
308 : : void ICMP_Context_Analyzer::NextICMP(double t, const struct icmp* icmpp,
309 : 0 : int len, int caplen, const u_char*& data)
310 : : {
311 : 0 : EventHandlerPtr f = 0;
312 [ # # # ]: 0 : switch ( type ) {
313 : 0 : case ICMP_UNREACH: f = icmp_unreachable; break;
314 : 0 : case ICMP_TIMXCEED: f = icmp_time_exceeded; break;
315 : : }
316 : :
317 [ # # ]: 0 : if ( f )
318 : : {
319 : 0 : val_list* vl = new val_list;
320 : 0 : vl->append(BuildConnVal());
321 : 0 : vl->append(BuildICMPVal());
322 : 0 : vl->append(new Val(code, TYPE_COUNT));
323 : 0 : vl->append(ExtractICMPContext(caplen, data));
324 : :
325 : 0 : ConnectionEvent(f, vl);
326 : : }
327 : 0 : }
328 : :
329 : :
330 : 31 : int ICMP_counterpart(int icmp_type, int icmp_code, bool& is_one_way)
331 : : {
332 : 31 : is_one_way = false;
333 : :
334 : : // return the counterpart type if one exists. This allows us
335 : : // to track corresponding ICMP requests/replies.
336 : : // Note that for the two-way ICMP messages, icmp_code is
337 : : // always 0 (RFC 792).
338 [ - - - - - : 31 : switch ( icmp_type ) {
- - - - + ]
339 : 0 : case ICMP_ECHO: return ICMP_ECHOREPLY;
340 : 0 : case ICMP_ECHOREPLY: return ICMP_ECHO;
341 : 0 : case ICMP_TSTAMP: return ICMP_TSTAMPREPLY;
342 : 0 : case ICMP_TSTAMPREPLY: return ICMP_TSTAMP;
343 : 0 : case ICMP_IREQ: return ICMP_IREQREPLY;
344 : 0 : case ICMP_IREQREPLY: return ICMP_IREQ;
345 : 0 : case ICMP_ROUTERSOLICIT: return ICMP_ROUTERADVERT;
346 : 0 : case ICMP_MASKREQ: return ICMP_MASKREPLY;
347 : 0 : case ICMP_MASKREPLY: return ICMP_MASKREQ;
348 : :
349 : 31 : default: is_one_way = true; return icmp_code;
350 : : }
351 [ + - ][ + - ]: 6 : }
|