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 $
6 * $FreeBSD: src/sys/contrib/ipfilter/netinet/ip_ipsec_pxy.c,v 1.1.1.1.2.1 2002/04/27 17:37:12 darrenr Exp $
7 * $DragonFly: src/sys/contrib/ipfilter/netinet/ip_ipsec_pxy.c,v 1.3 2003/08/27 11:02:14 rob Exp $
10 #define IPF_IPSEC_PROXY
13 int ippr_ipsec_init (void);
14 int ippr_ipsec_new (fr_info_t
*, ip_t
*, ap_session_t
*, nat_t
*);
15 void ippr_ipsec_del (ap_session_t
*);
16 int ippr_ipsec_out (fr_info_t
*, ip_t
*, ap_session_t
*, nat_t
*);
17 int ippr_ipsec_match (fr_info_t
*, ap_session_t
*, nat_t
*);
19 static frentry_t ipsecfr
;
22 static char ipsec_buffer
[1500];
25 * RCMD application proxy initialization.
29 bzero((char *)&ipsecfr
, sizeof(ipsecfr
));
31 ipsecfr
.fr_flags
= FR_OUTQUE
|FR_PASS
|FR_QUICK
|FR_KEEPSTATE
;
37 * Setup for a new IPSEC proxy.
39 int ippr_ipsec_new(fin
, ip
, aps
, nat
)
52 bzero(ipsec_buffer
, sizeof(ipsec_buffer
));
53 off
= fin
->fin_hlen
+ sizeof(udphdr_t
);
58 dlen
= msgdsize(m
) - off
;
61 copyout_mblk(m
, off
, MIN(sizeof(ipsec_buffer
), dlen
), ipsec_buffer
);
63 m
= *(mb_t
**)fin
->fin_mp
;
64 dlen
= mbufchainlen(m
) - off
;
67 m_copydata(m
, off
, MIN(sizeof(ipsec_buffer
), dlen
), ipsec_buffer
);
70 m
= *(mb_t
**)fin
->fin_mp
;
71 dlen
= ip
->ip_len
- off
;
74 bcopy(ptr
, ipsec_buffer
, MIN(sizeof(ipsec_buffer
), dlen
));
78 * Because _new() gets called from nat_new(), ipf_nat is held with a
79 * write lock so pass rw=1 to nat_outlookup().
81 if (nat_outlookup(fin
, 0, IPPROTO_ESP
, nat
->nat_inip
,
82 ip
->ip_dst
, 1) != NULL
)
85 aps
->aps_psiz
= sizeof(*ipsec
);
86 KMALLOCS(aps
->aps_data
, ipsec_pxy_t
*, sizeof(*ipsec
));
87 if (aps
->aps_data
== NULL
)
90 ipsec
= aps
->aps_data
;
91 bzero((char *)ipsec
, sizeof(*ipsec
));
94 * Create NAT rule against which the tunnel/transport mapping is
95 * created. This is required because the current NAT rule does not
96 * describe ESP but UDP instead.
98 ipn
= &ipsec
->ipsc_rule
;
99 ipn
->in_ifp
= fin
->fin_ifp
;
103 ipn
->in_nip
= ntohl(nat
->nat_outip
.s_addr
);
105 ipn
->in_inip
= nat
->nat_inip
.s_addr
;
106 ipn
->in_inmsk
= 0xffffffff;
107 ipn
->in_outip
= nat
->nat_outip
.s_addr
;
108 ipn
->in_outmsk
= 0xffffffff;
109 ipn
->in_srcip
= fin
->fin_saddr
;
110 ipn
->in_srcmsk
= 0xffffffff;
111 ipn
->in_redir
= NAT_MAP
;
112 bcopy(nat
->nat_ptr
->in_ifname
, ipn
->in_ifname
, sizeof(ipn
->in_ifname
));
113 ipn
->in_p
= IPPROTO_ESP
;
115 bcopy((char *)fin
, (char *)&fi
, sizeof(fi
));
116 fi
.fin_fi
.fi_p
= IPPROTO_ESP
;
117 fi
.fin_fr
= &ipsecfr
;
121 ip
->ip_p
= IPPROTO_ESP
;
122 fi
.fin_fl
&= ~FI_TCPUDP
;
125 bcopy(ptr
, ipsec
->ipsc_icookie
, sizeof(ipsec_cookie_t
));
126 ptr
+= sizeof(ipsec_cookie_t
);
127 bcopy(ptr
, ipsec
->ipsc_rcookie
, sizeof(ipsec_cookie_t
));
129 * The responder cookie should only be non-zero if the initiator
130 * cookie is non-zero. Therefore, it is safe to assume(!) that the
131 * cookies are both set after copying if the responder is non-zero.
133 if ((ipsec
->ipsc_rcookie
[0]|ipsec
->ipsc_rcookie
[1]) != 0)
134 ipsec
->ipsc_rckset
= 1;
136 nat
->nat_age
= 60; /* 30 seconds */
138 ipsec
->ipsc_nat
= nat_new(&fi
, ip
, ipn
, &ipsec
->ipsc_nat
, FI_IGNOREPKT
,
140 if (ipsec
->ipsc_nat
!= NULL
) {
143 ipsec
->ipsc_state
= fr_addstate(ip
, &fi
, &ipsec
->ipsc_state
,
144 FI_IGNOREPKT
|FI_NORULE
);
152 * For outgoing IKE packets. refresh timeouts for NAT & stat entries, if
153 * we can. If they have disappeared, recreate them.
155 int ippr_ipsec_out(fin
, ip
, aps
, nat
)
165 bcopy((char *)fin
, (char *)&fi
, sizeof(fi
));
166 fi
.fin_fi
.fi_p
= IPPROTO_ESP
;
167 fi
.fin_fr
= &ipsecfr
;
171 ip
->ip_p
= IPPROTO_ESP
;
172 fi
.fin_fl
&= ~FI_TCPUDP
;
174 ipsec
= aps
->aps_data
;
177 * Update NAT timeout/create NAT if missing.
179 if (ipsec
->ipsc_rckset
== 0)
180 nat
->nat_age
= 60; /* 30 seconds */
181 if (ipsec
->ipsc_nat
!= NULL
)
182 ipsec
->ipsc_nat
->nat_age
= nat
->nat_age
;
184 ipsec
->ipsc_nat
= nat_new(&fi
, ip
, &ipsec
->ipsc_rule
,
186 FI_IGNOREPKT
, NAT_OUTBOUND
);
189 * Update state timeout/create state if missing.
191 READ_ENTER(&ipf_state
);
192 if (ipsec
->ipsc_state
!= NULL
) {
193 ipsec
->ipsc_state
->is_age
= nat
->nat_age
;
194 RWLOCK_EXIT(&ipf_state
);
196 RWLOCK_EXIT(&ipf_state
);
199 ipsec
->ipsc_state
= fr_addstate(ip
, &fi
,
201 FI_IGNOREPKT
|FI_NORULE
);
210 * This extends the NAT matching to be based on the cookies associated with
211 * a session and found at the front of IKE packets. The cookies are always
212 * in the same order (not reversed depending on packet flow direction as with
213 * UDP/TCP port numbers).
215 int ippr_ipsec_match(fin
, aps
, nat
)
225 if ((fin
->fin_dlen
< sizeof(cookies
)) || (fin
->fin_fl
& FI_FRAG
))
228 ipsec
= aps
->aps_data
;
229 off
= fin
->fin_hlen
+ sizeof(udphdr_t
);
234 copyout_mblk(m
, off
, sizeof(cookies
), (char *)cookies
);
236 m
= *(mb_t
**)fin
->fin_mp
;
237 m_copydata(m
, off
, sizeof(cookies
), (char *)cookies
);
240 m
= *(mb_t
**)fin
->fin_mp
;
241 bcopy((char *)m
+ off
, cookies
, sizeof(cookies
));
244 if ((cookies
[0] != ipsec
->ipsc_icookie
[0]) ||
245 (cookies
[1] != ipsec
->ipsc_icookie
[1]))
248 if (ipsec
->ipsc_rckset
== 0) {
249 if ((cookies
[2]|cookies
[3]) == 0) {
250 nat
->nat_age
= 60; /* 30 seconds */
253 ipsec
->ipsc_rckset
= 1;
254 ipsec
->ipsc_rcookie
[0] = cookies
[2];
255 ipsec
->ipsc_rcookie
[1] = cookies
[3];
259 if ((cookies
[2] != ipsec
->ipsc_rcookie
[0]) ||
260 (cookies
[3] != ipsec
->ipsc_rcookie
[1]))
267 * clean up after ourselves.
269 void ippr_ipsec_del(aps
)
274 ipsec
= aps
->aps_data
;
278 * Don't delete it from here, just schedule it to be
281 if (ipsec
->ipsc_nat
!= NULL
) {
282 ipsec
->ipsc_nat
->nat_age
= 1;
283 ipsec
->ipsc_nat
->nat_ptr
= NULL
;
286 READ_ENTER(&ipf_state
);
287 if (ipsec
->ipsc_state
!= NULL
)
288 ipsec
->ipsc_state
->is_age
= 1;
289 RWLOCK_EXIT(&ipf_state
);
291 ipsec
->ipsc_state
= NULL
;
292 ipsec
->ipsc_nat
= NULL
;