学习中的新手求教,谢谢各位!
在struct ip_option结构中,我看到主要是定义了这么几个选项,包括严格路由、宽松路由、时间戳等选项。这些我用不到,我想在选项字段里,添加自己的连续信息,做一个数据包规则匹配过滤模块。能通过结合netfilter实现吗?主要是IP选项字段用什么思路去操作,不知该怎么去实现?我的测试环境是在无线局域网中,只做用户到AP这一段。

解决方案 »

  1.   

    为什么要在IP option中添加自定义的字段?如果这样做,可能就会涉及在TCP/IP 协议栈中的很多地方进行修改,有点牵一发动全身的意思。
    而且难道对端发送过来的数据包会包含你IP option中的内容?
    我只用过ip header中已有的字段,在option添加新字段,我个人感觉影响还是蛮大的。建议更换解决方案。
      

  2.   

    已有的字段,比如?因为我至少要添加16bit的数据起初我是想,在IP option中添加后,在收端做完匹配就去掉,不影响后面层的解析。
      

  3.   

    我所说的已有的字段就是IP header中sip dip之类的字段。
    楼主可以研究一下IP层数据包的处理流程,在IP option中加内容的话,我觉得ip的校验和处是不是需要注意一下,至于在哪里加内容,我觉得直接在内核中IP层部分直接加应该就可以。
    我之前做过FreeBSD TCP/IP 协议栈的修改与维护,我们的代码都是直接加在kernel中的。(好像FreeBSD没有netfilter这套架构,所以是直接去动协议栈了)
      

  4.   

    发送端ip_queue_xmit函数中可以自己添加个IP Option
    在tcp_transmit_skb函数中也可以添加TCP Option
    一般来说路由器的确不会丢包,但我试了,一般到网站后会被丢掉,可以在出口路由器的qdisc队列转发的过程中把该选项删除
    如果要用户态程序可以使用该选项,可能还要修改接口函数。
      

  5.   

    谢谢回答!校验和肯定是要重新计算的。我就是想请教下,IP选项字段加自定义内容可不可行。另外,求教您说的SIP DIP是指?我在学习协议栈时,IP头部没这字段啊?谢谢
      

  6.   

    谢谢回答!嗯,我思考下也觉得,发端到收端如果中间不经过其他路由网关处理的话,应该不会丢包,而且在收端我会再把添加的这部分自定义选项内容去掉,然后再重新计算校验和。只是在实施具体操作时,不太确定这个IP选项字段能否添加自定义的内容。因为毕竟看那个struct ip_option的结构体已经定义了几种固定的选项类型,是否我可以在成员unsigned char __data[]中直接添加呢?网上这部分自定义选项的内容确实少一些。谢谢不吝赐教
      

  7.   

    SIP/DIP是源IP目的IP。struct ip_options是存放option解析结果或待添加的option选项的,不是最终报文上的option结构。最后报文里的选项就是 type length payload的结构,注意4byte对齐就行。
    type注意避开已经在使用的IPOPT_XXX。
      

  8.   

    意思是IP头的选项字段其实就是数据段的一部分吗?我直接在IP固定报头20字节后添加就可以了吗(然后注意4字节对齐)?对选项在报文中的结构或内存描述,我查资料这部分内容确实比较少。大部分都是struct ip_option。新人刚学习,谢谢指教!
      

  9.   

    是Ip头的一部分,添加自定义选项之后还要修改iphdr->ihl字段
    (表示ip头部的长度,注意除以4,也就是说ihl=5意味着长度是5*4=20字节;
    由于Ihl字段长度只有4bit,所以最大值是15,表示长度为15*4=60字节;
    去掉固定的20字节长度,只有40字节的空间可以用于添加ip option;)。
      

  10.   

    麻烦再请教下。我加了自定IP选项后,还应该注意MTU的限制吗?是否要考虑到这个分片的问题,有没有可能我加了IP选项字段就超过了MTU的限制?
      

  11.   

    MTU可以通过设置TCP的mss来解决,以太网MTU1500,可以设置tcp的mss为1400左右,来避免分片
      

  12.   

    ip没有options,tcp才有
      

  13.   

    楼上为啥这么说,没听懂,IP报文头部不是有option这一块吗
      

  14.   

    是我想当然了,ip确实有options,只是在做报文分析和构造的时候没有见过,而一直都看到tcp options.久而久之就忘了。
     现在更正,多谢指教
      

  15.   

    是我想当然了,ip确实有options,只是在做报文分析和构造的时候没有见过,而一直都看到tcp options.久而久之就忘了。
     现在更正,多谢指教 那知道怎么在 options中添加自定义信息吗,有何见解
      

  16.   

    构造并不复杂,但是添加的自定义信息怎么用?接收方用什么解析?需要发回吗?
    以下是一个示例,还没有测试:
    struct ip_opt
    {
        uint8_t ipt_code;
        uint8_t ipt_len;
        uint8_t *data;
    } ipopt;insert_custom_ipopt(struct ipopt *ipop_p, uint8_t *data_p, uint8_t *ipoptbuff, uint32_t *optlen)
    {
        //pseudo code:ipopt->len = length(ipopt->code) + length(ipopt->len) + length(*data); //length unit: bytes    int i;
        if(iptopt_p-code > 1 || iptopt_p->len + 1 > optlen || ipopt_p->len + *optlen + 1 > MAXIPOPTLEN)
        {
            fprintf(stderr, "ip options build error: options length exceeds MAXIPOPTLEN");
            exit(EXIT_FAILURE);
        }    *((uint16_t *)iptoptbuff) + *optlen= htons(*((uint16_t *)ipopt_p));
        ipopt_p = ipopt_p + 2;    //确保data是little endian
        for (i = 0; i < ipopt_p->len -2 ; i ++)
        {
            *(iptoptbuff + i) = *(data +  i);
        }    *optlen = *optlen + ipopt_p->len;
    }
    ...
    int iolen = 0;
    uint32_t *optlen = &iolen;
    struct ipopt *ipopt_p = &ipoptstruct iphdr *iphdr = (struct iphdr *)(packet + sizeof(struct ethhdr));
    uint8_t *ipoptbuff = packet + sizeof(struct ethhdr) + sizeof(struct iphdr) 
    ...
    memset(ipoptbuff, 0, 40)ipopt.code = xxx;
    ipopt.len = 40; 
    char data[37] = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
    myipopt.data = data;
    insert_custom_ipopt(ipopt_p, data_p, ipoptbuff,optlen);
    iphdr->ihl = 5 + iol / sizeof(uint32_t);
    iphdr->check = 0;
    iphdr->check = iphdr_csum(iphdr);查看了RFC和wireshark的示例报文,得到以下几个概念:
    1. ip options的总长必须是40byts(这个部分RFC没有找到,仅仅参考wireshark给的samplecaptures),如果不够用0填充
    2. ipopt结构体的len必须包含ipopt->code和ipopt->len这两个字节的长度,即data的长度 + 2(这个部分RFC没有找到,仅仅参考wireshark给的samplecaptures)
    3. ip options最后的字节必须是0
    4.然后填充iphdr->ihl = 5 + iol / sizeof(uint32_t);
    5. 最后再计算iphdr->check
      

  17.   

    java不能做到吗,java中有一个socketOption,搞不懂和它有没有关系
      

  18.   

    java不能做到吗,java中有一个socketOption,搞不懂和它有没有关系
      

  19.   

    既然你继续聊,那我大致说一下:
    首先,我的代码有挺大的问题,我改了一下
    #define MAXIPOPTLEN (40 - 1)int add_ipopt(uint8_t ipopt_type, uint8_t ipopt_data_len, uint8_t *data, uint8_t *ipoptbuff, uint32_t optlen, uint8_t *ipopt_finish)
    {
        int i;
        if(*ipopt_finish > 0)
            return 0;
        if(ipopt_type == IPOPT_EOL)
            *ipopt_finish = 1;
            return optlen + 1;
        if(ipopt_type == IPOPT_NOP)
            *(ipoptbuff) = 1;
            return optlen + 1;    if(optlen + 2 + ipopt_data_len > MAXIPOPTLEN)
        {
            fprintf(stderr, "ip options build error: options length exceeds MAXIPOPTLEN");
            exit(EXIT_FAILURE);
        }
        *(ipoptbuff ++) = ipopt_type;
        *(ipoptbuff ++) = ipopt_data_len + 2;
        for (i = 0; i < ipopt_data_len; i ++)
        {
            *(iptoptbuff ++) = *(data ++);
        }
        return optlen + 2 + (uint32_t)ipopt_data_len;
    }void mypcap_build_ipopt(uint8_t *packet)
    {
        uint8_t ipopt_finish = 0;
        uint32_t optlen = 0;
        struct iphdr *iphdr = (struct iphdr *)(packet + sizeof(struct ethhdr));
        uint8_t *ipoptbuff = packet + sizeof(struct ethhdr) + sizeof(struct iphdr);
        /* 这里用add_ipopt()函数填入各种option
        ... ...
        optlen = add_ipopt(IPOPT_EOL, 0, NULL, ipoptbuff, optlen, &ipopt_finish); //最后必须填充IPOPT_EOL    /* 创建iphdr,计算csum */
        ... ...
    }
    但是毕竟option是一种无固定结构的数据类型,我暂时无法设计出能适应所有结构的函数(主要是大小端的问题)。java我只是拿来和hadoop、elk交互和生成json,偶尔访问一下数据库,我肯定不会用它来做协议构造分析的开发,因为那是它的短板。就好像一般人不会拿管道煤气炉烧烤,除非是在是没有其它可以用,也不怕难吃(管道煤气有毒且有硫化物的臭味)
    所以其实我不熟悉java,也不喜欢java(其实不怪java,主要是一般公司里用java的没有别人提供的框架,就啥也不会干了<框架就是超市里卖的盒饭,除了会加热他啥也不会,但居然和别人说他是个厨子>),但个人认为除了汇编以外,语言没有高下之分,只有使用的人的区别。java虽然处理内核级的问题也许性能比c低点儿,但肯定提供了能处理这种简单问题的库,你只需要构造好报文数据结构。
    大致看了一下oracle java doc,没有找到raw socket,但有第三方提供的jpcap、jnetpcap等收发链路层的库。虽然我不太熟悉java,但我可以很肯定的说,如果是一个一年以上经验的誊写工来说,用java做你说的应该是没有难度,最多就是多看看手册。
    另外你说的socketoption应该和c里的setsockopt/getsockopt对应,这个在oracle java doc里已经提到,在C里这个函数里是可以设置IPPROTO_IP的IP_OPTINOS,也就是ip option,但看oracle java doc的文档StandardSocketOptions里没有实现这个,估计是因为没有实现raw socket所以没有对网络层的设置就做了限制,避免不可预测错误。
    最后再扯扯,ip options是需要设备和系统支持的,我不确定路由器等会不会把它丢弃,除非本身是做网络设备的,估计才会在ip options里下功夫,但用java做网络设备的底层?如果不是,那就真的没有必要在这里放自定义数据。
    用什么语言不重要,但至少应该把Ethernet、IP、TCP/UDP的数据结构和协议规范基本清晰。
      

  20.   

    SocketOptions这个只是java提供了几个固定的属性,对我感觉没有用。周围人跟我说先实现在tcp报文头部的options中添加信息,(我不是很明白这两种方式有什么区别吗,为什么别人口中tcp实现会比ip实现更容易些)试了jpcap,发现他抓取的报文是镜像包,我想要做的是要在手机app发送的每个请求中都增加自定义数据,raw socket 在跟jdk代码的时候并没有发现,最后跟到的方法是用native 声明的,应该是java 虚拟机去实现了最底层的东西,目前想的是尽量在变动不是很大的情况下实现,但是又一想会导致tcp 报文的校验和和总长度发生变化,觉得自己是在幻想了,不知道有什么意见没,指导指导~
      

  21.   

    ip的options和tcp的options单单从raw socket、pcap(linux C)或则jpcap、jnetpcap构造解析来说,只是不同类型的数据段,方法上基本类似,难易程度也没有太大区别。如果接收端也是用raw socket或jnetpcap库,应该也就没有太多不同。
    ip的options和tcp的options其意义的不同是在于如果接收端不是自定义的一些socket处理,比如它是一个标准的网络设备(路由、防火墙或移动核心网分组域设备)或则内核,那么其中标准的字段是有其特殊意义的,这点可以参考rfc文档或则man手册。
    因为我对java实现底层socket不熟悉,我只能从网络协议方面说说,一就是ip层处理的时候还没有tcp的端口号,也就是五元组不全,在这层处理的时候必然要自定义tcp这层的处理才能判断,影响延时。二是中间经过的不同厂家网络设备有可能修改ip报头(比如做NAT),可能去掉ip的options(这个我没有较复杂的网络环境做判断,所以无法肯定),但至少移动网络肯定是一个比较复杂的网络体系,并不像局域网和普通的互联网,它核心网分组域有很多的协议层次,你发送的报文在其中要经过GGSN、SGSN或SGW、PGW等设备的处理,而且牵涉到Moblie IP和漫游的处理,有多次隧道包装和头部修改,所以用tcp options信息保持的完整性会应该高于ip options。而且在c里,raw socket是可以只构造tcp数据结构,而把ip交给内核去处理,那么当然会节省一些代码。
    java的SocketOptions的标准选项仅仅是告诉内核socket收发缓存、组播、tos、ttl等应该采取的处理方式,并没有针对ip options和tcp options的字段填充和解析,所以肯定满足不了你的需求。至于校验和以及总长度用C的话都是自己定义函数计算然后填充,而jpcap是否有定义好的方法以及是否能够发送报文我就不清楚了。
      

  22.   

    我有一个思路,你可以把自己想要的字段添加到ip报文的数据段,(就是发送时将应用层传下来的数据偏移几个字节,用于添加自己的字段),接收方收到数据后,在IP层向上传之前,对这段数据进行处理,并且偏移回来