dhcp4_srv.h 36 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875
  1. // Copyright (C) 2011-2017 Internet Systems Consortium, Inc. ("ISC")
  2. //
  3. // This Source Code Form is subject to the terms of the Mozilla Public
  4. // License, v. 2.0. If a copy of the MPL was not distributed with this
  5. // file, You can obtain one at http://mozilla.org/MPL/2.0/.
  6. #ifndef DHCPV4_SRV_H
  7. #define DHCPV4_SRV_H
  8. #include <asiolink/io_service.h>
  9. #include <dhcp/dhcp4.h>
  10. #include <dhcp/pkt4.h>
  11. #include <dhcp/option.h>
  12. #include <dhcp/option_string.h>
  13. #include <dhcp/option4_client_fqdn.h>
  14. #include <dhcp/option_custom.h>
  15. #include <dhcp_ddns/ncr_msg.h>
  16. #include <dhcpsrv/d2_client_mgr.h>
  17. #include <dhcpsrv/subnet.h>
  18. #include <dhcpsrv/alloc_engine.h>
  19. #include <dhcpsrv/cfg_option.h>
  20. #include <hooks/callout_handle.h>
  21. #include <dhcpsrv/daemon.h>
  22. #include <boost/noncopyable.hpp>
  23. #include <iostream>
  24. #include <queue>
  25. // Undefine the macro OPTIONAL which is defined in some operating
  26. // systems but conflicts with a member of the RequirementLevel enum in
  27. // the server class.
  28. #ifdef OPTIONAL
  29. #undef OPTIONAL
  30. #endif
  31. namespace isc {
  32. namespace dhcp {
  33. /// @brief DHCPv4 message exchange.
  34. ///
  35. /// This class represents the DHCPv4 message exchange. The message exchange
  36. /// consists of the single client message, server response to this message
  37. /// and the mechanisms to generate the server's response. The server creates
  38. /// the instance of the @c Dhcpv4Exchange for each inbound message that it
  39. /// accepts for processing.
  40. ///
  41. /// The use of the @c Dhcpv4Exchange object as a central repository of
  42. /// information about the message exchange simplifies the API of the
  43. /// @c Dhcpv4Srv class.
  44. ///
  45. /// Another benefit of using this class is that different methods of the
  46. /// @c Dhcpv4Srv may share information. For example, the constructor of this
  47. /// class selects the subnet and multiple methods of @c Dhcpv4Srv use this
  48. /// subnet, without the need to select it again.
  49. ///
  50. /// @todo This is the initial version of this class. In the future a lot of
  51. /// code from the @c Dhcpv4Srv class will be migrated here.
  52. class Dhcpv4Exchange {
  53. public:
  54. /// @brief Constructor.
  55. ///
  56. /// The constructor selects the subnet for the query and checks for the
  57. /// static host reservations for the client which has sent the message.
  58. /// The information about the reservations is stored in the
  59. /// @c AllocEngine::ClientContext4 object, which can be obtained by
  60. /// calling the @c getContext.
  61. ///
  62. /// @param alloc_engine Pointer to the instance of the Allocation Engine
  63. /// used by the server.
  64. /// @param query Pointer to the client message.
  65. /// @param subnet Pointer to the subnet to which the client belongs.
  66. Dhcpv4Exchange(const AllocEnginePtr& alloc_engine, const Pkt4Ptr& query,
  67. const Subnet4Ptr& subnet);
  68. /// @brief Initializes the instance of the response message.
  69. ///
  70. /// The type of the response depends on the type of the query message.
  71. /// For the DHCPDISCOVER the DHCPOFFER is created. For the DHCPREQUEST
  72. /// and DHCPINFORM the DHCPACK is created. For the DHCPRELEASE the
  73. /// response is not initialized.
  74. void initResponse();
  75. /// @brief Initializes the DHCPv6 part of the response message
  76. ///
  77. /// Called by initResponse() when the query is a DHCP4o6 message
  78. void initResponse4o6();
  79. /// @brief Returns the pointer to the query from the client.
  80. Pkt4Ptr getQuery() const {
  81. return (query_);
  82. }
  83. /// @brief Returns the pointer to the server's response.
  84. ///
  85. /// The returned pointer is NULL if the query type is DHCPRELEASE or DHCPDECLINE.
  86. Pkt4Ptr getResponse() const {
  87. return (resp_);
  88. }
  89. /// @brief Removes the response message by resetting the pointer to NULL.
  90. void deleteResponse() {
  91. resp_.reset();
  92. }
  93. /// @brief Returns the copy of the context for the Allocation engine.
  94. AllocEngine::ClientContext4Ptr getContext() const {
  95. return (context_);
  96. }
  97. /// @brief Returns the configured option list (non-const version)
  98. CfgOptionList& getCfgOptionList() {
  99. return (cfg_option_list_);
  100. }
  101. /// @brief Returns the configured option list (const version)
  102. const CfgOptionList& getCfgOptionList() const {
  103. return (cfg_option_list_);
  104. }
  105. /// @brief Sets reserved values of siaddr, sname and file in the
  106. /// server's response.
  107. void setReservedMessageFields();
  108. private:
  109. /// @brief Copies default parameters from client's to server's message
  110. ///
  111. /// Some fields are copied from client's message into server's response,
  112. /// e.g. client HW address, number of hops, transaction-id etc.
  113. ///
  114. /// @warning This message is called internally by @c initResponse and
  115. /// thus it doesn't check if the resp_ value has been initialized. The
  116. /// calling method is responsible for making sure that @c resp_ is
  117. /// not NULL.
  118. void copyDefaultFields();
  119. /// @brief Copies default options from client's to server's message
  120. ///
  121. /// Some options are copied from client's message into server's response,
  122. /// e.g. Relay Agent Info option, Subnet Selection option etc.
  123. ///
  124. /// @warning This message is called internally by @c initResponse and
  125. /// thus it doesn't check if the resp_ value has been initialized. The
  126. /// calling method is responsible for making sure that @c resp_ is
  127. /// not NULL.
  128. void copyDefaultOptions();
  129. /// @brief Set host identifiers within a context.
  130. ///
  131. /// This method sets an ordered list of host identifier types and
  132. /// values which the server should use to find host reservations.
  133. /// The order of the set is determined by the configuration parameter,
  134. /// host-reservation-identifiers
  135. void setHostIdentifiers();
  136. /// @brief Assigns classes retrieved from host reservation database.
  137. void setReservedClientClasses();
  138. /// @brief Pointer to the allocation engine used by the server.
  139. AllocEnginePtr alloc_engine_;
  140. /// @brief Pointer to the DHCPv4 message sent by the client.
  141. Pkt4Ptr query_;
  142. /// @brief Pointer to the DHCPv4 message to be sent to the client.
  143. Pkt4Ptr resp_;
  144. /// @brief Context for use with allocation engine.
  145. AllocEngine::ClientContext4Ptr context_;
  146. /// @brief Configured option list.
  147. /// @note The configured option list is an *ordered* list of
  148. /// @c CfgOption objects used to append options to the response.
  149. CfgOptionList cfg_option_list_;
  150. };
  151. /// @brief Type representing the pointer to the @c Dhcpv4Exchange.
  152. typedef boost::shared_ptr<Dhcpv4Exchange> Dhcpv4ExchangePtr;
  153. /// @brief DHCPv4 server service.
  154. ///
  155. /// This singleton class represents DHCPv4 server. It contains all
  156. /// top-level methods and routines necessary for server operation.
  157. /// In particular, it instantiates IfaceMgr, loads or generates DUID
  158. /// that is going to be used as server-identifier, receives incoming
  159. /// packets, processes them, manages leases assignment and generates
  160. /// appropriate responses.
  161. ///
  162. /// This class does not support any controlling mechanisms directly.
  163. /// See the derived \ref ControlledDhcpv4Srv class for support for
  164. /// command and configuration updates over msgq.
  165. class Dhcpv4Srv : public Daemon {
  166. private:
  167. /// @brief Pointer to IO service used by the server.
  168. asiolink::IOServicePtr io_service_;
  169. public:
  170. /// @brief defines if certain option may, must or must not appear
  171. typedef enum {
  172. FORBIDDEN,
  173. MANDATORY,
  174. OPTIONAL
  175. } RequirementLevel;
  176. /// @brief Default constructor.
  177. ///
  178. /// Instantiates necessary services, required to run DHCPv4 server.
  179. /// In particular, creates IfaceMgr that will be responsible for
  180. /// network interaction. Will instantiate lease manager, and load
  181. /// old or create new DUID. It is possible to specify alternate
  182. /// port on which DHCPv4 server will listen on. That is mostly useful
  183. /// for testing purposes. The Last two arguments of the constructor
  184. /// should be left at default values for normal server operation.
  185. /// They should be set to 'false' when creating an instance of this
  186. /// class for unit testing because features they enable require
  187. /// root privileges.
  188. ///
  189. /// @param port specifies port number to listen on
  190. /// @param use_bcast configure sockets to support broadcast messages.
  191. /// @param direct_response_desired specifies if it is desired to
  192. /// use direct V4 traffic.
  193. Dhcpv4Srv(uint16_t port = DHCP4_SERVER_PORT,
  194. const bool use_bcast = true,
  195. const bool direct_response_desired = true);
  196. /// @brief Destructor. Used during DHCPv4 service shutdown.
  197. virtual ~Dhcpv4Srv();
  198. /// @brief Returns pointer to the IO service used by the server.
  199. asiolink::IOServicePtr& getIOService() {
  200. return (io_service_);
  201. }
  202. /// @brief returns Kea version on stdout and exit.
  203. /// redeclaration/redefinition. @ref Daemon::getVersion()
  204. static std::string getVersion(bool extended);
  205. /// @brief Main server processing loop.
  206. ///
  207. /// Main server processing loop. Call the processing step routine
  208. /// until shut down.
  209. ///
  210. /// @return true, if being shut down gracefully, never fail.
  211. bool run();
  212. /// @brief Main server processing step.
  213. ///
  214. /// Main server processing step. Receives one incoming packet, calls
  215. /// the processing packet routing and (if necessary) transmits
  216. /// a response.
  217. void run_one();
  218. /// @brief Process a single incoming DHCPv4 packet.
  219. ///
  220. /// It verifies correctness of the passed packet, call per-type processXXX
  221. /// methods, generates appropriate answer.
  222. ///
  223. /// @param query A pointer to the packet to be processed.
  224. /// @param rsp A pointer to the response
  225. void processPacket(Pkt4Ptr& query, Pkt4Ptr& rsp);
  226. /// @brief Instructs the server to shut down.
  227. void shutdown();
  228. ///
  229. /// @name Public accessors returning values required to (re)open sockets.
  230. ///
  231. //@{
  232. ///
  233. /// @brief Get UDP port on which server should listen.
  234. ///
  235. /// Typically, server listens on UDP port number 67. Other ports are used
  236. /// for testing purposes only.
  237. ///
  238. /// @return UDP port on which server should listen.
  239. uint16_t getPort() const {
  240. return (port_);
  241. }
  242. /// @brief Return bool value indicating that broadcast flags should be set
  243. /// on sockets.
  244. ///
  245. /// @return A bool value indicating that broadcast should be used (if true).
  246. bool useBroadcast() const {
  247. return (use_bcast_);
  248. }
  249. //@}
  250. /// @brief Starts DHCP_DDNS client IO if DDNS updates are enabled.
  251. ///
  252. /// If updates are enabled, it instructs the D2ClientMgr singleton to
  253. /// enter send mode. If D2ClientMgr encounters errors it may throw
  254. /// D2ClientError. This method does not catch exceptions.
  255. void startD2();
  256. /// @brief Stops DHCP_DDNS client IO if DDNS updates are enabled.
  257. ///
  258. /// If updates are enabled, it instructs the D2ClientMgr singleton to
  259. /// leave send mode. If D2ClientMgr encounters errors it may throw
  260. /// D2ClientError. This method does not catch exceptions.
  261. void stopD2();
  262. /// @brief Implements the error handler for DHCP_DDNS IO errors
  263. ///
  264. /// Invoked when a NameChangeRequest send to kea-dhcp-ddns completes with
  265. /// a failed status. These are communications errors, not data related
  266. /// failures.
  267. ///
  268. /// This method logs the failure and then suspends all further updates.
  269. /// Updating can only be restored by reconfiguration or restarting the
  270. /// server. There is currently no retry logic so the first IO error that
  271. /// occurs will suspend updates.
  272. /// @todo We may wish to make this more robust or sophisticated.
  273. ///
  274. /// @param result Result code of the send operation.
  275. /// @param ncr NameChangeRequest which failed to send.
  276. virtual void d2ClientErrorHandler(const dhcp_ddns::
  277. NameChangeSender::Result result,
  278. dhcp_ddns::NameChangeRequestPtr& ncr);
  279. protected:
  280. /// @name Functions filtering and sanity-checking received messages.
  281. ///
  282. /// @todo These functions are supposed to be moved to a new class which
  283. /// will manage different rules for accepting and rejecting messages.
  284. /// Perhaps ticket #3116 is a good opportunity to do it.
  285. ///
  286. //@{
  287. /// @brief Checks whether received message should be processed or discarded.
  288. ///
  289. /// This function checks whether received message should be processed or
  290. /// discarded. It should be called on the beginning of message processing
  291. /// (just after the message has been decoded). This message calls a number
  292. /// of other functions which check whether message should be processed,
  293. /// using different criteria.
  294. ///
  295. /// This function should be extended when new criteria for accepting
  296. /// received message have to be implemented. This function is meant to
  297. /// aggregate all early filtering checks on the received message. By having
  298. /// a single function like this, we are avoiding bloat of the server's main
  299. /// loop.
  300. ///
  301. /// @warning This function should remain exception safe.
  302. ///
  303. /// @param query Received message.
  304. ///
  305. /// @return true if the message should be further processed, or false if
  306. /// the message should be discarded.
  307. bool accept(const Pkt4Ptr& query) const;
  308. /// @brief Check if a message sent by directly connected client should be
  309. /// accepted or discarded.
  310. ///
  311. /// This function checks if the received message is from directly connected
  312. /// client. If it is, it checks that it should be processed or discarded.
  313. ///
  314. /// Note that this function doesn't validate all addresses being carried in
  315. /// the message. The primary purpose of this function is to filter out
  316. /// direct messages in the local network for which there is no suitable
  317. /// subnet configured. For example, this function accepts unicast messages
  318. /// because unicasts may be used by clients located in remote networks to
  319. /// to renew existing leases. If their notion of address is wrong, the
  320. /// server will have to sent a NAK, instead of dropping the message.
  321. /// Detailed validation of such messages is performed at later stage of
  322. /// processing.
  323. ///
  324. /// This function accepts the following messages:
  325. /// - all valid relayed messages,
  326. /// - all unicast messages,
  327. /// - all broadcast messages except DHCPINFORM received on the interface
  328. /// for which the suitable subnet exists (is configured).
  329. /// - all DHCPINFORM messages with source address or ciaddr set.
  330. ///
  331. /// @param query Message sent by a client.
  332. ///
  333. /// @return true if message is accepted for further processing, false
  334. /// otherwise.
  335. bool acceptDirectRequest(const Pkt4Ptr& query) const;
  336. /// @brief Check if received message type is valid for the server to
  337. /// process.
  338. ///
  339. /// This function checks that the received message type belongs to
  340. /// the range of types recognized by the server and that the
  341. /// message of this type should be processed by the server.
  342. ///
  343. /// The messages types accepted for processing are:
  344. /// - Discover
  345. /// - Request
  346. /// - Release
  347. /// - Decline
  348. /// - Inform
  349. ///
  350. /// @param query Message sent by a client.
  351. ///
  352. /// @return true if message is accepted for further processing, false
  353. /// otherwise.
  354. bool acceptMessageType(const Pkt4Ptr& query) const;
  355. /// @brief Verifies if the server id belongs to our server.
  356. ///
  357. /// This function checks if the server identifier carried in the specified
  358. /// DHCPv4 message belongs to this server. If the server identifier option
  359. /// is absent or the value carried by this option is equal to one of the
  360. /// server identifiers used by the server, the true is returned. If the
  361. /// server identifier option is present, but it doesn't match any server
  362. /// identifier used by this server, the false value is returned.
  363. ///
  364. /// @param pkt DHCPv4 message which server identifier is to be checked.
  365. ///
  366. /// @return true, if the server identifier is absent or matches one of the
  367. /// server identifiers that the server is using; false otherwise.
  368. bool acceptServerId(const Pkt4Ptr& pkt) const;
  369. //@}
  370. /// @brief Verifies if specified packet meets RFC requirements
  371. ///
  372. /// Checks if mandatory option is really there, that forbidden option
  373. /// is not there, and that client-id or server-id appears only once.
  374. ///
  375. /// @param query Pointer to the client's message.
  376. /// @param serverid expectation regarding server-id option
  377. /// @throw RFCViolation if any issues are detected
  378. static void sanityCheck(const Pkt4Ptr& query, RequirementLevel serverid);
  379. /// @brief Processes incoming DISCOVER and returns response.
  380. ///
  381. /// Processes received DISCOVER message and verifies that its sender
  382. /// should be served. In particular, a lease is selected and sent
  383. /// as an offer to a client if it should be served.
  384. ///
  385. /// @param discover DISCOVER message received from client
  386. ///
  387. /// @return OFFER message or NULL
  388. Pkt4Ptr processDiscover(Pkt4Ptr& discover);
  389. /// @brief Processes incoming REQUEST and returns REPLY response.
  390. ///
  391. /// Processes incoming REQUEST message and verifies that its sender
  392. /// should be served. In particular, verifies that requested lease
  393. /// is valid, not expired, not reserved, not used by other client and
  394. /// that requesting client is allowed to use it.
  395. ///
  396. /// Returns ACK message, NAK message, or NULL
  397. ///
  398. /// @param request a message received from client
  399. ///
  400. /// @return ACK or NAK message
  401. Pkt4Ptr processRequest(Pkt4Ptr& request);
  402. /// @brief Processes incoming DHCPRELEASE messages.
  403. ///
  404. /// In DHCPv4, server does not respond to RELEASE messages, therefore
  405. /// this function does not return anything.
  406. ///
  407. /// @param release message received from client
  408. void processRelease(Pkt4Ptr& release);
  409. /// @brief Process incoming DHCPDECLINE messages.
  410. ///
  411. /// This method processes incoming DHCPDECLINE. In particular, it extracts
  412. /// Requested IP Address option, checks that the address really belongs to
  413. /// the client and if it does, calls @ref declineLease.
  414. ///
  415. /// @param decline message received from client
  416. void processDecline(Pkt4Ptr& decline);
  417. /// @brief Processes incoming DHCPINFORM messages.
  418. ///
  419. /// @param inform message received from client
  420. ///
  421. /// @return DHCPACK to be sent to the client.
  422. Pkt4Ptr processInform(Pkt4Ptr& inform);
  423. /// @brief Build the configured option list
  424. ///
  425. /// @note The configured option list is an *ordered* list of
  426. /// @c CfgOption objects used to append options to the response.
  427. ///
  428. /// @param ex The exchange where the configured option list is cached
  429. void buildCfgOptionList(Dhcpv4Exchange& ex);
  430. /// @brief Appends options requested by client.
  431. ///
  432. /// This method assigns options that were requested by client
  433. /// (sent in PRL) or are enforced by server.
  434. ///
  435. /// @param ex The exchange holding both the client's message and the
  436. /// server's response.
  437. void appendRequestedOptions(Dhcpv4Exchange& ex);
  438. /// @brief Appends requested vendor options as requested by client.
  439. ///
  440. /// This method is similar to \ref appendRequestedOptions(), but uses
  441. /// vendor options. The major difference is that vendor-options use
  442. /// its own option spaces (there may be more than one distinct set of vendor
  443. /// options, each with unique vendor-id). Vendor options are requested
  444. /// using separate options within their respective vendor-option spaces.
  445. ///
  446. /// @param ex The exchange holding both the client's message and the
  447. /// server's response.
  448. void appendRequestedVendorOptions(Dhcpv4Exchange& ex);
  449. /// @brief Assigns a lease and appends corresponding options
  450. ///
  451. /// This method chooses the most appropriate lease for requesting
  452. /// client and assigning it. Options corresponding to the lease
  453. /// are added to specific message.
  454. ///
  455. /// This method may reset the pointer to the response in the @c ex object
  456. /// to indicate that the response should not be sent to the client.
  457. /// The caller must check if the response is is null after calling
  458. /// this method.
  459. ///
  460. /// The response type in the @c ex object may be set to DHCPACK or DHCPNAK.
  461. ///
  462. /// @param ex DHCPv4 exchange holding the client's message to be checked.
  463. void assignLease(Dhcpv4Exchange& ex);
  464. /// @brief Append basic options if they are not present.
  465. ///
  466. /// This function adds the following basic options if they
  467. /// are not yet added to the response message:
  468. /// - Subnet Mask,
  469. /// - Router,
  470. /// - Name Server,
  471. /// - Domain Name.
  472. ///
  473. /// @param ex DHCPv4 exchange holding the client's message to be checked.
  474. void appendBasicOptions(Dhcpv4Exchange& ex);
  475. /// @brief Sets fixed fields of the outgoing packet.
  476. ///
  477. /// If the incoming packets belongs to a class and that class defines
  478. /// next-server, server-hostname or boot-file-name, we need to set the
  479. /// siaddr, sname or filename fields in the outgoing packet. Also, those
  480. /// values can be defined for subnet or in reservations. The values
  481. /// defined in reservation takes precedence over class values, which
  482. /// in turn take precedence over subnet values.
  483. ///
  484. /// @param ex DHCPv4 exchange holding the client's message and the server's
  485. /// response to be adjusted.
  486. void setFixedFields(Dhcpv4Exchange& ex);
  487. /// @brief Processes Client FQDN and Hostname Options sent by a client.
  488. ///
  489. /// Client may send Client FQDN or Hostname option to communicate its name
  490. /// to the server. Server may use this name to perform DNS update for the
  491. /// lease being assigned to a client. If server takes responsibility for
  492. /// updating DNS for a client it may communicate it by sending the Client
  493. /// FQDN or Hostname %Option back to the client. Server select a different
  494. /// name than requested by a client to update DNS. In such case, the server
  495. /// stores this different name in its response.
  496. ///
  497. /// Client should not send both Client FQDN and Hostname options. However,
  498. /// if client sends both options, server should prefer Client FQDN option
  499. /// and ignore the Hostname option. If Client FQDN option is not present,
  500. /// the Hostname option is processed.
  501. ///
  502. /// The Client FQDN %Option is processed by this function as described in
  503. /// RFC4702.
  504. ///
  505. /// In response to a Hostname %Option sent by a client, the server may send
  506. /// Hostname option with the same or different hostname. If different
  507. /// hostname is sent, it is an indication to the client that server has
  508. /// overridden the client's preferred name and will rather use this
  509. /// different name to update DNS. However, since Hostname option doesn't
  510. /// carry an information whether DNS update will be carried by the server
  511. /// or not, the client is responsible for checking whether DNS update
  512. /// has been performed.
  513. ///
  514. /// After successful processing options stored in the first parameter,
  515. /// this function may add Client FQDN or Hostname option to the response
  516. /// message. In some cases, server may cease to add any options to the
  517. /// response, i.e. when server doesn't support DNS updates.
  518. ///
  519. /// This function does not throw. It simply logs the debug message if the
  520. /// processing of the FQDN or Hostname failed.
  521. ///
  522. /// @param ex The exchange holding both the client's message and the
  523. /// server's response.
  524. void processClientName(Dhcpv4Exchange& ex);
  525. /// @brief this is a prefix added to the contend of vendor-class option
  526. ///
  527. /// If incoming packet has a vendor class option, its content is
  528. /// prepended with this prefix and then interpreted as a class.
  529. /// For example, a packet that sends vendor class with value of "FOO"
  530. /// will cause the packet to be assigned to class VENDOR_CLASS_FOO.
  531. static const std::string VENDOR_CLASS_PREFIX;
  532. private:
  533. /// @brief Process Client FQDN %Option sent by a client.
  534. ///
  535. /// This function is called by the @c Dhcpv4Srv::processClientName when
  536. /// the client has sent the FQDN option in its message to the server.
  537. /// It comprises the actual logic to parse the FQDN option and prepare
  538. /// the FQDN option to be sent back to the client in the server's
  539. /// response.
  540. ///
  541. /// @param ex The exchange holding both the client's message and the
  542. /// server's response.
  543. void processClientFqdnOption(Dhcpv4Exchange& ex);
  544. /// @brief Process Hostname %Option sent by a client.
  545. ///
  546. /// This method is called by the @c Dhcpv4Srv::processClientName to
  547. /// create an instance of the Hostname option to be returned to the
  548. /// client. If this instance is created it is included in the response
  549. /// message within the @c Dhcpv4Exchange object passed as an argument.
  550. ///
  551. /// The Hostname option instance is created if the client has included
  552. /// Hostname option in its query to the server or if the client has
  553. /// included Hostname option code in the Parameter Request List option.
  554. /// In the former case, the server can use the Hostname supplied by the
  555. /// client or replace it with a new hostname, depending on the server's
  556. /// configuration. A reserved hostname takes precedence over a hostname
  557. /// supplied by the client or auto generated hostname.
  558. ///
  559. /// If the 'qualifying-suffix' parameter is specified, its value is used
  560. /// to qualify a hostname. For example, if the host reservation contains
  561. /// a hostname 'marcin-laptop', and the qualifying suffix is
  562. /// 'example.isc.org', the hostname returned to the client will be
  563. /// 'marcin-laptop.example.isc.org'. If the 'qualifying-suffix' is not
  564. /// specified (empty), the reserved hostname is returned to the client
  565. /// unqualified.
  566. ///
  567. /// The 'qualifying-suffix' value is also used to qualify the hostname
  568. /// supplied by the client, when this hostname is unqualified,
  569. /// e.g. 'laptop-x'. If the supplied hostname is qualified, e.g.
  570. /// 'laptop-x.example.org', the qualifying suffix will not be appended
  571. /// to it.
  572. ///
  573. /// @param ex The exchange holding both the client's message and the
  574. /// server's response.
  575. void processHostnameOption(Dhcpv4Exchange& ex);
  576. /// @public
  577. /// @brief Marks lease as declined.
  578. ///
  579. /// This method moves a lease to declined state with all the steps involved:
  580. /// - trigger DNS removal (if necessary)
  581. /// - disassociate the client information
  582. /// - update lease in the database (switch to DECLINED state)
  583. /// - increase necessary statistics
  584. /// - call lease4_decline hook
  585. ///
  586. /// @param lease lease to be declined
  587. /// @param decline client's message
  588. void declineLease(const Lease4Ptr& lease, const Pkt4Ptr& decline);
  589. protected:
  590. /// @brief Creates NameChangeRequests which correspond to the lease
  591. /// which has been acquired.
  592. ///
  593. /// If this function is called when an existing lease is renewed, it
  594. /// may generate NameChangeRequest to remove existing DNS entries which
  595. /// correspond to the old lease instance. This function may cease to
  596. /// generate NameChangeRequests if the notion of the client's FQDN hasn't
  597. /// changed between an old and new lease.
  598. ///
  599. /// @param lease A pointer to the new lease which has been acquired.
  600. /// @param old_lease A pointer to the instance of the old lease which has
  601. /// been replaced by the new lease passed in the first argument. The NULL
  602. /// value indicates that the new lease has been allocated, rather than
  603. /// lease being renewed.
  604. void createNameChangeRequests(const Lease4Ptr& lease,
  605. const Lease4Ptr& old_lease);
  606. /// @brief Attempts to renew received addresses
  607. ///
  608. /// Attempts to renew existing lease. This typically includes finding a lease that
  609. /// corresponds to the received address. If no such lease is found, a status code
  610. /// response is generated.
  611. ///
  612. /// @param renew client's message asking for renew
  613. /// @param reply server's response (ACK or NAK)
  614. void renewLease(const Pkt4Ptr& renew, Pkt4Ptr& reply);
  615. /// @brief Adds server identifier option to the server's response.
  616. ///
  617. /// This method adds a server identifier to the DHCPv4 message. It expects
  618. /// that the local (source) address is set for this message. If address is
  619. /// not set, it will throw an exception. This method also expects that the
  620. /// server identifier option is not present in the specified message.
  621. /// Otherwise, it will throw an exception on attempt to add a duplicate
  622. /// server identifier option.
  623. ///
  624. /// @note This method doesn't throw exceptions by itself but the underlying
  625. /// classes being used my throw. The reason for this method to not sanity
  626. /// check the specified message is that it is meant to be called internally
  627. /// by the @c Dhcpv4Srv class.
  628. ///
  629. /// @note This method is static because it is not dependent on the class
  630. /// state.
  631. ///
  632. /// @param ex The exchange holding both the client's message and the
  633. /// server's response.
  634. static void appendServerID(Dhcpv4Exchange& ex);
  635. /// @brief Set IP/UDP and interface parameters for the DHCPv4 response.
  636. ///
  637. /// This method sets the following parameters for the DHCPv4 message being
  638. /// sent to a client:
  639. /// - client unicast or a broadcast address,
  640. /// - client or relay port,
  641. /// - server address,
  642. /// - server port,
  643. /// - name and index of the interface which is to be used to send the
  644. /// message.
  645. ///
  646. /// Internally it calls the @c Dhcpv4Srv::adjustRemoteAddr to figure
  647. /// out the destination address (client unicast address or broadcast
  648. /// address).
  649. ///
  650. /// The destination port is always DHCPv4 client (68) or relay (67) port,
  651. /// depending if the response will be sent directly to a client.
  652. ///
  653. /// The source port is always set to DHCPv4 server port (67).
  654. ///
  655. /// The interface selected for the response is always the same as the
  656. /// one through which the query has been received.
  657. ///
  658. /// The source address for the response is the IPv4 address assigned to
  659. /// the interface being used to send the response. This function uses
  660. /// @c IfaceMgr to get the socket bound to the IPv4 address on the
  661. /// particular interface.
  662. ///
  663. /// @note This method is static because it is not dependent on the class
  664. /// state.
  665. ///
  666. /// @param ex The exchange holding both the client's message and the
  667. /// server's response.
  668. static void adjustIfaceData(Dhcpv4Exchange& ex);
  669. /// @brief Sets remote addresses for outgoing packet.
  670. ///
  671. /// This method sets the local and remote addresses on outgoing packet.
  672. /// The addresses being set depend on the following conditions:
  673. /// - has incoming packet been relayed,
  674. /// - is direct response to a client without address supported,
  675. /// - type of the outgoing packet,
  676. /// - broadcast flag set in the incoming packet.
  677. ///
  678. /// @warning This method does not check whether provided packet pointers
  679. /// are valid. Make sure that pointers are correct before calling this
  680. /// function.
  681. ///
  682. /// @note This method is static because it is not dependent on the class
  683. /// state.
  684. ///
  685. /// @param ex The exchange holding both the client's message and the
  686. /// server's response.
  687. static void adjustRemoteAddr(Dhcpv4Exchange& ex);
  688. /// @brief converts server-id to text
  689. /// Converts content of server-id option to a text representation, e.g.
  690. /// "192.0.2.1"
  691. ///
  692. /// @param opt option that contains server-id
  693. /// @return string representation
  694. static std::string srvidToString(const OptionPtr& opt);
  695. /// @brief Selects a subnet for a given client's packet.
  696. ///
  697. /// @param query client's message
  698. /// @return selected subnet (or NULL if no suitable subnet was found)
  699. isc::dhcp::Subnet4Ptr selectSubnet(const Pkt4Ptr& query) const;
  700. /// @brief Selects a subnet for a given client's DHCP4o6 packet.
  701. ///
  702. /// @param query client's message
  703. /// @return selected subnet (or NULL if no suitable subnet was found)
  704. isc::dhcp::Subnet4Ptr selectSubnet4o6(const Pkt4Ptr& query) const;
  705. /// indicates if shutdown is in progress. Setting it to true will
  706. /// initiate server shutdown procedure.
  707. volatile bool shutdown_;
  708. /// @brief dummy wrapper around IfaceMgr::receive4
  709. ///
  710. /// This method is useful for testing purposes, where its replacement
  711. /// simulates reception of a packet. For that purpose it is protected.
  712. virtual Pkt4Ptr receivePacket(int timeout);
  713. /// @brief dummy wrapper around IfaceMgr::send()
  714. ///
  715. /// This method is useful for testing purposes, where its replacement
  716. /// simulates transmission of a packet. For that purpose it is protected.
  717. virtual void sendPacket(const Pkt4Ptr& pkt);
  718. /// @brief Assigns incoming packet to zero or more classes.
  719. ///
  720. /// @note This is done in two phases: first the content of the
  721. /// vendor-class-identifier option is used as a class, by
  722. /// calling @ref classifyByVendor(). Second classification match
  723. /// expressions are evaluated. The resulting classes will be stored
  724. /// in the packet (see @ref isc::dhcp::Pkt4::classes_ and
  725. /// @ref isc::dhcp::Pkt4::inClass).
  726. ///
  727. /// @param pkt packet to be classified
  728. void classifyPacket(const Pkt4Ptr& pkt);
  729. /// @brief Allocation Engine.
  730. /// Pointer to the allocation engine that we are currently using
  731. /// It must be a pointer, because we will support changing engines
  732. /// during normal operation (e.g. to use different allocators)
  733. boost::shared_ptr<AllocEngine> alloc_engine_;
  734. private:
  735. /// @public
  736. /// @brief Assign class using vendor-class-identifier option
  737. ///
  738. /// @note This is the first part of @ref classifyPacket
  739. ///
  740. /// @param pkt packet to be classified
  741. void classifyByVendor(const Pkt4Ptr& pkt);
  742. /// @private
  743. /// @brief Constructs netmask option based on subnet4
  744. /// @param subnet subnet for which the netmask will be calculated
  745. ///
  746. /// @return Option that contains netmask information
  747. static OptionPtr getNetmaskOption(const Subnet4Ptr& subnet);
  748. uint16_t port_; ///< UDP port number on which server listens.
  749. bool use_bcast_; ///< Should broadcast be enabled on sockets (if true).
  750. public:
  751. /// Class methods for DHCPv4-over-DHCPv6 handler
  752. /// @brief Updates statistics for received packets
  753. /// @param query packet received
  754. static void processStatsReceived(const Pkt4Ptr& query);
  755. /// @brief Updates statistics for transmitted packets
  756. /// @param response packet transmitted
  757. static void processStatsSent(const Pkt4Ptr& response);
  758. /// @brief Returns the index for "buffer4_receive" hook point
  759. /// @return the index for "buffer4_receive" hook point
  760. static int getHookIndexBuffer4Receive();
  761. /// @brief Returns the index for "pkt4_receive" hook point
  762. /// @return the index for "pkt4_receive" hook point
  763. static int getHookIndexPkt4Receive();
  764. /// @brief Returns the index for "subnet4_select" hook point
  765. /// @return the index for "subnet4_select" hook point
  766. static int getHookIndexSubnet4Select();
  767. /// @brief Returns the index for "lease4_release" hook point
  768. /// @return the index for "lease4_release" hook point
  769. static int getHookIndexLease4Release();
  770. /// @brief Returns the index for "pkt4_send" hook point
  771. /// @return the index for "pkt4_send" hook point
  772. static int getHookIndexPkt4Send();
  773. /// @brief Returns the index for "buffer4_send" hook point
  774. /// @return the index for "buffer4_send" hook point
  775. static int getHookIndexBuffer4Send();
  776. /// @brief Returns the index for "lease4_decline" hook point
  777. /// @return the index for "lease4_decline" hook point
  778. static int getHookIndexLease4Decline();
  779. };
  780. }; // namespace isc::dhcp
  781. }; // namespace isc
  782. #endif // DHCP4_SRV_H