1/* Shared library add-on to iptables to add ROUTE target support. 2 * Author : Cedric de Launois, <delaunois@info.ucl.ac.be> 3 * v 1.11 2004/11/23 4 */ 5 6#include <stdio.h> 7#include <string.h> 8#include <stdlib.h> 9#include <getopt.h> 10#include <iptables.h> 11#include <net/if.h> 12#include <sys/socket.h> 13#include <netinet/in.h> 14#include <arpa/inet.h> 15#include <linux/netfilter_ipv4/ip_tables.h> 16#include <linux/netfilter_ipv4/ipt_ROUTE.h> 17 18/* compile IPT_ROUTE_TEE support even if kernel headers are unpatched */ 19#ifndef IPT_ROUTE_TEE 20#define IPT_ROUTE_TEE 0x02 21#endif 22 23/* Function which prints out usage message. */ 24static void 25help(void) 26{ 27 printf( 28"ROUTE target v%s options:\n" 29" --oif \tifname \t\tRoute packet through `ifname' network interface\n" 30" --iif \tifname \t\tChange packet's incoming interface to `ifname'\n" 31" --gw \tip \t\tRoute packet via this gateway `ip'\n" 32" --continue\t \t\tRoute packet and continue traversing the\n" 33" \t \t\trules. Not valid with --iif or --tee.\n" 34" --tee\t \t\tDuplicate packet, route the duplicate,\n" 35" \t \t\tcontinue traversing with original packet.\n" 36" \t \t\tNot valid with --iif or --continue.\n" 37"\n", 38"1.11"); 39} 40 41static struct option route_opts[] = { 42 {.name = "oif", .has_arg = true, .val = '1' }, 43 {.name = "iif", .has_arg = true, .val = '2' }, 44 {.name = "gw", .has_arg = true, .val = '3' }, 45 {.name = "continue", .has_arg = false, .val = '4' }, 46 {.name = "tee", .has_arg = false, .val = '5' }, 47 XT_GETOPT_TABLEEND, 48}; 49 50/* Initialize the target. */ 51static void ROUTE_init(struct xt_entry_target *t) 52{ 53 struct ipt_route_target_info *route_info = (struct ipt_route_target_info*)t->data; 54 55 route_info->oif[0] = '\0'; 56 route_info->iif[0] = '\0'; 57 route_info->gw = 0; 58 route_info->flags = 0; 59} 60 61 62#define IPT_ROUTE_OPT_OIF 0x01 63#define IPT_ROUTE_OPT_IIF 0x02 64#define IPT_ROUTE_OPT_GW 0x04 65#define IPT_ROUTE_OPT_CONTINUE 0x08 66#define IPT_ROUTE_OPT_TEE 0x10 67 68/* Function which parses command options; returns true if it 69 ate an option */ 70static int ROUTE_parse(int c, char **argv, int invert, unsigned int *flags, 71 const void *entry, struct xt_entry_target **target) 72{ 73 struct ipt_route_target_info *route_info = 74 (struct ipt_route_target_info*)(*target)->data; 75 76 switch (c) { 77 case '1': 78 if (*flags & IPT_ROUTE_OPT_OIF) 79 xtables_error(PARAMETER_PROBLEM, 80 "Can't specify --oif twice"); 81 82 if (*flags & IPT_ROUTE_OPT_IIF) 83 xtables_error(PARAMETER_PROBLEM, 84 "Can't use --oif and --iif together"); 85 86 if (strlen(optarg) > sizeof(route_info->oif) - 1) 87 xtables_error(PARAMETER_PROBLEM, 88 "Maximum interface name length %u", 89 sizeof(route_info->oif) - 1); 90 91 strcpy(route_info->oif, optarg); 92 *flags |= IPT_ROUTE_OPT_OIF; 93 break; 94 95 case '2': 96 if (*flags & IPT_ROUTE_OPT_IIF) 97 xtables_error(PARAMETER_PROBLEM, 98 "Can't specify --iif twice"); 99 100 if (*flags & IPT_ROUTE_OPT_OIF) 101 xtables_error(PARAMETER_PROBLEM, 102 "Can't use --iif and --oif together"); 103 104 if (strlen(optarg) > sizeof(route_info->iif) - 1) 105 xtables_error(PARAMETER_PROBLEM, 106 "Maximum interface name length %u", 107 sizeof(route_info->iif) - 1); 108 109 strcpy(route_info->iif, optarg); 110 *flags |= IPT_ROUTE_OPT_IIF; 111 break; 112 113 case '3': 114 if (*flags & IPT_ROUTE_OPT_GW) 115 xtables_error(PARAMETER_PROBLEM, 116 "Can't specify --gw twice"); 117 118 if (!inet_aton(optarg, (struct in_addr*)&route_info->gw)) { 119 xtables_error(PARAMETER_PROBLEM, 120 "Invalid IP address %s", 121 optarg); 122 } 123 124 *flags |= IPT_ROUTE_OPT_GW; 125 break; 126 127 case '4': 128 if (*flags & IPT_ROUTE_OPT_CONTINUE) 129 xtables_error(PARAMETER_PROBLEM, 130 "Can't specify --continue twice"); 131 if (*flags & IPT_ROUTE_OPT_TEE) 132 xtables_error(PARAMETER_PROBLEM, 133 "Can't specify --continue AND --tee"); 134 135 route_info->flags |= IPT_ROUTE_CONTINUE; 136 *flags |= IPT_ROUTE_OPT_CONTINUE; 137 138 break; 139 140 case '5': 141 if (*flags & IPT_ROUTE_OPT_TEE) 142 xtables_error(PARAMETER_PROBLEM, 143 "Can't specify --tee twice"); 144 if (*flags & IPT_ROUTE_OPT_CONTINUE) 145 xtables_error(PARAMETER_PROBLEM, 146 "Can't specify --tee AND --continue"); 147 148 route_info->flags |= IPT_ROUTE_TEE; 149 *flags |= IPT_ROUTE_OPT_TEE; 150 151 break; 152 153 default: 154 return 0; 155 } 156 157 return 1; 158} 159 160 161static void 162final_check(unsigned int flags) 163{ 164 if (!flags) 165 xtables_error(PARAMETER_PROBLEM, 166 "ROUTE target: oif, iif or gw option required"); 167 168 if ((flags & (IPT_ROUTE_OPT_CONTINUE|IPT_ROUTE_OPT_TEE)) && (flags & IPT_ROUTE_OPT_IIF)) 169 xtables_error(PARAMETER_PROBLEM, 170 "ROUTE target: can't continue traversing the rules with iif option"); 171} 172 173 174/* Prints out the targinfo. */ 175static void 176ROUTE_print(const void *ip, const struct xt_entry_target *target, 177 int numeric) 178{ 179 const struct ipt_route_target_info *route_info 180 = (const struct ipt_route_target_info *)target->data; 181 182 printf("ROUTE "); 183 184 if (route_info->oif[0]) 185 printf("oif:%s ", route_info->oif); 186 187 if (route_info->iif[0]) 188 printf("iif:%s ", route_info->iif); 189 190 if (route_info->gw) { 191 struct in_addr ip_1 = { route_info->gw }; 192 printf("gw:%s ", inet_ntoa(ip_1)); 193 } 194 195 if (route_info->flags & IPT_ROUTE_CONTINUE) 196 printf("continue"); 197 198 if (route_info->flags & IPT_ROUTE_TEE) 199 printf("tee"); 200 201} 202 203 204static void ROUTE_save(const void *ip, const struct xt_entry_target *target) 205{ 206 const struct ipt_route_target_info *route_info 207 = (const struct ipt_route_target_info *)target->data; 208 209 if (route_info->oif[0]) 210 printf("--oif %s ", route_info->oif); 211 212 if (route_info->iif[0]) 213 printf("--iif %s ", route_info->iif); 214 215 if (route_info->gw) { 216 struct in_addr ip_1 = { route_info->gw }; 217 printf("--gw %s ", inet_ntoa(ip_1)); 218 } 219 220 if (route_info->flags & IPT_ROUTE_CONTINUE) 221 printf("--continue "); 222 223 if (route_info->flags & IPT_ROUTE_TEE) 224 printf("--tee "); 225} 226 227 228static struct xtables_target route_target = { 229 .family = NFPROTO_IPV4, 230 .name = "ROUTE", 231 .version = XTABLES_VERSION, 232 .size = XT_ALIGN(sizeof(struct ipt_route_target_info)), 233 .userspacesize = XT_ALIGN(sizeof(struct ipt_route_target_info)), 234 .help = help, 235 .init = ROUTE_init, 236 .parse = ROUTE_parse, 237 .final_check = final_check, 238 .print = ROUTE_print, 239 .save = ROUTE_save, 240 .extra_opts = route_opts 241}; 242 243void _init(void) 244{ 245 xtables_register_target(&route_target); 246} 247