From: Tomek Mrugalski Date: Tue, 1 Oct 2013 14:47:00 +0000 (+0200) Subject: [3177] Relayed traffic is now being send to the proper port X-Git-Tag: bind10-1.2.0beta1-release~191^2~4 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=eee878e7817bcdc270ff56867dc0671f1d223e31;p=thirdparty%2Fkea.git [3177] Relayed traffic is now being send to the proper port - Dhcp6Srv fix - unit-tests written - Added DOCSIS3.0 relayed traffic unit-test --- diff --git a/src/bin/dhcp6/dhcp6_srv.cc b/src/bin/dhcp6/dhcp6_srv.cc index 2da5c8bd14..be130052e5 100644 --- a/src/bin/dhcp6/dhcp6_srv.cc +++ b/src/bin/dhcp6/dhcp6_srv.cc @@ -369,7 +369,15 @@ bool Dhcpv6Srv::run() { if (rsp) { rsp->setRemoteAddr(query->getRemoteAddr()); rsp->setLocalAddr(query->getLocalAddr()); - rsp->setRemotePort(DHCP6_CLIENT_PORT); + + if (rsp->relay_info_.empty()) { + // Direct traffic, send back to the client directly + rsp->setRemotePort(DHCP6_CLIENT_PORT); + } else { + // Relayed traffic, send back to the relay agent + rsp->setRemotePort(DHCP6_SERVER_PORT); + } + rsp->setLocalPort(DHCP6_SERVER_PORT); rsp->setIndex(query->getIndex()); rsp->setIface(query->getIface()); @@ -433,10 +441,10 @@ bool Dhcpv6Srv::run() { // Pass incoming packet as argument callout_handle->setArgument("response6", rsp); - + // Call callouts HooksManager::callCallouts(Hooks.hook_index_buffer6_send_, *callout_handle); - + // Callouts decided to skip the next processing step. The next // processing step would to parse the packet, so skip at this // stage means drop. @@ -444,7 +452,7 @@ bool Dhcpv6Srv::run() { LOG_DEBUG(dhcp6_logger, DBG_DHCP6_HOOKS, DHCP6_HOOK_BUFFER_SEND_SKIP); continue; } - + callout_handle->getArgument("response6", rsp); } diff --git a/src/bin/dhcp6/tests/Makefile.am b/src/bin/dhcp6/tests/Makefile.am index 7ea71634bb..1cb8f6f9fc 100644 --- a/src/bin/dhcp6/tests/Makefile.am +++ b/src/bin/dhcp6/tests/Makefile.am @@ -68,6 +68,7 @@ dhcp6_unittests_SOURCES += ../dhcp6_srv.h ../dhcp6_srv.cc dhcp6_unittests_SOURCES += ../dhcp6_log.h ../dhcp6_log.cc dhcp6_unittests_SOURCES += ../ctrl_dhcp6_srv.cc dhcp6_unittests_SOURCES += ../config_parser.cc ../config_parser.h +dhcp6_unittests_SOURCES += wireshark.cc nodist_dhcp6_unittests_SOURCES = ../dhcp6_messages.h ../dhcp6_messages.cc nodist_dhcp6_unittests_SOURCES += marker_file.h test_libraries.h diff --git a/src/bin/dhcp6/tests/dhcp6_srv_unittest.cc b/src/bin/dhcp6/tests/dhcp6_srv_unittest.cc index 3869d2b81b..6a17aeb51d 100644 --- a/src/bin/dhcp6/tests/dhcp6_srv_unittest.cc +++ b/src/bin/dhcp6/tests/dhcp6_srv_unittest.cc @@ -2104,6 +2104,80 @@ TEST_F(FqdnDhcpv6SrvTest, processRequestRelease) { } +// Checks if server responses are sent to the proper port. +TEST_F(Dhcpv6SrvTest, portsDirectTraffic) { + + NakedDhcpv6Srv srv(0); + + // Let's create a simple SOLICIT + Pkt6Ptr sol = Pkt6Ptr(captureSimpleSolicit()); + + // Simulate that we have received that traffic + srv.fakeReceive(sol); + + // Server will now process to run its normal loop, but instead of calling + // IfaceMgr::receive6(), it will read all packets from the list set by + // fakeReceive() + srv.run(); + + // Get Advertise... + ASSERT_FALSE(srv.fake_sent_.empty()); + Pkt6Ptr adv = srv.fake_sent_.front(); + ASSERT_TRUE(adv); + + // This is sent back to client directly, should be port 546 + EXPECT_EQ(DHCP6_CLIENT_PORT, adv->getRemotePort()); +} + +// Checks if server responses are sent to the proper port. +TEST_F(Dhcpv6SrvTest, portsRelayedTraffic) { + + NakedDhcpv6Srv srv(0); + + // Let's create a simple SOLICIT + Pkt6Ptr sol = Pkt6Ptr(captureRelayedSolicit()); + + // Simulate that we have received that traffic + srv.fakeReceive(sol); + + // Server will now process to run its normal loop, but instead of calling + // IfaceMgr::receive6(), it will read all packets from the list set by + // fakeReceive() + srv.run(); + + // Get Advertise... + ASSERT_FALSE(srv.fake_sent_.empty()); + Pkt6Ptr adv = srv.fake_sent_.front(); + ASSERT_TRUE(adv); + + // This is sent back to relay, so port is 547 + EXPECT_EQ(DHCP6_SERVER_PORT, adv->getRemotePort()); +} + +// Checks if server is able to handle a relayed traffic from DOCSIS3.0 modems +TEST_F(Dhcpv6SrvTest, DISABLED_docsisTraffic) { + + NakedDhcpv6Srv srv(0); + + // Let's get a traffic capture from DOCSIS3.0 modem + Pkt6Ptr sol = Pkt6Ptr(captureDocsisRelayedSolicit()); + + // Simulate that we have received that traffic + srv.fakeReceive(sol); + + // Server will now process to run its normal loop, but instead of calling + // IfaceMgr::receive6(), it will read all packets from the list set by + // fakeReceive() + srv.run(); + + // We should have an Advertise in response + ASSERT_FALSE(srv.fake_sent_.empty()); + Pkt6Ptr adv = srv.fake_sent_.front(); + ASSERT_TRUE(adv); + + /// @todo Check that the ADVERTISE is ok, that it includes all options, + /// that is relayed properly, etc. +} /// @todo: Add more negative tests for processX(), e.g. extend sanityCheck() test /// to call processX() methods. diff --git a/src/bin/dhcp6/tests/dhcp6_test_utils.h b/src/bin/dhcp6/tests/dhcp6_test_utils.h index 0e5ad7c12a..6035d269bd 100644 --- a/src/bin/dhcp6/tests/dhcp6_test_utils.h +++ b/src/bin/dhcp6/tests/dhcp6_test_utils.h @@ -393,6 +393,13 @@ public: return (lease); } + // see wireshark.cc for descriptions + // The descriptions are too large and too closely related to the + // code, so it is kept in .cc rather than traditionally in .h + Pkt6* captureSimpleSolicit(); + Pkt6* captureRelayedSolicit(); + Pkt6* captureDocsisRelayedSolicit(); + ~Dhcpv6SrvTest() { CfgMgr::instance().deleteSubnets6(); }; diff --git a/src/bin/dhcp6/tests/hooks_unittest.cc b/src/bin/dhcp6/tests/hooks_unittest.cc index 767560ff8c..097f694d11 100644 --- a/src/bin/dhcp6/tests/hooks_unittest.cc +++ b/src/bin/dhcp6/tests/hooks_unittest.cc @@ -85,33 +85,6 @@ TEST_F(Dhcpv6SrvTest, Hooks) { EXPECT_TRUE(hook_index_lease6_release > 0); } -// This function returns buffer for very simple Solicit -Pkt6* captureSimpleSolicit() { - Pkt6* pkt; - uint8_t data[] = { - 1, // type 1 = SOLICIT - 0xca, 0xfe, 0x01, // trans-id = 0xcafe01 - 0, 1, // option type 1 (client-id) - 0, 10, // option lenth 10 - 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, // DUID - 0, 3, // option type 3 (IA_NA) - 0, 12, // option length 12 - 0, 0, 0, 1, // iaid = 1 - 0, 0, 0, 0, // T1 = 0 - 0, 0, 0, 0 // T2 = 0 - }; - - pkt = new Pkt6(data, sizeof(data)); - pkt->setRemotePort(546); - pkt->setRemoteAddr(IOAddress("fe80::1")); - pkt->setLocalPort(0); - pkt->setLocalAddr(IOAddress("ff02::1:2")); - pkt->setIndex(2); - pkt->setIface("eth0"); - - return (pkt); -} - /// @brief a class dedicated to Hooks testing in DHCPv6 server /// /// This class has a number of static members, because each non-static diff --git a/src/bin/dhcp6/tests/wireshark.cc b/src/bin/dhcp6/tests/wireshark.cc new file mode 100644 index 0000000000..1daeeac495 --- /dev/null +++ b/src/bin/dhcp6/tests/wireshark.cc @@ -0,0 +1,170 @@ +// Copyright (C) 2013 Internet Systems Consortium, Inc. ("ISC") +// +// Permission to use, copy, modify, and/or distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. +// +// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH +// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, +// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE +// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +// PERFORMANCE OF THIS SOFTWARE. + +#include +#include +#include + +/// @file wireshark.cc +/// +/// @brief contains packet captures imported from Wireshark +/// +/// These are actual packets captured over wire. They are used in various +/// tests. +/// +/// The procedure to export Wireshark -> unit-tests is manual, but rather +/// easy to follow: +/// 1. Open a file in wireshark +/// 2. Find the packet you want to export +/// 3. There's a protocol stack (Frame, Ethernet, IPv6, UDP, DHCPv6, ...) +/// 4. Right click on DHCPv6 -> Copy -> Bytes -> Hex Stream +/// 5. Paste it as: string hex_string="[paste here]"; +/// 6. Coding guidelines line restrictions apply, so wrap your code as necessary +/// 7. Make sure you decribe the capture appropriately +/// 8. Follow whatever rest of the methods are doing (set ports, ifaces etc.) + +using namespace std; + +namespace isc { +namespace test { + +// This function returns buffer for very simple Solicit +Pkt6* isc::test::Dhcpv6SrvTest::captureSimpleSolicit() { + Pkt6* pkt; + uint8_t data[] = { + 1, // type 1 = SOLICIT + 0xca, 0xfe, 0x01, // trans-id = 0xcafe01 + 0, 1, // option type 1 (client-id) + 0, 10, // option lenth 10 + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, // DUID + 0, 3, // option type 3 (IA_NA) + 0, 12, // option length 12 + 0, 0, 0, 1, // iaid = 1 + 0, 0, 0, 0, // T1 = 0 + 0, 0, 0, 0 // T2 = 0 + }; + + pkt = new Pkt6(data, sizeof(data)); + pkt->setRemotePort(546); + pkt->setRemoteAddr(IOAddress("fe80::1")); + pkt->setLocalPort(0); + pkt->setLocalAddr(IOAddress("ff02::1:2")); + pkt->setIndex(2); + pkt->setIface("eth0"); + + return (pkt); +} + +Pkt6* isc::test::Dhcpv6SrvTest::captureRelayedSolicit() { + + // This is a very simple relayed SOLICIT message: + // RELAY-FORW + // - interface-id + // - relay-message + // - SOLICIT + // - client-id + // - IA_NA (iaid=1, t1=0, t2=0) + // - ORO (7) + + // string exported from Wireshark + string hex_string = + "0c0500000000000000000000000000000000fc00000000000000000000000000000900" + "12000231350009002c010517100001000e0001000151b5e46208002758f1e80003000c" + "000000010000000000000000000600020007"; + + std::vector bin; + + // Decode the hex string and store it in bin (which happens + // to be OptionBuffer format) + isc::util::encode::decodeHex(hex_string, bin); + + Pkt6* pkt = new Pkt6(&bin[0], bin.size()); + pkt->setRemotePort(547); + pkt->setRemoteAddr(IOAddress("fe80::1234")); + pkt->setLocalPort(547); + pkt->setLocalAddr(IOAddress("ff05::1:3")); + pkt->setIndex(2); + pkt->setIface("eth0"); + return (pkt); +} + +/// returns a buffer with relayed SOLICIT (from DOCSIS3.0 cable modem) +/// see dhcp6_relay_forw-virginmedia.pcap +Pkt6* isc::test::Dhcpv6SrvTest::captureDocsisRelayedSolicit() { + + // This is an actual DOCSIS packet + // RELAY-FORW (12) + // - Relay Message + // - SOLICIT (1) + // - client-id + // - IA_NA (iaid=7f000788, t2=0, t2=0) + // - IAAddress (::, pref=0,valid=0) + // - rapid-commit + // - ORO + // - Reconfigure-accept + // - Vendor-Class ("docsis3.0") + // - Vendor-specific Info + // - subopt 1: Option request = 32,33,34,37,38 + // - subopt 36: Device identifier + // - subopt 35: TLV5 + // - subopt 2: Device type = ECM + // - subopt 3: Embedded components + // - subopt 4: Serial Number + // - subopt 5: Hardware version + // - subopt 6: Software version + // - subopt 7: Boot ROM Version + // - subopt 8: Organization Unique Identifier + // - subopt 9: Model Number + // - subopt 10: Vendor Name (Netgear) + // - subopt 15: unknown + // - Interface-Id + // - Vendor-specific Information + // - Suboption 1025: CMTS capabilities + // - Suboption 1026: Cable Modem MAC addr = 10:0d:7f:00:07:88 + + // string exported from Wireshark + string hex_string = + "0c002a0288fe00fe00015a8d09fffe7af955fe80000000000000120d7ffffe00078800" + "090189010d397f0001000a00030001100d7f000788000300287f000788000000000000" + "000000050018000000000000000000000000000000000000000000000000000e000000" + "0800020000000600020011001400000010000f0000118b0009646f63736973332e3000" + "1101200000118b0001000a0020002100220025002600240006100d7f00078800230081" + "0101010201030301010401010501010601010701180801080901000a01010b01180c01" + "010d0200400e0200100f01011004000000021101011301011401001501381601011701" + "011801041901041a01041b01281c01021d01081e01201f011020011821010222010123" + "010124011825010126020040270101120701100d7f00078a0002000345434d0003000b" + "45434d3a45524f555445520004000d3335463132395550303030353200050004332e31" + "310006000956312e30312e31315400070013505350552d426f6f7420312e302e31362e" + "323200080006303030393542000900084347343030305444000a00074e657467656172" + "000f000745524f5554455200120012427531264361312f3000100d7f00078800000011" + "00160000118b040100040102030004020006100d7f000788"; + + std::vector bin; + + // Decode the hex string and store it in bin (which happens + // to be OptionBuffer format) + isc::util::encode::decodeHex(hex_string, bin); + + Pkt6* pkt = new Pkt6(&bin[0], bin.size()); + pkt->setRemotePort(547); + pkt->setRemoteAddr(IOAddress("fe80::1234")); + pkt->setLocalPort(547); + pkt->setLocalAddr(IOAddress("ff05::1:3")); + pkt->setIndex(2); + pkt->setIface("eth0"); + return (pkt); +} + +}; // end of isc::test namespace +}; // end of isc namespace