Browse Source

[1186] Server now parses SOLICITs and replies with ADVERTISE.
Advertise is not perfect yet:
- server-id is missing
- client-id conveys invalid content

Tomek Mrugalski 13 years ago
parent
commit
f9ff938c75

+ 1 - 8
src/bin/dhcp6/Makefile.am

@@ -33,19 +33,12 @@ BUILT_SOURCES = spec_config.h
 pkglibexec_PROGRAMS = b10-dhcp6
 b10_dhcp6_SOURCES = main.cc iface_mgr.cc dhcp6_srv.cc
 b10_dhcp6_SOURCES += iface_mgr.h dhcp6_srv.h
-b10_dhcp6_LDADD =  $(top_builddir)/src/lib/datasrc/libdatasrc.la
-b10_dhcp6_LDADD += $(top_builddir)/src/lib/dns/libdns++.la
-b10_dhcp6_LDADD += $(top_builddir)/src/lib/util/libutil.la
-b10_dhcp6_LDADD += $(top_builddir)/src/lib/dhcp/libdhcp.la
+b10_dhcp6_LDADD = $(top_builddir)/src/lib/dhcp/libdhcp.la
 b10_dhcp6_LDADD += $(top_builddir)/src/lib/config/libcfgclient.la
 b10_dhcp6_LDADD += $(top_builddir)/src/lib/cc/libcc.la
 b10_dhcp6_LDADD += $(top_builddir)/src/lib/exceptions/libexceptions.la
-b10_dhcp6_LDADD += $(top_builddir)/src/lib/asiodns/libasiodns.la
 b10_dhcp6_LDADD += $(top_builddir)/src/lib/asiolink/libasiolink.la
 b10_dhcp6_LDADD += $(top_builddir)/src/lib/log/liblog.la
-b10_dhcp6_LDADD += $(top_builddir)/src/lib/xfr/libxfr.la
-b10_dhcp6_LDADD += $(top_builddir)/src/lib/server_common/libserver_common.la
-b10_dhcp6_LDADD += $(SQLITE_LIBS)
 
 # TODO: config.h.in is wrong because doesn't honor pkgdatadir
 # and can't use @datadir@ because doesn't expand default ${prefix}

+ 72 - 2
src/bin/dhcp6/dhcp6_srv.cc

@@ -16,9 +16,14 @@
 #include "dhcp/pkt6.h"
 #include "dhcp6/iface_mgr.h"
 #include "dhcp6/dhcp6_srv.h"
+#include "dhcp/option6_ia.h"
+#include "dhcp/option6_iaaddr.h"
+#include "io_address.h"
 
 using namespace std;
 using namespace isc;
+using namespace isc::dhcp;
+using namespace isc::asiolink;
 
 Dhcpv6Srv::Dhcpv6Srv() {
     cout << "Initialization" << endl;
@@ -26,6 +31,10 @@ Dhcpv6Srv::Dhcpv6Srv() {
     // first call to instance() will create IfaceMgr (it's a singleton)
     // it may throw something if things go wrong
     IfaceMgr::instance();
+
+    if (!setServerID()) {
+        isc_throw(Unexpected, "Failed to set up server-id.");
+    }
 }
 
 Dhcpv6Srv::~Dhcpv6Srv() {
@@ -74,8 +83,20 @@ Dhcpv6Srv::run() {
 
             cout << "Received " << query->data_len_ << " bytes packet type="
                  << query->getType() << endl;
+            cout << query->toText();
             if (rsp != boost::shared_ptr<Pkt6>()) {
-                cout << "Replying with " << rsp->getType() << endl;
+                rsp->remote_addr_ = query->remote_addr_;
+                rsp->local_addr_ = query->local_addr_;
+                rsp->remote_port_ = DHCP6_CLIENT_PORT;
+                rsp->local_port_ = DHCP6_SERVER_PORT;
+                rsp->ifindex_ = query->ifindex_;
+                rsp->iface_ = query->iface_; 
+                cout << "Replying with:" << rsp->getType() << endl;
+                cout << rsp->toText();
+                cout << "----" << endl;
+                if (rsp->pack()) {
+                    cout << "#### pack successful." << endl;
+                }
                 IfaceMgr::instance().send(rsp);
             }
         }
@@ -89,6 +110,32 @@ Dhcpv6Srv::run() {
     return (true);
 }
 
+boost::shared_ptr<Option>
+Dhcpv6Srv::getServerID() {
+    return serverid_;
+}
+
+bool
+Dhcpv6Srv::setServerID() {
+    /// TODO implement this for real once interface detection is done.
+    /// Use hardcoded server-id for now
+
+    boost::shared_array<char> srvid(new char[14]);
+    srvid[0] = 0;
+    srvid[1] = 1; // DUID type 1 = DUID-LLT (see section 9.2 of RFC3315)
+    srvid[2] = 0;
+    srvid[3] = 6; // HW type = ethernet (I think. I'm typing this from my head
+                  // in hotel, without Internet connection)
+    for (int i=4; i<14; i++) {
+        srvid[i]=i-4;
+    }
+    serverid_ = boost::shared_ptr<Option>(new Option(Option::V6,
+                                                     D6O_SERVERID,
+                                                     srvid,
+                                                     0, 14));
+    return (true);
+}
+
 boost::shared_ptr<Pkt6>
 Dhcpv6Srv::processSolicit(boost::shared_ptr<Pkt6> solicit) {
 
@@ -96,6 +143,29 @@ Dhcpv6Srv::processSolicit(boost::shared_ptr<Pkt6> solicit) {
                                            solicit->getTransid(),
                                            Pkt6::UDP));
 
+    // 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);
+    if (ia_opt) {
+        // found IA
+        Option * tmp = ia_opt.get();
+        Option6IA * ia_req = dynamic_cast<Option6IA*> (tmp); 
+        if (ia_req) {
+            boost::shared_ptr<Option6IA> ia_rsp(new Option6IA(Option::V6, D6O_IA_NA, ia_req->getIAID()));
+            ia_rsp->setT1(1500);
+            ia_rsp->setT2(2600);
+            boost::shared_ptr<Option6IAAddr> addr(new Option6IAAddr(D6O_IAADDR, IOAddress("2001:db8:1234:5678::abcd"), 5000, 7000));
+            ia_rsp->addOption(addr);
+            reply->addOption(ia_rsp);
+        }
+    }
+
+    // add client-id
+    boost::shared_ptr<Option> clientid = solicit->getOption(D6O_CLIENTID);
+    reply->addOption(clientid);
+
+    // add server-id
+    // reply->addOption(getServerID());
     return reply;
 }
 
@@ -104,7 +174,6 @@ Dhcpv6Srv::processRequest(boost::shared_ptr<Pkt6> request) {
     boost::shared_ptr<Pkt6> reply(new Pkt6(DHCPV6_REPLY,
                                            request->getTransid(),
                                            Pkt6::UDP));
-
     return reply;
 }
 
@@ -147,3 +216,4 @@ Dhcpv6Srv::processDecline(boost::shared_ptr<Pkt6> decline) {
                                            Pkt6::UDP));
     return reply;
 }
+

+ 9 - 0
src/bin/dhcp6/dhcp6_srv.h

@@ -17,6 +17,7 @@
 
 #include <boost/shared_ptr.hpp>
 #include "dhcp/pkt6.h"
+#include "dhcp/option.h"
 #include <iostream>
 
 namespace isc {
@@ -27,6 +28,14 @@ namespace isc {
         Dhcpv6Srv(const Dhcpv6Srv& src);
         Dhcpv6Srv& operator=(const Dhcpv6Srv& src);
 
+        boost::shared_ptr<isc::dhcp::Option> getServerID();
+
+        // this method sets server-identifier. it loads it from a file or
+        // generates using interface link-layer addresses (EUI-64)
+        bool setServerID();
+
+        boost::shared_ptr<isc::dhcp::Option> serverid_;
+
     public:
         // default constructor
         Dhcpv6Srv();

+ 7 - 0
src/lib/dhcp/option.cc

@@ -172,6 +172,13 @@ bool Option::valid() {
     return (true);
 }
 
+void
+isc::dhcp::Option::addOption(boost::shared_ptr<isc::dhcp::Option> opt) {
+    optionLst_.insert(pair<int, boost::shared_ptr<Option> >(opt->getType(), opt));
+
+}
+
+
 /**
  * Converts generic option to string.
  *

+ 3 - 1
src/lib/dhcp/option.h

@@ -70,12 +70,14 @@ public:
 
     unsigned short getType();
 
-    // returns data length (data length + DHCPv4/DHCPv6 option header)
+    // returns length of the complete option (data length + DHCPv4/DHCPv6 option header)
     virtual unsigned short len();
 
     // returns if option is valid (e.g. option may be truncated)
     virtual bool valid();
 
+    void addOption(boost::shared_ptr<Option> opt);
+
     // just to force that every option has virtual dtor
     virtual ~Option();
 

+ 4 - 8
src/lib/dhcp/option6_ia.cc

@@ -44,7 +44,7 @@ unsigned int
 Option6IA::pack(boost::shared_array<char> buf,
                 unsigned int buf_len,
                 unsigned int offset) {
-    if (len() > buf_len) {
+    if (offset + len() > buf_len) {
         isc_throw(OutOfRange, "Failed to pack IA option: len=" << len() 
                   << ", buffer=" << buf_len << ": too small buffer.");
     }
@@ -52,22 +52,18 @@ Option6IA::pack(boost::shared_array<char> buf,
     char* ptr = &buf[offset];
     *(uint16_t*)ptr = htons(type_);
     ptr += 2;
-    buf_len -= 2;
-    *(uint16_t*)ptr = htons(len());
+    *(uint16_t*)ptr = htons(len() - 4); // len() returns complete option length
+    // len field contains length without 4-byte option header
     ptr += 2;
-    buf_len -= 2;
     
     *(uint32_t*)ptr = htonl(iaid_);
     ptr += 4;
-    buf_len -= 4;
 
     *(uint32_t*)ptr = htonl(t1_);
     ptr += 4;
-    buf_len -= 4;
 
     *(uint32_t*)ptr = htonl(t2_);
     ptr += 4;
-    buf_len -= 4;
 
     offset = LibDHCP::packOptions6(buf, buf_len, offset+16, optionLst_);
     return offset;
@@ -116,7 +112,7 @@ std::string Option6IA::toText() {
 
 unsigned short Option6IA::len() {
     
-    unsigned short length = 12; // header
+    unsigned short length = 4/*header*/ + 12 /* option content */; // header
 
     // length of all suboptions
     for (Option::Option6Lst::iterator it = optionLst_.begin();

+ 3 - 2
src/lib/dhcp/option6_iaaddr.cc

@@ -55,7 +55,8 @@ Option6IAAddr::pack(boost::shared_array<char> buf,
     
     *(uint16_t*)&buf[offset] = htons(type_);
     offset += 2;
-    *(uint16_t*)&buf[offset] = htons(len());
+    *(uint16_t*)&buf[offset] = htons(len()-4); // len() returns complete option
+    // length. len field contains length without 4-byte option header
     offset += 2;
 
     memcpy(&buf[offset], addr_.getAddress().to_v6().to_bytes().data(), 16);
@@ -113,7 +114,7 @@ std::string Option6IAAddr::toText() {
 
 unsigned short Option6IAAddr::len() {
     
-    unsigned short length = 24; // header
+    unsigned short length = 4/*header*/ + 24 /* content */; // header
 
     // length of all suboptions
     // TODO implement:

+ 48 - 16
src/lib/dhcp/pkt6.cc

@@ -58,7 +58,13 @@ Pkt6::Pkt6(unsigned char msg_type,
      msg_type_(msg_type),
      transid_(transid) {
 
-
+    try {
+        data_ = boost::shared_array<char>(new char[4]);
+        data_len_ = 4;
+    } catch (Exception e) {
+        cout << "Packet creation failed:" << e.what() << endl;
+    }
+    data_len_ = 0;
 }
 
 /**
@@ -112,29 +118,39 @@ bool
 Pkt6::packUDP() {
     unsigned short length = len();
     if (data_len_ < length) {
-        // we have too small buffer, let's allocate bigger one
-        data_ = boost::shared_array<char>(new char[length]);
-        data_len_ = length;
-    }
+        cout << "Previous len=" << data_len_ << ", allocating new buffer: len="
+             << length << endl;
 
-    // DHCPv6 header: message-type (1 octect) + transaction id (3 octets)
-    data_[0] = msg_type_;
-    data_[1] = (transid_ >> 16) & 0xff;
-    data_[2] = (transid_ >> 8) & 0xff;
-    data_[3] = (transid_) & 0xff;
+        try {
+            data_ = boost::shared_array<char>(new char[length]);
+            data_len_ = length;
+        } catch (Exception e) {
+            cout << "Failed to allocate " << length << "-byte buffer:"
+                 << e.what() << endl;
+            return (false);
+        }
+    }
 
     try {
+        // DHCPv6 header: message-type (1 octect) + transaction id (3 octets)
+        data_[0] = msg_type_;
+        data_[1] = (transid_ >> 16) & 0xff;
+        data_[2] = (transid_ >> 8) & 0xff;
+        data_[3] = (transid_) & 0xff;
+
         // the rest are options
-        unsigned short offset = LibDHCP::packOptions6(data_, length, 4/*offset*/, options_);
+        unsigned short offset = LibDHCP::packOptions6(data_, length,
+                                                      4/*offset*/,
+                                                      options_);
 
         // sanity check
         if (offset != length) {
-            isc_throw(OutOfRange, "Packet build failed: expected size=" << length
-                      << ", actual len=" << offset);
+            isc_throw(OutOfRange, "Packet build failed: expected size="
+                      << length << ", actual len=" << offset);
         }
     }
     catch (Exception e) {
-        cout << "Packet build failed." << endl;
+        cout << "Packet build failed:" << e.what() << endl;
         return (false);
     }
     cout << "Packet built, len=" << len() << endl;
@@ -152,7 +168,8 @@ Pkt6::packUDP() {
 bool
 Pkt6::packTCP() {
     /// TODO Implement this function.
-    isc_throw(Unexpected, "DHCPv6 over TCP (bulk leasequery and failover) not implemented yet.");
+    isc_throw(Unexpected, "DHCPv6 over TCP (bulk leasequery and failover)"
+              "not implemented yet.");
 }
 
 /**
@@ -211,7 +228,8 @@ Pkt6::unpackUDP() {
  */
 bool
 Pkt6::unpackTCP() {
-    isc_throw(Unexpected, "DHCPv6 over TCP (bulk leasequery and failover) not implemented yet.");
+    isc_throw(Unexpected, "DHCPv6 over TCP (bulk leasequery and failover) "
+              "not implemented yet.");
 }
 
 
@@ -225,6 +243,9 @@ Pkt6::unpackTCP() {
 std::string
 Pkt6::toText() {
     stringstream tmp;
+    tmp << "localAddr=[" << local_addr_.toText() << "]:" << local_port_
+        << " remoteAddr=[" << remote_addr_.toText()
+        << "]:" << remote_port_ << endl;
     tmp << "msgtype=" << msg_type_ << ", transid=0x" << hex << transid_
         << dec << endl;
     for (isc::dhcp::Option::Option6Lst::iterator opt=options_.begin();
@@ -265,6 +286,17 @@ Pkt6::getType() {
     return (msg_type_);
 }
 
+void
+Pkt6::addOption(boost::shared_ptr<Option> opt) {
+    options_.insert(pair<int, boost::shared_ptr<Option> >(opt->getType(), opt));
+}
+
+bool
+Pkt6::delOption(unsigned short type) {
+    isc_throw(Unexpected, "Not implemented yet. Not added option " << type);
+    return (false);
+}
+
 Pkt6::~Pkt6() {
     // no need to delete anything shared_ptr will take care of data_
 }

+ 5 - 4
src/lib/dhcp/pkt6.h

@@ -51,10 +51,6 @@ namespace isc {
         unsigned char getType();
         unsigned int getTransid() { return transid_; };
 
-        boost::shared_ptr<isc::dhcp::Option> getOption(unsigned short opt_type);
-
-        /// TODO Need to implement getOptions() as well
-
         /// TODO need getter/setter wrappers
         ///      and hide following fields as protected
         /// buffer that holds memory. It is shared_array as options may
@@ -85,6 +81,11 @@ namespace isc {
         // remote TCP or UDP port
         int remote_port_;
 
+        void addOption(boost::shared_ptr<isc::dhcp::Option> opt);
+        boost::shared_ptr<isc::dhcp::Option> getOption(unsigned short type);
+        bool delOption(unsigned short type);
+        /// TODO Need to implement getOptions() as well
+
         // XXX: add *a lot* here
         isc::dhcp::Option::Option6Lst options_;