]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
[master] Merge branch 'trac2984' (additional DHCPv6 hooks)
authorTomek Mrugalski <tomasz@isc.org>
Fri, 9 Aug 2013 15:10:08 +0000 (17:10 +0200)
committerTomek Mrugalski <tomasz@isc.org>
Fri, 9 Aug 2013 15:10:08 +0000 (17:10 +0200)
Conflicts:
ChangeLog
src/bin/dhcp6/dhcp6_srv.cc

1  2 
ChangeLog
src/bin/dhcp6/dhcp6_hooks.dox
src/bin/dhcp6/dhcp6_srv.cc
src/lib/dhcp/pkt6.h
src/lib/dhcp/tests/pkt6_unittest.cc

diff --cc ChangeLog
index 35ce15084adecc695a6196c0785d83f8df5b761d,8ac46c95b2c49a09b2a4c6a74a1300345597f294..53e650c7cd6c3072afb89ab42870cf3130c253b0
+++ b/ChangeLog
@@@ -1,67 -1,10 +1,72 @@@
- 655.  [func]  tmark
 -6XX.  [func]          tomek
++656.  [func]          tomek
+       Additional hooks (buffer6_receive, lease6_renew,
+       lease6_release, buffer6_send) added to the DHCPv6 server.
 -      (Trac #2984, git ABCD)
++      (Trac #2984, git 540dd0449121094a56f294c500c2ed811f6016b6)
++
++655.  [func]          tmark
 +      Added D2UpdateMgr class to b10-dhcp-ddns. This class is the b10-dhcp-ddns
 +      task master, instantiating and supervising transactions that carry out the
 +      DNS updates needed to fulfill the requests (NameChangeRequests) received
 +      from b10-dhcp-ddns clients (e.g. DHCP servers).
-       (Trac #3059 git d72675617d6b60e3eb6160305738771f015849ba) 
++      (Trac #3059 git d72675617d6b60e3eb6160305738771f015849ba)
 +
 +654.  [bug]           stephen
 +      Always clear "skip" flag before calling any callouts on a hook.
 +      (Trac# 3050, git ff0b9b45869b1d9a4b99e785fbce421e184c2e93)
 +
 +653.  [func]          tmark
 +      Added initial implementation of D2QueueMgr to
 +      b10-dhcp-ddns.  This class manages the receipt and
 +      queueing of requests received by b10-dhcp-ddns from
 +      its clients (e.g. DHCP servers)
 +      (Trac# 3052, git a970f6c5255e000c053a2dc47926cea7cec2761c)
 +
 +652.  [doc]           stephen
 +      Added the "Hook Developer's Guide" to the BIND 10 developer
 +      documentation.
 +      (Trac# 2982, git 26a805c7e49a9ec85ee825f179cda41a2358f4c6)
 +
 +651.  [bug]           muks
 +      A race condition when creating cmdctl certificates caused corruption
 +      of these certificates in rare cases. This has now been fixed.
 +      (Trac# 2962, git 09f557d871faef090ed444ebeee7f13e142184a0)
 +
 +650.  [func]          muks
 +      The DomainTree rebalancing code has been updated to be more
 +      understandable. This ChangeLog entry is made just to make a note
 +      of this change. The change should not cause any observable
 +      difference whatsoever.
 +      (Trac# 2811, git 7c0bad1643af13dedf9356e9fb3a51264b7481de)
 +
 +649.  [func]          muks
 +      The default b10-xfrout also_notify port has been changed from
 +      0 to 53.
 +      (Trac# 2925, git 8acbf043daf590a9f2ad003e715cd4ffb0b3f979)
 +
 +648.  [func]          tmark
 +      Moved classes pertaining to sending and receiving
 +      NameChangeRequests from src/bin/d2 into their own library,
 +      libdhcp_ddns, in src/lib/dhcp_ddns.  This allows the
 +      classes to be shared between DHDCP-DDNS and its clients,
 +      such as the DHCP servers.
 +      (Trac# 3065, git 3d39bccaf3f0565152ef73ec3e2cd03e77572c56)
 +
 +647.  [func]          tmark
 +      Added initial implementation of classes for sending
 +      and receiving NameChangeRequests between DHCP-DDNS
 +      and its clients such as DHCP. This includes both
 +      abstract classes and a derivation which traffics
 +      requests across UDP sockets.
 +      (Trac #3008, git b54530b4539cec4476986442e72c047dddba7b48)
 +
 +646.  [func]          stephen
 +      Extended the hooks framework to add a "validate libraries" function.
 +      This will be used to check libraries specified during BIND 10
 +      configuration.
 +      (Trac #3054, git 0f845ed94f462dee85b67f056656b2a197878b04)
  
  645.  [func]          tomek
-       Added initial set of hooks (pk4_receive, subnet4_select,
+       Added initial set of hooks (pkt4_receive, subnet4_select,
        lease4_select, pkt4_send) to the DHCPv6 server.
        (Trac #2994, git be65cfba939a6a7abd3c93931ce35c33d3e8247b)
  
Simple merge
index b2ba67bc1c2b6cccd0be11983a4b511ef2ccca28,1d028f6f928d52d6e28ecf27f695077a057bbc7c..90c37165fc8d0d96988c69eaf40f6757cd7770b1
@@@ -191,148 -192,230 +192,238 @@@ bool Dhcpv6Srv::run() 
              LOG_ERROR(dhcp6_logger, DHCP6_PACKET_RECEIVE_FAIL).arg(e.what());
          }
  
-         if (query) {
-             if (!query->unpack()) {
-                 LOG_DEBUG(dhcp6_logger, DBG_DHCP6_DETAIL,
-                           DHCP6_PACKET_PARSE_FAIL);
-                 continue;
-             }
-             LOG_DEBUG(dhcp6_logger, DBG_DHCP6_DETAIL, DHCP6_PACKET_RECEIVED)
-                       .arg(query->getName());
-             LOG_DEBUG(dhcp6_logger, DBG_DHCP6_DETAIL_DATA, DHCP6_QUERY_DATA)
-                       .arg(static_cast<int>(query->getType()))
-                       .arg(query->getBuffer().getLength())
-                       .arg(query->toText());
-             // Let's execute all callouts registered for packet_received
-             if (HooksManager::getHooksManager().calloutsPresent(hook_index_pkt6_receive_)) {
-                 CalloutHandlePtr callout_handle = getCalloutHandle(query);
+         // Timeout may be reached or signal received, which breaks select() with no packet received
+         if (!query) {
+             continue;
+         }
  
-                 // Delete previously set arguments
-                 callout_handle->deleteAllArguments();
+         bool skip_unpack = false;
  
-                 // Pass incoming packet as argument
-                 callout_handle->setArgument("query6", query);
+         // The packet has just been received so contains the uninterpreted wire
+         // data; execute callouts registered for buffer6_receive.
+         if (HooksManager::getHooksManager().calloutsPresent(Hooks.hook_index_buffer6_receive_)) {
+             CalloutHandlePtr callout_handle = getCalloutHandle(query);
  
-                 // Call callouts
-                 HooksManager::callCallouts(hook_index_pkt6_receive_, *callout_handle);
+             // Delete previously set arguments
+             callout_handle->deleteAllArguments();
  
-                 // Callouts decided to skip the next processing step. The next
-                 // processing step would to process the packet, so skip at this
-                 // stage means drop.
-                 if (callout_handle->getSkip()) {
-                     LOG_DEBUG(dhcp6_logger, DBG_DHCP6_HOOKS, DHCP6_HOOK_PACKET_RCVD_SKIP);
-                     continue;
-                 }
+             // Pass incoming packet as argument
+             callout_handle->setArgument("query6", query);
  
-                 callout_handle->getArgument("query6", query);
+             // Call callouts
+             HooksManager::callCallouts(Hooks.hook_index_buffer6_receive_, *callout_handle);
+             // Callouts decided to skip the next processing step. The next
+             // processing step would to parse the packet, so skip at this
+             // stage means that callouts did the parsing already, so server
+             // should skip parsing.
+             if (callout_handle->getSkip()) {
+                 LOG_DEBUG(dhcp6_logger, DBG_DHCP6_HOOKS, DHCP6_HOOK_BUFFER_RCVD_SKIP);
+                 skip_unpack = true;
              }
  
-             try {
-                 switch (query->getType()) {
-                 case DHCPV6_SOLICIT:
-                     rsp = processSolicit(query);
-                     break;
+             callout_handle->getArgument("query6", query);
+         }
  
-                 case DHCPV6_REQUEST:
-                     rsp = processRequest(query);
-                     break;
+         // Unpack the packet information unless the buffer6_receive callouts
+         // indicated they did it
+         if (!skip_unpack) {
+             if (!query->unpack()) {
+                 LOG_DEBUG(dhcp6_logger, DBG_DHCP6_DETAIL,
+                           DHCP6_PACKET_PARSE_FAIL);
+                 continue;
+             }
+         }
+         LOG_DEBUG(dhcp6_logger, DBG_DHCP6_DETAIL, DHCP6_PACKET_RECEIVED)
+             .arg(query->getName());
+         LOG_DEBUG(dhcp6_logger, DBG_DHCP6_DETAIL_DATA, DHCP6_QUERY_DATA)
+             .arg(static_cast<int>(query->getType()))
+             .arg(query->getBuffer().getLength())
+             .arg(query->toText());
+         // At this point the information in the packet has been unpacked into
+         // the various packet fields and option objects has been cretated.
+         // Execute callouts registered for packet6_receive.
+         if (HooksManager::getHooksManager().calloutsPresent(Hooks.hook_index_pkt6_receive_)) {
+             CalloutHandlePtr callout_handle = getCalloutHandle(query);
+             // Delete previously set arguments
+             callout_handle->deleteAllArguments();
+             // Pass incoming packet as argument
+             callout_handle->setArgument("query6", query);
+             // Call callouts
+             HooksManager::callCallouts(Hooks.hook_index_pkt6_receive_, *callout_handle);
+             // Callouts decided to skip the next processing step. The next
+             // processing step would to process the packet, so skip at this
+             // stage means drop.
+             if (callout_handle->getSkip()) {
+                 LOG_DEBUG(dhcp6_logger, DBG_DHCP6_HOOKS, DHCP6_HOOK_PACKET_RCVD_SKIP);
+                 continue;
+             }
  
-                 case DHCPV6_RENEW:
-                     rsp = processRenew(query);
-                     break;
+             callout_handle->getArgument("query6", query);
+         }
  
-                 case DHCPV6_REBIND:
-                     rsp = processRebind(query);
+         try {
+             switch (query->getType()) {
+             case DHCPV6_SOLICIT:
+                 rsp = processSolicit(query);
                      break;
  
-                 case DHCPV6_CONFIRM:
-                     rsp = processConfirm(query);
-                     break;
+             case DHCPV6_REQUEST:
+                 rsp = processRequest(query);
+                 break;
+             case DHCPV6_RENEW:
+                 rsp = processRenew(query);
+                 break;
+             case DHCPV6_REBIND:
+                 rsp = processRebind(query);
+                 break;
+             case DHCPV6_CONFIRM:
+                 rsp = processConfirm(query);
+                 break;
+             case DHCPV6_RELEASE:
+                 rsp = processRelease(query);
+                 break;
+             case DHCPV6_DECLINE:
+                 rsp = processDecline(query);
+                 break;
+             case DHCPV6_INFORMATION_REQUEST:
+                 rsp = processInfRequest(query);
+                 break;
+             default:
+                 // We received a packet type that we do not recognize.
+                 LOG_DEBUG(dhcp6_logger, DBG_DHCP6_BASIC, DHCP6_UNKNOWN_MSG_RECEIVED)
+                     .arg(static_cast<int>(query->getType()))
+                     .arg(query->getIface());
+                 // Only action is to output a message if debug is enabled,
+                 // and that will be covered by the debug statement before
+                 // the "switch" statement.
+                 ;
+             }
  
-                 case DHCPV6_RELEASE:
-                     rsp = processRelease(query);
-                     break;
+         } catch (const RFCViolation& e) {
+             LOG_DEBUG(dhcp6_logger, DBG_DHCP6_BASIC, DHCP6_REQUIRED_OPTIONS_CHECK_FAIL)
+                 .arg(query->getName())
+                 .arg(query->getRemoteAddr().toText())
+                 .arg(e.what());
+         } catch (const isc::Exception& e) {
+             // Catch-all exception (at least for ones based on the isc
+             // Exception class, which covers more or less all that
+             // are explicitly raised in the BIND 10 code).  Just log
+             // the problem and ignore the packet. (The problem is logged
+             // as a debug message because debug is disabled by default -
+             // it prevents a DDOS attack based on the sending of problem
+             // packets.)
+             LOG_DEBUG(dhcp6_logger, DBG_DHCP6_BASIC, DHCP6_PACKET_PROCESS_FAIL)
+                 .arg(query->getName())
+                 .arg(query->getRemoteAddr().toText())
+                 .arg(e.what());
+         }
  
-                 case DHCPV6_DECLINE:
-                     rsp = processDecline(query);
-                     break;
+         if (rsp) {
+             rsp->setRemoteAddr(query->getRemoteAddr());
+             rsp->setLocalAddr(query->getLocalAddr());
+             rsp->setRemotePort(DHCP6_CLIENT_PORT);
+             rsp->setLocalPort(DHCP6_SERVER_PORT);
+             rsp->setIndex(query->getIndex());
+             rsp->setIface(query->getIface());
+             // Specifies if server should do the packing
+             bool skip_pack = false;
+             // Server's reply packet now has all options and fields set.
+             // Options are represented by individual objects, but the
+             // output wire data has not been prepared yet.
+             // Execute all callouts registered for packet6_send
+             if (HooksManager::getHooksManager().calloutsPresent(Hooks.hook_index_pkt6_send_)) {
+                 CalloutHandlePtr callout_handle = getCalloutHandle(query);
  
-                 case DHCPV6_INFORMATION_REQUEST:
-                     rsp = processInfRequest(query);
-                     break;
+                 // Delete all previous arguments
+                 callout_handle->deleteAllArguments();
+                 // Set our response
+                 callout_handle->setArgument("response6", rsp);
  
-                 default:
-                     // Only action is to output a message if debug is enabled,
-                     // and that will be covered by the debug statement before
-                     // the "switch" statement.
-                     ;
+                 // Call all installed callouts
+                 HooksManager::callCallouts(Hooks.hook_index_pkt6_send_, *callout_handle);
+                 // Callouts decided to skip the next processing step. The next
+                 // processing step would to pack the packet (create wire data).
+                 // That step will be skipped if any callout sets skip flag.
+                 // It essentially means that the callout already did packing,
+                 // so the server does not have to do it again.
+                 if (callout_handle->getSkip()) {
+                     LOG_DEBUG(dhcp6_logger, DBG_DHCP6_HOOKS, DHCP6_HOOK_PACKET_SEND_SKIP);
+                     skip_pack = true;
                  }
+             }
  
-             } catch (const RFCViolation& e) {
-                 LOG_DEBUG(dhcp6_logger, DBG_DHCP6_BASIC, DHCP6_REQUIRED_OPTIONS_CHECK_FAIL)
-                     .arg(query->getName())
-                     .arg(query->getRemoteAddr().toText())
-                     .arg(e.what());
+             LOG_DEBUG(dhcp6_logger, DBG_DHCP6_DETAIL_DATA,
+                       DHCP6_RESPONSE_DATA)
+                 .arg(static_cast<int>(rsp->getType())).arg(rsp->toText());
  
-             } catch (const isc::Exception& e) {
-                 // Catch-all exception (at least for ones based on the isc
-                 // Exception class, which covers more or less all that
-                 // are explicitly raised in the BIND 10 code).  Just log
-                 // the problem and ignore the packet. (The problem is logged
-                 // as a debug message because debug is disabled by default -
-                 // it prevents a DDOS attack based on the sending of problem
-                 // packets.)
-                 LOG_DEBUG(dhcp6_logger, DBG_DHCP6_BASIC, DHCP6_PACKET_PROCESS_FAIL)
-                     .arg(query->getName())
-                     .arg(query->getRemoteAddr().toText())
-                     .arg(e.what());
+             if (!skip_pack) {
 -                if (!rsp->pack()) {
 -                    LOG_ERROR(dhcp6_logger, DHCP6_PACK_FAIL);
++                try {
++                    rsp->pack();
++                } catch (const std::exception& e) {
++                    LOG_ERROR(dhcp6_logger, DHCP6_PACK_FAIL)
++                        .arg(e.what());
+                     continue;
+                 }
              }
  
-             if (rsp) {
-                 rsp->setRemoteAddr(query->getRemoteAddr());
-                 rsp->setLocalAddr(query->getLocalAddr());
-                 rsp->setRemotePort(DHCP6_CLIENT_PORT);
-                 rsp->setLocalPort(DHCP6_SERVER_PORT);
-                 rsp->setIndex(query->getIndex());
-                 rsp->setIface(query->getIface());
+             try {
  
-                 // Execute all callouts registered for packet6_send
-                 if (HooksManager::getHooksManager().calloutsPresent(hook_index_pkt6_send_)) {
+                 // Now all fields and options are constructed into output wire buffer.
+                 // Option objects modification does not make sense anymore. Hooks
+                 // can only manipulate wire buffer at this stage.
+                 // Let's execute all callouts registered for buffer6_send
+                 if (HooksManager::getHooksManager().calloutsPresent(Hooks.hook_index_buffer6_send_)) {
                      CalloutHandlePtr callout_handle = getCalloutHandle(query);
  
-                     // Delete all previous arguments
+                     // Delete previously set arguments
                      callout_handle->deleteAllArguments();
  
-                     // Set our response
+                     // Pass incoming packet as argument
                      callout_handle->setArgument("response6", rsp);
-                     // Call all installed callouts
-                     HooksManager::callCallouts(hook_index_pkt6_send_, *callout_handle);
+                     
+                     // Call callouts
+                     HooksManager::callCallouts(Hooks.hook_index_buffer6_send_, *callout_handle);
+                     
                      // Callouts decided to skip the next processing step. The next
-                     // processing step would to send the packet, so skip at this
-                     // stage means "drop response".
+                     // processing step would to parse the packet, so skip at this
+                     // stage means drop.
                      if (callout_handle->getSkip()) {
-                         LOG_DEBUG(dhcp6_logger, DBG_DHCP6_HOOKS, DHCP6_HOOK_PACKET_SEND_SKIP);
+                         LOG_DEBUG(dhcp6_logger, DBG_DHCP6_HOOKS, DHCP6_HOOK_BUFFER_SEND_SKIP);
                          continue;
                      }
+                     
+                     callout_handle->getArgument("response6", rsp);
                  }
 -                
 +
 +                LOG_DEBUG(dhcp6_logger, DBG_DHCP6_DETAIL_DATA,
 +                          DHCP6_RESPONSE_DATA)
 +                    .arg(static_cast<int>(rsp->getType())).arg(rsp->toText());
 +
-                 try {
-                     rsp->pack();
-                     sendPacket(rsp);
-                 } catch (const std::exception& e) {
-                     LOG_ERROR(dhcp6_logger, DHCP6_PACKET_SEND_FAIL)
-                               .arg(e.what());
-                 }
+                 sendPacket(rsp);
+             } catch (const std::exception& e) {
 -                LOG_ERROR(dhcp6_logger, DHCP6_PACKET_SEND_FAIL).arg(e.what());
++                LOG_ERROR(dhcp6_logger, DHCP6_PACKET_SEND_FAIL)
++                    .arg(e.what());
              }
 -        } 
 +        }
      }
  
      return (true);
Simple merge
Simple merge