1 #include <stdio.h>
2 #include <xtables.h>
3 #include <linux/netfilter_ipv6/ip6t_ah.h>
4
5 enum {
6 O_AHSPI = 0,
7 O_AHLEN,
8 O_AHRES,
9 };
10
ah_help(void)11 static void ah_help(void)
12 {
13 printf(
14 "ah match options:\n"
15 "[!] --ahspi spi[:spi] match spi (range)\n"
16 "[!] --ahlen length total length of this header\n"
17 " --ahres check the reserved field too\n");
18 }
19
20 #define s struct ip6t_ah
21 static const struct xt_option_entry ah_opts[] = {
22 {.name = "ahspi", .id = O_AHSPI, .type = XTTYPE_UINT32RC,
23 .flags = XTOPT_INVERT | XTOPT_PUT, XTOPT_POINTER(s, spis)},
24 {.name = "ahlen", .id = O_AHLEN, .type = XTTYPE_UINT32,
25 .flags = XTOPT_INVERT | XTOPT_PUT, XTOPT_POINTER(s, hdrlen)},
26 {.name = "ahres", .id = O_AHRES, .type = XTTYPE_NONE},
27 XTOPT_TABLEEND,
28 };
29 #undef s
30
ah_init(struct xt_entry_match * m)31 static void ah_init(struct xt_entry_match *m)
32 {
33 struct ip6t_ah *ahinfo = (void *)m->data;
34
35 /* Defaults for when no --ahspi is used at all */
36 ahinfo->spis[1] = ~0U;
37 }
38
ah_parse(struct xt_option_call * cb)39 static void ah_parse(struct xt_option_call *cb)
40 {
41 struct ip6t_ah *ahinfo = cb->data;
42
43 xtables_option_parse(cb);
44 switch (cb->entry->id) {
45 case O_AHSPI:
46 if (cb->nvals == 1)
47 ahinfo->spis[1] = ahinfo->spis[0];
48 if (cb->invert)
49 ahinfo->invflags |= IP6T_AH_INV_SPI;
50 break;
51 case O_AHLEN:
52 if (cb->invert)
53 ahinfo->invflags |= IP6T_AH_INV_LEN;
54 break;
55 case O_AHRES:
56 ahinfo->hdrres = 1;
57 break;
58 }
59 }
60
skip_spi_match(uint32_t min,uint32_t max,bool inv)61 static bool skip_spi_match(uint32_t min, uint32_t max, bool inv)
62 {
63 return min == 0 && max == UINT32_MAX && !inv;
64 }
65
66 static void
print_spis(const char * name,uint32_t min,uint32_t max,int invert)67 print_spis(const char *name, uint32_t min, uint32_t max,
68 int invert)
69 {
70 const char *inv = invert ? "!" : "";
71
72 if (!skip_spi_match(min, max, invert)) {
73 if (min == max)
74 printf("%s:%s%u", name, inv, min);
75 else
76 printf("%ss:%s%u:%u", name, inv, min, max);
77 }
78 }
79
80 static void
print_len(const char * name,uint32_t len,int invert)81 print_len(const char *name, uint32_t len, int invert)
82 {
83 const char *inv = invert ? "!" : "";
84
85 if (len != 0 || invert)
86 printf("%s:%s%u", name, inv, len);
87 }
88
ah_print(const void * ip,const struct xt_entry_match * match,int numeric)89 static void ah_print(const void *ip, const struct xt_entry_match *match,
90 int numeric)
91 {
92 const struct ip6t_ah *ah = (struct ip6t_ah *)match->data;
93
94 printf(" ah ");
95 print_spis("spi", ah->spis[0], ah->spis[1],
96 ah->invflags & IP6T_AH_INV_SPI);
97 print_len("length", ah->hdrlen,
98 ah->invflags & IP6T_AH_INV_LEN);
99
100 if (ah->hdrres)
101 printf(" reserved");
102
103 if (ah->invflags & ~IP6T_AH_INV_MASK)
104 printf(" Unknown invflags: 0x%X",
105 ah->invflags & ~IP6T_AH_INV_MASK);
106 }
107
ah_save(const void * ip,const struct xt_entry_match * match)108 static void ah_save(const void *ip, const struct xt_entry_match *match)
109 {
110 const struct ip6t_ah *ahinfo = (struct ip6t_ah *)match->data;
111 bool inv_spi = ahinfo->invflags & IP6T_AH_INV_SPI;
112
113 if (!skip_spi_match(ahinfo->spis[0], ahinfo->spis[1], inv_spi)) {
114 printf("%s --ahspi ", inv_spi ? " !" : "");
115 if (ahinfo->spis[0]
116 != ahinfo->spis[1])
117 printf("%u:%u",
118 ahinfo->spis[0],
119 ahinfo->spis[1]);
120 else
121 printf("%u",
122 ahinfo->spis[0]);
123 }
124
125 if (ahinfo->hdrlen != 0 || (ahinfo->invflags & IP6T_AH_INV_LEN) ) {
126 printf("%s --ahlen %u",
127 (ahinfo->invflags & IP6T_AH_INV_LEN) ? " !" : "",
128 ahinfo->hdrlen);
129 }
130
131 if (ahinfo->hdrres != 0 )
132 printf(" --ahres");
133 }
134
ah_xlate(struct xt_xlate * xl,const struct xt_xlate_mt_params * params)135 static int ah_xlate(struct xt_xlate *xl,
136 const struct xt_xlate_mt_params *params)
137 {
138 const struct ip6t_ah *ahinfo = (struct ip6t_ah *)params->match->data;
139 bool inv_spi = ahinfo->invflags & IP6T_AH_INV_SPI;
140 char *space = "";
141
142 if (!skip_spi_match(ahinfo->spis[0], ahinfo->spis[1], inv_spi)) {
143 xt_xlate_add(xl, "ah spi%s ", inv_spi ? " !=" : "");
144 if (ahinfo->spis[0] != ahinfo->spis[1])
145 xt_xlate_add(xl, "%u-%u", ahinfo->spis[0],
146 ahinfo->spis[1]);
147 else
148 xt_xlate_add(xl, "%u", ahinfo->spis[0]);
149 space = " ";
150 }
151
152 if (ahinfo->hdrlen != 0 || (ahinfo->invflags & IP6T_AH_INV_LEN)) {
153 xt_xlate_add(xl, "%sah hdrlength%s %u", space,
154 (ahinfo->invflags & IP6T_AH_INV_LEN) ? " !=" : "",
155 ahinfo->hdrlen);
156 space = " ";
157 }
158
159 if (ahinfo->hdrres != 0) {
160 xt_xlate_add(xl, "%sah reserved %u", space, ahinfo->hdrres);
161 space = " ";
162 }
163
164 if (!space[0]) /* plain '-m ah' */
165 xt_xlate_add(xl, "exthdr ah exists");
166
167 return 1;
168 }
169
170 static struct xtables_match ah_mt6_reg = {
171 .name = "ah",
172 .version = XTABLES_VERSION,
173 .family = NFPROTO_IPV6,
174 .size = XT_ALIGN(sizeof(struct ip6t_ah)),
175 .userspacesize = XT_ALIGN(sizeof(struct ip6t_ah)),
176 .help = ah_help,
177 .init = ah_init,
178 .print = ah_print,
179 .save = ah_save,
180 .x6_parse = ah_parse,
181 .x6_options = ah_opts,
182 .xlate = ah_xlate,
183 };
184
185 void
_init(void)186 _init(void)
187 {
188 xtables_register_match(&ah_mt6_reg);
189 }
190