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