xref: /openbsd-src/usr.sbin/bgpd/util.c (revision a28daedfc357b214be5c701aa8ba8adb29a7f1c2)
1 /*	$OpenBSD: util.c,v 1.5 2008/11/06 21:16:27 claudio Exp $ */
2 
3 /*
4  * Copyright (c) 2006 Claudio Jeker <claudio@openbsd.org>
5  * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
6  *
7  * Permission to use, copy, modify, and distribute this software for any
8  * purpose with or without fee is hereby granted, provided that the above
9  * copyright notice and this permission notice appear in all copies.
10  *
11  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18  */
19 #include <sys/types.h>
20 #include <sys/socket.h>
21 #include <netinet/in.h>
22 #include <arpa/inet.h>
23 #include <netdb.h>
24 #include <stdlib.h>
25 #include <stdio.h>
26 #include <string.h>
27 
28 #include "bgpd.h"
29 #include "rde.h"
30 
31 const char *
32 log_addr(const struct bgpd_addr *addr)
33 {
34 	static char	buf[48];
35 
36 	if (inet_ntop(addr->af, &addr->ba, buf, sizeof(buf)) == NULL)
37 		return ("?");
38 	else
39 		return (buf);
40 }
41 
42 const char *
43 log_in6addr(const struct in6_addr *addr)
44 {
45 	struct sockaddr_in6	sa_in6;
46 	u_int16_t		tmp16;
47 
48 	bzero(&sa_in6, sizeof(sa_in6));
49 	sa_in6.sin6_len = sizeof(sa_in6);
50 	sa_in6.sin6_family = AF_INET6;
51 	memcpy(&sa_in6.sin6_addr, addr, sizeof(sa_in6.sin6_addr));
52 
53 	/* XXX thanks, KAME, for this ugliness... adopted from route/show.c */
54 	if (IN6_IS_ADDR_LINKLOCAL(&sa_in6.sin6_addr) ||
55 	    IN6_IS_ADDR_MC_LINKLOCAL(&sa_in6.sin6_addr)) {
56 		memcpy(&tmp16, &sa_in6.sin6_addr.s6_addr[2], sizeof(tmp16));
57 		sa_in6.sin6_scope_id = ntohs(tmp16);
58 		sa_in6.sin6_addr.s6_addr[2] = 0;
59 		sa_in6.sin6_addr.s6_addr[3] = 0;
60 	}
61 
62 	return (log_sockaddr((struct sockaddr *)&sa_in6));
63 }
64 
65 const char *
66 log_sockaddr(struct sockaddr *sa)
67 {
68 	static char	buf[NI_MAXHOST];
69 
70 	if (getnameinfo(sa, sa->sa_len, buf, sizeof(buf), NULL, 0,
71 	    NI_NUMERICHOST))
72 		return ("(unknown)");
73 	else
74 		return (buf);
75 }
76 
77 const char *
78 log_as(u_int32_t as)
79 {
80 	static char	buf[12];	/* "65000.65000\0" */
81 
82 	if (as <= USHRT_MAX) {
83 		if (snprintf(buf, sizeof(buf), "%u", as) == -1)
84 			return ("?");
85 	} else {
86 		if (snprintf(buf, sizeof(buf), "%u.%u", as >> 16,
87 		    as & 0xffff) == -1)
88 			return ("?");
89 	}
90 	return (buf);
91 }
92 
93 int
94 aspath_snprint(char *buf, size_t size, void *data, u_int16_t len)
95 {
96 #define UPDATE()				\
97 	do {					\
98 		if (r == -1)			\
99 			return (-1);		\
100 		total_size += r;		\
101 		if ((unsigned int)r < size) {	\
102 			size -= r;		\
103 			buf += r;		\
104 		} else {			\
105 			buf += size;		\
106 			size = 0;		\
107 		}				\
108 	} while (0)
109 	u_int8_t	*seg;
110 	int		 r, total_size;
111 	u_int16_t	 seg_size;
112 	u_int8_t	 i, seg_type, seg_len;
113 
114 	total_size = 0;
115 	seg = data;
116 	for (; len > 0; len -= seg_size, seg += seg_size) {
117 		seg_type = seg[0];
118 		seg_len = seg[1];
119 		seg_size = 2 + sizeof(u_int32_t) * seg_len;
120 
121 		if (seg_type == AS_SET) {
122 			if (total_size != 0)
123 				r = snprintf(buf, size, " { ");
124 			else
125 				r = snprintf(buf, size, "{ ");
126 			UPDATE();
127 		} else if (total_size != 0) {
128 			r = snprintf(buf, size, " ");
129 			UPDATE();
130 		}
131 
132 		for (i = 0; i < seg_len; i++) {
133 			r = snprintf(buf, size, "%s",
134 			    log_as(aspath_extract(seg, i)));
135 			UPDATE();
136 			if (i + 1 < seg_len) {
137 				r = snprintf(buf, size, " ");
138 				UPDATE();
139 			}
140 		}
141 		if (seg_type == AS_SET) {
142 			r = snprintf(buf, size, " }");
143 			UPDATE();
144 		}
145 	}
146 	/* ensure that we have a valid C-string especially for empty as path */
147 	if (size > 0)
148 		*buf = '\0';
149 
150 	return (total_size);
151 #undef UPDATE
152 }
153 
154 int
155 aspath_asprint(char **ret, void *data, u_int16_t len)
156 {
157 	size_t	slen;
158 	int	plen;
159 
160 	slen = aspath_strlen(data, len) + 1;
161 	*ret = malloc(slen);
162 	if (*ret == NULL)
163 		return (-1);
164 
165 	plen = aspath_snprint(*ret, slen, data, len);
166 	if (plen == -1) {
167 		free(*ret);
168 		*ret = NULL;
169 		return (-1);
170 	}
171 
172 	return (0);
173 }
174 
175 size_t
176 aspath_strlen(void *data, u_int16_t len)
177 {
178 	u_int8_t	*seg;
179 	int		 total_size;
180 	u_int32_t	 as;
181 	u_int16_t	 seg_size;
182 	u_int8_t	 i, seg_type, seg_len;
183 
184 	total_size = 0;
185 	seg = data;
186 	for (; len > 0; len -= seg_size, seg += seg_size) {
187 		seg_type = seg[0];
188 		seg_len = seg[1];
189 		seg_size = 2 + sizeof(u_int32_t) * seg_len;
190 
191 		if (seg_type == AS_SET)
192 			if (total_size != 0)
193 				total_size += 3;
194 			else
195 				total_size += 2;
196 		else if (total_size != 0)
197 			total_size += 1;
198 
199 		for (i = 0; i < seg_len; i++) {
200 			as = aspath_extract(seg, i);
201 			if (as > USHRT_MAX) {
202 				u_int32_t	a = as >> 16;
203 
204 				if (a >= 10000)
205 					total_size += 5;
206 				else if (a >= 1000)
207 					total_size += 4;
208 				else if (a >= 100)
209 					total_size += 3;
210 				else if (a >= 10)
211 					total_size += 2;
212 				else
213 					total_size += 1;
214 				total_size += 1; /* dot between hi & lo */
215 				as &= 0xffff;
216 			}
217 			if (as >= 10000)
218 				total_size += 5;
219 			else if (as >= 1000)
220 				total_size += 4;
221 			else if (as >= 100)
222 				total_size += 3;
223 			else if (as >= 10)
224 				total_size += 2;
225 			else
226 				total_size += 1;
227 
228 			if (i + 1 < seg_len)
229 				total_size += 1;
230 		}
231 
232 		if (seg_type == AS_SET)
233 			total_size += 2;
234 	}
235 	return (total_size);
236 }
237 
238 /*
239  * Extract the asnum out of the as segment at the specified position.
240  * Direct access is not possible because of non-aligned reads.
241  * ATTENTION: no bounds checks are done.
242  */
243 u_int32_t
244 aspath_extract(const void *seg, int pos)
245 {
246 	const u_char	*ptr = seg;
247 	u_int32_t	 as;
248 
249 	ptr += 2 + sizeof(u_int32_t) * pos;
250 	memcpy(&as, ptr, sizeof(u_int32_t));
251 	return (ntohl(as));
252 }
253