libipt_icmp.c revision 3efb6ead2e51fe1eca55bcb2b06afb4dc4b8cb7c
1/* Shared library add-on to iptables 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 <iptables.h> 8#include <linux/netfilter_ipv4/ip_tables.h> 9 10struct icmp_names { 11 const char *name; 12 u_int8_t type; 13 u_int8_t code_min, code_max; 14}; 15 16static const struct icmp_names icmp_codes[] = { 17 { "echo-reply", 0, 0, 0xFF }, 18 /* Alias */ { "pong", 0, 0, 0xFF }, 19 20 { "destination-unreachable", 3, 0, 0xFF }, 21 { "network-unreachable", 3, 0, 0 }, 22 { "host-unreachable", 3, 1, 1 }, 23 { "protocol-unreachable", 3, 2, 2 }, 24 { "port-unreachable", 3, 3, 3 }, 25 { "fragmentation-needed", 3, 4, 4 }, 26 { "source-route-failed", 3, 5, 5 }, 27 { "network-unknown", 3, 6, 6 }, 28 { "host-unknown", 3, 7, 7 }, 29 { "network-prohibited", 3, 9, 9 }, 30 { "host-prohibited", 3, 10, 10 }, 31 { "TOS-network-unreachable", 3, 11, 11 }, 32 { "TOS-host-unreachable", 3, 12, 12 }, 33 { "communication-prohibited", 3, 13, 13 }, 34 { "host-precedence-violation", 3, 14, 14 }, 35 { "precedence-cutoff", 3, 15, 15 }, 36 37 { "source-quench", 4, 0, 0xFF }, 38 39 { "redirect", 5, 0, 0xFF }, 40 { "network-redirect", 5, 0, 0 }, 41 { "host-redirect", 5, 1, 1 }, 42 { "TOS-network-redirect", 5, 2, 2 }, 43 { "TOS-host-redirect", 5, 3, 3 }, 44 45 { "echo-request", 8, 0, 0xFF }, 46 /* Alias */ { "ping", 8, 0, 0xFF }, 47 48 { "router-advertisement", 9, 0, 0xFF }, 49 50 { "router-solicitation", 10, 0, 0xFF }, 51 52 { "time-exceeded", 11, 0, 0xFF }, 53 /* Alias */ { "ttl-exceeded", 11, 0, 0xFF }, 54 { "ttl-zero-during-transit", 11, 0, 0 }, 55 { "ttl-zero-during-reassembly", 11, 1, 1 }, 56 57 { "parameter-problem", 12, 0, 0xFF }, 58 { "ip-header-bad", 12, 0, 0 }, 59 { "required-option-missing", 12, 1, 1 }, 60 61 { "timestamp-request", 13, 0, 0xFF }, 62 63 { "timestamp-reply", 14, 0, 0xFF }, 64 65 { "address-mask-request", 17, 0, 0xFF }, 66 67 { "address-mask-reply", 18, 0, 0xFF } 68}; 69 70static void 71print_icmptypes() 72{ 73 unsigned int i; 74 printf("Valid ICMP Types:"); 75 76 for (i = 0; i < sizeof(icmp_codes)/sizeof(struct icmp_names); i++) { 77 if (i && icmp_codes[i].type == icmp_codes[i-1].type) { 78 if (icmp_codes[i].code_min == icmp_codes[i-1].code_min 79 && (icmp_codes[i].code_max 80 == icmp_codes[i-1].code_max)) 81 printf(" (%s)", icmp_codes[i].name); 82 else 83 printf("\n %s", icmp_codes[i].name); 84 } 85 else 86 printf("\n%s", icmp_codes[i].name); 87 } 88 printf("\n"); 89} 90 91/* Function which prints out usage message. */ 92static void 93help(void) 94{ 95 printf( 96"ICMP v%s options:\n" 97" --icmp-type [!] typename match icmp type\n" 98" (or numeric type or type/code)\n" 99"\n", NETFILTER_VERSION); 100 print_icmptypes(); 101} 102 103static struct option opts[] = { 104 { "icmp-type", 1, 0, '1' }, 105 {0} 106}; 107 108static unsigned int 109parse_icmp(const char *icmptype, u_int8_t *type, u_int8_t code[]) 110{ 111 unsigned int limit = sizeof(icmp_codes)/sizeof(struct icmp_names); 112 unsigned int match = limit; 113 unsigned int i; 114 115 for (i = 0; i < limit; i++) { 116 if (strncasecmp(icmp_codes[i].name, icmptype, strlen(icmptype)) 117 == 0) { 118 if (match != limit) 119 exit_error(PARAMETER_PROBLEM, 120 "Ambiguous ICMP type `%s':" 121 " `%s' or `%s'?", 122 icmptype, 123 icmp_codes[match].name, 124 icmp_codes[i].name); 125 match = i; 126 } 127 } 128 129 if (match != limit) { 130 *type = icmp_codes[match].type; 131 code[0] = icmp_codes[match].code_min; 132 code[1] = icmp_codes[match].code_max; 133 } else { 134 char *slash; 135 char buffer[strlen(icmptype) + 1]; 136 unsigned int number; 137 138 strcpy(buffer, icmptype); 139 slash = strchr(buffer, '/'); 140 141 if (slash) 142 *slash = '\0'; 143 144 if (string_to_number(buffer, 0, 255, &number) == -1) 145 exit_error(PARAMETER_PROBLEM, 146 "Invalid ICMP type `%s'\n", buffer); 147 *type = number; 148 if (slash) { 149 if (string_to_number(slash+1, 0, 255, &number) == -1) 150 exit_error(PARAMETER_PROBLEM, 151 "Invalid ICMP code `%s'\n", 152 slash+1); 153 code[0] = code[1] = number; 154 } else { 155 code[0] = 0; 156 code[1] = 0xFF; 157 } 158 } 159 160 if (code[0] == 0 && code[1] == 0xFF) 161 return NFC_IP_SRC_PT; 162 else return NFC_IP_SRC_PT | NFC_IP_DST_PT; 163} 164 165/* Initialize the match. */ 166static void 167init(struct ipt_entry_match *m, unsigned int *nfcache) 168{ 169 struct ipt_icmp *icmpinfo = (struct ipt_icmp *)m->data; 170 171 icmpinfo->code[1] = 0xFF; 172} 173 174/* Function which parses command options; returns true if it 175 ate an option */ 176static int 177parse(int c, char **argv, int invert, unsigned int *flags, 178 const struct ipt_entry *entry, 179 unsigned int *nfcache, 180 struct ipt_entry_match **match) 181{ 182 struct ipt_icmp *icmpinfo = (struct ipt_icmp *)(*match)->data; 183 184 switch (c) { 185 case '1': 186 if (check_inverse(optarg, &invert)) 187 optind++; 188 *nfcache |= parse_icmp(argv[optind-1], 189 &icmpinfo->type, 190 icmpinfo->code); 191 if (invert) 192 icmpinfo->invflags |= IPT_ICMP_INV; 193 break; 194 195 default: 196 return 0; 197 } 198 199 return 1; 200} 201 202static void print_icmptype(u_int8_t type, 203 u_int8_t code_min, u_int8_t code_max, 204 int invert, 205 int numeric) 206{ 207 if (!numeric) { 208 unsigned int i; 209 210 for (i = 0; 211 i < sizeof(icmp_codes)/sizeof(struct icmp_names); 212 i++) { 213 if (icmp_codes[i].type == type 214 && icmp_codes[i].code_min == code_min 215 && icmp_codes[i].code_max == code_max) 216 break; 217 } 218 219 if (i != sizeof(icmp_codes)/sizeof(struct icmp_names)) { 220 printf("%s%s ", 221 invert ? "!" : "", 222 icmp_codes[i].name); 223 return; 224 } 225 } 226 227 if (invert) 228 printf("!"); 229 230 printf("type %u", type); 231 if (code_min == 0 && code_max == 0xFF) 232 printf(" "); 233 else if (code_min == code_max) 234 printf(" code %u ", code_min); 235 else 236 printf(" codes %u-%u ", code_min, code_max); 237} 238 239/* Prints out the union ipt_matchinfo. */ 240static void 241print(const struct ipt_ip *ip, 242 const struct ipt_entry_match *match, 243 int numeric) 244{ 245 const struct ipt_icmp *icmp = (struct ipt_icmp *)match->data; 246 247 printf("icmp "); 248 print_icmptype(icmp->type, icmp->code[0], icmp->code[1], 249 icmp->invflags & IPT_ICMP_INV, 250 numeric); 251 252 if (icmp->invflags & ~IPT_ICMP_INV) 253 printf("Unknown invflags: 0x%X ", 254 icmp->invflags & ~IPT_ICMP_INV); 255} 256 257/* Saves the match in parsable form to stdout. */ 258static void save(const struct ipt_ip *ip, const struct ipt_entry_match *match) 259{ 260 const struct ipt_icmp *icmp = (struct ipt_icmp *)match->data; 261 262 if (icmp->invflags & IPT_ICMP_INV) 263 printf("! "); 264 265 printf("--icmp-type %u", icmp->type); 266 if (icmp->code[0] != 0 || icmp->code[1] != 0xFF) 267 printf("/%u", icmp->code[0]); 268 printf(" "); 269} 270 271/* Final check; we don't care. */ 272static void final_check(unsigned int flags) 273{ 274} 275 276static 277struct iptables_match icmp 278= { NULL, 279 "icmp", 280 NETFILTER_VERSION, 281 IPT_ALIGN(sizeof(struct ipt_icmp)), 282 IPT_ALIGN(sizeof(struct ipt_icmp)), 283 &help, 284 &init, 285 &parse, 286 &final_check, 287 &print, 288 &save, 289 opts 290}; 291 292void _init(void) 293{ 294 register_match(&icmp); 295} 296