xref: /openbsd/usr.sbin/ldpd/address.c (revision 38e65088)
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
send_address(struct nbr * nbr,int af,struct if_addr_head * addr_list,unsigned int addr_count,int withdraw)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
send_address_single(struct nbr * nbr,struct if_addr * if_addr,int withdraw)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
send_address_all(struct nbr * nbr,int af)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
send_mac_withdrawal(struct nbr * nbr,struct map * fec,uint8_t * mac)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
recv_address(struct nbr * nbr,char * buf,uint16_t len)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
gen_address_list_tlv(struct ibuf * buf,int af,struct if_addr_head * addr_list,unsigned int tlv_addr_count)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
gen_mac_list_tlv(struct ibuf * buf,uint8_t * mac)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
address_list_add(struct if_addr_head * addr_list,struct if_addr * if_addr)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
address_list_clr(struct if_addr_head * addr_list)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
log_msg_address(int out,uint16_t msg_type,struct nbr * nbr,int af,union ldpd_addr * addr)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
log_msg_mac_withdrawal(int out,struct nbr * nbr,uint8_t * mac)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