1 /* Shared library add-on to iptables to add customized REJECT support. 2 * 3 * (C) 2000 Jozsef Kadlecsik <kadlec (at) blackhole.kfki.hu> 4 */ 5 #include <stdio.h> 6 #include <string.h> 7 #include <stdlib.h> 8 #include <getopt.h> 9 #include <iptables.h> 10 #include <linux/netfilter_ipv4/ip_tables.h> 11 #include <linux/netfilter_ipv4/ipt_REJECT.h> 12 #include <linux/version.h> 13 14 /* If we are compiling against a kernel that does not support 15 * IPT_ICMP_ADMIN_PROHIBITED, we are emulating it. 16 * The result will be a plain DROP of the packet instead of 17 * reject. -- Maciej Soltysiak <solt (at) dns.toxicfilms.tv> 18 */ 19 #ifndef IPT_ICMP_ADMIN_PROHIBITED 20 #define IPT_ICMP_ADMIN_PROHIBITED IPT_TCP_RESET + 1 21 #endif 22 23 struct reject_names { 24 const char *name; 25 const char *alias; 26 enum ipt_reject_with with; 27 const char *desc; 28 }; 29 30 static const struct reject_names reject_table[] = { 31 {"icmp-net-unreachable", "net-unreach", 32 IPT_ICMP_NET_UNREACHABLE, "ICMP network unreachable"}, 33 {"icmp-host-unreachable", "host-unreach", 34 IPT_ICMP_HOST_UNREACHABLE, "ICMP host unreachable"}, 35 {"icmp-proto-unreachable", "proto-unreach", 36 IPT_ICMP_PROT_UNREACHABLE, "ICMP protocol unreachable"}, 37 {"icmp-port-unreachable", "port-unreach", 38 IPT_ICMP_PORT_UNREACHABLE, "ICMP port unreachable (default)"}, 39 #if 0 40 {"echo-reply", "echoreply", 41 IPT_ICMP_ECHOREPLY, "for ICMP echo only: faked ICMP echo reply"}, 42 #endif 43 {"icmp-net-prohibited", "net-prohib", 44 IPT_ICMP_NET_PROHIBITED, "ICMP network prohibited"}, 45 {"icmp-host-prohibited", "host-prohib", 46 IPT_ICMP_HOST_PROHIBITED, "ICMP host prohibited"}, 47 {"tcp-reset", "tcp-rst", 48 IPT_TCP_RESET, "TCP RST packet"}, 49 {"icmp-admin-prohibited", "admin-prohib", 50 IPT_ICMP_ADMIN_PROHIBITED, "ICMP administratively prohibited (*)"} 51 }; 52 53 static void 54 print_reject_types() 55 { 56 unsigned int i; 57 58 printf("Valid reject types:\n"); 59 60 for (i = 0; i < sizeof(reject_table)/sizeof(struct reject_names); i++) { 61 printf(" %-25s\t%s\n", reject_table[i].name, reject_table[i].desc); 62 printf(" %-25s\talias\n", reject_table[i].alias); 63 } 64 printf("\n"); 65 } 66 67 /* Saves the union ipt_targinfo in parsable form to stdout. */ 68 69 /* Function which prints out usage message. */ 70 static void 71 help(void) 72 { 73 printf( 74 "REJECT options:\n" 75 "--reject-with type drop input packet and send back\n" 76 " a reply packet according to type:\n"); 77 78 print_reject_types(); 79 80 printf("(*) See man page or read the INCOMPATIBILITES file for compatibility issues.\n"); 81 } 82 83 static struct option opts[] = { 84 { "reject-with", 1, 0, '1' }, 85 { 0 } 86 }; 87 88 /* Allocate and initialize the target. */ 89 static void 90 init(struct ipt_entry_target *t, unsigned int *nfcache) 91 { 92 struct ipt_reject_info *reject = (struct ipt_reject_info *)t->data; 93 94 /* default */ 95 reject->with = IPT_ICMP_PORT_UNREACHABLE; 96 97 } 98 99 /* Function which parses command options; returns true if it 100 ate an option */ 101 static int 102 parse(int c, char **argv, int invert, unsigned int *flags, 103 const struct ipt_entry *entry, 104 struct ipt_entry_target **target) 105 { 106 struct ipt_reject_info *reject = (struct ipt_reject_info *)(*target)->data; 107 unsigned int limit = sizeof(reject_table)/sizeof(struct reject_names); 108 unsigned int i; 109 110 switch(c) { 111 case '1': 112 if (check_inverse(optarg, &invert, NULL, 0)) 113 exit_error(PARAMETER_PROBLEM, 114 "Unexpected `!' after --reject-with"); 115 for (i = 0; i < limit; i++) { 116 if ((strncasecmp(reject_table[i].name, optarg, strlen(optarg)) == 0) 117 || (strncasecmp(reject_table[i].alias, optarg, strlen(optarg)) == 0)) { 118 reject->with = reject_table[i].with; 119 return 1; 120 } 121 } 122 /* This due to be dropped late in 2.4 pre-release cycle --RR */ 123 if (strncasecmp("echo-reply", optarg, strlen(optarg)) == 0 124 || strncasecmp("echoreply", optarg, strlen(optarg)) == 0) 125 fprintf(stderr, "--reject-with echo-reply no longer" 126 " supported\n"); 127 exit_error(PARAMETER_PROBLEM, "unknown reject type `%s'",optarg); 128 default: 129 /* Fall through */ 130 break; 131 } 132 return 0; 133 } 134 135 /* Final check; nothing. */ 136 static void final_check(unsigned int flags) 137 { 138 } 139 140 /* Prints out ipt_reject_info. */ 141 static void 142 print(const struct ipt_ip *ip, 143 const struct ipt_entry_target *target, 144 int numeric) 145 { 146 const struct ipt_reject_info *reject 147 = (const struct ipt_reject_info *)target->data; 148 unsigned int i; 149 150 for (i = 0; i < sizeof(reject_table)/sizeof(struct reject_names); i++) { 151 if (reject_table[i].with == reject->with) 152 break; 153 } 154 printf("reject-with %s ", reject_table[i].name); 155 } 156 157 /* Saves ipt_reject in parsable form to stdout. */ 158 static void save(const struct ipt_ip *ip, const struct ipt_entry_target *target) 159 { 160 const struct ipt_reject_info *reject 161 = (const struct ipt_reject_info *)target->data; 162 unsigned int i; 163 164 for (i = 0; i < sizeof(reject_table)/sizeof(struct reject_names); i++) 165 if (reject_table[i].with == reject->with) 166 break; 167 168 printf("--reject-with %s ", reject_table[i].name); 169 } 170 171 static struct iptables_target reject = { 172 .next = NULL, 173 .name = "REJECT", 174 .version = IPTABLES_VERSION, 175 .size = IPT_ALIGN(sizeof(struct ipt_reject_info)), 176 .userspacesize = IPT_ALIGN(sizeof(struct ipt_reject_info)), 177 .help = &help, 178 .init = &init, 179 .parse = &parse, 180 .final_check = &final_check, 181 .print = &print, 182 .save = &save, 183 .extra_opts = opts 184 }; 185 186 void ipt_REJECT_init(void) 187 { 188 register_target(&reject); 189 } 190