ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.6.tar.bz2
[linux-2.6.git] / net / ipv4 / ipvs / ip_vs_proto_icmp.c
1 /*
2  * ip_vs_proto_icmp.c:  ICMP load balancing support for IP Virtual Server
3  *
4  * Authors:     Julian Anastasov <ja@ssi.bg>, March 2002
5  *
6  *              This program is free software; you can redistribute it and/or
7  *              modify it under the terms of the GNU General Public License
8  *              version 2 as published by the Free Software Foundation;
9  *
10  */
11
12 #include <linux/module.h>
13 #include <linux/kernel.h>
14 #include <linux/icmp.h>
15 #include <linux/netfilter.h>
16 #include <linux/netfilter_ipv4.h>
17
18 #include <net/ip_vs.h>
19
20
21 static int icmp_timeouts[1] =           { 1*60*HZ };
22
23 static char * icmp_state_name_table[1] = { "ICMP" };
24
25 struct ip_vs_conn *
26 icmp_conn_in_get(const struct sk_buff *skb,
27                  struct ip_vs_protocol *pp,
28                  const struct iphdr *iph,
29                  unsigned int proto_off,
30                  int inverse)
31 {
32 #if 0
33         struct ip_vs_conn *cp;
34
35         if (likely(!inverse)) {
36                 cp = ip_vs_conn_in_get(iph->protocol,
37                         iph->saddr, 0,
38                         iph->daddr, 0);
39         } else {
40                 cp = ip_vs_conn_in_get(iph->protocol,
41                         iph->daddr, 0,
42                         iph->saddr, 0);
43         }
44
45         return cp;
46
47 #else
48         return NULL;
49 #endif
50 }
51
52 struct ip_vs_conn *
53 icmp_conn_out_get(const struct sk_buff *skb,
54                   struct ip_vs_protocol *pp,
55                   const struct iphdr *iph,
56                   unsigned int proto_off,
57                   int inverse)
58 {
59 #if 0
60         struct ip_vs_conn *cp;
61
62         if (likely(!inverse)) {
63                 cp = ip_vs_conn_out_get(iph->protocol,
64                         iph->saddr, 0,
65                         iph->daddr, 0);
66         } else {
67                 cp = ip_vs_conn_out_get(IPPROTO_UDP,
68                         iph->daddr, 0,
69                         iph->saddr, 0);
70         }
71
72         return cp;
73 #else
74         return NULL;
75 #endif
76 }
77
78 static int
79 icmp_conn_schedule(struct sk_buff *skb, struct ip_vs_protocol *pp,
80                    int *verdict, struct ip_vs_conn **cpp)
81 {
82         *verdict = NF_ACCEPT;
83         return 0;
84 }
85
86 static int
87 icmp_csum_check(struct sk_buff *skb, struct ip_vs_protocol *pp)
88 {
89         if (!(skb->nh.iph->frag_off & __constant_htons(IP_OFFSET))) {
90                 if (skb->ip_summed != CHECKSUM_UNNECESSARY) {
91                         if (ip_vs_checksum_complete(skb, skb->nh.iph->ihl * 4)) {
92                                 IP_VS_DBG_RL_PKT(0, pp, skb, 0, "Failed checksum for");
93                                 return 0;
94                         }
95                 }
96         }
97         return 1;
98 }
99
100 static void
101 icmp_debug_packet(struct ip_vs_protocol *pp,
102                   const struct sk_buff *skb,
103                   int offset,
104                   const char *msg)
105 {
106         char buf[256];
107         struct iphdr iph;
108         struct icmphdr icmph;
109
110         if (skb_copy_bits(skb, offset, &iph, sizeof(iph)) < 0)
111                 sprintf(buf, "%s TRUNCATED", pp->name);
112         else if (iph.frag_off & __constant_htons(IP_OFFSET))
113                 sprintf(buf, "%s %u.%u.%u.%u->%u.%u.%u.%u frag",
114                         pp->name, NIPQUAD(iph.saddr),
115                         NIPQUAD(iph.daddr));
116         else if (skb_copy_bits(skb, offset + iph.ihl*4, &icmph, sizeof(icmph)) < 0)
117                 sprintf(buf, "%s TRUNCATED to %u bytes\n",
118                         pp->name, skb->len - offset);
119         else
120                 sprintf(buf, "%s %u.%u.%u.%u->%u.%u.%u.%u T:%d C:%d",
121                         pp->name, NIPQUAD(iph.saddr),
122                         NIPQUAD(iph.daddr),
123                         icmph.type, icmph.code);
124
125         printk(KERN_DEBUG "IPVS: %s: %s\n", msg, buf);
126 }
127
128 static int
129 icmp_state_transition(struct ip_vs_conn *cp, int direction,
130                       const struct sk_buff *skb,
131                       struct ip_vs_protocol *pp)
132 {
133         cp->timeout = pp->timeout_table[IP_VS_ICMP_S_NORMAL];
134         return 1;
135 }
136
137 static int
138 icmp_set_state_timeout(struct ip_vs_protocol *pp, char *sname, int to)
139 {
140         int num;
141         char **names;
142
143         num = IP_VS_ICMP_S_LAST;
144         names = icmp_state_name_table;
145         return ip_vs_set_state_timeout(pp->timeout_table, num, names, sname, to);
146 }
147
148
149 static void icmp_init(struct ip_vs_protocol *pp)
150 {
151         pp->timeout_table = icmp_timeouts;
152 }
153
154 static void icmp_exit(struct ip_vs_protocol *pp)
155 {
156 }
157
158 struct ip_vs_protocol ip_vs_protocol_icmp = {
159         .name =                 "ICMP",
160         .protocol =             IPPROTO_ICMP,
161         .dont_defrag =          0,
162         .init =                 icmp_init,
163         .exit =                 icmp_exit,
164         .conn_schedule =        icmp_conn_schedule,
165         .conn_in_get =          icmp_conn_in_get,
166         .conn_out_get =         icmp_conn_out_get,
167         .snat_handler =         NULL,
168         .dnat_handler =         NULL,
169         .csum_check =           icmp_csum_check,
170         .state_transition =     icmp_state_transition,
171         .register_app =         NULL,
172         .unregister_app =       NULL,
173         .app_conn_bind =        NULL,
174         .debug_packet =         icmp_debug_packet,
175         .timeout_change =       NULL,
176         .set_state_timeout =    icmp_set_state_timeout,
177 };