Commit | Line | Data |
---|---|---|
1da177e4 | 1 | /* |
409a1966 | 2 | * ip_vs_proto_ah_esp.c: AH/ESP IPSec load balancing support for IPVS |
1da177e4 | 3 | * |
1da177e4 LT |
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 | ||
9aada7ac HE |
13 | #define KMSG_COMPONENT "IPVS" |
14 | #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt | |
15 | ||
14c85021 ACM |
16 | #include <linux/in.h> |
17 | #include <linux/ip.h> | |
1da177e4 LT |
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 | ||
28 | struct 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 | ||
44 | static struct ip_vs_conn * | |
51ef348b JV |
45 | ah_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, | |
409a1966 | 47 | int inverse) |
1da177e4 LT |
48 | { |
49 | struct ip_vs_conn *cp; | |
50 | ||
51 | if (likely(!inverse)) { | |
28364a59 JV |
52 | cp = ip_vs_conn_in_get(af, IPPROTO_UDP, |
53 | &iph->saddr, | |
4412ec49 | 54 | htons(PORT_ISAKMP), |
28364a59 | 55 | &iph->daddr, |
4412ec49 | 56 | htons(PORT_ISAKMP)); |
1da177e4 | 57 | } else { |
28364a59 JV |
58 | cp = ip_vs_conn_in_get(af, IPPROTO_UDP, |
59 | &iph->daddr, | |
4412ec49 | 60 | htons(PORT_ISAKMP), |
28364a59 | 61 | &iph->saddr, |
4412ec49 | 62 | htons(PORT_ISAKMP)); |
1da177e4 LT |
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 | */ | |
51ef348b JV |
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)); | |
1da177e4 LT |
76 | } |
77 | ||
78 | return cp; | |
79 | } | |
80 | ||
81 | ||
82 | static struct ip_vs_conn * | |
51ef348b JV |
83 | ah_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) | |
1da177e4 LT |
88 | { |
89 | struct ip_vs_conn *cp; | |
90 | ||
91 | if (likely(!inverse)) { | |
28364a59 JV |
92 | cp = ip_vs_conn_out_get(af, IPPROTO_UDP, |
93 | &iph->saddr, | |
4412ec49 | 94 | htons(PORT_ISAKMP), |
28364a59 | 95 | &iph->daddr, |
4412ec49 | 96 | htons(PORT_ISAKMP)); |
1da177e4 | 97 | } else { |
28364a59 JV |
98 | cp = ip_vs_conn_out_get(af, IPPROTO_UDP, |
99 | &iph->daddr, | |
4412ec49 | 100 | htons(PORT_ISAKMP), |
28364a59 | 101 | &iph->saddr, |
4412ec49 | 102 | htons(PORT_ISAKMP)); |
1da177e4 LT |
103 | } |
104 | ||
105 | if (!cp) { | |
51ef348b JV |
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)); | |
1da177e4 LT |
112 | } |
113 | ||
114 | return cp; | |
115 | } | |
116 | ||
117 | ||
118 | static int | |
51ef348b | 119 | ah_esp_conn_schedule(int af, struct sk_buff *skb, struct ip_vs_protocol *pp, |
409a1966 | 120 | int *verdict, struct ip_vs_conn **cpp) |
1da177e4 LT |
121 | { |
122 | /* | |
409a1966 | 123 | * AH/ESP is only related traffic. Pass the packet to IP stack. |
1da177e4 LT |
124 | */ |
125 | *verdict = NF_ACCEPT; | |
126 | return 0; | |
127 | } | |
128 | ||
129 | ||
130 | static void | |
3b047d9d JV |
131 | ah_esp_debug_packet_v4(struct ip_vs_protocol *pp, const struct sk_buff *skb, |
132 | int offset, const char *msg) | |
1da177e4 LT |
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, "%s TRUNCATED", pp->name); | |
140 | else | |
14d5e834 HH |
141 | sprintf(buf, "%s %pI4->%pI4", |
142 | pp->name, &ih->saddr, &ih->daddr); | |
1da177e4 | 143 | |
9aada7ac | 144 | pr_debug("%s: %s\n", msg, buf); |
1da177e4 LT |
145 | } |
146 | ||
3b047d9d JV |
147 | #ifdef CONFIG_IP_VS_IPV6 |
148 | static void | |
149 | ah_esp_debug_packet_v6(struct ip_vs_protocol *pp, const struct sk_buff *skb, | |
150 | int offset, const char *msg) | |
151 | { | |
152 | char buf[256]; | |
153 | struct ipv6hdr _iph, *ih; | |
154 | ||
155 | ih = skb_header_pointer(skb, offset, sizeof(_iph), &_iph); | |
156 | if (ih == NULL) | |
157 | sprintf(buf, "%s TRUNCATED", pp->name); | |
158 | else | |
5b095d98 | 159 | sprintf(buf, "%s %pI6->%pI6", |
38ff4fa4 | 160 | pp->name, &ih->saddr, &ih->daddr); |
3b047d9d | 161 | |
9aada7ac | 162 | pr_debug("%s: %s\n", msg, buf); |
3b047d9d JV |
163 | } |
164 | #endif | |
165 | ||
166 | static void | |
167 | ah_esp_debug_packet(struct ip_vs_protocol *pp, const struct sk_buff *skb, | |
168 | int offset, const char *msg) | |
169 | { | |
170 | #ifdef CONFIG_IP_VS_IPV6 | |
d286600e | 171 | if (skb->protocol == htons(ETH_P_IPV6)) |
3b047d9d JV |
172 | ah_esp_debug_packet_v6(pp, skb, offset, msg); |
173 | else | |
174 | #endif | |
175 | ah_esp_debug_packet_v4(pp, skb, offset, msg); | |
176 | } | |
177 | ||
1da177e4 | 178 | |
409a1966 | 179 | static void ah_esp_init(struct ip_vs_protocol *pp) |
1da177e4 LT |
180 | { |
181 | /* nothing to do now */ | |
182 | } | |
183 | ||
184 | ||
409a1966 | 185 | static void ah_esp_exit(struct ip_vs_protocol *pp) |
1da177e4 LT |
186 | { |
187 | /* nothing to do now */ | |
188 | } | |
189 | ||
190 | ||
409a1966 | 191 | #ifdef CONFIG_IP_VS_PROTO_AH |
1da177e4 LT |
192 | struct ip_vs_protocol ip_vs_protocol_ah = { |
193 | .name = "AH", | |
194 | .protocol = IPPROTO_AH, | |
2ad17def | 195 | .num_states = 1, |
1da177e4 | 196 | .dont_defrag = 1, |
409a1966 JV |
197 | .init = ah_esp_init, |
198 | .exit = ah_esp_exit, | |
199 | .conn_schedule = ah_esp_conn_schedule, | |
200 | .conn_in_get = ah_esp_conn_in_get, | |
201 | .conn_out_get = ah_esp_conn_out_get, | |
1da177e4 LT |
202 | .snat_handler = NULL, |
203 | .dnat_handler = NULL, | |
204 | .csum_check = NULL, | |
205 | .state_transition = NULL, | |
206 | .register_app = NULL, | |
207 | .unregister_app = NULL, | |
208 | .app_conn_bind = NULL, | |
409a1966 | 209 | .debug_packet = ah_esp_debug_packet, |
1da177e4 LT |
210 | .timeout_change = NULL, /* ISAKMP */ |
211 | .set_state_timeout = NULL, | |
212 | }; | |
409a1966 JV |
213 | #endif |
214 | ||
215 | #ifdef CONFIG_IP_VS_PROTO_ESP | |
216 | struct ip_vs_protocol ip_vs_protocol_esp = { | |
217 | .name = "ESP", | |
218 | .protocol = IPPROTO_ESP, | |
219 | .num_states = 1, | |
220 | .dont_defrag = 1, | |
221 | .init = ah_esp_init, | |
222 | .exit = ah_esp_exit, | |
223 | .conn_schedule = ah_esp_conn_schedule, | |
224 | .conn_in_get = ah_esp_conn_in_get, | |
225 | .conn_out_get = ah_esp_conn_out_get, | |
226 | .snat_handler = NULL, | |
227 | .dnat_handler = NULL, | |
228 | .csum_check = NULL, | |
229 | .state_transition = NULL, | |
230 | .register_app = NULL, | |
231 | .unregister_app = NULL, | |
232 | .app_conn_bind = NULL, | |
233 | .debug_packet = ah_esp_debug_packet, | |
234 | .timeout_change = NULL, /* ISAKMP */ | |
235 | }; | |
236 | #endif |