Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
Sebastian Schrader
Kea
Commits
31162437
Commit
31162437
authored
Feb 16, 2015
by
Marcin Siodelski
Browse files
[master] Merge branch 'trac3695'
parents
4ace9f75
15d0f2ed
Changes
14
Hide whitespace changes
Inline
Side-by-side
doc/guide/dhcp4-srv.xml
View file @
31162437
...
...
@@ -377,11 +377,9 @@ It is anticipated that this form of usage will only be used when it is desired t
temporarily override a list of interface names and listen on all interfaces.
</para>
<para>
Some deployments of the DHCP servers require that the servers listen
on the interfaces with multiple IPv4 addresses configured. In some cases,
multiple instances of the DHCP servers are running concurrently and each
instance should be bound to a different address on the particular interface.
In these situations, the address to use can be selected by
appending an IPv4 address to the interface name in the following manner:
on the interfaces with multiple IPv4 addresses configured. In these situations,
the address to use can be selected by appending an IPv4 address to the interface
name in the following manner:
<screen>
"Dhcp4": {
"interfaces-config": {
...
...
@@ -390,9 +388,24 @@ temporarily override a list of interface names and listen on all interfaces.
...
}
</screen>
Note that only one address can be specified on each interface.
</para>
<para>
If it is desired that the server listens on multiple IPv4 addresses assigned
to the same interface, multiple addresses can be specified for this interface
as in the example below:
<screen>
"Dhcp4": {
"interfaces-config": {
"interfaces": [
<userinput>
"eth1/10.0.0.1", "eth1/10.0.0.2"
</userinput>
]
},
...
}
</screen>
</para>
<para>
Alternatively, if the server should listen on all addresses for the particular
interface, an interface name without any address should be specified.
</para>
<para>
Kea supports responding to directly connected clients which don't have
an address configured on the interface yet. This requires that the server
injects the hardware address of the destination into the data link layer
...
...
@@ -428,6 +441,20 @@ temporarily override a list of interface names and listen on all interfaces.
default value
<userinput>
raw
</userinput>
is used.
</para>
<para>
Using UDP sockets automatically disables the reception of brodcast
packets from directly connected clients. This effectively means that the
UDP sockets can be used for relayed traffic only. When using the raw sockets,
both the traffic from the directly connected clients and the relayed traffic
will be handled. Caution should be taken when configuring the server to open
multiple raw sockets on the interface with several IPv4 addresses assigned.
If the directly connected client sends the message to the brodcast address
all sockets on this link will receive this message and multiple responses
will be sent to the client. Hence, the configuration with multiple IPv4
addresses assigned to the interface should not be used when the directly
connected clients are operating on that link. To use a single address on
such interface, the "interface-name/address" notation should be used.
</para>
<note>
<para>
Specifying the value
<userinput>
raw
</userinput>
as the socket type,
doesn't guarantee that the raw sockets will be used! The use of raw sockets
...
...
src/bin/dhcp4/dhcp4_srv.cc
View file @
31162437
...
...
@@ -522,10 +522,10 @@ Dhcpv4Srv::copyDefaultFields(const Pkt4Ptr& question, Pkt4Ptr& answer) {
answer
->
setIface
(
question
->
getIface
());
answer
->
setIndex
(
question
->
getIndex
());
answer
->
setSiaddr
(
IOAddress
(
"0.0.0.0"
));
// explicitly set this to 0
answer
->
setSiaddr
(
IOAddress
::
IPV4_ZERO_ADDRESS
(
));
// explicitly set this to 0
// ciaddr is always 0, except for the Renew/Rebind state when it may
// be set to the ciaddr sent by the client.
answer
->
setCiaddr
(
IOAddress
(
"0.0.0.0"
));
answer
->
setCiaddr
(
IOAddress
::
IPV4_ZERO_ADDRESS
(
));
answer
->
setHops
(
question
->
getHops
());
// copy MAC address
...
...
@@ -949,7 +949,7 @@ Dhcpv4Srv::assignLease(const Pkt4Ptr& question, Pkt4Ptr& answer) {
.
arg
(
question
->
getRemoteAddr
().
toText
())
.
arg
(
serverReceivedPacketName
(
question
->
getType
()));
answer
->
setType
(
DHCPNAK
);
answer
->
setYiaddr
(
IOAddress
(
"0.0.0.0"
));
answer
->
setYiaddr
(
IOAddress
::
IPV4_ZERO_ADDRESS
(
));
return
;
}
...
...
@@ -981,11 +981,11 @@ Dhcpv4Srv::assignLease(const Pkt4Ptr& question, Pkt4Ptr& answer) {
// ciaddr.
OptionCustomPtr
opt_requested_address
=
boost
::
dynamic_pointer_cast
<
OptionCustom
>
(
question
->
getOption
(
DHO_DHCP_REQUESTED_ADDRESS
));
IOAddress
hint
(
"0.0.0.0"
);
IOAddress
hint
(
0
);
if
(
opt_requested_address
)
{
hint
=
opt_requested_address
->
readAddress
();
}
else
if
(
question
->
getCiaddr
()
!=
IOAddress
(
"0.0.0.0"
))
{
}
else
if
(
question
->
getCiaddr
()
!=
IOAddress
::
IPV4_ZERO_ADDRESS
(
))
{
hint
=
question
->
getCiaddr
();
}
...
...
@@ -1023,7 +1023,7 @@ Dhcpv4Srv::assignLease(const Pkt4Ptr& question, Pkt4Ptr& answer) {
.
arg
(
hwaddr
?
hwaddr
->
toText
()
:
"(no hwaddr info)"
);
answer
->
setType
(
DHCPNAK
);
answer
->
setYiaddr
(
IOAddress
(
"0.0.0.0"
));
answer
->
setYiaddr
(
IOAddress
::
IPV4_ZERO_ADDRESS
(
));
return
;
}
// Now check the second error case: unknown client.
...
...
@@ -1191,7 +1191,7 @@ Dhcpv4Srv::assignLease(const Pkt4Ptr& question, Pkt4Ptr& answer) {
.
arg
(
hint
.
toText
());
answer
->
setType
(
DHCPNAK
);
answer
->
setYiaddr
(
IOAddress
(
"0.0.0.0"
));
answer
->
setYiaddr
(
IOAddress
::
IPV4_ZERO_ADDRESS
(
));
answer
->
delOption
(
DHO_FQDN
);
answer
->
delOption
(
DHO_HOST_NAME
);
...
...
@@ -1211,6 +1211,27 @@ Dhcpv4Srv::adjustIfaceData(const Pkt4Ptr& query, const Pkt4Ptr& response) {
response
->
setRemotePort
(
query
->
isRelayed
()
?
DHCP4_SERVER_PORT
:
DHCP4_CLIENT_PORT
);
IOAddress
local_addr
=
query
->
getLocalAddr
();
// In many cases the query is sent to a broadcast address. This address
// apears as a local address in the query message. We can't simply copy
// this address to a response message and use it as a source address.
// Instead we will need to use the address assigned to the interface
// on which the query has been received. In other cases, we will just
// use this address as a source address for the response.
if
(
local_addr
==
IOAddress
::
IPV4_BCAST_ADDRESS
())
{
SocketInfo
sock_info
=
IfaceMgr
::
instance
().
getSocket
(
*
query
);
local_addr
=
sock_info
.
addr_
;
}
// We assume that there is an appropriate socket bound to this address
// and that the address is correct. This is safe assumption because
// the local address of the query is set when the query is received.
// The query sent to an incorrect address wouldn't have been received.
// However, if socket is closed for this address between the reception
// of the query and sending a response, the IfaceMgr should detect it
// and return an error.
response
->
setLocalAddr
(
local_addr
);
// In many cases the query is sent to a broadcast address. This address
// appears as a local address in the query message. Therefore we can't
// simply copy local address from the query and use it as a source
...
...
@@ -1219,9 +1240,6 @@ Dhcpv4Srv::adjustIfaceData(const Pkt4Ptr& query, const Pkt4Ptr& response) {
// may throw if for some reason the socket is closed.
/// @todo Consider an optimization that we use local address from
/// the query if this address is not broadcast.
SocketInfo
sock_info
=
IfaceMgr
::
instance
().
getSocket
(
*
query
);
// Set local address, port and interface.
response
->
setLocalAddr
(
sock_info
.
addr_
);
response
->
setLocalPort
(
DHCP4_SERVER_PORT
);
response
->
setIface
(
query
->
getIface
());
response
->
setIndex
(
query
->
getIndex
());
...
...
@@ -1229,13 +1247,6 @@ Dhcpv4Srv::adjustIfaceData(const Pkt4Ptr& query, const Pkt4Ptr& response) {
void
Dhcpv4Srv
::
adjustRemoteAddr
(
const
Pkt4Ptr
&
question
,
const
Pkt4Ptr
&
response
)
{
// Let's create static objects representing zeroed and broadcast
// addresses. We will use them further in this function to test
// other addresses against them. Since they are static, they will
// be created only once.
static
const
IOAddress
zero_addr
(
"0.0.0.0"
);
static
const
IOAddress
bcast_addr
(
"255.255.255.255"
);
// The DHCPINFORM is slightly different than other messages in a sense
// that the server should always unicast the response to the ciaddr.
// It appears however that some clients don't set the ciaddr. We still
...
...
@@ -1244,7 +1255,7 @@ Dhcpv4Srv::adjustRemoteAddr(const Pkt4Ptr& question, const Pkt4Ptr& response) {
if
(
question
->
getType
()
==
DHCPINFORM
)
{
// If client adheres to RFC2131 it will set the ciaddr and in this
// case we always unicast our response to this address.
if
(
question
->
getCiaddr
()
!=
zero_addr
)
{
if
(
question
->
getCiaddr
()
!=
IOAddress
::
IPV4_ZERO_ADDRESS
()
)
{
response
->
setRemoteAddr
(
question
->
getCiaddr
());
// If we received DHCPINFORM via relay and the ciaddr is not set we
...
...
@@ -1275,24 +1286,24 @@ Dhcpv4Srv::adjustRemoteAddr(const Pkt4Ptr& question, const Pkt4Ptr& response) {
// the message is relayed. Therefore, we set the BROADCAST flag so
// as the relay can broadcast the packet.
if
((
question
->
getType
()
==
DHCPINFORM
)
&&
(
question
->
getCiaddr
()
==
zero_addr
))
{
(
question
->
getCiaddr
()
==
IOAddress
::
IPV4_ZERO_ADDRESS
()
))
{
response
->
setFlags
(
BOOTP_BROADCAST
);
}
response
->
setRemoteAddr
(
question
->
getGiaddr
());
// If giaddr is 0 but client set ciaddr, server should unicast the
// response to ciaddr.
}
else
if
(
question
->
getCiaddr
()
!=
zero_addr
)
{
}
else
if
(
question
->
getCiaddr
()
!=
IOAddress
::
IPV4_ZERO_ADDRESS
()
)
{
response
->
setRemoteAddr
(
question
->
getCiaddr
());
// We can't unicast the response to the client when sending NAK,
// because we haven't allocated address for him. Therefore,
// NAK is broadcast.
}
else
if
(
response
->
getType
()
==
DHCPNAK
)
{
response
->
setRemoteAddr
(
bcast_addr
);
response
->
setRemoteAddr
(
IOAddress
::
IPV4_BCAST_ADDRESS
()
);
// If yiaddr is set it means that we have created a lease for a client.
}
else
if
(
response
->
getYiaddr
()
!=
zero_addr
)
{
}
else
if
(
response
->
getYiaddr
()
!=
IOAddress
::
IPV4_ZERO_ADDRESS
()
)
{
// If the broadcast bit is set in the flags field, we have to
// send the response to broadcast address. Client may have requested it
// because it doesn't support reception of messages on the interface
...
...
@@ -1301,7 +1312,7 @@ Dhcpv4Srv::adjustRemoteAddr(const Pkt4Ptr& question, const Pkt4Ptr& response) {
// directly to a client without address assigned.
const
bool
bcast_flag
=
((
question
->
getFlags
()
&
Pkt4
::
FLAG_BROADCAST_MASK
)
!=
0
);
if
(
!
IfaceMgr
::
instance
().
isDirectResponseSupported
()
||
bcast_flag
)
{
response
->
setRemoteAddr
(
bcast_addr
);
response
->
setRemoteAddr
(
IOAddress
::
IPV4_BCAST_ADDRESS
()
);
// Client cleared the broadcast bit and we support direct responses
// so we should unicast the response to a newly allocated address -
...
...
@@ -1356,7 +1367,7 @@ Dhcpv4Srv::processDiscover(Pkt4Ptr& discover) {
}
// Adding any other options makes sense only when we got the lease.
if
(
offer
->
getYiaddr
()
!=
IOAddress
(
"0.0.0.0"
))
{
if
(
offer
->
getYiaddr
()
!=
IOAddress
::
IPV4_ZERO_ADDRESS
(
))
{
appendRequestedOptions
(
discover
,
offer
);
appendRequestedVendorOptions
(
discover
,
offer
);
// There are a few basic options that we always want to
...
...
@@ -1408,7 +1419,7 @@ Dhcpv4Srv::processRequest(Pkt4Ptr& request) {
}
// Adding any other options makes sense only when we got the lease.
if
(
ack
->
getYiaddr
()
!=
IOAddress
(
"0.0.0.0"
))
{
if
(
ack
->
getYiaddr
()
!=
IOAddress
::
IPV4_ZERO_ADDRESS
(
))
{
appendRequestedOptions
(
request
,
ack
);
appendRequestedVendorOptions
(
request
,
ack
);
// There are a few basic options that we always want to
...
...
@@ -1562,7 +1573,7 @@ Dhcpv4Srv::processInform(Pkt4Ptr& inform) {
// Also Relay Agent Options should be removed if present.
if
(
ack
->
getRemoteAddr
()
!=
inform
->
getGiaddr
())
{
ack
->
setHops
(
0
);
ack
->
setGiaddr
(
IOAddress
(
"0.0.0.0"
));
ack
->
setGiaddr
(
IOAddress
::
IPV4_ZERO_ADDRESS
(
));
ack
->
delOption
(
DHO_DHCP_AGENT_OPTIONS
);
}
...
...
@@ -1703,11 +1714,10 @@ Dhcpv4Srv::acceptDirectRequest(const Pkt4Ptr& pkt) const {
// The source address must not be zero for the DHCPINFORM message from
// the directly connected client because the server will not know where
// to respond if the ciaddr was not present.
static
const
IOAddress
zero_addr
(
"0.0.0.0"
);
try
{
if
(
pkt
->
getType
()
==
DHCPINFORM
)
{
if
((
pkt
->
getRemoteAddr
()
==
zero_addr
)
&&
(
pkt
->
getCiaddr
()
==
zero_addr
))
{
if
((
pkt
->
getRemoteAddr
()
==
IOAddress
::
IPV4_ZERO_ADDRESS
()
)
&&
(
pkt
->
getCiaddr
()
==
IOAddress
::
IPV4_ZERO_ADDRESS
()
))
{
return
(
false
);
}
}
...
...
@@ -1717,8 +1727,7 @@ Dhcpv4Srv::acceptDirectRequest(const Pkt4Ptr& pkt) const {
// we validate the message type prior to calling this function.
return
(
false
);
}
static
const
IOAddress
bcast
(
"255.255.255.255"
);
return
((
pkt
->
getLocalAddr
()
!=
bcast
||
selectSubnet
(
pkt
)));
return
((
pkt
->
getLocalAddr
()
!=
IOAddress
::
IPV4_BCAST_ADDRESS
()
||
selectSubnet
(
pkt
)));
}
bool
...
...
@@ -2034,7 +2043,7 @@ bool Dhcpv4Srv::classSpecificProcessing(const Pkt4Ptr& query, const Pkt4Ptr& rsp
if
(
query
->
inClass
(
VENDOR_CLASS_PREFIX
+
DOCSIS3_CLASS_EROUTER
))
{
// Do not set TFTP server address for eRouter devices.
rsp
->
setSiaddr
(
IOAddress
(
"0.0.0.0"
));
rsp
->
setSiaddr
(
IOAddress
::
IPV4_ZERO_ADDRESS
(
));
}
return
(
true
);
...
...
src/bin/dhcp4/tests/dhcp4_srv_unittest.cc
View file @
31162437
...
...
@@ -81,7 +81,7 @@ TEST_F(Dhcpv4SrvTest, adjustIfaceDataRelay) {
req
->
setFlags
(
0x0000
);
// Set local address, port and interface.
req
->
setLocalAddr
(
IOAddress
(
"192.0.2.
1
"
));
req
->
setLocalAddr
(
IOAddress
(
"192.0.2.
5
"
));
req
->
setLocalPort
(
1001
);
req
->
setIface
(
"eth1"
);
req
->
setIndex
(
1
);
...
...
@@ -104,7 +104,7 @@ TEST_F(Dhcpv4SrvTest, adjustIfaceDataRelay) {
// The query has been relayed, so the response must be sent to the port 67.
EXPECT_EQ
(
DHCP4_SERVER_PORT
,
resp
->
getRemotePort
());
// Local address should be the address assigned to interface eth1.
EXPECT_EQ
(
"192.0.2.
3
"
,
resp
->
getLocalAddr
().
toText
());
EXPECT_EQ
(
"192.0.2.
5
"
,
resp
->
getLocalAddr
().
toText
());
// The local port is always DHCPv4 server port 67.
EXPECT_EQ
(
DHCP4_SERVER_PORT
,
resp
->
getLocalPort
());
// We will send response over the same interface which was used to receive
...
...
@@ -184,7 +184,7 @@ TEST_F(Dhcpv4SrvTest, adjustIfaceDataRenew) {
EXPECT_EQ
(
DHCP4_CLIENT_PORT
,
resp
->
getRemotePort
());
// The response should be sent from the unicast address on which the
// query has been received.
EXPECT_EQ
(
"192.0.2.
3
"
,
resp
->
getLocalAddr
().
toText
());
EXPECT_EQ
(
"192.0.2.
1
"
,
resp
->
getLocalAddr
().
toText
());
// The response should be sent from the DHCPv4 server port.
EXPECT_EQ
(
DHCP4_SERVER_PORT
,
resp
->
getLocalPort
());
// The interface data should match the data in the query.
...
...
src/bin/dhcp4/tests/dora_unittest.cc
View file @
31162437
...
...
@@ -656,6 +656,8 @@ TEST_F(DORATest, reservationsWithConflicts) {
// Client A performs 4-way exchange.
client
.
setState
(
Dhcp4Client
::
SELECTING
);
// Revert to the broadcast address for the selcting client.
client
.
setDestAddress
(
IOAddress
::
IPV4_BCAST_ADDRESS
());
// Obtain a lease from the server using the 4-way exchange.
ASSERT_NO_THROW
(
client
.
doDORA
(
boost
::
shared_ptr
<
IOAddress
>
(
new
IOAddress
(
"0.0.0.0"
))));
...
...
src/lib/asiolink/io_address.h
View file @
31162437
// Copyright (C) 2010
Internet Systems Consortium, Inc. ("ISC")
// Copyright (C) 2010
,2015
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
...
...
@@ -230,6 +230,29 @@ public:
/// network byte order
operator
uint32_t
()
const
;
/// @name Methods returning @c IOAddress objects encapsulating typical addresses.
///
//@{
/// @brief Returns an address set to all zeros.
static
const
IOAddress
&
IPV4_ZERO_ADDRESS
()
{
static
IOAddress
address
(
0
);
return
(
address
);
}
/// @brief Returns a "255.255.255.255" broadcast address.
static
const
IOAddress
&
IPV4_BCAST_ADDRESS
()
{
static
IOAddress
address
(
0xFFFFFFFF
);
return
(
address
);
}
/// @brief Returns an IPv6 zero address.
static
const
IOAddress
&
IPV6_ZERO_ADDRESS
()
{
static
IOAddress
address
(
"::"
);
return
(
address
);
}
//@}
private:
asio
::
ip
::
address
asio_address_
;
};
...
...
src/lib/asiolink/tests/io_address_unittest.cc
View file @
31162437
// Copyright (C) 2011
Internet Systems Consortium, Inc. ("ISC")
// Copyright (C) 2011
, 2015
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
...
...
@@ -217,3 +217,9 @@ TEST(IOAddressTest, accessClassificationMethods) {
EXPECT_FALSE
(
addr5
.
isV6LinkLocal
());
EXPECT_TRUE
(
addr5
.
isV6Multicast
());
}
TEST
(
IOAddressTest
,
staticAddresses
)
{
EXPECT_EQ
(
IOAddress
(
"0.0.0.0"
),
IOAddress
::
IPV4_ZERO_ADDRESS
());
EXPECT_EQ
(
IOAddress
(
"255.255.255.255"
),
IOAddress
::
IPV4_BCAST_ADDRESS
());
EXPECT_EQ
(
IOAddress
(
"::"
),
IOAddress
::
IPV6_ZERO_ADDRESS
());
}
src/lib/dhcp/iface_mgr.cc
View file @
31162437
...
...
@@ -257,6 +257,18 @@ Iface::setActive(const bool active) {
}
}
unsigned
int
Iface
::
countActive4
()
const
{
uint16_t
count
=
0
;
for
(
AddressCollection
::
const_iterator
addr_it
=
addrs_
.
begin
();
addr_it
!=
addrs_
.
end
();
++
addr_it
)
{
if
(
addr_it
->
get
().
isV4
()
&&
addr_it
->
isSpecified
())
{
++
count
;
}
}
return
(
count
);
}
void
IfaceMgr
::
closeSockets
()
{
for
(
IfaceCollection
::
iterator
iface
=
ifaces_
.
begin
();
iface
!=
ifaces_
.
end
();
++
iface
)
{
...
...
@@ -1140,7 +1152,7 @@ Pkt6Ptr IfaceMgr::receive6(uint32_t timeout_sec, uint32_t timeout_usec /* = 0 */
uint16_t
IfaceMgr
::
getSocket
(
const
isc
::
dhcp
::
Pkt6
&
pkt
)
{
Iface
*
iface
=
getIface
(
pkt
.
getIface
());
if
(
iface
==
NULL
)
{
isc_throw
(
BadValue
,
"Tried to find socket for non-existent interface"
);
isc_throw
(
IfaceNotFound
,
"Tried to find socket for non-existent interface"
);
}
...
...
@@ -1189,7 +1201,7 @@ uint16_t IfaceMgr::getSocket(const isc::dhcp::Pkt6& pkt) {
return
(
candidate
->
sockfd_
);
}
isc_throw
(
Unexpecte
d
,
"Interface "
<<
iface
->
getFullName
()
isc_throw
(
SocketNotFoun
d
,
"Interface "
<<
iface
->
getFullName
()
<<
" does not have any suitable IPv6 sockets open."
);
}
...
...
@@ -1197,22 +1209,33 @@ SocketInfo
IfaceMgr
::
getSocket
(
isc
::
dhcp
::
Pkt4
const
&
pkt
)
{
Iface
*
iface
=
getIface
(
pkt
.
getIface
());
if
(
iface
==
NULL
)
{
isc_throw
(
BadValue
,
"Tried to find socket for non-existent interface"
);
isc_throw
(
IfaceNotFound
,
"Tried to find socket for non-existent interface"
);
}
const
Iface
::
SocketCollection
&
socket_collection
=
iface
->
getSockets
();
// A candidate being an end of the iterator marks that it is a begining of
// the socket search and that the candidate needs to be set to the first
// socket found.
Iface
::
SocketCollection
::
const_iterator
candidate
=
socket_collection
.
end
();
Iface
::
SocketCollection
::
const_iterator
s
;
for
(
s
=
socket_collection
.
begin
();
s
!=
socket_collection
.
end
();
++
s
)
{
if
(
s
->
family_
==
AF_INET
)
{
return
(
*
s
);
if
(
s
->
addr_
==
pkt
.
getLocalAddr
())
{
return
(
*
s
);
}
if
(
candidate
==
socket_collection
.
end
())
{
candidate
=
s
;
}
}
/// TODO: Add more checks here later. If remote address is
/// not link-local, we can't use link local bound socket
/// to send data.
}
isc_throw
(
Unexpected
,
"Interface "
<<
iface
->
getFullName
()
<<
" does not have any suitable IPv4 sockets open."
);
if
(
candidate
==
socket_collection
.
end
())
{
isc_throw
(
SocketNotFound
,
"Interface "
<<
iface
->
getFullName
()
<<
" does not have any suitable IPv4 sockets open."
);
}
return
(
*
candidate
);
}
}
// end of namespace isc::dhcp
...
...
src/lib/dhcp/iface_mgr.h
View file @
31162437
...
...
@@ -82,6 +82,20 @@ public:
isc
::
Exception
(
file
,
line
,
what
)
{
};
};
/// @brief IfaceMgr exception thrown when there is no suitable interface.
class
IfaceNotFound
:
public
Exception
{
public:
IfaceNotFound
(
const
char
*
file
,
size_t
line
,
const
char
*
what
)
:
isc
::
Exception
(
file
,
line
,
what
)
{
};
};
/// @brief IfaceMgr exception thrown when there is no suitable socket found.
class
SocketNotFound
:
public
Exception
{
public:
SocketNotFound
(
const
char
*
file
,
size_t
line
,
const
char
*
what
)
:
isc
::
Exception
(
file
,
line
,
what
)
{
};
};
/// Holds information about socket.
struct
SocketInfo
{
...
...
@@ -325,6 +339,9 @@ public:
/// should be active (if true) or inactive (if false).
void
setActive
(
const
bool
active
);
/// @brief Returns a number of activated IPv4 addresses on the interface.
unsigned
int
countActive4
()
const
;
/// @brief Deletes an address from an interface.
///
/// This only deletes address from collection, it does not physically
...
...
@@ -614,26 +631,30 @@ public:
///
/// This method takes Pkt6 (see overloaded implementation that takes
/// Pkt4) and chooses appropriate socket to send it. This method
/// may throw
BadValue
if specified packet does not have outbound
///
interface specified,
no such interface exists, or specified
///
interface does not have any
appropriate sockets open.
/// may throw if specified packet does not have outbound
interface specified,
/// no such interface exists, or specified
interface does not have any
/// appropriate sockets open.
///
/// @param pkt a packet to be transmitted
///
/// @return a socket descriptor
/// @throw SocketNotFound If no suitable socket found.
/// @throw IfaceNotFound If interface is not set for the packet.
uint16_t
getSocket
(
const
isc
::
dhcp
::
Pkt6
&
pkt
);
/// @brief Return most suitable socket for transmitting specified IPv4 packet.
///
/// This method
takes Pkt4 (see overloaded implementation that tak
es
///
Pkt6) and chooses appropriate socket to send it. This method
///
may throw BadValue if specified packet does not have outbound
///
interface specified, no such interface exists, or specified
///
interface does not have any appropriate sockets ope
n.
/// This method
uses the local address assigned to the packet and tri
es
///
to match it with addresses to which sockets are bound for the particular
///
interface. If the match is not found, the method returns the first IPv4
///
socket found for the particular interface. In case, there are no IPv4
///
sockets assigned to the interface the exception is throw
n.
///
/// @param pkt a packet to be transmitted
/// @param pkt A packet to be transmitted. It must hold a local address and
/// a valid pointer to the interface.
///
/// @return A structure describing a socket.
/// @throw SocketNotFound if no suitable socket found.
SocketInfo
getSocket
(
const
isc
::
dhcp
::
Pkt4
&
pkt
);
/// Debugging method that prints out all available interfaces.
...
...
src/lib/dhcp/tests/iface_mgr_unittest.cc
View file @
31162437
...
...
@@ -90,6 +90,28 @@ TEST(IfaceTest, readBuffer) {
}
}
// Check that counting the number of active addresses on the interface
// works as expected.
TEST
(
IfaceTest
,
countActive4
)
{
Iface
iface
(
"eth0"
,
0
);
ASSERT_EQ
(
0
,
iface
.
countActive4
());
iface
.
addAddress
(
IOAddress
(
"192.168.0.2"
));
ASSERT_EQ
(
1
,
iface
.
countActive4
());
iface
.
addAddress
(
IOAddress
(
"2001:db8:1::1"
));
ASSERT_EQ
(
1
,
iface
.
countActive4
());
iface
.
addAddress
(
IOAddress
(
"192.168.0.3"
));
ASSERT_EQ
(
2
,
iface
.
countActive4
());
ASSERT_NO_THROW
(
iface
.
setActive
(
IOAddress
(
"192.168.0.2"
),
false
));
ASSERT_EQ
(
1
,
iface
.
countActive4
());
ASSERT_NO_THROW
(
iface
.
setActive
(
IOAddress
(
"192.168.0.3"
),
false
));
ASSERT_EQ
(
0
,
iface
.
countActive4
());
}
/// Mock object implementing PktFilter class. It is used by
/// IfaceMgrTest::setPacketFilter to verify that IfaceMgr::setPacketFilter
/// sets this object as a handler for opening sockets. This dummy
...
...
@@ -2158,17 +2180,17 @@ TEST_F(IfaceMgrTest, socketInfo) {
Pkt6
pkt6
(
DHCPV6_REPLY
,
123456
);
// pkt6 dos not have interface set yet
// pkt6 do
e
s not have interface set yet
EXPECT_THROW
(
ifacemgr
->
getSocket
(
pkt6
),
BadValue
IfaceNotFound
);
// Try to send over non-existing interface
pkt6
.
setIface
(
"nosuchinterface45"
);
EXPECT_THROW
(
ifacemgr
->
getSocket
(
pkt6
),
BadValue
IfaceNotFound
);
// This will work
...
...
@@ -2184,7 +2206,7 @@ TEST_F(IfaceMgrTest, socketInfo) {
// It should throw again, there's no usable socket anymore
EXPECT_THROW
(
ifacemgr
->
getSocket
(
pkt6
),
Unexpecte
d
SocketNotFoun
d
);
// Repeat for pkt4
...
...
@@ -2193,20 +2215,30 @@ TEST_F(IfaceMgrTest, socketInfo) {
// pkt4 does not have interface set yet.
EXPECT_THROW
(
ifacemgr
->
getSocket
(
pkt4
),
BadValue
IfaceNotFound
);
// Try to send over non-existing interface.
pkt4
.
setIface
(
"nosuchinterface45"
);
EXPECT_THROW
(
ifacemgr
->
getSocket
(
pkt4
),
BadValue
IfaceNotFound
);
// Socket info is set, packet has well defined interface. It should work.
pkt4
.
setIface
(
LOOPBACK
);
EXPECT_EQ
(
7
,
ifacemgr
->
getSocket
(
pkt4
).
sockfd_
);
// Set the local address to check if the socket for this address will
// be returned.
pkt4
.
setLocalAddr
(
IOAddress
(
"192.0.2.56"
));
EXPECT_EQ
(
7
,
ifacemgr
->
getSocket
(
pkt4
).
sockfd_
);
// Modify the local address and expect that the other socket will be
// returned.
pkt4
.
setLocalAddr
(
IOAddress
(
"192.0.2.53"
));
EXPECT_EQ
(
8
,
ifacemgr
->
getSocket
(
pkt4
).
sockfd_
);
EXPECT_NO_THROW
(
ifacemgr
->
getIface
(
LOOPBACK
)
->
delSocket
(
7
);
ifacemgr
->
getIface
(
LOOPBACK
)
->
delSocket
(
8
);
...
...
@@ -2215,7 +2247,7 @@ TEST_F(IfaceMgrTest, socketInfo) {
// It should throw again, there's no usable socket anymore.
EXPECT_THROW
(
ifacemgr
->
getSocket
(
pkt4
),
Unexpecte
d
SocketNotFoun
d
);
}
...
...
src/lib/dhcp/tests/pkt_captures4.cc
View file @
31162437
...
...
@@ -62,9 +62,9 @@ Pkt4Ptr PktCaptures::packetFromCapture(const std::string& hex_string) {
void
PktCaptures
::
captureSetDefaultFields
(
const
Pkt4Ptr
&
pkt
)
{
pkt
->
setRemotePort
(
546
);
pkt
->
setRemoteAddr
(
IOAddress
(
"
fe80::1
"
));
pkt
->
setRemoteAddr
(
IOAddress
(
"
10.0.0.2
"
));
pkt
->
setLocalPort
(
0
);
pkt
->
setLocalAddr
(
IOAddress
(
"
ff02::1:2
"
));
pkt
->
setLocalAddr
(
IOAddress
(
"
10.0.0.1
"
));
pkt
->
setIndex
(
2
);
pkt
->
setIface
(
"eth0"
);
}
...
...
src/lib/dhcpsrv/cfg_iface.cc