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