mirror of
https://gitlab.isc.org/isc-projects/kea
synced 2025-08-30 05:27:55 +00:00
[82-improve-kea-test-capabilities] Added remote port to dhcp4/dhcp6/perfdhcp
This commit is contained in:
parent
0487f6fc96
commit
c25bbf2616
@ -716,8 +716,10 @@ ControlledDhcpv4Srv::checkConfig(isc::data::ConstElementPtr config) {
|
||||
return (configureDhcp4Server(*srv, config, true));
|
||||
}
|
||||
|
||||
ControlledDhcpv4Srv::ControlledDhcpv4Srv(uint16_t server_port /*= DHCP4_SERVER_PORT*/)
|
||||
: Dhcpv4Srv(server_port), io_service_(), timer_mgr_(TimerMgr::instance()) {
|
||||
ControlledDhcpv4Srv::ControlledDhcpv4Srv(uint16_t server_port /*= DHCP4_SERVER_PORT*/,
|
||||
uint16_t client_port /*= 0*/)
|
||||
: Dhcpv4Srv(server_port, client_port), io_service_(),
|
||||
timer_mgr_(TimerMgr::instance()) {
|
||||
if (getInstance()) {
|
||||
isc_throw(InvalidOperation,
|
||||
"There is another Dhcpv4Srv instance already.");
|
||||
|
@ -28,7 +28,9 @@ public:
|
||||
/// @brief Constructor
|
||||
///
|
||||
/// @param server_port UDP port to be opened for DHCP traffic
|
||||
ControlledDhcpv4Srv(uint16_t server_port = DHCP4_SERVER_PORT);
|
||||
/// @param client_port UDP port where all responses are sent to.
|
||||
ControlledDhcpv4Srv(uint16_t server_port = DHCP4_SERVER_PORT,
|
||||
uint16_t client_port = 0);
|
||||
|
||||
/// @brief Destructor.
|
||||
~ControlledDhcpv4Srv();
|
||||
|
@ -739,7 +739,7 @@ This informational message indicates that the DHCPv4 server has
|
||||
processed any command-line switches and is starting. The version
|
||||
is also printed.
|
||||
|
||||
% DHCP4_START_INFO pid: %1, server port: %2, verbose: %3
|
||||
% DHCP4_START_INFO pid: %1, server port: %2, client port: %3, verbose: %4
|
||||
This is a debug message issued during the DHCPv4 server startup.
|
||||
It lists some information about the parameters with which the server
|
||||
is running.
|
||||
|
@ -441,10 +441,11 @@ Dhcpv4Exchange::setReservedMessageFields() {
|
||||
|
||||
const std::string Dhcpv4Srv::VENDOR_CLASS_PREFIX("VENDOR_CLASS_");
|
||||
|
||||
Dhcpv4Srv::Dhcpv4Srv(uint16_t server_port, const bool use_bcast,
|
||||
const bool direct_response_desired)
|
||||
Dhcpv4Srv::Dhcpv4Srv(uint16_t server_port, uint16_t client_port,
|
||||
const bool use_bcast, const bool direct_response_desired)
|
||||
: io_service_(new IOService()), shutdown_(true), alloc_engine_(),
|
||||
server_port_(server_port), use_bcast_(use_bcast),
|
||||
client_port_(client_port),
|
||||
network_state_(new NetworkState(NetworkState::DHCPv4)) {
|
||||
|
||||
LOG_DEBUG(dhcp4_logger, DBG_DHCP4_START, DHCP4_OPEN_SOCKET)
|
||||
@ -2296,11 +2297,15 @@ Dhcpv4Srv::adjustIfaceData(Dhcpv4Exchange& ex) {
|
||||
// server has to reply via relay agent. For other messages we send back
|
||||
// through relay if message is relayed, and unicast to the client if the
|
||||
// message is not relayed.
|
||||
// If client port was set from the command line enforce all responses
|
||||
// to it. Of course it is only for testing purposes.
|
||||
// Note that the call to this function may throw if invalid combination
|
||||
// of hops and giaddr is found (hops = 0 if giaddr = 0 and hops != 0 if
|
||||
// giaddr != 0). The exception will propagate down and eventually cause the
|
||||
// packet to be discarded.
|
||||
if (((query->getType() == DHCPINFORM) &&
|
||||
if (client_port_) {
|
||||
response->setRemotePort(client_port_);
|
||||
} else if (((query->getType() == DHCPINFORM) &&
|
||||
((!query->getCiaddr().isV4Zero()) ||
|
||||
(!query->isRelayed() && !query->getRemoteAddr().isV4Zero()))) ||
|
||||
((query->getType() != DHCPINFORM) && !query->isRelayed())) {
|
||||
|
@ -212,7 +212,8 @@ public:
|
||||
/// In particular, creates IfaceMgr that will be responsible for
|
||||
/// network interaction. Will instantiate lease manager, and load
|
||||
/// old or create new DUID. It is possible to specify alternate
|
||||
/// port on which DHCPv4 server will listen on. That is mostly useful
|
||||
/// port on which DHCPv4 server will listen on and alternate port
|
||||
/// where DHCPv4 server sends all responses to. Those are mostly useful
|
||||
/// for testing purposes. The Last two arguments of the constructor
|
||||
/// should be left at default values for normal server operation.
|
||||
/// They should be set to 'false' when creating an instance of this
|
||||
@ -220,10 +221,12 @@ public:
|
||||
/// root privileges.
|
||||
///
|
||||
/// @param server_port specifies port number to listen on
|
||||
/// @param client_port specifies port number to send to
|
||||
/// @param use_bcast configure sockets to support broadcast messages.
|
||||
/// @param direct_response_desired specifies if it is desired to
|
||||
/// use direct V4 traffic.
|
||||
Dhcpv4Srv(uint16_t server_port = DHCP4_SERVER_PORT,
|
||||
uint16_t client_port = 0,
|
||||
const bool use_bcast = true,
|
||||
const bool direct_response_desired = true);
|
||||
|
||||
@ -772,7 +775,8 @@ protected:
|
||||
/// address).
|
||||
///
|
||||
/// The destination port is always DHCPv4 client (68) or relay (67) port,
|
||||
/// depending if the response will be sent directly to a client.
|
||||
/// depending if the response will be sent directly to a client, unless
|
||||
/// a client port was enforced from the command line.
|
||||
///
|
||||
/// The source port is always set to DHCPv4 server port (67).
|
||||
///
|
||||
@ -789,7 +793,7 @@ protected:
|
||||
///
|
||||
/// @param ex The exchange holding both the client's message and the
|
||||
/// server's response.
|
||||
static void adjustIfaceData(Dhcpv4Exchange& ex);
|
||||
void adjustIfaceData(Dhcpv4Exchange& ex);
|
||||
|
||||
/// @brief Sets remote addresses for outgoing packet.
|
||||
///
|
||||
@ -962,6 +966,9 @@ private:
|
||||
|
||||
protected:
|
||||
|
||||
/// UDP port number to which server sends responses.
|
||||
uint16_t client_port_;
|
||||
|
||||
/// @brief Holds information about disabled DHCP service and/or
|
||||
/// disabled subnet/network scopes.
|
||||
NetworkStatePtr network_state_;
|
||||
|
@ -50,6 +50,7 @@
|
||||
<arg choice="opt" rep="norepeat"><option>-c <replaceable class="parameter">config-file</replaceable></option></arg>
|
||||
<arg choice="opt" rep="norepeat"><option>-t <replaceable class="parameter">config-file</replaceable></option></arg>
|
||||
<arg choice="opt" rep="norepeat"><option>-p <replaceable class="parameter">server-port-number</replaceable></option></arg>
|
||||
<arg choice="opt" rep="norepeat"><option>-P <replaceable class="parameter">client-port-number</replaceable></option></arg>
|
||||
</cmdsynopsis>
|
||||
</refsynopsisdiv>
|
||||
|
||||
@ -123,6 +124,14 @@
|
||||
</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>-P</option></term>
|
||||
<listitem><para>
|
||||
Client port number (1-65535) to which the server responds.
|
||||
This is useful for testing purposes only.
|
||||
</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
</variablelist>
|
||||
</refsect1>
|
||||
|
||||
|
@ -44,7 +44,7 @@ usage() {
|
||||
cerr << "Kea DHCPv4 server, version " << VERSION << endl;
|
||||
cerr << endl;
|
||||
cerr << "Usage: " << DHCP4_NAME
|
||||
<< " -[v|V|W] [-d] [-{c|t} cfgfile] [-p number]" << endl;
|
||||
<< " -[v|V|W] [-d] [-{c|t} cfgfile] [-p number] [-P number]" << endl;
|
||||
cerr << " -v: print version number and exit" << endl;
|
||||
cerr << " -V: print extended version and exit" << endl;
|
||||
cerr << " -W: display the configuration report and exit" << endl;
|
||||
@ -53,6 +53,8 @@ usage() {
|
||||
cerr << " -t file: check the configuration file syntax and exit" << endl;
|
||||
cerr << " -p number: specify non-standard server port number 1-65535 "
|
||||
<< "(useful for testing only)" << endl;
|
||||
cerr << " -P number: specify non-standard client port number 1-65535 "
|
||||
<< "(useful for testing only)" << endl;
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
} // end of anonymous namespace
|
||||
@ -60,15 +62,17 @@ usage() {
|
||||
int
|
||||
main(int argc, char* argv[]) {
|
||||
int ch;
|
||||
// The default. any other values are useful for testing only.
|
||||
// The default. Any other values are useful for testing only.
|
||||
int server_port_number = DHCP4_SERVER_PORT;
|
||||
// Not zero values are useful for testing only.
|
||||
int client_port_number = 0;
|
||||
bool verbose_mode = false; // Should server be verbose?
|
||||
bool check_mode = false; // Check syntax
|
||||
|
||||
// The standard config file
|
||||
std::string config_file("");
|
||||
|
||||
while ((ch = getopt(argc, argv, "dvVWc:p:t:")) != -1) {
|
||||
while ((ch = getopt(argc, argv, "dvVWc:p:P:t:")) != -1) {
|
||||
switch (ch) {
|
||||
case 'd':
|
||||
verbose_mode = true;
|
||||
@ -98,12 +102,27 @@ main(int argc, char* argv[]) {
|
||||
try {
|
||||
server_port_number = boost::lexical_cast<int>(optarg);
|
||||
} catch (const boost::bad_lexical_cast &) {
|
||||
cerr << "Failed to parse port number: [" << optarg
|
||||
cerr << "Failed to parse server port number: [" << optarg
|
||||
<< "], 1-65535 allowed." << endl;
|
||||
usage();
|
||||
}
|
||||
if (server_port_number <= 0 || server_port_number > 65535) {
|
||||
cerr << "Failed to parse port number: [" << optarg
|
||||
cerr << "Failed to parse server port number: [" << optarg
|
||||
<< "], 1-65535 allowed." << endl;
|
||||
usage();
|
||||
}
|
||||
break;
|
||||
|
||||
case 'P':
|
||||
try {
|
||||
client_port_number = boost::lexical_cast<int>(optarg);
|
||||
} catch (const boost::bad_lexical_cast &) {
|
||||
cerr << "Failed to parse client port number: [" << optarg
|
||||
<< "], 1-65535 allowed." << endl;
|
||||
usage();
|
||||
}
|
||||
if (client_port_number <= 0 || client_port_number > 65535) {
|
||||
cerr << "Failed to parse client port number: [" << optarg
|
||||
<< "], 1-65535 allowed." << endl;
|
||||
usage();
|
||||
}
|
||||
@ -187,13 +206,15 @@ main(int argc, char* argv[]) {
|
||||
// Initialize logging. If verbose, we'll use maximum verbosity.
|
||||
Daemon::loggerInit(DHCP4_ROOT_LOGGER_NAME, verbose_mode);
|
||||
LOG_DEBUG(dhcp4_logger, DBG_DHCP4_START, DHCP4_START_INFO)
|
||||
.arg(getpid()).arg(server_port_number)
|
||||
.arg(getpid())
|
||||
.arg(server_port_number)
|
||||
.arg(client_port_number)
|
||||
.arg(verbose_mode ? "yes" : "no");
|
||||
|
||||
LOG_INFO(dhcp4_logger, DHCP4_STARTING).arg(VERSION);
|
||||
|
||||
// Create the server instance.
|
||||
ControlledDhcpv4Srv server(server_port_number);
|
||||
ControlledDhcpv4Srv server(server_port_number, client_port_number);
|
||||
|
||||
// Remember verbose-mode
|
||||
server.setVerbose(verbose_mode);
|
||||
|
@ -176,7 +176,7 @@ TEST_F(Dhcpv4SrvTest, adjustIfaceDataRelay) {
|
||||
resp->setHops(req->getHops());
|
||||
|
||||
// This function never throws.
|
||||
ASSERT_NO_THROW(NakedDhcpv4Srv::adjustIfaceData(ex));
|
||||
ASSERT_NO_THROW(srv_.adjustIfaceData(ex));
|
||||
|
||||
// Now the destination address should be relay's address.
|
||||
EXPECT_EQ("192.0.1.1", resp->getRemoteAddr().toText());
|
||||
@ -202,10 +202,16 @@ TEST_F(Dhcpv4SrvTest, adjustIfaceDataRelay) {
|
||||
// Clear remote address.
|
||||
resp->setRemoteAddr(IOAddress("0.0.0.0"));
|
||||
|
||||
ASSERT_NO_THROW(NakedDhcpv4Srv::adjustIfaceData(ex));
|
||||
// Set the client port.
|
||||
srv_.client_port_ = 1234;
|
||||
|
||||
ASSERT_NO_THROW(srv_.adjustIfaceData(ex));
|
||||
|
||||
// Response should be sent back to the relay address.
|
||||
EXPECT_EQ("192.0.1.50", resp->getRemoteAddr().toText());
|
||||
|
||||
// Remote port was enforced to the client port.
|
||||
EXPECT_EQ(srv_.client_port_, resp->getRemotePort());
|
||||
}
|
||||
|
||||
// This test verifies that the remote port is adjusted when
|
||||
@ -260,7 +266,7 @@ TEST_F(Dhcpv4SrvTest, adjustIfaceDataRelayPort) {
|
||||
resp->setRemotePort(67);
|
||||
|
||||
// This function never throws.
|
||||
ASSERT_NO_THROW(NakedDhcpv4Srv::adjustIfaceData(ex));
|
||||
ASSERT_NO_THROW(srv_.adjustIfaceData(ex));
|
||||
|
||||
// Now the destination address should be relay's address.
|
||||
EXPECT_EQ("192.0.1.1", resp->getRemoteAddr().toText());
|
||||
@ -325,7 +331,7 @@ TEST_F(Dhcpv4SrvTest, adjustIfaceDataUseRouting) {
|
||||
resp->setHops(req->getHops());
|
||||
|
||||
// This function never throws.
|
||||
ASSERT_NO_THROW(NakedDhcpv4Srv::adjustIfaceData(ex));
|
||||
ASSERT_NO_THROW(srv_.adjustIfaceData(ex));
|
||||
|
||||
// Now the destination address should be relay's address.
|
||||
EXPECT_EQ("192.0.1.1", resp->getRemoteAddr().toText());
|
||||
@ -354,7 +360,7 @@ TEST_F(Dhcpv4SrvTest, adjustIfaceDataUseRouting) {
|
||||
cfg_iface->setOutboundIface(CfgIface::SAME_AS_INBOUND);
|
||||
CfgMgr::instance().commit();
|
||||
|
||||
ASSERT_NO_THROW(NakedDhcpv4Srv::adjustIfaceData(ex));
|
||||
ASSERT_NO_THROW(srv_.adjustIfaceData(ex));
|
||||
|
||||
EXPECT_EQ("192.0.2.5", resp->getLocalAddr().toText());
|
||||
EXPECT_EQ("eth1", resp->getIface());
|
||||
@ -409,7 +415,7 @@ TEST_F(Dhcpv4SrvTest, adjustIfaceDataRenew) {
|
||||
// Copy hops value from the query.
|
||||
resp->setHops(req->getHops());
|
||||
|
||||
ASSERT_NO_THROW(NakedDhcpv4Srv::adjustIfaceData(ex));
|
||||
ASSERT_NO_THROW(srv_.adjustIfaceData(ex));
|
||||
|
||||
// Check that server responds to ciaddr
|
||||
EXPECT_EQ("192.0.1.15", resp->getRemoteAddr().toText());
|
||||
@ -482,7 +488,7 @@ TEST_F(Dhcpv4SrvTest, adjustIfaceDataSelect) {
|
||||
// are zero and client has just got new lease, the assigned address is
|
||||
// carried in yiaddr. In order to send this address to the client,
|
||||
// server must broadcast its response.
|
||||
ASSERT_NO_THROW(NakedDhcpv4Srv::adjustIfaceData(ex));
|
||||
ASSERT_NO_THROW(srv_.adjustIfaceData(ex));
|
||||
|
||||
// Check that the response is sent to broadcast address as the
|
||||
// server doesn't have capability to respond directly.
|
||||
@ -511,7 +517,7 @@ TEST_F(Dhcpv4SrvTest, adjustIfaceDataSelect) {
|
||||
|
||||
// Now we expect that the server will send its response to the
|
||||
// address assigned for the client.
|
||||
ASSERT_NO_THROW(NakedDhcpv4Srv::adjustIfaceData(ex));
|
||||
ASSERT_NO_THROW(srv_.adjustIfaceData(ex));
|
||||
|
||||
EXPECT_EQ("192.0.1.13", resp->getRemoteAddr().toText());
|
||||
}
|
||||
@ -553,7 +559,7 @@ TEST_F(Dhcpv4SrvTest, adjustIfaceDataBroadcast) {
|
||||
// Clear the remote address.
|
||||
resp->setRemoteAddr(IOAddress("0.0.0.0"));
|
||||
|
||||
ASSERT_NO_THROW(NakedDhcpv4Srv::adjustIfaceData(ex));
|
||||
ASSERT_NO_THROW(srv_.adjustIfaceData(ex));
|
||||
|
||||
// Server must respond to broadcast address when client desired that
|
||||
// by setting the broadcast flag in its request.
|
||||
|
@ -229,6 +229,7 @@ public:
|
||||
using Dhcpv4Srv::VENDOR_CLASS_PREFIX;
|
||||
using Dhcpv4Srv::shutdown_;
|
||||
using Dhcpv4Srv::alloc_engine_;
|
||||
using Dhcpv4Srv::client_port_;
|
||||
};
|
||||
|
||||
// We need to pass one reference to the Dhcp4Client, which is defined in
|
||||
|
@ -738,8 +738,10 @@ ControlledDhcpv6Srv::checkConfig(isc::data::ConstElementPtr config) {
|
||||
return (configureDhcp6Server(*srv, config, true));
|
||||
}
|
||||
|
||||
ControlledDhcpv6Srv::ControlledDhcpv6Srv(uint16_t server_port)
|
||||
: Dhcpv6Srv(server_port), io_service_(), timer_mgr_(TimerMgr::instance()) {
|
||||
ControlledDhcpv6Srv::ControlledDhcpv6Srv(uint16_t server_port,
|
||||
uint16_t client_port)
|
||||
: Dhcpv6Srv(server_port, client_port), io_service_(),
|
||||
timer_mgr_(TimerMgr::instance()) {
|
||||
if (server_) {
|
||||
isc_throw(InvalidOperation,
|
||||
"There is another Dhcpv6Srv instance already.");
|
||||
|
@ -28,7 +28,9 @@ public:
|
||||
/// @brief Constructor
|
||||
///
|
||||
/// @param server_port UDP port to be opened for DHCP traffic
|
||||
ControlledDhcpv6Srv(uint16_t server_port = DHCP6_SERVER_PORT);
|
||||
/// @param client_port UDP port where all responses are sent to.
|
||||
ControlledDhcpv6Srv(uint16_t server_port = DHCP6_SERVER_PORT,
|
||||
uint16_t client_port = 0);
|
||||
|
||||
/// @brief Destructor.
|
||||
virtual ~ControlledDhcpv6Srv();
|
||||
|
@ -782,7 +782,7 @@ This informational message indicates that the IPv6 DHCP server has
|
||||
processed any command-line switches and is starting. The version
|
||||
is also printed.
|
||||
|
||||
% DHCP6_START_INFO pid: %1, server port: %2, verbose: %3
|
||||
% DHCP6_START_INFO pid: %1, server port: %2, client port: %3, verbose: %4
|
||||
This is a debug message issued during the IPv6 DHCP server startup.
|
||||
It lists some information about the parameters with which the server
|
||||
is running.
|
||||
|
@ -179,15 +179,18 @@ namespace dhcp {
|
||||
|
||||
const std::string Dhcpv6Srv::VENDOR_CLASS_PREFIX("VENDOR_CLASS_");
|
||||
|
||||
Dhcpv6Srv::Dhcpv6Srv(uint16_t server_port)
|
||||
: io_service_(new IOService()), server_port_(server_port), serverid_(),
|
||||
shutdown_(true), alloc_engine_(), name_change_reqs_(),
|
||||
Dhcpv6Srv::Dhcpv6Srv(uint16_t server_port, uint16_t client_port)
|
||||
: io_service_(new IOService()), server_port_(server_port),
|
||||
client_port_(client_port), serverid_(), shutdown_(true),
|
||||
alloc_engine_(), name_change_reqs_(),
|
||||
network_state_(new NetworkState(NetworkState::DHCPv6))
|
||||
{
|
||||
|
||||
LOG_DEBUG(dhcp6_logger, DBG_DHCP6_START, DHCP6_OPEN_SOCKET)
|
||||
.arg(server_port);
|
||||
|
||||
Dhcp6to4Ipc::instance().client_port = client_port;
|
||||
|
||||
// Initialize objects required for DHCP server operation.
|
||||
try {
|
||||
// Port 0 is used for testing purposes where in most cases we don't
|
||||
@ -775,7 +778,10 @@ Dhcpv6Srv::processPacket(Pkt6Ptr& query, Pkt6Ptr& rsp) {
|
||||
rsp->setRemoteAddr(query->getRemoteAddr());
|
||||
rsp->setLocalAddr(query->getLocalAddr());
|
||||
|
||||
if (rsp->relay_info_.empty()) {
|
||||
if (client_port_) {
|
||||
// A command line option enforces a specific client port
|
||||
rsp->setRemotePort(client_port_);
|
||||
} else if (rsp->relay_info_.empty()) {
|
||||
// Direct traffic, send back to the client directly
|
||||
rsp->setRemotePort(DHCP6_CLIENT_PORT);
|
||||
} else {
|
||||
|
@ -80,8 +80,10 @@ public:
|
||||
/// network interaction. Will instantiate lease manager, and load
|
||||
/// old or create new DUID.
|
||||
///
|
||||
/// @param server_port port on will all sockets will listen
|
||||
Dhcpv6Srv(uint16_t server_port = DHCP6_SERVER_PORT);
|
||||
/// @param server_port port on which all sockets will listen
|
||||
/// @param client_port port to which all responses will be sent
|
||||
Dhcpv6Srv(uint16_t server_port = DHCP6_SERVER_PORT,
|
||||
uint16_t client_port = 0);
|
||||
|
||||
/// @brief Destructor. Used during DHCPv6 service shutdown.
|
||||
virtual ~Dhcpv6Srv();
|
||||
@ -943,6 +945,10 @@ private:
|
||||
/// UDP port number on which server listens.
|
||||
uint16_t server_port_;
|
||||
|
||||
protected:
|
||||
/// UDP port number to which server sends all responses.
|
||||
uint16_t client_port_;
|
||||
|
||||
public:
|
||||
/// @note used by DHCPv4-over-DHCPv6 so must be public and static
|
||||
|
||||
|
@ -27,6 +27,8 @@ using namespace isc::hooks;
|
||||
namespace isc {
|
||||
namespace dhcp {
|
||||
|
||||
uint16_t Dhcp6to4Ipc::client_port = 0;
|
||||
|
||||
Dhcp6to4Ipc::Dhcp6to4Ipc() : Dhcp4o6IpcBase() {}
|
||||
|
||||
Dhcp6to4Ipc& Dhcp6to4Ipc::instance() {
|
||||
@ -93,7 +95,10 @@ void Dhcp6to4Ipc::handler() {
|
||||
// want to know if it is a relayed message (vs. internal message type).
|
||||
// getType() always returns the type of internal message.
|
||||
uint8_t msg_type = buf[0];
|
||||
if ((msg_type == DHCPV6_RELAY_FORW) || (msg_type == DHCPV6_RELAY_REPL)) {
|
||||
if (client_port) {
|
||||
pkt->setRemotePort(client_port);
|
||||
} else if ((msg_type == DHCPV6_RELAY_FORW) ||
|
||||
(msg_type == DHCPV6_RELAY_REPL)) {
|
||||
pkt->setRemotePort(relay_port ? relay_port : DHCP6_SERVER_PORT);
|
||||
} else {
|
||||
pkt->setRemotePort(DHCP6_CLIENT_PORT);
|
||||
|
@ -45,6 +45,10 @@ public:
|
||||
///
|
||||
/// The handler sends the DHCPv6 packet back to the remote address
|
||||
static void handler();
|
||||
|
||||
/// @param client_port UDP port where all responses are sent to.
|
||||
/// Not zero is mostly useful for testing purposes.
|
||||
static uint16_t client_port;
|
||||
};
|
||||
|
||||
} // namespace isc
|
||||
|
@ -49,7 +49,7 @@ usage() {
|
||||
cerr << "Kea DHCPv6 server, version " << VERSION << endl;
|
||||
cerr << endl;
|
||||
cerr << "Usage: " << DHCP6_NAME
|
||||
<< " -[v|V|W] [-d] [-{c|t} cfgfile] [-p server_port_number]" << endl;
|
||||
<< " -[v|V|W] [-d] [-{c|t} cfgfile] [-p number] [-P number]" << endl;
|
||||
cerr << " -v: print version number and exit." << endl;
|
||||
cerr << " -V: print extended version and exit" << endl;
|
||||
cerr << " -W: display the configuration report and exit" << endl;
|
||||
@ -58,6 +58,8 @@ usage() {
|
||||
cerr << " -t file: check the configuration file syntax and exit" << endl;
|
||||
cerr << " -p number: specify non-standard server port number 1-65535 "
|
||||
<< "(useful for testing only)" << endl;
|
||||
cerr << " -P number: specify non-standard client port number 1-65535 "
|
||||
<< "(useful for testing only)" << endl;
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
} // end of anonymous namespace
|
||||
@ -67,13 +69,15 @@ main(int argc, char* argv[]) {
|
||||
int ch;
|
||||
// The default. Any other values are useful for testing only.
|
||||
int server_port_number = DHCP6_SERVER_PORT;
|
||||
// Not zero values are useful for testing only.
|
||||
int client_port_number = 0;
|
||||
bool verbose_mode = false; // Should server be verbose?
|
||||
bool check_mode = false; // Check syntax
|
||||
|
||||
// The standard config file
|
||||
std::string config_file("");
|
||||
|
||||
while ((ch = getopt(argc, argv, "dvVWc:p:t:")) != -1) {
|
||||
while ((ch = getopt(argc, argv, "dvVWc:p:P:t:")) != -1) {
|
||||
switch (ch) {
|
||||
case 'd':
|
||||
verbose_mode = true;
|
||||
@ -99,16 +103,31 @@ main(int argc, char* argv[]) {
|
||||
config_file = optarg;
|
||||
break;
|
||||
|
||||
case 'p': // port number
|
||||
case 'p': // server port number
|
||||
try {
|
||||
server_port_number = boost::lexical_cast<int>(optarg);
|
||||
} catch (const boost::bad_lexical_cast &) {
|
||||
cerr << "Failed to parse port number: [" << optarg
|
||||
cerr << "Failed to parse server port number: [" << optarg
|
||||
<< "], 1-65535 allowed." << endl;
|
||||
usage();
|
||||
}
|
||||
if (server_port_number <= 0 || server_port_number > 65535) {
|
||||
cerr << "Failed to parse port number: [" << optarg
|
||||
cerr << "Failed to parse server port number: [" << optarg
|
||||
<< "], 1-65535 allowed." << endl;
|
||||
usage();
|
||||
}
|
||||
break;
|
||||
|
||||
case 'P': // client port number
|
||||
try {
|
||||
client_port_number = boost::lexical_cast<int>(optarg);
|
||||
} catch (const boost::bad_lexical_cast &) {
|
||||
cerr << "Failed to parse client port number: [" << optarg
|
||||
<< "], 1-65535 allowed." << endl;
|
||||
usage();
|
||||
}
|
||||
if (client_port_number <= 0 || client_port_number > 65535) {
|
||||
cerr << "Failed to parse client port number: [" << optarg
|
||||
<< "], 1-65535 allowed." << endl;
|
||||
usage();
|
||||
}
|
||||
@ -194,13 +213,15 @@ main(int argc, char* argv[]) {
|
||||
Daemon::loggerInit(DHCP6_LOGGER_NAME, verbose_mode);
|
||||
|
||||
LOG_DEBUG(dhcp6_logger, DBG_DHCP6_START, DHCP6_START_INFO)
|
||||
.arg(getpid()).arg(server_port_number)
|
||||
.arg(getpid())
|
||||
.arg(server_port_number)
|
||||
.arg(client_port_number)
|
||||
.arg(verbose_mode ? "yes" : "no");
|
||||
|
||||
LOG_INFO(dhcp6_logger, DHCP6_STARTING).arg(VERSION);
|
||||
|
||||
// Create the server instance.
|
||||
ControlledDhcpv6Srv server(server_port_number);
|
||||
ControlledDhcpv6Srv server(server_port_number, client_port_number);
|
||||
|
||||
// Remember verbose-mode
|
||||
server.setVerbose(verbose_mode);
|
||||
|
@ -1609,6 +1609,35 @@ TEST_F(Dhcpv6SrvTest, selectSubnetRelayInterfaceId) {
|
||||
EXPECT_FALSE(drop);
|
||||
}
|
||||
|
||||
// Checks if server responses are sent to the proper port.
|
||||
TEST_F(Dhcpv6SrvTest, portsClientPort) {
|
||||
|
||||
NakedDhcpv6Srv srv(0);
|
||||
|
||||
// Enforce a specific client port value.
|
||||
EXPECT_EQ(0, srv.client_port_);
|
||||
srv.client_port_ = 1234;
|
||||
|
||||
// Let's create a simple SOLICIT
|
||||
Pkt6Ptr sol = PktCaptures::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(srv.client_port_, adv->getRemotePort());
|
||||
}
|
||||
|
||||
// Checks if server responses are sent to the proper port.
|
||||
TEST_F(Dhcpv6SrvTest, portsDirectTraffic) {
|
||||
|
||||
|
@ -272,6 +272,7 @@ public:
|
||||
using Dhcpv6Srv::name_change_reqs_;
|
||||
using Dhcpv6Srv::VENDOR_CLASS_PREFIX;
|
||||
using Dhcpv6Srv::initContext;
|
||||
using Dhcpv6Srv::client_port_;
|
||||
|
||||
/// @brief packets we pretend to receive
|
||||
///
|
||||
|
@ -139,6 +139,9 @@ TEST_F(Dhcp6to4IpcTest, receive) {
|
||||
// Create instance of the IPC endpoint being used as a source of messages.
|
||||
TestIpc src_ipc(TEST_PORT, TestIpc::ENDPOINT_TYPE_V4);
|
||||
|
||||
// Reset the IPC.
|
||||
ASSERT_NO_THROW(ipc.close());
|
||||
|
||||
// Open both endpoints.
|
||||
ASSERT_NO_THROW(ipc.open());
|
||||
ASSERT_NO_THROW(src_ipc.open());
|
||||
@ -197,6 +200,9 @@ TEST_F(Dhcp6to4IpcTest, DISABLED_receiveRelayed) {
|
||||
// Create instance of the IPC endpoint being used as a source of messages.
|
||||
TestIpc src_ipc(TEST_PORT, TestIpc::ENDPOINT_TYPE_V4);
|
||||
|
||||
// Reset the IPC.
|
||||
ASSERT_NO_THROW(ipc.close());
|
||||
|
||||
// Open both endpoints.
|
||||
ASSERT_NO_THROW(ipc.open());
|
||||
ASSERT_NO_THROW(src_ipc.open());
|
||||
@ -249,4 +255,49 @@ TEST_F(Dhcp6to4IpcTest, DISABLED_receiveRelayed) {
|
||||
EXPECT_EQ(1, d4_resp->getInteger().first);
|
||||
}
|
||||
|
||||
// This test verifies the client port is enforced also with DHCP4o6.
|
||||
TEST_F(Dhcp6to4IpcTest, clientPort) {
|
||||
// Create instance of the IPC endpoint under test.
|
||||
Dhcp6to4Ipc& ipc = Dhcp6to4Ipc::instance();
|
||||
// Set the client port.
|
||||
ipc.client_port = 1234;
|
||||
// Create instance of the IPC endpoint being used as a source of messages.
|
||||
TestIpc src_ipc(TEST_PORT, TestIpc::ENDPOINT_TYPE_V4);
|
||||
|
||||
// Reset the IPC.
|
||||
ASSERT_NO_THROW(ipc.close());
|
||||
|
||||
// Open both endpoints.
|
||||
ASSERT_NO_THROW(ipc.open());
|
||||
ASSERT_NO_THROW(src_ipc.open());
|
||||
|
||||
// Create message to be sent over IPC.
|
||||
Pkt6Ptr pkt(new Pkt6(DHCPV6_DHCPV4_RESPONSE, 1234));
|
||||
pkt->addOption(createDHCPv4MsgOption());
|
||||
pkt->setIface("eth0");
|
||||
pkt->setRemoteAddr(IOAddress("2001:db8:1::123"));
|
||||
ASSERT_NO_THROW(pkt->pack());
|
||||
|
||||
// Reset the callout cached packet
|
||||
Dhcp6to4IpcTest::callback_pkt_.reset();
|
||||
|
||||
// Send and wait up to 1 second to receive it.
|
||||
ASSERT_NO_THROW(src_ipc.send(pkt));
|
||||
ASSERT_NO_THROW(IfaceMgr::instance().receive6(1, 0));
|
||||
|
||||
// Make sure that the received packet was configured to return copy of
|
||||
// retrieved options within a callout.
|
||||
EXPECT_TRUE(callback_pkt_options_copy_);
|
||||
|
||||
// Get the forwarded packet from the callout
|
||||
Pkt6Ptr forwarded = Dhcp6to4IpcTest::callback_pkt_;
|
||||
ASSERT_TRUE(forwarded);
|
||||
|
||||
// Verify the packet received.
|
||||
EXPECT_EQ(ipc.client_port, forwarded->getRemotePort());
|
||||
|
||||
// Reset the value in case tests are not in order.
|
||||
ipc.client_port = 0;
|
||||
}
|
||||
|
||||
} // end of anonymous namespace
|
||||
|
@ -138,6 +138,7 @@ CommandOptions::reset() {
|
||||
is_interface_ = false;
|
||||
preload_ = 0;
|
||||
local_port_ = 0;
|
||||
remote_port_ = 0;
|
||||
seeded_ = false;
|
||||
seed_ = 0;
|
||||
broadcast_ = false;
|
||||
@ -226,7 +227,7 @@ CommandOptions::initialize(int argc, char** argv, bool print_cmd_line) {
|
||||
|
||||
// In this section we collect argument values from command line
|
||||
// they will be tuned and validated elsewhere
|
||||
while((opt = getopt(argc, argv, "hv46A:r:t:R:b:n:p:d:D:l:P:L:M:"
|
||||
while((opt = getopt(argc, argv, "hv46A:r:t:R:b:n:p:d:D:l:P:a:L:N:M:"
|
||||
"s:iBc1T:X:O:o:E:S:I:x:W:w:e:f:F:g:")) != -1) {
|
||||
stream << " -" << static_cast<char>(opt);
|
||||
if (optarg) {
|
||||
@ -373,8 +374,18 @@ CommandOptions::initialize(int argc, char** argv, bool print_cmd_line) {
|
||||
" negative integer");
|
||||
check(local_port_ >
|
||||
static_cast<int>(std::numeric_limits<uint16_t>::max()),
|
||||
"local-port must be lower than " +
|
||||
boost::lexical_cast<std::string>(std::numeric_limits<uint16_t>::max()));
|
||||
"local-port must be lower than " +
|
||||
boost::lexical_cast<std::string>(std::numeric_limits<uint16_t>::max()));
|
||||
break;
|
||||
|
||||
case 'N':
|
||||
remote_port_ = nonNegativeInteger("value of remote port:"
|
||||
" -L<value> must not be a"
|
||||
" negative integer");
|
||||
check(remote_port_ >
|
||||
static_cast<int>(std::numeric_limits<uint16_t>::max()),
|
||||
"remote-port must be lower than " +
|
||||
boost::lexical_cast<std::string>(std::numeric_limits<uint16_t>::max()));
|
||||
break;
|
||||
|
||||
case 'M':
|
||||
@ -992,6 +1003,9 @@ CommandOptions::printCommandLine() const {
|
||||
if (getLocalPort() != 0) {
|
||||
std::cout << "local-port=" << local_port_ << std::endl;
|
||||
}
|
||||
if (getRemotePort() != 0) {
|
||||
std::cout << "remote-port=" << remote_port_ << std::endl;
|
||||
}
|
||||
if (seeded_) {
|
||||
std::cout << "seed=" << seed_ << std::endl;
|
||||
}
|
||||
@ -1056,8 +1070,8 @@ CommandOptions::usage() const {
|
||||
" [-F<release-rate>] [-t<report>] [-R<range>] [-b<base>]\n"
|
||||
" [-n<num-request>] [-p<test-period>] [-d<drop-time>]\n"
|
||||
" [-D<max-drop>] [-l<local-addr|interface>] [-P<preload>]\n"
|
||||
" [-L<local-port>] [-s<seed>] [-i] [-B] [-g<single/multi>]\n"
|
||||
" [-W<late-exit-delay>]\n"
|
||||
" [-L<local-port>] [-N<remote-port>]\n"
|
||||
" [-s<seed>] [-i] [-B] [-W<late-exit-delay>]\n"
|
||||
" [-c] [-1] [-M<mac-list-file>] [-T<template-file>]\n"
|
||||
" [-X<xid-offset>] [-O<random-offset] [-E<time-offset>]\n"
|
||||
" [-S<srvid-offset>] [-I<ip-offset>] [-x<diagnostic-selector>]\n"
|
||||
@ -1129,6 +1143,8 @@ CommandOptions::usage() const {
|
||||
" from this list for every new exchange. In the DHCPv6 case, MAC\n"
|
||||
" addresses are used to generate DUID-LLs. This parameter must not be\n"
|
||||
" used in conjunction with the -b parameter.\n"
|
||||
"-N<remote-port>: Specify the remote port to use\n"
|
||||
" (the value 0 means to use the default).\n"
|
||||
"-O<random-offset>: Offset of the last octet to randomize in the template.\n"
|
||||
"-P<preload>: Initiate first <preload> exchanges back to back at startup.\n"
|
||||
"-r<rate>: Initiate <rate> DORA/SARR (or if -i is given, DO/SA)\n"
|
||||
|
@ -243,6 +243,11 @@ public:
|
||||
/// \return local port number.
|
||||
int getLocalPort() const { return local_port_; }
|
||||
|
||||
/// \brief Returns remote port number.
|
||||
///
|
||||
/// \return remote port number.
|
||||
int getRemotePort() const { return remote_port_; }
|
||||
|
||||
/// @brief Returns the time in microseconds to delay the program by.
|
||||
///
|
||||
/// @return the time in microseconds to delay the program by.
|
||||
@ -577,6 +582,9 @@ private:
|
||||
/// Local port number (host endian)
|
||||
int local_port_;
|
||||
|
||||
/// Remote port number (host endian)
|
||||
int remote_port_;
|
||||
|
||||
/// Randomization seed.
|
||||
uint32_t seed_;
|
||||
|
||||
|
@ -64,6 +64,7 @@
|
||||
<arg choice="opt" rep="norepeat"><option>-L <replaceable class="parameter">local-port</replaceable></option></arg>
|
||||
<arg choice="opt" rep="norepeat"><option>-M <replaceable class="parameter">mac-list-file</replaceable></option></arg>
|
||||
<arg choice="opt" rep="norepeat"><option>-n <replaceable class="parameter">num-request</replaceable></option></arg>
|
||||
<arg choice="opt" rep="norepeat"><option>-N <replaceable class="parameter">remote-port</replaceable></option></arg>
|
||||
<arg choice="opt" rep="norepeat"><option>-O <replaceable class="parameter">random-offset</replaceable></option></arg>
|
||||
<arg choice="opt" rep="norepeat"><option>-o <replaceable class="parameter">code,hexstring</replaceable></option></arg>
|
||||
<arg choice="opt" rep="norepeat"><option>-p <replaceable class="parameter">test-period</replaceable></option></arg>
|
||||
@ -416,6 +417,18 @@
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>-N <replaceable class="parameter">remote-port</replaceable></option></term>
|
||||
<listitem>
|
||||
<para>
|
||||
Specify the remote port to use. This must be zero
|
||||
or a positive integer up to 65535. A value of 0
|
||||
(the default) allows <command>perfdhcp</command>
|
||||
to choose the standard service port.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>-o <replaceable class="parameter">code,hexstring</replaceable></option></term>
|
||||
<listitem>
|
||||
|
@ -2190,7 +2190,11 @@ TestControl::setDefaults4(const PerfSocket& socket,
|
||||
// Local client's port (68)
|
||||
pkt->setLocalPort(DHCP4_CLIENT_PORT);
|
||||
// Server's port (67)
|
||||
pkt->setRemotePort(DHCP4_SERVER_PORT);
|
||||
if (options.getRemotePort()) {
|
||||
pkt->setRemotePort(options.getRemotePort());
|
||||
} else {
|
||||
pkt->setRemotePort(DHCP4_SERVER_PORT);
|
||||
}
|
||||
// The remote server's name or IP.
|
||||
pkt->setRemoteAddr(IOAddress(options.getServerName()));
|
||||
// Set local address.
|
||||
@ -2216,7 +2220,11 @@ TestControl::setDefaults6(const PerfSocket& socket,
|
||||
// Local client's port (547)
|
||||
pkt->setLocalPort(DHCP6_CLIENT_PORT);
|
||||
// Server's port (548)
|
||||
pkt->setRemotePort(DHCP6_SERVER_PORT);
|
||||
if (options.getRemotePort()) {
|
||||
pkt->setRemotePort(options.getRemotePort());
|
||||
} else {
|
||||
pkt->setRemotePort(DHCP6_SERVER_PORT);
|
||||
}
|
||||
// Set local address.
|
||||
pkt->setLocalAddr(socket.addr_);
|
||||
// The remote server's name or IP.
|
||||
|
Loading…
x
Reference in New Issue
Block a user