• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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