从ip_queue到nfnetlink_queue(下)

【现代电路理论】【2】考尔法设计无源单口网络 夏 弥:其实你在冰面上看到鱼浮上来 明年冬天如果你还在那里,那鱼还是会上来换气 那时候你就可以带一把冰镐 把冰面砸开把鱼捞上来熬汤 阅读详情
从ip_queue到nfnetlink_queue(下)
 
本文档的Copyleft归yfydz所有,使用GPL发布,可以自由拷贝,转载,转载时请保持文档的完整性,严
禁用于任何商业用途。
msn: yfydz_no1@hotmail.com
来源: http://yfydz.cublog.cn
 
3. 内核空间
内核版本2.6.17.11。
内核空间的代码程序包括net/netfilter/nfnetlink_queue.c和xt_NFQUEUE.c,前者是具体实现,后者
是iptables的一个目标,用来指定数据属于哪个队列。

3.1 数据结构

/* include/linux/netfilter/nfnetlink_queue.h */

// nfqueue netlink消息类型
enum nfqnl_msg_types {
 NFQNL_MSG_PACKET,  /* packet from kernel to userspace */
 NFQNL_MSG_VERDICT,  /* verdict from userspace to kernel */
 NFQNL_MSG_CONFIG,  /* connect to a particular queue */
 NFQNL_MSG_MAX
};

// nfqueue netlink消息数据包头
struct nfqnl_msg_packet_hdr {
 u_int32_t packet_id; /* unique ID of packet in queue */
 u_int16_t hw_protocol; /* hw protocol (network order) */
 u_int8_t hook;  /* netfilter hook */
} __attribute__ ((packed));

// nfqueue netlink消息数据包头硬件部分,MAC地址
struct nfqnl_msg_packet_hw {
 u_int16_t hw_addrlen;
 u_int16_t _pad;
 u_int8_t hw_addr[8];
} __attribute__ ((packed));

// nfqueue netlink消息数据包64位时间戳
struct nfqnl_msg_packet_timestamp {
 aligned_u64 sec;
 aligned_u64 usec;
} __attribute__ ((packed));

// nfqueue netlink属性
enum nfqnl_attr_type {类型
 NFQA_UNSPEC,
 NFQA_PACKET_HDR,
 NFQA_VERDICT_HDR,  /* nfqnl_msg_verdict_hrd */
 NFQA_MARK,   /* u_int32_t nfmark */
 NFQA_TIMESTAMP,   /* nfqnl_msg_packet_timestamp */
 NFQA_IFINDEX_INDEV,  /* u_int32_t ifindex */
 NFQA_IFINDEX_OUTDEV,  /* u_int32_t ifindex */
 NFQA_IFINDEX_PHYSINDEV,  /* u_int32_t ifindex */
 NFQA_IFINDEX_PHYSOUTDEV, /* u_int32_t ifindex */
 NFQA_HWADDR,   /* nfqnl_msg_packet_hw */
 NFQA_PAYLOAD,   /* opaque data payload */
 __NFQA_MAX
};
#define NFQA_MAX (__NFQA_MAX - 1)

// nfqueue netlink消息数据判定头
struct nfqnl_msg_verdict_hdr {
 u_int32_t verdict;
 u_int32_t id;
} __attribute__ ((packed));
 
// nfqueue netlink消息配置命令类型
enum nfqnl_msg_config_cmds {
 NFQNL_CFG_CMD_NONE,
 NFQNL_CFG_CMD_BIND,
 NFQNL_CFG_CMD_UNBIND,
 NFQNL_CFG_CMD_PF_BIND,
 NFQNL_CFG_CMD_PF_UNBIND,
};

// nfqueue netlink消息配置命令结构
struct nfqnl_msg_config_cmd {
 u_int8_t command; /* nfqnl_msg_config_cmds */
 u_int8_t _pad;
 u_int16_t pf;  /* AF_xxx for PF_[UN]BIND */
} __attribute__ ((packed));

// nfqueue netlink消息配置模式
enum nfqnl_config_mode {
 NFQNL_COPY_NONE,   // 不拷贝
 NFQNL_COPY_META,   // 只拷贝基本信息
 NFQNL_COPY_PACKET, // 拷贝整个数据包
};

// nfqueue netlink消息配置参数结构
struct nfqnl_msg_config_params {
 u_int32_t copy_range;
 u_int8_t copy_mode; /* enum nfqnl_config_mode */
} __attribute__ ((packed));
 
// nfqueue netlink消息配置模式
enum nfqnl_attr_config {
 NFQA_CFG_UNSPEC,
 NFQA_CFG_CMD,   /* nfqnl_msg_config_cmd */
 NFQA_CFG_PARAMS,  /* nfqnl_msg_config_params */
 __NFQA_CFG_MAX
};
#define NFQA_CFG_MAX (__NFQA_CFG_MAX-1)
 
/* include/linux/netfilter.c */
struct nf_info
{
 /* The ops struct which sent us to userspace. */
 struct nf_hook_ops *elem;
 
 /* If we're sent to userspace, this keeps housekeeping info */
 int pf;
 unsigned int hook;
 struct net_device *indev, *outdev;
 int (*okfn)(struct sk_buff *);
};
/* net/netfilter/nfnetlink_queue.c */
// 队列项结构
struct nfqnl_queue_entry {
 struct list_head list;
 struct nf_info *info;
 struct sk_buff *skb;
 unsigned int id;
};
// 队列实例结构
struct nfqnl_instance {
// HASH链表节点
 struct hlist_node hlist;  /* global list of queues */
 atomic_t use;
// 应用程序的pid
 int peer_pid;
// 队列最大长度
 unsigned int queue_maxlen;
// 数据拷贝范围
 unsigned int copy_range;
// 当前队列元素数
 unsigned int queue_total;
// 队列丢包数
 unsigned int queue_dropped;
// 用户程序判定丢包
 unsigned int queue_user_dropped;
// ID序
 atomic_t id_sequence;   /* 'sequence' of pkt ids */
// 队列号
 u_int16_t queue_num;   /* number of this queue */
// 拷贝模式
 u_int8_t copy_mode;
 spinlock_t lock;
// queue entry队列
 struct list_head queue_list;  /* packets in queue */
};

3.2 内核程序流程

3.2.1 系统初始化
/* net/netfilter/nfnetlink_queue.c */
static int __init nfnetlink_queue_init(void)
{
 int i, status = -ENOMEM;
#ifdef CONFIG_PROC_FS
 struct proc_dir_entry *proc_nfqueue;
#endif
 
// 16个HASH链表
 for (i = 0; i < INSTANCE_BUCKETS; i++)
  INIT_HLIST_HEAD(&instance_table[i]);
// 登记netlink通知
 netlink_register_notifier(&nfqnl_rtnl_notifier);
// 登记nfnetlink子系统
 status = nfnetlink_subsys_register(&nfqnl_subsys);
 if (status < 0) {
  printk(KERN_ERR "nf_queue: failed to create netlink socket/n");
  goto cleanup_netlink_notifier;
 }
#ifdef CONFIG_PROC_FS
// 建立/proc/net/netfilter/nfnetlink_queue文件
 proc_nfqueue = create_proc_entry("nfnetlink_queue", 0440,
      proc_net_netfilter);
 if (!proc_nfqueue)
  goto cleanup_subsys;
 proc_nfqueue->proc_fops = &nfqnl_file_ops;
#endif

// 登记nfqueue netlink设备通知
 register_netdevice_notifier(&nfqnl_dev_notifier);
 return status;
#ifdef CONFIG_PROC_FS
cleanup_subsys:
 nfnetlink_subsys_unregister(&nfqnl_subsys);
#endif
cleanup_netlink_notifier:
 netlink_unregister_notifier(&nfqnl_rtnl_notifier);
 return status;
}

3.2.2
// netlink通知,只是定义一个通知回调函数, 在接收到netlink套接字信息时调用
static struct notifier_block nfqnl_rtnl_notifier = {
 .notifier_call = nfqnl_rcv_nl_event,
};
static int
nfqnl_rcv_nl_event(struct notifier_block *this,
     unsigned long event, void *ptr)
{
 struct netlink_notify *n = ptr;
// 就只处理释放事件
 if (event == NETLINK_URELEASE &&
     n->protocol == NETLINK_NETFILTER && n->pid) {
  int i;
  /* destroy all instances for this pid */
  write_lock_bh(&instances_lock);
  for  (i = 0; i < INSTANCE_BUCKETS; i++) {
   struct hlist_node *tmp, *t2;
   struct nfqnl_instance *inst;
   struct hlist_head *head = &instance_table[i];
// 释放指定pid的所有子队列信息
   hlist_for_each_entry_safe(inst, tmp, t2, head, hlist) {
    if (n->pid == inst->peer_pid)
     __instance_destroy(inst);
   }
  }
  write_unlock_bh(&instances_lock);
 }
 return NOTIFY_DONE;
}

以下两个函数实现释放操作,实际是调用同一个函数,一个需要加锁,一个不需要
static inline void
instance_destroy(struct nfqnl_instance *inst)
{
 _instance_destroy2(inst, 1);
}
static inline void
__instance_destroy(struct nfqnl_instance *inst)
{
 _instance_destroy2(inst, 0);
}
 

static void
_instance_destroy2(struct nfqnl_instance *inst, int lock)
{
 /* first pull it out of the global list */
 if (lock)
  write_lock_bh(&instances_lock);
 QDEBUG("removing instance %p (queuenum=%u) from hash/n",
  inst, inst->queue_num);
// 将队列实例先从链表中移出
 hlist_del(&inst->hlist);
 if (lock)
  write_unlock_bh(&instances_lock);
 /* then flush all pending skbs from the queue */
// 将当前队列中所有包的判定都设置DROP
 nfqnl_flush(inst, NF_DROP);
 /* and finally put the refcount */
// 释放队列实例本身
 instance_put(inst);
// 释放模块引用
 module_put(THIS_MODULE);
}

3.2.3 子系统
// 子系统定义
static struct nfnetlink_subsystem nfqnl_subsys = {
 .name  = "nf_queue",
 .subsys_id = NFNL_SUBSYS_QUEUE, // NFQUEUE的ID号为3
 .cb_count = NFQNL_MSG_MAX, // 3个控制块
 .cb  = nfqnl_cb,
};

// 子系统回调控制
static struct nfnl_callback nfqnl_cb[NFQNL_MSG_MAX] = {
// 接收数据包,实际没进行定义
 [NFQNL_MSG_PACKET] = { .call = nfqnl_recv_unsupp,
        .attr_count = NFQA_MAX, },
// 接收判定
 [NFQNL_MSG_VERDICT] = { .call = nfqnl_recv_verdict,
        .attr_count = NFQA_MAX, },
// 接收配置
 [NFQNL_MSG_CONFIG] = { .call = nfqnl_recv_config,
        .attr_count = NFQA_CFG_MAX, },
};

3.2.3.1
// 实际没定义
static int
nfqnl_recv_unsupp(struct sock *ctnl, struct sk_buff *skb,
    struct nlmsghdr *nlh, struct nfattr *nfqa[], int *errp)
{
 return -ENOTSUP
【某音电商】protobuf聊天协议逆向 某音电商私信、聊天消息protobuf协议逆向分析与解析 阅读详情

相关推荐

torchsparse安装

torchsparse安装以及安装失败原因分析和解决

AI_BING_的博客 1万+

Upwork入门指南:如何创建吸引人的个人资料

本文详细介绍了如何在Upwork上创建并优化个人资料,帮助自由职业者吸引更多客户。内容包括: 注册与验证:从注册账号到邮箱验证的完整步骤。 个人资料填写:如何撰写吸引人的标题、简介,选择技能标签,以及设置专业头像和费率。 作品集与优化:上传高质量作品集,提升搜索排名和客户信任度。 常见问题解答:解决新手常见问题,如无工作经验或审核不通过。 通过本文的指导,你将学会打造一个专业且高效的个人资料,为在Upwork上获得更多机会奠定基础。

qq_61813593的博客 3515

如何在TRAE(国际版)中搭建ESP-IDF环境以及怎么使用ESP-IDF插件编译烧录到ESP32s3中

点击进入,再点击ESPRESSIF中的EXPRESS,这里会下载ESP-IDF所需要的全部工具和包等等。首先我们从终端中进入项目所在的目录中,我的项目在E盘下的jikecode\esp32s3-client中,我就进入这个目录下。,因为我的项目是针对ESP32-S3进行开发的,所以这里的芯片型号是esp32s3,大家根据各自芯片的型号来输入。执行了这个命令后,ESP-IDF会自动配置与ESP-S3相关的编译选项,生成对应芯片的配置文件。进入第一个ESP-IDF插件,进行安装,注意安装的是。

一个爱折腾技术的普通人,分享踩过的坑、学到的干货。 1503

解决VM 与 Device/Credential Guard 不兼容。在禁用 Device/Credential Guard 后,可以运行 VM 的方法

在启用了Credential Guard或Device Guard的Windows 10主机上启动12.5版之前的VMware Workstation中的虚拟机时,将显示蓝色诊断屏幕(BSOD)。 会看到类似于以下内容的错误: VMware Workstation和Device / Credential Guard不兼容。禁用Device / Credential Guard后,可以运行VMwar...

Hern(宋兆恒) 39万+

Diffusion models代码实战:从零搭建自己的扩散模型

这个系列曾经写过三篇文章专门讲代码,分别从数据集、超参数、loss设计、参数计算、Unet结构、正向过程、逆向过程等部分详细介绍了如何搭建DDPM。Diffusion models领域发展神速,最近半年代表作品有OpenAI的GLIDE、DALL-E 2,Google Brain的ImageGen,海森堡大学的Latent Diffusion。这篇博客针对入门新手讲解一下如何利用已有的资源快速搭建自己的Diffusion models。.........

沉迷单车的追风少年 1万+

UE5 Niagara基础知识讲解

在UE5版本中,Niagara粒子系统引入了许多可添加的模块,分别用于控制发射器的生成和更新、粒子的生成和更新以及渲染效果。本文采用虚幻5.2.1版本,以图文方式对Niagara基础知识进行讲解。

一碗清深的博客 2468

CAPL自动化测试

通过本文的学习,读者应该对CAPL自动化测试有了初步的了解,并能够编写复杂的CAPL脚本。在实际项目中,CAPL的应用非常广泛,希望读者能够通过不断的学习和实践,掌握更多的CAPL技巧,提高自己的开发能力。

闲人编程的博客 1527

【思博伦】史上最详细Spirent TestCenter测试仪使用教程精讲(一)!图解超赞超详细!!!

3. 在弹出的界面中,找到菜单栏中的“Connect/Create”,选择下拉框中的“Connect to Physical/Visual Chassis”,在弹出的对话框中输入思博伦测试仪的IP地址:192.168.6.244,点击“OK”;说明:目前我们只需要使用到Raw Stream Block,不需要用到Bound Stream Block。说明:如果要使用100G模式,由于硬件限制,必须连续3个面板端口同时配置为100G使用。打开安装包,并按照提示按照即可。

风云说通信 6478

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

廖雪峰Python教程[完整版]

廖雪峰的python教程整理的,已经排好版了,而且还是完整的,适合小白

RU DOS版、EFI版32bit/64bit BIOS常用工具

DOS版、EFI版的RU工具,可用来查看IO、MEM、PCI、SMBIOS等资源。亲测在EFI SHELL下可用。

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

上一篇: 在2.6内核下不编译内核给iptables添加模块
下一篇: 从ip_queue到nfnetlink_queue(上)
max415
博客等级 码龄22年 16粉丝 38原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值