1 #include <linux/types.h>
2 #include <linux/sched.h>
3 #include <linux/timer.h>
4 #include <linux/netfilter.h>
6 #include <linux/icmp.h>
7 #include <linux/netfilter_ipv4/ip_conntrack_protocol.h>
9 #define ICMP_TIMEOUT (30*HZ)
14 #define DEBUGP(format, args...)
17 static int icmp_pkt_to_tuple(const void *datah
, size_t datalen
,
18 struct ip_conntrack_tuple
*tuple
)
20 const struct icmphdr
*hdr
= datah
;
22 tuple
->dst
.u
.icmp
.type
= hdr
->type
;
23 tuple
->src
.u
.icmp
.id
= hdr
->un
.echo
.id
;
24 tuple
->dst
.u
.icmp
.code
= hdr
->code
;
29 static int icmp_invert_tuple(struct ip_conntrack_tuple
*tuple
,
30 const struct ip_conntrack_tuple
*orig
)
32 /* Add 1; spaces filled with 0. */
33 static u_int8_t invmap
[]
34 = { [ICMP_ECHO
] = ICMP_ECHOREPLY
+ 1,
35 [ICMP_ECHOREPLY
] = ICMP_ECHO
+ 1,
36 [ICMP_TIMESTAMP
] = ICMP_TIMESTAMPREPLY
+ 1,
37 [ICMP_TIMESTAMPREPLY
] = ICMP_TIMESTAMP
+ 1,
38 [ICMP_INFO_REQUEST
] = ICMP_INFO_REPLY
+ 1,
39 [ICMP_INFO_REPLY
] = ICMP_INFO_REQUEST
+ 1,
40 [ICMP_ADDRESS
] = ICMP_ADDRESSREPLY
+ 1,
41 [ICMP_ADDRESSREPLY
] = ICMP_ADDRESS
+ 1};
43 if (orig
->dst
.u
.icmp
.type
>= sizeof(invmap
)
44 || !invmap
[orig
->dst
.u
.icmp
.type
])
47 tuple
->src
.u
.icmp
.id
= orig
->src
.u
.icmp
.id
;
48 tuple
->dst
.u
.icmp
.type
= invmap
[orig
->dst
.u
.icmp
.type
] - 1;
49 tuple
->dst
.u
.icmp
.code
= orig
->dst
.u
.icmp
.code
;
53 /* Print out the per-protocol part of the tuple. */
54 static unsigned int icmp_print_tuple(char *buffer
,
55 const struct ip_conntrack_tuple
*tuple
)
57 return sprintf(buffer
, "type=%u code=%u id=%u ",
58 tuple
->dst
.u
.icmp
.type
,
59 tuple
->dst
.u
.icmp
.code
,
60 ntohs(tuple
->src
.u
.icmp
.id
));
63 /* Print out the private part of the conntrack. */
64 static unsigned int icmp_print_conntrack(char *buffer
,
65 const struct ip_conntrack
*conntrack
)
70 /* Returns verdict for packet, or -1 for invalid. */
71 static int icmp_packet(struct ip_conntrack
*ct
,
72 struct iphdr
*iph
, size_t len
,
73 enum ip_conntrack_info ctinfo
)
75 /* FIXME: Should keep count of orig - reply packets: if == 0,
77 /* Delete connection immediately on reply: won't actually
78 vanish as we still have skb */
79 if (CTINFO2DIR(ctinfo
) == IP_CT_DIR_REPLY
) {
80 if (del_timer(&ct
->timeout
))
81 ct
->timeout
.function((unsigned long)ct
);
83 ip_ct_refresh(ct
, ICMP_TIMEOUT
);
88 /* Called when a new connection for this protocol found. */
89 static int icmp_new(struct ip_conntrack
*conntrack
,
90 struct iphdr
*iph
, size_t len
)
92 static u_int8_t valid_new
[]
95 [ICMP_INFO_REQUEST
] = 1,
98 if (conntrack
->tuplehash
[0].tuple
.dst
.u
.icmp
.type
>= sizeof(valid_new
)
99 || !valid_new
[conntrack
->tuplehash
[0].tuple
.dst
.u
.icmp
.type
]) {
100 /* Can't create a new ICMP `conn' with this. */
101 DEBUGP("icmp: can't create new conn with type %u\n",
102 conntrack
->tuplehash
[0].tuple
.dst
.u
.icmp
.type
);
103 DUMP_TUPLE(&conntrack
->tuplehash
[0].tuple
);
109 struct 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
};