diff options
author | darrenr <darrenr@FreeBSD.org> | 2000-10-26 12:33:42 +0000 |
---|---|---|
committer | darrenr <darrenr@FreeBSD.org> | 2000-10-26 12:33:42 +0000 |
commit | 1a1de29bc037bc05ce4aec3d225e476799ab5a27 (patch) | |
tree | 50760b3edd676bcf8b9bc65cbfd7839eb1866c95 | |
parent | a21e3405e2f118d575c74cf92c09a22eaee4c261 (diff) | |
download | FreeBSD-src-1a1de29bc037bc05ce4aec3d225e476799ab5a27.zip FreeBSD-src-1a1de29bc037bc05ce4aec3d225e476799ab5a27.tar.gz |
fix conflicts from rcsids
28 files changed, 1198 insertions, 356 deletions
diff --git a/sys/contrib/ipfilter/netinet/fil.c b/sys/contrib/ipfilter/netinet/fil.c index 1fb4b6c..12993ca 100644 --- a/sys/contrib/ipfilter/netinet/fil.c +++ b/sys/contrib/ipfilter/netinet/fil.c @@ -277,6 +277,16 @@ fr_info_t *fin; int minicmpsz = sizeof(struct icmp); icmphdr_t *icmp; + if (fin->fin_dlen > 1) + fin->fin_data[0] = *(u_short *)tcp; + + if ((!(plen >= hlen + minicmpsz) && !off) || + (off && off < sizeof(struct icmp))) { + fi->fi_fl |= FI_SHORT; + if (fin->fin_dlen < 2) + break; + } + icmp = (icmphdr_t *)tcp; if (!off && (icmp->icmp_type == ICMP_ECHOREPLY || @@ -294,11 +304,6 @@ fr_info_t *fin; icmp->icmp_type == ICMP_MASKREPLY)) minicmpsz = 12; - if ((!(plen >= hlen + minicmpsz) && !off) || - (off && off < sizeof(struct icmp))) - fi->fi_fl |= FI_SHORT; - if (fin->fin_dlen > 1) - fin->fin_data[0] = *(u_short *)tcp; break; } case IPPROTO_TCP : @@ -743,6 +748,7 @@ int out; #ifdef _KERNEL mb_t *mc = NULL; + int p, len; # if !defined(__SVR4) && !defined(__svr4__) # ifdef __sgi char hbuf[(0xf << 2) + sizeof(struct icmp) + sizeof(ip_t) + 8]; @@ -767,13 +773,26 @@ int out; } # endif /* CSUM_DELAY_DATA */ +# ifdef USE_INET6 + if (v == 6) { + len = ntohs(((ip6_t*)ip)->ip6_plen); + p = ((ip6_t *)ip)->ip6_nxt; + } else +# endif + { + p = ip->ip_p; + len = ip->ip_len; + } - if ((ip->ip_p == IPPROTO_TCP || ip->ip_p == IPPROTO_UDP || - ip->ip_p == IPPROTO_ICMP)) { + if ((p == IPPROTO_TCP || p == IPPROTO_UDP || p == IPPROTO_ICMP +# ifdef USE_INET6 + || (v == 6 && p == IPPROTO_ICMPV6) +# endif + )) { int plen = 0; - if ((ip->ip_off & IP_OFFMASK) == 0) - switch(ip->ip_p) + if ((v == 6) || (ip->ip_off & IP_OFFMASK) == 0) + switch(p) { case IPPROTO_TCP: plen = sizeof(tcphdr_t); @@ -783,10 +802,13 @@ int out; break; /* 96 - enough for complete ICMP error IP header */ case IPPROTO_ICMP: +# ifdef USE_INET6 + case IPPROTO_ICMPV6 : +# endif plen = ICMPERR_MAXPKTLEN - sizeof(ip_t); break; } - up = MIN(hlen + plen, ip->ip_len); + up = MIN(hlen + plen, len); if (up > m->m_len) { # ifdef __sgi @@ -835,8 +857,8 @@ int out; #endif changed = 0; - fin->fin_v = v; fin->fin_ifp = ifp; + fin->fin_v = v; fin->fin_out = out; fin->fin_mp = mp; fr_makefrip(hlen, ip, fin); @@ -1383,7 +1405,7 @@ nodata: * SUCH DAMAGE. * * @(#)uipc_mbuf.c 8.2 (Berkeley) 1/4/94 - * $Id: fil.c,v 2.35.2.20 2000/08/13 04:15:43 darrenr Exp $ + * $Id: fil.c,v 2.35.2.26 2000/10/24 11:58:17 darrenr Exp $ */ /* * Copy data from an mbuf chain starting "off" bytes from the beginning, @@ -1862,7 +1884,7 @@ size_t c; int err; #if SOLARIS - if (copyin(a, &ca, sizeof(ca))) + if (copyin(a, (char *)&ca, sizeof(ca))) return EFAULT; #else bcopy(a, &ca, sizeof(ca)); @@ -1882,7 +1904,7 @@ size_t c; int err; #if SOLARIS - if (copyin(b, &ca, sizeof(ca))) + if (copyin(b, (char *)&ca, sizeof(ca))) return EFAULT; #else bcopy(b, &ca, sizeof(ca)); @@ -1976,6 +1998,15 @@ friostat_t *fiop; fiop->f_acctin6[1] = ipacct6[0][1]; fiop->f_acctout6[0] = ipacct6[1][0]; fiop->f_acctout6[1] = ipacct6[1][1]; +#else + fiop->f_fin6[0] = NULL; + fiop->f_fin6[1] = NULL; + fiop->f_fout6[0] = NULL; + fiop->f_fout6[1] = NULL; + fiop->f_acctin6[0] = NULL; + fiop->f_acctin6[1] = NULL; + fiop->f_acctout6[0] = NULL; + fiop->f_acctout6[1] = NULL; #endif fiop->f_active = fr_active; fiop->f_froute[0] = ipl_frouteok[0]; diff --git a/sys/contrib/ipfilter/netinet/ip_auth.h b/sys/contrib/ipfilter/netinet/ip_auth.h index 8be860c..2851c3d 100644 --- a/sys/contrib/ipfilter/netinet/ip_auth.h +++ b/sys/contrib/ipfilter/netinet/ip_auth.h @@ -47,8 +47,6 @@ typedef struct fr_authstat { extern frentry_t *ipauth; extern struct fr_authstat fr_authstats; extern int fr_defaultauthage; -extern int fr_authstart; -extern int fr_authend; extern int fr_authsize; extern int fr_authused; extern int fr_auth_lock; diff --git a/sys/contrib/ipfilter/netinet/ip_compat.h b/sys/contrib/ipfilter/netinet/ip_compat.h index 1c3e245..d313952 100644 --- a/sys/contrib/ipfilter/netinet/ip_compat.h +++ b/sys/contrib/ipfilter/netinet/ip_compat.h @@ -264,6 +264,12 @@ union i6addr { #if defined(__FreeBSD__) && (defined(KERNEL) || defined(_KERNEL)) +# ifdef IPFILTER_LKM +# include <osreldate.h> +# define ACTUALLY_LKM_NOT_KERNEL +# else +# include <sys/osreldate.h> +# endif # if __FreeBSD__ < 3 # include <machine/spl.h> # else @@ -289,6 +295,19 @@ union i6addr { # define ATOMIC_DEC32 ATOMIC_DEC # define ATOMIC_DEC16 ATOMIC_DEC #endif +#ifdef __sgi +# define hz HZ +# include <sys/ksynch.h> +# define IPF_LOCK_PL plhi +# include <sys/sema.h> +#undef kmutex_t +typedef struct { + lock_t *l; + int pl; +} kmutex_t; +# undef MUTEX_INIT +# undef MUTEX_DESTROY +#endif #ifdef KERNEL # if SOLARIS # if SOLARIS2 >= 6 @@ -338,8 +357,8 @@ union i6addr { # define MUTEX_DESTROY(x) mutex_destroy(x) # define MUTEX_EXIT(x) mutex_exit(x) # define MTOD(m,t) (t)((m)->b_rptr) -# define IRCOPY(a,b,c) copyin((a), (b), (c)) -# define IWCOPY(a,b,c) copyout((a), (b), (c)) +# define IRCOPY(a,b,c) copyin((caddr_t)(a), (caddr_t)(b), (c)) +# define IWCOPY(a,b,c) copyout((caddr_t)(a), (caddr_t)(b), (c)) # define IRCOPYPTR ircopyptr # define IWCOPYPTR iwcopyptr # define FREE_MB_T(m) freemsg(m) @@ -384,15 +403,6 @@ extern ill_t *get_unit __P((char *, int)); # define IFNAME(x) ((ill_t *)x)->ill_name # else /* SOLARIS */ # if defined(__sgi) -# define hz HZ -# include <sys/ksynch.h> -# define IPF_LOCK_PL plhi -# include <sys/sema.h> -#undef kmutex_t -typedef struct { - lock_t *l; - int pl; -} kmutex_t; # define ATOMIC_INC(x) { MUTEX_ENTER(&ipf_rw); \ (x)++; MUTEX_EXIT(&ipf_rw); } # define ATOMIC_DEC(x) { MUTEX_ENTER(&ipf_rw); \ @@ -405,8 +415,8 @@ typedef struct { # define MUTEX_DOWNGRADE(x) ; # define RWLOCK_EXIT(x) MUTEX_EXIT(x) # define MUTEX_EXIT(x) UNLOCK((x)->l, (x)->pl); -# define MUTEX_INIT(x,y,z) (x).l = LOCK_ALLOC((uchar_t)-1, IPF_LOCK_PL, (lkinfo_t *)-1, KM_NOSLEEP) -# define MUTEX_DESTROY(x) LOCK_DEALLOC((x).l) +# define MUTEX_INIT(x,y,z) (x)->l = LOCK_ALLOC((uchar_t)-1, IPF_LOCK_PL, (lkinfo_t *)-1, KM_NOSLEEP) +# define MUTEX_DESTROY(x) LOCK_DEALLOC((x)->l) # else /* __sgi */ # define ATOMIC_INC(x) (x)++ # define ATOMIC_DEC(x) (x)-- diff --git a/sys/contrib/ipfilter/netinet/ip_fil.c b/sys/contrib/ipfilter/netinet/ip_fil.c index 27aca2f..797e599 100644 --- a/sys/contrib/ipfilter/netinet/ip_fil.c +++ b/sys/contrib/ipfilter/netinet/ip_fil.c @@ -173,6 +173,9 @@ struct callout_handle ipfr_slowtimer_ch; # include <sys/callout.h> struct callout ipfr_slowtimer_ch; #endif +#if defined(__sgi) && defined(_KERNEL) +toid_t ipfr_slowtimer_ch; +#endif #if (_BSDI_VERSION >= 199510) && defined(_KERNEL) # include <sys/device.h> @@ -322,7 +325,7 @@ pfil_error: callout_init(&ipfr_slowtimer_ch); callout_reset(&ipfr_slowtimer_ch, hz / 2, ipfr_slowtimer, NULL); # else -# if (__FreeBSD_version >= 300000) && defined(_KERNEL) +# if (__FreeBSD_version >= 300000) || defined(__sgi) ipfr_slowtimer_ch = timeout(ipfr_slowtimer, NULL, hz/2); # else timeout(ipfr_slowtimer, NULL, hz/2); @@ -353,7 +356,7 @@ int ipldetach() untimeout(ipfr_slowtimer, NULL, ipfr_slowtimer_ch); # else # ifdef __sgi - untimeout(ipfr_slowtimer); + untimeout(ipfr_slowtimer_ch); # else untimeout(ipfr_slowtimer, NULL); # endif @@ -980,8 +983,10 @@ fr_info_t *fin; if (m == NULL) return -1; - if (tcp->th_flags & TH_SYN) - tlen = 1; + tlen = oip->ip_len - fin->fin_hlen - (tcp->th_off << 2) + + ((tcp->th_flags & TH_SYN) ? 1 : 0) + + ((tcp->th_flags & TH_FIN) ? 1 : 0); + #ifdef USE_INET6 hlen = (fin->fin_v == 6) ? sizeof(ip6_t) : sizeof(ip_t); #else @@ -1002,11 +1007,16 @@ fr_info_t *fin; tcp2->th_sport = tcp->th_dport; tcp2->th_dport = tcp->th_sport; - tcp2->th_ack = ntohl(tcp->th_seq); - tcp2->th_ack += tlen; - tcp2->th_ack = htonl(tcp2->th_ack); + if (tcp->th_flags & TH_ACK) { + tcp2->th_seq = tcp->th_ack; + tcp2->th_flags = TH_RST; + } else { + tcp2->th_ack = ntohl(tcp->th_seq); + tcp2->th_ack += tlen; + tcp2->th_ack = htonl(tcp2->th_ack); + tcp2->th_flags = TH_RST|TH_ACK; + } tcp2->th_off = sizeof(*tcp2) >> 2; - tcp2->th_flags = TH_RST|TH_ACK; # ifdef USE_INET6 if (fin->fin_v == 6) { ip6->ip6_plen = htons(sizeof(struct tcphdr)); @@ -1148,7 +1158,12 @@ int dst; m_freem(m); return ENOBUFS; } +# ifdef M_TRAILINGSPACE + m->m_len = 0; + avail = M_TRAILINGSPACE(m); +# else avail = (m->m_flags & M_EXT) ? MCLBYTES : MHLEN; +# endif xtra = MIN(ntohs(oip6->ip6_plen) + sizeof(ip6_t), avail - hlen - sizeof(*icmp) - max_linkhdr); if (dst == 0) { @@ -1182,6 +1197,12 @@ int dst; icmp->icmp_type = type; icmp->icmp_code = fin->fin_icode; icmp->icmp_cksum = 0; +#ifdef icmp_nextmtu + if (type == ICMP_UNREACH && + fin->fin_icode == ICMP_UNREACH_NEEDFRAG && ifp) + icmp->icmp_nextmtu = htons(((struct ifnet *) ifp)->if_mtu); +#endif + if (avail) { bcopy((char *)oip, (char *)&icmp->icmp_ip, MIN(ohlen, avail)); avail -= MIN(ohlen, avail); diff --git a/sys/contrib/ipfilter/netinet/ip_frag.c b/sys/contrib/ipfilter/netinet/ip_frag.c index 8d2bbc5..2a10988 100644 --- a/sys/contrib/ipfilter/netinet/ip_frag.c +++ b/sys/contrib/ipfilter/netinet/ip_frag.c @@ -215,7 +215,7 @@ u_int pass; ipfr_t *ipf; if ((ip->ip_v != 4) || (fr_frag_lock)) - return NULL; + return -1; WRITE_ENTER(&ipf_frag); ipf = ipfr_new(ip, fin, pass, ipfr_heads); RWLOCK_EXIT(&ipf_frag); @@ -232,7 +232,7 @@ nat_t *nat; ipfr_t *ipf; if ((ip->ip_v != 4) || (fr_frag_lock)) - return NULL; + return -1; WRITE_ENTER(&ipf_natfrag); ipf = ipfr_new(ip, fin, pass, ipfr_nattab); if (ipf != NULL) { @@ -329,13 +329,16 @@ fr_info_t *fin; ipf = ipfr_lookup(ip, fin, ipfr_nattab); if (ipf != NULL) { nat = ipf->ipfr_data; - /* - * This is the last fragment for this packet. - */ - if ((ipf->ipfr_ttl == 1) && (nat != NULL)) { - nat->nat_data = NULL; - ipf->ipfr_data = NULL; - } + if (nat->nat_ifp == fin->fin_ifp) { + /* + * This is the last fragment for this packet. + */ + if ((ipf->ipfr_ttl == 1) && (nat != NULL)) { + nat->nat_data = NULL; + ipf->ipfr_data = NULL; + } + } else + nat = NULL; } else nat = NULL; RWLOCK_EXIT(&ipf_natfrag); diff --git a/sys/contrib/ipfilter/netinet/ip_frag.h b/sys/contrib/ipfilter/netinet/ip_frag.h index 4fb3597..48144af 100644 --- a/sys/contrib/ipfilter/netinet/ip_frag.h +++ b/sys/contrib/ipfilter/netinet/ip_frag.h @@ -61,6 +61,6 @@ extern void ipfr_slowtimer __P((void *)); # endif #else extern int ipfr_slowtimer __P((void)); -#endif +#endif /* (BSD >= 199306) || SOLARIS */ #endif /* __IP_FIL_H__ */ diff --git a/sys/contrib/ipfilter/netinet/ip_ftp_pxy.c b/sys/contrib/ipfilter/netinet/ip_ftp_pxy.c index ce06851..c68361a 100644 --- a/sys/contrib/ipfilter/netinet/ip_ftp_pxy.c +++ b/sys/contrib/ipfilter/netinet/ip_ftp_pxy.c @@ -145,6 +145,7 @@ int dlen; } else return 0; a5 >>= 8; + a5 &= 0xff; /* * Calculate new address parts for PORT command */ @@ -213,7 +214,7 @@ int dlen; sum2 -= sum1; sum2 = (sum2 & 0xffff) + (sum2 >> 16); - fix_outcksum(&ip->ip_sum, sum2, 0); + fix_outcksum(&ip->ip_sum, sum2); #endif ip->ip_len += inc; } @@ -440,7 +441,7 @@ int dlen; sum2 -= sum1; sum2 = (sum2 & 0xffff) + (sum2 >> 16); - fix_outcksum(&ip->ip_sum, sum2, 0); + fix_outcksum(&ip->ip_sum, sum2); #endif /* SOLARIS || defined(__sgi) */ ip->ip_len += inc; } @@ -669,15 +670,18 @@ int rv; while ((rptr < wptr) && (*rptr != '\r')) rptr++; - if ((*rptr == '\r') && (rptr + 1 < wptr)) { - if (*(rptr + 1) == '\n') { - rptr += 2; - f->ftps_junk = 0; + if (*rptr == '\r') { + if (rptr + 1 < wptr) { + if (*(rptr + 1) == '\n') { + rptr += 2; + f->ftps_junk = 0; + } else + rptr++; } else - rptr++; + break; } - f->ftps_rptr = rptr; } + f->ftps_rptr = rptr; if (rptr == wptr) { rptr = wptr = f->ftps_buf; @@ -761,5 +765,7 @@ char **ptr; j += c - '0'; } *ptr = s; + i &= 0xff; + j &= 0xff; return (i << 8) | j; } diff --git a/sys/contrib/ipfilter/netinet/ip_nat.c b/sys/contrib/ipfilter/netinet/ip_nat.c index 47c5f6a..ca3a27f 100644 --- a/sys/contrib/ipfilter/netinet/ip_nat.c +++ b/sys/contrib/ipfilter/netinet/ip_nat.c @@ -119,6 +119,7 @@ u_int ipf_nattable_sz = NAT_TABLE_SZ; u_int ipf_natrules_sz = NAT_SIZE; u_int ipf_rdrrules_sz = RDR_SIZE; u_int ipf_hostmap_sz = HOSTMAP_SIZE; +int nat_wilds = 0; u_32_t nat_masks = 0; u_32_t rdr_masks = 0; ipnat_t **nat_rules = NULL; @@ -144,6 +145,7 @@ static void nat_delnat __P((struct ipnat *)); static int fr_natgetent __P((caddr_t)); static int fr_natgetsz __P((caddr_t)); static int fr_natputent __P((caddr_t)); +static void nat_tabmove __P((nat_t *, u_int)); static int nat_match __P((fr_info_t *, ipnat_t *, ip_t *)); static hostmap_t *nat_hostmap __P((ipnat_t *, struct in_addr, struct in_addr)); @@ -301,10 +303,9 @@ struct hostmap *hm; } -void fix_outcksum(sp, n , len) +void fix_outcksum(sp, n) u_short *sp; u_32_t n; -int len; { register u_short sumshort; register u_32_t sum1; @@ -327,10 +328,9 @@ int len; } -void fix_incksum(sp, n , len) +void fix_incksum(sp, n) u_short *sp; u_32_t n; -int len; { register u_short sumshort; register u_32_t sum1; @@ -358,6 +358,38 @@ int len; /* + * fix_datacksum is used *only* for the adjustments of checksums in the data + * section of an IP packet. + * + * The only situation in which you need to do this is when NAT'ing an + * ICMP error message. Such a message, contains in its body the IP header + * of the original IP packet, that causes the error. + * + * You can't use fix_incksum or fix_outcksum in that case, because for the + * kernel the data section of the ICMP error is just data, and no special + * processing like hardware cksum or ntohs processing have been done by the + * kernel on the data section. + */ +void fix_datacksum(sp, n) +u_short *sp; +u_32_t n; +{ + register u_short sumshort; + register u_32_t sum1; + + if (!n) + return; + + sum1 = (~ntohs(*sp)) & 0xffff; + sum1 += (n); + sum1 = (sum1 >> 16) + (sum1 & 0xffff); + /* Again */ + sum1 = (sum1 >> 16) + (sum1 & 0xffff); + sumshort = ~(u_short)sum1; + *(sp) = htons(sumshort); +} + +/* * How the NAT is organised and works. * * Inside (interface y) NAT Outside (interface x) @@ -857,8 +889,8 @@ caddr_t data; /* * Initialize all these so that nat_delete() doesn't cause a crash. */ - nat->nat_hstart[0] = NULL; - nat->nat_hstart[1] = NULL; + nat->nat_phnext[0] = NULL; + nat->nat_phnext[1] = NULL; fr = nat->nat_fr; nat->nat_fr = NULL; aps = nat->nat_aps; @@ -970,22 +1002,16 @@ junkput: static void nat_delete(natd) struct nat *natd; { - register struct nat **natp, *nat; struct ipnat *ipn; - for (natp = natd->nat_hstart[0]; natp && (nat = *natp); - natp = &nat->nat_hnext[0]) - if (nat == natd) { - *natp = nat->nat_hnext[0]; - break; - } - - for (natp = natd->nat_hstart[1]; natp && (nat = *natp); - natp = &nat->nat_hnext[1]) - if (nat == natd) { - *natp = nat->nat_hnext[1]; - break; - } + if (natd->nat_flags & FI_WILDP) + nat_wilds--; + if (natd->nat_hnext[0]) + natd->nat_hnext[0]->nat_phnext[0] = natd->nat_phnext[0]; + *natd->nat_phnext[0] = natd->nat_hnext[0]; + if (natd->nat_hnext[1]) + natd->nat_hnext[1]->nat_phnext[1] = natd->nat_phnext[1]; + *natd->nat_phnext[1] = natd->nat_hnext[1]; if (natd->nat_fr != NULL) { ATOMIC_DEC32(natd->nat_fr->fr_ref); @@ -1030,7 +1056,7 @@ static int nat_flushtable() { register nat_t *nat, **natp; register int j = 0; - + /* * ALL NAT mappings deleted, so lets just make the deletions * quicker. @@ -1122,6 +1148,8 @@ int direction; bzero((char *)nat, sizeof(*nat)); nat->nat_flags = flags; + if (flags & FI_WILDP) + nat_wilds++; /* * Search the current table for a match. */ @@ -1444,16 +1472,22 @@ nat_t *nat; nat->nat_next = nat_instances; nat_instances = nat; + hv = NAT_HASH_FN(nat->nat_inip.s_addr, nat->nat_inport, ipf_nattable_sz); natp = &nat_table[0][hv]; - nat->nat_hstart[0] = natp; + if (*natp) + (*natp)->nat_phnext[0] = &nat->nat_hnext[0]; + nat->nat_phnext[0] = natp; nat->nat_hnext[0] = *natp; *natp = nat; + hv = NAT_HASH_FN(nat->nat_outip.s_addr, nat->nat_outport, ipf_nattable_sz); natp = &nat_table[1][hv]; - nat->nat_hstart[1] = natp; + if (*natp) + (*natp)->nat_phnext[1] = &nat->nat_hnext[1]; + nat->nat_phnext[1] = natp; nat->nat_hnext[1] = *natp; *natp = nat; @@ -1561,12 +1595,16 @@ int dir; u_32_t sum1, sum2, sumd; struct in_addr in; icmphdr_t *icmp; + udphdr_t *udp; nat_t *nat; ip_t *oip; int flags = 0; if ((fin->fin_fi.fi_fl & FI_SHORT) || (ip->ip_off & IP_OFFMASK)) return NULL; + /* + * nat_icmplookup() will return NULL for `defective' packets. + */ if ((ip->ip_v != 4) || !(nat = nat_icmplookup(ip, fin, dir))) return NULL; *nflags = IPN_ICMPERR; @@ -1576,16 +1614,33 @@ int dir; flags = IPN_TCP; else if (oip->ip_p == IPPROTO_UDP) flags = IPN_UDP; + udp = (udphdr_t *)((((char *)oip) + (oip->ip_hl << 2))); /* * Need to adjust ICMP header to include the real IP#'s and * port #'s. Only apply a checksum change relative to the - * IP address change is it will be modified again in ip_natout + * IP address change as it will be modified again in ip_natout * for both address and port. Two checksum changes are * necessary for the two header address changes. Be careful * to only modify the checksum once for the port # and twice * for the IP#. */ + /* + * Step 1 + * Fix the IP addresses in the offending IP packet. You also need + * to adjust the IP header checksum of that offending IP packet + * and the ICMP checksum of the ICMP error message itself. + * + * Unfortunately, for UDP and TCP, the IP addresses are also contained + * in the pseudo header that is used to compute the UDP resp. TCP + * checksum. So, we must compensate that as well. Even worse, the + * change in the UDP and TCP checksums require yet another + * adjustment of the ICMP checksum of the ICMP error message. + * + * For the moment we forget about TCP, because that checksum is not + * in the first 8 bytes, so it will not be available in most cases. + */ + if (nat->nat_dir == NAT_OUTBOUND) { sum1 = LONG_SUM(ntohl(oip->ip_src.s_addr)); in = nat->nat_inip; @@ -1601,19 +1656,117 @@ int dir; CALC_SUMD(sum1, sum2, sumd); if (nat->nat_dir == NAT_OUTBOUND) { - fix_incksum(&oip->ip_sum, sumd, 0); + /* + * Fix IP checksum of the offending IP packet to adjust for + * the change in the IP address. + * + * Normally, you would expect that the ICMP checksum of the + * ICMP error message needs to be adjusted as well for the + * IP address change in oip. + * However, this is a NOP, because the ICMP checksum is + * calculated over the complete ICMP packet, which includes the + * changed oip IP addresses and oip->ip_sum. However, these + * two changes cancel each other out (if the delta for + * the IP address is x, then the delta for ip_sum is minus x), + * so no change in the icmp_cksum is necessary. + * + * Be careful that nat_dir refers to the direction of the + * offending IP packet (oip), not to its ICMP response (icmp) + */ + fix_datacksum(&oip->ip_sum, sumd); - sumd += (sumd & 0xffff); - while (sumd > 0xffff) - sumd = (sumd & 0xffff) + (sumd >> 16); - fix_outcksum(&icmp->icmp_cksum, sumd, 0); + /* + * Fix UDP pseudo header checksum to compensate for the + * IP address change. + */ + if (oip->ip_p == IPPROTO_UDP && udp->uh_sum) { + /* + * The UDP checksum is optional, only adjust it + * if it has been set. + */ + sum1 = ntohs(udp->uh_sum); + fix_datacksum(&udp->uh_sum, sumd); + sum2 = ntohs(udp->uh_sum); + + /* + * Fix ICMP checksum to compensate the UDP + * checksum adjustment. + */ + CALC_SUMD(sum1, sum2, sumd); + fix_outcksum(&icmp->icmp_cksum, sumd); + } + +#if 0 + /* + * Fix TCP pseudo header checksum to compensate for the + * IP address change. Before we can do the change, we + * must make sure that oip is sufficient large to hold + * the TCP checksum (normally it does not!). + */ + if (oip->ip_p == IPPROTO_TCP) { + + } +#endif } else { - fix_outcksum(&oip->ip_sum, sumd, 0); + + /* + * Fix IP checksum of the offending IP packet to adjust for + * the change in the IP address. + * + * Normally, you would expect that the ICMP checksum of the + * ICMP error message needs to be adjusted as well for the + * IP address change in oip. + * However, this is a NOP, because the ICMP checksum is + * calculated over the complete ICMP packet, which includes the + * changed oip IP addresses and oip->ip_sum. However, these + * two changes cancel each other out (if the delta for + * the IP address is x, then the delta for ip_sum is minus x), + * so no change in the icmp_cksum is necessary. + * + * Be careful that nat_dir refers to the direction of the + * offending IP packet (oip), not to its ICMP response (icmp) + */ + fix_datacksum(&oip->ip_sum, sumd); + +/* XXX FV : without having looked at Solaris source code, it seems unlikely + * that SOLARIS would compensate this in the kernel (a body of an IP packet + * in the data section of an ICMP packet). I have the feeling that this should + * be unconditional, but I'm not in a position to check. + */ #if !SOLARIS && !defined(__sgi) - sumd += (sumd & 0xffff); - while (sumd > 0xffff) - sumd = (sumd & 0xffff) + (sumd >> 16); - fix_incksum(&icmp->icmp_cksum, sumd, 0); + /* + * Fix UDP pseudo header checksum to compensate for the + * IP address change. + */ + if (oip->ip_p == IPPROTO_UDP && udp->uh_sum) { + /* + * The UDP checksum is optional, only adjust it + * if it has been set + */ + sum1 = ntohs(udp->uh_sum); + fix_datacksum(&udp->uh_sum, sumd); + sum2 = ntohs(udp->uh_sum); + + /* + * Fix ICMP checksum to compensate the UDP + * checksum adjustment. + */ + CALC_SUMD(sum1, sum2, sumd); + fix_incksum(&icmp->icmp_cksum, sumd); + } + +#if 0 + /* + * Fix TCP pseudo header checksum to compensate for the + * IP address change. Before we can do the change, we + * must make sure that oip is sufficient large to hold + * the TCP checksum (normally it does not!). + */ + if (oip->ip_p == IPPROTO_TCP) { + + }; +#endif + #endif } @@ -1624,23 +1777,98 @@ int dir; * XXX - what if this is bogus hl and we go off the end ? * In this case, nat_icmpinlookup() will have returned NULL. */ - tcp = (tcphdr_t *)((((char *)oip) + (oip->ip_hl << 2))); + tcp = (tcphdr_t *)udp; + + /* + * Step 2 : + * For offending TCP/UDP IP packets, translate the ports as + * well, based on the NAT specification. Of course such + * a change must be reflected in the ICMP checksum as well. + * + * Advance notice : Now it becomes complicated :-) + * + * Since the port fields are part of the TCP/UDP checksum + * of the offending IP packet, you need to adjust that checksum + * as well... but, if you change, you must change the icmp + * checksum *again*, to reflect that change. + * + * To further complicate: the TCP checksum is not in the first + * 8 bytes of the offending ip packet, so it most likely is not + * available (we might have to fix that if the encounter a + * device that returns more than 8 data bytes on icmp error) + */ if (nat->nat_dir == NAT_OUTBOUND) { if (tcp->th_sport != nat->nat_inport) { + /* + * Fix ICMP checksum to compensate port + * adjustment. + */ sum1 = ntohs(tcp->th_sport); sum2 = ntohs(nat->nat_inport); CALC_SUMD(sum1, sum2, sumd); tcp->th_sport = nat->nat_inport; - fix_outcksum(&icmp->icmp_cksum, sumd, 0); + fix_outcksum(&icmp->icmp_cksum, sumd); + + /* + * Fix udp checksum to compensate port + * adjustment. NOTE : the offending IP packet + * flows the other direction compared to the + * ICMP message. + * + * The UDP checksum is optional, only adjust + * it if it has been set. + */ + if (oip->ip_p == IPPROTO_UDP && udp->uh_sum) { + + sum1 = ntohs(udp->uh_sum); + fix_datacksum(&udp->uh_sum, sumd); + sum2 = ntohs(udp->uh_sum); + + /* + * Fix ICMP checksum to + * compensate UDP checksum + * adjustment. + */ + CALC_SUMD(sum1, sum2, sumd); + fix_outcksum(&icmp->icmp_cksum, sumd); + } } } else { + if (tcp->th_dport != nat->nat_outport) { + /* + * Fix ICMP checksum to compensate port + * adjustment. + */ sum1 = ntohs(tcp->th_dport); sum2 = ntohs(nat->nat_outport); CALC_SUMD(sum1, sum2, sumd); tcp->th_dport = nat->nat_outport; - fix_incksum(&icmp->icmp_cksum, sumd, 0); + fix_incksum(&icmp->icmp_cksum, sumd); + + /* + * Fix udp checksum to compensate port + * adjustment. NOTE : the offending IP + * packet flows the other direction compared + * to the ICMP message. + * + * The UDP checksum is optional, only adjust + * it if it has been set. + */ + if (oip->ip_p == IPPROTO_UDP && udp->uh_sum) { + + sum1 = ntohs(udp->uh_sum); + fix_datacksum(&udp->uh_sum, sumd); + sum2 = ntohs(udp->uh_sum); + + /* + * Fix ICMP checksum to compensate + * UDP checksum adjustment. + */ + CALC_SUMD(sum1, sum2, sumd); + fix_incksum(&icmp->icmp_cksum, sumd); + } } } } @@ -1665,30 +1893,92 @@ register u_int flags, p; struct in_addr src , mapdst; u_32_t ports; { - register u_short sport, mapdport; + register u_short sport, dport; register nat_t *nat; register int nflags; + register u_32_t dst; u_int hv; - mapdport = ports >> 16; + dst = mapdst.s_addr; + dport = ports >> 16; sport = ports & 0xffff; flags &= IPN_TCPUDP; - hv = NAT_HASH_FN(mapdst.s_addr, mapdport, ipf_nattable_sz); + hv = NAT_HASH_FN(dst, dport, ipf_nattable_sz); nat = nat_table[1][hv]; for (; nat; nat = nat->nat_hnext[1]) { nflags = nat->nat_flags; if ((!ifp || ifp == nat->nat_ifp) && nat->nat_oip.s_addr == src.s_addr && - nat->nat_outip.s_addr == mapdst.s_addr && + nat->nat_outip.s_addr == dst && (((p == 0) && (flags == (nat->nat_flags & IPN_TCPUDP))) || (p == nat->nat_p)) && (!flags || (((nat->nat_oport == sport) || (nflags & FI_W_DPORT)) && - ((nat->nat_outport == mapdport) || - (nflags & FI_W_SPORT))))) + ((nat->nat_outport == dport) || (nflags & FI_W_SPORT))))) return nat; } - return NULL; + if (!nat_wilds || !(flags & IPN_TCPUDP)) + return NULL; + RWLOCK_EXIT(&ipf_nat); + hv = NAT_HASH_FN(dst, 0, ipf_nattable_sz); + WRITE_ENTER(&ipf_nat); + nat = nat_table[1][hv]; + for (; nat; nat = nat->nat_hnext[1]) { + nflags = nat->nat_flags; + if (ifp && ifp != nat->nat_ifp) + continue; + if (!(nflags & IPN_TCPUDP)) + continue; + if (!(nflags & FI_WILDP)) + continue; + if (nat->nat_oip.s_addr != src.s_addr || + nat->nat_outip.s_addr != dst) + continue; + if (((nat->nat_oport == sport) || (nflags & FI_W_DPORT)) && + ((nat->nat_outport == dport) || (nflags & FI_W_SPORT))) { + hv = NAT_HASH_FN(dst, dport, ipf_nattable_sz); + nat_tabmove(nat, hv); + break; + } + } + MUTEX_DOWNGRADE(&ipf_nat); + return nat; +} + + +static void nat_tabmove(nat, hv) +nat_t *nat; +u_int hv; +{ + nat_t **natp; + + /* + * Remove the NAT entry from the old location + */ + if (nat->nat_hnext[0]) + nat->nat_hnext[0]->nat_phnext[0] = nat->nat_phnext[0]; + *nat->nat_phnext[0] = nat->nat_hnext[0]; + + if (nat->nat_hnext[1]) + nat->nat_hnext[0]->nat_phnext[1] = nat->nat_phnext[1]; + *nat->nat_phnext[1] = nat->nat_hnext[1]; + + natp = &nat_table[0][hv]; + if (*natp) + (*natp)->nat_phnext[0] = &nat->nat_hnext[0]; + nat->nat_phnext[0] = natp; + nat->nat_hnext[0] = *natp; + *natp = nat; + + /* + * Add into the NAT table in the new position + */ + natp = &nat_table[1][hv]; + if (*natp) + (*natp)->nat_phnext[1] = &nat->nat_hnext[1]; + nat->nat_phnext[1] = natp; + nat->nat_hnext[1] = *natp; + *natp = nat; } @@ -1707,19 +1997,21 @@ u_32_t ports; register u_short sport, dport; register nat_t *nat; register int nflags; + u_32_t srcip; u_int hv; sport = ports & 0xffff; dport = ports >> 16; flags &= IPN_TCPUDP; + srcip = src.s_addr; - hv = NAT_HASH_FN(src.s_addr, sport, ipf_nattable_sz); + hv = NAT_HASH_FN(srcip, sport, ipf_nattable_sz); nat = nat_table[0][hv]; for (; nat; nat = nat->nat_hnext[0]) { nflags = nat->nat_flags; if ((!ifp || ifp == nat->nat_ifp) && - nat->nat_inip.s_addr == src.s_addr && + nat->nat_inip.s_addr == srcip && nat->nat_oip.s_addr == dst.s_addr && (((p == 0) && (flags == (nat->nat_flags & IPN_TCPUDP))) || (p == nat->nat_p)) && (!flags || @@ -1727,7 +2019,32 @@ u_32_t ports; (nat->nat_oport == dport || nflags & FI_W_DPORT)))) return nat; } - return NULL; + if (!nat_wilds || !(flags & IPN_TCPUDP)) + return NULL; + RWLOCK_EXIT(&ipf_nat); + hv = NAT_HASH_FN(srcip, 0, ipf_nattable_sz); + WRITE_ENTER(&ipf_nat); + nat = nat_table[0][hv]; + for (; nat; nat = nat->nat_hnext[0]) { + nflags = nat->nat_flags; + if (ifp && ifp != nat->nat_ifp) + continue; + if (!(nflags & IPN_TCPUDP)) + continue; + if (!(nflags & FI_WILDP)) + continue; + if ((nat->nat_inip.s_addr != srcip) || + (nat->nat_oip.s_addr != dst.s_addr)) + continue; + if (((nat->nat_inport == sport) || (nflags & FI_W_DPORT)) && + ((nat->nat_oport == dport) || (nflags & FI_W_SPORT))) { + hv = NAT_HASH_FN(srcip, sport, ipf_nattable_sz); + nat_tabmove(nat, hv); + break; + } + } + MUTEX_DOWNGRADE(&ipf_nat); + return nat; } @@ -1863,6 +2180,7 @@ fr_info_t *fin; nat->nat_outport = sport; nat->nat_flags &= ~(FI_W_DPORT|FI_W_SPORT); nflags = nat->nat_flags; + nat_wilds--; } } else { RWLOCK_EXIT(&ipf_nat); @@ -1943,16 +2261,16 @@ maskloop: CALC_SUMD(s1, s2, sumd); if (nat->nat_dir == NAT_OUTBOUND) - fix_incksum(&ip->ip_sum, sumd, 0); + fix_incksum(&ip->ip_sum, sumd); else - fix_outcksum(&ip->ip_sum, sumd, 0); + fix_outcksum(&ip->ip_sum, sumd); } #if SOLARIS || defined(__sgi) else { if (nat->nat_dir == NAT_OUTBOUND) - fix_outcksum(&ip->ip_sum, nat->nat_ipsumd, 0); + fix_outcksum(&ip->ip_sum, nat->nat_ipsumd); else - fix_incksum(&ip->ip_sum, nat->nat_ipsumd, 0); + fix_incksum(&ip->ip_sum, nat->nat_ipsumd); } #endif ip->ip_src = nat->nat_outip; @@ -1996,11 +2314,9 @@ maskloop: if (csump) { if (nat->nat_dir == NAT_OUTBOUND) - fix_outcksum(csump, nat->nat_sumd[1], - ip->ip_len); + fix_outcksum(csump, nat->nat_sumd[1]); else - fix_incksum(csump, nat->nat_sumd[1], - ip->ip_len); + fix_incksum(csump, nat->nat_sumd[1]); } } @@ -2077,6 +2393,7 @@ fr_info_t *fin; nat->nat_outport = dport; nat->nat_flags &= ~(FI_W_SPORT|FI_W_DPORT); nflags = nat->nat_flags; + nat_wilds--; } } else { RWLOCK_EXIT(&ipf_nat); @@ -2154,9 +2471,9 @@ maskloop: */ #if SOLARIS || defined(__sgi) if (nat->nat_dir == NAT_OUTBOUND) - fix_incksum(&ip->ip_sum, nat->nat_ipsumd, 0); + fix_incksum(&ip->ip_sum, nat->nat_ipsumd); else - fix_outcksum(&ip->ip_sum, nat->nat_ipsumd, 0); + fix_outcksum(&ip->ip_sum, nat->nat_ipsumd); #endif if (!(ip->ip_off & IP_OFFMASK) && !(fin->fin_fi.fi_fl & FI_SHORT)) { @@ -2197,11 +2514,9 @@ maskloop: if (csump) { if (nat->nat_dir == NAT_OUTBOUND) - fix_incksum(csump, nat->nat_sumd[0], - 0); + fix_incksum(csump, nat->nat_sumd[0]); else - fix_outcksum(csump, nat->nat_sumd[0], - 0); + fix_outcksum(csump, nat->nat_sumd[0]); } } ATOMIC_INCL(nat_stats.ns_mapped[0]); diff --git a/sys/contrib/ipfilter/netinet/ip_nat.h b/sys/contrib/ipfilter/netinet/ip_nat.h index b5d53e8..4b24d81 100644 --- a/sys/contrib/ipfilter/netinet/ip_nat.h +++ b/sys/contrib/ipfilter/netinet/ip_nat.h @@ -82,7 +82,7 @@ typedef struct nat { struct hostmap *nat_hm; struct nat *nat_next; struct nat *nat_hnext[2]; - struct nat **nat_hstart[2]; + struct nat **nat_phnext[2]; void *nat_ifp; int nat_dir; char nat_ifname[IFNAMSIZ]; @@ -142,6 +142,11 @@ typedef struct ipnat { #define NAT_REDIRECT 0x02 #define NAT_BIMAP (NAT_MAP|NAT_REDIRECT) #define NAT_MAPBLK 0x04 +/* 0x100 reserved for FI_W_SPORT */ +/* 0x200 reserved for FI_W_DPORT */ +/* 0x400 reserved for FI_W_SADDR */ +/* 0x800 reserved for FI_W_DADDR */ +/* 0x1000 reserved for FI_W_NEWFR */ #define MAPBLK_MINPORT 1024 /* don't use reserved ports for src port */ #define USABLE_PORTS (65536 - MAPBLK_MINPORT) @@ -294,7 +299,8 @@ extern int ip_natout __P((ip_t *, fr_info_t *)); extern int ip_natin __P((ip_t *, fr_info_t *)); extern void ip_natunload __P((void)), ip_natexpire __P((void)); extern void nat_log __P((struct nat *, u_int)); -extern void fix_incksum __P((u_short *, u_32_t, int)); -extern void fix_outcksum __P((u_short *, u_32_t, int)); +extern void fix_incksum __P((u_short *, u_32_t)); +extern void fix_outcksum __P((u_short *, u_32_t)); +extern void fix_datacksum __P((u_short *, u_32_t)); #endif /* __IP_NAT_H__ */ diff --git a/sys/contrib/ipfilter/netinet/ip_raudio_pxy.c b/sys/contrib/ipfilter/netinet/ip_raudio_pxy.c index fd62033..ee527a3 100644 --- a/sys/contrib/ipfilter/netinet/ip_raudio_pxy.c +++ b/sys/contrib/ipfilter/netinet/ip_raudio_pxy.c @@ -171,8 +171,8 @@ nat_t *nat; tcphdr_t *tcp, tcph, *tcp2 = &tcph; raudio_t *rap = aps->aps_data; struct in_addr swa, swb; - u_int a1, a2, a3, a4; int off, dlen, slen; + int a1, a2, a3, a4; u_short sp, dp; fr_info_t fi; tcp_seq seq; diff --git a/sys/contrib/ipfilter/netinet/ip_state.c b/sys/contrib/ipfilter/netinet/ip_state.c index 01fc030..ec0fb7c 100644 --- a/sys/contrib/ipfilter/netinet/ip_state.c +++ b/sys/contrib/ipfilter/netinet/ip_state.c @@ -106,6 +106,7 @@ static const char rcsid[] = "@(#)$FreeBSD$"; static ipstate_t **ips_table = NULL; static ipstate_t *ips_list = NULL; static int ips_num = 0; +static int ips_wild = 0; static ips_stat_t ips_stats; #if (SOLARIS || defined(__sgi)) && defined(_KERNEL) extern KRWLOCK_T ipf_state, ipf_mutex; @@ -123,6 +124,7 @@ static int fr_state_flush __P((int)); static ips_stat_t *fr_statetstats __P((void)); static void fr_delstate __P((ipstate_t *)); static int fr_state_remove __P((caddr_t)); +static void fr_ipsmove __P((ipstate_t **, ipstate_t *, u_int)); int fr_stputent __P((caddr_t)); int fr_stgetent __P((caddr_t)); void fr_stinsert __P((ipstate_t *)); @@ -135,7 +137,8 @@ u_long fr_tcpidletimeout = FIVE_DAYS, fr_tcpclosewait = 2 * TCP_MSL, fr_tcplastack = 2 * TCP_MSL, fr_tcptimeout = 2 * TCP_MSL, - fr_tcpclosed = 1, + fr_tcpclosed = 120, + fr_tcphalfclosed = 2 * 2 * 3600, /* 2 hours */ fr_udptimeout = 240, fr_icmptimeout = 120; int fr_statemax = IPSTATE_MAX, @@ -240,9 +243,12 @@ caddr_t data; for (sp = ips_list; sp; sp = sp->is_next) if ((sp->is_p == st.is_p) && (sp->is_v == st.is_v) && - !bcmp(&sp->is_src, &st.is_src, sizeof(st.is_src)) && - !bcmp(&sp->is_dst, &st.is_src, sizeof(st.is_dst)) && - !bcmp(&sp->is_ps, &st.is_ps, sizeof(st.is_ps))) { + !bcmp((char *)&sp->is_src, (char *)&st.is_src, + sizeof(st.is_src)) && + !bcmp((char *)&sp->is_dst, (char *)&st.is_src, + sizeof(st.is_dst)) && + !bcmp((char *)&sp->is_ps, (char *)&st.is_ps, + sizeof(st.is_ps))) { WRITE_ENTER(&ipf_state); #ifdef IPFILTER_LOG ipstate_log(sp, ISL_REMOVE); @@ -590,8 +596,8 @@ u_int flags; hv += tcp->th_dport; hv += tcp->th_sport; } - is->is_send = ntohl(tcp->th_seq) + ip->ip_len - - fin->fin_hlen - (tcp->th_off << 2) + + is->is_send = ntohl(tcp->th_seq) + fin->fin_dlen - + (tcp->th_off << 2) + ((tcp->th_flags & TH_SYN) ? 1 : 0) + ((tcp->th_flags & TH_FIN) ? 1 : 0); is->is_maxsend = is->is_send; @@ -660,6 +666,8 @@ u_int flags; is->is_flags = fin->fin_fi.fi_fl & FI_CMP; is->is_flags |= FI_CMP << 4; is->is_flags |= flags & (FI_WILDP|FI_WILDA); + if (flags & (FI_WILDP|FI_WILDA)) + ips_wild++; is->is_ifp[1 - out] = NULL; is->is_ifp[out] = fin->fin_ifp; #ifdef _KERNEL @@ -718,6 +726,7 @@ tcphdr_t *tcp; ((tcp->th_flags & TH_SYN) ? 1 : 0) + ((tcp->th_flags & TH_FIN) ? 1 : 0); + MUTEX_ENTER(&is->is_lock); if (fdata->td_end == 0) { /* * Must be a (outgoing) SYN-ACK in reply to a SYN. @@ -783,12 +792,11 @@ tcphdr_t *tcp; /* * Nearing end of connection, start timeout. */ - MUTEX_ENTER(&is->is_lock); /* source ? 0 : 1 -> !source */ fr_tcp_age(&is->is_age, is->is_state, fin, !source); - MUTEX_EXIT(&is->is_lock); ret = 1; } + MUTEX_EXIT(&is->is_lock); return ret; } @@ -892,6 +900,7 @@ tcphdr_t *tcp; is->is_maxdend = is->is_dend + 1; } is->is_flags &= ~(FI_W_SPORT|FI_W_DPORT); + ips_wild--; } ret = -1; @@ -983,7 +992,7 @@ fr_info_t *fin; * Only a basic IP header (no options) should be with * an ICMP error header. */ - if (((ip->ip_v != 4) && (ip->ip_hl != 5)) || + if (((ip->ip_v != 4) || (ip->ip_hl != 5)) || (fin->fin_plen < ICMPERR_MINPKTLEN)) return NULL; ic = (struct icmp *)fin->fin_dp; @@ -1037,8 +1046,8 @@ fr_info_t *fin; * the IP6EQ and IP6NEQ macros produce the wrong results because * of the 'junk' in the unused part of the union */ - bzero(&src, sizeof(src)); - bzero(&dst, sizeof(dst)); + bzero((char *)&src, sizeof(src)); + bzero((char *)&dst, sizeof(dst)); if (oip->ip_p == IPPROTO_ICMP) { icmp = (icmphdr_t *)((char *)oip + (oip->ip_hl << 2)); @@ -1158,6 +1167,38 @@ fr_info_t *fin; return NULL; } + +static void fr_ipsmove(isp, is, hv) +ipstate_t **isp, *is; +u_int hv; +{ + u_int hvm; + + hvm = is->is_hv; + /* + * Remove the hash from the old location... + */ + if (is->is_hnext) + is->is_hnext->is_phnext = isp; + *isp = is->is_hnext; + if (ips_table[hvm] == NULL) + ips_stats.iss_inuse--; + + /* + * ...and put the hash in the new one. + */ + hvm = hv % fr_statesize; + isp = &ips_table[hvm]; + if (*isp) + (*isp)->is_phnext = &is->is_hnext; + else + ips_stats.iss_inuse++; + is->is_phnext = isp; + is->is_hnext = *isp; + *isp = is; +} + + /* * Check if a packet has a registered state. */ @@ -1240,7 +1281,7 @@ fr_info_t *fin; break; case IPPROTO_TCP : { - register u_short dport = tcp->th_dport, sport = tcp->th_sport; + register u_short dport, sport; register int i; i = tcp->th_flags; @@ -1250,57 +1291,42 @@ fr_info_t *fin; if ((i & TH_RST) && ((i & (TH_FIN|TH_SYN|TH_RST)) != TH_RST)) break; + case IPPROTO_UDP : + dport = tcp->th_dport; + sport = tcp->th_sport; tryagain = 0; -retry_tcp: - hvm = hv % fr_statesize; - WRITE_ENTER(&ipf_state); - for (isp = &ips_table[hvm]; (is = *isp); - isp = &is->is_hnext) - - - if ((is->is_p == pr) && (is->is_v == v) && - fr_matchsrcdst(is, src, dst, fin, tcp)) { - if (fr_tcpstate(is, fin, ip, tcp)) - break; - is = NULL; - break; - } - if (is != NULL) - break; - RWLOCK_EXIT(&ipf_state); hv += dport; hv += sport; - if (tryagain == 0) { - tryagain = 1; - goto retry_tcp; - } - break; - } - case IPPROTO_UDP : - { - register u_short dport = tcp->th_dport, sport = tcp->th_sport; - - tryagain = 0; -retry_udp: - hvm = hv % fr_statesize; - /* - * Nothing else to match on but ports. and IP#'s - */ READ_ENTER(&ipf_state); - for (is = ips_table[hvm]; is; is = is->is_hnext) +retry_tcpudp: + hvm = hv % fr_statesize; + for (isp = &ips_table[hvm]; (is = *isp); isp = &is->is_hnext) if ((is->is_p == pr) && (is->is_v == v) && fr_matchsrcdst(is, src, dst, fin, tcp)) { - is->is_age = fr_udptimeout; + if ((pr == IPPROTO_TCP)) { + if (!fr_tcpstate(is, fin, ip, tcp)) { + continue; + } + } break; } - if (is != NULL) + if (is != NULL) { + if (tryagain && + !(is->is_flags & (FI_WILDP|FI_WILDA))) { + hv += dport; + hv += sport; + fr_ipsmove(isp, is, hv); + MUTEX_DOWNGRADE(&ipf_state); + } break; + } RWLOCK_EXIT(&ipf_state); - hv += dport; - hv += sport; - if (tryagain == 0) { + if (!tryagain && ips_wild) { + hv -= dport; + hv -= sport; tryagain = 1; - goto retry_udp; + WRITE_ENTER(&ipf_state); + goto retry_tcpudp; } break; } @@ -1357,6 +1383,8 @@ ipstate_t *is; { frentry_t *fr; + if (is->is_flags & (FI_WILDP|FI_WILDA)) + ips_wild--; if (is->is_next) is->is_next->is_pnext = is->is_pnext; *is->is_pnext = is->is_next; @@ -1566,7 +1594,7 @@ int dir; * SYN_RECEIVED -> FIN_WAIT_1 */ state[dir] = TCPS_FIN_WAIT_1; - *age = fr_tcpidletimeout; /* or fr_tcptimeout? */ + *age = fr_tcpidletimeout; } break; @@ -1578,7 +1606,7 @@ int dir; * ESTABLISHED -> FIN_WAIT_1 */ state[dir] = TCPS_FIN_WAIT_1; - *age = fr_tcpidletimeout; + *age = fr_tcphalfclosed; } else if (flags & TH_ACK) { /* an ACK, should we exclude other flags here? */ if (ostate == TCPS_FIN_WAIT_1) { @@ -1590,7 +1618,7 @@ int dir; * a half-closed connection */ state[dir] = TCPS_CLOSE_WAIT; - *age = fr_tcpidletimeout; + *age = fr_tcphalfclosed; } else if (ostate < TCPS_CLOSE_WAIT) /* * Still a fully established connection, @@ -1614,7 +1642,7 @@ int dir; * closed already and we did not close our side yet; * reset timeout */ - *age = fr_tcpidletimeout; + *age = fr_tcphalfclosed; } break; @@ -1638,7 +1666,7 @@ int dir; * other side is still active (ESTABLISHED/CLOSE_WAIT); * continue with this half-closed connection */ - *age = fr_tcpidletimeout; + *age = fr_tcphalfclosed; break; case TCPS_CLOSING: /* 7 */ diff --git a/sys/contrib/ipfilter/netinet/ip_state.h b/sys/contrib/ipfilter/netinet/ip_state.h index 2374068..765709c 100644 --- a/sys/contrib/ipfilter/netinet/ip_state.h +++ b/sys/contrib/ipfilter/netinet/ip_state.h @@ -174,6 +174,7 @@ extern u_long fr_tcpclosewait; extern u_long fr_tcplastack; extern u_long fr_tcptimeout; extern u_long fr_tcpclosed; +extern u_long fr_tcphalfclosed; extern u_long fr_udptimeout; extern u_long fr_icmptimeout; extern int fr_state_lock; diff --git a/sys/contrib/ipfilter/netinet/ipl.h b/sys/contrib/ipfilter/netinet/ipl.h index edb4dc9..67cbf31 100644 --- a/sys/contrib/ipfilter/netinet/ipl.h +++ b/sys/contrib/ipfilter/netinet/ipl.h @@ -12,6 +12,6 @@ #ifndef __IPL_H__ #define __IPL_H__ -#define IPL_VERSION "IP Filter: v3.4.9" +#define IPL_VERSION "IP Filter: v3.4.12" #endif diff --git a/sys/contrib/ipfilter/netinet/mlfk_ipl.c b/sys/contrib/ipfilter/netinet/mlfk_ipl.c index e92360d..1be8916 100644 --- a/sys/contrib/ipfilter/netinet/mlfk_ipl.c +++ b/sys/contrib/ipfilter/netinet/mlfk_ipl.c @@ -65,6 +65,8 @@ SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_tcptimeout, CTLFLAG_RW, &fr_tcptimeout, 0, ""); SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_tcpclosed, CTLFLAG_RW, &fr_tcpclosed, 0, ""); +SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_tcphalfclosed, CTLFLAG_RW, + &fr_tcphalfclosed, 0, ""); SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_udptimeout, CTLFLAG_RW, &fr_udptimeout, 0, ""); SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_icmptimeout, CTLFLAG_RW, diff --git a/sys/netinet/fil.c b/sys/netinet/fil.c index 1fb4b6c..12993ca 100644 --- a/sys/netinet/fil.c +++ b/sys/netinet/fil.c @@ -277,6 +277,16 @@ fr_info_t *fin; int minicmpsz = sizeof(struct icmp); icmphdr_t *icmp; + if (fin->fin_dlen > 1) + fin->fin_data[0] = *(u_short *)tcp; + + if ((!(plen >= hlen + minicmpsz) && !off) || + (off && off < sizeof(struct icmp))) { + fi->fi_fl |= FI_SHORT; + if (fin->fin_dlen < 2) + break; + } + icmp = (icmphdr_t *)tcp; if (!off && (icmp->icmp_type == ICMP_ECHOREPLY || @@ -294,11 +304,6 @@ fr_info_t *fin; icmp->icmp_type == ICMP_MASKREPLY)) minicmpsz = 12; - if ((!(plen >= hlen + minicmpsz) && !off) || - (off && off < sizeof(struct icmp))) - fi->fi_fl |= FI_SHORT; - if (fin->fin_dlen > 1) - fin->fin_data[0] = *(u_short *)tcp; break; } case IPPROTO_TCP : @@ -743,6 +748,7 @@ int out; #ifdef _KERNEL mb_t *mc = NULL; + int p, len; # if !defined(__SVR4) && !defined(__svr4__) # ifdef __sgi char hbuf[(0xf << 2) + sizeof(struct icmp) + sizeof(ip_t) + 8]; @@ -767,13 +773,26 @@ int out; } # endif /* CSUM_DELAY_DATA */ +# ifdef USE_INET6 + if (v == 6) { + len = ntohs(((ip6_t*)ip)->ip6_plen); + p = ((ip6_t *)ip)->ip6_nxt; + } else +# endif + { + p = ip->ip_p; + len = ip->ip_len; + } - if ((ip->ip_p == IPPROTO_TCP || ip->ip_p == IPPROTO_UDP || - ip->ip_p == IPPROTO_ICMP)) { + if ((p == IPPROTO_TCP || p == IPPROTO_UDP || p == IPPROTO_ICMP +# ifdef USE_INET6 + || (v == 6 && p == IPPROTO_ICMPV6) +# endif + )) { int plen = 0; - if ((ip->ip_off & IP_OFFMASK) == 0) - switch(ip->ip_p) + if ((v == 6) || (ip->ip_off & IP_OFFMASK) == 0) + switch(p) { case IPPROTO_TCP: plen = sizeof(tcphdr_t); @@ -783,10 +802,13 @@ int out; break; /* 96 - enough for complete ICMP error IP header */ case IPPROTO_ICMP: +# ifdef USE_INET6 + case IPPROTO_ICMPV6 : +# endif plen = ICMPERR_MAXPKTLEN - sizeof(ip_t); break; } - up = MIN(hlen + plen, ip->ip_len); + up = MIN(hlen + plen, len); if (up > m->m_len) { # ifdef __sgi @@ -835,8 +857,8 @@ int out; #endif changed = 0; - fin->fin_v = v; fin->fin_ifp = ifp; + fin->fin_v = v; fin->fin_out = out; fin->fin_mp = mp; fr_makefrip(hlen, ip, fin); @@ -1383,7 +1405,7 @@ nodata: * SUCH DAMAGE. * * @(#)uipc_mbuf.c 8.2 (Berkeley) 1/4/94 - * $Id: fil.c,v 2.35.2.20 2000/08/13 04:15:43 darrenr Exp $ + * $Id: fil.c,v 2.35.2.26 2000/10/24 11:58:17 darrenr Exp $ */ /* * Copy data from an mbuf chain starting "off" bytes from the beginning, @@ -1862,7 +1884,7 @@ size_t c; int err; #if SOLARIS - if (copyin(a, &ca, sizeof(ca))) + if (copyin(a, (char *)&ca, sizeof(ca))) return EFAULT; #else bcopy(a, &ca, sizeof(ca)); @@ -1882,7 +1904,7 @@ size_t c; int err; #if SOLARIS - if (copyin(b, &ca, sizeof(ca))) + if (copyin(b, (char *)&ca, sizeof(ca))) return EFAULT; #else bcopy(b, &ca, sizeof(ca)); @@ -1976,6 +1998,15 @@ friostat_t *fiop; fiop->f_acctin6[1] = ipacct6[0][1]; fiop->f_acctout6[0] = ipacct6[1][0]; fiop->f_acctout6[1] = ipacct6[1][1]; +#else + fiop->f_fin6[0] = NULL; + fiop->f_fin6[1] = NULL; + fiop->f_fout6[0] = NULL; + fiop->f_fout6[1] = NULL; + fiop->f_acctin6[0] = NULL; + fiop->f_acctin6[1] = NULL; + fiop->f_acctout6[0] = NULL; + fiop->f_acctout6[1] = NULL; #endif fiop->f_active = fr_active; fiop->f_froute[0] = ipl_frouteok[0]; diff --git a/sys/netinet/ip_auth.h b/sys/netinet/ip_auth.h index 8be860c..2851c3d 100644 --- a/sys/netinet/ip_auth.h +++ b/sys/netinet/ip_auth.h @@ -47,8 +47,6 @@ typedef struct fr_authstat { extern frentry_t *ipauth; extern struct fr_authstat fr_authstats; extern int fr_defaultauthage; -extern int fr_authstart; -extern int fr_authend; extern int fr_authsize; extern int fr_authused; extern int fr_auth_lock; diff --git a/sys/netinet/ip_compat.h b/sys/netinet/ip_compat.h index 1c3e245..d313952 100644 --- a/sys/netinet/ip_compat.h +++ b/sys/netinet/ip_compat.h @@ -264,6 +264,12 @@ union i6addr { #if defined(__FreeBSD__) && (defined(KERNEL) || defined(_KERNEL)) +# ifdef IPFILTER_LKM +# include <osreldate.h> +# define ACTUALLY_LKM_NOT_KERNEL +# else +# include <sys/osreldate.h> +# endif # if __FreeBSD__ < 3 # include <machine/spl.h> # else @@ -289,6 +295,19 @@ union i6addr { # define ATOMIC_DEC32 ATOMIC_DEC # define ATOMIC_DEC16 ATOMIC_DEC #endif +#ifdef __sgi +# define hz HZ +# include <sys/ksynch.h> +# define IPF_LOCK_PL plhi +# include <sys/sema.h> +#undef kmutex_t +typedef struct { + lock_t *l; + int pl; +} kmutex_t; +# undef MUTEX_INIT +# undef MUTEX_DESTROY +#endif #ifdef KERNEL # if SOLARIS # if SOLARIS2 >= 6 @@ -338,8 +357,8 @@ union i6addr { # define MUTEX_DESTROY(x) mutex_destroy(x) # define MUTEX_EXIT(x) mutex_exit(x) # define MTOD(m,t) (t)((m)->b_rptr) -# define IRCOPY(a,b,c) copyin((a), (b), (c)) -# define IWCOPY(a,b,c) copyout((a), (b), (c)) +# define IRCOPY(a,b,c) copyin((caddr_t)(a), (caddr_t)(b), (c)) +# define IWCOPY(a,b,c) copyout((caddr_t)(a), (caddr_t)(b), (c)) # define IRCOPYPTR ircopyptr # define IWCOPYPTR iwcopyptr # define FREE_MB_T(m) freemsg(m) @@ -384,15 +403,6 @@ extern ill_t *get_unit __P((char *, int)); # define IFNAME(x) ((ill_t *)x)->ill_name # else /* SOLARIS */ # if defined(__sgi) -# define hz HZ -# include <sys/ksynch.h> -# define IPF_LOCK_PL plhi -# include <sys/sema.h> -#undef kmutex_t -typedef struct { - lock_t *l; - int pl; -} kmutex_t; # define ATOMIC_INC(x) { MUTEX_ENTER(&ipf_rw); \ (x)++; MUTEX_EXIT(&ipf_rw); } # define ATOMIC_DEC(x) { MUTEX_ENTER(&ipf_rw); \ @@ -405,8 +415,8 @@ typedef struct { # define MUTEX_DOWNGRADE(x) ; # define RWLOCK_EXIT(x) MUTEX_EXIT(x) # define MUTEX_EXIT(x) UNLOCK((x)->l, (x)->pl); -# define MUTEX_INIT(x,y,z) (x).l = LOCK_ALLOC((uchar_t)-1, IPF_LOCK_PL, (lkinfo_t *)-1, KM_NOSLEEP) -# define MUTEX_DESTROY(x) LOCK_DEALLOC((x).l) +# define MUTEX_INIT(x,y,z) (x)->l = LOCK_ALLOC((uchar_t)-1, IPF_LOCK_PL, (lkinfo_t *)-1, KM_NOSLEEP) +# define MUTEX_DESTROY(x) LOCK_DEALLOC((x)->l) # else /* __sgi */ # define ATOMIC_INC(x) (x)++ # define ATOMIC_DEC(x) (x)-- diff --git a/sys/netinet/ip_fil.c b/sys/netinet/ip_fil.c index 27aca2f..797e599 100644 --- a/sys/netinet/ip_fil.c +++ b/sys/netinet/ip_fil.c @@ -173,6 +173,9 @@ struct callout_handle ipfr_slowtimer_ch; # include <sys/callout.h> struct callout ipfr_slowtimer_ch; #endif +#if defined(__sgi) && defined(_KERNEL) +toid_t ipfr_slowtimer_ch; +#endif #if (_BSDI_VERSION >= 199510) && defined(_KERNEL) # include <sys/device.h> @@ -322,7 +325,7 @@ pfil_error: callout_init(&ipfr_slowtimer_ch); callout_reset(&ipfr_slowtimer_ch, hz / 2, ipfr_slowtimer, NULL); # else -# if (__FreeBSD_version >= 300000) && defined(_KERNEL) +# if (__FreeBSD_version >= 300000) || defined(__sgi) ipfr_slowtimer_ch = timeout(ipfr_slowtimer, NULL, hz/2); # else timeout(ipfr_slowtimer, NULL, hz/2); @@ -353,7 +356,7 @@ int ipldetach() untimeout(ipfr_slowtimer, NULL, ipfr_slowtimer_ch); # else # ifdef __sgi - untimeout(ipfr_slowtimer); + untimeout(ipfr_slowtimer_ch); # else untimeout(ipfr_slowtimer, NULL); # endif @@ -980,8 +983,10 @@ fr_info_t *fin; if (m == NULL) return -1; - if (tcp->th_flags & TH_SYN) - tlen = 1; + tlen = oip->ip_len - fin->fin_hlen - (tcp->th_off << 2) + + ((tcp->th_flags & TH_SYN) ? 1 : 0) + + ((tcp->th_flags & TH_FIN) ? 1 : 0); + #ifdef USE_INET6 hlen = (fin->fin_v == 6) ? sizeof(ip6_t) : sizeof(ip_t); #else @@ -1002,11 +1007,16 @@ fr_info_t *fin; tcp2->th_sport = tcp->th_dport; tcp2->th_dport = tcp->th_sport; - tcp2->th_ack = ntohl(tcp->th_seq); - tcp2->th_ack += tlen; - tcp2->th_ack = htonl(tcp2->th_ack); + if (tcp->th_flags & TH_ACK) { + tcp2->th_seq = tcp->th_ack; + tcp2->th_flags = TH_RST; + } else { + tcp2->th_ack = ntohl(tcp->th_seq); + tcp2->th_ack += tlen; + tcp2->th_ack = htonl(tcp2->th_ack); + tcp2->th_flags = TH_RST|TH_ACK; + } tcp2->th_off = sizeof(*tcp2) >> 2; - tcp2->th_flags = TH_RST|TH_ACK; # ifdef USE_INET6 if (fin->fin_v == 6) { ip6->ip6_plen = htons(sizeof(struct tcphdr)); @@ -1148,7 +1158,12 @@ int dst; m_freem(m); return ENOBUFS; } +# ifdef M_TRAILINGSPACE + m->m_len = 0; + avail = M_TRAILINGSPACE(m); +# else avail = (m->m_flags & M_EXT) ? MCLBYTES : MHLEN; +# endif xtra = MIN(ntohs(oip6->ip6_plen) + sizeof(ip6_t), avail - hlen - sizeof(*icmp) - max_linkhdr); if (dst == 0) { @@ -1182,6 +1197,12 @@ int dst; icmp->icmp_type = type; icmp->icmp_code = fin->fin_icode; icmp->icmp_cksum = 0; +#ifdef icmp_nextmtu + if (type == ICMP_UNREACH && + fin->fin_icode == ICMP_UNREACH_NEEDFRAG && ifp) + icmp->icmp_nextmtu = htons(((struct ifnet *) ifp)->if_mtu); +#endif + if (avail) { bcopy((char *)oip, (char *)&icmp->icmp_ip, MIN(ohlen, avail)); avail -= MIN(ohlen, avail); diff --git a/sys/netinet/ip_frag.c b/sys/netinet/ip_frag.c index 8d2bbc5..2a10988 100644 --- a/sys/netinet/ip_frag.c +++ b/sys/netinet/ip_frag.c @@ -215,7 +215,7 @@ u_int pass; ipfr_t *ipf; if ((ip->ip_v != 4) || (fr_frag_lock)) - return NULL; + return -1; WRITE_ENTER(&ipf_frag); ipf = ipfr_new(ip, fin, pass, ipfr_heads); RWLOCK_EXIT(&ipf_frag); @@ -232,7 +232,7 @@ nat_t *nat; ipfr_t *ipf; if ((ip->ip_v != 4) || (fr_frag_lock)) - return NULL; + return -1; WRITE_ENTER(&ipf_natfrag); ipf = ipfr_new(ip, fin, pass, ipfr_nattab); if (ipf != NULL) { @@ -329,13 +329,16 @@ fr_info_t *fin; ipf = ipfr_lookup(ip, fin, ipfr_nattab); if (ipf != NULL) { nat = ipf->ipfr_data; - /* - * This is the last fragment for this packet. - */ - if ((ipf->ipfr_ttl == 1) && (nat != NULL)) { - nat->nat_data = NULL; - ipf->ipfr_data = NULL; - } + if (nat->nat_ifp == fin->fin_ifp) { + /* + * This is the last fragment for this packet. + */ + if ((ipf->ipfr_ttl == 1) && (nat != NULL)) { + nat->nat_data = NULL; + ipf->ipfr_data = NULL; + } + } else + nat = NULL; } else nat = NULL; RWLOCK_EXIT(&ipf_natfrag); diff --git a/sys/netinet/ip_frag.h b/sys/netinet/ip_frag.h index 4fb3597..48144af 100644 --- a/sys/netinet/ip_frag.h +++ b/sys/netinet/ip_frag.h @@ -61,6 +61,6 @@ extern void ipfr_slowtimer __P((void *)); # endif #else extern int ipfr_slowtimer __P((void)); -#endif +#endif /* (BSD >= 199306) || SOLARIS */ #endif /* __IP_FIL_H__ */ diff --git a/sys/netinet/ip_ftp_pxy.c b/sys/netinet/ip_ftp_pxy.c index ce06851..c68361a 100644 --- a/sys/netinet/ip_ftp_pxy.c +++ b/sys/netinet/ip_ftp_pxy.c @@ -145,6 +145,7 @@ int dlen; } else return 0; a5 >>= 8; + a5 &= 0xff; /* * Calculate new address parts for PORT command */ @@ -213,7 +214,7 @@ int dlen; sum2 -= sum1; sum2 = (sum2 & 0xffff) + (sum2 >> 16); - fix_outcksum(&ip->ip_sum, sum2, 0); + fix_outcksum(&ip->ip_sum, sum2); #endif ip->ip_len += inc; } @@ -440,7 +441,7 @@ int dlen; sum2 -= sum1; sum2 = (sum2 & 0xffff) + (sum2 >> 16); - fix_outcksum(&ip->ip_sum, sum2, 0); + fix_outcksum(&ip->ip_sum, sum2); #endif /* SOLARIS || defined(__sgi) */ ip->ip_len += inc; } @@ -669,15 +670,18 @@ int rv; while ((rptr < wptr) && (*rptr != '\r')) rptr++; - if ((*rptr == '\r') && (rptr + 1 < wptr)) { - if (*(rptr + 1) == '\n') { - rptr += 2; - f->ftps_junk = 0; + if (*rptr == '\r') { + if (rptr + 1 < wptr) { + if (*(rptr + 1) == '\n') { + rptr += 2; + f->ftps_junk = 0; + } else + rptr++; } else - rptr++; + break; } - f->ftps_rptr = rptr; } + f->ftps_rptr = rptr; if (rptr == wptr) { rptr = wptr = f->ftps_buf; @@ -761,5 +765,7 @@ char **ptr; j += c - '0'; } *ptr = s; + i &= 0xff; + j &= 0xff; return (i << 8) | j; } diff --git a/sys/netinet/ip_nat.c b/sys/netinet/ip_nat.c index 47c5f6a..ca3a27f 100644 --- a/sys/netinet/ip_nat.c +++ b/sys/netinet/ip_nat.c @@ -119,6 +119,7 @@ u_int ipf_nattable_sz = NAT_TABLE_SZ; u_int ipf_natrules_sz = NAT_SIZE; u_int ipf_rdrrules_sz = RDR_SIZE; u_int ipf_hostmap_sz = HOSTMAP_SIZE; +int nat_wilds = 0; u_32_t nat_masks = 0; u_32_t rdr_masks = 0; ipnat_t **nat_rules = NULL; @@ -144,6 +145,7 @@ static void nat_delnat __P((struct ipnat *)); static int fr_natgetent __P((caddr_t)); static int fr_natgetsz __P((caddr_t)); static int fr_natputent __P((caddr_t)); +static void nat_tabmove __P((nat_t *, u_int)); static int nat_match __P((fr_info_t *, ipnat_t *, ip_t *)); static hostmap_t *nat_hostmap __P((ipnat_t *, struct in_addr, struct in_addr)); @@ -301,10 +303,9 @@ struct hostmap *hm; } -void fix_outcksum(sp, n , len) +void fix_outcksum(sp, n) u_short *sp; u_32_t n; -int len; { register u_short sumshort; register u_32_t sum1; @@ -327,10 +328,9 @@ int len; } -void fix_incksum(sp, n , len) +void fix_incksum(sp, n) u_short *sp; u_32_t n; -int len; { register u_short sumshort; register u_32_t sum1; @@ -358,6 +358,38 @@ int len; /* + * fix_datacksum is used *only* for the adjustments of checksums in the data + * section of an IP packet. + * + * The only situation in which you need to do this is when NAT'ing an + * ICMP error message. Such a message, contains in its body the IP header + * of the original IP packet, that causes the error. + * + * You can't use fix_incksum or fix_outcksum in that case, because for the + * kernel the data section of the ICMP error is just data, and no special + * processing like hardware cksum or ntohs processing have been done by the + * kernel on the data section. + */ +void fix_datacksum(sp, n) +u_short *sp; +u_32_t n; +{ + register u_short sumshort; + register u_32_t sum1; + + if (!n) + return; + + sum1 = (~ntohs(*sp)) & 0xffff; + sum1 += (n); + sum1 = (sum1 >> 16) + (sum1 & 0xffff); + /* Again */ + sum1 = (sum1 >> 16) + (sum1 & 0xffff); + sumshort = ~(u_short)sum1; + *(sp) = htons(sumshort); +} + +/* * How the NAT is organised and works. * * Inside (interface y) NAT Outside (interface x) @@ -857,8 +889,8 @@ caddr_t data; /* * Initialize all these so that nat_delete() doesn't cause a crash. */ - nat->nat_hstart[0] = NULL; - nat->nat_hstart[1] = NULL; + nat->nat_phnext[0] = NULL; + nat->nat_phnext[1] = NULL; fr = nat->nat_fr; nat->nat_fr = NULL; aps = nat->nat_aps; @@ -970,22 +1002,16 @@ junkput: static void nat_delete(natd) struct nat *natd; { - register struct nat **natp, *nat; struct ipnat *ipn; - for (natp = natd->nat_hstart[0]; natp && (nat = *natp); - natp = &nat->nat_hnext[0]) - if (nat == natd) { - *natp = nat->nat_hnext[0]; - break; - } - - for (natp = natd->nat_hstart[1]; natp && (nat = *natp); - natp = &nat->nat_hnext[1]) - if (nat == natd) { - *natp = nat->nat_hnext[1]; - break; - } + if (natd->nat_flags & FI_WILDP) + nat_wilds--; + if (natd->nat_hnext[0]) + natd->nat_hnext[0]->nat_phnext[0] = natd->nat_phnext[0]; + *natd->nat_phnext[0] = natd->nat_hnext[0]; + if (natd->nat_hnext[1]) + natd->nat_hnext[1]->nat_phnext[1] = natd->nat_phnext[1]; + *natd->nat_phnext[1] = natd->nat_hnext[1]; if (natd->nat_fr != NULL) { ATOMIC_DEC32(natd->nat_fr->fr_ref); @@ -1030,7 +1056,7 @@ static int nat_flushtable() { register nat_t *nat, **natp; register int j = 0; - + /* * ALL NAT mappings deleted, so lets just make the deletions * quicker. @@ -1122,6 +1148,8 @@ int direction; bzero((char *)nat, sizeof(*nat)); nat->nat_flags = flags; + if (flags & FI_WILDP) + nat_wilds++; /* * Search the current table for a match. */ @@ -1444,16 +1472,22 @@ nat_t *nat; nat->nat_next = nat_instances; nat_instances = nat; + hv = NAT_HASH_FN(nat->nat_inip.s_addr, nat->nat_inport, ipf_nattable_sz); natp = &nat_table[0][hv]; - nat->nat_hstart[0] = natp; + if (*natp) + (*natp)->nat_phnext[0] = &nat->nat_hnext[0]; + nat->nat_phnext[0] = natp; nat->nat_hnext[0] = *natp; *natp = nat; + hv = NAT_HASH_FN(nat->nat_outip.s_addr, nat->nat_outport, ipf_nattable_sz); natp = &nat_table[1][hv]; - nat->nat_hstart[1] = natp; + if (*natp) + (*natp)->nat_phnext[1] = &nat->nat_hnext[1]; + nat->nat_phnext[1] = natp; nat->nat_hnext[1] = *natp; *natp = nat; @@ -1561,12 +1595,16 @@ int dir; u_32_t sum1, sum2, sumd; struct in_addr in; icmphdr_t *icmp; + udphdr_t *udp; nat_t *nat; ip_t *oip; int flags = 0; if ((fin->fin_fi.fi_fl & FI_SHORT) || (ip->ip_off & IP_OFFMASK)) return NULL; + /* + * nat_icmplookup() will return NULL for `defective' packets. + */ if ((ip->ip_v != 4) || !(nat = nat_icmplookup(ip, fin, dir))) return NULL; *nflags = IPN_ICMPERR; @@ -1576,16 +1614,33 @@ int dir; flags = IPN_TCP; else if (oip->ip_p == IPPROTO_UDP) flags = IPN_UDP; + udp = (udphdr_t *)((((char *)oip) + (oip->ip_hl << 2))); /* * Need to adjust ICMP header to include the real IP#'s and * port #'s. Only apply a checksum change relative to the - * IP address change is it will be modified again in ip_natout + * IP address change as it will be modified again in ip_natout * for both address and port. Two checksum changes are * necessary for the two header address changes. Be careful * to only modify the checksum once for the port # and twice * for the IP#. */ + /* + * Step 1 + * Fix the IP addresses in the offending IP packet. You also need + * to adjust the IP header checksum of that offending IP packet + * and the ICMP checksum of the ICMP error message itself. + * + * Unfortunately, for UDP and TCP, the IP addresses are also contained + * in the pseudo header that is used to compute the UDP resp. TCP + * checksum. So, we must compensate that as well. Even worse, the + * change in the UDP and TCP checksums require yet another + * adjustment of the ICMP checksum of the ICMP error message. + * + * For the moment we forget about TCP, because that checksum is not + * in the first 8 bytes, so it will not be available in most cases. + */ + if (nat->nat_dir == NAT_OUTBOUND) { sum1 = LONG_SUM(ntohl(oip->ip_src.s_addr)); in = nat->nat_inip; @@ -1601,19 +1656,117 @@ int dir; CALC_SUMD(sum1, sum2, sumd); if (nat->nat_dir == NAT_OUTBOUND) { - fix_incksum(&oip->ip_sum, sumd, 0); + /* + * Fix IP checksum of the offending IP packet to adjust for + * the change in the IP address. + * + * Normally, you would expect that the ICMP checksum of the + * ICMP error message needs to be adjusted as well for the + * IP address change in oip. + * However, this is a NOP, because the ICMP checksum is + * calculated over the complete ICMP packet, which includes the + * changed oip IP addresses and oip->ip_sum. However, these + * two changes cancel each other out (if the delta for + * the IP address is x, then the delta for ip_sum is minus x), + * so no change in the icmp_cksum is necessary. + * + * Be careful that nat_dir refers to the direction of the + * offending IP packet (oip), not to its ICMP response (icmp) + */ + fix_datacksum(&oip->ip_sum, sumd); - sumd += (sumd & 0xffff); - while (sumd > 0xffff) - sumd = (sumd & 0xffff) + (sumd >> 16); - fix_outcksum(&icmp->icmp_cksum, sumd, 0); + /* + * Fix UDP pseudo header checksum to compensate for the + * IP address change. + */ + if (oip->ip_p == IPPROTO_UDP && udp->uh_sum) { + /* + * The UDP checksum is optional, only adjust it + * if it has been set. + */ + sum1 = ntohs(udp->uh_sum); + fix_datacksum(&udp->uh_sum, sumd); + sum2 = ntohs(udp->uh_sum); + + /* + * Fix ICMP checksum to compensate the UDP + * checksum adjustment. + */ + CALC_SUMD(sum1, sum2, sumd); + fix_outcksum(&icmp->icmp_cksum, sumd); + } + +#if 0 + /* + * Fix TCP pseudo header checksum to compensate for the + * IP address change. Before we can do the change, we + * must make sure that oip is sufficient large to hold + * the TCP checksum (normally it does not!). + */ + if (oip->ip_p == IPPROTO_TCP) { + + } +#endif } else { - fix_outcksum(&oip->ip_sum, sumd, 0); + + /* + * Fix IP checksum of the offending IP packet to adjust for + * the change in the IP address. + * + * Normally, you would expect that the ICMP checksum of the + * ICMP error message needs to be adjusted as well for the + * IP address change in oip. + * However, this is a NOP, because the ICMP checksum is + * calculated over the complete ICMP packet, which includes the + * changed oip IP addresses and oip->ip_sum. However, these + * two changes cancel each other out (if the delta for + * the IP address is x, then the delta for ip_sum is minus x), + * so no change in the icmp_cksum is necessary. + * + * Be careful that nat_dir refers to the direction of the + * offending IP packet (oip), not to its ICMP response (icmp) + */ + fix_datacksum(&oip->ip_sum, sumd); + +/* XXX FV : without having looked at Solaris source code, it seems unlikely + * that SOLARIS would compensate this in the kernel (a body of an IP packet + * in the data section of an ICMP packet). I have the feeling that this should + * be unconditional, but I'm not in a position to check. + */ #if !SOLARIS && !defined(__sgi) - sumd += (sumd & 0xffff); - while (sumd > 0xffff) - sumd = (sumd & 0xffff) + (sumd >> 16); - fix_incksum(&icmp->icmp_cksum, sumd, 0); + /* + * Fix UDP pseudo header checksum to compensate for the + * IP address change. + */ + if (oip->ip_p == IPPROTO_UDP && udp->uh_sum) { + /* + * The UDP checksum is optional, only adjust it + * if it has been set + */ + sum1 = ntohs(udp->uh_sum); + fix_datacksum(&udp->uh_sum, sumd); + sum2 = ntohs(udp->uh_sum); + + /* + * Fix ICMP checksum to compensate the UDP + * checksum adjustment. + */ + CALC_SUMD(sum1, sum2, sumd); + fix_incksum(&icmp->icmp_cksum, sumd); + } + +#if 0 + /* + * Fix TCP pseudo header checksum to compensate for the + * IP address change. Before we can do the change, we + * must make sure that oip is sufficient large to hold + * the TCP checksum (normally it does not!). + */ + if (oip->ip_p == IPPROTO_TCP) { + + }; +#endif + #endif } @@ -1624,23 +1777,98 @@ int dir; * XXX - what if this is bogus hl and we go off the end ? * In this case, nat_icmpinlookup() will have returned NULL. */ - tcp = (tcphdr_t *)((((char *)oip) + (oip->ip_hl << 2))); + tcp = (tcphdr_t *)udp; + + /* + * Step 2 : + * For offending TCP/UDP IP packets, translate the ports as + * well, based on the NAT specification. Of course such + * a change must be reflected in the ICMP checksum as well. + * + * Advance notice : Now it becomes complicated :-) + * + * Since the port fields are part of the TCP/UDP checksum + * of the offending IP packet, you need to adjust that checksum + * as well... but, if you change, you must change the icmp + * checksum *again*, to reflect that change. + * + * To further complicate: the TCP checksum is not in the first + * 8 bytes of the offending ip packet, so it most likely is not + * available (we might have to fix that if the encounter a + * device that returns more than 8 data bytes on icmp error) + */ if (nat->nat_dir == NAT_OUTBOUND) { if (tcp->th_sport != nat->nat_inport) { + /* + * Fix ICMP checksum to compensate port + * adjustment. + */ sum1 = ntohs(tcp->th_sport); sum2 = ntohs(nat->nat_inport); CALC_SUMD(sum1, sum2, sumd); tcp->th_sport = nat->nat_inport; - fix_outcksum(&icmp->icmp_cksum, sumd, 0); + fix_outcksum(&icmp->icmp_cksum, sumd); + + /* + * Fix udp checksum to compensate port + * adjustment. NOTE : the offending IP packet + * flows the other direction compared to the + * ICMP message. + * + * The UDP checksum is optional, only adjust + * it if it has been set. + */ + if (oip->ip_p == IPPROTO_UDP && udp->uh_sum) { + + sum1 = ntohs(udp->uh_sum); + fix_datacksum(&udp->uh_sum, sumd); + sum2 = ntohs(udp->uh_sum); + + /* + * Fix ICMP checksum to + * compensate UDP checksum + * adjustment. + */ + CALC_SUMD(sum1, sum2, sumd); + fix_outcksum(&icmp->icmp_cksum, sumd); + } } } else { + if (tcp->th_dport != nat->nat_outport) { + /* + * Fix ICMP checksum to compensate port + * adjustment. + */ sum1 = ntohs(tcp->th_dport); sum2 = ntohs(nat->nat_outport); CALC_SUMD(sum1, sum2, sumd); tcp->th_dport = nat->nat_outport; - fix_incksum(&icmp->icmp_cksum, sumd, 0); + fix_incksum(&icmp->icmp_cksum, sumd); + + /* + * Fix udp checksum to compensate port + * adjustment. NOTE : the offending IP + * packet flows the other direction compared + * to the ICMP message. + * + * The UDP checksum is optional, only adjust + * it if it has been set. + */ + if (oip->ip_p == IPPROTO_UDP && udp->uh_sum) { + + sum1 = ntohs(udp->uh_sum); + fix_datacksum(&udp->uh_sum, sumd); + sum2 = ntohs(udp->uh_sum); + + /* + * Fix ICMP checksum to compensate + * UDP checksum adjustment. + */ + CALC_SUMD(sum1, sum2, sumd); + fix_incksum(&icmp->icmp_cksum, sumd); + } } } } @@ -1665,30 +1893,92 @@ register u_int flags, p; struct in_addr src , mapdst; u_32_t ports; { - register u_short sport, mapdport; + register u_short sport, dport; register nat_t *nat; register int nflags; + register u_32_t dst; u_int hv; - mapdport = ports >> 16; + dst = mapdst.s_addr; + dport = ports >> 16; sport = ports & 0xffff; flags &= IPN_TCPUDP; - hv = NAT_HASH_FN(mapdst.s_addr, mapdport, ipf_nattable_sz); + hv = NAT_HASH_FN(dst, dport, ipf_nattable_sz); nat = nat_table[1][hv]; for (; nat; nat = nat->nat_hnext[1]) { nflags = nat->nat_flags; if ((!ifp || ifp == nat->nat_ifp) && nat->nat_oip.s_addr == src.s_addr && - nat->nat_outip.s_addr == mapdst.s_addr && + nat->nat_outip.s_addr == dst && (((p == 0) && (flags == (nat->nat_flags & IPN_TCPUDP))) || (p == nat->nat_p)) && (!flags || (((nat->nat_oport == sport) || (nflags & FI_W_DPORT)) && - ((nat->nat_outport == mapdport) || - (nflags & FI_W_SPORT))))) + ((nat->nat_outport == dport) || (nflags & FI_W_SPORT))))) return nat; } - return NULL; + if (!nat_wilds || !(flags & IPN_TCPUDP)) + return NULL; + RWLOCK_EXIT(&ipf_nat); + hv = NAT_HASH_FN(dst, 0, ipf_nattable_sz); + WRITE_ENTER(&ipf_nat); + nat = nat_table[1][hv]; + for (; nat; nat = nat->nat_hnext[1]) { + nflags = nat->nat_flags; + if (ifp && ifp != nat->nat_ifp) + continue; + if (!(nflags & IPN_TCPUDP)) + continue; + if (!(nflags & FI_WILDP)) + continue; + if (nat->nat_oip.s_addr != src.s_addr || + nat->nat_outip.s_addr != dst) + continue; + if (((nat->nat_oport == sport) || (nflags & FI_W_DPORT)) && + ((nat->nat_outport == dport) || (nflags & FI_W_SPORT))) { + hv = NAT_HASH_FN(dst, dport, ipf_nattable_sz); + nat_tabmove(nat, hv); + break; + } + } + MUTEX_DOWNGRADE(&ipf_nat); + return nat; +} + + +static void nat_tabmove(nat, hv) +nat_t *nat; +u_int hv; +{ + nat_t **natp; + + /* + * Remove the NAT entry from the old location + */ + if (nat->nat_hnext[0]) + nat->nat_hnext[0]->nat_phnext[0] = nat->nat_phnext[0]; + *nat->nat_phnext[0] = nat->nat_hnext[0]; + + if (nat->nat_hnext[1]) + nat->nat_hnext[0]->nat_phnext[1] = nat->nat_phnext[1]; + *nat->nat_phnext[1] = nat->nat_hnext[1]; + + natp = &nat_table[0][hv]; + if (*natp) + (*natp)->nat_phnext[0] = &nat->nat_hnext[0]; + nat->nat_phnext[0] = natp; + nat->nat_hnext[0] = *natp; + *natp = nat; + + /* + * Add into the NAT table in the new position + */ + natp = &nat_table[1][hv]; + if (*natp) + (*natp)->nat_phnext[1] = &nat->nat_hnext[1]; + nat->nat_phnext[1] = natp; + nat->nat_hnext[1] = *natp; + *natp = nat; } @@ -1707,19 +1997,21 @@ u_32_t ports; register u_short sport, dport; register nat_t *nat; register int nflags; + u_32_t srcip; u_int hv; sport = ports & 0xffff; dport = ports >> 16; flags &= IPN_TCPUDP; + srcip = src.s_addr; - hv = NAT_HASH_FN(src.s_addr, sport, ipf_nattable_sz); + hv = NAT_HASH_FN(srcip, sport, ipf_nattable_sz); nat = nat_table[0][hv]; for (; nat; nat = nat->nat_hnext[0]) { nflags = nat->nat_flags; if ((!ifp || ifp == nat->nat_ifp) && - nat->nat_inip.s_addr == src.s_addr && + nat->nat_inip.s_addr == srcip && nat->nat_oip.s_addr == dst.s_addr && (((p == 0) && (flags == (nat->nat_flags & IPN_TCPUDP))) || (p == nat->nat_p)) && (!flags || @@ -1727,7 +2019,32 @@ u_32_t ports; (nat->nat_oport == dport || nflags & FI_W_DPORT)))) return nat; } - return NULL; + if (!nat_wilds || !(flags & IPN_TCPUDP)) + return NULL; + RWLOCK_EXIT(&ipf_nat); + hv = NAT_HASH_FN(srcip, 0, ipf_nattable_sz); + WRITE_ENTER(&ipf_nat); + nat = nat_table[0][hv]; + for (; nat; nat = nat->nat_hnext[0]) { + nflags = nat->nat_flags; + if (ifp && ifp != nat->nat_ifp) + continue; + if (!(nflags & IPN_TCPUDP)) + continue; + if (!(nflags & FI_WILDP)) + continue; + if ((nat->nat_inip.s_addr != srcip) || + (nat->nat_oip.s_addr != dst.s_addr)) + continue; + if (((nat->nat_inport == sport) || (nflags & FI_W_DPORT)) && + ((nat->nat_oport == dport) || (nflags & FI_W_SPORT))) { + hv = NAT_HASH_FN(srcip, sport, ipf_nattable_sz); + nat_tabmove(nat, hv); + break; + } + } + MUTEX_DOWNGRADE(&ipf_nat); + return nat; } @@ -1863,6 +2180,7 @@ fr_info_t *fin; nat->nat_outport = sport; nat->nat_flags &= ~(FI_W_DPORT|FI_W_SPORT); nflags = nat->nat_flags; + nat_wilds--; } } else { RWLOCK_EXIT(&ipf_nat); @@ -1943,16 +2261,16 @@ maskloop: CALC_SUMD(s1, s2, sumd); if (nat->nat_dir == NAT_OUTBOUND) - fix_incksum(&ip->ip_sum, sumd, 0); + fix_incksum(&ip->ip_sum, sumd); else - fix_outcksum(&ip->ip_sum, sumd, 0); + fix_outcksum(&ip->ip_sum, sumd); } #if SOLARIS || defined(__sgi) else { if (nat->nat_dir == NAT_OUTBOUND) - fix_outcksum(&ip->ip_sum, nat->nat_ipsumd, 0); + fix_outcksum(&ip->ip_sum, nat->nat_ipsumd); else - fix_incksum(&ip->ip_sum, nat->nat_ipsumd, 0); + fix_incksum(&ip->ip_sum, nat->nat_ipsumd); } #endif ip->ip_src = nat->nat_outip; @@ -1996,11 +2314,9 @@ maskloop: if (csump) { if (nat->nat_dir == NAT_OUTBOUND) - fix_outcksum(csump, nat->nat_sumd[1], - ip->ip_len); + fix_outcksum(csump, nat->nat_sumd[1]); else - fix_incksum(csump, nat->nat_sumd[1], - ip->ip_len); + fix_incksum(csump, nat->nat_sumd[1]); } } @@ -2077,6 +2393,7 @@ fr_info_t *fin; nat->nat_outport = dport; nat->nat_flags &= ~(FI_W_SPORT|FI_W_DPORT); nflags = nat->nat_flags; + nat_wilds--; } } else { RWLOCK_EXIT(&ipf_nat); @@ -2154,9 +2471,9 @@ maskloop: */ #if SOLARIS || defined(__sgi) if (nat->nat_dir == NAT_OUTBOUND) - fix_incksum(&ip->ip_sum, nat->nat_ipsumd, 0); + fix_incksum(&ip->ip_sum, nat->nat_ipsumd); else - fix_outcksum(&ip->ip_sum, nat->nat_ipsumd, 0); + fix_outcksum(&ip->ip_sum, nat->nat_ipsumd); #endif if (!(ip->ip_off & IP_OFFMASK) && !(fin->fin_fi.fi_fl & FI_SHORT)) { @@ -2197,11 +2514,9 @@ maskloop: if (csump) { if (nat->nat_dir == NAT_OUTBOUND) - fix_incksum(csump, nat->nat_sumd[0], - 0); + fix_incksum(csump, nat->nat_sumd[0]); else - fix_outcksum(csump, nat->nat_sumd[0], - 0); + fix_outcksum(csump, nat->nat_sumd[0]); } } ATOMIC_INCL(nat_stats.ns_mapped[0]); diff --git a/sys/netinet/ip_nat.h b/sys/netinet/ip_nat.h index b5d53e8..4b24d81 100644 --- a/sys/netinet/ip_nat.h +++ b/sys/netinet/ip_nat.h @@ -82,7 +82,7 @@ typedef struct nat { struct hostmap *nat_hm; struct nat *nat_next; struct nat *nat_hnext[2]; - struct nat **nat_hstart[2]; + struct nat **nat_phnext[2]; void *nat_ifp; int nat_dir; char nat_ifname[IFNAMSIZ]; @@ -142,6 +142,11 @@ typedef struct ipnat { #define NAT_REDIRECT 0x02 #define NAT_BIMAP (NAT_MAP|NAT_REDIRECT) #define NAT_MAPBLK 0x04 +/* 0x100 reserved for FI_W_SPORT */ +/* 0x200 reserved for FI_W_DPORT */ +/* 0x400 reserved for FI_W_SADDR */ +/* 0x800 reserved for FI_W_DADDR */ +/* 0x1000 reserved for FI_W_NEWFR */ #define MAPBLK_MINPORT 1024 /* don't use reserved ports for src port */ #define USABLE_PORTS (65536 - MAPBLK_MINPORT) @@ -294,7 +299,8 @@ extern int ip_natout __P((ip_t *, fr_info_t *)); extern int ip_natin __P((ip_t *, fr_info_t *)); extern void ip_natunload __P((void)), ip_natexpire __P((void)); extern void nat_log __P((struct nat *, u_int)); -extern void fix_incksum __P((u_short *, u_32_t, int)); -extern void fix_outcksum __P((u_short *, u_32_t, int)); +extern void fix_incksum __P((u_short *, u_32_t)); +extern void fix_outcksum __P((u_short *, u_32_t)); +extern void fix_datacksum __P((u_short *, u_32_t)); #endif /* __IP_NAT_H__ */ diff --git a/sys/netinet/ip_raudio_pxy.c b/sys/netinet/ip_raudio_pxy.c index fd62033..ee527a3 100644 --- a/sys/netinet/ip_raudio_pxy.c +++ b/sys/netinet/ip_raudio_pxy.c @@ -171,8 +171,8 @@ nat_t *nat; tcphdr_t *tcp, tcph, *tcp2 = &tcph; raudio_t *rap = aps->aps_data; struct in_addr swa, swb; - u_int a1, a2, a3, a4; int off, dlen, slen; + int a1, a2, a3, a4; u_short sp, dp; fr_info_t fi; tcp_seq seq; diff --git a/sys/netinet/ip_state.c b/sys/netinet/ip_state.c index 01fc030..ec0fb7c 100644 --- a/sys/netinet/ip_state.c +++ b/sys/netinet/ip_state.c @@ -106,6 +106,7 @@ static const char rcsid[] = "@(#)$FreeBSD$"; static ipstate_t **ips_table = NULL; static ipstate_t *ips_list = NULL; static int ips_num = 0; +static int ips_wild = 0; static ips_stat_t ips_stats; #if (SOLARIS || defined(__sgi)) && defined(_KERNEL) extern KRWLOCK_T ipf_state, ipf_mutex; @@ -123,6 +124,7 @@ static int fr_state_flush __P((int)); static ips_stat_t *fr_statetstats __P((void)); static void fr_delstate __P((ipstate_t *)); static int fr_state_remove __P((caddr_t)); +static void fr_ipsmove __P((ipstate_t **, ipstate_t *, u_int)); int fr_stputent __P((caddr_t)); int fr_stgetent __P((caddr_t)); void fr_stinsert __P((ipstate_t *)); @@ -135,7 +137,8 @@ u_long fr_tcpidletimeout = FIVE_DAYS, fr_tcpclosewait = 2 * TCP_MSL, fr_tcplastack = 2 * TCP_MSL, fr_tcptimeout = 2 * TCP_MSL, - fr_tcpclosed = 1, + fr_tcpclosed = 120, + fr_tcphalfclosed = 2 * 2 * 3600, /* 2 hours */ fr_udptimeout = 240, fr_icmptimeout = 120; int fr_statemax = IPSTATE_MAX, @@ -240,9 +243,12 @@ caddr_t data; for (sp = ips_list; sp; sp = sp->is_next) if ((sp->is_p == st.is_p) && (sp->is_v == st.is_v) && - !bcmp(&sp->is_src, &st.is_src, sizeof(st.is_src)) && - !bcmp(&sp->is_dst, &st.is_src, sizeof(st.is_dst)) && - !bcmp(&sp->is_ps, &st.is_ps, sizeof(st.is_ps))) { + !bcmp((char *)&sp->is_src, (char *)&st.is_src, + sizeof(st.is_src)) && + !bcmp((char *)&sp->is_dst, (char *)&st.is_src, + sizeof(st.is_dst)) && + !bcmp((char *)&sp->is_ps, (char *)&st.is_ps, + sizeof(st.is_ps))) { WRITE_ENTER(&ipf_state); #ifdef IPFILTER_LOG ipstate_log(sp, ISL_REMOVE); @@ -590,8 +596,8 @@ u_int flags; hv += tcp->th_dport; hv += tcp->th_sport; } - is->is_send = ntohl(tcp->th_seq) + ip->ip_len - - fin->fin_hlen - (tcp->th_off << 2) + + is->is_send = ntohl(tcp->th_seq) + fin->fin_dlen - + (tcp->th_off << 2) + ((tcp->th_flags & TH_SYN) ? 1 : 0) + ((tcp->th_flags & TH_FIN) ? 1 : 0); is->is_maxsend = is->is_send; @@ -660,6 +666,8 @@ u_int flags; is->is_flags = fin->fin_fi.fi_fl & FI_CMP; is->is_flags |= FI_CMP << 4; is->is_flags |= flags & (FI_WILDP|FI_WILDA); + if (flags & (FI_WILDP|FI_WILDA)) + ips_wild++; is->is_ifp[1 - out] = NULL; is->is_ifp[out] = fin->fin_ifp; #ifdef _KERNEL @@ -718,6 +726,7 @@ tcphdr_t *tcp; ((tcp->th_flags & TH_SYN) ? 1 : 0) + ((tcp->th_flags & TH_FIN) ? 1 : 0); + MUTEX_ENTER(&is->is_lock); if (fdata->td_end == 0) { /* * Must be a (outgoing) SYN-ACK in reply to a SYN. @@ -783,12 +792,11 @@ tcphdr_t *tcp; /* * Nearing end of connection, start timeout. */ - MUTEX_ENTER(&is->is_lock); /* source ? 0 : 1 -> !source */ fr_tcp_age(&is->is_age, is->is_state, fin, !source); - MUTEX_EXIT(&is->is_lock); ret = 1; } + MUTEX_EXIT(&is->is_lock); return ret; } @@ -892,6 +900,7 @@ tcphdr_t *tcp; is->is_maxdend = is->is_dend + 1; } is->is_flags &= ~(FI_W_SPORT|FI_W_DPORT); + ips_wild--; } ret = -1; @@ -983,7 +992,7 @@ fr_info_t *fin; * Only a basic IP header (no options) should be with * an ICMP error header. */ - if (((ip->ip_v != 4) && (ip->ip_hl != 5)) || + if (((ip->ip_v != 4) || (ip->ip_hl != 5)) || (fin->fin_plen < ICMPERR_MINPKTLEN)) return NULL; ic = (struct icmp *)fin->fin_dp; @@ -1037,8 +1046,8 @@ fr_info_t *fin; * the IP6EQ and IP6NEQ macros produce the wrong results because * of the 'junk' in the unused part of the union */ - bzero(&src, sizeof(src)); - bzero(&dst, sizeof(dst)); + bzero((char *)&src, sizeof(src)); + bzero((char *)&dst, sizeof(dst)); if (oip->ip_p == IPPROTO_ICMP) { icmp = (icmphdr_t *)((char *)oip + (oip->ip_hl << 2)); @@ -1158,6 +1167,38 @@ fr_info_t *fin; return NULL; } + +static void fr_ipsmove(isp, is, hv) +ipstate_t **isp, *is; +u_int hv; +{ + u_int hvm; + + hvm = is->is_hv; + /* + * Remove the hash from the old location... + */ + if (is->is_hnext) + is->is_hnext->is_phnext = isp; + *isp = is->is_hnext; + if (ips_table[hvm] == NULL) + ips_stats.iss_inuse--; + + /* + * ...and put the hash in the new one. + */ + hvm = hv % fr_statesize; + isp = &ips_table[hvm]; + if (*isp) + (*isp)->is_phnext = &is->is_hnext; + else + ips_stats.iss_inuse++; + is->is_phnext = isp; + is->is_hnext = *isp; + *isp = is; +} + + /* * Check if a packet has a registered state. */ @@ -1240,7 +1281,7 @@ fr_info_t *fin; break; case IPPROTO_TCP : { - register u_short dport = tcp->th_dport, sport = tcp->th_sport; + register u_short dport, sport; register int i; i = tcp->th_flags; @@ -1250,57 +1291,42 @@ fr_info_t *fin; if ((i & TH_RST) && ((i & (TH_FIN|TH_SYN|TH_RST)) != TH_RST)) break; + case IPPROTO_UDP : + dport = tcp->th_dport; + sport = tcp->th_sport; tryagain = 0; -retry_tcp: - hvm = hv % fr_statesize; - WRITE_ENTER(&ipf_state); - for (isp = &ips_table[hvm]; (is = *isp); - isp = &is->is_hnext) - - - if ((is->is_p == pr) && (is->is_v == v) && - fr_matchsrcdst(is, src, dst, fin, tcp)) { - if (fr_tcpstate(is, fin, ip, tcp)) - break; - is = NULL; - break; - } - if (is != NULL) - break; - RWLOCK_EXIT(&ipf_state); hv += dport; hv += sport; - if (tryagain == 0) { - tryagain = 1; - goto retry_tcp; - } - break; - } - case IPPROTO_UDP : - { - register u_short dport = tcp->th_dport, sport = tcp->th_sport; - - tryagain = 0; -retry_udp: - hvm = hv % fr_statesize; - /* - * Nothing else to match on but ports. and IP#'s - */ READ_ENTER(&ipf_state); - for (is = ips_table[hvm]; is; is = is->is_hnext) +retry_tcpudp: + hvm = hv % fr_statesize; + for (isp = &ips_table[hvm]; (is = *isp); isp = &is->is_hnext) if ((is->is_p == pr) && (is->is_v == v) && fr_matchsrcdst(is, src, dst, fin, tcp)) { - is->is_age = fr_udptimeout; + if ((pr == IPPROTO_TCP)) { + if (!fr_tcpstate(is, fin, ip, tcp)) { + continue; + } + } break; } - if (is != NULL) + if (is != NULL) { + if (tryagain && + !(is->is_flags & (FI_WILDP|FI_WILDA))) { + hv += dport; + hv += sport; + fr_ipsmove(isp, is, hv); + MUTEX_DOWNGRADE(&ipf_state); + } break; + } RWLOCK_EXIT(&ipf_state); - hv += dport; - hv += sport; - if (tryagain == 0) { + if (!tryagain && ips_wild) { + hv -= dport; + hv -= sport; tryagain = 1; - goto retry_udp; + WRITE_ENTER(&ipf_state); + goto retry_tcpudp; } break; } @@ -1357,6 +1383,8 @@ ipstate_t *is; { frentry_t *fr; + if (is->is_flags & (FI_WILDP|FI_WILDA)) + ips_wild--; if (is->is_next) is->is_next->is_pnext = is->is_pnext; *is->is_pnext = is->is_next; @@ -1566,7 +1594,7 @@ int dir; * SYN_RECEIVED -> FIN_WAIT_1 */ state[dir] = TCPS_FIN_WAIT_1; - *age = fr_tcpidletimeout; /* or fr_tcptimeout? */ + *age = fr_tcpidletimeout; } break; @@ -1578,7 +1606,7 @@ int dir; * ESTABLISHED -> FIN_WAIT_1 */ state[dir] = TCPS_FIN_WAIT_1; - *age = fr_tcpidletimeout; + *age = fr_tcphalfclosed; } else if (flags & TH_ACK) { /* an ACK, should we exclude other flags here? */ if (ostate == TCPS_FIN_WAIT_1) { @@ -1590,7 +1618,7 @@ int dir; * a half-closed connection */ state[dir] = TCPS_CLOSE_WAIT; - *age = fr_tcpidletimeout; + *age = fr_tcphalfclosed; } else if (ostate < TCPS_CLOSE_WAIT) /* * Still a fully established connection, @@ -1614,7 +1642,7 @@ int dir; * closed already and we did not close our side yet; * reset timeout */ - *age = fr_tcpidletimeout; + *age = fr_tcphalfclosed; } break; @@ -1638,7 +1666,7 @@ int dir; * other side is still active (ESTABLISHED/CLOSE_WAIT); * continue with this half-closed connection */ - *age = fr_tcpidletimeout; + *age = fr_tcphalfclosed; break; case TCPS_CLOSING: /* 7 */ diff --git a/sys/netinet/ip_state.h b/sys/netinet/ip_state.h index 2374068..765709c 100644 --- a/sys/netinet/ip_state.h +++ b/sys/netinet/ip_state.h @@ -174,6 +174,7 @@ extern u_long fr_tcpclosewait; extern u_long fr_tcplastack; extern u_long fr_tcptimeout; extern u_long fr_tcpclosed; +extern u_long fr_tcphalfclosed; extern u_long fr_udptimeout; extern u_long fr_icmptimeout; extern int fr_state_lock; diff --git a/sys/netinet/ipl.h b/sys/netinet/ipl.h index edb4dc9..67cbf31 100644 --- a/sys/netinet/ipl.h +++ b/sys/netinet/ipl.h @@ -12,6 +12,6 @@ #ifndef __IPL_H__ #define __IPL_H__ -#define IPL_VERSION "IP Filter: v3.4.9" +#define IPL_VERSION "IP Filter: v3.4.12" #endif diff --git a/sys/netinet/mlfk_ipl.c b/sys/netinet/mlfk_ipl.c index e92360d..1be8916 100644 --- a/sys/netinet/mlfk_ipl.c +++ b/sys/netinet/mlfk_ipl.c @@ -65,6 +65,8 @@ SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_tcptimeout, CTLFLAG_RW, &fr_tcptimeout, 0, ""); SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_tcpclosed, CTLFLAG_RW, &fr_tcpclosed, 0, ""); +SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_tcphalfclosed, CTLFLAG_RW, + &fr_tcphalfclosed, 0, ""); SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_udptimeout, CTLFLAG_RW, &fr_udptimeout, 0, ""); SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_icmptimeout, CTLFLAG_RW, |