NPF checkpoint: - Add support for bi-directional NAT and redirection / port forwarding. - Finish filtering on ICMP type/code and add filtering on TCP flags. - Add support for TCP reset (RST) or ICMP destination unreachable on block. - Fix a bunch of bugs; misc cleanup.diff -r1.3 -r1.4 src/share/man/man9/npf_ncode.9
(rmind)
--- src/share/man/man9/Attic/npf_ncode.9 2010/08/24 23:55:05 1.3
+++ src/share/man/man9/Attic/npf_ncode.9 2010/09/16 04:53:27 1.4
--- src/sys/modules/npf/Makefile 2010/08/22 18:56:22 1.1
+++ src/sys/modules/npf/Makefile 2010/09/16 04:53:27 1.2
@@ -1,13 +1,13 @@ | @@ -1,13 +1,13 @@ | |||
1 | # $NetBSD: Makefile,v 1.1 2010/08/22 18:56:22 rmind Exp $ | 1 | # $NetBSD: Makefile,v 1.2 2010/09/16 04:53:27 rmind Exp $ | |
2 | 2 | |||
3 | .include "../Makefile.inc" | 3 | .include "../Makefile.inc" | |
4 | 4 | |||
5 | .PATH: ${S}/net/npf | 5 | .PATH: ${S}/net/npf | |
6 | 6 | |||
7 | KMOD= npf | 7 | KMOD= npf | |
8 | 8 | |||
9 | SRCS= npf.c npf_ctl.c npf_handler.c npf_instr.c npf_mbuf.c | 9 | SRCS= npf.c npf_ctl.c npf_handler.c npf_instr.c npf_mbuf.c | |
10 | SRCS+= npf_processor.c npf_ruleset.c npf_tableset.c npf_inet.c | 10 | SRCS+= npf_processor.c npf_ruleset.c npf_tableset.c npf_inet.c | |
11 | SRCS+= npf_session.c npf_nat.c npf_alg.c | 11 | SRCS+= npf_session.c npf_nat.c npf_sendpkt.c npf_alg.c | |
12 | 12 | |||
13 | .include <bsd.kmodule.mk> | 13 | .include <bsd.kmodule.mk> |
--- src/sys/net/npf/files.npf 2010/08/22 18:56:22 1.1
+++ src/sys/net/npf/files.npf 2010/09/16 04:53:27 1.2
@@ -1,23 +1,28 @@ | @@ -1,23 +1,28 @@ | |||
1 | # $NetBSD: files.npf,v 1.1 2010/08/22 18:56:22 rmind Exp $ | 1 | # $NetBSD: files.npf,v 1.2 2010/09/16 04:53:27 rmind Exp $ | |
2 | # | 2 | # | |
3 | # Public Domain. | 3 | # Public Domain. | |
4 | # | 4 | # | |
5 | 5 | |||
6 | # | 6 | # | |
7 | # NPF pseudo device and modules. | 7 | # NPF pseudo device and modules. | |
8 | # | 8 | # | |
9 | 9 | |||
10 | defpseudo npf: ifnet | 10 | defpseudo npf: ifnet | |
11 | 11 | |||
12 | # Core | |||
12 | file net/npf/npf.c npf | 13 | file net/npf/npf.c npf | |
13 | file net/npf/npf_ctl.c npf | 14 | file net/npf/npf_ctl.c npf | |
14 | file net/npf/npf_handler.c npf | 15 | file net/npf/npf_handler.c npf | |
15 | file net/npf/npf_instr.c npf | 16 | file net/npf/npf_instr.c npf | |
16 | file net/npf/npf_mbuf.c npf | 17 | file net/npf/npf_mbuf.c npf | |
17 | file net/npf/npf_processor.c npf | 18 | file net/npf/npf_processor.c npf | |
18 | file net/npf/npf_ruleset.c npf | 19 | file net/npf/npf_ruleset.c npf | |
19 | file net/npf/npf_tableset.c npf | 20 | file net/npf/npf_tableset.c npf | |
20 | file net/npf/npf_inet.c npf | 21 | file net/npf/npf_inet.c npf | |
21 | file net/npf/npf_session.c npf | 22 | file net/npf/npf_session.c npf | |
22 | file net/npf/npf_nat.c npf | 23 | file net/npf/npf_nat.c npf | |
23 | file net/npf/npf_alg.c npf | 24 | file net/npf/npf_alg.c npf | |
25 | file net/npf/npf_sendpkt.c npf | |||
26 | ||||
27 | # ALGs | |||
28 | file net/npf/npf_alg_icmp.c npf |
--- src/sys/net/npf/npf.h 2010/08/22 18:56:22 1.1
+++ src/sys/net/npf/npf.h 2010/09/16 04:53:27 1.2
@@ -1,14 +1,14 @@ | @@ -1,14 +1,14 @@ | |||
1 | /* $NetBSD: npf.h,v 1.1 2010/08/22 18:56:22 rmind Exp $ */ | 1 | /* $NetBSD: npf.h,v 1.2 2010/09/16 04:53:27 rmind Exp $ */ | |
2 | 2 | |||
3 | /*- | 3 | /*- | |
4 | * Copyright (c) 2009-2010 The NetBSD Foundation, Inc. | 4 | * Copyright (c) 2009-2010 The NetBSD Foundation, Inc. | |
5 | * All rights reserved. | 5 | * All rights reserved. | |
6 | * | 6 | * | |
7 | * This material is based upon work partially supported by The | 7 | * This material is based upon work partially supported by The | |
8 | * NetBSD Foundation under a contract with Mindaugas Rasiukevicius. | 8 | * NetBSD Foundation under a contract with Mindaugas Rasiukevicius. | |
9 | * | 9 | * | |
10 | * Redistribution and use in source and binary forms, with or without | 10 | * Redistribution and use in source and binary forms, with or without | |
11 | * modification, are permitted provided that the following conditions | 11 | * modification, are permitted provided that the following conditions | |
12 | * are met: | 12 | * are met: | |
13 | * 1. Redistributions of source code must retain the above copyright | 13 | * 1. Redistributions of source code must retain the above copyright | |
14 | * notice, this list of conditions and the following disclaimer. | 14 | * notice, this list of conditions and the following disclaimer. | |
@@ -71,27 +71,26 @@ typedef void nbuf_t; | @@ -71,27 +71,26 @@ typedef void nbuf_t; | |||
71 | */ | 71 | */ | |
72 | 72 | |||
73 | #define NPC_IP46 0x01 /* IPv4,6 packet with known protocol. */ | 73 | #define NPC_IP46 0x01 /* IPv4,6 packet with known protocol. */ | |
74 | #define NPC_IP6VER 0x02 /* If NPI_IP46, then: 0 - IPv4, 1 - IPv6. */ | 74 | #define NPC_IP6VER 0x02 /* If NPI_IP46, then: 0 - IPv4, 1 - IPv6. */ | |
75 | #define NPC_ADDRS 0x04 /* Known source and destination addresses. */ | 75 | #define NPC_ADDRS 0x04 /* Known source and destination addresses. */ | |
76 | #define NPC_PORTS 0x08 /* Known ports (for TCP/UDP cases). */ | 76 | #define NPC_PORTS 0x08 /* Known ports (for TCP/UDP cases). */ | |
77 | #define NPC_ICMP 0x10 /* ICMP with known type and code. */ | 77 | #define NPC_ICMP 0x10 /* ICMP with known type and code. */ | |
78 | #define NPC_ICMP_ID 0x20 /* ICMP with query ID. */ | 78 | #define NPC_ICMP_ID 0x20 /* ICMP with query ID. */ | |
79 | 79 | |||
80 | /* XXX: Optimise later, pack in unions, perhaps bitfields, etc. */ | 80 | /* XXX: Optimise later, pack in unions, perhaps bitfields, etc. */ | |
81 | typedef struct { | 81 | typedef struct { | |
82 | uint32_t npc_info; | 82 | uint32_t npc_info; | |
83 | int npc_dir; | 83 | int npc_dir; | |
84 | uint8_t npc_elen; | |||
85 | /* NPC_IP46 */ | 84 | /* NPC_IP46 */ | |
86 | uint8_t npc_proto; | 85 | uint8_t npc_proto; | |
87 | uint16_t npc_hlen; | 86 | uint16_t npc_hlen; | |
88 | uint16_t npc_ipsum; | 87 | uint16_t npc_ipsum; | |
89 | /* NPC_ADDRS */ | 88 | /* NPC_ADDRS */ | |
90 | in_addr_t npc_srcip; | 89 | in_addr_t npc_srcip; | |
91 | in_addr_t npc_dstip; | 90 | in_addr_t npc_dstip; | |
92 | /* NPC_PORTS */ | 91 | /* NPC_PORTS */ | |
93 | in_port_t npc_sport; | 92 | in_port_t npc_sport; | |
94 | in_port_t npc_dport; | 93 | in_port_t npc_dport; | |
95 | uint8_t npc_tcp_flags; | 94 | uint8_t npc_tcp_flags; | |
96 | /* NPC_ICMP */ | 95 | /* NPC_ICMP */ | |
97 | uint8_t npc_icmp_type; | 96 | uint8_t npc_icmp_type; | |
@@ -117,40 +116,49 @@ int nbuf_store_datum(nbuf_t *, void *, | @@ -117,40 +116,49 @@ int nbuf_store_datum(nbuf_t *, void *, | |||
117 | int nbuf_add_tag(nbuf_t *, uint32_t, uint32_t); | 116 | int nbuf_add_tag(nbuf_t *, uint32_t, uint32_t); | |
118 | int nbuf_find_tag(nbuf_t *, uint32_t, void **); | 117 | int nbuf_find_tag(nbuf_t *, uint32_t, void **); | |
119 | 118 | |||
120 | /* Ruleset interface. */ | 119 | /* Ruleset interface. */ | |
121 | npf_rule_t * npf_rule_alloc(int, pri_t, int, void *, size_t); | 120 | npf_rule_t * npf_rule_alloc(int, pri_t, int, void *, size_t); | |
122 | void npf_rule_free(npf_rule_t *); | 121 | void npf_rule_free(npf_rule_t *); | |
123 | void npf_activate_rule(npf_rule_t *); | 122 | void npf_activate_rule(npf_rule_t *); | |
124 | void npf_deactivate_rule(npf_rule_t *); | 123 | void npf_deactivate_rule(npf_rule_t *); | |
125 | 124 | |||
126 | npf_hook_t * npf_hook_register(npf_rule_t *, | 125 | npf_hook_t * npf_hook_register(npf_rule_t *, | |
127 | void (*)(const npf_cache_t *, void *), void *); | 126 | void (*)(const npf_cache_t *, void *), void *); | |
128 | void npf_hook_unregister(npf_rule_t *, npf_hook_t *); | 127 | void npf_hook_unregister(npf_rule_t *, npf_hook_t *); | |
129 | 128 | |||
130 | #endif | 129 | #endif /* _KERNEL */ | |
131 | 130 | |||
132 | /* Rule attributes. */ | 131 | /* Rule attributes. */ | |
133 | #define NPF_RULE_PASS 0x0001 | 132 | #define NPF_RULE_PASS 0x0001 | |
134 | #define NPF_RULE_COUNT 0x0002 | 133 | #define NPF_RULE_COUNT 0x0002 | |
135 | #define NPF_RULE_FINAL 0x0004 | 134 | #define NPF_RULE_FINAL 0x0004 | |
136 | #define NPF_RULE_LOG 0x0008 | 135 | #define NPF_RULE_LOG 0x0008 | |
137 | #define NPF_RULE_DEFAULT 0x0010 | 136 | #define NPF_RULE_DEFAULT 0x0010 | |
138 | #define NPF_RULE_KEEPSTATE 0x0020 | 137 | #define NPF_RULE_KEEPSTATE 0x0020 | |
138 | #define NPF_RULE_RETRST 0x0040 | |||
139 | #define NPF_RULE_RETICMP 0x0080 | |||
139 | 140 | |||
140 | #define NPF_RULE_IN 0x1000 | 141 | #define NPF_RULE_IN 0x1000 | |
141 | #define NPF_RULE_OUT 0x2000 | 142 | #define NPF_RULE_OUT 0x2000 | |
142 | #define NPF_RULE_DIMASK 0x3000 | 143 | #define NPF_RULE_DIMASK 0x3000 | |
143 | 144 | |||
145 | /* Address translation types and flags. */ | |||
146 | #define NPF_NATIN 1 | |||
147 | #define NPF_NATOUT 2 | |||
148 | ||||
149 | #define NPF_NAT_PORTS 0x01 | |||
150 | #define NPF_NAT_PORTMAP 0x02 | |||
151 | ||||
144 | /* Table types. */ | 152 | /* Table types. */ | |
145 | #define NPF_TABLE_HASH 1 | 153 | #define NPF_TABLE_HASH 1 | |
146 | #define NPF_TABLE_RBTREE 2 | 154 | #define NPF_TABLE_RBTREE 2 | |
147 | 155 | |||
148 | /* Layers. */ | 156 | /* Layers. */ | |
149 | #define NPF_LAYER_2 2 | 157 | #define NPF_LAYER_2 2 | |
150 | #define NPF_LAYER_3 3 | 158 | #define NPF_LAYER_3 3 | |
151 | 159 | |||
152 | /* XXX mbuf.h: just for now. */ | 160 | /* XXX mbuf.h: just for now. */ | |
153 | #define PACKET_TAG_NPF 10 | 161 | #define PACKET_TAG_NPF 10 | |
154 | 162 | |||
155 | /* | 163 | /* | |
156 | * IOCTL structures. | 164 | * IOCTL structures. | |
@@ -166,14 +174,14 @@ typedef struct npf_ioctl_table { | @@ -166,14 +174,14 @@ typedef struct npf_ioctl_table { | |||
166 | in_addr_t nct_mask; | 174 | in_addr_t nct_mask; | |
167 | int _reserved; | 175 | int _reserved; | |
168 | } npf_ioctl_table_t; | 176 | } npf_ioctl_table_t; | |
169 | 177 | |||
170 | /* | 178 | /* | |
171 | * IOCTL operations. | 179 | * IOCTL operations. | |
172 | */ | 180 | */ | |
173 | 181 | |||
174 | #define IOC_NPF_VERSION _IOR('N', 100, int) | 182 | #define IOC_NPF_VERSION _IOR('N', 100, int) | |
175 | #define IOC_NPF_SWITCH _IOW('N', 101, int) | 183 | #define IOC_NPF_SWITCH _IOW('N', 101, int) | |
176 | #define IOC_NPF_RELOAD _IOW('N', 102, struct plistref) | 184 | #define IOC_NPF_RELOAD _IOW('N', 102, struct plistref) | |
177 | #define IOC_NPF_TABLE _IOW('N', 103, struct npf_ioctl_table) | 185 | #define IOC_NPF_TABLE _IOW('N', 103, struct npf_ioctl_table) | |
178 | 186 | |||
179 | #endif | 187 | #endif /* _NPF_H_ */ |
--- src/sys/net/npf/npf_alg_icmp.c 2010/08/22 18:56:22 1.1
+++ src/sys/net/npf/npf_alg_icmp.c 2010/09/16 04:53:27 1.2
@@ -1,14 +1,14 @@ | @@ -1,14 +1,14 @@ | |||
1 | /* $NetBSD: npf_alg_icmp.c,v 1.1 2010/08/22 18:56:22 rmind Exp $ */ | 1 | /* $NetBSD: npf_alg_icmp.c,v 1.2 2010/09/16 04:53:27 rmind Exp $ */ | |
2 | 2 | |||
3 | /*- | 3 | /*- | |
4 | * Copyright (c) 2010 The NetBSD Foundation, Inc. | 4 | * Copyright (c) 2010 The NetBSD Foundation, Inc. | |
5 | * All rights reserved. | 5 | * All rights reserved. | |
6 | * | 6 | * | |
7 | * This material is based upon work partially supported by The | 7 | * This material is based upon work partially supported by The | |
8 | * NetBSD Foundation under a contract with Mindaugas Rasiukevicius. | 8 | * NetBSD Foundation under a contract with Mindaugas Rasiukevicius. | |
9 | * | 9 | * | |
10 | * Redistribution and use in source and binary forms, with or without | 10 | * Redistribution and use in source and binary forms, with or without | |
11 | * modification, are permitted provided that the following conditions | 11 | * modification, are permitted provided that the following conditions | |
12 | * are met: | 12 | * are met: | |
13 | * 1. Redistributions of source code must retain the above copyright | 13 | * 1. Redistributions of source code must retain the above copyright | |
14 | * notice, this list of conditions and the following disclaimer. | 14 | * notice, this list of conditions and the following disclaimer. | |
@@ -25,27 +25,27 @@ | @@ -25,27 +25,27 @@ | |||
25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | 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 | 26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | |
27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | 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 | 28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |
29 | * POSSIBILITY OF SUCH DAMAGE. | 29 | * POSSIBILITY OF SUCH DAMAGE. | |
30 | */ | 30 | */ | |
31 | 31 | |||
32 | /* | 32 | /* | |
33 | * NPF ALG for ICMP and traceroute translations. | 33 | * NPF ALG for ICMP and traceroute translations. | |
34 | */ | 34 | */ | |
35 | 35 | |||
36 | #ifdef _KERNEL | 36 | #ifdef _KERNEL | |
37 | #include <sys/cdefs.h> | 37 | #include <sys/cdefs.h> | |
38 | __KERNEL_RCSID(0, "$NetBSD: npf_alg_icmp.c,v 1.1 2010/08/22 18:56:22 rmind Exp $"); | 38 | __KERNEL_RCSID(0, "$NetBSD: npf_alg_icmp.c,v 1.2 2010/09/16 04:53:27 rmind Exp $"); | |
39 | 39 | |||
40 | #include <sys/param.h> | 40 | #include <sys/param.h> | |
41 | #include <sys/kernel.h> | 41 | #include <sys/kernel.h> | |
42 | #endif | 42 | #endif | |
43 | #include <sys/module.h> | 43 | #include <sys/module.h> | |
44 | #include <sys/pool.h> | 44 | #include <sys/pool.h> | |
45 | 45 | |||
46 | #include <netinet/in_systm.h> | 46 | #include <netinet/in_systm.h> | |
47 | #include <netinet/in.h> | 47 | #include <netinet/in.h> | |
48 | #include <netinet/ip.h> | 48 | #include <netinet/ip.h> | |
49 | #include <netinet/tcp.h> | 49 | #include <netinet/tcp.h> | |
50 | #include <netinet/udp.h> | 50 | #include <netinet/udp.h> | |
51 | #include <netinet/ip_icmp.h> | 51 | #include <netinet/ip_icmp.h> | |
@@ -218,31 +218,26 @@ npfa_icmp_session(npf_cache_t *npc, nbuf | @@ -218,31 +218,26 @@ npfa_icmp_session(npf_cache_t *npc, nbuf | |||
218 | { | 218 | { | |
219 | npf_cache_t *key = keyptr; | 219 | npf_cache_t *key = keyptr; | |
220 | void *n_ptr; | 220 | void *n_ptr; | |
221 | 221 | |||
222 | /* ICMP? Get unique identifiers from ICMP packet. */ | 222 | /* ICMP? Get unique identifiers from ICMP packet. */ | |
223 | if (npc->npc_proto != IPPROTO_ICMP) { | 223 | if (npc->npc_proto != IPPROTO_ICMP) { | |
224 | return false; | 224 | return false; | |
225 | } | 225 | } | |
226 | KASSERT(npf_iscached(npc, NPC_IP46 | NPC_ICMP)); | 226 | KASSERT(npf_iscached(npc, NPC_IP46 | NPC_ICMP)); | |
227 | key->npc_info = NPC_ICMP; | 227 | key->npc_info = NPC_ICMP; | |
228 | 228 | |||
229 | /* Advance to ICMP header. */ | 229 | /* Advance to ICMP header. */ | |
230 | n_ptr = nbuf_dataptr(nbuf); | 230 | n_ptr = nbuf_dataptr(nbuf); | |
231 | #ifdef _NPF_TESTING | |||
232 | if (npc->npc_elen && /* XXX */ | |||
233 | (n_ptr = nbuf_advance(&nbuf, n_ptr, npc->npc_elen)) == NULL) | |||
234 | return false; | |||
235 | #endif | |||
236 | if ((n_ptr = nbuf_advance(&nbuf, n_ptr, npc->npc_hlen)) == NULL) { | 231 | if ((n_ptr = nbuf_advance(&nbuf, n_ptr, npc->npc_hlen)) == NULL) { | |
237 | return false; | 232 | return false; | |
238 | } | 233 | } | |
239 | 234 | |||
240 | /* Fetch into the separate (key) cache. */ | 235 | /* Fetch into the separate (key) cache. */ | |
241 | if (!npf_icmp_uniqid(npc->npc_icmp_type, key, nbuf, n_ptr)) { | 236 | if (!npf_icmp_uniqid(npc->npc_icmp_type, key, nbuf, n_ptr)) { | |
242 | return false; | 237 | return false; | |
243 | } | 238 | } | |
244 | 239 | |||
245 | if (npf_iscached(key, NPC_ICMP_ID)) { | 240 | if (npf_iscached(key, NPC_ICMP_ID)) { | |
246 | /* Construct the key. */ | 241 | /* Construct the key. */ | |
247 | key->npc_proto = npc->npc_proto; | 242 | key->npc_proto = npc->npc_proto; | |
248 | key->npc_dir = npc->npc_dir; | 243 | key->npc_dir = npc->npc_dir; | |
@@ -307,27 +302,27 @@ npfa_icmp_natin(npf_cache_t *npc, nbuf_t | @@ -307,27 +302,27 @@ npfa_icmp_natin(npf_cache_t *npc, nbuf_t | |||
307 | offsetof(struct icmp, icmp_cksum); | 302 | offsetof(struct icmp, icmp_cksum); | |
308 | if ((n_ptr = nbuf_advance(&nbuf, n_ptr, offby)) == NULL) { | 303 | if ((n_ptr = nbuf_advance(&nbuf, n_ptr, offby)) == NULL) { | |
309 | return false; | 304 | return false; | |
310 | } | 305 | } | |
311 | 306 | |||
312 | /* | 307 | /* | |
313 | * Rewrite source IP address and port of the embedded IP header, | 308 | * Rewrite source IP address and port of the embedded IP header, | |
314 | * which represents original packet - therefore passing PFIL_OUT. | 309 | * which represents original packet - therefore passing PFIL_OUT. | |
315 | */ | 310 | */ | |
316 | npf_nat_t *nt = ntptr; | 311 | npf_nat_t *nt = ntptr; | |
317 | in_addr_t addr; | 312 | in_addr_t addr; | |
318 | in_port_t port; | 313 | in_port_t port; | |
319 | 314 | |||
320 | npf_nat_getlocal(nt, &addr, &port); | 315 | npf_nat_getorig(nt, &addr, &port); | |
321 | 316 | |||
322 | if (!npf_rwrip(&enpc, nbuf, n_ptr, PFIL_OUT, addr)) { | 317 | if (!npf_rwrip(&enpc, nbuf, n_ptr, PFIL_OUT, addr)) { | |
323 | return false; | 318 | return false; | |
324 | } | 319 | } | |
325 | if (!npf_rwrport(&enpc, nbuf, n_ptr, PFIL_OUT, port, addr)) { | 320 | if (!npf_rwrport(&enpc, nbuf, n_ptr, PFIL_OUT, port, addr)) { | |
326 | return false; | 321 | return false; | |
327 | } | 322 | } | |
328 | 323 | |||
329 | /* | 324 | /* | |
330 | * Fixup and update ICMP checksum. | 325 | * Fixup and update ICMP checksum. | |
331 | * Note: npf_rwrip() has updated the IP checksum. | 326 | * Note: npf_rwrip() has updated the IP checksum. | |
332 | */ | 327 | */ | |
333 | cksum = npf_fixup32_cksum(cksum, enpc.npc_srcip, addr); | 328 | cksum = npf_fixup32_cksum(cksum, enpc.npc_srcip, addr); |
--- src/sys/net/npf/npf_ctl.c 2010/08/22 18:56:22 1.1
+++ src/sys/net/npf/npf_ctl.c 2010/09/16 04:53:27 1.2
@@ -1,14 +1,14 @@ | @@ -1,14 +1,14 @@ | |||
1 | /* $NetBSD: npf_ctl.c,v 1.1 2010/08/22 18:56:22 rmind Exp $ */ | 1 | /* $NetBSD: npf_ctl.c,v 1.2 2010/09/16 04:53:27 rmind Exp $ */ | |
2 | 2 | |||
3 | /*- | 3 | /*- | |
4 | * Copyright (c) 2009-2010 The NetBSD Foundation, Inc. | 4 | * Copyright (c) 2009-2010 The NetBSD Foundation, Inc. | |
5 | * All rights reserved. | 5 | * All rights reserved. | |
6 | * | 6 | * | |
7 | * This material is based upon work partially supported by The | 7 | * This material is based upon work partially supported by The | |
8 | * NetBSD Foundation under a contract with Mindaugas Rasiukevicius. | 8 | * NetBSD Foundation under a contract with Mindaugas Rasiukevicius. | |
9 | * | 9 | * | |
10 | * Redistribution and use in source and binary forms, with or without | 10 | * Redistribution and use in source and binary forms, with or without | |
11 | * modification, are permitted provided that the following conditions | 11 | * modification, are permitted provided that the following conditions | |
12 | * are met: | 12 | * are met: | |
13 | * 1. Redistributions of source code must retain the above copyright | 13 | * 1. Redistributions of source code must retain the above copyright | |
14 | * notice, this list of conditions and the following disclaimer. | 14 | * notice, this list of conditions and the following disclaimer. | |
@@ -31,27 +31,27 @@ | @@ -31,27 +31,27 @@ | |||
31 | 31 | |||
32 | /* | 32 | /* | |
33 | * NPF device control. | 33 | * NPF device control. | |
34 | * | 34 | * | |
35 | * Implementation of (re)loading, construction of tables and rules. | 35 | * Implementation of (re)loading, construction of tables and rules. | |
36 | * NPF proplib(9) dictionary consumer. | 36 | * NPF proplib(9) dictionary consumer. | |
37 | * | 37 | * | |
38 | * TODO: | 38 | * TODO: | |
39 | * - Consider implementing 'sync' functionality. | 39 | * - Consider implementing 'sync' functionality. | |
40 | */ | 40 | */ | |
41 | 41 | |||
42 | #ifdef _KERNEL | 42 | #ifdef _KERNEL | |
43 | #include <sys/cdefs.h> | 43 | #include <sys/cdefs.h> | |
44 | __KERNEL_RCSID(0, "$NetBSD: npf_ctl.c,v 1.1 2010/08/22 18:56:22 rmind Exp $"); | 44 | __KERNEL_RCSID(0, "$NetBSD: npf_ctl.c,v 1.2 2010/09/16 04:53:27 rmind Exp $"); | |
45 | 45 | |||
46 | #include <sys/param.h> | 46 | #include <sys/param.h> | |
47 | #include <sys/conf.h> | 47 | #include <sys/conf.h> | |
48 | #include <sys/kernel.h> | 48 | #include <sys/kernel.h> | |
49 | #endif | 49 | #endif | |
50 | 50 | |||
51 | #include <prop/proplib.h> | 51 | #include <prop/proplib.h> | |
52 | 52 | |||
53 | #include "npf_ncode.h" | 53 | #include "npf_ncode.h" | |
54 | #include "npf_impl.h" | 54 | #include "npf_impl.h" | |
55 | 55 | |||
56 | /* | 56 | /* | |
57 | * npfctl_switch: enable or disable packet inspection. | 57 | * npfctl_switch: enable or disable packet inspection. | |
@@ -318,48 +318,62 @@ npf_mk_natlist(npf_ruleset_t *nset, prop | @@ -318,48 +318,62 @@ npf_mk_natlist(npf_ruleset_t *nset, prop | |||
318 | /* NAT policies - array. */ | 318 | /* NAT policies - array. */ | |
319 | if (prop_object_type(natlist) != PROP_TYPE_ARRAY) | 319 | if (prop_object_type(natlist) != PROP_TYPE_ARRAY) | |
320 | return EINVAL; | 320 | return EINVAL; | |
321 | 321 | |||
322 | it = prop_array_iterator(natlist); | 322 | it = prop_array_iterator(natlist); | |
323 | if (it == NULL) | 323 | if (it == NULL) | |
324 | return ENOMEM; | 324 | return ENOMEM; | |
325 | 325 | |||
326 | error = 0; | 326 | error = 0; | |
327 | while ((natdict = prop_object_iterator_next(it)) != NULL) { | 327 | while ((natdict = prop_object_iterator_next(it)) != NULL) { | |
328 | prop_object_t obj; | 328 | prop_object_t obj; | |
329 | npf_natpolicy_t *np; | 329 | npf_natpolicy_t *np; | |
330 | npf_rule_t *rl; | 330 | npf_rule_t *rl; | |
331 | in_addr_t gip; | 331 | in_addr_t taddr; | |
332 | in_port_t tport; | |||
333 | int type, flags; | |||
332 | 334 | |||
333 | /* NAT policy - dictionary. */ | 335 | /* NAT policy - dictionary. */ | |
334 | if (prop_object_type(natdict) != PROP_TYPE_DICTIONARY) { | 336 | if (prop_object_type(natdict) != PROP_TYPE_DICTIONARY) { | |
335 | error = EINVAL; | 337 | error = EINVAL; | |
336 | break; | 338 | break; | |
337 | } | 339 | } | |
338 | 340 | |||
339 | /* Gateway IP. */ | 341 | /* Translation type. */ | |
340 | obj = prop_dictionary_get(natdict, "gateway_ip"); | 342 | obj = prop_dictionary_get(natdict, "type"); | |
341 | gip = (in_addr_t)prop_number_integer_value(obj); | 343 | type = prop_number_integer_value(obj); | |
344 | ||||
345 | /* Translation type. */ | |||
346 | obj = prop_dictionary_get(natdict, "flags"); | |||
347 | flags = prop_number_integer_value(obj); | |||
348 | ||||
349 | /* Translation IP. */ | |||
350 | obj = prop_dictionary_get(natdict, "translation_ip"); | |||
351 | taddr = (in_addr_t)prop_number_integer_value(obj); | |||
352 | ||||
353 | /* Translation port (for redirect case). */ | |||
354 | obj = prop_dictionary_get(natdict, "translation_port"); | |||
355 | tport = (in_addr_t)prop_number_integer_value(obj); | |||
342 | 356 | |||
343 | /* | 357 | /* | |
344 | * NAT policies are standard rules, plus additional | 358 | * NAT policies are standard rules, plus additional | |
345 | * information for translation. Make a rule. | 359 | * information for translation. Make a rule. | |
346 | */ | 360 | */ | |
347 | error = npf_mk_singlerule(natdict, nset, &rl); | 361 | error = npf_mk_singlerule(natdict, nset, &rl); | |
348 | if (error) | 362 | if (error) | |
349 | break; | 363 | break; | |
350 | 364 | |||
351 | /* Allocate a new NAT policy and assign to the rule. */ | 365 | /* Allocate a new NAT policy and assign to the rule. */ | |
352 | np = npf_nat_newpolicy(gip); | 366 | np = npf_nat_newpolicy(type, flags, taddr, tport); | |
353 | if (np == NULL) { | 367 | if (np == NULL) { | |
354 | error = ENOMEM; | 368 | error = ENOMEM; | |
355 | break; | 369 | break; | |
356 | } | 370 | } | |
357 | npf_rule_setnat(rl, np); | 371 | npf_rule_setnat(rl, np); | |
358 | } | 372 | } | |
359 | prop_object_iterator_release(it); | 373 | prop_object_iterator_release(it); | |
360 | /* | 374 | /* | |
361 | * Note: in a case of error, caller will free entire NAT ruleset | 375 | * Note: in a case of error, caller will free entire NAT ruleset | |
362 | * with assigned NAT policies. | 376 | * with assigned NAT policies. | |
363 | */ | 377 | */ | |
364 | return error; | 378 | return error; | |
365 | } | 379 | } | |
@@ -392,27 +406,27 @@ npfctl_reload(u_long cmd, void *data) | @@ -392,27 +406,27 @@ npfctl_reload(u_long cmd, void *data) | |||
392 | #endif | 406 | #endif | |
393 | /* Version. */ | 407 | /* Version. */ | |
394 | ver = prop_dictionary_get(dict, "version"); | 408 | ver = prop_dictionary_get(dict, "version"); | |
395 | if (ver == NULL || prop_number_integer_value(ver) != NPF_VERSION) { | 409 | if (ver == NULL || prop_number_integer_value(ver) != NPF_VERSION) { | |
396 | error = EINVAL; | 410 | error = EINVAL; | |
397 | goto fail; | 411 | goto fail; | |
398 | } | 412 | } | |
399 | 413 | |||
400 | /* XXX: Hard way for now. */ | 414 | /* XXX: Hard way for now. */ | |
401 | (void)npf_session_tracking(false); | 415 | (void)npf_session_tracking(false); | |
402 | 416 | |||
403 | /* NAT policies. */ | 417 | /* NAT policies. */ | |
404 | nset = npf_ruleset_create(); | 418 | nset = npf_ruleset_create(); | |
405 | natlist = prop_dictionary_get(dict, "nat"); | 419 | natlist = prop_dictionary_get(dict, "translation"); | |
406 | error = npf_mk_natlist(nset, natlist); | 420 | error = npf_mk_natlist(nset, natlist); | |
407 | if (error) | 421 | if (error) | |
408 | goto fail; | 422 | goto fail; | |
409 | 423 | |||
410 | /* Tables. */ | 424 | /* Tables. */ | |
411 | tblset = npf_tableset_create(); | 425 | tblset = npf_tableset_create(); | |
412 | tables = prop_dictionary_get(dict, "tables"); | 426 | tables = prop_dictionary_get(dict, "tables"); | |
413 | error = npf_mk_tables(tblset, tables); | 427 | error = npf_mk_tables(tblset, tables); | |
414 | if (error) | 428 | if (error) | |
415 | goto fail; | 429 | goto fail; | |
416 | 430 | |||
417 | /* Rules. */ | 431 | /* Rules. */ | |
418 | rlset = npf_ruleset_create(); | 432 | rlset = npf_ruleset_create(); | |
@@ -445,27 +459,27 @@ fail: | @@ -445,27 +459,27 @@ fail: | |||
445 | if (nset) { | 459 | if (nset) { | |
446 | npf_ruleset_destroy(nset); | 460 | npf_ruleset_destroy(nset); | |
447 | } | 461 | } | |
448 | if (rlset) { | 462 | if (rlset) { | |
449 | npf_ruleset_destroy(rlset); | 463 | npf_ruleset_destroy(rlset); | |
450 | } | 464 | } | |
451 | if (tblset) { | 465 | if (tblset) { | |
452 | npf_tableset_destroy(tblset); | 466 | npf_tableset_destroy(tblset); | |
453 | } | 467 | } | |
454 | return error; | 468 | return error; | |
455 | } | 469 | } | |
456 | 470 | |||
457 | /* | 471 | /* | |
458 | * npf_table_ctl: add, remove or query entries in the specified table. | 472 | * npfctl_table: add, remove or query entries in the specified table. | |
459 | * | 473 | * | |
460 | * For maximum performance, interface is avoiding proplib(3)'s overhead. | 474 | * For maximum performance, interface is avoiding proplib(3)'s overhead. | |
461 | */ | 475 | */ | |
462 | int | 476 | int | |
463 | npfctl_table(void *data) | 477 | npfctl_table(void *data) | |
464 | { | 478 | { | |
465 | npf_ioctl_table_t *nct = data; | 479 | npf_ioctl_table_t *nct = data; | |
466 | int error; | 480 | int error; | |
467 | 481 | |||
468 | switch (nct->nct_action) { | 482 | switch (nct->nct_action) { | |
469 | case NPF_IOCTL_TBLENT_ADD: | 483 | case NPF_IOCTL_TBLENT_ADD: | |
470 | error = npf_table_add_v4cidr(NULL, nct->nct_tid, | 484 | error = npf_table_add_v4cidr(NULL, nct->nct_tid, | |
471 | nct->nct_addr, nct->nct_mask); | 485 | nct->nct_addr, nct->nct_mask); |
--- src/sys/net/npf/npf_handler.c 2010/08/22 18:56:22 1.1
+++ src/sys/net/npf/npf_handler.c 2010/09/16 04:53:27 1.2
@@ -1,14 +1,14 @@ | @@ -1,14 +1,14 @@ | |||
1 | /* $NetBSD: npf_handler.c,v 1.1 2010/08/22 18:56:22 rmind Exp $ */ | 1 | /* $NetBSD: npf_handler.c,v 1.2 2010/09/16 04:53:27 rmind Exp $ */ | |
2 | 2 | |||
3 | /*- | 3 | /*- | |
4 | * Copyright (c) 2009-2010 The NetBSD Foundation, Inc. | 4 | * Copyright (c) 2009-2010 The NetBSD Foundation, Inc. | |
5 | * All rights reserved. | 5 | * All rights reserved. | |
6 | * | 6 | * | |
7 | * This material is based upon work partially supported by The | 7 | * This material is based upon work partially supported by The | |
8 | * NetBSD Foundation under a contract with Mindaugas Rasiukevicius. | 8 | * NetBSD Foundation under a contract with Mindaugas Rasiukevicius. | |
9 | * | 9 | * | |
10 | * Redistribution and use in source and binary forms, with or without | 10 | * Redistribution and use in source and binary forms, with or without | |
11 | * modification, are permitted provided that the following conditions | 11 | * modification, are permitted provided that the following conditions | |
12 | * are met: | 12 | * are met: | |
13 | * 1. Redistributions of source code must retain the above copyright | 13 | * 1. Redistributions of source code must retain the above copyright | |
14 | * notice, this list of conditions and the following disclaimer. | 14 | * notice, this list of conditions and the following disclaimer. | |
@@ -25,124 +25,141 @@ | @@ -25,124 +25,141 @@ | |||
25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | 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 | 26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | |
27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | 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 | 28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |
29 | * POSSIBILITY OF SUCH DAMAGE. | 29 | * POSSIBILITY OF SUCH DAMAGE. | |
30 | */ | 30 | */ | |
31 | 31 | |||
32 | /* | 32 | /* | |
33 | * NPF packet handler. | 33 | * NPF packet handler. | |
34 | */ | 34 | */ | |
35 | 35 | |||
36 | #ifdef _KERNEL | 36 | #ifdef _KERNEL | |
37 | #include <sys/cdefs.h> | 37 | #include <sys/cdefs.h> | |
38 | __KERNEL_RCSID(0, "$NetBSD: npf_handler.c,v 1.1 2010/08/22 18:56:22 rmind Exp $"); | 38 | __KERNEL_RCSID(0, "$NetBSD: npf_handler.c,v 1.2 2010/09/16 04:53:27 rmind Exp $"); | |
39 | 39 | |||
40 | #include <sys/param.h> | 40 | #include <sys/param.h> | |
41 | #include <sys/systm.h> | 41 | #include <sys/systm.h> | |
42 | #endif | 42 | #endif | |
43 | 43 | |||
44 | #include <sys/mbuf.h> | 44 | #include <sys/mbuf.h> | |
45 | #include <sys/mutex.h> | 45 | #include <sys/mutex.h> | |
46 | #include <net/if.h> | 46 | #include <net/if.h> | |
47 | #include <net/pfil.h> | 47 | #include <net/pfil.h> | |
48 | #include <sys/socketvar.h> | 48 | #include <sys/socketvar.h> | |
49 | 49 | |||
50 | #include "npf_impl.h" | 50 | #include "npf_impl.h" | |
51 | 51 | |||
52 | /* | 52 | /* | |
53 | * If npf_ph_if != NULL, pfil hooks are registers. If NULL, not registered. | 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). | 54 | * Used to check the state. Locked by: softnet_lock + KERNEL_LOCK (XXX). | |
55 | */ | 55 | */ | |
56 | static struct pfil_head * npf_ph_if = NULL; | 56 | static struct pfil_head * npf_ph_if = NULL; | |
57 | static struct pfil_head * npf_ph_inet = NULL; | 57 | static struct pfil_head * npf_ph_inet = NULL; | |
58 | 58 | |||
59 | static bool default_pass = true; | |||
60 | ||||
59 | int npf_packet_handler(void *, struct mbuf **, struct ifnet *, int); | 61 | int npf_packet_handler(void *, struct mbuf **, struct ifnet *, int); | |
60 | 62 | |||
61 | /* | 63 | /* | |
62 | * npf_ifhook: hook handling interface changes. | 64 | * npf_ifhook: hook handling interface changes. | |
63 | */ | 65 | */ | |
64 | static int | 66 | static int | |
65 | npf_ifhook(void *arg, struct mbuf **mp, struct ifnet *ifp, int di) | 67 | npf_ifhook(void *arg, struct mbuf **mp, struct ifnet *ifp, int di) | |
66 | { | 68 | { | |
67 | 69 | |||
68 | return 0; | 70 | return 0; | |
69 | } | 71 | } | |
70 | 72 | |||
71 | /* | 73 | /* | |
72 | * npf_packet_handler: main packet handling routine. | 74 | * npf_packet_handler: main packet handling routine for layer 3. | |
73 | * | 75 | * | |
74 | * Note: packet flow and inspection logic is in strict order. | 76 | * Note: packet flow and inspection logic is in strict order. | |
75 | */ | 77 | */ | |
76 | int | 78 | int | |
77 | npf_packet_handler(void *arg, struct mbuf **mp, struct ifnet *ifp, int di) | 79 | npf_packet_handler(void *arg, struct mbuf **mp, struct ifnet *ifp, int di) | |
78 | { | 80 | { | |
79 | const int layer = (const int)(long)arg; | |||
80 | nbuf_t *nbuf = *mp; | 81 | nbuf_t *nbuf = *mp; | |
81 | npf_cache_t npc; | 82 | npf_cache_t npc; | |
82 | npf_session_t *se; | 83 | npf_session_t *se; | |
83 | npf_rule_t *rl; | 84 | npf_rule_t *rl; | |
84 | int error; | 85 | bool keepstate; | |
86 | int retfl, error; | |||
85 | 87 | |||
86 | /* | 88 | /* | |
87 | * Initialise packet information cache. | 89 | * Initialise packet information cache. | |
88 | * Note: it is enough to clear the info bits. | 90 | * Note: it is enough to clear the info bits. | |
89 | */ | 91 | */ | |
90 | npc.npc_info = 0; | 92 | npc.npc_info = 0; | |
93 | error = 0; | |||
94 | retfl = 0; | |||
91 | 95 | |||
92 | /* Inspect the list of sessions. */ | 96 | /* Inspect the list of sessions. */ | |
93 | se = npf_session_inspect(&npc, nbuf, ifp, di, layer); | 97 | se = npf_session_inspect(&npc, nbuf, ifp, di); | |
94 | 98 | |||
95 | /* Inbound NAT. */ | 99 | /* If "passing" session found - skip the ruleset inspection. */ | |
96 | if ((di & PFIL_IN) && (error = npf_natin(&npc, se, nbuf, layer)) != 0) { | 100 | if (se && npf_session_pass(se)) { | |
97 | goto out; | 101 | goto pass; | |
98 | } | 102 | } | |
99 | 103 | |||
100 | /* If session found - we pass this packet. */ | 104 | /* Inspect the ruleset using this packet. */ | |
101 | if (se && npf_session_pass(se)) { | 105 | rl = npf_ruleset_inspect(&npc, nbuf, ifp, di, NPF_LAYER_3); | |
102 | error = 0; | 106 | if (rl == NULL) { | |
103 | } else { | 107 | if (default_pass) { | |
104 | /* Inspect ruleset using this packet. */ | 108 | goto pass; | |
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 | } | 109 | } | |
118 | /* No rules or "default" rule - pass. */ | 110 | error = ENETUNREACH; | |
111 | goto out; | |||
119 | } | 112 | } | |
120 | 113 | |||
121 | /* Outbound NAT. */ | 114 | /* Apply the rule. */ | |
122 | if (di & PFIL_OUT) { | 115 | error = npf_rule_apply(&npc, rl, &keepstate, &retfl); | |
123 | error = npf_natout(&npc, se, nbuf, ifp, layer); | 116 | if (error) { | |
117 | goto out; | |||
124 | } | 118 | } | |
119 | ||||
120 | /* Establish a "pass" session, if required. */ | |||
121 | if (keepstate && !se) { | |||
122 | se = npf_session_establish(&npc, NULL, di); | |||
123 | if (se == NULL) { | |||
124 | error = ENOMEM; | |||
125 | goto out; | |||
126 | } | |||
127 | npf_session_setpass(se); | |||
128 | } | |||
129 | pass: | |||
130 | KASSERT(error == 0); | |||
131 | /* | |||
132 | * Perform NAT. | |||
133 | */ | |||
134 | error = npf_do_nat(&npc, se, nbuf, ifp, di); | |||
125 | out: | 135 | out: | |
126 | /* Release reference on session. */ | 136 | /* Release reference on session. */ | |
127 | if (se != NULL) { | 137 | if (se != NULL) { | |
128 | npf_session_release(se); | 138 | npf_session_release(se); | |
129 | } | 139 | } | |
130 | 140 | |||
131 | /* | 141 | /* | |
132 | * If error is set - drop the packet. | 142 | * If error is set - drop the packet. | |
133 | * Normally, ENETUNREACH is used to "block". | 143 | * Normally, ENETUNREACH is used for "block". | |
134 | */ | 144 | */ | |
135 | if (error) { | 145 | if (error) { | |
146 | /* | |||
147 | * Depending on flags and protocol, return TCP reset (RST) | |||
148 | * or ICMP destination unreachable | |||
149 | */ | |||
150 | if (retfl) { | |||
151 | npf_return_block(&npc, nbuf, retfl); | |||
152 | } | |||
136 | m_freem(*mp); | 153 | m_freem(*mp); | |
137 | *mp = NULL; | 154 | *mp = NULL; | |
138 | } | 155 | } | |
139 | return error; | 156 | return error; | |
140 | } | 157 | } | |
141 | 158 | |||
142 | /* | 159 | /* | |
143 | * npf_register_pfil: register pfil(9) hooks. | 160 | * npf_register_pfil: register pfil(9) hooks. | |
144 | */ | 161 | */ | |
145 | int | 162 | int | |
146 | npf_register_pfil(void) | 163 | npf_register_pfil(void) | |
147 | { | 164 | { | |
148 | int error; | 165 | int error; | |
@@ -161,46 +178,46 @@ npf_register_pfil(void) | @@ -161,46 +178,46 @@ npf_register_pfil(void) | |||
161 | npf_ph_inet = pfil_head_get(PFIL_TYPE_AF, AF_INET); | 178 | npf_ph_inet = pfil_head_get(PFIL_TYPE_AF, AF_INET); | |
162 | if (npf_ph_if == NULL || npf_ph_inet == NULL) { | 179 | if (npf_ph_if == NULL || npf_ph_inet == NULL) { | |
163 | npf_ph_if = NULL; | 180 | npf_ph_if = NULL; | |
164 | error = ENOENT; | 181 | error = ENOENT; | |
165 | goto fail; | 182 | goto fail; | |
166 | } | 183 | } | |
167 | 184 | |||
168 | /* Interface re-config or attach/detach hook. */ | 185 | /* Interface re-config or attach/detach hook. */ | |
169 | error = pfil_add_hook(npf_ifhook, NULL, | 186 | error = pfil_add_hook(npf_ifhook, NULL, | |
170 | PFIL_WAITOK | PFIL_IFADDR | PFIL_IFNET, npf_ph_if); | 187 | PFIL_WAITOK | PFIL_IFADDR | PFIL_IFNET, npf_ph_if); | |
171 | KASSERT(error == 0); | 188 | KASSERT(error == 0); | |
172 | 189 | |||
173 | /* Packet IN/OUT handler on all interfaces and IP layer. */ | 190 | /* Packet IN/OUT handler on all interfaces and IP layer. */ | |
174 | error = pfil_add_hook(npf_packet_handler, (void *)NPF_LAYER_3, | 191 | error = pfil_add_hook(npf_packet_handler, NULL, | |
175 | PFIL_WAITOK | PFIL_ALL, npf_ph_inet); | 192 | PFIL_WAITOK | PFIL_ALL, npf_ph_inet); | |
176 | KASSERT(error == 0); | 193 | KASSERT(error == 0); | |
177 | 194 | |||
178 | fail: | 195 | fail: | |
179 | KERNEL_UNLOCK_ONE(NULL); | 196 | KERNEL_UNLOCK_ONE(NULL); | |
180 | mutex_exit(softnet_lock); | 197 | mutex_exit(softnet_lock); | |
181 | 198 | |||
182 | return error; | 199 | return error; | |
183 | } | 200 | } | |
184 | 201 | |||
185 | /* | 202 | /* | |
186 | * npf_unregister: unregister pfil(9) hooks. | 203 | * npf_unregister: unregister pfil(9) hooks. | |
187 | */ | 204 | */ | |
188 | void | 205 | void | |
189 | npf_unregister_pfil(void) | 206 | npf_unregister_pfil(void) | |
190 | { | 207 | { | |
191 | 208 | |||
192 | mutex_enter(softnet_lock); | 209 | mutex_enter(softnet_lock); | |
193 | KERNEL_LOCK(1, NULL); | 210 | KERNEL_LOCK(1, NULL); | |
194 | 211 | |||
195 | if (npf_ph_if) { | 212 | if (npf_ph_if) { | |
196 | (void)pfil_remove_hook(npf_packet_handler, (void *)NPF_LAYER_3, | 213 | (void)pfil_remove_hook(npf_packet_handler, NULL, | |
197 | PFIL_ALL, npf_ph_inet); | 214 | PFIL_ALL, npf_ph_inet); | |
198 | (void)pfil_remove_hook(npf_ifhook, NULL, | 215 | (void)pfil_remove_hook(npf_ifhook, NULL, | |
199 | PFIL_IFADDR | PFIL_IFNET, npf_ph_if); | 216 | PFIL_IFADDR | PFIL_IFNET, npf_ph_if); | |
200 | 217 | |||
201 | npf_ph_if = NULL; | 218 | npf_ph_if = NULL; | |
202 | } | 219 | } | |
203 | 220 | |||
204 | KERNEL_UNLOCK_ONE(NULL); | 221 | KERNEL_UNLOCK_ONE(NULL); | |
205 | mutex_exit(softnet_lock); | 222 | mutex_exit(softnet_lock); | |
206 | } | 223 | } |
--- src/sys/net/npf/npf_impl.h 2010/08/22 18:56:22 1.1
+++ src/sys/net/npf/npf_impl.h 2010/09/16 04:53:27 1.2
@@ -1,14 +1,14 @@ | @@ -1,14 +1,14 @@ | |||
1 | /* $NetBSD: npf_impl.h,v 1.1 2010/08/22 18:56:22 rmind Exp $ */ | 1 | /* $NetBSD: npf_impl.h,v 1.2 2010/09/16 04:53:27 rmind Exp $ */ | |
2 | 2 | |||
3 | /*- | 3 | /*- | |
4 | * Copyright (c) 2009-2010 The NetBSD Foundation, Inc. | 4 | * Copyright (c) 2009-2010 The NetBSD Foundation, Inc. | |
5 | * All rights reserved. | 5 | * All rights reserved. | |
6 | * | 6 | * | |
7 | * This material is based upon work partially supported by The | 7 | * This material is based upon work partially supported by The | |
8 | * NetBSD Foundation under a contract with Mindaugas Rasiukevicius. | 8 | * NetBSD Foundation under a contract with Mindaugas Rasiukevicius. | |
9 | * | 9 | * | |
10 | * Redistribution and use in source and binary forms, with or without | 10 | * Redistribution and use in source and binary forms, with or without | |
11 | * modification, are permitted provided that the following conditions | 11 | * modification, are permitted provided that the following conditions | |
12 | * are met: | 12 | * are met: | |
13 | * 1. Redistributions of source code must retain the above copyright | 13 | * 1. Redistributions of source code must retain the above copyright | |
14 | * notice, this list of conditions and the following disclaimer. | 14 | * notice, this list of conditions and the following disclaimer. | |
@@ -88,48 +88,51 @@ typedef bool (*npf_algfunc_t)(npf_cache_ | @@ -88,48 +88,51 @@ typedef bool (*npf_algfunc_t)(npf_cache_ | |||
88 | /* NPF control. */ | 88 | /* NPF control. */ | |
89 | int npfctl_switch(void *); | 89 | int npfctl_switch(void *); | |
90 | int npfctl_reload(u_long, void *); | 90 | int npfctl_reload(u_long, void *); | |
91 | int npfctl_table(void *); | 91 | int npfctl_table(void *); | |
92 | 92 | |||
93 | /* Packet filter hooks. */ | 93 | /* Packet filter hooks. */ | |
94 | int npf_register_pfil(void); | 94 | int npf_register_pfil(void); | |
95 | void npf_unregister_pfil(void); | 95 | void npf_unregister_pfil(void); | |
96 | 96 | |||
97 | /* Protocol helpers. */ | 97 | /* Protocol helpers. */ | |
98 | bool npf_ip4_proto(npf_cache_t *, nbuf_t *, void *); | 98 | bool npf_ip4_proto(npf_cache_t *, nbuf_t *, void *); | |
99 | bool npf_fetch_ip4addrs(npf_cache_t *, nbuf_t *, void *); | 99 | bool npf_fetch_ip4addrs(npf_cache_t *, nbuf_t *, void *); | |
100 | bool npf_fetch_ports(npf_cache_t *, nbuf_t *, void *, const int); | 100 | bool npf_fetch_ports(npf_cache_t *, nbuf_t *, void *, const int); | |
101 | bool npf_fetch_tcpfl(npf_cache_t *, nbuf_t *, void *); | |||
101 | bool npf_fetch_icmp(npf_cache_t *, nbuf_t *, void *); | 102 | bool npf_fetch_icmp(npf_cache_t *, nbuf_t *, void *); | |
102 | bool npf_cache_all_ip4(npf_cache_t *, nbuf_t *, const int); | 103 | bool npf_cache_all(npf_cache_t *, nbuf_t *); | |
103 | 104 | |||
104 | bool npf_rwrport(npf_cache_t *, nbuf_t *, void *, const int, | 105 | bool npf_rwrport(npf_cache_t *, nbuf_t *, void *, const int, | |
105 | in_port_t, in_addr_t); | 106 | in_port_t, in_addr_t); | |
106 | bool npf_rwrip(npf_cache_t *, nbuf_t *, void *, const int, in_addr_t); | 107 | bool npf_rwrip(npf_cache_t *, nbuf_t *, void *, const int, in_addr_t); | |
107 | 108 | |||
108 | uint16_t npf_fixup16_cksum(uint16_t, uint16_t, uint16_t); | 109 | uint16_t npf_fixup16_cksum(uint16_t, uint16_t, uint16_t); | |
109 | uint16_t npf_fixup32_cksum(uint16_t, uint32_t, uint32_t); | 110 | uint16_t npf_fixup32_cksum(uint16_t, uint32_t, uint32_t); | |
110 | 111 | |||
112 | void npf_return_block(npf_cache_t *, nbuf_t *, const int); | |||
113 | ||||
111 | /* Complex instructions. */ | 114 | /* Complex instructions. */ | |
112 | int npf_match_ether(nbuf_t *, int, int, uint16_t, uint32_t *); | 115 | int npf_match_ether(nbuf_t *, int, int, uint16_t, uint32_t *); | |
113 | int npf_match_ip4table(npf_cache_t *, nbuf_t *, void *, | 116 | int npf_match_ip4table(npf_cache_t *, nbuf_t *, void *, | |
114 | const int, const u_int); | 117 | const int, const u_int); | |
115 | int npf_match_ip4mask(npf_cache_t *, nbuf_t *, void *, | 118 | int npf_match_ip4mask(npf_cache_t *, nbuf_t *, void *, | |
116 | const int, in_addr_t, in_addr_t); | 119 | const int, in_addr_t, in_addr_t); | |
117 | int npf_match_tcp_ports(npf_cache_t *, nbuf_t *, void *, | 120 | int npf_match_tcp_ports(npf_cache_t *, nbuf_t *, void *, | |
118 | const int, const uint32_t); | 121 | const int, const uint32_t); | |
119 | int npf_match_udp_ports(npf_cache_t *, nbuf_t *, void *, | 122 | int npf_match_udp_ports(npf_cache_t *, nbuf_t *, void *, | |
120 | const int, const uint32_t); | 123 | const int, const uint32_t); | |
121 | int npf_match_icmp4(npf_cache_t *, nbuf_t *, void *, | 124 | int npf_match_icmp4(npf_cache_t *, nbuf_t *, void *, const uint32_t); | |
122 | const int, const int); | 125 | int npf_match_tcpfl(npf_cache_t *, nbuf_t *, void *, const uint32_t); | |
123 | 126 | |||
124 | /* Tableset interface. */ | 127 | /* Tableset interface. */ | |
125 | int npf_tableset_sysinit(void); | 128 | int npf_tableset_sysinit(void); | |
126 | void npf_tableset_sysfini(void); | 129 | void npf_tableset_sysfini(void); | |
127 | 130 | |||
128 | npf_tableset_t *npf_tableset_create(void); | 131 | npf_tableset_t *npf_tableset_create(void); | |
129 | void npf_tableset_destroy(npf_tableset_t *); | 132 | void npf_tableset_destroy(npf_tableset_t *); | |
130 | int npf_tableset_insert(npf_tableset_t *, npf_table_t *); | 133 | int npf_tableset_insert(npf_tableset_t *, npf_table_t *); | |
131 | npf_tableset_t *npf_tableset_reload(npf_tableset_t *); | 134 | npf_tableset_t *npf_tableset_reload(npf_tableset_t *); | |
132 | 135 | |||
133 | npf_table_t * npf_table_create(u_int, int, size_t); | 136 | npf_table_t * npf_table_create(u_int, int, size_t); | |
134 | void npf_table_destroy(npf_table_t *); | 137 | void npf_table_destroy(npf_table_t *); | |
135 | void npf_table_ref(npf_table_t *); | 138 | void npf_table_ref(npf_table_t *); | |
@@ -147,63 +150,59 @@ int npf_table_match_v4addr(u_int, in_ad | @@ -147,63 +150,59 @@ int npf_table_match_v4addr(u_int, in_ad | |||
147 | /* Ruleset interface. */ | 150 | /* Ruleset interface. */ | |
148 | int npf_ruleset_sysinit(void); | 151 | int npf_ruleset_sysinit(void); | |
149 | void npf_ruleset_sysfini(void); | 152 | void npf_ruleset_sysfini(void); | |
150 | 153 | |||
151 | npf_ruleset_t * npf_ruleset_create(void); | 154 | npf_ruleset_t * npf_ruleset_create(void); | |
152 | void npf_ruleset_destroy(npf_ruleset_t *); | 155 | void npf_ruleset_destroy(npf_ruleset_t *); | |
153 | void npf_ruleset_insert(npf_ruleset_t *, npf_rule_t *); | 156 | void npf_ruleset_insert(npf_ruleset_t *, npf_rule_t *); | |
154 | void npf_ruleset_reload(npf_ruleset_t *, npf_tableset_t *); | 157 | void npf_ruleset_reload(npf_ruleset_t *, npf_tableset_t *); | |
155 | 158 | |||
156 | npf_rule_t * npf_ruleset_match(npf_ruleset_t *, npf_cache_t *, nbuf_t *, | 159 | npf_rule_t * npf_ruleset_match(npf_ruleset_t *, npf_cache_t *, nbuf_t *, | |
157 | struct ifnet *, const int, const int); | 160 | struct ifnet *, const int, const int); | |
158 | npf_rule_t * npf_ruleset_inspect(npf_cache_t *, nbuf_t *, | 161 | npf_rule_t * npf_ruleset_inspect(npf_cache_t *, nbuf_t *, | |
159 | struct ifnet *, const int, const int); | 162 | struct ifnet *, const int, const int); | |
160 | int npf_rule_apply(const npf_cache_t *, npf_rule_t *, bool *); | 163 | int npf_rule_apply(const npf_cache_t *, npf_rule_t *, bool *, int *); | |
161 | npf_ruleset_t * npf_rule_subset(npf_rule_t *); | 164 | npf_ruleset_t * npf_rule_subset(npf_rule_t *); | |
162 | 165 | |||
163 | npf_natpolicy_t *npf_rule_getnat(const npf_rule_t *); | 166 | npf_natpolicy_t *npf_rule_getnat(const npf_rule_t *); | |
164 | void npf_rule_setnat(npf_rule_t *, npf_natpolicy_t *); | 167 | void npf_rule_setnat(npf_rule_t *, npf_natpolicy_t *); | |
165 | 168 | |||
166 | /* State handling interface. */ | 169 | /* State handling interface. */ | |
167 | int npf_session_sysinit(void); | 170 | int npf_session_sysinit(void); | |
168 | void npf_session_sysfini(void); | 171 | void npf_session_sysfini(void); | |
169 | int npf_session_tracking(bool); | 172 | int npf_session_tracking(bool); | |
170 | 173 | |||
171 | npf_session_t * npf_session_inspect(npf_cache_t *, nbuf_t *, | 174 | npf_session_t * npf_session_inspect(npf_cache_t *, nbuf_t *, | |
172 | struct ifnet *, const int, const int); | 175 | struct ifnet *, const int); | |
173 | npf_session_t * npf_session_establish(const npf_cache_t *, | 176 | npf_session_t * npf_session_establish(const npf_cache_t *, | |
174 | npf_nat_t *, const int); | 177 | npf_nat_t *, const int); | |
175 | void npf_session_release(npf_session_t *); | 178 | void npf_session_release(npf_session_t *); | |
176 | bool npf_session_pass(const npf_session_t *); | 179 | bool npf_session_pass(const npf_session_t *); | |
177 | 180 | void npf_session_setpass(npf_session_t *); | ||
178 | npf_nat_t * npf_session_retnat(const npf_session_t *); | |||
179 | ||||
180 | void npf_session_link(npf_session_t *, npf_session_t *); | 181 | void npf_session_link(npf_session_t *, npf_session_t *); | |
181 | npf_nat_t * npf_session_retlinknat(const npf_session_t *); | 182 | npf_nat_t * npf_session_retnat(npf_session_t *, const int, bool *); | |
182 | 183 | |||
183 | /* NAT. */ | 184 | /* NAT. */ | |
184 | void npf_nat_sysinit(void); | 185 | void npf_nat_sysinit(void); | |
185 | void npf_nat_sysfini(void); | 186 | void npf_nat_sysfini(void); | |
186 | npf_natpolicy_t *npf_nat_newpolicy(in_addr_t); | 187 | npf_natpolicy_t *npf_nat_newpolicy(int, int, in_addr_t, in_port_t); | |
187 | void npf_nat_freepolicy(npf_natpolicy_t *); | 188 | void npf_nat_freepolicy(npf_natpolicy_t *); | |
188 | void npf_nat_flush(void); | 189 | void npf_nat_flush(void); | |
189 | void npf_nat_reload(npf_ruleset_t *); | 190 | void npf_nat_reload(npf_ruleset_t *); | |
190 | 191 | |||
191 | int npf_natout(npf_cache_t *, npf_session_t *, nbuf_t *, | 192 | int npf_do_nat(npf_cache_t *, npf_session_t *, nbuf_t *, | |
192 | struct ifnet *, const int); | 193 | struct ifnet *, const int); | |
193 | int npf_natin(npf_cache_t *, npf_session_t *, nbuf_t *, const int); | |||
194 | ||||
195 | void npf_nat_expire(npf_nat_t *); | 194 | void npf_nat_expire(npf_nat_t *); | |
196 | void npf_nat_getlocal(npf_nat_t *, in_addr_t *, in_port_t *); | 195 | void npf_nat_getorig(npf_nat_t *, in_addr_t *, in_port_t *); | |
197 | void npf_nat_setalg(npf_nat_t *, npf_alg_t *, uintptr_t); | 196 | void npf_nat_setalg(npf_nat_t *, npf_alg_t *, uintptr_t); | |
198 | 197 | |||
199 | /* ALG interface. */ | 198 | /* ALG interface. */ | |
200 | void npf_alg_sysinit(void); | 199 | void npf_alg_sysinit(void); | |
201 | void npf_alg_sysfini(void); | 200 | void npf_alg_sysfini(void); | |
202 | npf_alg_t * npf_alg_register(npf_algfunc_t, npf_algfunc_t, | 201 | npf_alg_t * npf_alg_register(npf_algfunc_t, npf_algfunc_t, | |
203 | npf_algfunc_t, npf_algfunc_t); | 202 | npf_algfunc_t, npf_algfunc_t); | |
204 | int npf_alg_unregister(npf_alg_t *); | 203 | int npf_alg_unregister(npf_alg_t *); | |
205 | void npf_alg_match(npf_cache_t *, nbuf_t *, npf_nat_t *); | 204 | void npf_alg_match(npf_cache_t *, nbuf_t *, npf_nat_t *); | |
206 | void npf_alg_exec(npf_cache_t *, nbuf_t *, npf_nat_t *, const int ); | 205 | void npf_alg_exec(npf_cache_t *, nbuf_t *, npf_nat_t *, const int ); | |
207 | bool npf_alg_sessionid(npf_cache_t *, nbuf_t *, npf_cache_t *); | 206 | bool npf_alg_sessionid(npf_cache_t *, nbuf_t *, npf_cache_t *); | |
208 | 207 | |||
209 | /* Debugging routines. */ | 208 | /* Debugging routines. */ |
--- src/sys/net/npf/npf_inet.c 2010/08/22 18:56:22 1.1
+++ src/sys/net/npf/npf_inet.c 2010/09/16 04:53:27 1.2
@@ -1,14 +1,14 @@ | @@ -1,14 +1,14 @@ | |||
1 | /* $NetBSD: npf_inet.c,v 1.1 2010/08/22 18:56:22 rmind Exp $ */ | 1 | /* $NetBSD: npf_inet.c,v 1.2 2010/09/16 04:53:27 rmind Exp $ */ | |
2 | 2 | |||
3 | /*- | 3 | /*- | |
4 | * Copyright (c) 2009-2010 The NetBSD Foundation, Inc. | 4 | * Copyright (c) 2009-2010 The NetBSD Foundation, Inc. | |
5 | * All rights reserved. | 5 | * All rights reserved. | |
6 | * | 6 | * | |
7 | * This material is based upon work partially supported by The | 7 | * This material is based upon work partially supported by The | |
8 | * NetBSD Foundation under a contract with Mindaugas Rasiukevicius. | 8 | * NetBSD Foundation under a contract with Mindaugas Rasiukevicius. | |
9 | * | 9 | * | |
10 | * Redistribution and use in source and binary forms, with or without | 10 | * Redistribution and use in source and binary forms, with or without | |
11 | * modification, are permitted provided that the following conditions | 11 | * modification, are permitted provided that the following conditions | |
12 | * are met: | 12 | * are met: | |
13 | * 1. Redistributions of source code must retain the above copyright | 13 | * 1. Redistributions of source code must retain the above copyright | |
14 | * notice, this list of conditions and the following disclaimer. | 14 | * notice, this list of conditions and the following disclaimer. | |
@@ -25,27 +25,27 @@ | @@ -25,27 +25,27 @@ | |||
25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | 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 | 26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | |
27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | 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 | 28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |
29 | * POSSIBILITY OF SUCH DAMAGE. | 29 | * POSSIBILITY OF SUCH DAMAGE. | |
30 | */ | 30 | */ | |
31 | 31 | |||
32 | /* | 32 | /* | |
33 | * Various procotol related helper routines. | 33 | * Various procotol related helper routines. | |
34 | */ | 34 | */ | |
35 | 35 | |||
36 | #ifdef _KERNEL | 36 | #ifdef _KERNEL | |
37 | #include <sys/cdefs.h> | 37 | #include <sys/cdefs.h> | |
38 | __KERNEL_RCSID(0, "$NetBSD: npf_inet.c,v 1.1 2010/08/22 18:56:22 rmind Exp $"); | 38 | __KERNEL_RCSID(0, "$NetBSD: npf_inet.c,v 1.2 2010/09/16 04:53:27 rmind Exp $"); | |
39 | 39 | |||
40 | #include <sys/param.h> | 40 | #include <sys/param.h> | |
41 | #include <sys/kernel.h> | 41 | #include <sys/kernel.h> | |
42 | 42 | |||
43 | #include <netinet/in_systm.h> | 43 | #include <netinet/in_systm.h> | |
44 | #include <netinet/in.h> | 44 | #include <netinet/in.h> | |
45 | #include <netinet/ip.h> | 45 | #include <netinet/ip.h> | |
46 | #include <netinet/tcp.h> | 46 | #include <netinet/tcp.h> | |
47 | #include <netinet/udp.h> | 47 | #include <netinet/udp.h> | |
48 | #include <netinet/ip_icmp.h> | 48 | #include <netinet/ip_icmp.h> | |
49 | 49 | |||
50 | #include <net/if.h> | 50 | #include <net/if.h> | |
51 | #include <net/ethertypes.h> | 51 | #include <net/ethertypes.h> | |
@@ -232,59 +232,51 @@ npf_fetch_icmp(npf_cache_t *npc, nbuf_t | @@ -232,59 +232,51 @@ npf_fetch_icmp(npf_cache_t *npc, nbuf_t | |||
232 | /* ICMP code. */ | 232 | /* ICMP code. */ | |
233 | offby = offsetof(struct icmp, icmp_code); | 233 | offby = offsetof(struct icmp, icmp_code); | |
234 | if ((n_ptr = nbuf_advance(&nbuf, n_ptr, offby)) == NULL) | 234 | if ((n_ptr = nbuf_advance(&nbuf, n_ptr, offby)) == NULL) | |
235 | return false; | 235 | return false; | |
236 | if (nbuf_fetch_datum(nbuf, n_ptr, sizeof(uint8_t), &npc->npc_icmp_code)) | 236 | if (nbuf_fetch_datum(nbuf, n_ptr, sizeof(uint8_t), &npc->npc_icmp_code)) | |
237 | return false; | 237 | return false; | |
238 | 238 | |||
239 | /* Mark as cached. */ | 239 | /* Mark as cached. */ | |
240 | npc->npc_icmp_type = type; | 240 | npc->npc_icmp_type = type; | |
241 | npc->npc_info |= NPC_ICMP; | 241 | npc->npc_info |= NPC_ICMP; | |
242 | return true; | 242 | return true; | |
243 | } | 243 | } | |
244 | 244 | |||
245 | static inline bool | 245 | /* | |
246 | * npf_fetch_tcpfl: fetch TCP flags and store into the cache. | |||
247 | */ | |||
248 | bool | |||
246 | npf_fetch_tcpfl(npf_cache_t *npc, nbuf_t *nbuf, void *n_ptr) | 249 | npf_fetch_tcpfl(npf_cache_t *npc, nbuf_t *nbuf, void *n_ptr) | |
247 | { | 250 | { | |
248 | u_int offby; | 251 | u_int offby; | |
249 | 252 | |||
250 | /* Get TCP flags. */ | 253 | /* Get TCP flags. */ | |
251 | offby = npc->npc_hlen + offsetof(struct tcphdr, th_flags); | 254 | offby = npc->npc_hlen + offsetof(struct tcphdr, th_flags); | |
252 | if ((n_ptr = nbuf_advance(&nbuf, n_ptr, offby)) == NULL) | 255 | if ((n_ptr = nbuf_advance(&nbuf, n_ptr, offby)) == NULL) | |
253 | return false; | 256 | return false; | |
254 | if (nbuf_fetch_datum(nbuf, n_ptr, sizeof(uint8_t), &npc->npc_tcp_flags)) | 257 | if (nbuf_fetch_datum(nbuf, n_ptr, sizeof(uint8_t), &npc->npc_tcp_flags)) | |
255 | return false; | 258 | return false; | |
256 | return true; | 259 | return true; | |
257 | } | 260 | } | |
258 | 261 | |||
259 | /* | 262 | /* | |
260 | * npf_cache_all_ip4: general routine to cache all relevant IPv4 and | 263 | * npf_cache_all: general routine to cache all relevant IPv4 and | |
261 | * TCP, UDP or ICMP data. | 264 | * TCP, UDP or ICMP data. | |
262 | */ | 265 | */ | |
263 | bool | 266 | bool | |
264 | npf_cache_all_ip4(npf_cache_t *npc, nbuf_t *nbuf, const int layer) | 267 | npf_cache_all(npf_cache_t *npc, nbuf_t *nbuf) | |
265 | { | 268 | { | |
266 | void *n_ptr = nbuf_dataptr(nbuf); | 269 | void *n_ptr = nbuf_dataptr(nbuf); | |
267 | u_int offby; | |||
268 | ||||
269 | if (layer == NPF_LAYER_2) { | |||
270 | /* Ethernet: match if ETHERTYPE_IP and if so - advance. */ | |||
271 | if (npf_match_ether(nbuf, 1, 0, ETHERTYPE_IP, &offby)) | |||
272 | return false; | |||
273 | if ((n_ptr = nbuf_advance(&nbuf, n_ptr, offby)) == NULL) | |||
274 | return false; | |||
275 | /* Cache Ethernet header length. XXX */ | |||
276 | npc->npc_elen = offby; | |||
277 | } | |||
278 | 270 | |||
279 | /* IPv4: get protocol, source and destination addresses. */ | 271 | /* IPv4: get protocol, source and destination addresses. */ | |
280 | if (!npf_iscached(npc, NPC_IP46) && !npf_ip4_proto(npc, nbuf, n_ptr)) { | 272 | if (!npf_iscached(npc, NPC_IP46) && !npf_ip4_proto(npc, nbuf, n_ptr)) { | |
281 | return false; | 273 | return false; | |
282 | } | 274 | } | |
283 | if (!npf_iscached(npc, NPC_ADDRS) && | 275 | if (!npf_iscached(npc, NPC_ADDRS) && | |
284 | !npf_fetch_ip4addrs(npc, nbuf, n_ptr)) { | 276 | !npf_fetch_ip4addrs(npc, nbuf, n_ptr)) { | |
285 | return false; | 277 | return false; | |
286 | } | 278 | } | |
287 | switch (npc->npc_proto) { | 279 | switch (npc->npc_proto) { | |
288 | case IPPROTO_TCP: | 280 | case IPPROTO_TCP: | |
289 | /* TCP flags. */ | 281 | /* TCP flags. */ | |
290 | if (!npf_fetch_tcpfl(npc, nbuf, n_ptr)) { | 282 | if (!npf_fetch_tcpfl(npc, nbuf, n_ptr)) { |
--- src/sys/net/npf/Attic/npf_instr.c 2010/08/22 18:56:22 1.1
+++ src/sys/net/npf/Attic/npf_instr.c 2010/09/16 04:53:27 1.2
@@ -1,14 +1,14 @@ | @@ -1,14 +1,14 @@ | |||
1 | /* $NetBSD: npf_instr.c,v 1.1 2010/08/22 18:56:22 rmind Exp $ */ | 1 | /* $NetBSD: npf_instr.c,v 1.2 2010/09/16 04:53:27 rmind Exp $ */ | |
2 | 2 | |||
3 | /*- | 3 | /*- | |
4 | * Copyright (c) 2009-2010 The NetBSD Foundation, Inc. | 4 | * Copyright (c) 2009-2010 The NetBSD Foundation, Inc. | |
5 | * All rights reserved. | 5 | * All rights reserved. | |
6 | * | 6 | * | |
7 | * This material is based upon work partially supported by The | 7 | * This material is based upon work partially supported by The | |
8 | * NetBSD Foundation under a contract with Mindaugas Rasiukevicius. | 8 | * NetBSD Foundation under a contract with Mindaugas Rasiukevicius. | |
9 | * | 9 | * | |
10 | * Redistribution and use in source and binary forms, with or without | 10 | * Redistribution and use in source and binary forms, with or without | |
11 | * modification, are permitted provided that the following conditions | 11 | * modification, are permitted provided that the following conditions | |
12 | * are met: | 12 | * are met: | |
13 | * 1. Redistributions of source code must retain the above copyright | 13 | * 1. Redistributions of source code must retain the above copyright | |
14 | * notice, this list of conditions and the following disclaimer. | 14 | * notice, this list of conditions and the following disclaimer. | |
@@ -25,27 +25,27 @@ | @@ -25,27 +25,27 @@ | |||
25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | 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 | 26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | |
27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | 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 | 28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |
29 | * POSSIBILITY OF SUCH DAMAGE. | 29 | * POSSIBILITY OF SUCH DAMAGE. | |
30 | */ | 30 | */ | |
31 | 31 | |||
32 | /* | 32 | /* | |
33 | * NPF complex instructions. | 33 | * NPF complex instructions. | |
34 | */ | 34 | */ | |
35 | 35 | |||
36 | #ifdef _KERNEL | 36 | #ifdef _KERNEL | |
37 | #include <sys/cdefs.h> | 37 | #include <sys/cdefs.h> | |
38 | __KERNEL_RCSID(0, "$NetBSD: npf_instr.c,v 1.1 2010/08/22 18:56:22 rmind Exp $"); | 38 | __KERNEL_RCSID(0, "$NetBSD: npf_instr.c,v 1.2 2010/09/16 04:53:27 rmind Exp $"); | |
39 | 39 | |||
40 | #include <sys/param.h> | 40 | #include <sys/param.h> | |
41 | #include <sys/kernel.h> | 41 | #include <sys/kernel.h> | |
42 | 42 | |||
43 | #include <net/if.h> | 43 | #include <net/if.h> | |
44 | #include <net/ethertypes.h> | 44 | #include <net/ethertypes.h> | |
45 | #include <net/if_ether.h> | 45 | #include <net/if_ether.h> | |
46 | #include <netinet/in_systm.h> | 46 | #include <netinet/in_systm.h> | |
47 | #include <netinet/in.h> | 47 | #include <netinet/in.h> | |
48 | #endif | 48 | #endif | |
49 | 49 | |||
50 | #include "npf_impl.h" | 50 | #include "npf_impl.h" | |
51 | 51 | |||
@@ -171,39 +171,63 @@ npf_match_udp_ports(npf_cache_t *npc, nb | @@ -171,39 +171,63 @@ npf_match_udp_ports(npf_cache_t *npc, nb | |||
171 | } | 171 | } | |
172 | KASSERT(npf_iscached(npc, NPC_PORTS)); | 172 | KASSERT(npf_iscached(npc, NPC_PORTS)); | |
173 | } | 173 | } | |
174 | p = sd ? npc->npc_sport : npc->npc_dport; | 174 | p = sd ? npc->npc_sport : npc->npc_dport; | |
175 | 175 | |||
176 | /* Match against the port range. */ | 176 | /* Match against the port range. */ | |
177 | return NPF_PORTRANGE_MATCH(prange, p) ? 0 : -1; | 177 | return NPF_PORTRANGE_MATCH(prange, p) ? 0 : -1; | |
178 | } | 178 | } | |
179 | 179 | |||
180 | /* | 180 | /* | |
181 | * npf_match_icmp4: match ICMPv4 packet. | 181 | * npf_match_icmp4: match ICMPv4 packet. | |
182 | */ | 182 | */ | |
183 | int | 183 | int | |
184 | npf_match_icmp4(npf_cache_t *npc, nbuf_t *nbuf, void *n_ptr, | 184 | npf_match_icmp4(npf_cache_t *npc, nbuf_t *nbuf, void *n_ptr, const uint32_t tc) | |
185 | const int type, const int code) | |||
186 | { | 185 | { | |
187 | 186 | |||
188 | if (!npf_iscached(npc, NPC_ICMP)) { | 187 | if (!npf_iscached(npc, NPC_ICMP)) { | |
189 | /* Perform checks, advance to ICMP header. */ | 188 | /* Perform checks, advance to ICMP header. */ | |
190 | if (!npf_iscached(npc, NPC_IP46) && | 189 | if (!npf_iscached(npc, NPC_IP46) && | |
191 | !npf_ip4_proto(npc, nbuf, n_ptr)) { | 190 | !npf_ip4_proto(npc, nbuf, n_ptr)) { | |
192 | return -1; | 191 | return -1; | |
193 | } | 192 | } | |
194 | n_ptr = nbuf_advance(&nbuf, n_ptr, npc->npc_hlen); | 193 | n_ptr = nbuf_advance(&nbuf, n_ptr, npc->npc_hlen); | |
195 | if (n_ptr == NULL || npc->npc_proto != IPPROTO_ICMP) { | 194 | if (n_ptr == NULL || npc->npc_proto != IPPROTO_ICMP) { | |
196 | return -1; | 195 | return -1; | |
197 | } | 196 | } | |
198 | if (!npf_fetch_icmp(npc, nbuf, n_ptr)) { | 197 | if (!npf_fetch_icmp(npc, nbuf, n_ptr)) { | |
199 | return -1; | 198 | return -1; | |
200 | } | 199 | } | |
201 | KASSERT(npf_iscached(npc, NPC_ICMP)); | 200 | KASSERT(npf_iscached(npc, NPC_ICMP)); | |
202 | } | 201 | } | |
203 | /* Match, if required. */ | 202 | /* Match code/type, if required. */ | |
204 | if (type != ~0 && type != npc->npc_icmp_type) | 203 | if ((1 << 31) & tc) { | |
204 | const uint8_t type = (tc >> 8) & 0xff; | |||
205 | if (type != npc->npc_icmp_type) { | |||
206 | return -1; | |||
207 | } | |||
208 | } | |||
209 | if ((1 << 30) & tc) { | |||
210 | const uint8_t code = tc & 0xff; | |||
211 | if (code != npc->npc_icmp_code) { | |||
212 | return -1; | |||
213 | } | |||
214 | } | |||
215 | return 0; | |||
216 | } | |||
217 | ||||
218 | /* | |||
219 | * npf_match_tcpfl: match TCP flags. | |||
220 | */ | |||
221 | int | |||
222 | npf_match_tcpfl(npf_cache_t *npc, nbuf_t *nbuf, void *n_ptr, const uint32_t fl) | |||
223 | { | |||
224 | const uint8_t tcpfl = (fl >> 8) & 0xff, mask = fl & 0xff; | |||
225 | ||||
226 | if (!npf_iscached(npc, NPC_IP46) && !npf_ip4_proto(npc, nbuf, n_ptr)) { | |||
205 | return -1; | 227 | return -1; | |
206 | if (code != ~0 && code != npc->npc_icmp_code) | 228 | } | |
229 | if (!npf_fetch_tcpfl(npc, nbuf, n_ptr)) { | |||
207 | return -1; | 230 | return -1; | |
208 | return 0; | 231 | } | |
232 | return ((npc->npc_tcp_flags & mask) == tcpfl) ? 0 : -1; | |||
209 | } | 233 | } |
--- src/sys/net/npf/npf_mbuf.c 2010/08/22 18:56:22 1.1
+++ src/sys/net/npf/npf_mbuf.c 2010/09/16 04:53:27 1.2
@@ -1,14 +1,14 @@ | @@ -1,14 +1,14 @@ | |||
1 | /* $NetBSD: npf_mbuf.c,v 1.1 2010/08/22 18:56:22 rmind Exp $ */ | 1 | /* $NetBSD: npf_mbuf.c,v 1.2 2010/09/16 04:53:27 rmind Exp $ */ | |
2 | 2 | |||
3 | /*- | 3 | /*- | |
4 | * Copyright (c) 2009-2010 The NetBSD Foundation, Inc. | 4 | * Copyright (c) 2009-2010 The NetBSD Foundation, Inc. | |
5 | * All rights reserved. | 5 | * All rights reserved. | |
6 | * | 6 | * | |
7 | * This material is based upon work partially supported by The | 7 | * This material is based upon work partially supported by The | |
8 | * NetBSD Foundation under a contract with Mindaugas Rasiukevicius. | 8 | * NetBSD Foundation under a contract with Mindaugas Rasiukevicius. | |
9 | * | 9 | * | |
10 | * Redistribution and use in source and binary forms, with or without | 10 | * Redistribution and use in source and binary forms, with or without | |
11 | * modification, are permitted provided that the following conditions | 11 | * modification, are permitted provided that the following conditions | |
12 | * are met: | 12 | * are met: | |
13 | * 1. Redistributions of source code must retain the above copyright | 13 | * 1. Redistributions of source code must retain the above copyright | |
14 | * notice, this list of conditions and the following disclaimer. | 14 | * notice, this list of conditions and the following disclaimer. | |
@@ -28,27 +28,27 @@ | @@ -28,27 +28,27 @@ | |||
28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | 28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |
29 | * POSSIBILITY OF SUCH DAMAGE. | 29 | * POSSIBILITY OF SUCH DAMAGE. | |
30 | */ | 30 | */ | |
31 | 31 | |||
32 | /* | 32 | /* | |
33 | * NPF network buffer management interface. | 33 | * NPF network buffer management interface. | |
34 | * | 34 | * | |
35 | * Network buffer in NetBSD is mbuf. Internal mbuf structures are | 35 | * Network buffer in NetBSD is mbuf. Internal mbuf structures are | |
36 | * abstracted within this source. | 36 | * abstracted within this source. | |
37 | */ | 37 | */ | |
38 | 38 | |||
39 | #ifdef _KERNEL | 39 | #ifdef _KERNEL | |
40 | #include <sys/cdefs.h> | 40 | #include <sys/cdefs.h> | |
41 | __KERNEL_RCSID(0, "$NetBSD: npf_mbuf.c,v 1.1 2010/08/22 18:56:22 rmind Exp $"); | 41 | __KERNEL_RCSID(0, "$NetBSD: npf_mbuf.c,v 1.2 2010/09/16 04:53:27 rmind Exp $"); | |
42 | #endif | 42 | #endif | |
43 | 43 | |||
44 | #include <sys/param.h> | 44 | #include <sys/param.h> | |
45 | #include <sys/mbuf.h> | 45 | #include <sys/mbuf.h> | |
46 | 46 | |||
47 | #include "npf_impl.h" | 47 | #include "npf_impl.h" | |
48 | 48 | |||
49 | /* | 49 | /* | |
50 | * nbuf_dataptr: return a pointer to data in nbuf. | 50 | * nbuf_dataptr: return a pointer to data in nbuf. | |
51 | */ | 51 | */ | |
52 | void * | 52 | void * | |
53 | nbuf_dataptr(nbuf_t *nbuf) | 53 | nbuf_dataptr(nbuf_t *nbuf) | |
54 | { | 54 | { | |
@@ -122,56 +122,58 @@ nbuf_rw_datum(const int wr, nbuf_t *nbuf | @@ -122,56 +122,58 @@ nbuf_rw_datum(const int wr, nbuf_t *nbuf | |||
122 | off = (uintptr_t)n_ptr - mtod(m, uintptr_t); | 122 | off = (uintptr_t)n_ptr - mtod(m, uintptr_t); | |
123 | KASSERT(off < m->m_len); | 123 | KASSERT(off < m->m_len); | |
124 | wmark = m->m_len; | 124 | wmark = m->m_len; | |
125 | 125 | |||
126 | /* Is datum overlapping? */ | 126 | /* Is datum overlapping? */ | |
127 | end = off + len; | 127 | end = off + len; | |
128 | while (__predict_false(end > wmark)) { | 128 | while (__predict_false(end > wmark)) { | |
129 | u_int l; | 129 | u_int l; | |
130 | 130 | |||
131 | /* Get the part of current mbuf. */ | 131 | /* Get the part of current mbuf. */ | |
132 | l = m->m_len - off; | 132 | l = m->m_len - off; | |
133 | KASSERT(l < len); | 133 | KASSERT(l < len); | |
134 | len -= l; | 134 | len -= l; | |
135 | if (wr) { | 135 | if (wr == NBUF_DATA_WRITE) { | |
136 | while (l--) | 136 | while (l--) | |
137 | *d++ = *b++; | 137 | *d++ = *b++; | |
138 | } else { | 138 | } else { | |
139 | KASSERT(wr == NBUF_DATA_READ); | |||
139 | while (l--) | 140 | while (l--) | |
140 | *b++ = *d++; | 141 | *b++ = *d++; | |
141 | } | 142 | } | |
142 | KASSERT(len > 0); | 143 | KASSERT(len > 0); | |
143 | 144 | |||
144 | /* Take next mbuf and continue. */ | 145 | /* Take next mbuf and continue. */ | |
145 | m = m->m_next; | 146 | m = m->m_next; | |
146 | if (__predict_false(m == NULL)) { | 147 | if (__predict_false(m == NULL)) { | |
147 | /* | 148 | /* | |
148 | * If out of chain, then offset with datum | 149 | * If out of chain, then offset with datum | |
149 | * length exceed the packet length. | 150 | * length exceed the packet length. | |
150 | */ | 151 | */ | |
151 | return EINVAL; | 152 | return EINVAL; | |
152 | } | 153 | } | |
153 | wmark += m->m_len; | 154 | wmark += m->m_len; | |
154 | d = mtod(m, uint8_t *); | 155 | d = mtod(m, uint8_t *); | |
155 | off = 0; | 156 | off = 0; | |
156 | } | 157 | } | |
157 | KASSERT(n_ptr == d || mtod(m, uint8_t *) == d); | 158 | KASSERT(n_ptr == d || mtod(m, uint8_t *) == d); | |
158 | KASSERT(len <= m->m_len); | 159 | KASSERT(len <= m->m_len); | |
159 | 160 | |||
160 | /* Non-overlapping case: fetch the actual data. */ | 161 | /* Non-overlapping case: fetch the actual data. */ | |
161 | if (wr) { | 162 | if (wr == NBUF_DATA_WRITE) { | |
162 | while (len--) | 163 | while (len--) | |
163 | *d++ = *b++; | 164 | *d++ = *b++; | |
164 | } else { | 165 | } else { | |
166 | KASSERT(wr == NBUF_DATA_READ); | |||
165 | while (len--) | 167 | while (len--) | |
166 | *b++ = *d++; | 168 | *b++ = *d++; | |
167 | } | 169 | } | |
168 | return 0; | 170 | return 0; | |
169 | } | 171 | } | |
170 | 172 | |||
171 | /* | 173 | /* | |
172 | * nbuf_{fetch|store}_datum: read/write absraction calls on nbuf_rw_datum(). | 174 | * nbuf_{fetch|store}_datum: read/write absraction calls on nbuf_rw_datum(). | |
173 | */ | 175 | */ | |
174 | int | 176 | int | |
175 | nbuf_fetch_datum(nbuf_t *nbuf, void *n_ptr, size_t len, void *buf) | 177 | nbuf_fetch_datum(nbuf_t *nbuf, void *n_ptr, size_t len, void *buf) | |
176 | { | 178 | { | |
177 | 179 |
--- src/sys/net/npf/npf_nat.c 2010/08/22 18:56:22 1.1
+++ src/sys/net/npf/npf_nat.c 2010/09/16 04:53:27 1.2
@@ -1,14 +1,14 @@ | @@ -1,14 +1,14 @@ | |||
1 | /* $NetBSD: npf_nat.c,v 1.1 2010/08/22 18:56:22 rmind Exp $ */ | 1 | /* $NetBSD: npf_nat.c,v 1.2 2010/09/16 04:53:27 rmind Exp $ */ | |
2 | 2 | |||
3 | /*- | 3 | /*- | |
4 | * Copyright (c) 2010 The NetBSD Foundation, Inc. | 4 | * Copyright (c) 2010 The NetBSD Foundation, Inc. | |
5 | * All rights reserved. | 5 | * All rights reserved. | |
6 | * | 6 | * | |
7 | * This material is based upon work partially supported by The | 7 | * This material is based upon work partially supported by The | |
8 | * NetBSD Foundation under a contract with Mindaugas Rasiukevicius. | 8 | * NetBSD Foundation under a contract with Mindaugas Rasiukevicius. | |
9 | * | 9 | * | |
10 | * Redistribution and use in source and binary forms, with or without | 10 | * Redistribution and use in source and binary forms, with or without | |
11 | * modification, are permitted provided that the following conditions | 11 | * modification, are permitted provided that the following conditions | |
12 | * are met: | 12 | * are met: | |
13 | * 1. Redistributions of source code must retain the above copyright | 13 | * 1. Redistributions of source code must retain the above copyright | |
14 | * notice, this list of conditions and the following disclaimer. | 14 | * notice, this list of conditions and the following disclaimer. | |
@@ -29,49 +29,65 @@ | @@ -29,49 +29,65 @@ | |||
29 | * POSSIBILITY OF SUCH DAMAGE. | 29 | * POSSIBILITY OF SUCH DAMAGE. | |
30 | */ | 30 | */ | |
31 | 31 | |||
32 | /* | 32 | /* | |
33 | * NPF network address port translation (NAPT). | 33 | * NPF network address port translation (NAPT). | |
34 | * Described in RFC 2663, RFC 3022. Commonly just "NAT". | 34 | * Described in RFC 2663, RFC 3022. Commonly just "NAT". | |
35 | * | 35 | * | |
36 | * Overview | 36 | * Overview | |
37 | * | 37 | * | |
38 | * There are few mechanisms: NAT policy, port map and translation. | 38 | * There are few mechanisms: NAT policy, port map and translation. | |
39 | * NAT module has a separate ruleset, where rules contain associated | 39 | * NAT module has a separate ruleset, where rules contain associated | |
40 | * NAT policy, thus flexible filter criteria can be used. | 40 | * NAT policy, thus flexible filter criteria can be used. | |
41 | * | 41 | * | |
42 | * Translation types | |||
43 | * | |||
44 | * There are two types of translation: outbound (NPF_NATOUT) and | |||
45 | * inbound (NPF_NATIN). It should not be confused with connection | |||
46 | * direction. | |||
47 | * | |||
48 | * Outbound NAT rewrites: | |||
49 | * - Source on "forwards" stream. | |||
50 | * - Destination on "backwards" stream. | |||
51 | * Inbound NAT rewrites: | |||
52 | * - Destination on "forwards" stream. | |||
53 | * - Source on "backwards" stream. | |||
54 | * | |||
55 | * It should be noted that bi-directional NAT is a combined outbound | |||
56 | * and inbound translation, therefore constructed as two policies. | |||
57 | * | |||
42 | * NAT policies and port maps | 58 | * NAT policies and port maps | |
43 | * | 59 | * | |
44 | * NAT policy is applied when a packet matches the rule. Apart from | 60 | * NAT (translation) policy is applied when a packet matches the rule. | |
45 | * filter criteria, NAT policy has a translation (gateway) IP address | 61 | * Apart from filter criteria, NAT policy has a translation IP address | |
46 | * and associated port map. Port map is a bitmap used to reserve and | 62 | * and associated port map. Port map is a bitmap used to reserve and | |
47 | * use unique TCP/UDP ports for translation. Port maps are unique to | 63 | * use unique TCP/UDP ports for translation. Port maps are unique to | |
48 | * the IP addresses, therefore multiple NAT policies with the same IP | 64 | * the IP addresses, therefore multiple NAT policies with the same IP | |
49 | * will share the same port map. | 65 | * will share the same port map. | |
50 | * | 66 | * | |
51 | * NAT sessions and translation entries | 67 | * NAT sessions and translation entries | |
52 | * | 68 | * | |
53 | * NAT module relies on session management module. Each "NAT" session | 69 | * NAT module relies on session management module. Each "NAT" session | |
54 | * has an associated translation entry (npf_nat_t). It contains local | 70 | * has an associated translation entry (npf_nat_t). It contains saved | |
55 | * i.e. original IP address with port and translation port, allocated | 71 | * i.e. original IP address with port and translation port, allocated | |
56 | * from the port map. Each NAT translation entry is associated with | 72 | * from the port map. Each NAT translation entry is associated with | |
57 | * the policy, which contains translation IP address. Allocated port | 73 | * the policy, which contains translation IP address. Allocated port | |
58 | * is returned to the port map and translation entry destroyed when | 74 | * is returned to the port map and translation entry destroyed when | |
59 | * "NAT" session expires. | 75 | * "NAT" session expires. | |
60 | */ | 76 | */ | |
61 | 77 | |||
62 | #ifdef _KERNEL | 78 | #ifdef _KERNEL | |
63 | #include <sys/cdefs.h> | 79 | #include <sys/cdefs.h> | |
64 | __KERNEL_RCSID(0, "$NetBSD: npf_nat.c,v 1.1 2010/08/22 18:56:22 rmind Exp $"); | 80 | __KERNEL_RCSID(0, "$NetBSD: npf_nat.c,v 1.2 2010/09/16 04:53:27 rmind Exp $"); | |
65 | 81 | |||
66 | #include <sys/param.h> | 82 | #include <sys/param.h> | |
67 | #include <sys/kernel.h> | 83 | #include <sys/kernel.h> | |
68 | #endif | 84 | #endif | |
69 | 85 | |||
70 | #include <sys/atomic.h> | 86 | #include <sys/atomic.h> | |
71 | #include <sys/bitops.h> | 87 | #include <sys/bitops.h> | |
72 | #include <sys/kmem.h> | 88 | #include <sys/kmem.h> | |
73 | #include <sys/pool.h> | 89 | #include <sys/pool.h> | |
74 | #include <net/pfil.h> | 90 | #include <net/pfil.h> | |
75 | #include <netinet/in.h> | 91 | #include <netinet/in.h> | |
76 | 92 | |||
77 | #include "npf_impl.h" | 93 | #include "npf_impl.h" | |
@@ -84,46 +100,49 @@ typedef struct { | @@ -84,46 +100,49 @@ typedef struct { | |||
84 | uint32_t p_bitmap[0]; | 100 | uint32_t p_bitmap[0]; | |
85 | } npf_portmap_t; | 101 | } npf_portmap_t; | |
86 | 102 | |||
87 | /* Portmap range: [ 1024 .. 65535 ] */ | 103 | /* Portmap range: [ 1024 .. 65535 ] */ | |
88 | #define PORTMAP_FIRST (1024) | 104 | #define PORTMAP_FIRST (1024) | |
89 | #define PORTMAP_SIZE ((65536 - PORTMAP_FIRST) / 32) | 105 | #define PORTMAP_SIZE ((65536 - PORTMAP_FIRST) / 32) | |
90 | #define PORTMAP_FILLED ((uint32_t)~0) | 106 | #define PORTMAP_FILLED ((uint32_t)~0) | |
91 | #define PORTMAP_MASK (31) | 107 | #define PORTMAP_MASK (31) | |
92 | #define PORTMAP_SHIFT (5) | 108 | #define PORTMAP_SHIFT (5) | |
93 | 109 | |||
94 | /* NAT policy structure. */ | 110 | /* NAT policy structure. */ | |
95 | struct npf_natpolicy { | 111 | struct npf_natpolicy { | |
96 | LIST_ENTRY(npf_natpolicy) n_entry; | 112 | LIST_ENTRY(npf_natpolicy) n_entry; | |
97 | in_addr_t n_gw_ip; | 113 | int n_type; | |
114 | int n_flags; | |||
115 | in_addr_t n_taddr; | |||
116 | in_port_t n_tport; | |||
98 | npf_portmap_t * n_portmap; | 117 | npf_portmap_t * n_portmap; | |
99 | }; | 118 | }; | |
100 | 119 | |||
101 | /* NAT translation entry for a session. */ | 120 | /* NAT translation entry for a session. */ | |
102 | struct npf_nat { | 121 | struct npf_nat { | |
103 | npf_natpolicy_t * nt_natpolicy; | 122 | npf_natpolicy_t * nt_natpolicy; | |
104 | /* Local address and port (for backwards translation). */ | 123 | /* Original address and port (for backwards translation). */ | |
105 | in_addr_t nt_laddr; | 124 | in_addr_t nt_oaddr; | |
106 | in_port_t nt_lport; | 125 | in_port_t nt_oport; | |
107 | /* Translation port (for forwards). */ | 126 | /* Translation port (for redirects). */ | |
108 | in_port_t nt_tport; | 127 | in_port_t nt_tport; | |
109 | /* ALG (if any) associated with this NAT entry. */ | 128 | /* ALG (if any) associated with this NAT entry. */ | |
110 | npf_alg_t * nt_alg; | 129 | npf_alg_t * nt_alg; | |
111 | uintptr_t nt_alg_arg; | 130 | uintptr_t nt_alg_arg; | |
112 | }; | 131 | }; | |
113 | 132 | |||
114 | static npf_ruleset_t * nat_ruleset; | 133 | static npf_ruleset_t * nat_ruleset __read_mostly; | |
115 | static LIST_HEAD(, npf_natpolicy) nat_policy_list; | 134 | static LIST_HEAD(, npf_natpolicy) nat_policy_list __read_mostly; | |
116 | static pool_cache_t nat_cache; | 135 | static pool_cache_t nat_cache __read_mostly; | |
117 | 136 | |||
118 | /* | 137 | /* | |
119 | * npf_nat_sys{init,fini}: initialise/destroy NAT subsystem structures. | 138 | * npf_nat_sys{init,fini}: initialise/destroy NAT subsystem structures. | |
120 | */ | 139 | */ | |
121 | 140 | |||
122 | void | 141 | void | |
123 | npf_nat_sysinit(void) | 142 | npf_nat_sysinit(void) | |
124 | { | 143 | { | |
125 | 144 | |||
126 | nat_cache = pool_cache_init(sizeof(npf_nat_t), coherency_unit, | 145 | nat_cache = pool_cache_init(sizeof(npf_nat_t), coherency_unit, | |
127 | 0, 0, "npfnatpl", NULL, IPL_NET, NULL, NULL, NULL); | 146 | 0, 0, "npfnatpl", NULL, IPL_NET, NULL, NULL, NULL); | |
128 | KASSERT(nat_cache != NULL); | 147 | KASSERT(nat_cache != NULL); | |
129 | nat_ruleset = npf_ruleset_create(); | 148 | nat_ruleset = npf_ruleset_create(); | |
@@ -131,86 +150,96 @@ npf_nat_sysinit(void) | @@ -131,86 +150,96 @@ npf_nat_sysinit(void) | |||
131 | } | 150 | } | |
132 | 151 | |||
133 | void | 152 | void | |
134 | npf_nat_sysfini(void) | 153 | npf_nat_sysfini(void) | |
135 | { | 154 | { | |
136 | 155 | |||
137 | /* Flush NAT policies. */ | 156 | /* Flush NAT policies. */ | |
138 | npf_nat_reload(NULL); | 157 | npf_nat_reload(NULL); | |
139 | KASSERT(LIST_EMPTY(&nat_policy_list)); | 158 | KASSERT(LIST_EMPTY(&nat_policy_list)); | |
140 | pool_cache_destroy(nat_cache); | 159 | pool_cache_destroy(nat_cache); | |
141 | } | 160 | } | |
142 | 161 | |||
143 | /* | 162 | /* | |
144 | * npf_nat_newpolicy: allocate a new NAT policy. | 163 | * npf_nat_newpolicy: create a new NAT policy. | |
145 | * | 164 | * | |
146 | * => Shares portmap if policy is on existing translation address. | 165 | * => Shares portmap if policy is on existing translation address. | |
147 | * => XXX: serialise at upper layer. | 166 | * => XXX: serialise at upper layer. | |
148 | */ | 167 | */ | |
149 | npf_natpolicy_t * | 168 | npf_natpolicy_t * | |
150 | npf_nat_newpolicy(in_addr_t gip) | 169 | npf_nat_newpolicy(int type, int flags, in_addr_t taddr, in_port_t tport) | |
151 | { | 170 | { | |
152 | npf_natpolicy_t *np, *it; | 171 | npf_natpolicy_t *np, *it; | |
153 | npf_portmap_t *pm; | 172 | npf_portmap_t *pm; | |
154 | 173 | |||
155 | np = kmem_zalloc(sizeof(npf_natpolicy_t), KM_SLEEP); | 174 | np = kmem_zalloc(sizeof(npf_natpolicy_t), KM_SLEEP); | |
156 | if (np == NULL) { | 175 | if (np == NULL) { | |
157 | return NULL; | 176 | return NULL; | |
158 | } | 177 | } | |
159 | np->n_gw_ip = gip; | 178 | KASSERT(type == NPF_NATIN || type == NPF_NATOUT); | |
179 | np->n_type = type; | |||
180 | np->n_flags = flags; | |||
181 | np->n_taddr = taddr; | |||
182 | np->n_tport = tport; | |||
160 | 183 | |||
161 | /* Search for a NAT policy using the same translation address. */ | |||
162 | pm = NULL; | 184 | pm = NULL; | |
185 | if ((flags & NPF_NAT_PORTMAP) == 0) { | |||
186 | goto nopm; | |||
187 | } | |||
188 | ||||
189 | /* Search for a NAT policy using the same translation address. */ | |||
163 | LIST_FOREACH(it, &nat_policy_list, n_entry) { | 190 | LIST_FOREACH(it, &nat_policy_list, n_entry) { | |
164 | if (it->n_gw_ip != np->n_gw_ip) | 191 | if (it->n_taddr != np->n_taddr) | |
165 | continue; | 192 | continue; | |
166 | pm = it->n_portmap; | 193 | pm = it->n_portmap; | |
167 | break; | 194 | break; | |
168 | } | 195 | } | |
169 | if (pm == NULL) { | 196 | if (pm == NULL) { | |
170 | /* Allocate a new port map for the NAT policy. */ | 197 | /* Allocate a new port map for the NAT policy. */ | |
171 | pm = kmem_zalloc(sizeof(npf_portmap_t) + | 198 | pm = kmem_zalloc(sizeof(npf_portmap_t) + | |
172 | (PORTMAP_SIZE * sizeof(uint32_t)), KM_SLEEP); | 199 | (PORTMAP_SIZE * sizeof(uint32_t)), KM_SLEEP); | |
173 | if (pm == NULL) { | 200 | if (pm == NULL) { | |
174 | kmem_free(np, sizeof(npf_natpolicy_t)); | 201 | kmem_free(np, sizeof(npf_natpolicy_t)); | |
175 | return NULL; | 202 | return NULL; | |
176 | } | 203 | } | |
177 | pm->p_refcnt = 1; | 204 | pm->p_refcnt = 1; | |
178 | KASSERT((uintptr_t)pm->p_bitmap == (uintptr_t)pm + sizeof(*pm)); | 205 | KASSERT((uintptr_t)pm->p_bitmap == (uintptr_t)pm + sizeof(*pm)); | |
179 | } else { | 206 | } else { | |
180 | /* Share the port map. */ | 207 | /* Share the port map. */ | |
181 | pm->p_refcnt++; | 208 | pm->p_refcnt++; | |
182 | } | 209 | } | |
210 | nopm: | |||
183 | np->n_portmap = pm; | 211 | np->n_portmap = pm; | |
184 | /* | 212 | /* | |
185 | * Note: old policies with new might co-exist in the list, | 213 | * Note: old policies with new might co-exist in the list, | |
186 | * while reload is in progress, but that is not an issue. | 214 | * while reload is in progress, but that is not an issue. | |
187 | */ | 215 | */ | |
188 | LIST_INSERT_HEAD(&nat_policy_list, np, n_entry); | 216 | LIST_INSERT_HEAD(&nat_policy_list, np, n_entry); | |
189 | return np; | 217 | return np; | |
190 | } | 218 | } | |
191 | 219 | |||
192 | /* | 220 | /* | |
193 | * npf_nat_freepolicy: free NAT policy and, on last reference, free portmap. | 221 | * npf_nat_freepolicy: free NAT policy and, on last reference, free portmap. | |
194 | * | 222 | * | |
195 | * => Called from npf_rule_free() during the reload via npf_nat_reload(). | 223 | * => Called from npf_rule_free() during the reload via npf_nat_reload(). | |
196 | */ | 224 | */ | |
197 | void | 225 | void | |
198 | npf_nat_freepolicy(npf_natpolicy_t *np) | 226 | npf_nat_freepolicy(npf_natpolicy_t *np) | |
199 | { | 227 | { | |
200 | npf_portmap_t *pm = np->n_portmap; | 228 | npf_portmap_t *pm = np->n_portmap; | |
201 | 229 | |||
202 | LIST_REMOVE(np, n_entry); | 230 | LIST_REMOVE(np, n_entry); | |
203 | if (--pm->p_refcnt == 0) { | 231 | if (pm && --pm->p_refcnt == 0) { | |
232 | KASSERT((np->n_flags & NPF_NAT_PORTMAP) != 0); | |||
204 | kmem_free(pm, sizeof(npf_portmap_t) + | 233 | kmem_free(pm, sizeof(npf_portmap_t) + | |
205 | (PORTMAP_SIZE * sizeof(uint32_t))); | 234 | (PORTMAP_SIZE * sizeof(uint32_t))); | |
206 | } | 235 | } | |
207 | kmem_free(np, sizeof(npf_natpolicy_t)); | 236 | kmem_free(np, sizeof(npf_natpolicy_t)); | |
208 | } | 237 | } | |
209 | 238 | |||
210 | /* | 239 | /* | |
211 | * npf_nat_reload: activate new ruleset of NAT policies and destroy old. | 240 | * npf_nat_reload: activate new ruleset of NAT policies and destroy old. | |
212 | * | 241 | * | |
213 | * => Destruction of ruleset will perform npf_nat_freepolicy() for each policy. | 242 | * => Destruction of ruleset will perform npf_nat_freepolicy() for each policy. | |
214 | */ | 243 | */ | |
215 | void | 244 | void | |
216 | npf_nat_reload(npf_ruleset_t *nset) | 245 | npf_nat_reload(npf_ruleset_t *nset) | |
@@ -235,27 +264,27 @@ npf_nat_getport(npf_natpolicy_t *np) | @@ -235,27 +264,27 @@ npf_nat_getport(npf_natpolicy_t *np) | |||
235 | npf_portmap_t *pm = np->n_portmap; | 264 | npf_portmap_t *pm = np->n_portmap; | |
236 | u_int n = PORTMAP_SIZE, idx, bit; | 265 | u_int n = PORTMAP_SIZE, idx, bit; | |
237 | uint32_t map, nmap; | 266 | uint32_t map, nmap; | |
238 | 267 | |||
239 | idx = arc4random() % PORTMAP_SIZE; | 268 | idx = arc4random() % PORTMAP_SIZE; | |
240 | for (;;) { | 269 | for (;;) { | |
241 | KASSERT(idx < PORTMAP_SIZE); | 270 | KASSERT(idx < PORTMAP_SIZE); | |
242 | map = pm->p_bitmap[idx]; | 271 | map = pm->p_bitmap[idx]; | |
243 | if (__predict_false(map == PORTMAP_FILLED)) { | 272 | if (__predict_false(map == PORTMAP_FILLED)) { | |
244 | if (n-- == 0) { | 273 | if (n-- == 0) { | |
245 | /* No space. */ | 274 | /* No space. */ | |
246 | return 0; | 275 | return 0; | |
247 | } | 276 | } | |
248 | /* This bitmap is sfilled, next. */ | 277 | /* This bitmap is filled, next. */ | |
249 | idx = (idx ? idx : PORTMAP_SIZE) - 1; | 278 | idx = (idx ? idx : PORTMAP_SIZE) - 1; | |
250 | continue; | 279 | continue; | |
251 | } | 280 | } | |
252 | bit = ffs32(~map) - 1; | 281 | bit = ffs32(~map) - 1; | |
253 | nmap = map | (1 << bit); | 282 | nmap = map | (1 << bit); | |
254 | if (atomic_cas_32(&pm->p_bitmap[idx], map, nmap) == map) { | 283 | if (atomic_cas_32(&pm->p_bitmap[idx], map, nmap) == map) { | |
255 | /* Success. */ | 284 | /* Success. */ | |
256 | break; | 285 | break; | |
257 | } | 286 | } | |
258 | } | 287 | } | |
259 | return htons(PORTMAP_FIRST + (idx << PORTMAP_SHIFT) + bit); | 288 | return htons(PORTMAP_FIRST + (idx << PORTMAP_SHIFT) + bit); | |
260 | } | 289 | } | |
261 | 290 | |||
@@ -272,279 +301,326 @@ npf_nat_putport(npf_natpolicy_t *np, in_ | @@ -272,279 +301,326 @@ npf_nat_putport(npf_natpolicy_t *np, in_ | |||
272 | u_int idx, bit; | 301 | u_int idx, bit; | |
273 | 302 | |||
274 | port = ntohs(port) - PORTMAP_FIRST; | 303 | port = ntohs(port) - PORTMAP_FIRST; | |
275 | idx = port >> PORTMAP_SHIFT; | 304 | idx = port >> PORTMAP_SHIFT; | |
276 | bit = port & PORTMAP_MASK; | 305 | bit = port & PORTMAP_MASK; | |
277 | do { | 306 | do { | |
278 | map = pm->p_bitmap[idx]; | 307 | map = pm->p_bitmap[idx]; | |
279 | KASSERT(map | (1 << bit)); | 308 | KASSERT(map | (1 << bit)); | |
280 | nmap = map & ~(1 << bit); | 309 | nmap = map & ~(1 << bit); | |
281 | } while (atomic_cas_32(&pm->p_bitmap[idx], map, nmap) != map); | 310 | } while (atomic_cas_32(&pm->p_bitmap[idx], map, nmap) != map); | |
282 | } | 311 | } | |
283 | 312 | |||
284 | /* | 313 | /* | |
285 | * npf_natout: | 314 | * npf_nat_inspect: inspect packet against NAT ruleset and return a policy. | |
286 | * - Inspect packet for a NAT policy, unless session with NAT | |||
287 | * association already exists. | |||
288 | * - Perform "forwards" translation: rewrite source address, etc. | |||
289 | * - Establish sessions or if already exists, associate NAT policy. | |||
290 | */ | 315 | */ | |
291 | int | 316 | static npf_natpolicy_t * | |
292 | npf_natout(npf_cache_t *npc, npf_session_t *se, nbuf_t *nbuf, | 317 | npf_nat_inspect(npf_cache_t *npc, nbuf_t *nbuf, struct ifnet *ifp, const int di) | |
293 | struct ifnet *ifp, const int layer) | 318 | { | |
319 | npf_rule_t *rl; | |||
320 | ||||
321 | rl = npf_ruleset_match(nat_ruleset, npc, nbuf, ifp, di, NPF_LAYER_3); | |||
322 | ||||
323 | return rl ? npf_rule_getnat(rl) : NULL; | |||
324 | } | |||
325 | ||||
326 | /* | |||
327 | * npf_nat_create: create a new NAT translation entry. | |||
328 | */ | |||
329 | static npf_nat_t * | |||
330 | npf_nat_create(npf_cache_t *npc, npf_natpolicy_t *np) | |||
294 | { | 331 | { | |
295 | const int proto = npc->npc_proto; | 332 | const int proto = npc->npc_proto; | |
333 | npf_nat_t *nt; | |||
334 | ||||
335 | /* New NAT association. */ | |||
336 | nt = pool_cache_get(nat_cache, PR_NOWAIT); | |||
337 | if (nt == NULL){ | |||
338 | return NULL; | |||
339 | } | |||
340 | nt->nt_natpolicy = np; | |||
341 | nt->nt_alg = NULL; | |||
342 | ||||
343 | /* Save the original address which may be rewritten. */ | |||
344 | if (np->n_type == NPF_NATOUT) { | |||
345 | /* Source (local) for Outbound NAT. */ | |||
346 | nt->nt_oaddr = npc->npc_srcip; | |||
347 | } else { | |||
348 | /* Destination (external) for Inbound NAT. */ | |||
349 | KASSERT(np->n_type == NPF_NATIN); | |||
350 | nt->nt_oaddr = npc->npc_dstip; | |||
351 | } | |||
352 | ||||
353 | /* | |||
354 | * Port translation, if required, and if it is TCP/UDP. | |||
355 | */ | |||
356 | if ((np->n_flags & NPF_NAT_PORTS) == 0 || | |||
357 | (proto != IPPROTO_TCP && proto != IPPROTO_UDP)) { | |||
358 | nt->nt_oport = 0; | |||
359 | nt->nt_tport = 0; | |||
360 | return nt; | |||
361 | } | |||
362 | /* Save a relevant TCP/UDP port. */ | |||
363 | KASSERT(npf_iscached(npc, NPC_PORTS)); | |||
364 | if (np->n_type == NPF_NATOUT) { | |||
365 | nt->nt_oport = npc->npc_sport; | |||
366 | } else { | |||
367 | nt->nt_oport = npc->npc_dport; | |||
368 | } | |||
369 | /* Get a new port for translation. */ | |||
370 | if ((np->n_flags & NPF_NAT_PORTMAP) != 0) { | |||
371 | nt->nt_tport = npf_nat_getport(np); | |||
372 | } else { | |||
373 | nt->nt_tport = np->n_tport; | |||
374 | } | |||
375 | return nt; | |||
376 | } | |||
377 | ||||
378 | /* | |||
379 | * npf_nat_translate: perform address and/or port translation. | |||
380 | */ | |||
381 | static int | |||
382 | npf_nat_translate(npf_cache_t *npc, nbuf_t *nbuf, npf_nat_t *nt, | |||
383 | const bool forw, const int di) | |||
384 | { | |||
385 | const npf_natpolicy_t *np = nt->nt_natpolicy; | |||
296 | void *n_ptr = nbuf_dataptr(nbuf); | 386 | void *n_ptr = nbuf_dataptr(nbuf); | |
297 | npf_session_t *nse = NULL; /* XXXgcc */ | 387 | in_addr_t addr; | |
388 | in_port_t port; | |||
389 | ||||
390 | KASSERT(npf_iscached(npc, NPC_IP46 | NPC_ADDRS)); | |||
391 | ||||
392 | if (forw) { | |||
393 | /* "Forwards" stream: use translation address/port. */ | |||
394 | KASSERT( | |||
395 | (np->n_type == NPF_NATIN && di == PFIL_IN) ^ | |||
396 | (np->n_type == NPF_NATOUT && di == PFIL_OUT) | |||
397 | ); | |||
398 | addr = np->n_taddr; | |||
399 | port = nt->nt_tport; | |||
400 | } else { | |||
401 | /* "Backwards" stream: use original address/port. */ | |||
402 | KASSERT( | |||
403 | (np->n_type == NPF_NATIN && di == PFIL_OUT) ^ | |||
404 | (np->n_type == NPF_NATOUT && di == PFIL_IN) | |||
405 | ); | |||
406 | addr = nt->nt_oaddr; | |||
407 | port = nt->nt_oport; | |||
408 | } | |||
409 | ||||
410 | /* Execute ALG hooks first. */ | |||
411 | npf_alg_exec(npc, nbuf, nt, di); | |||
412 | ||||
413 | /* | |||
414 | * Address translation: rewrite source/destination address, depending | |||
415 | * on direction (PFIL_OUT - for source, PFIL_IN - for destination). | |||
416 | * Note: cache will be used in npf_rwrport(), update only in the end. | |||
417 | */ | |||
418 | if (!npf_rwrip(npc, nbuf, n_ptr, di, addr)) { | |||
419 | return EINVAL; | |||
420 | } | |||
421 | if ((np->n_flags & NPF_NAT_PORTS) == 0) { | |||
422 | /* Cache new address. */ | |||
423 | if (di == PFIL_OUT) { | |||
424 | npc->npc_srcip = addr; | |||
425 | } else { | |||
426 | npc->npc_dstip = addr; | |||
427 | } | |||
428 | return 0; | |||
429 | } | |||
430 | switch (npc->npc_proto) { | |||
431 | case IPPROTO_TCP: | |||
432 | case IPPROTO_UDP: | |||
433 | KASSERT(npf_iscached(npc, NPC_PORTS)); | |||
434 | /* Rewrite source/destination port. */ | |||
435 | if (!npf_rwrport(npc, nbuf, n_ptr, di, port, addr)) { | |||
436 | return EINVAL; | |||
437 | } | |||
438 | break; | |||
439 | case IPPROTO_ICMP: | |||
440 | /* None. */ | |||
441 | break; | |||
442 | default: | |||
443 | return ENOTSUP; | |||
444 | } | |||
445 | /* Cache new address and port. */ | |||
446 | if (di == PFIL_OUT) { | |||
447 | npc->npc_srcip = addr; | |||
448 | npc->npc_sport = port; | |||
449 | } else { | |||
450 | npc->npc_dstip = addr; | |||
451 | npc->npc_dport = port; | |||
452 | } | |||
453 | return 0; | |||
454 | } | |||
455 | ||||
456 | /* | |||
457 | * npf_do_nat: | |||
458 | * - Inspect packet for a NAT policy, unless a session with a NAT | |||
459 | * association already exists. In such case, determine whether is | |||
460 | * is a "forwards" or "backwards" stream. | |||
461 | * - Perform translation: rewrite source address if "forwards" stream | |||
462 | * and destination address if "backwards". | |||
463 | * - Establish sessions or, if already exists, associate a NAT policy. | |||
464 | */ | |||
465 | int | |||
466 | npf_do_nat(npf_cache_t *npc, npf_session_t *se, nbuf_t *nbuf, | |||
467 | struct ifnet *ifp, const int di) | |||
468 | { | |||
469 | npf_session_t *nse = NULL; | |||
298 | npf_natpolicy_t *np; | 470 | npf_natpolicy_t *np; | |
299 | npf_nat_t *nt; | 471 | npf_nat_t *nt; | |
300 | npf_rule_t *rl; | |||
301 | in_addr_t gwip; | |||
302 | in_port_t tport; | |||
303 | int error; | 472 | int error; | |
304 | bool new; | 473 | bool forw, new; | |
305 | 474 | |||
306 | /* All relevant IPv4 data should be already cached. */ | 475 | /* All relevant IPv4 data should be already cached. */ | |
307 | if (!npf_iscached(npc, NPC_IP46 | NPC_ADDRS)) { | 476 | if (!npf_iscached(npc, NPC_IP46 | NPC_ADDRS)) { | |
308 | return 0; | 477 | return 0; | |
309 | } | 478 | } | |
310 | 479 | |||
311 | /* Detect if there is a linked session pointing to the NAT entry. */ | 480 | /* | |
312 | nt = se ? npf_session_retlinknat(se) : NULL; | 481 | * Return the NAT entry associated with the session, if any. | |
313 | if (nt) { | 482 | * Assumptions: | |
483 | * - If associated via linked session, then "forwards" stream. | |||
484 | * - If associated directly, then "backwards" stream. | |||
485 | */ | |||
486 | if (se && (nt = npf_session_retnat(se, di, &forw)) != NULL) { | |||
314 | np = nt->nt_natpolicy; | 487 | np = nt->nt_natpolicy; | |
315 | new = false; | 488 | new = false; | |
316 | goto skip; | 489 | goto translate; | |
317 | } | 490 | } | |
318 | 491 | |||
319 | /* Inspect packet against NAT ruleset, return a policy. */ | 492 | /* Inspect the packet for a NAT policy, if there is no session. */ | |
320 | rl = npf_ruleset_match(nat_ruleset, npc, nbuf, ifp, PFIL_OUT, layer); | 493 | np = npf_nat_inspect(npc, nbuf, ifp, di); | |
321 | np = rl ? npf_rule_getnat(rl) : NULL; | |||
322 | if (np == NULL) { | 494 | if (np == NULL) { | |
323 | /* If packet does not match - done. */ | 495 | /* If packet does not match - done. */ | |
324 | return 0; | 496 | return 0; | |
325 | } | 497 | } | |
498 | forw = true; | |||
326 | 499 | |||
327 | /* New NAT association. */ | 500 | /* Create a new NAT translation entry. */ | |
328 | nt = pool_cache_get(nat_cache, PR_NOWAIT); | 501 | nt = npf_nat_create(npc, np); | |
329 | if (nt == NULL){ | 502 | if (nt == NULL) { | |
330 | return ENOMEM; | 503 | return ENOMEM; | |
331 | } | 504 | } | |
332 | nt->nt_natpolicy = np; | |||
333 | nt->nt_alg = NULL; | |||
334 | new = true; | 505 | new = true; | |
335 | 506 | |||
336 | /* Save local (source) address. */ | 507 | /* | |
337 | nt->nt_laddr = npc->npc_srcip; | 508 | * If there is no local session (no "keep state" rule - unusual, but | |
338 | 509 | * possible configuration), establish one before translation. Note | ||
339 | if (proto == IPPROTO_TCP || proto == IPPROTO_UDP) { | 510 | * that it is not a "pass" session, therefore passing of "backwards" | |
340 | /* Also, save local TCP/UDP port. */ | 511 | * stream depends on other, stateless filtering rules. | |
341 | KASSERT(npf_iscached(npc, NPC_PORTS)); | 512 | */ | |
342 | nt->nt_lport = npc->npc_sport; | |||
343 | /* Get a new port for translation. */ | |||
344 | nt->nt_tport = npf_nat_getport(np); | |||
345 | } else { | |||
346 | nt->nt_lport = 0; | |||
347 | nt->nt_tport = 0; | |||
348 | } | |||
349 | ||||
350 | /* Match any ALGs. */ | |||
351 | npf_alg_exec(npc, nbuf, nt, PFIL_OUT); | |||
352 | ||||
353 | /* If there is no local session, establish one before translation. */ | |||
354 | if (se == NULL) { | 513 | if (se == NULL) { | |
355 | nse = npf_session_establish(npc, NULL, PFIL_OUT); | 514 | nse = npf_session_establish(npc, NULL, di); | |
356 | if (nse == NULL) { | 515 | if (nse == NULL) { | |
357 | error = ENOMEM; | 516 | error = ENOMEM; | |
358 | goto out; | 517 | goto out; | |
359 | } | 518 | } | |
360 | se = nse; | 519 | se = nse; | |
361 | } else { | |||
362 | nse = NULL; | |||
363 | } | 520 | } | |
364 | skip: | 521 | translate: | |
365 | if (layer == NPF_LAYER_2 && /* XXX */ | 522 | /* Perform the translation. */ | |
366 | (n_ptr = nbuf_advance(&nbuf, n_ptr, npc->npc_elen)) == NULL) | 523 | error = npf_nat_translate(npc, nbuf, nt, forw, di); | |
367 | return EINVAL; | 524 | if (error) { | |
368 | ||||
369 | /* Execute ALG hooks first. */ | |||
370 | npf_alg_exec(npc, nbuf, nt, PFIL_OUT); | |||
371 | ||||
372 | gwip = np->n_gw_ip; | |||
373 | tport = nt->nt_tport; | |||
374 | ||||
375 | /* | |||
376 | * Perform translation: rewrite source address et al. | |||
377 | * Note: cache may be used in npf_rwrport(), update only in the end. | |||
378 | */ | |||
379 | if (!npf_rwrip(npc, nbuf, n_ptr, PFIL_OUT, gwip)) { | |||
380 | error = EINVAL; | |||
381 | goto out; | 525 | goto out; | |
382 | } | 526 | } | |
383 | if (proto == IPPROTO_TCP || proto == IPPROTO_UDP) { | |||
384 | KASSERT(tport != 0); | |||
385 | if (!npf_rwrport(npc, nbuf, n_ptr, PFIL_OUT, tport, gwip)) { | |||
386 | error = EINVAL; | |||
387 | goto out; | |||
388 | } | |||
389 | } | |||
390 | /* Success: cache new address and port (if any). */ | |||
391 | npc->npc_srcip = gwip; | |||
392 | npc->npc_sport = tport; | |||
393 | error = 0; | |||
394 | 527 | |||
395 | if (__predict_false(new)) { | 528 | if (__predict_false(new)) { | |
396 | npf_session_t *natse; | 529 | npf_session_t *natse; | |
397 | /* | 530 | /* | |
398 | * Establish a new NAT session using translated address and | 531 | * Establish a new NAT session using translated address and | |
399 | * associate NAT translation data with this session. | 532 | * associate NAT translation data with this session. | |
400 | * | 533 | * | |
401 | * Note: packet now has a translated address in the cache. | 534 | * Note: packet now has a translated address in the cache. | |
402 | */ | 535 | */ | |
403 | natse = npf_session_establish(npc, nt, PFIL_OUT); | 536 | natse = npf_session_establish(npc, nt, di); | |
404 | if (natse == NULL) { | 537 | if (natse == NULL) { | |
405 | error = ENOMEM; | 538 | error = ENOMEM; | |
406 | goto out; | 539 | goto out; | |
407 | } | 540 | } | |
408 | /* | 541 | /* | |
409 | * Link local session with NAT session, if no link already. | 542 | * Link local session with NAT session, if no link already. | |
410 | */ | 543 | */ | |
411 | npf_session_link(se, natse); | 544 | npf_session_link(se, natse); | |
412 | npf_session_release(natse); | 545 | npf_session_release(natse); | |
413 | out: | 546 | out: | |
414 | if (error) { | 547 | if (error) { | |
415 | if (nse != NULL) { | 548 | if (nse != NULL) { | |
416 | /* XXX: expire local session if new? */ | 549 | /* XXX: Expire it?? */ | |
417 | } | 550 | } | |
418 | /* Will free the structure and return the port. */ | 551 | /* Will free the structure and return the port. */ | |
419 | npf_nat_expire(nt); | 552 | npf_nat_expire(nt); | |
420 | } | 553 | } | |
421 | if (nse != NULL) { | 554 | if (nse != NULL) { | |
422 | /* Drop the reference local session was new. */ | |||
423 | npf_session_release(nse); | 555 | npf_session_release(nse); | |
424 | } | 556 | } | |
425 | } | 557 | } | |
426 | return error; | 558 | return error; | |
427 | } | 559 | } | |
428 | 560 | |||
429 | /* | 561 | /* | |
430 | * npf_natin: | 562 | * npf_nat_getorig: return original IP address and port from translation entry. | |
431 | * - Inspect packet for a session with associated NAT policy. | |||
432 | * - Perform "backwards" translation: rewrite destination address, etc. | |||
433 | */ | |||
434 | int | |||
435 | npf_natin(npf_cache_t *npc, npf_session_t *se, nbuf_t *nbuf, const int layer) | |||
436 | { | |||
437 | npf_nat_t *nt = se ? npf_session_retnat(se) : NULL; | |||
438 | ||||
439 | if (nt == NULL) { | |||
440 | /* No association - no translation. */ | |||
441 | return 0; | |||
442 | } | |||
443 | KASSERT(npf_iscached(npc, NPC_IP46 | NPC_ADDRS)); | |||
444 | ||||
445 | void *n_ptr = nbuf_dataptr(nbuf); | |||
446 | in_addr_t laddr = nt->nt_laddr; | |||
447 | in_port_t lport = nt->nt_lport; | |||
448 | ||||
449 | if (layer == NPF_LAYER_2) { | |||
450 | n_ptr = nbuf_advance(&nbuf, n_ptr, npc->npc_elen); | |||
451 | if (n_ptr == NULL) { | |||
452 | return EINVAL; | |||
453 | } | |||
454 | } | |||
455 | ||||
456 | /* Execute ALG hooks first. */ | |||
457 | npf_alg_exec(npc, nbuf, nt, PFIL_IN); | |||
458 | ||||
459 | /* | |||
460 | * Address translation: rewrite destination address. | |||
461 | * Note: cache will be used in npf_rwrport(), update only in the end. | |||
462 | */ | |||
463 | if (!npf_rwrip(npc, nbuf, n_ptr, PFIL_IN, laddr)) { | |||
464 | return EINVAL; | |||
465 | } | |||
466 | switch (npc->npc_proto) { | |||
467 | case IPPROTO_TCP: | |||
468 | case IPPROTO_UDP: | |||
469 | KASSERT(npf_iscached(npc, NPC_PORTS)); | |||
470 | /* Rewrite destination port. */ | |||
471 | if (!npf_rwrport(npc, nbuf, n_ptr, PFIL_IN, lport, laddr)) { | |||
472 | return EINVAL; | |||
473 | } | |||
474 | break; | |||
475 | case IPPROTO_ICMP: | |||
476 | /* None. */ | |||
477 | break; | |||
478 | default: | |||
479 | return ENOTSUP; | |||
480 | } | |||
481 | /* Cache new address and port. */ | |||
482 | npc->npc_dstip = laddr; | |||
483 | npc->npc_dport = lport; | |||
484 | return 0; | |||
485 | } | |||
486 | ||||
487 | /* | |||
488 | * npf_nat_getlocal: return local IP address and port from translation entry. | |||
489 | */ | 563 | */ | |
490 | void | 564 | void | |
491 | npf_nat_getlocal(npf_nat_t *nt, in_addr_t *addr, in_port_t *port) | 565 | npf_nat_getorig(npf_nat_t *nt, in_addr_t *addr, in_port_t *port) | |
492 | { | 566 | { | |
493 | 567 | |||
494 | *addr = nt->nt_laddr; | 568 | *addr = nt->nt_oaddr; | |
495 | *port = nt->nt_lport; | 569 | *port = nt->nt_oport; | |
496 | } | 570 | } | |
497 | 571 | |||
498 | void | 572 | void | |
499 | npf_nat_setalg(npf_nat_t *nt, npf_alg_t *alg, uintptr_t arg) | 573 | npf_nat_setalg(npf_nat_t *nt, npf_alg_t *alg, uintptr_t arg) | |
500 | { | 574 | { | |
501 | 575 | |||
502 | nt->nt_alg = alg; | 576 | nt->nt_alg = alg; | |
503 | nt->nt_alg_arg = arg; | 577 | nt->nt_alg_arg = arg; | |
504 | } | 578 | } | |
505 | 579 | |||
506 | /* | 580 | /* | |
507 | * npf_nat_expire: free NAT-related data structures on session expiration. | 581 | * npf_nat_expire: free NAT-related data structures on session expiration. | |
508 | */ | 582 | */ | |
509 | void | 583 | void | |
510 | npf_nat_expire(npf_nat_t *nt) | 584 | npf_nat_expire(npf_nat_t *nt) | |
511 | { | 585 | { | |
586 | npf_natpolicy_t *np = nt->nt_natpolicy; | |||
512 | 587 | |||
513 | if (nt->nt_tport) { | 588 | if ((np->n_flags & NPF_NAT_PORTMAP) != 0) { | |
514 | npf_natpolicy_t *np = nt->nt_natpolicy; | 589 | KASSERT(nt->nt_tport != 0); | |
515 | npf_nat_putport(np, nt->nt_tport); | 590 | npf_nat_putport(np, nt->nt_tport); | |
516 | } | 591 | } | |
517 | pool_cache_put(nat_cache, nt); | 592 | pool_cache_put(nat_cache, nt); | |
518 | } | 593 | } | |
519 | 594 | |||
520 | #if defined(DDB) || defined(_NPF_TESTING) | 595 | #if defined(DDB) || defined(_NPF_TESTING) | |
521 | 596 | |||
522 | void | 597 | void | |
523 | npf_nat_dump(npf_nat_t *nt) | 598 | npf_nat_dump(npf_nat_t *nt) | |
524 | { | 599 | { | |
525 | npf_natpolicy_t *np; | 600 | npf_natpolicy_t *np; | |
526 | struct in_addr ip; | 601 | struct in_addr ip; | |
527 | 602 | |||
528 | if (nt) { | 603 | if (nt) { | |
529 | np = nt->nt_natpolicy; | 604 | np = nt->nt_natpolicy; | |
530 | goto skip; | 605 | goto skip; | |
531 | } | 606 | } | |
532 | LIST_FOREACH(np, &nat_policy_list, n_entry) { | 607 | LIST_FOREACH(np, &nat_policy_list, n_entry) { | |
533 | skip: | 608 | skip: | |
534 | ip.s_addr = np->n_gw_ip; | 609 | ip.s_addr = np->n_taddr; | |
535 | printf("\tNAT policy: gw_ip = %s\n", inet_ntoa(ip)); | 610 | printf("\tNAT policy: type = %d, flags = %d, taddr = %s\n", | |
611 | np->n_type, np->n_flags, inet_ntoa(ip)); | |||
536 | if (nt == NULL) { | 612 | if (nt == NULL) { | |
537 | continue; | 613 | continue; | |
538 | } | 614 | } | |
539 | ip.s_addr = nt->nt_laddr; | 615 | ip.s_addr = nt->nt_oaddr; | |
540 | printf("\tNAT: original address %s, lport %d, tport = %d\n", | 616 | printf("\tNAT: original address %s, oport %d, tport = %d\n", | |
541 | inet_ntoa(ip), ntohs(nt->nt_lport), ntohs(nt->nt_tport)); | 617 | inet_ntoa(ip), ntohs(nt->nt_oport), ntohs(nt->nt_tport)); | |
542 | if (nt->nt_alg) { | 618 | if (nt->nt_alg) { | |
543 | printf("\tNAT ALG = %p, ARG = %p\n", | 619 | printf("\tNAT ALG = %p, ARG = %p\n", | |
544 | nt->nt_alg, (void *)nt->nt_alg_arg); | 620 | nt->nt_alg, (void *)nt->nt_alg_arg); | |
545 | } | 621 | } | |
546 | return; | 622 | return; | |
547 | } | 623 | } | |
548 | } | 624 | } | |
549 | 625 | |||
550 | #endif | 626 | #endif |
--- src/sys/net/npf/Attic/npf_ncode.h 2010/08/22 18:56:22 1.1
+++ src/sys/net/npf/Attic/npf_ncode.h 2010/09/16 04:53:27 1.2
@@ -1,14 +1,14 @@ | @@ -1,14 +1,14 @@ | |||
1 | /* $NetBSD: npf_ncode.h,v 1.1 2010/08/22 18:56:22 rmind Exp $ */ | 1 | /* $NetBSD: npf_ncode.h,v 1.2 2010/09/16 04:53:27 rmind Exp $ */ | |
2 | 2 | |||
3 | /*- | 3 | /*- | |
4 | * Copyright (c) 2009-2010 The NetBSD Foundation, Inc. | 4 | * Copyright (c) 2009-2010 The NetBSD Foundation, Inc. | |
5 | * All rights reserved. | 5 | * All rights reserved. | |
6 | * | 6 | * | |
7 | * This material is based upon work partially supported by The | 7 | * This material is based upon work partially supported by The | |
8 | * NetBSD Foundation under a contract with Mindaugas Rasiukevicius. | 8 | * NetBSD Foundation under a contract with Mindaugas Rasiukevicius. | |
9 | * | 9 | * | |
10 | * Redistribution and use in source and binary forms, with or without | 10 | * Redistribution and use in source and binary forms, with or without | |
11 | * modification, are permitted provided that the following conditions | 11 | * modification, are permitted provided that the following conditions | |
12 | * are met: | 12 | * are met: | |
13 | * 1. Redistributions of source code must retain the above copyright | 13 | * 1. Redistributions of source code must retain the above copyright | |
14 | * notice, this list of conditions and the following disclaimer. | 14 | * notice, this list of conditions and the following disclaimer. | |
@@ -93,15 +93,16 @@ void npf_ncode_free(void *, size_t); | @@ -93,15 +93,16 @@ void npf_ncode_free(void *, size_t); | |||
93 | 93 | |||
94 | /* | 94 | /* | |
95 | * CISC-like n-code instructions. | 95 | * CISC-like n-code instructions. | |
96 | */ | 96 | */ | |
97 | 97 | |||
98 | #define NPF_OPCODE_ETHER 0x80 | 98 | #define NPF_OPCODE_ETHER 0x80 | |
99 | 99 | |||
100 | #define NPF_OPCODE_IP4MASK 0x90 | 100 | #define NPF_OPCODE_IP4MASK 0x90 | |
101 | #define NPF_OPCODE_IP4TABLE 0x91 | 101 | #define NPF_OPCODE_IP4TABLE 0x91 | |
102 | #define NPF_OPCODE_ICMP4 0x92 | 102 | #define NPF_OPCODE_ICMP4 0x92 | |
103 | 103 | |||
104 | #define NPF_OPCODE_TCP_PORTS 0xa0 | 104 | #define NPF_OPCODE_TCP_PORTS 0xa0 | |
105 | #define NPF_OPCODE_UDP_PORTS 0xa1 | 105 | #define NPF_OPCODE_UDP_PORTS 0xa1 | |
106 | #define NPF_OPCODE_TCP_FLAGS 0xa2 | |||
106 | 107 | |||
107 | #endif | 108 | #endif |
--- src/sys/net/npf/Attic/npf_processor.c 2010/08/22 18:56:22 1.1
+++ src/sys/net/npf/Attic/npf_processor.c 2010/09/16 04:53:27 1.2
@@ -1,14 +1,14 @@ | @@ -1,14 +1,14 @@ | |||
1 | /* $NetBSD: npf_processor.c,v 1.1 2010/08/22 18:56:22 rmind Exp $ */ | 1 | /* $NetBSD: npf_processor.c,v 1.2 2010/09/16 04:53:27 rmind Exp $ */ | |
2 | 2 | |||
3 | /*- | 3 | /*- | |
4 | * Copyright (c) 2009-2010 The NetBSD Foundation, Inc. | 4 | * Copyright (c) 2009-2010 The NetBSD Foundation, Inc. | |
5 | * All rights reserved. | 5 | * All rights reserved. | |
6 | * | 6 | * | |
7 | * This material is based upon work partially supported by The | 7 | * This material is based upon work partially supported by The | |
8 | * NetBSD Foundation under a contract with Mindaugas Rasiukevicius. | 8 | * NetBSD Foundation under a contract with Mindaugas Rasiukevicius. | |
9 | * | 9 | * | |
10 | * Redistribution and use in source and binary forms, with or without | 10 | * Redistribution and use in source and binary forms, with or without | |
11 | * modification, are permitted provided that the following conditions | 11 | * modification, are permitted provided that the following conditions | |
12 | * are met: | 12 | * are met: | |
13 | * 1. Redistributions of source code must retain the above copyright | 13 | * 1. Redistributions of source code must retain the above copyright | |
14 | * notice, this list of conditions and the following disclaimer. | 14 | * notice, this list of conditions and the following disclaimer. | |
@@ -45,27 +45,27 @@ | @@ -45,27 +45,27 @@ | |||
45 | * be fully optimized. | 45 | * be fully optimized. | |
46 | * | 46 | * | |
47 | * N-code memory address and thus instructions should be word aligned. | 47 | * N-code memory address and thus instructions should be word aligned. | |
48 | * All processing is done in 32 bit words, since both instructions (their | 48 | * All processing is done in 32 bit words, since both instructions (their | |
49 | * codes) and arguments use 32 bits words. | 49 | * codes) and arguments use 32 bits words. | |
50 | * | 50 | * | |
51 | * TODO: | 51 | * TODO: | |
52 | * - There is some space for better a abstraction. Duplicated opcode | 52 | * - There is some space for better a abstraction. Duplicated opcode | |
53 | * maintenance in npf_ncode_process() and nc_insn_check() might be avoided. | 53 | * maintenance in npf_ncode_process() and nc_insn_check() might be avoided. | |
54 | */ | 54 | */ | |
55 | 55 | |||
56 | #ifdef _KERNEL | 56 | #ifdef _KERNEL | |
57 | #include <sys/cdefs.h> | 57 | #include <sys/cdefs.h> | |
58 | __KERNEL_RCSID(0, "$NetBSD: npf_processor.c,v 1.1 2010/08/22 18:56:22 rmind Exp $"); | 58 | __KERNEL_RCSID(0, "$NetBSD: npf_processor.c,v 1.2 2010/09/16 04:53:27 rmind Exp $"); | |
59 | #endif | 59 | #endif | |
60 | 60 | |||
61 | #include <sys/param.h> | 61 | #include <sys/param.h> | |
62 | #include <sys/kernel.h> | 62 | #include <sys/kernel.h> | |
63 | #include <sys/types.h> | 63 | #include <sys/types.h> | |
64 | #include <sys/kmem.h> | 64 | #include <sys/kmem.h> | |
65 | 65 | |||
66 | #include "npf_impl.h" | 66 | #include "npf_impl.h" | |
67 | #include "npf_ncode.h" | 67 | #include "npf_ncode.h" | |
68 | 68 | |||
69 | /* | 69 | /* | |
70 | * nc_fetch_word: fetch a word (32 bits) from the n-code and increase | 70 | * nc_fetch_word: fetch a word (32 bits) from the n-code and increase | |
71 | * instruction pointer by one word. | 71 | * instruction pointer by one word. | |
@@ -144,27 +144,27 @@ npf_ncode_process(npf_cache_t *npc, cons | @@ -144,27 +144,27 @@ npf_ncode_process(npf_cache_t *npc, cons | |||
144 | nbuf_t * nbuf; | 144 | nbuf_t * nbuf; | |
145 | /* Data pointer in the current nbuf. */ | 145 | /* Data pointer in the current nbuf. */ | |
146 | void * n_ptr; | 146 | void * n_ptr; | |
147 | /* Virtual registers. */ | 147 | /* Virtual registers. */ | |
148 | uint32_t regs[NPF_NREGS]; | 148 | uint32_t regs[NPF_NREGS]; | |
149 | /* Local, state variables. */ | 149 | /* Local, state variables. */ | |
150 | uint32_t d, i, n; | 150 | uint32_t d, i, n; | |
151 | u_int lcount; | 151 | u_int lcount; | |
152 | int cmpval; | 152 | int cmpval; | |
153 | 153 | |||
154 | i_ptr = ncode; | 154 | i_ptr = ncode; | |
155 | regs[0] = layer; | 155 | regs[0] = layer; | |
156 | 156 | |||
157 | lcount = NPF_LOOP_LIMIT; /* XXX */ | 157 | lcount = NPF_LOOP_LIMIT; | |
158 | cmpval = 0; | 158 | cmpval = 0; | |
159 | 159 | |||
160 | /* Note: offset = n_ptr - nbuf_dataptr(nbuf); */ | 160 | /* Note: offset = n_ptr - nbuf_dataptr(nbuf); */ | |
161 | nbuf = nbuf0; | 161 | nbuf = nbuf0; | |
162 | n_ptr = nbuf_dataptr(nbuf); | 162 | n_ptr = nbuf_dataptr(nbuf); | |
163 | 163 | |||
164 | process_next: | 164 | process_next: | |
165 | /* | 165 | /* | |
166 | * Loop must always start on instruction, therefore first word | 166 | * Loop must always start on instruction, therefore first word | |
167 | * should be an opcode. Most used instructions are checked first. | 167 | * should be an opcode. Most used instructions are checked first. | |
168 | */ | 168 | */ | |
169 | i_ptr = nc_fetch_word(i_ptr, &d); | 169 | i_ptr = nc_fetch_word(i_ptr, &d); | |
170 | if (__predict_true(NPF_CISC_OPCODE(d))) { | 170 | if (__predict_true(NPF_CISC_OPCODE(d))) { | |
@@ -294,30 +294,35 @@ cisc_like: | @@ -294,30 +294,35 @@ cisc_like: | |||
294 | i_ptr = nc_fetch_double(i_ptr, &n, &i); | 294 | i_ptr = nc_fetch_double(i_ptr, &n, &i); | |
295 | cmpval = npf_match_ip4table(npc, nbuf, n_ptr, n, i); | 295 | cmpval = npf_match_ip4table(npc, nbuf, n_ptr, n, i); | |
296 | break; | 296 | break; | |
297 | case NPF_OPCODE_TCP_PORTS: | 297 | case NPF_OPCODE_TCP_PORTS: | |
298 | /* Source/destination, port range. */ | 298 | /* Source/destination, port range. */ | |
299 | i_ptr = nc_fetch_double(i_ptr, &n, &i); | 299 | i_ptr = nc_fetch_double(i_ptr, &n, &i); | |
300 | cmpval = npf_match_tcp_ports(npc, nbuf, n_ptr, n, i); | 300 | cmpval = npf_match_tcp_ports(npc, nbuf, n_ptr, n, i); | |
301 | break; | 301 | break; | |
302 | case NPF_OPCODE_UDP_PORTS: | 302 | case NPF_OPCODE_UDP_PORTS: | |
303 | /* Source/destination, port range. */ | 303 | /* Source/destination, port range. */ | |
304 | i_ptr = nc_fetch_double(i_ptr, &n, &i); | 304 | i_ptr = nc_fetch_double(i_ptr, &n, &i); | |
305 | cmpval = npf_match_udp_ports(npc, nbuf, n_ptr, n, i); | 305 | cmpval = npf_match_udp_ports(npc, nbuf, n_ptr, n, i); | |
306 | break; | 306 | break; | |
307 | case NPF_OPCODE_TCP_FLAGS: | |||
308 | /* TCP flags/mask. */ | |||
309 | i_ptr = nc_fetch_word(i_ptr, &n); | |||
310 | cmpval = npf_match_tcpfl(npc, nbuf, n_ptr, n); | |||
311 | break; | |||
307 | case NPF_OPCODE_ICMP4: | 312 | case NPF_OPCODE_ICMP4: | |
308 | /* ICMP type, code. */ | 313 | /* ICMP type/code. */ | |
309 | i_ptr = nc_fetch_double(i_ptr, &n, &i); | 314 | i_ptr = nc_fetch_word(i_ptr, &n); | |
310 | cmpval = npf_match_icmp4(npc, nbuf, n_ptr, n, i); | 315 | cmpval = npf_match_icmp4(npc, nbuf, n_ptr, n); | |
311 | break; | 316 | break; | |
312 | default: | 317 | default: | |
313 | /* Invalid instruction. */ | 318 | /* Invalid instruction. */ | |
314 | KASSERT(false); | 319 | KASSERT(false); | |
315 | } | 320 | } | |
316 | goto process_next; | 321 | goto process_next; | |
317 | fail: | 322 | fail: | |
318 | /* Failure case. */ | 323 | /* Failure case. */ | |
319 | return -1; | 324 | return -1; | |
320 | } | 325 | } | |
321 | 326 | |||
322 | /* | 327 | /* | |
323 | * nc_ptr_check: validate that instruction pointer is not out of range. | 328 | * nc_ptr_check: validate that instruction pointer is not out of range. | |
@@ -437,28 +442,31 @@ jmp_check: | @@ -437,28 +442,31 @@ jmp_check: | |||
437 | break; | 442 | break; | |
438 | case NPF_OPCODE_IP4MASK: | 443 | case NPF_OPCODE_IP4MASK: | |
439 | error = nc_ptr_check(&iptr, nc, sz, 3, NULL, 0); | 444 | error = nc_ptr_check(&iptr, nc, sz, 3, NULL, 0); | |
440 | break; | 445 | break; | |
441 | case NPF_OPCODE_IP4TABLE: | 446 | case NPF_OPCODE_IP4TABLE: | |
442 | error = nc_ptr_check(&iptr, nc, sz, 2, NULL, 0); | 447 | error = nc_ptr_check(&iptr, nc, sz, 2, NULL, 0); | |
443 | break; | 448 | break; | |
444 | case NPF_OPCODE_TCP_PORTS: | 449 | case NPF_OPCODE_TCP_PORTS: | |
445 | error = nc_ptr_check(&iptr, nc, sz, 2, NULL, 0); | 450 | error = nc_ptr_check(&iptr, nc, sz, 2, NULL, 0); | |
446 | break; | 451 | break; | |
447 | case NPF_OPCODE_UDP_PORTS: | 452 | case NPF_OPCODE_UDP_PORTS: | |
448 | error = nc_ptr_check(&iptr, nc, sz, 2, NULL, 0); | 453 | error = nc_ptr_check(&iptr, nc, sz, 2, NULL, 0); | |
449 | break; | 454 | break; | |
455 | case NPF_OPCODE_TCP_FLAGS: | |||
456 | error = nc_ptr_check(&iptr, nc, sz, 1, NULL, 0); | |||
457 | break; | |||
450 | case NPF_OPCODE_ICMP4: | 458 | case NPF_OPCODE_ICMP4: | |
451 | error = nc_ptr_check(&iptr, nc, sz, 2, NULL, 0); | 459 | error = nc_ptr_check(&iptr, nc, sz, 1, NULL, 0); | |
452 | break; | 460 | break; | |
453 | default: | 461 | default: | |
454 | /* Invalid instruction. */ | 462 | /* Invalid instruction. */ | |
455 | return NPF_ERR_OPCODE; | 463 | return NPF_ERR_OPCODE; | |
456 | } | 464 | } | |
457 | if (error) { | 465 | if (error) { | |
458 | return error; | 466 | return error; | |
459 | } | 467 | } | |
460 | if ((u_int)regidx >= NPF_NREGS) { | 468 | if ((u_int)regidx >= NPF_NREGS) { | |
461 | /* Invalid register. */ | 469 | /* Invalid register. */ | |
462 | return NPF_ERR_REG; | 470 | return NPF_ERR_REG; | |
463 | } | 471 | } | |
464 | *adv = iptr - optr; | 472 | *adv = iptr - optr; |
--- src/sys/net/npf/npf_ruleset.c 2010/08/22 18:56:22 1.1
+++ src/sys/net/npf/npf_ruleset.c 2010/09/16 04:53:27 1.2
@@ -1,14 +1,14 @@ | @@ -1,14 +1,14 @@ | |||
1 | /* $NetBSD: npf_ruleset.c,v 1.1 2010/08/22 18:56:22 rmind Exp $ */ | 1 | /* $NetBSD: npf_ruleset.c,v 1.2 2010/09/16 04:53:27 rmind Exp $ */ | |
2 | 2 | |||
3 | /*- | 3 | /*- | |
4 | * Copyright (c) 2009-2010 The NetBSD Foundation, Inc. | 4 | * Copyright (c) 2009-2010 The NetBSD Foundation, Inc. | |
5 | * All rights reserved. | 5 | * All rights reserved. | |
6 | * | 6 | * | |
7 | * This material is based upon work partially supported by The | 7 | * This material is based upon work partially supported by The | |
8 | * NetBSD Foundation under a contract with Mindaugas Rasiukevicius. | 8 | * NetBSD Foundation under a contract with Mindaugas Rasiukevicius. | |
9 | * | 9 | * | |
10 | * Redistribution and use in source and binary forms, with or without | 10 | * Redistribution and use in source and binary forms, with or without | |
11 | * modification, are permitted provided that the following conditions | 11 | * modification, are permitted provided that the following conditions | |
12 | * are met: | 12 | * are met: | |
13 | * 1. Redistributions of source code must retain the above copyright | 13 | * 1. Redistributions of source code must retain the above copyright | |
14 | * notice, this list of conditions and the following disclaimer. | 14 | * notice, this list of conditions and the following disclaimer. | |
@@ -29,27 +29,27 @@ | @@ -29,27 +29,27 @@ | |||
29 | * POSSIBILITY OF SUCH DAMAGE. | 29 | * POSSIBILITY OF SUCH DAMAGE. | |
30 | */ | 30 | */ | |
31 | 31 | |||
32 | /* | 32 | /* | |
33 | * NPF ruleset module. | 33 | * NPF ruleset module. | |
34 | * | 34 | * | |
35 | * Lock order: | 35 | * Lock order: | |
36 | * | 36 | * | |
37 | * ruleset_lock -> table_lock -> npf_table_t::t_lock | 37 | * ruleset_lock -> table_lock -> npf_table_t::t_lock | |
38 | */ | 38 | */ | |
39 | 39 | |||
40 | #ifdef _KERNEL | 40 | #ifdef _KERNEL | |
41 | #include <sys/cdefs.h> | 41 | #include <sys/cdefs.h> | |
42 | __KERNEL_RCSID(0, "$NetBSD: npf_ruleset.c,v 1.1 2010/08/22 18:56:22 rmind Exp $"); | 42 | __KERNEL_RCSID(0, "$NetBSD: npf_ruleset.c,v 1.2 2010/09/16 04:53:27 rmind Exp $"); | |
43 | 43 | |||
44 | #include <sys/param.h> | 44 | #include <sys/param.h> | |
45 | #include <sys/kernel.h> | 45 | #include <sys/kernel.h> | |
46 | #endif | 46 | #endif | |
47 | 47 | |||
48 | #include <sys/atomic.h> | 48 | #include <sys/atomic.h> | |
49 | #include <sys/kmem.h> | 49 | #include <sys/kmem.h> | |
50 | #include <sys/pool.h> | 50 | #include <sys/pool.h> | |
51 | #include <sys/queue.h> | 51 | #include <sys/queue.h> | |
52 | #include <sys/rwlock.h> | 52 | #include <sys/rwlock.h> | |
53 | #include <sys/types.h> | 53 | #include <sys/types.h> | |
54 | 54 | |||
55 | #include <net/if.h> | 55 | #include <net/if.h> | |
@@ -220,26 +220,27 @@ npf_rule_alloc(int attr, pri_t pri, int | @@ -220,26 +220,27 @@ npf_rule_alloc(int attr, pri_t pri, int | |||
220 | return NULL; | 220 | return NULL; | |
221 | } | 221 | } | |
222 | TAILQ_INIT(&rl->r_subset.rs_queue); | 222 | TAILQ_INIT(&rl->r_subset.rs_queue); | |
223 | LIST_INIT(&rl->r_hooks); | 223 | LIST_INIT(&rl->r_hooks); | |
224 | rl->r_priority = pri; | 224 | rl->r_priority = pri; | |
225 | rl->r_attr = attr; | 225 | rl->r_attr = attr; | |
226 | rl->r_ifid = ifidx; | 226 | rl->r_ifid = ifidx; | |
227 | rl->r_ncode = nc; | 227 | rl->r_ncode = nc; | |
228 | rl->r_nc_size = sz; | 228 | rl->r_nc_size = sz; | |
229 | rl->r_hitcount = 0; | 229 | rl->r_hitcount = 0; | |
230 | rl->r_nat = NULL; | 230 | rl->r_nat = NULL; | |
231 | return rl; | 231 | return rl; | |
232 | } | 232 | } | |
233 | ||||
233 | #if 0 | 234 | #if 0 | |
234 | /* | 235 | /* | |
235 | * npf_activate_rule: activate rule by inserting it into the global ruleset. | 236 | * npf_activate_rule: activate rule by inserting it into the global ruleset. | |
236 | */ | 237 | */ | |
237 | void | 238 | void | |
238 | npf_activate_rule(npf_rule_t *rl) | 239 | npf_activate_rule(npf_rule_t *rl) | |
239 | { | 240 | { | |
240 | 241 | |||
241 | rw_enter(&ruleset_lock, RW_WRITER); | 242 | rw_enter(&ruleset_lock, RW_WRITER); | |
242 | npf_ruleset_insert(ruleset, rl); | 243 | npf_ruleset_insert(ruleset, rl); | |
243 | rw_exit(&ruleset_lock); | 244 | rw_exit(&ruleset_lock); | |
244 | } | 245 | } | |
245 | 246 | |||
@@ -324,144 +325,146 @@ npf_hook_register(npf_rule_t *rl, | @@ -324,144 +325,146 @@ npf_hook_register(npf_rule_t *rl, | |||
324 | * => Hook should have been registered in the rule. | 325 | * => Hook should have been registered in the rule. | |
325 | */ | 326 | */ | |
326 | void | 327 | void | |
327 | npf_hook_unregister(npf_rule_t *rl, npf_hook_t *hk) | 328 | npf_hook_unregister(npf_rule_t *rl, npf_hook_t *hk) | |
328 | { | 329 | { | |
329 | 330 | |||
330 | rw_enter(&ruleset_lock, RW_WRITER); | 331 | rw_enter(&ruleset_lock, RW_WRITER); | |
331 | LIST_REMOVE(hk, hk_entry); | 332 | LIST_REMOVE(hk, hk_entry); | |
332 | rw_exit(&ruleset_lock); | 333 | rw_exit(&ruleset_lock); | |
333 | kmem_free(hk, sizeof(npf_hook_t)); | 334 | kmem_free(hk, sizeof(npf_hook_t)); | |
334 | } | 335 | } | |
335 | 336 | |||
336 | /* | 337 | /* | |
337 | * npf_ruleset_match: inspect the packet against the ruleset. | 338 | * npf_ruleset_match: inspect the packet against the given ruleset. | |
338 | * | |||
339 | * Loop for each rule in the set and perform run n-code processor of each | |||
340 | * rule against the packet (nbuf chain). If sub-ruleset found, inspect it. | |||
341 | * | 339 | * | |
342 | * => If found, ruleset is kept read-locked. | 340 | * Loop for each rule in the set and run n-code processor of each rule | |
343 | * => Caller should protect the nbuf chain. | 341 | * against the packet (nbuf chain). | |
344 | */ | 342 | */ | |
345 | npf_rule_t * | 343 | npf_rule_t * | |
346 | npf_ruleset_match(npf_ruleset_t *rlset0, npf_cache_t *npc, nbuf_t *nbuf, | 344 | npf_ruleset_match(npf_ruleset_t *rlset, npf_cache_t *npc, nbuf_t *nbuf, | |
347 | struct ifnet *ifp, const int di, const int layer) | 345 | struct ifnet *ifp, const int di, const int layer) | |
348 | { | 346 | { | |
349 | npf_rule_t *final_rl = NULL, *rl; | 347 | npf_rule_t *final_rl = NULL, *rl; | |
350 | npf_ruleset_t *rlset = rlset0; | |||
351 | 348 | |||
352 | KASSERT(((di & PFIL_IN) != 0) ^ ((di & PFIL_OUT) != 0)); | 349 | KASSERT(((di & PFIL_IN) != 0) ^ ((di & PFIL_OUT) != 0)); | |
353 | reinspect: | 350 | ||
354 | TAILQ_FOREACH(rl, &rlset->rs_queue, r_entry) { | 351 | TAILQ_FOREACH(rl, &rlset->rs_queue, r_entry) { | |
355 | KASSERT(!final_rl || rl->r_priority >= final_rl->r_priority); | 352 | KASSERT(!final_rl || rl->r_priority >= final_rl->r_priority); | |
356 | 353 | |||
357 | /* Match the interface. */ | 354 | /* Match the interface. */ | |
358 | if (rl->r_ifid && rl->r_ifid != ifp->if_index) { | 355 | if (rl->r_ifid && rl->r_ifid != ifp->if_index) { | |
359 | continue; | 356 | continue; | |
360 | } | 357 | } | |
361 | /* Match the direction. */ | 358 | /* Match the direction. */ | |
362 | if ((rl->r_attr & NPF_RULE_DIMASK) != NPF_RULE_DIMASK) { | 359 | if ((rl->r_attr & NPF_RULE_DIMASK) != NPF_RULE_DIMASK) { | |
363 | const int di_mask = | 360 | const int di_mask = | |
364 | (di & PFIL_IN) ? NPF_RULE_IN : NPF_RULE_OUT; | 361 | (di & PFIL_IN) ? NPF_RULE_IN : NPF_RULE_OUT; | |
365 | 362 | |||
366 | if ((rl->r_attr & di_mask) == 0) | 363 | if ((rl->r_attr & di_mask) == 0) | |
367 | continue; | 364 | continue; | |
368 | } | 365 | } | |
369 | /* Process the n-code, if any. */ | 366 | /* Process the n-code, if any. */ | |
370 | const void *nc = rl->r_ncode; | 367 | const void *nc = rl->r_ncode; | |
371 | if (nc && npf_ncode_process(npc, nc, nbuf, layer)) { | 368 | if (nc && npf_ncode_process(npc, nc, nbuf, layer)) { | |
372 | continue; | 369 | continue; | |
373 | } | 370 | } | |
374 | /* Set the matching rule and check for "final". */ | 371 | /* Set the matching rule and check for "final". */ | |
375 | final_rl = rl; | 372 | final_rl = rl; | |
376 | if (rl->r_attr & NPF_RULE_FINAL) { | 373 | if (rl->r_attr & NPF_RULE_FINAL) { | |
377 | goto final; | 374 | break; | |
378 | } | |||
379 | } | |||
380 | /* Default, if no final rule. */ | |||
381 | if (final_rl == NULL) { | |||
382 | rlset = rlset0; | |||
383 | final_rl = rlset->rs_default; | |||
384 | } | |||
385 | /* Inspect the sub-ruleset, if any. */ | |||
386 | if (final_rl) { | |||
387 | final: | |||
388 | if (TAILQ_EMPTY(&final_rl->r_subset.rs_queue)) { | |||
389 | return final_rl; | |||
390 | } | 375 | } | |
391 | rlset = &final_rl->r_subset; | |||
392 | final_rl = NULL; | |||
393 | goto reinspect; | |||
394 | } | 376 | } | |
395 | return final_rl; | 377 | return final_rl; | |
396 | } | 378 | } | |
397 | 379 | |||
398 | /* | 380 | /* | |
399 | * npf_ruleset_inspect: inspection of the main ruleset for filtering. | 381 | * npf_ruleset_inspect: inspection of the main ruleset for filtering. | |
382 | * If sub-ruleset is found, inspect it. | |||
383 | * | |||
384 | * => If found, ruleset is kept read-locked. | |||
385 | * => Caller should protect the nbuf chain. | |||
400 | */ | 386 | */ | |
401 | npf_rule_t * | 387 | npf_rule_t * | |
402 | npf_ruleset_inspect(npf_cache_t *npc, nbuf_t *nbuf, | 388 | npf_ruleset_inspect(npf_cache_t *npc, nbuf_t *nbuf, | |
403 | struct ifnet *ifp, const int di, const int layer) | 389 | struct ifnet *ifp, const int di, const int layer) | |
404 | { | 390 | { | |
391 | npf_ruleset_t *rlset = ruleset; | |||
405 | npf_rule_t *rl; | 392 | npf_rule_t *rl; | |
393 | bool defed; | |||
406 | 394 | |||
395 | defed = false; | |||
407 | rw_enter(&ruleset_lock, RW_READER); | 396 | rw_enter(&ruleset_lock, RW_READER); | |
408 | rl = npf_ruleset_match(ruleset, npc, nbuf, ifp, di, layer); | 397 | reinspect: | |
398 | rl = npf_ruleset_match(rlset, npc, nbuf, ifp, di, layer); | |||
399 | ||||
400 | /* If no final rule, then - default. */ | |||
401 | if (rl == NULL && !defed) { | |||
402 | rl = ruleset->rs_default; | |||
403 | defed = true; | |||
404 | } | |||
405 | /* Inspect the sub-ruleset, if any. */ | |||
406 | if (rl && !TAILQ_EMPTY(&rl->r_subset.rs_queue)) { | |||
407 | rlset = &rl->r_subset; | |||
408 | goto reinspect; | |||
409 | } | |||
409 | if (rl == NULL) { | 410 | if (rl == NULL) { | |
410 | rw_exit(&ruleset_lock); | 411 | rw_exit(&ruleset_lock); | |
411 | } | 412 | } | |
412 | return rl; | 413 | return rl; | |
413 | } | 414 | } | |
414 | 415 | |||
415 | /* | 416 | /* | |
416 | * npf_rule_apply: apply the rule i.e. run hooks and return appropriate value. | 417 | * npf_rule_apply: apply the rule i.e. run hooks and return appropriate value. | |
417 | * | 418 | * | |
418 | * => Returns ENETUNREACH if "block" and 0 if "pass". | 419 | * => Returns ENETUNREACH if "block" and 0 if "pass". | |
419 | * => Releases the ruleset lock. | 420 | * => Releases the ruleset lock. | |
420 | */ | 421 | */ | |
421 | int | 422 | int | |
422 | npf_rule_apply(const npf_cache_t *npc, npf_rule_t *rl, bool *keepstate) | 423 | npf_rule_apply(const npf_cache_t *npc, npf_rule_t *rl, | |
424 | bool *keepstate, int *retfl) | |||
423 | { | 425 | { | |
424 | npf_hook_t *hk; | 426 | npf_hook_t *hk; | |
425 | 427 | |||
426 | KASSERT(rw_lock_held(&ruleset_lock)); | 428 | KASSERT(rw_lock_held(&ruleset_lock)); | |
427 | 429 | |||
428 | /* Update the "hit" counter. */ | 430 | /* Update the "hit" counter. */ | |
429 | if (rl->r_attr & NPF_RULE_COUNT) { | 431 | if (rl->r_attr & NPF_RULE_COUNT) { | |
430 | atomic_inc_ulong(&rl->r_hitcount); | 432 | atomic_inc_ulong(&rl->r_hitcount); | |
431 | } | 433 | } | |
432 | 434 | |||
433 | /* If not passing - drop the packet. */ | 435 | /* If not passing - drop the packet. */ | |
434 | if ((rl->r_attr & NPF_RULE_PASS) == 0) { | 436 | if ((rl->r_attr & NPF_RULE_PASS) == 0) { | |
437 | /* Determine whether any return message is needed. */ | |||
438 | *retfl = rl->r_attr & (NPF_RULE_RETRST | NPF_RULE_RETICMP); | |||
435 | rw_exit(&ruleset_lock); | 439 | rw_exit(&ruleset_lock); | |
436 | return ENETUNREACH; | 440 | return ENETUNREACH; | |
437 | } | 441 | } | |
438 | 442 | |||
439 | /* Passing. Run the hooks. */ | 443 | /* Passing. Run the hooks. */ | |
440 | LIST_FOREACH(hk, &rl->r_hooks, hk_entry) { | 444 | LIST_FOREACH(hk, &rl->r_hooks, hk_entry) { | |
441 | KASSERT(hk->hk_fn != NULL); | 445 | KASSERT(hk->hk_fn != NULL); | |
442 | (*hk->hk_fn)(npc, hk->hk_arg); | 446 | (*hk->hk_fn)(npc, hk->hk_arg); | |
443 | } | 447 | } | |
444 | *keepstate = (rl->r_attr & NPF_RULE_KEEPSTATE) != 0; | 448 | *keepstate = (rl->r_attr & NPF_RULE_KEEPSTATE) != 0; | |
445 | rw_exit(&ruleset_lock); | 449 | rw_exit(&ruleset_lock); | |
446 | 450 | |||
447 | return 0; | 451 | return 0; | |
448 | } | 452 | } | |
449 | 453 | |||
450 | #if defined(DDB) || defined(_NPF_TESTING) | 454 | #if defined(DDB) || defined(_NPF_TESTING) | |
451 | 455 | |||
452 | void | 456 | void | |
453 | npf_rulenc_dump(npf_rule_t *rl) | 457 | npf_rulenc_dump(npf_rule_t *rl) | |
454 | { | 458 | { | |
455 | uint32_t *op = rl->r_ncode; | 459 | uint32_t *op = rl->r_ncode; | |
456 | size_t n = rl->r_nc_size; | 460 | size_t n = rl->r_nc_size; | |
457 | 461 | |||
458 | do { | 462 | while (n) { | |
459 | printf("\t> |0x%02x|\n", (uint32_t)*op); | 463 | printf("\t> |0x%02x|\n", (uint32_t)*op); | |
460 | op++; | 464 | op++; | |
461 | n -= sizeof(*op); | 465 | n -= sizeof(*op); | |
462 | } while (n); | 466 | } | |
463 | ||||
464 | printf("-> %s\n", (rl->r_attr & NPF_RULE_PASS) ? "pass" : "block"); | 467 | printf("-> %s\n", (rl->r_attr & NPF_RULE_PASS) ? "pass" : "block"); | |
465 | } | 468 | } | |
466 | 469 | |||
467 | #endif | 470 | #endif |
--- src/sys/net/npf/Attic/npf_session.c 2010/08/22 18:56:22 1.1
+++ src/sys/net/npf/Attic/npf_session.c 2010/09/16 04:53:27 1.2
@@ -1,14 +1,14 @@ | @@ -1,14 +1,14 @@ | |||
1 | /* $NetBSD: npf_session.c,v 1.1 2010/08/22 18:56:22 rmind Exp $ */ | 1 | /* $NetBSD: npf_session.c,v 1.2 2010/09/16 04:53:27 rmind Exp $ */ | |
2 | 2 | |||
3 | /*- | 3 | /*- | |
4 | * Copyright (c) 2010 The NetBSD Foundation, Inc. | 4 | * Copyright (c) 2010 The NetBSD Foundation, Inc. | |
5 | * All rights reserved. | 5 | * All rights reserved. | |
6 | * | 6 | * | |
7 | * This material is based upon work partially supported by The | 7 | * This material is based upon work partially supported by The | |
8 | * NetBSD Foundation under a contract with Mindaugas Rasiukevicius. | 8 | * NetBSD Foundation under a contract with Mindaugas Rasiukevicius. | |
9 | * | 9 | * | |
10 | * Redistribution and use in source and binary forms, with or without | 10 | * Redistribution and use in source and binary forms, with or without | |
11 | * modification, are permitted provided that the following conditions | 11 | * modification, are permitted provided that the following conditions | |
12 | * are met: | 12 | * are met: | |
13 | * 1. Redistributions of source code must retain the above copyright | 13 | * 1. Redistributions of source code must retain the above copyright | |
14 | * notice, this list of conditions and the following disclaimer. | 14 | * notice, this list of conditions and the following disclaimer. | |
@@ -24,26 +24,31 @@ | @@ -24,26 +24,31 @@ | |||
24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | 24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | |
25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | 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 | 26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | |
27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | 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 | 28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |
29 | * POSSIBILITY OF SUCH DAMAGE. | 29 | * POSSIBILITY OF SUCH DAMAGE. | |
30 | */ | 30 | */ | |
31 | 31 | |||
32 | /* | 32 | /* | |
33 | * NPF session tracking for stateful filtering and translation. | 33 | * NPF session tracking for stateful filtering and translation. | |
34 | * | 34 | * | |
35 | * Overview | 35 | * Overview | |
36 | * | 36 | * | |
37 | * Session direction is identified by the direction of its first packet. | |||
38 | * Packets can be incoming or outgoing with respect to an interface. | |||
39 | * To describe the packet in the context of session direction, we will | |||
40 | * use the terms "forwards stream" and "backwards stream". | |||
41 | * | |||
37 | * There are two types of sessions: "pass" and "NAT". The former are | 42 | * There are two types of sessions: "pass" and "NAT". The former are | |
38 | * sessions created according to the rules with "keep state" attribute | 43 | * sessions created according to the rules with "keep state" attribute | |
39 | * and are used for stateful filtering. Such sessions indicate that | 44 | * and are used for stateful filtering. Such sessions indicate that | |
40 | * packet of the "backwards" stream should be passed without inspection | 45 | * packet of the "backwards" stream should be passed without inspection | |
41 | * of the ruleset. | 46 | * of the ruleset. | |
42 | * | 47 | * | |
43 | * NAT sessions are created according to the NAT policies. Since they | 48 | * NAT sessions are created according to the NAT policies. Since they | |
44 | * are used to perform translation, such sessions have 1:1 relationship | 49 | * are used to perform translation, such sessions have 1:1 relationship | |
45 | * with NAT translation structure via npf_session_t::s_nat. Therefore, | 50 | * with NAT translation structure via npf_session_t::s_nat. Therefore, | |
46 | * non-NULL value of npf_session_t::s_nat indicates this session type. | 51 | * non-NULL value of npf_session_t::s_nat indicates this session type. | |
47 | * | 52 | * | |
48 | * Session life-cycle | 53 | * Session life-cycle | |
49 | * | 54 | * | |
@@ -70,64 +75,61 @@ | @@ -70,64 +75,61 @@ | |||
70 | * External session identifiers | 75 | * External session identifiers | |
71 | * | 76 | * | |
72 | * Application-level gateways (ALGs) can inspect the packet and fill | 77 | * Application-level gateways (ALGs) can inspect the packet and fill | |
73 | * the packet cache (npf_cache_t) representing the IDs. It is done | 78 | * the packet cache (npf_cache_t) representing the IDs. It is done | |
74 | * via npf_alg_sessionid() call. In such case, ALGs are responsible | 79 | * via npf_alg_sessionid() call. In such case, ALGs are responsible | |
75 | * for correct filling of protocol, addresses and ports/IDs. | 80 | * for correct filling of protocol, addresses and ports/IDs. | |
76 | * | 81 | * | |
77 | * TODO: | 82 | * TODO: | |
78 | * - Session monitoring via descriptor. | 83 | * - Session monitoring via descriptor. | |
79 | */ | 84 | */ | |
80 | 85 | |||
81 | #ifdef _KERNEL | 86 | #ifdef _KERNEL | |
82 | #include <sys/cdefs.h> | 87 | #include <sys/cdefs.h> | |
83 | __KERNEL_RCSID(0, "$NetBSD: npf_session.c,v 1.1 2010/08/22 18:56:22 rmind Exp $"); | 88 | __KERNEL_RCSID(0, "$NetBSD: npf_session.c,v 1.2 2010/09/16 04:53:27 rmind Exp $"); | |
84 | 89 | |||
85 | #include <sys/param.h> | 90 | #include <sys/param.h> | |
86 | #include <sys/kernel.h> | 91 | #include <sys/kernel.h> | |
87 | 92 | |||
88 | #include <netinet/in.h> | 93 | #include <netinet/in.h> | |
89 | #include <netinet/tcp.h> | 94 | #include <netinet/tcp.h> | |
90 | #endif | 95 | #endif | |
91 | #include <sys/atomic.h> | 96 | #include <sys/atomic.h> | |
92 | #include <sys/condvar.h> | 97 | #include <sys/condvar.h> | |
93 | #include <sys/hash.h> | 98 | #include <sys/hash.h> | |
94 | #include <sys/kmem.h> | 99 | #include <sys/kmem.h> | |
95 | #include <sys/kthread.h> | 100 | #include <sys/kthread.h> | |
96 | #include <sys/mutex.h> | 101 | #include <sys/mutex.h> | |
97 | #include <net/pfil.h> | 102 | #include <net/pfil.h> | |
98 | #include <sys/pool.h> | 103 | #include <sys/pool.h> | |
99 | #include <sys/rwlock.h> | 104 | #include <sys/rwlock.h> | |
100 | #include <sys/queue.h> | 105 | #include <sys/queue.h> | |
101 | #include <sys/systm.h> | 106 | #include <sys/systm.h> | |
102 | #include <sys/types.h> | 107 | #include <sys/types.h> | |
103 | 108 | |||
104 | #include "npf_impl.h" | 109 | #include "npf_impl.h" | |
105 | 110 | |||
106 | #define NPF_SESSION_TCP 1 | |||
107 | #define NPF_SESSION_UDP 2 | |||
108 | #define NPF_SESSION_ICMP 3 | |||
109 | ||||
110 | struct npf_session { | 111 | struct npf_session { | |
111 | /* Session node / list entry and reference count. */ | 112 | /* Session node / list entry and reference count. */ | |
112 | union { | 113 | union { | |
113 | struct rb_node rbnode; | 114 | struct rb_node rbnode; | |
114 | LIST_ENTRY(npf_session) gclist; | 115 | LIST_ENTRY(npf_session) gclist; | |
115 | } se_entry; | 116 | } se_entry; | |
116 | u_int s_refcnt; | 117 | u_int s_refcnt; | |
117 | /* Session type. Supported: TCP, UDP, ICMP. */ | 118 | /* Session type. Supported: TCP, UDP, ICMP. */ | |
118 | int s_type; | 119 | int s_type; | |
119 | int s_direction; | 120 | int s_direction; | |
120 | int s_state; | 121 | uint16_t s_state; | |
122 | uint16_t s_flags; | |||
121 | /* NAT data associated with this session (if any). */ | 123 | /* NAT data associated with this session (if any). */ | |
122 | npf_nat_t * s_nat; | 124 | npf_nat_t * s_nat; | |
123 | npf_session_t * s_nat_se; | 125 | npf_session_t * s_nat_se; | |
124 | /* Source and destination addresses. */ | 126 | /* Source and destination addresses. */ | |
125 | in_addr_t s_src_addr; | 127 | in_addr_t s_src_addr; | |
126 | in_addr_t s_dst_addr; | 128 | in_addr_t s_dst_addr; | |
127 | /* Source and destination ports (TCP / UDP) or generic IDs. */ | 129 | /* Source and destination ports (TCP / UDP) or generic IDs. */ | |
128 | union { | 130 | union { | |
129 | in_port_t port; | 131 | in_port_t port; | |
130 | uint32_t id; | 132 | uint32_t id; | |
131 | } s_src; | 133 | } s_src; | |
132 | union { | 134 | union { | |
133 | in_port_t port; | 135 | in_port_t port; | |
@@ -142,55 +144,57 @@ struct npf_session { | @@ -142,55 +144,57 @@ struct npf_session { | |||
142 | (npf_session_t *)((uintptr_t)n - offsetof(npf_session_t, se_entry.rbnode)) | 144 | (npf_session_t *)((uintptr_t)n - offsetof(npf_session_t, se_entry.rbnode)) | |
143 | 145 | |||
144 | LIST_HEAD(npf_sesslist, npf_session); | 146 | LIST_HEAD(npf_sesslist, npf_session); | |
145 | 147 | |||
146 | #define SESS_HASH_BUCKETS 1024 /* XXX tune + make tunable */ | 148 | #define SESS_HASH_BUCKETS 1024 /* XXX tune + make tunable */ | |
147 | #define SESS_HASH_MASK (SESS_HASH_BUCKETS - 1) | 149 | #define SESS_HASH_MASK (SESS_HASH_BUCKETS - 1) | |
148 | 150 | |||
149 | typedef struct { | 151 | typedef struct { | |
150 | struct rb_tree sh_tree; | 152 | struct rb_tree sh_tree; | |
151 | krwlock_t sh_lock; | 153 | krwlock_t sh_lock; | |
152 | u_int sh_count; | 154 | u_int sh_count; | |
153 | } npf_sess_hash_t; | 155 | } npf_sess_hash_t; | |
154 | 156 | |||
155 | /* XXX: give a separate cache-line to these. */ | 157 | static int sess_tracking __cacheline_aligned; | |
156 | static int sess_tracking; | |||
157 | 158 | |||
158 | /* Session hash table, lock and session cache. */ | 159 | /* Session hash table, lock and session cache. */ | |
159 | static npf_sess_hash_t * sess_hashtbl; | 160 | static npf_sess_hash_t * sess_hashtbl __read_mostly; | |
160 | static pool_cache_t sess_cache; | 161 | static pool_cache_t sess_cache __read_mostly; | |
161 | 162 | |||
162 | static kmutex_t sess_lock; | 163 | static kmutex_t sess_lock; | |
163 | static kcondvar_t sess_cv; | 164 | static kcondvar_t sess_cv; | |
164 | static lwp_t * sess_gc_lwp; | 165 | static lwp_t * sess_gc_lwp; | |
165 | 166 | |||
166 | #define SESS_GC_INTERVAL 5 /* 5 sec */ | 167 | #define SESS_GC_INTERVAL 5 /* 5 sec */ | |
167 | 168 | |||
168 | /* Session expiration table. XXX: TCP close: 2 * tcp_msl (e.g. 120)? Maybe. */ | 169 | /* Session expiration table. XXX: TCP close: 2 * tcp_msl (e.g. 120)? Maybe. */ | |
169 | static const u_int sess_expire_table[ ] = { | 170 | static const u_int sess_expire_table[ ] = { | |
170 | [NPF_SESSION_TCP] = 600, /* 10 min */ | 171 | [IPPROTO_TCP] = 600, /* 10 min */ | |
171 | [NPF_SESSION_UDP] = 300, /* 5 min */ | 172 | [IPPROTO_UDP] = 300, /* 5 min */ | |
172 | [NPF_SESSION_ICMP] = 30 /* 1 min */ | 173 | [IPPROTO_ICMP] = 30 /* 1 min */ | |
173 | }; | 174 | }; | |
174 | 175 | |||
176 | /* Session states and flags. */ | |||
175 | #define SE_OPENING 1 | 177 | #define SE_OPENING 1 | |
176 | #define SE_OPENING2 2 | 178 | #define SE_ACKNOWLEDGE 2 | |
177 | #define SE_ESTABLISHED 3 | 179 | #define SE_ESTABLISHED 3 | |
178 | #define SE_CLOSING 4 | 180 | #define SE_CLOSING 4 | |
179 | 181 | |||
182 | #define SE_PASSSING 0x01 | |||
183 | ||||
180 | static void sess_tracking_stop(void); | 184 | static void sess_tracking_stop(void); | |
181 | static void npf_session_worker(void *); | 185 | static void npf_session_worker(void *); | |
182 | 186 | |||
183 | #ifdef DEBUG | 187 | #ifdef SE_DEBUG | |
184 | #define DPRINTF(x) printf x | 188 | #define DPRINTF(x) printf x | |
185 | #else | 189 | #else | |
186 | #define DPRINTF(x) | 190 | #define DPRINTF(x) | |
187 | #endif | 191 | #endif | |
188 | 192 | |||
189 | /* | 193 | /* | |
190 | * npf_session_sys{init,fini}: initialise/destroy session handling structures. | 194 | * npf_session_sys{init,fini}: initialise/destroy session handling structures. | |
191 | * | 195 | * | |
192 | * Session table and G/C thread are initialised when session tracking gets | 196 | * Session table and G/C thread are initialised when session tracking gets | |
193 | * actually enabled via npf_session_tracking() interface. | 197 | * actually enabled via npf_session_tracking() interface. | |
194 | */ | 198 | */ | |
195 | 199 | |||
196 | int | 200 | int | |
@@ -211,129 +215,159 @@ npf_session_sysfini(void) | @@ -211,129 +215,159 @@ npf_session_sysfini(void) | |||
211 | 215 | |||
212 | /* Disable tracking to destroy all structures. */ | 216 | /* Disable tracking to destroy all structures. */ | |
213 | error = npf_session_tracking(false); | 217 | error = npf_session_tracking(false); | |
214 | KASSERT(error == 0); | 218 | KASSERT(error == 0); | |
215 | KASSERT(sess_tracking == 0); | 219 | KASSERT(sess_tracking == 0); | |
216 | KASSERT(sess_gc_lwp == NULL); | 220 | KASSERT(sess_gc_lwp == NULL); | |
217 | 221 | |||
218 | cv_destroy(&sess_cv); | 222 | cv_destroy(&sess_cv); | |
219 | mutex_destroy(&sess_lock); | 223 | mutex_destroy(&sess_lock); | |
220 | } | 224 | } | |
221 | 225 | |||
222 | /* | 226 | /* | |
223 | * Session hash table and RB-tree helper routines. | 227 | * Session hash table and RB-tree helper routines. | |
224 | * Order: (node1, node2) where (node1 < node2). | 228 | * Order: (src.id, dst.id, src.addr, dst.addr), where (node1 < node2). | |
225 | */ | 229 | */ | |
226 | 230 | |||
227 | static signed int | 231 | static signed int | |
228 | sess_rbtree_cmp_nodes(const struct rb_node *n1, const struct rb_node *n2) | 232 | sess_rbtree_cmp_nodes(const struct rb_node *n1, const struct rb_node *n2) | |
229 | { | 233 | { | |
230 | const npf_session_t *se1 = NPF_RBN2SESENT(n1); | 234 | const npf_session_t * const se1 = NPF_RBN2SESENT(n1); | |
231 | const npf_session_t *se2 = NPF_RBN2SESENT(n2); | 235 | const npf_session_t * const se2 = NPF_RBN2SESENT(n2); | |
232 | ||||
233 | if (se1->s_src.id < se2->s_src.id || se1->s_dst.id < se2->s_dst.id) | |||
234 | return 1; | |||
235 | if (se1->s_src.id > se2->s_src.id || se1->s_dst.id > se2->s_dst.id) | |||
236 | return -1; | |||
237 | ||||
238 | if (se1->s_src_addr < se2->s_src_addr || | |||
239 | se1->s_dst_addr < se2->s_dst_addr) | |||
240 | return -1; | |||
241 | if (se1->s_src_addr > se2->s_src_addr || | |||
242 | se1->s_dst_addr > se2->s_dst_addr) | |||
243 | return 1; | |||
244 | 236 | |||
237 | /* | |||
238 | * Note: must compare equivalent streams. | |||
239 | * See sess_rbtree_cmp_key() below. | |||
240 | */ | |||
241 | if (se1->s_direction == se2->s_direction) { | |||
242 | /* | |||
243 | * Direction "forwards". | |||
244 | */ | |||
245 | if (se1->s_src.id != se2->s_src.id) | |||
246 | return (se1->s_src.id < se2->s_src.id) ? -1 : 1; | |||
247 | if (se1->s_dst.id != se2->s_dst.id) | |||
248 | return (se1->s_dst.id < se2->s_dst.id) ? -1 : 1; | |||
249 | ||||
250 | if (__predict_false(se1->s_src_addr != se2->s_src_addr)) | |||
251 | return (se1->s_src_addr < se2->s_src_addr) ? -1 : 1; | |||
252 | if (__predict_false(se1->s_dst_addr != se2->s_dst_addr)) | |||
253 | return (se1->s_dst_addr < se2->s_dst_addr) ? -1 : 1; | |||
254 | } else { | |||
255 | /* | |||
256 | * Direction "backwards". | |||
257 | */ | |||
258 | if (se1->s_src.id != se2->s_dst.id) | |||
259 | return (se1->s_src.id < se2->s_dst.id) ? -1 : 1; | |||
260 | if (se1->s_dst.id != se2->s_src.id) | |||
261 | return (se1->s_dst.id < se2->s_src.id) ? -1 : 1; | |||
262 | ||||
263 | if (__predict_false(se1->s_src_addr != se2->s_dst_addr)) | |||
264 | return (se1->s_src_addr < se2->s_dst_addr) ? -1 : 1; | |||
265 | if (__predict_false(se1->s_dst_addr != se2->s_src_addr)) | |||
266 | return (se1->s_dst_addr < se2->s_src_addr) ? -1 : 1; | |||
267 | } | |||
245 | return 0; | 268 | return 0; | |
246 | } | 269 | } | |
247 | 270 | |||
248 | static signed int | 271 | static signed int | |
249 | sess_rbtree_cmp_key(const struct rb_node *n1, const void *key) | 272 | sess_rbtree_cmp_key(const struct rb_node *n1, const void *key) | |
250 | { | 273 | { | |
251 | const npf_session_t *se = NPF_RBN2SESENT(n1); | 274 | const npf_session_t * const se = NPF_RBN2SESENT(n1); | |
252 | const npf_cache_t *npc = key; | 275 | const npf_cache_t * const npc = key; | |
253 | in_port_t sport, dport; | 276 | in_port_t sport, dport; | |
254 | in_addr_t src, dst; | 277 | in_addr_t src, dst; | |
255 | 278 | |||
256 | if (se->s_direction == npc->npc_dir) { | 279 | if (se->s_direction == npc->npc_dir) { | |
257 | /* Direction "forwards". */ | 280 | /* Direction "forwards". */ | |
258 | src = npc->npc_srcip; sport = npc->npc_sport; | 281 | src = npc->npc_srcip; sport = npc->npc_sport; | |
259 | dst = npc->npc_dstip; dport = npc->npc_dport; | 282 | dst = npc->npc_dstip; dport = npc->npc_dport; | |
260 | } else { | 283 | } else { | |
261 | /* Direction "backwards". */ | 284 | /* Direction "backwards". */ | |
262 | src = npc->npc_dstip; sport = npc->npc_dport; | 285 | src = npc->npc_dstip; sport = npc->npc_dport; | |
263 | dst = npc->npc_srcip; dport = npc->npc_sport; | 286 | dst = npc->npc_srcip; dport = npc->npc_sport; | |
264 | } | 287 | } | |
265 | 288 | |||
266 | /* Ports are the main criteria and are first. */ | 289 | /* Ports are the main criteria and are first. */ | |
267 | if (se->s_src.id < sport || se->s_dst.id < dport) | 290 | if (se->s_src.id != sport) | |
268 | return 1; | 291 | return (se->s_src.id < sport) ? -1 : 1; | |
269 | if (se->s_src.id > sport || se->s_dst.id > dport) | 292 | ||
270 | return -1; | 293 | if (se->s_dst.id != dport) | |
294 | return (se->s_dst.id < dport) ? -1 : 1; | |||
271 | 295 | |||
272 | /* Note that hash should minimise differentiation on these. */ | 296 | /* Note that hash should minimise differentiation on these. */ | |
273 | if (__predict_false(se->s_src_addr < src || se->s_dst_addr < dst)) | 297 | if (__predict_false(se->s_src_addr != src)) | |
274 | return 1; | 298 | return (se->s_src_addr < src) ? -1 : 1; | |
275 | if (__predict_false(se->s_src_addr > src || se->s_dst_addr > dst)) | 299 | if (__predict_false(se->s_dst_addr < dst)) | |
276 | return -1; | 300 | return (se->s_dst_addr < dst) ? -1 : 1; | |
277 | 301 | |||
278 | return 0; | 302 | return 0; | |
279 | } | 303 | } | |
280 | 304 | |||
281 | static const struct rb_tree_ops sess_rbtree_ops = { | 305 | static const struct rb_tree_ops sess_rbtree_ops = { | |
282 | .rbto_compare_nodes = sess_rbtree_cmp_nodes, | 306 | .rbto_compare_nodes = sess_rbtree_cmp_nodes, | |
283 | .rbto_compare_key = sess_rbtree_cmp_key | 307 | .rbto_compare_key = sess_rbtree_cmp_key | |
284 | }; | 308 | }; | |
285 | 309 | |||
286 | static inline npf_sess_hash_t * | 310 | static inline npf_sess_hash_t * | |
287 | sess_hash_bucket(const npf_cache_t *key) | 311 | sess_hash_bucket(const npf_cache_t *key) | |
288 | { | 312 | { | |
289 | uint32_t hash, mix; | 313 | uint32_t hash, mix; | |
290 | 314 | |||
291 | KASSERT(npf_iscached(key, NPC_IP46 | NPC_ADDRS)); | 315 | KASSERT(npf_iscached(key, NPC_IP46 | NPC_ADDRS)); | |
292 | 316 | |||
293 | /* Sum addresses for both directions and mix in protocol. */ | 317 | /* Sum addresses for both directions and mix in protocol. */ | |
294 | mix = key->npc_srcip + key->npc_dstip + key->npc_proto; | 318 | mix = key->npc_srcip + key->npc_dstip + key->npc_proto; | |
295 | hash = hash32_buf(&mix, sizeof(uint32_t), HASH32_BUF_INIT); | 319 | hash = hash32_buf(&mix, sizeof(uint32_t), HASH32_BUF_INIT); | |
296 | return &sess_hashtbl[hash & SESS_HASH_MASK]; | 320 | return &sess_hashtbl[hash & SESS_HASH_MASK]; | |
297 | } | 321 | } | |
298 | 322 | |||
323 | static npf_sess_hash_t * | |||
324 | sess_hash_construct(void) | |||
325 | { | |||
326 | npf_sess_hash_t *ht, *sh; | |||
327 | u_int i; | |||
328 | ||||
329 | ht = kmem_alloc(SESS_HASH_BUCKETS * sizeof(*sh), KM_SLEEP); | |||
330 | if (ht == NULL) { | |||
331 | return NULL; | |||
332 | } | |||
333 | for (i = 0; i < SESS_HASH_BUCKETS; i++) { | |||
334 | sh = &ht[i]; | |||
335 | rb_tree_init(&sh->sh_tree, &sess_rbtree_ops); | |||
336 | rw_init(&sh->sh_lock); | |||
337 | sh->sh_count = 0; | |||
338 | } | |||
339 | return ht; | |||
340 | } | |||
341 | ||||
299 | /* | 342 | /* | |
300 | * Session tracking routines. Note: manages tracking structures. | 343 | * Session tracking routines. Note: manages tracking structures. | |
301 | */ | 344 | */ | |
302 | 345 | |||
303 | static int | 346 | static int | |
304 | sess_tracking_start(void) | 347 | sess_tracking_start(void) | |
305 | { | 348 | { | |
306 | npf_sess_hash_t *sh; | |||
307 | u_int i; | |||
308 | 349 | |||
309 | sess_cache = pool_cache_init(sizeof(npf_session_t), coherency_unit, | 350 | sess_cache = pool_cache_init(sizeof(npf_session_t), coherency_unit, | |
310 | 0, 0, "npfsespl", NULL, IPL_NET, NULL, NULL, NULL); | 351 | 0, 0, "npfsespl", NULL, IPL_NET, NULL, NULL, NULL); | |
311 | if (sess_cache == NULL) | 352 | if (sess_cache == NULL) | |
312 | return ENOMEM; | 353 | return ENOMEM; | |
313 | 354 | |||
314 | sess_hashtbl = kmem_alloc(SESS_HASH_BUCKETS * sizeof(*sh), KM_SLEEP); | 355 | sess_hashtbl = sess_hash_construct(); | |
315 | if (sess_hashtbl == NULL) { | 356 | if (sess_hashtbl == NULL) { | |
316 | pool_cache_destroy(sess_cache); | 357 | pool_cache_destroy(sess_cache); | |
317 | return ENOMEM; | 358 | return ENOMEM; | |
318 | } | 359 | } | |
319 | 360 | |||
320 | for (i = 0; i < SESS_HASH_BUCKETS; i++) { | |||
321 | sh = &sess_hashtbl[i]; | |||
322 | rb_tree_init(&sh->sh_tree, &sess_rbtree_ops); | |||
323 | rw_init(&sh->sh_lock); | |||
324 | sh->sh_count = 0; | |||
325 | } | |||
326 | ||||
327 | /* Make it visible before thread start. */ | 361 | /* Make it visible before thread start. */ | |
328 | sess_tracking = 1; | 362 | sess_tracking = 1; | |
329 | 363 | |||
330 | if (kthread_create(PRI_NONE, KTHREAD_MPSAFE, NULL, | 364 | if (kthread_create(PRI_NONE, KTHREAD_MPSAFE, NULL, | |
331 | npf_session_worker, NULL, &sess_gc_lwp, "npfgc")) { | 365 | npf_session_worker, NULL, &sess_gc_lwp, "npfgc")) { | |
332 | sess_tracking_stop(); | 366 | sess_tracking_stop(); | |
333 | return ENOMEM; | 367 | return ENOMEM; | |
334 | } | 368 | } | |
335 | return 0; | 369 | return 0; | |
336 | } | 370 | } | |
337 | 371 | |||
338 | static void | 372 | static void | |
339 | sess_tracking_stop(void) | 373 | sess_tracking_stop(void) | |
@@ -411,60 +445,60 @@ npf_session_pstate(const npf_cache_t *np | @@ -411,60 +445,60 @@ npf_session_pstate(const npf_cache_t *np | |||
411 | } | 445 | } | |
412 | return true; | 446 | return true; | |
413 | } | 447 | } | |
414 | 448 | |||
415 | const int tcpfl = npc->npc_tcp_flags & (TH_SYN|TH_ACK|TH_RST|TH_FIN); | 449 | const int tcpfl = npc->npc_tcp_flags & (TH_SYN|TH_ACK|TH_RST|TH_FIN); | |
416 | 450 | |||
417 | switch (tcpfl) { | 451 | switch (tcpfl) { | |
418 | case TH_ACK: | 452 | case TH_ACK: | |
419 | /* Common case. */ | 453 | /* Common case. */ | |
420 | if (__predict_true(se->s_state == SE_ESTABLISHED)) { | 454 | if (__predict_true(se->s_state == SE_ESTABLISHED)) { | |
421 | return true; | 455 | return true; | |
422 | } | 456 | } | |
423 | /* ACK seen after SYN-ACK: session fully established. */ | 457 | /* ACK seen after SYN-ACK: session fully established. */ | |
424 | if (se->s_state == SE_OPENING2 && !backwards) { | 458 | if (se->s_state == SE_ACKNOWLEDGE && !backwards) { | |
425 | se->s_state = SE_ESTABLISHED; | 459 | se->s_state = SE_ESTABLISHED; | |
426 | } | 460 | } | |
427 | break; | 461 | break; | |
428 | case TH_SYN | TH_ACK: | 462 | case TH_SYN | TH_ACK: | |
429 | /* SYN-ACK seen, wait for ACK. */ | 463 | /* SYN-ACK seen, wait for ACK. */ | |
430 | if (se->s_state == SE_OPENING && backwards) { | 464 | if (se->s_state == SE_OPENING && backwards) { | |
431 | se->s_state = SE_OPENING2; | 465 | se->s_state = SE_ACKNOWLEDGE; | |
432 | } | 466 | } | |
433 | break; | 467 | break; | |
434 | case TH_RST: | 468 | case TH_RST: | |
435 | case TH_FIN: | 469 | case TH_FIN: | |
436 | /* XXX/TODO: Handle TCP reset attacks; later. */ | 470 | /* XXX/TODO: Handle TCP reset attacks; later. */ | |
437 | se->s_state = SE_CLOSING; | 471 | se->s_state = SE_CLOSING; | |
438 | break; | 472 | break; | |
439 | } | 473 | } | |
440 | return true; | 474 | return true; | |
441 | } | 475 | } | |
442 | 476 | |||
443 | /* | 477 | /* | |
444 | * npf_session_inspect: look if there is an established session (connection). | 478 | * npf_session_inspect: look if there is an established session (connection). | |
445 | * | 479 | * | |
446 | * => If found, we will hold a reference for caller. | 480 | * => If found, we will hold a reference for caller. | |
447 | */ | 481 | */ | |
448 | npf_session_t * | 482 | npf_session_t * | |
449 | npf_session_inspect(npf_cache_t *npc, nbuf_t *nbuf, | 483 | npf_session_inspect(npf_cache_t *npc, nbuf_t *nbuf, | |
450 | struct ifnet *ifp, const int di, const int layer) | 484 | struct ifnet *ifp, const int di) | |
451 | { | 485 | { | |
452 | npf_sess_hash_t *sh; | 486 | npf_sess_hash_t *sh; | |
453 | struct rb_node *nd; | 487 | struct rb_node *nd; | |
454 | npf_session_t *se; | 488 | npf_session_t *se; | |
455 | 489 | |||
456 | /* Attempt to fetch and cache all relevant IPv4 data. */ | 490 | /* Attempt to fetch and cache all relevant IPv4 data. */ | |
457 | if (!sess_tracking || !npf_cache_all_ip4(npc, nbuf, layer)) { | 491 | if (!sess_tracking || !npf_cache_all(npc, nbuf)) { | |
458 | return NULL; | 492 | return NULL; | |
459 | } | 493 | } | |
460 | KASSERT(npf_iscached(npc, NPC_IP46 | NPC_ADDRS)); | 494 | KASSERT(npf_iscached(npc, NPC_IP46 | NPC_ADDRS)); | |
461 | KASSERT(npf_iscached(npc, NPC_PORTS) || npf_iscached(npc, NPC_ICMP)); | 495 | KASSERT(npf_iscached(npc, NPC_PORTS) || npf_iscached(npc, NPC_ICMP)); | |
462 | 496 | |||
463 | /* | 497 | /* | |
464 | * Execute ALG session helpers. | 498 | * Execute ALG session helpers. | |
465 | */ | 499 | */ | |
466 | npf_cache_t algkey, *key; | 500 | npf_cache_t algkey, *key; | |
467 | 501 | |||
468 | if (npf_alg_sessionid(npc, nbuf, &algkey)) { | 502 | if (npf_alg_sessionid(npc, nbuf, &algkey)) { | |
469 | /* Unique IDs filled by ALG in a separate key cache. */ | 503 | /* Unique IDs filled by ALG in a separate key cache. */ | |
470 | key = &algkey; | 504 | key = &algkey; | |
@@ -519,50 +553,51 @@ npf_session_establish(const npf_cache_t | @@ -519,50 +553,51 @@ npf_session_establish(const npf_cache_t | |||
519 | bool ok; | 553 | bool ok; | |
520 | 554 | |||
521 | if (!sess_tracking) /* XXX */ | 555 | if (!sess_tracking) /* XXX */ | |
522 | return NULL; | 556 | return NULL; | |
523 | 557 | |||
524 | /* Allocate and initialise new state. */ | 558 | /* Allocate and initialise new state. */ | |
525 | se = pool_cache_get(sess_cache, PR_NOWAIT); | 559 | se = pool_cache_get(sess_cache, PR_NOWAIT); | |
526 | if (__predict_false(se == NULL)) { | 560 | if (__predict_false(se == NULL)) { | |
527 | return NULL; | 561 | return NULL; | |
528 | } | 562 | } | |
529 | /* Reference count and direction. */ | 563 | /* Reference count and direction. */ | |
530 | se->s_refcnt = 1; | 564 | se->s_refcnt = 1; | |
531 | se->s_direction = di; | 565 | se->s_direction = di; | |
566 | se->s_flags = 0; | |||
532 | 567 | |||
533 | /* NAT and backwards session. */ | 568 | /* NAT and backwards session. */ | |
534 | se->s_nat = nt; | 569 | se->s_nat = nt; | |
535 | se->s_nat_se = NULL; | 570 | se->s_nat_se = NULL; | |
536 | 571 | |||
537 | /* Unique IDs: IP addresses. */ | 572 | /* Unique IDs: IP addresses. */ | |
538 | KASSERT(npf_iscached(npc, NPC_IP46 | NPC_ADDRS)); | 573 | KASSERT(npf_iscached(npc, NPC_IP46 | NPC_ADDRS)); | |
539 | se->s_src_addr = npc->npc_srcip; | 574 | se->s_src_addr = npc->npc_srcip; | |
540 | se->s_dst_addr = npc->npc_dstip; | 575 | se->s_dst_addr = npc->npc_dstip; | |
541 | 576 | |||
577 | /* Procotol. */ | |||
578 | se->s_type = npc->npc_proto; | |||
579 | ||||
542 | switch (npc->npc_proto) { | 580 | switch (npc->npc_proto) { | |
543 | case IPPROTO_TCP: | 581 | case IPPROTO_TCP: | |
544 | case IPPROTO_UDP: | 582 | case IPPROTO_UDP: | |
545 | KASSERT(npf_iscached(npc, NPC_PORTS)); | 583 | KASSERT(npf_iscached(npc, NPC_PORTS)); | |
546 | se->s_type = (npc->npc_proto == IPPROTO_TCP) ? | |||
547 | NPF_SESSION_TCP : NPF_SESSION_UDP; | |||
548 | /* Additional IDs: ports. */ | 584 | /* Additional IDs: ports. */ | |
549 | se->s_src.id = npc->npc_sport; | 585 | se->s_src.id = npc->npc_sport; | |
550 | se->s_dst.id = npc->npc_dport; | 586 | se->s_dst.id = npc->npc_dport; | |
551 | break; | 587 | break; | |
552 | case IPPROTO_ICMP: | 588 | case IPPROTO_ICMP: | |
553 | if (npf_iscached(npc, NPC_ICMP_ID)) { | 589 | if (npf_iscached(npc, NPC_ICMP_ID)) { | |
554 | /* ICMP query ID. (XXX) */ | 590 | /* ICMP query ID. (XXX) */ | |
555 | se->s_type = NPF_SESSION_ICMP; | |||
556 | se->s_src.id = npc->npc_icmp_id; | 591 | se->s_src.id = npc->npc_icmp_id; | |
557 | se->s_dst.id = npc->npc_icmp_id; | 592 | se->s_dst.id = npc->npc_icmp_id; | |
558 | break; | 593 | break; | |
559 | } | 594 | } | |
560 | /* FALLTHROUGH */ | 595 | /* FALLTHROUGH */ | |
561 | default: | 596 | default: | |
562 | /* Unsupported. */ | 597 | /* Unsupported. */ | |
563 | pool_cache_put(sess_cache, se); | 598 | pool_cache_put(sess_cache, se); | |
564 | return NULL; | 599 | return NULL; | |
565 | } | 600 | } | |
566 | 601 | |||
567 | /* Set last activity time for a new session. */ | 602 | /* Set last activity time for a new session. */ | |
568 | se->s_state = SE_OPENING; | 603 | se->s_state = SE_OPENING; | |
@@ -585,89 +620,106 @@ npf_session_establish(const npf_cache_t | @@ -585,89 +620,106 @@ npf_session_establish(const npf_cache_t | |||
585 | return NULL; | 620 | return NULL; | |
586 | } | 621 | } | |
587 | return se; | 622 | return se; | |
588 | } | 623 | } | |
589 | 624 | |||
590 | /* | 625 | /* | |
591 | * npf_session_pass: return true if session is "pass" one, otherwise false. | 626 | * npf_session_pass: return true if session is "pass" one, otherwise false. | |
592 | */ | 627 | */ | |
593 | bool | 628 | bool | |
594 | npf_session_pass(const npf_session_t *se) | 629 | npf_session_pass(const npf_session_t *se) | |
595 | { | 630 | { | |
596 | 631 | |||
597 | KASSERT(se->s_refcnt > 0); | 632 | KASSERT(se->s_refcnt > 0); | |
598 | return true; /* FIXME */ | 633 | return (se->s_flags & SE_PASSSING) != 0; | |
599 | } | 634 | } | |
600 | 635 | |||
601 | /* | 636 | /* | |
602 | * npf_session_release: release a reference, which might allow G/C thread | 637 | * npf_session_setpass: mark session as a "pass" one, also mark the | |
603 | * to destroy this session. | 638 | * linked session if there is one. | |
604 | */ | 639 | */ | |
605 | void | 640 | void | |
606 | npf_session_release(npf_session_t *se) | 641 | npf_session_setpass(npf_session_t *se) | |
607 | { | 642 | { | |
608 | 643 | |||
609 | KASSERT(se->s_refcnt > 0); | 644 | KASSERT(se->s_refcnt > 0); | |
610 | atomic_dec_uint(&se->s_refcnt); | 645 | se->s_flags |= SE_PASSSING; /* XXXSMP */ | |
646 | if (se->s_nat_se) { | |||
647 | se = se->s_nat_se; | |||
648 | se->s_flags |= SE_PASSSING; /* XXXSMP */ | |||
649 | } | |||
611 | } | 650 | } | |
612 | 651 | |||
613 | /* | 652 | /* | |
614 | * npf_session_retnat: return associated NAT data, if any. | 653 | * npf_session_release: release a reference, which might allow G/C thread | |
654 | * to destroy this session. | |||
615 | */ | 655 | */ | |
616 | npf_nat_t * | 656 | void | |
617 | npf_session_retnat(const npf_session_t *se) | 657 | npf_session_release(npf_session_t *se) | |
618 | { | 658 | { | |
619 | 659 | |||
620 | KASSERT(se->s_refcnt > 0); | 660 | KASSERT(se->s_refcnt > 0); | |
621 | return se->s_nat; | 661 | atomic_dec_uint(&se->s_refcnt); | |
622 | } | 662 | } | |
623 | 663 | |||
664 | /* | |||
665 | * npf_session_link: create a link between regular and NAT sessions. | |||
666 | * Note: NAT session inherits the flags, including "pass" bit. | |||
667 | */ | |||
624 | void | 668 | void | |
625 | npf_session_link(npf_session_t *se, npf_session_t *natse) | 669 | npf_session_link(npf_session_t *se, npf_session_t *natse) | |
626 | { | 670 | { | |
627 | 671 | |||
628 | /* Hold a reference on a session we link. */ | 672 | /* Hold a reference on the session we link. Inherit the flags. */ | |
629 | KASSERT(se->s_refcnt > 0 && natse->s_refcnt > 0); | 673 | KASSERT(se->s_refcnt > 0 && natse->s_refcnt > 0); | |
630 | atomic_inc_uint(&natse->s_refcnt); | 674 | atomic_inc_uint(&natse->s_refcnt); | |
675 | natse->s_flags = se->s_flags; | |||
676 | ||||
677 | KASSERT(se->s_nat_se == NULL); | |||
631 | se->s_nat_se = natse; | 678 | se->s_nat_se = natse; | |
632 | } | 679 | } | |
633 | 680 | |||
681 | /* | |||
682 | * npf_session_retnat: return associated NAT data entry and indicate | |||
683 | * whether it is a "forwards" or "backwards" stream. | |||
684 | */ | |||
634 | npf_nat_t * | 685 | npf_nat_t * | |
635 | npf_session_retlinknat(const npf_session_t *se) | 686 | npf_session_retnat(npf_session_t *se, const int di, bool *forw) | |
636 | { | 687 | { | |
637 | npf_session_t *natse = se->s_nat_se; | |||
638 | 688 | |||
639 | KASSERT(se->s_refcnt > 0); | 689 | KASSERT(se->s_refcnt > 0); | |
640 | KASSERT(natse == NULL || natse->s_refcnt > 0); | 690 | *forw = (se->s_direction == di); | |
641 | 691 | if (se->s_nat_se) { | ||
642 | /* If there is a link, we hold a reference on it. */ | 692 | se = se->s_nat_se; | |
643 | return natse ? natse->s_nat : NULL; | 693 | KASSERT(se->s_refcnt > 0); | |
694 | } | |||
695 | return se->s_nat; | |||
644 | } | 696 | } | |
645 | 697 | |||
646 | /* | 698 | /* | |
647 | * npf_session_expired: criterion to check if session is expired. | 699 | * npf_session_expired: criterion to check if session is expired. | |
648 | */ | 700 | */ | |
649 | static inline bool | 701 | static inline bool | |
650 | npf_session_expired(const npf_session_t *se, const struct timespec *tsnow) | 702 | npf_session_expired(const npf_session_t *se, const struct timespec *tsnow) | |
651 | { | 703 | { | |
652 | struct timespec tsdiff; | 704 | struct timespec tsdiff; | |
653 | int etime = 0; | 705 | int etime = 0; | |
654 | 706 | |||
655 | switch (se->s_state) { | 707 | switch (se->s_state) { | |
656 | case SE_ESTABLISHED: | 708 | case SE_ESTABLISHED: | |
657 | etime = sess_expire_table[se->s_type]; | 709 | etime = sess_expire_table[se->s_type]; | |
658 | break; | 710 | break; | |
659 | case SE_OPENING: | 711 | case SE_OPENING: | |
660 | case SE_OPENING2: | 712 | case SE_ACKNOWLEDGE: | |
661 | case SE_CLOSING: | 713 | case SE_CLOSING: | |
662 | etime = 10; /* XXX: figure out reasonable time */ | 714 | etime = 10; /* XXX: figure out reasonable time */ | |
663 | break; | 715 | break; | |
664 | default: | 716 | default: | |
665 | KASSERT(false); | 717 | KASSERT(false); | |
666 | } | 718 | } | |
667 | timespecsub(tsnow, &se->s_atime, &tsdiff); | 719 | timespecsub(tsnow, &se->s_atime, &tsdiff); | |
668 | return (tsdiff.tv_sec > etime); | 720 | return (tsdiff.tv_sec > etime); | |
669 | } | 721 | } | |
670 | 722 | |||
671 | /* | 723 | /* | |
672 | * npf_session_gc: scan all sessions, insert into G/C list all expired ones. | 724 | * npf_session_gc: scan all sessions, insert into G/C list all expired ones. | |
673 | */ | 725 | */ | |
@@ -811,29 +863,29 @@ npf_sessions_dump(void) | @@ -811,29 +863,29 @@ npf_sessions_dump(void) | |||
811 | } | 863 | } | |
812 | printf("s_bucket %d (count = %d)\n", i, sh->sh_count); | 864 | printf("s_bucket %d (count = %d)\n", i, sh->sh_count); | |
813 | RB_TREE_FOREACH(nd, &sh->sh_tree) { | 865 | RB_TREE_FOREACH(nd, &sh->sh_tree) { | |
814 | struct timespec tsdiff; | 866 | struct timespec tsdiff; | |
815 | struct in_addr ip; | 867 | struct in_addr ip; | |
816 | int etime; | 868 | int etime; | |
817 | 869 | |||
818 | se = NPF_RBN2SESENT(nd); | 870 | se = NPF_RBN2SESENT(nd); | |
819 | 871 | |||
820 | timespecsub(&tsnow, &se->s_atime, &tsdiff); | 872 | timespecsub(&tsnow, &se->s_atime, &tsdiff); | |
821 | etime = (se->s_state == SE_ESTABLISHED) ? | 873 | etime = (se->s_state == SE_ESTABLISHED) ? | |
822 | sess_expire_table[se->s_type] : 10; | 874 | sess_expire_table[se->s_type] : 10; | |
823 | 875 | |||
824 | printf("\t%p: type(%d) di = %d, tsdiff = %d, " | 876 | printf("\t%p: type(%d) di %d, pass %d, tsdiff %d, " | |
825 | "etime = %d\n", se, se->s_type, se->s_direction, | 877 | "etime %d\n", se, se->s_type, se->s_direction, | |
826 | (int)tsdiff.tv_sec, etime); | 878 | se->s_flags, (int)tsdiff.tv_sec, etime); | |
827 | ip.s_addr = se->s_src_addr; | 879 | ip.s_addr = se->s_src_addr; | |
828 | printf("\tsrc (%s, %d) ", | 880 | printf("\tsrc (%s, %d) ", | |
829 | inet_ntoa(ip), ntohs(se->s_src.port)); | 881 | inet_ntoa(ip), ntohs(se->s_src.port)); | |
830 | ip.s_addr = se->s_dst_addr; | 882 | ip.s_addr = se->s_dst_addr; | |
831 | printf("dst (%s, %d)\n", | 883 | printf("dst (%s, %d)\n", | |
832 | inet_ntoa(ip), ntohs(se->s_dst.port)); | 884 | inet_ntoa(ip), ntohs(se->s_dst.port)); | |
833 | if (se->s_nat_se != NULL) { | 885 | if (se->s_nat_se != NULL) { | |
834 | printf("\tlinked with %p\n", se->s_nat_se); | 886 | printf("\tlinked with %p\n", se->s_nat_se); | |
835 | } | 887 | } | |
836 | if (se->s_nat != NULL) { | 888 | if (se->s_nat != NULL) { | |
837 | npf_nat_dump(se->s_nat); | 889 | npf_nat_dump(se->s_nat); | |
838 | } | 890 | } | |
839 | } | 891 | } |
/* $NetBSD: npf_sendpkt.c,v 1.1 2010/09/16 04:53:27 rmind Exp $ */
/*-
* Copyright (c) 2010 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This material is based upon work partially supported by The
* NetBSD Foundation under a contract with Mindaugas Rasiukevicius.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/*
* NPF module for packet construction routines.
*/
#ifdef _KERNEL
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: npf_sendpkt.c,v 1.1 2010/09/16 04:53:27 rmind Exp $");
#include <sys/param.h>
#include <sys/kernel.h>
#include <netinet/in_systm.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/ip_icmp.h>
#include <netinet/ip_var.h>
#include <netinet/tcp.h>
#endif
#include <sys/mbuf.h>
#include "npf_impl.h"
#define DEFAULT_IP_TTL (ip_defttl)
/*
* npf_fetch_seqack: fetch TCP data length, SEQ and ACK numbers.
*
* NOTE: Returns in host byte-order.
*/
static inline bool
npf_fetch_seqack(nbuf_t *nbuf, npf_cache_t *npc,
tcp_seq *seq, tcp_seq *ack, size_t *tcpdlen)
{
void *n_ptr = nbuf_dataptr(nbuf);
u_int offby;
tcp_seq seqack[2];
uint16_t iplen;
uint8_t toff;
/* Fetch total length of IP. */
offby = offsetof(struct ip, ip_len);
if ((n_ptr = nbuf_advance(&nbuf, n_ptr, offby)) == NULL)
return false;
if (nbuf_fetch_datum(nbuf, n_ptr, sizeof(uint16_t), &iplen))
return false;
/* Fetch SEQ and ACK numbers. */
offby = (npc->npc_hlen - offby) + offsetof(struct tcphdr, th_seq);
if ((n_ptr = nbuf_advance(&nbuf, n_ptr, offby)) == NULL)
return false;
if (nbuf_fetch_datum(nbuf, n_ptr, sizeof(seqack), seqack))
return false;
/* Fetch TCP data offset (header length) value. */
offby = sizeof(seqack);
if ((n_ptr = nbuf_advance(&nbuf, n_ptr, offby)) == NULL)
return false;
if (nbuf_fetch_datum(nbuf, n_ptr, sizeof(uint8_t), &toff))
return false;
toff >>= 4;
*seq = ntohl(seqack[0]);
*ack = ntohl(seqack[1]);
*tcpdlen = ntohs(iplen) - npc->npc_hlen - (toff << 2);
return true;
}
/*
* npf_return_tcp: return a TCP reset (RST) packet.
*/
static int
npf_return_tcp(npf_cache_t *npc, nbuf_t *nbuf)
{
struct mbuf *m;
struct ip *ip;
struct tcphdr *th;
tcp_seq seq, ack;
size_t tcpdlen, len;
/* Fetch relevant data. */
if (!npf_iscached(npc, NPC_IP46 | NPC_ADDRS | NPC_PORTS) ||
!npf_fetch_seqack(nbuf, npc, &seq, &ack, &tcpdlen)) {
return EBADMSG;
}
if (npc->npc_tcp_flags & TH_RST) {
return 0;
}
/* Create and setup a network buffer. */
len = sizeof(struct ip) + sizeof(struct tcphdr);
m = m_gethdr(M_DONTWAIT, MT_HEADER);
if (m == NULL) {
return ENOMEM;
}
m->m_data += max_linkhdr;
m->m_len = len;
m->m_pkthdr.len = len;
ip = mtod(m, struct ip *);
memset(ip, 0, len);
/*
* First fill of IPv4 header, for TCP checksum.
* Note: IP length contains TCP header length.
*/
ip->ip_p = IPPROTO_TCP;
ip->ip_src.s_addr = npc->npc_dstip;
ip->ip_dst.s_addr = npc->npc_srcip;
ip->ip_len = htons(sizeof(struct tcphdr));
/* Construct TCP header and compute the checksum. */
th = (struct tcphdr *)(ip + 1);
th->th_sport = npc->npc_dport;
th->th_dport = npc->npc_sport;
th->th_seq = htonl(ack);
if (npc->npc_tcp_flags & TH_SYN) {
tcpdlen++;
}
th->th_ack = htonl(seq + tcpdlen);
th->th_off = sizeof(struct tcphdr) >> 2;
th->th_flags = TH_ACK | TH_RST;
th->th_sum = in_cksum(m, len);
/* Second fill of IPv4 header, fill correct IP length. */
ip->ip_v = IPVERSION;
ip->ip_hl = sizeof(struct ip) >> 2;
ip->ip_tos = IPTOS_LOWDELAY;
ip->ip_len = htons(len);
ip->ip_off = htons(IP_DF);
ip->ip_ttl = DEFAULT_IP_TTL;
/* Pass to IP layer. */
return ip_output(m, NULL, NULL, IP_FORWARDING, NULL, NULL);
}
/*
* npf_return_icmp: return an ICMP error.
*/
static int
npf_return_icmp(nbuf_t *nbuf)
{
struct mbuf *m = nbuf;
icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_ADMIN_PROHIBIT, 0, 0);
return 0;
}
/*
* npf_return_block: return TCP reset or ICMP host unreachable packet.
*/
void
npf_return_block(npf_cache_t *npc, nbuf_t *nbuf, const int retfl)
{
void *n_ptr = nbuf_dataptr(nbuf);
const int proto = npc->npc_proto;
if (!npf_iscached(npc, NPC_IP46) && !npf_ip4_proto(npc, nbuf, n_ptr))
return;
if ((proto == IPPROTO_TCP && (retfl & NPF_RULE_RETRST) == 0) ||
(proto == IPPROTO_UDP && (retfl & NPF_RULE_RETICMP) == 0)) {
return;
}
switch (proto) {
case IPPROTO_TCP:
(void)npf_return_tcp(npc, nbuf);
break;
case IPPROTO_UDP:
(void)npf_return_icmp(nbuf);
break;
}
}
--- src/usr.sbin/npf/npfctl/npf.conf.5 2010/08/24 23:55:05 1.1
+++ src/usr.sbin/npf/npfctl/npf.conf.5 2010/09/16 04:53:27 1.2
@@ -1,14 +1,14 @@ | @@ -1,14 +1,14 @@ | |||
1 | .\" $NetBSD: npf.conf.5,v 1.1 2010/08/24 23:55:05 rmind Exp $ | 1 | .\" $NetBSD: npf.conf.5,v 1.2 2010/09/16 04:53:27 rmind Exp $ | |
2 | .\" | 2 | .\" | |
3 | .\" Copyright (c) 2009-2010 The NetBSD Foundation, Inc. | 3 | .\" Copyright (c) 2009-2010 The NetBSD Foundation, Inc. | |
4 | .\" All rights reserved. | 4 | .\" All rights reserved. | |
5 | .\" | 5 | .\" | |
6 | .\" This material is based upon work partially supported by The | 6 | .\" This material is based upon work partially supported by The | |
7 | .\" NetBSD Foundation under a contract with Mindaugas Rasiukevicius. | 7 | .\" NetBSD Foundation under a contract with Mindaugas Rasiukevicius. | |
8 | .\" | 8 | .\" | |
9 | .\" Redistribution and use in source and binary forms, with or without | 9 | .\" Redistribution and use in source and binary forms, with or without | |
10 | .\" modification, are permitted provided that the following conditions | 10 | .\" modification, are permitted provided that the following conditions | |
11 | .\" are met: | 11 | .\" are met: | |
12 | .\" 1. Redistributions of source code must retain the above copyright | 12 | .\" 1. Redistributions of source code must retain the above copyright | |
13 | .\" notice, this list of conditions and the following disclaimer. | 13 | .\" notice, this list of conditions and the following disclaimer. | |
14 | .\" 2. Redistributions in binary form must reproduce the above copyright | 14 | .\" 2. Redistributions in binary form must reproduce the above copyright | |
@@ -17,27 +17,27 @@ | @@ -17,27 +17,27 @@ | |||
17 | .\" | 17 | .\" | |
18 | .\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS | 18 | .\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS | |
19 | .\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED | 19 | .\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED | |
20 | .\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | 20 | .\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | |
21 | .\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS | 21 | .\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS | |
22 | .\" BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | 22 | .\" BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | |
23 | .\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | 23 | .\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | |
24 | .\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | 24 | .\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | |
25 | .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | 25 | .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | |
26 | .\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | 26 | .\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |
27 | .\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | 27 | .\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |
28 | .\" POSSIBILITY OF SUCH DAMAGE. | 28 | .\" POSSIBILITY OF SUCH DAMAGE. | |
29 | .\" | 29 | .\" | |
30 | .Dd August 24, 2010 | 30 | .Dd September 16, 2010 | |
31 | .Dt NPF.CONF 5 | 31 | .Dt NPF.CONF 5 | |
32 | .Os | 32 | .Os | |
33 | .Sh NAME | 33 | .Sh NAME | |
34 | .Nm npf.conf | 34 | .Nm npf.conf | |
35 | .Nd NPF packet filter configuration file | 35 | .Nd NPF packet filter configuration file | |
36 | .\" ----- | 36 | .\" ----- | |
37 | .Sh DESCRIPTION | 37 | .Sh DESCRIPTION | |
38 | .Nm | 38 | .Nm | |
39 | is the default configuration file for NPF packet filter. | 39 | is the default configuration file for NPF packet filter. | |
40 | It can contain definitions, grouped rules, and tables. | 40 | It can contain definitions, grouped rules, and tables. | |
41 | .Sh DEFINITIONS | 41 | .Sh DEFINITIONS | |
42 | Definitions are general purpose keywords which can be used in the | 42 | Definitions are general purpose keywords which can be used in the | |
43 | ruleset to make it more flexible and easier to manage. | 43 | ruleset to make it more flexible and easier to manage. | |
@@ -85,47 +85,51 @@ Tables can be managed dynamically or loa | @@ -85,47 +85,51 @@ Tables can be managed dynamically or loa | |||
85 | is useful for large static tables. | 85 | is useful for large static tables. | |
86 | There are two types of storage: "tree" (red-black tree is used) and | 86 | There are two types of storage: "tree" (red-black tree is used) and | |
87 | "hash". | 87 | "hash". | |
88 | .Sh NAT | 88 | .Sh NAT | |
89 | Special rules for Network Address Translation (NAT) can be added. | 89 | Special rules for Network Address Translation (NAT) can be added. | |
90 | Translation is performed on specified interface, assigning a specified | 90 | Translation is performed on specified interface, assigning a specified | |
91 | address of said interface. | 91 | address of said interface. | |
92 | Minimal filtering criteria on local network and destination are provided. | 92 | Minimal filtering criteria on local network and destination are provided. | |
93 | .\" ----- | 93 | .\" ----- | |
94 | .Sh GRAMMAR | 94 | .Sh GRAMMAR | |
95 | .Bd -literal | 95 | .Bd -literal | |
96 | line = ( def | table | nat | group ) | 96 | line = ( def | table | nat | group ) | |
97 | 97 | |||
98 | def = ( "{ a, b, ... }" | "text" | "$\*[Lt]interface\*[Gt]" ) | 98 | def = ( \*[Lt]name\*[Gt] "=" "{ a, b, ... }" | "text" | "$\*[Lt]interface\*[Gt]" ) | |
99 | iface = ( \*[Lt]interface\*[Gt] | def ) | 99 | iface = ( \*[Lt]interface\*[Gt] | def ) | |
100 | 100 | |||
101 | table = "table" \*[Lt]tid\*[Gt] "type" ( "hash" | "tree" ) | 101 | table = "table" \*[Lt]tid\*[Gt] "type" ( "hash" | "tree" ) | |
102 | ( "dynamic" | "file" \*[Lt]path\*[Gt] ) | 102 | ( "dynamic" | "file" \*[Lt]path\*[Gt] ) | |
103 | 103 | |||
104 | nat = "nat" iface "from" \*[Lt]addr/mask\*[Gt] "to" \*[Lt]addr/mask\*[Gt] "->" \*[Lt]addr\*[Gt] | 104 | nat = "nat" iface filt-opts "->" \*[Lt]addr\*[Gt] | |
105 | binat = "binat" iface filt-opts "->" \*[Lt]addr\*[Gt] | |||
106 | rdr = "rdr" iface filt-opts "->" \*[Lt]addr\*[Gt] port-opts | |||
105 | 107 | |||
106 | group = "group" "(" ( "default" | group-opts ) "") ruleset | 108 | group = "group" "(" ( "default" | group-opts ) "") ruleset | |
107 | group-opts = "interface" iface "," [ "in" | "out" ] | 109 | group-opts = "interface" iface "," [ "in" | "out" ] | |
108 | 110 | |||
109 | ruleset = "{" rule1 \*[Lt]newline\*[Gt], rule2 \*[Lt]newline\*[Gt], ... "}" | 111 | ruleset = "{" rule1 \*[Lt]newline\*[Gt], rule2 \*[Lt]newline\*[Gt], ... "}" | |
110 | 112 | |||
111 | rule = ( "block" | "pass" ) [ "in" | out" ] rule-opts | 113 | rule = ( "block" block-opts | "pass" ) [ "in" | out" ] rule-opts | |
112 | [ "on" iface ] [ "inet" | "inet6" ] [ "proto" \*[Lt]protocol\*[Gt] ] | 114 | [ "on" iface ] [ "inet" | "inet6" ] [ "proto" \*[Lt]protocol\*[Gt] ] | |
113 | ( "all" | filt-opts ) | 115 | ( "all" | filt-opts [ "flags" \*[Lt]tcp_flags> \*[Gt] ) | |
114 | 116 | |||
117 | block-opts = [ "return-rst" | "return-icmp" | "return" ] | |||
115 | rule-opts = [ "log" ] [ "count" ] [ "quick" ] | 118 | rule-opts = [ "log" ] [ "count" ] [ "quick" ] | |
116 | filt-opts = [ "from" ( iface | def | \*[Lt]addr/mask\*[Gt] | \*[Lt]tid\*[Gt] ) port-opts ] | 119 | filt-opts = [ "from" ( iface | def | \*[Lt]addr/mask\*[Gt] | \*[Lt]tid\*[Gt] ) port-opts ] | |
117 | [ "to" ( iface | def | \*[Lt]addr/mask\*[Gt] | \*[Lt]tid\*[Gt] ) port-opts ] | 120 | [ "to" ( iface | def | \*[Lt]addr/mask\*[Gt] | \*[Lt]tid\*[Gt] ) port-opts ] | |
118 | port-opts = [ "port" ( \*[Lt]port-num\*[Gt] | \*[Lt]port-from\*[Gt] ":" \*[Lt]port-to\*[Gt] | def ) ] | 121 | port-opts = [ "port" ( \*[Lt]port-num\*[Gt] | \*[Lt]port-from\*[Gt] ":" \*[Lt]port-to\*[Gt] | def ) ] | |
122 | proto-opts = [ "flags" \*[Lt]tcp_flags\*[Gt] | "icmp-type" \*[Lt]type\*[Gt] "code" \*[Lt]code\*[Gt] ] | |||
119 | .Ed | 123 | .Ed | |
120 | .\" ----- | 124 | .\" ----- | |
121 | .Sh FILES | 125 | .Sh FILES | |
122 | .Bl -tag -width /dev/npf.conf -compact | 126 | .Bl -tag -width /dev/npf.conf -compact | |
123 | .It Pa /dev/npf | 127 | .It Pa /dev/npf | |
124 | control device | 128 | control device | |
125 | .It Pa /etc/npf.conf | 129 | .It Pa /etc/npf.conf | |
126 | default configuration file | 130 | default configuration file | |
127 | .El | 131 | .El | |
128 | .\" ----- | 132 | .\" ----- | |
129 | .Sh EXAMPLES | 133 | .Sh EXAMPLES | |
130 | .Bd -literal | 134 | .Bd -literal | |
131 | ext_if = "wm0" | 135 | ext_if = "wm0" |
--- src/usr.sbin/npf/npfctl/Attic/npf_ncgen.c 2010/08/22 18:56:23 1.1
+++ src/usr.sbin/npf/npfctl/Attic/npf_ncgen.c 2010/09/16 04:53:27 1.2
@@ -1,14 +1,14 @@ | @@ -1,14 +1,14 @@ | |||
1 | /* $NetBSD: npf_ncgen.c,v 1.1 2010/08/22 18:56:23 rmind Exp $ */ | 1 | /* $NetBSD: npf_ncgen.c,v 1.2 2010/09/16 04:53:27 rmind Exp $ */ | |
2 | 2 | |||
3 | /*- | 3 | /*- | |
4 | * Copyright (c) 2009-2010 The NetBSD Foundation, Inc. | 4 | * Copyright (c) 2009-2010 The NetBSD Foundation, Inc. | |
5 | * All rights reserved. | 5 | * All rights reserved. | |
6 | * | 6 | * | |
7 | * This material is based upon work partially supported by The | 7 | * This material is based upon work partially supported by The | |
8 | * NetBSD Foundation under a contract with Mindaugas Rasiukevicius. | 8 | * NetBSD Foundation under a contract with Mindaugas Rasiukevicius. | |
9 | * | 9 | * | |
10 | * Redistribution and use in source and binary forms, with or without | 10 | * Redistribution and use in source and binary forms, with or without | |
11 | * modification, are permitted provided that the following conditions | 11 | * modification, are permitted provided that the following conditions | |
12 | * are met: | 12 | * are met: | |
13 | * 1. Redistributions of source code must retain the above copyright | 13 | * 1. Redistributions of source code must retain the above copyright | |
14 | * notice, this list of conditions and the following disclaimer. | 14 | * notice, this list of conditions and the following disclaimer. | |
@@ -38,53 +38,56 @@ | @@ -38,53 +38,56 @@ | |||
38 | 38 | |||
39 | #include <sys/types.h> | 39 | #include <sys/types.h> | |
40 | 40 | |||
41 | #include "npfctl.h" | 41 | #include "npfctl.h" | |
42 | 42 | |||
43 | /* | 43 | /* | |
44 | * npfctl_calc_ncsize: calculate size required for the n-code. | 44 | * npfctl_calc_ncsize: calculate size required for the n-code. | |
45 | */ | 45 | */ | |
46 | size_t | 46 | size_t | |
47 | npfctl_calc_ncsize(int nblocks[]) | 47 | npfctl_calc_ncsize(int nblocks[]) | |
48 | { | 48 | { | |
49 | /* | 49 | /* | |
50 | * Blocks: | 50 | * Blocks: | |
51 | * - 13 words by npfctl_gennc_ether(), single initial block. | |||
52 | * - 5 words each by npfctl_gennc_ports/tbl(), stored in nblocks[0]. | 51 | * - 5 words each by npfctl_gennc_ports/tbl(), stored in nblocks[0]. | |
53 | * - 6 words each by npfctl_gennc_v4cidr(), stored in nblocks[1]. | 52 | * - 6 words each by npfctl_gennc_v4cidr(), stored in nblocks[1]. | |
53 | * - 4 words by npfctl_gennc_{icmp,tcpfl}(), stored in nblocks[2]. | |||
54 | * - 4 words by npfctl_gennc_complete(), single last fragment. | 54 | * - 4 words by npfctl_gennc_complete(), single last fragment. | |
55 | */ | 55 | */ | |
56 | return nblocks[0] * 5 * sizeof(uint32_t) + | 56 | return nblocks[0] * 5 * sizeof(uint32_t) + | |
57 | nblocks[1] * 6 * sizeof(uint32_t) + | 57 | nblocks[1] * 6 * sizeof(uint32_t) + | |
58 | 13 * sizeof(uint32_t) + | 58 | nblocks[2] * 4 * sizeof(uint32_t) + | |
59 | 4 * sizeof(uint32_t); | 59 | 4 * sizeof(uint32_t); | |
60 | } | 60 | } | |
61 | 61 | |||
62 | /* | 62 | /* | |
63 | * npfctl_failure_offset: calculate offset value to the failure block. | 63 | * npfctl_failure_offset: calculate offset value to the failure block. | |
64 | */ | 64 | */ | |
65 | size_t | 65 | size_t | |
66 | npfctl_failure_offset(int nblocks[]) | 66 | npfctl_failure_offset(int nblocks[]) | |
67 | { | 67 | { | |
68 | size_t tblport_blocks, v4cidr_blocks; | 68 | size_t tblport_blocks, v4cidr_blocks, icmp_tcpfl; | |
69 | /* | 69 | /* | |
70 | * Take into account all blocks (plus 2 words for comparison each), | 70 | * Take into account all blocks (plus 2 words for comparison each), | |
71 | * and additional 4 words to skip the last comparison and success path. | 71 | * and additional 4 words to skip the last comparison and success path. | |
72 | */ | 72 | */ | |
73 | tblport_blocks = (3 + 2) * nblocks[0]; | 73 | tblport_blocks = (3 + 2) * nblocks[0]; | |
74 | v4cidr_blocks = (4 + 2) * nblocks[1]; | 74 | v4cidr_blocks = (4 + 2) * nblocks[1]; | |
75 | return tblport_blocks + v4cidr_blocks + 4; | 75 | icmp_tcpfl = (2 + 2) * nblocks[2]; | |
76 | return tblport_blocks + v4cidr_blocks + icmp_tcpfl + 4; | |||
76 | } | 77 | } | |
77 | 78 | |||
79 | #if 0 | |||
80 | ||||
78 | /* | 81 | /* | |
79 | * npfctl_gennc_ether: initial n-code fragment to check Ethernet frame. | 82 | * npfctl_gennc_ether: initial n-code fragment to check Ethernet frame. | |
80 | */ | 83 | */ | |
81 | void | 84 | void | |
82 | npfctl_gennc_ether(void **ncptr, int foff, uint16_t ethertype) | 85 | npfctl_gennc_ether(void **ncptr, int foff, uint16_t ethertype) | |
83 | { | 86 | { | |
84 | uint32_t *nc = *ncptr; | 87 | uint32_t *nc = *ncptr; | |
85 | 88 | |||
86 | /* NPF handler will set REG_0 to either NPF_LAYER_2 or NPF_LAYER_3. */ | 89 | /* NPF handler will set REG_0 to either NPF_LAYER_2 or NPF_LAYER_3. */ | |
87 | *nc++ = NPF_OPCODE_CMP; | 90 | *nc++ = NPF_OPCODE_CMP; | |
88 | *nc++ = NPF_LAYER_3; | 91 | *nc++ = NPF_LAYER_3; | |
89 | *nc++ = 0; | 92 | *nc++ = 0; | |
90 | 93 | |||
@@ -99,26 +102,28 @@ npfctl_gennc_ether(void **ncptr, int fof | @@ -99,26 +102,28 @@ npfctl_gennc_ether(void **ncptr, int fof | |||
99 | *nc++ = ethertype; | 102 | *nc++ = ethertype; | |
100 | 103 | |||
101 | /* Fail (+ 2 words of ADVR) or advance to layer 3 (IPv4) header. */ | 104 | /* Fail (+ 2 words of ADVR) or advance to layer 3 (IPv4) header. */ | |
102 | *nc++ = NPF_OPCODE_BNE; | 105 | *nc++ = NPF_OPCODE_BNE; | |
103 | *nc++ = foff + 2; | 106 | *nc++ = foff + 2; | |
104 | /* Offset to the header is returned by NPF_OPCODE_ETHER in REG_3. */ | 107 | /* Offset to the header is returned by NPF_OPCODE_ETHER in REG_3. */ | |
105 | *nc++ = NPF_OPCODE_ADVR; | 108 | *nc++ = NPF_OPCODE_ADVR; | |
106 | *nc++ = 3; | 109 | *nc++ = 3; | |
107 | 110 | |||
108 | /* + 13 words. */ | 111 | /* + 13 words. */ | |
109 | *ncptr = (void *)nc; | 112 | *ncptr = (void *)nc; | |
110 | } | 113 | } | |
111 | 114 | |||
115 | #endif | |||
116 | ||||
112 | /* | 117 | /* | |
113 | * npfctl_gennc_v4cidr: fragment to match IPv4 CIDR. | 118 | * npfctl_gennc_v4cidr: fragment to match IPv4 CIDR. | |
114 | */ | 119 | */ | |
115 | void | 120 | void | |
116 | npfctl_gennc_v4cidr(void **ncptr, int foff, | 121 | npfctl_gennc_v4cidr(void **ncptr, int foff, | |
117 | in_addr_t netaddr, in_addr_t subnet, bool sd) | 122 | in_addr_t netaddr, in_addr_t subnet, bool sd) | |
118 | { | 123 | { | |
119 | uint32_t *nc = *ncptr; | 124 | uint32_t *nc = *ncptr; | |
120 | 125 | |||
121 | /* OP, direction, netaddr/subnet (4 words) */ | 126 | /* OP, direction, netaddr/subnet (4 words) */ | |
122 | *nc++ = NPF_OPCODE_IP4MASK; | 127 | *nc++ = NPF_OPCODE_IP4MASK; | |
123 | *nc++ = (sd ? 0x01 : 0x00); | 128 | *nc++ = (sd ? 0x01 : 0x00); | |
124 | *nc++ = netaddr; | 129 | *nc++ = netaddr; | |
@@ -145,69 +150,89 @@ npfctl_gennc_ports(void **ncptr, int fof | @@ -145,69 +150,89 @@ npfctl_gennc_ports(void **ncptr, int fof | |||
145 | *nc++ = (tcpudp ? NPF_OPCODE_TCP_PORTS : NPF_OPCODE_UDP_PORTS); | 150 | *nc++ = (tcpudp ? NPF_OPCODE_TCP_PORTS : NPF_OPCODE_UDP_PORTS); | |
146 | *nc++ = (sd ? 0x01 : 0x00); | 151 | *nc++ = (sd ? 0x01 : 0x00); | |
147 | *nc++ = ((uint32_t)pfrom << 16) | pto; | 152 | *nc++ = ((uint32_t)pfrom << 16) | pto; | |
148 | 153 | |||
149 | /* If not equal, jump to failure block, continue otherwise (2 words). */ | 154 | /* If not equal, jump to failure block, continue otherwise (2 words). */ | |
150 | *nc++ = NPF_OPCODE_BNE; | 155 | *nc++ = NPF_OPCODE_BNE; | |
151 | *nc++ = foff; | 156 | *nc++ = foff; | |
152 | 157 | |||
153 | /* + 5 words. */ | 158 | /* + 5 words. */ | |
154 | *ncptr = (void *)nc; | 159 | *ncptr = (void *)nc; | |
155 | } | 160 | } | |
156 | 161 | |||
157 | /* | 162 | /* | |
158 | * npfctl_gennc_icmp: fragment to match ICMP code and type. | 163 | * npfctl_gennc_icmp: fragment to match ICMP type and code. | |
159 | */ | 164 | */ | |
160 | void | 165 | void | |
161 | npfctl_gennc_icmp(void **ncptr, int foff, int code, int type) | 166 | npfctl_gennc_icmp(void **ncptr, int foff, int type, int code) | |
162 | { | 167 | { | |
163 | uint32_t *nc = *ncptr; | 168 | uint32_t *nc = *ncptr; | |
164 | 169 | |||
165 | /* OP, code, type (3 words) */ | 170 | /* OP, code, type (2 words) */ | |
166 | *nc++ = NPF_OPCODE_ICMP4; | 171 | *nc++ = NPF_OPCODE_ICMP4; | |
167 | *nc++ = code; | 172 | *nc++ = (type == -1 ? 0 : (1 << 31) & (type & 0xff << 8)) | | |
168 | *nc++ = type; | 173 | (code == -1 ? 0 : (1 << 31) & (code & 0xff)); | |
169 | 174 | |||
170 | /* If not equal, jump to failure block, continue otherwise (2 words). */ | 175 | /* If not equal, jump to failure block, continue otherwise (2 words). */ | |
171 | *nc++ = NPF_OPCODE_BNE; | 176 | *nc++ = NPF_OPCODE_BNE; | |
172 | *nc++ = foff; | 177 | *nc++ = foff; | |
173 | 178 | |||
174 | /* + 5 words. */ | 179 | /* + 4 words. */ | |
175 | *ncptr = (void *)nc; | 180 | *ncptr = (void *)nc; | |
176 | } | 181 | } | |
177 | 182 | |||
178 | /* | 183 | /* | |
179 | * npfctl_gennc_tbl: fragment to match IPv4 source/destination address of | 184 | * npfctl_gennc_tbl: fragment to match IPv4 source/destination address of | |
180 | * the packet against table specified by ID. | 185 | * the packet against table specified by ID. | |
181 | */ | 186 | */ | |
182 | void | 187 | void | |
183 | npfctl_gennc_tbl(void **ncptr, int foff, u_int tid, bool sd) | 188 | npfctl_gennc_tbl(void **ncptr, int foff, u_int tid, bool sd) | |
184 | { | 189 | { | |
185 | uint32_t *nc = *ncptr; | 190 | uint32_t *nc = *ncptr; | |
186 | 191 | |||
187 | /* OP, direction, table ID (3 words). */ | 192 | /* OP, direction, table ID (3 words). */ | |
188 | *nc++ = NPF_OPCODE_IP4TABLE; | 193 | *nc++ = NPF_OPCODE_IP4TABLE; | |
189 | *nc++ = (sd ? 0x01 : 0x00); | 194 | *nc++ = (sd ? 0x01 : 0x00); | |
190 | *nc++ = tid; | 195 | *nc++ = tid; | |
191 | 196 | |||
192 | /* If not equal, jump to failure block, continue otherwise (2 words). */ | 197 | /* If not equal, jump to failure block, continue otherwise (2 words). */ | |
193 | *nc++ = NPF_OPCODE_BNE; | 198 | *nc++ = NPF_OPCODE_BNE; | |
194 | *nc++ = foff; | 199 | *nc++ = foff; | |
195 | 200 | |||
196 | /* + 5 words. */ | 201 | /* + 5 words. */ | |
197 | *ncptr = (void *)nc; | 202 | *ncptr = (void *)nc; | |
198 | } | 203 | } | |
199 | 204 | |||
200 | /* | 205 | /* | |
206 | * npfctl_gennc_tcpfl: fragment to match TCP flags/mask. | |||
207 | */ | |||
208 | void | |||
209 | npfctl_gennc_tcpfl(void **ncptr, int foff, uint8_t tf, uint8_t tf_mask) | |||
210 | { | |||
211 | uint32_t *nc = *ncptr; | |||
212 | ||||
213 | /* OP, code, type (2 words) */ | |||
214 | *nc++ = NPF_OPCODE_TCP_FLAGS; | |||
215 | *nc++ = (tf << 8) | tf_mask; | |||
216 | ||||
217 | /* If not equal, jump to failure block, continue otherwise (2 words). */ | |||
218 | *nc++ = NPF_OPCODE_BNE; | |||
219 | *nc++ = foff; | |||
220 | ||||
221 | /* + 4 words. */ | |||
222 | *ncptr = (void *)nc; | |||
223 | } | |||
224 | ||||
225 | /* | |||
201 | * npfctl_gennc_complete: append success and failure fragments. | 226 | * npfctl_gennc_complete: append success and failure fragments. | |
202 | */ | 227 | */ | |
203 | void | 228 | void | |
204 | npfctl_gennc_complete(void **ncptr) | 229 | npfctl_gennc_complete(void **ncptr) | |
205 | { | 230 | { | |
206 | uint32_t *nc = *ncptr; | 231 | uint32_t *nc = *ncptr; | |
207 | 232 | |||
208 | /* Success path (return 0x0). */ | 233 | /* Success path (return 0x0). */ | |
209 | *nc++ = NPF_OPCODE_RET; | 234 | *nc++ = NPF_OPCODE_RET; | |
210 | *nc++ = 0x0; | 235 | *nc++ = 0x0; | |
211 | 236 | |||
212 | /* Failure path (return 0xff). */ | 237 | /* Failure path (return 0xff). */ | |
213 | *nc++ = NPF_OPCODE_RET; | 238 | *nc++ = NPF_OPCODE_RET; |
--- src/usr.sbin/npf/npfctl/Attic/npf_parser.c 2010/08/22 18:56:23 1.1
+++ src/usr.sbin/npf/npfctl/Attic/npf_parser.c 2010/09/16 04:53:27 1.2
@@ -1,14 +1,14 @@ | @@ -1,14 +1,14 @@ | |||
1 | /* $NetBSD: npf_parser.c,v 1.1 2010/08/22 18:56:23 rmind Exp $ */ | 1 | /* $NetBSD: npf_parser.c,v 1.2 2010/09/16 04:53:27 rmind Exp $ */ | |
2 | 2 | |||
3 | /*- | 3 | /*- | |
4 | * Copyright (c) 2009-2010 The NetBSD Foundation, Inc. | 4 | * Copyright (c) 2009-2010 The NetBSD Foundation, Inc. | |
5 | * All rights reserved. | 5 | * All rights reserved. | |
6 | * | 6 | * | |
7 | * Redistribution and use in source and binary forms, with or without | 7 | * Redistribution and use in source and binary forms, with or without | |
8 | * modification, are permitted provided that the following conditions | 8 | * modification, are permitted provided that the following conditions | |
9 | * are met: | 9 | * are met: | |
10 | * 1. Redistributions of source code must retain the above copyright | 10 | * 1. Redistributions of source code must retain the above copyright | |
11 | * notice, this list of conditions and the following disclaimer. | 11 | * notice, this list of conditions and the following disclaimer. | |
12 | * 2. Redistributions in binary form must reproduce the above copyright | 12 | * 2. Redistributions in binary form must reproduce the above copyright | |
13 | * notice, this list of conditions and the following disclaimer in the | 13 | * notice, this list of conditions and the following disclaimer in the | |
14 | * documentation and/or other materials provided with the distribution. | 14 | * documentation and/or other materials provided with the distribution. | |
@@ -144,44 +144,58 @@ npfctl_parsevalue(char *buf) | @@ -144,44 +144,58 @@ npfctl_parsevalue(char *buf) | |||
144 | * npfctl_parserule: main routine to parse a rule. Syntax: | 144 | * npfctl_parserule: main routine to parse a rule. Syntax: | |
145 | * | 145 | * | |
146 | * { pass | block | count } [ in | out ] [ log ] [ quick ] | 146 | * { pass | block | count } [ in | out ] [ log ] [ quick ] | |
147 | * [on <if>] [inet | inet6 ] proto <array> | 147 | * [on <if>] [inet | inet6 ] proto <array> | |
148 | * from <addr/mask> port <port(s)|range> | 148 | * from <addr/mask> port <port(s)|range> | |
149 | * too <addr/mask> port <port(s)|range> | 149 | * too <addr/mask> port <port(s)|range> | |
150 | * [ keep state ] | 150 | * [ keep state ] | |
151 | */ | 151 | */ | |
152 | static inline int | 152 | static inline int | |
153 | npfctl_parserule(char *buf, prop_dictionary_t rl) | 153 | npfctl_parserule(char *buf, prop_dictionary_t rl) | |
154 | { | 154 | { | |
155 | var_t *from_cidr = NULL, *fports = NULL; | 155 | var_t *from_cidr = NULL, *fports = NULL; | |
156 | var_t *to_cidr = NULL, *tports = NULL; | 156 | var_t *to_cidr = NULL, *tports = NULL; | |
157 | char *proto = NULL; | 157 | char *proto = NULL, *tcp_flags = NULL; | |
158 | char *p, *sptr, *iface; | 158 | char *p, *sptr, *iface; | |
159 | bool icmp = false, tcp = false; | |||
160 | int icmp_type = -1, icmp_code = -1; | |||
159 | int ret, attr = 0; | 161 | int ret, attr = 0; | |
160 | 162 | |||
161 | DPRINTF(("rule\t|%s|\n", buf)); | 163 | DPRINTF(("rule\t|%s|\n", buf)); | |
162 | 164 | |||
163 | p = buf; | 165 | p = buf; | |
164 | PARSE_FIRST_TOKEN(); | 166 | PARSE_FIRST_TOKEN(); | |
165 | 167 | |||
166 | /* pass or block (mandatory) */ | 168 | /* pass or block (mandatory) */ | |
167 | if (strcmp(p, "block") == 0) { | 169 | if (strcmp(p, "block") == 0) { | |
168 | attr = 0; | 170 | attr = 0; | |
171 | PARSE_NEXT_TOKEN(); | |||
172 | /* return-rst or return-icmp */ | |||
173 | if (strcmp(p, "return-rst") == 0) { | |||
174 | attr |= NPF_RULE_RETRST; | |||
175 | PARSE_NEXT_TOKEN(); | |||
176 | } else if (strcmp(p, "return-icmp") == 0) { | |||
177 | attr |= NPF_RULE_RETICMP; | |||
178 | PARSE_NEXT_TOKEN(); | |||
179 | } else if (strcmp(p, "return") == 0) { | |||
180 | attr |= NPF_RULE_RETRST | NPF_RULE_RETICMP; | |||
181 | PARSE_NEXT_TOKEN(); | |||
182 | } | |||
169 | } else if (strcmp(p, "pass") == 0) { | 183 | } else if (strcmp(p, "pass") == 0) { | |
170 | attr = NPF_RULE_PASS; | 184 | attr = NPF_RULE_PASS; | |
185 | PARSE_NEXT_TOKEN(); | |||
171 | } else { | 186 | } else { | |
172 | return PARSE_ERR(); | 187 | return PARSE_ERR(); | |
173 | } | 188 | } | |
174 | PARSE_NEXT_TOKEN(); | |||
175 | 189 | |||
176 | /* in or out */ | 190 | /* in or out */ | |
177 | if (strcmp(p, "in") == 0) { | 191 | if (strcmp(p, "in") == 0) { | |
178 | attr |= NPF_RULE_IN; | 192 | attr |= NPF_RULE_IN; | |
179 | PARSE_NEXT_TOKEN(); | 193 | PARSE_NEXT_TOKEN(); | |
180 | } else if (strcmp(p, "out") == 0) { | 194 | } else if (strcmp(p, "out") == 0) { | |
181 | attr |= NPF_RULE_OUT; | 195 | attr |= NPF_RULE_OUT; | |
182 | PARSE_NEXT_TOKEN(); | 196 | PARSE_NEXT_TOKEN(); | |
183 | } else { | 197 | } else { | |
184 | attr |= (NPF_RULE_IN | NPF_RULE_OUT); | 198 | attr |= (NPF_RULE_IN | NPF_RULE_OUT); | |
185 | } | 199 | } | |
186 | 200 | |||
187 | /* log (XXX: NOP) */ | 201 | /* log (XXX: NOP) */ | |
@@ -223,28 +237,34 @@ npfctl_parserule(char *buf, prop_diction | @@ -223,28 +237,34 @@ npfctl_parserule(char *buf, prop_diction | |||
223 | 237 | |||
224 | /* inet, inet6 (TODO) */ | 238 | /* inet, inet6 (TODO) */ | |
225 | if (strcmp(p, "inet") == 0) { | 239 | if (strcmp(p, "inet") == 0) { | |
226 | PARSE_NEXT_TOKEN(); | 240 | PARSE_NEXT_TOKEN(); | |
227 | } else if (strcmp(p, "inet6") == 0) { | 241 | } else if (strcmp(p, "inet6") == 0) { | |
228 | PARSE_NEXT_TOKEN(); | 242 | PARSE_NEXT_TOKEN(); | |
229 | } | 243 | } | |
230 | 244 | |||
231 | /* proto <proto> */ | 245 | /* proto <proto> */ | |
232 | if (strcmp(p, "proto") == 0) { | 246 | if (strcmp(p, "proto") == 0) { | |
233 | PARSE_NEXT_TOKEN(); | 247 | PARSE_NEXT_TOKEN(); | |
234 | var_t *pvar = npfctl_parsevalue(p); | 248 | var_t *pvar = npfctl_parsevalue(p); | |
235 | PARSE_NEXT_TOKEN(); | 249 | PARSE_NEXT_TOKEN(); | |
250 | if (pvar->v_type != VAR_SINGLE) { | |||
251 | errx(EXIT_FAILURE, "only one protocol can be specified"); | |||
252 | } | |||
236 | element_t *el = pvar->v_elements; | 253 | element_t *el = pvar->v_elements; | |
237 | proto = el->e_data; | 254 | proto = el->e_data; | |
255 | /* Determine TCP, ICMP. */ | |||
256 | tcp = (strcmp(proto, "tcp") == 0); | |||
257 | icmp = (strcmp(proto, "icmp") == 0); | |||
238 | } | 258 | } | |
239 | 259 | |||
240 | /* | 260 | /* | |
241 | * Can be: "all", "from", "to" or "from + to". | 261 | * Can be: "all", "from", "to" or "from + to". | |
242 | */ | 262 | */ | |
243 | 263 | |||
244 | if (strcmp(p, "all") == 0) { | 264 | if (strcmp(p, "all") == 0) { | |
245 | /* Should be no "from"/"to" after it. */ | 265 | /* Should be no "from"/"to" after it. */ | |
246 | PARSE_NEXT_TOKEN_NOCHECK(); | 266 | PARSE_NEXT_TOKEN_NOCHECK(); | |
247 | goto last; | 267 | goto last; | |
248 | } | 268 | } | |
249 | 269 | |||
250 | ret = PARSE_ERR(); | 270 | ret = PARSE_ERR(); | |
@@ -270,40 +290,73 @@ npfctl_parserule(char *buf, prop_diction | @@ -270,40 +290,73 @@ npfctl_parserule(char *buf, prop_diction | |||
270 | 290 | |||
271 | PARSE_NEXT_TOKEN_NOCHECK(); | 291 | PARSE_NEXT_TOKEN_NOCHECK(); | |
272 | if (p && strcmp(p, "port") == 0) { | 292 | if (p && strcmp(p, "port") == 0) { | |
273 | PARSE_NEXT_TOKEN(); | 293 | PARSE_NEXT_TOKEN(); | |
274 | tports = npfctl_parsevalue(p); | 294 | tports = npfctl_parsevalue(p); | |
275 | PARSE_NEXT_TOKEN_NOCHECK(); | 295 | PARSE_NEXT_TOKEN_NOCHECK(); | |
276 | } | 296 | } | |
277 | ret = 0; | 297 | ret = 0; | |
278 | } | 298 | } | |
279 | 299 | |||
280 | if (ret) { | 300 | if (ret) { | |
281 | return ret; | 301 | return ret; | |
282 | } | 302 | } | |
303 | ||||
304 | /* flags <fl/mask> */ | |||
305 | if (p && strcmp(p, "flags") == 0) { | |||
306 | if (icmp) { | |||
307 | errx(EXIT_FAILURE, | |||
308 | "TCP flags used with ICMP protocol"); | |||
309 | } | |||
310 | PARSE_NEXT_TOKEN(); | |||
311 | var_t *tfvar = npfctl_parsevalue(p); | |||
312 | PARSE_NEXT_TOKEN_NOCHECK(); | |||
313 | if (tfvar->v_type != VAR_SINGLE) { | |||
314 | errx(EXIT_FAILURE, "invalid TCP flags"); | |||
315 | } | |||
316 | element_t *el = tfvar->v_elements; | |||
317 | tcp_flags = el->e_data; | |||
318 | } | |||
319 | ||||
320 | /* icmp-type <t> code <c> */ | |||
321 | if (p && strcmp(p, "icmp-type") == 0) { | |||
322 | if (tcp) { | |||
323 | errx(EXIT_FAILURE, | |||
324 | "ICMP options used with TCP protocol"); | |||
325 | } | |||
326 | PARSE_NEXT_TOKEN(); | |||
327 | icmp_type = atoi(p); | |||
328 | PARSE_NEXT_TOKEN_NOCHECK(); | |||
329 | if (p && strcmp(p, "code") == 0) { | |||
330 | PARSE_NEXT_TOKEN(); | |||
331 | icmp_code = atoi(p); | |||
332 | PARSE_NEXT_TOKEN_NOCHECK(); | |||
333 | } | |||
334 | } | |||
283 | last: | 335 | last: | |
284 | /* keep state */ | 336 | /* keep state */ | |
285 | if (p && strcmp(p, "keep") == 0) { | 337 | if (p && strcmp(p, "keep") == 0) { | |
286 | attr |= NPF_RULE_KEEPSTATE; | 338 | attr |= NPF_RULE_KEEPSTATE; | |
287 | PARSE_NEXT_TOKEN(); | 339 | PARSE_NEXT_TOKEN(); | |
288 | } | 340 | } | |
289 | 341 | |||
290 | /* Set the rule attributes and interface, if any. */ | 342 | /* Set the rule attributes and interface, if any. */ | |
291 | npfctl_rule_setattr(rl, attr, iface); | 343 | npfctl_rule_setattr(rl, attr, iface); | |
292 | 344 | |||
293 | /* | 345 | /* | |
294 | * Generate all protocol data. | 346 | * Generate all protocol data. | |
295 | */ | 347 | */ | |
296 | npfctl_rule_protodata(rl, proto, from_cidr, fports, to_cidr, tports); | 348 | npfctl_rule_protodata(rl, proto, tcp_flags, icmp_type, icmp_code, | |
349 | from_cidr, fports, to_cidr, tports); | |||
297 | return 0; | 350 | return 0; | |
298 | } | 351 | } | |
299 | 352 | |||
300 | /* | 353 | /* | |
301 | * npfctl_parsegroup: parse group definition. Syntax: | 354 | * npfctl_parsegroup: parse group definition. Syntax: | |
302 | * | 355 | * | |
303 | * group (name <name>, interface <if>, [ in | out ]) { <rules> } | 356 | * group (name <name>, interface <if>, [ in | out ]) { <rules> } | |
304 | * group (default) { <rules> } | 357 | * group (default) { <rules> } | |
305 | */ | 358 | */ | |
306 | 359 | |||
307 | #define GROUP_ATTRS (NPF_RULE_PASS | NPF_RULE_FINAL) | 360 | #define GROUP_ATTRS (NPF_RULE_PASS | NPF_RULE_FINAL) | |
308 | 361 | |||
309 | static inline int | 362 | static inline int | |
@@ -440,79 +493,136 @@ npfctl_parsetable(char *buf, prop_dictio | @@ -440,79 +493,136 @@ npfctl_parsetable(char *buf, prop_dictio | |||
440 | PARSE_NEXT_TOKEN(); | 493 | PARSE_NEXT_TOKEN(); | |
441 | fname = ++p; | 494 | fname = ++p; | |
442 | p = strchr(p, '"'); | 495 | p = strchr(p, '"'); | |
443 | *p = '\0'; | 496 | *p = '\0'; | |
444 | 497 | |||
445 | /* Construct the table. */ | 498 | /* Construct the table. */ | |
446 | npfctl_construct_table(tl, fname); | 499 | npfctl_construct_table(tl, fname); | |
447 | return 0; | 500 | return 0; | |
448 | } | 501 | } | |
449 | 502 | |||
450 | /* | 503 | /* | |
451 | * npfctl_parse_nat: parse NAT policy definition. | 504 | * npfctl_parse_nat: parse NAT policy definition. | |
452 | * | 505 | * | |
453 | * nat on <if> from <localnet> to <filter> -> <ip> | 506 | * [bi]nat <if> from <net> to <net/addr> -> <ip> | |
507 | * rdr <if> from <net> to <addr> -> <ip> | |||
454 | */ | 508 | */ | |
455 | static inline int | 509 | static inline int | |
456 | npfctl_parse_nat(char *buf, prop_dictionary_t nat) | 510 | npfctl_parse_nat(char *buf, prop_dictionary_t nat) | |
457 | { | 511 | { | |
458 | var_t *ifvar, *from_cidr, *to_cidr, *ip; | 512 | var_t *ifvar, *from_cidr, *to_cidr, *ip; | |
513 | var_t *tports = NULL, *rports = NULL; | |||
459 | element_t *iface, *cidr; | 514 | element_t *iface, *cidr; | |
460 | char *p, *sptr; | 515 | char *p, *sptr; | |
516 | bool binat, rdr; | |||
517 | ||||
518 | DPRINTF(("[bi]nat/rdr\t|%s|\n", buf)); | |||
519 | binat = (strncmp(buf, "binat", 5) == 0); | |||
520 | rdr = (strncmp(buf, "rdr", 3) == 0); | |||
461 | 521 | |||
462 | DPRINTF(("nat\t|%s|\n", buf)); | |||
463 | if ((p = strchr(buf, ' ')) == NULL) { | 522 | if ((p = strchr(buf, ' ')) == NULL) { | |
464 | return PARSE_ERR(); | 523 | return PARSE_ERR(); | |
465 | } | 524 | } | |
466 | PARSE_FIRST_TOKEN(); | 525 | PARSE_FIRST_TOKEN(); | |
467 | 526 | |||
468 | /* on <interface> */ | 527 | /* <interface> */ | |
469 | if ((ifvar = npfctl_parsevalue(p)) == NULL) { | 528 | if ((ifvar = npfctl_parsevalue(p)) == NULL) { | |
470 | return PARSE_ERR(); | 529 | return PARSE_ERR(); | |
471 | } | 530 | } | |
472 | if (ifvar->v_type != VAR_SINGLE) { | 531 | if (ifvar->v_type != VAR_SINGLE) { | |
473 | errx(EXIT_FAILURE, "invalid interface value '%s'", p); | 532 | errx(EXIT_FAILURE, "invalid interface value '%s'", p); | |
474 | } else { | 533 | } else { | |
475 | iface = ifvar->v_elements; | 534 | iface = ifvar->v_elements; | |
476 | } | 535 | } | |
477 | PARSE_NEXT_TOKEN(); | 536 | PARSE_NEXT_TOKEN(); | |
478 | 537 | |||
479 | /* from <addr> */ | 538 | /* from <addr> */ | |
480 | if (strcmp(p, "from") != 0) { | 539 | if (strcmp(p, "from") != 0) { | |
481 | return PARSE_ERR(); | 540 | return PARSE_ERR(); | |
482 | } | 541 | } | |
483 | PARSE_NEXT_TOKEN(); | 542 | PARSE_NEXT_TOKEN(); | |
484 | from_cidr = npfctl_parsevalue(p); | 543 | from_cidr = npfctl_parsevalue(p); | |
485 | PARSE_NEXT_TOKEN(); | 544 | PARSE_NEXT_TOKEN(); | |
486 | 545 | |||
487 | /* to <addr> */ | 546 | /* to <addr> */ | |
488 | if (strcmp(p, "to") != 0) { | 547 | if (strcmp(p, "to") != 0) { | |
489 | return PARSE_ERR(); | 548 | return PARSE_ERR(); | |
490 | } | 549 | } | |
491 | PARSE_NEXT_TOKEN(); | 550 | PARSE_NEXT_TOKEN(); | |
492 | to_cidr = npfctl_parsevalue(p); | 551 | to_cidr = npfctl_parsevalue(p); | |
493 | PARSE_NEXT_TOKEN(); | 552 | PARSE_NEXT_TOKEN(); | |
494 | 553 | |||
554 | if (rdr && strcmp(p, "port") == 0) { | |||
555 | PARSE_NEXT_TOKEN(); | |||
556 | tports = npfctl_parsevalue(p); | |||
557 | PARSE_NEXT_TOKEN(); | |||
558 | } | |||
559 | ||||
495 | /* -> <ip> */ | 560 | /* -> <ip> */ | |
496 | if (strcmp(p, "->") != 0) { | 561 | if (strcmp(p, "->") != 0) { | |
497 | return PARSE_ERR(); | 562 | return PARSE_ERR(); | |
498 | } | 563 | } | |
499 | PARSE_NEXT_TOKEN(); | 564 | PARSE_NEXT_TOKEN(); | |
500 | ip = npfctl_parsevalue(p); | 565 | ip = npfctl_parsevalue(p); | |
501 | cidr = ip->v_elements; | 566 | cidr = ip->v_elements; | |
502 | 567 | |||
503 | /* Setup NAT policy (rule as filter and extra info). */ | 568 | if (rdr) { | |
504 | npfctl_rule_protodata(nat, NULL, from_cidr, NULL, to_cidr, NULL); | 569 | PARSE_NEXT_TOKEN(); | |
505 | npfctl_nat_setup(nat, iface->e_data, cidr->e_data); | 570 | if (strcmp(p, "port") != 0) { | |
571 | return PARSE_ERR(); | |||
572 | } | |||
573 | PARSE_NEXT_TOKEN(); | |||
574 | rports = npfctl_parsevalue(p); | |||
575 | } | |||
576 | ||||
577 | /* | |||
578 | * Setup NAT policy (rule as filter and extra info), which is | |||
579 | * Outbound NAT (NPF_NATOUT). Unless it is a redirect rule, | |||
580 | * in which case it is Inbound NAT with specified port. | |||
581 | * | |||
582 | * XXX mess | |||
583 | */ | |||
584 | if (!rdr) { | |||
585 | npfctl_rule_protodata(nat, NULL, NULL, -1, -1, from_cidr, | |||
586 | NULL, to_cidr, NULL); | |||
587 | npfctl_nat_setup(nat, NPF_NATOUT, | |||
588 | binat ? 0 : (NPF_NAT_PORTS | NPF_NAT_PORTMAP), | |||
589 | iface->e_data, cidr->e_data, NULL); | |||
590 | } else { | |||
591 | element_t *rp = rports->v_elements; | |||
592 | ||||
593 | npfctl_rule_protodata(nat, NULL, NULL, -1, -1, from_cidr, | |||
594 | NULL, to_cidr, tports); | |||
595 | npfctl_nat_setup(nat, NPF_NATIN, NPF_NAT_PORTS, | |||
596 | iface->e_data, cidr->e_data, rp->e_data); | |||
597 | } | |||
598 | ||||
599 | /* | |||
600 | * For bi-directional NAT case, create and setup additional | |||
601 | * Inbound NAT (NPF_NATIN) policy. Note that translation address | |||
602 | * is local IP, and filter criteria is inverted accordingly. | |||
603 | * | |||
604 | * XXX mess | |||
605 | */ | |||
606 | if (binat) { | |||
607 | prop_dictionary_t bn = npfctl_mk_nat(); | |||
608 | element_t *taddr = from_cidr->v_elements; | |||
609 | ||||
610 | npfctl_rule_protodata(bn, NULL, NULL, -1, -1, | |||
611 | to_cidr, NULL, ip, NULL); | |||
612 | npfctl_nat_setup(bn, NPF_NATIN, 0, iface->e_data, | |||
613 | taddr->e_data, NULL); | |||
614 | npfctl_add_nat(bn); | |||
615 | } | |||
506 | return 0; | 616 | return 0; | |
507 | } | 617 | } | |
508 | 618 | |||
509 | /* | 619 | /* | |
510 | * npfctl_parsevar: parse defined variable. | 620 | * npfctl_parsevar: parse defined variable. | |
511 | * | 621 | * | |
512 | * => Assigned value should be with double quotes ("). | 622 | * => Assigned value should be with double quotes ("). | |
513 | * => Value can be an array, use npf_parsevalue(). | 623 | * => Value can be an array, use npf_parsevalue(). | |
514 | * => Insert variable into the global list. | 624 | * => Insert variable into the global list. | |
515 | */ | 625 | */ | |
516 | static inline int | 626 | static inline int | |
517 | npfctl_parsevar(char *buf) | 627 | npfctl_parsevar(char *buf) | |
518 | { | 628 | { | |
@@ -593,27 +703,28 @@ npf_parseline(char *buf) | @@ -593,27 +703,28 @@ npf_parseline(char *buf) | |||
593 | return ret; | 703 | return ret; | |
594 | npfctl_add_rule(curgr, NULL); | 704 | npfctl_add_rule(curgr, NULL); | |
595 | 705 | |||
596 | } else if (strncmp(p, "table", 5) == 0) { | 706 | } else if (strncmp(p, "table", 5) == 0) { | |
597 | prop_dictionary_t tl; | 707 | prop_dictionary_t tl; | |
598 | 708 | |||
599 | /* Table. */ | 709 | /* Table. */ | |
600 | tl = npfctl_mk_table(); | 710 | tl = npfctl_mk_table(); | |
601 | ret = npfctl_parsetable(p, tl); | 711 | ret = npfctl_parsetable(p, tl); | |
602 | if (ret) | 712 | if (ret) | |
603 | return ret; | 713 | return ret; | |
604 | npfctl_add_table(tl); | 714 | npfctl_add_table(tl); | |
605 | 715 | |||
606 | } else if (strncmp(p, "nat", 3) == 0) { | 716 | } else if (strncmp(p, "nat", 3) == 0 || strncmp(p, "rdr", 3) == 0 || | |
717 | strncmp(p, "binat", 5) == 0) { | |||
607 | prop_dictionary_t nat; | 718 | prop_dictionary_t nat; | |
608 | 719 | |||
609 | /* NAT policy. */ | 720 | /* NAT policy. */ | |
610 | nat = npfctl_mk_nat(); | 721 | nat = npfctl_mk_nat(); | |
611 | ret = npfctl_parse_nat(p, nat); | 722 | ret = npfctl_parse_nat(p, nat); | |
612 | if (ret) | 723 | if (ret) | |
613 | return ret; | 724 | return ret; | |
614 | npfctl_add_nat(nat); | 725 | npfctl_add_nat(nat); | |
615 | 726 | |||
616 | } else { | 727 | } else { | |
617 | /* Defined variable or syntax error. */ | 728 | /* Defined variable or syntax error. */ | |
618 | ret = npfctl_parsevar(p); | 729 | ret = npfctl_parsevar(p); | |
619 | } | 730 | } |
--- src/usr.sbin/npf/npfctl/npfctl.h 2010/08/22 18:56:24 1.1
+++ src/usr.sbin/npf/npfctl/npfctl.h 2010/09/16 04:53:27 1.2
@@ -1,14 +1,14 @@ | @@ -1,14 +1,14 @@ | |||
1 | /* $NetBSD: npfctl.h,v 1.1 2010/08/22 18:56:24 rmind Exp $ */ | 1 | /* $NetBSD: npfctl.h,v 1.2 2010/09/16 04:53:27 rmind Exp $ */ | |
2 | 2 | |||
3 | /*- | 3 | /*- | |
4 | * Copyright (c) 2009-2010 The NetBSD Foundation, Inc. | 4 | * Copyright (c) 2009-2010 The NetBSD Foundation, Inc. | |
5 | * All rights reserved. | 5 | * All rights reserved. | |
6 | * | 6 | * | |
7 | * Redistribution and use in source and binary forms, with or without | 7 | * Redistribution and use in source and binary forms, with or without | |
8 | * modification, are permitted provided that the following conditions | 8 | * modification, are permitted provided that the following conditions | |
9 | * are met: | 9 | * are met: | |
10 | * 1. Redistributions of source code must retain the above copyright | 10 | * 1. Redistributions of source code must retain the above copyright | |
11 | * notice, this list of conditions and the following disclaimer. | 11 | * notice, this list of conditions and the following disclaimer. | |
12 | * 2. Redistributions in binary form must reproduce the above copyright | 12 | * 2. Redistributions in binary form must reproduce the above copyright | |
13 | * notice, this list of conditions and the following disclaimer in the | 13 | * notice, this list of conditions and the following disclaimer in the | |
14 | * documentation and/or other materials provided with the distribution. | 14 | * documentation and/or other materials provided with the distribution. | |
@@ -68,42 +68,44 @@ typedef struct { | @@ -68,42 +68,44 @@ typedef struct { | |||
68 | } var_t; | 68 | } var_t; | |
69 | 69 | |||
70 | void * zalloc(size_t); | 70 | void * zalloc(size_t); | |
71 | char * xstrdup(const char *); | 71 | char * xstrdup(const char *); | |
72 | 72 | |||
73 | void npfctl_init_data(void); | 73 | void npfctl_init_data(void); | |
74 | int npfctl_ioctl_send(int); | 74 | int npfctl_ioctl_send(int); | |
75 | 75 | |||
76 | bool npfctl_parse_v4mask(char *, in_addr_t *, in_addr_t *); | 76 | bool npfctl_parse_v4mask(char *, in_addr_t *, in_addr_t *); | |
77 | 77 | |||
78 | prop_dictionary_t npfctl_mk_rule(bool); | 78 | prop_dictionary_t npfctl_mk_rule(bool); | |
79 | void npfctl_add_rule(prop_dictionary_t, prop_dictionary_t); | 79 | void npfctl_add_rule(prop_dictionary_t, prop_dictionary_t); | |
80 | void npfctl_rule_setattr(prop_dictionary_t, int, char *); | 80 | void npfctl_rule_setattr(prop_dictionary_t, int, char *); | |
81 | void npfctl_rule_protodata(prop_dictionary_t, char *, var_t *, | 81 | void npfctl_rule_protodata(prop_dictionary_t, char *, char *, | |
82 | var_t *, var_t *, var_t *); | 82 | int, int, var_t *, var_t *, var_t *, var_t *); | |
83 | void npfctl_rule_icmpdata(prop_dictionary_t, var_t *, var_t *); | 83 | void npfctl_rule_icmpdata(prop_dictionary_t, var_t *, var_t *); | |
84 | 84 | |||
85 | prop_dictionary_t npfctl_lookup_table(char *); | 85 | prop_dictionary_t npfctl_lookup_table(char *); | |
86 | prop_dictionary_t npfctl_mk_table(void); | 86 | prop_dictionary_t npfctl_mk_table(void); | |
87 | void npfctl_table_setup(prop_dictionary_t, char *, char *); | 87 | void npfctl_table_setup(prop_dictionary_t, char *, char *); | |
88 | void npfctl_construct_table(prop_dictionary_t, char *); | 88 | void npfctl_construct_table(prop_dictionary_t, char *); | |
89 | void npfctl_add_table(prop_dictionary_t); | 89 | void npfctl_add_table(prop_dictionary_t); | |
90 | 90 | |||
91 | prop_dictionary_t npfctl_mk_nat(void); | 91 | prop_dictionary_t npfctl_mk_nat(void); | |
92 | void npfctl_add_nat(prop_dictionary_t); | 92 | void npfctl_add_nat(prop_dictionary_t); | |
93 | void npfctl_nat_setup(prop_dictionary_t, char *, char *); | 93 | void npfctl_nat_setup(prop_dictionary_t, int, int, | |
94 | char *, char *, char *); | |||
94 | 95 | |||
95 | size_t npfctl_calc_ncsize(int []); | 96 | size_t npfctl_calc_ncsize(int []); | |
96 | size_t npfctl_failure_offset(int []); | 97 | size_t npfctl_failure_offset(int []); | |
97 | 98 | |||
98 | void npfctl_gennc_ether(void **, int, uint16_t); | 99 | void npfctl_gennc_ether(void **, int, uint16_t); | |
99 | void npfctl_gennc_v4cidr(void **, int, | 100 | void npfctl_gennc_v4cidr(void **, int, | |
100 | in_addr_t, in_addr_t, bool); | 101 | in_addr_t, in_addr_t, bool); | |
101 | void npfctl_gennc_icmp(void **, int, int, int); | 102 | void npfctl_gennc_icmp(void **, int, int, int); | |
103 | void npfctl_gennc_tcpfl(void **, int , uint8_t, uint8_t); | |||
102 | void npfctl_gennc_ports(void **, int, | 104 | void npfctl_gennc_ports(void **, int, | |
103 | in_port_t, in_port_t, bool, bool); | 105 | in_port_t, in_port_t, bool, bool); | |
104 | void npfctl_gennc_tbl(void **, int, u_int , bool); | 106 | void npfctl_gennc_tbl(void **, int, u_int , bool); | |
105 | void npfctl_gennc_complete(void **); | 107 | void npfctl_gennc_complete(void **); | |
106 | 108 | |||
107 | int npf_parseline(char *); | 109 | int npf_parseline(char *); | |
108 | 110 | |||
109 | #endif | 111 | #endif |
--- src/usr.sbin/npf/npfctl/npf_data.c 2010/08/23 06:01:04 1.2
+++ src/usr.sbin/npf/npfctl/npf_data.c 2010/09/16 04:53:27 1.3
@@ -1,14 +1,14 @@ | @@ -1,14 +1,14 @@ | |||
1 | /* $NetBSD: npf_data.c,v 1.2 2010/08/23 06:01:04 jnemeth Exp $ */ | 1 | /* $NetBSD: npf_data.c,v 1.3 2010/09/16 04:53:27 rmind Exp $ */ | |
2 | 2 | |||
3 | /*- | 3 | /*- | |
4 | * Copyright (c) 2009-2010 The NetBSD Foundation, Inc. | 4 | * Copyright (c) 2009-2010 The NetBSD Foundation, Inc. | |
5 | * All rights reserved. | 5 | * All rights reserved. | |
6 | * | 6 | * | |
7 | * Redistribution and use in source and binary forms, with or without | 7 | * Redistribution and use in source and binary forms, with or without | |
8 | * modification, are permitted provided that the following conditions | 8 | * modification, are permitted provided that the following conditions | |
9 | * are met: | 9 | * are met: | |
10 | * 1. Redistributions of source code must retain the above copyright | 10 | * 1. Redistributions of source code must retain the above copyright | |
11 | * notice, this list of conditions and the following disclaimer. | 11 | * notice, this list of conditions and the following disclaimer. | |
12 | * 2. Redistributions in binary form must reproduce the above copyright | 12 | * 2. Redistributions in binary form must reproduce the above copyright | |
13 | * notice, this list of conditions and the following disclaimer in the | 13 | * notice, this list of conditions and the following disclaimer in the | |
14 | * documentation and/or other materials provided with the distribution. | 14 | * documentation and/or other materials provided with the distribution. | |
@@ -26,26 +26,27 @@ | @@ -26,26 +26,27 @@ | |||
26 | * POSSIBILITY OF SUCH DAMAGE. | 26 | * POSSIBILITY OF SUCH DAMAGE. | |
27 | */ | 27 | */ | |
28 | 28 | |||
29 | /* | 29 | /* | |
30 | * NPF proplib(9) dictionary producer. | 30 | * NPF proplib(9) dictionary producer. | |
31 | * | 31 | * | |
32 | * XXX: Needs some clean-up. | 32 | * XXX: Needs some clean-up. | |
33 | */ | 33 | */ | |
34 | 34 | |||
35 | #include <sys/types.h> | 35 | #include <sys/types.h> | |
36 | #include <sys/socket.h> | 36 | #include <sys/socket.h> | |
37 | #include <sys/ioctl.h> | 37 | #include <sys/ioctl.h> | |
38 | #include <net/if.h> | 38 | #include <net/if.h> | |
39 | #include <netinet/tcp.h> | |||
39 | 40 | |||
40 | #include <arpa/inet.h> | 41 | #include <arpa/inet.h> | |
41 | #include <prop/proplib.h> | 42 | #include <prop/proplib.h> | |
42 | 43 | |||
43 | #include <stdlib.h> | 44 | #include <stdlib.h> | |
44 | #include <string.h> | 45 | #include <string.h> | |
45 | #include <unistd.h> | 46 | #include <unistd.h> | |
46 | #include <ctype.h> | 47 | #include <ctype.h> | |
47 | #include <err.h> | 48 | #include <err.h> | |
48 | #include <ifaddrs.h> | 49 | #include <ifaddrs.h> | |
49 | #include <netdb.h> | 50 | #include <netdb.h> | |
50 | #include <assert.h> | 51 | #include <assert.h> | |
51 | 52 | |||
@@ -64,132 +65,190 @@ void | @@ -64,132 +65,190 @@ void | |||
64 | npfctl_init_data(void) | 65 | npfctl_init_data(void) | |
65 | { | 66 | { | |
66 | prop_number_t ver; | 67 | prop_number_t ver; | |
67 | 68 | |||
68 | if (getifaddrs(&ifs_list) == -1) | 69 | if (getifaddrs(&ifs_list) == -1) | |
69 | err(EXIT_FAILURE, "getifaddrs"); | 70 | err(EXIT_FAILURE, "getifaddrs"); | |
70 | 71 | |||
71 | npf_dict = prop_dictionary_create(); | 72 | npf_dict = prop_dictionary_create(); | |
72 | 73 | |||
73 | ver = prop_number_create_integer(NPF_VERSION); | 74 | ver = prop_number_create_integer(NPF_VERSION); | |
74 | prop_dictionary_set(npf_dict, "version", ver); | 75 | prop_dictionary_set(npf_dict, "version", ver); | |
75 | 76 | |||
76 | nat_arr = prop_array_create(); | 77 | nat_arr = prop_array_create(); | |
77 | prop_dictionary_set(npf_dict, "nat", nat_arr); | 78 | prop_dictionary_set(npf_dict, "translation", nat_arr); | |
78 | 79 | |||
79 | settings_dict = prop_dictionary_create(); | 80 | settings_dict = prop_dictionary_create(); | |
80 | prop_dictionary_set(npf_dict, "settings", settings_dict); | 81 | prop_dictionary_set(npf_dict, "settings", settings_dict); | |
81 | 82 | |||
82 | tables_arr = prop_array_create(); | 83 | tables_arr = prop_array_create(); | |
83 | prop_dictionary_set(npf_dict, "tables", tables_arr); | 84 | prop_dictionary_set(npf_dict, "tables", tables_arr); | |
84 | 85 | |||
85 | rules_arr = prop_array_create(); | 86 | rules_arr = prop_array_create(); | |
86 | prop_dictionary_set(npf_dict, "rules", rules_arr); | 87 | prop_dictionary_set(npf_dict, "rules", rules_arr); | |
87 | } | 88 | } | |
88 | 89 | |||
89 | int | 90 | int | |
90 | npfctl_ioctl_send(int fd) | 91 | npfctl_ioctl_send(int fd) | |
91 | { | 92 | { | |
92 | int ret = 0, errval; | 93 | int ret = 0, errval; | |
93 | 94 | |||
94 | #ifdef DEBUG | 95 | #ifdef DEBUG | |
95 | prop_dictionary_externalize_to_file(npf_dict, "/tmp/npf.plist"); | 96 | prop_dictionary_externalize_to_file(npf_dict, "./npf.plist"); | |
96 | #else | 97 | #else | |
97 | errval = prop_dictionary_send_ioctl(npf_dict, fd, IOC_NPF_RELOAD); | 98 | errval = prop_dictionary_send_ioctl(npf_dict, fd, IOC_NPF_RELOAD); | |
98 | if (errval) { | 99 | if (errval) { | |
99 | errx(EXIT_FAILURE, "npf_ioctl_send: %s\n", strerror(errval)); | 100 | errx(EXIT_FAILURE, "npf_ioctl_send: %s\n", strerror(errval)); | |
100 | ret = -1; | 101 | ret = -1; | |
101 | } | 102 | } | |
102 | #endif | 103 | #endif | |
103 | prop_object_release(npf_dict); | 104 | prop_object_release(npf_dict); | |
104 | return ret; | 105 | return ret; | |
105 | } | 106 | } | |
106 | 107 | |||
107 | /* | 108 | /* | |
108 | * Helper routines: | 109 | * Helper routines: | |
109 | * | 110 | * | |
110 | * npfctl_getif() - get interface addresses and index number from name. | 111 | * npfctl_getif() - get interface addresses and index number from name. | |
111 | * npfctl_servname2port() - get service ports from name. | |||
112 | * npfctl_parse_v4mask() - parse address/mask integers from CIDR block. | 112 | * npfctl_parse_v4mask() - parse address/mask integers from CIDR block. | |
113 | * npfctl_parse_port() - parse port number (which may be a service name). | |||
114 | * npfctl_parse_tcpfl() - parse TCP flags. | |||
113 | */ | 115 | */ | |
114 | 116 | |||
115 | static struct ifaddrs * | 117 | static struct ifaddrs * | |
116 | npfctl_getif(char *ifname, unsigned int *if_idx) | 118 | npfctl_getif(char *ifname, unsigned int *if_idx) | |
117 | { | 119 | { | |
118 | struct ifaddrs *ifent; | 120 | struct ifaddrs *ifent; | |
119 | struct sockaddr_in *sin; | 121 | struct sockaddr_in *sin; | |
120 | 122 | |||
121 | for (ifent = ifs_list; ifent != NULL; ifent = ifent->ifa_next) { | 123 | for (ifent = ifs_list; ifent != NULL; ifent = ifent->ifa_next) { | |
122 | sin = (struct sockaddr_in *)ifent->ifa_addr; | 124 | sin = (struct sockaddr_in *)ifent->ifa_addr; | |
123 | 125 | |||
124 | if (sin->sin_family != AF_INET) | 126 | if (sin->sin_family != AF_INET) | |
125 | continue; | 127 | continue; | |
126 | if (strcmp(ifent->ifa_name, ifname) == 0) | 128 | if (strcmp(ifent->ifa_name, ifname) == 0) | |
127 | break; | 129 | break; | |
128 | } | 130 | } | |
129 | if (ifent) { | 131 | if (ifent) { | |
130 | *if_idx = if_nametoindex(ifname); | 132 | *if_idx = if_nametoindex(ifname); | |
131 | } | 133 | } | |
132 | return ifent; | 134 | return ifent; | |
133 | } | 135 | } | |
134 | 136 | |||
135 | static int | |||
136 | npfctl_servname2port(char *name) | |||
137 | { | |||
138 | struct servent *se; | |||
139 | ||||
140 | se = getservbyname(name, NULL); | |||
141 | return se ? se->s_port : -1; | |||
142 | } | |||
143 | ||||
144 | bool | 137 | bool | |
145 | npfctl_parse_v4mask(char *str, in_addr_t *addr, in_addr_t *mask) | 138 | npfctl_parse_v4mask(char *ostr, in_addr_t *addr, in_addr_t *mask) | |
146 | { | 139 | { | |
140 | char *str = xstrdup(ostr); | |||
147 | char *p = strchr(str, '/'); | 141 | char *p = strchr(str, '/'); | |
148 | u_int bits; | 142 | u_int bits; | |
143 | bool ret; | |||
149 | 144 | |||
150 | /* In network byte order. */ | 145 | /* In network byte order. */ | |
151 | if (p) { | 146 | if (p) { | |
152 | *p++ = '\0'; | 147 | *p++ = '\0'; | |
153 | bits = (u_int)atoi(p); | 148 | bits = (u_int)atoi(p); | |
154 | *mask = bits ? htonl(0xffffffff << (32 - bits)) : 0; | 149 | *mask = bits ? htonl(0xffffffff << (32 - bits)) : 0; | |
155 | } else { | 150 | } else { | |
156 | *mask = 0xffffffff; | 151 | *mask = 0xffffffff; | |
157 | } | 152 | } | |
158 | return inet_aton(str, (struct in_addr *)addr) != 0; | 153 | ret = inet_aton(str, (struct in_addr *)addr) != 0; | |
154 | free(str); | |||
155 | return ret; | |||
156 | } | |||
157 | ||||
158 | static bool | |||
159 | npfctl_parse_port(char *ostr, bool *range, in_port_t *fport, in_port_t *tport) | |||
160 | { | |||
161 | char *str = xstrdup(ostr), *sep; | |||
162 | ||||
163 | *range = false; | |||
164 | if ((sep = strchr(str, ':')) != NULL) { | |||
165 | /* Port range (only numeric). */ | |||
166 | *range = true; | |||
167 | *sep = '\0'; | |||
168 | ||||
169 | } else if (isalpha((unsigned char)*str)) { | |||
170 | struct servent *se; | |||
171 | ||||
172 | se = getservbyname(str, NULL); | |||
173 | if (se == NULL) { | |||
174 | free(str); | |||
175 | return false; | |||
176 | } | |||
177 | *fport = se->s_port; | |||
178 | } else { | |||
179 | *fport = htons(atoi(str)); | |||
180 | } | |||
181 | *tport = sep ? htons(atoi(sep + 1)) : *fport; | |||
182 | free(str); | |||
183 | return true; | |||
159 | } | 184 | } | |
160 | 185 | |||
161 | static void | 186 | static void | |
162 | npfctl_parse_cidr(char *str, in_addr_t *addr, in_addr_t *mask) | 187 | npfctl_parse_cidr(char *str, in_addr_t *addr, in_addr_t *mask) | |
163 | { | 188 | { | |
164 | 189 | |||
165 | if (isalpha((unsigned char)*str)) { | 190 | if (isalpha((unsigned char)*str)) { | |
166 | struct ifaddrs *ifa; | 191 | struct ifaddrs *ifa; | |
167 | struct sockaddr_in *sin; | 192 | struct sockaddr_in *sin; | |
168 | u_int idx; | 193 | u_int idx; | |
169 | 194 | |||
170 | if ((ifa = npfctl_getif(str, &idx)) == NULL) { | 195 | if ((ifa = npfctl_getif(str, &idx)) == NULL) { | |
171 | errx(EXIT_FAILURE, "invalid interface '%s'", str); | 196 | errx(EXIT_FAILURE, "invalid interface '%s'", str); | |
172 | } | 197 | } | |
173 | /* Interface address. */ | 198 | /* Interface address. */ | |
174 | sin = (struct sockaddr_in *)ifa->ifa_addr; | 199 | sin = (struct sockaddr_in *)ifa->ifa_addr; | |
175 | *addr = sin->sin_addr.s_addr; | 200 | *addr = sin->sin_addr.s_addr; | |
176 | *mask = 0xffffffff; | 201 | *mask = 0xffffffff; | |
177 | 202 | |||
178 | } else if (!npfctl_parse_v4mask(str, addr, mask)) { | 203 | } else if (!npfctl_parse_v4mask(str, addr, mask)) { | |
179 | errx(EXIT_FAILURE, "invalid CIDR '%s'\n", str); | 204 | errx(EXIT_FAILURE, "invalid CIDR '%s'\n", str); | |
180 | } | 205 | } | |
181 | } | 206 | } | |
182 | 207 | |||
208 | static bool | |||
209 | npfctl_parse_tcpfl(char *s, uint8_t *tfl, uint8_t *tfl_mask) | |||
210 | { | |||
211 | uint8_t tcpfl = 0; | |||
212 | bool mask = false; | |||
213 | ||||
214 | while (*s) { | |||
215 | switch (*s) { | |||
216 | case 'F': tcpfl |= TH_FIN; break; | |||
217 | case 'S': tcpfl |= TH_SYN; break; | |||
218 | case 'R': tcpfl |= TH_RST; break; | |||
219 | case 'P': tcpfl |= TH_PUSH; break; | |||
220 | case 'A': tcpfl |= TH_ACK; break; | |||
221 | case 'U': tcpfl |= TH_URG; break; | |||
222 | case 'E': tcpfl |= TH_ECE; break; | |||
223 | case 'W': tcpfl |= TH_CWR; break; | |||
224 | case '/': | |||
225 | *s = '\0'; | |||
226 | *tfl = tcpfl; | |||
227 | tcpfl = 0; | |||
228 | mask = true; | |||
229 | break; | |||
230 | default: | |||
231 | return false; | |||
232 | } | |||
233 | s++; | |||
234 | } | |||
235 | if (!mask) { | |||
236 | *tfl = tcpfl; | |||
237 | } | |||
238 | *tfl_mask = tcpfl; | |||
239 | return true; | |||
240 | } | |||
241 | ||||
183 | /* | 242 | /* | |
184 | * NPF table creation and construction routines. | 243 | * NPF table creation and construction routines. | |
185 | */ | 244 | */ | |
186 | 245 | |||
187 | prop_dictionary_t | 246 | prop_dictionary_t | |
188 | npfctl_lookup_table(char *tidstr) | 247 | npfctl_lookup_table(char *tidstr) | |
189 | { | 248 | { | |
190 | prop_dictionary_t tl; | 249 | prop_dictionary_t tl; | |
191 | prop_object_iterator_t it; | 250 | prop_object_iterator_t it; | |
192 | prop_object_t obj; | 251 | prop_object_t obj; | |
193 | u_int tid; | 252 | u_int tid; | |
194 | 253 | |||
195 | if ((it = prop_array_iterator(tables_arr)) == NULL) | 254 | if ((it = prop_array_iterator(tables_arr)) == NULL) | |
@@ -380,155 +439,175 @@ npfctl_rulenc_v4cidr(void **nc, int nblo | @@ -380,155 +439,175 @@ npfctl_rulenc_v4cidr(void **nc, int nblo | |||
380 | } | 439 | } | |
381 | } | 440 | } | |
382 | 441 | |||
383 | static void | 442 | static void | |
384 | npfctl_rulenc_ports(void **nc, int nblocks[], var_t *dat, bool tcpudp, bool sd) | 443 | npfctl_rulenc_ports(void **nc, int nblocks[], var_t *dat, bool tcpudp, bool sd) | |
385 | { | 444 | { | |
386 | element_t *el = dat->v_elements; | 445 | element_t *el = dat->v_elements; | |
387 | int foff; | 446 | int foff; | |
388 | 447 | |||
389 | assert(dat->v_type != VAR_TABLE); | 448 | assert(dat->v_type != VAR_TABLE); | |
390 | 449 | |||
391 | /* Generate TCP/UDP port matching blocks. */ | 450 | /* Generate TCP/UDP port matching blocks. */ | |
392 | for (el = dat->v_elements; el != NULL; el = el->e_next) { | 451 | for (el = dat->v_elements; el != NULL; el = el->e_next) { | |
393 | int pfrom, pto; | 452 | in_port_t fport, tport; | |
394 | char *sep; | 453 | bool range; | |
395 | 454 | |||
396 | if ((sep = strchr(el->e_data, ':')) != NULL) { | 455 | if (!npfctl_parse_port(el->e_data, &range, &fport, &tport)) { | |
397 | /* Port range (only numeric). */ | 456 | errx(EXIT_FAILURE, "invalid service '%s'", el->e_data); | |
398 | *sep = '\0'; | |||
399 | } | 457 | } | |
400 | if (isalpha((unsigned char)*el->e_data)) { | |||
401 | pfrom = npfctl_servname2port(el->e_data); | |||
402 | if (pfrom == -1) { | |||
403 | errx(EXIT_FAILURE, "invalid service '%s'", | |||
404 | el->e_data); | |||
405 | } | |||
406 | } else { | |||
407 | pfrom = htons(atoi(el->e_data)); | |||
408 | } | |||
409 | pto = sep ? htons(atoi(sep + 1)) : pfrom; | |||
410 | ||||
411 | nblocks[0]--; | 458 | nblocks[0]--; | |
412 | foff = npfctl_failure_offset(nblocks); | 459 | foff = npfctl_failure_offset(nblocks); | |
413 | npfctl_gennc_ports(nc, foff, pfrom, pto, tcpudp, sd); | 460 | npfctl_gennc_ports(nc, foff, fport, tport, tcpudp, sd); | |
414 | } | 461 | } | |
415 | } | 462 | } | |
416 | 463 | |||
417 | static void | 464 | static void | |
418 | npfctl_rulenc_block(void **nc, int nblocks[], var_t *cidr, var_t *ports, | 465 | npfctl_rulenc_block(void **nc, int nblocks[], var_t *cidr, var_t *ports, | |
419 | bool both, bool tcpudp, bool sd) | 466 | bool both, bool tcpudp, bool sd) | |
420 | { | 467 | { | |
421 | 468 | |||
422 | npfctl_rulenc_v4cidr(nc, nblocks, cidr, sd); | 469 | npfctl_rulenc_v4cidr(nc, nblocks, cidr, sd); | |
423 | if (ports == NULL) { | 470 | if (ports == NULL) { | |
424 | return; | 471 | return; | |
425 | } | 472 | } | |
426 | npfctl_rulenc_ports(nc, nblocks, ports, tcpudp, sd); | 473 | npfctl_rulenc_ports(nc, nblocks, ports, tcpudp, sd); | |
427 | if (!both) { | 474 | if (!both) { | |
428 | return; | 475 | return; | |
429 | } | 476 | } | |
430 | npfctl_rulenc_ports(nc, nblocks, ports, !tcpudp, sd); | 477 | npfctl_rulenc_ports(nc, nblocks, ports, !tcpudp, sd); | |
431 | } | 478 | } | |
432 | 479 | |||
433 | void | 480 | void | |
434 | npfctl_rule_protodata(prop_dictionary_t rl, char *proto, var_t *from, | 481 | npfctl_rule_protodata(prop_dictionary_t rl, char *proto, char *tcp_flags, | |
435 | var_t *fports, var_t *to, var_t *tports) | 482 | int icmp_type, int icmp_code, | |
483 | var_t *from, var_t *fports, var_t *to, var_t *tports) | |||
436 | { | 484 | { | |
437 | prop_data_t ncdata; | 485 | prop_data_t ncdata; | |
438 | bool icmp, tcpudp, both; | 486 | bool icmp, tcpudp, both; | |
439 | int nblocks[2] = { 0, 0 }; | 487 | int foff, nblocks[3] = { 0, 0, 0 }; | |
440 | void *ncptr, *nc; | 488 | void *ncptr, *nc; | |
441 | size_t sz; | 489 | size_t sz; | |
442 | 490 | |||
443 | /* | 491 | /* | |
444 | * Default: both TCP and UDP. | 492 | * Default: both TCP and UDP. | |
445 | */ | 493 | */ | |
446 | icmp = false; | 494 | icmp = false; | |
447 | tcpudp = true; | 495 | tcpudp = true; | |
448 | both = false; | 496 | both = false; | |
449 | if (proto == NULL) { | 497 | if (proto == NULL) { | |
450 | goto skip_proto; | 498 | goto skip_proto; | |
451 | } | 499 | } | |
452 | 500 | |||
453 | if (strcmp(proto, "icmp") == 0) { | 501 | if (strcmp(proto, "icmp") == 0) { | |
454 | /* ICMP case. */ | 502 | /* ICMP case. */ | |
455 | fports = NULL; | 503 | fports = NULL; | |
456 | tports = NULL; | 504 | tports = NULL; | |
457 | icmp = true; | 505 | icmp = true; | |
458 | nblocks[0] += 1; | |||
459 | 506 | |||
460 | } else if (strcmp(proto, "tcp") == 0) { | 507 | } else if (strcmp(proto, "tcp") == 0) { | |
461 | /* Just TCP. */ | 508 | /* Just TCP. */ | |
462 | tcpudp = true; | 509 | tcpudp = true; | |
463 | 510 | |||
464 | } else if (strcmp(proto, "udp") == 0) { | 511 | } else if (strcmp(proto, "udp") == 0) { | |
465 | /* Just UDP. */ | 512 | /* Just UDP. */ | |
466 | tcpudp = false; | 513 | tcpudp = false; | |
467 | 514 | |||
468 | } else { | 515 | } else { | |
469 | /* Default. */ | 516 | /* Default. */ | |
470 | } | 517 | } | |
471 | skip_proto: | 518 | skip_proto: | |
519 | if (icmp_type != -1) { | |||
520 | assert(tcp_flags == NULL); | |||
521 | icmp = true; | |||
522 | nblocks[2] += 1; | |||
523 | } | |||
524 | if (tcpudp && tcp_flags) { | |||
525 | assert(icmp_type == -1 && icmp_code == -1); | |||
526 | nblocks[2] += 1; | |||
527 | } | |||
472 | 528 | |||
473 | /* Calculate how blocks to determince n-code. */ | 529 | /* Calculate how blocks to determince n-code. */ | |
474 | if (from && from->v_count) { | 530 | if (from && from->v_count) { | |
475 | if (from->v_type == VAR_TABLE) | 531 | if (from->v_type == VAR_TABLE) | |
476 | nblocks[0] += 1; | 532 | nblocks[0] += 1; | |
477 | else | 533 | else | |
478 | nblocks[1] += from->v_count; | 534 | nblocks[1] += from->v_count; | |
479 | if (fports && fports->v_count) | 535 | if (fports && fports->v_count) | |
480 | nblocks[0] += fports->v_count * (both ? 2 : 1); | 536 | nblocks[0] += fports->v_count * (both ? 2 : 1); | |
481 | } | 537 | } | |
482 | if (to && to->v_count) { | 538 | if (to && to->v_count) { | |
483 | if (to->v_type == VAR_TABLE) | 539 | if (to->v_type == VAR_TABLE) | |
484 | nblocks[0] += 1; | 540 | nblocks[0] += 1; | |
485 | else | 541 | else | |
486 | nblocks[1] += to->v_count; | 542 | nblocks[1] += to->v_count; | |
487 | if (tports && tports->v_count) | 543 | if (tports && tports->v_count) | |
488 | nblocks[0] += tports->v_count * (both ? 2 : 1); | 544 | nblocks[0] += tports->v_count * (both ? 2 : 1); | |
489 | } | 545 | } | |
490 | 546 | |||
547 | /* Any n-code to generate? */ | |||
548 | if ((nblocks[0] + nblocks[1] + nblocks[2]) == 0) { | |||
549 | /* Done, if none. */ | |||
550 | return; | |||
551 | } | |||
552 | ||||
491 | /* Allocate memory for the n-code. */ | 553 | /* Allocate memory for the n-code. */ | |
492 | sz = npfctl_calc_ncsize(nblocks); | 554 | sz = npfctl_calc_ncsize(nblocks); | |
493 | ncptr = malloc(sz); | 555 | ncptr = malloc(sz); | |
494 | if (ncptr == NULL) { | 556 | if (ncptr == NULL) { | |
495 | perror("malloc"); | 557 | perror("malloc"); | |
496 | exit(EXIT_FAILURE); | 558 | exit(EXIT_FAILURE); | |
497 | } | 559 | } | |
498 | nc = ncptr; | 560 | nc = ncptr; | |
499 | 561 | |||
500 | /* Ethernet fragment (ETHERTYPE_IP), XXX. */ | 562 | /* | |
501 | npfctl_gennc_ether(&nc, npfctl_failure_offset(nblocks), htons(0x0800)); | 563 | * Generate v4 CIDR matching blocks and TCP/UDP port matching. | |
502 | 564 | */ | ||
503 | /* Generate v4 CIDR matching blocks and TCP/UDP port matching. */ | |||
504 | if (from) { | 565 | if (from) { | |
505 | npfctl_rulenc_block(&nc, nblocks, from, fports, | 566 | npfctl_rulenc_block(&nc, nblocks, from, fports, | |
506 | both, tcpudp, true); | 567 | both, tcpudp, true); | |
507 | } | 568 | } | |
508 | if (to) { | 569 | if (to) { | |
509 | npfctl_rulenc_block(&nc, nblocks, to, tports, | 570 | npfctl_rulenc_block(&nc, nblocks, to, tports, | |
510 | both, tcpudp, false); | 571 | both, tcpudp, false); | |
511 | } | 572 | } | |
512 | /* ICMP case. */ | 573 | ||
513 | if (icmp) { | 574 | if (icmp) { | |
514 | const int foff = npfctl_failure_offset(nblocks); | 575 | /* | |
515 | npfctl_gennc_icmp(&nc, foff, -1, -1); | 576 | * ICMP case. | |
577 | */ | |||
578 | nblocks[2]--; | |||
579 | foff = npfctl_failure_offset(nblocks); | |||
580 | npfctl_gennc_icmp(&nc, foff, icmp_type, icmp_code); | |||
581 | ||||
582 | } else if (tcpudp && tcp_flags) { | |||
583 | /* | |||
584 | * TCP case, flags. | |||
585 | */ | |||
586 | uint8_t tfl = 0, tfl_mask; | |||
587 | ||||
588 | nblocks[2]--; | |||
589 | foff = npfctl_failure_offset(nblocks); | |||
590 | if (!npfctl_parse_tcpfl(tcp_flags, &tfl, &tfl_mask)) { | |||
591 | errx(EXIT_FAILURE, "invalid TCP flags '%s'", tcp_flags); | |||
592 | } | |||
593 | npfctl_gennc_tcpfl(&nc, foff, tfl, tfl_mask); | |||
516 | } | 594 | } | |
517 | npfctl_gennc_complete(&nc); | 595 | npfctl_gennc_complete(&nc); | |
518 | 596 | |||
519 | if ((uintptr_t)nc - (uintptr_t)ncptr != sz) | 597 | if ((uintptr_t)nc - (uintptr_t)ncptr != sz) { | |
520 | errx(EXIT_FAILURE, "n-code size got wrong (%tu != %zu)", | 598 | errx(EXIT_FAILURE, "n-code size got wrong (%tu != %zu)", | |
521 | (uintptr_t)nc - (uintptr_t)ncptr, sz); | 599 | (uintptr_t)nc - (uintptr_t)ncptr, sz); | |
600 | } | |||
522 | 601 | |||
523 | #ifdef DEBUG | 602 | #ifdef DEBUG | |
524 | uint32_t *op = ncptr; | 603 | uint32_t *op = ncptr; | |
525 | size_t n = sz; | 604 | size_t n = sz; | |
526 | do { | 605 | do { | |
527 | DPRINTF(("\t> |0x%02x|\n", (u_int)*op)); | 606 | DPRINTF(("\t> |0x%02x|\n", (u_int)*op)); | |
528 | op++; | 607 | op++; | |
529 | n -= sizeof(*op); | 608 | n -= sizeof(*op); | |
530 | } while (n); | 609 | } while (n); | |
531 | #endif | 610 | #endif | |
532 | 611 | |||
533 | /* Create a final memory block of data, ready to send. */ | 612 | /* Create a final memory block of data, ready to send. */ | |
534 | ncdata = prop_data_create_data(ncptr, sz); | 613 | ncdata = prop_data_create_data(ncptr, sz); | |
@@ -555,25 +634,49 @@ npfctl_mk_nat(void) | @@ -555,25 +634,49 @@ npfctl_mk_nat(void) | |||
555 | pri = nat_prio_counter++; | 634 | pri = nat_prio_counter++; | |
556 | prop_dictionary_set(rl, "priority", | 635 | prop_dictionary_set(rl, "priority", | |
557 | prop_number_create_integer(pri)); | 636 | prop_number_create_integer(pri)); | |
558 | return rl; | 637 | return rl; | |
559 | } | 638 | } | |
560 | 639 | |||
561 | void | 640 | void | |
562 | npfctl_add_nat(prop_dictionary_t nat) | 641 | npfctl_add_nat(prop_dictionary_t nat) | |
563 | { | 642 | { | |
564 | prop_array_add(nat_arr, nat); | 643 | prop_array_add(nat_arr, nat); | |
565 | } | 644 | } | |
566 | 645 | |||
567 | void | 646 | void | |
568 | npfctl_nat_setup(prop_dictionary_t rl, char *iface, char *gwip) | 647 | npfctl_nat_setup(prop_dictionary_t rl, int type, int flags, | |
648 | char *iface, char *taddr, char *rport) | |||
569 | { | 649 | { | |
570 | const int attr = NPF_RULE_PASS | NPF_RULE_OUT | NPF_RULE_FINAL; | 650 | int attr = NPF_RULE_PASS | NPF_RULE_FINAL; | |
571 | in_addr_t addr, mask; | 651 | in_addr_t addr, mask; | |
572 | 652 | |||
653 | /* Translation type and flags. */ | |||
654 | prop_dictionary_set(rl, "type", | |||
655 | prop_number_create_integer(type)); | |||
656 | prop_dictionary_set(rl, "flags", | |||
657 | prop_number_create_integer(flags)); | |||
658 | ||||
573 | /* Interface and attributes. */ | 659 | /* Interface and attributes. */ | |
660 | attr |= (type == NPF_NATOUT) ? NPF_RULE_OUT : NPF_RULE_IN; | |||
574 | npfctl_rule_setattr(rl, attr, iface); | 661 | npfctl_rule_setattr(rl, attr, iface); | |
575 | 662 | |||
576 | /* Gateway IP, XXX should be no mask. */ | 663 | /* Translation IP, XXX should be no mask. */ | |
577 | npfctl_parse_cidr(gwip, &addr, &mask); | 664 | npfctl_parse_cidr(taddr, &addr, &mask); | |
578 | prop_dictionary_set(rl, "gateway_ip", prop_number_create_integer(addr)); | 665 | prop_dictionary_set(rl, "translation_ip", | |
666 | prop_number_create_integer(addr)); | |||
667 | ||||
668 | /* Translation port (for redirect case). */ | |||
669 | if (rport) { | |||
670 | in_port_t port; | |||
671 | bool range; | |||
672 | ||||
673 | if (!npfctl_parse_port(rport, &range, &port, &port)) { | |||
674 | errx(EXIT_FAILURE, "invalid service '%s'", rport); | |||
675 | } | |||
676 | if (range) { | |||
677 | errx(EXIT_FAILURE, "range is not supported for 'rdr'"); | |||
678 | } | |||
679 | prop_dictionary_set(rl, "translation_port", | |||
680 | prop_number_create_integer(port)); | |||
681 | } | |||
579 | } | 682 | } |