1*35f7e862Sclaudio /* $OpenBSD: report.c,v 1.12 2023/06/26 10:08:56 claudio Exp $ */
2978e5cffSnorby
3978e5cffSnorby /*
4978e5cffSnorby * Copyright (c) 2005, 2006 Esben Norby <norby@openbsd.org>
5978e5cffSnorby *
6978e5cffSnorby * Permission to use, copy, modify, and distribute this software for any
7978e5cffSnorby * purpose with or without fee is hereby granted, provided that the above
8978e5cffSnorby * copyright notice and this permission notice appear in all copies.
9978e5cffSnorby *
10978e5cffSnorby * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11978e5cffSnorby * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12978e5cffSnorby * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13978e5cffSnorby * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14978e5cffSnorby * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15978e5cffSnorby * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16978e5cffSnorby * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17978e5cffSnorby */
18978e5cffSnorby
19978e5cffSnorby #include <sys/types.h>
20978e5cffSnorby #include <sys/socket.h>
21978e5cffSnorby #include <netinet/in.h>
22978e5cffSnorby #include <netinet/ip.h>
23978e5cffSnorby #include <arpa/inet.h>
24978e5cffSnorby
25978e5cffSnorby #include <stdlib.h>
26b53a5054Smmcc #include <string.h>
27978e5cffSnorby
28978e5cffSnorby #include "igmp.h"
29978e5cffSnorby #include "dvmrpd.h"
30978e5cffSnorby #include "dvmrp.h"
31978e5cffSnorby #include "dvmrpe.h"
32978e5cffSnorby #include "log.h"
33978e5cffSnorby
34978e5cffSnorby extern struct dvmrpd_conf *deconf;
35978e5cffSnorby
3650b67c3fSmichele void rr_list_remove(struct route_report *);
37978e5cffSnorby
38978e5cffSnorby /* DVMRP report packet handling */
39978e5cffSnorby int
send_report(struct iface * iface,struct in_addr addr,void * data,int len)40978e5cffSnorby send_report(struct iface *iface, struct in_addr addr, void *data, int len)
41978e5cffSnorby {
42978e5cffSnorby struct sockaddr_in dst;
43e39620e5Snicm struct ibuf *buf;
44978e5cffSnorby int ret = 0;
45978e5cffSnorby
46978e5cffSnorby log_debug("send_report: interface %s addr %s",
47978e5cffSnorby iface->name, inet_ntoa(addr));
48978e5cffSnorby
49978e5cffSnorby if (iface->passive)
50978e5cffSnorby return (0);
51978e5cffSnorby
52e39620e5Snicm if ((buf = ibuf_open(iface->mtu - sizeof(struct ip))) == NULL)
53978e5cffSnorby fatal("send_report");
54978e5cffSnorby
55978e5cffSnorby /* DVMRP header */
56978e5cffSnorby if (gen_dvmrp_hdr(buf, iface, DVMRP_CODE_REPORT))
57978e5cffSnorby goto fail;
58978e5cffSnorby
59e39620e5Snicm ibuf_add(buf, data, len);
60978e5cffSnorby
61978e5cffSnorby dst.sin_family = AF_INET;
62978e5cffSnorby dst.sin_len = sizeof(struct sockaddr_in);
63978e5cffSnorby dst.sin_addr.s_addr = addr.s_addr;
64978e5cffSnorby
65*35f7e862Sclaudio ret = send_packet(iface, buf, &dst);
66e39620e5Snicm ibuf_free(buf);
67978e5cffSnorby return (ret);
68978e5cffSnorby fail:
69978e5cffSnorby log_warn("send_report");
70e39620e5Snicm ibuf_free(buf);
71978e5cffSnorby return (-1);
72978e5cffSnorby }
73978e5cffSnorby
74978e5cffSnorby void
recv_report(struct nbr * nbr,char * buf,u_int16_t len)75978e5cffSnorby recv_report(struct nbr *nbr, char *buf, u_int16_t len)
76978e5cffSnorby {
77978e5cffSnorby struct route_report rr;
78978e5cffSnorby u_int32_t netid, netmask;
79978e5cffSnorby u_int8_t metric, netid_len, prefixlen;
80978e5cffSnorby
81978e5cffSnorby log_debug("recv_report: neighbor ID %s", inet_ntoa(nbr->id));
82978e5cffSnorby
83978e5cffSnorby if ((nbr->state != NBR_STA_2_WAY) && (!nbr->compat)) {
84978e5cffSnorby log_warnx("recv_report: neighbor %s not in state %s",
85978e5cffSnorby inet_ntoa(nbr->id), "2-WAY");
86978e5cffSnorby return;
87978e5cffSnorby }
88978e5cffSnorby
89978e5cffSnorby /* parse route report */
90978e5cffSnorby do {
91978e5cffSnorby /*
92978e5cffSnorby * get netmask
93978e5cffSnorby *
94978e5cffSnorby * The netmask in a DVMRP report is only represented by 3 bytes,
95978e5cffSnorby * to cope with that we read 4 bytes and shift 8 bits.
96978e5cffSnorby * The most significant part of the mask is always 255.
97978e5cffSnorby */
98978e5cffSnorby
99978e5cffSnorby /* read four bytes */
100978e5cffSnorby memcpy(&netmask, buf, sizeof(netmask));
101978e5cffSnorby /* ditch one byte, since we only need three */
102acfb6403Snorby netmask = ntohl(netmask) >> 8;
103acfb6403Snorby netmask = htonl(netmask);
104acfb6403Snorby
105978e5cffSnorby /* set the highest byte to 255 */
1068b293cb2Smichele netmask |= htonl(0xff000000);
107978e5cffSnorby buf += 3;
108978e5cffSnorby len -= 3;
109978e5cffSnorby
110978e5cffSnorby prefixlen = mask2prefixlen(netmask);
11113d89169Snorby netid_len = PREFIX_SIZE(prefixlen);
112978e5cffSnorby
113978e5cffSnorby do {
114978e5cffSnorby /*
115978e5cffSnorby * get netid
116978e5cffSnorby *
117978e5cffSnorby * The length of the netid is depending on the above
118978e5cffSnorby * netmask.
119978e5cffSnorby * Read 4 bytes and use the netmask from above to
120978e5cffSnorby * determine the netid.
121978e5cffSnorby */
122978e5cffSnorby memcpy(&netid, buf, sizeof(netid));
1238b293cb2Smichele netid &= netmask;
1248b293cb2Smichele
125978e5cffSnorby buf += netid_len;
126978e5cffSnorby len -= netid_len;
127978e5cffSnorby
128978e5cffSnorby /* get metric */
129978e5cffSnorby memcpy(&metric, buf, sizeof(metric));
130978e5cffSnorby buf += sizeof(metric);
131978e5cffSnorby len -= sizeof(metric);
132978e5cffSnorby
133978e5cffSnorby rr.net.s_addr = netid;
134978e5cffSnorby rr.mask.s_addr = netmask;
135978e5cffSnorby rr.nexthop = nbr->id;
136a2ed222dSmichele rr.metric = (metric & METRIC_MASK);
137978e5cffSnorby
138978e5cffSnorby /* ifindex */
139978e5cffSnorby rr.ifindex = nbr->iface->ifindex;
140978e5cffSnorby
141978e5cffSnorby /* send route report to RDE */
142978e5cffSnorby dvmrpe_imsg_compose_rde(IMSG_ROUTE_REPORT, nbr->peerid,
143978e5cffSnorby 0, &rr, sizeof(rr));
144978e5cffSnorby
145978e5cffSnorby } while (!(metric & LAST_MASK) && (len > 0));
146978e5cffSnorby } while (len > 0);
147978e5cffSnorby
148978e5cffSnorby return;
149978e5cffSnorby }
150978e5cffSnorby
151978e5cffSnorby /* timers */
152978e5cffSnorby void
report_timer(int fd,short event,void * arg)153978e5cffSnorby report_timer(int fd, short event, void *arg)
154978e5cffSnorby {
155978e5cffSnorby struct timeval tv;
156978e5cffSnorby
157978e5cffSnorby /* request full route report */
158978e5cffSnorby dvmrpe_imsg_compose_rde(IMSG_FULL_ROUTE_REPORT, 0, 0, NULL, 0);
159978e5cffSnorby
160978e5cffSnorby /* restart report timer */
161978e5cffSnorby timerclear(&tv);
162978e5cffSnorby tv.tv_sec = ROUTE_REPORT_INTERVAL;
163978e5cffSnorby evtimer_add(&deconf->report_timer, &tv);
164978e5cffSnorby }
165978e5cffSnorby
166978e5cffSnorby int
start_report_timer(void)167978e5cffSnorby start_report_timer(void)
168978e5cffSnorby {
169978e5cffSnorby struct timeval tv;
170978e5cffSnorby
171978e5cffSnorby timerclear(&tv);
172978e5cffSnorby tv.tv_sec = MIN_FLASH_UPDATE_INTERVAL; /* XXX safe?? */
173978e5cffSnorby return (evtimer_add(&deconf->report_timer, &tv));
174978e5cffSnorby }
175978e5cffSnorby
176978e5cffSnorby int
stop_report_timer(void)177978e5cffSnorby stop_report_timer(void)
178978e5cffSnorby {
179978e5cffSnorby return (evtimer_del(&deconf->report_timer));
180978e5cffSnorby }
181978e5cffSnorby
182978e5cffSnorby /* route report list */
183978e5cffSnorby void
rr_list_add(struct rr_head * rr_list,struct route_report * rr)184978e5cffSnorby rr_list_add(struct rr_head *rr_list, struct route_report *rr)
185978e5cffSnorby {
186978e5cffSnorby struct rr_entry *le;
187978e5cffSnorby
188978e5cffSnorby if (rr == NULL)
189978e5cffSnorby fatalx("rr_list_add: no route report");
190978e5cffSnorby
191978e5cffSnorby if ((le = calloc(1, sizeof(*le))) == NULL)
192978e5cffSnorby fatal("rr_list_add");
193978e5cffSnorby
194978e5cffSnorby TAILQ_INSERT_TAIL(rr_list, le, entry);
195978e5cffSnorby le->re = rr;
19650b67c3fSmichele rr->refcount++;
19750b67c3fSmichele }
19850b67c3fSmichele
19950b67c3fSmichele void
rr_list_remove(struct route_report * rr)20050b67c3fSmichele rr_list_remove(struct route_report *rr)
20150b67c3fSmichele {
20250b67c3fSmichele if (--rr->refcount == 0)
20350b67c3fSmichele free(rr);
204978e5cffSnorby }
205978e5cffSnorby
206978e5cffSnorby void
rr_list_clr(struct rr_head * rr_list)207978e5cffSnorby rr_list_clr(struct rr_head *rr_list)
208978e5cffSnorby {
209978e5cffSnorby struct rr_entry *le;
210978e5cffSnorby
211978e5cffSnorby while ((le = TAILQ_FIRST(rr_list)) != NULL) {
212978e5cffSnorby TAILQ_REMOVE(rr_list, le, entry);
21350b67c3fSmichele rr_list_remove(le->re);
214978e5cffSnorby free(le);
215978e5cffSnorby }
216978e5cffSnorby }
217978e5cffSnorby
218978e5cffSnorby void
rr_list_send(struct rr_head * rr_list,struct iface * xiface,struct nbr * nbr)219978e5cffSnorby rr_list_send(struct rr_head *rr_list, struct iface *xiface, struct nbr *nbr)
220978e5cffSnorby {
221978e5cffSnorby struct rr_entry *le, *le2;
222e39620e5Snicm struct ibuf *buf;
223978e5cffSnorby struct iface *iface;
224978e5cffSnorby struct in_addr addr;
225978e5cffSnorby u_int32_t netid, netmask;
226978e5cffSnorby u_int8_t metric, netid_len, prefixlen;
227978e5cffSnorby
228978e5cffSnorby /* set destination */
229978e5cffSnorby if (xiface == NULL) {
230978e5cffSnorby /* directly to a nbr */
231978e5cffSnorby iface = nbr->iface;
232978e5cffSnorby addr = nbr->addr;
233978e5cffSnorby } else {
234978e5cffSnorby /* multicast on interface */
235978e5cffSnorby iface = xiface;
236978e5cffSnorby inet_aton(AllDVMRPRouters, &addr);
237978e5cffSnorby }
238978e5cffSnorby
239978e5cffSnorby while (!TAILQ_EMPTY(rr_list)) {
240e39620e5Snicm if ((buf = ibuf_open(iface->mtu - sizeof(struct ip))) == NULL)
241978e5cffSnorby fatal("rr_list_send");
242978e5cffSnorby
243978e5cffSnorby prefixlen = 0;
244978e5cffSnorby while (((le = TAILQ_FIRST(rr_list)) != NULL) &&
245*35f7e862Sclaudio (ibuf_size(buf) < 1000)) {
246978e5cffSnorby /* netmask */
247978e5cffSnorby netmask = le->re->mask.s_addr;
248978e5cffSnorby if (prefixlen != mask2prefixlen(netmask)) {
249978e5cffSnorby prefixlen = mask2prefixlen(netmask);
250acfb6403Snorby netmask = ntohl(netmask) << 8;
251acfb6403Snorby netmask = htonl(netmask);
252e39620e5Snicm ibuf_add(buf, &netmask, 3);
253978e5cffSnorby }
25413d89169Snorby netid_len = PREFIX_SIZE(prefixlen);
255978e5cffSnorby
256978e5cffSnorby /* netid */
257978e5cffSnorby netid = le->re->net.s_addr;
258e39620e5Snicm ibuf_add(buf, &netid, netid_len);
259978e5cffSnorby
260978e5cffSnorby /* metric */
261978e5cffSnorby if (iface->ifindex == le->re->ifindex)
262978e5cffSnorby /* poison reverse */
263978e5cffSnorby metric = le->re->metric + INFINITY_METRIC;
264978e5cffSnorby else
265978e5cffSnorby metric = le->re->metric;
266978e5cffSnorby
267978e5cffSnorby /*
268978e5cffSnorby * determine if we need to flag last entry with current
269978e5cffSnorby * netmask.
270978e5cffSnorby */
271978e5cffSnorby le2 = TAILQ_NEXT(le, entry);
272978e5cffSnorby if (le2 != NULL) {
273978e5cffSnorby if (mask2prefixlen(le2->re->mask.s_addr) !=
274978e5cffSnorby prefixlen)
275978e5cffSnorby metric = metric | LAST_MASK;
276978e5cffSnorby } else {
277978e5cffSnorby metric = metric | LAST_MASK;
278978e5cffSnorby }
279978e5cffSnorby
280e39620e5Snicm ibuf_add(buf, &metric, sizeof(metric));
281978e5cffSnorby
282978e5cffSnorby TAILQ_REMOVE(rr_list, le, entry);
28350b67c3fSmichele rr_list_remove(le->re);
284978e5cffSnorby free(le);
285978e5cffSnorby }
286*35f7e862Sclaudio send_report(iface, addr, ibuf_data(buf), ibuf_size(buf));
287e39620e5Snicm ibuf_free(buf);
288978e5cffSnorby }
289978e5cffSnorby }
290