| lh | 9ed821d | 2023-04-07 01:36:19 -0700 | [diff] [blame] | 1 | /* Shared library add-on to ip6tables to add AH support. */ | 
|  | 2 | #include <stdio.h> | 
|  | 3 | #include <netdb.h> | 
|  | 4 | #include <string.h> | 
|  | 5 | #include <stdlib.h> | 
|  | 6 | #include <getopt.h> | 
|  | 7 | #include <errno.h> | 
|  | 8 | #include <xtables.h> | 
|  | 9 | #include <linux/netfilter_ipv6/ip6t_ah.h> | 
|  | 10 |  | 
|  | 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 filed, too\n"); | 
|  | 18 | } | 
|  | 19 |  | 
|  | 20 | static const struct option ah_opts[] = { | 
|  | 21 | { .name = "ahspi", .has_arg = 1, .val = '1' }, | 
|  | 22 | { .name = "ahlen", .has_arg = 1, .val = '2' }, | 
|  | 23 | { .name = "ahres", .has_arg = 0, .val = '3' }, | 
|  | 24 | { .name = NULL } | 
|  | 25 | }; | 
|  | 26 |  | 
|  | 27 | static u_int32_t | 
|  | 28 | parse_ah_spi(const char *spistr, const char *typestr) | 
|  | 29 | { | 
|  | 30 | unsigned long int spi; | 
|  | 31 | char* ep; | 
|  | 32 |  | 
|  | 33 | spi = strtoul(spistr, &ep, 0); | 
|  | 34 |  | 
|  | 35 | if ( spistr == ep ) | 
|  | 36 | xtables_error(PARAMETER_PROBLEM, | 
|  | 37 | "AH no valid digits in %s `%s'", typestr, spistr); | 
|  | 38 |  | 
|  | 39 | if ( spi == ULONG_MAX  && errno == ERANGE ) | 
|  | 40 | xtables_error(PARAMETER_PROBLEM, | 
|  | 41 | "%s `%s' specified too big: would overflow", | 
|  | 42 | typestr, spistr); | 
|  | 43 |  | 
|  | 44 | if ( *spistr != '\0'  && *ep != '\0' ) | 
|  | 45 | xtables_error(PARAMETER_PROBLEM, | 
|  | 46 | "AH error parsing %s `%s'", typestr, spistr); | 
|  | 47 |  | 
|  | 48 | return spi; | 
|  | 49 | } | 
|  | 50 |  | 
|  | 51 | static void | 
|  | 52 | parse_ah_spis(const char *spistring, u_int32_t *spis) | 
|  | 53 | { | 
|  | 54 | char *buffer; | 
|  | 55 | char *cp; | 
|  | 56 |  | 
|  | 57 | buffer = strdup(spistring); | 
|  | 58 | if ((cp = strchr(buffer, ':')) == NULL) | 
|  | 59 | spis[0] = spis[1] = parse_ah_spi(buffer, "spi"); | 
|  | 60 | else { | 
|  | 61 | *cp = '\0'; | 
|  | 62 | cp++; | 
|  | 63 |  | 
|  | 64 | spis[0] = buffer[0] ? parse_ah_spi(buffer, "spi") : 0; | 
|  | 65 | spis[1] = cp[0] ? parse_ah_spi(cp, "spi") : 0xFFFFFFFF; | 
|  | 66 | } | 
|  | 67 | free(buffer); | 
|  | 68 | } | 
|  | 69 |  | 
|  | 70 | static void ah_init(struct xt_entry_match *m) | 
|  | 71 | { | 
|  | 72 | struct ip6t_ah *ahinfo = (struct ip6t_ah *)m->data; | 
|  | 73 |  | 
|  | 74 | ahinfo->spis[1] = 0xFFFFFFFF; | 
|  | 75 | ahinfo->hdrlen = 0; | 
|  | 76 | ahinfo->hdrres = 0; | 
|  | 77 | } | 
|  | 78 |  | 
|  | 79 | static int ah_parse(int c, char **argv, int invert, unsigned int *flags, | 
|  | 80 | const void *entry, struct xt_entry_match **match) | 
|  | 81 | { | 
|  | 82 | struct ip6t_ah *ahinfo = (struct ip6t_ah *)(*match)->data; | 
|  | 83 |  | 
|  | 84 | switch (c) { | 
|  | 85 | case '1': | 
|  | 86 | if (*flags & IP6T_AH_SPI) | 
|  | 87 | xtables_error(PARAMETER_PROBLEM, | 
|  | 88 | "Only one `--ahspi' allowed"); | 
|  | 89 | xtables_check_inverse(optarg, &invert, &optind, 0); | 
|  | 90 | parse_ah_spis(argv[optind-1], ahinfo->spis); | 
|  | 91 | if (invert) | 
|  | 92 | ahinfo->invflags |= IP6T_AH_INV_SPI; | 
|  | 93 | *flags |= IP6T_AH_SPI; | 
|  | 94 | break; | 
|  | 95 | case '2': | 
|  | 96 | if (*flags & IP6T_AH_LEN) | 
|  | 97 | xtables_error(PARAMETER_PROBLEM, | 
|  | 98 | "Only one `--ahlen' allowed"); | 
|  | 99 | xtables_check_inverse(optarg, &invert, &optind, 0); | 
|  | 100 | ahinfo->hdrlen = parse_ah_spi(argv[optind-1], "length"); | 
|  | 101 | if (invert) | 
|  | 102 | ahinfo->invflags |= IP6T_AH_INV_LEN; | 
|  | 103 | *flags |= IP6T_AH_LEN; | 
|  | 104 | break; | 
|  | 105 | case '3': | 
|  | 106 | if (*flags & IP6T_AH_RES) | 
|  | 107 | xtables_error(PARAMETER_PROBLEM, | 
|  | 108 | "Only one `--ahres' allowed"); | 
|  | 109 | ahinfo->hdrres = 1; | 
|  | 110 | *flags |= IP6T_AH_RES; | 
|  | 111 | break; | 
|  | 112 | default: | 
|  | 113 | return 0; | 
|  | 114 | } | 
|  | 115 |  | 
|  | 116 | return 1; | 
|  | 117 | } | 
|  | 118 |  | 
|  | 119 | static void | 
|  | 120 | print_spis(const char *name, u_int32_t min, u_int32_t max, | 
|  | 121 | int invert) | 
|  | 122 | { | 
|  | 123 | const char *inv = invert ? "!" : ""; | 
|  | 124 |  | 
|  | 125 | if (min != 0 || max != 0xFFFFFFFF || invert) { | 
|  | 126 | if (min == max) | 
|  | 127 | printf("%s:%s%u ", name, inv, min); | 
|  | 128 | else | 
|  | 129 | printf("%ss:%s%u:%u ", name, inv, min, max); | 
|  | 130 | } | 
|  | 131 | } | 
|  | 132 |  | 
|  | 133 | static void | 
|  | 134 | print_len(const char *name, u_int32_t len, int invert) | 
|  | 135 | { | 
|  | 136 | const char *inv = invert ? "!" : ""; | 
|  | 137 |  | 
|  | 138 | if (len != 0 || invert) | 
|  | 139 | printf("%s:%s%u ", name, inv, len); | 
|  | 140 | } | 
|  | 141 |  | 
|  | 142 | static void ah_print(const void *ip, const struct xt_entry_match *match, | 
|  | 143 | int numeric) | 
|  | 144 | { | 
|  | 145 | const struct ip6t_ah *ah = (struct ip6t_ah *)match->data; | 
|  | 146 |  | 
|  | 147 | printf("ah "); | 
|  | 148 | print_spis("spi", ah->spis[0], ah->spis[1], | 
|  | 149 | ah->invflags & IP6T_AH_INV_SPI); | 
|  | 150 | print_len("length", ah->hdrlen, | 
|  | 151 | ah->invflags & IP6T_AH_INV_LEN); | 
|  | 152 |  | 
|  | 153 | if (ah->hdrres) | 
|  | 154 | printf("reserved "); | 
|  | 155 |  | 
|  | 156 | if (ah->invflags & ~IP6T_AH_INV_MASK) | 
|  | 157 | printf("Unknown invflags: 0x%X ", | 
|  | 158 | ah->invflags & ~IP6T_AH_INV_MASK); | 
|  | 159 | } | 
|  | 160 |  | 
|  | 161 | static void ah_save(const void *ip, const struct xt_entry_match *match) | 
|  | 162 | { | 
|  | 163 | const struct ip6t_ah *ahinfo = (struct ip6t_ah *)match->data; | 
|  | 164 |  | 
|  | 165 | if (!(ahinfo->spis[0] == 0 | 
|  | 166 | && ahinfo->spis[1] == 0xFFFFFFFF)) { | 
|  | 167 | printf("%s--ahspi ", | 
|  | 168 | (ahinfo->invflags & IP6T_AH_INV_SPI) ? "! " : ""); | 
|  | 169 | if (ahinfo->spis[0] | 
|  | 170 | != ahinfo->spis[1]) | 
|  | 171 | printf("%u:%u ", | 
|  | 172 | ahinfo->spis[0], | 
|  | 173 | ahinfo->spis[1]); | 
|  | 174 | else | 
|  | 175 | printf("%u ", | 
|  | 176 | ahinfo->spis[0]); | 
|  | 177 | } | 
|  | 178 |  | 
|  | 179 | if (ahinfo->hdrlen != 0 || (ahinfo->invflags & IP6T_AH_INV_LEN) ) { | 
|  | 180 | printf("%s--ahlen %u ", | 
|  | 181 | (ahinfo->invflags & IP6T_AH_INV_LEN) ? "! " : "", | 
|  | 182 | ahinfo->hdrlen); | 
|  | 183 | } | 
|  | 184 |  | 
|  | 185 | if (ahinfo->hdrres != 0 ) | 
|  | 186 | printf("--ahres "); | 
|  | 187 | } | 
|  | 188 |  | 
|  | 189 | static struct xtables_match ah_mt6_reg = { | 
|  | 190 | .name          = "ah", | 
|  | 191 | .version       = XTABLES_VERSION, | 
|  | 192 | .family        = NFPROTO_IPV6, | 
|  | 193 | .size          = XT_ALIGN(sizeof(struct ip6t_ah)), | 
|  | 194 | .userspacesize = XT_ALIGN(sizeof(struct ip6t_ah)), | 
|  | 195 | .help          = ah_help, | 
|  | 196 | .init          = ah_init, | 
|  | 197 | .parse         = ah_parse, | 
|  | 198 | .print         = ah_print, | 
|  | 199 | .save          = ah_save, | 
|  | 200 | .extra_opts    = ah_opts, | 
|  | 201 | }; | 
|  | 202 |  | 
|  | 203 | void | 
|  | 204 | _init(void) | 
|  | 205 | { | 
|  | 206 | xtables_register_match(&ah_mt6_reg); | 
|  | 207 | } |