1 /* $NetBSD: ipcomp_input.c,v 1.22.14.3 2007/11/22 19:07:15 bouyer 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.22.14.3 2007/11/22 19:07:15 bouyer 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/ip.h>
65 #include <netinet/ip_var.h>
66 #include <netinet/ip_ecn.h>
67
68 #ifdef INET6
69 #include <netinet/ip6.h>
70 #include <netinet6/ip6_var.h>
71 #endif
72 #include <netinet6/ipcomp.h>
73
74 #include <netinet6/ipsec.h>
75 #include <netkey/key.h>
76 #include <netkey/keydb.h>
77
78 #include <machine/stdarg.h>
79
80 #include <net/net_osdep.h>
81
82 /*#define IPLEN_FLIPPED*/
83
84 #ifdef INET
85 void
86 #if __STDC__
87 ipcomp4_input(struct mbuf *m, ...)
88 #else
89 ipcomp4_input(m, va_alist)
90 struct mbuf *m;
91 va_dcl
92 #endif
93 {
94 struct mbuf *md;
95 struct ip *ip;
96 struct ipcomp *ipcomp;
97 const struct ipcomp_algorithm *algo;
98 u_int16_t cpi; /* host order */
99 u_int16_t nxt;
100 size_t hlen;
101 int error;
102 size_t newlen, olen;
103 struct secasvar *sav = NULL;
104 int off, proto;
105 va_list ap;
106
107 va_start(ap, m);
108 off = va_arg(ap, int);
109 proto = va_arg(ap, int);
110 va_end(ap);
111
112 if (m->m_pkthdr.len < off + sizeof(struct ipcomp)) {
113 ipseclog((LOG_DEBUG, "IPv4 IPComp input: assumption failed "
114 "(packet too short)\n"));
115 ipsecstat.in_inval++;
116 goto fail;
117 }
118
119 md = m_pulldown(m, off, sizeof(*ipcomp), NULL);
120 if (!md) {
121 m = NULL; /* already freed */
122 ipseclog((LOG_DEBUG, "IPv4 IPComp input: assumption failed "
123 "(pulldown failure)\n"));
124 ipsecstat.in_inval++;
125 goto fail;
126 }
127 ipcomp = mtod(md, struct ipcomp *);
128 ip = mtod(m, struct ip *);
129 nxt = ipcomp->comp_nxt;
130 #ifdef _IP_VHL
131 hlen = IP_VHL_HL(ip->ip_vhl) << 2;
132 #else
133 hlen = ip->ip_hl << 2;
134 #endif
135
136 cpi = ntohs(ipcomp->comp_cpi);
137
138 if (cpi >= IPCOMP_CPI_NEGOTIATE_MIN) {
139 sav = key_allocsa(AF_INET, (caddr_t)&ip->ip_src,
140 (caddr_t)&ip->ip_dst, IPPROTO_IPCOMP, htonl(cpi),
141 0, 0);
142 if (sav != NULL &&
143 (sav->state == SADB_SASTATE_MATURE ||
144 sav->state == SADB_SASTATE_DYING)) {
145 cpi = sav->alg_enc; /* XXX */
146 /* other parameters to look at? */
147 }
148 }
149 algo = ipcomp_algorithm_lookup(cpi);
150 if (!algo) {
151 ipseclog((LOG_WARNING, "IPv4 IPComp input: unknown cpi %u\n",
152 cpi));
153 ipsecstat.in_nosa++;
154 goto fail;
155 }
156
157 /* chop ipcomp header */
158 ipcomp = NULL;
159 md->m_data += sizeof(struct ipcomp);
160 md->m_len -= sizeof(struct ipcomp);
161 m->m_pkthdr.len -= sizeof(struct ipcomp);
162 #ifdef IPLEN_FLIPPED
163 ip->ip_len -= sizeof(struct ipcomp);
164 #else
165 ip->ip_len = htons(ntohs(ip->ip_len) - sizeof(struct ipcomp));
166 #endif
167
168 olen = m->m_pkthdr.len;
169 newlen = m->m_pkthdr.len - off;
170 error = (*algo->decompress)(m, m->m_next, &newlen);
171 if (error != 0) {
172 if (error == EINVAL)
173 ipsecstat.in_inval++;
174 else if (error == ENOBUFS)
175 ipsecstat.in_nomem++;
176 m = NULL;
177 goto fail;
178 }
179 ipsecstat.in_comphist[cpi]++;
180
181 /*
182 * returning decompressed packet onto icmp is meaningless.
183 * mark it decrypted to prevent icmp from attaching original packet.
184 */
185 m->m_flags |= M_DECRYPTED;
186
187 m->m_pkthdr.len = off + newlen;
188 ip = mtod(m, struct ip *);
189 {
190 size_t len;
191 #ifdef IPLEN_FLIPPED
192 len = ip->ip_len;
193 #else
194 len = ntohs(ip->ip_len);
195 #endif
196 /*
197 * be careful about underflow. also, do not assign exact value
198 * as ip_len is manipulated differently on *BSDs.
199 */
200 len += m->m_pkthdr.len;
201 len -= olen;
202 if (len & ~0xffff) {
203 /* packet too big after decompress */
204 ipsecstat.in_inval++;
205 goto fail;
206 }
207 #ifdef IPLEN_FLIPPED
208 ip->ip_len = len & 0xffff;
209 #else
210 ip->ip_len = htons(len & 0xffff);
211 #endif
212 ip->ip_p = nxt;
213 }
214
215 if (sav) {
216 key_sa_recordxfer(sav, m);
217 if (ipsec_addhist(m, IPPROTO_IPCOMP, (u_int32_t)cpi) != 0) {
218 ipsecstat.in_nomem++;
219 goto fail;
220 }
221 key_freesav(sav);
222 sav = NULL;
223 }
224
225 if (nxt != IPPROTO_DONE) {
226 if ((inetsw[ip_protox[nxt]].pr_flags & PR_LASTHDR) != 0 &&
227 ipsec4_in_reject(m, NULL)) {
228 ipsecstat.in_polvio++;
229 goto fail;
230 }
231 (*inetsw[ip_protox[nxt]].pr_input)(m, off, nxt);
232 } else
233 m_freem(m);
234 m = NULL;
235
236 ipsecstat.in_success++;
237 return;
238
239 fail:
240 if (sav)
241 key_freesav(sav);
242 if (m)
243 m_freem(m);
244 return;
245 }
246 #endif /* INET */
247
248 #ifdef INET6
249 int
250 ipcomp6_input(mp, offp, proto)
251 struct mbuf **mp;
252 int *offp, proto;
253 {
254 struct mbuf *m, *md;
255 int off;
256 struct ip6_hdr *ip6;
257 struct ipcomp *ipcomp;
258 const struct ipcomp_algorithm *algo;
259 u_int16_t cpi; /* host order */
260 u_int16_t nxt;
261 int error;
262 size_t newlen;
263 struct secasvar *sav = NULL;
264 u_int8_t *prvnxtp;
265
266 m = *mp;
267 off = *offp;
268
269 md = m_pulldown(m, off, sizeof(*ipcomp), NULL);
270 if (!md) {
271 m = NULL; /* already freed */
272 ipseclog((LOG_DEBUG, "IPv6 IPComp input: assumption failed "
273 "(pulldown failure)\n"));
274 ipsec6stat.in_inval++;
275 goto fail;
276 }
277 ipcomp = mtod(md, struct ipcomp *);
278 ip6 = mtod(m, struct ip6_hdr *);
279 nxt = ipcomp->comp_nxt;
280
281 cpi = ntohs(ipcomp->comp_cpi);
282
283 if (cpi >= IPCOMP_CPI_NEGOTIATE_MIN) {
284 sav = key_allocsa(AF_INET6, (caddr_t)&ip6->ip6_src,
285 (caddr_t)&ip6->ip6_dst, IPPROTO_IPCOMP,
286 htonl(cpi), 0, 0);
287 if (sav != NULL &&
288 (sav->state == SADB_SASTATE_MATURE ||
289 sav->state == SADB_SASTATE_DYING)) {
290 cpi = sav->alg_enc; /* XXX */
291 /* other parameters to look at? */
292 }
293 }
294 algo = ipcomp_algorithm_lookup(cpi);
295 if (!algo) {
296 ipseclog((LOG_WARNING, "IPv6 IPComp input: unknown cpi %u; "
297 "dropping the packet for simplicity\n", cpi));
298 ipsec6stat.in_nosa++;
299 goto fail;
300 }
301
302 /* chop ipcomp header */
303 ipcomp = NULL;
304 md->m_data += sizeof(struct ipcomp);
305 md->m_len -= sizeof(struct ipcomp);
306 m->m_pkthdr.len -= sizeof(struct ipcomp);
307
308 newlen = m->m_pkthdr.len - off;
309 error = (*algo->decompress)(m, md, &newlen);
310 if (error != 0) {
311 if (error == EINVAL)
312 ipsec6stat.in_inval++;
313 else if (error == ENOBUFS)
314 ipsec6stat.in_nomem++;
315 m = NULL;
316 goto fail;
317 }
318 ipsec6stat.in_comphist[cpi]++;
319 m->m_pkthdr.len = off + newlen;
320
321 /*
322 * returning decompressed packet onto icmp is meaningless.
323 * mark it decrypted to prevent icmp from attaching original packet.
324 */
325 m->m_flags |= M_DECRYPTED;
326
327 /* update next header field */
328 prvnxtp = ip6_get_prevhdr(m, off);
329 *prvnxtp = nxt;
330
331 /*
332 * no need to adjust payload length, as all the IPv6 protocols
333 * look at m->m_pkthdr.len
334 */
335
336 if (sav) {
337 key_sa_recordxfer(sav, m);
338 if (ipsec_addhist(m, IPPROTO_IPCOMP, (u_int32_t)cpi) != 0) {
339 ipsec6stat.in_nomem++;
340 goto fail;
341 }
342 key_freesav(sav);
343 sav = NULL;
344 }
345 *offp = off;
346 *mp = m;
347 ipsec6stat.in_success++;
348 return nxt;
349
350 fail:
351 if (m)
352 m_freem(m);
353 if (sav)
354 key_freesav(sav);
355 return IPPROTO_DONE;
356 }
357 #endif /* INET6 */
Cache object: 0a9cca3b0e73a66a41ca4218aac604bc
|