iproute2/tc/em_nbyte.c
<<
>>
Prefs
   1/*
   2 * em_nbyte.c           N-Byte Ematch
   3 *
   4 *              This program is free software; you can distribute it and/or
   5 *              modify it under the terms of the GNU General Public License
   6 *              as published by the Free Software Foundation; either version
   7 *              2 of the License, or (at your option) any later version.
   8 *
   9 * Authors:     Thomas Graf <tgraf@suug.ch>
  10 */
  11
  12#include <stdio.h>
  13#include <stdlib.h>
  14#include <unistd.h>
  15#include <fcntl.h>
  16#include <sys/socket.h>
  17#include <netinet/in.h>
  18#include <arpa/inet.h>
  19#include <string.h>
  20#include <errno.h>
  21
  22#include "m_ematch.h"
  23#include <linux/tc_ematch/tc_em_nbyte.h>
  24
  25extern struct ematch_util nbyte_ematch_util;
  26
  27static void nbyte_print_usage(FILE *fd)
  28{
  29        fprintf(fd,
  30            "Usage: nbyte(NEEDLE at OFFSET [layer LAYER])\n" \
  31            "where: NEEDLE := { string | \"c-escape-sequence\" }\n" \
  32            "       OFFSET := int\n" \
  33            "       LAYER  := { link | network | transport | 0..%d }\n" \
  34            "\n" \
  35            "Example: nbyte(\"ababa\" at 12 layer 1)\n",
  36            TCF_LAYER_MAX);
  37}
  38
  39static int nbyte_parse_eopt(struct nlmsghdr *n, struct tcf_ematch_hdr *hdr,
  40                            struct bstr *args)
  41{
  42        struct bstr *a;
  43        struct bstr *needle = args;
  44        unsigned long offset = 0, layer = TCF_LAYER_NETWORK;
  45        int offset_present = 0;
  46        struct tcf_em_nbyte nb = {};
  47
  48#define PARSE_ERR(CARG, FMT, ARGS...) \
  49        em_parse_error(EINVAL, args, CARG, &nbyte_ematch_util, FMT, ##ARGS)
  50
  51        if (args == NULL)
  52                return PARSE_ERR(args, "nbyte: missing arguments");
  53
  54        if (needle->len <= 0)
  55                return PARSE_ERR(args, "nbyte: needle length is 0");
  56
  57        for (a = bstr_next(args); a; a = bstr_next(a)) {
  58                if (!bstrcmp(a, "at")) {
  59                        if (a->next == NULL)
  60                                return PARSE_ERR(a, "nbyte: missing argument");
  61                        a = bstr_next(a);
  62
  63                        offset = bstrtoul(a);
  64                        if (offset == ULONG_MAX)
  65                                return PARSE_ERR(a, "nbyte: invalid offset, " \
  66                                    "must be numeric");
  67
  68                        offset_present = 1;
  69                } else if (!bstrcmp(a, "layer")) {
  70                        if (a->next == NULL)
  71                                return PARSE_ERR(a, "nbyte: missing argument");
  72                        a = bstr_next(a);
  73
  74                        layer = parse_layer(a);
  75                        if (layer == INT_MAX) {
  76                                layer = bstrtoul(a);
  77                                if (layer == ULONG_MAX)
  78                                        return PARSE_ERR(a, "nbyte: invalid " \
  79                                            "layer");
  80                        }
  81
  82                        if (layer > TCF_LAYER_MAX)
  83                                return PARSE_ERR(a, "nbyte: illegal layer, " \
  84                                    "must be in 0..%d", TCF_LAYER_MAX);
  85                } else
  86                        return PARSE_ERR(a, "nbyte: unknown parameter");
  87        }
  88
  89        if (offset_present == 0)
  90                return PARSE_ERR(a, "nbyte: offset required");
  91
  92        nb.len = needle->len;
  93        nb.layer = (__u8) layer;
  94        nb.off = (__u16) offset;
  95
  96        addraw_l(n, MAX_MSG, hdr, sizeof(*hdr));
  97        addraw_l(n, MAX_MSG, &nb, sizeof(nb));
  98        addraw_l(n, MAX_MSG, needle->data, needle->len);
  99
 100#undef PARSE_ERR
 101        return 0;
 102}
 103
 104static int nbyte_print_eopt(FILE *fd, struct tcf_ematch_hdr *hdr, void *data,
 105                            int data_len)
 106{
 107        int i;
 108        struct tcf_em_nbyte *nb = data;
 109        __u8 *needle;
 110
 111        if (data_len < sizeof(*nb)) {
 112                fprintf(stderr, "NByte header size mismatch\n");
 113                return -1;
 114        }
 115
 116        if (data_len < sizeof(*nb) + nb->len) {
 117                fprintf(stderr, "NByte payload size mismatch\n");
 118                return -1;
 119        }
 120
 121        needle = data + sizeof(*nb);
 122
 123        for (i = 0; i < nb->len; i++)
 124                fprintf(fd, "%02x ", needle[i]);
 125
 126        fprintf(fd, "\"");
 127        for (i = 0; i < nb->len; i++)
 128                fprintf(fd, "%c", isprint(needle[i]) ? needle[i] : '.');
 129        fprintf(fd, "\" at %d layer %d", nb->off, nb->layer);
 130
 131        return 0;
 132}
 133
 134struct ematch_util nbyte_ematch_util = {
 135        .kind = "nbyte",
 136        .kind_num = TCF_EM_NBYTE,
 137        .parse_eopt = nbyte_parse_eopt,
 138        .print_eopt = nbyte_print_eopt,
 139        .print_usage = nbyte_print_usage
 140};
 141