1 /* $OpenBSD: kroute.c,v 1.7 2011/07/04 04:34:14 claudio Exp $ */ 2 3 /* 4 * Copyright (c) 2004 Esben Norby <norby@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 20 #include <sys/param.h> 21 #include <sys/types.h> 22 #include <sys/socket.h> 23 #include <sys/sysctl.h> 24 #include <sys/tree.h> 25 #include <netinet/in.h> 26 #include <arpa/inet.h> 27 #include <net/if.h> 28 #include <net/if_dl.h> 29 #include <net/if_types.h> 30 #include <net/route.h> 31 #include <err.h> 32 #include <errno.h> 33 #include <fcntl.h> 34 #include <stdio.h> 35 #include <stdlib.h> 36 #include <string.h> 37 #include <unistd.h> 38 39 #include "dvmrp.h" 40 #include "dvmrpd.h" 41 #include "log.h" 42 43 struct { 44 u_int32_t rtseq; 45 pid_t pid; 46 struct event ev; 47 } kr_state; 48 49 struct kif_node { 50 RB_ENTRY(kif_node) entry; 51 struct kif k; 52 }; 53 54 int kif_compare(struct kif_node *, struct kif_node *); 55 56 struct kif_node *kif_find(int); 57 int kif_insert(struct kif_node *); 58 int kif_remove(struct kif_node *); 59 void kif_clear(void); 60 61 in_addr_t prefixlen2mask(u_int8_t); 62 void get_rtaddrs(int, struct sockaddr *, struct sockaddr **); 63 void if_change(u_short, int, struct if_data *); 64 void if_announce(void *); 65 66 int fetchifs(int); 67 68 RB_HEAD(kif_tree, kif_node) kit; 69 RB_PROTOTYPE(kif_tree, kif_node, entry, kif_compare) 70 RB_GENERATE(kif_tree, kif_node, entry, kif_compare) 71 72 int 73 kif_init(void) 74 { 75 RB_INIT(&kit); 76 77 if (fetchifs(0) == -1) 78 return (-1); 79 80 return (0); 81 } 82 83 int 84 kr_init(void) 85 { 86 int opt, fd; 87 88 if ((fd = socket(AF_ROUTE, SOCK_RAW, 0)) == -1) { 89 log_warn("kr_init: socket"); 90 return (-1); 91 } 92 93 /* not interested in my own messages */ 94 if (setsockopt(fd, SOL_SOCKET, SO_USELOOPBACK, &opt, sizeof(opt)) == -1) 95 log_warn("kr_init: setsockopt"); /* not fatal */ 96 97 kr_state.pid = getpid(); 98 kr_state.rtseq = 1; 99 100 event_set(&kr_state.ev, fd, EV_READ | EV_PERSIST, 101 kr_dispatch_msg, NULL); 102 event_add(&kr_state.ev, NULL); 103 104 return (0); 105 } 106 107 void 108 kr_shutdown(void) 109 { 110 kif_clear(); 111 close(EVENT_FD((&kr_state.ev))); 112 } 113 114 void 115 kr_ifinfo(char *ifname) 116 { 117 struct kif_node *kif; 118 119 RB_FOREACH(kif, kif_tree, &kit) 120 if (!strcmp(ifname, kif->k.ifname)) { 121 main_imsg_compose_dvmrpe(IMSG_CTL_IFINFO, 0, 122 &kif->k, sizeof(kif->k)); 123 return; 124 } 125 } 126 127 /* rb-tree compare */ 128 int 129 kif_compare(struct kif_node *a, struct kif_node *b) 130 { 131 return (b->k.ifindex - a->k.ifindex); 132 } 133 134 struct kif_node * 135 kif_find(int ifindex) 136 { 137 struct kif_node s; 138 139 bzero(&s, sizeof(s)); 140 s.k.ifindex = ifindex; 141 142 return (RB_FIND(kif_tree, &kit, &s)); 143 } 144 145 struct kif * 146 kif_findname(char *ifname) 147 { 148 struct kif_node *kif; 149 150 RB_FOREACH(kif, kif_tree, &kit) 151 if (!strcmp(ifname, kif->k.ifname)) 152 return (&kif->k); 153 154 return (NULL); 155 } 156 157 int 158 kif_insert(struct kif_node *kif) 159 { 160 if (RB_INSERT(kif_tree, &kit, kif) != NULL) { 161 log_warnx("RB_INSERT(kif_tree, &kit, kif)"); 162 free(kif); 163 return (-1); 164 } 165 166 return (0); 167 } 168 169 int 170 kif_remove(struct kif_node *kif) 171 { 172 if (RB_REMOVE(kif_tree, &kit, kif) == NULL) { 173 log_warnx("RB_REMOVE(kif_tree, &kit, kif)"); 174 return (-1); 175 } 176 177 free(kif); 178 return (0); 179 } 180 181 void 182 kif_clear(void) 183 { 184 struct kif_node *kif; 185 186 while ((kif = RB_MIN(kif_tree, &kit)) != NULL) 187 kif_remove(kif); 188 } 189 190 /* misc */ 191 u_int8_t 192 prefixlen_classful(in_addr_t ina) 193 { 194 /* it hurt to write this. */ 195 196 if (ina >= 0xf0000000U) /* class E */ 197 return (32); 198 else if (ina >= 0xe0000000U) /* class D */ 199 return (4); 200 else if (ina >= 0xc0000000U) /* class C */ 201 return (24); 202 else if (ina >= 0x80000000U) /* class B */ 203 return (16); 204 else /* class A */ 205 return (8); 206 } 207 208 u_int8_t 209 mask2prefixlen(in_addr_t ina) 210 { 211 if (ina == 0) 212 return (0); 213 else 214 return (33 - ffs(ntohl(ina))); 215 } 216 217 in_addr_t 218 prefixlen2mask(u_int8_t prefixlen) 219 { 220 if (prefixlen == 0) 221 return (0); 222 223 return (0xffffffff << (32 - prefixlen)); 224 } 225 226 void 227 if_change(u_short ifindex, int flags, struct if_data *ifd) 228 { 229 struct kif_node *kif; 230 u_int8_t reachable; 231 232 if ((kif = kif_find(ifindex)) == NULL) { 233 log_warnx("interface with index %u not found", 234 ifindex); 235 return; 236 } 237 238 kif->k.flags = flags; 239 kif->k.link_state = ifd->ifi_link_state; 240 kif->k.media_type = ifd->ifi_type; 241 kif->k.baudrate = ifd->ifi_baudrate; 242 243 if ((reachable = (flags & IFF_UP) && 244 LINK_STATE_IS_UP(ifd->ifi_link_state)) == kif->k.nh_reachable) 245 return; /* nothing changed wrt nexthop validity */ 246 247 kif->k.nh_reachable = reachable; 248 main_imsg_compose_dvmrpe(IMSG_IFINFO, 0, &kif->k, sizeof(kif->k)); 249 } 250 251 void 252 if_announce(void *msg) 253 { 254 struct if_announcemsghdr *ifan; 255 struct kif_node *kif; 256 257 ifan = msg; 258 259 switch (ifan->ifan_what) { 260 case IFAN_ARRIVAL: 261 if ((kif = calloc(1, sizeof(struct kif_node))) == NULL) { 262 log_warn("if_announce"); 263 return; 264 } 265 266 kif->k.ifindex = ifan->ifan_index; 267 strlcpy(kif->k.ifname, ifan->ifan_name, sizeof(kif->k.ifname)); 268 kif_insert(kif); 269 break; 270 case IFAN_DEPARTURE: 271 kif = kif_find(ifan->ifan_index); 272 kif_remove(kif); 273 break; 274 } 275 } 276 277 /* rtsock */ 278 #define ROUNDUP(a, size) \ 279 (((a) & ((size) - 1)) ? (1 + ((a) | ((size) - 1))) : (a)) 280 281 void 282 get_rtaddrs(int addrs, struct sockaddr *sa, struct sockaddr **rti_info) 283 { 284 int i; 285 286 for (i = 0; i < RTAX_MAX; i++) { 287 if (addrs & (1 << i)) { 288 rti_info[i] = sa; 289 sa = (struct sockaddr *)((char *)(sa) + 290 ROUNDUP(sa->sa_len, sizeof(long))); 291 } else 292 rti_info[i] = NULL; 293 } 294 } 295 296 int 297 fetchifs(int ifindex) 298 { 299 size_t len; 300 int mib[6]; 301 char *buf, *next, *lim; 302 struct if_msghdr ifm; 303 struct kif_node *kif; 304 struct sockaddr *sa, *rti_info[RTAX_MAX]; 305 struct sockaddr_dl *sdl; 306 307 mib[0] = CTL_NET; 308 mib[1] = AF_ROUTE; 309 mib[2] = 0; 310 mib[3] = AF_INET; 311 mib[4] = NET_RT_IFLIST; 312 mib[5] = ifindex; 313 314 if (sysctl(mib, 6, NULL, &len, NULL, 0) == -1) { 315 log_warn("sysctl"); 316 return (-1); 317 } 318 if ((buf = malloc(len)) == NULL) { 319 log_warn("fetchif"); 320 return (-1); 321 } 322 if (sysctl(mib, 6, buf, &len, NULL, 0) == -1) { 323 log_warn("sysctl"); 324 free(buf); 325 return (-1); 326 } 327 328 lim = buf + len; 329 for (next = buf; next < lim; next += ifm.ifm_msglen) { 330 memcpy(&ifm, next, sizeof(ifm)); 331 sa = (struct sockaddr *)(next + sizeof(ifm)); 332 get_rtaddrs(ifm.ifm_addrs, sa, rti_info); 333 334 if (ifm.ifm_version != RTM_VERSION) 335 continue; 336 if (ifm.ifm_type != RTM_IFINFO) 337 continue; 338 339 if ((kif = calloc(1, sizeof(struct kif_node))) == NULL) { 340 log_warn("fetchifs"); 341 free(buf); 342 return (-1); 343 } 344 345 kif->k.ifindex = ifm.ifm_index; 346 kif->k.flags = ifm.ifm_flags; 347 kif->k.link_state = ifm.ifm_data.ifi_link_state; 348 kif->k.media_type = ifm.ifm_data.ifi_type; 349 kif->k.baudrate = ifm.ifm_data.ifi_baudrate; 350 kif->k.mtu = ifm.ifm_data.ifi_mtu; 351 kif->k.nh_reachable = (kif->k.flags & IFF_UP) && 352 LINK_STATE_IS_UP(ifm.ifm_data.ifi_link_state); 353 if ((sa = rti_info[RTAX_IFP]) != NULL) 354 if (sa->sa_family == AF_LINK) { 355 sdl = (struct sockaddr_dl *)sa; 356 if (sdl->sdl_nlen >= sizeof(kif->k.ifname)) 357 memcpy(kif->k.ifname, sdl->sdl_data, 358 sizeof(kif->k.ifname) - 1); 359 else if (sdl->sdl_nlen > 0) 360 memcpy(kif->k.ifname, sdl->sdl_data, 361 sdl->sdl_nlen); 362 /* string already terminated via calloc() */ 363 } 364 365 kif_insert(kif); 366 } 367 free(buf); 368 return (0); 369 } 370 371 void 372 kr_dispatch_msg(int fd, short event, void *bula) 373 { 374 char buf[RT_BUF_SIZE]; 375 ssize_t n; 376 char *next, *lim; 377 struct rt_msghdr *rtm; 378 struct if_msghdr ifm; 379 380 if ((n = read(fd, &buf, sizeof(buf))) == -1) 381 fatal("dispatch_rtmsg: read error"); 382 383 if (n == 0) 384 fatalx("routing socket closed"); 385 386 lim = buf + n; 387 for (next = buf; next < lim; next += rtm->rtm_msglen) { 388 rtm = (struct rt_msghdr *)next; 389 if (rtm->rtm_version != RTM_VERSION) 390 continue; 391 392 switch (rtm->rtm_type) { 393 case RTM_IFINFO: 394 memcpy(&ifm, next, sizeof(ifm)); 395 if_change(ifm.ifm_index, ifm.ifm_flags, 396 &ifm.ifm_data); 397 break; 398 case RTM_IFANNOUNCE: 399 if_announce(next); 400 break; 401 default: 402 /* ignore for now */ 403 break; 404 } 405 } 406 } 407