diff options
Diffstat (limited to 'sys/net/pf.c')
-rw-r--r-- | sys/net/pf.c | 501 |
1 files changed, 351 insertions, 150 deletions
diff --git a/sys/net/pf.c b/sys/net/pf.c index d3fa2450ede..5177466a4c1 100644 --- a/sys/net/pf.c +++ b/sys/net/pf.c @@ -1,8 +1,8 @@ -/* $OpenBSD: pf.c,v 1.815 2012/11/01 07:55:56 henning Exp $ */ +/* $OpenBSD: pf.c,v 1.816 2012/11/06 12:32:41 henning Exp $ */ /* * Copyright (c) 2001 Daniel Hartmeier - * Copyright (c) 2002 - 2012 Henning Brauer <henning@openbsd.org> + * Copyright (c) 2002 - 2010 Henning Brauer * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -148,16 +148,18 @@ void pf_add_threshold(struct pf_threshold *); int pf_check_threshold(struct pf_threshold *); void pf_change_ap(struct pf_addr *, u_int16_t *, - struct pf_addr *, u_int16_t, sa_family_t, - sa_family_t); + u_int16_t *, struct pf_addr *, u_int16_t, + u_int8_t, sa_family_t, sa_family_t); int pf_modulate_sack(struct pf_pdesc *, struct pf_state_peer *); -void pf_change_a6(struct pf_addr *a, struct pf_addr *an); +void pf_change_a6(struct pf_addr *, u_int16_t *, + struct pf_addr *, u_int8_t); int pf_icmp_mapping(struct pf_pdesc *, u_int8_t, int *, int *, u_int16_t *, u_int16_t *); void pf_change_icmp(struct pf_addr *, u_int16_t *, struct pf_addr *, struct pf_addr *, u_int16_t, - sa_family_t); + u_int16_t *, u_int16_t *, u_int16_t *, + u_int8_t, sa_family_t); int pf_change_icmp_af(struct mbuf *, int, struct pf_pdesc *, struct pf_pdesc *, struct pf_addr *, struct pf_addr *, sa_family_t, @@ -1650,27 +1652,137 @@ pf_addr_wrap_neq(struct pf_addr_wrap *aw1, struct pf_addr_wrap *aw2) } } +u_int16_t +pf_cksum_fixup(u_int16_t cksum, u_int16_t old, u_int16_t new, u_int8_t udp) +{ + u_int32_t l; + + if (udp && !cksum) + return (0x0000); + l = cksum + old - new; + l = (l >> 16) + (l & 65535); + l = l & 65535; + if (udp && !l) + return (0xFFFF); + return (l); +} + void -pf_change_ap(struct pf_addr *a, u_int16_t *p, struct pf_addr *an, - u_int16_t pn, sa_family_t af, sa_family_t naf) +pf_change_ap(struct pf_addr *a, u_int16_t *p, u_int16_t *pc, + struct pf_addr *an, u_int16_t pn, u_int8_t u, sa_family_t af, + sa_family_t naf) { + struct pf_addr ao; + u_int16_t po = *p; + + PF_ACPY(&ao, a, af); if (af == naf) PF_ACPY(a, an, naf); + *p = pn; + + switch (af) { +#ifdef INET + case AF_INET: + switch (naf) { + case AF_INET: + *pc = pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup(*pc, + ao.addr16[0], an->addr16[0], u), + ao.addr16[1], an->addr16[1], u), + po, pn, u); + break; +#ifdef INET6 + case AF_INET6: + *pc = pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup( + pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup( + pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup(*pc, + ao.addr16[0], an->addr16[0], u), + ao.addr16[1], an->addr16[1], u), + 0, an->addr16[2], u), + 0, an->addr16[3], u), + 0, an->addr16[4], u), + 0, an->addr16[5], u), + 0, an->addr16[6], u), + 0, an->addr16[7], u), + po, pn, u); + break; +#endif /* INET6 */ + } + break; +#endif /* INET */ +#ifdef INET6 + case AF_INET6: + switch (naf) { +#ifdef INET + case AF_INET: + *pc = pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup( + pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup( + pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup(*pc, + ao.addr16[0], an->addr16[0], u), + ao.addr16[1], an->addr16[1], u), + ao.addr16[2], 0, u), + ao.addr16[3], 0, u), + ao.addr16[4], 0, u), + ao.addr16[5], 0, u), + ao.addr16[6], 0, u), + ao.addr16[7], 0, u), + po, pn, u); + break; +#endif /* INET */ + case AF_INET6: + *pc = pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup( + pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup( + pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup(*pc, + ao.addr16[0], an->addr16[0], u), + ao.addr16[1], an->addr16[1], u), + ao.addr16[2], an->addr16[2], u), + ao.addr16[3], an->addr16[3], u), + ao.addr16[4], an->addr16[4], u), + ao.addr16[5], an->addr16[5], u), + ao.addr16[6], an->addr16[6], u), + ao.addr16[7], an->addr16[7], u), + po, pn, u); + break; + } + break; +#endif /* INET6 */ + } } /* Changes a u_int32_t. Uses a void * so there are no align restrictions */ void -pf_change_a(void *a, u_int32_t an) +pf_change_a(void *a, u_int16_t *c, u_int32_t an, u_int8_t u) { + u_int32_t ao; + + memcpy(&ao, a, sizeof(ao)); memcpy(a, &an, sizeof(u_int32_t)); + if (c != NULL) + *c = pf_cksum_fixup(pf_cksum_fixup(*c, ao / 65536, an / 65536, + u), ao % 65536, an % 65536, u); } #ifdef INET6 void -pf_change_a6(struct pf_addr *a, struct pf_addr *an) +pf_change_a6(struct pf_addr *a, u_int16_t *c, struct pf_addr *an, u_int8_t u) { + struct pf_addr ao; + + PF_ACPY(&ao, a, AF_INET6); PF_ACPY(a, an, AF_INET6); + + if (c) + *c = pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup( + pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup( + pf_cksum_fixup(pf_cksum_fixup(*c, + ao.addr16[0], an->addr16[0], u), + ao.addr16[1], an->addr16[1], u), + ao.addr16[2], an->addr16[2], u), + ao.addr16[3], an->addr16[3], u), + ao.addr16[4], an->addr16[4], u), + ao.addr16[5], an->addr16[5], u), + ao.addr16[6], an->addr16[6], u), + ao.addr16[7], an->addr16[7], u); } #endif /* INET6 */ @@ -1859,18 +1971,81 @@ pf_icmp_mapping(struct pf_pdesc *pd, u_int8_t type, int *icmp_dir, int *multi, void pf_change_icmp(struct pf_addr *ia, u_int16_t *ip, struct pf_addr *oa, - struct pf_addr *na, u_int16_t np, sa_family_t af) + struct pf_addr *na, u_int16_t np, u_int16_t *pc, u_int16_t *h2c, + u_int16_t *ic, u_int8_t u, sa_family_t af) { - /* Change inner protocol port */ - if (ip != NULL) - *ip = np; + struct pf_addr oia, ooa; - /* Change inner ip address */ - PF_ACPY(ia, na, af); + PF_ACPY(&oia, ia, af); + if (oa) + PF_ACPY(&ooa, oa, af); + + /* Change inner protocol port, fix inner protocol checksum. */ + if (ip != NULL) { + u_int16_t oip = *ip; + u_int32_t opc; + if (pc != NULL) + opc = *pc; + *ip = np; + if (pc != NULL) + *pc = pf_cksum_fixup(*pc, oip, *ip, u); + *ic = pf_cksum_fixup(*ic, oip, *ip, 0); + if (pc != NULL) + *ic = pf_cksum_fixup(*ic, opc, *pc, 0); + } + /* Change inner ip address, fix inner ip and icmp checksums. */ + PF_ACPY(ia, na, af); + switch (af) { +#ifdef INET + case AF_INET: { + u_int32_t oh2c = *h2c; + + /* XXX just in_cksum() */ + *h2c = pf_cksum_fixup(pf_cksum_fixup(*h2c, + oia.addr16[0], ia->addr16[0], 0), + oia.addr16[1], ia->addr16[1], 0); + *ic = pf_cksum_fixup(pf_cksum_fixup(*ic, + oia.addr16[0], ia->addr16[0], 0), + oia.addr16[1], ia->addr16[1], 0); + *ic = pf_cksum_fixup(*ic, oh2c, *h2c, 0); + break; + } +#endif /* INET */ +#ifdef INET6 + case AF_INET6: + *ic = pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup( + pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup( + pf_cksum_fixup(pf_cksum_fixup(*ic, + oia.addr16[0], ia->addr16[0], u), + oia.addr16[1], ia->addr16[1], u), + oia.addr16[2], ia->addr16[2], u), + oia.addr16[3], ia->addr16[3], u), + oia.addr16[4], ia->addr16[4], u), + oia.addr16[5], ia->addr16[5], u), + oia.addr16[6], ia->addr16[6], u), + oia.addr16[7], ia->addr16[7], u); + break; +#endif /* INET6 */ + } /* Outer ip address, fix outer icmpv6 checksum, if necessary. */ - if (oa) + if (oa) { PF_ACPY(oa, na, af); +#ifdef INET6 + if (af == AF_INET6) + *ic = pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup( + pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup( + pf_cksum_fixup(pf_cksum_fixup(*ic, + ooa.addr16[0], oa->addr16[0], u), + ooa.addr16[1], oa->addr16[1], u), + ooa.addr16[2], oa->addr16[2], u), + ooa.addr16[3], oa->addr16[3], u), + ooa.addr16[4], oa->addr16[4], u), + ooa.addr16[5], oa->addr16[5], u), + ooa.addr16[6], oa->addr16[6], u), + ooa.addr16[7], oa->addr16[7], u); +#endif /* INET6 */ + } } #if INET && INET6 @@ -2114,12 +2289,28 @@ pf_translate_icmp_af(int af, void *arg) default: return (-1); } - icmp6->icmp6_type = type; - icmp6->icmp6_code = code; - /* aligns well with a icmpv4 nextmtu */ - icmp6->icmp6_mtu = htonl(mtu); - /* icmpv4 pptr is a one most significant byte */ - icmp6->icmp6_pptr = htonl(ptr << 24); + if (icmp6->icmp6_type != type) { + icmp6->icmp6_cksum = pf_cksum_fixup(icmp6->icmp6_cksum, + icmp6->icmp6_type, type, 0); + icmp6->icmp6_type = type; + } + if (icmp6->icmp6_code != code) { + icmp6->icmp6_cksum = pf_cksum_fixup(icmp6->icmp6_cksum, + icmp6->icmp6_code, code, 0); + icmp6->icmp6_code = code; + } + if (icmp6->icmp6_mtu != htonl(mtu)) { + icmp6->icmp6_cksum = pf_cksum_fixup(icmp6->icmp6_cksum, + htons(ntohl(icmp6->icmp6_mtu)), htons(mtu), 0); + /* aligns well with a icmpv4 nextmtu */ + icmp6->icmp6_mtu = htonl(mtu); + } + if (ptr >= 0 && icmp6->icmp6_pptr != htonl(ptr)) { + icmp6->icmp6_cksum = pf_cksum_fixup(icmp6->icmp6_cksum, + htons(ntohl(icmp6->icmp6_pptr)), htons(ptr), 0); + /* icmpv4 pptr is a one most significant byte */ + icmp6->icmp6_pptr = htonl(ptr << 24); + } break; case AF_INET6: icmp4 = arg; @@ -2208,10 +2399,26 @@ pf_translate_icmp_af(int af, void *arg) default: return (-1); } - icmp4->icmp_type = type; - icmp4->icmp_code = code; - icmp4->icmp_nextmtu = htons(mtu); - icmp4->icmp_void = htonl(ptr); + if (icmp4->icmp_type != type) { + icmp4->icmp_cksum = pf_cksum_fixup(icmp4->icmp_cksum, + icmp4->icmp_type, type, 0); + icmp4->icmp_type = type; + } + if (icmp4->icmp_code != code) { + icmp4->icmp_cksum = pf_cksum_fixup(icmp4->icmp_cksum, + icmp4->icmp_code, code, 0); + icmp4->icmp_code = code; + } + if (icmp4->icmp_nextmtu != htons(mtu)) { + icmp4->icmp_cksum = pf_cksum_fixup(icmp4->icmp_cksum, + icmp4->icmp_nextmtu, htons(mtu), 0); + icmp4->icmp_nextmtu = htons(mtu); + } + if (ptr >= 0 && icmp4->icmp_void != ptr) { + icmp4->icmp_cksum = pf_cksum_fixup(icmp4->icmp_cksum, + htons(icmp4->icmp_pptr), htons(ptr), 0); + icmp4->icmp_void = htonl(ptr); + } break; } @@ -2253,12 +2460,12 @@ pf_modulate_sack(struct pf_pdesc *pd, struct pf_state_peer *dst) for (i = 2; i + TCPOLEN_SACK <= olen; i += TCPOLEN_SACK) { memcpy(&sack, &opt[i], sizeof(sack)); - pf_change_a(&sack.start, + pf_change_a(&sack.start, &th->th_sum, htonl(ntohl(sack.start) - - dst->seqdiff)); - pf_change_a(&sack.end, + dst->seqdiff), 0); + pf_change_a(&sack.end, &th->th_sum, htonl(ntohl(sack.end) - - dst->seqdiff)); + dst->seqdiff), 0); memcpy(&opt[i], &sack, sizeof(sack)); } copyback = 1; @@ -3408,7 +3615,7 @@ pf_test_rule(struct pf_pdesc *pd, struct pf_rule **rm, struct pf_state **sm, sk->port[pd->af == pd->naf ? pd->sidx : pd->didx], &sk->addr[pd->af == pd->naf ? pd->didx : pd->sidx], sk->port[pd->af == pd->naf ? pd->didx : pd->sidx], - virtual_type, icmp_dir, pd->m); + virtual_type, icmp_dir); } } else { while ((ri = SLIST_FIRST(&rules))) { @@ -3417,11 +3624,9 @@ pf_test_rule(struct pf_pdesc *pd, struct pf_rule **rm, struct pf_state **sm, } } - /* copy back packet headers if needed */ - if (rewrite && pd->hdrlen) { - pf_cksum(pd, pd->m); + /* copy back packet headers if we performed NAT operations */ + if (rewrite && pd->hdrlen) m_copyback(pd->m, pd->off, pd->hdrlen, pd->hdr.any, M_NOWAIT); - } #if NPFSYNC > 0 if (*sm != NULL && !ISSET((*sm)->state_flags, PFSTATE_NOSYNC) && @@ -3515,8 +3720,8 @@ pf_create_state(struct pf_pdesc *pd, struct pf_rule *r, struct pf_rule *a, if ((s->src.seqdiff = pf_tcp_iss(pd) - s->src.seqlo) == 0) s->src.seqdiff = 1; - pf_change_a(&th->th_seq, - htonl(s->src.seqlo + s->src.seqdiff)); + pf_change_a(&th->th_seq, &th->th_sum, + htonl(s->src.seqlo + s->src.seqdiff), 0); *rewrite = 1; } else s->src.seqdiff = 0; @@ -3653,7 +3858,7 @@ csfailed: int pf_translate(struct pf_pdesc *pd, struct pf_addr *saddr, u_int16_t sport, struct pf_addr *daddr, u_int16_t dport, u_int16_t virtual_type, - int icmp_dir, struct mbuf *m) + int icmp_dir) { /* * when called from bpf_mtap_pflog, there are extra constraints: @@ -3670,14 +3875,14 @@ pf_translate(struct pf_pdesc *pd, struct pf_addr *saddr, u_int16_t sport, case IPPROTO_TCP: if (afto || PF_ANEQ(saddr, pd->src, pd->af) || *pd->sport != sport) { - pf_change_ap(pd->src, pd->sport, saddr, sport, pd->af, - pd->naf); + pf_change_ap(pd->src, pd->sport, &pd->hdr.tcp->th_sum, + saddr, sport, 0, pd->af, pd->naf); rewrite = 1; } if (afto || PF_ANEQ(daddr, pd->dst, pd->af) || *pd->dport != dport) { - pf_change_ap(pd->dst, pd->dport, daddr, dport, pd->af, - pd->naf); + pf_change_ap(pd->dst, pd->dport, &pd->hdr.tcp->th_sum, + daddr, dport, 0, pd->af, pd->naf); rewrite = 1; } break; @@ -3685,14 +3890,14 @@ pf_translate(struct pf_pdesc *pd, struct pf_addr *saddr, u_int16_t sport, case IPPROTO_UDP: if (afto || PF_ANEQ(saddr, pd->src, pd->af) || *pd->sport != sport) { - pf_change_ap(pd->src, pd->sport, saddr, sport, pd->af, - pd->naf); + pf_change_ap(pd->src, pd->sport, &pd->hdr.udp->uh_sum, + saddr, sport, 1, pd->af, pd->naf); rewrite = 1; } if (afto || PF_ANEQ(daddr, pd->dst, pd->af) || *pd->dport != dport) { - pf_change_ap(pd->dst, pd->dport, daddr, dport, pd->af, - pd->naf); + pf_change_ap(pd->dst, pd->dport, &pd->hdr.udp->uh_sum, + daddr, dport, 1, pd->af, pd->naf); rewrite = 1; } break; @@ -3712,13 +3917,13 @@ pf_translate(struct pf_pdesc *pd, struct pf_addr *saddr, u_int16_t sport, #endif /* INET6 */ } else { if (PF_ANEQ(saddr, pd->src, pd->af)) { - pf_change_a(&pd->src->v4.s_addr, - saddr->v4.s_addr); + pf_change_a(&pd->src->v4.s_addr, NULL, + saddr->v4.s_addr, 0); rewrite = 1; } if (PF_ANEQ(daddr, pd->dst, pd->af)) { - pf_change_a(&pd->dst->v4.s_addr, - daddr->v4.s_addr); + pf_change_a(&pd->dst->v4.s_addr, NULL, + daddr->v4.s_addr, 0); rewrite = 1; } } @@ -3726,6 +3931,9 @@ pf_translate(struct pf_pdesc *pd, struct pf_addr *saddr, u_int16_t sport, u_int16_t icmpid = (icmp_dir == PF_IN) ? sport : dport; if (icmpid != pd->hdr.icmp->icmp_id) { + pd->hdr.icmp->icmp_cksum = pf_cksum_fixup( + pd->hdr.icmp->icmp_cksum, + pd->hdr.icmp->icmp_id, icmpid, 0); pd->hdr.icmp->icmp_id = icmpid; rewrite = 1; } @@ -3749,11 +3957,13 @@ pf_translate(struct pf_pdesc *pd, struct pf_addr *saddr, u_int16_t sport, #endif /* INET */ } else { if (PF_ANEQ(saddr, pd->src, pd->af)) { - pf_change_a6(pd->src, saddr); + pf_change_a6(pd->src, + &pd->hdr.icmp6->icmp6_cksum, saddr, 0); rewrite = 1; } if (PF_ANEQ(daddr, pd->dst, pd->af)) { - pf_change_a6(pd->dst, daddr); + pf_change_a6(pd->dst, + &pd->hdr.icmp6->icmp6_cksum, daddr, 0); rewrite = 1; } } @@ -3765,13 +3975,13 @@ pf_translate(struct pf_pdesc *pd, struct pf_addr *saddr, u_int16_t sport, #ifdef INET case AF_INET: if (!afto && PF_ANEQ(saddr, pd->src, pd->af)) { - pf_change_a(&pd->src->v4.s_addr, - saddr->v4.s_addr); + pf_change_a(&pd->src->v4.s_addr, NULL, + saddr->v4.s_addr, 0); rewrite = 1; } if (!afto && PF_ANEQ(daddr, pd->dst, pd->af)) { - pf_change_a(&pd->dst->v4.s_addr, - daddr->v4.s_addr); + pf_change_a(&pd->dst->v4.s_addr, NULL, + daddr->v4.s_addr, 0); rewrite = 1; } break; @@ -3779,11 +3989,11 @@ pf_translate(struct pf_pdesc *pd, struct pf_addr *saddr, u_int16_t sport, #ifdef INET6 case AF_INET6: if (!afto && PF_ANEQ(saddr, pd->src, pd->af)) { - pf_change_a6(pd->src, saddr); + pf_change_a6(pd->src, NULL, saddr, 0); rewrite = 1; } if (!afto && PF_ANEQ(daddr, pd->dst, pd->af)) { - pf_change_a6(pd->dst, daddr); + pf_change_a6(pd->dst, NULL, daddr, 0); rewrite = 1; } break; @@ -3834,8 +4044,9 @@ pf_tcp_track_full(struct pf_pdesc *pd, struct pf_state_peer *src, while ((src->seqdiff = arc4random() - seq) == 0) ; ack = ntohl(th->th_ack) - dst->seqdiff; - pf_change_a(&th->th_seq, htonl(seq + src->seqdiff)); - pf_change_a(&th->th_ack, htonl(ack)); + pf_change_a(&th->th_seq, &th->th_sum, htonl(seq + + src->seqdiff), 0); + pf_change_a(&th->th_ack, &th->th_sum, htonl(ack), 0); *copyback = 1; } else { ack = ntohl(th->th_ack); @@ -3884,8 +4095,9 @@ pf_tcp_track_full(struct pf_pdesc *pd, struct pf_state_peer *src, ack = ntohl(th->th_ack) - dst->seqdiff; if (src->seqdiff) { /* Modulate sequence numbers */ - pf_change_a(&th->th_seq, htonl(seq + src->seqdiff)); - pf_change_a(&th->th_ack, htonl(ack)); + pf_change_a(&th->th_seq, &th->th_sum, htonl(seq + + src->seqdiff), 0); + pf_change_a(&th->th_ack, &th->th_sum, htonl(ack), 0); *copyback = 1; } end = seq + pd->p_len; @@ -4345,14 +4557,17 @@ pf_test_state_tcp(struct pf_pdesc *pd, struct pf_state **state, u_short *reason) if (afto || PF_ANEQ(pd->src, &nk->addr[sidx], pd->af) || nk->port[sidx] != th->th_sport) - pf_change_ap(pd->src, &th->th_sport, - &nk->addr[sidx], nk->port[sidx], pd->af, nk->af); + pf_change_ap(pd->src, &th->th_sport, &th->th_sum, + &nk->addr[sidx], nk->port[sidx], 0, pd->af, nk->af); if (afto || PF_ANEQ(pd->dst, &nk->addr[didx], pd->af) || + pd->rdomain != nk->rdomain) + pd->destchg = 1; + if (afto || PF_ANEQ(pd->dst, &nk->addr[didx], pd->af) || nk->port[didx] != th->th_dport) - pf_change_ap(pd->dst, &th->th_dport, - &nk->addr[didx], nk->port[didx], pd->af, nk->af); - + pf_change_ap(pd->dst, &th->th_dport, &th->th_sum, + &nk->addr[didx], nk->port[didx], 0, pd->af, + nk->af); pd->m->m_pkthdr.rdomain = nk->rdomain; #if INET && INET6 @@ -4368,10 +4583,9 @@ pf_test_state_tcp(struct pf_pdesc *pd, struct pf_state **state, u_short *reason) } /* Copyback sequence modulation or stateful scrub changes if needed */ - if (copyback) { - pf_cksum(pd, pd->m); + if (copyback) m_copyback(pd->m, pd->off, sizeof(*th), th, M_NOWAIT); - } + return (action); } @@ -4430,17 +4644,17 @@ pf_test_state_udp(struct pf_pdesc *pd, struct pf_state **state) if (afto || PF_ANEQ(pd->src, &nk->addr[sidx], pd->af) || nk->port[sidx] != uh->uh_sport) - pf_change_ap(pd->src, &uh->uh_sport, - &nk->addr[sidx], nk->port[sidx], pd->af, nk->af); + pf_change_ap(pd->src, &uh->uh_sport, &uh->uh_sum, + &nk->addr[sidx], nk->port[sidx], 1, pd->af, nk->af); if (afto || PF_ANEQ(pd->dst, &nk->addr[didx], pd->af) || pd->rdomain != nk->rdomain) pd->destchg = 1; - if (afto || PF_ANEQ(pd->dst, &nk->addr[didx], pd->af) || nk->port[didx] != uh->uh_dport) - pf_change_ap(pd->dst, &uh->uh_dport, - &nk->addr[didx], nk->port[didx], pd->af, nk->af); + pf_change_ap(pd->dst, &uh->uh_dport, &uh->uh_sum, + &nk->addr[didx], nk->port[didx], 1, pd->af, nk->af); + pd->m->m_pkthdr.rdomain = nk->rdomain; #if INET && INET6 if (afto) { @@ -4451,8 +4665,6 @@ pf_test_state_udp(struct pf_pdesc *pd, struct pf_state **state) } #endif /* INET && INET6 */ - pd->m->m_pkthdr.rdomain = nk->rdomain; - pf_cksum(pd, pd->m); m_copyback(pd->m, pd->off, sizeof(*uh), uh, M_NOWAIT); } @@ -4516,8 +4728,7 @@ pf_test_state_icmp(struct pf_pdesc *pd, struct pf_state **state, struct pf_addr *saddr = pd->src, *daddr = pd->dst; u_int16_t *icmpsum, virtual_id, virtual_type; u_int8_t icmptype; - int icmp_dir, iidx, ret, multi, copyback = 0; - + int icmp_dir, iidx, ret, multi; struct pf_state_key_cmp key; switch (pd->proto) { @@ -4591,22 +4802,28 @@ pf_test_state_icmp(struct pf_pdesc *pd, struct pf_state **state, #endif /* INET6 */ if (!afto && PF_ANEQ(pd->src, &nk->addr[sidx], AF_INET)) - pf_change_a(&saddr->v4.s_addr, - nk->addr[sidx].v4.s_addr); + pf_change_a(&saddr->v4.s_addr, NULL, + nk->addr[sidx].v4.s_addr, 0); if (!afto && PF_ANEQ(pd->dst, &nk->addr[didx], AF_INET)) { - pf_change_a(&daddr->v4.s_addr, - nk->addr[didx].v4.s_addr); + pf_change_a(&daddr->v4.s_addr, NULL, + nk->addr[didx].v4.s_addr, 0); pd->destchg = 1; } - if (nk->port[iidx] != pd->hdr.icmp->icmp_id) + if (nk->port[iidx] != + pd->hdr.icmp->icmp_id) { + pd->hdr.icmp->icmp_cksum = + pf_cksum_fixup( + pd->hdr.icmp->icmp_cksum, + pd->hdr.icmp->icmp_id, + nk->port[iidx], 0); pd->hdr.icmp->icmp_id = nk->port[iidx]; + } m_copyback(pd->m, pd->off, ICMP_MINLEN, pd->hdr.icmp, M_NOWAIT); - copyback = 1; break; #endif /* INET */ #ifdef INET6 @@ -4622,12 +4839,14 @@ pf_test_state_icmp(struct pf_pdesc *pd, struct pf_state **state, if (!afto && PF_ANEQ(pd->src, &nk->addr[sidx], AF_INET6)) pf_change_a6(saddr, - &nk->addr[sidx]); + &pd->hdr.icmp6->icmp6_cksum, + &nk->addr[sidx], 0); if (!afto && PF_ANEQ(pd->dst, &nk->addr[didx], AF_INET6)) { pf_change_a6(daddr, - &nk->addr[didx]); + &pd->hdr.icmp6->icmp6_cksum, + &nk->addr[didx], 0); pd->destchg = 1; } @@ -4638,7 +4857,6 @@ pf_test_state_icmp(struct pf_pdesc *pd, struct pf_state **state, m_copyback(pd->m, pd->off, sizeof(struct icmp6_hdr), pd->hdr.icmp6, M_NOWAIT); - copyback = 1; break; #endif /* INET6 */ } @@ -4651,6 +4869,8 @@ pf_test_state_icmp(struct pf_pdesc *pd, struct pf_state **state, } #endif /* INET && INET6 */ } + return (PF_PASS); + } else { /* * ICMP error message in response to a TCP/UDP packet. @@ -4737,6 +4957,7 @@ pf_test_state_icmp(struct pf_pdesc *pd, struct pf_state **state, u_int32_t seq; struct pf_state_peer *src, *dst; u_int8_t dws; + int copyback = 0; /* * Only the first 8 bytes of the TCP header can be @@ -4786,7 +5007,8 @@ pf_test_state_icmp(struct pf_pdesc *pd, struct pf_state **state, /* Demodulate sequence number */ seq = ntohl(th.th_seq) - src->seqdiff; if (src->seqdiff) { - pf_change_a(&th.th_seq, htonl(seq)); + pf_change_a(&th.th_seq, icmpsum, + htonl(seq), 0); copyback = 1; } @@ -4870,7 +5092,8 @@ pf_test_state_icmp(struct pf_pdesc *pd, struct pf_state **state, nk->port[pd2.sidx] != th.th_sport) pf_change_icmp(pd2.src, &th.th_sport, daddr, &nk->addr[pd2.sidx], - nk->port[pd2.sidx], pd2.af); + nk->port[pd2.sidx], NULL, + ipsum2, icmpsum, 0, pd2.af); if (PF_ANEQ(pd2.dst, &nk->addr[pd2.didx], pd2.af) || pd2.rdomain != nk->rdomain) @@ -4882,7 +5105,8 @@ pf_test_state_icmp(struct pf_pdesc *pd, struct pf_state **state, nk->port[pd2.didx] != th.th_dport) pf_change_icmp(pd2.dst, &th.th_dport, saddr, &nk->addr[pd2.didx], - nk->port[pd2.didx], pd2.af); + nk->port[pd2.didx], NULL, + ipsum2, icmpsum, 0, pd2.af); copyback = 1; } @@ -4908,6 +5132,8 @@ pf_test_state_icmp(struct pf_pdesc *pd, struct pf_state **state, } m_copyback(pd2.m, pd2.off, 8, &th, M_NOWAIT); } + + return (PF_PASS); break; } case IPPROTO_UDP: { @@ -4961,12 +5187,12 @@ pf_test_state_icmp(struct pf_pdesc *pd, struct pf_state **state, pd->proto = IPPROTO_ICMP; else pd->proto = IPPROTO_ICMPV6; - pf_change_ap(pd2.src, + pf_change_ap(pd2.src, &uh.uh_sport, &uh.uh_sum, &nk->addr[pd2.sidx], - nk->port[sidx], pd->af, nk->af); - pf_change_ap(pd2.dst, + nk->port[sidx], 1, pd->af, nk->af); + pf_change_ap(pd2.dst, &uh.uh_dport, &uh.uh_sum, &nk->addr[pd2.didx], - nk->port[didx], pd->af, nk->af); + nk->port[didx], 1, pd->af, nk->af); m_copyback(pd2.m, pd2.off, sizeof(uh), &uh, M_NOWAIT); pd->m->m_pkthdr.rdomain = nk->rdomain; @@ -4985,7 +5211,8 @@ pf_test_state_icmp(struct pf_pdesc *pd, struct pf_state **state, nk->port[pd2.sidx] != uh.uh_sport) pf_change_icmp(pd2.src, &uh.uh_sport, daddr, &nk->addr[pd2.sidx], - nk->port[pd2.sidx], pd2.af); + nk->port[pd2.sidx], &uh.uh_sum, + ipsum2, icmpsum, 1, pd2.af); if (PF_ANEQ(pd2.dst, &nk->addr[pd2.didx], pd2.af) || pd2.rdomain != nk->rdomain) @@ -4997,7 +5224,8 @@ pf_test_state_icmp(struct pf_pdesc *pd, struct pf_state **state, nk->port[pd2.didx] != uh.uh_dport) pf_change_icmp(pd2.dst, &uh.uh_dport, saddr, &nk->addr[pd2.didx], - nk->port[pd2.didx], pd2.af); + nk->port[pd2.didx], &uh.uh_sum, + ipsum2, icmpsum, 1, pd2.af); switch (pd2.af) { #ifdef INET @@ -5018,11 +5246,10 @@ pf_test_state_icmp(struct pf_pdesc *pd, struct pf_state **state, break; #endif /* INET6 */ } - uh.uh_sum = 0; m_copyback(pd2.m, pd2.off, sizeof(uh), &uh, M_NOWAIT); - copyback = 1; } + return (PF_PASS); break; } #ifdef INET @@ -5109,7 +5336,8 @@ pf_test_state_icmp(struct pf_pdesc *pd, struct pf_state **state, &iih.icmp_id : NULL, daddr, &nk->addr[pd2.sidx], (virtual_type == htons(ICMP_ECHO)) ? - nk->port[iidx] : 0, AF_INET); + nk->port[iidx] : 0, NULL, + ipsum2, icmpsum, 0, AF_INET); if (PF_ANEQ(pd2.dst, &nk->addr[pd2.didx], pd2.af) || pd2.rdomain != nk->rdomain) @@ -5119,7 +5347,8 @@ pf_test_state_icmp(struct pf_pdesc *pd, struct pf_state **state, if (PF_ANEQ(pd2.dst, &nk->addr[pd2.didx], pd2.af)) pf_change_icmp(pd2.dst, NULL, saddr, - &nk->addr[pd2.didx], 0, AF_INET); + &nk->addr[pd2.didx], 0, NULL, + ipsum2, icmpsum, 0, AF_INET); m_copyback(pd->m, pd->off, ICMP_MINLEN, pd->hdr.icmp, M_NOWAIT); @@ -5127,8 +5356,8 @@ pf_test_state_icmp(struct pf_pdesc *pd, struct pf_state **state, M_NOWAIT); m_copyback(pd2.m, pd2.off, ICMP_MINLEN, &iih, M_NOWAIT); - copyback = 1; } + return (PF_PASS); break; } #endif /* INET */ @@ -5229,7 +5458,8 @@ pf_test_state_icmp(struct pf_pdesc *pd, struct pf_state **state, daddr, &nk->addr[pd2.sidx], (virtual_type == htons(ICMP6_ECHO_REQUEST)) - ? nk->port[iidx] : 0, AF_INET6); + ? nk->port[iidx] : 0, NULL, + ipsum2, icmpsum, 0, AF_INET6); if (PF_ANEQ(pd2.dst, &nk->addr[pd2.didx], pd2.af) || pd2.rdomain != nk->rdomain) @@ -5239,15 +5469,18 @@ pf_test_state_icmp(struct pf_pdesc *pd, struct pf_state **state, if (PF_ANEQ(pd2.dst, &nk->addr[pd2.didx], pd2.af)) pf_change_icmp(pd2.dst, NULL, saddr, - &nk->addr[pd2.didx], 0, AF_INET6); + &nk->addr[pd2.didx], 0, NULL, + ipsum2, icmpsum, 0, AF_INET6); m_copyback(pd->m, pd->off, sizeof(struct icmp6_hdr), pd->hdr.icmp6, M_NOWAIT); - m_copyback(pd->m, pd2.off, + m_copyback(pd2.m, ipoff2, sizeof(h2_6), &h2_6, + M_NOWAIT); + m_copyback(pd2.m, pd2.off, sizeof(struct icmp6_hdr), &iih, M_NOWAIT); - copyback = 1; } + return (PF_PASS); break; } #endif /* INET6 */ @@ -5270,7 +5503,8 @@ pf_test_state_icmp(struct pf_pdesc *pd, struct pf_state **state, if (PF_ANEQ(pd2.src, &nk->addr[pd2.sidx], pd2.af)) pf_change_icmp(pd2.src, NULL, daddr, - &nk->addr[pd2.sidx], 0, pd2.af); + &nk->addr[pd2.sidx], 0, NULL, + ipsum2, icmpsum, 0, pd2.af); if (PF_ANEQ(pd2.dst, &nk->addr[pd2.didx], pd2.af) || pd2.rdomain != nk->rdomain) @@ -5280,7 +5514,8 @@ pf_test_state_icmp(struct pf_pdesc *pd, struct pf_state **state, if (PF_ANEQ(pd2.dst, &nk->addr[pd2.didx], pd2.af)) pf_change_icmp(pd2.dst, NULL, saddr, - &nk->addr[pd2.didx], 0, pd2.af); + &nk->addr[pd2.didx], 0, NULL, + ipsum2, icmpsum, 0, pd2.af); switch (pd2.af) { #ifdef INET @@ -5301,16 +5536,12 @@ pf_test_state_icmp(struct pf_pdesc *pd, struct pf_state **state, break; #endif /* INET6 */ } - copyback = 1; } + return (PF_PASS); break; } } } - if (copyback) - pf_cksum(pd, pd->m); - - return (PF_PASS); } int @@ -5372,12 +5603,14 @@ pf_test_state_other(struct pf_pdesc *pd, struct pf_state **state) case AF_INET: if (!afto && PF_ANEQ(pd->src, &nk->addr[pd->sidx], AF_INET)) - pf_change_a(&pd->src->v4.s_addr, - nk->addr[pd->sidx].v4.s_addr); + pf_change_a(&pd->src->v4.s_addr, NULL, + nk->addr[pd->sidx].v4.s_addr, + 0); if (!afto && PF_ANEQ(pd->dst, &nk->addr[pd->didx], AF_INET)) { - pf_change_a(&pd->dst->v4.s_addr, - nk->addr[pd->didx].v4.s_addr); + pf_change_a(&pd->dst->v4.s_addr, NULL, + nk->addr[pd->didx].v4.s_addr, + 0); pd->destchg = 1; } break; @@ -6812,38 +7045,6 @@ pf_check_congestion(struct ifqueue *ifq) return (0); } -void -pf_cksum(struct pf_pdesc *pd, struct mbuf *m) -{ - switch (pd->proto) { - case IPPROTO_TCP: - pd->hdr.tcp->th_sum = 0; - if (pd->af == AF_INET) { - pd->hdr.tcp->th_sum = in_cksum_phdr(pd->src->v4.s_addr, - pd->dst->v4.s_addr, htons(pd->tot_len - - pd->off + IPPROTO_TCP)); - } - m->m_pkthdr.csum_flags |= M_TCP_CSUM_OUT; - break; - case IPPROTO_UDP: - pd->hdr.udp->uh_sum = 0; - if (pd->af == AF_INET) { - pd->hdr.udp->uh_sum = in_cksum_phdr(pd->src->v4.s_addr, - pd->dst->v4.s_addr, htons(pd->tot_len - - pd->off + IPPROTO_UDP)); - } - m->m_pkthdr.csum_flags |= M_UDP_CSUM_OUT; - break; - case IPPROTO_ICMP: - case IPPROTO_ICMPV6: - m->m_pkthdr.csum_flags |= M_ICMP_CSUM_OUT; - break; - default: - /* nothing */ - break; - } -} - /* * must be called whenever any addressing information such as * address, port, protocol has changed |