BIND 10 master, updated. 7fca81716ad3a755bf5744e88c3adeef15b04450 [master] Merge branch 'trac1957'
BIND 10 source code commits
bind10-changes at lists.isc.org
Fri Jul 13 10:26:10 UTC 2012
The branch, master has been updated
via 7fca81716ad3a755bf5744e88c3adeef15b04450 (commit)
via 1793d893ccb043537810cbed80079b7d373ef6d0 (commit)
via 66d9922628755b55d297c03e02d5c7fb2614f8ac (commit)
via 61667bcc9c013ce7d105609404c32cd5d83fa02c (commit)
via 0e1996af4d06ab528f76e13a3ce7c4c29b12d046 (commit)
via 41f4bacdf9f658999d94f36a2925dc5e0c62dcfd (commit)
via 53ae982184ecea7ee8efb8e1a78c6a62dc76212c (commit)
via 6df91c2dc854f8068a7f8aceb6b28ce380267ac1 (commit)
via b8306189256e5bceeb3017817681ecb9c39b5736 (commit)
via c4901d0f8f158eccafcc7d968b3253297a224272 (commit)
from 3fac7d5579c5f51b8e952b50db510b45bfa986f3 (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
commit 7fca81716ad3a755bf5744e88c3adeef15b04450
Merge: 3fac7d5 1793d89
Author: Marcin Siodelski <marcin at isc.org>
Date: Fri Jul 13 12:15:37 2012 +0200
[master] Merge branch 'trac1957'
Conflicts:
src/lib/dhcp/iface_mgr.cc
-----------------------------------------------------------------------
Summary of changes:
src/lib/dhcp/iface_mgr.cc | 140 +++++++++++++++++++++++++++---
src/lib/dhcp/iface_mgr.h | 70 ++++++++++++++-
src/lib/dhcp/tests/iface_mgr_unittest.cc | 92 ++++++++++++++++++--
3 files changed, 280 insertions(+), 22 deletions(-)
-----------------------------------------------------------------------
diff --git a/src/lib/dhcp/iface_mgr.cc b/src/lib/dhcp/iface_mgr.cc
index 508413d..ae975d0 100644
--- a/src/lib/dhcp/iface_mgr.cc
+++ b/src/lib/dhcp/iface_mgr.cc
@@ -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;
- // note that we claim that this is not a loopback. iface_mgr tries to open a
+ // Note 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) {
- // skip IPv6 addresses
+ // Skip 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()
diff --git a/src/lib/dhcp/iface_mgr.h b/src/lib/dhcp/iface_mgr.h
index 7fa2e85..a40f95c 100644
--- a/src/lib/dhcp/iface_mgr.h
+++ b/src/lib/dhcp/iface_mgr.h
@@ -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
diff --git a/src/lib/dhcp/tests/iface_mgr_unittest.cc b/src/lib/dhcp/tests/iface_mgr_unittest.cc
index e7ccb68..df818d8 100644
--- a/src/lib/dhcp/tests/iface_mgr_unittest.cc
+++ b/src/lib/dhcp/tests/iface_mgr_unittest.cc
@@ -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) {
}
}
-// uncomment this test to create packet writer. It will
+// Uncomment 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) {
More information about the bind10-changes
mailing list