ip_sync.c revision 147367
1/* $FreeBSD: head/sys/contrib/ipfilter/netinet/ip_sync.c 147367 2005-06-14 09:18:26Z darrenr $ */ 2 3/* 4 * Copyright (C) 1995-1998 by Darren Reed. 5 * 6 * See the IPFILTER.LICENCE file for details on licencing. 7 */ 8#if defined(KERNEL) || defined(_KERNEL) 9# undef KERNEL 10# undef _KERNEL 11# define KERNEL 1 12# define _KERNEL 1 13#endif 14#include <sys/errno.h> 15#include <sys/types.h> 16#include <sys/param.h> 17#include <sys/file.h> 18#if !defined(_KERNEL) && !defined(__KERNEL__) 19# include <stdio.h> 20# include <stdlib.h> 21# include <string.h> 22# define _KERNEL 23# define KERNEL 24# ifdef __OpenBSD__ 25struct file; 26# endif 27# include <sys/uio.h> 28# undef _KERNEL 29# undef KERNEL 30#else 31# include <sys/systm.h> 32# if !defined(__SVR4) && !defined(__svr4__) 33# include <sys/mbuf.h> 34# endif 35#endif 36#if defined(__NetBSD__) && (__NetBSD_Version__ >= 104000000) 37# include <sys/proc.h> 38#endif 39#if defined(_KERNEL) && (__FreeBSD_version >= 220000) 40# include <sys/filio.h> 41# include <sys/fcntl.h> 42# if (__FreeBSD_version >= 300000) && !defined(IPFILTER_LKM) 43# include "opt_ipfilter.h" 44# endif 45#else 46# include <sys/ioctl.h> 47#endif 48#include <sys/time.h> 49#if !defined(linux) 50# include <sys/protosw.h> 51#endif 52#include <sys/socket.h> 53#if defined(__SVR4) || defined(__svr4__) 54# include <sys/filio.h> 55# include <sys/byteorder.h> 56# ifdef _KERNEL 57# include <sys/dditypes.h> 58# endif 59# include <sys/stream.h> 60# include <sys/kmem.h> 61#endif 62 63#include <net/if.h> 64#ifdef sun 65# include <net/af.h> 66#endif 67#include <net/route.h> 68#include <netinet/in.h> 69#include <netinet/in_systm.h> 70#include <netinet/ip.h> 71#include <netinet/tcp.h> 72#if !defined(linux) 73# include <netinet/ip_var.h> 74#endif 75#if !defined(__hpux) && !defined(linux) 76# include <netinet/tcp_fsm.h> 77#endif 78#include <netinet/udp.h> 79#include <netinet/ip_icmp.h> 80#include "netinet/ip_compat.h" 81#include <netinet/tcpip.h> 82#include "netinet/ip_fil.h" 83#include "netinet/ip_nat.h" 84#include "netinet/ip_frag.h" 85#include "netinet/ip_state.h" 86#include "netinet/ip_proxy.h" 87#include "netinet/ip_sync.h" 88#ifdef USE_INET6 89#include <netinet/icmp6.h> 90#endif 91#if (__FreeBSD_version >= 300000) 92# include <sys/malloc.h> 93# if defined(_KERNEL) && !defined(IPFILTER_LKM) 94# include <sys/libkern.h> 95# include <sys/systm.h> 96# endif 97#endif 98/* END OF INCLUDES */ 99 100#if !defined(lint) 101static const char rcsid[] = "@(#)Id: ip_sync.c,v 2.40.2.3 2005/02/18 13:06:29 darrenr Exp"; 102#endif 103 104#define SYNC_STATETABSZ 256 105#define SYNC_NATTABSZ 256 106 107#ifdef IPFILTER_SYNC 108ipfmutex_t ipf_syncadd, ipsl_mutex; 109ipfrwlock_t ipf_syncstate, ipf_syncnat; 110#if SOLARIS && defined(_KERNEL) 111kcondvar_t ipslwait; 112#endif 113synclist_t *syncstatetab[SYNC_STATETABSZ]; 114synclist_t *syncnattab[SYNC_NATTABSZ]; 115synclogent_t synclog[SYNCLOG_SZ]; 116syncupdent_t syncupd[SYNCLOG_SZ]; 117u_int ipf_syncnum = 1; 118u_int ipf_syncwrap = 0; 119u_int sl_idx = 0, /* next available sync log entry */ 120 su_idx = 0, /* next available sync update entry */ 121 sl_tail = 0, /* next sync log entry to read */ 122 su_tail = 0; /* next sync update entry to read */ 123int ipf_sync_debug = 0; 124 125 126# if !defined(sparc) && !defined(__hppa) 127void ipfsync_tcporder __P((int, struct tcpdata *)); 128void ipfsync_natorder __P((int, struct nat *)); 129void ipfsync_storder __P((int, struct ipstate *)); 130# endif 131 132 133/* ------------------------------------------------------------------------ */ 134/* Function: ipfsync_init */ 135/* Returns: int - 0 == success, -1 == failure */ 136/* Parameters: Nil */ 137/* */ 138/* Initialise all of the locks required for the sync code and initialise */ 139/* any data structures, as required. */ 140/* ------------------------------------------------------------------------ */ 141int ipfsync_init() 142{ 143 RWLOCK_INIT(&ipf_syncstate, "add things to state sync table"); 144 RWLOCK_INIT(&ipf_syncnat, "add things to nat sync table"); 145 MUTEX_INIT(&ipf_syncadd, "add things to sync table"); 146 MUTEX_INIT(&ipsl_mutex, "add things to sync table"); 147# if SOLARIS && defined(_KERNEL) 148 cv_init(&ipslwait, "ipsl condvar", CV_DRIVER, NULL); 149# endif 150 151 bzero((char *)syncnattab, sizeof(syncnattab)); 152 bzero((char *)syncstatetab, sizeof(syncstatetab)); 153 154 return 0; 155} 156 157 158# if !defined(sparc) && !defined(__hppa) 159/* ------------------------------------------------------------------------ */ 160/* Function: ipfsync_tcporder */ 161/* Returns: Nil */ 162/* Parameters: way(I) - direction of byte order conversion. */ 163/* td(IO) - pointer to data to be converted. */ 164/* */ 165/* Do byte swapping on values in the TCP state information structure that */ 166/* need to be used at both ends by the host in their native byte order. */ 167/* ------------------------------------------------------------------------ */ 168void ipfsync_tcporder(way, td) 169int way; 170tcpdata_t *td; 171{ 172 if (way) { 173 td->td_maxwin = htons(td->td_maxwin); 174 td->td_end = htonl(td->td_end); 175 td->td_maxend = htonl(td->td_maxend); 176 } else { 177 td->td_maxwin = ntohs(td->td_maxwin); 178 td->td_end = ntohl(td->td_end); 179 td->td_maxend = ntohl(td->td_maxend); 180 } 181} 182 183 184/* ------------------------------------------------------------------------ */ 185/* Function: ipfsync_natorder */ 186/* Returns: Nil */ 187/* Parameters: way(I) - direction of byte order conversion. */ 188/* nat(IO) - pointer to data to be converted. */ 189/* */ 190/* Do byte swapping on values in the NAT data structure that need to be */ 191/* used at both ends by the host in their native byte order. */ 192/* ------------------------------------------------------------------------ */ 193void ipfsync_natorder(way, n) 194int way; 195nat_t *n; 196{ 197 if (way) { 198 n->nat_age = htonl(n->nat_age); 199 n->nat_flags = htonl(n->nat_flags); 200 n->nat_ipsumd = htonl(n->nat_ipsumd); 201 n->nat_use = htonl(n->nat_use); 202 n->nat_dir = htonl(n->nat_dir); 203 } else { 204 n->nat_age = ntohl(n->nat_age); 205 n->nat_flags = ntohl(n->nat_flags); 206 n->nat_ipsumd = ntohl(n->nat_ipsumd); 207 n->nat_use = ntohl(n->nat_use); 208 n->nat_dir = ntohl(n->nat_dir); 209 } 210} 211 212 213/* ------------------------------------------------------------------------ */ 214/* Function: ipfsync_storder */ 215/* Returns: Nil */ 216/* Parameters: way(I) - direction of byte order conversion. */ 217/* ips(IO) - pointer to data to be converted. */ 218/* */ 219/* Do byte swapping on values in the IP state data structure that need to */ 220/* be used at both ends by the host in their native byte order. */ 221/* ------------------------------------------------------------------------ */ 222void ipfsync_storder(way, ips) 223int way; 224ipstate_t *ips; 225{ 226 ipfsync_tcporder(way, &ips->is_tcp.ts_data[0]); 227 ipfsync_tcporder(way, &ips->is_tcp.ts_data[1]); 228 229 if (way) { 230 ips->is_hv = htonl(ips->is_hv); 231 ips->is_die = htonl(ips->is_die); 232 ips->is_pass = htonl(ips->is_pass); 233 ips->is_flags = htonl(ips->is_flags); 234 ips->is_opt = htonl(ips->is_opt); 235 ips->is_optmsk = htonl(ips->is_optmsk); 236 ips->is_sec = htons(ips->is_sec); 237 ips->is_secmsk = htons(ips->is_secmsk); 238 ips->is_auth = htons(ips->is_auth); 239 ips->is_authmsk = htons(ips->is_authmsk); 240 ips->is_s0[0] = htonl(ips->is_s0[0]); 241 ips->is_s0[1] = htonl(ips->is_s0[1]); 242 ips->is_smsk[0] = htons(ips->is_smsk[0]); 243 ips->is_smsk[1] = htons(ips->is_smsk[1]); 244 } else { 245 ips->is_hv = ntohl(ips->is_hv); 246 ips->is_die = ntohl(ips->is_die); 247 ips->is_pass = ntohl(ips->is_pass); 248 ips->is_flags = ntohl(ips->is_flags); 249 ips->is_opt = ntohl(ips->is_opt); 250 ips->is_optmsk = ntohl(ips->is_optmsk); 251 ips->is_sec = ntohs(ips->is_sec); 252 ips->is_secmsk = ntohs(ips->is_secmsk); 253 ips->is_auth = ntohs(ips->is_auth); 254 ips->is_authmsk = ntohs(ips->is_authmsk); 255 ips->is_s0[0] = ntohl(ips->is_s0[0]); 256 ips->is_s0[1] = ntohl(ips->is_s0[1]); 257 ips->is_smsk[0] = ntohl(ips->is_smsk[0]); 258 ips->is_smsk[1] = ntohl(ips->is_smsk[1]); 259 } 260} 261# else /* !defined(sparc) && !defined(__hppa) */ 262# define ipfsync_tcporder(x,y) 263# define ipfsync_natorder(x,y) 264# define ipfsync_storder(x,y) 265# endif /* !defined(sparc) && !defined(__hppa) */ 266 267/* enable this for debugging */ 268 269# ifdef _KERNEL 270/* ------------------------------------------------------------------------ */ 271/* Function: ipfsync_write */ 272/* Returns: int - 0 == success, else error value. */ 273/* Parameters: uio(I) - pointer to information about data to write */ 274/* */ 275/* Moves data from user space into the kernel and uses it for updating data */ 276/* structures in the state/NAT tables. */ 277/* ------------------------------------------------------------------------ */ 278int ipfsync_write(uio) 279struct uio *uio; 280{ 281 synchdr_t sh; 282 283 /* 284 * THIS MUST BE SUFFICIENT LARGE TO STORE 285 * ANY POSSIBLE DATA TYPE 286 */ 287 char data[2048]; 288 289 int err = 0; 290 291# if (BSD >= 199306) || defined(__FreeBSD__) || defined(__osf__) 292 uio->uio_rw = UIO_WRITE; 293# endif 294 295 /* Try to get bytes */ 296 while (uio->uio_resid > 0) { 297 298 if (uio->uio_resid >= sizeof(sh)) { 299 300 err = UIOMOVE((caddr_t)&sh, sizeof(sh), UIO_WRITE, uio); 301 302 if (err) { 303 if (ipf_sync_debug > 2) 304 printf("uiomove(header) failed: %d\n", 305 err); 306 return err; 307 } 308 309 /* convert to host order */ 310 sh.sm_magic = ntohl(sh.sm_magic); 311 sh.sm_len = ntohl(sh.sm_len); 312 sh.sm_num = ntohl(sh.sm_num); 313 314 if (ipf_sync_debug > 8) 315 printf("[%d] Read v:%d p:%d cmd:%d table:%d rev:%d len:%d magic:%x\n", 316 sh.sm_num, sh.sm_v, sh.sm_p, sh.sm_cmd, 317 sh.sm_table, sh.sm_rev, sh.sm_len, 318 sh.sm_magic); 319 320 if (sh.sm_magic != SYNHDRMAGIC) { 321 if (ipf_sync_debug > 2) 322 printf("uiomove(header) invalud %s\n", 323 "magic"); 324 return EINVAL; 325 } 326 327 if (sh.sm_v != 4 && sh.sm_v != 6) { 328 if (ipf_sync_debug > 2) 329 printf("uiomove(header) invalid %s\n", 330 "protocol"); 331 return EINVAL; 332 } 333 334 if (sh.sm_cmd > SMC_MAXCMD) { 335 if (ipf_sync_debug > 2) 336 printf("uiomove(header) invalid %s\n", 337 "command"); 338 return EINVAL; 339 } 340 341 342 if (sh.sm_table > SMC_MAXTBL) { 343 if (ipf_sync_debug > 2) 344 printf("uiomove(header) invalid %s\n", 345 "table"); 346 return EINVAL; 347 } 348 349 } else { 350 /* unsufficient data, wait until next call */ 351 if (ipf_sync_debug > 2) 352 printf("uiomove(header) insufficient data"); 353 return EAGAIN; 354 } 355 356 357 /* 358 * We have a header, so try to read the amount of data 359 * needed for the request 360 */ 361 362 /* not supported */ 363 if (sh.sm_len == 0) { 364 if (ipf_sync_debug > 2) 365 printf("uiomove(data zero length %s\n", 366 "not supported"); 367 return EINVAL; 368 } 369 370 if (uio->uio_resid >= sh.sm_len) { 371 372 err = UIOMOVE((caddr_t)data, sh.sm_len, UIO_WRITE, uio); 373 374 if (err) { 375 if (ipf_sync_debug > 2) 376 printf("uiomove(data) failed: %d\n", 377 err); 378 return err; 379 } 380 381 if (ipf_sync_debug > 7) 382 printf("uiomove(data) %d bytes read\n", 383 sh.sm_len); 384 385 if (sh.sm_table == SMC_STATE) 386 err = ipfsync_state(&sh, data); 387 else if (sh.sm_table == SMC_NAT) 388 err = ipfsync_nat(&sh, data); 389 if (ipf_sync_debug > 7) 390 printf("[%d] Finished with error %d\n", 391 sh.sm_num, err); 392 393 } else { 394 /* insufficient data, wait until next call */ 395 if (ipf_sync_debug > 2) 396 printf("uiomove(data) %s %d bytes, got %d\n", 397 "insufficient data, need", 398 sh.sm_len, uio->uio_resid); 399 return EAGAIN; 400 } 401 } 402 403 /* no more data */ 404 return 0; 405} 406 407 408/* ------------------------------------------------------------------------ */ 409/* Function: ipfsync_read */ 410/* Returns: int - 0 == success, else error value. */ 411/* Parameters: uio(O) - pointer to information about where to store data */ 412/* */ 413/* This function is called when a user program wants to read some data */ 414/* for pending state/NAT updates. If no data is available, the caller is */ 415/* put to sleep, pending a wakeup from the "lower half" of this code. */ 416/* ------------------------------------------------------------------------ */ 417int ipfsync_read(uio) 418struct uio *uio; 419{ 420 syncupdent_t *su; 421 synclogent_t *sl; 422 int err = 0; 423 424 if ((uio->uio_resid & 3) || (uio->uio_resid < 8)) 425 return EINVAL; 426 427# if (BSD >= 199306) || defined(__FreeBSD__) || defined(__osf__) 428 uio->uio_rw = UIO_READ; 429# endif 430 431 MUTEX_ENTER(&ipsl_mutex); 432 while ((sl_tail == sl_idx) && (su_tail == su_idx)) { 433# if SOLARIS && defined(_KERNEL) 434 if (!cv_wait_sig(&ipslwait, &ipsl_mutex)) { 435 MUTEX_EXIT(&ipsl_mutex); 436 return EINTR; 437 } 438# else 439# ifdef __hpux 440 { 441 lock_t *l; 442 443 l = get_sleep_lock(&sl_tail); 444 err = sleep(&sl_tail, PZERO+1); 445 if (err) { 446 MUTEX_EXIT(&ipsl_mutex); 447 return EINTR; 448 } 449 spinunlock(l); 450 } 451# else /* __hpux */ 452# ifdef __osf__ 453 err = mpsleep(&sl_tail, PSUSP|PCATCH, "ipl sleep", 0, 454 &ipsl_mutex, MS_LOCK_SIMPLE); 455 if (err) 456 return EINTR; 457# else 458 MUTEX_EXIT(&ipsl_mutex); 459 err = SLEEP(&sl_tail, "ipl sleep"); 460 if (err) 461 return EINTR; 462 MUTEX_ENTER(&ipsl_mutex); 463# endif /* __osf__ */ 464# endif /* __hpux */ 465# endif /* SOLARIS */ 466 } 467 MUTEX_EXIT(&ipsl_mutex); 468 469 READ_ENTER(&ipf_syncstate); 470 while ((sl_tail < sl_idx) && (uio->uio_resid > sizeof(*sl))) { 471 sl = synclog + sl_tail++; 472 err = UIOMOVE((caddr_t)sl, sizeof(*sl), UIO_READ, uio); 473 if (err != 0) 474 break; 475 } 476 477 while ((su_tail < su_idx) && (uio->uio_resid > sizeof(*su))) { 478 su = syncupd + su_tail; 479 su_tail++; 480 err = UIOMOVE((caddr_t)su, sizeof(*su), UIO_READ, uio); 481 if (err != 0) 482 break; 483 if (su->sup_hdr.sm_sl != NULL) 484 su->sup_hdr.sm_sl->sl_idx = -1; 485 } 486 487 MUTEX_ENTER(&ipf_syncadd); 488 if (su_tail == su_idx) 489 su_tail = su_idx = 0; 490 if (sl_tail == sl_idx) 491 sl_tail = sl_idx = 0; 492 MUTEX_EXIT(&ipf_syncadd); 493 RWLOCK_EXIT(&ipf_syncstate); 494 return err; 495} 496 497 498/* ------------------------------------------------------------------------ */ 499/* Function: ipfsync_state */ 500/* Returns: int - 0 == success, else error value. */ 501/* Parameters: sp(I) - pointer to sync packet data header */ 502/* uio(I) - pointer to user data for further information */ 503/* */ 504/* Updates the state table according to information passed in the sync */ 505/* header. As required, more data is fetched from the uio structure but */ 506/* varies depending on the contents of the sync header. This function can */ 507/* create a new state entry or update one. Deletion is left to the state */ 508/* structures being timed out correctly. */ 509/* ------------------------------------------------------------------------ */ 510int ipfsync_state(sp, data) 511synchdr_t *sp; 512void *data; 513{ 514 synctcp_update_t su; 515 ipstate_t *is, sn; 516 synclist_t *sl; 517 frentry_t *fr; 518 u_int hv; 519 int err = 0; 520 521 hv = sp->sm_num & (SYNC_STATETABSZ - 1); 522 523 switch (sp->sm_cmd) 524 { 525 case SMC_CREATE : 526 527 bcopy(data, &sn, sizeof(sn)); 528 KMALLOC(is, ipstate_t *); 529 if (is == NULL) { 530 err = ENOMEM; 531 break; 532 } 533 534 KMALLOC(sl, synclist_t *); 535 if (sl == NULL) { 536 err = ENOMEM; 537 KFREE(is); 538 break; 539 } 540 541 bzero((char *)is, offsetof(ipstate_t, is_die)); 542 bcopy((char *)&sn.is_die, (char *)&is->is_die, 543 sizeof(*is) - offsetof(ipstate_t, is_die)); 544 ipfsync_storder(0, is); 545 546 /* 547 * We need to find the same rule on the slave as was used on 548 * the master to create this state entry. 549 */ 550 READ_ENTER(&ipf_mutex); 551 fr = fr_getrulen(IPL_LOGIPF, sn.is_group, sn.is_rulen); 552 if (fr != NULL) { 553 MUTEX_ENTER(&fr->fr_lock); 554 fr->fr_ref++; 555 fr->fr_statecnt++; 556 MUTEX_EXIT(&fr->fr_lock); 557 } 558 RWLOCK_EXIT(&ipf_mutex); 559 560 if (ipf_sync_debug > 4) 561 printf("[%d] Filter rules = %p\n", sp->sm_num, fr); 562 563 is->is_rule = fr; 564 is->is_sync = sl; 565 566 sl->sl_idx = -1; 567 sl->sl_ips = is; 568 bcopy(sp, &sl->sl_hdr, sizeof(struct synchdr)); 569 570 WRITE_ENTER(&ipf_syncstate); 571 WRITE_ENTER(&ipf_state); 572 573 sl->sl_pnext = syncstatetab + hv; 574 sl->sl_next = syncstatetab[hv]; 575 if (syncstatetab[hv] != NULL) 576 syncstatetab[hv]->sl_pnext = &sl->sl_next; 577 syncstatetab[hv] = sl; 578 MUTEX_DOWNGRADE(&ipf_syncstate); 579 fr_stinsert(is, sp->sm_rev); 580 /* 581 * Do not initialise the interface pointers for the state 582 * entry as the full complement of interface names may not 583 * be present. 584 * 585 * Put this state entry on its timeout queue. 586 */ 587 /*fr_setstatequeue(is, sp->sm_rev);*/ 588 break; 589 590 case SMC_UPDATE : 591 bcopy(data, &su, sizeof(su)); 592 593 if (ipf_sync_debug > 4) 594 printf("[%d] Update age %lu state %d/%d \n", 595 sp->sm_num, su.stu_age, su.stu_state[0], 596 su.stu_state[1]); 597 598 READ_ENTER(&ipf_syncstate); 599 for (sl = syncstatetab[hv]; (sl != NULL); sl = sl->sl_next) 600 if (sl->sl_hdr.sm_num == sp->sm_num) 601 break; 602 if (sl == NULL) { 603 if (ipf_sync_debug > 1) 604 printf("[%d] State not found - can't update\n", 605 sp->sm_num); 606 RWLOCK_EXIT(&ipf_syncstate); 607 err = ENOENT; 608 break; 609 } 610 611 READ_ENTER(&ipf_state); 612 613 if (ipf_sync_debug > 6) 614 printf("[%d] Data from state v:%d p:%d cmd:%d table:%d rev:%d\n", 615 sp->sm_num, sl->sl_hdr.sm_v, sl->sl_hdr.sm_p, 616 sl->sl_hdr.sm_cmd, sl->sl_hdr.sm_table, 617 sl->sl_hdr.sm_rev); 618 619 is = sl->sl_ips; 620 621 MUTEX_ENTER(&is->is_lock); 622 switch (sp->sm_p) 623 { 624 case IPPROTO_TCP : 625 /* XXX FV --- shouldn't we do ntohl/htonl???? XXX */ 626 is->is_send = su.stu_data[0].td_end; 627 is->is_maxsend = su.stu_data[0].td_maxend; 628 is->is_maxswin = su.stu_data[0].td_maxwin; 629 is->is_state[0] = su.stu_state[0]; 630 is->is_dend = su.stu_data[1].td_end; 631 is->is_maxdend = su.stu_data[1].td_maxend; 632 is->is_maxdwin = su.stu_data[1].td_maxwin; 633 is->is_state[1] = su.stu_state[1]; 634 break; 635 default : 636 break; 637 } 638 639 if (ipf_sync_debug > 6) 640 printf("[%d] Setting timers for state\n", sp->sm_num); 641 642 fr_setstatequeue(is, sp->sm_rev); 643 644 MUTEX_EXIT(&is->is_lock); 645 break; 646 647 default : 648 err = EINVAL; 649 break; 650 } 651 652 if (err == 0) { 653 RWLOCK_EXIT(&ipf_state); 654 RWLOCK_EXIT(&ipf_syncstate); 655 } 656 657 if (ipf_sync_debug > 6) 658 printf("[%d] Update completed with error %d\n", 659 sp->sm_num, err); 660 661 return err; 662} 663# endif /* _KERNEL */ 664 665 666/* ------------------------------------------------------------------------ */ 667/* Function: ipfsync_del */ 668/* Returns: Nil */ 669/* Parameters: sl(I) - pointer to synclist object to delete */ 670/* */ 671/* Deletes an object from the synclist table and free's its memory. */ 672/* ------------------------------------------------------------------------ */ 673void ipfsync_del(sl) 674synclist_t *sl; 675{ 676 WRITE_ENTER(&ipf_syncstate); 677 *sl->sl_pnext = sl->sl_next; 678 if (sl->sl_next != NULL) 679 sl->sl_next->sl_pnext = sl->sl_pnext; 680 if (sl->sl_idx != -1) 681 syncupd[sl->sl_idx].sup_hdr.sm_sl = NULL; 682 RWLOCK_EXIT(&ipf_syncstate); 683 KFREE(sl); 684} 685 686 687/* ------------------------------------------------------------------------ */ 688/* Function: ipfsync_nat */ 689/* Returns: int - 0 == success, else error value. */ 690/* Parameters: sp(I) - pointer to sync packet data header */ 691/* uio(I) - pointer to user data for further information */ 692/* */ 693/* Updates the NAT table according to information passed in the sync */ 694/* header. As required, more data is fetched from the uio structure but */ 695/* varies depending on the contents of the sync header. This function can */ 696/* create a new NAT entry or update one. Deletion is left to the NAT */ 697/* structures being timed out correctly. */ 698/* ------------------------------------------------------------------------ */ 699int ipfsync_nat(sp, data) 700synchdr_t *sp; 701void *data; 702{ 703 synclogent_t sle; 704 syncupdent_t su; 705 nat_t *n, *nat; 706 synclist_t *sl; 707 u_int hv = 0; 708 int err; 709 710 READ_ENTER(&ipf_syncstate); 711 712 switch (sp->sm_cmd) 713 { 714 case SMC_CREATE : 715 bcopy(data, &sle, sizeof(sle)); 716 717 KMALLOC(n, nat_t *); 718 if (n == NULL) { 719 err = ENOMEM; 720 break; 721 } 722 723 KMALLOC(sl, synclist_t *); 724 if (sl == NULL) { 725 err = ENOMEM; 726 KFREE(n); 727 break; 728 } 729 730 WRITE_ENTER(&ipf_nat); 731 732 nat = &sle.sle_un.sleu_ipn; 733 bzero((char *)n, offsetof(nat_t, nat_age)); 734 bcopy((char *)&nat->nat_age, (char *)&n->nat_age, 735 sizeof(*n) - offsetof(nat_t, nat_age)); 736 ipfsync_natorder(0, n); 737 n->nat_sync = sl; 738 739 sl->sl_idx = -1; 740 sl->sl_ipn = n; 741 sl->sl_num = ntohl(sp->sm_num); 742 sl->sl_pnext = syncstatetab + hv; 743 sl->sl_next = syncstatetab[hv]; 744 if (syncstatetab[hv] != NULL) 745 syncstatetab[hv]->sl_pnext = &sl->sl_next; 746 syncstatetab[hv] = sl; 747 nat_insert(n, sl->sl_rev); 748 RWLOCK_EXIT(&ipf_nat); 749 break; 750 751 case SMC_UPDATE : 752 bcopy(data, &su, sizeof(su)); 753 754 READ_ENTER(&ipf_syncstate); 755 for (sl = syncstatetab[hv]; (sl != NULL); sl = sl->sl_next) 756 if (sl->sl_hdr.sm_num == sp->sm_num) 757 break; 758 if (sl == NULL) { 759 err = ENOENT; 760 break; 761 } 762 763 READ_ENTER(&ipf_nat); 764 765 nat = sl->sl_ipn; 766 767 MUTEX_ENTER(&nat->nat_lock); 768 fr_setnatqueue(nat, sl->sl_rev); 769 MUTEX_EXIT(&nat->nat_lock); 770 771 RWLOCK_EXIT(&ipf_nat); 772 773 break; 774 775 default : 776 err = EINVAL; 777 break; 778 } 779 780 RWLOCK_EXIT(&ipf_syncstate); 781 return 0; 782} 783 784 785/* ------------------------------------------------------------------------ */ 786/* Function: ipfsync_new */ 787/* Returns: synclist_t* - NULL == failure, else pointer to new synclist */ 788/* data structure. */ 789/* Parameters: tab(I) - type of synclist_t to create */ 790/* fin(I) - pointer to packet information */ 791/* ptr(I) - pointer to owning object */ 792/* */ 793/* Creates a new sync table entry and notifies any sleepers that it's there */ 794/* waiting to be processed. */ 795/* ------------------------------------------------------------------------ */ 796synclist_t *ipfsync_new(tab, fin, ptr) 797int tab; 798fr_info_t *fin; 799void *ptr; 800{ 801 synclist_t *sl, *ss; 802 synclogent_t *sle; 803 u_int hv, sz; 804 805 if (sl_idx == SYNCLOG_SZ) 806 return NULL; 807 KMALLOC(sl, synclist_t *); 808 if (sl == NULL) 809 return NULL; 810 811 MUTEX_ENTER(&ipf_syncadd); 812 /* 813 * Get a unique number for this synclist_t. The number is only meant 814 * to be unique for the lifetime of the structure and may be reused 815 * later. 816 */ 817 ipf_syncnum++; 818 if (ipf_syncnum == 0) { 819 ipf_syncnum = 1; 820 ipf_syncwrap = 1; 821 } 822 823 hv = ipf_syncnum & (SYNC_STATETABSZ - 1); 824 while (ipf_syncwrap != 0) { 825 for (ss = syncstatetab[hv]; ss; ss = ss->sl_next) 826 if (ss->sl_hdr.sm_num == ipf_syncnum) 827 break; 828 if (ss == NULL) 829 break; 830 ipf_syncnum++; 831 hv = ipf_syncnum & (SYNC_STATETABSZ - 1); 832 } 833 /* 834 * Use the synch number of the object as the hash key. Should end up 835 * with relatively even distribution over time. 836 * XXX - an attacker could lunch an DoS attack, of sorts, if they are 837 * the only one causing new table entries by only keeping open every 838 * nth connection they make, where n is a value in the interval 839 * [0, SYNC_STATETABSZ-1]. 840 */ 841 sl->sl_pnext = syncstatetab + hv; 842 sl->sl_next = syncstatetab[hv]; 843 syncstatetab[hv] = sl; 844 sl->sl_num = ipf_syncnum; 845 MUTEX_EXIT(&ipf_syncadd); 846 847 sl->sl_magic = htonl(SYNHDRMAGIC); 848 sl->sl_v = fin->fin_v; 849 sl->sl_p = fin->fin_p; 850 sl->sl_cmd = SMC_CREATE; 851 sl->sl_idx = -1; 852 sl->sl_table = tab; 853 sl->sl_rev = fin->fin_rev; 854 if (tab == SMC_STATE) { 855 sl->sl_ips = ptr; 856 sz = sizeof(*sl->sl_ips); 857 } else if (tab == SMC_NAT) { 858 sl->sl_ipn = ptr; 859 sz = sizeof(*sl->sl_ipn); 860 } else { 861 ptr = NULL; 862 sz = 0; 863 } 864 sl->sl_len = sz; 865 866 /* 867 * Create the log entry to be read by a user daemon. When it has been 868 * finished and put on the queue, send a signal to wakeup any waiters. 869 */ 870 MUTEX_ENTER(&ipf_syncadd); 871 sle = synclog + sl_idx++; 872 bcopy((char *)&sl->sl_hdr, (char *)&sle->sle_hdr, 873 sizeof(sle->sle_hdr)); 874 sle->sle_hdr.sm_num = htonl(sle->sle_hdr.sm_num); 875 sle->sle_hdr.sm_len = htonl(sle->sle_hdr.sm_len); 876 if (ptr != NULL) { 877 bcopy((char *)ptr, (char *)&sle->sle_un, sz); 878 if (tab == SMC_STATE) { 879 ipfsync_storder(1, &sle->sle_un.sleu_ips); 880 } else if (tab == SMC_NAT) { 881 ipfsync_natorder(1, &sle->sle_un.sleu_ipn); 882 } 883 } 884 MUTEX_EXIT(&ipf_syncadd); 885 886 MUTEX_ENTER(&ipsl_mutex); 887# if SOLARIS 888# ifdef _KERNEL 889 cv_signal(&ipslwait); 890# endif 891 MUTEX_EXIT(&ipsl_mutex); 892# else 893 MUTEX_EXIT(&ipsl_mutex); 894# ifdef _KERNEL 895 wakeup(&sl_tail); 896# endif 897# endif 898 return sl; 899} 900 901 902/* ------------------------------------------------------------------------ */ 903/* Function: ipfsync_update */ 904/* Returns: Nil */ 905/* Parameters: tab(I) - type of synclist_t to create */ 906/* fin(I) - pointer to packet information */ 907/* sl(I) - pointer to synchronisation object */ 908/* */ 909/* For outbound packets, only, create an sync update record for the user */ 910/* process to read. */ 911/* ------------------------------------------------------------------------ */ 912void ipfsync_update(tab, fin, sl) 913int tab; 914fr_info_t *fin; 915synclist_t *sl; 916{ 917 synctcp_update_t *st; 918 syncupdent_t *slu; 919 ipstate_t *ips; 920 nat_t *nat; 921 922 if (fin->fin_out == 0 || sl == NULL) 923 return; 924 925 WRITE_ENTER(&ipf_syncstate); 926 MUTEX_ENTER(&ipf_syncadd); 927 if (sl->sl_idx == -1) { 928 slu = syncupd + su_idx; 929 sl->sl_idx = su_idx++; 930 bcopy((char *)&sl->sl_hdr, (char *)&slu->sup_hdr, 931 sizeof(slu->sup_hdr)); 932 slu->sup_hdr.sm_magic = htonl(SYNHDRMAGIC); 933 slu->sup_hdr.sm_sl = sl; 934 slu->sup_hdr.sm_cmd = SMC_UPDATE; 935 slu->sup_hdr.sm_table = tab; 936 slu->sup_hdr.sm_num = htonl(sl->sl_num); 937 slu->sup_hdr.sm_len = htonl(sizeof(struct synctcp_update)); 938 slu->sup_hdr.sm_rev = fin->fin_rev; 939# if 0 940 if (fin->fin_p == IPPROTO_TCP) { 941 st->stu_len[0] = 0; 942 st->stu_len[1] = 0; 943 } 944# endif 945 } else 946 slu = syncupd + sl->sl_idx; 947 MUTEX_EXIT(&ipf_syncadd); 948 MUTEX_DOWNGRADE(&ipf_syncstate); 949 950 /* 951 * Only TCP has complex timeouts, others just use default timeouts. 952 * For TCP, we only need to track the connection state and window. 953 */ 954 if (fin->fin_p == IPPROTO_TCP) { 955 st = &slu->sup_tcp; 956 if (tab == SMC_STATE) { 957 ips = sl->sl_ips; 958 st->stu_age = htonl(ips->is_die); 959 st->stu_data[0].td_end = ips->is_send; 960 st->stu_data[0].td_maxend = ips->is_maxsend; 961 st->stu_data[0].td_maxwin = ips->is_maxswin; 962 st->stu_state[0] = ips->is_state[0]; 963 st->stu_data[1].td_end = ips->is_dend; 964 st->stu_data[1].td_maxend = ips->is_maxdend; 965 st->stu_data[1].td_maxwin = ips->is_maxdwin; 966 st->stu_state[1] = ips->is_state[1]; 967 } else if (tab == SMC_NAT) { 968 nat = sl->sl_ipn; 969 st->stu_age = htonl(nat->nat_age); 970 } 971 } 972 RWLOCK_EXIT(&ipf_syncstate); 973 974 MUTEX_ENTER(&ipsl_mutex); 975# if SOLARIS 976# ifdef _KERNEL 977 cv_signal(&ipslwait); 978# endif 979 MUTEX_EXIT(&ipsl_mutex); 980# else 981 MUTEX_EXIT(&ipsl_mutex); 982# ifdef _KERNEL 983 wakeup(&sl_tail); 984# endif 985# endif 986} 987 988 989/* ------------------------------------------------------------------------ */ 990/* Function: fr_sync_ioctl */ 991/* Returns: int - 0 == success, != 0 == failure */ 992/* Parameters: data(I) - pointer to ioctl data */ 993/* cmd(I) - ioctl command integer */ 994/* mode(I) - file mode bits used with open */ 995/* */ 996/* This function currently does not handle any ioctls and so just returns */ 997/* EINVAL on all occasions. */ 998/* ------------------------------------------------------------------------ */ 999int fr_sync_ioctl(data, cmd, mode) 1000caddr_t data; 1001ioctlcmd_t cmd; 1002int mode; 1003{ 1004 return EINVAL; 1005} 1006#endif /* IPFILTER_SYNC */ 1007