dhcp4_srv.cc 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634
  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 <asiolink/io_address.h>
  15. #include <dhcp/dhcp4.h>
  16. #include <dhcp/iface_mgr.h>
  17. #include <dhcp/option4_addrlst.h>
  18. #include <dhcp/option_int.h>
  19. #include <dhcp/pkt4.h>
  20. #include <dhcp/duid.h>
  21. #include <dhcp/hwaddr.h>
  22. #include <dhcp4/dhcp4_log.h>
  23. #include <dhcp4/dhcp4_srv.h>
  24. #include <dhcpsrv/utils.h>
  25. #include <dhcpsrv/cfgmgr.h>
  26. #include <dhcpsrv/lease_mgr.h>
  27. #include <dhcpsrv/lease_mgr_factory.h>
  28. #include <dhcpsrv/subnet.h>
  29. #include <dhcpsrv/utils.h>
  30. #include <dhcpsrv/addr_utilities.h>
  31. #include <boost/algorithm/string/erase.hpp>
  32. #include <iomanip>
  33. #include <fstream>
  34. using namespace isc;
  35. using namespace isc::asiolink;
  36. using namespace isc::dhcp;
  37. using namespace isc::log;
  38. using namespace std;
  39. // These are hardcoded parameters. Currently this is a skeleton server that only
  40. // grants those options and a single, fixed, hardcoded lease.
  41. const std::string HARDCODED_GATEWAY = "192.0.2.1";
  42. const std::string HARDCODED_DNS_SERVER = "192.0.2.2";
  43. const std::string HARDCODED_DOMAIN_NAME = "isc.example.com";
  44. Dhcpv4Srv::Dhcpv4Srv(uint16_t port, const char* dbconfig) {
  45. LOG_DEBUG(dhcp4_logger, DBG_DHCP4_START, DHCP4_OPEN_SOCKET).arg(port);
  46. try {
  47. // First call to instance() will create IfaceMgr (it's a singleton)
  48. // it may throw something if things go wrong
  49. IfaceMgr::instance();
  50. if (port) {
  51. // open sockets only if port is non-zero. Port 0 is used
  52. // for non-socket related testing.
  53. IfaceMgr::instance().openSockets4(port);
  54. }
  55. string srvid_file = CfgMgr::instance().getDataDir() + "/" + string(SERVER_ID_FILE);
  56. if (loadServerID(srvid_file)) {
  57. LOG_DEBUG(dhcp4_logger, DBG_DHCP4_START, DHCP4_SERVERID_LOADED)
  58. .arg(srvid_file);
  59. } else {
  60. generateServerID();
  61. LOG_INFO(dhcp4_logger, DHCP4_SERVERID_GENERATED)
  62. .arg(srvidToString(getServerID()))
  63. .arg(srvid_file);
  64. if (!writeServerID(srvid_file)) {
  65. LOG_WARN(dhcp4_logger, DHCP4_SERVERID_WRITE_FAIL)
  66. .arg(srvid_file);
  67. }
  68. }
  69. // Instantiate LeaseMgr
  70. LeaseMgrFactory::create(dbconfig);
  71. LOG_INFO(dhcp4_logger, DHCP4_DB_BACKEND_STARTED)
  72. .arg(LeaseMgrFactory::instance().getType())
  73. .arg(LeaseMgrFactory::instance().getName());
  74. // Instantiate allocation engine
  75. alloc_engine_.reset(new AllocEngine(AllocEngine::ALLOC_ITERATIVE, 100));
  76. } catch (const std::exception &e) {
  77. LOG_ERROR(dhcp4_logger, DHCP4_SRV_CONSTRUCT_ERROR).arg(e.what());
  78. shutdown_ = true;
  79. return;
  80. }
  81. shutdown_ = false;
  82. }
  83. Dhcpv4Srv::~Dhcpv4Srv() {
  84. IfaceMgr::instance().closeSockets();
  85. }
  86. void Dhcpv4Srv::shutdown() {
  87. LOG_DEBUG(dhcp4_logger, DBG_DHCP4_BASIC, DHCP4_SHUTDOWN_REQUEST);
  88. shutdown_ = true;
  89. }
  90. bool
  91. Dhcpv4Srv::run() {
  92. while (!shutdown_) {
  93. /// @todo: calculate actual timeout once we have lease database
  94. int timeout = 1000;
  95. // client's message and server's response
  96. Pkt4Ptr query;
  97. Pkt4Ptr rsp;
  98. try {
  99. query = IfaceMgr::instance().receive4(timeout);
  100. } catch (const std::exception& e) {
  101. LOG_ERROR(dhcp4_logger, DHCP4_PACKET_RECEIVE_FAIL).arg(e.what());
  102. }
  103. if (query) {
  104. try {
  105. query->unpack();
  106. } catch (const std::exception& e) {
  107. // Failed to parse the packet.
  108. LOG_DEBUG(dhcp4_logger, DBG_DHCP4_DETAIL,
  109. DHCP4_PACKET_PARSE_FAIL).arg(e.what());
  110. continue;
  111. }
  112. LOG_DEBUG(dhcp4_logger, DBG_DHCP4_DETAIL, DHCP4_PACKET_RECEIVED)
  113. .arg(serverReceivedPacketName(query->getType()))
  114. .arg(query->getType())
  115. .arg(query->getIface());
  116. LOG_DEBUG(dhcp4_logger, DBG_DHCP4_DETAIL_DATA, DHCP4_QUERY_DATA)
  117. .arg(query->toText());
  118. switch (query->getType()) {
  119. case DHCPDISCOVER:
  120. rsp = processDiscover(query);
  121. break;
  122. case DHCPREQUEST:
  123. rsp = processRequest(query);
  124. break;
  125. case DHCPRELEASE:
  126. processRelease(query);
  127. break;
  128. case DHCPDECLINE:
  129. processDecline(query);
  130. break;
  131. case DHCPINFORM:
  132. processInform(query);
  133. break;
  134. default:
  135. // Only action is to output a message if debug is enabled,
  136. // and that will be covered by the debug statement before
  137. // the "switch" statement.
  138. ;
  139. }
  140. if (rsp) {
  141. if (rsp->getRemoteAddr().toText() == "0.0.0.0") {
  142. rsp->setRemoteAddr(query->getRemoteAddr());
  143. }
  144. if (!rsp->getHops()) {
  145. rsp->setRemotePort(DHCP4_CLIENT_PORT);
  146. } else {
  147. rsp->setRemotePort(DHCP4_SERVER_PORT);
  148. }
  149. rsp->setLocalAddr(query->getLocalAddr());
  150. rsp->setLocalPort(DHCP4_SERVER_PORT);
  151. rsp->setIface(query->getIface());
  152. rsp->setIndex(query->getIndex());
  153. LOG_DEBUG(dhcp4_logger, DBG_DHCP4_DETAIL_DATA,
  154. DHCP4_RESPONSE_DATA)
  155. .arg(rsp->getType()).arg(rsp->toText());
  156. if (rsp->pack()) {
  157. try {
  158. IfaceMgr::instance().send(rsp);
  159. } catch (const std::exception& e) {
  160. LOG_ERROR(dhcp4_logger, DHCP4_PACKET_SEND_FAIL).arg(e.what());
  161. }
  162. } else {
  163. LOG_ERROR(dhcp4_logger, DHCP4_PACK_FAIL);
  164. }
  165. }
  166. }
  167. }
  168. return (true);
  169. }
  170. bool Dhcpv4Srv::loadServerID(const std::string& file_name) {
  171. // load content of the file into a string
  172. fstream f(file_name.c_str(), ios::in);
  173. if (!f.is_open()) {
  174. return (false);
  175. }
  176. string hex_string;
  177. f >> hex_string;
  178. f.close();
  179. // remove any spaces
  180. boost::algorithm::erase_all(hex_string, " ");
  181. try {
  182. IOAddress addr(hex_string);
  183. if (!addr.isV4()) {
  184. return (false);
  185. }
  186. // Now create server-id option
  187. serverid_.reset(new Option4AddrLst(DHO_DHCP_SERVER_IDENTIFIER, addr));
  188. } catch(...) {
  189. // any kind of malformed input (empty string, IPv6 address, complete
  190. // garbate etc.)
  191. return (false);
  192. }
  193. return (true);
  194. }
  195. void Dhcpv4Srv::generateServerID() {
  196. const IfaceMgr::IfaceCollection& ifaces = IfaceMgr::instance().getIfaces();
  197. // Let's find suitable interface.
  198. for (IfaceMgr::IfaceCollection::const_iterator iface = ifaces.begin();
  199. iface != ifaces.end(); ++iface) {
  200. // Let's don't use loopback.
  201. if (iface->flag_loopback_) {
  202. continue;
  203. }
  204. // Let's skip downed interfaces. It is better to use working ones.
  205. if (!iface->flag_up_) {
  206. continue;
  207. }
  208. const IfaceMgr::AddressCollection addrs = iface->getAddresses();
  209. for (IfaceMgr::AddressCollection::const_iterator addr = addrs.begin();
  210. addr != addrs.end(); ++addr) {
  211. if (addr->getFamily() != AF_INET) {
  212. continue;
  213. }
  214. serverid_ = OptionPtr(new Option4AddrLst(DHO_DHCP_SERVER_IDENTIFIER,
  215. *addr));
  216. return;
  217. }
  218. }
  219. isc_throw(BadValue, "No suitable interfaces for server-identifier found");
  220. }
  221. bool Dhcpv4Srv::writeServerID(const std::string& file_name) {
  222. fstream f(file_name.c_str(), ios::out | ios::trunc);
  223. if (!f.good()) {
  224. return (false);
  225. }
  226. f << srvidToString(getServerID());
  227. f.close();
  228. }
  229. string Dhcpv4Srv::srvidToString(const OptionPtr& srvid) {
  230. if (!srvid) {
  231. isc_throw(BadValue, "NULL pointer passed to srvidToString()");
  232. }
  233. boost::shared_ptr<Option4AddrLst> generated =
  234. boost::dynamic_pointer_cast<Option4AddrLst>(srvid);
  235. if (!srvid) {
  236. isc_throw(BadValue, "Pointer to invalid option passed to srvidToString()");
  237. }
  238. Option4AddrLst::AddressContainer addrs = generated->getAddresses();
  239. if (addrs.size() != 1) {
  240. isc_throw(BadValue, "Malformed option passed to srvidToString(). "
  241. << "Expected to contain a single IPv4 address.");
  242. }
  243. return (addrs[0].toText());
  244. }
  245. void Dhcpv4Srv::copyDefaultFields(const Pkt4Ptr& question, Pkt4Ptr& answer) {
  246. answer->setIface(question->getIface());
  247. answer->setIndex(question->getIndex());
  248. answer->setCiaddr(question->getCiaddr());
  249. answer->setSiaddr(IOAddress("0.0.0.0")); // explictly set this to 0
  250. answer->setHops(question->getHops());
  251. // copy MAC address
  252. answer->setHWAddr(question->getHWAddr());
  253. // relay address
  254. answer->setGiaddr(question->getGiaddr());
  255. if (question->getGiaddr().toText() != "0.0.0.0") {
  256. // relayed traffic
  257. answer->setRemoteAddr(question->getGiaddr());
  258. } else {
  259. // direct traffic
  260. answer->setRemoteAddr(question->getRemoteAddr());
  261. }
  262. // Let's copy client-id to response. See RFC6842.
  263. OptionPtr client_id = question->getOption(DHO_DHCP_CLIENT_IDENTIFIER);
  264. if (client_id) {
  265. answer->addOption(client_id);
  266. }
  267. }
  268. void Dhcpv4Srv::appendDefaultOptions(Pkt4Ptr& msg, uint8_t msg_type) {
  269. OptionPtr opt;
  270. // add Message Type Option (type 53)
  271. msg->setType(msg_type);
  272. // DHCP Server Identifier (type 54)
  273. msg->addOption(getServerID());
  274. // more options will be added here later
  275. }
  276. void Dhcpv4Srv::appendRequestedOptions(Pkt4Ptr& msg) {
  277. OptionPtr opt;
  278. // Domain name (type 15)
  279. vector<uint8_t> domain(HARDCODED_DOMAIN_NAME.begin(), HARDCODED_DOMAIN_NAME.end());
  280. opt = OptionPtr(new Option(Option::V4, DHO_DOMAIN_NAME, domain));
  281. msg->addOption(opt);
  282. // TODO: Add Option_String class
  283. // DNS servers (type 6)
  284. opt = OptionPtr(new Option4AddrLst(DHO_DOMAIN_NAME_SERVERS, IOAddress(HARDCODED_DNS_SERVER)));
  285. msg->addOption(opt);
  286. }
  287. void Dhcpv4Srv::assignLease(const Pkt4Ptr& question, Pkt4Ptr& answer) {
  288. // We need to select a subnet the client is connected in.
  289. Subnet4Ptr subnet = selectSubnet(question);
  290. if (!subnet) {
  291. // This particular client is out of luck today. We do not have
  292. // information about the subnet he is connected to. This likely means
  293. // misconfiguration of the server (or some relays). We will continue to
  294. // process this message, but our response will be almost useless: no
  295. // addresses or prefixes, no subnet specific configuration etc. The only
  296. // thing this client can get is some global information (like DNS
  297. // servers).
  298. // perhaps this should be logged on some higher level? This is most likely
  299. // configuration bug.
  300. LOG_ERROR(dhcp4_logger, DHCP4_SUBNET_SELECTION_FAILED)
  301. .arg(question->getRemoteAddr().toText())
  302. .arg(serverReceivedPacketName(question->getType()));
  303. answer->setType(DHCPNAK);
  304. answer->setYiaddr(IOAddress("0.0.0.0"));
  305. return;
  306. }
  307. LOG_DEBUG(dhcp4_logger, DBG_DHCP4_DETAIL_DATA, DHCP4_SUBNET_SELECTED)
  308. .arg(subnet->toText());
  309. // Get client-id option
  310. ClientIdPtr client_id;
  311. OptionPtr opt = question->getOption(DHO_DHCP_CLIENT_IDENTIFIER);
  312. if (opt) {
  313. client_id = ClientIdPtr(new ClientId(opt->getData()));
  314. }
  315. // client-id is not mandatory in DHCPv4
  316. IOAddress hint = question->getYiaddr();
  317. HWAddrPtr hwaddr = question->getHWAddr();
  318. // "Fake" allocation is processing of DISCOVER message. We pretend to do an
  319. // allocation, but we do not put the lease in the database. That is ok,
  320. // because we do not guarantee that the user will get that exact lease. If
  321. // the user selects this server to do actual allocation (i.e. sends REQUEST)
  322. // it should include this hint. That will help us during the actual lease
  323. // allocation.
  324. bool fake_allocation = (question->getType() == DHCPDISCOVER);
  325. // Use allocation engine to pick a lease for this client. Allocation engine
  326. // will try to honour the hint, but it is just a hint - some other address
  327. // may be used instead. If fake_allocation is set to false, the lease will
  328. // be inserted into the LeaseMgr as well.
  329. Lease4Ptr lease = alloc_engine_->allocateAddress4(subnet, client_id, hwaddr,
  330. hint, fake_allocation);
  331. if (lease) {
  332. // We have a lease! Let's set it in the packet and send it back to
  333. // the client.
  334. LOG_DEBUG(dhcp4_logger, DBG_DHCP4_DETAIL, fake_allocation?
  335. DHCP4_LEASE_ADVERT:DHCP4_LEASE_ALLOC)
  336. .arg(lease->addr_.toText())
  337. .arg(client_id?client_id->toText():"(no client-id)")
  338. .arg(hwaddr?hwaddr->toText():"(no hwaddr info)");
  339. answer->setYiaddr(lease->addr_);
  340. // IP Address Lease time (type 51)
  341. opt = OptionPtr(new Option(Option::V4, DHO_DHCP_LEASE_TIME));
  342. opt->setUint32(lease->valid_lft_);
  343. answer->addOption(opt);
  344. // @todo: include real router information here
  345. // Router (type 3)
  346. opt = OptionPtr(new Option4AddrLst(DHO_ROUTERS, IOAddress(HARDCODED_GATEWAY)));
  347. answer->addOption(opt);
  348. // Subnet mask (type 1)
  349. answer->addOption(getNetmaskOption(subnet));
  350. // @todo: send renew timer option (T1, option 58)
  351. // @todo: send rebind timer option (T2, option 59)
  352. } else {
  353. // Allocation engine did not allocate a lease. The engine logged
  354. // cause of that failure. The only thing left is to insert
  355. // status code to pass the sad news to the client.
  356. LOG_DEBUG(dhcp4_logger, DBG_DHCP4_DETAIL, fake_allocation?
  357. DHCP4_LEASE_ADVERT_FAIL:DHCP4_LEASE_ALLOC_FAIL)
  358. .arg(client_id?client_id->toText():"(no client-id)")
  359. .arg(hwaddr?hwaddr->toText():"(no hwaddr info)")
  360. .arg(hint.toText());
  361. answer->setType(DHCPNAK);
  362. answer->setYiaddr(IOAddress("0.0.0.0"));
  363. }
  364. }
  365. OptionPtr Dhcpv4Srv::getNetmaskOption(const Subnet4Ptr& subnet) {
  366. uint32_t netmask = getNetmask4(subnet->get().second);
  367. OptionPtr opt(new OptionInt<uint32_t>(Option::V4,
  368. DHO_SUBNET_MASK, netmask));
  369. return (opt);
  370. }
  371. Pkt4Ptr Dhcpv4Srv::processDiscover(Pkt4Ptr& discover) {
  372. Pkt4Ptr offer = Pkt4Ptr
  373. (new Pkt4(DHCPOFFER, discover->getTransid()));
  374. copyDefaultFields(discover, offer);
  375. appendDefaultOptions(offer, DHCPOFFER);
  376. appendRequestedOptions(offer);
  377. assignLease(discover, offer);
  378. return (offer);
  379. }
  380. Pkt4Ptr Dhcpv4Srv::processRequest(Pkt4Ptr& request) {
  381. Pkt4Ptr ack = Pkt4Ptr
  382. (new Pkt4(DHCPACK, request->getTransid()));
  383. copyDefaultFields(request, ack);
  384. appendDefaultOptions(ack, DHCPACK);
  385. appendRequestedOptions(ack);
  386. assignLease(request, ack);
  387. return (ack);
  388. }
  389. void Dhcpv4Srv::processRelease(Pkt4Ptr& release) {
  390. // Try to find client-id
  391. ClientIdPtr client_id;
  392. OptionPtr opt = release->getOption(DHO_DHCP_CLIENT_IDENTIFIER);
  393. if (opt) {
  394. client_id = ClientIdPtr(new ClientId(opt->getData()));
  395. }
  396. try {
  397. // Do we have a lease for that particular address?
  398. Lease4Ptr lease = LeaseMgrFactory::instance().getLease4(release->getYiaddr());
  399. if (!lease) {
  400. // No such lease - bogus release
  401. LOG_DEBUG(dhcp4_logger, DBG_DHCP4_DETAIL, DHCP4_RELEASE_FAIL_NO_LEASE)
  402. .arg(release->getYiaddr().toText())
  403. .arg(release->getHWAddr()->toText())
  404. .arg(client_id ? client_id->toText() : "(no client-id)");
  405. return;
  406. }
  407. // Does the hardware address match? We don't want one client releasing
  408. // second client's leases.
  409. if (lease->hwaddr_ != release->getHWAddr()->hwaddr_) {
  410. // @todo: Print hwaddr from lease as part of ticket #2589
  411. LOG_DEBUG(dhcp4_logger, DBG_DHCP4_DETAIL, DHCP4_RELEASE_FAIL_WRONG_HWADDR)
  412. .arg(release->getYiaddr().toText())
  413. .arg(client_id ? client_id->toText() : "(no client-id)")
  414. .arg(release->getHWAddr()->toText());
  415. return;
  416. }
  417. // Does the lease have client-id info? If it has, then check it with what
  418. // the client sent us.
  419. if (lease->client_id_ && client_id && *lease->client_id_ != *client_id) {
  420. LOG_DEBUG(dhcp4_logger, DBG_DHCP4_DETAIL, DHCP4_RELEASE_FAIL_WRONG_CLIENT_ID)
  421. .arg(release->getYiaddr().toText())
  422. .arg(client_id->toText())
  423. .arg(lease->client_id_->toText());
  424. return;
  425. }
  426. // Ok, hw and client-id match - let's release the lease.
  427. if (LeaseMgrFactory::instance().deleteLease(lease->addr_)) {
  428. // Release successful - we're done here
  429. LOG_DEBUG(dhcp4_logger, DBG_DHCP4_DETAIL, DHCP4_RELEASE)
  430. .arg(lease->addr_.toText())
  431. .arg(client_id ? client_id->toText() : "(no client-id)")
  432. .arg(release->getHWAddr()->toText());
  433. } else {
  434. // Release failed -
  435. LOG_ERROR(dhcp4_logger, DHCP4_RELEASE_FAIL)
  436. .arg(lease->addr_.toText())
  437. .arg(client_id ? client_id->toText() : "(no client-id)")
  438. .arg(release->getHWAddr()->toText());
  439. }
  440. } catch (const isc::Exception& ex) {
  441. // Rethrow the exception with a bit more data.
  442. LOG_ERROR(dhcp4_logger, DHCP4_RELEASE_EXCEPTION)
  443. .arg(ex.what())
  444. .arg(release->getYiaddr());
  445. }
  446. }
  447. void Dhcpv4Srv::processDecline(Pkt4Ptr& decline) {
  448. /// TODO: Implement this.
  449. }
  450. Pkt4Ptr Dhcpv4Srv::processInform(Pkt4Ptr& inform) {
  451. /// TODO: Currently implemented echo mode. Implement this for real
  452. return (inform);
  453. }
  454. const char*
  455. Dhcpv4Srv::serverReceivedPacketName(uint8_t type) {
  456. static const char* DISCOVER = "DISCOVER";
  457. static const char* REQUEST = "REQUEST";
  458. static const char* RELEASE = "RELEASE";
  459. static const char* DECLINE = "DECLINE";
  460. static const char* INFORM = "INFORM";
  461. static const char* UNKNOWN = "UNKNOWN";
  462. switch (type) {
  463. case DHCPDISCOVER:
  464. return (DISCOVER);
  465. case DHCPREQUEST:
  466. return (REQUEST);
  467. case DHCPRELEASE:
  468. return (RELEASE);
  469. case DHCPDECLINE:
  470. return (DECLINE);
  471. case DHCPINFORM:
  472. return (INFORM);
  473. default:
  474. ;
  475. }
  476. return (UNKNOWN);
  477. }
  478. Subnet4Ptr Dhcpv4Srv::selectSubnet(const Pkt4Ptr& question) {
  479. // Is this relayed message?
  480. IOAddress relay = question->getGiaddr();
  481. if (relay.toText() == "0.0.0.0") {
  482. // Yes: Use relay address to select subnet
  483. return (CfgMgr::instance().getSubnet4(relay));
  484. } else {
  485. // No: Use client's address to select subnet
  486. return (CfgMgr::instance().getSubnet4(question->getRemoteAddr()));
  487. }
  488. }
  489. void Dhcpv4Srv::sanityCheck(const Pkt4Ptr& pkt, RequirementLevel serverid) {
  490. OptionPtr server_id = pkt->getOption(DHO_DHCP_SERVER_IDENTIFIER);
  491. switch (serverid) {
  492. case FORBIDDEN:
  493. if (server_id) {
  494. isc_throw(RFCViolation, "Server-id option was not expected, but "
  495. << "received in " << serverReceivedPacketName(pkt->getType()));
  496. }
  497. break;
  498. case MANDATORY:
  499. if (!server_id) {
  500. isc_throw(RFCViolation, "Server-id option was expected, but not "
  501. " received in message "
  502. << serverReceivedPacketName(pkt->getType()));
  503. }
  504. break;
  505. case OPTIONAL:
  506. // do nothing here
  507. ;
  508. }
  509. }