File: | src/usr.sbin/dvmrpd/report.c |
Warning: | line 247, column 14 Use of memory after it is freed |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* $OpenBSD: report.c,v 1.12 2023/06/26 10:08:56 claudio Exp $ */ | |||
2 | ||||
3 | /* | |||
4 | * Copyright (c) 2005, 2006 Esben Norby <norby@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 <netinet/in.h> | |||
22 | #include <netinet/ip.h> | |||
23 | #include <arpa/inet.h> | |||
24 | ||||
25 | #include <stdlib.h> | |||
26 | #include <string.h> | |||
27 | ||||
28 | #include "igmp.h" | |||
29 | #include "dvmrpd.h" | |||
30 | #include "dvmrp.h" | |||
31 | #include "dvmrpe.h" | |||
32 | #include "log.h" | |||
33 | ||||
34 | extern struct dvmrpd_conf *deconf; | |||
35 | ||||
36 | void rr_list_remove(struct route_report *); | |||
37 | ||||
38 | /* DVMRP report packet handling */ | |||
39 | int | |||
40 | send_report(struct iface *iface, struct in_addr addr, void *data, int len) | |||
41 | { | |||
42 | struct sockaddr_in dst; | |||
43 | struct ibuf *buf; | |||
44 | int ret = 0; | |||
45 | ||||
46 | log_debug("send_report: interface %s addr %s", | |||
47 | iface->name, inet_ntoa(addr)); | |||
48 | ||||
49 | if (iface->passive) | |||
50 | return (0); | |||
51 | ||||
52 | if ((buf = ibuf_open(iface->mtu - sizeof(struct ip))) == NULL((void *)0)) | |||
53 | fatal("send_report"); | |||
54 | ||||
55 | /* DVMRP header */ | |||
56 | if (gen_dvmrp_hdr(buf, iface, DVMRP_CODE_REPORT0x02)) | |||
57 | goto fail; | |||
58 | ||||
59 | ibuf_add(buf, data, len); | |||
60 | ||||
61 | dst.sin_family = AF_INET2; | |||
62 | dst.sin_len = sizeof(struct sockaddr_in); | |||
63 | dst.sin_addr.s_addr = addr.s_addr; | |||
64 | ||||
65 | ret = send_packet(iface, buf, &dst); | |||
66 | ibuf_free(buf); | |||
67 | return (ret); | |||
68 | fail: | |||
69 | log_warn("send_report"); | |||
70 | ibuf_free(buf); | |||
71 | return (-1); | |||
72 | } | |||
73 | ||||
74 | void | |||
75 | recv_report(struct nbr *nbr, char *buf, u_int16_t len) | |||
76 | { | |||
77 | struct route_report rr; | |||
78 | u_int32_t netid, netmask; | |||
79 | u_int8_t metric, netid_len, prefixlen; | |||
80 | ||||
81 | log_debug("recv_report: neighbor ID %s", inet_ntoa(nbr->id)); | |||
82 | ||||
83 | if ((nbr->state != NBR_STA_2_WAY0x04) && (!nbr->compat)) { | |||
84 | log_warnx("recv_report: neighbor %s not in state %s", | |||
85 | inet_ntoa(nbr->id), "2-WAY"); | |||
86 | return; | |||
87 | } | |||
88 | ||||
89 | /* parse route report */ | |||
90 | do { | |||
91 | /* | |||
92 | * get netmask | |||
93 | * | |||
94 | * The netmask in a DVMRP report is only represented by 3 bytes, | |||
95 | * to cope with that we read 4 bytes and shift 8 bits. | |||
96 | * The most significant part of the mask is always 255. | |||
97 | */ | |||
98 | ||||
99 | /* read four bytes */ | |||
100 | memcpy(&netmask, buf, sizeof(netmask)); | |||
101 | /* ditch one byte, since we only need three */ | |||
102 | netmask = ntohl(netmask)(__uint32_t)(__builtin_constant_p(netmask) ? (__uint32_t)(((__uint32_t )(netmask) & 0xff) << 24 | ((__uint32_t)(netmask) & 0xff00) << 8 | ((__uint32_t)(netmask) & 0xff0000) >> 8 | ((__uint32_t)(netmask) & 0xff000000) >> 24) : __swap32md (netmask)) >> 8; | |||
103 | netmask = htonl(netmask)(__uint32_t)(__builtin_constant_p(netmask) ? (__uint32_t)(((__uint32_t )(netmask) & 0xff) << 24 | ((__uint32_t)(netmask) & 0xff00) << 8 | ((__uint32_t)(netmask) & 0xff0000) >> 8 | ((__uint32_t)(netmask) & 0xff000000) >> 24) : __swap32md (netmask)); | |||
104 | ||||
105 | /* set the highest byte to 255 */ | |||
106 | netmask |= htonl(0xff000000)(__uint32_t)(__builtin_constant_p(0xff000000) ? (__uint32_t)( ((__uint32_t)(0xff000000) & 0xff) << 24 | ((__uint32_t )(0xff000000) & 0xff00) << 8 | ((__uint32_t)(0xff000000 ) & 0xff0000) >> 8 | ((__uint32_t)(0xff000000) & 0xff000000) >> 24) : __swap32md(0xff000000)); | |||
107 | buf += 3; | |||
108 | len -= 3; | |||
109 | ||||
110 | prefixlen = mask2prefixlen(netmask); | |||
111 | netid_len = PREFIX_SIZE(prefixlen)(((prefixlen) + 7) / 8); | |||
112 | ||||
113 | do { | |||
114 | /* | |||
115 | * get netid | |||
116 | * | |||
117 | * The length of the netid is depending on the above | |||
118 | * netmask. | |||
119 | * Read 4 bytes and use the netmask from above to | |||
120 | * determine the netid. | |||
121 | */ | |||
122 | memcpy(&netid, buf, sizeof(netid)); | |||
123 | netid &= netmask; | |||
124 | ||||
125 | buf += netid_len; | |||
126 | len -= netid_len; | |||
127 | ||||
128 | /* get metric */ | |||
129 | memcpy(&metric, buf, sizeof(metric)); | |||
130 | buf += sizeof(metric); | |||
131 | len -= sizeof(metric); | |||
132 | ||||
133 | rr.net.s_addr = netid; | |||
134 | rr.mask.s_addr = netmask; | |||
135 | rr.nexthop = nbr->id; | |||
136 | rr.metric = (metric & METRIC_MASK~0x80); | |||
137 | ||||
138 | /* ifindex */ | |||
139 | rr.ifindex = nbr->iface->ifindex; | |||
140 | ||||
141 | /* send route report to RDE */ | |||
142 | dvmrpe_imsg_compose_rde(IMSG_ROUTE_REPORT, nbr->peerid, | |||
143 | 0, &rr, sizeof(rr)); | |||
144 | ||||
145 | } while (!(metric & LAST_MASK0x80) && (len > 0)); | |||
146 | } while (len > 0); | |||
147 | ||||
148 | return; | |||
149 | } | |||
150 | ||||
151 | /* timers */ | |||
152 | void | |||
153 | report_timer(int fd, short event, void *arg) | |||
154 | { | |||
155 | struct timeval tv; | |||
156 | ||||
157 | /* request full route report */ | |||
158 | dvmrpe_imsg_compose_rde(IMSG_FULL_ROUTE_REPORT, 0, 0, NULL((void *)0), 0); | |||
159 | ||||
160 | /* restart report timer */ | |||
161 | timerclear(&tv)(&tv)->tv_sec = (&tv)->tv_usec = 0; | |||
162 | tv.tv_sec = ROUTE_REPORT_INTERVAL60; | |||
163 | evtimer_add(&deconf->report_timer, &tv)event_add(&deconf->report_timer, &tv); | |||
164 | } | |||
165 | ||||
166 | int | |||
167 | start_report_timer(void) | |||
168 | { | |||
169 | struct timeval tv; | |||
170 | ||||
171 | timerclear(&tv)(&tv)->tv_sec = (&tv)->tv_usec = 0; | |||
172 | tv.tv_sec = MIN_FLASH_UPDATE_INTERVAL5; /* XXX safe?? */ | |||
173 | return (evtimer_add(&deconf->report_timer, &tv)event_add(&deconf->report_timer, &tv)); | |||
174 | } | |||
175 | ||||
176 | int | |||
177 | stop_report_timer(void) | |||
178 | { | |||
179 | return (evtimer_del(&deconf->report_timer)event_del(&deconf->report_timer)); | |||
180 | } | |||
181 | ||||
182 | /* route report list */ | |||
183 | void | |||
184 | rr_list_add(struct rr_head *rr_list, struct route_report *rr) | |||
185 | { | |||
186 | struct rr_entry *le; | |||
187 | ||||
188 | if (rr == NULL((void *)0)) | |||
189 | fatalx("rr_list_add: no route report"); | |||
190 | ||||
191 | if ((le = calloc(1, sizeof(*le))) == NULL((void *)0)) | |||
192 | fatal("rr_list_add"); | |||
193 | ||||
194 | TAILQ_INSERT_TAIL(rr_list, le, entry)do { (le)->entry.tqe_next = ((void *)0); (le)->entry.tqe_prev = (rr_list)->tqh_last; *(rr_list)->tqh_last = (le); (rr_list )->tqh_last = &(le)->entry.tqe_next; } while (0); | |||
195 | le->re = rr; | |||
196 | rr->refcount++; | |||
197 | } | |||
198 | ||||
199 | void | |||
200 | rr_list_remove(struct route_report *rr) | |||
201 | { | |||
202 | if (--rr->refcount == 0) | |||
203 | free(rr); | |||
204 | } | |||
205 | ||||
206 | void | |||
207 | rr_list_clr(struct rr_head *rr_list) | |||
208 | { | |||
209 | struct rr_entry *le; | |||
210 | ||||
211 | while ((le = TAILQ_FIRST(rr_list)((rr_list)->tqh_first)) != NULL((void *)0)) { | |||
212 | TAILQ_REMOVE(rr_list, le, entry)do { if (((le)->entry.tqe_next) != ((void *)0)) (le)->entry .tqe_next->entry.tqe_prev = (le)->entry.tqe_prev; else ( rr_list)->tqh_last = (le)->entry.tqe_prev; *(le)->entry .tqe_prev = (le)->entry.tqe_next; ; ; } while (0); | |||
213 | rr_list_remove(le->re); | |||
214 | free(le); | |||
215 | } | |||
216 | } | |||
217 | ||||
218 | void | |||
219 | rr_list_send(struct rr_head *rr_list, struct iface *xiface, struct nbr *nbr) | |||
220 | { | |||
221 | struct rr_entry *le, *le2; | |||
222 | struct ibuf *buf; | |||
223 | struct iface *iface; | |||
224 | struct in_addr addr; | |||
225 | u_int32_t netid, netmask; | |||
226 | u_int8_t metric, netid_len, prefixlen; | |||
227 | ||||
228 | /* set destination */ | |||
229 | if (xiface == NULL((void *)0)) { | |||
| ||||
230 | /* directly to a nbr */ | |||
231 | iface = nbr->iface; | |||
232 | addr = nbr->addr; | |||
233 | } else { | |||
234 | /* multicast on interface */ | |||
235 | iface = xiface; | |||
236 | inet_aton(AllDVMRPRouters"224.0.0.4", &addr); | |||
237 | } | |||
238 | ||||
239 | while (!TAILQ_EMPTY(rr_list)(((rr_list)->tqh_first) == ((void *)0))) { | |||
240 | if ((buf = ibuf_open(iface->mtu - sizeof(struct ip))) == NULL((void *)0)) | |||
241 | fatal("rr_list_send"); | |||
242 | ||||
243 | prefixlen = 0; | |||
244 | while (((le = TAILQ_FIRST(rr_list)((rr_list)->tqh_first)) != NULL((void *)0)) && | |||
245 | (ibuf_size(buf) < 1000)) { | |||
246 | /* netmask */ | |||
247 | netmask = le->re->mask.s_addr; | |||
| ||||
248 | if (prefixlen != mask2prefixlen(netmask)) { | |||
249 | prefixlen = mask2prefixlen(netmask); | |||
250 | netmask = ntohl(netmask)(__uint32_t)(__builtin_constant_p(netmask) ? (__uint32_t)(((__uint32_t )(netmask) & 0xff) << 24 | ((__uint32_t)(netmask) & 0xff00) << 8 | ((__uint32_t)(netmask) & 0xff0000) >> 8 | ((__uint32_t)(netmask) & 0xff000000) >> 24) : __swap32md (netmask)) << 8; | |||
251 | netmask = htonl(netmask)(__uint32_t)(__builtin_constant_p(netmask) ? (__uint32_t)(((__uint32_t )(netmask) & 0xff) << 24 | ((__uint32_t)(netmask) & 0xff00) << 8 | ((__uint32_t)(netmask) & 0xff0000) >> 8 | ((__uint32_t)(netmask) & 0xff000000) >> 24) : __swap32md (netmask)); | |||
252 | ibuf_add(buf, &netmask, 3); | |||
253 | } | |||
254 | netid_len = PREFIX_SIZE(prefixlen)(((prefixlen) + 7) / 8); | |||
255 | ||||
256 | /* netid */ | |||
257 | netid = le->re->net.s_addr; | |||
258 | ibuf_add(buf, &netid, netid_len); | |||
259 | ||||
260 | /* metric */ | |||
261 | if (iface->ifindex == le->re->ifindex) | |||
262 | /* poison reverse */ | |||
263 | metric = le->re->metric + INFINITY_METRIC31; | |||
264 | else | |||
265 | metric = le->re->metric; | |||
266 | ||||
267 | /* | |||
268 | * determine if we need to flag last entry with current | |||
269 | * netmask. | |||
270 | */ | |||
271 | le2 = TAILQ_NEXT(le, entry)((le)->entry.tqe_next); | |||
272 | if (le2 != NULL((void *)0)) { | |||
273 | if (mask2prefixlen(le2->re->mask.s_addr) != | |||
274 | prefixlen) | |||
275 | metric = metric | LAST_MASK0x80; | |||
276 | } else { | |||
277 | metric = metric | LAST_MASK0x80; | |||
278 | } | |||
279 | ||||
280 | ibuf_add(buf, &metric, sizeof(metric)); | |||
281 | ||||
282 | TAILQ_REMOVE(rr_list, le, entry)do { if (((le)->entry.tqe_next) != ((void *)0)) (le)->entry .tqe_next->entry.tqe_prev = (le)->entry.tqe_prev; else ( rr_list)->tqh_last = (le)->entry.tqe_prev; *(le)->entry .tqe_prev = (le)->entry.tqe_next; ; ; } while (0); | |||
283 | rr_list_remove(le->re); | |||
284 | free(le); | |||
285 | } | |||
286 | send_report(iface, addr, ibuf_data(buf), ibuf_size(buf)); | |||
287 | ibuf_free(buf); | |||
288 | } | |||
289 | } |