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