diff options
Diffstat (limited to 'net/ipv4/ipvs/ip_vs_proto_icmp.c')
-rw-r--r-- | net/ipv4/ipvs/ip_vs_proto_icmp.c | 182 |
1 files changed, 182 insertions, 0 deletions
diff --git a/net/ipv4/ipvs/ip_vs_proto_icmp.c b/net/ipv4/ipvs/ip_vs_proto_icmp.c new file mode 100644 index 000000000000..191e94aa1c1f --- /dev/null +++ b/net/ipv4/ipvs/ip_vs_proto_icmp.c @@ -0,0 +1,182 @@ +/* + * ip_vs_proto_icmp.c: ICMP load balancing support for IP Virtual Server + * + * Authors: Julian Anastasov <ja@ssi.bg>, March 2002 + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation; + * + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/icmp.h> +#include <linux/netfilter.h> +#include <linux/netfilter_ipv4.h> + +#include <net/ip_vs.h> + + +static int icmp_timeouts[1] = { 1*60*HZ }; + +static char * icmp_state_name_table[1] = { "ICMP" }; + +static struct ip_vs_conn * +icmp_conn_in_get(const struct sk_buff *skb, + struct ip_vs_protocol *pp, + const struct iphdr *iph, + unsigned int proto_off, + int inverse) +{ +#if 0 + struct ip_vs_conn *cp; + + if (likely(!inverse)) { + cp = ip_vs_conn_in_get(iph->protocol, + iph->saddr, 0, + iph->daddr, 0); + } else { + cp = ip_vs_conn_in_get(iph->protocol, + iph->daddr, 0, + iph->saddr, 0); + } + + return cp; + +#else + return NULL; +#endif +} + +static struct ip_vs_conn * +icmp_conn_out_get(const struct sk_buff *skb, + struct ip_vs_protocol *pp, + const struct iphdr *iph, + unsigned int proto_off, + int inverse) +{ +#if 0 + struct ip_vs_conn *cp; + + if (likely(!inverse)) { + cp = ip_vs_conn_out_get(iph->protocol, + iph->saddr, 0, + iph->daddr, 0); + } else { + cp = ip_vs_conn_out_get(IPPROTO_UDP, + iph->daddr, 0, + iph->saddr, 0); + } + + return cp; +#else + return NULL; +#endif +} + +static int +icmp_conn_schedule(struct sk_buff *skb, struct ip_vs_protocol *pp, + int *verdict, struct ip_vs_conn **cpp) +{ + *verdict = NF_ACCEPT; + return 0; +} + +static int +icmp_csum_check(struct sk_buff *skb, struct ip_vs_protocol *pp) +{ + if (!(skb->nh.iph->frag_off & __constant_htons(IP_OFFSET))) { + if (skb->ip_summed != CHECKSUM_UNNECESSARY) { + if (ip_vs_checksum_complete(skb, skb->nh.iph->ihl * 4)) { + IP_VS_DBG_RL_PKT(0, pp, skb, 0, "Failed checksum for"); + return 0; + } + } + } + return 1; +} + +static void +icmp_debug_packet(struct ip_vs_protocol *pp, + const struct sk_buff *skb, + int offset, + const char *msg) +{ + char buf[256]; + struct iphdr _iph, *ih; + + ih = skb_header_pointer(skb, offset, sizeof(_iph), &_iph); + if (ih == NULL) + sprintf(buf, "%s TRUNCATED", pp->name); + else if (ih->frag_off & __constant_htons(IP_OFFSET)) + sprintf(buf, "%s %u.%u.%u.%u->%u.%u.%u.%u frag", + pp->name, NIPQUAD(ih->saddr), + NIPQUAD(ih->daddr)); + else { + struct icmphdr _icmph, *ic; + + ic = skb_header_pointer(skb, offset + ih->ihl*4, + sizeof(_icmph), &_icmph); + if (ic == NULL) + sprintf(buf, "%s TRUNCATED to %u bytes\n", + pp->name, skb->len - offset); + else + sprintf(buf, "%s %u.%u.%u.%u->%u.%u.%u.%u T:%d C:%d", + pp->name, NIPQUAD(ih->saddr), + NIPQUAD(ih->daddr), + ic->type, ic->code); + } + printk(KERN_DEBUG "IPVS: %s: %s\n", msg, buf); +} + +static int +icmp_state_transition(struct ip_vs_conn *cp, int direction, + const struct sk_buff *skb, + struct ip_vs_protocol *pp) +{ + cp->timeout = pp->timeout_table[IP_VS_ICMP_S_NORMAL]; + return 1; +} + +static int +icmp_set_state_timeout(struct ip_vs_protocol *pp, char *sname, int to) +{ + int num; + char **names; + + num = IP_VS_ICMP_S_LAST; + names = icmp_state_name_table; + return ip_vs_set_state_timeout(pp->timeout_table, num, names, sname, to); +} + + +static void icmp_init(struct ip_vs_protocol *pp) +{ + pp->timeout_table = icmp_timeouts; +} + +static void icmp_exit(struct ip_vs_protocol *pp) +{ +} + +struct ip_vs_protocol ip_vs_protocol_icmp = { + .name = "ICMP", + .protocol = IPPROTO_ICMP, + .dont_defrag = 0, + .init = icmp_init, + .exit = icmp_exit, + .conn_schedule = icmp_conn_schedule, + .conn_in_get = icmp_conn_in_get, + .conn_out_get = icmp_conn_out_get, + .snat_handler = NULL, + .dnat_handler = NULL, + .csum_check = icmp_csum_check, + .state_transition = icmp_state_transition, + .register_app = NULL, + .unregister_app = NULL, + .app_conn_bind = NULL, + .debug_packet = icmp_debug_packet, + .timeout_change = NULL, + .set_state_timeout = icmp_set_state_timeout, +}; |