mirror of
https://github.com/mfontanini/libtins
synced 2026-01-23 18:55:58 +01:00
Compare commits
42 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ed175e0ad6 | ||
|
|
c5404a6111 | ||
|
|
6d7e06535a | ||
|
|
853e1ce647 | ||
|
|
dbcdda9d36 | ||
|
|
17ceba6064 | ||
|
|
52078cc567 | ||
|
|
e2656739f1 | ||
|
|
33091ccbae | ||
|
|
ca6b603478 | ||
|
|
069ae82b10 | ||
|
|
ea6638c163 | ||
|
|
112a357726 | ||
|
|
0e54579200 | ||
|
|
ccb8ffd1b5 | ||
|
|
b83c1a2a96 | ||
|
|
81a947e3b3 | ||
|
|
1cec0f106d | ||
|
|
0acb0fee3e | ||
|
|
9b57585b62 | ||
|
|
2ddec368c3 | ||
|
|
83dc8819b6 | ||
|
|
5e668e6e83 | ||
|
|
ca4912ded4 | ||
|
|
295ebb679c | ||
|
|
6355aff3cd | ||
|
|
a6655191d4 | ||
|
|
dc6c37777b | ||
|
|
23552ea105 | ||
|
|
9962381fc7 | ||
|
|
93ab8d3b91 | ||
|
|
5345b29f8c | ||
|
|
de06fee5ab | ||
|
|
6d329424f1 | ||
|
|
dfbbea33d5 | ||
|
|
0b02af616a | ||
|
|
a101ec9796 | ||
|
|
b0868b5d60 | ||
|
|
f57b8c189c | ||
|
|
a507355e27 | ||
|
|
87fdd62b57 | ||
|
|
3337335df2 |
54
CHANGES
54
CHANGES
@@ -1,3 +1,57 @@
|
||||
v2.0 - Thu Jan 23 11:09:38 ART 2014
|
||||
|
||||
- DNSResourceRecord was removed. Now DNS records are added using
|
||||
DNS::Resource.
|
||||
|
||||
- tins.h now includes ppi.h.
|
||||
|
||||
- Done significant improvements in the speed of DNS parsing.
|
||||
|
||||
- Added PDUOption<>::to<> which converts a PDUOption to a specific type.
|
||||
|
||||
- Layer 3 packets sent using PacketSender::send_recv for which the
|
||||
answer is a different PDU type.
|
||||
|
||||
- ICMP::gateway now uses IPv4Address.
|
||||
|
||||
- Added support for ICMP address mask request/reply.
|
||||
|
||||
- Fixed bug in PacketSender when using send_recv and a layer 2 PDU. The
|
||||
interface in which the packet was sent was not the default_interface
|
||||
set when the sender was constructed.
|
||||
|
||||
- IP packets sent using PacketSender::send_recv now match ICMP
|
||||
responses.
|
||||
|
||||
- Added support for ICMP timestamp request/reply packets.
|
||||
ICMP::matches_response now works with these types of packets as well.
|
||||
|
||||
- Added support for reassembling of fragmented IP packets via the
|
||||
IPv4Reassembler class.
|
||||
|
||||
- Fragmented IP packet's inner_pdu PDUs are not decoded now.
|
||||
|
||||
- Added 1000ms as the default read timeout used when calling
|
||||
pcap_open_live. Added BaseSniffer::set_timeout to modify this parameter.
|
||||
|
||||
- Added the --disable-dot11 configure switch.
|
||||
|
||||
- Added support for IPSec.
|
||||
|
||||
- Fixed bug triggered when ifaddrs::ifa_addr was null in
|
||||
NetworkInterface::addresses.
|
||||
|
||||
- Added another overload of Utils::route_entries which returns the
|
||||
result either than storing it in a parameter.
|
||||
|
||||
- Added ARP monitor, WPS detector, DNS queries sniffer and DNS spoofer
|
||||
examples.
|
||||
|
||||
- Added another Sniffer constructor which doesn't expect the maximum
|
||||
capture size.
|
||||
|
||||
- Added tins_cast as a replacement for dynamic_cast on PDUs.
|
||||
|
||||
v1.2 - Mon oct 7 23:33:49 ART 2013
|
||||
|
||||
- Added BaseSniffer::begin and BaseSniffer::end.
|
||||
|
||||
@@ -20,7 +20,6 @@ libtins_la_SOURCES=src/arp.cpp \
|
||||
src/dhcp.cpp \
|
||||
src/dhcpv6.cpp \
|
||||
src/dns.cpp \
|
||||
src/dns_record.cpp \
|
||||
src/dot3.cpp \
|
||||
src/dot1q.cpp \
|
||||
src/eapol.cpp \
|
||||
@@ -28,9 +27,12 @@ libtins_la_SOURCES=src/arp.cpp \
|
||||
src/icmp.cpp \
|
||||
src/icmpv6.cpp \
|
||||
src/internals.cpp \
|
||||
src/ip.cpp src/ip_address.cpp \
|
||||
src/ip_reassembler.cpp \
|
||||
src/ip.cpp \
|
||||
src/ip_address.cpp \
|
||||
src/ipv6.cpp \
|
||||
src/ipv6_address.cpp \
|
||||
src/ipsec.cpp \
|
||||
src/llc.cpp \
|
||||
src/loopback.cpp \
|
||||
src/network_interface.cpp \
|
||||
@@ -67,7 +69,7 @@ libtins_HEADERS = include/internals.h \
|
||||
include/dot3.h \
|
||||
include/small_uint.h \
|
||||
include/ip.h \
|
||||
include/dns_record.h \
|
||||
include/ipsec.h \
|
||||
include/eapol.h \
|
||||
include/tcp_stream.h \
|
||||
include/pppoe.h \
|
||||
@@ -82,6 +84,7 @@ libtins_HEADERS = include/internals.h \
|
||||
include/crypto.h \
|
||||
include/packet.h \
|
||||
include/llc.h \
|
||||
include/ip_reassembler.h \
|
||||
include/icmp.h \
|
||||
include/hw_address.h \
|
||||
include/packet_writer.h \
|
||||
|
||||
34
Makefile.in
34
Makefile.in
@@ -59,8 +59,8 @@ DIST_COMMON = README $(am__configure_deps) $(libtins_HEADERS) \
|
||||
$(libtins_dot11_HEADERS) $(srcdir)/Makefile.am \
|
||||
$(srcdir)/Makefile.in $(srcdir)/libtins.pc.in \
|
||||
$(top_srcdir)/configure $(top_srcdir)/include/config.h.in \
|
||||
AUTHORS COPYING INSTALL THANKS TODO config.guess config.sub \
|
||||
depcomp install-sh ltmain.sh missing
|
||||
AUTHORS THANKS config.guess config.sub depcomp install-sh \
|
||||
ltmain.sh missing
|
||||
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
|
||||
am__aclocal_m4_deps = $(top_srcdir)/m4/ax_cxx_compile_stdcxx_11.m4 \
|
||||
$(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
|
||||
@@ -108,10 +108,10 @@ libtins_la_LIBADD =
|
||||
am__dirstamp = $(am__leading_dot)dirstamp
|
||||
am_libtins_la_OBJECTS = src/arp.lo src/bootp.lo \
|
||||
src/handshake_capturer.lo src/stp.lo src/pppoe.lo \
|
||||
src/crypto.lo src/dhcp.lo src/dhcpv6.lo src/dns.lo \
|
||||
src/dns_record.lo src/dot3.lo src/dot1q.lo src/eapol.lo \
|
||||
src/ethernetII.lo src/icmp.lo src/icmpv6.lo src/internals.lo \
|
||||
src/ip.lo src/ip_address.lo src/ipv6.lo src/ipv6_address.lo \
|
||||
src/crypto.lo src/dhcp.lo src/dhcpv6.lo src/dns.lo src/dot3.lo \
|
||||
src/dot1q.lo src/eapol.lo src/ethernetII.lo src/icmp.lo \
|
||||
src/icmpv6.lo src/internals.lo src/ip_reassembler.lo src/ip.lo \
|
||||
src/ip_address.lo src/ipv6.lo src/ipv6_address.lo src/ipsec.lo \
|
||||
src/llc.lo src/loopback.lo src/network_interface.lo \
|
||||
src/packet_sender.lo src/packet_writer.lo src/ppi.lo \
|
||||
src/pdu.lo src/radiotap.lo src/address_range.lo src/rawpdu.lo \
|
||||
@@ -308,7 +308,6 @@ libtins_la_SOURCES = src/arp.cpp \
|
||||
src/dhcp.cpp \
|
||||
src/dhcpv6.cpp \
|
||||
src/dns.cpp \
|
||||
src/dns_record.cpp \
|
||||
src/dot3.cpp \
|
||||
src/dot1q.cpp \
|
||||
src/eapol.cpp \
|
||||
@@ -316,9 +315,12 @@ libtins_la_SOURCES = src/arp.cpp \
|
||||
src/icmp.cpp \
|
||||
src/icmpv6.cpp \
|
||||
src/internals.cpp \
|
||||
src/ip.cpp src/ip_address.cpp \
|
||||
src/ip_reassembler.cpp \
|
||||
src/ip.cpp \
|
||||
src/ip_address.cpp \
|
||||
src/ipv6.cpp \
|
||||
src/ipv6_address.cpp \
|
||||
src/ipsec.cpp \
|
||||
src/llc.cpp \
|
||||
src/loopback.cpp \
|
||||
src/network_interface.cpp \
|
||||
@@ -354,7 +356,7 @@ libtins_HEADERS = include/internals.h \
|
||||
include/dot3.h \
|
||||
include/small_uint.h \
|
||||
include/ip.h \
|
||||
include/dns_record.h \
|
||||
include/ipsec.h \
|
||||
include/eapol.h \
|
||||
include/tcp_stream.h \
|
||||
include/pppoe.h \
|
||||
@@ -369,6 +371,7 @@ libtins_HEADERS = include/internals.h \
|
||||
include/crypto.h \
|
||||
include/packet.h \
|
||||
include/llc.h \
|
||||
include/ip_reassembler.h \
|
||||
include/icmp.h \
|
||||
include/hw_address.h \
|
||||
include/packet_writer.h \
|
||||
@@ -516,7 +519,6 @@ src/crypto.lo: src/$(am__dirstamp) src/$(DEPDIR)/$(am__dirstamp)
|
||||
src/dhcp.lo: src/$(am__dirstamp) src/$(DEPDIR)/$(am__dirstamp)
|
||||
src/dhcpv6.lo: src/$(am__dirstamp) src/$(DEPDIR)/$(am__dirstamp)
|
||||
src/dns.lo: src/$(am__dirstamp) src/$(DEPDIR)/$(am__dirstamp)
|
||||
src/dns_record.lo: src/$(am__dirstamp) src/$(DEPDIR)/$(am__dirstamp)
|
||||
src/dot3.lo: src/$(am__dirstamp) src/$(DEPDIR)/$(am__dirstamp)
|
||||
src/dot1q.lo: src/$(am__dirstamp) src/$(DEPDIR)/$(am__dirstamp)
|
||||
src/eapol.lo: src/$(am__dirstamp) src/$(DEPDIR)/$(am__dirstamp)
|
||||
@@ -524,10 +526,13 @@ src/ethernetII.lo: src/$(am__dirstamp) src/$(DEPDIR)/$(am__dirstamp)
|
||||
src/icmp.lo: src/$(am__dirstamp) src/$(DEPDIR)/$(am__dirstamp)
|
||||
src/icmpv6.lo: src/$(am__dirstamp) src/$(DEPDIR)/$(am__dirstamp)
|
||||
src/internals.lo: src/$(am__dirstamp) src/$(DEPDIR)/$(am__dirstamp)
|
||||
src/ip_reassembler.lo: src/$(am__dirstamp) \
|
||||
src/$(DEPDIR)/$(am__dirstamp)
|
||||
src/ip.lo: src/$(am__dirstamp) src/$(DEPDIR)/$(am__dirstamp)
|
||||
src/ip_address.lo: src/$(am__dirstamp) src/$(DEPDIR)/$(am__dirstamp)
|
||||
src/ipv6.lo: src/$(am__dirstamp) src/$(DEPDIR)/$(am__dirstamp)
|
||||
src/ipv6_address.lo: src/$(am__dirstamp) src/$(DEPDIR)/$(am__dirstamp)
|
||||
src/ipsec.lo: src/$(am__dirstamp) src/$(DEPDIR)/$(am__dirstamp)
|
||||
src/llc.lo: src/$(am__dirstamp) src/$(DEPDIR)/$(am__dirstamp)
|
||||
src/loopback.lo: src/$(am__dirstamp) src/$(DEPDIR)/$(am__dirstamp)
|
||||
src/network_interface.lo: src/$(am__dirstamp) \
|
||||
@@ -592,8 +597,6 @@ mostlyclean-compile:
|
||||
-rm -f src/dhcpv6.lo
|
||||
-rm -f src/dns.$(OBJEXT)
|
||||
-rm -f src/dns.lo
|
||||
-rm -f src/dns_record.$(OBJEXT)
|
||||
-rm -f src/dns_record.lo
|
||||
-rm -f src/dot11/dot11_assoc.$(OBJEXT)
|
||||
-rm -f src/dot11/dot11_assoc.lo
|
||||
-rm -f src/dot11/dot11_auth.$(OBJEXT)
|
||||
@@ -630,6 +633,10 @@ mostlyclean-compile:
|
||||
-rm -f src/ip.lo
|
||||
-rm -f src/ip_address.$(OBJEXT)
|
||||
-rm -f src/ip_address.lo
|
||||
-rm -f src/ip_reassembler.$(OBJEXT)
|
||||
-rm -f src/ip_reassembler.lo
|
||||
-rm -f src/ipsec.$(OBJEXT)
|
||||
-rm -f src/ipsec.lo
|
||||
-rm -f src/ipv6.$(OBJEXT)
|
||||
-rm -f src/ipv6.lo
|
||||
-rm -f src/ipv6_address.$(OBJEXT)
|
||||
@@ -683,7 +690,6 @@ distclean-compile:
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/dhcp.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/dhcpv6.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/dns.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/dns_record.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/dot1q.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/dot3.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/eapol.Plo@am__quote@
|
||||
@@ -694,6 +700,8 @@ distclean-compile:
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/internals.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/ip.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/ip_address.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/ip_reassembler.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/ipsec.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/ipv6.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/ipv6_address.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/llc.Plo@am__quote@
|
||||
|
||||
33
README
33
README
@@ -1,24 +1,27 @@
|
||||
------------------------------------------------------------------------
|
||||
libtins v1.1
|
||||
libtins v2.0
|
||||
------------------------------------------------------------------------
|
||||
|
||||
|
||||
-------------------------------- About ---------------------------------
|
||||
|
||||
libtins is a C++ library for crafting, sending, sniffing and
|
||||
interpreting raw network packets.
|
||||
libtins is a high-level, multiplatform C++ network packet sniffing and
|
||||
crafting library.
|
||||
|
||||
Its main purpose is to provide the C++ developer an easy, efficient,
|
||||
platform and endianess-independent way to create tools which need to
|
||||
send, receive and manipulate specially crafted packets.
|
||||
|
||||
In order to read tutorials, examples and checkout some benchmarks which
|
||||
show libtins' actual performance, please visit:
|
||||
In order to read tutorials, examples and checkout some benchmarks of the
|
||||
library, please visit:
|
||||
|
||||
http://libtins.sourceforge.net
|
||||
http://libtins.github.io/
|
||||
|
||||
------------------------------- Compiling ------------------------------
|
||||
|
||||
libtins depends on libpcap and openssl, although the latter is not
|
||||
necessary if some features of the library are disabled.
|
||||
|
||||
In order to compile, execute:
|
||||
|
||||
./configure
|
||||
@@ -32,11 +35,23 @@ like to generate a static library file as well, run:
|
||||
The generated static/shared library files will be located in the .libs
|
||||
directory.
|
||||
|
||||
If you want to enable C++11 features, such as move semantics, use the
|
||||
--enable-c++11 switch:
|
||||
libtins is noticeable faster if you enable C++11 support. Therefore, if
|
||||
your compiler supports this standard, then you should enable it. In
|
||||
order to do so, use the --enable-c++11 switch:
|
||||
|
||||
./configure --enable-c++11
|
||||
|
||||
If you want to disable WPA2 decryption support, which will remove
|
||||
openssl as a dependency for compilation, use the --disable-wpa2 switch:
|
||||
|
||||
./configure --disable-wpa2
|
||||
|
||||
If you want to disable IEEE 802.11 support(this will also disable
|
||||
RadioTap and WPA2 decryption), which will reduce the size of the
|
||||
resulting library in around 20%, use the --disable-dot11 switch:
|
||||
|
||||
./configure --disable-dot11
|
||||
|
||||
------------------------------ Installing-------------------------------
|
||||
|
||||
Once you're done, if you want to install the header files and the
|
||||
@@ -55,4 +70,4 @@ ldconfig
|
||||
You might want to have a look at the examples located in the "examples"
|
||||
directory. The same samples can be found online at:
|
||||
|
||||
http://libtins.sourceforge.net/index.php?page=examples
|
||||
http://libtins.github.io/examples/
|
||||
|
||||
85
README.md
Normal file
85
README.md
Normal file
@@ -0,0 +1,85 @@
|
||||
libtins
|
||||
=======
|
||||
|
||||
libtins is a high-level, multiplatform C++ network packet sniffing and
|
||||
crafting library.
|
||||
|
||||
Its main purpose is to provide the C++ developer an easy, efficient,
|
||||
platform and endianess-independent way to create tools which need to
|
||||
send, receive and manipulate specially crafted packets.
|
||||
|
||||
In order to read tutorials, examples and checkout some benchmarks of the
|
||||
library, please visit:
|
||||
|
||||
http://libtins.github.io/
|
||||
|
||||
## Compiling ##
|
||||
|
||||
[libtins](http://libtins.github.io/) depends on
|
||||
[libpcap](http://www.tcpdump.org/) and
|
||||
[openssl](http://www.openssl.org/), although the latter is not necessary
|
||||
if some features of the library are disabled.
|
||||
|
||||
In order to compile, execute:
|
||||
|
||||
```Shell
|
||||
./configure
|
||||
make
|
||||
```
|
||||
|
||||
Note that by default, only the shared object is compiled. If you would
|
||||
like to generate a static library file as well, run:
|
||||
|
||||
```Shell
|
||||
./configure --enable-static
|
||||
```
|
||||
|
||||
The generated static/shared library files will be located in the .libs
|
||||
directory.
|
||||
|
||||
libtins is noticeable faster if you enable C++11 support. Therefore, if
|
||||
your compiler supports this standard, then you should enable it. In
|
||||
order to do so, use the --enable-c++11 switch:
|
||||
|
||||
```Shell
|
||||
./configure --enable-c++11
|
||||
```
|
||||
|
||||
If you want to disable WPA2 decryption support, which will remove
|
||||
openssl as a dependency for compilation, use the --disable-wpa2 switch:
|
||||
|
||||
```Shell
|
||||
./configure --disable-wpa2
|
||||
```
|
||||
|
||||
If you want to disable IEEE 802.11 support(this will also disable
|
||||
RadioTap and WPA2 decryption), which will reduce the size of the
|
||||
resulting library in around 20%, use the --disable-dot11 switch:
|
||||
|
||||
```Shell
|
||||
./configure --disable-dot11
|
||||
```
|
||||
|
||||
## Installing ##
|
||||
|
||||
Once you're done, if you want to install the header files and the
|
||||
shared object, execute as root:
|
||||
|
||||
```Shell
|
||||
make install
|
||||
```
|
||||
|
||||
This will install the shared object typically in /usr/local/lib. Note
|
||||
that you might have to update ldconfig's cache before using it, so
|
||||
in order to invalidate it, you should run(as root):
|
||||
|
||||
```Shell
|
||||
ldconfig
|
||||
```
|
||||
|
||||
## Examples ##
|
||||
|
||||
You might want to have a look at the examples located in the "examples"
|
||||
directory. The same samples can be found online at:
|
||||
|
||||
http://libtins.github.io/examples/
|
||||
44
configure
vendored
44
configure
vendored
@@ -1,6 +1,6 @@
|
||||
#! /bin/sh
|
||||
# Guess values for system-dependent variables and create Makefiles.
|
||||
# Generated by GNU Autoconf 2.69 for libtins 1.2.
|
||||
# Generated by GNU Autoconf 2.69 for libtins 2.0.
|
||||
#
|
||||
# Report bugs to <matias.fontanini@gmail.com>.
|
||||
#
|
||||
@@ -590,8 +590,8 @@ MAKEFLAGS=
|
||||
# Identity of this package.
|
||||
PACKAGE_NAME='libtins'
|
||||
PACKAGE_TARNAME='libtins'
|
||||
PACKAGE_VERSION='1.2'
|
||||
PACKAGE_STRING='libtins 1.2'
|
||||
PACKAGE_VERSION='2.0'
|
||||
PACKAGE_STRING='libtins 2.0'
|
||||
PACKAGE_BUGREPORT='matias.fontanini@gmail.com'
|
||||
PACKAGE_URL='http://libtins.sourceforge.net'
|
||||
|
||||
@@ -775,6 +775,7 @@ enable_maintainer_mode
|
||||
with_pcap_include_path
|
||||
with_pcap_lib_path
|
||||
enable_c__11
|
||||
enable_dot11
|
||||
enable_wpa2
|
||||
'
|
||||
ac_precious_vars='build_alias
|
||||
@@ -1330,7 +1331,7 @@ if test "$ac_init_help" = "long"; then
|
||||
# Omit some internal or obsolete options to make the list less imposing.
|
||||
# This message is too long to be a string in the A/UX 3.1 sh.
|
||||
cat <<_ACEOF
|
||||
\`configure' configures libtins 1.2 to adapt to many kinds of systems.
|
||||
\`configure' configures libtins 2.0 to adapt to many kinds of systems.
|
||||
|
||||
Usage: $0 [OPTION]... [VAR=VALUE]...
|
||||
|
||||
@@ -1401,7 +1402,7 @@ fi
|
||||
|
||||
if test -n "$ac_init_help"; then
|
||||
case $ac_init_help in
|
||||
short | recursive ) echo "Configuration of libtins 1.2:";;
|
||||
short | recursive ) echo "Configuration of libtins 2.0:";;
|
||||
esac
|
||||
cat <<\_ACEOF
|
||||
|
||||
@@ -1419,6 +1420,7 @@ Optional Features:
|
||||
--disable-maintainer-mode disable make rules and dependencies not useful
|
||||
(and sometimes confusing) to the casual installer
|
||||
--enable-c++11 enable C++11 features
|
||||
--disable-dot11 disable IEEE 802.11 support
|
||||
--disable-wpa2 disable WPA2 decryption features
|
||||
|
||||
Optional Packages:
|
||||
@@ -1514,7 +1516,7 @@ fi
|
||||
test -n "$ac_init_help" && exit $ac_status
|
||||
if $ac_init_version; then
|
||||
cat <<\_ACEOF
|
||||
libtins configure 1.2
|
||||
libtins configure 2.0
|
||||
generated by GNU Autoconf 2.69
|
||||
|
||||
Copyright (C) 2012 Free Software Foundation, Inc.
|
||||
@@ -2004,7 +2006,7 @@ cat >config.log <<_ACEOF
|
||||
This file contains any messages produced by compilers while
|
||||
running configure, to aid debugging if configure makes a mistake.
|
||||
|
||||
It was created by libtins $as_me 1.2, which was
|
||||
It was created by libtins $as_me 2.0, which was
|
||||
generated by GNU Autoconf 2.69. Invocation command line was
|
||||
|
||||
$ $0 $@
|
||||
@@ -2932,7 +2934,7 @@ fi
|
||||
|
||||
# Define the identity of the package.
|
||||
PACKAGE='libtins'
|
||||
VERSION='1.2'
|
||||
VERSION='2.0'
|
||||
|
||||
|
||||
cat >>confdefs.h <<_ACEOF
|
||||
@@ -15331,12 +15333,22 @@ $as_echo "#define HAVE_CXX11 1" >>confdefs.h
|
||||
fi
|
||||
|
||||
|
||||
# Check whether --enable-wpa2 was given.
|
||||
# Check whether --enable-dot11 was given.
|
||||
if test "${enable_dot11+set}" = set; then :
|
||||
enableval=$enable_dot11;
|
||||
else
|
||||
|
||||
|
||||
$as_echo "#define HAVE_DOT11 1" >>confdefs.h
|
||||
|
||||
|
||||
# Only allow enabling WPA2 if Dot11 is enabled.
|
||||
# Check whether --enable-wpa2 was given.
|
||||
if test "${enable_wpa2+set}" = set; then :
|
||||
enableval=$enable_wpa2;
|
||||
else
|
||||
|
||||
for ac_header in openssl/evp.h openssl/hmac.h openssl/aes.h
|
||||
for ac_header in openssl/evp.h openssl/hmac.h openssl/aes.h
|
||||
do :
|
||||
as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
|
||||
ac_fn_cxx_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default"
|
||||
@@ -15355,7 +15367,7 @@ fi
|
||||
|
||||
done
|
||||
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for PKCS5_PBKDF2_HMAC_SHA1 in -lcrypto" >&5
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for PKCS5_PBKDF2_HMAC_SHA1 in -lcrypto" >&5
|
||||
$as_echo_n "checking for PKCS5_PBKDF2_HMAC_SHA1 in -lcrypto... " >&6; }
|
||||
if ${ac_cv_lib_crypto_PKCS5_PBKDF2_HMAC_SHA1+:} false; then :
|
||||
$as_echo_n "(cached) " >&6
|
||||
@@ -15408,6 +15420,10 @@ $as_echo "#define HAVE_WPA2_DECRYPTION 1" >>confdefs.h
|
||||
|
||||
|
||||
|
||||
fi
|
||||
|
||||
|
||||
|
||||
fi
|
||||
|
||||
|
||||
@@ -15416,7 +15432,7 @@ fi
|
||||
|
||||
|
||||
|
||||
LIBTINS_VERSION=1:1:0
|
||||
LIBTINS_VERSION=2:0:0
|
||||
|
||||
ac_config_files="$ac_config_files Makefile libtins.pc"
|
||||
|
||||
@@ -15950,7 +15966,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
|
||||
# report actual input values of CONFIG_FILES etc. instead of their
|
||||
# values after options handling.
|
||||
ac_log="
|
||||
This file was extended by libtins $as_me 1.2, which was
|
||||
This file was extended by libtins $as_me 2.0, which was
|
||||
generated by GNU Autoconf 2.69. Invocation command line was
|
||||
|
||||
CONFIG_FILES = $CONFIG_FILES
|
||||
@@ -16017,7 +16033,7 @@ _ACEOF
|
||||
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
|
||||
ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
|
||||
ac_cs_version="\\
|
||||
libtins config.status 1.2
|
||||
libtins config.status 2.0
|
||||
configured by $0, generated by GNU Autoconf 2.69,
|
||||
with options \\"\$ac_cs_config\\"
|
||||
|
||||
|
||||
42
configure.ac
42
configure.ac
@@ -1,4 +1,4 @@
|
||||
AC_INIT([libtins], [1.2], [matias.fontanini@gmail.com], [libtins], [http://libtins.sourceforge.net])
|
||||
AC_INIT([libtins], [2.0], [matias.fontanini@gmail.com], [libtins], [http://libtins.sourceforge.net])
|
||||
AC_CANONICAL_SYSTEM
|
||||
AC_CONFIG_HEADER(include/config.h)
|
||||
AM_INIT_AUTOMAKE([-Wall -Werror -Wno-extra-portability foreign])
|
||||
@@ -45,23 +45,33 @@ AC_ARG_ENABLE(
|
||||
)
|
||||
|
||||
AC_ARG_ENABLE(
|
||||
wpa2,
|
||||
[ --disable-wpa2 disable WPA2 decryption features],
|
||||
dot11,
|
||||
[ --disable-dot11 disable IEEE 802.11 support],
|
||||
[],
|
||||
[
|
||||
AC_CHECK_HEADERS(
|
||||
[openssl/evp.h openssl/hmac.h openssl/aes.h],
|
||||
[],
|
||||
[AC_MSG_ERROR([openssl headers are missing! $wpa2_msg ])]
|
||||
AC_DEFINE([HAVE_WPA2_DECRYPTION], 0, Have WPA2 decryption library)
|
||||
AC_DEFINE([HAVE_DOT11], 1, Have IEEE 802.11 support)
|
||||
|
||||
# Only allow enabling WPA2 if Dot11 is enabled.
|
||||
AC_ARG_ENABLE(
|
||||
wpa2,
|
||||
[ --disable-wpa2 disable WPA2 decryption features],
|
||||
[],
|
||||
[
|
||||
AC_CHECK_HEADERS(
|
||||
[openssl/evp.h openssl/hmac.h openssl/aes.h],
|
||||
[],
|
||||
[AC_MSG_ERROR([openssl headers are missing! $wpa2_msg ])]
|
||||
AC_DEFINE([HAVE_WPA2_DECRYPTION], 0, Have WPA2 decryption library)
|
||||
)
|
||||
AC_CHECK_LIB(
|
||||
crypto,
|
||||
PKCS5_PBKDF2_HMAC_SHA1,
|
||||
[],
|
||||
[AC_MSG_ERROR([openssl library is missing! $wpa2_msg ])]
|
||||
)
|
||||
AC_DEFINE([HAVE_WPA2_DECRYPTION], 1, Have WPA2 decryption library)
|
||||
]
|
||||
)
|
||||
AC_CHECK_LIB(
|
||||
crypto,
|
||||
PKCS5_PBKDF2_HMAC_SHA1,
|
||||
[],
|
||||
[AC_MSG_ERROR([openssl library is missing! $wpa2_msg ])]
|
||||
)
|
||||
AC_DEFINE([HAVE_WPA2_DECRYPTION], 1, Have WPA2 decryption library)
|
||||
]
|
||||
)
|
||||
|
||||
@@ -70,6 +80,6 @@ AC_ARG_ENABLE(
|
||||
AC_SUBST(CXXFLAGS)
|
||||
AC_SUBST(LIBS)
|
||||
AC_SUBST(LIBTINS_INCLUDE_DIR)
|
||||
AC_SUBST([LIBTINS_VERSION], [1:1:0])
|
||||
AC_SUBST([LIBTINS_VERSION], [2:0:0])
|
||||
AC_CONFIG_FILES([Makefile libtins.pc])
|
||||
AC_OUTPUT
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
CXX=@CXX@
|
||||
CXXFLAGS=-Wall @CXXFLAGS@
|
||||
LDFLAGS=-ltins
|
||||
EXECUTABLES=arpspoof portscan traceroute beacon_display
|
||||
EXECUTABLES=arpspoofing arpmonitor portscan traceroute beacon_display dns_queries dns_spoof wps_detect
|
||||
|
||||
all: $(EXECUTABLES)
|
||||
|
||||
@@ -9,11 +9,23 @@ compile: $(OBJECTS)
|
||||
|
||||
recompile: clean all
|
||||
|
||||
arpspoof:
|
||||
arpspoofing:
|
||||
$(CXX) arpspoofing.cpp -o arpspoofing $(CXXFLAGS) $(LDFLAGS)
|
||||
|
||||
arpmonitor:
|
||||
$(CXX) arpmonitor.cpp -o arpmonitor -std=c++0x $(CXXFLAGS) $(LDFLAGS)
|
||||
|
||||
dns_queries:
|
||||
$(CXX) dns_queries.cpp -o dns_queries -std=c++0x $(CXXFLAGS) $(LDFLAGS)
|
||||
|
||||
dns_spoof:
|
||||
$(CXX) dns_spoof.cpp -o dns_spoof -std=c++0x $(CXXFLAGS) $(LDFLAGS)
|
||||
|
||||
beacon_display:
|
||||
$(CXX) beacon_display.cpp -o beacon_display $(CXXFLAGS) $(LDFLAGS)
|
||||
|
||||
wps_detect:
|
||||
$(CXX) wps_detect.cpp -o wps_detect -std=c++0x $(CXXFLAGS) $(LDFLAGS)
|
||||
|
||||
portscan:
|
||||
$(CXX) portscan.cpp -o portscan $(CXXFLAGS) $(LDFLAGS) -lpthread
|
||||
|
||||
63
examples/arpmonitor.cpp
Normal file
63
examples/arpmonitor.cpp
Normal file
@@ -0,0 +1,63 @@
|
||||
#include <tins/tins.h>
|
||||
#include <map>
|
||||
#include <iostream>
|
||||
#include <functional>
|
||||
|
||||
using namespace Tins;
|
||||
|
||||
class arp_monitor {
|
||||
public:
|
||||
void run(Sniffer &sniffer);
|
||||
private:
|
||||
bool callback(const PDU &pdu);
|
||||
|
||||
std::map<IPv4Address, HWAddress<6>> addresses;
|
||||
};
|
||||
|
||||
void arp_monitor::run(Sniffer &sniffer)
|
||||
{
|
||||
sniffer.sniff_loop(
|
||||
std::bind(
|
||||
&arp_monitor::callback,
|
||||
this,
|
||||
std::placeholders::_1
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
bool arp_monitor::callback(const PDU &pdu)
|
||||
{
|
||||
// Retrieve the ARP layer
|
||||
const ARP &arp = pdu.rfind_pdu<ARP>();
|
||||
// Is it an ARP reply?
|
||||
if(arp.opcode() == ARP::REPLY) {
|
||||
// Let's check if there's already an entry for this address
|
||||
auto iter = addresses.find(arp.sender_ip_addr());
|
||||
if(iter == addresses.end()) {
|
||||
// We haven't seen this address. Save it.
|
||||
addresses.insert({ arp.sender_ip_addr(), arp.sender_hw_addr()});
|
||||
std::cout << "[INFO] " << arp.sender_ip_addr() << " is at "
|
||||
<< arp.sender_hw_addr() << std::endl;
|
||||
}
|
||||
else {
|
||||
// We've seen this address. If it's not the same HW address, inform it
|
||||
if(arp.sender_hw_addr() != iter->second) {
|
||||
std::cout << "[WARNING] " << arp.sender_ip_addr() << " is at "
|
||||
<< iter->second << " but also at " << arp.sender_hw_addr()
|
||||
<< std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
if(argc != 2) {
|
||||
std::cout << "Usage: " << *argv << " <interface>\n";
|
||||
return 1;
|
||||
}
|
||||
arp_monitor monitor;
|
||||
Sniffer sniffer(argv[1], 2000, true, "arp");
|
||||
monitor.run(sniffer);
|
||||
}
|
||||
460
examples/configure
vendored
460
examples/configure
vendored
@@ -1,11 +1,9 @@
|
||||
#! /bin/sh
|
||||
# Guess values for system-dependent variables and create Makefiles.
|
||||
# Generated by GNU Autoconf 2.67 for myconfig 0.1.
|
||||
# Generated by GNU Autoconf 2.69 for myconfig 0.1.
|
||||
#
|
||||
#
|
||||
# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
|
||||
# 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Free Software
|
||||
# Foundation, Inc.
|
||||
# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc.
|
||||
#
|
||||
#
|
||||
# This configure script is free software; the Free Software Foundation
|
||||
@@ -89,6 +87,7 @@ fi
|
||||
IFS=" "" $as_nl"
|
||||
|
||||
# Find who we are. Look in the path if we contain no directory separator.
|
||||
as_myself=
|
||||
case $0 in #((
|
||||
*[\\/]* ) as_myself=$0 ;;
|
||||
*) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
|
||||
@@ -133,6 +132,31 @@ export LANGUAGE
|
||||
# CDPATH.
|
||||
(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
|
||||
|
||||
# Use a proper internal environment variable to ensure we don't fall
|
||||
# into an infinite loop, continuously re-executing ourselves.
|
||||
if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then
|
||||
_as_can_reexec=no; export _as_can_reexec;
|
||||
# We cannot yet assume a decent shell, so we have to provide a
|
||||
# neutralization value for shells without unset; and this also
|
||||
# works around shells that cannot unset nonexistent variables.
|
||||
# Preserve -v and -x to the replacement shell.
|
||||
BASH_ENV=/dev/null
|
||||
ENV=/dev/null
|
||||
(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV
|
||||
case $- in # ((((
|
||||
*v*x* | *x*v* ) as_opts=-vx ;;
|
||||
*v* ) as_opts=-v ;;
|
||||
*x* ) as_opts=-x ;;
|
||||
* ) as_opts= ;;
|
||||
esac
|
||||
exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"}
|
||||
# Admittedly, this is quite paranoid, since all the known shells bail
|
||||
# out after a failed `exec'.
|
||||
$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2
|
||||
as_fn_exit 255
|
||||
fi
|
||||
# We don't want this to propagate to other subprocesses.
|
||||
{ _as_can_reexec=; unset _as_can_reexec;}
|
||||
if test "x$CONFIG_SHELL" = x; then
|
||||
as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then :
|
||||
emulate sh
|
||||
@@ -166,7 +190,8 @@ if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then :
|
||||
else
|
||||
exitcode=1; echo positional parameters were not saved.
|
||||
fi
|
||||
test x\$exitcode = x0 || exit 1"
|
||||
test x\$exitcode = x0 || exit 1
|
||||
test -x / || exit 1"
|
||||
as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO
|
||||
as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO
|
||||
eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" &&
|
||||
@@ -211,14 +236,25 @@ IFS=$as_save_IFS
|
||||
|
||||
|
||||
if test "x$CONFIG_SHELL" != x; then :
|
||||
# We cannot yet assume a decent shell, so we have to provide a
|
||||
# neutralization value for shells without unset; and this also
|
||||
# works around shells that cannot unset nonexistent variables.
|
||||
BASH_ENV=/dev/null
|
||||
ENV=/dev/null
|
||||
(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV
|
||||
export CONFIG_SHELL
|
||||
exec "$CONFIG_SHELL" "$as_myself" ${1+"$@"}
|
||||
export CONFIG_SHELL
|
||||
# We cannot yet assume a decent shell, so we have to provide a
|
||||
# neutralization value for shells without unset; and this also
|
||||
# works around shells that cannot unset nonexistent variables.
|
||||
# Preserve -v and -x to the replacement shell.
|
||||
BASH_ENV=/dev/null
|
||||
ENV=/dev/null
|
||||
(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV
|
||||
case $- in # ((((
|
||||
*v*x* | *x*v* ) as_opts=-vx ;;
|
||||
*v* ) as_opts=-v ;;
|
||||
*x* ) as_opts=-x ;;
|
||||
* ) as_opts= ;;
|
||||
esac
|
||||
exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"}
|
||||
# Admittedly, this is quite paranoid, since all the known shells bail
|
||||
# out after a failed `exec'.
|
||||
$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2
|
||||
exit 255
|
||||
fi
|
||||
|
||||
if test x$as_have_required = xno; then :
|
||||
@@ -320,6 +356,14 @@ $as_echo X"$as_dir" |
|
||||
|
||||
|
||||
} # as_fn_mkdir_p
|
||||
|
||||
# as_fn_executable_p FILE
|
||||
# -----------------------
|
||||
# Test if FILE is an executable regular file.
|
||||
as_fn_executable_p ()
|
||||
{
|
||||
test -f "$1" && test -x "$1"
|
||||
} # as_fn_executable_p
|
||||
# as_fn_append VAR VALUE
|
||||
# ----------------------
|
||||
# Append the text in VALUE to the end of the definition contained in VAR. Take
|
||||
@@ -441,6 +485,10 @@ as_cr_alnum=$as_cr_Letters$as_cr_digits
|
||||
chmod +x "$as_me.lineno" ||
|
||||
{ $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; }
|
||||
|
||||
# If we had to re-execute with $CONFIG_SHELL, we're ensured to have
|
||||
# already done that, so ensure we don't try to do so again and fall
|
||||
# in an infinite loop. This has already happened in practice.
|
||||
_as_can_reexec=no; export _as_can_reexec
|
||||
# Don't try to exec as it changes $[0], causing all sort of problems
|
||||
# (the dirname of $[0] is not the place where we might find the
|
||||
# original and so on. Autoconf is especially sensitive to this).
|
||||
@@ -475,16 +523,16 @@ if (echo >conf$$.file) 2>/dev/null; then
|
||||
# ... but there are two gotchas:
|
||||
# 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
|
||||
# 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
|
||||
# In both cases, we have to default to `cp -p'.
|
||||
# In both cases, we have to default to `cp -pR'.
|
||||
ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
|
||||
as_ln_s='cp -p'
|
||||
as_ln_s='cp -pR'
|
||||
elif ln conf$$.file conf$$ 2>/dev/null; then
|
||||
as_ln_s=ln
|
||||
else
|
||||
as_ln_s='cp -p'
|
||||
as_ln_s='cp -pR'
|
||||
fi
|
||||
else
|
||||
as_ln_s='cp -p'
|
||||
as_ln_s='cp -pR'
|
||||
fi
|
||||
rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
|
||||
rmdir conf$$.dir 2>/dev/null
|
||||
@@ -496,28 +544,8 @@ else
|
||||
as_mkdir_p=false
|
||||
fi
|
||||
|
||||
if test -x / >/dev/null 2>&1; then
|
||||
as_test_x='test -x'
|
||||
else
|
||||
if ls -dL / >/dev/null 2>&1; then
|
||||
as_ls_L_option=L
|
||||
else
|
||||
as_ls_L_option=
|
||||
fi
|
||||
as_test_x='
|
||||
eval sh -c '\''
|
||||
if test -d "$1"; then
|
||||
test -d "$1/.";
|
||||
else
|
||||
case $1 in #(
|
||||
-*)set "./$1";;
|
||||
esac;
|
||||
case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #((
|
||||
???[sx]*):;;*)false;;esac;fi
|
||||
'\'' sh
|
||||
'
|
||||
fi
|
||||
as_executable_p=$as_test_x
|
||||
as_test_x='test -x'
|
||||
as_executable_p=as_fn_executable_p
|
||||
|
||||
# Sed expression to map a string onto a valid CPP name.
|
||||
as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
|
||||
@@ -592,7 +620,6 @@ ac_includes_default="\
|
||||
|
||||
ac_subst_vars='LTLIBOBJS
|
||||
LIBOBJS
|
||||
CFLAGS
|
||||
EGREP
|
||||
GREP
|
||||
CXXCPP
|
||||
@@ -1059,7 +1086,7 @@ Try \`$0 --help' for more information"
|
||||
$as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2
|
||||
expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null &&
|
||||
$as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2
|
||||
: ${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}
|
||||
: "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}"
|
||||
;;
|
||||
|
||||
esac
|
||||
@@ -1110,8 +1137,6 @@ target=$target_alias
|
||||
if test "x$host_alias" != x; then
|
||||
if test "x$build_alias" = x; then
|
||||
cross_compiling=maybe
|
||||
$as_echo "$as_me: WARNING: if you wanted to set the --build type, don't use --host.
|
||||
If a cross compiler is detected then cross compile mode will be used" >&2
|
||||
elif test "x$build_alias" != "x$host_alias"; then
|
||||
cross_compiling=yes
|
||||
fi
|
||||
@@ -1339,9 +1364,9 @@ test -n "$ac_init_help" && exit $ac_status
|
||||
if $ac_init_version; then
|
||||
cat <<\_ACEOF
|
||||
myconfig configure 0.1
|
||||
generated by GNU Autoconf 2.67
|
||||
generated by GNU Autoconf 2.69
|
||||
|
||||
Copyright (C) 2010 Free Software Foundation, Inc.
|
||||
Copyright (C) 2012 Free Software Foundation, Inc.
|
||||
This configure script is free software; the Free Software Foundation
|
||||
gives unlimited permission to copy, distribute and modify it.
|
||||
_ACEOF
|
||||
@@ -1385,11 +1410,57 @@ sed 's/^/| /' conftest.$ac_ext >&5
|
||||
|
||||
ac_retval=1
|
||||
fi
|
||||
eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;}
|
||||
eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
|
||||
as_fn_set_status $ac_retval
|
||||
|
||||
} # ac_fn_cxx_try_compile
|
||||
|
||||
# ac_fn_cxx_try_link LINENO
|
||||
# -------------------------
|
||||
# Try to link conftest.$ac_ext, and return whether this succeeded.
|
||||
ac_fn_cxx_try_link ()
|
||||
{
|
||||
as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
|
||||
rm -f conftest.$ac_objext conftest$ac_exeext
|
||||
if { { ac_try="$ac_link"
|
||||
case "(($ac_try" in
|
||||
*\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
|
||||
*) ac_try_echo=$ac_try;;
|
||||
esac
|
||||
eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
|
||||
$as_echo "$ac_try_echo"; } >&5
|
||||
(eval "$ac_link") 2>conftest.err
|
||||
ac_status=$?
|
||||
if test -s conftest.err; then
|
||||
grep -v '^ *+' conftest.err >conftest.er1
|
||||
cat conftest.er1 >&5
|
||||
mv -f conftest.er1 conftest.err
|
||||
fi
|
||||
$as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
|
||||
test $ac_status = 0; } && {
|
||||
test -z "$ac_cxx_werror_flag" ||
|
||||
test ! -s conftest.err
|
||||
} && test -s conftest$ac_exeext && {
|
||||
test "$cross_compiling" = yes ||
|
||||
test -x conftest$ac_exeext
|
||||
}; then :
|
||||
ac_retval=0
|
||||
else
|
||||
$as_echo "$as_me: failed program was:" >&5
|
||||
sed 's/^/| /' conftest.$ac_ext >&5
|
||||
|
||||
ac_retval=1
|
||||
fi
|
||||
# Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information
|
||||
# created by the PGI compiler (conftest_ipa8_conftest.oo), as it would
|
||||
# interfere with the next link command; also delete a directory that is
|
||||
# left behind by Apple's compiler. We do this before executing the actions.
|
||||
rm -rf conftest.dSYM conftest_ipa8_conftest.oo
|
||||
eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
|
||||
as_fn_set_status $ac_retval
|
||||
|
||||
} # ac_fn_cxx_try_link
|
||||
|
||||
# ac_fn_cxx_try_cpp LINENO
|
||||
# ------------------------
|
||||
# Try to preprocess conftest.$ac_ext, and return whether this succeeded.
|
||||
@@ -1422,7 +1493,7 @@ sed 's/^/| /' conftest.$ac_ext >&5
|
||||
|
||||
ac_retval=1
|
||||
fi
|
||||
eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;}
|
||||
eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
|
||||
as_fn_set_status $ac_retval
|
||||
|
||||
} # ac_fn_cxx_try_cpp
|
||||
@@ -1435,10 +1506,10 @@ fi
|
||||
ac_fn_cxx_check_header_mongrel ()
|
||||
{
|
||||
as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
|
||||
if eval "test \"\${$3+set}\"" = set; then :
|
||||
if eval \${$3+:} false; then :
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
|
||||
$as_echo_n "checking for $2... " >&6; }
|
||||
if eval "test \"\${$3+set}\"" = set; then :
|
||||
if eval \${$3+:} false; then :
|
||||
$as_echo_n "(cached) " >&6
|
||||
fi
|
||||
eval ac_res=\$$3
|
||||
@@ -1501,7 +1572,7 @@ $as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;}
|
||||
esac
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
|
||||
$as_echo_n "checking for $2... " >&6; }
|
||||
if eval "test \"\${$3+set}\"" = set; then :
|
||||
if eval \${$3+:} false; then :
|
||||
$as_echo_n "(cached) " >&6
|
||||
else
|
||||
eval "$3=\$ac_header_compiler"
|
||||
@@ -1510,7 +1581,7 @@ eval ac_res=\$$3
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
|
||||
$as_echo "$ac_res" >&6; }
|
||||
fi
|
||||
eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;}
|
||||
eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
|
||||
|
||||
} # ac_fn_cxx_check_header_mongrel
|
||||
|
||||
@@ -1551,7 +1622,7 @@ sed 's/^/| /' conftest.$ac_ext >&5
|
||||
ac_retval=$ac_status
|
||||
fi
|
||||
rm -rf conftest.dSYM conftest_ipa8_conftest.oo
|
||||
eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;}
|
||||
eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
|
||||
as_fn_set_status $ac_retval
|
||||
|
||||
} # ac_fn_cxx_try_run
|
||||
@@ -1565,7 +1636,7 @@ ac_fn_cxx_check_header_compile ()
|
||||
as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
|
||||
$as_echo_n "checking for $2... " >&6; }
|
||||
if eval "test \"\${$3+set}\"" = set; then :
|
||||
if eval \${$3+:} false; then :
|
||||
$as_echo_n "(cached) " >&6
|
||||
else
|
||||
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
|
||||
@@ -1583,61 +1654,15 @@ fi
|
||||
eval ac_res=\$$3
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
|
||||
$as_echo "$ac_res" >&6; }
|
||||
eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;}
|
||||
eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
|
||||
|
||||
} # ac_fn_cxx_check_header_compile
|
||||
|
||||
# ac_fn_cxx_try_link LINENO
|
||||
# -------------------------
|
||||
# Try to link conftest.$ac_ext, and return whether this succeeded.
|
||||
ac_fn_cxx_try_link ()
|
||||
{
|
||||
as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
|
||||
rm -f conftest.$ac_objext conftest$ac_exeext
|
||||
if { { ac_try="$ac_link"
|
||||
case "(($ac_try" in
|
||||
*\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
|
||||
*) ac_try_echo=$ac_try;;
|
||||
esac
|
||||
eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
|
||||
$as_echo "$ac_try_echo"; } >&5
|
||||
(eval "$ac_link") 2>conftest.err
|
||||
ac_status=$?
|
||||
if test -s conftest.err; then
|
||||
grep -v '^ *+' conftest.err >conftest.er1
|
||||
cat conftest.er1 >&5
|
||||
mv -f conftest.er1 conftest.err
|
||||
fi
|
||||
$as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
|
||||
test $ac_status = 0; } && {
|
||||
test -z "$ac_cxx_werror_flag" ||
|
||||
test ! -s conftest.err
|
||||
} && test -s conftest$ac_exeext && {
|
||||
test "$cross_compiling" = yes ||
|
||||
$as_test_x conftest$ac_exeext
|
||||
}; then :
|
||||
ac_retval=0
|
||||
else
|
||||
$as_echo "$as_me: failed program was:" >&5
|
||||
sed 's/^/| /' conftest.$ac_ext >&5
|
||||
|
||||
ac_retval=1
|
||||
fi
|
||||
# Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information
|
||||
# created by the PGI compiler (conftest_ipa8_conftest.oo), as it would
|
||||
# interfere with the next link command; also delete a directory that is
|
||||
# left behind by Apple's compiler. We do this before executing the actions.
|
||||
rm -rf conftest.dSYM conftest_ipa8_conftest.oo
|
||||
eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;}
|
||||
as_fn_set_status $ac_retval
|
||||
|
||||
} # ac_fn_cxx_try_link
|
||||
cat >config.log <<_ACEOF
|
||||
This file contains any messages produced by compilers while
|
||||
running configure, to aid debugging if configure makes a mistake.
|
||||
|
||||
It was created by myconfig $as_me 0.1, which was
|
||||
generated by GNU Autoconf 2.67. Invocation command line was
|
||||
generated by GNU Autoconf 2.69. Invocation command line was
|
||||
|
||||
$ $0 $@
|
||||
|
||||
@@ -1895,7 +1920,7 @@ $as_echo "$as_me: loading site script $ac_site_file" >&6;}
|
||||
|| { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
|
||||
$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
|
||||
as_fn_error $? "failed to load site script $ac_site_file
|
||||
See \`config.log' for more details" "$LINENO" 5 ; }
|
||||
See \`config.log' for more details" "$LINENO" 5; }
|
||||
fi
|
||||
done
|
||||
|
||||
@@ -2001,7 +2026,7 @@ if test -z "$CXX"; then
|
||||
set dummy $ac_tool_prefix$ac_prog; ac_word=$2
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
|
||||
$as_echo_n "checking for $ac_word... " >&6; }
|
||||
if test "${ac_cv_prog_CXX+set}" = set; then :
|
||||
if ${ac_cv_prog_CXX+:} false; then :
|
||||
$as_echo_n "(cached) " >&6
|
||||
else
|
||||
if test -n "$CXX"; then
|
||||
@@ -2013,7 +2038,7 @@ do
|
||||
IFS=$as_save_IFS
|
||||
test -z "$as_dir" && as_dir=.
|
||||
for ac_exec_ext in '' $ac_executable_extensions; do
|
||||
if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
|
||||
if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
|
||||
ac_cv_prog_CXX="$ac_tool_prefix$ac_prog"
|
||||
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
|
||||
break 2
|
||||
@@ -2045,7 +2070,7 @@ do
|
||||
set dummy $ac_prog; ac_word=$2
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
|
||||
$as_echo_n "checking for $ac_word... " >&6; }
|
||||
if test "${ac_cv_prog_ac_ct_CXX+set}" = set; then :
|
||||
if ${ac_cv_prog_ac_ct_CXX+:} false; then :
|
||||
$as_echo_n "(cached) " >&6
|
||||
else
|
||||
if test -n "$ac_ct_CXX"; then
|
||||
@@ -2057,7 +2082,7 @@ do
|
||||
IFS=$as_save_IFS
|
||||
test -z "$as_dir" && as_dir=.
|
||||
for ac_exec_ext in '' $ac_executable_extensions; do
|
||||
if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
|
||||
if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
|
||||
ac_cv_prog_ac_ct_CXX="$ac_prog"
|
||||
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
|
||||
break 2
|
||||
@@ -2209,7 +2234,7 @@ sed 's/^/| /' conftest.$ac_ext >&5
|
||||
{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
|
||||
$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
|
||||
as_fn_error 77 "C++ compiler cannot create executables
|
||||
See \`config.log' for more details" "$LINENO" 5 ; }
|
||||
See \`config.log' for more details" "$LINENO" 5; }
|
||||
else
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
|
||||
$as_echo "yes" >&6; }
|
||||
@@ -2252,7 +2277,7 @@ else
|
||||
{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
|
||||
$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
|
||||
as_fn_error $? "cannot compute suffix of executables: cannot compile and link
|
||||
See \`config.log' for more details" "$LINENO" 5 ; }
|
||||
See \`config.log' for more details" "$LINENO" 5; }
|
||||
fi
|
||||
rm -f conftest conftest$ac_cv_exeext
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5
|
||||
@@ -2311,7 +2336,7 @@ $as_echo "$ac_try_echo"; } >&5
|
||||
$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
|
||||
as_fn_error $? "cannot run C++ compiled programs.
|
||||
If you meant to cross compile, use \`--host'.
|
||||
See \`config.log' for more details" "$LINENO" 5 ; }
|
||||
See \`config.log' for more details" "$LINENO" 5; }
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
@@ -2322,7 +2347,7 @@ rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out
|
||||
ac_clean_files=$ac_clean_files_save
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5
|
||||
$as_echo_n "checking for suffix of object files... " >&6; }
|
||||
if test "${ac_cv_objext+set}" = set; then :
|
||||
if ${ac_cv_objext+:} false; then :
|
||||
$as_echo_n "(cached) " >&6
|
||||
else
|
||||
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
|
||||
@@ -2363,7 +2388,7 @@ sed 's/^/| /' conftest.$ac_ext >&5
|
||||
{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
|
||||
$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
|
||||
as_fn_error $? "cannot compute suffix of object files: cannot compile
|
||||
See \`config.log' for more details" "$LINENO" 5 ; }
|
||||
See \`config.log' for more details" "$LINENO" 5; }
|
||||
fi
|
||||
rm -f conftest.$ac_cv_objext conftest.$ac_ext
|
||||
fi
|
||||
@@ -2373,7 +2398,7 @@ OBJEXT=$ac_cv_objext
|
||||
ac_objext=$OBJEXT
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C++ compiler" >&5
|
||||
$as_echo_n "checking whether we are using the GNU C++ compiler... " >&6; }
|
||||
if test "${ac_cv_cxx_compiler_gnu+set}" = set; then :
|
||||
if ${ac_cv_cxx_compiler_gnu+:} false; then :
|
||||
$as_echo_n "(cached) " >&6
|
||||
else
|
||||
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
|
||||
@@ -2410,7 +2435,7 @@ ac_test_CXXFLAGS=${CXXFLAGS+set}
|
||||
ac_save_CXXFLAGS=$CXXFLAGS
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CXX accepts -g" >&5
|
||||
$as_echo_n "checking whether $CXX accepts -g... " >&6; }
|
||||
if test "${ac_cv_prog_cxx_g+set}" = set; then :
|
||||
if ${ac_cv_prog_cxx_g+:} false; then :
|
||||
$as_echo_n "(cached) " >&6
|
||||
else
|
||||
ac_save_cxx_werror_flag=$ac_cxx_werror_flag
|
||||
@@ -2499,13 +2524,30 @@ ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ex
|
||||
ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
|
||||
|
||||
|
||||
if test -n "$debug"
|
||||
then
|
||||
CFLAGS="-DDEBUG -g"
|
||||
else
|
||||
CFLAGS="-O3"
|
||||
fi
|
||||
saved_libs="${LIBS}"
|
||||
LIBS="${LIBS} -ltins"
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking libtins" >&5
|
||||
$as_echo_n "checking libtins... " >&6; }
|
||||
|
||||
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
|
||||
/* end confdefs.h. */
|
||||
#include <tins/dns.h>
|
||||
int
|
||||
main ()
|
||||
{
|
||||
Tins::DNS dummy
|
||||
;
|
||||
return 0;
|
||||
}
|
||||
_ACEOF
|
||||
if ac_fn_cxx_try_link "$LINENO"; then :
|
||||
echo done
|
||||
else
|
||||
echo error; echo *** libtins is not installed. Aborting... ***; exit 1
|
||||
fi
|
||||
rm -f core conftest.err conftest.$ac_objext \
|
||||
conftest$ac_exeext conftest.$ac_ext
|
||||
LIBS="${saved_libs}"
|
||||
|
||||
ac_ext=cpp
|
||||
ac_cpp='$CXXCPP $CPPFLAGS'
|
||||
@@ -2515,7 +2557,7 @@ ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C++ preprocessor" >&5
|
||||
$as_echo_n "checking how to run the C++ preprocessor... " >&6; }
|
||||
if test -z "$CXXCPP"; then
|
||||
if test "${ac_cv_prog_CXXCPP+set}" = set; then :
|
||||
if ${ac_cv_prog_CXXCPP+:} false; then :
|
||||
$as_echo_n "(cached) " >&6
|
||||
else
|
||||
# Double quotes because CXXCPP needs to be expanded
|
||||
@@ -2631,7 +2673,7 @@ else
|
||||
{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
|
||||
$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
|
||||
as_fn_error $? "C++ preprocessor \"$CXXCPP\" fails sanity check
|
||||
See \`config.log' for more details" "$LINENO" 5 ; }
|
||||
See \`config.log' for more details" "$LINENO" 5; }
|
||||
fi
|
||||
|
||||
ac_ext=cpp
|
||||
@@ -2643,7 +2685,7 @@ ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
|
||||
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5
|
||||
$as_echo_n "checking for grep that handles long lines and -e... " >&6; }
|
||||
if test "${ac_cv_path_GREP+set}" = set; then :
|
||||
if ${ac_cv_path_GREP+:} false; then :
|
||||
$as_echo_n "(cached) " >&6
|
||||
else
|
||||
if test -z "$GREP"; then
|
||||
@@ -2657,7 +2699,7 @@ do
|
||||
for ac_prog in grep ggrep; do
|
||||
for ac_exec_ext in '' $ac_executable_extensions; do
|
||||
ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext"
|
||||
{ test -f "$ac_path_GREP" && $as_test_x "$ac_path_GREP"; } || continue
|
||||
as_fn_executable_p "$ac_path_GREP" || continue
|
||||
# Check for GNU ac_path_GREP and select it if it is found.
|
||||
# Check for GNU $ac_path_GREP
|
||||
case `"$ac_path_GREP" --version 2>&1` in
|
||||
@@ -2706,7 +2748,7 @@ $as_echo "$ac_cv_path_GREP" >&6; }
|
||||
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5
|
||||
$as_echo_n "checking for egrep... " >&6; }
|
||||
if test "${ac_cv_path_EGREP+set}" = set; then :
|
||||
if ${ac_cv_path_EGREP+:} false; then :
|
||||
$as_echo_n "(cached) " >&6
|
||||
else
|
||||
if echo a | $GREP -E '(a|b)' >/dev/null 2>&1
|
||||
@@ -2723,7 +2765,7 @@ do
|
||||
for ac_prog in egrep; do
|
||||
for ac_exec_ext in '' $ac_executable_extensions; do
|
||||
ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext"
|
||||
{ test -f "$ac_path_EGREP" && $as_test_x "$ac_path_EGREP"; } || continue
|
||||
as_fn_executable_p "$ac_path_EGREP" || continue
|
||||
# Check for GNU ac_path_EGREP and select it if it is found.
|
||||
# Check for GNU $ac_path_EGREP
|
||||
case `"$ac_path_EGREP" --version 2>&1` in
|
||||
@@ -2773,7 +2815,7 @@ $as_echo "$ac_cv_path_EGREP" >&6; }
|
||||
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5
|
||||
$as_echo_n "checking for ANSI C header files... " >&6; }
|
||||
if test "${ac_cv_header_stdc+set}" = set; then :
|
||||
if ${ac_cv_header_stdc+:} false; then :
|
||||
$as_echo_n "(cached) " >&6
|
||||
else
|
||||
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
|
||||
@@ -2900,65 +2942,20 @@ fi
|
||||
done
|
||||
|
||||
|
||||
for ac_header in pcap.h
|
||||
for ac_header in tins/tins.h
|
||||
do :
|
||||
ac_fn_cxx_check_header_mongrel "$LINENO" "pcap.h" "ac_cv_header_pcap_h" "$ac_includes_default"
|
||||
if test "x$ac_cv_header_pcap_h" = x""yes; then :
|
||||
ac_fn_cxx_check_header_mongrel "$LINENO" "tins/tins.h" "ac_cv_header_tins_tins_h" "$ac_includes_default"
|
||||
if test "x$ac_cv_header_tins_tins_h" = xyes; then :
|
||||
cat >>confdefs.h <<_ACEOF
|
||||
#define HAVE_PCAP_H 1
|
||||
#define HAVE_TINS_TINS_H 1
|
||||
_ACEOF
|
||||
|
||||
else
|
||||
echo "*** Error: libtins' headers are absent ***"; exit 1;
|
||||
fi
|
||||
|
||||
done
|
||||
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for pcap_loop in -lpcap" >&5
|
||||
$as_echo_n "checking for pcap_loop in -lpcap... " >&6; }
|
||||
if test "${ac_cv_lib_pcap_pcap_loop+set}" = set; then :
|
||||
$as_echo_n "(cached) " >&6
|
||||
else
|
||||
ac_check_lib_save_LIBS=$LIBS
|
||||
LIBS="-lpcap $LIBS"
|
||||
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
|
||||
/* end confdefs.h. */
|
||||
|
||||
/* Override any GCC internal prototype to avoid an error.
|
||||
Use char because int might match the return type of a GCC
|
||||
builtin and then its argument prototype would still apply. */
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
#endif
|
||||
char pcap_loop ();
|
||||
int
|
||||
main ()
|
||||
{
|
||||
return pcap_loop ();
|
||||
;
|
||||
return 0;
|
||||
}
|
||||
_ACEOF
|
||||
if ac_fn_cxx_try_link "$LINENO"; then :
|
||||
ac_cv_lib_pcap_pcap_loop=yes
|
||||
else
|
||||
ac_cv_lib_pcap_pcap_loop=no
|
||||
fi
|
||||
rm -f core conftest.err conftest.$ac_objext \
|
||||
conftest$ac_exeext conftest.$ac_ext
|
||||
LIBS=$ac_check_lib_save_LIBS
|
||||
fi
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pcap_pcap_loop" >&5
|
||||
$as_echo "$ac_cv_lib_pcap_pcap_loop" >&6; }
|
||||
if test "x$ac_cv_lib_pcap_pcap_loop" = x""yes; then :
|
||||
cat >>confdefs.h <<_ACEOF
|
||||
#define HAVE_LIBPCAP 1
|
||||
_ACEOF
|
||||
|
||||
LIBS="-lpcap $LIBS"
|
||||
|
||||
else
|
||||
as_fn_error $? "pcap library is needed!" "$LINENO" 5
|
||||
fi
|
||||
|
||||
|
||||
ac_config_files="$ac_config_files Makefile"
|
||||
|
||||
@@ -3026,10 +3023,21 @@ $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
|
||||
:end' >>confcache
|
||||
if diff "$cache_file" confcache >/dev/null 2>&1; then :; else
|
||||
if test -w "$cache_file"; then
|
||||
test "x$cache_file" != "x/dev/null" &&
|
||||
if test "x$cache_file" != "x/dev/null"; then
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5
|
||||
$as_echo "$as_me: updating cache $cache_file" >&6;}
|
||||
cat confcache >$cache_file
|
||||
if test ! -f "$cache_file" || test -h "$cache_file"; then
|
||||
cat confcache >"$cache_file"
|
||||
else
|
||||
case $cache_file in #(
|
||||
*/* | ?:*)
|
||||
mv -f confcache "$cache_file"$$ &&
|
||||
mv -f "$cache_file"$$ "$cache_file" ;; #(
|
||||
*)
|
||||
mv -f confcache "$cache_file" ;;
|
||||
esac
|
||||
fi
|
||||
fi
|
||||
else
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5
|
||||
$as_echo "$as_me: not updating unwritable cache $cache_file" >&6;}
|
||||
@@ -3097,7 +3105,7 @@ LTLIBOBJS=$ac_ltlibobjs
|
||||
|
||||
|
||||
|
||||
: ${CONFIG_STATUS=./config.status}
|
||||
: "${CONFIG_STATUS=./config.status}"
|
||||
ac_write_fail=0
|
||||
ac_clean_files_save=$ac_clean_files
|
||||
ac_clean_files="$ac_clean_files $CONFIG_STATUS"
|
||||
@@ -3198,6 +3206,7 @@ fi
|
||||
IFS=" "" $as_nl"
|
||||
|
||||
# Find who we are. Look in the path if we contain no directory separator.
|
||||
as_myself=
|
||||
case $0 in #((
|
||||
*[\\/]* ) as_myself=$0 ;;
|
||||
*) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
|
||||
@@ -3393,16 +3402,16 @@ if (echo >conf$$.file) 2>/dev/null; then
|
||||
# ... but there are two gotchas:
|
||||
# 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
|
||||
# 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
|
||||
# In both cases, we have to default to `cp -p'.
|
||||
# In both cases, we have to default to `cp -pR'.
|
||||
ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
|
||||
as_ln_s='cp -p'
|
||||
as_ln_s='cp -pR'
|
||||
elif ln conf$$.file conf$$ 2>/dev/null; then
|
||||
as_ln_s=ln
|
||||
else
|
||||
as_ln_s='cp -p'
|
||||
as_ln_s='cp -pR'
|
||||
fi
|
||||
else
|
||||
as_ln_s='cp -p'
|
||||
as_ln_s='cp -pR'
|
||||
fi
|
||||
rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
|
||||
rmdir conf$$.dir 2>/dev/null
|
||||
@@ -3462,28 +3471,16 @@ else
|
||||
as_mkdir_p=false
|
||||
fi
|
||||
|
||||
if test -x / >/dev/null 2>&1; then
|
||||
as_test_x='test -x'
|
||||
else
|
||||
if ls -dL / >/dev/null 2>&1; then
|
||||
as_ls_L_option=L
|
||||
else
|
||||
as_ls_L_option=
|
||||
fi
|
||||
as_test_x='
|
||||
eval sh -c '\''
|
||||
if test -d "$1"; then
|
||||
test -d "$1/.";
|
||||
else
|
||||
case $1 in #(
|
||||
-*)set "./$1";;
|
||||
esac;
|
||||
case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #((
|
||||
???[sx]*):;;*)false;;esac;fi
|
||||
'\'' sh
|
||||
'
|
||||
fi
|
||||
as_executable_p=$as_test_x
|
||||
|
||||
# as_fn_executable_p FILE
|
||||
# -----------------------
|
||||
# Test if FILE is an executable regular file.
|
||||
as_fn_executable_p ()
|
||||
{
|
||||
test -f "$1" && test -x "$1"
|
||||
} # as_fn_executable_p
|
||||
as_test_x='test -x'
|
||||
as_executable_p=as_fn_executable_p
|
||||
|
||||
# Sed expression to map a string onto a valid CPP name.
|
||||
as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
|
||||
@@ -3505,7 +3502,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
|
||||
# values after options handling.
|
||||
ac_log="
|
||||
This file was extended by myconfig $as_me 0.1, which was
|
||||
generated by GNU Autoconf 2.67. Invocation command line was
|
||||
generated by GNU Autoconf 2.69. Invocation command line was
|
||||
|
||||
CONFIG_FILES = $CONFIG_FILES
|
||||
CONFIG_HEADERS = $CONFIG_HEADERS
|
||||
@@ -3558,10 +3555,10 @@ cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
|
||||
ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
|
||||
ac_cs_version="\\
|
||||
myconfig config.status 0.1
|
||||
configured by $0, generated by GNU Autoconf 2.67,
|
||||
configured by $0, generated by GNU Autoconf 2.69,
|
||||
with options \\"\$ac_cs_config\\"
|
||||
|
||||
Copyright (C) 2010 Free Software Foundation, Inc.
|
||||
Copyright (C) 2012 Free Software Foundation, Inc.
|
||||
This config.status script is free software; the Free Software Foundation
|
||||
gives unlimited permission to copy, distribute and modify it."
|
||||
|
||||
@@ -3638,7 +3635,7 @@ fi
|
||||
_ACEOF
|
||||
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
|
||||
if \$ac_cs_recheck; then
|
||||
set X '$SHELL' '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion
|
||||
set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion
|
||||
shift
|
||||
\$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6
|
||||
CONFIG_SHELL='$SHELL'
|
||||
@@ -3669,7 +3666,7 @@ do
|
||||
case $ac_config_target in
|
||||
"Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;;
|
||||
|
||||
*) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5 ;;
|
||||
*) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;;
|
||||
esac
|
||||
done
|
||||
|
||||
@@ -3690,9 +3687,10 @@ fi
|
||||
# after its creation but before its name has been assigned to `$tmp'.
|
||||
$debug ||
|
||||
{
|
||||
tmp=
|
||||
tmp= ac_tmp=
|
||||
trap 'exit_status=$?
|
||||
{ test -z "$tmp" || test ! -d "$tmp" || rm -fr "$tmp"; } && exit $exit_status
|
||||
: "${ac_tmp:=$tmp}"
|
||||
{ test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status
|
||||
' 0
|
||||
trap 'as_fn_exit 1' 1 2 13 15
|
||||
}
|
||||
@@ -3700,12 +3698,13 @@ $debug ||
|
||||
|
||||
{
|
||||
tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` &&
|
||||
test -n "$tmp" && test -d "$tmp"
|
||||
test -d "$tmp"
|
||||
} ||
|
||||
{
|
||||
tmp=./conf$$-$RANDOM
|
||||
(umask 077 && mkdir "$tmp")
|
||||
} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5
|
||||
ac_tmp=$tmp
|
||||
|
||||
# Set up the scripts for CONFIG_FILES section.
|
||||
# No need to generate them if there are no CONFIG_FILES.
|
||||
@@ -3727,7 +3726,7 @@ else
|
||||
ac_cs_awk_cr=$ac_cr
|
||||
fi
|
||||
|
||||
echo 'BEGIN {' >"$tmp/subs1.awk" &&
|
||||
echo 'BEGIN {' >"$ac_tmp/subs1.awk" &&
|
||||
_ACEOF
|
||||
|
||||
|
||||
@@ -3755,7 +3754,7 @@ done
|
||||
rm -f conf$$subs.sh
|
||||
|
||||
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
|
||||
cat >>"\$tmp/subs1.awk" <<\\_ACAWK &&
|
||||
cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK &&
|
||||
_ACEOF
|
||||
sed -n '
|
||||
h
|
||||
@@ -3803,7 +3802,7 @@ t delim
|
||||
rm -f conf$$subs.awk
|
||||
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
|
||||
_ACAWK
|
||||
cat >>"\$tmp/subs1.awk" <<_ACAWK &&
|
||||
cat >>"\$ac_tmp/subs1.awk" <<_ACAWK &&
|
||||
for (key in S) S_is_set[key] = 1
|
||||
FS = ""
|
||||
|
||||
@@ -3835,7 +3834,7 @@ if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then
|
||||
sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g"
|
||||
else
|
||||
cat
|
||||
fi < "$tmp/subs1.awk" > "$tmp/subs.awk" \
|
||||
fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \
|
||||
|| as_fn_error $? "could not setup config files machinery" "$LINENO" 5
|
||||
_ACEOF
|
||||
|
||||
@@ -3875,7 +3874,7 @@ do
|
||||
esac
|
||||
case $ac_mode$ac_tag in
|
||||
:[FHL]*:*);;
|
||||
:L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5 ;;
|
||||
:L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;;
|
||||
:[FH]-) ac_tag=-:-;;
|
||||
:[FH]*) ac_tag=$ac_tag:$ac_tag.in;;
|
||||
esac
|
||||
@@ -3894,7 +3893,7 @@ do
|
||||
for ac_f
|
||||
do
|
||||
case $ac_f in
|
||||
-) ac_f="$tmp/stdin";;
|
||||
-) ac_f="$ac_tmp/stdin";;
|
||||
*) # Look for the file first in the build tree, then in the source tree
|
||||
# (if the path is not absolute). The absolute path cannot be DOS-style,
|
||||
# because $ac_f cannot contain `:'.
|
||||
@@ -3903,7 +3902,7 @@ do
|
||||
[\\/$]*) false;;
|
||||
*) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";;
|
||||
esac ||
|
||||
as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5 ;;
|
||||
as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;;
|
||||
esac
|
||||
case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac
|
||||
as_fn_append ac_file_inputs " '$ac_f'"
|
||||
@@ -3929,8 +3928,8 @@ $as_echo "$as_me: creating $ac_file" >&6;}
|
||||
esac
|
||||
|
||||
case $ac_tag in
|
||||
*:-:* | *:-) cat >"$tmp/stdin" \
|
||||
|| as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;;
|
||||
*:-:* | *:-) cat >"$ac_tmp/stdin" \
|
||||
|| as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;;
|
||||
esac
|
||||
;;
|
||||
esac
|
||||
@@ -4055,21 +4054,22 @@ s&@abs_builddir@&$ac_abs_builddir&;t t
|
||||
s&@abs_top_builddir@&$ac_abs_top_builddir&;t t
|
||||
$ac_datarootdir_hack
|
||||
"
|
||||
eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$tmp/subs.awk" >$tmp/out \
|
||||
|| as_fn_error $? "could not create $ac_file" "$LINENO" 5
|
||||
eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \
|
||||
>$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5
|
||||
|
||||
test -z "$ac_datarootdir_hack$ac_datarootdir_seen" &&
|
||||
{ ac_out=`sed -n '/\${datarootdir}/p' "$tmp/out"`; test -n "$ac_out"; } &&
|
||||
{ ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' "$tmp/out"`; test -z "$ac_out"; } &&
|
||||
{ ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } &&
|
||||
{ ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \
|
||||
"$ac_tmp/out"`; test -z "$ac_out"; } &&
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir'
|
||||
which seems to be undefined. Please make sure it is defined" >&5
|
||||
$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir'
|
||||
which seems to be undefined. Please make sure it is defined" >&2;}
|
||||
|
||||
rm -f "$tmp/stdin"
|
||||
rm -f "$ac_tmp/stdin"
|
||||
case $ac_file in
|
||||
-) cat "$tmp/out" && rm -f "$tmp/out";;
|
||||
*) rm -f "$ac_file" && mv "$tmp/out" "$ac_file";;
|
||||
-) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";;
|
||||
*) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";;
|
||||
esac \
|
||||
|| as_fn_error $? "could not create $ac_file" "$LINENO" 5
|
||||
;;
|
||||
|
||||
@@ -3,14 +3,15 @@ AC_INIT(myconfig, 0.1)
|
||||
AC_PROG_CXX()
|
||||
AC_LANG(C++)
|
||||
|
||||
if test -n "$debug"
|
||||
then
|
||||
CFLAGS="-DDEBUG -g"
|
||||
else
|
||||
CFLAGS="-O3"
|
||||
fi
|
||||
saved_libs="${LIBS}"
|
||||
LIBS="${LIBS} -ltins"
|
||||
AC_MSG_CHECKING(libtins)
|
||||
AC_LINK_IFELSE([AC_LANG_PROGRAM([#include <tins/dns.h>],
|
||||
[Tins::DNS dummy])],
|
||||
[echo done],
|
||||
[echo error; echo *** libtins is not installed. Aborting... ***; exit 1])
|
||||
LIBS="${saved_libs}"
|
||||
|
||||
AC_CHECK_HEADERS([tins/tins.h], , [echo "*** Error: libtins' headers are absent ***"; exit 1;])
|
||||
|
||||
AC_CHECK_HEADERS([pcap.h])
|
||||
AC_CHECK_LIB(pcap, pcap_loop, [], [AC_MSG_ERROR([pcap library is needed!])])
|
||||
AC_SUBST(CFLAGS)
|
||||
AC_OUTPUT(Makefile)
|
||||
|
||||
61
examples/dns_queries.cpp
Normal file
61
examples/dns_queries.cpp
Normal file
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright (c) 2012, Matias Fontanini
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following disclaimer
|
||||
* in the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <tins/tins.h>
|
||||
#include <iostream>
|
||||
|
||||
using namespace Tins;
|
||||
|
||||
bool callback(const PDU &pdu)
|
||||
{
|
||||
// The packet probably looks like this:
|
||||
//
|
||||
// EthernetII / IP / UDP / RawPDU
|
||||
//
|
||||
// So we retrieve the RawPDU layer, and construct a
|
||||
// DNS PDU using its contents.
|
||||
DNS dns = pdu.rfind_pdu<RawPDU>().to<DNS>();
|
||||
|
||||
// Retrieve the queries and print the domain name:
|
||||
for(const auto &query : dns.queries())
|
||||
std::cout << query.dname() << std::endl;
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
if(argc != 2) {
|
||||
std::cout << "Usage: " << *argv << " <interface>" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
// Sniff on the provided interface, maximum packet size 2000
|
||||
// in promiscuos mode and only udp packets sent to port 53
|
||||
Sniffer sniffer(argv[1], 2000, true, "udp and dst port 53");
|
||||
sniffer.sniff_loop(callback);
|
||||
}
|
||||
94
examples/dns_spoof.cpp
Normal file
94
examples/dns_spoof.cpp
Normal file
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
* Copyright (c) 2012, Matias Fontanini
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following disclaimer
|
||||
* in the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <tins/tins.h>
|
||||
#include <iostream>
|
||||
|
||||
using namespace Tins;
|
||||
|
||||
PacketSender sender;
|
||||
|
||||
bool callback(const PDU &pdu)
|
||||
{
|
||||
// The packet probably looks like this:
|
||||
//
|
||||
// EthernetII / IP / UDP / RawPDU
|
||||
//
|
||||
// So we retrieve each layer, and construct a
|
||||
// DNS PDU from the RawPDU layer contents.
|
||||
EthernetII eth = pdu.rfind_pdu<EthernetII>();
|
||||
IP ip = eth.rfind_pdu<IP>();
|
||||
UDP udp = ip.rfind_pdu<UDP>();
|
||||
DNS dns = udp.rfind_pdu<RawPDU>().to<DNS>();
|
||||
|
||||
// Is it a DNS query?
|
||||
if(dns.type() == DNS::QUERY) {
|
||||
// Let's see if there's any query for an "A" record.
|
||||
for(const auto &query : dns.queries()) {
|
||||
if(query.type() == DNS::A) {
|
||||
// Here's one! Let's add an answer.
|
||||
dns.add_answer(
|
||||
query.dname(),
|
||||
// 777 is just a random TTL
|
||||
DNS::make_info(DNS::A, query.query_class(), 777),
|
||||
IPv4Address("127.0.0.1")
|
||||
);
|
||||
}
|
||||
}
|
||||
// Have we added some answers?
|
||||
if(dns.answers_count() > 0) {
|
||||
// It's a response now
|
||||
dns.type(DNS::RESPONSE);
|
||||
// Recursion is available(just in case)
|
||||
dns.recursion_available(1);
|
||||
// Build our packet
|
||||
auto pkt = EthernetII(eth.src_addr(), eth.dst_addr()) /
|
||||
IP(ip.src_addr(), ip.dst_addr()) /
|
||||
UDP(udp.sport(), udp.dport()) /
|
||||
dns;
|
||||
// Send it!
|
||||
sender.send(pkt);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
if(argc != 2) {
|
||||
std::cout << "Usage: " << *argv << " <interface>" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
// Sniff on the provided interface, maximum packet size 2000
|
||||
// in promiscuos mode and only udp packets sent to port 53
|
||||
Sniffer sniffer(argv[1], 2000, true, "udp and dst port 53");
|
||||
// All packets will be sent through the provided interface
|
||||
sender.default_interface(argv[1]);
|
||||
sniffer.sniff_loop(callback);
|
||||
}
|
||||
74
examples/wps_detect.cpp
Normal file
74
examples/wps_detect.cpp
Normal file
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Copyright (c) 2012, Matias Fontanini
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following disclaimer
|
||||
* in the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <tins/tins.h>
|
||||
#include <iostream>
|
||||
#include <set>
|
||||
#include <string>
|
||||
|
||||
using namespace Tins;
|
||||
|
||||
// BSSIDs which we've already seen
|
||||
std::set<HWAddress<6>> addrs;
|
||||
// This will be the content of the OUI field in the vendor specific
|
||||
// tagged option if it's a WPS tag.
|
||||
const HWAddress<3> expected_oui("00:50:F2");
|
||||
|
||||
bool handler(const PDU& pdu) {
|
||||
const Dot11Beacon &beacon = pdu.rfind_pdu<Dot11Beacon>();
|
||||
// Only process it once
|
||||
if(addrs.insert(beacon.addr3()).second) {
|
||||
// Iterate the tagged options
|
||||
for(const auto &opt : beacon.options()) {
|
||||
// Is this a vendor-specific tag?
|
||||
if(opt.option() == Dot11::VENDOR_SPECIFIC) {
|
||||
// Make sure there's enough size for the OUI + identifier
|
||||
if(opt.data_size() >= 4) {
|
||||
// Retrieve the OUI field
|
||||
HWAddress<3> addr = opt.data_ptr();
|
||||
// Are we interested in this OUI and is it a WPS tag?
|
||||
if(addr == expected_oui && opt.data_ptr()[3] == 0x04) {
|
||||
std::cout << "[+] Access point: " << beacon.ssid() << " uses WPS\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
if(argc != 2) {
|
||||
std::cout << "Usage: " << *argv << " <DEVICE>\n";
|
||||
return 1;
|
||||
}
|
||||
// Only sniff beacons
|
||||
Sniffer sniffer(argv[1], 2000, true, "wlan type mgt subtype beacon");
|
||||
sniffer.sniff_loop(handler);
|
||||
}
|
||||
@@ -6,6 +6,9 @@
|
||||
/* Define to 1 if you have the <dlfcn.h> header file. */
|
||||
#undef HAVE_DLFCN_H
|
||||
|
||||
/* Have IEEE 802.11 support */
|
||||
#undef HAVE_DOT11
|
||||
|
||||
/* Define to 1 if you have the <inttypes.h> header file. */
|
||||
#undef HAVE_INTTYPES_H
|
||||
|
||||
|
||||
@@ -27,7 +27,9 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef TINS_CRYPTO_H
|
||||
#include "config.h"
|
||||
|
||||
#if !defined(TINS_CRYPTO_H) && defined(HAVE_DOT11)
|
||||
#define TINS_CRYPTO_H
|
||||
|
||||
#include <map>
|
||||
@@ -38,7 +40,6 @@
|
||||
#include "snap.h"
|
||||
#include "rawpdu.h"
|
||||
#include "handshake_capturer.h"
|
||||
#include "config.h"
|
||||
|
||||
namespace Tins {
|
||||
class PDU;
|
||||
@@ -49,7 +50,7 @@ namespace Crypto {
|
||||
/**
|
||||
* \cond
|
||||
*/
|
||||
class RC4Key;
|
||||
struct RC4Key;
|
||||
#ifdef HAVE_WPA2_DECRYPTION
|
||||
namespace WPA2 {
|
||||
class invalid_handshake : public std::exception {
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
|
||||
|
||||
#include <list>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include "bootp.h"
|
||||
#include "pdu_option.h"
|
||||
@@ -145,7 +146,7 @@ namespace Tins {
|
||||
/**
|
||||
* The DHCP option type.
|
||||
*/
|
||||
typedef PDUOption<uint8_t> option;
|
||||
typedef PDUOption<uint8_t, DHCP> option;
|
||||
|
||||
/**
|
||||
* The type used to store the DHCP options.
|
||||
@@ -271,7 +272,7 @@ namespace Tins {
|
||||
*
|
||||
* \param routers A list of ip addresses.
|
||||
*/
|
||||
void routers(const std::list<ipaddress_type> &routers);
|
||||
void routers(const std::vector<ipaddress_type> &routers);
|
||||
|
||||
/**
|
||||
* \brief Adds a domain name servers option.
|
||||
@@ -280,7 +281,7 @@ namespace Tins {
|
||||
*
|
||||
* \param dns A list of ip addresses.
|
||||
*/
|
||||
void domain_name_servers(const std::list<ipaddress_type> &dns);
|
||||
void domain_name_servers(const std::vector<ipaddress_type> &dns);
|
||||
|
||||
/**
|
||||
* \brief Adds a broadcast address option.
|
||||
@@ -377,10 +378,10 @@ namespace Tins {
|
||||
* If the option is not found, an option_not_found exception
|
||||
* is thrown.
|
||||
*
|
||||
* \return std::list<ipaddress_type> Containing the routers
|
||||
* \return std::vector<ipaddress_type> Containing the routers
|
||||
* option data.
|
||||
*/
|
||||
std::list<ipaddress_type> routers() const;
|
||||
std::vector<ipaddress_type> routers() const;
|
||||
|
||||
/**
|
||||
* \brief Searchs for a dns option.
|
||||
@@ -391,7 +392,7 @@ namespace Tins {
|
||||
* \return std::list<ipaddress_type> Contanining the DNS servers
|
||||
* provided.
|
||||
*/
|
||||
std::list<ipaddress_type> domain_name_servers() const;
|
||||
std::vector<ipaddress_type> domain_name_servers() const;
|
||||
|
||||
/**
|
||||
* \brief Searchs for a broadcast option.
|
||||
@@ -450,27 +451,19 @@ namespace Tins {
|
||||
}
|
||||
private:
|
||||
static const uint32_t MAX_DHCP_SIZE;
|
||||
|
||||
template<typename T>
|
||||
struct type2type {};
|
||||
|
||||
void write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *parent);
|
||||
|
||||
|
||||
template<class T>
|
||||
T generic_search(OptionTypes opt, type2type<T>) const {
|
||||
T search_and_convert(OptionTypes opt) const {
|
||||
const option *option = search_option(opt);
|
||||
if(option && option->data_size() == sizeof(T))
|
||||
return *(const T*)option->data_ptr();
|
||||
else
|
||||
if(!option)
|
||||
throw option_not_found();
|
||||
return option->to<T>();
|
||||
}
|
||||
|
||||
void internal_add_option(const option &opt);
|
||||
std::list<ipaddress_type> generic_search(OptionTypes opt, type2type<std::list<ipaddress_type> >) const;
|
||||
std::string generic_search(OptionTypes opt, type2type<std::string>) const;
|
||||
ipaddress_type generic_search(OptionTypes opt, type2type<ipaddress_type>) const;
|
||||
|
||||
serialization_type serialize_list(const std::list<ipaddress_type> &ip_list);
|
||||
serialization_type serialize_list(const std::vector<ipaddress_type> &ip_list);
|
||||
|
||||
options_type _options;
|
||||
uint32_t _size;
|
||||
|
||||
121
include/dhcpv6.h
121
include/dhcpv6.h
@@ -46,7 +46,7 @@ public:
|
||||
/**
|
||||
* Represents a DHCPv6 option.
|
||||
*/
|
||||
typedef PDUOption<uint16_t> option;
|
||||
typedef PDUOption<uint16_t, DHCPv6> option;
|
||||
|
||||
/**
|
||||
* The message types.
|
||||
@@ -179,6 +179,8 @@ public:
|
||||
ia_na_type(uint32_t id = 0, uint32_t t1 = 0, uint32_t t2 = 0,
|
||||
const options_type& options = options_type())
|
||||
: id(id), t1(t1), t2(t2), options(options) {}
|
||||
|
||||
static ia_na_type from_option(const option &opt);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -194,6 +196,8 @@ public:
|
||||
ia_ta_type(uint32_t id = 0,
|
||||
const options_type& options = options_type())
|
||||
: id(id), options(options) {}
|
||||
|
||||
static ia_ta_type from_option(const option &opt);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -211,6 +215,8 @@ public:
|
||||
const options_type& options = options_type())
|
||||
: address(address), preferred_lifetime(preferred_lifetime),
|
||||
valid_lifetime(valid_lifetime), options(options) {}
|
||||
|
||||
static ia_address_type from_option(const option &opt);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -228,6 +234,8 @@ public:
|
||||
const auth_info_type &auth_info = auth_info_type())
|
||||
: protocol(protocol), algorithm(algorithm), rdm(rdm),
|
||||
replay_detection(replay_detection), auth_info(auth_info) {}
|
||||
|
||||
static authentication_type from_option(const option &opt);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -239,6 +247,8 @@ public:
|
||||
|
||||
status_code_type(uint16_t code = 0, const std::string &message = "")
|
||||
: code(code), message(message) { }
|
||||
|
||||
static status_code_type from_option(const option &opt);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -253,6 +263,8 @@ public:
|
||||
vendor_info_type(uint32_t enterprise_number = 0,
|
||||
const data_type &data = data_type())
|
||||
: enterprise_number(enterprise_number), data(data) { }
|
||||
|
||||
static vendor_info_type from_option(const option &opt);
|
||||
};
|
||||
|
||||
|
||||
@@ -264,7 +276,19 @@ public:
|
||||
/**
|
||||
* The type used to store the User Class option.
|
||||
*/
|
||||
typedef std::vector<class_option_data_type> user_class_type;
|
||||
//typedef std::vector<class_option_data_type> user_class_type;
|
||||
struct user_class_type {
|
||||
typedef std::vector<class_option_data_type> data_type;
|
||||
data_type data;
|
||||
|
||||
user_class_type(const data_type &data = data_type())
|
||||
: data(data)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
static user_class_type from_option(const option &opt);
|
||||
};
|
||||
|
||||
/**
|
||||
* The type used to store the Vendor Class option.
|
||||
@@ -279,6 +303,8 @@ public:
|
||||
const class_data_type &vendor_class_data = class_data_type())
|
||||
: enterprise_number(enterprise_number),
|
||||
vendor_class_data(vendor_class_data) { }
|
||||
|
||||
static vendor_class_type from_option(const option &opt);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -361,12 +387,14 @@ public:
|
||||
|
||||
duid_type(const duid_ll &identifier)
|
||||
: id(duid_en::duid_id), data(identifier.serialize()) {}
|
||||
|
||||
static duid_type from_option(const option &opt);
|
||||
};
|
||||
|
||||
/**
|
||||
* The type used to store the Option Request option.
|
||||
*/
|
||||
typedef std::vector<OptionTypes> option_request_type;
|
||||
typedef std::vector<uint16_t> option_request_type;
|
||||
|
||||
/**
|
||||
* The type used to store the Relay Message option.
|
||||
@@ -837,52 +865,61 @@ private:
|
||||
throw option_not_found();
|
||||
return option;
|
||||
}
|
||||
|
||||
template<typename InputIterator>
|
||||
void class_option_data2option(InputIterator start, InputIterator end,
|
||||
std::vector<uint8_t>& buffer, size_t start_index = 0)
|
||||
{
|
||||
size_t index = start_index;
|
||||
while(start != end) {
|
||||
buffer.resize(buffer.size() + sizeof(uint16_t) + start->size());
|
||||
*(uint16_t*)&buffer[index] = Endian::host_to_be<uint16_t>(start->size());
|
||||
index += sizeof(uint16_t);
|
||||
std::copy(start->begin(), start->end(), buffer.begin() + index);
|
||||
index += start->size();
|
||||
|
||||
start++;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename OutputType>
|
||||
OutputType option2class_option_data(const uint8_t *ptr, uint32_t total_sz) const
|
||||
{
|
||||
typedef typename OutputType::value_type value_type;
|
||||
OutputType output;
|
||||
size_t index = 0;
|
||||
while(index + 2 < total_sz) {
|
||||
uint16_t size = Endian::be_to_host(
|
||||
*(const uint16_t*)(ptr + index)
|
||||
);
|
||||
index += sizeof(uint16_t);
|
||||
if(index + size > total_sz)
|
||||
throw option_not_found();
|
||||
output.push_back(
|
||||
value_type(ptr + index, ptr + index + size)
|
||||
);
|
||||
index += size;
|
||||
}
|
||||
if(index != total_sz)
|
||||
|
||||
template<typename T>
|
||||
T search_and_convert(OptionTypes opt) const {
|
||||
const option *option = search_option(opt);
|
||||
if(!option)
|
||||
throw option_not_found();
|
||||
return output;
|
||||
return option->to<T>();
|
||||
}
|
||||
|
||||
|
||||
uint8_t header_data[4];
|
||||
uint32_t options_size;
|
||||
ipaddress_type link_addr, peer_addr;
|
||||
options_type options_;
|
||||
};
|
||||
};
|
||||
|
||||
namespace Internals {
|
||||
template<typename InputIterator>
|
||||
void class_option_data2option(InputIterator start, InputIterator end,
|
||||
std::vector<uint8_t>& buffer, size_t start_index = 0)
|
||||
{
|
||||
size_t index = start_index;
|
||||
while(start != end) {
|
||||
buffer.resize(buffer.size() + sizeof(uint16_t) + start->size());
|
||||
*(uint16_t*)&buffer[index] = Endian::host_to_be<uint16_t>(start->size());
|
||||
index += sizeof(uint16_t);
|
||||
std::copy(start->begin(), start->end(), buffer.begin() + index);
|
||||
index += start->size();
|
||||
|
||||
start++;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename OutputType>
|
||||
OutputType option2class_option_data(const uint8_t *ptr, uint32_t total_sz)
|
||||
{
|
||||
typedef typename OutputType::value_type value_type;
|
||||
OutputType output;
|
||||
size_t index = 0;
|
||||
while(index + 2 < total_sz) {
|
||||
uint16_t size = Endian::be_to_host(
|
||||
*(const uint16_t*)(ptr + index)
|
||||
);
|
||||
index += sizeof(uint16_t);
|
||||
if(index + size > total_sz)
|
||||
throw option_not_found();
|
||||
output.push_back(
|
||||
value_type(ptr + index, ptr + index + size)
|
||||
);
|
||||
index += size;
|
||||
}
|
||||
if(index != total_sz)
|
||||
throw malformed_option();
|
||||
return output;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif // TINS_DHCPV6_H
|
||||
|
||||
231
include/dns.h
231
include/dns.h
@@ -39,7 +39,6 @@
|
||||
#include "macros.h"
|
||||
#include "pdu.h"
|
||||
#include "endianness.h"
|
||||
#include "dns_record.h"
|
||||
|
||||
namespace Tins {
|
||||
class IPv4Address;
|
||||
@@ -200,14 +199,24 @@ namespace Tins {
|
||||
*/
|
||||
class Resource {
|
||||
public:
|
||||
Resource(const std::string &nm, const std::string &ad,
|
||||
uint16_t t, uint16_t c, uint32_t tt)
|
||||
: dname_(nm), addr_(ad), type_(t), qclass_(c), ttl_(tt) {}
|
||||
/**
|
||||
* Constructs a Resource object.
|
||||
*
|
||||
* \param dname The domain name for which this records
|
||||
* provides an answer.
|
||||
* \param data The resource's payload.
|
||||
* \param type The type of this record.
|
||||
* \param rclass The class of this record.
|
||||
* \param ttl The time-to-live of this record.
|
||||
*/
|
||||
Resource(const std::string &dname, const std::string &data,
|
||||
uint16_t type, uint16_t rclass, uint32_t ttl)
|
||||
: dname_(dname), data_(data), type_(type), qclass_(rclass), ttl_(ttl) {}
|
||||
|
||||
Resource() : type_(), qclass_(), ttl_() {}
|
||||
|
||||
/**
|
||||
* \brief Getter for the dname field.
|
||||
* \brief Getter for the domain name field.
|
||||
*
|
||||
* This returns the domain name for which this record
|
||||
* provides an answer.
|
||||
@@ -215,9 +224,9 @@ namespace Tins {
|
||||
const std::string &dname() const { return dname_; }
|
||||
|
||||
/**
|
||||
* Getter for the type field.
|
||||
* Getter for the data field.
|
||||
*/
|
||||
const std::string &data() const { return addr_; }
|
||||
const std::string &data() const { return data_; }
|
||||
|
||||
/**
|
||||
* Getter for the query type field.
|
||||
@@ -233,8 +242,52 @@ namespace Tins {
|
||||
* Getter for the type field.
|
||||
*/
|
||||
uint32_t ttl() const { return ttl_; }
|
||||
|
||||
/**
|
||||
* Setter for the domain name field.
|
||||
*/
|
||||
void dname(const std::string &data) {
|
||||
dname_ = data;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Setter for the data field.
|
||||
*
|
||||
* The data will be encoded properly by the DNS class before
|
||||
* being added to this packet. That means that if the type is
|
||||
* A or AAAA, it will be properly encoded as an IPv4 or
|
||||
* IPv6 address.
|
||||
*
|
||||
* The same happens for records that contain domain names,
|
||||
* such as NS or CNAME. This data will be encoded using
|
||||
* DNS domain name encoding.
|
||||
*/
|
||||
void data(const std::string &data) {
|
||||
data_ = data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter for the type field.
|
||||
*/
|
||||
void type(uint16_t data) {
|
||||
type_ = data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter for the class field.
|
||||
*/
|
||||
void query_class(uint16_t data) {
|
||||
qclass_ = data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter for the time-to-live field.
|
||||
*/
|
||||
void ttl(uint16_t data) {
|
||||
ttl_ = data;
|
||||
}
|
||||
private:
|
||||
std::string dname_, addr_;
|
||||
std::string dname_, data_;
|
||||
uint16_t type_, qclass_;
|
||||
uint32_t ttl_;
|
||||
};
|
||||
@@ -482,100 +535,71 @@ namespace Tins {
|
||||
void add_query(const Query &query);
|
||||
|
||||
/**
|
||||
* \brief Add a query response.
|
||||
* \brief Add an answer resource record.
|
||||
*
|
||||
* \param name The resolved name.
|
||||
* \param type The type of this answer.
|
||||
* \param qclass The class of this answer.
|
||||
* \param ttl The time-to-live of this answer.
|
||||
* \param ip The ip address of the resolved name.
|
||||
* \param resource The resource to be added.
|
||||
*/
|
||||
void add_answer(const std::string &name,
|
||||
const DNSResourceRecord::info &info, address_type ip);
|
||||
|
||||
void add_answer(const Resource &resource);
|
||||
|
||||
/**
|
||||
* \brief Add a query response.
|
||||
* \brief Add an authority resource record.
|
||||
*
|
||||
* \param name The resolved name.
|
||||
* \param type The type of this answer.
|
||||
* \param qclass The class of this answer.
|
||||
* \param ttl The time-to-live of this answer.
|
||||
* \param ip The ip address of the resolved name.
|
||||
* \param resource The resource to be added.
|
||||
*/
|
||||
void add_answer(const std::string &name,
|
||||
const DNSResourceRecord::info &info, address_v6_type ip);
|
||||
|
||||
/**
|
||||
* \brief Add a query response.
|
||||
*
|
||||
* \param name The resolved name.
|
||||
* \param type The type of this answer.
|
||||
* \param qclass The class of this answer.
|
||||
* \param ttl The time-to-live of this answer.
|
||||
* \param dname The domain of the resolved name.
|
||||
*/
|
||||
void add_answer(const std::string &name,
|
||||
const DNSResourceRecord::info &info, const std::string &dname);
|
||||
|
||||
/**
|
||||
* \brief Add a query response.
|
||||
*
|
||||
* \param name The resolved name.
|
||||
* \param type The type of this answer.
|
||||
* \param qclass The class of this answer.
|
||||
* \param ttl The time-to-live of this answer.
|
||||
* \param data The data of this option.
|
||||
* \param sz The size of the data.
|
||||
*/
|
||||
void add_answer(const std::string &name,
|
||||
const DNSResourceRecord::info &info, const uint8_t *data, uint32_t sz);
|
||||
void add_authority(const Resource &resource);
|
||||
|
||||
/**
|
||||
* \brief Add an authority record.
|
||||
* \brief Add an additional resource record.
|
||||
*
|
||||
* \param name The resolved name.
|
||||
* \param type The type of this record.
|
||||
* \param qclass The class of this record.
|
||||
* \param ttl The time-to-live of this record.
|
||||
* \param data The data of this option.
|
||||
* \param sz The size of the data.
|
||||
* \param resource The resource to be added.
|
||||
*/
|
||||
void add_authority(const std::string &name,
|
||||
const DNSResourceRecord::info &info, const uint8_t *data, uint32_t sz);
|
||||
|
||||
/**
|
||||
* \brief Add an additional record.
|
||||
*
|
||||
* \param name The resolved name.
|
||||
* \param type The type of this record.
|
||||
* \param qclass The class of this record.
|
||||
* \param ttl The time-to-live of this record.
|
||||
* \param ip The ip address of the resolved name.
|
||||
*/
|
||||
void add_additional(const std::string &name,
|
||||
const DNSResourceRecord::info &info, uint32_t ip);
|
||||
|
||||
void add_additional(const Resource &resource);
|
||||
|
||||
/**
|
||||
* \brief Getter for this PDU's DNS queries.
|
||||
*
|
||||
* This method is <b>not thread safe</b>.
|
||||
*
|
||||
* \return std::list<Query> containing the queries in this
|
||||
* record.
|
||||
* \return The query records in this PDU.
|
||||
*/
|
||||
queries_type queries() const;
|
||||
|
||||
/**
|
||||
* \brief Getter for this PDU's DNS answers
|
||||
*
|
||||
* This method is <b>not thread safe</b>.
|
||||
*
|
||||
* \return std::list<Resource> containing the answers in this
|
||||
* record.
|
||||
* \return The answer records in this PDU.
|
||||
*/
|
||||
resources_type answers() const;
|
||||
|
||||
/**
|
||||
* \brief Getter for this PDU's DNS authority records.
|
||||
*
|
||||
* \return The authority records in this PDU.
|
||||
*/
|
||||
resources_type authority() const;
|
||||
|
||||
/**
|
||||
* \brief Getter for this PDU's DNS additional records.
|
||||
*
|
||||
* \return The additional records in this PDU.
|
||||
*/
|
||||
resources_type additional() const;
|
||||
|
||||
/**
|
||||
* \brief Encodes a domain name.
|
||||
*
|
||||
* This processes the input domain name and returns the encoded
|
||||
* version. Each label in the original domain name will be
|
||||
* prefixed with a byte that indicates the label's length.
|
||||
* The null-terminator byte <b>will</b> be included in the encoded
|
||||
* string. No compression is performed.
|
||||
*
|
||||
* For example, given the input "www.example.com", the output would
|
||||
* be "\x03www\x07example\x03com\x00".
|
||||
*
|
||||
* \param domain_name The domain name to encode.
|
||||
* \return The encoded domain name.
|
||||
*/
|
||||
static std::string encode_domain_name(const std::string &domain_name);
|
||||
|
||||
/**
|
||||
* \brief Check wether ptr points to a valid response for this PDU.
|
||||
*
|
||||
@@ -591,17 +615,6 @@ namespace Tins {
|
||||
DNS *clone() const {
|
||||
return new DNS(*this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to create a resource record information.
|
||||
*
|
||||
* \param type The type of the query.
|
||||
* \param qclass The class of the query.
|
||||
* \param ttl The time-to-live of the query.
|
||||
*/
|
||||
static DNSResourceRecord::info make_info(QueryType type, QueryClass qclass, uint32_t ttl) {
|
||||
return DNSResourceRecord::info((uint16_t)type, (uint16_t)qclass, ttl);
|
||||
}
|
||||
private:
|
||||
TINS_BEGIN_PACK
|
||||
struct dnshdr {
|
||||
@@ -635,35 +648,23 @@ namespace Tins {
|
||||
authority, additional;
|
||||
} TINS_END_PACK;
|
||||
|
||||
typedef std::map<uint16_t, std::string> SuffixMap;
|
||||
typedef std::map<uint16_t, uint16_t> SuffixIndices;
|
||||
typedef std::list<DNSResourceRecord> ResourcesType;
|
||||
typedef std::list<Query> QueriesType;
|
||||
typedef std::vector<std::pair<uint32_t*, uint32_t> > sections_type;
|
||||
|
||||
const uint8_t *build_resource_list(ResourcesType &lst, const uint8_t *ptr, uint32_t &sz, uint16_t nrecs);
|
||||
uint32_t find_domain_name(const std::string &dname);
|
||||
bool find_domain_name(const std::string &dname, const ResourcesType &lst, uint16_t &out);
|
||||
void parse_domain_name(const std::string &dn, std::string &out) const;
|
||||
void unparse_domain_name(const std::string &dn, std::string &out) const;
|
||||
void write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *parent);
|
||||
uint8_t *serialize_list(const ResourcesType &lst, uint8_t *buffer) const;
|
||||
void compose_name(const uint8_t *ptr, uint32_t sz, std::string &out) const;
|
||||
void convert_resources(const ResourcesType &lst, std::list<Resource> &res) const;
|
||||
DNSResourceRecord make_record(const std::string &name, const DNSResourceRecord::info &info, uint32_t ip);
|
||||
DNSResourceRecord make_record(const std::string &name, const DNSResourceRecord::info &info, const std::string &dname);
|
||||
DNSResourceRecord make_record(const std::string &name, const DNSResourceRecord::info &info, const uint8_t *ptr, uint32_t len);
|
||||
void add_suffix(uint32_t index, const uint8_t *data, uint32_t sz) const;
|
||||
uint32_t build_suffix_map(uint32_t index, const ResourcesType &lst) const;
|
||||
uint32_t build_suffix_map(uint32_t index, const QueriesType &lst) const;
|
||||
void build_suffix_map() const ;
|
||||
const uint8_t* compose_name(const uint8_t *ptr, char *out_ptr) const;
|
||||
void convert_records(const uint8_t *ptr, const uint8_t *end, resources_type &res) const;
|
||||
const uint8_t* find_section_end(const uint8_t *ptr, const uint32_t num_records) const;
|
||||
const uint8_t* find_dname_end(const uint8_t *ptr) const;
|
||||
void update_records(uint32_t §ion_start, uint32_t num_records, uint32_t threshold, uint32_t offset);
|
||||
uint8_t *update_dname(uint8_t *ptr, uint32_t threshold, uint32_t offset);
|
||||
static void inline_convert_v4(uint32_t value, char *output);
|
||||
static bool contains_dname(uint16_t type);
|
||||
void write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *parent);
|
||||
void add_record(const Resource &resource, const sections_type §ions);
|
||||
|
||||
dnshdr dns;
|
||||
uint32_t extra_size;
|
||||
std::list<Query> queries_;
|
||||
ResourcesType ans, arity, addit;
|
||||
mutable SuffixMap suffixes;
|
||||
mutable SuffixIndices suffix_indices;
|
||||
byte_array records_data;
|
||||
uint32_t answers_idx, authority_idx, additional_idx;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -1,272 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2012, Matias Fontanini
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following disclaimer
|
||||
* in the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef TINS_DNS_RECORD_H
|
||||
#define TINS_DNS_RECORD_H
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <stdint.h>
|
||||
#include "cxxstd.h"
|
||||
#include "macros.h"
|
||||
|
||||
namespace Tins {
|
||||
/**
|
||||
* \cond
|
||||
*/
|
||||
class DNSRRImpl {
|
||||
public:
|
||||
virtual ~DNSRRImpl() {}
|
||||
virtual uint32_t size() const = 0;
|
||||
virtual uint32_t do_write(uint8_t *buffer) const = 0;
|
||||
virtual bool matches(const std::string &dname) const { return false; }
|
||||
virtual DNSRRImpl *clone() const = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Abstracts a DNS resource record.
|
||||
*/
|
||||
class DNSResourceRecord {
|
||||
public:
|
||||
/**
|
||||
* \brief The type used to store resource records' information.
|
||||
*/
|
||||
TINS_BEGIN_PACK
|
||||
struct info {
|
||||
uint16_t type, qclass;
|
||||
uint32_t ttl;
|
||||
|
||||
info(uint16_t tp, uint16_t qc, uint32_t tm)
|
||||
: type(tp), qclass(qc), ttl(tm) { }
|
||||
|
||||
info() : type(), qclass(), ttl() {}
|
||||
} TINS_END_PACK;
|
||||
|
||||
/**
|
||||
* \brief Constructs a record.
|
||||
* \param impl A pointer to the impl object.
|
||||
* \param data A pointer to the start of the data buffer.
|
||||
* \param len The length of the data.
|
||||
*/
|
||||
DNSResourceRecord(DNSRRImpl *impl = 0, const uint8_t *data = 0, uint16_t len = 0);
|
||||
|
||||
/**
|
||||
* \brief Constructs a record.
|
||||
*
|
||||
* If the input data is malformed, a malformed_packet exception
|
||||
* is thrown.
|
||||
*
|
||||
* \param buffer A pointer to the start of the data buffer.
|
||||
* \param len The length of the data.
|
||||
*/
|
||||
DNSResourceRecord(const uint8_t *buffer, uint32_t size);
|
||||
|
||||
/**
|
||||
* \brief Constructs a record from an input range.
|
||||
* \param impl A pointer to the impl object.
|
||||
* \param start The begining of the range.
|
||||
* \param end The end of the range.
|
||||
*/
|
||||
template<typename ForwardIterator>
|
||||
DNSResourceRecord(DNSRRImpl *impl, ForwardIterator start, ForwardIterator end)
|
||||
: impl(impl), data(start, end)
|
||||
{ }
|
||||
|
||||
/**
|
||||
* \brief Copy constructor.
|
||||
*
|
||||
* This handles cloning the impl object.
|
||||
* \param rhs The record which will be copied.
|
||||
*/
|
||||
DNSResourceRecord(const DNSResourceRecord &rhs);
|
||||
|
||||
/**
|
||||
* \brief Copy assignment operator.
|
||||
*
|
||||
* This handles cloning the impl object.
|
||||
* \param rhs The record which will be copied.
|
||||
*/
|
||||
DNSResourceRecord& operator=(const DNSResourceRecord &rhs);
|
||||
|
||||
#if TINS_IS_CXX11
|
||||
/**
|
||||
* Move constructor.
|
||||
*/
|
||||
DNSResourceRecord(DNSResourceRecord &&rhs) noexcept
|
||||
: info_(rhs.info_), data(std::move(rhs.data)), impl(0) {
|
||||
std::swap(impl, rhs.impl);
|
||||
}
|
||||
|
||||
/**
|
||||
* Move assignment operator.
|
||||
*/
|
||||
DNSResourceRecord& operator=(DNSResourceRecord &&rhs) noexcept
|
||||
{
|
||||
info_ = rhs.info_;
|
||||
data = std::move(rhs.data);
|
||||
delete impl;
|
||||
impl = 0;
|
||||
std::swap(impl, rhs.impl);
|
||||
return *this;
|
||||
}
|
||||
#endif // TINS_IS_CXX11
|
||||
|
||||
/**
|
||||
* \brief Destructor.
|
||||
*
|
||||
* This frees the impl object.
|
||||
*/
|
||||
~DNSResourceRecord();
|
||||
|
||||
/**
|
||||
* \brief Writes this record to a buffer.
|
||||
*
|
||||
* \param buffer The buffer in which to store the serialization.
|
||||
* \return uint32_t containing the number of bytes written.
|
||||
*/
|
||||
uint32_t write(uint8_t *buffer) const;
|
||||
|
||||
/**
|
||||
* \brief Returns the size of the data in this record.
|
||||
*/
|
||||
uint32_t data_size() const {
|
||||
return data.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Returns the pointer to the start of the data buffer.
|
||||
*/
|
||||
const uint8_t *data_ptr() const {
|
||||
return &data[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Returns a bool indicating whether this record contains
|
||||
* a domain name as the name being resolved.
|
||||
*/
|
||||
bool has_domain_name() const;
|
||||
|
||||
/**
|
||||
* \brief Returns a pointer to the domain name stored in this record.
|
||||
*
|
||||
* This will throw a std::bad_cast exception if the impl object is
|
||||
* not of the type NamedDNSRRImpl.
|
||||
*/
|
||||
const std::string *dname() const;
|
||||
|
||||
/**
|
||||
* \brief Returns the offset stored in this record.
|
||||
*
|
||||
* This will throw a std::bad_cast exception if the impl object is
|
||||
* not of the type OffsetedDNSRRImpl.
|
||||
*/
|
||||
uint16_t offset() const;
|
||||
|
||||
/**
|
||||
* \brief Returns the size of this record.
|
||||
*/
|
||||
uint32_t size() const;
|
||||
|
||||
/**
|
||||
* \brief Returns a reference to the info field.
|
||||
*/
|
||||
info &information() {
|
||||
return info_;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Returns a const reference to the info field.
|
||||
*/
|
||||
const info &information() const {
|
||||
return info_;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Checks if the domain name stored in this record matches
|
||||
* the given one.
|
||||
*
|
||||
* This is a shortcut
|
||||
*/
|
||||
bool matches(const std::string &dname) const;
|
||||
private:
|
||||
DNSRRImpl *clone_impl() const;
|
||||
size_t impl_size() const;
|
||||
|
||||
info info_;
|
||||
std::vector<uint8_t> data;
|
||||
DNSRRImpl *impl;
|
||||
};
|
||||
|
||||
class OffsetedDNSRRImpl : public DNSRRImpl {
|
||||
public:
|
||||
OffsetedDNSRRImpl(uint16_t off);
|
||||
|
||||
uint32_t do_write(uint8_t *buffer) const;
|
||||
uint32_t size() const;
|
||||
OffsetedDNSRRImpl *clone() const;
|
||||
uint16_t offset() const;
|
||||
private:
|
||||
uint16_t offset_;
|
||||
};
|
||||
|
||||
class NamedDNSRRImpl : public DNSRRImpl {
|
||||
public:
|
||||
NamedDNSRRImpl(const std::string &nm);
|
||||
|
||||
template<typename ForwardIterator>
|
||||
NamedDNSRRImpl(ForwardIterator start, ForwardIterator end)
|
||||
: name(start, end)
|
||||
{ }
|
||||
|
||||
uint32_t do_write(uint8_t *buffer) const;
|
||||
|
||||
uint32_t size() const;
|
||||
|
||||
bool matches(const std::string &dname) const;
|
||||
|
||||
const std::string *dname_pointer() const;
|
||||
NamedDNSRRImpl *clone() const;
|
||||
private:
|
||||
std::string name;
|
||||
};
|
||||
|
||||
/**
|
||||
* \endcond
|
||||
*/
|
||||
|
||||
inline DNSResourceRecord make_offseted_record(uint16_t offset, const uint8_t *data = 0, uint32_t size = 0) {
|
||||
return DNSResourceRecord(new OffsetedDNSRRImpl(offset), data, size);
|
||||
}
|
||||
|
||||
inline DNSResourceRecord make_named_record(const std::string &name, const uint8_t *data = 0, uint32_t size = 0) {
|
||||
return DNSResourceRecord(new NamedDNSRRImpl(name), data, size);
|
||||
}
|
||||
}
|
||||
|
||||
#endif // TINS_DNS_RECORD_H
|
||||
@@ -27,7 +27,9 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef TINS_DOT_11
|
||||
#include "config.h"
|
||||
|
||||
#if !defined(TINS_DOT_11) && defined(HAVE_DOT11)
|
||||
#define TINS_DOT_11
|
||||
|
||||
#include "dot11/dot11_base.h"
|
||||
|
||||
@@ -27,7 +27,9 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef TINS_DOT11_DOT11_ASSOC_H
|
||||
#include "../config.h"
|
||||
|
||||
#if !defined(TINS_DOT11_DOT11_ASSOC_H) && defined(HAVE_DOT11)
|
||||
#define TINS_DOT11_DOT11_ASSOC_H
|
||||
|
||||
#include "../dot11/dot11_mgmt.h"
|
||||
|
||||
@@ -27,7 +27,9 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef TINS_DOT11_DOT11_AUTH_H
|
||||
#include "../config.h"
|
||||
|
||||
#if !defined(TINS_DOT11_DOT11_AUTH_H) && defined(HAVE_DOT11)
|
||||
#define TINS_DOT11_DOT11_AUTH_H
|
||||
|
||||
#include "../dot11/dot11_mgmt.h"
|
||||
|
||||
@@ -27,7 +27,9 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef TINS_DOT11_DOT11_H
|
||||
#include "../config.h"
|
||||
|
||||
#if !defined(TINS_DOT11_DOT11_H) && defined(HAVE_DOT11)
|
||||
#define TINS_DOT11_DOT11_H
|
||||
|
||||
#include <list>
|
||||
@@ -55,7 +57,7 @@ public:
|
||||
/**
|
||||
* \brief IEEE 802.11 options struct.
|
||||
*/
|
||||
typedef PDUOption<uint8_t> option;
|
||||
typedef PDUOption<uint8_t, Dot11> option;
|
||||
|
||||
/**
|
||||
* The type used to store tagged options.
|
||||
@@ -72,6 +74,11 @@ public:
|
||||
*/
|
||||
static const address_type BROADCAST;
|
||||
|
||||
/**
|
||||
* The endianness used by Dot11.
|
||||
*/
|
||||
static const endian_type endianness = LE;
|
||||
|
||||
/**
|
||||
* \brief Enum for the different types of 802.11 frames.
|
||||
*
|
||||
|
||||
@@ -27,7 +27,9 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef TINS_DOT11_DOT11_BEACON_H
|
||||
#include "../config.h"
|
||||
|
||||
#if !defined(TINS_DOT11_DOT11_BEACON_H) && defined(HAVE_DOT11)
|
||||
#define TINS_DOT11_DOT11_BEACON_H
|
||||
|
||||
#include "../dot11/dot11_mgmt.h"
|
||||
|
||||
@@ -27,7 +27,10 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef TINS_DOT11_DOT11_CONTROL_H
|
||||
#include "../config.h"
|
||||
|
||||
#if !defined(TINS_DOT11_DOT11_CONTROL_H) && defined(HAVE_DOT11)
|
||||
|
||||
#define TINS_DOT11_DOT11_CONTROL_H
|
||||
|
||||
#include "../dot11/dot11_base.h"
|
||||
|
||||
@@ -27,7 +27,9 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef TINS_DOT11_DOT11_DATA_H
|
||||
#include "../config.h"
|
||||
|
||||
#if !defined(TINS_DOT11_DOT11_DATA_H) && defined(HAVE_DOT11)
|
||||
#define TINS_DOT11_DOT11_DATA_H
|
||||
|
||||
#include "../dot11/dot11_base.h"
|
||||
|
||||
@@ -27,7 +27,10 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef TINS_DOT11_DOT11_MGMT_H
|
||||
#include "../config.h"
|
||||
|
||||
#if !defined(TINS_DOT11_DOT11_MGMT_H) && defined(HAVE_DOT11)
|
||||
|
||||
#define TINS_DOT11_DOT11_MGMT_H
|
||||
|
||||
#include <vector>
|
||||
@@ -376,6 +379,8 @@ public:
|
||||
uint8_t hop_pattern, uint8_t hop_index)
|
||||
: dwell_time(dwell_time), hop_set(hop_set),
|
||||
hop_pattern(hop_pattern), hop_index(hop_index) {}
|
||||
|
||||
static fh_params_set from_option(const option &opt);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -392,6 +397,8 @@ public:
|
||||
: cfp_count(cfp_count), cfp_period(cfp_period),
|
||||
cfp_max_duration(cfp_max_duration),
|
||||
cfp_dur_remaining(cfp_dur_remaining) {}
|
||||
|
||||
static cf_params_set from_option(const option &opt);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -410,6 +417,8 @@ public:
|
||||
uint8_t recovery_interval, const channels_type &channels)
|
||||
: dfs_owner(addr), recovery_interval(recovery_interval),
|
||||
channel_map(channels) {}
|
||||
|
||||
static ibss_dfs_params from_option(const option &opt);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -428,6 +437,8 @@ public:
|
||||
const byte_array &number, const byte_array &max)
|
||||
: country(country), first_channel(first), number_channels(number),
|
||||
max_transmit_power(max) {}
|
||||
|
||||
static country_params from_option(const option &opt);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -445,6 +456,8 @@ public:
|
||||
uint8_t offset, const byte_array& table)
|
||||
: flag(flag), number_of_sets(sets), modulus(modulus),
|
||||
offset(offset), random_table(table) {}
|
||||
|
||||
static fh_pattern_type from_option(const option &opt);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -457,6 +470,8 @@ public:
|
||||
|
||||
channel_switch_type(uint8_t mode, uint8_t channel, uint8_t count)
|
||||
: switch_mode(mode), new_channel(channel), switch_count(count) { }
|
||||
|
||||
static channel_switch_type from_option(const option &opt);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -472,6 +487,8 @@ public:
|
||||
uint16_t offset)
|
||||
: quiet_count(count), quiet_period(period),
|
||||
quiet_duration(duration), quiet_offset(offset) {}
|
||||
|
||||
static quiet_type from_option(const option &opt);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -488,6 +505,8 @@ public:
|
||||
uint16_t capacity)
|
||||
: station_count(count), available_capacity(capacity),
|
||||
channel_utilization(utilization) {}
|
||||
|
||||
static bss_load_type from_option(const option &opt);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -503,6 +522,8 @@ public:
|
||||
const byte_array &bitmap)
|
||||
: dtim_count(count), dtim_period(period), bitmap_control(control),
|
||||
partial_virtual_bitmap(bitmap) {}
|
||||
|
||||
static tim_type from_option(const option &opt);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -520,6 +541,11 @@ public:
|
||||
|
||||
static vendor_specific_type from_bytes(const uint8_t *buffer, uint32_t sz);
|
||||
};
|
||||
|
||||
/**
|
||||
* The type used to store the QOS capability tagged option data.
|
||||
*/
|
||||
typedef uint8_t qos_capability_type;
|
||||
|
||||
/**
|
||||
* \brief Getter for the second address.
|
||||
@@ -638,7 +664,7 @@ public:
|
||||
*
|
||||
* \param new_qos_capabilities uint8_t with the capabilities.
|
||||
*/
|
||||
void qos_capability(uint8_t new_qos_capability);
|
||||
void qos_capability(qos_capability_type new_qos_capability);
|
||||
|
||||
/**
|
||||
* \brief Helper method to set the power capabilities option.
|
||||
@@ -848,7 +874,7 @@ public:
|
||||
*
|
||||
* \return uint8_t containing the QOS capability.
|
||||
*/
|
||||
uint8_t qos_capability() const;
|
||||
qos_capability_type qos_capability() const;
|
||||
|
||||
/**
|
||||
* \brief Helper method to get the power capability.
|
||||
@@ -1117,6 +1143,14 @@ protected:
|
||||
private:
|
||||
static uint8_t *serialize_rates(const rates_type &rates);
|
||||
static rates_type deserialize_rates(const option *option);
|
||||
|
||||
template<typename T>
|
||||
T search_and_convert(OptionTypes opt_type) const {
|
||||
const option *opt = search_option(opt_type);
|
||||
if(!opt)
|
||||
throw option_not_found();
|
||||
return opt->to<T>();
|
||||
}
|
||||
|
||||
ExtendedHeader _ext_header;
|
||||
address_type _addr4;
|
||||
|
||||
@@ -27,7 +27,10 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef TINS_DOT11_DOT11_PROBE_H
|
||||
#include "../config.h"
|
||||
|
||||
#if !defined(TINS_DOT11_DOT11_PROBE_H) && defined(HAVE_DOT11)
|
||||
|
||||
#define TINS_DOT11_DOT11_PROBE_H
|
||||
|
||||
#include "../dot11/dot11_mgmt.h"
|
||||
|
||||
@@ -55,6 +55,16 @@
|
||||
|
||||
namespace Tins {
|
||||
namespace Endian {
|
||||
/**
|
||||
* \brief "Changes" a 8-bit integral value's endianess. This is an
|
||||
* identity function.
|
||||
*
|
||||
* \param data The data to convert.
|
||||
*/
|
||||
inline uint8_t do_change_endian(uint8_t data) {
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Changes a 16-bit integral value's endianess.
|
||||
*
|
||||
@@ -100,6 +110,11 @@ namespace Endian {
|
||||
template<size_t>
|
||||
struct conversion_dispatcher;
|
||||
|
||||
template<>
|
||||
struct conversion_dispatcher<sizeof(uint8_t)>
|
||||
: public conversion_dispatch_helper<uint8_t>
|
||||
{ };
|
||||
|
||||
template<>
|
||||
struct conversion_dispatcher<sizeof(uint16_t)>
|
||||
: public conversion_dispatch_helper<uint16_t>
|
||||
|
||||
@@ -145,6 +145,28 @@ public:
|
||||
return "Malformed option";
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Exception thrown when a call to tins_cast fails.
|
||||
*/
|
||||
class bad_tins_cast : public std::exception {
|
||||
public:
|
||||
const char *what() const throw() {
|
||||
return "Bad Tins cast";
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Exception thrown when sniffing a protocol that
|
||||
* has been disabled at compile time.
|
||||
*/
|
||||
class protocol_disabled : public std::exception {
|
||||
public:
|
||||
const char *what() const throw() {
|
||||
return "Protocol disabled";
|
||||
}
|
||||
};
|
||||
|
||||
} // Tins
|
||||
|
||||
#endif // TINS_EXCEPTIONS_H
|
||||
|
||||
@@ -27,7 +27,9 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef TINS_HANDSHAKE_CAPTURER_H
|
||||
#include "config.h"
|
||||
|
||||
#if !defined(TINS_HANDSHAKE_CAPTURER_H) && defined(HAVE_DOT11)
|
||||
#define TINS_HANDSHAKE_CAPTURER_H
|
||||
|
||||
#include <vector>
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
#include "macros.h"
|
||||
#include "pdu.h"
|
||||
#include "endianness.h"
|
||||
#include "ip_address.h"
|
||||
|
||||
namespace Tins {
|
||||
|
||||
@@ -48,6 +49,11 @@ namespace Tins {
|
||||
*/
|
||||
static const PDU::PDUType pdu_flag = PDU::ICMP;
|
||||
|
||||
/**
|
||||
* The type used to store addresses.
|
||||
*/
|
||||
typedef IPv4Address address_type;
|
||||
|
||||
/** \brief ICMP flags
|
||||
*/
|
||||
enum Flags {
|
||||
@@ -58,8 +64,12 @@ namespace Tins {
|
||||
ECHO_REQUEST = 8,
|
||||
TIME_EXCEEDED = 11,
|
||||
PARAM_PROBLEM = 12,
|
||||
TIMESTAMP_REQUEST = 13,
|
||||
TIMESTAMP_REPLY = 14,
|
||||
INFO_REQUEST = 15,
|
||||
INFO_REPLY = 16
|
||||
INFO_REPLY = 16,
|
||||
ADDRESS_MASK_REQUEST = 17,
|
||||
ADDRESS_MASK_REPLY = 18
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -113,9 +123,9 @@ namespace Tins {
|
||||
/**
|
||||
* \brief Setter for the gateway field.
|
||||
*
|
||||
* \param new_gw uint32_t with the new gateway.
|
||||
* \param new_gw The new value for the gateway field.
|
||||
*/
|
||||
void gateway(uint32_t new_gw);
|
||||
void gateway(address_type new_gw);
|
||||
|
||||
/**
|
||||
* \brief Setter for the mtu field.
|
||||
@@ -131,6 +141,34 @@ namespace Tins {
|
||||
*/
|
||||
void pointer(uint8_t new_pointer);
|
||||
|
||||
/**
|
||||
* \brief Setter for the original timestamp field.
|
||||
*
|
||||
* \param new_timestamp the value to be set.
|
||||
*/
|
||||
void original_timestamp(uint32_t new_timestamp);
|
||||
|
||||
/**
|
||||
* \brief Setter for the receive timestamp field.
|
||||
*
|
||||
* \param new_timestamp the value to be set.
|
||||
*/
|
||||
void receive_timestamp(uint32_t new_timestamp);
|
||||
|
||||
/**
|
||||
* \brief Setter for the transmit timestamp field.
|
||||
*
|
||||
* \param new_timestamp the value to be set.
|
||||
*/
|
||||
void transmit_timestamp(uint32_t new_timestamp);
|
||||
|
||||
/**
|
||||
* \brief Setter for the address mask field.
|
||||
*
|
||||
* \param new_mask the value to be set.
|
||||
*/
|
||||
void address_mask(address_type new_mask);
|
||||
|
||||
/**
|
||||
* \brief Sets echo request flag for this PDU.
|
||||
*
|
||||
@@ -199,7 +237,7 @@ namespace Tins {
|
||||
* \param address Address of the gateway to which traffic should
|
||||
* be sent.
|
||||
*/
|
||||
void set_redirect(uint8_t icode, uint32_t address);
|
||||
void set_redirect(uint8_t icode, address_type address);
|
||||
|
||||
/**
|
||||
* \brief Getter for the ICMP type flag.
|
||||
@@ -239,24 +277,56 @@ namespace Tins {
|
||||
/**
|
||||
* \brief Getter for the gateway field.
|
||||
*
|
||||
* \return Returns the gateways in an unit32_t.
|
||||
* \return Returns the gateway field value.
|
||||
*/
|
||||
uint32_t gateway() const { return Endian::be_to_host(_icmp.un.gateway); }
|
||||
address_type gateway() const {
|
||||
return address_type(Endian::be_to_host(_icmp.un.gateway));
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Getter for the pointer field.
|
||||
*
|
||||
* \return Returns the pointer value.
|
||||
* \return Returns the pointer field value.
|
||||
*/
|
||||
uint8_t pointer() const { return this->_icmp.un.pointer; }
|
||||
|
||||
/**
|
||||
* \brief Getter for the mtu field.
|
||||
*
|
||||
* \return Returns the mtu value in an uint16_t.
|
||||
* \return Returns the mtu field value.
|
||||
*/
|
||||
uint16_t mtu() const { return Endian::be_to_host(_icmp.un.frag.mtu); }
|
||||
|
||||
/**
|
||||
* \brief Getter for the original timestamp field.
|
||||
*
|
||||
* \return Returns the original timestamp value.
|
||||
*/
|
||||
uint32_t original_timestamp() const { return Endian::be_to_host(_orig_timestamp_or_address_mask); }
|
||||
|
||||
/**
|
||||
* \brief Getter for the receive timestamp field.
|
||||
*
|
||||
* \return Returns the receive timestamp value.
|
||||
*/
|
||||
uint32_t receive_timestamp() const { return Endian::be_to_host(_recv_timestamp); }
|
||||
|
||||
/**
|
||||
* \brief Getter for the transmit timestamp field.
|
||||
*
|
||||
* \return Returns the transmit timestamp value.
|
||||
*/
|
||||
uint32_t transmit_timestamp() const { return Endian::be_to_host(_trans_timestamp); }
|
||||
|
||||
/**
|
||||
* \brief Getter for the address mask field.
|
||||
*
|
||||
* \return Returns the address mask value.
|
||||
*/
|
||||
address_type address_mask() const {
|
||||
return address_type(Endian::be_to_host(_orig_timestamp_or_address_mask));
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Returns the header size.
|
||||
*
|
||||
@@ -317,6 +387,7 @@ namespace Tins {
|
||||
void write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *parent);
|
||||
|
||||
icmphdr _icmp;
|
||||
uint32_t _orig_timestamp_or_address_mask, _recv_timestamp, _trans_timestamp;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
148
include/icmpv6.h
148
include/icmpv6.h
@@ -135,7 +135,7 @@ public:
|
||||
/**
|
||||
* The type used to represent ICMPv6 options.
|
||||
*/
|
||||
typedef PDUOption<uint8_t> option;
|
||||
typedef PDUOption<uint8_t, ICMPv6> option;
|
||||
|
||||
/**
|
||||
* The type used to store options.
|
||||
@@ -145,30 +145,53 @@ public:
|
||||
/**
|
||||
* \brief The type used to store the new home agent information
|
||||
* option data.
|
||||
*
|
||||
* The first member contains the home agent preference field, while
|
||||
* the second one contains the home agent lifetime.
|
||||
*/
|
||||
typedef std::pair<uint16_t, uint16_t> new_ha_info_type;
|
||||
typedef std::vector<uint16_t> new_ha_info_type;
|
||||
|
||||
/**
|
||||
* The type used to store the source/target address list options.
|
||||
*/
|
||||
typedef std::vector<ipaddress_type> addr_list_type;
|
||||
struct addr_list_type {
|
||||
typedef std::vector<ipaddress_type> addresses_type;
|
||||
|
||||
uint8_t reserved[6];
|
||||
addresses_type addresses;
|
||||
|
||||
addr_list_type(const addresses_type &addresses = addresses_type())
|
||||
: addresses(addresses)
|
||||
{
|
||||
std::fill(reserved, reserved + sizeof(reserved), 0);
|
||||
}
|
||||
|
||||
static addr_list_type from_option(const option &opt);
|
||||
};
|
||||
|
||||
/**
|
||||
* The type used to store the nonce option data.
|
||||
*/
|
||||
typedef std::vector<uint8_t> nonce_type;
|
||||
|
||||
/**
|
||||
* The type used to store the MTU option.
|
||||
*/
|
||||
typedef std::pair<uint16_t, uint32_t> mtu_type;
|
||||
|
||||
/**
|
||||
* \brief The type used to store the neighbour advertisement
|
||||
* acknowledgement option data.
|
||||
*
|
||||
* The first member contains the option code field, while
|
||||
* the second one contains the status.
|
||||
*/
|
||||
typedef std::pair<uint8_t, uint8_t> naack_type;
|
||||
struct naack_type {
|
||||
uint8_t code, status;
|
||||
uint8_t reserved[4];
|
||||
|
||||
naack_type(uint8_t code = 0, uint8_t status = 0)
|
||||
: code(code), status(status)
|
||||
{
|
||||
std::fill(reserved, reserved + 4, 0);
|
||||
}
|
||||
|
||||
static naack_type from_option(const option &opt);
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief The type used to store the link layer address option data.
|
||||
@@ -207,6 +230,8 @@ public:
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
static lladdr_type from_option(const option &opt);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -226,6 +251,8 @@ public:
|
||||
: prefix_len(prefix_len), A(A), L(L),
|
||||
valid_lifetime(valid_lifetime), preferred_lifetime(preferred_lifetime),
|
||||
prefix(prefix) { }
|
||||
|
||||
static prefix_info_type from_option(const option &opt);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -290,6 +317,8 @@ public:
|
||||
{
|
||||
std::fill(key_hash, key_hash + sizeof(key_hash), 0);
|
||||
}
|
||||
|
||||
static rsa_sign_type from_option(const option &opt);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -303,6 +332,8 @@ public:
|
||||
const ipaddress_type &address = ipaddress_type())
|
||||
: option_code(option_code), prefix_len(prefix_len), address(address)
|
||||
{}
|
||||
|
||||
static ip_prefix_type from_option(const option &opt);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -319,6 +350,8 @@ public:
|
||||
const ipaddress_type &address = ipaddress_type())
|
||||
: dist(dist), pref(pref), r(r), valid_lifetime(valid_lifetime),
|
||||
address(address) { }
|
||||
|
||||
static map_type from_option(const option &opt);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -336,6 +369,8 @@ public:
|
||||
uint32_t route_lifetime = 0, const prefix_type &prefix = prefix_type())
|
||||
: prefix_len(prefix_len), pref(pref), route_lifetime(route_lifetime),
|
||||
prefix(prefix) { }
|
||||
|
||||
static route_info_type from_option(const option &opt);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -350,6 +385,8 @@ public:
|
||||
recursive_dns_type(uint32_t lifetime = 0,
|
||||
const servers_type &servers = servers_type())
|
||||
: lifetime(lifetime), servers(servers) {}
|
||||
|
||||
static recursive_dns_type from_option(const option &opt);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -364,6 +401,8 @@ public:
|
||||
handover_key_req_type(small_uint<4> AT = 0,
|
||||
const key_type &key = key_type())
|
||||
: AT(AT), key(key) { }
|
||||
|
||||
static handover_key_req_type from_option(const option &opt);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -375,6 +414,8 @@ public:
|
||||
handover_key_reply_type(uint16_t lifetime = 0, small_uint<4> AT = 0,
|
||||
const key_type &key = key_type())
|
||||
: handover_key_req_type(AT, key), lifetime(lifetime) { }
|
||||
|
||||
static handover_key_reply_type from_option(const option &opt);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -389,6 +430,8 @@ public:
|
||||
handover_assist_info_type(uint8_t option_code=0,
|
||||
const hai_type &hai = hai_type())
|
||||
: option_code(option_code), hai(hai) { }
|
||||
|
||||
static handover_assist_info_type from_option(const option &opt);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -403,6 +446,8 @@ public:
|
||||
mobile_node_id_type(uint8_t option_code=0,
|
||||
const mn_type &mn = mn_type())
|
||||
: option_code(option_code), mn(mn) { }
|
||||
|
||||
static mobile_node_id_type from_option(const option &opt);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -417,8 +462,58 @@ public:
|
||||
dns_search_list_type(uint32_t lifetime = 0,
|
||||
const domains_type &domains = domains_type())
|
||||
: lifetime(lifetime), domains(domains) { }
|
||||
|
||||
static dns_search_list_type from_option(const option &opt);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* The type used to store the timestamp option.
|
||||
*/
|
||||
struct timestamp_type {
|
||||
uint8_t reserved[6];
|
||||
uint64_t timestamp;
|
||||
|
||||
timestamp_type(uint64_t timestamp = 0)
|
||||
: timestamp(timestamp)
|
||||
{
|
||||
std::fill(reserved, reserved + sizeof(reserved), 0);
|
||||
}
|
||||
|
||||
static timestamp_type from_option(const option &opt);
|
||||
};
|
||||
|
||||
/**
|
||||
* The type used to store the shortcut limit option.
|
||||
*/
|
||||
struct shortcut_limit_type {
|
||||
uint8_t limit, reserved1;
|
||||
uint32_t reserved2;
|
||||
|
||||
shortcut_limit_type(uint8_t limit = 0)
|
||||
: limit(limit), reserved1(), reserved2()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
static shortcut_limit_type from_option(const option &opt);
|
||||
};
|
||||
|
||||
/**
|
||||
* The type used to store new advertisement interval option.
|
||||
*/
|
||||
struct new_advert_interval_type {
|
||||
uint16_t reserved;
|
||||
uint32_t interval;
|
||||
|
||||
new_advert_interval_type(uint32_t interval = 0)
|
||||
: reserved(), interval(interval)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
static new_advert_interval_type from_option(const option &opt);
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Constructs an ICMPv6 object.
|
||||
*
|
||||
@@ -820,33 +915,30 @@ public:
|
||||
/**
|
||||
* \brief Setter for the redirect header option.
|
||||
*
|
||||
* This method appends the 6 reserved bytes and inserts the
|
||||
* necessary padding at the end.
|
||||
*
|
||||
* \param data The redirect header option data.
|
||||
*/
|
||||
void redirect_header(PDU::serialization_type data);
|
||||
void redirect_header(const byte_array &data);
|
||||
|
||||
/**
|
||||
* \brief Setter for the MTU option.
|
||||
*
|
||||
* \param value The MTU option data.
|
||||
*/
|
||||
void mtu(uint32_t value);
|
||||
void mtu(const mtu_type& value);
|
||||
|
||||
/**
|
||||
* \brief Setter for the shortcut limit option.
|
||||
*
|
||||
* \param value The shortcut limit option data.
|
||||
*/
|
||||
void shortcut_limit(uint8_t value);
|
||||
void shortcut_limit(const shortcut_limit_type& value);
|
||||
|
||||
/**
|
||||
* \brief Setter for the new advertisement interval option.
|
||||
*
|
||||
* \param value The new advertisement interval option data.
|
||||
*/
|
||||
void new_advert_interval(uint32_t value);
|
||||
void new_advert_interval(const new_advert_interval_type &value);
|
||||
|
||||
/**
|
||||
* \brief Setter for the new home agent information option.
|
||||
@@ -881,7 +973,7 @@ public:
|
||||
*
|
||||
* \param value The new timestamp option data.
|
||||
*/
|
||||
void timestamp(uint64_t value);
|
||||
void timestamp(const timestamp_type &value);
|
||||
|
||||
/**
|
||||
* \brief Setter for the new nonce option.
|
||||
@@ -1001,7 +1093,7 @@ public:
|
||||
* This method will throw an option_not_found exception if the
|
||||
* option is not found.
|
||||
*/
|
||||
PDU::serialization_type redirect_header() const;
|
||||
byte_array redirect_header() const;
|
||||
|
||||
/**
|
||||
* \brief Getter for the MTU option.
|
||||
@@ -1009,7 +1101,7 @@ public:
|
||||
* This method will throw an option_not_found exception if the
|
||||
* option is not found.
|
||||
*/
|
||||
uint32_t mtu() const;
|
||||
mtu_type mtu() const;
|
||||
|
||||
/**
|
||||
* \brief Getter for the shortcut limit option.
|
||||
@@ -1017,7 +1109,7 @@ public:
|
||||
* This method will throw an option_not_found exception if the
|
||||
* option is not found.
|
||||
*/
|
||||
uint8_t shortcut_limit() const;
|
||||
shortcut_limit_type shortcut_limit() const;
|
||||
|
||||
/**
|
||||
* \brief Getter for the new advertisement interval option.
|
||||
@@ -1025,7 +1117,7 @@ public:
|
||||
* This method will throw an option_not_found exception if the
|
||||
* option is not found.
|
||||
*/
|
||||
uint32_t new_advert_interval() const;
|
||||
new_advert_interval_type new_advert_interval() const;
|
||||
|
||||
/**
|
||||
* \brief Getter for the new home agent information option.
|
||||
@@ -1065,7 +1157,7 @@ public:
|
||||
* This method will throw an option_not_found exception if the
|
||||
* option is not found.
|
||||
*/
|
||||
uint64_t timestamp() const;
|
||||
timestamp_type timestamp() const;
|
||||
|
||||
/**
|
||||
* \brief Getter for the nonce option.
|
||||
@@ -1225,6 +1317,14 @@ private:
|
||||
return option;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T search_and_convert(OptionTypes type) const {
|
||||
const option *opt = search_option(type);
|
||||
if(!opt)
|
||||
throw option_not_found();
|
||||
return opt->to<T>();
|
||||
}
|
||||
|
||||
icmp6hdr _header;
|
||||
ipaddress_type _target_address, _dest_address;
|
||||
options_type _options;
|
||||
|
||||
@@ -57,7 +57,7 @@ public:
|
||||
|
||||
template<typename InputIterator>
|
||||
byte_array(InputIterator start, InputIterator last) {
|
||||
std::copy(start, end, data);
|
||||
std::copy(start, last, data);
|
||||
}
|
||||
|
||||
template<typename InputIterator>
|
||||
@@ -99,22 +99,24 @@ private:
|
||||
void skip_line(std::istream &input);
|
||||
bool from_hex(const std::string &str, uint32_t &result);
|
||||
|
||||
template<bool, typename>
|
||||
template<bool, typename T = void>
|
||||
struct enable_if {
|
||||
|
||||
typedef T type;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct enable_if<true, T> {
|
||||
typedef T type;
|
||||
struct enable_if<false, T> {
|
||||
|
||||
};
|
||||
|
||||
PDU *pdu_from_flag(Constants::Ethernet::e flag, const uint8_t *buffer,
|
||||
uint32_t size, bool rawpdu_on_no_match = true);
|
||||
|
||||
PDU *pdu_from_flag(Constants::IP::e flag, const uint8_t *buffer,
|
||||
uint32_t size, bool rawpdu_on_no_match = true);
|
||||
PDU *pdu_from_flag(PDU::PDUType type, const uint8_t *buffer, uint32_t size);
|
||||
|
||||
Constants::Ethernet::e pdu_flag_to_ether_type(PDU::PDUType flag);
|
||||
Constants::IP::e pdu_flag_to_ip_type(PDU::PDUType flag);
|
||||
|
||||
template<typename T>
|
||||
bool increment_buffer(T &addr) {
|
||||
@@ -171,6 +173,31 @@ HWAddress<n> last_address_from_mask(HWAddress<n> addr, const HWAddress<n> &mask)
|
||||
inline bool is_dot3(const uint8_t *ptr, size_t sz) {
|
||||
return (sz >= 13 && ptr[12] < 8);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
struct is_unsigned_integral {
|
||||
static const bool value = false;
|
||||
};
|
||||
|
||||
template<>
|
||||
struct is_unsigned_integral<uint8_t> {
|
||||
static const bool value = true;
|
||||
};
|
||||
|
||||
template<>
|
||||
struct is_unsigned_integral<uint16_t> {
|
||||
static const bool value = true;
|
||||
};
|
||||
|
||||
template<>
|
||||
struct is_unsigned_integral<uint32_t> {
|
||||
static const bool value = true;
|
||||
};
|
||||
|
||||
template<>
|
||||
struct is_unsigned_integral<uint64_t> {
|
||||
static const bool value = true;
|
||||
};
|
||||
} // namespace Internals
|
||||
} // namespace Tins
|
||||
/**
|
||||
|
||||
24
include/ip.h
24
include/ip.h
@@ -169,7 +169,7 @@ namespace Tins {
|
||||
/**
|
||||
* The IP options type.
|
||||
*/
|
||||
typedef PDUOption<option_identifier> option;
|
||||
typedef PDUOption<option_identifier, IP> option;
|
||||
|
||||
/**
|
||||
* The type of the security option.
|
||||
@@ -184,6 +184,8 @@ namespace Tins {
|
||||
: security(sec), compartments(comp),
|
||||
handling_restrictions(hand_res), transmission_control(tcc)
|
||||
{}
|
||||
|
||||
static security_type from_option(const option &opt);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -198,6 +200,8 @@ namespace Tins {
|
||||
generic_route_option_type(uint8_t ptr = 0,
|
||||
routes_type rts = routes_type())
|
||||
: pointer(ptr), routes(rts) {}
|
||||
|
||||
static generic_route_option_type from_option(const option &opt);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -364,6 +368,17 @@ namespace Tins {
|
||||
/**
|
||||
* \brief Setter for the protocol field.
|
||||
*
|
||||
* Note that this protocol will be overwritten using the
|
||||
* inner_pdu's protocol type during serialization unless the IP
|
||||
* datagram is fragmented.
|
||||
*
|
||||
* If the packet is fragmented and was originally sniffed, the
|
||||
* original protocol type will be kept when serialized.
|
||||
*
|
||||
* If this packet has been crafted manually and the inner_pdu
|
||||
* is, for example, a RawPDU, then setting the protocol yourself
|
||||
* is necessary.
|
||||
*
|
||||
* \param new_protocol The new protocol.
|
||||
*/
|
||||
void protocol(uint8_t new_protocol);
|
||||
@@ -568,6 +583,13 @@ namespace Tins {
|
||||
*/
|
||||
PDU *recv_response(PacketSender &sender, const NetworkInterface &);
|
||||
|
||||
/**
|
||||
* Indicates whether this PDU is fragmented.
|
||||
*
|
||||
* \return true if this PDU is fragmented, false otherwise.
|
||||
*/
|
||||
bool is_fragmented() const;
|
||||
|
||||
/**
|
||||
* \brief Getter for the PDU's type.
|
||||
* \sa PDU::pdu_type
|
||||
|
||||
216
include/ip_reassembler.h
Normal file
216
include/ip_reassembler.h
Normal file
@@ -0,0 +1,216 @@
|
||||
/*
|
||||
* Copyright (c) 2012, Matias Fontanini
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following disclaimer
|
||||
* in the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef TINS_IP_REASSEMBLER_H
|
||||
#define TINS_IP_REASSEMBLER_H
|
||||
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include "pdu.h"
|
||||
#include "ip_address.h"
|
||||
|
||||
namespace Tins {
|
||||
/**
|
||||
* \cond
|
||||
*/
|
||||
class IP;
|
||||
namespace Internals {
|
||||
class IPv4Fragment {
|
||||
public:
|
||||
typedef PDU::serialization_type payload_type;
|
||||
|
||||
IPv4Fragment() : offset_() { }
|
||||
|
||||
template<typename T>
|
||||
IPv4Fragment(T *pdu, uint16_t offset)
|
||||
: payload_(pdu->serialize()), offset_(offset)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
const payload_type &payload() const {
|
||||
return payload_;
|
||||
}
|
||||
|
||||
uint16_t offset() const {
|
||||
return offset_;
|
||||
}
|
||||
private:
|
||||
payload_type payload_;
|
||||
uint16_t offset_;
|
||||
};
|
||||
|
||||
class IPv4Stream {
|
||||
public:
|
||||
IPv4Stream();
|
||||
|
||||
void add_fragment(IP *ip);
|
||||
bool is_complete() const;
|
||||
PDU *allocate_pdu() const;
|
||||
private:
|
||||
typedef std::vector<IPv4Fragment> fragments_type;
|
||||
|
||||
uint16_t extract_offset(const IP *ip);
|
||||
bool extract_more_frag(const IP *ip);
|
||||
|
||||
fragments_type fragments;
|
||||
bool received_end;
|
||||
uint8_t transport_proto;
|
||||
size_t received_size, total_size;
|
||||
};
|
||||
} // namespace Internals
|
||||
|
||||
/**
|
||||
* \endcond
|
||||
*/
|
||||
|
||||
/**
|
||||
* \brief Reassembles fragmented IP packets.
|
||||
*/
|
||||
class IPv4Reassembler {
|
||||
public:
|
||||
/**
|
||||
* The status of each processed packet.
|
||||
*/
|
||||
enum packet_status {
|
||||
NOT_FRAGMENTED,
|
||||
FRAGMENTED,
|
||||
REASSEMBLED
|
||||
};
|
||||
|
||||
/**
|
||||
* The type used to represent the overlapped segment
|
||||
* reassembly technique to be used.
|
||||
*/
|
||||
enum overlapping_technique {
|
||||
NONE
|
||||
};
|
||||
|
||||
/**
|
||||
* Constructs an IPV4Reassembler.
|
||||
* \param technique The technique to be used for reassembling
|
||||
* overlapped fragments.
|
||||
*/
|
||||
IPv4Reassembler(overlapping_technique technique = NONE);
|
||||
|
||||
/**
|
||||
* \brief Processes a PDU and tries to reassemble it.
|
||||
*
|
||||
* This method tries to reassemble the provided packet. If
|
||||
* the packet is successfully reassembled using previously
|
||||
* processed packets, its contents will be modified so that
|
||||
* it contains the whole payload and not just a fragment.
|
||||
*
|
||||
* \param pdu The PDU to process.
|
||||
* \return NOT_FRAGMENTED if the PDU does not contain an IP
|
||||
* layer or is not fragmented, FRAGMENTED if the packet is
|
||||
* fragmented or REASSEMBLED if the packet was fragmented
|
||||
* but has now been reassembled.
|
||||
*/
|
||||
packet_status process(PDU &pdu);
|
||||
|
||||
/**
|
||||
* Removes all of the packets and data stored.
|
||||
*/
|
||||
void clear_streams();
|
||||
|
||||
/**
|
||||
* \brief Removes all of the packets and data stored that
|
||||
* belongs to IP headers whose identifier, source and destination
|
||||
* addresses are equal to the provided parameters.
|
||||
*
|
||||
* \param id The idenfier to search.
|
||||
* \param addr1 The source address to search.
|
||||
* \param addr2 The destinatin address to search.
|
||||
* \sa IP::id
|
||||
*/
|
||||
void remove_stream(uint16_t id, IPv4Address addr1, IPv4Address addr2);
|
||||
private:
|
||||
typedef std::pair<IPv4Address, IPv4Address> address_pair;
|
||||
typedef std::pair<uint16_t, address_pair> key_type;
|
||||
typedef std::map<key_type, Internals::IPv4Stream> streams_type;
|
||||
|
||||
key_type make_key(const IP *ip) const;
|
||||
address_pair make_address_pair(IPv4Address addr1, IPv4Address addr2) const;
|
||||
|
||||
streams_type streams;
|
||||
overlapping_technique technique;
|
||||
};
|
||||
|
||||
/**
|
||||
* Proxy functor class that reassembles PDUs.
|
||||
*/
|
||||
template<typename Functor>
|
||||
class IPv4ReassemblerProxy {
|
||||
public:
|
||||
/**
|
||||
* Constructs the proxy from a functor object.
|
||||
*
|
||||
* \param func The functor object.
|
||||
*/
|
||||
IPv4ReassemblerProxy(Functor func)
|
||||
: functor_(func)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Tries to reassemble the packet and forwards it to
|
||||
* the functor.
|
||||
*
|
||||
* \param pdu The packet to process
|
||||
* \return true if the packet wasn't forwarded, otherwise
|
||||
* the value returned by the functor.
|
||||
*/
|
||||
bool operator()(PDU &pdu) {
|
||||
// Forward it unless it's fragmented.
|
||||
if(reassembler.process(pdu) != IPv4Reassembler::FRAGMENTED)
|
||||
return functor_(pdu);
|
||||
else
|
||||
return true;
|
||||
}
|
||||
private:
|
||||
IPv4Reassembler reassembler;
|
||||
Functor functor_;
|
||||
};
|
||||
|
||||
/**
|
||||
* Helper function that creates an IPv4ReassemblerProxy.
|
||||
*
|
||||
* \param func The functor object to use in the IPv4ReassemblerProxy.
|
||||
* \return An IPv4ReassemblerProxy.
|
||||
*/
|
||||
template<typename Functor>
|
||||
IPv4ReassemblerProxy<Functor> make_ipv4_reassembler_proxy(Functor func) {
|
||||
return IPv4ReassemblerProxy<Functor>(func);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endif // TINS_IP_REASSEMBLER_H
|
||||
264
include/ipsec.h
Normal file
264
include/ipsec.h
Normal file
@@ -0,0 +1,264 @@
|
||||
/*
|
||||
* Copyright (c) 2012, Matias Fontanini
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following disclaimer
|
||||
* in the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef TINS_IPSEC_H
|
||||
#define TINS_IPSEC_H
|
||||
|
||||
#include "pdu.h"
|
||||
#include "endianness.h"
|
||||
#include "small_uint.h"
|
||||
|
||||
namespace Tins {
|
||||
/**
|
||||
* \brief Represents an IPSec Authentication Header.
|
||||
*/
|
||||
class IPSecAH : public PDU {
|
||||
public:
|
||||
/**
|
||||
* This PDU's flag.
|
||||
*/
|
||||
static const PDU::PDUType pdu_flag = PDU::IPSEC_AH;
|
||||
|
||||
/**
|
||||
* \brief Default constructor.
|
||||
*
|
||||
* The ICV field is initialized with four 0 bytes. The length
|
||||
* field is initialized appropriately.
|
||||
*/
|
||||
IPSecAH();
|
||||
|
||||
/**
|
||||
* \brief Constructs an IPSecAH object from a buffer and adds all
|
||||
* identifiable PDUs found in the buffer as children of this
|
||||
* one.
|
||||
*
|
||||
* If there is not enough size for an IPSecAH header, a
|
||||
* malformed_packet exception is thrown.
|
||||
*
|
||||
* \param buffer The buffer from which this PDU will be constructed.
|
||||
* \param total_sz The total size of the buffer.
|
||||
*/
|
||||
IPSecAH(const uint8_t *buffer, uint32_t total_sz);
|
||||
|
||||
// Getters
|
||||
|
||||
/**
|
||||
* \brief Getter for the Next header field.
|
||||
* \return The stored Next header field value.
|
||||
*/
|
||||
uint8_t next_header() const {
|
||||
return _header.next_header;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Getter for the Length field.
|
||||
* \return The stored Length field value.
|
||||
*/
|
||||
uint8_t length() const {
|
||||
return _header.length;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Getter for the Security Parameters Index field.
|
||||
* \return The stored Security Parameters Index field value.
|
||||
*/
|
||||
uint32_t spi() const {
|
||||
return Endian::be_to_host(_header.spi);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Getter for the Sequence number field.
|
||||
* \return The stored Sequence number field value.
|
||||
*/
|
||||
uint32_t seq_number() const {
|
||||
return Endian::be_to_host(_header.seq_number);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Getter for the ICV field.
|
||||
* \return The stored ICV field value.
|
||||
*/
|
||||
const byte_array &icv() const {
|
||||
return _icv;
|
||||
}
|
||||
|
||||
// Setters
|
||||
|
||||
/**
|
||||
* \brief Setter for the Next header field.
|
||||
* \param new_next_header The new Next header field value.
|
||||
*/
|
||||
void next_header(uint8_t new_next_header);
|
||||
|
||||
/**
|
||||
* \brief Setter for the Length field.
|
||||
* \param new_length The new Length field value.
|
||||
*/
|
||||
void length(uint8_t new_length);
|
||||
|
||||
/**
|
||||
* \brief Setter for the Security Parameters Index field.
|
||||
* \param new_spi The new Security Parameters Index field value.
|
||||
*/
|
||||
void spi(uint32_t new_spi);
|
||||
|
||||
/**
|
||||
* \brief Setter for the Sequence number field.
|
||||
* \param new_seq_number The new Sequence number field value.
|
||||
*/
|
||||
void seq_number(uint32_t new_seq_number);
|
||||
|
||||
/**
|
||||
* \brief Setter for the ICV field.
|
||||
* \param new_icv The new ICV field value.
|
||||
*/
|
||||
void icv(const byte_array &new_icv);
|
||||
|
||||
/**
|
||||
* \brief Returns the header size.
|
||||
*
|
||||
* This metod overrides PDU::header_size. \sa PDU::header_size
|
||||
*/
|
||||
uint32_t header_size() const;
|
||||
|
||||
/**
|
||||
* \brief Getter for the PDU's type.
|
||||
* \sa PDU::pdu_type
|
||||
*/
|
||||
PDUType pdu_type() const { return pdu_flag; }
|
||||
|
||||
/**
|
||||
* \sa PDU::clone
|
||||
*/
|
||||
IPSecAH *clone() const {
|
||||
return new IPSecAH(*this);
|
||||
}
|
||||
private:
|
||||
struct header {
|
||||
uint8_t next_header, length;
|
||||
uint32_t spi, seq_number;
|
||||
};
|
||||
|
||||
void write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *);
|
||||
|
||||
header _header;
|
||||
byte_array _icv;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Represents an IPSec Authentication Header.
|
||||
*/
|
||||
class IPSecESP : public PDU {
|
||||
public:
|
||||
/**
|
||||
* This PDU's flag.
|
||||
*/
|
||||
static const PDU::PDUType pdu_flag = PDU::IPSEC_ESP;
|
||||
|
||||
/**
|
||||
* \brief Default constructor.
|
||||
*/
|
||||
IPSecESP();
|
||||
|
||||
/**
|
||||
* \brief Constructs an IPSecESP object from a buffer and adds all
|
||||
* identifiable PDUs found in the buffer as children of this
|
||||
* one.
|
||||
*
|
||||
* If there is not enough size for an IPSecESP header, a
|
||||
* malformed_packet exception is thrown.
|
||||
*
|
||||
* \param buffer The buffer from which this PDU will be constructed.
|
||||
* \param total_sz The total size of the buffer.
|
||||
*/
|
||||
IPSecESP(const uint8_t *buffer, uint32_t total_sz);
|
||||
|
||||
// Getters
|
||||
|
||||
/**
|
||||
* \brief Getter for the Security Parameters Index field.
|
||||
* \return The stored Security Parameters Index field value.
|
||||
*/
|
||||
uint32_t spi() const {
|
||||
return Endian::be_to_host(_header.spi);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Getter for the Sequence number field.
|
||||
* \return The stored Sequence number field value.
|
||||
*/
|
||||
uint32_t seq_number() const {
|
||||
return Endian::be_to_host(_header.seq_number);
|
||||
}
|
||||
|
||||
// Setters
|
||||
|
||||
/**
|
||||
* \brief Setter for the Security Parameters Index field.
|
||||
* \param new_spi The new Security Parameters Index field value.
|
||||
*/
|
||||
void spi(uint32_t new_spi);
|
||||
|
||||
/**
|
||||
* \brief Setter for the Sequence number field.
|
||||
* \param new_seq_number The new Sequence number field value.
|
||||
*/
|
||||
void seq_number(uint32_t new_seq_number);
|
||||
|
||||
/**
|
||||
* \brief Returns the header size.
|
||||
*
|
||||
* This metod overrides PDU::header_size. \sa PDU::header_size
|
||||
*/
|
||||
uint32_t header_size() const;
|
||||
|
||||
/**
|
||||
* \brief Getter for the PDU's type.
|
||||
* \sa PDU::pdu_type
|
||||
*/
|
||||
PDUType pdu_type() const { return pdu_flag; }
|
||||
|
||||
/**
|
||||
* \sa PDU::clone
|
||||
*/
|
||||
IPSecESP *clone() const {
|
||||
return new IPSecESP(*this);
|
||||
}
|
||||
private:
|
||||
struct header {
|
||||
uint32_t spi, seq_number;
|
||||
};
|
||||
|
||||
void write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *);
|
||||
|
||||
header _header;
|
||||
};
|
||||
}
|
||||
|
||||
#endif // TINS_IPSEC_H
|
||||
@@ -60,7 +60,7 @@ public:
|
||||
/**
|
||||
* The type used to represent IPv6 extension headers.
|
||||
*/
|
||||
typedef PDUOption<uint8_t> ext_header;
|
||||
typedef PDUOption<uint8_t, IPv6> ext_header;
|
||||
|
||||
/**
|
||||
* The type used to store the extension headers.
|
||||
|
||||
@@ -310,7 +310,8 @@ namespace Tins {
|
||||
static_cast<T&>(pdu).send(*this, iface);
|
||||
}
|
||||
|
||||
PDU *recv_match_loop(int sock, PDU &pdu, struct sockaddr* link_addr, uint32_t addrlen);
|
||||
PDU *recv_match_loop(const std::vector<int>& sockets, PDU &pdu, struct sockaddr* link_addr,
|
||||
uint32_t addrlen);
|
||||
|
||||
std::vector<int> _sockets;
|
||||
#ifndef WIN32
|
||||
|
||||
@@ -65,6 +65,14 @@ namespace Tins {
|
||||
*/
|
||||
typedef byte_array serialization_type;
|
||||
|
||||
/**
|
||||
* The typep used to identify the endianness of every PDU.
|
||||
*/
|
||||
enum endian_type {
|
||||
BE,
|
||||
LE
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Enum which identifies each type of PDU.
|
||||
*
|
||||
@@ -119,8 +127,16 @@ namespace Tins {
|
||||
PPPOE,
|
||||
STP,
|
||||
PPI,
|
||||
IPSEC_AH,
|
||||
IPSEC_ESP,
|
||||
USER_DEFINED_PDU = 1000
|
||||
};
|
||||
|
||||
/**
|
||||
* The endianness used by this PDU. This can be overriden
|
||||
* by subclasses.
|
||||
*/
|
||||
static const endian_type endianness = BE;
|
||||
|
||||
/**
|
||||
* \brief Default constructor.
|
||||
@@ -456,6 +472,34 @@ namespace Tins {
|
||||
*lop /= rop;
|
||||
return lop;
|
||||
}
|
||||
|
||||
namespace Internals {
|
||||
template<typename T>
|
||||
struct remove_pointer {
|
||||
typedef T type;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct remove_pointer<T*> {
|
||||
typedef T type;
|
||||
};
|
||||
}
|
||||
|
||||
template<typename T, typename U>
|
||||
T tins_cast(U *pdu) {
|
||||
typedef typename Internals::remove_pointer<T>::type TrueT;
|
||||
return pdu && (TrueT::pdu_flag == pdu->pdu_type()) ?
|
||||
static_cast<T>(pdu) :
|
||||
0;
|
||||
}
|
||||
|
||||
template<typename T, typename U>
|
||||
T &tins_cast(U &pdu) {
|
||||
T *ptr = tins_cast<T*>(&pdu);
|
||||
if(!ptr)
|
||||
throw bad_tins_cast();
|
||||
return *ptr;
|
||||
}
|
||||
}
|
||||
|
||||
#endif // TINS_PDU_H
|
||||
|
||||
@@ -32,10 +32,259 @@
|
||||
|
||||
#include <vector>
|
||||
#include <iterator>
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
#include <stdint.h>
|
||||
#include "exceptions.h"
|
||||
#include "endianness.h"
|
||||
#include "internals.h"
|
||||
#include "ip_address.h"
|
||||
#include "ipv6_address.h"
|
||||
#include "hw_address.h"
|
||||
|
||||
namespace Tins {
|
||||
/**
|
||||
* \cond
|
||||
*/
|
||||
template<typename OptionType, class PDUType>
|
||||
class PDUOption;
|
||||
|
||||
namespace Internals {
|
||||
template<typename T, typename X, typename PDUType>
|
||||
T convert_to_integral(const PDUOption<X, PDUType> & opt) {
|
||||
if(opt.data_size() != sizeof(T))
|
||||
throw malformed_option();
|
||||
T data = *(T*)opt.data_ptr();
|
||||
if(PDUType::endianness == PDUType::BE)
|
||||
data = Endian::be_to_host(data);
|
||||
else
|
||||
data = Endian::le_to_host(data);
|
||||
return data;
|
||||
}
|
||||
|
||||
template<typename T, typename = void>
|
||||
struct converter {
|
||||
template<typename X, typename PDUType>
|
||||
static T convert(const PDUOption<X, PDUType>& opt) {
|
||||
return T::from_option(opt);
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct converter<uint8_t> {
|
||||
template<typename X, typename PDUType>
|
||||
static uint8_t convert(const PDUOption<X, PDUType>& opt) {
|
||||
if(opt.data_size() != 1)
|
||||
throw malformed_option();
|
||||
return *opt.data_ptr();
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct converter<uint16_t> {
|
||||
template<typename X, typename PDUType>
|
||||
static uint16_t convert(const PDUOption<X, PDUType>& opt) {
|
||||
return convert_to_integral<uint16_t>(opt);
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct converter<uint32_t> {
|
||||
template<typename X, typename PDUType>
|
||||
static uint32_t convert(const PDUOption<X, PDUType>& opt) {
|
||||
return convert_to_integral<uint32_t>(opt);
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct converter<uint64_t> {
|
||||
template<typename X, typename PDUType>
|
||||
static uint64_t convert(const PDUOption<X, PDUType>& opt) {
|
||||
return convert_to_integral<uint64_t>(opt);
|
||||
}
|
||||
};
|
||||
|
||||
template<size_t n>
|
||||
struct converter<HWAddress<n> > {
|
||||
template<typename X, typename PDUType>
|
||||
static HWAddress<n> convert(const PDUOption<X, PDUType>& opt) {
|
||||
if(opt.data_size() != n)
|
||||
throw malformed_option();
|
||||
return HWAddress<n>(opt.data_ptr());
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct converter<IPv4Address> {
|
||||
template<typename X, typename PDUType>
|
||||
static IPv4Address convert(const PDUOption<X, PDUType>& opt) {
|
||||
if(opt.data_size() != sizeof(uint32_t))
|
||||
throw malformed_option();
|
||||
const uint32_t *ptr = (const uint32_t*)opt.data_ptr();
|
||||
if(PDUType::endianness == PDUType::BE)
|
||||
return IPv4Address(*ptr);
|
||||
else
|
||||
return IPv4Address(Endian::change_endian(*ptr));
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct converter<IPv6Address> {
|
||||
template<typename X, typename PDUType>
|
||||
static IPv6Address convert(const PDUOption<X, PDUType>& opt) {
|
||||
if(opt.data_size() != IPv6Address::address_size)
|
||||
throw malformed_option();
|
||||
return IPv6Address(opt.data_ptr());
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct converter<std::string> {
|
||||
template<typename X, typename PDUType>
|
||||
static std::string convert(const PDUOption<X, PDUType>& opt) {
|
||||
return std::string(
|
||||
opt.data_ptr(),
|
||||
opt.data_ptr() + opt.data_size()
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct converter<std::vector<float> > {
|
||||
template<typename X, typename PDUType>
|
||||
static std::vector<float> convert(const PDUOption<X, PDUType>& opt) {
|
||||
std::vector<float> output;
|
||||
const uint8_t *ptr = opt.data_ptr(), *end = ptr + opt.data_size();
|
||||
while(ptr != end) {
|
||||
output.push_back(float(*(ptr++) & 0x7f) / 2);
|
||||
}
|
||||
return output;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct converter<std::vector<T>, typename enable_if<is_unsigned_integral<T>::value>::type> {
|
||||
template<typename X, typename PDUType>
|
||||
static std::vector<T> convert(const PDUOption<X, PDUType>& opt) {
|
||||
if(opt.data_size() % sizeof(T) != 0)
|
||||
throw malformed_option();
|
||||
const T *ptr = (const T*)opt.data_ptr();
|
||||
const T *end = (const T*)(opt.data_ptr() + opt.data_size());
|
||||
|
||||
std::vector<T> output(std::distance(ptr, end));
|
||||
typename std::vector<T>::iterator it = output.begin();
|
||||
while(ptr < end) {
|
||||
if(PDUType::endianness == PDUType::BE)
|
||||
*it++ = Endian::be_to_host(*ptr++);
|
||||
else
|
||||
*it++ = Endian::le_to_host(*ptr++);
|
||||
}
|
||||
return output;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T, typename U>
|
||||
struct converter<
|
||||
std::vector<std::pair<T, U> >,
|
||||
typename enable_if<
|
||||
is_unsigned_integral<T>::value && is_unsigned_integral<U>::value
|
||||
>::type
|
||||
> {
|
||||
template<typename X, typename PDUType>
|
||||
static std::vector<std::pair<T, U> > convert(const PDUOption<X, PDUType>& opt) {
|
||||
if(opt.data_size() % (sizeof(T) + sizeof(U)) != 0)
|
||||
throw malformed_option();
|
||||
const uint8_t *ptr = opt.data_ptr(), *end = ptr + opt.data_size();
|
||||
|
||||
std::vector<std::pair<T, U> > output;
|
||||
while(ptr < end) {
|
||||
std::pair<T, U> data;
|
||||
data.first = *(const T*)ptr;
|
||||
ptr += sizeof(T);
|
||||
data.second = *(const U*)ptr;
|
||||
ptr += sizeof(U);
|
||||
if(PDUType::endianness == PDUType::BE) {
|
||||
data.first = Endian::be_to_host(data.first);
|
||||
data.second = Endian::be_to_host(data.second);
|
||||
}
|
||||
else {
|
||||
data.first = Endian::le_to_host(data.first);
|
||||
data.second = Endian::le_to_host(data.second);
|
||||
}
|
||||
output.push_back(data);
|
||||
}
|
||||
return output;
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct converter<std::vector<IPv4Address> > {
|
||||
template<typename X, typename PDUType>
|
||||
static std::vector<IPv4Address> convert(const PDUOption<X, PDUType>& opt) {
|
||||
if(opt.data_size() % 4 != 0)
|
||||
throw malformed_option();
|
||||
const uint32_t *ptr = (const uint32_t*)opt.data_ptr();
|
||||
const uint32_t *end = (const uint32_t*)(opt.data_ptr() + opt.data_size());
|
||||
|
||||
std::vector<IPv4Address> output(std::distance(ptr, end));
|
||||
std::vector<IPv4Address>::iterator it = output.begin();
|
||||
while(ptr < end) {
|
||||
if(PDUType::endianness == PDUType::BE)
|
||||
*it++ = IPv4Address(*ptr++);
|
||||
else
|
||||
*it++ = IPv4Address(Endian::change_endian(*ptr++));
|
||||
}
|
||||
return output;
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct converter<std::vector<IPv6Address> > {
|
||||
template<typename X, typename PDUType>
|
||||
static std::vector<IPv6Address> convert(const PDUOption<X, PDUType>& opt) {
|
||||
if(opt.data_size() % IPv6Address::address_size != 0)
|
||||
throw malformed_option();
|
||||
const uint8_t *ptr = opt.data_ptr(), *end = opt.data_ptr() + opt.data_size();
|
||||
std::vector<IPv6Address> output;
|
||||
while(ptr < end) {
|
||||
output.push_back(IPv6Address(ptr));
|
||||
ptr += IPv6Address::address_size;
|
||||
}
|
||||
return output;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T, typename U>
|
||||
struct converter<
|
||||
std::pair<T, U>,
|
||||
typename enable_if<
|
||||
is_unsigned_integral<T>::value && is_unsigned_integral<U>::value
|
||||
>::type
|
||||
> {
|
||||
template<typename X, typename PDUType>
|
||||
static std::pair<T, U> convert(const PDUOption<X, PDUType>& opt) {
|
||||
if(opt.data_size() != sizeof(T) + sizeof(U))
|
||||
throw malformed_option();
|
||||
std::pair<T, U> output;
|
||||
output.first = *(const T*)opt.data_ptr();
|
||||
output.second = *(const U*)(opt.data_ptr() + sizeof(T));
|
||||
if(PDUType::endianness == PDUType::BE) {
|
||||
output.first = Endian::be_to_host(output.first);
|
||||
output.second = Endian::be_to_host(output.second);
|
||||
}
|
||||
else {
|
||||
output.first = Endian::le_to_host(output.first);
|
||||
output.second = Endian::le_to_host(output.second);
|
||||
}
|
||||
return output;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* \endcond
|
||||
*/
|
||||
|
||||
/**
|
||||
* \class PDUOption
|
||||
* \brief Represents a PDU option field.
|
||||
@@ -46,16 +295,11 @@ namespace Tins {
|
||||
*
|
||||
* The OptionType template parameter indicates the type that will be
|
||||
* used to store this option's identifier.
|
||||
*
|
||||
* The Container template parameter indicates the container which will
|
||||
* be used to store this option's data. The container <b>must</b>
|
||||
* store data sequentially. std::vector<uint8_t> is the default
|
||||
* container.
|
||||
*/
|
||||
template<typename OptionType, class Container = std::vector<uint8_t> >
|
||||
template<typename OptionType, class PDUType>
|
||||
class PDUOption {
|
||||
public:
|
||||
typedef Container container_type;
|
||||
typedef std::vector<uint8_t> container_type;
|
||||
typedef typename container_type::value_type data_type;
|
||||
typedef OptionType option_type;
|
||||
|
||||
@@ -158,6 +402,18 @@ public:
|
||||
size_t length_field() const {
|
||||
return size_;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Constructs a T from this PDUOption.
|
||||
*
|
||||
* Use this method to convert a PDUOption to the specific type that
|
||||
* represents it. For example, if you know an option is of type
|
||||
* PDU::SACK, you could use option.to<TCP::sack_type>().
|
||||
*/
|
||||
template<typename T>
|
||||
T to() const {
|
||||
return Internals::converter<T>::convert(*this);
|
||||
}
|
||||
private:
|
||||
option_type option_;
|
||||
uint16_t size_;
|
||||
|
||||
@@ -85,7 +85,7 @@ public:
|
||||
* \return The stored length field value.
|
||||
*/
|
||||
uint16_t length() const {
|
||||
return _header.length;
|
||||
return Endian::le_to_host(_header.length);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -93,7 +93,7 @@ public:
|
||||
* \return The stored Data Link Type field value.
|
||||
*/
|
||||
uint32_t dlt() const {
|
||||
return _header.dlt;
|
||||
return Endian::le_to_host(_header.dlt);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -72,7 +72,7 @@ public:
|
||||
/**
|
||||
* The type used to store a TLV option.
|
||||
*/
|
||||
typedef PDUOption<TagTypes> tag;
|
||||
typedef PDUOption<TagTypes, PPPoE> tag;
|
||||
|
||||
/**
|
||||
* The type used to store the options.
|
||||
@@ -90,6 +90,8 @@ public:
|
||||
|
||||
vendor_spec_type(uint32_t vendor_id = 0, const data_type &data = data_type())
|
||||
: vendor_id(vendor_id), data(data) { }
|
||||
|
||||
static vendor_spec_type from_option(const tag &opt);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -397,19 +399,11 @@ private:
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T retrieve_tag_iterable(TagTypes id) const {
|
||||
const tag *tag = search_tag(id);
|
||||
if(!tag)
|
||||
T search_and_convert(TagTypes id) const {
|
||||
const tag *t = search_tag(id);
|
||||
if(!t)
|
||||
throw option_not_found();
|
||||
return T(tag->data_ptr(), tag->data_ptr() + tag->data_size());
|
||||
}
|
||||
|
||||
template<template <typename> class Functor>
|
||||
const tag *safe_search_tag(TagTypes opt, uint32_t size) const {
|
||||
const tag *option = search_tag(opt);
|
||||
if(!option || Functor<uint32_t>()(option->data_size(), size))
|
||||
throw option_not_found();
|
||||
return option;
|
||||
return t->to<T>();
|
||||
}
|
||||
|
||||
TINS_BEGIN_PACK
|
||||
|
||||
@@ -27,7 +27,9 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef TINS_RADIOTAP_H
|
||||
#include "config.h"
|
||||
|
||||
#if !defined(TINS_RADIOTAP_H) && defined(HAVE_DOT11)
|
||||
#define TINS_RADIOTAP_H
|
||||
|
||||
#include "macros.h"
|
||||
|
||||
@@ -35,152 +35,160 @@
|
||||
#include "endianness.h"
|
||||
|
||||
namespace Tins{
|
||||
class Dot11;
|
||||
template<typename T, typename U>
|
||||
class PDUOption;
|
||||
/**
|
||||
* \brief Class that models the RSN information structure.
|
||||
*/
|
||||
class RSNInformation {
|
||||
public:
|
||||
/**
|
||||
* \brief Class that models the RSN information structure.
|
||||
* \brief Enum that represents the different cypher suites.
|
||||
*/
|
||||
class RSNInformation {
|
||||
public:
|
||||
/**
|
||||
* \brief Enum that represents the different cypher suites.
|
||||
*/
|
||||
enum CypherSuites {
|
||||
WEP_40 = 0x01ac0f00,
|
||||
TKIP = 0x02ac0f00,
|
||||
CCMP = 0x04ac0f00,
|
||||
WEP_104 = 0x05ac0f00
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Enum that represents the different akm suites.
|
||||
*/
|
||||
enum AKMSuites {
|
||||
PMKSA = 0x01ac0f00,
|
||||
PSK = 0x02ac0f00
|
||||
};
|
||||
|
||||
/**
|
||||
* The type used to store the cypher suites.
|
||||
*/
|
||||
typedef std::vector<CypherSuites> cyphers_type;
|
||||
|
||||
/**
|
||||
* The type used to store the AKM suites.
|
||||
*/
|
||||
typedef std::vector<AKMSuites> akm_type;
|
||||
|
||||
/**
|
||||
* The type returned on serialization.
|
||||
*/
|
||||
typedef std::vector<uint8_t> serialization_type;
|
||||
|
||||
/**
|
||||
* \brief Constructs an RSNInformation object.
|
||||
*
|
||||
* By default, the version is set to 1.
|
||||
*/
|
||||
RSNInformation();
|
||||
|
||||
/**
|
||||
* \brief Constructs an RSNInformation object from a
|
||||
* serialization_type object.
|
||||
*
|
||||
* \param buffer The buffer from which to construct this object.
|
||||
*/
|
||||
RSNInformation(const serialization_type &buffer);
|
||||
|
||||
/**
|
||||
* \brief Constructs a RSNInformation from a buffer.
|
||||
*
|
||||
* If the input is malformed, a malformed_packet exception is
|
||||
* thrown.
|
||||
*
|
||||
* \param buffer The buffer from which this object will be constructed.
|
||||
* \param total_sz The total size of the buffer.
|
||||
*/
|
||||
RSNInformation(const uint8_t *buffer, uint32_t total_sz);
|
||||
|
||||
/**
|
||||
* \brief Helper function to create a WPA2-PSK RSNInformation
|
||||
* \return An instance RSNInformation which contains information
|
||||
* for a WPA2-PSK AP.
|
||||
*/
|
||||
static RSNInformation wpa2_psk();
|
||||
|
||||
/**
|
||||
* \brief Adds a pairwise cypher suite.
|
||||
* \param cypher The pairwise cypher suite to be added.
|
||||
*/
|
||||
void add_pairwise_cypher(CypherSuites cypher);
|
||||
|
||||
/**
|
||||
* \brief Adds an akm suite.
|
||||
* \param akm The akm suite to be added.
|
||||
*/
|
||||
void add_akm_cypher(AKMSuites akm);
|
||||
|
||||
/**
|
||||
* \brief Sets the group suite cypher.
|
||||
* \param group The group suite cypher to be set.
|
||||
*/
|
||||
void group_suite(CypherSuites group);
|
||||
|
||||
/**
|
||||
* \brief Sets the version.
|
||||
* \param ver The version to be set.
|
||||
*/
|
||||
void version(uint16_t ver);
|
||||
|
||||
/**
|
||||
* \brief Sets the capabilities field.
|
||||
* \param cap The capabilities to be set.
|
||||
*/
|
||||
void capabilities(uint16_t cap);
|
||||
|
||||
/* Getters */
|
||||
|
||||
/**
|
||||
* \brief Getter for the group suite field.
|
||||
* \return The group suite field.
|
||||
*/
|
||||
CypherSuites group_suite() const { return _group_suite; }
|
||||
|
||||
/**
|
||||
* \brief Getter for the version field.
|
||||
* \return The version field.
|
||||
*/
|
||||
uint16_t version() const { return Endian::le_to_host(_version); }
|
||||
|
||||
/**
|
||||
* \brief Getter for the capabilities field.
|
||||
* \return The version field.
|
||||
*/
|
||||
uint16_t capabilities() const { return Endian::le_to_host(_capabilities); }
|
||||
|
||||
/**
|
||||
* \brief Getter for the pairwise cypher suite list.
|
||||
* \return A list of pairwise cypher suites.
|
||||
*/
|
||||
const cyphers_type &pairwise_cyphers() const { return _pairwise_cyphers; }
|
||||
|
||||
/**
|
||||
* \brief Getter for the akm suite list.
|
||||
* \return A list of akm suites.
|
||||
*/
|
||||
const akm_type &akm_cyphers() const { return _akm_cyphers; }
|
||||
|
||||
/**
|
||||
* \brief Serializes this object.
|
||||
* \return The result of the serialization.
|
||||
*/
|
||||
serialization_type serialize() const;
|
||||
private:
|
||||
void init(const uint8_t *buffer, uint32_t total_sz);
|
||||
|
||||
uint16_t _version, _capabilities;
|
||||
CypherSuites _group_suite;
|
||||
akm_type _akm_cyphers;
|
||||
cyphers_type _pairwise_cyphers;
|
||||
enum CypherSuites {
|
||||
WEP_40 = 0x01ac0f00,
|
||||
TKIP = 0x02ac0f00,
|
||||
CCMP = 0x04ac0f00,
|
||||
WEP_104 = 0x05ac0f00
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Enum that represents the different akm suites.
|
||||
*/
|
||||
enum AKMSuites {
|
||||
PMKSA = 0x01ac0f00,
|
||||
PSK = 0x02ac0f00
|
||||
};
|
||||
|
||||
/**
|
||||
* The type used to store the cypher suites.
|
||||
*/
|
||||
typedef std::vector<CypherSuites> cyphers_type;
|
||||
|
||||
/**
|
||||
* The type used to store the AKM suites.
|
||||
*/
|
||||
typedef std::vector<AKMSuites> akm_type;
|
||||
|
||||
/**
|
||||
* The type returned on serialization.
|
||||
*/
|
||||
typedef std::vector<uint8_t> serialization_type;
|
||||
|
||||
/**
|
||||
* \brief Constructs an RSNInformation object.
|
||||
*
|
||||
* By default, the version is set to 1.
|
||||
*/
|
||||
RSNInformation();
|
||||
|
||||
/**
|
||||
* \brief Constructs an RSNInformation object from a
|
||||
* serialization_type object.
|
||||
*
|
||||
* \param buffer The buffer from which to construct this object.
|
||||
*/
|
||||
RSNInformation(const serialization_type &buffer);
|
||||
|
||||
/**
|
||||
* \brief Constructs a RSNInformation from a buffer.
|
||||
*
|
||||
* If the input is malformed, a malformed_packet exception is
|
||||
* thrown.
|
||||
*
|
||||
* \param buffer The buffer from which this object will be constructed.
|
||||
* \param total_sz The total size of the buffer.
|
||||
*/
|
||||
RSNInformation(const uint8_t *buffer, uint32_t total_sz);
|
||||
|
||||
/**
|
||||
* \brief Helper function to create a WPA2-PSK RSNInformation
|
||||
* \return An instance RSNInformation which contains information
|
||||
* for a WPA2-PSK AP.
|
||||
*/
|
||||
static RSNInformation wpa2_psk();
|
||||
|
||||
/**
|
||||
* \brief Adds a pairwise cypher suite.
|
||||
* \param cypher The pairwise cypher suite to be added.
|
||||
*/
|
||||
void add_pairwise_cypher(CypherSuites cypher);
|
||||
|
||||
/**
|
||||
* \brief Adds an akm suite.
|
||||
* \param akm The akm suite to be added.
|
||||
*/
|
||||
void add_akm_cypher(AKMSuites akm);
|
||||
|
||||
/**
|
||||
* \brief Sets the group suite cypher.
|
||||
* \param group The group suite cypher to be set.
|
||||
*/
|
||||
void group_suite(CypherSuites group);
|
||||
|
||||
/**
|
||||
* \brief Sets the version.
|
||||
* \param ver The version to be set.
|
||||
*/
|
||||
void version(uint16_t ver);
|
||||
|
||||
/**
|
||||
* \brief Sets the capabilities field.
|
||||
* \param cap The capabilities to be set.
|
||||
*/
|
||||
void capabilities(uint16_t cap);
|
||||
|
||||
/* Getters */
|
||||
|
||||
/**
|
||||
* \brief Getter for the group suite field.
|
||||
* \return The group suite field.
|
||||
*/
|
||||
CypherSuites group_suite() const { return _group_suite; }
|
||||
|
||||
/**
|
||||
* \brief Getter for the version field.
|
||||
* \return The version field.
|
||||
*/
|
||||
uint16_t version() const { return Endian::le_to_host(_version); }
|
||||
|
||||
/**
|
||||
* \brief Getter for the capabilities field.
|
||||
* \return The version field.
|
||||
*/
|
||||
uint16_t capabilities() const { return Endian::le_to_host(_capabilities); }
|
||||
|
||||
/**
|
||||
* \brief Getter for the pairwise cypher suite list.
|
||||
* \return A list of pairwise cypher suites.
|
||||
*/
|
||||
const cyphers_type &pairwise_cyphers() const { return _pairwise_cyphers; }
|
||||
|
||||
/**
|
||||
* \brief Getter for the akm suite list.
|
||||
* \return A list of akm suites.
|
||||
*/
|
||||
const akm_type &akm_cyphers() const { return _akm_cyphers; }
|
||||
|
||||
/**
|
||||
* \brief Serializes this object.
|
||||
* \return The result of the serialization.
|
||||
*/
|
||||
serialization_type serialize() const;
|
||||
|
||||
/**
|
||||
* Constructs an RSNInformation object from a Dot11 tagged option.
|
||||
*/
|
||||
static RSNInformation from_option(const PDUOption<uint8_t, Dot11> &opt);
|
||||
private:
|
||||
void init(const uint8_t *buffer, uint32_t total_sz);
|
||||
|
||||
uint16_t _version, _capabilities;
|
||||
CypherSuites _group_suite;
|
||||
akm_type _akm_cyphers;
|
||||
cyphers_type _pairwise_cyphers;
|
||||
};
|
||||
} // namespace Tins
|
||||
|
||||
#endif // TINS_RSN_INFORMATION
|
||||
|
||||
@@ -38,17 +38,10 @@
|
||||
#include <stdexcept>
|
||||
#include <iterator>
|
||||
#include "pdu.h"
|
||||
#include "ethernetII.h"
|
||||
#include "radiotap.h"
|
||||
#include "packet.h"
|
||||
#include "loopback.h"
|
||||
#include "dot11/dot11_base.h"
|
||||
#include "dot3.h"
|
||||
#include "sll.h"
|
||||
#include "cxxstd.h"
|
||||
#include "exceptions.h"
|
||||
#include "internals.h"
|
||||
#include "ppi.h"
|
||||
|
||||
namespace Tins {
|
||||
class SnifferIterator;
|
||||
@@ -199,6 +192,14 @@ namespace Tins {
|
||||
*/
|
||||
int get_fd();
|
||||
|
||||
/**
|
||||
* \brief Sets the read timeout for this sniffer.
|
||||
*
|
||||
* This calls pcap_set_timeout using the provided parameter.
|
||||
* \param ms The amount of milliseconds.
|
||||
*/
|
||||
void set_timeout(int ms);
|
||||
|
||||
/**
|
||||
* \brief Retrieves this sniffer's link type.
|
||||
*
|
||||
@@ -246,8 +247,13 @@ namespace Tins {
|
||||
*/
|
||||
class Sniffer : public BaseSniffer {
|
||||
public:
|
||||
enum promisc_type {
|
||||
NON_PROMISC,
|
||||
PROMISC
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Constructs an instance of Sniffer.
|
||||
* Constructs an instance of Sniffer.
|
||||
* \param device The device which will be sniffed.
|
||||
* \param max_packet_size The maximum packet size to be read.
|
||||
* \param promisc bool indicating wether to put the interface in promiscuous mode.(optional)
|
||||
@@ -255,6 +261,22 @@ namespace Tins {
|
||||
*/
|
||||
Sniffer(const std::string &device, unsigned max_packet_size,
|
||||
bool promisc = false, const std::string &filter = "");
|
||||
|
||||
/**
|
||||
* \brief Constructs an instance of Sniffer.
|
||||
*
|
||||
* The maximum capture size is set to 65535. By default the interface won't
|
||||
* be put into promiscuous mode.
|
||||
*
|
||||
* \param device The device which will be sniffed.
|
||||
* \param promisc Indicates if the interface should be put in promiscuous mode.
|
||||
* \param filter A capture filter to be used on the sniffing session.(optional);
|
||||
*/
|
||||
Sniffer(const std::string &device, promisc_type promisc = NON_PROMISC,
|
||||
const std::string &filter = "");
|
||||
private:
|
||||
void init_sniffer(const std::string &device, unsigned max_packet_size,
|
||||
bool promisc = false, const std::string &filter = "");
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -102,7 +102,7 @@ namespace Tins {
|
||||
/**
|
||||
* The type used to store TCP options.
|
||||
*/
|
||||
typedef PDUOption<uint8_t> option;
|
||||
typedef PDUOption<uint8_t, TCP> option;
|
||||
|
||||
/**
|
||||
* The type used to store the options.
|
||||
@@ -490,11 +490,11 @@ namespace Tins {
|
||||
static const uint16_t DEFAULT_WINDOW;
|
||||
|
||||
template<class T>
|
||||
T generic_search(OptionTypes opt) const {
|
||||
const option *option = search_option(opt);
|
||||
if(option && option->data_size() == sizeof(T))
|
||||
return *(const T*)(&option->data_ptr()[0]);
|
||||
throw option_not_found();
|
||||
T generic_search(OptionTypes opt_type) const {
|
||||
const option *opt = search_option(opt_type);
|
||||
if(!opt)
|
||||
throw option_not_found();
|
||||
return opt->to<T>();
|
||||
}
|
||||
|
||||
void internal_add_option(const option &option);
|
||||
|
||||
@@ -70,5 +70,8 @@
|
||||
#include "handshake_capturer.h"
|
||||
#include "address_range.h"
|
||||
#include "pdu_allocator.h"
|
||||
#include "ipsec.h"
|
||||
#include "ip_reassembler.h"
|
||||
#include "ppi.h"
|
||||
|
||||
#endif // TINS_TINS_H
|
||||
|
||||
@@ -168,13 +168,20 @@ namespace Tins {
|
||||
|
||||
|
||||
/**
|
||||
* \brief Retrieves entries int the routing table.
|
||||
* \brief Retrieves entries in the routing table.
|
||||
*
|
||||
* \brief output ForwardIterator in which entries will be stored.
|
||||
*/
|
||||
template<class ForwardIterator>
|
||||
void route_entries(ForwardIterator output);
|
||||
|
||||
/**
|
||||
* \brief Retrieves entries in the routing table.
|
||||
*
|
||||
* \return a vector which contains all of the route entries.
|
||||
*/
|
||||
std::vector<RouteEntry> route_entries();
|
||||
|
||||
/** \brief Returns the 32 bit crc of the given buffer.
|
||||
*
|
||||
* \param data The input buffer.
|
||||
|
||||
@@ -28,6 +28,9 @@
|
||||
*/
|
||||
|
||||
#include "crypto.h"
|
||||
|
||||
#ifdef HAVE_DOT11
|
||||
|
||||
#ifdef HAVE_WPA2_DECRYPTION
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/hmac.h>
|
||||
@@ -542,3 +545,5 @@ bool WPA2Decrypter::decrypt(PDU &pdu) {
|
||||
#endif // HAVE_WPA2_DECRYPTION
|
||||
} // namespace Crypto
|
||||
} // namespace Tins
|
||||
|
||||
#endif // HAVE_DOT11
|
||||
61
src/dhcp.cpp
61
src/dhcp.cpp
@@ -104,7 +104,7 @@ void DHCP::end() {
|
||||
}
|
||||
|
||||
uint8_t DHCP::type() const {
|
||||
return generic_search(DHCP_MESSAGE_TYPE, type2type<uint8_t>());
|
||||
return search_and_convert<uint8_t>(DHCP_MESSAGE_TYPE);
|
||||
}
|
||||
|
||||
void DHCP::server_identifier(ipaddress_type ip) {
|
||||
@@ -113,7 +113,7 @@ void DHCP::server_identifier(ipaddress_type ip) {
|
||||
}
|
||||
|
||||
DHCP::ipaddress_type DHCP::server_identifier() const {
|
||||
return generic_search(DHCP_SERVER_IDENTIFIER, type2type<ipaddress_type>());
|
||||
return search_and_convert<ipaddress_type>(DHCP_SERVER_IDENTIFIER);
|
||||
}
|
||||
|
||||
void DHCP::lease_time(uint32_t time) {
|
||||
@@ -122,7 +122,7 @@ void DHCP::lease_time(uint32_t time) {
|
||||
}
|
||||
|
||||
uint32_t DHCP::lease_time() const {
|
||||
return Endian::host_to_be(generic_search(DHCP_LEASE_TIME, type2type<uint32_t>()));
|
||||
return search_and_convert<uint32_t>(DHCP_LEASE_TIME);
|
||||
}
|
||||
|
||||
void DHCP::renewal_time(uint32_t time) {
|
||||
@@ -131,7 +131,7 @@ void DHCP::renewal_time(uint32_t time) {
|
||||
}
|
||||
|
||||
uint32_t DHCP::renewal_time() const {
|
||||
return Endian::host_to_be(generic_search(DHCP_RENEWAL_TIME, type2type<uint32_t>()));
|
||||
return search_and_convert<uint32_t>(DHCP_RENEWAL_TIME);
|
||||
}
|
||||
|
||||
void DHCP::subnet_mask(ipaddress_type mask) {
|
||||
@@ -140,25 +140,25 @@ void DHCP::subnet_mask(ipaddress_type mask) {
|
||||
}
|
||||
|
||||
DHCP::ipaddress_type DHCP::subnet_mask() const {
|
||||
return generic_search(SUBNET_MASK, type2type<ipaddress_type>());
|
||||
return search_and_convert<ipaddress_type>(SUBNET_MASK);
|
||||
}
|
||||
|
||||
void DHCP::routers(const list<ipaddress_type> &routers) {
|
||||
void DHCP::routers(const std::vector<ipaddress_type> &routers) {
|
||||
serialization_type buffer = serialize_list(routers);
|
||||
add_option(option(ROUTERS, buffer.begin(), buffer.end()));
|
||||
}
|
||||
|
||||
std::list<DHCP::ipaddress_type> DHCP::routers() const {
|
||||
return generic_search(ROUTERS, type2type<std::list<ipaddress_type> >());
|
||||
std::vector<DHCP::ipaddress_type> DHCP::routers() const {
|
||||
return search_and_convert<std::vector<DHCP::ipaddress_type> >(ROUTERS);
|
||||
}
|
||||
|
||||
void DHCP::domain_name_servers(const list<ipaddress_type> &dns) {
|
||||
void DHCP::domain_name_servers(const std::vector<ipaddress_type> &dns) {
|
||||
serialization_type buffer = serialize_list(dns);
|
||||
add_option(option(DOMAIN_NAME_SERVERS, buffer.begin(), buffer.end()));
|
||||
}
|
||||
|
||||
std::list<DHCP::ipaddress_type> DHCP::domain_name_servers() const {
|
||||
return generic_search(DOMAIN_NAME_SERVERS, type2type<std::list<ipaddress_type> >());
|
||||
std::vector<DHCP::ipaddress_type> DHCP::domain_name_servers() const {
|
||||
return search_and_convert<std::vector<DHCP::ipaddress_type> >(DOMAIN_NAME_SERVERS);
|
||||
}
|
||||
|
||||
void DHCP::broadcast(ipaddress_type addr) {
|
||||
@@ -167,7 +167,7 @@ void DHCP::broadcast(ipaddress_type addr) {
|
||||
}
|
||||
|
||||
DHCP::ipaddress_type DHCP::broadcast() const {
|
||||
return generic_search(BROADCAST_ADDRESS, type2type<ipaddress_type>());
|
||||
return search_and_convert<ipaddress_type>(BROADCAST_ADDRESS);
|
||||
}
|
||||
|
||||
void DHCP::requested_ip(ipaddress_type addr) {
|
||||
@@ -176,7 +176,7 @@ void DHCP::requested_ip(ipaddress_type addr) {
|
||||
}
|
||||
|
||||
DHCP::ipaddress_type DHCP::requested_ip() const {
|
||||
return generic_search(DHCP_REQUESTED_ADDRESS, type2type<ipaddress_type>());
|
||||
return search_and_convert<ipaddress_type>(DHCP_REQUESTED_ADDRESS);
|
||||
}
|
||||
|
||||
void DHCP::domain_name(const string &name) {
|
||||
@@ -184,7 +184,7 @@ void DHCP::domain_name(const string &name) {
|
||||
}
|
||||
|
||||
std::string DHCP::domain_name() const {
|
||||
return generic_search(DOMAIN_NAME, type2type<std::string>());
|
||||
return search_and_convert<std::string>(DOMAIN_NAME);
|
||||
}
|
||||
|
||||
void DHCP::rebind_time(uint32_t time) {
|
||||
@@ -193,13 +193,13 @@ void DHCP::rebind_time(uint32_t time) {
|
||||
}
|
||||
|
||||
uint32_t DHCP::rebind_time() const {
|
||||
return Endian::host_to_be(generic_search(DHCP_REBINDING_TIME, type2type<uint32_t>()));
|
||||
return search_and_convert<uint32_t>(DHCP_REBINDING_TIME);
|
||||
}
|
||||
|
||||
PDU::serialization_type DHCP::serialize_list(const list<ipaddress_type> &ip_list) {
|
||||
PDU::serialization_type DHCP::serialize_list(const std::vector<ipaddress_type> &ip_list) {
|
||||
serialization_type buffer(ip_list.size() * sizeof(uint32_t));
|
||||
uint32_t *ptr = (uint32_t*)&buffer[0];
|
||||
for(list<ipaddress_type>::const_iterator it = ip_list.begin(); it != ip_list.end(); ++it)
|
||||
for(std::vector<ipaddress_type>::const_iterator it = ip_list.begin(); it != ip_list.end(); ++it)
|
||||
*(ptr++) = *it;
|
||||
return buffer;
|
||||
}
|
||||
@@ -227,31 +227,4 @@ void DHCP::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *pa
|
||||
}
|
||||
BootP::write_serialization(buffer, total_sz, parent);
|
||||
}
|
||||
|
||||
std::list<DHCP::ipaddress_type> DHCP::generic_search(OptionTypes opt_type, type2type<std::list<ipaddress_type> >) const {
|
||||
const option *opt = search_option(opt_type);
|
||||
if(!opt)
|
||||
throw option_not_found();
|
||||
const uint32_t *ptr = (const uint32_t*)opt->data_ptr();
|
||||
uint32_t len = opt->data_size();
|
||||
if((len % sizeof(uint32_t)) != 0)
|
||||
throw option_not_found();
|
||||
std::list<ipaddress_type> container;
|
||||
while(len) {
|
||||
container.push_back(ipaddress_type(*(ptr++)));
|
||||
len -= sizeof(uint32_t);
|
||||
}
|
||||
return container;
|
||||
}
|
||||
|
||||
std::string DHCP::generic_search(OptionTypes opt_type, type2type<std::string>) const {
|
||||
const option *opt = search_option(opt_type);
|
||||
if(!opt)
|
||||
throw option_not_found();
|
||||
return string(opt->data_ptr(), opt->data_ptr() + opt->data_size());
|
||||
}
|
||||
|
||||
DHCP::ipaddress_type DHCP::generic_search(OptionTypes opt, type2type<ipaddress_type>) const {
|
||||
return ipaddress_type(generic_search(opt, type2type<uint32_t>()));
|
||||
}
|
||||
}
|
||||
|
||||
300
src/dhcpv6.cpp
300
src/dhcpv6.cpp
@@ -157,121 +157,43 @@ void DHCPv6::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *
|
||||
// ********************************************************************
|
||||
|
||||
DHCPv6::ia_na_type DHCPv6::ia_na() const {
|
||||
const option *opt = safe_search_option<std::less>(
|
||||
IA_NA, sizeof(uint32_t) * 3
|
||||
);
|
||||
const uint8_t *ptr = opt->data_ptr() + sizeof(uint32_t) * 3;
|
||||
const uint32_t *ptr_32 = (const uint32_t*)opt->data_ptr();
|
||||
DHCPv6::ia_na_type output;
|
||||
output.id = Endian::be_to_host(*ptr_32++);
|
||||
output.t1 = Endian::be_to_host(*ptr_32++);
|
||||
output.t2 = Endian::be_to_host(*ptr_32++);
|
||||
output.options.assign(ptr, opt->data_ptr() + opt->data_size());
|
||||
return output;
|
||||
return search_and_convert<ia_na_type>(IA_NA);
|
||||
}
|
||||
|
||||
DHCPv6::ia_ta_type DHCPv6::ia_ta() const {
|
||||
const option *opt = safe_search_option<std::less>(
|
||||
IA_TA, sizeof(uint32_t)
|
||||
);
|
||||
const uint8_t *ptr = opt->data_ptr() + sizeof(uint32_t);
|
||||
const uint32_t *ptr_32 = (const uint32_t*)opt->data_ptr();
|
||||
DHCPv6::ia_ta_type output;
|
||||
output.id = Endian::be_to_host(*ptr_32++);
|
||||
output.options.assign(ptr, opt->data_ptr() + opt->data_size());
|
||||
return output;
|
||||
return search_and_convert<ia_ta_type>(IA_TA);
|
||||
}
|
||||
|
||||
DHCPv6::ia_address_type DHCPv6::ia_address() const {
|
||||
const option *opt = safe_search_option<std::less>(
|
||||
IA_ADDR, sizeof(uint32_t) * 2 + ipaddress_type::address_size
|
||||
);
|
||||
const uint8_t *ptr = opt->data_ptr() + sizeof(uint32_t) * 2 + ipaddress_type::address_size;
|
||||
const uint32_t *ptr_32 = (const uint32_t*)(opt->data_ptr() + ipaddress_type::address_size);
|
||||
DHCPv6::ia_address_type output;
|
||||
output.address = opt->data_ptr();
|
||||
output.preferred_lifetime = Endian::be_to_host(*ptr_32++);
|
||||
output.valid_lifetime = Endian::be_to_host(*ptr_32++);
|
||||
output.options.assign(ptr, opt->data_ptr() + opt->data_size());
|
||||
return output;
|
||||
return search_and_convert<ia_address_type>(IA_ADDR);
|
||||
}
|
||||
|
||||
DHCPv6::option_request_type DHCPv6::option_request() const {
|
||||
const option *opt = safe_search_option<std::less>(
|
||||
OPTION_REQUEST, 2
|
||||
);
|
||||
const uint16_t *ptr = (const uint16_t*)opt->data_ptr(),
|
||||
*end = (const uint16_t*)(opt->data_ptr() + opt->data_size());
|
||||
option_request_type output;
|
||||
while(ptr < end) {
|
||||
output.push_back(
|
||||
static_cast<OptionTypes>(Endian::be_to_host(*ptr++))
|
||||
);
|
||||
}
|
||||
return output;
|
||||
return search_and_convert<option_request_type>(OPTION_REQUEST);
|
||||
}
|
||||
|
||||
uint8_t DHCPv6::preference() const {
|
||||
const option *opt = safe_search_option<std::not_equal_to>(
|
||||
PREFERENCE, 1
|
||||
);
|
||||
return *opt->data_ptr();
|
||||
return search_and_convert<uint8_t>(PREFERENCE);
|
||||
}
|
||||
|
||||
uint16_t DHCPv6::elapsed_time() const {
|
||||
const option *opt = safe_search_option<std::not_equal_to>(
|
||||
ELAPSED_TIME, 2
|
||||
);
|
||||
return Endian::be_to_host(
|
||||
*(const uint16_t*)opt->data_ptr()
|
||||
);
|
||||
return search_and_convert<uint16_t>(ELAPSED_TIME);
|
||||
}
|
||||
|
||||
DHCPv6::relay_msg_type DHCPv6::relay_message() const {
|
||||
const option *opt = safe_search_option<std::less>(
|
||||
RELAY_MSG, 1
|
||||
);
|
||||
return relay_msg_type(
|
||||
opt->data_ptr(),
|
||||
opt->data_ptr() + opt->data_size()
|
||||
);
|
||||
return search_and_convert<relay_msg_type>(RELAY_MSG);
|
||||
}
|
||||
|
||||
DHCPv6::authentication_type DHCPv6::authentication() const {
|
||||
const option *opt = safe_search_option<std::less>(
|
||||
AUTH, sizeof(uint8_t) * 3 + sizeof(uint64_t)
|
||||
);
|
||||
const uint8_t *ptr = opt->data_ptr();
|
||||
authentication_type output;
|
||||
output.protocol = *ptr++;
|
||||
output.algorithm = *ptr++;
|
||||
output.rdm = *ptr++;
|
||||
output.replay_detection = Endian::be_to_host(
|
||||
*(const uint64_t*)ptr
|
||||
);
|
||||
ptr += sizeof(uint64_t);
|
||||
output.auth_info.assign(ptr, opt->data_ptr() + opt->data_size());
|
||||
return output;
|
||||
return search_and_convert<authentication_type>(AUTH);
|
||||
}
|
||||
|
||||
DHCPv6::ipaddress_type DHCPv6::server_unicast() const {
|
||||
const option *opt = safe_search_option<std::not_equal_to>(
|
||||
UNICAST, ipaddress_type::address_size
|
||||
);
|
||||
return ipaddress_type(opt->data_ptr());
|
||||
return search_and_convert<ipaddress_type>(UNICAST);
|
||||
}
|
||||
|
||||
DHCPv6::status_code_type DHCPv6::status_code() const {
|
||||
const option *opt = safe_search_option<std::less>(
|
||||
STATUS_CODE, sizeof(uint16_t)
|
||||
);
|
||||
status_code_type output;
|
||||
output.code = Endian::be_to_host(*(const uint16_t*)opt->data_ptr());
|
||||
output.message.assign(
|
||||
opt->data_ptr() + sizeof(uint16_t),
|
||||
opt->data_ptr() + opt->data_size()
|
||||
);
|
||||
return output;
|
||||
return search_and_convert<status_code_type>(STATUS_CODE);
|
||||
}
|
||||
|
||||
bool DHCPv6::has_rapid_commit() const {
|
||||
@@ -279,60 +201,23 @@ bool DHCPv6::has_rapid_commit() const {
|
||||
}
|
||||
|
||||
DHCPv6::user_class_type DHCPv6::user_class() const {
|
||||
const option *opt = safe_search_option<std::less>(
|
||||
USER_CLASS, sizeof(uint16_t)
|
||||
);
|
||||
return option2class_option_data<user_class_type>(
|
||||
opt->data_ptr(), opt->data_size()
|
||||
);
|
||||
return search_and_convert<user_class_type>(USER_CLASS);
|
||||
}
|
||||
|
||||
DHCPv6::vendor_class_type DHCPv6::vendor_class() const {
|
||||
const option *opt = safe_search_option<std::less>(
|
||||
VENDOR_CLASS, sizeof(uint32_t)
|
||||
);
|
||||
typedef vendor_class_type::class_data_type data_type;
|
||||
vendor_class_type output;
|
||||
output.enterprise_number = Endian::be_to_host(
|
||||
*(const uint32_t*)opt->data_ptr()
|
||||
);
|
||||
output.vendor_class_data = option2class_option_data<data_type>(
|
||||
opt->data_ptr() + sizeof(uint32_t),
|
||||
opt->data_size() - sizeof(uint32_t)
|
||||
);
|
||||
|
||||
return output;
|
||||
return search_and_convert<vendor_class_type>(VENDOR_CLASS);
|
||||
}
|
||||
|
||||
DHCPv6::vendor_info_type DHCPv6::vendor_info() const {
|
||||
const option *opt = safe_search_option<std::less>(
|
||||
VENDOR_OPTS, sizeof(uint32_t)
|
||||
);
|
||||
vendor_info_type output;
|
||||
output.enterprise_number = Endian::be_to_host(
|
||||
*(const uint32_t*)opt->data_ptr()
|
||||
);
|
||||
output.data.assign(
|
||||
opt->data_ptr() + sizeof(uint32_t),
|
||||
opt->data_ptr() + opt->data_size()
|
||||
);
|
||||
return output;
|
||||
return search_and_convert<vendor_info_type>(VENDOR_OPTS);
|
||||
}
|
||||
|
||||
DHCPv6::interface_id_type DHCPv6::interface_id() const {
|
||||
const option *opt = safe_search_option<std::equal_to>(
|
||||
INTERFACE_ID, 0
|
||||
);
|
||||
return interface_id_type(
|
||||
opt->data_ptr(),
|
||||
opt->data_ptr() + opt->data_size()
|
||||
);
|
||||
return search_and_convert<interface_id_type>(INTERFACE_ID);
|
||||
}
|
||||
|
||||
uint8_t DHCPv6::reconfigure_msg() const {
|
||||
return *safe_search_option<std::not_equal_to>(
|
||||
RECONF_MSG, 1
|
||||
)->data_ptr();
|
||||
return search_and_convert<uint8_t>(RECONF_MSG);
|
||||
}
|
||||
|
||||
bool DHCPv6::has_reconfigure_accept() const {
|
||||
@@ -340,29 +225,11 @@ bool DHCPv6::has_reconfigure_accept() const {
|
||||
}
|
||||
|
||||
DHCPv6::duid_type DHCPv6::client_id() const {
|
||||
const option *opt = safe_search_option<std::less>(
|
||||
CLIENTID, sizeof(uint16_t) + 1
|
||||
);
|
||||
return duid_type(
|
||||
Endian::be_to_host(*(const uint16_t*)opt->data_ptr()),
|
||||
serialization_type(
|
||||
opt->data_ptr() + sizeof(uint16_t),
|
||||
opt->data_ptr() + opt->data_size()
|
||||
)
|
||||
);
|
||||
return search_and_convert<duid_type>(CLIENTID);
|
||||
}
|
||||
|
||||
DHCPv6::duid_type DHCPv6::server_id() const {
|
||||
const option *opt = safe_search_option<std::less>(
|
||||
SERVERID, sizeof(uint16_t) + 1
|
||||
);
|
||||
return duid_type(
|
||||
Endian::be_to_host(*(const uint16_t*)opt->data_ptr()),
|
||||
serialization_type(
|
||||
opt->data_ptr() + sizeof(uint16_t),
|
||||
opt->data_ptr() + opt->data_size()
|
||||
)
|
||||
);
|
||||
return search_and_convert<duid_type>(SERVERID);
|
||||
}
|
||||
|
||||
// ********************************************************************
|
||||
@@ -492,10 +359,10 @@ void DHCPv6::rapid_commit() {
|
||||
}
|
||||
|
||||
void DHCPv6::user_class(const user_class_type &value) {
|
||||
typedef user_class_type::const_iterator iterator;
|
||||
typedef user_class_type::data_type::const_iterator iterator;
|
||||
|
||||
std::vector<uint8_t> buffer;
|
||||
class_option_data2option(value.begin(), value.end(), buffer);
|
||||
Internals::class_option_data2option(value.data.begin(), value.data.end(), buffer);
|
||||
add_option(
|
||||
option(USER_CLASS, buffer.begin(), buffer.end())
|
||||
);
|
||||
@@ -506,7 +373,7 @@ void DHCPv6::vendor_class(const vendor_class_type &value) {
|
||||
sizeof(uint32_t)
|
||||
);
|
||||
*(uint32_t*)&buffer[0] = Endian::host_to_be(value.enterprise_number);
|
||||
class_option_data2option(
|
||||
Internals::class_option_data2option(
|
||||
value.vendor_class_data.begin(),
|
||||
value.vendor_class_data.end(),
|
||||
buffer,
|
||||
@@ -650,4 +517,131 @@ void DHCPv6::server_id(const duid_type &value) {
|
||||
);
|
||||
}
|
||||
|
||||
// Options
|
||||
|
||||
DHCPv6::ia_na_type DHCPv6::ia_na_type::from_option(const option &opt)
|
||||
{
|
||||
if(opt.data_size() < sizeof(uint32_t) * 3)
|
||||
throw malformed_option();
|
||||
const uint8_t *ptr = opt.data_ptr() + sizeof(uint32_t) * 3;
|
||||
const uint32_t *ptr_32 = (const uint32_t*)opt.data_ptr();
|
||||
DHCPv6::ia_na_type output;
|
||||
output.id = Endian::be_to_host(*ptr_32++);
|
||||
output.t1 = Endian::be_to_host(*ptr_32++);
|
||||
output.t2 = Endian::be_to_host(*ptr_32++);
|
||||
output.options.assign(ptr, opt.data_ptr() + opt.data_size());
|
||||
return output;
|
||||
}
|
||||
|
||||
DHCPv6::ia_ta_type DHCPv6::ia_ta_type::from_option(const option &opt)
|
||||
{
|
||||
if(opt.data_size() < sizeof(uint32_t))
|
||||
throw malformed_option();
|
||||
const uint8_t *ptr = opt.data_ptr() + sizeof(uint32_t);
|
||||
const uint32_t *ptr_32 = (const uint32_t*)opt.data_ptr();
|
||||
DHCPv6::ia_ta_type output;
|
||||
output.id = Endian::be_to_host(*ptr_32++);
|
||||
output.options.assign(ptr, opt.data_ptr() + opt.data_size());
|
||||
return output;
|
||||
}
|
||||
|
||||
DHCPv6::ia_address_type DHCPv6::ia_address_type::from_option(const option &opt)
|
||||
{
|
||||
if(opt.data_size() < sizeof(uint32_t) * 2 + DHCPv6::ipaddress_type::address_size)
|
||||
throw malformed_option();
|
||||
const uint8_t *ptr = opt.data_ptr() + sizeof(uint32_t) * 2 + ipaddress_type::address_size;
|
||||
const uint32_t *ptr_32 = (const uint32_t*)(opt.data_ptr() + ipaddress_type::address_size);
|
||||
DHCPv6::ia_address_type output;
|
||||
output.address = opt.data_ptr();
|
||||
output.preferred_lifetime = Endian::be_to_host(*ptr_32++);
|
||||
output.valid_lifetime = Endian::be_to_host(*ptr_32++);
|
||||
output.options.assign(ptr, opt.data_ptr() + opt.data_size());
|
||||
return output;
|
||||
}
|
||||
|
||||
DHCPv6::authentication_type DHCPv6::authentication_type::from_option(const option &opt)
|
||||
{
|
||||
if(opt.data_size() < sizeof(uint8_t) * 3 + sizeof(uint64_t))
|
||||
throw malformed_option();
|
||||
const uint8_t *ptr = opt.data_ptr();
|
||||
authentication_type output;
|
||||
output.protocol = *ptr++;
|
||||
output.algorithm = *ptr++;
|
||||
output.rdm = *ptr++;
|
||||
output.replay_detection = Endian::be_to_host(
|
||||
*(const uint64_t*)ptr
|
||||
);
|
||||
ptr += sizeof(uint64_t);
|
||||
output.auth_info.assign(ptr, opt.data_ptr() + opt.data_size());
|
||||
return output;
|
||||
}
|
||||
|
||||
DHCPv6::status_code_type DHCPv6::status_code_type::from_option(const option &opt)
|
||||
{
|
||||
if(opt.data_size() < sizeof(uint16_t))
|
||||
throw malformed_option();
|
||||
status_code_type output;
|
||||
output.code = Endian::be_to_host(*(const uint16_t*)opt.data_ptr());
|
||||
output.message.assign(
|
||||
opt.data_ptr() + sizeof(uint16_t),
|
||||
opt.data_ptr() + opt.data_size()
|
||||
);
|
||||
return output;
|
||||
}
|
||||
|
||||
DHCPv6::vendor_info_type DHCPv6::vendor_info_type::from_option(const option &opt)
|
||||
{
|
||||
if(opt.data_size() < sizeof(uint32_t))
|
||||
throw malformed_option();
|
||||
vendor_info_type output;
|
||||
output.enterprise_number = Endian::be_to_host(
|
||||
*(const uint32_t*)opt.data_ptr()
|
||||
);
|
||||
output.data.assign(
|
||||
opt.data_ptr() + sizeof(uint32_t),
|
||||
opt.data_ptr() + opt.data_size()
|
||||
);
|
||||
return output;
|
||||
}
|
||||
|
||||
DHCPv6::vendor_class_type DHCPv6::vendor_class_type::from_option(const option &opt)
|
||||
{
|
||||
if(opt.data_size() < sizeof(uint32_t))
|
||||
throw malformed_option();
|
||||
typedef vendor_class_type::class_data_type data_type;
|
||||
vendor_class_type output;
|
||||
output.enterprise_number = Endian::be_to_host(
|
||||
*(const uint32_t*)opt.data_ptr()
|
||||
);
|
||||
output.vendor_class_data = Internals::option2class_option_data<data_type>(
|
||||
opt.data_ptr() + sizeof(uint32_t),
|
||||
opt.data_size() - sizeof(uint32_t)
|
||||
);
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
DHCPv6::duid_type DHCPv6::duid_type::from_option(const option &opt)
|
||||
{
|
||||
if(opt.data_size() < sizeof(uint16_t) + 1)
|
||||
throw malformed_option();
|
||||
return duid_type(
|
||||
Endian::be_to_host(*(const uint16_t*)opt.data_ptr()),
|
||||
serialization_type(
|
||||
opt.data_ptr() + sizeof(uint16_t),
|
||||
opt.data_ptr() + opt.data_size()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
DHCPv6::user_class_type DHCPv6::user_class_type::from_option(const option &opt)
|
||||
{
|
||||
if(opt.data_size() < sizeof(uint16_t))
|
||||
throw malformed_option();
|
||||
user_class_type output;
|
||||
output.data = Internals::option2class_option_data<data_type>(
|
||||
opt.data_ptr(), opt.data_size()
|
||||
);
|
||||
return output;
|
||||
}
|
||||
} // namespace Tins
|
||||
|
||||
673
src/dns.cpp
673
src/dns.cpp
@@ -32,6 +32,7 @@
|
||||
#include <cassert>
|
||||
#include <sstream>
|
||||
#include <memory>
|
||||
#include <cstdio>
|
||||
#include "dns.h"
|
||||
#include "ip_address.h"
|
||||
#include "ipv6_address.h"
|
||||
@@ -43,60 +44,75 @@ using std::list;
|
||||
|
||||
namespace Tins {
|
||||
|
||||
DNS::DNS() : extra_size(0) {
|
||||
DNS::DNS()
|
||||
: answers_idx(), authority_idx(), additional_idx()
|
||||
{
|
||||
std::memset(&dns, 0, sizeof(dns));
|
||||
}
|
||||
|
||||
DNS::DNS(const uint8_t *buffer, uint32_t total_sz) : extra_size(0) {
|
||||
DNS::DNS(const uint8_t *buffer, uint32_t total_sz)
|
||||
: answers_idx(), authority_idx(), additional_idx()
|
||||
{
|
||||
if(total_sz < sizeof(dnshdr))
|
||||
throw malformed_packet();
|
||||
std::memcpy(&dns, buffer, sizeof(dnshdr));
|
||||
const uint8_t *end(buffer + total_sz);
|
||||
uint16_t nquestions(questions_count());
|
||||
buffer += sizeof(dnshdr);
|
||||
total_sz -= sizeof(dnshdr);
|
||||
records_data.assign(
|
||||
buffer + sizeof(dnshdr),
|
||||
buffer + total_sz
|
||||
);
|
||||
buffer = &records_data[0];
|
||||
const uint8_t *end = &records_data[0] + records_data.size(), *prev_start = buffer;
|
||||
uint16_t nquestions = questions_count();
|
||||
for(uint16_t i(0); i < nquestions; ++i) {
|
||||
const uint8_t *ptr(buffer);
|
||||
while(ptr < end && *ptr)
|
||||
ptr++;
|
||||
Query query;
|
||||
if((ptr + (sizeof(uint16_t) * 2)) >= end)
|
||||
buffer = find_dname_end(buffer);
|
||||
if((buffer + (sizeof(uint16_t) * 2)) > end)
|
||||
throw malformed_packet();
|
||||
query.dname(string(buffer, ptr));
|
||||
ptr++;
|
||||
const uint16_t *opt_ptr = reinterpret_cast<const uint16_t*>(ptr);
|
||||
query.type((QueryType)*(opt_ptr++));
|
||||
query.query_class((QueryClass)*(opt_ptr++));
|
||||
queries_.push_back(query);
|
||||
total_sz -= reinterpret_cast<const uint8_t*>(opt_ptr) - buffer;
|
||||
extra_size += reinterpret_cast<const uint8_t*>(opt_ptr) - buffer;
|
||||
buffer = reinterpret_cast<const uint8_t*>(opt_ptr);
|
||||
buffer += sizeof(uint16_t) * 2;
|
||||
}
|
||||
buffer = build_resource_list(ans, buffer, total_sz, answers_count());
|
||||
buffer = build_resource_list(arity, buffer, total_sz, authority_count());
|
||||
build_resource_list(addit, buffer, total_sz, additional_count());
|
||||
if(total_sz)
|
||||
inner_pdu(new RawPDU(buffer, total_sz));
|
||||
answers_idx = buffer - prev_start;
|
||||
authority_idx = find_section_end(&records_data[answers_idx], answers_count()) - &records_data[0];
|
||||
additional_idx = find_section_end(&records_data[authority_idx], authority_count()) - &records_data[0];
|
||||
}
|
||||
|
||||
const uint8_t *DNS::build_resource_list(ResourcesType &lst, const uint8_t *ptr, uint32_t &sz, uint16_t nrecs) {
|
||||
const uint8_t *ptr_end(ptr + sz);
|
||||
const uint8_t *parse_start(ptr);
|
||||
for(uint16_t i(0); i < nrecs; ++i) {
|
||||
const uint8_t *this_opt_start(ptr);
|
||||
if(ptr + sizeof(uint16_t) > ptr_end)
|
||||
throw malformed_packet();
|
||||
lst.push_back(DNSResourceRecord(ptr, ptr_end - ptr));
|
||||
ptr += lst.back().size();
|
||||
extra_size += ptr - this_opt_start;
|
||||
|
||||
const uint8_t* DNS::find_dname_end(const uint8_t *ptr) const {
|
||||
const uint8_t *end = &records_data[0] + records_data.size();
|
||||
while(ptr < end) {
|
||||
if(*ptr == 0) {
|
||||
++ptr;
|
||||
break;
|
||||
}
|
||||
else {
|
||||
if((*ptr & 0xc0)) {
|
||||
ptr += sizeof(uint16_t);
|
||||
break;
|
||||
}
|
||||
else {
|
||||
uint8_t size = *ptr;
|
||||
ptr += size + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
|
||||
const uint8_t *DNS::find_section_end(const uint8_t *ptr, const uint32_t num_records) const {
|
||||
const uint8_t *end = &records_data[0] + records_data.size();
|
||||
for(uint32_t i = 0; i < num_records; ++i) {
|
||||
ptr = find_dname_end(ptr);
|
||||
if(ptr + sizeof(uint16_t) * 3 + sizeof(uint32_t) > end)
|
||||
throw malformed_packet();
|
||||
ptr += sizeof(uint16_t) * 2 + sizeof(uint32_t);
|
||||
uint16_t data_size = Endian::be_to_host(*(uint16_t*)ptr); // Data size
|
||||
ptr += sizeof(uint16_t);
|
||||
if(ptr + data_size > end)
|
||||
throw malformed_packet();
|
||||
ptr += data_size;
|
||||
}
|
||||
sz -= ptr - parse_start;
|
||||
return ptr;
|
||||
}
|
||||
|
||||
uint32_t DNS::header_size() const {
|
||||
return sizeof(dns) + extra_size;
|
||||
return sizeof(dns) + records_data.size();
|
||||
}
|
||||
|
||||
void DNS::id(uint16_t new_id) {
|
||||
@@ -144,363 +160,372 @@ void DNS::rcode(uint8_t new_rcode) {
|
||||
}
|
||||
|
||||
bool DNS::contains_dname(uint16_t type) {
|
||||
type = Endian::be_to_host(type);
|
||||
return type == MX || type == CNAME ||
|
||||
type == PTR || type == NS;
|
||||
}
|
||||
|
||||
void DNS::add_query(const Query &query) {
|
||||
string new_str;
|
||||
parse_domain_name(query.dname(), new_str);
|
||||
|
||||
queries_.push_back(
|
||||
Query(
|
||||
new_str,
|
||||
(QueryType)Endian::host_to_be<uint16_t>(query.type()),
|
||||
(QueryClass)Endian::host_to_be<uint16_t>(query.query_class())
|
||||
)
|
||||
string new_str = encode_domain_name(query.dname());
|
||||
// Type (2 bytes) + Class (2 Bytes)
|
||||
new_str.insert(new_str.end(), sizeof(uint16_t) * 2, ' ');
|
||||
*(uint16_t*)&new_str[new_str.size() - 4] = Endian::host_to_be<uint16_t>(query.type());
|
||||
*(uint16_t*)&new_str[new_str.size() - 2] = Endian::host_to_be<uint16_t>(query.query_class());
|
||||
|
||||
uint32_t offset = new_str.size(), threshold = answers_idx;
|
||||
update_records(answers_idx, answers_count(), threshold, offset);
|
||||
update_records(authority_idx, authority_count(), threshold, offset);
|
||||
update_records(additional_idx, additional_count(), threshold, offset);
|
||||
records_data.insert(
|
||||
records_data.begin() + threshold,
|
||||
new_str.begin(),
|
||||
new_str.end()
|
||||
);
|
||||
dns.questions = Endian::host_to_be<uint16_t>(
|
||||
questions_count() + 1
|
||||
);
|
||||
extra_size += new_str.size() + 1 + (sizeof(uint16_t) << 1);
|
||||
dns.questions = Endian::host_to_be<uint16_t>(queries_.size());
|
||||
}
|
||||
|
||||
void DNS::add_answer(const string &name, const DNSResourceRecord::info &info,
|
||||
address_type ip)
|
||||
{
|
||||
ans.push_back(make_record(name, info, Endian::host_to_be((uint32_t)ip)));
|
||||
dns.answers = Endian::host_to_be<uint16_t>(ans.size());
|
||||
void DNS::add_answer(const Resource &resource) {
|
||||
sections_type sections;
|
||||
sections.push_back(std::make_pair(&authority_idx, authority_count()));
|
||||
sections.push_back(std::make_pair(&additional_idx, additional_count()));
|
||||
add_record(resource, sections);
|
||||
dns.answers = Endian::host_to_be<uint16_t>(
|
||||
answers_count() + 1
|
||||
);
|
||||
}
|
||||
|
||||
void DNS::add_answer(const string &name, const DNSResourceRecord::info &info,
|
||||
address_v6_type ip)
|
||||
{
|
||||
ans.push_back(make_record(name, info, ip.begin(), address_v6_type::address_size));
|
||||
dns.answers = Endian::host_to_be<uint16_t>(ans.size());
|
||||
}
|
||||
|
||||
void DNS::add_answer(const std::string &name, const DNSResourceRecord::info &info,
|
||||
const std::string &dname)
|
||||
{
|
||||
string new_str;
|
||||
parse_domain_name(dname, new_str);
|
||||
DNSResourceRecord res = make_record(name, info, new_str);
|
||||
ans.push_back(res);
|
||||
dns.answers = Endian::host_to_be<uint16_t>(ans.size());
|
||||
}
|
||||
|
||||
void DNS::add_answer(const std::string &name, const DNSResourceRecord::info &info,
|
||||
const uint8_t *data, uint32_t sz)
|
||||
{
|
||||
ans.push_back(make_record(name, info, data, sz));
|
||||
dns.answers = Endian::host_to_be<uint16_t>(ans.size());
|
||||
}
|
||||
|
||||
void DNS::add_authority(const string &name, const DNSResourceRecord::info &info,
|
||||
const uint8_t *data, uint32_t sz)
|
||||
{
|
||||
arity.push_back(make_record(name, info, data, sz));
|
||||
dns.authority = Endian::host_to_be<uint16_t>(arity.size());
|
||||
}
|
||||
|
||||
void DNS::add_additional(const string &name, const DNSResourceRecord::info &info,
|
||||
uint32_t ip)
|
||||
{
|
||||
addit.push_back(make_record(name, info, ip));
|
||||
dns.additional = Endian::host_to_be<uint16_t>(addit.size());
|
||||
}
|
||||
|
||||
DNSResourceRecord DNS::make_record(const std::string &name, const DNSResourceRecord::info &info, uint32_t ip) {
|
||||
ip = Endian::host_to_be(ip);
|
||||
return make_record(name, info, reinterpret_cast<uint8_t*>(&ip), sizeof(ip));
|
||||
}
|
||||
|
||||
DNSResourceRecord DNS::make_record(const std::string &name,
|
||||
const DNSResourceRecord::info &info, const std::string &dname)
|
||||
{
|
||||
return make_record(name, info, reinterpret_cast<const uint8_t*>(dname.c_str()), dname.size() + 1);
|
||||
}
|
||||
|
||||
DNSResourceRecord DNS::make_record(const std::string &name,
|
||||
const DNSResourceRecord::info &info, const uint8_t *ptr, uint32_t len)
|
||||
{
|
||||
string nm;
|
||||
std::basic_string<uint8_t> data;
|
||||
parse_domain_name(name, nm);
|
||||
uint16_t index = find_domain_name(nm);
|
||||
DNSResourceRecord res;
|
||||
if(info.type == MX) {
|
||||
data.push_back(0);
|
||||
data.push_back(0);
|
||||
data.insert(data.end(), ptr, ptr + len);
|
||||
ptr = &data[0];
|
||||
len = data.size();
|
||||
void DNS::add_record(const Resource &resource, const sections_type §ions) {
|
||||
// We need to check that the data provided is correct. Otherwise, the sections
|
||||
// will end up being inconsistent.
|
||||
IPv4Address v4_addr;
|
||||
IPv6Address v6_addr;
|
||||
std::string buffer = encode_domain_name(resource.dname()), encoded_data;
|
||||
// By default the data size is the length of the data field.
|
||||
uint32_t data_size = resource.data().size();
|
||||
if(resource.type() == A) {
|
||||
v4_addr = resource.data();
|
||||
data_size = 4;
|
||||
}
|
||||
if(index)
|
||||
res = make_offseted_record(Endian::host_to_be(index), ptr, len);
|
||||
else
|
||||
res = make_named_record(nm, ptr, len);
|
||||
res.information().type = Endian::host_to_be<uint16_t>(info.type);
|
||||
res.information().qclass = Endian::host_to_be<uint16_t>(info.qclass);
|
||||
res.information().ttl = Endian::host_to_be(info.ttl);
|
||||
extra_size += res.size();
|
||||
return res;
|
||||
}
|
||||
|
||||
uint32_t DNS::find_domain_name(const std::string &dname) {
|
||||
uint16_t index(sizeof(dnshdr));
|
||||
list<Query>::const_iterator it(queries_.begin());
|
||||
for(; it != queries_.end() && it->dname() != dname; ++it)
|
||||
index += it->dname().size() + 1 + (sizeof(uint16_t) << 1);
|
||||
if(it != queries_.end() ||
|
||||
find_domain_name(dname, ans, index) ||
|
||||
find_domain_name(dname, arity, index) ||
|
||||
find_domain_name(dname, addit, index))
|
||||
return index;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool DNS::find_domain_name(const std::string &dname, const ResourcesType &lst, uint16_t &out) {
|
||||
ResourcesType::const_iterator it(lst.begin());
|
||||
while(it != lst.end()) {
|
||||
if(it->matches(dname))
|
||||
break;
|
||||
out += it->size();
|
||||
++it;
|
||||
else if(resource.type() == AAAA) {
|
||||
v6_addr = resource.data();
|
||||
data_size = IPv6Address::address_size;
|
||||
}
|
||||
else if(contains_dname(resource.type())) {
|
||||
encoded_data = encode_domain_name(resource.data());
|
||||
data_size = encoded_data.size();
|
||||
}
|
||||
uint32_t offset = buffer.size() + sizeof(uint16_t) * 3 + sizeof(uint32_t) + data_size,
|
||||
threshold = sections.empty() ? records_data.size() : *sections.front().first;
|
||||
// Skip the preference field
|
||||
if(resource.type() == MX) {
|
||||
offset += sizeof(uint16_t);
|
||||
}
|
||||
for(size_t i = 0; i < sections.size(); ++i) {
|
||||
update_records(*sections[i].first, sections[i].second, threshold, offset);
|
||||
}
|
||||
|
||||
records_data.insert(
|
||||
records_data.begin() + threshold,
|
||||
offset,
|
||||
0
|
||||
);
|
||||
uint8_t *ptr = std::copy(
|
||||
buffer.begin(),
|
||||
buffer.end(),
|
||||
&records_data[threshold]
|
||||
);
|
||||
*(uint16_t*)ptr = Endian::host_to_be(resource.type());
|
||||
ptr += sizeof(uint16_t);
|
||||
*(uint16_t*)ptr = Endian::host_to_be(resource.query_class());
|
||||
ptr += sizeof(uint16_t);
|
||||
*(uint32_t*)ptr = Endian::host_to_be(resource.ttl());
|
||||
ptr += sizeof(uint32_t);
|
||||
*(uint16_t*)ptr = Endian::host_to_be<uint16_t>(
|
||||
data_size + (resource.type() == MX ? 2 : 0)
|
||||
);
|
||||
ptr += sizeof(uint16_t);
|
||||
if(resource.type() == MX) {
|
||||
ptr += sizeof(uint16_t);
|
||||
}
|
||||
if(resource.type() == A) {
|
||||
uint32_t ip_int = v4_addr;
|
||||
std::memcpy(ptr, &ip_int, sizeof(ip_int));
|
||||
}
|
||||
else if(resource.type() == AAAA) {
|
||||
std::copy(v6_addr.begin(), v6_addr.end(), ptr);
|
||||
}
|
||||
else if(!encoded_data.empty()) {
|
||||
std::copy(encoded_data.begin(), encoded_data.end(), ptr);
|
||||
}
|
||||
else {
|
||||
std::copy(resource.data().begin(), resource.data().end(), ptr);
|
||||
}
|
||||
return it != lst.end();
|
||||
}
|
||||
|
||||
void DNS::parse_domain_name(const std::string &dn, std::string &out) const {
|
||||
void DNS::add_authority(const Resource &resource) {
|
||||
sections_type sections;
|
||||
sections.push_back(std::make_pair(&additional_idx, additional_count()));
|
||||
add_record(resource, sections);
|
||||
dns.authority = Endian::host_to_be<uint16_t>(
|
||||
authority_count() + 1
|
||||
);
|
||||
}
|
||||
|
||||
void DNS::add_additional(const Resource &resource){
|
||||
add_record(resource, sections_type());
|
||||
dns.additional = Endian::host_to_be<uint16_t>(
|
||||
additional_count() + 1
|
||||
);
|
||||
}
|
||||
|
||||
std::string DNS::encode_domain_name(const std::string &dn) {
|
||||
std::string output;
|
||||
size_t last_index(0), index;
|
||||
while((index = dn.find('.', last_index+1)) != string::npos) {
|
||||
out.push_back(index - last_index);
|
||||
out.append(dn.begin() + last_index, dn.begin() + index);
|
||||
output.push_back(index - last_index);
|
||||
output.append(dn.begin() + last_index, dn.begin() + index);
|
||||
last_index = index + 1; //skip dot
|
||||
}
|
||||
out.push_back(dn.size() - last_index);
|
||||
out.append(dn.begin() + last_index, dn.end());
|
||||
output.push_back(dn.size() - last_index);
|
||||
output.append(dn.begin() + last_index, dn.end());
|
||||
output.push_back('\0');
|
||||
return output;
|
||||
}
|
||||
|
||||
void DNS::unparse_domain_name(const std::string &dn, std::string &out) const {
|
||||
if(dn.size()) {
|
||||
uint32_t index(1), len(dn[0]);
|
||||
while(index + len < dn.size() && len) {
|
||||
if(index != 1)
|
||||
out.push_back('.');
|
||||
out.append(dn.begin() + index, dn.begin() + index + len);
|
||||
index += len;
|
||||
if(index < dn.size() - 1)
|
||||
len = dn[index];
|
||||
index++;
|
||||
// The output buffer should be at least 256 bytes long. This used to use
|
||||
// a std::string but it worked about 50% slower, so this is somehow
|
||||
// unsafe but a lot faster.
|
||||
const uint8_t* DNS::compose_name(const uint8_t *ptr, char *out_ptr) const {
|
||||
const uint8_t *end = &records_data[0] + records_data.size();
|
||||
const uint8_t *end_ptr = 0;
|
||||
char *current_out_ptr = out_ptr;
|
||||
while(*ptr) {
|
||||
// It's an offset
|
||||
if((*ptr & 0xc0)) {
|
||||
if(ptr + sizeof(uint16_t) > end)
|
||||
throw malformed_packet();
|
||||
uint16_t index = Endian::be_to_host(*(uint16_t*)ptr) & 0x3fff;
|
||||
// Check that the offset is neither too low or too high
|
||||
if(index < 0x0c || &records_data[index - 0x0c] >= ptr)
|
||||
throw malformed_packet();
|
||||
// We've probably found the end of the original domain name. Save it.
|
||||
if(end_ptr == 0)
|
||||
end_ptr = ptr + sizeof(uint16_t);
|
||||
// Now this is our pointer
|
||||
ptr = &records_data[index - 0x0c];
|
||||
}
|
||||
if(index < dn.size()) {
|
||||
out.push_back('.');
|
||||
out.append(dn.begin() + index, dn.end());
|
||||
else {
|
||||
// It's a label, grab its size.
|
||||
uint8_t size = *ptr;
|
||||
ptr++;
|
||||
if(ptr + size > end || current_out_ptr - out_ptr + size + 1 > 255)
|
||||
throw malformed_packet();
|
||||
// Append a dot if it's not the first one.
|
||||
if(current_out_ptr != out_ptr)
|
||||
*current_out_ptr++ = '.';
|
||||
std::copy(
|
||||
ptr,
|
||||
ptr + size,
|
||||
current_out_ptr
|
||||
);
|
||||
current_out_ptr += size;
|
||||
ptr += size;
|
||||
}
|
||||
}
|
||||
// Add the null terminator.
|
||||
*current_out_ptr = 0;
|
||||
return end_ptr ? end_ptr : (ptr + 1);
|
||||
}
|
||||
|
||||
void DNS::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *parent) {
|
||||
#ifdef TINS_DEBUG
|
||||
assert(total_sz >= sizeof(dns) + extra_size);
|
||||
assert(total_sz >= sizeof(dns) + records_data.size());//extra_size);
|
||||
#endif
|
||||
std::memcpy(buffer, &dns, sizeof(dns));
|
||||
buffer += sizeof(dns);
|
||||
for(list<Query>::const_iterator it(queries_.begin()); it != queries_.end(); ++it) {
|
||||
std::copy(it->dname().begin(), it->dname().end(), buffer);
|
||||
buffer += it->dname().size();
|
||||
*buffer++ = 0;
|
||||
*((uint16_t*)buffer) = it->type();
|
||||
buffer += sizeof(uint16_t);
|
||||
*((uint16_t*)buffer) = it->query_class();
|
||||
buffer += sizeof(uint16_t);
|
||||
}
|
||||
buffer = serialize_list(ans, buffer);
|
||||
buffer = serialize_list(arity, buffer);
|
||||
buffer = serialize_list(addit, buffer);
|
||||
std::copy(records_data.begin(), records_data.end(), buffer);
|
||||
}
|
||||
|
||||
uint8_t *DNS::serialize_list(const ResourcesType &lst, uint8_t *buffer) const {
|
||||
for(ResourcesType::const_iterator it(lst.begin()); it != lst.end(); ++it)
|
||||
buffer += it->write(buffer);
|
||||
return buffer;
|
||||
// Optimization. Creating an IPv4Address and then using IPv4Address::to_string
|
||||
// was quite slow. The output buffer should be able to hold an IPv4 address.
|
||||
void DNS::inline_convert_v4(uint32_t value, char *output) {
|
||||
output += sprintf(
|
||||
output,
|
||||
"%d.%d.%d.%d",
|
||||
value & 0xff,
|
||||
(value >> 8) & 0xff,
|
||||
(value >> 16) & 0xff,
|
||||
(value >> 24) & 0xff
|
||||
);
|
||||
*output = 0;
|
||||
}
|
||||
|
||||
void DNS::add_suffix(uint32_t index, const uint8_t *data, uint32_t sz) const {
|
||||
uint32_t i(0), suff_sz(data[0]);
|
||||
SuffixMap::iterator it;
|
||||
while((i + suff_sz + 1 <= sz || (suff_sz == 0xc0 && i + 1 < sz)) && suff_sz) {
|
||||
if((suff_sz & 0xc0)) {
|
||||
if((it = suffixes.find(data[i+1])) != suffixes.end())
|
||||
suffix_indices[index + i] = data[i+1];
|
||||
i += sizeof(uint16_t);
|
||||
}
|
||||
else {
|
||||
++i;
|
||||
suffixes.insert(std::make_pair(index + i - 1, string(data + i, data + i + suff_sz)));
|
||||
i += suff_sz;
|
||||
}
|
||||
if(i < sz)
|
||||
suff_sz = data[i];
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t DNS::build_suffix_map(uint32_t index, const ResourcesType &lst) const {
|
||||
const string *str;
|
||||
for(ResourcesType::const_iterator it(lst.begin()); it != lst.end(); ++it) {
|
||||
str = it->has_domain_name() ? it->dname() : 0;
|
||||
if(str) {
|
||||
add_suffix(index, (uint8_t*)str->c_str(), str->size());
|
||||
index += str->size() + 1;
|
||||
}
|
||||
else
|
||||
index += sizeof(uint16_t);
|
||||
index += sizeof(DNSResourceRecord::info) + sizeof(uint16_t);
|
||||
uint32_t sz(it->data_size());
|
||||
const uint8_t *ptr = it->data_ptr();
|
||||
if(Endian::be_to_host(it->information().type) == MX) {
|
||||
ptr += 2;
|
||||
sz -= 2;
|
||||
index += 2;
|
||||
}
|
||||
if(contains_dname(it->information().type))
|
||||
add_suffix(index, ptr, sz);
|
||||
index += sz;
|
||||
}
|
||||
return index;
|
||||
}
|
||||
|
||||
uint32_t DNS::build_suffix_map(uint32_t index, const list<Query> &lst) const {
|
||||
for(list<Query>::const_iterator it(lst.begin()); it != lst.end(); ++it) {
|
||||
add_suffix(index, (uint8_t*)it->dname().c_str(), it->dname().size());
|
||||
index += it->dname().size() + 1 + (sizeof(uint16_t) << 1);
|
||||
}
|
||||
return index;
|
||||
}
|
||||
|
||||
void DNS::build_suffix_map() const {
|
||||
uint32_t index(sizeof(dnshdr));
|
||||
index = build_suffix_map(index, queries_);
|
||||
index = build_suffix_map(index, ans);
|
||||
index = build_suffix_map(index, arity);
|
||||
build_suffix_map(index, addit);
|
||||
}
|
||||
|
||||
void DNS::compose_name(const uint8_t *ptr, uint32_t sz, std::string &out) const {
|
||||
uint32_t i(0);
|
||||
while(i < sz) {
|
||||
if(i && ptr[i])
|
||||
out.push_back('.');
|
||||
if((ptr[i] & 0xc0)) {
|
||||
uint16_t index = Endian::be_to_host(*((uint16_t*)(ptr + i)));
|
||||
index &= 0x3fff;
|
||||
SuffixMap::iterator it(suffixes.find(index));
|
||||
SuffixIndices::iterator suff_it(suffix_indices.find(index));
|
||||
// We need at least a suffix or a suffix index to compose
|
||||
// the domain name
|
||||
if(it == suffixes.end() && suff_it == suffix_indices.end())
|
||||
throw malformed_packet();
|
||||
bool first(true);
|
||||
do {
|
||||
if(it != suffixes.end()) {
|
||||
if(!first)
|
||||
out.push_back('.');
|
||||
first = false;
|
||||
out += it->second;
|
||||
index += it->second.size() + 1;
|
||||
}
|
||||
else
|
||||
index = suff_it->second;
|
||||
it = suffixes.find(index);
|
||||
if(it == suffixes.end())
|
||||
suff_it = suffix_indices.find(index);
|
||||
|
||||
} while(it != suffixes.end() || suff_it != suffix_indices.end());
|
||||
break;
|
||||
}
|
||||
else {
|
||||
uint8_t suff_sz(ptr[i]);
|
||||
i++;
|
||||
if(i + suff_sz <= sz)
|
||||
out.append(ptr + i, ptr + i + suff_sz);
|
||||
i += suff_sz;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DNS::convert_resources(const ResourcesType &lst, std::list<Resource> &res) const {
|
||||
if(!suffixes.size())
|
||||
build_suffix_map();
|
||||
const string *str_ptr;
|
||||
const uint8_t *ptr;
|
||||
uint32_t sz;
|
||||
for(ResourcesType::const_iterator it(lst.begin()); it != lst.end(); ++it) {
|
||||
string dname, addr;
|
||||
if(it->has_domain_name() && (str_ptr = it->dname()))
|
||||
compose_name(reinterpret_cast<const uint8_t*>(str_ptr->c_str()), str_ptr->size(), dname);
|
||||
else {
|
||||
uint16_t offset = it->offset();
|
||||
compose_name((uint8_t*)&offset, 2, dname);
|
||||
}
|
||||
ptr = it->data_ptr();
|
||||
sz = it->data_size();
|
||||
uint16_t record_type = Endian::be_to_host(it->information().type);
|
||||
// Parses records in some section.
|
||||
void DNS::convert_records(const uint8_t *ptr, const uint8_t *end, resources_type &res) const {
|
||||
char dname[256], small_addr_buf[256];
|
||||
while(ptr < end) {
|
||||
std::string addr;
|
||||
bool used_small_buffer = false;
|
||||
// Retrieve the record's domain name.
|
||||
ptr = compose_name(ptr, dname);
|
||||
// 3 uint16_t fields: Type + Class + Data size
|
||||
// 1 uint32_t field: TTL
|
||||
if(ptr + sizeof(uint16_t) * 3 + sizeof(uint32_t) > end)
|
||||
throw malformed_packet();
|
||||
// Retrieve the following fields.
|
||||
uint16_t type, qclass, data_size;
|
||||
uint32_t ttl;
|
||||
type = Endian::be_to_host(*(uint16_t*)ptr); // Type
|
||||
ptr += sizeof(uint16_t);
|
||||
qclass = Endian::be_to_host(*(uint16_t*)ptr); // Class
|
||||
ptr += sizeof(uint16_t);
|
||||
ttl = Endian::be_to_host(*(uint32_t*)ptr); // TTL
|
||||
ptr += sizeof(uint32_t);
|
||||
data_size = Endian::be_to_host(*(uint16_t*)ptr); // Data size
|
||||
ptr += sizeof(uint16_t);
|
||||
// Skip the preference field if it's MX
|
||||
if(record_type == MX) {
|
||||
if(type == MX) {
|
||||
if(data_size < 2)
|
||||
throw malformed_packet();
|
||||
ptr += 2;
|
||||
sz -= 2;
|
||||
data_size -= 2;
|
||||
}
|
||||
switch(record_type) {
|
||||
if(ptr + data_size > end)
|
||||
throw malformed_packet();
|
||||
switch(type) {
|
||||
case AAAA:
|
||||
if(sz != 16)
|
||||
if(data_size != 16)
|
||||
throw malformed_packet();
|
||||
addr = IPv6Address(ptr).to_string();
|
||||
break;
|
||||
case A:
|
||||
if(sz != 4)
|
||||
if(data_size != 4)
|
||||
throw malformed_packet();
|
||||
addr = IPv4Address(*(uint32_t*)ptr).to_string();
|
||||
inline_convert_v4(*(uint32_t*)ptr, small_addr_buf);
|
||||
used_small_buffer = true;
|
||||
break;
|
||||
case NS:
|
||||
case CNAME:
|
||||
case DNAM:
|
||||
case PTR:
|
||||
case MX:
|
||||
compose_name(ptr, sz, addr);
|
||||
compose_name(ptr, small_addr_buf);
|
||||
used_small_buffer = true;
|
||||
break;
|
||||
default:
|
||||
addr.assign(ptr, ptr + sz);
|
||||
if(data_size <= 256) {
|
||||
std::copy(
|
||||
ptr,
|
||||
ptr + data_size,
|
||||
small_addr_buf
|
||||
);
|
||||
used_small_buffer = true;
|
||||
}
|
||||
else
|
||||
addr.assign(ptr, ptr + data_size);
|
||||
break;
|
||||
}
|
||||
ptr += data_size;
|
||||
res.push_back(
|
||||
Resource(dname, addr, record_type,
|
||||
Endian::host_to_be(it->information().qclass),
|
||||
Endian::be_to_host(it->information().ttl)
|
||||
Resource(
|
||||
dname,
|
||||
(used_small_buffer) ? small_addr_buf : addr,
|
||||
type,
|
||||
qclass,
|
||||
ttl
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// no length checks, records should already be valid
|
||||
uint8_t *DNS::update_dname(uint8_t *ptr, uint32_t threshold, uint32_t offset) {
|
||||
while(*ptr != 0) {
|
||||
if((*ptr & 0xc0)) {
|
||||
uint16_t index = Endian::be_to_host(*(uint16_t*)ptr) & 0x3fff;
|
||||
if(index > threshold) {
|
||||
*(uint16_t*)ptr = Endian::host_to_be<uint16_t>((index + offset) | 0xc000);
|
||||
}
|
||||
ptr += sizeof(uint16_t);
|
||||
break;
|
||||
}
|
||||
else {
|
||||
ptr += *ptr + 1;
|
||||
}
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
|
||||
// Updates offsets in domain names inside records.
|
||||
// No length checks, records are already valid.
|
||||
void DNS::update_records(uint32_t §ion_start, uint32_t num_records, uint32_t threshold, uint32_t offset) {
|
||||
uint8_t *ptr = &records_data[section_start];
|
||||
for(uint32_t i = 0; i < num_records; ++i) {
|
||||
ptr = update_dname(ptr, threshold, offset);
|
||||
uint16_t type = Endian::be_to_host(*(const uint16_t*)ptr);
|
||||
ptr += sizeof(uint16_t) * 2 + sizeof(uint32_t);
|
||||
uint16_t size = Endian::be_to_host(*(uint16_t*)ptr);
|
||||
ptr += sizeof(uint16_t);
|
||||
if(type == MX) {
|
||||
ptr += sizeof(uint16_t);
|
||||
size -= sizeof(uint16_t);
|
||||
}
|
||||
if(contains_dname(type)) {
|
||||
update_dname(ptr, threshold, offset);
|
||||
}
|
||||
ptr += size;
|
||||
}
|
||||
section_start += offset;
|
||||
}
|
||||
|
||||
DNS::queries_type DNS::queries() const {
|
||||
queries_type output;
|
||||
for(std::list<Query>::const_iterator it(queries_.begin()); it != queries_.end(); ++it) {
|
||||
string dn;
|
||||
unparse_domain_name(it->dname(), dn);
|
||||
const uint8_t *ptr = &records_data[0], *end = &records_data[answers_idx];
|
||||
char buffer[256];
|
||||
while(ptr < end) {
|
||||
ptr = compose_name(ptr, buffer);
|
||||
if(ptr + sizeof(uint16_t) * 2 > end)
|
||||
throw malformed_packet();
|
||||
output.push_back(
|
||||
Query(
|
||||
dn,
|
||||
(QueryType)Endian::be_to_host<uint16_t>(it->type()),
|
||||
(QueryClass)Endian::be_to_host<uint16_t>(it->query_class())
|
||||
buffer,
|
||||
(QueryType)Endian::be_to_host(*(const uint16_t*)ptr),
|
||||
(QueryClass)Endian::be_to_host(*(const uint16_t*)(ptr + 2))
|
||||
)
|
||||
);
|
||||
ptr += sizeof(uint16_t) * 2;
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
DNS::resources_type DNS::answers() const {
|
||||
resources_type res;
|
||||
convert_resources(ans, res);
|
||||
convert_records(
|
||||
&records_data[answers_idx],
|
||||
&records_data[authority_idx],
|
||||
res
|
||||
);
|
||||
return res;
|
||||
}
|
||||
|
||||
DNS::resources_type DNS::authority() const {
|
||||
resources_type res;
|
||||
convert_records(
|
||||
&records_data[authority_idx],
|
||||
&records_data[additional_idx],
|
||||
res
|
||||
);
|
||||
return res;
|
||||
}
|
||||
|
||||
DNS::resources_type DNS::additional() const {
|
||||
resources_type res;
|
||||
convert_records(
|
||||
&records_data[additional_idx],
|
||||
&records_data[records_data.size()],
|
||||
res
|
||||
);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,212 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2012, Matias Fontanini
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following disclaimer
|
||||
* in the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <cstring>
|
||||
#include <stdexcept>
|
||||
#include <memory>
|
||||
#include <typeinfo>
|
||||
#include "dns_record.h"
|
||||
#include "endianness.h"
|
||||
#include "exceptions.h"
|
||||
|
||||
namespace Tins {
|
||||
bool contains_dname(uint16_t type) {
|
||||
type = Endian::be_to_host(type);
|
||||
return type == 1 || type == 2 ||
|
||||
type == 5 || type == 6 ||
|
||||
type == 12 || type == 15 ||
|
||||
type == 28 || type == 41;
|
||||
}
|
||||
|
||||
DNSResourceRecord::DNSResourceRecord(DNSRRImpl *impl,
|
||||
const uint8_t *d, uint16_t len) : impl(impl)
|
||||
{
|
||||
if(d && len)
|
||||
data.assign(d, d + len);
|
||||
}
|
||||
|
||||
DNSResourceRecord::DNSResourceRecord(const uint8_t *buffer, uint32_t size)
|
||||
{
|
||||
const uint8_t *buffer_end = buffer + size;
|
||||
Internals::smart_ptr<DNSRRImpl>::type tmp_impl;
|
||||
if((*buffer & 0xc0)) {
|
||||
uint16_t offset(*reinterpret_cast<const uint16_t*>(buffer));
|
||||
offset = Endian::be_to_host(offset) & 0x3fff;
|
||||
tmp_impl.reset(new OffsetedDNSRRImpl(Endian::host_to_be(offset)));
|
||||
buffer += sizeof(uint16_t);
|
||||
}
|
||||
else {
|
||||
const uint8_t *str_end(buffer);
|
||||
while(str_end < buffer_end && *str_end)
|
||||
str_end++;
|
||||
if(str_end == buffer_end)
|
||||
throw malformed_packet();
|
||||
//str_end++;
|
||||
tmp_impl.reset(new NamedDNSRRImpl(buffer, str_end));
|
||||
buffer = ++str_end;
|
||||
}
|
||||
if(buffer + sizeof(info_) > buffer_end)
|
||||
throw malformed_packet();
|
||||
std::memcpy(&info_, buffer, sizeof(info_));
|
||||
buffer += sizeof(info_);
|
||||
if(buffer + sizeof(uint16_t) > buffer_end)
|
||||
throw malformed_packet();
|
||||
|
||||
// Store the option size.
|
||||
data.resize(
|
||||
Endian::be_to_host(*reinterpret_cast<const uint16_t*>(buffer))
|
||||
);
|
||||
buffer += sizeof(uint16_t);
|
||||
if(buffer + data.size() > buffer_end)
|
||||
throw malformed_packet();
|
||||
if(contains_dname(info_.type) || data.size() != sizeof(uint32_t))
|
||||
std::copy(buffer, buffer + data.size(), data.begin());
|
||||
else if(data.size() == sizeof(uint32_t))
|
||||
*(uint32_t*)&data[0] = *(uint32_t*)buffer;
|
||||
impl = tmp_impl.release();
|
||||
}
|
||||
|
||||
DNSResourceRecord::DNSResourceRecord(const DNSResourceRecord &rhs)
|
||||
: info_(rhs.info_), data(rhs.data), impl(rhs.clone_impl())
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
DNSResourceRecord& DNSResourceRecord::operator=(const DNSResourceRecord &rhs)
|
||||
{
|
||||
delete impl;
|
||||
info_ = rhs.info_;
|
||||
data = rhs.data;
|
||||
impl = rhs.clone_impl();
|
||||
return *this;
|
||||
}
|
||||
|
||||
DNSResourceRecord::~DNSResourceRecord() {
|
||||
delete impl;
|
||||
}
|
||||
|
||||
uint32_t DNSResourceRecord::write(uint8_t *buffer) const {
|
||||
const uint32_t sz(impl ? impl->do_write(buffer) : 0);
|
||||
buffer += sz;
|
||||
std::memcpy(buffer, &info_, sizeof(info_));
|
||||
buffer += sizeof(info_);
|
||||
*((uint16_t*)buffer) = Endian::host_to_be<uint16_t>(data.size());
|
||||
buffer += sizeof(uint16_t);
|
||||
std::copy(data.begin(), data.end(), buffer);
|
||||
return sz + sizeof(info_) + sizeof(uint16_t) + data.size();
|
||||
}
|
||||
|
||||
DNSRRImpl *DNSResourceRecord::clone_impl() const {
|
||||
return impl ? impl->clone() : 0;
|
||||
}
|
||||
|
||||
bool DNSResourceRecord::has_domain_name() const {
|
||||
if(!impl)
|
||||
throw std::bad_cast();
|
||||
return dynamic_cast<NamedDNSRRImpl*>(impl) != 0;
|
||||
}
|
||||
|
||||
const std::string *DNSResourceRecord::dname() const {
|
||||
if(!impl)
|
||||
throw std::bad_cast();
|
||||
return dynamic_cast<NamedDNSRRImpl&>(*impl).dname_pointer();
|
||||
}
|
||||
|
||||
uint16_t DNSResourceRecord::offset() const {
|
||||
return dynamic_cast<OffsetedDNSRRImpl&>(*impl).offset();
|
||||
}
|
||||
|
||||
size_t DNSResourceRecord::impl_size() const {
|
||||
return impl ? impl->size() : 0;
|
||||
}
|
||||
|
||||
uint32_t DNSResourceRecord::size() const {
|
||||
return sizeof(info_) + data.size() + sizeof(uint16_t) + impl_size();
|
||||
}
|
||||
|
||||
bool DNSResourceRecord::matches(const std::string &dname) const {
|
||||
return impl ? impl->matches(dname) : false;
|
||||
}
|
||||
|
||||
// OffsetedRecord
|
||||
|
||||
OffsetedDNSRRImpl::OffsetedDNSRRImpl(uint16_t off)
|
||||
: offset_(off | Endian::host_to_be<uint16_t>(0xc000))
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
uint32_t OffsetedDNSRRImpl::do_write(uint8_t *buffer) const {
|
||||
std::memcpy(buffer, &offset_, sizeof(offset_));
|
||||
return sizeof(offset_);
|
||||
}
|
||||
|
||||
uint32_t OffsetedDNSRRImpl::size() const {
|
||||
return sizeof(offset_);
|
||||
}
|
||||
|
||||
OffsetedDNSRRImpl *OffsetedDNSRRImpl::clone() const {
|
||||
return new OffsetedDNSRRImpl(*this);
|
||||
}
|
||||
|
||||
uint16_t OffsetedDNSRRImpl::offset() const {
|
||||
return offset_;
|
||||
}
|
||||
|
||||
// NamedRecord
|
||||
|
||||
NamedDNSRRImpl::NamedDNSRRImpl(const std::string &nm)
|
||||
: name(nm)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
uint32_t NamedDNSRRImpl::size() const {
|
||||
return name.size() + 1;
|
||||
}
|
||||
|
||||
uint32_t NamedDNSRRImpl::do_write(uint8_t *buffer) const {
|
||||
buffer = std::copy(name.begin(), name.end(), buffer);
|
||||
*buffer = 0;
|
||||
return name.size() + 1;
|
||||
}
|
||||
|
||||
const std::string *NamedDNSRRImpl::dname_pointer() const {
|
||||
return &name;
|
||||
}
|
||||
|
||||
bool NamedDNSRRImpl::matches(const std::string &dname) const {
|
||||
return dname == name;
|
||||
}
|
||||
|
||||
NamedDNSRRImpl *NamedDNSRRImpl::clone() const {
|
||||
return new NamedDNSRRImpl(*this);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -27,9 +27,11 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include "dot11/dot11_assoc.h"
|
||||
#ifdef HAVE_DOT11
|
||||
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
#include "dot11/dot11_assoc.h"
|
||||
|
||||
namespace Tins {
|
||||
/* Diassoc */
|
||||
@@ -246,4 +248,6 @@ uint32_t Dot11ReAssocResponse::write_fixed_parameters(uint8_t *buffer, uint32_t
|
||||
memcpy(buffer, &this->_body, sz);
|
||||
return sz;
|
||||
}
|
||||
} // namespace Tins
|
||||
} // namespace Tins
|
||||
|
||||
#endif // HAVE_DOT11
|
||||
@@ -27,9 +27,11 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include "dot11/dot11_auth.h"
|
||||
#ifdef HAVE_DOT11
|
||||
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
#include "dot11/dot11_auth.h"
|
||||
|
||||
namespace Tins {
|
||||
/* Auth */
|
||||
@@ -120,4 +122,6 @@ uint32_t Dot11Deauthentication::write_fixed_parameters(uint8_t *buffer, uint32_t
|
||||
memcpy(buffer, &this->_body, sz);
|
||||
return sz;
|
||||
}
|
||||
} // namespace Tins
|
||||
} // namespace Tins
|
||||
|
||||
#endif // HAVE_DOT11
|
||||
@@ -27,6 +27,9 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include "dot11/dot11_base.h"
|
||||
|
||||
#ifdef HAVE_DOT11
|
||||
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
@@ -35,7 +38,6 @@
|
||||
#include <utility>
|
||||
#include "macros.h"
|
||||
#include "exceptions.h"
|
||||
#include "dot11/dot11_base.h"
|
||||
|
||||
#ifndef WIN32
|
||||
#if defined(__FreeBSD_kernel__) || defined(BSD) || defined(__APPLE__)
|
||||
@@ -272,4 +274,6 @@ Dot11 *Dot11::from_bytes(const uint8_t *buffer, uint32_t total_sz) {
|
||||
ret = new Dot11(buffer, total_sz);
|
||||
return ret;
|
||||
}
|
||||
} // namespace Tins
|
||||
} // namespace Tins
|
||||
|
||||
#endif // HAVE_DOT11
|
||||
@@ -27,9 +27,11 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include "dot11/dot11_beacon.h"
|
||||
#ifdef HAVE_DOT11
|
||||
|
||||
#include <cstring>
|
||||
#include <cassert>
|
||||
#include "dot11/dot11_beacon.h"
|
||||
|
||||
namespace Tins {
|
||||
/* Dot11Beacon */
|
||||
@@ -76,4 +78,6 @@ uint32_t Dot11Beacon::write_fixed_parameters(uint8_t *buffer, uint32_t total_sz)
|
||||
std::memcpy(buffer, &this->_body, sz);
|
||||
return sz;
|
||||
}
|
||||
} // namespace Tins
|
||||
} // namespace Tins
|
||||
|
||||
#endif // HAVE_DOT11
|
||||
@@ -27,9 +27,11 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include "dot11/dot11_control.h"
|
||||
#ifdef HAVE_DOT11
|
||||
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
#include "dot11/dot11_control.h"
|
||||
|
||||
namespace Tins {
|
||||
/* Dot11Control */
|
||||
@@ -280,4 +282,6 @@ uint32_t Dot11BlockAck::write_ext_header(uint8_t *buffer, uint32_t total_sz) {
|
||||
uint32_t Dot11BlockAck::header_size() const {
|
||||
return Dot11ControlTA::header_size() + sizeof(_start_sequence) + sizeof(_start_sequence) + sizeof(_bitmap);
|
||||
}
|
||||
} // namespace Tins
|
||||
} // namespace Tins
|
||||
|
||||
#endif // HAVE_DOT11
|
||||
@@ -27,9 +27,11 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include "dot11/dot11_data.h"
|
||||
#ifdef HAVE_DOT11
|
||||
|
||||
#include <cstring>
|
||||
#include <cassert>
|
||||
#include "dot11/dot11_data.h"
|
||||
#include "rawpdu.h"
|
||||
#include "snap.h"
|
||||
|
||||
@@ -180,3 +182,5 @@ uint32_t Dot11QoSData::write_fixed_parameters(uint8_t *buffer, uint32_t total_sz
|
||||
return sz;
|
||||
}
|
||||
} // namespace Tins
|
||||
|
||||
#endif // HAVE_DOT11
|
||||
@@ -27,8 +27,10 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <cstring>
|
||||
#include "dot11/dot11_mgmt.h"
|
||||
#ifdef HAVE_DOT11
|
||||
|
||||
#include <cstring>
|
||||
#include "rsn_information.h"
|
||||
|
||||
namespace Tins {
|
||||
@@ -147,7 +149,7 @@ void Dot11ManagementFrame::extended_supported_rates(const rates_type &new_rates)
|
||||
delete[] buffer;
|
||||
}
|
||||
|
||||
void Dot11ManagementFrame::qos_capability(uint8_t new_qos_capability) {
|
||||
void Dot11ManagementFrame::qos_capability(qos_capability_type new_qos_capability) {
|
||||
add_tagged_option(QOS_CAPABILITY, 1, &new_qos_capability);
|
||||
}
|
||||
|
||||
@@ -368,10 +370,7 @@ void Dot11ManagementFrame::vendor_specific(const vendor_specific_type &data) {
|
||||
// Getters
|
||||
|
||||
RSNInformation Dot11ManagementFrame::rsn_information() {
|
||||
const Dot11::option *option = search_option(RSN);
|
||||
if(!option || option->data_size() < (sizeof(uint16_t) << 1) + sizeof(uint32_t))
|
||||
throw option_not_found();
|
||||
return RSNInformation(option->data_ptr(), option->data_size());
|
||||
return search_and_convert<RSNInformation>(RSN);
|
||||
}
|
||||
|
||||
std::string Dot11ManagementFrame::ssid() const {
|
||||
@@ -385,239 +384,91 @@ std::string Dot11ManagementFrame::ssid() const {
|
||||
}
|
||||
|
||||
Dot11ManagementFrame::rates_type Dot11ManagementFrame::supported_rates() const {
|
||||
const Dot11::option *option = search_option(SUPPORTED_RATES);
|
||||
if(!option || option->data_size() == 0)
|
||||
throw option_not_found();
|
||||
return deserialize_rates(option);
|
||||
return search_and_convert<rates_type>(SUPPORTED_RATES);
|
||||
}
|
||||
|
||||
Dot11ManagementFrame::rates_type Dot11ManagementFrame::extended_supported_rates() const {
|
||||
const Dot11::option *option = search_option(EXT_SUPPORTED_RATES);
|
||||
if(!option || option->data_size() == 0)
|
||||
throw option_not_found();
|
||||
return deserialize_rates(option);
|
||||
return search_and_convert<rates_type>(EXT_SUPPORTED_RATES);
|
||||
}
|
||||
|
||||
uint8_t Dot11ManagementFrame::qos_capability() const {
|
||||
const Dot11::option *option = search_option(QOS_CAPABILITY);
|
||||
if(!option || option->data_size() != 1)
|
||||
throw option_not_found();
|
||||
return *option->data_ptr();
|
||||
Dot11ManagementFrame::qos_capability_type Dot11ManagementFrame::qos_capability() const {
|
||||
return search_and_convert<uint8_t>(QOS_CAPABILITY);
|
||||
}
|
||||
|
||||
std::pair<uint8_t, uint8_t> Dot11ManagementFrame::power_capability() const {
|
||||
const Dot11::option *option = search_option(POWER_CAPABILITY);
|
||||
if(!option || option->data_size() != 2)
|
||||
throw option_not_found();
|
||||
return std::make_pair(*option->data_ptr(), *(option->data_ptr() + 1));
|
||||
return search_and_convert<std::pair<uint8_t, uint8_t> >(POWER_CAPABILITY);
|
||||
}
|
||||
|
||||
Dot11ManagementFrame::channels_type Dot11ManagementFrame::supported_channels() const {
|
||||
const Dot11::option *option = search_option(SUPPORTED_CHANNELS);
|
||||
// We need a multiple of two
|
||||
if(!option || ((option->data_size() & 0x1) == 1))
|
||||
throw option_not_found();
|
||||
channels_type output;
|
||||
const uint8_t *ptr = option->data_ptr(), *end = ptr + option->data_size();
|
||||
while(ptr != end) {
|
||||
uint8_t first = *(ptr++);
|
||||
output.push_back(std::make_pair(first, *(ptr++)));
|
||||
}
|
||||
return output;
|
||||
return search_and_convert<channels_type>(SUPPORTED_CHANNELS);
|
||||
}
|
||||
|
||||
Dot11ManagementFrame::request_info_type Dot11ManagementFrame::request_information() const {
|
||||
const Dot11::option *option = search_option(REQUEST_INFORMATION);
|
||||
if(!option || option->data_size() == 0)
|
||||
throw option_not_found();
|
||||
request_info_type output;
|
||||
const uint8_t *ptr = option->data_ptr(), *end = ptr + option->data_size();
|
||||
output.assign(ptr, end);
|
||||
return output;
|
||||
return search_and_convert<request_info_type>(REQUEST_INFORMATION);
|
||||
}
|
||||
|
||||
Dot11ManagementFrame::fh_params_set Dot11ManagementFrame::fh_parameter_set() const {
|
||||
const Dot11::option *option = search_option(FH_SET);
|
||||
if(!option || option->data_size() != 5)
|
||||
throw option_not_found();
|
||||
fh_params_set output;
|
||||
output.dwell_time = Endian::le_to_host(*(uint16_t*)option->data_ptr());
|
||||
output.hop_set = option->data_ptr()[2];
|
||||
output.hop_pattern = option->data_ptr()[3];
|
||||
output.hop_index = option->data_ptr()[4];
|
||||
return output;
|
||||
return search_and_convert<fh_params_set>(FH_SET);
|
||||
}
|
||||
|
||||
uint8_t Dot11ManagementFrame::ds_parameter_set() const {
|
||||
const Dot11::option *option = search_option(DS_SET);
|
||||
if(!option || option->data_size() != sizeof(uint8_t))
|
||||
throw option_not_found();
|
||||
return *option->data_ptr();
|
||||
return search_and_convert<uint8_t>(DS_SET);
|
||||
}
|
||||
|
||||
Dot11ManagementFrame::cf_params_set Dot11ManagementFrame::cf_parameter_set() const {
|
||||
const Dot11::option *option = search_option(CF_SET);
|
||||
if(!option || option->data_size() != 6)
|
||||
throw option_not_found();
|
||||
cf_params_set output;
|
||||
output.cfp_count = *option->data_ptr();
|
||||
output.cfp_period = option->data_ptr()[1];
|
||||
output.cfp_max_duration = Endian::le_to_host(*(uint16_t*)&option->data_ptr()[2]);
|
||||
output.cfp_dur_remaining = Endian::le_to_host(*(uint16_t*)&option->data_ptr()[4]);
|
||||
return output;
|
||||
return search_and_convert<cf_params_set>(CF_SET);
|
||||
}
|
||||
|
||||
uint16_t Dot11ManagementFrame::ibss_parameter_set() const {
|
||||
const Dot11::option *option = search_option(IBSS_SET);
|
||||
if(!option || option->data_size() != sizeof(uint16_t))
|
||||
throw option_not_found();
|
||||
return Endian::le_to_host(*reinterpret_cast<const uint16_t*>(option->data_ptr()));
|
||||
return search_and_convert<uint16_t>(IBSS_SET);
|
||||
}
|
||||
|
||||
Dot11ManagementFrame::ibss_dfs_params Dot11ManagementFrame::ibss_dfs() const {
|
||||
const Dot11::option *option = search_option(IBSS_DFS);
|
||||
if(!option || option->data_size() < ibss_dfs_params::minimum_size)
|
||||
throw option_not_found();
|
||||
ibss_dfs_params output;
|
||||
const uint8_t *ptr = option->data_ptr(), *end = ptr + option->data_size();
|
||||
output.dfs_owner = ptr;
|
||||
ptr += output.dfs_owner.size();
|
||||
output.recovery_interval = *(ptr++);
|
||||
while(ptr != end) {
|
||||
uint8_t first = *(ptr++);
|
||||
if(ptr == end)
|
||||
throw option_not_found();
|
||||
output.channel_map.push_back(std::make_pair(first, *(ptr++)));
|
||||
}
|
||||
return output;
|
||||
return search_and_convert<ibss_dfs_params>(IBSS_DFS);
|
||||
}
|
||||
|
||||
Dot11ManagementFrame::country_params Dot11ManagementFrame::country() const {
|
||||
const Dot11::option *option = search_option(COUNTRY);
|
||||
if(!option || option->data_size() < country_params::minimum_size)
|
||||
throw option_not_found();
|
||||
country_params output;
|
||||
const uint8_t *ptr = option->data_ptr(), *end = ptr + option->data_size();
|
||||
std::copy(ptr, ptr + 3, std::back_inserter(output.country));
|
||||
ptr += output.country.size();
|
||||
while(end - ptr >= 3) {
|
||||
output.first_channel.push_back(*(ptr++));
|
||||
output.number_channels.push_back(*(ptr++));
|
||||
output.max_transmit_power.push_back(*(ptr++));
|
||||
}
|
||||
if(ptr != end)
|
||||
throw option_not_found();
|
||||
return output;
|
||||
return search_and_convert<country_params>(COUNTRY);
|
||||
}
|
||||
|
||||
std::pair<uint8_t, uint8_t> Dot11ManagementFrame::fh_parameters() const {
|
||||
const Dot11::option *option = search_option(HOPPING_PATTERN_PARAMS);
|
||||
if(!option || option->data_size() != sizeof(uint8_t) * 2)
|
||||
throw option_not_found();
|
||||
const uint8_t *ptr = option->data_ptr();
|
||||
uint8_t first = *(ptr++);
|
||||
return std::make_pair(first, *ptr);
|
||||
return search_and_convert<std::pair<uint8_t, uint8_t> >(HOPPING_PATTERN_PARAMS);
|
||||
}
|
||||
|
||||
Dot11ManagementFrame::fh_pattern_type Dot11ManagementFrame::fh_pattern_table() const {
|
||||
const Dot11::option *option = search_option(HOPPING_PATTERN_TABLE);
|
||||
if(!option || option->data_size() < fh_pattern_type::minimum_size)
|
||||
throw option_not_found();
|
||||
fh_pattern_type output;
|
||||
const uint8_t *ptr = option->data_ptr(), *end = ptr + option->data_size();
|
||||
|
||||
output.flag = *(ptr++);
|
||||
output.number_of_sets = *(ptr++);
|
||||
output.modulus = *(ptr++);
|
||||
output.offset = *(ptr++);
|
||||
|
||||
output.random_table.assign(ptr, end);
|
||||
return output;
|
||||
return search_and_convert<fh_pattern_type>(HOPPING_PATTERN_TABLE);
|
||||
}
|
||||
|
||||
uint8_t Dot11ManagementFrame::power_constraint() const {
|
||||
const Dot11::option *option = search_option(POWER_CONSTRAINT);
|
||||
if(!option || option->data_size() != 1)
|
||||
throw option_not_found();
|
||||
return *option->data_ptr();
|
||||
return search_and_convert<uint8_t>(POWER_CONSTRAINT);
|
||||
}
|
||||
|
||||
Dot11ManagementFrame::channel_switch_type Dot11ManagementFrame::channel_switch() const {
|
||||
const Dot11::option *option = search_option(CHANNEL_SWITCH);
|
||||
if(!option || option->data_size() != sizeof(uint8_t) * 3)
|
||||
throw option_not_found();
|
||||
const uint8_t *ptr = option->data_ptr();
|
||||
channel_switch_type output;
|
||||
output.switch_mode = *(ptr++);
|
||||
output.new_channel = *(ptr++);
|
||||
output.switch_count = *(ptr++);
|
||||
return output;
|
||||
return search_and_convert<channel_switch_type>(CHANNEL_SWITCH);
|
||||
}
|
||||
|
||||
Dot11ManagementFrame::quiet_type Dot11ManagementFrame::quiet() const {
|
||||
const Dot11::option *option = search_option(QUIET);
|
||||
if(!option || option->data_size() != (sizeof(uint8_t) * 2 + sizeof(uint16_t) * 2))
|
||||
throw option_not_found();
|
||||
const uint8_t *ptr = option->data_ptr();
|
||||
quiet_type output;
|
||||
|
||||
output.quiet_count = *(ptr++);
|
||||
output.quiet_period = *(ptr++);
|
||||
const uint16_t *ptr_16 = (const uint16_t*)ptr;
|
||||
output.quiet_duration = Endian::le_to_host(*(ptr_16++));
|
||||
output.quiet_offset = Endian::le_to_host(*ptr_16);
|
||||
return output;
|
||||
return search_and_convert<quiet_type>(QUIET);
|
||||
}
|
||||
|
||||
std::pair<uint8_t, uint8_t> Dot11ManagementFrame::tpc_report() const {
|
||||
const Dot11::option *option = search_option(TPC_REPORT);
|
||||
if(!option || option->data_size() != sizeof(uint8_t) * 2)
|
||||
throw option_not_found();
|
||||
const uint8_t *ptr = option->data_ptr();
|
||||
uint8_t first = *(ptr++);
|
||||
return std::make_pair(first, *ptr);
|
||||
return search_and_convert<std::pair<uint8_t, uint8_t> >(TPC_REPORT);
|
||||
}
|
||||
|
||||
uint8_t Dot11ManagementFrame::erp_information() const {
|
||||
const Dot11::option *option = search_option(ERP_INFORMATION);
|
||||
if(!option || option->data_size() != sizeof(uint8_t))
|
||||
throw option_not_found();
|
||||
return *option->data_ptr();
|
||||
return search_and_convert<uint8_t>(ERP_INFORMATION);
|
||||
}
|
||||
|
||||
Dot11ManagementFrame::bss_load_type Dot11ManagementFrame::bss_load() const {
|
||||
const Dot11::option *option = search_option(BSS_LOAD);
|
||||
if(!option || option->data_size() != sizeof(uint8_t) + 2 * sizeof(uint16_t))
|
||||
throw option_not_found();
|
||||
bss_load_type output;
|
||||
|
||||
const uint8_t *ptr = option->data_ptr();
|
||||
output.station_count = Endian::le_to_host(*(uint16_t*)ptr);
|
||||
output.channel_utilization = ptr[2];
|
||||
output.available_capacity = Endian::le_to_host(*(uint16_t*)(ptr + 3));
|
||||
return output;
|
||||
return search_and_convert<bss_load_type>(BSS_LOAD);
|
||||
}
|
||||
|
||||
Dot11ManagementFrame::tim_type Dot11ManagementFrame::tim() const {
|
||||
const Dot11::option *option = search_option(TIM);
|
||||
if(!option || option->data_size() < 4 * sizeof(uint8_t))
|
||||
throw option_not_found();
|
||||
const uint8_t *ptr = option->data_ptr(), *end = ptr + option->data_size();
|
||||
tim_type output;
|
||||
|
||||
output.dtim_count = *(ptr++);
|
||||
output.dtim_period = *(ptr++);
|
||||
output.bitmap_control = *(ptr++);
|
||||
|
||||
output.partial_virtual_bitmap.assign(ptr, end);
|
||||
return output;
|
||||
return search_and_convert<tim_type>(TIM);
|
||||
}
|
||||
|
||||
std::string Dot11ManagementFrame::challenge_text() const {
|
||||
const Dot11::option *option = search_option(CHALLENGE_TEXT);
|
||||
if(!option || option->data_size() == 0)
|
||||
throw option_not_found();
|
||||
return std::string(option->data_ptr(), option->data_ptr() + option->data_size());
|
||||
return search_and_convert<std::string>(CHALLENGE_TEXT);
|
||||
}
|
||||
|
||||
Dot11ManagementFrame::vendor_specific_type Dot11ManagementFrame::vendor_specific() const {
|
||||
@@ -638,4 +489,138 @@ Dot11ManagementFrame::vendor_specific_type
|
||||
);
|
||||
}
|
||||
|
||||
} // namespace Tins
|
||||
// Options
|
||||
|
||||
Dot11ManagementFrame::fh_params_set Dot11ManagementFrame::fh_params_set::from_option(const option &opt)
|
||||
{
|
||||
if(opt.data_size() != 5)
|
||||
throw malformed_option();
|
||||
fh_params_set output;
|
||||
output.dwell_time = Endian::le_to_host(*(uint16_t*)opt.data_ptr());
|
||||
output.hop_set = opt.data_ptr()[2];
|
||||
output.hop_pattern = opt.data_ptr()[3];
|
||||
output.hop_index = opt.data_ptr()[4];
|
||||
return output;
|
||||
}
|
||||
|
||||
Dot11ManagementFrame::cf_params_set Dot11ManagementFrame::cf_params_set::from_option(const option &opt)
|
||||
{
|
||||
if(opt.data_size() != 6)
|
||||
throw malformed_option();
|
||||
cf_params_set output;
|
||||
output.cfp_count = *opt.data_ptr();
|
||||
output.cfp_period = opt.data_ptr()[1];
|
||||
output.cfp_max_duration = Endian::le_to_host(*(uint16_t*)&opt.data_ptr()[2]);
|
||||
output.cfp_dur_remaining = Endian::le_to_host(*(uint16_t*)&opt.data_ptr()[4]);
|
||||
return output;
|
||||
}
|
||||
|
||||
Dot11ManagementFrame::ibss_dfs_params Dot11ManagementFrame::ibss_dfs_params::from_option(const option &opt)
|
||||
{
|
||||
if(opt.data_size() < ibss_dfs_params::minimum_size)
|
||||
throw malformed_option();
|
||||
ibss_dfs_params output;
|
||||
const uint8_t *ptr = opt.data_ptr(), *end = ptr + opt.data_size();
|
||||
output.dfs_owner = ptr;
|
||||
ptr += output.dfs_owner.size();
|
||||
output.recovery_interval = *(ptr++);
|
||||
while(ptr != end) {
|
||||
uint8_t first = *(ptr++);
|
||||
if(ptr == end)
|
||||
throw option_not_found();
|
||||
output.channel_map.push_back(std::make_pair(first, *(ptr++)));
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
Dot11ManagementFrame::country_params Dot11ManagementFrame::country_params::from_option(const option &opt)
|
||||
{
|
||||
if(opt.data_size() < country_params::minimum_size)
|
||||
throw malformed_option();
|
||||
country_params output;
|
||||
const uint8_t *ptr = opt.data_ptr(), *end = ptr + opt.data_size();
|
||||
std::copy(ptr, ptr + 3, std::back_inserter(output.country));
|
||||
ptr += output.country.size();
|
||||
while(end - ptr >= 3) {
|
||||
output.first_channel.push_back(*(ptr++));
|
||||
output.number_channels.push_back(*(ptr++));
|
||||
output.max_transmit_power.push_back(*(ptr++));
|
||||
}
|
||||
if(ptr != end)
|
||||
throw malformed_option();
|
||||
return output;
|
||||
}
|
||||
|
||||
Dot11ManagementFrame::fh_pattern_type Dot11ManagementFrame::fh_pattern_type::from_option(const option &opt)
|
||||
{
|
||||
if(opt.data_size() < fh_pattern_type::minimum_size)
|
||||
throw malformed_option();
|
||||
fh_pattern_type output;
|
||||
const uint8_t *ptr = opt.data_ptr(), *end = ptr + opt.data_size();
|
||||
|
||||
output.flag = *(ptr++);
|
||||
output.number_of_sets = *(ptr++);
|
||||
output.modulus = *(ptr++);
|
||||
output.offset = *(ptr++);
|
||||
|
||||
output.random_table.assign(ptr, end);
|
||||
return output;
|
||||
}
|
||||
|
||||
Dot11ManagementFrame::channel_switch_type Dot11ManagementFrame::channel_switch_type::from_option(const option &opt)
|
||||
{
|
||||
if(opt.data_size() != sizeof(uint8_t) * 3)
|
||||
throw malformed_option();
|
||||
const uint8_t *ptr = opt.data_ptr();
|
||||
channel_switch_type output;
|
||||
output.switch_mode = *(ptr++);
|
||||
output.new_channel = *(ptr++);
|
||||
output.switch_count = *(ptr++);
|
||||
return output;
|
||||
}
|
||||
|
||||
Dot11ManagementFrame::quiet_type Dot11ManagementFrame::quiet_type::from_option(const option &opt)
|
||||
{
|
||||
if(opt.data_size() != (sizeof(uint8_t) * 2 + sizeof(uint16_t) * 2))
|
||||
throw malformed_option();
|
||||
const uint8_t *ptr = opt.data_ptr();
|
||||
quiet_type output;
|
||||
|
||||
output.quiet_count = *(ptr++);
|
||||
output.quiet_period = *(ptr++);
|
||||
const uint16_t *ptr_16 = (const uint16_t*)ptr;
|
||||
output.quiet_duration = Endian::le_to_host(*(ptr_16++));
|
||||
output.quiet_offset = Endian::le_to_host(*ptr_16);
|
||||
return output;
|
||||
}
|
||||
|
||||
Dot11ManagementFrame::bss_load_type Dot11ManagementFrame::bss_load_type::from_option(const option &opt)
|
||||
{
|
||||
if(opt.data_size() != sizeof(uint8_t) + 2 * sizeof(uint16_t))
|
||||
throw malformed_option();
|
||||
bss_load_type output;
|
||||
|
||||
const uint8_t *ptr = opt.data_ptr();
|
||||
output.station_count = Endian::le_to_host(*(uint16_t*)ptr);
|
||||
output.channel_utilization = ptr[2];
|
||||
output.available_capacity = Endian::le_to_host(*(uint16_t*)(ptr + 3));
|
||||
return output;
|
||||
}
|
||||
|
||||
Dot11ManagementFrame::tim_type Dot11ManagementFrame::tim_type::from_option(const option &opt)
|
||||
{
|
||||
if(opt.data_size() < 4 * sizeof(uint8_t))
|
||||
throw malformed_option();
|
||||
const uint8_t *ptr = opt.data_ptr(), *end = ptr + opt.data_size();
|
||||
tim_type output;
|
||||
|
||||
output.dtim_count = *(ptr++);
|
||||
output.dtim_period = *(ptr++);
|
||||
output.bitmap_control = *(ptr++);
|
||||
|
||||
output.partial_virtual_bitmap.assign(ptr, end);
|
||||
return output;
|
||||
}
|
||||
} // namespace Tins
|
||||
|
||||
#endif // HAVE_DOT11
|
||||
|
||||
@@ -27,9 +27,12 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include "dot11/dot11_probe.h"
|
||||
|
||||
#ifdef HAVE_DOT11
|
||||
|
||||
#include <cstring>
|
||||
#include <cassert>
|
||||
#include "dot11/dot11_probe.h"
|
||||
|
||||
namespace Tins {
|
||||
/* Probe Request */
|
||||
@@ -94,4 +97,6 @@ uint32_t Dot11ProbeResponse::write_fixed_parameters(uint8_t *buffer, uint32_t to
|
||||
memcpy(buffer, &this->_body, sz);
|
||||
return sz;
|
||||
}
|
||||
} // namespace Tins
|
||||
} // namespace Tins
|
||||
|
||||
#endif // HAVE_DOT11
|
||||
@@ -28,6 +28,9 @@
|
||||
*/
|
||||
|
||||
#include "handshake_capturer.h"
|
||||
|
||||
#ifdef HAVE_DOT11
|
||||
|
||||
#include "dot11/dot11_data.h"
|
||||
|
||||
namespace Tins {
|
||||
@@ -93,3 +96,5 @@ namespace Tins {
|
||||
return false;
|
||||
}
|
||||
} // namespace Tins;
|
||||
|
||||
#endif // HAVE_DOT11
|
||||
74
src/icmp.cpp
74
src/icmp.cpp
@@ -43,6 +43,7 @@
|
||||
|
||||
namespace Tins {
|
||||
ICMP::ICMP(Flags flag)
|
||||
: _orig_timestamp_or_address_mask(), _recv_timestamp(), _trans_timestamp()
|
||||
{
|
||||
std::memset(&_icmp, 0, sizeof(icmphdr));
|
||||
type(flag);
|
||||
@@ -53,9 +54,28 @@ ICMP::ICMP(const uint8_t *buffer, uint32_t total_sz)
|
||||
if(total_sz < sizeof(icmphdr))
|
||||
throw malformed_packet();
|
||||
std::memcpy(&_icmp, buffer, sizeof(icmphdr));
|
||||
buffer += sizeof(icmphdr);
|
||||
total_sz -= sizeof(icmphdr);
|
||||
if(type() == TIMESTAMP_REQUEST || type() == TIMESTAMP_REPLY) {
|
||||
if(total_sz < sizeof(uint32_t) * 3)
|
||||
throw malformed_packet();
|
||||
const uint32_t *ptr = reinterpret_cast<const uint32_t*>(buffer);
|
||||
original_timestamp(*ptr++);
|
||||
receive_timestamp(*ptr++);
|
||||
transmit_timestamp(*ptr++);
|
||||
total_sz -= sizeof(uint32_t) * 3;
|
||||
buffer += sizeof(uint32_t) * 3;
|
||||
}
|
||||
else if(type() == ADDRESS_MASK_REQUEST || type() == ADDRESS_MASK_REPLY) {
|
||||
if(total_sz < sizeof(uint32_t))
|
||||
throw malformed_packet();
|
||||
const uint32_t *ptr = reinterpret_cast<const uint32_t*>(buffer);
|
||||
address_mask(address_type(*ptr++));
|
||||
total_sz -= sizeof(uint32_t);
|
||||
buffer += sizeof(uint32_t);
|
||||
}
|
||||
if(total_sz)
|
||||
inner_pdu(new RawPDU(buffer + sizeof(icmphdr), total_sz));
|
||||
inner_pdu(new RawPDU(buffer, total_sz));
|
||||
}
|
||||
|
||||
void ICMP::code(uint8_t new_code) {
|
||||
@@ -78,8 +98,8 @@ void ICMP::sequence(uint16_t new_seq) {
|
||||
_icmp.un.echo.sequence = Endian::host_to_be(new_seq);
|
||||
}
|
||||
|
||||
void ICMP::gateway(uint32_t new_gw) {
|
||||
_icmp.un.gateway = Endian::host_to_be(new_gw);
|
||||
void ICMP::gateway(address_type new_gw) {
|
||||
_icmp.un.gateway = Endian::host_to_be(static_cast<uint32_t>(new_gw));
|
||||
}
|
||||
|
||||
void ICMP::mtu(uint16_t new_mtu) {
|
||||
@@ -90,8 +110,29 @@ void ICMP::pointer(uint8_t new_pointer) {
|
||||
_icmp.un.pointer = new_pointer;
|
||||
}
|
||||
|
||||
void ICMP::original_timestamp(uint32_t new_timestamp) {
|
||||
_orig_timestamp_or_address_mask = Endian::host_to_be(new_timestamp);
|
||||
}
|
||||
|
||||
void ICMP::receive_timestamp(uint32_t new_timestamp) {
|
||||
_recv_timestamp = Endian::host_to_be(new_timestamp);
|
||||
}
|
||||
|
||||
void ICMP::transmit_timestamp(uint32_t new_timestamp) {
|
||||
_trans_timestamp = Endian::host_to_be(new_timestamp);
|
||||
}
|
||||
|
||||
void ICMP::address_mask(address_type new_mask) {
|
||||
_orig_timestamp_or_address_mask = Endian::host_to_be(static_cast<uint32_t>(new_mask));
|
||||
}
|
||||
|
||||
uint32_t ICMP::header_size() const {
|
||||
return sizeof(icmphdr);
|
||||
uint32_t extra = 0;
|
||||
if(type() == TIMESTAMP_REQUEST || type() == TIMESTAMP_REPLY)
|
||||
extra = sizeof(uint32_t) * 3;
|
||||
else if(type() == ADDRESS_MASK_REQUEST || type() == ADDRESS_MASK_REPLY)
|
||||
extra = sizeof(uint32_t);
|
||||
return sizeof(icmphdr) + extra;
|
||||
}
|
||||
|
||||
void ICMP::set_echo_request(uint16_t id, uint16_t seq) {
|
||||
@@ -143,7 +184,7 @@ void ICMP::set_source_quench() {
|
||||
type(SOURCE_QUENCH);
|
||||
}
|
||||
|
||||
void ICMP::set_redirect(uint8_t icode, uint32_t address) {
|
||||
void ICMP::set_redirect(uint8_t icode, address_type address) {
|
||||
type(REDIRECT);
|
||||
code(icode);
|
||||
gateway(address);
|
||||
@@ -154,22 +195,35 @@ void ICMP::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *)
|
||||
assert(total_sz >= sizeof(icmphdr));
|
||||
#endif
|
||||
|
||||
if(type() == TIMESTAMP_REQUEST || type() == TIMESTAMP_REPLY) {
|
||||
uint32_t *ptr = reinterpret_cast<uint32_t*>(buffer + sizeof(icmphdr));
|
||||
*ptr++ = original_timestamp();
|
||||
*ptr++ = receive_timestamp();
|
||||
*ptr++ = transmit_timestamp();
|
||||
}
|
||||
else if(type() == ADDRESS_MASK_REQUEST || type() == ADDRESS_MASK_REPLY) {
|
||||
uint32_t *ptr = reinterpret_cast<uint32_t*>(buffer + sizeof(icmphdr));
|
||||
*ptr++ = address_mask();
|
||||
}
|
||||
// checksum calc
|
||||
_icmp.check = 0;
|
||||
|
||||
uint32_t checksum = Utils::do_checksum(buffer + sizeof(icmphdr), buffer + total_sz) +
|
||||
Utils::do_checksum((uint8_t*)&_icmp, ((uint8_t*)&_icmp) + sizeof(icmphdr));
|
||||
memcpy(buffer, &_icmp, sizeof(icmphdr));
|
||||
uint32_t checksum = Utils::do_checksum(buffer, buffer + total_sz);
|
||||
|
||||
while (checksum >> 16)
|
||||
checksum = (checksum & 0xffff) + (checksum >> 16);
|
||||
|
||||
_icmp.check = Endian::host_to_be<uint16_t>(~checksum);
|
||||
memcpy(buffer, &_icmp, sizeof(icmphdr));
|
||||
((icmphdr*)buffer)->check = _icmp.check;
|
||||
}
|
||||
|
||||
bool ICMP::matches_response(const uint8_t *ptr, uint32_t total_sz) const {
|
||||
if(total_sz < sizeof(icmphdr))
|
||||
return false;
|
||||
const icmphdr *icmp_ptr = (const icmphdr*)ptr;
|
||||
if(_icmp.type == ECHO_REQUEST && icmp_ptr->type == ECHO_REPLY) {
|
||||
if((_icmp.type == ECHO_REQUEST && icmp_ptr->type == ECHO_REPLY) ||
|
||||
(_icmp.type == TIMESTAMP_REQUEST && icmp_ptr->type == TIMESTAMP_REPLY) ||
|
||||
(_icmp.type == ADDRESS_MASK_REQUEST && icmp_ptr->type == ADDRESS_MASK_REPLY)) {
|
||||
return icmp_ptr->un.echo.id == _icmp.un.echo.id && icmp_ptr->un.echo.sequence == _icmp.un.echo.sequence;
|
||||
}
|
||||
return false;
|
||||
|
||||
437
src/icmpv6.cpp
437
src/icmpv6.cpp
@@ -225,7 +225,7 @@ void ICMPv6::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *
|
||||
buffer = write_option(*it, buffer);
|
||||
}
|
||||
if(!_header.cksum) {
|
||||
const Tins::IPv6 *ipv6 = dynamic_cast<const Tins::IPv6*>(parent);
|
||||
const Tins::IPv6 *ipv6 = tins_cast<const Tins::IPv6*>(parent);
|
||||
if(ipv6) {
|
||||
uint32_t checksum = Utils::pseudoheader_checksum(
|
||||
ipv6->src_addr(),
|
||||
@@ -294,39 +294,57 @@ void ICMPv6::prefix_info(prefix_info_type info) {
|
||||
);
|
||||
}
|
||||
|
||||
void ICMPv6::redirect_header(PDU::serialization_type data) {
|
||||
// Reserved fields
|
||||
data.insert(data.begin(), 6, 0);
|
||||
// Padding(if necessary)
|
||||
uint8_t padding = 8 - (data.size() + sizeof(uint8_t) * 2) % 8;
|
||||
if(padding == 8)
|
||||
padding = 0;
|
||||
data.insert(data.end(), padding, 0);
|
||||
void ICMPv6::redirect_header(const byte_array& data) {
|
||||
add_option(option(REDIRECT_HEADER, data.begin(), data.end()));
|
||||
}
|
||||
|
||||
void ICMPv6::mtu(uint32_t value) {
|
||||
void ICMPv6::mtu(const mtu_type& value) {
|
||||
uint8_t buffer[sizeof(uint16_t) + sizeof(uint32_t)] = {0};
|
||||
*((uint32_t*)(buffer + sizeof(uint16_t))) = Endian::host_to_be(value);
|
||||
const uint16_t u16_tmp = value.first;
|
||||
const uint32_t u32_tmp = value.second;
|
||||
buffer[0] = u16_tmp >> 8;
|
||||
buffer[1] = u16_tmp & 0xff;
|
||||
|
||||
buffer[2] = u32_tmp >> 24;
|
||||
buffer[3] = u32_tmp >> 16;
|
||||
buffer[4] = u32_tmp >> 8;
|
||||
buffer[5] = u32_tmp & 0xff;
|
||||
add_option(option(MTU, sizeof(buffer), buffer));
|
||||
}
|
||||
|
||||
void ICMPv6::shortcut_limit(uint8_t value) {
|
||||
void ICMPv6::shortcut_limit(const shortcut_limit_type &value) {
|
||||
uint8_t buffer[sizeof(uint16_t) + sizeof(uint32_t)] = {0};
|
||||
buffer[0] = value;
|
||||
const uint32_t u32_tmp = value.reserved2;
|
||||
buffer[0] = value.limit;
|
||||
buffer[1] = value.reserved1;
|
||||
buffer[2] = u32_tmp >> 24;
|
||||
buffer[3] = u32_tmp >> 16;
|
||||
buffer[4] = u32_tmp >> 8;
|
||||
buffer[5] = u32_tmp & 0xff;
|
||||
add_option(option(NBMA_SHORT_LIMIT, sizeof(buffer), buffer));
|
||||
}
|
||||
|
||||
void ICMPv6::new_advert_interval(uint32_t value) {
|
||||
void ICMPv6::new_advert_interval(const new_advert_interval_type &value) {
|
||||
uint8_t buffer[sizeof(uint16_t) + sizeof(uint32_t)] = {0};
|
||||
*((uint32_t*)(buffer + sizeof(uint16_t))) = Endian::host_to_be(value);
|
||||
const uint16_t u16_tmp = value.reserved;
|
||||
const uint32_t u32_tmp = value.interval;
|
||||
buffer[0] = u16_tmp >> 8;
|
||||
buffer[1] = u16_tmp & 0xff;
|
||||
|
||||
buffer[2] = u32_tmp >> 24;
|
||||
buffer[3] = u32_tmp >> 16;
|
||||
buffer[4] = u32_tmp >> 8;
|
||||
buffer[5] = u32_tmp & 0xff;
|
||||
add_option(option(ADVERT_INTERVAL, sizeof(buffer), buffer));
|
||||
}
|
||||
|
||||
void ICMPv6::new_home_agent_info(const new_ha_info_type &value) {
|
||||
if(value.size() != 3)
|
||||
throw malformed_option();
|
||||
uint8_t buffer[sizeof(uint16_t) + sizeof(uint32_t)] = {0};
|
||||
*((uint16_t*)(buffer + sizeof(uint16_t))) = Endian::host_to_be(value.first);
|
||||
*((uint16_t*)(buffer + sizeof(uint16_t) * 2)) = Endian::host_to_be(value.second);
|
||||
*((uint16_t*)(buffer + sizeof(uint16_t))) = Endian::host_to_be(value[0]);
|
||||
*((uint16_t*)(buffer + sizeof(uint16_t))) = Endian::host_to_be(value[1]);
|
||||
*((uint16_t*)(buffer + sizeof(uint16_t) * 2)) = Endian::host_to_be(value[2]);
|
||||
add_option(option(HOME_AGENT_INFO, sizeof(buffer), buffer));
|
||||
}
|
||||
|
||||
@@ -339,10 +357,12 @@ void ICMPv6::target_addr_list(const addr_list_type &value) {
|
||||
}
|
||||
|
||||
void ICMPv6::add_addr_list(uint8_t type, const addr_list_type &value) {
|
||||
typedef addr_list_type::addresses_type::const_iterator iterator;
|
||||
|
||||
std::vector<uint8_t> buffer;
|
||||
buffer.reserve(value.size() + 6);
|
||||
buffer.insert(buffer.end(), 6, 0);
|
||||
for(addr_list_type::const_iterator it(value.begin()); it != value.end(); ++it)
|
||||
buffer.reserve(value.addresses.size() + 6);
|
||||
buffer.insert(buffer.end(), value.reserved, value.reserved + 6);
|
||||
for(iterator it = value.addresses.begin(); it != value.addresses.end(); ++it)
|
||||
buffer.insert(buffer.end(), it->begin(), it->end());
|
||||
add_option(option(type, buffer.begin(), buffer.end()));
|
||||
}
|
||||
@@ -361,10 +381,10 @@ void ICMPv6::rsa_signature(const rsa_sign_type &value) {
|
||||
add_option(option(RSA_SIGN, buffer.begin(), buffer.end()));
|
||||
}
|
||||
|
||||
void ICMPv6::timestamp(uint64_t value) {
|
||||
void ICMPv6::timestamp(const timestamp_type &value) {
|
||||
std::vector<uint8_t> buffer(6 + sizeof(uint64_t));
|
||||
buffer.insert(buffer.begin(), 6, 0);
|
||||
*((uint64_t*)&buffer[6]) = Endian::host_to_be(value);
|
||||
std::copy(value.reserved, value.reserved + 6, buffer.begin());
|
||||
*((uint64_t*)&buffer[6]) = Endian::host_to_be(value.timestamp);
|
||||
add_option(option(TIMESTAMP, buffer.begin(), buffer.end()));
|
||||
}
|
||||
|
||||
@@ -394,8 +414,9 @@ void ICMPv6::link_layer_addr(lladdr_type value) {
|
||||
|
||||
void ICMPv6::naack(const naack_type &value) {
|
||||
uint8_t buffer[6];
|
||||
buffer[0] = value.first;
|
||||
buffer[1] = value.second;
|
||||
buffer[0] = value.code;
|
||||
buffer[1] = value.status;
|
||||
std::copy(value.reserved, value.reserved + 4, buffer + 2);
|
||||
add_option(option(NAACK, buffer, buffer + sizeof(buffer)));
|
||||
}
|
||||
|
||||
@@ -536,72 +557,35 @@ void ICMPv6::dns_search_list(const dns_search_list_type &value) {
|
||||
// ********************************************************************
|
||||
|
||||
ICMPv6::hwaddress_type ICMPv6::source_link_layer_addr() const {
|
||||
const option *opt = search_option(SOURCE_ADDRESS);
|
||||
if(!opt || opt->data_size() != hwaddress_type::address_size)
|
||||
throw option_not_found();
|
||||
return hwaddress_type(opt->data_ptr());
|
||||
return search_and_convert<hwaddress_type>(SOURCE_ADDRESS);
|
||||
}
|
||||
|
||||
ICMPv6::hwaddress_type ICMPv6::target_link_layer_addr() const {
|
||||
const option *opt = search_option(TARGET_ADDRESS);
|
||||
if(!opt || opt->data_size() != hwaddress_type::address_size)
|
||||
throw option_not_found();
|
||||
return hwaddress_type(opt->data_ptr());
|
||||
return search_and_convert<hwaddress_type>(TARGET_ADDRESS);
|
||||
}
|
||||
|
||||
ICMPv6::prefix_info_type ICMPv6::prefix_info() const {
|
||||
const option *opt = search_option(PREFIX_INFO);
|
||||
if(!opt || opt->data_size() != 2 + sizeof(uint32_t) * 3 + ipaddress_type::address_size)
|
||||
throw option_not_found();
|
||||
const uint8_t *ptr = opt->data_ptr();
|
||||
prefix_info_type output;
|
||||
output.prefix_len = *ptr++;
|
||||
output.L = (*ptr >> 7) & 0x1;
|
||||
output.A = (*ptr++ >> 6) & 0x1;
|
||||
output.valid_lifetime = Endian::be_to_host(*(uint32_t*)ptr);
|
||||
ptr += sizeof(uint32_t);
|
||||
output.preferred_lifetime = Endian::be_to_host(*(uint32_t*)ptr);
|
||||
output.prefix = ptr + sizeof(uint32_t) * 2;
|
||||
return output;
|
||||
return search_and_convert<prefix_info_type>(PREFIX_INFO);
|
||||
}
|
||||
|
||||
PDU::serialization_type ICMPv6::redirect_header() const {
|
||||
const option *opt = search_option(REDIRECT_HEADER);
|
||||
if(!opt || opt->data_size() < 6)
|
||||
throw option_not_found();
|
||||
const uint8_t *ptr = opt->data_ptr() + 6;
|
||||
return serialization_type(ptr, ptr + opt->data_size() - 6);
|
||||
byte_array ICMPv6::redirect_header() const {
|
||||
return search_and_convert<PDU::serialization_type>(REDIRECT_HEADER);
|
||||
}
|
||||
|
||||
uint32_t ICMPv6::mtu() const {
|
||||
const option *opt = search_option(MTU);
|
||||
if(!opt || opt->data_size() != sizeof(uint16_t) + sizeof(uint32_t))
|
||||
throw option_not_found();
|
||||
return Endian::be_to_host(*(const uint32_t*)(opt->data_ptr() + sizeof(uint16_t)));
|
||||
ICMPv6::mtu_type ICMPv6::mtu() const {
|
||||
return search_and_convert<mtu_type>(MTU);
|
||||
}
|
||||
|
||||
uint8_t ICMPv6::shortcut_limit() const {
|
||||
const option *opt = search_option(NBMA_SHORT_LIMIT);
|
||||
if(!opt || opt->data_size() != sizeof(uint16_t) + sizeof(uint32_t))
|
||||
throw option_not_found();
|
||||
return *opt->data_ptr();
|
||||
ICMPv6::shortcut_limit_type ICMPv6::shortcut_limit() const {
|
||||
return search_and_convert<shortcut_limit_type>(NBMA_SHORT_LIMIT);
|
||||
}
|
||||
|
||||
uint32_t ICMPv6::new_advert_interval() const {
|
||||
const option *opt = search_option(ADVERT_INTERVAL);
|
||||
if(!opt || opt->data_size() != sizeof(uint16_t) + sizeof(uint32_t))
|
||||
throw option_not_found();
|
||||
return Endian::be_to_host(*(const uint32_t*)(opt->data_ptr() + sizeof(uint16_t)));
|
||||
ICMPv6::new_advert_interval_type ICMPv6::new_advert_interval() const {
|
||||
return search_and_convert<new_advert_interval_type>(ADVERT_INTERVAL);
|
||||
}
|
||||
|
||||
ICMPv6::new_ha_info_type ICMPv6::new_home_agent_info() const {
|
||||
const option *opt = search_option(HOME_AGENT_INFO);
|
||||
if(!opt || opt->data_size() != sizeof(uint16_t) + sizeof(uint32_t))
|
||||
throw option_not_found();
|
||||
return std::make_pair(
|
||||
Endian::be_to_host(*(const uint16_t*)(opt->data_ptr() + sizeof(uint16_t))),
|
||||
Endian::be_to_host(*(const uint16_t*)(opt->data_ptr() + sizeof(uint16_t) * 2))
|
||||
);
|
||||
return search_and_convert<new_ha_info_type>(HOME_AGENT_INFO);
|
||||
}
|
||||
|
||||
ICMPv6::addr_list_type ICMPv6::source_addr_list() const {
|
||||
@@ -613,87 +597,150 @@ ICMPv6::addr_list_type ICMPv6::target_addr_list() const {
|
||||
}
|
||||
|
||||
ICMPv6::addr_list_type ICMPv6::search_addr_list(OptionTypes type) const {
|
||||
const option *opt = search_option(type);
|
||||
if(!opt || opt->data_size() < 6 + ipaddress_type::address_size)
|
||||
throw option_not_found();
|
||||
return search_and_convert<addr_list_type>(type);
|
||||
}
|
||||
|
||||
ICMPv6::rsa_sign_type ICMPv6::rsa_signature() const {
|
||||
return search_and_convert<rsa_sign_type>(RSA_SIGN);
|
||||
}
|
||||
|
||||
ICMPv6::timestamp_type ICMPv6::timestamp() const {
|
||||
return search_and_convert<timestamp_type>(TIMESTAMP);
|
||||
}
|
||||
|
||||
ICMPv6::nonce_type ICMPv6::nonce() const {
|
||||
return search_and_convert<nonce_type>(NONCE);
|
||||
}
|
||||
|
||||
ICMPv6::ip_prefix_type ICMPv6::ip_prefix() const {
|
||||
return search_and_convert<ip_prefix_type>(IP_PREFIX);
|
||||
}
|
||||
|
||||
ICMPv6::lladdr_type ICMPv6::link_layer_addr() const {
|
||||
return search_and_convert<lladdr_type>(LINK_ADDRESS);
|
||||
}
|
||||
|
||||
ICMPv6::naack_type ICMPv6::naack() const {
|
||||
return search_and_convert<naack_type>(NAACK);
|
||||
}
|
||||
|
||||
ICMPv6::map_type ICMPv6::map() const {
|
||||
return search_and_convert<map_type>(MAP);
|
||||
}
|
||||
|
||||
ICMPv6::route_info_type ICMPv6::route_info() const {
|
||||
return search_and_convert<route_info_type>(ROUTE_INFO);
|
||||
}
|
||||
|
||||
ICMPv6::recursive_dns_type ICMPv6::recursive_dns_servers() const {
|
||||
return search_and_convert<recursive_dns_type>(RECURSIVE_DNS_SERV);
|
||||
}
|
||||
|
||||
ICMPv6::handover_key_req_type ICMPv6::handover_key_request() const {
|
||||
return search_and_convert<handover_key_req_type>(HANDOVER_KEY_REQ);
|
||||
}
|
||||
|
||||
ICMPv6::handover_key_reply_type ICMPv6::handover_key_reply() const {
|
||||
return search_and_convert<handover_key_reply_type>(HANDOVER_KEY_REPLY);
|
||||
}
|
||||
|
||||
ICMPv6::handover_assist_info_type ICMPv6::handover_assist_info() const {
|
||||
return search_and_convert<handover_assist_info_type>(HANDOVER_ASSIST_INFO);
|
||||
}
|
||||
|
||||
ICMPv6::mobile_node_id_type ICMPv6::mobile_node_identifier() const {
|
||||
return search_and_convert<mobile_node_id_type>(MOBILE_NODE_ID);
|
||||
}
|
||||
|
||||
ICMPv6::dns_search_list_type ICMPv6::dns_search_list() const {
|
||||
return search_and_convert<dns_search_list_type>(DNS_SEARCH_LIST);
|
||||
}
|
||||
|
||||
// Options stuff
|
||||
|
||||
ICMPv6::addr_list_type ICMPv6::addr_list_type::from_option(const option &opt)
|
||||
{
|
||||
if(opt.data_size() < 6 + ipaddress_type::address_size || (opt.data_size() - 6) % ipaddress_type::address_size != 0)
|
||||
throw malformed_option();
|
||||
addr_list_type output;
|
||||
const uint8_t *ptr = opt->data_ptr() + 6, *end = opt->data_ptr() + opt->data_size();
|
||||
const uint8_t *ptr = opt.data_ptr(), *end = opt.data_ptr() + opt.data_size();
|
||||
std::copy(ptr, ptr + 6, output.reserved);
|
||||
ptr += 6;
|
||||
while(ptr < end) {
|
||||
if(ptr + ipaddress_type::address_size > end)
|
||||
throw option_not_found();
|
||||
output.push_back(ipaddress_type(ptr));
|
||||
ptr += ipaddress_type::address_size;
|
||||
output.addresses.push_back(ICMPv6::ipaddress_type(ptr));
|
||||
ptr += ICMPv6::ipaddress_type::address_size;
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
ICMPv6::rsa_sign_type ICMPv6::rsa_signature() const {
|
||||
const option *opt = search_option(RSA_SIGN);
|
||||
// 2 bytes reserved + at least 1 byte signature.
|
||||
// 16 == sizeof(rsa_sign_type::key_hash), removed the sizeof
|
||||
// expression since gcc 4.2 doesn't like it
|
||||
if(!opt || opt->data_size() < 2 + 16 + 1)
|
||||
throw option_not_found();
|
||||
const uint8_t *ptr = opt->data_ptr() + 2;
|
||||
rsa_sign_type output;
|
||||
std::copy(ptr, ptr + sizeof(output.key_hash), output.key_hash);
|
||||
ptr += sizeof(output.key_hash);
|
||||
output.signature.assign(ptr, opt->data_ptr() + opt->data_size());
|
||||
ICMPv6::naack_type ICMPv6::naack_type::from_option(const option &opt)
|
||||
{
|
||||
if(opt.data_size() != 6)
|
||||
throw malformed_option();
|
||||
return naack_type(*opt.data_ptr(), opt.data_ptr()[1]);
|
||||
}
|
||||
|
||||
ICMPv6::lladdr_type ICMPv6::lladdr_type::from_option(const option &opt)
|
||||
{
|
||||
if(opt.data_size() < 2)
|
||||
throw malformed_option();
|
||||
const uint8_t *ptr = opt.data_ptr();
|
||||
lladdr_type output(*ptr++);
|
||||
output.address.assign(ptr, opt.data_ptr() + opt.data_size());
|
||||
return output;
|
||||
}
|
||||
|
||||
uint64_t ICMPv6::timestamp() const {
|
||||
const option *opt = safe_search_option<std::less>(
|
||||
TIMESTAMP, 6 + sizeof(uint64_t)
|
||||
);
|
||||
return Endian::be_to_host(*(uint64_t*)(opt->data_ptr() + 6));
|
||||
ICMPv6::prefix_info_type ICMPv6::prefix_info_type::from_option(const option &opt)
|
||||
{
|
||||
if(opt.data_size() != 2 + sizeof(uint32_t) * 3 + ICMPv6::ipaddress_type::address_size)
|
||||
throw malformed_option();
|
||||
const uint8_t *ptr = opt.data_ptr();
|
||||
prefix_info_type output;
|
||||
output.prefix_len = *ptr++;
|
||||
output.L = (*ptr >> 7) & 0x1;
|
||||
output.A = (*ptr++ >> 6) & 0x1;
|
||||
output.valid_lifetime = Endian::be_to_host(*(uint32_t*)ptr);
|
||||
ptr += sizeof(uint32_t);
|
||||
output.preferred_lifetime = Endian::be_to_host(*(uint32_t*)ptr);
|
||||
output.prefix = ptr + sizeof(uint32_t) * 2;
|
||||
return output;
|
||||
}
|
||||
|
||||
ICMPv6::nonce_type ICMPv6::nonce() const {
|
||||
const option *opt = safe_search_option<std::equal_to>(
|
||||
NONCE, 0
|
||||
);
|
||||
return nonce_type(opt->data_ptr(), opt->data_ptr() + opt->data_size());
|
||||
ICMPv6::rsa_sign_type ICMPv6::rsa_sign_type::from_option(const option &opt)
|
||||
{
|
||||
// 2 bytes reserved + at least 1 byte signature.
|
||||
// 16 == sizeof(rsa_sign_type::key_hash), removed the sizeof
|
||||
// expression since gcc 4.2 doesn't like it
|
||||
if(opt.data_size() < 2 + 16 + 1)
|
||||
throw malformed_option();
|
||||
const uint8_t *ptr = opt.data_ptr() + 2;
|
||||
rsa_sign_type output;
|
||||
std::copy(ptr, ptr + sizeof(output.key_hash), output.key_hash);
|
||||
ptr += sizeof(output.key_hash);
|
||||
output.signature.assign(ptr, opt.data_ptr() + opt.data_size());
|
||||
return output;
|
||||
}
|
||||
|
||||
ICMPv6::ip_prefix_type ICMPv6::ip_prefix() const {
|
||||
const option *opt = safe_search_option<std::less>(
|
||||
IP_PREFIX, 2
|
||||
);
|
||||
const uint8_t *ptr = opt->data_ptr();
|
||||
ICMPv6::ip_prefix_type ICMPv6::ip_prefix_type::from_option(const option &opt)
|
||||
{
|
||||
// 2 bytes + 4 padding + ipv6 address
|
||||
if(opt.data_size() != 2 + 4 + ICMPv6::ipaddress_type::address_size)
|
||||
throw malformed_option();
|
||||
const uint8_t *ptr = opt.data_ptr();
|
||||
ip_prefix_type output;
|
||||
output.option_code = *ptr++;
|
||||
output.prefix_len = *ptr++;
|
||||
// skip padding
|
||||
ptr += sizeof(uint32_t);
|
||||
output.address = ipaddress_type(ptr);
|
||||
return output;
|
||||
}
|
||||
|
||||
ICMPv6::lladdr_type ICMPv6::link_layer_addr() const {
|
||||
// at least the option_code and 1 byte from the link layer address
|
||||
const option *opt = safe_search_option<std::less>(
|
||||
LINK_ADDRESS, 2
|
||||
);
|
||||
const uint8_t *ptr = opt->data_ptr();
|
||||
lladdr_type output(*ptr++);
|
||||
output.address.assign(ptr, opt->data_ptr() + opt->data_size());
|
||||
output.address = ICMPv6::ipaddress_type(ptr);
|
||||
return output;
|
||||
}
|
||||
|
||||
ICMPv6::naack_type ICMPv6::naack() const {
|
||||
const option *opt = safe_search_option<std::not_equal_to>(
|
||||
NAACK, 6
|
||||
);
|
||||
const uint8_t *ptr = opt->data_ptr();
|
||||
return naack_type(ptr[0], ptr[1]);
|
||||
}
|
||||
|
||||
ICMPv6::map_type ICMPv6::map() const {
|
||||
const option *opt = safe_search_option<std::not_equal_to>(
|
||||
MAP, 2 + sizeof(uint32_t) + ipaddress_type::address_size
|
||||
);
|
||||
const uint8_t *ptr = opt->data_ptr();
|
||||
ICMPv6::map_type ICMPv6::map_type::from_option(const option &opt)
|
||||
{
|
||||
if(opt.data_size() != 2 + sizeof(uint32_t) + ipaddress_type::address_size)
|
||||
throw malformed_option();
|
||||
const uint8_t *ptr = opt.data_ptr();
|
||||
map_type output;
|
||||
output.dist = (*ptr >> 4) & 0x0f;
|
||||
output.pref = *ptr++ & 0x0f;
|
||||
@@ -704,98 +751,98 @@ ICMPv6::map_type ICMPv6::map() const {
|
||||
return output;
|
||||
}
|
||||
|
||||
ICMPv6::route_info_type ICMPv6::route_info() const {
|
||||
const option *opt = safe_search_option<std::less>(
|
||||
ROUTE_INFO, 2 + sizeof(uint32_t)
|
||||
);
|
||||
const uint8_t *ptr = opt->data_ptr();
|
||||
ICMPv6::route_info_type ICMPv6::route_info_type::from_option(const option &opt)
|
||||
{
|
||||
if(opt.data_size() < 2 + sizeof(uint32_t))
|
||||
throw malformed_option();
|
||||
const uint8_t *ptr = opt.data_ptr();
|
||||
route_info_type output;
|
||||
output.prefix_len = *ptr++;
|
||||
output.pref = (*ptr++ >> 3) & 0x3;
|
||||
output.route_lifetime = Endian::be_to_host(*(uint32_t*)ptr);
|
||||
ptr += sizeof(uint32_t);
|
||||
output.prefix.assign(ptr, opt->data_ptr() + opt->data_size());
|
||||
output.prefix.assign(ptr, opt.data_ptr() + opt.data_size());
|
||||
return output;
|
||||
}
|
||||
|
||||
ICMPv6::recursive_dns_type ICMPv6::recursive_dns_servers() const {
|
||||
const option *opt = safe_search_option<std::less>(
|
||||
RECURSIVE_DNS_SERV, 2 + sizeof(uint32_t) + ipaddress_type::address_size
|
||||
);
|
||||
const uint8_t *ptr = opt->data_ptr() + 2, *end = opt->data_ptr() + opt->data_size();
|
||||
ICMPv6::recursive_dns_type ICMPv6::recursive_dns_type::from_option(const option &opt)
|
||||
{
|
||||
if(opt.data_size() < 2 + sizeof(uint32_t) + ICMPv6::ipaddress_type::address_size)
|
||||
throw malformed_option();
|
||||
const uint8_t *ptr = opt.data_ptr() + 2, *end = opt.data_ptr() + opt.data_size();
|
||||
recursive_dns_type output;
|
||||
output.lifetime = Endian::be_to_host(*(uint32_t*)ptr);
|
||||
ptr += sizeof(uint32_t);
|
||||
while(ptr < end) {
|
||||
if(ptr + ipaddress_type::address_size > end)
|
||||
if(ptr + ICMPv6::ipaddress_type::address_size > end)
|
||||
throw option_not_found();
|
||||
output.servers.push_back(ptr);
|
||||
ptr += ipaddress_type::address_size;
|
||||
ptr += ICMPv6::ipaddress_type::address_size;
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
ICMPv6::handover_key_req_type ICMPv6::handover_key_request() const {
|
||||
const option *opt = safe_search_option<std::less>(
|
||||
HANDOVER_KEY_REQ, 2 + sizeof(uint32_t)
|
||||
);
|
||||
const uint8_t *ptr = opt->data_ptr() + 1, *end = opt->data_ptr() + opt->data_size();
|
||||
ICMPv6::handover_key_req_type ICMPv6::handover_key_req_type::from_option(const option &opt)
|
||||
{
|
||||
if(opt.data_size() < 2 + sizeof(uint32_t))
|
||||
throw option_not_found();
|
||||
const uint8_t *ptr = opt.data_ptr() + 1, *end = opt.data_ptr() + opt.data_size();
|
||||
handover_key_req_type output;
|
||||
output.AT = (*ptr++ >> 4) & 0x3;
|
||||
// is there enough size for the indicated padding?
|
||||
if(end - ptr < *opt->data_ptr())
|
||||
throw option_not_found();
|
||||
output.key.assign(ptr, ptr + ((end - ptr) - *opt->data_ptr()));
|
||||
if(end - ptr < *opt.data_ptr())
|
||||
throw malformed_option();
|
||||
output.key.assign(ptr, ptr + ((end - ptr) - *opt.data_ptr()));
|
||||
return output;
|
||||
}
|
||||
|
||||
ICMPv6::handover_key_reply_type ICMPv6::handover_key_reply() const {
|
||||
const option *opt = safe_search_option<std::less>(
|
||||
HANDOVER_KEY_REPLY, 2 + sizeof(uint32_t)
|
||||
);
|
||||
const uint8_t *ptr = opt->data_ptr() + 1, *end = opt->data_ptr() + opt->data_size();
|
||||
ICMPv6::handover_key_reply_type ICMPv6::handover_key_reply_type::from_option(const option &opt)
|
||||
{
|
||||
if(opt.data_size() < 2 + sizeof(uint32_t))
|
||||
throw malformed_option();
|
||||
const uint8_t *ptr = opt.data_ptr() + 1, *end = opt.data_ptr() + opt.data_size();
|
||||
handover_key_reply_type output;
|
||||
output.AT = (*ptr++ >> 4) & 0x3;
|
||||
output.lifetime = Endian::be_to_host(*(uint16_t*)ptr);
|
||||
ptr += sizeof(uint16_t);
|
||||
// is there enough size for the indicated padding?
|
||||
if(end - ptr < *opt->data_ptr())
|
||||
throw option_not_found();
|
||||
output.key.assign(ptr, ptr + ((end - ptr) - *opt->data_ptr()));
|
||||
if(end - ptr < *opt.data_ptr())
|
||||
throw malformed_option();
|
||||
output.key.assign(ptr, ptr + ((end - ptr) - *opt.data_ptr()));
|
||||
return output;
|
||||
}
|
||||
|
||||
ICMPv6::handover_assist_info_type ICMPv6::handover_assist_info() const {
|
||||
const option *opt = safe_search_option<std::less>(
|
||||
HANDOVER_ASSIST_INFO, 2
|
||||
);
|
||||
const uint8_t *ptr = opt->data_ptr(), *end = ptr + opt->data_size();
|
||||
ICMPv6::handover_assist_info_type ICMPv6::handover_assist_info_type::from_option(const option &opt)
|
||||
{
|
||||
if(opt.data_size() < 2)
|
||||
throw malformed_option();
|
||||
const uint8_t *ptr = opt.data_ptr(), *end = ptr + opt.data_size();
|
||||
handover_assist_info_type output;
|
||||
output.option_code = *ptr++;
|
||||
if((end - ptr - 1) < *ptr)
|
||||
throw option_not_found();
|
||||
throw malformed_option();
|
||||
output.hai.assign(ptr + 1, ptr + 1 + *ptr);
|
||||
return output;
|
||||
}
|
||||
|
||||
ICMPv6::mobile_node_id_type ICMPv6::mobile_node_identifier() const {
|
||||
const option *opt = safe_search_option<std::less>(
|
||||
MOBILE_NODE_ID, 2
|
||||
);
|
||||
const uint8_t *ptr = opt->data_ptr(), *end = ptr + opt->data_size();
|
||||
ICMPv6::mobile_node_id_type ICMPv6::mobile_node_id_type::from_option(const option &opt)
|
||||
{
|
||||
if(opt.data_size() < 2)
|
||||
throw malformed_option();
|
||||
const uint8_t *ptr = opt.data_ptr(), *end = ptr + opt.data_size();
|
||||
mobile_node_id_type output;
|
||||
output.option_code = *ptr++;
|
||||
if((end - ptr - 1) < *ptr)
|
||||
throw option_not_found();
|
||||
throw malformed_option();
|
||||
output.mn.assign(ptr + 1, ptr + 1 + *ptr);
|
||||
return output;
|
||||
}
|
||||
|
||||
ICMPv6::dns_search_list_type ICMPv6::dns_search_list() const {
|
||||
const option *opt = safe_search_option<std::less>(
|
||||
DNS_SEARCH_LIST, 2 + sizeof(uint32_t)
|
||||
);
|
||||
const uint8_t *ptr = opt->data_ptr(), *end = ptr + opt->data_size();
|
||||
ICMPv6::dns_search_list_type ICMPv6::dns_search_list_type::from_option(const option &opt)
|
||||
{
|
||||
if(opt.data_size() < 2 + sizeof(uint32_t))
|
||||
throw malformed_option();
|
||||
const uint8_t *ptr = opt.data_ptr(), *end = ptr + opt.data_size();
|
||||
dns_search_list_type output;
|
||||
output.lifetime = Endian::be_to_host(*(uint32_t*)(ptr + 2));
|
||||
ptr += 2 + sizeof(uint32_t);
|
||||
@@ -815,5 +862,35 @@ ICMPv6::dns_search_list_type ICMPv6::dns_search_list() const {
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
ICMPv6::timestamp_type ICMPv6::timestamp_type::from_option(const option &opt)
|
||||
{
|
||||
if(opt.data_size() != 6 + sizeof(uint64_t))
|
||||
throw malformed_option();
|
||||
timestamp_type output(Endian::be_to_host(*(uint64_t*)(opt.data_ptr() + 6)));
|
||||
std::copy(opt.data_ptr(), opt.data_ptr() + 6, output.reserved);
|
||||
return output;
|
||||
}
|
||||
|
||||
ICMPv6::shortcut_limit_type ICMPv6::shortcut_limit_type::from_option(const option &opt)
|
||||
{
|
||||
if(opt.data_size() != 6)
|
||||
throw malformed_option();
|
||||
const uint8_t *ptr = opt.data_ptr();
|
||||
shortcut_limit_type output(*ptr++);
|
||||
output.reserved1 = *ptr++;
|
||||
output.reserved2 = Endian::be_to_host(*(uint32_t*)ptr);
|
||||
return output;
|
||||
}
|
||||
|
||||
ICMPv6::new_advert_interval_type ICMPv6::new_advert_interval_type::from_option(const option &opt)
|
||||
{
|
||||
if(opt.data_size() != 6)
|
||||
throw malformed_option();
|
||||
new_advert_interval_type output;
|
||||
output.reserved = Endian::be_to_host(*(uint16_t*)opt.data_ptr());
|
||||
output.interval = Endian::be_to_host(*(uint32_t*)(opt.data_ptr() + sizeof(uint16_t)));
|
||||
return output;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -34,6 +34,11 @@
|
||||
#include "radiotap.h"
|
||||
#include "dot11/dot11_base.h"
|
||||
#include "ipv6.h"
|
||||
#include "tcp.h"
|
||||
#include "udp.h"
|
||||
#include "ipsec.h"
|
||||
#include "icmp.h"
|
||||
#include "icmpv6.h"
|
||||
#include "arp.h"
|
||||
#include "eapol.h"
|
||||
#include "rawpdu.h"
|
||||
@@ -100,6 +105,34 @@ Tins::PDU *pdu_from_flag(Constants::Ethernet::e flag, const uint8_t *buffer,
|
||||
};
|
||||
}
|
||||
|
||||
Tins::PDU *pdu_from_flag(Constants::IP::e flag, const uint8_t *buffer,
|
||||
uint32_t size, bool rawpdu_on_no_match)
|
||||
{
|
||||
switch(flag) {
|
||||
case Constants::IP::PROTO_IPIP:
|
||||
return new Tins::TCP(buffer, size);
|
||||
case Constants::IP::PROTO_TCP:
|
||||
return new Tins::TCP(buffer, size);
|
||||
case Constants::IP::PROTO_UDP:
|
||||
return new Tins::UDP(buffer, size);
|
||||
case Constants::IP::PROTO_ICMP:
|
||||
return new Tins::ICMP(buffer, size);
|
||||
case Constants::IP::PROTO_ICMPV6:
|
||||
return new Tins::ICMPv6(buffer, size);
|
||||
case Constants::IP::PROTO_IPV6:
|
||||
return new Tins::IPv6(buffer, size);
|
||||
case Constants::IP::PROTO_AH:
|
||||
return new Tins::IPSecAH(buffer, size);
|
||||
case Constants::IP::PROTO_ESP:
|
||||
return new Tins::IPSecESP(buffer, size);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if(rawpdu_on_no_match)
|
||||
return new Tins::RawPDU(buffer, size);
|
||||
return 0;
|
||||
}
|
||||
|
||||
Tins::PDU *pdu_from_flag(PDU::PDUType type, const uint8_t *buffer, uint32_t size)
|
||||
{
|
||||
switch(type) {
|
||||
@@ -113,33 +146,35 @@ Tins::PDU *pdu_from_flag(PDU::PDUType type, const uint8_t *buffer, uint32_t size
|
||||
return new Tins::ARP(buffer, size);
|
||||
case Tins::PDU::IEEE802_3:
|
||||
return new Tins::IEEE802_3(buffer, size);
|
||||
case Tins::PDU::RADIOTAP:
|
||||
return new Tins::RadioTap(buffer, size);
|
||||
case Tins::PDU::PPPOE:
|
||||
return new Tins::PPPoE(buffer, size);
|
||||
case Tins::PDU::DOT11:
|
||||
case Tins::PDU::DOT11_ACK:
|
||||
case Tins::PDU::DOT11_ASSOC_REQ:
|
||||
case Tins::PDU::DOT11_ASSOC_RESP:
|
||||
case Tins::PDU::DOT11_AUTH:
|
||||
case Tins::PDU::DOT11_BEACON:
|
||||
case Tins::PDU::DOT11_BLOCK_ACK:
|
||||
case Tins::PDU::DOT11_BLOCK_ACK_REQ:
|
||||
case Tins::PDU::DOT11_CF_END:
|
||||
case Tins::PDU::DOT11_DATA:
|
||||
case Tins::PDU::DOT11_CONTROL:
|
||||
case Tins::PDU::DOT11_DEAUTH:
|
||||
case Tins::PDU::DOT11_DIASSOC:
|
||||
case Tins::PDU::DOT11_END_CF_ACK:
|
||||
case Tins::PDU::DOT11_MANAGEMENT:
|
||||
case Tins::PDU::DOT11_PROBE_REQ:
|
||||
case Tins::PDU::DOT11_PROBE_RESP:
|
||||
case Tins::PDU::DOT11_PS_POLL:
|
||||
case Tins::PDU::DOT11_REASSOC_REQ:
|
||||
case Tins::PDU::DOT11_REASSOC_RESP:
|
||||
case Tins::PDU::DOT11_RTS:
|
||||
case Tins::PDU::DOT11_QOS_DATA:
|
||||
return Tins::Dot11::from_bytes(buffer, size);
|
||||
#ifdef HAVE_DOT11
|
||||
case Tins::PDU::RADIOTAP:
|
||||
return new Tins::RadioTap(buffer, size);
|
||||
case Tins::PDU::DOT11:
|
||||
case Tins::PDU::DOT11_ACK:
|
||||
case Tins::PDU::DOT11_ASSOC_REQ:
|
||||
case Tins::PDU::DOT11_ASSOC_RESP:
|
||||
case Tins::PDU::DOT11_AUTH:
|
||||
case Tins::PDU::DOT11_BEACON:
|
||||
case Tins::PDU::DOT11_BLOCK_ACK:
|
||||
case Tins::PDU::DOT11_BLOCK_ACK_REQ:
|
||||
case Tins::PDU::DOT11_CF_END:
|
||||
case Tins::PDU::DOT11_DATA:
|
||||
case Tins::PDU::DOT11_CONTROL:
|
||||
case Tins::PDU::DOT11_DEAUTH:
|
||||
case Tins::PDU::DOT11_DIASSOC:
|
||||
case Tins::PDU::DOT11_END_CF_ACK:
|
||||
case Tins::PDU::DOT11_MANAGEMENT:
|
||||
case Tins::PDU::DOT11_PROBE_REQ:
|
||||
case Tins::PDU::DOT11_PROBE_RESP:
|
||||
case Tins::PDU::DOT11_PS_POLL:
|
||||
case Tins::PDU::DOT11_REASSOC_REQ:
|
||||
case Tins::PDU::DOT11_REASSOC_RESP:
|
||||
case Tins::PDU::DOT11_RTS:
|
||||
case Tins::PDU::DOT11_QOS_DATA:
|
||||
return Tins::Dot11::from_bytes(buffer, size);
|
||||
#endif // HAVE_DOT11
|
||||
default:
|
||||
return 0;
|
||||
};
|
||||
@@ -166,6 +201,27 @@ Constants::Ethernet::e pdu_flag_to_ether_type(PDU::PDUType flag) {
|
||||
}
|
||||
}
|
||||
|
||||
Constants::IP::e pdu_flag_to_ip_type(PDU::PDUType flag) {
|
||||
switch(flag) {
|
||||
case PDU::IP:
|
||||
return Constants::IP::PROTO_IPIP;
|
||||
case PDU::TCP:
|
||||
return Constants::IP::PROTO_TCP;
|
||||
case PDU::UDP:
|
||||
return Constants::IP::PROTO_UDP;
|
||||
case PDU::ICMP:
|
||||
return Constants::IP::PROTO_ICMP;
|
||||
case PDU::ICMPv6:
|
||||
return Constants::IP::PROTO_ICMPV6;
|
||||
case PDU::IPSEC_AH:
|
||||
return Constants::IP::PROTO_AH;
|
||||
case PDU::IPSEC_ESP:
|
||||
return Constants::IP::PROTO_ESP;
|
||||
default:
|
||||
return static_cast<Constants::IP::e>(0xff);
|
||||
};
|
||||
}
|
||||
|
||||
bool increment(IPv4Address &addr) {
|
||||
uint32_t addr_int = Endian::be_to_host<uint32_t>(addr);
|
||||
bool reached_end = ++addr_int == 0xffffffff;
|
||||
|
||||
154
src/ip.cpp
154
src/ip.cpp
@@ -42,10 +42,6 @@
|
||||
#include <winsock2.h>
|
||||
#endif
|
||||
#include "ip.h"
|
||||
#include "ipv6.h"
|
||||
#include "tcp.h"
|
||||
#include "udp.h"
|
||||
#include "icmp.h"
|
||||
#include "rawpdu.h"
|
||||
#include "utils.h"
|
||||
#include "packet_sender.h"
|
||||
@@ -121,20 +117,17 @@ IP::IP(const uint8_t *buffer, uint32_t total_sz)
|
||||
throw malformed_packet();
|
||||
total_sz -= head_len() * sizeof(uint32_t);
|
||||
if (total_sz) {
|
||||
switch(_ip.protocol) {
|
||||
case Constants::IP::PROTO_TCP:
|
||||
inner_pdu(new Tins::TCP(buffer, total_sz));
|
||||
break;
|
||||
case Constants::IP::PROTO_UDP:
|
||||
inner_pdu(new Tins::UDP(buffer, total_sz));
|
||||
break;
|
||||
case Constants::IP::PROTO_ICMP:
|
||||
inner_pdu(new Tins::ICMP(buffer, total_sz));
|
||||
break;
|
||||
case Constants::IP::PROTO_IPV6:
|
||||
inner_pdu(new Tins::IPv6(buffer, total_sz));
|
||||
break;
|
||||
default:
|
||||
// Don't try to decode it if it's fragmented
|
||||
if(!is_fragmented()) {
|
||||
inner_pdu(
|
||||
Internals::pdu_from_flag(
|
||||
static_cast<Constants::IP::e>(_ip.protocol),
|
||||
buffer,
|
||||
total_sz,
|
||||
false
|
||||
)
|
||||
);
|
||||
if(!inner_pdu()) {
|
||||
inner_pdu(
|
||||
Internals::allocate<IP>(
|
||||
_ip.protocol,
|
||||
@@ -144,7 +137,11 @@ IP::IP(const uint8_t *buffer, uint32_t total_sz)
|
||||
);
|
||||
if(!inner_pdu())
|
||||
inner_pdu(new RawPDU(buffer, total_sz));
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// It's fragmented, just use RawPDU
|
||||
inner_pdu(new RawPDU(buffer, total_sz));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -158,6 +155,12 @@ void IP::init_ip_fields() {
|
||||
_padded_options_size = 0;
|
||||
}
|
||||
|
||||
bool IP::is_fragmented() const {
|
||||
// It's 0 if offset == 0 && more_frag == 0
|
||||
// It's 0x4000 if dont_fragment = 1
|
||||
return frag_off() != 0 && frag_off() != 0x4000;
|
||||
}
|
||||
|
||||
/* Setters */
|
||||
|
||||
void IP::tos(uint8_t new_tos) {
|
||||
@@ -268,40 +271,24 @@ void IP::add_route_option(option_identifier id, const generic_route_option_type
|
||||
}
|
||||
|
||||
IP::generic_route_option_type IP::search_route_option(option_identifier id) const {
|
||||
const option *option = search_option(id);
|
||||
if(!option || option->data_size() < 1 + sizeof(uint32_t) ||
|
||||
((option->data_size() - 1) % sizeof(uint32_t)) != 0)
|
||||
const option *opt = search_option(id);
|
||||
if(!opt)
|
||||
throw option_not_found();
|
||||
generic_route_option_type output;
|
||||
output.pointer = *option->data_ptr();
|
||||
const uint32_t *route = (const uint32_t*)(option->data_ptr() + 1),
|
||||
*end = route + (option->data_size() - 1) / sizeof(uint32_t);
|
||||
while(route < end)
|
||||
output.routes.push_back(address_type(*route++));
|
||||
return output;
|
||||
return opt->to<generic_route_option_type>();
|
||||
}
|
||||
|
||||
IP::security_type IP::security() const {
|
||||
const option *option = search_option(130);
|
||||
if(!option || option->data_size() < 9)
|
||||
const option *opt = search_option(130);
|
||||
if(!opt)
|
||||
throw option_not_found();
|
||||
security_type output;
|
||||
const uint16_t *ptr = reinterpret_cast<const uint16_t*>(option->data_ptr());
|
||||
output.security = Endian::be_to_host(*ptr++);
|
||||
output.compartments = Endian::be_to_host(*ptr++);
|
||||
output.handling_restrictions = Endian::be_to_host(*ptr++);
|
||||
uint32_t tcc = option->data_ptr()[6];
|
||||
tcc = (tcc << 8) | option->data_ptr()[7];
|
||||
tcc = (tcc << 8) | option->data_ptr()[8];
|
||||
output.transmission_control = tcc;
|
||||
return output;
|
||||
return opt->to<security_type>();
|
||||
}
|
||||
|
||||
uint16_t IP::stream_identifier() const {
|
||||
const option *option = search_option(136);
|
||||
if(!option || option->data_size() != sizeof(uint16_t))
|
||||
const option *opt = search_option(136);
|
||||
if(!opt)
|
||||
throw option_not_found();
|
||||
return Endian::be_to_host(*(const uint16_t*)option->data_ptr());
|
||||
return opt->to<uint16_t>();
|
||||
}
|
||||
|
||||
void IP::add_option(const option &opt) {
|
||||
@@ -391,31 +378,14 @@ void IP::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU* pare
|
||||
#endif
|
||||
checksum(0);
|
||||
if(inner_pdu()) {
|
||||
uint32_t new_flag;
|
||||
switch(inner_pdu()->pdu_type()) {
|
||||
case PDU::IP:
|
||||
new_flag = Constants::IP::PROTO_IPIP;
|
||||
break;
|
||||
case PDU::TCP:
|
||||
new_flag = Constants::IP::PROTO_TCP;
|
||||
break;
|
||||
case PDU::UDP:
|
||||
new_flag = Constants::IP::PROTO_UDP;
|
||||
break;
|
||||
case PDU::ICMP:
|
||||
new_flag = Constants::IP::PROTO_ICMP;
|
||||
break;
|
||||
default:
|
||||
if(Internals::pdu_type_registered<IP>(inner_pdu()->pdu_type()))
|
||||
new_flag = static_cast<Constants::IP::e>(
|
||||
Internals::pdu_type_to_id<IP>(inner_pdu()->pdu_type())
|
||||
);
|
||||
else
|
||||
// check for other protos
|
||||
new_flag = 0xff;
|
||||
};
|
||||
protocol(new_flag);
|
||||
//flag(new_flag);
|
||||
uint32_t new_flag = Internals::pdu_flag_to_ip_type(inner_pdu()->pdu_type());
|
||||
if(new_flag == 0xff && Internals::pdu_type_registered<IP>(inner_pdu()->pdu_type())) {
|
||||
new_flag = static_cast<Constants::IP::e>(
|
||||
Internals::pdu_type_to_id<IP>(inner_pdu()->pdu_type())
|
||||
);
|
||||
}
|
||||
if(!is_fragmented() || new_flag != 0xff)
|
||||
protocol(new_flag);
|
||||
}
|
||||
|
||||
#if __FreeBSD__ || defined(__FreeBSD_kernel__)
|
||||
@@ -446,6 +416,20 @@ bool IP::matches_response(const uint8_t *ptr, uint32_t total_sz) const {
|
||||
if(total_sz < sizeof(iphdr))
|
||||
return false;
|
||||
const iphdr *ip_ptr = (const iphdr*)ptr;
|
||||
// dest unreachable?
|
||||
if(ip_ptr->protocol == Constants::IP::PROTO_ICMP) {
|
||||
const uint8_t *pkt_ptr = ptr + sizeof(iphdr);
|
||||
uint32_t pkt_sz = total_sz - sizeof(iphdr);
|
||||
// It's an ICMP dest unreachable
|
||||
if(pkt_sz > 4 && pkt_ptr[0] == 3) {
|
||||
pkt_ptr += 4;
|
||||
pkt_sz -= 4;
|
||||
// If our IP header is in the ICMP payload, then it's the same packet.
|
||||
// This keeps in mind checksum and IP identifier, so I guess it's enough.
|
||||
if(pkt_sz >= sizeof(iphdr) && std::memcmp(&_ip, pkt_ptr, sizeof(iphdr)))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
// checks for broadcast addr
|
||||
if((_ip.saddr == ip_ptr->daddr && (_ip.daddr == ip_ptr->saddr || dst_addr().is_broadcast())) ||
|
||||
(dst_addr().is_broadcast() && _ip.saddr == 0)) {
|
||||
@@ -454,4 +438,36 @@ bool IP::matches_response(const uint8_t *ptr, uint32_t total_sz) const {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Option static constructors from options
|
||||
|
||||
IP::security_type IP::security_type::from_option(const option &opt)
|
||||
{
|
||||
if(opt.data_size() != 9)
|
||||
throw malformed_option();
|
||||
security_type output;
|
||||
const uint16_t *ptr = reinterpret_cast<const uint16_t*>(opt.data_ptr());
|
||||
output.security = Endian::be_to_host(*ptr++);
|
||||
output.compartments = Endian::be_to_host(*ptr++);
|
||||
output.handling_restrictions = Endian::be_to_host(*ptr++);
|
||||
uint32_t tcc = opt.data_ptr()[6];
|
||||
tcc = (tcc << 8) | opt.data_ptr()[7];
|
||||
tcc = (tcc << 8) | opt.data_ptr()[8];
|
||||
output.transmission_control = tcc;
|
||||
return output;
|
||||
}
|
||||
|
||||
IP::generic_route_option_type IP::generic_route_option_type::from_option(
|
||||
const option &opt)
|
||||
{
|
||||
if(opt.data_size() < 1 + sizeof(uint32_t) || ((opt.data_size() - 1) % sizeof(uint32_t)) != 0)
|
||||
throw malformed_option();
|
||||
generic_route_option_type output;
|
||||
output.pointer = *opt.data_ptr();
|
||||
const uint32_t *route = (const uint32_t*)(opt.data_ptr() + 1),
|
||||
*end = route + (opt.data_size() - 1) / sizeof(uint32_t);
|
||||
while(route < end)
|
||||
output.routes.push_back(address_type(*route++));
|
||||
return output;
|
||||
}
|
||||
}
|
||||
|
||||
153
src/ip_reassembler.cpp
Normal file
153
src/ip_reassembler.cpp
Normal file
@@ -0,0 +1,153 @@
|
||||
/*
|
||||
* Copyright (c) 2012, Matias Fontanini
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following disclaimer
|
||||
* in the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "ip.h"
|
||||
#include "rawpdu.h"
|
||||
#include "constants.h"
|
||||
#include "internals.h"
|
||||
#include "ip_reassembler.h"
|
||||
|
||||
namespace Tins {
|
||||
namespace Internals {
|
||||
IPv4Stream::IPv4Stream()
|
||||
: received_end(false), received_size(), total_size()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void IPv4Stream::add_fragment(IP *ip) {
|
||||
fragments_type::iterator it = fragments.begin();
|
||||
uint16_t offset = extract_offset(ip);
|
||||
while(it != fragments.end() && offset > it->offset()) {
|
||||
++it;
|
||||
}
|
||||
// No duplicates plx
|
||||
if(it != fragments.end() && it->offset() == offset)
|
||||
return;
|
||||
fragments.insert(it, IPv4Fragment(ip->inner_pdu(), offset));
|
||||
received_size += ip->inner_pdu()->size();
|
||||
if(!extract_more_frag(ip)) {
|
||||
total_size = offset + ip->inner_pdu()->size();
|
||||
received_end = true;
|
||||
}
|
||||
if(offset == 0)
|
||||
transport_proto = ip->protocol();
|
||||
}
|
||||
|
||||
bool IPv4Stream::is_complete() const {
|
||||
return received_end && received_size == total_size;
|
||||
}
|
||||
|
||||
PDU *IPv4Stream::allocate_pdu() const {
|
||||
PDU::serialization_type buffer;
|
||||
buffer.reserve(total_size);
|
||||
// Check if we actually have all the data we need. Otherwise return nullptr;
|
||||
uint16_t expected = 0;
|
||||
for(fragments_type::const_iterator it = fragments.begin(); it != fragments.end(); ++it) {
|
||||
if(expected != it->offset())
|
||||
return 0;
|
||||
expected = it->offset() + it->payload().size();
|
||||
buffer.insert(buffer.end(), it->payload().begin(), it->payload().end());
|
||||
}
|
||||
return Internals::pdu_from_flag(
|
||||
static_cast<Constants::IP::e>(transport_proto),
|
||||
&buffer[0],
|
||||
buffer.size()
|
||||
);
|
||||
}
|
||||
|
||||
uint16_t IPv4Stream::extract_offset(const IP *ip) {
|
||||
return (ip->frag_off() & 0x1fff) * 8;
|
||||
}
|
||||
|
||||
bool IPv4Stream::extract_more_frag(const IP *ip) {
|
||||
return ip->frag_off() & 0x2000;
|
||||
}
|
||||
} // namespace Internals
|
||||
|
||||
IPv4Reassembler::IPv4Reassembler(overlapping_technique technique)
|
||||
: technique(technique)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
IPv4Reassembler::packet_status IPv4Reassembler::process(PDU &pdu) {
|
||||
IP *ip = pdu.find_pdu<IP>();
|
||||
if(ip && ip->inner_pdu()) {
|
||||
// There's fragmentation
|
||||
if(ip->is_fragmented()) {
|
||||
// Create it or look it up, it's the same
|
||||
Internals::IPv4Stream &stream = streams[make_key(ip)];
|
||||
stream.add_fragment(ip);
|
||||
if(stream.is_complete()) {
|
||||
PDU *pdu = stream.allocate_pdu();
|
||||
// The packet is corrupt
|
||||
if(!pdu) {
|
||||
streams.erase(make_key(ip));
|
||||
return FRAGMENTED;
|
||||
}
|
||||
ip->inner_pdu(pdu);
|
||||
ip->frag_off(0);
|
||||
return REASSEMBLED;
|
||||
}
|
||||
else
|
||||
return FRAGMENTED;
|
||||
}
|
||||
}
|
||||
return NOT_FRAGMENTED;
|
||||
}
|
||||
|
||||
IPv4Reassembler::key_type IPv4Reassembler::make_key(const IP *ip) const {
|
||||
return std::make_pair(
|
||||
ip->id(),
|
||||
make_address_pair(ip->src_addr(), ip->dst_addr())
|
||||
);
|
||||
}
|
||||
|
||||
IPv4Reassembler::address_pair IPv4Reassembler::make_address_pair(IPv4Address addr1, IPv4Address addr2) const {
|
||||
if(addr1 < addr2)
|
||||
return std::make_pair(addr1, addr2);
|
||||
else
|
||||
return std::make_pair(addr2, addr1);
|
||||
}
|
||||
|
||||
void IPv4Reassembler::clear_streams() {
|
||||
streams.clear();
|
||||
}
|
||||
|
||||
void IPv4Reassembler::remove_stream(uint16_t id, IPv4Address addr1, IPv4Address addr2) {
|
||||
streams.erase(
|
||||
std::make_pair(
|
||||
id,
|
||||
make_address_pair(addr1, addr2)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
} // namespace Tins
|
||||
135
src/ipsec.cpp
Normal file
135
src/ipsec.cpp
Normal file
@@ -0,0 +1,135 @@
|
||||
/*
|
||||
* Copyright (c) 2012, Matias Fontanini
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following disclaimer
|
||||
* in the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <cstring>
|
||||
#include "ipsec.h"
|
||||
#include "internals.h"
|
||||
#include "rawpdu.h"
|
||||
|
||||
namespace Tins {
|
||||
|
||||
IPSecAH::IPSecAH()
|
||||
: _header(), _icv(4) {
|
||||
length(2);
|
||||
}
|
||||
|
||||
IPSecAH::IPSecAH(const uint8_t *buffer, uint32_t total_sz) {
|
||||
// At least size for the header + 32bits of ICV
|
||||
if(total_sz < sizeof(_header) + sizeof(uint32_t))
|
||||
throw malformed_packet();
|
||||
std::memcpy(&_header, buffer, sizeof(_header));
|
||||
const uint32_t ah_len = 4 * (static_cast<uint16_t>(length()) + 2);
|
||||
if(ah_len > total_sz)
|
||||
throw malformed_packet();
|
||||
_icv.assign(buffer + sizeof(_header), buffer + ah_len);
|
||||
buffer += ah_len;
|
||||
total_sz -= ah_len;
|
||||
if(total_sz) {
|
||||
inner_pdu(
|
||||
Internals::pdu_from_flag(
|
||||
static_cast<Constants::IP::e>(next_header()),
|
||||
buffer,
|
||||
total_sz,
|
||||
true
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void IPSecAH::next_header(uint8_t new_next_header) {
|
||||
_header.next_header = new_next_header;
|
||||
}
|
||||
|
||||
void IPSecAH::length(uint8_t new_length) {
|
||||
_header.length = new_length;
|
||||
}
|
||||
|
||||
void IPSecAH::spi(uint32_t new_spi) {
|
||||
_header.spi = Endian::host_to_be(new_spi);
|
||||
}
|
||||
|
||||
void IPSecAH::seq_number(uint32_t new_seq_number) {
|
||||
_header.seq_number = Endian::host_to_be(new_seq_number);
|
||||
}
|
||||
|
||||
void IPSecAH::icv(const byte_array &new_icv) {
|
||||
_icv = new_icv;
|
||||
}
|
||||
|
||||
uint32_t IPSecAH::header_size() const {
|
||||
return sizeof(_header) + _icv.size();
|
||||
}
|
||||
|
||||
void IPSecAH::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *) {
|
||||
if(inner_pdu())
|
||||
next_header(Internals::pdu_flag_to_ip_type(inner_pdu()->pdu_type()));
|
||||
std::memcpy(buffer, &_header, sizeof(_header));
|
||||
std::copy(
|
||||
_icv.begin(),
|
||||
_icv.end(),
|
||||
buffer + sizeof(_header)
|
||||
);
|
||||
}
|
||||
|
||||
// IPSecESP
|
||||
|
||||
IPSecESP::IPSecESP()
|
||||
: _header()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
IPSecESP::IPSecESP(const uint8_t *buffer, uint32_t total_sz) {
|
||||
if(total_sz < sizeof(_header))
|
||||
throw malformed_packet();
|
||||
std::memcpy(&_header, buffer, sizeof(_header));
|
||||
buffer += sizeof(_header);
|
||||
total_sz -= sizeof(_header);
|
||||
if(total_sz) {
|
||||
inner_pdu(new RawPDU(buffer, total_sz));
|
||||
}
|
||||
}
|
||||
|
||||
void IPSecESP::spi(uint32_t new_spi) {
|
||||
_header.spi = Endian::host_to_be(new_spi);
|
||||
}
|
||||
|
||||
void IPSecESP::seq_number(uint32_t new_seq_number) {
|
||||
_header.seq_number = Endian::host_to_be(new_seq_number);
|
||||
}
|
||||
|
||||
uint32_t IPSecESP::header_size() const {
|
||||
return sizeof(_header);
|
||||
}
|
||||
|
||||
void IPSecESP::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *) {
|
||||
std::memcpy(buffer, &_header, sizeof(_header));
|
||||
}
|
||||
|
||||
}
|
||||
78
src/ipv6.cpp
78
src/ipv6.cpp
@@ -41,14 +41,10 @@
|
||||
#include "ipv6.h"
|
||||
#include "constants.h"
|
||||
#include "packet_sender.h"
|
||||
#include "ip.h"
|
||||
#include "tcp.h"
|
||||
#include "udp.h"
|
||||
#include "icmp.h"
|
||||
#include "icmpv6.h"
|
||||
#include "rawpdu.h"
|
||||
#include "exceptions.h"
|
||||
#include "pdu_allocator.h"
|
||||
#include "internals.h"
|
||||
|
||||
namespace Tins {
|
||||
|
||||
@@ -88,30 +84,24 @@ IPv6::IPv6(const uint8_t *buffer, uint32_t total_sz)
|
||||
total_sz -= size;
|
||||
}
|
||||
else {
|
||||
switch(current_header) {
|
||||
case Constants::IP::PROTO_TCP:
|
||||
inner_pdu(new Tins::TCP(buffer, total_sz));
|
||||
break;
|
||||
case Constants::IP::PROTO_UDP:
|
||||
inner_pdu(new Tins::UDP(buffer, total_sz));
|
||||
break;
|
||||
case Constants::IP::PROTO_ICMP:
|
||||
inner_pdu(new Tins::ICMP(buffer, total_sz));
|
||||
break;
|
||||
case Constants::IP::PROTO_ICMPV6:
|
||||
inner_pdu(new Tins::ICMPv6(buffer, total_sz));
|
||||
break;
|
||||
default:
|
||||
inner_pdu(
|
||||
Internals::allocate<IPv6>(
|
||||
current_header,
|
||||
buffer,
|
||||
total_sz
|
||||
)
|
||||
);
|
||||
if(!inner_pdu())
|
||||
inner_pdu(new Tins::RawPDU(buffer, total_sz));
|
||||
break;
|
||||
inner_pdu(
|
||||
Internals::pdu_from_flag(
|
||||
static_cast<Constants::IP::e>(current_header),
|
||||
buffer,
|
||||
total_sz,
|
||||
false
|
||||
)
|
||||
);
|
||||
if(!inner_pdu()) {
|
||||
inner_pdu(
|
||||
Internals::allocate<IPv6>(
|
||||
current_header,
|
||||
buffer,
|
||||
total_sz
|
||||
)
|
||||
);
|
||||
if(!inner_pdu())
|
||||
inner_pdu(new Tins::RawPDU(buffer, total_sz));
|
||||
}
|
||||
total_sz = 0;
|
||||
}
|
||||
@@ -205,30 +195,12 @@ void IPv6::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *pa
|
||||
assert(total_sz >= header_size());
|
||||
#endif
|
||||
if(inner_pdu()) {
|
||||
uint8_t new_flag = 0xff;
|
||||
switch(inner_pdu()->pdu_type()) {
|
||||
case PDU::IP:
|
||||
new_flag = Constants::IP::PROTO_IPIP;
|
||||
break;
|
||||
case PDU::TCP:
|
||||
new_flag = Constants::IP::PROTO_TCP;
|
||||
break;
|
||||
case PDU::UDP:
|
||||
new_flag = Constants::IP::PROTO_UDP;
|
||||
break;
|
||||
case PDU::ICMP:
|
||||
new_flag = Constants::IP::PROTO_ICMP;
|
||||
break;
|
||||
case PDU::ICMPv6:
|
||||
new_flag = Constants::IP::PROTO_ICMPV6;
|
||||
break;
|
||||
default:
|
||||
if(Internals::pdu_type_registered<IPv6>(inner_pdu()->pdu_type()))
|
||||
new_flag = static_cast<Constants::IP::e>(
|
||||
Internals::pdu_type_to_id<IPv6>(inner_pdu()->pdu_type())
|
||||
);
|
||||
break;
|
||||
};
|
||||
uint8_t new_flag = Internals::pdu_flag_to_ip_type(inner_pdu()->pdu_type());
|
||||
if(new_flag == 0xff && Internals::pdu_type_registered<IPv6>(inner_pdu()->pdu_type())) {
|
||||
new_flag = static_cast<Constants::IP::e>(
|
||||
Internals::pdu_type_to_id<IPv6>(inner_pdu()->pdu_type())
|
||||
);
|
||||
}
|
||||
set_last_next_header(new_flag);
|
||||
}
|
||||
payload_length(total_sz - sizeof(_header));
|
||||
|
||||
@@ -96,9 +96,9 @@ void Loopback::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU
|
||||
#ifdef TINS_DEBUG
|
||||
assert(total_sz >= sizeof(_family));
|
||||
#endif
|
||||
if(dynamic_cast<const Tins::IP*>(inner_pdu()))
|
||||
if(tins_cast<const Tins::IP*>(inner_pdu()))
|
||||
_family = PF_INET;
|
||||
else if(dynamic_cast<const Tins::LLC*>(inner_pdu()))
|
||||
else if(tins_cast<const Tins::LLC*>(inner_pdu()))
|
||||
_family = PF_LLC;
|
||||
*reinterpret_cast<uint32_t*>(buffer) = _family;
|
||||
}
|
||||
|
||||
@@ -82,16 +82,18 @@ struct InterfaceInfoCollector {
|
||||
#else
|
||||
const struct sockaddr_ll* addr_ptr = ((struct sockaddr_ll*)addr->ifa_addr);
|
||||
|
||||
if(addr->ifa_addr->sa_family == AF_PACKET && addr_ptr->sll_ifindex == iface_id)
|
||||
info->hw_addr = addr_ptr->sll_addr;
|
||||
else if(addr->ifa_addr->sa_family == AF_INET && !std::strcmp(addr->ifa_name, iface_name)) {
|
||||
info->ip_addr = IPv4Address(((struct sockaddr_in *)addr->ifa_addr)->sin_addr.s_addr);
|
||||
info->netmask = IPv4Address(((struct sockaddr_in *)addr->ifa_netmask)->sin_addr.s_addr);
|
||||
if((addr->ifa_flags & (IFF_BROADCAST | IFF_POINTOPOINT)))
|
||||
info->bcast_addr = IPv4Address(((struct sockaddr_in *)addr->ifa_ifu.ifu_broadaddr)->sin_addr.s_addr);
|
||||
else
|
||||
info->bcast_addr = 0;
|
||||
found = true;
|
||||
if(addr->ifa_addr) {
|
||||
if(addr->ifa_addr->sa_family == AF_PACKET && addr_ptr->sll_ifindex == iface_id)
|
||||
info->hw_addr = addr_ptr->sll_addr;
|
||||
else if(addr->ifa_addr->sa_family == AF_INET && !std::strcmp(addr->ifa_name, iface_name)) {
|
||||
info->ip_addr = IPv4Address(((struct sockaddr_in *)addr->ifa_addr)->sin_addr.s_addr);
|
||||
info->netmask = IPv4Address(((struct sockaddr_in *)addr->ifa_netmask)->sin_addr.s_addr);
|
||||
if((addr->ifa_flags & (IFF_BROADCAST | IFF_POINTOPOINT)))
|
||||
info->bcast_addr = IPv4Address(((struct sockaddr_in *)addr->ifa_ifu.ifu_broadaddr)->sin_addr.s_addr);
|
||||
else
|
||||
info->bcast_addr = 0;
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
return found;
|
||||
#endif
|
||||
|
||||
@@ -55,6 +55,7 @@
|
||||
#endif
|
||||
#include <cstring>
|
||||
#include <ctime>
|
||||
#include <algorithm>
|
||||
#include "pdu.h"
|
||||
#include "macros.h"
|
||||
#include "network_interface.h"
|
||||
@@ -235,12 +236,14 @@ void PacketSender::send(PDU &pdu, const NetworkInterface &iface) {
|
||||
case PDU::ETHERNET_II:
|
||||
send<Tins::EthernetII>(pdu, iface);
|
||||
break;
|
||||
case PDU::DOT11:
|
||||
send<Tins::Dot11>(pdu, iface);
|
||||
break;
|
||||
case PDU::RADIOTAP:
|
||||
send<Tins::RadioTap>(pdu, iface);
|
||||
break;
|
||||
#ifdef HAVE_DOT11
|
||||
case PDU::DOT11:
|
||||
send<Tins::Dot11>(pdu, iface);
|
||||
break;
|
||||
case PDU::RADIOTAP:
|
||||
send<Tins::RadioTap>(pdu, iface);
|
||||
break;
|
||||
#endif // HAVE_DOT11
|
||||
case PDU::IEEE802_3:
|
||||
send<Tins::IEEE802_3>(pdu, iface);
|
||||
break;
|
||||
@@ -250,7 +253,7 @@ void PacketSender::send(PDU &pdu, const NetworkInterface &iface) {
|
||||
}
|
||||
|
||||
PDU *PacketSender::send_recv(PDU &pdu) {
|
||||
return send_recv(pdu, NetworkInterface());
|
||||
return send_recv(pdu, default_iface);
|
||||
}
|
||||
|
||||
PDU *PacketSender::send_recv(PDU &pdu, const NetworkInterface &iface) {
|
||||
@@ -283,13 +286,19 @@ PDU *PacketSender::recv_l2(PDU &pdu, struct sockaddr *link_addr,
|
||||
uint32_t len_addr, const NetworkInterface &iface)
|
||||
{
|
||||
int sock = get_ether_socket(iface);
|
||||
return recv_match_loop(sock, pdu, link_addr, len_addr);
|
||||
std::vector<int> sockets(1, sock);
|
||||
return recv_match_loop(sockets, pdu, link_addr, len_addr);
|
||||
}
|
||||
#endif // WIN32
|
||||
|
||||
PDU *PacketSender::recv_l3(PDU &pdu, struct sockaddr* link_addr, uint32_t len_addr, SocketType type) {
|
||||
open_l3_socket(type);
|
||||
return recv_match_loop(_sockets[type], pdu, link_addr, len_addr);
|
||||
std::vector<int> sockets(1, _sockets[type]);
|
||||
if(type == IP_TCP_SOCKET || type == IP_UDP_SOCKET) {
|
||||
open_l3_socket(ICMP_SOCKET);
|
||||
sockets.push_back(_sockets[ICMP_SOCKET]);
|
||||
}
|
||||
return recv_match_loop(sockets, pdu, link_addr, len_addr);
|
||||
}
|
||||
|
||||
void PacketSender::send_l3(PDU &pdu, struct sockaddr* link_addr, uint32_t len_addr, SocketType type) {
|
||||
@@ -300,7 +309,14 @@ void PacketSender::send_l3(PDU &pdu, struct sockaddr* link_addr, uint32_t len_ad
|
||||
throw socket_write_error(make_error_string());
|
||||
}
|
||||
|
||||
PDU *PacketSender::recv_match_loop(int sock, PDU &pdu, struct sockaddr* link_addr, uint32_t addrlen) {
|
||||
PDU *PacketSender::recv_match_loop(const std::vector<int>& sockets, PDU &pdu, struct sockaddr* link_addr, uint32_t addrlen) {
|
||||
#ifdef WIN32
|
||||
typedef int socket_len_type;
|
||||
typedef int recvfrom_ret_type;
|
||||
#else
|
||||
typedef socklen_t socket_len_type;
|
||||
typedef ssize_t recvfrom_ret_type;
|
||||
#endif
|
||||
fd_set readfds;
|
||||
struct timeval timeout, end_time;
|
||||
int read;
|
||||
@@ -310,21 +326,21 @@ PDU *PacketSender::recv_match_loop(int sock, PDU &pdu, struct sockaddr* link_add
|
||||
end_time.tv_usec = timeout.tv_usec = _timeout_usec;
|
||||
while(true) {
|
||||
FD_ZERO(&readfds);
|
||||
FD_SET(sock, &readfds);
|
||||
if((read = select(sock + 1, &readfds, 0, 0, &timeout)) == -1) {
|
||||
return 0;
|
||||
int max_fd = 0;
|
||||
for(std::vector<int>::const_iterator it = sockets.begin(); it != sockets.end(); ++it) {
|
||||
FD_SET(*it, &readfds);
|
||||
max_fd = std::max(max_fd, *it);
|
||||
}
|
||||
if(FD_ISSET(sock, &readfds)) {
|
||||
#ifdef WIN32
|
||||
int length = addrlen;
|
||||
int size;
|
||||
#else
|
||||
socklen_t length = addrlen;
|
||||
ssize_t size;
|
||||
#endif
|
||||
size = recvfrom(sock, (char*)buffer, 2048, 0, link_addr, &length);
|
||||
if(pdu.matches_response(buffer, size)) {
|
||||
return Internals::pdu_from_flag(pdu.pdu_type(), buffer, size);
|
||||
if((read = select(max_fd + 1, &readfds, 0, 0, &timeout)) == -1)
|
||||
return 0;
|
||||
for(std::vector<int>::const_iterator it = sockets.begin(); it != sockets.end(); ++it) {
|
||||
if(FD_ISSET(*it, &readfds)) {
|
||||
socket_len_type length = addrlen;
|
||||
recvfrom_ret_type size;
|
||||
size = recvfrom(*it, (char*)buffer, 2048, 0, link_addr, &length);
|
||||
if(pdu.matches_response(buffer, size)) {
|
||||
return Internals::pdu_from_flag(pdu.pdu_type(), buffer, size);
|
||||
}
|
||||
}
|
||||
}
|
||||
struct timeval this_time, diff;
|
||||
|
||||
13
src/ppi.cpp
13
src/ppi.cpp
@@ -41,6 +41,7 @@
|
||||
#include "sll.h"
|
||||
#include "ppi.h"
|
||||
#include "internals.h"
|
||||
#include "exceptions.h"
|
||||
|
||||
namespace Tins {
|
||||
PPI::PPI(const uint8_t *buffer, uint32_t total_sz) {
|
||||
@@ -61,7 +62,11 @@ PPI::PPI(const uint8_t *buffer, uint32_t total_sz) {
|
||||
if(total_sz > 0) {
|
||||
switch(dlt()) {
|
||||
case DLT_IEEE802_11:
|
||||
inner_pdu(Dot11::from_bytes(buffer, total_sz));
|
||||
#ifdef HAVE_DOT11
|
||||
inner_pdu(Dot11::from_bytes(buffer, total_sz));
|
||||
#else
|
||||
throw protocol_disabled();
|
||||
#endif
|
||||
break;
|
||||
case DLT_EN10MB:
|
||||
if(Internals::is_dot3(buffer, total_sz))
|
||||
@@ -70,7 +75,11 @@ PPI::PPI(const uint8_t *buffer, uint32_t total_sz) {
|
||||
inner_pdu(new EthernetII(buffer, total_sz));
|
||||
break;
|
||||
case DLT_IEEE802_11_RADIO:
|
||||
inner_pdu(new RadioTap(buffer, total_sz));
|
||||
#ifdef HAVE_DOT11
|
||||
inner_pdu(new RadioTap(buffer, total_sz));
|
||||
#else
|
||||
throw protocol_disabled();
|
||||
#endif
|
||||
break;
|
||||
case DLT_NULL:
|
||||
inner_pdu(new Loopback(buffer, total_sz));
|
||||
|
||||
@@ -192,48 +192,54 @@ void PPPoE::generic_error(const std::string &value) {
|
||||
// *********************** Getters *************************
|
||||
|
||||
std::string PPPoE::service_name() const {
|
||||
return retrieve_tag_iterable<std::string>(SERVICE_NAME);
|
||||
return search_and_convert<std::string>(SERVICE_NAME);
|
||||
}
|
||||
|
||||
std::string PPPoE::ac_name() const {
|
||||
return retrieve_tag_iterable<std::string>(AC_NAME);
|
||||
return search_and_convert<std::string>(AC_NAME);
|
||||
}
|
||||
|
||||
byte_array PPPoE::host_uniq() const {
|
||||
return retrieve_tag_iterable<byte_array>(HOST_UNIQ);
|
||||
return search_and_convert<byte_array>(HOST_UNIQ);
|
||||
}
|
||||
|
||||
byte_array PPPoE::ac_cookie() const {
|
||||
return retrieve_tag_iterable<byte_array>(AC_COOKIE);
|
||||
return search_and_convert<byte_array>(AC_COOKIE);
|
||||
}
|
||||
|
||||
PPPoE::vendor_spec_type PPPoE::vendor_specific() const {
|
||||
const tag *tag = safe_search_tag<std::less>(
|
||||
VENDOR_SPECIFIC, sizeof(uint32_t)
|
||||
);
|
||||
vendor_spec_type output;
|
||||
output.vendor_id = Endian::be_to_host(*(const uint32_t*)tag->data_ptr());
|
||||
output.data.assign(
|
||||
tag->data_ptr() + sizeof(uint32_t),
|
||||
tag->data_ptr() + tag->data_size()
|
||||
);
|
||||
return output;
|
||||
const tag *t = search_tag(VENDOR_SPECIFIC);
|
||||
if(!t)
|
||||
throw option_not_found();
|
||||
return t->to<vendor_spec_type>();
|
||||
}
|
||||
|
||||
byte_array PPPoE::relay_session_id() const {
|
||||
return retrieve_tag_iterable<byte_array>(RELAY_SESSION_ID);
|
||||
return search_and_convert<byte_array>(RELAY_SESSION_ID);
|
||||
}
|
||||
|
||||
std::string PPPoE::service_name_error() const {
|
||||
return retrieve_tag_iterable<std::string>(SERVICE_NAME_ERROR);
|
||||
return search_and_convert<std::string>(SERVICE_NAME_ERROR);
|
||||
}
|
||||
|
||||
std::string PPPoE::ac_system_error() const {
|
||||
return retrieve_tag_iterable<std::string>(AC_SYSTEM_ERROR);
|
||||
return search_and_convert<std::string>(AC_SYSTEM_ERROR);
|
||||
}
|
||||
|
||||
std::string PPPoE::generic_error() const {
|
||||
return retrieve_tag_iterable<std::string>(GENERIC_ERROR);
|
||||
return search_and_convert<std::string>(GENERIC_ERROR);
|
||||
}
|
||||
|
||||
PPPoE::vendor_spec_type PPPoE::vendor_spec_type::from_option(const tag &opt) {
|
||||
if(opt.data_size() < sizeof(uint32_t))
|
||||
throw malformed_option();
|
||||
vendor_spec_type output;
|
||||
output.vendor_id = Endian::be_to_host(*(const uint32_t*)opt.data_ptr());
|
||||
output.data.assign(
|
||||
opt.data_ptr() + sizeof(uint32_t),
|
||||
opt.data_ptr() + opt.data_size()
|
||||
);
|
||||
return output;
|
||||
}
|
||||
} //namespace Tins
|
||||
|
||||
|
||||
@@ -27,6 +27,10 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include "radiotap.h"
|
||||
|
||||
#ifdef HAVE_DOT11
|
||||
|
||||
#include <cstring>
|
||||
#ifdef TINS_DEBUG
|
||||
#include <cassert>
|
||||
@@ -41,7 +45,6 @@
|
||||
#endif
|
||||
#include <net/ethernet.h>
|
||||
#endif
|
||||
#include "radiotap.h"
|
||||
#include "dot11/dot11_base.h"
|
||||
#include "utils.h"
|
||||
#include "packet_sender.h"
|
||||
@@ -276,7 +279,7 @@ void RadioTap::send(PacketSender &sender, const NetworkInterface &iface) {
|
||||
addr.sll_halen = 6;
|
||||
addr.sll_ifindex = iface.id();
|
||||
|
||||
Tins::Dot11 *wlan = dynamic_cast<Tins::Dot11*>(inner_pdu());
|
||||
const Tins::Dot11 *wlan = tins_cast<Tins::Dot11*>(inner_pdu());
|
||||
if(wlan) {
|
||||
Tins::Dot11::address_type dot11_addr(wlan->addr1());
|
||||
std::copy(dot11_addr.begin(), dot11_addr.end(), addr.sll_addr);
|
||||
@@ -385,3 +388,5 @@ void RadioTap::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif // HAVE_DOT11
|
||||
@@ -30,6 +30,7 @@
|
||||
#include <stdexcept>
|
||||
#include "rsn_information.h"
|
||||
#include "exceptions.h"
|
||||
#include "dot11/dot11_base.h"
|
||||
|
||||
namespace Tins {
|
||||
template<typename T>
|
||||
@@ -143,4 +144,10 @@ RSNInformation RSNInformation::wpa2_psk() {
|
||||
info.add_akm_cypher(RSNInformation::PSK);
|
||||
return info;
|
||||
}
|
||||
|
||||
RSNInformation RSNInformation::from_option(const PDUOption<uint8_t, Dot11> &opt) {
|
||||
if(opt.data_size() < sizeof(uint16_t) * 2 + sizeof(uint32_t))
|
||||
throw malformed_option();
|
||||
return RSNInformation(opt.data_ptr(), opt.data_size());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,7 +29,13 @@
|
||||
|
||||
#include <algorithm>
|
||||
#include "sniffer.h"
|
||||
|
||||
#include "dot11/dot11_base.h"
|
||||
#include "ethernetII.h"
|
||||
#include "radiotap.h"
|
||||
#include "loopback.h"
|
||||
#include "dot3.h"
|
||||
#include "sll.h"
|
||||
#include "ppi.h"
|
||||
|
||||
using std::string;
|
||||
using std::runtime_error;
|
||||
@@ -92,6 +98,7 @@ void sniff_loop_eth_handler(u_char *user, const struct pcap_pkthdr *h, const u_c
|
||||
data->pdu = safe_alloc<EthernetII>((const uint8_t*)bytes, h->caplen);
|
||||
}
|
||||
|
||||
#ifdef HAVE_DOT11
|
||||
void sniff_loop_dot11_handler(u_char *user, const struct pcap_pkthdr *h, const u_char *bytes) {
|
||||
sniff_data *data = (sniff_data*)user;
|
||||
data->packet_processed = true;
|
||||
@@ -103,6 +110,7 @@ void sniff_loop_dot11_handler(u_char *user, const struct pcap_pkthdr *h, const u
|
||||
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
PtrPacket BaseSniffer::next_packet() {
|
||||
sniff_data data;
|
||||
@@ -110,10 +118,20 @@ PtrPacket BaseSniffer::next_packet() {
|
||||
pcap_handler handler = 0;
|
||||
if(iface_type == DLT_EN10MB)
|
||||
handler = sniff_loop_eth_handler;
|
||||
else if(iface_type == DLT_IEEE802_11_RADIO)
|
||||
handler = &sniff_loop_handler<RadioTap>;
|
||||
else if(iface_type == DLT_IEEE802_11)
|
||||
handler = sniff_loop_dot11_handler;
|
||||
else if(iface_type == DLT_IEEE802_11_RADIO) {
|
||||
#ifdef HAVE_DOT11
|
||||
handler = &sniff_loop_handler<RadioTap>;
|
||||
#else
|
||||
throw protocol_disabled();
|
||||
#endif
|
||||
}
|
||||
else if(iface_type == DLT_IEEE802_11) {
|
||||
#ifdef HAVE_DOT11
|
||||
handler = sniff_loop_dot11_handler;
|
||||
#else
|
||||
throw protocol_disabled();
|
||||
#endif
|
||||
}
|
||||
else if(iface_type == DLT_LOOP)
|
||||
handler = &sniff_loop_handler<Tins::Loopback>;
|
||||
else if(iface_type == DLT_LINUX_SLL)
|
||||
@@ -160,24 +178,41 @@ bool BaseSniffer::set_filter(const std::string &filter) {
|
||||
return result;
|
||||
}
|
||||
|
||||
void BaseSniffer::set_timeout(int ms) {
|
||||
pcap_set_timeout(handle, ms);
|
||||
}
|
||||
|
||||
// ****************************** Sniffer ******************************
|
||||
|
||||
Sniffer::Sniffer(const string &device, unsigned max_packet_size,
|
||||
bool promisc, const string &filter)
|
||||
{
|
||||
char error[PCAP_ERRBUF_SIZE];
|
||||
init_sniffer(device, max_packet_size, promisc, filter);
|
||||
}
|
||||
|
||||
Sniffer::Sniffer(const std::string &device, promisc_type promisc,
|
||||
const std::string &filter)
|
||||
{
|
||||
init_sniffer(device, 65535, promisc == PROMISC, filter);
|
||||
}
|
||||
|
||||
void Sniffer::init_sniffer(const std::string &device, unsigned max_packet_size,
|
||||
bool promisc, const std::string &filter)
|
||||
{
|
||||
char error[PCAP_ERRBUF_SIZE];
|
||||
bpf_u_int32 ip, if_mask;
|
||||
if (pcap_lookupnet(device.c_str(), &ip, &if_mask, error) == -1) {
|
||||
ip = 0;
|
||||
if_mask = 0;
|
||||
}
|
||||
pcap_t *phandle = pcap_open_live(device.c_str(), max_packet_size, promisc, 0, error);
|
||||
pcap_t *phandle = pcap_open_live(device.c_str(), max_packet_size, promisc, 1000, error);
|
||||
if(!phandle)
|
||||
throw runtime_error(error);
|
||||
|
||||
init(phandle, filter, if_mask);
|
||||
}
|
||||
|
||||
|
||||
// **************************** FileSniffer ****************************
|
||||
|
||||
FileSniffer::FileSniffer(const string &file_name, const string &filter) {
|
||||
|
||||
26
src/tcp.cpp
26
src/tcp.cpp
@@ -123,7 +123,7 @@ void TCP::mss(uint16_t value) {
|
||||
}
|
||||
|
||||
uint16_t TCP::mss() const {
|
||||
return Endian::host_to_be(generic_search<uint16_t>(MSS));
|
||||
return generic_search<uint16_t>(MSS);
|
||||
}
|
||||
|
||||
void TCP::winscale(uint8_t value) {
|
||||
@@ -161,16 +161,10 @@ void TCP::sack(const sack_type &edges) {
|
||||
}
|
||||
|
||||
TCP::sack_type TCP::sack() const {
|
||||
const option *option = search_option(SACK);
|
||||
if(!option || (option->data_size() % sizeof(uint32_t)) != 0)
|
||||
const option *opt = search_option(SACK);
|
||||
if(!opt)
|
||||
throw option_not_found();
|
||||
const uint32_t *ptr = (const uint32_t*)option->data_ptr();
|
||||
const uint32_t *end = ptr + (option->data_size() / sizeof(uint32_t));
|
||||
sack_type edges(end - ptr);
|
||||
sack_type::iterator it = edges.begin();
|
||||
while(ptr < end)
|
||||
*it++ = Endian::host_to_be(*(ptr++));
|
||||
return edges;
|
||||
return opt->to<sack_type>();
|
||||
}
|
||||
|
||||
void TCP::timestamp(uint32_t value, uint32_t reply) {
|
||||
@@ -180,12 +174,10 @@ void TCP::timestamp(uint32_t value, uint32_t reply) {
|
||||
}
|
||||
|
||||
std::pair<uint32_t, uint32_t> TCP::timestamp() const {
|
||||
const option *option = search_option(TSOPT);
|
||||
if(!option || option->data_size() != (sizeof(uint32_t) << 1))
|
||||
const option *opt = search_option(TSOPT);
|
||||
if(!opt)
|
||||
throw option_not_found();
|
||||
uint64_t buffer = *(const uint64_t*)option->data_ptr();
|
||||
buffer = Endian::be_to_host(buffer);
|
||||
return std::make_pair(static_cast<uint32_t>(buffer >> 32), buffer & 0xffffffff);
|
||||
return opt->to<std::pair<uint32_t, uint32_t> >();
|
||||
}
|
||||
|
||||
void TCP::altchecksum(AltChecksums value) {
|
||||
@@ -309,7 +301,7 @@ void TCP::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *par
|
||||
|
||||
memcpy(tcp_start, &_tcp, sizeof(tcphdr));
|
||||
|
||||
const Tins::IP *ip_packet = dynamic_cast<const Tins::IP*>(parent);
|
||||
const Tins::IP *ip_packet = tins_cast<const Tins::IP*>(parent);
|
||||
if(ip_packet) {
|
||||
uint32_t check = Utils::pseudoheader_checksum(ip_packet->src_addr(),
|
||||
ip_packet->dst_addr(),
|
||||
@@ -321,7 +313,7 @@ void TCP::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *par
|
||||
((tcphdr*)tcp_start)->check = _tcp.check;
|
||||
}
|
||||
else {
|
||||
const Tins::IPv6 *ipv6_packet = dynamic_cast<const Tins::IPv6*>(parent);
|
||||
const Tins::IPv6 *ipv6_packet = tins_cast<const Tins::IPv6*>(parent);
|
||||
if(ipv6_packet) {
|
||||
uint32_t check = Utils::pseudoheader_checksum(ipv6_packet->src_addr(),
|
||||
ipv6_packet->dst_addr(),
|
||||
|
||||
@@ -85,7 +85,7 @@ void UDP::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *par
|
||||
else
|
||||
length(sizeof(udphdr));
|
||||
std::memcpy(buffer, &_udp, sizeof(udphdr));
|
||||
const Tins::IP *ip_packet = dynamic_cast<const Tins::IP*>(parent);
|
||||
const Tins::IP *ip_packet = tins_cast<const Tins::IP*>(parent);
|
||||
if(ip_packet) {
|
||||
uint32_t checksum = Utils::pseudoheader_checksum(
|
||||
ip_packet->src_addr(),
|
||||
@@ -99,7 +99,7 @@ void UDP::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *par
|
||||
((udphdr*)buffer)->check = _udp.check;
|
||||
}
|
||||
else {
|
||||
const Tins::IPv6 *ip6_packet = dynamic_cast<const Tins::IPv6*>(parent);
|
||||
const Tins::IPv6 *ip6_packet = tins_cast<const Tins::IPv6*>(parent);
|
||||
if(ip6_packet) {
|
||||
uint32_t checksum = Utils::pseudoheader_checksum(
|
||||
ip6_packet->src_addr(),
|
||||
|
||||
@@ -62,12 +62,12 @@ struct InterfaceCollector {
|
||||
#ifdef WIN32
|
||||
bool operator() (PIP_ADAPTER_ADDRESSES addr) {
|
||||
ifaces.insert(addr->AdapterName);
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
bool operator() (struct ifaddrs *addr) {
|
||||
ifaces.insert(addr->ifa_name);
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
};
|
||||
@@ -121,6 +121,12 @@ HWAddress<6> resolve_hwaddr(IPv4Address ip, PacketSender &sender) {
|
||||
return resolve_hwaddr(sender.default_interface(), ip, sender);
|
||||
}
|
||||
|
||||
std::vector<RouteEntry> route_entries() {
|
||||
std::vector<RouteEntry> entries;
|
||||
route_entries(std::back_inserter(entries));
|
||||
return entries;
|
||||
}
|
||||
|
||||
bool gateway_from_ip(IPv4Address ip, IPv4Address &gw_addr) {
|
||||
typedef std::vector<RouteEntry> entries_type;
|
||||
entries_type entries;
|
||||
|
||||
2160
tests/depends.d
2160
tests/depends.d
File diff suppressed because it is too large
Load Diff
@@ -203,34 +203,24 @@ TEST_F(DHCPTest, SubnetMaskOption) {
|
||||
|
||||
TEST_F(DHCPTest, RoutersOption) {
|
||||
DHCP dhcp;
|
||||
list<IPv4Address> routers;
|
||||
std::vector<IPv4Address> routers;
|
||||
routers.push_back("192.168.0.253");
|
||||
routers.push_back("10.123.45.67");
|
||||
dhcp.routers(routers);
|
||||
|
||||
list<IPv4Address> routers2 = dhcp.routers();
|
||||
ASSERT_EQ(routers.size(), routers2.size());
|
||||
while(routers.size()) {
|
||||
EXPECT_EQ(routers.front(), routers2.front());
|
||||
routers.pop_front();
|
||||
routers2.pop_front();
|
||||
}
|
||||
std::vector<IPv4Address> routers2 = dhcp.routers();
|
||||
EXPECT_EQ(routers, routers2);
|
||||
}
|
||||
|
||||
TEST_F(DHCPTest, DNSOption) {
|
||||
DHCP dhcp;
|
||||
list<IPv4Address> dns;
|
||||
std::vector<IPv4Address> dns;
|
||||
dns.push_back("192.168.0.253");
|
||||
dns.push_back("10.123.45.67");
|
||||
dhcp.domain_name_servers(dns);
|
||||
|
||||
list<IPv4Address> dns2 = dhcp.domain_name_servers();
|
||||
ASSERT_EQ(dns.size(), dns2.size());
|
||||
while(dns.size()) {
|
||||
EXPECT_EQ(dns.front(), dns2.front());
|
||||
dns.pop_front();
|
||||
dns2.pop_front();
|
||||
}
|
||||
std::vector<IPv4Address> dns2 = dhcp.domain_name_servers();
|
||||
EXPECT_EQ(dns, dns2);
|
||||
}
|
||||
|
||||
TEST_F(DHCPTest, DomainNameOption) {
|
||||
@@ -277,8 +267,9 @@ void DHCPTest::test_equals(const DHCP &dhcp1, const DHCP &dhcp2) {
|
||||
|
||||
TEST_F(DHCPTest, ConstructorFromBuffer) {
|
||||
DHCP dhcp1(expected_packet, sizeof(expected_packet));
|
||||
std::list<IPv4Address> routers;
|
||||
IPv4Address expected_routers[] = { "192.168.0.1", "127.0.0.1" };
|
||||
std::vector<IPv4Address> routers, expected_routers;
|
||||
expected_routers.push_back("192.168.0.1");
|
||||
expected_routers.push_back("127.0.0.1");
|
||||
|
||||
EXPECT_EQ(dhcp1.opcode(), DHCP::DISCOVER);
|
||||
EXPECT_EQ(dhcp1.htype(), 1);
|
||||
@@ -293,9 +284,7 @@ TEST_F(DHCPTest, ConstructorFromBuffer) {
|
||||
EXPECT_EQ(dhcp1.siaddr(), IPv4Address("167.32.11.154"));
|
||||
EXPECT_EQ(dhcp1.server_identifier(), IPv4Address("192.168.4.2"));
|
||||
routers = dhcp1.routers();
|
||||
ASSERT_EQ(routers.size(), sizeof(expected_routers) / sizeof(IPv4Address));
|
||||
|
||||
ASSERT_TRUE(std::equal(routers.begin(), routers.end(), expected_routers));
|
||||
EXPECT_EQ(expected_routers, routers);
|
||||
}
|
||||
|
||||
TEST_F(DHCPTest, Serialize) {
|
||||
|
||||
@@ -202,16 +202,16 @@ TEST_F(DHCPv6Test, UserClass) {
|
||||
DHCPv6::class_option_data_type user_data;
|
||||
user_data.push_back(22);
|
||||
user_data.push_back(176);
|
||||
data.push_back(user_data);
|
||||
data.data.push_back(user_data);
|
||||
|
||||
user_data.push_back(99);
|
||||
user_data.push_back(231);
|
||||
data.push_back(user_data);
|
||||
data.data.push_back(user_data);
|
||||
|
||||
dhcp.user_class(data);
|
||||
output = dhcp.user_class();
|
||||
|
||||
EXPECT_EQ(data, output);
|
||||
EXPECT_EQ(data.data, output.data);
|
||||
}
|
||||
|
||||
TEST_F(DHCPv6Test, VendorClass) {
|
||||
|
||||
@@ -9,7 +9,7 @@ using namespace Tins;
|
||||
|
||||
class DNSTest : public testing::Test {
|
||||
public:
|
||||
static const uint8_t expected_packet[];
|
||||
static const uint8_t expected_packet[], dns_response1[];
|
||||
|
||||
void test_equals(const DNS &dns1, const DNS &dns2);
|
||||
void test_equals(const DNS::Query &q1, const DNS::Query &q2);
|
||||
@@ -23,6 +23,10 @@ const uint8_t DNSTest::expected_packet[] = {
|
||||
0, 1, 0, 1, 0, 0, 18, 52, 0, 4, 192, 168, 0, 1
|
||||
};
|
||||
|
||||
const uint8_t DNSTest::dns_response1[] = {
|
||||
174, 73, 129, 128, 0, 1, 0, 5, 0, 0, 0, 0, 6, 103, 111, 111, 103, 108, 101, 3, 99, 111, 109, 0, 0, 15, 0, 1, 192, 12, 0, 15, 0, 1, 0, 0, 2, 88, 0, 17, 0, 50, 4, 97, 108, 116, 52, 5, 97, 115, 112, 109, 120, 1, 108, 192, 12, 192, 12, 0, 15, 0, 1, 0, 0, 2, 88, 0, 9, 0, 40, 4, 97, 108, 116, 51, 192, 47, 192, 12, 0, 15, 0, 1, 0, 0, 2, 88, 0, 9, 0, 20, 4, 97, 108, 116, 49, 192, 47, 192, 12, 0, 15, 0, 1, 0, 0, 2, 88, 0, 4, 0, 10, 192, 47, 192, 12, 0, 15, 0, 1, 0, 0, 2, 88, 0, 9, 0, 30, 4, 97, 108, 116, 50, 192, 47
|
||||
};
|
||||
|
||||
|
||||
|
||||
void DNSTest::test_equals(const DNS &dns1, const DNS &dns2) {
|
||||
@@ -84,6 +88,44 @@ TEST_F(DNSTest, ConstructorFromBuffer) {
|
||||
test_equals(answers.front(), DNS::Resource("www.example.com", "192.168.0.1", DNS::A, DNS::IN, 0x1234));
|
||||
}
|
||||
|
||||
TEST_F(DNSTest, ConstructorFromBuffer2) {
|
||||
DNS dns(dns_response1, sizeof(dns_response1));
|
||||
EXPECT_EQ(dns.questions_count(), 1);
|
||||
EXPECT_EQ(dns.answers_count(), 5);
|
||||
|
||||
for(size_t i = 0; i < 2; ++i) {
|
||||
DNS::queries_type queries(dns.queries());
|
||||
for(DNS::queries_type::const_iterator it = queries.begin(); it != queries.end(); ++it) {
|
||||
EXPECT_EQ("google.com", it->dname());
|
||||
EXPECT_TRUE(it->type() == DNS::MX || it->type() == DNS::A);
|
||||
EXPECT_EQ(it->query_class(), DNS::IN);
|
||||
}
|
||||
|
||||
DNS::resources_type resources = dns.answers();
|
||||
for(DNS::resources_type::const_iterator it = resources.begin(); it != resources.end(); ++it) {
|
||||
EXPECT_EQ("google.com", it->dname());
|
||||
EXPECT_EQ(DNS::MX, it->type());
|
||||
EXPECT_EQ(DNS::IN, it->query_class());
|
||||
EXPECT_TRUE(
|
||||
it->data() == "alt1.aspmx.l.google.com" ||
|
||||
it->data() == "alt2.aspmx.l.google.com" ||
|
||||
it->data() == "alt3.aspmx.l.google.com" ||
|
||||
it->data() == "alt4.aspmx.l.google.com" ||
|
||||
it->data() == "alt5.aspmx.l.google.com" ||
|
||||
it->data() == "aspmx.l.google.com"
|
||||
);
|
||||
}
|
||||
// Add some stuff and see if something gets broken
|
||||
if(i == 0) {
|
||||
dns.add_query(DNS::Query("google.com", DNS::A, DNS::IN));
|
||||
dns.add_query(DNS::Query("google.com", DNS::MX, DNS::IN));
|
||||
dns.add_answer(
|
||||
DNS::Resource("google.com", "alt5.aspmx.l.google.com", DNS::MX, DNS::IN, 0x762)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(DNSTest, Serialization) {
|
||||
DNS dns(expected_packet, sizeof(expected_packet));
|
||||
DNS::serialization_type buffer = dns.serialize();
|
||||
@@ -203,8 +245,13 @@ TEST_F(DNSTest, Question) {
|
||||
|
||||
TEST_F(DNSTest, Answers) {
|
||||
DNS dns;
|
||||
dns.add_answer("www.example.com", DNS::make_info(DNS::A, DNS::IN, 0x762), IPv4Address("127.0.0.1"));
|
||||
dns.add_answer("www.example2.com", DNS::make_info(DNS::MX, DNS::IN, 0x762), std::string("mail.example.com"));
|
||||
dns.add_answer(
|
||||
DNS::Resource("www.example.com", "127.0.0.1", DNS::A, DNS::IN, 0x762)
|
||||
);
|
||||
dns.add_answer(
|
||||
DNS::Resource("www.example2.com", "mail.example.com", DNS::MX, DNS::IN, 0x762)
|
||||
);
|
||||
|
||||
ASSERT_EQ(dns.answers_count(), 2);
|
||||
|
||||
DNS::resources_type resources = dns.answers();
|
||||
@@ -225,10 +272,61 @@ TEST_F(DNSTest, Answers) {
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(DNSTest, Authority) {
|
||||
DNS dns;
|
||||
|
||||
const char *domain = "carlos.example.com";
|
||||
dns.add_authority(
|
||||
DNS::Resource("www.example.com", domain, DNS::CNAME, DNS::IN, 0x762)
|
||||
);
|
||||
dns.add_authority(
|
||||
DNS::Resource("www.example.com", domain, DNS::CNAME, DNS::IN, 0x762)
|
||||
);
|
||||
|
||||
ASSERT_EQ(dns.authority_count(), 2);
|
||||
|
||||
DNS::resources_type resources = dns.authority();
|
||||
EXPECT_EQ(2, resources.size());
|
||||
for(DNS::resources_type::const_iterator it = resources.begin(); it != resources.end(); ++it) {
|
||||
EXPECT_EQ("www.example.com", it->dname());
|
||||
EXPECT_EQ(it->type(), DNS::CNAME);
|
||||
EXPECT_EQ(it->ttl(), 0x762U);
|
||||
EXPECT_EQ(it->data(), domain);
|
||||
EXPECT_EQ(it->query_class(), DNS::IN);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(DNSTest, Additional) {
|
||||
DNS dns;
|
||||
|
||||
const char *domain = "carlos.example.com";
|
||||
dns.add_additional(
|
||||
DNS::Resource("www.example.com", domain, DNS::CNAME, DNS::IN, 0x762)
|
||||
);
|
||||
dns.add_additional(
|
||||
DNS::Resource("www.example.com", domain, DNS::CNAME, DNS::IN, 0x762)
|
||||
);
|
||||
|
||||
ASSERT_EQ(dns.additional_count(), 2);
|
||||
|
||||
DNS::resources_type resources = dns.additional();
|
||||
for(DNS::resources_type::const_iterator it = resources.begin(); it != resources.end(); ++it) {
|
||||
EXPECT_EQ("www.example.com", it->dname());
|
||||
EXPECT_EQ(it->type(), DNS::CNAME);
|
||||
EXPECT_EQ(it->ttl(), 0x762U);
|
||||
EXPECT_EQ(it->data(), domain);
|
||||
EXPECT_EQ(it->query_class(), DNS::IN);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(DNSTest, AnswersWithSameName) {
|
||||
DNS dns;
|
||||
dns.add_answer("www.example.com", DNS::make_info(DNS::A, DNS::IN, 0x762), IPv4Address("127.0.0.1"));
|
||||
dns.add_answer("www.example.com", DNS::make_info(DNS::A, DNS::IN, 0x762), IPv4Address("127.0.0.2"));
|
||||
dns.add_answer(
|
||||
DNS::Resource("www.example.com", "127.0.0.1", DNS::A, DNS::IN, 0x762)
|
||||
);
|
||||
dns.add_answer(
|
||||
DNS::Resource("www.example.com", "127.0.0.2", DNS::A, DNS::IN, 0x762)
|
||||
);
|
||||
ASSERT_EQ(dns.answers_count(), 2);
|
||||
DNS::resources_type resources = dns.answers();
|
||||
for(DNS::resources_type::const_iterator it = resources.begin(); it != resources.end(); ++it) {
|
||||
@@ -242,8 +340,12 @@ TEST_F(DNSTest, AnswersWithSameName) {
|
||||
|
||||
TEST_F(DNSTest, AnswersV6) {
|
||||
DNS dns;
|
||||
dns.add_answer("www.example.com", DNS::make_info(DNS::AAAA, DNS::IN, 0x762), IPv6Address("f9a8:239::1:1"));
|
||||
dns.add_answer("www.example.com", DNS::make_info(DNS::AAAA, DNS::IN, 0x762), IPv6Address("f9a8:239::1:1"));
|
||||
dns.add_answer(
|
||||
DNS::Resource("www.example.com", "f9a8:239::1:1", DNS::AAAA, DNS::IN, 0x762)
|
||||
);
|
||||
dns.add_answer(
|
||||
DNS::Resource("www.example.com", "f9a8:239::1:1", DNS::AAAA, DNS::IN, 0x762)
|
||||
);
|
||||
ASSERT_EQ(dns.answers_count(), 2);
|
||||
|
||||
DNS::resources_type resources = dns.answers();
|
||||
@@ -255,3 +357,64 @@ TEST_F(DNSTest, AnswersV6) {
|
||||
EXPECT_EQ(it->query_class(), DNS::IN);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(DNSTest, ItAintGonnaCorrupt) {
|
||||
DNS dns(dns_response1, sizeof(dns_response1));
|
||||
EXPECT_EQ(dns.questions_count(), 1);
|
||||
EXPECT_EQ(dns.answers_count(), 5);
|
||||
|
||||
const char *domain = "carlos.example.com";
|
||||
dns.add_additional(
|
||||
DNS::Resource("www.example.com", domain, DNS::CNAME, DNS::IN, 0x762)
|
||||
);
|
||||
dns.add_authority(
|
||||
DNS::Resource("www.example.com", domain, DNS::CNAME, DNS::IN, 0x762)
|
||||
);
|
||||
dns.add_query(DNS::Query("google.com", DNS::A, DNS::IN));
|
||||
|
||||
DNS::queries_type queries(dns.queries());
|
||||
for(DNS::queries_type::const_iterator it = queries.begin(); it != queries.end(); ++it) {
|
||||
EXPECT_EQ("google.com", it->dname());
|
||||
EXPECT_TRUE(it->type() == DNS::MX || it->type() == DNS::A);
|
||||
EXPECT_EQ(it->query_class(), DNS::IN);
|
||||
}
|
||||
|
||||
// Check answers
|
||||
DNS::resources_type resources = dns.answers();
|
||||
for(DNS::resources_type::const_iterator it = resources.begin(); it != resources.end(); ++it) {
|
||||
EXPECT_EQ("google.com", it->dname());
|
||||
EXPECT_EQ(DNS::MX, it->type());
|
||||
EXPECT_EQ(DNS::IN, it->query_class());
|
||||
EXPECT_TRUE(
|
||||
it->data() == "alt1.aspmx.l.google.com" ||
|
||||
it->data() == "alt2.aspmx.l.google.com" ||
|
||||
it->data() == "alt3.aspmx.l.google.com" ||
|
||||
it->data() == "alt4.aspmx.l.google.com" ||
|
||||
it->data() == "alt5.aspmx.l.google.com" ||
|
||||
it->data() == "aspmx.l.google.com"
|
||||
);
|
||||
}
|
||||
|
||||
// Check authority records
|
||||
resources = dns.authority();
|
||||
EXPECT_EQ(1, resources.size());
|
||||
for(DNS::resources_type::const_iterator it = resources.begin(); it != resources.end(); ++it) {
|
||||
EXPECT_EQ("www.example.com", it->dname());
|
||||
EXPECT_EQ(it->type(), DNS::CNAME);
|
||||
EXPECT_EQ(it->ttl(), 0x762U);
|
||||
EXPECT_EQ(it->data(), domain);
|
||||
EXPECT_EQ(it->query_class(), DNS::IN);
|
||||
}
|
||||
|
||||
|
||||
// Check additional records
|
||||
resources = dns.additional();
|
||||
EXPECT_EQ(1, resources.size());
|
||||
for(DNS::resources_type::const_iterator it = resources.begin(); it != resources.end(); ++it) {
|
||||
EXPECT_EQ("www.example.com", it->dname());
|
||||
EXPECT_EQ(it->type(), DNS::CNAME);
|
||||
EXPECT_EQ(it->ttl(), 0x762U);
|
||||
EXPECT_EQ(it->data(), domain);
|
||||
EXPECT_EQ(it->query_class(), DNS::IN);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
#include <gtest/gtest.h>
|
||||
#include "dot11/dot11_control.h"
|
||||
#ifdef HAVE_DOT11
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include "tests/dot11.h"
|
||||
|
||||
|
||||
@@ -98,3 +100,5 @@ TEST_F(Dot11AckTest, Serialize) {
|
||||
ASSERT_EQ(sizeof(expected_packet), buffer.size());
|
||||
EXPECT_TRUE(std::equal(buffer.begin(), buffer.end(), expected_packet));
|
||||
}
|
||||
|
||||
#endif // HAVE_DOT11
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
#include <gtest/gtest.h>
|
||||
#include "dot11/dot11_assoc.h"
|
||||
|
||||
#ifdef HAVE_DOT11
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include "tests/dot11_mgmt.h"
|
||||
|
||||
|
||||
@@ -87,3 +90,4 @@ TEST_F(Dot11AssocRequestTest, Serialize) {
|
||||
EXPECT_TRUE(std::equal(buffer.begin(), buffer.end(), expected_packet));
|
||||
}
|
||||
|
||||
#endif // HAVE_DOT11
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
#include <gtest/gtest.h>
|
||||
#include "dot11/dot11_assoc.h"
|
||||
|
||||
#ifdef HAVE_DOT11
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include "tests/dot11_mgmt.h"
|
||||
|
||||
|
||||
@@ -95,3 +98,4 @@ TEST_F(Dot11AssocResponseTest, Serialize) {
|
||||
EXPECT_TRUE(std::equal(buffer.begin(), buffer.end(), expected_packet));
|
||||
}
|
||||
|
||||
#endif // HAVE_DOT11
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
#include <gtest/gtest.h>
|
||||
#include "dot11/dot11_auth.h"
|
||||
|
||||
#ifdef HAVE_DOT11
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include "tests/dot11_mgmt.h"
|
||||
|
||||
|
||||
@@ -103,3 +106,4 @@ TEST_F(Dot11AuthenticationTest, Serialize) {
|
||||
EXPECT_TRUE(std::equal(buffer.begin(), buffer.end(), expected_packet));
|
||||
}
|
||||
|
||||
#endif // HAVE_DOT11
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
#include <gtest/gtest.h>
|
||||
#include "dot11/dot11_beacon.h"
|
||||
|
||||
#ifdef HAVE_DOT11
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include "rsn_information.h"
|
||||
#include "tests/dot11_mgmt.h"
|
||||
|
||||
@@ -456,3 +459,5 @@ TEST_F(Dot11BeaconTest, Serialize) {
|
||||
ASSERT_EQ(sizeof(expected_packet), buffer.size());
|
||||
EXPECT_TRUE(std::equal(buffer.begin(), buffer.end(), expected_packet));
|
||||
}
|
||||
|
||||
#endif // HAVE_DOT11
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
#include <gtest/gtest.h>
|
||||
#include "dot11/dot11_control.h"
|
||||
|
||||
#ifdef HAVE_DOT11
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include "tests/dot11.h"
|
||||
|
||||
|
||||
@@ -90,3 +93,5 @@ TEST_F(Dot11BlockAckRequestTest, Serialize) {
|
||||
ASSERT_EQ(sizeof(expected_packet), buffer.size());
|
||||
EXPECT_TRUE(std::equal(buffer.begin(), buffer.end(), expected_packet));
|
||||
}
|
||||
|
||||
#endif // HAVE_DOT11
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
#include "config.h"
|
||||
|
||||
#ifdef HAVE_DOT11
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include "tests/dot11_control.h"
|
||||
|
||||
@@ -73,3 +77,5 @@ TEST_F(Dot11CFEndTest, Serialize) {
|
||||
ASSERT_EQ(sizeof(expected_packet), buffer.size());
|
||||
EXPECT_TRUE(std::equal(buffer.begin(), buffer.end(), expected_packet));
|
||||
}
|
||||
|
||||
#endif // HAVE_DOT11
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
#include "config.h"
|
||||
|
||||
#ifdef HAVE_DOT11
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include "tests/dot11_control.h"
|
||||
|
||||
@@ -74,3 +78,4 @@ TEST_F(Dot11EndCFAckTest, Serialize) {
|
||||
EXPECT_TRUE(std::equal(buffer.begin(), buffer.end(), expected_packet));
|
||||
}
|
||||
|
||||
#endif // HAVE_DOT11
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
#include "config.h"
|
||||
|
||||
#ifdef HAVE_DOT11
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include "tests/dot11_data.h"
|
||||
|
||||
@@ -163,3 +167,5 @@ TEST_F(Dot11DataTest, Source_Dest_BSSID_Address3) {
|
||||
EXPECT_EQ(data.dst_addr(), "00:18:f8:f5:c2:c6");
|
||||
EXPECT_EQ(data.bssid_addr(), "00:18:f8:f5:c2:c6");
|
||||
}
|
||||
|
||||
#endif // HAVE_DOT11
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
#include <gtest/gtest.h>
|
||||
#include "dot11/dot11_auth.h"
|
||||
|
||||
#ifdef HAVE_DOT11
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include "tests/dot11_mgmt.h"
|
||||
|
||||
|
||||
@@ -85,3 +88,4 @@ TEST_F(Dot11DeauthenticationTest, Serialize) {
|
||||
EXPECT_TRUE(std::equal(buffer.begin(), buffer.end(), expected_packet));
|
||||
}
|
||||
|
||||
#endif // HAVE_DOT11
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
#include <gtest/gtest.h>
|
||||
#include "dot11/dot11_assoc.h"
|
||||
|
||||
#ifdef HAVE_DOT11
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include "tests/dot11_mgmt.h"
|
||||
|
||||
|
||||
@@ -85,3 +88,5 @@ TEST_F(Dot11DisassocTest, Serialize) {
|
||||
ASSERT_EQ(sizeof(expected_packet), buffer.size());
|
||||
EXPECT_TRUE(std::equal(buffer.begin(), buffer.end(), expected_packet));
|
||||
}
|
||||
|
||||
#endif // HAVE_DOT11
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
#include "config.h"
|
||||
|
||||
#ifdef HAVE_DOT11
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include "tests/dot11.h"
|
||||
#include "utils.h"
|
||||
@@ -161,4 +165,4 @@ TEST_F(Dot11Test, Serialize) {
|
||||
EXPECT_TRUE(std::equal(buffer.begin(), buffer.end(), expected_packet));
|
||||
}
|
||||
|
||||
|
||||
#endif // HAVE_DOT11
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
#include <gtest/gtest.h>
|
||||
#include "dot11/dot11_probe.h"
|
||||
|
||||
#ifdef HAVE_DOT11
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include "tests/dot11_mgmt.h"
|
||||
|
||||
|
||||
@@ -69,3 +72,4 @@ TEST_F(Dot11ProbeRequestTest, FromBytes) {
|
||||
test_equals_expected(*inner);
|
||||
}
|
||||
|
||||
#endif // HAVE_DOT11
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
#include <gtest/gtest.h>
|
||||
#include "dot11/dot11_probe.h"
|
||||
|
||||
#ifdef HAVE_DOT11
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include "tests/dot11_mgmt.h"
|
||||
|
||||
|
||||
@@ -93,3 +96,5 @@ TEST_F(Dot11ProbeResponseTest, Serialize) {
|
||||
ASSERT_EQ(sizeof(expected_packet), buffer.size());
|
||||
EXPECT_TRUE(std::equal(buffer.begin(), buffer.end(), expected_packet));
|
||||
}
|
||||
|
||||
#endif // HAVE_DOT11
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user