* Generate an error packet of type error * in response to bad packet ip. */
| 201 | * in response to bad packet ip. |
| 202 | */ |
| 203 | void |
| 204 | icmp_error(struct mbuf *n, int type, int code, uint32_t dest, int mtu) |
| 205 | { |
| 206 | struct ip *oip, *nip; |
| 207 | struct icmp *icp; |
| 208 | struct mbuf *m; |
| 209 | unsigned icmplen, icmpelen, nlen, oiphlen; |
| 210 | |
| 211 | KASSERT((u_int)type <= ICMP_MAXTYPE, ("%s: illegal ICMP type", |
| 212 | __func__)); |
| 213 | |
| 214 | if (type != ICMP_REDIRECT) |
| 215 | ICMPSTAT_INC(icps_error); |
| 216 | /* |
| 217 | * Don't send error: |
| 218 | * if the original packet was encrypted. |
| 219 | * if not the first fragment of message. |
| 220 | * in response to a multicast or broadcast packet. |
| 221 | * if the old packet protocol was an ICMP error message. |
| 222 | */ |
| 223 | if (n->m_flags & M_DECRYPTED) |
| 224 | goto freeit; |
| 225 | if (n->m_flags & (M_BCAST|M_MCAST)) |
| 226 | goto freeit; |
| 227 | |
| 228 | /* Drop if IP header plus 8 bytes is not contiguous in first mbuf. */ |
| 229 | if (n->m_len < sizeof(struct ip) + ICMP_MINLEN) |
| 230 | goto freeit; |
| 231 | oip = mtod(n, struct ip *); |
| 232 | oiphlen = oip->ip_hl << 2; |
| 233 | if (n->m_len < oiphlen + ICMP_MINLEN) |
| 234 | goto freeit; |
| 235 | #ifdef ICMPPRINTFS |
| 236 | if (icmpprintfs) |
| 237 | printf("icmp_error(%p, %x, %d)\n", oip, type, code); |
| 238 | #endif |
| 239 | if (oip->ip_off & htons(~(IP_MF|IP_DF))) |
| 240 | goto freeit; |
| 241 | if (oip->ip_p == IPPROTO_ICMP && type != ICMP_REDIRECT && |
| 242 | !ICMP_INFOTYPE(((struct icmp *)((caddr_t)oip + |
| 243 | oiphlen))->icmp_type)) { |
| 244 | ICMPSTAT_INC(icps_oldicmp); |
| 245 | goto freeit; |
| 246 | } |
| 247 | /* |
| 248 | * Calculate length to quote from original packet and |
| 249 | * prevent the ICMP mbuf from overflowing. |
| 250 | * Unfortunately this is non-trivial since ip_forward() |
| 251 | * sends us truncated packets. |
| 252 | */ |
| 253 | nlen = m_length(n, NULL); |
| 254 | if (oip->ip_p == IPPROTO_TCP) { |
| 255 | struct tcphdr *th; |
| 256 | int tcphlen; |
| 257 | |
| 258 | if (oiphlen + sizeof(struct tcphdr) > n->m_len && |
| 259 | n->m_next == NULL) |
| 260 | goto stdreply; |
no test coverage detected