Branch data Line data Source code
1 : : // $Id: ARP.cc 6219 2008-10-01 05:39:07Z vern $
2 : : //
3 : : // See the file "COPYING" in the main distribution directory for copyright.
4 : :
5 : :
6 : : #include "ARP.h"
7 : : #include "Event.h"
8 : :
9 : :
10 : 0 : ARP_Analyzer::ARP_Analyzer()
11 : : {
12 : 0 : bad_arp = internal_handler("bad_arp");
13 : 0 : arp_request = internal_handler("arp_request");
14 : 0 : arp_reply = internal_handler("arp_reply");
15 : 0 : }
16 : :
17 : 0 : ARP_Analyzer::~ARP_Analyzer()
18 : : {
19 [ # # ][ # # ]: 0 : }
[ # # ]
20 : :
21 : 0 : bool ARP_Analyzer::IsARP(const u_char* pkt, int hdr_size) const
22 : : {
23 : : unsigned short network_protocol =
24 : 0 : *(unsigned short*) (pkt + hdr_size - 2);
25 : :
26 [ # # ]: 0 : switch ( ntohs(network_protocol) ) {
27 : : case ETHERTYPE_ARP:
28 : : case ETHERTYPE_REVARP:
29 : 0 : return true;
30 : : default:
31 : 0 : return false;
32 : : }
33 : : }
34 : :
35 : :
36 : : // Argh! FreeBSD and Linux have almost completely different net/if_arp.h .
37 : : // ... and on Solaris we are missing half of the ARPOP codes, so define
38 : : // them here as necessary:
39 : :
40 : : #ifndef ARPOP_REQUEST
41 : : #define ARPOP_REQUEST 1 // ARP request.
42 : : #endif
43 : : #ifndef ARPOP_REPLY
44 : : #define ARPOP_REPLY 2 // ARP reply.
45 : : #endif
46 : : #ifndef ARPOP_PREQUEST
47 : : #define ARPOP_RREQUEST 3 // RARP request.
48 : : #endif
49 : : #ifndef ARPOP_RREPLY
50 : : #define ARPOP_RREPLY 4 // RARP reply.
51 : : #endif
52 : : #ifndef ARPOP_InREQUEST
53 : : #define ARPOP_InREQUEST 8 // InARP request.
54 : : #endif
55 : : #ifndef ARPOP_InREPLY
56 : : #define ARPOP_InREPLY 9 // InARP reply.
57 : : #endif
58 : : #ifndef ARPOP_NAK
59 : : #define ARPOP_NAK 10 // (ATM)ARP NAK.
60 : : #endif
61 : :
62 : : #ifndef ar_sha
63 : : #define ar_sha(ap) ((caddr_t((ap)+1)) + 0)
64 : : #endif
65 : :
66 : : #ifndef ar_spa
67 : : #define ar_spa(ap) ((caddr_t((ap)+1)) + (ap)->ar_hln)
68 : : #endif
69 : :
70 : : #ifndef ar_tha
71 : : #define ar_tha(ap) ((caddr_t((ap)+1)) + (ap)->ar_hln + (ap)->ar_pln)
72 : : #endif
73 : :
74 : : #ifndef ar_tpa
75 : : #define ar_tpa(ap) ((caddr_t((ap)+1)) + 2*(ap)->ar_hln + (ap)->ar_pln)
76 : : #endif
77 : :
78 : : #ifndef ARPOP_REVREQUEST
79 : : #define ARPOP_REVREQUEST ARPOP_RREQUEST
80 : : #endif
81 : :
82 : : #ifndef ARPOP_REVREPLY
83 : : #define ARPOP_REVREPLY ARPOP_RREPLY
84 : : #endif
85 : :
86 : : #ifndef ARPOP_INVREQUEST
87 : : #define ARPOP_INVREQUEST ARPOP_InREQUEST
88 : : #endif
89 : :
90 : : #ifndef ARPOP_INVREPLY
91 : : #define ARPOP_INVREPLY ARPOP_InREPLY
92 : : #endif
93 : :
94 : :
95 : : void ARP_Analyzer::NextPacket(double t, const struct pcap_pkthdr* hdr,
96 : 0 : const u_char* const pkt, int hdr_size)
97 : : {
98 : : // Check whether the packet is OK ("inspired" in tcpdump's print-arp.c).
99 : : const struct arp_pkthdr* ah =
100 : 0 : (const struct arp_pkthdr*) (pkt + hdr_size);
101 : :
102 : : // Check the size.
103 : 0 : int min_length = (ar_tpa(ah) - (char*) (pkt + hdr_size)) + ah->ar_pln;
104 : 0 : int real_length = hdr->caplen - hdr_size;
105 [ # # ]: 0 : if ( min_length > real_length )
106 : : {
107 : 0 : Corrupted("truncated_ARP");
108 : 0 : return;
109 : : }
110 : :
111 : : char errbuf[1024];
112 : :
113 : : // Check the address description fields.
114 [ # # ]: 0 : switch ( ntohs(ah->ar_hrd) ) {
115 : : case ARPHRD_ETHER:
116 [ # # ]: 0 : if ( ah->ar_hln != 6 )
117 : : { // don't know how to handle the opcode
118 : : snprintf(errbuf, sizeof(errbuf),
119 : : "corrupt-arp-header (hrd=%i, hln=%i)",
120 : 0 : ntohs(ah->ar_hrd), ah->ar_hln);
121 : 0 : BadARP(ah, errbuf);
122 : 0 : return;
123 : : }
124 : : break;
125 : :
126 : : default:
127 : : { // don't know how to proceed
128 : : snprintf(errbuf, sizeof(errbuf),
129 : 0 : "unknown-arp-hw-address (hrd=%i)", ntohs(ah->ar_hrd));
130 : 0 : BadARP(ah, errbuf);
131 : 0 : return;
132 : : }
133 : : }
134 : :
135 : : // ### Note, we don't support IPv6 addresses yet.
136 [ # # ]: 0 : switch ( ntohs(ah->ar_pro) ) {
137 : : case ETHERTYPE_IP:
138 [ # # ]: 0 : if ( ah->ar_pln != 4 )
139 : : { // don't know how to handle the opcode
140 : : snprintf(errbuf, sizeof(errbuf),
141 : : "corrupt-arp-header (pro=%i, pln=%i)",
142 : 0 : ntohs(ah->ar_pro), ah->ar_pln);
143 : 0 : BadARP(ah, errbuf);
144 : 0 : return;
145 : : }
146 : : break;
147 : :
148 : : default:
149 : : { // don't know how to proceed
150 : : snprintf(errbuf, sizeof(errbuf),
151 : : "unknown-arp-proto-address (pro=%i)",
152 : 0 : ntohs(ah->ar_pro));
153 : 0 : BadARP(ah, errbuf);
154 : 0 : return;
155 : : }
156 : : }
157 : :
158 : :
159 : : // Check MAC src address = ARP sender MAC address.
160 [ # # ]: 0 : if ( memcmp((const char*) (pkt+6), ar_sha(ah), ah->ar_hln) )
161 : : {
162 : 0 : BadARP(ah, "weird-arp-sha");
163 : 0 : return;
164 : : }
165 : :
166 : : // Check the code is supported.
167 [ # # # # ]: 0 : switch ( ntohs(ah->ar_op) ) {
168 : : case ARPOP_REQUEST:
169 : : RREvent(arp_request, pkt+6, pkt,
170 : 0 : ar_spa(ah), ar_sha(ah), ar_tpa(ah), ar_tha(ah));
171 : 0 : break;
172 : :
173 : : case ARPOP_REPLY:
174 : : RREvent(arp_reply, pkt+6, pkt,
175 : 0 : ar_spa(ah), ar_sha(ah), ar_tpa(ah), ar_tha(ah));
176 : 0 : break;
177 : :
178 : : case ARPOP_REVREQUEST:
179 : : case ARPOP_REVREPLY:
180 : : case ARPOP_INVREQUEST:
181 : : case ARPOP_INVREPLY:
182 : : { // don't know how to handle the opcode
183 : : snprintf(errbuf, sizeof(errbuf),
184 : 0 : "unimplemented-arp-opcode (%i)", ntohs(ah->ar_op));
185 : 0 : BadARP(ah, errbuf);
186 : 0 : break;
187 : : }
188 : :
189 : : default:
190 : : { // invalid opcode
191 : : snprintf(errbuf, sizeof(errbuf),
192 : 0 : "invalid-arp-opcode (opcode=%i)", ntohs(ah->ar_op));
193 : 0 : BadARP(ah, errbuf);
194 : 0 : return;
195 : : }
196 : : }
197 : : }
198 : :
199 : 0 : void ARP_Analyzer::Describe(ODesc* d) const
200 : : {
201 : 0 : d->Add("<ARP analyzer>");
202 : 0 : d->NL();
203 : 0 : }
204 : :
205 : 0 : void ARP_Analyzer::BadARP(const struct arp_pkthdr* hdr, const char* msg)
206 : : {
207 [ # # ]: 0 : if ( ! bad_arp )
208 : 0 : return;
209 : :
210 : 0 : val_list* vl = new val_list;
211 : 0 : vl->append(ConstructAddrVal(ar_spa(hdr)));
212 : 0 : vl->append(EthAddrToStr((const u_char*) ar_sha(hdr)));
213 : 0 : vl->append(ConstructAddrVal(ar_tpa(hdr)));
214 : 0 : vl->append(EthAddrToStr((const u_char*) ar_tha(hdr)));
215 : 0 : vl->append(new StringVal(msg));
216 : 0 : mgr.QueueEvent(bad_arp, vl);
217 : : }
218 : :
219 : 0 : void ARP_Analyzer::Corrupted(const char* msg)
220 : : {
221 [ # # ]: 0 : if ( ! net_weird )
222 : 0 : return;
223 : :
224 : 0 : val_list* vl = new val_list;
225 : 0 : vl->append(new StringVal(msg));
226 : 0 : mgr.QueueEvent(net_weird, vl);
227 : : }
228 : :
229 : : void ARP_Analyzer::RREvent(EventHandlerPtr e,
230 : : const u_char* src, const u_char *dst,
231 : : const char* spa, const char* sha,
232 : 0 : const char* tpa, const char* tha)
233 : : {
234 [ # # ]: 0 : if ( ! e )
235 : 0 : return;
236 : :
237 : : // init the val_list
238 : 0 : val_list* vl = new val_list;
239 : :
240 : : // prepare the event arguments
241 : 0 : vl->append(EthAddrToStr(src));
242 : 0 : vl->append(EthAddrToStr(dst));
243 : 0 : vl->append(ConstructAddrVal(spa));
244 : 0 : vl->append(EthAddrToStr((const u_char*) sha));
245 : 0 : vl->append(ConstructAddrVal(tpa));
246 : 0 : vl->append(EthAddrToStr((const u_char*) tha));
247 : :
248 : 0 : mgr.QueueEvent(e, vl);
249 : : }
250 : :
251 : 0 : AddrVal* ARP_Analyzer::ConstructAddrVal(const void* addr)
252 : : {
253 : : // ### For now, we only handle IPv4 addresses.
254 : 0 : return new AddrVal(*(const uint32*) addr);
255 : : }
256 : :
257 : 0 : StringVal* ARP_Analyzer::EthAddrToStr(const u_char* addr)
258 : : {
259 : : char buf[1024];
260 : : snprintf(buf, sizeof(buf), "%02x:%02x:%02x:%02x:%02x:%02x",
261 : 0 : addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);
262 : 0 : return new StringVal(buf);
263 [ + - ][ + - ]: 6 : }
|