BSD操作系统上的原始套接字

4
我正在用C语言编写一些套接字代码,需要修改数据包头并控制它们的发送方式,因此我采用了原始套接字的方法。然而,我写的这段代码不能在BSD系统(如Mac OS X/Darwin、FreeBSD等)上编译。
我进行了大量的研究,并发现BSD系统无法像Linux(甚至Windows)那样处理原始套接字。据我所读,似乎我需要使用bpf(Berkley Packet Filter),但我无法弄清楚bpf的工作原理,也不知道该如何在原始套接字中使用它。
如果有人能为我解决这个问题,我会非常兴奋:D
另外,如果有源代码可以展示在BSD环境下如何处理原始套接字,我会感到非常高兴。它不必是一个指南或解释,我只想看看它是如何工作的。
1个回答

5
使用原始套接字并不难,但它并非完全可移植。例如,在BSD和Linux中,您都可以发送任何内容,但在BSD中,无法接收具有处理程序(如TCP和UDP)的内容。
以下是一个发送SYN的示例程序。
#include <sys/socket.h>
#include <sys/types.h>

#include <netdb.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>

#include <err.h>
#include <stdio.h>
#include <string.h>
#include <sysexits.h>

int
main(int argc, char *argv[])
{
    int s, rc;
    struct protoent *p;
    struct sockaddr_in sin;
    struct tcphdr tcp;

    if (argc != 2)
        errx(EX_USAGE, "%s addr", argv[0]);

    memset(&sin, 0, sizeof(sin));
    sin.sin_family = AF_INET;
    sin.sin_port = 0;

    /* Parse command line address. */
    if (inet_pton(AF_INET, argv[1], &sin.sin_addr) <= 0)
        err(EX_USAGE, "Parse address");

    /* Look up tcp although it's 6. */
    p = getprotobyname("tcp");
    if (p == NULL)
        err(EX_UNAVAILABLE, "getprotobyname");

    /* Make a new shiny (Firefly) socket. */
    s = socket(AF_INET, SOCK_RAW, p->p_proto);
    if (s < 0)
        err(EX_OSERR, "socket");

    memset(&tcp, 0, sizeof(tcp));

    /* Fill in some random stuff. */
    tcp.th_sport = htons(4567);
    tcp.th_dport = htons(80);
    tcp.th_seq = 4; /* Chosen by fair dice roll. */
    tcp.th_ack = 0;
    tcp.th_off = 5;
    tcp.th_flags = TH_SYN;
    tcp.th_win = htonl(65535);

    rc = sendto(s, &tcp, sizeof(tcp), 0, (struct sockaddr *)&sin,
        sizeof(sin));

    printf("Wrote %d bytes\n", rc);

    return 0;
}

当然,还有更多特定于BSD的解决方案可用。例如,您可以使用divert(4)在数据包穿过系统时拦截并修改它们。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接