17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * Copyright (C) 2002-2003 by Ryan Beasley <ryanb@goddamnbastard.org>
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * See the IPFILTER.LICENCE file for details on licencing.
5f4b3ec61Sdh  *
633f2fefdSDarren Reed  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
7f4b3ec61Sdh  * Use is subject to license terms.
87c478bd9Sstevel@tonic-gate  */
97c478bd9Sstevel@tonic-gate /*
107c478bd9Sstevel@tonic-gate  * Overview:
117c478bd9Sstevel@tonic-gate  *   This is an in-kernel application proxy for Sun's RPCBIND (nee portmap)
127c478bd9Sstevel@tonic-gate  *   protocol as defined in RFC1833.  It is far from complete, mostly
137c478bd9Sstevel@tonic-gate  *   lacking in less-likely corner cases, but it's definitely functional.
147c478bd9Sstevel@tonic-gate  *
157c478bd9Sstevel@tonic-gate  *   Invocation:
167c478bd9Sstevel@tonic-gate  *     rdr <int> <e_ip>/32 port <e_p> -> <i_ip> port <i_p> udp proxy rpcbu
177c478bd9Sstevel@tonic-gate  *
187c478bd9Sstevel@tonic-gate  *   If the host running IP Filter is the same as the RPC server, it's
197c478bd9Sstevel@tonic-gate  *   perfectly legal for both the internal and external addresses and ports
207c478bd9Sstevel@tonic-gate  *   to match.
217c478bd9Sstevel@tonic-gate  *
227c478bd9Sstevel@tonic-gate  *   When triggered by appropriate IP NAT rules, this proxy works by
237c478bd9Sstevel@tonic-gate  *   examining data contained in received packets.  Requests and replies are
247c478bd9Sstevel@tonic-gate  *   modified, NAT and state table entries created, etc., as necessary.
257c478bd9Sstevel@tonic-gate  */
267c478bd9Sstevel@tonic-gate /*
277c478bd9Sstevel@tonic-gate  * TODO / NOTES
287c478bd9Sstevel@tonic-gate  *
297c478bd9Sstevel@tonic-gate  *   o Must implement locking to protect proxy session data.
307c478bd9Sstevel@tonic-gate  *   o Fragmentation isn't supported.
317c478bd9Sstevel@tonic-gate  *   o Only supports UDP.
327c478bd9Sstevel@tonic-gate  *   o Doesn't support multiple RPC records in a single request.
337c478bd9Sstevel@tonic-gate  *   o Errors should be more fine-grained.  (e.g., malloc failure vs.
347c478bd9Sstevel@tonic-gate  *     illegal RPCB request / reply)
357c478bd9Sstevel@tonic-gate  *   o Even with the limit on the total amount of recorded transactions,
367c478bd9Sstevel@tonic-gate  *     should there be a timeout on transaction removal?
377c478bd9Sstevel@tonic-gate  *   o There is a potential collision between cloning, wildcard NAT and
387c478bd9Sstevel@tonic-gate  *     state entries.  There should be an appr_getport routine for
397c478bd9Sstevel@tonic-gate  *     to avoid this.
407c478bd9Sstevel@tonic-gate  *   o The enclosed hack of STREAMS support is pretty sick and most likely
417c478bd9Sstevel@tonic-gate  *     broken.
427c478bd9Sstevel@tonic-gate  *
43ab25eeb5Syz  *	$Id: ip_rpcb_pxy.c,v 2.25.2.3 2005/02/04 10:22:56 darrenr Exp $
447c478bd9Sstevel@tonic-gate  */
457c478bd9Sstevel@tonic-gate 
467c478bd9Sstevel@tonic-gate #define	IPF_RPCB_PROXY
477c478bd9Sstevel@tonic-gate 
48f4b3ec61Sdh typedef struct ifs_rpcbpxy {
49f4b3ec61Sdh 	frentry_t	rpcbfr;	/* Skeleton rule for reference by entities
50f4b3ec61Sdh 				   this proxy creates. */
51f4b3ec61Sdh 	int		rpcbcnt;/* Upper bound of allocated RPCB sessions. */
52f4b3ec61Sdh 				/* XXX rpcbcnt still requires locking. */
53f4b3ec61Sdh 	int		rpcb_proxy_init;
54f4b3ec61Sdh } ifs_rpcbpxy_t;
55f4b3ec61Sdh 
567c478bd9Sstevel@tonic-gate /*
577c478bd9Sstevel@tonic-gate  * Function prototypes
587c478bd9Sstevel@tonic-gate  */
59f4b3ec61Sdh int	ippr_rpcb_init __P((void **, ipf_stack_t *));
60f4b3ec61Sdh void	ippr_rpcb_fini __P((void **, ipf_stack_t *));
61f4b3ec61Sdh int	ippr_rpcb_new __P((fr_info_t *, ap_session_t *, nat_t *, void *));
62f4b3ec61Sdh void	ippr_rpcb_del __P((ap_session_t *, void *, ipf_stack_t *));
63f4b3ec61Sdh int	ippr_rpcb_in __P((fr_info_t *, ap_session_t *, nat_t *, void *));
64f4b3ec61Sdh int	ippr_rpcb_out __P((fr_info_t *, ap_session_t *, nat_t *, void *));
657c478bd9Sstevel@tonic-gate 
667c478bd9Sstevel@tonic-gate static void	ippr_rpcb_flush __P((rpcb_session_t *));
677c478bd9Sstevel@tonic-gate static int	ippr_rpcb_decodereq __P((fr_info_t *, nat_t *,
68f4b3ec61Sdh 	rpcb_session_t *, rpc_msg_t *, ifs_rpcbpxy_t *));
697c478bd9Sstevel@tonic-gate static int	ippr_rpcb_skipauth __P((rpc_msg_t *, xdr_auth_t *, u_32_t **));
70f4b3ec61Sdh static int	ippr_rpcb_insert __P((rpcb_session_t *, rpcb_xact_t *,
71f4b3ec61Sdh 				      ifs_rpcbpxy_t *));
727c478bd9Sstevel@tonic-gate static int	ippr_rpcb_xdrrpcb __P((rpc_msg_t *, u_32_t *, rpcb_args_t *));
737c478bd9Sstevel@tonic-gate static int	ippr_rpcb_getuaddr __P((rpc_msg_t *, xdr_uaddr_t *,
747c478bd9Sstevel@tonic-gate 	u_32_t **));
757c478bd9Sstevel@tonic-gate static u_int	ippr_rpcb_atoi __P((char *));
767c478bd9Sstevel@tonic-gate static int	ippr_rpcb_modreq __P((fr_info_t *, nat_t *, rpc_msg_t *,
777c478bd9Sstevel@tonic-gate 	mb_t *, u_int));
787c478bd9Sstevel@tonic-gate static int	ippr_rpcb_decoderep __P((fr_info_t *, nat_t *,
79f4b3ec61Sdh 	rpcb_session_t *, rpc_msg_t *, rpcb_xact_t **, ifs_rpcbpxy_t *));
807c478bd9Sstevel@tonic-gate static rpcb_xact_t *	ippr_rpcb_lookup __P((rpcb_session_t *, u_32_t));
81f4b3ec61Sdh static void	ippr_rpcb_deref __P((rpcb_session_t *, rpcb_xact_t *,
82f4b3ec61Sdh 				     ifs_rpcbpxy_t *));
837c478bd9Sstevel@tonic-gate static int	ippr_rpcb_getproto __P((rpc_msg_t *, xdr_proto_t *,
847c478bd9Sstevel@tonic-gate 	u_32_t **));
85f4b3ec61Sdh static int	ippr_rpcb_getnat __P((fr_info_t *, nat_t *, u_int, u_int, ifs_rpcbpxy_t *));
867c478bd9Sstevel@tonic-gate static int	ippr_rpcb_modv3 __P((fr_info_t *, nat_t *, rpc_msg_t *,
877c478bd9Sstevel@tonic-gate 	mb_t *, u_int));
887c478bd9Sstevel@tonic-gate static int	ippr_rpcb_modv4 __P((fr_info_t *, nat_t *, rpc_msg_t *,
897c478bd9Sstevel@tonic-gate 	mb_t *, u_int));
907c478bd9Sstevel@tonic-gate static void     ippr_rpcb_fixlen __P((fr_info_t *, int));
91ab25eeb5Syz 
927c478bd9Sstevel@tonic-gate /*
937c478bd9Sstevel@tonic-gate  * Since rpc_msg contains only pointers, one should use this macro as a
947c478bd9Sstevel@tonic-gate  * handy way to get to the goods.  (In case you're wondering about the name,
957c478bd9Sstevel@tonic-gate  * this started as BYTEREF -> BREF -> B.)
967c478bd9Sstevel@tonic-gate  */
977c478bd9Sstevel@tonic-gate #define	B(r)	(u_32_t)ntohl(*(r))
987c478bd9Sstevel@tonic-gate 
997c478bd9Sstevel@tonic-gate /*
1007c478bd9Sstevel@tonic-gate  * Public subroutines
1017c478bd9Sstevel@tonic-gate  */
1027c478bd9Sstevel@tonic-gate 
1037c478bd9Sstevel@tonic-gate /* --------------------------------------------------------------------	*/
1047c478bd9Sstevel@tonic-gate /* Function:	ippr_rpcb_init						*/
1057c478bd9Sstevel@tonic-gate /* Returns:	int - 0 == success					*/
1067c478bd9Sstevel@tonic-gate /* Parameters:	(void)							*/
1077c478bd9Sstevel@tonic-gate /*									*/
1087c478bd9Sstevel@tonic-gate /* Initialize the filter rule entry and session limiter.		*/
1097c478bd9Sstevel@tonic-gate /* --------------------------------------------------------------------	*/
110f4b3ec61Sdh /*ARGSUSED*/
1117c478bd9Sstevel@tonic-gate int
ippr_rpcb_init(private,ifs)112f4b3ec61Sdh ippr_rpcb_init(private, ifs)
113f4b3ec61Sdh void **private;
114f4b3ec61Sdh ipf_stack_t *ifs;
1157c478bd9Sstevel@tonic-gate {
116f4b3ec61Sdh 	ifs_rpcbpxy_t *ifsrpcb;
117f4b3ec61Sdh 
118f4b3ec61Sdh 	KMALLOC(ifsrpcb, ifs_rpcbpxy_t *);
119f4b3ec61Sdh 	if (ifsrpcb == NULL)
120f4b3ec61Sdh 		return -1;
121f4b3ec61Sdh 
122f4b3ec61Sdh 	ifsrpcb->rpcbcnt = 0;
1237c478bd9Sstevel@tonic-gate 
124f4b3ec61Sdh 	bzero((char *)&ifsrpcb->rpcbfr, sizeof(ifsrpcb->rpcbfr));
125f4b3ec61Sdh 	ifsrpcb->rpcbfr.fr_ref = 1;
126f4b3ec61Sdh 	ifsrpcb->rpcbfr.fr_flags = FR_PASS|FR_QUICK|FR_KEEPSTATE;
127f4b3ec61Sdh 	MUTEX_INIT(&ifsrpcb->rpcbfr.fr_lock, "ipf Sun RPCB proxy rule lock");
128f4b3ec61Sdh 	ifsrpcb->rpcb_proxy_init = 1;
129f4b3ec61Sdh 
130f4b3ec61Sdh 	*private = (void *)ifsrpcb;
1317c478bd9Sstevel@tonic-gate 
1327c478bd9Sstevel@tonic-gate 	return(0);
1337c478bd9Sstevel@tonic-gate }
1347c478bd9Sstevel@tonic-gate 
1357c478bd9Sstevel@tonic-gate /* --------------------------------------------------------------------	*/
1367c478bd9Sstevel@tonic-gate /* Function:	ippr_rpcb_fini						*/
1377c478bd9Sstevel@tonic-gate /* Returns:	void							*/
1387c478bd9Sstevel@tonic-gate /* Parameters:	(void)							*/
1397c478bd9Sstevel@tonic-gate /*									*/
1407c478bd9Sstevel@tonic-gate /* Destroy rpcbfr's mutex to avoid a lock leak.				*/
1417c478bd9Sstevel@tonic-gate /* --------------------------------------------------------------------	*/
142f4b3ec61Sdh /*ARGSUSED*/
1437c478bd9Sstevel@tonic-gate void
ippr_rpcb_fini(private,ifs)144f4b3ec61Sdh ippr_rpcb_fini(private, ifs)
145f4b3ec61Sdh void **private;
146f4b3ec61Sdh ipf_stack_t *ifs;
1477c478bd9Sstevel@tonic-gate {
148f4b3ec61Sdh 	ifs_rpcbpxy_t *ifsrpcb = *((ifs_rpcbpxy_t **)private);
149f4b3ec61Sdh 
150f4b3ec61Sdh 	if (ifsrpcb->rpcb_proxy_init == 1) {
151f4b3ec61Sdh 		MUTEX_DESTROY(&ifsrpcb->rpcbfr.fr_lock);
152f4b3ec61Sdh 		ifsrpcb->rpcb_proxy_init = 0;
1537c478bd9Sstevel@tonic-gate 	}
154f4b3ec61Sdh 
155f4b3ec61Sdh 	KFREE(ifsrpcb);
156f4b3ec61Sdh 	*private = NULL;
1577c478bd9Sstevel@tonic-gate }
1587c478bd9Sstevel@tonic-gate 
1597c478bd9Sstevel@tonic-gate /* --------------------------------------------------------------------	*/
1607c478bd9Sstevel@tonic-gate /* Function:	ippr_rpcb_new						*/
1617c478bd9Sstevel@tonic-gate /* Returns:	int - -1 == failure, 0 == success			*/
1627c478bd9Sstevel@tonic-gate /* Parameters:	fin(I)	- pointer to packet information			*/
1637c478bd9Sstevel@tonic-gate /*		aps(I)	- pointer to proxy session structure		*/
1647c478bd9Sstevel@tonic-gate /*		nat(I)	- pointer to NAT session structure		*/
1657c478bd9Sstevel@tonic-gate /*									*/
1667c478bd9Sstevel@tonic-gate /* Allocate resources for per-session proxy structures.			*/
1677c478bd9Sstevel@tonic-gate /* --------------------------------------------------------------------	*/
168f4b3ec61Sdh /*ARGSUSED*/
1697c478bd9Sstevel@tonic-gate int
ippr_rpcb_new(fin,aps,nat,private)170f4b3ec61Sdh ippr_rpcb_new(fin, aps, nat, private)
1717c478bd9Sstevel@tonic-gate 	fr_info_t *fin;
1727c478bd9Sstevel@tonic-gate 	ap_session_t *aps;
1737c478bd9Sstevel@tonic-gate 	nat_t *nat;
174f4b3ec61Sdh 	void *private;
1757c478bd9Sstevel@tonic-gate {
1767c478bd9Sstevel@tonic-gate 	rpcb_session_t *rs;
1777c478bd9Sstevel@tonic-gate 
1787c478bd9Sstevel@tonic-gate 	fin = fin;	/* LINT */
1797c478bd9Sstevel@tonic-gate 	nat = nat;	/* LINT */
1807c478bd9Sstevel@tonic-gate 
1817c478bd9Sstevel@tonic-gate 	KMALLOC(rs, rpcb_session_t *);
1827c478bd9Sstevel@tonic-gate 	if (rs == NULL)
1837c478bd9Sstevel@tonic-gate 		return(-1);
1847c478bd9Sstevel@tonic-gate 
1857c478bd9Sstevel@tonic-gate 	bzero((char *)rs, sizeof(*rs));
1867c478bd9Sstevel@tonic-gate 	MUTEX_INIT(&rs->rs_rxlock, "ipf Sun RPCB proxy session lock");
1877c478bd9Sstevel@tonic-gate 
1887c478bd9Sstevel@tonic-gate 	aps->aps_data = rs;
1897c478bd9Sstevel@tonic-gate 
1907c478bd9Sstevel@tonic-gate 	return(0);
1917c478bd9Sstevel@tonic-gate }
1927c478bd9Sstevel@tonic-gate 
1937c478bd9Sstevel@tonic-gate /* --------------------------------------------------------------------	*/
1947c478bd9Sstevel@tonic-gate /* Function:	ippr_rpcb_del						*/
1957c478bd9Sstevel@tonic-gate /* Returns:	void							*/
1967c478bd9Sstevel@tonic-gate /* Parameters:	aps(I)	- pointer to proxy session structure		*/
1977c478bd9Sstevel@tonic-gate /*									*/
1987c478bd9Sstevel@tonic-gate /* Free up a session's list of RPCB requests.				*/
1997c478bd9Sstevel@tonic-gate /* --------------------------------------------------------------------	*/
200f4b3ec61Sdh /*ARGSUSED*/
2017c478bd9Sstevel@tonic-gate void
ippr_rpcb_del(aps,private,ifs)202f4b3ec61Sdh ippr_rpcb_del(aps, private, ifs)
2037c478bd9Sstevel@tonic-gate 	ap_session_t *aps;
204f4b3ec61Sdh 	void *private;
205f4b3ec61Sdh 	ipf_stack_t *ifs;
2067c478bd9Sstevel@tonic-gate {
2077c478bd9Sstevel@tonic-gate 	rpcb_session_t *rs;
2087c478bd9Sstevel@tonic-gate 	rs = (rpcb_session_t *)aps->aps_data;
2097c478bd9Sstevel@tonic-gate 
210f4b3ec61Sdh 	ifs = ifs;	/* LINT */
211f4b3ec61Sdh 
2127c478bd9Sstevel@tonic-gate 	MUTEX_ENTER(&rs->rs_rxlock);
2137c478bd9Sstevel@tonic-gate 	ippr_rpcb_flush(rs);
2147c478bd9Sstevel@tonic-gate 	MUTEX_EXIT(&rs->rs_rxlock);
2157c478bd9Sstevel@tonic-gate 	MUTEX_DESTROY(&rs->rs_rxlock);
2167c478bd9Sstevel@tonic-gate }
2177c478bd9Sstevel@tonic-gate 
2187c478bd9Sstevel@tonic-gate /* --------------------------------------------------------------------	*/
2197c478bd9Sstevel@tonic-gate /* Function:	ippr_rpcb_in						*/
2207c478bd9Sstevel@tonic-gate /* Returns:	int - APR_ERR(1) == drop the packet, 			*/
2217c478bd9Sstevel@tonic-gate /*		      APR_ERR(2) == kill the proxy session,		*/
2227c478bd9Sstevel@tonic-gate /*		      else change in packet length (in bytes)		*/
2237c478bd9Sstevel@tonic-gate /* Parameters:	fin(I)	- pointer to packet information			*/
2247c478bd9Sstevel@tonic-gate /*		ip(I)	- pointer to packet header			*/
2257c478bd9Sstevel@tonic-gate /*		aps(I)	- pointer to proxy session structure		*/
2267c478bd9Sstevel@tonic-gate /*		nat(I)	- pointer to NAT session structure		*/
2277c478bd9Sstevel@tonic-gate /*									*/
2287c478bd9Sstevel@tonic-gate /* Given a presumed RPCB request, perform some minor tests and pass off */
2297c478bd9Sstevel@tonic-gate /* for decoding.  Also pass packet off for a rewrite if necessary.	*/
2307c478bd9Sstevel@tonic-gate /* --------------------------------------------------------------------	*/
2317c478bd9Sstevel@tonic-gate int
ippr_rpcb_in(fin,aps,nat,private)232f4b3ec61Sdh ippr_rpcb_in(fin, aps, nat, private)
2337c478bd9Sstevel@tonic-gate 	fr_info_t *fin;
2347c478bd9Sstevel@tonic-gate 	ap_session_t *aps;
2357c478bd9Sstevel@tonic-gate 	nat_t *nat;
236f4b3ec61Sdh 	void *private;
2377c478bd9Sstevel@tonic-gate {
2387c478bd9Sstevel@tonic-gate 	rpc_msg_t rpcmsg, *rm;
2397c478bd9Sstevel@tonic-gate 	rpcb_session_t *rs;
2407c478bd9Sstevel@tonic-gate 	u_int off, dlen;
2417c478bd9Sstevel@tonic-gate 	mb_t *m;
2427c478bd9Sstevel@tonic-gate 	int rv;
2437c478bd9Sstevel@tonic-gate 
2447c478bd9Sstevel@tonic-gate 	/* Disallow fragmented or illegally short packets. */
2457c478bd9Sstevel@tonic-gate 	if ((fin->fin_flx & (FI_FRAG|FI_SHORT)) != 0)
2467c478bd9Sstevel@tonic-gate 		return(APR_ERR(1));
2477c478bd9Sstevel@tonic-gate 
2487c478bd9Sstevel@tonic-gate 	/* Perform basic variable initialization. */
2497c478bd9Sstevel@tonic-gate 	rs = (rpcb_session_t *)aps->aps_data;
2507c478bd9Sstevel@tonic-gate 
2517c478bd9Sstevel@tonic-gate 	m = fin->fin_m;
252ab25eeb5Syz 	off = (char *)fin->fin_dp - (char *)fin->fin_ip;
253ab25eeb5Syz 	off += sizeof(udphdr_t) + fin->fin_ipoff;
2547c478bd9Sstevel@tonic-gate 	dlen = fin->fin_dlen - sizeof(udphdr_t);
2557c478bd9Sstevel@tonic-gate 
2567c478bd9Sstevel@tonic-gate 	/* Disallow packets outside legal range for supported requests. */
2577c478bd9Sstevel@tonic-gate 	if ((dlen < RPCB_REQMIN) || (dlen > RPCB_REQMAX))
2587c478bd9Sstevel@tonic-gate 		return(APR_ERR(1));
2597c478bd9Sstevel@tonic-gate 
2607c478bd9Sstevel@tonic-gate 	/* Copy packet over to convenience buffer. */
2617c478bd9Sstevel@tonic-gate 	rm = &rpcmsg;
2627c478bd9Sstevel@tonic-gate 	bzero((char *)rm, sizeof(*rm));
2637c478bd9Sstevel@tonic-gate 	COPYDATA(m, off, dlen, (caddr_t)&rm->rm_msgbuf);
2647c478bd9Sstevel@tonic-gate 	rm->rm_buflen = dlen;
2657c478bd9Sstevel@tonic-gate 
2667c478bd9Sstevel@tonic-gate 	/* Send off to decode request. */
267f4b3ec61Sdh 	rv = ippr_rpcb_decodereq(fin, nat, rs, rm, (ifs_rpcbpxy_t *)private);
2687c478bd9Sstevel@tonic-gate 
2697c478bd9Sstevel@tonic-gate 	switch(rv)
2707c478bd9Sstevel@tonic-gate 	{
2717c478bd9Sstevel@tonic-gate 	case -1:
2727c478bd9Sstevel@tonic-gate 		return(APR_ERR(1));
2737c478bd9Sstevel@tonic-gate 	case 0:
2747c478bd9Sstevel@tonic-gate 		break;
2757c478bd9Sstevel@tonic-gate 	case 1:
2767c478bd9Sstevel@tonic-gate 		rv = ippr_rpcb_modreq(fin, nat, rm, m, off);
2777c478bd9Sstevel@tonic-gate 		break;
2787c478bd9Sstevel@tonic-gate 	default:
2797c478bd9Sstevel@tonic-gate 		/*CONSTANTCONDITION*/
2807c478bd9Sstevel@tonic-gate 		IPF_PANIC(1, ("illegal rv %d (ippr_rpcb_req)", rv));
2817c478bd9Sstevel@tonic-gate 	}
2827c478bd9Sstevel@tonic-gate 
2837c478bd9Sstevel@tonic-gate 	return(rv);
2847c478bd9Sstevel@tonic-gate }
2857c478bd9Sstevel@tonic-gate 
2867c478bd9Sstevel@tonic-gate /* --------------------------------------------------------------------	*/
2877c478bd9Sstevel@tonic-gate /* Function:	ippr_rpcb_out						*/
2887c478bd9Sstevel@tonic-gate /* Returns:	int - APR_ERR(1) == drop the packet, 			*/
2897c478bd9Sstevel@tonic-gate /*		      APR_ERR(2) == kill the proxy session,		*/
2907c478bd9Sstevel@tonic-gate /*		      else change in packet length (in bytes)		*/
2917c478bd9Sstevel@tonic-gate /* Parameters:	fin(I)	- pointer to packet information			*/
2927c478bd9Sstevel@tonic-gate /*		ip(I)	- pointer to packet header			*/
2937c478bd9Sstevel@tonic-gate /*		aps(I)	- pointer to proxy session structure		*/
2947c478bd9Sstevel@tonic-gate /*		nat(I)	- pointer to NAT session structure		*/
2957c478bd9Sstevel@tonic-gate /*									*/
2967c478bd9Sstevel@tonic-gate /* Given a presumed RPCB reply, perform some minor tests and pass off	*/
2977c478bd9Sstevel@tonic-gate /* for decoding.  If the message indicates a successful request with	*/
2987c478bd9Sstevel@tonic-gate /* valid addressing information, create NAT and state structures to	*/
2997c478bd9Sstevel@tonic-gate /* allow direct communication between RPC client and server.		*/
3007c478bd9Sstevel@tonic-gate /* --------------------------------------------------------------------	*/
3017c478bd9Sstevel@tonic-gate int
ippr_rpcb_out(fin,aps,nat,private)302f4b3ec61Sdh ippr_rpcb_out(fin, aps, nat, private)
3037c478bd9Sstevel@tonic-gate 	fr_info_t *fin;
3047c478bd9Sstevel@tonic-gate 	ap_session_t *aps;
3057c478bd9Sstevel@tonic-gate 	nat_t *nat;
306f4b3ec61Sdh 	void *private;
3077c478bd9Sstevel@tonic-gate {
3087c478bd9Sstevel@tonic-gate 	rpc_msg_t rpcmsg, *rm;
3097c478bd9Sstevel@tonic-gate 	rpcb_session_t *rs;
3107c478bd9Sstevel@tonic-gate 	rpcb_xact_t *rx;
3117c478bd9Sstevel@tonic-gate 	u_int off, dlen;
3127c478bd9Sstevel@tonic-gate 	int rv, diff;
3137c478bd9Sstevel@tonic-gate 	mb_t *m;
314f4b3ec61Sdh 	ifs_rpcbpxy_t *ifsrpcb = (ifs_rpcbpxy_t *)private;
3157c478bd9Sstevel@tonic-gate 
3167c478bd9Sstevel@tonic-gate 	/* Disallow fragmented or illegally short packets. */
3177c478bd9Sstevel@tonic-gate 	if ((fin->fin_flx & (FI_FRAG|FI_SHORT)) != 0)
3187c478bd9Sstevel@tonic-gate 		return(APR_ERR(1));
3197c478bd9Sstevel@tonic-gate 
3207c478bd9Sstevel@tonic-gate 	/* Perform basic variable initialization. */
3217c478bd9Sstevel@tonic-gate 	rs = (rpcb_session_t *)aps->aps_data;
3227c478bd9Sstevel@tonic-gate 
3237c478bd9Sstevel@tonic-gate 	m = fin->fin_m;
324ab25eeb5Syz 	off = (char *)fin->fin_dp - (char *)fin->fin_ip;
325ab25eeb5Syz 	off += sizeof(udphdr_t) + fin->fin_ipoff;
3267c478bd9Sstevel@tonic-gate 	dlen = fin->fin_dlen - sizeof(udphdr_t);
3277c478bd9Sstevel@tonic-gate 	diff = 0;
3287c478bd9Sstevel@tonic-gate 
3297c478bd9Sstevel@tonic-gate 	/* Disallow packets outside legal range for supported requests. */
3307c478bd9Sstevel@tonic-gate 	if ((dlen < RPCB_REPMIN) || (dlen > RPCB_REPMAX))
3317c478bd9Sstevel@tonic-gate 		return(APR_ERR(1));
3327c478bd9Sstevel@tonic-gate 
3337c478bd9Sstevel@tonic-gate 	/* Copy packet over to convenience buffer. */
3347c478bd9Sstevel@tonic-gate 	rm = &rpcmsg;
3357c478bd9Sstevel@tonic-gate 	bzero((char *)rm, sizeof(*rm));
3367c478bd9Sstevel@tonic-gate 	COPYDATA(m, off, dlen, (caddr_t)&rm->rm_msgbuf);
3377c478bd9Sstevel@tonic-gate 	rm->rm_buflen = dlen;
3387c478bd9Sstevel@tonic-gate 
3397c478bd9Sstevel@tonic-gate 	/* Send off to decode reply. */
340f4b3ec61Sdh 	rv = ippr_rpcb_decoderep(fin, nat, rs, rm, &rx, ifsrpcb);
3417c478bd9Sstevel@tonic-gate 
3427c478bd9Sstevel@tonic-gate 	switch(rv)
3437c478bd9Sstevel@tonic-gate 	{
3447c478bd9Sstevel@tonic-gate 	case -1: /* Bad packet */
3457c478bd9Sstevel@tonic-gate                 if (rx != NULL) {
3467c478bd9Sstevel@tonic-gate                         MUTEX_ENTER(&rs->rs_rxlock);
347f4b3ec61Sdh                         ippr_rpcb_deref(rs, rx, ifsrpcb);
3487c478bd9Sstevel@tonic-gate                         MUTEX_EXIT(&rs->rs_rxlock);
3497c478bd9Sstevel@tonic-gate                 }
3507c478bd9Sstevel@tonic-gate 		return(APR_ERR(1));
3517c478bd9Sstevel@tonic-gate 	case  0: /* Negative reply / request rejected */
3527c478bd9Sstevel@tonic-gate 		break;
3537c478bd9Sstevel@tonic-gate 	case  1: /* Positive reply */
3547c478bd9Sstevel@tonic-gate 		/*
3557c478bd9Sstevel@tonic-gate 		 * With the IP address embedded in a GETADDR(LIST) reply,
3567c478bd9Sstevel@tonic-gate 		 * we'll need to rewrite the packet in the very possible
3577c478bd9Sstevel@tonic-gate 		 * event that the internal & external addresses aren't the
3587c478bd9Sstevel@tonic-gate 		 * same.  (i.e., this box is either a router or rpcbind
3597c478bd9Sstevel@tonic-gate 		 * only listens on loopback.)
3607c478bd9Sstevel@tonic-gate 		 */
3617c478bd9Sstevel@tonic-gate 		if (nat->nat_inip.s_addr != nat->nat_outip.s_addr) {
3627c478bd9Sstevel@tonic-gate 			if (rx->rx_type == RPCB_RES_STRING)
3637c478bd9Sstevel@tonic-gate 				diff = ippr_rpcb_modv3(fin, nat, rm, m, off);
3647c478bd9Sstevel@tonic-gate 			else if (rx->rx_type == RPCB_RES_LIST)
3657c478bd9Sstevel@tonic-gate 				diff = ippr_rpcb_modv4(fin, nat, rm, m, off);
3667c478bd9Sstevel@tonic-gate 		}
3677c478bd9Sstevel@tonic-gate 		break;
3687c478bd9Sstevel@tonic-gate 	default:
3697c478bd9Sstevel@tonic-gate 		/*CONSTANTCONDITION*/
3707c478bd9Sstevel@tonic-gate 		IPF_PANIC(1, ("illegal rv %d (ippr_rpcb_decoderep)", rv));
3717c478bd9Sstevel@tonic-gate 	}
3727c478bd9Sstevel@tonic-gate 
3737c478bd9Sstevel@tonic-gate 	if (rx != NULL) {
3747c478bd9Sstevel@tonic-gate                 MUTEX_ENTER(&rs->rs_rxlock);
3757c478bd9Sstevel@tonic-gate                 /* XXX Gross hack - I'm overloading the reference
3767c478bd9Sstevel@tonic-gate                  * counter to deal with both threads and retransmitted
3777c478bd9Sstevel@tonic-gate                  * requests.  One deref signals that this thread is
3787c478bd9Sstevel@tonic-gate                  * finished with rx, and the other signals that we've
3797c478bd9Sstevel@tonic-gate                  * processed its reply.
3807c478bd9Sstevel@tonic-gate                  */
381f4b3ec61Sdh                 ippr_rpcb_deref(rs, rx, ifsrpcb);
382f4b3ec61Sdh                 ippr_rpcb_deref(rs, rx, ifsrpcb);
3837c478bd9Sstevel@tonic-gate                 MUTEX_EXIT(&rs->rs_rxlock);
3847c478bd9Sstevel@tonic-gate 	}
3857c478bd9Sstevel@tonic-gate 
3867c478bd9Sstevel@tonic-gate 	return(diff);
3877c478bd9Sstevel@tonic-gate }
3887c478bd9Sstevel@tonic-gate 
3897c478bd9Sstevel@tonic-gate /*
3907c478bd9Sstevel@tonic-gate  * Private support subroutines
3917c478bd9Sstevel@tonic-gate  */
3927c478bd9Sstevel@tonic-gate 
3937c478bd9Sstevel@tonic-gate /* --------------------------------------------------------------------	*/
3947c478bd9Sstevel@tonic-gate /* Function:	ippr_rpcb_flush						*/
3957c478bd9Sstevel@tonic-gate /* Returns:	void							*/
3967c478bd9Sstevel@tonic-gate /* Parameters:	rs(I)	- pointer to RPCB session structure		*/
3977c478bd9Sstevel@tonic-gate /*									*/
3987c478bd9Sstevel@tonic-gate /* Simply flushes the list of outstanding transactions, if any.		*/
3997c478bd9Sstevel@tonic-gate /* --------------------------------------------------------------------	*/
4007c478bd9Sstevel@tonic-gate static void
ippr_rpcb_flush(rs)4017c478bd9Sstevel@tonic-gate ippr_rpcb_flush(rs)
4027c478bd9Sstevel@tonic-gate 	rpcb_session_t *rs;
4037c478bd9Sstevel@tonic-gate {
4047c478bd9Sstevel@tonic-gate 	rpcb_xact_t *r1, *r2;
4057c478bd9Sstevel@tonic-gate 
4067c478bd9Sstevel@tonic-gate 	r1 = rs->rs_rxlist;
4077c478bd9Sstevel@tonic-gate 	if (r1 == NULL)
4087c478bd9Sstevel@tonic-gate 		return;
4097c478bd9Sstevel@tonic-gate 
4107c478bd9Sstevel@tonic-gate 	while (r1 != NULL) {
4117c478bd9Sstevel@tonic-gate 		r2 = r1;
4127c478bd9Sstevel@tonic-gate 		r1 = r1->rx_next;
4137c478bd9Sstevel@tonic-gate 		KFREE(r2);
4147c478bd9Sstevel@tonic-gate 	}
4157c478bd9Sstevel@tonic-gate }
4167c478bd9Sstevel@tonic-gate 
4177c478bd9Sstevel@tonic-gate /* --------------------------------------------------------------------	*/
4187c478bd9Sstevel@tonic-gate /* Function:	ippr_rpcb_decodereq					*/
4197c478bd9Sstevel@tonic-gate /* Returns:	int - -1 == bad request or critical failure,		*/
4207c478bd9Sstevel@tonic-gate /*		       0 == request successfully decoded,		*/
4217c478bd9Sstevel@tonic-gate /*		       1 == request successfully decoded; requires	*/
4227c478bd9Sstevel@tonic-gate /*			    address rewrite/modification		*/
4237c478bd9Sstevel@tonic-gate /* Parameters:	fin(I)	- pointer to packet information			*/
4247c478bd9Sstevel@tonic-gate /*		nat(I)	- pointer to NAT session structure		*/
4257c478bd9Sstevel@tonic-gate /*		rs(I)	- pointer to RPCB session structure		*/
4267c478bd9Sstevel@tonic-gate /*		rm(I)	- pointer to RPC message structure		*/
4277c478bd9Sstevel@tonic-gate /*									*/
4287c478bd9Sstevel@tonic-gate /* Take a presumed RPCB request, decode it, and store the results in	*/
4297c478bd9Sstevel@tonic-gate /* the transaction list.  If the internal target address needs to be	*/
4307c478bd9Sstevel@tonic-gate /* modified, store its location in ptr.					*/
4317c478bd9Sstevel@tonic-gate /* WARNING:  It's the responsibility of the caller to make sure there	*/
4327c478bd9Sstevel@tonic-gate /* is enough room in rs_buf for the basic RPC message "preamble".	*/
4337c478bd9Sstevel@tonic-gate /* --------------------------------------------------------------------	*/
4347c478bd9Sstevel@tonic-gate static int
ippr_rpcb_decodereq(fin,nat,rs,rm,ifsrpcb)435f4b3ec61Sdh ippr_rpcb_decodereq(fin, nat, rs, rm, ifsrpcb)
4367c478bd9Sstevel@tonic-gate 	fr_info_t *fin;
4377c478bd9Sstevel@tonic-gate 	nat_t *nat;
4387c478bd9Sstevel@tonic-gate 	rpcb_session_t *rs;
4397c478bd9Sstevel@tonic-gate 	rpc_msg_t *rm;
440f4b3ec61Sdh 	ifs_rpcbpxy_t *ifsrpcb;
4417c478bd9Sstevel@tonic-gate {
4427c478bd9Sstevel@tonic-gate 	rpcb_args_t *ra;
4437c478bd9Sstevel@tonic-gate 	u_32_t xdr, *p;
4447c478bd9Sstevel@tonic-gate 	rpc_call_t *rc;
4457c478bd9Sstevel@tonic-gate 	rpcb_xact_t rx;
4467c478bd9Sstevel@tonic-gate 	int mod;
4477c478bd9Sstevel@tonic-gate 
4487c478bd9Sstevel@tonic-gate 	p = (u_32_t *)rm->rm_msgbuf;
4497c478bd9Sstevel@tonic-gate 	mod = 0;
4507c478bd9Sstevel@tonic-gate 
4517c478bd9Sstevel@tonic-gate 	bzero((char *)&rx, sizeof(rx));
4527c478bd9Sstevel@tonic-gate 	rc = &rm->rm_call;
4537c478bd9Sstevel@tonic-gate 
4547c478bd9Sstevel@tonic-gate 	rm->rm_xid = p;
4557c478bd9Sstevel@tonic-gate 	rx.rx_xid = B(p++);	/* Record this message's XID. */
4567c478bd9Sstevel@tonic-gate 
4577c478bd9Sstevel@tonic-gate 	/* Parse out and test the RPC header. */
4587c478bd9Sstevel@tonic-gate 	if ((B(p++) != RPCB_CALL) ||
4597c478bd9Sstevel@tonic-gate 	    (B(p++) != RPCB_MSG_VERSION) ||
4607c478bd9Sstevel@tonic-gate 	    (B(p++) != RPCB_PROG))
4617c478bd9Sstevel@tonic-gate 		return(-1);
4627c478bd9Sstevel@tonic-gate 
4637c478bd9Sstevel@tonic-gate 	/* Record the RPCB version and procedure. */
4647c478bd9Sstevel@tonic-gate 	rc->rc_vers = p++;
4657c478bd9Sstevel@tonic-gate 	rc->rc_proc = p++;
4667c478bd9Sstevel@tonic-gate 
4677c478bd9Sstevel@tonic-gate 	/* Bypass RPC authentication stuff. */
4687c478bd9Sstevel@tonic-gate 	if (ippr_rpcb_skipauth(rm, &rc->rc_authcred, &p) != 0)
4697c478bd9Sstevel@tonic-gate 		return(-1);
4707c478bd9Sstevel@tonic-gate 	if (ippr_rpcb_skipauth(rm, &rc->rc_authverf, &p) != 0)
4717c478bd9Sstevel@tonic-gate 		return(-1);
4727c478bd9Sstevel@tonic-gate 
4737c478bd9Sstevel@tonic-gate 	/* Compare RPCB version and procedure numbers. */
4747c478bd9Sstevel@tonic-gate 	switch(B(rc->rc_vers))
4757c478bd9Sstevel@tonic-gate 	{
4767c478bd9Sstevel@tonic-gate 	case 2:
4777c478bd9Sstevel@tonic-gate 		/* This proxy only supports PMAP_GETPORT. */
4787c478bd9Sstevel@tonic-gate 		if (B(rc->rc_proc) != RPCB_GETPORT)
4797c478bd9Sstevel@tonic-gate 			return(-1);
4807c478bd9Sstevel@tonic-gate 
4817c478bd9Sstevel@tonic-gate 		/* Portmap requests contain four 4 byte parameters. */
4827c478bd9Sstevel@tonic-gate 		if (RPCB_BUF_EQ(rm, p, 16) == 0)
4837c478bd9Sstevel@tonic-gate 			return(-1);
4847c478bd9Sstevel@tonic-gate 
4857c478bd9Sstevel@tonic-gate 		p += 2; /* Skip requested program and version numbers. */
4867c478bd9Sstevel@tonic-gate 
4877c478bd9Sstevel@tonic-gate 		/* Sanity check the requested protocol. */
4887c478bd9Sstevel@tonic-gate 		xdr = B(p);
4897c478bd9Sstevel@tonic-gate 		if (!(xdr == IPPROTO_UDP || xdr == IPPROTO_TCP))
4907c478bd9Sstevel@tonic-gate 			return(-1);
4917c478bd9Sstevel@tonic-gate 
4927c478bd9Sstevel@tonic-gate 		rx.rx_type = RPCB_RES_PMAP;
4937c478bd9Sstevel@tonic-gate 		rx.rx_proto = xdr;
4947c478bd9Sstevel@tonic-gate 		break;
4957c478bd9Sstevel@tonic-gate 	case 3:
4967c478bd9Sstevel@tonic-gate 	case 4:
4977c478bd9Sstevel@tonic-gate 		/* GETADDRLIST is exclusive to v4; GETADDR for v3 & v4 */
4987c478bd9Sstevel@tonic-gate 		switch(B(rc->rc_proc))
4997c478bd9Sstevel@tonic-gate 		{
5007c478bd9Sstevel@tonic-gate 		case RPCB_GETADDR:
5017c478bd9Sstevel@tonic-gate 			rx.rx_type = RPCB_RES_STRING;
5027c478bd9Sstevel@tonic-gate 			rx.rx_proto = (u_int)fin->fin_p;
5037c478bd9Sstevel@tonic-gate 			break;
5047c478bd9Sstevel@tonic-gate 		case RPCB_GETADDRLIST:
5057c478bd9Sstevel@tonic-gate 			if (B(rc->rc_vers) != 4)
5067c478bd9Sstevel@tonic-gate 				return(-1);
5077c478bd9Sstevel@tonic-gate 			rx.rx_type = RPCB_RES_LIST;
5087c478bd9Sstevel@tonic-gate 			break;
5097c478bd9Sstevel@tonic-gate 		default:
5107c478bd9Sstevel@tonic-gate 			return(-1);
5117c478bd9Sstevel@tonic-gate 		}
5127c478bd9Sstevel@tonic-gate 
5137c478bd9Sstevel@tonic-gate 		ra = &rc->rc_rpcbargs;
5147c478bd9Sstevel@tonic-gate 
5157c478bd9Sstevel@tonic-gate 		/* Decode the 'struct rpcb' request. */
5167c478bd9Sstevel@tonic-gate 		if (ippr_rpcb_xdrrpcb(rm, p, ra) != 0)
5177c478bd9Sstevel@tonic-gate 			return(-1);
5187c478bd9Sstevel@tonic-gate 
5197c478bd9Sstevel@tonic-gate 		/* Are the target address & port valid? */
5207c478bd9Sstevel@tonic-gate 		if ((ra->ra_maddr.xu_ip != nat->nat_outip.s_addr) ||
5217c478bd9Sstevel@tonic-gate 		    (ra->ra_maddr.xu_port != nat->nat_outport))
5227c478bd9Sstevel@tonic-gate 		    	return(-1);
5237c478bd9Sstevel@tonic-gate 
5247c478bd9Sstevel@tonic-gate 		/* Do we need to rewrite this packet? */
5257c478bd9Sstevel@tonic-gate 		if ((nat->nat_outip.s_addr != nat->nat_inip.s_addr) ||
5267c478bd9Sstevel@tonic-gate 		    (nat->nat_outport != nat->nat_inport))
5277c478bd9Sstevel@tonic-gate 		    	mod = 1;
5287c478bd9Sstevel@tonic-gate 		break;
5297c478bd9Sstevel@tonic-gate 	default:
5307c478bd9Sstevel@tonic-gate 		return(-1);
5317c478bd9Sstevel@tonic-gate 	}
5327c478bd9Sstevel@tonic-gate 
5337c478bd9Sstevel@tonic-gate         MUTEX_ENTER(&rs->rs_rxlock);
534f4b3ec61Sdh 	if (ippr_rpcb_insert(rs, &rx, ifsrpcb) != 0) {
5357c478bd9Sstevel@tonic-gate                 MUTEX_EXIT(&rs->rs_rxlock);
5367c478bd9Sstevel@tonic-gate 		return(-1);
5377c478bd9Sstevel@tonic-gate 	}
5387c478bd9Sstevel@tonic-gate         MUTEX_EXIT(&rs->rs_rxlock);
5397c478bd9Sstevel@tonic-gate 
5407c478bd9Sstevel@tonic-gate 	return(mod);
5417c478bd9Sstevel@tonic-gate }
5427c478bd9Sstevel@tonic-gate 
5437c478bd9Sstevel@tonic-gate /* --------------------------------------------------------------------	*/
5447c478bd9Sstevel@tonic-gate /* Function:	ippr_rpcb_skipauth					*/
5457c478bd9Sstevel@tonic-gate /* Returns:	int -- -1 == illegal auth parameters (lengths)		*/
5467c478bd9Sstevel@tonic-gate /*			0 == valid parameters, pointer advanced		*/
5477c478bd9Sstevel@tonic-gate /* Parameters:	rm(I)	- pointer to RPC message structure		*/
5487c478bd9Sstevel@tonic-gate /*		auth(I)	- pointer to RPC auth structure			*/
5497c478bd9Sstevel@tonic-gate /*		buf(IO)	- pointer to location within convenience buffer	*/
5507c478bd9Sstevel@tonic-gate /*									*/
5517c478bd9Sstevel@tonic-gate /* Record auth data length & location of auth data, then advance past	*/
5527c478bd9Sstevel@tonic-gate /* it.									*/
5537c478bd9Sstevel@tonic-gate /* --------------------------------------------------------------------	*/
5547c478bd9Sstevel@tonic-gate static int
ippr_rpcb_skipauth(rm,auth,buf)5557c478bd9Sstevel@tonic-gate ippr_rpcb_skipauth(rm, auth, buf)
5567c478bd9Sstevel@tonic-gate 	rpc_msg_t *rm;
5577c478bd9Sstevel@tonic-gate 	xdr_auth_t *auth;
5587c478bd9Sstevel@tonic-gate 	u_32_t **buf;
5597c478bd9Sstevel@tonic-gate {
5607c478bd9Sstevel@tonic-gate 	u_32_t *p, xdr;
5617c478bd9Sstevel@tonic-gate 
5627c478bd9Sstevel@tonic-gate 	p = *buf;
5637c478bd9Sstevel@tonic-gate 
5647c478bd9Sstevel@tonic-gate 	/* Make sure we have enough space for expected fixed auth parms. */
5657c478bd9Sstevel@tonic-gate 	if (RPCB_BUF_GEQ(rm, p, 8) == 0)
5667c478bd9Sstevel@tonic-gate 		return(-1);
5677c478bd9Sstevel@tonic-gate 
5687c478bd9Sstevel@tonic-gate 	p++; /* We don't care about auth_flavor. */
5697c478bd9Sstevel@tonic-gate 
5707c478bd9Sstevel@tonic-gate 	auth->xa_string.xs_len = p;
5717c478bd9Sstevel@tonic-gate 	xdr = B(p++);		/* Length of auth_data */
5727c478bd9Sstevel@tonic-gate 
5737c478bd9Sstevel@tonic-gate 	/* Test for absurdity / illegality of auth_data length. */
5747c478bd9Sstevel@tonic-gate 	if ((XDRALIGN(xdr) < xdr) || (RPCB_BUF_GEQ(rm, p, XDRALIGN(xdr)) == 0))
5757c478bd9Sstevel@tonic-gate 		return(-1);
5767c478bd9Sstevel@tonic-gate 
5777c478bd9Sstevel@tonic-gate 	auth->xa_string.xs_str = (char *)p;
5787c478bd9Sstevel@tonic-gate 
5797c478bd9Sstevel@tonic-gate 	p += XDRALIGN(xdr);	/* Advance our location. */
5807c478bd9Sstevel@tonic-gate 
5817c478bd9Sstevel@tonic-gate 	*buf = (u_32_t *)p;
5827c478bd9Sstevel@tonic-gate 
5837c478bd9Sstevel@tonic-gate 	return(0);
5847c478bd9Sstevel@tonic-gate }
5857c478bd9Sstevel@tonic-gate 
5867c478bd9Sstevel@tonic-gate /* --------------------------------------------------------------------	*/
5877c478bd9Sstevel@tonic-gate /* Function:	ippr_rpcb_insert					*/
5887c478bd9Sstevel@tonic-gate /* Returns:	int -- -1 == list insertion failed,			*/
5897c478bd9Sstevel@tonic-gate /*			0 == item successfully added			*/
5907c478bd9Sstevel@tonic-gate /* Parameters:	rs(I)	- pointer to RPCB session structure		*/
5917c478bd9Sstevel@tonic-gate /*		rx(I)	- pointer to RPCB transaction structure		*/
5927c478bd9Sstevel@tonic-gate /* --------------------------------------------------------------------	*/
5937c478bd9Sstevel@tonic-gate static int
ippr_rpcb_insert(rs,rx,ifsrpcb)594f4b3ec61Sdh ippr_rpcb_insert(rs, rx, ifsrpcb)
5957c478bd9Sstevel@tonic-gate 	rpcb_session_t *rs;
5967c478bd9Sstevel@tonic-gate 	rpcb_xact_t *rx;
597f4b3ec61Sdh 	ifs_rpcbpxy_t *ifsrpcb;
5987c478bd9Sstevel@tonic-gate {
5997c478bd9Sstevel@tonic-gate 	rpcb_xact_t *rxp;
6007c478bd9Sstevel@tonic-gate 
6017c478bd9Sstevel@tonic-gate 	rxp = ippr_rpcb_lookup(rs, rx->rx_xid);
6027c478bd9Sstevel@tonic-gate 	if (rxp != NULL) {
6037c478bd9Sstevel@tonic-gate                 ++rxp->rx_ref;
6047c478bd9Sstevel@tonic-gate 		return(0);
6057c478bd9Sstevel@tonic-gate         }
6067c478bd9Sstevel@tonic-gate 
607f4b3ec61Sdh 	if (ifsrpcb->rpcbcnt == RPCB_MAXREQS)
6087c478bd9Sstevel@tonic-gate 		return(-1);
6097c478bd9Sstevel@tonic-gate 
6107c478bd9Sstevel@tonic-gate 	KMALLOC(rxp, rpcb_xact_t *);
6117c478bd9Sstevel@tonic-gate 	if (rxp == NULL)
6127c478bd9Sstevel@tonic-gate 		return(-1);
6137c478bd9Sstevel@tonic-gate 
6147c478bd9Sstevel@tonic-gate 	bcopy((char *)rx, (char *)rxp, sizeof(*rx));
6157c478bd9Sstevel@tonic-gate 
6167c478bd9Sstevel@tonic-gate 	if (rs->rs_rxlist != NULL)
6177c478bd9Sstevel@tonic-gate 		rs->rs_rxlist->rx_pnext = &rxp->rx_next;
6187c478bd9Sstevel@tonic-gate 
6197c478bd9Sstevel@tonic-gate 	rxp->rx_pnext = &rs->rs_rxlist;
6207c478bd9Sstevel@tonic-gate 	rxp->rx_next = rs->rs_rxlist;
6217c478bd9Sstevel@tonic-gate 	rs->rs_rxlist = rxp;
6227c478bd9Sstevel@tonic-gate 
6237c478bd9Sstevel@tonic-gate 	rxp->rx_ref = 1;
6247c478bd9Sstevel@tonic-gate 
625f4b3ec61Sdh 	++ifsrpcb->rpcbcnt;
6267c478bd9Sstevel@tonic-gate 
6277c478bd9Sstevel@tonic-gate 	return(0);
6287c478bd9Sstevel@tonic-gate }
6297c478bd9Sstevel@tonic-gate 
6307c478bd9Sstevel@tonic-gate /* --------------------------------------------------------------------	*/
6317c478bd9Sstevel@tonic-gate /* Function:	ippr_rpcb_xdrrpcb					*/
6327c478bd9Sstevel@tonic-gate /* Returns:	int -- -1 == failure to properly decode the request	*/
6337c478bd9Sstevel@tonic-gate /*			0 == rpcb successfully decoded			*/
6347c478bd9Sstevel@tonic-gate /* Parameters:	rs(I)	- pointer to RPCB session structure		*/
6357c478bd9Sstevel@tonic-gate /*		p(I)	- pointer to location within session buffer	*/
6367c478bd9Sstevel@tonic-gate /*		rpcb(O)	- pointer to rpcb (xdr type) structure		*/
6377c478bd9Sstevel@tonic-gate /*									*/
6387c478bd9Sstevel@tonic-gate /* Decode a XDR encoded rpcb structure and record its contents in rpcb  */
6397c478bd9Sstevel@tonic-gate /* within only the context of TCP/UDP over IP networks.			*/
6407c478bd9Sstevel@tonic-gate /* --------------------------------------------------------------------	*/
6417c478bd9Sstevel@tonic-gate static int
ippr_rpcb_xdrrpcb(rm,p,ra)6427c478bd9Sstevel@tonic-gate ippr_rpcb_xdrrpcb(rm, p, ra)
6437c478bd9Sstevel@tonic-gate 	rpc_msg_t *rm;
6447c478bd9Sstevel@tonic-gate 	u_32_t *p;
6457c478bd9Sstevel@tonic-gate 	rpcb_args_t *ra;
6467c478bd9Sstevel@tonic-gate {
6477c478bd9Sstevel@tonic-gate 	if (!RPCB_BUF_GEQ(rm, p, 20))
6487c478bd9Sstevel@tonic-gate 		return(-1);
6497c478bd9Sstevel@tonic-gate 
6507c478bd9Sstevel@tonic-gate 	/* Bypass target program & version. */
6517c478bd9Sstevel@tonic-gate 	p += 2;
6527c478bd9Sstevel@tonic-gate 
6537c478bd9Sstevel@tonic-gate 	/* Decode r_netid.  Must be "tcp" or "udp". */
6547c478bd9Sstevel@tonic-gate 	if (ippr_rpcb_getproto(rm, &ra->ra_netid, &p) != 0)
6557c478bd9Sstevel@tonic-gate 		return(-1);
6567c478bd9Sstevel@tonic-gate 
6577c478bd9Sstevel@tonic-gate 	/* Decode r_maddr. */
6587c478bd9Sstevel@tonic-gate 	if (ippr_rpcb_getuaddr(rm, &ra->ra_maddr, &p) != 0)
6597c478bd9Sstevel@tonic-gate 		return(-1);
6607c478bd9Sstevel@tonic-gate 
6617c478bd9Sstevel@tonic-gate 	/* Advance to r_owner and make sure it's empty. */
6627c478bd9Sstevel@tonic-gate 	if (!RPCB_BUF_EQ(rm, p, 4) || (B(p) != 0))
6637c478bd9Sstevel@tonic-gate 		return(-1);
6647c478bd9Sstevel@tonic-gate 
6657c478bd9Sstevel@tonic-gate 	return(0);
6667c478bd9Sstevel@tonic-gate }
6677c478bd9Sstevel@tonic-gate 
6687c478bd9Sstevel@tonic-gate /* --------------------------------------------------------------------	*/
6697c478bd9Sstevel@tonic-gate /* Function:	ippr_rpcb_getuaddr					*/
6707c478bd9Sstevel@tonic-gate /* Returns:	int -- -1 == illegal string,				*/
6717c478bd9Sstevel@tonic-gate /*			0 == string parsed; contents recorded		*/
6727c478bd9Sstevel@tonic-gate /* Parameters:	rm(I)	- pointer to RPC message structure		*/
6737c478bd9Sstevel@tonic-gate /*		xu(I)	- pointer to universal address structure	*/
6747c478bd9Sstevel@tonic-gate /*		p(IO)	- pointer to location within message buffer	*/
6757c478bd9Sstevel@tonic-gate /*									*/
6767c478bd9Sstevel@tonic-gate /* Decode the IP address / port at p and record them in xu.		*/
6777c478bd9Sstevel@tonic-gate /* --------------------------------------------------------------------	*/
6787c478bd9Sstevel@tonic-gate static int
ippr_rpcb_getuaddr(rm,xu,p)6797c478bd9Sstevel@tonic-gate ippr_rpcb_getuaddr(rm, xu, p)
6807c478bd9Sstevel@tonic-gate 	rpc_msg_t *rm;
6817c478bd9Sstevel@tonic-gate 	xdr_uaddr_t *xu;
6827c478bd9Sstevel@tonic-gate 	u_32_t **p;
6837c478bd9Sstevel@tonic-gate {
6847c478bd9Sstevel@tonic-gate 	char *c, *i, *b, *pp;
6857c478bd9Sstevel@tonic-gate 	u_int d, dd, l, t;
6867c478bd9Sstevel@tonic-gate 	char uastr[24];
6877c478bd9Sstevel@tonic-gate 
6887c478bd9Sstevel@tonic-gate 	/* Test for string length. */
6897c478bd9Sstevel@tonic-gate 	if (!RPCB_BUF_GEQ(rm, *p, 4))
6907c478bd9Sstevel@tonic-gate 		return(-1);
6917c478bd9Sstevel@tonic-gate 
6927c478bd9Sstevel@tonic-gate 	xu->xu_xslen = (*p)++;
6937c478bd9Sstevel@tonic-gate 	xu->xu_xsstr = (char *)*p;
6947c478bd9Sstevel@tonic-gate 
6957c478bd9Sstevel@tonic-gate 	/* Length check */
6967c478bd9Sstevel@tonic-gate 	l = B(xu->xu_xslen);
6977c478bd9Sstevel@tonic-gate 	if (l < 11 || l > 23 || !RPCB_BUF_GEQ(rm, *p, XDRALIGN(l)))
6987c478bd9Sstevel@tonic-gate 		return(-1);
6997c478bd9Sstevel@tonic-gate 
7007c478bd9Sstevel@tonic-gate 	/* Advance p */
7017c478bd9Sstevel@tonic-gate 	*(char **)p += XDRALIGN(l);
7027c478bd9Sstevel@tonic-gate 
7037c478bd9Sstevel@tonic-gate 	/* Copy string to local buffer & terminate C style */
7047c478bd9Sstevel@tonic-gate 	bcopy(xu->xu_xsstr, uastr, l);
7057c478bd9Sstevel@tonic-gate 	uastr[l] = '\0';
7067c478bd9Sstevel@tonic-gate 
7077c478bd9Sstevel@tonic-gate 	i = (char *)&xu->xu_ip;
7087c478bd9Sstevel@tonic-gate 	pp = (char *)&xu->xu_port;
7097c478bd9Sstevel@tonic-gate 
7107c478bd9Sstevel@tonic-gate 	/*
7117c478bd9Sstevel@tonic-gate 	 * Expected format: a.b.c.d.e.f where [a-d] correspond to bytes of
7127c478bd9Sstevel@tonic-gate 	 * an IP address and [ef] are the bytes of a L4 port.
7137c478bd9Sstevel@tonic-gate 	 */
714ab25eeb5Syz 	if (!(ISDIGIT(uastr[0]) && ISDIGIT(uastr[l-1])))
7157c478bd9Sstevel@tonic-gate 		return(-1);
7167c478bd9Sstevel@tonic-gate 	b = uastr;
7177c478bd9Sstevel@tonic-gate 	for (c = &uastr[1], d = 0, dd = 0; c < &uastr[l-1]; c++) {
718ab25eeb5Syz 		if (ISDIGIT(*c)) {
7197c478bd9Sstevel@tonic-gate 			dd = 0;
7207c478bd9Sstevel@tonic-gate 			continue;
7217c478bd9Sstevel@tonic-gate 		}
7227c478bd9Sstevel@tonic-gate 		if (*c == '.') {
7237c478bd9Sstevel@tonic-gate 			if (dd != 0)
7247c478bd9Sstevel@tonic-gate 				return(-1);
7257c478bd9Sstevel@tonic-gate 
7267c478bd9Sstevel@tonic-gate 			/* Check for ASCII byte. */
7277c478bd9Sstevel@tonic-gate 			*c = '\0';
7287c478bd9Sstevel@tonic-gate 			t = ippr_rpcb_atoi(b);
7297c478bd9Sstevel@tonic-gate 			if (t > 255)
7307c478bd9Sstevel@tonic-gate 				return(-1);
7317c478bd9Sstevel@tonic-gate 
7327c478bd9Sstevel@tonic-gate 			/* Aim b at beginning of the next byte. */
7337c478bd9Sstevel@tonic-gate 			b = c + 1;
7347c478bd9Sstevel@tonic-gate 
7357c478bd9Sstevel@tonic-gate 			/* Switch off IP addr vs port parsing. */
7367c478bd9Sstevel@tonic-gate 			if (d < 4)
7377c478bd9Sstevel@tonic-gate 				i[d++] = t & 0xff;
7387c478bd9Sstevel@tonic-gate 			else
7397c478bd9Sstevel@tonic-gate 				pp[d++ - 4] = t & 0xff;
7407c478bd9Sstevel@tonic-gate 
7417c478bd9Sstevel@tonic-gate 			dd = 1;
7427c478bd9Sstevel@tonic-gate 			continue;
7437c478bd9Sstevel@tonic-gate 		}
7447c478bd9Sstevel@tonic-gate 		return(-1);
7457c478bd9Sstevel@tonic-gate 	}
7467c478bd9Sstevel@tonic-gate 	if (d != 5) /* String must contain exactly 5 periods. */
7477c478bd9Sstevel@tonic-gate 		return(-1);
7487c478bd9Sstevel@tonic-gate 
7497c478bd9Sstevel@tonic-gate 	/* Handle the last byte (port low byte) */
7507c478bd9Sstevel@tonic-gate 	t = ippr_rpcb_atoi(b);
7517c478bd9Sstevel@tonic-gate 	if (t > 255)
7527c478bd9Sstevel@tonic-gate 		return(-1);
7537c478bd9Sstevel@tonic-gate 	pp[d - 4] = t & 0xff;
7547c478bd9Sstevel@tonic-gate 
7557c478bd9Sstevel@tonic-gate 	return(0);
7567c478bd9Sstevel@tonic-gate }
7577c478bd9Sstevel@tonic-gate 
7587c478bd9Sstevel@tonic-gate /* --------------------------------------------------------------------	*/
7597c478bd9Sstevel@tonic-gate /* Function:	ippr_rpcb_atoi (XXX should be generic for all proxies)	*/
7607c478bd9Sstevel@tonic-gate /* Returns:	int -- integer representation of supplied string	*/
7617c478bd9Sstevel@tonic-gate /* Parameters:	ptr(I)	- input string					*/
7627c478bd9Sstevel@tonic-gate /*									*/
7637c478bd9Sstevel@tonic-gate /* Simple version of atoi(3) ripped from ip_rcmd_pxy.c.			*/
7647c478bd9Sstevel@tonic-gate /* --------------------------------------------------------------------	*/
7657c478bd9Sstevel@tonic-gate static u_int
ippr_rpcb_atoi(ptr)7667c478bd9Sstevel@tonic-gate ippr_rpcb_atoi(ptr)
7677c478bd9Sstevel@tonic-gate 	char *ptr;
7687c478bd9Sstevel@tonic-gate {
7697c478bd9Sstevel@tonic-gate 	register char *s = ptr, c;
7707c478bd9Sstevel@tonic-gate 	register u_int i = 0;
7717c478bd9Sstevel@tonic-gate 
772ab25eeb5Syz 	while (((c = *s++) != '\0') && ISDIGIT(c)) {
7737c478bd9Sstevel@tonic-gate 		i *= 10;
7747c478bd9Sstevel@tonic-gate 		i += c - '0';
7757c478bd9Sstevel@tonic-gate 	}
7767c478bd9Sstevel@tonic-gate 	return i;
7777c478bd9Sstevel@tonic-gate }
7787c478bd9Sstevel@tonic-gate 
7797c478bd9Sstevel@tonic-gate /* --------------------------------------------------------------------	*/
7807c478bd9Sstevel@tonic-gate /* Function:	ippr_rpcb_modreq					*/
7817c478bd9Sstevel@tonic-gate /* Returns:	int -- change in datagram length			*/
7827c478bd9Sstevel@tonic-gate /*			APR_ERR(2) - critical failure			*/
7837c478bd9Sstevel@tonic-gate /* Parameters:	fin(I)	- pointer to packet information			*/
7847c478bd9Sstevel@tonic-gate /*		nat(I)	- pointer to NAT session			*/
7857c478bd9Sstevel@tonic-gate /*		rm(I)	- pointer to RPC message structure		*/
7867c478bd9Sstevel@tonic-gate /*		m(I)	- pointer to mbuf chain				*/
7877c478bd9Sstevel@tonic-gate /*		off(I)	- current offset within mbuf chain		*/
7887c478bd9Sstevel@tonic-gate /*									*/
7897c478bd9Sstevel@tonic-gate /* When external and internal addresses differ, we rewrite the former	*/
7907c478bd9Sstevel@tonic-gate /* with the latter.  (This is exclusive to protocol versions 3 & 4).	*/
7917c478bd9Sstevel@tonic-gate /* --------------------------------------------------------------------	*/
7927c478bd9Sstevel@tonic-gate static int
ippr_rpcb_modreq(fin,nat,rm,m,off)7937c478bd9Sstevel@tonic-gate ippr_rpcb_modreq(fin, nat, rm, m, off)
7947c478bd9Sstevel@tonic-gate 	fr_info_t *fin;
7957c478bd9Sstevel@tonic-gate 	nat_t *nat;
7967c478bd9Sstevel@tonic-gate 	rpc_msg_t *rm;
7977c478bd9Sstevel@tonic-gate 	mb_t *m;
7987c478bd9Sstevel@tonic-gate 	u_int off;
7997c478bd9Sstevel@tonic-gate {
8007c478bd9Sstevel@tonic-gate 	u_int len, xlen, pos, bogo;
8017c478bd9Sstevel@tonic-gate 	rpcb_args_t *ra;
8027c478bd9Sstevel@tonic-gate 	char uaddr[24];
8037c478bd9Sstevel@tonic-gate 	udphdr_t *udp;
8047c478bd9Sstevel@tonic-gate 	char *i, *p;
8057c478bd9Sstevel@tonic-gate 	int diff;
8067c478bd9Sstevel@tonic-gate 
8077c478bd9Sstevel@tonic-gate 	ra = &rm->rm_call.rc_rpcbargs;
8087c478bd9Sstevel@tonic-gate 	i = (char *)&nat->nat_inip.s_addr;
8097c478bd9Sstevel@tonic-gate 	p = (char *)&nat->nat_inport;
8107c478bd9Sstevel@tonic-gate 
8117c478bd9Sstevel@tonic-gate 	/* Form new string. */
8127c478bd9Sstevel@tonic-gate 	bzero(uaddr, sizeof(uaddr)); /* Just in case we need padding. */
813ab25eeb5Syz #if defined(SNPRINTF) && defined(_KERNEL)
814ab25eeb5Syz 	(void) SNPRINTF(uaddr, sizeof(uaddr),
815ab25eeb5Syz #else
816ab25eeb5Syz 	(void) sprintf(uaddr,
817ab25eeb5Syz #endif
818ab25eeb5Syz 		       "%u.%u.%u.%u.%u.%u", i[0] & 0xff, i[1] & 0xff,
819ab25eeb5Syz 		       i[2] & 0xff, i[3] & 0xff, p[0] & 0xff, p[1] & 0xff);
8207c478bd9Sstevel@tonic-gate 	len = strlen(uaddr);
8217c478bd9Sstevel@tonic-gate 	xlen = XDRALIGN(len);
8227c478bd9Sstevel@tonic-gate 
8237c478bd9Sstevel@tonic-gate 	/* Determine mbuf offset to start writing to. */
8247c478bd9Sstevel@tonic-gate 	pos = (char *)ra->ra_maddr.xu_xslen - rm->rm_msgbuf;
8257c478bd9Sstevel@tonic-gate 	off += pos;
8267c478bd9Sstevel@tonic-gate 
8277c478bd9Sstevel@tonic-gate 	/* Write new string length. */
8287c478bd9Sstevel@tonic-gate 	bogo = htonl(len);
8297c478bd9Sstevel@tonic-gate 	COPYBACK(m, off, 4, (caddr_t)&bogo);
8307c478bd9Sstevel@tonic-gate 	off += 4;
8317c478bd9Sstevel@tonic-gate 
8327c478bd9Sstevel@tonic-gate 	/* Write new string. */
8337c478bd9Sstevel@tonic-gate 	COPYBACK(m, off, xlen, uaddr);
8347c478bd9Sstevel@tonic-gate 	off += xlen;
8357c478bd9Sstevel@tonic-gate 
8367c478bd9Sstevel@tonic-gate 	/* Write in zero r_owner. */
8377c478bd9Sstevel@tonic-gate 	bogo = 0;
8387c478bd9Sstevel@tonic-gate 	COPYBACK(m, off, 4, (caddr_t)&bogo);
8397c478bd9Sstevel@tonic-gate 
8407c478bd9Sstevel@tonic-gate 	/* Determine difference in data lengths. */
8417c478bd9Sstevel@tonic-gate 	diff = xlen - XDRALIGN(B(ra->ra_maddr.xu_xslen));
8427c478bd9Sstevel@tonic-gate 
8437c478bd9Sstevel@tonic-gate 	/*
8447c478bd9Sstevel@tonic-gate 	 * If our new string has a different length, make necessary
8457c478bd9Sstevel@tonic-gate 	 * adjustments.
8467c478bd9Sstevel@tonic-gate 	 */
8477c478bd9Sstevel@tonic-gate 	if (diff != 0) {
8487c478bd9Sstevel@tonic-gate 		udp = fin->fin_dp;
8497c478bd9Sstevel@tonic-gate 		udp->uh_ulen = htons(ntohs(udp->uh_ulen) + diff);
8507c478bd9Sstevel@tonic-gate 		fin->fin_ip->ip_len += diff;
8517c478bd9Sstevel@tonic-gate 		fin->fin_dlen += diff;
8527c478bd9Sstevel@tonic-gate 		fin->fin_plen += diff;
8537c478bd9Sstevel@tonic-gate 		/* XXX Storage lengths. */
8547c478bd9Sstevel@tonic-gate 	}
8557c478bd9Sstevel@tonic-gate 
8567c478bd9Sstevel@tonic-gate 	return(diff);
8577c478bd9Sstevel@tonic-gate }
8587c478bd9Sstevel@tonic-gate 
8597c478bd9Sstevel@tonic-gate /* --------------------------------------------------------------------	*/
8607c478bd9Sstevel@tonic-gate /* Function:	ippr_rpcb_decoderep					*/
8617c478bd9Sstevel@tonic-gate /* Returns:	int - -1 == bad request or critical failure,		*/
8627c478bd9Sstevel@tonic-gate /*		       0 == valid, negative reply			*/
8637c478bd9Sstevel@tonic-gate /*		       1 == vaddlid, positive reply; needs no changes	*/
8647c478bd9Sstevel@tonic-gate /* Parameters:	fin(I)	- pointer to packet information			*/
8657c478bd9Sstevel@tonic-gate /*		nat(I)	- pointer to NAT session structure		*/
8667c478bd9Sstevel@tonic-gate /*		rs(I)	- pointer to RPCB session structure		*/
8677c478bd9Sstevel@tonic-gate /*		rm(I)	- pointer to RPC message structure		*/
8687c478bd9Sstevel@tonic-gate /*		rxp(O)	- pointer to RPCB transaction structure		*/
8697c478bd9Sstevel@tonic-gate /*									*/
8707c478bd9Sstevel@tonic-gate /* Take a presumed RPCB reply, extract the XID, search for the original */
8717c478bd9Sstevel@tonic-gate /* request information, and determine whether the request was accepted	*/
8727c478bd9Sstevel@tonic-gate /* or rejected.  With a valid accepted reply, go ahead and create NAT	*/
8737c478bd9Sstevel@tonic-gate /* and state entries, and finish up by rewriting the packet as 		*/
8747c478bd9Sstevel@tonic-gate /* required.								*/
8757c478bd9Sstevel@tonic-gate /*									*/
8767c478bd9Sstevel@tonic-gate /* WARNING:  It's the responsibility of the caller to make sure there	*/
8777c478bd9Sstevel@tonic-gate /* is enough room in rs_buf for the basic RPC message "preamble".	*/
8787c478bd9Sstevel@tonic-gate /* --------------------------------------------------------------------	*/
8797c478bd9Sstevel@tonic-gate static int
ippr_rpcb_decoderep(fin,nat,rs,rm,rxp,ifsrpcb)880f4b3ec61Sdh ippr_rpcb_decoderep(fin, nat, rs, rm, rxp, ifsrpcb)
8817c478bd9Sstevel@tonic-gate 	fr_info_t *fin;
8827c478bd9Sstevel@tonic-gate 	nat_t *nat;
8837c478bd9Sstevel@tonic-gate 	rpcb_session_t *rs;
8847c478bd9Sstevel@tonic-gate 	rpc_msg_t *rm;
8857c478bd9Sstevel@tonic-gate 	rpcb_xact_t **rxp;
886f4b3ec61Sdh 	ifs_rpcbpxy_t *ifsrpcb;
8877c478bd9Sstevel@tonic-gate {
8887c478bd9Sstevel@tonic-gate 	rpcb_listp_t *rl;
8897c478bd9Sstevel@tonic-gate 	rpcb_entry_t *re;
8907c478bd9Sstevel@tonic-gate 	rpcb_xact_t *rx;
8917c478bd9Sstevel@tonic-gate 	u_32_t xdr, *p;
8927c478bd9Sstevel@tonic-gate 	rpc_resp_t *rr;
8937c478bd9Sstevel@tonic-gate 	int rv, cnt;
8947c478bd9Sstevel@tonic-gate 
8957c478bd9Sstevel@tonic-gate 	p = (u_32_t *)rm->rm_msgbuf;
8967c478bd9Sstevel@tonic-gate 
8977c478bd9Sstevel@tonic-gate 	bzero((char *)&rx, sizeof(rx));
8987c478bd9Sstevel@tonic-gate 	rr = &rm->rm_resp;
8997c478bd9Sstevel@tonic-gate 
9007c478bd9Sstevel@tonic-gate 	rm->rm_xid = p;
9017c478bd9Sstevel@tonic-gate 	xdr = B(p++);		/* Record this message's XID. */
9027c478bd9Sstevel@tonic-gate 
9037c478bd9Sstevel@tonic-gate 	/* Lookup XID */
9047c478bd9Sstevel@tonic-gate         MUTEX_ENTER(&rs->rs_rxlock);
9057c478bd9Sstevel@tonic-gate 	if ((rx = ippr_rpcb_lookup(rs, xdr)) == NULL) {
9067c478bd9Sstevel@tonic-gate                 MUTEX_EXIT(&rs->rs_rxlock);
9077c478bd9Sstevel@tonic-gate 		return(-1);
9087c478bd9Sstevel@tonic-gate         }
9097c478bd9Sstevel@tonic-gate         ++rx->rx_ref;        /* per thread reference */
9107c478bd9Sstevel@tonic-gate         MUTEX_EXIT(&rs->rs_rxlock);
9117c478bd9Sstevel@tonic-gate 
9127c478bd9Sstevel@tonic-gate 	*rxp = rx;
9137c478bd9Sstevel@tonic-gate 
9147c478bd9Sstevel@tonic-gate 	/* Test call vs reply */
9157c478bd9Sstevel@tonic-gate 	if (B(p++) != RPCB_REPLY)
9167c478bd9Sstevel@tonic-gate 		return(-1);
9177c478bd9Sstevel@tonic-gate 
9187c478bd9Sstevel@tonic-gate 	/* Test reply_stat */
9197c478bd9Sstevel@tonic-gate 	switch(B(p++))
9207c478bd9Sstevel@tonic-gate 	{
9217c478bd9Sstevel@tonic-gate 	case RPCB_MSG_DENIED:
9227c478bd9Sstevel@tonic-gate 		return(0);
9237c478bd9Sstevel@tonic-gate 	case RPCB_MSG_ACCEPTED:
9247c478bd9Sstevel@tonic-gate 		break;
9257c478bd9Sstevel@tonic-gate 	default:
9267c478bd9Sstevel@tonic-gate 		return(-1);
9277c478bd9Sstevel@tonic-gate 	}
9287c478bd9Sstevel@tonic-gate 
9297c478bd9Sstevel@tonic-gate 	/* Bypass RPC authentication stuff. */
9307c478bd9Sstevel@tonic-gate 	if (ippr_rpcb_skipauth(rm, &rr->rr_authverf, &p) != 0)
9317c478bd9Sstevel@tonic-gate 		return(-1);
9327c478bd9Sstevel@tonic-gate 
9337c478bd9Sstevel@tonic-gate 	/* Test accept status */
9347c478bd9Sstevel@tonic-gate 	if (!RPCB_BUF_GEQ(rm, p, 4))
9357c478bd9Sstevel@tonic-gate 		return(-1);
9367c478bd9Sstevel@tonic-gate 	if (B(p++) != 0)
9377c478bd9Sstevel@tonic-gate 		return(0);
9387c478bd9Sstevel@tonic-gate 
9397c478bd9Sstevel@tonic-gate 	/* Parse out the expected reply */
9407c478bd9Sstevel@tonic-gate 	switch(rx->rx_type)
9417c478bd9Sstevel@tonic-gate 	{
9427c478bd9Sstevel@tonic-gate 	case RPCB_RES_PMAP:
9437c478bd9Sstevel@tonic-gate 		/* There must be only one 4 byte argument. */
9447c478bd9Sstevel@tonic-gate 		if (!RPCB_BUF_EQ(rm, p, 4))
9457c478bd9Sstevel@tonic-gate 			return(-1);
946*55fea89dSDan Cross 
9477c478bd9Sstevel@tonic-gate 		rr->rr_v2 = p;
9487c478bd9Sstevel@tonic-gate 		xdr = B(rr->rr_v2);
949*55fea89dSDan Cross 
9507c478bd9Sstevel@tonic-gate 		/* Reply w/ a 0 port indicates service isn't registered */
9517c478bd9Sstevel@tonic-gate 		if (xdr == 0)
9527c478bd9Sstevel@tonic-gate 			return(0);
953*55fea89dSDan Cross 
9547c478bd9Sstevel@tonic-gate 		/* Is the value sane? */
9557c478bd9Sstevel@tonic-gate 		if (xdr > 65535)
9567c478bd9Sstevel@tonic-gate 			return(-1);
9577c478bd9Sstevel@tonic-gate 
9587c478bd9Sstevel@tonic-gate 		/* Create NAT & state table entries. */
959f4b3ec61Sdh 		if (ippr_rpcb_getnat(fin, nat, rx->rx_proto, (u_int)xdr, ifsrpcb) != 0)
9607c478bd9Sstevel@tonic-gate 			return(-1);
9617c478bd9Sstevel@tonic-gate 		break;
9627c478bd9Sstevel@tonic-gate 	case RPCB_RES_STRING:
9637c478bd9Sstevel@tonic-gate 		/* Expecting a XDR string; need 4 bytes for length */
9647c478bd9Sstevel@tonic-gate 		if (!RPCB_BUF_GEQ(rm, p, 4))
9657c478bd9Sstevel@tonic-gate 			return(-1);
9667c478bd9Sstevel@tonic-gate 
9677c478bd9Sstevel@tonic-gate 		rr->rr_v3.xu_str.xs_len = p++;
9687c478bd9Sstevel@tonic-gate 		rr->rr_v3.xu_str.xs_str = (char *)p;
9697c478bd9Sstevel@tonic-gate 
9707c478bd9Sstevel@tonic-gate 		xdr = B(rr->rr_v3.xu_xslen);
9717c478bd9Sstevel@tonic-gate 
9727c478bd9Sstevel@tonic-gate 		/* A null string indicates an unregistered service */
9737c478bd9Sstevel@tonic-gate 		if ((xdr == 0) && RPCB_BUF_EQ(rm, p, 0))
9747c478bd9Sstevel@tonic-gate 			return(0);
9757c478bd9Sstevel@tonic-gate 
9767c478bd9Sstevel@tonic-gate 		/* Decode the target IP address / port. */
9777c478bd9Sstevel@tonic-gate 		if (ippr_rpcb_getuaddr(rm, &rr->rr_v3, &p) != 0)
9787c478bd9Sstevel@tonic-gate 			return(-1);
9797c478bd9Sstevel@tonic-gate 
9807c478bd9Sstevel@tonic-gate 		/* Validate the IP address and port contained. */
9817c478bd9Sstevel@tonic-gate 		if (nat->nat_inip.s_addr != rr->rr_v3.xu_ip)
9827c478bd9Sstevel@tonic-gate 			return(-1);
9837c478bd9Sstevel@tonic-gate 
9847c478bd9Sstevel@tonic-gate 		/* Create NAT & state table entries. */
9857c478bd9Sstevel@tonic-gate 		if (ippr_rpcb_getnat(fin, nat, rx->rx_proto,
986f4b3ec61Sdh 				     (u_int)rr->rr_v3.xu_port, ifsrpcb) != 0)
9877c478bd9Sstevel@tonic-gate 			return(-1);
9887c478bd9Sstevel@tonic-gate 		break;
9897c478bd9Sstevel@tonic-gate 	case RPCB_RES_LIST:
9907c478bd9Sstevel@tonic-gate 		if (!RPCB_BUF_GEQ(rm, p, 4))
9917c478bd9Sstevel@tonic-gate 			return(-1);
9927c478bd9Sstevel@tonic-gate 		/* rpcb_entry_list_ptr */
9937c478bd9Sstevel@tonic-gate 		switch(B(p))
9947c478bd9Sstevel@tonic-gate 		{
9957c478bd9Sstevel@tonic-gate 		case 0:
9967c478bd9Sstevel@tonic-gate 			return(0);
9977c478bd9Sstevel@tonic-gate 		case 1:
9987c478bd9Sstevel@tonic-gate 			break;
9997c478bd9Sstevel@tonic-gate 		default:
10007c478bd9Sstevel@tonic-gate 			return(-1);
10017c478bd9Sstevel@tonic-gate 		}
10027c478bd9Sstevel@tonic-gate 		rl = &rr->rr_v4;
10037c478bd9Sstevel@tonic-gate 		rl->rl_list = p++;
10047c478bd9Sstevel@tonic-gate 		cnt = 0;
10057c478bd9Sstevel@tonic-gate 
10067c478bd9Sstevel@tonic-gate 		for(;;) {
10077c478bd9Sstevel@tonic-gate 			re = &rl->rl_entries[rl->rl_cnt];
10087c478bd9Sstevel@tonic-gate 			if (ippr_rpcb_getuaddr(rm, &re->re_maddr, &p) != 0)
10097c478bd9Sstevel@tonic-gate 				return(-1);
10107c478bd9Sstevel@tonic-gate 			if (ippr_rpcb_getproto(rm, &re->re_netid, &p) != 0)
10117c478bd9Sstevel@tonic-gate 				return(-1);
10127c478bd9Sstevel@tonic-gate 			/* re_semantics & re_pfamily length */
10137c478bd9Sstevel@tonic-gate 			if (!RPCB_BUF_GEQ(rm, p, 12))
10147c478bd9Sstevel@tonic-gate 				return(-1);
10157c478bd9Sstevel@tonic-gate 			p++; /* Skipping re_semantics. */
10167c478bd9Sstevel@tonic-gate 			xdr = B(p++);
10177c478bd9Sstevel@tonic-gate 			if ((xdr != 4) || strncmp((char *)p, "inet", 4))
10187c478bd9Sstevel@tonic-gate 				return(-1);
10197c478bd9Sstevel@tonic-gate 			p++;
10207c478bd9Sstevel@tonic-gate 			if (ippr_rpcb_getproto(rm, &re->re_proto, &p) != 0)
10217c478bd9Sstevel@tonic-gate 				return(-1);
10227c478bd9Sstevel@tonic-gate 			if (!RPCB_BUF_GEQ(rm, p, 4))
10237c478bd9Sstevel@tonic-gate 				return(-1);
10247c478bd9Sstevel@tonic-gate 			re->re_more = p;
10257c478bd9Sstevel@tonic-gate 			if (B(re->re_more) > 1) /* 0,1 only legal values */
10267c478bd9Sstevel@tonic-gate 				return(-1);
10277c478bd9Sstevel@tonic-gate 			++rl->rl_cnt;
10287c478bd9Sstevel@tonic-gate 			++cnt;
10297c478bd9Sstevel@tonic-gate 			if (B(re->re_more) == 0)
10307c478bd9Sstevel@tonic-gate 				break;
10317c478bd9Sstevel@tonic-gate 			/* Replies in  max out at 2; TCP and/or UDP */
10327c478bd9Sstevel@tonic-gate 			if (cnt > 2)
10337c478bd9Sstevel@tonic-gate 				return(-1);
10347c478bd9Sstevel@tonic-gate 			p++;
10357c478bd9Sstevel@tonic-gate 		}
10367c478bd9Sstevel@tonic-gate 
10377c478bd9Sstevel@tonic-gate 		for(rl->rl_cnt = 0; rl->rl_cnt < cnt; rl->rl_cnt++) {
10387c478bd9Sstevel@tonic-gate 			re = &rl->rl_entries[rl->rl_cnt];
10397c478bd9Sstevel@tonic-gate 			rv = ippr_rpcb_getnat(fin, nat,
1040ab25eeb5Syz 			                      re->re_proto.xp_proto,
1041f4b3ec61Sdh 				              (u_int)re->re_maddr.xu_port,
1042f4b3ec61Sdh 					      ifsrpcb);
10437c478bd9Sstevel@tonic-gate 			if (rv != 0)
10447c478bd9Sstevel@tonic-gate 				return(-1);
10457c478bd9Sstevel@tonic-gate 		}
10467c478bd9Sstevel@tonic-gate 		break;
10477c478bd9Sstevel@tonic-gate 	default:
10487c478bd9Sstevel@tonic-gate 		/*CONSTANTCONDITION*/
10497c478bd9Sstevel@tonic-gate 		IPF_PANIC(1, ("illegal rx_type %d", rx->rx_type));
10507c478bd9Sstevel@tonic-gate 	}
10517c478bd9Sstevel@tonic-gate 
10527c478bd9Sstevel@tonic-gate 	return(1);
10537c478bd9Sstevel@tonic-gate }
10547c478bd9Sstevel@tonic-gate 
10557c478bd9Sstevel@tonic-gate /* --------------------------------------------------------------------	*/
10567c478bd9Sstevel@tonic-gate /* Function:	ippr_rpcb_lookup					*/
10577c478bd9Sstevel@tonic-gate /* Returns:	rpcb_xact_t * 	- NULL == no matching record,		*/
10587c478bd9Sstevel@tonic-gate /*				  else pointer to relevant entry	*/
10597c478bd9Sstevel@tonic-gate /* Parameters:	rs(I)	- pointer to RPCB session			*/
10607c478bd9Sstevel@tonic-gate /*		xid(I)	- XID to look for				*/
10617c478bd9Sstevel@tonic-gate /* --------------------------------------------------------------------	*/
10627c478bd9Sstevel@tonic-gate static rpcb_xact_t *
ippr_rpcb_lookup(rs,xid)10637c478bd9Sstevel@tonic-gate ippr_rpcb_lookup(rs, xid)
10647c478bd9Sstevel@tonic-gate 	rpcb_session_t *rs;
10657c478bd9Sstevel@tonic-gate 	u_32_t xid;
10667c478bd9Sstevel@tonic-gate {
10677c478bd9Sstevel@tonic-gate 	rpcb_xact_t *rx;
10687c478bd9Sstevel@tonic-gate 
10697c478bd9Sstevel@tonic-gate 	if (rs->rs_rxlist == NULL)
10707c478bd9Sstevel@tonic-gate 		return(NULL);
10717c478bd9Sstevel@tonic-gate 
10727c478bd9Sstevel@tonic-gate 	for (rx = rs->rs_rxlist; rx != NULL; rx = rx->rx_next)
10737c478bd9Sstevel@tonic-gate 		if (rx->rx_xid == xid)
10747c478bd9Sstevel@tonic-gate 			break;
10757c478bd9Sstevel@tonic-gate 
10767c478bd9Sstevel@tonic-gate 	return(rx);
10777c478bd9Sstevel@tonic-gate }
10787c478bd9Sstevel@tonic-gate 
10797c478bd9Sstevel@tonic-gate /* --------------------------------------------------------------------	*/
10807c478bd9Sstevel@tonic-gate /* Function:	ippr_rpcb_deref					        */
10817c478bd9Sstevel@tonic-gate /* Returns:	(void)							*/
10827c478bd9Sstevel@tonic-gate /* Parameters:	rs(I)	- pointer to RPCB session			*/
10837c478bd9Sstevel@tonic-gate /*		rx(I)	- pointer to RPC transaction struct to remove	*/
10847c478bd9Sstevel@tonic-gate /*              force(I) - indicates to delete entry regardless of      */
10857c478bd9Sstevel@tonic-gate /*                         reference count                              */
10867c478bd9Sstevel@tonic-gate /* Locking:	rs->rs_rxlock must be held write only			*/
10877c478bd9Sstevel@tonic-gate /*									*/
10887c478bd9Sstevel@tonic-gate /* Free the RPCB transaction record rx from the chain of entries.	*/
10897c478bd9Sstevel@tonic-gate /* --------------------------------------------------------------------	*/
10907c478bd9Sstevel@tonic-gate static void
ippr_rpcb_deref(rs,rx,ifsrpcb)1091f4b3ec61Sdh ippr_rpcb_deref(rs, rx, ifsrpcb)
10927c478bd9Sstevel@tonic-gate 	rpcb_session_t *rs;
10937c478bd9Sstevel@tonic-gate 	rpcb_xact_t *rx;
1094f4b3ec61Sdh 	ifs_rpcbpxy_t *ifsrpcb;
10957c478bd9Sstevel@tonic-gate {
10967c478bd9Sstevel@tonic-gate 	rs = rs;	/* LINT */
10977c478bd9Sstevel@tonic-gate 
10987c478bd9Sstevel@tonic-gate 	if (rx == NULL)
10997c478bd9Sstevel@tonic-gate 		return;
11007c478bd9Sstevel@tonic-gate 
11017c478bd9Sstevel@tonic-gate 	if (--rx->rx_ref != 0)
11027c478bd9Sstevel@tonic-gate 		return;
11037c478bd9Sstevel@tonic-gate 
11047c478bd9Sstevel@tonic-gate 	if (rx->rx_next != NULL)
11057c478bd9Sstevel@tonic-gate 		rx->rx_next->rx_pnext = rx->rx_pnext;
11067c478bd9Sstevel@tonic-gate 
11077c478bd9Sstevel@tonic-gate 	*rx->rx_pnext = rx->rx_next;
11087c478bd9Sstevel@tonic-gate 
11097c478bd9Sstevel@tonic-gate 	KFREE(rx);
11107c478bd9Sstevel@tonic-gate 
1111f4b3ec61Sdh 	--ifsrpcb->rpcbcnt;
11127c478bd9Sstevel@tonic-gate }
11137c478bd9Sstevel@tonic-gate 
11147c478bd9Sstevel@tonic-gate /* --------------------------------------------------------------------	*/
11157c478bd9Sstevel@tonic-gate /* Function:	ippr_rpcb_getproto					*/
11167c478bd9Sstevel@tonic-gate /* Returns:	int - -1 == illegal protocol/netid,			*/
11177c478bd9Sstevel@tonic-gate /*		       0 == legal protocol/netid			*/
11187c478bd9Sstevel@tonic-gate /* Parameters:	rm(I)	- pointer to RPC message structure		*/
11197c478bd9Sstevel@tonic-gate /*		xp(I)	- pointer to netid structure			*/
11207c478bd9Sstevel@tonic-gate /*		p(IO)	- pointer to location within packet buffer	*/
11217c478bd9Sstevel@tonic-gate /* 									*/
11227c478bd9Sstevel@tonic-gate /* Decode netid/proto stored at p and record its numeric value.	 	*/
11237c478bd9Sstevel@tonic-gate /* --------------------------------------------------------------------	*/
11247c478bd9Sstevel@tonic-gate static int
ippr_rpcb_getproto(rm,xp,p)11257c478bd9Sstevel@tonic-gate ippr_rpcb_getproto(rm, xp, p)
11267c478bd9Sstevel@tonic-gate 	rpc_msg_t *rm;
11277c478bd9Sstevel@tonic-gate 	xdr_proto_t *xp;
11287c478bd9Sstevel@tonic-gate 	u_32_t **p;
11297c478bd9Sstevel@tonic-gate {
11307c478bd9Sstevel@tonic-gate 	u_int len;
11317c478bd9Sstevel@tonic-gate 
11327c478bd9Sstevel@tonic-gate 	/* Must have 4 bytes for length & 4 bytes for "tcp" or "udp". */
11337c478bd9Sstevel@tonic-gate 	if (!RPCB_BUF_GEQ(rm, p, 8))
11347c478bd9Sstevel@tonic-gate 		return(-1);
11357c478bd9Sstevel@tonic-gate 
11367c478bd9Sstevel@tonic-gate 	xp->xp_xslen = (*p)++;
11377c478bd9Sstevel@tonic-gate 	xp->xp_xsstr = (char *)*p;
11387c478bd9Sstevel@tonic-gate 
11397c478bd9Sstevel@tonic-gate 	/* Test the string length. */
11407c478bd9Sstevel@tonic-gate 	len = B(xp->xp_xslen);
11417c478bd9Sstevel@tonic-gate 	if (len != 3)
11427c478bd9Sstevel@tonic-gate 	 	return(-1);
11437c478bd9Sstevel@tonic-gate 
11447c478bd9Sstevel@tonic-gate 	/* Test the actual string & record the protocol accordingly. */
11457c478bd9Sstevel@tonic-gate 	if (!strncmp((char *)xp->xp_xsstr, "tcp\0", 4))
11467c478bd9Sstevel@tonic-gate 		xp->xp_proto = IPPROTO_TCP;
11477c478bd9Sstevel@tonic-gate 	else if (!strncmp((char *)xp->xp_xsstr, "udp\0", 4))
11487c478bd9Sstevel@tonic-gate 		xp->xp_proto = IPPROTO_UDP;
11497c478bd9Sstevel@tonic-gate 	else {
11507c478bd9Sstevel@tonic-gate 		return(-1);
11517c478bd9Sstevel@tonic-gate 	}
1152*55fea89dSDan Cross 
11537c478bd9Sstevel@tonic-gate 	/* Advance past the string. */
11547c478bd9Sstevel@tonic-gate 	(*p)++;
11557c478bd9Sstevel@tonic-gate 
11567c478bd9Sstevel@tonic-gate 	return(0);
11577c478bd9Sstevel@tonic-gate }
11587c478bd9Sstevel@tonic-gate 
11597c478bd9Sstevel@tonic-gate /* --------------------------------------------------------------------	*/
11607c478bd9Sstevel@tonic-gate /* Function:	ippr_rpcb_getnat					*/
11617c478bd9Sstevel@tonic-gate /* Returns:	int -- -1 == failed to create table entries,		*/
11627c478bd9Sstevel@tonic-gate /*			0 == success					*/
11637c478bd9Sstevel@tonic-gate /* Parameters:	fin(I)	- pointer to packet information			*/
11647c478bd9Sstevel@tonic-gate /*		nat(I)	- pointer to NAT table entry			*/
11657c478bd9Sstevel@tonic-gate /*		proto(I) - transport protocol for new entries		*/
11667c478bd9Sstevel@tonic-gate /*		port(I)	- new port to use w/ wildcard table entries	*/
11677c478bd9Sstevel@tonic-gate /*									*/
11687c478bd9Sstevel@tonic-gate /* Create state and NAT entries to handle an anticipated connection	*/
11697c478bd9Sstevel@tonic-gate /* attempt between RPC client and server.				*/
11707c478bd9Sstevel@tonic-gate /* --------------------------------------------------------------------	*/
11717c478bd9Sstevel@tonic-gate static int
ippr_rpcb_getnat(fin,nat,proto,port,ifsrpcb)1172f4b3ec61Sdh ippr_rpcb_getnat(fin, nat, proto, port, ifsrpcb)
11737c478bd9Sstevel@tonic-gate 	fr_info_t *fin;
11747c478bd9Sstevel@tonic-gate 	nat_t *nat;
11757c478bd9Sstevel@tonic-gate 	u_int proto;
11767c478bd9Sstevel@tonic-gate 	u_int port;
1177f4b3ec61Sdh 	ifs_rpcbpxy_t *ifsrpcb;
11787c478bd9Sstevel@tonic-gate {
11797c478bd9Sstevel@tonic-gate 	ipnat_t *ipn, ipnat;
11807c478bd9Sstevel@tonic-gate 	tcphdr_t tcp;
11817c478bd9Sstevel@tonic-gate 	ipstate_t *is;
11827c478bd9Sstevel@tonic-gate 	fr_info_t fi;
11837c478bd9Sstevel@tonic-gate 	nat_t *natl;
11847c478bd9Sstevel@tonic-gate 	int nflags;
1185f4b3ec61Sdh 	ipf_stack_t *ifs = fin->fin_ifs;
11867c478bd9Sstevel@tonic-gate 
11877c478bd9Sstevel@tonic-gate 	ipn = nat->nat_ptr;
11887c478bd9Sstevel@tonic-gate 
11897c478bd9Sstevel@tonic-gate 	/* Generate dummy fr_info */
11907c478bd9Sstevel@tonic-gate 	bcopy((char *)fin, (char *)&fi, sizeof(fi));
11917c478bd9Sstevel@tonic-gate 	fi.fin_out = 0;
11927c478bd9Sstevel@tonic-gate 	fi.fin_src = fin->fin_dst;
11937c478bd9Sstevel@tonic-gate 	fi.fin_dst = nat->nat_outip;
11947c478bd9Sstevel@tonic-gate 	fi.fin_p = proto;
11957c478bd9Sstevel@tonic-gate 	fi.fin_sport = 0;
11967c478bd9Sstevel@tonic-gate 	fi.fin_dport = port & 0xffff;
11977c478bd9Sstevel@tonic-gate 	fi.fin_flx |= FI_IGNORE;
11987c478bd9Sstevel@tonic-gate 
11997c478bd9Sstevel@tonic-gate 	bzero((char *)&tcp, sizeof(tcp));
12007c478bd9Sstevel@tonic-gate 	tcp.th_dport = htons(port);
12017c478bd9Sstevel@tonic-gate 
12027c478bd9Sstevel@tonic-gate 	if (proto == IPPROTO_TCP) {
12037c478bd9Sstevel@tonic-gate 		tcp.th_win = htons(8192);
12047c478bd9Sstevel@tonic-gate 		TCP_OFF_A(&tcp, sizeof(tcphdr_t) >> 2);
12057c478bd9Sstevel@tonic-gate 		fi.fin_dlen = sizeof(tcphdr_t);
12067c478bd9Sstevel@tonic-gate 		tcp.th_flags = TH_SYN;
12077c478bd9Sstevel@tonic-gate 		nflags = NAT_TCP;
12087c478bd9Sstevel@tonic-gate 	} else {
12097c478bd9Sstevel@tonic-gate 		fi.fin_dlen = sizeof(udphdr_t);
12107c478bd9Sstevel@tonic-gate 		nflags = NAT_UDP;
12117c478bd9Sstevel@tonic-gate 	}
12127c478bd9Sstevel@tonic-gate 
12137c478bd9Sstevel@tonic-gate 	nflags |= SI_W_SPORT|NAT_SEARCH;
12147c478bd9Sstevel@tonic-gate 	fi.fin_dp = &tcp;
12157c478bd9Sstevel@tonic-gate 	fi.fin_plen = fi.fin_hlen + fi.fin_dlen;
12167c478bd9Sstevel@tonic-gate 
1217ab25eeb5Syz 	/*
12187c478bd9Sstevel@tonic-gate 	 * Search for existing NAT & state entries.  Pay close attention to
12197c478bd9Sstevel@tonic-gate 	 * mutexes / locks grabbed from lookup routines, as not doing so could
12207c478bd9Sstevel@tonic-gate 	 * lead to bad things.
12217c478bd9Sstevel@tonic-gate 	 *
12227c478bd9Sstevel@tonic-gate 	 * If successful, fr_stlookup returns with ipf_state locked.  We have
12237c478bd9Sstevel@tonic-gate 	 * no use for this lock, so simply unlock it if necessary.
12247c478bd9Sstevel@tonic-gate 	 */
12257c478bd9Sstevel@tonic-gate 	is = fr_stlookup(&fi, &tcp, NULL);
12267c478bd9Sstevel@tonic-gate 	if (is != NULL)
1227f4b3ec61Sdh 		RWLOCK_EXIT(&ifs->ifs_ipf_state);
12287c478bd9Sstevel@tonic-gate 
1229f4b3ec61Sdh 	RWLOCK_EXIT(&ifs->ifs_ipf_nat);
12307c478bd9Sstevel@tonic-gate 
1231f4b3ec61Sdh 	WRITE_ENTER(&ifs->ifs_ipf_nat);
12327c478bd9Sstevel@tonic-gate 	natl = nat_inlookup(&fi, nflags, proto, fi.fin_src, fi.fin_dst);
12337c478bd9Sstevel@tonic-gate 
12347c478bd9Sstevel@tonic-gate 	if ((natl != NULL) && (is != NULL)) {
1235f4b3ec61Sdh 		MUTEX_DOWNGRADE(&ifs->ifs_ipf_nat);
12367c478bd9Sstevel@tonic-gate 		return(0);
12377c478bd9Sstevel@tonic-gate 	}
12387c478bd9Sstevel@tonic-gate 
12397c478bd9Sstevel@tonic-gate 	/* Slightly modify the following structures for actual use in creating
12407c478bd9Sstevel@tonic-gate 	 * NAT and/or state entries.  We're primarily concerned with stripping
12417c478bd9Sstevel@tonic-gate 	 * flags that may be detrimental to the creation process or simply
12427c478bd9Sstevel@tonic-gate 	 * shouldn't be associated with a table entry.
12437c478bd9Sstevel@tonic-gate 	 */
1244f4b3ec61Sdh 	fi.fin_fr = &ifsrpcb->rpcbfr;
12457c478bd9Sstevel@tonic-gate 	fi.fin_flx &= ~FI_IGNORE;
12467c478bd9Sstevel@tonic-gate 	nflags &= ~NAT_SEARCH;
12477c478bd9Sstevel@tonic-gate 
12487c478bd9Sstevel@tonic-gate 	if (natl == NULL) {
12497c478bd9Sstevel@tonic-gate 		/* XXX Since we're just copying the original ipn contents
12507c478bd9Sstevel@tonic-gate 		 * back, would we be better off just sending a pointer to
12517c478bd9Sstevel@tonic-gate 		 * the 'temp' copy off to nat_new instead?
12527c478bd9Sstevel@tonic-gate 		 */
12537c478bd9Sstevel@tonic-gate 		/* Generate template/bogus NAT rule. */
12547c478bd9Sstevel@tonic-gate 		bcopy((char *)ipn, (char *)&ipnat, sizeof(ipnat));
12557c478bd9Sstevel@tonic-gate 		ipn->in_flags = nflags & IPN_TCPUDP;
12567c478bd9Sstevel@tonic-gate 		ipn->in_apr = NULL;
12577c478bd9Sstevel@tonic-gate 		ipn->in_p = proto;
12587c478bd9Sstevel@tonic-gate 		ipn->in_pmin = htons(fi.fin_dport);
12597c478bd9Sstevel@tonic-gate 		ipn->in_pmax = htons(fi.fin_dport);
12607c478bd9Sstevel@tonic-gate 		ipn->in_pnext = htons(fi.fin_dport);
12617c478bd9Sstevel@tonic-gate 		ipn->in_space = 1;
12627c478bd9Sstevel@tonic-gate 		ipn->in_ippip = 1;
12637c478bd9Sstevel@tonic-gate 		if (ipn->in_flags & IPN_FILTER) {
12647c478bd9Sstevel@tonic-gate 			ipn->in_scmp = 0;
12657c478bd9Sstevel@tonic-gate 			ipn->in_dcmp = 0;
12667c478bd9Sstevel@tonic-gate 		}
12677c478bd9Sstevel@tonic-gate 		*ipn->in_plabel = '\0';
12687c478bd9Sstevel@tonic-gate 
12697c478bd9Sstevel@tonic-gate 		/* Create NAT entry.  return NULL if this fails. */
12707c478bd9Sstevel@tonic-gate 		natl = nat_new(&fi, ipn, NULL, nflags|SI_CLONE|NAT_SLAVE,
12717c478bd9Sstevel@tonic-gate 			       NAT_INBOUND);
12727c478bd9Sstevel@tonic-gate 
12737c478bd9Sstevel@tonic-gate 		bcopy((char *)&ipnat, (char *)ipn, sizeof(ipnat));
12747c478bd9Sstevel@tonic-gate 
12757c478bd9Sstevel@tonic-gate 		if (natl == NULL) {
1276f4b3ec61Sdh 			MUTEX_DOWNGRADE(&ifs->ifs_ipf_nat);
12777c478bd9Sstevel@tonic-gate 			return(-1);
12787c478bd9Sstevel@tonic-gate 		}
12797c478bd9Sstevel@tonic-gate 
12807c478bd9Sstevel@tonic-gate 		ipn->in_use++;
12817c478bd9Sstevel@tonic-gate 		(void) nat_proto(&fi, natl, nflags);
12827c478bd9Sstevel@tonic-gate 		nat_update(&fi, natl, natl->nat_ptr);
12837c478bd9Sstevel@tonic-gate 	}
1284f4b3ec61Sdh 	MUTEX_DOWNGRADE(&ifs->ifs_ipf_nat);
12857c478bd9Sstevel@tonic-gate 
12867c478bd9Sstevel@tonic-gate 	if (is == NULL) {
12877c478bd9Sstevel@tonic-gate 		/* Create state entry.  Return NULL if this fails. */
12887c478bd9Sstevel@tonic-gate 		fi.fin_dst = nat->nat_inip;
12897c478bd9Sstevel@tonic-gate 		fi.fin_flx |= FI_NATED;
12907c478bd9Sstevel@tonic-gate 		fi.fin_flx &= ~FI_STATE;
12917c478bd9Sstevel@tonic-gate 		nflags &= NAT_TCPUDP;
12927c478bd9Sstevel@tonic-gate 		nflags |= SI_W_SPORT|SI_CLONE;
12937c478bd9Sstevel@tonic-gate 
12947c478bd9Sstevel@tonic-gate 		is = fr_addstate(&fi, NULL, nflags);
12957c478bd9Sstevel@tonic-gate 		if (is == NULL) {
12967c478bd9Sstevel@tonic-gate 			/*
12977c478bd9Sstevel@tonic-gate 			 * XXX nat_delete is private to ip_nat.c.  Should
12987c478bd9Sstevel@tonic-gate 			 * check w/ Darren about this one.
12997c478bd9Sstevel@tonic-gate 			 *
1300f4b3ec61Sdh 			 * nat_delete(natl, NL_EXPIRE, ifs);
13017c478bd9Sstevel@tonic-gate 			 */
13027c478bd9Sstevel@tonic-gate 			return(-1);
13037c478bd9Sstevel@tonic-gate 		}
13047c478bd9Sstevel@tonic-gate 	}
13057c478bd9Sstevel@tonic-gate 
13067c478bd9Sstevel@tonic-gate 	return(0);
13077c478bd9Sstevel@tonic-gate }
13087c478bd9Sstevel@tonic-gate 
13097c478bd9Sstevel@tonic-gate /* --------------------------------------------------------------------	*/
13107c478bd9Sstevel@tonic-gate /* Function:	ippr_rpcb_modv3						*/
13117c478bd9Sstevel@tonic-gate /* Returns:	int -- change in packet length				*/
13127c478bd9Sstevel@tonic-gate /* Parameters:	fin(I)	- pointer to packet information			*/
13137c478bd9Sstevel@tonic-gate /*		nat(I)	- pointer to NAT session			*/
13147c478bd9Sstevel@tonic-gate /*		rm(I)	- pointer to RPC message structure		*/
13157c478bd9Sstevel@tonic-gate /*		m(I)	- pointer to mbuf chain				*/
13167c478bd9Sstevel@tonic-gate /*		off(I)	- offset within mbuf chain			*/
13177c478bd9Sstevel@tonic-gate /*									*/
13187c478bd9Sstevel@tonic-gate /* Write a new universal address string to this packet, adjusting	*/
13197c478bd9Sstevel@tonic-gate /* lengths as necessary.						*/
13207c478bd9Sstevel@tonic-gate /* --------------------------------------------------------------------	*/
13217c478bd9Sstevel@tonic-gate static int
ippr_rpcb_modv3(fin,nat,rm,m,off)13227c478bd9Sstevel@tonic-gate ippr_rpcb_modv3(fin, nat, rm, m, off)
13237c478bd9Sstevel@tonic-gate 	fr_info_t *fin;
13247c478bd9Sstevel@tonic-gate 	nat_t *nat;
13257c478bd9Sstevel@tonic-gate 	rpc_msg_t *rm;
13267c478bd9Sstevel@tonic-gate 	mb_t *m;
13277c478bd9Sstevel@tonic-gate 	u_int off;
13287c478bd9Sstevel@tonic-gate {
13297c478bd9Sstevel@tonic-gate 	u_int len, xlen, pos, bogo;
13307c478bd9Sstevel@tonic-gate 	rpc_resp_t *rr;
13317c478bd9Sstevel@tonic-gate 	char uaddr[24];
13327c478bd9Sstevel@tonic-gate 	char *i, *p;
13337c478bd9Sstevel@tonic-gate 	int diff;
13347c478bd9Sstevel@tonic-gate 
13357c478bd9Sstevel@tonic-gate 	rr = &rm->rm_resp;
13367c478bd9Sstevel@tonic-gate 	i = (char *)&nat->nat_outip.s_addr;
13377c478bd9Sstevel@tonic-gate 	p = (char *)&rr->rr_v3.xu_port;
13387c478bd9Sstevel@tonic-gate 
13397c478bd9Sstevel@tonic-gate 	/* Form new string. */
13407c478bd9Sstevel@tonic-gate 	bzero(uaddr, sizeof(uaddr)); /* Just in case we need padding. */
1341ab25eeb5Syz #if defined(SNPRINTF) && defined(_KERNEL)
1342ab25eeb5Syz 	(void) SNPRINTF(uaddr, sizeof(uaddr),
1343ab25eeb5Syz #else
1344ab25eeb5Syz 	(void) sprintf(uaddr,
1345ab25eeb5Syz #endif
1346ab25eeb5Syz 		       "%u.%u.%u.%u.%u.%u", i[0] & 0xff, i[1] & 0xff,
1347ab25eeb5Syz 		       i[2] & 0xff, i[3] & 0xff, p[0] & 0xff, p[1] & 0xff);
13487c478bd9Sstevel@tonic-gate 	len = strlen(uaddr);
13497c478bd9Sstevel@tonic-gate 	xlen = XDRALIGN(len);
13507c478bd9Sstevel@tonic-gate 
13517c478bd9Sstevel@tonic-gate 	/* Determine mbuf offset to write to. */
13527c478bd9Sstevel@tonic-gate 	pos = (char *)rr->rr_v3.xu_xslen - rm->rm_msgbuf;
13537c478bd9Sstevel@tonic-gate 	off += pos;
13547c478bd9Sstevel@tonic-gate 
13557c478bd9Sstevel@tonic-gate 	/* Write new string length. */
13567c478bd9Sstevel@tonic-gate 	bogo = htonl(len);
13577c478bd9Sstevel@tonic-gate 	COPYBACK(m, off, 4, (caddr_t)&bogo);
13587c478bd9Sstevel@tonic-gate 	off += 4;
13597c478bd9Sstevel@tonic-gate 
13607c478bd9Sstevel@tonic-gate 	/* Write new string. */
13617c478bd9Sstevel@tonic-gate 	COPYBACK(m, off, xlen, uaddr);
1362*55fea89dSDan Cross 
13637c478bd9Sstevel@tonic-gate 	/* Determine difference in data lengths. */
13647c478bd9Sstevel@tonic-gate 	diff = xlen - XDRALIGN(B(rr->rr_v3.xu_xslen));
13657c478bd9Sstevel@tonic-gate 
13667c478bd9Sstevel@tonic-gate 	/*
13677c478bd9Sstevel@tonic-gate 	 * If our new string has a different length, make necessary
13687c478bd9Sstevel@tonic-gate 	 * adjustments.
13697c478bd9Sstevel@tonic-gate 	 */
13707c478bd9Sstevel@tonic-gate 	if (diff != 0)
13717c478bd9Sstevel@tonic-gate 		ippr_rpcb_fixlen(fin, diff);
13727c478bd9Sstevel@tonic-gate 
13737c478bd9Sstevel@tonic-gate 	return(diff);
13747c478bd9Sstevel@tonic-gate }
13757c478bd9Sstevel@tonic-gate 
13767c478bd9Sstevel@tonic-gate /* --------------------------------------------------------------------	*/
13777c478bd9Sstevel@tonic-gate /* Function:	ippr_rpcb_modv4						*/
13787c478bd9Sstevel@tonic-gate /* Returns:	int -- change in packet length				*/
13797c478bd9Sstevel@tonic-gate /* Parameters:	fin(I)	- pointer to packet information			*/
13807c478bd9Sstevel@tonic-gate /*		nat(I)	- pointer to NAT session			*/
13817c478bd9Sstevel@tonic-gate /*		rm(I)	- pointer to RPC message structure		*/
13827c478bd9Sstevel@tonic-gate /*		m(I)	- pointer to mbuf chain				*/
13837c478bd9Sstevel@tonic-gate /*		off(I)	- offset within mbuf chain			*/
13847c478bd9Sstevel@tonic-gate /*									*/
13857c478bd9Sstevel@tonic-gate /* Write new rpcb_entry list, adjusting	lengths as necessary.		*/
13867c478bd9Sstevel@tonic-gate /* --------------------------------------------------------------------	*/
13877c478bd9Sstevel@tonic-gate static int
ippr_rpcb_modv4(fin,nat,rm,m,off)13887c478bd9Sstevel@tonic-gate ippr_rpcb_modv4(fin, nat, rm, m, off)
13897c478bd9Sstevel@tonic-gate 	fr_info_t *fin;
13907c478bd9Sstevel@tonic-gate 	nat_t *nat;
13917c478bd9Sstevel@tonic-gate 	rpc_msg_t *rm;
13927c478bd9Sstevel@tonic-gate 	mb_t *m;
13937c478bd9Sstevel@tonic-gate 	u_int off;
13947c478bd9Sstevel@tonic-gate {
13957c478bd9Sstevel@tonic-gate 	u_int len, xlen, pos, bogo;
13967c478bd9Sstevel@tonic-gate 	rpcb_listp_t *rl;
13977c478bd9Sstevel@tonic-gate 	rpcb_entry_t *re;
13987c478bd9Sstevel@tonic-gate 	rpc_resp_t *rr;
13997c478bd9Sstevel@tonic-gate 	char uaddr[24];
14007c478bd9Sstevel@tonic-gate 	int diff, cnt;
14017c478bd9Sstevel@tonic-gate 	char *i, *p;
14027c478bd9Sstevel@tonic-gate 
14037c478bd9Sstevel@tonic-gate 	diff = 0;
14047c478bd9Sstevel@tonic-gate 	rr = &rm->rm_resp;
14057c478bd9Sstevel@tonic-gate 	rl = &rr->rr_v4;
14067c478bd9Sstevel@tonic-gate 
14077c478bd9Sstevel@tonic-gate 	i = (char *)&nat->nat_outip.s_addr;
14087c478bd9Sstevel@tonic-gate 
14097c478bd9Sstevel@tonic-gate 	/* Determine mbuf offset to write to. */
14107c478bd9Sstevel@tonic-gate 	re = &rl->rl_entries[0];
14117c478bd9Sstevel@tonic-gate 	pos = (char *)re->re_maddr.xu_xslen - rm->rm_msgbuf;
14127c478bd9Sstevel@tonic-gate 	off += pos;
14137c478bd9Sstevel@tonic-gate 
14147c478bd9Sstevel@tonic-gate 	for (cnt = 0; cnt < rl->rl_cnt; cnt++) {
14157c478bd9Sstevel@tonic-gate 		re = &rl->rl_entries[cnt];
14167c478bd9Sstevel@tonic-gate 		p = (char *)&re->re_maddr.xu_port;
14177c478bd9Sstevel@tonic-gate 
14187c478bd9Sstevel@tonic-gate 		/* Form new string. */
14197c478bd9Sstevel@tonic-gate 		bzero(uaddr, sizeof(uaddr)); /* Just in case we need
14207c478bd9Sstevel@tonic-gate 						padding. */
1421ab25eeb5Syz #if defined(SNPRINTF) && defined(_KERNEL)
1422ab25eeb5Syz 		(void) SNPRINTF(uaddr, sizeof(uaddr),
1423ab25eeb5Syz #else
1424ab25eeb5Syz 		(void) sprintf(uaddr,
1425ab25eeb5Syz #endif
1426ab25eeb5Syz 			       "%u.%u.%u.%u.%u.%u", i[0] & 0xff,
1427ab25eeb5Syz 			       i[1] & 0xff, i[2] & 0xff, i[3] & 0xff,
1428ab25eeb5Syz 			       p[0] & 0xff, p[1] & 0xff);
14297c478bd9Sstevel@tonic-gate 		len = strlen(uaddr);
14307c478bd9Sstevel@tonic-gate 		xlen = XDRALIGN(len);
14317c478bd9Sstevel@tonic-gate 
14327c478bd9Sstevel@tonic-gate 		/* Write new string length. */
14337c478bd9Sstevel@tonic-gate 		bogo = htonl(len);
14347c478bd9Sstevel@tonic-gate 		COPYBACK(m, off, 4, (caddr_t)&bogo);
14357c478bd9Sstevel@tonic-gate 		off += 4;
14367c478bd9Sstevel@tonic-gate 
14377c478bd9Sstevel@tonic-gate 		/* Write new string. */
14387c478bd9Sstevel@tonic-gate 		COPYBACK(m, off, xlen, uaddr);
14397c478bd9Sstevel@tonic-gate 		off += xlen;
14407c478bd9Sstevel@tonic-gate 
14417c478bd9Sstevel@tonic-gate 		/* Record any change in length. */
14427c478bd9Sstevel@tonic-gate 		diff += xlen - XDRALIGN(B(re->re_maddr.xu_xslen));
14437c478bd9Sstevel@tonic-gate 
14447c478bd9Sstevel@tonic-gate 		/* If the length changed, copy back the rest of this entry. */
14457c478bd9Sstevel@tonic-gate 		len = ((char *)re->re_more + 4) -
14467c478bd9Sstevel@tonic-gate 		       (char *)re->re_netid.xp_xslen;
14477c478bd9Sstevel@tonic-gate 		if (diff != 0) {
14487c478bd9Sstevel@tonic-gate 			COPYBACK(m, off, len, (caddr_t)re->re_netid.xp_xslen);
14497c478bd9Sstevel@tonic-gate 		}
14507c478bd9Sstevel@tonic-gate 		off += len;
14517c478bd9Sstevel@tonic-gate 	}
14527c478bd9Sstevel@tonic-gate 
14537c478bd9Sstevel@tonic-gate 	/*
14547c478bd9Sstevel@tonic-gate 	 * If our new string has a different length, make necessary
14557c478bd9Sstevel@tonic-gate 	 * adjustments.
14567c478bd9Sstevel@tonic-gate 	 */
14577c478bd9Sstevel@tonic-gate 	if (diff != 0)
14587c478bd9Sstevel@tonic-gate 		ippr_rpcb_fixlen(fin, diff);
14597c478bd9Sstevel@tonic-gate 
14607c478bd9Sstevel@tonic-gate 	return(diff);
14617c478bd9Sstevel@tonic-gate }
14627c478bd9Sstevel@tonic-gate 
14637c478bd9Sstevel@tonic-gate 
14647c478bd9Sstevel@tonic-gate /* --------------------------------------------------------------------	*/
14657c478bd9Sstevel@tonic-gate /* Function:    ippr_rpcb_fixlen                                        */
14667c478bd9Sstevel@tonic-gate /* Returns:     (void)                                                  */
14677c478bd9Sstevel@tonic-gate /* Parameters:  fin(I)  - pointer to packet information                 */
14687c478bd9Sstevel@tonic-gate /*              len(I)  - change in packet length                       */
14697c478bd9Sstevel@tonic-gate /*                                                                      */
14707c478bd9Sstevel@tonic-gate /* Adjust various packet related lengths held in structure and packet   */
14717c478bd9Sstevel@tonic-gate /* header fields.                                                       */
14727c478bd9Sstevel@tonic-gate /* --------------------------------------------------------------------	*/
14737c478bd9Sstevel@tonic-gate static void
ippr_rpcb_fixlen(fin,len)14747c478bd9Sstevel@tonic-gate ippr_rpcb_fixlen(fin, len)
14757c478bd9Sstevel@tonic-gate         fr_info_t *fin;
14767c478bd9Sstevel@tonic-gate         int len;
14777c478bd9Sstevel@tonic-gate {
14787c478bd9Sstevel@tonic-gate         udphdr_t *udp;
14797c478bd9Sstevel@tonic-gate 
14807c478bd9Sstevel@tonic-gate         udp = fin->fin_dp;
14817c478bd9Sstevel@tonic-gate         udp->uh_ulen = htons(ntohs(udp->uh_ulen) + len);
14827c478bd9Sstevel@tonic-gate         fin->fin_ip->ip_len += len;
14837c478bd9Sstevel@tonic-gate         fin->fin_dlen += len;
14847c478bd9Sstevel@tonic-gate         fin->fin_plen += len;
14857c478bd9Sstevel@tonic-gate }
14867c478bd9Sstevel@tonic-gate 
14877c478bd9Sstevel@tonic-gate #undef B
1488