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