Bug Summary

File:netinet/ipsec_output.c
Warning:line 177, column 17
The right operand of '<' is a garbage value

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple amd64-unknown-openbsd7.0 -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name ipsec_output.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model static -mframe-pointer=all -relaxed-aliasing -fno-rounding-math -mconstructor-aliases -ffreestanding -mcmodel=kernel -target-cpu x86-64 -target-feature +retpoline-indirect-calls -target-feature +retpoline-indirect-branches -target-feature -sse2 -target-feature -sse -target-feature -3dnow -target-feature -mmx -target-feature +save-args -disable-red-zone -no-implicit-float -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/usr/src/sys/arch/amd64/compile/GENERIC.MP/obj -nostdsysteminc -nobuiltininc -resource-dir /usr/local/lib/clang/13.0.0 -I /usr/src/sys -I /usr/src/sys/arch/amd64/compile/GENERIC.MP/obj -I /usr/src/sys/arch -I /usr/src/sys/dev/pci/drm/include -I /usr/src/sys/dev/pci/drm/include/uapi -I /usr/src/sys/dev/pci/drm/amd/include/asic_reg -I /usr/src/sys/dev/pci/drm/amd/include -I /usr/src/sys/dev/pci/drm/amd/amdgpu -I /usr/src/sys/dev/pci/drm/amd/display -I /usr/src/sys/dev/pci/drm/amd/display/include -I /usr/src/sys/dev/pci/drm/amd/display/dc -I /usr/src/sys/dev/pci/drm/amd/display/amdgpu_dm -I /usr/src/sys/dev/pci/drm/amd/pm/inc -I /usr/src/sys/dev/pci/drm/amd/pm/swsmu -I /usr/src/sys/dev/pci/drm/amd/pm/swsmu/smu11 -I /usr/src/sys/dev/pci/drm/amd/pm/swsmu/smu12 -I /usr/src/sys/dev/pci/drm/amd/pm/powerplay -I /usr/src/sys/dev/pci/drm/amd/pm/powerplay/hwmgr -I /usr/src/sys/dev/pci/drm/amd/pm/powerplay/smumgr -I /usr/src/sys/dev/pci/drm/amd/display/dc/inc -I /usr/src/sys/dev/pci/drm/amd/display/dc/inc/hw -I /usr/src/sys/dev/pci/drm/amd/display/dc/clk_mgr -I /usr/src/sys/dev/pci/drm/amd/display/modules/inc -I /usr/src/sys/dev/pci/drm/amd/display/modules/hdcp -I /usr/src/sys/dev/pci/drm/amd/display/dmub/inc -I /usr/src/sys/dev/pci/drm/i915 -D DDB -D DIAGNOSTIC -D KTRACE -D ACCOUNTING -D KMEMSTATS -D PTRACE -D POOL_DEBUG -D CRYPTO -D SYSVMSG -D SYSVSEM -D SYSVSHM -D UVM_SWAP_ENCRYPT -D FFS -D FFS2 -D FFS_SOFTUPDATES -D UFS_DIRHASH -D QUOTA -D EXT2FS -D MFS -D NFSCLIENT -D NFSSERVER -D CD9660 -D UDF -D MSDOSFS -D FIFO -D FUSE -D SOCKET_SPLICE -D TCP_ECN -D TCP_SIGNATURE -D INET6 -D IPSEC -D PPP_BSDCOMP -D PPP_DEFLATE -D PIPEX -D MROUTING -D MPLS -D BOOT_CONFIG -D USER_PCICONF -D APERTURE -D MTRR -D NTFS -D HIBERNATE -D PCIVERBOSE -D USBVERBOSE -D WSDISPLAY_COMPAT_USL -D WSDISPLAY_COMPAT_RAWKBD -D WSDISPLAY_DEFAULTSCREENS=6 -D X86EMU -D ONEWIREVERBOSE -D MULTIPROCESSOR -D MAXUSERS=80 -D _KERNEL -D CONFIG_DRM_AMD_DC_DCN3_0 -O2 -Wno-pointer-sign -Wno-address-of-packed-member -Wno-constant-conversion -Wno-unused-but-set-variable -Wno-gnu-folding-constant -fdebug-compilation-dir=/usr/src/sys/arch/amd64/compile/GENERIC.MP/obj -ferror-limit 19 -fwrapv -D_RET_PROTECTOR -ret-protector -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-valloc -fno-builtin-free -fno-builtin-strdup -fno-builtin-strndup -analyzer-output=html -faddrsig -o /usr/obj/sys/arch/amd64/compile/GENERIC.MP/scan-build/2022-01-12-131800-47421-1 -x c /usr/src/sys/netinet/ipsec_output.c
1/* $OpenBSD: ipsec_output.c,v 1.97 2022/01/02 22:36:04 jsg Exp $ */
2/*
3 * The author of this code is Angelos D. Keromytis (angelos@cis.upenn.edu)
4 *
5 * Copyright (c) 2000-2001 Angelos D. Keromytis.
6 *
7 * Permission to use, copy, and modify this software with or without fee
8 * is hereby granted, provided that this entire notice is included in
9 * all copies of any software which is or includes a copy or
10 * modification of this software.
11 * You may use this code under the GNU public license if you so wish. Please
12 * contribute changes back to the authors under this freer than GPL license
13 * so that we may further the use of strong encryption without limitations to
14 * all.
15 *
16 * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR
17 * IMPLIED WARRANTY. IN PARTICULAR, NONE OF THE AUTHORS MAKES ANY
18 * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE
19 * MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
20 * PURPOSE.
21 */
22
23#include "pf.h"
24
25#include <sys/param.h>
26#include <sys/systm.h>
27#include <sys/mbuf.h>
28#include <sys/socket.h>
29#include <sys/kernel.h>
30#include <sys/timeout.h>
31
32#include <net/if.h>
33#include <net/route.h>
34
35#include <netinet/in.h>
36#include <netinet/ip.h>
37#include <netinet/in_pcb.h>
38#include <netinet/ip_var.h>
39
40#if NPF1 > 0
41#include <net/pfvar.h>
42#endif
43
44#include <netinet/udp.h>
45#include <netinet/ip_ipip.h>
46#include <netinet/ip_ah.h>
47#include <netinet/ip_esp.h>
48#include <netinet/ip_ipcomp.h>
49
50#include <crypto/cryptodev.h>
51#include <crypto/xform.h>
52
53#ifdef ENCDEBUG
54#define DPRINTF(fmt, args...)do { } while (0) \
55 do { \
56 if (encdebug) \
57 printf("%s: " fmt "\n", __func__, ## args); \
58 } while (0)
59#else
60#define DPRINTF(fmt, args...)do { } while (0) \
61 do { } while (0)
62#endif
63
64int udpencap_enable = 1; /* enabled by default */
65int udpencap_port = 4500; /* triggers decapsulation */
66
67/*
68 * Loop over a tdb chain, taking into consideration protocol tunneling. The
69 * fourth argument is set if the first encapsulation header is already in
70 * place.
71 */
72int
73ipsp_process_packet(struct mbuf *m, struct tdb *tdb, int af, int tunalready)
74{
75 int hlen, off, error;
1
'hlen' declared without an initial value
76#ifdef INET61
77 struct ip6_ext ip6e;
78 int nxt;
79 int dstopt = 0;
80#endif
81
82 int setdf = 0;
83 struct ip *ip;
84#ifdef INET61
85 struct ip6_hdr *ip6;
86#endif /* INET6 */
87
88#ifdef ENCDEBUG
89 char buf[INET6_ADDRSTRLEN46];
90#endif
91
92 /* Check that the transform is allowed by the administrator. */
93 if ((tdb->tdb_sproto == IPPROTO_ESP50 && !esp_enable) ||
2
Assuming field 'tdb_sproto' is not equal to IPPROTO_ESP
94 (tdb->tdb_sproto == IPPROTO_AH51 && !ah_enable) ||
3
Assuming field 'tdb_sproto' is not equal to IPPROTO_AH
95 (tdb->tdb_sproto == IPPROTO_IPCOMP108 && !ipcomp_enable)) {
4
Assuming field 'tdb_sproto' is not equal to IPPROTO_IPCOMP
96 DPRINTF("IPsec outbound packet dropped due to policy "do { } while (0)
97 "(check your sysctls)")do { } while (0);
98 error = EHOSTUNREACH65;
99 goto drop;
100 }
101
102 /* Sanity check. */
103 if (!tdb->tdb_xform) {
5
Assuming field 'tdb_xform' is non-null
6
Taking false branch
104 DPRINTF("uninitialized TDB")do { } while (0);
105 error = EHOSTUNREACH65;
106 goto drop;
107 }
108
109 /* Check if the SPI is invalid. */
110 if (tdb->tdb_flags & TDBF_INVALID0x00010) {
7
Assuming the condition is false
8
Taking false branch
111 DPRINTF("attempt to use invalid SA %s/%08x/%u",do { } while (0)
112 ipsp_address(&tdb->tdb_dst, buf, sizeof(buf)),do { } while (0)
113 ntohl(tdb->tdb_spi), tdb->tdb_sproto)do { } while (0);
114 error = ENXIO6;
115 goto drop;
116 }
117
118 /* Check that the network protocol is supported */
119 switch (tdb->tdb_dst.sa.sa_family) {
9
Control jumps to 'case 24:' at line 124
120 case AF_INET2:
121 break;
122
123#ifdef INET61
124 case AF_INET624:
125 break;
10
Execution continues on line 140
126#endif /* INET6 */
127
128 default:
129 DPRINTF("attempt to use SA %s/%08x/%u for protocol family %d",do { } while (0)
130 ipsp_address(&tdb->tdb_dst, buf, sizeof(buf)),do { } while (0)
131 ntohl(tdb->tdb_spi), tdb->tdb_sproto,do { } while (0)
132 tdb->tdb_dst.sa.sa_family)do { } while (0);
133 error = EPFNOSUPPORT46;
134 goto drop;
135 }
136
137 /*
138 * Register first use if applicable, setup relevant expiration timer.
139 */
140 if (tdb->tdb_first_use == 0) {
11
Assuming field 'tdb_first_use' is equal to 0
12
Taking true branch
141 tdb->tdb_first_use = gettime();
142 if (tdb->tdb_flags & TDBF_FIRSTUSE0x00020) {
13
Assuming the condition is false
14
Taking false branch
143 if (timeout_add_sec(&tdb->tdb_first_tmo,
144 tdb->tdb_exp_first_use))
145 tdb_ref(tdb);
146 }
147 if (tdb->tdb_flags & TDBF_SOFT_FIRSTUSE0x00400) {
15
Assuming the condition is true
16
Taking true branch
148 if (timeout_add_sec(&tdb->tdb_sfirst_tmo,
17
Assuming the condition is false
18
Taking false branch
149 tdb->tdb_soft_first_use))
150 tdb_ref(tdb);
151 }
152 }
153
154 /*
155 * Check for tunneling if we don't have the first header in place.
156 * When doing Ethernet-over-IP, we are handed an already-encapsulated
157 * frame, so we don't need to re-encapsulate.
158 */
159 if (tunalready == 0) {
19
Assuming 'tunalready' is equal to 0
20
Taking true branch
160 /*
161 * If the target protocol family is different, we know we'll be
162 * doing tunneling.
163 */
164 if (af == tdb->tdb_dst.sa.sa_family) {
21
Assuming 'af' is equal to field 'sa_family'
22
Taking true branch
165 switch (af) {
23
'Default' branch taken. Execution continues on line 177
166 case AF_INET2:
167 hlen = sizeof(struct ip);
168 break;
169#ifdef INET61
170 case AF_INET624:
171 hlen = sizeof(struct ip6_hdr);
172 break;
173#endif /* INET6 */
174 }
175
176 /* Bring the network header in the first mbuf. */
177 if (m->m_lenm_hdr.mh_len < hlen) {
24
The right operand of '<' is a garbage value
178 if ((m = m_pullup(m, hlen)) == NULL((void *)0)) {
179 error = ENOBUFS55;
180 goto drop;
181 }
182 }
183
184 if (af == AF_INET2) {
185 ip = mtod(m, struct ip *)((struct ip *)((m)->m_hdr.mh_data));
186
187 /*
188 * This is not a bridge packet, remember if we
189 * had IP_DF.
190 */
191 setdf = ip->ip_off & htons(IP_DF)(__uint16_t)(__builtin_constant_p(0x4000) ? (__uint16_t)(((__uint16_t
)(0x4000) & 0xffU) << 8 | ((__uint16_t)(0x4000) &
0xff00U) >> 8) : __swap16md(0x4000))
;
192 }
193
194#ifdef INET61
195 if (af == AF_INET624)
196 ip6 = mtod(m, struct ip6_hdr *)((struct ip6_hdr *)((m)->m_hdr.mh_data));
197#endif /* INET6 */
198 }
199
200 /* Do the appropriate encapsulation, if necessary. */
201 if ((tdb->tdb_dst.sa.sa_family != af) || /* PF mismatch */
202 (tdb->tdb_flags & TDBF_TUNNELING0x01000) || /* Tunneling needed */
203 (tdb->tdb_xform->xf_type == XF_IP41) || /* ditto */
204 ((tdb->tdb_dst.sa.sa_family == AF_INET2) &&
205 (tdb->tdb_dst.sin.sin_addr.s_addr != INADDR_ANY((u_int32_t) (__uint32_t)(__builtin_constant_p((u_int32_t)(0x00000000
)) ? (__uint32_t)(((__uint32_t)((u_int32_t)(0x00000000)) &
0xff) << 24 | ((__uint32_t)((u_int32_t)(0x00000000)) &
0xff00) << 8 | ((__uint32_t)((u_int32_t)(0x00000000)) &
0xff0000) >> 8 | ((__uint32_t)((u_int32_t)(0x00000000)
) & 0xff000000) >> 24) : __swap32md((u_int32_t)(0x00000000
))))
) &&
206 (tdb->tdb_dst.sin.sin_addr.s_addr != ip->ip_dst.s_addr)) ||
207#ifdef INET61
208 ((tdb->tdb_dst.sa.sa_family == AF_INET624) &&
209 (!IN6_IS_ADDR_UNSPECIFIED(&tdb->tdb_dst.sin6.sin6_addr)((*(const u_int32_t *)(const void *)(&(&tdb->tdb_dst
.sin6.sin6_addr)->__u6_addr.__u6_addr8[0]) == 0) &&
(*(const u_int32_t *)(const void *)(&(&tdb->tdb_dst
.sin6.sin6_addr)->__u6_addr.__u6_addr8[4]) == 0) &&
(*(const u_int32_t *)(const void *)(&(&tdb->tdb_dst
.sin6.sin6_addr)->__u6_addr.__u6_addr8[8]) == 0) &&
(*(const u_int32_t *)(const void *)(&(&tdb->tdb_dst
.sin6.sin6_addr)->__u6_addr.__u6_addr8[12]) == 0))
) &&
210 (!IN6_ARE_ADDR_EQUAL(&tdb->tdb_dst.sin6.sin6_addr,(__builtin_memcmp((&(&tdb->tdb_dst.sin6.sin6_addr)
->__u6_addr.__u6_addr8[0]), (&(&ip6->ip6_dst)->
__u6_addr.__u6_addr8[0]), (sizeof(struct in6_addr))) == 0)
211 &ip6->ip6_dst)(__builtin_memcmp((&(&tdb->tdb_dst.sin6.sin6_addr)
->__u6_addr.__u6_addr8[0]), (&(&ip6->ip6_dst)->
__u6_addr.__u6_addr8[0]), (sizeof(struct in6_addr))) == 0)
)) ||
212#endif /* INET6 */
213 0) {
214 /* Fix IPv4 header checksum and length. */
215 if (af == AF_INET2) {
216 if (m->m_lenm_hdr.mh_len < sizeof(struct ip))
217 if ((m = m_pullup(m,
218 sizeof(struct ip))) == NULL((void *)0)) {
219 error = ENOBUFS55;
220 goto drop;
221 }
222
223 ip = mtod(m, struct ip *)((struct ip *)((m)->m_hdr.mh_data));
224 ip->ip_len = htons(m->m_pkthdr.len)(__uint16_t)(__builtin_constant_p(m->M_dat.MH.MH_pkthdr.len
) ? (__uint16_t)(((__uint16_t)(m->M_dat.MH.MH_pkthdr.len) &
0xffU) << 8 | ((__uint16_t)(m->M_dat.MH.MH_pkthdr.len
) & 0xff00U) >> 8) : __swap16md(m->M_dat.MH.MH_pkthdr
.len))
;
225 ip->ip_sum = 0;
226 ip->ip_sum = in_cksum(m, ip->ip_hl << 2);
227 }
228
229#ifdef INET61
230 /* Fix IPv6 header payload length. */
231 if (af == AF_INET624) {
232 if (m->m_lenm_hdr.mh_len < sizeof(struct ip6_hdr))
233 if ((m = m_pullup(m,
234 sizeof(struct ip6_hdr))) == NULL((void *)0)) {
235 error = ENOBUFS55;
236 goto drop;
237 }
238
239 if (m->m_pkthdrM_dat.MH.MH_pkthdr.len - sizeof(*ip6) >
240 IPV6_MAXPACKET65535) {
241 /* No jumbogram support. */
242 error = ENXIO6; /*?*/
243 goto drop;
244 }
245 ip6 = mtod(m, struct ip6_hdr *)((struct ip6_hdr *)((m)->m_hdr.mh_data));
246 ip6->ip6_plenip6_ctlun.ip6_un1.ip6_un1_plen = htons(m->m_pkthdr.len(__uint16_t)(__builtin_constant_p(m->M_dat.MH.MH_pkthdr.len
- sizeof(*ip6)) ? (__uint16_t)(((__uint16_t)(m->M_dat.MH.
MH_pkthdr.len - sizeof(*ip6)) & 0xffU) << 8 | ((__uint16_t
)(m->M_dat.MH.MH_pkthdr.len - sizeof(*ip6)) & 0xff00U)
>> 8) : __swap16md(m->M_dat.MH.MH_pkthdr.len - sizeof
(*ip6)))
247 - sizeof(*ip6))(__uint16_t)(__builtin_constant_p(m->M_dat.MH.MH_pkthdr.len
- sizeof(*ip6)) ? (__uint16_t)(((__uint16_t)(m->M_dat.MH.
MH_pkthdr.len - sizeof(*ip6)) & 0xffU) << 8 | ((__uint16_t
)(m->M_dat.MH.MH_pkthdr.len - sizeof(*ip6)) & 0xff00U)
>> 8) : __swap16md(m->M_dat.MH.MH_pkthdr.len - sizeof
(*ip6)))
;
248 }
249#endif /* INET6 */
250
251 /* Encapsulate -- m may be changed or set to NULL. */
252 error = ipip_output(&m, tdb);
253 if ((m == NULL((void *)0)) && (!error))
254 error = EFAULT14;
255 if (error)
256 goto drop;
257
258 if (tdb->tdb_dst.sa.sa_family == AF_INET2 && setdf) {
259 if (m->m_lenm_hdr.mh_len < sizeof(struct ip))
260 if ((m = m_pullup(m,
261 sizeof(struct ip))) == NULL((void *)0)) {
262 error = ENOBUFS55;
263 goto drop;
264 }
265
266 ip = mtod(m, struct ip *)((struct ip *)((m)->m_hdr.mh_data));
267 ip->ip_off |= htons(IP_DF)(__uint16_t)(__builtin_constant_p(0x4000) ? (__uint16_t)(((__uint16_t
)(0x4000) & 0xffU) << 8 | ((__uint16_t)(0x4000) &
0xff00U) >> 8) : __swap16md(0x4000))
;
268 }
269
270 /* Remember that we appended a tunnel header. */
271 mtx_enter(&tdb->tdb_mtx);
272 tdb->tdb_flags |= TDBF_USEDTUNNEL0x10000;
273 mtx_leave(&tdb->tdb_mtx);
274 }
275 }
276
277 /*
278 * If this is just an IP-IP TDB and we're told there's already an
279 * encapsulation header or ipip_output() has encapsulated it, move on.
280 */
281 if (tdb->tdb_xform->xf_type == XF_IP41)
282 return ipsp_process_done(m, tdb);
283
284 /* Extract some information off the headers. */
285 switch (tdb->tdb_dst.sa.sa_family) {
286 case AF_INET2:
287 ip = mtod(m, struct ip *)((struct ip *)((m)->m_hdr.mh_data));
288 hlen = ip->ip_hl << 2;
289 off = offsetof(struct ip, ip_p)__builtin_offsetof(struct ip, ip_p);
290 break;
291
292#ifdef INET61
293 case AF_INET624:
294 ip6 = mtod(m, struct ip6_hdr *)((struct ip6_hdr *)((m)->m_hdr.mh_data));
295 hlen = sizeof(struct ip6_hdr);
296 off = offsetof(struct ip6_hdr, ip6_nxt)__builtin_offsetof(struct ip6_hdr, ip6_ctlun.ip6_un1.ip6_un1_nxt
)
;
297 nxt = ip6->ip6_nxtip6_ctlun.ip6_un1.ip6_un1_nxt;
298 /*
299 * chase mbuf chain to find the appropriate place to
300 * put AH/ESP/IPcomp header.
301 * IPv6 hbh dest1 rthdr ah* [esp* dest2 payload]
302 */
303 do {
304 switch (nxt) {
305 case IPPROTO_AH51:
306 case IPPROTO_ESP50:
307 case IPPROTO_IPCOMP108:
308 /*
309 * we should not skip security header added
310 * beforehand.
311 */
312 goto exitip6loop;
313
314 case IPPROTO_HOPOPTS0:
315 case IPPROTO_DSTOPTS60:
316 case IPPROTO_ROUTING43:
317 /*
318 * if we see 2nd destination option header,
319 * we should stop there.
320 */
321 if (nxt == IPPROTO_DSTOPTS60 && dstopt)
322 goto exitip6loop;
323
324 if (nxt == IPPROTO_DSTOPTS60) {
325 /*
326 * seen 1st or 2nd destination option.
327 * next time we see one, it must be 2nd.
328 */
329 dstopt = 1;
330 } else if (nxt == IPPROTO_ROUTING43) {
331 /*
332 * if we see destination option next
333 * time, it must be dest2.
334 */
335 dstopt = 2;
336 }
337 if (m->m_pkthdrM_dat.MH.MH_pkthdr.len < hlen + sizeof(ip6e)) {
338 error = EINVAL22;
339 goto drop;
340 }
341 /* skip this header */
342 m_copydata(m, hlen, sizeof(ip6e),
343 (caddr_t)&ip6e);
344 nxt = ip6e.ip6e_nxt;
345 off = hlen + offsetof(struct ip6_ext, ip6e_nxt)__builtin_offsetof(struct ip6_ext, ip6e_nxt);
346 /*
347 * we will never see nxt == IPPROTO_AH
348 * so it is safe to omit AH case.
349 */
350 hlen += (ip6e.ip6e_len + 1) << 3;
351 break;
352 default:
353 goto exitip6loop;
354 }
355 } while (hlen < m->m_pkthdrM_dat.MH.MH_pkthdr.len);
356 exitip6loop:
357 break;
358#endif /* INET6 */
359 default:
360 error = EPFNOSUPPORT46;
361 goto drop;
362 }
363
364 if (m->m_pkthdrM_dat.MH.MH_pkthdr.len < hlen) {
365 error = EINVAL22;
366 goto drop;
367 }
368
369 ipsecstat_add(ipsec_ouncompbytes, m->m_pkthdrM_dat.MH.MH_pkthdr.len);
370 tdbstat_add(tdb, tdb_ouncompbytes, m->m_pkthdrM_dat.MH.MH_pkthdr.len);
371
372 /* Non expansion policy for IPCOMP */
373 if (tdb->tdb_sproto == IPPROTO_IPCOMP108) {
374 if ((m->m_pkthdrM_dat.MH.MH_pkthdr.len - hlen) < tdb->tdb_compalgxform->minlen) {
375 /* No need to compress, leave the packet untouched */
376 ipcompstat_inc(ipcomps_minlen);
377 return ipsp_process_done(m, tdb);
378 }
379 }
380
381 /* Invoke the IPsec transform. */
382 return (*(tdb->tdb_xform->xf_output))(m, tdb, hlen, off);
383
384 drop:
385 m_freem(m);
386 return error;
387}
388
389/*
390 * Called by the IPsec output transform callbacks, to transmit the packet
391 * or do further processing, as necessary.
392 */
393int
394ipsp_process_done(struct mbuf *m, struct tdb *tdb)
395{
396 struct ip *ip;
397#ifdef INET61
398 struct ip6_hdr *ip6;
399#endif /* INET6 */
400 struct tdb *tdbo;
401 struct tdb_ident *tdbi;
402 struct m_tag *mtag;
403 int roff, error;
404
405 NET_ASSERT_LOCKED()do { int _s = rw_status(&netlock); if ((splassert_ctl >
0) && (_s != 0x0001UL && _s != 0x0002UL)) splassert_fail
(0x0002UL, _s, __func__); } while (0)
;
406
407 tdb->tdb_last_used = gettime();
408
409 if ((tdb->tdb_flags & TDBF_UDPENCAP0x20000) != 0) {
410 struct mbuf *mi;
411 struct udphdr *uh;
412 int iphlen;
413
414 if (!udpencap_enable || !udpencap_port) {
415 error = ENXIO6;
416 goto drop;
417 }
418
419 switch (tdb->tdb_dst.sa.sa_family) {
420 case AF_INET2:
421 iphlen = sizeof(struct ip);
422 break;
423#ifdef INET61
424 case AF_INET624:
425 iphlen = sizeof(struct ip6_hdr);
426 break;
427#endif /* INET6 */
428 default:
429 DPRINTF("unknown protocol family (%d)",do { } while (0)
430 tdb->tdb_dst.sa.sa_family)do { } while (0);
431 error = EPFNOSUPPORT46;
432 goto drop;
433 }
434
435 mi = m_makespace(m, iphlen, sizeof(struct udphdr), &roff);
436 if (mi == NULL((void *)0)) {
437 error = ENOMEM12;
438 goto drop;
439 }
440 uh = (struct udphdr *)(mtod(mi, caddr_t)((caddr_t)((mi)->m_hdr.mh_data)) + roff);
441 uh->uh_sport = uh->uh_dport = htons(udpencap_port)(__uint16_t)(__builtin_constant_p(udpencap_port) ? (__uint16_t
)(((__uint16_t)(udpencap_port) & 0xffU) << 8 | ((__uint16_t
)(udpencap_port) & 0xff00U) >> 8) : __swap16md(udpencap_port
))
;
442 if (tdb->tdb_udpencap_port)
443 uh->uh_dport = tdb->tdb_udpencap_port;
444
445 uh->uh_ulen = htons(m->m_pkthdr.len - iphlen)(__uint16_t)(__builtin_constant_p(m->M_dat.MH.MH_pkthdr.len
- iphlen) ? (__uint16_t)(((__uint16_t)(m->M_dat.MH.MH_pkthdr
.len - iphlen) & 0xffU) << 8 | ((__uint16_t)(m->
M_dat.MH.MH_pkthdr.len - iphlen) & 0xff00U) >> 8) :
__swap16md(m->M_dat.MH.MH_pkthdr.len - iphlen))
;
446 uh->uh_sum = 0;
447#ifdef INET61
448 if (tdb->tdb_dst.sa.sa_family == AF_INET624)
449 m->m_pkthdrM_dat.MH.MH_pkthdr.csum_flags |= M_UDP_CSUM_OUT0x0004;
450#endif /* INET6 */
451 espstat_inc(esps_udpencout);
452 }
453
454 switch (tdb->tdb_dst.sa.sa_family) {
455 case AF_INET2:
456 /* Fix the header length, for AH processing. */
457 ip = mtod(m, struct ip *)((struct ip *)((m)->m_hdr.mh_data));
458 ip->ip_len = htons(m->m_pkthdr.len)(__uint16_t)(__builtin_constant_p(m->M_dat.MH.MH_pkthdr.len
) ? (__uint16_t)(((__uint16_t)(m->M_dat.MH.MH_pkthdr.len) &
0xffU) << 8 | ((__uint16_t)(m->M_dat.MH.MH_pkthdr.len
) & 0xff00U) >> 8) : __swap16md(m->M_dat.MH.MH_pkthdr
.len))
;
459 if ((tdb->tdb_flags & TDBF_UDPENCAP0x20000) != 0)
460 ip->ip_p = IPPROTO_UDP17;
461 break;
462
463#ifdef INET61
464 case AF_INET624:
465 /* Fix the header length, for AH processing. */
466 if (m->m_pkthdrM_dat.MH.MH_pkthdr.len < sizeof(*ip6)) {
467 error = ENXIO6;
468 goto drop;
469 }
470 if (m->m_pkthdrM_dat.MH.MH_pkthdr.len - sizeof(*ip6) > IPV6_MAXPACKET65535) {
471 /* No jumbogram support. */
472 error = ENXIO6;
473 goto drop;
474 }
475 ip6 = mtod(m, struct ip6_hdr *)((struct ip6_hdr *)((m)->m_hdr.mh_data));
476 ip6->ip6_plenip6_ctlun.ip6_un1.ip6_un1_plen = htons(m->m_pkthdr.len - sizeof(*ip6))(__uint16_t)(__builtin_constant_p(m->M_dat.MH.MH_pkthdr.len
- sizeof(*ip6)) ? (__uint16_t)(((__uint16_t)(m->M_dat.MH.
MH_pkthdr.len - sizeof(*ip6)) & 0xffU) << 8 | ((__uint16_t
)(m->M_dat.MH.MH_pkthdr.len - sizeof(*ip6)) & 0xff00U)
>> 8) : __swap16md(m->M_dat.MH.MH_pkthdr.len - sizeof
(*ip6)))
;
477 if ((tdb->tdb_flags & TDBF_UDPENCAP0x20000) != 0)
478 ip6->ip6_nxtip6_ctlun.ip6_un1.ip6_un1_nxt = IPPROTO_UDP17;
479 break;
480#endif /* INET6 */
481
482 default:
483 DPRINTF("unknown protocol family (%d)",do { } while (0)
484 tdb->tdb_dst.sa.sa_family)do { } while (0);
485 error = EPFNOSUPPORT46;
486 goto drop;
487 }
488
489 /*
490 * Add a record of what we've done or what needs to be done to the
491 * packet.
492 */
493 mtag = m_tag_get(PACKET_TAG_IPSEC_OUT_DONE0x0002, sizeof(struct tdb_ident),
494 M_NOWAIT0x0002);
495 if (mtag == NULL((void *)0)) {
496 DPRINTF("could not allocate packet tag")do { } while (0);
497 error = ENOMEM12;
498 goto drop;
499 }
500
501 tdbi = (struct tdb_ident *)(mtag + 1);
502 tdbi->dst = tdb->tdb_dst;
503 tdbi->proto = tdb->tdb_sproto;
504 tdbi->spi = tdb->tdb_spi;
505 tdbi->rdomain = tdb->tdb_rdomain;
506
507 m_tag_prepend(m, mtag);
508
509 ipsecstat_pkt(ipsec_opackets, ipsec_obytes, m->m_pkthdrM_dat.MH.MH_pkthdr.len);
510 tdbstat_pkt(tdb, tdb_opackets, tdb_obytes, m->m_pkthdrM_dat.MH.MH_pkthdr.len);
511
512 /* If there's another (bundled) TDB to apply, do so. */
513 tdbo = tdb_ref(tdb->tdb_onext);
514 if (tdbo != NULL((void *)0)) {
515 KERNEL_ASSERT_LOCKED()((_kernel_lock_held()) ? (void)0 : __assert("diagnostic ", "/usr/src/sys/netinet/ipsec_output.c"
, 515, "_kernel_lock_held()"))
;
516 error = ipsp_process_packet(m, tdbo,
517 tdb->tdb_dst.sa.sa_family, 0);
518 tdb_unref(tdbo);
519 return error;
520 }
521
522#if NPF1 > 0
523 /* Add pf tag if requested. */
524 pf_tag_packet(m, tdb->tdb_tag, -1);
525 pf_pkt_addr_changed(m);
526#endif
527 if (tdb->tdb_rdomain != tdb->tdb_rdomain_post)
528 m->m_pkthdrM_dat.MH.MH_pkthdr.ph_rtableid = tdb->tdb_rdomain_post;
529
530 /*
531 * We're done with IPsec processing, transmit the packet using the
532 * appropriate network protocol (IP or IPv6). SPD lookup will be
533 * performed again there.
534 */
535 switch (tdb->tdb_dst.sa.sa_family) {
536 case AF_INET2:
537 error = ip_output(m, NULL((void *)0), NULL((void *)0), IP_RAWOUTPUT0x2, NULL((void *)0), NULL((void *)0), 0);
538 break;
539#ifdef INET61
540 case AF_INET624:
541 /*
542 * We don't need massage, IPv6 header fields are always in
543 * net endian.
544 */
545 error = ip6_output(m, NULL((void *)0), NULL((void *)0), 0, NULL((void *)0), NULL((void *)0));
546 break;
547#endif /* INET6 */
548 default:
549 error = EPFNOSUPPORT46;
550 break;
551 }
552 return error;
553
554 drop:
555 m_freem(m);
556 return error;
557}
558
559ssize_t
560ipsec_hdrsz(struct tdb *tdbp)
561{
562 ssize_t adjust;
563
564 switch (tdbp->tdb_sproto) {
565 case IPPROTO_IPIP4:
566 adjust = 0;
567 break;
568
569 case IPPROTO_ESP50:
570 if (tdbp->tdb_encalgxform == NULL((void *)0))
571 return (-1);
572
573 /* Header length */
574 adjust = 2 * sizeof(u_int32_t) + tdbp->tdb_ivlen;
575 if (tdbp->tdb_flags & TDBF_UDPENCAP0x20000)
576 adjust += sizeof(struct udphdr);
577 /* Authenticator */
578 if (tdbp->tdb_authalgxform != NULL((void *)0))
579 adjust += tdbp->tdb_authalgxform->authsize;
580 /* Padding */
581 adjust += MAX(4, tdbp->tdb_encalgxform->blocksize)(((4)>(tdbp->tdb_encalgxform->blocksize))?(4):(tdbp->
tdb_encalgxform->blocksize))
;
582 break;
583
584 case IPPROTO_AH51:
585 if (tdbp->tdb_authalgxform == NULL((void *)0))
586 return (-1);
587
588 adjust = AH_FLENGTH8 + sizeof(u_int32_t);
589 adjust += tdbp->tdb_authalgxform->authsize;
590 break;
591
592 default:
593 return (-1);
594 }
595
596 if (!(tdbp->tdb_flags & TDBF_TUNNELING0x01000) &&
597 !(tdbp->tdb_flags & TDBF_USEDTUNNEL0x10000))
598 return (adjust);
599
600 switch (tdbp->tdb_dst.sa.sa_family) {
601 case AF_INET2:
602 adjust += sizeof(struct ip);
603 break;
604#ifdef INET61
605 case AF_INET624:
606 adjust += sizeof(struct ip6_hdr);
607 break;
608#endif /* INET6 */
609 }
610
611 return (adjust);
612}
613
614void
615ipsec_adjust_mtu(struct mbuf *m, u_int32_t mtu)
616{
617 struct tdb_ident *tdbi;
618 struct tdb *tdbp;
619 struct m_tag *mtag;
620 ssize_t adjust;
621
622 NET_ASSERT_LOCKED()do { int _s = rw_status(&netlock); if ((splassert_ctl >
0) && (_s != 0x0001UL && _s != 0x0002UL)) splassert_fail
(0x0002UL, _s, __func__); } while (0)
;
623
624 for (mtag = m_tag_find(m, PACKET_TAG_IPSEC_OUT_DONE0x0002, NULL((void *)0)); mtag;
625 mtag = m_tag_find(m, PACKET_TAG_IPSEC_OUT_DONE0x0002, mtag)) {
626 tdbi = (struct tdb_ident *)(mtag + 1);
627 tdbp = gettdb(tdbi->rdomain, tdbi->spi, &tdbi->dst,gettdb_dir((tdbi->rdomain),(tdbi->spi),(&tdbi->dst
),(tdbi->proto),0)
628 tdbi->proto)gettdb_dir((tdbi->rdomain),(tdbi->spi),(&tdbi->dst
),(tdbi->proto),0)
;
629 if (tdbp == NULL((void *)0))
630 break;
631
632 if ((adjust = ipsec_hdrsz(tdbp)) == -1) {
633 tdb_unref(tdbp);
634 break;
635 }
636
637 mtu -= adjust;
638 tdbp->tdb_mtu = mtu;
639 tdbp->tdb_mtutimeout = gettime() + ip_mtudisc_timeout;
640 DPRINTF("spi %08x mtu %d adjust %ld mbuf %p",do { } while (0)
641 ntohl(tdbp->tdb_spi), tdbp->tdb_mtu, adjust, m)do { } while (0);
642 tdb_unref(tdbp);
643 }
644}