1/*
2 * Copyright (C) 2012 by Darren Reed.
3 *
4 * See the IPFILTER.LICENCE file for details on licencing.
5 *
6 * Simple ISAKMP transparent proxy for in-kernel use.  For use with the NAT
7 * code.
8 *
9 * $Id$
10 *
11 */
12#define	IPF_IPSEC_PROXY
13
14
15/*
16 * IPSec proxy
17 */
18typedef struct ipf_ipsec_softc_s {
19	frentry_t	ipsec_fr;
20	int		ipsec_proxy_init;
21	int		ipsec_proxy_ttl;
22	ipftq_t		*ipsec_nat_tqe;
23	ipftq_t		*ipsec_state_tqe;
24	char		ipsec_buffer[1500];
25} ipf_ipsec_softc_t;
26
27
28void *ipf_p_ipsec_soft_create(ipf_main_softc_t *);
29void ipf_p_ipsec_soft_destroy(ipf_main_softc_t *, void *);
30int ipf_p_ipsec_soft_init(ipf_main_softc_t *, void *);
31void ipf_p_ipsec_soft_fini(ipf_main_softc_t *, void *);
32int ipf_p_ipsec_init(void);
33void ipf_p_ipsec_fini(void);
34int ipf_p_ipsec_new(void *, fr_info_t *, ap_session_t *, nat_t *);
35void ipf_p_ipsec_del(ipf_main_softc_t *, ap_session_t *);
36int ipf_p_ipsec_inout(void *, fr_info_t *, ap_session_t *, nat_t *);
37int ipf_p_ipsec_match(fr_info_t *, ap_session_t *, nat_t *);
38
39
40/*
41 * IPSec application proxy initialization.
42 */
43void *
44ipf_p_ipsec_soft_create(ipf_main_softc_t *softc)
45{
46	ipf_ipsec_softc_t *softi;
47
48	KMALLOC(softi, ipf_ipsec_softc_t *);
49	if (softi == NULL)
50		return (NULL);
51
52	bzero((char *)softi, sizeof(*softi));
53	softi->ipsec_fr.fr_ref = 1;
54	softi->ipsec_fr.fr_flags = FR_OUTQUE|FR_PASS|FR_QUICK|FR_KEEPSTATE;
55	MUTEX_INIT(&softi->ipsec_fr.fr_lock, "IPsec proxy rule lock");
56	softi->ipsec_proxy_init = 1;
57	softi->ipsec_proxy_ttl = 60;
58
59	return (softi);
60}
61
62
63int
64ipf_p_ipsec_soft_init(ipf_main_softc_t *softc, void *arg)
65{
66	ipf_ipsec_softc_t *softi = arg;
67
68	softi->ipsec_nat_tqe = ipf_state_add_tq(softc, softi->ipsec_proxy_ttl);
69	if (softi->ipsec_nat_tqe == NULL)
70		return (-1);
71	softi->ipsec_state_tqe = ipf_nat_add_tq(softc, softi->ipsec_proxy_ttl);
72	if (softi->ipsec_state_tqe == NULL) {
73		if (ipf_deletetimeoutqueue(softi->ipsec_nat_tqe) == 0)
74			ipf_freetimeoutqueue(softc, softi->ipsec_nat_tqe);
75		softi->ipsec_nat_tqe = NULL;
76		return (-1);
77	}
78
79	softi->ipsec_nat_tqe->ifq_flags |= IFQF_PROXY;
80	softi->ipsec_state_tqe->ifq_flags |= IFQF_PROXY;
81	softi->ipsec_fr.fr_age[0] = softi->ipsec_proxy_ttl;
82	softi->ipsec_fr.fr_age[1] = softi->ipsec_proxy_ttl;
83	return (0);
84}
85
86
87void
88ipf_p_ipsec_soft_fini(ipf_main_softc_t *softc, void *arg)
89{
90	ipf_ipsec_softc_t *softi = arg;
91
92	if (arg == NULL)
93		return;
94
95	if (softi->ipsec_nat_tqe != NULL) {
96		if (ipf_deletetimeoutqueue(softi->ipsec_nat_tqe) == 0)
97			ipf_freetimeoutqueue(softc, softi->ipsec_nat_tqe);
98	}
99	softi->ipsec_nat_tqe = NULL;
100	if (softi->ipsec_state_tqe != NULL) {
101		if (ipf_deletetimeoutqueue(softi->ipsec_state_tqe) == 0)
102			ipf_freetimeoutqueue(softc, softi->ipsec_state_tqe);
103	}
104	softi->ipsec_state_tqe = NULL;
105}
106
107
108void
109ipf_p_ipsec_soft_destroy(ipf_main_softc_t *softc, void *arg)
110{
111	ipf_ipsec_softc_t *softi = arg;
112
113	if (softi->ipsec_proxy_init == 1) {
114		MUTEX_DESTROY(&softi->ipsec_fr.fr_lock);
115		softi->ipsec_proxy_init = 0;
116	}
117
118	KFREE(softi);
119}
120
121
122/*
123 * Setup for a new IPSEC proxy.
124 */
125int
126ipf_p_ipsec_new(void *arg, fr_info_t *fin, ap_session_t *aps, nat_t *nat)
127{
128	ipf_ipsec_softc_t *softi = arg;
129	ipf_main_softc_t *softc = fin->fin_main_soft;
130#ifdef USE_MUTEXES
131	ipf_nat_softc_t *softn = softc->ipf_nat_soft;
132#endif
133	int p, off, dlen, ttl;
134	ipsec_pxy_t *ipsec;
135	ipnat_t *ipn, *np;
136	fr_info_t fi;
137	char *ptr;
138	int size;
139	ip_t *ip;
140	mb_t *m;
141
142	if (fin->fin_v != 4)
143		return (-1);
144
145	off = fin->fin_plen - fin->fin_dlen + fin->fin_ipoff;
146	bzero(softi->ipsec_buffer, sizeof(softi->ipsec_buffer));
147	ip = fin->fin_ip;
148	m = fin->fin_m;
149
150	dlen = M_LEN(m) - off;
151	if (dlen < 16)
152		return (-1);
153	COPYDATA(m, off, MIN(sizeof(softi->ipsec_buffer), dlen),
154		 softi->ipsec_buffer);
155
156	if (ipf_nat_outlookup(fin, 0, IPPROTO_ESP, nat->nat_nsrcip,
157			  ip->ip_dst) != NULL)
158		return (-1);
159
160	np = nat->nat_ptr;
161	size = np->in_size;
162	KMALLOC(ipsec, ipsec_pxy_t *);
163	if (ipsec == NULL)
164		return (-1);
165
166	KMALLOCS(ipn, ipnat_t *, size);
167	if (ipn == NULL) {
168		KFREE(ipsec);
169		return (-1);
170	}
171
172	aps->aps_data = ipsec;
173	aps->aps_psiz = sizeof(*ipsec);
174	bzero((char *)ipsec, sizeof(*ipsec));
175	bzero((char *)ipn, size);
176	ipsec->ipsc_rule = ipn;
177
178	/*
179	 * Create NAT rule against which the tunnel/transport mapping is
180	 * created.  This is required because the current NAT rule does not
181	 * describe ESP but UDP instead.
182	 */
183	ipn->in_size = size;
184	ttl = IPF_TTLVAL(softi->ipsec_nat_tqe->ifq_ttl);
185	ipn->in_tqehead[0] = ipf_nat_add_tq(softc, ttl);
186	ipn->in_tqehead[1] = ipf_nat_add_tq(softc, ttl);
187	ipn->in_ifps[0] = fin->fin_ifp;
188	ipn->in_apr = NULL;
189	ipn->in_use = 1;
190	ipn->in_hits = 1;
191	ipn->in_snip = ntohl(nat->nat_nsrcaddr);
192	ipn->in_ippip = 1;
193	ipn->in_osrcip = nat->nat_osrcip;
194	ipn->in_osrcmsk = 0xffffffff;
195	ipn->in_nsrcip = nat->nat_nsrcip;
196	ipn->in_nsrcmsk = 0xffffffff;
197	ipn->in_odstip = nat->nat_odstip;
198	ipn->in_odstmsk = 0xffffffff;
199	ipn->in_ndstip = nat->nat_ndstip;
200	ipn->in_ndstmsk = 0xffffffff;
201	ipn->in_redir = NAT_MAP;
202	ipn->in_pr[0] = IPPROTO_ESP;
203	ipn->in_pr[1] = IPPROTO_ESP;
204	ipn->in_flags = (np->in_flags | IPN_PROXYRULE);
205	MUTEX_INIT(&ipn->in_lock, "IPSec proxy NAT rule");
206
207	ipn->in_namelen = np->in_namelen;
208	bcopy(np->in_names, ipn->in_ifnames, ipn->in_namelen);
209	ipn->in_ifnames[0] = np->in_ifnames[0];
210	ipn->in_ifnames[1] = np->in_ifnames[1];
211
212	bcopy((char *)fin, (char *)&fi, sizeof(fi));
213	fi.fin_fi.fi_p = IPPROTO_ESP;
214	fi.fin_fr = &softi->ipsec_fr;
215	fi.fin_data[0] = 0;
216	fi.fin_data[1] = 0;
217	p = ip->ip_p;
218	ip->ip_p = IPPROTO_ESP;
219	fi.fin_flx &= ~(FI_TCPUDP|FI_STATE|FI_FRAG);
220	fi.fin_flx |= FI_IGNORE;
221
222	ptr = softi->ipsec_buffer;
223	bcopy(ptr, (char *)ipsec->ipsc_icookie, sizeof(ipsec_cookie_t));
224	ptr += sizeof(ipsec_cookie_t);
225	bcopy(ptr, (char *)ipsec->ipsc_rcookie, sizeof(ipsec_cookie_t));
226	/*
227	 * The responder cookie should only be non-zero if the initiator
228	 * cookie is non-zero.  Therefore, it is safe to assume(!) that the
229	 * cookies are both set after copying if the responder is non-zero.
230	 */
231	if ((ipsec->ipsc_rcookie[0]|ipsec->ipsc_rcookie[1]) != 0)
232		ipsec->ipsc_rckset = 1;
233
234	MUTEX_ENTER(&softn->ipf_nat_new);
235	ipsec->ipsc_nat = ipf_nat_add(&fi, ipn, &ipsec->ipsc_nat,
236				      NAT_SLAVE|SI_WILDP, NAT_OUTBOUND);
237	MUTEX_EXIT(&softn->ipf_nat_new);
238	if (ipsec->ipsc_nat != NULL) {
239		(void) ipf_nat_proto(&fi, ipsec->ipsc_nat, 0);
240		MUTEX_ENTER(&ipsec->ipsc_nat->nat_lock);
241		ipf_nat_update(&fi, ipsec->ipsc_nat);
242		MUTEX_EXIT(&ipsec->ipsc_nat->nat_lock);
243
244		fi.fin_data[0] = 0;
245		fi.fin_data[1] = 0;
246		(void) ipf_state_add(softc, &fi, &ipsec->ipsc_state, SI_WILDP);
247	}
248	ip->ip_p = p & 0xff;
249	return (0);
250}
251
252
253/*
254 * For outgoing IKE packets.  refresh timeouts for NAT & state entries, if
255 * we can.  If they have disappeared, recreate them.
256 */
257int
258ipf_p_ipsec_inout(void *arg, fr_info_t *fin, ap_session_t *aps, nat_t *nat)
259{
260	ipf_ipsec_softc_t *softi = arg;
261	ipf_main_softc_t *softc = fin->fin_main_soft;
262	ipsec_pxy_t *ipsec;
263	fr_info_t fi;
264	ip_t *ip;
265	int p;
266
267	if ((fin->fin_out == 1) && (nat->nat_dir == NAT_INBOUND))
268		return (0);
269
270	if ((fin->fin_out == 0) && (nat->nat_dir == NAT_OUTBOUND))
271		return (0);
272
273	ipsec = aps->aps_data;
274
275	if (ipsec != NULL) {
276		ip = fin->fin_ip;
277		p = ip->ip_p;
278
279		if ((ipsec->ipsc_nat == NULL) || (ipsec->ipsc_state == NULL)) {
280			bcopy((char *)fin, (char *)&fi, sizeof(fi));
281			fi.fin_fi.fi_p = IPPROTO_ESP;
282			fi.fin_fr = &softi->ipsec_fr;
283			fi.fin_data[0] = 0;
284			fi.fin_data[1] = 0;
285			ip->ip_p = IPPROTO_ESP;
286			fi.fin_flx &= ~(FI_TCPUDP|FI_STATE|FI_FRAG);
287			fi.fin_flx |= FI_IGNORE;
288		}
289
290		/*
291		 * Update NAT timeout/create NAT if missing.
292		 */
293		if (ipsec->ipsc_nat != NULL)
294			ipf_queueback(softc->ipf_ticks,
295				      &ipsec->ipsc_nat->nat_tqe);
296		else {
297#ifdef USE_MUTEXES
298			ipf_nat_softc_t *softn = softc->ipf_nat_soft;
299#endif
300
301			MUTEX_ENTER(&softn->ipf_nat_new);
302			ipsec->ipsc_nat = ipf_nat_add(&fi, ipsec->ipsc_rule,
303						      &ipsec->ipsc_nat,
304						      NAT_SLAVE|SI_WILDP,
305						      nat->nat_dir);
306			MUTEX_EXIT(&softn->ipf_nat_new);
307			if (ipsec->ipsc_nat != NULL) {
308				(void) ipf_nat_proto(&fi, ipsec->ipsc_nat, 0);
309				MUTEX_ENTER(&ipsec->ipsc_nat->nat_lock);
310				ipf_nat_update(&fi, ipsec->ipsc_nat);
311				MUTEX_EXIT(&ipsec->ipsc_nat->nat_lock);
312			}
313		}
314
315		/*
316		 * Update state timeout/create state if missing.
317		 */
318		READ_ENTER(&softc->ipf_state);
319		if (ipsec->ipsc_state != NULL) {
320			ipf_queueback(softc->ipf_ticks,
321				      &ipsec->ipsc_state->is_sti);
322			ipsec->ipsc_state->is_die = nat->nat_age;
323			RWLOCK_EXIT(&softc->ipf_state);
324		} else {
325			RWLOCK_EXIT(&softc->ipf_state);
326			fi.fin_data[0] = 0;
327			fi.fin_data[1] = 0;
328			(void) ipf_state_add(softc, &fi, &ipsec->ipsc_state,
329					     SI_WILDP);
330		}
331		ip->ip_p = p;
332	}
333	return (0);
334}
335
336
337/*
338 * This extends the NAT matching to be based on the cookies associated with
339 * a session and found at the front of IKE packets.  The cookies are always
340 * in the same order (not reversed depending on packet flow direction as with
341 * UDP/TCP port numbers).
342 */
343int
344ipf_p_ipsec_match(fr_info_t *fin, ap_session_t *aps, nat_t *nat)
345{
346	ipsec_pxy_t *ipsec;
347	u_32_t cookies[4];
348	mb_t *m;
349	int off;
350
351	nat = nat;	/* LINT */
352
353	if ((fin->fin_dlen < sizeof(cookies)) || (fin->fin_flx & FI_FRAG))
354		return (-1);
355
356	off = fin->fin_plen - fin->fin_dlen + fin->fin_ipoff;
357	ipsec = aps->aps_data;
358	m = fin->fin_m;
359	COPYDATA(m, off, sizeof(cookies), (char *)cookies);
360
361	if ((cookies[0] != ipsec->ipsc_icookie[0]) ||
362	    (cookies[1] != ipsec->ipsc_icookie[1]))
363		return (-1);
364
365	if (ipsec->ipsc_rckset == 0) {
366		if ((cookies[2]|cookies[3]) == 0) {
367			return (0);
368		}
369		ipsec->ipsc_rckset = 1;
370		ipsec->ipsc_rcookie[0] = cookies[2];
371		ipsec->ipsc_rcookie[1] = cookies[3];
372		return (0);
373	}
374
375	if ((cookies[2] != ipsec->ipsc_rcookie[0]) ||
376	    (cookies[3] != ipsec->ipsc_rcookie[1]))
377		return (-1);
378	return (0);
379}
380
381
382/*
383 * clean up after ourselves.
384 */
385void
386ipf_p_ipsec_del(ipf_main_softc_t *softc, ap_session_t *aps)
387{
388	ipsec_pxy_t *ipsec;
389
390	ipsec = aps->aps_data;
391
392	if (ipsec != NULL) {
393		/*
394		 * Don't bother changing any of the NAT structure details,
395		 * *_del() is on a callback from aps_free(), from nat_delete()
396		 */
397
398		READ_ENTER(&softc->ipf_state);
399		if (ipsec->ipsc_state != NULL) {
400			ipsec->ipsc_state->is_die = softc->ipf_ticks + 1;
401			ipsec->ipsc_state->is_me = NULL;
402			ipf_queuefront(&ipsec->ipsc_state->is_sti);
403		}
404		RWLOCK_EXIT(&softc->ipf_state);
405
406		ipsec->ipsc_state = NULL;
407		ipsec->ipsc_nat = NULL;
408		ipsec->ipsc_rule->in_flags |= IPN_DELETE;
409		ipf_nat_rule_deref(softc, &ipsec->ipsc_rule);
410	}
411}
412