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