libipt_icmp.c revision 73f72f541ac4dab538d4d418b9bbf1707b31342b
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 int number; 137 138 strcpy(buffer, icmptype); 139 slash = strchr(buffer, '/'); 140 141 if (slash) 142 *slash = '\0'; 143 144 number = string_to_number(buffer, 0, 255); 145 if (number == -1) 146 exit_error(PARAMETER_PROBLEM, 147 "Invalid ICMP type `%s'\n", buffer); 148 *type = number; 149 if (slash) { 150 number = string_to_number(slash+1, 0, 255); 151 if (number == -1) 152 exit_error(PARAMETER_PROBLEM, 153 "Invalid ICMP code `%s'\n", 154 slash+1); 155 code[0] = code[1] = number; 156 } else { 157 code[0] = 0; 158 code[1] = 0xFF; 159 } 160 } 161 162 if (code[0] == 0 && code[1] == 0xFF) 163 return NFC_IP_SRC_PT; 164 else return NFC_IP_SRC_PT | NFC_IP_DST_PT; 165} 166 167/* Initialize the match. */ 168static void 169init(struct ipt_entry_match *m, unsigned int *nfcache) 170{ 171 struct ipt_icmp *icmpinfo = (struct ipt_icmp *)m->data; 172 173 icmpinfo->code[1] = 0xFF; 174} 175 176/* Function which parses command options; returns true if it 177 ate an option */ 178static int 179parse(int c, char **argv, int invert, unsigned int *flags, 180 const struct ipt_entry *entry, 181 unsigned int *nfcache, 182 struct ipt_entry_match **match) 183{ 184 struct ipt_icmp *icmpinfo = (struct ipt_icmp *)(*match)->data; 185 186 switch (c) { 187 case '1': 188 if (check_inverse(optarg, &invert)) 189 optind++; 190 *nfcache |= parse_icmp(argv[optind-1], 191 &icmpinfo->type, 192 icmpinfo->code); 193 if (invert) 194 icmpinfo->invflags |= IPT_ICMP_INV; 195 break; 196 197 default: 198 return 0; 199 } 200 201 return 1; 202} 203 204static void print_icmptype(u_int8_t type, 205 u_int8_t code_min, u_int8_t code_max, 206 int invert, 207 int numeric) 208{ 209 if (!numeric) { 210 unsigned int i; 211 212 for (i = 0; 213 i < sizeof(icmp_codes)/sizeof(struct icmp_names); 214 i++) { 215 if (icmp_codes[i].type == type 216 && icmp_codes[i].code_min == code_min 217 && icmp_codes[i].code_max == code_max) 218 break; 219 } 220 221 if (i != sizeof(icmp_codes)/sizeof(struct icmp_names)) { 222 printf("%s%s ", 223 invert ? "!" : "", 224 icmp_codes[i].name); 225 return; 226 } 227 } 228 229 if (invert) 230 printf("!"); 231 232 printf("type %u", type); 233 if (code_min == 0 && code_max == 0xFF) 234 printf(" "); 235 else if (code_min == code_max) 236 printf(" code %u ", code_min); 237 else 238 printf(" codes %u-%u ", code_min, code_max); 239} 240 241/* Prints out the union ipt_matchinfo. */ 242static void 243print(const struct ipt_ip *ip, 244 const struct ipt_entry_match *match, 245 int numeric) 246{ 247 const struct ipt_icmp *icmp = (struct ipt_icmp *)match->data; 248 249 printf("icmp "); 250 print_icmptype(icmp->type, icmp->code[0], icmp->code[1], 251 icmp->invflags & IPT_ICMP_INV, 252 numeric); 253 254 if (icmp->invflags & ~IPT_ICMP_INV) 255 printf("Unknown invflags: 0x%X ", 256 icmp->invflags & ~IPT_ICMP_INV); 257} 258 259/* Saves the match in parsable form to stdout. */ 260static void save(const struct ipt_ip *ip, const struct ipt_entry_match *match) 261{ 262 const struct ipt_icmp *icmp = (struct ipt_icmp *)match->data; 263 264 if (icmp->invflags & IPT_ICMP_INV) 265 printf("! "); 266 267 printf("--icmp-type %u", icmp->type); 268 if (icmp->code[0] != 0 || icmp->code[1] != 0xFF) 269 printf("/%u", icmp->code[0]); 270 printf(" "); 271} 272 273/* Final check; we don't care. */ 274static void final_check(unsigned int flags) 275{ 276} 277 278struct iptables_match icmp 279= { NULL, 280 "icmp", 281 NETFILTER_VERSION, 282 IPT_ALIGN(sizeof(struct ipt_icmp)), 283 IPT_ALIGN(sizeof(struct ipt_icmp)), 284 &help, 285 &init, 286 &parse, 287 &final_check, 288 &print, 289 &save, 290 opts 291}; 292 293void _init(void) 294{ 295 register_match(&icmp); 296} 297