如何安全地将数据附加到 IPTables 目标的 sk_buff
How can I safely append data to a sk_buff for IPTables target
我正在开发一个 Linux 内核模块,它需要修改网络数据包并附加一个额外的 header。我已经实现了修改部分,重新计算了 check-sums 并且效果很好。但我不知道如何安全地附加一个额外的 header。如果我的输入数据包是这样的:
ip-header / tcp-header / data
我想要一个像这样的输出数据包:
ip-header / tcp-header / my-header / data
根据我的阅读,我认为我需要类似以下代码的内容。我在代码上写下了我的具体问题作为评论。我一般关心的是,如果我在这里编写的代码是 memory-safe,或者我应该如何使用 memory-safe 方法来附加新的 header。另外,如果我做错了什么或者有更好的方法,我也会感谢您的评论。我试图找到例子,但到目前为止没有运气。这是代码:
static unsigned int my_iptables_target(struct sk_buff *skb, const struct xt_action_param *par) {
const struct xt_mytarget_info *info = par->targinfo;
/* Some code ... */
if (!skb_make_writable(skb, skb->len)) {
//Drop the packet
return NF_DROP;
}
struct newheader* myheader;
// Check if there is enough space and do something about it
if (skb_headroom(skb) < sizeof(struct newheader)) {
// So there is no enugh space.
/* I don't know well what to put here. I read that a function called pskb_expand_head might
* do the job. I do not understand very well how it works, or why it might fail (return value
* different from zero). Does this code work:
*/
if (pskb_expand_head(skb, sizeof(struct newheader) - skb_headroom(skb), 0, GPF_ATOMIC) != 0) {
// What does it mean if the code reaches this point?
return NF_DROP;
}
}
// At this point, there should be enough space
skb_push(skb, sizeof(struct newheader));
/* I also think that skb_push() creates space at the beggining, to open space between the header and
* the body I guess I must move the network/transport headers up. Perhaps something like this:
*/
memcpy(skb->data, skb->data + sizeof(struct newheader), size_of_all_headers - sizeof(struct newheader));
// Then set myheader address and fill data.
myheader = skb->data + size_of_all_headers;
//Then just set the new header, and recompute checksums.
return XT_CONTINUE;
}
我假定变量 size_of_all_headers
包含网络和传输 header 的字节大小。我还认为 memcpy
以递增顺序复制字节,因此调用应该不是问题。那么上面的代码行得通吗?都是memory-safe?有更好的方法吗?有没有这样的例子(或者你能提供一个)吗?
我使用了与问题中的代码类似的代码,到目前为止,它在我完成的所有测试中都运行良好。为了回答一些具体问题,我使用了类似的东西:
if (skb_headroom(skb) < sizeof(struct newheader)) {
printk("I got here!\n");
if (pskb_expand_head(skb, sizeof(struct newheader) - skb_headroom(skb), 0, GPF_ATOMIC) != 0) {
printk("And also here\n");
return NF_DROP;
}
}
但是 none 的打印语句曾经执行过。我想发生这种情况是因为 OS 在内存中保留了足够的 space,因此在 IP header 的限制下不会出现问题。但我认为最好保留 if 语句以在必要时增加数据包。
我测试和运行的代码的另一个区别是,我没有移动所有其他 header 来为我的 header 创建一个 space,而是选择将数据包的 body 向下移动。
我正在开发一个 Linux 内核模块,它需要修改网络数据包并附加一个额外的 header。我已经实现了修改部分,重新计算了 check-sums 并且效果很好。但我不知道如何安全地附加一个额外的 header。如果我的输入数据包是这样的:
ip-header / tcp-header / data
我想要一个像这样的输出数据包:
ip-header / tcp-header / my-header / data
根据我的阅读,我认为我需要类似以下代码的内容。我在代码上写下了我的具体问题作为评论。我一般关心的是,如果我在这里编写的代码是 memory-safe,或者我应该如何使用 memory-safe 方法来附加新的 header。另外,如果我做错了什么或者有更好的方法,我也会感谢您的评论。我试图找到例子,但到目前为止没有运气。这是代码:
static unsigned int my_iptables_target(struct sk_buff *skb, const struct xt_action_param *par) {
const struct xt_mytarget_info *info = par->targinfo;
/* Some code ... */
if (!skb_make_writable(skb, skb->len)) {
//Drop the packet
return NF_DROP;
}
struct newheader* myheader;
// Check if there is enough space and do something about it
if (skb_headroom(skb) < sizeof(struct newheader)) {
// So there is no enugh space.
/* I don't know well what to put here. I read that a function called pskb_expand_head might
* do the job. I do not understand very well how it works, or why it might fail (return value
* different from zero). Does this code work:
*/
if (pskb_expand_head(skb, sizeof(struct newheader) - skb_headroom(skb), 0, GPF_ATOMIC) != 0) {
// What does it mean if the code reaches this point?
return NF_DROP;
}
}
// At this point, there should be enough space
skb_push(skb, sizeof(struct newheader));
/* I also think that skb_push() creates space at the beggining, to open space between the header and
* the body I guess I must move the network/transport headers up. Perhaps something like this:
*/
memcpy(skb->data, skb->data + sizeof(struct newheader), size_of_all_headers - sizeof(struct newheader));
// Then set myheader address and fill data.
myheader = skb->data + size_of_all_headers;
//Then just set the new header, and recompute checksums.
return XT_CONTINUE;
}
我假定变量 size_of_all_headers
包含网络和传输 header 的字节大小。我还认为 memcpy
以递增顺序复制字节,因此调用应该不是问题。那么上面的代码行得通吗?都是memory-safe?有更好的方法吗?有没有这样的例子(或者你能提供一个)吗?
我使用了与问题中的代码类似的代码,到目前为止,它在我完成的所有测试中都运行良好。为了回答一些具体问题,我使用了类似的东西:
if (skb_headroom(skb) < sizeof(struct newheader)) {
printk("I got here!\n");
if (pskb_expand_head(skb, sizeof(struct newheader) - skb_headroom(skb), 0, GPF_ATOMIC) != 0) {
printk("And also here\n");
return NF_DROP;
}
}
但是 none 的打印语句曾经执行过。我想发生这种情况是因为 OS 在内存中保留了足够的 space,因此在 IP header 的限制下不会出现问题。但我认为最好保留 if 语句以在必要时增加数据包。
我测试和运行的代码的另一个区别是,我没有移动所有其他 header 来为我的 header 创建一个 space,而是选择将数据包的 body 向下移动。