SP3CH8TR
SP3CH8TR

Reputation: 123

Unexpected results

At our organization we recieve a daily blacklist (much bigger as this is just a snippet) in the following format:

172.44.12.0

198.168.1.5

10.10.0.0

192.168.78.6

192.168.22.22

111.111.0.0

222.222.0.0

12.12.12.12

When I run the program after the code compiles I receive:

1

1

1

1

1

1

1

1

I am using C++ in a Linux/Unix environment.

So far, I am just spitting it out to make sure I have it formatted correctly.

The name of the file is blacklist.txt which contains the IP's listed above for now. I am only using cout to make sure my variable are defined correctly.

#include <iostream>
#include <vector>
#include <fstream>
#include <string>
#include <netinet/in.h>
#include <stdint.h>
#include <arpa/inet.h>

using namespace std;

bool is_match(std::string &hay_stack, std::string &srcip) {
    in_addr_t _ip = inet_addr(hay_stack.c_str());
    in_addr_t _IP = inet_addr(srcip.c_str());
    _ip = ntohl(_ip);
    _IP = ntohl(_IP);
    uint32_t mask=(_ip & 0x00ffffff == 0) ? 0xff000000 :
    (_ip & 0x0000ffff == 0 ? 0xffff0000 : 0);
    return ( (_ip & mask) == (_IP & mask) );
}

int main()
{
    vector<std::string> lines;
    lines.reserve(5000); //Assuming that the file to read can have max 5K lines

    string fileName("blacklist.txt");

    ifstream file;
    file.open(fileName.c_str());

    if(!file.is_open())
    {
        cerr<<"Error opening file : "<<fileName.c_str()<<endl;
        return -1;
    }

    //Read the lines and store it in the vector
    string line;
    while(getline(file,line))
    {
        lines.push_back(line);
    }

    file.close();

    //Dump all the lines in output
    for(unsigned int i = 0; i < lines.size(); i++)
    {
        string h = lines[i];
        string mi = "10.10.10.10";
        cout<<is_match(h,mi)<<endl;
    }

    return 0;
}

I am expecting the output to be 10.10.10.10 (some sort of host subnet here) 10.10.0.0 (and some sort of subnet mask here)

Upvotes: 3

Views: 203

Answers (2)

CG Morton
CG Morton

Reputation: 106

This is where your problem is:

uint32_t mask=(_ip & 0x00ffffff == 0) ? 0xff000000 :
(_ip & 0x0000ffff == 0 ? 0xffff0000 : 0);
return ( (_ip & mask) == (_IP & mask) );

If _ip is in the form x.0.0.0, it only compares x in _IP, and if _ip is in the form x.y.0.0, it only compares x and y in _IP, which is fine.

But if _ip isn't in either format you set the mask to 0 <- this is the problem.

When you take (_ip & 0) the result is always 0, likewise with (_IP & 0). This means you always return true on addresses with a.b.c.d, c != 0 or d != 0.

Instead, make the default mask equal 0xffffffff to check for a complete match.

But it turns out that's not the big problem. The big problem is that == has a higher operator precedence than &, so your code is actually working like this:

uint32_t mask=(_ip & (0x00ffffff == 0)) ? 0xff000000 :
    (_ip & (0x0000ffff == 0) ? 0xffff0000 : 0);
return ( (_ip & mask) == (_IP & mask) );

As a result, you will always get the 0 for a mask. You need to apply parens to fix this.

So in conclusion, your code should change to look like this:

uint32_t mask=( (_ip & 0x00ffffff) == 0) ? 0xff000000 :
    ( (_ip & 0x0000ffff) == 0 ? 0xffff0000 : 0xffffffff);
return ( (_ip & mask) == (_IP & mask) );

Upvotes: 4

Robᵩ
Robᵩ

Reputation: 168836

Responding to the implicit question, "Why doesn't my program work the way I expect?"

I am expecting the output to be 10.10.10.10 (some sort of host subnet here) 10.10.0.0 (and some sort of subnet mask here)

I don't know why you are expecting that. Your code (if the file opens successfully) only has one print statement in it:

cout<<is_match(h,mi)<<endl;

The function is_match always return a bool, either true or false. When printed, it will always be either 1 or 0, respectively. There simply isn't any code in your program which could print an IP address or netmask.

Upvotes: 3

Related Questions