rsp->setRemotePort(DHCP6_CLIENT_PORT);
} else {
// Relayed traffic, send back to the relay agent
- rsp->setRemotePort(DHCP6_SERVER_PORT);
+ uint16_t relay_port = testRelaySourcePort(query);
+ rsp->setRemotePort(relay_port ? relay_port : DHCP6_SERVER_PORT);
}
rsp->setLocalPort(DHCP6_SERVER_PORT);
}
}
+uint16_t Dhcpv6Srv::testRelaySourcePort(const Pkt6Ptr& query) {
+
+ if (query->relay_info_.empty()) {
+ // No relay agent
+ return (0);
+ }
+
+ // Did the last relay agent add a relay-source-port?
+ if (query->getRelayOption(D6O_RELAY_SOURCE_PORT, 0)) {
+ // draft-ietf-dhc-relay-port-10.txt section 5.2
+ return (query->getRemotePort());
+ }
+
+ return (0);
+}
+
void Dhcpv6Srv::processStatsReceived(const Pkt6Ptr& query) {
// Note that we're not bumping pkt6-received statistic as it was
// increased early in the packet reception code.
EXPECT_EQ(DHCP6_SERVER_PORT, adv->getRemotePort());
}
+// Test that the server processes relay-source-port option correctly.
+TEST_F(Dhcpv6SrvTest, relaySourcePort) {
+
+ NakedDhcpv6Srv srv(0);
+
+ string config =
+ "{"
+ " \"preferred-lifetime\": 3000,"
+ " \"rebind-timer\": 2000, "
+ " \"renew-timer\": 1000, "
+ " \"subnet6\": [ { "
+ " \"pools\": [ { \"pool\": \"2001:db8::/64\" } ],"
+ " \"subnet\": \"2001:db8::/48\" "
+ " } ],"
+ " \"valid-lifetime\": 4000"
+ "}";
+
+ EXPECT_NO_THROW(configure(config, srv));
+
+ // Create a solicit
+ Pkt6Ptr sol(new Pkt6(DHCPV6_SOLICIT, 1234));
+ sol->setRemoteAddr(IOAddress("fe80::abcd"));
+ sol->setIface("eth0");
+ sol->addOption(generateIA(D6O_IA_NA, 234, 1500, 3000));
+ OptionPtr clientid = generateClientId();
+ sol->addOption(clientid);
+
+ // Pretend the packet came via one relay.
+ Pkt6::RelayInfo relay;
+ relay.msg_type_ = DHCPV6_RELAY_FORW;
+ relay.hop_count_ = 1;
+ relay.linkaddr_ = IOAddress("2001:db8::1");
+ relay.peeraddr_ = IOAddress("fe80::1");
+
+ // Set the source port
+ sol->setRemotePort(1234);
+
+ // Simulate that we have received that traffic
+ sol->pack();
+
+ // Add a relay-source-port option
+ OptionBuffer zero(2, 0);
+ OptionPtr opt(new Option(Option::V6, D6O_RELAY_SOURCE_PORT, zero));
+ relay.options_.insert(make_pair(opt->getType(), opt));
+ sol->relay_info_.push_back(relay);
+
+ // Simulate that we have received that traffic
+ sol->pack();
+ EXPECT_EQ(DHCPV6_RELAY_FORW, sol->getBuffer()[0]);
+ Pkt6Ptr query(new Pkt6(static_cast<const uint8_t*>
+ (sol->getBuffer().getData()),
+ sol->getBuffer().getLength()));
+ query->setRemoteAddr(sol->getRemoteAddr());
+ query->setRemotePort(sol->getRemotePort());
+ query->setLocalAddr(sol->getLocalAddr());
+ query->setLocalPort(sol->getLocalPort());
+ query->setIface(sol->getIface());
+
+ srv.fakeReceive(query);
+
+ // 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();
+
+ // Check trace of processing
+ EXPECT_EQ(1234, query->getRemotePort());
+ ASSERT_EQ(1, query->relay_info_.size());
+ EXPECT_TRUE(query->getRelayOption(D6O_RELAY_SOURCE_PORT, 0));
+
+ // Get Response...
+ ASSERT_FALSE(srv.fake_sent_.empty());
+ Pkt6Ptr rsp = srv.fake_sent_.front();
+ ASSERT_TRUE(rsp);
+
+ // Check it
+ EXPECT_EQ(1234, rsp->getRemotePort());
+ EXPECT_EQ(DHCPV6_RELAY_REPL, rsp->getBuffer()[0]);
+
+ // Get Advertise
+ Pkt6Ptr adv(new Pkt6(static_cast<const uint8_t*>
+ (rsp->getBuffer().getData()),
+ rsp->getBuffer().getLength()));
+ adv->unpack();
+
+ // Check it
+ EXPECT_EQ(DHCPV6_ADVERTISE, adv->getType());
+ ASSERT_EQ(1, adv->relay_info_.size());
+ EXPECT_TRUE(adv->getRelayOption(D6O_RELAY_SOURCE_PORT, 0));
+}
+
// Checks effect of persistency (aka always-true) flag on the ORO
TEST_F(Dhcpv6SrvTest, prlPersistency) {
IfaceMgrTestConfig test_config(true);