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