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