| version 1.286, 2010/04/01 01:23:32 |
version 1.287, 2010/07/09 18:42:46 |
|
|
| * but it's not worth the time; just let them time out.) |
* but it's not worth the time; just let them time out.) |
| */ |
*/ |
| if (ip->ip_off & ~htons(IP_DF|IP_RF)) { |
if (ip->ip_off & ~htons(IP_DF|IP_RF)) { |
| uint16_t off; |
u_int off; |
| /* |
/* |
| * Prevent TCP blind data attacks by not allowing non-initial |
* Prevent TCP blind data attacks by not allowing non-initial |
| * fragments to start at less than 68 bytes (minimal fragment |
* fragments to start at less than 68 bytes (minimal fragment |
|
|
| IP_STATINC(IP_STAT_BADFRAGS); |
IP_STATINC(IP_STAT_BADFRAGS); |
| goto bad; |
goto bad; |
| } |
} |
| /* |
|
| * Look for queue of fragments |
|
| * of this datagram. |
|
| */ |
|
| IPQ_LOCK(); |
|
| hash = IPREASS_HASH(ip->ip_src.s_addr, ip->ip_id); |
|
| LIST_FOREACH(fp, &ipq[hash], ipq_q) { |
|
| if (ip->ip_id == fp->ipq_id && |
|
| in_hosteq(ip->ip_src, fp->ipq_src) && |
|
| in_hosteq(ip->ip_dst, fp->ipq_dst) && |
|
| ip->ip_p == fp->ipq_p) { |
|
| /* |
|
| * Make sure the TOS is matches previous |
|
| * fragments. |
|
| */ |
|
| if (ip->ip_tos != fp->ipq_tos) { |
|
| IP_STATINC(IP_STAT_BADFRAGS); |
|
| IPQ_UNLOCK(); |
|
| goto bad; |
|
| } |
|
| goto found; |
|
| } |
|
| } |
|
| fp = 0; |
|
| found: |
|
| |
|
| /* |
/* |
| * Adjust ip_len to not reflect header, |
* Adjust ip_len to not reflect header, |
|
|
| ip->ip_len = htons(ntohs(ip->ip_len) - hlen); |
ip->ip_len = htons(ntohs(ip->ip_len) - hlen); |
| mff = (ip->ip_off & htons(IP_MF)) != 0; |
mff = (ip->ip_off & htons(IP_MF)) != 0; |
| if (mff) { |
if (mff) { |
| /* |
/* |
| * Make sure that fragments have a data length |
* Make sure that fragments have a data length |
| * that's a non-zero multiple of 8 bytes. |
* that's a non-zero multiple of 8 bytes. |
| */ |
*/ |
| if (ntohs(ip->ip_len) == 0 || |
if (ntohs(ip->ip_len) == 0 || |
| (ntohs(ip->ip_len) & 0x7) != 0) { |
(ntohs(ip->ip_len) & 0x7) != 0) { |
| IP_STATINC(IP_STAT_BADFRAGS); |
IP_STATINC(IP_STAT_BADFRAGS); |
| IPQ_UNLOCK(); |
|
| goto bad; |
goto bad; |
| } |
} |
| } |
} |
| ip->ip_off = htons((ntohs(ip->ip_off) & IP_OFFMASK) << 3); |
ip->ip_off = htons((ntohs(ip->ip_off) & IP_OFFMASK) << 3); |
| |
|
| /* |
/* |
| |
* Look for queue of fragments of this datagram. |
| |
*/ |
| |
IPQ_LOCK(); |
| |
hash = IPREASS_HASH(ip->ip_src.s_addr, ip->ip_id); |
| |
LIST_FOREACH(fp, &ipq[hash], ipq_q) { |
| |
if (ip->ip_id != fp->ipq_id) |
| |
continue; |
| |
if (!in_hosteq(ip->ip_src, fp->ipq_src)) |
| |
continue; |
| |
if (!in_hosteq(ip->ip_dst, fp->ipq_dst)) |
| |
continue; |
| |
if (ip->ip_p != fp->ipq_p) |
| |
continue; |
| |
/* |
| |
* Make sure the TOS is matches previous fragments. |
| |
*/ |
| |
if (ip->ip_tos != fp->ipq_tos) { |
| |
IP_STATINC(IP_STAT_BADFRAGS); |
| |
IPQ_UNLOCK(); |
| |
goto bad; |
| |
} |
| |
break; |
| |
} |
| |
|
| |
/* |
| * If datagram marked as having more fragments |
* If datagram marked as having more fragments |
| * or if this is not the first fragment, |
* or if this is not the first fragment, |
| * attempt reassembly; if it succeeds, proceed. |
* attempt reassembly; if it succeeds, proceed. |
|
|
| ipqe->ipqe_m = m; |
ipqe->ipqe_m = m; |
| ipqe->ipqe_ip = ip; |
ipqe->ipqe_ip = ip; |
| m = ip_reass(ipqe, fp, &ipq[hash]); |
m = ip_reass(ipqe, fp, &ipq[hash]); |
| if (m == 0) { |
if (m == NULL) { |
| IPQ_UNLOCK(); |
IPQ_UNLOCK(); |
| return; |
return; |
| } |
} |
|
|
| ip = mtod(m, struct ip *); |
ip = mtod(m, struct ip *); |
| hlen = ip->ip_hl << 2; |
hlen = ip->ip_hl << 2; |
| ip->ip_len = htons(ntohs(ip->ip_len) + hlen); |
ip->ip_len = htons(ntohs(ip->ip_len) + hlen); |
| } else |
} else if (fp) { |
| if (fp) |
ip_freef(fp); |
| ip_freef(fp); |
} |
| IPQ_UNLOCK(); |
IPQ_UNLOCK(); |
| } |
} |
| |
|