npf_inet.c revision 1.11 1 /* $NetBSD: npf_inet.c,v 1.11 2012/02/20 00:18:19 rmind Exp $ */
2
3 /*-
4 * Copyright (c) 2009-2011 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This material is based upon work partially supported by The
8 * NetBSD Foundation under a contract with Mindaugas Rasiukevicius.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
32 /*
33 * Various procotol related helper routines.
34 */
35
36 #include <sys/cdefs.h>
37 __KERNEL_RCSID(0, "$NetBSD: npf_inet.c,v 1.11 2012/02/20 00:18:19 rmind Exp $");
38
39 #include <sys/param.h>
40 #include <sys/types.h>
41
42 #include <net/pfil.h>
43 #include <net/if.h>
44 #include <net/ethertypes.h>
45 #include <net/if_ether.h>
46
47 #include <netinet/in_systm.h>
48 #include <netinet/in.h>
49 #include <netinet/in_var.h>
50 #include <netinet/ip.h>
51 #include <netinet/ip6.h>
52 #include <netinet/tcp.h>
53 #include <netinet/udp.h>
54 #include <netinet/ip_icmp.h>
55
56 #include "npf_impl.h"
57
58 /*
59 * npf_fixup{16,32}_cksum: update IPv4 checksum.
60 */
61
62 uint16_t
63 npf_fixup16_cksum(uint16_t cksum, uint16_t odatum, uint16_t ndatum)
64 {
65 uint32_t sum;
66
67 /*
68 * RFC 1624:
69 * HC' = ~(~HC + ~m + m')
70 */
71 sum = ~ntohs(cksum) & 0xffff;
72 sum += (~ntohs(odatum) & 0xffff) + ntohs(ndatum);
73 sum = (sum >> 16) + (sum & 0xffff);
74 sum += (sum >> 16);
75
76 return htons(~sum & 0xffff);
77 }
78
79 uint16_t
80 npf_fixup32_cksum(uint16_t cksum, uint32_t odatum, uint32_t ndatum)
81 {
82
83 cksum = npf_fixup16_cksum(cksum, odatum & 0xffff, ndatum & 0xffff);
84 cksum = npf_fixup16_cksum(cksum, odatum >> 16, ndatum >> 16);
85 return cksum;
86 }
87
88 /*
89 * npf_addr_cksum: calculate checksum of the address, either IPv4 or IPv6.
90 */
91 uint16_t
92 npf_addr_cksum(uint16_t cksum, int sz, npf_addr_t *oaddr, npf_addr_t *naddr)
93 {
94 uint32_t *oip32 = (uint32_t *)oaddr, *nip32 = (uint32_t *)naddr;
95
96 KASSERT(sz % sizeof(uint32_t) == 0);
97 do {
98 cksum = npf_fixup32_cksum(cksum, *oip32++, *nip32++);
99 sz -= sizeof(uint32_t);
100 } while (sz);
101
102 return cksum;
103 }
104
105 /*
106 * npf_addr_sum: provide IP address as a summed (if needed) 32-bit integer.
107 * Note: used for hash function.
108 */
109 uint32_t
110 npf_addr_sum(const int sz, const npf_addr_t *a1, const npf_addr_t *a2)
111 {
112 uint32_t mix = 0;
113 int i;
114
115 KASSERT(sz > 0 && a1 != NULL && a2 != NULL);
116
117 for (i = 0; i < (sz >> 2); i++) {
118 mix += a1->s6_addr32[i];
119 mix += a2->s6_addr32[i];
120 }
121 return mix;
122 }
123
124 /*
125 * npf_tcpsaw: helper to fetch SEQ, ACK, WIN and return TCP data length.
126 * Returns all values in host byte-order.
127 */
128 int
129 npf_tcpsaw(npf_cache_t *npc, tcp_seq *seq, tcp_seq *ack, uint32_t *win)
130 {
131 struct tcphdr *th = &npc->npc_l4.tcp;
132 u_int thlen;
133
134 KASSERT(npf_iscached(npc, NPC_TCP));
135
136 *seq = ntohl(th->th_seq);
137 *ack = ntohl(th->th_ack);
138 *win = (uint32_t)ntohs(th->th_win);
139 thlen = th->th_off << 2;
140
141 if (npf_iscached(npc, NPC_IP4)) {
142 struct ip *ip = &npc->npc_ip.v4;
143 return ntohs(ip->ip_len) - npf_cache_hlen(npc) - thlen;
144 } else {
145 KASSERT(npf_iscached(npc, NPC_IP6));
146 struct ip6_hdr *ip6 = &npc->npc_ip.v6;
147 return ntohs(ip6->ip6_plen) - thlen;
148 }
149 return 0;
150 }
151
152 /*
153 * npf_fetch_tcpopts: parse and return TCP options.
154 */
155 bool
156 npf_fetch_tcpopts(const npf_cache_t *npc, nbuf_t *nbuf,
157 uint16_t *mss, int *wscale)
158 {
159 void *n_ptr = nbuf_dataptr(nbuf);
160 const struct tcphdr *th = &npc->npc_l4.tcp;
161 int topts_len, step;
162 uint16_t val16;
163 uint8_t val;
164
165 KASSERT(npf_iscached(npc, NPC_IP46));
166 KASSERT(npf_iscached(npc, NPC_TCP));
167
168 /* Determine if there are any TCP options, get their length. */
169 topts_len = (th->th_off << 2) - sizeof(struct tcphdr);
170 if (topts_len <= 0) {
171 /* No options. */
172 return false;
173 }
174 KASSERT(topts_len <= MAX_TCPOPTLEN);
175
176 /* First step: IP and TCP header up to options. */
177 step = npf_cache_hlen(npc) + sizeof(struct tcphdr);
178 next:
179 if (nbuf_advfetch(&nbuf, &n_ptr, step, sizeof(val), &val)) {
180 return false;
181 }
182 switch (val) {
183 case TCPOPT_EOL:
184 /* Done. */
185 return true;
186 case TCPOPT_NOP:
187 topts_len--;
188 step = 1;
189 break;
190 case TCPOPT_MAXSEG:
191 /*
192 * XXX: clean this mess.
193 */
194 if (mss && *mss) {
195 val16 = *mss;
196 if (nbuf_advstore(&nbuf, &n_ptr, 2,
197 sizeof(val16), &val16))
198 return false;
199 } else if (nbuf_advfetch(&nbuf, &n_ptr, 2,
200 sizeof(val16), &val16)) {
201 return false;
202 }
203 if (mss) {
204 *mss = val16;
205 }
206 topts_len -= TCPOLEN_MAXSEG;
207 step = sizeof(val16);
208 break;
209 case TCPOPT_WINDOW:
210 /* TCP Window Scaling (RFC 1323). */
211 if (nbuf_advfetch(&nbuf, &n_ptr, 2, sizeof(val), &val)) {
212 return false;
213 }
214 *wscale = (val > TCP_MAX_WINSHIFT) ? TCP_MAX_WINSHIFT : val;
215 topts_len -= TCPOLEN_WINDOW;
216 step = sizeof(val);
217 break;
218 default:
219 if (nbuf_advfetch(&nbuf, &n_ptr, 1, sizeof(val), &val)) {
220 return false;
221 }
222 if (val < 2 || val >= topts_len) {
223 return false;
224 }
225 topts_len -= val;
226 step = val - 1;
227 }
228 /* Any options left? */
229 if (__predict_true(topts_len > 0)) {
230 goto next;
231 }
232 return true;
233 }
234
235 /*
236 * npf_fetch_ip: fetch, check and cache IP header.
237 */
238 bool
239 npf_fetch_ip(npf_cache_t *npc, nbuf_t *nbuf, void *n_ptr)
240 {
241 struct ip *ip;
242 struct ip6_hdr *ip6;
243 uint8_t ver;
244
245 if (nbuf_fetch_datum(nbuf, n_ptr, sizeof(uint8_t), &ver)) {
246 return false;
247 }
248 switch (ver >> 4) {
249 case IPVERSION:
250 /* IPv4 */
251 ip = &npc->npc_ip.v4;
252 /* Fetch the header. */
253 if (nbuf_fetch_datum(nbuf, n_ptr, sizeof(struct ip), ip)) {
254 return false;
255 }
256 /* Check header length and fragment offset. */
257 if ((u_int)(ip->ip_hl << 2) < sizeof(struct ip)) {
258 return false;
259 }
260 if (ip->ip_off & ~htons(IP_DF | IP_RF)) {
261 /* Note fragmentation. */
262 npc->npc_info |= NPC_IPFRAG;
263 }
264 /* Cache: layer 3 - IPv4. */
265 npc->npc_ipsz = sizeof(struct in_addr);
266 npc->npc_srcip = (npf_addr_t *)&ip->ip_src;
267 npc->npc_dstip = (npf_addr_t *)&ip->ip_dst;
268 npc->npc_info |= NPC_IP4;
269 npc->npc_hlen = ip->ip_hl << 2;
270 npc->npc_next_proto = npc->npc_ip.v4.ip_p;
271 break;
272
273 case (IPV6_VERSION >> 4):
274 ip6 = &npc->npc_ip.v6;
275 if (nbuf_fetch_datum(nbuf, n_ptr, sizeof(struct ip6_hdr), ip6)) {
276 return false;
277 }
278
279 bool done = false;
280 uint_fast8_t next_proto;
281 size_t toskip;
282
283 /* Initial next-protocol value. */
284 next_proto = ip6->ip6_nxt;
285 toskip = sizeof(struct ip6_hdr);
286 npc->npc_hlen = 0;
287
288 do {
289 struct ip6_ext ip6e;
290
291 npc->npc_next_proto = next_proto;
292
293 /*
294 * Advance by the length of the previous known header
295 * and fetch the next extension header's length.
296 */
297 if (nbuf_advfetch(&nbuf, &n_ptr, toskip,
298 sizeof(struct ip6_ext), &ip6e)) {
299 return false;
300 }
301 switch (npc->npc_next_proto) {
302 case IPPROTO_DSTOPTS:
303 case IPPROTO_ROUTING:
304 toskip = (ip6e.ip6e_len + 1) << 3;
305 break;
306 case IPPROTO_FRAGMENT:
307 npc->npc_info |= NPC_IPFRAG;
308 toskip = sizeof(struct ip6_frag);
309 break;
310 case IPPROTO_AH:
311 toskip = (ip6e.ip6e_len + 2) << 2;
312 break;
313 default:
314 done = true;
315 break;
316 }
317 npc->npc_hlen += toskip;
318 next_proto = ip6e.ip6e_nxt;
319
320 } while (!done);
321
322 npc->npc_ipsz = sizeof(struct in6_addr);
323 npc->npc_srcip = (npf_addr_t *)&ip6->ip6_src;
324 npc->npc_dstip = (npf_addr_t *)&ip6->ip6_dst;
325 npc->npc_info |= NPC_IP6;
326 break;
327 default:
328 return false;
329 }
330 return true;
331 }
332
333 bool
334 npf_fetch_tcp(npf_cache_t *npc, nbuf_t *nbuf, void *n_ptr)
335 {
336 struct tcphdr *th;
337
338 /* Must have IP header processed for its length and protocol. */
339 if (!npf_iscached(npc, NPC_IP46) && !npf_fetch_ip(npc, nbuf, n_ptr)) {
340 return false;
341 }
342 if (npf_cache_ipproto(npc) != IPPROTO_TCP) {
343 return false;
344 }
345 th = &npc->npc_l4.tcp;
346
347 /* Fetch TCP header. */
348 if (nbuf_advfetch(&nbuf, &n_ptr, npf_cache_hlen(npc),
349 sizeof(struct tcphdr), th)) {
350 return false;
351 }
352
353 /* Cache: layer 4 - TCP. */
354 npc->npc_info |= (NPC_LAYER4 | NPC_TCP);
355 return true;
356 }
357
358 bool
359 npf_fetch_udp(npf_cache_t *npc, nbuf_t *nbuf, void *n_ptr)
360 {
361 struct ip *ip = &npc->npc_ip.v4;
362 struct udphdr *uh;
363 u_int hlen;
364
365 /* Must have IP header processed for its length and protocol. */
366 if (!npf_iscached(npc, NPC_IP46) && !npf_fetch_ip(npc, nbuf, n_ptr)) {
367 return false;
368 }
369 if (ip->ip_p != IPPROTO_UDP) {
370 return false;
371 }
372 uh = &npc->npc_l4.udp;
373 hlen = npf_cache_hlen(npc);
374
375 /* Fetch ICMP header. */
376 if (nbuf_advfetch(&nbuf, &n_ptr, hlen, sizeof(struct udphdr), uh)) {
377 return false;
378 }
379
380 /* Cache: layer 4 - UDP. */
381 npc->npc_info |= (NPC_LAYER4 | NPC_UDP);
382 return true;
383 }
384
385 /*
386 * npf_fetch_icmp: fetch ICMP code, type and possible query ID.
387 *
388 * => Stores both all fetched items into the cache.
389 */
390 bool
391 npf_fetch_icmp(npf_cache_t *npc, nbuf_t *nbuf, void *n_ptr)
392 {
393 struct ip *ip = &npc->npc_ip.v4;
394 struct icmp *ic;
395 u_int hlen, iclen;
396
397 /* Must have IP header processed for its length and protocol. */
398 if (!npf_iscached(npc, NPC_IP46) && !npf_fetch_ip(npc, nbuf, n_ptr)) {
399 return false;
400 }
401 if (ip->ip_p != IPPROTO_ICMP) {
402 return false;
403 }
404 ic = &npc->npc_l4.icmp;
405 hlen = npf_cache_hlen(npc);
406
407 /* Fetch basic ICMP header, up to the "data" point. */
408 iclen = offsetof(struct icmp, icmp_data);
409 if (nbuf_advfetch(&nbuf, &n_ptr, hlen, iclen, ic)) {
410 return false;
411 }
412
413 /* Cache: layer 4 - ICMP. */
414 npc->npc_info |= (NPC_LAYER4 | NPC_ICMP);
415 return true;
416 }
417
418 /*
419 * npf_cache_all: general routine to cache all relevant IP (v4 or v6)
420 * and TCP, UDP or ICMP data.
421 */
422 int
423 npf_cache_all(npf_cache_t *npc, nbuf_t *nbuf)
424 {
425 void *n_ptr = nbuf_dataptr(nbuf);
426
427 if (!npf_iscached(npc, NPC_IP46) && !npf_fetch_ip(npc, nbuf, n_ptr)) {
428 return npc->npc_info;
429 }
430 if (npf_iscached(npc, NPC_IPFRAG)) {
431 return npc->npc_info;
432 }
433 switch (npf_cache_ipproto(npc)) {
434 case IPPROTO_TCP:
435 (void)npf_fetch_tcp(npc, nbuf, n_ptr);
436 break;
437 case IPPROTO_UDP:
438 (void)npf_fetch_udp(npc, nbuf, n_ptr);
439 break;
440 case IPPROTO_ICMP:
441 (void)npf_fetch_icmp(npc, nbuf, n_ptr);
442 break;
443 }
444 return npc->npc_info;
445 }
446
447 /*
448 * npf_rwrip: rewrite required IP address, update the cache.
449 */
450 bool
451 npf_rwrip(npf_cache_t *npc, nbuf_t *nbuf, void *n_ptr, const int di,
452 npf_addr_t *addr)
453 {
454 npf_addr_t *oaddr;
455 u_int offby;
456
457 KASSERT(npf_iscached(npc, NPC_IP46));
458
459 if (di == PFIL_OUT) {
460 /* Rewrite source address, if outgoing. */
461 offby = offsetof(struct ip, ip_src);
462 oaddr = npc->npc_srcip;
463 } else {
464 /* Rewrite destination, if incoming. */
465 offby = offsetof(struct ip, ip_dst);
466 oaddr = npc->npc_dstip;
467 }
468
469 /* Advance to the address and rewrite it. */
470 if (nbuf_advstore(&nbuf, &n_ptr, offby, npc->npc_ipsz, addr))
471 return false;
472
473 /* Cache: IP address. */
474 memcpy(oaddr, addr, npc->npc_ipsz);
475 return true;
476 }
477
478 /*
479 * npf_rwrport: rewrite required TCP/UDP port, update the cache.
480 */
481 bool
482 npf_rwrport(npf_cache_t *npc, nbuf_t *nbuf, void *n_ptr, const int di,
483 in_port_t port)
484 {
485 const int proto = npf_cache_ipproto(npc);
486 u_int offby = npf_cache_hlen(npc);
487 in_port_t *oport;
488
489 KASSERT(npf_iscached(npc, NPC_TCP) || npf_iscached(npc, NPC_UDP));
490 KASSERT(proto == IPPROTO_TCP || proto == IPPROTO_UDP);
491
492 /* Offset to the port and pointer in the cache. */
493 if (proto == IPPROTO_TCP) {
494 struct tcphdr *th = &npc->npc_l4.tcp;
495 if (di == PFIL_OUT) {
496 CTASSERT(offsetof(struct tcphdr, th_sport) == 0);
497 oport = &th->th_sport;
498 } else {
499 offby += offsetof(struct tcphdr, th_dport);
500 oport = &th->th_dport;
501 }
502 } else {
503 struct udphdr *uh = &npc->npc_l4.udp;
504 if (di == PFIL_OUT) {
505 CTASSERT(offsetof(struct udphdr, uh_sport) == 0);
506 oport = &uh->uh_sport;
507 } else {
508 offby += offsetof(struct udphdr, uh_dport);
509 oport = &uh->uh_dport;
510 }
511 }
512
513 /* Advance and rewrite the port. */
514 if (nbuf_advstore(&nbuf, &n_ptr, offby, sizeof(in_port_t), &port))
515 return false;
516
517 /* Cache: TCP/UDP port. */
518 *oport = port;
519 return true;
520 }
521
522 /*
523 * npf_rwrcksum: rewrite IPv4 and/or TCP/UDP checksum, update the cache.
524 */
525 bool
526 npf_rwrcksum(npf_cache_t *npc, nbuf_t *nbuf, void *n_ptr, const int di,
527 npf_addr_t *addr, in_port_t port)
528 {
529 const int proto = npf_cache_ipproto(npc);
530 npf_addr_t *oaddr;
531 in_port_t *oport;
532 uint16_t *cksum;
533 u_int offby;
534
535 /* Checksum update for IPv4 header. */
536 if (npf_iscached(npc, NPC_IP4)) {
537 struct ip *ip = &npc->npc_ip.v4;
538 uint16_t ipsum;
539
540 oaddr = (di == PFIL_OUT) ? npc->npc_srcip : npc->npc_dstip;
541 ipsum = npf_addr_cksum(ip->ip_sum, npc->npc_ipsz, oaddr, addr);
542
543 /* Advance to the IPv4 checksum and rewrite it. */
544 offby = offsetof(struct ip, ip_sum);
545 if (nbuf_advstore(&nbuf, &n_ptr, offby, sizeof(ipsum), &ipsum))
546 return false;
547
548 ip->ip_sum = ipsum;
549 offby = npf_cache_hlen(npc) - offby;
550 } else {
551 /* No checksum for IPv6. */
552 KASSERT(npf_iscached(npc, NPC_IP6));
553 oaddr = NULL;
554 offby = 0;
555 return false; /* XXX: Not yet supported. */
556 }
557
558 /* Determine whether TCP/UDP checksum update is needed. */
559 if (proto == IPPROTO_ICMP || port == 0) {
560 return true;
561 }
562 KASSERT(npf_iscached(npc, NPC_TCP) || npf_iscached(npc, NPC_UDP));
563
564 /* Calculate TCP/UDP checksum. */
565 if (proto == IPPROTO_TCP) {
566 struct tcphdr *th = &npc->npc_l4.tcp;
567
568 cksum = &th->th_sum;
569 offby += offsetof(struct tcphdr, th_sum);
570 oport = (di == PFIL_OUT) ? &th->th_sport : &th->th_dport;
571 } else {
572 struct udphdr *uh = &npc->npc_l4.udp;
573
574 KASSERT(proto == IPPROTO_UDP);
575 cksum = &uh->uh_sum;
576 if (*cksum == 0) {
577 /* No need to update. */
578 return true;
579 }
580 offby += offsetof(struct udphdr, uh_sum);
581 oport = (di == PFIL_OUT) ? &uh->uh_sport : &uh->uh_dport;
582 }
583 *cksum = npf_addr_cksum(*cksum, npc->npc_ipsz, oaddr, addr);
584 *cksum = npf_fixup16_cksum(*cksum, *oport, port);
585
586 /* Advance to TCP/UDP checksum and rewrite it. */
587 if (nbuf_advstore(&nbuf, &n_ptr, offby, sizeof(uint16_t), cksum)) {
588 return false;
589 }
590 return true;
591 }
592
593 static inline bool
594 npf_normalize_ip4(npf_cache_t *npc, nbuf_t *nbuf,
595 bool rnd, bool no_df, int minttl)
596 {
597 void *n_ptr = nbuf_dataptr(nbuf);
598 struct ip *ip = &npc->npc_ip.v4;
599 uint16_t cksum = ip->ip_sum;
600 uint16_t ip_off = ip->ip_off;
601 uint8_t ttl = ip->ip_ttl;
602 u_int offby = 0;
603
604 KASSERT(rnd || minttl || no_df);
605
606 /* Randomize IPv4 ID. */
607 if (rnd) {
608 uint16_t oid = ip->ip_id, nid;
609
610 nid = htons(ip_randomid(ip_ids, 0));
611 offby = offsetof(struct ip, ip_id);
612 if (nbuf_advstore(&nbuf, &n_ptr, offby, sizeof(nid), &nid)) {
613 return false;
614 }
615 cksum = npf_fixup16_cksum(cksum, oid, nid);
616 ip->ip_id = nid;
617 }
618
619 /* IP_DF flag cleansing. */
620 if (no_df && (ip_off & htons(IP_DF)) != 0) {
621 uint16_t nip_off = ip_off & ~htons(IP_DF);
622
623 if (nbuf_advstore(&nbuf, &n_ptr,
624 offsetof(struct ip, ip_off) - offby,
625 sizeof(uint16_t), &nip_off)) {
626 return false;
627 }
628 cksum = npf_fixup16_cksum(cksum, ip_off, nip_off);
629 ip->ip_off = nip_off;
630 offby = offsetof(struct ip, ip_off);
631 }
632
633 /* Enforce minimum TTL. */
634 if (minttl && ttl < minttl) {
635 if (nbuf_advstore(&nbuf, &n_ptr,
636 offsetof(struct ip, ip_ttl) - offby,
637 sizeof(uint8_t), &minttl)) {
638 return false;
639 }
640 cksum = npf_fixup16_cksum(cksum, ttl, minttl);
641 ip->ip_ttl = minttl;
642 offby = offsetof(struct ip, ip_ttl);
643 }
644
645 /* Update IP checksum. */
646 offby = offsetof(struct ip, ip_sum) - offby;
647 if (nbuf_advstore(&nbuf, &n_ptr, offby, sizeof(cksum), &cksum)) {
648 return false;
649 }
650 ip->ip_sum = cksum;
651 return true;
652 }
653
654 bool
655 npf_normalize(npf_cache_t *npc, nbuf_t *nbuf,
656 bool no_df, bool rnd, u_int minttl, u_int maxmss)
657 {
658 void *n_ptr = nbuf_dataptr(nbuf);
659 struct tcphdr *th = &npc->npc_l4.tcp;
660 uint16_t cksum, mss;
661 u_int offby;
662 int wscale;
663
664 /* Normalize IPv4. */
665 if (npf_iscached(npc, NPC_IP4) && (rnd || minttl)) {
666 if (!npf_normalize_ip4(npc, nbuf, rnd, no_df, minttl)) {
667 return false;
668 }
669 } else if (!npf_iscached(npc, NPC_IP4)) {
670 /* XXX: no IPv6 */
671 return false;
672 }
673
674 /*
675 * TCP Maximum Segment Size (MSS) "clamping". Only if SYN packet.
676 * Fetch MSS and check whether rewrite to lower is needed.
677 */
678 if (maxmss == 0 || !npf_iscached(npc, NPC_TCP) ||
679 (th->th_flags & TH_SYN) == 0) {
680 /* Not required; done. */
681 return true;
682 }
683 mss = 0;
684 if (!npf_fetch_tcpopts(npc, nbuf, &mss, &wscale)) {
685 return false;
686 }
687 if (ntohs(mss) <= maxmss) {
688 return true;
689 }
690
691 /* Calculate TCP checksum, then rewrite MSS and the checksum. */
692 maxmss = htons(maxmss);
693 cksum = npf_fixup16_cksum(th->th_sum, mss, maxmss);
694 th->th_sum = cksum;
695 mss = maxmss;
696 if (!npf_fetch_tcpopts(npc, nbuf, &mss, &wscale)) {
697 return false;
698 }
699 offby = npf_cache_hlen(npc) + offsetof(struct tcphdr, th_sum);
700 if (nbuf_advstore(&nbuf, &n_ptr, offby, sizeof(cksum), &cksum)) {
701 return false;
702 }
703 return true;
704 }
705