投射到 iphdr 和 tcphdr 的正确偏移量是多少?

What is the correct offset for casting to iphdr and tcphdr?

这是 recv() 的一个奇怪行为。 我正在使用 libnetfilter_queue 库和 iptables 以便将传入的数据包存储到三个不同的队列中,这取决于它们的源端口(我检查这个条件要感谢下面写的 iptables 规则)。

基本上,我收到的数据包的有效载荷总是包含字母 E。 这是我的代码(为简洁起见,我省略了对错误的控制)。

/* bunch of #include <whatineed.h> */

int main() {
    pthread_t threads[3];
    pthread_create(&threads[0], NULL, queueThread, (void *)0);
    pthread_create(&threads[1], NULL, queueThread, (void *)1);
    pthread_create(&threads[2], NULL, queueThread, (void *)2);
    pthread_exit(NULL);
    return 0;
}

每个线程执行的函数:

void *queueThread(void *queuenum) {
    int fd, rv;
    int queue_num = (int)queuenum;
    struct nfq_handle *h = NULL;
    struct nfq_q_handle *qh = NULL;
    char buf[8192] __attribute__ ((aligned));

    /* queue handling setup */
    h = nfq_open();
    nfq_unbind_pf(h, AF_INET);
    nfq_bind_pf(h, AF_INET);
    qh = nfq_create_queue(h, queue_num, &packetHandler, NULL);
    nfq_set_queue_maxlen(qh, 10000);
    nfq_set_mode(qh, NFQNL_COPY_PACKET, 0xffff);
    memset(buf, '[=11=]', sizeof(buf));
    /* Tried to increase socket buffer size, but nothing changes  */
    nfnl_rcvbufsiz(nfq_nfnlh(h), 10000 * 1500);
    fd = nfq_fd(h);
    while ((rv = recv(fd, buf, sizeof(buf), 0)) > 0))  {
        printf("queueThread: read %d bytes from file descriptor %d\n", rv, fd);
        nfq_handle_packet(h, buf, rv);
    }
    nfq_destroy_queue(qh);
    nfq_close(h);
    pthread_exit(NULL);
}

我从 queueThread:

获得的每个数据包调用的回调函数
int packetHandler(struct nfq_q_handle *qh, struct nfgenmsg *nfmsg,
    struct nfq_data *nfa, void *data) {
        struct nfqnl_msg_packet_hdr *ph = NULL;
        unsigned char *nf_packet = NULL;
        int pkt_size = 0;
        ph = nfq_get_msg_packet_hdr(nfa);
        int id = ntohl(ph -> packet_id);
        pkt_size = nfq_get_payload(nfa, &nf_packet);
        printf("packetHandler: pkt is %d byte, it says: %s\n", pkt_size, nf_packet);
        /* Let's check, e.g., its protocol */
        struct iphdr *iph = (struct iphdr *) (nf_packet + sizeof(struct ethhdr));
        printf("packetHandler: pkt protocol is %d\n", iph->protocol);
        return nfq_set_verdict(qh, id, NF_ACCEPT, 0, NULL);
}

iptables 上设置以下规则后:

sudo iptables -I INPUT -p tcp --sport 25 -j NFQUEUE --queue-num 0
sudo iptables -I INPUT -p tcp --sport 80 -j NFQUEUE --queue-num 1
sudo iptables -I INPUT -p udp --sport 5060 -j NFQUEUE --queue-num 2
sudo iptables -I INPUT -p tcp --sport 5060 -j NFQUEUE --queue-num 2

在我的浏览器上打开一个新标签并加载一个页面(因此,从端口 80 获取数据包),这是我的输出:

queueThread: read 148 bytes from file descriptor 4
packetHandler: pkt is 60 byte, it says: E 
packetHandler: pkt protocol is 35
queueThread: read 148 bytes from file descriptor 4
packetHandler: pkt is 60 byte, it says: E 
packetHandler: pkt protocol is 35
queueThread: read 148 bytes from file descriptor 4
packetHandler: pkt is 60 byte, it says: E 
packetHandler: pkt protocol is 35

我也尝试过 nping 通过在另一个终端向自己发送来自端口 25 和端口 5060 的数据包,结果是一样的:奇怪的协议号和字母 E。 我无法将有效载荷正确地转换为 tcphdrudphdr 结构并获取我需要的数据,因为我不知道我从 queueThread() 得到了什么以及我传递给 packetHandler().

显然,我的错误是将 sizeof(struct ethhdr) 添加到有效载荷以到达数据包的 IP header:这就是为什么我总是得到奇怪的协议和端口号,我在一个抵消我不应该去的地方。 仍然有 E 但没关系,我现在可以成功读取协议和端口号;抱歉让我分心了。

这是我发现这个的地方:How does nfq_get_payload structure its return data?