【问题标题】:Modify header of a captured packet修改抓包头
【发布时间】:2014-04-11 15:04:03
【问题描述】:

我正在尝试使用 libnetfiletr_queue 修改 IP 标头以包含更多 IP 选项。到目前为止,我已经成功地获得了如下所示的数据包。

if (nfq_set_mode(qh, NFQNL_COPY_PACKET, 0xffff) < 0) {
    fprintf(stderr, "Unable to set nfq_set_mode\n");
    exit(1);
}

然后我设法走远了,如下所示,

static int my_callBack(struct nfq_q_handle *qh, struct nfgenmsg *nfmsg,struct nfq_data *tb)
{   
    int id = 0;
    int packet_len;
    unsigned char *data;
    struct nfqnl_msg_packet_hdr *packet_hdr;
    unsigned char *data;

    packet_hdr = nfq_get_msg_packet_hdr(tb);

    if (packet_hdr) {
        id = ntohl(packet_hdr->packet_id);          
    }

    packet_len = nfq_get_payload(tb, &data);

    if (packet_len >= 0) {
        //print payload length
        printf("payload_length = %d ", packet_len);
        //modify packet ip header  
    }

    return nfq_set_verdict(qh, id, NF_ACCEPT, 0, NULL);
}

但是从这里开始,我对如何继续修改//modify packet ip header 注释处捕获的数据包的IP header 有点困惑。修改IP 标头的示例(例如流量类(IPV6)/ IP选项/版本/标志/目标地址)是可以的,因为我只需要了解修改是如何工作的:)。

我尝试了很多资源,但无法继续进行。非常感谢您对此查询的专家建议和帮助。 :)

非常感谢:)

【问题讨论】:

  • 根据documentationnfq_get_payload 将使data 指向有效负载的第一个字节(可能是IP 标头)。您可以随意修改和读取/解析它。 libnetfilter 不公开允许您这样做的函数。
  • @MichaelFoukarakis 谢谢你的评论 :) 这也是我被困在这里的原因。 :) 也因为我对这个领域比较陌生,我没有足够的信息来做任何试错实验,因此求助于你的专家敌人帮助:) 知道如何操作会很棒标题,以便我可以做一些实验并实现我的目标:)
  • 好吧,从文档开始。您可以找到 IPv4 here 的描述。阅读 RFC。如果您在极端情况下遇到问题,请查看 SnortWireshark 之类的代码,了解它们是如何解析的。这是一个非常广泛的问题。
  • @MichaelFoukarakis 好的先生...谢谢你检查:)

标签: c linux linux-kernel network-programming netfilter


【解决方案1】:

要修改 IP 标头的值,首先要定义一个结构来表示您的标头。通过阅读您尝试访问的协议的 RFC 规范,您可以找到结构应该是什么。

这里是 IPv6 RFC 的链接:https://www.rfc-editor.org/rfc/rfc2460#section-3

IPv6 标头的第一行有点棘手,因为它们没有使用字节对齐字段。版本字段为 4 位宽,流量类别为 8 位宽,流标签为 20 位宽。整个标头是 320 位(40 字节),其中 256 位是 src 和 dest 地址。其他字段仅使用 64 位,因此像这样定义结构可能是最简单的:

struct ipv6_hdr {
    uint32_t row1;
    uint16_t payload_length;
    uint8_t next_header;
    uint8_t hop_limit;
    uint16_t src[8];
    uint16_t dest[8];
};

要提取第一行的值,您可以使用一些掩码:

#define VERSION_MASK 0xF0000000
#define TRAFFIC_CLASS_MASK 0x0FF00000
#define FLOW_LABEL_MASK 0x000FFFFF

struct ipv6_hdr foo;

...

nfq_get_payload(tb, &foo); // Just an example; don't overflow your buffer!

// bit-wise AND gets masked field from row1
uint8_t version = (uint8_t) ((foo->row1 & VERSION_MASK) >> 28);  // shift (32-4) bits

一旦你将你的结构指向数据负载,假设你的字节数组匹配这种格式,修改标题值就变成了简单的赋值:

version = 6;

// bit-wise OR puts our value in the right place in row1
foo->row1 &= ~(VERSION_MASK) // clear out the old value first
foo->row1 = ((uint32_t) version << 28) | foo->row1;  

我选择将结构中的 src 和 dest 地址设为 16 位值的数组,因为 IPv6 地址是一系列 8 个 16 位值。这应该可以很容易地隔离任何给定的字节对。

在应用适当的结构之前,您必须确定数据负载的格式。

有关如何创建 IPv4 标头的信息,请查看其 RFC:https://www.rfc-editor.org/rfc/rfc791#section-3.1

希望这会有所帮助(您可能不得不摆弄我的代码示例以使语法正确,已经几个月了)。


使用 cmets 中要求的校验和信息进行编辑

在修改您的标头后按照此 RFC 生成校验和:https://www.rfc-editor.org/rfc/rfc1071

关键是在生成新校验和之前将标头中的校验和字段归零。

【讨论】:

  • 感谢您的描述性回答!我将检查此示例并回发。非常感谢:) +1
  • 嗨,只是一个小问题......如果我需要根据变化修改校验和......有没有办法做到这一点:)再次感谢:)
  • 我在回答帖子的末尾添加了一些关于校验和的简短信息
  • 非常感谢您的帮助:)
  • 您好,您的回答使我在项目中取得了最高的进展,非常感谢您。如果问的不是太多,您可以添加一个从中获取源/目标 IP 的示例数据包?我有点困惑,非常感谢您的帮助:)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-07-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-11-01
  • 2014-04-12
相关资源
最近更新 更多