1 /* $NetBSD: npf_handler.c,v 1.1 2010/08/22 18:56:22 rmind Exp $ */ 2 3 /*- 4 * Copyright (c) 2009-2010 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This material is based upon work partially supported by The 8 * NetBSD Foundation under a contract with Mindaugas Rasiukevicius. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 /* 33 * NPF packet handler. 34 */ 35 36 #ifdef _KERNEL 37 #include <sys/cdefs.h> 38 __KERNEL_RCSID(0, "$NetBSD: npf_handler.c,v 1.1 2010/08/22 18:56:22 rmind Exp $"); 39 40 #include <sys/param.h> 41 #include <sys/systm.h> 42 #endif 43 44 #include <sys/mbuf.h> 45 #include <sys/mutex.h> 46 #include <net/if.h> 47 #include <net/pfil.h> 48 #include <sys/socketvar.h> 49 50 #include "npf_impl.h" 51 52 /* 53 * If npf_ph_if != NULL, pfil hooks are registers. If NULL, not registered. 54 * Used to check the state. Locked by: softnet_lock + KERNEL_LOCK (XXX). 55 */ 56 static struct pfil_head * npf_ph_if = NULL; 57 static struct pfil_head * npf_ph_inet = NULL; 58 59 int npf_packet_handler(void *, struct mbuf **, struct ifnet *, int); 60 61 /* 62 * npf_ifhook: hook handling interface changes. 63 */ 64 static int 65 npf_ifhook(void *arg, struct mbuf **mp, struct ifnet *ifp, int di) 66 { 67 68 return 0; 69 } 70 71 /* 72 * npf_packet_handler: main packet handling routine. 73 * 74 * Note: packet flow and inspection logic is in strict order. 75 */ 76 int 77 npf_packet_handler(void *arg, struct mbuf **mp, struct ifnet *ifp, int di) 78 { 79 const int layer = (const int)(long)arg; 80 nbuf_t *nbuf = *mp; 81 npf_cache_t npc; 82 npf_session_t *se; 83 npf_rule_t *rl; 84 int error; 85 86 /* 87 * Initialise packet information cache. 88 * Note: it is enough to clear the info bits. 89 */ 90 npc.npc_info = 0; 91 92 /* Inspect the list of sessions. */ 93 se = npf_session_inspect(&npc, nbuf, ifp, di, layer); 94 95 /* Inbound NAT. */ 96 if ((di & PFIL_IN) && (error = npf_natin(&npc, se, nbuf, layer)) != 0) { 97 goto out; 98 } 99 100 /* If session found - we pass this packet. */ 101 if (se && npf_session_pass(se)) { 102 error = 0; 103 } else { 104 /* Inspect ruleset using this packet. */ 105 rl = npf_ruleset_inspect(&npc, nbuf, ifp, di, layer); 106 if (rl != NULL) { 107 bool keepstate; 108 /* Apply the rule. */ 109 error = npf_rule_apply(&npc, rl, &keepstate); 110 if (error) { 111 goto out; 112 } 113 /* Establish a session, if required. */ 114 if (keepstate) { 115 se = npf_session_establish(&npc, NULL, di); 116 } 117 } 118 /* No rules or "default" rule - pass. */ 119 } 120 121 /* Outbound NAT. */ 122 if (di & PFIL_OUT) { 123 error = npf_natout(&npc, se, nbuf, ifp, layer); 124 } 125 out: 126 /* Release reference on session. */ 127 if (se != NULL) { 128 npf_session_release(se); 129 } 130 131 /* 132 * If error is set - drop the packet. 133 * Normally, ENETUNREACH is used to "block". 134 */ 135 if (error) { 136 m_freem(*mp); 137 *mp = NULL; 138 } 139 return error; 140 } 141 142 /* 143 * npf_register_pfil: register pfil(9) hooks. 144 */ 145 int 146 npf_register_pfil(void) 147 { 148 int error; 149 150 mutex_enter(softnet_lock); 151 KERNEL_LOCK(1, NULL); 152 153 /* Check if pfil hooks are not already registered. */ 154 if (npf_ph_if) { 155 error = EEXIST; 156 goto fail; 157 } 158 159 /* Capture point of any activity in interfaces and IP layer. */ 160 npf_ph_if = pfil_head_get(PFIL_TYPE_IFNET, 0); 161 npf_ph_inet = pfil_head_get(PFIL_TYPE_AF, AF_INET); 162 if (npf_ph_if == NULL || npf_ph_inet == NULL) { 163 npf_ph_if = NULL; 164 error = ENOENT; 165 goto fail; 166 } 167 168 /* Interface re-config or attach/detach hook. */ 169 error = pfil_add_hook(npf_ifhook, NULL, 170 PFIL_WAITOK | PFIL_IFADDR | PFIL_IFNET, npf_ph_if); 171 KASSERT(error == 0); 172 173 /* Packet IN/OUT handler on all interfaces and IP layer. */ 174 error = pfil_add_hook(npf_packet_handler, (void *)NPF_LAYER_3, 175 PFIL_WAITOK | PFIL_ALL, npf_ph_inet); 176 KASSERT(error == 0); 177 178 fail: 179 KERNEL_UNLOCK_ONE(NULL); 180 mutex_exit(softnet_lock); 181 182 return error; 183 } 184 185 /* 186 * npf_unregister: unregister pfil(9) hooks. 187 */ 188 void 189 npf_unregister_pfil(void) 190 { 191 192 mutex_enter(softnet_lock); 193 KERNEL_LOCK(1, NULL); 194 195 if (npf_ph_if) { 196 (void)pfil_remove_hook(npf_packet_handler, (void *)NPF_LAYER_3, 197 PFIL_ALL, npf_ph_inet); 198 (void)pfil_remove_hook(npf_ifhook, NULL, 199 PFIL_IFADDR | PFIL_IFNET, npf_ph_if); 200 201 npf_ph_if = NULL; 202 } 203 204 KERNEL_UNLOCK_ONE(NULL); 205 mutex_exit(softnet_lock); 206 } 207