Validating a Subnet Mask



  • Does anyone know of any existing algorithms within Qt which could validate a network subnet mask including checking that contiguous bits are set?

    For example, the following are valid subnets:

    255.255.255.0
    11111111.11111111.11111111.00000000
    
    255.255.224.0
    11111111.11111111.11110000.00000000
    
    255.224.0.0
    11111111.11110000.00000000.00000000
    

    Whereas these are not valid subnet masks

    255.15.0.0
    11111111.00001111.00000000.00000000
    
    255.255.88.0
    11111111.11111111.01011000.00000000
    
    224.15.0.0
    11110000.00001111.00000000.00000000
    

    I could go through each bit in turn starting with MSB, then set a flag when the bit is clear. If I see another set bit after the flag has been set then I can determine that the netmask is invalid.

    Seems a little clunky though and I'd perhaps expect that this is already covered somewhere in the QtNetwork library?

    uint32_t netmask = 0xFFF00000;
    bool flag = false;
    QString str;
    
    for (int i = 31; i >= 0; i--) {
    	bool set = (((netmask & (1 << i)) >> i) == 1);
    
    	if (set) {
    		str += "1";
    	}
    	else {
    		str += "0";
    	}
    
    	if (!set)
    		flag = true;
    
    	if (set && flag)
    		error = true;
    }
    
    qDebug() << str;
    

  • Moderators

    @webzoid There are not that many numbers to check against:

    00000000
    10000000
    11000000
    11100000
    11110000
    11111000
    11111100
    11111110
    11111111
    

    Simply check each byte of the mask whether it is one of this numbers. You don't even need to convert to binary representation.



  • @jsulm Sorry, I wasn't very explicit - the subnet mask is ultimately stored as a 32-bit number hence why I'm looping through all 32 bit positions.


  • Moderators

    @webzoid But then you can iterate over each byte instead of iterating over each bit.



  • @webzoid said in Validating a Subnet Mask:

    the subnet mask is ultimately stored as a 32-bit number

    There may be better ways, but you can do it like:

    bool isContiguous(quint32 mask)
    {
        for (;mask != 0; mask <<=1) {
            if ((mask & (1<<31)) == 0)
                return false; // Highest bit is now zero, but mask is non-zero.
        }
        return true; // Mask was, or became 0.
    }
    

    And calling it with your sample masks:

        qDebug() << isContiguous(QHostAddress(QStringLiteral("255.255.255.0")).toIPv4Address());
        qDebug() << isContiguous(QHostAddress(QStringLiteral("255.255.224.0")).toIPv4Address());
        qDebug() << isContiguous(QHostAddress(QStringLiteral("255.224.0.0")).toIPv4Address());
        qDebug() << isContiguous(QHostAddress(QStringLiteral("255.15.0.0")).toIPv4Address());
        qDebug() << isContiguous(QHostAddress(QStringLiteral("255.255.88.0")).toIPv4Address());
        qDebug() << isContiguous(QHostAddress(QStringLiteral("224.15.0.0")).toIPv4Address());
    

    Gives:

    true
    true
    true
    false
    false
    false
    

    Cheers.



  • @Paul-Colby Thanks Paul, that looks like a neat little way to do it.


  • Qt Champions 2016

    As @jsulm pointed out, it should be rather trivial. Here's an example, but you need to modify and/or fix it, as I don't test my snippets:

    bool isContiguous(const QString & maskString)
    {
        static const quint8 bits[16] = { 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4 };
    
        quint32 mask = QHostAddress(maskString).toIPv4Address();
    
        quint32 validity = ~(mask ^ ~(mask << 1));
        char * data = reinterpret_cast<char *>(&validity);
    
        quint8 raised = 0;
        for (qint8 i = 0; i < sizeof(quint32); i++)
            raised += bits[data[i] & 0x0f] + (bits[data[i] >> 4]);
    
        return raised == 1;
    }
    

    PS.
    The idea of the above snippet is to count the "discontinuities" in the bit stream (hence the shift and xor in the beginning). Basically you should have only one single bit set in the validity integer to have a valid mask. More than one raised bit means the mask is not valid (i.e. more than one switch from 0 to 1 or 1 to 0). The loop on the bytes is just for more efficient bit counting. If your compiler supports it you can use the popcnt instruction instead of the whole for loop.
    gcc: __builtin_popcount
    msvc: __popcnt


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.