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_parse(struct xt_option_call * cb)31 static void ah_parse(struct xt_option_call *cb)
32 {
33 	struct ip6t_ah *ahinfo = cb->data;
34 
35 	xtables_option_parse(cb);
36 	switch (cb->entry->id) {
37 	case O_AHSPI:
38 		if (cb->nvals == 1)
39 			ahinfo->spis[1] = ahinfo->spis[0];
40 		if (cb->invert)
41 			ahinfo->invflags |= IP6T_AH_INV_SPI;
42 		break;
43 	case O_AHLEN:
44 		if (cb->invert)
45 			ahinfo->invflags |= IP6T_AH_INV_LEN;
46 		break;
47 	case O_AHRES:
48 		ahinfo->hdrres = 1;
49 		break;
50 	}
51 }
52 
53 static void
print_spis(const char * name,uint32_t min,uint32_t max,int invert)54 print_spis(const char *name, uint32_t min, uint32_t max,
55 	    int invert)
56 {
57 	const char *inv = invert ? "!" : "";
58 
59 	if (min != 0 || max != 0xFFFFFFFF || invert) {
60 		if (min == max)
61 			printf("%s:%s%u", name, inv, min);
62 		else
63 			printf("%ss:%s%u:%u", name, inv, min, max);
64 	}
65 }
66 
67 static void
print_len(const char * name,uint32_t len,int invert)68 print_len(const char *name, uint32_t len, int invert)
69 {
70 	const char *inv = invert ? "!" : "";
71 
72 	if (len != 0 || invert)
73 		printf("%s:%s%u", name, inv, len);
74 }
75 
ah_print(const void * ip,const struct xt_entry_match * match,int numeric)76 static void ah_print(const void *ip, const struct xt_entry_match *match,
77                      int numeric)
78 {
79 	const struct ip6t_ah *ah = (struct ip6t_ah *)match->data;
80 
81 	printf(" ah ");
82 	print_spis("spi", ah->spis[0], ah->spis[1],
83 		    ah->invflags & IP6T_AH_INV_SPI);
84 	print_len("length", ah->hdrlen,
85 		    ah->invflags & IP6T_AH_INV_LEN);
86 
87 	if (ah->hdrres)
88 		printf(" reserved");
89 
90 	if (ah->invflags & ~IP6T_AH_INV_MASK)
91 		printf(" Unknown invflags: 0x%X",
92 		       ah->invflags & ~IP6T_AH_INV_MASK);
93 }
94 
ah_save(const void * ip,const struct xt_entry_match * match)95 static void ah_save(const void *ip, const struct xt_entry_match *match)
96 {
97 	const struct ip6t_ah *ahinfo = (struct ip6t_ah *)match->data;
98 
99 	if (!(ahinfo->spis[0] == 0
100 	    && ahinfo->spis[1] == 0xFFFFFFFF)) {
101 		printf("%s --ahspi ",
102 			(ahinfo->invflags & IP6T_AH_INV_SPI) ? " !" : "");
103 		if (ahinfo->spis[0]
104 		    != ahinfo->spis[1])
105 			printf("%u:%u",
106 			       ahinfo->spis[0],
107 			       ahinfo->spis[1]);
108 		else
109 			printf("%u",
110 			       ahinfo->spis[0]);
111 	}
112 
113 	if (ahinfo->hdrlen != 0 || (ahinfo->invflags & IP6T_AH_INV_LEN) ) {
114 		printf("%s --ahlen %u",
115 			(ahinfo->invflags & IP6T_AH_INV_LEN) ? " !" : "",
116 			ahinfo->hdrlen);
117 	}
118 
119 	if (ahinfo->hdrres != 0 )
120 		printf(" --ahres");
121 }
122 
123 static struct xtables_match ah_mt6_reg = {
124 	.name          = "ah",
125 	.version       = XTABLES_VERSION,
126 	.family        = NFPROTO_IPV6,
127 	.size          = XT_ALIGN(sizeof(struct ip6t_ah)),
128 	.userspacesize = XT_ALIGN(sizeof(struct ip6t_ah)),
129 	.help          = ah_help,
130 	.print         = ah_print,
131 	.save          = ah_save,
132 	.x6_parse      = ah_parse,
133 	.x6_options    = ah_opts,
134 };
135 
136 void
_init(void)137 _init(void)
138 {
139 	xtables_register_match(&ah_mt6_reg);
140 }
141