1 /* $OpenBSD: address.c,v 1.30 2016/09/03 16:07:08 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 *, uint16_t, int, 32 struct if_addr_head *, unsigned int); 33 static void address_list_add(struct if_addr_head *, struct if_addr *); 34 static void address_list_clr(struct if_addr_head *); 35 36 static void 37 send_address(struct nbr *nbr, int af, struct if_addr_head *addr_list, 38 unsigned int addr_count, int withdraw) 39 { 40 struct ibuf *buf; 41 uint16_t msg_type; 42 uint8_t addr_size; 43 struct if_addr *if_addr; 44 uint16_t size; 45 unsigned int tlv_addr_count = 0; 46 int err = 0; 47 48 /* nothing to send */ 49 if (LIST_EMPTY(addr_list)) 50 return; 51 52 if (!withdraw) 53 msg_type = MSG_TYPE_ADDR; 54 else 55 msg_type = MSG_TYPE_ADDRWITHDRAW; 56 57 switch (af) { 58 case AF_INET: 59 addr_size = sizeof(struct in_addr); 60 break; 61 case AF_INET6: 62 addr_size = sizeof(struct in6_addr); 63 break; 64 default: 65 fatalx("send_address: unknown af"); 66 } 67 68 while ((if_addr = LIST_FIRST(addr_list)) != NULL) { 69 /* 70 * Send as many addresses as possible - respect the session's 71 * negotiated maximum pdu length. 72 */ 73 size = LDP_HDR_SIZE + LDP_MSG_SIZE + ADDR_LIST_SIZE; 74 if (size + addr_count * addr_size <= nbr->max_pdu_len) 75 tlv_addr_count = addr_count; 76 else 77 tlv_addr_count = (nbr->max_pdu_len - size) / addr_size; 78 size += tlv_addr_count * addr_size; 79 addr_count -= tlv_addr_count; 80 81 if ((buf = ibuf_open(size)) == NULL) 82 fatal(__func__); 83 84 err |= gen_ldp_hdr(buf, size); 85 size -= LDP_HDR_SIZE; 86 err |= gen_msg_hdr(buf, msg_type, size); 87 size -= LDP_MSG_SIZE; 88 err |= gen_address_list_tlv(buf, size, af, addr_list, 89 tlv_addr_count); 90 if (err) { 91 address_list_clr(addr_list); 92 ibuf_free(buf); 93 return; 94 } 95 96 while ((if_addr = LIST_FIRST(addr_list)) != NULL) { 97 log_debug("msg-out: %s: lsr-id %s, address %s", 98 msg_name(msg_type), inet_ntoa(nbr->id), 99 log_addr(af, &if_addr->addr)); 100 101 LIST_REMOVE(if_addr, entry); 102 free(if_addr); 103 if (--tlv_addr_count == 0) 104 break; 105 } 106 107 evbuf_enqueue(&nbr->tcp->wbuf, buf); 108 } 109 110 nbr_fsm(nbr, NBR_EVT_PDU_SENT); 111 } 112 113 void 114 send_address_single(struct nbr *nbr, struct if_addr *if_addr, int withdraw) 115 { 116 struct if_addr_head addr_list; 117 118 LIST_INIT(&addr_list); 119 address_list_add(&addr_list, if_addr); 120 send_address(nbr, if_addr->af, &addr_list, 1, withdraw); 121 } 122 123 void 124 send_address_all(struct nbr *nbr, int af) 125 { 126 struct if_addr_head addr_list; 127 struct if_addr *if_addr; 128 unsigned int addr_count = 0; 129 130 LIST_INIT(&addr_list); 131 LIST_FOREACH(if_addr, &global.addr_list, entry) { 132 if (if_addr->af != af) 133 continue; 134 135 address_list_add(&addr_list, if_addr); 136 addr_count++; 137 } 138 139 send_address(nbr, af, &addr_list, addr_count, 0); 140 } 141 142 int 143 recv_address(struct nbr *nbr, char *buf, uint16_t len) 144 { 145 struct ldp_msg msg; 146 uint16_t msg_type; 147 struct address_list_tlv alt; 148 enum imsg_type type; 149 struct lde_addr lde_addr; 150 151 memcpy(&msg, buf, sizeof(msg)); 152 buf += LDP_MSG_SIZE; 153 len -= LDP_MSG_SIZE; 154 155 /* Address List TLV */ 156 if (len < ADDR_LIST_SIZE) { 157 session_shutdown(nbr, S_BAD_MSG_LEN, msg.id, msg.type); 158 return (-1); 159 } 160 161 memcpy(&alt, buf, sizeof(alt)); 162 if (ntohs(alt.length) != len - TLV_HDR_SIZE) { 163 session_shutdown(nbr, S_BAD_TLV_LEN, msg.id, msg.type); 164 return (-1); 165 } 166 if (ntohs(alt.type) != TLV_TYPE_ADDRLIST) { 167 session_shutdown(nbr, S_UNKNOWN_TLV, msg.id, msg.type); 168 return (-1); 169 } 170 switch (ntohs(alt.family)) { 171 case AF_IPV4: 172 if (!nbr->v4_enabled) 173 /* just ignore the message */ 174 return (0); 175 break; 176 case AF_IPV6: 177 if (!nbr->v6_enabled) 178 /* just ignore the message */ 179 return (0); 180 break; 181 default: 182 send_notification_nbr(nbr, S_UNSUP_ADDR, msg.id, msg.type); 183 return (-1); 184 } 185 buf += sizeof(alt); 186 len -= sizeof(alt); 187 188 msg_type = ntohs(msg.type); 189 if (msg_type == MSG_TYPE_ADDR) 190 type = IMSG_ADDRESS_ADD; 191 else 192 type = IMSG_ADDRESS_DEL; 193 194 while (len > 0) { 195 switch (ntohs(alt.family)) { 196 case AF_IPV4: 197 if (len < sizeof(struct in_addr)) { 198 session_shutdown(nbr, S_BAD_TLV_LEN, msg.id, 199 msg.type); 200 return (-1); 201 } 202 203 memset(&lde_addr, 0, sizeof(lde_addr)); 204 lde_addr.af = AF_INET; 205 memcpy(&lde_addr.addr, buf, sizeof(struct in_addr)); 206 207 buf += sizeof(struct in_addr); 208 len -= sizeof(struct in_addr); 209 break; 210 case AF_IPV6: 211 if (len < sizeof(struct in6_addr)) { 212 session_shutdown(nbr, S_BAD_TLV_LEN, msg.id, 213 msg.type); 214 return (-1); 215 } 216 217 memset(&lde_addr, 0, sizeof(lde_addr)); 218 lde_addr.af = AF_INET6; 219 memcpy(&lde_addr.addr, buf, sizeof(struct in6_addr)); 220 221 buf += sizeof(struct in6_addr); 222 len -= sizeof(struct in6_addr); 223 break; 224 default: 225 fatalx("recv_address: unknown af"); 226 } 227 228 log_debug("msg-in: %s: lsr-id %s, address %s", 229 msg_name(msg_type), inet_ntoa(nbr->id), 230 log_addr(lde_addr.af, &lde_addr.addr)); 231 232 ldpe_imsg_compose_lde(type, nbr->peerid, 0, &lde_addr, 233 sizeof(lde_addr)); 234 } 235 236 return (0); 237 } 238 239 static int 240 gen_address_list_tlv(struct ibuf *buf, uint16_t size, int af, 241 struct if_addr_head *addr_list, unsigned int tlv_addr_count) 242 { 243 struct address_list_tlv alt; 244 uint16_t addr_size; 245 struct if_addr *if_addr; 246 int err = 0; 247 248 memset(&alt, 0, sizeof(alt)); 249 alt.type = TLV_TYPE_ADDRLIST; 250 alt.length = htons(size - TLV_HDR_SIZE); 251 252 switch (af) { 253 case AF_INET: 254 alt.family = htons(AF_IPV4); 255 addr_size = sizeof(struct in_addr); 256 break; 257 case AF_INET6: 258 alt.family = htons(AF_IPV6); 259 addr_size = sizeof(struct in6_addr); 260 break; 261 default: 262 fatalx("gen_address_list_tlv: unknown af"); 263 } 264 265 err |= ibuf_add(buf, &alt, sizeof(alt)); 266 LIST_FOREACH(if_addr, addr_list, entry) { 267 err |= ibuf_add(buf, &if_addr->addr, addr_size); 268 if (--tlv_addr_count == 0) 269 break; 270 } 271 272 return (err); 273 } 274 275 static void 276 address_list_add(struct if_addr_head *addr_list, struct if_addr *if_addr) 277 { 278 struct if_addr *new; 279 280 new = malloc(sizeof(*new)); 281 if (new == NULL) 282 fatal(__func__); 283 *new = *if_addr; 284 285 LIST_INSERT_HEAD(addr_list, new, entry); 286 } 287 288 static void 289 address_list_clr(struct if_addr_head *addr_list) 290 { 291 struct if_addr *if_addr; 292 293 while ((if_addr = LIST_FIRST(addr_list)) != NULL) { 294 LIST_REMOVE(if_addr, entry); 295 free(if_addr); 296 } 297 } 298