1*28b8bcf0Sflorian /* $OpenBSD: message.c,v 1.18 2024/08/21 14:58:14 florian Exp $ */ 2c04d2e36Snorby 3c04d2e36Snorby /* 4c04d2e36Snorby * Copyright (c) 2006 Michele Marchetto <mydecay@openbeer.it> 5c04d2e36Snorby * 6c04d2e36Snorby * Permission to use, copy, modify, and distribute this software for any 7c04d2e36Snorby * purpose with or without fee is hereby granted, provided that the above 8c04d2e36Snorby * copyright notice and this permission notice appear in all copies. 9c04d2e36Snorby * 10c04d2e36Snorby * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11c04d2e36Snorby * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12c04d2e36Snorby * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13c04d2e36Snorby * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14c04d2e36Snorby * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15c04d2e36Snorby * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16c04d2e36Snorby * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17c04d2e36Snorby */ 18c04d2e36Snorby 19c04d2e36Snorby #include <sys/types.h> 20c04d2e36Snorby #include <sys/socket.h> 21c04d2e36Snorby #include <netinet/in.h> 22c04d2e36Snorby #include <netinet/ip.h> 23c04d2e36Snorby #include <arpa/inet.h> 24c04d2e36Snorby #include <netinet/udp.h> 25c04d2e36Snorby 26c04d2e36Snorby #include <stdlib.h> 27c04d2e36Snorby #include <string.h> 28c04d2e36Snorby 29c04d2e36Snorby #include "ripd.h" 30c04d2e36Snorby #include "rip.h" 31c04d2e36Snorby #include "ripe.h" 32c04d2e36Snorby #include "log.h" 33c04d2e36Snorby 34c04d2e36Snorby extern struct ripd_conf *oeconf; 35c04d2e36Snorby 36c04d2e36Snorby void delete_entry(struct rip_route *); 37c04d2e36Snorby 38c04d2e36Snorby /* timers */ 39c04d2e36Snorby void 40c04d2e36Snorby report_timer(int fd, short event, void *arg) 41c04d2e36Snorby { 42c04d2e36Snorby struct timeval tv; 43c04d2e36Snorby 44c04d2e36Snorby ripe_imsg_compose_rde(IMSG_FULL_RESPONSE, 0, 0, NULL, 0); 45c04d2e36Snorby 46c04d2e36Snorby /* restart report timer */ 47c04d2e36Snorby timerclear(&tv); 4866ad965fSdjm tv.tv_sec = KEEPALIVE + arc4random_uniform(OFFSET); 49c04d2e36Snorby evtimer_add(&oeconf->report_timer, &tv); 50c04d2e36Snorby } 51c04d2e36Snorby 52c04d2e36Snorby int 53c04d2e36Snorby start_report_timer(void) 54c04d2e36Snorby { 55c04d2e36Snorby struct timeval tv; 56c04d2e36Snorby 57c04d2e36Snorby timerclear(&tv); 5866ad965fSdjm tv.tv_sec = KEEPALIVE + arc4random_uniform(OFFSET); 59c04d2e36Snorby return (evtimer_add(&oeconf->report_timer, &tv)); 60c04d2e36Snorby } 61c04d2e36Snorby 6231b802a2Smichele /* list handlers */ 63c04d2e36Snorby void 64c04d2e36Snorby add_entry(struct packet_head *r_list, struct rip_route *rr) 65c04d2e36Snorby { 66c04d2e36Snorby struct packet_entry *re; 67c04d2e36Snorby 68c04d2e36Snorby if (rr == NULL) 69c04d2e36Snorby fatalx("add_entry: no route report"); 70c04d2e36Snorby 71c04d2e36Snorby if ((re = calloc(1, sizeof(*re))) == NULL) 72a59fb23fSremi fatal("add_entry"); 73c04d2e36Snorby 74c04d2e36Snorby TAILQ_INSERT_TAIL(r_list, re, entry); 75c04d2e36Snorby re->rr = rr; 76c04d2e36Snorby rr->refcount++; 77c04d2e36Snorby } 78c04d2e36Snorby 79c04d2e36Snorby void 80c04d2e36Snorby delete_entry(struct rip_route *rr) 81c04d2e36Snorby { 82c04d2e36Snorby if (--rr->refcount == 0) 83c04d2e36Snorby free(rr); 84c04d2e36Snorby } 85c04d2e36Snorby 8631b802a2Smichele void 8731b802a2Smichele clear_list(struct packet_head *r_list) 8831b802a2Smichele { 8931b802a2Smichele struct packet_entry *re; 9031b802a2Smichele 9131b802a2Smichele while ((re = TAILQ_FIRST(r_list)) != NULL) { 9231b802a2Smichele TAILQ_REMOVE(r_list, re, entry); 9331b802a2Smichele delete_entry(re->rr); 9431b802a2Smichele free(re); 9531b802a2Smichele } 9631b802a2Smichele } 9731b802a2Smichele 9831b802a2Smichele /* communications */ 99c04d2e36Snorby int 100c04d2e36Snorby send_triggered_update(struct iface *iface, struct rip_route *rr) 101c04d2e36Snorby { 102c04d2e36Snorby struct sockaddr_in dst; 103e39620e5Snicm struct ibuf *buf; 104c04d2e36Snorby u_int16_t afi, route_tag; 105c04d2e36Snorby u_int32_t address, netmask, nexthop, metric; 106c04d2e36Snorby 10744f2793aSremi if (iface->passive) 10844f2793aSremi return (0); 10944f2793aSremi 110*28b8bcf0Sflorian inet_pton(AF_INET, ALL_RIP_ROUTERS, &dst.sin_addr); 111c04d2e36Snorby 112c04d2e36Snorby dst.sin_port = htons(RIP_PORT); 113c04d2e36Snorby dst.sin_family = AF_INET; 114c04d2e36Snorby dst.sin_len = sizeof(struct sockaddr_in); 115c04d2e36Snorby 116e39620e5Snicm if ((buf = ibuf_open(iface->mtu - sizeof(struct ip) - 117726964a1Sderaadt sizeof(struct udphdr))) == NULL) 118c04d2e36Snorby fatal("send_triggered_update"); 119c04d2e36Snorby 120c04d2e36Snorby gen_rip_hdr(buf, COMMAND_RESPONSE); 121c04d2e36Snorby 122c04d2e36Snorby afi = htons(AF_INET); 123c04d2e36Snorby route_tag = 0; 124c04d2e36Snorby 125c04d2e36Snorby address = rr->address.s_addr; 126c04d2e36Snorby netmask = rr->mask.s_addr; 127c04d2e36Snorby nexthop = rr->nexthop.s_addr; 128c04d2e36Snorby metric = htonl(rr->metric); 129c04d2e36Snorby 130e39620e5Snicm ibuf_add(buf, &afi, sizeof(afi)); 131e39620e5Snicm ibuf_add(buf, &route_tag, sizeof(route_tag)); 132e39620e5Snicm ibuf_add(buf, &address, sizeof(address)); 133e39620e5Snicm ibuf_add(buf, &netmask, sizeof(netmask)); 134e39620e5Snicm ibuf_add(buf, &nexthop, sizeof(nexthop)); 135e39620e5Snicm ibuf_add(buf, &metric, sizeof(metric)); 136c04d2e36Snorby 137aa2e6c71Sclaudio send_packet(iface, ibuf_data(buf), ibuf_size(buf), &dst); 138e39620e5Snicm ibuf_free(buf); 139c04d2e36Snorby 140c04d2e36Snorby return (0); 141c04d2e36Snorby } 142c04d2e36Snorby 143c04d2e36Snorby int 144c04d2e36Snorby send_request(struct packet_head *r_list, struct iface *i, struct nbr *nbr) 145c04d2e36Snorby { 146e39620e5Snicm struct ibuf *buf; 147c04d2e36Snorby struct iface *iface; 148c04d2e36Snorby struct packet_entry *entry; 149c04d2e36Snorby struct sockaddr_in dst; 150c04d2e36Snorby u_int8_t nentries; 151c04d2e36Snorby u_int8_t single_entry = 0; 152c04d2e36Snorby u_int32_t address, netmask, nexthop; 153c04d2e36Snorby u_int16_t port, afi, route_tag; 154c04d2e36Snorby u_int32_t metric; 155c04d2e36Snorby 156c04d2e36Snorby if (i == NULL) { 157c04d2e36Snorby /* directly to a nbr */ 158c04d2e36Snorby iface = nbr->iface; 159c04d2e36Snorby dst.sin_addr = nbr->addr; 160c04d2e36Snorby port = htons(nbr->port); 161c04d2e36Snorby } else { 162c04d2e36Snorby /* multicast on interface */ 163c04d2e36Snorby iface = i; 164*28b8bcf0Sflorian inet_pton(AF_INET, ALL_RIP_ROUTERS, &dst.sin_addr); 165c04d2e36Snorby port = htons(RIP_PORT); 166c04d2e36Snorby } 167c04d2e36Snorby 16844f2793aSremi if (iface->passive) { 16944f2793aSremi clear_list(r_list); 17044f2793aSremi return (0); 17144f2793aSremi } 17244f2793aSremi 173c04d2e36Snorby dst.sin_port = port; 174c04d2e36Snorby dst.sin_family = AF_INET; 175c04d2e36Snorby dst.sin_len = sizeof(struct sockaddr_in); 176c04d2e36Snorby 177c04d2e36Snorby while (!TAILQ_EMPTY(r_list)) { 178e39620e5Snicm if ((buf = ibuf_open(iface->mtu - sizeof(struct ip) - 179726964a1Sderaadt sizeof(struct udphdr))) == NULL) 180c04d2e36Snorby fatal("send_request"); 181c04d2e36Snorby 182c04d2e36Snorby gen_rip_hdr(buf, COMMAND_REQUEST); 183c04d2e36Snorby 184c04d2e36Snorby route_tag = 0; 185c04d2e36Snorby nentries = 0; 186c04d2e36Snorby 187c04d2e36Snorby if (TAILQ_FIRST(r_list) == TAILQ_LAST(r_list, packet_head)) 188c04d2e36Snorby single_entry = 1; 189c04d2e36Snorby while (((entry = TAILQ_FIRST(r_list)) != NULL) && 190e3be6b29Smichele nentries < MAX_RIP_ENTRIES) { 191c04d2e36Snorby afi = htons(AF_INET); 192c04d2e36Snorby 193c04d2e36Snorby address = entry->rr->address.s_addr; 194c04d2e36Snorby netmask = entry->rr->mask.s_addr; 195c04d2e36Snorby nexthop = entry->rr->nexthop.s_addr; 196c04d2e36Snorby metric = htonl(entry->rr->metric); 197c04d2e36Snorby 198c04d2e36Snorby if (metric == htonl(INFINITY) && single_entry) 199c04d2e36Snorby afi = AF_UNSPEC; 200c04d2e36Snorby 201e39620e5Snicm ibuf_add(buf, &afi, sizeof(afi)); 202e39620e5Snicm ibuf_add(buf, &route_tag, sizeof(route_tag)); 203e39620e5Snicm ibuf_add(buf, &address, sizeof(address)); 204e39620e5Snicm ibuf_add(buf, &netmask, sizeof(netmask)); 205e39620e5Snicm ibuf_add(buf, &nexthop, sizeof(nexthop)); 206e39620e5Snicm ibuf_add(buf, &metric, sizeof(metric)); 207a9cd8339Sremi nentries++; 208c04d2e36Snorby 209c04d2e36Snorby TAILQ_REMOVE(r_list, entry, entry); 210c04d2e36Snorby delete_entry(entry->rr); 211c04d2e36Snorby free(entry); 212c04d2e36Snorby } 213aa2e6c71Sclaudio send_packet(iface, ibuf_data(buf), ibuf_size(buf), &dst); 214e39620e5Snicm ibuf_free(buf); 215c04d2e36Snorby } 216c04d2e36Snorby 217c04d2e36Snorby return (0); 218c04d2e36Snorby } 219c04d2e36Snorby 220c04d2e36Snorby int 221c04d2e36Snorby send_response(struct packet_head *r_list, struct iface *i, struct nbr *nbr) 222c04d2e36Snorby { 223e39620e5Snicm struct ibuf *buf; 224c04d2e36Snorby struct iface *iface; 225c04d2e36Snorby struct packet_entry *entry; 226c04d2e36Snorby struct sockaddr_in dst; 227c04d2e36Snorby u_int8_t nentries; 228c04d2e36Snorby u_int16_t port, afi, route_tag; 229c04d2e36Snorby u_int32_t address, netmask, nexthop; 230c04d2e36Snorby u_int32_t metric; 231c04d2e36Snorby 232c04d2e36Snorby if (i == NULL) { 233c04d2e36Snorby /* directly to a nbr */ 234c04d2e36Snorby iface = nbr->iface; 235c04d2e36Snorby dst.sin_addr = nbr->addr; 236c04d2e36Snorby port = htons(nbr->port); 237c04d2e36Snorby } else { 238c04d2e36Snorby /* multicast on interface */ 239c04d2e36Snorby iface = i; 240*28b8bcf0Sflorian inet_pton(AF_INET, ALL_RIP_ROUTERS, &dst.sin_addr); 241c04d2e36Snorby port = htons(RIP_PORT); 242c04d2e36Snorby } 243c04d2e36Snorby 24444f2793aSremi if (iface->passive) { 24544f2793aSremi clear_list(r_list); 24644f2793aSremi return (0); 24744f2793aSremi } 24844f2793aSremi 249c04d2e36Snorby dst.sin_port = port; 250c04d2e36Snorby dst.sin_family = AF_INET; 251c04d2e36Snorby dst.sin_len = sizeof(struct sockaddr_in); 252c04d2e36Snorby 253c04d2e36Snorby while (!TAILQ_EMPTY(r_list)) { 254e39620e5Snicm if ((buf = ibuf_open(iface->mtu - sizeof(struct ip) - 255726964a1Sderaadt sizeof(struct udphdr))) == NULL) 256c04d2e36Snorby fatal("send_response"); 257c04d2e36Snorby 258c04d2e36Snorby gen_rip_hdr(buf, COMMAND_RESPONSE); 259c04d2e36Snorby 260c04d2e36Snorby afi = htons(AF_INET); 261c04d2e36Snorby route_tag = 0; 262c04d2e36Snorby nentries = 0; 263c04d2e36Snorby 264c04d2e36Snorby if (iface->auth_type != AUTH_NONE) { 265badfb5d1Smichele if (auth_gen(buf, iface) == -1) { 266e39620e5Snicm ibuf_free(buf); 267c04d2e36Snorby return (-1); 268badfb5d1Smichele } 269c04d2e36Snorby nentries++; 270c04d2e36Snorby } 271c04d2e36Snorby 272c04d2e36Snorby while ((entry = TAILQ_FIRST(r_list)) != NULL && 27314afd964Smichele nentries < MAX_RIP_ENTRIES) { 274c04d2e36Snorby address = entry->rr->address.s_addr; 275c04d2e36Snorby netmask = entry->rr->mask.s_addr; 276c04d2e36Snorby nexthop = entry->rr->nexthop.s_addr; 277c04d2e36Snorby metric = htonl(entry->rr->metric); 278c04d2e36Snorby 279c04d2e36Snorby if (entry->rr->ifindex == iface->ifindex) { 280c04d2e36Snorby if (oeconf->options & OPT_SPLIT_HORIZON) 281c04d2e36Snorby goto free; 282c04d2e36Snorby else if (oeconf->options & OPT_SPLIT_POISONED) 283c04d2e36Snorby metric = htonl(INFINITY); 284c04d2e36Snorby } 285c04d2e36Snorby 28614afd964Smichele /* If the nexthop is not reachable through the 28714afd964Smichele * outgoing interface set it to INADDR_ANY */ 28814afd964Smichele if ((nexthop & iface->mask.s_addr) != 28914afd964Smichele (iface->addr.s_addr & iface->mask.s_addr)) 29014afd964Smichele nexthop = INADDR_ANY; 29114afd964Smichele 292e39620e5Snicm ibuf_add(buf, &afi, sizeof(afi)); 293e39620e5Snicm ibuf_add(buf, &route_tag, sizeof(route_tag)); 294e39620e5Snicm ibuf_add(buf, &address, sizeof(address)); 295e39620e5Snicm ibuf_add(buf, &netmask, sizeof(netmask)); 296e39620e5Snicm ibuf_add(buf, &nexthop, sizeof(nexthop)); 297e39620e5Snicm ibuf_add(buf, &metric, sizeof(metric)); 298a9cd8339Sremi nentries++; 299c04d2e36Snorby free: 300c04d2e36Snorby TAILQ_REMOVE(r_list, entry, entry); 301c04d2e36Snorby delete_entry(entry->rr); 302c04d2e36Snorby free(entry); 303c04d2e36Snorby } 304c04d2e36Snorby 305c04d2e36Snorby if (iface->auth_type == AUTH_CRYPT) 306c04d2e36Snorby auth_add_trailer(buf, iface); 307c04d2e36Snorby 308aa2e6c71Sclaudio send_packet(iface, ibuf_data(buf), ibuf_size(buf), &dst); 309e39620e5Snicm ibuf_free(buf); 310c04d2e36Snorby } 311c04d2e36Snorby 312c04d2e36Snorby return (0); 313c04d2e36Snorby } 314c04d2e36Snorby 315c04d2e36Snorby void 31687feb355Sclaudio recv_request(struct iface *i, struct nbr *nbr, u_int8_t *buf, u_int16_t len) 317c04d2e36Snorby { 318c04d2e36Snorby struct rip_entry *e; 319c04d2e36Snorby struct rip_route rr; 320c04d2e36Snorby int l = len; 321c04d2e36Snorby 322c04d2e36Snorby bzero(&rr, sizeof(rr)); 323c04d2e36Snorby 324c04d2e36Snorby if (len < RIP_ENTRY_LEN) { 325c04d2e36Snorby log_debug("recv_request: bad packet size, interface %s", 326c04d2e36Snorby i->name); 327c04d2e36Snorby return; 328c04d2e36Snorby } 329c04d2e36Snorby 330c04d2e36Snorby /* 331c04d2e36Snorby * XXX is it guaranteed that bus is properly aligned. 332b8bbf4e7Sdavid * If not this will bomb on strict alignment archs. 333c04d2e36Snorby * */ 334c04d2e36Snorby e = (struct rip_entry *)buf; 335c04d2e36Snorby 336c04d2e36Snorby if (len > RIP_ENTRY_LEN * MAX_RIP_ENTRIES) { 337c04d2e36Snorby log_debug("recv_request: packet too long\n"); 338c04d2e36Snorby return; 339c04d2e36Snorby } 340c04d2e36Snorby 341c04d2e36Snorby l -= RIP_ENTRY_LEN; 342c04d2e36Snorby 343c04d2e36Snorby /* 344c04d2e36Snorby * If there is exactly one entry in the request, and it has 345c04d2e36Snorby * an address family identifier of zero and a metric of 346c04d2e36Snorby * infinity (i.e., 16), then this is a request to send the 347c04d2e36Snorby * entire routing table. 348c04d2e36Snorby */ 349c04d2e36Snorby if (e->AFI == 0 && e->metric == ntohl(INFINITY) && l == 0) { 350c04d2e36Snorby ripe_imsg_compose_rde(IMSG_FULL_RESPONSE, nbr->peerid, 351c04d2e36Snorby 0, NULL, 0); 352c04d2e36Snorby return; 353c04d2e36Snorby } 354c04d2e36Snorby 355c04d2e36Snorby for ( ; l >= 0; l -= RIP_ENTRY_LEN) { 356c04d2e36Snorby if (e->AFI != AF_INET) { 357c04d2e36Snorby log_debug("recv_request: AFI %d not supported\n", 358c04d2e36Snorby e->AFI); 359c04d2e36Snorby return; 360c04d2e36Snorby } 361c04d2e36Snorby rr.address.s_addr = e->address; 362c04d2e36Snorby rr.mask.s_addr = e->mask; 363c04d2e36Snorby rr.nexthop.s_addr = e->nexthop; 364c04d2e36Snorby rr.metric = e->metric; 365c04d2e36Snorby rr.ifindex = i->ifindex; 366c04d2e36Snorby 367c04d2e36Snorby ripe_imsg_compose_rde(IMSG_ROUTE_REQUEST, nbr->peerid, 36887feb355Sclaudio 0, &rr, sizeof(rr)); 369c04d2e36Snorby 370c04d2e36Snorby e++; 371c04d2e36Snorby } 372c04d2e36Snorby 373c04d2e36Snorby ripe_imsg_compose_rde(IMSG_ROUTE_REQUEST_END, nbr->peerid, 374c04d2e36Snorby 0, NULL, 0); 375c04d2e36Snorby } 376c04d2e36Snorby 377c04d2e36Snorby void 37887feb355Sclaudio recv_response(struct iface *i, struct nbr *nbr, u_int8_t *buf, u_int16_t len) 379c04d2e36Snorby { 380c04d2e36Snorby struct rip_route r; 381c04d2e36Snorby struct rip_entry *e; 382c04d2e36Snorby int l; 383c04d2e36Snorby 384c04d2e36Snorby if (len < RIP_ENTRY_LEN) { 385c04d2e36Snorby log_debug("recv_response: bad packet size, interface %s", 386c04d2e36Snorby i->name); 387c04d2e36Snorby return; 388c04d2e36Snorby } 389c04d2e36Snorby 390c04d2e36Snorby /* We must double check the length, because the only entry 391c04d2e36Snorby * can be stripped off by authentication code 392c04d2e36Snorby */ 393c04d2e36Snorby if (len < RIP_ENTRY_LEN) { 394c04d2e36Snorby /* If there are no entries, our work is finished here */ 395c04d2e36Snorby return; 396c04d2e36Snorby } 397c04d2e36Snorby 398c04d2e36Snorby /* XXX again */ 399c04d2e36Snorby e = (struct rip_entry *)buf; 400c04d2e36Snorby 401c04d2e36Snorby if (len > RIP_ENTRY_LEN * MAX_RIP_ENTRIES) { 402c04d2e36Snorby log_debug("recv_response: packet too long\n"); 403c04d2e36Snorby return; 404c04d2e36Snorby } 405c04d2e36Snorby 406c04d2e36Snorby l = len - sizeof(*e); 407c04d2e36Snorby 408c04d2e36Snorby for ( ; l >= 0; l -= RIP_ENTRY_LEN) { 409c04d2e36Snorby if (ntohs(e->AFI) != AF_INET) { 410c04d2e36Snorby log_debug("recv_response: AFI %d not supported\n", 411c04d2e36Snorby e->AFI); 412c04d2e36Snorby return; 413c04d2e36Snorby } 414c04d2e36Snorby 415c04d2e36Snorby r.address.s_addr = e->address; 416c04d2e36Snorby r.mask.s_addr = e->mask; 417c04d2e36Snorby 418c04d2e36Snorby if (e->nexthop == INADDR_ANY || 419c04d2e36Snorby ((i->addr.s_addr & i->mask.s_addr) != 420c04d2e36Snorby (e->nexthop & i->mask.s_addr))) 421c04d2e36Snorby r.nexthop.s_addr = nbr->addr.s_addr; 422c04d2e36Snorby else 423c04d2e36Snorby r.nexthop.s_addr = e->nexthop; 424c04d2e36Snorby 425c04d2e36Snorby r.metric = ntohl(e->metric); 426c04d2e36Snorby r.ifindex = i->ifindex; 427c04d2e36Snorby 42887feb355Sclaudio ripe_imsg_compose_rde(IMSG_ROUTE_FEED, 0, 0, &r, sizeof(r)); 429c04d2e36Snorby 430c04d2e36Snorby e++; 431c04d2e36Snorby } 432c04d2e36Snorby } 433