The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/netinet/ip_rpcb_pxy.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*      $NetBSD: ip_rpcb_pxy.c,v 1.1.1.1.2.1 2004/08/13 03:56:01 jmc Exp $      */
    2 
    3 /*
    4  * Copyright (C) 2002-2003 by Ryan Beasley <ryanb@goddamnbastard.org>
    5  *
    6  * See the IPFILTER.LICENCE file for details on licencing.
    7  */
    8 /*
    9  * Overview:
   10  *   This is an in-kernel application proxy for Sun's RPCBIND (nee portmap)
   11  *   protocol as defined in RFC1833.  It is far from complete, mostly
   12  *   lacking in less-likely corner cases, but it's definitely functional.
   13  *
   14  *   Invocation:
   15  *     rdr <int> <e_ip>/32 port <e_p> -> <i_ip> port <i_p> udp proxy rpcbu
   16  *
   17  *   If the host running IP Filter is the same as the RPC server, it's
   18  *   perfectly legal for both the internal and external addresses and ports
   19  *   to match.
   20  *
   21  *   When triggered by appropriate IP NAT rules, this proxy works by
   22  *   examining data contained in received packets.  Requests and replies are
   23  *   modified, NAT and state table entries created, etc., as necessary.
   24  */
   25 /*
   26  * TODO / NOTES
   27  *
   28  *   o Must implement locking to protect proxy session data.
   29  *   o Fragmentation isn't supported.
   30  *   o Only supports UDP.
   31  *   o Doesn't support multiple RPC records in a single request.
   32  *   o Errors should be more fine-grained.  (e.g., malloc failure vs.
   33  *     illegal RPCB request / reply)
   34  *   o Even with the limit on the total amount of recorded transactions,
   35  *     should there be a timeout on transaction removal?
   36  *   o There is a potential collision between cloning, wildcard NAT and
   37  *     state entries.  There should be an appr_getport routine for
   38  *     to avoid this.
   39  *   o The enclosed hack of STREAMS support is pretty sick and most likely
   40  *     broken.
   41  *
   42  *      Id: ip_rpcb_pxy.c,v 2.25.2.1 2004/05/04 03:47:49 darrenr Exp
   43  */
   44 
   45 #define IPF_RPCB_PROXY
   46 
   47 /*
   48  * Function prototypes
   49  */
   50 int     ippr_rpcb_init __P((void));
   51 void    ippr_rpcb_fini __P((void));
   52 int     ippr_rpcb_new __P((fr_info_t *, ap_session_t *, nat_t *));
   53 void    ippr_rpcb_del __P((ap_session_t *));
   54 int     ippr_rpcb_in __P((fr_info_t *, ap_session_t *, nat_t *));
   55 int     ippr_rpcb_out __P((fr_info_t *, ap_session_t *, nat_t *));
   56 
   57 static void     ippr_rpcb_flush __P((rpcb_session_t *));
   58 static int      ippr_rpcb_decodereq __P((fr_info_t *, nat_t *,
   59         rpcb_session_t *, rpc_msg_t *));
   60 static int      ippr_rpcb_skipauth __P((rpc_msg_t *, xdr_auth_t *, u_32_t **));
   61 static int      ippr_rpcb_insert __P((rpcb_session_t *, rpcb_xact_t *));
   62 static int      ippr_rpcb_xdrrpcb __P((rpc_msg_t *, u_32_t *, rpcb_args_t *));
   63 static int      ippr_rpcb_getuaddr __P((rpc_msg_t *, xdr_uaddr_t *,
   64         u_32_t **));
   65 static u_int    ippr_rpcb_atoi __P((char *));
   66 static int      ippr_rpcb_modreq __P((fr_info_t *, nat_t *, rpc_msg_t *,
   67         mb_t *, u_int));
   68 static int      ippr_rpcb_decoderep __P((fr_info_t *, nat_t *,
   69         rpcb_session_t *, rpc_msg_t *, rpcb_xact_t **));
   70 static rpcb_xact_t *    ippr_rpcb_lookup __P((rpcb_session_t *, u_32_t));
   71 static void     ippr_rpcb_deref __P((rpcb_session_t *, rpcb_xact_t *));
   72 static int      ippr_rpcb_getproto __P((rpc_msg_t *, xdr_proto_t *,
   73         u_32_t **));
   74 static int      ippr_rpcb_getnat __P((fr_info_t *, nat_t *, u_int, u_int));
   75 static int      ippr_rpcb_modv3 __P((fr_info_t *, nat_t *, rpc_msg_t *,
   76         mb_t *, u_int));
   77 static int      ippr_rpcb_modv4 __P((fr_info_t *, nat_t *, rpc_msg_t *,
   78         mb_t *, u_int));
   79 static void     ippr_rpcb_fixlen __P((fr_info_t *, int));
   80 
   81 /*
   82  * Global variables
   83  */
   84 static  frentry_t       rpcbfr; /* Skeleton rule for reference by entities
   85                                    this proxy creates. */
   86 static  int     rpcbcnt;        /* Upper bound of allocated RPCB sessions. */
   87                                 /* XXX rpcbcnt still requires locking. */
   88 
   89 int     rpcb_proxy_init = 0;
   90 
   91 
   92 /*
   93  * Since rpc_msg contains only pointers, one should use this macro as a
   94  * handy way to get to the goods.  (In case you're wondering about the name,
   95  * this started as BYTEREF -> BREF -> B.)
   96  */
   97 #define B(r)    (u_32_t)ntohl(*(r))
   98 
   99 /*
  100  * Public subroutines
  101  */
  102 
  103 /* -------------------------------------------------------------------- */
  104 /* Function:    ippr_rpcb_init                                          */
  105 /* Returns:     int - 0 == success                                      */
  106 /* Parameters:  (void)                                                  */
  107 /*                                                                      */
  108 /* Initialize the filter rule entry and session limiter.                */
  109 /* -------------------------------------------------------------------- */
  110 int
  111 ippr_rpcb_init()
  112 {
  113         rpcbcnt = 0;
  114 
  115         bzero((char *)&rpcbfr, sizeof(rpcbfr));
  116         rpcbfr.fr_ref = 1;
  117         rpcbfr.fr_flags = FR_PASS|FR_QUICK|FR_KEEPSTATE;
  118         MUTEX_INIT(&rpcbfr.fr_lock, "ipf Sun RPCB proxy rule lock");
  119         rpcb_proxy_init = 1;
  120 
  121         return(0);
  122 }
  123 
  124 /* -------------------------------------------------------------------- */
  125 /* Function:    ippr_rpcb_fini                                          */
  126 /* Returns:     void                                                    */
  127 /* Parameters:  (void)                                                  */
  128 /*                                                                      */
  129 /* Destroy rpcbfr's mutex to avoid a lock leak.                         */
  130 /* -------------------------------------------------------------------- */
  131 void
  132 ippr_rpcb_fini()
  133 {
  134         if (rpcb_proxy_init == 1) {
  135                 MUTEX_DESTROY(&rpcbfr.fr_lock);
  136                 rpcb_proxy_init = 0;
  137         }
  138 }
  139 
  140 /* -------------------------------------------------------------------- */
  141 /* Function:    ippr_rpcb_new                                           */
  142 /* Returns:     int - -1 == failure, 0 == success                       */
  143 /* Parameters:  fin(I)  - pointer to packet information                 */
  144 /*              aps(I)  - pointer to proxy session structure            */
  145 /*              nat(I)  - pointer to NAT session structure              */
  146 /*                                                                      */
  147 /* Allocate resources for per-session proxy structures.                 */
  148 /* -------------------------------------------------------------------- */
  149 int
  150 ippr_rpcb_new(fin, aps, nat)
  151         fr_info_t *fin;
  152         ap_session_t *aps;
  153         nat_t *nat;
  154 {
  155         rpcb_session_t *rs;
  156 
  157         fin = fin;      /* LINT */
  158         nat = nat;      /* LINT */
  159 
  160         KMALLOC(rs, rpcb_session_t *);
  161         if (rs == NULL)
  162                 return(-1);
  163 
  164         bzero((char *)rs, sizeof(*rs));
  165         MUTEX_INIT(&rs->rs_rxlock, "ipf Sun RPCB proxy session lock");
  166 
  167         aps->aps_data = rs;
  168 
  169         return(0);
  170 }
  171 
  172 /* -------------------------------------------------------------------- */
  173 /* Function:    ippr_rpcb_del                                           */
  174 /* Returns:     void                                                    */
  175 /* Parameters:  aps(I)  - pointer to proxy session structure            */
  176 /*                                                                      */
  177 /* Free up a session's list of RPCB requests.                           */
  178 /* -------------------------------------------------------------------- */
  179 void
  180 ippr_rpcb_del(aps)
  181         ap_session_t *aps;
  182 {
  183         rpcb_session_t *rs;
  184         rs = (rpcb_session_t *)aps->aps_data;
  185 
  186         MUTEX_ENTER(&rs->rs_rxlock);
  187         ippr_rpcb_flush(rs);
  188         MUTEX_EXIT(&rs->rs_rxlock);
  189         MUTEX_DESTROY(&rs->rs_rxlock);
  190 }
  191 
  192 /* -------------------------------------------------------------------- */
  193 /* Function:    ippr_rpcb_in                                            */
  194 /* Returns:     int - APR_ERR(1) == drop the packet,                    */
  195 /*                    APR_ERR(2) == kill the proxy session,             */
  196 /*                    else change in packet length (in bytes)           */
  197 /* Parameters:  fin(I)  - pointer to packet information                 */
  198 /*              ip(I)   - pointer to packet header                      */
  199 /*              aps(I)  - pointer to proxy session structure            */
  200 /*              nat(I)  - pointer to NAT session structure              */
  201 /*                                                                      */
  202 /* Given a presumed RPCB request, perform some minor tests and pass off */
  203 /* for decoding.  Also pass packet off for a rewrite if necessary.      */
  204 /* -------------------------------------------------------------------- */
  205 int
  206 ippr_rpcb_in(fin, aps, nat)
  207         fr_info_t *fin;
  208         ap_session_t *aps;
  209         nat_t *nat;
  210 {
  211         rpc_msg_t rpcmsg, *rm;
  212         rpcb_session_t *rs;
  213         u_int off, dlen;
  214         mb_t *m;
  215         int rv;
  216 
  217         /* Disallow fragmented or illegally short packets. */
  218         if ((fin->fin_flx & (FI_FRAG|FI_SHORT)) != 0)
  219                 return(APR_ERR(1));
  220 
  221         /* Perform basic variable initialization. */
  222         rs = (rpcb_session_t *)aps->aps_data;
  223 
  224         m = fin->fin_m;
  225         off = (char *)fin->fin_dp - (char *)fin->fin_ip;
  226         off += sizeof(udphdr_t) + fin->fin_ipoff;
  227         dlen = fin->fin_dlen - sizeof(udphdr_t);
  228 
  229         /* Disallow packets outside legal range for supported requests. */
  230         if ((dlen < RPCB_REQMIN) || (dlen > RPCB_REQMAX))
  231                 return(APR_ERR(1));
  232 
  233         /* Copy packet over to convenience buffer. */
  234         rm = &rpcmsg;
  235         bzero((char *)rm, sizeof(*rm));
  236         COPYDATA(m, off, dlen, (caddr_t)&rm->rm_msgbuf);
  237         rm->rm_buflen = dlen;
  238 
  239         /* Send off to decode request. */
  240         rv = ippr_rpcb_decodereq(fin, nat, rs, rm);
  241 
  242         switch(rv)
  243         {
  244         case -1:
  245                 return(APR_ERR(1));
  246                 /*NOTREACHED*/
  247                 break;
  248         case 0:
  249                 break;
  250         case 1:
  251                 rv = ippr_rpcb_modreq(fin, nat, rm, m, off);
  252                 break;
  253         default:
  254                 /*CONSTANTCONDITION*/
  255                 IPF_PANIC(1, ("illegal rv %d (ippr_rpcb_req)", rv));
  256         }
  257 
  258         return(rv);
  259 }
  260 
  261 /* -------------------------------------------------------------------- */
  262 /* Function:    ippr_rpcb_out                                           */
  263 /* Returns:     int - APR_ERR(1) == drop the packet,                    */
  264 /*                    APR_ERR(2) == kill the proxy session,             */
  265 /*                    else change in packet length (in bytes)           */
  266 /* Parameters:  fin(I)  - pointer to packet information                 */
  267 /*              ip(I)   - pointer to packet header                      */
  268 /*              aps(I)  - pointer to proxy session structure            */
  269 /*              nat(I)  - pointer to NAT session structure              */
  270 /*                                                                      */
  271 /* Given a presumed RPCB reply, perform some minor tests and pass off   */
  272 /* for decoding.  If the message indicates a successful request with    */
  273 /* valid addressing information, create NAT and state structures to     */
  274 /* allow direct communication between RPC client and server.            */
  275 /* -------------------------------------------------------------------- */
  276 int
  277 ippr_rpcb_out(fin, aps, nat)
  278         fr_info_t *fin;
  279         ap_session_t *aps;
  280         nat_t *nat;
  281 {
  282         rpc_msg_t rpcmsg, *rm;
  283         rpcb_session_t *rs;
  284         rpcb_xact_t *rx;
  285         u_int off, dlen;
  286         int rv, diff;
  287         mb_t *m;
  288 
  289         /* Disallow fragmented or illegally short packets. */
  290         if ((fin->fin_flx & (FI_FRAG|FI_SHORT)) != 0)
  291                 return(APR_ERR(1));
  292 
  293         /* Perform basic variable initialization. */
  294         rs = (rpcb_session_t *)aps->aps_data;
  295 
  296         m = fin->fin_m;
  297         off = (char *)fin->fin_dp - (char *)fin->fin_ip;
  298         off += sizeof(udphdr_t) + fin->fin_ipoff;
  299         dlen = fin->fin_dlen - sizeof(udphdr_t);
  300         diff = 0;
  301 
  302         /* Disallow packets outside legal range for supported requests. */
  303         if ((dlen < RPCB_REPMIN) || (dlen > RPCB_REPMAX))
  304                 return(APR_ERR(1));
  305 
  306         /* Copy packet over to convenience buffer. */
  307         rm = &rpcmsg;
  308         bzero((char *)rm, sizeof(*rm));
  309         COPYDATA(m, off, dlen, (caddr_t)&rm->rm_msgbuf);
  310         rm->rm_buflen = dlen;
  311 
  312         /* Send off to decode reply. */
  313         rv = ippr_rpcb_decoderep(fin, nat, rs, rm, &rx);
  314 
  315         switch(rv)
  316         {
  317         case -1: /* Bad packet */
  318                 if (rx != NULL) {
  319                         MUTEX_ENTER(&rs->rs_rxlock);
  320                         ippr_rpcb_deref(rs, rx);
  321                         MUTEX_EXIT(&rs->rs_rxlock);
  322                 }
  323                 return(APR_ERR(1));
  324                 /*NOTREACHED*/
  325                 break;
  326         case  0: /* Negative reply / request rejected */
  327                 break;
  328         case  1: /* Positive reply */
  329                 /*
  330                  * With the IP address embedded in a GETADDR(LIST) reply,
  331                  * we'll need to rewrite the packet in the very possible
  332                  * event that the internal & external addresses aren't the
  333                  * same.  (i.e., this box is either a router or rpcbind
  334                  * only listens on loopback.)
  335                  */
  336                 if (nat->nat_inip.s_addr != nat->nat_outip.s_addr) {
  337                         if (rx->rx_type == RPCB_RES_STRING)
  338                                 diff = ippr_rpcb_modv3(fin, nat, rm, m, off);
  339                         else if (rx->rx_type == RPCB_RES_LIST)
  340                                 diff = ippr_rpcb_modv4(fin, nat, rm, m, off);
  341                 }
  342                 break;
  343         default:
  344                 /*CONSTANTCONDITION*/
  345                 IPF_PANIC(1, ("illegal rv %d (ippr_rpcb_decoderep)", rv));
  346         }
  347 
  348         if (rx != NULL) {
  349                 MUTEX_ENTER(&rs->rs_rxlock);
  350                 /* XXX Gross hack - I'm overloading the reference
  351                  * counter to deal with both threads and retransmitted
  352                  * requests.  One deref signals that this thread is
  353                  * finished with rx, and the other signals that we've
  354                  * processed its reply.
  355                  */
  356                 ippr_rpcb_deref(rs, rx);
  357                 ippr_rpcb_deref(rs, rx);
  358                 MUTEX_EXIT(&rs->rs_rxlock);
  359         }
  360 
  361         return(diff);
  362 }
  363 
  364 /*
  365  * Private support subroutines
  366  */
  367 
  368 /* -------------------------------------------------------------------- */
  369 /* Function:    ippr_rpcb_flush                                         */
  370 /* Returns:     void                                                    */
  371 /* Parameters:  rs(I)   - pointer to RPCB session structure             */
  372 /*                                                                      */
  373 /* Simply flushes the list of outstanding transactions, if any.         */
  374 /* -------------------------------------------------------------------- */
  375 static void
  376 ippr_rpcb_flush(rs)
  377         rpcb_session_t *rs;
  378 {
  379         rpcb_xact_t *r1, *r2;
  380 
  381         r1 = rs->rs_rxlist;
  382         if (r1 == NULL)
  383                 return;
  384 
  385         while (r1 != NULL) {
  386                 r2 = r1;
  387                 r1 = r1->rx_next;
  388                 KFREE(r2);
  389         }
  390 }
  391 
  392 /* -------------------------------------------------------------------- */
  393 /* Function:    ippr_rpcb_decodereq                                     */
  394 /* Returns:     int - -1 == bad request or critical failure,            */
  395 /*                     0 == request successfully decoded,               */
  396 /*                     1 == request successfully decoded; requires      */
  397 /*                          address rewrite/modification                */
  398 /* Parameters:  fin(I)  - pointer to packet information                 */
  399 /*              nat(I)  - pointer to NAT session structure              */
  400 /*              rs(I)   - pointer to RPCB session structure             */
  401 /*              rm(I)   - pointer to RPC message structure              */
  402 /*                                                                      */
  403 /* Take a presumed RPCB request, decode it, and store the results in    */
  404 /* the transaction list.  If the internal target address needs to be    */
  405 /* modified, store its location in ptr.                                 */
  406 /* WARNING:  It's the responsibility of the caller to make sure there   */
  407 /* is enough room in rs_buf for the basic RPC message "preamble".       */
  408 /* -------------------------------------------------------------------- */
  409 static int
  410 ippr_rpcb_decodereq(fin, nat, rs, rm)
  411         fr_info_t *fin;
  412         nat_t *nat;
  413         rpcb_session_t *rs;
  414         rpc_msg_t *rm;
  415 {
  416         rpcb_args_t *ra;
  417         u_32_t xdr, *p;
  418         rpc_call_t *rc;
  419         rpcb_xact_t rx;
  420         int mod;
  421 
  422         p = (u_32_t *)rm->rm_msgbuf;
  423         mod = 0;
  424 
  425         bzero((char *)&rx, sizeof(rx));
  426         rc = &rm->rm_call;
  427 
  428         rm->rm_xid = p;
  429         rx.rx_xid = B(p++);     /* Record this message's XID. */
  430 
  431         /* Parse out and test the RPC header. */
  432         if ((B(p++) != RPCB_CALL) ||
  433             (B(p++) != RPCB_MSG_VERSION) ||
  434             (B(p++) != RPCB_PROG))
  435                 return(-1);
  436 
  437         /* Record the RPCB version and procedure. */
  438         rc->rc_vers = p++;
  439         rc->rc_proc = p++;
  440 
  441         /* Bypass RPC authentication stuff. */
  442         if (ippr_rpcb_skipauth(rm, &rc->rc_authcred, &p) != 0)
  443                 return(-1);
  444         if (ippr_rpcb_skipauth(rm, &rc->rc_authverf, &p) != 0)
  445                 return(-1);
  446 
  447         /* Compare RPCB version and procedure numbers. */
  448         switch(B(rc->rc_vers))
  449         {
  450         case 2:
  451                 /* This proxy only supports PMAP_GETPORT. */
  452                 if (B(rc->rc_proc) != RPCB_GETPORT)
  453                         return(-1);
  454 
  455                 /* Portmap requests contain four 4 byte parameters. */
  456                 if (RPCB_BUF_EQ(rm, p, 16) == 0)
  457                         return(-1);
  458 
  459                 p += 2; /* Skip requested program and version numbers. */
  460 
  461                 /* Sanity check the requested protocol. */
  462                 xdr = B(p);
  463                 if (!(xdr == IPPROTO_UDP || xdr == IPPROTO_TCP))
  464                         return(-1);
  465 
  466                 rx.rx_type = RPCB_RES_PMAP;
  467                 rx.rx_proto = xdr;
  468                 break;
  469         case 3:
  470         case 4:
  471                 /* GETADDRLIST is exclusive to v4; GETADDR for v3 & v4 */
  472                 switch(B(rc->rc_proc))
  473                 {
  474                 case RPCB_GETADDR:
  475                         rx.rx_type = RPCB_RES_STRING;
  476                         rx.rx_proto = (u_int)fin->fin_p;
  477                         break;
  478                 case RPCB_GETADDRLIST:
  479                         if (B(rc->rc_vers) != 4)
  480                                 return(-1);
  481                         rx.rx_type = RPCB_RES_LIST;
  482                         break;
  483                 default:
  484                         return(-1);
  485                 }
  486 
  487                 ra = &rc->rc_rpcbargs;
  488 
  489                 /* Decode the 'struct rpcb' request. */
  490                 if (ippr_rpcb_xdrrpcb(rm, p, ra) != 0)
  491                         return(-1);
  492 
  493                 /* Are the target address & port valid? */
  494                 if ((ra->ra_maddr.xu_ip != nat->nat_outip.s_addr) ||
  495                     (ra->ra_maddr.xu_port != nat->nat_outport))
  496                         return(-1);
  497 
  498                 /* Do we need to rewrite this packet? */
  499                 if ((nat->nat_outip.s_addr != nat->nat_inip.s_addr) ||
  500                     (nat->nat_outport != nat->nat_inport))
  501                         mod = 1;
  502                 break;
  503         default:
  504                 return(-1);
  505         }
  506 
  507         MUTEX_ENTER(&rs->rs_rxlock);
  508         if (ippr_rpcb_insert(rs, &rx) != 0) {
  509                 MUTEX_EXIT(&rs->rs_rxlock);
  510                 return(-1);
  511         }
  512         MUTEX_EXIT(&rs->rs_rxlock);
  513 
  514         return(mod);
  515 }
  516 
  517 /* -------------------------------------------------------------------- */
  518 /* Function:    ippr_rpcb_skipauth                                      */
  519 /* Returns:     int -- -1 == illegal auth parameters (lengths)          */
  520 /*                      0 == valid parameters, pointer advanced         */
  521 /* Parameters:  rm(I)   - pointer to RPC message structure              */
  522 /*              auth(I) - pointer to RPC auth structure                 */
  523 /*              buf(IO) - pointer to location within convenience buffer */
  524 /*                                                                      */
  525 /* Record auth data length & location of auth data, then advance past   */
  526 /* it.                                                                  */
  527 /* -------------------------------------------------------------------- */
  528 static int
  529 ippr_rpcb_skipauth(rm, auth, buf)
  530         rpc_msg_t *rm;
  531         xdr_auth_t *auth;
  532         u_32_t **buf;
  533 {
  534         u_32_t *p, xdr;
  535 
  536         p = *buf;
  537 
  538         /* Make sure we have enough space for expected fixed auth parms. */
  539         if (RPCB_BUF_GEQ(rm, p, 8) == 0)
  540                 return(-1);
  541 
  542         p++; /* We don't care about auth_flavor. */
  543 
  544         auth->xa_string.xs_len = p;
  545         xdr = B(p++);           /* Length of auth_data */
  546 
  547         /* Test for absurdity / illegality of auth_data length. */
  548         if ((XDRALIGN(xdr) < xdr) || (RPCB_BUF_GEQ(rm, p, XDRALIGN(xdr)) == 0))
  549                 return(-1);
  550 
  551         auth->xa_string.xs_str = (char *)p;
  552 
  553         p += XDRALIGN(xdr);     /* Advance our location. */
  554 
  555         *buf = (u_32_t *)p;
  556 
  557         return(0);
  558 }
  559 
  560 /* -------------------------------------------------------------------- */
  561 /* Function:    ippr_rpcb_insert                                        */
  562 /* Returns:     int -- -1 == list insertion failed,                     */
  563 /*                      0 == item successfully added                    */
  564 /* Parameters:  rs(I)   - pointer to RPCB session structure             */
  565 /*              rx(I)   - pointer to RPCB transaction structure         */
  566 /* -------------------------------------------------------------------- */
  567 static int
  568 ippr_rpcb_insert(rs, rx)
  569         rpcb_session_t *rs;
  570         rpcb_xact_t *rx;
  571 {
  572         rpcb_xact_t *rxp;
  573 
  574         rxp = ippr_rpcb_lookup(rs, rx->rx_xid);
  575         if (rxp != NULL) {
  576                 ++rxp->rx_ref;
  577                 return(0);
  578         }
  579 
  580         if (rpcbcnt == RPCB_MAXREQS)
  581                 return(-1);
  582 
  583         KMALLOC(rxp, rpcb_xact_t *);
  584         if (rxp == NULL)
  585                 return(-1);
  586 
  587         bcopy((char *)rx, (char *)rxp, sizeof(*rx));
  588 
  589         if (rs->rs_rxlist != NULL)
  590                 rs->rs_rxlist->rx_pnext = &rxp->rx_next;
  591 
  592         rxp->rx_pnext = &rs->rs_rxlist;
  593         rxp->rx_next = rs->rs_rxlist;
  594         rs->rs_rxlist = rxp;
  595 
  596         rxp->rx_ref = 1;
  597 
  598         ++rpcbcnt;
  599 
  600         return(0);
  601 }
  602 
  603 /* -------------------------------------------------------------------- */
  604 /* Function:    ippr_rpcb_xdrrpcb                                       */
  605 /* Returns:     int -- -1 == failure to properly decode the request     */
  606 /*                      0 == rpcb successfully decoded                  */
  607 /* Parameters:  rs(I)   - pointer to RPCB session structure             */
  608 /*              p(I)    - pointer to location within session buffer     */
  609 /*              rpcb(O) - pointer to rpcb (xdr type) structure          */
  610 /*                                                                      */
  611 /* Decode a XDR encoded rpcb structure and record its contents in rpcb  */
  612 /* within only the context of TCP/UDP over IP networks.                 */
  613 /* -------------------------------------------------------------------- */
  614 static int
  615 ippr_rpcb_xdrrpcb(rm, p, ra)
  616         rpc_msg_t *rm;
  617         u_32_t *p;
  618         rpcb_args_t *ra;
  619 {
  620         if (!RPCB_BUF_GEQ(rm, p, 20))
  621                 return(-1);
  622 
  623         /* Bypass target program & version. */
  624         p += 2;
  625 
  626         /* Decode r_netid.  Must be "tcp" or "udp". */
  627         if (ippr_rpcb_getproto(rm, &ra->ra_netid, &p) != 0)
  628                 return(-1);
  629 
  630         /* Decode r_maddr. */
  631         if (ippr_rpcb_getuaddr(rm, &ra->ra_maddr, &p) != 0)
  632                 return(-1);
  633 
  634         /* Advance to r_owner and make sure it's empty. */
  635         if (!RPCB_BUF_EQ(rm, p, 4) || (B(p) != 0))
  636                 return(-1);
  637 
  638         return(0);
  639 }
  640 
  641 /* -------------------------------------------------------------------- */
  642 /* Function:    ippr_rpcb_getuaddr                                      */
  643 /* Returns:     int -- -1 == illegal string,                            */
  644 /*                      0 == string parsed; contents recorded           */
  645 /* Parameters:  rm(I)   - pointer to RPC message structure              */
  646 /*              xu(I)   - pointer to universal address structure        */
  647 /*              p(IO)   - pointer to location within message buffer     */
  648 /*                                                                      */
  649 /* Decode the IP address / port at p and record them in xu.             */
  650 /* -------------------------------------------------------------------- */
  651 static int
  652 ippr_rpcb_getuaddr(rm, xu, p)
  653         rpc_msg_t *rm;
  654         xdr_uaddr_t *xu;
  655         u_32_t **p;
  656 {
  657         char *c, *i, *b, *pp;
  658         u_int d, dd, l, t;
  659         char uastr[24];
  660 
  661         /* Test for string length. */
  662         if (!RPCB_BUF_GEQ(rm, *p, 4))
  663                 return(-1);
  664 
  665         xu->xu_xslen = (*p)++;
  666         xu->xu_xsstr = (char *)*p;
  667 
  668         /* Length check */
  669         l = B(xu->xu_xslen);
  670         if (l < 11 || l > 23 || !RPCB_BUF_GEQ(rm, *p, XDRALIGN(l)))
  671                 return(-1);
  672 
  673         /* Advance p */
  674         *(char **)p += XDRALIGN(l);
  675 
  676         /* Copy string to local buffer & terminate C style */
  677         bcopy(xu->xu_xsstr, uastr, l);
  678         uastr[l] = '\0';
  679 
  680         i = (char *)&xu->xu_ip;
  681         pp = (char *)&xu->xu_port;
  682 
  683         /*
  684          * Expected format: a.b.c.d.e.f where [a-d] correspond to bytes of
  685          * an IP address and [ef] are the bytes of a L4 port.
  686          */
  687         if (!(isdigit(uastr[0]) && isdigit(uastr[l-1])))
  688                 return(-1);
  689         b = uastr;
  690         for (c = &uastr[1], d = 0, dd = 0; c < &uastr[l-1]; c++) {
  691                 if (isdigit(*c)) {
  692                         dd = 0;
  693                         continue;
  694                 }
  695                 if (*c == '.') {
  696                         if (dd != 0)
  697                                 return(-1);
  698 
  699                         /* Check for ASCII byte. */
  700                         *c = '\0';
  701                         t = ippr_rpcb_atoi(b);
  702                         if (t > 255)
  703                                 return(-1);
  704 
  705                         /* Aim b at beginning of the next byte. */
  706                         b = c + 1;
  707 
  708                         /* Switch off IP addr vs port parsing. */
  709                         if (d < 4)
  710                                 i[d++] = t & 0xff;
  711                         else
  712                                 pp[d++ - 4] = t & 0xff;
  713 
  714                         dd = 1;
  715                         continue;
  716                 }
  717                 return(-1);
  718         }
  719         if (d != 5) /* String must contain exactly 5 periods. */
  720                 return(-1);
  721 
  722         /* Handle the last byte (port low byte) */
  723         t = ippr_rpcb_atoi(b);
  724         if (t > 255)
  725                 return(-1);
  726         pp[d - 4] = t & 0xff;
  727 
  728         return(0);
  729 }
  730 
  731 /* -------------------------------------------------------------------- */
  732 /* Function:    ippr_rpcb_atoi (XXX should be generic for all proxies)  */
  733 /* Returns:     int -- integer representation of supplied string        */
  734 /* Parameters:  ptr(I)  - input string                                  */
  735 /*                                                                      */
  736 /* Simple version of atoi(3) ripped from ip_rcmd_pxy.c.                 */
  737 /* -------------------------------------------------------------------- */
  738 static u_int
  739 ippr_rpcb_atoi(ptr)
  740         char *ptr;
  741 {
  742         register char *s = ptr, c;
  743         register u_int i = 0;
  744 
  745         while (((c = *s++) != '\0') && isdigit(c)) {
  746                 i *= 10;
  747                 i += c - '';
  748         }
  749         return i;
  750 }
  751 
  752 /* -------------------------------------------------------------------- */
  753 /* Function:    ippr_rpcb_modreq                                        */
  754 /* Returns:     int -- change in datagram length                        */
  755 /*                      APR_ERR(2) - critical failure                   */
  756 /* Parameters:  fin(I)  - pointer to packet information                 */
  757 /*              nat(I)  - pointer to NAT session                        */
  758 /*              rm(I)   - pointer to RPC message structure              */
  759 /*              m(I)    - pointer to mbuf chain                         */
  760 /*              off(I)  - current offset within mbuf chain              */
  761 /*                                                                      */
  762 /* When external and internal addresses differ, we rewrite the former   */
  763 /* with the latter.  (This is exclusive to protocol versions 3 & 4).    */
  764 /* -------------------------------------------------------------------- */
  765 static int
  766 ippr_rpcb_modreq(fin, nat, rm, m, off)
  767         fr_info_t *fin;
  768         nat_t *nat;
  769         rpc_msg_t *rm;
  770         mb_t *m;
  771         u_int off;
  772 {
  773         u_int len, xlen, pos, bogo;
  774         rpcb_args_t *ra;
  775         char uaddr[24];
  776         udphdr_t *udp;
  777         char *i, *p;
  778         int diff;
  779 
  780         ra = &rm->rm_call.rc_rpcbargs;
  781         i = (char *)&nat->nat_inip.s_addr;
  782         p = (char *)&nat->nat_inport;
  783 
  784         /* Form new string. */
  785         bzero(uaddr, sizeof(uaddr)); /* Just in case we need padding. */
  786 #if defined(SNPRINTF) && defined(_KERNEL)
  787         SNPRINTF(uaddr, sizeof(uaddr),
  788 #else
  789         (void) sprintf(uaddr,
  790 #endif
  791                        "%u.%u.%u.%u.%u.%u", i[0] & 0xff, i[1] & 0xff,
  792                        i[2] & 0xff, i[3] & 0xff, p[0] & 0xff, p[1] & 0xff);
  793         len = strlen(uaddr);
  794         xlen = XDRALIGN(len);
  795 
  796         /* Determine mbuf offset to start writing to. */
  797         pos = (char *)ra->ra_maddr.xu_xslen - rm->rm_msgbuf;
  798         off += pos;
  799 
  800         /* Write new string length. */
  801         bogo = htonl(len);
  802         COPYBACK(m, off, 4, (caddr_t)&bogo);
  803         off += 4;
  804 
  805         /* Write new string. */
  806         COPYBACK(m, off, xlen, uaddr);
  807         off += xlen;
  808 
  809         /* Write in zero r_owner. */
  810         bogo = 0;
  811         COPYBACK(m, off, 4, (caddr_t)&bogo);
  812 
  813         /* Determine difference in data lengths. */
  814         diff = xlen - XDRALIGN(B(ra->ra_maddr.xu_xslen));
  815 
  816         /*
  817          * If our new string has a different length, make necessary
  818          * adjustments.
  819          */
  820         if (diff != 0) {
  821                 udp = fin->fin_dp;
  822                 udp->uh_ulen = htons(ntohs(udp->uh_ulen) + diff);
  823                 fin->fin_ip->ip_len += diff;
  824                 fin->fin_dlen += diff;
  825                 fin->fin_plen += diff;
  826                 /* XXX Storage lengths. */
  827         }
  828 
  829         return(diff);
  830 }
  831 
  832 /* -------------------------------------------------------------------- */
  833 /* Function:    ippr_rpcb_decoderep                                     */
  834 /* Returns:     int - -1 == bad request or critical failure,            */
  835 /*                     0 == valid, negative reply                       */
  836 /*                     1 == vaddlid, positive reply; needs no changes   */
  837 /* Parameters:  fin(I)  - pointer to packet information                 */
  838 /*              nat(I)  - pointer to NAT session structure              */
  839 /*              rs(I)   - pointer to RPCB session structure             */
  840 /*              rm(I)   - pointer to RPC message structure              */
  841 /*              rxp(O)  - pointer to RPCB transaction structure         */
  842 /*                                                                      */
  843 /* Take a presumed RPCB reply, extract the XID, search for the original */
  844 /* request information, and determine whether the request was accepted  */
  845 /* or rejected.  With a valid accepted reply, go ahead and create NAT   */
  846 /* and state entries, and finish up by rewriting the packet as          */
  847 /* required.                                                            */
  848 /*                                                                      */
  849 /* WARNING:  It's the responsibility of the caller to make sure there   */
  850 /* is enough room in rs_buf for the basic RPC message "preamble".       */
  851 /* -------------------------------------------------------------------- */
  852 static int
  853 ippr_rpcb_decoderep(fin, nat, rs, rm, rxp)
  854         fr_info_t *fin;
  855         nat_t *nat;
  856         rpcb_session_t *rs;
  857         rpc_msg_t *rm;
  858         rpcb_xact_t **rxp;
  859 {
  860         rpcb_listp_t *rl;
  861         rpcb_entry_t *re;
  862         rpcb_xact_t *rx;
  863         u_32_t xdr, *p;
  864         rpc_resp_t *rr;
  865         int rv, cnt;
  866 
  867         p = (u_32_t *)rm->rm_msgbuf;
  868 
  869         bzero((char *)&rx, sizeof(rx));
  870         rr = &rm->rm_resp;
  871 
  872         rm->rm_xid = p;
  873         xdr = B(p++);           /* Record this message's XID. */
  874 
  875         /* Lookup XID */
  876         MUTEX_ENTER(&rs->rs_rxlock);
  877         if ((rx = ippr_rpcb_lookup(rs, xdr)) == NULL) {
  878                 MUTEX_EXIT(&rs->rs_rxlock);
  879                 return(-1);
  880         }
  881         ++rx->rx_ref;        /* per thread reference */
  882         MUTEX_EXIT(&rs->rs_rxlock);
  883 
  884         *rxp = rx;
  885 
  886         /* Test call vs reply */
  887         if (B(p++) != RPCB_REPLY)
  888                 return(-1);
  889 
  890         /* Test reply_stat */
  891         switch(B(p++))
  892         {
  893         case RPCB_MSG_DENIED:
  894                 return(0);
  895         case RPCB_MSG_ACCEPTED:
  896                 break;
  897         default:
  898                 return(-1);
  899         }
  900 
  901         /* Bypass RPC authentication stuff. */
  902         if (ippr_rpcb_skipauth(rm, &rr->rr_authverf, &p) != 0)
  903                 return(-1);
  904 
  905         /* Test accept status */
  906         if (!RPCB_BUF_GEQ(rm, p, 4))
  907                 return(-1);
  908         if (B(p++) != 0)
  909                 return(0);
  910 
  911         /* Parse out the expected reply */
  912         switch(rx->rx_type)
  913         {
  914         case RPCB_RES_PMAP:
  915                 /* There must be only one 4 byte argument. */
  916                 if (!RPCB_BUF_EQ(rm, p, 4))
  917                         return(-1);
  918                 
  919                 rr->rr_v2 = p;
  920                 xdr = B(rr->rr_v2);
  921                 
  922                 /* Reply w/ a 0 port indicates service isn't registered */
  923                 if (xdr == 0)
  924                         return(0);
  925                 
  926                 /* Is the value sane? */
  927                 if (xdr > 65535)
  928                         return(-1);
  929 
  930                 /* Create NAT & state table entries. */
  931                 if (ippr_rpcb_getnat(fin, nat, rx->rx_proto, (u_int)xdr) != 0)
  932                         return(-1);
  933                 break;
  934         case RPCB_RES_STRING:
  935                 /* Expecting a XDR string; need 4 bytes for length */
  936                 if (!RPCB_BUF_GEQ(rm, p, 4))
  937                         return(-1);
  938 
  939                 rr->rr_v3.xu_str.xs_len = p++;
  940                 rr->rr_v3.xu_str.xs_str = (char *)p;
  941 
  942                 xdr = B(rr->rr_v3.xu_xslen);
  943 
  944                 /* A null string indicates an unregistered service */
  945                 if ((xdr == 0) && RPCB_BUF_EQ(rm, p, 0))
  946                         return(0);
  947 
  948                 /* Decode the target IP address / port. */
  949                 if (ippr_rpcb_getuaddr(rm, &rr->rr_v3, &p) != 0)
  950                         return(-1);
  951 
  952                 /* Validate the IP address and port contained. */
  953                 if (nat->nat_inip.s_addr != rr->rr_v3.xu_ip)
  954                         return(-1);
  955 
  956                 /* Create NAT & state table entries. */
  957                 if (ippr_rpcb_getnat(fin, nat, rx->rx_proto,
  958                                      (u_int)rr->rr_v3.xu_port) != 0)
  959                         return(-1);
  960                 break;
  961         case RPCB_RES_LIST:
  962                 if (!RPCB_BUF_GEQ(rm, p, 4))
  963                         return(-1);
  964                 /* rpcb_entry_list_ptr */
  965                 switch(B(p))
  966                 {
  967                 case 0:
  968                         return(0);
  969                         /*NOTREACHED*/
  970                         break;
  971                 case 1:
  972                         break;
  973                 default:
  974                         return(-1);
  975                 }
  976                 rl = &rr->rr_v4;
  977                 rl->rl_list = p++;
  978                 cnt = 0;
  979 
  980                 for(;;) {
  981                         re = &rl->rl_entries[rl->rl_cnt];
  982                         if (ippr_rpcb_getuaddr(rm, &re->re_maddr, &p) != 0)
  983                                 return(-1);
  984                         if (ippr_rpcb_getproto(rm, &re->re_netid, &p) != 0)
  985                                 return(-1);
  986                         /* re_semantics & re_pfamily length */
  987                         if (!RPCB_BUF_GEQ(rm, p, 12))
  988                                 return(-1);
  989                         p++; /* Skipping re_semantics. */
  990                         xdr = B(p++);
  991                         if ((xdr != 4) || strncmp((char *)p, "inet", 4))
  992                                 return(-1);
  993                         p++;
  994                         if (ippr_rpcb_getproto(rm, &re->re_proto, &p) != 0)
  995                                 return(-1);
  996                         if (!RPCB_BUF_GEQ(rm, p, 4))
  997                                 return(-1);
  998                         re->re_more = p;
  999                         if (B(re->re_more) > 1) /* 0,1 only legal values */
 1000                                 return(-1);
 1001                         ++rl->rl_cnt;
 1002                         ++cnt;
 1003                         if (B(re->re_more) == 0)
 1004                                 break;
 1005                         /* Replies in  max out at 2; TCP and/or UDP */
 1006                         if (cnt > 2)
 1007                                 return(-1);
 1008                         p++;
 1009                 }
 1010 
 1011                 for(rl->rl_cnt = 0; rl->rl_cnt < cnt; rl->rl_cnt++) {
 1012                         re = &rl->rl_entries[rl->rl_cnt];
 1013                         rv = ippr_rpcb_getnat(fin, nat,
 1014                                               re->re_proto.xp_proto,
 1015                                               (u_int)re->re_maddr.xu_port);
 1016                         if (rv != 0)
 1017                                 return(-1);
 1018                 }
 1019                 break;
 1020         default:
 1021                 /*CONSTANTCONDITION*/
 1022                 IPF_PANIC(1, ("illegal rx_type %d", rx->rx_type));
 1023         }
 1024 
 1025         return(1);
 1026 }
 1027 
 1028 /* -------------------------------------------------------------------- */
 1029 /* Function:    ippr_rpcb_lookup                                        */
 1030 /* Returns:     rpcb_xact_t *   - NULL == no matching record,           */
 1031 /*                                else pointer to relevant entry        */
 1032 /* Parameters:  rs(I)   - pointer to RPCB session                       */
 1033 /*              xid(I)  - XID to look for                               */
 1034 /* -------------------------------------------------------------------- */
 1035 static rpcb_xact_t *
 1036 ippr_rpcb_lookup(rs, xid)
 1037         rpcb_session_t *rs;
 1038         u_32_t xid;
 1039 {
 1040         rpcb_xact_t *rx;
 1041 
 1042         if (rs->rs_rxlist == NULL)
 1043                 return(NULL);
 1044 
 1045         for (rx = rs->rs_rxlist; rx != NULL; rx = rx->rx_next)
 1046                 if (rx->rx_xid == xid)
 1047                         break;
 1048 
 1049         return(rx);
 1050 }
 1051 
 1052 /* -------------------------------------------------------------------- */
 1053 /* Function:    ippr_rpcb_deref                                         */
 1054 /* Returns:     (void)                                                  */
 1055 /* Parameters:  rs(I)   - pointer to RPCB session                       */
 1056 /*              rx(I)   - pointer to RPC transaction struct to remove   */
 1057 /*              force(I) - indicates to delete entry regardless of      */
 1058 /*                         reference count                              */
 1059 /* Locking:     rs->rs_rxlock must be held write only                   */
 1060 /*                                                                      */
 1061 /* Free the RPCB transaction record rx from the chain of entries.       */
 1062 /* -------------------------------------------------------------------- */
 1063 static void
 1064 ippr_rpcb_deref(rs, rx)
 1065         rpcb_session_t *rs;
 1066         rpcb_xact_t *rx;
 1067 {
 1068         rs = rs;        /* LINT */
 1069 
 1070         if (rx == NULL)
 1071                 return;
 1072 
 1073         if (--rx->rx_ref != 0)
 1074                 return;
 1075 
 1076         if (rx->rx_next != NULL)
 1077                 rx->rx_next->rx_pnext = rx->rx_pnext;
 1078 
 1079         *rx->rx_pnext = rx->rx_next;
 1080 
 1081         KFREE(rx);
 1082 
 1083         --rpcbcnt;
 1084 }
 1085 
 1086 /* -------------------------------------------------------------------- */
 1087 /* Function:    ippr_rpcb_getproto                                      */
 1088 /* Returns:     int - -1 == illegal protocol/netid,                     */
 1089 /*                     0 == legal protocol/netid                        */
 1090 /* Parameters:  rm(I)   - pointer to RPC message structure              */
 1091 /*              xp(I)   - pointer to netid structure                    */
 1092 /*              p(IO)   - pointer to location within packet buffer      */
 1093 /*                                                                      */
 1094 /* Decode netid/proto stored at p and record its numeric value.         */
 1095 /* -------------------------------------------------------------------- */
 1096 static int
 1097 ippr_rpcb_getproto(rm, xp, p)
 1098         rpc_msg_t *rm;
 1099         xdr_proto_t *xp;
 1100         u_32_t **p;
 1101 {
 1102         u_int len;
 1103 
 1104         /* Must have 4 bytes for length & 4 bytes for "tcp" or "udp". */
 1105         if (!RPCB_BUF_GEQ(rm, p, 8))
 1106                 return(-1);
 1107 
 1108         xp->xp_xslen = (*p)++;
 1109         xp->xp_xsstr = (char *)*p;
 1110 
 1111         /* Test the string length. */
 1112         len = B(xp->xp_xslen);
 1113         if (len != 3)
 1114                 return(-1);
 1115 
 1116         /* Test the actual string & record the protocol accordingly. */
 1117         if (!strncmp((char *)xp->xp_xsstr, "tcp\0", 4))
 1118                 xp->xp_proto = IPPROTO_TCP;
 1119         else if (!strncmp((char *)xp->xp_xsstr, "udp\0", 4))
 1120                 xp->xp_proto = IPPROTO_UDP;
 1121         else {
 1122                 return(-1);
 1123         }
 1124         
 1125         /* Advance past the string. */
 1126         (*p)++;
 1127 
 1128         return(0);
 1129 }
 1130 
 1131 /* -------------------------------------------------------------------- */
 1132 /* Function:    ippr_rpcb_getnat                                        */
 1133 /* Returns:     int -- -1 == failed to create table entries,            */
 1134 /*                      0 == success                                    */
 1135 /* Parameters:  fin(I)  - pointer to packet information                 */
 1136 /*              nat(I)  - pointer to NAT table entry                    */
 1137 /*              proto(I) - transport protocol for new entries           */
 1138 /*              port(I) - new port to use w/ wildcard table entries     */
 1139 /*                                                                      */
 1140 /* Create state and NAT entries to handle an anticipated connection     */
 1141 /* attempt between RPC client and server.                               */
 1142 /* -------------------------------------------------------------------- */
 1143 static int
 1144 ippr_rpcb_getnat(fin, nat, proto, port)
 1145         fr_info_t *fin;
 1146         nat_t *nat;
 1147         u_int proto;
 1148         u_int port;
 1149 {
 1150         ipnat_t *ipn, ipnat;
 1151         tcphdr_t tcp;
 1152         ipstate_t *is;
 1153         fr_info_t fi;
 1154         nat_t *natl;
 1155         int nflags;
 1156 
 1157         ipn = nat->nat_ptr;
 1158 
 1159         /* Generate dummy fr_info */
 1160         bcopy((char *)fin, (char *)&fi, sizeof(fi));
 1161         fi.fin_out = 0;
 1162         fi.fin_src = fin->fin_dst;
 1163         fi.fin_dst = nat->nat_outip;
 1164         fi.fin_p = proto;
 1165         fi.fin_sport = 0;
 1166         fi.fin_dport = port & 0xffff;
 1167         fi.fin_flx |= FI_IGNORE;
 1168 
 1169         bzero((char *)&tcp, sizeof(tcp));
 1170         tcp.th_dport = htons(port);
 1171 
 1172         if (proto == IPPROTO_TCP) {
 1173                 tcp.th_win = htons(8192);
 1174                 TCP_OFF_A(&tcp, sizeof(tcphdr_t) >> 2);
 1175                 fi.fin_dlen = sizeof(tcphdr_t);
 1176                 tcp.th_flags = TH_SYN;
 1177                 nflags = NAT_TCP;
 1178         } else {
 1179                 fi.fin_dlen = sizeof(udphdr_t);
 1180                 nflags = NAT_UDP;
 1181         }
 1182 
 1183         nflags |= SI_W_SPORT|NAT_SEARCH;
 1184         fi.fin_dp = &tcp;
 1185         fi.fin_plen = fi.fin_hlen + fi.fin_dlen;
 1186 
 1187         /*
 1188          * Search for existing NAT & state entries.  Pay close attention to
 1189          * mutexes / locks grabbed from lookup routines, as not doing so could
 1190          * lead to bad things.
 1191          *
 1192          * If successful, fr_stlookup returns with ipf_state locked.  We have
 1193          * no use for this lock, so simply unlock it if necessary.
 1194          */
 1195         is = fr_stlookup(&fi, &tcp, NULL);
 1196         if (is != NULL)
 1197                 RWLOCK_EXIT(&ipf_state);
 1198 
 1199         RWLOCK_EXIT(&ipf_nat);
 1200 
 1201         WRITE_ENTER(&ipf_nat);
 1202         natl = nat_inlookup(&fi, nflags, proto, fi.fin_src, fi.fin_dst);
 1203 
 1204         if ((natl != NULL) && (is != NULL)) {
 1205                 MUTEX_DOWNGRADE(&ipf_nat);
 1206                 return(0);
 1207         }
 1208 
 1209         /* Slightly modify the following structures for actual use in creating
 1210          * NAT and/or state entries.  We're primarily concerned with stripping
 1211          * flags that may be detrimental to the creation process or simply
 1212          * shouldn't be associated with a table entry.
 1213          */
 1214         fi.fin_fr = &rpcbfr;
 1215         fi.fin_flx &= ~FI_IGNORE;
 1216         nflags &= ~NAT_SEARCH;
 1217 
 1218         if (natl == NULL) {
 1219                 /* XXX Since we're just copying the original ipn contents
 1220                  * back, would we be better off just sending a pointer to
 1221                  * the 'temp' copy off to nat_new instead?
 1222                  */
 1223                 /* Generate template/bogus NAT rule. */
 1224                 bcopy((char *)ipn, (char *)&ipnat, sizeof(ipnat));
 1225                 ipn->in_flags = nflags & IPN_TCPUDP;
 1226                 ipn->in_apr = NULL;
 1227                 ipn->in_p = proto;
 1228                 ipn->in_pmin = htons(fi.fin_dport);
 1229                 ipn->in_pmax = htons(fi.fin_dport);
 1230                 ipn->in_pnext = htons(fi.fin_dport);
 1231                 ipn->in_space = 1;
 1232                 ipn->in_ippip = 1;
 1233                 if (ipn->in_flags & IPN_FILTER) {
 1234                         ipn->in_scmp = 0;
 1235                         ipn->in_dcmp = 0;
 1236                 }
 1237                 *ipn->in_plabel = '\0';
 1238 
 1239                 /* Create NAT entry.  return NULL if this fails. */
 1240                 natl = nat_new(&fi, ipn, NULL, nflags|SI_CLONE|NAT_SLAVE,
 1241                                NAT_INBOUND);
 1242 
 1243                 bcopy((char *)&ipnat, (char *)ipn, sizeof(ipnat));
 1244 
 1245                 if (natl == NULL) {
 1246                         MUTEX_DOWNGRADE(&ipf_nat);
 1247                         return(-1);
 1248                 }
 1249 
 1250                 ipn->in_use++;
 1251                 (void) nat_proto(&fi, natl, nflags);
 1252                 nat_update(&fi, natl, natl->nat_ptr);
 1253         }
 1254         MUTEX_DOWNGRADE(&ipf_nat);
 1255 
 1256         if (is == NULL) {
 1257                 /* Create state entry.  Return NULL if this fails. */
 1258                 fi.fin_dst = nat->nat_inip;
 1259                 fi.fin_nat = (void *)natl;
 1260                 fi.fin_flx |= FI_NATED;
 1261                 fi.fin_flx &= ~FI_STATE;
 1262                 nflags &= NAT_TCPUDP;
 1263                 nflags |= SI_W_SPORT|SI_CLONE;
 1264 
 1265                 is = fr_addstate(&fi, NULL, nflags);
 1266                 if (is == NULL) {
 1267                         /*
 1268                          * XXX nat_delete is private to ip_nat.c.  Should
 1269                          * check w/ Darren about this one.
 1270                          *
 1271                          * nat_delete(natl, NL_EXPIRE);
 1272                          */
 1273                         return(-1);
 1274                 }
 1275         }
 1276 
 1277         return(0);
 1278 }
 1279 
 1280 /* -------------------------------------------------------------------- */
 1281 /* Function:    ippr_rpcb_modv3                                         */
 1282 /* Returns:     int -- change in packet length                          */
 1283 /* Parameters:  fin(I)  - pointer to packet information                 */
 1284 /*              nat(I)  - pointer to NAT session                        */
 1285 /*              rm(I)   - pointer to RPC message structure              */
 1286 /*              m(I)    - pointer to mbuf chain                         */
 1287 /*              off(I)  - offset within mbuf chain                      */
 1288 /*                                                                      */
 1289 /* Write a new universal address string to this packet, adjusting       */
 1290 /* lengths as necessary.                                                */
 1291 /* -------------------------------------------------------------------- */
 1292 static int
 1293 ippr_rpcb_modv3(fin, nat, rm, m, off)
 1294         fr_info_t *fin;
 1295         nat_t *nat;
 1296         rpc_msg_t *rm;
 1297         mb_t *m;
 1298         u_int off;
 1299 {
 1300         u_int len, xlen, pos, bogo;
 1301         rpc_resp_t *rr;
 1302         char uaddr[24];
 1303         char *i, *p;
 1304         int diff;
 1305 
 1306         rr = &rm->rm_resp;
 1307         i = (char *)&nat->nat_outip.s_addr;
 1308         p = (char *)&rr->rr_v3.xu_port;
 1309 
 1310         /* Form new string. */
 1311         bzero(uaddr, sizeof(uaddr)); /* Just in case we need padding. */
 1312 #if defined(SNPRINTF) && defined(_KERNEL)
 1313         SNPRINTF(uaddr, sizeof(uaddr),
 1314 #else
 1315         (void) sprintf(uaddr,
 1316 #endif
 1317                        "%u.%u.%u.%u.%u.%u", i[0] & 0xff, i[1] & 0xff,
 1318                        i[2] & 0xff, i[3] & 0xff, p[0] & 0xff, p[1] & 0xff);
 1319         len = strlen(uaddr);
 1320         xlen = XDRALIGN(len);
 1321 
 1322         /* Determine mbuf offset to write to. */
 1323         pos = (char *)rr->rr_v3.xu_xslen - rm->rm_msgbuf;
 1324         off += pos;
 1325 
 1326         /* Write new string length. */
 1327         bogo = htonl(len);
 1328         COPYBACK(m, off, 4, (caddr_t)&bogo);
 1329         off += 4;
 1330 
 1331         /* Write new string. */
 1332         COPYBACK(m, off, xlen, uaddr);
 1333         
 1334         /* Determine difference in data lengths. */
 1335         diff = xlen - XDRALIGN(B(rr->rr_v3.xu_xslen));
 1336 
 1337         /*
 1338          * If our new string has a different length, make necessary
 1339          * adjustments.
 1340          */
 1341         if (diff != 0)
 1342                 ippr_rpcb_fixlen(fin, diff);
 1343 
 1344         return(diff);
 1345 }
 1346 
 1347 /* -------------------------------------------------------------------- */
 1348 /* Function:    ippr_rpcb_modv4                                         */
 1349 /* Returns:     int -- change in packet length                          */
 1350 /* Parameters:  fin(I)  - pointer to packet information                 */
 1351 /*              nat(I)  - pointer to NAT session                        */
 1352 /*              rm(I)   - pointer to RPC message structure              */
 1353 /*              m(I)    - pointer to mbuf chain                         */
 1354 /*              off(I)  - offset within mbuf chain                      */
 1355 /*                                                                      */
 1356 /* Write new rpcb_entry list, adjusting lengths as necessary.           */
 1357 /* -------------------------------------------------------------------- */
 1358 static int
 1359 ippr_rpcb_modv4(fin, nat, rm, m, off)
 1360         fr_info_t *fin;
 1361         nat_t *nat;
 1362         rpc_msg_t *rm;
 1363         mb_t *m;
 1364         u_int off;
 1365 {
 1366         u_int len, xlen, pos, bogo;
 1367         rpcb_listp_t *rl;
 1368         rpcb_entry_t *re;
 1369         rpc_resp_t *rr;
 1370         char uaddr[24];
 1371         int diff, cnt;
 1372         char *i, *p;
 1373 
 1374         diff = 0;
 1375         rr = &rm->rm_resp;
 1376         rl = &rr->rr_v4;
 1377 
 1378         i = (char *)&nat->nat_outip.s_addr;
 1379 
 1380         /* Determine mbuf offset to write to. */
 1381         re = &rl->rl_entries[0];
 1382         pos = (char *)re->re_maddr.xu_xslen - rm->rm_msgbuf;
 1383         off += pos;
 1384 
 1385         for (cnt = 0; cnt < rl->rl_cnt; cnt++) {
 1386                 re = &rl->rl_entries[cnt];
 1387                 p = (char *)&re->re_maddr.xu_port;
 1388 
 1389                 /* Form new string. */
 1390                 bzero(uaddr, sizeof(uaddr)); /* Just in case we need
 1391                                                 padding. */
 1392 #if defined(SNPRINTF) && defined(_KERNEL)
 1393                 SNPRINTF(uaddr, sizeof(uaddr),
 1394 #else
 1395                 (void) sprintf(uaddr,
 1396 #endif
 1397                                "%u.%u.%u.%u.%u.%u", i[0] & 0xff,
 1398                                i[1] & 0xff, i[2] & 0xff, i[3] & 0xff,
 1399                                p[0] & 0xff, p[1] & 0xff);
 1400                 len = strlen(uaddr);
 1401                 xlen = XDRALIGN(len);
 1402 
 1403                 /* Write new string length. */
 1404                 bogo = htonl(len);
 1405                 COPYBACK(m, off, 4, (caddr_t)&bogo);
 1406                 off += 4;
 1407 
 1408                 /* Write new string. */
 1409                 COPYBACK(m, off, xlen, uaddr);
 1410                 off += xlen;
 1411 
 1412                 /* Record any change in length. */
 1413                 diff += xlen - XDRALIGN(B(re->re_maddr.xu_xslen));
 1414 
 1415                 /* If the length changed, copy back the rest of this entry. */
 1416                 len = ((char *)re->re_more + 4) -
 1417                        (char *)re->re_netid.xp_xslen;
 1418                 if (diff != 0) {
 1419                         COPYBACK(m, off, len, (caddr_t)re->re_netid.xp_xslen);
 1420                 }
 1421                 off += len;
 1422         }
 1423 
 1424         /*
 1425          * If our new string has a different length, make necessary
 1426          * adjustments.
 1427          */
 1428         if (diff != 0)
 1429                 ippr_rpcb_fixlen(fin, diff);
 1430 
 1431         return(diff);
 1432 }
 1433 
 1434 
 1435 /* -------------------------------------------------------------------- */
 1436 /* Function:    ippr_rpcb_fixlen                                        */
 1437 /* Returns:     (void)                                                  */
 1438 /* Parameters:  fin(I)  - pointer to packet information                 */
 1439 /*              len(I)  - change in packet length                       */
 1440 /*                                                                      */
 1441 /* Adjust various packet related lengths held in structure and packet   */
 1442 /* header fields.                                                       */
 1443 /* -------------------------------------------------------------------- */
 1444 static void
 1445 ippr_rpcb_fixlen(fin, len)
 1446         fr_info_t *fin;
 1447         int len;
 1448 {
 1449         udphdr_t *udp;
 1450 
 1451         udp = fin->fin_dp;
 1452         udp->uh_ulen = htons(ntohs(udp->uh_ulen) + len);
 1453         fin->fin_ip->ip_len += len;
 1454         fin->fin_dlen += len;
 1455         fin->fin_plen += len;
 1456 }
 1457 
 1458 #undef B

Cache object: c5881005bb12c17814994190af3b4ff3


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.