是否有可能在数据包数据到达接口之前和接收之后拦截数据包数据?例如,对其进行预处理并将其送回原路?
我想创建一个自定义解决方案,例如这个很棒的程序叫做 vtun。它创建一个充当接口的虚拟设备。这使其能够执行各种操作,例如流量压缩、加密、整形等。
我想知道现在是否可以更容易地完成(vtun 已经很旧了......)。我的目标操作系统是 Ubuntu 14.04。
答案1
是的,Linux 内核的 Netfilter 框架足够灵活,足以使这成为可能。
我不知道你的期望是什么“定制解决方案”和“如果现在可以做得更容易的话”。我假设您准备编写代码来进行低级数据包处理。
总体思路如下:
- 创建
iptables
规则,将流量从所需的表 (filter
、nat
、mangle
) 通过目标传递到用户空间QUEUE
。 - 您将能够使用以下命令访问发送到队列的数据包libnetfilter_queue图书馆或nfqueue 绑定(如果您使用 Perl 或 Python)。
- 按照您认为合适的方式处理数据包并将其按原路发送回去。
请记住,您将使用原始 IP 数据包、TCP 分段或 UDP 数据报(取决于您要处理的流量类型),并且您有责任正确地重新组装流量、维护数据包级别的校验和正确性以及操作系统的 TCP/IP 堆栈在幕后神奇地处理的所有其他事情。
答案2
这是使用 @dkaragasidis 建议的示例代码。它读取数据包数据并将其传递。您可以在处理函数中修改数据包。
编译:-lnetfilter_queue -lnfnetlink
添加规则(示例):sudo iptables -A OUTPUT -p udp --dport 4444 -j NFQUEUE --queue-num 0
删除规则(示例):sudo iptables -D OUTPUT -p udp --dport 4444 -j NFQUEUE --queue-num 0
测试:nc -lu 4444
和nc -u YOUR_IP 4444
#include <netinet/in.h>
#include <linux/netfilter.h>
#include <libnetfilter_queue/libnetfilter_queue.h>
#include <stdio.h>
int handler(struct nfq_q_handle *myQueue, struct nfgenmsg *msg, struct nfq_data *pkt, void *cbData) {
int id = 0;
struct nfqnl_msg_packet_hdr *header;
if( header = nfq_get_msg_packet_hdr(pkt) )
id = ntohl(header->packet_id);
unsigned char *pktData;
int len = nfq_get_payload(pkt, &pktData);
printf("data[ %d ]:\n", len);
int i;
for (i = 0; i < len; i++)
printf("%2d 0x%02x %3d %c\n", i, pktData[i], pktData[i], pktData[i]);
printf("\n");
return nfq_set_verdict(myQueue, id, NF_ACCEPT, len, pktData);
}
int main(int argc, char **argv) {
struct nfq_handle *nfqHandle;
struct nfq_q_handle *myQueue;
struct nfnl_handle *netlinkHandle;
int fd, res;
char buf[4096];
// queue connection
if (!(nfqHandle = nfq_open())) {
perror("Error in nfq_open()");
return(-1);
}
// bind this handler
if (nfq_bind_pf(nfqHandle, AF_INET) < 0) {
perror("Error in nfq_bind_pf()");
return(1);
}
// define a handler
if (!(myQueue = nfq_create_queue(nfqHandle, 0, &handler, NULL))) {
perror("Error in nfq_create_queue()");
return(1);
}
// turn on packet copy mode
if (nfq_set_mode(myQueue, NFQNL_COPY_PACKET, 0xffff) < 0) {
perror("Could not set packet copy mode");
return(1);
}
netlinkHandle = nfq_nfnlh(nfqHandle);
fd = nfnl_fd(netlinkHandle);
while ((res = recv(fd, buf, sizeof(buf), 0)) && res >= 0)
nfq_handle_packet(nfqHandle, buf, res);
nfq_destroy_queue(myQueue);
nfq_close(nfqHandle);
return 0;
}