iproute2/tc/m_xt_old.c
<<
>>
Prefs
   1/*
   2 * m_xt.c       xtables based targets
   3 *              utilities mostly ripped from iptables <duh, its the linux way>
   4 *
   5 *              This program is free software; you can distribute it and/or
   6 *              modify it under the terms of the GNU General Public License
   7 *              as published by the Free Software Foundation; either version
   8 *              2 of the License, or (at your option) any later version.
   9 *
  10 * Authors:  J Hadi Salim (hadi@cyberus.ca)
  11 */
  12
  13/*XXX: in the future (xtables 1.4.3?) get rid of everything tagged
  14 * as TC_CONFIG_XT_H */
  15
  16#include <sys/socket.h>
  17#include <netinet/in.h>
  18#include <arpa/inet.h>
  19#include <net/if.h>
  20#include <linux/netfilter.h>
  21#include <linux/netfilter_ipv4/ip_tables.h>
  22#include <xtables.h>
  23#include "utils.h"
  24#include "tc_util.h"
  25#include <linux/tc_act/tc_ipt.h>
  26#include <stdio.h>
  27#include <getopt.h>
  28#include <errno.h>
  29#include <string.h>
  30#include <netdb.h>
  31#include <stdlib.h>
  32#include <ctype.h>
  33#include <stdarg.h>
  34#include <limits.h>
  35#include <unistd.h>
  36#include <fcntl.h>
  37#include <sys/wait.h>
  38#ifdef TC_CONFIG_XT_H
  39#include "xt-internal.h"
  40#endif
  41
  42#ifndef ALIGN
  43#define ALIGN(x, a)             __ALIGN_MASK(x, (typeof(x))(a)-1)
  44#define __ALIGN_MASK(x, mask)   (((x)+(mask))&~(mask))
  45#endif
  46
  47static const char *pname = "tc-ipt";
  48static const char *tname = "mangle";
  49static const char *pversion = "0.2";
  50
  51static const char *ipthooks[] = {
  52        "NF_IP_PRE_ROUTING",
  53        "NF_IP_LOCAL_IN",
  54        "NF_IP_FORWARD",
  55        "NF_IP_LOCAL_OUT",
  56        "NF_IP_POST_ROUTING",
  57};
  58
  59static struct option original_opts[] = {
  60        {"jump", 1, 0, 'j'},
  61        {0, 0, 0, 0}
  62};
  63
  64static struct option *opts = original_opts;
  65static unsigned int global_option_offset;
  66char *lib_dir;
  67const char *program_version = XTABLES_VERSION;
  68const char *program_name = "tc-ipt";
  69struct afinfo afinfo = {
  70        .family         = AF_INET,
  71        .libprefix      = "libxt_",
  72        .ipproto        = IPPROTO_IP,
  73        .kmod           = "ip_tables",
  74        .so_rev_target  = IPT_SO_GET_REVISION_TARGET,
  75};
  76
  77
  78#define OPTION_OFFSET 256
  79
  80/*XXX: TC_CONFIG_XT_H */
  81static void free_opts(struct option *local_opts)
  82{
  83        if (local_opts != original_opts) {
  84                free(local_opts);
  85                opts = original_opts;
  86                global_option_offset = 0;
  87        }
  88}
  89
  90/*XXX: TC_CONFIG_XT_H */
  91static struct option *
  92merge_options(struct option *oldopts, const struct option *newopts,
  93              unsigned int *option_offset)
  94{
  95        struct option *merge;
  96        unsigned int num_old, num_new, i;
  97
  98        for (num_old = 0; oldopts[num_old].name; num_old++);
  99        for (num_new = 0; newopts[num_new].name; num_new++);
 100
 101        *option_offset = global_option_offset + OPTION_OFFSET;
 102
 103        merge = malloc(sizeof(struct option) * (num_new + num_old + 1));
 104        memcpy(merge, oldopts, num_old * sizeof(struct option));
 105        for (i = 0; i < num_new; i++) {
 106                merge[num_old + i] = newopts[i];
 107                merge[num_old + i].val += *option_offset;
 108        }
 109        memset(merge + num_old + num_new, 0, sizeof(struct option));
 110
 111        return merge;
 112}
 113
 114
 115/*XXX: TC_CONFIG_XT_H */
 116#ifndef TRUE
 117#define TRUE 1
 118#endif
 119#ifndef FALSE
 120#define FALSE 0
 121#endif
 122
 123/*XXX: TC_CONFIG_XT_H */
 124int
 125check_inverse(const char option[], int *invert, int *my_optind, int argc)
 126{
 127        if (option && strcmp(option, "!") == 0) {
 128                if (*invert)
 129                        exit_error(PARAMETER_PROBLEM,
 130                                   "Multiple `!' flags not allowed");
 131                *invert = TRUE;
 132                if (my_optind != NULL) {
 133                        ++*my_optind;
 134                        if (argc && *my_optind > argc)
 135                                exit_error(PARAMETER_PROBLEM,
 136                                           "no argument following `!'");
 137                }
 138
 139                return TRUE;
 140        }
 141        return FALSE;
 142}
 143
 144/*XXX: TC_CONFIG_XT_H */
 145void exit_error(enum exittype status, const char *msg, ...)
 146{
 147        va_list args;
 148
 149        va_start(args, msg);
 150        fprintf(stderr, "%s v%s: ", pname, pversion);
 151        vfprintf(stderr, msg, args);
 152        va_end(args);
 153        fprintf(stderr, "\n");
 154        /* On error paths, make sure that we don't leak memory */
 155        exit(status);
 156}
 157
 158/*XXX: TC_CONFIG_XT_H */
 159static void set_revision(char *name, u_int8_t revision)
 160{
 161        /* Old kernel sources don't have ".revision" field,
 162        *  but we stole a byte from name. */
 163        name[IPT_FUNCTION_MAXNAMELEN - 2] = '\0';
 164        name[IPT_FUNCTION_MAXNAMELEN - 1] = revision;
 165}
 166
 167/*
 168 * we may need to check for version mismatch
 169*/
 170int
 171build_st(struct xtables_target *target, struct xt_entry_target *t)
 172{
 173
 174        size_t size =
 175                    XT_ALIGN(sizeof(struct xt_entry_target)) + target->size;
 176
 177        if (t == NULL) {
 178                target->t = fw_calloc(1, size);
 179                target->t->u.target_size = size;
 180                strcpy(target->t->u.user.name, target->name);
 181                set_revision(target->t->u.user.name, target->revision);
 182
 183                if (target->init != NULL)
 184                        target->init(target->t);
 185        } else {
 186                target->t = t;
 187        }
 188        return 0;
 189
 190}
 191
 192inline void set_lib_dir(void)
 193{
 194
 195        lib_dir = getenv("XTABLES_LIBDIR");
 196        if (!lib_dir) {
 197                lib_dir = getenv("IPTABLES_LIB_DIR");
 198                if (lib_dir)
 199                        fprintf(stderr, "using deprecated IPTABLES_LIB_DIR\n");
 200        }
 201        if (lib_dir == NULL)
 202                lib_dir = XT_LIB_DIR;
 203
 204}
 205
 206static int parse_ipt(struct action_util *a, int *argc_p,
 207                     char ***argv_p, int tca_id, struct nlmsghdr *n)
 208{
 209        struct xtables_target *m = NULL;
 210        struct ipt_entry fw;
 211        struct rtattr *tail;
 212        int c;
 213        int rargc = *argc_p;
 214        char **argv = *argv_p;
 215        int argc = 0, iargc = 0;
 216        char k[FILTER_NAMESZ];
 217        int size = 0;
 218        int iok = 0, ok = 0;
 219        __u32 hook = 0, index = 0;
 220
 221        set_lib_dir();
 222
 223        {
 224                int i;
 225
 226                for (i = 0; i < rargc; i++) {
 227                        if (!argv[i] || strcmp(argv[i], "action") == 0)
 228                                break;
 229                }
 230                iargc = argc = i;
 231        }
 232
 233        if (argc <= 2) {
 234                fprintf(stderr, "bad arguments to ipt %d vs %d\n", argc, rargc);
 235                return -1;
 236        }
 237
 238        while (1) {
 239                c = getopt_long(argc, argv, "j:", opts, NULL);
 240                if (c == -1)
 241                        break;
 242                switch (c) {
 243                case 'j':
 244                        m = find_target(optarg, TRY_LOAD);
 245                        if (m != NULL) {
 246
 247                                if (build_st(m, NULL) < 0) {
 248                                        printf(" %s error\n", m->name);
 249                                        return -1;
 250                                }
 251                                opts =
 252                                    merge_options(opts, m->extra_opts,
 253                                                  &m->option_offset);
 254                        } else {
 255                                fprintf(stderr, " failed to find target %s\n\n", optarg);
 256                                return -1;
 257                        }
 258                        ok++;
 259                        break;
 260
 261                default:
 262                        memset(&fw, 0, sizeof(fw));
 263                        if (m) {
 264                                m->parse(c - m->option_offset, argv, 0,
 265                                         &m->tflags, NULL, &m->t);
 266                        } else {
 267                                fprintf(stderr, " failed to find target %s\n\n", optarg);
 268                                return -1;
 269
 270                        }
 271                        ok++;
 272                        break;
 273
 274                }
 275        }
 276
 277        if (iargc > optind) {
 278                if (matches(argv[optind], "index") == 0) {
 279                        if (get_u32(&index, argv[optind + 1], 10)) {
 280                                fprintf(stderr, "Illegal \"index\"\n");
 281                                free_opts(opts);
 282                                return -1;
 283                        }
 284                        iok++;
 285
 286                        optind += 2;
 287                }
 288        }
 289
 290        if (!ok && !iok) {
 291                fprintf(stderr, " ipt Parser BAD!! (%s)\n", *argv);
 292                return -1;
 293        }
 294
 295        /* check that we passed the correct parameters to the target */
 296        if (m)
 297                m->final_check(m->tflags);
 298
 299        {
 300                struct tcmsg *t = NLMSG_DATA(n);
 301
 302                if (t->tcm_parent != TC_H_ROOT
 303                    && t->tcm_parent == TC_H_MAJ(TC_H_INGRESS)) {
 304                        hook = NF_IP_PRE_ROUTING;
 305                } else {
 306                        hook = NF_IP_POST_ROUTING;
 307                }
 308        }
 309
 310        tail = addattr_nest(n, MAX_MSG, tca_id);
 311        fprintf(stdout, "tablename: %s hook: %s\n ", tname, ipthooks[hook]);
 312        fprintf(stdout, "\ttarget: ");
 313
 314        if (m)
 315                m->print(NULL, m->t, 0);
 316        fprintf(stdout, " index %d\n", index);
 317
 318        if (strlen(tname) > 16) {
 319                size = 16;
 320                k[15] = 0;
 321        } else {
 322                size = 1 + strlen(tname);
 323        }
 324        strncpy(k, tname, size);
 325
 326        addattr_l(n, MAX_MSG, TCA_IPT_TABLE, k, size);
 327        addattr_l(n, MAX_MSG, TCA_IPT_HOOK, &hook, 4);
 328        addattr_l(n, MAX_MSG, TCA_IPT_INDEX, &index, 4);
 329        if (m)
 330                addattr_l(n, MAX_MSG, TCA_IPT_TARG, m->t, m->t->u.target_size);
 331        addattr_nest_end(n, tail);
 332
 333        argc -= optind;
 334        argv += optind;
 335        *argc_p = rargc - iargc;
 336        *argv_p = argv;
 337
 338        optind = 0;
 339        free_opts(opts);
 340        /* Clear flags if target will be used again */
 341        m->tflags = 0;
 342        m->used = 0;
 343        /* Free allocated memory */
 344        if (m->t)
 345            free(m->t);
 346
 347
 348        return 0;
 349
 350}
 351
 352static int
 353print_ipt(struct action_util *au, FILE * f, struct rtattr *arg)
 354{
 355        struct rtattr *tb[TCA_IPT_MAX + 1];
 356        struct xt_entry_target *t = NULL;
 357        struct xtables_target *m;
 358        __u32 hook;
 359
 360        if (arg == NULL)
 361                return 0;
 362
 363        set_lib_dir();
 364
 365        parse_rtattr_nested(tb, TCA_IPT_MAX, arg);
 366
 367        if (tb[TCA_IPT_TABLE] == NULL) {
 368                fprintf(stderr, "Missing ipt table name, assuming mangle\n");
 369        } else {
 370                fprintf(f, "tablename: %s ",
 371                        rta_getattr_str(tb[TCA_IPT_TABLE]));
 372        }
 373
 374        if (tb[TCA_IPT_HOOK] == NULL) {
 375                fprintf(stderr, "Missing ipt hook name\n");
 376                return -1;
 377        }
 378
 379        if (tb[TCA_IPT_TARG] == NULL) {
 380                fprintf(stderr, "Missing ipt target parameters\n");
 381                return -1;
 382        }
 383
 384        hook = rta_getattr_u32(tb[TCA_IPT_HOOK]);
 385        fprintf(f, " hook: %s\n", ipthooks[hook]);
 386
 387        t = RTA_DATA(tb[TCA_IPT_TARG]);
 388        m = find_target(t->u.user.name, TRY_LOAD);
 389        if (m != NULL) {
 390                if (build_st(m, t) < 0) {
 391                        fprintf(stderr, " %s error\n", m->name);
 392                        return -1;
 393                }
 394
 395                opts =
 396                        merge_options(opts, m->extra_opts,
 397                                      &m->option_offset);
 398        } else {
 399                fprintf(stderr, " failed to find target %s\n\n",
 400                        t->u.user.name);
 401                return -1;
 402        }
 403        fprintf(f, "\ttarget ");
 404        m->print(NULL, m->t, 0);
 405        if (tb[TCA_IPT_INDEX] == NULL) {
 406                fprintf(f, " [NULL ipt target index ]\n");
 407        } else {
 408                __u32 index;
 409
 410                index = rta_getattr_u32(tb[TCA_IPT_INDEX]);
 411                fprintf(f, "\n\tindex %u", index);
 412        }
 413
 414        if (tb[TCA_IPT_CNT]) {
 415                struct tc_cnt *c  = RTA_DATA(tb[TCA_IPT_CNT]);
 416
 417                fprintf(f, " ref %d bind %d", c->refcnt, c->bindcnt);
 418        }
 419        if (show_stats) {
 420                if (tb[TCA_IPT_TM]) {
 421                        struct tcf_t *tm = RTA_DATA(tb[TCA_IPT_TM]);
 422
 423                        print_tm(f, tm);
 424                }
 425        }
 426        fprintf(f, "\n");
 427
 428        free_opts(opts);
 429
 430        return 0;
 431}
 432
 433struct action_util ipt_action_util = {
 434        .id = "ipt",
 435        .parse_aopt = parse_ipt,
 436        .print_aopt = print_ipt,
 437};
 438