• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * em_u32.c		U32 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 <syslog.h>
16 #include <fcntl.h>
17 #include <sys/socket.h>
18 #include <netinet/in.h>
19 #include <arpa/inet.h>
20 #include <string.h>
21 #include <errno.h>
22 
23 #include "m_ematch.h"
24 
25 extern struct ematch_util u32_ematch_util;
26 
u32_print_usage(FILE * fd)27 static void u32_print_usage(FILE *fd)
28 {
29 	fprintf(fd,
30 	    "Usage: u32(ALIGN VALUE MASK at [ nexthdr+ ] OFFSET)\n" \
31 	    "where: ALIGN  := { u8 | u16 | u32 }\n" \
32 	    "\n" \
33 	    "Example: u32(u16 0x1122 0xffff at nexthdr+4)\n");
34 }
35 
u32_parse_eopt(struct nlmsghdr * n,struct tcf_ematch_hdr * hdr,struct bstr * args)36 static int u32_parse_eopt(struct nlmsghdr *n, struct tcf_ematch_hdr *hdr,
37 			  struct bstr *args)
38 {
39 	struct bstr *a;
40 	int align, nh_len;
41 	unsigned long key, mask, offmask = 0, offset;
42 	struct tc_u32_key u_key = {};
43 
44 #define PARSE_ERR(CARG, FMT, ARGS...) \
45 	em_parse_error(EINVAL, args, CARG, &u32_ematch_util, FMT, ##ARGS)
46 
47 	if (args == NULL)
48 		return PARSE_ERR(args, "u32: missing arguments");
49 
50 	if (!bstrcmp(args, "u8"))
51 		align = 1;
52 	else if (!bstrcmp(args, "u16"))
53 		align = 2;
54 	else if (!bstrcmp(args, "u32"))
55 		align = 4;
56 	else
57 		return PARSE_ERR(args, "u32: invalid alignment");
58 
59 	a = bstr_next(args);
60 	if (a == NULL)
61 		return PARSE_ERR(a, "u32: missing key");
62 
63 	key = bstrtoul(a);
64 	if (key == ULONG_MAX)
65 		return PARSE_ERR(a, "u32: invalid key, must be numeric");
66 
67 	a = bstr_next(a);
68 	if (a == NULL)
69 		return PARSE_ERR(a, "u32: missing mask");
70 
71 	mask = bstrtoul(a);
72 	if (mask == ULONG_MAX)
73 		return PARSE_ERR(a, "u32: invalid mask, must be numeric");
74 
75 	a = bstr_next(a);
76 	if (a == NULL || bstrcmp(a, "at") != 0)
77 		return PARSE_ERR(a, "u32: missing \"at\"");
78 
79 	a = bstr_next(a);
80 	if (a == NULL)
81 		return PARSE_ERR(a, "u32: missing offset");
82 
83 	nh_len = strlen("nexthdr+");
84 	if (a->len > nh_len && !memcmp(a->data, "nexthdr+", nh_len)) {
85 		char buf[a->len - nh_len + 1];
86 
87 		offmask = -1;
88 		memcpy(buf, a->data + nh_len, a->len - nh_len);
89 		offset = strtoul(buf, NULL, 0);
90 	} else if (!bstrcmp(a, "nexthdr+")) {
91 		a = bstr_next(a);
92 		if (a == NULL)
93 			return PARSE_ERR(a, "u32: missing offset");
94 		offset = bstrtoul(a);
95 	} else
96 		offset = bstrtoul(a);
97 
98 	if (offset == ULONG_MAX)
99 		return PARSE_ERR(a, "u32: invalid offset");
100 
101 	if (a->next)
102 		return PARSE_ERR(a->next, "u32: unexpected trailer");
103 
104 	switch (align) {
105 		case 1:
106 			if (key > 0xFF)
107 				return PARSE_ERR(a, "Illegal key (>0xFF)");
108 			if (mask > 0xFF)
109 				return PARSE_ERR(a, "Illegal mask (>0xFF)");
110 
111 			key <<= 24 - ((offset & 3) * 8);
112 			mask <<= 24 - ((offset & 3) * 8);
113 			offset &= ~3;
114 			break;
115 
116 		case 2:
117 			if (key > 0xFFFF)
118 				return PARSE_ERR(a, "Illegal key (>0xFFFF)");
119 			if (mask > 0xFFFF)
120 				return PARSE_ERR(a, "Illegal mask (>0xFFFF)");
121 
122 			if ((offset & 3) == 0) {
123 				key <<= 16;
124 				mask <<= 16;
125 			}
126 			offset &= ~3;
127 			break;
128 	}
129 
130 	key = htonl(key);
131 	mask = htonl(mask);
132 
133 	if (offset % 4)
134 		return PARSE_ERR(a, "u32: invalid offset alignment, " \
135 		    "must be aligned to 4.");
136 
137 	key &= mask;
138 
139 	u_key.mask = mask;
140 	u_key.val = key;
141 	u_key.off = offset;
142 	u_key.offmask = offmask;
143 
144 	addraw_l(n, MAX_MSG, hdr, sizeof(*hdr));
145 	addraw_l(n, MAX_MSG, &u_key, sizeof(u_key));
146 
147 #undef PARSE_ERR
148 	return 0;
149 }
150 
u32_print_eopt(FILE * fd,struct tcf_ematch_hdr * hdr,void * data,int data_len)151 static int u32_print_eopt(FILE *fd, struct tcf_ematch_hdr *hdr, void *data,
152 			  int data_len)
153 {
154 	struct tc_u32_key *u_key = data;
155 
156 	if (data_len < sizeof(*u_key)) {
157 		fprintf(stderr, "U32 header size mismatch\n");
158 		return -1;
159 	}
160 
161 	fprintf(fd, "%08x/%08x at %s%d",
162 	    (unsigned int) ntohl(u_key->val),
163 	    (unsigned int) ntohl(u_key->mask),
164 	    u_key->offmask ? "nexthdr+" : "",
165 	    u_key->off);
166 
167 	return 0;
168 }
169 
170 struct ematch_util u32_ematch_util = {
171 	.kind = "u32",
172 	.kind_num = TCF_EM_U32,
173 	.parse_eopt = u32_parse_eopt,
174 	.print_eopt = u32_print_eopt,
175 	.print_usage = u32_print_usage
176 };
177