mirror of
https://github.com/torvalds/linux.git
synced 2024-11-30 16:11:38 +00:00
7fe94612dd
As Nicolas noticed in his case, when xfrm_interface module is installed the standard IP tunnels will break in receiving packets. This is caused by the IP tunnel handlers with a higher priority in xfrm interface processing incoming packets by xfrm_input(), which would drop the packets and return 0 instead when anything wrong happens. Rather than changing xfrm_input(), this patch is to adjust the priority for the IP tunnel handlers in xfrm interface, so that the packets would go to xfrmi's later than the others', as the others' would not drop the packets when the handlers couldn't process them. Note that IPCOMP also defines its own IPIP tunnel handler and it calls xfrm_input() as well, so we must make its priority lower than xfrmi's, which means having xfrmi loaded would still break IPCOMP. We may seek another way to fix it in xfrm_input() in the future. Reported-by: Nicolas Dichtel <nicolas.dichtel@6wind.com> Tested-by: Nicolas Dichtel <nicolas.dichtel@6wind.com> Fixes:da9bbf0598
("xfrm: interface: support IPIP and IPIP6 tunnels processing with .cb_handler") FIxes:d7b360c286
("xfrm: interface: support IP6IP6 and IP6IP tunnels processing with .cb_handler") Signed-off-by: Xin Long <lucien.xin@gmail.com> Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
118 lines
2.7 KiB
C
118 lines
2.7 KiB
C
// SPDX-License-Identifier: GPL-2.0-only
|
|
/* xfrm4_tunnel.c: Generic IP tunnel transformer.
|
|
*
|
|
* Copyright (C) 2003 David S. Miller (davem@redhat.com)
|
|
*/
|
|
|
|
#define pr_fmt(fmt) "IPsec: " fmt
|
|
|
|
#include <linux/skbuff.h>
|
|
#include <linux/module.h>
|
|
#include <linux/mutex.h>
|
|
#include <net/xfrm.h>
|
|
#include <net/ip.h>
|
|
#include <net/protocol.h>
|
|
|
|
static int ipip_output(struct xfrm_state *x, struct sk_buff *skb)
|
|
{
|
|
skb_push(skb, -skb_network_offset(skb));
|
|
return 0;
|
|
}
|
|
|
|
static int ipip_xfrm_rcv(struct xfrm_state *x, struct sk_buff *skb)
|
|
{
|
|
return ip_hdr(skb)->protocol;
|
|
}
|
|
|
|
static int ipip_init_state(struct xfrm_state *x)
|
|
{
|
|
if (x->props.mode != XFRM_MODE_TUNNEL)
|
|
return -EINVAL;
|
|
|
|
if (x->encap)
|
|
return -EINVAL;
|
|
|
|
x->props.header_len = sizeof(struct iphdr);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void ipip_destroy(struct xfrm_state *x)
|
|
{
|
|
}
|
|
|
|
static const struct xfrm_type ipip_type = {
|
|
.description = "IPIP",
|
|
.owner = THIS_MODULE,
|
|
.proto = IPPROTO_IPIP,
|
|
.init_state = ipip_init_state,
|
|
.destructor = ipip_destroy,
|
|
.input = ipip_xfrm_rcv,
|
|
.output = ipip_output
|
|
};
|
|
|
|
static int xfrm_tunnel_rcv(struct sk_buff *skb)
|
|
{
|
|
return xfrm4_rcv_spi(skb, IPPROTO_IPIP, ip_hdr(skb)->saddr);
|
|
}
|
|
|
|
static int xfrm_tunnel_err(struct sk_buff *skb, u32 info)
|
|
{
|
|
return -ENOENT;
|
|
}
|
|
|
|
static struct xfrm_tunnel xfrm_tunnel_handler __read_mostly = {
|
|
.handler = xfrm_tunnel_rcv,
|
|
.err_handler = xfrm_tunnel_err,
|
|
.priority = 4,
|
|
};
|
|
|
|
#if IS_ENABLED(CONFIG_IPV6)
|
|
static struct xfrm_tunnel xfrm64_tunnel_handler __read_mostly = {
|
|
.handler = xfrm_tunnel_rcv,
|
|
.err_handler = xfrm_tunnel_err,
|
|
.priority = 3,
|
|
};
|
|
#endif
|
|
|
|
static int __init ipip_init(void)
|
|
{
|
|
if (xfrm_register_type(&ipip_type, AF_INET) < 0) {
|
|
pr_info("%s: can't add xfrm type\n", __func__);
|
|
return -EAGAIN;
|
|
}
|
|
|
|
if (xfrm4_tunnel_register(&xfrm_tunnel_handler, AF_INET)) {
|
|
pr_info("%s: can't add xfrm handler for AF_INET\n", __func__);
|
|
xfrm_unregister_type(&ipip_type, AF_INET);
|
|
return -EAGAIN;
|
|
}
|
|
#if IS_ENABLED(CONFIG_IPV6)
|
|
if (xfrm4_tunnel_register(&xfrm64_tunnel_handler, AF_INET6)) {
|
|
pr_info("%s: can't add xfrm handler for AF_INET6\n", __func__);
|
|
xfrm4_tunnel_deregister(&xfrm_tunnel_handler, AF_INET);
|
|
xfrm_unregister_type(&ipip_type, AF_INET);
|
|
return -EAGAIN;
|
|
}
|
|
#endif
|
|
return 0;
|
|
}
|
|
|
|
static void __exit ipip_fini(void)
|
|
{
|
|
#if IS_ENABLED(CONFIG_IPV6)
|
|
if (xfrm4_tunnel_deregister(&xfrm64_tunnel_handler, AF_INET6))
|
|
pr_info("%s: can't remove xfrm handler for AF_INET6\n",
|
|
__func__);
|
|
#endif
|
|
if (xfrm4_tunnel_deregister(&xfrm_tunnel_handler, AF_INET))
|
|
pr_info("%s: can't remove xfrm handler for AF_INET\n",
|
|
__func__);
|
|
xfrm_unregister_type(&ipip_type, AF_INET);
|
|
}
|
|
|
|
module_init(ipip_init);
|
|
module_exit(ipip_fini);
|
|
MODULE_LICENSE("GPL");
|
|
MODULE_ALIAS_XFRM_TYPE(AF_INET, XFRM_PROTO_IPIP);
|