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,

Reply via email to