出乎意料的结果

时间:2012-03-02 20:20:46

标签: c++

在我们的组织中,我们按以下格式收到每日黑名单(更大,因为这只是一个片段):

  

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

当我收到代码编译后运行程序时:

  

1

     

1

     

1

     

1

     

1

     

1

     

1

     

1

我在Linux / Unix环境中使用C ++。

到目前为止,我只是吐出来确保我的格式正确。

该文件的名称为blacklist.txt,其中包含上面列出的IP。我只使用cout来确保我的变量被正确定义。

#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;
}

我期待输出为10.10.10.10(这里是某种主机子网)10.10.0.0(以及某种子网掩码)

2 个答案:

答案 0 :(得分:4)

这就是您的问题所在:

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

如果_ip的形式为x.0.0.0,它只会比较_IP中的x, 如果_ip的形式为x.y.0.0,它只比较_IP中的x和y, 这很好。

但如果_ip不是这两种格式,你将掩码设置为0&lt; - 这就是问题。

当您(_ip&amp; 0)时,结果始终为0,同样(_IP&amp; 0)。 这意味着你总是在a.b.c.d,c!= 0或d!= 0。

的地址上返回true

相反,使默认掩码等于0xffffffff以检查完全匹配。

但结果证明这不是大问题。最大的问题是==具有比&amp;更高的运算符优先级,所以你的代码实际上是这样工作的:

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

因此,您将始终获得0作为掩码。你需要应用parens来解决这个问题。

总而言之,您的代码应该更改为:

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

答案 1 :(得分:3)

回应隐含的问题,&#34;为什么我的计划没有按照我期望的方式运作?&#34;

  

我期待输出为10.10.10.10(这里是某种主机子网)10.10.0.0(以及某种子网掩码)

我不知道你为什么这么想。您的代码(如果文件成功打开)只有一个print语句:

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

函数is_match始终返回一个bool,truefalse。打印时,它将始终分别为10。您的程序中没有任何代码可以打印IP地址或网络掩码。