iproute2/tc/em_ipt.c
<<
>>
Prefs
   1/*
   2 * em_ipt.c             IPtables extensions matching Ematch
   3 *
   4 * (C) 2018 Eyal Birger <eyal.birger@gmail.com>
   5 *
   6 * This program is free software; you can redistribute it and/or modify
   7 * it under the terms of the GNU General Public License version 2 as
   8 * published by the Free Software Foundation.
   9 */
  10
  11#include <getopt.h>
  12
  13#include <linux/tc_ematch/tc_em_ipt.h>
  14#include <linux/pkt_cls.h>
  15#include <xtables.h>
  16#include "m_ematch.h"
  17
  18static void em_ipt_print_usage(FILE *fd)
  19{
  20        fprintf(fd,
  21                "Usage: ipt([-6] -m MATCH_NAME [MATCH_OPTS])\n"
  22                "Example: 'ipt(-m policy --reqid 1 --pol ipsec --dir in)'\n");
  23}
  24
  25static struct option original_opts[] = {
  26        {
  27                .name = "match",
  28                .has_arg = 1,
  29                .val = 'm'
  30        },
  31        {
  32                .name = "ipv6",
  33                .val = '6'
  34        },
  35        {}
  36};
  37
  38static struct xtables_globals em_tc_ipt_globals = {
  39        .option_offset = 0,
  40        .program_name = "tc-em-ipt",
  41        .program_version = "0.1",
  42        .orig_opts = original_opts,
  43        .opts = original_opts,
  44#if (XTABLES_VERSION_CODE >= 11)
  45        .compat_rev = xtables_compatible_revision,
  46#endif
  47};
  48
  49static struct xt_entry_match *fake_xt_entry_match(int data_size, void *data)
  50{
  51        struct xt_entry_match *m;
  52
  53        m = xtables_calloc(1, XT_ALIGN(sizeof(*m)) + data_size);
  54        if (!m)
  55                return NULL;
  56
  57        if (data)
  58                memcpy(m->data, data, data_size);
  59
  60        m->u.user.match_size = data_size;
  61        return m;
  62}
  63
  64static void scrub_match(struct xtables_match *match)
  65{
  66        match->mflags = 0;
  67        free(match->m);
  68        match->m = NULL;
  69}
  70
  71/* IPv4 and IPv6 share the same hooking enumeration */
  72#define HOOK_PRE_ROUTING 0
  73#define HOOK_POST_ROUTING 4
  74
  75static __u32 em_ipt_hook(struct nlmsghdr *n)
  76{
  77        struct tcmsg *t = NLMSG_DATA(n);
  78
  79        if (t->tcm_parent != TC_H_ROOT &&
  80            t->tcm_parent == TC_H_MAJ(TC_H_INGRESS))
  81                return HOOK_PRE_ROUTING;
  82
  83        return HOOK_POST_ROUTING;
  84}
  85
  86static int em_ipt_parse_eopt_argv(struct nlmsghdr *n,
  87                                  struct tcf_ematch_hdr *hdr,
  88                                  int argc, char **argv)
  89{
  90        struct xtables_globals tmp_tcipt_globals = em_tc_ipt_globals;
  91        struct xtables_match *match = NULL;
  92        __u8 nfproto = NFPROTO_IPV4;
  93
  94        while (1) {
  95                struct option *opts;
  96                int c;
  97
  98                c = getopt_long(argc, argv, "6m:", tmp_tcipt_globals.opts,
  99                                NULL);
 100                if (c == -1)
 101                        break;
 102
 103                switch (c) {
 104                case 'm':
 105                        xtables_init_all(&tmp_tcipt_globals, nfproto);
 106
 107                        match = xtables_find_match(optarg, XTF_TRY_LOAD, NULL);
 108                        if (!match || !match->x6_parse) {
 109                                fprintf(stderr, " failed to find match %s\n\n",
 110                                        optarg);
 111                                return -1;
 112                        }
 113
 114                        match->m = fake_xt_entry_match(match->size, NULL);
 115                        if (!match->m) {
 116                                printf(" %s error\n", match->name);
 117                                return -1;
 118                        }
 119
 120                        if (match->init)
 121                                match->init(match->m);
 122
 123                        opts = xtables_options_xfrm(tmp_tcipt_globals.orig_opts,
 124                                                    tmp_tcipt_globals.opts,
 125                                                    match->x6_options,
 126                                                    &match->option_offset);
 127                        if (!opts) {
 128                                scrub_match(match);
 129                                return -1;
 130                        }
 131
 132                        tmp_tcipt_globals.opts = opts;
 133                        break;
 134
 135                case '6':
 136                        nfproto = NFPROTO_IPV6;
 137                        break;
 138
 139                default:
 140                        if (!match) {
 141                                fprintf(stderr, "failed to find match %s\n\n",
 142                                        optarg);
 143                                return -1;
 144
 145                        }
 146                        xtables_option_mpcall(c, argv, 0, match, NULL);
 147                        break;
 148                }
 149        }
 150
 151        if (!match) {
 152                fprintf(stderr, " failed to parse parameters (%s)\n", *argv);
 153                return -1;
 154        }
 155
 156        /* check that we passed the correct parameters to the match */
 157        xtables_option_mfcall(match);
 158
 159        addraw_l(n, MAX_MSG, hdr, sizeof(*hdr));
 160        addattr32(n, MAX_MSG, TCA_EM_IPT_HOOK, em_ipt_hook(n));
 161        addattrstrz(n, MAX_MSG, TCA_EM_IPT_MATCH_NAME, match->name);
 162        addattr8(n, MAX_MSG, TCA_EM_IPT_MATCH_REVISION, match->revision);
 163        addattr8(n, MAX_MSG, TCA_EM_IPT_NFPROTO, nfproto);
 164        addattr_l(n, MAX_MSG, TCA_EM_IPT_MATCH_DATA, match->m->data,
 165                  match->size);
 166
 167        xtables_free_opts(1);
 168
 169        scrub_match(match);
 170        return 0;
 171}
 172
 173static int em_ipt_print_epot(FILE *fd, struct tcf_ematch_hdr *hdr, void *data,
 174                             int data_len)
 175{
 176        struct rtattr *tb[TCA_EM_IPT_MAX + 1];
 177        struct xtables_match *match;
 178        const char *mname;
 179        __u8 nfproto;
 180
 181        if (parse_rtattr(tb, TCA_EM_IPT_MAX, data, data_len) < 0)
 182                return -1;
 183
 184        nfproto = rta_getattr_u8(tb[TCA_EM_IPT_NFPROTO]);
 185
 186        xtables_init_all(&em_tc_ipt_globals, nfproto);
 187
 188        mname = rta_getattr_str(tb[TCA_EM_IPT_MATCH_NAME]);
 189        match = xtables_find_match(mname, XTF_TRY_LOAD, NULL);
 190        if (!match)
 191                return -1;
 192
 193        match->m = fake_xt_entry_match(RTA_PAYLOAD(tb[TCA_EM_IPT_MATCH_DATA]),
 194                                       RTA_DATA(tb[TCA_EM_IPT_MATCH_DATA]));
 195        if (!match->m)
 196                return -1;
 197
 198        match->print(NULL, match->m, 0);
 199
 200        scrub_match(match);
 201        return 0;
 202}
 203
 204struct ematch_util ipt_ematch_util = {
 205        .kind = "ipt",
 206        .kind_num = TCF_EM_IPT,
 207        .parse_eopt_argv = em_ipt_parse_eopt_argv,
 208        .print_eopt = em_ipt_print_epot,
 209        .print_usage = em_ipt_print_usage
 210};
 211