1 /* NHRP NHC nexthop server functions (registration)
2  * Copyright (c) 2014-2015 Timo Teräs
3  *
4  * This file is free software: you may copy, redistribute and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation, either version 2 of the License, or
7  * (at your option) any later version.
8  */
9 
10 #include "zebra.h"
11 #include "zbuf.h"
12 #include "memory.h"
13 #include "thread.h"
14 #include "nhrpd.h"
15 #include "nhrp_protocol.h"
16 
17 static int nhrp_nhs_resolve(struct thread *t);
18 static int nhrp_reg_send_req(struct thread *t);
19 
nhrp_reg_reply(struct nhrp_reqid * reqid,void * arg)20 static void nhrp_reg_reply(struct nhrp_reqid *reqid, void *arg)
21 {
22 	struct nhrp_packet_parser *p = arg;
23 	struct nhrp_registration *r = container_of(reqid, struct nhrp_registration, reqid);
24 	struct nhrp_nhs *nhs = r->nhs;
25 	struct interface *ifp = nhs->ifp;
26 	struct nhrp_interface *nifp = ifp->info;
27 	struct nhrp_extension_header *ext;
28 	struct nhrp_cie_header *cie;
29 	struct nhrp_cache *c;
30 	struct zbuf extpl;
31 	union sockunion cie_nbma, cie_proto, *proto;
32 	char buf[64];
33 	int ok = 0, holdtime;
34 
35 	nhrp_reqid_free(&nhrp_packet_reqid, &r->reqid);
36 
37 	if (p->hdr->type != NHRP_PACKET_REGISTRATION_REPLY) {
38 		debugf(NHRP_DEBUG_COMMON, "NHS: Registration failed");
39 		return;
40 	}
41 
42 	debugf(NHRP_DEBUG_COMMON, "NHS: Reg.reply received");
43 
44 	ok = 1;
45 	while ((cie = nhrp_cie_pull(&p->payload, p->hdr, &cie_nbma, &cie_proto)) != NULL) {
46 		proto = sockunion_family(&cie_proto) != AF_UNSPEC ? &cie_proto : &p->src_proto;
47 		debugf(NHRP_DEBUG_COMMON, "NHS: CIE registration: %s: %d",
48 			sockunion2str(proto, buf, sizeof(buf)),
49 			cie->code);
50 		if (!((cie->code == NHRP_CODE_SUCCESS) ||
51                       (cie->code == NHRP_CODE_ADMINISTRATIVELY_PROHIBITED && nhs->hub)))
52 			ok = 0;
53 	}
54 
55 	if (!ok)
56 		return;
57 
58 	/* Parse extensions */
59 	sockunion_family(&nifp->nat_nbma) = AF_UNSPEC;
60 	while ((ext = nhrp_ext_pull(&p->extensions, &extpl)) != NULL) {
61 		switch (htons(ext->type) & ~NHRP_EXTENSION_FLAG_COMPULSORY) {
62 		case NHRP_EXTENSION_NAT_ADDRESS:
63 			/* NHS adds second CIE if NAT is detected */
64 			if (nhrp_cie_pull(&extpl, p->hdr, &cie_nbma, &cie_proto) &&
65 			    nhrp_cie_pull(&extpl, p->hdr, &cie_nbma, &cie_proto)) {
66 				nifp->nat_nbma = cie_nbma;
67 				debugf(NHRP_DEBUG_IF, "%s: NAT detected, real NBMA address: %s",
68 					ifp->name, sockunion2str(&nifp->nbma, buf, sizeof(buf)));
69 			}
70 			break;
71 		}
72 	}
73 
74 	/* Success - schedule next registration, and route NHS */
75 	r->timeout = 2;
76 	holdtime = nifp->afi[nhs->afi].holdtime;
77 	THREAD_OFF(r->t_register);
78 
79 	/* RFC 2332 5.2.3 - Registration is recommend to be renewed
80 	 * every one third of holdtime */
81 	THREAD_TIMER_ON(master, r->t_register, nhrp_reg_send_req, r, holdtime / 3);
82 
83 	r->proto_addr = p->dst_proto;
84 	c = nhrp_cache_get(ifp, &p->dst_proto, 1);
85 	if (c) nhrp_cache_update_binding(c, NHRP_CACHE_NHS, holdtime, nhrp_peer_ref(r->peer), 0, NULL);
86 }
87 
nhrp_reg_timeout(struct thread * t)88 static int nhrp_reg_timeout(struct thread *t)
89 {
90 	struct nhrp_registration *r = THREAD_ARG(t);
91 	struct nhrp_cache *c;
92 
93 	r->t_register = NULL;
94 
95 	if (r->timeout >= 16 && sockunion_family(&r->proto_addr) != AF_UNSPEC) {
96 		nhrp_reqid_free(&nhrp_packet_reqid, &r->reqid);
97 		c = nhrp_cache_get(r->nhs->ifp, &r->proto_addr, 0);
98 		if (c) nhrp_cache_update_binding(c, NHRP_CACHE_NHS, -1, NULL, 0, NULL);
99 		sockunion_family(&r->proto_addr) = AF_UNSPEC;
100 	}
101 
102 	r->timeout <<= 1;
103 	if (r->timeout > 64) r->timeout = 2;
104 	THREAD_TIMER_MSEC_ON(master, r->t_register, nhrp_reg_send_req, r, 10);
105 
106 	return 0;
107 }
108 
nhrp_reg_peer_notify(struct notifier_block * n,unsigned long cmd)109 static void nhrp_reg_peer_notify(struct notifier_block *n, unsigned long cmd)
110 {
111 	struct nhrp_registration *r = container_of(n, struct nhrp_registration, peer_notifier);
112 	char buf[SU_ADDRSTRLEN];
113 
114 	switch (cmd) {
115 	case NOTIFY_PEER_UP:
116 	case NOTIFY_PEER_DOWN:
117 	case NOTIFY_PEER_IFCONFIG_CHANGED:
118 	case NOTIFY_PEER_MTU_CHANGED:
119 		debugf(NHRP_DEBUG_COMMON, "NHS: Flush timer for %s",
120 			sockunion2str(&r->peer->vc->remote.nbma, buf, sizeof buf));
121 		THREAD_TIMER_OFF(r->t_register);
122 		THREAD_TIMER_MSEC_ON(master, r->t_register, nhrp_reg_send_req, r, 10);
123 		break;
124 	}
125 }
126 
nhrp_reg_send_req(struct thread * t)127 static int nhrp_reg_send_req(struct thread *t)
128 {
129 	struct nhrp_registration *r = THREAD_ARG(t);
130 	struct nhrp_nhs *nhs = r->nhs;
131 	char buf1[SU_ADDRSTRLEN], buf2[SU_ADDRSTRLEN];
132 	struct interface *ifp = nhs->ifp;
133 	struct nhrp_interface *nifp = ifp->info;
134 	struct nhrp_afi_data *if_ad = &nifp->afi[nhs->afi];
135 	union sockunion *dst_proto;
136 	struct zbuf *zb;
137 	struct nhrp_packet_header *hdr;
138 	struct nhrp_extension_header *ext;
139 	struct nhrp_cie_header *cie;
140 
141 	r->t_register = NULL;
142 	if (!nhrp_peer_check(r->peer, 2)) {
143 		debugf(NHRP_DEBUG_COMMON, "NHS: Waiting link for %s",
144 			sockunion2str(&r->peer->vc->remote.nbma, buf1, sizeof buf1));
145 		THREAD_TIMER_ON(master, r->t_register, nhrp_reg_send_req, r, 120);
146 		return 0;
147 	}
148 
149 	THREAD_TIMER_ON(master, r->t_register, nhrp_reg_timeout, r, r->timeout);
150 
151 	/* RFC2332 5.2.3 NHC uses it's own address as dst if NHS is unknown */
152 	dst_proto = &nhs->proto_addr;
153 	if (sockunion_family(dst_proto) == AF_UNSPEC)
154 		dst_proto = &if_ad->addr;
155 
156 	sockunion2str(&if_ad->addr, buf1, sizeof(buf1));
157 	sockunion2str(dst_proto, buf2, sizeof(buf2));
158 	debugf(NHRP_DEBUG_COMMON, "NHS: Register %s -> %s (timeout %d)", buf1, buf2, r->timeout);
159 
160 	/* No protocol address configured for tunnel interface */
161 	if (sockunion_family(&if_ad->addr) == AF_UNSPEC)
162 		return 0;
163 
164 	zb = zbuf_alloc(1400);
165 	hdr = nhrp_packet_push(zb, NHRP_PACKET_REGISTRATION_REQUEST, &nifp->nbma, &if_ad->addr, dst_proto);
166 	hdr->hop_count = 1;
167 	if (!(if_ad->flags & NHRP_IFF_REG_NO_UNIQUE))
168 		hdr->flags |= htons(NHRP_FLAG_REGISTRATION_UNIQUE);
169 
170 	hdr->u.request_id = htonl(nhrp_reqid_alloc(&nhrp_packet_reqid, &r->reqid, nhrp_reg_reply));
171 
172 	/* FIXME: push CIE for each local protocol address */
173 	cie = nhrp_cie_push(zb, NHRP_CODE_SUCCESS, NULL, NULL);
174 	cie->prefix_length = 0xff;
175 	cie->holding_time = htons(if_ad->holdtime);
176 	cie->mtu = htons(if_ad->mtu);
177 
178 	nhrp_ext_request(zb, hdr, ifp);
179 
180 	/* Cisco NAT detection extension */
181 	hdr->flags |= htons(NHRP_FLAG_REGISTRATION_NAT);
182 	ext = nhrp_ext_push(zb, hdr, NHRP_EXTENSION_NAT_ADDRESS);
183 	cie = nhrp_cie_push(zb, NHRP_CODE_SUCCESS, &nifp->nbma, &if_ad->addr);
184 	cie->prefix_length = 8 * sockunion_get_addrlen(&if_ad->addr);
185 	nhrp_ext_complete(zb, ext);
186 
187 	nhrp_packet_complete(zb, hdr);
188 	nhrp_peer_send(r->peer, zb);
189 	zbuf_free(zb);
190 
191 	return 0;
192 }
193 
nhrp_reg_delete(struct nhrp_registration * r)194 static void nhrp_reg_delete(struct nhrp_registration *r)
195 {
196 	nhrp_peer_notify_del(r->peer, &r->peer_notifier);
197 	nhrp_peer_unref(r->peer);
198 	list_del(&r->reglist_entry);
199 	THREAD_OFF(r->t_register);
200 	XFREE(MTYPE_NHRP_REGISTRATION, r);
201 }
202 
nhrp_reg_by_nbma(struct nhrp_nhs * nhs,const union sockunion * nbma_addr)203 static struct nhrp_registration *nhrp_reg_by_nbma(struct nhrp_nhs *nhs, const union sockunion *nbma_addr)
204 {
205 	struct nhrp_registration *r;
206 
207 	list_for_each_entry(r, &nhs->reglist_head, reglist_entry)
208 		if (sockunion_same(&r->peer->vc->remote.nbma, nbma_addr))
209 			return r;
210 	return NULL;
211 }
212 
nhrp_nhs_resolve_cb(struct resolver_query * q,int n,union sockunion * addrs)213 static void nhrp_nhs_resolve_cb(struct resolver_query *q, int n, union sockunion *addrs)
214 {
215 	struct nhrp_nhs *nhs = container_of(q, struct nhrp_nhs, dns_resolve);
216 	struct nhrp_interface *nifp = nhs->ifp->info;
217 	struct nhrp_registration *reg, *regn;
218 	int i;
219 
220 	nhs->t_resolve = NULL;
221 	if (n < 0) {
222 		/* Failed, retry in a moment */
223 		THREAD_TIMER_ON(master, nhs->t_resolve, nhrp_nhs_resolve, nhs, 5);
224 		return;
225 	}
226 
227 	THREAD_TIMER_ON(master, nhs->t_resolve, nhrp_nhs_resolve, nhs, 2*60*60);
228 
229 	list_for_each_entry(reg, &nhs->reglist_head, reglist_entry)
230 		reg->mark = 1;
231 
232 	nhs->hub = 0;
233 	for (i = 0; i < n; i++) {
234 		if (sockunion_same(&addrs[i], &nifp->nbma)) {
235 			nhs->hub = 1;
236 			continue;
237 		}
238 
239 		reg = nhrp_reg_by_nbma(nhs, &addrs[i]);
240 		if (reg) {
241 			reg->mark = 0;
242 			continue;
243 		}
244 
245 		reg = XCALLOC(MTYPE_NHRP_REGISTRATION, sizeof(*reg));
246 		reg->peer = nhrp_peer_get(nhs->ifp, &addrs[i]);
247 		reg->nhs = nhs;
248 		reg->timeout = 1;
249 		list_init(&reg->reglist_entry);
250 		list_add_tail(&reg->reglist_entry, &nhs->reglist_head);
251 		nhrp_peer_notify_add(reg->peer, &reg->peer_notifier, nhrp_reg_peer_notify);
252 		THREAD_TIMER_MSEC_ON(master, reg->t_register, nhrp_reg_send_req, reg, 50);
253 	}
254 
255 	list_for_each_entry_safe(reg, regn, &nhs->reglist_head, reglist_entry) {
256 		if (reg->mark)
257 			nhrp_reg_delete(reg);
258 	}
259 }
260 
nhrp_nhs_resolve(struct thread * t)261 static int nhrp_nhs_resolve(struct thread *t)
262 {
263 	struct nhrp_nhs *nhs = THREAD_ARG(t);
264 
265 	resolver_resolve(&nhs->dns_resolve, AF_INET, nhs->nbma_fqdn, nhrp_nhs_resolve_cb);
266 
267 	return 0;
268 }
269 
nhrp_nhs_add(struct interface * ifp,afi_t afi,union sockunion * proto_addr,const char * nbma_fqdn)270 int nhrp_nhs_add(struct interface *ifp, afi_t afi, union sockunion *proto_addr, const char *nbma_fqdn)
271 {
272 	struct nhrp_interface *nifp = ifp->info;
273 	struct nhrp_nhs *nhs;
274 
275 	if (sockunion_family(proto_addr) != AF_UNSPEC &&
276 	    sockunion_family(proto_addr) != afi2family(afi))
277 		return NHRP_ERR_PROTOCOL_ADDRESS_MISMATCH;
278 
279 	list_for_each_entry(nhs, &nifp->afi[afi].nhslist_head, nhslist_entry) {
280 		if (sockunion_family(&nhs->proto_addr) != AF_UNSPEC &&
281 		    sockunion_family(proto_addr) != AF_UNSPEC &&
282 		    sockunion_same(&nhs->proto_addr, proto_addr))
283 			return NHRP_ERR_ENTRY_EXISTS;
284 
285 		if (strcmp(nhs->nbma_fqdn, nbma_fqdn) == 0)
286 			return NHRP_ERR_ENTRY_EXISTS;
287 	}
288 
289 	nhs = XMALLOC(MTYPE_NHRP_NHS, sizeof(struct nhrp_nhs));
290 	if (!nhs) return NHRP_ERR_NO_MEMORY;
291 
292 	*nhs = (struct nhrp_nhs) {
293 		.afi = afi,
294 		.ifp = ifp,
295 		.proto_addr = *proto_addr,
296 		.nbma_fqdn = strdup(nbma_fqdn),
297 		.reglist_head = LIST_INITIALIZER(nhs->reglist_head),
298 	};
299 	list_add_tail(&nhs->nhslist_entry, &nifp->afi[afi].nhslist_head);
300 	THREAD_TIMER_MSEC_ON(master, nhs->t_resolve, nhrp_nhs_resolve, nhs, 1000);
301 
302 	return NHRP_OK;
303 }
304 
nhrp_nhs_del(struct interface * ifp,afi_t afi,union sockunion * proto_addr,const char * nbma_fqdn)305 int nhrp_nhs_del(struct interface *ifp, afi_t afi, union sockunion *proto_addr, const char *nbma_fqdn)
306 {
307 	struct nhrp_interface *nifp = ifp->info;
308 	struct nhrp_nhs *nhs, *nnhs;
309 	int ret = NHRP_ERR_ENTRY_NOT_FOUND;
310 
311 	if (sockunion_family(proto_addr) != AF_UNSPEC &&
312 	    sockunion_family(proto_addr) != afi2family(afi))
313 		return NHRP_ERR_PROTOCOL_ADDRESS_MISMATCH;
314 
315 	list_for_each_entry_safe(nhs, nnhs, &nifp->afi[afi].nhslist_head, nhslist_entry) {
316 		if (!sockunion_same(&nhs->proto_addr, proto_addr))
317 			continue;
318 		if (strcmp(nhs->nbma_fqdn, nbma_fqdn) != 0)
319 			continue;
320 
321 		nhrp_nhs_free(nhs);
322 		ret = NHRP_OK;
323 	}
324 
325 	return ret;
326 }
327 
nhrp_nhs_free(struct nhrp_nhs * nhs)328 int nhrp_nhs_free(struct nhrp_nhs *nhs)
329 {
330 	struct nhrp_registration *r, *rn;
331 
332 	list_for_each_entry_safe(r, rn, &nhs->reglist_head, reglist_entry)
333 		nhrp_reg_delete(r);
334 	THREAD_OFF(nhs->t_resolve);
335 	list_del(&nhs->nhslist_entry);
336 	free((void*) nhs->nbma_fqdn);
337 	XFREE(MTYPE_NHRP_NHS, nhs);
338 	return 0;
339 }
340 
nhrp_nhs_terminate(void)341 void nhrp_nhs_terminate(void)
342 {
343 	struct interface *ifp;
344 	struct nhrp_interface *nifp;
345 	struct nhrp_nhs *nhs, *tmp;
346 	struct listnode *node;
347 	afi_t afi;
348 
349 	for (ALL_LIST_ELEMENTS_RO(iflist, node, ifp)) {
350 		nifp = ifp->info;
351 		for (afi = 0; afi < AFI_MAX; afi++) {
352 			list_for_each_entry_safe(nhs, tmp, &nifp->afi[afi].nhslist_head, nhslist_entry)
353 				nhrp_nhs_free(nhs);
354 		}
355 	}
356 }
357 
nhrp_nhs_foreach(struct interface * ifp,afi_t afi,void (* cb)(struct nhrp_nhs *,struct nhrp_registration *,void *),void * ctx)358 void nhrp_nhs_foreach(struct interface *ifp, afi_t afi, void (*cb)(struct nhrp_nhs *, struct nhrp_registration *, void *), void *ctx)
359 {
360 	struct nhrp_interface *nifp = ifp->info;
361 	struct nhrp_nhs *nhs;
362 	struct nhrp_registration *reg;
363 
364 	list_for_each_entry(nhs, &nifp->afi[afi].nhslist_head, nhslist_entry) {
365 		if (!list_empty(&nhs->reglist_head)) {
366 			list_for_each_entry(reg, &nhs->reglist_head, reglist_entry)
367 				cb(nhs, reg, ctx);
368 		} else
369 			cb(nhs, 0, ctx);
370 	}
371 }
372