1*a71a9546SAutomerger Merge Worker #include <stdint.h>
2*a71a9546SAutomerger Merge Worker #include <stdio.h>
3*a71a9546SAutomerger Merge Worker #include <string.h>
4*a71a9546SAutomerger Merge Worker #include <xtables.h>
5*a71a9546SAutomerger Merge Worker #include <limits.h> /* INT_MAX in ip6_tables.h */
6*a71a9546SAutomerger Merge Worker #include <linux/netfilter_ipv4/ip_tables.h>
7*a71a9546SAutomerger Merge Worker
8*a71a9546SAutomerger Merge Worker #include "libxt_icmp.h"
9*a71a9546SAutomerger Merge Worker
10*a71a9546SAutomerger Merge Worker /* special hack for icmp-type 'any':
11*a71a9546SAutomerger Merge Worker * Up to kernel <=2.4.20 the problem was:
12*a71a9546SAutomerger Merge Worker * '-p icmp ' matches all icmp packets
13*a71a9546SAutomerger Merge Worker * '-p icmp -m icmp' matches _only_ ICMP type 0 :(
14*a71a9546SAutomerger Merge Worker * This is now fixed by initializing the field * to icmp type 0xFF
15*a71a9546SAutomerger Merge Worker * See: https://bugzilla.netfilter.org/cgi-bin/bugzilla/show_bug.cgi?id=37
16*a71a9546SAutomerger Merge Worker */
17*a71a9546SAutomerger Merge Worker
18*a71a9546SAutomerger Merge Worker enum {
19*a71a9546SAutomerger Merge Worker O_ICMP_TYPE = 0,
20*a71a9546SAutomerger Merge Worker };
21*a71a9546SAutomerger Merge Worker
icmp_help(void)22*a71a9546SAutomerger Merge Worker static void icmp_help(void)
23*a71a9546SAutomerger Merge Worker {
24*a71a9546SAutomerger Merge Worker printf(
25*a71a9546SAutomerger Merge Worker "icmp match options:\n"
26*a71a9546SAutomerger Merge Worker "[!] --icmp-type typename match icmp type\n"
27*a71a9546SAutomerger Merge Worker "[!] --icmp-type type[/code] (or numeric type or type/code)\n");
28*a71a9546SAutomerger Merge Worker printf("Valid ICMP Types:");
29*a71a9546SAutomerger Merge Worker xt_print_icmp_types(icmp_codes, ARRAY_SIZE(icmp_codes));
30*a71a9546SAutomerger Merge Worker }
31*a71a9546SAutomerger Merge Worker
32*a71a9546SAutomerger Merge Worker static const struct xt_option_entry icmp_opts[] = {
33*a71a9546SAutomerger Merge Worker {.name = "icmp-type", .id = O_ICMP_TYPE, .type = XTTYPE_STRING,
34*a71a9546SAutomerger Merge Worker .flags = XTOPT_MAND | XTOPT_INVERT},
35*a71a9546SAutomerger Merge Worker XTOPT_TABLEEND,
36*a71a9546SAutomerger Merge Worker };
37*a71a9546SAutomerger Merge Worker
icmp_init(struct xt_entry_match * m)38*a71a9546SAutomerger Merge Worker static void icmp_init(struct xt_entry_match *m)
39*a71a9546SAutomerger Merge Worker {
40*a71a9546SAutomerger Merge Worker struct ipt_icmp *icmpinfo = (struct ipt_icmp *)m->data;
41*a71a9546SAutomerger Merge Worker
42*a71a9546SAutomerger Merge Worker icmpinfo->type = 0xFF;
43*a71a9546SAutomerger Merge Worker icmpinfo->code[1] = 0xFF;
44*a71a9546SAutomerger Merge Worker }
45*a71a9546SAutomerger Merge Worker
icmp_parse(struct xt_option_call * cb)46*a71a9546SAutomerger Merge Worker static void icmp_parse(struct xt_option_call *cb)
47*a71a9546SAutomerger Merge Worker {
48*a71a9546SAutomerger Merge Worker struct ipt_icmp *icmpinfo = cb->data;
49*a71a9546SAutomerger Merge Worker
50*a71a9546SAutomerger Merge Worker xtables_option_parse(cb);
51*a71a9546SAutomerger Merge Worker ipt_parse_icmp(cb->arg, &icmpinfo->type, icmpinfo->code);
52*a71a9546SAutomerger Merge Worker if (cb->invert)
53*a71a9546SAutomerger Merge Worker icmpinfo->invflags |= IPT_ICMP_INV;
54*a71a9546SAutomerger Merge Worker }
55*a71a9546SAutomerger Merge Worker
print_icmptype(uint8_t type,uint8_t code_min,uint8_t code_max,int invert,int numeric)56*a71a9546SAutomerger Merge Worker static void print_icmptype(uint8_t type,
57*a71a9546SAutomerger Merge Worker uint8_t code_min, uint8_t code_max,
58*a71a9546SAutomerger Merge Worker int invert,
59*a71a9546SAutomerger Merge Worker int numeric)
60*a71a9546SAutomerger Merge Worker {
61*a71a9546SAutomerger Merge Worker if (!numeric) {
62*a71a9546SAutomerger Merge Worker unsigned int i;
63*a71a9546SAutomerger Merge Worker
64*a71a9546SAutomerger Merge Worker for (i = 0; i < ARRAY_SIZE(icmp_codes); ++i)
65*a71a9546SAutomerger Merge Worker if (icmp_codes[i].type == type
66*a71a9546SAutomerger Merge Worker && icmp_codes[i].code_min == code_min
67*a71a9546SAutomerger Merge Worker && icmp_codes[i].code_max == code_max)
68*a71a9546SAutomerger Merge Worker break;
69*a71a9546SAutomerger Merge Worker
70*a71a9546SAutomerger Merge Worker if (i != ARRAY_SIZE(icmp_codes)) {
71*a71a9546SAutomerger Merge Worker printf(" %s%s",
72*a71a9546SAutomerger Merge Worker invert ? "!" : "",
73*a71a9546SAutomerger Merge Worker icmp_codes[i].name);
74*a71a9546SAutomerger Merge Worker return;
75*a71a9546SAutomerger Merge Worker }
76*a71a9546SAutomerger Merge Worker }
77*a71a9546SAutomerger Merge Worker
78*a71a9546SAutomerger Merge Worker if (invert)
79*a71a9546SAutomerger Merge Worker printf(" !");
80*a71a9546SAutomerger Merge Worker
81*a71a9546SAutomerger Merge Worker printf("type %u", type);
82*a71a9546SAutomerger Merge Worker if (code_min == code_max)
83*a71a9546SAutomerger Merge Worker printf(" code %u", code_min);
84*a71a9546SAutomerger Merge Worker else if (code_min != 0 || code_max != 0xFF)
85*a71a9546SAutomerger Merge Worker printf(" codes %u-%u", code_min, code_max);
86*a71a9546SAutomerger Merge Worker }
87*a71a9546SAutomerger Merge Worker
icmp_print(const void * ip,const struct xt_entry_match * match,int numeric)88*a71a9546SAutomerger Merge Worker static void icmp_print(const void *ip, const struct xt_entry_match *match,
89*a71a9546SAutomerger Merge Worker int numeric)
90*a71a9546SAutomerger Merge Worker {
91*a71a9546SAutomerger Merge Worker const struct ipt_icmp *icmp = (struct ipt_icmp *)match->data;
92*a71a9546SAutomerger Merge Worker
93*a71a9546SAutomerger Merge Worker printf(" icmp");
94*a71a9546SAutomerger Merge Worker print_icmptype(icmp->type, icmp->code[0], icmp->code[1],
95*a71a9546SAutomerger Merge Worker icmp->invflags & IPT_ICMP_INV,
96*a71a9546SAutomerger Merge Worker numeric);
97*a71a9546SAutomerger Merge Worker
98*a71a9546SAutomerger Merge Worker if (icmp->invflags & ~IPT_ICMP_INV)
99*a71a9546SAutomerger Merge Worker printf(" Unknown invflags: 0x%X",
100*a71a9546SAutomerger Merge Worker icmp->invflags & ~IPT_ICMP_INV);
101*a71a9546SAutomerger Merge Worker }
102*a71a9546SAutomerger Merge Worker
icmp_save(const void * ip,const struct xt_entry_match * match)103*a71a9546SAutomerger Merge Worker static void icmp_save(const void *ip, const struct xt_entry_match *match)
104*a71a9546SAutomerger Merge Worker {
105*a71a9546SAutomerger Merge Worker const struct ipt_icmp *icmp = (struct ipt_icmp *)match->data;
106*a71a9546SAutomerger Merge Worker
107*a71a9546SAutomerger Merge Worker if (icmp->invflags & IPT_ICMP_INV)
108*a71a9546SAutomerger Merge Worker printf(" !");
109*a71a9546SAutomerger Merge Worker
110*a71a9546SAutomerger Merge Worker /* special hack for 'any' case */
111*a71a9546SAutomerger Merge Worker if (icmp->type == 0xFF &&
112*a71a9546SAutomerger Merge Worker icmp->code[0] == 0 && icmp->code[1] == 0xFF) {
113*a71a9546SAutomerger Merge Worker printf(" --icmp-type any");
114*a71a9546SAutomerger Merge Worker } else {
115*a71a9546SAutomerger Merge Worker printf(" --icmp-type %u", icmp->type);
116*a71a9546SAutomerger Merge Worker if (icmp->code[0] != 0 || icmp->code[1] != 0xFF)
117*a71a9546SAutomerger Merge Worker printf("/%u", icmp->code[0]);
118*a71a9546SAutomerger Merge Worker }
119*a71a9546SAutomerger Merge Worker }
120*a71a9546SAutomerger Merge Worker
type_xlate_print(struct xt_xlate * xl,unsigned int icmptype,unsigned int code_min,unsigned int code_max)121*a71a9546SAutomerger Merge Worker static unsigned int type_xlate_print(struct xt_xlate *xl, unsigned int icmptype,
122*a71a9546SAutomerger Merge Worker unsigned int code_min,
123*a71a9546SAutomerger Merge Worker unsigned int code_max)
124*a71a9546SAutomerger Merge Worker {
125*a71a9546SAutomerger Merge Worker unsigned int i;
126*a71a9546SAutomerger Merge Worker
127*a71a9546SAutomerger Merge Worker if (code_min != code_max) {
128*a71a9546SAutomerger Merge Worker for (i = 0; i < ARRAY_SIZE(icmp_codes); ++i)
129*a71a9546SAutomerger Merge Worker if (icmp_codes[i].type == icmptype &&
130*a71a9546SAutomerger Merge Worker icmp_codes[i].code_min == code_min &&
131*a71a9546SAutomerger Merge Worker icmp_codes[i].code_max == code_max) {
132*a71a9546SAutomerger Merge Worker xt_xlate_add(xl, "%s", icmp_codes[i].name);
133*a71a9546SAutomerger Merge Worker return 1;
134*a71a9546SAutomerger Merge Worker }
135*a71a9546SAutomerger Merge Worker }
136*a71a9546SAutomerger Merge Worker
137*a71a9546SAutomerger Merge Worker return 0;
138*a71a9546SAutomerger Merge Worker }
139*a71a9546SAutomerger Merge Worker
icmp_xlate(struct xt_xlate * xl,const struct xt_xlate_mt_params * params)140*a71a9546SAutomerger Merge Worker static int icmp_xlate(struct xt_xlate *xl,
141*a71a9546SAutomerger Merge Worker const struct xt_xlate_mt_params *params)
142*a71a9546SAutomerger Merge Worker {
143*a71a9546SAutomerger Merge Worker const struct ipt_icmp *info = (struct ipt_icmp *)params->match->data;
144*a71a9546SAutomerger Merge Worker
145*a71a9546SAutomerger Merge Worker if (info->type != 0xFF) {
146*a71a9546SAutomerger Merge Worker xt_xlate_add(xl, "icmp type%s ",
147*a71a9546SAutomerger Merge Worker (info->invflags & IPT_ICMP_INV) ? " !=" : "");
148*a71a9546SAutomerger Merge Worker
149*a71a9546SAutomerger Merge Worker if (!type_xlate_print(xl, info->type, info->code[0],
150*a71a9546SAutomerger Merge Worker info->code[1]))
151*a71a9546SAutomerger Merge Worker return 0;
152*a71a9546SAutomerger Merge Worker } else {
153*a71a9546SAutomerger Merge Worker /* '-m icmp --icmp-type any' is a noop by itself,
154*a71a9546SAutomerger Merge Worker * but it eats a (mandatory) previous '-p icmp' so
155*a71a9546SAutomerger Merge Worker * emit it here */
156*a71a9546SAutomerger Merge Worker xt_xlate_add(xl, "ip protocol icmp");
157*a71a9546SAutomerger Merge Worker }
158*a71a9546SAutomerger Merge Worker return 1;
159*a71a9546SAutomerger Merge Worker }
160*a71a9546SAutomerger Merge Worker
161*a71a9546SAutomerger Merge Worker static struct xtables_match icmp_mt_reg = {
162*a71a9546SAutomerger Merge Worker .name = "icmp",
163*a71a9546SAutomerger Merge Worker .version = XTABLES_VERSION,
164*a71a9546SAutomerger Merge Worker .family = NFPROTO_IPV4,
165*a71a9546SAutomerger Merge Worker .size = XT_ALIGN(sizeof(struct ipt_icmp)),
166*a71a9546SAutomerger Merge Worker .userspacesize = XT_ALIGN(sizeof(struct ipt_icmp)),
167*a71a9546SAutomerger Merge Worker .help = icmp_help,
168*a71a9546SAutomerger Merge Worker .init = icmp_init,
169*a71a9546SAutomerger Merge Worker .print = icmp_print,
170*a71a9546SAutomerger Merge Worker .save = icmp_save,
171*a71a9546SAutomerger Merge Worker .x6_parse = icmp_parse,
172*a71a9546SAutomerger Merge Worker .x6_options = icmp_opts,
173*a71a9546SAutomerger Merge Worker .xlate = icmp_xlate,
174*a71a9546SAutomerger Merge Worker };
175*a71a9546SAutomerger Merge Worker
_init(void)176*a71a9546SAutomerger Merge Worker void _init(void)
177*a71a9546SAutomerger Merge Worker {
178*a71a9546SAutomerger Merge Worker xtables_register_match(&icmp_mt_reg);
179*a71a9546SAutomerger Merge Worker }
180