1 /* $NetBSD: npf_ext_normalize.c,v 1.1 2013/03/12 20:47:48 christos Exp $ */ 2 3 /*- 4 * Copyright (c) 2009-2012 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 17 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 18 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 * POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 #include <sys/cdefs.h> 30 __KERNEL_RCSID(0, "$NetBSD: npf_ext_normalize.c,v 1.1 2013/03/12 20:47:48 christos Exp $"); 31 32 #include <sys/types.h> 33 #include <sys/module.h> 34 #include <sys/kmem.h> 35 36 #include <net/if.h> 37 #include <netinet/in_systm.h> 38 #include <netinet/in.h> 39 #include <netinet/in_var.h> 40 41 #include "npf.h" 42 #include "npf_impl.h" 43 44 /* 45 * NPF extension module definition and the identifier. 46 */ 47 NPF_EXT_MODULE(npf_ext_normalize, ""); 48 49 #define NPFEXT_NORMALIZE_VER 1 50 51 static void * npf_ext_normalize_id; 52 53 /* 54 * Normalisation parameters. 55 */ 56 typedef struct { 57 u_int n_minttl; 58 u_int n_maxmss; 59 bool n_random_id; 60 bool n_no_df; 61 } npf_normalize_t; 62 63 /* 64 * npf_normalize_ctor: a constructor for the normalisation rule procedure 65 * with the given parameters. 66 */ 67 static int 68 npf_normalize_ctor(npf_rproc_t *rp, prop_dictionary_t params) 69 { 70 npf_normalize_t *np; 71 72 /* Create a structure for normalisation parameters. */ 73 np = kmem_zalloc(sizeof(npf_normalize_t), KM_SLEEP); 74 75 /* IP ID randomisation and IP_DF flag cleansing. */ 76 prop_dictionary_get_bool(params, "random-id", &np->n_random_id); 77 prop_dictionary_get_bool(params, "no-df", &np->n_no_df); 78 79 /* Minimum IP TTL and maximum TCP MSS. */ 80 prop_dictionary_get_uint32(params, "min-ttl", &np->n_minttl); 81 prop_dictionary_get_uint32(params, "max-mss", &np->n_maxmss); 82 83 /* Assign the parameters for this rule procedure. */ 84 npf_rproc_assign(rp, np); 85 return 0; 86 } 87 88 /* 89 * npf_normalize_dtor: a destructor for a normalisation rule procedure. 90 */ 91 static void 92 npf_normalize_dtor(npf_rproc_t *rp, void *params) 93 { 94 /* Free our meta-data, associated with the procedure. */ 95 kmem_free(params, sizeof(npf_normalize_t)); 96 } 97 98 /* 99 * npf_normalize_ip4: routine to normalize IPv4 header (randomise ID, 100 * clear "don't fragment" and/or enforce minimum TTL). 101 */ 102 static inline void 103 npf_normalize_ip4(npf_cache_t *npc, npf_normalize_t *np) 104 { 105 struct ip *ip = npc->npc_ip.v4; 106 uint16_t cksum = ip->ip_sum; 107 uint16_t ip_off = ip->ip_off; 108 uint8_t ttl = ip->ip_ttl; 109 u_int minttl = np->n_minttl; 110 111 KASSERT(np->n_random_id || np->n_no_df || minttl); 112 113 /* Randomise IPv4 ID. */ 114 if (np->n_random_id) { 115 uint16_t oid = ip->ip_id, nid; 116 117 nid = htons(ip_randomid(ip_ids, 0)); 118 cksum = npf_fixup16_cksum(cksum, oid, nid); 119 ip->ip_id = nid; 120 } 121 122 /* IP_DF flag cleansing. */ 123 if (np->n_no_df && (ip_off & htons(IP_DF)) != 0) { 124 uint16_t nip_off = ip_off & ~htons(IP_DF); 125 126 cksum = npf_fixup16_cksum(cksum, ip_off, nip_off); 127 ip->ip_off = nip_off; 128 } 129 130 /* Enforce minimum TTL. */ 131 if (minttl && ttl < minttl) { 132 cksum = npf_fixup16_cksum(cksum, ttl, minttl); 133 ip->ip_ttl = minttl; 134 } 135 136 /* Update IPv4 checksum. */ 137 ip->ip_sum = cksum; 138 } 139 140 /* 141 * npf_normalize: the main routine to normalize IPv4 and/or TCP headers. 142 */ 143 static void 144 npf_normalize(npf_cache_t *npc, nbuf_t *nbuf, void *params, int *decision) 145 { 146 npf_normalize_t *np = params; 147 struct tcphdr *th = npc->npc_l4.tcp; 148 uint16_t cksum, mss, maxmss = np->n_maxmss; 149 int wscale; 150 151 /* Skip, if already blocking. */ 152 if (*decision == NPF_DECISION_BLOCK) { 153 return; 154 } 155 156 /* Normalise IPv4. Nothing to do for IPv6. */ 157 if (npf_iscached(npc, NPC_IP4) && (np->n_random_id || np->n_minttl)) { 158 npf_normalize_ip4(npc, np); 159 } 160 161 /* 162 * TCP Maximum Segment Size (MSS) "clamping". Only if SYN packet. 163 * Fetch MSS and check whether rewrite to lower is needed. 164 */ 165 if (maxmss == 0 || !npf_iscached(npc, NPC_TCP) || 166 (th->th_flags & TH_SYN) == 0) { 167 /* Not required; done. */ 168 return; 169 } 170 mss = 0; 171 if (!npf_fetch_tcpopts(npc, nbuf, &mss, &wscale)) { 172 return; 173 } 174 if (ntohs(mss) <= maxmss) { 175 /* Nothing else to do. */ 176 return; 177 } 178 maxmss = htons(maxmss); 179 180 /* Store new MSS, calculate TCP checksum and update it. */ 181 if (npf_fetch_tcpopts(npc, nbuf, &maxmss, &wscale)) { 182 cksum = npf_fixup16_cksum(th->th_sum, mss, maxmss); 183 th->th_sum = cksum; 184 } 185 } 186 187 static int 188 npf_ext_normalize_modcmd(modcmd_t cmd, void *arg) 189 { 190 static const npf_ext_ops_t npf_normalize_ops = { 191 .version = NPFEXT_NORMALIZE_VER, 192 .ctx = NULL, 193 .ctor = npf_normalize_ctor, 194 .dtor = npf_normalize_dtor, 195 .proc = npf_normalize 196 }; 197 198 switch (cmd) { 199 case MODULE_CMD_INIT: 200 /* 201 * Initialise normalisation module. Register the "normalize" 202 * extension and its calls. 203 */ 204 npf_ext_normalize_id = 205 npf_ext_register("normalize", &npf_normalize_ops); 206 return npf_ext_normalize_id ? 0 : EEXIST; 207 208 case MODULE_CMD_FINI: 209 /* Unregister the normalisation rule procedure. */ 210 return npf_ext_unregister(npf_ext_normalize_id); 211 212 case MODULE_CMD_AUTOUNLOAD: 213 return npf_autounload_p() ? 0 : EBUSY; 214 215 default: 216 return ENOTTY; 217 } 218 return 0; 219 } 220