Resolve IPv6 checksum errors with stateful inspection. According to
PR/203585 this appears to have been broken by r235959, which predates the ipfilter 5.1.2 import into FreeBSD. The IPv6 checksum calculation is incorrect. To resolve this we call in6_cksum() to do the the heavy lifting for us, through a new function ipf_pcksum6(). Should we need to revisit this area again, a DTrace probe is added to aid with future debugging. PR: 203275, 203585 MFC after: 1 month Differential Revision: https://reviews.freebsd.org/D20583
This commit is contained in:
parent
6000630b72
commit
394fa2b515
@ -3422,35 +3422,21 @@ fr_cksum(fin, ip, l4proto, l4hdr)
|
||||
sum += *sp++;
|
||||
sum += *sp++; /* ip_dst */
|
||||
sum += *sp++;
|
||||
slen = fin->fin_plen - off;
|
||||
sum += htons(slen);
|
||||
#ifdef USE_INET6
|
||||
} else if (IP_V(ip) == 6) {
|
||||
mb_t *m;
|
||||
|
||||
m = fin->fin_m;
|
||||
ip6 = (ip6_t *)ip;
|
||||
hlen = sizeof(*ip6);
|
||||
off = ((char *)fin->fin_dp - (char *)fin->fin_ip);
|
||||
sp = (u_short *)&ip6->ip6_src;
|
||||
sum += *sp++; /* ip6_src */
|
||||
sum += *sp++;
|
||||
sum += *sp++;
|
||||
sum += *sp++;
|
||||
sum += *sp++;
|
||||
sum += *sp++;
|
||||
sum += *sp++;
|
||||
sum += *sp++;
|
||||
/* This needs to be routing header aware. */
|
||||
sum += *sp++; /* ip6_dst */
|
||||
sum += *sp++;
|
||||
sum += *sp++;
|
||||
sum += *sp++;
|
||||
sum += *sp++;
|
||||
sum += *sp++;
|
||||
sum += *sp++;
|
||||
sum += *sp++;
|
||||
off = ((caddr_t)ip6 - m->m_data) + sizeof(struct ip6_hdr);
|
||||
int len = ntohs(ip6->ip6_plen) - (off - sizeof(*ip6));
|
||||
return(ipf_pcksum6(fin, ip6, off, len));
|
||||
} else {
|
||||
return 0xffff;
|
||||
}
|
||||
#endif
|
||||
slen = fin->fin_plen - off;
|
||||
sum += htons(slen);
|
||||
|
||||
switch (l4proto)
|
||||
{
|
||||
@ -6645,6 +6631,12 @@ ipf_checkl4sum(fin)
|
||||
if ((fin->fin_flx & (FI_FRAG|FI_SHORT|FI_BAD)) != 0)
|
||||
return 1;
|
||||
|
||||
DT2(l4sumo, int, fin->fin_out, int, (int)fin->fin_p);
|
||||
if (fin->fin_out == 1) {
|
||||
fin->fin_cksum = FI_CK_SUMOK;
|
||||
return 0;
|
||||
}
|
||||
|
||||
csump = NULL;
|
||||
hdrsum = 0;
|
||||
dosum = 0;
|
||||
@ -6696,7 +6688,11 @@ ipf_checkl4sum(fin)
|
||||
}
|
||||
#endif
|
||||
DT2(l4sums, u_short, hdrsum, u_short, sum);
|
||||
#ifdef USE_INET6
|
||||
if (hdrsum == sum || (sum == 0 && fin->fin_p == IPPROTO_ICMPV6)) {
|
||||
#else
|
||||
if (hdrsum == sum) {
|
||||
#endif
|
||||
fin->fin_cksum = FI_CK_SUMOK;
|
||||
return 0;
|
||||
}
|
||||
|
@ -1836,6 +1836,10 @@ extern int ipf_matchicmpqueryreply __P((int, icmpinfo_t *,
|
||||
struct icmp *, int));
|
||||
extern u_32_t ipf_newisn __P((fr_info_t *));
|
||||
extern u_int ipf_pcksum __P((fr_info_t *, int, u_int));
|
||||
#ifdef USE_INET6
|
||||
extern u_int ipf_pcksum6 __P((fr_info_t *, ip6_t *,
|
||||
u_int32_t, u_int32_t));
|
||||
#endif
|
||||
extern void ipf_rule_expire __P((ipf_main_softc_t *));
|
||||
extern int ipf_scanlist __P((fr_info_t *, u_32_t));
|
||||
extern frentry_t *ipf_srcgrpmap __P((fr_info_t *, u_32_t *));
|
||||
|
@ -1446,3 +1446,56 @@ ipf_pcksum(fin, hlen, sum)
|
||||
sum2 = ~sum & 0xffff;
|
||||
return sum2;
|
||||
}
|
||||
|
||||
#ifdef USE_INET6
|
||||
#ifdef _KERNEL
|
||||
u_int
|
||||
ipf_pcksum6(fin, ip6, off, len)
|
||||
fr_info_t *fin;
|
||||
ip6_t *ip6;
|
||||
u_int32_t off;
|
||||
u_int32_t len;
|
||||
{
|
||||
struct mbuf *m;
|
||||
int sum;
|
||||
|
||||
m = fin->fin_m;
|
||||
if (m->m_len < sizeof(struct ip6_hdr)) {
|
||||
return 0xffff;
|
||||
}
|
||||
|
||||
sum = in6_cksum(m, ip6->ip6_nxt, off, len);
|
||||
return(sum);
|
||||
}
|
||||
#else
|
||||
u_int
|
||||
ipf_pcksum6(fin, ip6, off, len)
|
||||
fr_info_t *fin;
|
||||
ip6_t *ip6;
|
||||
u_int32_t off;
|
||||
u_int32_t len;
|
||||
{
|
||||
u_short *sp;
|
||||
u_int sum;
|
||||
|
||||
sp = (u_short *)&ip6->ip6_src;
|
||||
sum = *sp++; /* ip6_src */
|
||||
sum += *sp++;
|
||||
sum += *sp++;
|
||||
sum += *sp++;
|
||||
sum += *sp++;
|
||||
sum += *sp++;
|
||||
sum += *sp++;
|
||||
sum += *sp++;
|
||||
sum += *sp++; /* ip6_dst */
|
||||
sum += *sp++;
|
||||
sum += *sp++;
|
||||
sum += *sp++;
|
||||
sum += *sp++;
|
||||
sum += *sp++;
|
||||
sum += *sp++;
|
||||
sum += *sp++;
|
||||
return(ipf_pcksum(fin, off, sum));
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
Loading…
x
Reference in New Issue
Block a user