1/*- 2 * Copyright (c) 2004 Ruslan Ermilov and Vsevolod Lobko. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 14 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 16 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 17 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 18 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 19 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 20 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 21 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 23 * SUCH DAMAGE. 24 */ 25 26#include <sys/cdefs.h>
| 1/*- 2 * Copyright (c) 2004 Ruslan Ermilov and Vsevolod Lobko. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 14 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 16 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 17 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 18 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 19 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 20 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 21 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 23 * SUCH DAMAGE. 24 */ 25 26#include <sys/cdefs.h>
|
27__FBSDID("$FreeBSD: head/sys/netinet/ipfw/ip_fw_table.c 200838 2009-12-22 13:53:34Z luigi $");
| 27__FBSDID("$FreeBSD: head/sys/netinet/ipfw/ip_fw_table.c 201120 2009-12-28 10:12:35Z luigi $");
|
28 29/* 30 * Lookup table support for ipfw 31 * 32 * Lookup tables are implemented (at the moment) using the radix 33 * tree used for routing tables. Tables store key-value entries, where 34 * keys are network prefixes (addr/masklen), and values are integers. 35 * As a degenerate case we can interpret keys as 32-bit integers 36 * (with a /32 mask). 37 * 38 * The table is protected by the IPFW lock even for manipulation coming 39 * from userland, because operations are typically fast. 40 */ 41 42#if !defined(KLD_MODULE) 43#include "opt_ipfw.h" 44#include "opt_ipdivert.h" 45#include "opt_ipdn.h" 46#include "opt_inet.h" 47#ifndef INET 48#error IPFIREWALL requires INET. 49#endif /* INET */ 50#endif 51#include "opt_inet6.h" 52#include "opt_ipsec.h" 53 54#include <sys/param.h> 55#include <sys/systm.h> 56#include <sys/malloc.h> 57#include <sys/kernel.h> 58#include <sys/lock.h> 59#include <sys/rwlock.h> 60#include <sys/socket.h> 61#include <net/if.h> /* ip_fw.h requires IFNAMSIZ */ 62#include <net/radix.h> 63#include <net/route.h> 64#include <net/vnet.h> 65 66#include <netinet/in.h> 67#include <netinet/ip_fw.h> 68#include <netinet/ipfw/ip_fw_private.h> 69 70#ifdef MAC 71#include <security/mac/mac_framework.h> 72#endif 73 74MALLOC_DEFINE(M_IPFW_TBL, "ipfw_tbl", "IpFw tables"); 75 76struct table_entry { 77 struct radix_node rn[2]; 78 struct sockaddr_in addr, mask; 79 u_int32_t value; 80}; 81
| 28 29/* 30 * Lookup table support for ipfw 31 * 32 * Lookup tables are implemented (at the moment) using the radix 33 * tree used for routing tables. Tables store key-value entries, where 34 * keys are network prefixes (addr/masklen), and values are integers. 35 * As a degenerate case we can interpret keys as 32-bit integers 36 * (with a /32 mask). 37 * 38 * The table is protected by the IPFW lock even for manipulation coming 39 * from userland, because operations are typically fast. 40 */ 41 42#if !defined(KLD_MODULE) 43#include "opt_ipfw.h" 44#include "opt_ipdivert.h" 45#include "opt_ipdn.h" 46#include "opt_inet.h" 47#ifndef INET 48#error IPFIREWALL requires INET. 49#endif /* INET */ 50#endif 51#include "opt_inet6.h" 52#include "opt_ipsec.h" 53 54#include <sys/param.h> 55#include <sys/systm.h> 56#include <sys/malloc.h> 57#include <sys/kernel.h> 58#include <sys/lock.h> 59#include <sys/rwlock.h> 60#include <sys/socket.h> 61#include <net/if.h> /* ip_fw.h requires IFNAMSIZ */ 62#include <net/radix.h> 63#include <net/route.h> 64#include <net/vnet.h> 65 66#include <netinet/in.h> 67#include <netinet/ip_fw.h> 68#include <netinet/ipfw/ip_fw_private.h> 69 70#ifdef MAC 71#include <security/mac/mac_framework.h> 72#endif 73 74MALLOC_DEFINE(M_IPFW_TBL, "ipfw_tbl", "IpFw tables"); 75 76struct table_entry { 77 struct radix_node rn[2]; 78 struct sockaddr_in addr, mask; 79 u_int32_t value; 80}; 81
|
| 82/* 83 * The radix code expects addr and mask to be array of bytes, 84 * with the first byte being the length of the array. rn_inithead 85 * is called with the offset in bits of the lookup key within the 86 * array. If we use a sockaddr_in as the underlying type, 87 * sin_len is conveniently located at offset 0, sin_addr is at 88 * offset 4 and normally aligned. 89 * But for portability, let's avoid assumption and make the code explicit 90 */ 91#define KEY_LEN(v) *((uint8_t *)&(v)) 92#define KEY_OFS (8*offsetof(struct sockaddr_in, sin_addr)) 93
|
82int 83ipfw_add_table_entry(struct ip_fw_chain *ch, uint16_t tbl, in_addr_t addr, 84 uint8_t mlen, uint32_t value) 85{ 86 struct radix_node_head *rnh; 87 struct table_entry *ent; 88 struct radix_node *rn; 89 90 if (tbl >= IPFW_TABLES_MAX) 91 return (EINVAL); 92 rnh = ch->tables[tbl]; 93 ent = malloc(sizeof(*ent), M_IPFW_TBL, M_NOWAIT | M_ZERO); 94 if (ent == NULL) 95 return (ENOMEM); 96 ent->value = value;
| 94int 95ipfw_add_table_entry(struct ip_fw_chain *ch, uint16_t tbl, in_addr_t addr, 96 uint8_t mlen, uint32_t value) 97{ 98 struct radix_node_head *rnh; 99 struct table_entry *ent; 100 struct radix_node *rn; 101 102 if (tbl >= IPFW_TABLES_MAX) 103 return (EINVAL); 104 rnh = ch->tables[tbl]; 105 ent = malloc(sizeof(*ent), M_IPFW_TBL, M_NOWAIT | M_ZERO); 106 if (ent == NULL) 107 return (ENOMEM); 108 ent->value = value;
|
97 ent->addr.sin_len = ent->mask.sin_len = 8;
| 109 KEY_LEN(ent->addr) = KEY_LEN(ent->mask) = 8;
|
98 ent->mask.sin_addr.s_addr = htonl(mlen ? ~((1 << (32 - mlen)) - 1) : 0); 99 ent->addr.sin_addr.s_addr = addr & ent->mask.sin_addr.s_addr; 100 IPFW_WLOCK(ch); 101 rn = rnh->rnh_addaddr(&ent->addr, &ent->mask, rnh, (void *)ent); 102 if (rn == NULL) { 103 IPFW_WUNLOCK(ch); 104 free(ent, M_IPFW_TBL); 105 return (EEXIST); 106 } 107 IPFW_WUNLOCK(ch); 108 return (0); 109} 110 111int 112ipfw_del_table_entry(struct ip_fw_chain *ch, uint16_t tbl, in_addr_t addr, 113 uint8_t mlen) 114{ 115 struct radix_node_head *rnh; 116 struct table_entry *ent; 117 struct sockaddr_in sa, mask; 118 119 if (tbl >= IPFW_TABLES_MAX) 120 return (EINVAL); 121 rnh = ch->tables[tbl];
| 110 ent->mask.sin_addr.s_addr = htonl(mlen ? ~((1 << (32 - mlen)) - 1) : 0); 111 ent->addr.sin_addr.s_addr = addr & ent->mask.sin_addr.s_addr; 112 IPFW_WLOCK(ch); 113 rn = rnh->rnh_addaddr(&ent->addr, &ent->mask, rnh, (void *)ent); 114 if (rn == NULL) { 115 IPFW_WUNLOCK(ch); 116 free(ent, M_IPFW_TBL); 117 return (EEXIST); 118 } 119 IPFW_WUNLOCK(ch); 120 return (0); 121} 122 123int 124ipfw_del_table_entry(struct ip_fw_chain *ch, uint16_t tbl, in_addr_t addr, 125 uint8_t mlen) 126{ 127 struct radix_node_head *rnh; 128 struct table_entry *ent; 129 struct sockaddr_in sa, mask; 130 131 if (tbl >= IPFW_TABLES_MAX) 132 return (EINVAL); 133 rnh = ch->tables[tbl];
|
122 sa.sin_len = mask.sin_len = 8;
| 134 KEY_LEN(sa) = KEY_LEN(mask) = 8;
|
123 mask.sin_addr.s_addr = htonl(mlen ? ~((1 << (32 - mlen)) - 1) : 0); 124 sa.sin_addr.s_addr = addr & mask.sin_addr.s_addr; 125 IPFW_WLOCK(ch); 126 ent = (struct table_entry *)rnh->rnh_deladdr(&sa, &mask, rnh); 127 if (ent == NULL) { 128 IPFW_WUNLOCK(ch); 129 return (ESRCH); 130 } 131 IPFW_WUNLOCK(ch); 132 free(ent, M_IPFW_TBL); 133 return (0); 134} 135 136static int 137flush_table_entry(struct radix_node *rn, void *arg) 138{ 139 struct radix_node_head * const rnh = arg; 140 struct table_entry *ent; 141 142 ent = (struct table_entry *) 143 rnh->rnh_deladdr(rn->rn_key, rn->rn_mask, rnh); 144 if (ent != NULL) 145 free(ent, M_IPFW_TBL); 146 return (0); 147} 148 149int 150ipfw_flush_table(struct ip_fw_chain *ch, uint16_t tbl) 151{ 152 struct radix_node_head *rnh; 153 154 IPFW_WLOCK_ASSERT(ch); 155 156 if (tbl >= IPFW_TABLES_MAX) 157 return (EINVAL); 158 rnh = ch->tables[tbl]; 159 KASSERT(rnh != NULL, ("NULL IPFW table")); 160 rnh->rnh_walktree(rnh, flush_table_entry, rnh); 161 return (0); 162} 163 164void 165ipfw_flush_tables(struct ip_fw_chain *ch) 166{ 167 uint16_t tbl; 168 169 IPFW_WLOCK_ASSERT(ch); 170 171 for (tbl = 0; tbl < IPFW_TABLES_MAX; tbl++) 172 ipfw_flush_table(ch, tbl); 173} 174 175int 176ipfw_init_tables(struct ip_fw_chain *ch) 177{ 178 int i; 179 uint16_t j; 180 181 for (i = 0; i < IPFW_TABLES_MAX; i++) {
| 135 mask.sin_addr.s_addr = htonl(mlen ? ~((1 << (32 - mlen)) - 1) : 0); 136 sa.sin_addr.s_addr = addr & mask.sin_addr.s_addr; 137 IPFW_WLOCK(ch); 138 ent = (struct table_entry *)rnh->rnh_deladdr(&sa, &mask, rnh); 139 if (ent == NULL) { 140 IPFW_WUNLOCK(ch); 141 return (ESRCH); 142 } 143 IPFW_WUNLOCK(ch); 144 free(ent, M_IPFW_TBL); 145 return (0); 146} 147 148static int 149flush_table_entry(struct radix_node *rn, void *arg) 150{ 151 struct radix_node_head * const rnh = arg; 152 struct table_entry *ent; 153 154 ent = (struct table_entry *) 155 rnh->rnh_deladdr(rn->rn_key, rn->rn_mask, rnh); 156 if (ent != NULL) 157 free(ent, M_IPFW_TBL); 158 return (0); 159} 160 161int 162ipfw_flush_table(struct ip_fw_chain *ch, uint16_t tbl) 163{ 164 struct radix_node_head *rnh; 165 166 IPFW_WLOCK_ASSERT(ch); 167 168 if (tbl >= IPFW_TABLES_MAX) 169 return (EINVAL); 170 rnh = ch->tables[tbl]; 171 KASSERT(rnh != NULL, ("NULL IPFW table")); 172 rnh->rnh_walktree(rnh, flush_table_entry, rnh); 173 return (0); 174} 175 176void 177ipfw_flush_tables(struct ip_fw_chain *ch) 178{ 179 uint16_t tbl; 180 181 IPFW_WLOCK_ASSERT(ch); 182 183 for (tbl = 0; tbl < IPFW_TABLES_MAX; tbl++) 184 ipfw_flush_table(ch, tbl); 185} 186 187int 188ipfw_init_tables(struct ip_fw_chain *ch) 189{ 190 int i; 191 uint16_t j; 192 193 for (i = 0; i < IPFW_TABLES_MAX; i++) {
|
182 if (!rn_inithead((void **)&ch->tables[i], 32)) {
| 194 if (!rn_inithead((void **)&ch->tables[i], KEY_OFS)) {
|
183 for (j = 0; j < i; j++) { 184 (void) ipfw_flush_table(ch, j); 185 } 186 return (ENOMEM); 187 } 188 } 189 return (0); 190} 191 192int 193ipfw_lookup_table(struct ip_fw_chain *ch, uint16_t tbl, in_addr_t addr, 194 uint32_t *val) 195{ 196 struct radix_node_head *rnh; 197 struct table_entry *ent; 198 struct sockaddr_in sa; 199 200 if (tbl >= IPFW_TABLES_MAX) 201 return (0); 202 rnh = ch->tables[tbl];
| 195 for (j = 0; j < i; j++) { 196 (void) ipfw_flush_table(ch, j); 197 } 198 return (ENOMEM); 199 } 200 } 201 return (0); 202} 203 204int 205ipfw_lookup_table(struct ip_fw_chain *ch, uint16_t tbl, in_addr_t addr, 206 uint32_t *val) 207{ 208 struct radix_node_head *rnh; 209 struct table_entry *ent; 210 struct sockaddr_in sa; 211 212 if (tbl >= IPFW_TABLES_MAX) 213 return (0); 214 rnh = ch->tables[tbl];
|
203 sa.sin_len = 8;
| 215 KEY_LEN(sa) = 8;
|
204 sa.sin_addr.s_addr = addr; 205 ent = (struct table_entry *)(rnh->rnh_lookup(&sa, NULL, rnh)); 206 if (ent != NULL) { 207 *val = ent->value; 208 return (1); 209 } 210 return (0); 211} 212 213static int 214count_table_entry(struct radix_node *rn, void *arg) 215{ 216 u_int32_t * const cnt = arg; 217 218 (*cnt)++; 219 return (0); 220} 221 222int 223ipfw_count_table(struct ip_fw_chain *ch, uint32_t tbl, uint32_t *cnt) 224{ 225 struct radix_node_head *rnh; 226 227 if (tbl >= IPFW_TABLES_MAX) 228 return (EINVAL); 229 rnh = ch->tables[tbl]; 230 *cnt = 0; 231 rnh->rnh_walktree(rnh, count_table_entry, cnt); 232 return (0); 233} 234 235static int 236dump_table_entry(struct radix_node *rn, void *arg) 237{ 238 struct table_entry * const n = (struct table_entry *)rn; 239 ipfw_table * const tbl = arg; 240 ipfw_table_entry *ent; 241 242 if (tbl->cnt == tbl->size) 243 return (1); 244 ent = &tbl->ent[tbl->cnt]; 245 ent->tbl = tbl->tbl; 246 if (in_nullhost(n->mask.sin_addr)) 247 ent->masklen = 0; 248 else 249 ent->masklen = 33 - ffs(ntohl(n->mask.sin_addr.s_addr)); 250 ent->addr = n->addr.sin_addr.s_addr; 251 ent->value = n->value; 252 tbl->cnt++; 253 return (0); 254} 255 256int 257ipfw_dump_table(struct ip_fw_chain *ch, ipfw_table *tbl) 258{ 259 struct radix_node_head *rnh; 260 261 if (tbl->tbl >= IPFW_TABLES_MAX) 262 return (EINVAL); 263 rnh = ch->tables[tbl->tbl]; 264 tbl->cnt = 0; 265 rnh->rnh_walktree(rnh, dump_table_entry, tbl); 266 return (0); 267} 268/* end of file */
| 216 sa.sin_addr.s_addr = addr; 217 ent = (struct table_entry *)(rnh->rnh_lookup(&sa, NULL, rnh)); 218 if (ent != NULL) { 219 *val = ent->value; 220 return (1); 221 } 222 return (0); 223} 224 225static int 226count_table_entry(struct radix_node *rn, void *arg) 227{ 228 u_int32_t * const cnt = arg; 229 230 (*cnt)++; 231 return (0); 232} 233 234int 235ipfw_count_table(struct ip_fw_chain *ch, uint32_t tbl, uint32_t *cnt) 236{ 237 struct radix_node_head *rnh; 238 239 if (tbl >= IPFW_TABLES_MAX) 240 return (EINVAL); 241 rnh = ch->tables[tbl]; 242 *cnt = 0; 243 rnh->rnh_walktree(rnh, count_table_entry, cnt); 244 return (0); 245} 246 247static int 248dump_table_entry(struct radix_node *rn, void *arg) 249{ 250 struct table_entry * const n = (struct table_entry *)rn; 251 ipfw_table * const tbl = arg; 252 ipfw_table_entry *ent; 253 254 if (tbl->cnt == tbl->size) 255 return (1); 256 ent = &tbl->ent[tbl->cnt]; 257 ent->tbl = tbl->tbl; 258 if (in_nullhost(n->mask.sin_addr)) 259 ent->masklen = 0; 260 else 261 ent->masklen = 33 - ffs(ntohl(n->mask.sin_addr.s_addr)); 262 ent->addr = n->addr.sin_addr.s_addr; 263 ent->value = n->value; 264 tbl->cnt++; 265 return (0); 266} 267 268int 269ipfw_dump_table(struct ip_fw_chain *ch, ipfw_table *tbl) 270{ 271 struct radix_node_head *rnh; 272 273 if (tbl->tbl >= IPFW_TABLES_MAX) 274 return (EINVAL); 275 rnh = ch->tables[tbl->tbl]; 276 tbl->cnt = 0; 277 rnh->rnh_walktree(rnh, dump_table_entry, tbl); 278 return (0); 279} 280/* end of file */
|