Linux内核网络模块笔记 - IPv4查询路由与发出

背景

干网络这块的活,经常会涉及到一些报文封装与转发的需求.本文记录的就是完成报文的封装后,如何查询现有系统的路由来进行转发;

前提

IP层的信息已经就绪,意思是源IP(IP_SRC),目的IP(IP_DST);

涉及到的内核结构体

由于内核版本的差异,如下结构体可能会有所出入,大家灵活处理哈;

  1. struct rtable
  2. struct flowi
  3. struct sk_buff

涉及到的内核函数

  1. ip_route_output_key
  2. ip_local_out

C代码:直接使用netfilter框架外发

#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/etherdevice.h>
#include <linux/rtnetlink.h>
#include <net/route.h>
#include <net/flow.h>

extern int ip_local_out(struct net *net, struct sock *sk, struct sk_buff *skb);

int cmpkt_out(struct sk_buff *skb) {
	int ret = 0;
	struct rtable *rp = NULL;
	struct flowi fl4 = {
		.u.ip4 = {},
	};
	//此处init_net,未考虑其他命名空间,可优化
	rp = ip_route_output_key(&init_net, &fl4.u.ip4);
	if (!rp)
		goto drop;
	skb->dev = rp->dst.dev;
	skb_dst_set(skb, &rp->dst);
	ret = ip_local_out(&init_net, skb->sk, skb);
end:
	return ret;
drop:
	ret = -2;
	goto end;
}

C代码:自定义完成2层外发

#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/etherdevice.h>
#include <linux/rtnetlink.h>
#include <net/route.h>
#include <net/flow.h>

extern int ip_local_out(struct net *net, struct sock *sk, struct sk_buff *skb);

int cmpkt_l2_out(struct sk_buff *skb) {
	int ret = 0;
	struct rtable *rt = NULL;
	__be32 nexthop;
	struct neighbour *neigh;
	struct ethhdr *eth;
	struct iphdr *iph;

	nexthop = 0;
	rt = NULL;
	neigh = NULL;

	struct flowi fl4 = {
		.u.ip4 = {},
	};
	//此处init_net,未考虑其他命名空间,可优化
	rt = ip_route_output_key(&init_net, &fl4.u.ip4);
	if (!rt)
		goto drop;
	skb->dev = rt->dst.dev;
	skb_dst_set(skb, &rt->dst);

	rcu_read_lock_bh();
	nexthop = rt_nexthop(rt, iph->daddr);
	neigh = __ipv4_neigh_lookup_noref(skb->dev, nexthop);
	if (neigh == NULL || IS_ERR(neigh)) {
		rcu_read_unlock_bh();
		goto drop;
	}
	skb_reset_mac_header(skb);
	memcpy(eth_hdr(skb)->h_dest, neigh->ha, ETH_ALEN);
	memcpy(eth_hdr(skb)->h_source, skb->dev->dev_addr, ETH_ALEN);
	//根据3层协议填值如下h_proto
	eth_hdr(skb)->h_proto = htons(0x0800);
	ret = dev_queue_xmit(skb);
	rcu_read_unlock_bh();
	return ret;
end:
	return ret;
drop:
	ret = -2;
	goto end;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值