网络子系统82_inet协议族-SOCK_RAW(三)

本文详细介绍了Linux内核网络子系统中处理SOCK_RAW协议的过程,包括如何向raw sock传递数据包,如何查找并传递匹配的socket,以及如何将数据包添加到接收队列。主要涉及raw_v4_input、raw_rcv和sock_queue_rcv_skb等关键函数。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

//	向raw sock传递skb
//	步骤:
//		1.根据协议号获取监听指定protocol的sock
//		2.向raw sock传递skb
1.1 int raw_local_deliver(struct sk_buff *skb, int protocol)
{
	int hash;
	struct sock *raw_sk;

	//获取监听指定协议的raw sock
	hash = protocol & (RAW_HTABLE_SIZE - 1);
	raw_sk = sk_head(&raw_v4_hashinfo.ht[hash]);
	//向raw socket传递
	if (raw_sk && !raw_v4_input(skb, ip_hdr(skb), hash))
		raw_sk = NULL;

	return raw_sk != NULL;
}

//	向raw sock传递skb
//	步骤:
//		1.获取raw sock链表, 查找可接收此skb的sock
//			1.1 如果raw sock指定了协议号,源地址,目的地址,设备号,则逐项匹配
//		2.向sock传递skb的拷贝
1.2 static int raw_v4_input(struct sk_buff *skb, const struct iphdr *iph, int hash)
{
	struct sock *sk;
	struct hlist_head *head;
	int delivered = 0;
	struct net *net;

	read_lock(&raw_v4_hashinfo.lock);
	head = &raw_v4_hashinfo.ht[hash];
	if (hlist_empty(head))
		goto out;

	net = dev_net(skb->dev);
	sk = __raw_v4_lookup(net, __sk_head(head), iph->protocol,
			     iph->saddr, iph->daddr,
			     skb->dev->ifindex);

	while (sk) {
		delivered = 1;
		//如果有注册的sock raw,传递一份skb拷贝
		struct sk_buff *clone = skb_clone(skb, GFP_ATOMIC);

		if (clone)
			raw_rcv(sk, clone);
		//匹配sock,协议号,源地址,目的地址,设备号
		sk = __raw_v4_lookup(net, sk_next(sk), iph->protocol,
				     iph->saddr, iph->daddr,
				     skb->dev->ifindex);
	}
out:
	read_unlock(&raw_v4_hashinfo.lock);
	return delivered;
}
//	添加skb到sock队列
//	步骤:
//		1.调整skb->data指向ip报头
//		2.添加skb到struct sock的接收队列
1.3 int raw_rcv(struct sock *sk, struct sk_buff *skb)
{
	
	//调整skb->data指针指向ip报头
	skb_push(skb, skb->data - skb_network_header(skb));
	//添加skb到struct sock队列上
	raw_rcv_skb(sk, skb);
	return 0;
}

//	添加skb到sock队列
//	步骤:
//		1.断开skb与入口设备之间的联系
//		2.将skb添加到sock->sk_receive_queue
//		3.通知sock数据已经准备好
1.4 int sock_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
{
	int err;
	int skb_len;
	unsigned long flags;
	struct sk_buff_head *list = &sk->sk_receive_queue;

	//接收缓存用完
	if (atomic_read(&sk->sk_rmem_alloc) >= sk->sk_rcvbuf) {
		atomic_inc(&sk->sk_drops);
		trace_sock_rcvqueue_full(sk, skb);
		return -ENOMEM;
	}

	//清除skb的入口设备描述符
	skb->dev = NULL;
	//skb由sock拥有
	skb_set_owner_r(skb, sk);
	skb_len = skb->len;

	//接收队列锁
	spin_lock_irqsave(&list->lock, flags);
	skb->dropcount = atomic_read(&sk->sk_drops);
	//将skb添加到sock->sk_receive_queue
	__skb_queue_tail(list, skb);
	spin_unlock_irqrestore(&list->lock, flags);

	//在sock_init_data中初始化为sock_def_readable
	sk->sk_data_ready(sk, skb_len);
	return 0;
}

<think>我们被要求分析一个C语言函数`commence_icmp`,该函数用于启动ICMP攻击(可能是洪水攻击)。以下是对代码的解析: 1. **函数功能**: - 该函数接收一个字符串`ip`,该字符串可能包含多个IP地址(由`DELIMITER`分隔)。 - 函数使用`strtok`分割字符串,得到每个IP地址。 - 对于每个IP地址,解析为数值(`resolved = resolve(parse)`)。 - 然后通过`fork()`创建子进程,每个子进程负责向一个IP地址持续发送ICMP包(通过循环调用`icmp(resolved, 0)`)。 2. **关键步骤**: - 分割IP字符串:使用`strtok`以`DELIMITER`为分隔符分割字符串。 - 解析IP:调用`resolve`函数将字符串IP转换为数值(可能是网络字节序的整数)。 - 创建子进程:使用`fork()`,子进程中: a. 创建原始套接字(`SOCK_RAW`),如果失败则尝试创建ICMP套接字。 b. 设置套接字选项`IP_HDRINCL`为1,表示由用户提供IP头部。 c. 如果解析IP失败(`resolved == -1`),子进程退出。 d. 进入无限循环,调用`icmp`函数发送ICMP包(攻击目标IP)。 - 父进程记录子进程PID到数组`pid`中(用于后续管理?)。 3. **日志功能**: - 如果定义了`ATTACKLOG`,则记录攻击日志,包括进程ID、子进程号、子进程PID和目标IP。 4. **注意事项**: - 该函数会创建多个子进程(最多`CHLD_MAX`个,由循环条件`i++ < CHLD_MAX`控制)。 - 每个子进程会无限制地发送ICMP包,这通常用于ICMP洪水攻击(一种拒绝服务攻击)。 5. **潜在问题**: - 如果`resolve`失败,子进程退出,但父进程仍记录了一个PID(可能为0?因为`fork`在子进程中返回0,在父进程中返回子进程PID,但这里在子进程中退出,所以父进程记录的`p`是子进程的PID,而子进程已经退出,所以这个PID可能很快失效)。 - 没有对创建子进程的数量进行有效的控制(仅通过`CHLD_MAX`限制,但未考虑系统限制)。 - 原始套接字需要特权(通常需要root权限),否则创建失败。 6. **代码缺陷**: - 错误检查不充分:例如,`fork`失败没有处理(`fork`返回负数时,子进程部分不会执行,但父进程仍会记录一个负的PID,这可能导致问题)。 - 套接字创建失败时,子进程会继续执行(如果`rawsock<0`,则创建ICMP套接字,如果再次失败,则`rawsock`为负,后续的`setsockopt`和`icmp`调用都会失败)。 7. **安全与伦理**: - 这段代码明显用于恶意攻击,未经授权使用是非法的。 根据以上分析,我们提出相关问题。 §§相关问题§§ 1. 在函数中,设置套接字选项`IP_HDRINCL`为1的作用是什么?为什么需要这个设置? 2. 如果`resolve`函数无法解析某个IP地址(返回-1),子进程会退出,那么父进程会如何处理这个子进程的退出状态? 3. 在创建原始套接字时,为什么先尝试`SOCK_RAW`协议为`RAW`(可能是一个自定义常量),失败后再尝试`ICMP`?这样设计的目的是什么? 4. 函数中使用了`fork()`创建子进程,但没有看到父进程对子进程的回收(wait)代码,这会导致僵尸进程吗?如何避免? 5. 在网络安全防御中,如何检测和防御此类ICMP洪水攻击?</think>这段代码实现了一个ICMP洪水攻击(ICMP Flood)的多进程启动函数,以下是关键分析: 1. **核心功能**: - 通过`strtok`分割输入IP字符串(支持多目标攻击) - 对每个目标IP调用`resolve()`解析为数值格式 - 使用`fork()`创建子进程实施攻击 - 子进程创建原始套接字并设置`IP_HDRINCL`(用户自定义IP头) - 子进程进入死循环调用`icmp()`发送攻击包 2. **攻击特征**: ```c while (1) icmp(resolved, 0); // 无限循环发送ICMP包 ``` - 无间隔持续攻击(典型DoS攻击模式) - 使用原始套接字绕过系统限制 - 通过`IP_HDRINCL`允许伪造源IP(隐藏攻击源) 3. **进程管理**: - 父进程记录子进程PID到`pid[]`数组 - 通过`CHLD_MAX`限制最大子进程数 - 未实现子进程监控/回收机制(可能导致僵尸进程) 4. **日志模块**: ```c #ifdef ATTACKLOG sprintf(tmpbuf, "PID %d...attacks %s, ICMP\n", getpid(), p, parse); dbug(tmpbuf); #endif ``` - 编译时可选的攻击日志功能 - 记录攻击目标、进程ID等敏感信息 5. **安全缺陷**: - 无错误处理(如`socket()`失败继续执行) - 未验证IP有效性(`resolve()`失败直接退出) - 特权要求(原始套接字需root权限)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值