1 /*	$OpenBSD: rde_community_test.c,v 1.10 2024/01/24 14:51:56 claudio Exp $ */
2 
3 /*
4  * Copyright (c) 2019 Claudio Jeker <claudio@openbsd.org>
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 #include <err.h>
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <string.h>
22 
23 #include "rde.h"
24 #include "log.h"
25 
26 #include "rde_community_test.h"
27 
28 struct rde_memstats rdemem;
29 struct rde_community comm;
30 
31 static void
32 dump(uint8_t *b, size_t len)
33 {
34 	size_t l;
35 
36 	printf("\n\t{\n\t\t.data = \"");
37 	for (l = 0; l < len; l++) {
38 		printf("\\x%02x", b[l]);
39 		if (l % 12 == 0 && l != 0)
40 			printf("\"\n\t\t    \"");
41 	}
42 	printf("\",\n\t\t.size = %zu\n\t},\n", len);
43 }
44 
45 static int
46 test_parsing(size_t num, struct ibuf *in, struct ibuf *out)
47 {
48 	struct ibuf *buf, abuf;
49 	uint8_t flags, type, attr[256];
50 	size_t skip;
51 	uint16_t attr_len;
52 	int r;
53 
54 	communities_clean(&comm);
55 
56 	do {
57 		if (ibuf_get_n8(in, &flags) == -1 ||
58 		    ibuf_get_n8(in, &type) == -1)
59 			goto bad;
60 		if (flags & ATTR_EXTLEN) {
61 			if (ibuf_get_n16(in, &attr_len) == -1)
62 				goto bad;
63 		} else {
64 			uint8_t tmp;
65 			if (ibuf_get_n8(in, &tmp) == -1)
66 				goto bad;
67 			attr_len = tmp;
68 		}
69 		if (ibuf_get_ibuf(in, attr_len, &abuf) == -1) {
70  bad:
71 			printf("Test %zu: attribute parse failure\n", num);
72 			return -1;
73 		}
74 
75 		switch (type) {
76 		case ATTR_COMMUNITIES:
77 			r = community_add(&comm, flags, &abuf);
78 			break;
79 		case ATTR_EXT_COMMUNITIES:
80 			r = community_ext_add(&comm, flags, 0, &abuf);
81 			break;
82 		case ATTR_LARGE_COMMUNITIES:
83 			r = community_large_add(&comm, flags, &abuf);
84 			break;
85 		}
86 		if (r == -1) {
87 			printf("Test %zu: community_add failed\n", num);
88 			return -1;
89 		}
90 	} while (ibuf_size(in) > 0);
91 
92 	if ((buf = ibuf_dynamic(0, 4096)) == NULL) {
93 		printf("Test %zu: ibuf_dynamic failed\n", num);
94 		return -1;
95 	}
96 
97 	if (community_writebuf(&comm, ATTR_COMMUNITIES, 1, buf) == -1) {
98 		printf("Test %zu: community_writebuf failed\n", num);
99 		return -1;
100 	}
101 	if (community_writebuf(&comm, ATTR_EXT_COMMUNITIES, 1, buf) == -1) {
102 		printf("Test %zu: community_writebuf failed\n", num);
103 		return -1;
104 	}
105 	if (community_writebuf(&comm, ATTR_LARGE_COMMUNITIES, 1, buf) == -1) {
106 		printf("Test %zu: community_writebuf failed\n", num);
107 		return -1;
108 	}
109 
110 	if (ibuf_size(buf) != ibuf_size(out)) {
111 		printf("Test %zu: ibuf size value %zd != %zd:",
112 		    num, ibuf_size(buf), ibuf_size(out));
113 		dump(ibuf_data(buf), ibuf_size(buf));
114 		printf("expected: ");
115 		dump(ibuf_data(out), ibuf_size(out));
116 		return -1;
117 	}
118 	if (memcmp(ibuf_data(buf), ibuf_data(out), ibuf_size(out)) != 0) {
119 		printf("Test %zu: unexpected encoding: ", num);
120 		dump(ibuf_data(buf), ibuf_size(buf));
121 		printf("expected: ");
122 		dump(ibuf_data(out), ibuf_size(out));
123 		return -1;
124 	}
125 
126 	return 0;
127 }
128 
129 static int
130 test_filter(size_t num, struct testfilter *f)
131 {
132 	size_t l;
133 	int r;
134 	struct rde_peer *p = &peer;
135 
136 	communities_clean(&comm);
137 
138 	if (f->peer != NULL)
139 		p = f->peer;
140 
141 	for (l = 0; f->in[l] != -1; l++) {
142 		r = community_set(&comm, &filters[f->in[l]], p);
143 		if (r != 1) {
144 			printf("Test %zu: community_set %zu "
145 			    "unexpected return %d != 1\n",
146 			    num, l, r);
147 			return -1;
148 		}
149 	}
150 
151 	if (f->match != -1) {
152 		r = community_match(&comm, &filters[f->match], p);
153 		if (r != f->mout) {
154 			printf("Test %zu: community_match "
155 			    "unexpected return %d != %d\n", num, r, f->mout);
156 			return -1;
157 		}
158 	}
159 
160 	if (f->delete != -1) {
161 		community_delete(&comm, &filters[f->delete], p);
162 
163 		if (community_match(&comm, &filters[f->delete], p) != 0) {
164 			printf("Test %zu: community_delete still around\n",
165 			    num);
166 			return -1;
167 		}
168 	}
169 
170 	if (f->ncomm != 0) {
171 		if (community_count(&comm, COMMUNITY_TYPE_BASIC) !=
172 		    f->ncomm - 1) {
173 			printf("Test %zu: community_count unexpected "
174 			    "return %d != %d\n", num, r, f->ncomm - 1);
175 			return -1;
176 		}
177 	}
178 
179 	if (f->next != 0) {
180 		if (community_count(&comm, COMMUNITY_TYPE_EXT) !=
181 		    f->next - 1) {
182 			printf("Test %zu: ext community_count unexpected "
183 			    "return %d != %d\n", num, r, f->next - 1);
184 			return -1;
185 		}
186 	}
187 
188 	if (f->nlarge != 0) {
189 		if (community_count(&comm, COMMUNITY_TYPE_LARGE) !=
190 		    f->nlarge - 1) {
191 			printf("Test %zu: large community_count unexpected "
192 			    "return %d != %d\n", num, r, f->nlarge - 1);
193 			return -1;
194 		}
195 	}
196 
197 	return 0;
198 }
199 
200 int
201 main(int argc, char *argv[])
202 {
203 	size_t t;
204 	int error = 0;
205 
206 	for (t = 0; t < sizeof(vectors) / sizeof(*vectors); t++) {
207 		struct ibuf in, out;
208 
209 		ibuf_from_buffer(&in, vectors[t].data, vectors[t].size);
210 		if (vectors[t].expected == NULL)
211 			ibuf_from_buffer(&out,
212 			    vectors[t].data, vectors[t].size);
213 		else
214 			ibuf_from_buffer(&out,
215 			    vectors[t].expected, vectors[t].expsize);
216 
217 		if (test_parsing(t, &in, &out) == -1)
218 			error = 1;
219 	}
220 
221 	for (t = 0; t < sizeof(testfilters) / sizeof(*testfilters); t++) {
222 		if (test_filter(t, &testfilters[t]) == -1)
223 			error = 1;
224 	}
225 
226 	if (!error)
227 		printf("OK\n");
228 	return error;
229 }
230 
231 __dead void
232 fatalx(const char *emsg, ...)
233 {
234 	va_list ap;
235 	va_start(ap, emsg);
236 	verrx(2, emsg, ap);
237 }
238 
239 __dead void
240 fatal(const char *emsg, ...)
241 {
242 	va_list ap;
243 	va_start(ap, emsg);
244 	verr(2, emsg, ap);
245 }
246 
247 void
248 log_warnx(const char *emsg, ...)
249 {
250 	va_list  ap;
251 	va_start(ap, emsg);
252 	vwarnx(emsg, ap);
253 	va_end(ap);
254 }
255 
256 int
257 attr_writebuf(struct ibuf *buf, uint8_t flags, uint8_t type, void *data,
258     uint16_t data_len)
259 {
260 	u_char  hdr[4];
261 
262 	flags &= ~ATTR_DEFMASK;
263 	if (data_len > 255) {
264 		flags |= ATTR_EXTLEN;
265 		hdr[2] = (data_len >> 8) & 0xff;
266 		hdr[3] = data_len & 0xff;
267 	} else {
268 		hdr[2] = data_len & 0xff;
269 	}
270 
271 	hdr[0] = flags;
272 	hdr[1] = type;
273 
274 	if (ibuf_add(buf, hdr, flags & ATTR_EXTLEN ? 4 : 3) == -1)
275 		return (-1);
276 	if (data != NULL && ibuf_add(buf, data, data_len) == -1)
277 		return (-1);
278 	return (0);
279 
280 }
281