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,
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;
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;
}
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++;
#define IGMP_DEFAULT_VERSION (3)
+#define IGMP_GET_INT16(ptr, output) \
+ do { \
+ output = *(ptr) << 8; \
+ output |= *((ptr) + 1); \
+ } while (0)
+
struct igmp_join {
struct in_addr group_addr;
struct in_addr source_addr;
void pim_igmp_other_querier_timer_on(struct igmp_sock *igmp);
void pim_igmp_other_querier_timer_off(struct igmp_sock *igmp);
+int igmp_validate_checksum(char *igmp_msg, int igmp_msg_len);
+
#define IGMP_SOURCE_MASK_FORWARDING (1 << 0)
#define IGMP_SOURCE_MASK_DELETE (1 << 1)
#define IGMP_SOURCE_MASK_SEND (1 << 2)
return -1;
}
+ if (igmp_validate_checksum(igmp_msg, igmp_msg_len) == -1) {
+ zlog_warn(
+ "Recv IGMPv2 REPORT from %s on %s: size=%d with invalid checksum",
+ from_str, ifp->name, igmp_msg_len);
+ return -1;
+ }
+
/* Collecting IGMP Rx stats */
igmp->rx_stats.report_v2++;
return -1;
}
+ if (igmp_validate_checksum(igmp_msg, igmp_msg_len) == -1) {
+ zlog_warn(
+ "Recv IGMPv2 LEAVE from %s on %s with invalid checksum",
+ from_str, ifp->name);
+ return -1;
+ }
+
/* Collecting IGMP Rx stats */
igmp->rx_stats.leave_v2++;
int igmp_v3_recv_report(struct igmp_sock *igmp, struct in_addr from,
const char *from_str, char *igmp_msg, int igmp_msg_len)
{
- uint16_t recv_checksum;
- uint16_t checksum;
int num_groups;
uint8_t *group_record;
uint8_t *report_pastend = (uint8_t *)igmp_msg + igmp_msg_len;
return -1;
}
- 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 report v3 from %s on %s: checksum mismatch: received=%x computed=%x",
- from_str, ifp->name, recv_checksum, checksum);
+ "Recv IGMPv3 report from %s on %s with invalid checksum",
+ from_str, ifp->name);
return -1;
}
if (PIM_DEBUG_IGMP_PACKETS) {
zlog_debug(
- "Recv IGMP report v3 from %s on %s: size=%d checksum=%x groups=%d",
- from_str, ifp->name, igmp_msg_len, checksum,
- num_groups);
+ "Recv IGMP report v3 from %s on %s: size=%d groups=%d",
+ from_str, ifp->name, igmp_msg_len, num_groups);
}
group_record = (uint8_t *)igmp_msg + IGMP_V3_REPORT_GROUPPRECORD_OFFSET;