1 /* $OpenBSD: message.c,v 1.11 2010/05/26 13:56:08 nicm Exp $ */ 2 3 /* 4 * Copyright (c) 2006 Michele Marchetto <mydecay@openbeer.it> 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 19 #include <sys/types.h> 20 #include <sys/socket.h> 21 #include <netinet/in.h> 22 #include <netinet/in_systm.h> 23 #include <netinet/ip.h> 24 #include <arpa/inet.h> 25 #include <netinet/udp.h> 26 27 #include <stdlib.h> 28 #include <string.h> 29 30 #include "ripd.h" 31 #include "rip.h" 32 #include "ripe.h" 33 #include "log.h" 34 35 extern struct ripd_conf *oeconf; 36 37 void delete_entry(struct rip_route *); 38 39 /* timers */ 40 /* ARGSUSED */ 41 void 42 report_timer(int fd, short event, void *arg) 43 { 44 struct timeval tv; 45 46 ripe_imsg_compose_rde(IMSG_FULL_RESPONSE, 0, 0, NULL, 0); 47 48 /* restart report timer */ 49 timerclear(&tv); 50 tv.tv_sec = KEEPALIVE + arc4random_uniform(OFFSET); 51 evtimer_add(&oeconf->report_timer, &tv); 52 } 53 54 int 55 start_report_timer(void) 56 { 57 struct timeval tv; 58 59 timerclear(&tv); 60 tv.tv_sec = KEEPALIVE + arc4random_uniform(OFFSET); 61 return (evtimer_add(&oeconf->report_timer, &tv)); 62 } 63 64 /* list handlers */ 65 void 66 add_entry(struct packet_head *r_list, struct rip_route *rr) 67 { 68 struct packet_entry *re; 69 70 if (rr == NULL) 71 fatalx("add_entry: no route report"); 72 73 if ((re = calloc(1, sizeof(*re))) == NULL) 74 fatal("add_response"); 75 76 TAILQ_INSERT_TAIL(r_list, re, entry); 77 re->rr = rr; 78 rr->refcount++; 79 } 80 81 void 82 delete_entry(struct rip_route *rr) 83 { 84 if (--rr->refcount == 0) 85 free(rr); 86 } 87 88 void 89 clear_list(struct packet_head *r_list) 90 { 91 struct packet_entry *re; 92 93 while ((re = TAILQ_FIRST(r_list)) != NULL) { 94 TAILQ_REMOVE(r_list, re, entry); 95 delete_entry(re->rr); 96 free(re); 97 } 98 } 99 100 /* communications */ 101 int 102 send_triggered_update(struct iface *iface, struct rip_route *rr) 103 { 104 struct sockaddr_in dst; 105 struct ibuf *buf; 106 u_int16_t afi, route_tag; 107 u_int32_t address, netmask, nexthop, metric; 108 109 inet_aton(ALL_RIP_ROUTERS, &dst.sin_addr); 110 111 dst.sin_port = htons(RIP_PORT); 112 dst.sin_family = AF_INET; 113 dst.sin_len = sizeof(struct sockaddr_in); 114 115 if (iface->passive) 116 return (0); 117 118 if ((buf = ibuf_open(iface->mtu - sizeof(struct ip) - 119 sizeof(struct udphdr))) == NULL) 120 fatal("send_triggered_update"); 121 122 gen_rip_hdr(buf, COMMAND_RESPONSE); 123 124 afi = htons(AF_INET); 125 route_tag = 0; 126 127 address = rr->address.s_addr; 128 netmask = rr->mask.s_addr; 129 nexthop = rr->nexthop.s_addr; 130 metric = htonl(rr->metric); 131 132 ibuf_add(buf, &afi, sizeof(afi)); 133 ibuf_add(buf, &route_tag, sizeof(route_tag)); 134 ibuf_add(buf, &address, sizeof(address)); 135 ibuf_add(buf, &netmask, sizeof(netmask)); 136 ibuf_add(buf, &nexthop, sizeof(nexthop)); 137 ibuf_add(buf, &metric, sizeof(metric)); 138 139 send_packet(iface, buf->buf, buf->wpos, &dst); 140 ibuf_free(buf); 141 142 return (0); 143 } 144 145 int 146 send_request(struct packet_head *r_list, struct iface *i, struct nbr *nbr) 147 { 148 struct ibuf *buf; 149 struct iface *iface; 150 struct packet_entry *entry; 151 struct sockaddr_in dst; 152 u_int8_t nentries; 153 u_int8_t single_entry = 0; 154 u_int32_t address, netmask, nexthop; 155 u_int16_t port, afi, route_tag; 156 u_int32_t metric; 157 158 if (i == NULL) { 159 /* directly to a nbr */ 160 iface = nbr->iface; 161 dst.sin_addr = nbr->addr; 162 port = htons(nbr->port); 163 } else { 164 /* multicast on interface */ 165 iface = i; 166 inet_aton(ALL_RIP_ROUTERS, &dst.sin_addr); 167 port = htons(RIP_PORT); 168 } 169 170 dst.sin_port = port; 171 dst.sin_family = AF_INET; 172 dst.sin_len = sizeof(struct sockaddr_in); 173 174 if (iface->passive) 175 return (0); 176 177 while (!TAILQ_EMPTY(r_list)) { 178 if ((buf = ibuf_open(iface->mtu - sizeof(struct ip) - 179 sizeof(struct udphdr))) == NULL) 180 fatal("send_request"); 181 182 gen_rip_hdr(buf, COMMAND_REQUEST); 183 184 route_tag = 0; 185 nentries = 0; 186 187 if (TAILQ_FIRST(r_list) == TAILQ_LAST(r_list, packet_head)) 188 single_entry = 1; 189 while (((entry = TAILQ_FIRST(r_list)) != NULL) && 190 nentries < MAX_RIP_ENTRIES) { 191 afi = htons(AF_INET); 192 193 address = entry->rr->address.s_addr; 194 netmask = entry->rr->mask.s_addr; 195 nexthop = entry->rr->nexthop.s_addr; 196 metric = htonl(entry->rr->metric); 197 198 if (metric == htonl(INFINITY) && single_entry) 199 afi = AF_UNSPEC; 200 201 ibuf_add(buf, &afi, sizeof(afi)); 202 ibuf_add(buf, &route_tag, sizeof(route_tag)); 203 ibuf_add(buf, &address, sizeof(address)); 204 ibuf_add(buf, &netmask, sizeof(netmask)); 205 ibuf_add(buf, &nexthop, sizeof(nexthop)); 206 ibuf_add(buf, &metric, sizeof(metric)); 207 208 TAILQ_REMOVE(r_list, entry, entry); 209 delete_entry(entry->rr); 210 free(entry); 211 nentries++; 212 } 213 send_packet(iface, buf->buf, buf->wpos, &dst); 214 ibuf_free(buf); 215 } 216 217 return (0); 218 } 219 220 int 221 send_response(struct packet_head *r_list, struct iface *i, struct nbr *nbr) 222 { 223 struct ibuf *buf; 224 struct iface *iface; 225 struct packet_entry *entry; 226 struct sockaddr_in dst; 227 u_int8_t nentries; 228 u_int16_t port, afi, route_tag; 229 u_int32_t address, netmask, nexthop; 230 u_int32_t metric; 231 232 if (i == NULL) { 233 /* directly to a nbr */ 234 iface = nbr->iface; 235 dst.sin_addr = nbr->addr; 236 port = htons(nbr->port); 237 } else { 238 /* multicast on interface */ 239 iface = i; 240 inet_aton(ALL_RIP_ROUTERS, &dst.sin_addr); 241 port = htons(RIP_PORT); 242 } 243 244 dst.sin_port = port; 245 dst.sin_family = AF_INET; 246 dst.sin_len = sizeof(struct sockaddr_in); 247 248 if (iface->passive) 249 return (0); 250 251 while (!TAILQ_EMPTY(r_list)) { 252 if ((buf = ibuf_open(iface->mtu - sizeof(struct ip) - 253 sizeof(struct udphdr))) == NULL) 254 fatal("send_response"); 255 256 gen_rip_hdr(buf, COMMAND_RESPONSE); 257 258 afi = htons(AF_INET); 259 route_tag = 0; 260 nentries = 0; 261 262 if (iface->auth_type != AUTH_NONE) { 263 if (auth_gen(buf, iface) == -1) { 264 ibuf_free(buf); 265 return (-1); 266 } 267 nentries++; 268 } 269 270 while ((entry = TAILQ_FIRST(r_list)) != NULL && 271 nentries < MAX_RIP_ENTRIES) { 272 address = entry->rr->address.s_addr; 273 netmask = entry->rr->mask.s_addr; 274 nexthop = entry->rr->nexthop.s_addr; 275 metric = htonl(entry->rr->metric); 276 277 if (entry->rr->ifindex == iface->ifindex) { 278 if (oeconf->options & OPT_SPLIT_HORIZON) 279 goto free; 280 else if (oeconf->options & OPT_SPLIT_POISONED) 281 metric = htonl(INFINITY); 282 } 283 284 /* If the nexthop is not reachable through the 285 * outgoing interface set it to INADDR_ANY */ 286 if ((nexthop & iface->mask.s_addr) != 287 (iface->addr.s_addr & iface->mask.s_addr)) 288 nexthop = INADDR_ANY; 289 290 ibuf_add(buf, &afi, sizeof(afi)); 291 ibuf_add(buf, &route_tag, sizeof(route_tag)); 292 ibuf_add(buf, &address, sizeof(address)); 293 ibuf_add(buf, &netmask, sizeof(netmask)); 294 ibuf_add(buf, &nexthop, sizeof(nexthop)); 295 ibuf_add(buf, &metric, sizeof(metric)); 296 free: 297 TAILQ_REMOVE(r_list, entry, entry); 298 delete_entry(entry->rr); 299 free(entry); 300 nentries++; 301 } 302 303 if (iface->auth_type == AUTH_CRYPT) 304 auth_add_trailer(buf, iface); 305 306 send_packet(iface, buf->buf, buf->wpos, &dst); 307 ibuf_free(buf); 308 } 309 310 return (0); 311 } 312 313 void 314 recv_request(struct iface *i, struct nbr *nbr, u_int8_t *buf, u_int16_t len) 315 { 316 struct rip_entry *e; 317 struct rip_route rr; 318 int l = len; 319 320 bzero(&rr, sizeof(rr)); 321 322 if (len < RIP_ENTRY_LEN) { 323 log_debug("recv_request: bad packet size, interface %s", 324 i->name); 325 return; 326 } 327 328 /* 329 * XXX is it guaranteed that bus is properly aligned. 330 * If not this will bomb on strict alignment archs. 331 * */ 332 e = (struct rip_entry *)buf; 333 334 if (len > RIP_ENTRY_LEN * MAX_RIP_ENTRIES) { 335 log_debug("recv_request: packet too long\n"); 336 return; 337 } 338 339 l -= RIP_ENTRY_LEN; 340 341 /* 342 * If there is exactly one entry in the request, and it has 343 * an address family identifier of zero and a metric of 344 * infinity (i.e., 16), then this is a request to send the 345 * entire routing table. 346 */ 347 if (e->AFI == 0 && e->metric == ntohl(INFINITY) && l == 0) { 348 ripe_imsg_compose_rde(IMSG_FULL_RESPONSE, nbr->peerid, 349 0, NULL, 0); 350 return; 351 } 352 353 for ( ; l >= 0; l -= RIP_ENTRY_LEN) { 354 if (e->AFI != AF_INET) { 355 log_debug("recv_request: AFI %d not supported\n", 356 e->AFI); 357 return; 358 } 359 rr.address.s_addr = e->address; 360 rr.mask.s_addr = e->mask; 361 rr.nexthop.s_addr = e->nexthop; 362 rr.metric = e->metric; 363 rr.ifindex = i->ifindex; 364 365 ripe_imsg_compose_rde(IMSG_ROUTE_REQUEST, nbr->peerid, 366 0, &rr, sizeof(rr)); 367 368 e++; 369 } 370 371 ripe_imsg_compose_rde(IMSG_ROUTE_REQUEST_END, nbr->peerid, 372 0, NULL, 0); 373 } 374 375 void 376 recv_response(struct iface *i, struct nbr *nbr, u_int8_t *buf, u_int16_t len) 377 { 378 struct rip_route r; 379 struct rip_entry *e; 380 int l; 381 382 if (len < RIP_ENTRY_LEN) { 383 log_debug("recv_response: bad packet size, interface %s", 384 i->name); 385 return; 386 } 387 388 /* We must double check the length, because the only entry 389 * can be stripped off by authentication code 390 */ 391 if (len < RIP_ENTRY_LEN) { 392 /* If there are no entries, our work is finished here */ 393 return; 394 } 395 396 /* XXX again */ 397 e = (struct rip_entry *)buf; 398 399 if (len > RIP_ENTRY_LEN * MAX_RIP_ENTRIES) { 400 log_debug("recv_response: packet too long\n"); 401 return; 402 } 403 404 l = len - sizeof(*e); 405 406 for ( ; l >= 0; l -= RIP_ENTRY_LEN) { 407 if (ntohs(e->AFI) != AF_INET) { 408 log_debug("recv_response: AFI %d not supported\n", 409 e->AFI); 410 return; 411 } 412 413 r.address.s_addr = e->address; 414 r.mask.s_addr = e->mask; 415 416 if (e->nexthop == INADDR_ANY || 417 ((i->addr.s_addr & i->mask.s_addr) != 418 (e->nexthop & i->mask.s_addr))) 419 r.nexthop.s_addr = nbr->addr.s_addr; 420 else 421 r.nexthop.s_addr = e->nexthop; 422 423 r.metric = ntohl(e->metric); 424 r.ifindex = i->ifindex; 425 426 ripe_imsg_compose_rde(IMSG_ROUTE_FEED, 0, 0, &r, sizeof(r)); 427 428 e++; 429 } 430 } 431