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