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