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

发布于 2024-11-29 12:23:45 字数 348 浏览 11 评论 0原文

我一直在用 C 编写一些套接字代码。我需要修改数据包标头并控制它们的发送方式,因此我采用了原始套接字方法。然而,我编写的代码无法在 BSD 系统(Mac OS X/Darwin、FreeBSD 等)上编译。

我对此进行了大量研究,发现 BSD 系统无法像 Linux 那样处理原始套接字(甚至 Windows)也可以。从我读到的内容来看,我似乎需要使用 bpf(伯克利数据包过滤器),但我无法弄清楚 bpf 是如何工作的,或者我将如何将它与原始套接字一起使用。

如果有人能阐明这一点,我会非常兴奋:D

P.S.我什至会对一些显示如何在 BSD 环境中处理原始套接字的源代码感到满意。它不一定是指南或解释。我只是想看看它是如何工作的。

I've been writing some sockets code in C. I need modify packet headers and control how they're sent out, so I took the raw sockets approach. However, the code I wrote will not compile on BSD systems (Mac OS X/Darwin, FreeBSD, etc.)

I've done a bunch of research on this and have found that BSD systems can't handle raw sockets the way Linux (or even Windows) does. From what I've read, it seems I need to use bpf (berkley packet filter), but I can't figure out how bpf works or how I would go about using it with raw sockets.

If someone could shed some light on this one, I'd be very excited :D

P.S. I'll even be happy with some source code showing how raw sockets are handled in a BSD environment. It doesn't have to be a guide or explanation. I just want to see how it works.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

浊酒尽余欢 2024-12-06 12:23:45

使用原始套接字并不难,但它并不完全可移植。例如,在 BSD 和 Linux 中,您都可以发送您想要的任何内容,但在 BSD 中,您无法接收任何具有处理程序的内容(例如 TCPUDP)。

下面是一个发送 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) 在数据包穿越您的系统时拦截它们并更改它们。

Using raw sockets isn't hard but it's not entirely portable. For instance, both in BSD and in Linux you can send whatever you want, but in BSD you can't receive anything that has a handler (like TCP and UDP).

Here is an example program that sends a 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;
}

Of course, more BSD-specific solutions are available. For instance you could use divert(4) to intercept packets as they traverse your system and alter them.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文