Print this page
OS-7667 IPFilter needs to keep and report state for cloud firewall logging
Portions contributed by: Mike Gerdts <mike.gerdts@joyent.com>
   1 /*
   2  * Copyright (C) 1993-2001, 2003 by Darren Reed.
   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  * Copyright (c) 2014, Joyent, Inc.  All rights reserved.
  10  */
  11 
  12 /*
  13  * ipfilter kernel module mutexes and locking:
  14  *
  15  * Enabling ipfilter creates a per-netstack ipf_stack_t object that is
  16  * stored in the ipf_stacks list, which is protected by ipf_stack_lock.
  17  * ipf_stack_t objects are accessed in three contexts:
  18  *
  19  * 1) administering that filter (eg: ioctls handled with iplioctl())
  20  * 2) reading log data (eg: iplread() / iplwrite())
  21  * 3) filtering packets (eg: ipf_hook4_* and ipf_hook6_* pfhooks
  22  *    functions)
  23  *
  24  * Each ipf_stack_t has a RW lock, ifs_ipf_global, protecting access to the
  25  * whole structure. The structure also has locks protecting the various
  26  * data structures used for filtering. The following guidelines should be
  27  * followed for ipf_stack_t locks:
  28  *
  29  * - ipf_stack_lock must be held when accessing the ipf_stacks list


  99 #include "netinet/ip_frag.h"
 100 #include "netinet/ip_auth.h"
 101 #include "netinet/ip_state.h"
 102 #include "netinet/ipf_stack.h"
 103 
 104 extern  int     iplwrite __P((dev_t, struct uio *, cred_t *));
 105 
 106 static  int     ipf_getinfo __P((dev_info_t *, ddi_info_cmd_t,
 107                     void *, void **));
 108 #if SOLARIS2 < 10
 109 static  int     ipf_identify __P((dev_info_t *));
 110 #endif
 111 static  int     ipf_attach __P((dev_info_t *, ddi_attach_cmd_t));
 112 static  int     ipf_detach __P((dev_info_t *, ddi_detach_cmd_t));
 113 static  void    *ipf_stack_create __P((const netid_t));
 114 static  void    ipf_stack_destroy __P((const netid_t, void *));
 115 static  void    ipf_stack_shutdown __P((const netid_t, void *));
 116 static  int     ipf_property_g_update __P((dev_info_t *));
 117 static  char    *ipf_devfiles[] = { IPL_NAME, IPNAT_NAME, IPSTATE_NAME,
 118                                     IPAUTH_NAME, IPSYNC_NAME, IPSCAN_NAME,
 119                                     IPLOOKUP_NAME, NULL };
 120 extern void     *ipf_state;     /* DDI state */
 121 extern vmem_t   *ipf_minor;     /* minor number arena */
 122 
 123 static struct cb_ops ipf_cb_ops = {
 124         iplopen,
 125         iplclose,
 126         nodev,          /* strategy */
 127         nodev,          /* print */
 128         nodev,          /* dump */
 129         iplread,
 130         iplwrite,       /* write */
 131         iplioctl,       /* ioctl */
 132         nodev,          /* devmap */
 133         nodev,          /* mmap */
 134         nodev,          /* segmap */
 135         nochpoll,       /* poll */
 136         ddi_prop_op,
 137         NULL,
 138         D_MTSAFE,
 139 #if SOLARIS2 > 4


 724                 (void) ipf_property_g_update(dip);
 725 
 726                 if (ddi_soft_state_init(&ipf_state, sizeof (ipf_devstate_t), 1)
 727                     != 0) {
 728                         ddi_prop_remove_all(dip);
 729                         return (DDI_FAILURE);
 730                 }
 731 
 732                 for (i = 0; ((s = ipf_devfiles[i]) != NULL); i++) {
 733                         s = strrchr(s, '/');
 734                         if (s == NULL)
 735                                 continue;
 736                         s++;
 737                         if (ddi_create_minor_node(dip, s, S_IFCHR, i,
 738                             DDI_PSEUDO, 0) == DDI_FAILURE)
 739                                 goto attach_failed;
 740                 }
 741 
 742                 ipf_dev_info = dip;
 743 



 744                 ipfncb = net_instance_alloc(NETINFO_VERSION);
 745                 if (ipfncb == NULL)
 746                         goto attach_failed;
 747 
 748                 ipfncb->nin_name = "ipf";
 749                 ipfncb->nin_create = ipf_stack_create;
 750                 ipfncb->nin_destroy = ipf_stack_destroy;
 751                 ipfncb->nin_shutdown = ipf_stack_shutdown;
 752                 if (net_instance_register(ipfncb) == DDI_FAILURE) {
 753                         net_instance_free(ipfncb);
 754                         goto attach_failed;
 755                 }
 756 
 757                 ipf_minor = vmem_create("ipf_minor", (void *)1, UINT32_MAX - 1,
 758                     1, NULL, NULL, NULL, 0, VM_SLEEP | VMC_IDENTIFIER);
 759 
 760 #ifdef IPFDEBUG
 761                 cmn_err(CE_CONT, "IP Filter:stack_create callback_reg=%d", i);
 762 #endif
 763 
 764                 return (DDI_SUCCESS);
 765                 /* NOTREACHED */
 766         default:
 767                 break;
 768         }
 769 
 770 attach_failed:

 771         ddi_remove_minor_node(dip, NULL);
 772         ddi_prop_remove_all(dip);
 773         ddi_soft_state_fini(&ipf_state);
 774         return (DDI_FAILURE);
 775 }
 776 
 777 
 778 static int ipf_detach(dip, cmd)
 779 dev_info_t *dip;
 780 ddi_detach_cmd_t cmd;
 781 {
 782         int i;
 783 
 784 #ifdef  IPFDEBUG
 785         cmn_err(CE_NOTE, "IP Filter: ipf_detach(%p,%x)", dip, cmd);
 786 #endif
 787         switch (cmd) {
 788         case DDI_DETACH:
 789                 if (ipf_detach_check_all() != 0)
 790                         return (DDI_FAILURE);
 791 
 792                 /*
 793                  * Undo what we did in ipf_attach, freeing resources
 794                  * and removing things we installed.  The system
 795                  * framework guarantees we are not active with this devinfo
 796                  * node in any other entry points at this time.
 797                  */

 798                 ddi_prop_remove_all(dip);
 799                 i = ddi_get_instance(dip);
 800                 ddi_remove_minor_node(dip, NULL);
 801                 if (i > 0) {
 802                         cmn_err(CE_CONT, "IP Filter: still attached (%d)\n", i);
 803                         return (DDI_FAILURE);
 804                 }
 805 
 806                 vmem_destroy(ipf_minor);
 807                 ddi_soft_state_fini(&ipf_state);
 808 
 809                 (void) net_instance_unregister(ipfncb);
 810                 net_instance_free(ipfncb);
 811 
 812                 return (DDI_SUCCESS);
 813                 /* NOTREACHED */
 814         default:
 815                 break;
 816         }
 817         cmn_err(CE_NOTE, "IP Filter: failed to detach\n");


   1 /*
   2  * Copyright (C) 1993-2001, 2003 by Darren Reed.
   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  * Copyright 2019 Joyent, Inc.
  10  */
  11 
  12 /*
  13  * ipfilter kernel module mutexes and locking:
  14  *
  15  * Enabling ipfilter creates a per-netstack ipf_stack_t object that is
  16  * stored in the ipf_stacks list, which is protected by ipf_stack_lock.
  17  * ipf_stack_t objects are accessed in three contexts:
  18  *
  19  * 1) administering that filter (eg: ioctls handled with iplioctl())
  20  * 2) reading log data (eg: iplread() / iplwrite())
  21  * 3) filtering packets (eg: ipf_hook4_* and ipf_hook6_* pfhooks
  22  *    functions)
  23  *
  24  * Each ipf_stack_t has a RW lock, ifs_ipf_global, protecting access to the
  25  * whole structure. The structure also has locks protecting the various
  26  * data structures used for filtering. The following guidelines should be
  27  * followed for ipf_stack_t locks:
  28  *
  29  * - ipf_stack_lock must be held when accessing the ipf_stacks list


  99 #include "netinet/ip_frag.h"
 100 #include "netinet/ip_auth.h"
 101 #include "netinet/ip_state.h"
 102 #include "netinet/ipf_stack.h"
 103 
 104 extern  int     iplwrite __P((dev_t, struct uio *, cred_t *));
 105 
 106 static  int     ipf_getinfo __P((dev_info_t *, ddi_info_cmd_t,
 107                     void *, void **));
 108 #if SOLARIS2 < 10
 109 static  int     ipf_identify __P((dev_info_t *));
 110 #endif
 111 static  int     ipf_attach __P((dev_info_t *, ddi_attach_cmd_t));
 112 static  int     ipf_detach __P((dev_info_t *, ddi_detach_cmd_t));
 113 static  void    *ipf_stack_create __P((const netid_t));
 114 static  void    ipf_stack_destroy __P((const netid_t, void *));
 115 static  void    ipf_stack_shutdown __P((const netid_t, void *));
 116 static  int     ipf_property_g_update __P((dev_info_t *));
 117 static  char    *ipf_devfiles[] = { IPL_NAME, IPNAT_NAME, IPSTATE_NAME,
 118                                     IPAUTH_NAME, IPSYNC_NAME, IPSCAN_NAME,
 119                                     IPLOOKUP_NAME, IPFEV_NAME, NULL };
 120 extern void     *ipf_state;     /* DDI state */
 121 extern vmem_t   *ipf_minor;     /* minor number arena */
 122 
 123 static struct cb_ops ipf_cb_ops = {
 124         iplopen,
 125         iplclose,
 126         nodev,          /* strategy */
 127         nodev,          /* print */
 128         nodev,          /* dump */
 129         iplread,
 130         iplwrite,       /* write */
 131         iplioctl,       /* ioctl */
 132         nodev,          /* devmap */
 133         nodev,          /* mmap */
 134         nodev,          /* segmap */
 135         nochpoll,       /* poll */
 136         ddi_prop_op,
 137         NULL,
 138         D_MTSAFE,
 139 #if SOLARIS2 > 4


 724                 (void) ipf_property_g_update(dip);
 725 
 726                 if (ddi_soft_state_init(&ipf_state, sizeof (ipf_devstate_t), 1)
 727                     != 0) {
 728                         ddi_prop_remove_all(dip);
 729                         return (DDI_FAILURE);
 730                 }
 731 
 732                 for (i = 0; ((s = ipf_devfiles[i]) != NULL); i++) {
 733                         s = strrchr(s, '/');
 734                         if (s == NULL)
 735                                 continue;
 736                         s++;
 737                         if (ddi_create_minor_node(dip, s, S_IFCHR, i,
 738                             DDI_PSEUDO, 0) == DDI_FAILURE)
 739                                 goto attach_failed;
 740                 }
 741 
 742                 ipf_dev_info = dip;
 743 
 744                 if (ipf_cfw_ring_resize(IPF_CFW_RING_ALLOCATE) != 0)
 745                         goto attach_failed;
 746 
 747                 ipfncb = net_instance_alloc(NETINFO_VERSION);
 748                 if (ipfncb == NULL)
 749                         goto attach_failed;
 750 
 751                 ipfncb->nin_name = "ipf";
 752                 ipfncb->nin_create = ipf_stack_create;
 753                 ipfncb->nin_destroy = ipf_stack_destroy;
 754                 ipfncb->nin_shutdown = ipf_stack_shutdown;
 755                 if (net_instance_register(ipfncb) == DDI_FAILURE) {
 756                         net_instance_free(ipfncb);
 757                         goto attach_failed;
 758                 }
 759 
 760                 ipf_minor = vmem_create("ipf_minor", (void *)1, UINT32_MAX - 1,
 761                     1, NULL, NULL, NULL, 0, VM_SLEEP | VMC_IDENTIFIER);
 762 
 763 #ifdef IPFDEBUG
 764                 cmn_err(CE_CONT, "IP Filter:stack_create callback_reg=%d", i);
 765 #endif
 766 
 767                 return (DDI_SUCCESS);
 768                 /* NOTREACHED */
 769         default:
 770                 break;
 771         }
 772 
 773 attach_failed:
 774         (void) ipf_cfw_ring_resize(IPF_CFW_RING_DESTROY);
 775         ddi_remove_minor_node(dip, NULL);
 776         ddi_prop_remove_all(dip);
 777         ddi_soft_state_fini(&ipf_state);
 778         return (DDI_FAILURE);
 779 }
 780 
 781 
 782 static int ipf_detach(dip, cmd)
 783 dev_info_t *dip;
 784 ddi_detach_cmd_t cmd;
 785 {
 786         int i;
 787 
 788 #ifdef  IPFDEBUG
 789         cmn_err(CE_NOTE, "IP Filter: ipf_detach(%p,%x)", dip, cmd);
 790 #endif
 791         switch (cmd) {
 792         case DDI_DETACH:
 793                 if (ipf_detach_check_all() != 0)
 794                         return (DDI_FAILURE);
 795 
 796                 /*
 797                  * Undo what we did in ipf_attach, freeing resources
 798                  * and removing things we installed.  The system
 799                  * framework guarantees we are not active with this devinfo
 800                  * node in any other entry points at this time.
 801                  */
 802                 (void) ipf_cfw_ring_resize(IPF_CFW_RING_DESTROY);
 803                 ddi_prop_remove_all(dip);
 804                 i = ddi_get_instance(dip);
 805                 ddi_remove_minor_node(dip, NULL);
 806                 if (i > 0) {
 807                         cmn_err(CE_CONT, "IP Filter: still attached (%d)\n", i);
 808                         return (DDI_FAILURE);
 809                 }
 810 
 811                 vmem_destroy(ipf_minor);
 812                 ddi_soft_state_fini(&ipf_state);
 813 
 814                 (void) net_instance_unregister(ipfncb);
 815                 net_instance_free(ipfncb);
 816 
 817                 return (DDI_SUCCESS);
 818                 /* NOTREACHED */
 819         default:
 820                 break;
 821         }
 822         cmn_err(CE_NOTE, "IP Filter: failed to detach\n");