diff options
Diffstat (limited to 'pimd/pim_igmp.c')
| -rw-r--r-- | pimd/pim_igmp.c | 43 |
1 files changed, 31 insertions, 12 deletions
diff --git a/pimd/pim_igmp.c b/pimd/pim_igmp.c index 19d7817577..9924e335b0 100644 --- a/pimd/pim_igmp.c +++ b/pimd/pim_igmp.c @@ -270,6 +270,27 @@ void pim_igmp_other_querier_timer_off(struct igmp_sock *igmp) THREAD_OFF(igmp->t_other_querier_timer); } +int igmp_validate_checksum(char *igmp_msg, int igmp_msg_len) +{ + uint16_t recv_checksum; + uint16_t checksum; + + IGMP_GET_INT16((unsigned char *)(igmp_msg + IGMP_CHECKSUM_OFFSET), + recv_checksum); + + /* Clear the checksum field */ + memset(igmp_msg + IGMP_CHECKSUM_OFFSET, 0, 2); + + checksum = in_cksum(igmp_msg, igmp_msg_len); + if (ntohs(checksum) != recv_checksum) { + zlog_warn("Invalid checksum received %x, calculated %x", + recv_checksum, ntohs(checksum)); + return -1; + } + + return 0; +} + static int igmp_recv_query(struct igmp_sock *igmp, int query_version, int max_resp_code, struct in_addr from, const char *from_str, char *igmp_msg, @@ -278,8 +299,6 @@ static int igmp_recv_query(struct igmp_sock *igmp, int query_version, struct interface *ifp; struct pim_interface *pim_ifp; struct in_addr group_addr; - uint16_t recv_checksum; - uint16_t checksum; if (igmp->mtrace_only) return 0; @@ -289,17 +308,10 @@ static int igmp_recv_query(struct igmp_sock *igmp, int query_version, ifp = igmp->interface; pim_ifp = ifp->info; - recv_checksum = *(uint16_t *)(igmp_msg + IGMP_CHECKSUM_OFFSET); - - /* for computing checksum */ - *(uint16_t *)(igmp_msg + IGMP_CHECKSUM_OFFSET) = 0; - - checksum = in_cksum(igmp_msg, igmp_msg_len); - if (checksum != recv_checksum) { + if (igmp_validate_checksum(igmp_msg, igmp_msg_len) == -1) { zlog_warn( - "Recv IGMP query v%d from %s on %s: checksum mismatch: received=%x computed=%x", - query_version, from_str, ifp->name, recv_checksum, - checksum); + "Recv IGMP query v%d from %s on %s with invalid checksum", + query_version, from_str, ifp->name); return -1; } @@ -427,6 +439,13 @@ static int igmp_v1_recv_report(struct igmp_sock *igmp, struct in_addr from, return -1; } + if (igmp_validate_checksum(igmp_msg, igmp_msg_len) == -1) { + zlog_warn( + "Recv IGMP report v1 from %s on %s with invalid checksum", + from_str, ifp->name); + return -1; + } + /* Collecting IGMP Rx stats */ igmp->rx_stats.report_v1++; |
