1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193
|
/*
* Dibbler - a portable DHCPv6
*
* authors: Tomasz Mrugalski <thomson@klub.com.pl>
* Marek Senderski <msend@o2.pl>
* changes: Michal Kowalczuk <michal@kowalczuk.eu>
*
* released under GNU GPL v2 only licence
*
*/
#include "SmartPtr.h"
#include "ClntMsgConfirm.h"
#include "OptDUID.h"
#include "ClntOptStatusCode.h"
#include "ClntOptIA_NA.h"
#include "DHCPConst.h"
#include "Logger.h"
// iaLst - contain all IA's to be checked (they have to be in the same link)
TClntMsgConfirm::TClntMsgConfirm(unsigned int iface,
List(TAddrIA) iaLst)
:TClntMsg(iface, SPtr<TIPv6Addr>(), CONFIRM_MSG) {
IRT = CNF_TIMEOUT;
MRT = CNF_MAX_RT;
MRC = 0;
MRD = CNF_MAX_RD;
//The client sets the "msg-type" field to CONFIRM. The client
//generates a transaction ID and inserts this value in the
//"transaction-id" field.
//The client MUST include a Client Identifier option to identify itself
//to the server.
Options.push_back(new TOptDUID(OPTION_CLIENTID, ClntCfgMgr().getDUID(), this ) );
//The client includes IA options for all of the IAs
//assigned to the interface for which the Confirm message is being
//sent. The IA options include all of the addresses the client
//currently has associated with those IAs. The client SHOULD set the
//T1 and T2 fields in any IA_NA options, and the preferred-lifetime and
//valid-lifetime fields in the IA Address options to 0, as the server
//will ignore these fields.
SPtr<TAddrIA> ia;
iaLst.first();
while(ia=iaLst.get())
Options.push_back(new TClntOptIA_NA(ia,true,this));
appendRequestedOptions();
appendElapsedOption();
appendAuthenticationOption();
IsDone = false;
send();
}
void TClntMsgConfirm::answer(SPtr<TClntMsg> reply)
{
SPtr <TClntOptStatusCode> status;
status = (Ptr*) reply->getOption(OPTION_STATUS_CODE);
if (!status) {
Log(Warning) << "Received malformed REPLY for CONFIRM: no status option." << LogEnd;
addrsRejected();
return;
}
switch (status->getCode() ) {
case STATUSCODE_SUCCESS:
addrsAccepted();
IsDone = true;
break;
case STATUSCODE_NOTONLINK:
addrsRejected();
IsDone = true;
break;
case STATUSCODE_UNSPECFAIL:
case STATUSCODE_NOADDRSAVAIL:
case STATUSCODE_NOBINDING:
case STATUSCODE_USEMULTICAST:
default:
Log(Warning) << "REPLY for CONFIRM received with invalid ("
<< status->getCode() << ") status code." << LogEnd;
break;
}
return;
}
void TClntMsgConfirm::addrsAccepted() {
SPtr<TAddrIA> ptrIA;
SPtr<TOpt> ptrOpt;
this->firstOption();
SPtr<TAddrAddr> ptrAddrAddr;
while ( ptrOpt = this->getOption() ) {
if (ptrOpt->getOptType()!=OPTION_IA_NA)
continue;
SPtr<TClntOptIA_NA> ptrOptIA = (Ptr*) ptrOpt;
ptrIA = ClntAddrMgr().getIA( ptrOptIA->getIAID() );
if (!ptrIA)
continue;
// Uncomment this line if you don't want RENEW to be sent after
// CONFIRM exchange is complete
ptrIA->setState(STATE_CONFIGURED);
// Once confirmed, this triggers the
ptrIA->setTimestamp( (uint32_t)time(NULL) - ptrIA->getT1() );
SPtr<TIfaceIface> ptrIface = ClntIfaceMgr().getIfaceByID(ptrIA->getIfindex());
if (!ptrIface)
continue;
ptrIA->firstAddr();
while (ptrAddrAddr = ptrIA->getAddr()) {
ptrIface->addAddr(ptrAddrAddr->get(),ptrAddrAddr->getPref(),
ptrAddrAddr->getValid(), ptrIface->getPrefixLength());
}
}
}
void TClntMsgConfirm::addrsRejected() {
SPtr<TAddrIA> ptrIA;
SPtr<TOpt> ptrOpt;
this->firstOption();
while ( ptrOpt = this->getOption() ) {
if (ptrOpt->getOptType()!=OPTION_IA_NA)
continue;
SPtr<TClntOptIA_NA> ptrOptIA = (Ptr*) ptrOpt;
ptrIA = ClntAddrMgr().getIA(ptrOptIA->getIAID());
if (!ptrIA)
continue;
// release all addrs
SPtr<TIfaceIface> ptrIface;
ptrIface = ClntIfaceMgr().getIfaceByID(ptrIA->getIfindex());
if (!ptrIface) {
Log(Crit) << "We have addresses assigned to non-existing interface."
"Help! Somebody stole an interface!" << LogEnd;
ptrIA->setState(STATE_NOTCONFIGURED);
return;
}
SPtr<TAddrAddr> ptrAddr;
ptrIA->firstAddr();
while (ptrAddr = ptrIA->getAddr() ) {
// remove addr from ...
ptrIface->delAddr( ptrAddr->get(), ptrIface->getPrefixLength() );
// ... and from DB
ptrIA->delAddr( ptrAddr->get() );
}
//not only the address should be rejected, but also the original IA should be deleted and using a new IA to process SOLICIT
SPtr<TClntCfgIA> ptrCfgIA = ClntCfgMgr().getIA(ptrOptIA->getIAID());
ptrCfgIA->reset();
ptrIA->reset();
}
ClntAddrMgr().firstIA();
}
void TClntMsgConfirm::doDuties()
{
//The first Confirm message from the client on the interface MUST be
//delayed by a random amount of time between 0 and CNF_MAX_DELAY.
/// @todo: MRD counters are a mess.
if (!MRD) {
// MRD reached. Nobody said that out addrs are faulty, so we suppose
// they are ok. Use them
Log(Info) << "MRD reached and there is no valid response for CONFIRM. "
<< "Assuming addresses are valid." << LogEnd;
addrsAccepted();
IsDone = true;
return;
}
send();
}
unsigned long TClntMsgConfirm::getTimeout()
{
return 0;
}
bool TClntMsgConfirm::check()
{
return 0;
}
std::string TClntMsgConfirm::getName() const {
return "CONFIRM";
}
TClntMsgConfirm::~TClntMsgConfirm() {
}
|