dhcp4_srv.cc 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274
  1. // Copyright (C) 2011 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 <dhcp/dhcp4.h>
  15. #include <dhcp/pkt4.h>
  16. #include <dhcp/iface_mgr.h>
  17. #include <dhcp4/dhcp4_srv.h>
  18. #include <asiolink/io_address.h>
  19. #include <dhcp/option4_addrlst.h>
  20. using namespace std;
  21. using namespace isc;
  22. using namespace isc::dhcp;
  23. using namespace isc::asiolink;
  24. // These are hardcoded parameters. Currently this is a skeleton server that only
  25. // grants those options and a single, fixed, hardcoded lease.
  26. const std::string HARDCODED_LEASE = "192.0.2.222"; // assigned lease
  27. const std::string HARDCODED_NETMASK = "255.255.255.0";
  28. const uint32_t HARDCODED_LEASE_TIME = 60; // in seconds
  29. const std::string HARDCODED_GATEWAY = "192.0.2.1";
  30. const std::string HARDCODED_DNS_SERVER = "192.0.2.2";
  31. const std::string HARDCODED_DOMAIN_NAME = "isc.example.com";
  32. const std::string HARDCODED_SERVER_ID = "192.0.2.1";
  33. Dhcpv4Srv::Dhcpv4Srv(uint16_t port) {
  34. cout << "Initialization: opening sockets on port " << port << endl;
  35. // first call to instance() will create IfaceMgr (it's a singleton)
  36. // it may throw something if things go wrong
  37. IfaceMgr::instance();
  38. /// @todo: instantiate LeaseMgr here once it is imlpemented.
  39. IfaceMgr::instance().printIfaces();
  40. IfaceMgr::instance().openSockets4(port);
  41. setServerID();
  42. shutdown_ = false;
  43. }
  44. Dhcpv4Srv::~Dhcpv4Srv() {
  45. cout << "DHCPv4 server shutdown." << endl;
  46. IfaceMgr::instance().closeSockets();
  47. }
  48. bool
  49. Dhcpv4Srv::run() {
  50. while (!shutdown_) {
  51. boost::shared_ptr<Pkt4> query; // client's message
  52. boost::shared_ptr<Pkt4> rsp; // server's response
  53. query = IfaceMgr::instance().receive4();
  54. if (query) {
  55. try {
  56. query->unpack();
  57. } catch (const std::exception& e) {
  58. /// TODO: Printout reasons of failed parsing
  59. cout << "Failed to parse incoming packet " << endl;
  60. continue;
  61. }
  62. switch (query->getType()) {
  63. case DHCPDISCOVER:
  64. rsp = processDiscover(query);
  65. break;
  66. case DHCPREQUEST:
  67. rsp = processRequest(query);
  68. break;
  69. case DHCPRELEASE:
  70. processRelease(query);
  71. break;
  72. case DHCPDECLINE:
  73. processDecline(query);
  74. break;
  75. case DHCPINFORM:
  76. processInform(query);
  77. break;
  78. default:
  79. cout << "Unknown pkt type received:"
  80. << query->getType() << endl;
  81. }
  82. cout << "Received message type " << int(query->getType()) << endl;
  83. // TODO: print out received packets only if verbose (or debug)
  84. // mode is enabled
  85. cout << query->toText();
  86. if (rsp) {
  87. if (rsp->getRemoteAddr().toText() == "0.0.0.0") {
  88. rsp->setRemoteAddr(query->getRemoteAddr());
  89. }
  90. if (!rsp->getHops()) {
  91. rsp->setRemotePort(DHCP4_CLIENT_PORT);
  92. } else {
  93. rsp->setRemotePort(DHCP4_SERVER_PORT);
  94. }
  95. rsp->setLocalAddr(query->getLocalAddr());
  96. rsp->setLocalPort(DHCP4_SERVER_PORT);
  97. rsp->setIface(query->getIface());
  98. rsp->setIndex(query->getIndex());
  99. cout << "Replying with message type "
  100. << static_cast<int>(rsp->getType()) << ":" << endl;
  101. cout << rsp->toText();
  102. cout << "----" << endl;
  103. if (rsp->pack()) {
  104. cout << "Packet assembled correctly." << endl;
  105. }
  106. IfaceMgr::instance().send(rsp);
  107. }
  108. }
  109. // TODO add support for config session (see src/bin/auth/main.cc)
  110. // so this daemon can be controlled from bob
  111. }
  112. return (true);
  113. }
  114. void
  115. Dhcpv4Srv::setServerID() {
  116. /// TODO implement this for real once interface detection (ticket 1237)
  117. /// is done. Use hardcoded server-id for now.
  118. #if 0
  119. // uncomment this once ticket 1350 is merged.
  120. IOAddress srvId("127.0.0.1");
  121. serverid_ = boost::shared_ptr<Option>(
  122. new Option4AddrLst(Option::V4, DHO_DHCP_SERVER_IDENTIFIER, srvId));
  123. #endif
  124. }
  125. void Dhcpv4Srv::copyDefaultFields(const boost::shared_ptr<Pkt4>& question,
  126. boost::shared_ptr<Pkt4>& answer) {
  127. answer->setIface(question->getIface());
  128. answer->setIndex(question->getIndex());
  129. answer->setCiaddr(question->getCiaddr());
  130. answer->setSiaddr(IOAddress("0.0.0.0")); // explictly set this to 0
  131. answer->setHops(question->getHops());
  132. // copy MAC address
  133. vector<uint8_t> mac(question->getChaddr(),
  134. question->getChaddr() + Pkt4::MAX_CHADDR_LEN);
  135. answer->setHWAddr(question->getHtype(), question->getHlen(), mac);
  136. // relay address
  137. answer->setGiaddr(question->getGiaddr());
  138. if (question->getGiaddr().toText() != "0.0.0.0") {
  139. // relayed traffic
  140. answer->setRemoteAddr(question->getGiaddr());
  141. } else {
  142. // direct traffic
  143. answer->setRemoteAddr(question->getRemoteAddr());
  144. }
  145. }
  146. void Dhcpv4Srv::appendDefaultOptions(boost::shared_ptr<Pkt4>& msg, uint8_t msg_type) {
  147. boost::shared_ptr<Option> opt;
  148. // add Message Type Option (type 53)
  149. std::vector<uint8_t> tmp;
  150. tmp.push_back(static_cast<uint8_t>(msg_type));
  151. opt = boost::shared_ptr<Option>(new Option(Option::V4, DHO_DHCP_MESSAGE_TYPE, tmp));
  152. msg->addOption(opt);
  153. // DHCP Server Identifier (type 54)
  154. opt = boost::shared_ptr<Option>
  155. (new Option4AddrLst(DHO_DHCP_SERVER_IDENTIFIER, IOAddress(HARDCODED_SERVER_ID)));
  156. msg->addOption(opt);
  157. // more options will be added here later
  158. }
  159. void Dhcpv4Srv::appendRequestedOptions(boost::shared_ptr<Pkt4>& msg) {
  160. boost::shared_ptr<Option> opt;
  161. // Domain name (type 15)
  162. vector<uint8_t> domain(HARDCODED_DOMAIN_NAME.begin(), HARDCODED_DOMAIN_NAME.end());
  163. opt = boost::shared_ptr<Option>(new Option(Option::V4, DHO_DOMAIN_NAME, domain));
  164. msg->addOption(opt);
  165. // TODO: Add Option_String class
  166. // DNS servers (type 6)
  167. opt = boost::shared_ptr<Option>
  168. (new Option4AddrLst(DHO_DOMAIN_NAME_SERVERS, IOAddress(HARDCODED_DNS_SERVER)));
  169. msg->addOption(opt);
  170. }
  171. void Dhcpv4Srv::tryAssignLease(boost::shared_ptr<Pkt4>& msg) {
  172. boost::shared_ptr<Option> opt;
  173. // TODO: Implement actual lease assignment here
  174. msg->setYiaddr(IOAddress(HARDCODED_LEASE));
  175. // IP Address Lease time (type 51)
  176. opt = boost::shared_ptr<Option>(new Option(Option::V4, DHO_DHCP_LEASE_TIME));
  177. opt->setUint32(HARDCODED_LEASE_TIME);
  178. msg->addOption(opt);
  179. // TODO: create Option_IntArray that holds list of integers, similar to Option4_AddrLst
  180. // Subnet mask (type 1)
  181. opt = boost::shared_ptr<Option>
  182. (new Option4AddrLst(DHO_SUBNET_MASK, IOAddress(HARDCODED_NETMASK)));
  183. msg->addOption(opt);
  184. // Router (type 3)
  185. opt = boost::shared_ptr<Option>
  186. (new Option4AddrLst(DHO_ROUTERS, IOAddress(HARDCODED_GATEWAY)));
  187. msg->addOption(opt);
  188. }
  189. boost::shared_ptr<Pkt4>
  190. Dhcpv4Srv::processDiscover(boost::shared_ptr<Pkt4>& discover) {
  191. boost::shared_ptr<Pkt4> offer = boost::shared_ptr<Pkt4>
  192. (new Pkt4(DHCPOFFER, discover->getTransid()));
  193. copyDefaultFields(discover, offer);
  194. appendDefaultOptions(offer, DHCPOFFER);
  195. appendRequestedOptions(offer);
  196. tryAssignLease(offer);
  197. return (offer);
  198. }
  199. boost::shared_ptr<Pkt4>
  200. Dhcpv4Srv::processRequest(boost::shared_ptr<Pkt4>& request) {
  201. boost::shared_ptr<Pkt4> ack = boost::shared_ptr<Pkt4>
  202. (new Pkt4(DHCPACK, request->getTransid()));
  203. copyDefaultFields(request, ack);
  204. appendDefaultOptions(ack, DHCPACK);
  205. appendRequestedOptions(ack);
  206. tryAssignLease(ack);
  207. return (ack);
  208. }
  209. void Dhcpv4Srv::processRelease(boost::shared_ptr<Pkt4>& release) {
  210. /// TODO: Implement this.
  211. cout << "Received RELEASE on " << release->getIface() << " interface." << endl;
  212. }
  213. void Dhcpv4Srv::processDecline(boost::shared_ptr<Pkt4>& decline) {
  214. /// TODO: Implement this.
  215. cout << "Received DECLINE on " << decline->getIface() << " interface." << endl;
  216. }
  217. boost::shared_ptr<Pkt4> Dhcpv4Srv::processInform(boost::shared_ptr<Pkt4>& inform) {
  218. /// TODO: Currently implemented echo mode. Implement this for real
  219. return (inform);
  220. }