转换为iphdr和tcphdr的正确偏移量是多少?

时间:2015-07-16 17:44:27

标签: c network-programming netfilter

这是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, '\0', 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()得到了什么以及我传递给{{{ 1}}。

1 个答案:

答案 0 :(得分:0)

显然,我的错误是将sizeof(struct ethhdr)添加到有效负载以便到达数据包的IP头:这就是为什么我总是得到奇怪的协议和端口号,我在偏移的地方我不应该。 仍然得到E但是没关系,我现在可以阅读成功的协议和端口号;对不起我的分心。

我在这里找到了这个:How does nfq_get_payload structure its return data?