xref: /openbsd/usr.sbin/ldpd/hello.c (revision cecf84d4)
1 /*	$OpenBSD: hello.c,v 1.25 2015/04/04 15:09:47 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 <sys/socket.h>
21 #include <sys/uio.h>
22 
23 #include <netinet/in.h>
24 #include <netinet/ip.h>
25 #include <arpa/inet.h>
26 #include <net/if_dl.h>
27 
28 #include <errno.h>
29 #include <event.h>
30 #include <stdlib.h>
31 #include <string.h>
32 
33 #include "ldpd.h"
34 #include "ldp.h"
35 #include "log.h"
36 #include "ldpe.h"
37 
38 extern struct ldpd_conf        *leconf;
39 
40 int	tlv_decode_hello_prms(char *, u_int16_t, u_int16_t *, u_int16_t *);
41 int	tlv_decode_opt_hello_prms(char *, u_int16_t, struct in_addr *,
42 	    u_int32_t *);
43 int	gen_hello_prms_tlv(struct ibuf *buf, u_int16_t, u_int16_t);
44 int	gen_opt4_hello_prms_tlv(struct ibuf *, u_int16_t, u_int32_t);
45 
46 int
47 send_hello(enum hello_type type, struct iface *iface, struct tnbr *tnbr)
48 {
49 	struct sockaddr_in	 dst;
50 	struct ibuf		*buf;
51 	u_int16_t		 size, holdtime = 0, flags = 0;
52 	int			 fd = 0;
53 
54 	dst.sin_port = htons(LDP_PORT);
55 	dst.sin_family = AF_INET;
56 	dst.sin_len = sizeof(struct sockaddr_in);
57 
58 	switch (type) {
59 	case HELLO_LINK:
60 		inet_aton(AllRouters, &dst.sin_addr);
61 		holdtime = iface->hello_holdtime;
62 		flags = 0;
63 		fd = iface->discovery_fd;
64 		break;
65 	case HELLO_TARGETED:
66 		dst.sin_addr.s_addr = tnbr->addr.s_addr;
67 		holdtime = tnbr->hello_holdtime;
68 		flags = TARGETED_HELLO;
69 		if (tnbr->flags & F_TNBR_CONFIGURED)
70 			flags |= REQUEST_TARG_HELLO;
71 		fd = tnbr->discovery_fd;
72 		break;
73 	}
74 
75 	if ((buf = ibuf_open(LDP_MAX_LEN)) == NULL)
76 		fatal("send_hello");
77 
78 	size = LDP_HDR_SIZE + sizeof(struct ldp_msg) +
79 	    sizeof(struct hello_prms_tlv) +
80 	    sizeof(struct hello_prms_opt4_tlv);
81 
82 	gen_ldp_hdr(buf, size);
83 
84 	size -= LDP_HDR_SIZE;
85 
86 	gen_msg_tlv(buf, MSG_TYPE_HELLO, size);
87 
88 	gen_hello_prms_tlv(buf, holdtime, flags);
89 	gen_opt4_hello_prms_tlv(buf, TLV_TYPE_IPV4TRANSADDR, ldpe_router_id());
90 
91 	send_packet(fd, iface, buf->buf, buf->wpos, &dst);
92 	ibuf_free(buf);
93 
94 	return (0);
95 }
96 
97 void
98 recv_hello(struct iface *iface, struct in_addr src, char *buf, u_int16_t len)
99 {
100 	struct ldp_msg		 hello;
101 	struct ldp_hdr		 ldp;
102 	struct adj		*adj;
103 	struct nbr		*nbr;
104 	struct in_addr		 lsr_id;
105 	struct in_addr		 transport_addr;
106 	u_int32_t		 conf_number;
107 	u_int16_t		 holdtime, flags;
108 	int			 r;
109 	struct hello_source	 source;
110 	struct tnbr		*tnbr = NULL;
111 
112 	bcopy(buf, &ldp, sizeof(ldp));
113 	buf += LDP_HDR_SIZE;
114 	len -= LDP_HDR_SIZE;
115 
116 	bcopy(buf, &hello, sizeof(hello));
117 	buf += sizeof(struct ldp_msg);
118 	len -= sizeof(struct ldp_msg);
119 
120 	lsr_id.s_addr = ldp.lsr_id;
121 
122 	r = tlv_decode_hello_prms(buf, len, &holdtime, &flags);
123 	if (r == -1) {
124 		log_debug("recv_hello: neighbor %s: failed to decode params",
125 		    inet_ntoa(lsr_id));
126 		return;
127 	}
128 
129 	bzero(&source, sizeof(source));
130 	if (flags & TARGETED_HELLO) {
131 		tnbr = tnbr_find(src);
132 		if (!tnbr) {
133 			if (!((flags & REQUEST_TARG_HELLO) &&
134 			    leconf->flags & LDPD_FLAG_TH_ACCEPT))
135 				return;
136 
137 			tnbr = tnbr_new(leconf, src, 0);
138 			if (!tnbr)
139 				return;
140 			tnbr_init(leconf, tnbr);
141 			LIST_INSERT_HEAD(&leconf->tnbr_list, tnbr, entry);
142 		}
143 		source.type = HELLO_TARGETED;
144 		source.target = tnbr;
145 	} else {
146 		if (ldp.lspace_id != 0) {
147 			log_debug("recv_hello: invalid label space "
148 			    "ID %u, interface %s", ldp.lspace_id,
149 			    iface->name);
150 			return;
151 		}
152 		source.type = HELLO_LINK;
153 		source.link.iface = iface;
154 		source.link.src_addr.s_addr = src.s_addr;
155 	}
156 
157 	buf += r;
158 	len -= r;
159 
160 	r = tlv_decode_opt_hello_prms(buf, len, &transport_addr,
161 	    &conf_number);
162 	if (r == -1) {
163 		log_debug("recv_hello: neighbor %s: failed to decode "
164 		    "optional params", inet_ntoa(lsr_id));
165 		return;
166 	}
167 	if (transport_addr.s_addr == INADDR_ANY)
168 		transport_addr.s_addr = src.s_addr;
169 
170 	if (r != len) {
171 		log_debug("recv_hello: neighbor %s: unexpected data in message",
172 		    inet_ntoa(lsr_id));
173 		return;
174 	}
175 
176 	nbr = nbr_find_ldpid(ldp.lsr_id);
177 	if (!nbr) {
178 		/* create new adjacency and new neighbor */
179 		nbr = nbr_new(lsr_id, transport_addr);
180 		adj = adj_new(nbr, &source, transport_addr);
181 	} else {
182 		adj = adj_find(nbr, &source);
183 		if (!adj) {
184 			/* create new adjacency for existing neighbor */
185 			adj = adj_new(nbr, &source, transport_addr);
186 
187 			if (nbr->addr.s_addr != transport_addr.s_addr)
188 				log_warnx("recv_hello: neighbor %s: multiple "
189 				    "adjacencies advertising different "
190 				    "transport addresses", inet_ntoa(lsr_id));
191 		}
192 	}
193 
194 	/* always update the holdtime to properly handle runtime changes */
195 	switch (source.type) {
196 	case HELLO_LINK:
197 		if (holdtime == 0)
198 			holdtime = LINK_DFLT_HOLDTIME;
199 
200 		adj->holdtime = min(iface->hello_holdtime, holdtime);
201 		break;
202 	case HELLO_TARGETED:
203 		if (holdtime == 0)
204 			holdtime = TARGETED_DFLT_HOLDTIME;
205 
206 		adj->holdtime = min(tnbr->hello_holdtime, holdtime);
207 	}
208 
209 	if (adj->holdtime != INFINITE_HOLDTIME)
210 		adj_start_itimer(adj);
211 	else
212 		adj_stop_itimer(adj);
213 
214 	if (nbr->state == NBR_STA_PRESENT && nbr_session_active_role(nbr) &&
215 	    !nbr_pending_connect(nbr) && !nbr_pending_idtimer(nbr))
216 		nbr_establish_connection(nbr);
217 }
218 
219 int
220 gen_hello_prms_tlv(struct ibuf *buf, u_int16_t holdtime, u_int16_t flags)
221 {
222 	struct hello_prms_tlv	parms;
223 
224 	bzero(&parms, sizeof(parms));
225 	parms.type = htons(TLV_TYPE_COMMONHELLO);
226 	parms.length = htons(sizeof(parms.holdtime) + sizeof(parms.flags));
227 	parms.holdtime = htons(holdtime);
228 	parms.flags = htons(flags);
229 
230 	return (ibuf_add(buf, &parms, sizeof(parms)));
231 }
232 
233 int
234 gen_opt4_hello_prms_tlv(struct ibuf *buf, u_int16_t type, u_int32_t value)
235 {
236 	struct hello_prms_opt4_tlv	parms;
237 
238 	bzero(&parms, sizeof(parms));
239 	parms.type = htons(type);
240 	parms.length = htons(4);
241 	parms.value = value;
242 
243 	return (ibuf_add(buf, &parms, sizeof(parms)));
244 }
245 
246 int
247 tlv_decode_hello_prms(char *buf, u_int16_t len, u_int16_t *holdtime,
248     u_int16_t *flags)
249 {
250 	struct hello_prms_tlv	tlv;
251 
252 	if (len < sizeof(tlv))
253 		return (-1);
254 	bcopy(buf, &tlv, sizeof(tlv));
255 
256 	if (ntohs(tlv.length) != sizeof(tlv) - TLV_HDR_LEN)
257 		return (-1);
258 
259 	if (tlv.type != htons(TLV_TYPE_COMMONHELLO))
260 		return (-1);
261 
262 	*holdtime = ntohs(tlv.holdtime);
263 	*flags = ntohs(tlv.flags);
264 
265 	return (sizeof(tlv));
266 }
267 
268 int
269 tlv_decode_opt_hello_prms(char *buf, u_int16_t len, struct in_addr *addr,
270     u_int32_t *conf_number)
271 {
272 	struct tlv	tlv;
273 	int		cons = 0;
274 	u_int16_t	tlv_len;
275 
276 	bzero(addr, sizeof(*addr));
277 	*conf_number = 0;
278 
279 	while (len >= sizeof(tlv)) {
280 		bcopy(buf, &tlv, sizeof(tlv));
281 		tlv_len = ntohs(tlv.length);
282 		switch (ntohs(tlv.type)) {
283 		case TLV_TYPE_IPV4TRANSADDR:
284 			if (tlv_len != sizeof(u_int32_t))
285 				return (-1);
286 			bcopy(buf + TLV_HDR_LEN, addr, sizeof(u_int32_t));
287 			break;
288 		case TLV_TYPE_CONFIG:
289 			if (tlv_len != sizeof(u_int32_t))
290 				return (-1);
291 			bcopy(buf + TLV_HDR_LEN, conf_number,
292 			    sizeof(u_int32_t));
293 			break;
294 		default:
295 			/* if unknown flag set, ignore TLV */
296 			if (!(ntohs(tlv.type) & UNKNOWN_FLAG))
297 				return (-1);
298 			break;
299 		}
300 		buf += TLV_HDR_LEN + tlv_len;
301 		len -= TLV_HDR_LEN + tlv_len;
302 		cons += TLV_HDR_LEN + tlv_len;
303 	}
304 
305 	return (cons);
306 }
307