/// Checks if a given client is supported /// /// @param msg message sent by client /// /// @return true if supported, false otherwise bool TSrvCfgMgr::isClntSupported(SPtr<TSrvMsg> msg) { int iface=msg->getIface(); SPtr<TIPv6Addr> clntAddr = msg->getAddr(); SPtr<TOpt> opt = msg->getOption(OPTION_CLIENTID); SPtr<TDUID> duid; if (!opt) { // malformed message or anonymous inf-request duid = new TDUID("", 0); // zero-length DUID } else { SPtr<TOptDUID> clientId = (Ptr*) opt; duid = clientId->getDUID(); } SPtr<TSrvCfgIface> ptrIface; firstIface(); while((ptrIface=getIface())&&(ptrIface->getID()!=iface)) ; /** @todo: reject-client and accept-only does not work in stateless mode */ if (this->stateless()) return true; int classCnt = 0; if (ptrIface) { SPtr<TSrvCfgAddrClass> ptrClass; ptrIface->firstAddrClass(); while(ptrClass=ptrIface->getAddrClass()) { if (ptrClass->clntSupported(duid,clntAddr)) return true; classCnt++; } SPtr<TSrvCfgPD> pd; ptrIface->firstPD(); while ( pd=ptrIface->getPD() ) { if (pd->clntSupported(duid, clntAddr, msg)) return true; classCnt++; } } if (!classCnt && ptrIface) { Log(Warning) << "There are no address class defined on the " << ptrIface->getFullName() << ". Maybe you are trying to configure clients on cascade relay interface? " << "If that is so, please define separate class on this interface, too." << LogEnd; } else if (!classCnt) { Log(Warning) << "Interface not found." << "Maybe you are trying to configure clients on cascade relay interface? " << "If that is so, please define separate class on this interface, too." << LogEnd; } return false; }
/* * Method checks whether client is supported and assigned addresses from any class */ bool TSrvCfgMgr::isClntSupported(SPtr<TDUID> duid, SPtr<TIPv6Addr> clntAddr, int iface, SPtr<TSrvMsg> msg) { SPtr<TSrvCfgIface> ptrIface; firstIface(); while((ptrIface=getIface())&&(ptrIface->getID()!=iface)) ; /** @todo: reject-client and accept-only does not work in stateless mode */ if (this->stateless()) return true; int classCnt = 0; if (ptrIface) { SPtr<TSrvCfgAddrClass> ptrClass; ptrIface->firstAddrClass(); while(ptrClass=ptrIface->getAddrClass()) { if (ptrClass->clntSupported(duid,clntAddr,msg)) return true; classCnt++; } } if (!classCnt) { Log(Warning) << "There are no address class defined on the " << ptrIface->getFullName() << ". Maybe you are trying to configure clients on cascade relay interface? " << "If that is so, please define separate class on this interface, too." << LogEnd; } return false; }
/** * returns how many addresses can be assigned to this client? * factors used: * - iface-max-lease * - clntSupported() * - class-max-lease in each class * - assignedCount in each class * * @param clntDuid * @param clntAddr * @param iface * * @return return value <= clnt-max-lease <= iface-max-lease */ long TSrvCfgMgr::countAvailAddrs(SPtr<TDUID> clntDuid, SPtr<TIPv6Addr> clntAddr, int iface) { /// @todo: long long long int (128bit) could come in handy double avail = 0; // how many are available? double ifaceAssigned = 0; // how many are assigned on this iface? SPtr<TSrvCfgIface> ptrIface; ptrIface = this->getIfaceByID(iface); if (!ptrIface) { Log(Error) << "Interface " << iface << " does not exist in SrvCfgMgr." << LogEnd; return 0; } unsigned long ifaceMaxLease = ptrIface->getIfaceMaxLease(); SPtr<TSrvCfgAddrClass> ptrClass; ptrIface->firstAddrClass(); while (ptrClass = ptrIface->getAddrClass()) { if (!ptrClass->clntSupported(clntDuid,clntAddr)) continue; unsigned long classMaxLease; unsigned long classAssigned; double tmp; classMaxLease = ptrClass->getClassMaxLease(); classAssigned = ptrClass->getAssignedCount(); tmp = classMaxLease - classAssigned; ifaceAssigned += classAssigned; if (tmp>0) avail += tmp; } if (avail > (ifaceMaxLease-ifaceAssigned)) avail = ifaceMaxLease-ifaceAssigned; return (long)avail; }
/// this method finds a temp. address for this client, marks it as used and then /// creates IAAADDR option containing this option. /// /// @param clientMsg /// /// @return IAADDR option with new temporary address (or NULL) SPtr<TSrvOptIAAddress> TSrvOptTA::assignAddr(SPtr<TSrvMsg> clientMsg) { SPtr<TSrvCfgIface> ptrIface; ptrIface = SrvCfgMgr().getIfaceByID(this->Iface); if (!ptrIface) { Log(Error) << "Trying to find free address on non-existent interface (id=%d)\n" << this->Iface << LogEnd; return SPtr<TSrvOptIAAddress>(); // NULL } SPtr<TSrvCfgTA> ta; ptrIface->firstTA(); while ( ta = ptrIface->getTA()) { if (!ta->clntSupported(ClntDuid, ClntAddr, clientMsg )) continue; break; } if (!ta) { Log(Warning) << "Unable to find any suitable (allowed,non-full) TA for this client." << LogEnd; return SPtr<TSrvOptIAAddress>(); // NULL } SPtr<TIPv6Addr> addr; int safety=0; while (safety < SERVER_MAX_TA_RANDOM_TRIES) { addr = ta->getRandomAddr(); if (SrvAddrMgr().taAddrIsFree(addr)) { if ((this->OrgMessage == REQUEST_MSG)) { Log(Debug) << "Temporary address " << addr->getPlain() << " granted." << LogEnd; SrvAddrMgr().addTAAddr(this->ClntDuid, this->ClntAddr, this->Iface, IAID_, addr, ta->getPref(), ta->getValid()); SrvCfgMgr().addTAAddr(this->Iface); } else { Log(Debug) << "Temporary address " << addr->getPlain() << " generated (not granted)." << LogEnd; } return new TSrvOptIAAddress(addr, ta->getPref(), ta->getValid(), this->Parent); } safety++; } Log(Error) << "Unable to randomly choose address after " << SERVER_MAX_TA_RANDOM_TRIES << " tries." << LogEnd; return SPtr<TSrvOptIAAddress>(); // NULL }
/** * @brief returns list of free prefixes for this client * * return free prefixes for a client. There are several ways that method may work: * 1 - client didn't provide any hints: * => one prefix from each pool will be granted * 2 - client has provided hint and that is valid (supported and unused): * => requested prefix will be granted * 3 - client has provided hint, which belongs to supported pool, but this prefix is used: * => other prefix from that pool will be asigned * 4 - client has provided hint, but it is invalid (not beloninging to a supported pool, * multicast or link-local): * => see 1 * * @param clientMsg message received from a client * @param cli_hint hint provided by client (or ::) * * @return - list of prefixes */ List(TIPv6Addr) TSrvOptIA_PD::getFreePrefixes(SPtr<TSrvMsg> clientMsg, SPtr<TIPv6Addr> cli_hint) { SPtr<TSrvCfgIface> ptrIface; SPtr<TIPv6Addr> prefix; SPtr<TSrvCfgPD> ptrPD; bool validHint = true; List(TIPv6Addr) lst; lst.clear(); ptrIface = SrvCfgMgr().getIfaceByID(this->Iface); if (!ptrIface) { Log(Error) << "PD: Trying to find free prefix on non-existent interface (ifindex=" << this->Iface << ")." << LogEnd; return lst; // empty list } if (!ptrIface->supportPrefixDelegation()) { // this method should not be called anyway Log(Error) << "PD: Prefix delegation is not supported on the " << ptrIface->getFullName() << "." << LogEnd; return lst; // empty list } ptrIface->firstPD(); ptrPD = ptrIface->getPD(); // should be ==, asigned>total should never happen if (ptrPD->getAssignedCount() >= ptrPD->getTotalCount()) { Log(Error) << "PD: Unable to grant any prefixes: Already asigned " << ptrPD->getAssignedCount() << " out of " << ptrPD->getTotalCount() << "." << LogEnd; return lst; // empty list } // check if this prefix is ok // is it anyaddress (::)? SPtr<TIPv6Addr> anyaddr = new TIPv6Addr(); if (*anyaddr==*cli_hint) { Log(Debug) << "PD: Client requested unspecified (" << *cli_hint << ") prefix. Hint ignored." << LogEnd; validHint = false; } // is it multicast address (ff...)? if ((*(cli_hint->getAddr()))==0xff) { Log(Debug) << "PD: Client requested multicast (" << *cli_hint << ") prefix. Hint ignored." << LogEnd; validHint = false; } // is it link-local address (fe80::...)? char linklocal[]={0xfe, 0x80}; if (!memcmp(cli_hint->getAddr(),linklocal,2)) { Log(Debug) << "PD: Client requested link-local (" << *cli_hint << ") prefix. Hint ignored." << LogEnd; validHint = false; } SPtr<TOptVendorData> remoteID; TSrvMsg * par = (TSrvMsg*)(Parent); if (par) { remoteID = par->getRemoteID(); } if ( validHint ) { // hint is valid, try to use it ptrPD = SrvCfgMgr().getClassByPrefix(this->Iface, cli_hint); // if the PD allow the hint, based on DUID, Addr, and Msg from client if (ptrPD && ptrPD->clntSupported(ClntDuid, ClntAddr, clientMsg)) { // Let's make a copy of the hint (we may need to tweak the hint in a second) SPtr<TIPv6Addr> hint(new TIPv6Addr(cli_hint->getAddr())); // Now zero the remaining part hint->truncate(0, ptrPD->getPD_Length()); // Is this hint reserved for someone else? if (!ptrIface->checkReservedPrefix(hint, ClntDuid, remoteID, ClntAddr)) { // Nope, not reserved. // case 2: address belongs to supported class, and is free if ( SrvAddrMgr().prefixIsFree(hint) ) { Log(Debug) << "PD: Requested prefix (" << *hint << ") is free, great!" << LogEnd; this->PDLength = ptrPD->getPD_Length(); this->Prefered = ptrPD->getPrefered(this->Prefered); this->Valid = ptrPD->getValid(this->Valid); T1_ = ptrPD->getT1(T1_); T2_ = ptrPD->getT2(T2_); lst.append(hint); return lst; } else { // case 3: hint is used, but we can assign another prefix from the same pool do { prefix=ptrPD->getRandomPrefix(); } while (!SrvAddrMgr().prefixIsFree(prefix)); lst.append(prefix); this->PDLength = ptrPD->getPD_Length(); this->Prefered = ptrPD->getPrefered(this->Prefered); this->Valid = ptrPD->getValid(this->Valid); T1_ = ptrPD->getT1(T1_); T2_ = ptrPD->getT2(T2_); return lst; } // if hint is used } // if this hint is reserved for someone? } // if client is supported at all } // if this is a valid hint // case 1: no hint provided, assign one prefix from each pool // case 4: provided hint does not belong to supported class or is useless (multicast,link-local, ::) ptrIface->firstPD(); while ( ptrPD = ptrIface->getPD()) { if (!ptrPD->clntSupported(ClntDuid, ClntAddr, clientMsg )) continue; break; } if (!ptrPD) { Log(Warning) << "Unable to find any PD for this client." << LogEnd; return lst; // return empty list } int attempts = SERVER_MAX_PD_RANDOM_TRIES; while (attempts--) { List(TIPv6Addr) lst; lst = ptrPD->getRandomList(); lst.first(); bool allFree = true; while (prefix = lst.get()) { if (!SrvAddrMgr().prefixIsFree(prefix) || SrvCfgMgr().prefixReserved(prefix)) { allFree = false; } } if (allFree) { this->PDLength = ptrPD->getPD_Length(); this->Prefered = ptrPD->getPrefered(this->Prefered); this->Valid = ptrPD->getValid(this->Valid); T1_ = ptrPD->getT1(T1_); T2_ = ptrPD->getT2(T2_); return lst; } }; // failed to find available prefixes after 100 attempts. Return empty list return List(TIPv6Addr)(); }