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