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