pkt6.cc 5.69 KB
Newer Older
1
// Copyright (C) 2011-2012 Internet Systems Consortium, Inc. ("ISC")
2 3 4 5 6 7 8 9 10 11 12 13 14 15
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.


16 17 18 19
#include <dhcp/dhcp6.h>
#include <dhcp/pkt6.h>
#include <dhcp/libdhcp++.h>
#include <exceptions/exceptions.h>
20
#include <iostream>
21 22 23
#include <sstream>

using namespace std;
24 25

namespace isc {
26
namespace dhcp {
27

28 29
Pkt6::Pkt6(const uint8_t* buf, uint32_t buf_len, DHCPv6Proto proto /* = UDP */) :
    proto_(proto),
30
    msg_type_(0),
31 32 33 34 35
    transid_(rand()%0xffffff),
    iface_(""),
    ifindex_(-1),
    local_addr_("::"),
    remote_addr_("::"),
36 37
    local_port_(0),
    remote_port_(0),
38 39 40
    bufferOut_(0) {
    data_.resize(buf_len);
    memcpy(&data_[0], buf, buf_len);
41
}
42

43
Pkt6::Pkt6(uint8_t msg_type, uint32_t transid, DHCPv6Proto proto /*= UDP*/) :
44 45 46 47 48 49 50
    proto_(proto),
    msg_type_(msg_type),
    transid_(transid),
    iface_(""),
    ifindex_(-1),
    local_addr_("::"),
    remote_addr_("::"),
51 52
    local_port_(0),
    remote_port_(0),
53
    bufferOut_(0) {
54 55
}

56 57
uint16_t Pkt6::len() {
    uint16_t length = DHCPV6_PKT_HDR_LEN; // DHCPv6 header
58

59
    for (Option::OptionCollection::iterator it = options_.begin();
60 61 62 63 64
         it != options_.end();
         ++it) {
        length += (*it).second->len();
    }

65
    return (length);
66 67 68 69 70 71 72 73 74 75 76 77 78
}


bool
Pkt6::pack() {
    switch (proto_) {
    case UDP:
        return packUDP();
    case TCP:
        return packTCP();
    default:
        isc_throw(BadValue, "Invalid protocol specified (non-TCP, non-UDP)");
    }
79
    return (false); // never happens
80 81 82 83
}

bool
Pkt6::packUDP() {
84 85 86 87 88 89 90

    // TODO: Once OutputBuffer is used here, some thing like this
    // will be used. Yikes! That's ugly.
    // bufferOut_.writeData(ciaddr_.getAddress().to_v6().to_bytes().data(), 16);
    // It is better to implement a method in IOAddress that extracts
    // vector<uint8_t>

91
    try {
92
        // DHCPv6 header: message-type (1 octect) + transaction id (3 octets)
93
        bufferOut_.writeUint8(msg_type_);
94
        // store 3-octet transaction-id
95 96 97
        bufferOut_.writeUint8( (transid_ >> 16) & 0xff );
        bufferOut_.writeUint8( (transid_ >> 8) & 0xff );
        bufferOut_.writeUint8( (transid_) & 0xff );
98

99
        // the rest are options
100
        LibDHCP::packOptions6(bufferOut_, options_);
101
    }
102
    catch (const Exception& e) {
103
        cout << "Packet build failed:" << e.what() << endl;
104
        return (false);
105
    }
106
    return (true);
107 108 109 110 111
}

bool
Pkt6::packTCP() {
    /// TODO Implement this function.
112 113
    isc_throw(Unexpected, "DHCPv6 over TCP (bulk leasequery and failover)"
              "not implemented yet.");
114 115 116 117 118 119 120 121 122 123 124 125
}

bool
Pkt6::unpack() {
    switch (proto_) {
    case UDP:
        return unpackUDP();
    case TCP:
        return unpackTCP();
    default:
        isc_throw(BadValue, "Invalid protocol specified (non-TCP, non-UDP)");
    }
126
    return (false); // never happens
127 128 129 130
}

bool
Pkt6::unpackUDP() {
131 132
    if (data_.size() < 4) {
        std::cout << "DHCPv6 packet truncated. Only " << data_.size()
133
                  << " bytes. Need at least 4." << std::endl;
134
        return (false);
135 136
    }
    msg_type_ = data_[0];
137 138
    transid_ = ( (data_[1]) << 16 ) +
        ((data_[2]) << 8) + (data_[3]);
139
    transid_ = transid_ & 0xffffff;
140

141 142 143 144 145 146 147
    try {
        OptionBuffer opt_buffer(data_.begin() + 4, data_.end());

        LibDHCP::unpackOptions6(opt_buffer, options_);
    } catch (const Exception& e) {
        cout << "Packet parsing failed:" << e.what() << endl;
        return (false);
148
    }
149
    return (true);
150 151 152 153
}

bool
Pkt6::unpackTCP() {
154 155
    isc_throw(Unexpected, "DHCPv6 over TCP (bulk leasequery and failover) "
              "not implemented yet.");
156 157 158 159 160 161
}


std::string
Pkt6::toText() {
    stringstream tmp;
162 163 164
    tmp << "localAddr=[" << local_addr_.toText() << "]:" << local_port_
        << " remoteAddr=[" << remote_addr_.toText()
        << "]:" << remote_port_ << endl;
165 166
    tmp << "msgtype=" << msg_type_ << ", transid=0x" << hex << transid_
        << dec << endl;
167
    for (isc::dhcp::Option::OptionCollection::iterator opt=options_.begin();
168 169 170 171 172 173 174 175
         opt != options_.end();
         ++opt) {
        tmp << opt->second->toText() << std::endl;
    }
    return tmp.str();
}

boost::shared_ptr<isc::dhcp::Option>
176
Pkt6::getOption(uint16_t opt_type) {
177
    isc::dhcp::Option::OptionCollection::const_iterator x = options_.find(opt_type);
178 179 180 181 182 183
    if (x!=options_.end()) {
        return (*x).second;
    }
    return boost::shared_ptr<isc::dhcp::Option>(); // NULL
}

184 185 186 187 188 189
void
Pkt6::addOption(boost::shared_ptr<Option> opt) {
    options_.insert(pair<int, boost::shared_ptr<Option> >(opt->getType(), opt));
}

bool
190
Pkt6::delOption(uint16_t type) {
191
    isc::dhcp::Option::OptionCollection::iterator x = options_.find(type);
192 193 194 195 196
    if (x!=options_.end()) {
        options_.erase(x);
        return (true); // delete successful
    }
    return (false); // can't find option to be deleted
197 198
}

199 200 201 202 203 204
void Pkt6::repack() {
    cout << "Convering RX packet to TX packet: " << data_.size() << " bytes." << endl;

    bufferOut_.writeData(&data_[0], data_.size());
}

205 206
void
Pkt6::updateTimestamp() {
207
    timestamp_ = boost::posix_time::microsec_clock::universal_time();
208 209 210
}


211 212
} // end of isc::dhcp namespace
} // end of isc namespace