00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #ifndef WIFI_FRAME_HASH_HXX_
00023 # define WIFI_FRAME_HASH_HXX_
00024
00025 # include <wipal/tool/options.hh>
00026 # include <wipal/pcap/list_of_traces.hh>
00027
00028 # include <wipal/wifi/frame/unique_id/hash.hh>
00029 # include <wipal/wifi/frame/frame.hh>
00030 # include <wipal/wifi/frame/mgt.hh>
00031
00032 # include <wipal/proto/en2.hh>
00033 # include <wipal/proto/llc.hh>
00034 # include <wipal/proto/snap.hh>
00035
00036 namespace wifi
00037 {
00038
00039 namespace frame
00040 {
00041
00042 namespace internals
00043 {
00044
00045 hash_value::hash_value(const void* data, size_t len)
00046 {
00047 MD5(static_cast<const unsigned char*> (data), len, &this->front());
00048 }
00049
00050 inline
00051 bool
00052 unique_udp(const udp::header* const h, const size_t caplen)
00053 {
00054 if (caplen < sizeof (*h))
00055 return false;
00056
00057 switch (tool::extract_big_endian_short_u(h->ports[udp::header::dp]))
00058 {
00059 case udp::port::OLSR:
00060
00061
00062
00063
00064 return caplen >= sizeof (udp::header) + 4;
00065
00066 default:
00067 return false;
00068 }
00069 }
00070
00071 inline
00072 bool
00073 unique_icmp6(const icmp6::header* const h, const size_t caplen)
00074 {
00075 if (caplen < sizeof (*h))
00076 return false;
00077
00078 return h->type == icmp6::type::router_adv;
00079 }
00080
00081 inline
00082 bool
00083 unique_ip4(const ip4::header* const h,
00084 const size_t caplen,
00085 const ip4::addr* const ignore)
00086 {
00087 if (caplen < sizeof (*h))
00088 return false;
00089
00090 const size_t len = (h->headerlength & 0xF) << 2;
00091
00092 if (caplen < len or (ignore and *ignore == h->addrs[ip4::header::sa]))
00093 return false;
00094
00095 switch (h->ipproto)
00096 {
00097 case ip4::proto::UDP:
00098 {
00099 const uint8_t* const p = reinterpret_cast<const uint8_t*> (h);
00100
00101 return unique_udp(reinterpret_cast<const udp::header*> (p + len),
00102 caplen - len);
00103 }
00104
00105 default:
00106 return false;
00107 }
00108 }
00109
00110 inline
00111 bool
00112 unique_ip6(const ip6::header* const h,
00113 const size_t caplen,
00114 const ip6::addr* const ignore)
00115 {
00116 if (caplen < sizeof (*h) or (ignore and
00117 *ignore == h->addrs[ip6::header::sa]))
00118 return false;
00119
00120 switch (h->nextheader)
00121 {
00122 case ip6::proto::ICMPv6:
00123 return unique_icmp6(reinterpret_cast<const icmp6::header*> (h + 1),
00124 caplen - sizeof (*h));
00125
00126 case ip6::proto::UDP:
00127 return unique_udp(reinterpret_cast<const udp::header*> (h + 1),
00128 caplen - sizeof (*h));
00129
00130 default:
00131 return false;
00132 }
00133 }
00134
00135 template <class Addr, class D>
00136 boost::optional<Addr>
00137 get(const pcapxx::frame_descriptor<D>& f)
00138 {
00139 typedef const D* desc_ptr;
00140 typedef typename pcapxx::list_of_traces<D>* list_ptr;
00141 typedef const typename pcapxx::list_of_traces<D>* list_const_ptr;
00142
00143 boost::optional<Addr> r;
00144 const desc_ptr d = f.desc_ptr();
00145
00146 if (d)
00147 {
00148 const tool::opt::list& m = d->metadata();
00149
00150 if (m.count("addr"))
00151 r = Addr (m["addr"].get<std::string>());
00152 else if (m.count("list_of_traces"))
00153 {
00154 const list_const_ptr l = m["list_of_traces"].get<list_ptr>();
00155 const tool::opt::list& lm = l->metadata();
00156
00157 if (lm.count("addr"))
00158 r = Addr (lm["addr"].get<std::string>());
00159 }
00160 }
00161
00162 return r;
00163 }
00164
00165 struct hash_hooks_80211: public dissector_default_hooks
00166 {
00167
00168 inline
00169 void
00170 probe_resp_hook(const mgt::header* frame, size_t caplen)
00171 {
00172 if (not control_flag(3, frame))
00173 result_ = hash_value (frame, caplen);
00174 }
00175
00176 inline
00177 void
00178 beacon_hook(const mgt::header* frame, size_t caplen)
00179 {
00180 result_ = hash_value (frame, caplen);
00181 }
00182
00183 boost::optional<hash_value> result_;
00184 };
00185
00186 struct hash_hooks_80211_OLSR: public hash_hooks_80211
00187 {
00188
00189 inline
00190 hash_hooks_80211_OLSR(): orig_data_ (false)
00191 {
00192 }
00193
00194 inline
00195 void
00196 data_hook(const void* frame, size_t)
00197 {
00198 if (not control_flag(3, frame))
00199 orig_data_ = true;
00200 }
00201
00202 inline
00203 void
00204 end_of_frame_headers_hook(const void* frame,
00205 size_t caplen,
00206 const void* pload)
00207 {
00208 typedef const llc::header* llc_hdr;
00209 typedef const snap::header* snp_hdr;
00210 typedef const ip4::header* ip4_hdr;
00211 typedef const ip6::header* ip6_hdr;
00212
00213 if (not orig_data_)
00214 return;
00215
00216 const size_t plen = caplen - (static_cast<const uint8_t*> (pload) -
00217 static_cast<const uint8_t*> (frame));
00218 const size_t hlen = sizeof (llc::header) + sizeof (snap::header);
00219
00220 if (plen < hlen)
00221 return;
00222
00223 const llc::header* l = static_cast<llc_hdr> (pload);
00224
00225 if (l->dsap != 0xAA or l->ssap != 0xAA)
00226 return;
00227
00228 const snp_hdr snap = reinterpret_cast<snp_hdr> (l + 1);
00229 static const uint8_t snap_ip4[] = { 0x00, 0x00, 0x00, 0x08, 0x00 };
00230 static const uint8_t snap_ip6[] = { 0x00, 0x00, 0x00, 0x86, 0xDD };
00231
00232 if ((not memcmp(snap, snap_ip4, sizeof (snap_ip4)) and
00233 unique_ip4(reinterpret_cast<ip4_hdr> (snap + 1), plen - hlen)) or
00234 (not memcmp(snap, snap_ip6, sizeof (snap_ip6)) and
00235 unique_ip6(reinterpret_cast<ip6_hdr> (snap + 1), plen - hlen)))
00236 result_ = hash_value (frame, caplen);
00237 }
00238
00239 protected:
00240 bool orig_data_;
00241 };
00242
00243 }
00244
00245 template <class HeaderType, class D>
00246 boost::optional<hsh_80211_id>
00247 unique_id_factory<hsh_80211_id>::
00248 build(const pcapxx::frame_descriptor<D>& desc, addr_mapping&)
00249 {
00250 WP_UNIQUE_ID_DISSECT(desc, d, internals::hash_hooks_80211, h);
00251
00252 if (h.result_)
00253 return hsh_80211_id (desc.id(), h.result_.get());
00254 else
00255 return boost::none_t ();
00256 }
00257
00258 template <class HeaderType, class D>
00259 boost::optional<hsh_80211_x_id>
00260 unique_id_factory<hsh_80211_x_id>::
00261 build(const pcapxx::frame_descriptor<D>& desc, addr_mapping&)
00262 {
00263 WP_UNIQUE_ID_DISSECT(desc, d, internals::hash_hooks_80211_OLSR, h);
00264
00265 if (h.result_)
00266 return hsh_80211_x_id (desc.id(), h.result_.get());
00267 else
00268 return boost::none_t ();
00269 }
00270
00271 template <class HeaderType, class D>
00272 boost::optional<hsh_en2_id>
00273 unique_id_factory<hsh_en2_id>::
00274 build(const pcapxx::frame_descriptor<D>& desc, addr_mapping&)
00275 {
00276 typedef const en2::header* en2_hdr;
00277 typedef const ip4::header* ip4_hdr;
00278 typedef const ip6::header* ip6_hdr;
00279
00280 const size_t caplen = desc.pcap_header()->caplen;
00281
00282 if (caplen < sizeof (en2::header))
00283 return boost::none_t ();
00284
00285 const en2_hdr hdr = reinterpret_cast<en2_hdr> (desc.bytes().get());
00286 bool uniq;
00287
00288 switch (tool::extract_big_endian_short_u(hdr->ethertype))
00289 {
00290 case en2::type::IP:
00291 {
00292 boost::optional<ip4::addr> a = internals::get<ip4::addr>(desc);
00293
00294 uniq = internals::unique_ip4(reinterpret_cast<ip4_hdr> (hdr->data),
00295 caplen - sizeof (*hdr),
00296 a.get_ptr());
00297 }
00298 break;
00299
00300 case en2::type::IPv6:
00301 uniq = internals::unique_ip6(reinterpret_cast<ip6_hdr> (hdr->data),
00302 caplen - sizeof (*hdr));
00303 break;
00304
00305 default:
00306 uniq = false;
00307 break;
00308 }
00309
00310 if (uniq)
00311 return hsh_en2_id (desc.id(), internals::hash_value (hdr, caplen));
00312 else
00313 return boost::none_t ();
00314 }
00315
00316 }
00317
00318 }
00319
00320 WP_HASH_NAMESPACE_BEGIN
00321
00322 inline
00323 size_t
00324 hash<wifi::frame::internals::hash_value>::
00325 operator () (const wifi::frame::internals::hash_value& v) const
00326 {
00327 typedef wifi::frame::internals::hash_value hash_value;
00328 typedef hash_value::value_type value_type;
00329 typedef hash_value::const_iterator const_iterator;
00330
00331 size_t r = 0;
00332 const_iterator i = v.begin();
00333 const const_iterator e = v.end();
00334
00335 while (i != e)
00336 for (unsigned j = 0; i != e and j < sizeof (size_t); ++i, ++j)
00337 r ^= (*i << (j * 8));
00338
00339 return r;
00340 }
00341
00342 WP_HASH_NAMESPACE_END
00343
00344 #endif // ! WIFI_FRAME_HASH_HXX_