1
0
mirror of https://github.com/mfontanini/libtins synced 2026-01-23 18:55:58 +01:00

42 Commits
v1.2 ... v2.0

Author SHA1 Message Date
Matias F
ed175e0ad6 Updated CHANGES, README and configure.ac files. 2014-01-23 11:30:05 -03:00
Matias Fontanini
c5404a6111 Removed DNSResourceRecord. Records in DNS are now managed completely by DNS::Resource. 2014-01-21 22:56:53 -03:00
Matias Fontanini
6d7e06535a Fixed some endianness bugs on ICMPv6 and PPI. 2014-01-19 14:40:57 -03:00
Matias Fontanini
853e1ce647 tins.h now includes ppi.h. 2014-01-19 14:17:25 -03:00
Matias Fontanini
dbcdda9d36 Rewrote the DNS parsing algorithm. Everything is now done on the read buffer, without any extra data structures, making it work about 400% faster than before. 2014-01-19 13:11:50 -03:00
Matias Fontanini
17ceba6064 Fixed broken strict-aliasing rules on ICMPv6. 2014-01-15 19:56:58 -03:00
Matias Fontanini
52078cc567 Finished porting DHCPv6. 2014-01-15 19:39:07 -03:00
Matias Fontanini
e2656739f1 Ported DHCP and Dot11. Almost ported DHCPv6 completely. 2013-12-23 23:02:58 -03:00
Matias Fontanini
33091ccbae Ported PPPoE and started porting Dot11. 2013-12-18 13:02:41 -03:00
Matias Fontanini
ca6b603478 Finished porting ICMPv6. 2013-12-17 19:00:00 -03:00
Matias Fontanini
069ae82b10 Keep porting ICMPv6 to use PDUOption::to<>. 2013-12-17 00:10:26 -03:00
Matias Fontanini
ea6638c163 IP now uses PDUOption::to<>. Started porting ICMPv6 to do so as well. 2013-12-16 15:50:17 -03:00
Matias Fontanini
112a357726 Added PDUOption::to<>. TCP options now use this method when being converted to their appropriate types. 2013-12-16 14:11:53 -03:00
Matias Fontanini
0e54579200 Layer 3 packets sent using PacketSender::send_recv for which the answer is a different PDU type(such as ICMP destination unreachable), are detected by PacketSender and matched like usual. 2013-12-14 18:10:33 -03:00
Matias Fontanini
ccb8ffd1b5 ICMP::gateway is now an IPv4Address. 2013-12-14 14:28:39 -03:00
Matias Fontanini
b83c1a2a96 Added support for ICMP address mask request/reply. 2013-12-14 14:21:04 -03:00
Matias Fontanini
81a947e3b3 Fixed bug on ICMP checksum calculation when using timestamp request/replies. 2013-12-14 13:42:12 -03:00
Matias Fontanini
1cec0f106d 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. 2013-12-14 12:49:50 -03:00
Matias Fontanini
0acb0fee3e IP packets sent using PacketSender::send_recv now match ICMP responses. 2013-12-14 12:48:56 -03:00
Matias Fontanini
9b57585b62 Added support for ICMP timestamp request/reply packets. ICMP::matches_response now works with these types of packets as well. 2013-12-13 17:23:17 -03:00
Matias Fontanini
2ddec368c3 Fixed bug on IP when serializing fragmented packets.
The original protocol id was being overwritten with 0xff(unknown)
when the inner_pdu was a RawPDU, even if it was just a fragment of
a transport layer PDU. The protocol id is now kept if the packet
is fragmented.
2013-12-04 10:56:48 -03:00
matias
83dc8819b6 Updated README.md. 2013-11-24 16:37:10 -03:00
matias
5e668e6e83 Updated README.md 2013-11-24 13:31:19 -03:00
matias
ca4912ded4 Added README.md and updated README. 2013-11-24 11:07:39 -03:00
Matias Fontanini
295ebb679c Added 1000ms as the default read timeout used when calling pcap_open_live. Added BaseSniffer::set_timeout to modify this parameter. 2013-11-19 20:51:58 -03:00
Matias Fontanini
6355aff3cd Added IPv4Reassembler class. 2013-11-17 15:32:24 -03:00
Matias Fontanini
a6655191d4 Fragmented IP packet's inner_pdu PDUs are not decoded now. 2013-11-16 19:40:08 -03:00
Matias Fontanini
dc6c37777b Updated configure.ac and README files. 2013-11-10 14:14:25 -03:00
Matias Fontanini
23552ea105 Fixed issue with relative include paths in dot11 headers. 2013-11-10 11:55:36 -03:00
Matias Fontanini
9962381fc7 Added the --disable-dot11 configure switch. 2013-11-09 14:41:08 -03:00
Matias Fontanini
93ab8d3b91 Removed useless include directives from ip.cpp and ipv6.cpp. 2013-11-04 23:31:46 -03:00
Matias Fontanini
5345b29f8c Added support for IPSec. 2013-11-04 23:05:00 -03:00
Matias Fontanini
de06fee5ab Fixed bug triggered when ifaddrs::ifa_addr was null. 2013-11-04 15:53:55 -03:00
Matias Fontanini
6d329424f1 Created an overload of Internals::pdu_from_flag for transport layer PDUs. 2013-11-04 13:46:25 -03:00
Matias Fontanini
dfbbea33d5 Added another overload of Utils::route_entries and fixed a bug in Utils::network_interfaces. 2013-11-02 19:19:55 -03:00
Matias Fontanini
0b02af616a Added ARP monitor example. 2013-10-29 21:10:11 -03:00
Matias Fontanini
a101ec9796 Added the missing WPS detector example. 2013-10-29 19:19:53 -03:00
Matias Fontanini
b0868b5d60 Added another Sniffer constructor. 2013-10-21 23:31:07 -03:00
Matias Fontanini
f57b8c189c Added WPS detector example. Updated configure files. 2013-10-21 22:54:18 -03:00
Matias Fontanini
a507355e27 Added tins_cast as a replacement for dynamic_cast when using it on PDU classes. 2013-10-18 09:28:43 -03:00
Matias Fontanini
87fdd62b57 Added some examples. 2013-10-17 20:44:54 -03:00
Matias Fontanini
3337335df2 Fixed compilation error on internals.h. 2013-10-16 14:45:03 -03:00
116 changed files with 6454 additions and 2911 deletions

54
CHANGES
View File

@@ -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.

View File

@@ -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 \

View File

@@ -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
View File

@@ -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
View 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
View File

@@ -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\\"

View File

@@ -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

View File

@@ -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
View 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
View File

@@ -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
;;

View File

@@ -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
View 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
View 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
View 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);
}

View File

@@ -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

View File

@@ -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 {

View File

@@ -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;

View File

@@ -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

View File

@@ -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 &section_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 &sections);
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;
};
}

View File

@@ -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

View File

@@ -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"

View File

@@ -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"

View File

@@ -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"

View File

@@ -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.
*

View File

@@ -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"

View File

@@ -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"

View File

@@ -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"

View File

@@ -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;

View File

@@ -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"

View File

@@ -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>

View File

@@ -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

View File

@@ -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>

View File

@@ -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;
};
}

View File

@@ -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;

View File

@@ -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
/**

View File

@@ -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
View 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
View 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

View File

@@ -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.

View File

@@ -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

View File

@@ -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

View File

@@ -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_;

View File

@@ -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);
}
/**

View File

@@ -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

View File

@@ -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"

View File

@@ -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

View File

@@ -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 = "");
};
/**

View File

@@ -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);

View File

@@ -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

View File

@@ -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.

View File

@@ -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

View File

@@ -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>()));
}
}

View File

@@ -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

View File

@@ -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 &sections) {
// 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 &section_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;
}

View File

@@ -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);
}
}

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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;

View File

@@ -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;
}
}

View File

@@ -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;

View File

@@ -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
View 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
View 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));
}
}

View File

@@ -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));

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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;

View File

@@ -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));

View File

@@ -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

View File

@@ -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

View File

@@ -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());
}
}

View File

@@ -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) {

View File

@@ -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(),

View File

@@ -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(),

View File

@@ -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;

File diff suppressed because it is too large Load Diff

View File

@@ -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) {

View File

@@ -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) {

View File

@@ -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);
}
}

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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