• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /netgear-R7000-V1.0.7.12_1.2.5/components/opensource/linux/linux-2.6.36/net/netfilter/ipvs/
1/*
2 * ip_vs_proto_ah_esp.c:	AH/ESP IPSec load balancing support for IPVS
3 *
4 * Authors:	Julian Anastasov <ja@ssi.bg>, February 2002
5 *		Wensong Zhang <wensong@linuxvirtualserver.org>
6 *
7 *		This program is free software; you can redistribute it and/or
8 *		modify it under the terms of the GNU General Public License
9 *		version 2 as published by the Free Software Foundation;
10 *
11 */
12
13#define KMSG_COMPONENT "IPVS"
14#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
15
16#include <linux/in.h>
17#include <linux/ip.h>
18#include <linux/module.h>
19#include <linux/kernel.h>
20#include <linux/netfilter.h>
21#include <linux/netfilter_ipv4.h>
22
23#include <net/ip_vs.h>
24
25
26/* TODO:
27
28struct isakmp_hdr {
29	__u8		icookie[8];
30	__u8		rcookie[8];
31	__u8		np;
32	__u8		version;
33	__u8		xchgtype;
34	__u8		flags;
35	__u32		msgid;
36	__u32		length;
37};
38
39*/
40
41#define PORT_ISAKMP	500
42
43
44static struct ip_vs_conn *
45ah_esp_conn_in_get(int af, const struct sk_buff *skb, struct ip_vs_protocol *pp,
46		   const struct ip_vs_iphdr *iph, unsigned int proto_off,
47		   int inverse)
48{
49	struct ip_vs_conn *cp;
50
51	if (likely(!inverse)) {
52		cp = ip_vs_conn_in_get(af, IPPROTO_UDP,
53				       &iph->saddr,
54				       htons(PORT_ISAKMP),
55				       &iph->daddr,
56				       htons(PORT_ISAKMP));
57	} else {
58		cp = ip_vs_conn_in_get(af, IPPROTO_UDP,
59				       &iph->daddr,
60				       htons(PORT_ISAKMP),
61				       &iph->saddr,
62				       htons(PORT_ISAKMP));
63	}
64
65	if (!cp) {
66		/*
67		 * We are not sure if the packet is from our
68		 * service, so our conn_schedule hook should return NF_ACCEPT
69		 */
70		IP_VS_DBG_BUF(12, "Unknown ISAKMP entry for outin packet "
71			      "%s%s %s->%s\n",
72			      inverse ? "ICMP+" : "",
73			      pp->name,
74			      IP_VS_DBG_ADDR(af, &iph->saddr),
75			      IP_VS_DBG_ADDR(af, &iph->daddr));
76	}
77
78	return cp;
79}
80
81
82static struct ip_vs_conn *
83ah_esp_conn_out_get(int af, const struct sk_buff *skb,
84		    struct ip_vs_protocol *pp,
85		    const struct ip_vs_iphdr *iph,
86		    unsigned int proto_off,
87		    int inverse)
88{
89	struct ip_vs_conn *cp;
90
91	if (likely(!inverse)) {
92		cp = ip_vs_conn_out_get(af, IPPROTO_UDP,
93					&iph->saddr,
94					htons(PORT_ISAKMP),
95					&iph->daddr,
96					htons(PORT_ISAKMP));
97	} else {
98		cp = ip_vs_conn_out_get(af, IPPROTO_UDP,
99					&iph->daddr,
100					htons(PORT_ISAKMP),
101					&iph->saddr,
102					htons(PORT_ISAKMP));
103	}
104
105	if (!cp) {
106		IP_VS_DBG_BUF(12, "Unknown ISAKMP entry for inout packet "
107			      "%s%s %s->%s\n",
108			      inverse ? "ICMP+" : "",
109			      pp->name,
110			      IP_VS_DBG_ADDR(af, &iph->saddr),
111			      IP_VS_DBG_ADDR(af, &iph->daddr));
112	}
113
114	return cp;
115}
116
117
118static int
119ah_esp_conn_schedule(int af, struct sk_buff *skb, struct ip_vs_protocol *pp,
120		     int *verdict, struct ip_vs_conn **cpp)
121{
122	/*
123	 * AH/ESP is only related traffic. Pass the packet to IP stack.
124	 */
125	*verdict = NF_ACCEPT;
126	return 0;
127}
128
129
130static void
131ah_esp_debug_packet_v4(struct ip_vs_protocol *pp, const struct sk_buff *skb,
132		       int offset, const char *msg)
133{
134	char buf[256];
135	struct iphdr _iph, *ih;
136
137	ih = skb_header_pointer(skb, offset, sizeof(_iph), &_iph);
138	if (ih == NULL)
139		sprintf(buf, "TRUNCATED");
140	else
141		sprintf(buf, "%pI4->%pI4", &ih->saddr, &ih->daddr);
142
143	pr_debug("%s: %s %s\n", msg, pp->name, buf);
144}
145
146#ifdef CONFIG_IP_VS_IPV6
147static void
148ah_esp_debug_packet_v6(struct ip_vs_protocol *pp, const struct sk_buff *skb,
149		       int offset, const char *msg)
150{
151	char buf[256];
152	struct ipv6hdr _iph, *ih;
153
154	ih = skb_header_pointer(skb, offset, sizeof(_iph), &_iph);
155	if (ih == NULL)
156		sprintf(buf, "TRUNCATED");
157	else
158		sprintf(buf, "%pI6->%pI6", &ih->saddr, &ih->daddr);
159
160	pr_debug("%s: %s %s\n", msg, pp->name, buf);
161}
162#endif
163
164static void
165ah_esp_debug_packet(struct ip_vs_protocol *pp, const struct sk_buff *skb,
166		    int offset, const char *msg)
167{
168#ifdef CONFIG_IP_VS_IPV6
169	if (skb->protocol == htons(ETH_P_IPV6))
170		ah_esp_debug_packet_v6(pp, skb, offset, msg);
171	else
172#endif
173		ah_esp_debug_packet_v4(pp, skb, offset, msg);
174}
175
176
177static void ah_esp_init(struct ip_vs_protocol *pp)
178{
179	/* nothing to do now */
180}
181
182
183static void ah_esp_exit(struct ip_vs_protocol *pp)
184{
185	/* nothing to do now */
186}
187
188
189#ifdef CONFIG_IP_VS_PROTO_AH
190struct ip_vs_protocol ip_vs_protocol_ah = {
191	.name =			"AH",
192	.protocol =		IPPROTO_AH,
193	.num_states =		1,
194	.dont_defrag =		1,
195	.init =			ah_esp_init,
196	.exit =			ah_esp_exit,
197	.conn_schedule =	ah_esp_conn_schedule,
198	.conn_in_get =		ah_esp_conn_in_get,
199	.conn_out_get =		ah_esp_conn_out_get,
200	.snat_handler =		NULL,
201	.dnat_handler =		NULL,
202	.csum_check =		NULL,
203	.state_transition =	NULL,
204	.register_app =		NULL,
205	.unregister_app =	NULL,
206	.app_conn_bind =	NULL,
207	.debug_packet =		ah_esp_debug_packet,
208	.timeout_change =	NULL,		/* ISAKMP */
209	.set_state_timeout =	NULL,
210};
211#endif
212
213#ifdef CONFIG_IP_VS_PROTO_ESP
214struct ip_vs_protocol ip_vs_protocol_esp = {
215	.name =			"ESP",
216	.protocol =		IPPROTO_ESP,
217	.num_states =		1,
218	.dont_defrag =		1,
219	.init =			ah_esp_init,
220	.exit =			ah_esp_exit,
221	.conn_schedule =	ah_esp_conn_schedule,
222	.conn_in_get =		ah_esp_conn_in_get,
223	.conn_out_get =		ah_esp_conn_out_get,
224	.snat_handler =		NULL,
225	.dnat_handler =		NULL,
226	.csum_check =		NULL,
227	.state_transition =	NULL,
228	.register_app =		NULL,
229	.unregister_app =	NULL,
230	.app_conn_bind =	NULL,
231	.debug_packet =		ah_esp_debug_packet,
232	.timeout_change =	NULL,		/* ISAKMP */
233};
234#endif
235