]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
[1230] Generic DHCPv6 server clean-up:
authorTomek Mrugalski <tomasz@isc.org>
Tue, 27 Dec 2011 13:48:29 +0000 (14:48 +0100)
committerTomek Mrugalski <tomasz@isc.org>
Tue, 27 Dec 2011 13:48:29 +0000 (14:48 +0100)
- DHCPv6 server now sends DNS-SERVERS option
- refactored processSolicit(), processRequest()
- added appendDefaultOptions(), appendRequestedOptions(), assignLeases()
- many parameters are now const &
- const HARDCODDED_* parameters added for similar customizations
- IfaceMgr::openSockets6() now skips loopback, down, or unicast interfaces.

src/bin/dhcp6/dhcp6_srv.cc
src/bin/dhcp6/dhcp6_srv.h
src/lib/dhcp/iface_mgr.cc

index 7d1b549bdcbb47f265a1f5a58221177fde967d0a..4e69f051535f3fcce71aea577324b4f11f9c8d22 100644 (file)
@@ -18,6 +18,7 @@
 #include <dhcp6/dhcp6_srv.h>
 #include <dhcp/option6_ia.h>
 #include <dhcp/option6_iaaddr.h>
+#include <dhcp/option6_addrlst.h>
 #include <asiolink/io_address.h>
 #include <exceptions/exceptions.h>
 
@@ -26,21 +27,28 @@ using namespace isc;
 using namespace isc::dhcp;
 using namespace isc::asiolink;
 
+const std::string HARDCODED_LEASE = "2001:db8:1::1234:abcd";
+const uint32_t HARDCODED_T1 = 1500; // in seconds
+const uint32_t HARDCODED_T2 = 2600; // in seconds
+const uint32_t HARDCODED_PREFERRED_LIFETIME = 3600; // in seconds
+const uint32_t HARDCODED_VALID_LIFETIME = 7200; // in seconds
+const std::string HARDCODED_DNS_SERVER = "2001:db8:1::1";
+
 Dhcpv6Srv::Dhcpv6Srv(uint16_t port) {
     cout << "Initialization" << endl;
 
     // first call to instance() will create IfaceMgr (it's a singleton)
     // it may throw something if things go wrong
     try {
-       IfaceMgr::instance();
+        IfaceMgr::instance();
     } catch (const std::exception &e) {
-       cout << "Failed to instantiate InterfaceManager:" << e.what() << ". Aborting." << endl;
-       shutdown = true;
+        cout << "Failed to instantiate InterfaceManager:" << e.what() << ". Aborting." << endl;
+        shutdown = true;
     }
 
     if (IfaceMgr::instance().countIfaces() == 0) {
-       cout << "Failed to detect any network interfaces. Aborting." << endl;
-       shutdown = true;
+        cout << "Failed to detect any network interfaces. Aborting." << endl;
+        shutdown = true;
     }
 
     // Now try to open IPv6 sockets on detected interfaces.
@@ -115,8 +123,9 @@ Dhcpv6Srv::run() {
                 cout << "Replying with:" << rsp->getType() << endl;
                 cout << rsp->toText();
                 cout << "----" << endl;
-                if (rsp->pack()) {
-                    cout << "#### pack successful." << endl;
+                if (!rsp->pack()) {
+                    cout << "Failed to assemble response packet." << endl;
+                    continue;
                 }
                 IfaceMgr::instance().send(rsp);
             }
@@ -149,18 +158,45 @@ Dhcpv6Srv::setServerID() {
                                                      0, 14));
 }
 
-boost::shared_ptr<Pkt6>
-Dhcpv6Srv::processSolicit(boost::shared_ptr<Pkt6> solicit) {
+void Dhcpv6Srv::copyDefaultOptions(const boost::shared_ptr<Pkt6>& question,
+                                   boost::shared_ptr<Pkt6>& answer) {
+    // add client-id
+    boost::shared_ptr<Option> clientid = question->getOption(D6O_CLIENTID);
+    if (clientid) {
+        answer->addOption(clientid);
+    }
 
-    boost::shared_ptr<Pkt6> reply(new Pkt6(DHCPV6_ADVERTISE,
-                                           solicit->getTransid(),
-                                           Pkt6::UDP));
+    // TODO: Should throw if there is no client-id (except anonymous INF-REQUEST)
+}
+
+void Dhcpv6Srv::appendDefaultOptions(const boost::shared_ptr<Pkt6>& /*question*/,
+                                   boost::shared_ptr<Pkt6>& answer) {
+    // TODO: question is currently unused, but we need it at least to know
+    // message type we are answering
 
+    // add server-id
+    answer->addOption(getServerID());
+}
+
+
+void Dhcpv6Srv::appendRequestedOptions(const boost::shared_ptr<Pkt6>& /*question*/,
+                                       boost::shared_ptr<Pkt6>& answer) {
+    // TODO: question is currently unused, but we need to extract ORO from it
+    // and act on its content. Now we just send DNS-SERVERS option.
+
+    // add dns-servers option
+    boost::shared_ptr<Option> dnsservers(new Option6AddrLst(D6O_NAME_SERVERS,
+                                         IOAddress(HARDCODED_DNS_SERVER)));
+    answer->addOption(dnsservers);
+}
+
+void Dhcpv6Srv::assignLeases(const boost::shared_ptr<Pkt6>& question,
+                             boost::shared_ptr<Pkt6>& answer) {
     /// TODO Rewrite this once LeaseManager is implemented.
 
     // answer client's IA (this is mostly a dummy,
     // so let's answer only first IA and hope there is only one)
-    boost::shared_ptr<Option> ia_opt = solicit->getOption(D6O_IA_NA);
+    boost::shared_ptr<Option> ia_opt = question->getOption(D6O_IA_NA);
     if (ia_opt) {
         // found IA
         Option* tmp = ia_opt.get();
@@ -168,38 +204,51 @@ Dhcpv6Srv::processSolicit(boost::shared_ptr<Pkt6> solicit) {
         if (ia_req) {
             boost::shared_ptr<Option6IA>
                 ia_rsp(new Option6IA(D6O_IA_NA, ia_req->getIAID()));
-            ia_rsp->setT1(1500);
-            ia_rsp->setT2(2600);
+            ia_rsp->setT1(HARDCODED_T1);
+            ia_rsp->setT2(HARDCODED_T2);
             boost::shared_ptr<Option6IAAddr>
                 addr(new Option6IAAddr(D6O_IAADDR,
-                                       IOAddress("2001:db8:1234:5678::abcd"),
-                                       5000, 7000));
+                                       IOAddress(HARDCODED_LEASE),
+                                       HARDCODED_PREFERRED_LIFETIME,
+                                       HARDCODED_VALID_LIFETIME));
             ia_rsp->addOption(addr);
-            reply->addOption(ia_rsp);
+            answer->addOption(ia_rsp);
         }
     }
+}
 
-    // add client-id
-    boost::shared_ptr<Option> clientid = solicit->getOption(D6O_CLIENTID);
-    if (clientid) {
-        reply->addOption(clientid);
-    }
+boost::shared_ptr<Pkt6>
+Dhcpv6Srv::processSolicit(const boost::shared_ptr<Pkt6>& solicit) {
 
-    // add server-id
-    reply->addOption(getServerID());
-    return reply;
+    boost::shared_ptr<Pkt6> advertise(new Pkt6(DHCPV6_ADVERTISE,
+                                               solicit->getTransid()));
+
+    copyDefaultOptions(solicit, advertise);
+    appendDefaultOptions(solicit, advertise);
+    appendRequestedOptions(solicit, advertise);
+
+    assignLeases(solicit, advertise);
+
+    return (advertise);
 }
 
 boost::shared_ptr<Pkt6>
-Dhcpv6Srv::processRequest(boost::shared_ptr<Pkt6> request) {
-    /// TODO: Implement processRequest() for real
-    boost::shared_ptr<Pkt6> reply = processSolicit(request);
-    reply->setType(DHCPV6_REPLY);
-    return reply;
+Dhcpv6Srv::processRequest(const boost::shared_ptr<Pkt6>& request) {
+
+    boost::shared_ptr<Pkt6> reply(new Pkt6(DHCPV6_REPLY,
+                                           request->getTransid()));
+
+    copyDefaultOptions(request, reply);
+    appendDefaultOptions(request, reply);
+    appendRequestedOptions(request, reply);
+
+    assignLeases(request, reply);
+
+    return (reply);
 }
 
 boost::shared_ptr<Pkt6>
-Dhcpv6Srv::processRenew(boost::shared_ptr<Pkt6> renew) {
+Dhcpv6Srv::processRenew(const boost::shared_ptr<Pkt6>& renew) {
     boost::shared_ptr<Pkt6> reply(new Pkt6(DHCPV6_REPLY,
                                            renew->getTransid(),
                                            Pkt6::UDP));
@@ -207,7 +256,7 @@ Dhcpv6Srv::processRenew(boost::shared_ptr<Pkt6> renew) {
 }
 
 boost::shared_ptr<Pkt6>
-Dhcpv6Srv::processRebind(boost::shared_ptr<Pkt6> rebind) {
+Dhcpv6Srv::processRebind(const boost::shared_ptr<Pkt6>& rebind) {
     boost::shared_ptr<Pkt6> reply(new Pkt6(DHCPV6_REPLY,
                                            rebind->getTransid(),
                                            Pkt6::UDP));
@@ -215,7 +264,7 @@ Dhcpv6Srv::processRebind(boost::shared_ptr<Pkt6> rebind) {
 }
 
 boost::shared_ptr<Pkt6>
-Dhcpv6Srv::processConfirm(boost::shared_ptr<Pkt6> confirm) {
+Dhcpv6Srv::processConfirm(const boost::shared_ptr<Pkt6>& confirm) {
     boost::shared_ptr<Pkt6> reply(new Pkt6(DHCPV6_REPLY,
                                            confirm->getTransid(),
                                            Pkt6::UDP));
@@ -223,7 +272,7 @@ Dhcpv6Srv::processConfirm(boost::shared_ptr<Pkt6> confirm) {
 }
 
 boost::shared_ptr<Pkt6>
-Dhcpv6Srv::processRelease(boost::shared_ptr<Pkt6> release) {
+Dhcpv6Srv::processRelease(const boost::shared_ptr<Pkt6>& release) {
     boost::shared_ptr<Pkt6> reply(new Pkt6(DHCPV6_REPLY,
                                            release->getTransid(),
                                            Pkt6::UDP));
@@ -231,7 +280,7 @@ Dhcpv6Srv::processRelease(boost::shared_ptr<Pkt6> release) {
 }
 
 boost::shared_ptr<Pkt6>
-Dhcpv6Srv::processDecline(boost::shared_ptr<Pkt6> decline) {
+Dhcpv6Srv::processDecline(const boost::shared_ptr<Pkt6>& decline) {
     boost::shared_ptr<Pkt6> reply(new Pkt6(DHCPV6_REPLY,
                                            decline->getTransid(),
                                            Pkt6::UDP));
@@ -239,7 +288,7 @@ Dhcpv6Srv::processDecline(boost::shared_ptr<Pkt6> decline) {
 }
 
 boost::shared_ptr<Pkt6>
-Dhcpv6Srv::processInfRequest(boost::shared_ptr<Pkt6> infRequest) {
+Dhcpv6Srv::processInfRequest(const boost::shared_ptr<Pkt6>& infRequest) {
     boost::shared_ptr<Pkt6> reply(new Pkt6(DHCPV6_REPLY,
                                            infRequest->getTransid(),
                                            Pkt6::UDP));
index bcc7818fe64c101781f5227a85e4962b61e98b8f..44a9f8a912b78b538f298465481e8b3d90d8496b 100644 (file)
@@ -81,7 +81,7 @@ protected:
     ///
     /// @return ADVERTISE, REPLY message or NULL
     boost::shared_ptr<Pkt6>
-    processSolicit(boost::shared_ptr<Pkt6> solicit);
+    processSolicit(const boost::shared_ptr<Pkt6>& solicit);
 
     /// @brief Processes incoming REQUEST and returns REPLY response.
     ///
@@ -95,43 +95,87 @@ protected:
     ///
     /// @return REPLY message or NULL
     boost::shared_ptr<Pkt6>
-    processRequest(boost::shared_ptr<Pkt6> request);
+    processRequest(const boost::shared_ptr<Pkt6>& request);
 
     /// @brief Stub function that will handle incoming RENEW messages.
     ///
     /// @param renew message received from client
     boost::shared_ptr<Pkt6>
-    processRenew(boost::shared_ptr<Pkt6> renew);
+    processRenew(const boost::shared_ptr<Pkt6>& renew);
 
     /// @brief Stub function that will handle incoming REBIND messages.
     ///
     /// @param rebind message received from client
     boost::shared_ptr<Pkt6>
-    processRebind(boost::shared_ptr<Pkt6> rebind);
+    processRebind(const boost::shared_ptr<Pkt6>& rebind);
 
     /// @brief Stub function that will handle incoming CONFIRM messages.
     ///
     /// @param confirm message received from client
     boost::shared_ptr<Pkt6>
-    processConfirm(boost::shared_ptr<Pkt6> confirm);
+    processConfirm(const boost::shared_ptr<Pkt6>& confirm);
 
     /// @brief Stub function that will handle incoming RELEASE messages.
     ///
     /// @param release message received from client
     boost::shared_ptr<Pkt6>
-    processRelease(boost::shared_ptr<Pkt6> release);
+    processRelease(const boost::shared_ptr<Pkt6>& release);
 
     /// @brief Stub function that will handle incoming DECLINE messages.
     ///
     /// @param decline message received from client
     boost::shared_ptr<Pkt6>
-    processDecline(boost::shared_ptr<Pkt6> decline);
+    processDecline(const boost::shared_ptr<Pkt6>& decline);
 
     /// @brief Stub function that will handle incoming INF-REQUEST messages.
     ///
     /// @param infRequest message received from client
     boost::shared_ptr<Pkt6>
-    processInfRequest(boost::shared_ptr<Pkt6> infRequest);
+    processInfRequest(const boost::shared_ptr<Pkt6>& infRequest);
+
+    /// @brief Copies required options from client message to server answer
+    ///
+    /// Copies options that must appear in any server response (ADVERTISE, REPLY)
+    /// to client's messages (SOLICIT, REQUEST, RENEW, REBIND, DECLINE, RELEASE).
+    /// One notable example is client-id. Other options may be copied as required.
+    ///
+    /// @param question client's message (options will be copied from here)
+    /// @param answer server's message (options will be copied here)
+    void copyDefaultOptions(const boost::shared_ptr<Pkt6>& question,
+                            boost::shared_ptr<Pkt6>& answer);
+
+    /// @brief Appends default options to server's answer.
+    ///
+    /// Adds required options to server's answer. In particular, server-id
+    /// is added. Possibly other mandatory options will be added, depending
+    /// on type (or content) of client message.
+    ///
+    /// @param question client's message
+    /// @param answer server's message (options will be added here)
+    void appendDefaultOptions(const boost::shared_ptr<Pkt6>& question,
+                              boost::shared_ptr<Pkt6>& answer);
+
+    /// @brief Appends requested options to server's answer.
+    ///
+    /// Appends options requested by client to the server's answer.
+    /// TODO: This method is currently a stub. It just appends DNS-SERVERS
+    /// option.
+    ///
+    /// @param question client's message
+    /// @param answer server's message (options will be added here)
+    void appendRequestedOptions(const boost::shared_ptr<Pkt6>& question,
+                                boost::shared_ptr<Pkt6>& answer);
+
+    /// @brief Assigns leases.
+    ///
+    /// TODO: This method is currently a stub. It just appends one
+    /// hardcoded lease. It supports addresses (IA_NA) only. It does NOT
+    /// support temporary addresses (IA_TA) nor prefixes (IA_PD).
+    ///
+    /// @param question client's message (with requested IA_NA)
+    /// @param answer server's message (IA_NA options will be added here)
+    void assignLeases(const boost::shared_ptr<Pkt6>& question,
+                      boost::shared_ptr<Pkt6>& answer);
 
     /// @brief Sets server-identifier.
     ///
index e3e2a4a6bfd52bc929fbc72fc8ce6c0c3c840847..c1aa36b185e86c44c7e1115b4da43e299de74c53 100644 (file)
@@ -249,6 +249,12 @@ bool IfaceMgr::openSockets6(uint16_t port) {
          iface!=ifaces_.end();
          ++iface) {
 
+        if (iface->flag_loopback_ ||
+            !iface->flag_up_ ||
+            !iface->flag_running_) {
+            continue;
+        }
+
         AddressCollection addrs = iface->getAddresses();
 
         for (AddressCollection::iterator addr= addrs.begin();
@@ -274,15 +280,15 @@ bool IfaceMgr::openSockets6(uint16_t port) {
             }
 
             count++;
-#if 0
+#if defined(OS_LINUX)
             // this doesn't work too well on NetBSD
-            sock2 = openSocket(iface->getName(),
-                               IOAddress(ALL_DHCP_RELAY_AGENTS_AND_SERVERS),
-                               DHCP6_SERVER_PORT);
+            int sock2 = openSocket(iface->getName(),
+                                   IOAddress(ALL_DHCP_RELAY_AGENTS_AND_SERVERS),
+                                   port);
             if (sock2<0) {
                 isc_throw(Unexpected, "Failed to open multicast socket on "
                           << " interface " << iface->getFullName());
-                iface->delSocket(sock1); // delete previously opened socket
+                iface->delSocket(sock); // delete previously opened socket
             }
 #endif
         }
@@ -875,25 +881,32 @@ IfaceMgr::receive6() {
     /// all available sockets. For now, we just take the
     /// first interface and use first socket from it.
     IfaceCollection::const_iterator iface = ifaces_.begin();
-    if (iface == ifaces_.end()) {
-        isc_throw(Unexpected, "No interfaces detected. Can't receive anything.");
-    }
-    SocketCollection::const_iterator s = iface->sockets_.begin();
     const SocketInfo* candidate = 0;
-    while (s != iface->sockets_.end()) {
-        if (s->addr_.getFamily() != AF_INET6) {
+    while (iface != ifaces_.end()) {
+        SocketCollection::const_iterator s = iface->sockets_.begin();
+        while (s != iface->sockets_.end()) {
+            if (s->addr_.getFamily() != AF_INET6) {
+                ++s;
+                continue;
+            }
+            if (s->addr_.getAddress().to_v6().is_multicast()) {
+                candidate = &(*s);
+                break;
+            }
+            if (!candidate) {
+                candidate = &(*s); // it's not multicast, but it's better than nothing
+            }
             ++s;
-            continue;
         }
-        if (s->addr_.getAddress().to_v6().is_multicast()) {
-            candidate = &(*s);
+        if (candidate) {
             break;
         }
-        if (!candidate) {
-            candidate = &(*s); // it's not multicast, but it's better than nothing
-        }
-        ++s;
+        ++iface;
     }
+    if (iface == ifaces_.end()) {
+        isc_throw(Unexpected, "No interfaces detected. Can't receive anything.");
+    }
+
     if (!candidate) {
         isc_throw(Unexpected, "Interface " << iface->getFullName()
                   << " does not have any sockets open.");