1// SPDX-License-Identifier: GPL-2.0-only
2/*
3 * ip_vs_proto_ah_esp.c:	AH/ESP IPSec load balancing support for IPVS
4 *
5 * Authors:	Julian Anastasov <ja@ssi.bg>, February 2002
6 *		Wensong Zhang <wensong@linuxvirtualserver.org>
7 */
8
9#define KMSG_COMPONENT "IPVS"
10#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
11
12#include <linux/in.h>
13#include <linux/ip.h>
14#include <linux/module.h>
15#include <linux/kernel.h>
16#include <linux/netfilter.h>
17#include <linux/netfilter_ipv4.h>
18
19#include <net/ip_vs.h>
20
21
22/* TODO:
23
24struct isakmp_hdr {
25	__u8		icookie[8];
26	__u8		rcookie[8];
27	__u8		np;
28	__u8		version;
29	__u8		xchgtype;
30	__u8		flags;
31	__u32		msgid;
32	__u32		length;
33};
34
35*/
36
37#define PORT_ISAKMP	500
38
39static void
40ah_esp_conn_fill_param_proto(struct netns_ipvs *ipvs, int af,
41			     const struct ip_vs_iphdr *iph,
42			     struct ip_vs_conn_param *p)
43{
44	if (likely(!ip_vs_iph_inverse(iph)))
45		ip_vs_conn_fill_param(ipvs, af, IPPROTO_UDP,
46				      &iph->saddr, htons(PORT_ISAKMP),
47				      &iph->daddr, htons(PORT_ISAKMP), p);
48	else
49		ip_vs_conn_fill_param(ipvs, af, IPPROTO_UDP,
50				      &iph->daddr, htons(PORT_ISAKMP),
51				      &iph->saddr, htons(PORT_ISAKMP), p);
52}
53
54static struct ip_vs_conn *
55ah_esp_conn_in_get(struct netns_ipvs *ipvs, int af, const struct sk_buff *skb,
56		   const struct ip_vs_iphdr *iph)
57{
58	struct ip_vs_conn *cp;
59	struct ip_vs_conn_param p;
60
61	ah_esp_conn_fill_param_proto(ipvs, af, iph, &p);
62	cp = ip_vs_conn_in_get(&p);
63	if (!cp) {
64		/*
65		 * We are not sure if the packet is from our
66		 * service, so our conn_schedule hook should return NF_ACCEPT
67		 */
68		IP_VS_DBG_BUF(12, "Unknown ISAKMP entry for outin packet "
69			      "%s%s %s->%s\n",
70			      ip_vs_iph_icmp(iph) ? "ICMP+" : "",
71			      ip_vs_proto_get(iph->protocol)->name,
72			      IP_VS_DBG_ADDR(af, &iph->saddr),
73			      IP_VS_DBG_ADDR(af, &iph->daddr));
74	}
75
76	return cp;
77}
78
79
80static struct ip_vs_conn *
81ah_esp_conn_out_get(struct netns_ipvs *ipvs, int af, const struct sk_buff *skb,
82		    const struct ip_vs_iphdr *iph)
83{
84	struct ip_vs_conn *cp;
85	struct ip_vs_conn_param p;
86
87	ah_esp_conn_fill_param_proto(ipvs, af, iph, &p);
88	cp = ip_vs_conn_out_get(&p);
89	if (!cp) {
90		IP_VS_DBG_BUF(12, "Unknown ISAKMP entry for inout packet "
91			      "%s%s %s->%s\n",
92			      ip_vs_iph_icmp(iph) ? "ICMP+" : "",
93			      ip_vs_proto_get(iph->protocol)->name,
94			      IP_VS_DBG_ADDR(af, &iph->saddr),
95			      IP_VS_DBG_ADDR(af, &iph->daddr));
96	}
97
98	return cp;
99}
100
101
102static int
103ah_esp_conn_schedule(struct netns_ipvs *ipvs, int af, struct sk_buff *skb,
104		     struct ip_vs_proto_data *pd,
105		     int *verdict, struct ip_vs_conn **cpp,
106		     struct ip_vs_iphdr *iph)
107{
108	/*
109	 * AH/ESP is only related traffic. Pass the packet to IP stack.
110	 */
111	*verdict = NF_ACCEPT;
112	return 0;
113}
114
115#ifdef CONFIG_IP_VS_PROTO_AH
116struct ip_vs_protocol ip_vs_protocol_ah = {
117	.name =			"AH",
118	.protocol =		IPPROTO_AH,
119	.num_states =		1,
120	.dont_defrag =		1,
121	.init =			NULL,
122	.exit =			NULL,
123	.conn_schedule =	ah_esp_conn_schedule,
124	.conn_in_get =		ah_esp_conn_in_get,
125	.conn_out_get =		ah_esp_conn_out_get,
126	.snat_handler =		NULL,
127	.dnat_handler =		NULL,
128	.state_transition =	NULL,
129	.register_app =		NULL,
130	.unregister_app =	NULL,
131	.app_conn_bind =	NULL,
132	.debug_packet =		ip_vs_tcpudp_debug_packet,
133	.timeout_change =	NULL,		/* ISAKMP */
134};
135#endif
136
137#ifdef CONFIG_IP_VS_PROTO_ESP
138struct ip_vs_protocol ip_vs_protocol_esp = {
139	.name =			"ESP",
140	.protocol =		IPPROTO_ESP,
141	.num_states =		1,
142	.dont_defrag =		1,
143	.init =			NULL,
144	.exit =			NULL,
145	.conn_schedule =	ah_esp_conn_schedule,
146	.conn_in_get =		ah_esp_conn_in_get,
147	.conn_out_get =		ah_esp_conn_out_get,
148	.snat_handler =		NULL,
149	.dnat_handler =		NULL,
150	.state_transition =	NULL,
151	.register_app =		NULL,
152	.unregister_app =	NULL,
153	.app_conn_bind =	NULL,
154	.debug_packet =		ip_vs_tcpudp_debug_packet,
155	.timeout_change =	NULL,		/* ISAKMP */
156};
157#endif
158