xref: /freebsd/sys/netpfil/ipfw/nat64/nat64lsn.h (revision 4a77657cbc011ea657ccb079fff6b58b295eccb0)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause
3  *
4  * Copyright (c) 2015-2020 Yandex LLC
5  * Copyright (c) 2015 Alexander V. Chernikov <melifaro@FreeBSD.org>
6  * Copyright (c) 2015-2020 Andrey V. Elsukov <ae@FreeBSD.org>
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  */
29 
30 #ifndef	_IP_FW_NAT64LSN_H_
31 #define	_IP_FW_NAT64LSN_H_
32 
33 #include "ip_fw_nat64.h"
34 #include "nat64_translate.h"
35 
36 #define	NAT64_MIN_PORT		1024
37 struct nat64lsn_host;
38 struct nat64lsn_alias;
39 
40 struct nat64lsn_state {
41 	/* IPv6 host entry keeps hash table to speedup state lookup */
42 	CK_SLIST_ENTRY(nat64lsn_state)	entries;
43 	struct nat64lsn_host	*host;
44 
45 	struct in6_addr	ip6_dst;	/* Destination IPv6 address */
46 
47 	in_addr_t	ip_src;		/* Alias IPv4 address */
48 	in_addr_t	ip_dst;		/* Destination IPv4 address */
49 	uint16_t	dport;		/* Destination port */
50 	uint16_t	sport;		/* Source port */
51 
52 	uint32_t	hval;
53 	uint32_t	flags;		/* Internal flags */
54 	uint16_t	aport;
55 	uint16_t	timestamp;	/* last used */
56 	uint8_t		proto;
57 	uint8_t		_spare[7];
58 };
59 
60 struct nat64lsn_states_chunk {
61 	struct nat64lsn_state	state[64];
62 };
63 
64 #define	ISSET64(mask, bit)	((mask) & ((uint64_t)1 << (bit)))
65 #define	ISSET32(mask, bit)	((mask) & ((uint32_t)1 << (bit)))
66 struct nat64lsn_pg {
67 	uint16_t		base_port;
68 	uint16_t		timestamp;
69 	uint8_t			proto;
70 	uint8_t			chunks_count;
71 	uint16_t		flags;
72 #define	NAT64LSN_DEADPG		1
73 
74 	union {
75 		uint64_t	freemask64;
76 		uint32_t	freemask32[2];
77 		uint64_t	*freemask64_chunk;
78 		uint32_t	*freemask32_chunk;
79 		void		*freemask_chunk;
80 	};
81 	union {
82 		struct nat64lsn_states_chunk *states;
83 		struct nat64lsn_states_chunk **states_chunk;
84 	};
85 	/*
86 	 * An alias object holds chain of all allocated PGs.
87 	 * The chain is used mostly by expiration code.
88 	 */
89 	CK_SLIST_ENTRY(nat64lsn_pg)	entries;
90 };
91 
92 #define	CHUNK_BY_FADDR(p, a)	((a) & ((p)->chunks_count - 1))
93 
94 #ifdef __LP64__
95 #define	FREEMASK_CHUNK(p, v)	\
96     ((p)->chunks_count == 1 ? &(p)->freemask64 : \
97 	&(p)->freemask64_chunk[CHUNK_BY_FADDR(p, v)])
98 #define	FREEMASK_BITCOUNT(pg, faddr)	\
99     bitcount64(*FREEMASK_CHUNK((pg), (faddr)))
100 #else
101 #define	FREEMASK_CHUNK(p, v)	\
102     ((p)->chunks_count == 1 ? &(p)->freemask32[0] : \
103 	&(p)->freemask32_chunk[CHUNK_BY_FADDR(p, v) * 2])
104 #define	FREEMASK_BITCOUNT(pg, faddr)	\
105     bitcount64(*(uint64_t *)FREEMASK_CHUNK((pg), (faddr)))
106 #endif /* !__LP64__ */
107 
108 struct nat64lsn_pgchunk {
109 	struct nat64lsn_pg	*pgptr[32];
110 };
111 
112 struct nat64lsn_aliaslink {
113 	CK_SLIST_ENTRY(nat64lsn_aliaslink)	alias_entries;
114 	CK_SLIST_ENTRY(nat64lsn_aliaslink)	host_entries;
115 	struct nat64lsn_alias	*alias;
116 };
117 
118 CK_SLIST_HEAD(nat64lsn_aliaslink_slist, nat64lsn_aliaslink);
119 CK_SLIST_HEAD(nat64lsn_states_slist, nat64lsn_state);
120 CK_SLIST_HEAD(nat64lsn_hosts_slist, nat64lsn_host);
121 CK_SLIST_HEAD(nat64lsn_pg_slist, nat64lsn_pg);
122 
123 struct nat64lsn_alias {
124 	struct nat64lsn_aliaslink_slist	hosts;
125 	struct nat64lsn_pg_slist	portgroups;
126 
127 	struct mtx		lock;
128 	in_addr_t		addr;	/* host byte order */
129 	uint32_t		hosts_count;
130 
131 	uint16_t		timestamp;
132 	uint16_t		tcp_pgcount;
133 	uint16_t		udp_pgcount;
134 	uint16_t		icmp_pgcount;
135 	/*
136 	 * We keep PGs in chunks by 32 PGs in each.
137 	 * Each chunk allocated by demand, and then corresponding bit
138 	 * is set in chunkmask.
139 	 *
140 	 * Also we keep last used PG's index for each protocol.
141 	 *   pgidx / 32 = index of pgchunk;
142 	 *   pgidx % 32 = index of pgptr in pgchunk.
143 	 */
144 	uint32_t		tcp_chunkmask;
145 	uint32_t		tcp_pgidx;
146 
147 	uint32_t		udp_chunkmask;
148 	uint32_t		udp_pgidx;
149 
150 	uint32_t		icmp_chunkmask;
151 	uint32_t		icmp_pgidx;
152 	/*
153 	 * Each pgchunk keeps 32 pointers to PGs. If pgptr pointer is
154 	 * valid, we have corresponding bit set in the pgmask.
155 	 */
156 	uint32_t		tcp_pgmask[32];
157 	uint32_t		udp_pgmask[32];
158 	uint32_t		icmp_pgmask[32];
159 
160 	struct nat64lsn_pgchunk	*tcp[32];
161 	struct nat64lsn_pgchunk	*udp[32];
162 	struct nat64lsn_pgchunk	*icmp[32];
163 };
164 #define	ALIAS_LOCK_INIT(p)	\
165 	mtx_init(&(p)->lock, "alias_lock", NULL, MTX_DEF)
166 #define	ALIAS_LOCK_DESTROY(p)	mtx_destroy(&(p)->lock)
167 #define	ALIAS_LOCK(p)		mtx_lock(&(p)->lock)
168 #define	ALIAS_UNLOCK(p)		mtx_unlock(&(p)->lock)
169 
170 #define	NAT64LSN_HSIZE		256
171 #define	NAT64LSN_MAX_HSIZE	4096
172 #define	NAT64LSN_HOSTS_HSIZE	1024
173 
174 struct nat64lsn_host {
175 	struct in6_addr		addr;
176 	struct nat64lsn_aliaslink_slist	aliases;
177 	struct nat64lsn_states_slist	*states_hash;
178 	CK_SLIST_ENTRY(nat64lsn_host)	entries;
179 	uint32_t		states_count;
180 	uint32_t		hval;
181 	uint32_t		flags;
182 #define	NAT64LSN_DEADHOST	1
183 #define	NAT64LSN_GROWHASH	2
184 	uint16_t		states_hashsize;
185 	uint16_t		timestamp;
186 	struct mtx		lock;
187 };
188 
189 #define	HOST_LOCK_INIT(p)	\
190 	mtx_init(&(p)->lock, "host_lock", NULL, MTX_DEF|MTX_NEW)
191 #define	HOST_LOCK_DESTROY(p)	mtx_destroy(&(p)->lock)
192 #define	HOST_LOCK(p)		mtx_lock(&(p)->lock)
193 #define	HOST_UNLOCK(p)		mtx_unlock(&(p)->lock)
194 
195 VNET_DECLARE(uint32_t, nat64lsn_eid);
196 #define	V_nat64lsn_eid		VNET(nat64lsn_eid)
197 #define	IPFW_TLV_NAT64LSN_NAME	IPFW_TLV_EACTION_NAME(V_nat64lsn_eid)
198 
199 /* Timestamp macro */
200 #define	_CT		((int)time_uptime % 65536)
201 #define	SET_AGE(x)	(x) = _CT
202 #define	GET_AGE(x)	((_CT >= (x)) ? _CT - (x): (int)65536 + _CT - (x))
203 
204 STAILQ_HEAD(nat64lsn_job_head, nat64lsn_job_item);
205 
206 struct nat64lsn_cfg {
207 	struct nat64lsn_hosts_slist	*hosts_hash;
208 	struct nat64lsn_alias	*aliases;	/* array of aliases */
209 
210 	struct mtx	lock;
211 	uint32_t	hosts_hashsize;
212 	uint32_t	hash_seed;
213 
214 	uint32_t	prefix4;	/* IPv4 prefix */
215 	uint32_t	pmask4;		/* IPv4 prefix mask */
216 	uint8_t		plen4;
217 	uint8_t		nomatch_verdict;/* Return value on no-match */
218 
219 	uint32_t	hosts_count;	/* Number of items in host hash */
220 	uint32_t	states_chunks;	/* Number of states chunks per PG */
221 	uint32_t	jmaxlen;	/* Max jobqueue length */
222 	uint16_t	host_delete_delay;	/* Stale host delete delay */
223 	uint16_t	pgchunk_delete_delay;
224 	uint16_t	pg_delete_delay;	/* Stale portgroup del delay */
225 	uint16_t	st_syn_ttl;	/* TCP syn expire */
226 	uint16_t	st_close_ttl;	/* TCP fin expire */
227 	uint16_t	st_estab_ttl;	/* TCP established expire */
228 	uint16_t	st_udp_ttl;	/* UDP expire */
229 	uint16_t	st_icmp_ttl;	/* ICMP expire */
230 
231 	struct nat64_config	base;
232 #define	NAT64LSN_FLAGSMASK	(NAT64_LOG | NAT64_ALLOW_PRIVATE | \
233     NAT64LSN_ALLOW_SWAPCONF)
234 #define	NAT64LSN_ANYPREFIX	0x00000100
235 
236 	struct mtx		periodic_lock;
237 	struct callout		periodic;
238 	struct callout		jcallout;
239 	struct vnet		*vp;
240 	struct nat64lsn_job_head	jhead;
241 	int			jlen;
242 	char			name[64];	/* Nat instance name */
243 };
244 
245 struct nat64lsn_instance {
246 	struct named_object	no;
247 	struct nat64lsn_cfg	*cfg;
248 	char			name[64];	/* Nat instance name */
249 };
250 
251 /* CFG_LOCK protects cfg->hosts_hash from modification */
252 #define	CFG_LOCK_INIT(p)	\
253 	mtx_init(&(p)->lock, "cfg_lock", NULL, MTX_DEF)
254 #define	CFG_LOCK_DESTROY(p)	mtx_destroy(&(p)->lock)
255 #define	CFG_LOCK(p)		mtx_lock(&(p)->lock)
256 #define	CFG_UNLOCK(p)		mtx_unlock(&(p)->lock)
257 
258 #define	CALLOUT_LOCK_INIT(p)	\
259 	mtx_init(&(p)->periodic_lock, "periodic_lock", NULL, MTX_DEF)
260 #define	CALLOUT_LOCK_DESTROY(p)	mtx_destroy(&(p)->periodic_lock)
261 #define	CALLOUT_LOCK(p)		mtx_lock(&(p)->periodic_lock)
262 #define	CALLOUT_UNLOCK(p)	mtx_unlock(&(p)->periodic_lock)
263 
264 MALLOC_DECLARE(M_NAT64LSN);
265 
266 struct nat64lsn_cfg *nat64lsn_init_config(struct ip_fw_chain *ch,
267     in_addr_t prefix, int plen);
268 void nat64lsn_destroy_config(struct nat64lsn_cfg *cfg);
269 void nat64lsn_start_instance(struct nat64lsn_cfg *cfg);
270 void nat64lsn_init_internal(void);
271 void nat64lsn_uninit_internal(void);
272 int ipfw_nat64lsn(struct ip_fw_chain *ch, struct ip_fw_args *args,
273     ipfw_insn *cmd, int *done);
274 
275 #endif /* _IP_FW_NAT64LSN_H_ */
276