1311b41454dc445639924c691a949bd15fbfab0cbshemminger/*
2311b41454dc445639924c691a949bd15fbfab0cbshemminger * em_nbyte.c		N-Byte Ematch
3311b41454dc445639924c691a949bd15fbfab0cbshemminger *
4311b41454dc445639924c691a949bd15fbfab0cbshemminger *		This program is free software; you can distribute it and/or
5311b41454dc445639924c691a949bd15fbfab0cbshemminger *		modify it under the terms of the GNU General Public License
6311b41454dc445639924c691a949bd15fbfab0cbshemminger *		as published by the Free Software Foundation; either version
7311b41454dc445639924c691a949bd15fbfab0cbshemminger *		2 of the License, or (at your option) any later version.
8311b41454dc445639924c691a949bd15fbfab0cbshemminger *
9311b41454dc445639924c691a949bd15fbfab0cbshemminger * Authors:	Thomas Graf <tgraf@suug.ch>
10311b41454dc445639924c691a949bd15fbfab0cbshemminger */
11311b41454dc445639924c691a949bd15fbfab0cbshemminger
12311b41454dc445639924c691a949bd15fbfab0cbshemminger#include <stdio.h>
13311b41454dc445639924c691a949bd15fbfab0cbshemminger#include <stdlib.h>
14311b41454dc445639924c691a949bd15fbfab0cbshemminger#include <unistd.h>
15311b41454dc445639924c691a949bd15fbfab0cbshemminger#include <syslog.h>
16311b41454dc445639924c691a949bd15fbfab0cbshemminger#include <fcntl.h>
17311b41454dc445639924c691a949bd15fbfab0cbshemminger#include <sys/socket.h>
18311b41454dc445639924c691a949bd15fbfab0cbshemminger#include <netinet/in.h>
19311b41454dc445639924c691a949bd15fbfab0cbshemminger#include <arpa/inet.h>
20311b41454dc445639924c691a949bd15fbfab0cbshemminger#include <string.h>
21311b41454dc445639924c691a949bd15fbfab0cbshemminger#include <errno.h>
22311b41454dc445639924c691a949bd15fbfab0cbshemminger
23311b41454dc445639924c691a949bd15fbfab0cbshemminger#include "m_ematch.h"
24311b41454dc445639924c691a949bd15fbfab0cbshemminger#include <linux/tc_ematch/tc_em_nbyte.h>
25311b41454dc445639924c691a949bd15fbfab0cbshemminger
26311b41454dc445639924c691a949bd15fbfab0cbshemmingerextern struct ematch_util nbyte_ematch_util;
27311b41454dc445639924c691a949bd15fbfab0cbshemminger
28311b41454dc445639924c691a949bd15fbfab0cbshemmingerstatic void nbyte_print_usage(FILE *fd)
29311b41454dc445639924c691a949bd15fbfab0cbshemminger{
30311b41454dc445639924c691a949bd15fbfab0cbshemminger	fprintf(fd,
31311b41454dc445639924c691a949bd15fbfab0cbshemminger	    "Usage: nbyte(NEEDLE at OFFSET [layer LAYER])\n" \
32311b41454dc445639924c691a949bd15fbfab0cbshemminger	    "where: NEEDLE := { string | \"c-escape-sequence\" }\n" \
33311b41454dc445639924c691a949bd15fbfab0cbshemminger	    "       OFFSET := int\n" \
34bc45ded42ca835a735dcd934e69c17f90442d790Lionel Elie Mamane	    "       LAYER  := { link | network | transport | 0..%d }\n" \
35311b41454dc445639924c691a949bd15fbfab0cbshemminger	    "\n" \
36311b41454dc445639924c691a949bd15fbfab0cbshemminger	    "Example: nbyte(\"ababa\" at 12 layer 1)\n",
37311b41454dc445639924c691a949bd15fbfab0cbshemminger	    TCF_LAYER_MAX);
38311b41454dc445639924c691a949bd15fbfab0cbshemminger}
39311b41454dc445639924c691a949bd15fbfab0cbshemminger
40311b41454dc445639924c691a949bd15fbfab0cbshemmingerstatic int nbyte_parse_eopt(struct nlmsghdr *n, struct tcf_ematch_hdr *hdr,
41311b41454dc445639924c691a949bd15fbfab0cbshemminger			    struct bstr *args)
42311b41454dc445639924c691a949bd15fbfab0cbshemminger{
43311b41454dc445639924c691a949bd15fbfab0cbshemminger	struct bstr *a;
44311b41454dc445639924c691a949bd15fbfab0cbshemminger	struct bstr *needle = args;
45311b41454dc445639924c691a949bd15fbfab0cbshemminger	unsigned long offset = 0, layer = TCF_LAYER_NETWORK;
46311b41454dc445639924c691a949bd15fbfab0cbshemminger	int offset_present = 0;
47311b41454dc445639924c691a949bd15fbfab0cbshemminger	struct tcf_em_nbyte nb;
48311b41454dc445639924c691a949bd15fbfab0cbshemminger
49311b41454dc445639924c691a949bd15fbfab0cbshemminger	memset(&nb, 0, sizeof(nb));
50311b41454dc445639924c691a949bd15fbfab0cbshemminger
51311b41454dc445639924c691a949bd15fbfab0cbshemminger#define PARSE_ERR(CARG, FMT, ARGS...) \
52311b41454dc445639924c691a949bd15fbfab0cbshemminger	em_parse_error(EINVAL, args, CARG, &nbyte_ematch_util, FMT ,##ARGS)
53311b41454dc445639924c691a949bd15fbfab0cbshemminger
54311b41454dc445639924c691a949bd15fbfab0cbshemminger	if (args == NULL)
55311b41454dc445639924c691a949bd15fbfab0cbshemminger		return PARSE_ERR(args, "nbyte: missing arguments");
56311b41454dc445639924c691a949bd15fbfab0cbshemminger
57311b41454dc445639924c691a949bd15fbfab0cbshemminger	if (needle->len <= 0)
58311b41454dc445639924c691a949bd15fbfab0cbshemminger		return PARSE_ERR(args, "nbyte: needle length is 0");
59311b41454dc445639924c691a949bd15fbfab0cbshemminger
60311b41454dc445639924c691a949bd15fbfab0cbshemminger	for (a = bstr_next(args); a; a = bstr_next(a)) {
61311b41454dc445639924c691a949bd15fbfab0cbshemminger		if (!bstrcmp(a, "at")) {
62311b41454dc445639924c691a949bd15fbfab0cbshemminger			if (a->next == NULL)
63311b41454dc445639924c691a949bd15fbfab0cbshemminger				return PARSE_ERR(a, "nbyte: missing argument");
64311b41454dc445639924c691a949bd15fbfab0cbshemminger			a = bstr_next(a);
65311b41454dc445639924c691a949bd15fbfab0cbshemminger
66311b41454dc445639924c691a949bd15fbfab0cbshemminger			offset = bstrtoul(a);
67311b41454dc445639924c691a949bd15fbfab0cbshemminger			if (offset == ULONG_MAX)
68311b41454dc445639924c691a949bd15fbfab0cbshemminger				return PARSE_ERR(a, "nbyte: invalid offset, " \
69311b41454dc445639924c691a949bd15fbfab0cbshemminger				    "must be numeric");
70311b41454dc445639924c691a949bd15fbfab0cbshemminger
71311b41454dc445639924c691a949bd15fbfab0cbshemminger			offset_present = 1;
72311b41454dc445639924c691a949bd15fbfab0cbshemminger		} else if (!bstrcmp(a, "layer")) {
73311b41454dc445639924c691a949bd15fbfab0cbshemminger			if (a->next == NULL)
74311b41454dc445639924c691a949bd15fbfab0cbshemminger				return PARSE_ERR(a, "nbyte: missing argument");
75311b41454dc445639924c691a949bd15fbfab0cbshemminger			a = bstr_next(a);
76311b41454dc445639924c691a949bd15fbfab0cbshemminger
77311b41454dc445639924c691a949bd15fbfab0cbshemminger			layer = parse_layer(a);
78311b41454dc445639924c691a949bd15fbfab0cbshemminger			if (layer == INT_MAX) {
79311b41454dc445639924c691a949bd15fbfab0cbshemminger				layer = bstrtoul(a);
80311b41454dc445639924c691a949bd15fbfab0cbshemminger				if (layer == ULONG_MAX)
81311b41454dc445639924c691a949bd15fbfab0cbshemminger					return PARSE_ERR(a, "nbyte: invalid " \
82311b41454dc445639924c691a949bd15fbfab0cbshemminger					    "layer");
83311b41454dc445639924c691a949bd15fbfab0cbshemminger			}
84311b41454dc445639924c691a949bd15fbfab0cbshemminger
85311b41454dc445639924c691a949bd15fbfab0cbshemminger			if (layer > TCF_LAYER_MAX)
86311b41454dc445639924c691a949bd15fbfab0cbshemminger				return PARSE_ERR(a, "nbyte: illegal layer, " \
87311b41454dc445639924c691a949bd15fbfab0cbshemminger				    "must be in 0..%d", TCF_LAYER_MAX);
88311b41454dc445639924c691a949bd15fbfab0cbshemminger		} else
89311b41454dc445639924c691a949bd15fbfab0cbshemminger			return PARSE_ERR(a, "nbyte: unknown parameter");
90311b41454dc445639924c691a949bd15fbfab0cbshemminger	}
91311b41454dc445639924c691a949bd15fbfab0cbshemminger
92311b41454dc445639924c691a949bd15fbfab0cbshemminger	if (offset_present == 0)
93311b41454dc445639924c691a949bd15fbfab0cbshemminger		return PARSE_ERR(a, "nbyte: offset required");
94ae665a522bd46bea44c5ea84c89c8b1731954170Stephen Hemminger
95311b41454dc445639924c691a949bd15fbfab0cbshemminger	nb.len = needle->len;
96311b41454dc445639924c691a949bd15fbfab0cbshemminger	nb.layer = (__u8) layer;
97311b41454dc445639924c691a949bd15fbfab0cbshemminger	nb.off = (__u16) offset;
98311b41454dc445639924c691a949bd15fbfab0cbshemminger
99311b41454dc445639924c691a949bd15fbfab0cbshemminger	addraw_l(n, MAX_MSG, hdr, sizeof(*hdr));
100311b41454dc445639924c691a949bd15fbfab0cbshemminger	addraw_l(n, MAX_MSG, &nb, sizeof(nb));
101311b41454dc445639924c691a949bd15fbfab0cbshemminger	addraw_l(n, MAX_MSG, needle->data, needle->len);
102311b41454dc445639924c691a949bd15fbfab0cbshemminger
103311b41454dc445639924c691a949bd15fbfab0cbshemminger#undef PARSE_ERR
104311b41454dc445639924c691a949bd15fbfab0cbshemminger	return 0;
105311b41454dc445639924c691a949bd15fbfab0cbshemminger}
106311b41454dc445639924c691a949bd15fbfab0cbshemminger
107311b41454dc445639924c691a949bd15fbfab0cbshemmingerstatic int nbyte_print_eopt(FILE *fd, struct tcf_ematch_hdr *hdr, void *data,
108311b41454dc445639924c691a949bd15fbfab0cbshemminger			    int data_len)
109311b41454dc445639924c691a949bd15fbfab0cbshemminger{
110311b41454dc445639924c691a949bd15fbfab0cbshemminger	int i;
111311b41454dc445639924c691a949bd15fbfab0cbshemminger	struct tcf_em_nbyte *nb = data;
112311b41454dc445639924c691a949bd15fbfab0cbshemminger	__u8 *needle;
113311b41454dc445639924c691a949bd15fbfab0cbshemminger
114311b41454dc445639924c691a949bd15fbfab0cbshemminger	if (data_len < sizeof(*nb)) {
115311b41454dc445639924c691a949bd15fbfab0cbshemminger		fprintf(stderr, "NByte header size mismatch\n");
116311b41454dc445639924c691a949bd15fbfab0cbshemminger		return -1;
117311b41454dc445639924c691a949bd15fbfab0cbshemminger	}
118311b41454dc445639924c691a949bd15fbfab0cbshemminger
119311b41454dc445639924c691a949bd15fbfab0cbshemminger	if (data_len < sizeof(*nb) + nb->len) {
120311b41454dc445639924c691a949bd15fbfab0cbshemminger		fprintf(stderr, "NByte payload size mismatch\n");
121311b41454dc445639924c691a949bd15fbfab0cbshemminger		return -1;
122311b41454dc445639924c691a949bd15fbfab0cbshemminger	}
123311b41454dc445639924c691a949bd15fbfab0cbshemminger
124311b41454dc445639924c691a949bd15fbfab0cbshemminger	needle = data + sizeof(*nb);
125311b41454dc445639924c691a949bd15fbfab0cbshemminger
126311b41454dc445639924c691a949bd15fbfab0cbshemminger	for (i = 0; i < nb->len; i++)
127311b41454dc445639924c691a949bd15fbfab0cbshemminger		fprintf(fd, "%02x ", needle[i]);
128311b41454dc445639924c691a949bd15fbfab0cbshemminger
129311b41454dc445639924c691a949bd15fbfab0cbshemminger	fprintf(fd, "\"");
130311b41454dc445639924c691a949bd15fbfab0cbshemminger	for (i = 0; i < nb->len; i++)
131311b41454dc445639924c691a949bd15fbfab0cbshemminger		fprintf(fd, "%c", isprint(needle[i]) ? needle[i] : '.');
132311b41454dc445639924c691a949bd15fbfab0cbshemminger	fprintf(fd, "\" at %d layer %d", nb->off, nb->layer);
133ae665a522bd46bea44c5ea84c89c8b1731954170Stephen Hemminger
134311b41454dc445639924c691a949bd15fbfab0cbshemminger	return 0;
135311b41454dc445639924c691a949bd15fbfab0cbshemminger}
136311b41454dc445639924c691a949bd15fbfab0cbshemminger
137311b41454dc445639924c691a949bd15fbfab0cbshemmingerstruct ematch_util nbyte_ematch_util = {
138311b41454dc445639924c691a949bd15fbfab0cbshemminger	.kind = "nbyte",
139311b41454dc445639924c691a949bd15fbfab0cbshemminger	.kind_num = TCF_EM_NBYTE,
140311b41454dc445639924c691a949bd15fbfab0cbshemminger	.parse_eopt = nbyte_parse_eopt,
141311b41454dc445639924c691a949bd15fbfab0cbshemminger	.print_eopt = nbyte_print_eopt,
142311b41454dc445639924c691a949bd15fbfab0cbshemminger	.print_usage = nbyte_print_usage
143311b41454dc445639924c691a949bd15fbfab0cbshemminger};
144