1 /* $NetBSD: ipcomp_input.c,v 1.30.2.1 2011/04/03 15:16:11 riz Exp $ */
2 /* $KAME: ipcomp_input.c,v 1.29 2001/09/04 08:43:19 itojun Exp $ */
3
4 /*
5 * Copyright (C) 1999 WIDE Project.
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. Neither the name of the project nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 */
32
33 /*
34 * RFC2393 IP payload compression protocol (IPComp).
35 */
36
37 #include <sys/cdefs.h>
38 __KERNEL_RCSID(0, "$NetBSD: ipcomp_input.c,v 1.30.2.1 2011/04/03 15:16:11 riz Exp $");
39
40 #include "opt_inet.h"
41 #include "opt_ipsec.h"
42
43 #include <sys/param.h>
44 #include <sys/systm.h>
45 #include <sys/malloc.h>
46 #include <sys/mbuf.h>
47 #include <sys/domain.h>
48 #include <sys/protosw.h>
49 #include <sys/socket.h>
50 #include <sys/errno.h>
51 #include <sys/time.h>
52 #include <sys/kernel.h>
53 #include <sys/syslog.h>
54
55 #include <net/if.h>
56 #include <net/route.h>
57 #include <net/netisr.h>
58 #include <net/zlib.h>
59 #include <machine/cpu.h>
60
61 #include <netinet/in.h>
62 #include <netinet/in_systm.h>
63 #include <netinet/in_var.h>
64 #include <netinet/in_proto.h>
65 #include <netinet/ip.h>
66 #include <netinet/ip_var.h>
67 #include <netinet/ip_ecn.h>
68
69 #ifdef INET6
70 #include <netinet/ip6.h>
71 #include <netinet6/ip6_var.h>
72 #endif
73 #include <netinet6/ipcomp.h>
74
75 #include <netinet6/ipsec.h>
76 #include <netkey/key.h>
77 #include <netkey/keydb.h>
78
79 #include <machine/stdarg.h>
80
81 #include <net/net_osdep.h>
82
83 /*#define IPLEN_FLIPPED*/
84
85 #ifdef INET
86 void
87 #if __STDC__
88 ipcomp4_input(struct mbuf *m, ...)
89 #else
90 ipcomp4_input(m, va_alist)
91 struct mbuf *m;
92 va_dcl
93 #endif
94 {
95 struct mbuf *md;
96 struct ip *ip;
97 struct ipcomp *ipcomp;
98 const struct ipcomp_algorithm *algo;
99 u_int16_t cpi; /* host order */
100 u_int16_t nxt;
101 size_t hlen;
102 int error;
103 size_t newlen, olen;
104 struct secasvar *sav = NULL;
105 int off, proto;
106 va_list ap;
107 u_int16_t sport = 0;
108 u_int16_t dport = 0;
109 #ifdef IPSEC_NAT_T
110 struct m_tag *tag = NULL;
111 #endif
112
113 va_start(ap, m);
114 off = va_arg(ap, int);
115 proto = va_arg(ap, int);
116 va_end(ap);
117
118 if (m->m_pkthdr.len < off + sizeof(struct ipcomp)) {
119 ipseclog((LOG_DEBUG, "IPv4 IPComp input: assumption failed "
120 "(packet too short)\n"));
121 ipsecstat.in_inval++;
122 goto fail;
123 }
124 #ifdef IPSEC_NAT_T
125 /* find the source port for NAT-T */
126 if ((tag = m_tag_find(m, PACKET_TAG_IPSEC_NAT_T_PORTS, NULL)) != NULL) {
127 sport = ((u_int16_t *)(tag + 1))[0];
128 dport = ((u_int16_t *)(tag + 1))[1];
129 }
130 #endif
131
132 md = m_pulldown(m, off, sizeof(*ipcomp), NULL);
133 if (!md) {
134 m = NULL; /* already freed */
135 ipseclog((LOG_DEBUG, "IPv4 IPComp input: assumption failed "
136 "(pulldown failure)\n"));
137 ipsecstat.in_inval++;
138 goto fail;
139 }
140 ipcomp = mtod(md, struct ipcomp *);
141 ip = mtod(m, struct ip *);
142 nxt = ipcomp->comp_nxt;
143 if (nxt == IPPROTO_IPCOMP || nxt == IPPROTO_AH || nxt == IPPROTO_ESP) {
144 /* nested ipcomp - possible attack, not likely useful */
145 ipseclog((LOG_DEBUG, "IPv4 IPComp input: nested ipcomp "
146 "(bailing)\n"));
147 ipsecstat.in_inval++;
148 goto fail;
149 }
150
151 #ifdef _IP_VHL
152 hlen = IP_VHL_HL(ip->ip_vhl) << 2;
153 #else
154 hlen = ip->ip_hl << 2;
155 #endif
156
157 cpi = ntohs(ipcomp->comp_cpi);
158
159 if (cpi >= IPCOMP_CPI_NEGOTIATE_MIN) {
160 sav = key_allocsa(AF_INET, (caddr_t)&ip->ip_src,
161 (caddr_t)&ip->ip_dst, IPPROTO_IPCOMP, htonl(cpi),
162 sport, dport);
163 if (sav != NULL &&
164 (sav->state == SADB_SASTATE_MATURE ||
165 sav->state == SADB_SASTATE_DYING)) {
166 cpi = sav->alg_enc; /* XXX */
167 /* other parameters to look at? */
168 }
169 }
170 algo = ipcomp_algorithm_lookup(cpi);
171 if (!algo) {
172 ipseclog((LOG_WARNING, "IPv4 IPComp input: unknown cpi %u\n",
173 cpi));
174 ipsecstat.in_nosa++;
175 goto fail;
176 }
177
178 /* chop ipcomp header */
179 ipcomp = NULL;
180 md->m_data += sizeof(struct ipcomp);
181 md->m_len -= sizeof(struct ipcomp);
182 m->m_pkthdr.len -= sizeof(struct ipcomp);
183 #ifdef IPLEN_FLIPPED
184 ip->ip_len -= sizeof(struct ipcomp);
185 #else
186 ip->ip_len = htons(ntohs(ip->ip_len) - sizeof(struct ipcomp));
187 #endif
188
189 olen = m->m_pkthdr.len;
190 newlen = m->m_pkthdr.len - off;
191 error = (*algo->decompress)(m, m->m_next, &newlen);
192 if (error != 0) {
193 if (error == EINVAL)
194 ipsecstat.in_inval++;
195 else if (error == ENOBUFS)
196 ipsecstat.in_nomem++;
197 m = NULL;
198 goto fail;
199 }
200 ipsecstat.in_comphist[cpi]++;
201
202 /*
203 * returning decompressed packet onto icmp is meaningless.
204 * mark it decrypted to prevent icmp from attaching original packet.
205 */
206 m->m_flags |= M_DECRYPTED;
207
208 m->m_pkthdr.len = off + newlen;
209 ip = mtod(m, struct ip *);
210 {
211 size_t len;
212 #ifdef IPLEN_FLIPPED
213 len = ip->ip_len;
214 #else
215 len = ntohs(ip->ip_len);
216 #endif
217 /*
218 * be careful about underflow. also, do not assign exact value
219 * as ip_len is manipulated differently on *BSDs.
220 */
221 len += m->m_pkthdr.len;
222 len -= olen;
223 if (len & ~0xffff) {
224 /* packet too big after decompress */
225 ipsecstat.in_inval++;
226 goto fail;
227 }
228 #ifdef IPLEN_FLIPPED
229 ip->ip_len = len & 0xffff;
230 #else
231 ip->ip_len = htons(len & 0xffff);
232 #endif
233 ip->ip_p = nxt;
234 }
235
236 if (sav) {
237 key_sa_recordxfer(sav, m);
238 if (ipsec_addhist(m, IPPROTO_IPCOMP, (u_int32_t)cpi) != 0) {
239 ipsecstat.in_nomem++;
240 goto fail;
241 }
242 key_freesav(sav);
243 sav = NULL;
244 }
245
246 if (nxt != IPPROTO_DONE) {
247 if ((inetsw[ip_protox[nxt]].pr_flags & PR_LASTHDR) != 0 &&
248 ipsec4_in_reject(m, NULL)) {
249 ipsecstat.in_polvio++;
250 goto fail;
251 }
252 (*inetsw[ip_protox[nxt]].pr_input)(m, off, nxt);
253 } else
254 m_freem(m);
255 m = NULL;
256
257 ipsecstat.in_success++;
258 return;
259
260 fail:
261 if (sav)
262 key_freesav(sav);
263 if (m)
264 m_freem(m);
265 return;
266 }
267 #endif /* INET */
268
269 #ifdef INET6
270 int
271 ipcomp6_input(struct mbuf **mp, int *offp, int proto)
272 {
273 struct mbuf *m, *md;
274 int off;
275 struct ip6_hdr *ip6;
276 struct ipcomp *ipcomp;
277 const struct ipcomp_algorithm *algo;
278 u_int16_t cpi; /* host order */
279 u_int16_t nxt;
280 int error;
281 size_t newlen;
282 struct secasvar *sav = NULL;
283 u_int8_t *prvnxtp;
284
285 m = *mp;
286 off = *offp;
287
288 md = m_pulldown(m, off, sizeof(*ipcomp), NULL);
289 if (!md) {
290 m = NULL; /* already freed */
291 ipseclog((LOG_DEBUG, "IPv6 IPComp input: assumption failed "
292 "(pulldown failure)\n"));
293 ipsec6stat.in_inval++;
294 goto fail;
295 }
296 ipcomp = mtod(md, struct ipcomp *);
297 ip6 = mtod(m, struct ip6_hdr *);
298 nxt = ipcomp->comp_nxt;
299
300 cpi = ntohs(ipcomp->comp_cpi);
301
302 if (cpi >= IPCOMP_CPI_NEGOTIATE_MIN) {
303 sav = key_allocsa(AF_INET6, (caddr_t)&ip6->ip6_src,
304 (caddr_t)&ip6->ip6_dst, IPPROTO_IPCOMP,
305 htonl(cpi), 0, 0);
306 if (sav != NULL &&
307 (sav->state == SADB_SASTATE_MATURE ||
308 sav->state == SADB_SASTATE_DYING)) {
309 cpi = sav->alg_enc; /* XXX */
310 /* other parameters to look at? */
311 }
312 }
313 algo = ipcomp_algorithm_lookup(cpi);
314 if (!algo) {
315 ipseclog((LOG_WARNING, "IPv6 IPComp input: unknown cpi %u; "
316 "dropping the packet for simplicity\n", cpi));
317 ipsec6stat.in_nosa++;
318 goto fail;
319 }
320
321 /* chop ipcomp header */
322 ipcomp = NULL;
323 md->m_data += sizeof(struct ipcomp);
324 md->m_len -= sizeof(struct ipcomp);
325 m->m_pkthdr.len -= sizeof(struct ipcomp);
326
327 newlen = m->m_pkthdr.len - off;
328 error = (*algo->decompress)(m, md, &newlen);
329 if (error != 0) {
330 if (error == EINVAL)
331 ipsec6stat.in_inval++;
332 else if (error == ENOBUFS)
333 ipsec6stat.in_nomem++;
334 m = NULL;
335 goto fail;
336 }
337 ipsec6stat.in_comphist[cpi]++;
338 m->m_pkthdr.len = off + newlen;
339
340 /*
341 * returning decompressed packet onto icmp is meaningless.
342 * mark it decrypted to prevent icmp from attaching original packet.
343 */
344 m->m_flags |= M_DECRYPTED;
345
346 /* update next header field */
347 prvnxtp = ip6_get_prevhdr(m, off);
348 *prvnxtp = nxt;
349
350 /*
351 * no need to adjust payload length, as all the IPv6 protocols
352 * look at m->m_pkthdr.len
353 */
354
355 if (sav) {
356 key_sa_recordxfer(sav, m);
357 if (ipsec_addhist(m, IPPROTO_IPCOMP, (u_int32_t)cpi) != 0) {
358 ipsec6stat.in_nomem++;
359 goto fail;
360 }
361 key_freesav(sav);
362 sav = NULL;
363 }
364 *offp = off;
365 *mp = m;
366 ipsec6stat.in_success++;
367 return nxt;
368
369 fail:
370 if (m)
371 m_freem(m);
372 if (sav)
373 key_freesav(sav);
374 return IPPROTO_DONE;
375 }
376 #endif /* INET6 */
Cache object: c1f27dfa693b9fd1a3ad0f71dbe4d7d7
|