1145516Sdarrenr/* 2255332Scy * Copyright (C) 2002-2012 by Ryan Beasley <ryanb@goddamnbastard.org> 3145516Sdarrenr * 4145516Sdarrenr * See the IPFILTER.LICENCE file for details on licencing. 5145516Sdarrenr */ 6145516Sdarrenr/* 7145516Sdarrenr * Overview: 8145516Sdarrenr * This is an in-kernel application proxy for Sun's RPCBIND (nee portmap) 9145516Sdarrenr * protocol as defined in RFC1833. It is far from complete, mostly 10145516Sdarrenr * lacking in less-likely corner cases, but it's definitely functional. 11145516Sdarrenr * 12145516Sdarrenr * Invocation: 13145516Sdarrenr * rdr <int> <e_ip>/32 port <e_p> -> <i_ip> port <i_p> udp proxy rpcbu 14145516Sdarrenr * 15145516Sdarrenr * If the host running IP Filter is the same as the RPC server, it's 16145516Sdarrenr * perfectly legal for both the internal and external addresses and ports 17145516Sdarrenr * to match. 18145516Sdarrenr * 19145516Sdarrenr * When triggered by appropriate IP NAT rules, this proxy works by 20145516Sdarrenr * examining data contained in received packets. Requests and replies are 21145516Sdarrenr * modified, NAT and state table entries created, etc., as necessary. 22145516Sdarrenr */ 23145516Sdarrenr/* 24145516Sdarrenr * TODO / NOTES 25145516Sdarrenr * 26145516Sdarrenr * o Must implement locking to protect proxy session data. 27145516Sdarrenr * o Fragmentation isn't supported. 28145516Sdarrenr * o Only supports UDP. 29145516Sdarrenr * o Doesn't support multiple RPC records in a single request. 30145516Sdarrenr * o Errors should be more fine-grained. (e.g., malloc failure vs. 31145516Sdarrenr * illegal RPCB request / reply) 32145516Sdarrenr * o Even with the limit on the total amount of recorded transactions, 33145516Sdarrenr * should there be a timeout on transaction removal? 34145516Sdarrenr * o There is a potential collision between cloning, wildcard NAT and 35145516Sdarrenr * state entries. There should be an appr_getport routine for 36145516Sdarrenr * to avoid this. 37145516Sdarrenr * o The enclosed hack of STREAMS support is pretty sick and most likely 38145516Sdarrenr * broken. 39145516Sdarrenr * 40255332Scy * $Id$ 41145516Sdarrenr */ 42145516Sdarrenr#define IPF_RPCB_PROXY 43145516Sdarrenr 44145516Sdarrenr/* 45145516Sdarrenr * Function prototypes 46145516Sdarrenr */ 47255332Scyvoid ipf_p_rpcb_main_load __P((void)); 48255332Scyvoid ipf_p_rpcb_main_unload __P((void)); 49255332Scyint ipf_p_rpcb_new __P((void *, fr_info_t *, ap_session_t *, nat_t *)); 50255332Scyvoid ipf_p_rpcb_del __P((ipf_main_softc_t *, ap_session_t *)); 51255332Scyint ipf_p_rpcb_in __P((void *, fr_info_t *, ap_session_t *, nat_t *)); 52255332Scyint ipf_p_rpcb_out __P((void *, fr_info_t *, ap_session_t *, nat_t *)); 53145516Sdarrenr 54255332Scystatic void ipf_p_rpcb_flush __P((rpcb_session_t *)); 55255332Scystatic int ipf_p_rpcb_decodereq __P((fr_info_t *, nat_t *, 56145516Sdarrenr rpcb_session_t *, rpc_msg_t *)); 57255332Scystatic int ipf_p_rpcb_skipauth __P((rpc_msg_t *, xdr_auth_t *, u_32_t **)); 58255332Scystatic int ipf_p_rpcb_insert __P((rpcb_session_t *, rpcb_xact_t *)); 59255332Scystatic int ipf_p_rpcb_xdrrpcb __P((rpc_msg_t *, u_32_t *, rpcb_args_t *)); 60255332Scystatic int ipf_p_rpcb_getuaddr __P((rpc_msg_t *, xdr_uaddr_t *, 61145516Sdarrenr u_32_t **)); 62255332Scystatic u_int ipf_p_rpcb_atoi __P((char *)); 63255332Scystatic int ipf_p_rpcb_modreq __P((fr_info_t *, nat_t *, rpc_msg_t *, 64145516Sdarrenr mb_t *, u_int)); 65255332Scystatic int ipf_p_rpcb_decoderep __P((fr_info_t *, nat_t *, 66145516Sdarrenr rpcb_session_t *, rpc_msg_t *, rpcb_xact_t **)); 67255332Scystatic rpcb_xact_t * ipf_p_rpcb_lookup __P((rpcb_session_t *, u_32_t)); 68255332Scystatic void ipf_p_rpcb_deref __P((rpcb_session_t *, rpcb_xact_t *)); 69255332Scystatic int ipf_p_rpcb_getproto __P((rpc_msg_t *, xdr_proto_t *, 70145516Sdarrenr u_32_t **)); 71255332Scystatic int ipf_p_rpcb_getnat __P((fr_info_t *, nat_t *, u_int, u_int)); 72255332Scystatic int ipf_p_rpcb_modv3 __P((fr_info_t *, nat_t *, rpc_msg_t *, 73145516Sdarrenr mb_t *, u_int)); 74255332Scystatic int ipf_p_rpcb_modv4 __P((fr_info_t *, nat_t *, rpc_msg_t *, 75145516Sdarrenr mb_t *, u_int)); 76255332Scystatic void ipf_p_rpcb_fixlen __P((fr_info_t *, int)); 77145516Sdarrenr 78145516Sdarrenr/* 79145516Sdarrenr * Global variables 80145516Sdarrenr */ 81145516Sdarrenrstatic frentry_t rpcbfr; /* Skeleton rule for reference by entities 82145516Sdarrenr this proxy creates. */ 83145516Sdarrenrstatic int rpcbcnt; /* Upper bound of allocated RPCB sessions. */ 84145516Sdarrenr /* XXX rpcbcnt still requires locking. */ 85145516Sdarrenr 86255332Scystatic int rpcb_proxy_init = 0; 87145516Sdarrenr 88145516Sdarrenr 89145516Sdarrenr/* 90145516Sdarrenr * Since rpc_msg contains only pointers, one should use this macro as a 91145516Sdarrenr * handy way to get to the goods. (In case you're wondering about the name, 92145516Sdarrenr * this started as BYTEREF -> BREF -> B.) 93145516Sdarrenr */ 94145516Sdarrenr#define B(r) (u_32_t)ntohl(*(r)) 95145516Sdarrenr 96145516Sdarrenr/* 97145516Sdarrenr * Public subroutines 98145516Sdarrenr */ 99145516Sdarrenr 100255332Scy/* -------------------------------------------------------------------- */ 101255332Scy/* Function: ipf_p_rpcb_main_load */ 102255332Scy/* Returns: void */ 103255332Scy/* Parameters: (void) */ 104255332Scy/* */ 105255332Scy/* Initialize the filter rule entry and session limiter. */ 106255332Scy/* -------------------------------------------------------------------- */ 107255332Scyvoid 108255332Scyipf_p_rpcb_main_load() 109145516Sdarrenr{ 110145516Sdarrenr rpcbcnt = 0; 111145516Sdarrenr 112145516Sdarrenr bzero((char *)&rpcbfr, sizeof(rpcbfr)); 113145516Sdarrenr rpcbfr.fr_ref = 1; 114145516Sdarrenr rpcbfr.fr_flags = FR_PASS|FR_QUICK|FR_KEEPSTATE; 115145516Sdarrenr MUTEX_INIT(&rpcbfr.fr_lock, "ipf Sun RPCB proxy rule lock"); 116145516Sdarrenr rpcb_proxy_init = 1; 117145516Sdarrenr} 118145516Sdarrenr 119255332Scy/* -------------------------------------------------------------------- */ 120255332Scy/* Function: ipf_p_rpcb_main_unload */ 121255332Scy/* Returns: void */ 122255332Scy/* Parameters: (void) */ 123255332Scy/* */ 124255332Scy/* Destroy rpcbfr's mutex to avoid a lock leak. */ 125255332Scy/* -------------------------------------------------------------------- */ 126145516Sdarrenrvoid 127255332Scyipf_p_rpcb_main_unload() 128145516Sdarrenr{ 129145516Sdarrenr if (rpcb_proxy_init == 1) { 130145516Sdarrenr MUTEX_DESTROY(&rpcbfr.fr_lock); 131145516Sdarrenr rpcb_proxy_init = 0; 132145516Sdarrenr } 133145516Sdarrenr} 134145516Sdarrenr 135145516Sdarrenr/* -------------------------------------------------------------------- */ 136255332Scy/* Function: ipf_p_rpcb_new */ 137145516Sdarrenr/* Returns: int - -1 == failure, 0 == success */ 138145516Sdarrenr/* Parameters: fin(I) - pointer to packet information */ 139145516Sdarrenr/* aps(I) - pointer to proxy session structure */ 140145516Sdarrenr/* nat(I) - pointer to NAT session structure */ 141145516Sdarrenr/* */ 142145516Sdarrenr/* Allocate resources for per-session proxy structures. */ 143145516Sdarrenr/* -------------------------------------------------------------------- */ 144145516Sdarrenrint 145255332Scyipf_p_rpcb_new(arg, fin, aps, nat) 146255332Scy void *arg; 147145516Sdarrenr fr_info_t *fin; 148145516Sdarrenr ap_session_t *aps; 149145516Sdarrenr nat_t *nat; 150145516Sdarrenr{ 151145516Sdarrenr rpcb_session_t *rs; 152145516Sdarrenr 153145516Sdarrenr nat = nat; /* LINT */ 154145516Sdarrenr 155255332Scy if (fin->fin_v != 4) 156255332Scy return -1; 157255332Scy 158145516Sdarrenr KMALLOC(rs, rpcb_session_t *); 159145516Sdarrenr if (rs == NULL) 160145516Sdarrenr return(-1); 161145516Sdarrenr 162145516Sdarrenr bzero((char *)rs, sizeof(*rs)); 163145516Sdarrenr MUTEX_INIT(&rs->rs_rxlock, "ipf Sun RPCB proxy session lock"); 164145516Sdarrenr 165145516Sdarrenr aps->aps_data = rs; 166145516Sdarrenr 167145516Sdarrenr return(0); 168145516Sdarrenr} 169145516Sdarrenr 170145516Sdarrenr/* -------------------------------------------------------------------- */ 171255332Scy/* Function: ipf_p_rpcb_del */ 172145516Sdarrenr/* Returns: void */ 173145516Sdarrenr/* Parameters: aps(I) - pointer to proxy session structure */ 174145516Sdarrenr/* */ 175145516Sdarrenr/* Free up a session's list of RPCB requests. */ 176145516Sdarrenr/* -------------------------------------------------------------------- */ 177145516Sdarrenrvoid 178255332Scyipf_p_rpcb_del(softc, aps) 179255332Scy ipf_main_softc_t *softc; 180145516Sdarrenr ap_session_t *aps; 181145516Sdarrenr{ 182145516Sdarrenr rpcb_session_t *rs; 183145516Sdarrenr rs = (rpcb_session_t *)aps->aps_data; 184145516Sdarrenr 185145516Sdarrenr MUTEX_ENTER(&rs->rs_rxlock); 186255332Scy ipf_p_rpcb_flush(rs); 187145516Sdarrenr MUTEX_EXIT(&rs->rs_rxlock); 188145516Sdarrenr MUTEX_DESTROY(&rs->rs_rxlock); 189145516Sdarrenr} 190145516Sdarrenr 191145516Sdarrenr/* -------------------------------------------------------------------- */ 192255332Scy/* Function: ipf_p_rpcb_in */ 193145516Sdarrenr/* Returns: int - APR_ERR(1) == drop the packet, */ 194145516Sdarrenr/* APR_ERR(2) == kill the proxy session, */ 195145516Sdarrenr/* else change in packet length (in bytes) */ 196145516Sdarrenr/* Parameters: fin(I) - pointer to packet information */ 197145516Sdarrenr/* ip(I) - pointer to packet header */ 198145516Sdarrenr/* aps(I) - pointer to proxy session structure */ 199145516Sdarrenr/* nat(I) - pointer to NAT session structure */ 200145516Sdarrenr/* */ 201145516Sdarrenr/* Given a presumed RPCB request, perform some minor tests and pass off */ 202145516Sdarrenr/* for decoding. Also pass packet off for a rewrite if necessary. */ 203145516Sdarrenr/* -------------------------------------------------------------------- */ 204145516Sdarrenrint 205255332Scyipf_p_rpcb_in(arg, fin, aps, nat) 206255332Scy void *arg; 207145516Sdarrenr fr_info_t *fin; 208145516Sdarrenr ap_session_t *aps; 209145516Sdarrenr nat_t *nat; 210145516Sdarrenr{ 211145516Sdarrenr rpc_msg_t rpcmsg, *rm; 212145516Sdarrenr rpcb_session_t *rs; 213145516Sdarrenr u_int off, dlen; 214145516Sdarrenr mb_t *m; 215145516Sdarrenr int rv; 216145516Sdarrenr 217145516Sdarrenr /* Disallow fragmented or illegally short packets. */ 218145516Sdarrenr if ((fin->fin_flx & (FI_FRAG|FI_SHORT)) != 0) 219145516Sdarrenr return(APR_ERR(1)); 220145516Sdarrenr 221145516Sdarrenr /* Perform basic variable initialization. */ 222145516Sdarrenr rs = (rpcb_session_t *)aps->aps_data; 223145516Sdarrenr 224145516Sdarrenr m = fin->fin_m; 225145516Sdarrenr off = (char *)fin->fin_dp - (char *)fin->fin_ip; 226145516Sdarrenr off += sizeof(udphdr_t) + fin->fin_ipoff; 227145516Sdarrenr dlen = fin->fin_dlen - sizeof(udphdr_t); 228145516Sdarrenr 229145516Sdarrenr /* Disallow packets outside legal range for supported requests. */ 230145516Sdarrenr if ((dlen < RPCB_REQMIN) || (dlen > RPCB_REQMAX)) 231145516Sdarrenr return(APR_ERR(1)); 232145516Sdarrenr 233145516Sdarrenr /* Copy packet over to convenience buffer. */ 234145516Sdarrenr rm = &rpcmsg; 235145516Sdarrenr bzero((char *)rm, sizeof(*rm)); 236145516Sdarrenr COPYDATA(m, off, dlen, (caddr_t)&rm->rm_msgbuf); 237145516Sdarrenr rm->rm_buflen = dlen; 238145516Sdarrenr 239145516Sdarrenr /* Send off to decode request. */ 240255332Scy rv = ipf_p_rpcb_decodereq(fin, nat, rs, rm); 241145516Sdarrenr 242145516Sdarrenr switch(rv) 243145516Sdarrenr { 244145516Sdarrenr case -1: 245145516Sdarrenr return(APR_ERR(1)); 246145516Sdarrenr /*NOTREACHED*/ 247145516Sdarrenr break; 248145516Sdarrenr case 0: 249145516Sdarrenr break; 250145516Sdarrenr case 1: 251255332Scy rv = ipf_p_rpcb_modreq(fin, nat, rm, m, off); 252145516Sdarrenr break; 253145516Sdarrenr default: 254145516Sdarrenr /*CONSTANTCONDITION*/ 255255332Scy IPF_PANIC(1, ("illegal rv %d (ipf_p_rpcb_req)", rv)); 256145516Sdarrenr } 257145516Sdarrenr 258145516Sdarrenr return(rv); 259145516Sdarrenr} 260145516Sdarrenr 261145516Sdarrenr/* -------------------------------------------------------------------- */ 262255332Scy/* Function: ipf_p_rpcb_out */ 263145516Sdarrenr/* Returns: int - APR_ERR(1) == drop the packet, */ 264145516Sdarrenr/* APR_ERR(2) == kill the proxy session, */ 265145516Sdarrenr/* else change in packet length (in bytes) */ 266145516Sdarrenr/* Parameters: fin(I) - pointer to packet information */ 267145516Sdarrenr/* ip(I) - pointer to packet header */ 268145516Sdarrenr/* aps(I) - pointer to proxy session structure */ 269145516Sdarrenr/* nat(I) - pointer to NAT session structure */ 270145516Sdarrenr/* */ 271145516Sdarrenr/* Given a presumed RPCB reply, perform some minor tests and pass off */ 272145516Sdarrenr/* for decoding. If the message indicates a successful request with */ 273145516Sdarrenr/* valid addressing information, create NAT and state structures to */ 274145516Sdarrenr/* allow direct communication between RPC client and server. */ 275145516Sdarrenr/* -------------------------------------------------------------------- */ 276145516Sdarrenrint 277255332Scyipf_p_rpcb_out(arg, fin, aps, nat) 278255332Scy void *arg; 279145516Sdarrenr fr_info_t *fin; 280145516Sdarrenr ap_session_t *aps; 281145516Sdarrenr nat_t *nat; 282145516Sdarrenr{ 283145516Sdarrenr rpc_msg_t rpcmsg, *rm; 284145516Sdarrenr rpcb_session_t *rs; 285145516Sdarrenr rpcb_xact_t *rx; 286145516Sdarrenr u_int off, dlen; 287145516Sdarrenr int rv, diff; 288145516Sdarrenr mb_t *m; 289145516Sdarrenr 290145516Sdarrenr /* Disallow fragmented or illegally short packets. */ 291145516Sdarrenr if ((fin->fin_flx & (FI_FRAG|FI_SHORT)) != 0) 292145516Sdarrenr return(APR_ERR(1)); 293145516Sdarrenr 294145516Sdarrenr /* Perform basic variable initialization. */ 295145516Sdarrenr rs = (rpcb_session_t *)aps->aps_data; 296170263Sdarrenr rx = NULL; 297145516Sdarrenr 298145516Sdarrenr m = fin->fin_m; 299145516Sdarrenr off = (char *)fin->fin_dp - (char *)fin->fin_ip; 300145516Sdarrenr off += sizeof(udphdr_t) + fin->fin_ipoff; 301145516Sdarrenr dlen = fin->fin_dlen - sizeof(udphdr_t); 302145516Sdarrenr diff = 0; 303145516Sdarrenr 304145516Sdarrenr /* Disallow packets outside legal range for supported requests. */ 305145516Sdarrenr if ((dlen < RPCB_REPMIN) || (dlen > RPCB_REPMAX)) 306145516Sdarrenr return(APR_ERR(1)); 307145516Sdarrenr 308145516Sdarrenr /* Copy packet over to convenience buffer. */ 309145516Sdarrenr rm = &rpcmsg; 310145516Sdarrenr bzero((char *)rm, sizeof(*rm)); 311145516Sdarrenr COPYDATA(m, off, dlen, (caddr_t)&rm->rm_msgbuf); 312145516Sdarrenr rm->rm_buflen = dlen; 313145516Sdarrenr 314170263Sdarrenr rx = NULL; /* XXX gcc */ 315170263Sdarrenr 316145516Sdarrenr /* Send off to decode reply. */ 317255332Scy rv = ipf_p_rpcb_decoderep(fin, nat, rs, rm, &rx); 318145516Sdarrenr 319145516Sdarrenr switch(rv) 320145516Sdarrenr { 321145516Sdarrenr case -1: /* Bad packet */ 322145516Sdarrenr if (rx != NULL) { 323145516Sdarrenr MUTEX_ENTER(&rs->rs_rxlock); 324255332Scy ipf_p_rpcb_deref(rs, rx); 325145516Sdarrenr MUTEX_EXIT(&rs->rs_rxlock); 326145516Sdarrenr } 327145516Sdarrenr return(APR_ERR(1)); 328145516Sdarrenr /*NOTREACHED*/ 329145516Sdarrenr break; 330145516Sdarrenr case 0: /* Negative reply / request rejected */ 331145516Sdarrenr break; 332145516Sdarrenr case 1: /* Positive reply */ 333145516Sdarrenr /* 334145516Sdarrenr * With the IP address embedded in a GETADDR(LIST) reply, 335145516Sdarrenr * we'll need to rewrite the packet in the very possible 336145516Sdarrenr * event that the internal & external addresses aren't the 337145516Sdarrenr * same. (i.e., this box is either a router or rpcbind 338145516Sdarrenr * only listens on loopback.) 339145516Sdarrenr */ 340255332Scy if (nat->nat_odstaddr != nat->nat_ndstaddr) { 341145516Sdarrenr if (rx->rx_type == RPCB_RES_STRING) 342255332Scy diff = ipf_p_rpcb_modv3(fin, nat, rm, m, off); 343145516Sdarrenr else if (rx->rx_type == RPCB_RES_LIST) 344255332Scy diff = ipf_p_rpcb_modv4(fin, nat, rm, m, off); 345145516Sdarrenr } 346145516Sdarrenr break; 347145516Sdarrenr default: 348145516Sdarrenr /*CONSTANTCONDITION*/ 349255332Scy IPF_PANIC(1, ("illegal rv %d (ipf_p_rpcb_decoderep)", rv)); 350145516Sdarrenr } 351145516Sdarrenr 352145516Sdarrenr if (rx != NULL) { 353145516Sdarrenr MUTEX_ENTER(&rs->rs_rxlock); 354145516Sdarrenr /* XXX Gross hack - I'm overloading the reference 355145516Sdarrenr * counter to deal with both threads and retransmitted 356145516Sdarrenr * requests. One deref signals that this thread is 357145516Sdarrenr * finished with rx, and the other signals that we've 358145516Sdarrenr * processed its reply. 359145516Sdarrenr */ 360255332Scy ipf_p_rpcb_deref(rs, rx); 361255332Scy ipf_p_rpcb_deref(rs, rx); 362145516Sdarrenr MUTEX_EXIT(&rs->rs_rxlock); 363145516Sdarrenr } 364145516Sdarrenr 365145516Sdarrenr return(diff); 366145516Sdarrenr} 367145516Sdarrenr 368145516Sdarrenr/* 369145516Sdarrenr * Private support subroutines 370145516Sdarrenr */ 371145516Sdarrenr 372145516Sdarrenr/* -------------------------------------------------------------------- */ 373255332Scy/* Function: ipf_p_rpcb_flush */ 374145516Sdarrenr/* Returns: void */ 375145516Sdarrenr/* Parameters: rs(I) - pointer to RPCB session structure */ 376145516Sdarrenr/* */ 377145516Sdarrenr/* Simply flushes the list of outstanding transactions, if any. */ 378145516Sdarrenr/* -------------------------------------------------------------------- */ 379145516Sdarrenrstatic void 380255332Scyipf_p_rpcb_flush(rs) 381145516Sdarrenr rpcb_session_t *rs; 382145516Sdarrenr{ 383145516Sdarrenr rpcb_xact_t *r1, *r2; 384145516Sdarrenr 385145516Sdarrenr r1 = rs->rs_rxlist; 386145516Sdarrenr if (r1 == NULL) 387145516Sdarrenr return; 388145516Sdarrenr 389145516Sdarrenr while (r1 != NULL) { 390145516Sdarrenr r2 = r1; 391145516Sdarrenr r1 = r1->rx_next; 392145516Sdarrenr KFREE(r2); 393145516Sdarrenr } 394145516Sdarrenr} 395145516Sdarrenr 396145516Sdarrenr/* -------------------------------------------------------------------- */ 397255332Scy/* Function: ipf_p_rpcb_decodereq */ 398145516Sdarrenr/* Returns: int - -1 == bad request or critical failure, */ 399145516Sdarrenr/* 0 == request successfully decoded, */ 400145516Sdarrenr/* 1 == request successfully decoded; requires */ 401145516Sdarrenr/* address rewrite/modification */ 402145516Sdarrenr/* Parameters: fin(I) - pointer to packet information */ 403145516Sdarrenr/* nat(I) - pointer to NAT session structure */ 404145516Sdarrenr/* rs(I) - pointer to RPCB session structure */ 405145516Sdarrenr/* rm(I) - pointer to RPC message structure */ 406145516Sdarrenr/* */ 407145516Sdarrenr/* Take a presumed RPCB request, decode it, and store the results in */ 408145516Sdarrenr/* the transaction list. If the internal target address needs to be */ 409145516Sdarrenr/* modified, store its location in ptr. */ 410145516Sdarrenr/* WARNING: It's the responsibility of the caller to make sure there */ 411145516Sdarrenr/* is enough room in rs_buf for the basic RPC message "preamble". */ 412145516Sdarrenr/* -------------------------------------------------------------------- */ 413145516Sdarrenrstatic int 414255332Scyipf_p_rpcb_decodereq(fin, nat, rs, rm) 415145516Sdarrenr fr_info_t *fin; 416145516Sdarrenr nat_t *nat; 417145516Sdarrenr rpcb_session_t *rs; 418145516Sdarrenr rpc_msg_t *rm; 419145516Sdarrenr{ 420145516Sdarrenr rpcb_args_t *ra; 421145516Sdarrenr u_32_t xdr, *p; 422145516Sdarrenr rpc_call_t *rc; 423145516Sdarrenr rpcb_xact_t rx; 424145516Sdarrenr int mod; 425145516Sdarrenr 426145516Sdarrenr p = (u_32_t *)rm->rm_msgbuf; 427145516Sdarrenr mod = 0; 428145516Sdarrenr 429145516Sdarrenr bzero((char *)&rx, sizeof(rx)); 430145516Sdarrenr rc = &rm->rm_call; 431145516Sdarrenr 432145516Sdarrenr rm->rm_xid = p; 433145516Sdarrenr rx.rx_xid = B(p++); /* Record this message's XID. */ 434145516Sdarrenr 435145516Sdarrenr /* Parse out and test the RPC header. */ 436145516Sdarrenr if ((B(p++) != RPCB_CALL) || 437145516Sdarrenr (B(p++) != RPCB_MSG_VERSION) || 438145516Sdarrenr (B(p++) != RPCB_PROG)) 439145516Sdarrenr return(-1); 440145516Sdarrenr 441145516Sdarrenr /* Record the RPCB version and procedure. */ 442145516Sdarrenr rc->rc_vers = p++; 443145516Sdarrenr rc->rc_proc = p++; 444145516Sdarrenr 445145516Sdarrenr /* Bypass RPC authentication stuff. */ 446255332Scy if (ipf_p_rpcb_skipauth(rm, &rc->rc_authcred, &p) != 0) 447145516Sdarrenr return(-1); 448255332Scy if (ipf_p_rpcb_skipauth(rm, &rc->rc_authverf, &p) != 0) 449145516Sdarrenr return(-1); 450145516Sdarrenr 451145516Sdarrenr /* Compare RPCB version and procedure numbers. */ 452145516Sdarrenr switch(B(rc->rc_vers)) 453145516Sdarrenr { 454145516Sdarrenr case 2: 455145516Sdarrenr /* This proxy only supports PMAP_GETPORT. */ 456145516Sdarrenr if (B(rc->rc_proc) != RPCB_GETPORT) 457145516Sdarrenr return(-1); 458145516Sdarrenr 459145516Sdarrenr /* Portmap requests contain four 4 byte parameters. */ 460145516Sdarrenr if (RPCB_BUF_EQ(rm, p, 16) == 0) 461145516Sdarrenr return(-1); 462145516Sdarrenr 463145516Sdarrenr p += 2; /* Skip requested program and version numbers. */ 464145516Sdarrenr 465145516Sdarrenr /* Sanity check the requested protocol. */ 466145516Sdarrenr xdr = B(p); 467145516Sdarrenr if (!(xdr == IPPROTO_UDP || xdr == IPPROTO_TCP)) 468145516Sdarrenr return(-1); 469145516Sdarrenr 470145516Sdarrenr rx.rx_type = RPCB_RES_PMAP; 471145516Sdarrenr rx.rx_proto = xdr; 472145516Sdarrenr break; 473145516Sdarrenr case 3: 474145516Sdarrenr case 4: 475145516Sdarrenr /* GETADDRLIST is exclusive to v4; GETADDR for v3 & v4 */ 476145516Sdarrenr switch(B(rc->rc_proc)) 477145516Sdarrenr { 478145516Sdarrenr case RPCB_GETADDR: 479145516Sdarrenr rx.rx_type = RPCB_RES_STRING; 480145516Sdarrenr rx.rx_proto = (u_int)fin->fin_p; 481145516Sdarrenr break; 482145516Sdarrenr case RPCB_GETADDRLIST: 483145516Sdarrenr if (B(rc->rc_vers) != 4) 484145516Sdarrenr return(-1); 485145516Sdarrenr rx.rx_type = RPCB_RES_LIST; 486145516Sdarrenr break; 487145516Sdarrenr default: 488145516Sdarrenr return(-1); 489145516Sdarrenr } 490145516Sdarrenr 491145516Sdarrenr ra = &rc->rc_rpcbargs; 492145516Sdarrenr 493145516Sdarrenr /* Decode the 'struct rpcb' request. */ 494255332Scy if (ipf_p_rpcb_xdrrpcb(rm, p, ra) != 0) 495145516Sdarrenr return(-1); 496145516Sdarrenr 497145516Sdarrenr /* Are the target address & port valid? */ 498255332Scy if ((ra->ra_maddr.xu_ip != nat->nat_ndstaddr) || 499255332Scy (ra->ra_maddr.xu_port != nat->nat_ndport)) 500145516Sdarrenr return(-1); 501145516Sdarrenr 502145516Sdarrenr /* Do we need to rewrite this packet? */ 503255332Scy if ((nat->nat_ndstaddr != nat->nat_odstaddr) || 504255332Scy (nat->nat_ndport != nat->nat_odport)) 505145516Sdarrenr mod = 1; 506145516Sdarrenr break; 507145516Sdarrenr default: 508145516Sdarrenr return(-1); 509145516Sdarrenr } 510145516Sdarrenr 511145516Sdarrenr MUTEX_ENTER(&rs->rs_rxlock); 512255332Scy if (ipf_p_rpcb_insert(rs, &rx) != 0) { 513145516Sdarrenr MUTEX_EXIT(&rs->rs_rxlock); 514145516Sdarrenr return(-1); 515145516Sdarrenr } 516145516Sdarrenr MUTEX_EXIT(&rs->rs_rxlock); 517145516Sdarrenr 518145516Sdarrenr return(mod); 519145516Sdarrenr} 520145516Sdarrenr 521145516Sdarrenr/* -------------------------------------------------------------------- */ 522255332Scy/* Function: ipf_p_rpcb_skipauth */ 523145516Sdarrenr/* Returns: int -- -1 == illegal auth parameters (lengths) */ 524145516Sdarrenr/* 0 == valid parameters, pointer advanced */ 525145516Sdarrenr/* Parameters: rm(I) - pointer to RPC message structure */ 526145516Sdarrenr/* auth(I) - pointer to RPC auth structure */ 527145516Sdarrenr/* buf(IO) - pointer to location within convenience buffer */ 528145516Sdarrenr/* */ 529145516Sdarrenr/* Record auth data length & location of auth data, then advance past */ 530145516Sdarrenr/* it. */ 531145516Sdarrenr/* -------------------------------------------------------------------- */ 532145516Sdarrenrstatic int 533255332Scyipf_p_rpcb_skipauth(rm, auth, buf) 534145516Sdarrenr rpc_msg_t *rm; 535145516Sdarrenr xdr_auth_t *auth; 536145516Sdarrenr u_32_t **buf; 537145516Sdarrenr{ 538145516Sdarrenr u_32_t *p, xdr; 539145516Sdarrenr 540145516Sdarrenr p = *buf; 541145516Sdarrenr 542145516Sdarrenr /* Make sure we have enough space for expected fixed auth parms. */ 543145516Sdarrenr if (RPCB_BUF_GEQ(rm, p, 8) == 0) 544145516Sdarrenr return(-1); 545145516Sdarrenr 546145516Sdarrenr p++; /* We don't care about auth_flavor. */ 547145516Sdarrenr 548145516Sdarrenr auth->xa_string.xs_len = p; 549145516Sdarrenr xdr = B(p++); /* Length of auth_data */ 550145516Sdarrenr 551145516Sdarrenr /* Test for absurdity / illegality of auth_data length. */ 552145516Sdarrenr if ((XDRALIGN(xdr) < xdr) || (RPCB_BUF_GEQ(rm, p, XDRALIGN(xdr)) == 0)) 553145516Sdarrenr return(-1); 554145516Sdarrenr 555145516Sdarrenr auth->xa_string.xs_str = (char *)p; 556145516Sdarrenr 557145516Sdarrenr p += XDRALIGN(xdr); /* Advance our location. */ 558145516Sdarrenr 559145516Sdarrenr *buf = (u_32_t *)p; 560145516Sdarrenr 561145516Sdarrenr return(0); 562145516Sdarrenr} 563145516Sdarrenr 564145516Sdarrenr/* -------------------------------------------------------------------- */ 565255332Scy/* Function: ipf_p_rpcb_insert */ 566145516Sdarrenr/* Returns: int -- -1 == list insertion failed, */ 567145516Sdarrenr/* 0 == item successfully added */ 568145516Sdarrenr/* Parameters: rs(I) - pointer to RPCB session structure */ 569145516Sdarrenr/* rx(I) - pointer to RPCB transaction structure */ 570145516Sdarrenr/* -------------------------------------------------------------------- */ 571145516Sdarrenrstatic int 572255332Scyipf_p_rpcb_insert(rs, rx) 573145516Sdarrenr rpcb_session_t *rs; 574145516Sdarrenr rpcb_xact_t *rx; 575145516Sdarrenr{ 576145516Sdarrenr rpcb_xact_t *rxp; 577145516Sdarrenr 578255332Scy rxp = ipf_p_rpcb_lookup(rs, rx->rx_xid); 579145516Sdarrenr if (rxp != NULL) { 580145516Sdarrenr ++rxp->rx_ref; 581145516Sdarrenr return(0); 582145516Sdarrenr } 583145516Sdarrenr 584145516Sdarrenr if (rpcbcnt == RPCB_MAXREQS) 585145516Sdarrenr return(-1); 586145516Sdarrenr 587145516Sdarrenr KMALLOC(rxp, rpcb_xact_t *); 588145516Sdarrenr if (rxp == NULL) 589145516Sdarrenr return(-1); 590145516Sdarrenr 591145516Sdarrenr bcopy((char *)rx, (char *)rxp, sizeof(*rx)); 592145516Sdarrenr 593145516Sdarrenr if (rs->rs_rxlist != NULL) 594145516Sdarrenr rs->rs_rxlist->rx_pnext = &rxp->rx_next; 595145516Sdarrenr 596145516Sdarrenr rxp->rx_pnext = &rs->rs_rxlist; 597145516Sdarrenr rxp->rx_next = rs->rs_rxlist; 598145516Sdarrenr rs->rs_rxlist = rxp; 599145516Sdarrenr 600145516Sdarrenr rxp->rx_ref = 1; 601145516Sdarrenr 602145516Sdarrenr ++rpcbcnt; 603145516Sdarrenr 604145516Sdarrenr return(0); 605145516Sdarrenr} 606145516Sdarrenr 607145516Sdarrenr/* -------------------------------------------------------------------- */ 608255332Scy/* Function: ipf_p_rpcb_xdrrpcb */ 609145516Sdarrenr/* Returns: int -- -1 == failure to properly decode the request */ 610145516Sdarrenr/* 0 == rpcb successfully decoded */ 611145516Sdarrenr/* Parameters: rs(I) - pointer to RPCB session structure */ 612145516Sdarrenr/* p(I) - pointer to location within session buffer */ 613145516Sdarrenr/* rpcb(O) - pointer to rpcb (xdr type) structure */ 614145516Sdarrenr/* */ 615145516Sdarrenr/* Decode a XDR encoded rpcb structure and record its contents in rpcb */ 616145516Sdarrenr/* within only the context of TCP/UDP over IP networks. */ 617145516Sdarrenr/* -------------------------------------------------------------------- */ 618145516Sdarrenrstatic int 619255332Scyipf_p_rpcb_xdrrpcb(rm, p, ra) 620145516Sdarrenr rpc_msg_t *rm; 621145516Sdarrenr u_32_t *p; 622145516Sdarrenr rpcb_args_t *ra; 623145516Sdarrenr{ 624145516Sdarrenr if (!RPCB_BUF_GEQ(rm, p, 20)) 625145516Sdarrenr return(-1); 626145516Sdarrenr 627145516Sdarrenr /* Bypass target program & version. */ 628145516Sdarrenr p += 2; 629145516Sdarrenr 630145516Sdarrenr /* Decode r_netid. Must be "tcp" or "udp". */ 631255332Scy if (ipf_p_rpcb_getproto(rm, &ra->ra_netid, &p) != 0) 632145516Sdarrenr return(-1); 633145516Sdarrenr 634145516Sdarrenr /* Decode r_maddr. */ 635255332Scy if (ipf_p_rpcb_getuaddr(rm, &ra->ra_maddr, &p) != 0) 636145516Sdarrenr return(-1); 637145516Sdarrenr 638145516Sdarrenr /* Advance to r_owner and make sure it's empty. */ 639145516Sdarrenr if (!RPCB_BUF_EQ(rm, p, 4) || (B(p) != 0)) 640145516Sdarrenr return(-1); 641145516Sdarrenr 642145516Sdarrenr return(0); 643145516Sdarrenr} 644145516Sdarrenr 645145516Sdarrenr/* -------------------------------------------------------------------- */ 646255332Scy/* Function: ipf_p_rpcb_getuaddr */ 647145516Sdarrenr/* Returns: int -- -1 == illegal string, */ 648145516Sdarrenr/* 0 == string parsed; contents recorded */ 649145516Sdarrenr/* Parameters: rm(I) - pointer to RPC message structure */ 650145516Sdarrenr/* xu(I) - pointer to universal address structure */ 651145516Sdarrenr/* p(IO) - pointer to location within message buffer */ 652145516Sdarrenr/* */ 653145516Sdarrenr/* Decode the IP address / port at p and record them in xu. */ 654145516Sdarrenr/* -------------------------------------------------------------------- */ 655145516Sdarrenrstatic int 656255332Scyipf_p_rpcb_getuaddr(rm, xu, p) 657145516Sdarrenr rpc_msg_t *rm; 658145516Sdarrenr xdr_uaddr_t *xu; 659145516Sdarrenr u_32_t **p; 660145516Sdarrenr{ 661145516Sdarrenr char *c, *i, *b, *pp; 662145516Sdarrenr u_int d, dd, l, t; 663145516Sdarrenr char uastr[24]; 664145516Sdarrenr 665145516Sdarrenr /* Test for string length. */ 666145516Sdarrenr if (!RPCB_BUF_GEQ(rm, *p, 4)) 667145516Sdarrenr return(-1); 668145516Sdarrenr 669145516Sdarrenr xu->xu_xslen = (*p)++; 670145516Sdarrenr xu->xu_xsstr = (char *)*p; 671145516Sdarrenr 672145516Sdarrenr /* Length check */ 673145516Sdarrenr l = B(xu->xu_xslen); 674145516Sdarrenr if (l < 11 || l > 23 || !RPCB_BUF_GEQ(rm, *p, XDRALIGN(l))) 675145516Sdarrenr return(-1); 676145516Sdarrenr 677145516Sdarrenr /* Advance p */ 678145516Sdarrenr *(char **)p += XDRALIGN(l); 679145516Sdarrenr 680145516Sdarrenr /* Copy string to local buffer & terminate C style */ 681145516Sdarrenr bcopy(xu->xu_xsstr, uastr, l); 682145516Sdarrenr uastr[l] = '\0'; 683145516Sdarrenr 684145516Sdarrenr i = (char *)&xu->xu_ip; 685145516Sdarrenr pp = (char *)&xu->xu_port; 686145516Sdarrenr 687145516Sdarrenr /* 688145516Sdarrenr * Expected format: a.b.c.d.e.f where [a-d] correspond to bytes of 689145516Sdarrenr * an IP address and [ef] are the bytes of a L4 port. 690145516Sdarrenr */ 691145516Sdarrenr if (!(ISDIGIT(uastr[0]) && ISDIGIT(uastr[l-1]))) 692145516Sdarrenr return(-1); 693145516Sdarrenr b = uastr; 694145516Sdarrenr for (c = &uastr[1], d = 0, dd = 0; c < &uastr[l-1]; c++) { 695145516Sdarrenr if (ISDIGIT(*c)) { 696145516Sdarrenr dd = 0; 697145516Sdarrenr continue; 698145516Sdarrenr } 699145516Sdarrenr if (*c == '.') { 700145516Sdarrenr if (dd != 0) 701145516Sdarrenr return(-1); 702145516Sdarrenr 703145516Sdarrenr /* Check for ASCII byte. */ 704145516Sdarrenr *c = '\0'; 705255332Scy t = ipf_p_rpcb_atoi(b); 706145516Sdarrenr if (t > 255) 707145516Sdarrenr return(-1); 708145516Sdarrenr 709145516Sdarrenr /* Aim b at beginning of the next byte. */ 710145516Sdarrenr b = c + 1; 711145516Sdarrenr 712145516Sdarrenr /* Switch off IP addr vs port parsing. */ 713145516Sdarrenr if (d < 4) 714145516Sdarrenr i[d++] = t & 0xff; 715145516Sdarrenr else 716145516Sdarrenr pp[d++ - 4] = t & 0xff; 717145516Sdarrenr 718145516Sdarrenr dd = 1; 719145516Sdarrenr continue; 720145516Sdarrenr } 721145516Sdarrenr return(-1); 722145516Sdarrenr } 723145516Sdarrenr if (d != 5) /* String must contain exactly 5 periods. */ 724145516Sdarrenr return(-1); 725145516Sdarrenr 726145516Sdarrenr /* Handle the last byte (port low byte) */ 727255332Scy t = ipf_p_rpcb_atoi(b); 728145516Sdarrenr if (t > 255) 729145516Sdarrenr return(-1); 730145516Sdarrenr pp[d - 4] = t & 0xff; 731145516Sdarrenr 732145516Sdarrenr return(0); 733145516Sdarrenr} 734145516Sdarrenr 735145516Sdarrenr/* -------------------------------------------------------------------- */ 736255332Scy/* Function: ipf_p_rpcb_atoi (XXX should be generic for all proxies) */ 737145516Sdarrenr/* Returns: int -- integer representation of supplied string */ 738145516Sdarrenr/* Parameters: ptr(I) - input string */ 739145516Sdarrenr/* */ 740145516Sdarrenr/* Simple version of atoi(3) ripped from ip_rcmd_pxy.c. */ 741145516Sdarrenr/* -------------------------------------------------------------------- */ 742145516Sdarrenrstatic u_int 743255332Scyipf_p_rpcb_atoi(ptr) 744145516Sdarrenr char *ptr; 745145516Sdarrenr{ 746145516Sdarrenr register char *s = ptr, c; 747145516Sdarrenr register u_int i = 0; 748145516Sdarrenr 749145516Sdarrenr while (((c = *s++) != '\0') && ISDIGIT(c)) { 750145516Sdarrenr i *= 10; 751145516Sdarrenr i += c - '0'; 752145516Sdarrenr } 753145516Sdarrenr return i; 754145516Sdarrenr} 755145516Sdarrenr 756145516Sdarrenr/* -------------------------------------------------------------------- */ 757255332Scy/* Function: ipf_p_rpcb_modreq */ 758145516Sdarrenr/* Returns: int -- change in datagram length */ 759145516Sdarrenr/* APR_ERR(2) - critical failure */ 760145516Sdarrenr/* Parameters: fin(I) - pointer to packet information */ 761145516Sdarrenr/* nat(I) - pointer to NAT session */ 762145516Sdarrenr/* rm(I) - pointer to RPC message structure */ 763145516Sdarrenr/* m(I) - pointer to mbuf chain */ 764145516Sdarrenr/* off(I) - current offset within mbuf chain */ 765145516Sdarrenr/* */ 766145516Sdarrenr/* When external and internal addresses differ, we rewrite the former */ 767145516Sdarrenr/* with the latter. (This is exclusive to protocol versions 3 & 4). */ 768145516Sdarrenr/* -------------------------------------------------------------------- */ 769145516Sdarrenrstatic int 770255332Scyipf_p_rpcb_modreq(fin, nat, rm, m, off) 771145516Sdarrenr fr_info_t *fin; 772145516Sdarrenr nat_t *nat; 773145516Sdarrenr rpc_msg_t *rm; 774145516Sdarrenr mb_t *m; 775145516Sdarrenr u_int off; 776145516Sdarrenr{ 777145516Sdarrenr u_int len, xlen, pos, bogo; 778145516Sdarrenr rpcb_args_t *ra; 779145516Sdarrenr char uaddr[24]; 780145516Sdarrenr udphdr_t *udp; 781145516Sdarrenr char *i, *p; 782145516Sdarrenr int diff; 783145516Sdarrenr 784145516Sdarrenr ra = &rm->rm_call.rc_rpcbargs; 785255332Scy i = (char *)&nat->nat_odstaddr; 786255332Scy p = (char *)&nat->nat_odport; 787145516Sdarrenr 788145516Sdarrenr /* Form new string. */ 789145516Sdarrenr bzero(uaddr, sizeof(uaddr)); /* Just in case we need padding. */ 790145516Sdarrenr#if defined(SNPRINTF) && defined(_KERNEL) 791145516Sdarrenr SNPRINTF(uaddr, sizeof(uaddr), 792145516Sdarrenr#else 793145516Sdarrenr (void) sprintf(uaddr, 794145516Sdarrenr#endif 795145516Sdarrenr "%u.%u.%u.%u.%u.%u", i[0] & 0xff, i[1] & 0xff, 796145516Sdarrenr i[2] & 0xff, i[3] & 0xff, p[0] & 0xff, p[1] & 0xff); 797145516Sdarrenr len = strlen(uaddr); 798145516Sdarrenr xlen = XDRALIGN(len); 799145516Sdarrenr 800145516Sdarrenr /* Determine mbuf offset to start writing to. */ 801145516Sdarrenr pos = (char *)ra->ra_maddr.xu_xslen - rm->rm_msgbuf; 802145516Sdarrenr off += pos; 803145516Sdarrenr 804145516Sdarrenr /* Write new string length. */ 805145516Sdarrenr bogo = htonl(len); 806145516Sdarrenr COPYBACK(m, off, 4, (caddr_t)&bogo); 807145516Sdarrenr off += 4; 808145516Sdarrenr 809145516Sdarrenr /* Write new string. */ 810145516Sdarrenr COPYBACK(m, off, xlen, uaddr); 811145516Sdarrenr off += xlen; 812145516Sdarrenr 813145516Sdarrenr /* Write in zero r_owner. */ 814145516Sdarrenr bogo = 0; 815145516Sdarrenr COPYBACK(m, off, 4, (caddr_t)&bogo); 816145516Sdarrenr 817145516Sdarrenr /* Determine difference in data lengths. */ 818145516Sdarrenr diff = xlen - XDRALIGN(B(ra->ra_maddr.xu_xslen)); 819145516Sdarrenr 820145516Sdarrenr /* 821145516Sdarrenr * If our new string has a different length, make necessary 822145516Sdarrenr * adjustments. 823145516Sdarrenr */ 824145516Sdarrenr if (diff != 0) { 825145516Sdarrenr udp = fin->fin_dp; 826145516Sdarrenr udp->uh_ulen = htons(ntohs(udp->uh_ulen) + diff); 827255332Scy fin->fin_plen += diff; 828255332Scy fin->fin_ip->ip_len = htons(fin->fin_plen); 829145516Sdarrenr fin->fin_dlen += diff; 830145516Sdarrenr /* XXX Storage lengths. */ 831145516Sdarrenr } 832145516Sdarrenr 833145516Sdarrenr return(diff); 834145516Sdarrenr} 835145516Sdarrenr 836145516Sdarrenr/* -------------------------------------------------------------------- */ 837255332Scy/* Function: ipf_p_rpcb_decoderep */ 838145516Sdarrenr/* Returns: int - -1 == bad request or critical failure, */ 839145516Sdarrenr/* 0 == valid, negative reply */ 840145516Sdarrenr/* 1 == vaddlid, positive reply; needs no changes */ 841145516Sdarrenr/* Parameters: fin(I) - pointer to packet information */ 842145516Sdarrenr/* nat(I) - pointer to NAT session structure */ 843145516Sdarrenr/* rs(I) - pointer to RPCB session structure */ 844145516Sdarrenr/* rm(I) - pointer to RPC message structure */ 845145516Sdarrenr/* rxp(O) - pointer to RPCB transaction structure */ 846145516Sdarrenr/* */ 847145516Sdarrenr/* Take a presumed RPCB reply, extract the XID, search for the original */ 848145516Sdarrenr/* request information, and determine whether the request was accepted */ 849145516Sdarrenr/* or rejected. With a valid accepted reply, go ahead and create NAT */ 850145516Sdarrenr/* and state entries, and finish up by rewriting the packet as */ 851145516Sdarrenr/* required. */ 852145516Sdarrenr/* */ 853145516Sdarrenr/* WARNING: It's the responsibility of the caller to make sure there */ 854145516Sdarrenr/* is enough room in rs_buf for the basic RPC message "preamble". */ 855145516Sdarrenr/* -------------------------------------------------------------------- */ 856145516Sdarrenrstatic int 857255332Scyipf_p_rpcb_decoderep(fin, nat, rs, rm, rxp) 858145516Sdarrenr fr_info_t *fin; 859145516Sdarrenr nat_t *nat; 860145516Sdarrenr rpcb_session_t *rs; 861145516Sdarrenr rpc_msg_t *rm; 862145516Sdarrenr rpcb_xact_t **rxp; 863145516Sdarrenr{ 864145516Sdarrenr rpcb_listp_t *rl; 865145516Sdarrenr rpcb_entry_t *re; 866145516Sdarrenr rpcb_xact_t *rx; 867145516Sdarrenr u_32_t xdr, *p; 868145516Sdarrenr rpc_resp_t *rr; 869145516Sdarrenr int rv, cnt; 870145516Sdarrenr 871145516Sdarrenr p = (u_32_t *)rm->rm_msgbuf; 872145516Sdarrenr 873145516Sdarrenr bzero((char *)&rx, sizeof(rx)); 874145516Sdarrenr rr = &rm->rm_resp; 875145516Sdarrenr 876145516Sdarrenr rm->rm_xid = p; 877145516Sdarrenr xdr = B(p++); /* Record this message's XID. */ 878145516Sdarrenr 879145516Sdarrenr /* Lookup XID */ 880145516Sdarrenr MUTEX_ENTER(&rs->rs_rxlock); 881255332Scy if ((rx = ipf_p_rpcb_lookup(rs, xdr)) == NULL) { 882145516Sdarrenr MUTEX_EXIT(&rs->rs_rxlock); 883145516Sdarrenr return(-1); 884145516Sdarrenr } 885145516Sdarrenr ++rx->rx_ref; /* per thread reference */ 886145516Sdarrenr MUTEX_EXIT(&rs->rs_rxlock); 887145516Sdarrenr 888145516Sdarrenr *rxp = rx; 889145516Sdarrenr 890145516Sdarrenr /* Test call vs reply */ 891145516Sdarrenr if (B(p++) != RPCB_REPLY) 892145516Sdarrenr return(-1); 893145516Sdarrenr 894145516Sdarrenr /* Test reply_stat */ 895145516Sdarrenr switch(B(p++)) 896145516Sdarrenr { 897145516Sdarrenr case RPCB_MSG_DENIED: 898145516Sdarrenr return(0); 899145516Sdarrenr case RPCB_MSG_ACCEPTED: 900145516Sdarrenr break; 901145516Sdarrenr default: 902145516Sdarrenr return(-1); 903145516Sdarrenr } 904145516Sdarrenr 905145516Sdarrenr /* Bypass RPC authentication stuff. */ 906255332Scy if (ipf_p_rpcb_skipauth(rm, &rr->rr_authverf, &p) != 0) 907145516Sdarrenr return(-1); 908145516Sdarrenr 909145516Sdarrenr /* Test accept status */ 910145516Sdarrenr if (!RPCB_BUF_GEQ(rm, p, 4)) 911145516Sdarrenr return(-1); 912145516Sdarrenr if (B(p++) != 0) 913145516Sdarrenr return(0); 914145516Sdarrenr 915145516Sdarrenr /* Parse out the expected reply */ 916145516Sdarrenr switch(rx->rx_type) 917145516Sdarrenr { 918145516Sdarrenr case RPCB_RES_PMAP: 919145516Sdarrenr /* There must be only one 4 byte argument. */ 920145516Sdarrenr if (!RPCB_BUF_EQ(rm, p, 4)) 921145516Sdarrenr return(-1); 922255332Scy 923145516Sdarrenr rr->rr_v2 = p; 924145516Sdarrenr xdr = B(rr->rr_v2); 925255332Scy 926145516Sdarrenr /* Reply w/ a 0 port indicates service isn't registered */ 927145516Sdarrenr if (xdr == 0) 928145516Sdarrenr return(0); 929255332Scy 930145516Sdarrenr /* Is the value sane? */ 931145516Sdarrenr if (xdr > 65535) 932145516Sdarrenr return(-1); 933145516Sdarrenr 934145516Sdarrenr /* Create NAT & state table entries. */ 935255332Scy if (ipf_p_rpcb_getnat(fin, nat, rx->rx_proto, (u_int)xdr) != 0) 936145516Sdarrenr return(-1); 937145516Sdarrenr break; 938145516Sdarrenr case RPCB_RES_STRING: 939145516Sdarrenr /* Expecting a XDR string; need 4 bytes for length */ 940145516Sdarrenr if (!RPCB_BUF_GEQ(rm, p, 4)) 941145516Sdarrenr return(-1); 942145516Sdarrenr 943145516Sdarrenr rr->rr_v3.xu_str.xs_len = p++; 944145516Sdarrenr rr->rr_v3.xu_str.xs_str = (char *)p; 945145516Sdarrenr 946145516Sdarrenr xdr = B(rr->rr_v3.xu_xslen); 947145516Sdarrenr 948145516Sdarrenr /* A null string indicates an unregistered service */ 949145516Sdarrenr if ((xdr == 0) && RPCB_BUF_EQ(rm, p, 0)) 950145516Sdarrenr return(0); 951145516Sdarrenr 952145516Sdarrenr /* Decode the target IP address / port. */ 953255332Scy if (ipf_p_rpcb_getuaddr(rm, &rr->rr_v3, &p) != 0) 954145516Sdarrenr return(-1); 955145516Sdarrenr 956145516Sdarrenr /* Validate the IP address and port contained. */ 957255332Scy if (nat->nat_odstaddr != rr->rr_v3.xu_ip) 958145516Sdarrenr return(-1); 959145516Sdarrenr 960145516Sdarrenr /* Create NAT & state table entries. */ 961255332Scy if (ipf_p_rpcb_getnat(fin, nat, rx->rx_proto, 962145516Sdarrenr (u_int)rr->rr_v3.xu_port) != 0) 963145516Sdarrenr return(-1); 964145516Sdarrenr break; 965145516Sdarrenr case RPCB_RES_LIST: 966145516Sdarrenr if (!RPCB_BUF_GEQ(rm, p, 4)) 967145516Sdarrenr return(-1); 968145516Sdarrenr /* rpcb_entry_list_ptr */ 969145516Sdarrenr switch(B(p)) 970145516Sdarrenr { 971145516Sdarrenr case 0: 972145516Sdarrenr return(0); 973145516Sdarrenr /*NOTREACHED*/ 974145516Sdarrenr break; 975145516Sdarrenr case 1: 976145516Sdarrenr break; 977145516Sdarrenr default: 978145516Sdarrenr return(-1); 979145516Sdarrenr } 980145516Sdarrenr rl = &rr->rr_v4; 981145516Sdarrenr rl->rl_list = p++; 982145516Sdarrenr cnt = 0; 983145516Sdarrenr 984145516Sdarrenr for(;;) { 985145516Sdarrenr re = &rl->rl_entries[rl->rl_cnt]; 986255332Scy if (ipf_p_rpcb_getuaddr(rm, &re->re_maddr, &p) != 0) 987145516Sdarrenr return(-1); 988255332Scy if (ipf_p_rpcb_getproto(rm, &re->re_netid, &p) != 0) 989145516Sdarrenr return(-1); 990145516Sdarrenr /* re_semantics & re_pfamily length */ 991145516Sdarrenr if (!RPCB_BUF_GEQ(rm, p, 12)) 992145516Sdarrenr return(-1); 993145516Sdarrenr p++; /* Skipping re_semantics. */ 994145516Sdarrenr xdr = B(p++); 995145516Sdarrenr if ((xdr != 4) || strncmp((char *)p, "inet", 4)) 996145516Sdarrenr return(-1); 997145516Sdarrenr p++; 998255332Scy if (ipf_p_rpcb_getproto(rm, &re->re_proto, &p) != 0) 999145516Sdarrenr return(-1); 1000145516Sdarrenr if (!RPCB_BUF_GEQ(rm, p, 4)) 1001145516Sdarrenr return(-1); 1002145516Sdarrenr re->re_more = p; 1003145516Sdarrenr if (B(re->re_more) > 1) /* 0,1 only legal values */ 1004145516Sdarrenr return(-1); 1005145516Sdarrenr ++rl->rl_cnt; 1006145516Sdarrenr ++cnt; 1007145516Sdarrenr if (B(re->re_more) == 0) 1008145516Sdarrenr break; 1009145516Sdarrenr /* Replies in max out at 2; TCP and/or UDP */ 1010145516Sdarrenr if (cnt > 2) 1011145516Sdarrenr return(-1); 1012145516Sdarrenr p++; 1013145516Sdarrenr } 1014145516Sdarrenr 1015145516Sdarrenr for(rl->rl_cnt = 0; rl->rl_cnt < cnt; rl->rl_cnt++) { 1016145516Sdarrenr re = &rl->rl_entries[rl->rl_cnt]; 1017255332Scy rv = ipf_p_rpcb_getnat(fin, nat, 1018145516Sdarrenr re->re_proto.xp_proto, 1019145516Sdarrenr (u_int)re->re_maddr.xu_port); 1020145516Sdarrenr if (rv != 0) 1021145516Sdarrenr return(-1); 1022145516Sdarrenr } 1023145516Sdarrenr break; 1024145516Sdarrenr default: 1025145516Sdarrenr /*CONSTANTCONDITION*/ 1026145516Sdarrenr IPF_PANIC(1, ("illegal rx_type %d", rx->rx_type)); 1027145516Sdarrenr } 1028145516Sdarrenr 1029145516Sdarrenr return(1); 1030145516Sdarrenr} 1031145516Sdarrenr 1032145516Sdarrenr/* -------------------------------------------------------------------- */ 1033255332Scy/* Function: ipf_p_rpcb_lookup */ 1034145516Sdarrenr/* Returns: rpcb_xact_t * - NULL == no matching record, */ 1035145516Sdarrenr/* else pointer to relevant entry */ 1036145516Sdarrenr/* Parameters: rs(I) - pointer to RPCB session */ 1037145516Sdarrenr/* xid(I) - XID to look for */ 1038145516Sdarrenr/* -------------------------------------------------------------------- */ 1039145516Sdarrenrstatic rpcb_xact_t * 1040255332Scyipf_p_rpcb_lookup(rs, xid) 1041145516Sdarrenr rpcb_session_t *rs; 1042145516Sdarrenr u_32_t xid; 1043145516Sdarrenr{ 1044145516Sdarrenr rpcb_xact_t *rx; 1045145516Sdarrenr 1046145516Sdarrenr if (rs->rs_rxlist == NULL) 1047145516Sdarrenr return(NULL); 1048145516Sdarrenr 1049145516Sdarrenr for (rx = rs->rs_rxlist; rx != NULL; rx = rx->rx_next) 1050145516Sdarrenr if (rx->rx_xid == xid) 1051145516Sdarrenr break; 1052145516Sdarrenr 1053145516Sdarrenr return(rx); 1054145516Sdarrenr} 1055145516Sdarrenr 1056145516Sdarrenr/* -------------------------------------------------------------------- */ 1057255332Scy/* Function: ipf_p_rpcb_deref */ 1058145516Sdarrenr/* Returns: (void) */ 1059145516Sdarrenr/* Parameters: rs(I) - pointer to RPCB session */ 1060145516Sdarrenr/* rx(I) - pointer to RPC transaction struct to remove */ 1061145516Sdarrenr/* force(I) - indicates to delete entry regardless of */ 1062145516Sdarrenr/* reference count */ 1063145516Sdarrenr/* Locking: rs->rs_rxlock must be held write only */ 1064145516Sdarrenr/* */ 1065145516Sdarrenr/* Free the RPCB transaction record rx from the chain of entries. */ 1066145516Sdarrenr/* -------------------------------------------------------------------- */ 1067145516Sdarrenrstatic void 1068255332Scyipf_p_rpcb_deref(rs, rx) 1069145516Sdarrenr rpcb_session_t *rs; 1070145516Sdarrenr rpcb_xact_t *rx; 1071145516Sdarrenr{ 1072145516Sdarrenr rs = rs; /* LINT */ 1073145516Sdarrenr 1074145516Sdarrenr if (rx == NULL) 1075145516Sdarrenr return; 1076145516Sdarrenr 1077145516Sdarrenr if (--rx->rx_ref != 0) 1078145516Sdarrenr return; 1079145516Sdarrenr 1080145516Sdarrenr if (rx->rx_next != NULL) 1081145516Sdarrenr rx->rx_next->rx_pnext = rx->rx_pnext; 1082145516Sdarrenr 1083145516Sdarrenr *rx->rx_pnext = rx->rx_next; 1084145516Sdarrenr 1085145516Sdarrenr KFREE(rx); 1086145516Sdarrenr 1087145516Sdarrenr --rpcbcnt; 1088145516Sdarrenr} 1089145516Sdarrenr 1090145516Sdarrenr/* -------------------------------------------------------------------- */ 1091255332Scy/* Function: ipf_p_rpcb_getproto */ 1092145516Sdarrenr/* Returns: int - -1 == illegal protocol/netid, */ 1093145516Sdarrenr/* 0 == legal protocol/netid */ 1094145516Sdarrenr/* Parameters: rm(I) - pointer to RPC message structure */ 1095145516Sdarrenr/* xp(I) - pointer to netid structure */ 1096145516Sdarrenr/* p(IO) - pointer to location within packet buffer */ 1097145516Sdarrenr/* */ 1098145516Sdarrenr/* Decode netid/proto stored at p and record its numeric value. */ 1099145516Sdarrenr/* -------------------------------------------------------------------- */ 1100145516Sdarrenrstatic int 1101255332Scyipf_p_rpcb_getproto(rm, xp, p) 1102145516Sdarrenr rpc_msg_t *rm; 1103145516Sdarrenr xdr_proto_t *xp; 1104145516Sdarrenr u_32_t **p; 1105145516Sdarrenr{ 1106145516Sdarrenr u_int len; 1107145516Sdarrenr 1108145516Sdarrenr /* Must have 4 bytes for length & 4 bytes for "tcp" or "udp". */ 1109145516Sdarrenr if (!RPCB_BUF_GEQ(rm, p, 8)) 1110145516Sdarrenr return(-1); 1111145516Sdarrenr 1112145516Sdarrenr xp->xp_xslen = (*p)++; 1113145516Sdarrenr xp->xp_xsstr = (char *)*p; 1114145516Sdarrenr 1115145516Sdarrenr /* Test the string length. */ 1116145516Sdarrenr len = B(xp->xp_xslen); 1117145516Sdarrenr if (len != 3) 1118145516Sdarrenr return(-1); 1119145516Sdarrenr 1120145516Sdarrenr /* Test the actual string & record the protocol accordingly. */ 1121145516Sdarrenr if (!strncmp((char *)xp->xp_xsstr, "tcp\0", 4)) 1122145516Sdarrenr xp->xp_proto = IPPROTO_TCP; 1123145516Sdarrenr else if (!strncmp((char *)xp->xp_xsstr, "udp\0", 4)) 1124145516Sdarrenr xp->xp_proto = IPPROTO_UDP; 1125145516Sdarrenr else { 1126145516Sdarrenr return(-1); 1127145516Sdarrenr } 1128255332Scy 1129145516Sdarrenr /* Advance past the string. */ 1130145516Sdarrenr (*p)++; 1131145516Sdarrenr 1132145516Sdarrenr return(0); 1133145516Sdarrenr} 1134145516Sdarrenr 1135145516Sdarrenr/* -------------------------------------------------------------------- */ 1136255332Scy/* Function: ipf_p_rpcb_getnat */ 1137145516Sdarrenr/* Returns: int -- -1 == failed to create table entries, */ 1138145516Sdarrenr/* 0 == success */ 1139145516Sdarrenr/* Parameters: fin(I) - pointer to packet information */ 1140145516Sdarrenr/* nat(I) - pointer to NAT table entry */ 1141145516Sdarrenr/* proto(I) - transport protocol for new entries */ 1142145516Sdarrenr/* port(I) - new port to use w/ wildcard table entries */ 1143145516Sdarrenr/* */ 1144145516Sdarrenr/* Create state and NAT entries to handle an anticipated connection */ 1145145516Sdarrenr/* attempt between RPC client and server. */ 1146145516Sdarrenr/* -------------------------------------------------------------------- */ 1147145516Sdarrenrstatic int 1148255332Scyipf_p_rpcb_getnat(fin, nat, proto, port) 1149145516Sdarrenr fr_info_t *fin; 1150145516Sdarrenr nat_t *nat; 1151145516Sdarrenr u_int proto; 1152145516Sdarrenr u_int port; 1153145516Sdarrenr{ 1154255332Scy ipf_main_softc_t *softc = fin->fin_main_soft; 1155145516Sdarrenr ipnat_t *ipn, ipnat; 1156145516Sdarrenr tcphdr_t tcp; 1157145516Sdarrenr ipstate_t *is; 1158145516Sdarrenr fr_info_t fi; 1159145516Sdarrenr nat_t *natl; 1160145516Sdarrenr int nflags; 1161145516Sdarrenr 1162145516Sdarrenr ipn = nat->nat_ptr; 1163145516Sdarrenr 1164145516Sdarrenr /* Generate dummy fr_info */ 1165145516Sdarrenr bcopy((char *)fin, (char *)&fi, sizeof(fi)); 1166145516Sdarrenr fi.fin_out = 0; 1167145516Sdarrenr fi.fin_p = proto; 1168145516Sdarrenr fi.fin_sport = 0; 1169145516Sdarrenr fi.fin_dport = port & 0xffff; 1170145516Sdarrenr fi.fin_flx |= FI_IGNORE; 1171255332Scy fi.fin_saddr = nat->nat_osrcaddr; 1172255332Scy fi.fin_daddr = nat->nat_odstaddr; 1173145516Sdarrenr 1174145516Sdarrenr bzero((char *)&tcp, sizeof(tcp)); 1175145516Sdarrenr tcp.th_dport = htons(port); 1176145516Sdarrenr 1177145516Sdarrenr if (proto == IPPROTO_TCP) { 1178145516Sdarrenr tcp.th_win = htons(8192); 1179145516Sdarrenr TCP_OFF_A(&tcp, sizeof(tcphdr_t) >> 2); 1180145516Sdarrenr fi.fin_dlen = sizeof(tcphdr_t); 1181145516Sdarrenr tcp.th_flags = TH_SYN; 1182145516Sdarrenr nflags = NAT_TCP; 1183145516Sdarrenr } else { 1184145516Sdarrenr fi.fin_dlen = sizeof(udphdr_t); 1185145516Sdarrenr nflags = NAT_UDP; 1186145516Sdarrenr } 1187145516Sdarrenr 1188145516Sdarrenr nflags |= SI_W_SPORT|NAT_SEARCH; 1189145516Sdarrenr fi.fin_dp = &tcp; 1190145516Sdarrenr fi.fin_plen = fi.fin_hlen + fi.fin_dlen; 1191145516Sdarrenr 1192145516Sdarrenr /* 1193145516Sdarrenr * Search for existing NAT & state entries. Pay close attention to 1194145516Sdarrenr * mutexes / locks grabbed from lookup routines, as not doing so could 1195145516Sdarrenr * lead to bad things. 1196145516Sdarrenr * 1197145516Sdarrenr * If successful, fr_stlookup returns with ipf_state locked. We have 1198145516Sdarrenr * no use for this lock, so simply unlock it if necessary. 1199145516Sdarrenr */ 1200255332Scy is = ipf_state_lookup(&fi, &tcp, NULL); 1201170263Sdarrenr if (is != NULL) { 1202255332Scy RWLOCK_EXIT(&softc->ipf_state); 1203170263Sdarrenr } 1204145516Sdarrenr 1205255332Scy RWLOCK_EXIT(&softc->ipf_nat); 1206145516Sdarrenr 1207255332Scy WRITE_ENTER(&softc->ipf_nat); 1208255332Scy natl = ipf_nat_inlookup(&fi, nflags, proto, fi.fin_src, fi.fin_dst); 1209145516Sdarrenr 1210145516Sdarrenr if ((natl != NULL) && (is != NULL)) { 1211255332Scy MUTEX_DOWNGRADE(&softc->ipf_nat); 1212145516Sdarrenr return(0); 1213145516Sdarrenr } 1214145516Sdarrenr 1215145516Sdarrenr /* Slightly modify the following structures for actual use in creating 1216145516Sdarrenr * NAT and/or state entries. We're primarily concerned with stripping 1217145516Sdarrenr * flags that may be detrimental to the creation process or simply 1218145516Sdarrenr * shouldn't be associated with a table entry. 1219145516Sdarrenr */ 1220145516Sdarrenr fi.fin_fr = &rpcbfr; 1221145516Sdarrenr fi.fin_flx &= ~FI_IGNORE; 1222145516Sdarrenr nflags &= ~NAT_SEARCH; 1223145516Sdarrenr 1224145516Sdarrenr if (natl == NULL) { 1225255332Scy#ifdef USE_MUTEXES 1226255332Scy ipf_nat_softc_t *softn = softc->ipf_nat_soft; 1227255332Scy#endif 1228255332Scy 1229145516Sdarrenr /* XXX Since we're just copying the original ipn contents 1230145516Sdarrenr * back, would we be better off just sending a pointer to 1231145516Sdarrenr * the 'temp' copy off to nat_new instead? 1232145516Sdarrenr */ 1233145516Sdarrenr /* Generate template/bogus NAT rule. */ 1234145516Sdarrenr bcopy((char *)ipn, (char *)&ipnat, sizeof(ipnat)); 1235145516Sdarrenr ipn->in_flags = nflags & IPN_TCPUDP; 1236145516Sdarrenr ipn->in_apr = NULL; 1237255332Scy ipn->in_pr[0] = proto; 1238255332Scy ipn->in_pr[1] = proto; 1239255332Scy ipn->in_dpmin = fi.fin_dport; 1240255332Scy ipn->in_dpmax = fi.fin_dport; 1241255332Scy ipn->in_dpnext = fi.fin_dport; 1242145516Sdarrenr ipn->in_space = 1; 1243145516Sdarrenr ipn->in_ippip = 1; 1244145516Sdarrenr if (ipn->in_flags & IPN_FILTER) { 1245145516Sdarrenr ipn->in_scmp = 0; 1246145516Sdarrenr ipn->in_dcmp = 0; 1247145516Sdarrenr } 1248255332Scy ipn->in_plabel = -1; 1249145516Sdarrenr 1250145516Sdarrenr /* Create NAT entry. return NULL if this fails. */ 1251255332Scy MUTEX_ENTER(&softn->ipf_nat_new); 1252255332Scy natl = ipf_nat_add(&fi, ipn, NULL, nflags|SI_CLONE|NAT_SLAVE, 1253145516Sdarrenr NAT_INBOUND); 1254255332Scy MUTEX_EXIT(&softn->ipf_nat_new); 1255145516Sdarrenr 1256145516Sdarrenr bcopy((char *)&ipnat, (char *)ipn, sizeof(ipnat)); 1257145516Sdarrenr 1258145516Sdarrenr if (natl == NULL) { 1259255332Scy MUTEX_DOWNGRADE(&softc->ipf_nat); 1260145516Sdarrenr return(-1); 1261145516Sdarrenr } 1262145516Sdarrenr 1263255332Scy natl->nat_ptr = ipn; 1264255332Scy fi.fin_saddr = natl->nat_nsrcaddr; 1265255332Scy fi.fin_daddr = natl->nat_ndstaddr; 1266145516Sdarrenr ipn->in_use++; 1267255332Scy (void) ipf_nat_proto(&fi, natl, nflags); 1268255332Scy MUTEX_ENTER(&natl->nat_lock); 1269255332Scy ipf_nat_update(&fi, natl); 1270255332Scy MUTEX_EXIT(&natl->nat_lock); 1271145516Sdarrenr } 1272255332Scy MUTEX_DOWNGRADE(&softc->ipf_nat); 1273145516Sdarrenr 1274145516Sdarrenr if (is == NULL) { 1275145516Sdarrenr /* Create state entry. Return NULL if this fails. */ 1276145516Sdarrenr fi.fin_flx |= FI_NATED; 1277145516Sdarrenr fi.fin_flx &= ~FI_STATE; 1278145516Sdarrenr nflags &= NAT_TCPUDP; 1279145516Sdarrenr nflags |= SI_W_SPORT|SI_CLONE; 1280145516Sdarrenr 1281255332Scy if (ipf_state_add(softc, &fi, NULL, nflags) != 0) { 1282145516Sdarrenr /* 1283145516Sdarrenr * XXX nat_delete is private to ip_nat.c. Should 1284145516Sdarrenr * check w/ Darren about this one. 1285145516Sdarrenr * 1286145516Sdarrenr * nat_delete(natl, NL_EXPIRE); 1287145516Sdarrenr */ 1288145516Sdarrenr return(-1); 1289145516Sdarrenr } 1290145516Sdarrenr } 1291145516Sdarrenr 1292145516Sdarrenr return(0); 1293145516Sdarrenr} 1294145516Sdarrenr 1295145516Sdarrenr/* -------------------------------------------------------------------- */ 1296255332Scy/* Function: ipf_p_rpcb_modv3 */ 1297145516Sdarrenr/* Returns: int -- change in packet length */ 1298145516Sdarrenr/* Parameters: fin(I) - pointer to packet information */ 1299145516Sdarrenr/* nat(I) - pointer to NAT session */ 1300145516Sdarrenr/* rm(I) - pointer to RPC message structure */ 1301145516Sdarrenr/* m(I) - pointer to mbuf chain */ 1302145516Sdarrenr/* off(I) - offset within mbuf chain */ 1303145516Sdarrenr/* */ 1304145516Sdarrenr/* Write a new universal address string to this packet, adjusting */ 1305145516Sdarrenr/* lengths as necessary. */ 1306145516Sdarrenr/* -------------------------------------------------------------------- */ 1307145516Sdarrenrstatic int 1308255332Scyipf_p_rpcb_modv3(fin, nat, rm, m, off) 1309145516Sdarrenr fr_info_t *fin; 1310145516Sdarrenr nat_t *nat; 1311145516Sdarrenr rpc_msg_t *rm; 1312145516Sdarrenr mb_t *m; 1313145516Sdarrenr u_int off; 1314145516Sdarrenr{ 1315145516Sdarrenr u_int len, xlen, pos, bogo; 1316145516Sdarrenr rpc_resp_t *rr; 1317145516Sdarrenr char uaddr[24]; 1318145516Sdarrenr char *i, *p; 1319145516Sdarrenr int diff; 1320145516Sdarrenr 1321145516Sdarrenr rr = &rm->rm_resp; 1322255332Scy i = (char *)&nat->nat_ndstaddr; 1323145516Sdarrenr p = (char *)&rr->rr_v3.xu_port; 1324145516Sdarrenr 1325145516Sdarrenr /* Form new string. */ 1326145516Sdarrenr bzero(uaddr, sizeof(uaddr)); /* Just in case we need padding. */ 1327145516Sdarrenr#if defined(SNPRINTF) && defined(_KERNEL) 1328145516Sdarrenr SNPRINTF(uaddr, sizeof(uaddr), 1329145516Sdarrenr#else 1330145516Sdarrenr (void) sprintf(uaddr, 1331145516Sdarrenr#endif 1332145516Sdarrenr "%u.%u.%u.%u.%u.%u", i[0] & 0xff, i[1] & 0xff, 1333145516Sdarrenr i[2] & 0xff, i[3] & 0xff, p[0] & 0xff, p[1] & 0xff); 1334145516Sdarrenr len = strlen(uaddr); 1335145516Sdarrenr xlen = XDRALIGN(len); 1336145516Sdarrenr 1337145516Sdarrenr /* Determine mbuf offset to write to. */ 1338145516Sdarrenr pos = (char *)rr->rr_v3.xu_xslen - rm->rm_msgbuf; 1339145516Sdarrenr off += pos; 1340145516Sdarrenr 1341145516Sdarrenr /* Write new string length. */ 1342145516Sdarrenr bogo = htonl(len); 1343145516Sdarrenr COPYBACK(m, off, 4, (caddr_t)&bogo); 1344145516Sdarrenr off += 4; 1345145516Sdarrenr 1346145516Sdarrenr /* Write new string. */ 1347145516Sdarrenr COPYBACK(m, off, xlen, uaddr); 1348255332Scy 1349145516Sdarrenr /* Determine difference in data lengths. */ 1350145516Sdarrenr diff = xlen - XDRALIGN(B(rr->rr_v3.xu_xslen)); 1351145516Sdarrenr 1352145516Sdarrenr /* 1353145516Sdarrenr * If our new string has a different length, make necessary 1354145516Sdarrenr * adjustments. 1355145516Sdarrenr */ 1356145516Sdarrenr if (diff != 0) 1357255332Scy ipf_p_rpcb_fixlen(fin, diff); 1358145516Sdarrenr 1359145516Sdarrenr return(diff); 1360145516Sdarrenr} 1361145516Sdarrenr 1362145516Sdarrenr/* -------------------------------------------------------------------- */ 1363255332Scy/* Function: ipf_p_rpcb_modv4 */ 1364145516Sdarrenr/* Returns: int -- change in packet length */ 1365145516Sdarrenr/* Parameters: fin(I) - pointer to packet information */ 1366145516Sdarrenr/* nat(I) - pointer to NAT session */ 1367145516Sdarrenr/* rm(I) - pointer to RPC message structure */ 1368145516Sdarrenr/* m(I) - pointer to mbuf chain */ 1369145516Sdarrenr/* off(I) - offset within mbuf chain */ 1370145516Sdarrenr/* */ 1371145516Sdarrenr/* Write new rpcb_entry list, adjusting lengths as necessary. */ 1372145516Sdarrenr/* -------------------------------------------------------------------- */ 1373145516Sdarrenrstatic int 1374255332Scyipf_p_rpcb_modv4(fin, nat, rm, m, off) 1375145516Sdarrenr fr_info_t *fin; 1376145516Sdarrenr nat_t *nat; 1377145516Sdarrenr rpc_msg_t *rm; 1378145516Sdarrenr mb_t *m; 1379145516Sdarrenr u_int off; 1380145516Sdarrenr{ 1381145516Sdarrenr u_int len, xlen, pos, bogo; 1382145516Sdarrenr rpcb_listp_t *rl; 1383145516Sdarrenr rpcb_entry_t *re; 1384145516Sdarrenr rpc_resp_t *rr; 1385145516Sdarrenr char uaddr[24]; 1386145516Sdarrenr int diff, cnt; 1387145516Sdarrenr char *i, *p; 1388145516Sdarrenr 1389145516Sdarrenr diff = 0; 1390145516Sdarrenr rr = &rm->rm_resp; 1391145516Sdarrenr rl = &rr->rr_v4; 1392145516Sdarrenr 1393255332Scy i = (char *)&nat->nat_ndstaddr; 1394145516Sdarrenr 1395145516Sdarrenr /* Determine mbuf offset to write to. */ 1396145516Sdarrenr re = &rl->rl_entries[0]; 1397145516Sdarrenr pos = (char *)re->re_maddr.xu_xslen - rm->rm_msgbuf; 1398145516Sdarrenr off += pos; 1399145516Sdarrenr 1400145516Sdarrenr for (cnt = 0; cnt < rl->rl_cnt; cnt++) { 1401145516Sdarrenr re = &rl->rl_entries[cnt]; 1402145516Sdarrenr p = (char *)&re->re_maddr.xu_port; 1403145516Sdarrenr 1404145516Sdarrenr /* Form new string. */ 1405145516Sdarrenr bzero(uaddr, sizeof(uaddr)); /* Just in case we need 1406145516Sdarrenr padding. */ 1407145516Sdarrenr#if defined(SNPRINTF) && defined(_KERNEL) 1408145516Sdarrenr SNPRINTF(uaddr, sizeof(uaddr), 1409145516Sdarrenr#else 1410145516Sdarrenr (void) sprintf(uaddr, 1411145516Sdarrenr#endif 1412145516Sdarrenr "%u.%u.%u.%u.%u.%u", i[0] & 0xff, 1413145516Sdarrenr i[1] & 0xff, i[2] & 0xff, i[3] & 0xff, 1414145516Sdarrenr p[0] & 0xff, p[1] & 0xff); 1415145516Sdarrenr len = strlen(uaddr); 1416145516Sdarrenr xlen = XDRALIGN(len); 1417145516Sdarrenr 1418145516Sdarrenr /* Write new string length. */ 1419145516Sdarrenr bogo = htonl(len); 1420145516Sdarrenr COPYBACK(m, off, 4, (caddr_t)&bogo); 1421145516Sdarrenr off += 4; 1422145516Sdarrenr 1423145516Sdarrenr /* Write new string. */ 1424145516Sdarrenr COPYBACK(m, off, xlen, uaddr); 1425145516Sdarrenr off += xlen; 1426145516Sdarrenr 1427145516Sdarrenr /* Record any change in length. */ 1428145516Sdarrenr diff += xlen - XDRALIGN(B(re->re_maddr.xu_xslen)); 1429145516Sdarrenr 1430145516Sdarrenr /* If the length changed, copy back the rest of this entry. */ 1431145516Sdarrenr len = ((char *)re->re_more + 4) - 1432145516Sdarrenr (char *)re->re_netid.xp_xslen; 1433145516Sdarrenr if (diff != 0) { 1434145516Sdarrenr COPYBACK(m, off, len, (caddr_t)re->re_netid.xp_xslen); 1435145516Sdarrenr } 1436145516Sdarrenr off += len; 1437145516Sdarrenr } 1438145516Sdarrenr 1439145516Sdarrenr /* 1440145516Sdarrenr * If our new string has a different length, make necessary 1441145516Sdarrenr * adjustments. 1442145516Sdarrenr */ 1443145516Sdarrenr if (diff != 0) 1444255332Scy ipf_p_rpcb_fixlen(fin, diff); 1445145516Sdarrenr 1446145516Sdarrenr return(diff); 1447145516Sdarrenr} 1448145516Sdarrenr 1449145516Sdarrenr 1450145516Sdarrenr/* -------------------------------------------------------------------- */ 1451255332Scy/* Function: ipf_p_rpcb_fixlen */ 1452145516Sdarrenr/* Returns: (void) */ 1453145516Sdarrenr/* Parameters: fin(I) - pointer to packet information */ 1454145516Sdarrenr/* len(I) - change in packet length */ 1455145516Sdarrenr/* */ 1456145516Sdarrenr/* Adjust various packet related lengths held in structure and packet */ 1457145516Sdarrenr/* header fields. */ 1458145516Sdarrenr/* -------------------------------------------------------------------- */ 1459145516Sdarrenrstatic void 1460255332Scyipf_p_rpcb_fixlen(fin, len) 1461145516Sdarrenr fr_info_t *fin; 1462145516Sdarrenr int len; 1463145516Sdarrenr{ 1464145516Sdarrenr udphdr_t *udp; 1465145516Sdarrenr 1466145516Sdarrenr udp = fin->fin_dp; 1467145516Sdarrenr udp->uh_ulen = htons(ntohs(udp->uh_ulen) + len); 1468255332Scy fin->fin_plen += len; 1469255332Scy fin->fin_ip->ip_len = htons(fin->fin_plen); 1470145516Sdarrenr fin->fin_dlen += len; 1471145516Sdarrenr} 1472145516Sdarrenr 1473145516Sdarrenr#undef B 1474