1 /* $OpenBSD: hello.c,v 1.23 2020/07/15 14:47:41 denis Exp $ */ 2 3 /* 4 * Copyright (c) 2005 Claudio Jeker <claudio@openbsd.org> 5 * Copyright (c) 2004, 2005 Esben Norby <norby@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/types.h> 21 #include <sys/socket.h> 22 #include <netinet/in.h> 23 #include <arpa/inet.h> 24 #include <sys/time.h> 25 #include <stdlib.h> 26 #include <string.h> 27 #include <event.h> 28 29 #include "ospf6d.h" 30 #include "ospf6.h" 31 #include "log.h" 32 #include "ospfe.h" 33 34 /* hello packet handling */ 35 int 36 send_hello(struct iface *iface) 37 { 38 struct in6_addr dst; 39 struct hello_hdr hello; 40 struct nbr *nbr; 41 struct ibuf *buf; 42 43 switch (iface->type) { 44 case IF_TYPE_POINTOPOINT: 45 case IF_TYPE_BROADCAST: 46 inet_pton(AF_INET6, AllSPFRouters, &dst); 47 break; 48 case IF_TYPE_NBMA: 49 case IF_TYPE_POINTOMULTIPOINT: 50 log_debug("send_hello: type %s not supported, interface %s", 51 if_type_name(iface->type), iface->name); 52 return (-1); 53 case IF_TYPE_VIRTUALLINK: 54 dst = iface->dst; 55 break; 56 default: 57 fatalx("send_hello: unknown interface type"); 58 } 59 60 /* XXX IBUF_READ_SIZE */ 61 if ((buf = ibuf_dynamic(PKG_DEF_SIZE, IBUF_READ_SIZE)) == NULL) 62 fatal("send_hello"); 63 64 /* OSPF header */ 65 if (gen_ospf_hdr(buf, iface, PACKET_TYPE_HELLO)) 66 goto fail; 67 68 /* hello header */ 69 hello.iface_id = htonl(iface->ifindex); 70 LSA_24_SETHI(hello.opts, iface->priority); 71 LSA_24_SETLO(hello.opts, area_ospf_options(iface->area)); 72 hello.opts = htonl(hello.opts); 73 hello.hello_interval = htons(iface->hello_interval); 74 hello.rtr_dead_interval = htons(iface->dead_interval); 75 76 if (iface->dr) { 77 hello.d_rtr = iface->dr->id.s_addr; 78 iface->self->dr.s_addr = iface->dr->id.s_addr; 79 } else 80 hello.d_rtr = 0; 81 if (iface->bdr) { 82 hello.bd_rtr = iface->bdr->id.s_addr; 83 iface->self->bdr.s_addr = iface->bdr->id.s_addr; 84 } else 85 hello.bd_rtr = 0; 86 87 if (ibuf_add(buf, &hello, sizeof(hello))) 88 goto fail; 89 90 /* active neighbor(s) */ 91 LIST_FOREACH(nbr, &iface->nbr_list, entry) { 92 if ((nbr->state >= NBR_STA_INIT) && (nbr != iface->self)) 93 if (ibuf_add(buf, &nbr->id, sizeof(nbr->id))) 94 goto fail; 95 } 96 97 /* calculate checksum */ 98 if (upd_ospf_hdr(buf, iface)) 99 goto fail; 100 101 if (send_packet(iface, buf, &dst) == -1) 102 goto fail; 103 104 ibuf_free(buf); 105 return (0); 106 fail: 107 log_warn("send_hello"); 108 ibuf_free(buf); 109 return (-1); 110 } 111 112 void 113 recv_hello(struct iface *iface, struct in6_addr *src, u_int32_t rtr_id, 114 char *buf, u_int16_t len) 115 { 116 struct hello_hdr hello; 117 struct nbr *nbr = NULL, *dr; 118 u_int32_t nbr_id, opts; 119 int nbr_change = 0; 120 121 if (len < sizeof(hello) || (len & 0x03)) { 122 log_warnx("recv_hello: bad packet size, interface %s", 123 iface->name); 124 return; 125 } 126 127 memcpy(&hello, buf, sizeof(hello)); 128 buf += sizeof(hello); 129 len -= sizeof(hello); 130 131 if (ntohs(hello.hello_interval) != iface->hello_interval) { 132 log_warnx("recv_hello: invalid hello-interval %d, " 133 "interface %s", ntohs(hello.hello_interval), 134 iface->name); 135 return; 136 } 137 138 if (ntohs(hello.rtr_dead_interval) != iface->dead_interval) { 139 log_warnx("recv_hello: invalid router-dead-interval %d, " 140 "interface %s", ntohl(hello.rtr_dead_interval), 141 iface->name); 142 return; 143 } 144 145 opts = LSA_24_GETLO(ntohl(hello.opts)); 146 if ((opts & OSPF_OPTION_E && iface->area->stub) || 147 ((opts & OSPF_OPTION_E) == 0 && !iface->area->stub)) { 148 log_warnx("recv_hello: ExternalRoutingCapability mismatch, " 149 "interface %s", iface->name); 150 return; 151 } 152 153 /* match router-id */ 154 LIST_FOREACH(nbr, &iface->nbr_list, entry) { 155 if (nbr == iface->self) { 156 if (nbr->id.s_addr == rtr_id) { 157 log_warnx("recv_hello: Router-ID collision on " 158 "interface %s neighbor IP %s", iface->name, 159 log_in6addr(src)); 160 return; 161 } 162 continue; 163 } 164 if (nbr->id.s_addr == rtr_id) 165 break; 166 } 167 168 if (!nbr) { 169 nbr = nbr_new(rtr_id, iface, ntohl(hello.iface_id), 0, src); 170 /* set neighbor parameters */ 171 nbr->dr.s_addr = hello.d_rtr; 172 nbr->bdr.s_addr = hello.bd_rtr; 173 nbr->priority = LSA_24_GETHI(ntohl(hello.opts)); 174 /* XXX neighbor address shouldn't be stored on virtual links */ 175 nbr->addr = *src; 176 } 177 178 if (!IN6_ARE_ADDR_EQUAL(&nbr->addr, src)) { 179 log_warnx("%s: neighbor ID %s changed its address to %s", 180 __func__, inet_ntoa(nbr->id), log_in6addr(src)); 181 nbr->addr = *src; 182 } 183 184 nbr->options = opts; 185 186 nbr_fsm(nbr, NBR_EVT_HELLO_RCVD); 187 188 while (len >= sizeof(nbr_id)) { 189 memcpy(&nbr_id, buf, sizeof(nbr_id)); 190 if (nbr_id == ospfe_router_id()) { 191 /* seen myself */ 192 if (nbr->state & NBR_STA_PRELIM) { 193 nbr_fsm(nbr, NBR_EVT_2_WAY_RCVD); 194 nbr_change = 1; 195 } 196 break; 197 } 198 buf += sizeof(nbr_id); 199 len -= sizeof(nbr_id); 200 } 201 202 if (len == 0) { 203 nbr_fsm(nbr, NBR_EVT_1_WAY_RCVD); 204 /* set neighbor parameters */ 205 nbr->dr.s_addr = hello.d_rtr; 206 nbr->bdr.s_addr = hello.bd_rtr; 207 nbr->priority = LSA_24_GETHI(ntohl(hello.opts)); 208 return; 209 } 210 211 if (nbr->priority != LSA_24_GETHI(ntohl(hello.opts))) { 212 nbr->priority = LSA_24_GETHI(ntohl(hello.opts)); 213 nbr_change = 1; 214 } 215 216 if (iface->state & IF_STA_WAITING && 217 hello.d_rtr == nbr->id.s_addr && hello.bd_rtr == 0) 218 if_fsm(iface, IF_EVT_BACKUP_SEEN); 219 220 if (iface->state & IF_STA_WAITING && hello.bd_rtr == nbr->id.s_addr) { 221 /* 222 * In case we see the BDR make sure that the DR is around 223 * with a bidirectional (2_WAY or better) connection 224 */ 225 LIST_FOREACH(dr, &iface->nbr_list, entry) 226 if (hello.d_rtr == dr->id.s_addr && 227 dr->state & NBR_STA_BIDIR) 228 if_fsm(iface, IF_EVT_BACKUP_SEEN); 229 } 230 231 if ((nbr->id.s_addr == nbr->dr.s_addr && 232 nbr->id.s_addr != hello.d_rtr) || 233 (nbr->id.s_addr != nbr->dr.s_addr && 234 nbr->id.s_addr == hello.d_rtr)) 235 /* neighbor changed from or to DR */ 236 nbr_change = 1; 237 if ((nbr->id.s_addr == nbr->bdr.s_addr && 238 nbr->id.s_addr != hello.bd_rtr) || 239 (nbr->id.s_addr != nbr->bdr.s_addr && 240 nbr->id.s_addr == hello.bd_rtr)) 241 /* neighbor changed from or to BDR */ 242 nbr_change = 1; 243 244 nbr->dr.s_addr = hello.d_rtr; 245 nbr->bdr.s_addr = hello.bd_rtr; 246 247 if (nbr_change) 248 if_fsm(iface, IF_EVT_NBR_CHNG); 249 250 /* TODO NBMA needs some special handling */ 251 } 252