Commit f9ff938c authored by Tomek Mrugalski's avatar Tomek Mrugalski 🛰
Browse files

[1186] Server now parses SOLICITs and replies with ADVERTISE.

Advertise is not perfect yet:
- server-id is missing
- client-id conveys invalid content
parent a6902002
......@@ -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}
......
......@@ -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;
}
......@@ -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();
......
......@@ -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.
*
......
......@@ -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();
......
......@@ -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();
......
......@@ -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:
......
......@@ -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_
}
......
......@@ -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_;
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment