Package: dibbler-client Version: 1.0.1-1.1 Severity: normal Tags: patch Dear Maintainer,
When you run dibbler-client and configure it to request a prefix delegation and receive a /60 and want it to be split on 2 interfaces, the current version of dibbler as packaged by Debian will create 2 /68 prefixes. Because of this you can't use router announcement as an easy way to get IPv6 configured on the interfaces. For instance: 21:35 Client Notice PD: Adding prefix 2601:1234:5678:9a00::/60 to all interfaces (prefix will be split to /68 prefixes if necessary). ^^^ 21:35 Client Info PD: Using 2 suitable interface(s):eth2.10 eth2.30 21:35 Client Notice PD: Adding prefix 2601:1234:5678:9a00:9000::/68 on the eth2.10/9 interface. 21:35 Client Notice PD: Adding prefix 2601:1234:5678:9a00:7000::/68 on the eth2.30/7 interface. ^^^^ It turns out that upstream code for dibbler-client has already a better solution with this this commit: https://github.com/tomaszmrugalski/dibbler/commit/41fa1dbc148331ec1a465ee3be449cf37d05943a It would be great to fix this in the patched version of dibbler. -- System Information: Debian Release: 11.3 APT prefers stable-updates APT policy: (500, 'stable-updates'), (500, 'stable-security'), (500, 'stable') Architecture: amd64 (x86_64) Kernel: Linux 5.10.0-13-amd64 (SMP w/2 CPU threads) Locale: LANG=fr_FR.UTF-8, LC_CTYPE=fr_FR.UTF-8 (charmap=UTF-8), LANGUAGE not set Shell: /bin/sh linked to /bin/dash Init: systemd (via /run/systemd/system) Versions of packages dibbler-client depends on: ii cdebconf [debconf-2.0] 0.260 ii debconf [debconf-2.0] 1.5.77 ii libc6 2.31-13+deb11u3 ii libgcc-s1 10.2.1-6 ii libstdc++6 10.2.1-6 ii ucf 3.0043 Versions of packages dibbler-client recommends: pn dibbler-doc <none> ii resolvconf 1.87 dibbler-client suggests no packages. -- debconf information: * dibbler-client/start: true * dibbler-client/options: dns * dibbler-client/interfaces: eth1 dibbler-client/title:
diff -ur dibbler-1.0.1.bak/ClntIfaceMgr/ClntIfaceMgr.cpp dibbler-1.0.1/ClntIfaceMgr/ClntIfaceMgr.cpp --- dibbler-1.0.1.bak/ClntIfaceMgr/ClntIfaceMgr.cpp 2015-07-30 14:35:53.000000000 -0700 +++ dibbler-1.0.1/ClntIfaceMgr/ClntIfaceMgr.cpp 2022-04-26 22:18:09.259630252 -0700 @@ -433,6 +433,21 @@ return modifyPrefix(iface, prefix, prefixLen, 0, 0, PREFIX_MODIFY_DEL, params); } +/// Returns number of bits required to store specific number of interfaces +/// +/// @param i +/// @return ceil(log2(i)) or 0 for 0 +int TClntIfaceMgr::numBits(int i) { + int bits = 0; + if (i == 0) { + return (0); + } else { + i--; + } + while (i >>= 1) { ++bits; } + return (bits + 1); +} + bool TClntIfaceMgr::modifyPrefix(int iface, SPtr<TIPv6Addr> prefix, int prefixLen, unsigned int pref, unsigned int valid, PrefixModifyMode mode, @@ -562,66 +577,47 @@ stringstream prefix_split; // textual representation, used to pass as script for (TIfaceIfaceLst::const_iterator i=ifaceLst.begin(); i!=ifaceLst.end(); ++i) { - char buf[16]; - int subprefixLen; - memmove(buf, prefix->getAddr(), 16); - - if (ifaceLst.size() == 1) { - // just one interface - use delegated prefix as is - subprefixLen = prefixLen; - } else if (ifaceLst.size()<256) { - subprefixLen = prefixLen + 8; - int offset = prefixLen/8; - if (prefixLen%8 == 0) { - // that's easy, just put ID in the next octet - buf[offset] = (*i)->getID(); - } else { - // here's fun - uint16_t existing = readUint16(buf+offset); - uint16_t bitmask = 0xff00; - uint16_t infixmask = ((uint8_t)(*i)->getID()) << 8; - bitmask = bitmask >> (prefixLen%8); - infixmask = infixmask >> (prefixLen%8); - - // clear out if there is anything there, i.e. server assigned prefix - // with garbage in host section - existing = existing & (~bitmask); - existing = existing | (bitmask & infixmask); - writeUint16(buf+offset, existing); - } + int subprefixLen = 0; - } else { + int numPrefixes = ifaceLst.size(); + + if (numPrefixes > 256) { // users with too much time that play with virtual interfaces are out of luck Log(Error) << "Something is wrong. Detected more than 256 interface." << LogEnd; return false; } - SPtr<TIPv6Addr> tmpAddr = new TIPv6Addr(buf, false); + SPtr<TIPv6Addr> subprefix = calculateSubprefix(prefix, prefixLen, + numPrefixes, (*i)->getID(), subprefixLen); - Log(Notice) << "PD: " << action << " prefix " << tmpAddr->getPlain() << "/" << subprefixLen + Log(Notice) << "PD: " << action << " prefix " << subprefix->getPlain() << "/" << subprefixLen << " on the " << (*i)->getFullName() << " interface." << LogEnd; - if (params) { - prefix_split << (*i)->getName() << " " << tmpAddr->getPlain() - << "/" << subprefixLen << " "; - } + if (params) { + prefix_split << (*i)->getName() << " " << subprefix->getPlain() + << "/" << subprefixLen << " "; + } switch (mode) { case PREFIX_MODIFY_ADD: - status = prefix_add( (*i)->getName(), (*i)->getID(), tmpAddr->getPlain(), subprefixLen, pref, valid); + status = prefix_add( (*i)->getName(), (*i)->getID(), subprefix->getPlain(), + subprefixLen, pref, valid); break; case PREFIX_MODIFY_UPDATE: - status = prefix_update( (*i)->getName(), (*i)->getID(), tmpAddr->getPlain(), subprefixLen, pref, valid); + status = prefix_update( (*i)->getName(), (*i)->getID(), subprefix->getPlain(), + subprefixLen, pref, valid); break; case PREFIX_MODIFY_DEL: - status = prefix_del( (*i)->getName(), (*i)->getID(), tmpAddr->getPlain(), subprefixLen); + status = prefix_del( (*i)->getName(), (*i)->getID(), subprefix->getPlain(), + subprefixLen); break; } if (status==LOWLEVEL_NO_ERROR) { conf++; } else { string tmp = error_message(); - Log(Error) << "Prefix error encountered during " << action << " operation: " << tmp << LogEnd; + Log(Error) << "Prefix error encountered during " << action << " operation: " + << tmp << LogEnd; } } @@ -640,6 +636,68 @@ } } +/// @brief Calculates subprefix based on prefix/prefixLen and a given +/// number of sub-prefixes +/// +/// @param prefix delegated prefix +/// @param prefixLen delegated prefix length +/// @param numPrefixes total number of sub-prefixes +/// @param i index of the interface +/// @param [out] subprefixLen This parameter is set to appropriate value +/// +/// @return Generated subprefix +SPtr<TIPv6Addr> +TClntIfaceMgr::calculateSubprefix(const SPtr<TIPv6Addr>& prefix, int prefixLen, + int numPrefixes, int i, int& subprefixLen) { + if (numPrefixes == 1) { + // just one interface - use delegated prefix as is + subprefixLen = prefixLen; + return (prefix); + } + + // Get the prefix in binary form. (we need one octet extra to handle operations + // on very long prefixes: /120 to /127). + char buf[17]; + memset(buf, 0, 17); + memmove(buf, prefix->getAddr(), 16); + + // Calculate how many bits are needed for handling this amount of downlink + // interfaces. + int bit_shift = numBits(numPrefixes); + + subprefixLen = prefixLen + bit_shift; + int offset = prefixLen / 8; + if (prefixLen%8 == 0) { + // that's easy, just put ID in the next octet + buf[offset] = i; + } else { + // here's fun + uint16_t existing = readUint16(buf+offset); + uint16_t bitmask = 0xff00; + uint16_t infixmask = ((uint8_t)i) << 8; + bitmask = bitmask >> (prefixLen%8); + infixmask = infixmask >> (prefixLen%8); + + // clear out if there is anything there, i.e. server assigned prefix + // with garbage in host section + existing = existing & (~bitmask); + existing = existing | (bitmask & infixmask); + writeUint16(buf+offset, existing); + } + + // Ok, some users are unhappy if they get prefixes larger than /64, + // so trim down downlink prefixes to /64 if we get something larger. + // One day this parameter will have to be configurable. + if (subprefixLen < 64) { + Log(Info) << "PD: Prefix per downlink interface could be /" << subprefixLen + << ", trimming down to /64" << LogEnd; + subprefixLen = 64; + } + + SPtr<TIPv6Addr> tmpAddr(new TIPv6Addr(buf, false)); + return (tmpAddr); +} + void TClntIfaceMgr::redetectIfaces() { struct iface * ptr; struct iface * ifaceList; diff -ur dibbler-1.0.1.bak/ClntIfaceMgr/ClntIfaceMgr.h dibbler-1.0.1/ClntIfaceMgr/ClntIfaceMgr.h --- dibbler-1.0.1.bak/ClntIfaceMgr/ClntIfaceMgr.h 2014-02-15 09:37:44.000000000 -0800 +++ dibbler-1.0.1/ClntIfaceMgr/ClntIfaceMgr.h 2022-04-26 22:13:44.358121122 -0700 @@ -79,6 +79,11 @@ void redetectIfaces(); + int numBits(int i); + + SPtr<TIPv6Addr> calculateSubprefix(const SPtr<TIPv6Addr>& prefix, int prefixLen, + int numPrefixes, int i, int& subprefixLen); + private: bool modifyPrefix(int iface, SPtr<TIPv6Addr> prefix, int prefixLen, unsigned int pref, unsigned int valid, PrefixModifyMode mode,