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