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