libxt_TPROXY.c revision 73866357e4a7a0fdc1b293bf8863fee2bd56da9e
11320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci/* 21320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * Shared library add-on to iptables to add TPROXY target support. 31320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * 41320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * Copyright (C) 2002-2008 BalaBit IT Ltd. 51320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci */ 61320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include <getopt.h> 71320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include <stdbool.h> 81320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include <stdint.h> 91320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include <stdio.h> 101320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include <string.h> 111320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include <stdlib.h> 121320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include <limits.h> 131320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 141320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include <xtables.h> 151320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include <linux/netfilter/x_tables.h> 161320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include <linux/netfilter/xt_TPROXY.h> 171320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 181320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccistatic const struct option tproxy_tg_opts[] = { 191320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci {.name = "on-port", .has_arg = true, .val = '1'}, 201320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci {.name = "on-ip", .has_arg = true, .val = '2'}, 211320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci {.name = "tproxy-mark", .has_arg = true, .val = '3'}, 221320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci XT_GETOPT_TABLEEND, 231320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}; 241320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 251320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccienum { 261320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci PARAM_ONPORT = 1 << 0, 271320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci PARAM_ONIP = 1 << 1, 281320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci PARAM_MARK = 1 << 2, 291320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}; 301320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 311320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccistatic void tproxy_tg_help(void) 321320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci{ 331320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci printf( 341320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci"TPROXY target options:\n" 351320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci" --on-port port Redirect connection to port, or the original port if 0\n" 361320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci" --on-ip ip Optionally redirect to the given IP\n" 371320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci" --tproxy-mark value[/mask] Mark packets with the given value/mask\n\n"); 381320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci} 391320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 401320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccistatic void parse_tproxy_lport(const char *s, uint16_t *portp) 411320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci{ 421320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci unsigned int lport; 431320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 441320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (xtables_strtoui(s, NULL, &lport, 0, UINT16_MAX)) 451320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci *portp = htons(lport); 461320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci else 471320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci xtables_param_act(XTF_BAD_VALUE, "TPROXY", "--on-port", s); 481320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci} 491320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 501320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccistatic void parse_tproxy_laddr(const char *s, union nf_inet_addr *addrp, 511320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci unsigned int nfproto) 521320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci{ 531320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci struct in6_addr *laddr6 = NULL; 541320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci struct in_addr *laddr4 = NULL; 551320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 561320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (nfproto == NFPROTO_IPV6) { 571320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci laddr6 = xtables_numeric_to_ip6addr(s); 581320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (laddr6 == NULL) 591320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci goto out; 601320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci addrp->in6 = *laddr6; 611320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } else if (nfproto == NFPROTO_IPV4) { 621320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci laddr4 = xtables_numeric_to_ipaddr(s); 631320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (laddr4 == NULL) 641320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci goto out; 651320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci addrp->in = *laddr4; 661320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 671320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci return; 681320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci out: 691320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci xtables_param_act(XTF_BAD_VALUE, "TPROXY", "--on-ip", s); 701320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci} 711320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 721320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccistatic void parse_tproxy_mark(char *s, uint32_t *markp, uint32_t *maskp) 731320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci{ 741320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci unsigned int value, mask = UINT32_MAX; 751320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci char *end; 761320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 771320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (!xtables_strtoui(s, &end, &value, 0, UINT32_MAX)) 781320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci xtables_param_act(XTF_BAD_VALUE, "TPROXY", "--tproxy-mark", s); 791320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (*end == '/') 801320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (!xtables_strtoui(end + 1, &end, &mask, 0, UINT32_MAX)) 811320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci xtables_param_act(XTF_BAD_VALUE, "TPROXY", "--tproxy-mark", s); 821320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (*end != '\0') 831320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci xtables_param_act(XTF_BAD_VALUE, "TPROXY", "--tproxy-mark", s); 841320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 851320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci *markp = value; 861320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci *maskp = mask; 871320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci} 881320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 891320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccistatic int tproxy_tg_parse(int c, char **argv, int invert, unsigned int *flags, 901320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci const void *entry, struct xt_entry_target **target) 911320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci{ 921320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci struct xt_tproxy_target_info *info = (void *)(*target)->data; 931320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 941320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci switch (c) { 951320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci case '1': 961320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci xtables_param_act(XTF_ONLY_ONCE, "TPROXY", "--on-port", *flags & PARAM_ONPORT); 971320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci xtables_param_act(XTF_NO_INVERT, "TPROXY", "--on-port", invert); 981320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci parse_tproxy_lport(optarg, &info->lport); 991320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci *flags |= PARAM_ONPORT; 1001320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci return 1; 1011320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci case '2': 1021320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci xtables_param_act(XTF_ONLY_ONCE, "TPROXY", "--on-ip", *flags & PARAM_ONIP); 1031320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci xtables_param_act(XTF_NO_INVERT, "TPROXY", "--on-ip", invert); 1041320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci parse_tproxy_laddr(optarg, (void *)&info->laddr, NFPROTO_IPV4); 1051320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci *flags |= PARAM_ONIP; 1061320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci return 1; 1071320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci case '3': 1081320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci xtables_param_act(XTF_ONLY_ONCE, "TPROXY", "--tproxy-mark", *flags & PARAM_MARK); 1091320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci xtables_param_act(XTF_NO_INVERT, "TPROXY", "--tproxy-mark", invert); 1101320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci parse_tproxy_mark(optarg, &info->mark_value, &info->mark_mask); 1111320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci *flags |= PARAM_MARK; 1121320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci return 1; 1131320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 1141320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 1151320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci return 0; 116} 117 118static int 119tproxy_tg_parse1(int c, char **argv, int invert, unsigned int *flags, 120 struct xt_tproxy_target_info_v1 *info, unsigned int nfproto) 121{ 122 switch (c) { 123 case '1': 124 xtables_param_act(XTF_ONLY_ONCE, "TPROXY", "--on-port", *flags & PARAM_ONPORT); 125 xtables_param_act(XTF_NO_INVERT, "TPROXY", "--on-port", invert); 126 parse_tproxy_lport(optarg, &info->lport); 127 *flags |= PARAM_ONPORT; 128 return true; 129 case '2': 130 xtables_param_act(XTF_ONLY_ONCE, "TPROXY", "--on-ip", *flags & PARAM_ONIP); 131 xtables_param_act(XTF_NO_INVERT, "TPROXY", "--on-ip", invert); 132 parse_tproxy_laddr(optarg, (void *)&info->laddr, nfproto); 133 *flags |= PARAM_ONIP; 134 return true; 135 case '3': 136 xtables_param_act(XTF_ONLY_ONCE, "TPROXY", "--tproxy-mark", *flags & PARAM_MARK); 137 xtables_param_act(XTF_NO_INVERT, "TPROXY", "--tproxy-mark", invert); 138 parse_tproxy_mark(optarg, &info->mark_value, &info->mark_mask); 139 *flags |= PARAM_MARK; 140 return true; 141 } 142 return false; 143} 144 145static int 146tproxy_tg_parse4(int c, char **argv, int invert, unsigned int *flags, 147 const void *entry, struct xt_entry_target **target) 148{ 149 struct xt_tproxy_target_info_v1 *info = (void *)(*target)->data; 150 return tproxy_tg_parse1(c, argv, invert, flags, info, NFPROTO_IPV4); 151} 152 153static int 154tproxy_tg_parse6(int c, char **argv, int invert, unsigned int *flags, 155 const void *entry, struct xt_entry_target **target) 156{ 157 struct xt_tproxy_target_info_v1 *info = (void *)(*target)->data; 158 return tproxy_tg_parse1(c, argv, invert, flags, info, NFPROTO_IPV6); 159} 160 161static void tproxy_tg_check(unsigned int flags) 162{ 163 if (!(flags & PARAM_ONPORT)) 164 xtables_error(PARAMETER_PROBLEM, 165 "TPROXY target: Parameter --on-port is required"); 166} 167 168static void tproxy_tg_print(const void *ip, const struct xt_entry_target *target, 169 int numeric) 170{ 171 const struct xt_tproxy_target_info *info = (const void *)target->data; 172 printf(" TPROXY redirect %s:%u mark 0x%x/0x%x", 173 xtables_ipaddr_to_numeric((const struct in_addr *)&info->laddr), 174 ntohs(info->lport), (unsigned int)info->mark_value, 175 (unsigned int)info->mark_mask); 176} 177 178static void 179tproxy_tg_print4(const void *ip, const struct xt_entry_target *target, 180 int numeric) 181{ 182 const struct xt_tproxy_target_info_v1 *info = 183 (const void *)target->data; 184 185 printf(" TPROXY redirect %s:%u mark 0x%x/0x%x", 186 xtables_ipaddr_to_numeric(&info->laddr.in), 187 ntohs(info->lport), (unsigned int)info->mark_value, 188 (unsigned int)info->mark_mask); 189} 190 191static void 192tproxy_tg_print6(const void *ip, const struct xt_entry_target *target, 193 int numeric) 194{ 195 const struct xt_tproxy_target_info_v1 *info = 196 (const void *)target->data; 197 198 printf(" TPROXY redirect %s:%u mark 0x%x/0x%x", 199 xtables_ip6addr_to_numeric(&info->laddr.in6), 200 ntohs(info->lport), (unsigned int)info->mark_value, 201 (unsigned int)info->mark_mask); 202} 203 204static void tproxy_tg_save(const void *ip, const struct xt_entry_target *target) 205{ 206 const struct xt_tproxy_target_info *info = (const void *)target->data; 207 208 printf(" --on-port %u", ntohs(info->lport)); 209 printf(" --on-ip %s", 210 xtables_ipaddr_to_numeric((const struct in_addr *)&info->laddr)); 211 printf(" --tproxy-mark 0x%x/0x%x", 212 (unsigned int)info->mark_value, (unsigned int)info->mark_mask); 213} 214 215static void 216tproxy_tg_save4(const void *ip, const struct xt_entry_target *target) 217{ 218 const struct xt_tproxy_target_info_v1 *info; 219 220 info = (const void *)target->data; 221 printf(" --on-port %u", ntohs(info->lport)); 222 printf(" --on-ip %s", xtables_ipaddr_to_numeric(&info->laddr.in)); 223 printf(" --tproxy-mark 0x%x/0x%x", 224 (unsigned int)info->mark_value, (unsigned int)info->mark_mask); 225} 226 227static void 228tproxy_tg_save6(const void *ip, const struct xt_entry_target *target) 229{ 230 const struct xt_tproxy_target_info_v1 *info; 231 232 info = (const void *)target->data; 233 printf(" --on-port %u", ntohs(info->lport)); 234 printf(" --on-ip %s", xtables_ip6addr_to_numeric(&info->laddr.in6)); 235 printf(" --tproxy-mark 0x%x/0x%x", 236 (unsigned int)info->mark_value, (unsigned int)info->mark_mask); 237} 238 239static struct xtables_target tproxy_tg_reg[] = { 240 { 241 .name = "TPROXY", 242 .revision = 0, 243 .family = NFPROTO_IPV4, 244 .version = XTABLES_VERSION, 245 .size = XT_ALIGN(sizeof(struct xt_tproxy_target_info)), 246 .userspacesize = XT_ALIGN(sizeof(struct xt_tproxy_target_info)), 247 .help = tproxy_tg_help, 248 .parse = tproxy_tg_parse, 249 .final_check = tproxy_tg_check, 250 .print = tproxy_tg_print, 251 .save = tproxy_tg_save, 252 .extra_opts = tproxy_tg_opts, 253 }, 254 { 255 .name = "TPROXY", 256 .revision = 1, 257 .family = NFPROTO_IPV4, 258 .version = XTABLES_VERSION, 259 .size = XT_ALIGN(sizeof(struct xt_tproxy_target_info_v1)), 260 .userspacesize = XT_ALIGN(sizeof(struct xt_tproxy_target_info_v1)), 261 .help = tproxy_tg_help, 262 .parse = tproxy_tg_parse4, 263 .final_check = tproxy_tg_check, 264 .print = tproxy_tg_print4, 265 .save = tproxy_tg_save4, 266 .extra_opts = tproxy_tg_opts, 267 }, 268 { 269 .name = "TPROXY", 270 .revision = 1, 271 .family = NFPROTO_IPV6, 272 .version = XTABLES_VERSION, 273 .size = XT_ALIGN(sizeof(struct xt_tproxy_target_info_v1)), 274 .userspacesize = XT_ALIGN(sizeof(struct xt_tproxy_target_info_v1)), 275 .help = tproxy_tg_help, 276 .parse = tproxy_tg_parse6, 277 .final_check = tproxy_tg_check, 278 .print = tproxy_tg_print6, 279 .save = tproxy_tg_save6, 280 .extra_opts = tproxy_tg_opts, 281 }, 282}; 283 284void _init(void) 285{ 286 xtables_register_targets(tproxy_tg_reg, ARRAY_SIZE(tproxy_tg_reg)); 287} 288