1
0
mirror of https://github.com/mfontanini/libtins synced 2026-01-23 10:45:57 +01:00

128 Commits
v0.2 ... v1.0

Author SHA1 Message Date
Matias Fontanini
cf19c8758d UDP now calculates the checksum when the transport layer protocol is IPv6. 2013-04-23 23:00:43 -03:00
Matias Fontanini
5197e7f5f1 Sniffer now differentiates between EthernetII and Dot3 when sniffing. 2013-04-23 22:55:32 -03:00
Matias Fontanini
eb87b82c17 Fixed the CHANGES and README files. 2013-04-23 20:57:56 -03:00
Matias Fontanini
5064a9255b Fixed BSD notice. Updated AUTHORS file. 2013-04-23 20:33:00 -03:00
Matias Fontanini
bf604339f0 Removed the PDU* parameter in several PDU's constructors. 2013-04-23 20:03:08 -03:00
Matias Fontanini
7e85058ef1 Added another overload of Utils::resolv_hwaddr. 2013-04-23 15:19:48 -03:00
Matias Fontanini
ec05a49cce Done minor modifications on configure.ac 2013-04-23 14:46:56 -03:00
Matias Fontanini
b0eefe15f9 Modified the soname. 2013-04-23 13:43:12 -03:00
Matias Fontanini
0f2bc45059 Moved definitions inside TINS_IS_CXX11 into header files. 2013-04-23 13:04:57 -03:00
Matias Fontanini
f8134be8b7 Done some modifications on the configure script. 2013-04-23 13:03:00 -03:00
Matias Fontanini
8afbe14c82 PacketSender is not copyable and movable. 2013-04-23 11:05:44 -03:00
Matias Fontanini
fdfb8b0dea Fixed compilation issues triggered in GNU/kFreeBSD. 2013-04-22 23:48:53 -03:00
Matias Fontanini
9be4f0ca37 Removed IP, UDP and IP checksum setters. Added some checksum tests. 2013-04-22 20:06:35 -03:00
Matias Fontanini
66ff604580 assert() is only called when TINS_DEBUG is defined. 2013-04-22 18:45:56 -03:00
Matias Fontanini
7e0e85db65 Added AC_CANONICAL_SYSTEM to configure.ac. 2013-04-22 13:58:42 -03:00
Matias Fontanini
ed39eb36f5 Dot11BlockAck and Dot11BlockAckRequests' frag_seq, start_sequence and bar_control now use small_uint rather than uintX_t. 2013-04-22 12:54:27 -03:00
Matias Fontanini
7da8de6ea7 Added another test case for RadioTap's constructor from buffer. 2013-04-22 12:53:01 -03:00
Matias Fontanini
d1b64ec48e PDU::matches_response is now const. 2013-04-21 20:03:47 -03:00
Matias Fontanini
69968cbc5c Removed deprecated methods/types. 2013-04-21 19:52:39 -03:00
Matias Fontanini
9e20c0241f Added a default interface to PacketSender. 2013-04-21 19:40:17 -03:00
Matias Fontanini
97f049580b Link layer PDUs no longer contain a NetworkInterface. 2013-04-21 18:50:08 -03:00
Matias Fontanini
6f04329fbe All tests now run successfully on big endian architectures. 2013-04-21 15:40:28 -03:00
Matias Fontanini
077b54bbed Added STP root_id and bridge_id setters/getters. 2013-04-21 13:22:15 -03:00
Matias Fontanini
759e92706f Sniffer::sniff_loop now catches malformed_packet and pdu_not_found, when thrown by the functor argument. 2013-04-21 13:21:47 -03:00
Matias Fontanini
2ea952d6ab Added PDU::rfind_pdu. 2013-04-19 22:27:48 -03:00
Matias Fontanini
91bdcca577 Dot11 now uses option_not_found. Sniffer catches malformed_packet rather than std::runtime_error while sniffing. 2013-04-19 14:06:59 -03:00
Matias Fontanini
75bd445bd3 Dot11 now uses malformed_packet. 2013-04-19 02:05:28 -03:00
Matias Fontanini
9812ad441f Added missing exceptions.h file. 2013-04-18 17:52:53 -03:00
Matias Fontanini
3fd1b3d37d Added malformed_packet exception. Every class except Dot11* use it. 2013-04-18 00:12:20 -03:00
Matias Fontanini
923f51ae15 Fixed bug triggered when parsing Dot11 QoS packets. 2013-04-16 15:01:48 -03:00
Matias Fontanini
804ea411fc Fixed bug in RadioTap when using FCS at the end. 2013-04-16 13:45:30 -03:00
Piotr Haber
9bcfd07896 fix radiotap header parsing
Signed-off-by: Matias Fontanini <matias.fontanini@gmail.com>
2013-04-16 13:37:31 -03:00
Matias Fontanini
58c8eccc46 Makefile issue fix. 2013-04-16 13:15:35 -03:00
Matias F
a674640ef2 Now hopefully make problems are fixed. 2013-04-16 13:00:12 -03:00
Matias F
dde890b24b Fixed make issues. 2013-04-16 12:51:07 -03:00
Matias Fontanini
38ccb4413b STP is now serialized correctly. LLC behaves correctly when it contains an STP is its inner pdu. 2013-04-16 01:05:06 -03:00
Matias F
9631734805 Added STP class. 2013-04-15 14:01:44 -03:00
Matias Fontanini
7faf514496 Merge branch 'master' of ssh://git.code.sf.net/p/libtins/code 2013-04-15 08:49:25 -03:00
Matias Fontanini
08091fc7c2 Added missing the deprecated header ieee802_3.h to Makefile.am. 2013-04-15 08:48:51 -03:00
Matias Fontanini
1450c8cf26 Fixed missing header in Makefile.in as well. 2013-04-15 08:41:21 -03:00
Matias Fontanini
b533775cb4 Added missing the deprecated header ieee802_3.h to Makefile.am. 2013-04-15 08:35:34 -03:00
Matias Fontanini
3f4c48ad9f Fixed bug triggered when parsing EOL and NOP options in IP. 2013-04-15 00:23:29 -03:00
Matias Fontanini
30d6a4f2e0 UDP checksum is now calculated always inside write_serialization. 2013-04-12 13:42:11 -03:00
Matias Fontanini
f4522acd44 IP and TCP now calculate checksums always inside write_serialization. 2013-04-11 00:57:36 -03:00
Matias Fontanini
1fbef641da TCP options now use PDUOption<>::length_field when it is != from data_size. 2013-04-10 18:44:00 -03:00
Matias Fontanini
fee938b46d Added move constructor/assignment operator to PDU. 2013-04-10 18:43:24 -03:00
Matias Fontanini
ae1e1c2ce2 Modified some protocols' internal type names. 2013-04-09 15:40:58 -03:00
Matias Fontanini
20054e6c73 Several classes now use PDUOption::length_field instead of data_size. 2013-04-08 11:58:12 -03:00
Matias Fontanini
f7f5a9bc9a Added PPPoE. 2013-04-07 20:57:43 -03:00
Matias Fontanini
f2a5f73337 Implemented matches_response on several PDUs. Added some test cases. 2013-04-02 21:05:53 -03:00
Matias Fontanini
97049140af Added some helper methods to Dot1Q. 2013-03-26 23:42:43 -03:00
Matias Fontanini
dfc0498b70 DNS, RadioTap and Dot1Q work when using PacketSender::send_recv. 2013-03-26 14:54:24 -03:00
Matias Fontanini
1cec099c0e Dot3::matches_response now works as expected. 2013-03-26 00:25:47 -03:00
Matias Fontanini
3989566608 Renamed IEEE802_3 to Dot3. 2013-03-25 15:35:30 -03:00
Matias Fontanini
b32586e739 Fixed compilation error on IP and TCP. 2013-03-25 15:17:26 -03:00
Matias Fontanini
82ef41dd92 IP now fills automatically the sender address when no link layer PDU is present. Made some protocols work when using PacketSender::send_recv. 2013-03-25 14:08:59 -03:00
Matias Fontanini
b0dc376494 Fixed compilation error in pdu_cacher.h. 2013-03-25 09:55:15 -03:00
Matias Fontanini
8be0c4c23c Marked PDU::clone_packet as deprecated. 2013-03-24 16:08:09 -03:00
Matias Fontanini
d7dd1e131f Added an overload of add_option that takes an rvalue-ref in IP, TCP, DHCP, ICMPv6 and Dot11. 2013-03-24 00:08:53 -03:00
Matias Fontanini
584fe81f04 Optimized TCP, IP and PDUOption<>. 2013-03-23 13:44:33 -03:00
Matias Fontanini
16a99ef35b Added an overload of PacketSender::send that takes a NetworkInterface. 2013-03-20 23:24:43 -03:00
Matias Fontanini
247273e086 Added constructor from buffer test for Dot11BlockAckRequest. 2013-03-18 13:32:34 -03:00
Matias Fontanini
0f27b04a92 Fixed lots of warnings in test cases, due to narrowing conversions. 2013-03-18 11:32:34 -03:00
Matias Fontanini
a8edc2af74 Added serialization test for Dot1Q. 2013-03-18 10:17:43 -03:00
Matias Fontanini
f5ecaa3faa Added Dot1Q class. 2013-03-17 23:27:34 -03:00
Matias Fontanini
b5f9f5095e Added Utils::resolve_domain and resolve_domain6. 2013-03-15 15:43:42 -03:00
Matias Fontanini
02a53da361 Fixed bug triggered when parsing RadioTap in BE architectures. 2013-03-15 15:13:00 -03:00
Matias Fontanini
f86f727810 Added RadioTap::iface. 2013-02-06 14:10:21 -03:00
Matias Fontanini
836dbd8955 Fixed compilation issue in 2 examples. 2013-02-01 13:55:29 -03:00
Matias Fontanini
a24e0d5a4b Done some changes on the build system. 2013-01-31 16:48:32 -03:00
Bruno Nery
c6dc18d215 Added get_fd() to BaseSniffer.
Signed-off-by: Matias Fontanini <matias.fontanini@gmail.com>
2013-01-29 20:25:48 -03:00
Matias Fontanini
931a86eff9 Done minor modification, mostly on documentation. 2013-01-29 16:18:08 -03:00
Matias Fontanini
2a1a28c3fb Added README, THANKS and CHANGES files. 2013-01-28 17:57:43 -03:00
Matias Fontanini
3f060de381 PacketWriter is now movable. 2013-01-28 17:56:59 -03:00
Matias Fontanini
0945e0b29e Added DHCPv6 client/server id options' getters/setters. 2013-01-28 16:23:47 -03:00
Matias Fontanini
5ee0ebb264 Added some fixes to the build system. Fixed bugs in DNS and ICMPv6 triggered in big-endian architectures. 2013-01-24 23:55:01 -03:00
Matias Fontanini
0dc762f15d Added missing build system files. 2013-01-24 13:52:45 -03:00
Matias Fontanini
c7c56a610c Done some -pedantic modifications. 2013-01-24 13:44:30 -03:00
Matias Fontanini
a826d92666 The build system now uses libtool. 2013-01-24 13:44:15 -03:00
Matias Fontanini
5b2e117347 Implemented every DHCPv6 option getter/setter, except for those involving DUIDs. 2013-01-22 23:24:10 -03:00
Matias Fontanini
e712550cb8 Move constructors are now noexcept. 2013-01-20 00:22:21 -03:00
Matias Fontanini
044d0a5a31 Added DHCPv6 initial support. 2013-01-16 20:15:04 -03:00
Matias Fontanini
9d0e84f1fa Added SLL tests. 2013-01-16 16:24:44 -03:00
Matias Fontanini
02265061cc Added SLL pseudo protocol header. 2013-01-16 00:05:28 -03:00
Bruno Nery
a13d7d0cb1 Fixed Timestamp::operator std::chrono::microseconds issue.
Signed-off-by: Matias Fontanini <matias.fontanini@gmail.com>
2013-01-15 18:38:35 -03:00
Matias Fontanini
7a86012292 IPv6::send now works on linux. BSD does not support sending IPv6 as the lowest layer. 2012-12-10 20:31:32 -03:00
Matias Fontanini
c933faaf5e Null/Loopback PDUs can now be sent on *BSD. 2012-12-09 13:05:39 -03:00
Matias Fontanini
a7e0c094fb Implemented several ICMPv6 option getters/setters. 2012-12-08 11:15:41 -03:00
Matias Fontanini
592a15ebe4 Added some ICMPv6 option getters/setters. 2012-12-05 23:33:09 -03:00
Matias Fontanini
75b32c75bc Added concat operator to Packet and an overload that takes a PDU*. 2012-12-05 17:04:39 -03:00
Matias Fontanini
765285c6ee Added several ICMPv6 option getters/setters. 2012-12-04 23:15:38 -03:00
Matias Fontanini
356fe00aad Fixed compilation error in OSX. Fixed bug when sending IP PDUs in BSD. 2012-12-04 16:15:08 -03:00
Matias Fontanini
647ba1f46e Fixed ternary operator associativity issue in dot11.h. 2012-12-03 20:56:47 -03:00
Matias Fontanini
53fe80d8a7 Added fix for IP::tot_len's endianess in OSX. 2012-12-03 20:34:15 -03:00
Matias Fontanini
742276c251 libtins compiles and runs under windows. Packets apparently can't be sent yet. 2012-12-02 20:25:05 -03:00
Matias Fontanini
6d1e96866e libtins now compiles on windows. A couple of features were disabled and need to be fixed though. 2012-12-02 00:45:10 -03:00
Matias Fontanini
dbe67c8cae DNSRecords are now movable.! 2012-12-01 20:18:23 -03:00
Matias Fontanini
dd9c0b3fd5 Fixed bugs in IPv6 and ICMPv6 when constructing an object from a buffer. 2012-12-01 13:43:19 -03:00
Matias Fontanini
9bdee61e5b Fixed some issues with Endian::change_endian triggered in OSX. 2012-11-29 21:30:13 -03:00
Matias Fontanini
e2426b493e configure script now works on BSD. 2012-11-29 18:00:41 -03:00
Matias Fontanini
acff776d56 Utils::route_entries now works on BSD. 2012-11-29 17:11:10 -03:00
Matias Fontanini
4036e7daa2 Merge branch 'master' of ssh://git.code.sf.net/p/libtins/code 2012-11-29 14:01:55 -03:00
Matias Fontanini
93b5b86c5d Added some ICMPv6 option getters/setters. 2012-11-29 14:01:22 -03:00
Matias Fontanini
de82dc2322 Link layer protocols can now be sent on BSD. 2012-11-28 16:50:47 -03:00
Matias Fontanini
6696c1b284 Ported almost everything to BSD. Utils::route_entries and sending link layer PDUs still don't work. 2012-11-28 00:11:42 -03:00
Matias Fontanini
e6e3e8453b Fixed some bugs in ICMPv6. 2012-11-26 19:47:15 -03:00
Matias Fontanini
4576d8746c Added another constructor to Packet. 2012-11-26 16:01:26 -03:00
Matias Fontanini
b42c868a66 Added .so file symlinks. 2012-11-26 15:50:06 -03:00
Matias Fontanini
a18cd3e0de PDU::find_pdu now has a const overload. 2012-11-26 15:38:53 -03:00
Matias Fontanini
88faee9b26 Added Packet conversion to bool. 2012-11-26 15:22:29 -03:00
Matias Fontanini
16a29fab3e Fixed memory leak in Packet's copy assignment operator. 2012-11-26 15:03:09 -03:00
Matias Fontanini
cd6bc16d48 Packets are now copyable and movable. 2012-11-26 14:02:50 -03:00
Matias Fontanini
443803caf0 Added ICMPv6 class. It's working. Option getters/setters are missing. 2012-11-24 18:50:21 -03:00
Matias Fontanini
75a4bbfed6 Added Timestamp conversion to std::chrono::microseconds. BaseSniffer is now movable. 2012-11-23 20:30:16 -03:00
Matias Fontanini
b74a353c17 Added packet.h and timestamp.h to tins.h 2012-11-23 18:56:39 -03:00
Matias Fontanini
492fd611f9 Added Packet and some wrapper packet classes. Modified the return value of BaseSniffer::next_packet. 2012-11-23 18:10:51 -03:00
Matias Fontanini
a938d2ecfd Added support for IPv6 extension headers. Specific headers getters and setters are not yet implemented. 2012-11-22 17:18:59 -03:00
Matias Fontanini
8276e7d086 Added IPv6 class. It's working, but there's no support for extension headers yet. 2012-11-21 22:09:58 -03:00
Matias Fontanini
ffdfb160c4 Added ipv6_address.h include to tins.h. 2012-11-21 15:52:31 -03:00
Matias Fontanini
bf6c086b3d Added BaseSniffer::timestamp method. 2012-11-21 13:33:28 -03:00
Matias Fontanini
08b4c92dac Added support for IPv6 addresses in DNS. 2012-11-20 23:57:02 -03:00
Matias Fontanini
2a0b248518 Added IPv6Address. 2012-11-20 23:46:22 -03:00
Matias Fontanini
60323ded9b AAAA records are now parsed correctly. 2012-11-20 21:19:05 -03:00
Matias Fontanini
f3ea99e0b0 Used a better strategy in DNSResourceRecord's constructor from buffer which will parse the data even if contains_dname returns false. 2012-11-20 18:31:33 -03:00
Matias Fontanini
7e080cf1ab Added some missing DNS record types which contain domain names to the 'contains_dname' helper function. 2012-11-20 18:27:59 -03:00
Matias Fontanini
688be1e1da Fixed the try/catch block in BaseSniffer::sniff_loop. It now only catches std::runtime_errors. 2012-11-20 16:33:26 -03:00
Bruno Nery
28e5df3abc Fixed BaseSniffer::next_packet() to return when error occurred. Updated its documentation.
Signed-off-by: Matias Fontanini <matias.fontanini@gmail.com>
2012-11-20 16:30:34 -03:00
Matias Fontanini
d0048e3aef Fixed bug in DNS triggered when adding two records for the same domain name. 2012-11-20 16:10:24 -03:00
164 changed files with 54993 additions and 4223 deletions

11
AUTHORS
View File

@@ -1,2 +1,9 @@
Matias Fontanini - mfontanini@nasel.com.ar
Santiago Alessandri - salessandri@nasel.com.ar
# Below is a list of people and organizations that have contributed source
# code to libtins. Names are listed using the following format:
#
# Name/Organization <email address>
Matias Fontanini <matias.fontanini@gmail.com>
Santiago Alessandri <san.lt.ss@gmail.com>
Bruno Nery <brunonery@brunonery.com>
Piotr Haber <piotr.haber@sens.us>

79
CHANGES Normal file
View File

@@ -0,0 +1,79 @@
v1.0 - Tue Apr 23 20:40:57 ART 2013
- Link layer protocol PDUs now don't hold a NetworkInterface. This led
to changes in their constructors.
- Removed the obsolete PDU* parameter taken by several classes'
constructors.
- IP now sets the sender's address automatically when no link layer
PDU is used.
- IP, TCP and UDP now calculate the checksum everytime they're
serialized.
- Added PDU::rfind_pdu.
- Defined several exception types.
- Implemented matches_response on several protocols.
- PacketSender is now movable.
- Added an overload of add_option that takes an rvalue-reference in IP,
TCP, DHCP, ICMPv6 and Dot11.
- Added support for GNU/kFreeBSD.
- Removed several deprecated methods, such as PDU::clone_packet.
- Added PacketSender::send(PDU&, NetworkInterface).
- Normalized the TLV options naming conventions in all of the classes
that used them.
- Added support for Dot1Q, STP, PPPoE protocols.
- Made some important optimizations on PDUOption<>'s constructors.
- Added Utils::resolve_domain and Utils::resolve_domain6
v0.3 - Thu Jan 31 16:47:27 ART 2013
- Added IPv6, ICMPv6 and DHCPv6 classes.
- Added support for Loopback interfaces and the Linux Crooked Capture
pseudo protocol.
- Added support for IPv6 records in DNS.
- Added Packet/RefPacket class.
- Added support for FreeBSD, OSX and Windows.
- Added C++11 move semantics to several classes.
- Done a complete rewrite of the build system; it now uses libtool.
- Fixed several bugs in DNS.
v0.2 - Sat Oct 20 11:26:40 2012
- Added support for big endian architectures.
- Simplified several interfaces.
- Added IPv4Address and HWAddress class to simplify handling IP and hardware addresses.
- Added NetworkInterface class to abstract network interfaces.
- Added TCPStreamFollower class to follow TCP streams on the fly.
- Added WEPDecrypter class to decrypt WEP-encrypted 802.11 data frames on the fly.
- Added several new PDUs: Loopback, IEEE802_3, LLC, DNS.
- Added support for reading and writing pcap files.
- Moved to BSD-2 license.

View File

@@ -31,14 +31,14 @@ PROJECT_NAME = libtins
# This could be handy for archiving the generated documentation or
# if some version control system is used.
PROJECT_NUMBER = 0.1
PROJECT_NUMBER = 1.0
# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
# base path where the generated documentation will be put.
# If a relative path is entered, it will be relative to the location
# where doxygen was started. If left blank the current directory will be used.
OUTPUT_DIRECTORY = docs/
OUTPUT_DIRECTORY = ../docs/
# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create
# 4096 sub-directories (in 2 levels) under the output directory of each output

101
Makefile.am Normal file
View File

@@ -0,0 +1,101 @@
AUTOMAKE_OPTIONS=subdir-objects
ACLOCAL_AMFLAGS=${ACLOCAL_FLAGS} -I m4
# pkg-config stuff
pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_DATA = libtins.pc
lib_LTLIBRARIES=libtins.la
libtins_la_LDFLAGS = -version-info @LIBTINS_VERSION@
AM_CXXFLAGS = -Wall -pedantic -I@LIBTINS_INCLUDE_DIR@
libtins_la_SOURCES=src/arp.cpp \
src/bootp.cpp \
src/stp.cpp \
src/pppoe.cpp \
src/crypto.cpp \
src/dhcp.cpp \
src/dhcpv6.cpp \
src/dns.cpp \
src/dns_record.cpp \
src/dot11.cpp \
src/dot3.cpp \
src/dot1q.cpp \
src/eapol.cpp \
src/ethernetII.cpp \
src/icmp.cpp \
src/icmpv6.cpp \
src/internals.cpp \
src/ip.cpp src/ip_address.cpp \
src/ipv6.cpp \
src/ipv6_address.cpp \
src/llc.cpp \
src/loopback.cpp \
src/network_interface.cpp \
src/packet_sender.cpp \
src/packet_writer.cpp \
src/pdu.cpp \
src/radiotap.cpp \
src/rawpdu.cpp \
src/rsn_information.cpp \
src/sll.cpp \
src/snap.cpp \
src/sniffer.cpp \
src/tcp.cpp \
src/tcp_stream.cpp \
src/udp.cpp \
src/utils.cpp
libtins_includedir = $(includedir)/tins
libtins_include_HEADERS = include/internals.h \
include/dhcpv6.h \
include/dot11.h \
include/dot1q.h \
include/dot3.h \
include/small_uint.h \
include/ip.h \
include/dns_record.h \
include/eapol.h \
include/tcp_stream.h \
include/pppoe.h \
include/ipv6.h \
include/icmpv6.h \
include/ieee802_3.h \
include/endianness.h \
include/rsn_information.h \
include/loopback.h \
include/ethernetII.h \
include/crypto.h \
include/packet.h \
include/llc.h \
include/icmp.h \
include/hw_address.h \
include/packet_writer.h \
include/macros.h \
include/arp.h \
include/ip_address.h \
include/pdu.h \
include/packet_sender.h \
include/bootp.h \
include/network_interface.h \
include/sll.h \
include/radiotap.h \
include/dns.h \
include/rawpdu.h \
include/sniffer.h \
include/snap.h \
include/pdu_cacher.h \
include/dhcp.h \
include/timestamp.h \
include/tcp.h \
include/pdu_option.h \
include/tins.h \
include/udp.h \
include/ipv6_address.h \
include/constants.h \
include/utils.h \
include/cxxstd.h \
include/stp.h \
include/exceptions.h

File diff suppressed because it is too large Load Diff

58
README Normal file
View File

@@ -0,0 +1,58 @@
------------------------------------------------------------------------
libtins v1.0
------------------------------------------------------------------------
-------------------------------- About ---------------------------------
libtins is a C++ library for crafting, sending, sniffing and
interpreting raw network packets.
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:
http://libtins.sourceforge.net
------------------------------- Compiling ------------------------------
In order to compile, execute:
./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:
./configure --enable-static
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:
./configure --enable-c++11
------------------------------ Installing-------------------------------
Once you're done, if you want to install the header files and the
shared object, execute as root:
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):
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.sourceforge.net/index.php?page=examples

4
THANKS Normal file
View File

@@ -0,0 +1,4 @@
We'd like to thank the following people, who have been of great help
through the development of libtins:
- Raúl Benencia <rbenencia@gmail.com> - For creating the Debian package.

1017
aclocal.m4 vendored Normal file

File diff suppressed because it is too large Load Diff

1530
config.guess vendored Executable file

File diff suppressed because it is too large Load Diff

1782
config.sub vendored Executable file

File diff suppressed because it is too large Load Diff

14932
configure vendored

File diff suppressed because it is too large Load Diff

View File

@@ -1,16 +1,52 @@
AC_INIT(myconfig, 0.2)
AC_INIT([libtins], [1.0], [matias.fontanini@gmail.com], [libtins], [http://libtins.sourceforge.net])
AC_CANONICAL_SYSTEM
AC_CONFIG_HEADER(include/config.h)
AM_INIT_AUTOMAKE([-Wall -Werror])
LT_INIT([disable-static])
AC_CONFIG_MACRO_DIR([m4])
AM_MAINTAINER_MODE([enable])
AC_PROG_CXX()
AC_PROG_CXX
AC_LANG(C++)
if test -n "$debug"
then
CFLAGS="-DDEBUG -g"
else
CFLAGS="-O3"
fi
AC_PROG_LIBTOOL
AC_CHECK_HEADERS([pcap.h])
AC_CHECK_LIB(pcap, pcap_loop, [], [AC_MSG_ERROR([pcap library is needed!])])
AC_SUBST(CFLAGS)
AC_OUTPUT(Makefile)
# Check that libpcap exists
AC_ARG_WITH([pcap-include-path],
[AS_HELP_STRING([--with-pcap-include-path],
[location of the libpcap headers, defaults to /usr/include/pcap])],
[CXXFLAGS="$CXXFLAGS -I$withval"; CPPFLAGS="-I$withval"])
AC_ARG_WITH([pcap-lib-path],
[AS_HELP_STRING([--with-pcap-lib-path], [location of the libpcap libraries])],
[LIBS="$LIBS -L$withval"])
AC_CHECK_LIB(pcap, pcap_loop, [], [AC_MSG_ERROR([pcap library is missing!])])
old_cppflags=$CPPFLAGS
CPPFLAGS=""
# Headers
LIBTINS_INCLUDE_DIR="include"
AC_CHECK_HEADERS([pcap.h], [], [AC_MSG_ERROR([libpcap headers are missing!])])
CPPFLAGS=$old_cppflags
# Options
AC_ARG_ENABLE(
c++11,
[ --enable-c++11 enable C++11 features],
[AX_CXX_COMPILE_STDCXX_11(noext)]
)
# Substitute options
AC_SUBST(CXXFLAGS)
AC_SUBST(LIBS)
AC_SUBST(LIBTINS_INCLUDE_DIR)
AC_SUBST([LIBTINS_VERSION], [1:0:0])
AC_CONFIG_FILES([Makefile libtins.pc])
AC_OUTPUT

708
depcomp Executable file
View File

@@ -0,0 +1,708 @@
#! /bin/sh
# depcomp - compile a program generating dependencies as side-effects
scriptversion=2012-03-27.16; # UTC
# Copyright (C) 1999, 2000, 2003, 2004, 2005, 2006, 2007, 2009, 2010,
# 2011, 2012 Free Software Foundation, Inc.
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2, or (at your option)
# any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# As a special exception to the GNU General Public License, if you
# distribute this file as part of a program that contains a
# configuration script generated by Autoconf, you may include it under
# the same distribution terms that you use for the rest of that program.
# Originally written by Alexandre Oliva <oliva@dcc.unicamp.br>.
case $1 in
'')
echo "$0: No command. Try '$0 --help' for more information." 1>&2
exit 1;
;;
-h | --h*)
cat <<\EOF
Usage: depcomp [--help] [--version] PROGRAM [ARGS]
Run PROGRAMS ARGS to compile a file, generating dependencies
as side-effects.
Environment variables:
depmode Dependency tracking mode.
source Source file read by 'PROGRAMS ARGS'.
object Object file output by 'PROGRAMS ARGS'.
DEPDIR directory where to store dependencies.
depfile Dependency file to output.
tmpdepfile Temporary file to use when outputting dependencies.
libtool Whether libtool is used (yes/no).
Report bugs to <bug-automake@gnu.org>.
EOF
exit $?
;;
-v | --v*)
echo "depcomp $scriptversion"
exit $?
;;
esac
# A tabulation character.
tab=' '
# A newline character.
nl='
'
if test -z "$depmode" || test -z "$source" || test -z "$object"; then
echo "depcomp: Variables source, object and depmode must be set" 1>&2
exit 1
fi
# Dependencies for sub/bar.o or sub/bar.obj go into sub/.deps/bar.Po.
depfile=${depfile-`echo "$object" |
sed 's|[^\\/]*$|'${DEPDIR-.deps}'/&|;s|\.\([^.]*\)$|.P\1|;s|Pobj$|Po|'`}
tmpdepfile=${tmpdepfile-`echo "$depfile" | sed 's/\.\([^.]*\)$/.T\1/'`}
rm -f "$tmpdepfile"
# Some modes work just like other modes, but use different flags. We
# parameterize here, but still list the modes in the big case below,
# to make depend.m4 easier to write. Note that we *cannot* use a case
# here, because this file can only contain one case statement.
if test "$depmode" = hp; then
# HP compiler uses -M and no extra arg.
gccflag=-M
depmode=gcc
fi
if test "$depmode" = dashXmstdout; then
# This is just like dashmstdout with a different argument.
dashmflag=-xM
depmode=dashmstdout
fi
cygpath_u="cygpath -u -f -"
if test "$depmode" = msvcmsys; then
# This is just like msvisualcpp but w/o cygpath translation.
# Just convert the backslash-escaped backslashes to single forward
# slashes to satisfy depend.m4
cygpath_u='sed s,\\\\,/,g'
depmode=msvisualcpp
fi
if test "$depmode" = msvc7msys; then
# This is just like msvc7 but w/o cygpath translation.
# Just convert the backslash-escaped backslashes to single forward
# slashes to satisfy depend.m4
cygpath_u='sed s,\\\\,/,g'
depmode=msvc7
fi
if test "$depmode" = xlc; then
# IBM C/C++ Compilers xlc/xlC can output gcc-like dependency informations.
gccflag=-qmakedep=gcc,-MF
depmode=gcc
fi
case "$depmode" in
gcc3)
## gcc 3 implements dependency tracking that does exactly what
## we want. Yay! Note: for some reason libtool 1.4 doesn't like
## it if -MD -MP comes after the -MF stuff. Hmm.
## Unfortunately, FreeBSD c89 acceptance of flags depends upon
## the command line argument order; so add the flags where they
## appear in depend2.am. Note that the slowdown incurred here
## affects only configure: in makefiles, %FASTDEP% shortcuts this.
for arg
do
case $arg in
-c) set fnord "$@" -MT "$object" -MD -MP -MF "$tmpdepfile" "$arg" ;;
*) set fnord "$@" "$arg" ;;
esac
shift # fnord
shift # $arg
done
"$@"
stat=$?
if test $stat -eq 0; then :
else
rm -f "$tmpdepfile"
exit $stat
fi
mv "$tmpdepfile" "$depfile"
;;
gcc)
## There are various ways to get dependency output from gcc. Here's
## why we pick this rather obscure method:
## - Don't want to use -MD because we'd like the dependencies to end
## up in a subdir. Having to rename by hand is ugly.
## (We might end up doing this anyway to support other compilers.)
## - The DEPENDENCIES_OUTPUT environment variable makes gcc act like
## -MM, not -M (despite what the docs say).
## - Using -M directly means running the compiler twice (even worse
## than renaming).
if test -z "$gccflag"; then
gccflag=-MD,
fi
"$@" -Wp,"$gccflag$tmpdepfile"
stat=$?
if test $stat -eq 0; then :
else
rm -f "$tmpdepfile"
exit $stat
fi
rm -f "$depfile"
echo "$object : \\" > "$depfile"
alpha=ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz
## The second -e expression handles DOS-style file names with drive letters.
sed -e 's/^[^:]*: / /' \
-e 's/^['$alpha']:\/[^:]*: / /' < "$tmpdepfile" >> "$depfile"
## This next piece of magic avoids the "deleted header file" problem.
## The problem is that when a header file which appears in a .P file
## is deleted, the dependency causes make to die (because there is
## typically no way to rebuild the header). We avoid this by adding
## dummy dependencies for each header file. Too bad gcc doesn't do
## this for us directly.
tr ' ' "$nl" < "$tmpdepfile" |
## Some versions of gcc put a space before the ':'. On the theory
## that the space means something, we add a space to the output as
## well. hp depmode also adds that space, but also prefixes the VPATH
## to the object. Take care to not repeat it in the output.
## Some versions of the HPUX 10.20 sed can't process this invocation
## correctly. Breaking it into two sed invocations is a workaround.
sed -e 's/^\\$//' -e '/^$/d' -e "s|.*$object$||" -e '/:$/d' \
| sed -e 's/$/ :/' >> "$depfile"
rm -f "$tmpdepfile"
;;
hp)
# This case exists only to let depend.m4 do its work. It works by
# looking at the text of this script. This case will never be run,
# since it is checked for above.
exit 1
;;
sgi)
if test "$libtool" = yes; then
"$@" "-Wp,-MDupdate,$tmpdepfile"
else
"$@" -MDupdate "$tmpdepfile"
fi
stat=$?
if test $stat -eq 0; then :
else
rm -f "$tmpdepfile"
exit $stat
fi
rm -f "$depfile"
if test -f "$tmpdepfile"; then # yes, the sourcefile depend on other files
echo "$object : \\" > "$depfile"
# Clip off the initial element (the dependent). Don't try to be
# clever and replace this with sed code, as IRIX sed won't handle
# lines with more than a fixed number of characters (4096 in
# IRIX 6.2 sed, 8192 in IRIX 6.5). We also remove comment lines;
# the IRIX cc adds comments like '#:fec' to the end of the
# dependency line.
tr ' ' "$nl" < "$tmpdepfile" \
| sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' | \
tr "$nl" ' ' >> "$depfile"
echo >> "$depfile"
# The second pass generates a dummy entry for each header file.
tr ' ' "$nl" < "$tmpdepfile" \
| sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \
>> "$depfile"
else
# The sourcefile does not contain any dependencies, so just
# store a dummy comment line, to avoid errors with the Makefile
# "include basename.Plo" scheme.
echo "#dummy" > "$depfile"
fi
rm -f "$tmpdepfile"
;;
xlc)
# This case exists only to let depend.m4 do its work. It works by
# looking at the text of this script. This case will never be run,
# since it is checked for above.
exit 1
;;
aix)
# The C for AIX Compiler uses -M and outputs the dependencies
# in a .u file. In older versions, this file always lives in the
# current directory. Also, the AIX compiler puts '$object:' at the
# start of each line; $object doesn't have directory information.
# Version 6 uses the directory in both cases.
dir=`echo "$object" | sed -e 's|/[^/]*$|/|'`
test "x$dir" = "x$object" && dir=
base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'`
if test "$libtool" = yes; then
tmpdepfile1=$dir$base.u
tmpdepfile2=$base.u
tmpdepfile3=$dir.libs/$base.u
"$@" -Wc,-M
else
tmpdepfile1=$dir$base.u
tmpdepfile2=$dir$base.u
tmpdepfile3=$dir$base.u
"$@" -M
fi
stat=$?
if test $stat -eq 0; then :
else
rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
exit $stat
fi
for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
do
test -f "$tmpdepfile" && break
done
if test -f "$tmpdepfile"; then
# Each line is of the form 'foo.o: dependent.h'.
# Do two passes, one to just change these to
# '$object: dependent.h' and one to simply 'dependent.h:'.
sed -e "s,^.*\.[a-z]*:,$object:," < "$tmpdepfile" > "$depfile"
sed -e 's,^.*\.[a-z]*:['"$tab"' ]*,,' -e 's,$,:,' < "$tmpdepfile" >> "$depfile"
else
# The sourcefile does not contain any dependencies, so just
# store a dummy comment line, to avoid errors with the Makefile
# "include basename.Plo" scheme.
echo "#dummy" > "$depfile"
fi
rm -f "$tmpdepfile"
;;
icc)
# Intel's C compiler anf tcc (Tiny C Compiler) understand '-MD -MF file'.
# However on
# $CC -MD -MF foo.d -c -o sub/foo.o sub/foo.c
# ICC 7.0 will fill foo.d with something like
# foo.o: sub/foo.c
# foo.o: sub/foo.h
# which is wrong. We want
# sub/foo.o: sub/foo.c
# sub/foo.o: sub/foo.h
# sub/foo.c:
# sub/foo.h:
# ICC 7.1 will output
# foo.o: sub/foo.c sub/foo.h
# and will wrap long lines using '\':
# foo.o: sub/foo.c ... \
# sub/foo.h ... \
# ...
# tcc 0.9.26 (FIXME still under development at the moment of writing)
# will emit a similar output, but also prepend the continuation lines
# with horizontal tabulation characters.
"$@" -MD -MF "$tmpdepfile"
stat=$?
if test $stat -eq 0; then :
else
rm -f "$tmpdepfile"
exit $stat
fi
rm -f "$depfile"
# Each line is of the form 'foo.o: dependent.h',
# or 'foo.o: dep1.h dep2.h \', or ' dep3.h dep4.h \'.
# Do two passes, one to just change these to
# '$object: dependent.h' and one to simply 'dependent.h:'.
sed -e "s/^[ $tab][ $tab]*/ /" -e "s,^[^:]*:,$object :," \
< "$tmpdepfile" > "$depfile"
sed '
s/[ '"$tab"'][ '"$tab"']*/ /g
s/^ *//
s/ *\\*$//
s/^[^:]*: *//
/^$/d
/:$/d
s/$/ :/
' < "$tmpdepfile" >> "$depfile"
rm -f "$tmpdepfile"
;;
hp2)
# The "hp" stanza above does not work with aCC (C++) and HP's ia64
# compilers, which have integrated preprocessors. The correct option
# to use with these is +Maked; it writes dependencies to a file named
# 'foo.d', which lands next to the object file, wherever that
# happens to be.
# Much of this is similar to the tru64 case; see comments there.
dir=`echo "$object" | sed -e 's|/[^/]*$|/|'`
test "x$dir" = "x$object" && dir=
base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'`
if test "$libtool" = yes; then
tmpdepfile1=$dir$base.d
tmpdepfile2=$dir.libs/$base.d
"$@" -Wc,+Maked
else
tmpdepfile1=$dir$base.d
tmpdepfile2=$dir$base.d
"$@" +Maked
fi
stat=$?
if test $stat -eq 0; then :
else
rm -f "$tmpdepfile1" "$tmpdepfile2"
exit $stat
fi
for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2"
do
test -f "$tmpdepfile" && break
done
if test -f "$tmpdepfile"; then
sed -e "s,^.*\.[a-z]*:,$object:," "$tmpdepfile" > "$depfile"
# Add 'dependent.h:' lines.
sed -ne '2,${
s/^ *//
s/ \\*$//
s/$/:/
p
}' "$tmpdepfile" >> "$depfile"
else
echo "#dummy" > "$depfile"
fi
rm -f "$tmpdepfile" "$tmpdepfile2"
;;
tru64)
# The Tru64 compiler uses -MD to generate dependencies as a side
# effect. 'cc -MD -o foo.o ...' puts the dependencies into 'foo.o.d'.
# At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put
# dependencies in 'foo.d' instead, so we check for that too.
# Subdirectories are respected.
dir=`echo "$object" | sed -e 's|/[^/]*$|/|'`
test "x$dir" = "x$object" && dir=
base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'`
if test "$libtool" = yes; then
# With Tru64 cc, shared objects can also be used to make a
# static library. This mechanism is used in libtool 1.4 series to
# handle both shared and static libraries in a single compilation.
# With libtool 1.4, dependencies were output in $dir.libs/$base.lo.d.
#
# With libtool 1.5 this exception was removed, and libtool now
# generates 2 separate objects for the 2 libraries. These two
# compilations output dependencies in $dir.libs/$base.o.d and
# in $dir$base.o.d. We have to check for both files, because
# one of the two compilations can be disabled. We should prefer
# $dir$base.o.d over $dir.libs/$base.o.d because the latter is
# automatically cleaned when .libs/ is deleted, while ignoring
# the former would cause a distcleancheck panic.
tmpdepfile1=$dir.libs/$base.lo.d # libtool 1.4
tmpdepfile2=$dir$base.o.d # libtool 1.5
tmpdepfile3=$dir.libs/$base.o.d # libtool 1.5
tmpdepfile4=$dir.libs/$base.d # Compaq CCC V6.2-504
"$@" -Wc,-MD
else
tmpdepfile1=$dir$base.o.d
tmpdepfile2=$dir$base.d
tmpdepfile3=$dir$base.d
tmpdepfile4=$dir$base.d
"$@" -MD
fi
stat=$?
if test $stat -eq 0; then :
else
rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" "$tmpdepfile4"
exit $stat
fi
for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" "$tmpdepfile4"
do
test -f "$tmpdepfile" && break
done
if test -f "$tmpdepfile"; then
sed -e "s,^.*\.[a-z]*:,$object:," < "$tmpdepfile" > "$depfile"
sed -e 's,^.*\.[a-z]*:['"$tab"' ]*,,' -e 's,$,:,' < "$tmpdepfile" >> "$depfile"
else
echo "#dummy" > "$depfile"
fi
rm -f "$tmpdepfile"
;;
msvc7)
if test "$libtool" = yes; then
showIncludes=-Wc,-showIncludes
else
showIncludes=-showIncludes
fi
"$@" $showIncludes > "$tmpdepfile"
stat=$?
grep -v '^Note: including file: ' "$tmpdepfile"
if test "$stat" = 0; then :
else
rm -f "$tmpdepfile"
exit $stat
fi
rm -f "$depfile"
echo "$object : \\" > "$depfile"
# The first sed program below extracts the file names and escapes
# backslashes for cygpath. The second sed program outputs the file
# name when reading, but also accumulates all include files in the
# hold buffer in order to output them again at the end. This only
# works with sed implementations that can handle large buffers.
sed < "$tmpdepfile" -n '
/^Note: including file: *\(.*\)/ {
s//\1/
s/\\/\\\\/g
p
}' | $cygpath_u | sort -u | sed -n '
s/ /\\ /g
s/\(.*\)/'"$tab"'\1 \\/p
s/.\(.*\) \\/\1:/
H
$ {
s/.*/'"$tab"'/
G
p
}' >> "$depfile"
rm -f "$tmpdepfile"
;;
msvc7msys)
# This case exists only to let depend.m4 do its work. It works by
# looking at the text of this script. This case will never be run,
# since it is checked for above.
exit 1
;;
#nosideeffect)
# This comment above is used by automake to tell side-effect
# dependency tracking mechanisms from slower ones.
dashmstdout)
# Important note: in order to support this mode, a compiler *must*
# always write the preprocessed file to stdout, regardless of -o.
"$@" || exit $?
# Remove the call to Libtool.
if test "$libtool" = yes; then
while test "X$1" != 'X--mode=compile'; do
shift
done
shift
fi
# Remove '-o $object'.
IFS=" "
for arg
do
case $arg in
-o)
shift
;;
$object)
shift
;;
*)
set fnord "$@" "$arg"
shift # fnord
shift # $arg
;;
esac
done
test -z "$dashmflag" && dashmflag=-M
# Require at least two characters before searching for ':'
# in the target name. This is to cope with DOS-style filenames:
# a dependency such as 'c:/foo/bar' could be seen as target 'c' otherwise.
"$@" $dashmflag |
sed 's:^['"$tab"' ]*[^:'"$tab"' ][^:][^:]*\:['"$tab"' ]*:'"$object"'\: :' > "$tmpdepfile"
rm -f "$depfile"
cat < "$tmpdepfile" > "$depfile"
tr ' ' "$nl" < "$tmpdepfile" | \
## Some versions of the HPUX 10.20 sed can't process this invocation
## correctly. Breaking it into two sed invocations is a workaround.
sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile"
rm -f "$tmpdepfile"
;;
dashXmstdout)
# This case only exists to satisfy depend.m4. It is never actually
# run, as this mode is specially recognized in the preamble.
exit 1
;;
makedepend)
"$@" || exit $?
# Remove any Libtool call
if test "$libtool" = yes; then
while test "X$1" != 'X--mode=compile'; do
shift
done
shift
fi
# X makedepend
shift
cleared=no eat=no
for arg
do
case $cleared in
no)
set ""; shift
cleared=yes ;;
esac
if test $eat = yes; then
eat=no
continue
fi
case "$arg" in
-D*|-I*)
set fnord "$@" "$arg"; shift ;;
# Strip any option that makedepend may not understand. Remove
# the object too, otherwise makedepend will parse it as a source file.
-arch)
eat=yes ;;
-*|$object)
;;
*)
set fnord "$@" "$arg"; shift ;;
esac
done
obj_suffix=`echo "$object" | sed 's/^.*\././'`
touch "$tmpdepfile"
${MAKEDEPEND-makedepend} -o"$obj_suffix" -f"$tmpdepfile" "$@"
rm -f "$depfile"
# makedepend may prepend the VPATH from the source file name to the object.
# No need to regex-escape $object, excess matching of '.' is harmless.
sed "s|^.*\($object *:\)|\1|" "$tmpdepfile" > "$depfile"
sed '1,2d' "$tmpdepfile" | tr ' ' "$nl" | \
## Some versions of the HPUX 10.20 sed can't process this invocation
## correctly. Breaking it into two sed invocations is a workaround.
sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile"
rm -f "$tmpdepfile" "$tmpdepfile".bak
;;
cpp)
# Important note: in order to support this mode, a compiler *must*
# always write the preprocessed file to stdout.
"$@" || exit $?
# Remove the call to Libtool.
if test "$libtool" = yes; then
while test "X$1" != 'X--mode=compile'; do
shift
done
shift
fi
# Remove '-o $object'.
IFS=" "
for arg
do
case $arg in
-o)
shift
;;
$object)
shift
;;
*)
set fnord "$@" "$arg"
shift # fnord
shift # $arg
;;
esac
done
"$@" -E |
sed -n -e '/^# [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \
-e '/^#line [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' |
sed '$ s: \\$::' > "$tmpdepfile"
rm -f "$depfile"
echo "$object : \\" > "$depfile"
cat < "$tmpdepfile" >> "$depfile"
sed < "$tmpdepfile" '/^$/d;s/^ //;s/ \\$//;s/$/ :/' >> "$depfile"
rm -f "$tmpdepfile"
;;
msvisualcpp)
# Important note: in order to support this mode, a compiler *must*
# always write the preprocessed file to stdout.
"$@" || exit $?
# Remove the call to Libtool.
if test "$libtool" = yes; then
while test "X$1" != 'X--mode=compile'; do
shift
done
shift
fi
IFS=" "
for arg
do
case "$arg" in
-o)
shift
;;
$object)
shift
;;
"-Gm"|"/Gm"|"-Gi"|"/Gi"|"-ZI"|"/ZI")
set fnord "$@"
shift
shift
;;
*)
set fnord "$@" "$arg"
shift
shift
;;
esac
done
"$@" -E 2>/dev/null |
sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::\1:p' | $cygpath_u | sort -u > "$tmpdepfile"
rm -f "$depfile"
echo "$object : \\" > "$depfile"
sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::'"$tab"'\1 \\:p' >> "$depfile"
echo "$tab" >> "$depfile"
sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::\1\::p' >> "$depfile"
rm -f "$tmpdepfile"
;;
msvcmsys)
# This case exists only to let depend.m4 do its work. It works by
# looking at the text of this script. This case will never be run,
# since it is checked for above.
exit 1
;;
none)
exec "$@"
;;
*)
echo "Unknown depmode $depmode" 1>&2
exit 1
;;
esac
exit 0
# Local Variables:
# mode: shell-script
# sh-indentation: 2
# eval: (add-hook 'write-file-hooks 'time-stamp)
# time-stamp-start: "scriptversion="
# time-stamp-format: "%:y-%02m-%02d.%02H"
# time-stamp-time-zone: "UTC"
# time-stamp-end: "; # UTC"
# End:

558
depends.d
View File

@@ -1,558 +0,0 @@
src/arp.o: src/arp.cpp include/arp.h include/pdu.h include/endianness.h \
include/hw_address.h include/ip_address.h include/ip.h \
include/small_uint.h include/pdu_option.h include/ethernetII.h \
include/network_interface.h include/rawpdu.h include/constants.h \
include/network_interface.h
include/arp.h:
include/pdu.h:
include/endianness.h:
include/hw_address.h:
include/ip_address.h:
include/ip.h:
include/small_uint.h:
include/pdu_option.h:
include/ethernetII.h:
include/network_interface.h:
include/rawpdu.h:
include/constants.h:
include/network_interface.h:
src/bootp.o: src/bootp.cpp include/bootp.h include/pdu.h \
include/endianness.h include/ip_address.h include/hw_address.h
include/bootp.h:
include/pdu.h:
include/endianness.h:
include/ip_address.h:
include/hw_address.h:
src/crypto.o: src/crypto.cpp include/crypto.h include/dot11.h \
include/pdu.h include/endianness.h include/hw_address.h \
include/small_uint.h include/pdu_option.h include/network_interface.h \
include/ip_address.h include/utils.h include/snap.h include/rawpdu.h
include/crypto.h:
include/dot11.h:
include/pdu.h:
include/endianness.h:
include/hw_address.h:
include/small_uint.h:
include/pdu_option.h:
include/network_interface.h:
include/ip_address.h:
include/utils.h:
include/snap.h:
include/rawpdu.h:
src/dhcp.o: src/dhcp.cpp include/endianness.h include/dhcp.h \
include/bootp.h include/pdu.h include/endianness.h include/ip_address.h \
include/hw_address.h include/pdu_option.h include/ethernetII.h \
include/network_interface.h
include/endianness.h:
include/dhcp.h:
include/bootp.h:
include/pdu.h:
include/endianness.h:
include/ip_address.h:
include/hw_address.h:
include/pdu_option.h:
include/ethernetII.h:
include/network_interface.h:
src/dns.o: src/dns.cpp include/dns.h include/pdu.h include/endianness.h \
include/dns_record.h include/ip_address.h
include/dns.h:
include/pdu.h:
include/endianness.h:
include/dns_record.h:
include/ip_address.h:
src/dns_record.o: src/dns_record.cpp include/dns_record.h \
include/endianness.h
include/dns_record.h:
include/endianness.h:
src/dot11.o: src/dot11.cpp include/dot11.h include/pdu.h \
include/endianness.h include/hw_address.h include/small_uint.h \
include/pdu_option.h include/network_interface.h include/ip_address.h \
include/rawpdu.h include/radiotap.h include/rsn_information.h \
include/packet_sender.h include/snap.h
include/dot11.h:
include/pdu.h:
include/endianness.h:
include/hw_address.h:
include/small_uint.h:
include/pdu_option.h:
include/network_interface.h:
include/ip_address.h:
include/rawpdu.h:
include/radiotap.h:
include/rsn_information.h:
include/packet_sender.h:
include/snap.h:
src/eapol.o: src/eapol.cpp include/eapol.h include/pdu.h \
include/small_uint.h include/endianness.h include/dot11.h \
include/hw_address.h include/pdu_option.h include/network_interface.h \
include/ip_address.h include/rsn_information.h
include/eapol.h:
include/pdu.h:
include/small_uint.h:
include/endianness.h:
include/dot11.h:
include/hw_address.h:
include/pdu_option.h:
include/network_interface.h:
include/ip_address.h:
include/rsn_information.h:
src/ethernetII.o: src/ethernetII.cpp include/ethernetII.h include/pdu.h \
include/endianness.h include/hw_address.h include/network_interface.h \
include/ip_address.h include/packet_sender.h include/rawpdu.h \
include/ip.h include/small_uint.h include/pdu_option.h include/arp.h \
include/constants.h
include/ethernetII.h:
include/pdu.h:
include/endianness.h:
include/hw_address.h:
include/network_interface.h:
include/ip_address.h:
include/packet_sender.h:
include/rawpdu.h:
include/ip.h:
include/small_uint.h:
include/pdu_option.h:
include/arp.h:
include/constants.h:
src/icmp.o: src/icmp.cpp include/icmp.h include/pdu.h \
include/endianness.h include/rawpdu.h include/utils.h \
include/ip_address.h include/hw_address.h
include/icmp.h:
include/pdu.h:
include/endianness.h:
include/rawpdu.h:
include/utils.h:
include/ip_address.h:
include/hw_address.h:
src/ieee802_3.o: src/ieee802_3.cpp include/ieee802_3.h include/pdu.h \
include/endianness.h include/hw_address.h include/network_interface.h \
include/ip_address.h include/packet_sender.h include/llc.h
include/ieee802_3.h:
include/pdu.h:
include/endianness.h:
include/hw_address.h:
include/network_interface.h:
include/ip_address.h:
include/packet_sender.h:
include/llc.h:
src/ip_address.o: src/ip_address.cpp include/ip_address.h \
include/endianness.h
include/ip_address.h:
include/endianness.h:
src/ip.o: src/ip.cpp include/ip.h include/pdu.h include/small_uint.h \
include/endianness.h include/ip_address.h include/pdu_option.h \
include/tcp.h include/udp.h include/icmp.h include/rawpdu.h \
include/utils.h include/hw_address.h include/packet_sender.h \
include/constants.h
include/ip.h:
include/pdu.h:
include/small_uint.h:
include/endianness.h:
include/ip_address.h:
include/pdu_option.h:
include/tcp.h:
include/udp.h:
include/icmp.h:
include/rawpdu.h:
include/utils.h:
include/hw_address.h:
include/packet_sender.h:
include/constants.h:
src/llc.o: src/llc.cpp include/pdu.h include/llc.h include/pdu.h \
include/endianness.h include/rawpdu.h
include/pdu.h:
include/llc.h:
include/pdu.h:
include/endianness.h:
include/rawpdu.h:
src/loopback.o: src/loopback.cpp include/loopback.h include/pdu.h \
include/packet_sender.h include/ip.h include/small_uint.h \
include/endianness.h include/ip_address.h include/pdu_option.h \
include/llc.h include/rawpdu.h
include/loopback.h:
include/pdu.h:
include/packet_sender.h:
include/ip.h:
include/small_uint.h:
include/endianness.h:
include/ip_address.h:
include/pdu_option.h:
include/llc.h:
include/rawpdu.h:
src/network_interface.o: src/network_interface.cpp \
include/network_interface.h include/hw_address.h include/ip_address.h \
include/utils.h include/endianness.h
include/network_interface.h:
include/hw_address.h:
include/ip_address.h:
include/utils.h:
include/endianness.h:
src/packet_sender.o: src/packet_sender.cpp include/pdu.h \
include/packet_sender.h
include/pdu.h:
include/packet_sender.h:
src/packet_writer.o: src/packet_writer.cpp include/packet_writer.h \
include/pdu.h
include/packet_writer.h:
include/pdu.h:
src/pdu.o: src/pdu.cpp include/pdu.h include/rawpdu.h include/pdu.h \
include/packet_sender.h
include/pdu.h:
include/rawpdu.h:
include/pdu.h:
include/packet_sender.h:
src/radiotap.o: src/radiotap.cpp include/radiotap.h include/pdu.h \
include/endianness.h include/network_interface.h include/hw_address.h \
include/ip_address.h include/dot11.h include/small_uint.h \
include/pdu_option.h include/utils.h include/packet_sender.h
include/radiotap.h:
include/pdu.h:
include/endianness.h:
include/network_interface.h:
include/hw_address.h:
include/ip_address.h:
include/dot11.h:
include/small_uint.h:
include/pdu_option.h:
include/utils.h:
include/packet_sender.h:
src/rawpdu.o: src/rawpdu.cpp include/rawpdu.h include/pdu.h
include/rawpdu.h:
include/pdu.h:
src/rsn_information.o: src/rsn_information.cpp include/rsn_information.h \
include/endianness.h
include/rsn_information.h:
include/endianness.h:
src/snap.o: src/snap.cpp include/snap.h include/pdu.h \
include/endianness.h include/small_uint.h include/constants.h \
include/arp.h include/hw_address.h include/ip_address.h include/ip.h \
include/pdu_option.h include/eapol.h
include/snap.h:
include/pdu.h:
include/endianness.h:
include/small_uint.h:
include/constants.h:
include/arp.h:
include/hw_address.h:
include/ip_address.h:
include/ip.h:
include/pdu_option.h:
include/eapol.h:
src/sniffer.o: src/sniffer.cpp include/sniffer.h include/pdu.h \
include/ethernetII.h include/endianness.h include/hw_address.h \
include/network_interface.h include/ip_address.h include/radiotap.h \
include/loopback.h include/dot11.h include/small_uint.h \
include/pdu_option.h
include/sniffer.h:
include/pdu.h:
include/ethernetII.h:
include/endianness.h:
include/hw_address.h:
include/network_interface.h:
include/ip_address.h:
include/radiotap.h:
include/loopback.h:
include/dot11.h:
include/small_uint.h:
include/pdu_option.h:
src/tcp.o: src/tcp.cpp include/tcp.h include/pdu.h include/endianness.h \
include/small_uint.h include/pdu_option.h include/ip.h \
include/ip_address.h include/constants.h include/rawpdu.h \
include/utils.h include/hw_address.h
include/tcp.h:
include/pdu.h:
include/endianness.h:
include/small_uint.h:
include/pdu_option.h:
include/ip.h:
include/ip_address.h:
include/constants.h:
include/rawpdu.h:
include/utils.h:
include/hw_address.h:
src/tcp_stream.o: src/tcp_stream.cpp include/rawpdu.h include/pdu.h \
include/tcp_stream.h include/sniffer.h include/ethernetII.h \
include/endianness.h include/hw_address.h include/network_interface.h \
include/ip_address.h include/radiotap.h include/loopback.h \
include/dot11.h include/small_uint.h include/pdu_option.h include/tcp.h \
include/ip.h
include/rawpdu.h:
include/pdu.h:
include/tcp_stream.h:
include/sniffer.h:
include/ethernetII.h:
include/endianness.h:
include/hw_address.h:
include/network_interface.h:
include/ip_address.h:
include/radiotap.h:
include/loopback.h:
include/dot11.h:
include/small_uint.h:
include/pdu_option.h:
include/tcp.h:
include/ip.h:
src/udp.o: src/udp.cpp include/udp.h include/pdu.h include/endianness.h \
include/constants.h include/utils.h include/ip_address.h \
include/hw_address.h include/ip.h include/small_uint.h \
include/pdu_option.h include/rawpdu.h
include/udp.h:
include/pdu.h:
include/endianness.h:
include/constants.h:
include/utils.h:
include/ip_address.h:
include/hw_address.h:
include/ip.h:
include/small_uint.h:
include/pdu_option.h:
include/rawpdu.h:
src/utils.o: src/utils.cpp include/utils.h include/ip_address.h \
include/hw_address.h include/pdu.h include/ip.h include/pdu.h \
include/small_uint.h include/endianness.h include/pdu_option.h \
include/arp.h include/endianness.h include/network_interface.h \
include/packet_sender.h
include/utils.h:
include/ip_address.h:
include/hw_address.h:
include/pdu.h:
include/ip.h:
include/pdu.h:
include/small_uint.h:
include/endianness.h:
include/pdu_option.h:
include/arp.h:
include/endianness.h:
include/network_interface.h:
include/packet_sender.h:

View File

@@ -32,6 +32,7 @@
#include <string>
#include <stdexcept>
#include <cstdlib>
#include <unistd.h>
#include <tins/arp.h>
#include <tins/network_interface.h>
#include <tins/utils.h>
@@ -42,23 +43,18 @@ using namespace std;
using namespace Tins;
int do_arp_spoofing(NetworkInterface iface, IPv4Address gw, IPv4Address victim,
void do_arp_spoofing(NetworkInterface iface, IPv4Address gw, IPv4Address victim,
const NetworkInterface::Info &info)
{
PacketSender sender;
EthernetII::address_type gw_hw, victim_hw;
// Resolves gateway's hardware address.
if(!Utils::resolve_hwaddr(iface, gw, &gw_hw, sender)) {
cout << "Could not resolve gateway's ip address.\n";
return 5;
}
gw_hw = Utils::resolve_hwaddr(iface, gw, sender);
// Resolves victim's hardware address.
if(!Utils::resolve_hwaddr(iface, victim, &victim_hw, sender)) {
cout << "Could not resolve victim's ip address.\n";
return 6;
}
victim_hw = Utils::resolve_hwaddr(iface, victim, sender);
// Print out the hw addresses we're using.
cout << " Using gateway hw address: " << gw_hw << "\n";
cout << " Using victim hw address: " << victim_hw << "\n";
@@ -76,12 +72,12 @@ int do_arp_spoofing(NetworkInterface iface, IPv4Address gw, IPv4Address victim,
* We include our hw address as the source address
* in ethernet layer, to avoid possible packet dropping
* performed by any routers. */
EthernetII to_gw(iface, gw_hw, info.hw_addr, gw_arp);
EthernetII to_victim(iface, victim_hw, info.hw_addr, victim_arp);
EthernetII to_gw(gw_hw, info.hw_addr, gw_arp);
EthernetII to_victim(victim_hw, info.hw_addr, victim_arp);
while(true) {
// Just send them once every 5 seconds.
sender.send(to_gw);
sender.send(to_victim);
sender.send(to_gw, iface);
sender.send(to_victim, iface);
sleep(5);
}
}
@@ -115,7 +111,7 @@ int main(int argc, char *argv[]) {
return 3;
}
try {
return do_arp_spoofing(iface, gw, victim, info);
do_arp_spoofing(iface, gw, victim, info);
}
catch(std::runtime_error &ex) {
std::cout << "Runtime error: " << ex.what() << std::endl;

View File

@@ -33,6 +33,7 @@
#include <string>
#include <cstdlib>
#include <pthread.h>
#include <unistd.h>
#include <tins/ip.h>
#include <tins/tcp.h>
#include <tins/ip_address.h>
@@ -96,8 +97,8 @@ void send_syns(const NetworkInterface &iface, IPv4Address dest_ip, const vector<
// Pretend we're the scanned host...
ip.src_addr(dest_ip);
// We use an ethernet pdu, otherwise the kernel will drop it.
EthernetII eth(iface, info.hw_addr, info.hw_addr, ip.clone());
sender.send(eth);
EthernetII eth(info.hw_addr, info.hw_addr, ip.clone());
sender.send(eth, iface);
}
void *thread_proc(void *param) {

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, Nasel
* Copyright (c) 2012, Matias Fontanini
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -31,6 +31,7 @@
#ifndef TINS_ARP_H
#define TINS_ARP_H
#include "macros.h"
#include "pdu.h"
#include "endianness.h"
#include "hw_address.h"
@@ -81,8 +82,14 @@ namespace Tins {
const hwaddress_type &sender_hw = hwaddress_type());
/**
* \brief Constructor which creates an ARP object from a buffer and adds all identifiable
* PDUs found in the buffer as children of this one.
* \brief Constructs an ARP object from a buffer.
*
* If there is not enough size for an ARP header in the buffer,
* a malformed_packet exception is thrown.
*
* If the buffer is bigger than the size of the ARP header,
* then the extra data is stored in a RawPDU.
*
* \param buffer The buffer from which this PDU will be constructed.
* \param total_sz The total size of the buffer.
*/
@@ -229,34 +236,32 @@ namespace Tins {
PDUType pdu_type() const { return PDU::ARP; }
/**
* \brief Creates an ARP Request within a Layer 2 PDU using uint32_t for target and sender.
* \brief Creates an ARP Request within an EthernetII PDU.
*
* Creates an ARP Request PDU and embeds it within a Layer 2 PDU ready to be
* sent. The target and sender's protocol address are given using uint32_t.
* sent.
*
* \param iface string with the interface from where to send the ARP.
* \param target IPv4Address with the target's IP.
* \param sender IPv4Address with the sender's IP.
* \param hw_snd uint8_t array of 6 bytes containing the sender's hardware address.
* \return Returns a EthernetII containing the ARP Request.
*/
static EthernetII make_arp_request(const NetworkInterface& iface, ipaddress_type target,
static EthernetII make_arp_request(ipaddress_type target,
ipaddress_type sender, const hwaddress_type &hw_snd = hwaddress_type());
/**
* \brief Creates an ARP Reply within a Layer 2 PDU using uint32_t for target and sender.
* \brief Creates an ARP Reply within an EthernetII PDU.
*
* Creates an ARP Reply PDU and embeds it within a Layer 2 PDU ready to be
* sent. The target and sender's protocol address are given using uint32_t.
* sent.
*
* \param iface string with the interface from where to send the ARP.
* \param target IPv4Address with the target's IP.
* \param sender IPv4Address with the sender's IP.
* \param hw_tgt uint8_t array of 6 bytes containing the target's hardware address.
* \param hw_snd uint8_t array of 6 bytes containing the sender's hardware address.
* \return Returns an EthetnetII containing the ARP Replay.
*/
static EthernetII make_arp_reply(const NetworkInterface& iface, ipaddress_type target,
static EthernetII make_arp_reply(ipaddress_type target,
ipaddress_type sender, const hwaddress_type &hw_tgt = hwaddress_type(),
const hwaddress_type &hw_snd = hwaddress_type());
@@ -266,17 +271,7 @@ namespace Tins {
* \param ptr The pointer to the buffer.
* \param total_sz The size of the buffer.
*/
bool matches_response(uint8_t *ptr, uint32_t total_sz);
/** \brief Clones this pdu, filling the corresponding header with data
* extracted from a buffer.
*
* \param ptr The pointer to the from from which the data will be extracted.
* \param total_sz The size of the buffer.
* \return The cloned PDU.
* \sa PDU::clone_packet
*/
PDU *clone_packet(const uint8_t *ptr, uint32_t total_sz);
bool matches_response(const uint8_t *ptr, uint32_t total_sz) const;
/**
* \sa PDU::clone
@@ -285,6 +280,7 @@ namespace Tins {
return new ARP(*this);
}
private:
TINS_BEGIN_PACK
struct arphdr {
uint16_t ar_hrd; /* format of hardware address */
uint16_t ar_pro; /* format of protocol address */
@@ -300,11 +296,11 @@ namespace Tins {
uint8_t ar_tha[hwaddress_type::address_size];
/* target IP address */
uint32_t ar_tip;
} __attribute__((__packed__));
} TINS_END_PACK;
void write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *parent);
arphdr _arp;
};
};
}
#endif //TINS_ARP_H

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, Nasel
* Copyright (c) 2012, Matias Fontanini
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -34,6 +34,7 @@
#include <algorithm>
#include <vector>
#include "pdu.h"
#include "macros.h"
#include "endianness.h"
#include "ip_address.h"
#include "hw_address.h"
@@ -83,8 +84,11 @@ namespace Tins {
BootP();
/**
* \brief Constructor which creates a BootP object from a buffer and adds all identifiable
* PDUs found in the buffer as children of this one.
* \brief Constructs a BootP object from a buffer .
*
* If there's not enough size for a BootP header, then 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.
* \param vend_field_size The vend field size to allocate.
@@ -292,6 +296,17 @@ namespace Tins {
*/
void vend(const vend_type &new_vend);
/**
* \brief Check wether ptr points to a valid response for this PDU.
*
* This returns true, if the xid field is equal.
*
* \sa PDU::matches_response
* \param ptr The pointer to the buffer.
* \param total_sz The size of the buffer.
*/
bool matches_response(const uint8_t *ptr, uint32_t total_sz) const;
/**
* \brief Getter for the PDU's type.
* \sa PDU::pdu_type
@@ -320,6 +335,7 @@ namespace Tins {
/**
* Struct that represents the Bootp datagram.
*/
TINS_BEGIN_PACK
struct bootphdr {
uint8_t opcode;
uint8_t htype;
@@ -335,11 +351,11 @@ namespace Tins {
uint8_t chaddr[16];
uint8_t sname[64];
uint8_t file[128];
} __attribute__((__packed__));
} TINS_END_PACK;
bootphdr _bootp;
vend_type _vend;
};
};
}
#endif // TINS_BOOTP_H

71
include/config.h.in Normal file
View File

@@ -0,0 +1,71 @@
/* include/config.h.in. Generated from configure.ac by autoheader. */
/* define if the compiler supports basic C++11 syntax */
#undef HAVE_CXX11
/* Define to 1 if you have the <dlfcn.h> header file. */
#undef HAVE_DLFCN_H
/* Define to 1 if you have the <inttypes.h> header file. */
#undef HAVE_INTTYPES_H
/* Define to 1 if you have the `pcap' library (-lpcap). */
#undef HAVE_LIBPCAP
/* Define to 1 if you have the <memory.h> header file. */
#undef HAVE_MEMORY_H
/* Define to 1 if you have the <pcap.h> header file. */
#undef HAVE_PCAP_H
/* Define to 1 if you have the <stdint.h> header file. */
#undef HAVE_STDINT_H
/* Define to 1 if you have the <stdlib.h> header file. */
#undef HAVE_STDLIB_H
/* Define to 1 if you have the <strings.h> header file. */
#undef HAVE_STRINGS_H
/* Define to 1 if you have the <string.h> header file. */
#undef HAVE_STRING_H
/* Define to 1 if you have the <sys/stat.h> header file. */
#undef HAVE_SYS_STAT_H
/* Define to 1 if you have the <sys/types.h> header file. */
#undef HAVE_SYS_TYPES_H
/* Define to 1 if you have the <unistd.h> header file. */
#undef HAVE_UNISTD_H
/* Define to the sub-directory in which libtool stores uninstalled libraries.
*/
#undef LT_OBJDIR
/* Name of package */
#undef PACKAGE
/* Define to the address where bug reports for this package should be sent. */
#undef PACKAGE_BUGREPORT
/* Define to the full name of this package. */
#undef PACKAGE_NAME
/* Define to the full name and version of this package. */
#undef PACKAGE_STRING
/* Define to the one symbol short name of this package. */
#undef PACKAGE_TARNAME
/* Define to the home page for this package. */
#undef PACKAGE_URL
/* Define to the version of this package. */
#undef PACKAGE_VERSION
/* Define to 1 if you have the ANSI C header files. */
#undef STDC_HEADERS
/* Version number of package */
#undef VERSION

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, Nasel
* Copyright (c) 2012, Matias Fontanini
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -73,7 +73,8 @@ namespace Tins {
struct Ethernet {
enum e {
PUP = 0x0200, /* Xerox PUP */
UNKNOWN = 0,
//~ PUP = 0x0200, /* Xerox PUP */
SPRITE = 0x0500, /* Sprite */
IP = 0x0800, /* IP */
ARP = 0x0806, /* Address resolution */
@@ -83,6 +84,7 @@ namespace Tins {
VLAN = 0x8100, /* IEEE 802.1Q VLAN tagging */
IPX = 0x8137, /* IPX */
IPV6 = 0x86dd, /* IP protocol version 6 */
PPPOED = 0x8863, /* PPPoE Discovery */
EAPOL = 0x888e, /* EAPOL */
LOOPBACK = 0x9000 /* used to test interfaces */
};
@@ -147,11 +149,11 @@ namespace Tins {
IEEE802154 = 804, /* IEEE 802.15.4 header. */
IEEE802154_PHY = 805, /* IEEE 802.15.4 PHY header. */
VOID_TYPE = 0xFFFF, /* Void type, nothing is known. */
NONE = 0xFFFE, /* Zero header length. */
NONE = 0xFFFE /* Zero header length. */
};
};
};
};
}
}
#endif // TINS_CONSTANTS_H

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, Nasel
* Copyright (c) 2012, Matias Fontanini
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without

56
include/cxxstd.h Normal file
View File

@@ -0,0 +1,56 @@
/*
* 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_CXXSTD_H
#define TINS_CXXSTD_H
#include <memory>
#ifdef __GXX_EXPERIMENTAL_CXX0X__
#define TINS_CXXSTD_GCC_FIX 1
#else
#define TINS_CXXSTD_GCC_FIX 0
#endif // __GXX_EXPERIMENTAL_CXX0X__
#define TINS_IS_CXX11 (__cplusplus > 199711L || TINS_CXXSTD_GCC_FIX == 1)
namespace Tins{
namespace Internals {
template<typename T>
struct smart_ptr {
#if TINS_IS_CXX11
typedef std::unique_ptr<T> type;
#else
typedef std::auto_ptr<T> type;
#endif
};
}
}
#endif // TINS_CXXSTD_H

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, Nasel
* Copyright (c) 2012, Matias Fontanini
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -35,6 +35,7 @@
#include <string>
#include "bootp.h"
#include "pdu_option.h"
#include "cxxstd.h"
namespace Tins {
/**
@@ -66,7 +67,7 @@ namespace Tins {
/**
* \brief DHCP options enum.
*/
enum Options {
enum OptionTypes {
PAD,
SUBNET_MASK,
TIME_OFFSET,
@@ -142,12 +143,12 @@ namespace Tins {
/**
* The DHCP option type.
*/
typedef PDUOption<uint8_t> dhcp_option;
typedef PDUOption<uint8_t> option;
/**
* The type used to store the DHCP options.
*/
typedef std::list<dhcp_option> options_type;
typedef std::list<option> options_type;
/**
* \brief Creates an instance of DHCP.
@@ -158,8 +159,12 @@ namespace Tins {
DHCP();
/**
* \brief Constructor which creates a DHCP object from a buffer and adds all identifiable
* PDUs found in the buffer as children of this one.
* \brief Constructs a DHCP object from a buffer.
*
* If there is not enough size for a BootP header, or any of
* the TLV options contain an invalid size field, then 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.
* Subclasses might use 0 to provide their own interpretation of this field.
@@ -168,16 +173,30 @@ namespace Tins {
/**
* \brief Adds a new option to this DHCP PDU.
* \param option The option to be added.
* \param opt The option to be added.
*/
void add_option(const dhcp_option &option);
void add_option(const option &opt);
#if TINS_IS_CXX11
/**
* \brief Adds a new option to this DHCP PDU.
*
* The option is move-constructed.
*
* \param opt The option to be added.
*/
void add_option(option &&opt) {
internal_add_option(opt);
_options.push_back(std::move(opt));
}
#endif
/**
* \brief Searchs for an option that matchs the given flag.
* \param opt_flag The flag to be searched.
* \return A pointer to the option, or 0 if it was not found.
*/
const dhcp_option *search_option(Options opt) const;
const option *search_option(OptionTypes opt) const;
/**
* \brief Adds a type option the the option list.
@@ -401,23 +420,24 @@ namespace Tins {
void write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *parent);
template<class T>
T generic_search(Options opt, type2type<T>) const {
const dhcp_option *option = search_option(opt);
T generic_search(OptionTypes opt, type2type<T>) const {
const option *option = search_option(opt);
if(option && option->data_size() == sizeof(T))
return *(const T*)option->data_ptr();
else
throw option_not_found();
}
std::list<ipaddress_type> generic_search(Options opt, type2type<std::list<ipaddress_type> >) const;
std::string generic_search(Options opt, type2type<std::string>) const;
ipaddress_type generic_search(Options opt, type2type<ipaddress_type>) const;
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);
options_type _options;
uint32_t _size;
};
};
}
#endif // TINS_DHCP_H

889
include/dhcpv6.h Normal file
View File

@@ -0,0 +1,889 @@
/*
* 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_DHCPV6_H
#define TINS_DHCPV6_H
#include <list>
#include "pdu.h"
#include "endianness.h"
#include "small_uint.h"
#include "ipv6_address.h"
#include "pdu_option.h"
namespace Tins {
/**
* Represents a DHCPv6 PDU.
*/
class DHCPv6 : public PDU {
public:
/**
* Represents a DHCPv6 option.
*/
typedef PDUOption<uint16_t> option;
/**
* The message types.
*/
enum MessageType {
SOLICIT = 1,
ADVERTISE,
REQUEST,
CONFIRM,
RENEW,
REBIND,
REPLY,
RELEASE,
DECLINE,
RECONFIGURE,
INFO_REQUEST,
RELAY_FORWARD,
RELAY_REPLY,
LEASE_QUERY,
LEASE_QUERY_REPLY,
LEASE_QUERY_DONE,
LEASE_QUERY_DATA
};
/**
* The DHCPv6 options.
*/
enum OptionTypes {
CLIENTID = 1,
SERVERID,
IA_NA,
IA_TA,
IA_ADDR,
OPTION_REQUEST,
PREFERENCE,
ELAPSED_TIME,
RELAY_MSG,
AUTH = 11,
UNICAST,
STATUS_CODE,
RAPID_COMMIT,
USER_CLASS,
VENDOR_CLASS,
VENDOR_OPTS,
INTERFACE_ID,
RECONF_MSG,
RECONF_ACCEPT,
SIP_SERVER_D,
SIP_SERVER_A,
DNS_SERVERS,
DOMAIN_LIST,
IA_PD,
IAPREFIX,
NIS_SERVERS,
NISP_SERVERS,
NIS_DOMAIN_NAME,
NISP_DOMAIN_NAME,
SNTP_SERVERS,
INFORMATION_REFRESH_TIME,
BCMCS_SERVER_D,
BCMCS_SERVER_A,
GEOCONF_CIVIC = 36,
REMOTE_ID,
SUBSCRIBER_ID,
CLIENT_FQDN,
PANA_AGENT,
NEW_POSIX_TIMEZONE,
NEW_TZDB_TIMEZONE,
ERO,
LQ_QUERY,
CLIENT_DATA,
CLT_TIME,
LQ_RELAY_DATA,
LQ_CLIENT_LINK,
MIP6_HNIDF,
MIP6_VDINF,
V6_LOST,
CAPWAP_AC_V6,
RELAY_ID,
NTP_SERVER,
V6_ACCESS_DOMAIN,
SIP_UA_CS_LIST,
BOOTFILE_URL,
BOOTFILE_PARAM,
CLIENT_ARCH_TYPE,
NII,
GEOLOCATION,
AFTR_NAME,
ERP_LOCAL_DOMAIN_NAME,
RSOO,
PD_EXCLUDE,
VSS,
MIP6_IDINF,
MIP6_UDINF,
MIP6_HNP,
MIP6_HAA,
MIP6_HAF,
RDNSS_SELECTION,
KRB_PRINCIPAL_NAME,
KRB_REALM_NAME,
KRB_DEFAULT_REALM_NAME,
KRB_KDC
};
/**
* The type used to store the DHCPv6 options.
*/
typedef std::list<option> options_type;
/**
* The type used to store IP addresses.
*/
typedef IPv6Address ipaddress_type;
/**
* This PDU's flag.
*/
static const PDU::PDUType pdu_flag = PDU::DHCPv6;
/**
* The type used to store the Identity Association for Non-Temporary
* Addresses option.
*/
struct ia_na_type {
typedef std::vector<uint8_t> options_type;
uint32_t id, t1, t2;
options_type options;
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) {}
};
/**
* The type used to store the Identity Association for Temporary
* Addresses option.
*/
struct ia_ta_type {
typedef std::vector<uint8_t> options_type;
uint32_t id;
options_type options;
ia_ta_type(uint32_t id = 0,
const options_type& options = options_type())
: id(id), options(options) {}
};
/**
* The type used to store the Identity Association Address option.
*/
struct ia_address_type {
typedef std::vector<uint8_t> options_type;
ipaddress_type address;
uint32_t preferred_lifetime, valid_lifetime;
options_type options;
ia_address_type(ipaddress_type address = ipaddress_type(),
uint32_t preferred_lifetime = 0, uint32_t valid_lifetime = 0,
const options_type& options = options_type())
: address(address), preferred_lifetime(preferred_lifetime),
valid_lifetime(valid_lifetime), options(options) {}
};
/**
* The type used to store the Authentication option.
*/
struct authentication_type {
typedef std::vector<uint8_t> auth_info_type;
uint8_t protocol, algorithm, rdm;
uint64_t replay_detection;
auth_info_type auth_info;
authentication_type(uint8_t protocol = 0, uint8_t algorithm = 0,
uint8_t rdm = 0, uint64_t replay_detection = 0,
const auth_info_type &auth_info = auth_info_type())
: protocol(protocol), algorithm(algorithm), rdm(rdm),
replay_detection(replay_detection), auth_info(auth_info) {}
};
/**
* The type used to store the Status Code option.
*/
struct status_code_type {
uint16_t code;
std::string message;
status_code_type(uint16_t code = 0, const std::string &message = "")
: code(code), message(message) { }
};
/**
* The type used to store the Vendor-specific Information option.
*/
struct vendor_info_type {
typedef std::vector<uint8_t> data_type;
uint32_t enterprise_number;
data_type data;
vendor_info_type(uint32_t enterprise_number = 0,
const data_type &data = data_type())
: enterprise_number(enterprise_number), data(data) { }
};
/**
* The type used to store the User Class option's user class data.
*/
typedef std::vector<uint8_t> class_option_data_type;
/**
* The type used to store the User Class option.
*/
typedef std::vector<class_option_data_type> user_class_type;
/**
* The type used to store the Vendor Class option.
*/
struct vendor_class_type {
typedef std::vector<class_option_data_type> class_data_type;
uint32_t enterprise_number;
class_data_type vendor_class_data;
vendor_class_type(uint32_t enterprise_number = 0,
const class_data_type &vendor_class_data = class_data_type())
: enterprise_number(enterprise_number),
vendor_class_data(vendor_class_data) { }
};
/**
* The type used to represent DUIDs Based on Link-layer Address Plus
* Time.
*/
struct duid_llt {
static const uint16_t duid_id = 1;
typedef std::vector<uint8_t> lladdress_type;
uint16_t hw_type;
uint32_t time;
lladdress_type lladdress;
duid_llt(uint16_t hw_type = 0, uint32_t time = 0,
const lladdress_type &lladdress = lladdress_type())
: hw_type(hw_type), time(time), lladdress(lladdress) {}
PDU::serialization_type serialize() const;
static duid_llt from_bytes(const uint8_t *buffer, uint32_t total_sz);
};
/**
* The type used to represent DUIDs Based on Enterprise Number
*/
struct duid_en {
static const uint16_t duid_id = 2;
typedef std::vector<uint8_t> identifier_type;
uint32_t enterprise_number;
identifier_type identifier;
duid_en(uint32_t enterprise_number = 0,
const identifier_type &identifier = identifier_type())
: enterprise_number(enterprise_number), identifier(identifier) {}
PDU::serialization_type serialize() const;
static duid_en from_bytes(const uint8_t *buffer, uint32_t total_sz);
};
/**
* The type used to represent DUIDs Based on Link-layer Address.
*/
struct duid_ll {
static const uint16_t duid_id = 3;
typedef std::vector<uint8_t> lladdress_type;
uint16_t hw_type;
lladdress_type lladdress;
duid_ll(uint16_t hw_type = 0,
const lladdress_type &lladdress = lladdress_type())
: hw_type(hw_type), lladdress(lladdress) {}
PDU::serialization_type serialize() const;
static duid_ll from_bytes(const uint8_t *buffer, uint32_t total_sz);
};
/**
* Type type used to represent DUIDs. This will be stored as the
* value for the Client/Server Identifier options.
*/
struct duid_type {
typedef PDU::serialization_type data_type;
uint16_t id;
data_type data;
duid_type(uint16_t id = 0, const data_type &data = data_type())
: id(id), data(data) {}
duid_type(const duid_llt &identifier)
: id(duid_llt::duid_id), data(identifier.serialize()) {}
duid_type(const duid_en &identifier)
: id(duid_en::duid_id), data(identifier.serialize()) {}
duid_type(const duid_ll &identifier)
: id(duid_en::duid_id), data(identifier.serialize()) {}
};
/**
* The type used to store the Option Request option.
*/
typedef std::vector<OptionTypes> option_request_type;
/**
* The type used to store the Relay Message option.
*/
typedef std::vector<uint8_t> relay_msg_type;
/**
* The type used to store the Interface-ID option.
*/
typedef std::vector<uint8_t> interface_id_type;
/**
* Default constructor.
*/
DHCPv6();
/**
* \brief Constructs a DHCPv6 object from a buffer.
*
* If there is not enough size for the DHCPv6 header, or any
* of the TLV options contains an invalid size field, 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.
*/
DHCPv6(const uint8_t *buffer, uint32_t total_sz);
// Getters
/**
* \brief Getter for the message type field.
*
* \return The stored message type field.
*/
MessageType msg_type() const {
return static_cast<MessageType>(header_data[0]);
}
/**
* \brief Getter for the hop count field.
*
* \return The stored hop count field.
*/
uint8_t hop_count() const { return header_data[1]; }
/**
* \brief Getter for the transaction id field.
*
* \return The stored transaction id field.
*/
small_uint<24> transaction_id() const {
return (header_data[1] << 16) | (header_data[2] << 8) | header_data[3];
}
/**
* \brief Getter for the peer address field.
*
* \return The stored peer address field.
*/
const ipaddress_type &peer_address() const { return peer_addr; }
/**
* \brief Getter for the link address field.
*
* \return The stored link address field.
*/
const ipaddress_type &link_address() const { return link_addr; }
/**
* \brief Getter for the DHCPv6 options.
*
* \return The stored options.
*/
const options_type &options() const { return options_; }
;
// Setters
/**
* \brief Setter for the message type field.
*
* \param type The new message type.
*/
void msg_type(MessageType type);
/**
* \brief Setter for the hop count field.
*
* \param count The new hop count.
*/
void hop_count(uint8_t count);
/**
* \brief Setter for the transaction id field.
*
* \param id The new transaction id.
*/
void transaction_id(small_uint<24> id);
/**
* \brief Setter for the peer address field.
*
* \param count The new peer address.
*/
void peer_address(const ipaddress_type &addr);
/**
* \brief Setter for the link address field.
*
* \param count The new link address.
*/
void link_address(const ipaddress_type &addr);
// Option getters
/**
* \brief Getter for the Identity Association for Non-Temporary
* Addresses option.
*
* This method will throw an option_not_found exception if the
* option is not found.
*/
ia_na_type ia_na() const;
/**
* \brief Getter for the Identity Association for Temporary
* Addresses option.
*
* This method will throw an option_not_found exception if the
* option is not found.
*/
ia_ta_type ia_ta() const;
/**
* \brief Getter for the Identity Association Address option.
*
* This method will throw an option_not_found exception if the
* option is not found.
*/
ia_address_type ia_address() const;
/**
* \brief Getter for the Option Request option.
*
* This method will throw an option_not_found exception if the
* option is not found.
*/
option_request_type option_request() const;
/**
* \brief Getter for the Preference option.
*
* This method will throw an option_not_found exception if the
* option is not found.
*/
uint8_t preference() const;
/**
* \brief Getter for the Elapsed Time option.
*
* This method will throw an option_not_found exception if the
* option is not found.
*/
uint16_t elapsed_time() const;
/**
* \brief Getter for the Relay Message option.
*
* This method will throw an option_not_found exception if the
* option is not found.
*/
relay_msg_type relay_message() const;
/**
* \brief Getter for the Authentication option.
*
* This method will throw an option_not_found exception if the
* option is not found.
*/
authentication_type authentication() const;
/**
* \brief Getter for the Server Unicast option.
*
* This method will throw an option_not_found exception if the
* option is not found.
*/
ipaddress_type server_unicast() const;
/**
* \brief Getter for the Server Unicast option.
*
* This method will throw an option_not_found exception if the
* option is not found.
*/
status_code_type status_code() const;
/**
* \brief Getter for the Rapid Commit option.
*
* This method will throw an option_not_found exception if the
* option is not found.
*/
bool has_rapid_commit() const;
/**
* \brief Getter for the User Class option.
*
* This method will throw an option_not_found exception if the
* option is not found.
*/
user_class_type user_class() const;
/**
* \brief Getter for the Vendor Class option.
*
* This method will throw an option_not_found exception if the
* option is not found.
*/
vendor_class_type vendor_class() const;
/**
* \brief Getter for the Vendor-specific Information option.
*
* This method will throw an option_not_found exception if the
* option is not found.
*/
vendor_info_type vendor_info() const;
/**
* \brief Getter for the Interface ID option.
*
* This method will throw an option_not_found exception if the
* option is not found.
*/
interface_id_type interface_id() const;
/**
* \brief Getter for the Reconfigure Message option.
*
* This method will throw an option_not_found exception if the
* option is not found.
*/
uint8_t reconfigure_msg() const;
/**
* \brief Getter for the Reconfigure Accept option.
*
* This method will throw an option_not_found exception if the
* option is not found.
*/
bool has_reconfigure_accept() const;
/**
* \brief Getter for the Client Identifier option.
*
* This method will throw an option_not_found exception if the
* option is not found.
*/
duid_type client_id() const;
/**
* \brief Getter for the Server Identifier option.
*
* This method will throw an option_not_found exception if the
* option is not found.
*/
duid_type server_id() const;
// Option setters
/**
* \brief Setter for the Identity Association for Non-Temporary
* Addresses option.
*
* \param value The new IA_NA option data.
*/
void ia_na(const ia_na_type &value);
/**
* \brief Setter for the Identity Association for Temporary
* Addresses option.
*
* \param value The new IA_TA option data.
*/
void ia_ta(const ia_ta_type &value);
/**
* \brief Setter for the Identity Association Address option.
*
* \param value The new IA Address option data.
*/
void ia_address(const ia_address_type &value);
/**
* \brief Setter for the Identity Association Address option.
*
* \param value The new Option Request option data.
*/
void option_request(const option_request_type &value);
/**
* \brief Setter for the Preference option.
*
* \param value The new Preference option data.
*/
void preference(uint8_t value);
/**
* \brief Setter for the Elapsed Time option.
*
* \param value The new Elapsed Time option data.
*/
void elapsed_time(uint16_t value);
/**
* \brief Setter for the Relay Message option.
*
* \param value The new Relay Message option data.
*/
void relay_message(const relay_msg_type &value);
/**
* \brief Setter for the Authentication option.
*
* \param value The new Authentication option data.
*/
void authentication(const authentication_type &value);
/**
* \brief Setter for the Server Unicast option.
*
* \param value The new Server Unicast option data.
*/
void server_unicast(const ipaddress_type &value);
/**
* \brief Setter for the Status Code option.
*
* \param value The new Status Code option data.
*/
void status_code(const status_code_type &value);
/**
* \brief Adds a Rapid Commit option.
*/
void rapid_commit();
/**
* \brief Setter for the User Class option.
*
* \param value The new User Class option data.
*/
void user_class(const user_class_type &value);
/**
* \brief Setter for the Vendor Class option.
*
* \param value The new Vendor Class option data.
*/
void vendor_class(const vendor_class_type &value);
/**
* \brief Setter for the Vendor-specific Information option.
*
* \param value The new Vendor-specific Information option data.
*/
void vendor_info(const vendor_info_type &value);
/**
* \brief Setter for the Interface ID option.
*
* \param value The new Interface ID option data.
*/
void interface_id(const interface_id_type &value);
/**
* \brief Setter for the Reconfigure Message option.
*
* \param value The new Reconfigure Message option data.
*/
void reconfigure_msg(uint8_t value);
/**
* \brief Adds a Reconfigure Accept option.
*/
void reconfigure_accept();
/**
* \brief Setter for the Client Identifier option.
*
* \param value The new Client Identifier option data.
*/
void client_id(const duid_type &value);
/**
* \brief Setter for the Server Identifier option.
*
* \param value The new Server Identifier option data.
*/
void server_id(const duid_type &value);
// Other stuff
/**
* Indicates whether this is a relay agent/server message
*/
bool is_relay_message() const;
/**
* \brief Adds a DHCPv6 option.
*
* The option is added after the last option in the option
* fields.
*
* \param opt The option to be added
*/
void add_option(const option &opt);
/**
* \brief Searchs for an option that matchs the given flag.
*
* If the option is not found, a null pointer is returned.
* Deleting the returned pointer will result in <b>undefined
* behaviour</b>.
*
* \param id The option identifier to be searched.
*/
const option *search_option(OptionTypes id) const;
// PDU stuff
/**
* \brief Returns the header size.
*
* This metod overrides PDU::header_size. \sa PDU::header_size
*/
uint32_t header_size() const;
/**
* \brief Check wether ptr points to a valid response for this PDU.
*
* \sa PDU::matches_response
* \param ptr The pointer to the buffer.
* \param total_sz The size of the buffer.
*/
bool matches_response(const uint8_t *ptr, uint32_t total_sz) const;
/**
* \brief Getter for the PDU's type.
* \sa PDU::pdu_type
*/
PDUType pdu_type() const { return pdu_flag; }
/**
* \sa PDU::clone
*/
DHCPv6 *clone() const {
return new DHCPv6(*this);
}
private:
void write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *);
uint8_t* write_option(const option &option, uint8_t* buffer) const;
template<template <typename> class Functor>
const option *safe_search_option(OptionTypes opt, uint32_t size) const {
const option *option = search_option(opt);
if(!option || Functor<uint32_t>()(option->data_size(), size))
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)
throw option_not_found();
return output;
}
uint8_t header_data[4];
uint32_t options_size;
ipaddress_type link_addr, peer_addr;
options_type options_;
};
}
#endif // TINS_DHCPV6_H

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, Nasel
* Copyright (c) 2012, Matias Fontanini
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -36,12 +36,14 @@
#include <cstring>
#include <string>
#include <map>
#include "macros.h"
#include "pdu.h"
#include "endianness.h"
#include "dns_record.h"
namespace Tins {
class IPv4Address;
class IPv6Address;
/**
* \class DNS
@@ -240,6 +242,7 @@ namespace Tins {
typedef std::list<Query> queries_type;
typedef std::list<Resource> resources_type;
typedef IPv4Address address_type;
typedef IPv6Address address_v6_type;
/**
* \brief Default constructor.
@@ -249,7 +252,11 @@ namespace Tins {
DNS();
/**
* \brief Constructor which creates a DNS object from a buffer.
* \brief Constructs a DNS object from a buffer.
*
* If there's not enough size for the DNS header, or any of the
* records are malformed, a malformed_packet is be thrown.
*
* \param buffer The buffer from which this PDU will be
* constructed.
* \param total_sz The total size of the buffer.
@@ -485,6 +492,18 @@ namespace Tins {
*/
void add_answer(const std::string &name,
const DNSResourceRecord::info &info, address_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 ip The ip address of the resolved name.
*/
void add_answer(const std::string &name,
const DNSResourceRecord::info &info, address_v6_type ip);
/**
* \brief Add a query response.
@@ -551,6 +570,15 @@ namespace Tins {
*/
resources_type answers() const;
/**
* \brief Check wether ptr points to a valid response for this PDU.
*
* \sa PDU::matches_response
* \param ptr The pointer to the buffer.
* \param total_sz The size of the buffer.
*/
bool matches_response(const uint8_t *ptr, uint32_t total_sz) const;
/**
* \sa PDU::clone
*/
@@ -569,6 +597,7 @@ namespace Tins {
return DNSResourceRecord::info((uint16_t)type, (uint16_t)qclass, ttl);
}
private:
TINS_BEGIN_PACK
struct dnshdr {
uint16_t id;
#if TINS_IS_LITTLE_ENDIAN
@@ -598,7 +627,7 @@ namespace Tins {
#endif
uint16_t questions, answers,
authority, additional;
} __attribute__((packed));
} TINS_END_PACK;
typedef std::map<uint16_t, std::string> SuffixMap;
typedef std::map<uint16_t, uint16_t> SuffixIndices;
@@ -630,7 +659,7 @@ namespace Tins {
mutable SuffixMap suffixes;
mutable SuffixIndices suffix_indices;
};
};
}
#endif // TINS_DNS_H

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, Nasel
* Copyright (c) 2012, Matias Fontanini
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -33,9 +33,21 @@
#include <string>
#include <vector>
#include <stdint.h>
#include "cxxstd.h"
#include "macros.h"
namespace Tins {
class DNSRRImpl;
/**
* \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.
@@ -45,6 +57,7 @@ public:
/**
* \brief The type used to store resource records' information.
*/
TINS_BEGIN_PACK
struct info {
uint16_t type, qclass;
uint32_t ttl;
@@ -53,7 +66,7 @@ public:
: type(tp), qclass(qc), ttl(tm) { }
info() : type(), qclass(), ttl() {}
} __attribute__((packed));
} TINS_END_PACK;
/**
* \brief Constructs a record.
@@ -65,6 +78,10 @@ public:
/**
* \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.
*/
@@ -97,6 +114,29 @@ public:
*/
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.
*
@@ -183,18 +223,6 @@ private:
DNSRRImpl *impl;
};
/**
* \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;
};
class OffsetedDNSRRImpl : public DNSRRImpl {
public:
OffsetedDNSRRImpl(uint16_t off);

File diff suppressed because it is too large Load Diff

209
include/dot1q.h Normal file
View File

@@ -0,0 +1,209 @@
/*
* 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_DOT1Q_H
#define TINS_DOT1Q_H
#include "pdu.h"
#include "endianness.h"
#include "small_uint.h"
namespace Tins {
class Dot1Q : public PDU {
public:
/**
* This PDU's flag.
*/
static const PDU::PDUType pdu_flag = PDU::DOT1Q;
/**
* Default constructor
*/
Dot1Q(small_uint<12> tag_id = 0, bool append_pad = true);
/**
* \brief Constructs a Dot1Q object from a buffer and adds all
* identifiable PDUs found in the buffer as children of this
* one.
*
* If the next PDU is not recognized, then a RawPDU is used.
*
* If there is not enough size for a Dot1Q header in the buffer,
* 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.
*/
Dot1Q(const uint8_t *buffer, uint32_t total_sz);
// Getters
/**
* \brief Returns the header size.
*
* This metod overrides PDU::header_size. \sa PDU::header_size
*/
uint32_t header_size() const;
/**
* \brief Returns the frame's trailer size.
* \return The trailer's size.
*/
uint32_t trailer_size() const;
/**
* \brief Getter for the priority field.
* \return The stored priority field value.
*/
small_uint<3> priority() const {
return _header.priority;
}
/**
* \brief Getter for the cfi field.
* \return The stored cfi field value.
*/
small_uint<1> cfi() const {
return _header.cfi;
}
/**
* \brief Getter for the id field.
* \return The stored id field value.
*/
small_uint<12> id() const {
#if TINS_IS_LITTLE_ENDIAN
return _header.idL | (_header.idH << 8);
#else
return _header.id;
#endif
}
/**
* \brief Getter for the payload type field.
* \return The stored type field value.
*/
uint16_t payload_type() const {
return Endian::be_to_host(_header.type);
}
/**
* \brief Getter for the PDU's type.
* \sa PDU::pdu_type
*/
PDUType pdu_type() const { return pdu_flag; }
/**
* \sa PDU::clone
*/
Dot1Q *clone() const {
return new Dot1Q(*this);
}
/**
* \brief Retrieves the flag indicating whether padding will be
* appended at the end of this packet.
*/
bool append_padding() const {
return _append_padding;
}
// Setters
/**
* \brief Setter for the priority field.
* \param new_priority The new priority field value.
*/
void priority(small_uint<3> new_priority);
/**
* \brief Setter for the cfi field.
* \param new_cfi The new cfi field value.
*/
void cfi(small_uint<1> new_cfi);
/**
* \brief Setter for the id field.
* \param new_id The new id field value.
*/
void id(small_uint<12> new_id);
/**
* \brief Setter for the payload type field.
* \param new_type The new type field value.
*/
void payload_type(uint16_t new_type);
/**
* \brief Indicates whether the appropriate padding will be
* at the end of the packet.
*
* This flag could be disabled in case two or more contiguous Dot1Q
* PDUs are added to a packet. In that case, only the Dot1Q which is
* closer to the link layer should add the padding at the end.
*
* \param value A boolean indicating whether padding will be appended.
*/
void append_padding(bool value);
/**
* \brief Check wether ptr points to a valid response for this PDU.
*
* \sa PDU::matches_response
* \param ptr The pointer to the buffer.
* \param total_sz The size of the buffer.
*/
bool matches_response(const uint8_t *ptr, uint32_t total_sz) const;
private:
void write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *parent);
TINS_BEGIN_PACK
struct dot1q_hdr {
#if TINS_IS_BIG_ENDIAN
uint16_t priority:3,
cfi:1,
id:12;
uint16_t type;
#else
uint16_t idH:4,
cfi:1,
priority:3,
idL:8;
uint16_t type;
#endif
} TINS_END_PACK;
static uint16_t get_id(const dot1q_hdr *hdr);
dot1q_hdr _header;
bool _append_padding;
};
}
#endif // TINS_DOT1Q_H

193
include/dot3.h Normal file
View File

@@ -0,0 +1,193 @@
/*
* 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_DOT3_H
#define TINS_DOT3_H
#include <stdint.h>
#include "macros.h"
#include "pdu.h"
#include "endianness.h"
#include "hw_address.h"
namespace Tins {
/**
* \brief Class representing an Ethernet II PDU.
*/
class Dot3 : public PDU {
public:
/**
* \brief The address type.
*/
typedef HWAddress<6> address_type;
/**
* \brief This PDU's flag.
*/
static const PDU::PDUType pdu_flag = PDU::IEEE802_3;
/**
* \brief Represents the Dot3 broadcast address.
*/
static const address_type BROADCAST;
/**
* \brief Constructor for creating an Dot3 PDU
*
* Constructor that builds an Dot3 PDU taking the interface name,
* destination's and source's MAC.
*
* \param dst_hw_addr The destination hardware address.
* \param src_hw_addr The source hardware address.
* \param child The PDU which will be set as the inner PDU.
*/
Dot3(const address_type &dst_hw_addr = address_type(),
const address_type &src_hw_addr = address_type());
/**
* \brief Constructs a Dot3 object from a buffer and adds a
* LLC object with the remaining data as the inner PDU.
*
* If there is not enough size for a Dot3 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.
*/
Dot3(const uint8_t *buffer, uint32_t total_sz);
/* Getters */
/**
* \brief Getter for the destination hardware address.
*
* \return The destination hardware address.
*/
address_type dst_addr() const { return _eth.dst_mac; }
/**
* \brief Getter for the source hardware address.
*
* \return The source hardware address.
*/
address_type src_addr() const { return _eth.src_mac; }
/**
* \brief Getter for the length field.
* \return The length field value.
*/
uint16_t length() const { return Endian::be_to_host(_eth.length); };
/* Setters */
/**
* \brief Setter for the destination hardware address.
*
* \param new_dst_mac The new destination hardware address.
*/
void dst_addr(const address_type &new_dst_mac);
/**
* \brief Setter for the source hardware address.
*
* \param new_src_mac The new source hardware address.
*/
void src_addr(const address_type &new_src_mac);
/**
* \brief Setter for the length field.
*
* \param new_length uint16_t with the new value of the length field.
*/
void length(uint16_t new_length);
/* Virtual methods */
/**
* \brief Returns the Dot3 frame's header length.
*
* \return An uint32_t with the header's size.
* \sa PDU::header_size()
*/
uint32_t header_size() const;
#ifndef WIN32
/**
* \sa PDU::send()
*/
void send(PacketSender &sender, const NetworkInterface &iface);
#endif // WIN32
/**
* \brief Check wether ptr points to a valid response for this PDU.
*
* \sa PDU::matches_response
* \param ptr The pointer to the buffer.
* \param total_sz The size of the buffer.
*/
bool matches_response(const uint8_t *ptr, uint32_t total_sz) const;
#ifndef WIN32
/**
* \sa PDU::recv_response
*/
PDU *recv_response(PacketSender &sender, const NetworkInterface &iface);
#endif // WIN32
/**
* \brief Getter for the PDU's type.
* \sa PDU::pdu_type
*/
PDUType pdu_type() const { return pdu_flag; }
/**
* \sa PDU::clone
*/
Dot3 *clone() const {
return new Dot3(*this);
}
private:
/**
* Struct that represents the Ethernet II header
*/
TINS_BEGIN_PACK
struct ethhdr {
uint8_t dst_mac[address_type::address_size];
uint8_t src_mac[address_type::address_size];
uint16_t length;
} TINS_END_PACK;
void write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *parent);
ethhdr _eth;
};
}
#endif // TINS_DOT3_H

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, Nasel
* Copyright (c) 2012, Matias Fontanini
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -32,6 +32,7 @@
#include <stdint.h>
#include "pdu.h"
#include "macros.h"
#include "small_uint.h"
#include "endianness.h"
@@ -66,6 +67,12 @@ namespace Tins {
/**
* \brief Static method to instantiate the correct EAPOL subclass
* based on a raw buffer.
*
* If no valid EAPOL type is detected, a null pointer is returned.
*
* \sa RC4EAPOL
* \sa RSNEAPOL
*
* \param buffer The buffer from which the data will be taken.
* \param total_sz The total size of the buffer.
*/
@@ -134,11 +141,6 @@ namespace Tins {
*/
EAPOL(uint8_t packet_type, EAPOLTYPE type);
/**
* \brief Copy constructor.
*/
EAPOL(const EAPOL &other);
/**
* \brief Constructor which creates an EAPOL object from a buffer.
* \param buffer The buffer from which this PDU will be constructed.
@@ -146,13 +148,12 @@ namespace Tins {
*/
EAPOL(const uint8_t *buffer, uint32_t total_sz);
void copy_eapol_fields(const EAPOL *other);
TINS_BEGIN_PACK
struct eapolhdr {
uint8_t version, packet_type;
uint16_t length;
uint8_t type;
} __attribute__((__packed__));
} TINS_END_PACK;
/**
* \brief Virtual method which should serialize the subclass specific
@@ -202,12 +203,16 @@ namespace Tins {
static const size_t key_sign_size = 16;
/**
* \brief Creates an instance of RC4EAPOL
* \brief Default constructor.
*/
RC4EAPOL();
/**
* \brief Constructor which creates an RC4EAPOL object from a buffer.
* \brief Constructs a RC4EAPOL object from a buffer.
*
* If there is not enough size for a RC4EAPOL header in the
* buffer, 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.
*/
@@ -324,7 +329,7 @@ namespace Tins {
* \param flag The flag to match
* \sa PDU::matches_flag
*/
bool matches_flag(PDUType flag) {
bool matches_flag(PDUType flag) const {
return flag == PDU::RC4EAPOL || EAPOL::matches_flag(flag);
}
@@ -337,6 +342,7 @@ namespace Tins {
return new RC4EAPOL(*this);
}
private:
TINS_BEGIN_PACK
struct rc4hdr {
uint16_t key_length;
uint64_t replay_counter;
@@ -344,7 +350,7 @@ namespace Tins {
uint8_t key_index:7,
key_flag:1;
uint8_t key_sign[16];
} __attribute__((__packed__));
} TINS_END_PACK;
void write_body(uint8_t *buffer, uint32_t total_sz);
@@ -400,7 +406,11 @@ namespace Tins {
RSNEAPOL();
/**
* \brief Constructor which creates an RSNEAPOL object from a buffer.
* \brief Constructs a RSNEAPOL object from a buffer.
*
* If there is not enough size for the RSNEAPOL 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.
*/
@@ -665,7 +675,7 @@ namespace Tins {
* \param flag The flag to match
* \sa PDU::matches_flag
*/
bool matches_flag(PDUType flag) {
bool matches_flag(PDUType flag) const {
return flag == PDU::RSNEAPOL || EAPOL::matches_flag(flag);
}
@@ -678,6 +688,7 @@ namespace Tins {
return new RSNEAPOL(*this);
}
private:
TINS_BEGIN_PACK
struct rsnhdr {
#if TINS_IS_LITTLE_ENDIAN
uint16_t key_mic:1,
@@ -716,7 +727,7 @@ namespace Tins {
uint8_t mic[mic_size];
uint16_t wpa_length;
#endif
} __attribute__((__packed__));
} TINS_END_PACK;
void write_body(uint8_t *buffer, uint32_t total_sz);
@@ -724,6 +735,6 @@ namespace Tins {
rsnhdr _header;
key_type _key;
};
};
}
#endif // TINS_EAPOL_H

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, Nasel
* Copyright (c) 2012, Matias Fontanini
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -31,12 +31,27 @@
#define TINS_ENDIANNESS_H
#include <stdint.h>
#ifndef WIN32
#include "macros.h"
#if defined(__APPLE__)
#include <sys/types.h>
#define TINS_IS_LITTLE_ENDIAN (BYTE_ORDER == LITTLE_ENDIAN)
#define TINS_IS_BIG_ENDIAN (BYTE_ORDER == BIG_ENDIAN)
#elif defined(BSD)
#include <sys/endian.h>
#define TINS_IS_LITTLE_ENDIAN (_BYTE_ORDER == _LITTLE_ENDIAN)
#define TINS_IS_BIG_ENDIAN (_BYTE_ORDER == _BIG_ENDIAN)
#elif defined(WIN32)
// Assume windows == little endian. fixme later
#define TINS_IS_LITTLE_ENDIAN 1
#define TINS_IS_BIG_ENDIAN 0
#else
#include <endian.h>
#define TINS_IS_LITTLE_ENDIAN (__BYTE_ORDER == __LITTLE_ENDIAN)
#define TINS_IS_BIG_ENDIAN (__BYTE_ORDER == __BIG_ENDIAN)
#endif
#define TINS_IS_LITTLE_ENDIAN (__BYTE_ORDER == __LITTLE_ENDIAN)
#define TINS_IS_BIG_ENDIAN (__BYTE_ORDER == __BIG_ENDIAN)
namespace Tins {
namespace Endian {
@@ -45,7 +60,7 @@ namespace Endian {
*
* \param data The data to convert.
*/
inline uint16_t change_endian(uint16_t data) {
inline uint16_t do_change_endian(uint16_t data) {
return ((data & 0xff00) >> 8) | ((data & 0x00ff) << 8);
}
@@ -54,7 +69,7 @@ namespace Endian {
*
* \param data The data to convert.
*/
inline uint32_t change_endian(uint32_t data) {
inline uint32_t do_change_endian(uint32_t data) {
return (((data & 0xff000000) >> 24) | ((data & 0x00ff0000) >> 8) |
((data & 0x0000ff00) << 8) | ((data & 0x000000ff) << 24));
}
@@ -64,9 +79,56 @@ namespace Endian {
*
* \param data The data to convert.
*/
inline uint64_t change_endian(uint64_t data) {
return (((uint64_t)(change_endian((uint32_t)((data << 32) >> 32))) << 32) |
(change_endian(((uint32_t)(data >> 32)))));
inline uint64_t do_change_endian(uint64_t data) {
return (((uint64_t)(do_change_endian((uint32_t)((data << 32) >> 32))) << 32) |
(do_change_endian(((uint32_t)(data >> 32)))));
}
/**
* \cond
*/
// Helpers to convert
template<typename T>
struct conversion_dispatch_helper {
static T dispatch(T data) {
return do_change_endian(data);
}
};
template<size_t>
struct conversion_dispatcher;
template<>
struct conversion_dispatcher<sizeof(uint16_t)>
: public conversion_dispatch_helper<uint16_t>
{ };
template<>
struct conversion_dispatcher<sizeof(uint32_t)>
: public conversion_dispatch_helper<uint32_t>
{ };
template<>
struct conversion_dispatcher<sizeof(uint64_t)>
: public conversion_dispatch_helper<uint64_t>
{ };
/**
* \endcond
*/
/**
* \brief Changes an integral value's endianess.
*
* This dispatchs to the corresponding function.
*
* \param data The data to convert.
*/
template<typename T>
inline T change_endian(T data) {
return conversion_dispatcher<sizeof(T)>::dispatch(data);
}
#if TINS_IS_LITTLE_ENDIAN

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, Nasel
* Copyright (c) 2012, Matias Fontanini
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -31,11 +31,10 @@
#define TINS_ETHERNET_II_H
#include <stdint.h>
#include "macros.h"
#include "pdu.h"
#include "endianness.h"
#include "hw_address.h"
#include "network_interface.h"
namespace Tins {
@@ -60,24 +59,23 @@ namespace Tins {
static const address_type BROADCAST;
/**
* \brief Constructor for creating an ethernet PDU
* \brief Constructs an ethernet II PDU.
*
* Constructor that builds an ethernet PDU taking the interface name,
* destination's and source's MAC.
*
* \param iface string containing the interface's name from where to send the packet.
* \param dst_hw_addr address_type containing the destination's MAC(optional).
* \param src_hw_addr address_type containing the source's MAC(optional).
* \param child PDU* with the PDU contained by the ethernet PDU (optional).
* \param dst_hw_addr address_type containing the destination's MAC.
* \param src_hw_addr address_type containing the source's MAC.
*/
EthernetII(const NetworkInterface& iface = NetworkInterface(),
const address_type &dst_hw_addr = address_type(),
const address_type &src_hw_addr = address_type(),
PDU* child = 0);
EthernetII(const address_type &dst_hw_addr = address_type(),
const address_type &src_hw_addr = address_type());
/**
* \brief Constructor which creates an EthernetII object from a buffer and adds all identifiable
* PDUs found in the buffer as children of this one.
* \brief Constructs a EthernetII object from a buffer and adds
* all identifiable PDUs found in the buffer as children of
* this one.
*
* If the next PDU is not recognized, then a RawPDU is used.
*
* If there is not enough size for a EthernetII header in the
* buffer, 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.
@@ -100,13 +98,6 @@ namespace Tins {
*/
address_type src_addr() const { return _eth.src_mac; }
/**
* \brief Getter for the interface.
*
* \return Returns the interface in which this PDU will be sent.
*/
const NetworkInterface &iface() const { return _iface; }
/**
* \brief Getter for the payload_type
* \return The payload type.
@@ -129,13 +120,6 @@ namespace Tins {
*/
void src_addr(const address_type &new_src_addr);
/**
* \brief Setter for the interface.
*
* \param new_iface the interface to be set.
*/
void iface(const NetworkInterface& new_iface);
/**
* \brief Setter for the payload type.
*
@@ -157,24 +141,25 @@ namespace Tins {
/**
* \sa PDU::send()
*/
void send(PacketSender &sender);
void send(PacketSender &sender, const NetworkInterface &iface);
#endif // WIN32
/** \brief Check wether ptr points to a valid response for this PDU.
/**
* \brief Check wether ptr points to a valid response for this PDU.
*
* \sa PDU::matches_response
* \param ptr The pointer to the buffer.
* \param total_sz The size of the buffer.
*/
bool matches_response(uint8_t *ptr, uint32_t total_sz);
bool matches_response(const uint8_t *ptr, uint32_t total_sz) const;
#ifndef WIN32
/** \brief Receives a matching response for this packet.
/**
* \brief Receives a matching response for this packet.
*
* \sa PDU::recv_response
* \param sender The packet sender which will receive the packet.
*/
PDU *recv_response(PacketSender &sender);
PDU *recv_response(PacketSender &sender, const NetworkInterface &iface);
#endif // WIN32
/**
@@ -183,16 +168,6 @@ namespace Tins {
*/
PDUType pdu_type() const { return PDU::ETHERNET_II; }
/** \brief Clones this pdu, filling the corresponding header with data
* extracted from a buffer.
*
* \param ptr The pointer to the from from which the data will be extracted.
* \param total_sz The size of the buffer.
* \return The cloned PDU.
* \sa PDU::clone_packet
*/
PDU *clone_packet(const uint8_t *ptr, uint32_t total_sz);
/**
* \sa PDU::clone
*/
@@ -203,19 +178,19 @@ namespace Tins {
/**
* Struct that represents the Ethernet II header
*/
TINS_BEGIN_PACK
struct ethhdr {
uint8_t dst_mac[address_type::address_size];
uint8_t src_mac[address_type::address_size];
uint16_t payload_type;
} __attribute__((__packed__));
} TINS_END_PACK;
void write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *parent);
ethhdr _eth;
NetworkInterface _iface;
};
};
}
#endif // TINS_ETHERNET_II_H

129
include/exceptions.h Normal file
View File

@@ -0,0 +1,129 @@
/*
* 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_EXCEPTIONS_H
#define TINS_EXCEPTIONS_H
#include <stdexcept>
namespace Tins {
/**
* \brief Exception thrown when an option is not found.
*/
class option_not_found : public std::runtime_error {
public:
option_not_found()
: std::runtime_error(std::string()) { }
// try to avoid allocations by doing this.
const char* what() const throw() {
return "Option not found";
}
};
/**
* \brief Exception thrown when a malformed packet is parsed.
*/
class malformed_packet : public std::runtime_error {
public:
malformed_packet()
: std::runtime_error(std::string()) { }
const char* what() const throw() {
return "Malformed packet";
}
};
/**
* \brief Exception thrown when a PDU is not found when using PDU::rfind_pdu.
*/
class pdu_not_found : public std::runtime_error {
public:
pdu_not_found()
: std::runtime_error(std::string()) { }
const char* what() const throw() {
return "PDU not found";
}
};
/**
* \brief Exception thrown when PDU::send requires a valid interface,
* but an invalid is used.
*/
class invalid_interface : public std::runtime_error {
public:
invalid_interface()
: std::runtime_error(std::string()) { }
const char* what() const throw() {
return "Invalid interface";
}
};
/**
* \brief Exception thrown when PacketSender fails to open a socket.
*/
class socket_open_error : public std::runtime_error {
public:
socket_open_error(const std::string &msg)
: std::runtime_error(msg) { }
};
/**
* \brief Exception thrown when PacketSender fails to close a socket.
*/
class socket_close_error : public std::runtime_error {
public:
socket_close_error(const std::string &msg)
: std::runtime_error(msg) { }
};
/**
* \brief Exception thrown when PacketSender fails to write on a socket.
*/
class socket_write_error : public std::runtime_error {
public:
socket_write_error(const std::string &msg)
: std::runtime_error(msg) { }
};
/**
* \brief Exception thrown when an invalid socket type is provided
* to PacketSender.
*/
class invalid_socket_type : public std::exception {
public:
const char *what() const throw() {
return "The provided socket type is invalid";
}
};
}
#endif // TINS_EXCEPTIONS_H

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, Nasel
* Copyright (c) 2012, Matias Fontanini
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, Nasel
* Copyright (c) 2012, Matias Fontanini
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -30,7 +30,7 @@
#ifndef TINS_ICMP_H
#define TINS_ICMP_H
#include "macros.h"
#include "pdu.h"
#include "endianness.h"
@@ -71,8 +71,13 @@ namespace Tins {
ICMP(Flags flag = ECHO_REQUEST);
/**
* \brief Constructor which creates an ICMP object from a buffer and adds all identifiable
* PDUs found in the buffer as children of this one.
* \brief Constructs an ICMP object from a buffer.
*
* If there is not enough size for an ICMP header, a
* malformed_packet exception is thrown.
*
* Any extra data in the buffer will be stored in a RawPDU.
*
* \param buffer The buffer from which this PDU will be constructed.
* \param total_sz The total size of the buffer.
*/
@@ -141,14 +146,6 @@ namespace Tins {
*/
void set_echo_request(uint16_t id, uint16_t seq);
/**
* \brief Sets echo request flag for this PDU.
*
* This uses a global id and sequence number to fill the request's
* fields.
*/
void set_echo_request();
/**
* \brief Sets echo reply flag for this PDU.
*
@@ -157,14 +154,6 @@ namespace Tins {
*/
void set_echo_reply(uint16_t id, uint16_t seq);
/**
* \brief Sets echo reply flag for this PDU.
*
* This uses a global id and sequence number to fill the request's
* fields.
*/
void set_echo_reply();
/**
* \brief Sets information request flag for this PDU.
*
@@ -290,7 +279,7 @@ namespace Tins {
* \param ptr The pointer to the buffer.
* \param total_sz The size of the buffer.
*/
bool matches_response(uint8_t *ptr, uint32_t total_sz);
bool matches_response(const uint8_t *ptr, uint32_t total_sz) const;
/**
* \brief Getter for the PDU's type.
@@ -298,17 +287,6 @@ namespace Tins {
* \sa PDU::pdu_type
*/
PDUType pdu_type() const { return PDU::ICMP; }
/**
* \brief Clones this pdu, filling the corresponding header with data
* extracted from a buffer.
*
* \param ptr The pointer to the from from which the data will be extracted.
* \param total_sz The size of the buffer.
* \return The cloned PDU.
* \sa PDU::clone_packet
*/
PDU *clone_packet(const uint8_t *ptr, uint32_t total_sz);
/**
* \sa PDU::clone
@@ -317,8 +295,7 @@ namespace Tins {
return new ICMP(*this);
}
private:
static uint16_t global_id, global_seq;
TINS_BEGIN_PACK
struct icmphdr {
uint8_t type;
uint8_t code;
@@ -330,12 +307,12 @@ namespace Tins {
} echo;
uint32_t gateway;
struct {
uint16_t __unused;
uint16_t unused;
uint16_t mtu;
} frag;
uint8_t pointer;
} un;
} __attribute__((__packed__));
} TINS_END_PACK;
/** \brief Serialices this ICMP PDU.
* \param buffer The buffer in which the PDU will be serialized.
@@ -346,6 +323,6 @@ namespace Tins {
icmphdr _icmp;
};
};
}
#endif // TINS_ICMP_H

1237
include/icmpv6.h Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, Nasel
* Copyright (c) 2012, Matias Fontanini
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -30,191 +30,11 @@
#ifndef TINS_IEEE802_3_H
#define TINS_IEEE802_3_H
#include <stdint.h>
#include "pdu.h"
#include "endianness.h"
#include "hw_address.h"
#include "network_interface.h"
#include "dot3.h"
namespace Tins {
/**
* \brief Class representing an Ethernet II PDU.
*/
class IEEE802_3 : public PDU {
public:
/**
* \brief The address type.
*/
typedef HWAddress<6> address_type;
/**
* \brief This PDU's flag.
*/
static const PDU::PDUType pdu_flag = PDU::IEEE802_3;
/**
* \brief Represents the IEEE802_3 broadcast address.
*/
static const address_type BROADCAST;
/**
* \brief Constructor for creating an IEEE802_3 PDU
*
* Constructor that builds an IEEE802_3 PDU taking the interface name,
* destination's and source's MAC.
*
* \param iface string containing the interface's name from where to send the packet.
* \param dst_hw_addr The destination hardware address.
* \param src_hw_addr The source hardware address.
* \param child The PDU which will be set as the inner PDU.
*/
IEEE802_3(const NetworkInterface& iface = NetworkInterface(),
const address_type &dst_hw_addr = address_type(),
const address_type &src_hw_addr = address_type(),
PDU* child = 0);
/**
* \brief Constructor which creates an IEEE802_3 object from a buffer and adds all identifiable
* PDUs found in the buffer as children of this one.
* \param buffer The buffer from which this PDU will be constructed.
* \param total_sz The total size of the buffer.
*/
IEEE802_3(const uint8_t *buffer, uint32_t total_sz);
/* Getters */
/**
* \brief Getter for the destination hardware address.
*
* \return The destination hardware address.
*/
address_type dst_addr() const { return _eth.dst_mac; }
/**
* \brief Getter for the source hardware address.
*
* \return The source hardware address.
*/
address_type src_addr() const { return _eth.src_mac; }
/**
* \brief Getter for the interface.
*
* \return The network interface.
*/
const NetworkInterface &iface() const { return this->_iface; }
/**
* \brief Getter for the length field.
* \return The length field value.
*/
uint16_t length() const { return Endian::be_to_host(_eth.length); };
/* Setters */
/**
* \brief Setter for the destination hardware address.
*
* \param new_dst_mac The new destination hardware address.
*/
void dst_addr(const address_type &new_dst_mac);
/**
* \brief Setter for the source hardware address.
*
* \param new_src_mac The new source hardware address.
*/
void src_addr(const address_type &new_src_mac);
/**
* \brief Setter for the interface.
*
* \param new_iface The interface in which to send this PDU.
*/
void iface(const NetworkInterface &new_iface);
/**
* \brief Setter for the length field.
*
* \param new_length uint16_t with the new value of the length field.
*/
void length(uint16_t new_length);
/* Virtual methods */
/**
* \brief Returns the IEEE802_3 frame's header length.
*
* \return An uint32_t with the header's size.
* \sa PDU::header_size()
*/
uint32_t header_size() const;
#ifndef WIN32
/**
* \sa PDU::send()
*/
void send(PacketSender &sender);
#endif // WIN32
/** \brief Check wether ptr points to a valid response for this PDU.
*
* \sa PDU::matches_response
* \param ptr The pointer to the buffer.
* \param total_sz The size of the buffer.
*/
bool matches_response(uint8_t *ptr, uint32_t total_sz);
#ifndef WIN32
/** \brief Receives a matching response for this packet.
*
* \sa PDU::recv_response
* \param sender The packet sender which will receive the packet.
*/
PDU *recv_response(PacketSender &sender);
#endif // WIN32
/**
* \brief Getter for the PDU's type.
* \sa PDU::pdu_type
*/
PDUType pdu_type() const { return PDU::IEEE802_3; }
/**
* \brief Clones this pdu, filling the corresponding header with data
* extracted from a buffer.
*
* \param ptr The pointer to the from from which the data will be extracted.
* \param total_sz The size of the buffer.
* \return The cloned PDU.
* \sa PDU::clone_packet
*/
PDU *clone_packet(const uint8_t *ptr, uint32_t total_sz);
/**
* \sa PDU::clone
*/
IEEE802_3 *clone() const {
return new IEEE802_3(*this);
}
private:
/**
* Struct that represents the Ethernet II header
*/
struct ethhdr {
uint8_t dst_mac[address_type::address_size];
uint8_t src_mac[address_type::address_size];
uint16_t length;
} __attribute__((__packed__));
void write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *parent);
ethhdr _eth;
NetworkInterface _iface;
};
};
typedef Dot3 IEEE802_3;
}
#endif // TINS_IEEE802_3_H

69
include/internals.h Normal file
View File

@@ -0,0 +1,69 @@
/*
* 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_INTERNALS_H
#define TINS_INTERNALS_H
#include <sstream>
#include <string>
#include <stdint.h>
#include "constants.h"
#include "pdu.h"
/**
* \cond
*/
namespace Tins {
namespace Internals {
void skip_line(std::istream &input);
bool from_hex(const std::string &str, uint32_t &result);
template<bool, typename>
struct enable_if {
};
template<typename T>
struct enable_if<true, T> {
typedef T type;
};
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(PDU::PDUType type, const uint8_t *buffer, uint32_t size);
Constants::Ethernet::e pdu_flag_to_ether_type(PDU::PDUType flag);
}
}
/**
* \endcond
*/
#endif

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, Nasel
* Copyright (c) 2012, Matias Fontanini
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -36,6 +36,8 @@
#include "endianness.h"
#include "ip_address.h"
#include "pdu_option.h"
#include "macros.h"
#include "cxxstd.h"
namespace Tins {
@@ -49,7 +51,7 @@ namespace Tins {
class IP : public PDU {
public:
/**
* his PDU's flag.
* This PDU's flag.
*/
static const PDU::PDUType pdu_flag = PDU::IP;
@@ -99,6 +101,7 @@ namespace Tins {
/**
* \brief The type used to represent an option's type.
*/
TINS_BEGIN_PACK
struct option_identifier {
#if TINS_IS_LITTLE_ENDIAN
uint8_t number:5,
@@ -161,12 +164,12 @@ namespace Tins {
bool operator==(const option_identifier &rhs) const {
return number == rhs.number && op_class == rhs.op_class && copied == rhs.copied;
}
} __attribute__((__packed__));
} TINS_END_PACK;
/**
* The IP options type.
*/
typedef PDUOption<option_identifier> ip_option;
typedef PDUOption<option_identifier> option;
/**
* The type of the security option.
@@ -212,6 +215,11 @@ namespace Tins {
*/
typedef generic_route_option_type record_route_type;
/**
* The type used to store IP options.
*/
typedef std::list<option> options_type;
/**
* \brief Constructor for building the IP PDU.
*
@@ -221,16 +229,18 @@ namespace Tins {
*
* \param ip_dst The destination ip address(optional).
* \param ip_src The source ip address(optional).
* \param child pointer to a PDU which will be set as the inner_pdu
* for the packet being constructed(optional).
*/
IP(address_type ip_dst = address_type(),
address_type ip_src = address_type(),
PDU *child = 0);
address_type ip_src = address_type());
/**
* \brief Constructor which creates an IP object from a buffer and adds all identifiable
* PDUs found in the buffer as children of this one.
* \brief Constructs an IP 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 IP 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.
*/
@@ -257,7 +267,9 @@ namespace Tins {
*
* \return The total length of this IP PDU.
*/
uint16_t tot_len() const { return Endian::be_to_host(_ip.tot_len); }
uint16_t tot_len() const {
return Endian::be_to_host(_ip.tot_len);
}
/**
* \brief Getter for the id field.
@@ -292,7 +304,7 @@ namespace Tins {
*
* \return The checksum for this IP PDU.
*/
uint16_t check() const { return Endian::be_to_host(_ip.check); }
uint16_t checksum() const { return Endian::be_to_host(_ip.check); }
/**
* \brief Getter for the source address field.
@@ -313,6 +325,12 @@ namespace Tins {
*/
small_uint<4> version() const { return _ip.version; }
/**
* \brief Getter for the IP options.
* \return The stored options.
*/
const options_type &options() const { return _ip_options; }
/* Setters */
/**
@@ -364,13 +382,6 @@ namespace Tins {
*/
void protocol(uint8_t new_protocol);
/**
* \brief Setter for the checksum field.
*
* \param new_check The new checksum.
*/
void check(uint16_t new_check);
/**
* \brief Setter for the source address field.
*
@@ -398,15 +409,34 @@ namespace Tins {
* The option is added after the last option in the option
* fields.
*
* \param option The option to be added
* \param opt The option to be added
*/
void add_option(const ip_option &option);
void add_option(const option &opt);
#if TINS_IS_CXX11
/**
* \brief Adds an IP option.
*
* The option is move-constructed.
*
* \param opt The option to be added.
*/
void add_option(option &&opt) {
internal_add_option(opt);
_ip_options.push_back(std::move(opt));
}
#endif
/**
* \brief Searchs for an option that matchs the given flag.
*
* If the option is not found, a null pointer is returned.
* Deleting the returned pointer will result in <b>undefined
* behaviour</b>.
*
* \param id The option identifier to be searched.
*/
const ip_option *search_option(option_identifier id) const;
const option *search_option(option_identifier id) const;
// Option setters
@@ -533,7 +563,7 @@ namespace Tins {
/**
* \sa PDU::send()
*/
void send(PacketSender &sender);
void send(PacketSender &sender, const NetworkInterface &);
/**
* \brief Check wether ptr points to a valid response for this PDU.
@@ -542,7 +572,7 @@ namespace Tins {
* \param ptr The pointer to the buffer.
* \param total_sz The size of the buffer.
*/
bool matches_response(uint8_t *ptr, uint32_t total_sz);
bool matches_response(const uint8_t *ptr, uint32_t total_sz) const;
/**
* \brief Receives a matching response for this packet.
@@ -550,7 +580,7 @@ namespace Tins {
* \sa PDU::recv_response
* \param sender The packet sender which will receive the packet.
*/
PDU *recv_response(PacketSender &sender);
PDU *recv_response(PacketSender &sender, const NetworkInterface &);
/**
* \brief Getter for the PDU's type.
@@ -558,17 +588,6 @@ namespace Tins {
*/
PDUType pdu_type() const { return PDU::IP; }
/**
* \brief Clones this pdu, filling the corresponding header with data
* extracted from a buffer.
*
* \param ptr The pointer to the from from which the data will be extracted.
* \param total_sz The size of the buffer.
* \return The cloned PDU.
* \sa PDU::clone_packet
*/
PDU *clone_packet(const uint8_t *ptr, uint32_t total_sz);
/**
* \sa PDU::clone
*/
@@ -578,15 +597,14 @@ namespace Tins {
private:
static const uint8_t DEFAULT_TTL;
TINS_BEGIN_PACK
struct iphdr {
#if TINS_IS_LITTLE_ENDIAN
unsigned int ihl:4;
unsigned int version:4;
#elif TINS_IS_BIG_ENDIAN
unsigned int version:4;
unsigned int ihl:4;
uint8_t ihl:4,
version:4;
#else
# error "Endian is not LE nor BE..."
uint8_t version:4,
ihl:4;
#endif
uint8_t tos;
uint16_t tot_len;
@@ -598,18 +616,21 @@ namespace Tins {
uint32_t saddr;
uint32_t daddr;
/*The options start here. */
} __attribute__((__packed__));
} TINS_END_PACK;
void prepare_for_serialize(const PDU *parent);
void internal_add_option(const option &option);
void init_ip_fields();
void write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *parent);
uint8_t* write_option(const ip_option &opt, uint8_t* buffer);
uint8_t* write_option(const option &opt, uint8_t* buffer);
void add_route_option(option_identifier id, const generic_route_option_type &data);
generic_route_option_type search_route_option(option_identifier id) const;
void checksum(uint16_t new_check);
iphdr _ip;
std::list<ip_option> _ip_options;
uint32_t _options_size, _padded_options_size;
uint16_t _options_size, _padded_options_size;
options_type _ip_options;
};
};
}
#endif // TINS_IP_H

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, Nasel
* Copyright (c) 2012, Matias Fontanini
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -136,7 +136,7 @@ namespace Tins {
uint32_t ip_addr;
};
};
}
#endif // TINS_IPADDRESS_H

330
include/ipv6.h Normal file
View File

@@ -0,0 +1,330 @@
/*
* 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_IPV6_h
#define TINS_IPV6_h
#include <list>
#include <stdexcept>
#include "macros.h"
#include "pdu.h"
#include "endianness.h"
#include "small_uint.h"
#include "pdu_option.h"
#include "ipv6_address.h"
namespace Tins {
class PacketSender;
/**
* Represents an IPv6 PDU.
*/
class IPv6 : public PDU {
public:
/**
* This PDU's flag.
*/
static const PDU::PDUType pdu_flag = PDU::IPv6;
/**
* The type used to store addresses.
*/
typedef IPv6Address address_type;
/**
* The type used to represent IPv6 extension headers.
*/
typedef PDUOption<uint8_t> ext_header;
/**
* The type used to store the extension headers.
*/
typedef std::list<ext_header> headers_type;
/**
* The values used to identify extension headers.
*/
enum ExtensionHeader {
HOP_BY_HOP = 0,
DESTINATION_ROUTING_OPTIONS = 60,
ROUTING = 43,
FRAGMENT = 44,
AUTHENTICATION = 51,
SECURITY_ENCAPSULATION = 50,
DESTINATION_OPTIONS = 60,
MOBILITY = 135,
NO_NEXT_HEADER = 59
};
/**
* \brief Constructs an IPv6 object.
*
* \param ip_dst The destination ip address(optional).
* \param ip_src The source ip address(optional).
* \param child pointer to a PDU which will be set as the inner_pdu
* for the packet being constructed(optional).
*/
IPv6(address_type ip_dst = address_type(),
address_type ip_src = address_type(),
PDU *child = 0);
/**
* \brief Constructs an IPv6 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 IPv6 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.
*/
IPv6(const uint8_t *buffer, uint32_t total_sz);
// Getters
/**
* \brief Getter for the version field.
* \return The stored version field value.
*/
small_uint<4> version() const {
return _header.version;
}
/**
* \brief Getter for the traffic_class field.
* \return The stored traffic_class field value.
*/
uint8_t traffic_class() const {
#if TINS_IS_LITTLE_ENDIAN
return ((_header.traffic_class << 4) & 0xf0) |
((_header.flow_label[0] >> 4) & 0x0f);
#else
return _header.traffic_class;
#endif
}
/**
* \brief Getter for the flow_label field.
* \return The stored flow_label field value.
*/
small_uint<20> flow_label() const {
#if TINS_IS_LITTLE_ENDIAN
return ((_header.flow_label[0] & 0x0f) << 16)
| (_header.flow_label[1] << 8)
| (_header.flow_label[2]);
#else
return _header.flow_label;
#endif
}
/**
* \brief Getter for the payload_length field.
* \return The stored payload_length field value.
*/
uint16_t payload_length() const {
return Endian::be_to_host(_header.payload_length);
}
/**
* \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 hop_limit field.
* \return The stored hop_limit field value.
*/
uint8_t hop_limit() const {
return _header.hop_limit;
}
/**
* \brief Getter for the src_addr field.
* \return The stored src_addr field value.
*/
address_type src_addr() const {
return _header.src_addr;
}
/**
* \brief Getter for the dst_addr field.
* \return The stored dst_addr field value.
*/
address_type dst_addr() const {
return _header.dst_addr;
}
/**
* \brief Getter for the IPv6 extension headers.
* \return The stored headers.
*/
const headers_type& headers() const {
return ext_headers;
}
// Setters
/**
* \brief Setter for the version field.
* \param new_version The new version field value.
*/
void version(small_uint<4> new_version);
/**
* \brief Setter for the traffic_class field.
* \param new_traffic_class The new traffic_class field value.
*/
void traffic_class(uint8_t new_traffic_class);
/**
* \brief Setter for the flow_label field.
* \param new_flow_label The new flow_label field value.
*/
void flow_label(small_uint<20> new_flow_label);
/**
* \brief Setter for the payload_length field.
* \param new_payload_length The new payload_length field value.
*/
void payload_length(uint16_t new_payload_length);
/**
* \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 hop_limit field.
* \param new_hop_limit The new hop_limit field value.
*/
void hop_limit(uint8_t new_hop_limit);
/**
* \brief Setter for the src_addr field.
* \param new_src_addr The new src_addr field value.
*/
void src_addr(const address_type &new_src_addr);
/**
* \brief Setter for the dst_addr field.
* \param new_dst_addr The new dst_addr field value.
*/
void dst_addr(const address_type &new_dst_addr);
/**
* \brief Returns the header size.
*
* This metod overrides PDU::header_size. \sa PDU::header_size
*/
uint32_t header_size() const;
/**
* \brief Check wether ptr points to a valid response for this PDU.
*
* \sa PDU::matches_response
* \param ptr The pointer to the buffer.
* \param total_sz The size of the buffer.
*/
bool matches_response(const uint8_t *ptr, uint32_t total_sz) const;
/**
* \sa PDU::clone
*/
IPv6 *clone() const {
return new IPv6(*this);
}
/**
* \brief Getter for the PDU's type.
* \sa PDU::pdu_type
*/
PDUType pdu_type() const { return pdu_flag; }
#ifndef BSD
/**
* \sa PDU::send()
*/
void send(PacketSender &sender, const NetworkInterface &);
#endif
/**
* Adds an extension header.
*
* \param header The extension header to be added.
*/
void add_ext_header(const ext_header &header);
/**
* \brief Searchs for an extension header that matchs the given
* flag.
*
* If the header is not found, a null pointer is returned.
* Deleting the returned pointer will result in <b>undefined
* behaviour</b>.
*
* \param id The header identifier to be searched.
*/
const ext_header *search_header(ExtensionHeader id) const;
private:
void write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *parent);
void set_last_next_header(uint8_t value);
static uint8_t *write_header(const ext_header &header, uint8_t *buffer);
static bool is_extension_header(uint8_t header_id);
TINS_BEGIN_PACK
struct ipv6_header {
#if TINS_IS_BIG_ENDIAN
uint32_t version:4,
traffic_class:8,
flow_label:20;
uint32_t payload_length:16,
next_header:8,
hop_limit:8;
#else
uint8_t traffic_class:4,
version:4;
uint8_t flow_label[3];
uint16_t payload_length;
uint8_t next_header;
uint8_t hop_limit;
#endif
uint8_t src_addr[16], dst_addr[16];
} TINS_END_PACK;
ipv6_header _header;
headers_type ext_headers;
uint32_t headers_size;
};
}
#endif // TINS_IPV6_h

197
include/ipv6_address.h Normal file
View File

@@ -0,0 +1,197 @@
/*
* 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_IPV6_ADDRESS
#define TINS_IPV6_ADDRESS
#include <string>
#include <stdexcept>
#include <stdint.h>
namespace Tins {
class IPv6Address {
public:
/**
* The exception thrown when a malformed address is parsed.
*/
class malformed_address : public std::exception {
public:
const char *what() const throw() {
return "Malformed address";
}
};
static const size_t address_size = 16;
/**
* The iterator type.
*/
typedef uint8_t* iterator;
/**
* The const iterator type.
*/
typedef const uint8_t* const_iterator;
/**
* \brief Default constructor.
* Initializes this IPv6 address to "::"
*/
IPv6Address();
/**
* \brief Constructor from a text representation char*.
* \param addr The text representation from which to construct this
* object.
*/
IPv6Address(const char *addr);
/**
* \brief Constructor from a text representation std::string.
* \param addr The text representation from which to construct this
* object.
*/
IPv6Address(const std::string &addr);
/**
* \brief Constructor from a buffer.
*
* The ptr parameter must be at least address_size bytes long.
*
* \param ptr The buffer from which to construct this object.
*/
IPv6Address(const_iterator ptr);
/**
* \brief Retrieve the string representation of this address.
*
* \return std::string containing the representation of this address.
*/
std::string to_string() const;
/**
* Returns an iterator to the beginning of this address.
*/
iterator begin() {
return address;
}
/**
* Returns a const iterator to the beginning of this address.
*/
const_iterator begin() const {
return address;
}
/**
* Returns an iterator to the one-past-the-end element of this address.
*/
iterator end() {
return address + address_size;
}
/**
* Returns a const iterator to the one-past-the-end element of this
* address.
*/
const_iterator end() const {
return address + address_size;
}
/**
* \brief Compares this address for equality.
*
* \param rhs The address to be compared to.
*
* \return bool indicating whether addresses are equal.
*/
bool operator==(const IPv6Address &rhs) const {
return std::equal(begin(), end(), rhs.begin());
}
/**
* \brief Compares this address for inequality.
*
* \param rhs The address to be compared to.
*
* \return bool indicating whether addresses are distinct.
*/
bool operator!=(const IPv6Address &rhs) const {
return !(*this == rhs);
}
/**
* \brief Compares this address for less-than inequality.
*
* \param rhs The address to be compared to.
*
* \return bool indicating whether this address is less-than rhs.
*/
bool operator<(const IPv6Address &rhs) const {
return std::lexicographical_compare(begin(), end(), rhs.begin(), rhs.end());
}
/**
* \brief Helper function which copies the address into an output
* iterator.
*
* This is the same as:
*
* std::copy(begin(), end(), iter);
*
* But since some PDUs return a IPv6Address by value, this function
* can be used to avoid temporaries.
*
* \param iter The output iterator in which to store this address.
* \return OutputIterator pointing to one-past the last position
* written.
*/
template<typename OutputIterator>
OutputIterator copy(OutputIterator iter) const {
return std::copy(begin(), end(), iter);
}
/**
* \brief Writes this address in hex-notation to a std::ostream.
*
* \param os The stream in which to write the address.
* \param addr The parameter to be written.
* \return std::ostream& pointing to the os parameter.
*/
friend std::ostream &operator<<(std::ostream &os, const IPv6Address &addr) {
return os << addr.to_string();
}
private:
void init(const char *addr);
uint8_t address[address_size];
};
}
#endif // TINS_IPV6_ADDRESS

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, Nasel
* Copyright (c) 2012, Matias Fontanini
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -33,6 +33,7 @@
#include <list>
#include <vector>
#include <stdint.h>
#include "macros.h"
#include "pdu.h"
#include "endianness.h"
@@ -89,22 +90,25 @@ namespace Tins {
};
/**
* \brief Creates an instance of LLC
* \param child The child PDU.(optional)
* \brief Default constructor.
*/
LLC(PDU *child = 0);
LLC();
/**
* \brief Creates an instance of LLC, setting the dsap and ssap.
* The control field is set all to 0.
* @param dsap The dsap value to be set.
* @param ssap The ssap value to be set.
* \brief Constructs an instance of LLC, setting the dsap and ssap.
* The control field is set to 0.
* \param dsap The dsap value to be set.
* \param ssap The ssap value to be set.
*/
LLC(uint8_t dsap, uint8_t ssap, PDU* child = 0);
LLC(uint8_t dsap, uint8_t ssap);
/**
* \brief Constructor which creates a LLC object from a buffer and adds all identifiable
* PDUs found in the buffer as children of this one.
* \brief Constructs a LLC 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 a LLC 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.
*/
@@ -314,62 +318,67 @@ namespace Tins {
return new LLC(*this);
}
private:
TINS_BEGIN_PACK
struct llchdr {
uint8_t dsap;
uint8_t ssap;
} __attribute__((__packed__));
} TINS_END_PACK;
#if TINS_IS_LITTLE_ENDIAN
TINS_BEGIN_PACK
struct info_control_field {
uint16_t
type_bit:1,
send_seq_num:7,
poll_final_bit:1,
recv_seq_num:7;
} __attribute__((__packed__));
} TINS_END_PACK;
TINS_BEGIN_PACK
struct super_control_field {
uint16_t type_bit:2,
supervisory_func:2,
unused:4,
poll_final_bit:1,
recv_seq_num:7;
} __attribute__((__packed__));
} TINS_END_PACK;
TINS_BEGIN_PACK
struct un_control_field {
uint8_t type_bits:2,
mod_func1:2,
poll_final_bit:1,
mod_func2:3;
} __attribute__((__packed__));
} TINS_END_PACK;
#elif TINS_IS_BIG_ENDIAN
TINS_BEGIN_PACK
struct info_control_field {
uint16_t send_seq_num:7,
type_bit:1,
recv_seq_num:7,
poll_final_bit:1;
} __attribute__((__packed__));
} TINS_END_PACK;
TINS_BEGIN_PACK
struct super_control_field {
uint16_t unused:4,
supervisory_func:2,
type_bit:2,
recv_seq_num:7,
poll_final_bit:1;
} __attribute__((__packed__));
} TINS_END_PACK;
TINS_BEGIN_PACK
struct un_control_field {
uint8_t mod_func2:3,
poll_final_bit:1,
mod_func1:2,
type_bits:2;
} __attribute__((__packed__));
} TINS_END_PACK;
#endif
typedef std::vector<uint8_t> field_type;
void copy_fields(const LLC *other);
void write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *parent);
llchdr _header;
@@ -384,6 +393,6 @@ namespace Tins {
std::list<field_type> information_fields;
};
};
}
#endif // TINS_IEEE8022_H

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, Nasel
* Copyright (c) 2012, Matias Fontanini
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -31,6 +31,7 @@
#define TINS_LOOPBACK_H
#include "pdu.h"
#include "macros.h"
namespace Tins {
class Loopback : public PDU {
@@ -46,17 +47,16 @@ public:
* The family identifier is left as zero.
*/
Loopback();
/**
* \brief Construct a Loopback object.
*
* \param family_id The family id to be used.
* \param inner_pdu The inner pdu to be set.
*/
Loopback(uint32_t family_id, PDU *inner_pdu = 0);
/**
* \brief Construct a Loopback object from a buffer.
* \brief Construct a Loopback object from a buffer and adds
* all identifiable PDUs found in the buffer as children of
* this one.
*
* If the next PDU is not recognized, then a RawPDU is used.
*
* If there is not enough size for a Loopback 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.
@@ -92,6 +92,13 @@ public:
Loopback *clone() const {
return new Loopback(*this);
}
// Null/Loopback can only be sent in *BSD
#ifdef BSD
/**
* \sa PDU::send()
*/
void send(PacketSender &sender, const NetworkInterface &iface);
#endif // BSD
private:
void write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *parent);

50
include/macros.h Normal file
View File

@@ -0,0 +1,50 @@
/*
* 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_MACROS_H
#define TINS_MACROS_H
#if defined(__unix__) || (defined(__APPLE__) && defined(__MACH__))
#include <sys/param.h>
#endif
// Packing directives....
#ifdef _MSC_VER
#define TINS_BEGIN_PACK __pragma( pack(push, 1) )
#define TINS_END_PACK __pragma( pack(pop) )
#define TINS_PACKED(DECLARATION) __pragma( pack(push, 1) ) DECLARATION __pragma( pack(pop) )
#define TINS_DEPRECATED(func) __declspec(deprecated) func
#else
#define TINS_BEGIN_PACK
#define TINS_END_PACK __attribute__((packed))
#define TINS_PACKED(DECLARATION) DECLARATION __attribute__((packed))
#define TINS_DEPRECATED(func) func __attribute__ ((deprecated))
#endif
#endif

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, Nasel
* Copyright (c) 2012, Matias Fontanini
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without

292
include/packet.h Normal file
View File

@@ -0,0 +1,292 @@
/*
* 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_PACKET_H
#define TINS_PACKET_H
#include <algorithm>
#include "cxxstd.h"
#include "pdu.h"
#include "timestamp.h"
/**
* \namespace Tins
*/
namespace Tins {
template<typename WrappedType, typename TimestampType>
class PacketWrapper;
/**
* \brief Thin wrapper over a PDU and Timestamp reference.
*/
typedef PacketWrapper<PDU&, const Timestamp&> RefPacket;
/**
* \brief Thin wrapper over a PDU pointer and a Timestamp.
*/
typedef PacketWrapper<PDU*, Timestamp> PtrPacket;
/**
* \brief Represents a sniffed packet.
*
* RefPackets contain a PDU reference and a timestamp. The difference between
* this class and the Packet class is that this one contains a reference
* to a PDU, and not a pointer to one.
*
* This class is only used in some BaseSniffer methods as a thin wrapper
* to a PDU pointer/reference. Only BaseSniffer and derived objects can
* create instances of it.
*/
template<typename PDUType, typename TimestampType>
class PacketWrapper {
public:
typedef PDUType pdu_type;
typedef TimestampType timestamp_type;
/**
* \brief User defined conversion to wrapped_type.
*
* This conversion is defined so that BaseSniffer::sniff_loop callback
* or code that calls BaseSniffer::next_packet can still receive a
* PDU pointer/reference without modifying the code at all.
*/
operator pdu_type() {
return pdu_;
}
/**
* \brief Returns the wrapped_type.
*/
pdu_type pdu() {
return pdu_;
}
/**
* \brief Returns the PDU const reference.
*/
const pdu_type pdu() const {
return pdu_;
}
/**
* \brief Returns the packet timestamp.
*
* This is the timestamp in which the packet was taken out of the
* network interface/pcap file.
*/
const Timestamp &timestamp() const {
return ts_;
}
private:
friend class BaseSniffer;
PacketWrapper(pdu_type pdu, const Timestamp &ts)
: pdu_(pdu), ts_(ts) {}
PacketWrapper(const PacketWrapper&);
PacketWrapper& operator=(const PacketWrapper&);
void* operator new (size_t size);
void operator delete (void *p);
pdu_type pdu_;
timestamp_type ts_;
};
/**
* \class Represents a sniffed packet.
*
* A Packet contains a PDU pointer and a Timestamp object. Packets
* <b>will delete</b> the stored PDU* unless you call release_pdu at
* some point before destruction.
*/
class Packet {
public:
/**
* \brief Default constructs a Packet.
*
* The PDU* will be set to a null pointer.
*/
Packet()
: pdu_(0) { }
/**
* \brief Constructs a Packet from a PDU* and a Timestamp.
*
* The PDU* is cloned using PDU::clone.
*/
Packet(const PDU *apdu, const Timestamp &tstamp)
: pdu_(apdu->clone()), ts(tstamp) { }
/**
* \brief Constructs a Packet from a const PDU&.
*
* The timestamp will be set to the current time.
*
* This calls PDU::clone on the PDU parameter.
*
*/
Packet(const PDU &rhs)
: pdu_(rhs.clone()), ts(Timestamp::current_time()) { }
/**
* \brief Constructs a Packet from a RefPacket.
*
* This calls PDU::clone on the RefPacket's PDU.
*
*/
Packet(const RefPacket &pck)
: pdu_(pck.pdu().clone()), ts(pck.timestamp()) { }
/**
* \brief Constructs a Packet from a PtrPacket object.
*/
Packet(const PtrPacket &pck)
: pdu_(pck.pdu()), ts(pck.timestamp()) { }
/**
* \brief Copy constructor.
*
* This calls PDU::clone on the rhs's PDU* member.
*/
Packet(const Packet &rhs) : ts(rhs.timestamp()) {
pdu_ = rhs.pdu() ? rhs.pdu()->clone() : 0;
}
/**
* \brief Copy assignment operator.
*
* This calls PDU::clone on the rhs's PDU* member.
*/
Packet& operator=(const Packet &rhs) {
if(this != &rhs) {
delete pdu_;
ts = rhs.timestamp();
pdu_ = rhs.pdu() ? rhs.pdu()->clone() : 0;
}
return *this;
}
#if TINS_IS_CXX11
/**
* Move constructor.
*/
Packet(Packet &&rhs) noexcept : pdu_(rhs.pdu()), ts(rhs.timestamp()) {
rhs.pdu_ = nullptr;
}
/**
* Move assignment operator.
*/
Packet& operator=(Packet &&rhs) noexcept {
if(this != &rhs) {
std::swap(pdu_, rhs.pdu_);
ts = rhs.timestamp();
}
return *this;
}
#endif
/**
* \brief Packet destructor.
*
* This calls operator delete on the stored PDU*.
*/
~Packet() {
delete pdu_;
}
/**
* Returns this Packet's timestamp.
*/
const Timestamp &timestamp() const {
return ts;
}
/**
* \brief Returns the stored PDU*.
*
* Caller <b>must not</b> delete the pointer. \sa Packet::release_pdu
*/
PDU *pdu() {
return pdu_;
}
/**
* \brief Returns the stored PDU*.
*
* Caller <b>must not</b> delete the pointer. \sa Packet::release_pdu
*/
const PDU *pdu() const {
return pdu_;
}
/**
* \brief Releases ownership of the stored PDU*.
*
* This method returns the stored PDU* and sets the stored PDU* to
* a null pointer, so the destructor will be well behaved. Use this
* method if you want to keep the internal PDU* somewhere. Otherwise,
* when Packet's destructor is called, the stored pointer will be
* deleted.
*/
PDU *release_pdu() {
PDU *some_pdu = pdu_;
pdu_ = 0;
return some_pdu;
}
/**
* \brief Tests whether this is Packet contains a valid PDU.
*
* \return true if pdu() == nullptr, false otherwise.
*/
operator bool() const {
return bool(pdu_);
}
/**
*
* \brief Concatenation operator.
*
* Adds the PDU at the end of the PDU stack.
*
* \param rhs The PDU to be appended.
*/
Packet &operator/=(const PDU &rhs) {
pdu_ /= rhs;
return *this;
}
private:
PDU *pdu_;
Timestamp ts;
};
}
#endif // TINS_PACKET_H

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, Nasel
* Copyright (c) 2012, Matias Fontanini
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -36,12 +36,16 @@
#include <vector>
#include <stdint.h>
#include <map>
#include "network_interface.h"
#include "macros.h"
#include "cxxstd.h"
struct timeval;
struct sockaddr;
namespace Tins {
class PDU;
/**
* \brief Class that enables sending the created PDUs
*
@@ -60,9 +64,12 @@ namespace Tins {
*/
enum SocketType {
ETHER_SOCKET,
IP_SOCKET,
IP_TCP_SOCKET,
IP_UDP_SOCKET,
IP_RAW_SOCKET,
ARP_SOCKET,
ICMP_SOCKET,
IPV6_SOCKET,
SOCKETS_END
};
@@ -71,7 +78,40 @@ namespace Tins {
*
* \param recv_timeout The timeout which will be used when receiving responses.
*/
PacketSender(uint32_t recv_timeout = DEFAULT_TIMEOUT, uint32_t usec = 0);
PacketSender(const NetworkInterface &iface = NetworkInterface(),
uint32_t recv_timeout = DEFAULT_TIMEOUT, uint32_t usec = 0);
#if TINS_IS_CXX11
/**
* \brief Move constructor.
* \param rhs The sender to be moved.
*/
PacketSender(PacketSender &&rhs) noexcept {
*this = std::move(rhs);
}
/**
* \brief Move assignment operator.
* \param rhs The sender to be moved.
*/
PacketSender& operator=(PacketSender &&rhs) noexcept {
_sockets = std::move(rhs._sockets);
rhs._sockets = std::vector<int>(SOCKETS_END, INVALID_RAW_SOCKET);
#ifndef WIN32
#if defined(BSD) || defined(__FreeBSD_kernel__)
_ether_socket = std::move(rhs._ether_socket);
#else
_ether_socket = rhs._ether_socket;
rhs._ether_socket = INVALID_RAW_SOCKET;
#endif
#endif
_types = rhs._types; // no move
_timeout = rhs._timeout;
_timeout_usec = rhs._timeout_usec;
default_iface = rhs.default_iface;
return *this;
}
#endif
/**
* \brief PacketSender destructor.
@@ -84,18 +124,18 @@ namespace Tins {
/**
* \brief Opens a layer 2 socket.
*
* If this operation fails, then a SocketOpenError will be thrown.
* If this operation fails, then a socket_open_error will be thrown.
*/
void open_l2_socket();
void open_l2_socket(const NetworkInterface& iface = NetworkInterface());
#endif // WIN32
/**
* \brief Opens a layer 3 socket, using the corresponding protocol
* for the given flag.
*
* If this operation fails, then a SocketOpenError will be thrown.
* If the provided socket type is not valid, a InvalidSocketTypeError
* will be throw.
* If this operation fails, then a socket_open_error will be thrown.
* If the provided socket type is not valid, an invalid_socket_type
* exception will be throw.
*
* \param type The type of socket which will be used to pick the protocol flag
* for this socket.
@@ -106,14 +146,29 @@ namespace Tins {
* \brief Closes the socket associated with the given flag.
*
* If the provided type is invalid, meaning no such open socket
* exists, a InvalidSocketTypeError is thrown.
* exists, an invalid_socket_type exception is thrown.
*
* If any socket close errors are encountered, a SocketCloseError
* If any socket close errors are encountered, a socket_close_error
* is thrown.
*
* \param type The type of the socket to be closed.
*/
void close_socket(SocketType type);
void close_socket(SocketType type, const NetworkInterface &iface = NetworkInterface());
/**
* \brief Sets the default interface.
*
* The interface will be used whenever PacketSender::send(PDU&)
* is called.
*/
void default_interface(const NetworkInterface &iface);
/**
* \brief Gets the default interface.
*
* \sa PacketSender::default_interface
*/
const NetworkInterface& default_interface();
/**
* \brief Sends a PDU.
@@ -121,11 +176,33 @@ namespace Tins {
* This method opens the appropriate socket, if it's not open yet,
* and sends the PDU on the open socket.
*
* If any send error occurs, then a SocketWriteError is thrown.
* If any send error occurs, then a socket_write_error is thrown.
*
* If the PDU contains a link layer protocol, then default_interface
* is used.
*
* \sa PacketSender::default_interface
*
* \param pdu The PDU to be sent.
*/
void send(PDU &pdu);
/**
* \brief Sends a PDU.
*
* \sa PacketSender::send
*
* This overload takes a NetworkInterface. The packet is sent
* through that interface if a link-layer PDU is present,
* otherwise this call is equivalent to send(PDU&).
*
* The interface stored in the link layer PDU(if any), is restored
* after this method ends.
*
* \param pdu The PDU to be sent.
* \param iface The network interface to use.
*/
void send(PDU &pdu, const NetworkInterface &iface);
/**
* \brief Sends a PDU and waits for its response.
@@ -139,6 +216,20 @@ namespace Tins {
* \return Returns the response PDU, 0 if not response was received.
*/
PDU *send_recv(PDU &pdu);
/**
* \brief Sends a PDU and waits for its response.
*
* This method is used to send PDUs and receive their response.
* It opens the required socket(if it's not open yet). This can be used
* to expect responses for ICMP, ARP, and such packets that are normally
* answered by the host that receives the packet.
*
* \param pdu The PDU to send.
* \param iface The network interface in which to send and receive.
* \return Returns the response PDU, 0 if not response was received.
*/
PDU *send_recv(PDU &pdu, const NetworkInterface &iface);
#ifndef WIN32
/**
@@ -152,7 +243,8 @@ namespace Tins {
* \param len_addr The sockaddr struct length.
* \return Returns the response PDU. If no response is received, then 0 is returned.
*/
PDU *recv_l2(PDU &pdu, struct sockaddr *link_addr, uint32_t len_addr);
PDU *recv_l2(PDU &pdu, struct sockaddr *link_addr, uint32_t len_addr,
const NetworkInterface &iface = NetworkInterface());
/**
* \brief Sends a level 2 PDU.
@@ -161,13 +253,14 @@ namespace Tins {
* using the corresponding flag, according to the given type of
* protocol.
*
* If any socket write error occurs, a SocketWriteError is thrown.
* If any socket write error occurs, a socket_write_error is thrown.
*
* \param pdu The PDU to send.
* \param link_addr The sockaddr struct which will be used to send the PDU.
* \param len_addr The sockaddr struct length.
*/
void send_l2(PDU &pdu, struct sockaddr* link_addr, uint32_t len_addr);
void send_l2(PDU &pdu, struct sockaddr* link_addr, uint32_t len_addr,
const NetworkInterface &iface = NetworkInterface());
#endif // WIN32
/**
@@ -190,7 +283,7 @@ namespace Tins {
* This method sends a layer 3 PDU, using a raw socket, open using the corresponding flag,
* according to the given type of protocol.
*
* If any socket write error occurs, a SocketWriteError is thrown.
* If any socket write error occurs, a socket_write_error is thrown.
*
* \param pdu The PDU to send.
* \param link_addr The sockaddr struct which will be used to send the PDU.
@@ -203,41 +296,34 @@ namespace Tins {
typedef std::map<SocketType, int> SocketTypeMap;
PacketSender(const PacketSender&);
PacketSender& operator=(const PacketSender&);
int find_type(SocketType type);
int timeval_subtract (struct timeval *result, struct timeval *x, struct timeval *y);
#ifndef WIN32
bool ether_socket_initialized(const NetworkInterface& iface = NetworkInterface()) const;
int get_ether_socket(const NetworkInterface& iface = NetworkInterface());
#endif
template<typename T>
void send(PDU &pdu, const NetworkInterface &iface) {
static_cast<T&>(pdu).send(*this, iface);
}
PDU *recv_match_loop(int sock, PDU &pdu, struct sockaddr* link_addr, uint32_t addrlen);
std::vector<int> _sockets;
#ifndef WIN32
#if defined(BSD) || defined(__FreeBSD_kernel__)
typedef std::map<uint32_t, int> BSDEtherSockets;
BSDEtherSockets _ether_socket;
#else
int _ether_socket;
#endif
#endif
SocketTypeMap _types;
uint32_t _timeout, _timeout_usec;
NetworkInterface default_iface;
};
class SocketOpenError : public std::runtime_error {
public:
SocketOpenError(const std::string &msg)
: std::runtime_error(msg) { }
};
class SocketCloseError : public std::runtime_error {
public:
SocketCloseError(const std::string &msg)
: std::runtime_error(msg) { }
};
class SocketWriteError : public std::runtime_error {
public:
SocketWriteError(const std::string &msg)
: std::runtime_error(msg) { }
};
class InvalidSocketTypeError : public std::exception {
public:
const char *what() const throw() {
return "The provided socket type is invalid";
}
};
};
}
#endif // TINS_PACKET_SENDER_H

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, Nasel
* Copyright (c) 2012, Matias Fontanini
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -34,6 +34,7 @@
#include <iterator>
#include <pcap.h>
#include "utils.h"
#include "cxxstd.h"
namespace Tins {
class PDU;
@@ -53,7 +54,9 @@ public:
enum LinkType {
RADIOTAP = DLT_IEEE802_11_RADIO,
DOT11 = DLT_IEEE802_11,
ETH2 = DLT_EN10MB
ETH2 = DLT_EN10MB,
DOT3 = DLT_EN10MB,
SLL = DLT_LINUX_SLL
};
/**
@@ -64,6 +67,36 @@ public:
*/
PacketWriter(const std::string &file_name, LinkType lt);
#if TINS_IS_CXX11
/**
* \brief Move constructor.
*
* Note that calling PacketWriter::write on an previously moved
* object will lead to undefined behaviour.
*
* \param rhs The PacketWriter to be moved.
*/
PacketWriter(PacketWriter &&rhs) noexcept {
*this = std::move(rhs);
}
/**
* \brief Move assignment operator.
*
* Note that calling PacketWriter::write on an previously moved
* object will lead to undefined behaviour.
*
* \param rhs The PacketWriter to be moved.
*/
PacketWriter& operator=(PacketWriter &&rhs) noexcept {
handle = 0;
dumper = 0;
std::swap(handle, rhs.handle);
std::swap(dumper, rhs.dumper);
return *this;
}
#endif
/**
* Destructor.
*/
@@ -74,6 +107,18 @@ public:
*/
void write(PDU &pdu);
/**
* \brief Writes a PDU to this file.
*
* The template parameter T must at some point yield a PDU& after
* applying operator* one or more than one time. This accepts both
* raw and smartpointers.
*/
template<typename T>
void write(T &pdu) {
write(Utils::dereference_until_pdu(pdu));
}
/**
* \brief Writes all the PDUs in the range [start, end)
* \param start A forward iterator pointing to the first PDU

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, Nasel
* Copyright (c) 2012, Matias Fontanini
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -33,12 +33,21 @@
#include <stdint.h>
#include <vector>
#include "macros.h"
#include "cxxstd.h"
#include "exceptions.h"
/** \brief The Tins namespace.
*/
namespace Tins {
class PacketSender;
class NetworkInterface;
/**
* The type used to store several PDU option values.
*/
typedef std::vector<uint8_t> byte_array;
/** \brief Base class for protocol data units.
*
@@ -54,7 +63,7 @@ namespace Tins {
/**
* The type that will be returned when serializing PDUs.
*/
typedef std::vector<uint8_t> serialization_type;
typedef byte_array serialization_type;
/**
* \brief Enum which identifies each type of PDU.
@@ -101,18 +110,46 @@ namespace Tins {
RC4EAPOL,
RSNEAPOL,
DNS,
LOOPBACK
LOOPBACK,
IPv6,
ICMPv6,
SLL,
DHCPv6,
DOT1Q,
PPPOE,
STP
};
/** \brief PDU constructor
*
* Must be called by subclasses in their constructors.
* \param flag The flag identifier for the subclass' PDU.
* \param next_pdu The child PDU. Can be obviated.
/**
* \brief Default constructor.
*/
PDU(PDU *next_pdu = 0);
PDU();
#if TINS_IS_CXX11
/**
* \brief Move constructor.
*
* \param rhs The PDU to be moved.
*/
PDU(PDU &&rhs) noexcept
: _inner_pdu(0)
{
std::swap(_inner_pdu, rhs._inner_pdu);
}
/**
* \brief Move assignment operator.
*
* \param rhs The PDU to be moved.
*/
PDU& operator=(PDU &&rhs) noexcept {
std::swap(_inner_pdu, rhs._inner_pdu);
return *this;
}
#endif
/** \brief PDU destructor.
/**
* \brief PDU destructor.
*
* Deletes the inner pdu, as a consequence every child pdu is
* deleted.
@@ -159,11 +196,21 @@ namespace Tins {
/**
* \brief Sets the child PDU.
*
* \param next_pdu The new child PDU.
* When setting a new inner_pdu, the instance takesownership of
* the object, therefore deleting it when it's no longer required.
*
* \param next_pdu The new child PDU.
*/
void inner_pdu(PDU *next_pdu);
/**
* \brief Sets the child PDU.
*
* The PDU parameter is cloned using PDU::clone.
*
* \param next_pdu The new child PDU.
*/
void inner_pdu(const PDU &next_pdu);
/**
@@ -178,14 +225,14 @@ namespace Tins {
serialization_type serialize();
/**
* \brief Find and returns the first PDU that matches the given flag.
* \brief Finds and returns the first PDU that matches the given flag.
*
* This method searches for the first PDU which has the same type flag as
* the given one. If the first PDU matches that flag, it is returned.
* If no PDU matches, 0 is returned.
* \param flag The flag which being searched.
*/
template<class T>
template<typename T>
T *find_pdu(PDUType type = T::pdu_flag) {
PDU *pdu = this;
while(pdu) {
@@ -195,6 +242,43 @@ namespace Tins {
}
return 0;
}
/**
* \brief Finds and returns the first PDU that matches the given flag.
*
* \param flag The flag which being searched.
*/
template<typename T>
const T *find_pdu(PDUType type = T::pdu_flag) const {
return const_cast<PDU*>(this)->find_pdu<T>();
}
/**
* \brief Finds and returns the first PDU that matches the given flag.
*
* If the PDU is not found, a pdu_not_found exception is thrown.
*
* \sa PDU::find_pdu
*
* \param flag The flag which being searched.
*/
template<typename T>
T &rfind_pdu(PDUType type = T::pdu_flag) {
T *ptr = find_pdu<T>(type);
if(!ptr)
throw pdu_not_found();
return *ptr;
}
/**
* \brief Finds and returns the first PDU that matches the given flag.
*
* \param flag The flag which being searched.
*/
template<typename T>
const T &rfind_pdu(PDUType type = T::pdu_flag) const {
return const_cast<PDU*>(this)->rfind_pdu<T>();
}
/**
* \brief Clones this packet.
@@ -206,25 +290,37 @@ namespace Tins {
*/
virtual PDU *clone() const = 0;
/** \brief Send the stack of PDUs through a PacketSender.
/**
* \brief Send the stack of PDUs through a PacketSender.
*
* This method will be called only for the PDU on the bottom of the stack,
* therefore it should only implement this method if it can be sent.
*
* PacketSender implements specific methods to send packets which start
* on every valid TCP/IP stack layer; this should only be a proxy for
* those methods.
*
* If this PDU does not represent a link layer protocol, then
* the interface argument will be ignored.
*
* \param sender The PacketSender which will send the packet.
* \param iface The network interface in which this packet will
* be sent.
*/
virtual void send(PacketSender &sender);
virtual void send(PacketSender &sender, const NetworkInterface &iface);
/** \brief Receives a matching response for this packet.
/**
* \brief Receives a matching response for this packet.
*
* This method should act as a proxy for PacketSender::recv_lX methods.
*
* \param sender The packet sender which will receive the packet.
* \param iface The interface in which to expect the response.
*/
virtual PDU *recv_response(PacketSender &sender);
virtual PDU *recv_response(PacketSender &sender, const NetworkInterface &iface);
/** \brief Check wether ptr points to a valid response for this PDU.
/**
* \brief Check wether ptr points to a valid response for this PDU.
*
* This method must check wether the buffer pointed by ptr is a valid
* response for this PDU. If it is valid, then it might want to propagate
@@ -233,7 +329,9 @@ namespace Tins {
* \param ptr The pointer to the buffer.
* \param total_sz The size of the buffer.
*/
virtual bool matches_response(uint8_t *ptr, uint32_t total_sz) { return false; }
virtual bool matches_response(const uint8_t *ptr, uint32_t total_sz) const {
return false;
}
/**
* \brief Check wether this PDU matches the specified flag.
@@ -243,7 +341,7 @@ namespace Tins {
* classes' flag.
* \param flag The flag to match.
*/
virtual bool matches_flag(PDUType flag) {
virtual bool matches_flag(PDUType flag) const {
return flag == pdu_type();
}
@@ -253,15 +351,6 @@ namespace Tins {
* \return Returns the PDUType corresponding to the PDU.
*/
virtual PDUType pdu_type() const = 0;
/** \brief Clones this pdu, filling the corresponding header with data
* extracted from a buffer.
*
* \param ptr The pointer to the from from which the data will be extracted.
* \param total_sz The size of the buffer.
* \return The cloned PDU.
*/
virtual PDU *clone_packet(const uint8_t *ptr, uint32_t total_sz) { return 0; }
protected:
/**
* \brief Copy constructor.
@@ -279,6 +368,20 @@ namespace Tins {
*/
void copy_inner_pdu(const PDU &pdu);
/**
* \brief Prepares this PDU for serialization.
*
* This method is called before the inner PDUs are serialized.
* It's useful in situations such as when serializing IP PDUs,
* which don't contain any link layer encapsulation, and therefore
* require to set the source IP address before the TCP/UDP checksum
* is calculated.
*
* By default, this method does nothing
*
* \param parent The parent PDU.
*/
virtual void prepare_for_serialize(const PDU *parent) { }
/**
* \brief Serializes this PDU and propagates this action to child PDUs.
@@ -289,16 +392,6 @@ namespace Tins {
*/
void serialize(uint8_t *buffer, uint32_t total_sz, const PDU *parent);
/**
* \brief Clones the inner pdu(if any).
*
* This method clones the inner pdu using data from a buffer.
* \param ptr The pointer from which the child PDU must be cloned.
* \param total_sz The total size of the buffer.
* \return Returns the cloned PDU. Will be 0 if cloning failed.
*/
PDU *clone_inner_pdu(const uint8_t *ptr, uint32_t total_sz);
/**
* \brief Serializes this TCP PDU.
*
@@ -350,6 +443,17 @@ namespace Tins {
lop /= rop;
return lop;
}
};
/**
* \brief Concatenation operator on PDU pointers.
*
* \sa operator/=
*/
template<typename T>
T *operator/= (T* lop, const PDU &rop) {
*lop /= rop;
return lop;
}
}
#endif // TINS_PDU_H

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, Nasel
* Copyright (c) 2012, Matias Fontanini
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -32,6 +32,7 @@
#include <algorithm>
#include "pdu.h"
#include "macros.h"
namespace Tins {
/**
@@ -94,28 +95,28 @@ public:
/**
* Forwards the call to the cached PDU. \sa PDU::send.
*/
void send(PacketSender &sender) {
cached.send(sender);
void send(PacketSender &sender, const NetworkInterface &iface) {
cached.send(sender, iface);
}
/**
* Forwards the call to the cached PDU. \sa PDU::recv_responde.
*/
PDU *recv_response(PacketSender &sender) {
return cached.recv_response(sender);
PDU *recv_response(PacketSender &sender, const NetworkInterface &iface) {
return cached.recv_response(sender, iface);
}
/**
* Forwards the call to the cached PDU. \sa PDU::matches_response.
*/
bool matches_response(uint8_t *ptr, uint32_t total_sz) {
bool matches_response(const uint8_t *ptr, uint32_t total_sz) const {
return cached.matches_response(ptr, total_sz);
}
/**
* Forwards the call to the cached PDU. \sa PDU::matches_flag.
*/
bool matches_flag(PDUType flag) {
bool matches_flag(PDUType flag) const {
return cached.matches_flag(flag);
}
@@ -125,13 +126,6 @@ public:
PDUType pdu_type() const {
return cached.pdu_type();
}
/**
* Forwards the call to the cached PDU. \sa PDU::clone_packet.
*/
PDU *clone_packet(const uint8_t *ptr, uint32_t total_sz) {
return cached.clone_packet(ptr, total_sz);
}
private:
void write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *parent) {
if(cached_serialization.size() != total_sz) {

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, Nasel
* Copyright (c) 2012, Matias Fontanini
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -33,18 +33,9 @@
#include <vector>
#include <iterator>
#include <stdint.h>
#include "exceptions.h"
namespace Tins {
/**
* \brief Exception thrown when an option is not found.
*/
class option_not_found : public std::exception {
public:
const char* what() const throw() {
return "Option not found";
}
};
/**
* \class PDUOption
* \brief Represents a PDU option field.
@@ -75,10 +66,8 @@ public:
* \param data The option's data(if any).
*/
PDUOption(option_type opt = option_type(), size_t length = 0, const data_type *data = 0)
: option_(opt) {
value_.push_back(length);
if(data)
value_.insert(value_.end(), data, data + length);
: option_(opt), size_(length), value_(data, data + (data ? length : 0)) {
}
/**
@@ -91,9 +80,29 @@ public:
*/
template<typename ForwardIterator>
PDUOption(option_type opt, ForwardIterator start, ForwardIterator end)
: option_(opt) {
value_.push_back(std::distance(start, end));
value_.insert(value_.end(), start, end);
: option_(opt), size_(std::distance(start, end)), value_(start, end) {
}
/**
* \brief Constructs a PDUOption from iterators, which
* indicate the data to be stored in it.
*
* The length parameter indicates the contents of the length field
* when this option is serialized. Note that this can be different
* to std::distance(start, end).
*
* \sa length_field
*
* \param opt The option type.
* \param length The length of this option.
* \param start The beginning of the option data.
* \param end The end of the option data.
*/
template<typename ForwardIterator>
PDUOption(option_type opt, size_t length, ForwardIterator start, ForwardIterator end)
: option_(opt), size_(length), value_(start, end) {
}
/**
@@ -104,6 +113,14 @@ public:
return option_;
}
/**
* Sets this option's type
* \param opt The option type to be set.
*/
void option(option_type opt) {
option_ = opt;
}
/**
* Retrieves this option's data.
*
@@ -111,20 +128,39 @@ public:
* dereferencing the returned pointer will result in undefined
* behaviour.
*
* \return const value_type& containing this option's value.
* \return const data_type& containing this option's value.
*/
const data_type *data_ptr() const {
return &*(++value_.begin());
return &*value_.begin();
}
/**
* Retrieves the length of this option's data.
* \brief Retrieves the length of this option's data.
*
* This is the actual size of the data.
*/
size_t data_size() const {
return value_.empty() ? 0 : (value_.size() - 1);
return value_.size();
}
/**
* \brief Retrieves the data length field.
*
* This is what the size field will contain when this option is
* serialized. It can differ from the actual data size.
*
* This will be equal to data_size unless the constructor that takes
* both a data length and two iterators is used.
*
* \sa data_size.
*/
size_t length_field() const {
return size_;
}
private:
option_type option_;
uint16_t size_;
container_type value_;
};
} // namespace Tins

436
include/pppoe.h Normal file
View File

@@ -0,0 +1,436 @@
/*
* 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_PPPoE_H
#define TINS_PPPoE_H
#include <list>
#include <string>
#include <vector>
#include "pdu.h"
#include "endianness.h"
#include "small_uint.h"
#include "pdu_option.h"
#include "cxxstd.h"
namespace Tins {
class PPPoE : public PDU {
public:
/**
* The tag types enum.
*/
enum TagTypes {
END_OF_LIST = 0,
SERVICE_NAME = 0x101,
#if TINS_IS_LITTLE_ENDIAN
AC_NAME = 0x201,
HOST_UNIQ = 0x301,
AC_COOKIE = 0x401,
VENDOR_SPECIFIC = 0x501,
RELAY_SESSION_ID = 0x101,
SERVICE_NAME_ERROR = 0x201,
AC_SYSTEM_ERROR = 0x202,
GENERIC_ERROR = 0x302
#else
AC_NAME = 0x102,
HOST_UNIQ = 0x103,
AC_COOKIE = 0x104,
VENDOR_SPECIFIC = 0x105,
RELAY_SESSION_ID = 0x110,
SERVICE_NAME_ERROR = 0x201,
AC_SYSTEM_ERROR = 0x202,
GENERIC_ERROR = 0x203
#endif
};
/**
* The type used to store a TLV option.
*/
typedef PDUOption<TagTypes> tag;
/**
* The type used to store the options.
*/
typedef std::list<tag> tags_type;
/**
* The type used to store the Vendor-Specific tag's value.
*/
struct vendor_spec_type {
typedef std::vector<uint8_t> data_type;
uint32_t vendor_id;
data_type data;
vendor_spec_type(uint32_t vendor_id = 0, const data_type &data = data_type())
: vendor_id(vendor_id), data(data) { }
};
/**
* This PDU's flag.
*/
static const PDU::PDUType pdu_flag = PDU::PPPOE;
/**
* \brief Default constructor.
*
* This sets the version and type fields to 0x1.
*/
PPPoE();
/**
* \brief Constructor which creates an PPPoE object from a buffer.
*
* If there is not enough size for a PPPoE 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.
*/
PPPoE(const uint8_t *buffer, uint32_t total_sz);
// Getters
/**
* \brief Getter for the version field.
* \return The stored version field value.
*/
small_uint<4> version() const {
return _header.version;
}
/**
* \brief Getter for the type field.
* \return The stored type field value.
*/
small_uint<4> type() const {
return _header.type;
}
/**
* \brief Getter for the code field.
* \return The stored code field value.
*/
uint8_t code() const {
return _header.code;
}
/**
* \brief Getter for the session_id field.
* \return The stored session_id field value.
*/
uint16_t session_id() const {
return Endian::be_to_host(_header.session_id);
}
/**
* \brief Getter for the payload_length field.
* \return The stored payload_length field value.
*/
uint16_t payload_length() const {
return Endian::be_to_host(_header.payload_length);
}
/**
* \brief Returns the header size.
*
* This metod overrides PDU::header_size. \sa PDU::header_size
*/
uint32_t header_size() const;
/**
* \brief Returns the list of tags.
*/
const tags_type &tags() const {
return _tags;
}
/**
* \sa PDU::clone
*/
PPPoE *clone() const {
return new PPPoE(*this);
}
const tag *search_tag(TagTypes identifier) const;
/**
* \brief Getter for the PDU's type.
* \sa PDU::pdu_type
*/
PDUType pdu_type() const { return pdu_flag; }
// Setters
/**
* \brief Setter for the version field.
* \param new_version The new version field value.
*/
void version(small_uint<4> new_version);
/**
* \brief Setter for the type field.
* \param new_type The new type field value.
*/
void type(small_uint<4> new_type);
/**
* \brief Setter for the code field.
* \param new_code The new code field value.
*/
void code(uint8_t new_code);
/**
* \brief Setter for the session_id field.
* \param new_session_id The new session_id field value.
*/
void session_id(uint16_t new_session_id);
/**
* \brief Setter for the payload_length field.
* \param new_payload_length The new payload_length field value.
*/
void payload_length(uint16_t new_payload_length);
/**
* \brief Adds a PPPoE tag.
*
* \param option The option to be added.
*/
void add_tag(const tag &option);
#if TINS_IS_CXX11
/**
* \brief Adds a PPPoE tag.
*
* This move-constructs the option.
*
* \param option The option to be added.
*/
void add_tag(tag &&option) {
_tags_size += option.data_size() + sizeof(uint16_t) * 2;
_tags.push_back(std::move(option));
}
#endif
// Option setters
/**
* \brief Adds an end-of-list tag.
*/
void end_of_list();
/**
* \brief Adds a service-name tag.
*
* \param value The service name.
*/
void service_name(const std::string &value);
/**
* \brief Adds a AC-name tag.
*
* \param value The AC name.
*/
void ac_name(const std::string &value);
/**
* \brief Adds a host-uniq tag.
*
* \param value The tag's value.
*/
void host_uniq(const byte_array &value);
/**
* \brief Adds a AC-Cookie tag.
*
* \param value The tag's value.
*/
void ac_cookie(const byte_array &value);
/**
* \brief Adds a Vendor-Specific tag.
*
* \param value The tag's value.
*/
void vendor_specific(const vendor_spec_type &value);
/**
* \brief Adds a Relay-Session-Id tag.
*
* \param value The tag's value.
*/
void relay_session_id(const byte_array &value);
/**
* \brief Adds a Service-Name-Error tag.
*
* \param value The tag's value.
*/
void service_name_error(const std::string &value);
/**
* \brief Adds a AC-System-Error tag.
*
* \param value The tag's value.
*/
void ac_system_error(const std::string &value);
/**
* \brief Adds a Generic-Error tag.
*
* \param value The tag's value.
*/
void generic_error(const std::string &value);
// Option getters
/**
* \brief Getter for the service-name tag.
*
* This method will throw an option_not_found exception if the
* option is not found.
*/
std::string service_name() const;
/**
* \brief Getter for the AC-name tag.
*
* This method will throw an option_not_found exception if the
* option is not found.
*/
std::string ac_name() const;
/**
* \brief Getter for the host-uniq tag.
*
* This method will throw an option_not_found exception if the
* option is not found.
*/
byte_array host_uniq() const;
/**
* \brief Getter for the AC-Cookie tag.
*
* This method will throw an option_not_found exception if the
* option is not found.
*/
byte_array ac_cookie() const;
/**
* \brief Getter for the Vendor-Specific tag.
*
* This method will throw an option_not_found exception if the
* option is not found.
*/
vendor_spec_type vendor_specific() const;
/**
* \brief Getter for the Vendor-Specific tag.
*
* This method will throw an option_not_found exception if the
* option is not found.
*/
byte_array relay_session_id() const;
/**
* \brief Getter for the Service-Name-Error tag.
*
* This method will throw an option_not_found exception if the
* option is not found.
*/
std::string service_name_error() const;
/**
* \brief Getter for the AC-System-Error tag.
*
* This method will throw an option_not_found exception if the
* option is not found.
*/
std::string ac_system_error() const;
/**
* \brief Getter for the Generic-Error tag.
*
* This method will throw an option_not_found exception if the
* option is not found.
*/
std::string generic_error() const;
private:
void write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *);
template<typename T>
void add_tag_iterable(TagTypes id, const T &data) {
add_tag(
tag(
id,
data.begin(),
data.end()
)
);
}
template<typename T>
T retrieve_tag_iterable(TagTypes id) const {
const tag *tag = search_tag(id);
if(!tag)
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;
}
TINS_BEGIN_PACK
struct pppoe_hdr {
#if TINS_IS_LITTLE_ENDIAN
uint8_t version:4,
type:4;
uint8_t code;
#else
uint16_t version:4,
type:4,
code:8;
#endif
uint16_t session_id;
uint16_t payload_length;
} TINS_END_PACK;
pppoe_hdr _header;
tags_type _tags;
uint16_t _tags_size;
};
}
#endif // TINS_PPPoE_H

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, Nasel
* Copyright (c) 2012, Matias Fontanini
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -30,9 +30,9 @@
#ifndef TINS_RADIOTAP_H
#define TINS_RADIOTAP_H
#include "macros.h"
#include "pdu.h"
#include "endianness.h"
#include "network_interface.h"
namespace Tins {
class PacketSender;
@@ -107,16 +107,17 @@ namespace Tins {
};
/**
* \brief Creates an instance of RadioTap.
* \param iface The interface in which to send this PDU.
* \param child The child PDU.(optional)
* \brief Default constructor.
*/
RadioTap(const NetworkInterface &iface = NetworkInterface(),
PDU *child = 0);
RadioTap();
/**
* \brief Constructor which creates a RadioTap object from a buffer and adds all
* \brief Constructs a RadioTap 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 a RadioTap 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.
*/
@@ -124,10 +125,12 @@ namespace Tins {
/* Setters */
#ifndef WIN32
/**
* \sa PDU::send()
*/
void send(PacketSender &sender);
void send(PacketSender &sender, const NetworkInterface &iface);
#endif
/**
* \brief Setter for the version field.
@@ -289,6 +292,14 @@ namespace Tins {
return (PresentFlags)*(uint32_t*)(&_radio.it_len + 1);
}
/** \brief Check wether ptr points to a valid response for this PDU.
*
* \sa PDU::matches_response
* \param ptr The pointer to the buffer.
* \param total_sz The size of the buffer.
*/
bool matches_response(const uint8_t *ptr, uint32_t total_sz) const;
/**
* \brief Returns the RadioTap frame's header length.
*
@@ -316,6 +327,7 @@ namespace Tins {
*/
PDUType pdu_type() const { return PDU::RADIOTAP; }
private:
TINS_BEGIN_PACK
struct radiotap_hdr {
#if TINS_IS_LITTLE_ENDIAN
uint8_t it_version;
@@ -353,33 +365,32 @@ namespace Tins {
flags:1,
tsft:1,
reserved3:1,
tx_attenuation:1,
rx_flags:1,
db_tx_attenuation:1,
dbm_tx_attenuation:1,
antenna:1,
db_signal:1,
db_noise:1,
rx_flags:1,
tx_attenuation:1,
reserved2:5,
channel_plus:1,
reserved1:2,
reserved4:7,
ext:1;
#endif
} __attribute__((__packed__));
} TINS_END_PACK;
void init();
void write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *parent);
radiotap_hdr _radio;
NetworkInterface _iface;
// present fields...
uint64_t _tsft;
uint32_t _channel_type;
uint16_t _channel_freq, _rx_flags;
uint8_t _antenna, _flags, _rate, _dbm_signal, _dbm_noise, _channel, _max_power;
};
};
}
#endif // TINS_RADIOTAP_H

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, Nasel
* Copyright (c) 2012, Matias Fontanini
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -116,12 +116,33 @@ namespace Tins {
return _payload.size();
}
/**
* \brief Check wether ptr points to a valid response for this PDU.
*
* This always returns true, since we don't know what this
* RawPDU is holding.
*
* \sa PDU::matches_response
* \param ptr The pointer to the buffer.
* \param total_sz The size of the buffer.
*/
bool matches_response(const uint8_t *ptr, uint32_t total_sz) const;
/**
* \brief Getter for the PDU's type.
* \sa PDU::pdu_type
*/
PDUType pdu_type() const { return PDU::RAW; }
/**
* \brief Constructs the given PDU type from the raw data stored
* in this RawPDU.
*/
template<typename T>
T to() const {
return T(&_payload[0], _payload.size());
}
/**
* \sa PDU::clone
*/
@@ -133,7 +154,7 @@ namespace Tins {
payload_type _payload;
};
};
}
#endif // TINS_RAWPDU_H

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, Nasel
* Copyright (c) 2012, Matias Fontanini
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -89,7 +89,10 @@ namespace Tins{
RSNInformation(const serialization_type &buffer);
/**
* \brief Constructor from 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.

177
include/sll.h Normal file
View File

@@ -0,0 +1,177 @@
/*
* 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_SLL_H
#define TINS_SLL_H
#include <vector>
#include "pdu.h"
#include "endianness.h"
#include "hw_address.h"
namespace Tins {
class SLL : public PDU {
public:
/**
* This PDU's flag.
*/
static const PDU::PDUType pdu_flag = PDU::SLL;
/**
* The type of the address type
*/
typedef HWAddress<8> address_type;
/**
* Default constructor
*/
SLL();
/**
* \brief Constructs a SLL object from a buffer and adds all
* identifiable PDUs found in the buffer as children of this one.
*
* If the next PDU is not recognized, then a RawPDU is used.
*
* If there is not enough size for a SLL header in the
* buffer, 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.
*/
SLL(const uint8_t *buffer, uint32_t total_sz);
// Getters
/**
* \brief Getter for the packet_type field.
* \return The stored packet_type field value.
*/
uint16_t packet_type() const {
return Endian::be_to_host(_header.packet_type);
}
/**
* \brief Getter for the lladdr_type field.
* \return The stored lladdr_type field value.
*/
uint16_t lladdr_type() const {
return Endian::be_to_host(_header.lladdr_type);
}
/**
* \brief Getter for the lladdr_len field.
* \return The stored lladdr_len field value.
*/
uint16_t lladdr_len() const {
return Endian::be_to_host(_header.lladdr_len);
}
/**
* \brief Getter for the address field.
* \return The stored address field value.
*/
address_type address() const {
return _header.address;
}
/**
* \brief Getter for the protocol field.
* \return The stored protocol field value.
*/
uint16_t protocol() const {
return Endian::be_to_host(_header.protocol);
}
/**
* \brief Getter for the PDU's type.
* \sa PDU::pdu_type
*/
PDUType pdu_type() const { return pdu_flag; }
// Setters
/**
* \brief Setter for the packet_type field.
* \param new_packet_type The new packet_type field value.
*/
void packet_type(uint16_t new_packet_type);
/**
* \brief Setter for the lladdr_type field.
* \param new_lladdr_type The new lladdr_type field value.
*/
void lladdr_type(uint16_t new_lladdr_type);
/**
* \brief Setter for the lladdr_len field.
* \param new_lladdr_len The new lladdr_len field value.
*/
void lladdr_len(uint16_t new_lladdr_len);
/**
* \brief Setter for the address field.
* \param new_address The new address field value.
*/
void address(const address_type &new_address);
/**
* \brief Setter for the protocol field.
* \param new_protocol The new protocol field value.
*/
void protocol(uint16_t new_protocol);
/**
* \brief Returns the header size.
*
* This metod overrides PDU::header_size. \sa PDU::header_size
*/
uint32_t header_size() const;
/**
* \sa PDU::clone
*/
SLL *clone() const {
return new SLL(*this);
}
private:
TINS_BEGIN_PACK
struct sllhdr {
uint16_t packet_type, lladdr_type, lladdr_len;
uint8_t address[8];
uint16_t protocol;
} TINS_END_PACK;
void write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *);
sllhdr _header;
};
}
#endif // TINS_SLL_H

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, Nasel
* Copyright (c) 2012, Matias Fontanini
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, Nasel
* Copyright (c) 2012, Matias Fontanini
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -33,6 +33,7 @@
#include <stdint.h>
#include "pdu.h"
#include "macros.h"
#include "endianness.h"
#include "small_uint.h"
@@ -55,13 +56,18 @@ namespace Tins {
* \brief Creates an instance of SNAP
* This constructor sets the dsap and ssap fields to 0xaa, and
* the id field to 3.
* \param child The child PDU.(optional)
*/
SNAP(PDU *child = 0);
SNAP();
/**
* \brief Constructor which creates a SNAP object from a buffer and adds all identifiable
* PDUs found in the buffer as children of this one.
* \brief Constructs a SNAP object from a buffer and adds all
* identifiable PDUs found in the buffer as children of this one.
*
* If the next PDU is not recognized, then a RawPDU is used.
*
* If there is not enough size for a SNAP header in the
* buffer, 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.
*/
@@ -154,25 +160,18 @@ namespace Tins {
return new SNAP(*this);
}
private:
TINS_BEGIN_PACK
struct snaphdr {
uint8_t dsap;
uint8_t ssap;
/*#if TINS_IS_LITTLE_ENDIAN
uint32_t control:8,
org_code:24;
#elif TINS_IS_BIG_ENDIAN
uint32_t org_code:24,
control:8;
#endif*/
uint32_t control_org;
uint16_t eth_type;
} __attribute__((__packed__));
} TINS_END_PACK;
void write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *parent);
snaphdr _snap;
};
};
}
#endif // TINS_SNAP_H

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, Nasel
* Copyright (c) 2012, Matias Fontanini
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -39,8 +39,13 @@
#include "pdu.h"
#include "ethernetII.h"
#include "radiotap.h"
#include "packet.h"
#include "loopback.h"
#include "dot11.h"
#include "dot3.h"
#include "sll.h"
#include "cxxstd.h"
#include "exceptions.h"
namespace Tins {
/**
@@ -55,6 +60,32 @@ namespace Tins {
*/
class BaseSniffer {
public:
#if TINS_IS_CXX11
/**
* \brief Move constructor.
* This constructor is available only in C++11.
*/
BaseSniffer(BaseSniffer &&rhs) noexcept
{
*this = std::move(rhs);
}
/**
* \brief Move assignment operator.
* This opeartor is available only in C++11.
*/
BaseSniffer& operator=(BaseSniffer &&rhs) noexcept
{
handle = 0;
mask = rhs.mask;
iface_type = rhs.iface_type;
actual_filter.bf_insns = 0;
std::swap(handle, rhs.handle);
std::swap(actual_filter, rhs.actual_filter);
return *this;
}
#endif
/**
* \brief Sniffer destructor.
* This frees all memory used by the pcap handle.
@@ -67,29 +98,64 @@ namespace Tins {
* This method returns the first sniffed packet that matches the
* sniffer's filter, or the first sniffed packet if no filter has
* been set.
* \return The captured packet, matching the given filter, 0 if an
* error occured(probably compiling the filter).
*
* The return type is a thin wrapper over a PDU* and a Timestamp
* object. This wrapper can be both implicitly converted to a
* PDU* and a Packet object. So doing this:
*
* \code
* Sniffer s(...);
* std::unique_ptr<PDU> pdu(s.next_packet());
* // Packet takes care of the PDU*.
* Packet packet(s.next_packet());
* \endcode
*
* Is fine, but this:
*
* \code
* // bad!!
* PtrPacket p = s.next_packet();
*
* \endcode
*
* Is not, since PtrPacket can't be copy constructed.
*
* \sa Packet::release_pdu
*
* \return The captured packet, matching the given filter.
* If an error occured(probably compiling the filter), PtrPacket::pdu
* will return 0. Caller takes ownership of the PDU * stored in
* the PtrPacket.
*/
PDU *next_packet();
PtrPacket next_packet();
/**
* \brief Starts a sniffing loop, using a callback object for every
* sniffed packet.
*
* The callback object must implement an operator with the
* following(or compatible) signature:
* The callback object must implement an operator with some of
* the following(or compatible) signatures:
*
* \code
* bool operator()(PDU&);
* bool operator()(RefPacket&);
* \endcode
*
* This operator will be called using the sniffed packets
* as arguments. You can modify the PDU argument as you wish.
* as arguments. You can modify the parameter argument as you wish.
* Calling PDU methods like PDU::release_inner_pdu is perfectly
* valid.
*
* The callback taking a RefPacket will contain a timestamp
* indicating the moment in which the packet was taken out of
* the wire/pcap file.
*
* Note that the Functor object will be copied using its copy
* constructor, so that object should be some kind of proxy to
* another object which will process the packets(e.g. std::bind).
*
* \sa RefPacket
*
* \param cback_handler The callback handler object which should process packets.
* \param max_packets The maximum amount of packets to sniff. 0 == infinite.
*/
@@ -107,6 +173,11 @@ namespace Tins {
* \brief Stops sniffing loops.
*/
void stop_sniff();
/**
* \brief Gets the file descriptor associated with the sniffer.
*/
int get_fd();
protected:
/**
* Default constructor.
@@ -132,14 +203,31 @@ namespace Tins {
LoopData(pcap_t *_handle, const Functor _handler,
int if_type)
: handle(_handle), c_handler(_handler), iface_type(if_type) { }
: handle(_handle), c_handler(_handler), iface_type(if_type)
{ }
};
struct PCapLoopBreaker {
bool &went_well;
pcap_t *handle;
PCapLoopBreaker(bool &went_well, pcap_t *handle)
: went_well(went_well), handle(handle) { }
~PCapLoopBreaker() {
if(!went_well)
pcap_breakloop(handle);
}
};
BaseSniffer(const BaseSniffer&);
BaseSniffer &operator=(const BaseSniffer&);
static bool is_dot3(const uint8_t *ptr, size_t sz) {
return (sz >= 13 && ptr[12] < 8);
}
template<class ConcretePDU, class Functor>
static bool call_functor(LoopData<Functor> *data, const u_char *packet, size_t len);
static bool call_functor(LoopData<Functor> *data, const u_char *packet, const struct pcap_pkthdr *header);
bool compile_set_filter(const std::string &filter, bpf_program &prog);
@@ -199,34 +287,48 @@ namespace Tins {
}
template<class ConcretePDU, class Functor>
bool Tins::BaseSniffer::call_functor(LoopData<Functor> *data, const u_char *packet, size_t len) {
ConcretePDU some_pdu((const uint8_t*)packet, len);
return data->c_handler(some_pdu);
bool Tins::BaseSniffer::call_functor(LoopData<Functor> *data, const u_char *packet,
const struct pcap_pkthdr *header)
{
ConcretePDU some_pdu((const uint8_t*)packet, header->caplen);
Timestamp ts(header->ts);
RefPacket pck(some_pdu, ts);
return data->c_handler(pck);
}
template<class Functor>
void Tins::BaseSniffer::callback_handler(u_char *args, const struct pcap_pkthdr *header, const u_char *packet) {
bool ret_val(true);
LoopData<Functor> *data = reinterpret_cast<LoopData<Functor>*>(args);
PCapLoopBreaker _(ret_val, data->handle);
try {
std::auto_ptr<PDU> pdu;
LoopData<Functor> *data = reinterpret_cast<LoopData<Functor>*>(args);
bool ret_val(false);
if(data->iface_type == DLT_EN10MB)
ret_val = call_functor<Tins::EthernetII>(data, packet, header->caplen);
Internals::smart_ptr<PDU>::type pdu;
if(data->iface_type == DLT_EN10MB) {
ret_val = is_dot3((const uint8_t*)packet, header->caplen) ?
call_functor<Tins::Dot3>(data, packet, header) :
call_functor<Tins::EthernetII>(data, packet, header);
}
else if(data->iface_type == DLT_IEEE802_11_RADIO)
ret_val = call_functor<Tins::RadioTap>(data, packet, header->caplen);
ret_val = call_functor<Tins::RadioTap>(data, packet, header);
else if(data->iface_type == DLT_IEEE802_11) {
std::auto_ptr<PDU> pdu(Tins::Dot11::from_bytes((const uint8_t*)packet, header->caplen));
if(pdu.get())
ret_val = data->c_handler(*pdu);
Internals::smart_ptr<PDU>::type pdu(
Tins::Dot11::from_bytes((const uint8_t*)packet, header->caplen)
);
if(pdu.get()) {
RefPacket pck(*pdu, header->ts);
ret_val = data->c_handler(pck);
}
}
else if(data->iface_type == DLT_NULL)
ret_val = call_functor<Tins::Loopback>(data, packet, header->caplen);
if(!ret_val)
pcap_breakloop(data->handle);
ret_val = call_functor<Tins::Loopback>(data, packet, header);
else if(data->iface_type == DLT_LINUX_SLL)
ret_val = call_functor<Tins::SLL>(data, packet, header);
}
catch(...) {
catch(malformed_packet&) {
ret_val = true;
}
catch(pdu_not_found&) {
ret_val = true;
}
}
@@ -252,6 +354,6 @@ namespace Tins {
{
return HandlerProxy<T>(ptr, function);
}
};
}
#endif // TINS_SNIFFER_H

307
include/stp.h Normal file
View File

@@ -0,0 +1,307 @@
/*
* 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_STP_H
#define TINS_STP_H
#include "pdu.h"
#include "endianness.h"
#include "hw_address.h"
#include "small_uint.h"
namespace Tins {
class STP : public PDU {
public:
/**
* This PDU's flag.
*/
static const PDU::PDUType pdu_flag = PDU::STP;
/**
* The type used to store BPDU identifier addresses.
*/
typedef HWAddress<6> address_type;
/**
* The type used to store the BPDU identifiers.
*/
struct bpdu_id_type {
small_uint<4> priority;
small_uint<12> ext_id;
address_type id;
bpdu_id_type(small_uint<4> priority=0, small_uint<12> ext_id=0,
const address_type& id=address_type())
: priority(priority), ext_id(ext_id), id(id) { }
};
/**
* \brief Default constructor.
*/
STP();
/**
* \brief Constructs a STP object from a buffer.
*
* If there is not enough size for a STP 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.
*/
STP(const uint8_t *buffer, uint32_t total_sz);
// Getters
/**
* \brief Getter for the proto_id field.
* \return The stored proto_id field value.
*/
uint16_t proto_id() const {
return Endian::be_to_host(_header.proto_id);
}
/**
* \brief Getter for the proto_version field.
* \return The stored proto_version field value.
*/
uint8_t proto_version() const {
return _header.proto_version;
}
/**
* \brief Getter for the bpdu_type field.
* \return The stored bpdu_type field value.
*/
uint8_t bpdu_type() const {
return _header.bpdu_type;
}
/**
* \brief Getter for the bpdu_flags field.
* \return The stored bpdu_flags field value.
*/
uint8_t bpdu_flags() const {
return _header.bpdu_flags;
}
/**
* \brief Getter for the root_path_cost field.
* \return The stored root_path_cost field value.
*/
uint32_t root_path_cost() const {
return Endian::be_to_host(_header.root_path_cost);
}
/**
* \brief Getter for the port_id field.
* \return The stored port_id field value.
*/
uint16_t port_id() const {
return Endian::be_to_host(_header.port_id);
}
/**
* \brief Getter for the msg_age field.
* \return The stored msg_age field value.
*/
uint16_t msg_age() const {
return Endian::be_to_host(_header.msg_age) / 256;
}
/**
* \brief Getter for the max_age field.
* \return The stored max_age field value.
*/
uint16_t max_age() const {
return Endian::be_to_host(_header.max_age) / 256;
}
/**
* \brief Getter for the hello_time field.
* \return The stored hello_time field value.
*/
uint16_t hello_time() const {
return Endian::be_to_host(_header.hello_time) / 256;
}
/**
* \brief Getter for the fwd_delay field.
* \return The stored fwd_delay field value.
*/
uint16_t fwd_delay() const {
return Endian::be_to_host(_header.fwd_delay) / 256;
}
/**
* \brief Getter for the root id field.
* \return The stored root id field value.
*/
bpdu_id_type root_id() const;
/**
* \brief Getter for the bridge id field.
* \return The stored bridge id field value.
*/
bpdu_id_type bridge_id() const;
/**
* \brief Getter for the PDU's type.
* \sa PDU::pdu_type
*/
PDUType pdu_type() const { return pdu_flag; }
/**
* \sa PDU::clone
*/
STP *clone() const {
return new STP(*this);
}
/**
* \brief Returns the header size.
*
* This metod overrides PDU::header_size. \sa PDU::header_size
*/
uint32_t header_size() const;
// Setters
/**
* \brief Setter for the proto_id field.
* \param new_proto_id The new proto_id field value.
*/
void proto_id(uint16_t new_proto_id);
/**
* \brief Setter for the proto_version field.
* \param new_proto_version The new proto_version field value.
*/
void proto_version(uint8_t new_proto_version);
/**
* \brief Setter for the bpdu_type field.
* \param new_bpdu_type The new bpdu_type field value.
*/
void bpdu_type(uint8_t new_bpdu_type);
/**
* \brief Setter for the bpdu_flags field.
* \param new_bpdu_flags The new bpdu_flags field value.
*/
void bpdu_flags(uint8_t new_bpdu_flags);
/**
* \brief Setter for the root_path_cost field.
* \param new_root_path_cost The new root_path_cost field value.
*/
void root_path_cost(uint32_t new_root_path_cost);
/**
* \brief Setter for the port_id field.
* \param new_port_id The new port_id field value.
*/
void port_id(uint16_t new_port_id);
/**
* \brief Setter for the msg_age field.
* \param new_msg_age The new msg_age field value.
*/
void msg_age(uint16_t new_msg_age);
/**
* \brief Setter for the max_age field.
* \param new_max_age The new max_age field value.
*/
void max_age(uint16_t new_max_age);
/**
* \brief Setter for the hello_time field.
* \param new_hello_time The new hello_time field value.
*/
void hello_time(uint16_t new_hello_time);
/**
* \brief Setter for the fwd_delay field.
* \param new_fwd_delay The new fwd_delay field value.
*/
void fwd_delay(uint16_t new_fwd_delay);
/**
* \brief Setter for the root id field.
* \param new_fwd_delay The new root id field value.
*/
void root_id(const bpdu_id_type &id);
/**
* \brief Setter for the bridge id field.
* \param new_fwd_delay The new bridge id field value.
*/
void bridge_id(const bpdu_id_type &id);
private:
TINS_BEGIN_PACK
struct pvt_bpdu_id {
#if TINS_IS_LITTLE_ENDIAN
// fixme
uint16_t ext_id:4,
priority:4,
ext_idL:8;
#else
uint16_t priority:4,
ext_id:12;
#endif
uint8_t id[6];
} TINS_END_PACK;
TINS_BEGIN_PACK
struct stphdr {
uint16_t proto_id;
uint8_t proto_version;
uint8_t bpdu_type;
uint8_t bpdu_flags;
pvt_bpdu_id root_id;
uint32_t root_path_cost;
pvt_bpdu_id bridge_id;
uint16_t port_id;
uint16_t msg_age;
uint16_t max_age;
uint16_t hello_time;
uint16_t fwd_delay;
} TINS_END_PACK;
static bpdu_id_type convert(const pvt_bpdu_id &id);
static pvt_bpdu_id convert(const bpdu_id_type &id);
void write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *parent);
stphdr _header;
};
}
#endif // TINS_STP_H

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, Nasel
* Copyright (c) 2012, Matias Fontanini
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -37,9 +37,11 @@
#include <stdexcept>
#include <utility>
#include "pdu.h"
#include "macros.h"
#include "endianness.h"
#include "small_uint.h"
#include "pdu_option.h"
#include "cxxstd.h"
namespace Tins {
/**
@@ -77,8 +79,7 @@ namespace Tins {
*
* This enum identifies valid options supported by TCP PDU.
*/
enum Option {
enum OptionTypes {
EOL = 0,
NOP = 1,
MSS = 2,
@@ -98,12 +99,15 @@ namespace Tins {
CHK_16FLETCHER
};
typedef PDUOption<uint8_t> tcp_option;
/**
* The type used to store TCP options.
*/
typedef PDUOption<uint8_t> option;
/**
* The type used to store the options.
*/
typedef std::list<tcp_option> options_type;
typedef std::list<option> options_type;
/**
* The type used to store the sack option.
@@ -121,9 +125,14 @@ namespace Tins {
TCP(uint16_t dport = 0, uint16_t sport = 0);
/**
* \brief Constructor which creates an TCP object from a buffer
* and adds all identifiable PDUs found in the buffer as children
* of this one.
* \brief Constructs TCP object from a buffer.
*
* If there is not enough size for a TCP header, or any of the
* TLV options are malformed a malformed_packet exception is
* thrown.
*
* Any extra data will be stored in a RawPDU.
*
* \param buffer The buffer from which this PDU will be constructed.
* \param total_sz The total size of the buffer.
*/
@@ -169,7 +178,7 @@ namespace Tins {
*
* \return The checksum field in an uint16_t.
*/
uint16_t check() const { return Endian::be_to_host(_tcp.check); }
uint16_t checksum() const { return Endian::be_to_host(_tcp.check); }
/**
* \brief Getter for the urgent pointer field.
@@ -237,13 +246,6 @@ namespace Tins {
*/
void window(uint16_t new_window);
/**
* \brief Setter for the checksum field.
*
* \param new_check The new checksum.
*/
void check(uint16_t new_check);
/**
* \brief Setter for the urgent pointer field.
*
@@ -350,15 +352,27 @@ namespace Tins {
* \param value The new value for this flag. Must be 0 or 1.
*/
void set_flag(Flags tcp_flag, small_uint<1> value);
/**
* \brief Adds a TCP option.
*
* \param option The option type flag to be set.
* \param length The length of this option(optional).
* \param data Pointer to this option's data(optional).
* \param option The option to be added.
*/
void add_option(Option option, uint8_t length = 0, const uint8_t *data = 0);
void add_option(const option &opt);
#if TINS_IS_CXX11
/**
* \brief Adds a TCP option.
*
* This move-constructs the option.
*
* \param option The option to be added.
*/
void add_option(option &&opt) {
internal_add_option(opt);
_options.push_back(std::move(opt));
}
#endif
/**
* \brief Returns the header size.
@@ -369,6 +383,15 @@ namespace Tins {
* \sa PDU::header_size
*/
uint32_t header_size() const;
/**
* \brief Check wether ptr points to a valid response for this PDU.
*
* \sa PDU::matches_response
* \param ptr The pointer to the buffer.
* \param total_sz The size of the buffer.
*/
bool matches_response(const uint8_t *ptr, uint32_t total_sz) const;
/**
* \brief Getter for the PDU's type.
@@ -382,7 +405,7 @@ namespace Tins {
* \param opt_flag The flag to be searched.
* \return A pointer to the option, or 0 if it was not found.
*/
const tcp_option *search_option(Option opt) const;
const option *search_option(OptionTypes opt) const;
/**
* \sa PDU::clone
@@ -391,6 +414,7 @@ namespace Tins {
return new TCP(*this);
}
private:
TINS_BEGIN_PACK
struct tcphdr {
uint16_t sport;
uint16_t dport;
@@ -424,26 +448,28 @@ namespace Tins {
uint16_t window;
uint16_t check;
uint16_t urg_ptr;
} __attribute__((packed));
} TINS_END_PACK;
static const uint16_t DEFAULT_WINDOW;
template<class T>
T generic_search(Option opt) const {
const tcp_option *option = search_option(opt);
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();
}
void write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *parent);
uint8_t *write_option(const tcp_option &opt, uint8_t *buffer);
void internal_add_option(const option &option);
void write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *parent);
void checksum(uint16_t new_check);
uint8_t *write_option(const option &opt, uint8_t *buffer);
tcphdr _tcp;
uint16_t _options_size, _total_options_size;
options_type _options;
uint32_t _options_size, _total_options_size;
};
};
}
#endif // TINS_TCP_H

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, Nasel
* Copyright (c) 2012, Matias Fontanini
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without

111
include/timestamp.h Normal file
View File

@@ -0,0 +1,111 @@
/*
* 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_TIMESTAMP_H
#define TINS_TIMESTAMP_H
#ifdef WIN32
#define NOMINMAX
#include <winsock2.h>
#else
#include <sys/time.h>
#endif
#include "cxxstd.h"
#if TINS_IS_CXX11
#include <chrono>
#endif
namespace Tins {
/**
* \brief Represents a packet timestamp.
*/
class Timestamp {
public:
#ifdef WIN32
typedef long seconds_type;
typedef long microseconds_type;
#else
typedef time_t seconds_type;
typedef suseconds_t microseconds_type;
#endif
/**
* \brief Constructs a Timestamp which will hold the current time.
*/
static Timestamp current_time() {
#ifdef WIN32
//fixme
return Timestamp();
#else
timeval tv;
gettimeofday(&tv, 0);
return tv;
#endif
}
/**
* Default constructs the timestamp.
*/
Timestamp() : tv() {}
/**
* Constructs a timestamp from a timeval object.
* \param time_val The timeval object.
*/
Timestamp(const timeval &time_val) : tv(time_val) {}
/**
* Returns the amount of seconds in this timestamp.
*/
seconds_type seconds() const {
return tv.tv_sec;
}
/**
* Returns the amount of microseconds in this timestamp.
*/
microseconds_type microseconds() const {
return tv.tv_usec;
}
#if TINS_IS_CXX11
/**
* Converts this Timestamp to a std::chrono::microseconds
*/
operator std::chrono::microseconds() const {
return std::chrono::seconds(seconds()) +
std::chrono::microseconds(microseconds());
}
#endif
private:
timeval tv;
};
}
#endif // TINS_TIMESTAMP_H

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, Nasel
* Copyright (c) 2012, Matias Fontanini
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -30,6 +30,7 @@
#ifndef TINS_TINS_H
#define TINS_TINS_H
#include "dns.h"
#include "arp.h"
#include "bootp.h"
#include "dhcp.h"
@@ -38,8 +39,12 @@
#include "ieee802_3.h"
#include "llc.h"
#include "icmp.h"
#include "icmpv6.h"
#include "dot11.h"
#include "dot1q.h"
#include "dot3.h"
#include "ip.h"
#include "ipv6.h"
#include "packet_sender.h"
#include "packet_writer.h"
#include "pdu.h"
@@ -50,10 +55,17 @@
#include "tcp.h"
#include "udp.h"
#include "utils.h"
#include "dns.h"
#include "tcp_stream.h"
#include "crypto.h"
#include "pdu_cacher.h"
#include "rsn_information.h"
#include "ipv6_address.h"
#include "ip_address.h"
#include "packet.h"
#include "timestamp.h"
#include "sll.h"
#include "dhcpv6.h"
#include "pppoe.h"
#include "stp.h"
#endif // TINS_TINS_H

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, Nasel
* Copyright (c) 2012, Matias Fontanini
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -30,7 +30,7 @@
#ifndef TINS_UDP_H
#define TINS_UDP_H
#include "macros.h"
#include "pdu.h"
#include "endianness.h"
@@ -53,15 +53,20 @@ namespace Tins {
*
* Creates an instance of UDP. Destination and source port can
* be provided, otherwise both will be 0.
*
* \param dport Destination port.
* \param sport Source port.
* \param child The child PDU(optional).
* */
UDP(uint16_t dport = 0, uint16_t sport = 0, PDU *child = 0);
UDP(uint16_t dport = 0, uint16_t sport = 0);
/**
* \brief Constructor which creates an UDP object from a buffer and adds all identifiable
* PDUs found in the buffer as children of this one.
* \brief Constructs an UDP object from a buffer.
*
* If there is not enough size for a UDP header a malformed_packet
* exception is thrown.
*
* Any extra data will be stored in a RawPDU.
*
* \param buffer The buffer from which this PDU will be constructed.
* \param total_sz The total size of the buffer.
*/
@@ -84,6 +89,12 @@ namespace Tins {
* \return The length of the datagram.
*/
uint16_t length() const { return Endian::be_to_host(_udp.len); }
/**
* \brief Getter for the checksum of the datagram.
* \return The datagram's checksum.
*/
uint16_t checksum() const { return Endian::be_to_host(_udp.check); }
/**
* \brief Set the destination port.
@@ -91,19 +102,34 @@ namespace Tins {
*/
void dport(uint16_t new_dport);
/** \brief Set the source port.
/**
* \brief Set the source port.
*
* \param new_sport The new source port.
*/
void sport(uint16_t new_sport);
/** \brief Getter for the length field.
/**
* \brief Getter for the length field.
* \param new_len The new length field.
* \return The length field.
*/
void length(uint16_t new_len);
/** \brief Returns the header size.
/**
* \brief Check wether ptr points to a valid response for this PDU.
*
* This compares the source and destination ports in the provided
* response with those stored in this PDU.
*
* \sa PDU::matches_response
* \param ptr The pointer to the buffer.
* \param total_sz The size of the buffer.
*/
bool matches_response(const uint8_t *ptr, uint32_t total_sz) const;
/**
* \brief Returns the header size.
*
* This metod overrides PDU::header_size. This size includes the
* payload and options size. \sa PDU::header_size
@@ -119,22 +145,22 @@ namespace Tins {
/**
* \sa PDU::clone
*/
PDU *clone() const {
UDP *clone() const {
return new UDP(*this);
}
private:
TINS_BEGIN_PACK
struct udphdr {
uint16_t sport;
uint16_t dport;
uint16_t len;
uint16_t check;
} __attribute__((packed));
} TINS_END_PACK;
void copy_fields(const UDP *other);
void write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *parent);
udphdr _udp;
};
};
}
#endif // TINS_UDP_H

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, Nasel
* Copyright (c) 2012, Matias Fontanini
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -33,16 +33,30 @@
#ifndef WIN32
#include <ifaddrs.h>
#else
#define NOMINMAX
#include <winsock2.h>
#include <iphlpapi.h>
#undef interface
#endif
#include "macros.h"
#if defined(BSD) || defined(__FreeBSD_kernel__)
#include <sys/file.h>
#include <sys/socket.h>
#include <sys/sysctl.h>
#include <net/if.h>
#include <net/route.h>
#include <netinet/in.h>
#endif
#include <string>
#include <set>
#include <fstream>
#include <vector>
#include <stdint.h>
#include "ip_address.h"
#include "ipv6_address.h"
#include "hw_address.h"
#include "internals.h"
namespace Tins {
class NetworkInterface;
@@ -81,7 +95,7 @@ namespace Tins {
*/
IPv4Address mask;
};
/**
* \brief Resolves a domain name and returns its corresponding ip address.
*
@@ -90,20 +104,17 @@ namespace Tins {
*
* \param to_resolve The domain name/ip address to resolve.
*/
IPv4Address resolve_ip(const std::string &to_resolve);
IPv4Address resolve_domain(const std::string &to_resolve);
/**
* \brief Resolves the hardware address for a given ip.
* \brief Resolves a domain name and returns its corresponding ip address.
*
* \param iface The interface in which the packet will be sent.
* \param ip The ip to resolve, in integer format.
* \param buffer The buffer in which the host's hardware address will be stored.
* \param sender The sender to use to send and receive the ARP requests.
* \return Returns true if the hardware address was resolved successfully,
* false otherwise.
* If an ip address is given, its integer representation is returned.
* Otherwise, the domain name is resolved and its ip address is returned.
*
* \param to_resolve The domain name/ip address to resolve.
*/
bool resolve_hwaddr(const NetworkInterface &iface, IPv4Address ip,
HWAddress<6> *address, PacketSender &sender);
IPv6Address resolve_domain6(const std::string &to_resolve);
/**
* \brief Resolves the hardware address for a given ip.
@@ -118,6 +129,21 @@ namespace Tins {
*/
HWAddress<6> resolve_hwaddr(const NetworkInterface &iface,
IPv4Address ip, PacketSender &sender);
/**
* \brief Resolves the hardware address for a given ip.
*
* If the address can't be resolved, a std::runtime_error
* exception is thrown.
*
* This method sends and receives the packet through
* PacketSender::default_interface.
*
* \param ip The ip to resolve, in integer format.
* \param sender The sender to use to send and receive the ARP requests.
* \return HWAddress<6> containing the resolved hardware address.
*/
HWAddress<6> resolve_hwaddr(IPv4Address ip, PacketSender &sender);
/** \brief List all network interfaces.
*
@@ -190,6 +216,16 @@ namespace Tins {
* \return The pseudo header checksum.
*/
uint32_t pseudoheader_checksum(IPv4Address source_ip, IPv4Address dest_ip, uint32_t len, uint32_t flag);
/** \brief Performs the pseudo header checksum used in TCP and UDP PDUs.
*
* \param source_ip The source ip address.
* \param dest_ip The destination ip address.
* \param len The length to be included in the pseudo header.
* \param flag The flag to use in the protocol field of the pseudo header.
* \return The pseudo header checksum.
*/
uint32_t pseudoheader_checksum(IPv6Address source_ip, IPv6Address dest_ip, uint32_t len, uint32_t flag);
/** \brief Generic function to iterate through interface and collect
* data.
@@ -228,27 +264,6 @@ namespace Tins {
}
#endif // WIN32
/**
* \cond
*/
namespace Internals {
void skip_line(std::istream &input);
bool from_hex(const std::string &str, uint32_t &result);
template<bool, typename>
struct enable_if {
};
template<typename T>
struct enable_if<true, T> {
typedef T type;
};
}
/**
* \endcond
*/
template <typename T>
struct is_pdu {
template <typename U>
@@ -280,12 +295,101 @@ namespace Tins {
dereference_until_pdu(T &value) {
return dereference_until_pdu(*value);
}
#if defined(BSD) || defined(__FreeBSD_kernel__)
inline std::vector<char> query_route_table() {
int mib[6];
std::vector<char> buf;
size_t len;
mib[0] = CTL_NET;
mib[1] = AF_ROUTE;
mib[2] = 0;
mib[3] = AF_INET;
mib[4] = NET_RT_DUMP;
mib[5] = 0;
if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0)
throw std::runtime_error("sysctl failed");
buf.resize(len);
if (sysctl(mib, 6, &buf[0], &len, NULL, 0) < 0) {
throw std::runtime_error("sysctl failed");
}
return buf;
}
template<typename ForwardIterator>
void parse_header(struct rt_msghdr *rtm, ForwardIterator iter)
{
char *ptr = (char *)(rtm + 1);
sockaddr *sa = 0;
for (int i = 0; i < RTAX_MAX; i++) {
if (rtm->rtm_addrs & (1 << i)) {
sa = (struct sockaddr *)ptr;
ptr += sa->sa_len;
if (sa->sa_family == 0)
sa = 0;
}
*iter++ = sa;
}
}
#endif
}
}
#if defined(BSD) || defined(__FreeBSD_kernel__)
template<class ForwardIterator>
void Tins::Utils::route_entries(ForwardIterator output) {
using namespace Utils::Internals;
std::vector<char> buffer = query_route_table();
char *next = &buffer[0], *end = &buffer[buffer.size()];
rt_msghdr *rtm;
std::vector<sockaddr*> sa(RTAX_MAX);
char iface_name[IF_NAMESIZE];
while(next < end) {
rtm = (rt_msghdr*)next;
parse_header(rtm, sa.begin());
if (sa[RTAX_DST] && sa[RTAX_GATEWAY] && if_indextoname(rtm->rtm_index, iface_name)) {
RouteEntry entry;
entry.destination = IPv4Address(((struct sockaddr_in *)sa[RTAX_DST])->sin_addr.s_addr);
entry.gateway = IPv4Address(((struct sockaddr_in *)sa[RTAX_GATEWAY])->sin_addr.s_addr);
if(sa[RTAX_GENMASK])
entry.mask = IPv4Address(((struct sockaddr_in *)sa[RTAX_GENMASK])->sin_addr.s_addr);
else
entry.mask = IPv4Address(uint32_t());
entry.interface = iface_name;
*output++ = entry;
}
next += rtm->rtm_msglen;
}
}
#elif defined(WIN32)
template<class ForwardIterator>
void Tins::Utils::route_entries(ForwardIterator output) {
MIB_IPFORWARDTABLE *table;
ULONG size = 0;
char iface_name[256];
GetIpForwardTable(0, &size, 0);
std::vector<uint8_t> buffer(size);
table = (MIB_IPFORWARDTABLE*)&buffer[0];
GetIpForwardTable(table, &size, 0);
for (DWORD i = 0; i < table->dwNumEntries; i++) {
MIB_IPFORWARDROW *row = &table->table[i];
if(row->dwForwardType == MIB_IPROUTE_TYPE_INDIRECT) {
if_indextoname(row->dwForwardIfIndex, iface_name);
RouteEntry entry;
entry.interface = iface_name;
entry.destination = IPv4Address(row->dwForwardDest);
entry.mask = IPv4Address(row->dwForwardMask);
entry.gateway = IPv4Address(row->dwForwardNextHop);
*output++ = entry;
}
}
}
#else
template<class ForwardIterator>
void Tins::Utils::route_entries(ForwardIterator output) {
using namespace Tins::Internals;
std::ifstream input("/proc/net/route");
std::string destination, mask, gw;
uint32_t dummy;
@@ -305,5 +409,6 @@ void Tins::Utils::route_entries(ForwardIterator output) {
++output;
}
}
#endif
#endif // TINS_UTILS_H

527
install-sh Executable file
View File

@@ -0,0 +1,527 @@
#!/bin/sh
# install - install a program, script, or datafile
scriptversion=2011-01-19.21; # UTC
# This originates from X11R5 (mit/util/scripts/install.sh), which was
# later released in X11R6 (xc/config/util/install.sh) with the
# following copyright and license.
#
# Copyright (C) 1994 X Consortium
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to
# deal in the Software without restriction, including without limitation the
# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
# sell copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC-
# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
# Except as contained in this notice, the name of the X Consortium shall not
# be used in advertising or otherwise to promote the sale, use or other deal-
# ings in this Software without prior written authorization from the X Consor-
# tium.
#
#
# FSF changes to this file are in the public domain.
#
# Calling this script install-sh is preferred over install.sh, to prevent
# `make' implicit rules from creating a file called install from it
# when there is no Makefile.
#
# This script is compatible with the BSD install script, but was written
# from scratch.
nl='
'
IFS=" "" $nl"
# set DOITPROG to echo to test this script
# Don't use :- since 4.3BSD and earlier shells don't like it.
doit=${DOITPROG-}
if test -z "$doit"; then
doit_exec=exec
else
doit_exec=$doit
fi
# Put in absolute file names if you don't have them in your path;
# or use environment vars.
chgrpprog=${CHGRPPROG-chgrp}
chmodprog=${CHMODPROG-chmod}
chownprog=${CHOWNPROG-chown}
cmpprog=${CMPPROG-cmp}
cpprog=${CPPROG-cp}
mkdirprog=${MKDIRPROG-mkdir}
mvprog=${MVPROG-mv}
rmprog=${RMPROG-rm}
stripprog=${STRIPPROG-strip}
posix_glob='?'
initialize_posix_glob='
test "$posix_glob" != "?" || {
if (set -f) 2>/dev/null; then
posix_glob=
else
posix_glob=:
fi
}
'
posix_mkdir=
# Desired mode of installed file.
mode=0755
chgrpcmd=
chmodcmd=$chmodprog
chowncmd=
mvcmd=$mvprog
rmcmd="$rmprog -f"
stripcmd=
src=
dst=
dir_arg=
dst_arg=
copy_on_change=false
no_target_directory=
usage="\
Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE
or: $0 [OPTION]... SRCFILES... DIRECTORY
or: $0 [OPTION]... -t DIRECTORY SRCFILES...
or: $0 [OPTION]... -d DIRECTORIES...
In the 1st form, copy SRCFILE to DSTFILE.
In the 2nd and 3rd, copy all SRCFILES to DIRECTORY.
In the 4th, create DIRECTORIES.
Options:
--help display this help and exit.
--version display version info and exit.
-c (ignored)
-C install only if different (preserve the last data modification time)
-d create directories instead of installing files.
-g GROUP $chgrpprog installed files to GROUP.
-m MODE $chmodprog installed files to MODE.
-o USER $chownprog installed files to USER.
-s $stripprog installed files.
-t DIRECTORY install into DIRECTORY.
-T report an error if DSTFILE is a directory.
Environment variables override the default commands:
CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG
RMPROG STRIPPROG
"
while test $# -ne 0; do
case $1 in
-c) ;;
-C) copy_on_change=true;;
-d) dir_arg=true;;
-g) chgrpcmd="$chgrpprog $2"
shift;;
--help) echo "$usage"; exit $?;;
-m) mode=$2
case $mode in
*' '* | *' '* | *'
'* | *'*'* | *'?'* | *'['*)
echo "$0: invalid mode: $mode" >&2
exit 1;;
esac
shift;;
-o) chowncmd="$chownprog $2"
shift;;
-s) stripcmd=$stripprog;;
-t) dst_arg=$2
# Protect names problematic for `test' and other utilities.
case $dst_arg in
-* | [=\(\)!]) dst_arg=./$dst_arg;;
esac
shift;;
-T) no_target_directory=true;;
--version) echo "$0 $scriptversion"; exit $?;;
--) shift
break;;
-*) echo "$0: invalid option: $1" >&2
exit 1;;
*) break;;
esac
shift
done
if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then
# When -d is used, all remaining arguments are directories to create.
# When -t is used, the destination is already specified.
# Otherwise, the last argument is the destination. Remove it from $@.
for arg
do
if test -n "$dst_arg"; then
# $@ is not empty: it contains at least $arg.
set fnord "$@" "$dst_arg"
shift # fnord
fi
shift # arg
dst_arg=$arg
# Protect names problematic for `test' and other utilities.
case $dst_arg in
-* | [=\(\)!]) dst_arg=./$dst_arg;;
esac
done
fi
if test $# -eq 0; then
if test -z "$dir_arg"; then
echo "$0: no input file specified." >&2
exit 1
fi
# It's OK to call `install-sh -d' without argument.
# This can happen when creating conditional directories.
exit 0
fi
if test -z "$dir_arg"; then
do_exit='(exit $ret); exit $ret'
trap "ret=129; $do_exit" 1
trap "ret=130; $do_exit" 2
trap "ret=141; $do_exit" 13
trap "ret=143; $do_exit" 15
# Set umask so as not to create temps with too-generous modes.
# However, 'strip' requires both read and write access to temps.
case $mode in
# Optimize common cases.
*644) cp_umask=133;;
*755) cp_umask=22;;
*[0-7])
if test -z "$stripcmd"; then
u_plus_rw=
else
u_plus_rw='% 200'
fi
cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;;
*)
if test -z "$stripcmd"; then
u_plus_rw=
else
u_plus_rw=,u+rw
fi
cp_umask=$mode$u_plus_rw;;
esac
fi
for src
do
# Protect names problematic for `test' and other utilities.
case $src in
-* | [=\(\)!]) src=./$src;;
esac
if test -n "$dir_arg"; then
dst=$src
dstdir=$dst
test -d "$dstdir"
dstdir_status=$?
else
# Waiting for this to be detected by the "$cpprog $src $dsttmp" command
# might cause directories to be created, which would be especially bad
# if $src (and thus $dsttmp) contains '*'.
if test ! -f "$src" && test ! -d "$src"; then
echo "$0: $src does not exist." >&2
exit 1
fi
if test -z "$dst_arg"; then
echo "$0: no destination specified." >&2
exit 1
fi
dst=$dst_arg
# If destination is a directory, append the input filename; won't work
# if double slashes aren't ignored.
if test -d "$dst"; then
if test -n "$no_target_directory"; then
echo "$0: $dst_arg: Is a directory" >&2
exit 1
fi
dstdir=$dst
dst=$dstdir/`basename "$src"`
dstdir_status=0
else
# Prefer dirname, but fall back on a substitute if dirname fails.
dstdir=`
(dirname "$dst") 2>/dev/null ||
expr X"$dst" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
X"$dst" : 'X\(//\)[^/]' \| \
X"$dst" : 'X\(//\)$' \| \
X"$dst" : 'X\(/\)' \| . 2>/dev/null ||
echo X"$dst" |
sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
s//\1/
q
}
/^X\(\/\/\)[^/].*/{
s//\1/
q
}
/^X\(\/\/\)$/{
s//\1/
q
}
/^X\(\/\).*/{
s//\1/
q
}
s/.*/./; q'
`
test -d "$dstdir"
dstdir_status=$?
fi
fi
obsolete_mkdir_used=false
if test $dstdir_status != 0; then
case $posix_mkdir in
'')
# Create intermediate dirs using mode 755 as modified by the umask.
# This is like FreeBSD 'install' as of 1997-10-28.
umask=`umask`
case $stripcmd.$umask in
# Optimize common cases.
*[2367][2367]) mkdir_umask=$umask;;
.*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;;
*[0-7])
mkdir_umask=`expr $umask + 22 \
- $umask % 100 % 40 + $umask % 20 \
- $umask % 10 % 4 + $umask % 2
`;;
*) mkdir_umask=$umask,go-w;;
esac
# With -d, create the new directory with the user-specified mode.
# Otherwise, rely on $mkdir_umask.
if test -n "$dir_arg"; then
mkdir_mode=-m$mode
else
mkdir_mode=
fi
posix_mkdir=false
case $umask in
*[123567][0-7][0-7])
# POSIX mkdir -p sets u+wx bits regardless of umask, which
# is incompatible with FreeBSD 'install' when (umask & 300) != 0.
;;
*)
tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$
trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0
if (umask $mkdir_umask &&
exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1
then
if test -z "$dir_arg" || {
# Check for POSIX incompatibilities with -m.
# HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or
# other-writeable bit of parent directory when it shouldn't.
# FreeBSD 6.1 mkdir -m -p sets mode of existing directory.
ls_ld_tmpdir=`ls -ld "$tmpdir"`
case $ls_ld_tmpdir in
d????-?r-*) different_mode=700;;
d????-?--*) different_mode=755;;
*) false;;
esac &&
$mkdirprog -m$different_mode -p -- "$tmpdir" && {
ls_ld_tmpdir_1=`ls -ld "$tmpdir"`
test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1"
}
}
then posix_mkdir=:
fi
rmdir "$tmpdir/d" "$tmpdir"
else
# Remove any dirs left behind by ancient mkdir implementations.
rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null
fi
trap '' 0;;
esac;;
esac
if
$posix_mkdir && (
umask $mkdir_umask &&
$doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir"
)
then :
else
# The umask is ridiculous, or mkdir does not conform to POSIX,
# or it failed possibly due to a race condition. Create the
# directory the slow way, step by step, checking for races as we go.
case $dstdir in
/*) prefix='/';;
[-=\(\)!]*) prefix='./';;
*) prefix='';;
esac
eval "$initialize_posix_glob"
oIFS=$IFS
IFS=/
$posix_glob set -f
set fnord $dstdir
shift
$posix_glob set +f
IFS=$oIFS
prefixes=
for d
do
test X"$d" = X && continue
prefix=$prefix$d
if test -d "$prefix"; then
prefixes=
else
if $posix_mkdir; then
(umask=$mkdir_umask &&
$doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break
# Don't fail if two instances are running concurrently.
test -d "$prefix" || exit 1
else
case $prefix in
*\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;;
*) qprefix=$prefix;;
esac
prefixes="$prefixes '$qprefix'"
fi
fi
prefix=$prefix/
done
if test -n "$prefixes"; then
# Don't fail if two instances are running concurrently.
(umask $mkdir_umask &&
eval "\$doit_exec \$mkdirprog $prefixes") ||
test -d "$dstdir" || exit 1
obsolete_mkdir_used=true
fi
fi
fi
if test -n "$dir_arg"; then
{ test -z "$chowncmd" || $doit $chowncmd "$dst"; } &&
{ test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } &&
{ test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false ||
test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1
else
# Make a couple of temp file names in the proper directory.
dsttmp=$dstdir/_inst.$$_
rmtmp=$dstdir/_rm.$$_
# Trap to clean up those temp files at exit.
trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0
# Copy the file name to the temp name.
(umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") &&
# and set any options; do chmod last to preserve setuid bits.
#
# If any of these fail, we abort the whole thing. If we want to
# ignore errors from any of these, just make sure not to ignore
# errors from the above "$doit $cpprog $src $dsttmp" command.
#
{ test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } &&
{ test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } &&
{ test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } &&
{ test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } &&
# If -C, don't bother to copy if it wouldn't change the file.
if $copy_on_change &&
old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` &&
new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` &&
eval "$initialize_posix_glob" &&
$posix_glob set -f &&
set X $old && old=:$2:$4:$5:$6 &&
set X $new && new=:$2:$4:$5:$6 &&
$posix_glob set +f &&
test "$old" = "$new" &&
$cmpprog "$dst" "$dsttmp" >/dev/null 2>&1
then
rm -f "$dsttmp"
else
# Rename the file to the real destination.
$doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null ||
# The rename failed, perhaps because mv can't rename something else
# to itself, or perhaps because mv is so ancient that it does not
# support -f.
{
# Now remove or move aside any old file at destination location.
# We try this two ways since rm can't unlink itself on some
# systems and the destination file might be busy for other
# reasons. In this case, the final cleanup might fail but the new
# file should still install successfully.
{
test ! -f "$dst" ||
$doit $rmcmd -f "$dst" 2>/dev/null ||
{ $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null &&
{ $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; }
} ||
{ echo "$0: cannot unlink or rename $dst" >&2
(exit 1); exit 1
}
} &&
# Now rename the file to the real destination.
$doit $mvcmd "$dsttmp" "$dst"
}
fi || exit 1
trap '' 0
fi
done
# Local variables:
# eval: (add-hook 'write-file-hooks 'time-stamp)
# time-stamp-start: "scriptversion="
# time-stamp-format: "%:y-%02m-%02d.%02H"
# time-stamp-time-zone: "UTC"
# time-stamp-end: "; # UTC"
# End:

11
libtins.pc.in Normal file
View File

@@ -0,0 +1,11 @@
prefix=@prefix@
exec_prefix=@exec_prefix@
libdir=@libdir@
includedir=@includedir@
Name: @PACKAGE_NAME@
Description: C++ packet crafting, sniffing and interpretation library.
Version: @PACKAGE_VERSION@
URL: @PACKAGE_URL@
Libs: -L${libdir} -ltins
Cflags: -I${includedir}/tins

9661
ltmain.sh Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,134 @@
# ============================================================================
# http://www.gnu.org/software/autoconf-archive/ax_cxx_compile_stdcxx_11.html
# ============================================================================
#
# SYNOPSIS
#
# AX_CXX_COMPILE_STDCXX_11([ext|noext],[mandatory|optional])
#
# DESCRIPTION
#
# Check for baseline language coverage in the compiler for the C++11
# standard; if necessary, add switches to CXXFLAGS to enable support.
#
# The first argument, if specified, indicates whether you insist on an
# extended mode (e.g. -std=gnu++11) or a strict conformance mode (e.g.
# -std=c++11). If neither is specified, you get whatever works, with
# preference for an extended mode.
#
# The second argument, if specified 'mandatory' or if left unspecified,
# indicates that baseline C++11 support is required and that the macro
# should error out if no mode with that support is found. If specified
# 'optional', then configuration proceeds regardless, after defining
# HAVE_CXX11 if and only if a supporting mode is found.
#
# LICENSE
#
# Copyright (c) 2008 Benjamin Kosnik <bkoz@redhat.com>
# Copyright (c) 2012 Zack Weinberg <zackw@panix.com>
# Copyright (c) 2013 Roy Stogner <roystgnr@ices.utexas.edu>
#
# Copying and distribution of this file, with or without modification, are
# permitted in any medium without royalty provided the copyright notice
# and this notice are preserved. This file is offered as-is, without any
# warranty.
#serial 3
m4_define([_AX_CXX_COMPILE_STDCXX_11_testbody], [
template <typename T>
struct check
{
static_assert(sizeof(int) <= sizeof(T), "not big enough");
};
typedef check<check<bool>> right_angle_brackets;
int a;
decltype(a) b;
typedef check<int> check_type;
check_type c;
check_type&& cr = static_cast<check_type&&>(c);
auto d = a;
])
AC_DEFUN([AX_CXX_COMPILE_STDCXX_11], [dnl
m4_if([$1], [], [],
[$1], [ext], [],
[$1], [noext], [],
[m4_fatal([invalid argument `$1' to AX_CXX_COMPILE_STDCXX_11])])dnl
m4_if([$2], [], [ax_cxx_compile_cxx11_required=true],
[$2], [mandatory], [ax_cxx_compile_cxx11_required=true],
[$2], [optional], [ax_cxx_compile_cxx11_required=false],
[m4_fatal([invalid second argument `$2' to AX_CXX_COMPILE_STDCXX_11])])dnl
AC_LANG_PUSH([C++])dnl
ac_success=no
AC_CACHE_CHECK(whether $CXX supports C++11 features by default,
ax_cv_cxx_compile_cxx11,
[AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_11_testbody])],
[ax_cv_cxx_compile_cxx11=yes],
[ax_cv_cxx_compile_cxx11=no])])
if test x$ax_cv_cxx_compile_cxx11 = xyes; then
ac_success=yes
fi
m4_if([$1], [noext], [], [dnl
if test x$ac_success = xno; then
for switch in -std=gnu++11 -std=gnu++0x; do
cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx11_$switch])
AC_CACHE_CHECK(whether $CXX supports C++11 features with $switch,
$cachevar,
[ac_save_CXXFLAGS="$CXXFLAGS"
CXXFLAGS="$CXXFLAGS $switch"
AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_11_testbody])],
[eval $cachevar=yes],
[eval $cachevar=no])
CXXFLAGS="$ac_save_CXXFLAGS"])
if eval test x\$$cachevar = xyes; then
CXXFLAGS="$CXXFLAGS $switch"
ac_success=yes
break
fi
done
fi])
m4_if([$1], [ext], [], [dnl
if test x$ac_success = xno; then
for switch in -std=c++11 -std=c++0x; do
cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx11_$switch])
AC_CACHE_CHECK(whether $CXX supports C++11 features with $switch,
$cachevar,
[ac_save_CXXFLAGS="$CXXFLAGS"
CXXFLAGS="$CXXFLAGS $switch"
AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_11_testbody])],
[eval $cachevar=yes],
[eval $cachevar=no])
CXXFLAGS="$ac_save_CXXFLAGS"])
if eval test x\$$cachevar = xyes; then
CXXFLAGS="$CXXFLAGS $switch"
ac_success=yes
break
fi
done
fi])
AC_LANG_POP([C++])
if test x$ax_cxx_compile_cxx11_required = xtrue; then
if test x$ac_success = xno; then
AC_MSG_ERROR([*** A compiler with support for C++11 language features is required.])
fi
else
if test x$ac_success = xno; then
HAVE_CXX11=0
AC_MSG_NOTICE([No compiler with C++11 support was found])
else
HAVE_CXX11=1
AC_DEFINE(HAVE_CXX11,1,
[define if the compiler supports basic C++11 syntax])
fi
AC_SUBST(HAVE_CXX11)
fi
])

8001
m4/libtool.m4 vendored Normal file

File diff suppressed because it is too large Load Diff

384
m4/ltoptions.m4 vendored Normal file
View File

@@ -0,0 +1,384 @@
# Helper functions for option handling. -*- Autoconf -*-
#
# Copyright (C) 2004, 2005, 2007, 2008, 2009 Free Software Foundation,
# Inc.
# Written by Gary V. Vaughan, 2004
#
# This file is free software; the Free Software Foundation gives
# unlimited permission to copy and/or distribute it, with or without
# modifications, as long as this notice is preserved.
# serial 7 ltoptions.m4
# This is to help aclocal find these macros, as it can't see m4_define.
AC_DEFUN([LTOPTIONS_VERSION], [m4_if([1])])
# _LT_MANGLE_OPTION(MACRO-NAME, OPTION-NAME)
# ------------------------------------------
m4_define([_LT_MANGLE_OPTION],
[[_LT_OPTION_]m4_bpatsubst($1__$2, [[^a-zA-Z0-9_]], [_])])
# _LT_SET_OPTION(MACRO-NAME, OPTION-NAME)
# ---------------------------------------
# Set option OPTION-NAME for macro MACRO-NAME, and if there is a
# matching handler defined, dispatch to it. Other OPTION-NAMEs are
# saved as a flag.
m4_define([_LT_SET_OPTION],
[m4_define(_LT_MANGLE_OPTION([$1], [$2]))dnl
m4_ifdef(_LT_MANGLE_DEFUN([$1], [$2]),
_LT_MANGLE_DEFUN([$1], [$2]),
[m4_warning([Unknown $1 option `$2'])])[]dnl
])
# _LT_IF_OPTION(MACRO-NAME, OPTION-NAME, IF-SET, [IF-NOT-SET])
# ------------------------------------------------------------
# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise.
m4_define([_LT_IF_OPTION],
[m4_ifdef(_LT_MANGLE_OPTION([$1], [$2]), [$3], [$4])])
# _LT_UNLESS_OPTIONS(MACRO-NAME, OPTION-LIST, IF-NOT-SET)
# -------------------------------------------------------
# Execute IF-NOT-SET unless all options in OPTION-LIST for MACRO-NAME
# are set.
m4_define([_LT_UNLESS_OPTIONS],
[m4_foreach([_LT_Option], m4_split(m4_normalize([$2])),
[m4_ifdef(_LT_MANGLE_OPTION([$1], _LT_Option),
[m4_define([$0_found])])])[]dnl
m4_ifdef([$0_found], [m4_undefine([$0_found])], [$3
])[]dnl
])
# _LT_SET_OPTIONS(MACRO-NAME, OPTION-LIST)
# ----------------------------------------
# OPTION-LIST is a space-separated list of Libtool options associated
# with MACRO-NAME. If any OPTION has a matching handler declared with
# LT_OPTION_DEFINE, dispatch to that macro; otherwise complain about
# the unknown option and exit.
m4_defun([_LT_SET_OPTIONS],
[# Set options
m4_foreach([_LT_Option], m4_split(m4_normalize([$2])),
[_LT_SET_OPTION([$1], _LT_Option)])
m4_if([$1],[LT_INIT],[
dnl
dnl Simply set some default values (i.e off) if boolean options were not
dnl specified:
_LT_UNLESS_OPTIONS([LT_INIT], [dlopen], [enable_dlopen=no
])
_LT_UNLESS_OPTIONS([LT_INIT], [win32-dll], [enable_win32_dll=no
])
dnl
dnl If no reference was made to various pairs of opposing options, then
dnl we run the default mode handler for the pair. For example, if neither
dnl `shared' nor `disable-shared' was passed, we enable building of shared
dnl archives by default:
_LT_UNLESS_OPTIONS([LT_INIT], [shared disable-shared], [_LT_ENABLE_SHARED])
_LT_UNLESS_OPTIONS([LT_INIT], [static disable-static], [_LT_ENABLE_STATIC])
_LT_UNLESS_OPTIONS([LT_INIT], [pic-only no-pic], [_LT_WITH_PIC])
_LT_UNLESS_OPTIONS([LT_INIT], [fast-install disable-fast-install],
[_LT_ENABLE_FAST_INSTALL])
])
])# _LT_SET_OPTIONS
## --------------------------------- ##
## Macros to handle LT_INIT options. ##
## --------------------------------- ##
# _LT_MANGLE_DEFUN(MACRO-NAME, OPTION-NAME)
# -----------------------------------------
m4_define([_LT_MANGLE_DEFUN],
[[_LT_OPTION_DEFUN_]m4_bpatsubst(m4_toupper([$1__$2]), [[^A-Z0-9_]], [_])])
# LT_OPTION_DEFINE(MACRO-NAME, OPTION-NAME, CODE)
# -----------------------------------------------
m4_define([LT_OPTION_DEFINE],
[m4_define(_LT_MANGLE_DEFUN([$1], [$2]), [$3])[]dnl
])# LT_OPTION_DEFINE
# dlopen
# ------
LT_OPTION_DEFINE([LT_INIT], [dlopen], [enable_dlopen=yes
])
AU_DEFUN([AC_LIBTOOL_DLOPEN],
[_LT_SET_OPTION([LT_INIT], [dlopen])
AC_DIAGNOSE([obsolete],
[$0: Remove this warning and the call to _LT_SET_OPTION when you
put the `dlopen' option into LT_INIT's first parameter.])
])
dnl aclocal-1.4 backwards compatibility:
dnl AC_DEFUN([AC_LIBTOOL_DLOPEN], [])
# win32-dll
# ---------
# Declare package support for building win32 dll's.
LT_OPTION_DEFINE([LT_INIT], [win32-dll],
[enable_win32_dll=yes
case $host in
*-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-cegcc*)
AC_CHECK_TOOL(AS, as, false)
AC_CHECK_TOOL(DLLTOOL, dlltool, false)
AC_CHECK_TOOL(OBJDUMP, objdump, false)
;;
esac
test -z "$AS" && AS=as
_LT_DECL([], [AS], [1], [Assembler program])dnl
test -z "$DLLTOOL" && DLLTOOL=dlltool
_LT_DECL([], [DLLTOOL], [1], [DLL creation program])dnl
test -z "$OBJDUMP" && OBJDUMP=objdump
_LT_DECL([], [OBJDUMP], [1], [Object dumper program])dnl
])# win32-dll
AU_DEFUN([AC_LIBTOOL_WIN32_DLL],
[AC_REQUIRE([AC_CANONICAL_HOST])dnl
_LT_SET_OPTION([LT_INIT], [win32-dll])
AC_DIAGNOSE([obsolete],
[$0: Remove this warning and the call to _LT_SET_OPTION when you
put the `win32-dll' option into LT_INIT's first parameter.])
])
dnl aclocal-1.4 backwards compatibility:
dnl AC_DEFUN([AC_LIBTOOL_WIN32_DLL], [])
# _LT_ENABLE_SHARED([DEFAULT])
# ----------------------------
# implement the --enable-shared flag, and supports the `shared' and
# `disable-shared' LT_INIT options.
# DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'.
m4_define([_LT_ENABLE_SHARED],
[m4_define([_LT_ENABLE_SHARED_DEFAULT], [m4_if($1, no, no, yes)])dnl
AC_ARG_ENABLE([shared],
[AS_HELP_STRING([--enable-shared@<:@=PKGS@:>@],
[build shared libraries @<:@default=]_LT_ENABLE_SHARED_DEFAULT[@:>@])],
[p=${PACKAGE-default}
case $enableval in
yes) enable_shared=yes ;;
no) enable_shared=no ;;
*)
enable_shared=no
# Look at the argument we got. We use all the common list separators.
lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
for pkg in $enableval; do
IFS="$lt_save_ifs"
if test "X$pkg" = "X$p"; then
enable_shared=yes
fi
done
IFS="$lt_save_ifs"
;;
esac],
[enable_shared=]_LT_ENABLE_SHARED_DEFAULT)
_LT_DECL([build_libtool_libs], [enable_shared], [0],
[Whether or not to build shared libraries])
])# _LT_ENABLE_SHARED
LT_OPTION_DEFINE([LT_INIT], [shared], [_LT_ENABLE_SHARED([yes])])
LT_OPTION_DEFINE([LT_INIT], [disable-shared], [_LT_ENABLE_SHARED([no])])
# Old names:
AC_DEFUN([AC_ENABLE_SHARED],
[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[shared])
])
AC_DEFUN([AC_DISABLE_SHARED],
[_LT_SET_OPTION([LT_INIT], [disable-shared])
])
AU_DEFUN([AM_ENABLE_SHARED], [AC_ENABLE_SHARED($@)])
AU_DEFUN([AM_DISABLE_SHARED], [AC_DISABLE_SHARED($@)])
dnl aclocal-1.4 backwards compatibility:
dnl AC_DEFUN([AM_ENABLE_SHARED], [])
dnl AC_DEFUN([AM_DISABLE_SHARED], [])
# _LT_ENABLE_STATIC([DEFAULT])
# ----------------------------
# implement the --enable-static flag, and support the `static' and
# `disable-static' LT_INIT options.
# DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'.
m4_define([_LT_ENABLE_STATIC],
[m4_define([_LT_ENABLE_STATIC_DEFAULT], [m4_if($1, no, no, yes)])dnl
AC_ARG_ENABLE([static],
[AS_HELP_STRING([--enable-static@<:@=PKGS@:>@],
[build static libraries @<:@default=]_LT_ENABLE_STATIC_DEFAULT[@:>@])],
[p=${PACKAGE-default}
case $enableval in
yes) enable_static=yes ;;
no) enable_static=no ;;
*)
enable_static=no
# Look at the argument we got. We use all the common list separators.
lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
for pkg in $enableval; do
IFS="$lt_save_ifs"
if test "X$pkg" = "X$p"; then
enable_static=yes
fi
done
IFS="$lt_save_ifs"
;;
esac],
[enable_static=]_LT_ENABLE_STATIC_DEFAULT)
_LT_DECL([build_old_libs], [enable_static], [0],
[Whether or not to build static libraries])
])# _LT_ENABLE_STATIC
LT_OPTION_DEFINE([LT_INIT], [static], [_LT_ENABLE_STATIC([yes])])
LT_OPTION_DEFINE([LT_INIT], [disable-static], [_LT_ENABLE_STATIC([no])])
# Old names:
AC_DEFUN([AC_ENABLE_STATIC],
[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[static])
])
AC_DEFUN([AC_DISABLE_STATIC],
[_LT_SET_OPTION([LT_INIT], [disable-static])
])
AU_DEFUN([AM_ENABLE_STATIC], [AC_ENABLE_STATIC($@)])
AU_DEFUN([AM_DISABLE_STATIC], [AC_DISABLE_STATIC($@)])
dnl aclocal-1.4 backwards compatibility:
dnl AC_DEFUN([AM_ENABLE_STATIC], [])
dnl AC_DEFUN([AM_DISABLE_STATIC], [])
# _LT_ENABLE_FAST_INSTALL([DEFAULT])
# ----------------------------------
# implement the --enable-fast-install flag, and support the `fast-install'
# and `disable-fast-install' LT_INIT options.
# DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'.
m4_define([_LT_ENABLE_FAST_INSTALL],
[m4_define([_LT_ENABLE_FAST_INSTALL_DEFAULT], [m4_if($1, no, no, yes)])dnl
AC_ARG_ENABLE([fast-install],
[AS_HELP_STRING([--enable-fast-install@<:@=PKGS@:>@],
[optimize for fast installation @<:@default=]_LT_ENABLE_FAST_INSTALL_DEFAULT[@:>@])],
[p=${PACKAGE-default}
case $enableval in
yes) enable_fast_install=yes ;;
no) enable_fast_install=no ;;
*)
enable_fast_install=no
# Look at the argument we got. We use all the common list separators.
lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
for pkg in $enableval; do
IFS="$lt_save_ifs"
if test "X$pkg" = "X$p"; then
enable_fast_install=yes
fi
done
IFS="$lt_save_ifs"
;;
esac],
[enable_fast_install=]_LT_ENABLE_FAST_INSTALL_DEFAULT)
_LT_DECL([fast_install], [enable_fast_install], [0],
[Whether or not to optimize for fast installation])dnl
])# _LT_ENABLE_FAST_INSTALL
LT_OPTION_DEFINE([LT_INIT], [fast-install], [_LT_ENABLE_FAST_INSTALL([yes])])
LT_OPTION_DEFINE([LT_INIT], [disable-fast-install], [_LT_ENABLE_FAST_INSTALL([no])])
# Old names:
AU_DEFUN([AC_ENABLE_FAST_INSTALL],
[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[fast-install])
AC_DIAGNOSE([obsolete],
[$0: Remove this warning and the call to _LT_SET_OPTION when you put
the `fast-install' option into LT_INIT's first parameter.])
])
AU_DEFUN([AC_DISABLE_FAST_INSTALL],
[_LT_SET_OPTION([LT_INIT], [disable-fast-install])
AC_DIAGNOSE([obsolete],
[$0: Remove this warning and the call to _LT_SET_OPTION when you put
the `disable-fast-install' option into LT_INIT's first parameter.])
])
dnl aclocal-1.4 backwards compatibility:
dnl AC_DEFUN([AC_ENABLE_FAST_INSTALL], [])
dnl AC_DEFUN([AM_DISABLE_FAST_INSTALL], [])
# _LT_WITH_PIC([MODE])
# --------------------
# implement the --with-pic flag, and support the `pic-only' and `no-pic'
# LT_INIT options.
# MODE is either `yes' or `no'. If omitted, it defaults to `both'.
m4_define([_LT_WITH_PIC],
[AC_ARG_WITH([pic],
[AS_HELP_STRING([--with-pic@<:@=PKGS@:>@],
[try to use only PIC/non-PIC objects @<:@default=use both@:>@])],
[lt_p=${PACKAGE-default}
case $withval in
yes|no) pic_mode=$withval ;;
*)
pic_mode=default
# Look at the argument we got. We use all the common list separators.
lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
for lt_pkg in $withval; do
IFS="$lt_save_ifs"
if test "X$lt_pkg" = "X$lt_p"; then
pic_mode=yes
fi
done
IFS="$lt_save_ifs"
;;
esac],
[pic_mode=default])
test -z "$pic_mode" && pic_mode=m4_default([$1], [default])
_LT_DECL([], [pic_mode], [0], [What type of objects to build])dnl
])# _LT_WITH_PIC
LT_OPTION_DEFINE([LT_INIT], [pic-only], [_LT_WITH_PIC([yes])])
LT_OPTION_DEFINE([LT_INIT], [no-pic], [_LT_WITH_PIC([no])])
# Old name:
AU_DEFUN([AC_LIBTOOL_PICMODE],
[_LT_SET_OPTION([LT_INIT], [pic-only])
AC_DIAGNOSE([obsolete],
[$0: Remove this warning and the call to _LT_SET_OPTION when you
put the `pic-only' option into LT_INIT's first parameter.])
])
dnl aclocal-1.4 backwards compatibility:
dnl AC_DEFUN([AC_LIBTOOL_PICMODE], [])
## ----------------- ##
## LTDL_INIT Options ##
## ----------------- ##
m4_define([_LTDL_MODE], [])
LT_OPTION_DEFINE([LTDL_INIT], [nonrecursive],
[m4_define([_LTDL_MODE], [nonrecursive])])
LT_OPTION_DEFINE([LTDL_INIT], [recursive],
[m4_define([_LTDL_MODE], [recursive])])
LT_OPTION_DEFINE([LTDL_INIT], [subproject],
[m4_define([_LTDL_MODE], [subproject])])
m4_define([_LTDL_TYPE], [])
LT_OPTION_DEFINE([LTDL_INIT], [installable],
[m4_define([_LTDL_TYPE], [installable])])
LT_OPTION_DEFINE([LTDL_INIT], [convenience],
[m4_define([_LTDL_TYPE], [convenience])])

123
m4/ltsugar.m4 vendored Normal file
View File

@@ -0,0 +1,123 @@
# ltsugar.m4 -- libtool m4 base layer. -*-Autoconf-*-
#
# Copyright (C) 2004, 2005, 2007, 2008 Free Software Foundation, Inc.
# Written by Gary V. Vaughan, 2004
#
# This file is free software; the Free Software Foundation gives
# unlimited permission to copy and/or distribute it, with or without
# modifications, as long as this notice is preserved.
# serial 6 ltsugar.m4
# This is to help aclocal find these macros, as it can't see m4_define.
AC_DEFUN([LTSUGAR_VERSION], [m4_if([0.1])])
# lt_join(SEP, ARG1, [ARG2...])
# -----------------------------
# Produce ARG1SEPARG2...SEPARGn, omitting [] arguments and their
# associated separator.
# Needed until we can rely on m4_join from Autoconf 2.62, since all earlier
# versions in m4sugar had bugs.
m4_define([lt_join],
[m4_if([$#], [1], [],
[$#], [2], [[$2]],
[m4_if([$2], [], [], [[$2]_])$0([$1], m4_shift(m4_shift($@)))])])
m4_define([_lt_join],
[m4_if([$#$2], [2], [],
[m4_if([$2], [], [], [[$1$2]])$0([$1], m4_shift(m4_shift($@)))])])
# lt_car(LIST)
# lt_cdr(LIST)
# ------------
# Manipulate m4 lists.
# These macros are necessary as long as will still need to support
# Autoconf-2.59 which quotes differently.
m4_define([lt_car], [[$1]])
m4_define([lt_cdr],
[m4_if([$#], 0, [m4_fatal([$0: cannot be called without arguments])],
[$#], 1, [],
[m4_dquote(m4_shift($@))])])
m4_define([lt_unquote], $1)
# lt_append(MACRO-NAME, STRING, [SEPARATOR])
# ------------------------------------------
# Redefine MACRO-NAME to hold its former content plus `SEPARATOR'`STRING'.
# Note that neither SEPARATOR nor STRING are expanded; they are appended
# to MACRO-NAME as is (leaving the expansion for when MACRO-NAME is invoked).
# No SEPARATOR is output if MACRO-NAME was previously undefined (different
# than defined and empty).
#
# This macro is needed until we can rely on Autoconf 2.62, since earlier
# versions of m4sugar mistakenly expanded SEPARATOR but not STRING.
m4_define([lt_append],
[m4_define([$1],
m4_ifdef([$1], [m4_defn([$1])[$3]])[$2])])
# lt_combine(SEP, PREFIX-LIST, INFIX, SUFFIX1, [SUFFIX2...])
# ----------------------------------------------------------
# Produce a SEP delimited list of all paired combinations of elements of
# PREFIX-LIST with SUFFIX1 through SUFFIXn. Each element of the list
# has the form PREFIXmINFIXSUFFIXn.
# Needed until we can rely on m4_combine added in Autoconf 2.62.
m4_define([lt_combine],
[m4_if(m4_eval([$# > 3]), [1],
[m4_pushdef([_Lt_sep], [m4_define([_Lt_sep], m4_defn([lt_car]))])]]dnl
[[m4_foreach([_Lt_prefix], [$2],
[m4_foreach([_Lt_suffix],
]m4_dquote(m4_dquote(m4_shift(m4_shift(m4_shift($@)))))[,
[_Lt_sep([$1])[]m4_defn([_Lt_prefix])[$3]m4_defn([_Lt_suffix])])])])])
# lt_if_append_uniq(MACRO-NAME, VARNAME, [SEPARATOR], [UNIQ], [NOT-UNIQ])
# -----------------------------------------------------------------------
# Iff MACRO-NAME does not yet contain VARNAME, then append it (delimited
# by SEPARATOR if supplied) and expand UNIQ, else NOT-UNIQ.
m4_define([lt_if_append_uniq],
[m4_ifdef([$1],
[m4_if(m4_index([$3]m4_defn([$1])[$3], [$3$2$3]), [-1],
[lt_append([$1], [$2], [$3])$4],
[$5])],
[lt_append([$1], [$2], [$3])$4])])
# lt_dict_add(DICT, KEY, VALUE)
# -----------------------------
m4_define([lt_dict_add],
[m4_define([$1($2)], [$3])])
# lt_dict_add_subkey(DICT, KEY, SUBKEY, VALUE)
# --------------------------------------------
m4_define([lt_dict_add_subkey],
[m4_define([$1($2:$3)], [$4])])
# lt_dict_fetch(DICT, KEY, [SUBKEY])
# ----------------------------------
m4_define([lt_dict_fetch],
[m4_ifval([$3],
m4_ifdef([$1($2:$3)], [m4_defn([$1($2:$3)])]),
m4_ifdef([$1($2)], [m4_defn([$1($2)])]))])
# lt_if_dict_fetch(DICT, KEY, [SUBKEY], VALUE, IF-TRUE, [IF-FALSE])
# -----------------------------------------------------------------
m4_define([lt_if_dict_fetch],
[m4_if(lt_dict_fetch([$1], [$2], [$3]), [$4],
[$5],
[$6])])
# lt_dict_filter(DICT, [SUBKEY], VALUE, [SEPARATOR], KEY, [...])
# --------------------------------------------------------------
m4_define([lt_dict_filter],
[m4_if([$5], [], [],
[lt_join(m4_quote(m4_default([$4], [[, ]])),
lt_unquote(m4_split(m4_normalize(m4_foreach(_Lt_key, lt_car([m4_shiftn(4, $@)]),
[lt_if_dict_fetch([$1], _Lt_key, [$2], [$3], [_Lt_key ])])))))])[]dnl
])

23
m4/ltversion.m4 vendored Normal file
View File

@@ -0,0 +1,23 @@
# ltversion.m4 -- version numbers -*- Autoconf -*-
#
# Copyright (C) 2004 Free Software Foundation, Inc.
# Written by Scott James Remnant, 2004
#
# This file is free software; the Free Software Foundation gives
# unlimited permission to copy and/or distribute it, with or without
# modifications, as long as this notice is preserved.
# @configure_input@
# serial 3337 ltversion.m4
# This file is part of GNU Libtool
m4_define([LT_PACKAGE_VERSION], [2.4.2])
m4_define([LT_PACKAGE_REVISION], [1.3337])
AC_DEFUN([LTVERSION_VERSION],
[macro_version='2.4.2'
macro_revision='1.3337'
_LT_DECL(, macro_version, 0, [Which release of libtool.m4 was used?])
_LT_DECL(, macro_revision, 0)
])

98
m4/lt~obsolete.m4 vendored Normal file
View File

@@ -0,0 +1,98 @@
# lt~obsolete.m4 -- aclocal satisfying obsolete definitions. -*-Autoconf-*-
#
# Copyright (C) 2004, 2005, 2007, 2009 Free Software Foundation, Inc.
# Written by Scott James Remnant, 2004.
#
# This file is free software; the Free Software Foundation gives
# unlimited permission to copy and/or distribute it, with or without
# modifications, as long as this notice is preserved.
# serial 5 lt~obsolete.m4
# These exist entirely to fool aclocal when bootstrapping libtool.
#
# In the past libtool.m4 has provided macros via AC_DEFUN (or AU_DEFUN)
# which have later been changed to m4_define as they aren't part of the
# exported API, or moved to Autoconf or Automake where they belong.
#
# The trouble is, aclocal is a bit thick. It'll see the old AC_DEFUN
# in /usr/share/aclocal/libtool.m4 and remember it, then when it sees us
# using a macro with the same name in our local m4/libtool.m4 it'll
# pull the old libtool.m4 in (it doesn't see our shiny new m4_define
# and doesn't know about Autoconf macros at all.)
#
# So we provide this file, which has a silly filename so it's always
# included after everything else. This provides aclocal with the
# AC_DEFUNs it wants, but when m4 processes it, it doesn't do anything
# because those macros already exist, or will be overwritten later.
# We use AC_DEFUN over AU_DEFUN for compatibility with aclocal-1.6.
#
# Anytime we withdraw an AC_DEFUN or AU_DEFUN, remember to add it here.
# Yes, that means every name once taken will need to remain here until
# we give up compatibility with versions before 1.7, at which point
# we need to keep only those names which we still refer to.
# This is to help aclocal find these macros, as it can't see m4_define.
AC_DEFUN([LTOBSOLETE_VERSION], [m4_if([1])])
m4_ifndef([AC_LIBTOOL_LINKER_OPTION], [AC_DEFUN([AC_LIBTOOL_LINKER_OPTION])])
m4_ifndef([AC_PROG_EGREP], [AC_DEFUN([AC_PROG_EGREP])])
m4_ifndef([_LT_AC_PROG_ECHO_BACKSLASH], [AC_DEFUN([_LT_AC_PROG_ECHO_BACKSLASH])])
m4_ifndef([_LT_AC_SHELL_INIT], [AC_DEFUN([_LT_AC_SHELL_INIT])])
m4_ifndef([_LT_AC_SYS_LIBPATH_AIX], [AC_DEFUN([_LT_AC_SYS_LIBPATH_AIX])])
m4_ifndef([_LT_PROG_LTMAIN], [AC_DEFUN([_LT_PROG_LTMAIN])])
m4_ifndef([_LT_AC_TAGVAR], [AC_DEFUN([_LT_AC_TAGVAR])])
m4_ifndef([AC_LTDL_ENABLE_INSTALL], [AC_DEFUN([AC_LTDL_ENABLE_INSTALL])])
m4_ifndef([AC_LTDL_PREOPEN], [AC_DEFUN([AC_LTDL_PREOPEN])])
m4_ifndef([_LT_AC_SYS_COMPILER], [AC_DEFUN([_LT_AC_SYS_COMPILER])])
m4_ifndef([_LT_AC_LOCK], [AC_DEFUN([_LT_AC_LOCK])])
m4_ifndef([AC_LIBTOOL_SYS_OLD_ARCHIVE], [AC_DEFUN([AC_LIBTOOL_SYS_OLD_ARCHIVE])])
m4_ifndef([_LT_AC_TRY_DLOPEN_SELF], [AC_DEFUN([_LT_AC_TRY_DLOPEN_SELF])])
m4_ifndef([AC_LIBTOOL_PROG_CC_C_O], [AC_DEFUN([AC_LIBTOOL_PROG_CC_C_O])])
m4_ifndef([AC_LIBTOOL_SYS_HARD_LINK_LOCKS], [AC_DEFUN([AC_LIBTOOL_SYS_HARD_LINK_LOCKS])])
m4_ifndef([AC_LIBTOOL_OBJDIR], [AC_DEFUN([AC_LIBTOOL_OBJDIR])])
m4_ifndef([AC_LTDL_OBJDIR], [AC_DEFUN([AC_LTDL_OBJDIR])])
m4_ifndef([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH], [AC_DEFUN([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH])])
m4_ifndef([AC_LIBTOOL_SYS_LIB_STRIP], [AC_DEFUN([AC_LIBTOOL_SYS_LIB_STRIP])])
m4_ifndef([AC_PATH_MAGIC], [AC_DEFUN([AC_PATH_MAGIC])])
m4_ifndef([AC_PROG_LD_GNU], [AC_DEFUN([AC_PROG_LD_GNU])])
m4_ifndef([AC_PROG_LD_RELOAD_FLAG], [AC_DEFUN([AC_PROG_LD_RELOAD_FLAG])])
m4_ifndef([AC_DEPLIBS_CHECK_METHOD], [AC_DEFUN([AC_DEPLIBS_CHECK_METHOD])])
m4_ifndef([AC_LIBTOOL_PROG_COMPILER_NO_RTTI], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_NO_RTTI])])
m4_ifndef([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE], [AC_DEFUN([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE])])
m4_ifndef([AC_LIBTOOL_PROG_COMPILER_PIC], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_PIC])])
m4_ifndef([AC_LIBTOOL_PROG_LD_SHLIBS], [AC_DEFUN([AC_LIBTOOL_PROG_LD_SHLIBS])])
m4_ifndef([AC_LIBTOOL_POSTDEP_PREDEP], [AC_DEFUN([AC_LIBTOOL_POSTDEP_PREDEP])])
m4_ifndef([LT_AC_PROG_EGREP], [AC_DEFUN([LT_AC_PROG_EGREP])])
m4_ifndef([LT_AC_PROG_SED], [AC_DEFUN([LT_AC_PROG_SED])])
m4_ifndef([_LT_CC_BASENAME], [AC_DEFUN([_LT_CC_BASENAME])])
m4_ifndef([_LT_COMPILER_BOILERPLATE], [AC_DEFUN([_LT_COMPILER_BOILERPLATE])])
m4_ifndef([_LT_LINKER_BOILERPLATE], [AC_DEFUN([_LT_LINKER_BOILERPLATE])])
m4_ifndef([_AC_PROG_LIBTOOL], [AC_DEFUN([_AC_PROG_LIBTOOL])])
m4_ifndef([AC_LIBTOOL_SETUP], [AC_DEFUN([AC_LIBTOOL_SETUP])])
m4_ifndef([_LT_AC_CHECK_DLFCN], [AC_DEFUN([_LT_AC_CHECK_DLFCN])])
m4_ifndef([AC_LIBTOOL_SYS_DYNAMIC_LINKER], [AC_DEFUN([AC_LIBTOOL_SYS_DYNAMIC_LINKER])])
m4_ifndef([_LT_AC_TAGCONFIG], [AC_DEFUN([_LT_AC_TAGCONFIG])])
m4_ifndef([AC_DISABLE_FAST_INSTALL], [AC_DEFUN([AC_DISABLE_FAST_INSTALL])])
m4_ifndef([_LT_AC_LANG_CXX], [AC_DEFUN([_LT_AC_LANG_CXX])])
m4_ifndef([_LT_AC_LANG_F77], [AC_DEFUN([_LT_AC_LANG_F77])])
m4_ifndef([_LT_AC_LANG_GCJ], [AC_DEFUN([_LT_AC_LANG_GCJ])])
m4_ifndef([AC_LIBTOOL_LANG_C_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_C_CONFIG])])
m4_ifndef([_LT_AC_LANG_C_CONFIG], [AC_DEFUN([_LT_AC_LANG_C_CONFIG])])
m4_ifndef([AC_LIBTOOL_LANG_CXX_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_CXX_CONFIG])])
m4_ifndef([_LT_AC_LANG_CXX_CONFIG], [AC_DEFUN([_LT_AC_LANG_CXX_CONFIG])])
m4_ifndef([AC_LIBTOOL_LANG_F77_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_F77_CONFIG])])
m4_ifndef([_LT_AC_LANG_F77_CONFIG], [AC_DEFUN([_LT_AC_LANG_F77_CONFIG])])
m4_ifndef([AC_LIBTOOL_LANG_GCJ_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_GCJ_CONFIG])])
m4_ifndef([_LT_AC_LANG_GCJ_CONFIG], [AC_DEFUN([_LT_AC_LANG_GCJ_CONFIG])])
m4_ifndef([AC_LIBTOOL_LANG_RC_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_RC_CONFIG])])
m4_ifndef([_LT_AC_LANG_RC_CONFIG], [AC_DEFUN([_LT_AC_LANG_RC_CONFIG])])
m4_ifndef([AC_LIBTOOL_CONFIG], [AC_DEFUN([AC_LIBTOOL_CONFIG])])
m4_ifndef([_LT_AC_FILE_LTDLL_C], [AC_DEFUN([_LT_AC_FILE_LTDLL_C])])
m4_ifndef([_LT_REQUIRED_DARWIN_CHECKS], [AC_DEFUN([_LT_REQUIRED_DARWIN_CHECKS])])
m4_ifndef([_LT_AC_PROG_CXXCPP], [AC_DEFUN([_LT_AC_PROG_CXXCPP])])
m4_ifndef([_LT_PREPARE_SED_QUOTE_VARS], [AC_DEFUN([_LT_PREPARE_SED_QUOTE_VARS])])
m4_ifndef([_LT_PROG_ECHO_BACKSLASH], [AC_DEFUN([_LT_PROG_ECHO_BACKSLASH])])
m4_ifndef([_LT_PROG_F77], [AC_DEFUN([_LT_PROG_F77])])
m4_ifndef([_LT_PROG_FC], [AC_DEFUN([_LT_PROG_FC])])
m4_ifndef([_LT_PROG_CXX], [AC_DEFUN([_LT_PROG_CXX])])

331
missing Executable file
View File

@@ -0,0 +1,331 @@
#! /bin/sh
# Common stub for a few missing GNU programs while installing.
scriptversion=2012-01-06.13; # UTC
# Copyright (C) 1996, 1997, 1999, 2000, 2002, 2003, 2004, 2005, 2006,
# 2008, 2009, 2010, 2011, 2012 Free Software Foundation, Inc.
# Originally by Fran,cois Pinard <pinard@iro.umontreal.ca>, 1996.
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2, or (at your option)
# any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# As a special exception to the GNU General Public License, if you
# distribute this file as part of a program that contains a
# configuration script generated by Autoconf, you may include it under
# the same distribution terms that you use for the rest of that program.
if test $# -eq 0; then
echo 1>&2 "Try \`$0 --help' for more information"
exit 1
fi
run=:
sed_output='s/.* --output[ =]\([^ ]*\).*/\1/p'
sed_minuso='s/.* -o \([^ ]*\).*/\1/p'
# In the cases where this matters, `missing' is being run in the
# srcdir already.
if test -f configure.ac; then
configure_ac=configure.ac
else
configure_ac=configure.in
fi
msg="missing on your system"
case $1 in
--run)
# Try to run requested program, and just exit if it succeeds.
run=
shift
"$@" && exit 0
# Exit code 63 means version mismatch. This often happens
# when the user try to use an ancient version of a tool on
# a file that requires a minimum version. In this case we
# we should proceed has if the program had been absent, or
# if --run hadn't been passed.
if test $? = 63; then
run=:
msg="probably too old"
fi
;;
-h|--h|--he|--hel|--help)
echo "\
$0 [OPTION]... PROGRAM [ARGUMENT]...
Handle \`PROGRAM [ARGUMENT]...' for when PROGRAM is missing, or return an
error status if there is no known handling for PROGRAM.
Options:
-h, --help display this help and exit
-v, --version output version information and exit
--run try to run the given command, and emulate it if it fails
Supported PROGRAM values:
aclocal touch file \`aclocal.m4'
autoconf touch file \`configure'
autoheader touch file \`config.h.in'
autom4te touch the output file, or create a stub one
automake touch all \`Makefile.in' files
bison create \`y.tab.[ch]', if possible, from existing .[ch]
flex create \`lex.yy.c', if possible, from existing .c
help2man touch the output file
lex create \`lex.yy.c', if possible, from existing .c
makeinfo touch the output file
yacc create \`y.tab.[ch]', if possible, from existing .[ch]
Version suffixes to PROGRAM as well as the prefixes \`gnu-', \`gnu', and
\`g' are ignored when checking the name.
Send bug reports to <bug-automake@gnu.org>."
exit $?
;;
-v|--v|--ve|--ver|--vers|--versi|--versio|--version)
echo "missing $scriptversion (GNU Automake)"
exit $?
;;
-*)
echo 1>&2 "$0: Unknown \`$1' option"
echo 1>&2 "Try \`$0 --help' for more information"
exit 1
;;
esac
# normalize program name to check for.
program=`echo "$1" | sed '
s/^gnu-//; t
s/^gnu//; t
s/^g//; t'`
# Now exit if we have it, but it failed. Also exit now if we
# don't have it and --version was passed (most likely to detect
# the program). This is about non-GNU programs, so use $1 not
# $program.
case $1 in
lex*|yacc*)
# Not GNU programs, they don't have --version.
;;
*)
if test -z "$run" && ($1 --version) > /dev/null 2>&1; then
# We have it, but it failed.
exit 1
elif test "x$2" = "x--version" || test "x$2" = "x--help"; then
# Could not run --version or --help. This is probably someone
# running `$TOOL --version' or `$TOOL --help' to check whether
# $TOOL exists and not knowing $TOOL uses missing.
exit 1
fi
;;
esac
# If it does not exist, or fails to run (possibly an outdated version),
# try to emulate it.
case $program in
aclocal*)
echo 1>&2 "\
WARNING: \`$1' is $msg. You should only need it if
you modified \`acinclude.m4' or \`${configure_ac}'. You might want
to install the \`Automake' and \`Perl' packages. Grab them from
any GNU archive site."
touch aclocal.m4
;;
autoconf*)
echo 1>&2 "\
WARNING: \`$1' is $msg. You should only need it if
you modified \`${configure_ac}'. You might want to install the
\`Autoconf' and \`GNU m4' packages. Grab them from any GNU
archive site."
touch configure
;;
autoheader*)
echo 1>&2 "\
WARNING: \`$1' is $msg. You should only need it if
you modified \`acconfig.h' or \`${configure_ac}'. You might want
to install the \`Autoconf' and \`GNU m4' packages. Grab them
from any GNU archive site."
files=`sed -n 's/^[ ]*A[CM]_CONFIG_HEADER(\([^)]*\)).*/\1/p' ${configure_ac}`
test -z "$files" && files="config.h"
touch_files=
for f in $files; do
case $f in
*:*) touch_files="$touch_files "`echo "$f" |
sed -e 's/^[^:]*://' -e 's/:.*//'`;;
*) touch_files="$touch_files $f.in";;
esac
done
touch $touch_files
;;
automake*)
echo 1>&2 "\
WARNING: \`$1' is $msg. You should only need it if
you modified \`Makefile.am', \`acinclude.m4' or \`${configure_ac}'.
You might want to install the \`Automake' and \`Perl' packages.
Grab them from any GNU archive site."
find . -type f -name Makefile.am -print |
sed 's/\.am$/.in/' |
while read f; do touch "$f"; done
;;
autom4te*)
echo 1>&2 "\
WARNING: \`$1' is needed, but is $msg.
You might have modified some files without having the
proper tools for further handling them.
You can get \`$1' as part of \`Autoconf' from any GNU
archive site."
file=`echo "$*" | sed -n "$sed_output"`
test -z "$file" && file=`echo "$*" | sed -n "$sed_minuso"`
if test -f "$file"; then
touch $file
else
test -z "$file" || exec >$file
echo "#! /bin/sh"
echo "# Created by GNU Automake missing as a replacement of"
echo "# $ $@"
echo "exit 0"
chmod +x $file
exit 1
fi
;;
bison*|yacc*)
echo 1>&2 "\
WARNING: \`$1' $msg. You should only need it if
you modified a \`.y' file. You may need the \`Bison' package
in order for those modifications to take effect. You can get
\`Bison' from any GNU archive site."
rm -f y.tab.c y.tab.h
if test $# -ne 1; then
eval LASTARG=\${$#}
case $LASTARG in
*.y)
SRCFILE=`echo "$LASTARG" | sed 's/y$/c/'`
if test -f "$SRCFILE"; then
cp "$SRCFILE" y.tab.c
fi
SRCFILE=`echo "$LASTARG" | sed 's/y$/h/'`
if test -f "$SRCFILE"; then
cp "$SRCFILE" y.tab.h
fi
;;
esac
fi
if test ! -f y.tab.h; then
echo >y.tab.h
fi
if test ! -f y.tab.c; then
echo 'main() { return 0; }' >y.tab.c
fi
;;
lex*|flex*)
echo 1>&2 "\
WARNING: \`$1' is $msg. You should only need it if
you modified a \`.l' file. You may need the \`Flex' package
in order for those modifications to take effect. You can get
\`Flex' from any GNU archive site."
rm -f lex.yy.c
if test $# -ne 1; then
eval LASTARG=\${$#}
case $LASTARG in
*.l)
SRCFILE=`echo "$LASTARG" | sed 's/l$/c/'`
if test -f "$SRCFILE"; then
cp "$SRCFILE" lex.yy.c
fi
;;
esac
fi
if test ! -f lex.yy.c; then
echo 'main() { return 0; }' >lex.yy.c
fi
;;
help2man*)
echo 1>&2 "\
WARNING: \`$1' is $msg. You should only need it if
you modified a dependency of a manual page. You may need the
\`Help2man' package in order for those modifications to take
effect. You can get \`Help2man' from any GNU archive site."
file=`echo "$*" | sed -n "$sed_output"`
test -z "$file" && file=`echo "$*" | sed -n "$sed_minuso"`
if test -f "$file"; then
touch $file
else
test -z "$file" || exec >$file
echo ".ab help2man is required to generate this page"
exit $?
fi
;;
makeinfo*)
echo 1>&2 "\
WARNING: \`$1' is $msg. You should only need it if
you modified a \`.texi' or \`.texinfo' file, or any other file
indirectly affecting the aspect of the manual. The spurious
call might also be the consequence of using a buggy \`make' (AIX,
DU, IRIX). You might want to install the \`Texinfo' package or
the \`GNU make' package. Grab either from any GNU archive site."
# The file to touch is that specified with -o ...
file=`echo "$*" | sed -n "$sed_output"`
test -z "$file" && file=`echo "$*" | sed -n "$sed_minuso"`
if test -z "$file"; then
# ... or it is the one specified with @setfilename ...
infile=`echo "$*" | sed 's/.* \([^ ]*\) *$/\1/'`
file=`sed -n '
/^@setfilename/{
s/.* \([^ ]*\) *$/\1/
p
q
}' $infile`
# ... or it is derived from the source name (dir/f.texi becomes f.info)
test -z "$file" && file=`echo "$infile" | sed 's,.*/,,;s,.[^.]*$,,'`.info
fi
# If the file does not exist, the user really needs makeinfo;
# let's fail without touching anything.
test -f $file || exit 1
touch $file
;;
*)
echo 1>&2 "\
WARNING: \`$1' is needed, and is $msg.
You might have modified some files without having the
proper tools for further handling them. Check the \`README' file,
it often tells you about the needed prerequisites for installing
this package. You may also peek at any GNU archive site, in case
some other package would contain this missing \`$1' program."
exit 1
;;
esac
exit 0
# Local variables:
# eval: (add-hook 'write-file-hooks 'time-stamp)
# time-stamp-start: "scriptversion="
# time-stamp-format: "%:y-%02m-%02d.%02H"
# time-stamp-time-zone: "UTC"
# time-stamp-end: "; # UTC"
# End:

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, Nasel
* Copyright (c) 2012, Matias Fontanini
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -36,6 +36,7 @@
#include "rawpdu.h"
#include "constants.h"
#include "network_interface.h"
#include "exceptions.h"
using std::runtime_error;
@@ -59,7 +60,7 @@ ARP::ARP(ipaddress_type target_ip, ipaddress_type sender_ip,
ARP::ARP(const uint8_t *buffer, uint32_t total_sz)
{
if(total_sz < sizeof(arphdr))
throw runtime_error("Not enough size for an ARP header in the buffer.");
throw malformed_packet();
memcpy(&_arp, buffer, sizeof(arphdr));
total_sz -= sizeof(arphdr);
if(total_sz)
@@ -107,54 +108,41 @@ uint32_t ARP::header_size() const {
}
void ARP::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *) {
#ifdef TINS_DEBUG
assert(total_sz >= sizeof(arphdr));
#endif
memcpy(buffer, &_arp, sizeof(arphdr));
}
bool ARP::matches_response(uint8_t *ptr, uint32_t total_sz) {
bool ARP::matches_response(const uint8_t *ptr, uint32_t total_sz) const {
if(total_sz < sizeof(arphdr))
return false;
arphdr *arp_ptr = (arphdr*)ptr;
const arphdr *arp_ptr = (const arphdr*)ptr;
return arp_ptr->ar_sip == _arp.ar_tip && arp_ptr->ar_tip == _arp.ar_sip;
}
PDU *ARP::clone_packet(const uint8_t *ptr, uint32_t total_sz) {
if(total_sz < sizeof(arphdr))
return 0;
PDU *child = 0, *cloned;
if(total_sz > sizeof(arphdr)) {
child = PDU::clone_inner_pdu(ptr + sizeof(arphdr), total_sz - sizeof(arphdr));
if(!child)
return 0;
}
cloned = new ARP(ptr, std::min(total_sz, (uint32_t)sizeof(_arp)));
cloned->inner_pdu(child);
return cloned;
}
EthernetII ARP::make_arp_request(const NetworkInterface& iface,
ipaddress_type target, ipaddress_type sender, const hwaddress_type &hw_snd)
EthernetII ARP::make_arp_request(ipaddress_type target, ipaddress_type sender,
const hwaddress_type &hw_snd)
{
/* Create ARP packet and set its attributes */
ARP* arp = new ARP();
arp->target_ip_addr(target);
arp->sender_ip_addr(sender);
arp->sender_hw_addr(hw_snd);
arp->opcode(REQUEST);
ARP arp;
arp.target_ip_addr(target);
arp.sender_ip_addr(sender);
arp.sender_hw_addr(hw_snd);
arp.opcode(REQUEST);
/* Create the EthernetII PDU with the ARP PDU as its inner PDU */
return EthernetII(iface, EthernetII::BROADCAST, hw_snd, arp);
return EthernetII(EthernetII::BROADCAST, hw_snd) / arp;
}
EthernetII ARP::make_arp_reply(const NetworkInterface& iface,
ipaddress_type target, ipaddress_type sender, const hwaddress_type &hw_tgt,
const hwaddress_type &hw_snd)
EthernetII ARP::make_arp_reply(ipaddress_type target, ipaddress_type sender,
const hwaddress_type &hw_tgt, const hwaddress_type &hw_snd)
{
/* Create ARP packet and set its attributes */
ARP* arp = new ARP(target, sender, hw_tgt, hw_snd);
arp->opcode(REPLY);
ARP arp(target, sender, hw_tgt, hw_snd);
arp.opcode(REPLY);
/* Create the EthernetII PDU with the ARP PDU as its inner PDU */
return EthernetII(iface, hw_tgt, hw_snd, arp);
return EthernetII(hw_tgt, hw_snd) / arp;
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, Nasel
* Copyright (c) 2012, Matias Fontanini
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -31,6 +31,7 @@
#include <cstring>
#include <cassert>
#include "bootp.h"
#include "exceptions.h"
namespace Tins{
BootP::BootP()
@@ -42,7 +43,7 @@ BootP::BootP(const uint8_t *buffer, uint32_t total_sz, uint32_t vend_field_size)
: _vend(vend_field_size)
{
if(total_sz < sizeof(bootphdr) + vend_field_size)
throw std::runtime_error("Not enough size for a BootP header in the buffer.");
throw malformed_packet();
std::memcpy(&_bootp, buffer, sizeof(bootphdr));
buffer += sizeof(bootphdr);
total_sz -= sizeof(bootphdr);
@@ -113,8 +114,17 @@ void BootP::vend(const vend_type &new_vend) {
}
void BootP::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *parent) {
#ifdef TINS_DEBUG
assert(total_sz >= sizeof(bootphdr) + _vend.size());
#endif
std::memcpy(buffer, &_bootp, sizeof(bootphdr));
std::copy(_vend.begin(), _vend.end(), buffer + sizeof(bootphdr));
}
bool BootP::matches_response(const uint8_t *ptr, uint32_t total_sz) const {
if(total_sz < sizeof(bootphdr))
return false;
const bootphdr *bootp_ptr = (const bootphdr *)ptr;
return bootp_ptr->xid == _bootp.xid;
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, Nasel
* Copyright (c) 2012, Matias Fontanini
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, Nasel
* Copyright (c) 2012, Matias Fontanini
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -32,6 +32,7 @@
#include "endianness.h"
#include "dhcp.h"
#include "ethernetII.h"
#include "exceptions.h"
using std::string;
using std::list;
@@ -52,7 +53,7 @@ DHCP::DHCP(const uint8_t *buffer, uint32_t total_sz)
total_sz -= BootP::header_size() - vend().size();
uint8_t args[2] = {0};
if(total_sz < sizeof(uint32_t) || *(uint32_t*)buffer != Endian::host_to_be<uint32_t>(0x63825363))
throw std::runtime_error("Not enough size for a DHCP header in the buffer.");
throw malformed_packet();
buffer += sizeof(uint32_t);
total_sz -= sizeof(uint32_t);
while(total_sz) {
@@ -64,22 +65,28 @@ DHCP::DHCP(const uint8_t *buffer, uint32_t total_sz)
i = 2;
}
else if(!total_sz)
throw std::runtime_error("Not enough size for a DHCP header in the buffer.");
throw malformed_packet();
}
if(total_sz < args[1])
throw std::runtime_error("Not enough size for a DHCP header in the buffer.");
add_option(dhcp_option((Options)args[0], args[1], buffer));
throw malformed_packet();
add_option(
option((OptionTypes)args[0], args[1], buffer)
);
buffer += args[1];
total_sz -= args[1];
}
}
void DHCP::add_option(const dhcp_option &option) {
_options.push_back(option);
_size += option.data_size() + (sizeof(uint8_t) << 1);
void DHCP::add_option(const option &opt) {
internal_add_option(opt);
_options.push_back(opt);
}
const DHCP::dhcp_option *DHCP::search_option(Options opt) const {
void DHCP::internal_add_option(const option &opt) {
_size += opt.data_size() + (sizeof(uint8_t) << 1);
}
const DHCP::option *DHCP::search_option(OptionTypes opt) const {
for(options_type::const_iterator it = _options.begin(); it != _options.end(); ++it) {
if(it->option() == opt)
return &(*it);
@@ -89,11 +96,11 @@ const DHCP::dhcp_option *DHCP::search_option(Options opt) const {
void DHCP::type(Flags type) {
uint8_t int_type = type;
add_option(dhcp_option(DHCP_MESSAGE_TYPE, sizeof(uint8_t), &int_type));
add_option(option(DHCP_MESSAGE_TYPE, sizeof(uint8_t), &int_type));
}
void DHCP::end() {
add_option(dhcp_option(DHCP_MESSAGE_TYPE));
add_option(option(DHCP_MESSAGE_TYPE));
}
uint8_t DHCP::type() const {
@@ -102,7 +109,7 @@ uint8_t DHCP::type() const {
void DHCP::server_identifier(ipaddress_type ip) {
uint32_t ip_int = ip;
add_option(dhcp_option(DHCP_SERVER_IDENTIFIER, sizeof(uint32_t), (const uint8_t*)&ip_int));
add_option(option(DHCP_SERVER_IDENTIFIER, sizeof(uint32_t), (const uint8_t*)&ip_int));
}
DHCP::ipaddress_type DHCP::server_identifier() const {
@@ -111,7 +118,7 @@ DHCP::ipaddress_type DHCP::server_identifier() const {
void DHCP::lease_time(uint32_t time) {
time = Endian::host_to_be(time);
add_option(dhcp_option(DHCP_LEASE_TIME, sizeof(uint32_t), (const uint8_t*)&time));
add_option(option(DHCP_LEASE_TIME, sizeof(uint32_t), (const uint8_t*)&time));
}
uint32_t DHCP::lease_time() const {
@@ -120,7 +127,7 @@ uint32_t DHCP::lease_time() const {
void DHCP::renewal_time(uint32_t time) {
time = Endian::host_to_be(time);
add_option(dhcp_option(DHCP_RENEWAL_TIME, sizeof(uint32_t), (const uint8_t*)&time));
add_option(option(DHCP_RENEWAL_TIME, sizeof(uint32_t), (const uint8_t*)&time));
}
uint32_t DHCP::renewal_time() const {
@@ -129,7 +136,7 @@ uint32_t DHCP::renewal_time() const {
void DHCP::subnet_mask(ipaddress_type mask) {
uint32_t mask_int = mask;
add_option(dhcp_option(SUBNET_MASK, sizeof(uint32_t), (const uint8_t*)&mask_int));
add_option(option(SUBNET_MASK, sizeof(uint32_t), (const uint8_t*)&mask_int));
}
DHCP::ipaddress_type DHCP::subnet_mask() const {
@@ -138,7 +145,7 @@ DHCP::ipaddress_type DHCP::subnet_mask() const {
void DHCP::routers(const list<ipaddress_type> &routers) {
serialization_type buffer = serialize_list(routers);
add_option(dhcp_option(ROUTERS, buffer.begin(), buffer.end()));
add_option(option(ROUTERS, buffer.begin(), buffer.end()));
}
std::list<DHCP::ipaddress_type> DHCP::routers() const {
@@ -147,7 +154,7 @@ std::list<DHCP::ipaddress_type> DHCP::routers() const {
void DHCP::domain_name_servers(const list<ipaddress_type> &dns) {
serialization_type buffer = serialize_list(dns);
add_option(dhcp_option(DOMAIN_NAME_SERVERS, buffer.begin(), buffer.end()));
add_option(option(DOMAIN_NAME_SERVERS, buffer.begin(), buffer.end()));
}
std::list<DHCP::ipaddress_type> DHCP::domain_name_servers() const {
@@ -156,7 +163,7 @@ std::list<DHCP::ipaddress_type> DHCP::domain_name_servers() const {
void DHCP::broadcast(ipaddress_type addr) {
uint32_t int_addr = addr;
add_option(dhcp_option(BROADCAST_ADDRESS, sizeof(uint32_t), (uint8_t*)&int_addr));
add_option(option(BROADCAST_ADDRESS, sizeof(uint32_t), (uint8_t*)&int_addr));
}
DHCP::ipaddress_type DHCP::broadcast() const {
@@ -165,7 +172,7 @@ DHCP::ipaddress_type DHCP::broadcast() const {
void DHCP::requested_ip(ipaddress_type addr) {
uint32_t int_addr = addr;
add_option(dhcp_option(DHCP_REQUESTED_ADDRESS, sizeof(uint32_t), (uint8_t*)&int_addr));
add_option(option(DHCP_REQUESTED_ADDRESS, sizeof(uint32_t), (uint8_t*)&int_addr));
}
DHCP::ipaddress_type DHCP::requested_ip() const {
@@ -173,7 +180,7 @@ DHCP::ipaddress_type DHCP::requested_ip() const {
}
void DHCP::domain_name(const string &name) {
add_option(dhcp_option(DOMAIN_NAME, name.size(), (const uint8_t*)name.c_str()));
add_option(option(DOMAIN_NAME, name.size(), (const uint8_t*)name.c_str()));
}
std::string DHCP::domain_name() const {
@@ -182,7 +189,7 @@ std::string DHCP::domain_name() const {
void DHCP::rebind_time(uint32_t time) {
time = Endian::host_to_be(time);
add_option(dhcp_option(DHCP_REBINDING_TIME, sizeof(uint32_t), (uint8_t*)&time));
add_option(option(DHCP_REBINDING_TIME, sizeof(uint32_t), (uint8_t*)&time));
}
uint32_t DHCP::rebind_time() const {
@@ -202,7 +209,9 @@ uint32_t DHCP::header_size() const {
}
void DHCP::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *parent) {
#ifdef TINS_DEBUG
assert(total_sz >= header_size());
#endif
if(_size) {
vend_type &result(BootP::vend());
result.resize(_size);
@@ -211,7 +220,7 @@ void DHCP::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *pa
*((uint32_t*)&result[0]) = Endian::host_to_be<uint32_t>(0x63825363);
for(options_type::const_iterator it = _options.begin(); it != _options.end(); ++it) {
*(ptr++) = it->option();
*(ptr++) = it->data_size();
*(ptr++) = it->length_field();
std::copy(it->data_ptr(), it->data_ptr() + it->data_size(), ptr);
ptr += it->data_size();
}
@@ -219,12 +228,12 @@ 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(Options opt, type2type<std::list<ipaddress_type> >) const {
const dhcp_option *option = search_option(opt);
if(!option)
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*)option->data_ptr();
uint32_t len = option->data_size();
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;
@@ -235,14 +244,14 @@ std::list<DHCP::ipaddress_type> DHCP::generic_search(Options opt, type2type<std:
return container;
}
std::string DHCP::generic_search(Options opt, type2type<std::string>) const {
const dhcp_option *option = search_option(opt);
if(!option)
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(option->data_ptr(), option->data_ptr() + option->data_size());
return string(opt->data_ptr(), opt->data_ptr() + opt->data_size());
}
DHCP::ipaddress_type DHCP::generic_search(Options opt, type2type<ipaddress_type>) const {
DHCP::ipaddress_type DHCP::generic_search(OptionTypes opt, type2type<ipaddress_type>) const {
return ipaddress_type(generic_search(opt, type2type<uint32_t>()));
}
}

653
src/dhcpv6.cpp Normal file
View File

@@ -0,0 +1,653 @@
/*
* 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 <vector>
#include <algorithm>
#include "dhcpv6.h"
#include "exceptions.h"
namespace Tins {
DHCPv6::DHCPv6() : options_size() {
std::fill(header_data, header_data + sizeof(header_data), 0);
}
DHCPv6::DHCPv6(const uint8_t *buffer, uint32_t total_sz)
: options_size()
{
if(total_sz == 0)
throw malformed_packet();
// Relay Agent/Server Messages
bool is_relay_msg = (buffer[0] == 12 || buffer[0] == 13);
uint32_t required_size = is_relay_msg ? 2 : 4;
if(total_sz < required_size)
throw malformed_packet();
std::copy(buffer, buffer + required_size, header_data);
buffer += required_size;
total_sz -= required_size;
if(is_relay_message()) {
if(total_sz < ipaddress_type::address_size * 2)
throw malformed_packet();
link_addr = buffer;
peer_addr = buffer + ipaddress_type::address_size;
buffer += ipaddress_type::address_size * 2;
total_sz -= ipaddress_type::address_size * 2;
}
options_size = total_sz;
while(total_sz) {
if(total_sz < sizeof(uint16_t) * 2)
throw malformed_packet();
const uint16_t opt = Endian::be_to_host(*(const uint16_t*)buffer);
const uint16_t data_size = Endian::be_to_host(
*(const uint16_t*)(buffer + sizeof(uint16_t))
);
if(total_sz - sizeof(uint16_t) * 2 < data_size)
throw malformed_packet();
buffer += sizeof(uint16_t) * 2;
add_option(
option(opt, buffer, buffer + data_size)
);
buffer += data_size;
total_sz -= sizeof(uint16_t) * 2 + data_size;
}
}
void DHCPv6::add_option(const option &opt) {
options_.push_back(opt);
}
const DHCPv6::option *DHCPv6::search_option(OptionTypes id) const {
for(options_type::const_iterator it = options_.begin(); it != options_.end(); ++it) {
if(it->option() == static_cast<uint16_t>(id))
return &*it;
}
return 0;
}
uint8_t* DHCPv6::write_option(const option &opt, uint8_t* buffer) const {
*(uint16_t*)buffer = Endian::host_to_be(opt.option());
*(uint16_t*)&buffer[sizeof(uint16_t)] = Endian::host_to_be<uint16_t>(opt.length_field());
return std::copy(
opt.data_ptr(),
opt.data_ptr() + opt.data_size(),
buffer + sizeof(uint16_t) * 2
);
}
void DHCPv6::msg_type(MessageType type) {
header_data[0] = static_cast<uint8_t>(type);
}
void DHCPv6::hop_count(uint8_t count) {
header_data[1] = count;
}
void DHCPv6::transaction_id(small_uint<24> id) {
uint32_t id_32 = id;
header_data[1] = id_32 >> 16;
header_data[2] = id_32 >> 8;
header_data[3] = id_32 & 0xff;
}
void DHCPv6::peer_address(const ipaddress_type &addr) {
peer_addr = addr;
}
void DHCPv6::link_address(const ipaddress_type &addr) {
link_addr = addr;
}
bool DHCPv6::is_relay_message() const {
return msg_type() == 12 || msg_type() == 13;
}
uint32_t DHCPv6::header_size() const {
return (is_relay_message() ? (2 + ipaddress_type::address_size * 2) : 4) + options_size;
}
bool DHCPv6::matches_response(const uint8_t *ptr, uint32_t total_sz) const {
if(!is_relay_message()) {
if(total_sz < 4 || (ptr[0] == 12 || ptr[0] == 13))
return false;
return std::equal(header_data + 1, header_data + 4, ptr + 1);
}
return false;
}
void DHCPv6::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *) {
const uint32_t required_size = is_relay_message() ? 2 : 4;
buffer = std::copy(header_data, header_data + required_size, buffer);
if(is_relay_message()) {
buffer = link_addr.copy(buffer);
buffer = peer_addr.copy(buffer);
}
for(options_type::const_iterator it = options_.begin(); it != options_.end(); ++it)
buffer = write_option(*it, buffer);
}
// ********************************************************************
// Option getters
// ********************************************************************
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;
}
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;
}
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;
}
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;
}
uint8_t DHCPv6::preference() const {
const option *opt = safe_search_option<std::not_equal_to>(
PREFERENCE, 1
);
return *opt->data_ptr();
}
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()
);
}
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()
);
}
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;
}
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());
}
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;
}
bool DHCPv6::has_rapid_commit() const {
return search_option(RAPID_COMMIT);
}
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()
);
}
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;
}
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;
}
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()
);
}
uint8_t DHCPv6::reconfigure_msg() const {
return *safe_search_option<std::not_equal_to>(
RECONF_MSG, 1
)->data_ptr();
}
bool DHCPv6::has_reconfigure_accept() const {
return search_option(RECONF_ACCEPT);
}
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()
)
);
}
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()
)
);
}
// ********************************************************************
// Option setters
// ********************************************************************
void DHCPv6::ia_na(const ia_na_type &value) {
std::vector<uint8_t> buffer(sizeof(uint32_t) * 3 + value.options.size());
uint32_t *ptr = (uint32_t*)&buffer[0];
*ptr++ = Endian::host_to_be(value.id);
*ptr++ = Endian::host_to_be(value.t1);
*ptr++ = Endian::host_to_be(value.t2);
std::copy(
value.options.begin(),
value.options.end(),
buffer.begin() + sizeof(uint32_t) * 3
);
add_option(
option(IA_NA, buffer.begin(), buffer.end())
);
}
void DHCPv6::ia_ta(const ia_ta_type &value) {
std::vector<uint8_t> buffer(sizeof(uint32_t) + value.options.size());
uint32_t *ptr = (uint32_t*)&buffer[0];
*ptr++ = Endian::host_to_be(value.id);
std::copy(
value.options.begin(),
value.options.end(),
buffer.begin() + sizeof(uint32_t)
);
add_option(
option(IA_TA, buffer.begin(), buffer.end())
);
}
void DHCPv6::ia_address(const ia_address_type &value) {
std::vector<uint8_t> buffer(
sizeof(uint32_t) * 2 + ipaddress_type::address_size + value.options.size()
);
uint32_t *ptr = (uint32_t*)&buffer[ipaddress_type::address_size];
value.address.copy(&buffer[0]);
*ptr++ = Endian::host_to_be(value.preferred_lifetime);
*ptr++ = Endian::host_to_be(value.valid_lifetime);
std::copy(
value.options.begin(),
value.options.end(),
buffer.begin() + sizeof(uint32_t) * 2 + ipaddress_type::address_size
);
add_option(
option(IA_ADDR, buffer.begin(), buffer.end())
);
}
void DHCPv6::option_request(const option_request_type &value) {
typedef option_request_type::const_iterator iterator;
std::vector<uint8_t> buffer(value.size() * sizeof(uint16_t));
size_t index = 0;
for(iterator it = value.begin(); it != value.end(); ++it, index += 2)
*(uint16_t*)&buffer[index] = Endian::host_to_be<uint16_t>(*it);
add_option(
option(OPTION_REQUEST, buffer.begin(), buffer.end())
);
}
void DHCPv6::preference(uint8_t value) {
add_option(
option(PREFERENCE, 1, &value)
);
}
void DHCPv6::elapsed_time(uint16_t value) {
value = Endian::host_to_be(value);
add_option(
option(ELAPSED_TIME, 2, (const uint8_t*)&value)
);
}
void DHCPv6::relay_message(const relay_msg_type &value) {
add_option(
option(RELAY_MSG, value.begin(), value.end())
);
}
void DHCPv6::authentication(const authentication_type &value) {
std::vector<uint8_t> buffer(
sizeof(uint8_t) * 3 + sizeof(uint64_t) + value.auth_info.size()
);
buffer[0] = value.protocol;
buffer[1] = value.algorithm;
buffer[2] = value.rdm;
*(uint64_t*)&buffer[3] = Endian::host_to_be(value.replay_detection);
std::copy(
value.auth_info.begin(),
value.auth_info.end(),
buffer.begin() + sizeof(uint8_t) * 3 + sizeof(uint64_t)
);
add_option(
option(AUTH, buffer.begin(), buffer.end())
);
}
void DHCPv6::server_unicast(const ipaddress_type &value) {
add_option(
option(UNICAST, value.begin(), value.end())
);
}
void DHCPv6::status_code(const status_code_type &value) {
std::vector<uint8_t> buffer(sizeof(uint16_t) + value.message.size());
*(uint16_t*)&buffer[0] = Endian::host_to_be(value.code);
std::copy(
value.message.begin(),
value.message.end(),
buffer.begin() + sizeof(uint16_t)
);
add_option(
option(STATUS_CODE, buffer.begin(), buffer.end())
);
}
void DHCPv6::rapid_commit() {
add_option(
RAPID_COMMIT
);
}
void DHCPv6::user_class(const user_class_type &value) {
typedef user_class_type::const_iterator iterator;
std::vector<uint8_t> buffer;
class_option_data2option(value.begin(), value.end(), buffer);
add_option(
option(USER_CLASS, buffer.begin(), buffer.end())
);
}
void DHCPv6::vendor_class(const vendor_class_type &value) {
std::vector<uint8_t> buffer(
sizeof(uint32_t)
);
*(uint32_t*)&buffer[0] = Endian::host_to_be(value.enterprise_number);
class_option_data2option(
value.vendor_class_data.begin(),
value.vendor_class_data.end(),
buffer,
sizeof(uint32_t)
);
add_option(
option(VENDOR_CLASS, buffer.begin(), buffer.end())
);
}
void DHCPv6::vendor_info(const vendor_info_type &value) {
std::vector<uint8_t> buffer(sizeof(uint32_t) + value.data.size());
*(uint32_t*)&buffer[0] = Endian::host_to_be(value.enterprise_number);
std::copy(
value.data.begin(),
value.data.end(),
buffer.begin() + sizeof(uint32_t)
);
add_option(
option(VENDOR_OPTS, buffer.begin(), buffer.end())
);
}
void DHCPv6::interface_id(const interface_id_type &value) {
add_option(
option(INTERFACE_ID, value.begin(), value.end())
);
}
void DHCPv6::reconfigure_msg(uint8_t value) {
add_option(
option(RECONF_MSG, 1, &value)
);
}
void DHCPv6::reconfigure_accept() {
add_option(RECONF_ACCEPT);
}
// DUIDs
DHCPv6::duid_llt DHCPv6::duid_llt::from_bytes(const uint8_t *buffer, uint32_t total_sz)
{
// at least one byte for lladdress
if(total_sz < sizeof(uint16_t) + sizeof(uint32_t) + 1)
throw std::runtime_error("Not enough size for a DUID_LLT identifier");
duid_llt output;
output.hw_type = Endian::be_to_host(*(const uint16_t*)buffer);
buffer += sizeof(uint16_t);
output.time = Endian::be_to_host(*(const uint32_t*)buffer);
buffer += sizeof(uint32_t);
total_sz -= sizeof(uint16_t) + sizeof(uint32_t);
output.lladdress.assign(buffer, buffer + total_sz);
return output;
}
PDU::serialization_type DHCPv6::duid_llt::serialize() const {
serialization_type output(sizeof(uint16_t) + sizeof(uint32_t) + lladdress.size());
*(uint16_t*)&output[0] = Endian::host_to_be(hw_type);
*(uint32_t*)&output[sizeof(uint16_t)] = Endian::host_to_be(time);
std::copy(
lladdress.begin(),
lladdress.end(),
output.begin() + sizeof(uint16_t) + sizeof(uint32_t)
);
return output;
}
DHCPv6::duid_en DHCPv6::duid_en::from_bytes(const uint8_t *buffer, uint32_t total_sz)
{
// at least one byte for identifier
if(total_sz < sizeof(uint32_t) + 1)
throw std::runtime_error("Not enough size for a DUID_en identifier");
duid_en output;
output.enterprise_number = Endian::be_to_host(*(const uint32_t*)buffer);
buffer += sizeof(uint32_t);
total_sz -= sizeof(uint32_t);
output.identifier.assign(buffer, buffer + total_sz);
return output;
}
PDU::serialization_type DHCPv6::duid_en::serialize() const {
serialization_type output(sizeof(uint32_t) + identifier.size());
*(uint32_t*)&output[0] = Endian::host_to_be(enterprise_number);
std::copy(
identifier.begin(),
identifier.end(),
output.begin() + sizeof(uint32_t)
);
return output;
}
DHCPv6::duid_ll DHCPv6::duid_ll::from_bytes(const uint8_t *buffer, uint32_t total_sz)
{
// at least one byte for lladdress
if(total_sz < sizeof(uint16_t) + 1)
throw std::runtime_error("Not enough size for a DUID_en identifier");
duid_ll output;
output.hw_type = Endian::be_to_host(*(const uint16_t*)buffer);
buffer += sizeof(uint16_t);
total_sz -= sizeof(uint16_t);
output.lladdress.assign(buffer, buffer + total_sz);
return output;
}
PDU::serialization_type DHCPv6::duid_ll::serialize() const {
serialization_type output(sizeof(uint16_t) + lladdress.size());
*(uint16_t*)&output[0] = Endian::host_to_be(hw_type);
std::copy(
lladdress.begin(),
lladdress.end(),
output.begin() + sizeof(uint16_t)
);
return output;
}
void DHCPv6::client_id(const duid_type &value) {
serialization_type buffer(sizeof(uint16_t) + value.data.size());
*(uint16_t*)&buffer[0] = Endian::host_to_be(value.id);
std::copy(
value.data.begin(),
value.data.end(),
buffer.begin() + sizeof(uint16_t)
);
add_option(
option(CLIENTID, buffer.begin(), buffer.end())
);
}
void DHCPv6::server_id(const duid_type &value) {
serialization_type buffer(sizeof(uint16_t) + value.data.size());
*(uint16_t*)&buffer[0] = Endian::host_to_be(value.id);
std::copy(
value.data.begin(),
value.data.end(),
buffer.begin() + sizeof(uint16_t)
);
add_option(
option(SERVERID, buffer.begin(), buffer.end())
);
}
} // namespace Tins

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, Nasel
* Copyright (c) 2012, Matias Fontanini
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -30,9 +30,13 @@
#include <utility>
#include <stdexcept>
#include <cassert>
#include <sstream>
#include <memory>
#include "dns.h"
#include "ip_address.h"
#include "ipv6_address.h"
#include "exceptions.h"
#include "rawpdu.h"
using std::string;
using std::list;
@@ -45,7 +49,7 @@ DNS::DNS() : extra_size(0) {
DNS::DNS(const uint8_t *buffer, uint32_t total_sz) : extra_size(0) {
if(total_sz < sizeof(dnshdr))
throw std::runtime_error("Not enough size for a DNS header in the buffer.");
throw malformed_packet();
std::memcpy(&dns, buffer, sizeof(dnshdr));
const uint8_t *end(buffer + total_sz);
uint16_t nquestions(questions_count());
@@ -57,7 +61,7 @@ DNS::DNS(const uint8_t *buffer, uint32_t total_sz) : extra_size(0) {
ptr++;
Query query;
if((ptr + (sizeof(uint16_t) * 2)) >= end)
throw std::runtime_error("Not enough size for a given query.");
throw malformed_packet();
query.dname(string(buffer, ptr));
ptr++;
const uint16_t *opt_ptr = reinterpret_cast<const uint16_t*>(ptr);
@@ -71,6 +75,8 @@ DNS::DNS(const uint8_t *buffer, uint32_t total_sz) : extra_size(0) {
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));
}
const uint8_t *DNS::build_resource_list(ResourcesType &lst, const uint8_t *ptr, uint32_t &sz, uint16_t nrecs) {
@@ -79,7 +85,7 @@ const uint8_t *DNS::build_resource_list(ResourcesType &lst, const uint8_t *ptr,
for(uint16_t i(0); i < nrecs; ++i) {
const uint8_t *this_opt_start(ptr);
if(ptr + sizeof(uint16_t) > ptr_end)
throw std::runtime_error("Not enough size for a given resource.");
throw malformed_packet();
lst.push_back(DNSResourceRecord(ptr, ptr_end - ptr));
ptr += lst.back().size();
extra_size += ptr - this_opt_start;
@@ -165,6 +171,13 @@ void DNS::add_answer(const string &name, const DNSResourceRecord::info &info,
dns.answers = Endian::host_to_be<uint16_t>(ans.size());
}
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)
{
@@ -281,7 +294,9 @@ void DNS::unparse_domain_name(const std::string &dn, std::string &out) const {
}
void DNS::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *parent) {
#ifdef TINS_DEBUG
assert(total_sz >= sizeof(dns) + extra_size);
#endif
std::memcpy(buffer, &dns, sizeof(dns));
buffer += sizeof(dns);
for(list<Query>::const_iterator it(queries_.begin()); it != queries_.end(); ++it) {
@@ -326,7 +341,7 @@ void DNS::add_suffix(uint32_t index, const uint8_t *data, uint32_t sz) const {
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->dname();
str = it->has_domain_name() ? it->dname() : 0;
if(str) {
add_suffix(index, (uint8_t*)str->c_str(), str->size());
index += str->size() + 1;
@@ -374,8 +389,10 @@ void DNS::compose_name(const uint8_t *ptr, uint32_t sz, std::string &out) const
index &= 0x3fff;
SuffixMap::iterator it(suffixes.find(index));
SuffixIndices::iterator suff_it(suffix_indices.find(index));
if(it == suffixes.end() || suff_it == suffix_indices.end())
throw std::runtime_error("Malformed DNS packet");
// 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()) {
@@ -427,7 +444,13 @@ void DNS::convert_resources(const ResourcesType &lst, std::list<Resource> &res)
ptr += 2;
sz -= 2;
}
compose_name(ptr, sz, addr);
if(Endian::be_to_host(it->information().type) == DNS::AAAA) {
if(sz != 16)
throw std::runtime_error("Malformed IPv6 address");
addr = IPv6Address(ptr).to_string();
}
else
compose_name(ptr, sz, addr);
}
res.push_back(
Resource(dname, addr, Endian::be_to_host(it->information().type),
@@ -459,4 +482,11 @@ DNS::resources_type DNS::answers() const {
convert_resources(ans, res);
return res;
}
bool DNS::matches_response(const uint8_t *ptr, uint32_t total_sz) const {
if(total_sz < sizeof(dnshdr))
return false;
const dnshdr *hdr = (const dnshdr*)ptr;
return hdr->id == dns.id;
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, Nasel
* Copyright (c) 2012, Matias Fontanini
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -33,12 +33,15 @@
#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 == 15 || type == 5 ||
type == 12 || type == 2;
return type == 1 || type == 2 ||
type == 5 || type == 6 ||
type == 12 || type == 15 ||
type == 28 || type == 41;
}
DNSResourceRecord::DNSResourceRecord(DNSRRImpl *impl,
@@ -51,7 +54,7 @@ DNSResourceRecord::DNSResourceRecord(DNSRRImpl *impl,
DNSResourceRecord::DNSResourceRecord(const uint8_t *buffer, uint32_t size)
{
const uint8_t *buffer_end = buffer + size;
std::auto_ptr<DNSRRImpl> tmp_impl;
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;
@@ -63,17 +66,17 @@ DNSResourceRecord::DNSResourceRecord(const uint8_t *buffer, uint32_t size)
while(str_end < buffer_end && *str_end)
str_end++;
if(str_end == buffer_end)
throw std::runtime_error("Not enough size for a resource domain name.");
throw malformed_packet();
//str_end++;
tmp_impl.reset(new NamedDNSRRImpl(buffer, str_end));
buffer = ++str_end;
}
if(buffer + sizeof(info_) > buffer_end)
throw std::runtime_error("Not enough size for a resource info.");
throw malformed_packet();
std::memcpy(&info_, buffer, sizeof(info_));
buffer += sizeof(info_);
if(buffer + sizeof(uint16_t) > buffer_end)
throw std::runtime_error("Not enough size for resource data size.");
throw malformed_packet();
// Store the option size.
data.resize(
@@ -81,13 +84,11 @@ DNSResourceRecord::DNSResourceRecord(const uint8_t *buffer, uint32_t size)
);
buffer += sizeof(uint16_t);
if(buffer + data.size() > buffer_end)
throw std::runtime_error("Not enough size for resource data");
if(contains_dname(info_.type))
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;
else
throw std::runtime_error("Not enough size for resource data");
impl = tmp_impl.release();
}
@@ -156,7 +157,7 @@ bool DNSResourceRecord::matches(const std::string &dname) const {
// OffsetedRecord
OffsetedDNSRRImpl::OffsetedDNSRRImpl(uint16_t off)
: offset_(off | 0xc0)
: offset_(off | Endian::host_to_be<uint16_t>(0xc000))
{
}
@@ -191,7 +192,8 @@ uint32_t NamedDNSRRImpl::size() const {
}
uint32_t NamedDNSRRImpl::do_write(uint8_t *buffer) const {
std::copy(name.begin(), name.end() + 1, buffer);
buffer = std::copy(name.begin(), name.end(), buffer);
*buffer = 0;
return name.size() + 1;
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, Nasel
* Copyright (c) 2012, Matias Fontanini
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -32,9 +32,17 @@
#include <stdexcept>
#include <algorithm>
#include <utility>
#include "macros.h"
#include "exceptions.h"
#ifndef WIN32
#if defined(__FreeBSD_kernel__) || defined(BSD) || defined(__APPLE__)
#include <sys/types.h>
#include <net/if_dl.h>
#else
#include <netpacket/packet.h>
#endif
#include <net/ethernet.h>
#include <netpacket/packet.h>
#include <netinet/in.h>
#endif
#include "dot11.h"
@@ -52,8 +60,8 @@ using std::runtime_error;
namespace Tins {
const Dot11::address_type Dot11::BROADCAST = "ff:ff:ff:ff:ff:ff";
Dot11::Dot11(const address_type &dst_hw_addr, PDU* child)
: PDU(child), _options_size(0)
Dot11::Dot11(const address_type &dst_hw_addr)
: _options_size(0)
{
memset(&_header, 0, sizeof(ieee80211_header));
addr1(dst_hw_addr);
@@ -68,7 +76,7 @@ Dot11::Dot11(const uint8_t *buffer, uint32_t total_sz)
: _options_size(0)
{
if(total_sz < sizeof(_header))
throw runtime_error("Not enough size for an Dot11 header in the buffer.");
throw malformed_packet();
std::memcpy(&_header, buffer, sizeof(_header));
}
@@ -81,28 +89,32 @@ void Dot11::parse_tagged_parameters(const uint8_t *buffer, uint32_t total_sz) {
buffer += 2;
total_sz -= 2;
if(length > total_sz) {
throw std::runtime_error("Malformed option encountered");
throw malformed_packet();
}
add_tagged_option((TaggedOption)opcode, length, buffer);
add_tagged_option((OptionTypes)opcode, length, buffer);
buffer += length;
total_sz -= length;
}
}
}
void Dot11::add_tagged_option(TaggedOption opt, uint8_t len, const uint8_t *val) {
void Dot11::add_tagged_option(OptionTypes opt, uint8_t len, const uint8_t *val) {
uint32_t opt_size = len + sizeof(uint8_t) * 2;
_options.push_back(dot11_option((uint8_t)opt, len, val));
_options.push_back(option((uint8_t)opt, len, val));
_options_size += opt_size;
}
void Dot11::add_tagged_option(const dot11_option &opt) {
_options.push_back(opt);
void Dot11::internal_add_option(const option &opt) {
_options_size += opt.data_size() + sizeof(uint8_t) * 2;
}
const Dot11::dot11_option *Dot11::search_option(TaggedOption opt) const {
for(std::list<dot11_option>::const_iterator it = _options.begin(); it != _options.end(); ++it)
void Dot11::add_option(const option &opt) {
internal_add_option(opt);
_options.push_back(opt);
}
const Dot11::option *Dot11::search_option(OptionTypes opt) const {
for(std::list<option>::const_iterator it = _options.begin(); it != _options.end(); ++it)
if(it->option() == (uint8_t)opt)
return &(*it);
return 0;
@@ -156,37 +168,37 @@ void Dot11::addr1(const address_type &new_addr1) {
std::copy(new_addr1.begin(), new_addr1.end(), _header.addr1);
}
void Dot11::iface(const NetworkInterface &new_iface) {
this->_iface = new_iface;
}
uint32_t Dot11::header_size() const {
uint32_t sz = sizeof(ieee80211_header) + _options_size;
return sz;
}
#ifndef WIN32
void Dot11::send(PacketSender &sender) {
if(!_iface)
throw std::runtime_error("Interface has not been set");
void Dot11::send(PacketSender &sender, const NetworkInterface &iface) {
if(!iface)
throw invalid_interface();
struct sockaddr_ll addr;
#if !defined(BSD) && !defined(__FreeBSD_kernel__)
sockaddr_ll addr;
memset(&addr, 0, sizeof(struct sockaddr_ll));
memset(&addr, 0, sizeof(struct sockaddr_ll));
addr.sll_family = Endian::host_to_be<uint16_t>(PF_PACKET);
addr.sll_protocol = Endian::host_to_be<uint16_t>(ETH_P_ALL);
addr.sll_halen = 6;
addr.sll_ifindex = _iface.id();
memcpy(&(addr.sll_addr), _header.addr1, 6);
sender.send_l2(*this, (struct sockaddr*)&addr, (uint32_t)sizeof(addr));
addr.sll_family = Endian::host_to_be<uint16_t>(PF_PACKET);
addr.sll_protocol = Endian::host_to_be<uint16_t>(ETH_P_ALL);
addr.sll_halen = 6;
addr.sll_ifindex = iface.id();
memcpy(&(addr.sll_addr), _header.addr1, 6);
sender.send_l2(*this, (struct sockaddr*)&addr, (uint32_t)sizeof(addr));
#else
sender.send_l2(*this, 0, 0, iface);
#endif
}
#endif // WIN32
void Dot11::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *parent) {
uint32_t my_sz = header_size();
assert(total_sz >= my_sz);
#ifdef TINS_DEBUG
assert(total_sz >= header_size());
#endif
memcpy(buffer, &_header, sizeof(_header));
buffer += sizeof(_header);
total_sz -= sizeof(_header);
@@ -197,10 +209,12 @@ void Dot11::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *p
uint32_t child_len = write_fixed_parameters(buffer, total_sz - _options_size);
buffer += child_len;
#ifdef TINS_DEBUG
assert(total_sz >= child_len + _options_size);
for(std::list<dot11_option>::const_iterator it = _options.begin(); it != _options.end(); ++it) {
#endif
for(std::list<option>::const_iterator it = _options.begin(); it != _options.end(); ++it) {
*(buffer++) = it->option();
*(buffer++) = it->data_size();
*(buffer++) = it->length_field();
std::copy(it->data_ptr(), it->data_ptr() + it->data_size(), buffer);
buffer += it->data_size();
}
@@ -208,8 +222,10 @@ void Dot11::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *p
Dot11 *Dot11::from_bytes(const uint8_t *buffer, uint32_t total_sz) {
// We only need the control field, the length of the PDU will depend on the flags set.
if(total_sz < sizeof(ieee80211_header::control))
throw runtime_error("Not enough size for a IEEE 802.11 header in the buffer.");
// This should be sizeof(ieee80211_header::control), but gcc 4.2 complains
if(total_sz < 2)
throw malformed_packet();
const ieee80211_header *hdr = (const ieee80211_header*)buffer;
Dot11 *ret = 0;
if(hdr->control.type == MANAGEMENT) {
@@ -268,14 +284,14 @@ Dot11ManagementFrame::Dot11ManagementFrame(const uint8_t *buffer, uint32_t total
buffer += sizeof(ieee80211_header);
total_sz -= sizeof(ieee80211_header);
if(total_sz < sizeof(_ext_header))
throw runtime_error("Not enough size for an Dot11ManagementFrame header in the buffer.");
throw malformed_packet();
std::memcpy(&_ext_header, buffer, sizeof(_ext_header));
total_sz -= sizeof(_ext_header);
if(from_ds() && to_ds()) {
if(total_sz >= _addr4.size())
_addr4 = buffer + sizeof(_ext_header);
else
throw runtime_error("Not enough size for an Dot11ManagementFrame header in the buffer.");
throw malformed_packet();
}
}
@@ -354,9 +370,9 @@ uint8_t *Dot11ManagementFrame::serialize_rates(const rates_type &rates) {
return buffer;
}
Dot11ManagementFrame::rates_type Dot11ManagementFrame::deserialize_rates(const dot11_option *option) {
Dot11ManagementFrame::rates_type Dot11ManagementFrame::deserialize_rates(const option *opt) {
rates_type output;
const uint8_t *ptr = option->data_ptr(), *end = ptr + option->data_size();
const uint8_t *ptr = opt->data_ptr(), *end = ptr + opt->data_size();
while(ptr != end) {
output.push_back(float(*(ptr++) & 0x7f) / 2);
}
@@ -586,52 +602,52 @@ void Dot11ManagementFrame::challenge_text(const std::string &text) {
// Getters
RSNInformation Dot11ManagementFrame::rsn_information() {
const Dot11::dot11_option *option = search_option(RSN);
const Dot11::option *option = search_option(RSN);
if(!option || option->data_size() < (sizeof(uint16_t) << 1) + sizeof(uint32_t))
throw std::runtime_error("RSN information not set");
throw option_not_found();
return RSNInformation(option->data_ptr(), option->data_size());
}
string Dot11ManagementFrame::ssid() const {
const Dot11::dot11_option *option = search_option(SSID);
const Dot11::option *option = search_option(SSID);
if(!option || option->data_size() == 0)
throw std::runtime_error("SSID not set");
throw option_not_found();
return string((const char*)option->data_ptr(), option->data_size());
}
Dot11ManagementFrame::rates_type Dot11ManagementFrame::supported_rates() const {
const Dot11::dot11_option *option = search_option(SUPPORTED_RATES);
const Dot11::option *option = search_option(SUPPORTED_RATES);
if(!option || option->data_size() == 0)
throw std::runtime_error("Supported rates not set");
throw option_not_found();
return deserialize_rates(option);
}
Dot11ManagementFrame::rates_type Dot11ManagementFrame::extended_supported_rates() const {
const Dot11::dot11_option *option = search_option(EXT_SUPPORTED_RATES);
const Dot11::option *option = search_option(EXT_SUPPORTED_RATES);
if(!option || option->data_size() == 0)
throw std::runtime_error("Extended supported rates not set");
throw option_not_found();
return deserialize_rates(option);
}
uint8_t Dot11ManagementFrame::qos_capability() const {
const Dot11::dot11_option *option = search_option(QOS_CAPABILITY);
const Dot11::option *option = search_option(QOS_CAPABILITY);
if(!option || option->data_size() != 1)
throw std::runtime_error("QOS capability not set");
throw option_not_found();
return *option->data_ptr();
}
std::pair<uint8_t, uint8_t> Dot11ManagementFrame::power_capability() const {
const Dot11::dot11_option *option = search_option(POWER_CAPABILITY);
const Dot11::option *option = search_option(POWER_CAPABILITY);
if(!option || option->data_size() != 2)
throw std::runtime_error("Power capability not set");
throw option_not_found();
return std::make_pair(*option->data_ptr(), *(option->data_ptr() + 1));
}
Dot11ManagementFrame::channels_type Dot11ManagementFrame::supported_channels() const {
const Dot11::dot11_option *option = search_option(SUPPORTED_CHANNELS);
const Dot11::option *option = search_option(SUPPORTED_CHANNELS);
// We need a multiple of two
if(!option || ((option->data_size() & 0x1) == 1))
throw std::runtime_error("Supported channels not set");
throw option_not_found();
channels_type output;
const uint8_t *ptr = option->data_ptr(), *end = ptr + option->data_size();
while(ptr != end) {
@@ -642,9 +658,9 @@ Dot11ManagementFrame::channels_type Dot11ManagementFrame::supported_channels() c
}
Dot11ManagementFrame::request_info_type Dot11ManagementFrame::request_information() const {
const Dot11::dot11_option *option = search_option(REQUEST_INFORMATION);
const Dot11::option *option = search_option(REQUEST_INFORMATION);
if(!option || option->data_size() == 0)
throw std::runtime_error("Request information not set");
throw option_not_found();
request_info_type output;
const uint8_t *ptr = option->data_ptr(), *end = ptr + option->data_size();
output.assign(ptr, end);
@@ -652,9 +668,9 @@ Dot11ManagementFrame::request_info_type Dot11ManagementFrame::request_informatio
}
Dot11ManagementFrame::fh_params_set Dot11ManagementFrame::fh_parameter_set() const {
const Dot11::dot11_option *option = search_option(FH_SET);
const Dot11::option *option = search_option(FH_SET);
if(!option || option->data_size() != sizeof(fh_params_set))
throw std::runtime_error("FH parameters set not set");
throw option_not_found();
fh_params_set output = *reinterpret_cast<const fh_params_set*>(option->data_ptr());
output.dwell_time = Endian::le_to_host(output.dwell_time);
output.hop_set = output.hop_set;
@@ -664,23 +680,23 @@ Dot11ManagementFrame::fh_params_set Dot11ManagementFrame::fh_parameter_set() con
}
uint8_t Dot11ManagementFrame::ds_parameter_set() const {
const Dot11::dot11_option *option = search_option(DS_SET);
const Dot11::option *option = search_option(DS_SET);
if(!option || option->data_size() != sizeof(uint8_t))
throw std::runtime_error("DS parameters set not set");
throw option_not_found();
return *option->data_ptr();
}
uint16_t Dot11ManagementFrame::ibss_parameter_set() const {
const Dot11::dot11_option *option = search_option(IBSS_SET);
const Dot11::option *option = search_option(IBSS_SET);
if(!option || option->data_size() != sizeof(uint16_t))
throw std::runtime_error("IBSS parameters set not set");
throw option_not_found();
return Endian::le_to_host(*reinterpret_cast<const uint16_t*>(option->data_ptr()));
}
Dot11ManagementFrame::ibss_dfs_params Dot11ManagementFrame::ibss_dfs() const {
const Dot11::dot11_option *option = search_option(IBSS_DFS);
const Dot11::option *option = search_option(IBSS_DFS);
if(!option || option->data_size() < ibss_dfs_params::minimum_size)
throw std::runtime_error("IBSS DFS set not set");
throw option_not_found();
ibss_dfs_params output;
const uint8_t *ptr = option->data_ptr(), *end = ptr + option->data_size();
output.dfs_owner = ptr;
@@ -689,16 +705,16 @@ Dot11ManagementFrame::ibss_dfs_params Dot11ManagementFrame::ibss_dfs() const {
while(ptr != end) {
uint8_t first = *(ptr++);
if(ptr == end)
throw std::runtime_error("Malformed channel data");
throw option_not_found();
output.channel_map.push_back(std::make_pair(first, *(ptr++)));
}
return output;
}
Dot11ManagementFrame::country_params Dot11ManagementFrame::country() const {
const Dot11::dot11_option *option = search_option(COUNTRY);
const Dot11::option *option = search_option(COUNTRY);
if(!option || option->data_size() < country_params::minimum_size)
throw std::runtime_error("Country option not set");
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));
@@ -709,23 +725,23 @@ Dot11ManagementFrame::country_params Dot11ManagementFrame::country() const {
output.max_transmit_power.push_back(*(ptr++));
}
if(ptr != end)
throw std::runtime_error("Malformed option");
throw option_not_found();
return output;
}
std::pair<uint8_t, uint8_t> Dot11ManagementFrame::fh_parameters() const {
const Dot11::dot11_option *option = search_option(HOPPING_PATTERN_PARAMS);
const Dot11::option *option = search_option(HOPPING_PATTERN_PARAMS);
if(!option || option->data_size() != sizeof(uint8_t) * 2)
throw std::runtime_error("FH parameters option not set");
throw option_not_found();
const uint8_t *ptr = option->data_ptr();
uint8_t first = *(ptr++);
return std::make_pair(first, *ptr);
}
Dot11ManagementFrame::fh_pattern_type Dot11ManagementFrame::fh_pattern_table() const {
const Dot11::dot11_option *option = search_option(HOPPING_PATTERN_TABLE);
const Dot11::option *option = search_option(HOPPING_PATTERN_TABLE);
if(!option || option->data_size() < fh_pattern_type::minimum_size)
throw std::runtime_error("FH pattern option not set");
throw option_not_found();
fh_pattern_type output;
const uint8_t *ptr = option->data_ptr(), *end = ptr + option->data_size();
@@ -739,16 +755,16 @@ Dot11ManagementFrame::fh_pattern_type Dot11ManagementFrame::fh_pattern_table() c
}
uint8_t Dot11ManagementFrame::power_constraint() const {
const Dot11::dot11_option *option = search_option(POWER_CONSTRAINT);
const Dot11::option *option = search_option(POWER_CONSTRAINT);
if(!option || option->data_size() != 1)
throw std::runtime_error("Power constraint option not set");
throw option_not_found();
return *option->data_ptr();
}
Dot11ManagementFrame::channel_switch_type Dot11ManagementFrame::channel_switch() const {
const Dot11::dot11_option *option = search_option(CHANNEL_SWITCH);
const Dot11::option *option = search_option(CHANNEL_SWITCH);
if(!option || option->data_size() != sizeof(uint8_t) * 3)
throw std::runtime_error("Channel switch option not set");
throw option_not_found();
const uint8_t *ptr = option->data_ptr();
channel_switch_type output;
output.switch_mode = *(ptr++);
@@ -758,9 +774,9 @@ Dot11ManagementFrame::channel_switch_type Dot11ManagementFrame::channel_switch()
}
Dot11ManagementFrame::quiet_type Dot11ManagementFrame::quiet() const {
const Dot11::dot11_option *option = search_option(QUIET);
const Dot11::option *option = search_option(QUIET);
if(!option || option->data_size() != (sizeof(uint8_t) * 2 + sizeof(uint16_t) * 2))
throw std::runtime_error("Quiet option not set");
throw option_not_found();
const uint8_t *ptr = option->data_ptr();
quiet_type output;
@@ -773,25 +789,25 @@ Dot11ManagementFrame::quiet_type Dot11ManagementFrame::quiet() const {
}
std::pair<uint8_t, uint8_t> Dot11ManagementFrame::tpc_report() const {
const Dot11::dot11_option *option = search_option(TPC_REPORT);
const Dot11::option *option = search_option(TPC_REPORT);
if(!option || option->data_size() != sizeof(uint8_t) * 2)
throw std::runtime_error("TPC Report option not set");
throw option_not_found();
const uint8_t *ptr = option->data_ptr();
uint8_t first = *(ptr++);
return std::make_pair(first, *ptr);
}
uint8_t Dot11ManagementFrame::erp_information() const {
const Dot11::dot11_option *option = search_option(ERP_INFORMATION);
const Dot11::option *option = search_option(ERP_INFORMATION);
if(!option || option->data_size() != sizeof(uint8_t))
throw std::runtime_error("ERP Information option not set");
throw option_not_found();
return *option->data_ptr();
}
Dot11ManagementFrame::bss_load_type Dot11ManagementFrame::bss_load() const {
const Dot11::dot11_option *option = search_option(BSS_LOAD);
const Dot11::option *option = search_option(BSS_LOAD);
if(!option || option->data_size() != sizeof(uint8_t) + 2 * sizeof(uint16_t))
throw std::runtime_error("BSS Load option not set");
throw option_not_found();
bss_load_type output;
const uint8_t *ptr = option->data_ptr();
@@ -802,9 +818,9 @@ Dot11ManagementFrame::bss_load_type Dot11ManagementFrame::bss_load() const {
}
Dot11ManagementFrame::tim_type Dot11ManagementFrame::tim() const {
const Dot11::dot11_option *option = search_option(TIM);
const Dot11::option *option = search_option(TIM);
if(!option || option->data_size() < 4 * sizeof(uint8_t))
throw std::runtime_error("TIM option not set");
throw option_not_found();
const uint8_t *ptr = option->data_ptr(), *end = ptr + option->data_size();
tim_type output;
@@ -817,9 +833,9 @@ Dot11ManagementFrame::tim_type Dot11ManagementFrame::tim() const {
}
std::string Dot11ManagementFrame::challenge_text() const {
const Dot11::dot11_option *option = search_option(CHALLENGE_TEXT);
const Dot11::option *option = search_option(CHALLENGE_TEXT);
if(!option || option->data_size() == 0)
throw std::runtime_error("Challenge text option not set");
throw option_not_found();
return std::string(option->data_ptr(), option->data_ptr() + option->data_size());
}
@@ -840,7 +856,7 @@ Dot11Beacon::Dot11Beacon(const uint8_t *buffer, uint32_t total_sz)
buffer += sz;
total_sz -= sz;
if(total_sz < sizeof(_body))
throw runtime_error("Not enough size for a IEEE 802.11 beacon header in the buffer.");
throw malformed_packet();
memcpy(&_body, buffer, sizeof(_body));
buffer += sizeof(_body);
total_sz -= sizeof(_body);
@@ -861,7 +877,9 @@ uint32_t Dot11Beacon::header_size() const {
uint32_t Dot11Beacon::write_fixed_parameters(uint8_t *buffer, uint32_t total_sz) {
uint32_t sz = sizeof(_body);
#ifdef TINS_DEBUG
assert(sz <= total_sz);
#endif
memcpy(buffer, &this->_body, sz);
return sz;
}
@@ -882,7 +900,7 @@ Dot11Disassoc::Dot11Disassoc(const uint8_t *buffer, uint32_t total_sz)
buffer += sz;
total_sz -= sz;
if(total_sz < sizeof(_body))
throw runtime_error("Not enough size for a IEEE 802.11 disassociation header in the buffer.");
throw malformed_packet();
memcpy(&_body, buffer, sizeof(_body));
buffer += sizeof(_body);
total_sz -= sizeof(_body);
@@ -899,7 +917,9 @@ uint32_t Dot11Disassoc::header_size() const {
uint32_t Dot11Disassoc::write_fixed_parameters(uint8_t *buffer, uint32_t total_sz) {
uint32_t sz = sizeof(DisassocBody);
#ifdef TINS_DEBUG
assert(sz <= total_sz);
#endif
memcpy(buffer, &this->_body, sz);
return sz;
}
@@ -914,12 +934,14 @@ const address_type &src_hw_addr)
memset(&_body, 0, sizeof(_body));
}
Dot11AssocRequest::Dot11AssocRequest(const uint8_t *buffer, uint32_t total_sz) : Dot11ManagementFrame(buffer, total_sz) {
Dot11AssocRequest::Dot11AssocRequest(const uint8_t *buffer, uint32_t total_sz)
: Dot11ManagementFrame(buffer, total_sz)
{
uint32_t sz = management_frame_size();
buffer += sz;
total_sz -= sz;
if(total_sz < sizeof(_body))
throw runtime_error("Not enough size for an IEEE 802.11 association request header in the buffer.");
throw malformed_packet();
memcpy(&_body, buffer, sizeof(_body));
buffer += sizeof(_body);
total_sz -= sizeof(_body);
@@ -936,7 +958,9 @@ uint32_t Dot11AssocRequest::header_size() const {
uint32_t Dot11AssocRequest::write_fixed_parameters(uint8_t *buffer, uint32_t total_sz) {
uint32_t sz = sizeof(AssocReqBody);
#ifdef TINS_DEBUG
assert(sz <= total_sz);
#endif
memcpy(buffer, &this->_body, sz);
return sz;
}
@@ -958,7 +982,7 @@ Dot11AssocResponse::Dot11AssocResponse(const uint8_t *buffer, uint32_t total_sz)
buffer += sz;
total_sz -= sz;
if(total_sz < sizeof(_body))
throw runtime_error("Not enough size for an IEEE 802.11 association response header in the buffer.");
throw malformed_packet();
memcpy(&_body, buffer, sizeof(_body));
buffer += sizeof(_body);
total_sz -= sizeof(_body);
@@ -979,7 +1003,9 @@ uint32_t Dot11AssocResponse::header_size() const {
uint32_t Dot11AssocResponse::write_fixed_parameters(uint8_t *buffer, uint32_t total_sz) {
uint32_t sz = sizeof(AssocRespBody);
#ifdef TINS_DEBUG
assert(sz <= total_sz);
#endif
memcpy(buffer, &this->_body, sz);
return sz;
}
@@ -1001,7 +1027,7 @@ Dot11ReAssocRequest::Dot11ReAssocRequest(const uint8_t *buffer, uint32_t total_s
buffer += sz;
total_sz -= sz;
if(total_sz < sizeof(_body))
throw runtime_error("Not enough size for an IEEE 802.11 reassociation request header in the buffer.");
throw malformed_packet();
memcpy(&_body, buffer, sizeof(_body));
buffer += sizeof(_body);
total_sz -= sizeof(_body);
@@ -1022,7 +1048,9 @@ uint32_t Dot11ReAssocRequest::header_size() const {
uint32_t Dot11ReAssocRequest::write_fixed_parameters(uint8_t *buffer, uint32_t total_sz) {
uint32_t sz = sizeof(this->_body);
#ifdef TINS_DEBUG
assert(sz <= total_sz);
#endif
memcpy(buffer, &this->_body, sz);
return sz;
}
@@ -1043,7 +1071,7 @@ Dot11ReAssocResponse::Dot11ReAssocResponse(const uint8_t *buffer, uint32_t total
buffer += sz;
total_sz -= sz;
if(total_sz < sizeof(_body))
throw runtime_error("Not enough size for an IEEE 802.11 reassociation response header in the buffer.");
throw malformed_packet();
memcpy(&_body, buffer, sizeof(_body));
buffer += sizeof(_body);
total_sz -= sizeof(_body);
@@ -1064,7 +1092,9 @@ uint32_t Dot11ReAssocResponse::header_size() const {
uint32_t Dot11ReAssocResponse::write_fixed_parameters(uint8_t *buffer, uint32_t total_sz) {
uint32_t sz = sizeof(this->_body);
#ifdef TINS_DEBUG
assert(sz <= total_sz);
#endif
memcpy(buffer, &this->_body, sz);
return sz;
}
@@ -1087,7 +1117,7 @@ Dot11Authentication::Dot11Authentication(const uint8_t *buffer, uint32_t total_s
buffer += sz;
total_sz -= sz;
if(total_sz < sizeof(_body))
throw runtime_error("Not enough size for an IEEE 802.11 authentication header in the buffer.");
throw malformed_packet();
memcpy(&_body, buffer, sizeof(_body));
buffer += sizeof(_body);
total_sz -= sizeof(_body);
@@ -1112,7 +1142,9 @@ uint32_t Dot11Authentication::header_size() const {
uint32_t Dot11Authentication::write_fixed_parameters(uint8_t *buffer, uint32_t total_sz) {
uint32_t sz = sizeof(this->_body);
#ifdef TINS_DEBUG
assert(sz <= total_sz);
#endif
memcpy(buffer, &this->_body, sz);
return sz;
}
@@ -1133,7 +1165,7 @@ Dot11Deauthentication::Dot11Deauthentication(const uint8_t *buffer, uint32_t tot
buffer += sz;
total_sz -= sz;
if(total_sz < sizeof(_body))
throw runtime_error("Not enough size for a IEEE 802.11 deauthentication header in the buffer.");
throw malformed_packet();
memcpy(&_body, buffer, sizeof(_body));
buffer += sizeof(_body);
total_sz -= sizeof(_body);
@@ -1150,7 +1182,9 @@ uint32_t Dot11Deauthentication::header_size() const {
uint32_t Dot11Deauthentication::write_fixed_parameters(uint8_t *buffer, uint32_t total_sz) {
uint32_t sz = sizeof(this->_body);
#ifdef TINS_DEBUG
assert(sz <= total_sz);
#endif
memcpy(buffer, &this->_body, sz);
return sz;
}
@@ -1190,7 +1224,7 @@ Dot11ProbeResponse::Dot11ProbeResponse(const uint8_t *buffer, uint32_t total_sz)
buffer += sz;
total_sz -= sz;
if(total_sz < sizeof(_body))
throw runtime_error("Not enough size for an IEEE 802.11 probe response header in the buffer.");
throw malformed_packet();
memcpy(&_body, buffer, sizeof(_body));
buffer += sizeof(_body);
total_sz -= sizeof(_body);
@@ -1211,7 +1245,9 @@ uint32_t Dot11ProbeResponse::header_size() const {
uint32_t Dot11ProbeResponse::write_fixed_parameters(uint8_t *buffer, uint32_t total_sz) {
uint32_t sz = sizeof(this->_body);
#ifdef TINS_DEBUG
assert(sz <= total_sz);
#endif
memcpy(buffer, &this->_body, sz);
return sz;
}
@@ -1219,22 +1255,11 @@ uint32_t Dot11ProbeResponse::write_fixed_parameters(uint8_t *buffer, uint32_t to
/* Dot11Data */
Dot11Data::Dot11Data(const uint8_t *buffer, uint32_t total_sz)
: Dot11(buffer, total_sz) {
uint32_t sz = Dot11::header_size();
buffer += sz;
total_sz -= sz;
if(total_sz < sizeof(_ext_header))
throw runtime_error("Not enough size for an IEEE 802.11 data header in the buffer.");
std::memcpy(&_ext_header, buffer, sizeof(_ext_header));
buffer += sizeof(_ext_header);
total_sz -= sizeof(_ext_header);
if(from_ds() && to_ds()) {
if(total_sz < _addr4.size())
throw runtime_error("Not enough size for an IEEE 802.11 data header in the buffer.");
_addr4 = buffer;
buffer += _addr4.size();
total_sz -= _addr4.size();
}
: Dot11(buffer, total_sz)
{
const uint32_t offset = init(buffer, total_sz);
buffer += offset;
total_sz -= offset;
if(total_sz) {
// If the wep bit is on, then just use a RawPDU
if(wep())
@@ -1244,10 +1269,35 @@ Dot11Data::Dot11Data(const uint8_t *buffer, uint32_t total_sz)
}
}
Dot11Data::Dot11Data(const uint8_t *buffer, uint32_t total_sz, no_inner_pdu)
: Dot11(buffer, total_sz)
{
init(buffer, total_sz);
}
uint32_t Dot11Data::init(const uint8_t *buffer, uint32_t total_sz) {
const uint8_t *start_ptr = buffer;
uint32_t sz = Dot11::header_size();
buffer += sz;
total_sz -= sz;
if(total_sz < sizeof(_ext_header))
throw malformed_packet();
std::memcpy(&_ext_header, buffer, sizeof(_ext_header));
buffer += sizeof(_ext_header);
total_sz -= sizeof(_ext_header);
if(from_ds() && to_ds()) {
if(total_sz < _addr4.size())
throw malformed_packet();
_addr4 = buffer;
buffer += _addr4.size();
total_sz -= _addr4.size();
}
return buffer - start_ptr;
}
Dot11Data::Dot11Data(const address_type &dst_hw_addr,
const address_type &src_hw_addr, PDU* child)
: Dot11(dst_hw_addr, child)
const address_type &src_hw_addr)
: Dot11(dst_hw_addr)
{
type(Dot11::DATA);
memset(&_ext_header, 0, sizeof(_ext_header));
@@ -1304,8 +1354,8 @@ uint32_t Dot11Data::write_ext_header(uint8_t *buffer, uint32_t total_sz) {
/* QoS data. */
Dot11QoSData::Dot11QoSData(const address_type &dst_hw_addr,
const address_type &src_hw_addr, PDU* child)
: Dot11Data(dst_hw_addr, src_hw_addr, child)
const address_type &src_hw_addr)
: Dot11Data(dst_hw_addr, src_hw_addr)
{
subtype(Dot11::QOS_DATA_DATA);
_qos_control = 0;
@@ -1313,13 +1363,12 @@ Dot11QoSData::Dot11QoSData(const address_type &dst_hw_addr,
Dot11QoSData::Dot11QoSData(const uint8_t *buffer, uint32_t total_sz)
// Am I breaking something? :S
//: Dot11Data(buffer, std::min(data_frame_size(), total_sz)) {
: Dot11Data(buffer, total_sz) {
: Dot11Data(buffer, total_sz, no_inner_pdu()) {
uint32_t sz = data_frame_size();
buffer += sz;
total_sz -= sz;
if(total_sz < sizeof(this->_qos_control))
throw runtime_error("Not enough size for an IEEE 802.11 data header in the buffer.");
if(total_sz < sizeof(_qos_control))
throw malformed_packet();
_qos_control = *(uint16_t*)buffer;
total_sz -= sizeof(uint16_t);
buffer += sizeof(uint16_t);
@@ -1337,15 +1386,17 @@ uint32_t Dot11QoSData::header_size() const {
uint32_t Dot11QoSData::write_fixed_parameters(uint8_t *buffer, uint32_t total_sz) {
uint32_t sz = sizeof(this->_qos_control);
#ifdef TINS_DEBUG
assert(sz <= total_sz);
#endif
*(uint16_t*)buffer = this->_qos_control;
return sz;
}
/* Dot11Control */
Dot11Control::Dot11Control(const address_type &dst_addr, PDU* child)
: Dot11(dst_addr, child)
Dot11Control::Dot11Control(const address_type &dst_addr)
: Dot11(dst_addr)
{
type(CONTROL);
}
@@ -1358,8 +1409,8 @@ Dot11Control::Dot11Control(const uint8_t *buffer, uint32_t total_sz)
/* Dot11ControlTA */
Dot11ControlTA::Dot11ControlTA(const address_type &dst_addr,
const address_type &target_address, PDU* child)
: Dot11Control(dst_addr, child)
const address_type &target_address)
: Dot11Control(dst_addr)
{
target_addr(target_address);
}
@@ -1378,7 +1429,9 @@ uint32_t Dot11ControlTA::header_size() const {
}
uint32_t Dot11ControlTA::write_ext_header(uint8_t *buffer, uint32_t total_sz) {
#ifdef TINS_DEBUG
assert(total_sz >= sizeof(_taddr));
#endif
//std::memcpy(buffer, _taddr, sizeof(_taddr));
_taddr.copy(buffer);
return sizeof(_taddr);
@@ -1391,8 +1444,8 @@ void Dot11ControlTA::target_addr(const address_type &addr) {
/* Dot11RTS */
Dot11RTS::Dot11RTS(const address_type &dst_addr,
const address_type &target_addr, PDU* child)
: Dot11ControlTA(dst_addr, target_addr, child)
const address_type &target_addr)
: Dot11ControlTA(dst_addr, target_addr)
{
subtype(RTS);
}
@@ -1405,8 +1458,8 @@ Dot11RTS::Dot11RTS(const uint8_t *buffer, uint32_t total_sz)
/* Dot11PSPoll */
Dot11PSPoll::Dot11PSPoll(const address_type &dst_addr,
const address_type &target_addr, PDU* child)
: Dot11ControlTA(dst_addr, target_addr, child)
const address_type &target_addr)
: Dot11ControlTA(dst_addr, target_addr)
{
subtype(PS);
}
@@ -1419,8 +1472,8 @@ Dot11PSPoll::Dot11PSPoll(const uint8_t *buffer, uint32_t total_sz)
/* Dot11CFEnd */
Dot11CFEnd::Dot11CFEnd(const address_type &dst_addr,
const address_type &target_addr, PDU* child)
: Dot11ControlTA(dst_addr, target_addr, child)
const address_type &target_addr)
: Dot11ControlTA(dst_addr, target_addr)
{
subtype(CF_END);
}
@@ -1433,8 +1486,8 @@ Dot11CFEnd::Dot11CFEnd(const uint8_t *buffer, uint32_t total_sz)
/* Dot11EndCFAck */
Dot11EndCFAck::Dot11EndCFAck(const address_type &dst_addr,
const address_type &target_addr, PDU* child)
: Dot11ControlTA(dst_addr, target_addr, child)
const address_type &target_addr)
: Dot11ControlTA(dst_addr, target_addr)
{
subtype(CF_END_ACK);
}
@@ -1446,26 +1499,30 @@ Dot11EndCFAck::Dot11EndCFAck(const uint8_t *buffer, uint32_t total_sz)
/* Dot11Ack */
Dot11Ack::Dot11Ack(const address_type &dst_addr, PDU* child)
: Dot11Control(dst_addr, child)
Dot11Ack::Dot11Ack(const address_type &dst_addr)
: Dot11Control(dst_addr)
{
subtype(ACK);
}
Dot11Ack::Dot11Ack(const uint8_t *buffer, uint32_t total_sz) : Dot11Control(buffer, total_sz) {
Dot11Ack::Dot11Ack(const uint8_t *buffer, uint32_t total_sz)
: Dot11Control(buffer, total_sz)
{
}
/* Dot11BlockAck */
Dot11BlockAckRequest::Dot11BlockAckRequest(const address_type &dst_addr,
const address_type &target_addr, PDU* child)
: Dot11ControlTA(dst_addr, target_addr, child)
const address_type &target_addr)
: Dot11ControlTA(dst_addr, target_addr)
{
init_block_ack();
}
Dot11BlockAckRequest::Dot11BlockAckRequest(const uint8_t *buffer, uint32_t total_sz) : Dot11ControlTA(buffer, total_sz) {
Dot11BlockAckRequest::Dot11BlockAckRequest(const uint8_t *buffer, uint32_t total_sz)
: Dot11ControlTA(buffer, total_sz)
{
uint32_t padding = controlta_size();
buffer += padding;
total_sz -= padding;
@@ -1491,18 +1548,28 @@ uint32_t Dot11BlockAckRequest::write_ext_header(uint8_t *buffer, uint32_t total_
return parent_size + sizeof(_start_sequence) + sizeof(_bar_control);
}
void Dot11BlockAckRequest::bar_control(uint16_t bar) {
//std::memcpy(&_bar_control, &bar, sizeof(bar));
_bar_control.tid = Endian::host_to_le(bar);
void Dot11BlockAckRequest::bar_control(small_uint<4> bar) {
#if TINS_IS_LITTLE_ENDIAN
_bar_control = bar | (_bar_control & 0xfff0);
#else
_bar_control = (bar << 8) | (_bar_control & 0xf0ff);
#endif
}
void Dot11BlockAckRequest::start_sequence(uint16_t seq) {
//std::memcpy(&_start_sequence, &seq, sizeof(seq));
_start_sequence.seq = Endian::host_to_le(seq);
void Dot11BlockAckRequest::start_sequence(small_uint<12> seq) {
#if TINS_IS_LITTLE_ENDIAN
_start_sequence = (seq << 4) | (_start_sequence & 0xf);
#else
_start_sequence = Endian::host_to_le<uint16_t>(seq << 4) | (_start_sequence & 0xf00);
#endif
}
void Dot11BlockAckRequest::fragment_number(uint8_t frag) {
_start_sequence.frag = frag;
void Dot11BlockAckRequest::fragment_number(small_uint<4> frag) {
#if TINS_IS_LITTLE_ENDIAN
_start_sequence = frag | (_start_sequence & 0xfff0);
#else
_start_sequence = (frag << 8) | (_start_sequence & 0xf0ff);
#endif
}
uint32_t Dot11BlockAckRequest::header_size() const {
@@ -1512,8 +1579,8 @@ uint32_t Dot11BlockAckRequest::header_size() const {
/* Dot11BlockAck */
Dot11BlockAck::Dot11BlockAck(const address_type &dst_addr,
const address_type &target_addr, PDU* child)
: Dot11ControlTA(dst_addr, target_addr, child)
const address_type &target_addr)
: Dot11ControlTA(dst_addr, target_addr)
{
subtype(BLOCK_ACK);
std::memset(_bitmap, 0, sizeof(_bitmap));
@@ -1532,12 +1599,28 @@ Dot11BlockAck::Dot11BlockAck(const uint8_t *buffer, uint32_t total_sz) : Dot11Co
std::memcpy(&_bitmap, buffer, sizeof(_bitmap));
}
void Dot11BlockAck::bar_control(uint16_t bar) {
std::memcpy(&_bar_control, &bar, sizeof(bar));
void Dot11BlockAck::bar_control(small_uint<4> bar) {
#if TINS_IS_LITTLE_ENDIAN
_bar_control = bar | (_bar_control & 0xfff0);
#else
_bar_control = (bar << 8) | (_bar_control & 0xf0ff);
#endif
}
void Dot11BlockAck::start_sequence(uint16_t seq) {
std::memcpy(&_start_sequence, &seq, sizeof(seq));
void Dot11BlockAck::start_sequence(small_uint<12> seq) {
#if TINS_IS_LITTLE_ENDIAN
_start_sequence = (seq << 4) | (_start_sequence & 0xf);
#else
_start_sequence = Endian::host_to_le<uint16_t>(seq << 4) | (_start_sequence & 0xf00);
#endif
}
void Dot11BlockAck::fragment_number(small_uint<4> frag) {
#if TINS_IS_LITTLE_ENDIAN
_start_sequence = frag | (_start_sequence & 0xfff0);
#else
_start_sequence = (frag << 8) | (_start_sequence & 0xf0ff);
#endif
}
void Dot11BlockAck::bitmap(const uint8_t *bit) {

144
src/dot1q.cpp Normal file
View File

@@ -0,0 +1,144 @@
/*
* 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 <stdexcept>
#include <cstring>
#include <cassert>
#include "dot1q.h"
#include "internals.h"
#include "exceptions.h"
namespace Tins {
Dot1Q::Dot1Q(small_uint<12> tag_id, bool append_pad)
: _header(), _append_padding(append_pad)
{
id(tag_id);
}
Dot1Q::Dot1Q(const uint8_t *buffer, uint32_t total_sz)
: _append_padding()
{
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(
Internals::pdu_from_flag(
(Constants::Ethernet::e)payload_type(),
buffer,
total_sz
)
);
}
}
void Dot1Q::priority(small_uint<3> new_priority) {
_header.priority = new_priority;
}
void Dot1Q::cfi(small_uint<1> new_cfi) {
_header.cfi = new_cfi;
}
void Dot1Q::id(small_uint<12> new_id) {
#if TINS_IS_LITTLE_ENDIAN
_header.idL = new_id & 0xff;
_header.idH = new_id >> 8;
#else
_header.id = new_id;
#endif
}
void Dot1Q::payload_type(uint16_t new_type) {
_header.type = Endian::host_to_be(new_type);
}
uint32_t Dot1Q::header_size() const {
return sizeof(_header);
}
uint32_t Dot1Q::trailer_size() const {
if(_append_padding) {
uint32_t total_size = sizeof(_header);
if(inner_pdu())
total_size += inner_pdu()->size();
return (total_size > 50) ? 0 : (50 - total_size);
}
else
return 0;
}
void Dot1Q::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *) {
uint32_t trailer = trailer_size();
#ifdef TINS_DEBUG
assert(total_sz >= sizeof(_header) + trailer);
#endif
if ((payload_type() == 0) && inner_pdu()) {
Constants::Ethernet::e flag = Internals::pdu_flag_to_ether_type(
inner_pdu()->pdu_type()
);
payload_type(static_cast<uint16_t>(flag));
}
std::memcpy(buffer, &_header, sizeof(_header));
buffer += sizeof(_header) + inner_pdu()->size();
std::fill(buffer, buffer + trailer, 0);
}
#if TINS_IS_LITTLE_ENDIAN
uint16_t Dot1Q::get_id(const dot1q_hdr *hdr) {
return hdr->idL | (hdr->idH << 8);
}
#else
uint16_t Dot1Q::get_id(const dot1q_hdr *hdr) {
return hdr->id;
}
#endif
void Dot1Q::append_padding(bool value) {
_append_padding = value;
}
bool Dot1Q::matches_response(const uint8_t *ptr, uint32_t total_sz) const {
if(total_sz < sizeof(_header))
return false;
const dot1q_hdr *dot1q_ptr = (const dot1q_hdr*)ptr;
if(get_id(dot1q_ptr) == get_id(&_header)) {
ptr += sizeof(_header);
total_sz -= sizeof(_header);
return inner_pdu() ? inner_pdu()->matches_response(ptr, total_sz) : true;
}
return false;
}
}

164
src/dot3.cpp Normal file
View File

@@ -0,0 +1,164 @@
/*
* 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.
*
*/
#ifdef TINS_DEBUG
#include <cassert>
#endif
#include <cstring>
#include <stdexcept>
#include <algorithm>
#include "macros.h"
#ifndef WIN32
#if defined(BSD) || defined(__FreeBSD_kernel__)
#include <net/if_dl.h>
#else
#include <netpacket/packet.h>
#endif
#include <net/ethernet.h>
#include <netinet/in.h>
#endif
#include "dot3.h"
#include "packet_sender.h"
#include "llc.h"
#include "exceptions.h"
namespace Tins {
const Dot3::address_type Dot3::BROADCAST("ff:ff:ff:ff:ff:ff");
Dot3::Dot3(const address_type &dst_hw_addr, const address_type &src_hw_addr)
{
memset(&_eth, 0, sizeof(ethhdr));
this->dst_addr(dst_hw_addr);
this->src_addr(src_hw_addr);
this->_eth.length = 0;
}
Dot3::Dot3(const uint8_t *buffer, uint32_t total_sz)
{
if(total_sz < sizeof(ethhdr))
throw malformed_packet();
memcpy(&_eth, buffer, sizeof(ethhdr));
buffer += sizeof(ethhdr);
total_sz -= sizeof(ethhdr);
if(total_sz)
inner_pdu(new Tins::LLC(buffer, total_sz));
}
void Dot3::dst_addr(const address_type &new_dst_mac) {
std::copy(new_dst_mac.begin(), new_dst_mac.end(), _eth.dst_mac);
}
void Dot3::src_addr(const address_type &new_src_mac) {
std::copy(new_src_mac.begin(), new_src_mac.end(), _eth.src_mac);
}
void Dot3::length(uint16_t new_length) {
this->_eth.length = Endian::host_to_be(new_length);
}
uint32_t Dot3::header_size() const {
return sizeof(ethhdr);
}
#ifndef WIN32
void Dot3::send(PacketSender &sender, const NetworkInterface &iface) {
if(!iface)
throw invalid_interface();
#if !defined(BSD) && !defined(__FreeBSD_kernel__)
struct sockaddr_ll addr;
memset(&addr, 0, sizeof(struct sockaddr_ll));
addr.sll_family = Endian::host_to_be<uint16_t>(PF_PACKET);
addr.sll_protocol = Endian::host_to_be<uint16_t>(ETH_P_ALL);
addr.sll_halen = address_type::address_size;
addr.sll_ifindex = iface.id();
memcpy(&(addr.sll_addr), _eth.dst_mac, sizeof(_eth.dst_mac));
sender.send_l2(*this, (struct sockaddr*)&addr, (uint32_t)sizeof(addr));
#else
sender.send_l2(*this, 0, 0, iface);
#endif
}
#endif // WIN32
bool Dot3::matches_response(const uint8_t *ptr, uint32_t total_sz) const {
if(total_sz < sizeof(ethhdr))
return false;
const size_t addr_sz = address_type::address_size;
const ethhdr *eth_ptr = (const ethhdr*)ptr;
if(std::equal(_eth.src_mac, _eth.src_mac + addr_sz, eth_ptr->dst_mac)) {
if(std::equal(_eth.src_mac, _eth.src_mac + addr_sz, eth_ptr->dst_mac) || dst_addr() == BROADCAST)
{
ptr += sizeof(ethhdr);
total_sz -= sizeof(ethhdr);
return inner_pdu() ? inner_pdu()->matches_response(ptr, total_sz) : true;
}
}
return false;
}
void Dot3::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *parent) {
bool set_length = _eth.length == 0;
#ifdef TINS_DEBUG
assert(total_sz >= header_size());
#endif
if (set_length)
_eth.length = Endian::host_to_be(size() - sizeof(_eth));
memcpy(buffer, &_eth, sizeof(ethhdr));
if (set_length)
_eth.length = 0;
}
#ifndef WIN32
PDU *Dot3::recv_response(PacketSender &sender, const NetworkInterface &iface) {
if(!iface)
throw invalid_interface();
#if !defined(BSD) && !defined(__FreeBSD_kernel__)
struct sockaddr_ll addr;
memset(&addr, 0, sizeof(struct sockaddr_ll));
addr.sll_family = Endian::host_to_be<uint16_t>(PF_PACKET);
addr.sll_protocol = Endian::host_to_be<uint16_t>(ETH_P_802_3);
addr.sll_halen = address_type::address_size;
addr.sll_ifindex = iface.id();
memcpy(&(addr.sll_addr), _eth.dst_mac, sizeof(_eth.dst_mac));
return sender.recv_l2(*this, (struct sockaddr*)&addr, (uint32_t)sizeof(addr));
#else
return sender.recv_l2(*this, 0, 0, iface);
#endif
}
#endif // WIN32
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, Nasel
* Copyright (c) 2012, Matias Fontanini
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -28,12 +28,14 @@
*/
#include <cstring>
#ifdef TINS_DEBUG
#include <cassert>
#endif
#include <stdexcept>
#include "eapol.h"
#include "dot11.h"
#include "rsn_information.h"
#include "exceptions.h"
namespace Tins {
EAPOL::EAPOL(uint8_t packet_type, EAPOLTYPE type)
@@ -47,17 +49,13 @@ EAPOL::EAPOL(uint8_t packet_type, EAPOLTYPE type)
EAPOL::EAPOL(const uint8_t *buffer, uint32_t total_sz)
{
if(total_sz < sizeof(_header))
throw std::runtime_error("Not enough size for an EAPOL header in the buffer.");
throw malformed_packet();
std::memcpy(&_header, buffer, sizeof(_header));
}
EAPOL::EAPOL(const EAPOL &other) : PDU(other) {
copy_eapol_fields(&other);
}
EAPOL *EAPOL::from_bytes(const uint8_t *buffer, uint32_t total_sz) {
if(total_sz < sizeof(eapolhdr))
throw std::runtime_error("Not enough size for an EAPOL header in the buffer.");
throw malformed_packet();
const eapolhdr *ptr = (const eapolhdr*)buffer;
switch(ptr->type) {
case RC4:
@@ -88,19 +86,13 @@ void EAPOL::type(uint8_t new_type) {
}
void EAPOL::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *) {
uint32_t sz = header_size();
assert(total_sz >= sz);
//if(!_header.length)
// length(sz - sizeof(_header.version) - sizeof(_header.length) - sizeof(_header.type));
#ifdef TINS_DEBUG
assert(total_sz >= header_size());
#endif
std::memcpy(buffer, &_header, sizeof(_header));
write_body(buffer + sizeof(_header), total_sz - sizeof(_header));
}
void EAPOL::copy_eapol_fields(const EAPOL *other) {
std::memcpy(&_header, &other->_header, sizeof(_header));
}
/* RC4EAPOL */
RC4EAPOL::RC4EAPOL()
@@ -115,7 +107,7 @@ RC4EAPOL::RC4EAPOL(const uint8_t *buffer, uint32_t total_sz)
buffer += sizeof(eapolhdr);
total_sz -= sizeof(eapolhdr);
if(total_sz < sizeof(_header))
throw std::runtime_error("Not enough size for an EAPOL header in the buffer.");
throw malformed_packet();
std::memcpy(&_header, buffer, sizeof(_header));
buffer += sizeof(_header);
total_sz -= sizeof(_header);
@@ -156,8 +148,9 @@ uint32_t RC4EAPOL::header_size() const {
}
void RC4EAPOL::write_body(uint8_t *buffer, uint32_t total_sz) {
uint32_t sz = sizeof(_header) + _key.size();
assert(total_sz >= sz);
#ifdef TINS_DEBUG
assert(total_sz >= sizeof(_header) + _key.size());
#endif
if(_key.size())
_header.key_length = Endian::host_to_be(_key.size());
std::memcpy(buffer, &_header, sizeof(_header));
@@ -180,7 +173,7 @@ RSNEAPOL::RSNEAPOL(const uint8_t *buffer, uint32_t total_sz)
buffer += sizeof(eapolhdr);
total_sz -= sizeof(eapolhdr);
if(total_sz < sizeof(_header))
throw std::runtime_error("Not enough size for an EAPOL header in the buffer.");
throw malformed_packet();
std::memcpy(&_header, buffer, sizeof(_header));
buffer += sizeof(_header);
total_sz -= sizeof(_header);
@@ -188,7 +181,7 @@ RSNEAPOL::RSNEAPOL(const uint8_t *buffer, uint32_t total_sz)
_key.assign(buffer, buffer + total_sz);
}
void RSNEAPOL::RSNEAPOL::nonce(const uint8_t *new_nonce) {
void RSNEAPOL::nonce(const uint8_t *new_nonce) {
std::copy(new_nonce, new_nonce + nonce_size, _header.nonce);
}
@@ -270,8 +263,9 @@ uint32_t RSNEAPOL::header_size() const {
}
void RSNEAPOL::write_body(uint8_t *buffer, uint32_t total_sz) {
uint32_t sz = header_size() - sizeof(eapolhdr);
assert(total_sz >= sz);
#ifdef TINS_DEBUG
assert(total_sz >= header_size() - sizeof(eapolhdr));
#endif
if(_key.size()) {
if(!_header.key_t) {
_header.key_length = Endian::host_to_be<uint16_t>(32);

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, Nasel
* Copyright (c) 2012, Matias Fontanini
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -27,34 +27,41 @@
*
*/
#ifdef TINS_DEBUG
#include <cassert>
#endif
#include <cstring>
#include <stdexcept>
#include <algorithm>
#include "macros.h"
#ifndef WIN32
#include <net/ethernet.h>
#if defined(BSD) || defined(__FreeBSD_kernel__)
#include <net/if_dl.h>
#else
#include <netpacket/packet.h>
#endif
#include <netinet/in.h>
#include <netpacket/packet.h>
#include <net/ethernet.h>
#endif
#include "ethernetII.h"
#include "packet_sender.h"
#include "rawpdu.h"
#include "ip.h"
#include "ipv6.h"
#include "arp.h"
#include "constants.h"
#include "internals.h"
#include "exceptions.h"
namespace Tins {
const EthernetII::address_type EthernetII::BROADCAST("ff:ff:ff:ff:ff:ff");
EthernetII::EthernetII(const NetworkInterface& iface,
const address_type &dst_hw_addr, const address_type &src_hw_addr,
PDU* child)
: PDU(child)
EthernetII::EthernetII(const address_type &dst_hw_addr,
const address_type &src_hw_addr)
{
memset(&_eth, 0, sizeof(ethhdr));
dst_addr(dst_hw_addr);
src_addr(src_hw_addr);
this->iface(iface);
_eth.payload_type = 0;
}
@@ -62,24 +69,18 @@ EthernetII::EthernetII(const NetworkInterface& iface,
EthernetII::EthernetII(const uint8_t *buffer, uint32_t total_sz)
{
if(total_sz < sizeof(ethhdr))
throw std::runtime_error("Not enough size for an ethernetII header in the buffer.");
throw malformed_packet();
memcpy(&_eth, buffer, sizeof(ethhdr));
PDU *next = 0;
buffer += sizeof(ethhdr);
total_sz -= sizeof(ethhdr);
if(total_sz) {
switch(payload_type()) {
case Constants::Ethernet::IP:
next = new Tins::IP(buffer, total_sz);
break;
case Constants::Ethernet::ARP:
next = new Tins::ARP(buffer, total_sz);
break;
default:
next = new Tins::RawPDU(buffer, total_sz);
// Other protos plz
}
inner_pdu(next);
inner_pdu(
Internals::pdu_from_flag(
(Constants::Ethernet::e)payload_type(),
buffer,
total_sz
)
);
}
}
@@ -91,10 +92,6 @@ void EthernetII::src_addr(const address_type &new_src_addr) {
new_src_addr.copy(_eth.src_mac);
}
void EthernetII::iface(const NetworkInterface& new_iface) {
_iface = new_iface;
}
void EthernetII::payload_type(uint16_t new_payload_type) {
this->_eth.payload_type = Endian::host_to_be(new_payload_type);
}
@@ -104,81 +101,74 @@ uint32_t EthernetII::header_size() const {
}
#ifndef WIN32
void EthernetII::send(PacketSender &sender) {
if(!_iface)
throw std::runtime_error("Interface has not been set");
struct sockaddr_ll addr;
void EthernetII::send(PacketSender &sender, const NetworkInterface &iface) {
if(!iface)
throw invalid_interface();
#if !defined(BSD) && !defined(__FreeBSD_kernel__)
struct sockaddr_ll addr;
memset(&addr, 0, sizeof(struct sockaddr_ll));
memset(&addr, 0, sizeof(struct sockaddr_ll));
addr.sll_family = Endian::host_to_be<uint16_t>(PF_PACKET);
addr.sll_protocol = Endian::host_to_be<uint16_t>(ETH_P_ALL);
addr.sll_halen = address_type::address_size;
addr.sll_ifindex = _iface.id();
memcpy(&(addr.sll_addr), _eth.dst_mac, address_type::address_size);
addr.sll_family = Endian::host_to_be<uint16_t>(PF_PACKET);
addr.sll_protocol = Endian::host_to_be<uint16_t>(ETH_P_ALL);
addr.sll_halen = address_type::address_size;
addr.sll_ifindex = iface.id();
memcpy(&(addr.sll_addr), _eth.dst_mac, address_type::address_size);
sender.send_l2(*this, (struct sockaddr*)&addr, (uint32_t)sizeof(addr));
sender.send_l2(*this, (struct sockaddr*)&addr, (uint32_t)sizeof(addr));
#else
sender.send_l2(*this, 0, 0, iface);
#endif
}
#endif // WIN32
bool EthernetII::matches_response(uint8_t *ptr, uint32_t total_sz) {
bool EthernetII::matches_response(const uint8_t *ptr, uint32_t total_sz) const {
if(total_sz < sizeof(ethhdr))
return false;
ethhdr *eth_ptr = (ethhdr*)ptr;
if(!memcmp(eth_ptr->dst_mac, _eth.src_mac, address_type::address_size)) {
// chequear broadcast en destino original...
return (inner_pdu()) ? inner_pdu()->matches_response(ptr + sizeof(_eth), total_sz - sizeof(_eth)) : true;
const size_t addr_sz = address_type::address_size;
const ethhdr *eth_ptr = (const ethhdr*)ptr;
if(std::equal(_eth.src_mac, _eth.src_mac + addr_sz, eth_ptr->dst_mac)) {
if(std::equal(_eth.src_mac, _eth.src_mac + addr_sz, eth_ptr->dst_mac) || dst_addr() == BROADCAST ||
(_eth.src_mac[0] == 0x33 && _eth.src_mac[1] == 0x33))
{
return (inner_pdu()) ? inner_pdu()->matches_response(ptr + sizeof(_eth), total_sz - sizeof(_eth)) : true;
}
}
return false;
}
void EthernetII::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *parent) {
uint32_t my_sz = header_size();
assert(total_sz >= my_sz);
#ifdef TINS_DEBUG
assert(total_sz >= header_size());
#endif
/* Inner type defaults to IP */
if ((_eth.payload_type == 0) && inner_pdu()) {
uint16_t type = Constants::Ethernet::IP;
switch (inner_pdu()->pdu_type()) {
case PDU::IP:
type = Constants::Ethernet::IP;
break;
case PDU::ARP:
type = Constants::Ethernet::ARP;
break;
default:
type = 0;
}
_eth.payload_type = Endian::host_to_be(type);
Constants::Ethernet::e flag = Internals::pdu_flag_to_ether_type(
inner_pdu()->pdu_type()
);
payload_type(static_cast<uint16_t>(flag));
}
memcpy(buffer, &_eth, sizeof(ethhdr));
}
#ifndef WIN32
PDU *EthernetII::recv_response(PacketSender &sender) {
struct sockaddr_ll addr;
memset(&addr, 0, sizeof(struct sockaddr_ll));
PDU *EthernetII::recv_response(PacketSender &sender, const NetworkInterface &iface) {
#if !defined(BSD) && !defined(__FreeBSD_kernel__)
struct sockaddr_ll addr;
memset(&addr, 0, sizeof(struct sockaddr_ll));
addr.sll_family = Endian::host_to_be<uint16_t>(PF_PACKET);
addr.sll_protocol = Endian::host_to_be<uint16_t>(ETH_P_ALL);
addr.sll_halen = address_type::address_size;
addr.sll_ifindex = _iface.id();
memcpy(&(addr.sll_addr), _eth.dst_mac, address_type::address_size);
addr.sll_family = Endian::host_to_be<uint16_t>(PF_PACKET);
addr.sll_protocol = Endian::host_to_be<uint16_t>(ETH_P_ALL);
addr.sll_halen = address_type::address_size;
addr.sll_ifindex = iface.id();
memcpy(&(addr.sll_addr), _eth.dst_mac, address_type::address_size);
return sender.recv_l2(*this, (struct sockaddr*)&addr, (uint32_t)sizeof(addr));
return sender.recv_l2(*this, (struct sockaddr*)&addr, (uint32_t)sizeof(addr));
#else
return sender.recv_l2(*this, 0, 0, iface);
#endif
}
#endif // WIN32
PDU *EthernetII::clone_packet(const uint8_t *ptr, uint32_t total_sz) {
if(total_sz < sizeof(_eth))
return 0;
PDU *child = 0, *cloned;
if(total_sz > sizeof(_eth)) {
if((child = PDU::clone_inner_pdu(ptr + sizeof(_eth), total_sz - sizeof(_eth))) == 0)
return 0;
}
cloned = new EthernetII(ptr, std::min(total_sz, (uint32_t)sizeof(_eth)));
cloned->inner_pdu(child);
return cloned;
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, Nasel
* Copyright (c) 2012, Matias Fontanini
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -29,132 +29,107 @@
#include <stdexcept>
#include <cstring>
#ifdef TINS_DEBUG
#include <cassert>
#endif
#ifndef WIN32
#define NOMINMAX
#include <netinet/in.h>
#endif
#include "icmp.h"
#include "rawpdu.h"
#include "utils.h"
#include "exceptions.h"
uint16_t Tins::ICMP::global_id = 0, Tins::ICMP::global_seq = 0;
Tins::ICMP::ICMP(Flags flag)
namespace Tins {
ICMP::ICMP(Flags flag)
{
std::memset(&_icmp, 0, sizeof(icmphdr));
switch(flag) {
case ECHO_REPLY:
break;
case ECHO_REQUEST:
set_echo_request();
break;
case DEST_UNREACHABLE:
set_dest_unreachable();
break;
default:
break;
};
type(flag);
}
Tins::ICMP::ICMP(const uint8_t *buffer, uint32_t total_sz)
ICMP::ICMP(const uint8_t *buffer, uint32_t total_sz)
{
if(total_sz < sizeof(icmphdr))
throw std::runtime_error("Not enough size for an ICMP header in the buffer.");
throw malformed_packet();
std::memcpy(&_icmp, buffer, sizeof(icmphdr));
total_sz -= sizeof(icmphdr);
if(total_sz)
inner_pdu(new RawPDU(buffer + sizeof(icmphdr), total_sz));
}
void Tins::ICMP::code(uint8_t new_code) {
void ICMP::code(uint8_t new_code) {
_icmp.code = new_code;
}
void Tins::ICMP::type(Flags new_type) {
void ICMP::type(Flags new_type) {
_icmp.type = new_type;
}
void Tins::ICMP::check(uint16_t new_check) {
void ICMP::check(uint16_t new_check) {
_icmp.check = Endian::host_to_be(new_check);
}
void Tins::ICMP::id(uint16_t new_id) {
void ICMP::id(uint16_t new_id) {
_icmp.un.echo.id = Endian::host_to_be(new_id);
}
void Tins::ICMP::sequence(uint16_t new_seq) {
void ICMP::sequence(uint16_t new_seq) {
_icmp.un.echo.sequence = Endian::host_to_be(new_seq);
}
void Tins::ICMP::gateway(uint32_t new_gw) {
void ICMP::gateway(uint32_t new_gw) {
_icmp.un.gateway = Endian::host_to_be(new_gw);
}
void Tins::ICMP::mtu(uint16_t new_mtu) {
void ICMP::mtu(uint16_t new_mtu) {
_icmp.un.frag.mtu = Endian::host_to_be(new_mtu);
}
void Tins::ICMP::pointer(uint8_t new_pointer) {
void ICMP::pointer(uint8_t new_pointer) {
_icmp.un.pointer = new_pointer;
}
uint32_t Tins::ICMP::header_size() const {
uint32_t ICMP::header_size() const {
return sizeof(icmphdr);
}
void Tins::ICMP::set_echo_request(uint16_t id, uint16_t seq) {
void ICMP::set_echo_request(uint16_t id, uint16_t seq) {
type(ECHO_REQUEST);
this->id(id);
sequence(seq);
}
void Tins::ICMP::set_echo_request() {
set_echo_request(global_id++, global_seq++);
if(global_id == 0xffff)
global_id = 0;
if(global_seq == 0xffff)
global_seq = 0;
}
void Tins::ICMP::set_echo_reply(uint16_t id, uint16_t seq) {
void ICMP::set_echo_reply(uint16_t id, uint16_t seq) {
type(ECHO_REPLY);
this->id(id);
sequence(seq);
}
void Tins::ICMP::set_echo_reply() {
set_echo_reply(global_id++, global_seq++);
if(global_id == 0xffff)
global_id = 0;
if(global_seq == 0xffff)
global_seq = 0;
}
void Tins::ICMP::set_info_request(uint16_t id, uint16_t seq) {
void ICMP::set_info_request(uint16_t id, uint16_t seq) {
type(INFO_REQUEST);
code(0);
this->id(id);
sequence(seq);
}
void Tins::ICMP::set_info_reply(uint16_t id, uint16_t seq) {
void ICMP::set_info_reply(uint16_t id, uint16_t seq) {
type(INFO_REPLY);
code(0);
this->id(id);
sequence(seq);
}
void Tins::ICMP::set_dest_unreachable() {
void ICMP::set_dest_unreachable() {
type(DEST_UNREACHABLE);
}
void Tins::ICMP::set_time_exceeded(bool ttl_exceeded) {
void ICMP::set_time_exceeded(bool ttl_exceeded) {
type(TIME_EXCEEDED);
code((ttl_exceeded) ? 0 : 1);
}
void Tins::ICMP::set_param_problem(bool set_pointer, uint8_t bad_octet) {
void ICMP::set_param_problem(bool set_pointer, uint8_t bad_octet) {
type(PARAM_PROBLEM);
if(set_pointer) {
code(0);
@@ -164,18 +139,20 @@ void Tins::ICMP::set_param_problem(bool set_pointer, uint8_t bad_octet) {
code(1);
}
void Tins::ICMP::set_source_quench() {
void ICMP::set_source_quench() {
type(SOURCE_QUENCH);
}
void Tins::ICMP::set_redirect(uint8_t icode, uint32_t address) {
void ICMP::set_redirect(uint8_t icode, uint32_t address) {
type(REDIRECT);
code(icode);
gateway(address);
}
void Tins::ICMP::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *) {
void ICMP::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *) {
#ifdef TINS_DEBUG
assert(total_sz >= sizeof(icmphdr));
#endif
if(!_icmp.check) {
uint32_t checksum = Utils::do_checksum(buffer + sizeof(icmphdr), buffer + total_sz) +
Utils::do_checksum((uint8_t*)&_icmp, ((uint8_t*)&_icmp) + sizeof(icmphdr));
@@ -187,25 +164,13 @@ void Tins::ICMP::write_serialization(uint8_t *buffer, uint32_t total_sz, const P
_icmp.check = 0;
}
bool Tins::ICMP::matches_response(uint8_t *ptr, uint32_t total_sz) {
bool ICMP::matches_response(const uint8_t *ptr, uint32_t total_sz) const {
if(total_sz < sizeof(icmphdr))
return false;
icmphdr *icmp_ptr = (icmphdr*)ptr;
if(_icmp.type == ECHO_REQUEST) {
return icmp_ptr->type == ECHO_REPLY && icmp_ptr->un.echo.id == _icmp.un.echo.id && icmp_ptr->un.echo.sequence == _icmp.un.echo.sequence;
const icmphdr *icmp_ptr = (const icmphdr*)ptr;
if(_icmp.type == ECHO_REQUEST && icmp_ptr->type == ECHO_REPLY) {
return icmp_ptr->un.echo.id == _icmp.un.echo.id && icmp_ptr->un.echo.sequence == _icmp.un.echo.sequence;
}
return false;
}
Tins::PDU *Tins::ICMP::clone_packet(const uint8_t *ptr, uint32_t total_sz) {
if(total_sz < sizeof(icmphdr))
return 0;
PDU *child = 0, *cloned;
if(total_sz > sizeof(icmphdr)) {
if((child = PDU::clone_inner_pdu(ptr + sizeof(icmphdr), total_sz - sizeof(icmphdr))) == 0)
return 0;
}
cloned = new ICMP(ptr, std::min(total_sz, (uint32_t)sizeof(_icmp)));
cloned->inner_pdu(child);
return cloned;
}
} // namespace Tins

819
src/icmpv6.cpp Normal file
View File

@@ -0,0 +1,819 @@
/*
* 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.
*
*/
#ifdef TINS_DEBUG
#include <cassert>
#endif
#include <cstring>
#include "icmpv6.h"
#include "ipv6.h"
#include "rawpdu.h"
#include "utils.h"
#include "constants.h"
#include "exceptions.h"
namespace Tins {
ICMPv6::ICMPv6(Types tp)
: _options_size(), reach_time(0), retrans_timer(0)
{
std::memset(&_header, 0, sizeof(_header));
type(tp);
}
ICMPv6::ICMPv6(const uint8_t *buffer, uint32_t total_sz)
: _options_size(), reach_time(0), retrans_timer(0)
{
if(total_sz < sizeof(_header))
throw malformed_packet();
std::memcpy(&_header, buffer, sizeof(_header));
buffer += sizeof(_header);
total_sz -= sizeof(_header);
if(has_target_addr()) {
if(total_sz < ipaddress_type::address_size)
throw malformed_packet();
target_addr(buffer);
buffer += ipaddress_type::address_size;
total_sz -= ipaddress_type::address_size;
}
if(has_dest_addr()) {
if(total_sz < ipaddress_type::address_size)
throw malformed_packet();
dest_addr(buffer);
buffer += ipaddress_type::address_size;
total_sz -= ipaddress_type::address_size;
}
if(type() == ROUTER_ADVERT) {
if(total_sz < sizeof(uint32_t) * 2)
throw malformed_packet();
const uint32_t *ptr_32 = (const uint32_t*)buffer;
reach_time = *ptr_32++;
retrans_timer = *ptr_32++;
buffer += sizeof(uint32_t) * 2;
total_sz -= sizeof(uint32_t) * 2;
}
if(has_options())
parse_options(buffer, total_sz);
if(total_sz > 0)
inner_pdu(new RawPDU(buffer, total_sz));
}
void ICMPv6::parse_options(const uint8_t *&buffer, uint32_t &total_sz) {
while(total_sz > 0) {
if(total_sz < 8 || (static_cast<uint32_t>(buffer[1]) * 8) > total_sz || buffer[1] < 1)
throw malformed_packet();
// size(option) = option_size - identifier_size - length_identifier_size
add_option(
option(
buffer[0],
static_cast<uint32_t>(buffer[1]) * 8 - sizeof(uint8_t) * 2,
buffer + 2
)
);
total_sz -= buffer[1] * 8;
buffer += buffer[1] * 8;
}
}
void ICMPv6::type(Types new_type) {
_header.type = new_type;
}
void ICMPv6::code(uint8_t new_code) {
_header.code = new_code;
}
void ICMPv6::checksum(uint16_t new_cksum) {
_header.cksum = Endian::host_to_be(new_cksum);
}
void ICMPv6::identifier(uint16_t new_identifier) {
_header.u_echo.identifier = Endian::host_to_be(new_identifier);
}
void ICMPv6::sequence(uint16_t new_sequence) {
_header.u_echo.sequence = Endian::host_to_be(new_sequence);
}
void ICMPv6::override(small_uint<1> new_override) {
_header.u_nd_advt.override = new_override;
}
void ICMPv6::solicited(small_uint<1> new_solicited) {
_header.u_nd_advt.solicited = new_solicited;
}
void ICMPv6::router(small_uint<1> new_router) {
_header.u_nd_advt.router = new_router;
}
void ICMPv6::hop_limit(uint8_t new_hop_limit) {
_header.u_nd_ra.hop_limit = new_hop_limit;
}
void ICMPv6::router_pref(small_uint<2> new_router_pref) {
_header.u_nd_ra.router_pref = new_router_pref;
}
void ICMPv6::home_agent(small_uint<1> new_home_agent) {
_header.u_nd_ra.home_agent = new_home_agent;
}
void ICMPv6::other(small_uint<1> new_other) {
_header.u_nd_ra.other = new_other;
}
void ICMPv6::managed(small_uint<1> new_managed) {
_header.u_nd_ra.managed = new_managed;
}
void ICMPv6::router_lifetime(uint16_t new_router_lifetime) {
_header.u_nd_ra.router_lifetime = Endian::host_to_be(new_router_lifetime);
}
void ICMPv6::reachable_time(uint32_t new_reachable_time) {
reach_time = Endian::host_to_be(new_reachable_time);
}
void ICMPv6::retransmit_timer(uint32_t new_retrans_timer) {
retrans_timer = Endian::host_to_be(new_retrans_timer);
}
void ICMPv6::target_addr(const ipaddress_type &new_target_addr) {
_target_address = new_target_addr;
}
void ICMPv6::dest_addr(const ipaddress_type &new_dest_addr) {
_dest_address = new_dest_addr;
}
uint32_t ICMPv6::header_size() const {
uint32_t extra = 0;
if(type() == ROUTER_ADVERT)
extra = sizeof(uint32_t) * 2;
return sizeof(_header) + _options_size + extra +
(has_target_addr() ? ipaddress_type::address_size : 0) +
(has_dest_addr() ? ipaddress_type::address_size : 0);
}
bool ICMPv6::matches_response(const uint8_t *ptr, uint32_t total_sz) const {
if(total_sz < sizeof(icmp6hdr))
return false;
const icmp6hdr *hdr_ptr = (const icmp6hdr*)ptr;
if(type() == ECHO_REQUEST && hdr_ptr->type == ECHO_REPLY)
return hdr_ptr->u_echo.identifier == _header.u_echo.identifier &&
hdr_ptr->u_echo.sequence == _header.u_echo.sequence;
return false;
}
void ICMPv6::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *parent) {
#ifdef TINS_DEBUG
assert(total_sz >= header_size());
#endif
icmp6hdr* ptr_header = (icmp6hdr*)buffer;
std::memcpy(buffer, &_header, sizeof(_header));
buffer += sizeof(_header);
total_sz -= sizeof(_header);
if(has_target_addr()) {
buffer = _target_address.copy(buffer);
total_sz -= sizeof(ipaddress_type::address_size);
}
if(has_dest_addr()) {
buffer = _dest_address.copy(buffer);
total_sz -= sizeof(ipaddress_type::address_size);
}
if(type() == ROUTER_ADVERT) {
*(uint32_t*)buffer = reach_time;
buffer += sizeof(uint32_t);
*(uint32_t*)buffer = retrans_timer;
buffer += sizeof(uint32_t);
total_sz -= sizeof(uint32_t) * 2;
}
for(options_type::const_iterator it = _options.begin(); it != _options.end(); ++it) {
#ifdef TINS_DEBUG
assert(total_sz >= it->data_size() + sizeof(uint8_t) * 2);
// total_sz is only used if TINS_DEBUG is defined.
total_sz -= it->data_size() + sizeof(uint8_t) * 2;
#endif
buffer = write_option(*it, buffer);
}
if(!_header.cksum) {
const Tins::IPv6 *ipv6 = dynamic_cast<const Tins::IPv6*>(parent);
if(ipv6) {
uint32_t checksum = Utils::pseudoheader_checksum(
ipv6->src_addr(),
ipv6->dst_addr(),
size(),
Constants::IP::PROTO_ICMPV6
) + Utils::do_checksum((uint8_t*)ptr_header, buffer);
while (checksum >> 16)
checksum = (checksum & 0xffff) + (checksum >> 16);
ptr_header->cksum = Endian::host_to_be<uint16_t>(~checksum);
}
}
}
// can i haz more?
bool ICMPv6::has_options() const {
return type() == NEIGHBOUR_SOLICIT ||
type() == ROUTER_ADVERT;
}
void ICMPv6::add_option(const option &option) {
internal_add_option(option);
_options.push_back(option);
}
void ICMPv6::internal_add_option(const option &option) {
_options_size += option.data_size() + sizeof(uint8_t) * 2;
}
uint8_t *ICMPv6::write_option(const option &opt, uint8_t *buffer) {
*buffer++ = opt.option();
*buffer++ = (opt.length_field() + sizeof(uint8_t) * 2) / 8;
return std::copy(opt.data_ptr(), opt.data_ptr() + opt.data_size(), buffer);
}
const ICMPv6::option *ICMPv6::search_option(OptionTypes id) const {
for(options_type::const_iterator it = _options.begin(); it != _options.end(); ++it) {
if(it->option() == id)
return &*it;
}
return 0;
}
// ********************************************************************
// Option setters
// ********************************************************************
void ICMPv6::source_link_layer_addr(const hwaddress_type &addr) {
add_option(option(SOURCE_ADDRESS, addr.begin(), addr.end()));
}
void ICMPv6::target_link_layer_addr(const hwaddress_type &addr) {
add_option(option(TARGET_ADDRESS, addr.begin(), addr.end()));
}
void ICMPv6::prefix_info(prefix_info_type info) {
uint8_t buffer[2 + sizeof(uint32_t) * 3 + ipaddress_type::address_size];
buffer[0] = info.prefix_len;
buffer[1] = (info.L << 7) | (info.A << 6);
*(uint32_t*)(buffer + 2) = Endian::host_to_be(info.valid_lifetime);
*(uint32_t*)(buffer + 2 + sizeof(uint32_t)) = Endian::host_to_be(info.preferred_lifetime);
*(uint32_t*)(buffer + 2 + sizeof(uint32_t) * 2) = 0;
info.prefix.copy(buffer + 2 + sizeof(uint32_t) * 3);
add_option(
option(PREFIX_INFO, buffer, buffer + sizeof(buffer))
);
}
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);
add_option(option(REDIRECT_HEADER, data.begin(), data.end()));
}
void ICMPv6::mtu(uint32_t value) {
uint8_t buffer[sizeof(uint16_t) + sizeof(uint32_t)] = {0};
*((uint32_t*)(buffer + sizeof(uint16_t))) = Endian::host_to_be(value);
add_option(option(MTU, sizeof(buffer), buffer));
}
void ICMPv6::shortcut_limit(uint8_t value) {
uint8_t buffer[sizeof(uint16_t) + sizeof(uint32_t)] = {0};
buffer[0] = value;
add_option(option(NBMA_SHORT_LIMIT, sizeof(buffer), buffer));
}
void ICMPv6::new_advert_interval(uint32_t value) {
uint8_t buffer[sizeof(uint16_t) + sizeof(uint32_t)] = {0};
*((uint32_t*)(buffer + sizeof(uint16_t))) = Endian::host_to_be(value);
add_option(option(ADVERT_INTERVAL, sizeof(buffer), buffer));
}
void ICMPv6::new_home_agent_info(const new_ha_info_type &value) {
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);
add_option(option(HOME_AGENT_INFO, sizeof(buffer), buffer));
}
void ICMPv6::source_addr_list(const addr_list_type &value) {
add_addr_list(S_ADDRESS_LIST, value);
}
void ICMPv6::target_addr_list(const addr_list_type &value) {
add_addr_list(T_ADDRESS_LIST, value);
}
void ICMPv6::add_addr_list(uint8_t type, const addr_list_type &value) {
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.insert(buffer.end(), it->begin(), it->end());
add_option(option(type, buffer.begin(), buffer.end()));
}
void ICMPv6::rsa_signature(const rsa_sign_type &value) {
uint32_t total_sz = 4 + sizeof(value.key_hash) + value.signature.size();
uint8_t padding = 8 - total_sz % 8;
if(padding == 8)
padding = 0;
std::vector<uint8_t> buffer;
buffer.reserve(total_sz + padding);
buffer.insert(buffer.end(), 2, 0);
buffer.insert(buffer.end(), value.key_hash, value.key_hash + sizeof(value.key_hash));
buffer.insert(buffer.end(), value.signature.begin(), value.signature.end());
buffer.insert(buffer.end(), padding, 0);
add_option(option(RSA_SIGN, buffer.begin(), buffer.end()));
}
void ICMPv6::timestamp(uint64_t 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);
add_option(option(TIMESTAMP, buffer.begin(), buffer.end()));
}
void ICMPv6::nonce(const nonce_type &value) {
add_option(option(NONCE, value.begin(), value.end()));
}
void ICMPv6::ip_prefix(const ip_prefix_type &value) {
std::vector<uint8_t> buffer;
buffer.reserve(6 + ipaddress_type::address_size);
buffer.push_back(value.option_code);
buffer.push_back(value.prefix_len);
// reserved
buffer.insert(buffer.end(), sizeof(uint32_t), 0);
buffer.insert(buffer.end(), value.address.begin(), value.address.end());
add_option(option(IP_PREFIX, buffer.begin(), buffer.end()));
}
void ICMPv6::link_layer_addr(lladdr_type value) {
value.address.insert(value.address.begin(), value.option_code);
uint8_t padding = 8 - (2 + value.address.size()) % 8;
if(padding == 8)
padding = 0;
value.address.insert(value.address.end(), padding, 0);
add_option(option(LINK_ADDRESS, value.address.begin(), value.address.end()));
}
void ICMPv6::naack(const naack_type &value) {
uint8_t buffer[6];
buffer[0] = value.first;
buffer[1] = value.second;
add_option(option(NAACK, buffer, buffer + sizeof(buffer)));
}
void ICMPv6::map(const map_type &value) {
uint8_t buffer[sizeof(uint8_t) * 2 + sizeof(uint32_t) + ipaddress_type::address_size];
buffer[0] = value.dist << 4 | value.pref;
buffer[1] = value.r << 7;
*(uint32_t*)(buffer + 2) = Endian::host_to_be(value.valid_lifetime);
value.address.copy(buffer + 2 + sizeof(uint32_t));
add_option(option(MAP, buffer, buffer + sizeof(buffer)));
}
void ICMPv6::route_info(const route_info_type &value) {
uint8_t padding = 8 - value.prefix.size() % 8;
if(padding == 8)
padding = 0;
std::vector<uint8_t> buffer(2 + sizeof(uint32_t) + value.prefix.size() + padding);
buffer[0] = value.prefix_len;
buffer[1] = value.pref << 3;
*(uint32_t*)&buffer[2] = Endian::host_to_be(value.route_lifetime);
// copy the prefix and then fill with padding
buffer.insert(
std::copy(value.prefix.begin(), value.prefix.end(), buffer.begin() + 2 + sizeof(uint32_t)),
padding,
0
);
add_option(option(ROUTE_INFO, buffer.begin(), buffer.end()));
}
void ICMPv6::recursive_dns_servers(const recursive_dns_type &value) {
std::vector<uint8_t> buffer(
2 + sizeof(uint32_t) + value.servers.size() * ipaddress_type::address_size
);
buffer[0] = buffer[1] = 0;
*(uint32_t*)&buffer[2] = Endian::host_to_be(value.lifetime);
std::vector<uint8_t>::iterator out = buffer.begin() + 2 + sizeof(uint32_t);
typedef recursive_dns_type::servers_type::const_iterator iterator;
for(iterator it = value.servers.begin(); it != value.servers.end(); ++it)
out = it->copy(out);
add_option(option(RECURSIVE_DNS_SERV, buffer.begin(), buffer.end()));
}
void ICMPv6::handover_key_request(const handover_key_req_type &value) {
uint8_t padding = 8 - (value.key.size() + 4) % 8;
if(padding == 8)
padding = 0;
std::vector<uint8_t> buffer(2 + value.key.size() + padding);
buffer[0] = padding;
buffer[1] = value.AT << 4;
// copy the key, and fill with padding
std::fill(
std::copy(value.key.begin(), value.key.end(), buffer.begin() + 2),
buffer.end(),
0
);
add_option(option(HANDOVER_KEY_REQ, buffer.begin(), buffer.end()));
}
void ICMPv6::handover_key_reply(const handover_key_reply_type &value) {
const uint32_t data_size = value.key.size() + 2 + sizeof(uint16_t);
uint8_t padding = 8 - (data_size+2) % 8;
if(padding == 8)
padding = 0;
std::vector<uint8_t> buffer(data_size + padding);
buffer[0] = padding;
buffer[1] = value.AT << 4;
*(uint16_t*)&buffer[2] = Endian::host_to_be(value.lifetime);
// copy the key, and fill with padding
std::fill(
std::copy(value.key.begin(), value.key.end(), buffer.begin() + 2 + sizeof(uint16_t)),
buffer.end(),
0
);
add_option(option(HANDOVER_KEY_REPLY, buffer.begin(), buffer.end()));
}
void ICMPv6::handover_assist_info(const handover_assist_info_type &value) {
const uint32_t data_size = value.hai.size() + 2;
uint8_t padding = 8 - (data_size+2) % 8;
if(padding == 8)
padding = 0;
std::vector<uint8_t> buffer(data_size + padding);
buffer[0] = value.option_code;
buffer[1] = static_cast<uint8_t>(value.hai.size());
// copy hai + padding
buffer.insert(
std::copy(value.hai.begin(), value.hai.end(), buffer.begin() + 2),
padding,
0
);
add_option(option(HANDOVER_ASSIST_INFO, buffer.begin(), buffer.end()));
}
void ICMPv6::mobile_node_identifier(const mobile_node_id_type &value) {
const uint32_t data_size = value.mn.size() + 2;
uint8_t padding = 8 - (data_size+2) % 8;
if(padding == 8)
padding = 0;
std::vector<uint8_t> buffer(data_size + padding);
buffer[0] = value.option_code;
buffer[1] = static_cast<uint8_t>(value.mn.size());
// copy mn + padding
buffer.insert(
std::copy(value.mn.begin(), value.mn.end(), buffer.begin() + 2),
padding,
0
);
add_option(option(MOBILE_NODE_ID, buffer.begin(), buffer.end()));
}
void ICMPv6::dns_search_list(const dns_search_list_type &value) {
// at least it's got this size
std::vector<uint8_t> buffer(2 + sizeof(uint32_t));
*(uint32_t*)&buffer[2] = Endian::host_to_be(value.lifetime);
typedef dns_search_list_type::domains_type::const_iterator iterator;
for(iterator it = value.domains.begin(); it != value.domains.end(); ++it) {
size_t prev = 0, index;
do {
index = it->find('.', prev);
std::string::const_iterator end = (index == std::string::npos) ? it->end() : (it->begin() + index);
buffer.push_back(end - (it->begin() + prev));
buffer.insert(buffer.end(), it->begin() + prev, end);
prev = index + 1;
} while(index != std::string::npos);
// delimiter
buffer.push_back(0);
}
uint8_t padding = 8 - (buffer.size() + 2) % 8;
if(padding == 8)
padding = 0;
buffer.insert(buffer.end(), padding, 0);
add_option(option(DNS_SEARCH_LIST, buffer.begin(), buffer.end()));
}
// ********************************************************************
// Option getters
// ********************************************************************
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());
}
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());
}
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;
}
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);
}
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)));
}
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();
}
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_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))
);
}
ICMPv6::addr_list_type ICMPv6::source_addr_list() const {
return search_addr_list(S_ADDRESS_LIST);
}
ICMPv6::addr_list_type ICMPv6::target_addr_list() const {
return search_addr_list(T_ADDRESS_LIST);
}
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();
addr_list_type output;
const uint8_t *ptr = opt->data_ptr() + 6, *end = opt->data_ptr() + opt->data_size();
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;
}
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());
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::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::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();
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());
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();
map_type output;
output.dist = (*ptr >> 4) & 0x0f;
output.pref = *ptr++ & 0x0f;
output.r = (*ptr++ >> 7) & 0x01;
output.valid_lifetime = *(uint32_t*)ptr;
ptr += sizeof(uint32_t);
output.address = ptr;
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();
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());
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();
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)
throw option_not_found();
output.servers.push_back(ptr);
ptr += 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();
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()));
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();
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()));
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();
handover_assist_info_type output;
output.option_code = *ptr++;
if((end - ptr - 1) < *ptr)
throw option_not_found();
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();
mobile_node_id_type output;
output.option_code = *ptr++;
if((end - ptr - 1) < *ptr)
throw option_not_found();
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();
dns_search_list_type output;
output.lifetime = Endian::be_to_host(*(uint32_t*)(ptr + 2));
ptr += 2 + sizeof(uint32_t);
while(ptr < end && *ptr) {
std::string domain;
while(ptr < end && *ptr && *ptr < (end - ptr)) {
if(!domain.empty())
domain.push_back('.');
domain.insert(domain.end(), ptr + 1, ptr + *ptr + 1);
ptr += *ptr + 1;
}
// not enough size
if(ptr < end && *ptr != 0)
throw option_not_found();
output.domains.push_back(domain);
ptr++;
}
return output;
}
}

View File

@@ -1,160 +0,0 @@
/*
* Copyright (c) 2012, Nasel
* 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 <cassert>
#include <cstring>
#include <stdexcept>
#include <algorithm>
#ifndef WIN32
#include <net/ethernet.h>
#include <netinet/in.h>
#include <netpacket/packet.h>
#endif
#include "ieee802_3.h"
#include "packet_sender.h"
#include "llc.h"
namespace Tins {
const IEEE802_3::address_type IEEE802_3::BROADCAST("ff:ff:ff:ff:ff:ff");
IEEE802_3::IEEE802_3(const NetworkInterface& iface,
const address_type &dst_hw_addr, const address_type &src_hw_addr,
PDU* child)
: PDU(child)
{
memset(&_eth, 0, sizeof(ethhdr));
this->dst_addr(dst_hw_addr);
this->src_addr(src_hw_addr);
this->iface(iface);
this->_eth.length = 0;
}
IEEE802_3::IEEE802_3(const uint8_t *buffer, uint32_t total_sz)
{
if(total_sz < sizeof(ethhdr))
throw std::runtime_error("Not enough size for an ethernetII header in the buffer.");
memcpy(&_eth, buffer, sizeof(ethhdr));
buffer += sizeof(ethhdr);
total_sz -= sizeof(ethhdr);
if(total_sz)
inner_pdu(new Tins::LLC(buffer, total_sz));
}
void IEEE802_3::dst_addr(const address_type &new_dst_mac) {
std::copy(new_dst_mac.begin(), new_dst_mac.end(), _eth.dst_mac);
}
void IEEE802_3::src_addr(const address_type &new_src_mac) {
std::copy(new_src_mac.begin(), new_src_mac.end(), _eth.src_mac);
}
void IEEE802_3::iface(const NetworkInterface &new_iface) {
_iface = new_iface;
}
void IEEE802_3::length(uint16_t new_length) {
this->_eth.length = Endian::host_to_be(new_length);
}
uint32_t IEEE802_3::header_size() const {
return sizeof(ethhdr);
}
#ifndef WIN32
void IEEE802_3::send(PacketSender &sender) {
if(!_iface)
throw std::runtime_error("Interface has not been set");
struct sockaddr_ll addr;
memset(&addr, 0, sizeof(struct sockaddr_ll));
addr.sll_family = Endian::host_to_be<uint16_t>(PF_PACKET);
addr.sll_protocol = Endian::host_to_be<uint16_t>(ETH_P_ALL);
addr.sll_halen = address_type::address_size;
addr.sll_ifindex = _iface.id();
memcpy(&(addr.sll_addr), _eth.dst_mac, sizeof(_eth.dst_mac));
sender.send_l2(*this, (struct sockaddr*)&addr, (uint32_t)sizeof(addr));
}
#endif // WIN32
bool IEEE802_3::matches_response(uint8_t *ptr, uint32_t total_sz) {
if(total_sz < sizeof(ethhdr))
return false;
ethhdr *eth_ptr = (ethhdr*)ptr;
if(!memcmp(eth_ptr->dst_mac, _eth.src_mac, sizeof(_eth.src_mac))) {
return true;
}
return false;
}
void IEEE802_3::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *parent) {
uint32_t my_sz = header_size();
bool set_length = _eth.length == 0;
assert(total_sz >= my_sz);
if (set_length)
_eth.length = Endian::host_to_be(size() - sizeof(_eth));
memcpy(buffer, &_eth, sizeof(ethhdr));
if (set_length)
_eth.length = 0;
}
#ifndef WIN32
PDU *IEEE802_3::recv_response(PacketSender &sender) {
struct sockaddr_ll addr;
memset(&addr, 0, sizeof(struct sockaddr_ll));
addr.sll_family = Endian::host_to_be<uint16_t>(PF_PACKET);
addr.sll_protocol = Endian::host_to_be<uint16_t>(ETH_P_802_3);
addr.sll_halen = address_type::address_size;
addr.sll_ifindex = _iface.id();
memcpy(&(addr.sll_addr), _eth.dst_mac, sizeof(_eth.dst_mac));
return sender.recv_l2(*this, (struct sockaddr*)&addr, (uint32_t)sizeof(addr));
}
#endif // WIN32
PDU *IEEE802_3::clone_packet(const uint8_t *ptr, uint32_t total_sz) {
if(total_sz < sizeof(_eth))
return 0;
PDU *child = 0, *cloned;
if(total_sz > sizeof(_eth)) {
if((child = PDU::clone_inner_pdu(ptr + sizeof(_eth), total_sz - sizeof(_eth))) == 0)
return 0;
}
cloned = new IEEE802_3(ptr, std::min(total_sz, (uint32_t)sizeof(_eth)));
cloned->inner_pdu(child);
return cloned;
}
}

153
src/internals.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 "internals.h"
#include "ip.h"
#include "ethernetII.h"
#include "ieee802_3.h"
#include "radiotap.h"
#include "dot11.h"
#include "ipv6.h"
#include "arp.h"
#include "eapol.h"
#include "rawpdu.h"
#include "dot1q.h"
#include "pppoe.h"
using std::string;
namespace Tins {
namespace Internals {
bool from_hex(const string &str, uint32_t &result) {
unsigned i(0);
result = 0;
while(i < str.size()) {
uint8_t tmp;
if(str[i] >= 'A' && str[i] <= 'F')
tmp = (str[i] - 'A' + 10);
else if(str[i] >= '0' && str[i] <= '9')
tmp = (str[i] - '0');
else
return false;
result = (result << 4) | tmp;
i++;
}
return true;
}
void skip_line(std::istream &input) {
int c = 0;
while(c != '\n' && input)
c = input.get();
}
Tins::PDU *pdu_from_flag(Constants::Ethernet::e flag, const uint8_t *buffer,
uint32_t size, bool rawpdu_on_no_match)
{
switch(flag) {
case Tins::Constants::Ethernet::IP:
return new Tins::IP(buffer, size);
case Constants::Ethernet::IPV6:
return new Tins::IPv6(buffer, size);
case Tins::Constants::Ethernet::ARP:
return new Tins::ARP(buffer, size);
case Tins::Constants::Ethernet::PPPOED:
return new Tins::PPPoE(buffer, size);
case Tins::Constants::Ethernet::EAPOL:
return Tins::EAPOL::from_bytes(buffer, size);
case Tins::Constants::Ethernet::VLAN:
return new Tins::Dot1Q(buffer, size);
default:
return rawpdu_on_no_match ? new RawPDU(buffer, size) : 0;
};
}
Tins::PDU *pdu_from_flag(PDU::PDUType type, const uint8_t *buffer, uint32_t size)
{
switch(type) {
case Tins::PDU::ETHERNET_II:
return new Tins::EthernetII(buffer, size);
case Tins::PDU::IP:
return new Tins::IP(buffer, size);
case Tins::PDU::IPv6:
return new Tins::IPv6(buffer, size);
case Tins::PDU::ARP:
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);
default:
return 0;
};
}
Constants::Ethernet::e pdu_flag_to_ether_type(PDU::PDUType flag) {
switch (flag) {
case PDU::IP:
return Constants::Ethernet::IP;
case PDU::IPv6:
return Constants::Ethernet::IPV6;
case PDU::ARP:
return Constants::Ethernet::ARP;
case PDU::DOT1Q:
return Constants::Ethernet::VLAN;
case PDU::PPPOE:
return Constants::Ethernet::PPPOED;
default:
return Constants::Ethernet::UNKNOWN;
}
}
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, Nasel
* Copyright (c) 2012, Matias Fontanini
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -29,15 +29,20 @@
#include <stdexcept>
#include <cstring>
#ifdef TINS_DEBUG
#include <cassert>
#endif
#include <algorithm>
#ifndef WIN32
#include <netdb.h>
#include <sys/socket.h>
#include <netinet/in.h>
#else
#define NOMINMAX
#include <winsock2.h>
#endif
#include "ip.h"
#include "ipv6.h"
#include "tcp.h"
#include "udp.h"
#include "icmp.h"
@@ -45,6 +50,8 @@
#include "utils.h"
#include "packet_sender.h"
#include "constants.h"
#include "network_interface.h"
#include "exceptions.h"
using std::list;
@@ -52,8 +59,7 @@ namespace Tins {
const uint8_t IP::DEFAULT_TTL = 128;
IP::IP(address_type ip_dst, address_type ip_src, PDU *child)
: PDU(child)
IP::IP(address_type ip_dst, address_type ip_src)
{
init_ip_fields();
this->dst_addr(ip_dst);
@@ -62,18 +68,17 @@ IP::IP(address_type ip_dst, address_type ip_src, PDU *child)
IP::IP(const uint8_t *buffer, uint32_t total_sz)
{
const char *msg = "Not enough size for an IP header in the buffer.";
if(total_sz < sizeof(iphdr))
throw std::runtime_error(msg);
throw malformed_packet();
std::memcpy(&_ip, buffer, sizeof(iphdr));
/* Options... */
/* Establish beginning and ending of the options */
const uint8_t* ptr_buffer = buffer + sizeof(iphdr);
if(total_sz < head_len() * sizeof(uint32_t))
throw std::runtime_error(msg);
throw malformed_packet();
if(head_len() * sizeof(uint32_t) < sizeof(iphdr))
throw std::runtime_error("Malformed head len field");
throw malformed_packet();
buffer += head_len() * sizeof(uint32_t);
_options_size = 0;
@@ -84,47 +89,28 @@ IP::IP(const uint8_t *buffer, uint32_t total_sz)
option_identifier opt_type;
memcpy(&opt_type, ptr_buffer, sizeof(uint8_t));
ptr_buffer++;
switch (opt_type.number) {
if(opt_type.number > NOOP) {
/* Multibyte options with length as second byte */
case SEC:
case LSSR:
case TIMESTAMP:
case EXTSEC:
case RR:
case SID:
case SSRR:
case MTUPROBE:
case MTUREPLY:
case EIP:
case TR:
case ADDEXT:
case RTRALT:
case SDB:
case DPS:
case UMP:
case QS:
if(ptr_buffer == buffer || *ptr_buffer == 0)
throw std::runtime_error(msg);
{
const uint8_t data_size = *ptr_buffer - 2;
if(data_size > 0) {
ptr_buffer++;
if(buffer - ptr_buffer < data_size)
throw std::runtime_error(msg);
_ip_options.push_back(ip_option(opt_type, ptr_buffer, ptr_buffer + data_size));
}
else
_ip_options.push_back(ip_option(opt_type));
}
if(ptr_buffer == buffer || *ptr_buffer == 0)
throw malformed_packet();
ptr_buffer += _ip_options.back().data_size() + 1;
break;
default:
_ip_options.push_back(ip_option(opt_type));
break;
const uint8_t data_size = *ptr_buffer - 2;
if(data_size > 0) {
ptr_buffer++;
if(buffer - ptr_buffer < data_size)
throw malformed_packet();
_ip_options.push_back(option(opt_type, ptr_buffer, ptr_buffer + data_size));
}
else
_ip_options.push_back(option(opt_type));
ptr_buffer += _ip_options.back().data_size() + 1;
_options_size += _ip_options.back().data_size() + 2;
}
else {
_ip_options.push_back(option(opt_type));
_options_size++;
}
_options_size += _ip_options.back().data_size() + 2;
}
uint8_t padding = _options_size % 4;
_padded_options_size = padding ? (_options_size - padding + 4) : _options_size;
@@ -141,6 +127,9 @@ IP::IP(const uint8_t *buffer, uint32_t total_sz)
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:
inner_pdu(new Tins::RawPDU(buffer, total_sz));
break;
@@ -183,7 +172,7 @@ void IP::protocol(uint8_t new_protocol) {
_ip.protocol = new_protocol;
}
void IP::check(uint16_t new_check) {
void IP::checksum(uint16_t new_check) {
_ip.check = Endian::host_to_be(new_check);
}
@@ -225,7 +214,7 @@ void IP::security(const security_type &data) {
array[6] = ((value >> 16) & 0xff);
add_option(
ip_option(
option(
130,
sizeof(array),
array
@@ -236,7 +225,7 @@ void IP::security(const security_type &data) {
void IP::stream_identifier(uint16_t stream_id) {
stream_id = Endian::host_to_be(stream_id);
add_option(
ip_option(
option(
136,
sizeof(uint16_t),
(const uint8_t*)&stream_id
@@ -258,7 +247,7 @@ void IP::add_route_option(option_identifier id, const generic_route_option_type
opt_data[1 + i * 4 + 3] = (ip >> 24) & 0xff;
}
add_option(
ip_option(
option(
id,
opt_data.size(),
&opt_data[0]
@@ -267,7 +256,7 @@ 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 ip_option *option = search_option(id);
const option *option = search_option(id);
if(!option || option->data_size() < 1 + sizeof(uint32_t) ||
((option->data_size() - 1) % sizeof(uint32_t)) != 0)
throw option_not_found();
@@ -281,7 +270,7 @@ IP::generic_route_option_type IP::search_route_option(option_identifier id) cons
}
IP::security_type IP::security() const {
const ip_option *option = search_option(130);
const option *option = search_option(130);
if(!option || option->data_size() < 9)
throw option_not_found();
security_type output;
@@ -297,35 +286,42 @@ IP::security_type IP::security() const {
}
uint16_t IP::stream_identifier() const {
const ip_option *option = search_option(136);
const option *option = search_option(136);
if(!option || option->data_size() != sizeof(uint16_t))
throw option_not_found();
return Endian::be_to_host(*(const uint16_t*)option->data_ptr());
}
void IP::add_option(const ip_option &option) {
_ip_options.push_back(option);
_options_size += 1 + option.data_size();
void IP::add_option(const option &opt) {
internal_add_option(opt);
_ip_options.push_back(opt);
}
void IP::internal_add_option(const option &opt) {
_options_size += 1 + opt.data_size();
uint8_t padding = _options_size % 4;
_padded_options_size = padding ? (_options_size - padding + 4) : _options_size;
}
const IP::ip_option *IP::search_option(option_identifier id) const {
for(std::list<ip_option>::const_iterator it = _ip_options.begin(); it != _ip_options.end(); ++it) {
const IP::option *IP::search_option(option_identifier id) const {
for(options_type::const_iterator it = _ip_options.begin(); it != _ip_options.end(); ++it) {
if(it->option() == id)
return &(*it);
}
return 0;
}
uint8_t* IP::write_option(const ip_option &opt, uint8_t* buffer) {
uint8_t* IP::write_option(const option &opt, uint8_t* buffer) {
option_identifier opt_type = opt.option();
memcpy(buffer, &opt_type, 1);
if(*buffer <= 1)
return ++buffer;
buffer++;
*(buffer++) = opt.data_size() + 2;
std::copy(opt.data_ptr(), opt.data_ptr() + opt.data_size(), buffer);
buffer += opt.data_size();
return buffer;
*buffer = opt.length_field();
if(opt.data_size() == opt.length_field())
*buffer += 2;
buffer++;
return std::copy(opt.data_ptr(), opt.data_ptr() + opt.data_size(), buffer);
}
/* Virtual method overriding. */
@@ -334,33 +330,54 @@ uint32_t IP::header_size() const {
return sizeof(iphdr) + _padded_options_size;
}
void IP::send(PacketSender& sender) {
struct sockaddr_in link_addr;
PacketSender::SocketType type = PacketSender::IP_SOCKET;
PacketSender::SocketType pdu_type_to_sender_type(PDU::PDUType type) {
switch(type) {
case PDU::TCP:
return PacketSender::IP_TCP_SOCKET;
case PDU::UDP:
return PacketSender::IP_UDP_SOCKET;
case PDU::ICMP:
return PacketSender::ICMP_SOCKET;
default:
return PacketSender::IP_RAW_SOCKET;
}
}
void IP::send(PacketSender& sender, const NetworkInterface &) {
sockaddr_in link_addr;
PacketSender::SocketType type = PacketSender::IP_RAW_SOCKET;
link_addr.sin_family = AF_INET;
link_addr.sin_port = 0;
link_addr.sin_addr.s_addr = _ip.daddr;
if(inner_pdu() && inner_pdu()->pdu_type() == PDU::ICMP)
type = PacketSender::ICMP_SOCKET;
if(inner_pdu())
type = pdu_type_to_sender_type(inner_pdu()->pdu_type());
sender.send_l3(*this, (struct sockaddr*)&link_addr, sizeof(link_addr), type);
}
PDU *IP::recv_response(PacketSender &sender) {
struct sockaddr_in link_addr;
PacketSender::SocketType type = PacketSender::IP_SOCKET;
link_addr.sin_family = AF_INET;
link_addr.sin_port = 0;
link_addr.sin_addr.s_addr = _ip.daddr;
if(inner_pdu() && inner_pdu()->pdu_type() == PDU::ICMP)
type = PacketSender::ICMP_SOCKET;
PDU *IP::recv_response(PacketSender &sender, const NetworkInterface &) {
sockaddr_in link_addr;
PacketSender::SocketType type = PacketSender::IP_RAW_SOCKET;
std::memset(&link_addr, 0, sizeof(link_addr));
if(inner_pdu())
type = pdu_type_to_sender_type(inner_pdu()->pdu_type());
return sender.recv_l3(*this, (struct sockaddr*)&link_addr, sizeof(link_addr), type);
return sender.recv_l3(*this, 0, sizeof(link_addr), type);
}
void IP::prepare_for_serialize(const PDU *parent) {
if(!parent && _ip.saddr == 0) {
NetworkInterface iface(dst_addr());
src_addr(iface.addresses().ip_addr);
}
}
void IP::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU* parent) {
uint32_t my_sz = header_size();
#ifdef TINS_DEBUG
assert(total_sz >= my_sz);
#endif
checksum(0);
if(inner_pdu()) {
uint32_t new_flag;
switch(inner_pdu()->pdu_type()) {
@@ -383,50 +400,41 @@ void IP::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU* pare
protocol(new_flag);
//flag(new_flag);
}
#if __FreeBSD__ || defined(__FreeBSD_kernel__)
if(!parent)
total_sz = Endian::host_to_be<uint16_t>(total_sz);
#endif
tot_len(total_sz);
head_len(my_sz / sizeof(uint32_t));
memcpy(buffer, &_ip, sizeof(_ip));
uint8_t* ptr_buffer = buffer + sizeof(_ip);
for(list<ip_option>::iterator it = _ip_options.begin(); it != _ip_options.end(); ++it)
for(options_type::const_iterator it = _ip_options.begin(); it != _ip_options.end(); ++it) {
ptr_buffer = write_option(*it, ptr_buffer);
}
memset(buffer + sizeof(_ip) + _options_size, 0, _padded_options_size - _options_size);
if(parent && !_ip.check) {
uint32_t checksum = Utils::do_checksum(buffer, buffer + sizeof(_ip) + _padded_options_size);
while (checksum >> 16)
checksum = (checksum & 0xffff) + (checksum >> 16);
((iphdr*)buffer)->check = Endian::host_to_be<uint16_t>(~checksum);
this->check(0);
if(parent) {
uint32_t check = Utils::do_checksum(buffer, buffer + sizeof(_ip) + _padded_options_size);
while (check >> 16)
check = (check & 0xffff) + (check >> 16);
checksum(~check);
((iphdr*)buffer)->check = _ip.check;
}
}
bool IP::matches_response(uint8_t *ptr, uint32_t total_sz) {
bool IP::matches_response(const uint8_t *ptr, uint32_t total_sz) const {
if(total_sz < sizeof(iphdr))
return false;
iphdr *ip_ptr = (iphdr*)ptr;
if(_ip.daddr == ip_ptr->saddr && _ip.saddr == ip_ptr->daddr) {
uint32_t sz = _ip.ihl * sizeof(uint32_t);
const iphdr *ip_ptr = (const iphdr*)ptr;
// checks for broadcast addr
if((_ip.saddr == ip_ptr->daddr && (_ip.daddr == ip_ptr->saddr || _ip.daddr == 0xffffffff)) ||
(_ip.daddr == 0xffffffff && _ip.saddr == 0)) {
uint32_t sz = std::min<uint32_t>(_ip.ihl * sizeof(uint32_t), total_sz);
return inner_pdu() ? inner_pdu()->matches_response(ptr + sz, total_sz - sz) : true;
}
return false;
}
PDU *IP::clone_packet(const uint8_t *ptr, uint32_t total_sz) {
if(total_sz < sizeof(iphdr))
return 0;
const iphdr *ip_ptr = (iphdr*)ptr;
uint32_t sz = ip_ptr->ihl * sizeof(uint32_t);
if(total_sz < sz)
return 0;
PDU *child = 0, *cloned;
if(total_sz > sz) {
if((child = PDU::clone_inner_pdu(ptr + sizeof(_ip), total_sz - sizeof(_ip))) == 0)
return 0;
}
cloned = new IP(ptr, std::min(total_sz, (uint32_t)(Endian::be_to_host(ip_ptr->tot_len) * sizeof(uint32_t))));
cloned->inner_pdu(child);
return cloned;
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, Nasel
* Copyright (c) 2012, Matias Fontanini
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without

274
src/ipv6.cpp Normal file
View File

@@ -0,0 +1,274 @@
/*
* 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>
#ifdef TINS_DEBUG
#include <cassert>
#endif
#ifndef WIN32
#include <netinet/in.h>
#include <sys/socket.h>
#else
#include <ws2tcpip.h>
#endif
#include <algorithm>
#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"
namespace Tins {
IPv6::IPv6(address_type ip_dst, address_type ip_src, PDU *child)
: headers_size(0)
{
std::memset(&_header, 0, sizeof(_header));
version(6);
dst_addr(ip_dst);
src_addr(ip_src);
}
IPv6::IPv6(const uint8_t *buffer, uint32_t total_sz)
: headers_size(0) {
if(total_sz < sizeof(_header))
throw malformed_packet();
std::memcpy(&_header, buffer, sizeof(_header));
buffer += sizeof(_header);
total_sz -= sizeof(_header);
uint8_t current_header = _header.next_header;
while(total_sz) {
if(is_extension_header(current_header)) {
if(total_sz < 8)
throw malformed_packet();
// every ext header is at least 8 bytes long
// minus one, from the next_header field.
uint32_t size = static_cast<uint32_t>(buffer[1]) + 8;
// -1 -> next header identifier
if(total_sz < size)
throw malformed_packet();
// minus one, from the size field
add_ext_header(
ext_header(buffer[0], size - sizeof(uint8_t)*2, buffer + 2)
);
current_header = buffer[0];
buffer += size;
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(new Tins::RawPDU(buffer, total_sz));
break;
}
total_sz = 0;
}
}
}
bool IPv6::is_extension_header(uint8_t header_id) {
return header_id == HOP_BY_HOP || header_id == DESTINATION_ROUTING_OPTIONS
|| header_id == ROUTING || header_id == FRAGMENT || header_id == AUTHENTICATION
|| header_id == SECURITY_ENCAPSULATION || header_id == DESTINATION_OPTIONS
|| header_id == MOBILITY || header_id == NO_NEXT_HEADER;
}
void IPv6::version(small_uint<4> new_version) {
_header.version = new_version;
}
void IPv6::traffic_class(uint8_t new_traffic_class) {
#if TINS_IS_LITTLE_ENDIAN
_header.traffic_class = (new_traffic_class >> 4) & 0xf;
_header.flow_label[0] = (_header.flow_label[0] & 0x0f) | ((new_traffic_class << 4) & 0xf0);
#else
_header.traffic_class = new_traffic_class;
#endif
}
void IPv6::flow_label(small_uint<20> new_flow_label) {
#if TINS_IS_LITTLE_ENDIAN
uint32_t value = Endian::host_to_be<uint32_t>(new_flow_label);
_header.flow_label[2] = (value >> 24) & 0xff;
_header.flow_label[1] = (value >> 16) & 0xff;
_header.flow_label[0] = ((value >> 8) & 0x0f) | (_header.flow_label[0] & 0xf0);
#else
_header.flow_label = new_flow_label;
#endif
}
void IPv6::payload_length(uint16_t new_payload_length) {
_header.payload_length = Endian::host_to_be(new_payload_length);
}
void IPv6::next_header(uint8_t new_next_header) {
_header.next_header = new_next_header;
}
void IPv6::hop_limit(uint8_t new_hop_limit) {
_header.hop_limit = new_hop_limit;
}
void IPv6::src_addr(const address_type &new_src_addr) {
new_src_addr.copy(_header.src_addr);
}
void IPv6::dst_addr(const address_type &new_dst_addr) {
new_dst_addr.copy(_header.dst_addr);
}
uint32_t IPv6::header_size() const {
return sizeof(_header) + headers_size;
}
bool IPv6::matches_response(const uint8_t *ptr, uint32_t total_sz) const {
if(total_sz < sizeof(ipv6_header))
return false;
const ipv6_header *hdr_ptr = (const ipv6_header*)ptr;
// checks for ff02 multicast
if(src_addr() == hdr_ptr->dst_addr &&
(dst_addr() == hdr_ptr->src_addr || (_header.dst_addr[0] == 0xff && _header.dst_addr[1] == 0x02))) {
// is this OK? there's no inner pdu, simple dst/src addr match should suffice
if(!inner_pdu())
return true;
ptr += sizeof(ipv6_header);
total_sz -= sizeof(ipv6_header);
uint8_t current = hdr_ptr->next_header;
// 8 == minimum header size
while(total_sz > 8 && is_extension_header(current)) {
if(static_cast<uint32_t>(ptr[1] + 1) * 8 > total_sz)
return false;
current = ptr[0];
total_sz -= (ptr[1] + 1) * 8;
ptr += (ptr[1] + 1) * 8;
}
if(!is_extension_header(current))
return inner_pdu()->matches_response(ptr, total_sz);
}
return false;
}
void IPv6::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *parent) {
#ifdef TINS_DEBUG
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:
break;
};
if(new_flag != 0xff)
set_last_next_header(new_flag);
}
payload_length(total_sz - sizeof(_header));
std::memcpy(buffer, &_header, sizeof(_header));
buffer += sizeof(_header);
for(headers_type::const_iterator it = ext_headers.begin(); it != ext_headers.end(); ++it) {
buffer = write_header(*it, buffer);
}
}
#ifndef BSD
void IPv6::send(PacketSender &sender, const NetworkInterface &) {
struct sockaddr_in6 link_addr;
PacketSender::SocketType type = PacketSender::IPV6_SOCKET;
link_addr.sin6_family = AF_INET6;
link_addr.sin6_port = 0;
std::copy(_header.dst_addr, _header.dst_addr + address_type::address_size, (uint8_t*)&link_addr.sin6_addr);
if(inner_pdu() && inner_pdu()->pdu_type() == PDU::ICMP)
type = PacketSender::ICMP_SOCKET;
sender.send_l3(*this, (struct sockaddr*)&link_addr, sizeof(link_addr), type);
}
#endif
void IPv6::add_ext_header(const ext_header &header) {
ext_headers.push_back(header);
headers_size += header.data_size() + sizeof(uint8_t) * 2;
}
const IPv6::ext_header *IPv6::search_header(ExtensionHeader id) const {
uint8_t current_header = _header.next_header;
headers_type::const_iterator it = ext_headers.begin();
while(it != ext_headers.end() && current_header != id) {
current_header = it->option();
++it;
}
if(it == ext_headers.end())
return 0;
return &*it;
}
void IPv6::set_last_next_header(uint8_t value) {
if(ext_headers.empty())
_header.next_header = value;
else
ext_headers.back().option(value);
}
uint8_t *IPv6::write_header(const ext_header &header, uint8_t *buffer) {
*buffer++ = header.option();
*buffer++ = (header.length_field() > 8) ? (header.length_field() - 8) : 0;
return std::copy(header.data_ptr(), header.data_ptr() + header.data_size(), buffer);
}
}

101
src/ipv6_address.cpp Normal file
View File

@@ -0,0 +1,101 @@
/*
* 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 <algorithm>
#include "macros.h"
#ifndef WIN32
#include <arpa/inet.h>
#ifdef BSD
#include <sys/socket.h>
#endif
#else
#include <ws2tcpip.h>
#include <mstcpip.h>
#endif
#include <limits>
#include <sstream>
#include "ipv6_address.h"
namespace Tins {
IPv6Address::IPv6Address() {
std::fill(address, address + address_size, 0);
}
IPv6Address::IPv6Address(const char *addr) {
init(addr);
}
IPv6Address::IPv6Address(const_iterator ptr) {
std::copy(ptr, ptr + address_size, address);
}
IPv6Address::IPv6Address(const std::string &addr) {
init(addr.c_str());
}
void IPv6Address::init(const char *addr) {
#ifdef WIN32
// mingw on linux somehow doesn't have InetPton
#ifdef _MSC_VER
if(InetPtonA(AF_INET6, addr, address) != 1)
throw malformed_address();
#else
ULONG dummy1;
USHORT dummy2;
// Maybe change this, mingw doesn't have any other conversion function
if(RtlIpv6StringToAddressExA(addr, (IN6_ADDR*)address, &dummy1, &dummy2) != NO_ERROR)
throw malformed_address();
#endif
#else
if(inet_pton(AF_INET6, addr, address) == 0)
throw malformed_address();
#endif
}
std::string IPv6Address::to_string() const {
char buffer[INET6_ADDRSTRLEN];
#ifdef WIN32
// mingw on linux somehow doesn't have InetNtop
#ifdef _MSC_VER
if(InetNtopA(AF_INET6, (PVOID)address, buffer, sizeof(buffer)) != 0)
throw malformed_address();
#else
ULONG sz = sizeof(buffer);
if(RtlIpv6AddressToStringExA((const IN6_ADDR*)address, 0, 0, buffer, &sz) != NO_ERROR)
throw malformed_address();
#endif
#else
if(inet_ntop(AF_INET6, address, buffer, sizeof(buffer)) == 0)
throw malformed_address();
#endif
return buffer;
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, Nasel
* Copyright (c) 2012, Matias Fontanini
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -29,11 +29,13 @@
#include <stdexcept>
#include <cstring>
#ifdef TINS_DEBUG
#include <cassert>
#include "pdu.h"
#endif
#include "llc.h"
#include "stp.h"
#include "rawpdu.h"
#include "exceptions.h"
using std::list;
@@ -41,8 +43,8 @@ namespace Tins {
const uint8_t LLC::GLOBAL_DSAP_ADDR = 0xFF;
const uint8_t LLC::NULL_ADDR = 0x00;
LLC::LLC(PDU *child)
: PDU(child), _type(LLC::INFORMATION)
LLC::LLC()
: _type(LLC::INFORMATION)
{
memset(&_header, 0, sizeof(llchdr));
control_field_length = 2;
@@ -50,8 +52,8 @@ LLC::LLC(PDU *child)
information_field_length = 0;
}
LLC::LLC(uint8_t dsap, uint8_t ssap, PDU *child)
: PDU(child), _type(LLC::INFORMATION)
LLC::LLC(uint8_t dsap, uint8_t ssap)
: _type(LLC::INFORMATION)
{
_header.dsap = dsap;
_header.ssap = ssap;
@@ -63,14 +65,14 @@ LLC::LLC(uint8_t dsap, uint8_t ssap, PDU *child)
LLC::LLC(const uint8_t *buffer, uint32_t total_sz) {
// header + 1 info byte
if(total_sz < sizeof(_header) + 1)
throw std::runtime_error("Not enough size for a LLC header in the buffer.");
throw malformed_packet();
std::memcpy(&_header, buffer, sizeof(_header));
buffer += sizeof(_header);
total_sz -= sizeof(_header);
information_field_length = 0;
if ((buffer[0] & 0x03) == LLC::UNNUMBERED) {
if(total_sz < sizeof(un_control_field))
throw std::runtime_error("Not enough size for a LLC header in the buffer.");
throw malformed_packet();
type(LLC::UNNUMBERED);
std::memcpy(&control_field.unnumbered, buffer, sizeof(un_control_field));
buffer += sizeof(un_control_field);
@@ -79,15 +81,19 @@ LLC::LLC(const uint8_t *buffer, uint32_t total_sz) {
}
else {
if(total_sz < sizeof(info_control_field))
throw std::runtime_error("Not enough size for a LLC header in the buffer.");
throw malformed_packet();
type((Format)(buffer[0] & 0x03));
control_field_length = 2;
std::memcpy(&control_field.info, buffer, sizeof(info_control_field));
buffer += 2;
total_sz -= 2;
}
if(total_sz > 0)
inner_pdu(new Tins::RawPDU(buffer, total_sz));
if(total_sz > 0) {
if(dsap() == 0x42 && ssap() == 0x42)
inner_pdu(new Tins::STP(buffer, total_sz));
else
inner_pdu(new Tins::RawPDU(buffer, total_sz));
}
}
void LLC::group(bool value) {
@@ -200,7 +206,13 @@ void LLC::clear_information_fields() {
}
void LLC::write_serialization(uint8_t *buffer, uint32_t total_sz, const Tins::PDU *parent) {
#ifdef TINS_DEBUG
assert(total_sz >= header_size());
#endif
if(inner_pdu() && inner_pdu()->pdu_type() == PDU::STP) {
dsap(0x42);
ssap(0x42);
}
std::memcpy(buffer, &_header, sizeof(_header));
buffer += sizeof(_header);
switch (type()) {
@@ -219,7 +231,6 @@ void LLC::write_serialization(uint8_t *buffer, uint32_t total_sz, const Tins::PD
}
for (list<field_type>::const_iterator it = information_fields.begin(); it != information_fields.end(); it++) {
//std::memcpy(buffer, it->second, it->first);
std::copy(it->begin(), it->end(), buffer);
buffer += it->size();
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, Nasel
* Copyright (c) 2012, Matias Fontanini
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -29,32 +29,40 @@
#ifndef WIN32
#include <sys/socket.h>
#ifdef BSD
#include <net/if_dl.h>
#include <netinet/in.h>
#include <net/ethernet.h>
#endif
#endif
#include <stdexcept>
#ifdef TINS_DEBUG
#include <cassert>
#endif
#include <cstring>
#include "loopback.h"
#include "packet_sender.h"
#include "ip.h"
#include "llc.h"
#include "rawpdu.h"
#include "exceptions.h"
#if !defined(PF_LLC)
// compilation fix, nasty but at least works on BSD
#define PF_LLC 26
#endif
namespace Tins {
Loopback::Loopback()
: _family()
{
}
Loopback::Loopback(uint32_t family_id, PDU *inner_pdu)
: PDU(inner_pdu), _family(family_id)
{
}
Loopback::Loopback(const uint8_t *buffer, uint32_t total_sz)
{
if(total_sz < sizeof(_family))
throw std::runtime_error("Not enough size for a loopback PDU");
throw malformed_packet();
_family = *reinterpret_cast<const uint32_t*>(buffer);
buffer += sizeof(uint32_t);
total_sz -= sizeof(uint32_t);
@@ -85,7 +93,21 @@ uint32_t Loopback::header_size() const {
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()))
_family = PF_INET;
else if(dynamic_cast<const Tins::LLC*>(inner_pdu()))
_family = PF_LLC;
*reinterpret_cast<uint32_t*>(buffer) = _family;
}
#ifdef BSD
void Loopback::send(PacketSender &sender, const NetworkInterface &iface) {
if(!iface)
throw invalid_interface();
sender.send_l2(*this, 0, 0, iface);
}
#endif // WIN32
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, Nasel
* Copyright (c) 2012, Matias Fontanini
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -30,11 +30,19 @@
#include <stdexcept>
#include <vector>
#include <cstring>
#include "macros.h"
#ifndef WIN32
#include <linux/if_packet.h>
#include <net/if.h>
#include <netinet/in.h>
#if defined(BSD) || defined(__FreeBSD_kernel__)
#include <ifaddrs.h>
#include <net/if_dl.h>
#include <sys/socket.h>
#else
#include <linux/if_packet.h>
#endif
#include <net/if.h>
#else
#define NOMINMAX
#include <winsock2.h>
#endif
#include "network_interface.h"
@@ -55,38 +63,52 @@ struct InterfaceInfoCollector {
#ifndef WIN32
bool operator() (const struct ifaddrs *addr) {
using Tins::Endian::host_to_be;
using Tins::IPv4Address;
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;
}
return found;
using Tins::IPv4Address;
#if defined(BSD) || defined(__FreeBSD_kernel__)
const struct sockaddr_dl* addr_ptr = ((struct sockaddr_dl*)addr->ifa_addr);
if(addr->ifa_addr->sa_family == AF_LINK && addr_ptr->sdl_index == iface_id)
info->hw_addr = (const uint8_t*)LLADDR(addr_ptr); // mmmm
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_dstaddr)->sin_addr.s_addr);
else
info->bcast_addr = 0;
found = true;
}
return found;
#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;
}
return found;
#endif
}
#else // WIN32
bool operator() (const IP_ADAPTER_ADDRESSES *iface) {
using Tins::IPv4Address;
// This surely doesn't work
if(iface_id == iface->IfIndex) {
using Tins::Endian::host_to_be;
if(iface_id == uint32_t(iface->IfIndex)) {
std::copy(iface->PhysicalAddress, iface->PhysicalAddress + 6, info->hw_addr.begin());
const IP_ADAPTER_PREFIX *prefix_ptr = iface->FirstPrefix;
for(size_t i = 0; prefix_ptr; prefix_ptr = prefix_ptr->Next, i++) {
if(i == 0)
info->ip_addr = IPv4Address(((const struct sockaddr_in *)prefix_ptr->Address.lpSockaddr)->sin_addr.s_addr);
else if(i == 2)
info->bcast_addr = IPv4Address(((const struct sockaddr_in *)prefix_ptr->Address.lpSockaddr)->sin_addr.s_addr);
const IP_ADAPTER_UNICAST_ADDRESS *unicast = iface->FirstUnicastAddress;
if(unicast) {
info->ip_addr = IPv4Address(((const struct sockaddr_in *)unicast->Address.lpSockaddr)->sin_addr.s_addr);
info->netmask = IPv4Address(host_to_be<uint32_t>(0xffffffff << (32 - unicast->OnLinkPrefixLength)));
info->bcast_addr = IPv4Address((info->ip_addr & info->netmask) | ~info->netmask);
found = true;
}
// (?????)
info->netmask = IPv4Address(info->ip_addr - info->bcast_addr);
found = true;
}
return found;
}
@@ -116,20 +138,26 @@ NetworkInterface::NetworkInterface(IPv4Address ip) : iface_id(0) {
typedef std::vector<Utils::RouteEntry> entries_type;
if(ip == "127.0.0.1")
#if defined(BSD) || defined(__FreeBSD_kernel__)
iface_id = resolve_index("lo0");
#else
iface_id = resolve_index("lo");
#endif
else {
Utils::RouteEntry *best_match = 0;
const Utils::RouteEntry *best_match = 0;
entries_type entries;
uint32_t ip_int = ip;
Utils::route_entries(std::back_inserter(entries));
for(entries_type::const_iterator it(entries.begin()); it != entries.end(); ++it) {
if((ip_int & it->mask) == it->destination) {
if(!best_match || it->mask > best_match->mask)
iface_id = resolve_index(it->interface.c_str());
if(!best_match || it->mask > best_match->mask) {
best_match = &*it;
}
}
}
if(best_match)
if(!best_match)
throw std::runtime_error("Error looking up interface");
iface_id = resolve_index(best_match->interface.c_str());
}
}
@@ -155,26 +183,9 @@ NetworkInterface::Info NetworkInterface::addresses() const {
}
NetworkInterface::id_type NetworkInterface::resolve_index(const char *name) {
#ifndef WIN32
id_type id = if_nametoindex(name);
if(!id)
throw std::runtime_error("Invalid interface error");
#else // WIN32
id_type id;
ULONG size;
GetAdaptersInfo(0, &size);
std::vector<uint8_t> buffer(size);
if ( GetAdaptersInfo((IP_ADAPTER_INFO *)&buffer[0], &size) == ERROR_SUCCESS) {
PIP_ADAPTER_INFO iface = (IP_ADAPTER_INFO *)&buffer[0];
while(iface) {
if(!strcmp(iface->AdapterName, name)) {
id = iface->Index;
break;
}
iface = iface->Next;
}
}
#endif // WIN32
throw std::runtime_error("Invalid interface");
return id;
}
}

Some files were not shown because too many files have changed in this diff Show More