netfilter filter表

news2025/1/22 9:23:26

iptables是linux下常用的一个防火墙软件,可以实现对网络访问的各种限制。iptables相当于防火墙的客户端,与用户进行交换,其后台依赖于内核的netfilter模块。iptables的各种配置,最终都是netfilter模块来实现的。

iptables分为4个表:filter表,nat表,raw表,mangle表。filter表为默认表。如下每的指令,不指定表名,默认操作的是filter表。

iptables -I INPUT -s 1.2.3.4 -j ACCEPT

 再如下面的指令,操作的是nat表,需要用-t指令,指明操作的表名。

iptables -t nat -A PREROUTING -d 1.2.3.4 -p tcp -m tcp --dport 81 -j DNAT --to-destination 192.168.0.2:8180 

 ipv4 filter的初始化函数是iptable_filter_init,代码在net/ipv4/netfilter/iptable_filter.c文件中。

static int __init iptable_filter_init(void)
{
	int ret;

	// 将packet_filter表的nf_hooks_ops对象的钩子回调函数设置为iptable_filter_hook
	filter_ops = xt_hook_ops_alloc(&packet_filter, iptable_filter_hook);
	if (IS_ERR(filter_ops))
		return PTR_ERR(filter_ops);

	ret = register_pernet_subsys(&iptable_filter_net_ops);
	if (ret < 0)
		kfree(filter_ops);

	return ret;
}

packet_filter的定义如下:

#define FILTER_VALID_HOOKS ((1 << NF_INET_LOCAL_IN) | \

(1 << NF_INET_FORWARD) | \

(1 << NF_INET_LOCAL_OUT))

static const struct xt_table packet_filter = {

.name = "filter",

.valid_hooks = FILTER_VALID_HOOKS,

.me = THIS_MODULE,

.af = NFPROTO_IPV4,

.priority = NF_IP_PRI_FILTER,

.table_init = iptable_filter_table_init,

};

xt_hook_ops_alloc的处理逻辑是根据valid_hooks计算需要添加几个钩子处理函数。有FILTER_VALID_HOOKS的定义可知,其3个bit位是1,因此num_hooks为3。调用kcalloc申请三个nf_hook_ops对象,并分别赋值。

xt_hook_ops_alloc代码如下:

struct nf_hook_ops *
xt_hook_ops_alloc(const struct xt_table *table, nf_hookfn *fn)
{
	unsigned int hook_mask = table->valid_hooks;

	// num_hooks即hook_mask有几个bit位是1,对于packet_filter,num_hooks为3
	uint8_t i, num_hooks = hweight32(hook_mask);
	uint8_t hooknum;
	struct nf_hook_ops *ops;

	if (!num_hooks)
		return ERR_PTR(-EINVAL);

	ops = kcalloc(num_hooks, sizeof(*ops), GFP_KERNEL);
	if (ops == NULL)
		return ERR_PTR(-ENOMEM);

	for (i = 0, hooknum = 0; i < num_hooks && hook_mask != 0;
	     hook_mask >>= 1, ++hooknum) {
		if (!(hook_mask & 1))
			continue;
		ops[i].hook     = fn;
		ops[i].pf       = table->af; // NFPROTO_IPV4
		ops[i].hooknum  = hooknum;
		ops[i].priority = table->priority; // NF_IP_PRI_FILTER
		++i;
	}

	return ops;
}

iptable_filter_net_ops的初始化方法是,iptable_filter_net_init,最后调到iptable_filter_table_init。

static int __net_init iptable_filter_table_init(struct net *net)
{
	struct ipt_replace *repl;
	int err;

	if (net->ipv4.iptable_filter)
		return 0;

	repl = ipt_alloc_initial_table(&packet_filter);
	if (repl == NULL)
		return -ENOMEM;
	/* Entry 1 is the FORWARD hook */
	((struct ipt_standard *)repl->entries)[1].target.verdict =
		forward ? -NF_ACCEPT - 1 : -NF_DROP - 1;

	err = ipt_register_table(net, &packet_filter, repl, filter_ops,
				 &net->ipv4.iptable_filter);
	kfree(repl);
	return err;
}

 将ipt_alloc_initial_table展开后,代码如下:

void *ipt_alloc_initial_table(const struct xt_table *info)
{
	unsigned int hook_mask = info->valid_hooks; 
	unsigned int nhooks = hweight32(hook_mask); //3
	unsigned int bytes = 0, hooknum = 0, i = 0; 
	struct { 
		struct ipt_replace repl; 
		struct ipt_standard entries[]; 
	} *tbl; 
	struct ipt_error *term; 
	size_t term_offset = (offsetof(typeof(*tbl), entries[nhooks]) + 
		__alignof__(*term) - 1) & ~(__alignof__(*term) - 1); 
	tbl = kzalloc(term_offset + sizeof(*term), GFP_KERNEL); 
	if (tbl == NULL) 
		return NULL; 
	term = (struct ipt_error *)&(((char *)tbl)[term_offset]); 
	strncpy(tbl->repl.name, info->name, sizeof(tbl->repl.name)); 
	*term = (struct ipt_error)IPT_ERROR_INIT;  
	tbl->repl.valid_hooks = hook_mask; 
	tbl->repl.num_entries = nhooks + 1; 
	tbl->repl.size = nhooks * sizeof(struct ipt_standard) + 
			 sizeof(struct ipt_error); 
	for (; hook_mask != 0; hook_mask >>= 1, ++hooknum) { 
		if (!(hook_mask & 1)) 
			continue; 
		tbl->repl.hook_entry[hooknum] = bytes; 
		tbl->repl.underflow[hooknum]  = bytes; 
		tbl->entries[i++] = (struct ipt_standard) 
			IPT_STANDARD_INIT(NF_ACCEPT); 
		bytes += sizeof(struct ipt_standard); 
	} 
	return tbl; 
}

在分析ipt_register_table前,先看下xt_alloc_table_info的代码:

struct xt_table_info *xt_alloc_table_info(unsigned int size)
{
	struct xt_table_info *info = NULL;
	size_t sz = sizeof(*info) + size;

	if (sz < sizeof(*info))
		return NULL;

	/* Pedantry: prevent them from hitting BUG() in vmalloc.c --RR */
	if ((SMP_ALIGN(size) >> PAGE_SHIFT) + 2 > totalram_pages)
		return NULL;

	info = kvmalloc(sz, GFP_KERNEL);
	if (!info)
		return NULL;

	memset(info, 0, sizeof(*info));
	info->size = size;
	return info;
}

申请的实际大小为sizeof(xt_table_info) + size,且xt_table_info类型的info的size设置为入参。

int ipt_register_table(struct net *net, const struct xt_table *table,
		       const struct ipt_replace *repl,
		       const struct nf_hook_ops *ops, struct xt_table **res)
{
	int ret;
	struct xt_table_info *newinfo;
	struct xt_table_info bootstrap = {0};
	void *loc_cpu_entry;
	struct xt_table *new_table;

	// repl->size为{nhooks * sizeof(struct ipt_standard) + sizeof(struct ipt_error)}
	// 本次分析,nhooks为3
	// xt_alloc_table_info申请的空间,实际为:1个xt_table_info + 3个ipt_standard + 1个ipt_error
	newinfo = xt_alloc_table_info(repl->size);
	if (!newinfo)
		return -ENOMEM;

	loc_cpu_entry = newinfo->entries;

	// repl->entries为IPT_STANDARD_INIT(NF_ACCEPT),在ipt_alloc_initial_table中设置
	memcpy(loc_cpu_entry, repl->entries, repl->size);

	ret = translate_table(net, newinfo, loc_cpu_entry, repl);
	if (ret != 0)
		goto out_free;

	// 复制input_table,将拷贝的对象添加到net->xt.tables[table->af]列表上
	// new_table->private为newinfo
	new_table = xt_register_table(net, table, &bootstrap, newinfo);
	if (IS_ERR(new_table)) {
		ret = PTR_ERR(new_table);
		goto out_free;
	}

	/* set res now, will see skbs right after nf_register_net_hooks */
	// 将net->ipv4.iptable_filter的内容修改为new_table的内容
	WRITE_ONCE(*res, new_table);

	// 注册ops,即 filter_ops
	ret = nf_register_net_hooks(net, ops, hweight32(table->valid_hooks));
	if (ret != 0) {
		__ipt_unregister_table(net, new_table);
		*res = NULL;
	}

	return ret;

out_free:
	xt_free_table_info(newinfo);
	return ret;
}

注册完filter_ops后,经过NF_INET_LOCAL_IN,NF_INET_FORWARD,NF_INET_LOCAL_OUT链的数据,会调用iptable_filter_hook进行处理。iptable_filter_hook的代码如下:

static unsigned int
iptable_filter_hook(void *priv, struct sk_buff *skb,
		    const struct nf_hook_state *state)
{
	if (state->hook == NF_INET_LOCAL_OUT &&
	    (skb->len < sizeof(struct iphdr) ||
	     ip_hdrlen(skb) < sizeof(struct iphdr)))
		/* root is playing with raw sockets. */
		return NF_ACCEPT;

	return ipt_do_table(skb, state, state->net->ipv4.iptable_filter);
}
unsigned int
ipt_do_table(struct sk_buff *skb,
	     const struct nf_hook_state *state,
	     struct xt_table *table)
{
	unsigned int hook = state->hook; // NF_INET_LOCAL_IN等
	const struct iphdr *ip;
	/* Initializing verdict to NF_DROP keeps gcc happy. */
	unsigned int verdict = NF_DROP;
	const char *indev, *outdev;
	const void *table_base;
    struct ipt_entry *e;
	unsigned int stackidx, cpu;
	const struct xt_table_info *private;
	struct xt_action_param acpar;

	ip = ip_hdr(skb); // 网络层头

	private = table->private;
	table_base = private->entries; // entries为xt_table_info最后一个成员

	// 获取hook点的ipt_entry
    // get_entry ==> (struct ipt_entry *)(base + offset)
	e = get_entry(table_base, private->hook_entry[hook]);

	do {
		const struct xt_entry_target *t;
		const struct xt_entry_match *ematch;
		struct xt_counters *counter;

		WARN_ON(!e);

		// 匹配ip包,成功则继续匹配下去,否则跳到下一个规则
		// ip_packet_match匹配标准match,如:源/目的地址,进/出网口,协议等
		if (!ip_packet_match(ip, indev, outdev,
		    &e->ip, acpar.fragoff)) {
 no_match:
			e = ipt_next_entry(e);
			continue;
		}

	} while (!acpar.hotdrop);

	if (acpar.hotdrop)
		return NF_DROP;
	else return verdict;
}

总结一下:一个xt_table结构,代表netfilter一个表,其中filter表对应的是packet_filter。packet_filter的信息,保存到了net->ipv4.iptable_filter上。通过table->private获取到xt_table_info的指针。通过get_entry获取struct ipt_entry结构的指针。一个struct ipt_entry代表filter链中的一条配置。

struct ipt_entry {
    struct ipt_ip ip;

    /* Mark with fields that we care about. */
    unsigned int nfcache;

    /* Size of ipt_entry + matches */
    __u16 target_offset;
    /* Size of ipt_entry + matches + target */
    __u16 next_offset; 

    /* Back pointer */
    unsigned int comefrom;

    /* Packet and byte counters. */
    struct xt_counters counters;

    /* The matches (if any), then the target. */
    unsigned char elems[0];
};

说起来有点抽象,让我们进入内核,把这写信息打印出来吧。

首先在filter表的INPUT链添加几条数据,指令如下:

iptables -I INPUT -s 1.2.3.4 -j ACCEPT
iptables -I INPUT -p tcp ! -s 1.2.3.5 -j ACCEPT
iptables -I INPUT -p udp -d 1.2.3.0/24 -j ACCEPT

 配置结果为下:

 怎么把内核里的数据,打印出来呢。可以通过编写字符驱动,实现驱动的打开操作,在打开操作的回调函数中,将所需的信息打印出来。

 

void ipt_entry_print(struct ipt_entry* ipt_entry)
{
	if (NULL == ipt_entry)
	{
		printk("ipt_entry is null\n");
		return;
	}

	struct ipt_ip ip = ipt_entry->ip;
	// 打印ip
	printk("---ip---\n");
	printk("src ip: %X, src mask: %X\n", ip.src, ip.smsk);
	printk("dst ip: %X, dst mask: %X\n", ip.dst, ip.dmsk);
	printk("iniface: %s\n", ip.iniface);
	printk("outiface: %s\n", ip.outiface);

	/*
	IPPROTO_IP		0
	IPPROTO_TCP		6
	IPPROTO_UDP		17
	*/
	printk("proto: %d\n", ip.proto); // 6-tcp
	printk("flags: %d\n", ip.flags);

	/*
	取反标志
	#define IPT_INV_VIA_IN		0x01	Invert the sense of IN IFACE. 
	#define IPT_INV_VIA_OUT		0x02	Invert the sense of OUT IFACE 
	#define IPT_INV_TOS			0x04	Invert the sense of TOS. 
	#define IPT_INV_SRCIP		0x08	Invert the sense of SRC IP. 
	#define IPT_INV_DSTIP		0x10	Invert the sense of DST OP. 
	#define IPT_INV_FRAG		0x20	Invert the sense of FRAG. 
	#define IPT_INV_PROTO		XT_INV_PROTO
	#define IPT_INV_MASK		0x7F	All possible flag bits mask. 
	*/
	printk("invflags: %d\n", ip.invflags); // 8-源地址取反

	printk("---ipt_entry---\n");
	printk("nfcache: %d\n", ipt_entry->nfcache);
	printk("target_offset: %d\n", ipt_entry->target_offset);
	printk("next_offset: %d\n", ipt_entry->next_offset);
	printk("comefrom: %d\n", ipt_entry->comefrom);
}

static int hello_open(struct inode* inode, struct file*filep)
{
	printk("hello_open\n");
	struct task_struct *tsk = current;
	struct net *net;
	struct xt_table *xt_filter;
	struct xt_table_info *filter_info;
	const void* table_base;
	int i = 0;
	int local_in_hook_entry;
	struct ipt_entry* ipt_entry;

	struct nsproxy *nsprx = tsk->nsproxy; //命名空间
	if (NULL == nsprx)
	{
		printk("nsprx is null\n");
		return 0;
	}

	printk("hello_open get net\n");
	net = nsprx->net_ns;
	if (NULL == net)
	{
		printk("net is null\n");
		return 0;
	}

	printk("hello_open get xt_table\n");
	xt_filter = net->ipv4.iptable_filter;
	if (NULL == xt_filter)
	{
		printk("xt_filter is null\n");
		return 0;
	}

	// 打印xt_table信息
	printk("xt_table: af - %d\n", xt_filter->af);
	printk("xt_table: name - %s\n", xt_filter->name);
	printk("xt_table: valid_hooks - %d\n", xt_filter->valid_hooks);
	printk("xt_table: priority - %d\n", xt_filter->priority);

	filter_info = xt_filter->private;
	if (NULL == filter_info)
	{
		printk("filter_info is null\n");
		return 0;
	}

	printk("filter_info: size - %d\n", filter_info->size);
	printk("filter_info: number - %d\n", filter_info->number); // 4?
	printk("filter_info: initial_entries - %d\n", filter_info->initial_entries);
	printk("filter_info: stacksize - %d\n", filter_info->stacksize);

	table_base = filter_info->entries;

	local_in_hook_entry = filter_info->hook_entry[NF_INET_LOCAL_IN];
	printk("filter_info: local_in_hook_entry - %d\n", local_in_hook_entry);

	// 其实获取到的是ipt_standard的地址,ipt_entry在ipt_standardh中
	ipt_entry = table_base + local_in_hook_entry;
	if (NULL == ipt_entry)
	{
		printk("ipt_entry is null\n");
		return 0;
	}

	for (; i < 24; ++i)
	{
		printk("***BEGIN***\n");
		ipt_entry_print(ipt_entry);

		ipt_entry = (void *)ipt_entry + ipt_entry->next_offset;
		printk("***END***\n\n");
	}

	//struct ipt_entry* nxt_ipt_entry = (void *)ipt_entry + ipt_entry->next_offset;
	//ipt_entry_print(nxt_ipt_entry);

	printk("hello_open finish\n");
	return 0;
}

驱动编译,安装完成后,再编写客户端程序,打开字符驱动文件,如:

int fd = open("/dev/test",O_RDWR);

打开/dev/test后,可触发字符驱动执行hello_open。打印的内核日志,可以通过dmesg指令查看。

 

[ 7539.033208] hello_open
[ 7539.033209] hello_open get net
[ 7539.033209] hello_open get xt_table
[ 7539.033210] xt_table: af - 2  // NFPROTO_IPV4
[ 7539.033210] xt_table: name - filter // 名称
[ 7539.033211] xt_table: valid_hooks - 14 // 第1,2,3 bit位为1(从0开始)
[ 7539.033211] xt_table: priority - 0
[ 7539.033212] filter_info: size - 4272
[ 7539.033212] filter_info: number - 26 //共26条配置?
[ 7539.033213] filter_info: initial_entries - 4
[ 7539.033213] filter_info: stacksize - 5
[ 7539.033213] filter_info: local_in_hook_entry - 0
[ 7539.033214] ***BEGIN***
[ 7539.033214] ---ip--- // 对应第1条配置,目的地址为 1.2.3.0/24
[ 7539.033215] src ip: 0, src mask: 0
[ 7539.033215] dst ip: 30201, dst mask: FFFFFF
[ 7539.033216] iniface: 
[ 7539.033216] outiface: 
[ 7539.033216] proto: 17 // UPD协议
[ 7539.033217] flags: 0
[ 7539.033217] invflags: 0
[ 7539.033217] ---ipt_entry---
[ 7539.033218] nfcache: 0
[ 7539.033218] target_offset: 112
[ 7539.033219] next_offset: 152
[ 7539.033219] comefrom: 2
[ 7539.033219] ***END***

[ 7539.033219] ***BEGIN***
[ 7539.033220] ---ip--- // 对应第2条配置,源地址不是1.2.3.5
[ 7539.033220] src ip: 5030201, src mask: FFFFFFFF
[ 7539.033221] dst ip: 0, dst mask: 0
[ 7539.033221] iniface: 
[ 7539.033221] outiface: 
[ 7539.033222] proto: 6 // TCP协议
[ 7539.033222] flags: 0
[ 7539.033223] invflags: 8 // #define IPT_INV_SRCIP      0x08
[ 7539.033223] ---ipt_entry---
[ 7539.033223] nfcache: 0
[ 7539.033224] target_offset: 112
[ 7539.033224] next_offset: 152
[ 7539.033224] comefrom: 2
[ 7539.033225] ***END***

[ 7539.033225] ***BEGIN***
[ 7539.033225] ---ip--- // 对应第3条配置,对源地址1.2.3.4放行
[ 7539.033226] src ip: 4030201, src mask: FFFFFFFF
[ 7539.033226] dst ip: 0, dst mask: 0
[ 7539.033226] iniface: 
[ 7539.033227] outiface: 
[ 7539.033227] proto: 0 // 所有协议
[ 7539.033227] flags: 0
[ 7539.033228] invflags: 0
[ 7539.033228] ---ipt_entry---
[ 7539.033228] nfcache: 0
[ 7539.033229] target_offset: 112
[ 7539.033229] next_offset: 152
[ 7539.033229] comefrom: 2
[ 7539.033230] ***END***

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/414185.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Python-DQN代码阅读(12)

目录 1.代码 1.1代码解读 1.2 代码分解 1.2.1 latest_checkpoint tf.train.latest_checkpoint(checkpoint_dir) 1.2.2 saver.restore(sess, latest_checkpoint) 1.2.3 sess.run(tf.global_variables_initializer()) 1.2.4 deep_q_learning() 1.3 输出结果 1.4 问题 1…

v-for比v-if优先级更高?

前言 v-if和v-for哪个优先级更高呢&#xff1f;这是面试官常常问到的一个问题&#xff0c;如果是在三年前&#xff0c;我会毫不犹豫的回答当然是v-for哩&#xff0c;但在3202的今天&#xff0c;如果还这么答&#xff0c;显然是低估了前端技术的日新月异啰。下面我们就来结合编…

第十四届蓝桥杯大赛软件赛省赛 C/C++ 大学 A 组 E 题

颜色平衡树问题描述格式输入格式输出样例输入样例输出评测用例规模与约定解析参考程序问题描述 格式输入 输入的第一行包含一个整数 n &#xff0c;表示树的结点数。 接下来 n 行&#xff0c;每行包含两个整数 Ci , Fi&#xff0c;用一个空格分隔&#xff0c;表示第 i 个结点 …

动态内存管理【下篇】

文章目录⚙️5.C/C程序的内存开辟⚙️6.柔性数组&#x1f514;6.1.柔性数组的特点&#x1f514;6.2.柔性数组的使用⚙️5.C/C程序的内存开辟 C/C程序内存分配的几个区域&#xff1a; &#x1f534;1.栈区&#xff08;stack&#xff09;&#xff1a;在执行函数时&#xff0c;函数…

2023软件测试最难求职季,哪些测试技能更容易拿到offer?

在一线大厂&#xff0c;没有测试这个岗位&#xff0c;只有测开这个岗位。这几年&#xff0c;各互联网大厂技术高速更新迭代&#xff0c;软件测试行业也正处于转型期。传统的功能测试技术逐步淘汰&#xff0c;各种新的测试技术层出不穷&#xff0c;测试人员的薪资也水涨船高。与…

【刷题之路】LeetCode 2389. 和有限的最长子序列

【刷题之路】LeetCode 2389. 和有限的最长子序列一、题目描述二、解题1、方法——二分法1.1、思路分析1.2、代码实现一、题目描述 原题连接&#xff1a; 2389. 和有限的最长子序列 题目描述&#xff1a; 给你一个长度为 n 的整数数组 nums &#xff0c;和一个长度为 m 的整数数…

UR5构型机械臂正逆运动学

前言 整理之前的一个项目&#xff0c;当时看着一个博客硬生生计算了差不多一个星期。尝试用MatLab符号推导工具箱化简一部分工作。我使用的大象机器人一款开源入门级协作机器人产品myCobot&#xff0c;开发文档十分完善&#xff0c;但是有部分技术没有开源&#xff0c;如正逆运…

数据分析师 ---- SQL强化(2)

数据分析师 ---- SQL强化(2) 文章目录数据分析师 ---- SQL强化(2)题目一&#xff1a;SQL实现文本处理题目二&#xff1a;语种播放量前三高所有歌曲总结&#xff1a;题目一&#xff1a;SQL实现文本处理 现有试卷信息表examination_info&#xff08;exam_id试卷ID, tag试卷类别,…

钢铁侠材质制作——2、线条轮廓部分的制作

钢铁侠Unlit光照Shader&#xff0c;三种效果变化返回目录大家好&#xff0c;我是阿赵&#xff0c;这里是钢铁侠材质制作第二部分&#xff0c;线条轮廓部分的制作 为了实现这个效果&#xff0c;可以把细节拆分成以下几个部分&#xff1a; 1、轮廓光 1.效果分析 这是一个很基…

时间序列 | MATLAB实现CNN-BiLSTM-Attention时间序列预测

时间序列 | MATLAB实现CNN-BiLSTM-Attention时间序列预测 目录时间序列 | MATLAB实现CNN-BiLSTM-Attention时间序列预测预测效果基本介绍模型描述程序设计参考资料预测效果 基本介绍 MATLAB实现CNN-BiLSTM-Attention时间序列预测&#xff0c;CNN-BiLSTM结合注意力机制时间序列预…

语言模型ChatGPT,为什么能引领各行各业的AI技术革命

为什么ChatGPT这样一个语言模型的发展能引发所有行业的AI技术革命呢&#xff1f; 答案就在于它能理解我们的自然语言&#xff0c; 并能将我们的语言转换成计算机能够完全理解的特征。 自然语言与计算机理解 ChatGPT之所以能引领技术革命&#xff0c;关键在于它能理解我们的…

GPT、科技、人类的生产、知识与未来(上)

本文将继续结合GPT探讨人工智能技术升级可能对人类社会带来的影响。主要还是侧重历史、社会、文化、经济、政治等角度。 问题的提出&#xff1a;ChatGPT等工具会提高人的工作效率和产出。但它会让人类使用者自身变得更“聪明”&#xff0c;还是“更笨”&#xff1f;更“强”&am…

CVE-2017-16995 Ubuntu 16.04 漏洞复现

目录 1.背景介绍 2.目的&#xff1a; 3.环境 4.操作&#xff1a; 工具下载地址&#xff1a; 1.背景介绍 Ubuntu 16.04版本存在本地提权漏洞&#xff0c;该漏洞存在于Linux内核带有的eBPF bpf(2)系统调用中&#xff0c;当用户提供恶意BPF程序使eBPF验证器模块产生计算错误&…

JDBC03-批处理、连接池、DBUtils、事物、DAO通用方法

1. 封装 JDBCUtils 【关闭、得到连接】 1.1 说明 1.2 代码实现 工具类 JDBCUtils package com.hspedu.jdbc.utils;import java.io.FileInputStream; import java.io.IOException; import java.sql.*; import java.util.Properties; /** * 这是一个工具类&#xff0c;完成 my…

【Microsoft Edge】安装详解

文章目录一、下载 Edge1.1 下载网址1.2 版本分类二、安装 Edge2.1 可能的异常情况2.2 安装目录详解2.2.1 Edge 非 Canary 版2.2.2 Edge Canary 版一、下载 Edge Edge 的安装包其实是一个简易安装包&#xff0c;里面封装了一个安装的配置文件&#xff0c;提供真正的安装包下载链…

FreeRTOS 任务基础知识

文章目录一、什么是多任务系统&#xff1f;二、FreeRTOS 任务与协程三、任务状态四、任务优先级五、任务实现六、任务控制块七、任务堆栈RTOS 系统的核心就是任务管理&#xff0c;FreeRTOS 也不例外&#xff0c;而且大多数学习 RTOS 系统的工程师或者学生主要就是为了使用 RTOS…

Revit中怎么绘制多面坡度的屋顶及生成墙

​一、Revit中怎么绘制多面坡度的屋顶 像这种坡屋顶我们可以观察到&#xff0c;它的屋顶轮廓都是带有坡度的&#xff0c;那我可以通过添加定义坡度的方式来绘制出该屋顶。 点击建筑选项卡中的屋顶按钮&#xff0c;选择迹线屋顶。 选择使用拾取线工具&#xff0c;在选项栏中将偏…

从零学习SDK(4)使用SDK创建一个简单的应用程序

SDK&#xff08;Software Development Kit&#xff09;即软件开发工具包&#xff0c;是一组帮助我们开发出软件的工具&#xff0c;包括代码、文档、示例等。一般情况下&#xff0c;我们需要将SDK引入到我们的项目中才能使用它。比如&#xff0c;学Java的朋友最早接触的JDK&…

JMeter使用JDBC Request取样器 获取查询结果

JDBC获取查询结果Java脚本创建文件JSON字符串解析 数据库连接配置定义全局变量JDBC Request 创建文件路径以及文件的脚本 import java.io.FileOutputStream; import java.text.SimpleDateFormat; import java.util.Date; boolean result false; try {//String message new Si…

JAVA初学下(仅做笔记)

一. Map集合&#xff08;双列集合&#xff09; 1.特点 键不能重复&#xff0c;值可以重复 Map接口位于最高层 2.常见API 2.1基本功能 ①注意V put&#xff08;K key,V value&#xff09;这个方法&#xff0c; 当加入 的键值对元素的键(key) 不存在时&#xff0c;就会将 键值…