iface_mgr.cc 41 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217
  1. // Copyright (C) 2011-2012 Internet Systems Consortium, Inc. ("ISC")
  2. //
  3. // Permission to use, copy, modify, and/or distribute this software for any
  4. // purpose with or without fee is hereby granted, provided that the above
  5. // copyright notice and this permission notice appear in all copies.
  6. //
  7. // THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
  8. // REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
  9. // AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
  10. // INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  11. // LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
  12. // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  13. // PERFORMANCE OF THIS SOFTWARE.
  14. #include <config.h>
  15. #include <sstream>
  16. #include <fstream>
  17. #include <string.h>
  18. #include <netinet/in.h>
  19. #include <arpa/inet.h>
  20. #include <sys/select.h>
  21. #include <asio.hpp>
  22. #include <dhcp/dhcp4.h>
  23. #include <dhcp/dhcp6.h>
  24. #include <dhcp/iface_mgr.h>
  25. #include <exceptions/exceptions.h>
  26. #include <asiolink/udp_endpoint.h>
  27. #include <asiolink/io_error.h>
  28. #include <util/io/pktinfo_utilities.h>
  29. using namespace std;
  30. using namespace isc::asiolink;
  31. using namespace isc::util::io::internal;
  32. namespace isc {
  33. namespace dhcp {
  34. IfaceMgr&
  35. IfaceMgr::instance() {
  36. static IfaceMgr iface_mgr;
  37. return (iface_mgr);
  38. }
  39. IfaceMgr::Iface::Iface(const std::string& name, int ifindex)
  40. :name_(name), ifindex_(ifindex), mac_len_(0), hardware_type_(0),
  41. flag_loopback_(false), flag_up_(false), flag_running_(false),
  42. flag_multicast_(false), flag_broadcast_(false), flags_(0)
  43. {
  44. memset(mac_, 0, sizeof(mac_));
  45. }
  46. std::string
  47. IfaceMgr::Iface::getFullName() const {
  48. ostringstream tmp;
  49. tmp << name_ << "/" << ifindex_;
  50. return (tmp.str());
  51. }
  52. std::string
  53. IfaceMgr::Iface::getPlainMac() const {
  54. ostringstream tmp;
  55. tmp.fill('0');
  56. tmp << hex;
  57. for (int i = 0; i < mac_len_; i++) {
  58. tmp.width(2);
  59. tmp << static_cast<int>(mac_[i]);
  60. if (i < mac_len_-1) {
  61. tmp << ":";
  62. }
  63. }
  64. return (tmp.str());
  65. }
  66. void IfaceMgr::Iface::setMac(const uint8_t* mac, size_t len) {
  67. if (len > IfaceMgr::MAX_MAC_LEN) {
  68. isc_throw(OutOfRange, "Interface " << getFullName()
  69. << " was detected to have link address of length "
  70. << len << ", but maximum supported length is "
  71. << IfaceMgr::MAX_MAC_LEN);
  72. }
  73. mac_len_ = len;
  74. memcpy(mac_, mac, len);
  75. }
  76. bool IfaceMgr::Iface::delAddress(const isc::asiolink::IOAddress& addr) {
  77. for (AddressCollection::iterator a = addrs_.begin();
  78. a!=addrs_.end(); ++a) {
  79. if (*a==addr) {
  80. addrs_.erase(a);
  81. return (true);
  82. }
  83. }
  84. return (false);
  85. }
  86. bool IfaceMgr::Iface::delSocket(uint16_t sockfd) {
  87. list<SocketInfo>::iterator sock = sockets_.begin();
  88. while (sock!=sockets_.end()) {
  89. if (sock->sockfd_ == sockfd) {
  90. close(sockfd);
  91. sockets_.erase(sock);
  92. return (true); //socket found
  93. }
  94. ++sock;
  95. }
  96. return (false); // socket not found
  97. }
  98. IfaceMgr::IfaceMgr()
  99. :control_buf_len_(CMSG_SPACE(sizeof(struct in6_pktinfo))),
  100. control_buf_(new char[control_buf_len_]),
  101. session_socket_(INVALID_SOCKET), session_callback_(NULL)
  102. {
  103. cout << "IfaceMgr initialization." << endl;
  104. try {
  105. // required for sending/receiving packets
  106. // let's keep it in front, just in case someone
  107. // wants to send anything during initialization
  108. // control_buf_ = boost::scoped_array<char>();
  109. detectIfaces();
  110. } catch (const std::exception& ex) {
  111. cout << "IfaceMgr creation failed:" << ex.what() << endl;
  112. // TODO Uncomment this (or call LOG_FATAL) once
  113. // interface detection is implemented. Otherwise
  114. // it is not possible to run tests in a portable
  115. // way (see detectIfaces() method).
  116. throw;
  117. }
  118. }
  119. void IfaceMgr::closeSockets() {
  120. for (IfaceCollection::iterator iface = ifaces_.begin();
  121. iface != ifaces_.end(); ++iface) {
  122. for (SocketCollection::iterator sock = iface->sockets_.begin();
  123. sock != iface->sockets_.end(); ++sock) {
  124. cout << "Closing socket " << sock->sockfd_ << endl;
  125. close(sock->sockfd_);
  126. }
  127. iface->sockets_.clear();
  128. }
  129. }
  130. IfaceMgr::~IfaceMgr() {
  131. // control_buf_ is deleted automatically (scoped_ptr)
  132. control_buf_len_ = 0;
  133. closeSockets();
  134. }
  135. void IfaceMgr::stubDetectIfaces() {
  136. string ifaceName;
  137. const string v4addr("127.0.0.1"), v6addr("::1");
  138. // This is a stub implementation for interface detection. Actual detection
  139. // is faked by detecting loopback interface (lo or lo0). It will eventually
  140. // be removed once we have actual implementations for all supported systems.
  141. cout << "Interface detection is not implemented on this Operating System yet. "
  142. << endl;
  143. try {
  144. if (if_nametoindex("lo") > 0) {
  145. ifaceName = "lo";
  146. // this is Linux-like OS
  147. } else if (if_nametoindex("lo0") > 0) {
  148. ifaceName = "lo0";
  149. // this is BSD-like OS
  150. } else {
  151. // we give up. What OS is this, anyway? Solaris? Hurd?
  152. isc_throw(NotImplemented,
  153. "Interface detection on this OS is not supported.");
  154. }
  155. Iface iface(ifaceName, if_nametoindex(ifaceName.c_str()));
  156. iface.flag_up_ = true;
  157. iface.flag_running_ = true;
  158. // Note that we claim that this is not a loopback. iface_mgr tries to open a
  159. // socket on all interaces that are up, running and not loopback. As this is
  160. // the only interface we were able to detect, let's pretend this is a normal
  161. // interface.
  162. iface.flag_loopback_ = false;
  163. iface.flag_multicast_ = true;
  164. iface.flag_broadcast_ = true;
  165. iface.setHWType(HWTYPE_ETHERNET);
  166. iface.addAddress(IOAddress(v4addr));
  167. iface.addAddress(IOAddress(v6addr));
  168. addInterface(iface);
  169. cout << "Detected interface " << ifaceName << "/" << v4addr << "/"
  170. << v6addr << endl;
  171. } catch (const std::exception& ex) {
  172. // TODO: deallocate whatever memory we used
  173. // not that important, since this function is going to be
  174. // thrown away as soon as we get proper interface detection
  175. // implemented
  176. // TODO Do LOG_FATAL here
  177. std::cerr << "Interface detection failed." << std::endl;
  178. throw;
  179. }
  180. }
  181. bool IfaceMgr::openSockets4(const uint16_t port) {
  182. int sock;
  183. int count = 0;
  184. for (IfaceCollection::iterator iface = ifaces_.begin();
  185. iface != ifaces_.end();
  186. ++iface) {
  187. cout << "Trying opening socket on interface " << iface->getFullName() << endl;
  188. if (iface->flag_loopback_ ||
  189. !iface->flag_up_ ||
  190. !iface->flag_running_) {
  191. cout << "Interface " << iface->getFullName()
  192. << " not suitable: is loopback, is down or not running" << endl;
  193. continue;
  194. }
  195. AddressCollection addrs = iface->getAddresses();
  196. for (AddressCollection::iterator addr = addrs.begin();
  197. addr != addrs.end();
  198. ++addr) {
  199. // Skip IPv6 addresses
  200. if (addr->getFamily() != AF_INET) {
  201. continue;
  202. }
  203. sock = openSocket(iface->getName(), *addr, port);
  204. if (sock < 0) {
  205. cout << "Failed to open unicast socket." << endl;
  206. return (false);
  207. }
  208. count++;
  209. }
  210. }
  211. return (count > 0);
  212. }
  213. bool IfaceMgr::openSockets6(const uint16_t port) {
  214. int sock;
  215. int count = 0;
  216. for (IfaceCollection::iterator iface = ifaces_.begin();
  217. iface != ifaces_.end();
  218. ++iface) {
  219. if (iface->flag_loopback_ ||
  220. !iface->flag_up_ ||
  221. !iface->flag_running_) {
  222. continue;
  223. }
  224. AddressCollection addrs = iface->getAddresses();
  225. for (AddressCollection::iterator addr = addrs.begin();
  226. addr != addrs.end();
  227. ++addr) {
  228. // skip IPv4 addresses
  229. if (addr->getFamily() != AF_INET6) {
  230. continue;
  231. }
  232. sock = openSocket(iface->getName(), *addr, port);
  233. if (sock < 0) {
  234. cout << "Failed to open unicast socket." << endl;
  235. return (false);
  236. }
  237. // Binding socket to unicast address and then joining multicast group
  238. // works well on Mac OS (and possibly other BSDs), but does not work
  239. // on Linux.
  240. if ( !joinMulticast(sock, iface->getName(),
  241. string(ALL_DHCP_RELAY_AGENTS_AND_SERVERS))) {
  242. close(sock);
  243. isc_throw(Unexpected, "Failed to join " << ALL_DHCP_RELAY_AGENTS_AND_SERVERS
  244. << " multicast group.");
  245. }
  246. count++;
  247. /// @todo: Remove this ifdef once we start supporting BSD systems.
  248. #if defined(OS_LINUX)
  249. // To receive multicast traffic, Linux requires binding socket to
  250. // a multicast group. That in turn doesn't work on NetBSD.
  251. int sock2 = openSocket(iface->getName(),
  252. IOAddress(ALL_DHCP_RELAY_AGENTS_AND_SERVERS),
  253. port);
  254. if (sock2 < 0) {
  255. isc_throw(Unexpected, "Failed to open multicast socket on "
  256. << " interface " << iface->getFullName());
  257. iface->delSocket(sock); // delete previously opened socket
  258. }
  259. #endif
  260. }
  261. }
  262. return (count > 0);
  263. }
  264. void
  265. IfaceMgr::printIfaces(std::ostream& out /*= std::cout*/) {
  266. for (IfaceCollection::const_iterator iface=ifaces_.begin();
  267. iface!=ifaces_.end();
  268. ++iface) {
  269. const AddressCollection& addrs = iface->getAddresses();
  270. out << "Detected interface " << iface->getFullName()
  271. << ", hwtype=" << iface->getHWType()
  272. << ", mac=" << iface->getPlainMac();
  273. out << ", flags=" << hex << iface->flags_ << dec << "("
  274. << (iface->flag_loopback_?"LOOPBACK ":"")
  275. << (iface->flag_up_?"UP ":"")
  276. << (iface->flag_running_?"RUNNING ":"")
  277. << (iface->flag_multicast_?"MULTICAST ":"")
  278. << (iface->flag_broadcast_?"BROADCAST ":"")
  279. << ")" << endl;
  280. out << " " << addrs.size() << " addr(s):";
  281. for (AddressCollection::const_iterator addr = addrs.begin();
  282. addr != addrs.end(); ++addr) {
  283. out << " " << addr->toText();
  284. }
  285. out << endl;
  286. }
  287. }
  288. IfaceMgr::Iface*
  289. IfaceMgr::getIface(int ifindex) {
  290. for (IfaceCollection::iterator iface=ifaces_.begin();
  291. iface!=ifaces_.end();
  292. ++iface) {
  293. if (iface->getIndex() == ifindex)
  294. return (&(*iface));
  295. }
  296. return (NULL); // not found
  297. }
  298. IfaceMgr::Iface*
  299. IfaceMgr::getIface(const std::string& ifname) {
  300. for (IfaceCollection::iterator iface=ifaces_.begin();
  301. iface!=ifaces_.end();
  302. ++iface) {
  303. if (iface->getName() == ifname)
  304. return (&(*iface));
  305. }
  306. return (NULL); // not found
  307. }
  308. int IfaceMgr::openSocket(const std::string& ifname, const IOAddress& addr,
  309. const uint16_t port) {
  310. Iface* iface = getIface(ifname);
  311. if (!iface) {
  312. isc_throw(BadValue, "There is no " << ifname << " interface present.");
  313. }
  314. switch (addr.getFamily()) {
  315. case AF_INET:
  316. return openSocket4(*iface, addr, port);
  317. case AF_INET6:
  318. return openSocket6(*iface, addr, port);
  319. default:
  320. isc_throw(BadValue, "Failed to detect family of address: "
  321. << addr.toText());
  322. }
  323. }
  324. int IfaceMgr::openSocketFromIface(const std::string& ifname,
  325. const uint16_t port,
  326. const uint8_t family) {
  327. // Search for specified interface among detected interfaces.
  328. for (IfaceCollection::iterator iface = ifaces_.begin();
  329. iface != ifaces_.end();
  330. ++iface) {
  331. if ((iface->getFullName() != ifname) &&
  332. (iface->getName() != ifname)) {
  333. continue;
  334. }
  335. // Interface is now detected. Search for address on interface
  336. // that matches address family (v6 or v4).
  337. AddressCollection addrs = iface->getAddresses();
  338. AddressCollection::iterator addr_it = addrs.begin();
  339. while (addr_it != addrs.end()) {
  340. if (addr_it->getFamily() == family) {
  341. // We have interface and address so let's open socket.
  342. // This may cause isc::Unexpected exception.
  343. return (openSocket(iface->getName(), *addr_it, port));
  344. }
  345. ++addr_it;
  346. }
  347. // If we are at the end of address collection it means that we found
  348. // interface but there is no address for family specified.
  349. if (addr_it == addrs.end()) {
  350. // Stringify the family value to append it to exception string.
  351. std::string family_name("AF_INET");
  352. if (family == AF_INET6) {
  353. family_name = "AF_INET6";
  354. }
  355. // We did not find address on the interface.
  356. isc_throw(BadValue, "There is no address for interface: "
  357. << ifname << ", port: " << port << ", address "
  358. " family: " << family_name);
  359. }
  360. }
  361. // If we got here it means that we had not found the specified interface.
  362. // Otherwise we would have returned from previous exist points.
  363. isc_throw(BadValue, "There is no " << ifname << " interface present.");
  364. }
  365. int IfaceMgr::openSocketFromAddress(const IOAddress& addr,
  366. const uint16_t port) {
  367. // Search through detected interfaces and addresses to match
  368. // local address we got.
  369. for (IfaceCollection::iterator iface = ifaces_.begin();
  370. iface != ifaces_.end();
  371. ++iface) {
  372. AddressCollection addrs = iface->getAddresses();
  373. for (AddressCollection::iterator addr_it = addrs.begin();
  374. addr_it != addrs.end();
  375. ++addr_it) {
  376. // Local address must match one of the addresses
  377. // on detected interfaces. If it does, we have
  378. // address and interface detected so we can open
  379. // socket.
  380. if (*addr_it == addr) {
  381. // Open socket using local interface, address and port.
  382. // This may cause isc::Unexpected exception.
  383. return (openSocket(iface->getName(), *addr_it, port));
  384. }
  385. }
  386. }
  387. // If we got here it means that we did not find specified address
  388. // on any available interface.
  389. isc_throw(BadValue, "There is no such address " << addr.toText());
  390. }
  391. int IfaceMgr::openSocketFromRemoteAddress(const IOAddress& remote_addr,
  392. const uint16_t port) {
  393. // Get local address to be used to connect to remote location.
  394. IOAddress local_address(getLocalAddress(remote_addr, port).getAddress());
  395. return openSocketFromAddress(local_address, port);
  396. }
  397. isc::asiolink::IOAddress
  398. IfaceMgr::getLocalAddress(const IOAddress& remote_addr, const uint16_t port) {
  399. // Create remote endpoint, we will be connecting to it.
  400. boost::scoped_ptr<const UDPEndpoint>
  401. remote_endpoint(static_cast<const UDPEndpoint*>
  402. (UDPEndpoint::create(IPPROTO_UDP, remote_addr, port)));
  403. if (!remote_endpoint) {
  404. isc_throw(Unexpected, "Unable to create remote endpoint");
  405. }
  406. // Create socket that will be used to connect to remote endpoint.
  407. asio::io_service io_service;
  408. asio::ip::udp::socket sock(io_service);
  409. // Try to connect to remote endpoint and check if attempt is successful.
  410. asio::error_code err_code;
  411. sock.connect(remote_endpoint->getASIOEndpoint(), err_code);
  412. if (err_code) {
  413. isc_throw(Unexpected,"Failed to connect to remote endpoint.");
  414. }
  415. // Once we are connected socket object holds local endpoint.
  416. asio::ip::udp::socket::endpoint_type local_endpoint =
  417. sock.local_endpoint();
  418. asio::ip::address local_address(local_endpoint.address());
  419. // Return address of local endpoint.
  420. return IOAddress(local_address);
  421. }
  422. int IfaceMgr::openSocket4(Iface& iface, const IOAddress& addr, uint16_t port) {
  423. cout << "Creating UDP4 socket on " << iface.getFullName()
  424. << " " << addr.toText() << "/port=" << port << endl;
  425. struct sockaddr_in addr4;
  426. memset(&addr4, 0, sizeof(sockaddr));
  427. addr4.sin_family = AF_INET;
  428. addr4.sin_port = htons(port);
  429. addr4.sin_addr.s_addr = htonl(addr);
  430. //addr4.sin_addr.s_addr = 0; // anyaddr: this will receive 0.0.0.0 => 255.255.255.255 traffic
  431. // addr4.sin_addr.s_addr = 0xffffffffu; // broadcast address. This will receive 0.0.0.0 => 255.255.255.255 as well
  432. int sock = socket(AF_INET, SOCK_DGRAM, 0);
  433. if (sock < 0) {
  434. isc_throw(Unexpected, "Failed to create UDP6 socket.");
  435. }
  436. if (bind(sock, (struct sockaddr *)&addr4, sizeof(addr4)) < 0) {
  437. close(sock);
  438. isc_throw(Unexpected, "Failed to bind socket " << sock << " to " << addr.toText()
  439. << "/port=" << port);
  440. }
  441. // if there is no support for IP_PKTINFO, we are really out of luck
  442. // it will be difficult to undersand, where this packet came from
  443. #if defined(IP_PKTINFO)
  444. int flag = 1;
  445. if (setsockopt(sock, IPPROTO_IP, IP_PKTINFO, &flag, sizeof(flag)) != 0) {
  446. close(sock);
  447. isc_throw(Unexpected, "setsockopt: IP_PKTINFO: failed.");
  448. }
  449. #endif
  450. cout << "Created socket " << sock << " on " << iface.getName() << "/" <<
  451. addr.toText() << "/port=" << port << endl;
  452. SocketInfo info(sock, addr, port);
  453. iface.addSocket(info);
  454. return (sock);
  455. }
  456. int IfaceMgr::openSocket6(Iface& iface, const IOAddress& addr, uint16_t port) {
  457. cout << "Creating UDP6 socket on " << iface.getFullName()
  458. << " " << addr.toText() << "/port=" << port << endl;
  459. struct sockaddr_in6 addr6;
  460. memset(&addr6, 0, sizeof(addr6));
  461. addr6.sin6_family = AF_INET6;
  462. addr6.sin6_port = htons(port);
  463. if (addr.toText() != "::1")
  464. addr6.sin6_scope_id = if_nametoindex(iface.getName().c_str());
  465. memcpy(&addr6.sin6_addr,
  466. addr.getAddress().to_v6().to_bytes().data(),
  467. sizeof(addr6.sin6_addr));
  468. #ifdef HAVE_SA_LEN
  469. addr6.sin6_len = sizeof(addr6);
  470. #endif
  471. // TODO: use sockcreator once it becomes available
  472. // make a socket
  473. int sock = socket(AF_INET6, SOCK_DGRAM, 0);
  474. if (sock < 0) {
  475. isc_throw(Unexpected, "Failed to create UDP6 socket.");
  476. }
  477. // Set the REUSEADDR option so that we don't fail to start if
  478. // we're being restarted.
  479. int flag = 1;
  480. if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
  481. (char *)&flag, sizeof(flag)) < 0) {
  482. close(sock);
  483. isc_throw(Unexpected, "Can't set SO_REUSEADDR option on dhcpv6 socket.");
  484. }
  485. if (bind(sock, (struct sockaddr *)&addr6, sizeof(addr6)) < 0) {
  486. close(sock);
  487. isc_throw(Unexpected, "Failed to bind socket " << sock << " to " << addr.toText()
  488. << "/port=" << port);
  489. }
  490. #ifdef IPV6_RECVPKTINFO
  491. // RFC3542 - a new way
  492. if (setsockopt(sock, IPPROTO_IPV6, IPV6_RECVPKTINFO,
  493. &flag, sizeof(flag)) != 0) {
  494. close(sock);
  495. isc_throw(Unexpected, "setsockopt: IPV6_RECVPKTINFO failed.");
  496. }
  497. #else
  498. // RFC2292 - an old way
  499. if (setsockopt(sock, IPPROTO_IPV6, IPV6_PKTINFO,
  500. &flag, sizeof(flag)) != 0) {
  501. close(sock);
  502. isc_throw(Unexpected, "setsockopt: IPV6_PKTINFO: failed.");
  503. }
  504. #endif
  505. // multicast stuff
  506. if (addr.getAddress().to_v6().is_multicast()) {
  507. // both mcast (ALL_DHCP_RELAY_AGENTS_AND_SERVERS and ALL_DHCP_SERVERS)
  508. // are link and site-scoped, so there is no sense to join those groups
  509. // with global addresses.
  510. if ( !joinMulticast( sock, iface.getName(),
  511. string(ALL_DHCP_RELAY_AGENTS_AND_SERVERS) ) ) {
  512. close(sock);
  513. isc_throw(Unexpected, "Failed to join " << ALL_DHCP_RELAY_AGENTS_AND_SERVERS
  514. << " multicast group.");
  515. }
  516. }
  517. cout << "Created socket " << sock << " on " << iface.getName() << "/" <<
  518. addr.toText() << "/port=" << port << endl;
  519. SocketInfo info(sock, addr, port);
  520. iface.addSocket(info);
  521. return (sock);
  522. }
  523. bool
  524. IfaceMgr::joinMulticast(int sock, const std::string& ifname,
  525. const std::string & mcast) {
  526. struct ipv6_mreq mreq;
  527. if (inet_pton(AF_INET6, mcast.c_str(),
  528. &mreq.ipv6mr_multiaddr) <= 0) {
  529. cout << "Failed to convert " << ifname
  530. << " to IPv6 multicast address." << endl;
  531. return (false);
  532. }
  533. mreq.ipv6mr_interface = if_nametoindex(ifname.c_str());
  534. if (setsockopt(sock, IPPROTO_IPV6, IPV6_JOIN_GROUP,
  535. &mreq, sizeof(mreq)) < 0) {
  536. cout << "Failed to join " << mcast << " multicast group." << endl;
  537. return (false);
  538. }
  539. cout << "Joined multicast " << mcast << " group." << endl;
  540. return (true);
  541. }
  542. bool
  543. IfaceMgr::send(const Pkt6Ptr& pkt) {
  544. int result;
  545. Iface* iface = getIface(pkt->getIface());
  546. if (!iface) {
  547. isc_throw(BadValue, "Unable to send Pkt6. Invalid interface ("
  548. << pkt->getIface() << ") specified.");
  549. }
  550. memset(&control_buf_[0], 0, control_buf_len_);
  551. // Set the target address we're sending to.
  552. sockaddr_in6 to;
  553. memset(&to, 0, sizeof(to));
  554. to.sin6_family = AF_INET6;
  555. to.sin6_port = htons(pkt->getRemotePort());
  556. memcpy(&to.sin6_addr,
  557. pkt->getRemoteAddr().getAddress().to_v6().to_bytes().data(),
  558. 16);
  559. to.sin6_scope_id = pkt->getIndex();
  560. // Initialize our message header structure.
  561. struct msghdr m;
  562. memset(&m, 0, sizeof(m));
  563. m.msg_name = &to;
  564. m.msg_namelen = sizeof(to);
  565. // Set the data buffer we're sending. (Using this wacky
  566. // "scatter-gather" stuff... we only have a single chunk
  567. // of data to send, so we declare a single vector entry.)
  568. // As v structure is a C-style is used for both sending and
  569. // receiving data, it is shared between sending and receiving
  570. // (sendmsg and recvmsg). It is also defined in system headers,
  571. // so we have no control over its definition. To set iov_base
  572. // (defined as void*) we must use const cast from void *.
  573. // Otherwise C++ compiler would complain that we are trying
  574. // to assign const void* to void*.
  575. struct iovec v;
  576. memset(&v, 0, sizeof(v));
  577. v.iov_base = const_cast<void *>(pkt->getBuffer().getData());
  578. v.iov_len = pkt->getBuffer().getLength();
  579. m.msg_iov = &v;
  580. m.msg_iovlen = 1;
  581. // Setting the interface is a bit more involved.
  582. //
  583. // We have to create a "control message", and set that to
  584. // define the IPv6 packet information. We could set the
  585. // source address if we wanted, but we can safely let the
  586. // kernel decide what that should be.
  587. m.msg_control = &control_buf_[0];
  588. m.msg_controllen = control_buf_len_;
  589. struct cmsghdr *cmsg = CMSG_FIRSTHDR(&m);
  590. cmsg->cmsg_level = IPPROTO_IPV6;
  591. cmsg->cmsg_type = IPV6_PKTINFO;
  592. cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
  593. struct in6_pktinfo *pktinfo = convertPktInfo6(CMSG_DATA(cmsg));
  594. memset(pktinfo, 0, sizeof(struct in6_pktinfo));
  595. pktinfo->ipi6_ifindex = pkt->getIndex();
  596. m.msg_controllen = cmsg->cmsg_len;
  597. pkt->updateTimestamp();
  598. result = sendmsg(getSocket(*pkt), &m, 0);
  599. if (result < 0) {
  600. isc_throw(Unexpected, "Pkt6 send failed: sendmsg() returned " << result);
  601. }
  602. cout << "Sent " << pkt->getBuffer().getLength() << " bytes over socket " << getSocket(*pkt)
  603. << " on " << iface->getFullName() << " interface: "
  604. << " dst=[" << pkt->getRemoteAddr().toText() << "]:" << pkt->getRemotePort()
  605. << ", src=" << pkt->getLocalAddr().toText() << "]:" << pkt->getLocalPort()
  606. << endl;
  607. return (result);
  608. }
  609. bool
  610. IfaceMgr::send(const Pkt4Ptr& pkt)
  611. {
  612. Iface* iface = getIface(pkt->getIface());
  613. if (!iface) {
  614. isc_throw(BadValue, "Unable to send Pkt4. Invalid interface ("
  615. << pkt->getIface() << ") specified.");
  616. }
  617. memset(&control_buf_[0], 0, control_buf_len_);
  618. // Set the target address we're sending to.
  619. sockaddr_in to;
  620. memset(&to, 0, sizeof(to));
  621. to.sin_family = AF_INET;
  622. to.sin_port = htons(pkt->getRemotePort());
  623. to.sin_addr.s_addr = htonl(pkt->getRemoteAddr());
  624. struct msghdr m;
  625. // Initialize our message header structure.
  626. memset(&m, 0, sizeof(m));
  627. m.msg_name = &to;
  628. m.msg_namelen = sizeof(to);
  629. // Set the data buffer we're sending. (Using this wacky
  630. // "scatter-gather" stuff... we only have a single chunk
  631. // of data to send, so we declare a single vector entry.)
  632. struct iovec v;
  633. memset(&v, 0, sizeof(v));
  634. // iov_base field is of void * type. We use it for packet
  635. // transmission, so this buffer will not be modified.
  636. v.iov_base = const_cast<void *>(pkt->getBuffer().getData());
  637. v.iov_len = pkt->getBuffer().getLength();
  638. m.msg_iov = &v;
  639. m.msg_iovlen = 1;
  640. // call OS-specific routines (like setting interface index)
  641. os_send4(m, control_buf_, control_buf_len_, pkt);
  642. cout << "Trying to send " << pkt->getBuffer().getLength() << " bytes to "
  643. << pkt->getRemoteAddr().toText() << ":" << pkt->getRemotePort()
  644. << " over socket " << getSocket(*pkt) << " on interface "
  645. << getIface(pkt->getIface())->getFullName() << endl;
  646. pkt->updateTimestamp();
  647. int result = sendmsg(getSocket(*pkt), &m, 0);
  648. if (result < 0) {
  649. isc_throw(Unexpected, "Pkt4 send failed.");
  650. }
  651. cout << "Sent " << pkt->getBuffer().getLength() << " bytes over socket " << getSocket(*pkt)
  652. << " on " << iface->getFullName() << " interface: "
  653. << " dst=" << pkt->getRemoteAddr().toText() << ":" << pkt->getRemotePort()
  654. << ", src=" << pkt->getLocalAddr().toText() << ":" << pkt->getLocalPort()
  655. << endl;
  656. return (result);
  657. }
  658. boost::shared_ptr<Pkt4>
  659. IfaceMgr::receive4(uint32_t timeout_sec, uint32_t timeout_usec /* = 0 */) {
  660. // Sanity check for microsecond timeout.
  661. if (timeout_usec >= 1000000) {
  662. isc_throw(BadValue, "fractional timeout must be shorter than"
  663. " one million microseconds");
  664. }
  665. const SocketInfo* candidate = 0;
  666. IfaceCollection::const_iterator iface;
  667. fd_set sockets;
  668. int maxfd = 0;
  669. stringstream names;
  670. FD_ZERO(&sockets);
  671. /// @todo: marginal performance optimization. We could create the set once
  672. /// and then use its copy for select(). Please note that select() modifies
  673. /// provided set to indicated which sockets have something to read.
  674. for (iface = ifaces_.begin(); iface != ifaces_.end(); ++iface) {
  675. for (SocketCollection::const_iterator s = iface->sockets_.begin();
  676. s != iface->sockets_.end(); ++s) {
  677. // Only deal with IPv4 addresses.
  678. if (s->addr_.getFamily() == AF_INET) {
  679. names << s->sockfd_ << "(" << iface->getName() << ") ";
  680. // Add this socket to listening set
  681. FD_SET(s->sockfd_, &sockets);
  682. if (maxfd < s->sockfd_) {
  683. maxfd = s->sockfd_;
  684. }
  685. }
  686. }
  687. }
  688. // if there is session socket registered...
  689. if (session_socket_ != INVALID_SOCKET) {
  690. // at it to the set as well
  691. FD_SET(session_socket_, &sockets);
  692. if (maxfd < session_socket_)
  693. maxfd = session_socket_;
  694. names << session_socket_ << "(session)";
  695. }
  696. struct timeval select_timeout;
  697. select_timeout.tv_sec = timeout_sec;
  698. select_timeout.tv_usec = timeout_usec;
  699. cout << "Trying to receive data on sockets: " << names.str()
  700. << ". Timeout is " << timeout_sec << "." << setw(6) << setfill('0')
  701. << timeout_usec << " seconds." << endl;
  702. int result = select(maxfd + 1, &sockets, NULL, NULL, &select_timeout);
  703. cout << "select returned " << result << endl;
  704. if (result == 0) {
  705. // nothing received and timeout has been reached
  706. return (Pkt4Ptr()); // NULL
  707. } else if (result < 0) {
  708. cout << "Socket read error: " << strerror(errno) << endl;
  709. /// @todo: perhaps throw here?
  710. return (Pkt4Ptr()); // NULL
  711. }
  712. // Let's find out which socket has the data
  713. if ((session_socket_ != INVALID_SOCKET) && (FD_ISSET(session_socket_, &sockets))) {
  714. // something received over session socket
  715. cout << "BIND10 command or config available over session socket." << endl;
  716. if (session_callback_) {
  717. // in theory we could call io_service.run_one() here, instead of
  718. // implementing callback mechanism, but that would introduce
  719. // asiolink dependency to libdhcp++ and that is something we want
  720. // to avoid (see CPE market and out long term plans for minimalistic
  721. // implementations.
  722. session_callback_();
  723. }
  724. return (Pkt4Ptr()); // NULL
  725. }
  726. // Let's find out which interface/socket has the data
  727. for (iface = ifaces_.begin(); iface != ifaces_.end(); ++iface) {
  728. for (SocketCollection::const_iterator s = iface->sockets_.begin();
  729. s != iface->sockets_.end(); ++s) {
  730. if (FD_ISSET(s->sockfd_, &sockets)) {
  731. candidate = &(*s);
  732. break;
  733. }
  734. }
  735. if (candidate) {
  736. break;
  737. }
  738. }
  739. if (!candidate) {
  740. cout << "Received data over unknown socket." << endl;
  741. return (Pkt4Ptr()); // NULL
  742. }
  743. cout << "Trying to receive over UDP4 socket " << candidate->sockfd_ << " bound to "
  744. << candidate->addr_.toText() << "/port=" << candidate->port_ << " on "
  745. << iface->getFullName() << endl;
  746. // Now we have a socket, let's get some data from it!
  747. struct sockaddr_in from_addr;
  748. uint8_t buf[RCVBUFSIZE];
  749. memset(&control_buf_[0], 0, control_buf_len_);
  750. memset(&from_addr, 0, sizeof(from_addr));
  751. // Initialize our message header structure.
  752. struct msghdr m;
  753. memset(&m, 0, sizeof(m));
  754. // Point so we can get the from address.
  755. m.msg_name = &from_addr;
  756. m.msg_namelen = sizeof(from_addr);
  757. struct iovec v;
  758. v.iov_base = static_cast<void*>(buf);
  759. v.iov_len = RCVBUFSIZE;
  760. m.msg_iov = &v;
  761. m.msg_iovlen = 1;
  762. // Getting the interface is a bit more involved.
  763. //
  764. // We set up some space for a "control message". We have
  765. // previously asked the kernel to give us packet
  766. // information (when we initialized the interface), so we
  767. // should get the destination address from that.
  768. m.msg_control = &control_buf_[0];
  769. m.msg_controllen = control_buf_len_;
  770. result = recvmsg(candidate->sockfd_, &m, 0);
  771. if (result < 0) {
  772. cout << "Failed to receive UDP4 data." << endl;
  773. return (Pkt4Ptr()); // NULL
  774. }
  775. // We have all data let's create Pkt4 object.
  776. Pkt4Ptr pkt = Pkt4Ptr(new Pkt4(buf, result));
  777. pkt->updateTimestamp();
  778. unsigned int ifindex = iface->getIndex();
  779. IOAddress from(htonl(from_addr.sin_addr.s_addr));
  780. uint16_t from_port = htons(from_addr.sin_port);
  781. // Set receiving interface based on information, which socket was used to
  782. // receive data. OS-specific info (see os_receive4()) may be more reliable,
  783. // so this value may be overwritten.
  784. pkt->setIndex(ifindex);
  785. pkt->setIface(iface->getName());
  786. pkt->setRemoteAddr(from);
  787. pkt->setRemotePort(from_port);
  788. pkt->setLocalPort(candidate->port_);
  789. if (!os_receive4(m, pkt)) {
  790. cout << "Unable to find pktinfo" << endl;
  791. return (boost::shared_ptr<Pkt4>()); // NULL
  792. }
  793. cout << "Received " << result << " bytes from " << from.toText()
  794. << "/port=" << from_port
  795. << " sent to " << pkt->getLocalAddr().toText() << " over interface "
  796. << iface->getFullName() << endl;
  797. return (pkt);
  798. }
  799. Pkt6Ptr IfaceMgr::receive6(uint32_t timeout_sec, uint32_t timeout_usec /* = 0 */ ) {
  800. // Sanity check for microsecond timeout.
  801. if (timeout_usec >= 1000000) {
  802. isc_throw(BadValue, "fractional timeout must be shorter than"
  803. " one million microseconds");
  804. }
  805. const SocketInfo* candidate = 0;
  806. fd_set sockets;
  807. int maxfd = 0;
  808. stringstream names;
  809. FD_ZERO(&sockets);
  810. /// @todo: marginal performance optimization. We could create the set once
  811. /// and then use its copy for select(). Please note that select() modifies
  812. /// provided set to indicated which sockets have something to read.
  813. IfaceCollection::const_iterator iface;
  814. for (iface = ifaces_.begin(); iface != ifaces_.end(); ++iface) {
  815. for (SocketCollection::const_iterator s = iface->sockets_.begin();
  816. s != iface->sockets_.end(); ++s) {
  817. // Only deal with IPv4 addresses.
  818. if (s->addr_.getFamily() == AF_INET6) {
  819. names << s->sockfd_ << "(" << iface->getName() << ") ";
  820. // Add this socket to listening set
  821. FD_SET(s->sockfd_, &sockets);
  822. if (maxfd < s->sockfd_) {
  823. maxfd = s->sockfd_;
  824. }
  825. }
  826. }
  827. }
  828. // if there is session socket registered...
  829. if (session_socket_ != INVALID_SOCKET) {
  830. // at it to the set as well
  831. FD_SET(session_socket_, &sockets);
  832. if (maxfd < session_socket_)
  833. maxfd = session_socket_;
  834. names << session_socket_ << "(session)";
  835. }
  836. cout << "Trying to receive data on sockets: " << names.str()
  837. << ". Timeout is " << timeout_sec << "." << setw(6) << setfill('0')
  838. << timeout_usec << " seconds." << endl;
  839. struct timeval select_timeout;
  840. select_timeout.tv_sec = timeout_sec;
  841. select_timeout.tv_usec = timeout_usec;
  842. int result = select(maxfd + 1, &sockets, NULL, NULL, &select_timeout);
  843. if (result == 0) {
  844. // nothing received and timeout has been reached
  845. return (Pkt6Ptr()); // NULL
  846. } else if (result < 0) {
  847. cout << "Socket read error: " << strerror(errno) << endl;
  848. /// @todo: perhaps throw here?
  849. return (Pkt6Ptr()); // NULL
  850. }
  851. // Let's find out which socket has the data
  852. if ((session_socket_ != INVALID_SOCKET) && (FD_ISSET(session_socket_, &sockets))) {
  853. // something received over session socket
  854. cout << "BIND10 command or config available over session socket." << endl;
  855. if (session_callback_) {
  856. // in theory we could call io_service.run_one() here, instead of
  857. // implementing callback mechanism, but that would introduce
  858. // asiolink dependency to libdhcp++ and that is something we want
  859. // to avoid (see CPE market and out long term plans for minimalistic
  860. // implementations.
  861. session_callback_();
  862. }
  863. return (Pkt6Ptr()); // NULL
  864. }
  865. // Let's find out which interface/socket has the data
  866. for (iface = ifaces_.begin(); iface != ifaces_.end(); ++iface) {
  867. for (SocketCollection::const_iterator s = iface->sockets_.begin();
  868. s != iface->sockets_.end(); ++s) {
  869. if (FD_ISSET(s->sockfd_, &sockets)) {
  870. candidate = &(*s);
  871. break;
  872. }
  873. }
  874. if (candidate) {
  875. break;
  876. }
  877. }
  878. if (!candidate) {
  879. cout << "Received data over unknown socket." << endl;
  880. return (Pkt6Ptr()); // NULL
  881. }
  882. cout << "Trying to receive over UDP6 socket " << candidate->sockfd_ << " bound to "
  883. << candidate->addr_.toText() << "/port=" << candidate->port_ << " on "
  884. << iface->getFullName() << endl;
  885. // Now we have a socket, let's get some data from it!
  886. uint8_t buf[RCVBUFSIZE];
  887. memset(&control_buf_[0], 0, control_buf_len_);
  888. struct sockaddr_in6 from;
  889. memset(&from, 0, sizeof(from));
  890. // Initialize our message header structure.
  891. struct msghdr m;
  892. memset(&m, 0, sizeof(m));
  893. // Point so we can get the from address.
  894. m.msg_name = &from;
  895. m.msg_namelen = sizeof(from);
  896. // Set the data buffer we're receiving. (Using this wacky
  897. // "scatter-gather" stuff... but we that doesn't really make
  898. // sense for us, so we use a single vector entry.)
  899. struct iovec v;
  900. memset(&v, 0, sizeof(v));
  901. v.iov_base = static_cast<void*>(buf);
  902. v.iov_len = RCVBUFSIZE;
  903. m.msg_iov = &v;
  904. m.msg_iovlen = 1;
  905. // Getting the interface is a bit more involved.
  906. //
  907. // We set up some space for a "control message". We have
  908. // previously asked the kernel to give us packet
  909. // information (when we initialized the interface), so we
  910. // should get the destination address from that.
  911. m.msg_control = &control_buf_[0];
  912. m.msg_controllen = control_buf_len_;
  913. result = recvmsg(candidate->sockfd_, &m, 0);
  914. struct in6_addr to_addr;
  915. memset(&to_addr, 0, sizeof(to_addr));
  916. int ifindex = -1;
  917. if (result >= 0) {
  918. struct in6_pktinfo* pktinfo = NULL;
  919. // If we did read successfully, then we need to loop
  920. // through the control messages we received and
  921. // find the one with our destination address.
  922. //
  923. // We also keep a flag to see if we found it. If we
  924. // didn't, then we consider this to be an error.
  925. bool found_pktinfo = false;
  926. struct cmsghdr* cmsg = CMSG_FIRSTHDR(&m);
  927. while (cmsg != NULL) {
  928. if ((cmsg->cmsg_level == IPPROTO_IPV6) &&
  929. (cmsg->cmsg_type == IPV6_PKTINFO)) {
  930. pktinfo = convertPktInfo6(CMSG_DATA(cmsg));
  931. to_addr = pktinfo->ipi6_addr;
  932. ifindex = pktinfo->ipi6_ifindex;
  933. found_pktinfo = true;
  934. break;
  935. }
  936. cmsg = CMSG_NXTHDR(&m, cmsg);
  937. }
  938. if (!found_pktinfo) {
  939. cout << "Unable to find pktinfo" << endl;
  940. return (Pkt6Ptr()); // NULL
  941. }
  942. } else {
  943. cout << "Failed to receive data." << endl;
  944. return (Pkt6Ptr()); // NULL
  945. }
  946. // Let's create a packet.
  947. Pkt6Ptr pkt;
  948. try {
  949. pkt = Pkt6Ptr(new Pkt6(buf, result));
  950. } catch (const std::exception& ex) {
  951. cout << "Failed to create new packet." << endl;
  952. return (Pkt6Ptr()); // NULL
  953. }
  954. pkt->updateTimestamp();
  955. pkt->setLocalAddr(IOAddress::from_bytes(AF_INET6,
  956. reinterpret_cast<const uint8_t*>(&to_addr)));
  957. pkt->setRemoteAddr(IOAddress::from_bytes(AF_INET6,
  958. reinterpret_cast<const uint8_t*>(&from.sin6_addr)));
  959. pkt->setRemotePort(ntohs(from.sin6_port));
  960. pkt->setIndex(ifindex);
  961. Iface* received = getIface(pkt->getIndex());
  962. if (received) {
  963. pkt->setIface(received->getName());
  964. } else {
  965. cout << "Received packet over unknown interface (ifindex="
  966. << pkt->getIndex() << ")." << endl;
  967. return (boost::shared_ptr<Pkt6>()); // NULL
  968. }
  969. /// @todo: Move this to LOG_DEBUG
  970. cout << "Received " << pkt->getBuffer().getLength() << " bytes over "
  971. << pkt->getIface() << "/" << pkt->getIndex() << " interface: "
  972. << " src=" << pkt->getRemoteAddr().toText()
  973. << ", dst=" << pkt->getLocalAddr().toText()
  974. << endl;
  975. return (pkt);
  976. }
  977. uint16_t IfaceMgr::getSocket(const isc::dhcp::Pkt6& pkt) {
  978. Iface* iface = getIface(pkt.getIface());
  979. if (iface == NULL) {
  980. isc_throw(BadValue, "Tried to find socket for non-existent interface "
  981. << pkt.getIface());
  982. }
  983. SocketCollection::const_iterator s;
  984. for (s = iface->sockets_.begin(); s != iface->sockets_.end(); ++s) {
  985. if ((s->family_ == AF_INET6) &&
  986. (!s->addr_.getAddress().to_v6().is_multicast())) {
  987. return (s->sockfd_);
  988. }
  989. /// @todo: Add more checks here later. If remote address is
  990. /// not link-local, we can't use link local bound socket
  991. /// to send data.
  992. }
  993. isc_throw(Unexpected, "Interface " << iface->getFullName()
  994. << " does not have any suitable IPv6 sockets open.");
  995. }
  996. uint16_t IfaceMgr::getSocket(isc::dhcp::Pkt4 const& pkt) {
  997. Iface* iface = getIface(pkt.getIface());
  998. if (iface == NULL) {
  999. isc_throw(BadValue, "Tried to find socket for non-existent interface "
  1000. << pkt.getIface());
  1001. }
  1002. SocketCollection::const_iterator s;
  1003. for (s = iface->sockets_.begin(); s != iface->sockets_.end(); ++s) {
  1004. if (s->family_ == AF_INET) {
  1005. return (s->sockfd_);
  1006. }
  1007. /// TODO: Add more checks here later. If remote address is
  1008. /// not link-local, we can't use link local bound socket
  1009. /// to send data.
  1010. }
  1011. isc_throw(Unexpected, "Interface " << iface->getFullName()
  1012. << " does not have any suitable IPv4 sockets open.");
  1013. }
  1014. } // end of namespace isc::dhcp
  1015. } // end of namespace isc