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
ISC Open Source Projects
Kea
Commits
ff71887c
Commit
ff71887c
authored
Dec 22, 2014
by
Marcin Siodelski
Browse files
[master] Merge branch 'trac3539'
parents
173fbd24
b0453ead
Changes
11
Hide whitespace changes
Inline
Side-by-side
doc/guide/dhcp4-srv.xml
View file @
ff71887c
...
...
@@ -348,9 +348,19 @@ url="http://jsonviewer.stack.hu/"/>.
with explicit interface names:
<screen>
"Dhcp4": {
<userinput>
"interfaces": [ "eth1", "eth3", "*" ]
</userinput>
, ... }
</screen>
It is anticipated that this
will
form of usage only be used whe
re
it is desired to
It is anticipated that this form of usage
will
only be used whe
n
it is desired to
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:
<screen>
"Dhcp4": {
<userinput>
"interfaces": [ "eth1/10.0.0.1", "eth3/192.0.2.3" ]
</userinput>
, ... }
</screen>
Note that only one address can be specified on each interface.
</para>
</section>
<section
id=
"ipv4-subnet-id"
>
...
...
src/bin/dhcp4/tests/config_parser_unittest.cc
View file @
ff71887c
...
...
@@ -3002,6 +3002,45 @@ TEST_F(Dhcp4ParserTest, allInterfaces) {
ASSERT_TRUE
(
test_config
.
socketOpen
(
"eth1"
,
AF_INET
));
}
// This test verifies that it is possible to select subset of interfaces
// and addresses.
TEST_F
(
Dhcp4ParserTest
,
selectedInterfacesAndAddresses
)
{
IfaceMgrTestConfig
test_config
(
true
);
ConstElementPtr
x
;
string
config
=
"{
\"
interfaces
\"
: [
\"
eth0/10.0.0.1
\"
,
\"
eth1/192.0.2.3
\"
],"
"
\"
rebind-timer
\"
: 2000, "
"
\"
renew-timer
\"
: 1000, "
"
\"
valid-lifetime
\"
: 4000 }"
;
ElementPtr
json
=
Element
::
fromJSON
(
config
);
ConstElementPtr
status
;
// Make sure the config manager is clean and there is no hanging
// interface configuration.
ASSERT_FALSE
(
test_config
.
socketOpen
(
"eth0"
,
"10.0.0.1"
));
ASSERT_FALSE
(
test_config
.
socketOpen
(
"eth1"
,
"192.0.2.3"
));
ASSERT_FALSE
(
test_config
.
socketOpen
(
"eth1"
,
"192.0.2.5"
));
// Apply configuration.
EXPECT_NO_THROW
(
status
=
configureDhcp4Server
(
*
srv_
,
json
));
ASSERT_TRUE
(
status
);
checkResult
(
status
,
0
);
CfgMgr
::
instance
().
getStagingCfg
()
->
getCfgIface
().
openSockets
(
AF_INET
,
10000
);
// An address on eth0 was selected
EXPECT_TRUE
(
test_config
.
socketOpen
(
"eth0"
,
"10.0.0.1"
));
// The 192.0.2.3 address on eth1 was selected.
EXPECT_TRUE
(
test_config
.
socketOpen
(
"eth1"
,
"192.0.2.3"
));
// The 192.0.2.5 was not selected, thus the socket should not
// be bound to this address.
EXPECT_FALSE
(
test_config
.
socketOpen
(
"eth1"
,
"192.0.2.5"
));
}
// This test checks the ability of the server to parse a configuration
// containing a full, valid dhcp-ddns (D2ClientConfig) entry.
TEST_F
(
Dhcp4ParserTest
,
d2ClientConfig
)
{
...
...
src/lib/dhcp/iface_mgr.cc
View file @
ff71887c
...
...
@@ -40,6 +40,7 @@
using
namespace
std
;
using
namespace
isc
::
asiolink
;
using
namespace
isc
::
util
;
using
namespace
isc
::
util
::
io
::
internal
;
namespace
isc
{
...
...
@@ -149,7 +150,7 @@ void Iface::setMac(const uint8_t* mac, size_t len) {
bool
Iface
::
delAddress
(
const
isc
::
asiolink
::
IOAddress
&
addr
)
{
for
(
AddressCollection
::
iterator
a
=
addrs_
.
begin
();
a
!=
addrs_
.
end
();
++
a
)
{
if
(
*
a
==
addr
)
{
if
(
a
->
get
()
==
addr
)
{
addrs_
.
erase
(
a
);
return
(
true
);
}
...
...
@@ -216,12 +217,12 @@ IfaceMgr::IfaceMgr()
void
Iface
::
addUnicast
(
const
isc
::
asiolink
::
IOAddress
&
addr
)
{
for
(
Iface
::
AddressCollection
::
const_iterator
i
=
unicasts_
.
begin
();
i
!=
unicasts_
.
end
();
++
i
)
{
if
(
*
i
==
addr
)
{
if
(
i
->
get
()
==
addr
)
{
isc_throw
(
BadValue
,
"Address "
<<
addr
<<
" already defined on the "
<<
name_
<<
" interface."
);
}
}
unicasts_
.
push_back
(
addr
);
unicasts_
.
push_back
(
OptionalValue
<
IOAddress
>
(
addr
,
true
)
);
}
bool
...
...
@@ -233,8 +234,8 @@ Iface::getAddress4(isc::asiolink::IOAddress& address) const {
addr
!=
addrs
.
end
();
++
addr
)
{
// If address is IPv4, we assign it to the function argument
// and return true.
if
(
addr
->
isV4
())
{
address
=
*
addr
;
if
(
addr
->
get
().
isV4
())
{
address
=
addr
->
get
()
;
return
(
true
);
}
}
...
...
@@ -247,13 +248,39 @@ Iface::hasAddress(const isc::asiolink::IOAddress& address) const {
const
AddressCollection
&
addrs
=
getAddresses
();
for
(
AddressCollection
::
const_iterator
addr
=
addrs
.
begin
();
addr
!=
addrs
.
end
();
++
addr
)
{
if
(
address
==
*
addr
)
{
if
(
address
==
addr
->
get
()
)
{
return
(
true
);
}
}
return
(
false
);
}
void
Iface
::
addAddress
(
const
isc
::
asiolink
::
IOAddress
&
addr
)
{
addrs_
.
push_back
(
OptionalValue
<
IOAddress
>
(
addr
,
OptionalValueState
(
true
)));
}
void
Iface
::
setActive
(
const
IOAddress
&
address
,
const
bool
active
)
{
for
(
AddressCollection
::
iterator
addr_it
=
addrs_
.
begin
();
addr_it
!=
addrs_
.
end
();
++
addr_it
)
{
if
(
address
==
addr_it
->
get
())
{
addr_it
->
specify
(
active
);
return
;
}
}
isc_throw
(
BadValue
,
"specified address "
<<
address
<<
" was not"
" found on the interface "
<<
getName
());
}
void
Iface
::
setActive
(
const
bool
active
)
{
for
(
AddressCollection
::
iterator
addr_it
=
addrs_
.
begin
();
addr_it
!=
addrs_
.
end
();
++
addr_it
)
{
addr_it
->
specify
(
active
);
}
}
void
IfaceMgr
::
closeSockets
()
{
for
(
IfaceCollection
::
iterator
iface
=
ifaces_
.
begin
();
iface
!=
ifaces_
.
end
();
++
iface
)
{
...
...
@@ -393,7 +420,7 @@ IfaceMgr::hasOpenSocket(const IOAddress& addr) const {
iface
->
getAddresses
().
begin
();
addr_it
!=
iface
->
getAddresses
().
end
();
++
addr_it
)
{
if
(
addr
==
*
addr_it
)
{
if
(
addr
==
addr_it
->
get
()
)
{
return
(
true
);
}
}
...
...
@@ -487,8 +514,8 @@ IfaceMgr::openSockets4(const uint16_t port, const bool use_bcast,
addr
!=
addrs
.
end
();
++
addr
)
{
// Skip
all but V
4 addresses.
if
(
!
addr
->
isV4
())
{
// Skip
non-IPv
4 addresses
and those that weren't selected.
.
if
(
!
addr
->
get
().
isV4
()
||
!
addr
->
isSpecified
())
{
continue
;
}
...
...
@@ -616,7 +643,7 @@ IfaceMgr::openSockets6(const uint16_t port,
++
addr
)
{
// Skip all but V6 addresses.
if
(
!
addr
->
isV6
())
{
if
(
!
addr
->
get
().
isV6
())
{
continue
;
}
...
...
@@ -625,7 +652,7 @@ IfaceMgr::openSockets6(const uint16_t port,
// with interface with 2 global addresses, we would bind 3 sockets
// (one for link-local and two for global). That would result in
// getting each message 3 times.
if
(
!
addr
->
isV6LinkLocal
()){
if
(
!
addr
->
get
().
isV6LinkLocal
()){
continue
;
}
...
...
@@ -663,7 +690,7 @@ IfaceMgr::printIfaces(std::ostream& out /*= std::cout*/) {
for
(
Iface
::
AddressCollection
::
const_iterator
addr
=
addrs
.
begin
();
addr
!=
addrs
.
end
();
++
addr
)
{
out
<<
" "
<<
addr
->
toText
();
out
<<
" "
<<
addr
->
get
().
toText
();
}
out
<<
endl
;
}
...
...
@@ -743,7 +770,7 @@ int IfaceMgr::openSocketFromIface(const std::string& ifname,
Iface
::
AddressCollection
addrs
=
iface
->
getAddresses
();
Iface
::
AddressCollection
::
iterator
addr_it
=
addrs
.
begin
();
while
(
addr_it
!=
addrs
.
end
())
{
if
(
addr_it
->
getFamily
()
==
family
)
{
if
(
addr_it
->
get
().
getFamily
()
==
family
)
{
// We have interface and address so let's open socket.
// This may cause isc::Unexpected exception.
return
(
openSocket
(
iface
->
getName
(),
*
addr_it
,
port
,
false
));
...
...
@@ -787,7 +814,7 @@ int IfaceMgr::openSocketFromAddress(const IOAddress& addr,
// on detected interfaces. If it does, we have
// address and interface detected so we can open
// socket.
if
(
*
addr_it
==
addr
)
{
if
(
addr_it
->
get
()
==
addr
)
{
// Open socket using local interface, address and port.
// This may cause isc::Unexpected exception.
return
(
openSocket
(
iface
->
getName
(),
*
addr_it
,
port
,
false
));
...
...
src/lib/dhcp/iface_mgr.h
View file @
ff71887c
...
...
@@ -22,6 +22,7 @@
#include
<dhcp/pkt6.h>
#include
<dhcp/pkt_filter.h>
#include
<dhcp/pkt_filter6.h>
#include
<util/optional_value.h>
#include
<boost/function.hpp>
#include
<boost/noncopyable.hpp>
...
...
@@ -150,7 +151,8 @@ public:
static
const
unsigned
int
MAX_MAC_LEN
=
20
;
/// Type that defines list of addresses
typedef
std
::
vector
<
isc
::
asiolink
::
IOAddress
>
AddressCollection
;
typedef
std
::
list
<
util
::
OptionalValue
<
asiolink
::
IOAddress
>
>
AddressCollection
;
/// @brief Type that holds a list of socket information.
///
...
...
@@ -256,7 +258,15 @@ public:
/// @return hardware type
uint16_t
getHWType
()
const
{
return
hardware_type_
;
}
/// @brief Returns all interfaces available on an interface.
/// @brief Returns all addresses available on an interface.
///
/// The returned addresses are encapsulated in the @c util::OptionalValue
/// class to be able to selectively flag some of the addresses as active
/// (when optional value is specified) or inactive (when optional value
/// is specified). If the address is marked as active, the
/// @c IfaceMgr::openSockets4 method will open socket and bind to this
/// address. Otherwise, it will not bind any socket to this address.
/// This is useful when an interface has multiple IPv4 addresses assigned.
///
/// Care should be taken to not use this collection after Iface object
/// ceases to exist. That is easy in most cases as Iface objects are
...
...
@@ -291,9 +301,30 @@ public:
/// configure address on actual network interface.
///
/// @param addr address to be added
void
addAddress
(
const
isc
::
asiolink
::
IOAddress
&
addr
)
{
addrs_
.
push_back
(
addr
);
}
void
addAddress
(
const
isc
::
asiolink
::
IOAddress
&
addr
);
/// @brief Activates or deactivates address for the interface.
///
/// This method marks a specified address on the interface active or
/// inactive. If the address is marked inactive, the
/// @c IfaceMgr::openSockets4 method will NOT open socket for this address.
///
/// @param address An address which should be activated, deactivated.
/// @param active A boolean flag which indicates that the specified address
/// should be active (if true) or inactive (if false).
///
/// @throw BadValue if specified address doesn't exist for the interface.
void
setActive
(
const
isc
::
asiolink
::
IOAddress
&
address
,
const
bool
active
);
/// @brief Activates or deactivates all addresses for the interface.
///
/// This method marks all addresses on the interface active or inactive.
/// If the address is marked inactive, the @c IfaceMgr::openSockets4
/// method will NOT open socket for this address.
///
/// @param active A boolean flag which indicates that the addresses
/// should be active (if true) or inactive (if false).
void
setActive
(
const
bool
active
);
/// @brief Deletes an address from an interface.
///
...
...
src/lib/dhcp/tests/iface_mgr_test_config.cc
View file @
ff71887c
...
...
@@ -107,6 +107,7 @@ IfaceMgrTestConfig::createIfaces() {
// eth1
addIface
(
"eth1"
,
2
);
addAddress
(
"eth1"
,
IOAddress
(
"192.0.2.3"
));
addAddress
(
"eth1"
,
IOAddress
(
"192.0.2.5"
));
addAddress
(
"eth1"
,
IOAddress
(
"fe80::3a60:77ff:fed5:abcd"
));
}
...
...
@@ -143,7 +144,7 @@ IfaceMgrTestConfig::setIfaceFlags(const std::string& name,
bool
IfaceMgrTestConfig
::
socketOpen
(
const
std
::
string
&
iface_name
,
const
int
family
)
const
{
const
int
family
)
const
{
Iface
*
iface
=
IfaceMgr
::
instance
().
getIface
(
iface_name
);
if
(
iface
==
NULL
)
{
isc_throw
(
Unexpected
,
"No such interface '"
<<
iface_name
<<
"'"
);
...
...
@@ -159,6 +160,25 @@ IfaceMgrTestConfig::socketOpen(const std::string& iface_name,
return
(
false
);
}
bool
IfaceMgrTestConfig
::
socketOpen
(
const
std
::
string
&
iface_name
,
const
std
::
string
&
address
)
const
{
Iface
*
iface
=
IfaceMgr
::
instance
().
getIface
(
iface_name
);
if
(
iface
==
NULL
)
{
isc_throw
(
Unexpected
,
"No such interface '"
<<
iface_name
<<
"'"
);
}
const
Iface
::
SocketCollection
&
sockets
=
iface
->
getSockets
();
for
(
Iface
::
SocketCollection
::
const_iterator
sock
=
sockets
.
begin
();
sock
!=
sockets
.
end
();
++
sock
)
{
if
((
sock
->
family_
==
AF_INET
)
&&
(
sock
->
addr_
==
IOAddress
(
address
)))
{
return
(
true
);
}
}
return
(
false
);
}
bool
IfaceMgrTestConfig
::
unicastOpen
(
const
std
::
string
&
iface_name
)
const
{
Iface
*
iface
=
IfaceMgr
::
instance
().
getIface
(
iface_name
);
...
...
src/lib/dhcp/tests/iface_mgr_test_config.h
View file @
ff71887c
...
...
@@ -235,6 +235,14 @@ public:
/// @param family One of: AF_INET or AF_INET6
bool
socketOpen
(
const
std
::
string
&
iface_name
,
const
int
family
)
const
;
/// @brief Checks is socket is opened on the interface and bound to a
/// specified address.
///
/// @param iface_name Interface name.
/// @param address Address to which the socket is bound.
bool
socketOpen
(
const
std
::
string
&
iface_name
,
const
std
::
string
&
address
)
const
;
/// @brief Checks if unicast socket is opened on interface.
///
/// @param iface_name Interface name.
...
...
src/lib/dhcp/tests/iface_mgr_unittest.cc
View file @
ff71887c
...
...
@@ -289,7 +289,7 @@ public:
iface
->
getAddresses
().
begin
();
addr_it
!=
iface
->
getAddresses
().
end
();
++
addr_it
)
{
if
(
*
addr_it
==
IOAddress
(
addr
))
{
if
(
addr_it
->
get
()
==
IOAddress
(
addr
))
{
return
(
true
);
}
}
...
...
@@ -1501,7 +1501,7 @@ TEST_F(IfaceMgrTest, openSockets4IfaceDown) {
// Expecting that the socket is open on eth1 because it was up, running
// and active.
EXPECT_EQ
(
1
,
IfaceMgr
::
instance
().
getIface
(
"eth1"
)
->
getSockets
().
size
());
EXPECT_EQ
(
2
,
IfaceMgr
::
instance
().
getIface
(
"eth1"
)
->
getSockets
().
size
());
// Never open socket on loopback interface.
EXPECT_TRUE
(
IfaceMgr
::
instance
().
getIface
(
"lo"
)
->
getSockets
().
empty
());
...
...
@@ -2072,7 +2072,7 @@ TEST_F(IfaceMgrTest, iface) {
addrs
=
iface
->
getAddresses
();
ASSERT_EQ
(
1
,
addrs
.
size
());
EXPECT_EQ
(
"192.0.2.6"
,
addrs
.
a
t
(
0
).
toText
());
EXPECT_EQ
(
"192.0.2.6"
,
addrs
.
begin
()
->
ge
t
().
toText
());
// No such address, should return false.
EXPECT_FALSE
(
iface
->
delAddress
(
IOAddress
(
"192.0.8.9"
)));
...
...
@@ -2332,7 +2332,7 @@ checkIfAddrs(const Iface & iface, struct ifaddrs *& ifptr) {
for
(
Iface
::
AddressCollection
::
const_iterator
a
=
iface
.
getAddresses
().
begin
();
a
!=
iface
.
getAddresses
().
end
();
++
a
)
{
if
(
a
->
isV4
()
&&
(
*
a
)
==
addrv4
)
{
if
(
a
->
get
().
isV4
()
&&
(
a
->
get
()
)
==
addrv4
)
{
return
(
true
);
}
}
...
...
@@ -2349,7 +2349,7 @@ checkIfAddrs(const Iface & iface, struct ifaddrs *& ifptr) {
for
(
Iface
::
AddressCollection
::
const_iterator
a
=
iface
.
getAddresses
().
begin
();
a
!=
iface
.
getAddresses
().
end
();
++
a
)
{
if
(
a
->
isV6
()
&&
(
*
a
)
==
addrv6
)
{
if
(
a
->
get
().
isV6
()
&&
(
a
->
get
(
)
==
addrv6
)
)
{
return
(
true
);
}
}
...
...
src/lib/dhcpsrv/cfg_iface.cc
View file @
ff71887c
...
...
@@ -37,7 +37,7 @@ CfgIface::closeSockets() const {
bool
CfgIface
::
equals
(
const
CfgIface
&
other
)
const
{
return
(
iface_set_
==
other
.
iface_set_
&&
unicast
_map_
==
other
.
unicast
_map_
&&
address
_map_
==
other
.
address
_map_
&&
wildcard_used_
==
other
.
wildcard_used_
);
}
...
...
@@ -70,6 +70,20 @@ CfgIface::openSockets(const uint16_t family, const uint16_t port,
}
else
if
(
family
==
AF_INET
)
{
iface
->
inactive4_
=
false
;
ExplicitAddressMap
::
const_iterator
addr
=
address_map_
.
find
(
iface
->
getName
());
// If user has specified an address to listen on, let's activate
// only this address.
if
(
addr
!=
address_map_
.
end
())
{
iface
->
setActive
(
addr
->
second
,
true
);
// Otherwise, activate first one.
}
else
{
IOAddress
address
(
0
);
if
(
iface
->
getAddress4
(
address
))
{
iface
->
setActive
(
address
,
true
);
}
}
}
else
{
iface
->
inactive6_
=
false
;
...
...
@@ -79,8 +93,8 @@ CfgIface::openSockets(const uint16_t family, const uint16_t port,
// Select unicast sockets. It works only for V6. Ignore for V4.
if
(
family
==
AF_INET6
)
{
for
(
Unicast
Map
::
const_iterator
unicast
=
unicast
_map_
.
begin
();
unicast
!=
unicast
_map_
.
end
();
++
unicast
)
{
for
(
ExplicitAddress
Map
::
const_iterator
unicast
=
address
_map_
.
begin
();
unicast
!=
address
_map_
.
end
();
++
unicast
)
{
Iface
*
iface
=
IfaceMgr
::
instance
().
getIface
(
unicast
->
first
);
if
(
iface
==
NULL
)
{
isc_throw
(
Unexpected
,
...
...
@@ -121,6 +135,7 @@ void
CfgIface
::
reset
()
{
wildcard_used_
=
false
;
iface_set_
.
clear
();
address_map_
.
clear
();
}
void
...
...
@@ -130,13 +145,23 @@ CfgIface::setState(const uint16_t family, const bool inactive,
for
(
IfaceMgr
::
IfaceCollection
::
iterator
iface
=
ifaces
.
begin
();
iface
!=
ifaces
.
end
();
++
iface
)
{
Iface
*
iface_ptr
=
IfaceMgr
::
instance
().
getIface
(
iface
->
getName
());
bool
iface_inactive
=
iface_ptr
->
flag_loopback_
?
loopback_inactive
:
inactive
;
if
(
family
==
AF_INET
)
{
iface_ptr
->
inactive4_
=
iface_ptr
->
flag_loopback_
?
loopback_inactive
:
inactive
;
iface_ptr
->
inactive4_
=
iface_inactive
;
}
else
{
iface_ptr
->
inactive6_
=
iface_ptr
->
flag_loopback_
?
loopback_inactive
:
inactive
;
iface_ptr
->
inactive6_
=
iface_inactive
;
}
// Activate/deactivate all addresses.
const
Iface
::
AddressCollection
addresses
=
iface_ptr
->
getAddresses
();
for
(
Iface
::
AddressCollection
::
const_iterator
addr_it
=
addresses
.
begin
();
addr_it
!=
addresses
.
end
();
++
addr_it
)
{
if
(
addr_it
->
get
().
getFamily
()
==
family
)
{
iface_ptr
->
setActive
(
addr_it
->
get
(),
!
iface_inactive
);
}
}
}
}
...
...
@@ -169,18 +194,6 @@ CfgIface::use(const uint16_t family, const std::string& iface_name) {
<<
"' doesn't exist in the system"
);
}
// If interface has already been specified.
if
(
iface_set_
.
find
(
name
)
!=
iface_set_
.
end
())
{
isc_throw
(
DuplicateIfaceName
,
"interface '"
<<
name
<<
"' has already been specified"
);
}
// All ok, add interface.
LOG_INFO
(
dhcpsrv_logger
,
DHCPSRV_CFGMGR_ADD_IFACE
)
.
arg
(
name
);
iface_set_
.
insert
(
name
);
}
else
if
(
wildcard_used_
)
{
isc_throw
(
DuplicateIfaceName
,
"the wildcard interface '"
<<
ALL_IFACES_KEYWORD
<<
"' can only be specified once"
);
...
...
@@ -192,14 +205,10 @@ CfgIface::use(const uint16_t family, const std::string& iface_name) {
}
}
else
if
(
family
==
AF_INET
)
{
isc_throw
(
InvalidIfaceName
,
"unicast addresses in the format of: "
"iface-name/unicast-addr_stress can only be specified for"
" IPv6 addr_stress family"
);
}
else
{
// The interface name includes the unicast addr_stress, so we split
// interface name and the unicast addr_stress to two variables.
// The interface name includes the address on which the socket should
// be opened, we we need to split interface name and the address to
// two variables.
name
=
util
::
str
::
trim
(
iface_name
.
substr
(
0
,
pos
));
addr_str
=
util
::
str
::
trim
(
iface_name
.
substr
(
pos
+
1
));
...
...
@@ -210,10 +219,10 @@ CfgIface::use(const uint16_t family, const std::string& iface_name) {
" interface configuration"
);
}
//
Unicast addr_st
ress following the interface name must not be empty.
//
An add
ress following the interface name must not be empty.
if
(
addr_str
.
empty
())
{
isc_throw
(
InvalidIfaceName
,
"empty
unicast addr_st
ress specified in the interface"
"empty
add
ress specified in the interface"
<<
" configuration"
);
}
...
...
@@ -222,8 +231,8 @@ CfgIface::use(const uint16_t family, const std::string& iface_name) {
if
(
name
==
ALL_IFACES_KEYWORD
)
{
isc_throw
(
InvalidIfaceName
,
"wildcard interface name '"
<<
ALL_IFACES_KEYWORD
<<
"' must not be used in conjunction with a"
"
unicast addr_st
ress"
);
<<
"' must not be used in conjunction with a
n
"
"
add
ress"
);
}
...
...
@@ -239,17 +248,26 @@ CfgIface::use(const uint16_t family, const std::string& iface_name) {
// is invalid.
IOAddress
addr
(
addr_str
);
// Check that the address is a valid unicast address.
if
(
!
addr
.
isV6
()
||
addr
.
isV6LinkLocal
()
||
addr
.
isV6Multicast
())
{
isc_throw
(
InvalidIfaceName
,
"address '"
<<
addr
<<
"' is not"
" a valid IPv6 unicast address"
);
}
// Validate V6 address.
if
(
family
==
AF_INET6
)
{
// Check that the address is a valid unicast address.
if
(
!
addr
.
isV6
()
||
addr
.
isV6Multicast
())
{
isc_throw
(
InvalidIfaceName
,
"address '"
<<
addr
<<
"' is not"
" a valid IPv6 unicast address"
);
}
// There are valid cases where link local address can be specified to
// receive unicast traffic, e.g. sent by relay agent.
if
(
addr
.
isV6LinkLocal
())
{
LOG_WARN
(
dhcpsrv_logger
,
DHCPSRV_CFGMGR_UNICAST_LINK_LOCAL
)
.
arg
(
addr
.
toText
()).
arg
(
name
);
// There are valid cases where link local address can be specified to
// receive unicast traffic, e.g. sent by relay agent.
if
(
addr
.
isV6LinkLocal
())
{
LOG_WARN
(
dhcpsrv_logger
,
DHCPSRV_CFGMGR_UNICAST_LINK_LOCAL
)
.
arg
(
addr
.
toText
()).
arg
(
name
);
}
}
else
{
if
(
!
addr
.
isV4
())
{
isc_throw
(
InvalidIfaceName
,
"address '"
<<
addr
<<
"' is not"
" a valid IPv4 address"
);
}
}
// Interface must have this address assigned.
...
...
@@ -261,17 +279,41 @@ CfgIface::use(const uint16_t family, const std::string& iface_name) {
// Insert address and the interface to the collection of unicast
// addresses.
if
(
unicast
_map_
.
find
(
name
)
!=
unicast
_map_
.
end
())
{
isc_throw
(
DuplicateIfaceName
,
"must not s
pecify unicas
t address '"
if
(
address
_map_
.
find
(
name
)
!=
address
_map_
.
end
())
{
isc_throw
(
DuplicateIfaceName
,
"must not s
elec
t address '"
<<
addr
<<
"' for interface '"
<<
name
<<
"' "
"because other
unicast
address has already been"
"because
an
other address has already been"
" specified for this interface"
);
}
LOG_INFO
(
dhcpsrv_logger
,
DHCPSRV_CFGMGR_ADD_UNICAST
)
.
arg
(
addr
.
toText
()).
arg
(
name
);
unicast_map_
.
insert
(
std
::
pair
<
std
::
string
,
IOAddress
>
(
name
,
addr
));
if
(
family
==
AF_INET6
)
{
LOG_INFO
(
dhcpsrv_logger
,
DHCPSRV_CFGMGR_USE_UNICAST
)
.
arg
(
addr
.
toText
()).
arg
(
name
);
}
else
{
LOG_INFO
(
dhcpsrv_logger
,
DHCPSRV_CFGMGR_USE_ADDRESS
)
.
arg
(
addr
.
toText
()).
arg
(
name
);
}
address_map_
.
insert
(
std
::
pair
<
std
::
string
,
IOAddress
>
(
name
,
addr
));
}
// If interface name was explicitly specified and we're not parsing
// a unicast IPv6 address, add the interface to the interface set.
if
((
name
!=
ALL_IFACES_KEYWORD
)
&&
((
family
==
AF_INET
)
||
((
family
==
AF_INET6
)
&&
addr_str
.
empty
())))
{
// If interface has already been specified.
if
(
iface_set_
.
find
(
name
)
!=
iface_set_
.
end
())
{
isc_throw
(
DuplicateIfaceName
,
"interface '"
<<
name
<<
"' has already been specified"
);
}
// Log that we're listening on the specific interface and that the
// address is not explicitly specified.
if
(
addr_str
.
empty
())
{
LOG_INFO
(
dhcpsrv_logger
,
DHCPSRV_CFGMGR_ADD_IFACE
).
arg
(
name
);
}
iface_set_
.
insert
(
name
);
}
}
}
// end of isc::dhcp namespace
...
...
src/lib/dhcpsrv/cfg_iface.h
View file @
ff71887c
...
...
@@ -12,8 +12,8 @@
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
#ifndef IFACE_
CFG_
H
#define IFACE_
CFG_
H
#ifndef
CFG_
IFACE_H
#define
CFG_
IFACE_H
#include
<asiolink/io_address.h>