1 #include <stdint.h> 2 #include <stdio.h> 3 #include <string.h> 4 #include <xtables.h> 5 #include <limits.h> /* INT_MAX in ip6_tables.h */ 6 #include <linux/netfilter_ipv6/ip6_tables.h> 7 8 enum { 9 O_ICMPV6_TYPE = 0, 10 }; 11 12 struct icmpv6_names { 13 const char *name; 14 uint8_t type; 15 uint8_t code_min, code_max; 16 }; 17 18 static const struct icmpv6_names icmpv6_codes[] = { 19 { "destination-unreachable", 1, 0, 0xFF }, 20 { "no-route", 1, 0, 0 }, 21 { "communication-prohibited", 1, 1, 1 }, 22 { "address-unreachable", 1, 3, 3 }, 23 { "port-unreachable", 1, 4, 4 }, 24 25 { "packet-too-big", 2, 0, 0xFF }, 26 27 { "time-exceeded", 3, 0, 0xFF }, 28 /* Alias */ { "ttl-exceeded", 3, 0, 0xFF }, 29 { "ttl-zero-during-transit", 3, 0, 0 }, 30 { "ttl-zero-during-reassembly", 3, 1, 1 }, 31 32 { "parameter-problem", 4, 0, 0xFF }, 33 { "bad-header", 4, 0, 0 }, 34 { "unknown-header-type", 4, 1, 1 }, 35 { "unknown-option", 4, 2, 2 }, 36 37 { "echo-request", 128, 0, 0xFF }, 38 /* Alias */ { "ping", 128, 0, 0xFF }, 39 40 { "echo-reply", 129, 0, 0xFF }, 41 /* Alias */ { "pong", 129, 0, 0xFF }, 42 43 { "router-solicitation", 133, 0, 0xFF }, 44 45 { "router-advertisement", 134, 0, 0xFF }, 46 47 { "neighbour-solicitation", 135, 0, 0xFF }, 48 /* Alias */ { "neighbor-solicitation", 135, 0, 0xFF }, 49 50 { "neighbour-advertisement", 136, 0, 0xFF }, 51 /* Alias */ { "neighbor-advertisement", 136, 0, 0xFF }, 52 53 { "redirect", 137, 0, 0xFF }, 54 55 }; 56 57 static void 58 print_icmpv6types(void) 59 { 60 unsigned int i; 61 printf("Valid ICMPv6 Types:"); 62 63 for (i = 0; i < ARRAY_SIZE(icmpv6_codes); ++i) { 64 if (i && icmpv6_codes[i].type == icmpv6_codes[i-1].type) { 65 if (icmpv6_codes[i].code_min == icmpv6_codes[i-1].code_min 66 && (icmpv6_codes[i].code_max 67 == icmpv6_codes[i-1].code_max)) 68 printf(" (%s)", icmpv6_codes[i].name); 69 else 70 printf("\n %s", icmpv6_codes[i].name); 71 } 72 else 73 printf("\n%s", icmpv6_codes[i].name); 74 } 75 printf("\n"); 76 } 77 78 static void icmp6_help(void) 79 { 80 printf( 81 "icmpv6 match options:\n" 82 "[!] --icmpv6-type typename match icmpv6 type\n" 83 " (or numeric type or type/code)\n"); 84 print_icmpv6types(); 85 } 86 87 static const struct xt_option_entry icmp6_opts[] = { 88 {.name = "icmpv6-type", .id = O_ICMPV6_TYPE, .type = XTTYPE_STRING, 89 .flags = XTOPT_MAND | XTOPT_INVERT}, 90 XTOPT_TABLEEND, 91 }; 92 93 static void 94 parse_icmpv6(const char *icmpv6type, uint8_t *type, uint8_t code[]) 95 { 96 static const unsigned int limit = ARRAY_SIZE(icmpv6_codes); 97 unsigned int match = limit; 98 unsigned int i; 99 100 for (i = 0; i < limit; i++) { 101 if (strncasecmp(icmpv6_codes[i].name, icmpv6type, strlen(icmpv6type)) 102 == 0) { 103 if (match != limit) 104 xtables_error(PARAMETER_PROBLEM, 105 "Ambiguous ICMPv6 type `%s':" 106 " `%s' or `%s'?", 107 icmpv6type, 108 icmpv6_codes[match].name, 109 icmpv6_codes[i].name); 110 match = i; 111 } 112 } 113 114 if (match != limit) { 115 *type = icmpv6_codes[match].type; 116 code[0] = icmpv6_codes[match].code_min; 117 code[1] = icmpv6_codes[match].code_max; 118 } else { 119 char *slash; 120 char buffer[strlen(icmpv6type) + 1]; 121 unsigned int number; 122 123 strcpy(buffer, icmpv6type); 124 slash = strchr(buffer, '/'); 125 126 if (slash) 127 *slash = '\0'; 128 129 if (!xtables_strtoui(buffer, NULL, &number, 0, UINT8_MAX)) 130 xtables_error(PARAMETER_PROBLEM, 131 "Invalid ICMPv6 type `%s'\n", buffer); 132 *type = number; 133 if (slash) { 134 if (!xtables_strtoui(slash+1, NULL, &number, 0, UINT8_MAX)) 135 xtables_error(PARAMETER_PROBLEM, 136 "Invalid ICMPv6 code `%s'\n", 137 slash+1); 138 code[0] = code[1] = number; 139 } else { 140 code[0] = 0; 141 code[1] = 0xFF; 142 } 143 } 144 } 145 146 static void icmp6_init(struct xt_entry_match *m) 147 { 148 struct ip6t_icmp *icmpv6info = (struct ip6t_icmp *)m->data; 149 150 icmpv6info->code[1] = 0xFF; 151 } 152 153 static void icmp6_parse(struct xt_option_call *cb) 154 { 155 struct ip6t_icmp *icmpv6info = cb->data; 156 157 xtables_option_parse(cb); 158 parse_icmpv6(cb->arg, &icmpv6info->type, icmpv6info->code); 159 if (cb->invert) 160 icmpv6info->invflags |= IP6T_ICMP_INV; 161 } 162 163 static void print_icmpv6type(uint8_t type, 164 uint8_t code_min, uint8_t code_max, 165 int invert, 166 int numeric) 167 { 168 if (!numeric) { 169 unsigned int i; 170 171 for (i = 0; i < ARRAY_SIZE(icmpv6_codes); ++i) 172 if (icmpv6_codes[i].type == type 173 && icmpv6_codes[i].code_min == code_min 174 && icmpv6_codes[i].code_max == code_max) 175 break; 176 177 if (i != ARRAY_SIZE(icmpv6_codes)) { 178 printf(" %s%s", 179 invert ? "!" : "", 180 icmpv6_codes[i].name); 181 return; 182 } 183 } 184 185 if (invert) 186 printf(" !"); 187 188 printf("type %u", type); 189 if (code_min == code_max) 190 printf(" code %u", code_min); 191 else if (code_min != 0 || code_max != 0xFF) 192 printf(" codes %u-%u", code_min, code_max); 193 } 194 195 static void icmp6_print(const void *ip, const struct xt_entry_match *match, 196 int numeric) 197 { 198 const struct ip6t_icmp *icmpv6 = (struct ip6t_icmp *)match->data; 199 200 printf(" ipv6-icmp"); 201 print_icmpv6type(icmpv6->type, icmpv6->code[0], icmpv6->code[1], 202 icmpv6->invflags & IP6T_ICMP_INV, 203 numeric); 204 205 if (icmpv6->invflags & ~IP6T_ICMP_INV) 206 printf(" Unknown invflags: 0x%X", 207 icmpv6->invflags & ~IP6T_ICMP_INV); 208 } 209 210 static void icmp6_save(const void *ip, const struct xt_entry_match *match) 211 { 212 const struct ip6t_icmp *icmpv6 = (struct ip6t_icmp *)match->data; 213 214 if (icmpv6->invflags & IP6T_ICMP_INV) 215 printf(" !"); 216 217 printf(" --icmpv6-type %u", icmpv6->type); 218 if (icmpv6->code[0] != 0 || icmpv6->code[1] != 0xFF) 219 printf("/%u", icmpv6->code[0]); 220 } 221 222 static struct xtables_match icmp6_mt6_reg = { 223 .name = "icmp6", 224 .version = XTABLES_VERSION, 225 .family = NFPROTO_IPV6, 226 .size = XT_ALIGN(sizeof(struct ip6t_icmp)), 227 .userspacesize = XT_ALIGN(sizeof(struct ip6t_icmp)), 228 .help = icmp6_help, 229 .init = icmp6_init, 230 .print = icmp6_print, 231 .save = icmp6_save, 232 .x6_parse = icmp6_parse, 233 .x6_options = icmp6_opts, 234 }; 235 236 void _init(void) 237 { 238 xtables_register_match(&icmp6_mt6_reg); 239 } 240