123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285 |
- /*
- * Shared library add-on to iptables to add IPVS matching.
- *
- * Detailed doc is in the kernel module source net/netfilter/xt_ipvs.c
- *
- * Author: Hannes Eder <heder@google.com>
- */
- #include <stdbool.h>
- #include <stdio.h>
- #include <string.h>
- #include <xtables.h>
- #include <linux/ip_vs.h>
- #include <linux/netfilter/xt_ipvs.h>
- enum {
- /* For xt_ipvs: make sure this matches up with %XT_IPVS_*'s order */
- O_IPVS = 0,
- O_VPROTO,
- O_VADDR,
- O_VPORT,
- O_VDIR,
- O_VMETHOD,
- O_VPORTCTL,
- };
- #define s struct xt_ipvs_mtinfo
- static const struct xt_option_entry ipvs_mt_opts[] = {
- {.name = "ipvs", .id = O_IPVS, .type = XTTYPE_NONE,
- .flags = XTOPT_INVERT},
- {.name = "vproto", .id = O_VPROTO, .type = XTTYPE_STRING,
- .flags = XTOPT_INVERT | XTOPT_PUT, XTOPT_POINTER(s, l4proto)},
- {.name = "vaddr", .id = O_VADDR, .type = XTTYPE_HOSTMASK,
- .flags = XTOPT_INVERT},
- {.name = "vport", .id = O_VPORT, .type = XTTYPE_PORT,
- .flags = XTOPT_NBO | XTOPT_INVERT | XTOPT_PUT,
- XTOPT_POINTER(s, vport)},
- {.name = "vdir", .id = O_VDIR, .type = XTTYPE_STRING},
- {.name = "vmethod", .id = O_VMETHOD, .type = XTTYPE_STRING,
- .flags = XTOPT_INVERT},
- {.name = "vportctl", .id = O_VPORTCTL, .type = XTTYPE_PORT,
- .flags = XTOPT_NBO | XTOPT_INVERT | XTOPT_PUT,
- XTOPT_POINTER(s, vportctl)},
- XTOPT_TABLEEND,
- };
- #undef s
- static void ipvs_mt_help(void)
- {
- printf(
- "IPVS match options:\n"
- "[!] --ipvs packet belongs to an IPVS connection\n"
- "\n"
- "Any of the following options implies --ipvs (even negated)\n"
- "[!] --vproto protocol VIP protocol to match; by number or name,\n"
- " e.g. \"tcp\"\n"
- "[!] --vaddr address[/mask] VIP address to match\n"
- "[!] --vport port VIP port to match; by number or name,\n"
- " e.g. \"http\"\n"
- " --vdir {ORIGINAL|REPLY} flow direction of packet\n"
- "[!] --vmethod {GATE|IPIP|MASQ} IPVS forwarding method used\n"
- "[!] --vportctl port VIP port of the controlling connection to\n"
- " match, e.g. 21 for FTP\n"
- );
- }
- static void ipvs_mt_parse(struct xt_option_call *cb)
- {
- struct xt_ipvs_mtinfo *data = cb->data;
- xtables_option_parse(cb);
- switch (cb->entry->id) {
- case O_VPROTO:
- data->l4proto = cb->val.protocol;
- break;
- case O_VADDR:
- memcpy(&data->vaddr, &cb->val.haddr, sizeof(cb->val.haddr));
- memcpy(&data->vmask, &cb->val.hmask, sizeof(cb->val.hmask));
- break;
- case O_VDIR:
- if (strcasecmp(cb->arg, "ORIGINAL") == 0) {
- data->bitmask |= XT_IPVS_DIR;
- data->invert &= ~XT_IPVS_DIR;
- } else if (strcasecmp(cb->arg, "REPLY") == 0) {
- data->bitmask |= XT_IPVS_DIR;
- data->invert |= XT_IPVS_DIR;
- } else {
- xtables_param_act(XTF_BAD_VALUE,
- "ipvs", "--vdir", cb->arg);
- }
- break;
- case O_VMETHOD:
- if (strcasecmp(cb->arg, "GATE") == 0)
- data->fwd_method = IP_VS_CONN_F_DROUTE;
- else if (strcasecmp(cb->arg, "IPIP") == 0)
- data->fwd_method = IP_VS_CONN_F_TUNNEL;
- else if (strcasecmp(cb->arg, "MASQ") == 0)
- data->fwd_method = IP_VS_CONN_F_MASQ;
- else
- xtables_param_act(XTF_BAD_VALUE,
- "ipvs", "--vmethod", cb->arg);
- break;
- }
- data->bitmask |= 1 << cb->entry->id;
- if (cb->invert)
- data->invert |= 1 << cb->entry->id;
- }
- static void ipvs_mt_check(struct xt_fcheck_call *cb)
- {
- struct xt_ipvs_mtinfo *info = cb->data;
- if (cb->xflags == 0)
- xtables_error(PARAMETER_PROBLEM,
- "IPVS: At least one option is required");
- if (info->bitmask & XT_IPVS_ONCE_MASK) {
- if (info->invert & XT_IPVS_IPVS_PROPERTY)
- xtables_error(PARAMETER_PROBLEM,
- "! --ipvs cannot be together with"
- " other options");
- info->bitmask |= XT_IPVS_IPVS_PROPERTY;
- }
- }
- /* Shamelessly copied from libxt_conntrack.c */
- static void ipvs_mt_dump_addr(const union nf_inet_addr *addr,
- const union nf_inet_addr *mask,
- unsigned int family, bool numeric)
- {
- char buf[BUFSIZ];
- if (family == NFPROTO_IPV4) {
- if (!numeric && addr->ip == 0) {
- printf(" anywhere");
- return;
- }
- if (numeric)
- strcpy(buf, xtables_ipaddr_to_numeric(&addr->in));
- else
- strcpy(buf, xtables_ipaddr_to_anyname(&addr->in));
- strcat(buf, xtables_ipmask_to_numeric(&mask->in));
- printf(" %s", buf);
- } else if (family == NFPROTO_IPV6) {
- if (!numeric && addr->ip6[0] == 0 && addr->ip6[1] == 0 &&
- addr->ip6[2] == 0 && addr->ip6[3] == 0) {
- printf(" anywhere");
- return;
- }
- if (numeric)
- strcpy(buf, xtables_ip6addr_to_numeric(&addr->in6));
- else
- strcpy(buf, xtables_ip6addr_to_anyname(&addr->in6));
- strcat(buf, xtables_ip6mask_to_numeric(&mask->in6));
- printf(" %s", buf);
- }
- }
- static void ipvs_mt_dump(const void *ip, const struct xt_ipvs_mtinfo *data,
- unsigned int family, bool numeric, const char *prefix)
- {
- if (data->bitmask == XT_IPVS_IPVS_PROPERTY) {
- if (data->invert & XT_IPVS_IPVS_PROPERTY)
- printf(" !");
- printf(" %sipvs", prefix);
- }
- if (data->bitmask & XT_IPVS_PROTO) {
- if (data->invert & XT_IPVS_PROTO)
- printf(" !");
- printf(" %sproto %u", prefix, data->l4proto);
- }
- if (data->bitmask & XT_IPVS_VADDR) {
- if (data->invert & XT_IPVS_VADDR)
- printf(" !");
- printf(" %svaddr", prefix);
- ipvs_mt_dump_addr(&data->vaddr, &data->vmask, family, numeric);
- }
- if (data->bitmask & XT_IPVS_VPORT) {
- if (data->invert & XT_IPVS_VPORT)
- printf(" !");
- printf(" %svport %u", prefix, ntohs(data->vport));
- }
- if (data->bitmask & XT_IPVS_DIR) {
- if (data->invert & XT_IPVS_DIR)
- printf(" %svdir REPLY", prefix);
- else
- printf(" %svdir ORIGINAL", prefix);
- }
- if (data->bitmask & XT_IPVS_METHOD) {
- if (data->invert & XT_IPVS_METHOD)
- printf(" !");
- printf(" %svmethod", prefix);
- switch (data->fwd_method) {
- case IP_VS_CONN_F_DROUTE:
- printf(" GATE");
- break;
- case IP_VS_CONN_F_TUNNEL:
- printf(" IPIP");
- break;
- case IP_VS_CONN_F_MASQ:
- printf(" MASQ");
- break;
- default:
- /* Hu? */
- printf(" UNKNOWN");
- break;
- }
- }
- if (data->bitmask & XT_IPVS_VPORTCTL) {
- if (data->invert & XT_IPVS_VPORTCTL)
- printf(" !");
- printf(" %svportctl %u", prefix, ntohs(data->vportctl));
- }
- }
- static void ipvs_mt4_print(const void *ip, const struct xt_entry_match *match,
- int numeric)
- {
- const struct xt_ipvs_mtinfo *data = (const void *)match->data;
- ipvs_mt_dump(ip, data, NFPROTO_IPV4, numeric, "");
- }
- static void ipvs_mt6_print(const void *ip, const struct xt_entry_match *match,
- int numeric)
- {
- const struct xt_ipvs_mtinfo *data = (const void *)match->data;
- ipvs_mt_dump(ip, data, NFPROTO_IPV6, numeric, "");
- }
- static void ipvs_mt4_save(const void *ip, const struct xt_entry_match *match)
- {
- const struct xt_ipvs_mtinfo *data = (const void *)match->data;
- ipvs_mt_dump(ip, data, NFPROTO_IPV4, true, "--");
- }
- static void ipvs_mt6_save(const void *ip, const struct xt_entry_match *match)
- {
- const struct xt_ipvs_mtinfo *data = (const void *)match->data;
- ipvs_mt_dump(ip, data, NFPROTO_IPV6, true, "--");
- }
- static struct xtables_match ipvs_matches_reg[] = {
- {
- .version = XTABLES_VERSION,
- .name = "ipvs",
- .revision = 0,
- .family = NFPROTO_IPV4,
- .size = XT_ALIGN(sizeof(struct xt_ipvs_mtinfo)),
- .userspacesize = XT_ALIGN(sizeof(struct xt_ipvs_mtinfo)),
- .help = ipvs_mt_help,
- .x6_parse = ipvs_mt_parse,
- .x6_fcheck = ipvs_mt_check,
- .print = ipvs_mt4_print,
- .save = ipvs_mt4_save,
- .x6_options = ipvs_mt_opts,
- },
- {
- .version = XTABLES_VERSION,
- .name = "ipvs",
- .revision = 0,
- .family = NFPROTO_IPV6,
- .size = XT_ALIGN(sizeof(struct xt_ipvs_mtinfo)),
- .userspacesize = XT_ALIGN(sizeof(struct xt_ipvs_mtinfo)),
- .help = ipvs_mt_help,
- .x6_parse = ipvs_mt_parse,
- .x6_fcheck = ipvs_mt_check,
- .print = ipvs_mt6_print,
- .save = ipvs_mt6_save,
- .x6_options = ipvs_mt_opts,
- },
- };
- void _init(void)
- {
- xtables_register_matches(ipvs_matches_reg,
- ARRAY_SIZE(ipvs_matches_reg));
- }
|