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