网络子系统63_路由子系统处理netlink事件

//	路由子系统netlink控制块
//		在ip_rt_init->devinet_init中注册。
1.1 static struct rtnetlink_link inet_rtnetlink_table[RTM_MAX - RTM_BASE + 1] = {
	 [4] = { .doit	 = inet_rtm_newaddr,  },
	 [5] = { .doit	 = inet_rtm_deladdr,  },
	 [6] = { .dumpit = inet_dump_ifaddr,  },
	 [8] = { .doit	 = inet_rtm_newroute, },
	 [9] = { .doit	 = inet_rtm_delroute, },
	[10] = { .doit	 = inet_rtm_getroute, .dumpit = inet_dump_fib, },
#ifdef CONFIG_IP_MULTIPLE_TABLES
	[16] = { .doit	 = inet_rtm_newrule, },
	[17] = { .doit	 = inet_rtm_delrule, },
	[18] = { .dumpit = inet_dump_rules,  },
#endif
};

//	为设备配置ip地址
//	函数主要任务:
//		1.检查有效性
//			1.1 网络部分<=32,提供了ip地址
//		2.分配in_ifaddr并填充信息
//		3.将in_ifaddr插入到in_device中

1.2 static int inet_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
{
	struct rtattr **rta = arg;
	struct net_device *dev;
	struct in_device *in_dev;
	struct ifaddrmsg *ifm = NLMSG_DATA(nlh);
	struct in_ifaddr *ifa;
	int rc = -EINVAL;
	// 有效性检查
	//	网路地址部分 <= 32
	if (ifm->ifa_prefixlen > 32 || !rta[IFA_LOCAL - 1])
		goto out;

	rc = -ENODEV;
	//通过设备index获取设备描述符
	if ((dev = __dev_get_by_index(ifm->ifa_index)) == NULL)
		goto out;

	rc = -ENOBUFS;
	//获取设备配置信息
	if ((in_dev = __in_dev_get(dev)) == NULL) {
		//第一次配置设备,则创建配置信息
		in_dev = inetdev_init(dev);
	}
	//分配ip地址
	if ((ifa = inet_alloc_ifa()) == NULL)
		goto out;
	//如果地址指派给隧道接口:
	//	ifa->ifa_local为隧道的本地地址,ifa->ifa_address为远程地址
	//否则:
	// ifa->ifa_local, ifa->ifa_address均为本地地址
	if (!rta[IFA_ADDRESS - 1])
		rta[IFA_ADDRESS - 1] = rta[IFA_LOCAL - 1];
	memcpy(&ifa->ifa_local, RTA_DATA(rta[IFA_LOCAL - 1]), 4);
	memcpy(&ifa->ifa_address, RTA_DATA(rta[IFA_ADDRESS - 1]), 4);
	//网络地址部分
	ifa->ifa_prefixlen = ifm->ifa_prefixlen;
	//掩码
	ifa->ifa_mask = inet_make_mask(ifm->ifa_prefixlen);
	//广播地址
	if (rta[IFA_BROADCAST - 1])
		memcpy(&ifa->ifa_broadcast,
		       RTA_DATA(rta[IFA_BROADCAST - 1]), 4);
	//选播地址
	if (rta[IFA_ANYCAST - 1])
		memcpy(&ifa->ifa_anycast, RTA_DATA(rta[IFA_ANYCAST - 1]), 4);
	//ifa_flags标示主辅地址
	ifa->ifa_flags = ifm->ifa_flags;
	ifa->ifa_scope = ifm->ifa_scope;
	in_dev_hold(in_dev);
	ifa->ifa_dev   = in_dev;
	//设备别名
	if (rta[IFA_LABEL - 1])
		rtattr_strlcpy(ifa->ifa_label, rta[IFA_LABEL - 1], IFNAMSIZ);
	else
		memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
	//将新地址插入到in_device中
	rc = inet_insert_ifa(ifa);
out:
	return rc;
}

//	删除设备ip地址
//	函数主要任务:
//		1.获取设备的配置描述符in_device
//		2.从配置描述符中删除ip信息
1.3 static int inet_rtm_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
{
	struct rtattr **rta = arg;
	struct in_device *in_dev;
	struct ifaddrmsg *ifm = NLMSG_DATA(nlh);
	struct in_ifaddr *ifa, **ifap;
	//获取设备描述
	if ((in_dev = inetdev_by_index(ifm->ifa_index)) == NULL)
		goto out;
	__in_dev_put(in_dev);

	for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL;
	     ifap = &ifa->ifa_next) {
		if ((rta[IFA_LOCAL - 1] &&
		     memcmp(RTA_DATA(rta[IFA_LOCAL - 1]),
			    &ifa->ifa_local, 4)) ||
		    (rta[IFA_LABEL - 1] &&
		     rtattr_strcmp(rta[IFA_LABEL - 1], ifa->ifa_label)) ||
		    (rta[IFA_ADDRESS - 1] &&
		     (ifm->ifa_prefixlen != ifa->ifa_prefixlen ||
		      !inet_ifa_match(*(u32*)RTA_DATA(rta[IFA_ADDRESS - 1]),
			      	      ifa))))
			continue;
		//从in_device 删除配置的ip地址
		inet_del_ifa(in_dev, ifap, 1);
		return 0;
	}
out:
	return -EADDRNOTAVAIL;
}

//	添加路由
//		通过id选择路由表,通过特定于路由表的回调函数添加路由项
1.4 int inet_rtm_newroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)
{
	struct fib_table * tb;
	struct rtattr **rta = arg;
	struct rtmsg *r = NLMSG_DATA(nlh);

	if (inet_check_attr(r, rta))
		return -EINVAL;
	//根据指定的id,选择路由表
	tb = fib_new_table(r->rtm_table);
	if (tb)	//有路由表的回调函数添加一条新路由
		return tb->tb_insert(tb, r, (struct kern_rta*)rta, nlh, &NETLINK_CB(skb));
	return -ENOBUFS;
}

//	获取路由信息
//	函数主要任务:
//		1.指定了入口设备,通过ip_route_input路由数据包,获取路由信息
//		2.否则通过出口路由,获取路由信息
//		3.将获取的路由信息通过netlink应答
1.5 int inet_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void *arg)
{
	struct rtattr **rta = arg;
	struct rtmsg *rtm = NLMSG_DATA(nlh);
	struct rtable *rt = NULL;
	u32 dst = 0;
	u32 src = 0;
	int iif = 0;
	int err = -ENOBUFS;
	struct sk_buff *skb;

	skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
	if (!skb)
		goto out;

	skb->mac.raw = skb->data;
	skb_reserve(skb, MAX_HEADER + sizeof(struct iphdr));

	if (rta[RTA_SRC - 1])
		memcpy(&src, RTA_DATA(rta[RTA_SRC - 1]), 4);
	if (rta[RTA_DST - 1])
		memcpy(&dst, RTA_DATA(rta[RTA_DST - 1]), 4);
	if (rta[RTA_IIF - 1])
		memcpy(&iif, RTA_DATA(rta[RTA_IIF - 1]), sizeof(int));
	//入口路由
	if (iif) {
		struct net_device *dev = __dev_get_by_index(iif);
		err = -ENODEV;
		if (!dev)
			goto out_free;
		skb->protocol	= htons(ETH_P_IP);
		skb->dev	= dev;
		local_bh_disable();
		//路由此skb,获取路由信息
		err = ip_route_input(skb, dst, src, rtm->rtm_tos, dev);
		local_bh_enable();
		rt = (struct rtable*)skb->dst;
		if (!err && rt->u.dst.error)
			err = -rt->u.dst.error;
	//出口路由
	} else {
		//构造查找关键字
		struct flowi fl = { .nl_u = { .ip4_u = { .daddr = dst,
							 .saddr = src,
							 .tos = rtm->rtm_tos } } };
		int oif = 0;
		//出口设备
		if (rta[RTA_OIF - 1])
			memcpy(&oif, RTA_DATA(rta[RTA_OIF - 1]), sizeof(int));
		fl.oif = oif;
		//出口路由
		err = ip_route_output_key(&rt, &fl);
	}
	if (err)
		goto out_free;

	skb->dst = &rt->u.dst;
	if (rtm->rtm_flags & RTM_F_NOTIFY)
		rt->rt_flags |= RTCF_NOTIFY;
	//netlink控制块
	NETLINK_CB(skb).dst_pid = NETLINK_CB(in_skb).pid;

	err = rt_fill_info(skb, NETLINK_CB(in_skb).pid, nlh->nlmsg_seq,
				RTM_NEWROUTE, 0);
	//通过netlink应答
	err = netlink_unicast(rtnl, skb, NETLINK_CB(in_skb).pid, MSG_DONTWAIT);
	if (err > 0)
		err = 0;
out:	return err;

out_free:
	kfree_skb(skb);
	goto out;
}
时间: 2024-08-02 21:06:25

网络子系统63_路由子系统处理netlink事件的相关文章

网络子系统62_路由子系统处理设备事件

// 监听设备事件 // 在ip_rt_init->devinet_init中注册 1.1 static struct notifier_block ip_netdev_notifier = { .notifier_call =inetdev_event, }; // 路由子系统对网络设备事件的处理 // 与事件相关的设备需要有inet配置信息 // 函数主要任务: // 1.开启设备,加入多播组,为回环设备配置ip地址 // 2.关闭设备,设备退出多播组 // 3.设备注销,删除该设备的配置信

网络子系统61_路由子系统初始化

// 路由缓存内存量指定办法: // 1.通过启动参数rhash_entries指定hash表bucket个数 // 2.根据物理内存页数确定使用的内存量 // 根据物理页数分配缓存内存: // 1.goal目标内存页数=总页数/(2**(26-PAGE_SHIFT)) // 2.最接近goal内存页数的order,用于从伙伴系统中分配 // 3.rt_hash_mask=order页可容纳的bucket数 // 4.对齐rt_hash_mask到2的幂次 // 5.从伙伴系统中分配order页

网络子系统71_路由缓存垃圾回收

// 同步回收机制 // 返回值: // 0,达到回收目标 // 1,没有达到回收目标 // 注:ip_rt_gc_min_interval = HZ/2 // ip_rt_gc_timeout = RT_GC_TIMEOUT = 300HZ // ip_rt_gc_elasticity = 8*(rt_hash_mask+1)(正常情况下) // ip_rt_gc_elasticity = 1(当绑定缓存到邻居子系统失败时) // 平衡点,gc目标数的动态调整: // 1.当前缓存个数 < 安

网络子系统68_路由表处理设备ip配置事件

// 路由表处理inet配置事件 // 在ip_rt_init->ip_fib_init中注册 1.1 static struct notifier_block fib_inetaddr_notifier = { .notifier_call = fib_inetaddr_event, }; // 路由表处理地址配置事件 // 函数主要功能: // 1.设备配置ip地址 // 1.1 将ip地址添加到路由表 // 1.2 同步多路径路由 // 1.3 刷新路由缓存 // 2.设备删除ip地址 /

朝鲜间谍机构被指主使孟加拉央行网络劫案和索尼影业黑客事件

新分析从另一角度再次指证朝鲜是孟加拉央行8100万美元网络劫案和索尼影业黑客事件背后主谋. 莫斯科威胁情报公司Group-IB"确认":对孟加拉央行和数家波兰银行发起攻击的Lazarus网络犯罪团伙,与朝鲜有关.Group-IB分析师深入分析了该网络罪犯的C2基础设施,审查了其他威胁情报信息,最终得出这一结论. 西方情报机构和私营网络安全公司,同样将朝鲜放在这一系列网络攻击的头号疑犯位置.Group-IB称,其研究与之前的工作略有不同,不仅仅依靠恶意软件分析或基于恶意软件分析的归因,而

ISA Server 2004和KWF网络间的路由功能

无论是ISA Server 2004还是KWF,都可以让你在你的内网中划分多个子网或者VLAN,然后让这些VLAN通过ISA Server 2004或KWF所做的NAT Server 访问外部网络.不过ISA Server 2004和KWF都建议你对不同的网络使用不同的网络接口(网卡),如果在同个网络接口(网卡)上实现不同的网络,那么ISA Server 2004和KWF的部分网络间的路由功能将会受到限制,或者出现一些未知的问题. 一.同个接口上实现多个网段 图一是一个在相同网络接口上实现多个网

网络子系统70_路由缓存操作

// 刷新路由缓存 // 参数: // delay, 刷新操作的延迟时间 // 函数主要任务: // 1.重新计算路由刷新定时器的到期时间 // 2.如果delay=0,则立即刷新缓存 // 3.激活定时器,使用最近的刷新延迟作为到期时间 1.1 void rt_cache_flush(int delay) { unsigned long now = jiffies; //用户态 int user_mode = !in_softirq(); if (delay < 0) delay = ip_r

网络子系统57_路由Scope

// 参考 深入理解linux网络技术内幕 // Scope // 1.路由的Scope表示到目的网路网络的距离 // 2.ip地址的Scope表示该ip地址距离本地主机有多远 // 路由Scope // 保存在fib_alias->fa_scope // 路由Scope常见取值及其意义: // 1.RT_SCOPE_NOWHERE: 路由不通往任何地方 // 2.RT_SCOPE_HOST:为本地接口配置ip地址时,自动创建的路由表项 // 3.RT_SCOPE_LINK:为本地接口配置ip地

网络子系统14_邻居子系统通用接口

//创建一个新的邻居项 //参考 深入理解linux网络技术内幕 // 1.邻居子系统为具体的邻居协议,提供通用的功能接口 // 2.系统中所有的邻居协议被链接在neigh_tables链表中 // 3.neigh_table代表一个具体的邻居协议 // 4.具体邻居协议在运行时的行为,可以通过struct neigh_parms调节, // neigh_params与设备关联,每个邻居协议neigh_table提供一个默认的neigh_params. //注册一个邻居协议到系统中 // 1.与