1#include <linux/types.h> 2#include <linux/sched.h> 3#include <linux/timer.h> 4#include <linux/netfilter.h> 5#include <linux/in.h> 6#include <linux/icmp.h> 7#include <linux/netfilter_ipv4/ip_conntrack_protocol.h> 8 9#define ICMP_TIMEOUT (30*HZ) 10 11#define DEBUGP(format, args...) 12 13static int icmp_pkt_to_tuple(const void *datah, size_t datalen, 14 struct ip_conntrack_tuple *tuple) 15{ 16 const struct icmphdr *hdr = datah; 17 18 tuple->dst.u.icmp.type = hdr->type; 19 tuple->src.u.icmp.id = hdr->un.echo.id; 20 tuple->dst.u.icmp.code = hdr->code; 21 22 return 1; 23} 24 25static int icmp_invert_tuple(struct ip_conntrack_tuple *tuple, 26 const struct ip_conntrack_tuple *orig) 27{ 28 /* Add 1; spaces filled with 0. */ 29 static u_int8_t invmap[] 30 = { [ICMP_ECHO] = ICMP_ECHOREPLY + 1, 31 [ICMP_ECHOREPLY] = ICMP_ECHO + 1, 32 [ICMP_TIMESTAMP] = ICMP_TIMESTAMPREPLY + 1, 33 [ICMP_TIMESTAMPREPLY] = ICMP_TIMESTAMP + 1, 34 [ICMP_INFO_REQUEST] = ICMP_INFO_REPLY + 1, 35 [ICMP_INFO_REPLY] = ICMP_INFO_REQUEST + 1, 36 [ICMP_ADDRESS] = ICMP_ADDRESSREPLY + 1, 37 [ICMP_ADDRESSREPLY] = ICMP_ADDRESS + 1}; 38 39 if (orig->dst.u.icmp.type >= sizeof(invmap) 40 || !invmap[orig->dst.u.icmp.type]) 41 return 0; 42 43 tuple->src.u.icmp.id = orig->src.u.icmp.id; 44 tuple->dst.u.icmp.type = invmap[orig->dst.u.icmp.type] - 1; 45 tuple->dst.u.icmp.code = orig->dst.u.icmp.code; 46 return 1; 47} 48 49/* Print out the per-protocol part of the tuple. */ 50static unsigned int icmp_print_tuple(char *buffer, 51 const struct ip_conntrack_tuple *tuple) 52{ 53 return sprintf(buffer, "type=%u code=%u id=%u ", 54 tuple->dst.u.icmp.type, 55 tuple->dst.u.icmp.code, 56 ntohs(tuple->src.u.icmp.id)); 57} 58 59/* Print out the private part of the conntrack. */ 60static unsigned int icmp_print_conntrack(char *buffer, 61 const struct ip_conntrack *conntrack) 62{ 63 return 0; 64} 65 66/* Returns verdict for packet, or -1 for invalid. */ 67static int icmp_packet(struct ip_conntrack *ct, 68 struct iphdr *iph, size_t len, 69 enum ip_conntrack_info ctinfo) 70{ 71 /* Try to delete connection immediately after all replies: 72 won't actually vanish as we still have skb, and del_timer 73 means this will only run once even if count hits zero twice 74 (theoretically possible with SMP) */ 75 if (CTINFO2DIR(ctinfo) == IP_CT_DIR_REPLY) { 76 if (atomic_dec_and_test(&ct->proto.icmp.count) 77 && del_timer(&ct->timeout)) 78 ct->timeout.function((unsigned long)ct); 79 } else { 80 atomic_inc(&ct->proto.icmp.count); 81 ip_ct_refresh(ct, ICMP_TIMEOUT); 82 } 83 84 return NF_ACCEPT; 85} 86 87/* Called when a new connection for this protocol found. */ 88static int icmp_new(struct ip_conntrack *conntrack, 89 struct iphdr *iph, size_t len) 90{ 91 static u_int8_t valid_new[] 92 = { [ICMP_ECHO] = 1, 93 [ICMP_TIMESTAMP] = 1, 94 [ICMP_INFO_REQUEST] = 1, 95 [ICMP_ADDRESS] = 1 }; 96 97 if (conntrack->tuplehash[0].tuple.dst.u.icmp.type >= sizeof(valid_new) 98 || !valid_new[conntrack->tuplehash[0].tuple.dst.u.icmp.type]) { 99 /* Can't create a new ICMP `conn' with this. */ 100 DEBUGP("icmp: can't create new conn with type %u\n", 101 conntrack->tuplehash[0].tuple.dst.u.icmp.type); 102 DUMP_TUPLE(&conntrack->tuplehash[0].tuple); 103 return 0; 104 } 105 atomic_set(&conntrack->proto.icmp.count, 0); 106 return 1; 107} 108 109struct ip_conntrack_protocol ip_conntrack_protocol_icmp 110= { { NULL, NULL }, IPPROTO_ICMP, "icmp", 111 icmp_pkt_to_tuple, icmp_invert_tuple, icmp_print_tuple, 112 icmp_print_conntrack, icmp_packet, icmp_new, NULL, NULL, NULL }; 113