1145516Sdarrenr/* 2145516Sdarrenr * Copyright (C) 2002-2003 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 * 40172771Sdarrenr * $Id: ip_rpcb_pxy.c,v 2.25.2.7 2007/06/04 09:16:31 darrenr Exp $ 41145516Sdarrenr */ 42145516Sdarrenr 43145516Sdarrenr#define IPF_RPCB_PROXY 44145516Sdarrenr 45145516Sdarrenr/* 46145516Sdarrenr * Function prototypes 47145516Sdarrenr */ 48145516Sdarrenrint ippr_rpcb_init __P((void)); 49145516Sdarrenrvoid ippr_rpcb_fini __P((void)); 50145516Sdarrenrint ippr_rpcb_new __P((fr_info_t *, ap_session_t *, nat_t *)); 51145516Sdarrenrvoid ippr_rpcb_del __P((ap_session_t *)); 52145516Sdarrenrint ippr_rpcb_in __P((fr_info_t *, ap_session_t *, nat_t *)); 53145516Sdarrenrint ippr_rpcb_out __P((fr_info_t *, ap_session_t *, nat_t *)); 54145516Sdarrenr 55145516Sdarrenrstatic void ippr_rpcb_flush __P((rpcb_session_t *)); 56145516Sdarrenrstatic int ippr_rpcb_decodereq __P((fr_info_t *, nat_t *, 57145516Sdarrenr rpcb_session_t *, rpc_msg_t *)); 58145516Sdarrenrstatic int ippr_rpcb_skipauth __P((rpc_msg_t *, xdr_auth_t *, u_32_t **)); 59145516Sdarrenrstatic int ippr_rpcb_insert __P((rpcb_session_t *, rpcb_xact_t *)); 60145516Sdarrenrstatic int ippr_rpcb_xdrrpcb __P((rpc_msg_t *, u_32_t *, rpcb_args_t *)); 61145516Sdarrenrstatic int ippr_rpcb_getuaddr __P((rpc_msg_t *, xdr_uaddr_t *, 62145516Sdarrenr u_32_t **)); 63145516Sdarrenrstatic u_int ippr_rpcb_atoi __P((char *)); 64145516Sdarrenrstatic int ippr_rpcb_modreq __P((fr_info_t *, nat_t *, rpc_msg_t *, 65145516Sdarrenr mb_t *, u_int)); 66145516Sdarrenrstatic int ippr_rpcb_decoderep __P((fr_info_t *, nat_t *, 67145516Sdarrenr rpcb_session_t *, rpc_msg_t *, rpcb_xact_t **)); 68145516Sdarrenrstatic rpcb_xact_t * ippr_rpcb_lookup __P((rpcb_session_t *, u_32_t)); 69145516Sdarrenrstatic void ippr_rpcb_deref __P((rpcb_session_t *, rpcb_xact_t *)); 70145516Sdarrenrstatic int ippr_rpcb_getproto __P((rpc_msg_t *, xdr_proto_t *, 71145516Sdarrenr u_32_t **)); 72145516Sdarrenrstatic int ippr_rpcb_getnat __P((fr_info_t *, nat_t *, u_int, u_int)); 73145516Sdarrenrstatic int ippr_rpcb_modv3 __P((fr_info_t *, nat_t *, rpc_msg_t *, 74145516Sdarrenr mb_t *, u_int)); 75145516Sdarrenrstatic int ippr_rpcb_modv4 __P((fr_info_t *, nat_t *, rpc_msg_t *, 76145516Sdarrenr mb_t *, u_int)); 77145516Sdarrenrstatic void ippr_rpcb_fixlen __P((fr_info_t *, int)); 78145516Sdarrenr 79145516Sdarrenr/* 80145516Sdarrenr * Global variables 81145516Sdarrenr */ 82145516Sdarrenrstatic frentry_t rpcbfr; /* Skeleton rule for reference by entities 83145516Sdarrenr this proxy creates. */ 84145516Sdarrenrstatic int rpcbcnt; /* Upper bound of allocated RPCB sessions. */ 85145516Sdarrenr /* XXX rpcbcnt still requires locking. */ 86145516Sdarrenr 87145516Sdarrenrint rpcb_proxy_init = 0; 88145516Sdarrenr 89145516Sdarrenr 90145516Sdarrenr/* 91145516Sdarrenr * Since rpc_msg contains only pointers, one should use this macro as a 92145516Sdarrenr * handy way to get to the goods. (In case you're wondering about the name, 93145516Sdarrenr * this started as BYTEREF -> BREF -> B.) 94145516Sdarrenr */ 95145516Sdarrenr#define B(r) (u_32_t)ntohl(*(r)) 96145516Sdarrenr 97145516Sdarrenr/* 98145516Sdarrenr * Public subroutines 99145516Sdarrenr */ 100145516Sdarrenr 101145516Sdarrenr/* -------------------------------------------------------------------- */ 102145516Sdarrenr/* Function: ippr_rpcb_init */ 103145516Sdarrenr/* Returns: int - 0 == success */ 104145516Sdarrenr/* Parameters: (void) */ 105145516Sdarrenr/* */ 106145516Sdarrenr/* Initialize the filter rule entry and session limiter. */ 107145516Sdarrenr/* -------------------------------------------------------------------- */ 108145516Sdarrenrint 109145516Sdarrenrippr_rpcb_init() 110145516Sdarrenr{ 111145516Sdarrenr rpcbcnt = 0; 112145516Sdarrenr 113145516Sdarrenr bzero((char *)&rpcbfr, sizeof(rpcbfr)); 114145516Sdarrenr rpcbfr.fr_ref = 1; 115145516Sdarrenr rpcbfr.fr_flags = FR_PASS|FR_QUICK|FR_KEEPSTATE; 116145516Sdarrenr MUTEX_INIT(&rpcbfr.fr_lock, "ipf Sun RPCB proxy rule lock"); 117145516Sdarrenr rpcb_proxy_init = 1; 118145516Sdarrenr 119145516Sdarrenr return(0); 120145516Sdarrenr} 121145516Sdarrenr 122145516Sdarrenr/* -------------------------------------------------------------------- */ 123145516Sdarrenr/* Function: ippr_rpcb_fini */ 124145516Sdarrenr/* Returns: void */ 125145516Sdarrenr/* Parameters: (void) */ 126145516Sdarrenr/* */ 127145516Sdarrenr/* Destroy rpcbfr's mutex to avoid a lock leak. */ 128145516Sdarrenr/* -------------------------------------------------------------------- */ 129145516Sdarrenrvoid 130145516Sdarrenrippr_rpcb_fini() 131145516Sdarrenr{ 132145516Sdarrenr if (rpcb_proxy_init == 1) { 133145516Sdarrenr MUTEX_DESTROY(&rpcbfr.fr_lock); 134145516Sdarrenr rpcb_proxy_init = 0; 135145516Sdarrenr } 136145516Sdarrenr} 137145516Sdarrenr 138145516Sdarrenr/* -------------------------------------------------------------------- */ 139145516Sdarrenr/* Function: ippr_rpcb_new */ 140145516Sdarrenr/* Returns: int - -1 == failure, 0 == success */ 141145516Sdarrenr/* Parameters: fin(I) - pointer to packet information */ 142145516Sdarrenr/* aps(I) - pointer to proxy session structure */ 143145516Sdarrenr/* nat(I) - pointer to NAT session structure */ 144145516Sdarrenr/* */ 145145516Sdarrenr/* Allocate resources for per-session proxy structures. */ 146145516Sdarrenr/* -------------------------------------------------------------------- */ 147145516Sdarrenrint 148145516Sdarrenrippr_rpcb_new(fin, aps, nat) 149145516Sdarrenr fr_info_t *fin; 150145516Sdarrenr ap_session_t *aps; 151145516Sdarrenr nat_t *nat; 152145516Sdarrenr{ 153145516Sdarrenr rpcb_session_t *rs; 154145516Sdarrenr 155145516Sdarrenr fin = fin; /* LINT */ 156145516Sdarrenr nat = nat; /* LINT */ 157145516Sdarrenr 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/* -------------------------------------------------------------------- */ 171145516Sdarrenr/* Function: ippr_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 178145516Sdarrenrippr_rpcb_del(aps) 179145516Sdarrenr ap_session_t *aps; 180145516Sdarrenr{ 181145516Sdarrenr rpcb_session_t *rs; 182145516Sdarrenr rs = (rpcb_session_t *)aps->aps_data; 183145516Sdarrenr 184145516Sdarrenr MUTEX_ENTER(&rs->rs_rxlock); 185145516Sdarrenr ippr_rpcb_flush(rs); 186145516Sdarrenr MUTEX_EXIT(&rs->rs_rxlock); 187145516Sdarrenr MUTEX_DESTROY(&rs->rs_rxlock); 188145516Sdarrenr} 189145516Sdarrenr 190145516Sdarrenr/* -------------------------------------------------------------------- */ 191145516Sdarrenr/* Function: ippr_rpcb_in */ 192145516Sdarrenr/* Returns: int - APR_ERR(1) == drop the packet, */ 193145516Sdarrenr/* APR_ERR(2) == kill the proxy session, */ 194145516Sdarrenr/* else change in packet length (in bytes) */ 195145516Sdarrenr/* Parameters: fin(I) - pointer to packet information */ 196145516Sdarrenr/* ip(I) - pointer to packet header */ 197145516Sdarrenr/* aps(I) - pointer to proxy session structure */ 198145516Sdarrenr/* nat(I) - pointer to NAT session structure */ 199145516Sdarrenr/* */ 200145516Sdarrenr/* Given a presumed RPCB request, perform some minor tests and pass off */ 201145516Sdarrenr/* for decoding. Also pass packet off for a rewrite if necessary. */ 202145516Sdarrenr/* -------------------------------------------------------------------- */ 203145516Sdarrenrint 204145516Sdarrenrippr_rpcb_in(fin, aps, nat) 205145516Sdarrenr fr_info_t *fin; 206145516Sdarrenr ap_session_t *aps; 207145516Sdarrenr nat_t *nat; 208145516Sdarrenr{ 209145516Sdarrenr rpc_msg_t rpcmsg, *rm; 210145516Sdarrenr rpcb_session_t *rs; 211145516Sdarrenr u_int off, dlen; 212145516Sdarrenr mb_t *m; 213145516Sdarrenr int rv; 214145516Sdarrenr 215145516Sdarrenr /* Disallow fragmented or illegally short packets. */ 216145516Sdarrenr if ((fin->fin_flx & (FI_FRAG|FI_SHORT)) != 0) 217145516Sdarrenr return(APR_ERR(1)); 218145516Sdarrenr 219145516Sdarrenr /* Perform basic variable initialization. */ 220145516Sdarrenr rs = (rpcb_session_t *)aps->aps_data; 221145516Sdarrenr 222145516Sdarrenr m = fin->fin_m; 223145516Sdarrenr off = (char *)fin->fin_dp - (char *)fin->fin_ip; 224145516Sdarrenr off += sizeof(udphdr_t) + fin->fin_ipoff; 225145516Sdarrenr dlen = fin->fin_dlen - sizeof(udphdr_t); 226145516Sdarrenr 227145516Sdarrenr /* Disallow packets outside legal range for supported requests. */ 228145516Sdarrenr if ((dlen < RPCB_REQMIN) || (dlen > RPCB_REQMAX)) 229145516Sdarrenr return(APR_ERR(1)); 230145516Sdarrenr 231145516Sdarrenr /* Copy packet over to convenience buffer. */ 232145516Sdarrenr rm = &rpcmsg; 233145516Sdarrenr bzero((char *)rm, sizeof(*rm)); 234145516Sdarrenr COPYDATA(m, off, dlen, (caddr_t)&rm->rm_msgbuf); 235145516Sdarrenr rm->rm_buflen = dlen; 236145516Sdarrenr 237145516Sdarrenr /* Send off to decode request. */ 238145516Sdarrenr rv = ippr_rpcb_decodereq(fin, nat, rs, rm); 239145516Sdarrenr 240145516Sdarrenr switch(rv) 241145516Sdarrenr { 242145516Sdarrenr case -1: 243145516Sdarrenr return(APR_ERR(1)); 244145516Sdarrenr /*NOTREACHED*/ 245145516Sdarrenr break; 246145516Sdarrenr case 0: 247145516Sdarrenr break; 248145516Sdarrenr case 1: 249145516Sdarrenr rv = ippr_rpcb_modreq(fin, nat, rm, m, off); 250145516Sdarrenr break; 251145516Sdarrenr default: 252145516Sdarrenr /*CONSTANTCONDITION*/ 253145516Sdarrenr IPF_PANIC(1, ("illegal rv %d (ippr_rpcb_req)", rv)); 254145516Sdarrenr } 255145516Sdarrenr 256145516Sdarrenr return(rv); 257145516Sdarrenr} 258145516Sdarrenr 259145516Sdarrenr/* -------------------------------------------------------------------- */ 260145516Sdarrenr/* Function: ippr_rpcb_out */ 261145516Sdarrenr/* Returns: int - APR_ERR(1) == drop the packet, */ 262145516Sdarrenr/* APR_ERR(2) == kill the proxy session, */ 263145516Sdarrenr/* else change in packet length (in bytes) */ 264145516Sdarrenr/* Parameters: fin(I) - pointer to packet information */ 265145516Sdarrenr/* ip(I) - pointer to packet header */ 266145516Sdarrenr/* aps(I) - pointer to proxy session structure */ 267145516Sdarrenr/* nat(I) - pointer to NAT session structure */ 268145516Sdarrenr/* */ 269145516Sdarrenr/* Given a presumed RPCB reply, perform some minor tests and pass off */ 270145516Sdarrenr/* for decoding. If the message indicates a successful request with */ 271145516Sdarrenr/* valid addressing information, create NAT and state structures to */ 272145516Sdarrenr/* allow direct communication between RPC client and server. */ 273145516Sdarrenr/* -------------------------------------------------------------------- */ 274145516Sdarrenrint 275145516Sdarrenrippr_rpcb_out(fin, aps, nat) 276145516Sdarrenr fr_info_t *fin; 277145516Sdarrenr ap_session_t *aps; 278145516Sdarrenr nat_t *nat; 279145516Sdarrenr{ 280145516Sdarrenr rpc_msg_t rpcmsg, *rm; 281145516Sdarrenr rpcb_session_t *rs; 282145516Sdarrenr rpcb_xact_t *rx; 283145516Sdarrenr u_int off, dlen; 284145516Sdarrenr int rv, diff; 285145516Sdarrenr mb_t *m; 286145516Sdarrenr 287145516Sdarrenr /* Disallow fragmented or illegally short packets. */ 288145516Sdarrenr if ((fin->fin_flx & (FI_FRAG|FI_SHORT)) != 0) 289145516Sdarrenr return(APR_ERR(1)); 290145516Sdarrenr 291145516Sdarrenr /* Perform basic variable initialization. */ 292145516Sdarrenr rs = (rpcb_session_t *)aps->aps_data; 293170263Sdarrenr rx = NULL; 294145516Sdarrenr 295145516Sdarrenr m = fin->fin_m; 296145516Sdarrenr off = (char *)fin->fin_dp - (char *)fin->fin_ip; 297145516Sdarrenr off += sizeof(udphdr_t) + fin->fin_ipoff; 298145516Sdarrenr dlen = fin->fin_dlen - sizeof(udphdr_t); 299145516Sdarrenr diff = 0; 300145516Sdarrenr 301145516Sdarrenr /* Disallow packets outside legal range for supported requests. */ 302145516Sdarrenr if ((dlen < RPCB_REPMIN) || (dlen > RPCB_REPMAX)) 303145516Sdarrenr return(APR_ERR(1)); 304145516Sdarrenr 305145516Sdarrenr /* Copy packet over to convenience buffer. */ 306145516Sdarrenr rm = &rpcmsg; 307145516Sdarrenr bzero((char *)rm, sizeof(*rm)); 308145516Sdarrenr COPYDATA(m, off, dlen, (caddr_t)&rm->rm_msgbuf); 309145516Sdarrenr rm->rm_buflen = dlen; 310145516Sdarrenr 311170263Sdarrenr rx = NULL; /* XXX gcc */ 312170263Sdarrenr 313145516Sdarrenr /* Send off to decode reply. */ 314145516Sdarrenr rv = ippr_rpcb_decoderep(fin, nat, rs, rm, &rx); 315145516Sdarrenr 316145516Sdarrenr switch(rv) 317145516Sdarrenr { 318145516Sdarrenr case -1: /* Bad packet */ 319145516Sdarrenr if (rx != NULL) { 320145516Sdarrenr MUTEX_ENTER(&rs->rs_rxlock); 321145516Sdarrenr ippr_rpcb_deref(rs, rx); 322145516Sdarrenr MUTEX_EXIT(&rs->rs_rxlock); 323145516Sdarrenr } 324145516Sdarrenr return(APR_ERR(1)); 325145516Sdarrenr /*NOTREACHED*/ 326145516Sdarrenr break; 327145516Sdarrenr case 0: /* Negative reply / request rejected */ 328145516Sdarrenr break; 329145516Sdarrenr case 1: /* Positive reply */ 330145516Sdarrenr /* 331145516Sdarrenr * With the IP address embedded in a GETADDR(LIST) reply, 332145516Sdarrenr * we'll need to rewrite the packet in the very possible 333145516Sdarrenr * event that the internal & external addresses aren't the 334145516Sdarrenr * same. (i.e., this box is either a router or rpcbind 335145516Sdarrenr * only listens on loopback.) 336145516Sdarrenr */ 337145516Sdarrenr if (nat->nat_inip.s_addr != nat->nat_outip.s_addr) { 338145516Sdarrenr if (rx->rx_type == RPCB_RES_STRING) 339145516Sdarrenr diff = ippr_rpcb_modv3(fin, nat, rm, m, off); 340145516Sdarrenr else if (rx->rx_type == RPCB_RES_LIST) 341145516Sdarrenr diff = ippr_rpcb_modv4(fin, nat, rm, m, off); 342145516Sdarrenr } 343145516Sdarrenr break; 344145516Sdarrenr default: 345145516Sdarrenr /*CONSTANTCONDITION*/ 346145516Sdarrenr IPF_PANIC(1, ("illegal rv %d (ippr_rpcb_decoderep)", rv)); 347145516Sdarrenr } 348145516Sdarrenr 349145516Sdarrenr if (rx != NULL) { 350145516Sdarrenr MUTEX_ENTER(&rs->rs_rxlock); 351145516Sdarrenr /* XXX Gross hack - I'm overloading the reference 352145516Sdarrenr * counter to deal with both threads and retransmitted 353145516Sdarrenr * requests. One deref signals that this thread is 354145516Sdarrenr * finished with rx, and the other signals that we've 355145516Sdarrenr * processed its reply. 356145516Sdarrenr */ 357145516Sdarrenr ippr_rpcb_deref(rs, rx); 358145516Sdarrenr ippr_rpcb_deref(rs, rx); 359145516Sdarrenr MUTEX_EXIT(&rs->rs_rxlock); 360145516Sdarrenr } 361145516Sdarrenr 362145516Sdarrenr return(diff); 363145516Sdarrenr} 364145516Sdarrenr 365145516Sdarrenr/* 366145516Sdarrenr * Private support subroutines 367145516Sdarrenr */ 368145516Sdarrenr 369145516Sdarrenr/* -------------------------------------------------------------------- */ 370145516Sdarrenr/* Function: ippr_rpcb_flush */ 371145516Sdarrenr/* Returns: void */ 372145516Sdarrenr/* Parameters: rs(I) - pointer to RPCB session structure */ 373145516Sdarrenr/* */ 374145516Sdarrenr/* Simply flushes the list of outstanding transactions, if any. */ 375145516Sdarrenr/* -------------------------------------------------------------------- */ 376145516Sdarrenrstatic void 377145516Sdarrenrippr_rpcb_flush(rs) 378145516Sdarrenr rpcb_session_t *rs; 379145516Sdarrenr{ 380145516Sdarrenr rpcb_xact_t *r1, *r2; 381145516Sdarrenr 382145516Sdarrenr r1 = rs->rs_rxlist; 383145516Sdarrenr if (r1 == NULL) 384145516Sdarrenr return; 385145516Sdarrenr 386145516Sdarrenr while (r1 != NULL) { 387145516Sdarrenr r2 = r1; 388145516Sdarrenr r1 = r1->rx_next; 389145516Sdarrenr KFREE(r2); 390145516Sdarrenr } 391145516Sdarrenr} 392145516Sdarrenr 393145516Sdarrenr/* -------------------------------------------------------------------- */ 394145516Sdarrenr/* Function: ippr_rpcb_decodereq */ 395145516Sdarrenr/* Returns: int - -1 == bad request or critical failure, */ 396145516Sdarrenr/* 0 == request successfully decoded, */ 397145516Sdarrenr/* 1 == request successfully decoded; requires */ 398145516Sdarrenr/* address rewrite/modification */ 399145516Sdarrenr/* Parameters: fin(I) - pointer to packet information */ 400145516Sdarrenr/* nat(I) - pointer to NAT session structure */ 401145516Sdarrenr/* rs(I) - pointer to RPCB session structure */ 402145516Sdarrenr/* rm(I) - pointer to RPC message structure */ 403145516Sdarrenr/* */ 404145516Sdarrenr/* Take a presumed RPCB request, decode it, and store the results in */ 405145516Sdarrenr/* the transaction list. If the internal target address needs to be */ 406145516Sdarrenr/* modified, store its location in ptr. */ 407145516Sdarrenr/* WARNING: It's the responsibility of the caller to make sure there */ 408145516Sdarrenr/* is enough room in rs_buf for the basic RPC message "preamble". */ 409145516Sdarrenr/* -------------------------------------------------------------------- */ 410145516Sdarrenrstatic int 411145516Sdarrenrippr_rpcb_decodereq(fin, nat, rs, rm) 412145516Sdarrenr fr_info_t *fin; 413145516Sdarrenr nat_t *nat; 414145516Sdarrenr rpcb_session_t *rs; 415145516Sdarrenr rpc_msg_t *rm; 416145516Sdarrenr{ 417145516Sdarrenr rpcb_args_t *ra; 418145516Sdarrenr u_32_t xdr, *p; 419145516Sdarrenr rpc_call_t *rc; 420145516Sdarrenr rpcb_xact_t rx; 421145516Sdarrenr int mod; 422145516Sdarrenr 423145516Sdarrenr p = (u_32_t *)rm->rm_msgbuf; 424145516Sdarrenr mod = 0; 425145516Sdarrenr 426145516Sdarrenr bzero((char *)&rx, sizeof(rx)); 427145516Sdarrenr rc = &rm->rm_call; 428145516Sdarrenr 429145516Sdarrenr rm->rm_xid = p; 430145516Sdarrenr rx.rx_xid = B(p++); /* Record this message's XID. */ 431145516Sdarrenr 432145516Sdarrenr /* Parse out and test the RPC header. */ 433145516Sdarrenr if ((B(p++) != RPCB_CALL) || 434145516Sdarrenr (B(p++) != RPCB_MSG_VERSION) || 435145516Sdarrenr (B(p++) != RPCB_PROG)) 436145516Sdarrenr return(-1); 437145516Sdarrenr 438145516Sdarrenr /* Record the RPCB version and procedure. */ 439145516Sdarrenr rc->rc_vers = p++; 440145516Sdarrenr rc->rc_proc = p++; 441145516Sdarrenr 442145516Sdarrenr /* Bypass RPC authentication stuff. */ 443145516Sdarrenr if (ippr_rpcb_skipauth(rm, &rc->rc_authcred, &p) != 0) 444145516Sdarrenr return(-1); 445145516Sdarrenr if (ippr_rpcb_skipauth(rm, &rc->rc_authverf, &p) != 0) 446145516Sdarrenr return(-1); 447145516Sdarrenr 448145516Sdarrenr /* Compare RPCB version and procedure numbers. */ 449145516Sdarrenr switch(B(rc->rc_vers)) 450145516Sdarrenr { 451145516Sdarrenr case 2: 452145516Sdarrenr /* This proxy only supports PMAP_GETPORT. */ 453145516Sdarrenr if (B(rc->rc_proc) != RPCB_GETPORT) 454145516Sdarrenr return(-1); 455145516Sdarrenr 456145516Sdarrenr /* Portmap requests contain four 4 byte parameters. */ 457145516Sdarrenr if (RPCB_BUF_EQ(rm, p, 16) == 0) 458145516Sdarrenr return(-1); 459145516Sdarrenr 460145516Sdarrenr p += 2; /* Skip requested program and version numbers. */ 461145516Sdarrenr 462145516Sdarrenr /* Sanity check the requested protocol. */ 463145516Sdarrenr xdr = B(p); 464145516Sdarrenr if (!(xdr == IPPROTO_UDP || xdr == IPPROTO_TCP)) 465145516Sdarrenr return(-1); 466145516Sdarrenr 467145516Sdarrenr rx.rx_type = RPCB_RES_PMAP; 468145516Sdarrenr rx.rx_proto = xdr; 469145516Sdarrenr break; 470145516Sdarrenr case 3: 471145516Sdarrenr case 4: 472145516Sdarrenr /* GETADDRLIST is exclusive to v4; GETADDR for v3 & v4 */ 473145516Sdarrenr switch(B(rc->rc_proc)) 474145516Sdarrenr { 475145516Sdarrenr case RPCB_GETADDR: 476145516Sdarrenr rx.rx_type = RPCB_RES_STRING; 477145516Sdarrenr rx.rx_proto = (u_int)fin->fin_p; 478145516Sdarrenr break; 479145516Sdarrenr case RPCB_GETADDRLIST: 480145516Sdarrenr if (B(rc->rc_vers) != 4) 481145516Sdarrenr return(-1); 482145516Sdarrenr rx.rx_type = RPCB_RES_LIST; 483145516Sdarrenr break; 484145516Sdarrenr default: 485145516Sdarrenr return(-1); 486145516Sdarrenr } 487145516Sdarrenr 488145516Sdarrenr ra = &rc->rc_rpcbargs; 489145516Sdarrenr 490145516Sdarrenr /* Decode the 'struct rpcb' request. */ 491145516Sdarrenr if (ippr_rpcb_xdrrpcb(rm, p, ra) != 0) 492145516Sdarrenr return(-1); 493145516Sdarrenr 494145516Sdarrenr /* Are the target address & port valid? */ 495145516Sdarrenr if ((ra->ra_maddr.xu_ip != nat->nat_outip.s_addr) || 496145516Sdarrenr (ra->ra_maddr.xu_port != nat->nat_outport)) 497145516Sdarrenr return(-1); 498145516Sdarrenr 499145516Sdarrenr /* Do we need to rewrite this packet? */ 500145516Sdarrenr if ((nat->nat_outip.s_addr != nat->nat_inip.s_addr) || 501145516Sdarrenr (nat->nat_outport != nat->nat_inport)) 502145516Sdarrenr mod = 1; 503145516Sdarrenr break; 504145516Sdarrenr default: 505145516Sdarrenr return(-1); 506145516Sdarrenr } 507145516Sdarrenr 508145516Sdarrenr MUTEX_ENTER(&rs->rs_rxlock); 509145516Sdarrenr if (ippr_rpcb_insert(rs, &rx) != 0) { 510145516Sdarrenr MUTEX_EXIT(&rs->rs_rxlock); 511145516Sdarrenr return(-1); 512145516Sdarrenr } 513145516Sdarrenr MUTEX_EXIT(&rs->rs_rxlock); 514145516Sdarrenr 515145516Sdarrenr return(mod); 516145516Sdarrenr} 517145516Sdarrenr 518145516Sdarrenr/* -------------------------------------------------------------------- */ 519145516Sdarrenr/* Function: ippr_rpcb_skipauth */ 520145516Sdarrenr/* Returns: int -- -1 == illegal auth parameters (lengths) */ 521145516Sdarrenr/* 0 == valid parameters, pointer advanced */ 522145516Sdarrenr/* Parameters: rm(I) - pointer to RPC message structure */ 523145516Sdarrenr/* auth(I) - pointer to RPC auth structure */ 524145516Sdarrenr/* buf(IO) - pointer to location within convenience buffer */ 525145516Sdarrenr/* */ 526145516Sdarrenr/* Record auth data length & location of auth data, then advance past */ 527145516Sdarrenr/* it. */ 528145516Sdarrenr/* -------------------------------------------------------------------- */ 529145516Sdarrenrstatic int 530145516Sdarrenrippr_rpcb_skipauth(rm, auth, buf) 531145516Sdarrenr rpc_msg_t *rm; 532145516Sdarrenr xdr_auth_t *auth; 533145516Sdarrenr u_32_t **buf; 534145516Sdarrenr{ 535145516Sdarrenr u_32_t *p, xdr; 536145516Sdarrenr 537145516Sdarrenr p = *buf; 538145516Sdarrenr 539145516Sdarrenr /* Make sure we have enough space for expected fixed auth parms. */ 540145516Sdarrenr if (RPCB_BUF_GEQ(rm, p, 8) == 0) 541145516Sdarrenr return(-1); 542145516Sdarrenr 543145516Sdarrenr p++; /* We don't care about auth_flavor. */ 544145516Sdarrenr 545145516Sdarrenr auth->xa_string.xs_len = p; 546145516Sdarrenr xdr = B(p++); /* Length of auth_data */ 547145516Sdarrenr 548145516Sdarrenr /* Test for absurdity / illegality of auth_data length. */ 549145516Sdarrenr if ((XDRALIGN(xdr) < xdr) || (RPCB_BUF_GEQ(rm, p, XDRALIGN(xdr)) == 0)) 550145516Sdarrenr return(-1); 551145516Sdarrenr 552145516Sdarrenr auth->xa_string.xs_str = (char *)p; 553145516Sdarrenr 554145516Sdarrenr p += XDRALIGN(xdr); /* Advance our location. */ 555145516Sdarrenr 556145516Sdarrenr *buf = (u_32_t *)p; 557145516Sdarrenr 558145516Sdarrenr return(0); 559145516Sdarrenr} 560145516Sdarrenr 561145516Sdarrenr/* -------------------------------------------------------------------- */ 562145516Sdarrenr/* Function: ippr_rpcb_insert */ 563145516Sdarrenr/* Returns: int -- -1 == list insertion failed, */ 564145516Sdarrenr/* 0 == item successfully added */ 565145516Sdarrenr/* Parameters: rs(I) - pointer to RPCB session structure */ 566145516Sdarrenr/* rx(I) - pointer to RPCB transaction structure */ 567145516Sdarrenr/* -------------------------------------------------------------------- */ 568145516Sdarrenrstatic int 569145516Sdarrenrippr_rpcb_insert(rs, rx) 570145516Sdarrenr rpcb_session_t *rs; 571145516Sdarrenr rpcb_xact_t *rx; 572145516Sdarrenr{ 573145516Sdarrenr rpcb_xact_t *rxp; 574145516Sdarrenr 575145516Sdarrenr rxp = ippr_rpcb_lookup(rs, rx->rx_xid); 576145516Sdarrenr if (rxp != NULL) { 577145516Sdarrenr ++rxp->rx_ref; 578145516Sdarrenr return(0); 579145516Sdarrenr } 580145516Sdarrenr 581145516Sdarrenr if (rpcbcnt == RPCB_MAXREQS) 582145516Sdarrenr return(-1); 583145516Sdarrenr 584145516Sdarrenr KMALLOC(rxp, rpcb_xact_t *); 585145516Sdarrenr if (rxp == NULL) 586145516Sdarrenr return(-1); 587145516Sdarrenr 588145516Sdarrenr bcopy((char *)rx, (char *)rxp, sizeof(*rx)); 589145516Sdarrenr 590145516Sdarrenr if (rs->rs_rxlist != NULL) 591145516Sdarrenr rs->rs_rxlist->rx_pnext = &rxp->rx_next; 592145516Sdarrenr 593145516Sdarrenr rxp->rx_pnext = &rs->rs_rxlist; 594145516Sdarrenr rxp->rx_next = rs->rs_rxlist; 595145516Sdarrenr rs->rs_rxlist = rxp; 596145516Sdarrenr 597145516Sdarrenr rxp->rx_ref = 1; 598145516Sdarrenr 599145516Sdarrenr ++rpcbcnt; 600145516Sdarrenr 601145516Sdarrenr return(0); 602145516Sdarrenr} 603145516Sdarrenr 604145516Sdarrenr/* -------------------------------------------------------------------- */ 605145516Sdarrenr/* Function: ippr_rpcb_xdrrpcb */ 606145516Sdarrenr/* Returns: int -- -1 == failure to properly decode the request */ 607145516Sdarrenr/* 0 == rpcb successfully decoded */ 608145516Sdarrenr/* Parameters: rs(I) - pointer to RPCB session structure */ 609145516Sdarrenr/* p(I) - pointer to location within session buffer */ 610145516Sdarrenr/* rpcb(O) - pointer to rpcb (xdr type) structure */ 611145516Sdarrenr/* */ 612145516Sdarrenr/* Decode a XDR encoded rpcb structure and record its contents in rpcb */ 613145516Sdarrenr/* within only the context of TCP/UDP over IP networks. */ 614145516Sdarrenr/* -------------------------------------------------------------------- */ 615145516Sdarrenrstatic int 616145516Sdarrenrippr_rpcb_xdrrpcb(rm, p, ra) 617145516Sdarrenr rpc_msg_t *rm; 618145516Sdarrenr u_32_t *p; 619145516Sdarrenr rpcb_args_t *ra; 620145516Sdarrenr{ 621145516Sdarrenr if (!RPCB_BUF_GEQ(rm, p, 20)) 622145516Sdarrenr return(-1); 623145516Sdarrenr 624145516Sdarrenr /* Bypass target program & version. */ 625145516Sdarrenr p += 2; 626145516Sdarrenr 627145516Sdarrenr /* Decode r_netid. Must be "tcp" or "udp". */ 628145516Sdarrenr if (ippr_rpcb_getproto(rm, &ra->ra_netid, &p) != 0) 629145516Sdarrenr return(-1); 630145516Sdarrenr 631145516Sdarrenr /* Decode r_maddr. */ 632145516Sdarrenr if (ippr_rpcb_getuaddr(rm, &ra->ra_maddr, &p) != 0) 633145516Sdarrenr return(-1); 634145516Sdarrenr 635145516Sdarrenr /* Advance to r_owner and make sure it's empty. */ 636145516Sdarrenr if (!RPCB_BUF_EQ(rm, p, 4) || (B(p) != 0)) 637145516Sdarrenr return(-1); 638145516Sdarrenr 639145516Sdarrenr return(0); 640145516Sdarrenr} 641145516Sdarrenr 642145516Sdarrenr/* -------------------------------------------------------------------- */ 643145516Sdarrenr/* Function: ippr_rpcb_getuaddr */ 644145516Sdarrenr/* Returns: int -- -1 == illegal string, */ 645145516Sdarrenr/* 0 == string parsed; contents recorded */ 646145516Sdarrenr/* Parameters: rm(I) - pointer to RPC message structure */ 647145516Sdarrenr/* xu(I) - pointer to universal address structure */ 648145516Sdarrenr/* p(IO) - pointer to location within message buffer */ 649145516Sdarrenr/* */ 650145516Sdarrenr/* Decode the IP address / port at p and record them in xu. */ 651145516Sdarrenr/* -------------------------------------------------------------------- */ 652145516Sdarrenrstatic int 653145516Sdarrenrippr_rpcb_getuaddr(rm, xu, p) 654145516Sdarrenr rpc_msg_t *rm; 655145516Sdarrenr xdr_uaddr_t *xu; 656145516Sdarrenr u_32_t **p; 657145516Sdarrenr{ 658145516Sdarrenr char *c, *i, *b, *pp; 659145516Sdarrenr u_int d, dd, l, t; 660145516Sdarrenr char uastr[24]; 661145516Sdarrenr 662145516Sdarrenr /* Test for string length. */ 663145516Sdarrenr if (!RPCB_BUF_GEQ(rm, *p, 4)) 664145516Sdarrenr return(-1); 665145516Sdarrenr 666145516Sdarrenr xu->xu_xslen = (*p)++; 667145516Sdarrenr xu->xu_xsstr = (char *)*p; 668145516Sdarrenr 669145516Sdarrenr /* Length check */ 670145516Sdarrenr l = B(xu->xu_xslen); 671145516Sdarrenr if (l < 11 || l > 23 || !RPCB_BUF_GEQ(rm, *p, XDRALIGN(l))) 672145516Sdarrenr return(-1); 673145516Sdarrenr 674145516Sdarrenr /* Advance p */ 675145516Sdarrenr *(char **)p += XDRALIGN(l); 676145516Sdarrenr 677145516Sdarrenr /* Copy string to local buffer & terminate C style */ 678145516Sdarrenr bcopy(xu->xu_xsstr, uastr, l); 679145516Sdarrenr uastr[l] = '\0'; 680145516Sdarrenr 681145516Sdarrenr i = (char *)&xu->xu_ip; 682145516Sdarrenr pp = (char *)&xu->xu_port; 683145516Sdarrenr 684145516Sdarrenr /* 685145516Sdarrenr * Expected format: a.b.c.d.e.f where [a-d] correspond to bytes of 686145516Sdarrenr * an IP address and [ef] are the bytes of a L4 port. 687145516Sdarrenr */ 688145516Sdarrenr if (!(ISDIGIT(uastr[0]) && ISDIGIT(uastr[l-1]))) 689145516Sdarrenr return(-1); 690145516Sdarrenr b = uastr; 691145516Sdarrenr for (c = &uastr[1], d = 0, dd = 0; c < &uastr[l-1]; c++) { 692145516Sdarrenr if (ISDIGIT(*c)) { 693145516Sdarrenr dd = 0; 694145516Sdarrenr continue; 695145516Sdarrenr } 696145516Sdarrenr if (*c == '.') { 697145516Sdarrenr if (dd != 0) 698145516Sdarrenr return(-1); 699145516Sdarrenr 700145516Sdarrenr /* Check for ASCII byte. */ 701145516Sdarrenr *c = '\0'; 702145516Sdarrenr t = ippr_rpcb_atoi(b); 703145516Sdarrenr if (t > 255) 704145516Sdarrenr return(-1); 705145516Sdarrenr 706145516Sdarrenr /* Aim b at beginning of the next byte. */ 707145516Sdarrenr b = c + 1; 708145516Sdarrenr 709145516Sdarrenr /* Switch off IP addr vs port parsing. */ 710145516Sdarrenr if (d < 4) 711145516Sdarrenr i[d++] = t & 0xff; 712145516Sdarrenr else 713145516Sdarrenr pp[d++ - 4] = t & 0xff; 714145516Sdarrenr 715145516Sdarrenr dd = 1; 716145516Sdarrenr continue; 717145516Sdarrenr } 718145516Sdarrenr return(-1); 719145516Sdarrenr } 720145516Sdarrenr if (d != 5) /* String must contain exactly 5 periods. */ 721145516Sdarrenr return(-1); 722145516Sdarrenr 723145516Sdarrenr /* Handle the last byte (port low byte) */ 724145516Sdarrenr t = ippr_rpcb_atoi(b); 725145516Sdarrenr if (t > 255) 726145516Sdarrenr return(-1); 727145516Sdarrenr pp[d - 4] = t & 0xff; 728145516Sdarrenr 729145516Sdarrenr return(0); 730145516Sdarrenr} 731145516Sdarrenr 732145516Sdarrenr/* -------------------------------------------------------------------- */ 733145516Sdarrenr/* Function: ippr_rpcb_atoi (XXX should be generic for all proxies) */ 734145516Sdarrenr/* Returns: int -- integer representation of supplied string */ 735145516Sdarrenr/* Parameters: ptr(I) - input string */ 736145516Sdarrenr/* */ 737145516Sdarrenr/* Simple version of atoi(3) ripped from ip_rcmd_pxy.c. */ 738145516Sdarrenr/* -------------------------------------------------------------------- */ 739145516Sdarrenrstatic u_int 740145516Sdarrenrippr_rpcb_atoi(ptr) 741145516Sdarrenr char *ptr; 742145516Sdarrenr{ 743145516Sdarrenr register char *s = ptr, c; 744145516Sdarrenr register u_int i = 0; 745145516Sdarrenr 746145516Sdarrenr while (((c = *s++) != '\0') && ISDIGIT(c)) { 747145516Sdarrenr i *= 10; 748145516Sdarrenr i += c - '0'; 749145516Sdarrenr } 750145516Sdarrenr return i; 751145516Sdarrenr} 752145516Sdarrenr 753145516Sdarrenr/* -------------------------------------------------------------------- */ 754145516Sdarrenr/* Function: ippr_rpcb_modreq */ 755145516Sdarrenr/* Returns: int -- change in datagram length */ 756145516Sdarrenr/* APR_ERR(2) - critical failure */ 757145516Sdarrenr/* Parameters: fin(I) - pointer to packet information */ 758145516Sdarrenr/* nat(I) - pointer to NAT session */ 759145516Sdarrenr/* rm(I) - pointer to RPC message structure */ 760145516Sdarrenr/* m(I) - pointer to mbuf chain */ 761145516Sdarrenr/* off(I) - current offset within mbuf chain */ 762145516Sdarrenr/* */ 763145516Sdarrenr/* When external and internal addresses differ, we rewrite the former */ 764145516Sdarrenr/* with the latter. (This is exclusive to protocol versions 3 & 4). */ 765145516Sdarrenr/* -------------------------------------------------------------------- */ 766145516Sdarrenrstatic int 767145516Sdarrenrippr_rpcb_modreq(fin, nat, rm, m, off) 768145516Sdarrenr fr_info_t *fin; 769145516Sdarrenr nat_t *nat; 770145516Sdarrenr rpc_msg_t *rm; 771145516Sdarrenr mb_t *m; 772145516Sdarrenr u_int off; 773145516Sdarrenr{ 774145516Sdarrenr u_int len, xlen, pos, bogo; 775145516Sdarrenr rpcb_args_t *ra; 776145516Sdarrenr char uaddr[24]; 777145516Sdarrenr udphdr_t *udp; 778145516Sdarrenr char *i, *p; 779145516Sdarrenr int diff; 780145516Sdarrenr 781145516Sdarrenr ra = &rm->rm_call.rc_rpcbargs; 782145516Sdarrenr i = (char *)&nat->nat_inip.s_addr; 783145516Sdarrenr p = (char *)&nat->nat_inport; 784145516Sdarrenr 785145516Sdarrenr /* Form new string. */ 786145516Sdarrenr bzero(uaddr, sizeof(uaddr)); /* Just in case we need padding. */ 787145516Sdarrenr#if defined(SNPRINTF) && defined(_KERNEL) 788145516Sdarrenr SNPRINTF(uaddr, sizeof(uaddr), 789145516Sdarrenr#else 790145516Sdarrenr (void) sprintf(uaddr, 791145516Sdarrenr#endif 792145516Sdarrenr "%u.%u.%u.%u.%u.%u", i[0] & 0xff, i[1] & 0xff, 793145516Sdarrenr i[2] & 0xff, i[3] & 0xff, p[0] & 0xff, p[1] & 0xff); 794145516Sdarrenr len = strlen(uaddr); 795145516Sdarrenr xlen = XDRALIGN(len); 796145516Sdarrenr 797145516Sdarrenr /* Determine mbuf offset to start writing to. */ 798145516Sdarrenr pos = (char *)ra->ra_maddr.xu_xslen - rm->rm_msgbuf; 799145516Sdarrenr off += pos; 800145516Sdarrenr 801145516Sdarrenr /* Write new string length. */ 802145516Sdarrenr bogo = htonl(len); 803145516Sdarrenr COPYBACK(m, off, 4, (caddr_t)&bogo); 804145516Sdarrenr off += 4; 805145516Sdarrenr 806145516Sdarrenr /* Write new string. */ 807145516Sdarrenr COPYBACK(m, off, xlen, uaddr); 808145516Sdarrenr off += xlen; 809145516Sdarrenr 810145516Sdarrenr /* Write in zero r_owner. */ 811145516Sdarrenr bogo = 0; 812145516Sdarrenr COPYBACK(m, off, 4, (caddr_t)&bogo); 813145516Sdarrenr 814145516Sdarrenr /* Determine difference in data lengths. */ 815145516Sdarrenr diff = xlen - XDRALIGN(B(ra->ra_maddr.xu_xslen)); 816145516Sdarrenr 817145516Sdarrenr /* 818145516Sdarrenr * If our new string has a different length, make necessary 819145516Sdarrenr * adjustments. 820145516Sdarrenr */ 821145516Sdarrenr if (diff != 0) { 822145516Sdarrenr udp = fin->fin_dp; 823145516Sdarrenr udp->uh_ulen = htons(ntohs(udp->uh_ulen) + diff); 824145516Sdarrenr fin->fin_ip->ip_len += diff; 825145516Sdarrenr fin->fin_dlen += diff; 826145516Sdarrenr fin->fin_plen += diff; 827145516Sdarrenr /* XXX Storage lengths. */ 828145516Sdarrenr } 829145516Sdarrenr 830145516Sdarrenr return(diff); 831145516Sdarrenr} 832145516Sdarrenr 833145516Sdarrenr/* -------------------------------------------------------------------- */ 834145516Sdarrenr/* Function: ippr_rpcb_decoderep */ 835145516Sdarrenr/* Returns: int - -1 == bad request or critical failure, */ 836145516Sdarrenr/* 0 == valid, negative reply */ 837145516Sdarrenr/* 1 == vaddlid, positive reply; needs no changes */ 838145516Sdarrenr/* Parameters: fin(I) - pointer to packet information */ 839145516Sdarrenr/* nat(I) - pointer to NAT session structure */ 840145516Sdarrenr/* rs(I) - pointer to RPCB session structure */ 841145516Sdarrenr/* rm(I) - pointer to RPC message structure */ 842145516Sdarrenr/* rxp(O) - pointer to RPCB transaction structure */ 843145516Sdarrenr/* */ 844145516Sdarrenr/* Take a presumed RPCB reply, extract the XID, search for the original */ 845145516Sdarrenr/* request information, and determine whether the request was accepted */ 846145516Sdarrenr/* or rejected. With a valid accepted reply, go ahead and create NAT */ 847145516Sdarrenr/* and state entries, and finish up by rewriting the packet as */ 848145516Sdarrenr/* required. */ 849145516Sdarrenr/* */ 850145516Sdarrenr/* WARNING: It's the responsibility of the caller to make sure there */ 851145516Sdarrenr/* is enough room in rs_buf for the basic RPC message "preamble". */ 852145516Sdarrenr/* -------------------------------------------------------------------- */ 853145516Sdarrenrstatic int 854145516Sdarrenrippr_rpcb_decoderep(fin, nat, rs, rm, rxp) 855145516Sdarrenr fr_info_t *fin; 856145516Sdarrenr nat_t *nat; 857145516Sdarrenr rpcb_session_t *rs; 858145516Sdarrenr rpc_msg_t *rm; 859145516Sdarrenr rpcb_xact_t **rxp; 860145516Sdarrenr{ 861145516Sdarrenr rpcb_listp_t *rl; 862145516Sdarrenr rpcb_entry_t *re; 863145516Sdarrenr rpcb_xact_t *rx; 864145516Sdarrenr u_32_t xdr, *p; 865145516Sdarrenr rpc_resp_t *rr; 866145516Sdarrenr int rv, cnt; 867145516Sdarrenr 868145516Sdarrenr p = (u_32_t *)rm->rm_msgbuf; 869145516Sdarrenr 870145516Sdarrenr bzero((char *)&rx, sizeof(rx)); 871145516Sdarrenr rr = &rm->rm_resp; 872145516Sdarrenr 873145516Sdarrenr rm->rm_xid = p; 874145516Sdarrenr xdr = B(p++); /* Record this message's XID. */ 875145516Sdarrenr 876145516Sdarrenr /* Lookup XID */ 877145516Sdarrenr MUTEX_ENTER(&rs->rs_rxlock); 878145516Sdarrenr if ((rx = ippr_rpcb_lookup(rs, xdr)) == NULL) { 879145516Sdarrenr MUTEX_EXIT(&rs->rs_rxlock); 880145516Sdarrenr return(-1); 881145516Sdarrenr } 882145516Sdarrenr ++rx->rx_ref; /* per thread reference */ 883145516Sdarrenr MUTEX_EXIT(&rs->rs_rxlock); 884145516Sdarrenr 885145516Sdarrenr *rxp = rx; 886145516Sdarrenr 887145516Sdarrenr /* Test call vs reply */ 888145516Sdarrenr if (B(p++) != RPCB_REPLY) 889145516Sdarrenr return(-1); 890145516Sdarrenr 891145516Sdarrenr /* Test reply_stat */ 892145516Sdarrenr switch(B(p++)) 893145516Sdarrenr { 894145516Sdarrenr case RPCB_MSG_DENIED: 895145516Sdarrenr return(0); 896145516Sdarrenr case RPCB_MSG_ACCEPTED: 897145516Sdarrenr break; 898145516Sdarrenr default: 899145516Sdarrenr return(-1); 900145516Sdarrenr } 901145516Sdarrenr 902145516Sdarrenr /* Bypass RPC authentication stuff. */ 903145516Sdarrenr if (ippr_rpcb_skipauth(rm, &rr->rr_authverf, &p) != 0) 904145516Sdarrenr return(-1); 905145516Sdarrenr 906145516Sdarrenr /* Test accept status */ 907145516Sdarrenr if (!RPCB_BUF_GEQ(rm, p, 4)) 908145516Sdarrenr return(-1); 909145516Sdarrenr if (B(p++) != 0) 910145516Sdarrenr return(0); 911145516Sdarrenr 912145516Sdarrenr /* Parse out the expected reply */ 913145516Sdarrenr switch(rx->rx_type) 914145516Sdarrenr { 915145516Sdarrenr case RPCB_RES_PMAP: 916145516Sdarrenr /* There must be only one 4 byte argument. */ 917145516Sdarrenr if (!RPCB_BUF_EQ(rm, p, 4)) 918145516Sdarrenr return(-1); 919145516Sdarrenr 920145516Sdarrenr rr->rr_v2 = p; 921145516Sdarrenr xdr = B(rr->rr_v2); 922145516Sdarrenr 923145516Sdarrenr /* Reply w/ a 0 port indicates service isn't registered */ 924145516Sdarrenr if (xdr == 0) 925145516Sdarrenr return(0); 926145516Sdarrenr 927145516Sdarrenr /* Is the value sane? */ 928145516Sdarrenr if (xdr > 65535) 929145516Sdarrenr return(-1); 930145516Sdarrenr 931145516Sdarrenr /* Create NAT & state table entries. */ 932145516Sdarrenr if (ippr_rpcb_getnat(fin, nat, rx->rx_proto, (u_int)xdr) != 0) 933145516Sdarrenr return(-1); 934145516Sdarrenr break; 935145516Sdarrenr case RPCB_RES_STRING: 936145516Sdarrenr /* Expecting a XDR string; need 4 bytes for length */ 937145516Sdarrenr if (!RPCB_BUF_GEQ(rm, p, 4)) 938145516Sdarrenr return(-1); 939145516Sdarrenr 940145516Sdarrenr rr->rr_v3.xu_str.xs_len = p++; 941145516Sdarrenr rr->rr_v3.xu_str.xs_str = (char *)p; 942145516Sdarrenr 943145516Sdarrenr xdr = B(rr->rr_v3.xu_xslen); 944145516Sdarrenr 945145516Sdarrenr /* A null string indicates an unregistered service */ 946145516Sdarrenr if ((xdr == 0) && RPCB_BUF_EQ(rm, p, 0)) 947145516Sdarrenr return(0); 948145516Sdarrenr 949145516Sdarrenr /* Decode the target IP address / port. */ 950145516Sdarrenr if (ippr_rpcb_getuaddr(rm, &rr->rr_v3, &p) != 0) 951145516Sdarrenr return(-1); 952145516Sdarrenr 953145516Sdarrenr /* Validate the IP address and port contained. */ 954145516Sdarrenr if (nat->nat_inip.s_addr != rr->rr_v3.xu_ip) 955145516Sdarrenr return(-1); 956145516Sdarrenr 957145516Sdarrenr /* Create NAT & state table entries. */ 958145516Sdarrenr if (ippr_rpcb_getnat(fin, nat, rx->rx_proto, 959145516Sdarrenr (u_int)rr->rr_v3.xu_port) != 0) 960145516Sdarrenr return(-1); 961145516Sdarrenr break; 962145516Sdarrenr case RPCB_RES_LIST: 963145516Sdarrenr if (!RPCB_BUF_GEQ(rm, p, 4)) 964145516Sdarrenr return(-1); 965145516Sdarrenr /* rpcb_entry_list_ptr */ 966145516Sdarrenr switch(B(p)) 967145516Sdarrenr { 968145516Sdarrenr case 0: 969145516Sdarrenr return(0); 970145516Sdarrenr /*NOTREACHED*/ 971145516Sdarrenr break; 972145516Sdarrenr case 1: 973145516Sdarrenr break; 974145516Sdarrenr default: 975145516Sdarrenr return(-1); 976145516Sdarrenr } 977145516Sdarrenr rl = &rr->rr_v4; 978145516Sdarrenr rl->rl_list = p++; 979145516Sdarrenr cnt = 0; 980145516Sdarrenr 981145516Sdarrenr for(;;) { 982145516Sdarrenr re = &rl->rl_entries[rl->rl_cnt]; 983145516Sdarrenr if (ippr_rpcb_getuaddr(rm, &re->re_maddr, &p) != 0) 984145516Sdarrenr return(-1); 985145516Sdarrenr if (ippr_rpcb_getproto(rm, &re->re_netid, &p) != 0) 986145516Sdarrenr return(-1); 987145516Sdarrenr /* re_semantics & re_pfamily length */ 988145516Sdarrenr if (!RPCB_BUF_GEQ(rm, p, 12)) 989145516Sdarrenr return(-1); 990145516Sdarrenr p++; /* Skipping re_semantics. */ 991145516Sdarrenr xdr = B(p++); 992145516Sdarrenr if ((xdr != 4) || strncmp((char *)p, "inet", 4)) 993145516Sdarrenr return(-1); 994145516Sdarrenr p++; 995145516Sdarrenr if (ippr_rpcb_getproto(rm, &re->re_proto, &p) != 0) 996145516Sdarrenr return(-1); 997145516Sdarrenr if (!RPCB_BUF_GEQ(rm, p, 4)) 998145516Sdarrenr return(-1); 999145516Sdarrenr re->re_more = p; 1000145516Sdarrenr if (B(re->re_more) > 1) /* 0,1 only legal values */ 1001145516Sdarrenr return(-1); 1002145516Sdarrenr ++rl->rl_cnt; 1003145516Sdarrenr ++cnt; 1004145516Sdarrenr if (B(re->re_more) == 0) 1005145516Sdarrenr break; 1006145516Sdarrenr /* Replies in max out at 2; TCP and/or UDP */ 1007145516Sdarrenr if (cnt > 2) 1008145516Sdarrenr return(-1); 1009145516Sdarrenr p++; 1010145516Sdarrenr } 1011145516Sdarrenr 1012145516Sdarrenr for(rl->rl_cnt = 0; rl->rl_cnt < cnt; rl->rl_cnt++) { 1013145516Sdarrenr re = &rl->rl_entries[rl->rl_cnt]; 1014145516Sdarrenr rv = ippr_rpcb_getnat(fin, nat, 1015145516Sdarrenr re->re_proto.xp_proto, 1016145516Sdarrenr (u_int)re->re_maddr.xu_port); 1017145516Sdarrenr if (rv != 0) 1018145516Sdarrenr return(-1); 1019145516Sdarrenr } 1020145516Sdarrenr break; 1021145516Sdarrenr default: 1022145516Sdarrenr /*CONSTANTCONDITION*/ 1023145516Sdarrenr IPF_PANIC(1, ("illegal rx_type %d", rx->rx_type)); 1024145516Sdarrenr } 1025145516Sdarrenr 1026145516Sdarrenr return(1); 1027145516Sdarrenr} 1028145516Sdarrenr 1029145516Sdarrenr/* -------------------------------------------------------------------- */ 1030145516Sdarrenr/* Function: ippr_rpcb_lookup */ 1031145516Sdarrenr/* Returns: rpcb_xact_t * - NULL == no matching record, */ 1032145516Sdarrenr/* else pointer to relevant entry */ 1033145516Sdarrenr/* Parameters: rs(I) - pointer to RPCB session */ 1034145516Sdarrenr/* xid(I) - XID to look for */ 1035145516Sdarrenr/* -------------------------------------------------------------------- */ 1036145516Sdarrenrstatic rpcb_xact_t * 1037145516Sdarrenrippr_rpcb_lookup(rs, xid) 1038145516Sdarrenr rpcb_session_t *rs; 1039145516Sdarrenr u_32_t xid; 1040145516Sdarrenr{ 1041145516Sdarrenr rpcb_xact_t *rx; 1042145516Sdarrenr 1043145516Sdarrenr if (rs->rs_rxlist == NULL) 1044145516Sdarrenr return(NULL); 1045145516Sdarrenr 1046145516Sdarrenr for (rx = rs->rs_rxlist; rx != NULL; rx = rx->rx_next) 1047145516Sdarrenr if (rx->rx_xid == xid) 1048145516Sdarrenr break; 1049145516Sdarrenr 1050145516Sdarrenr return(rx); 1051145516Sdarrenr} 1052145516Sdarrenr 1053145516Sdarrenr/* -------------------------------------------------------------------- */ 1054145516Sdarrenr/* Function: ippr_rpcb_deref */ 1055145516Sdarrenr/* Returns: (void) */ 1056145516Sdarrenr/* Parameters: rs(I) - pointer to RPCB session */ 1057145516Sdarrenr/* rx(I) - pointer to RPC transaction struct to remove */ 1058145516Sdarrenr/* force(I) - indicates to delete entry regardless of */ 1059145516Sdarrenr/* reference count */ 1060145516Sdarrenr/* Locking: rs->rs_rxlock must be held write only */ 1061145516Sdarrenr/* */ 1062145516Sdarrenr/* Free the RPCB transaction record rx from the chain of entries. */ 1063145516Sdarrenr/* -------------------------------------------------------------------- */ 1064145516Sdarrenrstatic void 1065145516Sdarrenrippr_rpcb_deref(rs, rx) 1066145516Sdarrenr rpcb_session_t *rs; 1067145516Sdarrenr rpcb_xact_t *rx; 1068145516Sdarrenr{ 1069145516Sdarrenr rs = rs; /* LINT */ 1070145516Sdarrenr 1071145516Sdarrenr if (rx == NULL) 1072145516Sdarrenr return; 1073145516Sdarrenr 1074145516Sdarrenr if (--rx->rx_ref != 0) 1075145516Sdarrenr return; 1076145516Sdarrenr 1077145516Sdarrenr if (rx->rx_next != NULL) 1078145516Sdarrenr rx->rx_next->rx_pnext = rx->rx_pnext; 1079145516Sdarrenr 1080145516Sdarrenr *rx->rx_pnext = rx->rx_next; 1081145516Sdarrenr 1082145516Sdarrenr KFREE(rx); 1083145516Sdarrenr 1084145516Sdarrenr --rpcbcnt; 1085145516Sdarrenr} 1086145516Sdarrenr 1087145516Sdarrenr/* -------------------------------------------------------------------- */ 1088145516Sdarrenr/* Function: ippr_rpcb_getproto */ 1089145516Sdarrenr/* Returns: int - -1 == illegal protocol/netid, */ 1090145516Sdarrenr/* 0 == legal protocol/netid */ 1091145516Sdarrenr/* Parameters: rm(I) - pointer to RPC message structure */ 1092145516Sdarrenr/* xp(I) - pointer to netid structure */ 1093145516Sdarrenr/* p(IO) - pointer to location within packet buffer */ 1094145516Sdarrenr/* */ 1095145516Sdarrenr/* Decode netid/proto stored at p and record its numeric value. */ 1096145516Sdarrenr/* -------------------------------------------------------------------- */ 1097145516Sdarrenrstatic int 1098145516Sdarrenrippr_rpcb_getproto(rm, xp, p) 1099145516Sdarrenr rpc_msg_t *rm; 1100145516Sdarrenr xdr_proto_t *xp; 1101145516Sdarrenr u_32_t **p; 1102145516Sdarrenr{ 1103145516Sdarrenr u_int len; 1104145516Sdarrenr 1105145516Sdarrenr /* Must have 4 bytes for length & 4 bytes for "tcp" or "udp". */ 1106145516Sdarrenr if (!RPCB_BUF_GEQ(rm, p, 8)) 1107145516Sdarrenr return(-1); 1108145516Sdarrenr 1109145516Sdarrenr xp->xp_xslen = (*p)++; 1110145516Sdarrenr xp->xp_xsstr = (char *)*p; 1111145516Sdarrenr 1112145516Sdarrenr /* Test the string length. */ 1113145516Sdarrenr len = B(xp->xp_xslen); 1114145516Sdarrenr if (len != 3) 1115145516Sdarrenr return(-1); 1116145516Sdarrenr 1117145516Sdarrenr /* Test the actual string & record the protocol accordingly. */ 1118145516Sdarrenr if (!strncmp((char *)xp->xp_xsstr, "tcp\0", 4)) 1119145516Sdarrenr xp->xp_proto = IPPROTO_TCP; 1120145516Sdarrenr else if (!strncmp((char *)xp->xp_xsstr, "udp\0", 4)) 1121145516Sdarrenr xp->xp_proto = IPPROTO_UDP; 1122145516Sdarrenr else { 1123145516Sdarrenr return(-1); 1124145516Sdarrenr } 1125145516Sdarrenr 1126145516Sdarrenr /* Advance past the string. */ 1127145516Sdarrenr (*p)++; 1128145516Sdarrenr 1129145516Sdarrenr return(0); 1130145516Sdarrenr} 1131145516Sdarrenr 1132145516Sdarrenr/* -------------------------------------------------------------------- */ 1133145516Sdarrenr/* Function: ippr_rpcb_getnat */ 1134145516Sdarrenr/* Returns: int -- -1 == failed to create table entries, */ 1135145516Sdarrenr/* 0 == success */ 1136145516Sdarrenr/* Parameters: fin(I) - pointer to packet information */ 1137145516Sdarrenr/* nat(I) - pointer to NAT table entry */ 1138145516Sdarrenr/* proto(I) - transport protocol for new entries */ 1139145516Sdarrenr/* port(I) - new port to use w/ wildcard table entries */ 1140145516Sdarrenr/* */ 1141145516Sdarrenr/* Create state and NAT entries to handle an anticipated connection */ 1142145516Sdarrenr/* attempt between RPC client and server. */ 1143145516Sdarrenr/* -------------------------------------------------------------------- */ 1144145516Sdarrenrstatic int 1145145516Sdarrenrippr_rpcb_getnat(fin, nat, proto, port) 1146145516Sdarrenr fr_info_t *fin; 1147145516Sdarrenr nat_t *nat; 1148145516Sdarrenr u_int proto; 1149145516Sdarrenr u_int port; 1150145516Sdarrenr{ 1151145516Sdarrenr ipnat_t *ipn, ipnat; 1152145516Sdarrenr tcphdr_t tcp; 1153145516Sdarrenr ipstate_t *is; 1154145516Sdarrenr fr_info_t fi; 1155145516Sdarrenr nat_t *natl; 1156145516Sdarrenr int nflags; 1157145516Sdarrenr 1158145516Sdarrenr ipn = nat->nat_ptr; 1159145516Sdarrenr 1160145516Sdarrenr /* Generate dummy fr_info */ 1161145516Sdarrenr bcopy((char *)fin, (char *)&fi, sizeof(fi)); 1162170263Sdarrenr fi.fin_state = NULL; 1163170263Sdarrenr fi.fin_nat = NULL; 1164145516Sdarrenr fi.fin_out = 0; 1165145516Sdarrenr fi.fin_src = fin->fin_dst; 1166145516Sdarrenr fi.fin_dst = nat->nat_outip; 1167145516Sdarrenr fi.fin_p = proto; 1168145516Sdarrenr fi.fin_sport = 0; 1169145516Sdarrenr fi.fin_dport = port & 0xffff; 1170145516Sdarrenr fi.fin_flx |= FI_IGNORE; 1171145516Sdarrenr 1172145516Sdarrenr bzero((char *)&tcp, sizeof(tcp)); 1173145516Sdarrenr tcp.th_dport = htons(port); 1174145516Sdarrenr 1175145516Sdarrenr if (proto == IPPROTO_TCP) { 1176145516Sdarrenr tcp.th_win = htons(8192); 1177145516Sdarrenr TCP_OFF_A(&tcp, sizeof(tcphdr_t) >> 2); 1178145516Sdarrenr fi.fin_dlen = sizeof(tcphdr_t); 1179145516Sdarrenr tcp.th_flags = TH_SYN; 1180145516Sdarrenr nflags = NAT_TCP; 1181145516Sdarrenr } else { 1182145516Sdarrenr fi.fin_dlen = sizeof(udphdr_t); 1183145516Sdarrenr nflags = NAT_UDP; 1184145516Sdarrenr } 1185145516Sdarrenr 1186145516Sdarrenr nflags |= SI_W_SPORT|NAT_SEARCH; 1187145516Sdarrenr fi.fin_dp = &tcp; 1188145516Sdarrenr fi.fin_plen = fi.fin_hlen + fi.fin_dlen; 1189145516Sdarrenr 1190145516Sdarrenr /* 1191145516Sdarrenr * Search for existing NAT & state entries. Pay close attention to 1192145516Sdarrenr * mutexes / locks grabbed from lookup routines, as not doing so could 1193145516Sdarrenr * lead to bad things. 1194145516Sdarrenr * 1195145516Sdarrenr * If successful, fr_stlookup returns with ipf_state locked. We have 1196145516Sdarrenr * no use for this lock, so simply unlock it if necessary. 1197145516Sdarrenr */ 1198145516Sdarrenr is = fr_stlookup(&fi, &tcp, NULL); 1199170263Sdarrenr if (is != NULL) { 1200145516Sdarrenr RWLOCK_EXIT(&ipf_state); 1201170263Sdarrenr } 1202145516Sdarrenr 1203145516Sdarrenr RWLOCK_EXIT(&ipf_nat); 1204145516Sdarrenr 1205145516Sdarrenr WRITE_ENTER(&ipf_nat); 1206145516Sdarrenr natl = nat_inlookup(&fi, nflags, proto, fi.fin_src, fi.fin_dst); 1207145516Sdarrenr 1208145516Sdarrenr if ((natl != NULL) && (is != NULL)) { 1209145516Sdarrenr MUTEX_DOWNGRADE(&ipf_nat); 1210145516Sdarrenr return(0); 1211145516Sdarrenr } 1212145516Sdarrenr 1213145516Sdarrenr /* Slightly modify the following structures for actual use in creating 1214145516Sdarrenr * NAT and/or state entries. We're primarily concerned with stripping 1215145516Sdarrenr * flags that may be detrimental to the creation process or simply 1216145516Sdarrenr * shouldn't be associated with a table entry. 1217145516Sdarrenr */ 1218145516Sdarrenr fi.fin_fr = &rpcbfr; 1219145516Sdarrenr fi.fin_flx &= ~FI_IGNORE; 1220145516Sdarrenr nflags &= ~NAT_SEARCH; 1221145516Sdarrenr 1222145516Sdarrenr if (natl == NULL) { 1223145516Sdarrenr /* XXX Since we're just copying the original ipn contents 1224145516Sdarrenr * back, would we be better off just sending a pointer to 1225145516Sdarrenr * the 'temp' copy off to nat_new instead? 1226145516Sdarrenr */ 1227145516Sdarrenr /* Generate template/bogus NAT rule. */ 1228145516Sdarrenr bcopy((char *)ipn, (char *)&ipnat, sizeof(ipnat)); 1229145516Sdarrenr ipn->in_flags = nflags & IPN_TCPUDP; 1230145516Sdarrenr ipn->in_apr = NULL; 1231145516Sdarrenr ipn->in_p = proto; 1232145516Sdarrenr ipn->in_pmin = htons(fi.fin_dport); 1233145516Sdarrenr ipn->in_pmax = htons(fi.fin_dport); 1234145516Sdarrenr ipn->in_pnext = htons(fi.fin_dport); 1235145516Sdarrenr ipn->in_space = 1; 1236145516Sdarrenr ipn->in_ippip = 1; 1237145516Sdarrenr if (ipn->in_flags & IPN_FILTER) { 1238145516Sdarrenr ipn->in_scmp = 0; 1239145516Sdarrenr ipn->in_dcmp = 0; 1240145516Sdarrenr } 1241145516Sdarrenr *ipn->in_plabel = '\0'; 1242145516Sdarrenr 1243145516Sdarrenr /* Create NAT entry. return NULL if this fails. */ 1244145516Sdarrenr natl = nat_new(&fi, ipn, NULL, nflags|SI_CLONE|NAT_SLAVE, 1245145516Sdarrenr NAT_INBOUND); 1246145516Sdarrenr 1247145516Sdarrenr bcopy((char *)&ipnat, (char *)ipn, sizeof(ipnat)); 1248145516Sdarrenr 1249145516Sdarrenr if (natl == NULL) { 1250145516Sdarrenr MUTEX_DOWNGRADE(&ipf_nat); 1251145516Sdarrenr return(-1); 1252145516Sdarrenr } 1253145516Sdarrenr 1254145516Sdarrenr ipn->in_use++; 1255145516Sdarrenr (void) nat_proto(&fi, natl, nflags); 1256145516Sdarrenr nat_update(&fi, natl, natl->nat_ptr); 1257145516Sdarrenr } 1258145516Sdarrenr MUTEX_DOWNGRADE(&ipf_nat); 1259145516Sdarrenr 1260145516Sdarrenr if (is == NULL) { 1261145516Sdarrenr /* Create state entry. Return NULL if this fails. */ 1262145516Sdarrenr fi.fin_dst = nat->nat_inip; 1263145516Sdarrenr fi.fin_nat = (void *)natl; 1264145516Sdarrenr fi.fin_flx |= FI_NATED; 1265145516Sdarrenr fi.fin_flx &= ~FI_STATE; 1266145516Sdarrenr nflags &= NAT_TCPUDP; 1267145516Sdarrenr nflags |= SI_W_SPORT|SI_CLONE; 1268145516Sdarrenr 1269145516Sdarrenr is = fr_addstate(&fi, NULL, nflags); 1270145516Sdarrenr if (is == NULL) { 1271145516Sdarrenr /* 1272145516Sdarrenr * XXX nat_delete is private to ip_nat.c. Should 1273145516Sdarrenr * check w/ Darren about this one. 1274145516Sdarrenr * 1275145516Sdarrenr * nat_delete(natl, NL_EXPIRE); 1276145516Sdarrenr */ 1277145516Sdarrenr return(-1); 1278145516Sdarrenr } 1279145516Sdarrenr if (fi.fin_state != NULL) 1280170263Sdarrenr fr_statederef((ipstate_t **)&fi.fin_state); 1281145516Sdarrenr } 1282145516Sdarrenr 1283145516Sdarrenr return(0); 1284145516Sdarrenr} 1285145516Sdarrenr 1286145516Sdarrenr/* -------------------------------------------------------------------- */ 1287145516Sdarrenr/* Function: ippr_rpcb_modv3 */ 1288145516Sdarrenr/* Returns: int -- change in packet length */ 1289145516Sdarrenr/* Parameters: fin(I) - pointer to packet information */ 1290145516Sdarrenr/* nat(I) - pointer to NAT session */ 1291145516Sdarrenr/* rm(I) - pointer to RPC message structure */ 1292145516Sdarrenr/* m(I) - pointer to mbuf chain */ 1293145516Sdarrenr/* off(I) - offset within mbuf chain */ 1294145516Sdarrenr/* */ 1295145516Sdarrenr/* Write a new universal address string to this packet, adjusting */ 1296145516Sdarrenr/* lengths as necessary. */ 1297145516Sdarrenr/* -------------------------------------------------------------------- */ 1298145516Sdarrenrstatic int 1299145516Sdarrenrippr_rpcb_modv3(fin, nat, rm, m, off) 1300145516Sdarrenr fr_info_t *fin; 1301145516Sdarrenr nat_t *nat; 1302145516Sdarrenr rpc_msg_t *rm; 1303145516Sdarrenr mb_t *m; 1304145516Sdarrenr u_int off; 1305145516Sdarrenr{ 1306145516Sdarrenr u_int len, xlen, pos, bogo; 1307145516Sdarrenr rpc_resp_t *rr; 1308145516Sdarrenr char uaddr[24]; 1309145516Sdarrenr char *i, *p; 1310145516Sdarrenr int diff; 1311145516Sdarrenr 1312145516Sdarrenr rr = &rm->rm_resp; 1313145516Sdarrenr i = (char *)&nat->nat_outip.s_addr; 1314145516Sdarrenr p = (char *)&rr->rr_v3.xu_port; 1315145516Sdarrenr 1316145516Sdarrenr /* Form new string. */ 1317145516Sdarrenr bzero(uaddr, sizeof(uaddr)); /* Just in case we need padding. */ 1318145516Sdarrenr#if defined(SNPRINTF) && defined(_KERNEL) 1319145516Sdarrenr SNPRINTF(uaddr, sizeof(uaddr), 1320145516Sdarrenr#else 1321145516Sdarrenr (void) sprintf(uaddr, 1322145516Sdarrenr#endif 1323145516Sdarrenr "%u.%u.%u.%u.%u.%u", i[0] & 0xff, i[1] & 0xff, 1324145516Sdarrenr i[2] & 0xff, i[3] & 0xff, p[0] & 0xff, p[1] & 0xff); 1325145516Sdarrenr len = strlen(uaddr); 1326145516Sdarrenr xlen = XDRALIGN(len); 1327145516Sdarrenr 1328145516Sdarrenr /* Determine mbuf offset to write to. */ 1329145516Sdarrenr pos = (char *)rr->rr_v3.xu_xslen - rm->rm_msgbuf; 1330145516Sdarrenr off += pos; 1331145516Sdarrenr 1332145516Sdarrenr /* Write new string length. */ 1333145516Sdarrenr bogo = htonl(len); 1334145516Sdarrenr COPYBACK(m, off, 4, (caddr_t)&bogo); 1335145516Sdarrenr off += 4; 1336145516Sdarrenr 1337145516Sdarrenr /* Write new string. */ 1338145516Sdarrenr COPYBACK(m, off, xlen, uaddr); 1339145516Sdarrenr 1340145516Sdarrenr /* Determine difference in data lengths. */ 1341145516Sdarrenr diff = xlen - XDRALIGN(B(rr->rr_v3.xu_xslen)); 1342145516Sdarrenr 1343145516Sdarrenr /* 1344145516Sdarrenr * If our new string has a different length, make necessary 1345145516Sdarrenr * adjustments. 1346145516Sdarrenr */ 1347145516Sdarrenr if (diff != 0) 1348145516Sdarrenr ippr_rpcb_fixlen(fin, diff); 1349145516Sdarrenr 1350145516Sdarrenr return(diff); 1351145516Sdarrenr} 1352145516Sdarrenr 1353145516Sdarrenr/* -------------------------------------------------------------------- */ 1354145516Sdarrenr/* Function: ippr_rpcb_modv4 */ 1355145516Sdarrenr/* Returns: int -- change in packet length */ 1356145516Sdarrenr/* Parameters: fin(I) - pointer to packet information */ 1357145516Sdarrenr/* nat(I) - pointer to NAT session */ 1358145516Sdarrenr/* rm(I) - pointer to RPC message structure */ 1359145516Sdarrenr/* m(I) - pointer to mbuf chain */ 1360145516Sdarrenr/* off(I) - offset within mbuf chain */ 1361145516Sdarrenr/* */ 1362145516Sdarrenr/* Write new rpcb_entry list, adjusting lengths as necessary. */ 1363145516Sdarrenr/* -------------------------------------------------------------------- */ 1364145516Sdarrenrstatic int 1365145516Sdarrenrippr_rpcb_modv4(fin, nat, rm, m, off) 1366145516Sdarrenr fr_info_t *fin; 1367145516Sdarrenr nat_t *nat; 1368145516Sdarrenr rpc_msg_t *rm; 1369145516Sdarrenr mb_t *m; 1370145516Sdarrenr u_int off; 1371145516Sdarrenr{ 1372145516Sdarrenr u_int len, xlen, pos, bogo; 1373145516Sdarrenr rpcb_listp_t *rl; 1374145516Sdarrenr rpcb_entry_t *re; 1375145516Sdarrenr rpc_resp_t *rr; 1376145516Sdarrenr char uaddr[24]; 1377145516Sdarrenr int diff, cnt; 1378145516Sdarrenr char *i, *p; 1379145516Sdarrenr 1380145516Sdarrenr diff = 0; 1381145516Sdarrenr rr = &rm->rm_resp; 1382145516Sdarrenr rl = &rr->rr_v4; 1383145516Sdarrenr 1384145516Sdarrenr i = (char *)&nat->nat_outip.s_addr; 1385145516Sdarrenr 1386145516Sdarrenr /* Determine mbuf offset to write to. */ 1387145516Sdarrenr re = &rl->rl_entries[0]; 1388145516Sdarrenr pos = (char *)re->re_maddr.xu_xslen - rm->rm_msgbuf; 1389145516Sdarrenr off += pos; 1390145516Sdarrenr 1391145516Sdarrenr for (cnt = 0; cnt < rl->rl_cnt; cnt++) { 1392145516Sdarrenr re = &rl->rl_entries[cnt]; 1393145516Sdarrenr p = (char *)&re->re_maddr.xu_port; 1394145516Sdarrenr 1395145516Sdarrenr /* Form new string. */ 1396145516Sdarrenr bzero(uaddr, sizeof(uaddr)); /* Just in case we need 1397145516Sdarrenr padding. */ 1398145516Sdarrenr#if defined(SNPRINTF) && defined(_KERNEL) 1399145516Sdarrenr SNPRINTF(uaddr, sizeof(uaddr), 1400145516Sdarrenr#else 1401145516Sdarrenr (void) sprintf(uaddr, 1402145516Sdarrenr#endif 1403145516Sdarrenr "%u.%u.%u.%u.%u.%u", i[0] & 0xff, 1404145516Sdarrenr i[1] & 0xff, i[2] & 0xff, i[3] & 0xff, 1405145516Sdarrenr p[0] & 0xff, p[1] & 0xff); 1406145516Sdarrenr len = strlen(uaddr); 1407145516Sdarrenr xlen = XDRALIGN(len); 1408145516Sdarrenr 1409145516Sdarrenr /* Write new string length. */ 1410145516Sdarrenr bogo = htonl(len); 1411145516Sdarrenr COPYBACK(m, off, 4, (caddr_t)&bogo); 1412145516Sdarrenr off += 4; 1413145516Sdarrenr 1414145516Sdarrenr /* Write new string. */ 1415145516Sdarrenr COPYBACK(m, off, xlen, uaddr); 1416145516Sdarrenr off += xlen; 1417145516Sdarrenr 1418145516Sdarrenr /* Record any change in length. */ 1419145516Sdarrenr diff += xlen - XDRALIGN(B(re->re_maddr.xu_xslen)); 1420145516Sdarrenr 1421145516Sdarrenr /* If the length changed, copy back the rest of this entry. */ 1422145516Sdarrenr len = ((char *)re->re_more + 4) - 1423145516Sdarrenr (char *)re->re_netid.xp_xslen; 1424145516Sdarrenr if (diff != 0) { 1425145516Sdarrenr COPYBACK(m, off, len, (caddr_t)re->re_netid.xp_xslen); 1426145516Sdarrenr } 1427145516Sdarrenr off += len; 1428145516Sdarrenr } 1429145516Sdarrenr 1430145516Sdarrenr /* 1431145516Sdarrenr * If our new string has a different length, make necessary 1432145516Sdarrenr * adjustments. 1433145516Sdarrenr */ 1434145516Sdarrenr if (diff != 0) 1435145516Sdarrenr ippr_rpcb_fixlen(fin, diff); 1436145516Sdarrenr 1437145516Sdarrenr return(diff); 1438145516Sdarrenr} 1439145516Sdarrenr 1440145516Sdarrenr 1441145516Sdarrenr/* -------------------------------------------------------------------- */ 1442145516Sdarrenr/* Function: ippr_rpcb_fixlen */ 1443145516Sdarrenr/* Returns: (void) */ 1444145516Sdarrenr/* Parameters: fin(I) - pointer to packet information */ 1445145516Sdarrenr/* len(I) - change in packet length */ 1446145516Sdarrenr/* */ 1447145516Sdarrenr/* Adjust various packet related lengths held in structure and packet */ 1448145516Sdarrenr/* header fields. */ 1449145516Sdarrenr/* -------------------------------------------------------------------- */ 1450145516Sdarrenrstatic void 1451145516Sdarrenrippr_rpcb_fixlen(fin, len) 1452145516Sdarrenr fr_info_t *fin; 1453145516Sdarrenr int len; 1454145516Sdarrenr{ 1455145516Sdarrenr udphdr_t *udp; 1456145516Sdarrenr 1457145516Sdarrenr udp = fin->fin_dp; 1458145516Sdarrenr udp->uh_ulen = htons(ntohs(udp->uh_ulen) + len); 1459145516Sdarrenr fin->fin_ip->ip_len += len; 1460145516Sdarrenr fin->fin_dlen += len; 1461145516Sdarrenr fin->fin_plen += len; 1462145516Sdarrenr} 1463145516Sdarrenr 1464145516Sdarrenr#undef B 1465