dhcp4_srv.h 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402
  1. // Copyright (C) 2011-2013 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. #ifndef DHCPV4_SRV_H
  15. #define DHCPV4_SRV_H
  16. #include <dhcp/dhcp4.h>
  17. #include <dhcp/pkt4.h>
  18. #include <dhcp/option.h>
  19. #include <dhcpsrv/subnet.h>
  20. #include <dhcpsrv/alloc_engine.h>
  21. #include <hooks/callout_handle.h>
  22. #include <boost/noncopyable.hpp>
  23. #include <iostream>
  24. namespace isc {
  25. namespace dhcp {
  26. /// @brief DHCPv4 server service.
  27. ///
  28. /// This singleton class represents DHCPv4 server. It contains all
  29. /// top-level methods and routines necessary for server operation.
  30. /// In particular, it instantiates IfaceMgr, loads or generates DUID
  31. /// that is going to be used as server-identifier, receives incoming
  32. /// packets, processes them, manages leases assignment and generates
  33. /// appropriate responses.
  34. ///
  35. /// This class does not support any controlling mechanisms directly.
  36. /// See the derived \ref ControlledDhcpv4Srv class for support for
  37. /// command and configuration updates over msgq.
  38. ///
  39. /// For detailed explanation or relations between main(), ControlledDhcpv4Srv,
  40. /// Dhcpv4Srv and other classes, see \ref dhcpv4Session.
  41. class Dhcpv4Srv : public boost::noncopyable {
  42. public:
  43. /// @brief defines if certain option may, must or must not appear
  44. typedef enum {
  45. FORBIDDEN,
  46. MANDATORY,
  47. OPTIONAL
  48. } RequirementLevel;
  49. /// @brief Default constructor.
  50. ///
  51. /// Instantiates necessary services, required to run DHCPv4 server.
  52. /// In particular, creates IfaceMgr that will be responsible for
  53. /// network interaction. Will instantiate lease manager, and load
  54. /// old or create new DUID. It is possible to specify alternate
  55. /// port on which DHCPv4 server will listen on. That is mostly useful
  56. /// for testing purposes. The Last two arguments of the constructor
  57. /// should be left at default values for normal server operation.
  58. /// They should be set to 'false' when creating an instance of this
  59. /// class for unit testing because features they enable require
  60. /// root privileges.
  61. ///
  62. /// @param port specifies port number to listen on
  63. /// @param dbconfig Lease manager configuration string. The default
  64. /// of the "memfile" manager is used for testing.
  65. /// @param use_bcast configure sockets to support broadcast messages.
  66. /// @param direct_response_desired specifies if it is desired to
  67. /// use direct V4 traffic.
  68. Dhcpv4Srv(uint16_t port = DHCP4_SERVER_PORT,
  69. const char* dbconfig = "type=memfile",
  70. const bool use_bcast = true,
  71. const bool direct_response_desired = true);
  72. /// @brief Destructor. Used during DHCPv4 service shutdown.
  73. virtual ~Dhcpv4Srv();
  74. /// @brief Main server processing loop.
  75. ///
  76. /// Main server processing loop. Receives incoming packets, verifies
  77. /// their correctness, generates appropriate answer (if needed) and
  78. /// transmits respones.
  79. ///
  80. /// @return true, if being shut down gracefully, fail if experienced
  81. /// critical error.
  82. bool run();
  83. /// @brief Instructs the server to shut down.
  84. void shutdown();
  85. /// @brief Return textual type of packet received by server
  86. ///
  87. /// Returns the name of valid packet received by the server (e.g. DISCOVER).
  88. /// If the packet is unknown - or if it is a valid DHCP packet but not one
  89. /// expected to be received by the server (such as an OFFER), the string
  90. /// "UNKNOWN" is returned. This method is used in debug messages.
  91. ///
  92. /// As the operation of the method does not depend on any server state, it
  93. /// is declared static.
  94. ///
  95. /// @todo: This should be named static Pkt4::getName()
  96. ///
  97. /// @param type DHCPv4 packet type
  98. ///
  99. /// @return Pointer to "const" string containing the packet name.
  100. /// Note that this string is statically allocated and MUST NOT
  101. /// be freed by the caller.
  102. static const char* serverReceivedPacketName(uint8_t type);
  103. ///
  104. /// @name Public accessors returning values required to (re)open sockets.
  105. ///
  106. /// These accessors must be public because sockets are reopened from the
  107. /// static configuration callback handler. This callback handler invokes
  108. /// @c ControlledDhcpv4Srv::openActiveSockets which requires parameters
  109. /// which has to be retrieved from the @c ControlledDhcpv4Srv object.
  110. /// They are retrieved using these public functions
  111. //@{
  112. ///
  113. /// @brief Get UDP port on which server should listen.
  114. ///
  115. /// Typically, server listens on UDP port number 67. Other ports are used
  116. /// for testing purposes only.
  117. ///
  118. /// @return UDP port on which server should listen.
  119. uint16_t getPort() const {
  120. return (port_);
  121. }
  122. /// @brief Return bool value indicating that broadcast flags should be set
  123. /// on sockets.
  124. ///
  125. /// @return A bool value indicating that broadcast should be used (if true).
  126. bool useBroadcast() const {
  127. return (use_bcast_);
  128. }
  129. //@}
  130. /// @brief Open sockets which are marked as active in @c CfgMgr.
  131. ///
  132. /// This function reopens sockets according to the current settings in the
  133. /// Configuration Manager. It holds the list of the interfaces which server
  134. /// should listen on. This function will open sockets on these interfaces
  135. /// only. This function is not exception safe.
  136. ///
  137. /// @param port UDP port on which server should listen.
  138. /// @param use_bcast should broadcast flags be set on the sockets.
  139. static void openActiveSockets(const uint16_t port, const bool use_bcast);
  140. protected:
  141. /// @brief verifies if specified packet meets RFC requirements
  142. ///
  143. /// Checks if mandatory option is really there, that forbidden option
  144. /// is not there, and that client-id or server-id appears only once.
  145. ///
  146. /// @param pkt packet to be checked
  147. /// @param serverid expectation regarding server-id option
  148. /// @throw RFCViolation if any issues are detected
  149. void sanityCheck(const Pkt4Ptr& pkt, RequirementLevel serverid);
  150. /// @brief Processes incoming DISCOVER and returns response.
  151. ///
  152. /// Processes received DISCOVER message and verifies that its sender
  153. /// should be served. In particular, a lease is selected and sent
  154. /// as an offer to a client if it should be served.
  155. ///
  156. /// @param discover DISCOVER message received from client
  157. ///
  158. /// @return OFFER message or NULL
  159. Pkt4Ptr processDiscover(Pkt4Ptr& discover);
  160. /// @brief Processes incoming REQUEST and returns REPLY response.
  161. ///
  162. /// Processes incoming REQUEST message and verifies that its sender
  163. /// should be served. In particular, verifies that requested lease
  164. /// is valid, not expired, not reserved, not used by other client and
  165. /// that requesting client is allowed to use it.
  166. ///
  167. /// Returns ACK message, NAK message, or NULL
  168. ///
  169. /// @param request a message received from client
  170. ///
  171. /// @return ACK or NAK message
  172. Pkt4Ptr processRequest(Pkt4Ptr& request);
  173. /// @brief Stub function that will handle incoming RELEASE messages.
  174. ///
  175. /// In DHCPv4, server does not respond to RELEASE messages, therefore
  176. /// this function does not return anything.
  177. ///
  178. /// @param release message received from client
  179. void processRelease(Pkt4Ptr& release);
  180. /// @brief Stub function that will handle incoming DHCPDECLINE messages.
  181. ///
  182. /// @param decline message received from client
  183. void processDecline(Pkt4Ptr& decline);
  184. /// @brief Stub function that will handle incoming INFORM messages.
  185. ///
  186. /// @param inform message received from client
  187. Pkt4Ptr processInform(Pkt4Ptr& inform);
  188. /// @brief Copies default parameters from client's to server's message
  189. ///
  190. /// Some fields are copied from client's message into server's response,
  191. /// e.g. client HW address, number of hops, transaction-id etc.
  192. ///
  193. /// @param question any message sent by client
  194. /// @param answer any message server is going to send as response
  195. void copyDefaultFields(const Pkt4Ptr& question, Pkt4Ptr& answer);
  196. /// @brief Appends options requested by client.
  197. ///
  198. /// This method assigns options that were requested by client
  199. /// (sent in PRL) or are enforced by server.
  200. ///
  201. /// @param question DISCOVER or REQUEST message from a client.
  202. /// @param msg outgoing message (options will be added here)
  203. void appendRequestedOptions(const Pkt4Ptr& question, Pkt4Ptr& msg);
  204. /// @brief Appends requested vendor options as requested by client.
  205. ///
  206. /// This method is similar to \ref appendRequestedOptions(), but uses
  207. /// vendor options. The major difference is that vendor-options use
  208. /// its own option spaces (there may be more than one distinct set of vendor
  209. /// options, each with unique vendor-id). Vendor options are requested
  210. /// using separate options within their respective vendor-option spaces.
  211. ///
  212. /// @param question DISCOVER or REQUEST message from a client.
  213. /// @param msg outgoing message (options will be added here)
  214. void appendRequestedVendorOptions(const Pkt4Ptr& question, Pkt4Ptr& answer);
  215. /// @brief Assigns a lease and appends corresponding options
  216. ///
  217. /// This method chooses the most appropriate lease for reqesting
  218. /// client and assigning it. Options corresponding to the lease
  219. /// are added to specific message.
  220. ///
  221. /// @param question DISCOVER or REQUEST message from client
  222. /// @param answer OFFER or ACK/NAK message (lease options will be added here)
  223. void assignLease(const Pkt4Ptr& question, Pkt4Ptr& answer);
  224. /// @brief Append basic options if they are not present.
  225. ///
  226. /// This function adds the following basic options if they
  227. /// are not yet added to the message:
  228. /// - Subnet Mask,
  229. /// - Router,
  230. /// - Name Server,
  231. /// - Domain Name.
  232. ///
  233. /// @param question DISCOVER or REQUEST message from a client.
  234. /// @param msg the message to add options to.
  235. void appendBasicOptions(const Pkt4Ptr& question, Pkt4Ptr& msg);
  236. /// @brief Attempts to renew received addresses
  237. ///
  238. /// Attempts to renew existing lease. This typically includes finding a lease that
  239. /// corresponds to the received address. If no such lease is found, a status code
  240. /// response is generated.
  241. ///
  242. /// @param renew client's message asking for renew
  243. /// @param reply server's response (ACK or NAK)
  244. void renewLease(const Pkt4Ptr& renew, Pkt4Ptr& reply);
  245. /// @brief Appends default options to a message
  246. ///
  247. /// @param msg message object (options will be added to it)
  248. /// @param msg_type specifies message type
  249. void appendDefaultOptions(Pkt4Ptr& msg, uint8_t msg_type);
  250. /// @brief Sets remote addresses for outgoing packet.
  251. ///
  252. /// This method sets the local and remote addresses on outgoing packet.
  253. /// The addresses being set depend on the following conditions:
  254. /// - has incoming packet been relayed,
  255. /// - is direct response to a client without address supported,
  256. /// - type of the outgoing packet,
  257. /// - broadcast flag set in the incoming packet.
  258. ///
  259. /// @warning This method does not check whether provided packet pointers
  260. /// are valid. Make sure that pointers are correct before calling this
  261. /// function.
  262. ///
  263. /// @param question instance of a packet received by a server.
  264. /// @param [out] msg response packet which addresses are to be adjusted.
  265. void adjustRemoteAddr(const Pkt4Ptr& question, Pkt4Ptr& msg);
  266. /// @brief Returns server-identifier option
  267. ///
  268. /// @return server-id option
  269. OptionPtr getServerID() { return serverid_; }
  270. /// @brief Sets server-identifier.
  271. ///
  272. /// This method attempts to set server-identifier DUID. It tries to
  273. /// load previously stored IP from configuration. If there is no previously
  274. /// stored server identifier, it will pick up one address from configured
  275. /// and supported network interfaces.
  276. ///
  277. /// @throws isc::Unexpected Failed to obtain server identifier (i.e. no
  278. // previously stored configuration and no network interfaces available)
  279. void generateServerID();
  280. /// @brief attempts to load server-id from a file
  281. ///
  282. /// Tries to load duid from a text file. If the load is successful,
  283. /// it creates server-id option and stores it in serverid_ (to be used
  284. /// later by getServerID()).
  285. ///
  286. /// @param file_name name of the server-id file to load
  287. /// @return true if load was successful, false otherwise
  288. bool loadServerID(const std::string& file_name);
  289. /// @brief attempts to write server-id to a file
  290. /// Tries to write server-id content (stored in serverid_) to a text file.
  291. ///
  292. /// @param file_name name of the server-id file to write
  293. /// @return true if write was successful, false otherwise
  294. bool writeServerID(const std::string& file_name);
  295. /// @brief converts server-id to text
  296. /// Converts content of server-id option to a text representation, e.g.
  297. /// "192.0.2.1"
  298. ///
  299. /// @param opt option that contains server-id
  300. /// @return string representation
  301. static std::string srvidToString(const OptionPtr& opt);
  302. /// @brief Selects a subnet for a given client's packet.
  303. ///
  304. /// @param question client's message
  305. /// @return selected subnet (or NULL if no suitable subnet was found)
  306. isc::dhcp::Subnet4Ptr selectSubnet(const Pkt4Ptr& question);
  307. /// server DUID (to be sent in server-identifier option)
  308. OptionPtr serverid_;
  309. /// indicates if shutdown is in progress. Setting it to true will
  310. /// initiate server shutdown procedure.
  311. volatile bool shutdown_;
  312. /// @brief dummy wrapper around IfaceMgr::receive4
  313. ///
  314. /// This method is useful for testing purposes, where its replacement
  315. /// simulates reception of a packet. For that purpose it is protected.
  316. virtual Pkt4Ptr receivePacket(int timeout);
  317. /// @brief dummy wrapper around IfaceMgr::send()
  318. ///
  319. /// This method is useful for testing purposes, where its replacement
  320. /// simulates transmission of a packet. For that purpose it is protected.
  321. virtual void sendPacket(const Pkt4Ptr& pkt);
  322. /// @brief Implements a callback function to parse options in the message.
  323. ///
  324. /// @param buf a A buffer holding options in on-wire format.
  325. /// @param option_space A name of the option space which holds definitions
  326. /// of to be used to parse options in the packets.
  327. /// @param [out] options A reference to the collection where parsed options
  328. /// will be stored.
  329. /// @return An offset to the first byte after last parsed option.
  330. size_t unpackOptions(const OptionBuffer& buf,
  331. const std::string& option_space,
  332. isc::dhcp::OptionCollection& options);
  333. private:
  334. /// @brief Constructs netmask option based on subnet4
  335. /// @param subnet subnet for which the netmask will be calculated
  336. ///
  337. /// @return Option that contains netmask information
  338. static OptionPtr getNetmaskOption(const Subnet4Ptr& subnet);
  339. /// @brief Allocation Engine.
  340. /// Pointer to the allocation engine that we are currently using
  341. /// It must be a pointer, because we will support changing engines
  342. /// during normal operation (e.g. to use different allocators)
  343. boost::shared_ptr<AllocEngine> alloc_engine_;
  344. uint16_t port_; ///< UDP port number on which server listens.
  345. bool use_bcast_; ///< Should broadcast be enabled on sockets (if true).
  346. /// Indexes for registered hook points
  347. int hook_index_pkt4_receive_;
  348. int hook_index_subnet4_select_;
  349. int hook_index_pkt4_send_;
  350. };
  351. }; // namespace isc::dhcp
  352. }; // namespace isc
  353. #endif // DHCP4_SRV_H