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
7fca8171
Commit
7fca8171
authored
Jul 13, 2012
by
Marcin Siodelski
Browse files
[master] Merge branch 'trac1957'
Conflicts: src/lib/dhcp/iface_mgr.cc
parents
3fac7d55
1793d893
Changes
3
Hide whitespace changes
Inline
Side-by-side
src/lib/dhcp/iface_mgr.cc
View file @
7fca8171
...
...
@@ -19,11 +19,14 @@
#include
<netinet/in.h>
#include
<arpa/inet.h>
#include
<sys/select.h>
#include
<asio.hpp>
#include
<dhcp/dhcp4.h>
#include
<dhcp/dhcp6.h>
#include
<dhcp/iface_mgr.h>
#include
<exceptions/exceptions.h>
#include
<asiolink/udp_endpoint.h>
#include
<asiolink/io_error.h>
#include
<util/io/pktinfo_utilities.h>
using
namespace
std
;
...
...
@@ -197,7 +200,7 @@ void IfaceMgr::stubDetectIfaces() {
iface
.
flag_up_
=
true
;
iface
.
flag_running_
=
true
;
//
n
ote that we claim that this is not a loopback. iface_mgr tries to open a
//
N
ote that we claim that this is not a loopback. iface_mgr tries to open a
// socket on all interaces that are up, running and not loopback. As this is
// the only interface we were able to detect, let's pretend this is a normal
// interface.
...
...
@@ -228,8 +231,8 @@ bool IfaceMgr::openSockets4(const uint16_t port) {
int
sock
;
int
count
=
0
;
for
(
IfaceCollection
::
iterator
iface
=
ifaces_
.
begin
();
iface
!=
ifaces_
.
end
();
for
(
IfaceCollection
::
iterator
iface
=
ifaces_
.
begin
();
iface
!=
ifaces_
.
end
();
++
iface
)
{
cout
<<
"Trying opening socket on interface "
<<
iface
->
getFullName
()
<<
endl
;
...
...
@@ -243,18 +246,17 @@ bool IfaceMgr::openSockets4(const uint16_t port) {
}
AddressCollection
addrs
=
iface
->
getAddresses
();
for
(
AddressCollection
::
iterator
addr
=
addrs
.
begin
();
for
(
AddressCollection
::
iterator
addr
=
addrs
.
begin
();
addr
!=
addrs
.
end
();
++
addr
)
{
//
s
kip IPv6 addresses
//
S
kip IPv6 addresses
if
(
addr
->
getFamily
()
!=
AF_INET
)
{
continue
;
}
sock
=
openSocket
(
iface
->
getName
(),
*
addr
,
port
);
if
(
sock
<
0
)
{
if
(
sock
<
0
)
{
cout
<<
"Failed to open unicast socket."
<<
endl
;
return
(
false
);
}
...
...
@@ -270,8 +272,8 @@ bool IfaceMgr::openSockets6(const uint16_t port) {
int
sock
;
int
count
=
0
;
for
(
IfaceCollection
::
iterator
iface
=
ifaces_
.
begin
();
iface
!=
ifaces_
.
end
();
for
(
IfaceCollection
::
iterator
iface
=
ifaces_
.
begin
();
iface
!=
ifaces_
.
end
();
++
iface
)
{
if
(
iface
->
flag_loopback_
||
...
...
@@ -281,8 +283,7 @@ bool IfaceMgr::openSockets6(const uint16_t port) {
}
AddressCollection
addrs
=
iface
->
getAddresses
();
for
(
AddressCollection
::
iterator
addr
=
addrs
.
begin
();
for
(
AddressCollection
::
iterator
addr
=
addrs
.
begin
();
addr
!=
addrs
.
end
();
++
addr
)
{
...
...
@@ -292,7 +293,7 @@ bool IfaceMgr::openSockets6(const uint16_t port) {
}
sock
=
openSocket
(
iface
->
getName
(),
*
addr
,
port
);
if
(
sock
<
0
)
{
if
(
sock
<
0
)
{
cout
<<
"Failed to open unicast socket."
<<
endl
;
return
(
false
);
}
...
...
@@ -301,7 +302,7 @@ bool IfaceMgr::openSockets6(const uint16_t port) {
// works well on Mac OS (and possibly other BSDs), but does not work
// on Linux.
if
(
!
joinMulticast
(
sock
,
iface
->
getName
(),
string
(
ALL_DHCP_RELAY_AGENTS_AND_SERVERS
)
)
)
{
string
(
ALL_DHCP_RELAY_AGENTS_AND_SERVERS
)
)
)
{
close
(
sock
);
isc_throw
(
Unexpected
,
"Failed to join "
<<
ALL_DHCP_RELAY_AGENTS_AND_SERVERS
<<
" multicast group."
);
...
...
@@ -317,7 +318,7 @@ bool IfaceMgr::openSockets6(const uint16_t port) {
int
sock2
=
openSocket
(
iface
->
getName
(),
IOAddress
(
ALL_DHCP_RELAY_AGENTS_AND_SERVERS
),
port
);
if
(
sock2
<
0
)
{
if
(
sock2
<
0
)
{
isc_throw
(
Unexpected
,
"Failed to open multicast socket on "
<<
" interface "
<<
iface
->
getFullName
());
iface
->
delSocket
(
sock
);
// delete previously opened socket
...
...
@@ -397,6 +398,117 @@ int IfaceMgr::openSocket(const std::string& ifname, const IOAddress& addr,
}
}
int
IfaceMgr
::
openSocketFromIface
(
const
std
::
string
&
ifname
,
const
uint16_t
port
,
const
uint8_t
family
)
{
// Search for specified interface among detected interfaces.
for
(
IfaceCollection
::
iterator
iface
=
ifaces_
.
begin
();
iface
!=
ifaces_
.
end
();
++
iface
)
{
if
((
iface
->
getFullName
()
!=
ifname
)
&&
(
iface
->
getName
()
!=
ifname
))
{
continue
;
}
// Interface is now detected. Search for address on interface
// that matches address family (v6 or v4).
AddressCollection
addrs
=
iface
->
getAddresses
();
AddressCollection
::
iterator
addr_it
=
addrs
.
begin
();
while
(
addr_it
!=
addrs
.
end
())
{
if
(
addr_it
->
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
));
}
++
addr_it
;
}
// If we are at the end of address collection it means that we found
// interface but there is no address for family specified.
if
(
addr_it
==
addrs
.
end
())
{
// Stringify the family value to append it to exception string.
std
::
string
family_name
(
"AF_INET"
);
if
(
family
==
AF_INET6
)
{
family_name
=
"AF_INET6"
;
}
// We did not find address on the interface.
isc_throw
(
BadValue
,
"There is no address for interface: "
<<
ifname
<<
", port: "
<<
port
<<
", address "
" family: "
<<
family_name
);
}
}
// If we got here it means that we had not found the specified interface.
// Otherwise we would have returned from previous exist points.
isc_throw
(
BadValue
,
"There is no "
<<
ifname
<<
" interface present."
);
}
int
IfaceMgr
::
openSocketFromAddress
(
const
IOAddress
&
addr
,
const
uint16_t
port
)
{
// Search through detected interfaces and addresses to match
// local address we got.
for
(
IfaceCollection
::
iterator
iface
=
ifaces_
.
begin
();
iface
!=
ifaces_
.
end
();
++
iface
)
{
AddressCollection
addrs
=
iface
->
getAddresses
();
for
(
AddressCollection
::
iterator
addr_it
=
addrs
.
begin
();
addr_it
!=
addrs
.
end
();
++
addr_it
)
{
// Local address must match one of the addresses
// on detected interfaces. If it does, we have
// address and interface detected so we can open
// socket.
if
(
*
addr_it
==
addr
)
{
// Open socket using local interface, address and port.
// This may cause isc::Unexpected exception.
return
(
openSocket
(
iface
->
getName
(),
*
addr_it
,
port
));
}
}
}
// If we got here it means that we did not find specified address
// on any available interface.
isc_throw
(
BadValue
,
"There is no such address "
<<
addr
.
toText
());
}
int
IfaceMgr
::
openSocketFromRemoteAddress
(
const
IOAddress
&
remote_addr
,
const
uint16_t
port
)
{
// Get local address to be used to connect to remote location.
IOAddress
local_address
(
getLocalAddress
(
remote_addr
,
port
).
getAddress
());
return
openSocketFromAddress
(
local_address
,
port
);
}
isc
::
asiolink
::
IOAddress
IfaceMgr
::
getLocalAddress
(
const
IOAddress
&
remote_addr
,
const
uint16_t
port
)
{
// Create remote endpoint, we will be connecting to it.
boost
::
scoped_ptr
<
const
UDPEndpoint
>
remote_endpoint
(
static_cast
<
const
UDPEndpoint
*>
(
UDPEndpoint
::
create
(
IPPROTO_UDP
,
remote_addr
,
port
)));
if
(
!
remote_endpoint
)
{
isc_throw
(
Unexpected
,
"Unable to create remote endpoint"
);
}
// Create socket that will be used to connect to remote endpoint.
asio
::
io_service
io_service
;
asio
::
ip
::
udp
::
socket
sock
(
io_service
);
// Try to connect to remote endpoint and check if attempt is successful.
asio
::
error_code
err_code
;
sock
.
connect
(
remote_endpoint
->
getASIOEndpoint
(),
err_code
);
if
(
err_code
)
{
isc_throw
(
Unexpected
,
"Failed to connect to remote endpoint."
);
}
// Once we are connected socket object holds local endpoint.
asio
::
ip
::
udp
::
socket
::
endpoint_type
local_endpoint
=
sock
.
local_endpoint
();
asio
::
ip
::
address
local_address
(
local_endpoint
.
address
());
// Return address of local endpoint.
return
IOAddress
(
local_address
);
}
int
IfaceMgr
::
openSocket4
(
Iface
&
iface
,
const
IOAddress
&
addr
,
uint16_t
port
)
{
cout
<<
"Creating UDP4 socket on "
<<
iface
.
getFullName
()
...
...
src/lib/dhcp/iface_mgr.h
View file @
7fca8171
...
...
@@ -374,7 +374,58 @@ public:
/// @return socket descriptor, if socket creation, binding and multicast
/// group join were all successful.
int
openSocket
(
const
std
::
string
&
ifname
,
const
isc
::
asiolink
::
IOAddress
&
addr
,
const
uint16_t
port
);
const
isc
::
asiolink
::
IOAddress
&
addr
,
const
uint16_t
port
);
/// @brief Opens UDP/IP socket and binds it to interface specified.
///
/// This method differs from \ref openSocket in that it does not require
/// the specification of a local address to which socket will be bound.
/// Instead, the method searches through the addresses on the specified
/// interface and selects one that matches the address family.
///
/// @param ifname name of the interface
/// @param port UDP port
/// @param family address family (AF_INET or AF_INET6)
/// @return socket descriptor, if socket creation, binding and multicast
/// group join were all successful.
/// @throw isc::Unexpected if failed to create and bind socket.
/// @throw isc::BadValue if there is no address on specified interface
/// that belongs to given family.
int
openSocketFromIface
(
const
std
::
string
&
ifname
,
const
uint16_t
port
,
const
uint8_t
family
);
/// @brief Opens UDP/IP socket and binds to address specified
///
/// This methods differs from \ref openSocket in that it does not require
/// the specification of the interface to which the socket will be bound.
///
/// @param addr address to be bound
/// @param port UDP port
/// @return socket descriptor, if socket creation, binding and multicast
/// group join were all successful.
/// @throw isc::Unexpected if failed to create and bind socket
/// @throw isc::BadValue if specified address is not available on
/// any interface
int
openSocketFromAddress
(
const
isc
::
asiolink
::
IOAddress
&
addr
,
const
uint16_t
port
);
/// @brief Opens UDP/IP socket to be used to connect to remote address
///
/// This method identifies the local address to be used to connect to the
/// remote address specified as argument. Once the local address is
/// identified, \ref openSocket is called to open a socket and bind it to
/// the interface, address and port.
///
/// @param remote_addr remote address to connect to
/// @param port UDP port
/// @return socket descriptor, if socket creation, binding and multicast
/// group join were all successful.
/// @throw isc::Unexpected if failed to create and bind socket
int
openSocketFromRemoteAddress
(
const
isc
::
asiolink
::
IOAddress
&
remote_addr
,
const
uint16_t
port
);
/// Opens IPv6 sockets on detected interfaces.
///
...
...
@@ -548,6 +599,23 @@ private:
joinMulticast
(
int
sock
,
const
std
::
string
&
ifname
,
const
std
::
string
&
mcast
);
/// @brief Identifies local network address to be used to
/// connect to remote address.
///
/// This method identifies local network address that can be used
/// to connect to remote address specified.
/// It first creates socket and makes attempt to connect
/// to remote location via this socket. If connection
/// is established successfully, the local address to which
/// socket is bound is returned.
///
/// @param remote_addr remote address to connect to
/// @param port port to be used
/// @return local address to be used to connect to remote address
/// @throw isc::Unexpected if unable to indentify local address
isc
::
asiolink
::
IOAddress
getLocalAddress
(
const
isc
::
asiolink
::
IOAddress
&
remote_addr
,
const
uint16_t
port
);
};
};
// namespace isc::dhcp
...
...
src/lib/dhcp/tests/iface_mgr_unittest.cc
View file @
7fca8171
...
...
@@ -19,6 +19,7 @@
#include
<unistd.h>
#include
<arpa/inet.h>
#include
<boost/scoped_ptr.hpp>
#include
<gtest/gtest.h>
#include
<asiolink/io_address.h>
...
...
@@ -31,12 +32,17 @@ using namespace isc;
using
namespace
isc
::
asiolink
;
using
namespace
isc
::
dhcp
;
// name of loopback interface detection
const
size_t
buf_size
=
32
;
char
LOOPBACK
[
buf_size
]
=
"lo"
;
namespace
{
// Name of loopback interface detection
const
size_t
BUF_SIZE
=
32
;
char
LOOPBACK
[
BUF_SIZE
]
=
"lo"
;
// Ports used during testing
const
uint16_t
PORT1
=
10547
;
// V6 socket
const
uint16_t
PORT2
=
10548
;
// V4 socket
class
NakedIfaceMgr
:
public
IfaceMgr
{
// "naked" Interface Manager, exposes internal fields
public:
...
...
@@ -69,10 +75,10 @@ TEST_F(IfaceMgrTest, loDetect) {
// is implemented
if
(
if_nametoindex
(
"lo"
)
>
0
)
{
cout
<<
"This is Linux, using lo as loopback."
<<
endl
;
snprintf
(
LOOPBACK
,
buf_size
-
1
,
"lo"
);
snprintf
(
LOOPBACK
,
BUF_SIZE
-
1
,
"lo"
);
}
else
if
(
if_nametoindex
(
"lo0"
)
>
0
)
{
cout
<<
"This is BSD, using lo0 as loopback."
<<
endl
;
snprintf
(
LOOPBACK
,
buf_size
-
1
,
"lo0"
);
snprintf
(
LOOPBACK
,
BUF_SIZE
-
1
,
"lo0"
);
}
else
{
cout
<<
"Failed to detect loopback interface. Neither "
<<
"lo nor lo0 worked. I give up."
<<
endl
;
...
...
@@ -80,7 +86,7 @@ TEST_F(IfaceMgrTest, loDetect) {
}
}
//
u
ncomment this test to create packet writer. It will
//
U
ncomment this test to create packet writer. It will
// write incoming DHCPv6 packets as C arrays. That is useful
// for generating test sequences based on actual traffic
//
...
...
@@ -241,6 +247,78 @@ TEST_F(IfaceMgrTest, sockets6) {
delete
ifacemgr
;
}
TEST_F
(
IfaceMgrTest
,
socketsFromIface
)
{
boost
::
scoped_ptr
<
NakedIfaceMgr
>
ifacemgr
(
new
NakedIfaceMgr
());
// Open v6 socket on loopback interface and bind to port
int
socket1
=
0
;
EXPECT_NO_THROW
(
socket1
=
ifacemgr
->
openSocketFromIface
(
LOOPBACK
,
PORT1
,
AF_INET6
);
);
// Socket descriptor must be positive integer
EXPECT_GT
(
socket1
,
0
);
close
(
socket1
);
// Open v4 socket on loopback interface and bind to different port
int
socket2
=
0
;
EXPECT_NO_THROW
(
socket2
=
ifacemgr
->
openSocketFromIface
(
LOOPBACK
,
PORT2
,
AF_INET
);
);
// socket descriptor must be positive integer
EXPECT_GT
(
socket2
,
0
);
close
(
socket2
);
}
TEST_F
(
IfaceMgrTest
,
socketsFromAddress
)
{
boost
::
scoped_ptr
<
NakedIfaceMgr
>
ifacemgr
(
new
NakedIfaceMgr
());
// Open v6 socket on loopback interface and bind to port
int
socket1
=
0
;
IOAddress
loAddr6
(
"::1"
);
EXPECT_NO_THROW
(
socket1
=
ifacemgr
->
openSocketFromAddress
(
loAddr6
,
PORT1
);
);
// socket descriptor must be positive integer
EXPECT_GT
(
socket1
,
0
);
close
(
socket1
);
// Open v4 socket on loopback interface and bind to different port
int
socket2
=
0
;
IOAddress
loAddr
(
"127.0.0.1"
);
EXPECT_NO_THROW
(
socket2
=
ifacemgr
->
openSocketFromAddress
(
loAddr
,
PORT2
);
);
// socket descriptor must be positive integer
EXPECT_GT
(
socket2
,
0
);
close
(
socket2
);
}
TEST_F
(
IfaceMgrTest
,
socketsFromRemoteAddress
)
{
boost
::
scoped_ptr
<
NakedIfaceMgr
>
ifacemgr
(
new
NakedIfaceMgr
());
// Open v6 socket to connect to remote address.
// Loopback address is the only one that we know
// so let's treat it as remote address.
int
socket1
=
0
;
IOAddress
loAddr6
(
"::1"
);
EXPECT_NO_THROW
(
socket1
=
ifacemgr
->
openSocketFromRemoteAddress
(
loAddr6
,
PORT1
);
);
EXPECT_GT
(
socket1
,
0
);
close
(
socket1
);
// Open v4 socket to connect to remote address.
int
socket2
=
0
;
IOAddress
loAddr
(
"127.0.0.1"
);
EXPECT_NO_THROW
(
socket2
=
ifacemgr
->
openSocketFromRemoteAddress
(
loAddr
,
PORT2
);
);
EXPECT_GT
(
socket2
,
0
);
close
(
socket2
);
}
// TODO: disabled due to other naming on various systems
// (lo in Linux, lo0 in BSD systems)
TEST_F
(
IfaceMgrTest
,
DISABLED_sockets6Mcast
)
{
...
...
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