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