1 /*	$OpenBSD: rde_community_test.c,v 1.2 2019/07/04 10:20:59 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 struct rde_peer peer = {
31 	.conf.remote_as = 22512,
32 	.conf.local_as = 42,
33 };
34 
35 static void
36 dump(uint8_t *b, size_t len)
37 {
38 	size_t l;
39 
40 	printf("\n\t{\n\t\t.data = \"");
41 	for (l = 0; l < len; l++) {
42 		printf("\\x%02x", b[l]);
43 		if (l % 12 == 0 && l != 0)
44 			printf("\"\n\t\t    \"");
45 	}
46 	printf("\",\n\t\t.size = %zu\n\t},\n", len);
47 }
48 
49 static int
50 test_parsing(size_t num, uint8_t *in, size_t inlen)
51 {
52 	const char *func = "community";
53 	uint8_t flags, type, attr[256];
54 	size_t skip = 2;
55 	uint16_t attr_len;
56 	int r;
57 
58 	communities_clean(&comm);
59 
60 	flags = in[0];
61 	type = in[1];
62 	if (flags & ATTR_EXTLEN) {
63 		memcpy(&attr_len, in + 2, sizeof(attr_len));
64 		attr_len = ntohs(attr_len);
65 		skip += 2;
66 	} else {
67 		attr_len = in[2];
68 		skip += 1;
69 	}
70 
71 	switch (type) {
72 	case ATTR_COMMUNITIES:
73 		r = community_add(&comm, flags, in + skip, attr_len);
74 		break;
75 	case ATTR_EXT_COMMUNITIES:
76 		r = community_ext_add(&comm, flags, in + skip, attr_len);
77 		break;
78 	case ATTR_LARGE_COMMUNITIES:
79 		r = community_large_add(&comm, flags, in + skip, attr_len);
80 		break;
81 	}
82 	if (r == -1) {
83 		printf("Test %zu: %s_add failed\n", num, func);
84 		return -1;
85 	}
86 
87 	switch (type) {
88 	case ATTR_COMMUNITIES:
89 		r = community_write(&comm, attr, sizeof(attr));
90 		break;
91 	case ATTR_EXT_COMMUNITIES:
92 		r = community_ext_write(&comm, 0, attr, sizeof(attr));
93 		break;
94 	case ATTR_LARGE_COMMUNITIES:
95 		r = community_large_write(&comm, attr, sizeof(attr));
96 		break;
97 	}
98 
99 	if (r != inlen) {
100 		printf("Test %zu: %s_write return value %d != %zd\n",
101 		    num, func, r, inlen);
102 		return -1;
103 	}
104 	if (r != -1 && memcmp(attr, in, inlen) != 0) {
105 		printf("Test %zu: %s_write unexpected encoding: ", num, func);
106 		dump(attr, inlen);
107 		printf("expected: ");
108 		dump(in, inlen);
109 		return -1;
110 	}
111 
112 	return 0;
113 }
114 
115 static int
116 test_filter(size_t num, struct testfilter *f)
117 {
118 	size_t l;
119 	int r;
120 
121 	communities_clean(&comm);
122 	for (l = 0; f->in[l] != -1; l++) {
123 		r = community_set(&comm, &filters[f->in[l]], &peer);
124 		if (r != 1) {
125 			printf("Test %zu: community_set %zu "
126 			    "unexpected return %d != 1\n",
127 			    num, l, r);
128 			return -1;
129 		}
130 	}
131 
132 	r = community_match(&comm, &filters[f->match], &peer);
133 	if (r != f->mout) {
134 		printf("Test %zu: community_match "
135 		    "unexpected return %d != %d\n", num, r, f->mout);
136 		return -1;
137 	}
138 
139 	if (f->delete == -1)
140 		return 0;
141 
142 	community_delete(&comm, &filters[f->delete], &peer);
143 
144 	if (community_match(&comm, &filters[f->delete], &peer) != 0) {
145 		printf("Test %zu: community_delete still around\n", num);
146 		return -1;
147 	}
148 
149 	return 0;
150 }
151 
152 int
153 main(int argc, char *argv[])
154 {
155 	size_t t;
156 	int error = 0;
157 
158 	for (t = 0; t < sizeof(vectors) / sizeof(*vectors); t++) {
159 		if (test_parsing(t, vectors[t].data, vectors[t].size) == -1)
160 			error = 1;
161 	}
162 
163 	for (t = 0; t < sizeof(testfilters) / sizeof(*testfilters); t++) {
164 		if (test_filter(t, &testfilters[t]) == -1)
165 			error = 1;
166 	}
167 
168 	if (!error)
169 		printf("OK\n");
170 	return error;
171 }
172 
173 __dead void
174 fatalx(const char *emsg, ...)
175 {
176 	va_list ap;
177 	va_start(ap, emsg);
178 	verrx(2, emsg, ap);
179 }
180 
181 __dead void
182 fatal(const char *emsg, ...)
183 {
184 	va_list ap;
185 	va_start(ap, emsg);
186 	verr(2, emsg, ap);
187 }
188 
189 void
190 log_warnx(const char *emsg, ...)
191 {
192 	va_list  ap;
193 	va_start(ap, emsg);
194 	vwarnx(emsg, ap);
195 	va_end(ap);
196 }
197 
198 int
199 attr_write(void *p, u_int16_t p_len, u_int8_t flags, u_int8_t type,
200     void *data, u_int16_t data_len)
201 {
202 	u_char		*b = p;
203 	u_int16_t	 tmp, tot_len = 2; /* attribute header (without len) */
204 
205 	flags &= ~ATTR_DEFMASK;
206 	if (data_len > 255) {
207 		tot_len += 2 + data_len;
208 		flags |= ATTR_EXTLEN;
209 	} else {
210 		tot_len += 1 + data_len;
211 	}
212 
213 	if (tot_len > p_len)
214 		return (-1);
215 
216 	*b++ = flags;
217 	*b++ = type;
218 	if (data_len > 255) {
219 		tmp = htons(data_len);
220 		memcpy(b, &tmp, sizeof(tmp));
221 		b += 2;
222 	} else
223 		*b++ = (u_char)data_len;
224 
225 	if (data == NULL)
226 		return (tot_len - data_len);
227 
228 	if (data_len != 0)
229 		memcpy(b, data, data_len);
230 
231 	return (tot_len);
232 }
233 
234 int
235 attr_writebuf(struct ibuf *buf, u_int8_t flags, u_int8_t type, void *data,
236     u_int16_t data_len)
237 {
238 	return (-1);
239 }
240