2 * Simple ISAKMP transparent proxy for in-kernel use. For use with the NAT
5 * $Id: ip_ipsec_pxy.c,v 1.1.2.10 2002/01/13 04:58:29 darrenr Exp $
8 #define IPF_IPSEC_PROXY
11 int ippr_ipsec_init
__P((void));
12 int ippr_ipsec_new
__P((fr_info_t
*, ip_t
*, ap_session_t
*, nat_t
*));
13 void ippr_ipsec_del
__P((ap_session_t
*));
14 int ippr_ipsec_out
__P((fr_info_t
*, ip_t
*, ap_session_t
*, nat_t
*));
15 int ippr_ipsec_match
__P((fr_info_t
*, ap_session_t
*, nat_t
*));
17 static frentry_t ipsecfr
;
20 static char ipsec_buffer
[1500];
23 * RCMD application proxy initialization.
27 bzero((char *)&ipsecfr
, sizeof(ipsecfr
));
29 ipsecfr
.fr_flags
= FR_OUTQUE
|FR_PASS
|FR_QUICK
|FR_KEEPSTATE
;
35 * Setup for a new IPSEC proxy.
37 int ippr_ipsec_new(fin
, ip
, aps
, nat
)
50 bzero(ipsec_buffer
, sizeof(ipsec_buffer
));
51 off
= fin
->fin_hlen
+ sizeof(udphdr_t
);
56 dlen
= msgdsize(m
) - off
;
59 copyout_mblk(m
, off
, MIN(sizeof(ipsec_buffer
), dlen
), ipsec_buffer
);
61 m
= *(mb_t
**)fin
->fin_mp
;
62 dlen
= mbufchainlen(m
) - off
;
65 m_copydata(m
, off
, MIN(sizeof(ipsec_buffer
), dlen
), ipsec_buffer
);
68 m
= *(mb_t
**)fin
->fin_mp
;
69 dlen
= ip
->ip_len
- off
;
72 bcopy(ptr
, ipsec_buffer
, MIN(sizeof(ipsec_buffer
), dlen
));
76 * Because _new() gets called from nat_new(), ipf_nat is held with a
77 * write lock so pass rw=1 to nat_outlookup().
79 if (nat_outlookup(fin
, 0, IPPROTO_ESP
, nat
->nat_inip
,
80 ip
->ip_dst
, 1) != NULL
)
83 aps
->aps_psiz
= sizeof(*ipsec
);
84 KMALLOCS(aps
->aps_data
, ipsec_pxy_t
*, sizeof(*ipsec
));
85 if (aps
->aps_data
== NULL
)
88 ipsec
= aps
->aps_data
;
89 bzero((char *)ipsec
, sizeof(*ipsec
));
92 * Create NAT rule against which the tunnel/transport mapping is
93 * created. This is required because the current NAT rule does not
94 * describe ESP but UDP instead.
96 ipn
= &ipsec
->ipsc_rule
;
97 ipn
->in_ifp
= fin
->fin_ifp
;
101 ipn
->in_nip
= ntohl(nat
->nat_outip
.s_addr
);
103 ipn
->in_inip
= nat
->nat_inip
.s_addr
;
104 ipn
->in_inmsk
= 0xffffffff;
105 ipn
->in_outip
= nat
->nat_outip
.s_addr
;
106 ipn
->in_outmsk
= 0xffffffff;
107 ipn
->in_srcip
= fin
->fin_saddr
;
108 ipn
->in_srcmsk
= 0xffffffff;
109 ipn
->in_redir
= NAT_MAP
;
110 bcopy(nat
->nat_ptr
->in_ifname
, ipn
->in_ifname
, sizeof(ipn
->in_ifname
));
111 ipn
->in_p
= IPPROTO_ESP
;
113 bcopy((char *)fin
, (char *)&fi
, sizeof(fi
));
114 fi
.fin_fi
.fi_p
= IPPROTO_ESP
;
115 fi
.fin_fr
= &ipsecfr
;
119 ip
->ip_p
= IPPROTO_ESP
;
120 fi
.fin_fl
&= ~FI_TCPUDP
;
123 bcopy(ptr
, ipsec
->ipsc_icookie
, sizeof(ipsec_cookie_t
));
124 ptr
+= sizeof(ipsec_cookie_t
);
125 bcopy(ptr
, ipsec
->ipsc_rcookie
, sizeof(ipsec_cookie_t
));
127 * The responder cookie should only be non-zero if the initiator
128 * cookie is non-zero. Therefore, it is safe to assume(!) that the
129 * cookies are both set after copying if the responder is non-zero.
131 if ((ipsec
->ipsc_rcookie
[0]|ipsec
->ipsc_rcookie
[1]) != 0)
132 ipsec
->ipsc_rckset
= 1;
134 nat
->nat_age
= 60; /* 30 seconds */
136 ipsec
->ipsc_nat
= nat_new(&fi
, ip
, ipn
, &ipsec
->ipsc_nat
, FI_IGNOREPKT
,
138 if (ipsec
->ipsc_nat
!= NULL
) {
141 ipsec
->ipsc_state
= fr_addstate(ip
, &fi
, &ipsec
->ipsc_state
,
142 FI_IGNOREPKT
|FI_NORULE
);
150 * For outgoing IKE packets. refresh timeouts for NAT & stat entries, if
151 * we can. If they have disappeared, recreate them.
153 int ippr_ipsec_out(fin
, ip
, aps
, nat
)
163 bcopy((char *)fin
, (char *)&fi
, sizeof(fi
));
164 fi
.fin_fi
.fi_p
= IPPROTO_ESP
;
165 fi
.fin_fr
= &ipsecfr
;
169 ip
->ip_p
= IPPROTO_ESP
;
170 fi
.fin_fl
&= ~FI_TCPUDP
;
172 ipsec
= aps
->aps_data
;
175 * Update NAT timeout/create NAT if missing.
177 if (ipsec
->ipsc_rckset
== 0)
178 nat
->nat_age
= 60; /* 30 seconds */
179 if (ipsec
->ipsc_nat
!= NULL
)
180 ipsec
->ipsc_nat
->nat_age
= nat
->nat_age
;
182 ipsec
->ipsc_nat
= nat_new(&fi
, ip
, &ipsec
->ipsc_rule
,
184 FI_IGNOREPKT
, NAT_OUTBOUND
);
187 * Update state timeout/create state if missing.
189 READ_ENTER(&ipf_state
);
190 if (ipsec
->ipsc_state
!= NULL
) {
191 ipsec
->ipsc_state
->is_age
= nat
->nat_age
;
192 RWLOCK_EXIT(&ipf_state
);
194 RWLOCK_EXIT(&ipf_state
);
197 ipsec
->ipsc_state
= fr_addstate(ip
, &fi
,
199 FI_IGNOREPKT
|FI_NORULE
);
208 * This extends the NAT matching to be based on the cookies associated with
209 * a session and found at the front of IKE packets. The cookies are always
210 * in the same order (not reversed depending on packet flow direction as with
211 * UDP/TCP port numbers).
213 int ippr_ipsec_match(fin
, aps
, nat
)
223 if ((fin
->fin_dlen
< sizeof(cookies
)) || (fin
->fin_fl
& FI_FRAG
))
226 ipsec
= aps
->aps_data
;
227 off
= fin
->fin_hlen
+ sizeof(udphdr_t
);
232 copyout_mblk(m
, off
, sizeof(cookies
), (char *)cookies
);
234 m
= *(mb_t
**)fin
->fin_mp
;
235 m_copydata(m
, off
, sizeof(cookies
), (char *)cookies
);
238 m
= *(mb_t
**)fin
->fin_mp
;
239 bcopy((char *)m
+ off
, cookies
, sizeof(cookies
));
242 if ((cookies
[0] != ipsec
->ipsc_icookie
[0]) ||
243 (cookies
[1] != ipsec
->ipsc_icookie
[1]))
246 if (ipsec
->ipsc_rckset
== 0) {
247 if ((cookies
[2]|cookies
[3]) == 0) {
248 nat
->nat_age
= 60; /* 30 seconds */
251 ipsec
->ipsc_rckset
= 1;
252 ipsec
->ipsc_rcookie
[0] = cookies
[2];
253 ipsec
->ipsc_rcookie
[1] = cookies
[3];
257 if ((cookies
[2] != ipsec
->ipsc_rcookie
[0]) ||
258 (cookies
[3] != ipsec
->ipsc_rcookie
[1]))
265 * clean up after ourselves.
267 void ippr_ipsec_del(aps
)
272 ipsec
= aps
->aps_data
;
276 * Don't delete it from here, just schedule it to be
279 if (ipsec
->ipsc_nat
!= NULL
) {
280 ipsec
->ipsc_nat
->nat_age
= 1;
281 ipsec
->ipsc_nat
->nat_ptr
= NULL
;
284 READ_ENTER(&ipf_state
);
285 if (ipsec
->ipsc_state
!= NULL
)
286 ipsec
->ipsc_state
->is_age
= 1;
287 RWLOCK_EXIT(&ipf_state
);
289 ipsec
->ipsc_state
= NULL
;
290 ipsec
->ipsc_nat
= NULL
;