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