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