1 /* $OpenBSD: address.c,v 1.35 2017/03/04 00:21:48 renato Exp $ */ 2 3 /* 4 * Copyright (c) 2009 Michele Marchetto <michele@openbsd.org> 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 <arpa/inet.h> 21 #include <stdlib.h> 22 #include <string.h> 23 24 #include "ldpd.h" 25 #include "ldpe.h" 26 #include "lde.h" 27 #include "log.h" 28 29 static void send_address(struct nbr *, int, struct if_addr_head *, 30 unsigned int, int); 31 static int gen_address_list_tlv(struct ibuf *, int, struct if_addr_head *, 32 unsigned int); 33 static int gen_mac_list_tlv(struct ibuf *, uint8_t *); 34 static void address_list_add(struct if_addr_head *, struct if_addr *); 35 static void address_list_clr(struct if_addr_head *); 36 static void log_msg_address(int, uint16_t, struct nbr *, int, 37 union ldpd_addr *); 38 static void log_msg_mac_withdrawal(int, struct nbr *, uint8_t *); 39 40 static void 41 send_address(struct nbr *nbr, int af, struct if_addr_head *addr_list, 42 unsigned int addr_count, int withdraw) 43 { 44 struct ibuf *buf; 45 uint16_t msg_type; 46 uint8_t addr_size; 47 struct if_addr *if_addr; 48 uint16_t size; 49 unsigned int tlv_addr_count = 0; 50 int err = 0; 51 52 /* nothing to send */ 53 if (LIST_EMPTY(addr_list)) 54 return; 55 56 if (!withdraw) 57 msg_type = MSG_TYPE_ADDR; 58 else 59 msg_type = MSG_TYPE_ADDRWITHDRAW; 60 61 switch (af) { 62 case AF_INET: 63 addr_size = sizeof(struct in_addr); 64 break; 65 case AF_INET6: 66 addr_size = sizeof(struct in6_addr); 67 break; 68 default: 69 fatalx("send_address: unknown af"); 70 } 71 72 while ((if_addr = LIST_FIRST(addr_list)) != NULL) { 73 /* 74 * Send as many addresses as possible - respect the session's 75 * negotiated maximum pdu length. 76 */ 77 size = LDP_HDR_SIZE + LDP_MSG_SIZE + ADDR_LIST_SIZE; 78 if (size + addr_count * addr_size <= nbr->max_pdu_len) 79 tlv_addr_count = addr_count; 80 else 81 tlv_addr_count = (nbr->max_pdu_len - size) / addr_size; 82 size += tlv_addr_count * addr_size; 83 addr_count -= tlv_addr_count; 84 85 if ((buf = ibuf_open(size)) == NULL) 86 fatal(__func__); 87 88 err |= gen_ldp_hdr(buf, size); 89 size -= LDP_HDR_SIZE; 90 err |= gen_msg_hdr(buf, msg_type, size); 91 size -= LDP_MSG_SIZE; 92 err |= gen_address_list_tlv(buf, af, addr_list, tlv_addr_count); 93 if (err) { 94 address_list_clr(addr_list); 95 ibuf_free(buf); 96 return; 97 } 98 99 while ((if_addr = LIST_FIRST(addr_list)) != NULL) { 100 log_msg_address(1, msg_type, nbr, af, &if_addr->addr); 101 102 LIST_REMOVE(if_addr, entry); 103 free(if_addr); 104 if (--tlv_addr_count == 0) 105 break; 106 } 107 108 evbuf_enqueue(&nbr->tcp->wbuf, buf); 109 } 110 111 nbr_fsm(nbr, NBR_EVT_PDU_SENT); 112 } 113 114 void 115 send_address_single(struct nbr *nbr, struct if_addr *if_addr, int withdraw) 116 { 117 struct if_addr_head addr_list; 118 119 LIST_INIT(&addr_list); 120 address_list_add(&addr_list, if_addr); 121 send_address(nbr, if_addr->af, &addr_list, 1, withdraw); 122 } 123 124 void 125 send_address_all(struct nbr *nbr, int af) 126 { 127 struct if_addr_head addr_list; 128 struct if_addr *if_addr; 129 unsigned int addr_count = 0; 130 131 LIST_INIT(&addr_list); 132 LIST_FOREACH(if_addr, &global.addr_list, entry) { 133 if (if_addr->af != af) 134 continue; 135 136 address_list_add(&addr_list, if_addr); 137 addr_count++; 138 } 139 140 send_address(nbr, af, &addr_list, addr_count, 0); 141 } 142 143 void 144 send_mac_withdrawal(struct nbr *nbr, struct map *fec, uint8_t *mac) 145 { 146 struct ibuf *buf; 147 uint16_t size; 148 int err; 149 150 size = LDP_HDR_SIZE + LDP_MSG_SIZE + ADDR_LIST_SIZE + len_fec_tlv(fec) + 151 TLV_HDR_SIZE; 152 if (mac) 153 size += ETHER_ADDR_LEN; 154 155 if ((buf = ibuf_open(size)) == NULL) 156 fatal(__func__); 157 158 err = gen_ldp_hdr(buf, size); 159 size -= LDP_HDR_SIZE; 160 err |= gen_msg_hdr(buf, MSG_TYPE_ADDRWITHDRAW, size); 161 size -= LDP_MSG_SIZE; 162 err |= gen_address_list_tlv(buf, AF_INET, NULL, 0); 163 err |= gen_fec_tlv(buf, fec); 164 err |= gen_mac_list_tlv(buf, mac); 165 if (err) { 166 ibuf_free(buf); 167 return; 168 } 169 170 log_msg_mac_withdrawal(1, nbr, mac); 171 172 evbuf_enqueue(&nbr->tcp->wbuf, buf); 173 174 nbr_fsm(nbr, NBR_EVT_PDU_SENT); 175 } 176 177 int 178 recv_address(struct nbr *nbr, char *buf, uint16_t len) 179 { 180 struct ldp_msg msg; 181 uint16_t msg_type; 182 enum imsg_type type; 183 struct address_list_tlv alt; 184 uint16_t alt_len; 185 uint16_t alt_family; 186 struct lde_addr lde_addr; 187 188 memcpy(&msg, buf, sizeof(msg)); 189 msg_type = ntohs(msg.type); 190 switch (msg_type) { 191 case MSG_TYPE_ADDR: 192 type = IMSG_ADDRESS_ADD; 193 break; 194 case MSG_TYPE_ADDRWITHDRAW: 195 type = IMSG_ADDRESS_DEL; 196 break; 197 default: 198 fatalx("recv_address: unexpected msg type"); 199 } 200 buf += LDP_MSG_SIZE; 201 len -= LDP_MSG_SIZE; 202 203 /* Address List TLV */ 204 if (len < ADDR_LIST_SIZE) { 205 session_shutdown(nbr, S_BAD_MSG_LEN, msg.id, msg.type); 206 return (-1); 207 } 208 memcpy(&alt, buf, sizeof(alt)); 209 alt_len = ntohs(alt.length); 210 alt_family = ntohs(alt.family); 211 if (alt_len > len - TLV_HDR_SIZE) { 212 session_shutdown(nbr, S_BAD_TLV_LEN, msg.id, msg.type); 213 return (-1); 214 } 215 if (ntohs(alt.type) != TLV_TYPE_ADDRLIST) { 216 send_notification(nbr->tcp, S_MISS_MSG, msg.id, msg.type); 217 return (-1); 218 } 219 switch (alt_family) { 220 case AF_IPV4: 221 if (!nbr->v4_enabled) 222 /* just ignore the message */ 223 return (0); 224 break; 225 case AF_IPV6: 226 if (!nbr->v6_enabled) 227 /* just ignore the message */ 228 return (0); 229 break; 230 default: 231 send_notification(nbr->tcp, S_UNSUP_ADDR, msg.id, msg.type); 232 return (-1); 233 } 234 alt_len -= sizeof(alt.family); 235 buf += sizeof(alt); 236 len -= sizeof(alt); 237 238 /* Process all received addresses */ 239 while (alt_len > 0) { 240 switch (alt_family) { 241 case AF_IPV4: 242 if (alt_len < sizeof(struct in_addr)) { 243 session_shutdown(nbr, S_BAD_TLV_LEN, msg.id, 244 msg.type); 245 return (-1); 246 } 247 248 memset(&lde_addr, 0, sizeof(lde_addr)); 249 lde_addr.af = AF_INET; 250 memcpy(&lde_addr.addr, buf, sizeof(struct in_addr)); 251 252 buf += sizeof(struct in_addr); 253 len -= sizeof(struct in_addr); 254 alt_len -= sizeof(struct in_addr); 255 break; 256 case AF_IPV6: 257 if (alt_len < sizeof(struct in6_addr)) { 258 session_shutdown(nbr, S_BAD_TLV_LEN, msg.id, 259 msg.type); 260 return (-1); 261 } 262 263 memset(&lde_addr, 0, sizeof(lde_addr)); 264 lde_addr.af = AF_INET6; 265 memcpy(&lde_addr.addr, buf, sizeof(struct in6_addr)); 266 267 buf += sizeof(struct in6_addr); 268 len -= sizeof(struct in6_addr); 269 alt_len -= sizeof(struct in6_addr); 270 break; 271 default: 272 fatalx("recv_address: unknown af"); 273 } 274 275 log_msg_address(0, msg_type, nbr, lde_addr.af, &lde_addr.addr); 276 277 ldpe_imsg_compose_lde(type, nbr->peerid, 0, &lde_addr, 278 sizeof(lde_addr)); 279 } 280 281 /* Optional Parameters */ 282 while (len > 0) { 283 struct tlv tlv; 284 uint16_t tlv_type; 285 uint16_t tlv_len; 286 287 if (len < sizeof(tlv)) { 288 session_shutdown(nbr, S_BAD_TLV_LEN, msg.id, msg.type); 289 return (-1); 290 } 291 292 memcpy(&tlv, buf, TLV_HDR_SIZE); 293 tlv_type = ntohs(tlv.type); 294 tlv_len = ntohs(tlv.length); 295 if (tlv_len + TLV_HDR_SIZE > len) { 296 session_shutdown(nbr, S_BAD_TLV_LEN, msg.id, msg.type); 297 return (-1); 298 } 299 buf += TLV_HDR_SIZE; 300 len -= TLV_HDR_SIZE; 301 302 switch (tlv_type) { 303 default: 304 if (!(ntohs(tlv.type) & UNKNOWN_FLAG)) 305 send_notification_rtlvs(nbr, S_UNKNOWN_TLV, 306 msg.id, msg.type, tlv_type, tlv_len, buf); 307 /* ignore unknown tlv */ 308 break; 309 } 310 buf += tlv_len; 311 len -= tlv_len; 312 } 313 314 return (0); 315 } 316 317 static int 318 gen_address_list_tlv(struct ibuf *buf, int af, struct if_addr_head *addr_list, 319 unsigned int tlv_addr_count) 320 { 321 struct address_list_tlv alt; 322 uint16_t addr_size; 323 struct if_addr *if_addr; 324 int err = 0; 325 326 memset(&alt, 0, sizeof(alt)); 327 alt.type = htons(TLV_TYPE_ADDRLIST); 328 329 switch (af) { 330 case AF_INET: 331 alt.family = htons(AF_IPV4); 332 addr_size = sizeof(struct in_addr); 333 break; 334 case AF_INET6: 335 alt.family = htons(AF_IPV6); 336 addr_size = sizeof(struct in6_addr); 337 break; 338 default: 339 fatalx("gen_address_list_tlv: unknown af"); 340 } 341 alt.length = htons(sizeof(alt.family) + addr_size * tlv_addr_count); 342 343 err |= ibuf_add(buf, &alt, sizeof(alt)); 344 if (addr_list == NULL) 345 return (err); 346 347 LIST_FOREACH(if_addr, addr_list, entry) { 348 err |= ibuf_add(buf, &if_addr->addr, addr_size); 349 if (--tlv_addr_count == 0) 350 break; 351 } 352 353 return (err); 354 } 355 356 static int 357 gen_mac_list_tlv(struct ibuf *buf, uint8_t *mac) 358 { 359 struct tlv tlv; 360 int err; 361 362 memset(&tlv, 0, sizeof(tlv)); 363 tlv.type = htons(TLV_TYPE_MAC_LIST); 364 if (mac) 365 tlv.length = htons(ETHER_ADDR_LEN); 366 err = ibuf_add(buf, &tlv, sizeof(tlv)); 367 if (mac) 368 err |= ibuf_add(buf, mac, ETHER_ADDR_LEN); 369 370 return (err); 371 } 372 373 static void 374 address_list_add(struct if_addr_head *addr_list, struct if_addr *if_addr) 375 { 376 struct if_addr *new; 377 378 new = malloc(sizeof(*new)); 379 if (new == NULL) 380 fatal(__func__); 381 *new = *if_addr; 382 383 LIST_INSERT_HEAD(addr_list, new, entry); 384 } 385 386 static void 387 address_list_clr(struct if_addr_head *addr_list) 388 { 389 struct if_addr *if_addr; 390 391 while ((if_addr = LIST_FIRST(addr_list)) != NULL) { 392 LIST_REMOVE(if_addr, entry); 393 free(if_addr); 394 } 395 } 396 397 static void 398 log_msg_address(int out, uint16_t msg_type, struct nbr *nbr, int af, 399 union ldpd_addr *addr) 400 { 401 log_debug("msg-%s: %s: lsr-id %s, address %s", (out) ? "out" : "in", 402 msg_name(msg_type), inet_ntoa(nbr->id), log_addr(af, addr)); 403 } 404 405 static void 406 log_msg_mac_withdrawal(int out, struct nbr *nbr, uint8_t *mac) 407 { 408 log_debug("msg-%s: mac withdrawal: lsr-id %s, mac %s", 409 (out) ? "out" : "in", inet_ntoa(nbr->id), 410 (mac) ? ether_ntoa((struct ether_addr *)mac) : "wildcard"); 411 } 412