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