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