]> CyberLeo.Net >> Repos - FreeBSD/releng/8.1.git/blob - sys/contrib/ipfilter/netinet/ip_ipsec_pxy.c
Copy stable/8 to releng/8.1 in preparation for 8.1-RC1.
[FreeBSD/releng/8.1.git] / sys / contrib / ipfilter / netinet / ip_ipsec_pxy.c
1 /*
2  * Copyright (C) 2001-2003 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: ip_ipsec_pxy.c,v 2.20.2.8 2006/07/14 06:12:14 darrenr Exp $
10  *
11  */
12 #define IPF_IPSEC_PROXY
13
14
15 int ippr_ipsec_init __P((void));
16 void ippr_ipsec_fini __P((void));
17 int ippr_ipsec_new __P((fr_info_t *, ap_session_t *, nat_t *));
18 void ippr_ipsec_del __P((ap_session_t *));
19 int ippr_ipsec_inout __P((fr_info_t *, ap_session_t *, nat_t *));
20 int ippr_ipsec_match __P((fr_info_t *, ap_session_t *, nat_t *));
21
22 static  frentry_t       ipsecfr;
23 static  ipftq_t         *ipsecnattqe;
24 static  ipftq_t         *ipsecstatetqe;
25 static  char    ipsec_buffer[1500];
26
27 int     ipsec_proxy_init = 0;
28 int     ipsec_proxy_ttl = 60;
29
30 /*
31  * IPSec application proxy initialization.
32  */
33 int ippr_ipsec_init()
34 {
35         bzero((char *)&ipsecfr, sizeof(ipsecfr));
36         ipsecfr.fr_ref = 1;
37         ipsecfr.fr_flags = FR_OUTQUE|FR_PASS|FR_QUICK|FR_KEEPSTATE;
38         MUTEX_INIT(&ipsecfr.fr_lock, "IPsec proxy rule lock");
39         ipsec_proxy_init = 1;
40
41         ipsecnattqe = fr_addtimeoutqueue(&nat_utqe, ipsec_proxy_ttl);
42         if (ipsecnattqe == NULL)
43                 return -1;
44         ipsecstatetqe = fr_addtimeoutqueue(&ips_utqe, ipsec_proxy_ttl);
45         if (ipsecstatetqe == NULL) {
46                 if (fr_deletetimeoutqueue(ipsecnattqe) == 0)
47                         fr_freetimeoutqueue(ipsecnattqe);
48                 ipsecnattqe = NULL;
49                 return -1;
50         }
51
52         ipsecnattqe->ifq_flags |= IFQF_PROXY;
53         ipsecstatetqe->ifq_flags |= IFQF_PROXY;
54
55         ipsecfr.fr_age[0] = ipsec_proxy_ttl;
56         ipsecfr.fr_age[1] = ipsec_proxy_ttl;
57         return 0;
58 }
59
60
61 void ippr_ipsec_fini()
62 {
63         if (ipsecnattqe != NULL) {
64                 if (fr_deletetimeoutqueue(ipsecnattqe) == 0)
65                         fr_freetimeoutqueue(ipsecnattqe);
66         }
67         ipsecnattqe = NULL;
68         if (ipsecstatetqe != NULL) {
69                 if (fr_deletetimeoutqueue(ipsecstatetqe) == 0)
70                         fr_freetimeoutqueue(ipsecstatetqe);
71         }
72         ipsecstatetqe = NULL;
73
74         if (ipsec_proxy_init == 1) {
75                 MUTEX_DESTROY(&ipsecfr.fr_lock);
76                 ipsec_proxy_init = 0;
77         }
78 }
79
80
81 /*
82  * Setup for a new IPSEC proxy.
83  */
84 int ippr_ipsec_new(fin, aps, nat)
85 fr_info_t *fin;
86 ap_session_t *aps;
87 nat_t *nat;
88 {
89         ipsec_pxy_t *ipsec;
90         fr_info_t fi;
91         ipnat_t *ipn;
92         char *ptr;
93         int p, off, dlen, ttl;
94         mb_t *m;
95         ip_t *ip;
96
97         off = fin->fin_plen - fin->fin_dlen + fin->fin_ipoff;
98         bzero(ipsec_buffer, sizeof(ipsec_buffer));
99         ip = fin->fin_ip;
100         m = fin->fin_m;
101
102         dlen = M_LEN(m) - off;
103         if (dlen < 16)
104                 return -1;
105         COPYDATA(m, off, MIN(sizeof(ipsec_buffer), dlen), ipsec_buffer);
106
107         if (nat_outlookup(fin, 0, IPPROTO_ESP, nat->nat_inip,
108                           ip->ip_dst) != NULL)
109                 return -1;
110
111         aps->aps_psiz = sizeof(*ipsec);
112         KMALLOCS(aps->aps_data, ipsec_pxy_t *, sizeof(*ipsec));
113         if (aps->aps_data == NULL)
114                 return -1;
115
116         ipsec = aps->aps_data;
117         bzero((char *)ipsec, sizeof(*ipsec));
118
119         /*
120          * Create NAT rule against which the tunnel/transport mapping is
121          * created.  This is required because the current NAT rule does not
122          * describe ESP but UDP instead.
123          */
124         ipn = &ipsec->ipsc_rule;
125         ttl = IPF_TTLVAL(ipsecnattqe->ifq_ttl);
126         ipn->in_tqehead[0] = fr_addtimeoutqueue(&nat_utqe, ttl);
127         ipn->in_tqehead[1] = fr_addtimeoutqueue(&nat_utqe, ttl);
128         ipn->in_ifps[0] = fin->fin_ifp;
129         ipn->in_apr = NULL;
130         ipn->in_use = 1;
131         ipn->in_hits = 1;
132         ipn->in_nip = ntohl(nat->nat_outip.s_addr);
133         ipn->in_ippip = 1;
134         ipn->in_inip = nat->nat_inip.s_addr;
135         ipn->in_inmsk = 0xffffffff;
136         ipn->in_outip = fin->fin_saddr;
137         ipn->in_outmsk = nat->nat_outip.s_addr;
138         ipn->in_srcip = fin->fin_saddr;
139         ipn->in_srcmsk = 0xffffffff;
140         ipn->in_redir = NAT_MAP;
141         bcopy(nat->nat_ptr->in_ifnames[0], ipn->in_ifnames[0],
142               sizeof(ipn->in_ifnames[0]));
143         ipn->in_p = IPPROTO_ESP;
144
145         bcopy((char *)fin, (char *)&fi, sizeof(fi));
146         fi.fin_state = NULL;
147         fi.fin_nat = NULL;
148         fi.fin_fi.fi_p = IPPROTO_ESP;
149         fi.fin_fr = &ipsecfr;
150         fi.fin_data[0] = 0;
151         fi.fin_data[1] = 0;
152         p = ip->ip_p;
153         ip->ip_p = IPPROTO_ESP;
154         fi.fin_flx &= ~(FI_TCPUDP|FI_STATE|FI_FRAG);
155         fi.fin_flx |= FI_IGNORE;
156
157         ptr = ipsec_buffer;
158         bcopy(ptr, (char *)ipsec->ipsc_icookie, sizeof(ipsec_cookie_t));
159         ptr += sizeof(ipsec_cookie_t);
160         bcopy(ptr, (char *)ipsec->ipsc_rcookie, sizeof(ipsec_cookie_t));
161         /*
162          * The responder cookie should only be non-zero if the initiator
163          * cookie is non-zero.  Therefore, it is safe to assume(!) that the
164          * cookies are both set after copying if the responder is non-zero.
165          */
166         if ((ipsec->ipsc_rcookie[0]|ipsec->ipsc_rcookie[1]) != 0)
167                 ipsec->ipsc_rckset = 1;
168
169         ipsec->ipsc_nat = nat_new(&fi, ipn, &ipsec->ipsc_nat,
170                                   NAT_SLAVE|SI_WILDP, NAT_OUTBOUND);
171         if (ipsec->ipsc_nat != NULL) {
172                 (void) nat_proto(&fi, ipsec->ipsc_nat, 0);
173                 nat_update(&fi, ipsec->ipsc_nat, ipn);
174
175                 fi.fin_data[0] = 0;
176                 fi.fin_data[1] = 0;
177                 ipsec->ipsc_state = fr_addstate(&fi, &ipsec->ipsc_state,
178                                                 SI_WILDP);
179                 if (fi.fin_state != NULL)
180                         fr_statederef((ipstate_t **)&fi.fin_state);
181         }
182         ip->ip_p = p & 0xff;
183         return 0;
184 }
185
186
187 /*
188  * For outgoing IKE packets.  refresh timeouts for NAT & state entries, if
189  * we can.  If they have disappeared, recreate them.
190  */
191 int ippr_ipsec_inout(fin, aps, nat)
192 fr_info_t *fin;
193 ap_session_t *aps;
194 nat_t *nat;
195 {
196         ipsec_pxy_t *ipsec;
197         fr_info_t fi;
198         ip_t *ip;
199         int p;
200
201         if ((fin->fin_out == 1) && (nat->nat_dir == NAT_INBOUND))
202                 return 0;
203
204         if ((fin->fin_out == 0) && (nat->nat_dir == NAT_OUTBOUND))
205                 return 0;
206
207         ipsec = aps->aps_data;
208
209         if (ipsec != NULL) {
210                 ip = fin->fin_ip;
211                 p = ip->ip_p;
212
213                 if ((ipsec->ipsc_nat == NULL) || (ipsec->ipsc_state == NULL)) {
214                         bcopy((char *)fin, (char *)&fi, sizeof(fi));
215                         fi.fin_state = NULL;
216                         fi.fin_nat = NULL;
217                         fi.fin_fi.fi_p = IPPROTO_ESP;
218                         fi.fin_fr = &ipsecfr;
219                         fi.fin_data[0] = 0;
220                         fi.fin_data[1] = 0;
221                         ip->ip_p = IPPROTO_ESP;
222                         fi.fin_flx &= ~(FI_TCPUDP|FI_STATE|FI_FRAG);
223                         fi.fin_flx |= FI_IGNORE;
224                 }
225
226                 /*
227                  * Update NAT timeout/create NAT if missing.
228                  */
229                 if (ipsec->ipsc_nat != NULL)
230                         fr_queueback(&ipsec->ipsc_nat->nat_tqe);
231                 else {
232                         ipsec->ipsc_nat = nat_new(&fi, &ipsec->ipsc_rule,
233                                                   &ipsec->ipsc_nat,
234                                                   NAT_SLAVE|SI_WILDP,
235                                                   nat->nat_dir);
236                         if (ipsec->ipsc_nat != NULL) {
237                                 (void) nat_proto(&fi, ipsec->ipsc_nat, 0);
238                                 nat_update(&fi, ipsec->ipsc_nat,
239                                            &ipsec->ipsc_rule);
240                         }
241                 }
242
243                 /*
244                  * Update state timeout/create state if missing.
245                  */
246                 READ_ENTER(&ipf_state);
247                 if (ipsec->ipsc_state != NULL) {
248                         fr_queueback(&ipsec->ipsc_state->is_sti);
249                         ipsec->ipsc_state->is_die = nat->nat_age;
250                         RWLOCK_EXIT(&ipf_state);
251                 } else {
252                         RWLOCK_EXIT(&ipf_state);
253                         fi.fin_data[0] = 0;
254                         fi.fin_data[1] = 0;
255                         ipsec->ipsc_state = fr_addstate(&fi,
256                                                         &ipsec->ipsc_state,
257                                                         SI_WILDP);
258                         if (fi.fin_state != NULL)
259                                 fr_statederef((ipstate_t **)&fi.fin_state);
260                 }
261                 ip->ip_p = p;
262         }
263         return 0;
264 }
265
266
267 /*
268  * This extends the NAT matching to be based on the cookies associated with
269  * a session and found at the front of IKE packets.  The cookies are always
270  * in the same order (not reversed depending on packet flow direction as with
271  * UDP/TCP port numbers).
272  */
273 int ippr_ipsec_match(fin, aps, nat)
274 fr_info_t *fin;
275 ap_session_t *aps;
276 nat_t *nat;
277 {
278         ipsec_pxy_t *ipsec;
279         u_32_t cookies[4];
280         mb_t *m;
281         int off;
282
283         nat = nat;      /* LINT */
284
285         if ((fin->fin_dlen < sizeof(cookies)) || (fin->fin_flx & FI_FRAG))
286                 return -1;
287
288         off = fin->fin_plen - fin->fin_dlen + fin->fin_ipoff;
289         ipsec = aps->aps_data;
290         m = fin->fin_m;
291         COPYDATA(m, off, sizeof(cookies), (char *)cookies);
292
293         if ((cookies[0] != ipsec->ipsc_icookie[0]) ||
294             (cookies[1] != ipsec->ipsc_icookie[1]))
295                 return -1;
296
297         if (ipsec->ipsc_rckset == 0) {
298                 if ((cookies[2]|cookies[3]) == 0) {
299                         return 0;
300                 }
301                 ipsec->ipsc_rckset = 1;
302                 ipsec->ipsc_rcookie[0] = cookies[2];
303                 ipsec->ipsc_rcookie[1] = cookies[3];
304                 return 0;
305         }
306
307         if ((cookies[2] != ipsec->ipsc_rcookie[0]) ||
308             (cookies[3] != ipsec->ipsc_rcookie[1]))
309                 return -1;
310         return 0;
311 }
312
313
314 /*
315  * clean up after ourselves.
316  */
317 void ippr_ipsec_del(aps)
318 ap_session_t *aps;
319 {
320         ipsec_pxy_t *ipsec;
321
322         ipsec = aps->aps_data;
323
324         if (ipsec != NULL) {
325                 /*
326                  * Don't bother changing any of the NAT structure details,
327                  * *_del() is on a callback from aps_free(), from nat_delete()
328                  */
329
330                 READ_ENTER(&ipf_state);
331                 if (ipsec->ipsc_state != NULL) {
332                         ipsec->ipsc_state->is_die = fr_ticks + 1;
333                         ipsec->ipsc_state->is_me = NULL;
334                         fr_queuefront(&ipsec->ipsc_state->is_sti);
335                 }
336                 RWLOCK_EXIT(&ipf_state);
337
338                 ipsec->ipsc_state = NULL;
339                 ipsec->ipsc_nat = NULL;
340         }
341 }