upload tizen1.0 source
[kernel/linux-2.6.36.git] / net / netfilter / ipvs / ip_vs_proto_ah_esp.c
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
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 *
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,
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
82 static struct ip_vs_conn *
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)
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
118 static int
119 ah_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
130 static void
131 ah_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
147 static void
148 ah_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
164 static void
165 ah_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
177 static void ah_esp_init(struct ip_vs_protocol *pp)
178 {
179         /* nothing to do now */
180 }
181
182
183 static 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
190 struct 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
214 struct 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