xref: /openbsd-src/usr.sbin/ripd/message.c (revision 28b8bcf042e3db412777424b03537ccaa99d9113)
1*28b8bcf0Sflorian /*	$OpenBSD: message.c,v 1.18 2024/08/21 14:58:14 florian Exp $ */
2c04d2e36Snorby 
3c04d2e36Snorby /*
4c04d2e36Snorby  * Copyright (c) 2006 Michele Marchetto <mydecay@openbeer.it>
5c04d2e36Snorby  *
6c04d2e36Snorby  * Permission to use, copy, modify, and distribute this software for any
7c04d2e36Snorby  * purpose with or without fee is hereby granted, provided that the above
8c04d2e36Snorby  * copyright notice and this permission notice appear in all copies.
9c04d2e36Snorby  *
10c04d2e36Snorby  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11c04d2e36Snorby  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12c04d2e36Snorby  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13c04d2e36Snorby  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14c04d2e36Snorby  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15c04d2e36Snorby  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16c04d2e36Snorby  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17c04d2e36Snorby  */
18c04d2e36Snorby 
19c04d2e36Snorby #include <sys/types.h>
20c04d2e36Snorby #include <sys/socket.h>
21c04d2e36Snorby #include <netinet/in.h>
22c04d2e36Snorby #include <netinet/ip.h>
23c04d2e36Snorby #include <arpa/inet.h>
24c04d2e36Snorby #include <netinet/udp.h>
25c04d2e36Snorby 
26c04d2e36Snorby #include <stdlib.h>
27c04d2e36Snorby #include <string.h>
28c04d2e36Snorby 
29c04d2e36Snorby #include "ripd.h"
30c04d2e36Snorby #include "rip.h"
31c04d2e36Snorby #include "ripe.h"
32c04d2e36Snorby #include "log.h"
33c04d2e36Snorby 
34c04d2e36Snorby extern struct ripd_conf	*oeconf;
35c04d2e36Snorby 
36c04d2e36Snorby void	 delete_entry(struct rip_route *);
37c04d2e36Snorby 
38c04d2e36Snorby /* timers */
39c04d2e36Snorby void
40c04d2e36Snorby report_timer(int fd, short event, void *arg)
41c04d2e36Snorby {
42c04d2e36Snorby 	struct timeval	 tv;
43c04d2e36Snorby 
44c04d2e36Snorby 	ripe_imsg_compose_rde(IMSG_FULL_RESPONSE, 0, 0, NULL, 0);
45c04d2e36Snorby 
46c04d2e36Snorby 	/* restart report timer */
47c04d2e36Snorby 	timerclear(&tv);
4866ad965fSdjm 	tv.tv_sec = KEEPALIVE + arc4random_uniform(OFFSET);
49c04d2e36Snorby 	evtimer_add(&oeconf->report_timer, &tv);
50c04d2e36Snorby }
51c04d2e36Snorby 
52c04d2e36Snorby int
53c04d2e36Snorby start_report_timer(void)
54c04d2e36Snorby {
55c04d2e36Snorby 	struct timeval	 tv;
56c04d2e36Snorby 
57c04d2e36Snorby 	timerclear(&tv);
5866ad965fSdjm 	tv.tv_sec = KEEPALIVE + arc4random_uniform(OFFSET);
59c04d2e36Snorby 	return (evtimer_add(&oeconf->report_timer, &tv));
60c04d2e36Snorby }
61c04d2e36Snorby 
6231b802a2Smichele /* list handlers */
63c04d2e36Snorby void
64c04d2e36Snorby add_entry(struct packet_head *r_list, struct rip_route *rr)
65c04d2e36Snorby {
66c04d2e36Snorby 	struct packet_entry	*re;
67c04d2e36Snorby 
68c04d2e36Snorby 	if (rr == NULL)
69c04d2e36Snorby 		fatalx("add_entry: no route report");
70c04d2e36Snorby 
71c04d2e36Snorby 	if ((re = calloc(1, sizeof(*re))) == NULL)
72a59fb23fSremi 		fatal("add_entry");
73c04d2e36Snorby 
74c04d2e36Snorby 	TAILQ_INSERT_TAIL(r_list, re, entry);
75c04d2e36Snorby 	re->rr = rr;
76c04d2e36Snorby 	rr->refcount++;
77c04d2e36Snorby }
78c04d2e36Snorby 
79c04d2e36Snorby void
80c04d2e36Snorby delete_entry(struct rip_route *rr)
81c04d2e36Snorby {
82c04d2e36Snorby 	if (--rr->refcount == 0)
83c04d2e36Snorby 		free(rr);
84c04d2e36Snorby }
85c04d2e36Snorby 
8631b802a2Smichele void
8731b802a2Smichele clear_list(struct packet_head *r_list)
8831b802a2Smichele {
8931b802a2Smichele 	struct packet_entry	*re;
9031b802a2Smichele 
9131b802a2Smichele 	while ((re = TAILQ_FIRST(r_list)) != NULL) {
9231b802a2Smichele 		TAILQ_REMOVE(r_list, re, entry);
9331b802a2Smichele 		delete_entry(re->rr);
9431b802a2Smichele 		free(re);
9531b802a2Smichele 	}
9631b802a2Smichele }
9731b802a2Smichele 
9831b802a2Smichele /* communications */
99c04d2e36Snorby int
100c04d2e36Snorby send_triggered_update(struct iface *iface, struct rip_route *rr)
101c04d2e36Snorby {
102c04d2e36Snorby 	struct sockaddr_in	 dst;
103e39620e5Snicm 	struct ibuf		*buf;
104c04d2e36Snorby 	u_int16_t		 afi, route_tag;
105c04d2e36Snorby 	u_int32_t		 address, netmask, nexthop, metric;
106c04d2e36Snorby 
10744f2793aSremi 	if (iface->passive)
10844f2793aSremi 		return (0);
10944f2793aSremi 
110*28b8bcf0Sflorian 	inet_pton(AF_INET, ALL_RIP_ROUTERS, &dst.sin_addr);
111c04d2e36Snorby 
112c04d2e36Snorby 	dst.sin_port = htons(RIP_PORT);
113c04d2e36Snorby 	dst.sin_family = AF_INET;
114c04d2e36Snorby 	dst.sin_len = sizeof(struct sockaddr_in);
115c04d2e36Snorby 
116e39620e5Snicm 	if ((buf = ibuf_open(iface->mtu - sizeof(struct ip) -
117726964a1Sderaadt 	    sizeof(struct udphdr))) == NULL)
118c04d2e36Snorby 		fatal("send_triggered_update");
119c04d2e36Snorby 
120c04d2e36Snorby 	gen_rip_hdr(buf, COMMAND_RESPONSE);
121c04d2e36Snorby 
122c04d2e36Snorby 	afi = htons(AF_INET);
123c04d2e36Snorby 	route_tag = 0;
124c04d2e36Snorby 
125c04d2e36Snorby 	address = rr->address.s_addr;
126c04d2e36Snorby 	netmask = rr->mask.s_addr;
127c04d2e36Snorby 	nexthop = rr->nexthop.s_addr;
128c04d2e36Snorby 	metric = htonl(rr->metric);
129c04d2e36Snorby 
130e39620e5Snicm 	ibuf_add(buf, &afi, sizeof(afi));
131e39620e5Snicm 	ibuf_add(buf, &route_tag, sizeof(route_tag));
132e39620e5Snicm 	ibuf_add(buf, &address, sizeof(address));
133e39620e5Snicm 	ibuf_add(buf, &netmask, sizeof(netmask));
134e39620e5Snicm 	ibuf_add(buf, &nexthop, sizeof(nexthop));
135e39620e5Snicm 	ibuf_add(buf, &metric, sizeof(metric));
136c04d2e36Snorby 
137aa2e6c71Sclaudio 	send_packet(iface, ibuf_data(buf), ibuf_size(buf), &dst);
138e39620e5Snicm 	ibuf_free(buf);
139c04d2e36Snorby 
140c04d2e36Snorby 	return (0);
141c04d2e36Snorby }
142c04d2e36Snorby 
143c04d2e36Snorby int
144c04d2e36Snorby send_request(struct packet_head *r_list, struct iface *i, struct nbr *nbr)
145c04d2e36Snorby {
146e39620e5Snicm 	struct ibuf		*buf;
147c04d2e36Snorby 	struct iface		*iface;
148c04d2e36Snorby 	struct packet_entry	*entry;
149c04d2e36Snorby 	struct sockaddr_in	 dst;
150c04d2e36Snorby 	u_int8_t		 nentries;
151c04d2e36Snorby 	u_int8_t		 single_entry = 0;
152c04d2e36Snorby 	u_int32_t		 address, netmask, nexthop;
153c04d2e36Snorby 	u_int16_t		 port, afi, route_tag;
154c04d2e36Snorby 	u_int32_t		 metric;
155c04d2e36Snorby 
156c04d2e36Snorby 	if (i == NULL) {
157c04d2e36Snorby 		/* directly to a nbr */
158c04d2e36Snorby 		iface = nbr->iface;
159c04d2e36Snorby 		dst.sin_addr = nbr->addr;
160c04d2e36Snorby 		port = htons(nbr->port);
161c04d2e36Snorby 	} else {
162c04d2e36Snorby 		/* multicast on interface */
163c04d2e36Snorby 		iface = i;
164*28b8bcf0Sflorian 		inet_pton(AF_INET, ALL_RIP_ROUTERS, &dst.sin_addr);
165c04d2e36Snorby 		port = htons(RIP_PORT);
166c04d2e36Snorby 	}
167c04d2e36Snorby 
16844f2793aSremi 	if (iface->passive) {
16944f2793aSremi 		clear_list(r_list);
17044f2793aSremi 		return (0);
17144f2793aSremi 	}
17244f2793aSremi 
173c04d2e36Snorby 	dst.sin_port = port;
174c04d2e36Snorby 	dst.sin_family = AF_INET;
175c04d2e36Snorby 	dst.sin_len = sizeof(struct sockaddr_in);
176c04d2e36Snorby 
177c04d2e36Snorby 	while (!TAILQ_EMPTY(r_list)) {
178e39620e5Snicm 		if ((buf = ibuf_open(iface->mtu - sizeof(struct ip) -
179726964a1Sderaadt 		    sizeof(struct udphdr))) == NULL)
180c04d2e36Snorby 			fatal("send_request");
181c04d2e36Snorby 
182c04d2e36Snorby 		gen_rip_hdr(buf, COMMAND_REQUEST);
183c04d2e36Snorby 
184c04d2e36Snorby 		route_tag = 0;
185c04d2e36Snorby 		nentries = 0;
186c04d2e36Snorby 
187c04d2e36Snorby 		if (TAILQ_FIRST(r_list) == TAILQ_LAST(r_list, packet_head))
188c04d2e36Snorby 			single_entry = 1;
189c04d2e36Snorby 		while (((entry = TAILQ_FIRST(r_list)) != NULL) &&
190e3be6b29Smichele 		    nentries < MAX_RIP_ENTRIES) {
191c04d2e36Snorby 			afi = htons(AF_INET);
192c04d2e36Snorby 
193c04d2e36Snorby 			address = entry->rr->address.s_addr;
194c04d2e36Snorby 			netmask = entry->rr->mask.s_addr;
195c04d2e36Snorby 			nexthop = entry->rr->nexthop.s_addr;
196c04d2e36Snorby 			metric = htonl(entry->rr->metric);
197c04d2e36Snorby 
198c04d2e36Snorby 			if (metric == htonl(INFINITY) && single_entry)
199c04d2e36Snorby 				afi = AF_UNSPEC;
200c04d2e36Snorby 
201e39620e5Snicm 			ibuf_add(buf, &afi, sizeof(afi));
202e39620e5Snicm 			ibuf_add(buf, &route_tag, sizeof(route_tag));
203e39620e5Snicm 			ibuf_add(buf, &address, sizeof(address));
204e39620e5Snicm 			ibuf_add(buf, &netmask, sizeof(netmask));
205e39620e5Snicm 			ibuf_add(buf, &nexthop, sizeof(nexthop));
206e39620e5Snicm 			ibuf_add(buf, &metric, sizeof(metric));
207a9cd8339Sremi 			nentries++;
208c04d2e36Snorby 
209c04d2e36Snorby 			TAILQ_REMOVE(r_list, entry, entry);
210c04d2e36Snorby 			delete_entry(entry->rr);
211c04d2e36Snorby 			free(entry);
212c04d2e36Snorby 		}
213aa2e6c71Sclaudio 		send_packet(iface, ibuf_data(buf), ibuf_size(buf), &dst);
214e39620e5Snicm 		ibuf_free(buf);
215c04d2e36Snorby 	}
216c04d2e36Snorby 
217c04d2e36Snorby 	return (0);
218c04d2e36Snorby }
219c04d2e36Snorby 
220c04d2e36Snorby int
221c04d2e36Snorby send_response(struct packet_head *r_list, struct iface *i, struct nbr *nbr)
222c04d2e36Snorby {
223e39620e5Snicm 	struct ibuf		*buf;
224c04d2e36Snorby 	struct iface		*iface;
225c04d2e36Snorby 	struct packet_entry	*entry;
226c04d2e36Snorby 	struct sockaddr_in	 dst;
227c04d2e36Snorby 	u_int8_t		 nentries;
228c04d2e36Snorby 	u_int16_t		 port, afi, route_tag;
229c04d2e36Snorby 	u_int32_t		 address, netmask, nexthop;
230c04d2e36Snorby 	u_int32_t		 metric;
231c04d2e36Snorby 
232c04d2e36Snorby 	if (i == NULL) {
233c04d2e36Snorby 		/* directly to a nbr */
234c04d2e36Snorby 		iface = nbr->iface;
235c04d2e36Snorby 		dst.sin_addr = nbr->addr;
236c04d2e36Snorby 		port = htons(nbr->port);
237c04d2e36Snorby 	} else {
238c04d2e36Snorby 		/* multicast on interface */
239c04d2e36Snorby 		iface = i;
240*28b8bcf0Sflorian 		inet_pton(AF_INET, ALL_RIP_ROUTERS, &dst.sin_addr);
241c04d2e36Snorby 		port = htons(RIP_PORT);
242c04d2e36Snorby 	}
243c04d2e36Snorby 
24444f2793aSremi 	if (iface->passive) {
24544f2793aSremi 		clear_list(r_list);
24644f2793aSremi 		return (0);
24744f2793aSremi 	}
24844f2793aSremi 
249c04d2e36Snorby 	dst.sin_port = port;
250c04d2e36Snorby 	dst.sin_family = AF_INET;
251c04d2e36Snorby 	dst.sin_len = sizeof(struct sockaddr_in);
252c04d2e36Snorby 
253c04d2e36Snorby 	while (!TAILQ_EMPTY(r_list)) {
254e39620e5Snicm 		if ((buf = ibuf_open(iface->mtu - sizeof(struct ip) -
255726964a1Sderaadt 		    sizeof(struct udphdr))) == NULL)
256c04d2e36Snorby 			fatal("send_response");
257c04d2e36Snorby 
258c04d2e36Snorby 		gen_rip_hdr(buf, COMMAND_RESPONSE);
259c04d2e36Snorby 
260c04d2e36Snorby 		afi = htons(AF_INET);
261c04d2e36Snorby 		route_tag = 0;
262c04d2e36Snorby 		nentries = 0;
263c04d2e36Snorby 
264c04d2e36Snorby 		if (iface->auth_type != AUTH_NONE) {
265badfb5d1Smichele 			if (auth_gen(buf, iface) == -1) {
266e39620e5Snicm 				ibuf_free(buf);
267c04d2e36Snorby 				return (-1);
268badfb5d1Smichele 			}
269c04d2e36Snorby 			nentries++;
270c04d2e36Snorby 		}
271c04d2e36Snorby 
272c04d2e36Snorby 		while ((entry = TAILQ_FIRST(r_list)) != NULL &&
27314afd964Smichele 		    nentries < MAX_RIP_ENTRIES) {
274c04d2e36Snorby 			address = entry->rr->address.s_addr;
275c04d2e36Snorby 			netmask = entry->rr->mask.s_addr;
276c04d2e36Snorby 			nexthop = entry->rr->nexthop.s_addr;
277c04d2e36Snorby 			metric = htonl(entry->rr->metric);
278c04d2e36Snorby 
279c04d2e36Snorby 			if (entry->rr->ifindex == iface->ifindex) {
280c04d2e36Snorby 				if (oeconf->options & OPT_SPLIT_HORIZON)
281c04d2e36Snorby 					goto free;
282c04d2e36Snorby 				else if (oeconf->options & OPT_SPLIT_POISONED)
283c04d2e36Snorby 					metric = htonl(INFINITY);
284c04d2e36Snorby 			}
285c04d2e36Snorby 
28614afd964Smichele 			/* If the nexthop is not reachable through the
28714afd964Smichele 			 * outgoing interface set it to INADDR_ANY */
28814afd964Smichele 			if ((nexthop & iface->mask.s_addr) !=
28914afd964Smichele 			    (iface->addr.s_addr & iface->mask.s_addr))
29014afd964Smichele 				nexthop = INADDR_ANY;
29114afd964Smichele 
292e39620e5Snicm 			ibuf_add(buf, &afi, sizeof(afi));
293e39620e5Snicm 			ibuf_add(buf, &route_tag, sizeof(route_tag));
294e39620e5Snicm 			ibuf_add(buf, &address, sizeof(address));
295e39620e5Snicm 			ibuf_add(buf, &netmask, sizeof(netmask));
296e39620e5Snicm 			ibuf_add(buf, &nexthop, sizeof(nexthop));
297e39620e5Snicm 			ibuf_add(buf, &metric, sizeof(metric));
298a9cd8339Sremi 			nentries++;
299c04d2e36Snorby free:
300c04d2e36Snorby 			TAILQ_REMOVE(r_list, entry, entry);
301c04d2e36Snorby 			delete_entry(entry->rr);
302c04d2e36Snorby 			free(entry);
303c04d2e36Snorby 		}
304c04d2e36Snorby 
305c04d2e36Snorby 		if (iface->auth_type == AUTH_CRYPT)
306c04d2e36Snorby 			auth_add_trailer(buf, iface);
307c04d2e36Snorby 
308aa2e6c71Sclaudio 		send_packet(iface, ibuf_data(buf), ibuf_size(buf), &dst);
309e39620e5Snicm 		ibuf_free(buf);
310c04d2e36Snorby 	}
311c04d2e36Snorby 
312c04d2e36Snorby 	return (0);
313c04d2e36Snorby }
314c04d2e36Snorby 
315c04d2e36Snorby void
31687feb355Sclaudio recv_request(struct iface *i, struct nbr *nbr, u_int8_t *buf, u_int16_t len)
317c04d2e36Snorby {
318c04d2e36Snorby 	struct rip_entry	*e;
319c04d2e36Snorby 	struct rip_route	 rr;
320c04d2e36Snorby 	int			 l = len;
321c04d2e36Snorby 
322c04d2e36Snorby 	bzero(&rr, sizeof(rr));
323c04d2e36Snorby 
324c04d2e36Snorby 	if (len < RIP_ENTRY_LEN) {
325c04d2e36Snorby 		log_debug("recv_request: bad packet size, interface %s",
326c04d2e36Snorby 		    i->name);
327c04d2e36Snorby 		return;
328c04d2e36Snorby 	}
329c04d2e36Snorby 
330c04d2e36Snorby 	/*
331c04d2e36Snorby 	 * XXX is it guaranteed that bus is properly aligned.
332b8bbf4e7Sdavid 	 * If not this will bomb on strict alignment archs.
333c04d2e36Snorby 	 * */
334c04d2e36Snorby 	e = (struct rip_entry *)buf;
335c04d2e36Snorby 
336c04d2e36Snorby 	if (len > RIP_ENTRY_LEN * MAX_RIP_ENTRIES) {
337c04d2e36Snorby 		log_debug("recv_request: packet too long\n");
338c04d2e36Snorby 		return;
339c04d2e36Snorby 	}
340c04d2e36Snorby 
341c04d2e36Snorby 	l -= RIP_ENTRY_LEN;
342c04d2e36Snorby 
343c04d2e36Snorby 	/*
344c04d2e36Snorby 	 * If there is exactly one entry in the request, and it has
345c04d2e36Snorby 	 * an address family identifier of zero and a metric of
346c04d2e36Snorby 	 * infinity (i.e., 16), then this is a request to send the
347c04d2e36Snorby 	 * entire routing table.
348c04d2e36Snorby 	 */
349c04d2e36Snorby 	if (e->AFI == 0 && e->metric == ntohl(INFINITY) && l == 0) {
350c04d2e36Snorby 		ripe_imsg_compose_rde(IMSG_FULL_RESPONSE, nbr->peerid,
351c04d2e36Snorby 		    0, NULL, 0);
352c04d2e36Snorby 		return;
353c04d2e36Snorby 	}
354c04d2e36Snorby 
355c04d2e36Snorby 	for ( ; l >= 0; l -= RIP_ENTRY_LEN) {
356c04d2e36Snorby 		if (e->AFI != AF_INET) {
357c04d2e36Snorby 			log_debug("recv_request: AFI %d not supported\n",
358c04d2e36Snorby 			    e->AFI);
359c04d2e36Snorby 			return;
360c04d2e36Snorby 		}
361c04d2e36Snorby 		rr.address.s_addr = e->address;
362c04d2e36Snorby 		rr.mask.s_addr = e->mask;
363c04d2e36Snorby 		rr.nexthop.s_addr = e->nexthop;
364c04d2e36Snorby 		rr.metric = e->metric;
365c04d2e36Snorby 		rr.ifindex = i->ifindex;
366c04d2e36Snorby 
367c04d2e36Snorby 		ripe_imsg_compose_rde(IMSG_ROUTE_REQUEST, nbr->peerid,
36887feb355Sclaudio 		    0, &rr, sizeof(rr));
369c04d2e36Snorby 
370c04d2e36Snorby 		e++;
371c04d2e36Snorby 	}
372c04d2e36Snorby 
373c04d2e36Snorby 	ripe_imsg_compose_rde(IMSG_ROUTE_REQUEST_END, nbr->peerid,
374c04d2e36Snorby 	    0, NULL, 0);
375c04d2e36Snorby }
376c04d2e36Snorby 
377c04d2e36Snorby void
37887feb355Sclaudio recv_response(struct iface *i, struct nbr *nbr, u_int8_t *buf, u_int16_t len)
379c04d2e36Snorby {
380c04d2e36Snorby 	struct rip_route	 r;
381c04d2e36Snorby 	struct rip_entry	*e;
382c04d2e36Snorby 	int			 l;
383c04d2e36Snorby 
384c04d2e36Snorby 	if (len < RIP_ENTRY_LEN) {
385c04d2e36Snorby 		log_debug("recv_response: bad packet size, interface %s",
386c04d2e36Snorby 		    i->name);
387c04d2e36Snorby 		return;
388c04d2e36Snorby 	}
389c04d2e36Snorby 
390c04d2e36Snorby 	/* We must double check the length, because the only entry
391c04d2e36Snorby 	 * can be stripped off by authentication code
392c04d2e36Snorby 	 */
393c04d2e36Snorby 	if (len < RIP_ENTRY_LEN) {
394c04d2e36Snorby 		/* If there are no entries, our work is finished here */
395c04d2e36Snorby 		return;
396c04d2e36Snorby 	}
397c04d2e36Snorby 
398c04d2e36Snorby 	/* XXX again */
399c04d2e36Snorby 	e = (struct rip_entry *)buf;
400c04d2e36Snorby 
401c04d2e36Snorby 	if (len > RIP_ENTRY_LEN * MAX_RIP_ENTRIES) {
402c04d2e36Snorby 		log_debug("recv_response: packet too long\n");
403c04d2e36Snorby 		return;
404c04d2e36Snorby 	}
405c04d2e36Snorby 
406c04d2e36Snorby 	l = len - sizeof(*e);
407c04d2e36Snorby 
408c04d2e36Snorby 	for ( ; l >= 0; l -= RIP_ENTRY_LEN) {
409c04d2e36Snorby 		if (ntohs(e->AFI) != AF_INET) {
410c04d2e36Snorby 			log_debug("recv_response: AFI %d not supported\n",
411c04d2e36Snorby 			    e->AFI);
412c04d2e36Snorby 			return;
413c04d2e36Snorby 		}
414c04d2e36Snorby 
415c04d2e36Snorby 		r.address.s_addr = e->address;
416c04d2e36Snorby 		r.mask.s_addr = e->mask;
417c04d2e36Snorby 
418c04d2e36Snorby 		if (e->nexthop == INADDR_ANY ||
419c04d2e36Snorby 		    ((i->addr.s_addr & i->mask.s_addr) !=
420c04d2e36Snorby 		    (e->nexthop & i->mask.s_addr)))
421c04d2e36Snorby 			r.nexthop.s_addr = nbr->addr.s_addr;
422c04d2e36Snorby 		else
423c04d2e36Snorby 			r.nexthop.s_addr = e->nexthop;
424c04d2e36Snorby 
425c04d2e36Snorby 		r.metric = ntohl(e->metric);
426c04d2e36Snorby 		r.ifindex = i->ifindex;
427c04d2e36Snorby 
42887feb355Sclaudio 		ripe_imsg_compose_rde(IMSG_ROUTE_FEED, 0, 0, &r, sizeof(r));
429c04d2e36Snorby 
430c04d2e36Snorby 		e++;
431c04d2e36Snorby 	}
432c04d2e36Snorby }
433