Thu Sep 16 04:53:27 2010 UTC ()
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.


(rmind)
diff -r1.3 -r1.4 src/share/man/man9/npf_ncode.9
diff -r1.1 -r1.2 src/sys/modules/npf/Makefile
diff -r1.1 -r1.2 src/sys/net/npf/files.npf
diff -r1.1 -r1.2 src/sys/net/npf/npf.h
diff -r1.1 -r1.2 src/sys/net/npf/npf_alg_icmp.c
diff -r1.1 -r1.2 src/sys/net/npf/npf_ctl.c
diff -r1.1 -r1.2 src/sys/net/npf/npf_handler.c
diff -r1.1 -r1.2 src/sys/net/npf/npf_impl.h
diff -r1.1 -r1.2 src/sys/net/npf/npf_inet.c
diff -r1.1 -r1.2 src/sys/net/npf/npf_instr.c
diff -r1.1 -r1.2 src/sys/net/npf/npf_mbuf.c
diff -r1.1 -r1.2 src/sys/net/npf/npf_nat.c
diff -r1.1 -r1.2 src/sys/net/npf/npf_ncode.h
diff -r1.1 -r1.2 src/sys/net/npf/npf_processor.c
diff -r1.1 -r1.2 src/sys/net/npf/npf_ruleset.c
diff -r1.1 -r1.2 src/sys/net/npf/npf_session.c
diff -r0 -r1.1 src/sys/net/npf/npf_sendpkt.c
diff -r1.1 -r1.2 src/usr.sbin/npf/npfctl/npf.conf.5
diff -r1.1 -r1.2 src/usr.sbin/npf/npfctl/npf_ncgen.c
diff -r1.1 -r1.2 src/usr.sbin/npf/npfctl/npf_parser.c
diff -r1.1 -r1.2 src/usr.sbin/npf/npfctl/npfctl.h
diff -r1.2 -r1.3 src/usr.sbin/npf/npfctl/npf_data.c

cvs diff -r1.3 -r1.4 src/share/man/man9/Attic/npf_ncode.9 (expand / switch to unified diff)

--- 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
@@ -1,14 +1,14 @@ @@ -1,14 +1,14 @@
1.\" $NetBSD: npf_ncode.9,v 1.3 2010/08/24 23:55:05 rmind Exp $ 1.\" $NetBSD: npf_ncode.9,v 1.4 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 22, 2010 30.Dd September 16, 2010
31.Dt NPF_NCODE 9 31.Dt NPF_NCODE 9
32.Os 32.Os
33.Sh NAME 33.Sh NAME
34.Nm npf_ncode 34.Nm npf_ncode
35.Nd NPF n-code processor 35.Nd NPF n-code processor
36.Sh SYNOPSIS 36.Sh SYNOPSIS
37.In net/npf_ncode.h 37.In net/npf_ncode.h
38.Ft int 38.Ft int
39.Fn npf_ncode_process \ 39.Fn npf_ncode_process \
40"npf_cache_t *npc" "const void *ncode" "nbuf_t *nbuf" "int layer" 40"npf_cache_t *npc" "const void *ncode" "nbuf_t *nbuf" "int layer"
41.Ft int 41.Ft int
42.Fn npf_ncode_validate "const void *ncode" "size_t sz" "int *errat" 42.Fn npf_ncode_validate "const void *ncode" "size_t sz" "int *errat"
43.\" ----- 43.\" -----
@@ -210,47 +210,52 @@ Return value to advance to layer 3 heade @@ -210,47 +210,52 @@ Return value to advance to layer 3 heade
210.\" - 210.\" -
211.It Sy 0x90 NPF_OPCODE_IP4MASK <s/d>, <network address>, <subnet mask> 211.It Sy 0x90 NPF_OPCODE_IP4MASK <s/d>, <network address>, <subnet mask>
212Match passed network address with subnet mask against source or destination 212Match passed network address with subnet mask against source or destination
213address in the IPv4 header. 213address in the IPv4 header.
214Address and mask should be in network byte order. 214Address and mask should be in network byte order.
215Value of first argument indicates whether source (if 0x1) or destination 215Value of first argument indicates whether source (if 0x1) or destination
216(if 0x0) address should be matched. 216(if 0x0) address should be matched.
217.It Sy 0x91 NPF_OPCODE_IP4TABLE <s/d>, <table id> 217.It Sy 0x91 NPF_OPCODE_IP4TABLE <s/d>, <table id>
218Match the source or destination address with NPF table contents 218Match the source or destination address with NPF table contents
219specified by table ID. 219specified by table ID.
220Value of the first argument indicates whether source (if 0x1) or 220Value of the first argument indicates whether source (if 0x1) or
221destination (if 0x0) address should be matched. 221destination (if 0x0) address should be matched.
222.\" - 222.\" -
223.It Sy 0x92 NPF_OPCODE_ICMP4 <type> <code> 223.It Sy 0x92 NPF_OPCODE_ICMP4 <type/code>
224Match ICMP type and code of the packet, unless a value of ~0 (all bits set) 224Match that packet is ICMP and compare type and code values, if required.
225is passed, which indicates that comparison should not be performed. 225Highest 32nd and 31st bits indicate whether the type and code values,
 226accordingly, should be compared.
 227If comparison is required, the type and code values are represented by
 228lower 16 bits.
 229The higher 8 bits represent type, and the lower 8 bits code number.
226.\" - 230.\" -
227.It Sy 0xa0 NPF_OPCODE_TCP_PORT <s/d>, <port range> 231.It Sy 0xa0 NPF_OPCODE_TCP_PORT <s/d>, <port range>
228Match the source or destination port with a specified port range. 232Match the TCP source or destination port with a specified port range.
229The higher 16 bits of the second argument represent the "from" and 233The higher 16 bits of the second argument represent the "from" and
230the lower 16 bits represent the "to" values of the range. 234the lower 16 bits represent the "to" values of the range.
231The 32-bit port range value is in host byte order, however the actual 235The 32-bit port range value is in host byte order, however the actual
232"from" and "to" values should be in network byte order. 236"from" and "to" values should be in network byte order.
233The value of the first argument indicates whether source (if 0x1) or 237The value of the first argument indicates whether source (if 0x1) or
234destination (if 0x0) port should be matched. 238destination (if 0x0) port should be matched.
235.\" - 239.\" -
236.It Sy 0xa1 NPF_OPCODE_UDP_PORT <s/d>, <port range> 240.It Sy 0xa1 NPF_OPCODE_UDP_PORT <s/d>, <port range>
237Match the source or destination port with a specified port range. 241Equivalent of
238The higher 16 bits of the second argument represent the "from" and 242.Dv NPF_OPCODE_TCP_PORT ,
239the lower 16 bits represent the "to" values of range. 243but for UDP protocol.
240The 32-bit port range value is in host byte order, however the actual 244.\" -
241"from" and "to" values should be in network byte order. 245.It Sy 0xa2 NPF_OPCODE_TCP_FLAGS <fl/mask>
242The value of the first argument indicates whether source (if 0x1) or 246Match the TCP flags with the a specified flags and mask,
243destination (if 0x0) port should be matched. 247represented by the lower 16 bits.
 248The higher 8 bits represent flags and the lower 8 bits mask to apply.
244.El 249.El
245.\" ----- 250.\" -----
246.Sh CODE REFERENCES 251.Sh CODE REFERENCES
247This section describes places within the 252This section describes places within the
248.Nx 253.Nx
249source tree where actual code implementing the 254source tree where actual code implementing the
250.Nm 255.Nm
251subsystem 256subsystem
252can be found. 257can be found.
253All pathnames are relative to 258All pathnames are relative to
254.Pa /usr/src . 259.Pa /usr/src .
255.Pp 260.Pp
256The 261The

cvs diff -r1.1 -r1.2 src/sys/modules/npf/Makefile (expand / switch to unified diff)

--- 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
7KMOD= npf 7KMOD= npf
8 8
9SRCS= npf.c npf_ctl.c npf_handler.c npf_instr.c npf_mbuf.c 9SRCS= npf.c npf_ctl.c npf_handler.c npf_instr.c npf_mbuf.c
10SRCS+= npf_processor.c npf_ruleset.c npf_tableset.c npf_inet.c 10SRCS+= npf_processor.c npf_ruleset.c npf_tableset.c npf_inet.c
11SRCS+= npf_session.c npf_nat.c npf_alg.c 11SRCS+= npf_session.c npf_nat.c npf_sendpkt.c npf_alg.c
12 12
13.include <bsd.kmodule.mk> 13.include <bsd.kmodule.mk>

cvs diff -r1.1 -r1.2 src/sys/net/npf/files.npf (expand / switch to unified diff)

--- 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
10defpseudo npf: ifnet 10defpseudo npf: ifnet
11 11
 12# Core
12file net/npf/npf.c npf 13file net/npf/npf.c npf
13file net/npf/npf_ctl.c npf 14file net/npf/npf_ctl.c npf
14file net/npf/npf_handler.c npf 15file net/npf/npf_handler.c npf
15file net/npf/npf_instr.c npf 16file net/npf/npf_instr.c npf
16file net/npf/npf_mbuf.c npf 17file net/npf/npf_mbuf.c npf
17file net/npf/npf_processor.c npf 18file net/npf/npf_processor.c npf
18file net/npf/npf_ruleset.c npf 19file net/npf/npf_ruleset.c npf
19file net/npf/npf_tableset.c npf 20file net/npf/npf_tableset.c npf
20file net/npf/npf_inet.c npf 21file net/npf/npf_inet.c npf
21file net/npf/npf_session.c npf 22file net/npf/npf_session.c npf
22file net/npf/npf_nat.c npf 23file net/npf/npf_nat.c npf
23file net/npf/npf_alg.c npf 24file net/npf/npf_alg.c npf
 25file net/npf/npf_sendpkt.c npf
 26
 27# ALGs
 28file net/npf/npf_alg_icmp.c npf

cvs diff -r1.1 -r1.2 src/sys/net/npf/npf.h (expand / switch to unified diff)

--- 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. */
81typedef struct { 81typedef 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 *,
117int nbuf_add_tag(nbuf_t *, uint32_t, uint32_t); 116int nbuf_add_tag(nbuf_t *, uint32_t, uint32_t);
118int nbuf_find_tag(nbuf_t *, uint32_t, void **); 117int nbuf_find_tag(nbuf_t *, uint32_t, void **);
119 118
120/* Ruleset interface. */ 119/* Ruleset interface. */
121npf_rule_t * npf_rule_alloc(int, pri_t, int, void *, size_t); 120npf_rule_t * npf_rule_alloc(int, pri_t, int, void *, size_t);
122void npf_rule_free(npf_rule_t *); 121void npf_rule_free(npf_rule_t *);
123void npf_activate_rule(npf_rule_t *); 122void npf_activate_rule(npf_rule_t *);
124void npf_deactivate_rule(npf_rule_t *); 123void npf_deactivate_rule(npf_rule_t *);
125 124
126npf_hook_t * npf_hook_register(npf_rule_t *, 125npf_hook_t * npf_hook_register(npf_rule_t *,
127 void (*)(const npf_cache_t *, void *), void *); 126 void (*)(const npf_cache_t *, void *), void *);
128void npf_hook_unregister(npf_rule_t *, npf_hook_t *); 127void 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_ */

cvs diff -r1.1 -r1.2 src/sys/net/npf/npf_alg_icmp.c (expand / switch to unified diff)

--- 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);

cvs diff -r1.1 -r1.2 src/sys/net/npf/npf_ctl.c (expand / switch to unified diff)

--- 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 */
462int 476int
463npfctl_table(void *data) 477npfctl_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);

cvs diff -r1.1 -r1.2 src/sys/net/npf/npf_handler.c (expand / switch to unified diff)

--- 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 */
56static struct pfil_head * npf_ph_if = NULL; 56static struct pfil_head * npf_ph_if = NULL;
57static struct pfil_head * npf_ph_inet = NULL; 57static struct pfil_head * npf_ph_inet = NULL;
58 58
 59static bool default_pass = true;
 60
59int npf_packet_handler(void *, struct mbuf **, struct ifnet *, int); 61int 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 */
64static int 66static int
65npf_ifhook(void *arg, struct mbuf **mp, struct ifnet *ifp, int di) 67npf_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 */
76int 78int
77npf_packet_handler(void *arg, struct mbuf **mp, struct ifnet *ifp, int di) 79npf_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 }
 129pass:
 130 KASSERT(error == 0);
 131 /*
 132 * Perform NAT.
 133 */
 134 error = npf_do_nat(&npc, se, nbuf, ifp, di);
125out: 135out:
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 */
145int 162int
146npf_register_pfil(void) 163npf_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
178fail: 195fail:
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 */
188void 205void
189npf_unregister_pfil(void) 206npf_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}

cvs diff -r1.1 -r1.2 src/sys/net/npf/npf_impl.h (expand / switch to unified diff)

--- 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. */
89int npfctl_switch(void *); 89int npfctl_switch(void *);
90int npfctl_reload(u_long, void *); 90int npfctl_reload(u_long, void *);
91int npfctl_table(void *); 91int npfctl_table(void *);
92 92
93/* Packet filter hooks. */ 93/* Packet filter hooks. */
94int npf_register_pfil(void); 94int npf_register_pfil(void);
95void npf_unregister_pfil(void); 95void npf_unregister_pfil(void);
96 96
97/* Protocol helpers. */ 97/* Protocol helpers. */
98bool npf_ip4_proto(npf_cache_t *, nbuf_t *, void *); 98bool npf_ip4_proto(npf_cache_t *, nbuf_t *, void *);
99bool npf_fetch_ip4addrs(npf_cache_t *, nbuf_t *, void *); 99bool npf_fetch_ip4addrs(npf_cache_t *, nbuf_t *, void *);
100bool npf_fetch_ports(npf_cache_t *, nbuf_t *, void *, const int); 100bool npf_fetch_ports(npf_cache_t *, nbuf_t *, void *, const int);
 101bool npf_fetch_tcpfl(npf_cache_t *, nbuf_t *, void *);
101bool npf_fetch_icmp(npf_cache_t *, nbuf_t *, void *); 102bool npf_fetch_icmp(npf_cache_t *, nbuf_t *, void *);
102bool npf_cache_all_ip4(npf_cache_t *, nbuf_t *, const int); 103bool npf_cache_all(npf_cache_t *, nbuf_t *);
103 104
104bool npf_rwrport(npf_cache_t *, nbuf_t *, void *, const int, 105bool npf_rwrport(npf_cache_t *, nbuf_t *, void *, const int,
105 in_port_t, in_addr_t); 106 in_port_t, in_addr_t);
106bool npf_rwrip(npf_cache_t *, nbuf_t *, void *, const int, in_addr_t); 107bool npf_rwrip(npf_cache_t *, nbuf_t *, void *, const int, in_addr_t);
107 108
108uint16_t npf_fixup16_cksum(uint16_t, uint16_t, uint16_t); 109uint16_t npf_fixup16_cksum(uint16_t, uint16_t, uint16_t);
109uint16_t npf_fixup32_cksum(uint16_t, uint32_t, uint32_t); 110uint16_t npf_fixup32_cksum(uint16_t, uint32_t, uint32_t);
110 111
 112void npf_return_block(npf_cache_t *, nbuf_t *, const int);
 113
111/* Complex instructions. */ 114/* Complex instructions. */
112int npf_match_ether(nbuf_t *, int, int, uint16_t, uint32_t *); 115int npf_match_ether(nbuf_t *, int, int, uint16_t, uint32_t *);
113int npf_match_ip4table(npf_cache_t *, nbuf_t *, void *, 116int npf_match_ip4table(npf_cache_t *, nbuf_t *, void *,
114 const int, const u_int); 117 const int, const u_int);
115int npf_match_ip4mask(npf_cache_t *, nbuf_t *, void *, 118int 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);
117int npf_match_tcp_ports(npf_cache_t *, nbuf_t *, void *, 120int npf_match_tcp_ports(npf_cache_t *, nbuf_t *, void *,
118 const int, const uint32_t); 121 const int, const uint32_t);
119int npf_match_udp_ports(npf_cache_t *, nbuf_t *, void *, 122int npf_match_udp_ports(npf_cache_t *, nbuf_t *, void *,
120 const int, const uint32_t); 123 const int, const uint32_t);
121int npf_match_icmp4(npf_cache_t *, nbuf_t *, void *, 124int npf_match_icmp4(npf_cache_t *, nbuf_t *, void *, const uint32_t);
122 const int, const int); 125int npf_match_tcpfl(npf_cache_t *, nbuf_t *, void *, const uint32_t);
123 126
124/* Tableset interface. */ 127/* Tableset interface. */
125int npf_tableset_sysinit(void); 128int npf_tableset_sysinit(void);
126void npf_tableset_sysfini(void); 129void npf_tableset_sysfini(void);
127 130
128npf_tableset_t *npf_tableset_create(void); 131npf_tableset_t *npf_tableset_create(void);
129void npf_tableset_destroy(npf_tableset_t *); 132void npf_tableset_destroy(npf_tableset_t *);
130int npf_tableset_insert(npf_tableset_t *, npf_table_t *); 133int npf_tableset_insert(npf_tableset_t *, npf_table_t *);
131npf_tableset_t *npf_tableset_reload(npf_tableset_t *); 134npf_tableset_t *npf_tableset_reload(npf_tableset_t *);
132 135
133npf_table_t * npf_table_create(u_int, int, size_t); 136npf_table_t * npf_table_create(u_int, int, size_t);
134void npf_table_destroy(npf_table_t *); 137void npf_table_destroy(npf_table_t *);
135void npf_table_ref(npf_table_t *); 138void 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. */
148int npf_ruleset_sysinit(void); 151int npf_ruleset_sysinit(void);
149void npf_ruleset_sysfini(void); 152void npf_ruleset_sysfini(void);
150 153
151npf_ruleset_t * npf_ruleset_create(void); 154npf_ruleset_t * npf_ruleset_create(void);
152void npf_ruleset_destroy(npf_ruleset_t *); 155void npf_ruleset_destroy(npf_ruleset_t *);
153void npf_ruleset_insert(npf_ruleset_t *, npf_rule_t *); 156void npf_ruleset_insert(npf_ruleset_t *, npf_rule_t *);
154void npf_ruleset_reload(npf_ruleset_t *, npf_tableset_t *); 157void npf_ruleset_reload(npf_ruleset_t *, npf_tableset_t *);
155 158
156npf_rule_t * npf_ruleset_match(npf_ruleset_t *, npf_cache_t *, nbuf_t *, 159npf_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);
158npf_rule_t * npf_ruleset_inspect(npf_cache_t *, nbuf_t *, 161npf_rule_t * npf_ruleset_inspect(npf_cache_t *, nbuf_t *,
159 struct ifnet *, const int, const int); 162 struct ifnet *, const int, const int);
160int npf_rule_apply(const npf_cache_t *, npf_rule_t *, bool *); 163int npf_rule_apply(const npf_cache_t *, npf_rule_t *, bool *, int *);
161npf_ruleset_t * npf_rule_subset(npf_rule_t *); 164npf_ruleset_t * npf_rule_subset(npf_rule_t *);
162 165
163npf_natpolicy_t *npf_rule_getnat(const npf_rule_t *); 166npf_natpolicy_t *npf_rule_getnat(const npf_rule_t *);
164void npf_rule_setnat(npf_rule_t *, npf_natpolicy_t *); 167void npf_rule_setnat(npf_rule_t *, npf_natpolicy_t *);
165 168
166/* State handling interface. */ 169/* State handling interface. */
167int npf_session_sysinit(void); 170int npf_session_sysinit(void);
168void npf_session_sysfini(void); 171void npf_session_sysfini(void);
169int npf_session_tracking(bool); 172int npf_session_tracking(bool);
170 173
171npf_session_t * npf_session_inspect(npf_cache_t *, nbuf_t *, 174npf_session_t * npf_session_inspect(npf_cache_t *, nbuf_t *,
172 struct ifnet *, const int, const int); 175 struct ifnet *, const int);
173npf_session_t * npf_session_establish(const npf_cache_t *, 176npf_session_t * npf_session_establish(const npf_cache_t *,
174 npf_nat_t *, const int); 177 npf_nat_t *, const int);
175void npf_session_release(npf_session_t *); 178void npf_session_release(npf_session_t *);
176bool npf_session_pass(const npf_session_t *); 179bool npf_session_pass(const npf_session_t *);
177 180void npf_session_setpass(npf_session_t *);
178npf_nat_t * npf_session_retnat(const npf_session_t *); 
179 
180void npf_session_link(npf_session_t *, npf_session_t *); 181void npf_session_link(npf_session_t *, npf_session_t *);
181npf_nat_t * npf_session_retlinknat(const npf_session_t *); 182npf_nat_t * npf_session_retnat(npf_session_t *, const int, bool *);
182 183
183/* NAT. */ 184/* NAT. */
184void npf_nat_sysinit(void); 185void npf_nat_sysinit(void);
185void npf_nat_sysfini(void); 186void npf_nat_sysfini(void);
186npf_natpolicy_t *npf_nat_newpolicy(in_addr_t); 187npf_natpolicy_t *npf_nat_newpolicy(int, int, in_addr_t, in_port_t);
187void npf_nat_freepolicy(npf_natpolicy_t *); 188void npf_nat_freepolicy(npf_natpolicy_t *);
188void npf_nat_flush(void); 189void npf_nat_flush(void);
189void npf_nat_reload(npf_ruleset_t *); 190void npf_nat_reload(npf_ruleset_t *);
190 191
191int npf_natout(npf_cache_t *, npf_session_t *, nbuf_t *, 192int npf_do_nat(npf_cache_t *, npf_session_t *, nbuf_t *,
192 struct ifnet *, const int); 193 struct ifnet *, const int);
193int npf_natin(npf_cache_t *, npf_session_t *, nbuf_t *, const int); 
194 
195void npf_nat_expire(npf_nat_t *); 194void npf_nat_expire(npf_nat_t *);
196void npf_nat_getlocal(npf_nat_t *, in_addr_t *, in_port_t *); 195void npf_nat_getorig(npf_nat_t *, in_addr_t *, in_port_t *);
197void npf_nat_setalg(npf_nat_t *, npf_alg_t *, uintptr_t); 196void npf_nat_setalg(npf_nat_t *, npf_alg_t *, uintptr_t);
198 197
199/* ALG interface. */ 198/* ALG interface. */
200void npf_alg_sysinit(void); 199void npf_alg_sysinit(void);
201void npf_alg_sysfini(void); 200void npf_alg_sysfini(void);
202npf_alg_t * npf_alg_register(npf_algfunc_t, npf_algfunc_t, 201npf_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);
204int npf_alg_unregister(npf_alg_t *); 203int npf_alg_unregister(npf_alg_t *);
205void npf_alg_match(npf_cache_t *, nbuf_t *, npf_nat_t *); 204void npf_alg_match(npf_cache_t *, nbuf_t *, npf_nat_t *);
206void npf_alg_exec(npf_cache_t *, nbuf_t *, npf_nat_t *, const int ); 205void npf_alg_exec(npf_cache_t *, nbuf_t *, npf_nat_t *, const int );
207bool npf_alg_sessionid(npf_cache_t *, nbuf_t *, npf_cache_t *); 206bool npf_alg_sessionid(npf_cache_t *, nbuf_t *, npf_cache_t *);
208 207
209/* Debugging routines. */ 208/* Debugging routines. */

cvs diff -r1.1 -r1.2 src/sys/net/npf/npf_inet.c (expand / switch to unified diff)

--- 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
245static inline bool 245/*
 246 * npf_fetch_tcpfl: fetch TCP flags and store into the cache.
 247 */
 248bool
246npf_fetch_tcpfl(npf_cache_t *npc, nbuf_t *nbuf, void *n_ptr) 249npf_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 */
263bool 266bool
264npf_cache_all_ip4(npf_cache_t *npc, nbuf_t *nbuf, const int layer) 267npf_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)) {

cvs diff -r1.1 -r1.2 src/sys/net/npf/Attic/npf_instr.c (expand / switch to unified diff)

--- 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 */
183int 183int
184npf_match_icmp4(npf_cache_t *npc, nbuf_t *nbuf, void *n_ptr, 184npf_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 */
 221int
 222npf_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}

cvs diff -r1.1 -r1.2 src/sys/net/npf/npf_mbuf.c (expand / switch to unified diff)

--- 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 */
52void * 52void *
53nbuf_dataptr(nbuf_t *nbuf) 53nbuf_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 */
174int 176int
175nbuf_fetch_datum(nbuf_t *nbuf, void *n_ptr, size_t len, void *buf) 177nbuf_fetch_datum(nbuf_t *nbuf, void *n_ptr, size_t len, void *buf)
176{ 178{
177 179

cvs diff -r1.1 -r1.2 src/sys/net/npf/npf_nat.c (expand / switch to unified diff)

--- 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. */
95struct npf_natpolicy { 111struct 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. */
102struct npf_nat { 121struct 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
114static npf_ruleset_t * nat_ruleset; 133static npf_ruleset_t * nat_ruleset __read_mostly;
115static LIST_HEAD(, npf_natpolicy) nat_policy_list; 134static LIST_HEAD(, npf_natpolicy) nat_policy_list __read_mostly;
116static pool_cache_t nat_cache; 135static 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
122void 141void
123npf_nat_sysinit(void) 142npf_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
133void 152void
134npf_nat_sysfini(void) 153npf_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 */
149npf_natpolicy_t * 168npf_natpolicy_t *
150npf_nat_newpolicy(in_addr_t gip) 169npf_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 }
 210nopm:
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 */
197void 225void
198npf_nat_freepolicy(npf_natpolicy_t *np) 226npf_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 */
215void 244void
216npf_nat_reload(npf_ruleset_t *nset) 245npf_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 */
291int 316static npf_natpolicy_t *
292npf_natout(npf_cache_t *npc, npf_session_t *se, nbuf_t *nbuf, 317npf_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 */
 329static npf_nat_t *
 330npf_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 */
 381static int
 382npf_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 */
 465int
 466npf_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 }
364skip: 521translate:
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);
413out: 546out:
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 */ 
434int 
435npf_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 */
490void 564void
491npf_nat_getlocal(npf_nat_t *nt, in_addr_t *addr, in_port_t *port) 565npf_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
498void 572void
499npf_nat_setalg(npf_nat_t *nt, npf_alg_t *alg, uintptr_t arg) 573npf_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 */
509void 583void
510npf_nat_expire(npf_nat_t *nt) 584npf_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
522void 597void
523npf_nat_dump(npf_nat_t *nt) 598npf_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) {
533skip: 608skip:
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

cvs diff -r1.1 -r1.2 src/sys/net/npf/Attic/npf_ncode.h (expand / switch to unified diff)

--- 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

cvs diff -r1.1 -r1.2 src/sys/net/npf/Attic/npf_processor.c (expand / switch to unified diff)

--- 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
164process_next: 164process_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;
317fail: 322fail:
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;

cvs diff -r1.1 -r1.2 src/sys/net/npf/npf_ruleset.c (expand / switch to unified diff)

--- 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 */
237void 238void
238npf_activate_rule(npf_rule_t *rl) 239npf_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 */
326void 327void
327npf_hook_unregister(npf_rule_t *rl, npf_hook_t *hk) 328npf_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 */
345npf_rule_t * 343npf_rule_t *
346npf_ruleset_match(npf_ruleset_t *rlset0, npf_cache_t *npc, nbuf_t *nbuf, 344npf_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));
353reinspect: 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) { 
387final: 
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 */
401npf_rule_t * 387npf_rule_t *
402npf_ruleset_inspect(npf_cache_t *npc, nbuf_t *nbuf, 388npf_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); 397reinspect:
 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 */
421int 422int
422npf_rule_apply(const npf_cache_t *npc, npf_rule_t *rl, bool *keepstate) 423npf_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
452void 456void
453npf_rulenc_dump(npf_rule_t *rl) 457npf_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

cvs diff -r1.1 -r1.2 src/sys/net/npf/Attic/npf_session.c (expand / switch to unified diff)

--- 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 
110struct npf_session { 111struct 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
144LIST_HEAD(npf_sesslist, npf_session); 146LIST_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
149typedef struct { 151typedef 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. */ 157static int sess_tracking __cacheline_aligned;
156static int sess_tracking; 
157 158
158/* Session hash table, lock and session cache. */ 159/* Session hash table, lock and session cache. */
159static npf_sess_hash_t * sess_hashtbl; 160static npf_sess_hash_t * sess_hashtbl __read_mostly;
160static pool_cache_t sess_cache; 161static pool_cache_t sess_cache __read_mostly;
161 162
162static kmutex_t sess_lock; 163static kmutex_t sess_lock;
163static kcondvar_t sess_cv; 164static kcondvar_t sess_cv;
164static lwp_t * sess_gc_lwp; 165static 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. */
169static const u_int sess_expire_table[ ] = { 170static 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
180static void sess_tracking_stop(void); 184static void sess_tracking_stop(void);
181static void npf_session_worker(void *); 185static 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
196int 200int
@@ -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
227static signed int 231static signed int
228sess_rbtree_cmp_nodes(const struct rb_node *n1, const struct rb_node *n2) 232sess_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
248static signed int 271static signed int
249sess_rbtree_cmp_key(const struct rb_node *n1, const void *key) 272sess_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
281static const struct rb_tree_ops sess_rbtree_ops = { 305static 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
286static inline npf_sess_hash_t * 310static inline npf_sess_hash_t *
287sess_hash_bucket(const npf_cache_t *key) 311sess_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
 323static npf_sess_hash_t *
 324sess_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
303static int 346static int
304sess_tracking_start(void) 347sess_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
338static void 372static void
339sess_tracking_stop(void) 373sess_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 */
448npf_session_t * 482npf_session_t *
449npf_session_inspect(npf_cache_t *npc, nbuf_t *nbuf, 483npf_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 */
593bool 628bool
594npf_session_pass(const npf_session_t *se) 629npf_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 */
605void 640void
606npf_session_release(npf_session_t *se) 641npf_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 */
616npf_nat_t * 656void
617npf_session_retnat(const npf_session_t *se) 657npf_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 */
624void 668void
625npf_session_link(npf_session_t *se, npf_session_t *natse) 669npf_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 */
634npf_nat_t * 685npf_nat_t *
635npf_session_retlinknat(const npf_session_t *se) 686npf_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 */
649static inline bool 701static inline bool
650npf_session_expired(const npf_session_t *se, const struct timespec *tsnow) 702npf_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 }

File Added: src/sys/net/npf/npf_sendpkt.c
/*	$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;
	}
}

cvs diff -r1.1 -r1.2 src/usr.sbin/npf/npfctl/npf.conf.5 (expand / switch to unified diff)

--- 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
39is the default configuration file for NPF packet filter. 39is the default configuration file for NPF packet filter.
40It can contain definitions, grouped rules, and tables. 40It can contain definitions, grouped rules, and tables.
41.Sh DEFINITIONS 41.Sh DEFINITIONS
42Definitions are general purpose keywords which can be used in the 42Definitions are general purpose keywords which can be used in the
43ruleset to make it more flexible and easier to manage. 43ruleset 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
85is useful for large static tables. 85is useful for large static tables.
86There are two types of storage: "tree" (red-black tree is used) and 86There are two types of storage: "tree" (red-black tree is used) and
87"hash". 87"hash".
88.Sh NAT 88.Sh NAT
89Special rules for Network Address Translation (NAT) can be added. 89Special rules for Network Address Translation (NAT) can be added.
90Translation is performed on specified interface, assigning a specified 90Translation is performed on specified interface, assigning a specified
91address of said interface. 91address of said interface.
92Minimal filtering criteria on local network and destination are provided. 92Minimal filtering criteria on local network and destination are provided.
93.\" ----- 93.\" -----
94.Sh GRAMMAR 94.Sh GRAMMAR
95.Bd -literal 95.Bd -literal
96line = ( def | table | nat | group ) 96line = ( def | table | nat | group )
97 97
98def = ( "{ a, b, ... }" | "text" | "$\*[Lt]interface\*[Gt]" ) 98def = ( \*[Lt]name\*[Gt] "=" "{ a, b, ... }" | "text" | "$\*[Lt]interface\*[Gt]" )
99iface = ( \*[Lt]interface\*[Gt] | def ) 99iface = ( \*[Lt]interface\*[Gt] | def )
100 100
101table = "table" \*[Lt]tid\*[Gt] "type" ( "hash" | "tree" ) 101table = "table" \*[Lt]tid\*[Gt] "type" ( "hash" | "tree" )
102 ( "dynamic" | "file" \*[Lt]path\*[Gt] ) 102 ( "dynamic" | "file" \*[Lt]path\*[Gt] )
103 103
104nat = "nat" iface "from" \*[Lt]addr/mask\*[Gt] "to" \*[Lt]addr/mask\*[Gt] "->" \*[Lt]addr\*[Gt] 104nat = "nat" iface filt-opts "->" \*[Lt]addr\*[Gt]
 105binat = "binat" iface filt-opts "->" \*[Lt]addr\*[Gt]
 106rdr = "rdr" iface filt-opts "->" \*[Lt]addr\*[Gt] port-opts
105 107
106group = "group" "(" ( "default" | group-opts ) "") ruleset 108group = "group" "(" ( "default" | group-opts ) "") ruleset
107group-opts = "interface" iface "," [ "in" | "out" ] 109group-opts = "interface" iface "," [ "in" | "out" ]
108 110
109ruleset = "{" rule1 \*[Lt]newline\*[Gt], rule2 \*[Lt]newline\*[Gt], ... "}" 111ruleset = "{" rule1 \*[Lt]newline\*[Gt], rule2 \*[Lt]newline\*[Gt], ... "}"
110 112
111rule = ( "block" | "pass" ) [ "in" | out" ] rule-opts 113rule = ( "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
 117block-opts = [ "return-rst" | "return-icmp" | "return" ]
115rule-opts = [ "log" ] [ "count" ] [ "quick" ] 118rule-opts = [ "log" ] [ "count" ] [ "quick" ]
116filt-opts = [ "from" ( iface | def | \*[Lt]addr/mask\*[Gt] | \*[Lt]tid\*[Gt] ) port-opts ] 119filt-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 ]
118port-opts = [ "port" ( \*[Lt]port-num\*[Gt] | \*[Lt]port-from\*[Gt] ":" \*[Lt]port-to\*[Gt] | def ) ] 121port-opts = [ "port" ( \*[Lt]port-num\*[Gt] | \*[Lt]port-from\*[Gt] ":" \*[Lt]port-to\*[Gt] | def ) ]
 122proto-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
124control device 128control device
125.It Pa /etc/npf.conf 129.It Pa /etc/npf.conf
126default configuration file 130default configuration file
127.El 131.El
128.\" ----- 132.\" -----
129.Sh EXAMPLES 133.Sh EXAMPLES
130.Bd -literal 134.Bd -literal
131ext_if = "wm0" 135ext_if = "wm0"

cvs diff -r1.1 -r1.2 src/usr.sbin/npf/npfctl/Attic/npf_ncgen.c (expand / switch to unified diff)

--- 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 */
46size_t 46size_t
47npfctl_calc_ncsize(int nblocks[]) 47npfctl_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 */
65size_t 65size_t
66npfctl_failure_offset(int nblocks[]) 66npfctl_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 */
81void 84void
82npfctl_gennc_ether(void **ncptr, int foff, uint16_t ethertype) 85npfctl_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 */
115void 120void
116npfctl_gennc_v4cidr(void **ncptr, int foff, 121npfctl_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 */
160void 165void
161npfctl_gennc_icmp(void **ncptr, int foff, int code, int type) 166npfctl_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 */
182void 187void
183npfctl_gennc_tbl(void **ncptr, int foff, u_int tid, bool sd) 188npfctl_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 */
 208void
 209npfctl_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 */
203void 228void
204npfctl_gennc_complete(void **ncptr) 229npfctl_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;

cvs diff -r1.1 -r1.2 src/usr.sbin/npf/npfctl/Attic/npf_parser.c (expand / switch to unified diff)

--- 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 */
152static inline int 152static inline int
153npfctl_parserule(char *buf, prop_dictionary_t rl) 153npfctl_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 }
283last: 335last:
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
309static inline int 362static 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 */
455static inline int 509static inline int
456npfctl_parse_nat(char *buf, prop_dictionary_t nat) 510npfctl_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 */
516static inline int 626static inline int
517npfctl_parsevar(char *buf) 627npfctl_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 }

cvs diff -r1.1 -r1.2 src/usr.sbin/npf/npfctl/npfctl.h (expand / switch to unified diff)

--- 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
70void * zalloc(size_t); 70void * zalloc(size_t);
71char * xstrdup(const char *); 71char * xstrdup(const char *);
72 72
73void npfctl_init_data(void); 73void npfctl_init_data(void);
74int npfctl_ioctl_send(int); 74int npfctl_ioctl_send(int);
75 75
76bool npfctl_parse_v4mask(char *, in_addr_t *, in_addr_t *); 76bool npfctl_parse_v4mask(char *, in_addr_t *, in_addr_t *);
77 77
78prop_dictionary_t npfctl_mk_rule(bool); 78prop_dictionary_t npfctl_mk_rule(bool);
79void npfctl_add_rule(prop_dictionary_t, prop_dictionary_t); 79void npfctl_add_rule(prop_dictionary_t, prop_dictionary_t);
80void npfctl_rule_setattr(prop_dictionary_t, int, char *); 80void npfctl_rule_setattr(prop_dictionary_t, int, char *);
81void npfctl_rule_protodata(prop_dictionary_t, char *, var_t *, 81void 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 *);
83void npfctl_rule_icmpdata(prop_dictionary_t, var_t *, var_t *); 83void npfctl_rule_icmpdata(prop_dictionary_t, var_t *, var_t *);
84 84
85prop_dictionary_t npfctl_lookup_table(char *); 85prop_dictionary_t npfctl_lookup_table(char *);
86prop_dictionary_t npfctl_mk_table(void); 86prop_dictionary_t npfctl_mk_table(void);
87void npfctl_table_setup(prop_dictionary_t, char *, char *); 87void npfctl_table_setup(prop_dictionary_t, char *, char *);
88void npfctl_construct_table(prop_dictionary_t, char *); 88void npfctl_construct_table(prop_dictionary_t, char *);
89void npfctl_add_table(prop_dictionary_t); 89void npfctl_add_table(prop_dictionary_t);
90 90
91prop_dictionary_t npfctl_mk_nat(void); 91prop_dictionary_t npfctl_mk_nat(void);
92void npfctl_add_nat(prop_dictionary_t); 92void npfctl_add_nat(prop_dictionary_t);
93void npfctl_nat_setup(prop_dictionary_t, char *, char *); 93void npfctl_nat_setup(prop_dictionary_t, int, int,
 94 char *, char *, char *);
94 95
95size_t npfctl_calc_ncsize(int []); 96size_t npfctl_calc_ncsize(int []);
96size_t npfctl_failure_offset(int []); 97size_t npfctl_failure_offset(int []);
97 98
98void npfctl_gennc_ether(void **, int, uint16_t); 99void npfctl_gennc_ether(void **, int, uint16_t);
99void npfctl_gennc_v4cidr(void **, int, 100void npfctl_gennc_v4cidr(void **, int,
100 in_addr_t, in_addr_t, bool); 101 in_addr_t, in_addr_t, bool);
101void npfctl_gennc_icmp(void **, int, int, int); 102void npfctl_gennc_icmp(void **, int, int, int);
 103void npfctl_gennc_tcpfl(void **, int , uint8_t, uint8_t);
102void npfctl_gennc_ports(void **, int, 104void npfctl_gennc_ports(void **, int,
103 in_port_t, in_port_t, bool, bool); 105 in_port_t, in_port_t, bool, bool);
104void npfctl_gennc_tbl(void **, int, u_int , bool); 106void npfctl_gennc_tbl(void **, int, u_int , bool);
105void npfctl_gennc_complete(void **); 107void npfctl_gennc_complete(void **);
106 108
107int npf_parseline(char *); 109int npf_parseline(char *);
108 110
109#endif 111#endif

cvs diff -r1.2 -r1.3 src/usr.sbin/npf/npfctl/npf_data.c (expand / switch to unified diff)

--- 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
64npfctl_init_data(void) 65npfctl_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
89int 90int
90npfctl_ioctl_send(int fd) 91npfctl_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
115static struct ifaddrs * 117static struct ifaddrs *
116npfctl_getif(char *ifname, unsigned int *if_idx) 118npfctl_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
135static int 
136npfctl_servname2port(char *name) 
137{ 
138 struct servent *se; 
139 
140 se = getservbyname(name, NULL); 
141 return se ? se->s_port : -1; 
142} 
143 
144bool 137bool
145npfctl_parse_v4mask(char *str, in_addr_t *addr, in_addr_t *mask) 138npfctl_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
 158static bool
 159npfctl_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
161static void 186static void
162npfctl_parse_cidr(char *str, in_addr_t *addr, in_addr_t *mask) 187npfctl_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
 208static bool
 209npfctl_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
187prop_dictionary_t 246prop_dictionary_t
188npfctl_lookup_table(char *tidstr) 247npfctl_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
383static void 442static void
384npfctl_rulenc_ports(void **nc, int nblocks[], var_t *dat, bool tcpudp, bool sd) 443npfctl_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
417static void 464static void
418npfctl_rulenc_block(void **nc, int nblocks[], var_t *cidr, var_t *ports, 465npfctl_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
433void 480void
434npfctl_rule_protodata(prop_dictionary_t rl, char *proto, var_t *from, 481npfctl_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 }
471skip_proto: 518skip_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
561void 640void
562npfctl_add_nat(prop_dictionary_t nat) 641npfctl_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
567void 646void
568npfctl_nat_setup(prop_dictionary_t rl, char *iface, char *gwip) 647npfctl_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}