在不使用环回网络的情况下将数据包转发到同一主机中的服务

2024-02-18

我有这个 libnetfilter_queue 应用程序,它根据某些 iptables 规则从内核接收数据包。在直接讨论我的问题之前,我提供了一个示例可行代码和其他工具来设置测试环境,以便我们的问题定义和可能的解决方案可以更加准确和稳健。

以下代码描述了该应用程序的核心功能:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <netinet/in.h>
#include <linux/types.h>
#include <linux/netfilter.h>    /* for NF_ACCEPT */
#include <errno.h>

#include <libnetfilter_queue/libnetfilter_queue.h>
#define PREROUTING 0
#define POSTROUTING 4
#define OUTPUT 3


/* returns packet id */
static u_int32_t
print_pkt (struct nfq_data *tb)
{
  int id = 0;
  struct nfqnl_msg_packet_hdr *ph;
  struct nfqnl_msg_packet_hw *hwph;
  u_int32_t mark, ifi;
  int ret;
  unsigned char *data;

  ph = nfq_get_msg_packet_hdr (tb);
  if (ph)
    {
      id = ntohl (ph->packet_id);
      printf ("hw_protocol=0x%04x hook=%u id=%u ",
          ntohs (ph->hw_protocol), ph->hook, id);
    }

  hwph = nfq_get_packet_hw (tb);
  if (hwph)
    {
      int i, hlen = ntohs (hwph->hw_addrlen);

      printf ("hw_src_addr=");
      for (i = 0; i < hlen - 1; i++)
    printf ("%02x:", hwph->hw_addr[i]);
      printf ("%02x ", hwph->hw_addr[hlen - 1]);
    }

  mark = nfq_get_nfmark (tb);
  if (mark)
    printf ("mark=%u ", mark);

  ifi = nfq_get_indev (tb);
  if (ifi)
    printf ("indev=%u ", ifi);

  ifi = nfq_get_outdev (tb);
  if (ifi)
    printf ("outdev=%u ", ifi);
  ifi = nfq_get_physindev (tb);
  if (ifi)
    printf ("physindev=%u ", ifi);

  ifi = nfq_get_physoutdev (tb);
  if (ifi)
    printf ("physoutdev=%u ", ifi);

  ret = nfq_get_payload (tb, &data);
  if (ret >= 0)
    printf ("payload_len=%d ", ret);

  fputc ('\n', stdout);

  return id;
}


static int
cb (struct nfq_q_handle *qh, struct nfgenmsg *nfmsg,
    struct nfq_data *nfa, void *data)
{
  uint32_t ip_src, ip_dst;
  struct in_addr s_ip;
  struct in_addr d_ip;
  uint16_t src_port;
  uint16_t dst_port;
  int verdict;
  int id;
  int ret;
  unsigned char *buffer;
  struct nfqnl_msg_packet_hdr *ph = nfq_get_msg_packet_hdr (nfa);
  if (ph)
    {
      id = ntohl (ph->packet_id);
      printf ("received packet with id %d", id);
    }
  ret = nfq_get_payload (nfa, &buffer);
  ip_src = *((uint32_t *) (buffer + 12));
  ip_dst = *((uint32_t *) (buffer + 16));
  src_port = *((uint16_t *) (buffer + 20));
  dst_port = *((uint16_t *) (buffer + 22));
  s_ip.s_addr = (uint32_t) ip_src;
  d_ip.s_addr = (uint32_t) ip_dst;
  *(buffer + 26) = 0x00;
  *(buffer + 27) = 0x00;
  printf ( "source IP %s", inet_ntoa (s_ip));
  printf ( "destination IP %s", inet_ntoa (d_ip));
  printf ( "source port %d", src_port);
  printf ( "destination port %d", dst_port);
  if (ret)
    {
      switch (ph->hook)
    {
    case PREROUTING:
      printf ( "inbound packet");
      //my_mangling_fun();
      break;
    case OUTPUT:
      printf ( "outbound packet");
      //my_mangling_fun();
      break;
    }
    }
  verdict = nfq_set_verdict (qh, id, NF_ACCEPT, ret, buffer);
  if (verdict)
    printf ( "verdict ok");
  return verdict;
}

int
main (int argc, char **argv)
{
  struct nfq_handle *h;
  struct nfq_q_handle *qh;
  struct nfnl_handle *nh;
  int fd;
  int rv;
  char buf[4096] __attribute__ ((aligned));

  printf ("opening library handle\n");
  h = nfq_open ();
  if (!h)
    {
      fprintf (stderr, "error during nfq_open()\n");
      exit (1);
    }

  printf ("unbinding existing nf_queue handler for AF_INET (if any)\n");
  if (nfq_unbind_pf (h, AF_INET) < 0)
    {
      fprintf (stderr, "error during nfq_unbind_pf()\n");
      exit (1);
    }

  printf ("binding nfnetlink_queue as nf_queue handler for AF_INET\n");
  if (nfq_bind_pf (h, AF_INET) < 0)
    {
      fprintf (stderr, "error during nfq_bind_pf()\n");
      exit (1);
    }

  printf ("binding this socket to queue '0'\n");
  qh = nfq_create_queue (h, 0, &cb, NULL);
  if (!qh)
    {
      fprintf (stderr, "error during nfq_create_queue()\n");
      exit (1);
    }

  printf ("setting copy_packet mode\n");
  if (nfq_set_mode (qh, NFQNL_COPY_PACKET, 0xffff) < 0)
    {
      fprintf (stderr, "can't set packet_copy mode\n");
      exit (1);
    }

  fd = nfq_fd (h);

  for (;;)
    {
      if ((rv = recv (fd, buf, sizeof (buf), 0)) >= 0)
    {
      printf ("pkt received\n");
      nfq_handle_packet (h, buf, rv);
      continue;
    }
      /* if your application is too slow to digest the packets that
       * are sent from kernel-space, the socket buffer that we use
       * to enqueue packets may fill up returning ENOBUFS. Depending
       * on your application, this error may be ignored. Please, see
       * the doxygen documentation of this library on how to improve
       * this situation.
       */
      if (rv < 0 && errno == ENOBUFS)
    {
      printf ("losing packets!\n");
      continue;
    }
      perror ("recv failed");
      break;
    }

  printf ("unbinding from queue 0\n");
  nfq_destroy_queue (qh);

#ifdef INSANE
  /* normally, applications SHOULD NOT issue this command, since
   * it detaches other programs/sockets from AF_INET, too ! */
  printf ("unbinding from AF_INET\n");
  nfq_unbind_pf (h, AF_INET);
#endif

  printf ("closing library handle\n");
  nfq_close (h);

  exit (0);
}

请注意,在回调函数中,对 my_mangling_fun() 的两次调用被注释掉了。这是我破坏传入和传出数据包的地方。我认为这段代码足以描述我的情况。如果需要进一步澄清,请询问,我将发布更多详细信息。

假设随附的 iptables 规则如下:

$iptables -t mangle -A PREROUTING -p udp --dport 5000 -j NFQUEUE
$iptables -t mangle -A OUTPUT -p udp --sport 5000 -j NFQUEUE

让我们编译并启动 udp 吧。

$gcc -g3 nfq_test.c -lnfnetlink -lnetfilter_queue
$./a.out (should be as root)

现在我们可以通过 netcat 客户端和服务器模式将垃圾 udp 有效负载提供给这个东西

$nc -ul 5000
$nc -uvv <IP> 5000

这将在标准输出中打印来自我的 netfilter_queue 应用程序的数据包。现在开发环境已经搭建完毕,我们可以进行下一步了。

我们想要实现的目标如下:

我们的服务器正在监听 5000 端口。现在,所有发往 udp 端口​​ 5000 的传入数据包将由内核排队。该队列的句柄将提供给我们前面列出的用户应用程序。这种队列机制的工作原理如下:当数据包可用时,调用回调函数(在我们的代码中为 cb())。处理完成后,回调函数调用nfq_set_verdict()。之后verdict返回后,下一个数据包将从队列中弹出。请注意,如果前一个数据包尚未得到判决,则该数据包不会从队列中弹出。该判决值为 NF_ACCEPT(接受数据包)、NF_DROP(丢弃数据包)。

现在,如果我想连接传入和传出数据包的 udp 有效负载而不接触客户端和服务器端代码怎么办?

如果我想从我们的应用程序(这个应用程序)连接 udp 有效负载,那么我们手头需要有多个数据包。但我们已经看到,在对前一个数据包做出判决之前,数据包不会从队列中弹出。

那么如何才能做到这一点呢?

一种可能的解决方案是向每个数据包发出 NF_DROP 并将这些数据包保存在中间数据结构中。假设我们已经做到了。但是这个数据包如何传递到监听 5000 端口的服务呢?

我们不能使用网络堆栈来传递数据包,因为如果这样做,数据包将再次进入 NFQUEUE。

另一个问题是,服务器完全不知道这个应用程序。这意味着它不应该看到数据包有任何差异。它应该看到数据包,就像它来自原始客户端一样。

我听说应用程序可以通过编写一些文件来将数据发送到同一主机中的服务器,而无需使用网络层(ip,端口)。我不知道这个说法的有效性。但如果有人知道任何关于它的事情,那就太好了。

我可能会因为过于冗长而被投票。但我认为这会是一次有趣的会议。我们可以一起找到解决方案:)


我提出以下解决方案:

  • 将数据包存储在应用程序中并返回判决 NF_DROP
  • 使用原始套接字将数据包重新注入网络堆栈
  • 使用 DSCP 标记串联的 UDP 数据包(请参阅 IP 数据包格式)
  • 在 iptables 中,添加一条规则来匹配此 DSCP (--dscp) 并直接接受数据包,而不通过您的 netfilter 应用程序

如果您的提供商已经使用 DSCP 标记了某些数据包,您可以添加一些 iptables 规则来清除它们,例如:

iptables -t mangle -A INPUT -j DSCP --set-dscp 0

我希望这能解决您的用例。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

在不使用环回网络的情况下将数据包转发到同一主机中的服务 的相关文章

  • 如何进行带有偏差的浮点舍入(始终向上或向下舍入)?

    我想以偏置舍入浮动 要么总是向下 要么总是向上 代码中有一个特定的点 我需要这个 程序的其余部分应该像往常一样四舍五入到最接近的值 例如 我想四舍五入到最接近的 1 10 倍数 最接近 7 10 的浮点数约为 0 69999998807 但
  • 当我单击 C# 中的“取消”按钮时重定向到新页面(Web 部分)

    Cancel button tc new TableCell btnCancel new Button btnCancel Text Cancel btnCancel Click new EventHandler btnCanel Clic
  • 在 OpenCL 中将函数作为参数传递

    是否可以在 OpenCL 1 2 中将函数指针传递给内核 我知道可以用C实现 但不知道如何在OpenCL的C中实现 编辑 我想做这篇文章中描述的同样的事情 在 C 中如何将函数作为参数传递 https stackoverflow com q
  • 捕获 foreach 条件中抛出的异常

    我有一个foreach在 foreach 本身的条件下循环期间中断的循环 有没有办法try catch抛出异常然后继续循环的项 这将运行几次 直到异常发生然后结束 try foreach b in bees exception is in
  • Guid 应包含 32 位数字和 4 个破折号

    我有一个包含 createuserwizard 控件的网站 创建帐户后 验证电子邮件及其验证 URL 将发送到用户的电子邮件地址 但是 当我进行测试运行时 单击电子邮件中的 URL 时 会出现以下错误 Guid should contain
  • ZLIB 解压缩

    我编写了一个小型应用程序 该应用程序应该解压缩以 gzip deflate 格式编码的数据 为了实现这一点 我使用 ZLIB 库 使用解压缩功能 问题是这个功能不起作用 换句话说 数据不是未压缩的 我在这里发布代码 int decompre
  • 在 C# 中将位从 ulong 复制到 long

    所以看来 NET 性能计数器类型 http msdn microsoft com en us library system diagnostics performancecounter aspx有一个恼人的问题 它暴露了long对于计数器
  • 转到 C# WPF 中的第一页

    我正在 WPF 中使用导航服务 为了导航到页面 我使用 this NavigationService Navigate new MyPage 为了返回我使用 this NavigationService GoBack 但是如何在不使用的情况
  • Xamarin Android:获取内存中的所有进程

    有没有办法读取所有进程 而不仅仅是正在运行的进程 如果我对 Android 的理解正确的话 一次只有一个进程在运行 其他所有进程都被冻结 后台进程被忽略 您可以使用以下代码片段获取当前正在运行的所有 Android 应用程序进程 Activ
  • 范围和临时初始化列表

    我试图将我认为是纯右值的内容传递到范围适配器闭包对象中 除非我将名称绑定到初始值设定项列表并使其成为左值 否则它不会编译 这里发生了什么 include
  • 组合框项目为空但数据源已满

    将列表绑定到组合框后 其 dataSource Count 为 5 但组合框项目计数为 0 怎么会这样 我习惯了 Web 编程 而且这是在 Windows 窗体中进行的 所以不行combo DataBind 方法存在 这里的问题是 我试图以
  • C# 编译器如何决定发出可重定向的程序集引用?

    NET Compact Framework 引入了可重定向程序集引用 现在用于支持可移植类库 基本上 编译器会发出以下 MSIL assembly extern retargetable mscorlib publickeytoken 7C
  • “MyClass”的类型初始值设定项引发异常

    以下是我的Windows服务代码 当我调试代码时 我收到错误 异常 CSMessageUtility CSDetails 的类型初始值设定项引发异常 using System using System Collections Generic
  • 如何排列表格中的项目 - MVC3 视图 (Index.cshtml)

    我想使用 ASP NET MVC3 显示特定类型食品样本中存在的不同类型维生素的含量 如何在我的视图 Index cshtml 中显示它 an example 这些是我的代码 table tr th th foreach var m in
  • 如何在 shell 脚本中并行运行多个实例以提高时间效率[重复]

    这个问题在这里已经有答案了 我正在使用 shell 脚本 它读取 16000 行的输入文件 运行该脚本需要8个多小时 我需要减少它 所以我将其划分为 8 个实例并读取数据 其中我使用 for 循环迭代 8 个文件 并在其中使用 while
  • Silverlight Datagrid:在对列进行排序时突出显示整个列

    我的 Silverlight 应用程序中有一个 DataGrid 我想在对该列进行排序时突出显示整个列 它在概念上与上一个问题类似 Silverlight DataGrid 突出显示整列 https stackoverflow com qu
  • 32位PPC rlwinm指令

    我在理解上有点困难rlwinmPPC 汇编指令 旋转左字立即然后与掩码 我正在尝试反转函数的这一部分 rlwinm r3 r3 0 28 28 我已经知道什么了r3 is r3在本例中是一个 4 字节整数 但我不确定这条指令到底是什么rlw
  • 为什么 Linux perf 使用事件 l1d.replacement 来处理 x86 上的“L1 dcache misses”?

    在英特尔 x86 上 Linux用途 https stackoverflow com a 52172985 149138事件l1d replacements来实施其L1 dcache load misses event 该事件定义如下 计数
  • 我应该在应用程序退出之前运行 Dispose 吗?

    我应该在应用程序退出之前运行 Dispose 吗 例如 我创建了许多对象 其中一些对象具有事件订阅 var myObject new MyClass myObject OnEvent OnEventHandle 例如 在我的工作中 我应该使
  • Azure函数版本2.0-应用程序blobTrigger不工作

    我有一个工作功能应用程序 它有一个 blob 输入和一个事件中心输出 在测试版中工作 随着最新的更改 我的功能不再起作用 我尝试根据发行说明更新 host json 文件 但它没有引用 blob 触发器 version 2 0 extens

随机推荐

  • ASP.NET MVC 和 IIS 5

    让 ASP NET MVC 应用程序托管在 IIS 5 6 或 7 上运行的最佳方法是什么 当我尝试发布 ASP NET MVC 应用程序时 我收到的似乎只是 404 错误 我做了一些谷歌搜索并找到了一些解决方案 但看起来都不是超级优雅 而
  • 如何从 Jena API Eclipse 项目启动 Fuseki 服务器?

    您好 我也是语义 Web 域和 Apache Jena 环境的新手 这就是我发布此问题的原因 我有一个使用 Jena API 的项目 当我运行它时 它会在控制台中显示输出 我确实从命令行运行了 Fuseki 服务器 它作为本地服务器运行 我
  • 运行 crontab 时出现权限被拒绝错误[重复]

    这个问题在这里已经有答案了 我在文件夹 csv file 中创建了一个 r 脚本 marc Marc Linux csv file ls 8388 26580527145 csv csv file Rproj excel source wr
  • Spark Dataframes UPSERT 到 Postgres 表

    我正在使用 Apache Spark DataFrames 来连接两个数据源并将结果作为另一个 DataFrame 获取 我想将结果写入另一个 Postgres 表 我看到这个选项 myDataFrame write jdbc url ta
  • Postman - 使用密钥文件进行 JWT 身份验证

    我正在尝试使用 Postman 来测试在 Google Cloud Platform 上开发的 API API 端点后面的 App Engine 我有 JSON 格式的密钥文件 type service account project id
  • BlackBerry 是否支持其应用程序开发人员的演示/测试版?

    我有兴趣为 BlackBerry 设备开发应用程序 想知道他们是否支持应用程序开发人员的演示版或测试版概念 我的意思是能够将我的应用程序的测试版或演示版部署给有限 受限的受众 例如业务合作伙伴 客户 外部测试人员等 他们中没有任何内容测试和
  • ASP.NET MVC - 如何抛出类似于 StackOverflow 上的 404 页面

    我目前有一个继承自的 BaseController 类System Web Mvc Controller 在那堂课上我有HandleError将用户重定向到 500 哎呀 我们搞砸了 页面的属性 目前这正在按预期进行 这有效
  • 让标签参与控制选项卡

    我有继承自的自定义控件Label并且有ControlStyle Selectable set to true 当用户单击该控件时 该控件将获得焦点 但如果用户从另一个控件进行选项卡 则不会获得焦点 即使当我有一个仅由该类型的控件填充的表单时
  • Reactjs 光滑的幻灯片

    我正在使用reactjs制作一个非常简单的滑块reactstrap 引导程序 工作示例 https codesandbox io s compassionate brook fz5mm https codesandbox io s comp
  • 尝试找出从 Firestore 字典中删除元素的更好方法

    我在应用程序中使用 Firestore 并且有一个名为 投票 的地图字段 用于显示用户的赞成票或反对票 它看起来像这样 我想添加一个选项来从那里删除元素 这就是我现在得到的 getting the user s votes dictiona
  • 将光标后的文本移动到新行

    我是 Vim 新手 我在 OSX Snow Leopard 上使用 MacVim 我必须采取的最常见操作之一是将光标移动到新行 并将光标后面的文本移动到新行 我知道在正常或可视模式下按 o 会将光标移动到新行并切换模式以进行插入 我想做的是
  • 注入和资源以及自动装配注释

    有什么区别 Inject and Resource and Autowired注释 我们什么时候应该使用它们 Inject Autowire Resource 之间的区别 自动连线 spring propriety 注解 与 Inject
  • 清除 Coldfusion 生产服务器中的缓存

    我正在使用 CFMX 并且存在一个问题 变量 yy 在 yyfiling 中未定义 这是生产中的一个问题 我正在推动对其进行更正 但它们似乎没有出现在服务器上 我想清除服务器缓存 以便我升级的代码可以生效 CFAdmin 生产模板已被缓存
  • 如何使用 protobuf-net 序列化/反序列化大型项目列表

    我有大约 5 亿个项目的清单 如果我序列化单个项目而不是列表 我可以将其序列化为带有 protobuf net 文件的文件 我无法将项目收集到价格列表中然后序列化 因为我耗尽了内存 因此 我必须一次序列化一条记录 using var inp
  • 为什么 Finalize() 仅在创建新对象后执行,而不是在调用 gc() 后执行?

    调用 gc 时 finalize 不应该立即执行吗 输出结果的顺序有点不太令人信服 class Test int x 100 int y 115 protected void finalize System out println Reso
  • 我可以在Asp.Net中访问另一个页面中一个页面的ViewState吗?

    有没有办法在另一个页面中访问一个页面的视图状态 请详细说明答案以消除我的疑虑 因为我认为 ViewState 的范围仅限于页面 无法在页面外部访问 您无法直接从一个页面访问另一个页面的 ViewState 如果要访问特定的 ViewStat
  • 如何在 HttpWebRequest 中混合压缩和缓存?

    我有一个 C 客户端与 Cherrypy http rest Web 服务通信 问题是我无法同时打开压缩和缓存 request AutomaticDecompression DecompressionMethods GZip Decompr
  • 如何在 HAML 中执行 if/else 而不重复缩进代码

    根据用户是否登录 我想打印不同类型的 body标签 这就是我目前的做法 if defined user body data account user account h1 Welcome all my content else body h
  • 在 Docker 容器中运行时,Flask_oidc 给出“Errno 99 无法分配请求的地址”

    Goal 从 Docker 容器中运行的 Flask 应用程序使用 OIDC 背景 我正在使用 Flask 构建一个 Web 应用程序 并希望使用 Keycloak 来提供访问权限 为此 我使用 Python 库flask oidc 所有服
  • 在不使用环回网络的情况下将数据包转发到同一主机中的服务

    我有这个 libnetfilter queue 应用程序 它根据某些 iptables 规则从内核接收数据包 在直接讨论我的问题之前 我提供了一个示例可行代码和其他工具来设置测试环境 以便我们的问题定义和可能的解决方案可以更加准确和稳健 以