1 /* $OpenBSD: message.c,v 1.18 2024/08/21 14:58:14 florian Exp $ */
2
3 /*
4 * Copyright (c) 2006 Michele Marchetto <mydecay@openbeer.it>
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 <netinet/in.h>
22 #include <netinet/ip.h>
23 #include <arpa/inet.h>
24 #include <netinet/udp.h>
25
26 #include <stdlib.h>
27 #include <string.h>
28
29 #include "ripd.h"
30 #include "rip.h"
31 #include "ripe.h"
32 #include "log.h"
33
34 extern struct ripd_conf *oeconf;
35
36 void delete_entry(struct rip_route *);
37
38 /* timers */
39 void
report_timer(int fd,short event,void * arg)40 report_timer(int fd, short event, void *arg)
41 {
42 struct timeval tv;
43
44 ripe_imsg_compose_rde(IMSG_FULL_RESPONSE, 0, 0, NULL, 0);
45
46 /* restart report timer */
47 timerclear(&tv);
48 tv.tv_sec = KEEPALIVE + arc4random_uniform(OFFSET);
49 evtimer_add(&oeconf->report_timer, &tv);
50 }
51
52 int
start_report_timer(void)53 start_report_timer(void)
54 {
55 struct timeval tv;
56
57 timerclear(&tv);
58 tv.tv_sec = KEEPALIVE + arc4random_uniform(OFFSET);
59 return (evtimer_add(&oeconf->report_timer, &tv));
60 }
61
62 /* list handlers */
63 void
add_entry(struct packet_head * r_list,struct rip_route * rr)64 add_entry(struct packet_head *r_list, struct rip_route *rr)
65 {
66 struct packet_entry *re;
67
68 if (rr == NULL)
69 fatalx("add_entry: no route report");
70
71 if ((re = calloc(1, sizeof(*re))) == NULL)
72 fatal("add_entry");
73
74 TAILQ_INSERT_TAIL(r_list, re, entry);
75 re->rr = rr;
76 rr->refcount++;
77 }
78
79 void
delete_entry(struct rip_route * rr)80 delete_entry(struct rip_route *rr)
81 {
82 if (--rr->refcount == 0)
83 free(rr);
84 }
85
86 void
clear_list(struct packet_head * r_list)87 clear_list(struct packet_head *r_list)
88 {
89 struct packet_entry *re;
90
91 while ((re = TAILQ_FIRST(r_list)) != NULL) {
92 TAILQ_REMOVE(r_list, re, entry);
93 delete_entry(re->rr);
94 free(re);
95 }
96 }
97
98 /* communications */
99 int
send_triggered_update(struct iface * iface,struct rip_route * rr)100 send_triggered_update(struct iface *iface, struct rip_route *rr)
101 {
102 struct sockaddr_in dst;
103 struct ibuf *buf;
104 u_int16_t afi, route_tag;
105 u_int32_t address, netmask, nexthop, metric;
106
107 if (iface->passive)
108 return (0);
109
110 inet_pton(AF_INET, ALL_RIP_ROUTERS, &dst.sin_addr);
111
112 dst.sin_port = htons(RIP_PORT);
113 dst.sin_family = AF_INET;
114 dst.sin_len = sizeof(struct sockaddr_in);
115
116 if ((buf = ibuf_open(iface->mtu - sizeof(struct ip) -
117 sizeof(struct udphdr))) == NULL)
118 fatal("send_triggered_update");
119
120 gen_rip_hdr(buf, COMMAND_RESPONSE);
121
122 afi = htons(AF_INET);
123 route_tag = 0;
124
125 address = rr->address.s_addr;
126 netmask = rr->mask.s_addr;
127 nexthop = rr->nexthop.s_addr;
128 metric = htonl(rr->metric);
129
130 ibuf_add(buf, &afi, sizeof(afi));
131 ibuf_add(buf, &route_tag, sizeof(route_tag));
132 ibuf_add(buf, &address, sizeof(address));
133 ibuf_add(buf, &netmask, sizeof(netmask));
134 ibuf_add(buf, &nexthop, sizeof(nexthop));
135 ibuf_add(buf, &metric, sizeof(metric));
136
137 send_packet(iface, ibuf_data(buf), ibuf_size(buf), &dst);
138 ibuf_free(buf);
139
140 return (0);
141 }
142
143 int
send_request(struct packet_head * r_list,struct iface * i,struct nbr * nbr)144 send_request(struct packet_head *r_list, struct iface *i, struct nbr *nbr)
145 {
146 struct ibuf *buf;
147 struct iface *iface;
148 struct packet_entry *entry;
149 struct sockaddr_in dst;
150 u_int8_t nentries;
151 u_int8_t single_entry = 0;
152 u_int32_t address, netmask, nexthop;
153 u_int16_t port, afi, route_tag;
154 u_int32_t metric;
155
156 if (i == NULL) {
157 /* directly to a nbr */
158 iface = nbr->iface;
159 dst.sin_addr = nbr->addr;
160 port = htons(nbr->port);
161 } else {
162 /* multicast on interface */
163 iface = i;
164 inet_pton(AF_INET, ALL_RIP_ROUTERS, &dst.sin_addr);
165 port = htons(RIP_PORT);
166 }
167
168 if (iface->passive) {
169 clear_list(r_list);
170 return (0);
171 }
172
173 dst.sin_port = port;
174 dst.sin_family = AF_INET;
175 dst.sin_len = sizeof(struct sockaddr_in);
176
177 while (!TAILQ_EMPTY(r_list)) {
178 if ((buf = ibuf_open(iface->mtu - sizeof(struct ip) -
179 sizeof(struct udphdr))) == NULL)
180 fatal("send_request");
181
182 gen_rip_hdr(buf, COMMAND_REQUEST);
183
184 route_tag = 0;
185 nentries = 0;
186
187 if (TAILQ_FIRST(r_list) == TAILQ_LAST(r_list, packet_head))
188 single_entry = 1;
189 while (((entry = TAILQ_FIRST(r_list)) != NULL) &&
190 nentries < MAX_RIP_ENTRIES) {
191 afi = htons(AF_INET);
192
193 address = entry->rr->address.s_addr;
194 netmask = entry->rr->mask.s_addr;
195 nexthop = entry->rr->nexthop.s_addr;
196 metric = htonl(entry->rr->metric);
197
198 if (metric == htonl(INFINITY) && single_entry)
199 afi = AF_UNSPEC;
200
201 ibuf_add(buf, &afi, sizeof(afi));
202 ibuf_add(buf, &route_tag, sizeof(route_tag));
203 ibuf_add(buf, &address, sizeof(address));
204 ibuf_add(buf, &netmask, sizeof(netmask));
205 ibuf_add(buf, &nexthop, sizeof(nexthop));
206 ibuf_add(buf, &metric, sizeof(metric));
207 nentries++;
208
209 TAILQ_REMOVE(r_list, entry, entry);
210 delete_entry(entry->rr);
211 free(entry);
212 }
213 send_packet(iface, ibuf_data(buf), ibuf_size(buf), &dst);
214 ibuf_free(buf);
215 }
216
217 return (0);
218 }
219
220 int
send_response(struct packet_head * r_list,struct iface * i,struct nbr * nbr)221 send_response(struct packet_head *r_list, struct iface *i, struct nbr *nbr)
222 {
223 struct ibuf *buf;
224 struct iface *iface;
225 struct packet_entry *entry;
226 struct sockaddr_in dst;
227 u_int8_t nentries;
228 u_int16_t port, afi, route_tag;
229 u_int32_t address, netmask, nexthop;
230 u_int32_t metric;
231
232 if (i == NULL) {
233 /* directly to a nbr */
234 iface = nbr->iface;
235 dst.sin_addr = nbr->addr;
236 port = htons(nbr->port);
237 } else {
238 /* multicast on interface */
239 iface = i;
240 inet_pton(AF_INET, ALL_RIP_ROUTERS, &dst.sin_addr);
241 port = htons(RIP_PORT);
242 }
243
244 if (iface->passive) {
245 clear_list(r_list);
246 return (0);
247 }
248
249 dst.sin_port = port;
250 dst.sin_family = AF_INET;
251 dst.sin_len = sizeof(struct sockaddr_in);
252
253 while (!TAILQ_EMPTY(r_list)) {
254 if ((buf = ibuf_open(iface->mtu - sizeof(struct ip) -
255 sizeof(struct udphdr))) == NULL)
256 fatal("send_response");
257
258 gen_rip_hdr(buf, COMMAND_RESPONSE);
259
260 afi = htons(AF_INET);
261 route_tag = 0;
262 nentries = 0;
263
264 if (iface->auth_type != AUTH_NONE) {
265 if (auth_gen(buf, iface) == -1) {
266 ibuf_free(buf);
267 return (-1);
268 }
269 nentries++;
270 }
271
272 while ((entry = TAILQ_FIRST(r_list)) != NULL &&
273 nentries < MAX_RIP_ENTRIES) {
274 address = entry->rr->address.s_addr;
275 netmask = entry->rr->mask.s_addr;
276 nexthop = entry->rr->nexthop.s_addr;
277 metric = htonl(entry->rr->metric);
278
279 if (entry->rr->ifindex == iface->ifindex) {
280 if (oeconf->options & OPT_SPLIT_HORIZON)
281 goto free;
282 else if (oeconf->options & OPT_SPLIT_POISONED)
283 metric = htonl(INFINITY);
284 }
285
286 /* If the nexthop is not reachable through the
287 * outgoing interface set it to INADDR_ANY */
288 if ((nexthop & iface->mask.s_addr) !=
289 (iface->addr.s_addr & iface->mask.s_addr))
290 nexthop = INADDR_ANY;
291
292 ibuf_add(buf, &afi, sizeof(afi));
293 ibuf_add(buf, &route_tag, sizeof(route_tag));
294 ibuf_add(buf, &address, sizeof(address));
295 ibuf_add(buf, &netmask, sizeof(netmask));
296 ibuf_add(buf, &nexthop, sizeof(nexthop));
297 ibuf_add(buf, &metric, sizeof(metric));
298 nentries++;
299 free:
300 TAILQ_REMOVE(r_list, entry, entry);
301 delete_entry(entry->rr);
302 free(entry);
303 }
304
305 if (iface->auth_type == AUTH_CRYPT)
306 auth_add_trailer(buf, iface);
307
308 send_packet(iface, ibuf_data(buf), ibuf_size(buf), &dst);
309 ibuf_free(buf);
310 }
311
312 return (0);
313 }
314
315 void
recv_request(struct iface * i,struct nbr * nbr,u_int8_t * buf,u_int16_t len)316 recv_request(struct iface *i, struct nbr *nbr, u_int8_t *buf, u_int16_t len)
317 {
318 struct rip_entry *e;
319 struct rip_route rr;
320 int l = len;
321
322 bzero(&rr, sizeof(rr));
323
324 if (len < RIP_ENTRY_LEN) {
325 log_debug("recv_request: bad packet size, interface %s",
326 i->name);
327 return;
328 }
329
330 /*
331 * XXX is it guaranteed that bus is properly aligned.
332 * If not this will bomb on strict alignment archs.
333 * */
334 e = (struct rip_entry *)buf;
335
336 if (len > RIP_ENTRY_LEN * MAX_RIP_ENTRIES) {
337 log_debug("recv_request: packet too long\n");
338 return;
339 }
340
341 l -= RIP_ENTRY_LEN;
342
343 /*
344 * If there is exactly one entry in the request, and it has
345 * an address family identifier of zero and a metric of
346 * infinity (i.e., 16), then this is a request to send the
347 * entire routing table.
348 */
349 if (e->AFI == 0 && e->metric == ntohl(INFINITY) && l == 0) {
350 ripe_imsg_compose_rde(IMSG_FULL_RESPONSE, nbr->peerid,
351 0, NULL, 0);
352 return;
353 }
354
355 for ( ; l >= 0; l -= RIP_ENTRY_LEN) {
356 if (e->AFI != AF_INET) {
357 log_debug("recv_request: AFI %d not supported\n",
358 e->AFI);
359 return;
360 }
361 rr.address.s_addr = e->address;
362 rr.mask.s_addr = e->mask;
363 rr.nexthop.s_addr = e->nexthop;
364 rr.metric = e->metric;
365 rr.ifindex = i->ifindex;
366
367 ripe_imsg_compose_rde(IMSG_ROUTE_REQUEST, nbr->peerid,
368 0, &rr, sizeof(rr));
369
370 e++;
371 }
372
373 ripe_imsg_compose_rde(IMSG_ROUTE_REQUEST_END, nbr->peerid,
374 0, NULL, 0);
375 }
376
377 void
recv_response(struct iface * i,struct nbr * nbr,u_int8_t * buf,u_int16_t len)378 recv_response(struct iface *i, struct nbr *nbr, u_int8_t *buf, u_int16_t len)
379 {
380 struct rip_route r;
381 struct rip_entry *e;
382 int l;
383
384 if (len < RIP_ENTRY_LEN) {
385 log_debug("recv_response: bad packet size, interface %s",
386 i->name);
387 return;
388 }
389
390 /* We must double check the length, because the only entry
391 * can be stripped off by authentication code
392 */
393 if (len < RIP_ENTRY_LEN) {
394 /* If there are no entries, our work is finished here */
395 return;
396 }
397
398 /* XXX again */
399 e = (struct rip_entry *)buf;
400
401 if (len > RIP_ENTRY_LEN * MAX_RIP_ENTRIES) {
402 log_debug("recv_response: packet too long\n");
403 return;
404 }
405
406 l = len - sizeof(*e);
407
408 for ( ; l >= 0; l -= RIP_ENTRY_LEN) {
409 if (ntohs(e->AFI) != AF_INET) {
410 log_debug("recv_response: AFI %d not supported\n",
411 e->AFI);
412 return;
413 }
414
415 r.address.s_addr = e->address;
416 r.mask.s_addr = e->mask;
417
418 if (e->nexthop == INADDR_ANY ||
419 ((i->addr.s_addr & i->mask.s_addr) !=
420 (e->nexthop & i->mask.s_addr)))
421 r.nexthop.s_addr = nbr->addr.s_addr;
422 else
423 r.nexthop.s_addr = e->nexthop;
424
425 r.metric = ntohl(e->metric);
426 r.ifindex = i->ifindex;
427
428 ripe_imsg_compose_rde(IMSG_ROUTE_FEED, 0, 0, &r, sizeof(r));
429
430 e++;
431 }
432 }
433