npf_inet.c revision 1.27 1 1.27 rmind /* $NetBSD: npf_inet.c,v 1.27 2013/11/22 01:48:36 rmind Exp $ */
2 1.1 rmind
3 1.1 rmind /*-
4 1.12 rmind * Copyright (c) 2009-2012 The NetBSD Foundation, Inc.
5 1.1 rmind * All rights reserved.
6 1.1 rmind *
7 1.1 rmind * This material is based upon work partially supported by The
8 1.1 rmind * NetBSD Foundation under a contract with Mindaugas Rasiukevicius.
9 1.1 rmind *
10 1.1 rmind * Redistribution and use in source and binary forms, with or without
11 1.1 rmind * modification, are permitted provided that the following conditions
12 1.1 rmind * are met:
13 1.1 rmind * 1. Redistributions of source code must retain the above copyright
14 1.1 rmind * notice, this list of conditions and the following disclaimer.
15 1.1 rmind * 2. Redistributions in binary form must reproduce the above copyright
16 1.1 rmind * notice, this list of conditions and the following disclaimer in the
17 1.1 rmind * documentation and/or other materials provided with the distribution.
18 1.1 rmind *
19 1.1 rmind * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 1.1 rmind * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 1.1 rmind * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 1.1 rmind * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 1.1 rmind * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 1.1 rmind * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 1.1 rmind * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 1.1 rmind * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 1.1 rmind * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 1.1 rmind * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 1.1 rmind * POSSIBILITY OF SUCH DAMAGE.
30 1.1 rmind */
31 1.1 rmind
32 1.1 rmind /*
33 1.22 rmind * Various protocol related helper routines.
34 1.12 rmind *
35 1.12 rmind * This layer manipulates npf_cache_t structure i.e. caches requested headers
36 1.12 rmind * and stores which information was cached in the information bit field.
37 1.12 rmind * It is also responsibility of this layer to update or invalidate the cache
38 1.12 rmind * on rewrites (e.g. by translation routines).
39 1.1 rmind */
40 1.1 rmind
41 1.1 rmind #include <sys/cdefs.h>
42 1.27 rmind __KERNEL_RCSID(0, "$NetBSD: npf_inet.c,v 1.27 2013/11/22 01:48:36 rmind Exp $");
43 1.1 rmind
44 1.1 rmind #include <sys/param.h>
45 1.11 rmind #include <sys/types.h>
46 1.1 rmind
47 1.4 rmind #include <net/pfil.h>
48 1.4 rmind #include <net/if.h>
49 1.4 rmind #include <net/ethertypes.h>
50 1.4 rmind #include <net/if_ether.h>
51 1.4 rmind
52 1.1 rmind #include <netinet/in_systm.h>
53 1.1 rmind #include <netinet/in.h>
54 1.1 rmind #include <netinet/ip.h>
55 1.4 rmind #include <netinet/ip6.h>
56 1.1 rmind #include <netinet/tcp.h>
57 1.1 rmind #include <netinet/udp.h>
58 1.1 rmind #include <netinet/ip_icmp.h>
59 1.1 rmind
60 1.1 rmind #include "npf_impl.h"
61 1.1 rmind
62 1.1 rmind /*
63 1.27 rmind * npf_fixup{16,32}_cksum: incremental update of the Internet checksum.
64 1.1 rmind */
65 1.1 rmind
66 1.1 rmind uint16_t
67 1.1 rmind npf_fixup16_cksum(uint16_t cksum, uint16_t odatum, uint16_t ndatum)
68 1.1 rmind {
69 1.1 rmind uint32_t sum;
70 1.1 rmind
71 1.1 rmind /*
72 1.1 rmind * RFC 1624:
73 1.1 rmind * HC' = ~(~HC + ~m + m')
74 1.27 rmind *
75 1.27 rmind * Note: 1's complement sum is endian-independent (RFC 1071, page 2).
76 1.1 rmind */
77 1.27 rmind sum = ~cksum & 0xffff;
78 1.27 rmind sum += (~odatum & 0xffff) + ndatum;
79 1.1 rmind sum = (sum >> 16) + (sum & 0xffff);
80 1.1 rmind sum += (sum >> 16);
81 1.1 rmind
82 1.27 rmind return ~sum & 0xffff;
83 1.1 rmind }
84 1.1 rmind
85 1.1 rmind uint16_t
86 1.1 rmind npf_fixup32_cksum(uint16_t cksum, uint32_t odatum, uint32_t ndatum)
87 1.1 rmind {
88 1.27 rmind uint32_t sum;
89 1.27 rmind
90 1.27 rmind /*
91 1.27 rmind * Checksum 32-bit datum as as two 16-bit. Note, the first
92 1.27 rmind * 32->16 bit reduction is not necessary.
93 1.27 rmind */
94 1.27 rmind sum = ~cksum & 0xffff;
95 1.27 rmind sum += (~odatum & 0xffff) + (ndatum & 0xffff);
96 1.1 rmind
97 1.27 rmind sum += (~odatum >> 16) + (ndatum >> 16);
98 1.27 rmind sum = (sum >> 16) + (sum & 0xffff);
99 1.27 rmind sum += (sum >> 16);
100 1.27 rmind return ~sum & 0xffff;
101 1.1 rmind }
102 1.1 rmind
103 1.1 rmind /*
104 1.4 rmind * npf_addr_cksum: calculate checksum of the address, either IPv4 or IPv6.
105 1.4 rmind */
106 1.4 rmind uint16_t
107 1.19 rmind npf_addr_cksum(uint16_t cksum, int sz, const npf_addr_t *oaddr,
108 1.19 rmind const npf_addr_t *naddr)
109 1.4 rmind {
110 1.19 rmind const uint32_t *oip32 = (const uint32_t *)oaddr;
111 1.19 rmind const uint32_t *nip32 = (const uint32_t *)naddr;
112 1.4 rmind
113 1.4 rmind KASSERT(sz % sizeof(uint32_t) == 0);
114 1.4 rmind do {
115 1.4 rmind cksum = npf_fixup32_cksum(cksum, *oip32++, *nip32++);
116 1.4 rmind sz -= sizeof(uint32_t);
117 1.4 rmind } while (sz);
118 1.4 rmind
119 1.4 rmind return cksum;
120 1.4 rmind }
121 1.4 rmind
122 1.4 rmind /*
123 1.26 rmind * npf_addr_sum: provide IP addresses as a XORed 32-bit integer.
124 1.4 rmind * Note: used for hash function.
125 1.1 rmind */
126 1.4 rmind uint32_t
127 1.26 rmind npf_addr_mix(const int sz, const npf_addr_t *a1, const npf_addr_t *a2)
128 1.1 rmind {
129 1.4 rmind uint32_t mix = 0;
130 1.1 rmind
131 1.5 rmind KASSERT(sz > 0 && a1 != NULL && a2 != NULL);
132 1.5 rmind
133 1.26 rmind for (int i = 0; i < (sz >> 2); i++) {
134 1.26 rmind mix ^= a1->s6_addr32[i];
135 1.26 rmind mix ^= a2->s6_addr32[i];
136 1.4 rmind }
137 1.4 rmind return mix;
138 1.4 rmind }
139 1.1 rmind
140 1.13 rmind /*
141 1.13 rmind * npf_addr_mask: apply the mask to a given address and store the result.
142 1.13 rmind */
143 1.13 rmind void
144 1.13 rmind npf_addr_mask(const npf_addr_t *addr, const npf_netmask_t mask,
145 1.13 rmind const int alen, npf_addr_t *out)
146 1.12 rmind {
147 1.13 rmind const int nwords = alen >> 2;
148 1.12 rmind uint_fast8_t length = mask;
149 1.12 rmind
150 1.12 rmind /* Note: maximum length is 32 for IPv4 and 128 for IPv6. */
151 1.12 rmind KASSERT(length <= NPF_MAX_NETMASK);
152 1.12 rmind
153 1.13 rmind for (int i = 0; i < nwords; i++) {
154 1.13 rmind uint32_t wordmask;
155 1.13 rmind
156 1.12 rmind if (length >= 32) {
157 1.13 rmind wordmask = htonl(0xffffffff);
158 1.12 rmind length -= 32;
159 1.13 rmind } else if (length) {
160 1.13 rmind wordmask = htonl(0xffffffff << (32 - length));
161 1.13 rmind length = 0;
162 1.12 rmind } else {
163 1.13 rmind wordmask = 0;
164 1.12 rmind }
165 1.13 rmind out->s6_addr32[i] = addr->s6_addr32[i] & wordmask;
166 1.12 rmind }
167 1.12 rmind }
168 1.12 rmind
169 1.12 rmind /*
170 1.12 rmind * npf_addr_cmp: compare two addresses, either IPv4 or IPv6.
171 1.12 rmind *
172 1.13 rmind * => Return 0 if equal and negative/positive if less/greater accordingly.
173 1.12 rmind * => Ignore the mask, if NPF_NO_NETMASK is specified.
174 1.12 rmind */
175 1.12 rmind int
176 1.12 rmind npf_addr_cmp(const npf_addr_t *addr1, const npf_netmask_t mask1,
177 1.13 rmind const npf_addr_t *addr2, const npf_netmask_t mask2, const int alen)
178 1.12 rmind {
179 1.13 rmind npf_addr_t realaddr1, realaddr2;
180 1.12 rmind
181 1.12 rmind if (mask1 != NPF_NO_NETMASK) {
182 1.13 rmind npf_addr_mask(addr1, mask1, alen, &realaddr1);
183 1.13 rmind addr1 = &realaddr1;
184 1.12 rmind }
185 1.12 rmind if (mask2 != NPF_NO_NETMASK) {
186 1.13 rmind npf_addr_mask(addr2, mask2, alen, &realaddr2);
187 1.13 rmind addr2 = &realaddr2;
188 1.12 rmind }
189 1.13 rmind return memcmp(addr1, addr2, alen);
190 1.12 rmind }
191 1.12 rmind
192 1.4 rmind /*
193 1.4 rmind * npf_tcpsaw: helper to fetch SEQ, ACK, WIN and return TCP data length.
194 1.12 rmind *
195 1.12 rmind * => Returns all values in host byte-order.
196 1.4 rmind */
197 1.4 rmind int
198 1.12 rmind npf_tcpsaw(const npf_cache_t *npc, tcp_seq *seq, tcp_seq *ack, uint32_t *win)
199 1.4 rmind {
200 1.19 rmind const struct tcphdr *th = npc->npc_l4.tcp;
201 1.8 rmind u_int thlen;
202 1.1 rmind
203 1.7 zoltan KASSERT(npf_iscached(npc, NPC_TCP));
204 1.1 rmind
205 1.4 rmind *seq = ntohl(th->th_seq);
206 1.4 rmind *ack = ntohl(th->th_ack);
207 1.4 rmind *win = (uint32_t)ntohs(th->th_win);
208 1.8 rmind thlen = th->th_off << 2;
209 1.1 rmind
210 1.7 zoltan if (npf_iscached(npc, NPC_IP4)) {
211 1.19 rmind const struct ip *ip = npc->npc_ip.v4;
212 1.21 rmind return ntohs(ip->ip_len) - npc->npc_hlen - thlen;
213 1.12 rmind } else if (npf_iscached(npc, NPC_IP6)) {
214 1.19 rmind const struct ip6_hdr *ip6 = npc->npc_ip.v6;
215 1.8 rmind return ntohs(ip6->ip6_plen) - thlen;
216 1.7 zoltan }
217 1.7 zoltan return 0;
218 1.1 rmind }
219 1.1 rmind
220 1.1 rmind /*
221 1.4 rmind * npf_fetch_tcpopts: parse and return TCP options.
222 1.1 rmind */
223 1.1 rmind bool
224 1.19 rmind npf_fetch_tcpopts(npf_cache_t *npc, nbuf_t *nbuf, uint16_t *mss, int *wscale)
225 1.1 rmind {
226 1.19 rmind const struct tcphdr *th = npc->npc_l4.tcp;
227 1.4 rmind int topts_len, step;
228 1.19 rmind void *nptr;
229 1.4 rmind uint8_t val;
230 1.19 rmind bool ok;
231 1.4 rmind
232 1.7 zoltan KASSERT(npf_iscached(npc, NPC_IP46));
233 1.7 zoltan KASSERT(npf_iscached(npc, NPC_TCP));
234 1.10 rmind
235 1.4 rmind /* Determine if there are any TCP options, get their length. */
236 1.4 rmind topts_len = (th->th_off << 2) - sizeof(struct tcphdr);
237 1.4 rmind if (topts_len <= 0) {
238 1.4 rmind /* No options. */
239 1.1 rmind return false;
240 1.4 rmind }
241 1.4 rmind KASSERT(topts_len <= MAX_TCPOPTLEN);
242 1.1 rmind
243 1.4 rmind /* First step: IP and TCP header up to options. */
244 1.21 rmind step = npc->npc_hlen + sizeof(struct tcphdr);
245 1.19 rmind nbuf_reset(nbuf);
246 1.4 rmind next:
247 1.19 rmind if ((nptr = nbuf_advance(nbuf, step, 1)) == NULL) {
248 1.19 rmind ok = false;
249 1.19 rmind goto done;
250 1.4 rmind }
251 1.19 rmind val = *(uint8_t *)nptr;
252 1.12 rmind
253 1.4 rmind switch (val) {
254 1.4 rmind case TCPOPT_EOL:
255 1.4 rmind /* Done. */
256 1.19 rmind ok = true;
257 1.19 rmind goto done;
258 1.4 rmind case TCPOPT_NOP:
259 1.4 rmind topts_len--;
260 1.4 rmind step = 1;
261 1.4 rmind break;
262 1.4 rmind case TCPOPT_MAXSEG:
263 1.19 rmind if ((nptr = nbuf_advance(nbuf, 2, 2)) == NULL) {
264 1.19 rmind ok = false;
265 1.19 rmind goto done;
266 1.4 rmind }
267 1.4 rmind if (mss) {
268 1.19 rmind if (*mss) {
269 1.19 rmind memcpy(nptr, mss, sizeof(uint16_t));
270 1.19 rmind } else {
271 1.19 rmind memcpy(mss, nptr, sizeof(uint16_t));
272 1.19 rmind }
273 1.4 rmind }
274 1.4 rmind topts_len -= TCPOLEN_MAXSEG;
275 1.19 rmind step = 2;
276 1.4 rmind break;
277 1.4 rmind case TCPOPT_WINDOW:
278 1.10 rmind /* TCP Window Scaling (RFC 1323). */
279 1.19 rmind if ((nptr = nbuf_advance(nbuf, 2, 1)) == NULL) {
280 1.19 rmind ok = false;
281 1.19 rmind goto done;
282 1.4 rmind }
283 1.19 rmind val = *(uint8_t *)nptr;
284 1.4 rmind *wscale = (val > TCP_MAX_WINSHIFT) ? TCP_MAX_WINSHIFT : val;
285 1.4 rmind topts_len -= TCPOLEN_WINDOW;
286 1.19 rmind step = 1;
287 1.4 rmind break;
288 1.4 rmind default:
289 1.19 rmind if ((nptr = nbuf_advance(nbuf, 1, 1)) == NULL) {
290 1.19 rmind ok = false;
291 1.19 rmind goto done;
292 1.4 rmind }
293 1.19 rmind val = *(uint8_t *)nptr;
294 1.16 rmind if (val < 2 || val > topts_len) {
295 1.19 rmind ok = false;
296 1.19 rmind goto done;
297 1.4 rmind }
298 1.4 rmind topts_len -= val;
299 1.4 rmind step = val - 1;
300 1.4 rmind }
301 1.12 rmind
302 1.6 rmind /* Any options left? */
303 1.4 rmind if (__predict_true(topts_len > 0)) {
304 1.4 rmind goto next;
305 1.4 rmind }
306 1.19 rmind ok = true;
307 1.19 rmind done:
308 1.19 rmind if (nbuf_flag_p(nbuf, NBUF_DATAREF_RESET)) {
309 1.19 rmind npf_recache(npc, nbuf);
310 1.19 rmind }
311 1.19 rmind return ok;
312 1.1 rmind }
313 1.1 rmind
314 1.19 rmind static int
315 1.19 rmind npf_cache_ip(npf_cache_t *npc, nbuf_t *nbuf)
316 1.1 rmind {
317 1.19 rmind const void *nptr = nbuf_dataptr(nbuf);
318 1.19 rmind const uint8_t ver = *(const uint8_t *)nptr;
319 1.19 rmind int flags = 0;
320 1.12 rmind
321 1.4 rmind switch (ver >> 4) {
322 1.12 rmind case IPVERSION: {
323 1.19 rmind struct ip *ip;
324 1.12 rmind
325 1.19 rmind ip = nbuf_ensure_contig(nbuf, sizeof(struct ip));
326 1.19 rmind if (ip == NULL) {
327 1.19 rmind return 0;
328 1.4 rmind }
329 1.12 rmind
330 1.4 rmind /* Check header length and fragment offset. */
331 1.10 rmind if ((u_int)(ip->ip_hl << 2) < sizeof(struct ip)) {
332 1.19 rmind return 0;
333 1.4 rmind }
334 1.4 rmind if (ip->ip_off & ~htons(IP_DF | IP_RF)) {
335 1.4 rmind /* Note fragmentation. */
336 1.19 rmind flags |= NPC_IPFRAG;
337 1.4 rmind }
338 1.12 rmind
339 1.4 rmind /* Cache: layer 3 - IPv4. */
340 1.14 rmind npc->npc_alen = sizeof(struct in_addr);
341 1.4 rmind npc->npc_srcip = (npf_addr_t *)&ip->ip_src;
342 1.4 rmind npc->npc_dstip = (npf_addr_t *)&ip->ip_dst;
343 1.7 zoltan npc->npc_hlen = ip->ip_hl << 2;
344 1.19 rmind npc->npc_proto = ip->ip_p;
345 1.19 rmind
346 1.19 rmind npc->npc_ip.v4 = ip;
347 1.19 rmind flags |= NPC_IP4;
348 1.4 rmind break;
349 1.12 rmind }
350 1.4 rmind
351 1.12 rmind case (IPV6_VERSION >> 4): {
352 1.19 rmind struct ip6_hdr *ip6;
353 1.19 rmind struct ip6_ext *ip6e;
354 1.19 rmind size_t off, hlen;
355 1.19 rmind
356 1.19 rmind ip6 = nbuf_ensure_contig(nbuf, sizeof(struct ip6_hdr));
357 1.19 rmind if (ip6 == NULL) {
358 1.19 rmind return 0;
359 1.7 zoltan }
360 1.19 rmind
361 1.19 rmind /* Set initial next-protocol value. */
362 1.19 rmind hlen = sizeof(struct ip6_hdr);
363 1.19 rmind npc->npc_proto = ip6->ip6_nxt;
364 1.13 rmind npc->npc_hlen = hlen;
365 1.7 zoltan
366 1.12 rmind /*
367 1.19 rmind * Advance by the length of the current header.
368 1.12 rmind */
369 1.19 rmind off = nbuf_offset(nbuf);
370 1.19 rmind while (nbuf_advance(nbuf, hlen, 0) != NULL) {
371 1.19 rmind ip6e = nbuf_ensure_contig(nbuf, sizeof(*ip6e));
372 1.19 rmind if (ip6e == NULL) {
373 1.19 rmind return 0;
374 1.19 rmind }
375 1.19 rmind
376 1.13 rmind /*
377 1.13 rmind * Determine whether we are going to continue.
378 1.13 rmind */
379 1.19 rmind switch (npc->npc_proto) {
380 1.13 rmind case IPPROTO_HOPOPTS:
381 1.7 zoltan case IPPROTO_DSTOPTS:
382 1.7 zoltan case IPPROTO_ROUTING:
383 1.19 rmind hlen = (ip6e->ip6e_len + 1) << 3;
384 1.7 zoltan break;
385 1.7 zoltan case IPPROTO_FRAGMENT:
386 1.13 rmind hlen = sizeof(struct ip6_frag);
387 1.19 rmind flags |= NPC_IPFRAG;
388 1.7 zoltan break;
389 1.7 zoltan case IPPROTO_AH:
390 1.19 rmind hlen = (ip6e->ip6e_len + 2) << 2;
391 1.7 zoltan break;
392 1.7 zoltan default:
393 1.13 rmind hlen = 0;
394 1.13 rmind break;
395 1.13 rmind }
396 1.13 rmind
397 1.13 rmind if (!hlen) {
398 1.7 zoltan break;
399 1.7 zoltan }
400 1.19 rmind npc->npc_proto = ip6e->ip6e_nxt;
401 1.13 rmind npc->npc_hlen += hlen;
402 1.13 rmind }
403 1.7 zoltan
404 1.23 rmind /*
405 1.23 rmind * Re-fetch the header pointers (nbufs might have been
406 1.23 rmind * reallocated). Restore the original offset (if any).
407 1.23 rmind */
408 1.19 rmind nbuf_reset(nbuf);
409 1.23 rmind ip6 = nbuf_dataptr(nbuf);
410 1.19 rmind if (off) {
411 1.19 rmind nbuf_advance(nbuf, off, 0);
412 1.19 rmind }
413 1.19 rmind
414 1.12 rmind /* Cache: layer 3 - IPv6. */
415 1.14 rmind npc->npc_alen = sizeof(struct in6_addr);
416 1.7 zoltan npc->npc_srcip = (npf_addr_t *)&ip6->ip6_src;
417 1.7 zoltan npc->npc_dstip = (npf_addr_t *)&ip6->ip6_dst;
418 1.19 rmind
419 1.19 rmind npc->npc_ip.v6 = ip6;
420 1.19 rmind flags |= NPC_IP6;
421 1.7 zoltan break;
422 1.12 rmind }
423 1.4 rmind default:
424 1.19 rmind break;
425 1.4 rmind }
426 1.19 rmind return flags;
427 1.1 rmind }
428 1.1 rmind
429 1.1 rmind /*
430 1.4 rmind * npf_cache_all: general routine to cache all relevant IP (v4 or v6)
431 1.12 rmind * and TCP, UDP or ICMP headers.
432 1.19 rmind *
433 1.19 rmind * => nbuf offset shall be set accordingly.
434 1.1 rmind */
435 1.10 rmind int
436 1.2 rmind npf_cache_all(npf_cache_t *npc, nbuf_t *nbuf)
437 1.1 rmind {
438 1.19 rmind int flags, l4flags;
439 1.19 rmind u_int hlen;
440 1.19 rmind
441 1.19 rmind /*
442 1.19 rmind * This routine is a main point where the references are cached,
443 1.19 rmind * therefore clear the flag as we reset.
444 1.19 rmind */
445 1.19 rmind again:
446 1.19 rmind nbuf_unset_flag(nbuf, NBUF_DATAREF_RESET);
447 1.1 rmind
448 1.19 rmind /*
449 1.19 rmind * First, cache the L3 header (IPv4 or IPv6). If IP packet is
450 1.19 rmind * fragmented, then we cannot look into L4.
451 1.19 rmind */
452 1.19 rmind flags = npf_cache_ip(npc, nbuf);
453 1.19 rmind if ((flags & NPC_IP46) == 0 || (flags & NPC_IPFRAG) != 0) {
454 1.23 rmind nbuf_unset_flag(nbuf, NBUF_DATAREF_RESET);
455 1.19 rmind npc->npc_info |= flags;
456 1.19 rmind return flags;
457 1.1 rmind }
458 1.19 rmind hlen = npc->npc_hlen;
459 1.19 rmind
460 1.19 rmind switch (npc->npc_proto) {
461 1.1 rmind case IPPROTO_TCP:
462 1.19 rmind /* Cache: layer 4 - TCP. */
463 1.19 rmind npc->npc_l4.tcp = nbuf_advance(nbuf, hlen,
464 1.19 rmind sizeof(struct tcphdr));
465 1.19 rmind l4flags = NPC_LAYER4 | NPC_TCP;
466 1.10 rmind break;
467 1.1 rmind case IPPROTO_UDP:
468 1.19 rmind /* Cache: layer 4 - UDP. */
469 1.19 rmind npc->npc_l4.udp = nbuf_advance(nbuf, hlen,
470 1.19 rmind sizeof(struct udphdr));
471 1.19 rmind l4flags = NPC_LAYER4 | NPC_UDP;
472 1.10 rmind break;
473 1.1 rmind case IPPROTO_ICMP:
474 1.19 rmind /* Cache: layer 4 - ICMPv4. */
475 1.19 rmind npc->npc_l4.icmp = nbuf_advance(nbuf, hlen,
476 1.19 rmind offsetof(struct icmp, icmp_void));
477 1.19 rmind l4flags = NPC_LAYER4 | NPC_ICMP;
478 1.19 rmind break;
479 1.15 spz case IPPROTO_ICMPV6:
480 1.19 rmind /* Cache: layer 4 - ICMPv6. */
481 1.19 rmind npc->npc_l4.icmp6 = nbuf_advance(nbuf, hlen,
482 1.19 rmind offsetof(struct icmp6_hdr, icmp6_data32));
483 1.19 rmind l4flags = NPC_LAYER4 | NPC_ICMP;
484 1.19 rmind break;
485 1.19 rmind default:
486 1.19 rmind l4flags = 0;
487 1.10 rmind break;
488 1.1 rmind }
489 1.19 rmind
490 1.19 rmind if (nbuf_flag_p(nbuf, NBUF_DATAREF_RESET)) {
491 1.19 rmind goto again;
492 1.19 rmind }
493 1.19 rmind
494 1.19 rmind /* Add the L4 flags if nbuf_advance() succeeded. */
495 1.19 rmind if (l4flags && npc->npc_l4.hdr) {
496 1.19 rmind flags |= l4flags;
497 1.19 rmind }
498 1.19 rmind npc->npc_info |= flags;
499 1.19 rmind return flags;
500 1.19 rmind }
501 1.19 rmind
502 1.19 rmind void
503 1.19 rmind npf_recache(npf_cache_t *npc, nbuf_t *nbuf)
504 1.19 rmind {
505 1.24 martin const int mflags __diagused = npc->npc_info & (NPC_IP46 | NPC_LAYER4);
506 1.25 mrg int flags __diagused;
507 1.19 rmind
508 1.19 rmind nbuf_reset(nbuf);
509 1.19 rmind npc->npc_info = 0;
510 1.19 rmind flags = npf_cache_all(npc, nbuf);
511 1.19 rmind KASSERT((flags & mflags) == mflags);
512 1.19 rmind KASSERT(nbuf_flag_p(nbuf, NBUF_DATAREF_RESET) == 0);
513 1.1 rmind }
514 1.1 rmind
515 1.1 rmind /*
516 1.19 rmind * npf_rwrip: rewrite required IP address.
517 1.4 rmind */
518 1.4 rmind bool
519 1.19 rmind npf_rwrip(const npf_cache_t *npc, int di, const npf_addr_t *addr)
520 1.4 rmind {
521 1.4 rmind npf_addr_t *oaddr;
522 1.4 rmind
523 1.4 rmind KASSERT(npf_iscached(npc, NPC_IP46));
524 1.4 rmind
525 1.19 rmind /*
526 1.19 rmind * Rewrite source address if outgoing and destination if incoming.
527 1.19 rmind */
528 1.19 rmind oaddr = (di == PFIL_OUT) ? npc->npc_srcip : npc->npc_dstip;
529 1.14 rmind memcpy(oaddr, addr, npc->npc_alen);
530 1.4 rmind return true;
531 1.4 rmind }
532 1.4 rmind
533 1.4 rmind /*
534 1.19 rmind * npf_rwrport: rewrite required TCP/UDP port.
535 1.1 rmind */
536 1.1 rmind bool
537 1.19 rmind npf_rwrport(const npf_cache_t *npc, int di, const in_port_t port)
538 1.1 rmind {
539 1.21 rmind const int proto = npc->npc_proto;
540 1.4 rmind in_port_t *oport;
541 1.1 rmind
542 1.4 rmind KASSERT(npf_iscached(npc, NPC_TCP) || npf_iscached(npc, NPC_UDP));
543 1.1 rmind KASSERT(proto == IPPROTO_TCP || proto == IPPROTO_UDP);
544 1.1 rmind
545 1.19 rmind /* Get the offset and store the port in it. */
546 1.4 rmind if (proto == IPPROTO_TCP) {
547 1.19 rmind struct tcphdr *th = npc->npc_l4.tcp;
548 1.19 rmind oport = (di == PFIL_OUT) ? &th->th_sport : &th->th_dport;
549 1.1 rmind } else {
550 1.19 rmind struct udphdr *uh = npc->npc_l4.udp;
551 1.19 rmind oport = (di == PFIL_OUT) ? &uh->uh_sport : &uh->uh_dport;
552 1.1 rmind }
553 1.19 rmind memcpy(oport, &port, sizeof(in_port_t));
554 1.1 rmind return true;
555 1.1 rmind }
556 1.1 rmind
557 1.1 rmind /*
558 1.19 rmind * npf_rwrcksum: rewrite IPv4 and/or TCP/UDP checksum.
559 1.1 rmind */
560 1.1 rmind bool
561 1.19 rmind npf_rwrcksum(const npf_cache_t *npc, const int di,
562 1.19 rmind const npf_addr_t *addr, const in_port_t port)
563 1.1 rmind {
564 1.21 rmind const int proto = npc->npc_proto;
565 1.19 rmind const int alen = npc->npc_alen;
566 1.4 rmind npf_addr_t *oaddr;
567 1.18 rmind uint16_t *ocksum;
568 1.18 rmind in_port_t oport;
569 1.18 rmind
570 1.19 rmind KASSERT(npf_iscached(npc, NPC_LAYER4));
571 1.18 rmind oaddr = (di == PFIL_OUT) ? npc->npc_srcip : npc->npc_dstip;
572 1.18 rmind
573 1.4 rmind if (npf_iscached(npc, NPC_IP4)) {
574 1.19 rmind struct ip *ip = npc->npc_ip.v4;
575 1.19 rmind uint16_t ipsum = ip->ip_sum;
576 1.4 rmind
577 1.19 rmind /* Recalculate IPv4 checksum and rewrite. */
578 1.19 rmind ip->ip_sum = npf_addr_cksum(ipsum, alen, oaddr, addr);
579 1.4 rmind } else {
580 1.4 rmind /* No checksum for IPv6. */
581 1.4 rmind KASSERT(npf_iscached(npc, NPC_IP6));
582 1.4 rmind }
583 1.4 rmind
584 1.18 rmind /* Nothing else to do for ICMP. */
585 1.18 rmind if (proto == IPPROTO_ICMP) {
586 1.4 rmind return true;
587 1.4 rmind }
588 1.7 zoltan KASSERT(npf_iscached(npc, NPC_TCP) || npf_iscached(npc, NPC_UDP));
589 1.4 rmind
590 1.18 rmind /*
591 1.18 rmind * Calculate TCP/UDP checksum:
592 1.18 rmind * - Skip if UDP and the current checksum is zero.
593 1.18 rmind * - Fixup the IP address change.
594 1.18 rmind * - Fixup the port change, if required (non-zero).
595 1.18 rmind */
596 1.4 rmind if (proto == IPPROTO_TCP) {
597 1.19 rmind struct tcphdr *th = npc->npc_l4.tcp;
598 1.4 rmind
599 1.18 rmind ocksum = &th->th_sum;
600 1.18 rmind oport = (di == PFIL_OUT) ? th->th_sport : th->th_dport;
601 1.4 rmind } else {
602 1.19 rmind struct udphdr *uh = npc->npc_l4.udp;
603 1.4 rmind
604 1.4 rmind KASSERT(proto == IPPROTO_UDP);
605 1.18 rmind ocksum = &uh->uh_sum;
606 1.18 rmind if (*ocksum == 0) {
607 1.4 rmind /* No need to update. */
608 1.4 rmind return true;
609 1.4 rmind }
610 1.18 rmind oport = (di == PFIL_OUT) ? uh->uh_sport : uh->uh_dport;
611 1.18 rmind }
612 1.18 rmind
613 1.19 rmind uint16_t cksum = npf_addr_cksum(*ocksum, alen, oaddr, addr);
614 1.18 rmind if (port) {
615 1.18 rmind cksum = npf_fixup16_cksum(cksum, oport, port);
616 1.4 rmind }
617 1.1 rmind
618 1.19 rmind /* Rewrite TCP/UDP checksum. */
619 1.19 rmind memcpy(ocksum, &cksum, sizeof(uint16_t));
620 1.4 rmind return true;
621 1.4 rmind }
622 1.4 rmind
623 1.13 rmind #if defined(DDB) || defined(_NPF_TESTING)
624 1.13 rmind
625 1.13 rmind void
626 1.13 rmind npf_addr_dump(const npf_addr_t *addr)
627 1.13 rmind {
628 1.13 rmind printf("IP[%x:%x:%x:%x]\n",
629 1.13 rmind addr->s6_addr32[0], addr->s6_addr32[1],
630 1.13 rmind addr->s6_addr32[2], addr->s6_addr32[3]);
631 1.13 rmind }
632 1.13 rmind
633 1.13 rmind #endif
634