Subject: Re: placement of PFIL_HOOKS filtering points
To: Darren Reed <darrenr@reed.wattle.id.au>
From: Jason R Thorpe <thorpej@zembu.com>
List: tech-net
Date: 11/07/2000 17:18:36
On Wed, Nov 08, 2000 at 08:08:15AM +1100, Darren Reed wrote:

 > Hmmm, it would make sense for all packet information going through
 > pfil to either be in network byte order or host byte order.  Since
 > it is both impracticle and awkward to do the latter for all places
 > where you might want to add filtering hooks, changing it to always
 > pass packets in network byte order does seem better.

So, here is my proposed patch.

-- 
        -- Jason R. Thorpe <thorpej@zembu.com>

Index: fil.c
===================================================================
RCS file: /cvsroot/syssrc/sys/netinet/fil.c,v
retrieving revision 1.40
diff -c -r1.40 fil.c
*** fil.c	2000/10/08 13:01:30	1.40
--- fil.c	2000/11/08 01:14:24
***************
*** 713,718 ****
--- 713,744 ----
  	return pass;
  }
  
+ #if defined(__NetBSD__) && defined(_KERNEL)
+ int
+ fr_check_wrapper(ip_t *ip, int hlen, void *ifp, int out, mb_t **mp)
+ {
+ 	int rv;
+ 
+ 	/*
+ 	 * We get the packet with all fields in network byte
+ 	 * order.  We expect ip_len and ip_off to be in host
+ 	 * order.  We frob them, call the filter, then frob
+ 	 * them back.
+ 	 *
+ 	 * Note, we don't need to update the checksum, because
+ 	 * it has already been verified.
+ 	 */
+ 	NTOHS(ip->ip_len);
+ 	NTOHS(ip->ip_off);
+ 
+ 	rv = fr_check(ip, hlen, ifp, out, mp);
+ 
+ 	HTONS(ip->ip_len);
+ 	HTONS(ip->ip_off);
+ 
+ 	return (rv);
+ }
+ #endif /* __NetBSD__ && _KERNEL */
  
  /*
   * frcheck - filter check
Index: ip_fil.c
===================================================================
RCS file: /cvsroot/syssrc/sys/netinet/ip_fil.c,v
retrieving revision 1.59
diff -c -r1.59 ip_fil.c
*** ip_fil.c	2000/08/22 16:02:16	1.59
--- ip_fil.c	2000/11/08 01:14:25
***************
*** 265,271 ****
  
  # ifdef NETBSD_PF
  #  if __NetBSD_Version__ >= 104200000
! 	error = pfil_add_hook((void *)fr_check, PFIL_IN|PFIL_OUT,
  			      &inetsw[ip_protox[IPPROTO_IP]].pr_pfh);
  	if (error) {
  #   ifdef USE_INET6
--- 265,271 ----
  
  # ifdef NETBSD_PF
  #  if __NetBSD_Version__ >= 104200000
! 	error = pfil_add_hook((void *)fr_check_wrapper, PFIL_IN|PFIL_OUT,
  			      &inetsw[ip_protox[IPPROTO_IP]].pr_pfh);
  	if (error) {
  #   ifdef USE_INET6
***************
*** 284,290 ****
  	error = pfil_add_hook((void *)fr_check, PFIL_IN|PFIL_OUT,
  			      &inetsw[ip_protox[IPPROTO_IPV6]].pr_pfh);
  	if (error) {
! 		pfil_remove_hook((void *)fr_check, PFIL_IN|PFIL_OUT,
  				 &inetsw[ip_protox[IPPROTO_IP]].pr_pfh);
  pfil_error:
  		appr_unload();
--- 284,290 ----
  	error = pfil_add_hook((void *)fr_check, PFIL_IN|PFIL_OUT,
  			      &inetsw[ip_protox[IPPROTO_IPV6]].pr_pfh);
  	if (error) {
! 		pfil_remove_hook((void *)fr_check_wrapper, PFIL_IN|PFIL_OUT,
  				 &inetsw[ip_protox[IPPROTO_IP]].pr_pfh);
  pfil_error:
  		appr_unload();
***************
*** 388,394 ****
  
  # ifdef NETBSD_PF
  #  if __NetBSD_Version__ >= 104200000
! 	error = pfil_remove_hook((void *)fr_check, PFIL_IN|PFIL_OUT,
  				 &inetsw[ip_protox[IPPROTO_IP]].pr_pfh);
  	if (error)
  		return error;
--- 388,394 ----
  
  # ifdef NETBSD_PF
  #  if __NetBSD_Version__ >= 104200000
! 	error = pfil_remove_hook((void *)fr_check_wrapper, PFIL_IN|PFIL_OUT,
  				 &inetsw[ip_protox[IPPROTO_IP]].pr_pfh);
  	if (error)
  		return error;
***************
*** 396,402 ****
  	pfil_remove_hook((void *)fr_check, PFIL_IN|PFIL_OUT);
  #  endif
  #  ifdef USE_INET6
! 	error = pfil_remove_hook((void *)fr_check, PFIL_IN|PFIL_OUT,
  				 &inetsw[ip_protox[IPPROTO_IPV6]].pr_pfh);
  	if (error)
  		return error;
--- 396,402 ----
  	pfil_remove_hook((void *)fr_check, PFIL_IN|PFIL_OUT);
  #  endif
  #  ifdef USE_INET6
! 	error = pfil_remove_hook((void *)fr_check_wrapper, PFIL_IN|PFIL_OUT,
  				 &inetsw[ip_protox[IPPROTO_IPV6]].pr_pfh);
  	if (error)
  		return error;
Index: ip_fil.h
===================================================================
RCS file: /cvsroot/syssrc/sys/netinet/ip_fil.h,v
retrieving revision 1.37
diff -c -r1.37 ip_fil.h
*** ip_fil.h	2000/06/12 10:28:21	1.37
--- ip_fil.h	2000/11/08 01:14:25
***************
*** 531,536 ****
--- 531,539 ----
  extern	int	fr_qout __P((queue_t *, mblk_t *));
  extern	int	iplread __P((dev_t, struct uio *, cred_t *));
  # else /* SOLARIS */
+ #if defined(__NetBSD__)
+ extern	int	fr_check_wrapper __P((ip_t *, int, void *, int, mb_t **));
+ #endif
  extern	int	fr_check __P((ip_t *, int, void *, int, mb_t **));
  extern	int	(*fr_checkp) __P((ip_t *, int, void *, int, mb_t **));
  extern	int	ipfr_fastroute __P((mb_t *, fr_info_t *, frdest_t *));
Index: ip_input.c
===================================================================
RCS file: /cvsroot/syssrc/sys/netinet/ip_input.c,v
retrieving revision 1.119
diff -c -r1.119 ip_input.c
*** ip_input.c	2000/10/13 01:50:04	1.119
--- ip_input.c	2000/11/08 01:14:26
***************
*** 414,425 ****
  		goto bad;
  	}
  
! 	/*
! 	 * Convert fields to host representation.
! 	 */
! 	NTOHS(ip->ip_len);
! 	NTOHS(ip->ip_off);
! 	len = ip->ip_len;
  
  	/*
  	 * Check for additional length bogosity
--- 414,421 ----
  		goto bad;
  	}
  
! 	/* Retrieve the packet length. */
! 	len = ntohs(ip->ip_len);
  
  	/*
  	 * Check for additional length bogosity
***************
*** 480,485 ****
--- 476,487 ----
  			ip = mtod(m, struct ip *);
  		}
  #endif /* PFIL_HOOKS */
+ 
+ 	/*
+ 	 * Convert fields to host representation.
+ 	 */
+ 	NTOHS(ip->ip_len);
+ 	NTOHS(ip->ip_off);
  
  	/*
  	 * Process options and, if not destined for us,
Index: ip_output.c
===================================================================
RCS file: /cvsroot/syssrc/sys/netinet/ip_output.c,v
retrieving revision 1.77
diff -c -r1.77 ip_output.c
*** ip_output.c	2000/10/23 03:42:18	1.77
--- ip_output.c	2000/11/08 01:14:27
***************
*** 185,190 ****
--- 185,191 ----
  	struct socket *so;
  	struct secpolicy *sp = NULL;
  #endif /*IPSEC*/
+ 	u_int16_t ip_len, ip_off;
  
  	va_start(ap, m0);
  	opt = va_arg(ap, struct mbuf *);
***************
*** 420,425 ****
--- 421,436 ----
  	    (ro->ro_rt->rt_rmx.rmx_locks & RTV_MTU) == 0)
  		ip->ip_off |= IP_DF;
  
+ 	/*
+ 	 * Remember the current ip_len and ip_off, and swap them into
+ 	 * network order.
+ 	 */
+ 	ip_len = ip->ip_len;
+ 	ip_off = ip->ip_off;
+ 
+ 	HTONS(ip->ip_len);
+ 	HTONS(ip->ip_off);
+ 
  #ifdef PFIL_HOOKS
  	/*
  	 * Run through list of hooks for output packets.
***************
*** 482,490 ****
  		printf("ip_output: Invalid policy found. %d\n", sp->policy);
  	}
  
! 	ip->ip_len = htons((u_short)ip->ip_len);
! 	ip->ip_off = htons((u_short)ip->ip_off);
! 	ip->ip_sum = 0;
  
      {
  	struct ipsec_output_state state;
--- 493,502 ----
  		printf("ip_output: Invalid policy found. %d\n", sp->policy);
  	}
  
! 	/*
! 	 * ipsec4_output() expects ip_len and ip_off in network
! 	 * order.  They have been set to network order above.
! 	 */
  
      {
  	struct ipsec_output_state state;
***************
*** 541,546 ****
--- 553,561 ----
  #else
  	hlen = ip->ip_hl << 2;
  #endif
+ 	ip_len = ntohs(ip->ip_len);
+ 	ip_off = ntohs(ip->ip_off);
+ 
  	if (ro->ro_rt == NULL) {
  		if ((flags & IP_ROUTETOIF) == 0) {
  			printf("ip_output: "
***************
*** 553,568 ****
  		ifp = ro->ro_rt->rt_ifp;
  	}
  
- 	/* make it flipped, again. */
- 	ip->ip_len = ntohs((u_short)ip->ip_len);
- 	ip->ip_off = ntohs((u_short)ip->ip_off);
  skip_ipsec:
  #endif /*IPSEC*/
  
  	/*
  	 * If small enough for mtu of path, can just send directly.
  	 */
! 	if ((u_int16_t)ip->ip_len <= mtu) {
  #if IFA_STATS
  		/*
  		 * search for the source address structure to
--- 568,580 ----
  		ifp = ro->ro_rt->rt_ifp;
  	}
  
  skip_ipsec:
  #endif /*IPSEC*/
  
  	/*
  	 * If small enough for mtu of path, can just send directly.
  	 */
! 	if (ip_len <= mtu) {
  #if IFA_STATS
  		/*
  		 * search for the source address structure to
***************
*** 570,579 ****
  		 */
  		INADDR_TO_IA(ip->ip_src, ia);
  		if (ia)
! 			ia->ia_ifa.ifa_data.ifad_outbytes += ip->ip_len;
  #endif
- 		HTONS(ip->ip_len);
- 		HTONS(ip->ip_off);
  		ip->ip_sum = 0;
  		ip->ip_sum = in_cksum(m, hlen);
  		error = (*ifp->if_output)(ifp, m, sintosa(dst), ro->ro_rt);
--- 582,589 ----
  		 */
  		INADDR_TO_IA(ip->ip_src, ia);
  		if (ia)
! 			ia->ia_ifa.ifa_data.ifad_outbytes += ip_len;
  #endif
  		ip->ip_sum = 0;
  		ip->ip_sum = in_cksum(m, hlen);
  		error = (*ifp->if_output)(ifp, m, sintosa(dst), ro->ro_rt);
***************
*** 583,589 ****
--- 593,606 ----
  	/*
  	 * Too large for interface; fragment if possible.
  	 * Must be able to put at least 8 bytes per fragment.
+ 	 *
+ 	 * Note we swap ip_len and ip_off into host order to make
+ 	 * the logic below a little simpler.
  	 */
+ 
+ 	NTOHS(ip->ip_len);
+ 	NTOHS(ip->ip_off);
+ 
  #if 0
  	/*
  	 * If IPsec packet is too big for the interface, try fragment it.