ip6t_frag.c (3816B)
1// SPDX-License-Identifier: GPL-2.0-only 2/* Kernel module to match FRAG parameters. */ 3 4/* (C) 2001-2002 Andras Kis-Szabo <kisza@sch.bme.hu> 5 */ 6#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 7#include <linux/module.h> 8#include <linux/skbuff.h> 9#include <linux/ipv6.h> 10#include <linux/types.h> 11#include <net/checksum.h> 12#include <net/ipv6.h> 13 14#include <linux/netfilter/x_tables.h> 15#include <linux/netfilter_ipv6/ip6_tables.h> 16#include <linux/netfilter_ipv6/ip6t_frag.h> 17 18MODULE_LICENSE("GPL"); 19MODULE_DESCRIPTION("Xtables: IPv6 fragment match"); 20MODULE_AUTHOR("Andras Kis-Szabo <kisza@sch.bme.hu>"); 21 22/* Returns 1 if the id is matched by the range, 0 otherwise */ 23static inline bool 24id_match(u_int32_t min, u_int32_t max, u_int32_t id, bool invert) 25{ 26 bool r; 27 pr_debug("id_match:%c 0x%x <= 0x%x <= 0x%x\n", invert ? '!' : ' ', 28 min, id, max); 29 r = (id >= min && id <= max) ^ invert; 30 pr_debug(" result %s\n", r ? "PASS" : "FAILED"); 31 return r; 32} 33 34static bool 35frag_mt6(const struct sk_buff *skb, struct xt_action_param *par) 36{ 37 struct frag_hdr _frag; 38 const struct frag_hdr *fh; 39 const struct ip6t_frag *fraginfo = par->matchinfo; 40 unsigned int ptr = 0; 41 int err; 42 43 err = ipv6_find_hdr(skb, &ptr, NEXTHDR_FRAGMENT, NULL, NULL); 44 if (err < 0) { 45 if (err != -ENOENT) 46 par->hotdrop = true; 47 return false; 48 } 49 50 fh = skb_header_pointer(skb, ptr, sizeof(_frag), &_frag); 51 if (fh == NULL) { 52 par->hotdrop = true; 53 return false; 54 } 55 56 pr_debug("INFO %04X ", fh->frag_off); 57 pr_debug("OFFSET %04X ", ntohs(fh->frag_off) & ~0x7); 58 pr_debug("RES %02X %04X", fh->reserved, ntohs(fh->frag_off) & 0x6); 59 pr_debug("MF %04X ", fh->frag_off & htons(IP6_MF)); 60 pr_debug("ID %u %08X\n", ntohl(fh->identification), 61 ntohl(fh->identification)); 62 63 pr_debug("IPv6 FRAG id %02X ", 64 id_match(fraginfo->ids[0], fraginfo->ids[1], 65 ntohl(fh->identification), 66 !!(fraginfo->invflags & IP6T_FRAG_INV_IDS))); 67 pr_debug("res %02X %02X%04X %02X ", 68 fraginfo->flags & IP6T_FRAG_RES, fh->reserved, 69 ntohs(fh->frag_off) & 0x6, 70 !((fraginfo->flags & IP6T_FRAG_RES) && 71 (fh->reserved || (ntohs(fh->frag_off) & 0x06)))); 72 pr_debug("first %02X %02X %02X ", 73 fraginfo->flags & IP6T_FRAG_FST, 74 ntohs(fh->frag_off) & ~0x7, 75 !((fraginfo->flags & IP6T_FRAG_FST) && 76 (ntohs(fh->frag_off) & ~0x7))); 77 pr_debug("mf %02X %02X %02X ", 78 fraginfo->flags & IP6T_FRAG_MF, 79 ntohs(fh->frag_off) & IP6_MF, 80 !((fraginfo->flags & IP6T_FRAG_MF) && 81 !((ntohs(fh->frag_off) & IP6_MF)))); 82 pr_debug("last %02X %02X %02X\n", 83 fraginfo->flags & IP6T_FRAG_NMF, 84 ntohs(fh->frag_off) & IP6_MF, 85 !((fraginfo->flags & IP6T_FRAG_NMF) && 86 (ntohs(fh->frag_off) & IP6_MF))); 87 88 return id_match(fraginfo->ids[0], fraginfo->ids[1], 89 ntohl(fh->identification), 90 !!(fraginfo->invflags & IP6T_FRAG_INV_IDS)) && 91 !((fraginfo->flags & IP6T_FRAG_RES) && 92 (fh->reserved || (ntohs(fh->frag_off) & 0x6))) && 93 !((fraginfo->flags & IP6T_FRAG_FST) && 94 (ntohs(fh->frag_off) & ~0x7)) && 95 !((fraginfo->flags & IP6T_FRAG_MF) && 96 !(ntohs(fh->frag_off) & IP6_MF)) && 97 !((fraginfo->flags & IP6T_FRAG_NMF) && 98 (ntohs(fh->frag_off) & IP6_MF)); 99} 100 101static int frag_mt6_check(const struct xt_mtchk_param *par) 102{ 103 const struct ip6t_frag *fraginfo = par->matchinfo; 104 105 if (fraginfo->invflags & ~IP6T_FRAG_INV_MASK) { 106 pr_debug("unknown flags %X\n", fraginfo->invflags); 107 return -EINVAL; 108 } 109 return 0; 110} 111 112static struct xt_match frag_mt6_reg __read_mostly = { 113 .name = "frag", 114 .family = NFPROTO_IPV6, 115 .match = frag_mt6, 116 .matchsize = sizeof(struct ip6t_frag), 117 .checkentry = frag_mt6_check, 118 .me = THIS_MODULE, 119}; 120 121static int __init frag_mt6_init(void) 122{ 123 return xt_register_match(&frag_mt6_reg); 124} 125 126static void __exit frag_mt6_exit(void) 127{ 128 xt_unregister_match(&frag_mt6_reg); 129} 130 131module_init(frag_mt6_init); 132module_exit(frag_mt6_exit);