|
@@ -177,6 +177,17 @@ 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) {
|
|
|
|
+ isc_throw(BadValue, "Address " << addr.toText()
|
|
|
|
+ << " already defined on the " << name_ << " interface.");
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ unicasts_.push_back(addr);
|
|
|
|
+}
|
|
|
|
+
|
|
void IfaceMgr::closeSockets() {
|
|
void IfaceMgr::closeSockets() {
|
|
for (IfaceCollection::iterator iface = ifaces_.begin();
|
|
for (IfaceCollection::iterator iface = ifaces_.begin();
|
|
iface != ifaces_.end(); ++iface) {
|
|
iface != ifaces_.end(); ++iface) {
|
|
@@ -343,8 +354,10 @@ bool IfaceMgr::openSockets4(const uint16_t port, const bool use_bcast) {
|
|
|
|
|
|
}
|
|
}
|
|
if (sock < 0) {
|
|
if (sock < 0) {
|
|
|
|
+ const char* errstr = strerror(errno);
|
|
isc_throw(SocketConfigError, "failed to open IPv4 socket"
|
|
isc_throw(SocketConfigError, "failed to open IPv4 socket"
|
|
- << " supporting broadcast traffic");
|
|
|
|
|
|
+ << " supporting broadcast traffic, reason:"
|
|
|
|
+ << errstr);
|
|
}
|
|
}
|
|
|
|
|
|
count++;
|
|
count++;
|
|
@@ -368,6 +381,23 @@ bool IfaceMgr::openSockets6(const uint16_t port) {
|
|
continue;
|
|
continue;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ // Open unicast sockets if there are any unicast addresses defined
|
|
|
|
+ Iface::AddressCollection unicasts = iface->getUnicasts();
|
|
|
|
+ for (Iface::AddressCollection::iterator addr = unicasts.begin();
|
|
|
|
+ addr != unicasts.end(); ++addr) {
|
|
|
|
+
|
|
|
|
+ sock = openSocket(iface->getName(), *addr, port);
|
|
|
|
+ if (sock < 0) {
|
|
|
|
+ const char* errstr = strerror(errno);
|
|
|
|
+ isc_throw(SocketConfigError, "failed to open unicast socket on "
|
|
|
|
+ << addr->toText() << " on interface " << iface->getName()
|
|
|
|
+ << ", reason: " << errstr);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ count++;
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+
|
|
Iface::AddressCollection addrs = iface->getAddresses();
|
|
Iface::AddressCollection addrs = iface->getAddresses();
|
|
for (Iface::AddressCollection::iterator addr = addrs.begin();
|
|
for (Iface::AddressCollection::iterator addr = addrs.begin();
|
|
addr != addrs.end();
|
|
addr != addrs.end();
|
|
@@ -389,7 +419,10 @@ bool IfaceMgr::openSockets6(const uint16_t port) {
|
|
|
|
|
|
sock = openSocket(iface->getName(), *addr, port);
|
|
sock = openSocket(iface->getName(), *addr, port);
|
|
if (sock < 0) {
|
|
if (sock < 0) {
|
|
- isc_throw(SocketConfigError, "failed to open unicast socket");
|
|
|
|
|
|
+ const char* errstr = strerror(errno);
|
|
|
|
+ isc_throw(SocketConfigError, "failed to open link-local socket on "
|
|
|
|
+ << addr->toText() << " on interface "
|
|
|
|
+ << iface->getName() << ", reason: " << errstr);
|
|
}
|
|
}
|
|
|
|
|
|
// Binding socket to unicast address and then joining multicast group
|
|
// Binding socket to unicast address and then joining multicast group
|
|
@@ -414,8 +447,10 @@ bool IfaceMgr::openSockets6(const uint16_t port) {
|
|
IOAddress(ALL_DHCP_RELAY_AGENTS_AND_SERVERS),
|
|
IOAddress(ALL_DHCP_RELAY_AGENTS_AND_SERVERS),
|
|
port);
|
|
port);
|
|
if (sock2 < 0) {
|
|
if (sock2 < 0) {
|
|
|
|
+ const char* errstr = strerror(errno);
|
|
isc_throw(SocketConfigError, "Failed to open multicast socket on "
|
|
isc_throw(SocketConfigError, "Failed to open multicast socket on "
|
|
- << " interface " << iface->getFullName());
|
|
|
|
|
|
+ << " interface " << iface->getFullName() << ", reason:"
|
|
|
|
+ << errstr);
|
|
iface->delSocket(sock); // delete previously opened socket
|
|
iface->delSocket(sock); // delete previously opened socket
|
|
}
|
|
}
|
|
#endif
|
|
#endif
|
|
@@ -608,7 +643,9 @@ IfaceMgr::getLocalAddress(const IOAddress& remote_addr, const uint16_t port) {
|
|
// interface.
|
|
// interface.
|
|
sock.open(asio::ip::udp::v4(), err_code);
|
|
sock.open(asio::ip::udp::v4(), err_code);
|
|
if (err_code) {
|
|
if (err_code) {
|
|
- isc_throw(Unexpected, "failed to open UDPv4 socket");
|
|
|
|
|
|
+ const char* errstr = strerror(errno);
|
|
|
|
+ isc_throw(Unexpected, "failed to open UDPv4 socket, reason:"
|
|
|
|
+ << errstr);
|
|
}
|
|
}
|
|
sock.set_option(asio::socket_base::broadcast(true), err_code);
|
|
sock.set_option(asio::socket_base::broadcast(true), err_code);
|
|
if (err_code) {
|
|
if (err_code) {
|
|
@@ -1137,16 +1174,50 @@ uint16_t IfaceMgr::getSocket(const isc::dhcp::Pkt6& pkt) {
|
|
<< pkt.getIface());
|
|
<< pkt.getIface());
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+
|
|
const Iface::SocketCollection& socket_collection = iface->getSockets();
|
|
const Iface::SocketCollection& socket_collection = iface->getSockets();
|
|
|
|
+
|
|
|
|
+ Iface::SocketCollection::const_iterator candidate = socket_collection.end();
|
|
|
|
+
|
|
Iface::SocketCollection::const_iterator s;
|
|
Iface::SocketCollection::const_iterator s;
|
|
for (s = socket_collection.begin(); s != socket_collection.end(); ++s) {
|
|
for (s = socket_collection.begin(); s != socket_collection.end(); ++s) {
|
|
- if ((s->family_ == AF_INET6) &&
|
|
|
|
- (!s->addr_.getAddress().to_v6().is_multicast())) {
|
|
|
|
|
|
+
|
|
|
|
+ // We should not merge those conditions for debugging reasons.
|
|
|
|
+
|
|
|
|
+ // V4 sockets are useless for sending v6 packets.
|
|
|
|
+ if (s->family_ != AF_INET6) {
|
|
|
|
+ continue;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // Sockets bound to multicast address are useless for sending anything.
|
|
|
|
+ if (s->addr_.getAddress().to_v6().is_multicast()) {
|
|
|
|
+ continue;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (s->addr_ == pkt.getLocalAddr()) {
|
|
|
|
+ // This socket is bound to the source address. This is perfect
|
|
|
|
+ // match, no need to look any further.
|
|
return (s->sockfd_);
|
|
return (s->sockfd_);
|
|
}
|
|
}
|
|
- /// @todo: Add more checks here later. If remote address is
|
|
|
|
- /// not link-local, we can't use link local bound socket
|
|
|
|
- /// to send data.
|
|
|
|
|
|
+
|
|
|
|
+ // If we don't have any other candidate, this one will do
|
|
|
|
+ if (candidate == socket_collection.end()) {
|
|
|
|
+ candidate = s;
|
|
|
|
+ } else {
|
|
|
|
+ // If we want to send something to link-local and the socket is
|
|
|
|
+ // bound to link-local or we want to send to global and the socket
|
|
|
|
+ // is bound to global, then use it as candidate
|
|
|
|
+ if ( (pkt.getRemoteAddr().getAddress().to_v6().is_link_local() &&
|
|
|
|
+ s->addr_.getAddress().to_v6().is_link_local()) ||
|
|
|
|
+ (!pkt.getRemoteAddr().getAddress().to_v6().is_link_local() &&
|
|
|
|
+ !s->addr_.getAddress().to_v6().is_link_local()) ) {
|
|
|
|
+ candidate = s;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (candidate != socket_collection.end()) {
|
|
|
|
+ return (candidate->sockfd_);
|
|
}
|
|
}
|
|
|
|
|
|
isc_throw(Unexpected, "Interface " << iface->getFullName()
|
|
isc_throw(Unexpected, "Interface " << iface->getFullName()
|
|
@@ -1175,5 +1246,6 @@ uint16_t IfaceMgr::getSocket(isc::dhcp::Pkt4 const& pkt) {
|
|
<< " does not have any suitable IPv4 sockets open.");
|
|
<< " does not have any suitable IPv4 sockets open.");
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+
|
|
} // end of namespace isc::dhcp
|
|
} // end of namespace isc::dhcp
|
|
} // end of namespace isc
|
|
} // end of namespace isc
|