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
5f6ae1f6
Commit
5f6ae1f6
authored
Jan 14, 2013
by
Tomek Mrugalski
🛰
Browse files
[2597] Server-id in DHCPv4 is now stored to a file.
parent
4c2bed01
Changes
4
Hide whitespace changes
Inline
Side-by-side
src/bin/dhcp4/dhcp4_messages.mes
View file @
5f6ae1f6
...
...
@@ -162,6 +162,24 @@ A debug message listing the data returned to the client.
The IPv4 DHCP server has encountered a fatal error and is terminating.
The reason for the failure is included in the message.
% DHCP4_SERVERID_GENERATED Server-id %1 has been generated and will be stored in %2
This informational messages indicates that the server was not able to read
its server identifier and has generated a new one. This server-id will
be stored in a file and will be read and used during next restart. It is normal
behavior when the server is started for the first time. If this message is printed
every start, please check that the server have sufficient permission to write its
duid file and that the duid file is not corrupted.
% DHCP4_SERVERID_LOADED Server-id %1 has been loaded from file %2
This debug message indicates that the server loaded its server identifier.
That value is sent in all server responses and clients use it to discriminate
between servers. This is a part of normal startup or reconfiguration procedure.
% DHCP4_SERVERID_WRITE_FAIL server was not able to write its duid to file %1
This warning message indicates that server was not able to write its server identifier
(DUID) to a file. This likely indicates lack of write permission to a given
file or directory.
% DHCP4_SESSION_FAIL failed to establish BIND 10 session (%1), running stand-alone
The server has failed to establish communication with the rest of BIND
10 and is running in stand-alone mode. (This behavior will change once
...
...
src/bin/dhcp4/dhcp4_srv.cc
View file @
5f6ae1f6
...
...
@@ -30,6 +30,11 @@
#include
<dhcpsrv/utils.h>
#include
<dhcpsrv/addr_utilities.h>
#include
<boost/algorithm/string/erase.hpp>
#include
<iomanip>
#include
<fstream>
using
namespace
isc
;
using
namespace
isc
::
asiolink
;
using
namespace
isc
::
dhcp
;
...
...
@@ -41,7 +46,6 @@ using namespace std;
const
std
::
string
HARDCODED_GATEWAY
=
"192.0.2.1"
;
const
std
::
string
HARDCODED_DNS_SERVER
=
"192.0.2.2"
;
const
std
::
string
HARDCODED_DOMAIN_NAME
=
"isc.example.com"
;
const
std
::
string
HARDCODED_SERVER_ID
=
"192.0.2.1"
;
Dhcpv4Srv
::
Dhcpv4Srv
(
uint16_t
port
,
const
char
*
dbconfig
)
{
LOG_DEBUG
(
dhcp4_logger
,
DBG_DHCP4_START
,
DHCP4_OPEN_SOCKET
).
arg
(
port
);
...
...
@@ -56,7 +60,22 @@ Dhcpv4Srv::Dhcpv4Srv(uint16_t port, const char* dbconfig) {
IfaceMgr
::
instance
().
openSockets4
(
port
);
}
setServerID
();
string
srvid_file
=
CfgMgr
::
instance
().
getDataDir
()
+
"/"
+
string
(
SERVER_ID_FILE
);
if
(
loadServerID
(
srvid_file
))
{
LOG_DEBUG
(
dhcp4_logger
,
DBG_DHCP4_START
,
DHCP4_SERVERID_LOADED
)
.
arg
(
srvid_file
);
}
else
{
generateServerID
();
LOG_INFO
(
dhcp4_logger
,
DHCP4_SERVERID_GENERATED
)
.
arg
(
srvidToString
(
getServerID
()))
.
arg
(
srvid_file
);
if
(
!
writeServerID
(
srvid_file
))
{
LOG_WARN
(
dhcp4_logger
,
DHCP4_SERVERID_WRITE_FAIL
)
.
arg
(
srvid_file
);
}
}
// Instantiate LeaseMgr
LeaseMgrFactory
::
create
(
dbconfig
);
...
...
@@ -176,19 +195,108 @@ Dhcpv4Srv::run() {
}
}
}
}
return
(
true
);
}
bool
Dhcpv4Srv
::
loadServerID
(
const
std
::
string
&
file_name
)
{
// load content of the file into a string
fstream
f
(
file_name
.
c_str
(),
ios
::
in
);
if
(
!
f
.
is_open
())
{
return
(
false
);
}
string
hex_string
;
f
>>
hex_string
;
f
.
close
();
// remove any spaces
boost
::
algorithm
::
erase_all
(
hex_string
,
" "
);
try
{
IOAddress
addr
(
hex_string
);
if
(
addr
.
getFamily
()
!=
AF_INET
)
{
return
(
false
);
}
// Now create server-id option
serverid_
.
reset
(
new
Option4AddrLst
(
DHO_DHCP_SERVER_IDENTIFIER
,
addr
));
// TODO add support for config session (see src/bin/auth/main.cc)
// so this daemon can be controlled from bob
}
catch
(...)
{
// any kind of malformed input (empty string, IPv6 address, complete
// garbate etc.)
return
(
false
);
}
return
(
true
);
}
void
Dhcpv4Srv
::
setServerID
()
{
/// @todo: implement this for real (see ticket #2588)
serverid_
=
OptionPtr
(
new
Option4AddrLst
(
DHO_DHCP_SERVER_IDENTIFIER
,
IOAddress
(
HARDCODED_SERVER_ID
)));
void
Dhcpv4Srv
::
generateServerID
()
{
const
IfaceMgr
::
IfaceCollection
&
ifaces
=
IfaceMgr
::
instance
().
getIfaces
();
// Let's find suitable interface.
for
(
IfaceMgr
::
IfaceCollection
::
const_iterator
iface
=
ifaces
.
begin
();
iface
!=
ifaces
.
end
();
++
iface
)
{
// Let's don't use loopback.
if
(
iface
->
flag_loopback_
)
{
continue
;
}
// Let's skip downed interfaces. It is better to use working ones.
if
(
!
iface
->
flag_up_
)
{
continue
;
}
const
IfaceMgr
::
AddressCollection
addrs
=
iface
->
getAddresses
();
for
(
IfaceMgr
::
AddressCollection
::
const_iterator
addr
=
addrs
.
begin
();
addr
!=
addrs
.
end
();
++
addr
)
{
if
(
addr
->
getFamily
()
!=
AF_INET
)
{
continue
;
}
serverid_
=
OptionPtr
(
new
Option4AddrLst
(
DHO_DHCP_SERVER_IDENTIFIER
,
*
addr
));
return
;
}
}
isc_throw
(
BadValue
,
"No suitable interfaces for server-identifier found"
);
}
bool
Dhcpv4Srv
::
writeServerID
(
const
std
::
string
&
file_name
)
{
fstream
f
(
file_name
.
c_str
(),
ios
::
out
|
ios
::
trunc
);
if
(
!
f
.
good
())
{
return
(
false
);
}
f
<<
srvidToString
(
getServerID
());
f
.
close
();
}
string
Dhcpv4Srv
::
srvidToString
(
const
OptionPtr
&
srvid
)
{
if
(
!
srvid
)
{
isc_throw
(
BadValue
,
"NULL pointer passed to srvidToString()"
);
}
boost
::
shared_ptr
<
Option4AddrLst
>
generated
=
boost
::
dynamic_pointer_cast
<
Option4AddrLst
>
(
srvid
);
if
(
!
srvid
)
{
isc_throw
(
BadValue
,
"Pointer to invalid option passed to srvidToString()"
);
}
Option4AddrLst
::
AddressContainer
addrs
=
generated
->
getAddresses
();
if
(
addrs
.
size
()
!=
1
)
{
isc_throw
(
BadValue
,
"Malformed option passed to srvidToString(). "
<<
"Expected to contain a single IPv4 address."
);
}
return
(
addrs
[
0
].
toText
());
}
void
Dhcpv4Srv
::
copyDefaultFields
(
const
Pkt4Ptr
&
question
,
Pkt4Ptr
&
answer
)
{
...
...
src/bin/dhcp4/dhcp4_srv.h
View file @
5f6ae1f6
...
...
@@ -28,6 +28,15 @@
namespace
isc
{
namespace
dhcp
{
/// @brief file name of a server-id file
///
/// Server must store its duid in persistent storage that must not change
/// between restarts. This is name of the file that is created in dataDir
/// (see isc::dhcp::CfgMgr::getDataDir()). It is a text file that uses
/// regular IPv4 address, e.g. 192.0.2.1. Server will create it during
/// first run and then use it afterwards.
static
const
char
*
SERVER_ID_FILE
=
"b10-dhcp4-serverid"
;
/// @brief DHCPv4 server service.
///
/// This singleton class represents DHCPv4 server. It contains all
...
...
@@ -216,7 +225,32 @@ protected:
///
/// @throws isc::Unexpected Failed to obtain server identifier (i.e. no
// previously stored configuration and no network interfaces available)
void
setServerID
();
void
generateServerID
();
/// @brief attempts to load server-id from a file
///
/// Tries to load duid from a text file. If the load is successful,
/// it creates server-id option and stores it in serverid_ (to be used
/// later by getServerID()).
///
/// @param file_name name of the server-id file to load
/// @return true if load was successful, false otherwise
bool
loadServerID
(
const
std
::
string
&
file_name
);
/// @brief attempts to write server-id to a file
/// Tries to write server-id content (stored in serverid_) to a text file.
///
/// @param file_name name of the server-id file to write
/// @return true if write was successful, false otherwise
bool
writeServerID
(
const
std
::
string
&
file_name
);
/// @brief converts server-id to text
/// Converts content of server-id option to a text representation, e.g.
/// "192.0.2.1"
///
/// @param opt option that contains server-id
/// @return string representation
static
std
::
string
srvidToString
(
const
OptionPtr
&
opt
);
/// @brief Selects a subnet for a given client's packet.
///
...
...
src/bin/dhcp4/tests/dhcp4_srv_unittest.cc
View file @
5f6ae1f6
...
...
@@ -49,9 +49,15 @@ public:
using
Dhcpv4Srv
::
processDecline
;
using
Dhcpv4Srv
::
processInform
;
using
Dhcpv4Srv
::
getServerID
;
using
Dhcpv4Srv
::
loadServerID
;
using
Dhcpv4Srv
::
generateServerID
;
using
Dhcpv4Srv
::
writeServerID
;
using
Dhcpv4Srv
::
sanityCheck
;
using
Dhcpv4Srv
::
srvidToString
;
};
static
const
char
*
SRVID_FILE
=
"server-id-test.txt"
;
class
Dhcpv4SrvTest
:
public
::
testing
::
Test
{
public:
...
...
@@ -67,6 +73,9 @@ public:
CfgMgr
::
instance
().
deleteSubnets4
();
CfgMgr
::
instance
().
addSubnet4
(
subnet_
);
// it's ok if that fails. There should not be such a file anyway
unlink
(
SRVID_FILE
);
}
/// @brief checks that the response matches request
...
...
@@ -245,6 +254,9 @@ public:
~
Dhcpv4SrvTest
()
{
CfgMgr
::
instance
().
deleteSubnets4
();
// Let's clean up if there is such a file.
unlink
(
SRVID_FILE
);
};
/// @brief A subnet used in most tests
...
...
@@ -691,7 +703,7 @@ TEST_F(Dhcpv4SrvTest, ManyDiscovers) {
checkAddressParams
(
offer2
,
subnet_
);
checkAddressParams
(
offer3
,
subnet_
);
// Check
DUID
s
// Check
server-id
s
checkServerId
(
offer1
,
srv
->
getServerID
());
checkServerId
(
offer2
,
srv
->
getServerID
());
checkServerId
(
offer3
,
srv
->
getServerID
());
...
...
@@ -1126,4 +1138,34 @@ TEST_F(Dhcpv4SrvTest, ReleaseReject) {
EXPECT_FALSE
(
l
);
}
// This test verifies if the server-id disk operations (read, write) are
// working properly.
TEST_F
(
Dhcpv4SrvTest
,
ServerID
)
{
NakedDhcpv4Srv
srv
(
0
);
string
srvid_text
=
"192.0.2.100"
;
IOAddress
srvid
(
srvid_text
);
fstream
file1
(
SRVID_FILE
,
ios
::
out
|
ios
::
trunc
);
file1
<<
srvid_text
;
file1
.
close
();
// Test reading from a file
EXPECT_TRUE
(
srv
.
loadServerID
(
SRVID_FILE
));
ASSERT_TRUE
(
srv
.
getServerID
());
EXPECT_EQ
(
srvid_text
,
srv
.
srvidToString
(
srv
.
getServerID
()));
// Now test writing to a file
EXPECT_EQ
(
0
,
unlink
(
SRVID_FILE
));
EXPECT_NO_THROW
(
srv
.
writeServerID
(
SRVID_FILE
));
fstream
file2
(
SRVID_FILE
,
ios
::
in
);
ASSERT_TRUE
(
file2
.
good
());
string
text
;
file2
>>
text
;
file2
.
close
();
EXPECT_EQ
(
srvid_text
,
text
);
}
}
// end of anonymous namespace
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment