1 1.27 rillig /* $NetBSD: ip_nat.c,v 1.27 2024/09/08 09:36:51 rillig Exp $ */ 2 1.1 christos 3 1.1 christos /* 4 1.1 christos * Copyright (C) 2012 by Darren Reed. 5 1.1 christos * 6 1.1 christos * See the IPFILTER.LICENCE file for details on licencing. 7 1.1 christos */ 8 1.1 christos #if defined(KERNEL) || defined(_KERNEL) 9 1.1 christos # undef KERNEL 10 1.3 darrenr # undef KERNEL 11 1.3 darrenr # define KERNEL 1 12 1.1 christos # define KERNEL 1 13 1.1 christos #endif 14 1.1 christos #include <sys/errno.h> 15 1.1 christos #include <sys/types.h> 16 1.1 christos #include <sys/param.h> 17 1.1 christos #include <sys/time.h> 18 1.1 christos #include <sys/file.h> 19 1.1 christos #if defined(_KERNEL) && \ 20 1.1 christos (defined(__NetBSD_Version) && (__NetBSD_Version >= 399002000)) 21 1.1 christos # include <sys/kauth.h> 22 1.1 christos #endif 23 1.1 christos #if !defined(_KERNEL) 24 1.1 christos # include <stdio.h> 25 1.1 christos # include <string.h> 26 1.1 christos # include <stdlib.h> 27 1.3 darrenr # define KERNEL 28 1.3 darrenr # ifdef _OpenBSD__ 29 1.1 christos struct file; 30 1.1 christos # endif 31 1.1 christos # include <sys/uio.h> 32 1.3 darrenr # undef KERNEL 33 1.1 christos #endif 34 1.1 christos #if defined(_KERNEL) && \ 35 1.1 christos defined(__FreeBSD_version) && (__FreeBSD_version >= 220000) 36 1.1 christos # include <sys/filio.h> 37 1.1 christos # include <sys/fcntl.h> 38 1.1 christos #else 39 1.1 christos # include <sys/ioctl.h> 40 1.1 christos #endif 41 1.1 christos #if !defined(AIX) 42 1.1 christos # include <sys/fcntl.h> 43 1.1 christos #endif 44 1.1 christos #if !defined(linux) 45 1.1 christos # include <sys/protosw.h> 46 1.1 christos #endif 47 1.1 christos #include <sys/socket.h> 48 1.1 christos #if defined(_KERNEL) 49 1.1 christos # include <sys/systm.h> 50 1.1 christos # if !defined(__SVR4) && !defined(__svr4__) 51 1.1 christos # include <sys/mbuf.h> 52 1.1 christos # endif 53 1.1 christos #endif 54 1.1 christos #if defined(__SVR4) || defined(__svr4__) 55 1.1 christos # include <sys/filio.h> 56 1.1 christos # include <sys/byteorder.h> 57 1.3 darrenr # ifdef KERNEL 58 1.1 christos # include <sys/dditypes.h> 59 1.1 christos # endif 60 1.1 christos # include <sys/stream.h> 61 1.1 christos # include <sys/kmem.h> 62 1.1 christos #endif 63 1.3 darrenr #if _FreeBSD_version >= 300000 64 1.1 christos # include <sys/queue.h> 65 1.1 christos #endif 66 1.1 christos #include <net/if.h> 67 1.3 darrenr #if _FreeBSD_version >= 300000 68 1.1 christos # include <net/if_var.h> 69 1.1 christos #endif 70 1.1 christos #ifdef sun 71 1.1 christos # include <net/af.h> 72 1.1 christos #endif 73 1.1 christos #include <netinet/in.h> 74 1.1 christos #include <netinet/in_systm.h> 75 1.1 christos #include <netinet/ip.h> 76 1.1 christos 77 1.1 christos #ifdef RFC1825 78 1.1 christos # include <vpn/md5.h> 79 1.1 christos # include <vpn/ipsec.h> 80 1.1 christos extern struct ifnet vpnif; 81 1.1 christos #endif 82 1.1 christos 83 1.1 christos #if !defined(linux) 84 1.1 christos # include <netinet/ip_var.h> 85 1.1 christos #endif 86 1.1 christos #include <netinet/tcp.h> 87 1.1 christos #include <netinet/udp.h> 88 1.1 christos #include <netinet/ip_icmp.h> 89 1.1 christos #include "netinet/ip_compat.h" 90 1.1 christos #include "netinet/ipl.h" 91 1.1 christos #include "netinet/ip_fil.h" 92 1.1 christos #include "netinet/ip_nat.h" 93 1.1 christos #include "netinet/ip_frag.h" 94 1.1 christos #include "netinet/ip_state.h" 95 1.1 christos #include "netinet/ip_proxy.h" 96 1.1 christos #include "netinet/ip_lookup.h" 97 1.1 christos #include "netinet/ip_dstlist.h" 98 1.1 christos #include "netinet/ip_sync.h" 99 1.1 christos #if FREEBSD_GE_REV(300000) 100 1.1 christos # include <sys/malloc.h> 101 1.1 christos #endif 102 1.1 christos #ifdef HAS_SYS_MD5_H 103 1.1 christos # include <sys/md5.h> 104 1.1 christos #else 105 1.1 christos # include "md5.h" 106 1.1 christos #endif 107 1.1 christos /* END OF INCLUDES */ 108 1.1 christos 109 1.1 christos #undef SOCKADDR_IN 110 1.1 christos #define SOCKADDR_IN struct sockaddr_in 111 1.1 christos 112 1.1 christos #if !defined(lint) 113 1.2 christos #if defined(__NetBSD__) 114 1.2 christos #include <sys/cdefs.h> 115 1.27 rillig __KERNEL_RCSID(0, "$NetBSD: ip_nat.c,v 1.27 2024/09/08 09:36:51 rillig Exp $"); 116 1.2 christos #else 117 1.1 christos static const char sccsid[] = "@(#)ip_nat.c 1.11 6/5/96 (C) 1995 Darren Reed"; 118 1.3 darrenr static const char rcsid[] = "@(#)Id: ip_nat.c,v 1.1.1.2 2012/07/22 13:45:27 darrenr Exp"; 119 1.2 christos #endif 120 1.1 christos #endif 121 1.1 christos 122 1.1 christos 123 1.1 christos #define NATFSUM(n,v,f) ((v) == 4 ? (n)->f.in4.s_addr : (n)->f.i6[0] + \ 124 1.1 christos (n)->f.i6[1] + (n)->f.i6[2] + (n)->f.i6[3]) 125 1.1 christos #define NBUMP(x) softn->(x)++ 126 1.1 christos #define NBUMPD(x, y) do { \ 127 1.1 christos softn->x.y++; \ 128 1.1 christos DT(y); \ 129 1.1 christos } while (0) 130 1.1 christos #define NBUMPSIDE(y,x) softn->ipf_nat_stats.ns_side[y].x++ 131 1.1 christos #define NBUMPSIDED(y,x) do { softn->ipf_nat_stats.ns_side[y].x++; \ 132 1.1 christos DT(x); } while (0) 133 1.1 christos #define NBUMPSIDEX(y,x,z) \ 134 1.1 christos do { softn->ipf_nat_stats.ns_side[y].x++; \ 135 1.1 christos DT(z); } while (0) 136 1.1 christos #define NBUMPSIDEDF(y,x)do { softn->ipf_nat_stats.ns_side[y].x++; \ 137 1.1 christos DT1(x, fr_info_t *, fin); } while (0) 138 1.1 christos 139 1.1 christos frentry_t ipfnatblock; 140 1.1 christos 141 1.20 maxv static const ipftuneable_t ipf_nat_tuneables[] = { 142 1.1 christos /* nat */ 143 1.1 christos { { (void *)offsetof(ipf_nat_softc_t, ipf_nat_lock) }, 144 1.1 christos "nat_lock", 0, 1, 145 1.1 christos stsizeof(ipf_nat_softc_t, ipf_nat_lock), 146 1.1 christos IPFT_RDONLY, NULL, NULL }, 147 1.1 christos { { (void *)offsetof(ipf_nat_softc_t, ipf_nat_table_sz) }, 148 1.1 christos "nat_table_size", 1, 0x7fffffff, 149 1.1 christos stsizeof(ipf_nat_softc_t, ipf_nat_table_sz), 150 1.1 christos 0, NULL, ipf_nat_rehash }, 151 1.1 christos { { (void *)offsetof(ipf_nat_softc_t, ipf_nat_table_max) }, 152 1.1 christos "nat_table_max", 1, 0x7fffffff, 153 1.1 christos stsizeof(ipf_nat_softc_t, ipf_nat_table_max), 154 1.1 christos 0, NULL, NULL }, 155 1.1 christos { { (void *)offsetof(ipf_nat_softc_t, ipf_nat_maprules_sz) }, 156 1.1 christos "nat_rules_size", 1, 0x7fffffff, 157 1.1 christos stsizeof(ipf_nat_softc_t, ipf_nat_maprules_sz), 158 1.1 christos 0, NULL, ipf_nat_rehash_rules }, 159 1.1 christos { { (void *)offsetof(ipf_nat_softc_t, ipf_nat_rdrrules_sz) }, 160 1.1 christos "rdr_rules_size", 1, 0x7fffffff, 161 1.1 christos stsizeof(ipf_nat_softc_t, ipf_nat_rdrrules_sz), 162 1.1 christos 0, NULL, ipf_nat_rehash_rules }, 163 1.1 christos { { (void *)offsetof(ipf_nat_softc_t, ipf_nat_hostmap_sz) }, 164 1.1 christos "hostmap_size", 1, 0x7fffffff, 165 1.1 christos stsizeof(ipf_nat_softc_t, ipf_nat_hostmap_sz), 166 1.1 christos 0, NULL, ipf_nat_hostmap_rehash }, 167 1.1 christos { { (void *)offsetof(ipf_nat_softc_t, ipf_nat_maxbucket) }, 168 1.1 christos "nat_maxbucket",1, 0x7fffffff, 169 1.1 christos stsizeof(ipf_nat_softc_t, ipf_nat_maxbucket), 170 1.1 christos 0, NULL, NULL }, 171 1.1 christos { { (void *)offsetof(ipf_nat_softc_t, ipf_nat_logging) }, 172 1.1 christos "nat_logging", 0, 1, 173 1.1 christos stsizeof(ipf_nat_softc_t, ipf_nat_logging), 174 1.1 christos 0, NULL, NULL }, 175 1.1 christos { { (void *)offsetof(ipf_nat_softc_t, ipf_nat_doflush) }, 176 1.1 christos "nat_doflush", 0, 1, 177 1.1 christos stsizeof(ipf_nat_softc_t, ipf_nat_doflush), 178 1.1 christos 0, NULL, NULL }, 179 1.1 christos { { (void *)offsetof(ipf_nat_softc_t, ipf_nat_table_wm_low) }, 180 1.1 christos "nat_table_wm_low", 1, 99, 181 1.1 christos stsizeof(ipf_nat_softc_t, ipf_nat_table_wm_low), 182 1.1 christos 0, NULL, NULL }, 183 1.1 christos { { (void *)offsetof(ipf_nat_softc_t, ipf_nat_table_wm_high) }, 184 1.1 christos "nat_table_wm_high", 2, 100, 185 1.1 christos stsizeof(ipf_nat_softc_t, ipf_nat_table_wm_high), 186 1.1 christos 0, NULL, NULL }, 187 1.1 christos { { 0 }, 188 1.1 christos NULL, 0, 0, 189 1.1 christos 0, 190 1.1 christos 0, NULL, NULL } 191 1.1 christos }; 192 1.1 christos 193 1.1 christos /* ======================================================================== */ 194 1.1 christos /* How the NAT is organised and works. */ 195 1.1 christos /* */ 196 1.1 christos /* Inside (interface y) NAT Outside (interface x) */ 197 1.1 christos /* -------------------- -+- ------------------------------------- */ 198 1.1 christos /* Packet going | out, processsed by ipf_nat_checkout() for x */ 199 1.1 christos /* ------------> | ------------> */ 200 1.1 christos /* src=10.1.1.1 | src=192.1.1.1 */ 201 1.1 christos /* | */ 202 1.1 christos /* | in, processed by ipf_nat_checkin() for x */ 203 1.1 christos /* <------------ | <------------ */ 204 1.1 christos /* dst=10.1.1.1 | dst=192.1.1.1 */ 205 1.1 christos /* -------------------- -+- ------------------------------------- */ 206 1.1 christos /* ipf_nat_checkout() - changes ip_src and if required, sport */ 207 1.1 christos /* - creates a new mapping, if required. */ 208 1.1 christos /* ipf_nat_checkin() - changes ip_dst and if required, dport */ 209 1.1 christos /* */ 210 1.1 christos /* In the NAT table, internal source is recorded as "in" and externally */ 211 1.1 christos /* seen as "out". */ 212 1.1 christos /* ======================================================================== */ 213 1.1 christos 214 1.1 christos 215 1.1 christos #if SOLARIS && !defined(INSTANCES) 216 1.1 christos extern int pfil_delayed_copy; 217 1.1 christos #endif 218 1.1 christos 219 1.2 christos static int ipf_nat_flush_entry(ipf_main_softc_t *, void *); 220 1.2 christos static int ipf_nat_getent(ipf_main_softc_t *, void *, int); 221 1.2 christos static int ipf_nat_getsz(ipf_main_softc_t *, void *, int); 222 1.2 christos static int ipf_nat_putent(ipf_main_softc_t *, void *, int); 223 1.2 christos static void ipf_nat_addmap(ipf_nat_softc_t *, ipnat_t *); 224 1.2 christos static void ipf_nat_addrdr(ipf_nat_softc_t *, ipnat_t *); 225 1.2 christos static int ipf_nat_builddivertmp(ipf_nat_softc_t *, ipnat_t *); 226 1.2 christos static int ipf_nat_clearlist(ipf_main_softc_t *, ipf_nat_softc_t *); 227 1.2 christos static int ipf_nat_cmp_rules(ipnat_t *, ipnat_t *); 228 1.2 christos static int ipf_nat_decap(fr_info_t *, nat_t *); 229 1.3 darrenr static void ipf_nat_delrule(ipf_main_softc_t *, ipf_nat_softc_t *, 230 1.3 darrenr ipnat_t *, int); 231 1.2 christos static int ipf_nat_extraflush(ipf_main_softc_t *, ipf_nat_softc_t *, int); 232 1.2 christos static int ipf_nat_finalise(fr_info_t *, nat_t *); 233 1.2 christos static int ipf_nat_flushtable(ipf_main_softc_t *, ipf_nat_softc_t *); 234 1.2 christos static int ipf_nat_getnext(ipf_main_softc_t *, ipftoken_t *, 235 1.2 christos ipfgeniter_t *, ipfobj_t *); 236 1.2 christos static int ipf_nat_gettable(ipf_main_softc_t *, ipf_nat_softc_t *, char *); 237 1.2 christos static hostmap_t *ipf_nat_hostmap(ipf_nat_softc_t *, ipnat_t *, 238 1.2 christos struct in_addr, struct in_addr, 239 1.2 christos struct in_addr, u_32_t); 240 1.2 christos static int ipf_nat_icmpquerytype(int); 241 1.2 christos static int ipf_nat_iterator(ipf_main_softc_t *, ipftoken_t *, 242 1.2 christos ipfgeniter_t *, ipfobj_t *); 243 1.2 christos static int ipf_nat_match(fr_info_t *, ipnat_t *); 244 1.2 christos static int ipf_nat_matcharray(nat_t *, int *, u_long); 245 1.2 christos static int ipf_nat_matchflush(ipf_main_softc_t *, ipf_nat_softc_t *, 246 1.2 christos void *); 247 1.2 christos static void ipf_nat_mssclamp(tcphdr_t *, u_32_t, fr_info_t *, u_short *); 248 1.2 christos static int ipf_nat_newmap(fr_info_t *, nat_t *, natinfo_t *); 249 1.2 christos static int ipf_nat_newdivert(fr_info_t *, nat_t *, natinfo_t *); 250 1.2 christos static int ipf_nat_newrdr(fr_info_t *, nat_t *, natinfo_t *); 251 1.2 christos static int ipf_nat_newrewrite(fr_info_t *, nat_t *, natinfo_t *); 252 1.2 christos static int ipf_nat_nextaddr(fr_info_t *, nat_addr_t *, u_32_t *, u_32_t *); 253 1.2 christos static int ipf_nat_nextaddrinit(ipf_main_softc_t *, char *, 254 1.2 christos nat_addr_t *, int, void *); 255 1.2 christos static int ipf_nat_resolverule(ipf_main_softc_t *, ipnat_t *); 256 1.2 christos static int ipf_nat_ruleaddrinit(ipf_main_softc_t *, 257 1.2 christos ipf_nat_softc_t *, ipnat_t *); 258 1.3 darrenr static void ipf_nat_rule_fini(ipf_main_softc_t *, ipnat_t *); 259 1.3 darrenr static int ipf_nat_rule_init(ipf_main_softc_t *, ipf_nat_softc_t *, 260 1.3 darrenr ipnat_t *); 261 1.2 christos static int ipf_nat_siocaddnat(ipf_main_softc_t *, ipf_nat_softc_t *, 262 1.3 darrenr ipnat_t *, int); 263 1.2 christos static void ipf_nat_siocdelnat(ipf_main_softc_t *, ipf_nat_softc_t *, 264 1.3 darrenr ipnat_t *, int); 265 1.2 christos static void ipf_nat_tabmove(ipf_nat_softc_t *, nat_t *); 266 1.1 christos 267 1.1 christos /* ------------------------------------------------------------------------ */ 268 1.1 christos /* Function: ipf_nat_main_load */ 269 1.1 christos /* Returns: int - 0 == success, -1 == failure */ 270 1.1 christos /* Parameters: Nil */ 271 1.1 christos /* */ 272 1.1 christos /* The only global NAT structure that needs to be initialised is the filter */ 273 1.1 christos /* rule that is used with blocking packets. */ 274 1.1 christos /* ------------------------------------------------------------------------ */ 275 1.1 christos int 276 1.2 christos ipf_nat_main_load(void) 277 1.1 christos { 278 1.1 christos bzero((char *)&ipfnatblock, sizeof(ipfnatblock)); 279 1.1 christos ipfnatblock.fr_flags = FR_BLOCK|FR_QUICK; 280 1.1 christos ipfnatblock.fr_ref = 1; 281 1.1 christos 282 1.1 christos return 0; 283 1.1 christos } 284 1.1 christos 285 1.1 christos 286 1.1 christos /* ------------------------------------------------------------------------ */ 287 1.1 christos /* Function: ipf_nat_main_unload */ 288 1.1 christos /* Returns: int - 0 == success, -1 == failure */ 289 1.1 christos /* Parameters: Nil */ 290 1.1 christos /* */ 291 1.1 christos /* A null-op function that exists as a placeholder so that the flow in */ 292 1.1 christos /* other functions is obvious. */ 293 1.1 christos /* ------------------------------------------------------------------------ */ 294 1.1 christos int 295 1.2 christos ipf_nat_main_unload(void) 296 1.1 christos { 297 1.1 christos return 0; 298 1.1 christos } 299 1.1 christos 300 1.1 christos 301 1.1 christos /* ------------------------------------------------------------------------ */ 302 1.1 christos /* Function: ipf_nat_soft_create */ 303 1.1 christos /* Returns: void * - NULL = failure, else pointer to NAT context */ 304 1.1 christos /* Parameters: softc(I) - pointer to soft context main structure */ 305 1.1 christos /* */ 306 1.1 christos /* Allocate the initial soft context structure for NAT and populate it with */ 307 1.1 christos /* some default values. Creating the tables is left until we call _init so */ 308 1.1 christos /* that sizes can be changed before we get under way. */ 309 1.1 christos /* ------------------------------------------------------------------------ */ 310 1.1 christos void * 311 1.2 christos ipf_nat_soft_create(ipf_main_softc_t *softc) 312 1.1 christos { 313 1.1 christos ipf_nat_softc_t *softn; 314 1.1 christos 315 1.1 christos KMALLOC(softn, ipf_nat_softc_t *); 316 1.1 christos if (softn == NULL) 317 1.1 christos return NULL; 318 1.1 christos 319 1.1 christos bzero((char *)softn, sizeof(*softn)); 320 1.1 christos 321 1.1 christos softn->ipf_nat_tune = ipf_tune_array_copy(softn, 322 1.1 christos sizeof(ipf_nat_tuneables), 323 1.1 christos ipf_nat_tuneables); 324 1.1 christos if (softn->ipf_nat_tune == NULL) { 325 1.1 christos ipf_nat_soft_destroy(softc, softn); 326 1.1 christos return NULL; 327 1.1 christos } 328 1.1 christos if (ipf_tune_array_link(softc, softn->ipf_nat_tune) == -1) { 329 1.1 christos ipf_nat_soft_destroy(softc, softn); 330 1.1 christos return NULL; 331 1.1 christos } 332 1.1 christos 333 1.3 darrenr softn->ipf_nat_list_tail = &softn->ipf_nat_list; 334 1.3 darrenr 335 1.1 christos softn->ipf_nat_table_max = NAT_TABLE_MAX; 336 1.1 christos softn->ipf_nat_table_sz = NAT_TABLE_SZ; 337 1.1 christos softn->ipf_nat_maprules_sz = NAT_SIZE; 338 1.1 christos softn->ipf_nat_rdrrules_sz = RDR_SIZE; 339 1.1 christos softn->ipf_nat_hostmap_sz = HOSTMAP_SIZE; 340 1.1 christos softn->ipf_nat_doflush = 0; 341 1.1 christos #ifdef IPFILTER_LOG 342 1.1 christos softn->ipf_nat_logging = 1; 343 1.1 christos #else 344 1.1 christos softn->ipf_nat_logging = 0; 345 1.1 christos #endif 346 1.1 christos 347 1.1 christos softn->ipf_nat_defage = DEF_NAT_AGE; 348 1.1 christos softn->ipf_nat_defipage = IPF_TTLVAL(60); 349 1.1 christos softn->ipf_nat_deficmpage = IPF_TTLVAL(3); 350 1.1 christos softn->ipf_nat_table_wm_high = 99; 351 1.1 christos softn->ipf_nat_table_wm_low = 90; 352 1.1 christos 353 1.1 christos return softn; 354 1.1 christos } 355 1.1 christos 356 1.1 christos /* ------------------------------------------------------------------------ */ 357 1.1 christos /* Function: ipf_nat_soft_destroy */ 358 1.1 christos /* Returns: Nil */ 359 1.1 christos /* Parameters: softc(I) - pointer to soft context main structure */ 360 1.1 christos /* */ 361 1.1 christos /* ------------------------------------------------------------------------ */ 362 1.1 christos void 363 1.2 christos ipf_nat_soft_destroy(ipf_main_softc_t *softc, void *arg) 364 1.1 christos { 365 1.1 christos ipf_nat_softc_t *softn = arg; 366 1.1 christos 367 1.1 christos if (softn->ipf_nat_tune != NULL) { 368 1.1 christos ipf_tune_array_unlink(softc, softn->ipf_nat_tune); 369 1.1 christos KFREES(softn->ipf_nat_tune, sizeof(ipf_nat_tuneables)); 370 1.1 christos softn->ipf_nat_tune = NULL; 371 1.1 christos } 372 1.1 christos 373 1.1 christos KFREE(softn); 374 1.1 christos } 375 1.1 christos 376 1.1 christos 377 1.1 christos /* ------------------------------------------------------------------------ */ 378 1.1 christos /* Function: ipf_nat_init */ 379 1.1 christos /* Returns: int - 0 == success, -1 == failure */ 380 1.1 christos /* Parameters: softc(I) - pointer to soft context main structure */ 381 1.1 christos /* */ 382 1.1 christos /* Initialise all of the NAT locks, tables and other structures. */ 383 1.1 christos /* ------------------------------------------------------------------------ */ 384 1.1 christos int 385 1.2 christos ipf_nat_soft_init(ipf_main_softc_t *softc, void *arg) 386 1.1 christos { 387 1.1 christos ipf_nat_softc_t *softn = arg; 388 1.1 christos ipftq_t *tq; 389 1.1 christos int i; 390 1.1 christos 391 1.1 christos KMALLOCS(softn->ipf_nat_table[0], nat_t **, \ 392 1.1 christos sizeof(nat_t *) * softn->ipf_nat_table_sz); 393 1.1 christos 394 1.1 christos if (softn->ipf_nat_table[0] != NULL) { 395 1.1 christos bzero((char *)softn->ipf_nat_table[0], 396 1.1 christos softn->ipf_nat_table_sz * sizeof(nat_t *)); 397 1.1 christos } else { 398 1.1 christos return -1; 399 1.1 christos } 400 1.1 christos 401 1.1 christos KMALLOCS(softn->ipf_nat_table[1], nat_t **, \ 402 1.1 christos sizeof(nat_t *) * softn->ipf_nat_table_sz); 403 1.1 christos 404 1.1 christos if (softn->ipf_nat_table[1] != NULL) { 405 1.1 christos bzero((char *)softn->ipf_nat_table[1], 406 1.1 christos softn->ipf_nat_table_sz * sizeof(nat_t *)); 407 1.1 christos } else { 408 1.1 christos return -2; 409 1.1 christos } 410 1.1 christos 411 1.1 christos KMALLOCS(softn->ipf_nat_map_rules, ipnat_t **, \ 412 1.1 christos sizeof(ipnat_t *) * softn->ipf_nat_maprules_sz); 413 1.1 christos 414 1.1 christos if (softn->ipf_nat_map_rules != NULL) { 415 1.1 christos bzero((char *)softn->ipf_nat_map_rules, 416 1.1 christos softn->ipf_nat_maprules_sz * sizeof(ipnat_t *)); 417 1.1 christos } else { 418 1.1 christos return -3; 419 1.1 christos } 420 1.1 christos 421 1.1 christos KMALLOCS(softn->ipf_nat_rdr_rules, ipnat_t **, \ 422 1.1 christos sizeof(ipnat_t *) * softn->ipf_nat_rdrrules_sz); 423 1.1 christos 424 1.1 christos if (softn->ipf_nat_rdr_rules != NULL) { 425 1.1 christos bzero((char *)softn->ipf_nat_rdr_rules, 426 1.1 christos softn->ipf_nat_rdrrules_sz * sizeof(ipnat_t *)); 427 1.1 christos } else { 428 1.1 christos return -4; 429 1.1 christos } 430 1.1 christos 431 1.1 christos KMALLOCS(softn->ipf_hm_maptable, hostmap_t **, \ 432 1.1 christos sizeof(hostmap_t *) * softn->ipf_nat_hostmap_sz); 433 1.1 christos 434 1.1 christos if (softn->ipf_hm_maptable != NULL) { 435 1.1 christos bzero((char *)softn->ipf_hm_maptable, 436 1.1 christos sizeof(hostmap_t *) * softn->ipf_nat_hostmap_sz); 437 1.1 christos } else { 438 1.1 christos return -5; 439 1.1 christos } 440 1.1 christos softn->ipf_hm_maplist = NULL; 441 1.1 christos 442 1.1 christos KMALLOCS(softn->ipf_nat_stats.ns_side[0].ns_bucketlen, u_int *, 443 1.1 christos softn->ipf_nat_table_sz * sizeof(u_int)); 444 1.1 christos 445 1.1 christos if (softn->ipf_nat_stats.ns_side[0].ns_bucketlen == NULL) { 446 1.1 christos return -6; 447 1.1 christos } 448 1.1 christos bzero((char *)softn->ipf_nat_stats.ns_side[0].ns_bucketlen, 449 1.1 christos softn->ipf_nat_table_sz * sizeof(u_int)); 450 1.1 christos 451 1.1 christos KMALLOCS(softn->ipf_nat_stats.ns_side[1].ns_bucketlen, u_int *, 452 1.1 christos softn->ipf_nat_table_sz * sizeof(u_int)); 453 1.1 christos 454 1.1 christos if (softn->ipf_nat_stats.ns_side[1].ns_bucketlen == NULL) { 455 1.1 christos return -7; 456 1.1 christos } 457 1.1 christos 458 1.1 christos bzero((char *)softn->ipf_nat_stats.ns_side[1].ns_bucketlen, 459 1.1 christos softn->ipf_nat_table_sz * sizeof(u_int)); 460 1.1 christos 461 1.1 christos if (softn->ipf_nat_maxbucket == 0) { 462 1.1 christos for (i = softn->ipf_nat_table_sz; i > 0; i >>= 1) 463 1.1 christos softn->ipf_nat_maxbucket++; 464 1.1 christos softn->ipf_nat_maxbucket *= 2; 465 1.1 christos } 466 1.1 christos 467 1.1 christos ipf_sttab_init(softc, softn->ipf_nat_tcptq); 468 1.1 christos /* 469 1.1 christos * Increase this because we may have "keep state" following this too 470 1.1 christos * and packet storms can occur if this is removed too quickly. 471 1.1 christos */ 472 1.1 christos softn->ipf_nat_tcptq[IPF_TCPS_CLOSED].ifq_ttl = softc->ipf_tcplastack; 473 1.1 christos softn->ipf_nat_tcptq[IPF_TCP_NSTATES - 1].ifq_next = 474 1.1 christos &softn->ipf_nat_udptq; 475 1.1 christos 476 1.1 christos IPFTQ_INIT(&softn->ipf_nat_udptq, softn->ipf_nat_defage, 477 1.1 christos "nat ipftq udp tab"); 478 1.1 christos softn->ipf_nat_udptq.ifq_next = &softn->ipf_nat_udpacktq; 479 1.1 christos 480 1.1 christos IPFTQ_INIT(&softn->ipf_nat_udpacktq, softn->ipf_nat_defage, 481 1.1 christos "nat ipftq udpack tab"); 482 1.1 christos softn->ipf_nat_udpacktq.ifq_next = &softn->ipf_nat_icmptq; 483 1.1 christos 484 1.1 christos IPFTQ_INIT(&softn->ipf_nat_icmptq, softn->ipf_nat_deficmpage, 485 1.1 christos "nat icmp ipftq tab"); 486 1.1 christos softn->ipf_nat_icmptq.ifq_next = &softn->ipf_nat_icmpacktq; 487 1.1 christos 488 1.1 christos IPFTQ_INIT(&softn->ipf_nat_icmpacktq, softn->ipf_nat_defage, 489 1.1 christos "nat icmpack ipftq tab"); 490 1.1 christos softn->ipf_nat_icmpacktq.ifq_next = &softn->ipf_nat_iptq; 491 1.1 christos 492 1.1 christos IPFTQ_INIT(&softn->ipf_nat_iptq, softn->ipf_nat_defipage, 493 1.1 christos "nat ip ipftq tab"); 494 1.1 christos softn->ipf_nat_iptq.ifq_next = &softn->ipf_nat_pending; 495 1.1 christos 496 1.1 christos IPFTQ_INIT(&softn->ipf_nat_pending, 1, "nat pending ipftq tab"); 497 1.1 christos softn->ipf_nat_pending.ifq_next = NULL; 498 1.1 christos 499 1.1 christos for (i = 0, tq = softn->ipf_nat_tcptq; i < IPF_TCP_NSTATES; i++, tq++) { 500 1.1 christos if (tq->ifq_ttl < softn->ipf_nat_deficmpage) 501 1.1 christos tq->ifq_ttl = softn->ipf_nat_deficmpage; 502 1.1 christos #ifdef LARGE_NAT 503 1.1 christos else if (tq->ifq_ttl > softn->ipf_nat_defage) 504 1.1 christos tq->ifq_ttl = softn->ipf_nat_defage; 505 1.1 christos #endif 506 1.1 christos } 507 1.1 christos 508 1.1 christos /* 509 1.1 christos * Increase this because we may have "keep state" following 510 1.1 christos * this too and packet storms can occur if this is removed 511 1.1 christos * too quickly. 512 1.1 christos */ 513 1.1 christos softn->ipf_nat_tcptq[IPF_TCPS_CLOSED].ifq_ttl = softc->ipf_tcplastack; 514 1.1 christos 515 1.1 christos MUTEX_INIT(&softn->ipf_nat_new, "ipf nat new mutex"); 516 1.1 christos MUTEX_INIT(&softn->ipf_nat_io, "ipf nat io mutex"); 517 1.1 christos 518 1.1 christos softn->ipf_nat_inited = 1; 519 1.1 christos 520 1.1 christos return 0; 521 1.1 christos } 522 1.1 christos 523 1.1 christos 524 1.1 christos /* ------------------------------------------------------------------------ */ 525 1.1 christos /* Function: ipf_nat_soft_fini */ 526 1.1 christos /* Returns: Nil */ 527 1.1 christos /* Parameters: softc(I) - pointer to soft context main structure */ 528 1.1 christos /* */ 529 1.1 christos /* Free all memory used by NAT structures allocated at runtime. */ 530 1.1 christos /* ------------------------------------------------------------------------ */ 531 1.1 christos int 532 1.2 christos ipf_nat_soft_fini(ipf_main_softc_t *softc, void *arg) 533 1.1 christos { 534 1.1 christos ipf_nat_softc_t *softn = arg; 535 1.1 christos ipftq_t *ifq, *ifqnext; 536 1.1 christos 537 1.1 christos (void) ipf_nat_clearlist(softc, softn); 538 1.1 christos (void) ipf_nat_flushtable(softc, softn); 539 1.1 christos 540 1.1 christos /* 541 1.1 christos * Proxy timeout queues are not cleaned here because although they 542 1.1 christos * exist on the NAT list, ipf_proxy_unload is called after unload 543 1.1 christos * and the proxies actually are responsible for them being created. 544 1.1 christos * Should the proxy timeouts have their own list? There's no real 545 1.1 christos * justification as this is the only complication. 546 1.1 christos */ 547 1.1 christos for (ifq = softn->ipf_nat_utqe; ifq != NULL; ifq = ifqnext) { 548 1.1 christos ifqnext = ifq->ifq_next; 549 1.1 christos if (ipf_deletetimeoutqueue(ifq) == 0) 550 1.1 christos ipf_freetimeoutqueue(softc, ifq); 551 1.1 christos } 552 1.1 christos 553 1.1 christos if (softn->ipf_nat_table[0] != NULL) { 554 1.1 christos KFREES(softn->ipf_nat_table[0], 555 1.1 christos sizeof(nat_t *) * softn->ipf_nat_table_sz); 556 1.1 christos softn->ipf_nat_table[0] = NULL; 557 1.1 christos } 558 1.1 christos if (softn->ipf_nat_table[1] != NULL) { 559 1.1 christos KFREES(softn->ipf_nat_table[1], 560 1.1 christos sizeof(nat_t *) * softn->ipf_nat_table_sz); 561 1.1 christos softn->ipf_nat_table[1] = NULL; 562 1.1 christos } 563 1.1 christos if (softn->ipf_nat_map_rules != NULL) { 564 1.1 christos KFREES(softn->ipf_nat_map_rules, 565 1.1 christos sizeof(ipnat_t *) * softn->ipf_nat_maprules_sz); 566 1.1 christos softn->ipf_nat_map_rules = NULL; 567 1.1 christos } 568 1.1 christos if (softn->ipf_nat_rdr_rules != NULL) { 569 1.1 christos KFREES(softn->ipf_nat_rdr_rules, 570 1.1 christos sizeof(ipnat_t *) * softn->ipf_nat_rdrrules_sz); 571 1.1 christos softn->ipf_nat_rdr_rules = NULL; 572 1.1 christos } 573 1.1 christos if (softn->ipf_hm_maptable != NULL) { 574 1.1 christos KFREES(softn->ipf_hm_maptable, 575 1.1 christos sizeof(hostmap_t *) * softn->ipf_nat_hostmap_sz); 576 1.1 christos softn->ipf_hm_maptable = NULL; 577 1.1 christos } 578 1.1 christos if (softn->ipf_nat_stats.ns_side[0].ns_bucketlen != NULL) { 579 1.1 christos KFREES(softn->ipf_nat_stats.ns_side[0].ns_bucketlen, 580 1.1 christos sizeof(u_int) * softn->ipf_nat_table_sz); 581 1.1 christos softn->ipf_nat_stats.ns_side[0].ns_bucketlen = NULL; 582 1.1 christos } 583 1.1 christos if (softn->ipf_nat_stats.ns_side[1].ns_bucketlen != NULL) { 584 1.1 christos KFREES(softn->ipf_nat_stats.ns_side[1].ns_bucketlen, 585 1.1 christos sizeof(u_int) * softn->ipf_nat_table_sz); 586 1.1 christos softn->ipf_nat_stats.ns_side[1].ns_bucketlen = NULL; 587 1.1 christos } 588 1.1 christos 589 1.1 christos if (softn->ipf_nat_inited == 1) { 590 1.1 christos softn->ipf_nat_inited = 0; 591 1.1 christos ipf_sttab_destroy(softn->ipf_nat_tcptq); 592 1.1 christos 593 1.1 christos MUTEX_DESTROY(&softn->ipf_nat_new); 594 1.1 christos MUTEX_DESTROY(&softn->ipf_nat_io); 595 1.1 christos 596 1.1 christos MUTEX_DESTROY(&softn->ipf_nat_udptq.ifq_lock); 597 1.1 christos MUTEX_DESTROY(&softn->ipf_nat_udpacktq.ifq_lock); 598 1.1 christos MUTEX_DESTROY(&softn->ipf_nat_icmptq.ifq_lock); 599 1.1 christos MUTEX_DESTROY(&softn->ipf_nat_icmpacktq.ifq_lock); 600 1.1 christos MUTEX_DESTROY(&softn->ipf_nat_iptq.ifq_lock); 601 1.1 christos MUTEX_DESTROY(&softn->ipf_nat_pending.ifq_lock); 602 1.1 christos } 603 1.1 christos 604 1.1 christos return 0; 605 1.1 christos } 606 1.1 christos 607 1.1 christos 608 1.1 christos /* ------------------------------------------------------------------------ */ 609 1.1 christos /* Function: ipf_nat_setlock */ 610 1.1 christos /* Returns: Nil */ 611 1.1 christos /* Parameters: arg(I) - pointer to soft state information */ 612 1.1 christos /* tmp(I) - new lock value */ 613 1.1 christos /* */ 614 1.1 christos /* Set the "lock status" of NAT to the value in tmp. */ 615 1.1 christos /* ------------------------------------------------------------------------ */ 616 1.1 christos void 617 1.2 christos ipf_nat_setlock(void *arg, int tmp) 618 1.1 christos { 619 1.1 christos ipf_nat_softc_t *softn = arg; 620 1.1 christos 621 1.1 christos softn->ipf_nat_lock = tmp; 622 1.1 christos } 623 1.1 christos 624 1.1 christos 625 1.1 christos /* ------------------------------------------------------------------------ */ 626 1.1 christos /* Function: ipf_nat_addrdr */ 627 1.1 christos /* Returns: Nil */ 628 1.1 christos /* Parameters: n(I) - pointer to NAT rule to add */ 629 1.1 christos /* */ 630 1.1 christos /* Adds a redirect rule to the hash table of redirect rules and the list of */ 631 1.1 christos /* loaded NAT rules. Updates the bitmask indicating which netmasks are in */ 632 1.1 christos /* use by redirect rules. */ 633 1.1 christos /* ------------------------------------------------------------------------ */ 634 1.1 christos static void 635 1.2 christos ipf_nat_addrdr(ipf_nat_softc_t *softn, ipnat_t *n) 636 1.1 christos { 637 1.1 christos ipnat_t **np; 638 1.1 christos u_32_t j; 639 1.1 christos u_int hv; 640 1.1 christos u_int rhv; 641 1.1 christos int k; 642 1.1 christos 643 1.1 christos if (n->in_odstatype == FRI_NORMAL) { 644 1.1 christos k = count4bits(n->in_odstmsk); 645 1.3 darrenr ipf_inet_mask_add(k, &softn->ipf_nat_rdr_mask); 646 1.1 christos j = (n->in_odstaddr & n->in_odstmsk); 647 1.1 christos rhv = NAT_HASH_FN(j, 0, 0xffffffff); 648 1.1 christos } else { 649 1.3 darrenr ipf_inet_mask_add(0, &softn->ipf_nat_rdr_mask); 650 1.1 christos j = 0; 651 1.1 christos rhv = 0; 652 1.1 christos } 653 1.1 christos hv = rhv % softn->ipf_nat_rdrrules_sz; 654 1.1 christos np = softn->ipf_nat_rdr_rules + hv; 655 1.1 christos while (*np != NULL) 656 1.1 christos np = &(*np)->in_rnext; 657 1.1 christos n->in_rnext = NULL; 658 1.1 christos n->in_prnext = np; 659 1.1 christos n->in_hv[0] = hv; 660 1.3 darrenr n->in_use++; 661 1.1 christos *np = n; 662 1.1 christos } 663 1.1 christos 664 1.1 christos 665 1.1 christos /* ------------------------------------------------------------------------ */ 666 1.1 christos /* Function: ipf_nat_addmap */ 667 1.1 christos /* Returns: Nil */ 668 1.1 christos /* Parameters: n(I) - pointer to NAT rule to add */ 669 1.1 christos /* */ 670 1.1 christos /* Adds a NAT map rule to the hash table of rules and the list of loaded */ 671 1.1 christos /* NAT rules. Updates the bitmask indicating which netmasks are in use by */ 672 1.1 christos /* redirect rules. */ 673 1.1 christos /* ------------------------------------------------------------------------ */ 674 1.1 christos static void 675 1.2 christos ipf_nat_addmap(ipf_nat_softc_t *softn, ipnat_t *n) 676 1.1 christos { 677 1.1 christos ipnat_t **np; 678 1.1 christos u_32_t j; 679 1.1 christos u_int hv; 680 1.1 christos u_int rhv; 681 1.1 christos int k; 682 1.1 christos 683 1.1 christos if (n->in_osrcatype == FRI_NORMAL) { 684 1.1 christos k = count4bits(n->in_osrcmsk); 685 1.3 darrenr ipf_inet_mask_add(k, &softn->ipf_nat_map_mask); 686 1.1 christos j = (n->in_osrcaddr & n->in_osrcmsk); 687 1.1 christos rhv = NAT_HASH_FN(j, 0, 0xffffffff); 688 1.1 christos } else { 689 1.3 darrenr ipf_inet_mask_add(0, &softn->ipf_nat_map_mask); 690 1.1 christos j = 0; 691 1.1 christos rhv = 0; 692 1.1 christos } 693 1.1 christos hv = rhv % softn->ipf_nat_maprules_sz; 694 1.1 christos np = softn->ipf_nat_map_rules + hv; 695 1.1 christos while (*np != NULL) 696 1.1 christos np = &(*np)->in_mnext; 697 1.1 christos n->in_mnext = NULL; 698 1.1 christos n->in_pmnext = np; 699 1.1 christos n->in_hv[1] = rhv; 700 1.3 darrenr n->in_use++; 701 1.1 christos *np = n; 702 1.1 christos } 703 1.1 christos 704 1.1 christos 705 1.1 christos /* ------------------------------------------------------------------------ */ 706 1.1 christos /* Function: ipf_nat_delrdr */ 707 1.1 christos /* Returns: Nil */ 708 1.1 christos /* Parameters: n(I) - pointer to NAT rule to delete */ 709 1.1 christos /* */ 710 1.1 christos /* Removes a redirect rule from the hash table of redirect rules. */ 711 1.1 christos /* ------------------------------------------------------------------------ */ 712 1.1 christos void 713 1.2 christos ipf_nat_delrdr(ipf_nat_softc_t *softn, ipnat_t *n) 714 1.1 christos { 715 1.1 christos if (n->in_odstatype == FRI_NORMAL) { 716 1.1 christos int k = count4bits(n->in_odstmsk); 717 1.3 darrenr ipf_inet_mask_del(k, &softn->ipf_nat_rdr_mask); 718 1.1 christos } else { 719 1.3 darrenr ipf_inet_mask_del(0, &softn->ipf_nat_rdr_mask); 720 1.1 christos } 721 1.1 christos if (n->in_rnext) 722 1.1 christos n->in_rnext->in_prnext = n->in_prnext; 723 1.1 christos *n->in_prnext = n->in_rnext; 724 1.3 darrenr n->in_use--; 725 1.1 christos } 726 1.1 christos 727 1.1 christos 728 1.1 christos /* ------------------------------------------------------------------------ */ 729 1.1 christos /* Function: ipf_nat_delmap */ 730 1.1 christos /* Returns: Nil */ 731 1.1 christos /* Parameters: n(I) - pointer to NAT rule to delete */ 732 1.1 christos /* */ 733 1.1 christos /* Removes a NAT map rule from the hash table of NAT map rules. */ 734 1.1 christos /* ------------------------------------------------------------------------ */ 735 1.1 christos void 736 1.2 christos ipf_nat_delmap(ipf_nat_softc_t *softn, ipnat_t *n) 737 1.1 christos { 738 1.1 christos if (n->in_osrcatype == FRI_NORMAL) { 739 1.1 christos int k = count4bits(n->in_osrcmsk); 740 1.3 darrenr ipf_inet_mask_del(k, &softn->ipf_nat_map_mask); 741 1.1 christos } else { 742 1.3 darrenr ipf_inet_mask_del(0, &softn->ipf_nat_map_mask); 743 1.1 christos } 744 1.1 christos if (n->in_mnext != NULL) 745 1.1 christos n->in_mnext->in_pmnext = n->in_pmnext; 746 1.1 christos *n->in_pmnext = n->in_mnext; 747 1.3 darrenr n->in_use--; 748 1.1 christos } 749 1.1 christos 750 1.1 christos 751 1.1 christos /* ------------------------------------------------------------------------ */ 752 1.1 christos /* Function: ipf_nat_hostmap */ 753 1.1 christos /* Returns: struct hostmap* - NULL if no hostmap could be created, */ 754 1.1 christos /* else a pointer to the hostmapping to use */ 755 1.1 christos /* Parameters: np(I) - pointer to NAT rule */ 756 1.1 christos /* real(I) - real IP address */ 757 1.1 christos /* map(I) - mapped IP address */ 758 1.1 christos /* port(I) - destination port number */ 759 1.1 christos /* Write Locks: ipf_nat */ 760 1.1 christos /* */ 761 1.1 christos /* Check if an ip address has already been allocated for a given mapping */ 762 1.1 christos /* that is not doing port based translation. If is not yet allocated, then */ 763 1.1 christos /* create a new entry if a non-NULL NAT rule pointer has been supplied. */ 764 1.1 christos /* ------------------------------------------------------------------------ */ 765 1.1 christos static struct hostmap * 766 1.2 christos ipf_nat_hostmap(ipf_nat_softc_t *softn, ipnat_t *np, struct in_addr src, 767 1.2 christos struct in_addr dst, struct in_addr map, u_32_t port) 768 1.1 christos { 769 1.1 christos hostmap_t *hm; 770 1.1 christos u_int hv, rhv; 771 1.1 christos 772 1.1 christos hv = (src.s_addr ^ dst.s_addr); 773 1.1 christos hv += src.s_addr; 774 1.1 christos hv += dst.s_addr; 775 1.1 christos rhv = hv; 776 1.1 christos hv %= softn->ipf_nat_hostmap_sz; 777 1.1 christos for (hm = softn->ipf_hm_maptable[hv]; hm; hm = hm->hm_hnext) 778 1.1 christos if ((hm->hm_osrcip.s_addr == src.s_addr) && 779 1.1 christos (hm->hm_odstip.s_addr == dst.s_addr) && 780 1.1 christos ((np == NULL) || (np == hm->hm_ipnat)) && 781 1.1 christos ((port == 0) || (port == hm->hm_port))) { 782 1.1 christos softn->ipf_nat_stats.ns_hm_addref++; 783 1.1 christos hm->hm_ref++; 784 1.1 christos return hm; 785 1.1 christos } 786 1.1 christos 787 1.1 christos if (np == NULL) { 788 1.1 christos softn->ipf_nat_stats.ns_hm_nullnp++; 789 1.1 christos return NULL; 790 1.1 christos } 791 1.1 christos 792 1.1 christos KMALLOC(hm, hostmap_t *); 793 1.1 christos if (hm) { 794 1.1 christos hm->hm_next = softn->ipf_hm_maplist; 795 1.1 christos hm->hm_pnext = &softn->ipf_hm_maplist; 796 1.1 christos if (softn->ipf_hm_maplist != NULL) 797 1.1 christos softn->ipf_hm_maplist->hm_pnext = &hm->hm_next; 798 1.1 christos softn->ipf_hm_maplist = hm; 799 1.1 christos hm->hm_hnext = softn->ipf_hm_maptable[hv]; 800 1.1 christos hm->hm_phnext = softn->ipf_hm_maptable + hv; 801 1.1 christos if (softn->ipf_hm_maptable[hv] != NULL) 802 1.1 christos softn->ipf_hm_maptable[hv]->hm_phnext = &hm->hm_hnext; 803 1.1 christos softn->ipf_hm_maptable[hv] = hm; 804 1.1 christos hm->hm_ipnat = np; 805 1.3 darrenr np->in_use++; 806 1.1 christos hm->hm_osrcip = src; 807 1.1 christos hm->hm_odstip = dst; 808 1.1 christos hm->hm_nsrcip = map; 809 1.1 christos hm->hm_ndstip.s_addr = 0; 810 1.1 christos hm->hm_ref = 1; 811 1.1 christos hm->hm_port = port; 812 1.1 christos hm->hm_hv = rhv; 813 1.1 christos hm->hm_v = 4; 814 1.1 christos softn->ipf_nat_stats.ns_hm_new++; 815 1.1 christos } else { 816 1.1 christos softn->ipf_nat_stats.ns_hm_newfail++; 817 1.1 christos } 818 1.1 christos return hm; 819 1.1 christos } 820 1.1 christos 821 1.1 christos 822 1.1 christos /* ------------------------------------------------------------------------ */ 823 1.1 christos /* Function: ipf_nat_hostmapdel */ 824 1.1 christos /* Returns: Nil */ 825 1.1 christos /* Parameters: hmp(I) - pointer to hostmap structure pointer */ 826 1.1 christos /* Write Locks: ipf_nat */ 827 1.1 christos /* */ 828 1.1 christos /* Decrement the references to this hostmap structure by one. If this */ 829 1.1 christos /* reaches zero then remove it and free it. */ 830 1.1 christos /* ------------------------------------------------------------------------ */ 831 1.1 christos void 832 1.3 darrenr ipf_nat_hostmapdel(ipf_main_softc_t *softc, struct hostmap **hmp) 833 1.1 christos { 834 1.1 christos struct hostmap *hm; 835 1.1 christos 836 1.1 christos hm = *hmp; 837 1.1 christos *hmp = NULL; 838 1.1 christos 839 1.1 christos hm->hm_ref--; 840 1.1 christos if (hm->hm_ref == 0) { 841 1.3 darrenr ipf_nat_rule_deref(softc, &hm->hm_ipnat); 842 1.1 christos if (hm->hm_hnext) 843 1.1 christos hm->hm_hnext->hm_phnext = hm->hm_phnext; 844 1.1 christos *hm->hm_phnext = hm->hm_hnext; 845 1.1 christos if (hm->hm_next) 846 1.1 christos hm->hm_next->hm_pnext = hm->hm_pnext; 847 1.1 christos *hm->hm_pnext = hm->hm_next; 848 1.1 christos KFREE(hm); 849 1.1 christos } 850 1.1 christos } 851 1.1 christos 852 1.1 christos 853 1.1 christos /* ------------------------------------------------------------------------ */ 854 1.1 christos /* Function: ipf_fix_outcksum */ 855 1.1 christos /* Returns: Nil */ 856 1.1 christos /* Parameters: fin(I) - pointer to packet information */ 857 1.1 christos /* sp(I) - location of 16bit checksum to update */ 858 1.1 christos /* n((I) - amount to adjust checksum by */ 859 1.1 christos /* */ 860 1.1 christos /* Adjusts the 16bit checksum by "n" for packets going out. */ 861 1.1 christos /* ------------------------------------------------------------------------ */ 862 1.1 christos void 863 1.3 darrenr ipf_fix_outcksum(int cksum, u_short *sp, u_32_t n, u_32_t partial) 864 1.1 christos { 865 1.1 christos u_short sumshort; 866 1.1 christos u_32_t sum1; 867 1.1 christos 868 1.1 christos if (n == 0) 869 1.1 christos return; 870 1.1 christos 871 1.3 darrenr if (cksum == 4) { 872 1.3 darrenr *sp = 0; 873 1.1 christos return; 874 1.3 darrenr } 875 1.3 darrenr if (cksum == 2) { 876 1.3 darrenr sum1 = partial; 877 1.3 darrenr sum1 = (sum1 & 0xffff) + (sum1 >> 16); 878 1.3 darrenr *sp = htons(sum1); 879 1.1 christos return; 880 1.1 christos } 881 1.1 christos sum1 = (~ntohs(*sp)) & 0xffff; 882 1.1 christos sum1 += (n); 883 1.1 christos sum1 = (sum1 >> 16) + (sum1 & 0xffff); 884 1.1 christos /* Again */ 885 1.1 christos sum1 = (sum1 >> 16) + (sum1 & 0xffff); 886 1.1 christos sumshort = ~(u_short)sum1; 887 1.1 christos *(sp) = htons(sumshort); 888 1.1 christos } 889 1.1 christos 890 1.1 christos 891 1.1 christos /* ------------------------------------------------------------------------ */ 892 1.1 christos /* Function: ipf_fix_incksum */ 893 1.1 christos /* Returns: Nil */ 894 1.1 christos /* Parameters: fin(I) - pointer to packet information */ 895 1.1 christos /* sp(I) - location of 16bit checksum to update */ 896 1.1 christos /* n((I) - amount to adjust checksum by */ 897 1.1 christos /* */ 898 1.1 christos /* Adjusts the 16bit checksum by "n" for packets going in. */ 899 1.1 christos /* ------------------------------------------------------------------------ */ 900 1.1 christos void 901 1.3 darrenr ipf_fix_incksum(int cksum, u_short *sp, u_32_t n, u_32_t partial) 902 1.1 christos { 903 1.1 christos u_short sumshort; 904 1.1 christos u_32_t sum1; 905 1.1 christos 906 1.1 christos if (n == 0) 907 1.1 christos return; 908 1.1 christos 909 1.3 darrenr if (cksum == 4) { 910 1.3 darrenr *sp = 0; 911 1.1 christos return; 912 1.1 christos } 913 1.3 darrenr if (cksum == 2) { 914 1.3 darrenr sum1 = partial; 915 1.3 darrenr sum1 = (sum1 & 0xffff) + (sum1 >> 16); 916 1.3 darrenr *sp = htons(sum1); 917 1.3 darrenr return; 918 1.3 darrenr } 919 1.3 darrenr 920 1.1 christos sum1 = (~ntohs(*sp)) & 0xffff; 921 1.1 christos sum1 += ~(n) & 0xffff; 922 1.1 christos sum1 = (sum1 >> 16) + (sum1 & 0xffff); 923 1.1 christos /* Again */ 924 1.1 christos sum1 = (sum1 >> 16) + (sum1 & 0xffff); 925 1.1 christos sumshort = ~(u_short)sum1; 926 1.1 christos *(sp) = htons(sumshort); 927 1.1 christos } 928 1.1 christos 929 1.1 christos 930 1.1 christos /* ------------------------------------------------------------------------ */ 931 1.1 christos /* Function: ipf_fix_datacksum */ 932 1.1 christos /* Returns: Nil */ 933 1.1 christos /* Parameters: sp(I) - location of 16bit checksum to update */ 934 1.1 christos /* n((I) - amount to adjust checksum by */ 935 1.1 christos /* */ 936 1.1 christos /* Fix_datacksum is used *only* for the adjustments of checksums in the */ 937 1.1 christos /* data section of an IP packet. */ 938 1.1 christos /* */ 939 1.1 christos /* The only situation in which you need to do this is when NAT'ing an */ 940 1.1 christos /* ICMP error message. Such a message, contains in its body the IP header */ 941 1.1 christos /* of the original IP packet, that causes the error. */ 942 1.1 christos /* */ 943 1.1 christos /* You can't use fix_incksum or fix_outcksum in that case, because for the */ 944 1.1 christos /* kernel the data section of the ICMP error is just data, and no special */ 945 1.1 christos /* processing like hardware cksum or ntohs processing have been done by the */ 946 1.1 christos /* kernel on the data section. */ 947 1.1 christos /* ------------------------------------------------------------------------ */ 948 1.1 christos void 949 1.2 christos ipf_fix_datacksum(u_short *sp, u_32_t n) 950 1.1 christos { 951 1.1 christos u_short sumshort; 952 1.1 christos u_32_t sum1; 953 1.1 christos 954 1.1 christos if (n == 0) 955 1.1 christos return; 956 1.1 christos 957 1.1 christos sum1 = (~ntohs(*sp)) & 0xffff; 958 1.1 christos sum1 += (n); 959 1.1 christos sum1 = (sum1 >> 16) + (sum1 & 0xffff); 960 1.1 christos /* Again */ 961 1.1 christos sum1 = (sum1 >> 16) + (sum1 & 0xffff); 962 1.1 christos sumshort = ~(u_short)sum1; 963 1.1 christos *(sp) = htons(sumshort); 964 1.1 christos } 965 1.1 christos 966 1.1 christos 967 1.1 christos /* ------------------------------------------------------------------------ */ 968 1.1 christos /* Function: ipf_nat_ioctl */ 969 1.1 christos /* Returns: int - 0 == success, != 0 == failure */ 970 1.3 darrenr /* Parameters: softc(I) - pointer to soft context main structure */ 971 1.3 darrenr /* data(I) - pointer to ioctl data */ 972 1.3 darrenr /* cmd(I) - ioctl command integer */ 973 1.3 darrenr /* mode(I) - file mode bits used with open */ 974 1.3 darrenr /* uid(I) - uid of calling process */ 975 1.3 darrenr /* ctx(I) - pointer used as key for finding context */ 976 1.1 christos /* */ 977 1.1 christos /* Processes an ioctl call made to operate on the IP Filter NAT device. */ 978 1.1 christos /* ------------------------------------------------------------------------ */ 979 1.1 christos int 980 1.2 christos ipf_nat_ioctl(ipf_main_softc_t *softc, void *data, ioctlcmd_t cmd, int mode, 981 1.2 christos int uid, void *ctx) 982 1.1 christos { 983 1.1 christos ipf_nat_softc_t *softn = softc->ipf_nat_soft; 984 1.1 christos int error = 0, ret, arg, getlock; 985 1.3 darrenr ipnat_t *nat, *nt, *n; 986 1.22 jdolecek ipnat_t *natd = NULL; 987 1.1 christos SPL_INT(s); 988 1.1 christos 989 1.1 christos #if BSD_GE_YEAR(199306) && defined(_KERNEL) 990 1.1 christos # if NETBSD_GE_REV(399002000) 991 1.25 christos if ((mode & FWRITE) && kauth_authorize_network( 992 1.25 christos kauth_cred_get(), KAUTH_NETWORK_FIREWALL, 993 1.25 christos KAUTH_REQ_NETWORK_FIREWALL_FW, NULL, NULL, NULL)) 994 1.1 christos # else 995 1.1 christos # if defined(__FreeBSD_version) && (__FreeBSD_version >= 500034) 996 1.1 christos if (securelevel_ge(curthread->td_ucred, 3) && (mode & FWRITE)) 997 1.1 christos # else 998 1.1 christos if ((securelevel >= 3) && (mode & FWRITE)) 999 1.1 christos # endif 1000 1.1 christos # endif 1001 1.1 christos { 1002 1.1 christos IPFERROR(60001); 1003 1.1 christos return EPERM; 1004 1.1 christos } 1005 1.1 christos #endif 1006 1.1 christos 1007 1.1 christos #if defined(__osf__) && defined(_KERNEL) 1008 1.1 christos getlock = 0; 1009 1.1 christos #else 1010 1.1 christos getlock = (mode & NAT_LOCKHELD) ? 0 : 1; 1011 1.1 christos #endif 1012 1.1 christos 1013 1.3 darrenr n = NULL; 1014 1.1 christos nt = NULL; 1015 1.3 darrenr nat = NULL; 1016 1.1 christos 1017 1.3 darrenr if ((cmd == (ioctlcmd_t)SIOCADNAT) || (cmd == (ioctlcmd_t)SIOCRMNAT) || 1018 1.3 darrenr (cmd == (ioctlcmd_t)SIOCPURGENAT)) { 1019 1.22 jdolecek KMALLOC(natd, ipnat_t *); 1020 1.22 jdolecek if (natd == NULL) { 1021 1.22 jdolecek error = ENOMEM; 1022 1.22 jdolecek goto done; 1023 1.22 jdolecek } 1024 1.1 christos if (mode & NAT_SYSSPACE) { 1025 1.22 jdolecek bcopy(data, natd, sizeof(*natd)); 1026 1.22 jdolecek nat = natd; 1027 1.1 christos error = 0; 1028 1.1 christos } else { 1029 1.22 jdolecek bzero(natd, sizeof(*natd)); 1030 1.22 jdolecek error = ipf_inobj(softc, data, NULL, natd, 1031 1.1 christos IPFOBJ_IPNAT); 1032 1.1 christos if (error != 0) 1033 1.1 christos goto done; 1034 1.1 christos 1035 1.22 jdolecek if (natd->in_size < sizeof(ipnat_t)) { 1036 1.1 christos error = EINVAL; 1037 1.1 christos goto done; 1038 1.1 christos } 1039 1.22 jdolecek KMALLOCS(nt, ipnat_t *, natd->in_size); 1040 1.1 christos if (nt == NULL) { 1041 1.1 christos IPFERROR(60070); 1042 1.1 christos error = ENOMEM; 1043 1.1 christos goto done; 1044 1.1 christos } 1045 1.22 jdolecek bzero(nt, natd->in_size); 1046 1.1 christos error = ipf_inobjsz(softc, data, nt, IPFOBJ_IPNAT, 1047 1.22 jdolecek natd->in_size); 1048 1.1 christos if (error) 1049 1.1 christos goto done; 1050 1.1 christos nat = nt; 1051 1.1 christos } 1052 1.1 christos 1053 1.1 christos /* 1054 1.1 christos * For add/delete, look to see if the NAT entry is 1055 1.1 christos * already present 1056 1.1 christos */ 1057 1.1 christos nat->in_flags &= IPN_USERFLAGS; 1058 1.1 christos if ((nat->in_redir & NAT_MAPBLK) == 0) { 1059 1.1 christos if (nat->in_osrcatype == FRI_NORMAL || 1060 1.1 christos nat->in_osrcatype == FRI_NONE) 1061 1.1 christos nat->in_osrcaddr &= nat->in_osrcmsk; 1062 1.1 christos if (nat->in_odstatype == FRI_NORMAL || 1063 1.1 christos nat->in_odstatype == FRI_NONE) 1064 1.1 christos nat->in_odstaddr &= nat->in_odstmsk; 1065 1.1 christos if ((nat->in_flags & (IPN_SPLIT|IPN_SIPRANGE)) == 0) { 1066 1.1 christos if (nat->in_nsrcatype == FRI_NORMAL) 1067 1.1 christos nat->in_nsrcaddr &= nat->in_nsrcmsk; 1068 1.1 christos if (nat->in_ndstatype == FRI_NORMAL) 1069 1.1 christos nat->in_ndstaddr &= nat->in_ndstmsk; 1070 1.1 christos } 1071 1.1 christos } 1072 1.3 darrenr 1073 1.3 darrenr error = ipf_nat_rule_init(softc, softn, nat); 1074 1.3 darrenr if (error != 0) 1075 1.3 darrenr goto done; 1076 1.3 darrenr 1077 1.1 christos MUTEX_ENTER(&softn->ipf_nat_io); 1078 1.3 darrenr for (n = softn->ipf_nat_list; n != NULL; n = n->in_next) 1079 1.2 christos if (ipf_nat_cmp_rules(nat, n) == 0) 1080 1.1 christos break; 1081 1.1 christos } 1082 1.1 christos 1083 1.1 christos switch (cmd) 1084 1.1 christos { 1085 1.1 christos #ifdef IPFILTER_LOG 1086 1.1 christos case SIOCIPFFB : 1087 1.1 christos { 1088 1.1 christos int tmp; 1089 1.1 christos 1090 1.1 christos if (!(mode & FWRITE)) { 1091 1.1 christos IPFERROR(60002); 1092 1.1 christos error = EPERM; 1093 1.1 christos } else { 1094 1.1 christos tmp = ipf_log_clear(softc, IPL_LOGNAT); 1095 1.1 christos error = BCOPYOUT(&tmp, data, sizeof(tmp)); 1096 1.1 christos if (error != 0) { 1097 1.1 christos IPFERROR(60057); 1098 1.1 christos error = EFAULT; 1099 1.1 christos } 1100 1.1 christos } 1101 1.1 christos break; 1102 1.1 christos } 1103 1.1 christos 1104 1.1 christos case SIOCSETLG : 1105 1.1 christos if (!(mode & FWRITE)) { 1106 1.1 christos IPFERROR(60003); 1107 1.1 christos error = EPERM; 1108 1.1 christos } else { 1109 1.1 christos error = BCOPYIN(data, &softn->ipf_nat_logging, 1110 1.1 christos sizeof(softn->ipf_nat_logging)); 1111 1.1 christos if (error != 0) 1112 1.1 christos error = EFAULT; 1113 1.1 christos } 1114 1.1 christos break; 1115 1.1 christos 1116 1.1 christos case SIOCGETLG : 1117 1.1 christos error = BCOPYOUT(&softn->ipf_nat_logging, data, 1118 1.1 christos sizeof(softn->ipf_nat_logging)); 1119 1.1 christos if (error != 0) { 1120 1.1 christos IPFERROR(60004); 1121 1.1 christos error = EFAULT; 1122 1.1 christos } 1123 1.1 christos break; 1124 1.1 christos 1125 1.1 christos case FIONREAD : 1126 1.1 christos arg = ipf_log_bytesused(softc, IPL_LOGNAT); 1127 1.1 christos error = BCOPYOUT(&arg, data, sizeof(arg)); 1128 1.1 christos if (error != 0) { 1129 1.1 christos IPFERROR(60005); 1130 1.1 christos error = EFAULT; 1131 1.1 christos } 1132 1.1 christos break; 1133 1.1 christos #endif 1134 1.1 christos case SIOCADNAT : 1135 1.1 christos if (!(mode & FWRITE)) { 1136 1.1 christos IPFERROR(60006); 1137 1.1 christos error = EPERM; 1138 1.1 christos } else if (n != NULL) { 1139 1.22 jdolecek KMALLOC(natd, ipnat_t *); 1140 1.22 jdolecek if (natd == NULL) { 1141 1.22 jdolecek error = ENOMEM; 1142 1.22 jdolecek goto done; 1143 1.22 jdolecek } 1144 1.22 jdolecek bzero(natd, sizeof(*natd)); 1145 1.22 jdolecek natd->in_flineno = n->in_flineno; 1146 1.3 darrenr (void) ipf_outobj(softc, data, &natd, IPFOBJ_IPNAT); 1147 1.1 christos IPFERROR(60007); 1148 1.1 christos error = EEXIST; 1149 1.1 christos } else if (nt == NULL) { 1150 1.1 christos IPFERROR(60008); 1151 1.1 christos error = ENOMEM; 1152 1.1 christos } 1153 1.1 christos if (error != 0) { 1154 1.1 christos MUTEX_EXIT(&softn->ipf_nat_io); 1155 1.1 christos break; 1156 1.1 christos } 1157 1.1 christos if (nat != nt) 1158 1.1 christos bcopy((char *)nat, (char *)nt, sizeof(*n)); 1159 1.3 darrenr error = ipf_nat_siocaddnat(softc, softn, nt, getlock); 1160 1.1 christos MUTEX_EXIT(&softn->ipf_nat_io); 1161 1.3 darrenr if (error == 0) { 1162 1.3 darrenr nat = NULL; 1163 1.1 christos nt = NULL; 1164 1.3 darrenr } 1165 1.1 christos break; 1166 1.1 christos 1167 1.1 christos case SIOCRMNAT : 1168 1.3 darrenr case SIOCPURGENAT : 1169 1.1 christos if (!(mode & FWRITE)) { 1170 1.1 christos IPFERROR(60009); 1171 1.1 christos error = EPERM; 1172 1.1 christos n = NULL; 1173 1.1 christos } else if (n == NULL) { 1174 1.1 christos IPFERROR(60010); 1175 1.1 christos error = ESRCH; 1176 1.1 christos } 1177 1.1 christos 1178 1.1 christos if (error != 0) { 1179 1.1 christos MUTEX_EXIT(&softn->ipf_nat_io); 1180 1.1 christos break; 1181 1.1 christos } 1182 1.3 darrenr if (cmd == (ioctlcmd_t)SIOCPURGENAT) { 1183 1.3 darrenr error = ipf_outobjsz(softc, data, n, IPFOBJ_IPNAT, 1184 1.3 darrenr n->in_size); 1185 1.3 darrenr if (error) { 1186 1.3 darrenr MUTEX_EXIT(&softn->ipf_nat_io); 1187 1.3 darrenr goto done; 1188 1.3 darrenr } 1189 1.3 darrenr n->in_flags |= IPN_PURGE; 1190 1.3 darrenr } 1191 1.3 darrenr ipf_nat_siocdelnat(softc, softn, n, getlock); 1192 1.1 christos 1193 1.1 christos MUTEX_EXIT(&softn->ipf_nat_io); 1194 1.1 christos n = NULL; 1195 1.1 christos break; 1196 1.1 christos 1197 1.1 christos case SIOCGNATS : 1198 1.1 christos { 1199 1.1 christos natstat_t *nsp = &softn->ipf_nat_stats; 1200 1.1 christos 1201 1.1 christos nsp->ns_side[0].ns_table = softn->ipf_nat_table[0]; 1202 1.1 christos nsp->ns_side[1].ns_table = softn->ipf_nat_table[1]; 1203 1.1 christos nsp->ns_list = softn->ipf_nat_list; 1204 1.1 christos nsp->ns_maptable = softn->ipf_hm_maptable; 1205 1.1 christos nsp->ns_maplist = softn->ipf_hm_maplist; 1206 1.1 christos nsp->ns_nattab_sz = softn->ipf_nat_table_sz; 1207 1.1 christos nsp->ns_nattab_max = softn->ipf_nat_table_max; 1208 1.1 christos nsp->ns_rultab_sz = softn->ipf_nat_maprules_sz; 1209 1.1 christos nsp->ns_rdrtab_sz = softn->ipf_nat_rdrrules_sz; 1210 1.1 christos nsp->ns_hostmap_sz = softn->ipf_nat_hostmap_sz; 1211 1.1 christos nsp->ns_instances = softn->ipf_nat_instances; 1212 1.1 christos nsp->ns_ticks = softc->ipf_ticks; 1213 1.1 christos #ifdef IPFILTER_LOGGING 1214 1.1 christos nsp->ns_log_ok = ipf_log_logok(softc, IPF_LOGNAT); 1215 1.1 christos nsp->ns_log_fail = ipf_log_failures(softc, IPF_LOGNAT); 1216 1.1 christos #else 1217 1.1 christos nsp->ns_log_ok = 0; 1218 1.1 christos nsp->ns_log_fail = 0; 1219 1.1 christos #endif 1220 1.1 christos error = ipf_outobj(softc, data, nsp, IPFOBJ_NATSTAT); 1221 1.1 christos break; 1222 1.1 christos } 1223 1.1 christos 1224 1.1 christos case SIOCGNATL : 1225 1.1 christos { 1226 1.1 christos natlookup_t nl; 1227 1.1 christos 1228 1.1 christos error = ipf_inobj(softc, data, NULL, &nl, IPFOBJ_NATLOOKUP); 1229 1.1 christos if (error == 0) { 1230 1.1 christos void *ptr; 1231 1.1 christos 1232 1.1 christos if (getlock) { 1233 1.1 christos READ_ENTER(&softc->ipf_nat); 1234 1.1 christos } 1235 1.1 christos 1236 1.1 christos switch (nl.nl_v) 1237 1.1 christos { 1238 1.1 christos case 4 : 1239 1.14 prlw1 ptr = ipf_nat_lookupredir(softc, &nl); 1240 1.1 christos break; 1241 1.1 christos #ifdef USE_INET6 1242 1.1 christos case 6 : 1243 1.14 prlw1 ptr = ipf_nat6_lookupredir(softc, &nl); 1244 1.1 christos break; 1245 1.1 christos #endif 1246 1.1 christos default: 1247 1.1 christos ptr = NULL; 1248 1.1 christos break; 1249 1.1 christos } 1250 1.1 christos 1251 1.1 christos if (getlock) { 1252 1.1 christos RWLOCK_EXIT(&softc->ipf_nat); 1253 1.1 christos } 1254 1.1 christos if (ptr != NULL) { 1255 1.1 christos error = ipf_outobj(softc, data, &nl, 1256 1.1 christos IPFOBJ_NATLOOKUP); 1257 1.1 christos } else { 1258 1.1 christos IPFERROR(60011); 1259 1.1 christos error = ESRCH; 1260 1.1 christos } 1261 1.1 christos } 1262 1.1 christos break; 1263 1.1 christos } 1264 1.1 christos 1265 1.1 christos case SIOCIPFFL : /* old SIOCFLNAT & SIOCCNATL */ 1266 1.1 christos if (!(mode & FWRITE)) { 1267 1.1 christos IPFERROR(60012); 1268 1.1 christos error = EPERM; 1269 1.1 christos break; 1270 1.1 christos } 1271 1.1 christos if (getlock) { 1272 1.1 christos WRITE_ENTER(&softc->ipf_nat); 1273 1.1 christos } 1274 1.1 christos 1275 1.1 christos error = BCOPYIN(data, &arg, sizeof(arg)); 1276 1.1 christos if (error != 0) { 1277 1.1 christos IPFERROR(60013); 1278 1.1 christos error = EFAULT; 1279 1.1 christos } else { 1280 1.1 christos if (arg == 0) 1281 1.1 christos ret = ipf_nat_flushtable(softc, softn); 1282 1.1 christos else if (arg == 1) 1283 1.1 christos ret = ipf_nat_clearlist(softc, softn); 1284 1.1 christos else 1285 1.1 christos ret = ipf_nat_extraflush(softc, softn, arg); 1286 1.1 christos ipf_proxy_flush(softc->ipf_proxy_soft, arg); 1287 1.1 christos } 1288 1.1 christos 1289 1.1 christos if (getlock) { 1290 1.1 christos RWLOCK_EXIT(&softc->ipf_nat); 1291 1.1 christos } 1292 1.1 christos if (error == 0) { 1293 1.1 christos error = BCOPYOUT(&ret, data, sizeof(ret)); 1294 1.1 christos } 1295 1.1 christos break; 1296 1.1 christos 1297 1.1 christos case SIOCMATCHFLUSH : 1298 1.1 christos if (!(mode & FWRITE)) { 1299 1.1 christos IPFERROR(60014); 1300 1.1 christos error = EPERM; 1301 1.1 christos break; 1302 1.1 christos } 1303 1.1 christos if (getlock) { 1304 1.1 christos WRITE_ENTER(&softc->ipf_nat); 1305 1.1 christos } 1306 1.1 christos 1307 1.1 christos error = ipf_nat_matchflush(softc, softn, data); 1308 1.1 christos 1309 1.1 christos if (getlock) { 1310 1.1 christos RWLOCK_EXIT(&softc->ipf_nat); 1311 1.1 christos } 1312 1.1 christos break; 1313 1.1 christos 1314 1.1 christos case SIOCPROXY : 1315 1.1 christos error = ipf_proxy_ioctl(softc, data, cmd, mode, ctx); 1316 1.1 christos break; 1317 1.1 christos 1318 1.1 christos case SIOCSTLCK : 1319 1.1 christos if (!(mode & FWRITE)) { 1320 1.1 christos IPFERROR(60015); 1321 1.1 christos error = EPERM; 1322 1.1 christos } else { 1323 1.1 christos error = ipf_lock(data, &softn->ipf_nat_lock); 1324 1.1 christos } 1325 1.1 christos break; 1326 1.1 christos 1327 1.1 christos case SIOCSTPUT : 1328 1.1 christos if ((mode & FWRITE) != 0) { 1329 1.1 christos error = ipf_nat_putent(softc, data, getlock); 1330 1.1 christos } else { 1331 1.1 christos IPFERROR(60016); 1332 1.1 christos error = EACCES; 1333 1.1 christos } 1334 1.1 christos break; 1335 1.1 christos 1336 1.1 christos case SIOCSTGSZ : 1337 1.1 christos if (softn->ipf_nat_lock) { 1338 1.1 christos error = ipf_nat_getsz(softc, data, getlock); 1339 1.1 christos } else { 1340 1.1 christos IPFERROR(60017); 1341 1.1 christos error = EACCES; 1342 1.1 christos } 1343 1.1 christos break; 1344 1.1 christos 1345 1.1 christos case SIOCSTGET : 1346 1.1 christos if (softn->ipf_nat_lock) { 1347 1.1 christos error = ipf_nat_getent(softc, data, getlock); 1348 1.1 christos } else { 1349 1.1 christos IPFERROR(60018); 1350 1.1 christos error = EACCES; 1351 1.1 christos } 1352 1.1 christos break; 1353 1.1 christos 1354 1.1 christos case SIOCGENITER : 1355 1.1 christos { 1356 1.1 christos ipfgeniter_t iter; 1357 1.1 christos ipftoken_t *token; 1358 1.1 christos ipfobj_t obj; 1359 1.1 christos 1360 1.1 christos error = ipf_inobj(softc, data, &obj, &iter, IPFOBJ_GENITER); 1361 1.1 christos if (error != 0) 1362 1.1 christos break; 1363 1.1 christos 1364 1.1 christos SPL_SCHED(s); 1365 1.1 christos token = ipf_token_find(softc, iter.igi_type, uid, ctx); 1366 1.1 christos if (token != NULL) { 1367 1.1 christos error = ipf_nat_iterator(softc, token, &iter, &obj); 1368 1.1 christos WRITE_ENTER(&softc->ipf_tokens); 1369 1.3 darrenr ipf_token_deref(softc, token); 1370 1.1 christos RWLOCK_EXIT(&softc->ipf_tokens); 1371 1.1 christos } 1372 1.1 christos SPL_X(s); 1373 1.1 christos break; 1374 1.1 christos } 1375 1.1 christos 1376 1.1 christos case SIOCIPFDELTOK : 1377 1.1 christos error = BCOPYIN(data, &arg, sizeof(arg)); 1378 1.1 christos if (error == 0) { 1379 1.1 christos SPL_SCHED(s); 1380 1.1 christos error = ipf_token_del(softc, arg, uid, ctx); 1381 1.1 christos SPL_X(s); 1382 1.1 christos } else { 1383 1.1 christos IPFERROR(60019); 1384 1.1 christos error = EFAULT; 1385 1.1 christos } 1386 1.1 christos break; 1387 1.1 christos 1388 1.1 christos case SIOCGTQTAB : 1389 1.1 christos error = ipf_outobj(softc, data, softn->ipf_nat_tcptq, 1390 1.1 christos IPFOBJ_STATETQTAB); 1391 1.1 christos break; 1392 1.1 christos 1393 1.1 christos case SIOCGTABL : 1394 1.1 christos error = ipf_nat_gettable(softc, softn, data); 1395 1.1 christos break; 1396 1.1 christos 1397 1.1 christos default : 1398 1.1 christos IPFERROR(60020); 1399 1.1 christos error = EINVAL; 1400 1.1 christos break; 1401 1.1 christos } 1402 1.1 christos done: 1403 1.3 darrenr if (nat != NULL) 1404 1.3 darrenr ipf_nat_rule_fini(softc, nat); 1405 1.22 jdolecek if (natd != NULL) 1406 1.22 jdolecek KFREE(natd); 1407 1.1 christos if (nt != NULL) 1408 1.1 christos KFREES(nt, nt->in_size); 1409 1.1 christos return error; 1410 1.1 christos } 1411 1.1 christos 1412 1.1 christos 1413 1.1 christos /* ------------------------------------------------------------------------ */ 1414 1.1 christos /* Function: ipf_nat_siocaddnat */ 1415 1.1 christos /* Returns: int - 0 == success, != 0 == failure */ 1416 1.3 darrenr /* Parameters: softc(I) - pointer to soft context main structure */ 1417 1.3 darrenr /* softn(I) - pointer to NAT context structure */ 1418 1.3 darrenr /* n(I) - pointer to new NAT rule */ 1419 1.1 christos /* np(I) - pointer to where to insert new NAT rule */ 1420 1.1 christos /* getlock(I) - flag indicating if lock on is held */ 1421 1.3 darrenr /* Mutex Locks: ipf_nat_io */ 1422 1.1 christos /* */ 1423 1.1 christos /* Handle SIOCADNAT. Resolve and calculate details inside the NAT rule */ 1424 1.1 christos /* from information passed to the kernel, then add it to the appropriate */ 1425 1.1 christos /* NAT rule table(s). */ 1426 1.1 christos /* ------------------------------------------------------------------------ */ 1427 1.1 christos static int 1428 1.3 darrenr ipf_nat_siocaddnat(ipf_main_softc_t *softc, ipf_nat_softc_t *softn, ipnat_t *n, 1429 1.3 darrenr int getlock) 1430 1.1 christos { 1431 1.1 christos int error = 0; 1432 1.1 christos 1433 1.1 christos if (ipf_nat_resolverule(softc, n) != 0) { 1434 1.1 christos IPFERROR(60022); 1435 1.1 christos return ENOENT; 1436 1.1 christos } 1437 1.1 christos 1438 1.1 christos if ((n->in_age[0] == 0) && (n->in_age[1] != 0)) { 1439 1.1 christos IPFERROR(60023); 1440 1.1 christos return EINVAL; 1441 1.1 christos } 1442 1.1 christos 1443 1.1 christos if (n->in_redir == (NAT_DIVERTUDP|NAT_MAP)) { 1444 1.1 christos /* 1445 1.1 christos * Prerecord whether or not the destination of the divert 1446 1.1 christos * is local or not to the interface the packet is going 1447 1.1 christos * to be sent out. 1448 1.1 christos */ 1449 1.1 christos n->in_dlocal = ipf_deliverlocal(softc, n->in_v[1], 1450 1.1 christos n->in_ifps[1], &n->in_ndstip6); 1451 1.1 christos } 1452 1.1 christos 1453 1.1 christos if (getlock) { 1454 1.1 christos WRITE_ENTER(&softc->ipf_nat); 1455 1.1 christos } 1456 1.1 christos n->in_next = NULL; 1457 1.3 darrenr n->in_pnext = softn->ipf_nat_list_tail; 1458 1.3 darrenr *n->in_pnext = n; 1459 1.3 darrenr softn->ipf_nat_list_tail = &n->in_next; 1460 1.3 darrenr n->in_use++; 1461 1.1 christos 1462 1.1 christos if (n->in_redir & NAT_REDIRECT) { 1463 1.1 christos n->in_flags &= ~IPN_NOTDST; 1464 1.1 christos switch (n->in_v[0]) 1465 1.1 christos { 1466 1.1 christos case 4 : 1467 1.1 christos ipf_nat_addrdr(softn, n); 1468 1.1 christos break; 1469 1.1 christos #ifdef USE_INET6 1470 1.1 christos case 6 : 1471 1.1 christos ipf_nat6_addrdr(softn, n); 1472 1.1 christos break; 1473 1.1 christos #endif 1474 1.1 christos default : 1475 1.1 christos break; 1476 1.1 christos } 1477 1.1 christos ATOMIC_INC32(softn->ipf_nat_stats.ns_rules_rdr); 1478 1.1 christos } 1479 1.1 christos 1480 1.1 christos if (n->in_redir & (NAT_MAP|NAT_MAPBLK)) { 1481 1.1 christos n->in_flags &= ~IPN_NOTSRC; 1482 1.1 christos switch (n->in_v[0]) 1483 1.1 christos { 1484 1.1 christos case 4 : 1485 1.1 christos ipf_nat_addmap(softn, n); 1486 1.1 christos break; 1487 1.1 christos #ifdef USE_INET6 1488 1.1 christos case 6 : 1489 1.1 christos ipf_nat6_addmap(softn, n); 1490 1.1 christos break; 1491 1.1 christos #endif 1492 1.1 christos default : 1493 1.1 christos break; 1494 1.1 christos } 1495 1.1 christos ATOMIC_INC32(softn->ipf_nat_stats.ns_rules_map); 1496 1.1 christos } 1497 1.1 christos 1498 1.1 christos if (n->in_age[0] != 0) 1499 1.1 christos n->in_tqehead[0] = ipf_addtimeoutqueue(softc, 1500 1.1 christos &softn->ipf_nat_utqe, 1501 1.1 christos n->in_age[0]); 1502 1.1 christos 1503 1.1 christos if (n->in_age[1] != 0) 1504 1.1 christos n->in_tqehead[1] = ipf_addtimeoutqueue(softc, 1505 1.1 christos &softn->ipf_nat_utqe, 1506 1.1 christos n->in_age[1]); 1507 1.1 christos 1508 1.1 christos MUTEX_INIT(&n->in_lock, "ipnat rule lock"); 1509 1.1 christos 1510 1.1 christos n = NULL; 1511 1.1 christos ATOMIC_INC32(softn->ipf_nat_stats.ns_rules); 1512 1.1 christos #if SOLARIS && !defined(INSTANCES) 1513 1.1 christos pfil_delayed_copy = 0; 1514 1.1 christos #endif 1515 1.1 christos if (getlock) { 1516 1.1 christos RWLOCK_EXIT(&softc->ipf_nat); /* WRITE */ 1517 1.1 christos } 1518 1.1 christos 1519 1.1 christos return error; 1520 1.1 christos } 1521 1.1 christos 1522 1.1 christos 1523 1.3 darrenr /* ------------------------------------------------------------------------ */ 1524 1.3 darrenr /* Function: ipf_nat_ruleaddrinit */ 1525 1.3 darrenr /* Parameters: softc(I) - pointer to soft context main structure */ 1526 1.3 darrenr /* softn(I) - pointer to NAT context structure */ 1527 1.3 darrenr /* n(I) - pointer to NAT rule */ 1528 1.3 darrenr /* */ 1529 1.3 darrenr /* Initialise all of the NAT address structures in a NAT rule. */ 1530 1.3 darrenr /* ------------------------------------------------------------------------ */ 1531 1.1 christos static int 1532 1.2 christos ipf_nat_ruleaddrinit(ipf_main_softc_t *softc, ipf_nat_softc_t *softn, 1533 1.2 christos ipnat_t *n) 1534 1.1 christos { 1535 1.1 christos int idx, error; 1536 1.1 christos 1537 1.3 darrenr if ((n->in_ndst.na_atype == FRI_LOOKUP) && 1538 1.3 darrenr (n->in_ndst.na_type != IPLT_DSTLIST)) { 1539 1.3 darrenr IPFERROR(60071); 1540 1.3 darrenr return EINVAL; 1541 1.3 darrenr } 1542 1.3 darrenr if ((n->in_nsrc.na_atype == FRI_LOOKUP) && 1543 1.3 darrenr (n->in_nsrc.na_type != IPLT_DSTLIST)) { 1544 1.3 darrenr IPFERROR(60069); 1545 1.3 darrenr return EINVAL; 1546 1.3 darrenr } 1547 1.3 darrenr 1548 1.1 christos if (n->in_redir == NAT_BIMAP) { 1549 1.1 christos n->in_ndstaddr = n->in_osrcaddr; 1550 1.1 christos n->in_ndstmsk = n->in_osrcmsk; 1551 1.1 christos n->in_odstaddr = n->in_nsrcaddr; 1552 1.1 christos n->in_odstmsk = n->in_nsrcmsk; 1553 1.1 christos 1554 1.1 christos } 1555 1.1 christos 1556 1.1 christos if (n->in_redir & NAT_REDIRECT) 1557 1.1 christos idx = 1; 1558 1.1 christos else 1559 1.1 christos idx = 0; 1560 1.1 christos /* 1561 1.1 christos * Initialise all of the address fields. 1562 1.1 christos */ 1563 1.1 christos error = ipf_nat_nextaddrinit(softc, n->in_names, &n->in_osrc, 1, 1564 1.1 christos n->in_ifps[idx]); 1565 1.1 christos if (error != 0) 1566 1.1 christos return error; 1567 1.1 christos 1568 1.1 christos error = ipf_nat_nextaddrinit(softc, n->in_names, &n->in_odst, 1, 1569 1.1 christos n->in_ifps[idx]); 1570 1.1 christos if (error != 0) 1571 1.1 christos return error; 1572 1.1 christos 1573 1.1 christos error = ipf_nat_nextaddrinit(softc, n->in_names, &n->in_nsrc, 1, 1574 1.1 christos n->in_ifps[idx]); 1575 1.1 christos if (error != 0) 1576 1.1 christos return error; 1577 1.1 christos 1578 1.1 christos error = ipf_nat_nextaddrinit(softc, n->in_names, &n->in_ndst, 1, 1579 1.1 christos n->in_ifps[idx]); 1580 1.1 christos if (error != 0) 1581 1.1 christos return error; 1582 1.1 christos 1583 1.3 darrenr if (n->in_redir & NAT_DIVERTUDP) 1584 1.1 christos ipf_nat_builddivertmp(softn, n); 1585 1.1 christos 1586 1.1 christos return 0; 1587 1.1 christos } 1588 1.1 christos 1589 1.1 christos 1590 1.1 christos /* ------------------------------------------------------------------------ */ 1591 1.3 darrenr /* Function: ipf_nat_resolvrule */ 1592 1.1 christos /* Returns: Nil */ 1593 1.3 darrenr /* Parameters: softc(I) - pointer to soft context main structure */ 1594 1.3 darrenr /* n(I) - pointer to NAT rule */ 1595 1.1 christos /* */ 1596 1.1 christos /* Handle SIOCADNAT. Resolve and calculate details inside the NAT rule */ 1597 1.1 christos /* from information passed to the kernel, then add it to the appropriate */ 1598 1.1 christos /* NAT rule table(s). */ 1599 1.1 christos /* ------------------------------------------------------------------------ */ 1600 1.1 christos static int 1601 1.2 christos ipf_nat_resolverule(ipf_main_softc_t *softc, ipnat_t *n) 1602 1.1 christos { 1603 1.1 christos char *base; 1604 1.1 christos 1605 1.1 christos base = n->in_names; 1606 1.1 christos 1607 1.1 christos n->in_ifps[0] = ipf_resolvenic(softc, base + n->in_ifnames[0], 1608 1.1 christos n->in_v[0]); 1609 1.1 christos 1610 1.1 christos if (n->in_ifnames[1] == -1) { 1611 1.1 christos n->in_ifnames[1] = n->in_ifnames[0]; 1612 1.1 christos n->in_ifps[1] = n->in_ifps[0]; 1613 1.1 christos } else { 1614 1.1 christos n->in_ifps[1] = ipf_resolvenic(softc, base + n->in_ifnames[1], 1615 1.1 christos n->in_v[1]); 1616 1.1 christos } 1617 1.1 christos 1618 1.1 christos if (n->in_plabel != -1) { 1619 1.1 christos if (n->in_redir & NAT_REDIRECT) 1620 1.1 christos n->in_apr = ipf_proxy_lookup(softc->ipf_proxy_soft, 1621 1.1 christos n->in_pr[0], 1622 1.1 christos base + n->in_plabel); 1623 1.1 christos else 1624 1.1 christos n->in_apr = ipf_proxy_lookup(softc->ipf_proxy_soft, 1625 1.1 christos n->in_pr[1], 1626 1.1 christos base + n->in_plabel); 1627 1.1 christos if (n->in_apr == NULL) 1628 1.1 christos return -1; 1629 1.1 christos } 1630 1.1 christos return 0; 1631 1.1 christos } 1632 1.1 christos 1633 1.1 christos 1634 1.1 christos /* ------------------------------------------------------------------------ */ 1635 1.3 darrenr /* Function: ipf_nat_siocdelnat */ 1636 1.1 christos /* Returns: int - 0 == success, != 0 == failure */ 1637 1.3 darrenr /* Parameters: softc(I) - pointer to soft context main structure */ 1638 1.3 darrenr /* softn(I) - pointer to NAT context structure */ 1639 1.3 darrenr /* n(I) - pointer to new NAT rule */ 1640 1.1 christos /* getlock(I) - flag indicating if lock on is held */ 1641 1.1 christos /* Mutex Locks: ipf_nat_io */ 1642 1.1 christos /* */ 1643 1.1 christos /* Handle SIOCADNAT. Resolve and calculate details inside the NAT rule */ 1644 1.1 christos /* from information passed to the kernel, then add it to the appropriate */ 1645 1.1 christos /* NAT rule table(s). */ 1646 1.1 christos /* ------------------------------------------------------------------------ */ 1647 1.1 christos static void 1648 1.2 christos ipf_nat_siocdelnat(ipf_main_softc_t *softc, ipf_nat_softc_t *softn, ipnat_t *n, 1649 1.3 darrenr int getlock) 1650 1.1 christos { 1651 1.1 christos #ifdef IPF_NAT6 1652 1.1 christos int i; 1653 1.1 christos #endif 1654 1.1 christos 1655 1.1 christos if (getlock) { 1656 1.1 christos WRITE_ENTER(&softc->ipf_nat); 1657 1.1 christos } 1658 1.1 christos 1659 1.3 darrenr ipf_nat_delrule(softc, softn, n, 1); 1660 1.1 christos 1661 1.1 christos if (getlock) { 1662 1.1 christos RWLOCK_EXIT(&softc->ipf_nat); /* READ/WRITE */ 1663 1.1 christos } 1664 1.1 christos } 1665 1.1 christos 1666 1.1 christos 1667 1.1 christos /* ------------------------------------------------------------------------ */ 1668 1.1 christos /* Function: ipf_nat_getsz */ 1669 1.1 christos /* Returns: int - 0 == success, != 0 is the error value. */ 1670 1.3 darrenr /* Parameters: softc(I) - pointer to soft context main structure */ 1671 1.3 darrenr /* data(I) - pointer to natget structure with kernel */ 1672 1.1 christos /* pointer get the size of. */ 1673 1.1 christos /* getlock(I) - flag indicating whether or not the caller */ 1674 1.1 christos /* holds a lock on ipf_nat */ 1675 1.1 christos /* */ 1676 1.1 christos /* Handle SIOCSTGSZ. */ 1677 1.1 christos /* Return the size of the nat list entry to be copied back to user space. */ 1678 1.1 christos /* The size of the entry is stored in the ng_sz field and the enture natget */ 1679 1.1 christos /* structure is copied back to the user. */ 1680 1.1 christos /* ------------------------------------------------------------------------ */ 1681 1.1 christos static int 1682 1.2 christos ipf_nat_getsz(ipf_main_softc_t *softc, void *data, int getlock) 1683 1.1 christos { 1684 1.1 christos ipf_nat_softc_t *softn = softc->ipf_nat_soft; 1685 1.1 christos ap_session_t *aps; 1686 1.1 christos nat_t *nat, *n; 1687 1.1 christos natget_t ng; 1688 1.1 christos int error; 1689 1.1 christos 1690 1.1 christos error = BCOPYIN(data, &ng, sizeof(ng)); 1691 1.1 christos if (error != 0) { 1692 1.1 christos IPFERROR(60024); 1693 1.1 christos return EFAULT; 1694 1.1 christos } 1695 1.1 christos 1696 1.1 christos if (getlock) { 1697 1.1 christos READ_ENTER(&softc->ipf_nat); 1698 1.1 christos } 1699 1.1 christos 1700 1.1 christos nat = ng.ng_ptr; 1701 1.1 christos if (!nat) { 1702 1.1 christos nat = softn->ipf_nat_instances; 1703 1.1 christos ng.ng_sz = 0; 1704 1.1 christos /* 1705 1.1 christos * Empty list so the size returned is 0. Simple. 1706 1.1 christos */ 1707 1.1 christos if (nat == NULL) { 1708 1.1 christos if (getlock) { 1709 1.1 christos RWLOCK_EXIT(&softc->ipf_nat); 1710 1.1 christos } 1711 1.1 christos error = BCOPYOUT(&ng, data, sizeof(ng)); 1712 1.1 christos if (error != 0) { 1713 1.1 christos IPFERROR(60025); 1714 1.1 christos return EFAULT; 1715 1.1 christos } 1716 1.1 christos return 0; 1717 1.1 christos } 1718 1.1 christos } else { 1719 1.1 christos /* 1720 1.1 christos * Make sure the pointer we're copying from exists in the 1721 1.1 christos * current list of entries. Security precaution to prevent 1722 1.1 christos * copying of random kernel data. 1723 1.1 christos */ 1724 1.1 christos for (n = softn->ipf_nat_instances; n; n = n->nat_next) 1725 1.1 christos if (n == nat) 1726 1.1 christos break; 1727 1.1 christos if (n == NULL) { 1728 1.1 christos if (getlock) { 1729 1.1 christos RWLOCK_EXIT(&softc->ipf_nat); 1730 1.1 christos } 1731 1.1 christos IPFERROR(60026); 1732 1.1 christos return ESRCH; 1733 1.1 christos } 1734 1.1 christos } 1735 1.1 christos 1736 1.1 christos /* 1737 1.26 msaitoh * Include any space required for proxy data structures. 1738 1.1 christos */ 1739 1.1 christos ng.ng_sz = sizeof(nat_save_t); 1740 1.1 christos aps = nat->nat_aps; 1741 1.1 christos if (aps != NULL) { 1742 1.1 christos ng.ng_sz += sizeof(ap_session_t) - 4; 1743 1.1 christos if (aps->aps_data != 0) 1744 1.1 christos ng.ng_sz += aps->aps_psiz; 1745 1.1 christos } 1746 1.1 christos if (getlock) { 1747 1.1 christos RWLOCK_EXIT(&softc->ipf_nat); 1748 1.1 christos } 1749 1.1 christos 1750 1.1 christos error = BCOPYOUT(&ng, data, sizeof(ng)); 1751 1.1 christos if (error != 0) { 1752 1.1 christos IPFERROR(60027); 1753 1.1 christos return EFAULT; 1754 1.1 christos } 1755 1.1 christos return 0; 1756 1.1 christos } 1757 1.1 christos 1758 1.1 christos 1759 1.1 christos /* ------------------------------------------------------------------------ */ 1760 1.1 christos /* Function: ipf_nat_getent */ 1761 1.1 christos /* Returns: int - 0 == success, != 0 is the error value. */ 1762 1.3 darrenr /* Parameters: softc(I) - pointer to soft context main structure */ 1763 1.3 darrenr /* data(I) - pointer to natget structure with kernel pointer*/ 1764 1.1 christos /* to NAT structure to copy out. */ 1765 1.1 christos /* getlock(I) - flag indicating whether or not the caller */ 1766 1.1 christos /* holds a lock on ipf_nat */ 1767 1.1 christos /* */ 1768 1.1 christos /* Handle SIOCSTGET. */ 1769 1.1 christos /* Copies out NAT entry to user space. Any additional data held for a */ 1770 1.1 christos /* proxy is also copied, as to is the NAT rule which was responsible for it */ 1771 1.1 christos /* ------------------------------------------------------------------------ */ 1772 1.1 christos static int 1773 1.2 christos ipf_nat_getent(ipf_main_softc_t *softc, void *data, int getlock) 1774 1.1 christos { 1775 1.1 christos ipf_nat_softc_t *softn = softc->ipf_nat_soft; 1776 1.1 christos int error, outsize; 1777 1.1 christos ap_session_t *aps; 1778 1.1 christos nat_save_t *ipn, ipns; 1779 1.1 christos nat_t *n, *nat; 1780 1.1 christos 1781 1.1 christos error = ipf_inobj(softc, data, NULL, &ipns, IPFOBJ_NATSAVE); 1782 1.1 christos if (error != 0) 1783 1.1 christos return error; 1784 1.1 christos 1785 1.1 christos if ((ipns.ipn_dsize < sizeof(ipns)) || (ipns.ipn_dsize > 81920)) { 1786 1.1 christos IPFERROR(60028); 1787 1.1 christos return EINVAL; 1788 1.1 christos } 1789 1.1 christos 1790 1.1 christos KMALLOCS(ipn, nat_save_t *, ipns.ipn_dsize); 1791 1.1 christos if (ipn == NULL) { 1792 1.1 christos IPFERROR(60029); 1793 1.1 christos return ENOMEM; 1794 1.1 christos } 1795 1.1 christos 1796 1.1 christos if (getlock) { 1797 1.1 christos READ_ENTER(&softc->ipf_nat); 1798 1.1 christos } 1799 1.1 christos 1800 1.1 christos ipn->ipn_dsize = ipns.ipn_dsize; 1801 1.1 christos nat = ipns.ipn_next; 1802 1.1 christos if (nat == NULL) { 1803 1.1 christos nat = softn->ipf_nat_instances; 1804 1.1 christos if (nat == NULL) { 1805 1.1 christos if (softn->ipf_nat_instances == NULL) { 1806 1.1 christos IPFERROR(60030); 1807 1.1 christos error = ENOENT; 1808 1.1 christos } 1809 1.1 christos goto finished; 1810 1.1 christos } 1811 1.1 christos } else { 1812 1.1 christos /* 1813 1.1 christos * Make sure the pointer we're copying from exists in the 1814 1.1 christos * current list of entries. Security precaution to prevent 1815 1.1 christos * copying of random kernel data. 1816 1.1 christos */ 1817 1.1 christos for (n = softn->ipf_nat_instances; n; n = n->nat_next) 1818 1.1 christos if (n == nat) 1819 1.1 christos break; 1820 1.1 christos if (n == NULL) { 1821 1.1 christos IPFERROR(60031); 1822 1.1 christos error = ESRCH; 1823 1.1 christos goto finished; 1824 1.1 christos } 1825 1.1 christos } 1826 1.1 christos ipn->ipn_next = nat->nat_next; 1827 1.1 christos 1828 1.1 christos /* 1829 1.1 christos * Copy the NAT structure. 1830 1.1 christos */ 1831 1.1 christos bcopy((char *)nat, &ipn->ipn_nat, sizeof(*nat)); 1832 1.1 christos 1833 1.1 christos /* 1834 1.1 christos * If we have a pointer to the NAT rule it belongs to, save that too. 1835 1.1 christos */ 1836 1.1 christos if (nat->nat_ptr != NULL) 1837 1.1 christos bcopy((char *)nat->nat_ptr, (char *)&ipn->ipn_ipnat, 1838 1.1 christos ipn->ipn_ipnat.in_size); 1839 1.1 christos 1840 1.1 christos /* 1841 1.1 christos * If we also know the NAT entry has an associated filter rule, 1842 1.1 christos * save that too. 1843 1.1 christos */ 1844 1.1 christos if (nat->nat_fr != NULL) 1845 1.1 christos bcopy((char *)nat->nat_fr, (char *)&ipn->ipn_fr, 1846 1.1 christos sizeof(ipn->ipn_fr)); 1847 1.1 christos 1848 1.1 christos /* 1849 1.1 christos * Last but not least, if there is an application proxy session set 1850 1.1 christos * up for this NAT entry, then copy that out too, including any 1851 1.1 christos * private data saved along side it by the proxy. 1852 1.1 christos */ 1853 1.1 christos aps = nat->nat_aps; 1854 1.1 christos outsize = ipn->ipn_dsize - sizeof(*ipn) + sizeof(ipn->ipn_data); 1855 1.1 christos if (aps != NULL) { 1856 1.1 christos char *s; 1857 1.1 christos 1858 1.1 christos if (outsize < sizeof(*aps)) { 1859 1.1 christos IPFERROR(60032); 1860 1.1 christos error = ENOBUFS; 1861 1.1 christos goto finished; 1862 1.1 christos } 1863 1.1 christos 1864 1.1 christos s = ipn->ipn_data; 1865 1.1 christos bcopy((char *)aps, s, sizeof(*aps)); 1866 1.1 christos s += sizeof(*aps); 1867 1.1 christos outsize -= sizeof(*aps); 1868 1.1 christos if ((aps->aps_data != NULL) && (outsize >= aps->aps_psiz)) 1869 1.1 christos bcopy(aps->aps_data, s, aps->aps_psiz); 1870 1.1 christos else { 1871 1.1 christos IPFERROR(60033); 1872 1.1 christos error = ENOBUFS; 1873 1.1 christos } 1874 1.1 christos } 1875 1.1 christos if (error == 0) { 1876 1.1 christos if (getlock) { 1877 1.1 christos READ_ENTER(&softc->ipf_nat); 1878 1.1 christos getlock = 0; 1879 1.1 christos } 1880 1.1 christos error = ipf_outobjsz(softc, data, ipn, IPFOBJ_NATSAVE, 1881 1.1 christos ipns.ipn_dsize); 1882 1.1 christos } 1883 1.1 christos 1884 1.1 christos finished: 1885 1.1 christos if (getlock) { 1886 1.1 christos READ_ENTER(&softc->ipf_nat); 1887 1.1 christos } 1888 1.1 christos if (ipn != NULL) { 1889 1.1 christos KFREES(ipn, ipns.ipn_dsize); 1890 1.1 christos } 1891 1.1 christos return error; 1892 1.1 christos } 1893 1.1 christos 1894 1.1 christos 1895 1.1 christos /* ------------------------------------------------------------------------ */ 1896 1.1 christos /* Function: ipf_nat_putent */ 1897 1.1 christos /* Returns: int - 0 == success, != 0 is the error value. */ 1898 1.3 darrenr /* Parameters: softc(I) - pointer to soft context main structure */ 1899 1.3 darrenr /* data(I) - pointer to natget structure with NAT */ 1900 1.3 darrenr /* structure information to load into the kernel */ 1901 1.1 christos /* getlock(I) - flag indicating whether or not a write lock */ 1902 1.3 darrenr /* on is already held. */ 1903 1.1 christos /* */ 1904 1.1 christos /* Handle SIOCSTPUT. */ 1905 1.1 christos /* Loads a NAT table entry from user space, including a NAT rule, proxy and */ 1906 1.1 christos /* firewall rule data structures, if pointers to them indicate so. */ 1907 1.1 christos /* ------------------------------------------------------------------------ */ 1908 1.1 christos static int 1909 1.2 christos ipf_nat_putent(ipf_main_softc_t *softc, void *data, int getlock) 1910 1.1 christos { 1911 1.1 christos ipf_nat_softc_t *softn = softc->ipf_nat_soft; 1912 1.2 christos nat_save_t *ipn, *ipnn; 1913 1.1 christos ap_session_t *aps; 1914 1.1 christos nat_t *n, *nat; 1915 1.1 christos frentry_t *fr; 1916 1.2 christos fr_info_t *fin; 1917 1.1 christos ipnat_t *in; 1918 1.1 christos int error; 1919 1.1 christos 1920 1.2 christos KMALLOC(ipn, nat_save_t *); 1921 1.2 christos if (ipn == NULL) 1922 1.2 christos return ENOMEM; 1923 1.2 christos error = ipf_inobj(softc, data, NULL, ipn, IPFOBJ_NATSAVE); 1924 1.1 christos if (error != 0) 1925 1.1 christos return error; 1926 1.1 christos 1927 1.1 christos /* 1928 1.1 christos * Initialise early because of code at junkput label. 1929 1.1 christos */ 1930 1.1 christos n = NULL; 1931 1.1 christos in = NULL; 1932 1.1 christos aps = NULL; 1933 1.1 christos nat = NULL; 1934 1.1 christos ipnn = NULL; 1935 1.2 christos fin = NULL; 1936 1.1 christos fr = NULL; 1937 1.1 christos 1938 1.1 christos /* 1939 1.1 christos * New entry, copy in the rest of the NAT entry if it's size is more 1940 1.1 christos * than just the nat_t structure. 1941 1.1 christos */ 1942 1.2 christos if (ipn->ipn_dsize > sizeof(*ipn)) { 1943 1.2 christos if (ipn->ipn_dsize > 81920) { 1944 1.1 christos IPFERROR(60034); 1945 1.1 christos error = ENOMEM; 1946 1.1 christos goto junkput; 1947 1.1 christos } 1948 1.1 christos 1949 1.2 christos KMALLOCS(ipnn, nat_save_t *, ipn->ipn_dsize); 1950 1.1 christos if (ipnn == NULL) { 1951 1.1 christos IPFERROR(60035); 1952 1.1 christos return ENOMEM; 1953 1.1 christos } 1954 1.1 christos 1955 1.2 christos bzero(ipnn, ipn->ipn_dsize); 1956 1.1 christos error = ipf_inobjsz(softc, data, ipnn, IPFOBJ_NATSAVE, 1957 1.2 christos ipn->ipn_dsize); 1958 1.1 christos if (error != 0) { 1959 1.1 christos goto junkput; 1960 1.1 christos } 1961 1.1 christos } else 1962 1.2 christos ipnn = ipn; 1963 1.1 christos 1964 1.1 christos KMALLOC(nat, nat_t *); 1965 1.1 christos if (nat == NULL) { 1966 1.1 christos IPFERROR(60037); 1967 1.1 christos error = ENOMEM; 1968 1.1 christos goto junkput; 1969 1.1 christos } 1970 1.1 christos 1971 1.1 christos bcopy((char *)&ipnn->ipn_nat, (char *)nat, sizeof(*nat)); 1972 1.1 christos 1973 1.1 christos switch (nat->nat_v[0]) 1974 1.1 christos { 1975 1.1 christos case 4: 1976 1.1 christos #ifdef USE_IENT6 1977 1.1 christos case 6 : 1978 1.1 christos #endif 1979 1.1 christos break; 1980 1.1 christos default : 1981 1.1 christos IPFERROR(60061); 1982 1.1 christos error = EPROTONOSUPPORT; 1983 1.1 christos goto junkput; 1984 1.1 christos /*NOTREACHED*/ 1985 1.1 christos } 1986 1.1 christos 1987 1.1 christos /* 1988 1.1 christos * Initialize all these so that ipf_nat_delete() doesn't cause a crash. 1989 1.1 christos */ 1990 1.1 christos bzero((char *)nat, offsetof(struct nat, nat_tqe)); 1991 1.1 christos nat->nat_tqe.tqe_pnext = NULL; 1992 1.1 christos nat->nat_tqe.tqe_next = NULL; 1993 1.1 christos nat->nat_tqe.tqe_ifq = NULL; 1994 1.1 christos nat->nat_tqe.tqe_parent = nat; 1995 1.1 christos 1996 1.1 christos /* 1997 1.1 christos * Restore the rule associated with this nat session 1998 1.1 christos */ 1999 1.1 christos in = ipnn->ipn_nat.nat_ptr; 2000 1.1 christos if (in != NULL) { 2001 1.1 christos KMALLOCS(in, ipnat_t *, ipnn->ipn_ipnat.in_size); 2002 1.1 christos nat->nat_ptr = in; 2003 1.1 christos if (in == NULL) { 2004 1.1 christos IPFERROR(60038); 2005 1.1 christos error = ENOMEM; 2006 1.1 christos goto junkput; 2007 1.1 christos } 2008 1.1 christos bcopy((char *)&ipnn->ipn_ipnat, (char *)in, 2009 1.1 christos ipnn->ipn_ipnat.in_size); 2010 1.1 christos in->in_use = 1; 2011 1.1 christos in->in_flags |= IPN_DELETE; 2012 1.1 christos 2013 1.1 christos ATOMIC_INC32(softn->ipf_nat_stats.ns_rules); 2014 1.1 christos 2015 1.1 christos if (ipf_nat_resolverule(softc, in) != 0) { 2016 1.1 christos IPFERROR(60039); 2017 1.1 christos error = ESRCH; 2018 1.1 christos goto junkput; 2019 1.1 christos } 2020 1.1 christos } 2021 1.1 christos 2022 1.1 christos /* 2023 1.1 christos * Check that the NAT entry doesn't already exist in the kernel. 2024 1.1 christos * 2025 1.1 christos * For NAT_OUTBOUND, we're lookup for a duplicate MAP entry. To do 2026 1.1 christos * this, we check to see if the inbound combination of addresses and 2027 1.1 christos * ports is already known. Similar logic is applied for NAT_INBOUND. 2028 1.1 christos * 2029 1.1 christos */ 2030 1.2 christos KMALLOC(fin, fr_info_t *); 2031 1.2 christos if (fin == NULL) { 2032 1.2 christos error = ENOMEM; 2033 1.2 christos goto junkput; 2034 1.2 christos } 2035 1.2 christos bzero(fin, sizeof(*fin)); 2036 1.2 christos fin->fin_v = nat->nat_v[0]; 2037 1.2 christos fin->fin_p = nat->nat_pr[0]; 2038 1.2 christos fin->fin_rev = nat->nat_rev; 2039 1.2 christos fin->fin_ifp = nat->nat_ifps[0]; 2040 1.2 christos fin->fin_data[0] = ntohs(nat->nat_ndport); 2041 1.2 christos fin->fin_data[1] = ntohs(nat->nat_nsport); 2042 1.1 christos 2043 1.1 christos switch (nat->nat_dir) 2044 1.1 christos { 2045 1.1 christos case NAT_OUTBOUND : 2046 1.1 christos case NAT_DIVERTOUT : 2047 1.1 christos if (getlock) { 2048 1.1 christos READ_ENTER(&softc->ipf_nat); 2049 1.1 christos } 2050 1.1 christos 2051 1.2 christos fin->fin_v = nat->nat_v[1]; 2052 1.1 christos if (nat->nat_v[1] == 4) { 2053 1.2 christos n = ipf_nat_inlookup(fin, nat->nat_flags, fin->fin_p, 2054 1.1 christos nat->nat_ndstip, nat->nat_nsrcip); 2055 1.1 christos #ifdef USE_INET6 2056 1.1 christos } else if (nat->nat_v[1] == 6) { 2057 1.2 christos n = ipf_nat6_inlookup(fin, nat->nat_flags, fin->fin_p, 2058 1.1 christos &nat->nat_ndst6.in6, 2059 1.1 christos &nat->nat_nsrc6.in6); 2060 1.1 christos #endif 2061 1.1 christos } 2062 1.1 christos 2063 1.1 christos if (getlock) { 2064 1.1 christos RWLOCK_EXIT(&softc->ipf_nat); 2065 1.1 christos } 2066 1.1 christos if (n != NULL) { 2067 1.1 christos IPFERROR(60040); 2068 1.1 christos error = EEXIST; 2069 1.1 christos goto junkput; 2070 1.1 christos } 2071 1.1 christos break; 2072 1.1 christos 2073 1.1 christos case NAT_INBOUND : 2074 1.1 christos case NAT_DIVERTIN : 2075 1.1 christos if (getlock) { 2076 1.1 christos READ_ENTER(&softc->ipf_nat); 2077 1.1 christos } 2078 1.1 christos 2079 1.2 christos if (fin->fin_v == 4) { 2080 1.2 christos n = ipf_nat_outlookup(fin, nat->nat_flags, fin->fin_p, 2081 1.1 christos nat->nat_ndstip, 2082 1.1 christos nat->nat_nsrcip); 2083 1.1 christos #ifdef USE_INET6 2084 1.2 christos } else if (fin->fin_v == 6) { 2085 1.2 christos n = ipf_nat6_outlookup(fin, nat->nat_flags, fin->fin_p, 2086 1.1 christos &nat->nat_ndst6.in6, 2087 1.1 christos &nat->nat_nsrc6.in6); 2088 1.1 christos #endif 2089 1.1 christos } 2090 1.1 christos 2091 1.1 christos if (getlock) { 2092 1.1 christos RWLOCK_EXIT(&softc->ipf_nat); 2093 1.1 christos } 2094 1.1 christos if (n != NULL) { 2095 1.1 christos IPFERROR(60041); 2096 1.1 christos error = EEXIST; 2097 1.1 christos goto junkput; 2098 1.1 christos } 2099 1.1 christos break; 2100 1.1 christos 2101 1.1 christos default : 2102 1.1 christos IPFERROR(60042); 2103 1.1 christos error = EINVAL; 2104 1.1 christos goto junkput; 2105 1.1 christos } 2106 1.1 christos 2107 1.1 christos /* 2108 1.1 christos * Restore ap_session_t structure. Include the private data allocated 2109 1.1 christos * if it was there. 2110 1.1 christos */ 2111 1.1 christos aps = nat->nat_aps; 2112 1.1 christos if (aps != NULL) { 2113 1.1 christos KMALLOC(aps, ap_session_t *); 2114 1.1 christos nat->nat_aps = aps; 2115 1.1 christos if (aps == NULL) { 2116 1.1 christos IPFERROR(60043); 2117 1.1 christos error = ENOMEM; 2118 1.1 christos goto junkput; 2119 1.1 christos } 2120 1.1 christos bcopy(ipnn->ipn_data, (char *)aps, sizeof(*aps)); 2121 1.1 christos if (in != NULL) 2122 1.1 christos aps->aps_apr = in->in_apr; 2123 1.1 christos else 2124 1.1 christos aps->aps_apr = NULL; 2125 1.1 christos if (aps->aps_psiz != 0) { 2126 1.1 christos if (aps->aps_psiz > 81920) { 2127 1.1 christos IPFERROR(60044); 2128 1.1 christos error = ENOMEM; 2129 1.1 christos goto junkput; 2130 1.1 christos } 2131 1.1 christos KMALLOCS(aps->aps_data, void *, aps->aps_psiz); 2132 1.1 christos if (aps->aps_data == NULL) { 2133 1.1 christos IPFERROR(60045); 2134 1.1 christos error = ENOMEM; 2135 1.1 christos goto junkput; 2136 1.1 christos } 2137 1.1 christos bcopy(ipnn->ipn_data + sizeof(*aps), aps->aps_data, 2138 1.1 christos aps->aps_psiz); 2139 1.1 christos } else { 2140 1.1 christos aps->aps_psiz = 0; 2141 1.1 christos aps->aps_data = NULL; 2142 1.1 christos } 2143 1.1 christos } 2144 1.1 christos 2145 1.1 christos /* 2146 1.1 christos * If there was a filtering rule associated with this entry then 2147 1.1 christos * build up a new one. 2148 1.1 christos */ 2149 1.1 christos fr = nat->nat_fr; 2150 1.1 christos if (fr != NULL) { 2151 1.1 christos if ((nat->nat_flags & SI_NEWFR) != 0) { 2152 1.1 christos KMALLOC(fr, frentry_t *); 2153 1.1 christos nat->nat_fr = fr; 2154 1.1 christos if (fr == NULL) { 2155 1.1 christos IPFERROR(60046); 2156 1.1 christos error = ENOMEM; 2157 1.1 christos goto junkput; 2158 1.1 christos } 2159 1.1 christos ipnn->ipn_nat.nat_fr = fr; 2160 1.1 christos fr->fr_ref = 1; 2161 1.1 christos (void) ipf_outobj(softc, data, ipnn, IPFOBJ_NATSAVE); 2162 1.1 christos bcopy((char *)&ipnn->ipn_fr, (char *)fr, sizeof(*fr)); 2163 1.1 christos 2164 1.1 christos fr->fr_ref = 1; 2165 1.1 christos fr->fr_dsize = 0; 2166 1.1 christos fr->fr_data = NULL; 2167 1.1 christos fr->fr_type = FR_T_NONE; 2168 1.1 christos 2169 1.1 christos MUTEX_NUKE(&fr->fr_lock); 2170 1.1 christos MUTEX_INIT(&fr->fr_lock, "nat-filter rule lock"); 2171 1.1 christos } else { 2172 1.1 christos if (getlock) { 2173 1.1 christos READ_ENTER(&softc->ipf_nat); 2174 1.1 christos } 2175 1.1 christos for (n = softn->ipf_nat_instances; n; n = n->nat_next) 2176 1.1 christos if (n->nat_fr == fr) 2177 1.1 christos break; 2178 1.1 christos 2179 1.1 christos if (n != NULL) { 2180 1.1 christos MUTEX_ENTER(&fr->fr_lock); 2181 1.1 christos fr->fr_ref++; 2182 1.1 christos MUTEX_EXIT(&fr->fr_lock); 2183 1.1 christos } 2184 1.1 christos if (getlock) { 2185 1.1 christos RWLOCK_EXIT(&softc->ipf_nat); 2186 1.1 christos } 2187 1.1 christos 2188 1.1 christos if (n == NULL) { 2189 1.1 christos IPFERROR(60047); 2190 1.1 christos error = ESRCH; 2191 1.1 christos goto junkput; 2192 1.1 christos } 2193 1.1 christos } 2194 1.1 christos } 2195 1.1 christos 2196 1.2 christos if (ipnn != ipn) { 2197 1.2 christos KFREES(ipnn, ipn->ipn_dsize); 2198 1.1 christos ipnn = NULL; 2199 1.1 christos } 2200 1.1 christos 2201 1.1 christos if (getlock) { 2202 1.1 christos WRITE_ENTER(&softc->ipf_nat); 2203 1.1 christos } 2204 1.1 christos 2205 1.2 christos if (fin->fin_v == 4) 2206 1.2 christos error = ipf_nat_finalise(fin, nat); 2207 1.1 christos #ifdef USE_INET6 2208 1.1 christos else 2209 1.2 christos error = ipf_nat6_finalise(fin, nat); 2210 1.1 christos #endif 2211 1.1 christos 2212 1.1 christos if (getlock) { 2213 1.1 christos RWLOCK_EXIT(&softc->ipf_nat); 2214 1.1 christos } 2215 1.1 christos 2216 1.1 christos if (error == 0) 2217 1.1 christos return 0; 2218 1.1 christos 2219 1.1 christos IPFERROR(60048); 2220 1.1 christos error = ENOMEM; 2221 1.1 christos 2222 1.1 christos junkput: 2223 1.2 christos if (fin != NULL) 2224 1.2 christos KFREE(fin); 2225 1.1 christos if (fr != NULL) { 2226 1.1 christos (void) ipf_derefrule(softc, &fr); 2227 1.1 christos } 2228 1.1 christos 2229 1.2 christos if ((ipnn != NULL) && (ipnn != ipn)) { 2230 1.2 christos KFREES(ipnn, ipn->ipn_dsize); 2231 1.1 christos } 2232 1.2 christos if (ipn != NULL) 2233 1.2 christos KFREE(ipn); 2234 1.1 christos if (nat != NULL) { 2235 1.1 christos if (aps != NULL) { 2236 1.1 christos if (aps->aps_data != NULL) { 2237 1.1 christos KFREES(aps->aps_data, aps->aps_psiz); 2238 1.1 christos } 2239 1.1 christos KFREE(aps); 2240 1.1 christos } 2241 1.1 christos if (in != NULL) { 2242 1.1 christos if (in->in_apr) 2243 1.3 darrenr ipf_proxy_deref(in->in_apr); 2244 1.1 christos KFREES(in, in->in_size); 2245 1.1 christos } 2246 1.1 christos KFREE(nat); 2247 1.1 christos } 2248 1.1 christos return error; 2249 1.1 christos } 2250 1.1 christos 2251 1.1 christos 2252 1.1 christos /* ------------------------------------------------------------------------ */ 2253 1.1 christos /* Function: ipf_nat_delete */ 2254 1.1 christos /* Returns: Nil */ 2255 1.3 darrenr /* Parameters: softc(I) - pointer to soft context main structure */ 2256 1.3 darrenr /* nat(I) - pointer to NAT structure to delete */ 2257 1.1 christos /* logtype(I) - type of LOG record to create before deleting */ 2258 1.1 christos /* Write Lock: ipf_nat */ 2259 1.1 christos /* */ 2260 1.1 christos /* Delete a nat entry from the various lists and table. If NAT logging is */ 2261 1.1 christos /* enabled then generate a NAT log record for this event. */ 2262 1.1 christos /* ------------------------------------------------------------------------ */ 2263 1.1 christos void 2264 1.2 christos ipf_nat_delete(ipf_main_softc_t *softc, struct nat *nat, int logtype) 2265 1.1 christos { 2266 1.1 christos ipf_nat_softc_t *softn = softc->ipf_nat_soft; 2267 1.8 christos int madeorphan = 0, removed = 0; 2268 1.9 christos u_int bkt; 2269 1.3 darrenr nat_stat_side_t *nss; 2270 1.1 christos struct ipnat *ipn; 2271 1.1 christos 2272 1.1 christos if (logtype != 0 && softn->ipf_nat_logging != 0) 2273 1.1 christos ipf_nat_log(softc, softn, nat, logtype); 2274 1.1 christos 2275 1.1 christos /* 2276 1.1 christos * Take it as a general indication that all the pointers are set if 2277 1.1 christos * nat_pnext is set. 2278 1.1 christos */ 2279 1.1 christos if (nat->nat_pnext != NULL) { 2280 1.1 christos removed = 1; 2281 1.1 christos 2282 1.9 christos bkt = nat->nat_hv[0] % softn->ipf_nat_table_sz; 2283 1.3 darrenr nss = &softn->ipf_nat_stats.ns_side[0]; 2284 1.9 christos ASSERT(nss->ns_bucketlen[bkt] > 0); 2285 1.9 christos nss->ns_bucketlen[bkt]--; 2286 1.9 christos if (nss->ns_bucketlen[bkt] == 0) { 2287 1.3 darrenr nss->ns_inuse--; 2288 1.1 christos } 2289 1.1 christos 2290 1.9 christos bkt = nat->nat_hv[1] % softn->ipf_nat_table_sz; 2291 1.3 darrenr nss = &softn->ipf_nat_stats.ns_side[1]; 2292 1.9 christos ASSERT(nss->ns_bucketlen[bkt] > 0); 2293 1.9 christos nss->ns_bucketlen[bkt]--; 2294 1.9 christos if (nss->ns_bucketlen[bkt] == 0) { 2295 1.3 darrenr nss->ns_inuse--; 2296 1.1 christos } 2297 1.1 christos 2298 1.1 christos *nat->nat_pnext = nat->nat_next; 2299 1.1 christos if (nat->nat_next != NULL) { 2300 1.1 christos nat->nat_next->nat_pnext = nat->nat_pnext; 2301 1.1 christos nat->nat_next = NULL; 2302 1.1 christos } 2303 1.1 christos nat->nat_pnext = NULL; 2304 1.1 christos 2305 1.1 christos *nat->nat_phnext[0] = nat->nat_hnext[0]; 2306 1.1 christos if (nat->nat_hnext[0] != NULL) { 2307 1.1 christos nat->nat_hnext[0]->nat_phnext[0] = nat->nat_phnext[0]; 2308 1.1 christos nat->nat_hnext[0] = NULL; 2309 1.1 christos } 2310 1.1 christos nat->nat_phnext[0] = NULL; 2311 1.1 christos 2312 1.1 christos *nat->nat_phnext[1] = nat->nat_hnext[1]; 2313 1.1 christos if (nat->nat_hnext[1] != NULL) { 2314 1.1 christos nat->nat_hnext[1]->nat_phnext[1] = nat->nat_phnext[1]; 2315 1.1 christos nat->nat_hnext[1] = NULL; 2316 1.1 christos } 2317 1.1 christos nat->nat_phnext[1] = NULL; 2318 1.1 christos 2319 1.1 christos if ((nat->nat_flags & SI_WILDP) != 0) { 2320 1.1 christos ATOMIC_DEC32(softn->ipf_nat_stats.ns_wilds); 2321 1.1 christos } 2322 1.1 christos madeorphan = 1; 2323 1.1 christos } 2324 1.1 christos 2325 1.1 christos if (nat->nat_me != NULL) { 2326 1.1 christos *nat->nat_me = NULL; 2327 1.1 christos nat->nat_me = NULL; 2328 1.1 christos nat->nat_ref--; 2329 1.3 darrenr ASSERT(nat->nat_ref >= 0); 2330 1.1 christos } 2331 1.1 christos 2332 1.1 christos if (nat->nat_tqe.tqe_ifq != NULL) { 2333 1.1 christos /* 2334 1.1 christos * No call to ipf_freetimeoutqueue() is made here, they are 2335 1.1 christos * garbage collected in ipf_nat_expire(). 2336 1.1 christos */ 2337 1.1 christos (void) ipf_deletequeueentry(&nat->nat_tqe); 2338 1.1 christos } 2339 1.1 christos 2340 1.3 darrenr if (nat->nat_sync) { 2341 1.3 darrenr ipf_sync_del_nat(softc->ipf_sync_soft, nat->nat_sync); 2342 1.3 darrenr nat->nat_sync = NULL; 2343 1.3 darrenr } 2344 1.3 darrenr 2345 1.1 christos if (logtype == NL_EXPIRE) 2346 1.1 christos softn->ipf_nat_stats.ns_expire++; 2347 1.1 christos 2348 1.1 christos MUTEX_ENTER(&nat->nat_lock); 2349 1.1 christos /* 2350 1.1 christos * NL_DESTROY should only be passed in when we've got nat_ref >= 2. 2351 1.1 christos * This happens when a nat'd packet is blocked and we want to throw 2352 1.1 christos * away the NAT session. 2353 1.1 christos */ 2354 1.1 christos if (logtype == NL_DESTROY) { 2355 1.1 christos if (nat->nat_ref > 2) { 2356 1.1 christos nat->nat_ref -= 2; 2357 1.1 christos MUTEX_EXIT(&nat->nat_lock); 2358 1.1 christos if (removed) 2359 1.1 christos softn->ipf_nat_stats.ns_orphans++; 2360 1.1 christos return; 2361 1.1 christos } 2362 1.1 christos } else if (nat->nat_ref > 1) { 2363 1.1 christos nat->nat_ref--; 2364 1.1 christos MUTEX_EXIT(&nat->nat_lock); 2365 1.1 christos if (madeorphan == 1) 2366 1.1 christos softn->ipf_nat_stats.ns_orphans++; 2367 1.1 christos return; 2368 1.1 christos } 2369 1.3 darrenr ASSERT(nat->nat_ref >= 0); 2370 1.1 christos MUTEX_EXIT(&nat->nat_lock); 2371 1.1 christos 2372 1.1 christos nat->nat_ref = 0; 2373 1.1 christos 2374 1.1 christos if (madeorphan == 0) 2375 1.1 christos softn->ipf_nat_stats.ns_orphans--; 2376 1.1 christos 2377 1.1 christos /* 2378 1.1 christos * At this point, nat_ref can be either 0 or -1 2379 1.1 christos */ 2380 1.1 christos softn->ipf_nat_stats.ns_proto[nat->nat_pr[0]]--; 2381 1.1 christos 2382 1.1 christos if (nat->nat_fr != NULL) { 2383 1.1 christos (void) ipf_derefrule(softc, &nat->nat_fr); 2384 1.1 christos } 2385 1.1 christos 2386 1.1 christos if (nat->nat_hm != NULL) { 2387 1.3 darrenr ipf_nat_hostmapdel(softc, &nat->nat_hm); 2388 1.1 christos } 2389 1.1 christos 2390 1.1 christos /* 2391 1.1 christos * If there is an active reference from the nat entry to its parent 2392 1.1 christos * rule, decrement the rule's reference count and free it too if no 2393 1.1 christos * longer being used. 2394 1.1 christos */ 2395 1.1 christos ipn = nat->nat_ptr; 2396 1.1 christos nat->nat_ptr = NULL; 2397 1.1 christos 2398 1.1 christos if (ipn != NULL) { 2399 1.3 darrenr ipn->in_space++; 2400 1.3 darrenr ipf_nat_rule_deref(softc, &ipn); 2401 1.3 darrenr } 2402 1.3 darrenr 2403 1.3 darrenr if (nat->nat_aps != NULL) { 2404 1.3 darrenr ipf_proxy_free(softc, nat->nat_aps); 2405 1.3 darrenr nat->nat_aps = NULL; 2406 1.1 christos } 2407 1.1 christos 2408 1.1 christos MUTEX_DESTROY(&nat->nat_lock); 2409 1.1 christos 2410 1.1 christos softn->ipf_nat_stats.ns_active--; 2411 1.1 christos 2412 1.1 christos /* 2413 1.1 christos * If there's a fragment table entry too for this nat entry, then 2414 1.1 christos * dereference that as well. This is after nat_lock is released 2415 1.1 christos * because of Tru64. 2416 1.1 christos */ 2417 1.1 christos ipf_frag_natforget(softc, (void *)nat); 2418 1.1 christos 2419 1.1 christos KFREE(nat); 2420 1.1 christos } 2421 1.1 christos 2422 1.1 christos 2423 1.1 christos /* ------------------------------------------------------------------------ */ 2424 1.1 christos /* Function: ipf_nat_flushtable */ 2425 1.1 christos /* Returns: int - number of NAT rules deleted */ 2426 1.3 darrenr /* Parameters: softc(I) - pointer to soft context main structure */ 2427 1.3 darrenr /* softn(I) - pointer to NAT context structure */ 2428 1.1 christos /* Write Lock: ipf_nat */ 2429 1.1 christos /* */ 2430 1.1 christos /* Deletes all currently active NAT sessions. In deleting each NAT entry a */ 2431 1.1 christos /* log record should be emitted in ipf_nat_delete() if NAT logging is */ 2432 1.1 christos /* enabled. */ 2433 1.1 christos /* ------------------------------------------------------------------------ */ 2434 1.1 christos /* 2435 1.1 christos * nat_flushtable - clear the NAT table of all mapping entries. 2436 1.1 christos */ 2437 1.1 christos static int 2438 1.2 christos ipf_nat_flushtable(ipf_main_softc_t *softc, ipf_nat_softc_t *softn) 2439 1.1 christos { 2440 1.1 christos nat_t *nat; 2441 1.1 christos int j = 0; 2442 1.1 christos 2443 1.1 christos /* 2444 1.1 christos * ALL NAT mappings deleted, so lets just make the deletions 2445 1.1 christos * quicker. 2446 1.1 christos */ 2447 1.1 christos if (softn->ipf_nat_table[0] != NULL) 2448 1.1 christos bzero((char *)softn->ipf_nat_table[0], 2449 1.1 christos sizeof(softn->ipf_nat_table[0]) * 2450 1.1 christos softn->ipf_nat_table_sz); 2451 1.1 christos if (softn->ipf_nat_table[1] != NULL) 2452 1.1 christos bzero((char *)softn->ipf_nat_table[1], 2453 1.1 christos sizeof(softn->ipf_nat_table[1]) * 2454 1.1 christos softn->ipf_nat_table_sz); 2455 1.1 christos 2456 1.1 christos while ((nat = softn->ipf_nat_instances) != NULL) { 2457 1.1 christos ipf_nat_delete(softc, nat, NL_FLUSH); 2458 1.1 christos j++; 2459 1.1 christos } 2460 1.1 christos 2461 1.1 christos return j; 2462 1.1 christos } 2463 1.1 christos 2464 1.1 christos 2465 1.1 christos /* ------------------------------------------------------------------------ */ 2466 1.1 christos /* Function: ipf_nat_clearlist */ 2467 1.1 christos /* Returns: int - number of NAT/RDR rules deleted */ 2468 1.3 darrenr /* Parameters: softc(I) - pointer to soft context main structure */ 2469 1.3 darrenr /* softn(I) - pointer to NAT context structure */ 2470 1.1 christos /* */ 2471 1.1 christos /* Delete all rules in the current list of rules. There is nothing elegant */ 2472 1.1 christos /* about this cleanup: simply free all entries on the list of rules and */ 2473 1.1 christos /* clear out the tables used for hashed NAT rule lookups. */ 2474 1.1 christos /* ------------------------------------------------------------------------ */ 2475 1.1 christos static int 2476 1.2 christos ipf_nat_clearlist(ipf_main_softc_t *softc, ipf_nat_softc_t *softn) 2477 1.1 christos { 2478 1.3 darrenr ipnat_t *n; 2479 1.1 christos int i = 0; 2480 1.1 christos 2481 1.1 christos if (softn->ipf_nat_map_rules != NULL) { 2482 1.1 christos bzero((char *)softn->ipf_nat_map_rules, 2483 1.1 christos sizeof(*softn->ipf_nat_map_rules) * 2484 1.1 christos softn->ipf_nat_maprules_sz); 2485 1.1 christos } 2486 1.1 christos if (softn->ipf_nat_rdr_rules != NULL) { 2487 1.1 christos bzero((char *)softn->ipf_nat_rdr_rules, 2488 1.1 christos sizeof(*softn->ipf_nat_rdr_rules) * 2489 1.1 christos softn->ipf_nat_rdrrules_sz); 2490 1.1 christos } 2491 1.1 christos 2492 1.3 darrenr while ((n = softn->ipf_nat_list) != NULL) { 2493 1.3 darrenr ipf_nat_delrule(softc, softn, n, 0); 2494 1.1 christos i++; 2495 1.1 christos } 2496 1.1 christos #if SOLARIS && !defined(INSTANCES) 2497 1.1 christos pfil_delayed_copy = 1; 2498 1.1 christos #endif 2499 1.1 christos return i; 2500 1.1 christos } 2501 1.1 christos 2502 1.1 christos 2503 1.1 christos /* ------------------------------------------------------------------------ */ 2504 1.1 christos /* Function: ipf_nat_delrule */ 2505 1.1 christos /* Returns: Nil */ 2506 1.3 darrenr /* Parameters: softc(I) - pointer to soft context main structure */ 2507 1.3 darrenr /* softn(I) - pointer to NAT context structure */ 2508 1.3 darrenr /* np(I) - pointer to NAT rule to delete */ 2509 1.3 darrenr /* purge(I) - 1 == allow purge, 0 == prevent purge */ 2510 1.3 darrenr /* Locks: WRITE(ipf_nat) */ 2511 1.3 darrenr /* */ 2512 1.3 darrenr /* Preventing "purge" from occuring is allowed because when all of the NAT */ 2513 1.3 darrenr /* rules are being removed, allowing the "purge" to walk through the list */ 2514 1.3 darrenr /* of NAT sessions, possibly multiple times, would be a large performance */ 2515 1.3 darrenr /* hit, on the order of O(N^2). */ 2516 1.1 christos /* ------------------------------------------------------------------------ */ 2517 1.3 darrenr static void 2518 1.3 darrenr ipf_nat_delrule(ipf_main_softc_t *softc, ipf_nat_softc_t *softn, ipnat_t *np, 2519 1.3 darrenr int purge) 2520 1.1 christos { 2521 1.3 darrenr 2522 1.3 darrenr if (np->in_pnext != NULL) { 2523 1.3 darrenr *np->in_pnext = np->in_next; 2524 1.3 darrenr if (np->in_next != NULL) 2525 1.3 darrenr np->in_next->in_pnext = np->in_pnext; 2526 1.3 darrenr if (softn->ipf_nat_list_tail == &np->in_next) 2527 1.3 darrenr softn->ipf_nat_list_tail = np->in_pnext; 2528 1.3 darrenr } 2529 1.3 darrenr 2530 1.3 darrenr if ((purge == 1) && ((np->in_flags & IPN_PURGE) != 0)) { 2531 1.3 darrenr nat_t *next; 2532 1.3 darrenr nat_t *nat; 2533 1.3 darrenr 2534 1.3 darrenr for (next = softn->ipf_nat_instances; (nat = next) != NULL;) { 2535 1.3 darrenr next = nat->nat_next; 2536 1.3 darrenr if (nat->nat_ptr == np) 2537 1.3 darrenr ipf_nat_delete(softc, nat, NL_PURGE); 2538 1.3 darrenr } 2539 1.3 darrenr } 2540 1.3 darrenr 2541 1.3 darrenr if ((np->in_flags & IPN_DELETE) == 0) { 2542 1.3 darrenr if (np->in_redir & NAT_REDIRECT) { 2543 1.3 darrenr switch (np->in_v[0]) 2544 1.3 darrenr { 2545 1.3 darrenr case 4 : 2546 1.3 darrenr ipf_nat_delrdr(softn, np); 2547 1.3 darrenr break; 2548 1.6 pgoyette #ifdef USE_INET6 2549 1.3 darrenr case 6 : 2550 1.3 darrenr ipf_nat6_delrdr(softn, np); 2551 1.3 darrenr break; 2552 1.6 pgoyette #endif 2553 1.3 darrenr } 2554 1.3 darrenr } 2555 1.3 darrenr if (np->in_redir & (NAT_MAPBLK|NAT_MAP)) { 2556 1.3 darrenr switch (np->in_v[0]) 2557 1.3 darrenr { 2558 1.3 darrenr case 4 : 2559 1.3 darrenr ipf_nat_delmap(softn, np); 2560 1.3 darrenr break; 2561 1.6 pgoyette #ifdef USE_INET6 2562 1.3 darrenr case 6 : 2563 1.3 darrenr ipf_nat6_delmap(softn, np); 2564 1.3 darrenr break; 2565 1.6 pgoyette #endif 2566 1.3 darrenr } 2567 1.3 darrenr } 2568 1.1 christos } 2569 1.1 christos 2570 1.3 darrenr np->in_flags |= IPN_DELETE; 2571 1.3 darrenr ipf_nat_rule_deref(softc, &np); 2572 1.1 christos } 2573 1.1 christos 2574 1.1 christos 2575 1.1 christos /* ------------------------------------------------------------------------ */ 2576 1.1 christos /* Function: ipf_nat_newmap */ 2577 1.1 christos /* Returns: int - -1 == error, 0 == success */ 2578 1.1 christos /* Parameters: fin(I) - pointer to packet information */ 2579 1.1 christos /* nat(I) - pointer to NAT entry */ 2580 1.1 christos /* ni(I) - pointer to structure with misc. information needed */ 2581 1.1 christos /* to create new NAT entry. */ 2582 1.1 christos /* */ 2583 1.1 christos /* Given an empty NAT structure, populate it with new information about a */ 2584 1.1 christos /* new NAT session, as defined by the matching NAT rule. */ 2585 1.1 christos /* ni.nai_ip is passed in uninitialised and must be set, in host byte order,*/ 2586 1.1 christos /* to the new IP address for the translation. */ 2587 1.1 christos /* ------------------------------------------------------------------------ */ 2588 1.1 christos static int 2589 1.2 christos ipf_nat_newmap(fr_info_t *fin, nat_t *nat, natinfo_t *ni) 2590 1.1 christos { 2591 1.1 christos ipf_main_softc_t *softc = fin->fin_main_soft; 2592 1.1 christos ipf_nat_softc_t *softn = softc->ipf_nat_soft; 2593 1.1 christos u_short st_port, dport, sport, port, sp, dp; 2594 1.1 christos struct in_addr in, inb; 2595 1.1 christos hostmap_t *hm; 2596 1.1 christos u_32_t flags; 2597 1.1 christos u_32_t st_ip; 2598 1.1 christos ipnat_t *np; 2599 1.1 christos nat_t *natl; 2600 1.1 christos int l; 2601 1.1 christos 2602 1.1 christos /* 2603 1.1 christos * If it's an outbound packet which doesn't match any existing 2604 1.1 christos * record, then create a new port 2605 1.1 christos */ 2606 1.1 christos l = 0; 2607 1.1 christos hm = NULL; 2608 1.1 christos np = ni->nai_np; 2609 1.1 christos st_ip = np->in_snip; 2610 1.1 christos st_port = np->in_spnext; 2611 1.1 christos flags = nat->nat_flags; 2612 1.1 christos 2613 1.1 christos if (flags & IPN_ICMPQUERY) { 2614 1.1 christos sport = fin->fin_data[1]; 2615 1.1 christos dport = 0; 2616 1.1 christos } else { 2617 1.1 christos sport = htons(fin->fin_data[0]); 2618 1.1 christos dport = htons(fin->fin_data[1]); 2619 1.1 christos } 2620 1.1 christos 2621 1.1 christos /* 2622 1.1 christos * Do a loop until we either run out of entries to try or we find 2623 1.1 christos * a NAT mapping that isn't currently being used. This is done 2624 1.1 christos * because the change to the source is not (usually) being fixed. 2625 1.1 christos */ 2626 1.1 christos do { 2627 1.1 christos port = 0; 2628 1.1 christos in.s_addr = htonl(np->in_snip); 2629 1.1 christos if (l == 0) { 2630 1.1 christos /* 2631 1.1 christos * Check to see if there is an existing NAT 2632 1.1 christos * setup for this IP address pair. 2633 1.1 christos */ 2634 1.1 christos hm = ipf_nat_hostmap(softn, np, fin->fin_src, 2635 1.1 christos fin->fin_dst, in, 0); 2636 1.1 christos if (hm != NULL) 2637 1.1 christos in.s_addr = hm->hm_nsrcip.s_addr; 2638 1.1 christos } else if ((l == 1) && (hm != NULL)) { 2639 1.3 darrenr ipf_nat_hostmapdel(softc, &hm); 2640 1.1 christos } 2641 1.1 christos in.s_addr = ntohl(in.s_addr); 2642 1.1 christos 2643 1.1 christos nat->nat_hm = hm; 2644 1.1 christos 2645 1.1 christos if ((np->in_nsrcmsk == 0xffffffff) && (np->in_spnext == 0)) { 2646 1.1 christos if (l > 0) { 2647 1.1 christos NBUMPSIDEX(1, ns_exhausted, ns_exhausted_1); 2648 1.1 christos return -1; 2649 1.1 christos } 2650 1.1 christos } 2651 1.1 christos 2652 1.1 christos if (np->in_redir == NAT_BIMAP && 2653 1.1 christos np->in_osrcmsk == np->in_nsrcmsk) { 2654 1.1 christos /* 2655 1.1 christos * map the address block in a 1:1 fashion 2656 1.1 christos */ 2657 1.1 christos in.s_addr = np->in_nsrcaddr; 2658 1.1 christos in.s_addr |= fin->fin_saddr & ~np->in_osrcmsk; 2659 1.1 christos in.s_addr = ntohl(in.s_addr); 2660 1.1 christos 2661 1.1 christos } else if (np->in_redir & NAT_MAPBLK) { 2662 1.1 christos if ((l >= np->in_ppip) || ((l > 0) && 2663 1.1 christos !(flags & IPN_TCPUDP))) { 2664 1.1 christos NBUMPSIDEX(1, ns_exhausted, ns_exhausted_2); 2665 1.1 christos return -1; 2666 1.1 christos } 2667 1.1 christos /* 2668 1.1 christos * map-block - Calculate destination address. 2669 1.1 christos */ 2670 1.1 christos in.s_addr = ntohl(fin->fin_saddr); 2671 1.1 christos in.s_addr &= ntohl(~np->in_osrcmsk); 2672 1.1 christos inb.s_addr = in.s_addr; 2673 1.1 christos in.s_addr /= np->in_ippip; 2674 1.1 christos in.s_addr &= ntohl(~np->in_nsrcmsk); 2675 1.1 christos in.s_addr += ntohl(np->in_nsrcaddr); 2676 1.1 christos /* 2677 1.1 christos * Calculate destination port. 2678 1.1 christos */ 2679 1.1 christos if ((flags & IPN_TCPUDP) && 2680 1.1 christos (np->in_ppip != 0)) { 2681 1.1 christos port = ntohs(sport) + l; 2682 1.1 christos port %= np->in_ppip; 2683 1.1 christos port += np->in_ppip * 2684 1.1 christos (inb.s_addr % np->in_ippip); 2685 1.1 christos port += MAPBLK_MINPORT; 2686 1.1 christos port = htons(port); 2687 1.1 christos } 2688 1.1 christos 2689 1.1 christos } else if ((np->in_nsrcaddr == 0) && 2690 1.1 christos (np->in_nsrcmsk == 0xffffffff)) { 2691 1.1 christos i6addr_t in6; 2692 1.1 christos 2693 1.1 christos /* 2694 1.1 christos * 0/32 - use the interface's IP address. 2695 1.1 christos */ 2696 1.1 christos if ((l > 0) || 2697 1.1 christos ipf_ifpaddr(softc, 4, FRI_NORMAL, fin->fin_ifp, 2698 1.1 christos &in6, NULL) == -1) { 2699 1.1 christos NBUMPSIDEX(1, ns_new_ifpaddr, ns_new_ifpaddr_1); 2700 1.1 christos return -1; 2701 1.1 christos } 2702 1.1 christos in.s_addr = ntohl(in6.in4.s_addr); 2703 1.1 christos 2704 1.1 christos } else if ((np->in_nsrcaddr == 0) && (np->in_nsrcmsk == 0)) { 2705 1.1 christos /* 2706 1.1 christos * 0/0 - use the original source address/port. 2707 1.1 christos */ 2708 1.1 christos if (l > 0) { 2709 1.1 christos NBUMPSIDEX(1, ns_exhausted, ns_exhausted_3); 2710 1.1 christos return -1; 2711 1.1 christos } 2712 1.1 christos in.s_addr = ntohl(fin->fin_saddr); 2713 1.1 christos 2714 1.1 christos } else if ((np->in_nsrcmsk != 0xffffffff) && 2715 1.1 christos (np->in_spnext == 0) && ((l > 0) || (hm == NULL))) 2716 1.1 christos np->in_snip++; 2717 1.1 christos 2718 1.1 christos natl = NULL; 2719 1.1 christos 2720 1.1 christos if ((flags & IPN_TCPUDP) && 2721 1.1 christos ((np->in_redir & NAT_MAPBLK) == 0) && 2722 1.1 christos (np->in_flags & IPN_AUTOPORTMAP)) { 2723 1.1 christos /* 2724 1.1 christos * "ports auto" (without map-block) 2725 1.1 christos */ 2726 1.2 christos if ((l > 0) && np->in_ppip && (l % np->in_ppip == 0)) { 2727 1.2 christos if (l > np->in_space) { 2728 1.2 christos return -1; 2729 1.2 christos } else if ((l > np->in_ppip) && 2730 1.2 christos np->in_nsrcmsk != 0xffffffff) 2731 1.1 christos np->in_snip++; 2732 1.1 christos } 2733 1.1 christos if (np->in_ppip != 0) { 2734 1.1 christos port = ntohs(sport); 2735 1.1 christos port += (l % np->in_ppip); 2736 1.1 christos port %= np->in_ppip; 2737 1.1 christos port += np->in_ppip * 2738 1.1 christos (ntohl(fin->fin_saddr) % 2739 1.1 christos np->in_ippip); 2740 1.1 christos port += MAPBLK_MINPORT; 2741 1.1 christos port = htons(port); 2742 1.1 christos } 2743 1.1 christos 2744 1.1 christos } else if (((np->in_redir & NAT_MAPBLK) == 0) && 2745 1.1 christos (flags & IPN_TCPUDPICMP) && (np->in_spnext != 0)) { 2746 1.1 christos /* 2747 1.1 christos * Standard port translation. Select next port. 2748 1.1 christos */ 2749 1.1 christos if (np->in_flags & IPN_SEQUENTIAL) { 2750 1.1 christos port = np->in_spnext; 2751 1.1 christos } else { 2752 1.1 christos port = ipf_random() % (np->in_spmax - 2753 1.1 christos np->in_spmin + 1); 2754 1.1 christos port += np->in_spmin; 2755 1.1 christos } 2756 1.1 christos port = htons(port); 2757 1.1 christos np->in_spnext++; 2758 1.1 christos 2759 1.1 christos if (np->in_spnext > np->in_spmax) { 2760 1.1 christos np->in_spnext = np->in_spmin; 2761 1.1 christos if (np->in_nsrcmsk != 0xffffffff) 2762 1.1 christos np->in_snip++; 2763 1.1 christos } 2764 1.1 christos } 2765 1.1 christos 2766 1.1 christos if (np->in_flags & IPN_SIPRANGE) { 2767 1.1 christos if (np->in_snip > ntohl(np->in_nsrcmsk)) 2768 1.1 christos np->in_snip = ntohl(np->in_nsrcaddr); 2769 1.1 christos } else { 2770 1.1 christos if ((np->in_nsrcmsk != 0xffffffff) && 2771 1.1 christos ((np->in_snip + 1) & ntohl(np->in_nsrcmsk)) > 2772 1.1 christos ntohl(np->in_nsrcaddr)) 2773 1.1 christos np->in_snip = ntohl(np->in_nsrcaddr) + 1; 2774 1.1 christos } 2775 1.1 christos 2776 1.1 christos if ((port == 0) && (flags & (IPN_TCPUDPICMP|IPN_ICMPQUERY))) 2777 1.1 christos port = sport; 2778 1.1 christos 2779 1.1 christos /* 2780 1.1 christos * Here we do a lookup of the connection as seen from 2781 1.1 christos * the outside. If an IP# pair already exists, try 2782 1.1 christos * again. So if you have A->B becomes C->B, you can 2783 1.1 christos * also have D->E become C->E but not D->B causing 2784 1.1 christos * another C->B. Also take protocol and ports into 2785 1.1 christos * account when determining whether a pre-existing 2786 1.1 christos * NAT setup will cause an external conflict where 2787 1.1 christos * this is appropriate. 2788 1.1 christos */ 2789 1.1 christos inb.s_addr = htonl(in.s_addr); 2790 1.1 christos sp = fin->fin_data[0]; 2791 1.1 christos dp = fin->fin_data[1]; 2792 1.1 christos fin->fin_data[0] = fin->fin_data[1]; 2793 1.1 christos fin->fin_data[1] = ntohs(port); 2794 1.1 christos natl = ipf_nat_inlookup(fin, flags & ~(SI_WILDP|NAT_SEARCH), 2795 1.1 christos (u_int)fin->fin_p, fin->fin_dst, inb); 2796 1.1 christos fin->fin_data[0] = sp; 2797 1.1 christos fin->fin_data[1] = dp; 2798 1.1 christos 2799 1.1 christos /* 2800 1.1 christos * Has the search wrapped around and come back to the 2801 1.1 christos * start ? 2802 1.1 christos */ 2803 1.1 christos if ((natl != NULL) && 2804 1.1 christos (np->in_spnext != 0) && (st_port == np->in_spnext) && 2805 1.1 christos (np->in_snip != 0) && (st_ip == np->in_snip)) { 2806 1.1 christos NBUMPSIDED(1, ns_wrap); 2807 1.1 christos return -1; 2808 1.1 christos } 2809 1.1 christos l++; 2810 1.1 christos } while (natl != NULL); 2811 1.1 christos 2812 1.1 christos /* Setup the NAT table */ 2813 1.1 christos nat->nat_osrcip = fin->fin_src; 2814 1.1 christos nat->nat_nsrcaddr = htonl(in.s_addr); 2815 1.1 christos nat->nat_odstip = fin->fin_dst; 2816 1.1 christos nat->nat_ndstip = fin->fin_dst; 2817 1.1 christos if (nat->nat_hm == NULL) 2818 1.1 christos nat->nat_hm = ipf_nat_hostmap(softn, np, fin->fin_src, 2819 1.1 christos fin->fin_dst, nat->nat_nsrcip, 2820 1.1 christos 0); 2821 1.1 christos 2822 1.1 christos if (flags & IPN_TCPUDP) { 2823 1.1 christos nat->nat_osport = sport; 2824 1.1 christos nat->nat_nsport = port; /* sport */ 2825 1.1 christos nat->nat_odport = dport; 2826 1.1 christos nat->nat_ndport = dport; 2827 1.1 christos ((tcphdr_t *)fin->fin_dp)->th_sport = port; 2828 1.1 christos } else if (flags & IPN_ICMPQUERY) { 2829 1.1 christos nat->nat_oicmpid = fin->fin_data[1]; 2830 1.1 christos ((icmphdr_t *)fin->fin_dp)->icmp_id = port; 2831 1.1 christos nat->nat_nicmpid = port; 2832 1.1 christos } 2833 1.1 christos return 0; 2834 1.1 christos } 2835 1.1 christos 2836 1.1 christos 2837 1.1 christos /* ------------------------------------------------------------------------ */ 2838 1.1 christos /* Function: ipf_nat_newrdr */ 2839 1.1 christos /* Returns: int - -1 == error, 0 == success (no move), 1 == success and */ 2840 1.1 christos /* allow rule to be moved if IPN_ROUNDR is set. */ 2841 1.1 christos /* Parameters: fin(I) - pointer to packet information */ 2842 1.1 christos /* nat(I) - pointer to NAT entry */ 2843 1.1 christos /* ni(I) - pointer to structure with misc. information needed */ 2844 1.1 christos /* to create new NAT entry. */ 2845 1.1 christos /* */ 2846 1.1 christos /* ni.nai_ip is passed in uninitialised and must be set, in host byte order,*/ 2847 1.1 christos /* to the new IP address for the translation. */ 2848 1.1 christos /* ------------------------------------------------------------------------ */ 2849 1.1 christos static int 2850 1.2 christos ipf_nat_newrdr(fr_info_t *fin, nat_t *nat, natinfo_t *ni) 2851 1.1 christos { 2852 1.1 christos ipf_main_softc_t *softc = fin->fin_main_soft; 2853 1.1 christos ipf_nat_softc_t *softn = softc->ipf_nat_soft; 2854 1.1 christos u_short nport, dport, sport; 2855 1.1 christos struct in_addr in, inb; 2856 1.1 christos u_short sp, dp; 2857 1.1 christos hostmap_t *hm; 2858 1.1 christos u_32_t flags; 2859 1.1 christos ipnat_t *np; 2860 1.1 christos nat_t *natl; 2861 1.1 christos int move; 2862 1.1 christos 2863 1.1 christos move = 1; 2864 1.1 christos hm = NULL; 2865 1.1 christos in.s_addr = 0; 2866 1.1 christos np = ni->nai_np; 2867 1.1 christos flags = nat->nat_flags; 2868 1.1 christos 2869 1.1 christos if (flags & IPN_ICMPQUERY) { 2870 1.1 christos dport = fin->fin_data[1]; 2871 1.1 christos sport = 0; 2872 1.1 christos } else { 2873 1.1 christos sport = htons(fin->fin_data[0]); 2874 1.1 christos dport = htons(fin->fin_data[1]); 2875 1.1 christos } 2876 1.1 christos 2877 1.1 christos /* TRACE sport, dport */ 2878 1.1 christos 2879 1.1 christos 2880 1.1 christos /* 2881 1.1 christos * If the matching rule has IPN_STICKY set, then we want to have the 2882 1.1 christos * same rule kick in as before. Why would this happen? If you have 2883 1.1 christos * a collection of rdr rules with "round-robin sticky", the current 2884 1.1 christos * packet might match a different one to the previous connection but 2885 1.1 christos * we want the same destination to be used. 2886 1.1 christos */ 2887 1.1 christos if (((np->in_flags & (IPN_ROUNDR|IPN_SPLIT)) != 0) && 2888 1.1 christos ((np->in_flags & IPN_STICKY) != 0)) { 2889 1.1 christos hm = ipf_nat_hostmap(softn, NULL, fin->fin_src, fin->fin_dst, 2890 1.1 christos in, (u_32_t)dport); 2891 1.1 christos if (hm != NULL) { 2892 1.1 christos in.s_addr = ntohl(hm->hm_ndstip.s_addr); 2893 1.1 christos np = hm->hm_ipnat; 2894 1.1 christos ni->nai_np = np; 2895 1.1 christos move = 0; 2896 1.3 darrenr ipf_nat_hostmapdel(softc, &hm); 2897 1.1 christos } 2898 1.1 christos } 2899 1.1 christos 2900 1.1 christos /* 2901 1.1 christos * Otherwise, it's an inbound packet. Most likely, we don't 2902 1.1 christos * want to rewrite source ports and source addresses. Instead, 2903 1.1 christos * we want to rewrite to a fixed internal address and fixed 2904 1.1 christos * internal port. 2905 1.1 christos */ 2906 1.1 christos if (np->in_flags & IPN_SPLIT) { 2907 1.1 christos in.s_addr = np->in_dnip; 2908 1.12 darrenr inb.s_addr = htonl(in.s_addr); 2909 1.1 christos 2910 1.1 christos if ((np->in_flags & (IPN_ROUNDR|IPN_STICKY)) == IPN_STICKY) { 2911 1.1 christos hm = ipf_nat_hostmap(softn, NULL, fin->fin_src, 2912 1.12 darrenr fin->fin_dst, inb, (u_32_t)dport); 2913 1.1 christos if (hm != NULL) { 2914 1.1 christos in.s_addr = hm->hm_ndstip.s_addr; 2915 1.1 christos move = 0; 2916 1.1 christos } 2917 1.1 christos } 2918 1.1 christos 2919 1.1 christos if (hm == NULL || hm->hm_ref == 1) { 2920 1.1 christos if (np->in_ndstaddr == htonl(in.s_addr)) { 2921 1.1 christos np->in_dnip = ntohl(np->in_ndstmsk); 2922 1.1 christos move = 0; 2923 1.1 christos } else { 2924 1.1 christos np->in_dnip = ntohl(np->in_ndstaddr); 2925 1.1 christos } 2926 1.1 christos } 2927 1.1 christos if (hm != NULL) 2928 1.3 darrenr ipf_nat_hostmapdel(softc, &hm); 2929 1.1 christos 2930 1.1 christos } else if ((np->in_ndstaddr == 0) && (np->in_ndstmsk == 0xffffffff)) { 2931 1.1 christos i6addr_t in6; 2932 1.1 christos 2933 1.1 christos /* 2934 1.1 christos * 0/32 - use the interface's IP address. 2935 1.1 christos */ 2936 1.1 christos if (ipf_ifpaddr(softc, 4, FRI_NORMAL, fin->fin_ifp, 2937 1.1 christos &in6, NULL) == -1) { 2938 1.1 christos NBUMPSIDEX(0, ns_new_ifpaddr, ns_new_ifpaddr_2); 2939 1.1 christos return -1; 2940 1.1 christos } 2941 1.1 christos in.s_addr = ntohl(in6.in4.s_addr); 2942 1.1 christos 2943 1.1 christos } else if ((np->in_ndstaddr == 0) && (np->in_ndstmsk== 0)) { 2944 1.1 christos /* 2945 1.1 christos * 0/0 - use the original destination address/port. 2946 1.1 christos */ 2947 1.1 christos in.s_addr = ntohl(fin->fin_daddr); 2948 1.1 christos 2949 1.1 christos } else if (np->in_redir == NAT_BIMAP && 2950 1.1 christos np->in_ndstmsk == np->in_odstmsk) { 2951 1.1 christos /* 2952 1.1 christos * map the address block in a 1:1 fashion 2953 1.1 christos */ 2954 1.1 christos in.s_addr = np->in_ndstaddr; 2955 1.1 christos in.s_addr |= fin->fin_daddr & ~np->in_ndstmsk; 2956 1.1 christos in.s_addr = ntohl(in.s_addr); 2957 1.1 christos } else { 2958 1.1 christos in.s_addr = ntohl(np->in_ndstaddr); 2959 1.1 christos } 2960 1.1 christos 2961 1.1 christos if ((np->in_dpnext == 0) || ((flags & NAT_NOTRULEPORT) != 0)) 2962 1.1 christos nport = dport; 2963 1.1 christos else { 2964 1.1 christos /* 2965 1.1 christos * Whilst not optimized for the case where 2966 1.1 christos * pmin == pmax, the gain is not significant. 2967 1.1 christos */ 2968 1.1 christos if (((np->in_flags & IPN_FIXEDDPORT) == 0) && 2969 1.1 christos (np->in_odport != np->in_dtop)) { 2970 1.1 christos nport = ntohs(dport) - np->in_odport + np->in_dpmax; 2971 1.1 christos nport = htons(nport); 2972 1.1 christos } else { 2973 1.1 christos nport = htons(np->in_dpnext); 2974 1.1 christos np->in_dpnext++; 2975 1.1 christos if (np->in_dpnext > np->in_dpmax) 2976 1.1 christos np->in_dpnext = np->in_dpmin; 2977 1.1 christos } 2978 1.1 christos } 2979 1.1 christos 2980 1.1 christos /* 2981 1.1 christos * When the redirect-to address is set to 0.0.0.0, just 2982 1.1 christos * assume a blank `forwarding' of the packet. We don't 2983 1.1 christos * setup any translation for this either. 2984 1.1 christos */ 2985 1.1 christos if (in.s_addr == 0) { 2986 1.1 christos if (nport == dport) { 2987 1.1 christos NBUMPSIDED(0, ns_xlate_null); 2988 1.1 christos return -1; 2989 1.1 christos } 2990 1.1 christos in.s_addr = ntohl(fin->fin_daddr); 2991 1.1 christos } 2992 1.1 christos 2993 1.1 christos /* 2994 1.1 christos * Check to see if this redirect mapping already exists and if 2995 1.1 christos * it does, return "failure" (allowing it to be created will just 2996 1.1 christos * cause one or both of these "connections" to stop working.) 2997 1.1 christos */ 2998 1.1 christos inb.s_addr = htonl(in.s_addr); 2999 1.1 christos sp = fin->fin_data[0]; 3000 1.1 christos dp = fin->fin_data[1]; 3001 1.1 christos fin->fin_data[1] = fin->fin_data[0]; 3002 1.1 christos fin->fin_data[0] = ntohs(nport); 3003 1.1 christos natl = ipf_nat_outlookup(fin, flags & ~(SI_WILDP|NAT_SEARCH), 3004 1.1 christos (u_int)fin->fin_p, inb, fin->fin_src); 3005 1.1 christos fin->fin_data[0] = sp; 3006 1.1 christos fin->fin_data[1] = dp; 3007 1.1 christos if (natl != NULL) { 3008 1.1 christos DT2(ns_new_xlate_exists, fr_info_t *, fin, nat_t *, natl); 3009 1.1 christos NBUMPSIDE(0, ns_xlate_exists); 3010 1.1 christos return -1; 3011 1.1 christos } 3012 1.1 christos 3013 1.1 christos nat->nat_ndstaddr = htonl(in.s_addr); 3014 1.1 christos nat->nat_odstip = fin->fin_dst; 3015 1.1 christos nat->nat_nsrcip = fin->fin_src; 3016 1.1 christos nat->nat_osrcip = fin->fin_src; 3017 1.1 christos if ((nat->nat_hm == NULL) && ((np->in_flags & IPN_STICKY) != 0)) 3018 1.1 christos nat->nat_hm = ipf_nat_hostmap(softn, np, fin->fin_src, 3019 1.12 darrenr fin->fin_dst, inb, (u_32_t)dport); 3020 1.1 christos 3021 1.1 christos if (flags & IPN_TCPUDP) { 3022 1.1 christos nat->nat_odport = dport; 3023 1.1 christos nat->nat_ndport = nport; 3024 1.1 christos nat->nat_osport = sport; 3025 1.1 christos nat->nat_nsport = sport; 3026 1.1 christos ((tcphdr_t *)fin->fin_dp)->th_dport = nport; 3027 1.1 christos } else if (flags & IPN_ICMPQUERY) { 3028 1.1 christos nat->nat_oicmpid = fin->fin_data[1]; 3029 1.1 christos ((icmphdr_t *)fin->fin_dp)->icmp_id = nport; 3030 1.1 christos nat->nat_nicmpid = nport; 3031 1.1 christos } 3032 1.1 christos 3033 1.1 christos return move; 3034 1.1 christos } 3035 1.1 christos 3036 1.1 christos /* ------------------------------------------------------------------------ */ 3037 1.1 christos /* Function: ipf_nat_add */ 3038 1.1 christos /* Returns: nat_t* - NULL == failure to create new NAT structure, */ 3039 1.1 christos /* else pointer to new NAT structure */ 3040 1.1 christos /* Parameters: fin(I) - pointer to packet information */ 3041 1.1 christos /* np(I) - pointer to NAT rule */ 3042 1.1 christos /* natsave(I) - pointer to where to store NAT struct pointer */ 3043 1.1 christos /* flags(I) - flags describing the current packet */ 3044 1.1 christos /* direction(I) - direction of packet (in/out) */ 3045 1.1 christos /* Write Lock: ipf_nat */ 3046 1.1 christos /* */ 3047 1.1 christos /* Attempts to create a new NAT entry. Does not actually change the packet */ 3048 1.1 christos /* in any way. */ 3049 1.1 christos /* */ 3050 1.7 christos /* This function is in three main parts: (1) deal with creating a new NAT */ 3051 1.1 christos /* structure for a "MAP" rule (outgoing NAT translation); (2) deal with */ 3052 1.1 christos /* creating a new NAT structure for a "RDR" rule (incoming NAT translation) */ 3053 1.1 christos /* and (3) building that structure and putting it into the NAT table(s). */ 3054 1.1 christos /* */ 3055 1.7 christos /* NOTE: natsave should NOT be used to point back to an ipstate_t struct */ 3056 1.1 christos /* as it can result in memory being corrupted. */ 3057 1.1 christos /* ------------------------------------------------------------------------ */ 3058 1.1 christos nat_t * 3059 1.2 christos ipf_nat_add(fr_info_t *fin, ipnat_t *np, nat_t **natsave, u_int flags, 3060 1.2 christos int direction) 3061 1.1 christos { 3062 1.1 christos ipf_main_softc_t *softc = fin->fin_main_soft; 3063 1.1 christos ipf_nat_softc_t *softn = softc->ipf_nat_soft; 3064 1.1 christos hostmap_t *hm = NULL; 3065 1.1 christos nat_t *nat, *natl; 3066 1.1 christos natstat_t *nsp; 3067 1.1 christos u_int nflags; 3068 1.1 christos natinfo_t ni; 3069 1.1 christos int move; 3070 1.1 christos 3071 1.2 christos memset(&ni, 0, sizeof ni); /* XXX gcc */ 3072 1.1 christos nsp = &softn->ipf_nat_stats; 3073 1.1 christos 3074 1.1 christos if ((nsp->ns_active * 100 / softn->ipf_nat_table_max) > 3075 1.1 christos softn->ipf_nat_table_wm_high) { 3076 1.1 christos softn->ipf_nat_doflush = 1; 3077 1.1 christos } 3078 1.1 christos 3079 1.1 christos if (nsp->ns_active >= softn->ipf_nat_table_max) { 3080 1.1 christos NBUMPSIDED(fin->fin_out, ns_table_max); 3081 1.1 christos return NULL; 3082 1.1 christos } 3083 1.1 christos 3084 1.1 christos move = 1; 3085 1.1 christos nflags = np->in_flags & flags; 3086 1.1 christos nflags &= NAT_FROMRULE; 3087 1.1 christos 3088 1.1 christos ni.nai_np = np; 3089 1.1 christos ni.nai_dport = 0; 3090 1.1 christos ni.nai_sport = 0; 3091 1.1 christos 3092 1.1 christos /* Give me a new nat */ 3093 1.1 christos KMALLOC(nat, nat_t *); 3094 1.1 christos if (nat == NULL) { 3095 1.1 christos NBUMPSIDED(fin->fin_out, ns_memfail); 3096 1.1 christos /* 3097 1.1 christos * Try to automatically tune the max # of entries in the 3098 1.1 christos * table allowed to be less than what will cause kmem_alloc() 3099 1.1 christos * to fail and try to eliminate panics due to out of memory 3100 1.1 christos * conditions arising. 3101 1.1 christos */ 3102 1.1 christos if ((softn->ipf_nat_table_max > softn->ipf_nat_table_sz) && 3103 1.1 christos (nsp->ns_active > 100)) { 3104 1.1 christos softn->ipf_nat_table_max = nsp->ns_active - 100; 3105 1.1 christos printf("table_max reduced to %d\n", 3106 1.1 christos softn->ipf_nat_table_max); 3107 1.1 christos } 3108 1.1 christos return NULL; 3109 1.1 christos } 3110 1.1 christos 3111 1.1 christos if (flags & IPN_ICMPQUERY) { 3112 1.1 christos /* 3113 1.1 christos * In the ICMP query NAT code, we translate the ICMP id fields 3114 1.1 christos * to make them unique. This is indepedent of the ICMP type 3115 1.1 christos * (e.g. in the unlikely event that a host sends an echo and 3116 1.27 rillig * a tstamp request with the same id, both packets will have 3117 1.1 christos * their ip address/id field changed in the same way). 3118 1.1 christos */ 3119 1.1 christos /* The icmp_id field is used by the sender to identify the 3120 1.1 christos * process making the icmp request. (the receiver justs 3121 1.1 christos * copies it back in its response). So, it closely matches 3122 1.1 christos * the concept of source port. We overlay sport, so we can 3123 1.1 christos * maximally reuse the existing code. 3124 1.1 christos */ 3125 1.1 christos ni.nai_sport = fin->fin_data[1]; 3126 1.1 christos ni.nai_dport = 0; 3127 1.1 christos } 3128 1.1 christos 3129 1.1 christos bzero((char *)nat, sizeof(*nat)); 3130 1.1 christos nat->nat_flags = flags; 3131 1.1 christos nat->nat_redir = np->in_redir; 3132 1.1 christos nat->nat_dir = direction; 3133 1.1 christos nat->nat_pr[0] = fin->fin_p; 3134 1.1 christos nat->nat_pr[1] = fin->fin_p; 3135 1.1 christos 3136 1.1 christos /* 3137 1.1 christos * Search the current table for a match and create a new mapping 3138 1.1 christos * if there is none found. 3139 1.1 christos */ 3140 1.3 darrenr if (np->in_redir & NAT_DIVERTUDP) { 3141 1.1 christos move = ipf_nat_newdivert(fin, nat, &ni); 3142 1.1 christos 3143 1.1 christos } else if (np->in_redir & NAT_REWRITE) { 3144 1.1 christos move = ipf_nat_newrewrite(fin, nat, &ni); 3145 1.1 christos 3146 1.1 christos } else if (direction == NAT_OUTBOUND) { 3147 1.1 christos /* 3148 1.1 christos * We can now arrange to call this for the same connection 3149 1.1 christos * because ipf_nat_new doesn't protect the code path into 3150 1.1 christos * this function. 3151 1.1 christos */ 3152 1.1 christos natl = ipf_nat_outlookup(fin, nflags, (u_int)fin->fin_p, 3153 1.1 christos fin->fin_src, fin->fin_dst); 3154 1.1 christos if (natl != NULL) { 3155 1.1 christos KFREE(nat); 3156 1.1 christos nat = natl; 3157 1.1 christos goto done; 3158 1.1 christos } 3159 1.1 christos 3160 1.1 christos move = ipf_nat_newmap(fin, nat, &ni); 3161 1.1 christos } else { 3162 1.1 christos /* 3163 1.1 christos * NAT_INBOUND is used for redirects rules 3164 1.1 christos */ 3165 1.1 christos natl = ipf_nat_inlookup(fin, nflags, (u_int)fin->fin_p, 3166 1.1 christos fin->fin_src, fin->fin_dst); 3167 1.1 christos if (natl != NULL) { 3168 1.1 christos KFREE(nat); 3169 1.1 christos nat = natl; 3170 1.1 christos goto done; 3171 1.1 christos } 3172 1.1 christos 3173 1.1 christos move = ipf_nat_newrdr(fin, nat, &ni); 3174 1.1 christos } 3175 1.1 christos if (move == -1) 3176 1.1 christos goto badnat; 3177 1.1 christos 3178 1.1 christos np = ni.nai_np; 3179 1.1 christos 3180 1.1 christos nat->nat_mssclamp = np->in_mssclamp; 3181 1.1 christos nat->nat_me = natsave; 3182 1.1 christos nat->nat_fr = fin->fin_fr; 3183 1.1 christos nat->nat_rev = fin->fin_rev; 3184 1.1 christos nat->nat_ptr = np; 3185 1.1 christos nat->nat_dlocal = np->in_dlocal; 3186 1.1 christos 3187 1.3 darrenr if ((np->in_apr != NULL) && ((nat->nat_flags & NAT_SLAVE) == 0)) { 3188 1.3 darrenr if (ipf_proxy_new(fin, nat) == -1) { 3189 1.3 darrenr NBUMPSIDED(fin->fin_out, ns_appr_fail); 3190 1.1 christos goto badnat; 3191 1.3 darrenr } 3192 1.3 darrenr } 3193 1.1 christos 3194 1.1 christos nat->nat_ifps[0] = np->in_ifps[0]; 3195 1.1 christos if (np->in_ifps[0] != NULL) { 3196 1.1 christos COPYIFNAME(np->in_v[0], np->in_ifps[0], nat->nat_ifnames[0]); 3197 1.1 christos } 3198 1.1 christos 3199 1.1 christos nat->nat_ifps[1] = np->in_ifps[1]; 3200 1.1 christos if (np->in_ifps[1] != NULL) { 3201 1.1 christos COPYIFNAME(np->in_v[1], np->in_ifps[1], nat->nat_ifnames[1]); 3202 1.1 christos } 3203 1.1 christos 3204 1.1 christos if (ipf_nat_finalise(fin, nat) == -1) { 3205 1.1 christos goto badnat; 3206 1.1 christos } 3207 1.1 christos 3208 1.1 christos np->in_use++; 3209 1.1 christos 3210 1.1 christos if ((move == 1) && (np->in_flags & IPN_ROUNDR)) { 3211 1.1 christos if ((np->in_redir & (NAT_REDIRECT|NAT_MAP)) == NAT_REDIRECT) { 3212 1.1 christos ipf_nat_delrdr(softn, np); 3213 1.1 christos ipf_nat_addrdr(softn, np); 3214 1.1 christos } else if ((np->in_redir & (NAT_REDIRECT|NAT_MAP)) == NAT_MAP) { 3215 1.1 christos ipf_nat_delmap(softn, np); 3216 1.1 christos ipf_nat_addmap(softn, np); 3217 1.1 christos } 3218 1.1 christos } 3219 1.1 christos 3220 1.1 christos if (flags & SI_WILDP) 3221 1.1 christos nsp->ns_wilds++; 3222 1.1 christos nsp->ns_proto[nat->nat_pr[0]]++; 3223 1.1 christos 3224 1.1 christos goto done; 3225 1.1 christos badnat: 3226 1.1 christos DT2(ns_badnatnew, fr_info_t *, fin, nat_t *, nat); 3227 1.1 christos NBUMPSIDE(fin->fin_out, ns_badnatnew); 3228 1.1 christos if ((hm = nat->nat_hm) != NULL) 3229 1.3 darrenr ipf_nat_hostmapdel(softc, &hm); 3230 1.1 christos KFREE(nat); 3231 1.1 christos nat = NULL; 3232 1.1 christos done: 3233 1.1 christos if (nat != NULL && np != NULL) 3234 1.1 christos np->in_hits++; 3235 1.3 darrenr if (natsave != NULL) 3236 1.3 darrenr *natsave = nat; 3237 1.1 christos return nat; 3238 1.1 christos } 3239 1.1 christos 3240 1.1 christos 3241 1.1 christos /* ------------------------------------------------------------------------ */ 3242 1.1 christos /* Function: ipf_nat_finalise */ 3243 1.1 christos /* Returns: int - 0 == sucess, -1 == failure */ 3244 1.1 christos /* Parameters: fin(I) - pointer to packet information */ 3245 1.1 christos /* nat(I) - pointer to NAT entry */ 3246 1.1 christos /* Write Lock: ipf_nat */ 3247 1.1 christos /* */ 3248 1.1 christos /* This is the tail end of constructing a new NAT entry and is the same */ 3249 1.1 christos /* for both IPv4 and IPv6. */ 3250 1.1 christos /* ------------------------------------------------------------------------ */ 3251 1.1 christos /*ARGSUSED*/ 3252 1.1 christos static int 3253 1.2 christos ipf_nat_finalise(fr_info_t *fin, nat_t *nat) 3254 1.1 christos { 3255 1.1 christos ipf_main_softc_t *softc = fin->fin_main_soft; 3256 1.1 christos ipf_nat_softc_t *softn = softc->ipf_nat_soft; 3257 1.1 christos u_32_t sum1, sum2, sumd; 3258 1.1 christos frentry_t *fr; 3259 1.1 christos #if SOLARIS && defined(_KERNEL) && (SOLARIS2 >= 6) && defined(ICK_M_CTL_MAGIC) 3260 1.1 christos qpktinfo_t *qpi = fin->fin_qpi; 3261 1.1 christos #endif 3262 1.1 christos 3263 1.1 christos switch (nat->nat_pr[0]) 3264 1.1 christos { 3265 1.1 christos case IPPROTO_ICMP : 3266 1.3 darrenr sum1 = LONG_SUM(ntohs(nat->nat_oicmpid)); 3267 1.3 darrenr sum2 = LONG_SUM(ntohs(nat->nat_nicmpid)); 3268 1.1 christos CALC_SUMD(sum1, sum2, sumd); 3269 1.1 christos nat->nat_sumd[0] = (sumd & 0xffff) + (sumd >> 16); 3270 1.1 christos 3271 1.1 christos break; 3272 1.1 christos 3273 1.1 christos default : 3274 1.1 christos sum1 = LONG_SUM(ntohl(nat->nat_osrcaddr) + \ 3275 1.1 christos ntohs(nat->nat_osport)); 3276 1.1 christos sum2 = LONG_SUM(ntohl(nat->nat_nsrcaddr) + \ 3277 1.1 christos ntohs(nat->nat_nsport)); 3278 1.1 christos CALC_SUMD(sum1, sum2, sumd); 3279 1.1 christos nat->nat_sumd[0] = (sumd & 0xffff) + (sumd >> 16); 3280 1.1 christos 3281 1.1 christos sum1 = LONG_SUM(ntohl(nat->nat_odstaddr) + \ 3282 1.1 christos ntohs(nat->nat_odport)); 3283 1.1 christos sum2 = LONG_SUM(ntohl(nat->nat_ndstaddr) + \ 3284 1.1 christos ntohs(nat->nat_ndport)); 3285 1.1 christos CALC_SUMD(sum1, sum2, sumd); 3286 1.1 christos nat->nat_sumd[0] += (sumd & 0xffff) + (sumd >> 16); 3287 1.1 christos break; 3288 1.1 christos } 3289 1.1 christos 3290 1.3 darrenr /* 3291 1.3 darrenr * Compute the partial checksum, just in case. 3292 1.3 darrenr * This is only ever placed into outbound packets so care needs 3293 1.3 darrenr * to be taken over which pair of addresses are used. 3294 1.3 darrenr */ 3295 1.3 darrenr if (nat->nat_dir == NAT_OUTBOUND) { 3296 1.1 christos sum1 = LONG_SUM(ntohl(nat->nat_nsrcaddr)); 3297 1.1 christos sum1 += LONG_SUM(ntohl(nat->nat_ndstaddr)); 3298 1.3 darrenr } else { 3299 1.3 darrenr sum1 = LONG_SUM(ntohl(nat->nat_osrcaddr)); 3300 1.3 darrenr sum1 += LONG_SUM(ntohl(nat->nat_odstaddr)); 3301 1.3 darrenr } 3302 1.3 darrenr sum1 += nat->nat_pr[1]; 3303 1.3 darrenr nat->nat_sumd[1] = (sum1 & 0xffff) + (sum1 >> 16); 3304 1.1 christos 3305 1.1 christos sum1 = LONG_SUM(ntohl(nat->nat_osrcaddr)); 3306 1.1 christos sum2 = LONG_SUM(ntohl(nat->nat_nsrcaddr)); 3307 1.1 christos CALC_SUMD(sum1, sum2, sumd); 3308 1.1 christos nat->nat_ipsumd = (sumd & 0xffff) + (sumd >> 16); 3309 1.1 christos 3310 1.1 christos sum1 = LONG_SUM(ntohl(nat->nat_odstaddr)); 3311 1.1 christos sum2 = LONG_SUM(ntohl(nat->nat_ndstaddr)); 3312 1.1 christos CALC_SUMD(sum1, sum2, sumd); 3313 1.1 christos nat->nat_ipsumd += (sumd & 0xffff) + (sumd >> 16); 3314 1.1 christos 3315 1.1 christos nat->nat_v[0] = 4; 3316 1.1 christos nat->nat_v[1] = 4; 3317 1.1 christos 3318 1.1 christos if ((nat->nat_ifps[0] != NULL) && (nat->nat_ifps[0] != (void *)-1)) { 3319 1.1 christos nat->nat_mtu[0] = GETIFMTU_4(nat->nat_ifps[0]); 3320 1.1 christos } 3321 1.1 christos 3322 1.1 christos if ((nat->nat_ifps[1] != NULL) && (nat->nat_ifps[1] != (void *)-1)) { 3323 1.1 christos nat->nat_mtu[1] = GETIFMTU_4(nat->nat_ifps[1]); 3324 1.1 christos } 3325 1.1 christos 3326 1.1 christos if ((nat->nat_flags & SI_CLONE) == 0) 3327 1.1 christos nat->nat_sync = ipf_sync_new(softc, SMC_NAT, fin, nat); 3328 1.1 christos 3329 1.1 christos if (ipf_nat_insert(softc, softn, nat) == 0) { 3330 1.1 christos if (softn->ipf_nat_logging) 3331 1.1 christos ipf_nat_log(softc, softn, nat, NL_NEW); 3332 1.1 christos fr = nat->nat_fr; 3333 1.1 christos if (fr != NULL) { 3334 1.1 christos MUTEX_ENTER(&fr->fr_lock); 3335 1.1 christos fr->fr_ref++; 3336 1.1 christos MUTEX_EXIT(&fr->fr_lock); 3337 1.1 christos } 3338 1.1 christos return 0; 3339 1.1 christos } 3340 1.1 christos 3341 1.1 christos NBUMPSIDED(fin->fin_out, ns_unfinalised); 3342 1.1 christos /* 3343 1.1 christos * nat_insert failed, so cleanup time... 3344 1.1 christos */ 3345 1.3 darrenr if (nat->nat_sync != NULL) 3346 1.3 darrenr ipf_sync_del_nat(softc->ipf_sync_soft, nat->nat_sync); 3347 1.1 christos return -1; 3348 1.1 christos } 3349 1.1 christos 3350 1.1 christos 3351 1.1 christos /* ------------------------------------------------------------------------ */ 3352 1.9 christos /* Function: ipf_nat_insert */ 3353 1.9 christos /* Returns: int - 0 == sucess, -1 == failure */ 3354 1.9 christos /* Parameters: softc(I) - pointer to soft context main structure */ 3355 1.9 christos /* softn(I) - pointer to NAT context structure */ 3356 1.9 christos /* nat(I) - pointer to NAT structure */ 3357 1.3 darrenr /* Write Lock: ipf_nat */ 3358 1.1 christos /* */ 3359 1.9 christos /* Insert a NAT entry into the hash tables for searching and add it to the */ 3360 1.9 christos /* list of active NAT entries. Adjust global counters when complete. */ 3361 1.1 christos /* ------------------------------------------------------------------------ */ 3362 1.9 christos int 3363 1.9 christos ipf_nat_insert(ipf_main_softc_t *softc, ipf_nat_softc_t *softn, nat_t *nat) 3364 1.1 christos { 3365 1.3 darrenr u_int hv0, hv1; 3366 1.9 christos u_int sp, dp; 3367 1.9 christos ipnat_t *in; 3368 1.9 christos int ret; 3369 1.1 christos 3370 1.9 christos /* 3371 1.9 christos * Try and return an error as early as possible, so calculate the hash 3372 1.9 christos * entry numbers first and then proceed. 3373 1.9 christos */ 3374 1.1 christos if ((nat->nat_flags & (SI_W_SPORT|SI_W_DPORT)) == 0) { 3375 1.3 darrenr if ((nat->nat_flags & IPN_TCPUDP) != 0) { 3376 1.9 christos sp = nat->nat_osport; 3377 1.9 christos dp = nat->nat_odport; 3378 1.3 darrenr } else if ((nat->nat_flags & IPN_ICMPQUERY) != 0) { 3379 1.9 christos sp = 0; 3380 1.9 christos dp = nat->nat_oicmpid; 3381 1.3 darrenr } else { 3382 1.9 christos sp = 0; 3383 1.9 christos dp = 0; 3384 1.3 darrenr } 3385 1.9 christos hv0 = NAT_HASH_FN(nat->nat_osrcaddr, sp, 0xffffffff); 3386 1.9 christos hv0 = NAT_HASH_FN(nat->nat_odstaddr, hv0 + dp, 0xffffffff); 3387 1.1 christos /* 3388 1.1 christos * TRACE nat_osrcaddr, nat_osport, nat_odstaddr, 3389 1.1 christos * nat_odport, hv0 3390 1.1 christos */ 3391 1.1 christos 3392 1.3 darrenr if ((nat->nat_flags & IPN_TCPUDP) != 0) { 3393 1.9 christos sp = nat->nat_nsport; 3394 1.9 christos dp = nat->nat_ndport; 3395 1.3 darrenr } else if ((nat->nat_flags & IPN_ICMPQUERY) != 0) { 3396 1.9 christos sp = 0; 3397 1.9 christos dp = nat->nat_nicmpid; 3398 1.3 darrenr } else { 3399 1.9 christos sp = 0; 3400 1.9 christos dp = 0; 3401 1.3 darrenr } 3402 1.9 christos hv1 = NAT_HASH_FN(nat->nat_nsrcaddr, sp, 0xffffffff); 3403 1.9 christos hv1 = NAT_HASH_FN(nat->nat_ndstaddr, hv1 + dp, 0xffffffff); 3404 1.1 christos /* 3405 1.1 christos * TRACE nat_nsrcaddr, nat_nsport, nat_ndstaddr, 3406 1.1 christos * nat_ndport, hv1 3407 1.1 christos */ 3408 1.1 christos } else { 3409 1.3 darrenr hv0 = NAT_HASH_FN(nat->nat_osrcaddr, 0, 0xffffffff); 3410 1.3 darrenr hv0 = NAT_HASH_FN(nat->nat_odstaddr, hv0, 0xffffffff); 3411 1.3 darrenr /* TRACE nat_osrcaddr, nat_odstaddr, hv0 */ 3412 1.1 christos 3413 1.3 darrenr hv1 = NAT_HASH_FN(nat->nat_nsrcaddr, 0, 0xffffffff); 3414 1.3 darrenr hv1 = NAT_HASH_FN(nat->nat_ndstaddr, hv1, 0xffffffff); 3415 1.3 darrenr /* TRACE nat_nsrcaddr, nat_ndstaddr, hv1 */ 3416 1.1 christos } 3417 1.1 christos 3418 1.9 christos if ((nat->nat_dir & NAT_OUTBOUND) == NAT_OUTBOUND) { 3419 1.9 christos nat->nat_hv[0] = hv0; 3420 1.9 christos nat->nat_hv[1] = hv1; 3421 1.9 christos } else { 3422 1.9 christos nat->nat_hv[0] = hv1; 3423 1.9 christos nat->nat_hv[1] = hv0; 3424 1.9 christos } 3425 1.1 christos 3426 1.1 christos MUTEX_INIT(&nat->nat_lock, "nat entry lock"); 3427 1.1 christos 3428 1.1 christos in = nat->nat_ptr; 3429 1.1 christos nat->nat_ref = nat->nat_me ? 2 : 1; 3430 1.1 christos 3431 1.1 christos nat->nat_ifnames[0][LIFNAMSIZ - 1] = '\0'; 3432 1.1 christos nat->nat_ifps[0] = ipf_resolvenic(softc, nat->nat_ifnames[0], 4); 3433 1.1 christos 3434 1.1 christos if (nat->nat_ifnames[1][0] != '\0') { 3435 1.1 christos nat->nat_ifnames[1][LIFNAMSIZ - 1] = '\0'; 3436 1.1 christos nat->nat_ifps[1] = ipf_resolvenic(softc, 3437 1.1 christos nat->nat_ifnames[1], 4); 3438 1.1 christos } else if (in->in_ifnames[1] != -1) { 3439 1.1 christos char *name; 3440 1.1 christos 3441 1.1 christos name = in->in_names + in->in_ifnames[1]; 3442 1.1 christos if (name[1] != '\0' && name[0] != '-' && name[0] != '*') { 3443 1.1 christos (void) strncpy(nat->nat_ifnames[1], 3444 1.1 christos nat->nat_ifnames[0], LIFNAMSIZ); 3445 1.1 christos nat->nat_ifnames[1][LIFNAMSIZ - 1] = '\0'; 3446 1.1 christos nat->nat_ifps[1] = nat->nat_ifps[0]; 3447 1.1 christos } 3448 1.1 christos } 3449 1.1 christos if ((nat->nat_ifps[0] != NULL) && (nat->nat_ifps[0] != (void *)-1)) { 3450 1.1 christos nat->nat_mtu[0] = GETIFMTU_4(nat->nat_ifps[0]); 3451 1.1 christos } 3452 1.1 christos if ((nat->nat_ifps[1] != NULL) && (nat->nat_ifps[1] != (void *)-1)) { 3453 1.1 christos nat->nat_mtu[1] = GETIFMTU_4(nat->nat_ifps[1]); 3454 1.1 christos } 3455 1.1 christos 3456 1.7 christos ret = ipf_nat_hashtab_add(softc, softn, nat); 3457 1.13 darrenr if (ret != 0) 3458 1.7 christos MUTEX_DESTROY(&nat->nat_lock); 3459 1.7 christos return ret; 3460 1.3 darrenr } 3461 1.3 darrenr 3462 1.3 darrenr 3463 1.3 darrenr /* ------------------------------------------------------------------------ */ 3464 1.3 darrenr /* Function: ipf_nat_hashtab_add */ 3465 1.9 christos /* Returns: int - 0 == sucess, -1 == failure */ 3466 1.3 darrenr /* Parameters: softc(I) - pointer to soft context main structure */ 3467 1.3 darrenr /* softn(I) - pointer to NAT context structure */ 3468 1.3 darrenr /* nat(I) - pointer to NAT structure */ 3469 1.9 christos /* Write Lock: ipf_nat */ 3470 1.3 darrenr /* */ 3471 1.3 darrenr /* Handle the insertion of a NAT entry into the table/list. */ 3472 1.3 darrenr /* ------------------------------------------------------------------------ */ 3473 1.3 darrenr int 3474 1.5 darrenr ipf_nat_hashtab_add(ipf_main_softc_t *softc, ipf_nat_softc_t *softn, nat_t *nat) 3475 1.3 darrenr { 3476 1.3 darrenr nat_t **natp; 3477 1.3 darrenr u_int hv0; 3478 1.3 darrenr u_int hv1; 3479 1.3 darrenr 3480 1.3 darrenr hv0 = nat->nat_hv[0] % softn->ipf_nat_table_sz; 3481 1.3 darrenr hv1 = nat->nat_hv[1] % softn->ipf_nat_table_sz; 3482 1.3 darrenr 3483 1.3 darrenr if (softn->ipf_nat_stats.ns_side[0].ns_bucketlen[hv0] >= 3484 1.3 darrenr softn->ipf_nat_maxbucket) { 3485 1.3 darrenr DT1(ns_bucket_max_0, int, 3486 1.3 darrenr softn->ipf_nat_stats.ns_side[0].ns_bucketlen[hv0]); 3487 1.3 darrenr NBUMPSIDE(0, ns_bucket_max); 3488 1.3 darrenr return -1; 3489 1.3 darrenr } 3490 1.3 darrenr 3491 1.3 darrenr if (softn->ipf_nat_stats.ns_side[1].ns_bucketlen[hv1] >= 3492 1.3 darrenr softn->ipf_nat_maxbucket) { 3493 1.3 darrenr DT1(ns_bucket_max_1, int, 3494 1.3 darrenr softn->ipf_nat_stats.ns_side[1].ns_bucketlen[hv1]); 3495 1.3 darrenr NBUMPSIDE(1, ns_bucket_max); 3496 1.3 darrenr return -1; 3497 1.3 darrenr } 3498 1.3 darrenr 3499 1.1 christos /* 3500 1.1 christos * The ordering of operations in the list and hash table insertion 3501 1.1 christos * is very important. The last operation for each task should be 3502 1.1 christos * to update the top of the list, after all the "nexts" have been 3503 1.1 christos * done so that walking the list while it is being done does not 3504 1.1 christos * find strange pointers. 3505 1.1 christos * 3506 1.1 christos * Global list of NAT instances 3507 1.1 christos */ 3508 1.1 christos nat->nat_next = softn->ipf_nat_instances; 3509 1.1 christos nat->nat_pnext = &softn->ipf_nat_instances; 3510 1.1 christos if (softn->ipf_nat_instances) 3511 1.1 christos softn->ipf_nat_instances->nat_pnext = &nat->nat_next; 3512 1.1 christos softn->ipf_nat_instances = nat; 3513 1.1 christos 3514 1.1 christos /* 3515 1.1 christos * Inbound hash table. 3516 1.1 christos */ 3517 1.1 christos natp = &softn->ipf_nat_table[0][hv0]; 3518 1.1 christos nat->nat_phnext[0] = natp; 3519 1.1 christos nat->nat_hnext[0] = *natp; 3520 1.1 christos if (*natp) { 3521 1.1 christos (*natp)->nat_phnext[0] = &nat->nat_hnext[0]; 3522 1.1 christos } else { 3523 1.1 christos NBUMPSIDE(0, ns_inuse); 3524 1.1 christos } 3525 1.1 christos *natp = nat; 3526 1.1 christos NBUMPSIDE(0, ns_bucketlen[hv0]); 3527 1.1 christos 3528 1.1 christos /* 3529 1.1 christos * Outbound hash table. 3530 1.1 christos */ 3531 1.1 christos natp = &softn->ipf_nat_table[1][hv1]; 3532 1.1 christos nat->nat_phnext[1] = natp; 3533 1.1 christos nat->nat_hnext[1] = *natp; 3534 1.1 christos if (*natp) 3535 1.1 christos (*natp)->nat_phnext[1] = &nat->nat_hnext[1]; 3536 1.1 christos else { 3537 1.1 christos NBUMPSIDE(1, ns_inuse); 3538 1.1 christos } 3539 1.1 christos *natp = nat; 3540 1.1 christos NBUMPSIDE(1, ns_bucketlen[hv1]); 3541 1.1 christos 3542 1.1 christos ipf_nat_setqueue(softc, softn, nat); 3543 1.1 christos 3544 1.1 christos if (nat->nat_dir & NAT_OUTBOUND) { 3545 1.1 christos NBUMPSIDE(1, ns_added); 3546 1.1 christos } else { 3547 1.1 christos NBUMPSIDE(0, ns_added); 3548 1.1 christos } 3549 1.1 christos softn->ipf_nat_stats.ns_active++; 3550 1.1 christos return 0; 3551 1.1 christos } 3552 1.1 christos 3553 1.1 christos 3554 1.1 christos /* ------------------------------------------------------------------------ */ 3555 1.1 christos /* Function: ipf_nat_icmperrorlookup */ 3556 1.1 christos /* Returns: nat_t* - point to matching NAT structure */ 3557 1.1 christos /* Parameters: fin(I) - pointer to packet information */ 3558 1.1 christos /* dir(I) - direction of packet (in/out) */ 3559 1.1 christos /* */ 3560 1.1 christos /* Check if the ICMP error message is related to an existing TCP, UDP or */ 3561 1.1 christos /* ICMP query nat entry. It is assumed that the packet is already of the */ 3562 1.1 christos /* the required length. */ 3563 1.1 christos /* ------------------------------------------------------------------------ */ 3564 1.1 christos nat_t * 3565 1.2 christos ipf_nat_icmperrorlookup(fr_info_t *fin, int dir) 3566 1.1 christos { 3567 1.1 christos ipf_main_softc_t *softc = fin->fin_main_soft; 3568 1.1 christos ipf_nat_softc_t *softn = softc->ipf_nat_soft; 3569 1.10 martin int flags = 0, minlen; 3570 1.10 martin icmphdr_t *orgicmp; 3571 1.1 christos nat_stat_side_t *nside; 3572 1.1 christos tcphdr_t *tcp = NULL; 3573 1.1 christos u_short data[2]; 3574 1.1 christos nat_t *nat; 3575 1.1 christos ip_t *oip; 3576 1.1 christos u_int p; 3577 1.1 christos 3578 1.1 christos nside = &softn->ipf_nat_stats.ns_side[fin->fin_out]; 3579 1.1 christos /* 3580 1.1 christos * Does it at least have the return (basic) IP header ? 3581 1.1 christos * Only a basic IP header (no options) should be with an ICMP error 3582 1.1 christos * header. Also, if it's not an error type, then return. 3583 1.1 christos */ 3584 1.1 christos if ((fin->fin_hlen != sizeof(ip_t)) || !(fin->fin_flx & FI_ICMPERR)) { 3585 1.1 christos ATOMIC_INCL(nside->ns_icmp_basic); 3586 1.1 christos return NULL; 3587 1.1 christos } 3588 1.1 christos 3589 1.1 christos /* 3590 1.1 christos * Check packet size 3591 1.1 christos */ 3592 1.1 christos oip = (ip_t *)((char *)fin->fin_dp + 8); 3593 1.1 christos minlen = IP_HL(oip) << 2; 3594 1.1 christos if ((minlen < sizeof(ip_t)) || 3595 1.1 christos (fin->fin_plen < ICMPERR_IPICMPHLEN + minlen)) { 3596 1.1 christos ATOMIC_INCL(nside->ns_icmp_size); 3597 1.1 christos return NULL; 3598 1.1 christos } 3599 1.1 christos 3600 1.1 christos /* 3601 1.1 christos * Is the buffer big enough for all of it ? It's the size of the IP 3602 1.1 christos * header claimed in the encapsulated part which is of concern. It 3603 1.1 christos * may be too big to be in this buffer but not so big that it's 3604 1.1 christos * outside the ICMP packet, leading to TCP deref's causing problems. 3605 1.1 christos * This is possible because we don't know how big oip_hl is when we 3606 1.1 christos * do the pullup early in ipf_check() and thus can't gaurantee it is 3607 1.1 christos * all here now. 3608 1.1 christos */ 3609 1.1 christos #ifdef ipf_nat_KERNEL 3610 1.1 christos { 3611 1.1 christos mb_t *m; 3612 1.1 christos 3613 1.1 christos m = fin->fin_m; 3614 1.1 christos # if defined(MENTAT) 3615 1.1 christos if ((char *)oip + fin->fin_dlen - ICMPERR_ICMPHLEN > 3616 1.1 christos (char *)m->b_wptr) { 3617 1.1 christos ATOMIC_INCL(nside->ns_icmp_mbuf); 3618 1.1 christos return NULL; 3619 1.1 christos } 3620 1.1 christos # else 3621 1.1 christos if ((char *)oip + fin->fin_dlen - ICMPERR_ICMPHLEN > 3622 1.1 christos (char *)fin->fin_ip + M_LEN(m)) { 3623 1.1 christos ATOMIC_INCL(nside->ns_icmp_mbuf); 3624 1.1 christos return NULL; 3625 1.1 christos } 3626 1.1 christos # endif 3627 1.1 christos } 3628 1.1 christos #endif 3629 1.1 christos 3630 1.1 christos if (fin->fin_daddr != oip->ip_src.s_addr) { 3631 1.1 christos ATOMIC_INCL(nside->ns_icmp_address); 3632 1.1 christos return NULL; 3633 1.1 christos } 3634 1.1 christos 3635 1.1 christos p = oip->ip_p; 3636 1.1 christos if (p == IPPROTO_TCP) 3637 1.1 christos flags = IPN_TCP; 3638 1.1 christos else if (p == IPPROTO_UDP) 3639 1.1 christos flags = IPN_UDP; 3640 1.1 christos else if (p == IPPROTO_ICMP) { 3641 1.1 christos orgicmp = (icmphdr_t *)((char *)oip + (IP_HL(oip) << 2)); 3642 1.1 christos 3643 1.1 christos /* see if this is related to an ICMP query */ 3644 1.1 christos if (ipf_nat_icmpquerytype(orgicmp->icmp_type)) { 3645 1.1 christos data[0] = fin->fin_data[0]; 3646 1.1 christos data[1] = fin->fin_data[1]; 3647 1.1 christos fin->fin_data[0] = 0; 3648 1.1 christos fin->fin_data[1] = orgicmp->icmp_id; 3649 1.1 christos 3650 1.1 christos flags = IPN_ICMPERR|IPN_ICMPQUERY; 3651 1.1 christos /* 3652 1.1 christos * NOTE : dir refers to the direction of the original 3653 1.1 christos * ip packet. By definition the icmp error 3654 1.1 christos * message flows in the opposite direction. 3655 1.1 christos */ 3656 1.1 christos if (dir == NAT_INBOUND) 3657 1.1 christos nat = ipf_nat_inlookup(fin, flags, p, 3658 1.1 christos oip->ip_dst, 3659 1.1 christos oip->ip_src); 3660 1.1 christos else 3661 1.1 christos nat = ipf_nat_outlookup(fin, flags, p, 3662 1.1 christos oip->ip_dst, 3663 1.1 christos oip->ip_src); 3664 1.1 christos fin->fin_data[0] = data[0]; 3665 1.1 christos fin->fin_data[1] = data[1]; 3666 1.1 christos return nat; 3667 1.1 christos } 3668 1.1 christos } 3669 1.1 christos 3670 1.1 christos if (flags & IPN_TCPUDP) { 3671 1.1 christos minlen += 8; /* + 64bits of data to get ports */ 3672 1.1 christos /* TRACE (fin,minlen) */ 3673 1.1 christos if (fin->fin_plen < ICMPERR_IPICMPHLEN + minlen) { 3674 1.1 christos ATOMIC_INCL(nside->ns_icmp_short); 3675 1.1 christos return NULL; 3676 1.1 christos } 3677 1.1 christos 3678 1.1 christos data[0] = fin->fin_data[0]; 3679 1.1 christos data[1] = fin->fin_data[1]; 3680 1.1 christos tcp = (tcphdr_t *)((char *)oip + (IP_HL(oip) << 2)); 3681 1.1 christos fin->fin_data[0] = ntohs(tcp->th_dport); 3682 1.1 christos fin->fin_data[1] = ntohs(tcp->th_sport); 3683 1.1 christos 3684 1.1 christos if (dir == NAT_INBOUND) { 3685 1.1 christos nat = ipf_nat_inlookup(fin, flags, p, oip->ip_dst, 3686 1.1 christos oip->ip_src); 3687 1.1 christos } else { 3688 1.1 christos nat = ipf_nat_outlookup(fin, flags, p, oip->ip_dst, 3689 1.1 christos oip->ip_src); 3690 1.1 christos } 3691 1.1 christos fin->fin_data[0] = data[0]; 3692 1.1 christos fin->fin_data[1] = data[1]; 3693 1.1 christos return nat; 3694 1.1 christos } 3695 1.1 christos if (dir == NAT_INBOUND) 3696 1.1 christos nat = ipf_nat_inlookup(fin, 0, p, oip->ip_dst, oip->ip_src); 3697 1.1 christos else 3698 1.1 christos nat = ipf_nat_outlookup(fin, 0, p, oip->ip_dst, oip->ip_src); 3699 1.1 christos 3700 1.1 christos return nat; 3701 1.1 christos } 3702 1.1 christos 3703 1.1 christos 3704 1.1 christos /* ------------------------------------------------------------------------ */ 3705 1.1 christos /* Function: ipf_nat_icmperror */ 3706 1.1 christos /* Returns: nat_t* - point to matching NAT structure */ 3707 1.1 christos /* Parameters: fin(I) - pointer to packet information */ 3708 1.1 christos /* nflags(I) - NAT flags for this packet */ 3709 1.1 christos /* dir(I) - direction of packet (in/out) */ 3710 1.1 christos /* */ 3711 1.1 christos /* Fix up an ICMP packet which is an error message for an existing NAT */ 3712 1.1 christos /* session. This will correct both packet header data and checksums. */ 3713 1.1 christos /* */ 3714 1.1 christos /* This should *ONLY* be used for incoming ICMP error packets to make sure */ 3715 1.1 christos /* a NAT'd ICMP packet gets correctly recognised. */ 3716 1.1 christos /* ------------------------------------------------------------------------ */ 3717 1.1 christos nat_t * 3718 1.2 christos ipf_nat_icmperror(fr_info_t *fin, u_int *nflags, int dir) 3719 1.1 christos { 3720 1.1 christos ipf_main_softc_t *softc = fin->fin_main_soft; 3721 1.1 christos ipf_nat_softc_t *softn = softc->ipf_nat_soft; 3722 1.1 christos u_32_t sum1, sum2, sumd, sumd2; 3723 1.1 christos struct in_addr a1, a2, a3, a4; 3724 1.1 christos int flags, dlen, odst; 3725 1.1 christos icmphdr_t *icmp; 3726 1.1 christos u_short *csump; 3727 1.1 christos tcphdr_t *tcp; 3728 1.1 christos nat_t *nat; 3729 1.1 christos ip_t *oip; 3730 1.1 christos void *dp; 3731 1.1 christos 3732 1.1 christos if ((fin->fin_flx & (FI_SHORT|FI_FRAGBODY))) { 3733 1.1 christos NBUMPSIDED(fin->fin_out, ns_icmp_short); 3734 1.1 christos return NULL; 3735 1.1 christos } 3736 1.1 christos 3737 1.1 christos /* 3738 1.1 christos * ipf_nat_icmperrorlookup() will return NULL for `defective' packets. 3739 1.1 christos */ 3740 1.1 christos if ((fin->fin_v != 4) || !(nat = ipf_nat_icmperrorlookup(fin, dir))) { 3741 1.1 christos NBUMPSIDED(fin->fin_out, ns_icmp_notfound); 3742 1.1 christos return NULL; 3743 1.1 christos } 3744 1.1 christos 3745 1.1 christos tcp = NULL; 3746 1.1 christos csump = NULL; 3747 1.1 christos flags = 0; 3748 1.1 christos sumd2 = 0; 3749 1.1 christos *nflags = IPN_ICMPERR; 3750 1.1 christos icmp = fin->fin_dp; 3751 1.1 christos oip = (ip_t *)&icmp->icmp_ip; 3752 1.1 christos dp = (((char *)oip) + (IP_HL(oip) << 2)); 3753 1.1 christos if (oip->ip_p == IPPROTO_TCP) { 3754 1.1 christos tcp = (tcphdr_t *)dp; 3755 1.1 christos csump = (u_short *)&tcp->th_sum; 3756 1.1 christos flags = IPN_TCP; 3757 1.1 christos } else if (oip->ip_p == IPPROTO_UDP) { 3758 1.1 christos udphdr_t *udp; 3759 1.1 christos 3760 1.1 christos udp = (udphdr_t *)dp; 3761 1.1 christos tcp = (tcphdr_t *)dp; 3762 1.1 christos csump = (u_short *)&udp->uh_sum; 3763 1.1 christos flags = IPN_UDP; 3764 1.1 christos } else if (oip->ip_p == IPPROTO_ICMP) 3765 1.1 christos flags = IPN_ICMPQUERY; 3766 1.1 christos dlen = fin->fin_plen - ((char *)dp - (char *)fin->fin_ip); 3767 1.1 christos 3768 1.1 christos /* 3769 1.1 christos * Need to adjust ICMP header to include the real IP#'s and 3770 1.1 christos * port #'s. Only apply a checksum change relative to the 3771 1.1 christos * IP address change as it will be modified again in ipf_nat_checkout 3772 1.1 christos * for both address and port. Two checksum changes are 3773 1.1 christos * necessary for the two header address changes. Be careful 3774 1.1 christos * to only modify the checksum once for the port # and twice 3775 1.1 christos * for the IP#. 3776 1.1 christos */ 3777 1.1 christos 3778 1.1 christos /* 3779 1.1 christos * Step 1 3780 1.1 christos * Fix the IP addresses in the offending IP packet. You also need 3781 1.1 christos * to adjust the IP header checksum of that offending IP packet. 3782 1.1 christos * 3783 1.1 christos * Normally, you would expect that the ICMP checksum of the 3784 1.1 christos * ICMP error message needs to be adjusted as well for the 3785 1.1 christos * IP address change in oip. 3786 1.1 christos * However, this is a NOP, because the ICMP checksum is 3787 1.1 christos * calculated over the complete ICMP packet, which includes the 3788 1.1 christos * changed oip IP addresses and oip->ip_sum. However, these 3789 1.1 christos * two changes cancel each other out (if the delta for 3790 1.1 christos * the IP address is x, then the delta for ip_sum is minus x), 3791 1.1 christos * so no change in the icmp_cksum is necessary. 3792 1.1 christos * 3793 1.1 christos * Inbound ICMP 3794 1.1 christos * ------------ 3795 1.1 christos * MAP rule, SRC=a,DST=b -> SRC=c,DST=b 3796 1.1 christos * - response to outgoing packet (a,b)=>(c,b) (OIP_SRC=c,OIP_DST=b) 3797 1.1 christos * - OIP_SRC(c)=nat_newsrcip, OIP_DST(b)=nat_newdstip 3798 1.1 christos *=> OIP_SRC(c)=nat_oldsrcip, OIP_DST(b)=nat_olddstip 3799 1.1 christos * 3800 1.1 christos * RDR rule, SRC=a,DST=b -> SRC=a,DST=c 3801 1.1 christos * - response to outgoing packet (c,a)=>(b,a) (OIP_SRC=b,OIP_DST=a) 3802 1.1 christos * - OIP_SRC(b)=nat_olddstip, OIP_DST(a)=nat_oldsrcip 3803 1.1 christos *=> OIP_SRC(b)=nat_newdstip, OIP_DST(a)=nat_newsrcip 3804 1.1 christos * 3805 1.1 christos * REWRITE out rule, SRC=a,DST=b -> SRC=c,DST=d 3806 1.1 christos * - response to outgoing packet (a,b)=>(c,d) (OIP_SRC=c,OIP_DST=d) 3807 1.1 christos * - OIP_SRC(c)=nat_newsrcip, OIP_DST(d)=nat_newdstip 3808 1.1 christos *=> OIP_SRC(c)=nat_oldsrcip, OIP_DST(d)=nat_olddstip 3809 1.1 christos * 3810 1.1 christos * REWRITE in rule, SRC=a,DST=b -> SRC=c,DST=d 3811 1.1 christos * - response to outgoing packet (d,c)=>(b,a) (OIP_SRC=b,OIP_DST=a) 3812 1.1 christos * - OIP_SRC(b)=nat_olddstip, OIP_DST(a)=nat_oldsrcip 3813 1.1 christos *=> OIP_SRC(b)=nat_newdstip, OIP_DST(a)=nat_newsrcip 3814 1.1 christos * 3815 1.1 christos * Outbound ICMP 3816 1.1 christos * ------------- 3817 1.1 christos * MAP rule, SRC=a,DST=b -> SRC=c,DST=b 3818 1.1 christos * - response to incoming packet (b,c)=>(b,a) (OIP_SRC=b,OIP_DST=a) 3819 1.1 christos * - OIP_SRC(b)=nat_olddstip, OIP_DST(a)=nat_oldsrcip 3820 1.1 christos *=> OIP_SRC(b)=nat_newdstip, OIP_DST(a)=nat_newsrcip 3821 1.1 christos * 3822 1.1 christos * RDR rule, SRC=a,DST=b -> SRC=a,DST=c 3823 1.1 christos * - response to incoming packet (a,b)=>(a,c) (OIP_SRC=a,OIP_DST=c) 3824 1.1 christos * - OIP_SRC(a)=nat_newsrcip, OIP_DST(c)=nat_newdstip 3825 1.1 christos *=> OIP_SRC(a)=nat_oldsrcip, OIP_DST(c)=nat_olddstip 3826 1.1 christos * 3827 1.1 christos * REWRITE out rule, SRC=a,DST=b -> SRC=c,DST=d 3828 1.1 christos * - response to incoming packet (d,c)=>(b,a) (OIP_SRC=c,OIP_DST=d) 3829 1.1 christos * - OIP_SRC(c)=nat_olddstip, OIP_DST(d)=nat_oldsrcip 3830 1.1 christos *=> OIP_SRC(b)=nat_newdstip, OIP_DST(a)=nat_newsrcip 3831 1.1 christos * 3832 1.1 christos * REWRITE in rule, SRC=a,DST=b -> SRC=c,DST=d 3833 1.1 christos * - response to incoming packet (a,b)=>(c,d) (OIP_SRC=b,OIP_DST=a) 3834 1.1 christos * - OIP_SRC(b)=nat_newsrcip, OIP_DST(a)=nat_newdstip 3835 1.1 christos *=> OIP_SRC(a)=nat_oldsrcip, OIP_DST(c)=nat_olddstip 3836 1.1 christos */ 3837 1.1 christos 3838 1.1 christos if (((fin->fin_out == 0) && ((nat->nat_redir & NAT_MAP) != 0)) || 3839 1.1 christos ((fin->fin_out == 1) && ((nat->nat_redir & NAT_REDIRECT) != 0))) { 3840 1.1 christos a1.s_addr = ntohl(nat->nat_osrcaddr); 3841 1.1 christos a4.s_addr = ntohl(oip->ip_src.s_addr); 3842 1.1 christos a3.s_addr = ntohl(nat->nat_odstaddr); 3843 1.1 christos a2.s_addr = ntohl(oip->ip_dst.s_addr); 3844 1.1 christos oip->ip_src.s_addr = htonl(a1.s_addr); 3845 1.1 christos oip->ip_dst.s_addr = htonl(a3.s_addr); 3846 1.1 christos odst = 1; 3847 1.1 christos } else { 3848 1.1 christos a1.s_addr = ntohl(nat->nat_ndstaddr); 3849 1.1 christos a2.s_addr = ntohl(oip->ip_dst.s_addr); 3850 1.1 christos a3.s_addr = ntohl(nat->nat_nsrcaddr); 3851 1.1 christos a4.s_addr = ntohl(oip->ip_src.s_addr); 3852 1.1 christos oip->ip_dst.s_addr = htonl(a3.s_addr); 3853 1.1 christos oip->ip_src.s_addr = htonl(a1.s_addr); 3854 1.1 christos odst = 0; 3855 1.1 christos } 3856 1.3 darrenr sum1 = 0; 3857 1.3 darrenr sum2 = 0; 3858 1.1 christos sumd = 0; 3859 1.3 darrenr CALC_SUMD(a2.s_addr, a3.s_addr, sum1); 3860 1.3 darrenr CALC_SUMD(a4.s_addr, a1.s_addr, sum2); 3861 1.3 darrenr sumd = sum2 + sum1; 3862 1.3 darrenr if (sumd != 0) 3863 1.1 christos ipf_fix_datacksum(&oip->ip_sum, sumd); 3864 1.1 christos 3865 1.1 christos sumd2 = sumd; 3866 1.1 christos sum1 = 0; 3867 1.1 christos sum2 = 0; 3868 1.1 christos 3869 1.1 christos /* 3870 1.1 christos * Fix UDP pseudo header checksum to compensate for the 3871 1.1 christos * IP address change. 3872 1.1 christos */ 3873 1.1 christos if (((flags & IPN_TCPUDP) != 0) && (dlen >= 4)) { 3874 1.3 darrenr u_32_t sum3, sum4, sumt; 3875 1.3 darrenr 3876 1.1 christos /* 3877 1.1 christos * Step 2 : 3878 1.1 christos * For offending TCP/UDP IP packets, translate the ports as 3879 1.1 christos * well, based on the NAT specification. Of course such 3880 1.1 christos * a change may be reflected in the ICMP checksum as well. 3881 1.1 christos * 3882 1.1 christos * Since the port fields are part of the TCP/UDP checksum 3883 1.1 christos * of the offending IP packet, you need to adjust that checksum 3884 1.1 christos * as well... except that the change in the port numbers should 3885 1.1 christos * be offset by the checksum change. However, the TCP/UDP 3886 1.1 christos * checksum will also need to change if there has been an 3887 1.1 christos * IP address change. 3888 1.1 christos */ 3889 1.1 christos if (odst == 1) { 3890 1.1 christos sum1 = ntohs(nat->nat_osport); 3891 1.1 christos sum4 = ntohs(tcp->th_sport); 3892 1.1 christos sum3 = ntohs(nat->nat_odport); 3893 1.1 christos sum2 = ntohs(tcp->th_dport); 3894 1.1 christos 3895 1.1 christos tcp->th_sport = htons(sum1); 3896 1.1 christos tcp->th_dport = htons(sum3); 3897 1.1 christos } else { 3898 1.1 christos sum1 = ntohs(nat->nat_ndport); 3899 1.1 christos sum2 = ntohs(tcp->th_dport); 3900 1.1 christos sum3 = ntohs(nat->nat_nsport); 3901 1.1 christos sum4 = ntohs(tcp->th_sport); 3902 1.1 christos 3903 1.1 christos tcp->th_dport = htons(sum3); 3904 1.1 christos tcp->th_sport = htons(sum1); 3905 1.1 christos } 3906 1.3 darrenr CALC_SUMD(sum4, sum1, sumt); 3907 1.3 darrenr sumd += sumt; 3908 1.3 darrenr CALC_SUMD(sum2, sum3, sumt); 3909 1.3 darrenr sumd += sumt; 3910 1.1 christos 3911 1.1 christos if (sumd != 0 || sumd2 != 0) { 3912 1.1 christos /* 3913 1.1 christos * At this point, sumd is the delta to apply to the 3914 1.1 christos * TCP/UDP header, given the changes in both the IP 3915 1.1 christos * address and the ports and sumd2 is the delta to 3916 1.1 christos * apply to the ICMP header, given the IP address 3917 1.1 christos * change delta that may need to be applied to the 3918 1.1 christos * TCP/UDP checksum instead. 3919 1.1 christos * 3920 1.1 christos * If we will both the IP and TCP/UDP checksums 3921 1.1 christos * then the ICMP checksum changes by the address 3922 1.1 christos * delta applied to the TCP/UDP checksum. If we 3923 1.1 christos * do not change the TCP/UDP checksum them we 3924 1.1 christos * apply the delta in ports to the ICMP checksum. 3925 1.1 christos */ 3926 1.1 christos if (oip->ip_p == IPPROTO_UDP) { 3927 1.1 christos if ((dlen >= 8) && (*csump != 0)) { 3928 1.1 christos ipf_fix_datacksum(csump, sumd); 3929 1.1 christos } else { 3930 1.3 darrenr CALC_SUMD(sum1, sum4, sumd2); 3931 1.3 darrenr CALC_SUMD(sum3, sum2, sumt); 3932 1.3 darrenr sumd2 += sumt; 3933 1.1 christos } 3934 1.1 christos } else if (oip->ip_p == IPPROTO_TCP) { 3935 1.1 christos if (dlen >= 18) { 3936 1.1 christos ipf_fix_datacksum(csump, sumd); 3937 1.1 christos } else { 3938 1.3 darrenr CALC_SUMD(sum1, sum4, sumd2); 3939 1.3 darrenr CALC_SUMD(sum3, sum2, sumt); 3940 1.3 darrenr sumd2 += sumt; 3941 1.1 christos } 3942 1.1 christos } 3943 1.1 christos if (sumd2 != 0) { 3944 1.1 christos sumd2 = (sumd2 & 0xffff) + (sumd2 >> 16); 3945 1.1 christos sumd2 = (sumd2 & 0xffff) + (sumd2 >> 16); 3946 1.1 christos sumd2 = (sumd2 & 0xffff) + (sumd2 >> 16); 3947 1.3 darrenr ipf_fix_incksum(0, &icmp->icmp_cksum, sumd2, 0); 3948 1.1 christos } 3949 1.1 christos } 3950 1.1 christos } else if (((flags & IPN_ICMPQUERY) != 0) && (dlen >= 8)) { 3951 1.1 christos icmphdr_t *orgicmp; 3952 1.1 christos 3953 1.1 christos /* 3954 1.1 christos * XXX - what if this is bogus hl and we go off the end ? 3955 1.1 christos * In this case, ipf_nat_icmperrorlookup() will have 3956 1.1 christos * returned NULL. 3957 1.1 christos */ 3958 1.1 christos orgicmp = (icmphdr_t *)dp; 3959 1.1 christos 3960 1.1 christos if (odst == 1) { 3961 1.1 christos if (orgicmp->icmp_id != nat->nat_osport) { 3962 1.1 christos 3963 1.1 christos /* 3964 1.1 christos * Fix ICMP checksum (of the offening ICMP 3965 1.1 christos * query packet) to compensate the change 3966 1.1 christos * in the ICMP id of the offending ICMP 3967 1.1 christos * packet. 3968 1.1 christos * 3969 1.1 christos * Since you modify orgicmp->icmp_id with 3970 1.1 christos * a delta (say x) and you compensate that 3971 1.1 christos * in origicmp->icmp_cksum with a delta 3972 1.1 christos * minus x, you don't have to adjust the 3973 1.1 christos * overall icmp->icmp_cksum 3974 1.1 christos */ 3975 1.1 christos sum1 = ntohs(orgicmp->icmp_id); 3976 1.3 darrenr sum2 = ntohs(nat->nat_oicmpid); 3977 1.1 christos CALC_SUMD(sum1, sum2, sumd); 3978 1.1 christos orgicmp->icmp_id = nat->nat_oicmpid; 3979 1.1 christos ipf_fix_datacksum(&orgicmp->icmp_cksum, sumd); 3980 1.1 christos } 3981 1.1 christos } /* nat_dir == NAT_INBOUND is impossible for icmp queries */ 3982 1.1 christos } 3983 1.1 christos return nat; 3984 1.1 christos } 3985 1.1 christos 3986 1.1 christos 3987 1.1 christos /* 3988 1.1 christos * MAP-IN MAP-OUT RDR-IN RDR-OUT 3989 1.1 christos * osrc X == src == src X 3990 1.1 christos * odst X == dst == dst X 3991 1.1 christos * nsrc == dst X X == dst 3992 1.1 christos * ndst == src X X == src 3993 1.1 christos * MAP = NAT_OUTBOUND, RDR = NAT_INBOUND 3994 1.1 christos */ 3995 1.1 christos /* 3996 1.1 christos * NB: these lookups don't lock access to the list, it assumed that it has 3997 1.1 christos * already been done! 3998 1.1 christos */ 3999 1.1 christos /* ------------------------------------------------------------------------ */ 4000 1.1 christos /* Function: ipf_nat_inlookup */ 4001 1.1 christos /* Returns: nat_t* - NULL == no match, */ 4002 1.1 christos /* else pointer to matching NAT entry */ 4003 1.1 christos /* Parameters: fin(I) - pointer to packet information */ 4004 1.1 christos /* flags(I) - NAT flags for this packet */ 4005 1.1 christos /* p(I) - protocol for this packet */ 4006 1.1 christos /* src(I) - source IP address */ 4007 1.1 christos /* mapdst(I) - destination IP address */ 4008 1.1 christos /* */ 4009 1.1 christos /* Lookup a nat entry based on the mapped destination ip address/port and */ 4010 1.1 christos /* real source address/port. We use this lookup when receiving a packet, */ 4011 1.1 christos /* we're looking for a table entry, based on the destination address. */ 4012 1.1 christos /* */ 4013 1.1 christos /* NOTE: THE PACKET BEING CHECKED (IF FOUND) HAS A MAPPING ALREADY. */ 4014 1.1 christos /* */ 4015 1.1 christos /* NOTE: IT IS ASSUMED THAT IS ONLY HELD WITH A READ LOCK WHEN */ 4016 1.1 christos /* THIS FUNCTION IS CALLED WITH NAT_SEARCH SET IN nflags. */ 4017 1.1 christos /* */ 4018 1.1 christos /* flags -> relevant are IPN_UDP/IPN_TCP/IPN_ICMPQUERY that indicate if */ 4019 1.1 christos /* the packet is of said protocol */ 4020 1.1 christos /* ------------------------------------------------------------------------ */ 4021 1.1 christos nat_t * 4022 1.2 christos ipf_nat_inlookup(fr_info_t *fin, u_int flags, u_int p, struct in_addr src, 4023 1.2 christos struct in_addr mapdst) 4024 1.1 christos { 4025 1.1 christos ipf_main_softc_t *softc = fin->fin_main_soft; 4026 1.1 christos ipf_nat_softc_t *softn = softc->ipf_nat_soft; 4027 1.1 christos u_short sport, dport; 4028 1.1 christos ipnat_t *ipn; 4029 1.1 christos nat_t *nat; 4030 1.1 christos int nflags; 4031 1.1 christos u_32_t dst; 4032 1.1 christos void *ifp; 4033 1.1 christos u_int hv, rhv; 4034 1.1 christos 4035 1.1 christos ifp = fin->fin_ifp; 4036 1.1 christos dst = mapdst.s_addr; 4037 1.1 christos 4038 1.1 christos switch (p) 4039 1.1 christos { 4040 1.1 christos case IPPROTO_TCP : 4041 1.1 christos case IPPROTO_UDP : 4042 1.1 christos sport = htons(fin->fin_data[0]); 4043 1.1 christos dport = htons(fin->fin_data[1]); 4044 1.1 christos break; 4045 1.1 christos case IPPROTO_ICMP : 4046 1.16 khorben sport = 0; 4047 1.16 khorben dport = fin->fin_data[1]; 4048 1.1 christos break; 4049 1.1 christos default : 4050 1.1 christos sport = 0; 4051 1.1 christos dport = 0; 4052 1.1 christos break; 4053 1.1 christos } 4054 1.1 christos 4055 1.1 christos 4056 1.1 christos if ((flags & SI_WILDP) != 0) 4057 1.1 christos goto find_in_wild_ports; 4058 1.1 christos 4059 1.1 christos rhv = NAT_HASH_FN(dst, dport, 0xffffffff); 4060 1.1 christos rhv = NAT_HASH_FN(src.s_addr, rhv + sport, 0xffffffff); 4061 1.1 christos hv = rhv % softn->ipf_nat_table_sz; 4062 1.1 christos nat = softn->ipf_nat_table[1][hv]; 4063 1.1 christos /* TRACE dst, dport, src, sport, hv, nat */ 4064 1.1 christos 4065 1.1 christos for (; nat; nat = nat->nat_hnext[1]) { 4066 1.1 christos if (nat->nat_ifps[0] != NULL) { 4067 1.1 christos if ((ifp != NULL) && (ifp != nat->nat_ifps[0])) 4068 1.1 christos continue; 4069 1.1 christos } 4070 1.1 christos 4071 1.1 christos if (nat->nat_pr[0] != p) 4072 1.1 christos continue; 4073 1.1 christos 4074 1.1 christos switch (nat->nat_dir) 4075 1.1 christos { 4076 1.1 christos case NAT_INBOUND : 4077 1.1 christos case NAT_DIVERTIN : 4078 1.1 christos if (nat->nat_v[0] != 4) 4079 1.1 christos continue; 4080 1.1 christos if (nat->nat_osrcaddr != src.s_addr || 4081 1.1 christos nat->nat_odstaddr != dst) 4082 1.1 christos continue; 4083 1.1 christos if ((nat->nat_flags & IPN_TCPUDP) != 0) { 4084 1.1 christos if (nat->nat_osport != sport) 4085 1.1 christos continue; 4086 1.1 christos if (nat->nat_odport != dport) 4087 1.1 christos continue; 4088 1.1 christos 4089 1.1 christos } else if (p == IPPROTO_ICMP) { 4090 1.13 darrenr if (nat->nat_oicmpid != dport) { 4091 1.1 christos continue; 4092 1.1 christos } 4093 1.1 christos } 4094 1.1 christos break; 4095 1.1 christos case NAT_DIVERTOUT : 4096 1.1 christos if (nat->nat_dlocal) 4097 1.1 christos continue; 4098 1.21 mrg /* FALLTHROUGH */ 4099 1.1 christos case NAT_OUTBOUND : 4100 1.1 christos if (nat->nat_v[1] != 4) 4101 1.1 christos continue; 4102 1.1 christos if (nat->nat_dlocal) 4103 1.1 christos continue; 4104 1.1 christos if (nat->nat_dlocal) 4105 1.1 christos continue; 4106 1.1 christos if (nat->nat_ndstaddr != src.s_addr || 4107 1.1 christos nat->nat_nsrcaddr != dst) 4108 1.1 christos continue; 4109 1.1 christos if ((nat->nat_flags & IPN_TCPUDP) != 0) { 4110 1.1 christos if (nat->nat_ndport != sport) 4111 1.1 christos continue; 4112 1.1 christos if (nat->nat_nsport != dport) 4113 1.1 christos continue; 4114 1.1 christos 4115 1.1 christos } else if (p == IPPROTO_ICMP) { 4116 1.13 darrenr if (nat->nat_nicmpid != dport) { 4117 1.1 christos continue; 4118 1.1 christos } 4119 1.1 christos } 4120 1.1 christos break; 4121 1.1 christos } 4122 1.1 christos 4123 1.1 christos 4124 1.1 christos if ((nat->nat_flags & IPN_TCPUDP) != 0) { 4125 1.1 christos ipn = nat->nat_ptr; 4126 1.1 christos if ((ipn != NULL) && (nat->nat_aps != NULL)) 4127 1.1 christos if (ipf_proxy_match(fin, nat) != 0) 4128 1.1 christos continue; 4129 1.1 christos } 4130 1.1 christos if ((nat->nat_ifps[0] == NULL) && (ifp != NULL)) { 4131 1.1 christos nat->nat_ifps[0] = ifp; 4132 1.1 christos nat->nat_mtu[0] = GETIFMTU_4(ifp); 4133 1.1 christos } 4134 1.1 christos return nat; 4135 1.1 christos } 4136 1.1 christos 4137 1.1 christos /* 4138 1.1 christos * So if we didn't find it but there are wildcard members in the hash 4139 1.1 christos * table, go back and look for them. We do this search and update here 4140 1.1 christos * because it is modifying the NAT table and we want to do this only 4141 1.1 christos * for the first packet that matches. The exception, of course, is 4142 1.1 christos * for "dummy" (FI_IGNORE) lookups. 4143 1.1 christos */ 4144 1.1 christos find_in_wild_ports: 4145 1.1 christos if (!(flags & NAT_TCPUDP) || !(flags & NAT_SEARCH)) { 4146 1.1 christos NBUMPSIDEX(0, ns_lookup_miss, ns_lookup_miss_0); 4147 1.1 christos return NULL; 4148 1.1 christos } 4149 1.3 darrenr if (softn->ipf_nat_stats.ns_wilds == 0 || (fin->fin_flx & FI_NOWILD)) { 4150 1.1 christos NBUMPSIDEX(0, ns_lookup_nowild, ns_lookup_nowild_0); 4151 1.1 christos return NULL; 4152 1.1 christos } 4153 1.1 christos 4154 1.1 christos RWLOCK_EXIT(&softc->ipf_nat); 4155 1.1 christos 4156 1.1 christos hv = NAT_HASH_FN(dst, 0, 0xffffffff); 4157 1.1 christos hv = NAT_HASH_FN(src.s_addr, hv, softn->ipf_nat_table_sz); 4158 1.1 christos WRITE_ENTER(&softc->ipf_nat); 4159 1.1 christos 4160 1.1 christos nat = softn->ipf_nat_table[1][hv]; 4161 1.1 christos /* TRACE dst, src, hv, nat */ 4162 1.1 christos for (; nat; nat = nat->nat_hnext[1]) { 4163 1.1 christos if (nat->nat_ifps[0] != NULL) { 4164 1.1 christos if ((ifp != NULL) && (ifp != nat->nat_ifps[0])) 4165 1.1 christos continue; 4166 1.1 christos } 4167 1.1 christos 4168 1.1 christos if (nat->nat_pr[0] != fin->fin_p) 4169 1.1 christos continue; 4170 1.1 christos 4171 1.1 christos switch (nat->nat_dir & (NAT_INBOUND|NAT_OUTBOUND)) 4172 1.1 christos { 4173 1.1 christos case NAT_INBOUND : 4174 1.1 christos if (nat->nat_v[0] != 4) 4175 1.1 christos continue; 4176 1.1 christos if (nat->nat_osrcaddr != src.s_addr || 4177 1.1 christos nat->nat_odstaddr != dst) 4178 1.1 christos continue; 4179 1.1 christos break; 4180 1.1 christos case NAT_OUTBOUND : 4181 1.1 christos if (nat->nat_v[1] != 4) 4182 1.1 christos continue; 4183 1.1 christos if (nat->nat_ndstaddr != src.s_addr || 4184 1.1 christos nat->nat_nsrcaddr != dst) 4185 1.1 christos continue; 4186 1.1 christos break; 4187 1.1 christos } 4188 1.1 christos 4189 1.1 christos nflags = nat->nat_flags; 4190 1.1 christos if (!(nflags & (NAT_TCPUDP|SI_WILDP))) 4191 1.1 christos continue; 4192 1.1 christos 4193 1.1 christos if (ipf_nat_wildok(nat, (int)sport, (int)dport, nflags, 4194 1.1 christos NAT_INBOUND) == 1) { 4195 1.1 christos if ((fin->fin_flx & FI_IGNORE) != 0) 4196 1.1 christos break; 4197 1.1 christos if ((nflags & SI_CLONE) != 0) { 4198 1.1 christos nat = ipf_nat_clone(fin, nat); 4199 1.1 christos if (nat == NULL) 4200 1.1 christos break; 4201 1.1 christos } else { 4202 1.1 christos MUTEX_ENTER(&softn->ipf_nat_new); 4203 1.1 christos softn->ipf_nat_stats.ns_wilds--; 4204 1.1 christos MUTEX_EXIT(&softn->ipf_nat_new); 4205 1.1 christos } 4206 1.1 christos 4207 1.1 christos if (nat->nat_dir == NAT_INBOUND) { 4208 1.1 christos if (nat->nat_osport == 0) { 4209 1.1 christos nat->nat_osport = sport; 4210 1.1 christos nat->nat_nsport = sport; 4211 1.1 christos } 4212 1.1 christos if (nat->nat_odport == 0) { 4213 1.1 christos nat->nat_odport = dport; 4214 1.1 christos nat->nat_ndport = dport; 4215 1.1 christos } 4216 1.1 christos } else if (nat->nat_dir == NAT_OUTBOUND) { 4217 1.1 christos if (nat->nat_osport == 0) { 4218 1.1 christos nat->nat_osport = dport; 4219 1.1 christos nat->nat_nsport = dport; 4220 1.1 christos } 4221 1.1 christos if (nat->nat_odport == 0) { 4222 1.1 christos nat->nat_odport = sport; 4223 1.1 christos nat->nat_ndport = sport; 4224 1.1 christos } 4225 1.1 christos } 4226 1.1 christos if ((nat->nat_ifps[0] == NULL) && (ifp != NULL)) { 4227 1.1 christos nat->nat_ifps[0] = ifp; 4228 1.1 christos nat->nat_mtu[0] = GETIFMTU_4(ifp); 4229 1.1 christos } 4230 1.1 christos nat->nat_flags &= ~(SI_W_DPORT|SI_W_SPORT); 4231 1.1 christos ipf_nat_tabmove(softn, nat); 4232 1.1 christos break; 4233 1.1 christos } 4234 1.1 christos } 4235 1.1 christos 4236 1.1 christos MUTEX_DOWNGRADE(&softc->ipf_nat); 4237 1.1 christos 4238 1.1 christos if (nat == NULL) { 4239 1.1 christos NBUMPSIDE(0, ns_lookup_miss); 4240 1.1 christos } 4241 1.1 christos return nat; 4242 1.1 christos } 4243 1.1 christos 4244 1.1 christos 4245 1.1 christos /* ------------------------------------------------------------------------ */ 4246 1.1 christos /* Function: ipf_nat_tabmove */ 4247 1.1 christos /* Returns: Nil */ 4248 1.3 darrenr /* Parameters: softn(I) - pointer to NAT context structure */ 4249 1.3 darrenr /* nat(I) - pointer to NAT structure */ 4250 1.1 christos /* Write Lock: ipf_nat */ 4251 1.1 christos /* */ 4252 1.1 christos /* This function is only called for TCP/UDP NAT table entries where the */ 4253 1.1 christos /* original was placed in the table without hashing on the ports and we now */ 4254 1.1 christos /* want to include hashing on port numbers. */ 4255 1.1 christos /* ------------------------------------------------------------------------ */ 4256 1.1 christos static void 4257 1.2 christos ipf_nat_tabmove(ipf_nat_softc_t *softn, nat_t *nat) 4258 1.1 christos { 4259 1.1 christos u_int hv0, hv1, rhv0, rhv1; 4260 1.1 christos natstat_t *nsp; 4261 1.1 christos nat_t **natp; 4262 1.1 christos 4263 1.1 christos if (nat->nat_flags & SI_CLONE) 4264 1.1 christos return; 4265 1.1 christos 4266 1.1 christos nsp = &softn->ipf_nat_stats; 4267 1.1 christos /* 4268 1.1 christos * Remove the NAT entry from the old location 4269 1.1 christos */ 4270 1.1 christos if (nat->nat_hnext[0]) 4271 1.1 christos nat->nat_hnext[0]->nat_phnext[0] = nat->nat_phnext[0]; 4272 1.1 christos *nat->nat_phnext[0] = nat->nat_hnext[0]; 4273 1.8 christos hv0 = nat->nat_hv[0] % softn->ipf_nat_table_sz; 4274 1.9 christos hv1 = nat->nat_hv[1] % softn->ipf_nat_table_sz; 4275 1.9 christos 4276 1.9 christos ASSERT(nsp->ns_side[0].ns_bucketlen[hv0] > 0); 4277 1.8 christos nsp->ns_side[0].ns_bucketlen[hv0]--; 4278 1.1 christos 4279 1.1 christos if (nat->nat_hnext[1]) 4280 1.1 christos nat->nat_hnext[1]->nat_phnext[1] = nat->nat_phnext[1]; 4281 1.1 christos *nat->nat_phnext[1] = nat->nat_hnext[1]; 4282 1.9 christos ASSERT(nsp->ns_side[1].ns_bucketlen[hv1] > 0); 4283 1.8 christos nsp->ns_side[1].ns_bucketlen[hv1]--; 4284 1.1 christos 4285 1.1 christos /* 4286 1.1 christos * Add into the NAT table in the new position 4287 1.1 christos */ 4288 1.1 christos rhv0 = NAT_HASH_FN(nat->nat_osrcaddr, nat->nat_osport, 0xffffffff); 4289 1.1 christos rhv0 = NAT_HASH_FN(nat->nat_odstaddr, rhv0 + nat->nat_odport, 4290 1.1 christos 0xffffffff); 4291 1.1 christos rhv1 = NAT_HASH_FN(nat->nat_nsrcaddr, nat->nat_nsport, 0xffffffff); 4292 1.1 christos rhv1 = NAT_HASH_FN(nat->nat_ndstaddr, rhv1 + nat->nat_ndport, 4293 1.1 christos 0xffffffff); 4294 1.1 christos 4295 1.9 christos if ((nat->nat_dir & NAT_OUTBOUND) == NAT_OUTBOUND) { 4296 1.9 christos nat->nat_hv[0] = rhv0; 4297 1.9 christos nat->nat_hv[1] = rhv1; 4298 1.9 christos } else { 4299 1.9 christos nat->nat_hv[0] = rhv1; 4300 1.9 christos nat->nat_hv[1] = rhv0; 4301 1.9 christos } 4302 1.1 christos 4303 1.9 christos hv0 = nat->nat_hv[0] % softn->ipf_nat_table_sz; 4304 1.9 christos hv1 = nat->nat_hv[1] % softn->ipf_nat_table_sz; 4305 1.1 christos 4306 1.1 christos /* TRACE nat_osrcaddr, nat_osport, nat_odstaddr, nat_odport, hv0 */ 4307 1.1 christos /* TRACE nat_nsrcaddr, nat_nsport, nat_ndstaddr, nat_ndport, hv1 */ 4308 1.1 christos 4309 1.1 christos natp = &softn->ipf_nat_table[0][hv0]; 4310 1.1 christos if (*natp) 4311 1.1 christos (*natp)->nat_phnext[0] = &nat->nat_hnext[0]; 4312 1.1 christos nat->nat_phnext[0] = natp; 4313 1.1 christos nat->nat_hnext[0] = *natp; 4314 1.1 christos *natp = nat; 4315 1.1 christos nsp->ns_side[0].ns_bucketlen[hv0]++; 4316 1.1 christos 4317 1.1 christos natp = &softn->ipf_nat_table[1][hv1]; 4318 1.1 christos if (*natp) 4319 1.1 christos (*natp)->nat_phnext[1] = &nat->nat_hnext[1]; 4320 1.1 christos nat->nat_phnext[1] = natp; 4321 1.1 christos nat->nat_hnext[1] = *natp; 4322 1.1 christos *natp = nat; 4323 1.1 christos nsp->ns_side[1].ns_bucketlen[hv1]++; 4324 1.1 christos } 4325 1.1 christos 4326 1.1 christos 4327 1.1 christos /* ------------------------------------------------------------------------ */ 4328 1.1 christos /* Function: ipf_nat_outlookup */ 4329 1.1 christos /* Returns: nat_t* - NULL == no match, */ 4330 1.1 christos /* else pointer to matching NAT entry */ 4331 1.1 christos /* Parameters: fin(I) - pointer to packet information */ 4332 1.1 christos /* flags(I) - NAT flags for this packet */ 4333 1.1 christos /* p(I) - protocol for this packet */ 4334 1.1 christos /* src(I) - source IP address */ 4335 1.1 christos /* dst(I) - destination IP address */ 4336 1.1 christos /* rw(I) - 1 == write lock on held, 0 == read lock. */ 4337 1.1 christos /* */ 4338 1.1 christos /* Lookup a nat entry based on the source 'real' ip address/port and */ 4339 1.1 christos /* destination address/port. We use this lookup when sending a packet out, */ 4340 1.1 christos /* we're looking for a table entry, based on the source address. */ 4341 1.1 christos /* */ 4342 1.1 christos /* NOTE: THE PACKET BEING CHECKED (IF FOUND) HAS A MAPPING ALREADY. */ 4343 1.1 christos /* */ 4344 1.1 christos /* NOTE: IT IS ASSUMED THAT IS ONLY HELD WITH A READ LOCK WHEN */ 4345 1.1 christos /* THIS FUNCTION IS CALLED WITH NAT_SEARCH SET IN nflags. */ 4346 1.1 christos /* */ 4347 1.1 christos /* flags -> relevant are IPN_UDP/IPN_TCP/IPN_ICMPQUERY that indicate if */ 4348 1.1 christos /* the packet is of said protocol */ 4349 1.1 christos /* ------------------------------------------------------------------------ */ 4350 1.1 christos nat_t * 4351 1.2 christos ipf_nat_outlookup(fr_info_t *fin, u_int flags, u_int p, struct in_addr src, 4352 1.2 christos struct in_addr dst) 4353 1.1 christos { 4354 1.1 christos ipf_main_softc_t *softc = fin->fin_main_soft; 4355 1.1 christos ipf_nat_softc_t *softn = softc->ipf_nat_soft; 4356 1.1 christos u_short sport, dport; 4357 1.1 christos ipnat_t *ipn; 4358 1.1 christos nat_t *nat; 4359 1.1 christos void *ifp; 4360 1.1 christos u_int hv; 4361 1.1 christos 4362 1.1 christos ifp = fin->fin_ifp; 4363 1.1 christos 4364 1.1 christos switch (p) 4365 1.1 christos { 4366 1.1 christos case IPPROTO_TCP : 4367 1.1 christos case IPPROTO_UDP : 4368 1.1 christos sport = htons(fin->fin_data[0]); 4369 1.1 christos dport = htons(fin->fin_data[1]); 4370 1.1 christos break; 4371 1.1 christos case IPPROTO_ICMP : 4372 1.16 khorben sport = 0; 4373 1.16 khorben dport = fin->fin_data[1]; 4374 1.1 christos break; 4375 1.1 christos default : 4376 1.16 khorben sport = 0; 4377 1.16 khorben dport = 0; 4378 1.1 christos break; 4379 1.1 christos } 4380 1.1 christos 4381 1.1 christos if ((flags & SI_WILDP) != 0) 4382 1.1 christos goto find_out_wild_ports; 4383 1.1 christos 4384 1.1 christos hv = NAT_HASH_FN(src.s_addr, sport, 0xffffffff); 4385 1.1 christos hv = NAT_HASH_FN(dst.s_addr, hv + dport, softn->ipf_nat_table_sz); 4386 1.1 christos nat = softn->ipf_nat_table[0][hv]; 4387 1.1 christos 4388 1.1 christos /* TRACE src, sport, dst, dport, hv, nat */ 4389 1.1 christos 4390 1.1 christos for (; nat; nat = nat->nat_hnext[0]) { 4391 1.1 christos if (nat->nat_ifps[1] != NULL) { 4392 1.1 christos if ((ifp != NULL) && (ifp != nat->nat_ifps[1])) 4393 1.1 christos continue; 4394 1.1 christos } 4395 1.1 christos 4396 1.1 christos if (nat->nat_pr[1] != p) 4397 1.1 christos continue; 4398 1.1 christos 4399 1.1 christos switch (nat->nat_dir) 4400 1.1 christos { 4401 1.1 christos case NAT_INBOUND : 4402 1.1 christos case NAT_DIVERTIN : 4403 1.1 christos if (nat->nat_v[1] != 4) 4404 1.1 christos continue; 4405 1.1 christos if (nat->nat_ndstaddr != src.s_addr || 4406 1.1 christos nat->nat_nsrcaddr != dst.s_addr) 4407 1.1 christos continue; 4408 1.1 christos 4409 1.1 christos if ((nat->nat_flags & IPN_TCPUDP) != 0) { 4410 1.1 christos if (nat->nat_ndport != sport) 4411 1.1 christos continue; 4412 1.1 christos if (nat->nat_nsport != dport) 4413 1.1 christos continue; 4414 1.1 christos 4415 1.1 christos } else if (p == IPPROTO_ICMP) { 4416 1.13 darrenr if (nat->nat_nicmpid != dport) { 4417 1.1 christos continue; 4418 1.1 christos } 4419 1.1 christos } 4420 1.1 christos break; 4421 1.1 christos case NAT_OUTBOUND : 4422 1.1 christos case NAT_DIVERTOUT : 4423 1.1 christos if (nat->nat_v[0] != 4) 4424 1.1 christos continue; 4425 1.1 christos if (nat->nat_osrcaddr != src.s_addr || 4426 1.1 christos nat->nat_odstaddr != dst.s_addr) 4427 1.1 christos continue; 4428 1.1 christos 4429 1.1 christos if ((nat->nat_flags & IPN_TCPUDP) != 0) { 4430 1.1 christos if (nat->nat_odport != dport) 4431 1.1 christos continue; 4432 1.1 christos if (nat->nat_osport != sport) 4433 1.1 christos continue; 4434 1.1 christos 4435 1.1 christos } else if (p == IPPROTO_ICMP) { 4436 1.13 darrenr if (nat->nat_oicmpid != dport) { 4437 1.1 christos continue; 4438 1.1 christos } 4439 1.1 christos } 4440 1.1 christos break; 4441 1.1 christos } 4442 1.1 christos 4443 1.1 christos ipn = nat->nat_ptr; 4444 1.1 christos if ((ipn != NULL) && (nat->nat_aps != NULL)) 4445 1.1 christos if (ipf_proxy_match(fin, nat) != 0) 4446 1.1 christos continue; 4447 1.1 christos 4448 1.1 christos if ((nat->nat_ifps[1] == NULL) && (ifp != NULL)) { 4449 1.1 christos nat->nat_ifps[1] = ifp; 4450 1.1 christos nat->nat_mtu[1] = GETIFMTU_4(ifp); 4451 1.1 christos } 4452 1.1 christos return nat; 4453 1.1 christos } 4454 1.1 christos 4455 1.1 christos /* 4456 1.1 christos * So if we didn't find it but there are wildcard members in the hash 4457 1.1 christos * table, go back and look for them. We do this search and update here 4458 1.1 christos * because it is modifying the NAT table and we want to do this only 4459 1.1 christos * for the first packet that matches. The exception, of course, is 4460 1.1 christos * for "dummy" (FI_IGNORE) lookups. 4461 1.1 christos */ 4462 1.1 christos find_out_wild_ports: 4463 1.1 christos if (!(flags & NAT_TCPUDP) || !(flags & NAT_SEARCH)) { 4464 1.1 christos NBUMPSIDEX(1, ns_lookup_miss, ns_lookup_miss_1); 4465 1.1 christos return NULL; 4466 1.1 christos } 4467 1.3 darrenr if (softn->ipf_nat_stats.ns_wilds == 0 || (fin->fin_flx & FI_NOWILD)) { 4468 1.1 christos NBUMPSIDEX(1, ns_lookup_nowild, ns_lookup_nowild_1); 4469 1.1 christos return NULL; 4470 1.1 christos } 4471 1.1 christos 4472 1.1 christos RWLOCK_EXIT(&softc->ipf_nat); 4473 1.1 christos 4474 1.1 christos hv = NAT_HASH_FN(src.s_addr, 0, 0xffffffff); 4475 1.1 christos hv = NAT_HASH_FN(dst.s_addr, hv, softn->ipf_nat_table_sz); 4476 1.1 christos 4477 1.1 christos WRITE_ENTER(&softc->ipf_nat); 4478 1.1 christos 4479 1.1 christos nat = softn->ipf_nat_table[0][hv]; 4480 1.1 christos for (; nat; nat = nat->nat_hnext[0]) { 4481 1.1 christos if (nat->nat_ifps[1] != NULL) { 4482 1.1 christos if ((ifp != NULL) && (ifp != nat->nat_ifps[1])) 4483 1.1 christos continue; 4484 1.1 christos } 4485 1.1 christos 4486 1.1 christos if (nat->nat_pr[1] != fin->fin_p) 4487 1.1 christos continue; 4488 1.1 christos 4489 1.1 christos switch (nat->nat_dir & (NAT_INBOUND|NAT_OUTBOUND)) 4490 1.1 christos { 4491 1.1 christos case NAT_INBOUND : 4492 1.1 christos if (nat->nat_v[1] != 4) 4493 1.1 christos continue; 4494 1.1 christos if (nat->nat_ndstaddr != src.s_addr || 4495 1.1 christos nat->nat_nsrcaddr != dst.s_addr) 4496 1.1 christos continue; 4497 1.1 christos break; 4498 1.1 christos case NAT_OUTBOUND : 4499 1.1 christos if (nat->nat_v[0] != 4) 4500 1.1 christos continue; 4501 1.1 christos if (nat->nat_osrcaddr != src.s_addr || 4502 1.1 christos nat->nat_odstaddr != dst.s_addr) 4503 1.1 christos continue; 4504 1.1 christos break; 4505 1.1 christos } 4506 1.1 christos 4507 1.1 christos if (!(nat->nat_flags & (NAT_TCPUDP|SI_WILDP))) 4508 1.1 christos continue; 4509 1.1 christos 4510 1.1 christos if (ipf_nat_wildok(nat, (int)sport, (int)dport, nat->nat_flags, 4511 1.1 christos NAT_OUTBOUND) == 1) { 4512 1.1 christos if ((fin->fin_flx & FI_IGNORE) != 0) 4513 1.1 christos break; 4514 1.1 christos if ((nat->nat_flags & SI_CLONE) != 0) { 4515 1.1 christos nat = ipf_nat_clone(fin, nat); 4516 1.1 christos if (nat == NULL) 4517 1.1 christos break; 4518 1.1 christos } else { 4519 1.1 christos MUTEX_ENTER(&softn->ipf_nat_new); 4520 1.1 christos softn->ipf_nat_stats.ns_wilds--; 4521 1.1 christos MUTEX_EXIT(&softn->ipf_nat_new); 4522 1.1 christos } 4523 1.1 christos 4524 1.1 christos if (nat->nat_dir == NAT_OUTBOUND) { 4525 1.1 christos if (nat->nat_osport == 0) { 4526 1.1 christos nat->nat_osport = sport; 4527 1.1 christos nat->nat_nsport = sport; 4528 1.1 christos } 4529 1.1 christos if (nat->nat_odport == 0) { 4530 1.1 christos nat->nat_odport = dport; 4531 1.1 christos nat->nat_ndport = dport; 4532 1.1 christos } 4533 1.1 christos } else if (nat->nat_dir == NAT_INBOUND) { 4534 1.1 christos if (nat->nat_osport == 0) { 4535 1.1 christos nat->nat_osport = dport; 4536 1.1 christos nat->nat_nsport = dport; 4537 1.1 christos } 4538 1.1 christos if (nat->nat_odport == 0) { 4539 1.1 christos nat->nat_odport = sport; 4540 1.1 christos nat->nat_ndport = sport; 4541 1.1 christos } 4542 1.1 christos } 4543 1.1 christos if ((nat->nat_ifps[1] == NULL) && (ifp != NULL)) { 4544 1.1 christos nat->nat_ifps[1] = ifp; 4545 1.1 christos nat->nat_mtu[1] = GETIFMTU_4(ifp); 4546 1.1 christos } 4547 1.1 christos nat->nat_flags &= ~(SI_W_DPORT|SI_W_SPORT); 4548 1.1 christos ipf_nat_tabmove(softn, nat); 4549 1.1 christos break; 4550 1.1 christos } 4551 1.1 christos } 4552 1.1 christos 4553 1.1 christos MUTEX_DOWNGRADE(&softc->ipf_nat); 4554 1.1 christos 4555 1.1 christos if (nat == NULL) { 4556 1.1 christos NBUMPSIDE(1, ns_lookup_miss); 4557 1.1 christos } 4558 1.1 christos return nat; 4559 1.1 christos } 4560 1.1 christos 4561 1.1 christos 4562 1.1 christos /* ------------------------------------------------------------------------ */ 4563 1.1 christos /* Function: ipf_nat_lookupredir */ 4564 1.1 christos /* Returns: nat_t* - NULL == no match, */ 4565 1.1 christos /* else pointer to matching NAT entry */ 4566 1.15 prlw1 /* Parameters: softc(I) - pointer to soft context main structure */ 4567 1.15 prlw1 /* np(I) - pointer to description of packet to find NAT */ 4568 1.15 prlw1 /* table entry for. */ 4569 1.1 christos /* */ 4570 1.1 christos /* Lookup the NAT tables to search for a matching redirect */ 4571 1.1 christos /* The contents of natlookup_t should imitate those found in a packet that */ 4572 1.1 christos /* would be translated - ie a packet coming in for RDR or going out for MAP.*/ 4573 1.1 christos /* We can do the lookup in one of two ways, imitating an inbound or */ 4574 1.1 christos /* outbound packet. By default we assume outbound, unless IPN_IN is set. */ 4575 1.1 christos /* For IN, the fields are set as follows: */ 4576 1.1 christos /* nl_real* = source information */ 4577 1.1 christos /* nl_out* = destination information (translated) */ 4578 1.1 christos /* For an out packet, the fields are set like this: */ 4579 1.1 christos /* nl_in* = source information (untranslated) */ 4580 1.1 christos /* nl_out* = destination information (translated) */ 4581 1.1 christos /* ------------------------------------------------------------------------ */ 4582 1.1 christos nat_t * 4583 1.14 prlw1 ipf_nat_lookupredir(ipf_main_softc_t *softc, natlookup_t *np) 4584 1.1 christos { 4585 1.1 christos fr_info_t fi; 4586 1.1 christos nat_t *nat; 4587 1.1 christos 4588 1.1 christos bzero((char *)&fi, sizeof(fi)); 4589 1.14 prlw1 fi.fin_main_soft = softc; 4590 1.1 christos if (np->nl_flags & IPN_IN) { 4591 1.1 christos fi.fin_data[0] = ntohs(np->nl_realport); 4592 1.1 christos fi.fin_data[1] = ntohs(np->nl_outport); 4593 1.1 christos } else { 4594 1.1 christos fi.fin_data[0] = ntohs(np->nl_inport); 4595 1.1 christos fi.fin_data[1] = ntohs(np->nl_outport); 4596 1.1 christos } 4597 1.1 christos if (np->nl_flags & IPN_TCP) 4598 1.1 christos fi.fin_p = IPPROTO_TCP; 4599 1.1 christos else if (np->nl_flags & IPN_UDP) 4600 1.1 christos fi.fin_p = IPPROTO_UDP; 4601 1.1 christos else if (np->nl_flags & (IPN_ICMPERR|IPN_ICMPQUERY)) 4602 1.1 christos fi.fin_p = IPPROTO_ICMP; 4603 1.1 christos 4604 1.1 christos /* 4605 1.1 christos * We can do two sorts of lookups: 4606 1.1 christos * - IPN_IN: we have the `real' and `out' address, look for `in'. 4607 1.1 christos * - default: we have the `in' and `out' address, look for `real'. 4608 1.1 christos */ 4609 1.1 christos if (np->nl_flags & IPN_IN) { 4610 1.1 christos if ((nat = ipf_nat_inlookup(&fi, np->nl_flags, fi.fin_p, 4611 1.1 christos np->nl_realip, np->nl_outip))) { 4612 1.1 christos np->nl_inip = nat->nat_odstip; 4613 1.1 christos np->nl_inport = nat->nat_odport; 4614 1.1 christos } 4615 1.1 christos } else { 4616 1.1 christos /* 4617 1.1 christos * If nl_inip is non null, this is a lookup based on the real 4618 1.1 christos * ip address. Else, we use the fake. 4619 1.1 christos */ 4620 1.1 christos if ((nat = ipf_nat_outlookup(&fi, np->nl_flags, fi.fin_p, 4621 1.1 christos np->nl_inip, np->nl_outip))) { 4622 1.1 christos 4623 1.1 christos if ((np->nl_flags & IPN_FINDFORWARD) != 0) { 4624 1.1 christos fr_info_t fin; 4625 1.1 christos bzero((char *)&fin, sizeof(fin)); 4626 1.1 christos fin.fin_p = nat->nat_pr[0]; 4627 1.1 christos fin.fin_data[0] = ntohs(nat->nat_ndport); 4628 1.1 christos fin.fin_data[1] = ntohs(nat->nat_nsport); 4629 1.1 christos if (ipf_nat_inlookup(&fin, np->nl_flags, 4630 1.1 christos fin.fin_p, nat->nat_ndstip, 4631 1.1 christos nat->nat_nsrcip) != NULL) { 4632 1.1 christos np->nl_flags &= ~IPN_FINDFORWARD; 4633 1.1 christos } 4634 1.1 christos } 4635 1.1 christos 4636 1.17 sborrill np->nl_realip = nat->nat_odstip; 4637 1.17 sborrill np->nl_realport = nat->nat_odport; 4638 1.1 christos } 4639 1.1 christos } 4640 1.1 christos 4641 1.1 christos return nat; 4642 1.1 christos } 4643 1.1 christos 4644 1.1 christos 4645 1.1 christos /* ------------------------------------------------------------------------ */ 4646 1.1 christos /* Function: ipf_nat_match */ 4647 1.1 christos /* Returns: int - 0 == no match, 1 == match */ 4648 1.1 christos /* Parameters: fin(I) - pointer to packet information */ 4649 1.1 christos /* np(I) - pointer to NAT rule */ 4650 1.1 christos /* */ 4651 1.1 christos /* Pull the matching of a packet against a NAT rule out of that complex */ 4652 1.1 christos /* loop inside ipf_nat_checkin() and lay it out properly in its own function. */ 4653 1.1 christos /* ------------------------------------------------------------------------ */ 4654 1.1 christos static int 4655 1.2 christos ipf_nat_match(fr_info_t *fin, ipnat_t *np) 4656 1.1 christos { 4657 1.1 christos ipf_main_softc_t *softc = fin->fin_main_soft; 4658 1.1 christos frtuc_t *ft; 4659 1.1 christos int match; 4660 1.1 christos 4661 1.1 christos match = 0; 4662 1.1 christos switch (np->in_osrcatype) 4663 1.1 christos { 4664 1.1 christos case FRI_NORMAL : 4665 1.1 christos match = ((fin->fin_saddr & np->in_osrcmsk) != np->in_osrcaddr); 4666 1.1 christos break; 4667 1.1 christos case FRI_LOOKUP : 4668 1.1 christos match = (*np->in_osrcfunc)(softc, np->in_osrcptr, 4669 1.1 christos 4, &fin->fin_saddr, fin->fin_plen); 4670 1.1 christos break; 4671 1.1 christos } 4672 1.1 christos match ^= ((np->in_flags & IPN_NOTSRC) != 0); 4673 1.1 christos if (match) 4674 1.1 christos return 0; 4675 1.1 christos 4676 1.1 christos match = 0; 4677 1.1 christos switch (np->in_odstatype) 4678 1.1 christos { 4679 1.1 christos case FRI_NORMAL : 4680 1.1 christos match = ((fin->fin_daddr & np->in_odstmsk) != np->in_odstaddr); 4681 1.1 christos break; 4682 1.1 christos case FRI_LOOKUP : 4683 1.1 christos match = (*np->in_odstfunc)(softc, np->in_odstptr, 4684 1.1 christos 4, &fin->fin_daddr, fin->fin_plen); 4685 1.1 christos break; 4686 1.1 christos } 4687 1.1 christos 4688 1.1 christos match ^= ((np->in_flags & IPN_NOTDST) != 0); 4689 1.1 christos if (match) 4690 1.1 christos return 0; 4691 1.1 christos 4692 1.1 christos ft = &np->in_tuc; 4693 1.1 christos if (!(fin->fin_flx & FI_TCPUDP) || 4694 1.1 christos (fin->fin_flx & (FI_SHORT|FI_FRAGBODY))) { 4695 1.1 christos if (ft->ftu_scmp || ft->ftu_dcmp) 4696 1.1 christos return 0; 4697 1.1 christos return 1; 4698 1.1 christos } 4699 1.1 christos 4700 1.1 christos return ipf_tcpudpchk(&fin->fin_fi, ft); 4701 1.1 christos } 4702 1.1 christos 4703 1.1 christos 4704 1.1 christos /* ------------------------------------------------------------------------ */ 4705 1.1 christos /* Function: ipf_nat_update */ 4706 1.1 christos /* Returns: Nil */ 4707 1.3 darrenr /* Parameters: fin(I) - pointer to packet information */ 4708 1.3 darrenr /* nat(I) - pointer to NAT structure */ 4709 1.1 christos /* */ 4710 1.1 christos /* Updates the lifetime of a NAT table entry for non-TCP packets. Must be */ 4711 1.1 christos /* called with fin_rev updated - i.e. after calling ipf_nat_proto(). */ 4712 1.1 christos /* */ 4713 1.1 christos /* This *MUST* be called after ipf_nat_proto() as it expects fin_rev to */ 4714 1.1 christos /* already be set. */ 4715 1.1 christos /* ------------------------------------------------------------------------ */ 4716 1.1 christos void 4717 1.2 christos ipf_nat_update(fr_info_t *fin, nat_t *nat) 4718 1.1 christos { 4719 1.1 christos ipf_main_softc_t *softc = fin->fin_main_soft; 4720 1.1 christos ipf_nat_softc_t *softn = softc->ipf_nat_soft; 4721 1.1 christos ipftq_t *ifq, *ifq2; 4722 1.1 christos ipftqent_t *tqe; 4723 1.1 christos ipnat_t *np = nat->nat_ptr; 4724 1.1 christos 4725 1.1 christos tqe = &nat->nat_tqe; 4726 1.1 christos ifq = tqe->tqe_ifq; 4727 1.1 christos 4728 1.1 christos /* 4729 1.1 christos * We allow over-riding of NAT timeouts from NAT rules, even for 4730 1.1 christos * TCP, however, if it is TCP and there is no rule timeout set, 4731 1.1 christos * then do not update the timeout here. 4732 1.1 christos */ 4733 1.1 christos if (np != NULL) { 4734 1.1 christos np->in_bytes[fin->fin_rev] += fin->fin_plen; 4735 1.1 christos ifq2 = np->in_tqehead[fin->fin_rev]; 4736 1.1 christos } else { 4737 1.1 christos ifq2 = NULL; 4738 1.1 christos } 4739 1.1 christos 4740 1.1 christos if (nat->nat_pr[0] == IPPROTO_TCP && ifq2 == NULL) { 4741 1.1 christos (void) ipf_tcp_age(&nat->nat_tqe, fin, softn->ipf_nat_tcptq, 4742 1.1 christos 0, 2); 4743 1.1 christos } else { 4744 1.1 christos if (ifq2 == NULL) { 4745 1.1 christos if (nat->nat_pr[0] == IPPROTO_UDP) 4746 1.1 christos ifq2 = fin->fin_rev ? &softn->ipf_nat_udpacktq : 4747 1.1 christos &softn->ipf_nat_udptq; 4748 1.3 darrenr else if (nat->nat_pr[0] == IPPROTO_ICMP || 4749 1.3 darrenr nat->nat_pr[0] == IPPROTO_ICMPV6) 4750 1.1 christos ifq2 = fin->fin_rev ? &softn->ipf_nat_icmpacktq: 4751 1.1 christos &softn->ipf_nat_icmptq; 4752 1.1 christos else 4753 1.1 christos ifq2 = &softn->ipf_nat_iptq; 4754 1.1 christos } 4755 1.1 christos 4756 1.1 christos ipf_movequeue(softc->ipf_ticks, tqe, ifq, ifq2); 4757 1.1 christos } 4758 1.1 christos } 4759 1.1 christos 4760 1.1 christos 4761 1.1 christos /* ------------------------------------------------------------------------ */ 4762 1.1 christos /* Function: ipf_nat_checkout */ 4763 1.1 christos /* Returns: int - -1 == packet failed NAT checks so block it, */ 4764 1.1 christos /* 0 == no packet translation occurred, */ 4765 1.1 christos /* 1 == packet was successfully translated. */ 4766 1.1 christos /* Parameters: fin(I) - pointer to packet information */ 4767 1.1 christos /* passp(I) - pointer to filtering result flags */ 4768 1.1 christos /* */ 4769 1.1 christos /* Check to see if an outcoming packet should be changed. ICMP packets are */ 4770 1.1 christos /* first checked to see if they match an existing entry (if an error), */ 4771 1.1 christos /* otherwise a search of the current NAT table is made. If neither results */ 4772 1.1 christos /* in a match then a search for a matching NAT rule is made. Create a new */ 4773 1.1 christos /* NAT entry if a we matched a NAT rule. Lastly, actually change the */ 4774 1.1 christos /* packet header(s) as required. */ 4775 1.1 christos /* ------------------------------------------------------------------------ */ 4776 1.1 christos int 4777 1.2 christos ipf_nat_checkout(fr_info_t *fin, u_32_t *passp) 4778 1.1 christos { 4779 1.1 christos ipnat_t *np = NULL, *npnext; 4780 1.1 christos struct ifnet *ifp, *sifp; 4781 1.1 christos ipf_main_softc_t *softc; 4782 1.1 christos ipf_nat_softc_t *softn; 4783 1.1 christos tcphdr_t *tcp = NULL; 4784 1.1 christos int rval, natfailed; 4785 1.1 christos u_int nflags = 0; 4786 1.1 christos u_32_t ipa, iph; 4787 1.1 christos int natadd = 1; 4788 1.1 christos frentry_t *fr; 4789 1.1 christos nat_t *nat; 4790 1.1 christos 4791 1.1 christos if (fin->fin_v == 6) { 4792 1.1 christos #ifdef USE_INET6 4793 1.1 christos return ipf_nat6_checkout(fin, passp); 4794 1.1 christos #else 4795 1.1 christos return 0; 4796 1.1 christos #endif 4797 1.1 christos } 4798 1.1 christos 4799 1.1 christos softc = fin->fin_main_soft; 4800 1.1 christos softn = softc->ipf_nat_soft; 4801 1.1 christos 4802 1.1 christos if (softn->ipf_nat_lock != 0) 4803 1.1 christos return 0; 4804 1.1 christos if (softn->ipf_nat_stats.ns_rules == 0 && 4805 1.1 christos softn->ipf_nat_instances == NULL) 4806 1.1 christos return 0; 4807 1.1 christos 4808 1.1 christos natfailed = 0; 4809 1.1 christos fr = fin->fin_fr; 4810 1.1 christos sifp = fin->fin_ifp; 4811 1.1 christos if (fr != NULL) { 4812 1.1 christos ifp = fr->fr_tifs[fin->fin_rev].fd_ptr; 4813 1.1 christos if ((ifp != NULL) && (ifp != (void *)-1)) 4814 1.1 christos fin->fin_ifp = ifp; 4815 1.1 christos } 4816 1.1 christos ifp = fin->fin_ifp; 4817 1.1 christos 4818 1.1 christos if (!(fin->fin_flx & FI_SHORT) && (fin->fin_off == 0)) { 4819 1.1 christos switch (fin->fin_p) 4820 1.1 christos { 4821 1.1 christos case IPPROTO_TCP : 4822 1.1 christos nflags = IPN_TCP; 4823 1.1 christos break; 4824 1.1 christos case IPPROTO_UDP : 4825 1.1 christos nflags = IPN_UDP; 4826 1.1 christos break; 4827 1.1 christos case IPPROTO_ICMP : 4828 1.1 christos /* 4829 1.1 christos * This is an incoming packet, so the destination is 4830 1.1 christos * the icmp_id and the source port equals 0 4831 1.1 christos */ 4832 1.1 christos if ((fin->fin_flx & FI_ICMPQUERY) != 0) 4833 1.1 christos nflags = IPN_ICMPQUERY; 4834 1.1 christos break; 4835 1.1 christos default : 4836 1.1 christos break; 4837 1.1 christos } 4838 1.1 christos 4839 1.1 christos if ((nflags & IPN_TCPUDP)) 4840 1.1 christos tcp = fin->fin_dp; 4841 1.1 christos } 4842 1.1 christos 4843 1.1 christos ipa = fin->fin_saddr; 4844 1.1 christos 4845 1.1 christos READ_ENTER(&softc->ipf_nat); 4846 1.1 christos 4847 1.1 christos if ((fin->fin_p == IPPROTO_ICMP) && !(nflags & IPN_ICMPQUERY) && 4848 1.1 christos (nat = ipf_nat_icmperror(fin, &nflags, NAT_OUTBOUND))) 4849 1.1 christos /*EMPTY*/; 4850 1.1 christos else if ((fin->fin_flx & FI_FRAG) && (nat = ipf_frag_natknown(fin))) 4851 1.1 christos natadd = 0; 4852 1.1 christos else if ((nat = ipf_nat_outlookup(fin, nflags|NAT_SEARCH, 4853 1.1 christos (u_int)fin->fin_p, fin->fin_src, 4854 1.1 christos fin->fin_dst))) { 4855 1.1 christos nflags = nat->nat_flags; 4856 1.1 christos } else if (fin->fin_off == 0) { 4857 1.1 christos u_32_t hv, msk, nmsk = 0; 4858 1.1 christos 4859 1.1 christos /* 4860 1.1 christos * If there is no current entry in the nat table for this IP#, 4861 1.1 christos * create one for it (if there is a matching rule). 4862 1.1 christos */ 4863 1.1 christos maskloop: 4864 1.1 christos msk = softn->ipf_nat_map_active_masks[nmsk]; 4865 1.1 christos iph = ipa & msk; 4866 1.1 christos hv = NAT_HASH_FN(iph, 0, softn->ipf_nat_maprules_sz); 4867 1.1 christos retry_roundrobin: 4868 1.1 christos for (np = softn->ipf_nat_map_rules[hv]; np; np = npnext) { 4869 1.1 christos npnext = np->in_mnext; 4870 1.1 christos if ((np->in_ifps[1] && (np->in_ifps[1] != ifp))) 4871 1.1 christos continue; 4872 1.1 christos if (np->in_v[0] != 4) 4873 1.1 christos continue; 4874 1.1 christos if (np->in_pr[1] && (np->in_pr[1] != fin->fin_p)) 4875 1.1 christos continue; 4876 1.1 christos if ((np->in_flags & IPN_RF) && 4877 1.1 christos !(np->in_flags & nflags)) 4878 1.1 christos continue; 4879 1.1 christos if (np->in_flags & IPN_FILTER) { 4880 1.1 christos switch (ipf_nat_match(fin, np)) 4881 1.1 christos { 4882 1.1 christos case 0 : 4883 1.1 christos continue; 4884 1.1 christos case -1 : 4885 1.1 christos rval = -1; 4886 1.1 christos goto outmatchfail; 4887 1.1 christos case 1 : 4888 1.1 christos default : 4889 1.1 christos break; 4890 1.1 christos } 4891 1.1 christos } else if ((ipa & np->in_osrcmsk) != np->in_osrcaddr) 4892 1.1 christos continue; 4893 1.1 christos 4894 1.1 christos if ((fr != NULL) && 4895 1.1 christos !ipf_matchtag(&np->in_tag, &fr->fr_nattag)) 4896 1.1 christos continue; 4897 1.1 christos 4898 1.1 christos if (np->in_plabel != -1) { 4899 1.1 christos if (((np->in_flags & IPN_FILTER) == 0) && 4900 1.1 christos (np->in_odport != fin->fin_data[1])) 4901 1.1 christos continue; 4902 1.1 christos if (ipf_proxy_ok(fin, tcp, np) == 0) 4903 1.1 christos continue; 4904 1.1 christos } 4905 1.1 christos 4906 1.1 christos if (np->in_flags & IPN_NO) { 4907 1.1 christos np->in_hits++; 4908 1.1 christos break; 4909 1.1 christos } 4910 1.1 christos MUTEX_ENTER(&softn->ipf_nat_new); 4911 1.1 christos /* 4912 1.1 christos * If we've matched a round-robin rule but it has 4913 1.1 christos * moved in the list since we got it, start over as 4914 1.1 christos * this is now no longer correct. 4915 1.1 christos */ 4916 1.1 christos if (npnext != np->in_mnext) { 4917 1.1 christos if ((np->in_flags & IPN_ROUNDR) != 0) { 4918 1.1 christos MUTEX_EXIT(&softn->ipf_nat_new); 4919 1.1 christos goto retry_roundrobin; 4920 1.1 christos } 4921 1.1 christos npnext = np->in_mnext; 4922 1.1 christos } 4923 1.1 christos 4924 1.1 christos nat = ipf_nat_add(fin, np, NULL, nflags, NAT_OUTBOUND); 4925 1.1 christos MUTEX_EXIT(&softn->ipf_nat_new); 4926 1.1 christos if (nat != NULL) { 4927 1.1 christos natfailed = 0; 4928 1.1 christos break; 4929 1.1 christos } 4930 1.1 christos natfailed = -1; 4931 1.1 christos } 4932 1.1 christos if ((np == NULL) && (nmsk < softn->ipf_nat_map_max)) { 4933 1.1 christos nmsk++; 4934 1.1 christos goto maskloop; 4935 1.1 christos } 4936 1.1 christos } 4937 1.1 christos 4938 1.1 christos if (nat != NULL) { 4939 1.1 christos rval = ipf_nat_out(fin, nat, natadd, nflags); 4940 1.1 christos if (rval == 1) { 4941 1.1 christos MUTEX_ENTER(&nat->nat_lock); 4942 1.1 christos ipf_nat_update(fin, nat); 4943 1.1 christos nat->nat_bytes[1] += fin->fin_plen; 4944 1.1 christos nat->nat_pkts[1]++; 4945 1.1 christos fin->fin_pktnum = nat->nat_pkts[1]; 4946 1.1 christos MUTEX_EXIT(&nat->nat_lock); 4947 1.1 christos } 4948 1.1 christos } else 4949 1.1 christos rval = natfailed; 4950 1.1 christos outmatchfail: 4951 1.1 christos RWLOCK_EXIT(&softc->ipf_nat); 4952 1.1 christos 4953 1.1 christos switch (rval) 4954 1.1 christos { 4955 1.1 christos case -1 : 4956 1.1 christos if (passp != NULL) { 4957 1.1 christos DT1(frb_natv4out, fr_info_t *, fin); 4958 1.1 christos NBUMPSIDED(1, ns_drop); 4959 1.1 christos *passp = FR_BLOCK; 4960 1.3 darrenr fin->fin_reason = FRB_NATV4; 4961 1.1 christos } 4962 1.1 christos fin->fin_flx |= FI_BADNAT; 4963 1.1 christos NBUMPSIDED(1, ns_badnat); 4964 1.1 christos break; 4965 1.1 christos case 0 : 4966 1.1 christos NBUMPSIDE(1, ns_ignored); 4967 1.1 christos break; 4968 1.1 christos case 1 : 4969 1.1 christos NBUMPSIDE(1, ns_translated); 4970 1.1 christos break; 4971 1.1 christos } 4972 1.1 christos fin->fin_ifp = sifp; 4973 1.1 christos return rval; 4974 1.1 christos } 4975 1.1 christos 4976 1.1 christos /* ------------------------------------------------------------------------ */ 4977 1.1 christos /* Function: ipf_nat_out */ 4978 1.1 christos /* Returns: int - -1 == packet failed NAT checks so block it, */ 4979 1.1 christos /* 1 == packet was successfully translated. */ 4980 1.1 christos /* Parameters: fin(I) - pointer to packet information */ 4981 1.1 christos /* nat(I) - pointer to NAT structure */ 4982 1.1 christos /* natadd(I) - flag indicating if it is safe to add frag cache */ 4983 1.1 christos /* nflags(I) - NAT flags set for this packet */ 4984 1.1 christos /* */ 4985 1.1 christos /* Translate a packet coming "out" on an interface. */ 4986 1.1 christos /* ------------------------------------------------------------------------ */ 4987 1.1 christos int 4988 1.2 christos ipf_nat_out(fr_info_t *fin, nat_t *nat, int natadd, u_32_t nflags) 4989 1.1 christos { 4990 1.1 christos ipf_main_softc_t *softc = fin->fin_main_soft; 4991 1.1 christos ipf_nat_softc_t *softn = softc->ipf_nat_soft; 4992 1.1 christos icmphdr_t *icmp; 4993 1.1 christos tcphdr_t *tcp; 4994 1.1 christos ipnat_t *np; 4995 1.1 christos int skip; 4996 1.1 christos int i; 4997 1.1 christos 4998 1.1 christos tcp = NULL; 4999 1.1 christos icmp = NULL; 5000 1.1 christos np = nat->nat_ptr; 5001 1.1 christos 5002 1.1 christos if ((natadd != 0) && (fin->fin_flx & FI_FRAG) && (np != NULL)) 5003 1.1 christos (void) ipf_frag_natnew(softc, fin, 0, nat); 5004 1.1 christos 5005 1.1 christos /* 5006 1.1 christos * Fix up checksums, not by recalculating them, but 5007 1.1 christos * simply computing adjustments. 5008 1.1 christos * This is only done for STREAMS based IP implementations where the 5009 1.1 christos * checksum has already been calculated by IP. In all other cases, 5010 1.1 christos * IPFilter is called before the checksum needs calculating so there 5011 1.1 christos * is no call to modify whatever is in the header now. 5012 1.1 christos */ 5013 1.1 christos if (nflags == IPN_ICMPERR) { 5014 1.1 christos u_32_t s1, s2, sumd, msumd; 5015 1.1 christos 5016 1.1 christos s1 = LONG_SUM(ntohl(fin->fin_saddr)); 5017 1.1 christos if (nat->nat_dir == NAT_OUTBOUND) { 5018 1.1 christos s2 = LONG_SUM(ntohl(nat->nat_nsrcaddr)); 5019 1.1 christos } else { 5020 1.1 christos s2 = LONG_SUM(ntohl(nat->nat_odstaddr)); 5021 1.1 christos } 5022 1.1 christos CALC_SUMD(s1, s2, sumd); 5023 1.1 christos msumd = sumd; 5024 1.1 christos 5025 1.1 christos s1 = LONG_SUM(ntohl(fin->fin_daddr)); 5026 1.1 christos if (nat->nat_dir == NAT_OUTBOUND) { 5027 1.1 christos s2 = LONG_SUM(ntohl(nat->nat_ndstaddr)); 5028 1.1 christos } else { 5029 1.1 christos s2 = LONG_SUM(ntohl(nat->nat_osrcaddr)); 5030 1.1 christos } 5031 1.1 christos CALC_SUMD(s1, s2, sumd); 5032 1.1 christos msumd += sumd; 5033 1.1 christos 5034 1.3 darrenr ipf_fix_outcksum(0, &fin->fin_ip->ip_sum, msumd, 0); 5035 1.1 christos } 5036 1.1 christos #if !defined(_KERNEL) || defined(MENTAT) || defined(__sgi) || \ 5037 1.23 maxv defined(linux) 5038 1.1 christos else { 5039 1.1 christos /* 5040 1.1 christos * Strictly speaking, this isn't necessary on BSD 5041 1.1 christos * kernels because they do checksum calculation after 5042 1.1 christos * this code has run BUT if ipfilter is being used 5043 1.1 christos * to do NAT as a bridge, that code doesn't exist. 5044 1.1 christos */ 5045 1.1 christos switch (nat->nat_dir) 5046 1.1 christos { 5047 1.1 christos case NAT_OUTBOUND : 5048 1.3 darrenr ipf_fix_outcksum(fin->fin_cksum & FI_CK_L4PART, 5049 1.3 darrenr &fin->fin_ip->ip_sum, 5050 1.3 darrenr nat->nat_ipsumd, 0); 5051 1.1 christos break; 5052 1.1 christos 5053 1.1 christos case NAT_INBOUND : 5054 1.3 darrenr ipf_fix_incksum(fin->fin_cksum & FI_CK_L4PART, 5055 1.3 darrenr &fin->fin_ip->ip_sum, 5056 1.3 darrenr nat->nat_ipsumd, 0); 5057 1.1 christos break; 5058 1.1 christos 5059 1.1 christos default : 5060 1.1 christos break; 5061 1.1 christos } 5062 1.1 christos } 5063 1.1 christos #endif 5064 1.1 christos 5065 1.1 christos /* 5066 1.1 christos * Address assignment is after the checksum modification because 5067 1.1 christos * we are using the address in the packet for determining the 5068 1.1 christos * correct checksum offset (the ICMP error could be coming from 5069 1.1 christos * anyone...) 5070 1.1 christos */ 5071 1.1 christos switch (nat->nat_dir) 5072 1.1 christos { 5073 1.1 christos case NAT_OUTBOUND : 5074 1.1 christos fin->fin_ip->ip_src = nat->nat_nsrcip; 5075 1.1 christos fin->fin_saddr = nat->nat_nsrcaddr; 5076 1.1 christos fin->fin_ip->ip_dst = nat->nat_ndstip; 5077 1.1 christos fin->fin_daddr = nat->nat_ndstaddr; 5078 1.1 christos break; 5079 1.1 christos 5080 1.1 christos case NAT_INBOUND : 5081 1.1 christos fin->fin_ip->ip_src = nat->nat_odstip; 5082 1.1 christos fin->fin_saddr = nat->nat_ndstaddr; 5083 1.1 christos fin->fin_ip->ip_dst = nat->nat_osrcip; 5084 1.1 christos fin->fin_daddr = nat->nat_nsrcaddr; 5085 1.1 christos break; 5086 1.1 christos 5087 1.1 christos case NAT_DIVERTIN : 5088 1.1 christos { 5089 1.1 christos mb_t *m; 5090 1.1 christos 5091 1.1 christos skip = ipf_nat_decap(fin, nat); 5092 1.1 christos if (skip <= 0) { 5093 1.1 christos NBUMPSIDED(1, ns_decap_fail); 5094 1.1 christos return -1; 5095 1.1 christos } 5096 1.1 christos 5097 1.1 christos m = fin->fin_m; 5098 1.1 christos 5099 1.1 christos #if defined(MENTAT) && defined(_KERNEL) 5100 1.1 christos m->b_rptr += skip; 5101 1.1 christos #else 5102 1.1 christos m->m_data += skip; 5103 1.1 christos m->m_len -= skip; 5104 1.1 christos 5105 1.1 christos # ifdef M_PKTHDR 5106 1.1 christos if (m->m_flags & M_PKTHDR) 5107 1.1 christos m->m_pkthdr.len -= skip; 5108 1.1 christos # endif 5109 1.1 christos #endif 5110 1.1 christos 5111 1.1 christos MUTEX_ENTER(&nat->nat_lock); 5112 1.1 christos ipf_nat_update(fin, nat); 5113 1.1 christos MUTEX_EXIT(&nat->nat_lock); 5114 1.1 christos fin->fin_flx |= FI_NATED; 5115 1.1 christos if (np != NULL && np->in_tag.ipt_num[0] != 0) 5116 1.1 christos fin->fin_nattag = &np->in_tag; 5117 1.1 christos return 1; 5118 1.1 christos /* NOTREACHED */ 5119 1.1 christos } 5120 1.1 christos 5121 1.1 christos case NAT_DIVERTOUT : 5122 1.1 christos { 5123 1.1 christos u_32_t s1, s2, sumd; 5124 1.1 christos udphdr_t *uh; 5125 1.1 christos ip_t *ip; 5126 1.1 christos mb_t *m; 5127 1.1 christos 5128 1.1 christos m = M_DUP(np->in_divmp); 5129 1.1 christos if (m == NULL) { 5130 1.1 christos NBUMPSIDED(1, ns_divert_dup); 5131 1.1 christos return -1; 5132 1.1 christos } 5133 1.1 christos 5134 1.1 christos ip = MTOD(m, ip_t *); 5135 1.1 christos ip->ip_id = htons(ipf_nextipid(fin)); 5136 1.1 christos s2 = ntohs(ip->ip_id); 5137 1.1 christos 5138 1.1 christos s1 = ip->ip_len; 5139 1.1 christos ip->ip_len = ntohs(ip->ip_len); 5140 1.1 christos ip->ip_len += fin->fin_plen; 5141 1.1 christos ip->ip_len = htons(ip->ip_len); 5142 1.1 christos s2 += ntohs(ip->ip_len); 5143 1.1 christos CALC_SUMD(s1, s2, sumd); 5144 1.1 christos 5145 1.1 christos uh = (udphdr_t *)(ip + 1); 5146 1.1 christos uh->uh_ulen += fin->fin_plen; 5147 1.1 christos uh->uh_ulen = htons(uh->uh_ulen); 5148 1.1 christos #if !defined(_KERNEL) || defined(MENTAT) || defined(__sgi) || \ 5149 1.23 maxv defined(linux) 5150 1.3 darrenr ipf_fix_outcksum(0, &ip->ip_sum, sumd, 0); 5151 1.1 christos #endif 5152 1.1 christos 5153 1.1 christos PREP_MB_T(fin, m); 5154 1.1 christos 5155 1.1 christos fin->fin_src = ip->ip_src; 5156 1.1 christos fin->fin_dst = ip->ip_dst; 5157 1.1 christos fin->fin_ip = ip; 5158 1.1 christos fin->fin_plen += sizeof(ip_t) + 8; /* UDP + IPv4 hdr */ 5159 1.1 christos fin->fin_dlen += sizeof(ip_t) + 8; /* UDP + IPv4 hdr */ 5160 1.1 christos 5161 1.1 christos nflags &= ~IPN_TCPUDPICMP; 5162 1.1 christos 5163 1.1 christos break; 5164 1.1 christos } 5165 1.1 christos 5166 1.1 christos default : 5167 1.1 christos break; 5168 1.1 christos } 5169 1.1 christos 5170 1.1 christos if (!(fin->fin_flx & FI_SHORT) && (fin->fin_off == 0)) { 5171 1.1 christos u_short *csump; 5172 1.1 christos 5173 1.1 christos if ((nat->nat_nsport != 0) && (nflags & IPN_TCPUDP)) { 5174 1.1 christos tcp = fin->fin_dp; 5175 1.1 christos 5176 1.1 christos switch (nat->nat_dir) 5177 1.1 christos { 5178 1.1 christos case NAT_OUTBOUND : 5179 1.1 christos tcp->th_sport = nat->nat_nsport; 5180 1.1 christos fin->fin_data[0] = ntohs(nat->nat_nsport); 5181 1.1 christos tcp->th_dport = nat->nat_ndport; 5182 1.3 darrenr fin->fin_data[1] = ntohs(nat->nat_ndport); 5183 1.1 christos break; 5184 1.1 christos 5185 1.1 christos case NAT_INBOUND : 5186 1.1 christos tcp->th_sport = nat->nat_odport; 5187 1.1 christos fin->fin_data[0] = ntohs(nat->nat_odport); 5188 1.1 christos tcp->th_dport = nat->nat_osport; 5189 1.3 darrenr fin->fin_data[1] = ntohs(nat->nat_osport); 5190 1.1 christos break; 5191 1.1 christos } 5192 1.1 christos } 5193 1.1 christos 5194 1.13 darrenr if ((nat->nat_oicmpid != 0) && (nflags & IPN_ICMPQUERY)) { 5195 1.1 christos icmp = fin->fin_dp; 5196 1.13 darrenr 5197 1.13 darrenr switch (nat->nat_dir) 5198 1.13 darrenr { 5199 1.13 darrenr case NAT_OUTBOUND : 5200 1.13 darrenr icmp->icmp_id = nat->nat_nicmpid; 5201 1.13 darrenr break; 5202 1.13 darrenr case NAT_INBOUND : 5203 1.13 darrenr icmp->icmp_id = nat->nat_oicmpid; 5204 1.13 darrenr break; 5205 1.13 darrenr } 5206 1.1 christos } 5207 1.1 christos 5208 1.1 christos csump = ipf_nat_proto(fin, nat, nflags); 5209 1.1 christos 5210 1.1 christos /* 5211 1.1 christos * The above comments do not hold for layer 4 (or higher) 5212 1.1 christos * checksums... 5213 1.1 christos */ 5214 1.1 christos if (csump != NULL) { 5215 1.1 christos if (nat->nat_dir == NAT_OUTBOUND) 5216 1.3 darrenr ipf_fix_outcksum(fin->fin_cksum, csump, 5217 1.3 darrenr nat->nat_sumd[0], 5218 1.3 darrenr nat->nat_sumd[1] + 5219 1.3 darrenr fin->fin_dlen); 5220 1.1 christos else 5221 1.3 darrenr ipf_fix_incksum(fin->fin_cksum, csump, 5222 1.3 darrenr nat->nat_sumd[0], 5223 1.3 darrenr nat->nat_sumd[1] + 5224 1.3 darrenr fin->fin_dlen); 5225 1.1 christos } 5226 1.1 christos } 5227 1.1 christos 5228 1.1 christos ipf_sync_update(softc, SMC_NAT, fin, nat->nat_sync); 5229 1.1 christos /* ------------------------------------------------------------- */ 5230 1.1 christos /* A few quick notes: */ 5231 1.1 christos /* Following are test conditions prior to calling the */ 5232 1.1 christos /* ipf_proxy_check routine. */ 5233 1.1 christos /* */ 5234 1.1 christos /* A NULL tcp indicates a non TCP/UDP packet. When dealing */ 5235 1.1 christos /* with a redirect rule, we attempt to match the packet's */ 5236 1.1 christos /* source port against in_dport, otherwise we'd compare the */ 5237 1.1 christos /* packet's destination. */ 5238 1.1 christos /* ------------------------------------------------------------- */ 5239 1.1 christos if ((np != NULL) && (np->in_apr != NULL)) { 5240 1.1 christos i = ipf_proxy_check(fin, nat); 5241 1.3 darrenr if (i == 0) { 5242 1.1 christos i = 1; 5243 1.3 darrenr } else if (i == -1) { 5244 1.1 christos NBUMPSIDED(1, ns_ipf_proxy_fail); 5245 1.1 christos } 5246 1.1 christos } else { 5247 1.1 christos i = 1; 5248 1.1 christos } 5249 1.1 christos fin->fin_flx |= FI_NATED; 5250 1.1 christos return i; 5251 1.1 christos } 5252 1.1 christos 5253 1.1 christos 5254 1.1 christos /* ------------------------------------------------------------------------ */ 5255 1.1 christos /* Function: ipf_nat_checkin */ 5256 1.1 christos /* Returns: int - -1 == packet failed NAT checks so block it, */ 5257 1.1 christos /* 0 == no packet translation occurred, */ 5258 1.1 christos /* 1 == packet was successfully translated. */ 5259 1.1 christos /* Parameters: fin(I) - pointer to packet information */ 5260 1.1 christos /* passp(I) - pointer to filtering result flags */ 5261 1.1 christos /* */ 5262 1.1 christos /* Check to see if an incoming packet should be changed. ICMP packets are */ 5263 1.1 christos /* first checked to see if they match an existing entry (if an error), */ 5264 1.1 christos /* otherwise a search of the current NAT table is made. If neither results */ 5265 1.1 christos /* in a match then a search for a matching NAT rule is made. Create a new */ 5266 1.1 christos /* NAT entry if a we matched a NAT rule. Lastly, actually change the */ 5267 1.1 christos /* packet header(s) as required. */ 5268 1.1 christos /* ------------------------------------------------------------------------ */ 5269 1.1 christos int 5270 1.2 christos ipf_nat_checkin(fr_info_t *fin, u_32_t *passp) 5271 1.1 christos { 5272 1.1 christos ipf_main_softc_t *softc; 5273 1.1 christos ipf_nat_softc_t *softn; 5274 1.1 christos u_int nflags, natadd; 5275 1.1 christos ipnat_t *np, *npnext; 5276 1.1 christos int rval, natfailed; 5277 1.1 christos struct ifnet *ifp; 5278 1.1 christos struct in_addr in; 5279 1.1 christos icmphdr_t *icmp; 5280 1.1 christos tcphdr_t *tcp; 5281 1.1 christos u_short dport; 5282 1.1 christos nat_t *nat; 5283 1.1 christos u_32_t iph; 5284 1.1 christos 5285 1.1 christos softc = fin->fin_main_soft; 5286 1.1 christos softn = softc->ipf_nat_soft; 5287 1.1 christos 5288 1.1 christos if (softn->ipf_nat_lock != 0) 5289 1.1 christos return 0; 5290 1.1 christos if (softn->ipf_nat_stats.ns_rules == 0 && 5291 1.1 christos softn->ipf_nat_instances == NULL) 5292 1.1 christos return 0; 5293 1.1 christos 5294 1.1 christos tcp = NULL; 5295 1.1 christos icmp = NULL; 5296 1.1 christos dport = 0; 5297 1.1 christos natadd = 1; 5298 1.1 christos nflags = 0; 5299 1.1 christos natfailed = 0; 5300 1.1 christos ifp = fin->fin_ifp; 5301 1.1 christos 5302 1.1 christos if (!(fin->fin_flx & FI_SHORT) && (fin->fin_off == 0)) { 5303 1.1 christos switch (fin->fin_p) 5304 1.1 christos { 5305 1.1 christos case IPPROTO_TCP : 5306 1.1 christos nflags = IPN_TCP; 5307 1.1 christos break; 5308 1.1 christos case IPPROTO_UDP : 5309 1.1 christos nflags = IPN_UDP; 5310 1.1 christos break; 5311 1.1 christos case IPPROTO_ICMP : 5312 1.1 christos icmp = fin->fin_dp; 5313 1.1 christos 5314 1.1 christos /* 5315 1.1 christos * This is an incoming packet, so the destination is 5316 1.1 christos * the icmp_id and the source port equals 0 5317 1.1 christos */ 5318 1.1 christos if ((fin->fin_flx & FI_ICMPQUERY) != 0) { 5319 1.1 christos nflags = IPN_ICMPQUERY; 5320 1.1 christos dport = icmp->icmp_id; 5321 1.1 christos } break; 5322 1.1 christos default : 5323 1.1 christos break; 5324 1.1 christos } 5325 1.1 christos 5326 1.1 christos if ((nflags & IPN_TCPUDP)) { 5327 1.1 christos tcp = fin->fin_dp; 5328 1.1 christos dport = fin->fin_data[1]; 5329 1.1 christos } 5330 1.1 christos } 5331 1.1 christos 5332 1.1 christos in = fin->fin_dst; 5333 1.1 christos 5334 1.1 christos READ_ENTER(&softc->ipf_nat); 5335 1.1 christos 5336 1.1 christos if ((fin->fin_p == IPPROTO_ICMP) && !(nflags & IPN_ICMPQUERY) && 5337 1.1 christos (nat = ipf_nat_icmperror(fin, &nflags, NAT_INBOUND))) 5338 1.1 christos /*EMPTY*/; 5339 1.1 christos else if ((fin->fin_flx & FI_FRAG) && (nat = ipf_frag_natknown(fin))) 5340 1.1 christos natadd = 0; 5341 1.1 christos else if ((nat = ipf_nat_inlookup(fin, nflags|NAT_SEARCH, 5342 1.1 christos (u_int)fin->fin_p, 5343 1.1 christos fin->fin_src, in))) { 5344 1.1 christos nflags = nat->nat_flags; 5345 1.1 christos } else if (fin->fin_off == 0) { 5346 1.1 christos u_32_t hv, msk, rmsk = 0; 5347 1.1 christos 5348 1.1 christos /* 5349 1.1 christos * If there is no current entry in the nat table for this IP#, 5350 1.1 christos * create one for it (if there is a matching rule). 5351 1.1 christos */ 5352 1.1 christos maskloop: 5353 1.1 christos msk = softn->ipf_nat_rdr_active_masks[rmsk]; 5354 1.1 christos iph = in.s_addr & msk; 5355 1.1 christos hv = NAT_HASH_FN(iph, 0, softn->ipf_nat_rdrrules_sz); 5356 1.1 christos retry_roundrobin: 5357 1.1 christos /* TRACE (iph,msk,rmsk,hv,softn->ipf_nat_rdrrules_sz) */ 5358 1.1 christos for (np = softn->ipf_nat_rdr_rules[hv]; np; np = npnext) { 5359 1.1 christos npnext = np->in_rnext; 5360 1.1 christos if (np->in_ifps[0] && (np->in_ifps[0] != ifp)) 5361 1.1 christos continue; 5362 1.1 christos if (np->in_v[0] != 4) 5363 1.1 christos continue; 5364 1.1 christos if (np->in_pr[0] && (np->in_pr[0] != fin->fin_p)) 5365 1.1 christos continue; 5366 1.1 christos if ((np->in_flags & IPN_RF) && !(np->in_flags & nflags)) 5367 1.1 christos continue; 5368 1.1 christos if (np->in_flags & IPN_FILTER) { 5369 1.1 christos switch (ipf_nat_match(fin, np)) 5370 1.1 christos { 5371 1.1 christos case 0 : 5372 1.1 christos continue; 5373 1.1 christos case -1 : 5374 1.1 christos rval = -1; 5375 1.1 christos goto inmatchfail; 5376 1.1 christos case 1 : 5377 1.1 christos default : 5378 1.1 christos break; 5379 1.1 christos } 5380 1.1 christos } else { 5381 1.1 christos if ((in.s_addr & np->in_odstmsk) != 5382 1.1 christos np->in_odstaddr) 5383 1.1 christos continue; 5384 1.1 christos if (np->in_odport && 5385 1.1 christos ((np->in_dtop < dport) || 5386 1.1 christos (dport < np->in_odport))) 5387 1.1 christos continue; 5388 1.1 christos } 5389 1.1 christos 5390 1.1 christos if (np->in_plabel != -1) { 5391 1.1 christos if (!ipf_proxy_ok(fin, tcp, np)) { 5392 1.1 christos continue; 5393 1.1 christos } 5394 1.1 christos } 5395 1.1 christos 5396 1.1 christos if (np->in_flags & IPN_NO) { 5397 1.1 christos np->in_hits++; 5398 1.1 christos break; 5399 1.1 christos } 5400 1.1 christos 5401 1.1 christos MUTEX_ENTER(&softn->ipf_nat_new); 5402 1.1 christos /* 5403 1.1 christos * If we've matched a round-robin rule but it has 5404 1.1 christos * moved in the list since we got it, start over as 5405 1.1 christos * this is now no longer correct. 5406 1.1 christos */ 5407 1.1 christos if (npnext != np->in_rnext) { 5408 1.1 christos if ((np->in_flags & IPN_ROUNDR) != 0) { 5409 1.1 christos MUTEX_EXIT(&softn->ipf_nat_new); 5410 1.1 christos goto retry_roundrobin; 5411 1.1 christos } 5412 1.1 christos npnext = np->in_rnext; 5413 1.1 christos } 5414 1.1 christos 5415 1.1 christos nat = ipf_nat_add(fin, np, NULL, nflags, NAT_INBOUND); 5416 1.1 christos MUTEX_EXIT(&softn->ipf_nat_new); 5417 1.1 christos if (nat != NULL) { 5418 1.1 christos natfailed = 0; 5419 1.1 christos break; 5420 1.1 christos } 5421 1.1 christos natfailed = -1; 5422 1.1 christos } 5423 1.1 christos if ((np == NULL) && (rmsk < softn->ipf_nat_rdr_max)) { 5424 1.1 christos rmsk++; 5425 1.1 christos goto maskloop; 5426 1.1 christos } 5427 1.1 christos } 5428 1.3 darrenr 5429 1.1 christos if (nat != NULL) { 5430 1.1 christos rval = ipf_nat_in(fin, nat, natadd, nflags); 5431 1.1 christos if (rval == 1) { 5432 1.1 christos MUTEX_ENTER(&nat->nat_lock); 5433 1.1 christos ipf_nat_update(fin, nat); 5434 1.1 christos nat->nat_bytes[0] += fin->fin_plen; 5435 1.1 christos nat->nat_pkts[0]++; 5436 1.1 christos fin->fin_pktnum = nat->nat_pkts[0]; 5437 1.1 christos MUTEX_EXIT(&nat->nat_lock); 5438 1.1 christos } 5439 1.1 christos } else 5440 1.1 christos rval = natfailed; 5441 1.1 christos inmatchfail: 5442 1.1 christos RWLOCK_EXIT(&softc->ipf_nat); 5443 1.1 christos 5444 1.1 christos switch (rval) 5445 1.1 christos { 5446 1.1 christos case -1 : 5447 1.1 christos if (passp != NULL) { 5448 1.1 christos DT1(frb_natv4in, fr_info_t *, fin); 5449 1.1 christos NBUMPSIDED(0, ns_drop); 5450 1.1 christos *passp = FR_BLOCK; 5451 1.3 darrenr fin->fin_reason = FRB_NATV4; 5452 1.1 christos } 5453 1.1 christos fin->fin_flx |= FI_BADNAT; 5454 1.1 christos NBUMPSIDED(0, ns_badnat); 5455 1.1 christos break; 5456 1.1 christos case 0 : 5457 1.1 christos NBUMPSIDE(0, ns_ignored); 5458 1.1 christos break; 5459 1.1 christos case 1 : 5460 1.1 christos NBUMPSIDE(0, ns_translated); 5461 1.1 christos break; 5462 1.1 christos } 5463 1.1 christos return rval; 5464 1.1 christos } 5465 1.1 christos 5466 1.1 christos 5467 1.1 christos /* ------------------------------------------------------------------------ */ 5468 1.1 christos /* Function: ipf_nat_in */ 5469 1.1 christos /* Returns: int - -1 == packet failed NAT checks so block it, */ 5470 1.1 christos /* 1 == packet was successfully translated. */ 5471 1.1 christos /* Parameters: fin(I) - pointer to packet information */ 5472 1.1 christos /* nat(I) - pointer to NAT structure */ 5473 1.1 christos /* natadd(I) - flag indicating if it is safe to add frag cache */ 5474 1.1 christos /* nflags(I) - NAT flags set for this packet */ 5475 1.1 christos /* Locks Held: ipf_nat(READ) */ 5476 1.1 christos /* */ 5477 1.1 christos /* Translate a packet coming "in" on an interface. */ 5478 1.1 christos /* ------------------------------------------------------------------------ */ 5479 1.1 christos int 5480 1.2 christos ipf_nat_in(fr_info_t *fin, nat_t *nat, int natadd, u_32_t nflags) 5481 1.1 christos { 5482 1.1 christos ipf_main_softc_t *softc = fin->fin_main_soft; 5483 1.1 christos ipf_nat_softc_t *softn = softc->ipf_nat_soft; 5484 1.1 christos u_32_t sumd, ipsumd, sum1, sum2; 5485 1.1 christos icmphdr_t *icmp; 5486 1.1 christos tcphdr_t *tcp; 5487 1.1 christos ipnat_t *np; 5488 1.1 christos int skip; 5489 1.1 christos int i; 5490 1.1 christos 5491 1.1 christos tcp = NULL; 5492 1.1 christos np = nat->nat_ptr; 5493 1.1 christos fin->fin_fr = nat->nat_fr; 5494 1.1 christos 5495 1.1 christos if (np != NULL) { 5496 1.1 christos if ((natadd != 0) && (fin->fin_flx & FI_FRAG)) 5497 1.1 christos (void) ipf_frag_natnew(softc, fin, 0, nat); 5498 1.1 christos 5499 1.1 christos /* ------------------------------------------------------------- */ 5500 1.1 christos /* A few quick notes: */ 5501 1.1 christos /* Following are test conditions prior to calling the */ 5502 1.1 christos /* ipf_proxy_check routine. */ 5503 1.1 christos /* */ 5504 1.1 christos /* A NULL tcp indicates a non TCP/UDP packet. When dealing */ 5505 1.1 christos /* with a map rule, we attempt to match the packet's */ 5506 1.1 christos /* source port against in_dport, otherwise we'd compare the */ 5507 1.1 christos /* packet's destination. */ 5508 1.1 christos /* ------------------------------------------------------------- */ 5509 1.1 christos if (np->in_apr != NULL) { 5510 1.1 christos i = ipf_proxy_check(fin, nat); 5511 1.1 christos if (i == -1) { 5512 1.1 christos NBUMPSIDED(0, ns_ipf_proxy_fail); 5513 1.1 christos return -1; 5514 1.1 christos } 5515 1.1 christos } 5516 1.1 christos } 5517 1.1 christos 5518 1.1 christos ipf_sync_update(softc, SMC_NAT, fin, nat->nat_sync); 5519 1.1 christos 5520 1.1 christos ipsumd = nat->nat_ipsumd; 5521 1.1 christos /* 5522 1.1 christos * Fix up checksums, not by recalculating them, but 5523 1.1 christos * simply computing adjustments. 5524 1.1 christos * Why only do this for some platforms on inbound packets ? 5525 1.1 christos * Because for those that it is done, IP processing is yet to happen 5526 1.1 christos * and so the IPv4 header checksum has not yet been evaluated. 5527 1.1 christos * Perhaps it should always be done for the benefit of things like 5528 1.1 christos * fast forwarding (so that it doesn't need to be recomputed) but with 5529 1.1 christos * header checksum offloading, perhaps it is a moot point. 5530 1.1 christos */ 5531 1.1 christos 5532 1.1 christos switch (nat->nat_dir) 5533 1.1 christos { 5534 1.1 christos case NAT_INBOUND : 5535 1.1 christos if ((fin->fin_flx & FI_ICMPERR) == 0) { 5536 1.1 christos fin->fin_ip->ip_src = nat->nat_nsrcip; 5537 1.1 christos fin->fin_saddr = nat->nat_nsrcaddr; 5538 1.1 christos } else { 5539 1.1 christos sum1 = nat->nat_osrcaddr; 5540 1.1 christos sum2 = nat->nat_nsrcaddr; 5541 1.1 christos CALC_SUMD(sum1, sum2, sumd); 5542 1.1 christos ipsumd -= sumd; 5543 1.1 christos } 5544 1.1 christos fin->fin_ip->ip_dst = nat->nat_ndstip; 5545 1.1 christos fin->fin_daddr = nat->nat_ndstaddr; 5546 1.1 christos #if !defined(_KERNEL) || defined(MENTAT) || defined(__sgi) || \ 5547 1.1 christos defined(__osf__) || defined(linux) 5548 1.3 darrenr ipf_fix_outcksum(0, &fin->fin_ip->ip_sum, ipsumd, 0); 5549 1.1 christos #endif 5550 1.1 christos break; 5551 1.1 christos 5552 1.1 christos case NAT_OUTBOUND : 5553 1.1 christos if ((fin->fin_flx & FI_ICMPERR) == 0) { 5554 1.1 christos fin->fin_ip->ip_src = nat->nat_odstip; 5555 1.1 christos fin->fin_saddr = nat->nat_odstaddr; 5556 1.1 christos } else { 5557 1.1 christos sum1 = nat->nat_odstaddr; 5558 1.1 christos sum2 = nat->nat_ndstaddr; 5559 1.1 christos CALC_SUMD(sum1, sum2, sumd); 5560 1.1 christos ipsumd -= sumd; 5561 1.1 christos } 5562 1.1 christos fin->fin_ip->ip_dst = nat->nat_osrcip; 5563 1.1 christos fin->fin_daddr = nat->nat_osrcaddr; 5564 1.1 christos #if !defined(_KERNEL) || defined(MENTAT) || defined(__sgi) || \ 5565 1.1 christos defined(__osf__) || defined(linux) 5566 1.3 darrenr ipf_fix_incksum(0, &fin->fin_ip->ip_sum, ipsumd, 0); 5567 1.1 christos #endif 5568 1.1 christos break; 5569 1.1 christos 5570 1.3 darrenr case NAT_DIVERTIN : 5571 1.1 christos { 5572 1.3 darrenr udphdr_t *uh; 5573 1.1 christos ip_t *ip; 5574 1.1 christos mb_t *m; 5575 1.1 christos 5576 1.1 christos m = M_DUP(np->in_divmp); 5577 1.1 christos if (m == NULL) { 5578 1.3 darrenr NBUMPSIDED(0, ns_divert_dup); 5579 1.1 christos return -1; 5580 1.1 christos } 5581 1.1 christos 5582 1.1 christos ip = MTOD(m, ip_t *); 5583 1.1 christos ip->ip_id = htons(ipf_nextipid(fin)); 5584 1.1 christos sum1 = ntohs(ip->ip_len); 5585 1.3 darrenr ip->ip_len = ntohs(ip->ip_len); 5586 1.3 darrenr ip->ip_len += fin->fin_plen; 5587 1.3 darrenr ip->ip_len = htons(ip->ip_len); 5588 1.3 darrenr 5589 1.3 darrenr uh = (udphdr_t *)(ip + 1); 5590 1.3 darrenr uh->uh_ulen += fin->fin_plen; 5591 1.3 darrenr uh->uh_ulen = htons(uh->uh_ulen); 5592 1.3 darrenr 5593 1.1 christos sum2 = ntohs(ip->ip_id) + ntohs(ip->ip_len); 5594 1.3 darrenr sum2 += ntohs(ip->ip_off) & IP_DF; 5595 1.1 christos CALC_SUMD(sum1, sum2, sumd); 5596 1.1 christos 5597 1.1 christos #if !defined(_KERNEL) || defined(MENTAT) || defined(__sgi) || \ 5598 1.1 christos defined(__osf__) || defined(linux) 5599 1.3 darrenr ipf_fix_outcksum(0, &ip->ip_sum, sumd, 0); 5600 1.1 christos #endif 5601 1.1 christos PREP_MB_T(fin, m); 5602 1.1 christos 5603 1.1 christos fin->fin_ip = ip; 5604 1.3 darrenr fin->fin_plen += sizeof(ip_t) + 8; /* UDP + new IPv4 hdr */ 5605 1.1 christos fin->fin_dlen += sizeof(ip_t) + 8; /* UDP + old IPv4 hdr */ 5606 1.1 christos 5607 1.1 christos nflags &= ~IPN_TCPUDPICMP; 5608 1.1 christos 5609 1.1 christos break; 5610 1.1 christos } 5611 1.1 christos 5612 1.1 christos case NAT_DIVERTOUT : 5613 1.1 christos { 5614 1.1 christos mb_t *m; 5615 1.1 christos 5616 1.1 christos skip = ipf_nat_decap(fin, nat); 5617 1.1 christos if (skip <= 0) { 5618 1.1 christos NBUMPSIDED(0, ns_decap_fail); 5619 1.1 christos return -1; 5620 1.1 christos } 5621 1.1 christos 5622 1.1 christos m = fin->fin_m; 5623 1.1 christos 5624 1.1 christos #if defined(MENTAT) && defined(_KERNEL) 5625 1.1 christos m->b_rptr += skip; 5626 1.1 christos #else 5627 1.1 christos m->m_data += skip; 5628 1.1 christos m->m_len -= skip; 5629 1.1 christos 5630 1.1 christos # ifdef M_PKTHDR 5631 1.1 christos if (m->m_flags & M_PKTHDR) 5632 1.1 christos m->m_pkthdr.len -= skip; 5633 1.1 christos # endif 5634 1.1 christos #endif 5635 1.1 christos 5636 1.1 christos ipf_nat_update(fin, nat); 5637 1.1 christos nflags &= ~IPN_TCPUDPICMP; 5638 1.1 christos fin->fin_flx |= FI_NATED; 5639 1.1 christos if (np != NULL && np->in_tag.ipt_num[0] != 0) 5640 1.1 christos fin->fin_nattag = &np->in_tag; 5641 1.1 christos return 1; 5642 1.1 christos /* NOTREACHED */ 5643 1.1 christos } 5644 1.1 christos } 5645 1.1 christos if (nflags & IPN_TCPUDP) 5646 1.1 christos tcp = fin->fin_dp; 5647 1.1 christos 5648 1.1 christos if (!(fin->fin_flx & FI_SHORT) && (fin->fin_off == 0)) { 5649 1.1 christos u_short *csump; 5650 1.1 christos 5651 1.1 christos if ((nat->nat_odport != 0) && (nflags & IPN_TCPUDP)) { 5652 1.1 christos switch (nat->nat_dir) 5653 1.1 christos { 5654 1.1 christos case NAT_INBOUND : 5655 1.1 christos tcp->th_sport = nat->nat_nsport; 5656 1.1 christos fin->fin_data[0] = ntohs(nat->nat_nsport); 5657 1.1 christos tcp->th_dport = nat->nat_ndport; 5658 1.1 christos fin->fin_data[1] = ntohs(nat->nat_ndport); 5659 1.1 christos break; 5660 1.1 christos 5661 1.1 christos case NAT_OUTBOUND : 5662 1.1 christos tcp->th_sport = nat->nat_odport; 5663 1.1 christos fin->fin_data[0] = ntohs(nat->nat_odport); 5664 1.1 christos tcp->th_dport = nat->nat_osport; 5665 1.1 christos fin->fin_data[1] = ntohs(nat->nat_osport); 5666 1.1 christos break; 5667 1.1 christos } 5668 1.1 christos } 5669 1.1 christos 5670 1.1 christos 5671 1.13 darrenr if ((nat->nat_oicmpid != 0) && (nflags & IPN_ICMPQUERY)) { 5672 1.1 christos icmp = fin->fin_dp; 5673 1.1 christos 5674 1.13 darrenr switch (nat->nat_dir) 5675 1.13 darrenr { 5676 1.13 darrenr case NAT_INBOUND : 5677 1.13 darrenr icmp->icmp_id = nat->nat_nicmpid; 5678 1.13 darrenr break; 5679 1.13 darrenr case NAT_OUTBOUND : 5680 1.13 darrenr icmp->icmp_id = nat->nat_oicmpid; 5681 1.13 darrenr break; 5682 1.13 darrenr } 5683 1.1 christos } 5684 1.1 christos 5685 1.1 christos csump = ipf_nat_proto(fin, nat, nflags); 5686 1.1 christos 5687 1.1 christos /* 5688 1.1 christos * The above comments do not hold for layer 4 (or higher) 5689 1.1 christos * checksums... 5690 1.1 christos */ 5691 1.1 christos if (csump != NULL) { 5692 1.1 christos if (nat->nat_dir == NAT_OUTBOUND) 5693 1.3 darrenr ipf_fix_incksum(0, csump, nat->nat_sumd[0], 0); 5694 1.1 christos else 5695 1.3 darrenr ipf_fix_outcksum(0, csump, nat->nat_sumd[0], 0); 5696 1.1 christos } 5697 1.1 christos } 5698 1.1 christos 5699 1.1 christos fin->fin_flx |= FI_NATED; 5700 1.1 christos if (np != NULL && np->in_tag.ipt_num[0] != 0) 5701 1.1 christos fin->fin_nattag = &np->in_tag; 5702 1.1 christos return 1; 5703 1.1 christos } 5704 1.1 christos 5705 1.1 christos 5706 1.1 christos /* ------------------------------------------------------------------------ */ 5707 1.1 christos /* Function: ipf_nat_proto */ 5708 1.1 christos /* Returns: u_short* - pointer to transport header checksum to update, */ 5709 1.1 christos /* NULL if the transport protocol is not recognised */ 5710 1.1 christos /* as needing a checksum update. */ 5711 1.1 christos /* Parameters: fin(I) - pointer to packet information */ 5712 1.1 christos /* nat(I) - pointer to NAT structure */ 5713 1.1 christos /* nflags(I) - NAT flags set for this packet */ 5714 1.1 christos /* */ 5715 1.1 christos /* Return the pointer to the checksum field for each protocol so understood.*/ 5716 1.1 christos /* If support for making other changes to a protocol header is required, */ 5717 1.1 christos /* that is not strictly 'address' translation, such as clamping the MSS in */ 5718 1.1 christos /* TCP down to a specific value, then do it from here. */ 5719 1.1 christos /* ------------------------------------------------------------------------ */ 5720 1.1 christos u_short * 5721 1.2 christos ipf_nat_proto(fr_info_t *fin, nat_t *nat, u_int nflags) 5722 1.1 christos { 5723 1.1 christos icmphdr_t *icmp; 5724 1.1 christos u_short *csump; 5725 1.1 christos tcphdr_t *tcp; 5726 1.1 christos udphdr_t *udp; 5727 1.1 christos 5728 1.1 christos csump = NULL; 5729 1.1 christos if (fin->fin_out == 0) { 5730 1.1 christos fin->fin_rev = (nat->nat_dir & NAT_OUTBOUND); 5731 1.1 christos } else { 5732 1.1 christos fin->fin_rev = ((nat->nat_dir & NAT_OUTBOUND) == 0); 5733 1.1 christos } 5734 1.1 christos 5735 1.1 christos switch (fin->fin_p) 5736 1.1 christos { 5737 1.1 christos case IPPROTO_TCP : 5738 1.1 christos tcp = fin->fin_dp; 5739 1.1 christos 5740 1.1 christos if ((nflags & IPN_TCP) != 0) 5741 1.1 christos csump = &tcp->th_sum; 5742 1.1 christos 5743 1.1 christos /* 5744 1.1 christos * Do a MSS CLAMPING on a SYN packet, 5745 1.1 christos * only deal IPv4 for now. 5746 1.1 christos */ 5747 1.1 christos if ((nat->nat_mssclamp != 0) && (tcp->th_flags & TH_SYN) != 0) 5748 1.1 christos ipf_nat_mssclamp(tcp, nat->nat_mssclamp, fin, csump); 5749 1.1 christos 5750 1.1 christos break; 5751 1.1 christos 5752 1.1 christos case IPPROTO_UDP : 5753 1.1 christos udp = fin->fin_dp; 5754 1.1 christos 5755 1.1 christos if ((nflags & IPN_UDP) != 0) { 5756 1.1 christos if (udp->uh_sum != 0) 5757 1.1 christos csump = &udp->uh_sum; 5758 1.1 christos } 5759 1.1 christos break; 5760 1.1 christos 5761 1.1 christos case IPPROTO_ICMP : 5762 1.1 christos icmp = fin->fin_dp; 5763 1.1 christos 5764 1.1 christos if ((nflags & IPN_ICMPQUERY) != 0) { 5765 1.1 christos if (icmp->icmp_cksum != 0) 5766 1.1 christos csump = &icmp->icmp_cksum; 5767 1.1 christos } 5768 1.1 christos break; 5769 1.3 darrenr 5770 1.3 darrenr #ifdef USE_INET6 5771 1.3 darrenr case IPPROTO_ICMPV6 : 5772 1.3 darrenr { 5773 1.3 darrenr struct icmp6_hdr *icmp6 = (struct icmp6_hdr *)fin->fin_dp; 5774 1.3 darrenr 5775 1.3 darrenr icmp6 = fin->fin_dp; 5776 1.3 darrenr 5777 1.3 darrenr if ((nflags & IPN_ICMPQUERY) != 0) { 5778 1.3 darrenr if (icmp6->icmp6_cksum != 0) 5779 1.3 darrenr csump = &icmp6->icmp6_cksum; 5780 1.3 darrenr } 5781 1.3 darrenr break; 5782 1.3 darrenr } 5783 1.3 darrenr #endif 5784 1.1 christos } 5785 1.1 christos return csump; 5786 1.1 christos } 5787 1.1 christos 5788 1.1 christos 5789 1.1 christos /* ------------------------------------------------------------------------ */ 5790 1.1 christos /* Function: ipf_nat_expire */ 5791 1.1 christos /* Returns: Nil */ 5792 1.3 darrenr /* Parameters: softc(I) - pointer to soft context main structure */ 5793 1.1 christos /* */ 5794 1.1 christos /* Check all of the timeout queues for entries at the top which need to be */ 5795 1.1 christos /* expired. */ 5796 1.1 christos /* ------------------------------------------------------------------------ */ 5797 1.1 christos void 5798 1.2 christos ipf_nat_expire(ipf_main_softc_t *softc) 5799 1.1 christos { 5800 1.1 christos ipf_nat_softc_t *softn = softc->ipf_nat_soft; 5801 1.1 christos ipftq_t *ifq, *ifqnext; 5802 1.1 christos ipftqent_t *tqe, *tqn; 5803 1.1 christos int i; 5804 1.1 christos SPL_INT(s); 5805 1.1 christos 5806 1.1 christos SPL_NET(s); 5807 1.1 christos WRITE_ENTER(&softc->ipf_nat); 5808 1.1 christos for (ifq = softn->ipf_nat_tcptq, i = 0; ifq != NULL; 5809 1.1 christos ifq = ifq->ifq_next) { 5810 1.1 christos for (tqn = ifq->ifq_head; ((tqe = tqn) != NULL); i++) { 5811 1.1 christos if (tqe->tqe_die > softc->ipf_ticks) 5812 1.1 christos break; 5813 1.1 christos tqn = tqe->tqe_next; 5814 1.1 christos ipf_nat_delete(softc, tqe->tqe_parent, NL_EXPIRE); 5815 1.1 christos } 5816 1.1 christos } 5817 1.1 christos 5818 1.1 christos for (ifq = softn->ipf_nat_utqe; ifq != NULL; ifq = ifq->ifq_next) { 5819 1.1 christos for (tqn = ifq->ifq_head; ((tqe = tqn) != NULL); i++) { 5820 1.1 christos if (tqe->tqe_die > softc->ipf_ticks) 5821 1.1 christos break; 5822 1.1 christos tqn = tqe->tqe_next; 5823 1.1 christos ipf_nat_delete(softc, tqe->tqe_parent, NL_EXPIRE); 5824 1.1 christos } 5825 1.1 christos } 5826 1.1 christos 5827 1.1 christos for (ifq = softn->ipf_nat_utqe; ifq != NULL; ifq = ifqnext) { 5828 1.1 christos ifqnext = ifq->ifq_next; 5829 1.1 christos 5830 1.1 christos if (((ifq->ifq_flags & IFQF_DELETE) != 0) && 5831 1.1 christos (ifq->ifq_ref == 0)) { 5832 1.1 christos ipf_freetimeoutqueue(softc, ifq); 5833 1.1 christos } 5834 1.1 christos } 5835 1.1 christos 5836 1.1 christos if (softn->ipf_nat_doflush != 0) { 5837 1.1 christos ipf_nat_extraflush(softc, softn, 2); 5838 1.1 christos softn->ipf_nat_doflush = 0; 5839 1.1 christos } 5840 1.1 christos 5841 1.1 christos RWLOCK_EXIT(&softc->ipf_nat); 5842 1.1 christos SPL_X(s); 5843 1.1 christos } 5844 1.1 christos 5845 1.1 christos 5846 1.1 christos /* ------------------------------------------------------------------------ */ 5847 1.1 christos /* Function: ipf_nat_sync */ 5848 1.1 christos /* Returns: Nil */ 5849 1.3 darrenr /* Parameters: softc(I) - pointer to soft context main structure */ 5850 1.3 darrenr /* ifp(I) - pointer to network interface */ 5851 1.1 christos /* */ 5852 1.1 christos /* Walk through all of the currently active NAT sessions, looking for those */ 5853 1.1 christos /* which need to have their translated address updated. */ 5854 1.1 christos /* ------------------------------------------------------------------------ */ 5855 1.1 christos void 5856 1.2 christos ipf_nat_sync(ipf_main_softc_t *softc, void *ifp) 5857 1.1 christos { 5858 1.1 christos ipf_nat_softc_t *softn = softc->ipf_nat_soft; 5859 1.1 christos u_32_t sum1, sum2, sumd; 5860 1.1 christos i6addr_t in; 5861 1.1 christos ipnat_t *n; 5862 1.1 christos nat_t *nat; 5863 1.1 christos void *ifp2; 5864 1.1 christos int idx; 5865 1.1 christos SPL_INT(s); 5866 1.1 christos 5867 1.1 christos if (softc->ipf_running <= 0) 5868 1.1 christos return; 5869 1.1 christos 5870 1.1 christos /* 5871 1.1 christos * Change IP addresses for NAT sessions for any protocol except TCP 5872 1.1 christos * since it will break the TCP connection anyway. The only rules 5873 1.1 christos * which will get changed are those which are "map ... -> 0/32", 5874 1.1 christos * where the rule specifies the address is taken from the interface. 5875 1.1 christos */ 5876 1.1 christos SPL_NET(s); 5877 1.1 christos WRITE_ENTER(&softc->ipf_nat); 5878 1.1 christos 5879 1.1 christos if (softc->ipf_running <= 0) { 5880 1.1 christos RWLOCK_EXIT(&softc->ipf_nat); 5881 1.1 christos return; 5882 1.1 christos } 5883 1.1 christos 5884 1.1 christos for (nat = softn->ipf_nat_instances; nat; nat = nat->nat_next) { 5885 1.1 christos if ((nat->nat_flags & IPN_TCP) != 0) 5886 1.1 christos continue; 5887 1.1 christos 5888 1.1 christos n = nat->nat_ptr; 5889 1.1 christos if (n != NULL) { 5890 1.1 christos if (n->in_v[1] == 4) { 5891 1.1 christos if (n->in_redir & NAT_MAP) { 5892 1.1 christos if ((n->in_nsrcaddr != 0) || 5893 1.1 christos (n->in_nsrcmsk != 0xffffffff)) 5894 1.1 christos continue; 5895 1.1 christos } else if (n->in_redir & NAT_REDIRECT) { 5896 1.1 christos if ((n->in_ndstaddr != 0) || 5897 1.1 christos (n->in_ndstmsk != 0xffffffff)) 5898 1.1 christos continue; 5899 1.1 christos } 5900 1.1 christos } 5901 1.1 christos #ifdef USE_INET6 5902 1.1 christos if (n->in_v[1] == 4) { 5903 1.1 christos if (n->in_redir & NAT_MAP) { 5904 1.1 christos if (!IP6_ISZERO(&n->in_nsrcaddr) || 5905 1.1 christos !IP6_ISONES(&n->in_nsrcmsk)) 5906 1.1 christos continue; 5907 1.1 christos } else if (n->in_redir & NAT_REDIRECT) { 5908 1.1 christos if (!IP6_ISZERO(&n->in_ndstaddr) || 5909 1.1 christos !IP6_ISONES(&n->in_ndstmsk)) 5910 1.1 christos continue; 5911 1.1 christos } 5912 1.1 christos } 5913 1.1 christos #endif 5914 1.1 christos } 5915 1.1 christos 5916 1.1 christos if (((ifp == NULL) || (ifp == nat->nat_ifps[0]) || 5917 1.1 christos (ifp == nat->nat_ifps[1]))) { 5918 1.1 christos nat->nat_ifps[0] = GETIFP(nat->nat_ifnames[0], 5919 1.1 christos nat->nat_v[0]); 5920 1.1 christos if ((nat->nat_ifps[0] != NULL) && 5921 1.1 christos (nat->nat_ifps[0] != (void *)-1)) { 5922 1.1 christos nat->nat_mtu[0] = GETIFMTU_4(nat->nat_ifps[0]); 5923 1.1 christos } 5924 1.1 christos if (nat->nat_ifnames[1][0] != '\0') { 5925 1.1 christos nat->nat_ifps[1] = GETIFP(nat->nat_ifnames[1], 5926 1.1 christos nat->nat_v[1]); 5927 1.1 christos } else { 5928 1.1 christos nat->nat_ifps[1] = nat->nat_ifps[0]; 5929 1.1 christos } 5930 1.1 christos if ((nat->nat_ifps[1] != NULL) && 5931 1.1 christos (nat->nat_ifps[1] != (void *)-1)) { 5932 1.1 christos nat->nat_mtu[1] = GETIFMTU_4(nat->nat_ifps[1]); 5933 1.1 christos } 5934 1.1 christos ifp2 = nat->nat_ifps[0]; 5935 1.1 christos if (ifp2 == NULL) 5936 1.1 christos continue; 5937 1.1 christos 5938 1.1 christos /* 5939 1.1 christos * Change the map-to address to be the same as the 5940 1.1 christos * new one. 5941 1.1 christos */ 5942 1.1 christos sum1 = NATFSUM(nat, nat->nat_v[1], nat_nsrc6); 5943 1.1 christos if (ipf_ifpaddr(softc, nat->nat_v[0], FRI_NORMAL, ifp2, 5944 1.1 christos &in, NULL) != -1) { 5945 1.1 christos if (nat->nat_v[0] == 4) 5946 1.1 christos nat->nat_nsrcip = in.in4; 5947 1.1 christos } 5948 1.1 christos sum2 = NATFSUM(nat, nat->nat_v[1], nat_nsrc6); 5949 1.1 christos 5950 1.1 christos if (sum1 == sum2) 5951 1.1 christos continue; 5952 1.1 christos /* 5953 1.1 christos * Readjust the checksum adjustment to take into 5954 1.1 christos * account the new IP#. 5955 1.1 christos */ 5956 1.1 christos CALC_SUMD(sum1, sum2, sumd); 5957 1.1 christos /* XXX - dont change for TCP when solaris does 5958 1.1 christos * hardware checksumming. 5959 1.1 christos */ 5960 1.1 christos sumd += nat->nat_sumd[0]; 5961 1.1 christos nat->nat_sumd[0] = (sumd & 0xffff) + (sumd >> 16); 5962 1.1 christos nat->nat_sumd[1] = nat->nat_sumd[0]; 5963 1.1 christos } 5964 1.1 christos } 5965 1.1 christos 5966 1.1 christos for (n = softn->ipf_nat_list; (n != NULL); n = n->in_next) { 5967 1.1 christos char *base = n->in_names; 5968 1.1 christos 5969 1.1 christos if ((ifp == NULL) || (n->in_ifps[0] == ifp)) 5970 1.1 christos n->in_ifps[0] = ipf_resolvenic(softc, 5971 1.1 christos base + n->in_ifnames[0], 5972 1.1 christos n->in_v[0]); 5973 1.1 christos if ((ifp == NULL) || (n->in_ifps[1] == ifp)) 5974 1.1 christos n->in_ifps[1] = ipf_resolvenic(softc, 5975 1.1 christos base + n->in_ifnames[1], 5976 1.1 christos n->in_v[1]); 5977 1.1 christos 5978 1.1 christos if (n->in_redir & NAT_REDIRECT) 5979 1.1 christos idx = 1; 5980 1.1 christos else 5981 1.1 christos idx = 0; 5982 1.1 christos 5983 1.1 christos if (((ifp == NULL) || (n->in_ifps[idx] == ifp)) && 5984 1.1 christos (n->in_ifps[idx] != NULL && 5985 1.1 christos n->in_ifps[idx] != (void *)-1)) { 5986 1.1 christos 5987 1.1 christos ipf_nat_nextaddrinit(softc, n->in_names, &n->in_osrc, 5988 1.1 christos 0, n->in_ifps[idx]); 5989 1.1 christos ipf_nat_nextaddrinit(softc, n->in_names, &n->in_odst, 5990 1.1 christos 0, n->in_ifps[idx]); 5991 1.1 christos ipf_nat_nextaddrinit(softc, n->in_names, &n->in_nsrc, 5992 1.1 christos 0, n->in_ifps[idx]); 5993 1.1 christos ipf_nat_nextaddrinit(softc, n->in_names, &n->in_ndst, 5994 1.1 christos 0, n->in_ifps[idx]); 5995 1.1 christos } 5996 1.1 christos } 5997 1.1 christos RWLOCK_EXIT(&softc->ipf_nat); 5998 1.1 christos SPL_X(s); 5999 1.1 christos } 6000 1.1 christos 6001 1.1 christos 6002 1.1 christos /* ------------------------------------------------------------------------ */ 6003 1.1 christos /* Function: ipf_nat_icmpquerytype */ 6004 1.1 christos /* Returns: int - 1 == success, 0 == failure */ 6005 1.1 christos /* Parameters: icmptype(I) - ICMP type number */ 6006 1.1 christos /* */ 6007 1.1 christos /* Tests to see if the ICMP type number passed is a query/response type or */ 6008 1.1 christos /* not. */ 6009 1.1 christos /* ------------------------------------------------------------------------ */ 6010 1.1 christos static int 6011 1.2 christos ipf_nat_icmpquerytype(int icmptype) 6012 1.1 christos { 6013 1.1 christos 6014 1.1 christos /* 6015 1.1 christos * For the ICMP query NAT code, it is essential that both the query 6016 1.1 christos * and the reply match on the NAT rule. Because the NAT structure 6017 1.1 christos * does not keep track of the icmptype, and a single NAT structure 6018 1.1 christos * is used for all icmp types with the same src, dest and id, we 6019 1.1 christos * simply define the replies as queries as well. The funny thing is, 6020 1.2 christos * although it seems silly to call a reply a query, this is exactly 6021 1.1 christos * as it is defined in the IPv4 specification 6022 1.1 christos */ 6023 1.1 christos switch (icmptype) 6024 1.1 christos { 6025 1.1 christos case ICMP_ECHOREPLY: 6026 1.1 christos case ICMP_ECHO: 6027 1.18 khorben /* route advertisement/sollicitation is currently unsupported: */ 6028 1.1 christos /* it would require rewriting the ICMP data section */ 6029 1.1 christos case ICMP_TSTAMP: 6030 1.1 christos case ICMP_TSTAMPREPLY: 6031 1.1 christos case ICMP_IREQ: 6032 1.1 christos case ICMP_IREQREPLY: 6033 1.1 christos case ICMP_MASKREQ: 6034 1.1 christos case ICMP_MASKREPLY: 6035 1.1 christos return 1; 6036 1.1 christos default: 6037 1.1 christos return 0; 6038 1.1 christos } 6039 1.1 christos } 6040 1.1 christos 6041 1.1 christos 6042 1.1 christos /* ------------------------------------------------------------------------ */ 6043 1.1 christos /* Function: nat_log */ 6044 1.1 christos /* Returns: Nil */ 6045 1.3 darrenr /* Parameters: softc(I) - pointer to soft context main structure */ 6046 1.3 darrenr /* softn(I) - pointer to NAT context structure */ 6047 1.3 darrenr /* nat(I) - pointer to NAT structure */ 6048 1.1 christos /* action(I) - action related to NAT structure being performed */ 6049 1.1 christos /* */ 6050 1.1 christos /* Creates a NAT log entry. */ 6051 1.1 christos /* ------------------------------------------------------------------------ */ 6052 1.1 christos void 6053 1.2 christos ipf_nat_log(ipf_main_softc_t *softc, ipf_nat_softc_t *softn, struct nat *nat, 6054 1.2 christos u_int action) 6055 1.1 christos { 6056 1.1 christos #ifdef IPFILTER_LOG 6057 1.1 christos # ifndef LARGE_NAT 6058 1.1 christos struct ipnat *np; 6059 1.1 christos int rulen; 6060 1.1 christos # endif 6061 1.1 christos struct natlog natl; 6062 1.1 christos void *items[1]; 6063 1.1 christos size_t sizes[1]; 6064 1.1 christos int types[1]; 6065 1.1 christos 6066 1.1 christos bcopy((char *)&nat->nat_osrc6, (char *)&natl.nl_osrcip, 6067 1.1 christos sizeof(natl.nl_osrcip)); 6068 1.1 christos bcopy((char *)&nat->nat_nsrc6, (char *)&natl.nl_nsrcip, 6069 1.1 christos sizeof(natl.nl_nsrcip)); 6070 1.1 christos bcopy((char *)&nat->nat_odst6, (char *)&natl.nl_odstip, 6071 1.1 christos sizeof(natl.nl_odstip)); 6072 1.1 christos bcopy((char *)&nat->nat_ndst6, (char *)&natl.nl_ndstip, 6073 1.1 christos sizeof(natl.nl_ndstip)); 6074 1.1 christos 6075 1.1 christos natl.nl_bytes[0] = nat->nat_bytes[0]; 6076 1.1 christos natl.nl_bytes[1] = nat->nat_bytes[1]; 6077 1.1 christos natl.nl_pkts[0] = nat->nat_pkts[0]; 6078 1.1 christos natl.nl_pkts[1] = nat->nat_pkts[1]; 6079 1.1 christos natl.nl_odstport = nat->nat_odport; 6080 1.1 christos natl.nl_osrcport = nat->nat_osport; 6081 1.1 christos natl.nl_nsrcport = nat->nat_nsport; 6082 1.1 christos natl.nl_ndstport = nat->nat_ndport; 6083 1.1 christos natl.nl_p[0] = nat->nat_pr[0]; 6084 1.1 christos natl.nl_p[1] = nat->nat_pr[1]; 6085 1.1 christos natl.nl_v[0] = nat->nat_v[0]; 6086 1.1 christos natl.nl_v[1] = nat->nat_v[1]; 6087 1.1 christos natl.nl_type = nat->nat_redir; 6088 1.1 christos natl.nl_action = action; 6089 1.1 christos natl.nl_rule = -1; 6090 1.1 christos 6091 1.1 christos bcopy(nat->nat_ifnames[0], natl.nl_ifnames[0], 6092 1.1 christos sizeof(nat->nat_ifnames[0])); 6093 1.1 christos bcopy(nat->nat_ifnames[1], natl.nl_ifnames[1], 6094 1.1 christos sizeof(nat->nat_ifnames[1])); 6095 1.1 christos 6096 1.1 christos # ifndef LARGE_NAT 6097 1.1 christos if (nat->nat_ptr != NULL) { 6098 1.1 christos for (rulen = 0, np = softn->ipf_nat_list; np != NULL; 6099 1.1 christos np = np->in_next, rulen++) 6100 1.1 christos if (np == nat->nat_ptr) { 6101 1.1 christos natl.nl_rule = rulen; 6102 1.1 christos break; 6103 1.1 christos } 6104 1.1 christos } 6105 1.1 christos # endif 6106 1.1 christos items[0] = &natl; 6107 1.1 christos sizes[0] = sizeof(natl); 6108 1.1 christos types[0] = 0; 6109 1.1 christos 6110 1.1 christos (void) ipf_log_items(softc, IPL_LOGNAT, NULL, items, sizes, types, 1); 6111 1.1 christos #endif 6112 1.1 christos } 6113 1.1 christos 6114 1.1 christos 6115 1.1 christos #if defined(__OpenBSD__) 6116 1.1 christos /* ------------------------------------------------------------------------ */ 6117 1.1 christos /* Function: ipf_nat_ifdetach */ 6118 1.1 christos /* Returns: Nil */ 6119 1.1 christos /* Parameters: ifp(I) - pointer to network interface */ 6120 1.1 christos /* */ 6121 1.1 christos /* Compatibility interface for OpenBSD to trigger the correct updating of */ 6122 1.1 christos /* interface references within IPFilter. */ 6123 1.1 christos /* ------------------------------------------------------------------------ */ 6124 1.1 christos void 6125 1.1 christos ipf_nat_ifdetach(ifp) 6126 1.1 christos void *ifp; 6127 1.1 christos { 6128 1.1 christos ipf_main_softc_t *softc; 6129 1.1 christos 6130 1.1 christos softc = ipf_get_softc(0); 6131 1.1 christos 6132 1.1 christos ipf_sync(ifp); 6133 1.1 christos return; 6134 1.1 christos } 6135 1.1 christos #endif 6136 1.1 christos 6137 1.1 christos 6138 1.1 christos /* ------------------------------------------------------------------------ */ 6139 1.3 darrenr /* Function: ipf_nat_rule_deref */ 6140 1.1 christos /* Returns: Nil */ 6141 1.3 darrenr /* Parameters: softc(I) - pointer to soft context main structure */ 6142 1.3 darrenr /* inp(I) - pointer to pointer to NAT rule */ 6143 1.1 christos /* Write Locks: ipf_nat */ 6144 1.1 christos /* */ 6145 1.3 darrenr /* Dropping the refernce count for a rule means that whatever held the */ 6146 1.3 darrenr /* pointer to this rule (*inp) is no longer interested in it and when the */ 6147 1.3 darrenr /* reference count drops to zero, any resources allocated for the rule can */ 6148 1.3 darrenr /* be released and the rule itself free'd. */ 6149 1.1 christos /* ------------------------------------------------------------------------ */ 6150 1.1 christos void 6151 1.3 darrenr ipf_nat_rule_deref(ipf_main_softc_t *softc, ipnat_t **inp) 6152 1.1 christos { 6153 1.1 christos ipf_nat_softc_t *softn = softc->ipf_nat_soft; 6154 1.3 darrenr ipnat_t *n; 6155 1.1 christos 6156 1.3 darrenr n = *inp; 6157 1.1 christos *inp = NULL; 6158 1.3 darrenr n->in_use--; 6159 1.3 darrenr if (n->in_use > 0) 6160 1.3 darrenr return; 6161 1.3 darrenr 6162 1.3 darrenr if (n->in_apr != NULL) 6163 1.3 darrenr ipf_proxy_deref(n->in_apr); 6164 1.3 darrenr 6165 1.3 darrenr ipf_nat_rule_fini(softc, n); 6166 1.3 darrenr 6167 1.3 darrenr if (n->in_redir & NAT_REDIRECT) { 6168 1.3 darrenr if ((n->in_flags & IPN_PROXYRULE) == 0) { 6169 1.3 darrenr ATOMIC_DEC32(softn->ipf_nat_stats.ns_rules_rdr); 6170 1.3 darrenr } 6171 1.1 christos } 6172 1.3 darrenr if (n->in_redir & (NAT_MAP|NAT_MAPBLK)) { 6173 1.3 darrenr if ((n->in_flags & IPN_PROXYRULE) == 0) { 6174 1.3 darrenr ATOMIC_DEC32(softn->ipf_nat_stats.ns_rules_map); 6175 1.3 darrenr } 6176 1.3 darrenr } 6177 1.3 darrenr 6178 1.3 darrenr if (n->in_tqehead[0] != NULL) { 6179 1.3 darrenr if (ipf_deletetimeoutqueue(n->in_tqehead[0]) == 0) { 6180 1.24 christos ipf_freetimeoutqueue(softc, n->in_tqehead[0]); 6181 1.3 darrenr } 6182 1.3 darrenr } 6183 1.3 darrenr 6184 1.3 darrenr if (n->in_tqehead[1] != NULL) { 6185 1.3 darrenr if (ipf_deletetimeoutqueue(n->in_tqehead[1]) == 0) { 6186 1.3 darrenr ipf_freetimeoutqueue(softc, n->in_tqehead[1]); 6187 1.3 darrenr } 6188 1.3 darrenr } 6189 1.3 darrenr 6190 1.3 darrenr if ((n->in_flags & IPN_PROXYRULE) == 0) { 6191 1.3 darrenr ATOMIC_DEC32(softn->ipf_nat_stats.ns_rules); 6192 1.3 darrenr } 6193 1.3 darrenr 6194 1.3 darrenr MUTEX_DESTROY(&n->in_lock); 6195 1.3 darrenr 6196 1.3 darrenr KFREES(n, n->in_size); 6197 1.3 darrenr 6198 1.3 darrenr #if SOLARIS && !defined(INSTANCES) 6199 1.3 darrenr if (softn->ipf_nat_stats.ns_rules == 0) 6200 1.3 darrenr pfil_delayed_copy = 1; 6201 1.3 darrenr #endif 6202 1.1 christos } 6203 1.1 christos 6204 1.1 christos 6205 1.1 christos /* ------------------------------------------------------------------------ */ 6206 1.1 christos /* Function: ipf_nat_deref */ 6207 1.1 christos /* Returns: Nil */ 6208 1.3 darrenr /* Parameters: softc(I) - pointer to soft context main structure */ 6209 1.3 darrenr /* natp(I) - pointer to pointer to NAT table entry */ 6210 1.1 christos /* */ 6211 1.1 christos /* Decrement the reference counter for this NAT table entry and free it if */ 6212 1.1 christos /* there are no more things using it. */ 6213 1.1 christos /* */ 6214 1.1 christos /* IF nat_ref == 1 when this function is called, then we have an orphan nat */ 6215 1.1 christos /* structure *because* it only gets called on paths _after_ nat_ref has been*/ 6216 1.1 christos /* incremented. If nat_ref == 1 then we shouldn't decrement it here */ 6217 1.1 christos /* because nat_delete() will do that and send nat_ref to -1. */ 6218 1.1 christos /* */ 6219 1.1 christos /* Holding the lock on nat_lock is required to serialise nat_delete() being */ 6220 1.1 christos /* called from a NAT flush ioctl with a deref happening because of a packet.*/ 6221 1.1 christos /* ------------------------------------------------------------------------ */ 6222 1.1 christos void 6223 1.2 christos ipf_nat_deref(ipf_main_softc_t *softc, nat_t **natp) 6224 1.1 christos { 6225 1.1 christos nat_t *nat; 6226 1.1 christos 6227 1.1 christos nat = *natp; 6228 1.1 christos *natp = NULL; 6229 1.1 christos 6230 1.1 christos MUTEX_ENTER(&nat->nat_lock); 6231 1.1 christos if (nat->nat_ref > 1) { 6232 1.1 christos nat->nat_ref--; 6233 1.3 darrenr ASSERT(nat->nat_ref >= 0); 6234 1.1 christos MUTEX_EXIT(&nat->nat_lock); 6235 1.1 christos return; 6236 1.1 christos } 6237 1.1 christos MUTEX_EXIT(&nat->nat_lock); 6238 1.1 christos 6239 1.1 christos WRITE_ENTER(&softc->ipf_nat); 6240 1.1 christos ipf_nat_delete(softc, nat, NL_EXPIRE); 6241 1.1 christos RWLOCK_EXIT(&softc->ipf_nat); 6242 1.1 christos } 6243 1.1 christos 6244 1.1 christos 6245 1.1 christos /* ------------------------------------------------------------------------ */ 6246 1.1 christos /* Function: ipf_nat_clone */ 6247 1.1 christos /* Returns: ipstate_t* - NULL == cloning failed, */ 6248 1.1 christos /* else pointer to new state structure */ 6249 1.1 christos /* Parameters: fin(I) - pointer to packet information */ 6250 1.1 christos /* is(I) - pointer to master state structure */ 6251 1.1 christos /* Write Lock: ipf_nat */ 6252 1.1 christos /* */ 6253 1.1 christos /* Create a "duplcate" state table entry from the master. */ 6254 1.1 christos /* ------------------------------------------------------------------------ */ 6255 1.1 christos nat_t * 6256 1.2 christos ipf_nat_clone(fr_info_t *fin, nat_t *nat) 6257 1.1 christos { 6258 1.1 christos ipf_main_softc_t *softc = fin->fin_main_soft; 6259 1.1 christos ipf_nat_softc_t *softn = softc->ipf_nat_soft; 6260 1.1 christos frentry_t *fr; 6261 1.1 christos nat_t *clone; 6262 1.1 christos ipnat_t *np; 6263 1.1 christos 6264 1.1 christos KMALLOC(clone, nat_t *); 6265 1.1 christos if (clone == NULL) { 6266 1.1 christos NBUMPSIDED(fin->fin_out, ns_clone_nomem); 6267 1.1 christos return NULL; 6268 1.1 christos } 6269 1.1 christos bcopy((char *)nat, (char *)clone, sizeof(*clone)); 6270 1.1 christos 6271 1.1 christos MUTEX_NUKE(&clone->nat_lock); 6272 1.1 christos 6273 1.1 christos clone->nat_rev = fin->fin_rev; 6274 1.1 christos clone->nat_aps = NULL; 6275 1.1 christos /* 6276 1.1 christos * Initialize all these so that ipf_nat_delete() doesn't cause a crash. 6277 1.1 christos */ 6278 1.1 christos clone->nat_tqe.tqe_pnext = NULL; 6279 1.1 christos clone->nat_tqe.tqe_next = NULL; 6280 1.1 christos clone->nat_tqe.tqe_ifq = NULL; 6281 1.1 christos clone->nat_tqe.tqe_parent = clone; 6282 1.1 christos 6283 1.1 christos clone->nat_flags &= ~SI_CLONE; 6284 1.1 christos clone->nat_flags |= SI_CLONED; 6285 1.1 christos 6286 1.1 christos if (clone->nat_hm) 6287 1.1 christos clone->nat_hm->hm_ref++; 6288 1.1 christos 6289 1.1 christos if (ipf_nat_insert(softc, softn, clone) == -1) { 6290 1.1 christos KFREE(clone); 6291 1.1 christos NBUMPSIDED(fin->fin_out, ns_insert_fail); 6292 1.1 christos return NULL; 6293 1.1 christos } 6294 1.1 christos 6295 1.1 christos np = clone->nat_ptr; 6296 1.1 christos if (np != NULL) { 6297 1.1 christos if (softn->ipf_nat_logging) 6298 1.1 christos ipf_nat_log(softc, softn, clone, NL_CLONE); 6299 1.1 christos np->in_use++; 6300 1.1 christos } 6301 1.1 christos fr = clone->nat_fr; 6302 1.1 christos if (fr != NULL) { 6303 1.1 christos MUTEX_ENTER(&fr->fr_lock); 6304 1.1 christos fr->fr_ref++; 6305 1.1 christos MUTEX_EXIT(&fr->fr_lock); 6306 1.1 christos } 6307 1.1 christos 6308 1.1 christos 6309 1.1 christos /* 6310 1.1 christos * Because the clone is created outside the normal loop of things and 6311 1.1 christos * TCP has special needs in terms of state, initialise the timeout 6312 1.1 christos * state of the new NAT from here. 6313 1.1 christos */ 6314 1.1 christos if (clone->nat_pr[0] == IPPROTO_TCP) { 6315 1.1 christos (void) ipf_tcp_age(&clone->nat_tqe, fin, softn->ipf_nat_tcptq, 6316 1.1 christos clone->nat_flags, 2); 6317 1.1 christos } 6318 1.1 christos clone->nat_sync = ipf_sync_new(softc, SMC_NAT, fin, clone); 6319 1.1 christos if (softn->ipf_nat_logging) 6320 1.1 christos ipf_nat_log(softc, softn, clone, NL_CLONE); 6321 1.1 christos return clone; 6322 1.1 christos } 6323 1.1 christos 6324 1.1 christos 6325 1.1 christos /* ------------------------------------------------------------------------ */ 6326 1.1 christos /* Function: ipf_nat_wildok */ 6327 1.1 christos /* Returns: int - 1 == packet's ports match wildcards */ 6328 1.1 christos /* 0 == packet's ports don't match wildcards */ 6329 1.1 christos /* Parameters: nat(I) - NAT entry */ 6330 1.1 christos /* sport(I) - source port */ 6331 1.1 christos /* dport(I) - destination port */ 6332 1.1 christos /* flags(I) - wildcard flags */ 6333 1.1 christos /* dir(I) - packet direction */ 6334 1.1 christos /* */ 6335 1.1 christos /* Use NAT entry and packet direction to determine which combination of */ 6336 1.1 christos /* wildcard flags should be used. */ 6337 1.1 christos /* ------------------------------------------------------------------------ */ 6338 1.1 christos int 6339 1.2 christos ipf_nat_wildok(nat_t *nat, int sport, int dport, int flags, int dir) 6340 1.1 christos { 6341 1.1 christos /* 6342 1.1 christos * When called by dir is set to 6343 1.1 christos * nat_inlookup NAT_INBOUND (0) 6344 1.1 christos * nat_outlookup NAT_OUTBOUND (1) 6345 1.1 christos * 6346 1.1 christos * We simply combine the packet's direction in dir with the original 6347 1.1 christos * "intended" direction of that NAT entry in nat->nat_dir to decide 6348 1.1 christos * which combination of wildcard flags to allow. 6349 1.1 christos */ 6350 1.1 christos switch ((dir << 1) | (nat->nat_dir & (NAT_INBOUND|NAT_OUTBOUND))) 6351 1.1 christos { 6352 1.1 christos case 3: /* outbound packet / outbound entry */ 6353 1.1 christos if (((nat->nat_osport == sport) || 6354 1.1 christos (flags & SI_W_SPORT)) && 6355 1.1 christos ((nat->nat_odport == dport) || 6356 1.1 christos (flags & SI_W_DPORT))) 6357 1.1 christos return 1; 6358 1.1 christos break; 6359 1.1 christos case 2: /* outbound packet / inbound entry */ 6360 1.1 christos if (((nat->nat_osport == dport) || 6361 1.1 christos (flags & SI_W_SPORT)) && 6362 1.1 christos ((nat->nat_odport == sport) || 6363 1.1 christos (flags & SI_W_DPORT))) 6364 1.1 christos return 1; 6365 1.1 christos break; 6366 1.1 christos case 1: /* inbound packet / outbound entry */ 6367 1.1 christos if (((nat->nat_osport == dport) || 6368 1.1 christos (flags & SI_W_SPORT)) && 6369 1.1 christos ((nat->nat_odport == sport) || 6370 1.1 christos (flags & SI_W_DPORT))) 6371 1.1 christos return 1; 6372 1.1 christos break; 6373 1.1 christos case 0: /* inbound packet / inbound entry */ 6374 1.1 christos if (((nat->nat_osport == sport) || 6375 1.1 christos (flags & SI_W_SPORT)) && 6376 1.1 christos ((nat->nat_odport == dport) || 6377 1.1 christos (flags & SI_W_DPORT))) 6378 1.1 christos return 1; 6379 1.1 christos break; 6380 1.1 christos default: 6381 1.1 christos break; 6382 1.1 christos } 6383 1.1 christos 6384 1.1 christos return(0); 6385 1.1 christos } 6386 1.1 christos 6387 1.1 christos 6388 1.1 christos /* ------------------------------------------------------------------------ */ 6389 1.1 christos /* Function: nat_mssclamp */ 6390 1.1 christos /* Returns: Nil */ 6391 1.1 christos /* Parameters: tcp(I) - pointer to TCP header */ 6392 1.1 christos /* maxmss(I) - value to clamp the TCP MSS to */ 6393 1.1 christos /* fin(I) - pointer to packet information */ 6394 1.1 christos /* csump(I) - pointer to TCP checksum */ 6395 1.1 christos /* */ 6396 1.1 christos /* Check for MSS option and clamp it if necessary. If found and changed, */ 6397 1.1 christos /* then the TCP header checksum will be updated to reflect the change in */ 6398 1.1 christos /* the MSS. */ 6399 1.1 christos /* ------------------------------------------------------------------------ */ 6400 1.1 christos static void 6401 1.2 christos ipf_nat_mssclamp(tcphdr_t *tcp, u_32_t maxmss, fr_info_t *fin, u_short *csump) 6402 1.1 christos { 6403 1.1 christos u_char *cp, *ep, opt; 6404 1.1 christos int hlen, advance; 6405 1.1 christos u_32_t mss, sumd; 6406 1.1 christos 6407 1.1 christos hlen = TCP_OFF(tcp) << 2; 6408 1.1 christos if (hlen > sizeof(*tcp)) { 6409 1.1 christos cp = (u_char *)tcp + sizeof(*tcp); 6410 1.1 christos ep = (u_char *)tcp + hlen; 6411 1.1 christos 6412 1.1 christos while (cp < ep) { 6413 1.1 christos opt = cp[0]; 6414 1.1 christos if (opt == TCPOPT_EOL) 6415 1.1 christos break; 6416 1.1 christos else if (opt == TCPOPT_NOP) { 6417 1.1 christos cp++; 6418 1.1 christos continue; 6419 1.1 christos } 6420 1.1 christos 6421 1.1 christos if (cp + 1 >= ep) 6422 1.1 christos break; 6423 1.1 christos advance = cp[1]; 6424 1.1 christos if ((cp + advance > ep) || (advance <= 0)) 6425 1.1 christos break; 6426 1.1 christos switch (opt) 6427 1.1 christos { 6428 1.1 christos case TCPOPT_MAXSEG: 6429 1.1 christos if (advance != 4) 6430 1.1 christos break; 6431 1.1 christos mss = cp[2] * 256 + cp[3]; 6432 1.1 christos if (mss > maxmss) { 6433 1.1 christos cp[2] = maxmss / 256; 6434 1.1 christos cp[3] = maxmss & 0xff; 6435 1.1 christos CALC_SUMD(mss, maxmss, sumd); 6436 1.3 darrenr ipf_fix_outcksum(0, csump, sumd, 0); 6437 1.1 christos } 6438 1.1 christos break; 6439 1.1 christos default: 6440 1.1 christos /* ignore unknown options */ 6441 1.1 christos break; 6442 1.1 christos } 6443 1.1 christos 6444 1.1 christos cp += advance; 6445 1.1 christos } 6446 1.1 christos } 6447 1.1 christos } 6448 1.1 christos 6449 1.1 christos 6450 1.1 christos /* ------------------------------------------------------------------------ */ 6451 1.3 darrenr /* Function: ipf_nat_setqueue */ 6452 1.1 christos /* Returns: Nil */ 6453 1.3 darrenr /* Parameters: softc(I) - pointer to soft context main structure */ 6454 1.3 darrenr /* softn(I) - pointer to NAT context structure */ 6455 1.3 darrenr /* nat(I)- pointer to NAT structure */ 6456 1.1 christos /* Locks: ipf_nat (read or write) */ 6457 1.1 christos /* */ 6458 1.1 christos /* Put the NAT entry on its default queue entry, using rev as a helped in */ 6459 1.1 christos /* determining which queue it should be placed on. */ 6460 1.1 christos /* ------------------------------------------------------------------------ */ 6461 1.1 christos void 6462 1.2 christos ipf_nat_setqueue(ipf_main_softc_t *softc, ipf_nat_softc_t *softn, nat_t *nat) 6463 1.1 christos { 6464 1.1 christos ipftq_t *oifq, *nifq; 6465 1.1 christos int rev = nat->nat_rev; 6466 1.1 christos 6467 1.1 christos if (nat->nat_ptr != NULL) 6468 1.1 christos nifq = nat->nat_ptr->in_tqehead[rev]; 6469 1.1 christos else 6470 1.1 christos nifq = NULL; 6471 1.1 christos 6472 1.1 christos if (nifq == NULL) { 6473 1.1 christos switch (nat->nat_pr[0]) 6474 1.1 christos { 6475 1.1 christos case IPPROTO_UDP : 6476 1.1 christos nifq = &softn->ipf_nat_udptq; 6477 1.1 christos break; 6478 1.1 christos case IPPROTO_ICMP : 6479 1.1 christos nifq = &softn->ipf_nat_icmptq; 6480 1.1 christos break; 6481 1.1 christos case IPPROTO_TCP : 6482 1.1 christos nifq = softn->ipf_nat_tcptq + 6483 1.1 christos nat->nat_tqe.tqe_state[rev]; 6484 1.1 christos break; 6485 1.1 christos default : 6486 1.1 christos nifq = &softn->ipf_nat_iptq; 6487 1.1 christos break; 6488 1.1 christos } 6489 1.1 christos } 6490 1.1 christos 6491 1.1 christos oifq = nat->nat_tqe.tqe_ifq; 6492 1.1 christos /* 6493 1.1 christos * If it's currently on a timeout queue, move it from one queue to 6494 1.1 christos * another, else put it on the end of the newly determined queue. 6495 1.1 christos */ 6496 1.1 christos if (oifq != NULL) 6497 1.1 christos ipf_movequeue(softc->ipf_ticks, &nat->nat_tqe, oifq, nifq); 6498 1.1 christos else 6499 1.1 christos ipf_queueappend(softc->ipf_ticks, &nat->nat_tqe, nifq, nat); 6500 1.1 christos return; 6501 1.1 christos } 6502 1.1 christos 6503 1.1 christos 6504 1.1 christos /* ------------------------------------------------------------------------ */ 6505 1.1 christos /* Function: nat_getnext */ 6506 1.1 christos /* Returns: int - 0 == ok, else error */ 6507 1.3 darrenr /* Parameters: softc(I) - pointer to soft context main structure */ 6508 1.3 darrenr /* t(I) - pointer to ipftoken structure */ 6509 1.1 christos /* itp(I) - pointer to ipfgeniter_t structure */ 6510 1.1 christos /* */ 6511 1.1 christos /* Fetch the next nat/ipnat structure pointer from the linked list and */ 6512 1.1 christos /* copy it out to the storage space pointed to by itp_data. The next item */ 6513 1.1 christos /* in the list to look at is put back in the ipftoken struture. */ 6514 1.1 christos /* ------------------------------------------------------------------------ */ 6515 1.1 christos static int 6516 1.2 christos ipf_nat_getnext(ipf_main_softc_t *softc, ipftoken_t *t, ipfgeniter_t *itp, 6517 1.2 christos ipfobj_t *objp) 6518 1.1 christos { 6519 1.1 christos ipf_nat_softc_t *softn = softc->ipf_nat_soft; 6520 1.1 christos hostmap_t *hm, *nexthm = NULL, zerohm; 6521 1.1 christos ipnat_t *ipn, *nextipnat = NULL, zeroipn; 6522 1.1 christos nat_t *nat, *nextnat = NULL, zeronat; 6523 1.1 christos int error = 0; 6524 1.1 christos void *nnext; 6525 1.1 christos 6526 1.1 christos if (itp->igi_nitems != 1) { 6527 1.1 christos IPFERROR(60075); 6528 1.1 christos return ENOSPC; 6529 1.1 christos } 6530 1.1 christos 6531 1.1 christos READ_ENTER(&softc->ipf_nat); 6532 1.1 christos 6533 1.1 christos switch (itp->igi_type) 6534 1.1 christos { 6535 1.1 christos case IPFGENITER_HOSTMAP : 6536 1.1 christos hm = t->ipt_data; 6537 1.1 christos if (hm == NULL) { 6538 1.1 christos nexthm = softn->ipf_hm_maplist; 6539 1.1 christos } else { 6540 1.1 christos nexthm = hm->hm_next; 6541 1.1 christos } 6542 1.1 christos if (nexthm != NULL) { 6543 1.1 christos ATOMIC_INC32(nexthm->hm_ref); 6544 1.1 christos t->ipt_data = nexthm; 6545 1.1 christos } else { 6546 1.1 christos bzero(&zerohm, sizeof(zerohm)); 6547 1.1 christos nexthm = &zerohm; 6548 1.1 christos t->ipt_data = NULL; 6549 1.1 christos } 6550 1.1 christos nnext = nexthm->hm_next; 6551 1.1 christos break; 6552 1.1 christos 6553 1.1 christos case IPFGENITER_IPNAT : 6554 1.1 christos ipn = t->ipt_data; 6555 1.1 christos if (ipn == NULL) { 6556 1.1 christos nextipnat = softn->ipf_nat_list; 6557 1.1 christos } else { 6558 1.1 christos nextipnat = ipn->in_next; 6559 1.1 christos } 6560 1.1 christos if (nextipnat != NULL) { 6561 1.1 christos ATOMIC_INC32(nextipnat->in_use); 6562 1.1 christos t->ipt_data = nextipnat; 6563 1.1 christos } else { 6564 1.1 christos bzero(&zeroipn, sizeof(zeroipn)); 6565 1.1 christos nextipnat = &zeroipn; 6566 1.1 christos t->ipt_data = NULL; 6567 1.1 christos } 6568 1.1 christos nnext = nextipnat->in_next; 6569 1.1 christos break; 6570 1.1 christos 6571 1.1 christos case IPFGENITER_NAT : 6572 1.1 christos nat = t->ipt_data; 6573 1.1 christos if (nat == NULL) { 6574 1.1 christos nextnat = softn->ipf_nat_instances; 6575 1.1 christos } else { 6576 1.1 christos nextnat = nat->nat_next; 6577 1.1 christos } 6578 1.1 christos if (nextnat != NULL) { 6579 1.1 christos MUTEX_ENTER(&nextnat->nat_lock); 6580 1.1 christos nextnat->nat_ref++; 6581 1.1 christos MUTEX_EXIT(&nextnat->nat_lock); 6582 1.1 christos t->ipt_data = nextnat; 6583 1.1 christos } else { 6584 1.1 christos bzero(&zeronat, sizeof(zeronat)); 6585 1.1 christos nextnat = &zeronat; 6586 1.1 christos t->ipt_data = NULL; 6587 1.1 christos } 6588 1.1 christos nnext = nextnat->nat_next; 6589 1.1 christos break; 6590 1.1 christos 6591 1.1 christos default : 6592 1.1 christos RWLOCK_EXIT(&softc->ipf_nat); 6593 1.1 christos IPFERROR(60055); 6594 1.1 christos return EINVAL; 6595 1.1 christos } 6596 1.1 christos 6597 1.1 christos RWLOCK_EXIT(&softc->ipf_nat); 6598 1.1 christos 6599 1.1 christos objp->ipfo_ptr = itp->igi_data; 6600 1.1 christos 6601 1.1 christos switch (itp->igi_type) 6602 1.1 christos { 6603 1.1 christos case IPFGENITER_HOSTMAP : 6604 1.1 christos error = COPYOUT(nexthm, objp->ipfo_ptr, sizeof(*nexthm)); 6605 1.1 christos if (error != 0) { 6606 1.1 christos IPFERROR(60049); 6607 1.1 christos error = EFAULT; 6608 1.1 christos } 6609 1.1 christos if (hm != NULL) { 6610 1.1 christos WRITE_ENTER(&softc->ipf_nat); 6611 1.3 darrenr ipf_nat_hostmapdel(softc, &hm); 6612 1.1 christos RWLOCK_EXIT(&softc->ipf_nat); 6613 1.1 christos } 6614 1.1 christos break; 6615 1.1 christos 6616 1.1 christos case IPFGENITER_IPNAT : 6617 1.1 christos objp->ipfo_size = nextipnat->in_size; 6618 1.1 christos objp->ipfo_type = IPFOBJ_IPNAT; 6619 1.1 christos error = ipf_outobjk(softc, objp, nextipnat); 6620 1.1 christos if (ipn != NULL) { 6621 1.1 christos WRITE_ENTER(&softc->ipf_nat); 6622 1.3 darrenr ipf_nat_rule_deref(softc, &ipn); 6623 1.1 christos RWLOCK_EXIT(&softc->ipf_nat); 6624 1.1 christos } 6625 1.1 christos break; 6626 1.1 christos 6627 1.1 christos case IPFGENITER_NAT : 6628 1.1 christos objp->ipfo_size = sizeof(nat_t); 6629 1.1 christos objp->ipfo_type = IPFOBJ_NAT; 6630 1.1 christos error = ipf_outobjk(softc, objp, nextnat); 6631 1.1 christos if (nat != NULL) 6632 1.1 christos ipf_nat_deref(softc, &nat); 6633 1.1 christos 6634 1.1 christos break; 6635 1.1 christos } 6636 1.1 christos 6637 1.1 christos if (nnext == NULL) 6638 1.1 christos ipf_token_mark_complete(t); 6639 1.1 christos 6640 1.1 christos return error; 6641 1.1 christos } 6642 1.1 christos 6643 1.1 christos 6644 1.1 christos /* ------------------------------------------------------------------------ */ 6645 1.1 christos /* Function: nat_extraflush */ 6646 1.1 christos /* Returns: int - 0 == success, -1 == failure */ 6647 1.3 darrenr /* Parameters: softc(I) - pointer to soft context main structure */ 6648 1.3 darrenr /* softn(I) - pointer to NAT context structure */ 6649 1.3 darrenr /* which(I) - how to flush the active NAT table */ 6650 1.1 christos /* Write Locks: ipf_nat */ 6651 1.1 christos /* */ 6652 1.1 christos /* Flush nat tables. Three actions currently defined: */ 6653 1.1 christos /* which == 0 : flush all nat table entries */ 6654 1.1 christos /* which == 1 : flush TCP connections which have started to close but are */ 6655 1.1 christos /* stuck for some reason. */ 6656 1.1 christos /* which == 2 : flush TCP connections which have been idle for a long time, */ 6657 1.1 christos /* starting at > 4 days idle and working back in successive half-*/ 6658 1.1 christos /* days to at most 12 hours old. If this fails to free enough */ 6659 1.1 christos /* slots then work backwards in half hour slots to 30 minutes. */ 6660 1.1 christos /* If that too fails, then work backwards in 30 second intervals */ 6661 1.1 christos /* for the last 30 minutes to at worst 30 seconds idle. */ 6662 1.1 christos /* ------------------------------------------------------------------------ */ 6663 1.1 christos static int 6664 1.2 christos ipf_nat_extraflush(ipf_main_softc_t *softc, ipf_nat_softc_t *softn, int which) 6665 1.1 christos { 6666 1.1 christos nat_t *nat, **natp; 6667 1.1 christos ipftqent_t *tqn; 6668 1.1 christos ipftq_t *ifq; 6669 1.1 christos int removed; 6670 1.1 christos SPL_INT(s); 6671 1.1 christos 6672 1.1 christos removed = 0; 6673 1.1 christos 6674 1.1 christos SPL_NET(s); 6675 1.1 christos switch (which) 6676 1.1 christos { 6677 1.1 christos case 0 : 6678 1.1 christos softn->ipf_nat_stats.ns_flush_all++; 6679 1.1 christos /* 6680 1.1 christos * Style 0 flush removes everything... 6681 1.1 christos */ 6682 1.1 christos for (natp = &softn->ipf_nat_instances; 6683 1.1 christos ((nat = *natp) != NULL); ) { 6684 1.1 christos ipf_nat_delete(softc, nat, NL_FLUSH); 6685 1.1 christos removed++; 6686 1.1 christos } 6687 1.1 christos break; 6688 1.1 christos 6689 1.1 christos case 1 : 6690 1.1 christos softn->ipf_nat_stats.ns_flush_closing++; 6691 1.1 christos /* 6692 1.1 christos * Since we're only interested in things that are closing, 6693 1.1 christos * we can start with the appropriate timeout queue. 6694 1.1 christos */ 6695 1.1 christos for (ifq = softn->ipf_nat_tcptq + IPF_TCPS_CLOSE_WAIT; 6696 1.1 christos ifq != NULL; ifq = ifq->ifq_next) { 6697 1.1 christos 6698 1.1 christos for (tqn = ifq->ifq_head; tqn != NULL; ) { 6699 1.1 christos nat = tqn->tqe_parent; 6700 1.1 christos tqn = tqn->tqe_next; 6701 1.1 christos if (nat->nat_pr[0] != IPPROTO_TCP || 6702 1.1 christos nat->nat_pr[1] != IPPROTO_TCP) 6703 1.1 christos break; 6704 1.1 christos ipf_nat_delete(softc, nat, NL_EXPIRE); 6705 1.1 christos removed++; 6706 1.1 christos } 6707 1.1 christos } 6708 1.1 christos 6709 1.1 christos /* 6710 1.1 christos * Also need to look through the user defined queues. 6711 1.1 christos */ 6712 1.1 christos for (ifq = softn->ipf_nat_utqe; ifq != NULL; 6713 1.1 christos ifq = ifq->ifq_next) { 6714 1.1 christos for (tqn = ifq->ifq_head; tqn != NULL; ) { 6715 1.1 christos nat = tqn->tqe_parent; 6716 1.1 christos tqn = tqn->tqe_next; 6717 1.1 christos if (nat->nat_pr[0] != IPPROTO_TCP || 6718 1.1 christos nat->nat_pr[1] != IPPROTO_TCP) 6719 1.1 christos continue; 6720 1.1 christos 6721 1.1 christos if ((nat->nat_tcpstate[0] > 6722 1.1 christos IPF_TCPS_ESTABLISHED) && 6723 1.1 christos (nat->nat_tcpstate[1] > 6724 1.1 christos IPF_TCPS_ESTABLISHED)) { 6725 1.1 christos ipf_nat_delete(softc, nat, NL_EXPIRE); 6726 1.1 christos removed++; 6727 1.1 christos } 6728 1.1 christos } 6729 1.1 christos } 6730 1.1 christos break; 6731 1.1 christos 6732 1.1 christos /* 6733 1.1 christos * Args 5-11 correspond to flushing those particular states 6734 1.1 christos * for TCP connections. 6735 1.1 christos */ 6736 1.1 christos case IPF_TCPS_CLOSE_WAIT : 6737 1.1 christos case IPF_TCPS_FIN_WAIT_1 : 6738 1.1 christos case IPF_TCPS_CLOSING : 6739 1.1 christos case IPF_TCPS_LAST_ACK : 6740 1.1 christos case IPF_TCPS_FIN_WAIT_2 : 6741 1.1 christos case IPF_TCPS_TIME_WAIT : 6742 1.1 christos case IPF_TCPS_CLOSED : 6743 1.1 christos softn->ipf_nat_stats.ns_flush_state++; 6744 1.1 christos tqn = softn->ipf_nat_tcptq[which].ifq_head; 6745 1.1 christos while (tqn != NULL) { 6746 1.1 christos nat = tqn->tqe_parent; 6747 1.1 christos tqn = tqn->tqe_next; 6748 1.1 christos ipf_nat_delete(softc, nat, NL_FLUSH); 6749 1.1 christos removed++; 6750 1.1 christos } 6751 1.1 christos break; 6752 1.1 christos 6753 1.1 christos default : 6754 1.1 christos if (which < 30) 6755 1.1 christos break; 6756 1.1 christos 6757 1.1 christos softn->ipf_nat_stats.ns_flush_timeout++; 6758 1.1 christos /* 6759 1.1 christos * Take a large arbitrary number to mean the number of seconds 6760 1.1 christos * for which which consider to be the maximum value we'll allow 6761 1.1 christos * the expiration to be. 6762 1.1 christos */ 6763 1.1 christos which = IPF_TTLVAL(which); 6764 1.1 christos for (natp = &softn->ipf_nat_instances; 6765 1.1 christos ((nat = *natp) != NULL); ) { 6766 1.1 christos if (softc->ipf_ticks - nat->nat_touched > which) { 6767 1.1 christos ipf_nat_delete(softc, nat, NL_FLUSH); 6768 1.1 christos removed++; 6769 1.1 christos } else 6770 1.1 christos natp = &nat->nat_next; 6771 1.1 christos } 6772 1.1 christos break; 6773 1.1 christos } 6774 1.1 christos 6775 1.1 christos if (which != 2) { 6776 1.1 christos SPL_X(s); 6777 1.1 christos return removed; 6778 1.1 christos } 6779 1.1 christos 6780 1.1 christos softn->ipf_nat_stats.ns_flush_queue++; 6781 1.1 christos 6782 1.1 christos /* 6783 1.1 christos * Asked to remove inactive entries because the table is full, try 6784 1.1 christos * again, 3 times, if first attempt failed with a different criteria 6785 1.1 christos * each time. The order tried in must be in decreasing age. 6786 1.1 christos * Another alternative is to implement random drop and drop N entries 6787 1.1 christos * at random until N have been freed up. 6788 1.1 christos */ 6789 1.1 christos if (softc->ipf_ticks - softn->ipf_nat_last_force_flush > 6790 1.1 christos IPF_TTLVAL(5)) { 6791 1.1 christos softn->ipf_nat_last_force_flush = softc->ipf_ticks; 6792 1.1 christos 6793 1.1 christos removed = ipf_queueflush(softc, ipf_nat_flush_entry, 6794 1.1 christos softn->ipf_nat_tcptq, 6795 1.1 christos softn->ipf_nat_utqe, 6796 1.1 christos &softn->ipf_nat_stats.ns_active, 6797 1.1 christos softn->ipf_nat_table_sz, 6798 1.1 christos softn->ipf_nat_table_wm_low); 6799 1.1 christos } 6800 1.1 christos 6801 1.1 christos SPL_X(s); 6802 1.1 christos return removed; 6803 1.1 christos } 6804 1.1 christos 6805 1.1 christos 6806 1.1 christos /* ------------------------------------------------------------------------ */ 6807 1.1 christos /* Function: ipf_nat_flush_entry */ 6808 1.1 christos /* Returns: 0 - always succeeds */ 6809 1.3 darrenr /* Parameters: softc(I) - pointer to soft context main structure */ 6810 1.3 darrenr /* entry(I) - pointer to NAT entry */ 6811 1.1 christos /* Write Locks: ipf_nat */ 6812 1.1 christos /* */ 6813 1.1 christos /* This function is a stepping stone between ipf_queueflush() and */ 6814 1.1 christos /* nat_dlete(). It is used so we can provide a uniform interface via the */ 6815 1.1 christos /* ipf_queueflush() function. Since the nat_delete() function returns void */ 6816 1.1 christos /* we translate that to mean it always succeeds in deleting something. */ 6817 1.1 christos /* ------------------------------------------------------------------------ */ 6818 1.1 christos static int 6819 1.2 christos ipf_nat_flush_entry(ipf_main_softc_t *softc, void *entry) 6820 1.1 christos { 6821 1.1 christos ipf_nat_delete(softc, entry, NL_FLUSH); 6822 1.1 christos return 0; 6823 1.1 christos } 6824 1.1 christos 6825 1.1 christos 6826 1.1 christos /* ------------------------------------------------------------------------ */ 6827 1.1 christos /* Function: ipf_nat_iterator */ 6828 1.1 christos /* Returns: int - 0 == ok, else error */ 6829 1.3 darrenr /* Parameters: softc(I) - pointer to soft context main structure */ 6830 1.3 darrenr /* token(I) - pointer to ipftoken structure */ 6831 1.3 darrenr /* itp(I) - pointer to ipfgeniter_t structure */ 6832 1.3 darrenr /* obj(I) - pointer to data description structure */ 6833 1.1 christos /* */ 6834 1.1 christos /* This function acts as a handler for the SIOCGENITER ioctls that use a */ 6835 1.1 christos /* generic structure to iterate through a list. There are three different */ 6836 1.1 christos /* linked lists of NAT related information to go through: NAT rules, active */ 6837 1.1 christos /* NAT mappings and the NAT fragment cache. */ 6838 1.1 christos /* ------------------------------------------------------------------------ */ 6839 1.1 christos static int 6840 1.2 christos ipf_nat_iterator(ipf_main_softc_t *softc, ipftoken_t *token, ipfgeniter_t *itp, 6841 1.2 christos ipfobj_t *obj) 6842 1.1 christos { 6843 1.1 christos int error; 6844 1.1 christos 6845 1.1 christos if (itp->igi_data == NULL) { 6846 1.1 christos IPFERROR(60052); 6847 1.1 christos return EFAULT; 6848 1.1 christos } 6849 1.1 christos 6850 1.1 christos switch (itp->igi_type) 6851 1.1 christos { 6852 1.1 christos case IPFGENITER_HOSTMAP : 6853 1.1 christos case IPFGENITER_IPNAT : 6854 1.1 christos case IPFGENITER_NAT : 6855 1.1 christos error = ipf_nat_getnext(softc, token, itp, obj); 6856 1.1 christos break; 6857 1.1 christos 6858 1.1 christos case IPFGENITER_NATFRAG : 6859 1.1 christos error = ipf_frag_nat_next(softc, token, itp); 6860 1.1 christos break; 6861 1.1 christos default : 6862 1.1 christos IPFERROR(60053); 6863 1.1 christos error = EINVAL; 6864 1.1 christos break; 6865 1.1 christos } 6866 1.1 christos 6867 1.1 christos return error; 6868 1.1 christos } 6869 1.1 christos 6870 1.1 christos 6871 1.1 christos /* ------------------------------------------------------------------------ */ 6872 1.1 christos /* Function: ipf_nat_setpending */ 6873 1.1 christos /* Returns: Nil */ 6874 1.3 darrenr /* Parameters: softc(I) - pointer to soft context main structure */ 6875 1.3 darrenr /* nat(I) - pointer to NAT structure */ 6876 1.1 christos /* Locks: ipf_nat (read or write) */ 6877 1.1 christos /* */ 6878 1.1 christos /* Put the NAT entry on to the pending queue - this queue has a very short */ 6879 1.1 christos /* lifetime where items are put that can't be deleted straight away because */ 6880 1.1 christos /* of locking issues but we want to delete them ASAP, anyway. In calling */ 6881 1.1 christos /* this function, it is assumed that the owner (if there is one, as shown */ 6882 1.1 christos /* by nat_me) is no longer interested in it. */ 6883 1.1 christos /* ------------------------------------------------------------------------ */ 6884 1.1 christos void 6885 1.2 christos ipf_nat_setpending(ipf_main_softc_t *softc, nat_t *nat) 6886 1.1 christos { 6887 1.1 christos ipf_nat_softc_t *softn = softc->ipf_nat_soft; 6888 1.1 christos ipftq_t *oifq; 6889 1.1 christos 6890 1.1 christos oifq = nat->nat_tqe.tqe_ifq; 6891 1.1 christos if (oifq != NULL) 6892 1.1 christos ipf_movequeue(softc->ipf_ticks, &nat->nat_tqe, oifq, 6893 1.1 christos &softn->ipf_nat_pending); 6894 1.1 christos else 6895 1.1 christos ipf_queueappend(softc->ipf_ticks, &nat->nat_tqe, 6896 1.1 christos &softn->ipf_nat_pending, nat); 6897 1.1 christos 6898 1.1 christos if (nat->nat_me != NULL) { 6899 1.1 christos *nat->nat_me = NULL; 6900 1.1 christos nat->nat_me = NULL; 6901 1.1 christos nat->nat_ref--; 6902 1.3 darrenr ASSERT(nat->nat_ref >= 0); 6903 1.1 christos } 6904 1.1 christos } 6905 1.1 christos 6906 1.1 christos 6907 1.1 christos /* ------------------------------------------------------------------------ */ 6908 1.1 christos /* Function: nat_newrewrite */ 6909 1.1 christos /* Returns: int - -1 == error, 0 == success (no move), 1 == success and */ 6910 1.1 christos /* allow rule to be moved if IPN_ROUNDR is set. */ 6911 1.1 christos /* Parameters: fin(I) - pointer to packet information */ 6912 1.1 christos /* nat(I) - pointer to NAT entry */ 6913 1.1 christos /* ni(I) - pointer to structure with misc. information needed */ 6914 1.1 christos /* to create new NAT entry. */ 6915 1.1 christos /* Write Lock: ipf_nat */ 6916 1.1 christos /* */ 6917 1.1 christos /* This function is responsible for setting up an active NAT session where */ 6918 1.1 christos /* we are changing both the source and destination parameters at the same */ 6919 1.1 christos /* time. The loop in here works differently to elsewhere - each iteration */ 6920 1.1 christos /* is responsible for changing a single parameter that can be incremented. */ 6921 1.1 christos /* So one pass may increase the source IP#, next source port, next dest. IP#*/ 6922 1.1 christos /* and the last destination port for a total of 4 iterations to try each. */ 6923 1.1 christos /* This is done to try and exhaustively use the translation space available.*/ 6924 1.1 christos /* ------------------------------------------------------------------------ */ 6925 1.1 christos static int 6926 1.2 christos ipf_nat_newrewrite(fr_info_t *fin, nat_t *nat, natinfo_t *nai) 6927 1.1 christos { 6928 1.1 christos int src_search = 1; 6929 1.1 christos int dst_search = 1; 6930 1.1 christos fr_info_t frnat; 6931 1.1 christos u_32_t flags; 6932 1.1 christos u_short swap; 6933 1.1 christos ipnat_t *np; 6934 1.1 christos nat_t *natl; 6935 1.1 christos int l = 0; 6936 1.1 christos int changed; 6937 1.1 christos 6938 1.1 christos natl = NULL; 6939 1.1 christos changed = -1; 6940 1.1 christos np = nai->nai_np; 6941 1.1 christos flags = nat->nat_flags; 6942 1.1 christos bcopy((char *)fin, (char *)&frnat, sizeof(*fin)); 6943 1.1 christos 6944 1.1 christos nat->nat_hm = NULL; 6945 1.1 christos 6946 1.1 christos do { 6947 1.1 christos changed = -1; 6948 1.1 christos /* TRACE (l, src_search, dst_search, np) */ 6949 1.1 christos 6950 1.1 christos if ((src_search == 0) && (np->in_spnext == 0) && 6951 1.1 christos (dst_search == 0) && (np->in_dpnext == 0)) { 6952 1.1 christos if (l > 0) 6953 1.1 christos return -1; 6954 1.1 christos } 6955 1.1 christos 6956 1.1 christos /* 6957 1.1 christos * Find a new source address 6958 1.1 christos */ 6959 1.1 christos if (ipf_nat_nextaddr(fin, &np->in_nsrc, &frnat.fin_saddr, 6960 1.1 christos &frnat.fin_saddr) == -1) { 6961 1.1 christos return -1; 6962 1.1 christos } 6963 1.1 christos 6964 1.1 christos if ((np->in_nsrcaddr == 0) && (np->in_nsrcmsk == 0xffffffff)) { 6965 1.1 christos src_search = 0; 6966 1.1 christos if (np->in_stepnext == 0) 6967 1.1 christos np->in_stepnext = 1; 6968 1.1 christos 6969 1.1 christos } else if ((np->in_nsrcaddr == 0) && (np->in_nsrcmsk == 0)) { 6970 1.1 christos src_search = 0; 6971 1.1 christos if (np->in_stepnext == 0) 6972 1.1 christos np->in_stepnext = 1; 6973 1.1 christos 6974 1.1 christos } else if (np->in_nsrcmsk == 0xffffffff) { 6975 1.1 christos src_search = 0; 6976 1.1 christos if (np->in_stepnext == 0) 6977 1.1 christos np->in_stepnext = 1; 6978 1.1 christos 6979 1.1 christos } else if (np->in_nsrcmsk != 0xffffffff) { 6980 1.1 christos if (np->in_stepnext == 0 && changed == -1) { 6981 1.1 christos np->in_snip++; 6982 1.1 christos np->in_stepnext++; 6983 1.1 christos changed = 0; 6984 1.1 christos } 6985 1.1 christos } 6986 1.1 christos 6987 1.1 christos if ((flags & IPN_TCPUDPICMP) != 0) { 6988 1.1 christos if (np->in_spnext != 0) 6989 1.1 christos frnat.fin_data[0] = np->in_spnext; 6990 1.1 christos 6991 1.1 christos /* 6992 1.1 christos * Standard port translation. Select next port. 6993 1.1 christos */ 6994 1.1 christos if ((flags & IPN_FIXEDSPORT) != 0) { 6995 1.1 christos np->in_stepnext = 2; 6996 1.1 christos } else if ((np->in_stepnext == 1) && 6997 1.1 christos (changed == -1) && (natl != NULL)) { 6998 1.1 christos np->in_spnext++; 6999 1.1 christos np->in_stepnext++; 7000 1.1 christos changed = 1; 7001 1.1 christos if (np->in_spnext > np->in_spmax) 7002 1.1 christos np->in_spnext = np->in_spmin; 7003 1.1 christos } 7004 1.1 christos } else { 7005 1.1 christos np->in_stepnext = 2; 7006 1.1 christos } 7007 1.1 christos np->in_stepnext &= 0x3; 7008 1.1 christos 7009 1.1 christos /* 7010 1.1 christos * Find a new destination address 7011 1.1 christos */ 7012 1.1 christos /* TRACE (fin, np, l, frnat) */ 7013 1.1 christos 7014 1.1 christos if (ipf_nat_nextaddr(fin, &np->in_ndst, &frnat.fin_daddr, 7015 1.1 christos &frnat.fin_daddr) == -1) 7016 1.1 christos return -1; 7017 1.1 christos if ((np->in_ndstaddr == 0) && (np->in_ndstmsk == 0xffffffff)) { 7018 1.1 christos dst_search = 0; 7019 1.1 christos if (np->in_stepnext == 2) 7020 1.1 christos np->in_stepnext = 3; 7021 1.1 christos 7022 1.1 christos } else if ((np->in_ndstaddr == 0) && (np->in_ndstmsk == 0)) { 7023 1.1 christos dst_search = 0; 7024 1.1 christos if (np->in_stepnext == 2) 7025 1.1 christos np->in_stepnext = 3; 7026 1.1 christos 7027 1.1 christos } else if (np->in_ndstmsk == 0xffffffff) { 7028 1.1 christos dst_search = 0; 7029 1.1 christos if (np->in_stepnext == 2) 7030 1.1 christos np->in_stepnext = 3; 7031 1.1 christos 7032 1.1 christos } else if (np->in_ndstmsk != 0xffffffff) { 7033 1.1 christos if ((np->in_stepnext == 2) && (changed == -1) && 7034 1.1 christos (natl != NULL)) { 7035 1.1 christos changed = 2; 7036 1.1 christos np->in_stepnext++; 7037 1.1 christos np->in_dnip++; 7038 1.1 christos } 7039 1.1 christos } 7040 1.1 christos 7041 1.1 christos if ((flags & IPN_TCPUDPICMP) != 0) { 7042 1.1 christos if (np->in_dpnext != 0) 7043 1.1 christos frnat.fin_data[1] = np->in_dpnext; 7044 1.1 christos 7045 1.1 christos /* 7046 1.1 christos * Standard port translation. Select next port. 7047 1.1 christos */ 7048 1.1 christos if ((flags & IPN_FIXEDDPORT) != 0) { 7049 1.1 christos np->in_stepnext = 0; 7050 1.1 christos } else if (np->in_stepnext == 3 && changed == -1) { 7051 1.1 christos np->in_dpnext++; 7052 1.1 christos np->in_stepnext++; 7053 1.1 christos changed = 3; 7054 1.1 christos if (np->in_dpnext > np->in_dpmax) 7055 1.1 christos np->in_dpnext = np->in_dpmin; 7056 1.1 christos } 7057 1.1 christos } else { 7058 1.1 christos if (np->in_stepnext == 3) 7059 1.1 christos np->in_stepnext = 0; 7060 1.1 christos } 7061 1.1 christos 7062 1.1 christos /* TRACE (frnat) */ 7063 1.1 christos 7064 1.1 christos /* 7065 1.1 christos * Here we do a lookup of the connection as seen from 7066 1.1 christos * the outside. If an IP# pair already exists, try 7067 1.1 christos * again. So if you have A->B becomes C->B, you can 7068 1.1 christos * also have D->E become C->E but not D->B causing 7069 1.1 christos * another C->B. Also take protocol and ports into 7070 1.1 christos * account when determining whether a pre-existing 7071 1.1 christos * NAT setup will cause an external conflict where 7072 1.1 christos * this is appropriate. 7073 1.1 christos * 7074 1.1 christos * fin_data[] is swapped around because we are doing a 7075 1.1 christos * lookup of the packet is if it were moving in the opposite 7076 1.1 christos * direction of the one we are working with now. 7077 1.1 christos */ 7078 1.1 christos if (flags & IPN_TCPUDP) { 7079 1.1 christos swap = frnat.fin_data[0]; 7080 1.1 christos frnat.fin_data[0] = frnat.fin_data[1]; 7081 1.1 christos frnat.fin_data[1] = swap; 7082 1.1 christos } 7083 1.1 christos if (fin->fin_out == 1) { 7084 1.1 christos natl = ipf_nat_inlookup(&frnat, 7085 1.1 christos flags & ~(SI_WILDP|NAT_SEARCH), 7086 1.1 christos (u_int)frnat.fin_p, 7087 1.1 christos frnat.fin_dst, frnat.fin_src); 7088 1.1 christos 7089 1.1 christos } else { 7090 1.1 christos natl = ipf_nat_outlookup(&frnat, 7091 1.1 christos flags & ~(SI_WILDP|NAT_SEARCH), 7092 1.1 christos (u_int)frnat.fin_p, 7093 1.1 christos frnat.fin_dst, frnat.fin_src); 7094 1.1 christos } 7095 1.1 christos if (flags & IPN_TCPUDP) { 7096 1.1 christos swap = frnat.fin_data[0]; 7097 1.1 christos frnat.fin_data[0] = frnat.fin_data[1]; 7098 1.1 christos frnat.fin_data[1] = swap; 7099 1.1 christos } 7100 1.1 christos 7101 1.1 christos /* TRACE natl, in_stepnext, l */ 7102 1.1 christos 7103 1.1 christos if ((natl != NULL) && (l > 8)) /* XXX 8 is arbitrary */ 7104 1.1 christos return -1; 7105 1.1 christos 7106 1.1 christos np->in_stepnext &= 0x3; 7107 1.1 christos 7108 1.1 christos l++; 7109 1.1 christos changed = -1; 7110 1.1 christos } while (natl != NULL); 7111 1.1 christos 7112 1.1 christos nat->nat_osrcip = fin->fin_src; 7113 1.1 christos nat->nat_odstip = fin->fin_dst; 7114 1.1 christos nat->nat_nsrcip = frnat.fin_src; 7115 1.1 christos nat->nat_ndstip = frnat.fin_dst; 7116 1.1 christos 7117 1.3 darrenr if ((flags & IPN_TCPUDP) != 0) { 7118 1.1 christos nat->nat_osport = htons(fin->fin_data[0]); 7119 1.1 christos nat->nat_odport = htons(fin->fin_data[1]); 7120 1.1 christos nat->nat_nsport = htons(frnat.fin_data[0]); 7121 1.1 christos nat->nat_ndport = htons(frnat.fin_data[1]); 7122 1.3 darrenr } else if ((flags & IPN_ICMPQUERY) != 0) { 7123 1.3 darrenr nat->nat_oicmpid = fin->fin_data[1]; 7124 1.3 darrenr nat->nat_nicmpid = frnat.fin_data[1]; 7125 1.1 christos } 7126 1.1 christos 7127 1.1 christos return 0; 7128 1.1 christos } 7129 1.1 christos 7130 1.1 christos 7131 1.1 christos /* ------------------------------------------------------------------------ */ 7132 1.1 christos /* Function: nat_newdivert */ 7133 1.1 christos /* Returns: int - -1 == error, 0 == success */ 7134 1.1 christos /* Parameters: fin(I) - pointer to packet information */ 7135 1.1 christos /* nat(I) - pointer to NAT entry */ 7136 1.1 christos /* ni(I) - pointer to structure with misc. information needed */ 7137 1.1 christos /* to create new NAT entry. */ 7138 1.1 christos /* Write Lock: ipf_nat */ 7139 1.1 christos /* */ 7140 1.3 darrenr /* Create a new NAT divert session as defined by the NAT rule. This is */ 7141 1.3 darrenr /* somewhat different to other NAT session creation routines because we */ 7142 1.1 christos /* do not iterate through either port numbers or IP addresses, searching */ 7143 1.1 christos /* for a unique mapping, however, a complimentary duplicate check is made. */ 7144 1.1 christos /* ------------------------------------------------------------------------ */ 7145 1.1 christos static int 7146 1.2 christos ipf_nat_newdivert(fr_info_t *fin, nat_t *nat, natinfo_t *nai) 7147 1.1 christos { 7148 1.1 christos ipf_main_softc_t *softc = fin->fin_main_soft; 7149 1.1 christos ipf_nat_softc_t *softn = softc->ipf_nat_soft; 7150 1.1 christos fr_info_t frnat; 7151 1.1 christos ipnat_t *np; 7152 1.1 christos nat_t *natl; 7153 1.1 christos int p; 7154 1.1 christos 7155 1.1 christos np = nai->nai_np; 7156 1.1 christos bcopy((char *)fin, (char *)&frnat, sizeof(*fin)); 7157 1.1 christos 7158 1.1 christos nat->nat_pr[0] = 0; 7159 1.1 christos nat->nat_osrcaddr = fin->fin_saddr; 7160 1.1 christos nat->nat_odstaddr = fin->fin_daddr; 7161 1.1 christos frnat.fin_saddr = htonl(np->in_snip); 7162 1.1 christos frnat.fin_daddr = htonl(np->in_dnip); 7163 1.3 darrenr if ((nat->nat_flags & IPN_TCPUDP) != 0) { 7164 1.3 darrenr nat->nat_osport = htons(fin->fin_data[0]); 7165 1.3 darrenr nat->nat_odport = htons(fin->fin_data[1]); 7166 1.3 darrenr } else if ((nat->nat_flags & IPN_ICMPQUERY) != 0) { 7167 1.3 darrenr nat->nat_oicmpid = fin->fin_data[1]; 7168 1.3 darrenr } 7169 1.1 christos 7170 1.1 christos if (np->in_redir & NAT_DIVERTUDP) { 7171 1.1 christos frnat.fin_data[0] = np->in_spnext; 7172 1.1 christos frnat.fin_data[1] = np->in_dpnext; 7173 1.1 christos frnat.fin_flx |= FI_TCPUDP; 7174 1.1 christos p = IPPROTO_UDP; 7175 1.1 christos } else { 7176 1.1 christos frnat.fin_flx &= ~FI_TCPUDP; 7177 1.1 christos p = IPPROTO_IPIP; 7178 1.1 christos } 7179 1.1 christos 7180 1.1 christos if (fin->fin_out == 1) { 7181 1.1 christos natl = ipf_nat_inlookup(&frnat, 0, p, 7182 1.1 christos frnat.fin_dst, frnat.fin_src); 7183 1.1 christos 7184 1.1 christos } else { 7185 1.1 christos natl = ipf_nat_outlookup(&frnat, 0, p, 7186 1.1 christos frnat.fin_dst, frnat.fin_src); 7187 1.1 christos } 7188 1.1 christos 7189 1.1 christos if (natl != NULL) { 7190 1.1 christos NBUMPSIDED(fin->fin_out, ns_divert_exist); 7191 1.1 christos return -1; 7192 1.1 christos } 7193 1.1 christos 7194 1.1 christos nat->nat_nsrcaddr = frnat.fin_saddr; 7195 1.1 christos nat->nat_ndstaddr = frnat.fin_daddr; 7196 1.3 darrenr if ((nat->nat_flags & IPN_TCPUDP) != 0) { 7197 1.1 christos nat->nat_nsport = htons(frnat.fin_data[0]); 7198 1.1 christos nat->nat_ndport = htons(frnat.fin_data[1]); 7199 1.3 darrenr } else if ((nat->nat_flags & IPN_ICMPQUERY) != 0) { 7200 1.3 darrenr nat->nat_nicmpid = frnat.fin_data[1]; 7201 1.1 christos } 7202 1.3 darrenr 7203 1.1 christos nat->nat_pr[fin->fin_out] = fin->fin_p; 7204 1.1 christos nat->nat_pr[1 - fin->fin_out] = p; 7205 1.1 christos 7206 1.3 darrenr if (np->in_redir & NAT_REDIRECT) 7207 1.3 darrenr nat->nat_dir = NAT_DIVERTIN; 7208 1.3 darrenr else 7209 1.3 darrenr nat->nat_dir = NAT_DIVERTOUT; 7210 1.1 christos 7211 1.1 christos return 0; 7212 1.1 christos } 7213 1.1 christos 7214 1.1 christos 7215 1.1 christos /* ------------------------------------------------------------------------ */ 7216 1.1 christos /* Function: nat_builddivertmp */ 7217 1.1 christos /* Returns: int - -1 == error, 0 == success */ 7218 1.3 darrenr /* Parameters: softn(I) - pointer to NAT context structure */ 7219 1.3 darrenr /* np(I) - pointer to a NAT rule */ 7220 1.1 christos /* */ 7221 1.3 darrenr /* For divert rules, a skeleton packet representing what will be prepended */ 7222 1.3 darrenr /* to the real packet is created. Even though we don't have the full */ 7223 1.3 darrenr /* packet here, a checksum is calculated that we update later when we */ 7224 1.1 christos /* fill in the final details. At present a 0 checksum for UDP is being set */ 7225 1.1 christos /* here because it is expected that divert will be used for localhost. */ 7226 1.1 christos /* ------------------------------------------------------------------------ */ 7227 1.1 christos static int 7228 1.2 christos ipf_nat_builddivertmp(ipf_nat_softc_t *softn, ipnat_t *np) 7229 1.1 christos { 7230 1.1 christos udphdr_t *uh; 7231 1.1 christos size_t len; 7232 1.1 christos ip_t *ip; 7233 1.1 christos 7234 1.1 christos if ((np->in_redir & NAT_DIVERTUDP) != 0) 7235 1.1 christos len = sizeof(ip_t) + sizeof(udphdr_t); 7236 1.1 christos else 7237 1.1 christos len = sizeof(ip_t); 7238 1.1 christos 7239 1.1 christos ALLOC_MB_T(np->in_divmp, len); 7240 1.1 christos if (np->in_divmp == NULL) { 7241 1.1 christos NBUMPD(ipf_nat_stats, ns_divert_build); 7242 1.1 christos return -1; 7243 1.1 christos } 7244 1.1 christos 7245 1.1 christos /* 7246 1.1 christos * First, the header to get the packet diverted to the new destination 7247 1.1 christos */ 7248 1.1 christos ip = MTOD(np->in_divmp, ip_t *); 7249 1.1 christos IP_V_A(ip, 4); 7250 1.1 christos IP_HL_A(ip, 5); 7251 1.1 christos ip->ip_tos = 0; 7252 1.1 christos if ((np->in_redir & NAT_DIVERTUDP) != 0) 7253 1.1 christos ip->ip_p = IPPROTO_UDP; 7254 1.1 christos else 7255 1.1 christos ip->ip_p = IPPROTO_IPIP; 7256 1.1 christos ip->ip_ttl = 255; 7257 1.1 christos ip->ip_off = 0; 7258 1.1 christos ip->ip_sum = 0; 7259 1.1 christos ip->ip_len = htons(len); 7260 1.1 christos ip->ip_id = 0; 7261 1.1 christos ip->ip_src.s_addr = htonl(np->in_snip); 7262 1.1 christos ip->ip_dst.s_addr = htonl(np->in_dnip); 7263 1.1 christos ip->ip_sum = ipf_cksum((u_short *)ip, sizeof(*ip)); 7264 1.1 christos 7265 1.1 christos if (np->in_redir & NAT_DIVERTUDP) { 7266 1.1 christos uh = (udphdr_t *)(ip + 1); 7267 1.1 christos uh->uh_sum = 0; 7268 1.1 christos uh->uh_ulen = 8; 7269 1.1 christos uh->uh_sport = htons(np->in_spnext); 7270 1.1 christos uh->uh_dport = htons(np->in_dpnext); 7271 1.1 christos } 7272 1.1 christos 7273 1.1 christos return 0; 7274 1.1 christos } 7275 1.1 christos 7276 1.1 christos 7277 1.1 christos #define MINDECAP (sizeof(ip_t) + sizeof(udphdr_t) + sizeof(ip_t)) 7278 1.1 christos 7279 1.1 christos /* ------------------------------------------------------------------------ */ 7280 1.1 christos /* Function: nat_decap */ 7281 1.1 christos /* Returns: int - -1 == error, 0 == success */ 7282 1.1 christos /* Parameters: fin(I) - pointer to packet information */ 7283 1.1 christos /* nat(I) - pointer to current NAT session */ 7284 1.1 christos /* */ 7285 1.1 christos /* This function is responsible for undoing a packet's encapsulation in the */ 7286 1.1 christos /* reverse of an encap/divert rule. After removing the outer encapsulation */ 7287 1.1 christos /* it is necessary to call ipf_makefrip() again so that the contents of 'fin'*/ 7288 1.1 christos /* match the "new" packet as it may still be used by IPFilter elsewhere. */ 7289 1.1 christos /* We use "dir" here as the basis for some of the expectations about the */ 7290 1.1 christos /* outer header. If we return an error, the goal is to leave the original */ 7291 1.1 christos /* packet information undisturbed - this falls short at the end where we'd */ 7292 1.1 christos /* need to back a backup copy of "fin" - expensive. */ 7293 1.1 christos /* ------------------------------------------------------------------------ */ 7294 1.1 christos static int 7295 1.2 christos ipf_nat_decap(fr_info_t *fin, nat_t *nat) 7296 1.1 christos { 7297 1.1 christos ipf_main_softc_t *softc = fin->fin_main_soft; 7298 1.1 christos ipf_nat_softc_t *softn = softc->ipf_nat_soft; 7299 1.1 christos char *hdr; 7300 1.1 christos int hlen; 7301 1.1 christos int skip; 7302 1.1 christos mb_t *m; 7303 1.1 christos 7304 1.1 christos if ((fin->fin_flx & FI_ICMPERR) != 0) { 7305 1.1 christos /* 7306 1.1 christos * ICMP packets don't get decapsulated, instead what we need 7307 1.1 christos * to do is change the ICMP reply from including (in the data 7308 1.1 christos * portion for errors) the encapsulated packet that we sent 7309 1.1 christos * out to something that resembles the original packet prior 7310 1.1 christos * to encapsulation. This isn't done here - all we're doing 7311 1.1 christos * here is changing the outer address to ensure that it gets 7312 1.1 christos * targetted back to the correct system. 7313 1.1 christos */ 7314 1.1 christos 7315 1.1 christos if (nat->nat_dir & NAT_OUTBOUND) { 7316 1.1 christos u_32_t sum1, sum2, sumd; 7317 1.1 christos 7318 1.1 christos sum1 = ntohl(fin->fin_daddr); 7319 1.1 christos sum2 = ntohl(nat->nat_osrcaddr); 7320 1.1 christos CALC_SUMD(sum1, sum2, sumd); 7321 1.1 christos fin->fin_ip->ip_dst = nat->nat_osrcip; 7322 1.1 christos fin->fin_daddr = nat->nat_osrcaddr; 7323 1.1 christos #if !defined(_KERNEL) || defined(MENTAT) || defined(__sgi) || \ 7324 1.1 christos defined(__osf__) || defined(linux) 7325 1.3 darrenr ipf_fix_outcksum(0, &fin->fin_ip->ip_sum, sumd, 0); 7326 1.1 christos #endif 7327 1.1 christos } 7328 1.1 christos return 0; 7329 1.1 christos } 7330 1.1 christos 7331 1.1 christos m = fin->fin_m; 7332 1.1 christos skip = fin->fin_hlen; 7333 1.1 christos 7334 1.1 christos switch (nat->nat_dir) 7335 1.1 christos { 7336 1.1 christos case NAT_DIVERTIN : 7337 1.1 christos case NAT_DIVERTOUT : 7338 1.1 christos if (fin->fin_plen < MINDECAP) 7339 1.1 christos return -1; 7340 1.1 christos skip += sizeof(udphdr_t); 7341 1.1 christos break; 7342 1.1 christos 7343 1.1 christos case NAT_ENCAPIN : 7344 1.1 christos case NAT_ENCAPOUT : 7345 1.1 christos if (fin->fin_plen < (skip + sizeof(ip_t))) 7346 1.1 christos return -1; 7347 1.1 christos break; 7348 1.1 christos default : 7349 1.1 christos return -1; 7350 1.1 christos /* NOTREACHED */ 7351 1.1 christos } 7352 1.1 christos 7353 1.1 christos /* 7354 1.1 christos * The aim here is to keep the original packet details in "fin" for 7355 1.1 christos * as long as possible so that returning with an error is for the 7356 1.1 christos * original packet and there is little undoing work to do. 7357 1.1 christos */ 7358 1.1 christos if (M_LEN(m) < skip + sizeof(ip_t)) { 7359 1.1 christos if (ipf_pr_pullup(fin, skip + sizeof(ip_t)) == -1) 7360 1.1 christos return -1; 7361 1.1 christos } 7362 1.1 christos 7363 1.1 christos hdr = MTOD(fin->fin_m, char *); 7364 1.1 christos fin->fin_ip = (ip_t *)(hdr + skip); 7365 1.1 christos hlen = IP_HL(fin->fin_ip) << 2; 7366 1.1 christos 7367 1.1 christos if (ipf_pr_pullup(fin, skip + hlen) == -1) { 7368 1.1 christos NBUMPSIDED(fin->fin_out, ns_decap_pullup); 7369 1.1 christos return -1; 7370 1.1 christos } 7371 1.1 christos 7372 1.1 christos fin->fin_hlen = hlen; 7373 1.1 christos fin->fin_dlen -= skip; 7374 1.1 christos fin->fin_plen -= skip; 7375 1.1 christos fin->fin_ipoff += skip; 7376 1.1 christos 7377 1.1 christos if (ipf_makefrip(hlen, (ip_t *)hdr, fin) == -1) { 7378 1.1 christos NBUMPSIDED(fin->fin_out, ns_decap_bad); 7379 1.1 christos return -1; 7380 1.1 christos } 7381 1.1 christos 7382 1.1 christos return skip; 7383 1.1 christos } 7384 1.1 christos 7385 1.1 christos 7386 1.1 christos /* ------------------------------------------------------------------------ */ 7387 1.1 christos /* Function: nat_nextaddr */ 7388 1.1 christos /* Returns: int - -1 == bad input (no new address), */ 7389 1.1 christos /* 0 == success and dst has new address */ 7390 1.1 christos /* Parameters: fin(I) - pointer to packet information */ 7391 1.1 christos /* na(I) - how to generate new address */ 7392 1.1 christos /* old(I) - original address being replaced */ 7393 1.1 christos /* dst(O) - where to put the new address */ 7394 1.1 christos /* Write Lock: ipf_nat */ 7395 1.1 christos /* */ 7396 1.1 christos /* This function uses the contents of the "na" structure, in combination */ 7397 1.1 christos /* with "old" to produce a new address to store in "dst". Not all of the */ 7398 1.1 christos /* possible uses of "na" will result in a new address. */ 7399 1.1 christos /* ------------------------------------------------------------------------ */ 7400 1.1 christos static int 7401 1.2 christos ipf_nat_nextaddr(fr_info_t *fin, nat_addr_t *na, u_32_t *old, u_32_t *dst) 7402 1.1 christos { 7403 1.1 christos ipf_main_softc_t *softc = fin->fin_main_soft; 7404 1.1 christos ipf_nat_softc_t *softn = softc->ipf_nat_soft; 7405 1.1 christos u_32_t amin, amax, new; 7406 1.1 christos i6addr_t newip; 7407 1.1 christos int error; 7408 1.1 christos 7409 1.1 christos new = 0; 7410 1.1 christos amin = na->na_addr[0].in4.s_addr; 7411 1.1 christos 7412 1.1 christos switch (na->na_atype) 7413 1.1 christos { 7414 1.1 christos case FRI_RANGE : 7415 1.1 christos amax = na->na_addr[1].in4.s_addr; 7416 1.1 christos break; 7417 1.1 christos 7418 1.1 christos case FRI_NETMASKED : 7419 1.1 christos case FRI_DYNAMIC : 7420 1.1 christos case FRI_NORMAL : 7421 1.1 christos /* 7422 1.1 christos * Compute the maximum address by adding the inverse of the 7423 1.1 christos * netmask to the minimum address. 7424 1.1 christos */ 7425 1.1 christos amax = ~na->na_addr[1].in4.s_addr; 7426 1.1 christos amax |= amin; 7427 1.1 christos break; 7428 1.1 christos 7429 1.1 christos case FRI_LOOKUP : 7430 1.1 christos break; 7431 1.1 christos 7432 1.1 christos case FRI_BROADCAST : 7433 1.1 christos case FRI_PEERADDR : 7434 1.1 christos case FRI_NETWORK : 7435 1.1 christos default : 7436 1.1 christos return -1; 7437 1.1 christos } 7438 1.1 christos 7439 1.1 christos error = -1; 7440 1.1 christos 7441 1.1 christos if (na->na_atype == FRI_LOOKUP) { 7442 1.1 christos if (na->na_type == IPLT_DSTLIST) { 7443 1.1 christos error = ipf_dstlist_select_node(fin, na->na_ptr, dst, 7444 1.1 christos NULL); 7445 1.1 christos } else { 7446 1.1 christos NBUMPSIDE(fin->fin_out, ns_badnextaddr); 7447 1.1 christos } 7448 1.1 christos 7449 1.1 christos } else if (na->na_atype == IPLT_NONE) { 7450 1.1 christos /* 7451 1.1 christos * 0/0 as the new address means leave it alone. 7452 1.1 christos */ 7453 1.1 christos if (na->na_addr[0].in4.s_addr == 0 && 7454 1.1 christos na->na_addr[1].in4.s_addr == 0) { 7455 1.1 christos new = *old; 7456 1.1 christos 7457 1.1 christos /* 7458 1.1 christos * 0/32 means get the interface's address 7459 1.1 christos */ 7460 1.1 christos } else if (na->na_addr[0].in4.s_addr == 0 && 7461 1.1 christos na->na_addr[1].in4.s_addr == 0xffffffff) { 7462 1.1 christos if (ipf_ifpaddr(softc, 4, na->na_atype, 7463 1.1 christos fin->fin_ifp, &newip, NULL) == -1) { 7464 1.1 christos NBUMPSIDED(fin->fin_out, ns_ifpaddrfail); 7465 1.1 christos return -1; 7466 1.1 christos } 7467 1.1 christos new = newip.in4.s_addr; 7468 1.1 christos } else { 7469 1.1 christos new = htonl(na->na_nextip); 7470 1.1 christos } 7471 1.1 christos *dst = new; 7472 1.1 christos error = 0; 7473 1.1 christos 7474 1.1 christos } else { 7475 1.1 christos NBUMPSIDE(fin->fin_out, ns_badnextaddr); 7476 1.1 christos } 7477 1.1 christos 7478 1.1 christos return error; 7479 1.1 christos } 7480 1.1 christos 7481 1.1 christos 7482 1.1 christos /* ------------------------------------------------------------------------ */ 7483 1.1 christos /* Function: nat_nextaddrinit */ 7484 1.1 christos /* Returns: int - 0 == success, else error number */ 7485 1.3 darrenr /* Parameters: softc(I) - pointer to soft context main structure */ 7486 1.3 darrenr /* na(I) - NAT address information for generating new addr*/ 7487 1.1 christos /* initial(I) - flag indicating if it is the first call for */ 7488 1.1 christos /* this "na" structure. */ 7489 1.1 christos /* ifp(I) - network interface to derive address */ 7490 1.1 christos /* information from. */ 7491 1.1 christos /* */ 7492 1.1 christos /* This function is expected to be called in two scenarious: when a new NAT */ 7493 1.1 christos /* rule is loaded into the kernel and when the list of NAT rules is sync'd */ 7494 1.1 christos /* up with the valid network interfaces (possibly due to them changing.) */ 7495 1.1 christos /* To distinguish between these, the "initial" parameter is used. If it is */ 7496 1.1 christos /* 1 then this indicates the rule has just been reloaded and 0 for when we */ 7497 1.1 christos /* are updating information. This difference is important because in */ 7498 1.1 christos /* instances where we are not updating address information associated with */ 7499 1.1 christos /* a network interface, we don't want to disturb what the "next" address to */ 7500 1.1 christos /* come out of ipf_nat_nextaddr() will be. */ 7501 1.1 christos /* ------------------------------------------------------------------------ */ 7502 1.1 christos static int 7503 1.2 christos ipf_nat_nextaddrinit(ipf_main_softc_t *softc, char *base, nat_addr_t *na, 7504 1.2 christos int initial, void *ifp) 7505 1.1 christos { 7506 1.1 christos 7507 1.1 christos switch (na->na_atype) 7508 1.1 christos { 7509 1.1 christos case FRI_LOOKUP : 7510 1.1 christos if (na->na_subtype == 0) { 7511 1.1 christos na->na_ptr = ipf_lookup_res_num(softc, IPL_LOGNAT, 7512 1.1 christos na->na_type, 7513 1.1 christos na->na_num, 7514 1.1 christos &na->na_func); 7515 1.1 christos } else if (na->na_subtype == 1) { 7516 1.1 christos na->na_ptr = ipf_lookup_res_name(softc, IPL_LOGNAT, 7517 1.1 christos na->na_type, 7518 1.1 christos base + na->na_num, 7519 1.1 christos &na->na_func); 7520 1.1 christos } 7521 1.1 christos if (na->na_func == NULL) { 7522 1.1 christos IPFERROR(60060); 7523 1.1 christos return ESRCH; 7524 1.1 christos } 7525 1.1 christos if (na->na_ptr == NULL) { 7526 1.1 christos IPFERROR(60056); 7527 1.1 christos return ESRCH; 7528 1.1 christos } 7529 1.1 christos break; 7530 1.1 christos 7531 1.1 christos case FRI_DYNAMIC : 7532 1.1 christos case FRI_BROADCAST : 7533 1.1 christos case FRI_NETWORK : 7534 1.1 christos case FRI_NETMASKED : 7535 1.1 christos case FRI_PEERADDR : 7536 1.1 christos if (ifp != NULL) 7537 1.1 christos (void )ipf_ifpaddr(softc, 4, na->na_atype, ifp, 7538 1.1 christos &na->na_addr[0], &na->na_addr[1]); 7539 1.1 christos break; 7540 1.1 christos 7541 1.1 christos case FRI_SPLIT : 7542 1.1 christos case FRI_RANGE : 7543 1.1 christos if (initial) 7544 1.1 christos na->na_nextip = ntohl(na->na_addr[0].in4.s_addr); 7545 1.1 christos break; 7546 1.1 christos 7547 1.1 christos case FRI_NONE : 7548 1.1 christos na->na_addr[0].in4.s_addr &= na->na_addr[1].in4.s_addr; 7549 1.1 christos return 0; 7550 1.1 christos 7551 1.1 christos case FRI_NORMAL : 7552 1.1 christos na->na_addr[0].in4.s_addr &= na->na_addr[1].in4.s_addr; 7553 1.1 christos break; 7554 1.1 christos 7555 1.1 christos default : 7556 1.1 christos IPFERROR(60054); 7557 1.1 christos return EINVAL; 7558 1.1 christos } 7559 1.1 christos 7560 1.1 christos if (initial && (na->na_atype == FRI_NORMAL)) { 7561 1.1 christos if (na->na_addr[0].in4.s_addr == 0) { 7562 1.1 christos if ((na->na_addr[1].in4.s_addr == 0xffffffff) || 7563 1.1 christos (na->na_addr[1].in4.s_addr == 0)) { 7564 1.1 christos return 0; 7565 1.1 christos } 7566 1.1 christos } 7567 1.1 christos 7568 1.1 christos if (na->na_addr[1].in4.s_addr == 0xffffffff) { 7569 1.1 christos na->na_nextip = ntohl(na->na_addr[0].in4.s_addr); 7570 1.1 christos } else { 7571 1.1 christos na->na_nextip = ntohl(na->na_addr[0].in4.s_addr) + 1; 7572 1.1 christos } 7573 1.1 christos } 7574 1.1 christos 7575 1.1 christos return 0; 7576 1.1 christos } 7577 1.1 christos 7578 1.1 christos 7579 1.1 christos /* ------------------------------------------------------------------------ */ 7580 1.1 christos /* Function: ipf_nat_matchflush */ 7581 1.1 christos /* Returns: int - -1 == error, 0 == success */ 7582 1.3 darrenr /* Parameters: softc(I) - pointer to soft context main structure */ 7583 1.3 darrenr /* softn(I) - pointer to NAT context structure */ 7584 1.3 darrenr /* nat(I) - pointer to current NAT session */ 7585 1.1 christos /* */ 7586 1.1 christos /* ------------------------------------------------------------------------ */ 7587 1.1 christos static int 7588 1.2 christos ipf_nat_matchflush(ipf_main_softc_t *softc, ipf_nat_softc_t *softn, void *data) 7589 1.1 christos { 7590 1.1 christos int *array, flushed, error; 7591 1.1 christos nat_t *nat, *natnext; 7592 1.1 christos ipfobj_t obj; 7593 1.1 christos 7594 1.1 christos error = ipf_matcharray_load(softc, data, &obj, &array); 7595 1.1 christos if (error != 0) 7596 1.1 christos return error; 7597 1.1 christos 7598 1.1 christos flushed = 0; 7599 1.1 christos 7600 1.1 christos for (nat = softn->ipf_nat_instances; nat != NULL; nat = natnext) { 7601 1.1 christos natnext = nat->nat_next; 7602 1.1 christos if (ipf_nat_matcharray(nat, array, softc->ipf_ticks) == 0) { 7603 1.1 christos ipf_nat_delete(softc, nat, NL_FLUSH); 7604 1.1 christos flushed++; 7605 1.1 christos } 7606 1.1 christos } 7607 1.1 christos 7608 1.1 christos obj.ipfo_retval = flushed; 7609 1.1 christos error = BCOPYOUT(&obj, data, sizeof(obj)); 7610 1.1 christos 7611 1.1 christos KFREES(array, array[0] * sizeof(*array)); 7612 1.1 christos 7613 1.1 christos return error; 7614 1.1 christos } 7615 1.1 christos 7616 1.1 christos 7617 1.1 christos /* ------------------------------------------------------------------------ */ 7618 1.1 christos /* Function: ipf_nat_matcharray */ 7619 1.1 christos /* Returns: int - -1 == error, 0 == success */ 7620 1.1 christos /* Parameters: fin(I) - pointer to packet information */ 7621 1.1 christos /* nat(I) - pointer to current NAT session */ 7622 1.1 christos /* */ 7623 1.1 christos /* ------------------------------------------------------------------------ */ 7624 1.1 christos static int 7625 1.2 christos ipf_nat_matcharray(nat_t *nat, int *array, u_long ticks) 7626 1.1 christos { 7627 1.1 christos int i, n, *x, e, p; 7628 1.1 christos 7629 1.1 christos e = 0; 7630 1.1 christos n = array[0]; 7631 1.1 christos x = array + 1; 7632 1.1 christos 7633 1.1 christos for (; n > 0; x += 3 + x[2]) { 7634 1.1 christos if (x[0] == IPF_EXP_END) 7635 1.1 christos break; 7636 1.1 christos e = 0; 7637 1.1 christos 7638 1.1 christos n -= x[2] + 3; 7639 1.1 christos if (n < 0) 7640 1.1 christos break; 7641 1.1 christos 7642 1.1 christos p = x[0] >> 16; 7643 1.1 christos if (p != 0 && p != nat->nat_pr[1]) 7644 1.1 christos break; 7645 1.1 christos 7646 1.1 christos switch (x[0]) 7647 1.1 christos { 7648 1.1 christos case IPF_EXP_IP_PR : 7649 1.1 christos for (i = 0; !e && i < x[2]; i++) { 7650 1.1 christos e |= (nat->nat_pr[1] == x[i + 3]); 7651 1.1 christos } 7652 1.1 christos break; 7653 1.1 christos 7654 1.1 christos case IPF_EXP_IP_SRCADDR : 7655 1.1 christos if (nat->nat_v[0] == 4) { 7656 1.1 christos for (i = 0; !e && i < x[2]; i++) { 7657 1.1 christos e |= ((nat->nat_osrcaddr & x[i + 4]) == 7658 1.1 christos x[i + 3]); 7659 1.1 christos } 7660 1.1 christos } 7661 1.1 christos if (nat->nat_v[1] == 4) { 7662 1.1 christos for (i = 0; !e && i < x[2]; i++) { 7663 1.1 christos e |= ((nat->nat_nsrcaddr & x[i + 4]) == 7664 1.1 christos x[i + 3]); 7665 1.1 christos } 7666 1.1 christos } 7667 1.1 christos break; 7668 1.1 christos 7669 1.1 christos case IPF_EXP_IP_DSTADDR : 7670 1.1 christos if (nat->nat_v[0] == 4) { 7671 1.1 christos for (i = 0; !e && i < x[2]; i++) { 7672 1.1 christos e |= ((nat->nat_odstaddr & x[i + 4]) == 7673 1.1 christos x[i + 3]); 7674 1.1 christos } 7675 1.1 christos } 7676 1.1 christos if (nat->nat_v[1] == 4) { 7677 1.1 christos for (i = 0; !e && i < x[2]; i++) { 7678 1.1 christos e |= ((nat->nat_ndstaddr & x[i + 4]) == 7679 1.1 christos x[i + 3]); 7680 1.1 christos } 7681 1.1 christos } 7682 1.1 christos break; 7683 1.1 christos 7684 1.1 christos case IPF_EXP_IP_ADDR : 7685 1.1 christos for (i = 0; !e && i < x[2]; i++) { 7686 1.1 christos if (nat->nat_v[0] == 4) { 7687 1.1 christos e |= ((nat->nat_osrcaddr & x[i + 4]) == 7688 1.1 christos x[i + 3]); 7689 1.1 christos } 7690 1.1 christos if (nat->nat_v[1] == 4) { 7691 1.1 christos e |= ((nat->nat_nsrcaddr & x[i + 4]) == 7692 1.1 christos x[i + 3]); 7693 1.1 christos } 7694 1.1 christos if (nat->nat_v[0] == 4) { 7695 1.1 christos e |= ((nat->nat_odstaddr & x[i + 4]) == 7696 1.1 christos x[i + 3]); 7697 1.1 christos } 7698 1.1 christos if (nat->nat_v[1] == 4) { 7699 1.1 christos e |= ((nat->nat_ndstaddr & x[i + 4]) == 7700 1.1 christos x[i + 3]); 7701 1.1 christos } 7702 1.1 christos } 7703 1.1 christos break; 7704 1.1 christos 7705 1.1 christos #ifdef USE_INET6 7706 1.1 christos case IPF_EXP_IP6_SRCADDR : 7707 1.1 christos if (nat->nat_v[0] == 6) { 7708 1.1 christos for (i = 0; !e && i < x[3]; i++) { 7709 1.1 christos e |= IP6_MASKEQ(&nat->nat_osrc6, 7710 1.1 christos x + i + 7, x + i + 3); 7711 1.1 christos } 7712 1.1 christos } 7713 1.1 christos if (nat->nat_v[1] == 6) { 7714 1.1 christos for (i = 0; !e && i < x[3]; i++) { 7715 1.1 christos e |= IP6_MASKEQ(&nat->nat_nsrc6, 7716 1.1 christos x + i + 7, x + i + 3); 7717 1.1 christos } 7718 1.1 christos } 7719 1.1 christos break; 7720 1.1 christos 7721 1.1 christos case IPF_EXP_IP6_DSTADDR : 7722 1.1 christos if (nat->nat_v[0] == 6) { 7723 1.1 christos for (i = 0; !e && i < x[3]; i++) { 7724 1.1 christos e |= IP6_MASKEQ(&nat->nat_odst6, 7725 1.1 christos x + i + 7, 7726 1.1 christos x + i + 3); 7727 1.1 christos } 7728 1.1 christos } 7729 1.1 christos if (nat->nat_v[1] == 6) { 7730 1.1 christos for (i = 0; !e && i < x[3]; i++) { 7731 1.1 christos e |= IP6_MASKEQ(&nat->nat_ndst6, 7732 1.1 christos x + i + 7, 7733 1.1 christos x + i + 3); 7734 1.1 christos } 7735 1.1 christos } 7736 1.1 christos break; 7737 1.1 christos 7738 1.1 christos case IPF_EXP_IP6_ADDR : 7739 1.1 christos for (i = 0; !e && i < x[3]; i++) { 7740 1.1 christos if (nat->nat_v[0] == 6) { 7741 1.1 christos e |= IP6_MASKEQ(&nat->nat_osrc6, 7742 1.1 christos x + i + 7, 7743 1.1 christos x + i + 3); 7744 1.1 christos } 7745 1.1 christos if (nat->nat_v[0] == 6) { 7746 1.1 christos e |= IP6_MASKEQ(&nat->nat_odst6, 7747 1.1 christos x + i + 7, 7748 1.1 christos x + i + 3); 7749 1.1 christos } 7750 1.1 christos if (nat->nat_v[1] == 6) { 7751 1.1 christos e |= IP6_MASKEQ(&nat->nat_nsrc6, 7752 1.1 christos x + i + 7, 7753 1.1 christos x + i + 3); 7754 1.1 christos } 7755 1.1 christos if (nat->nat_v[1] == 6) { 7756 1.1 christos e |= IP6_MASKEQ(&nat->nat_ndst6, 7757 1.1 christos x + i + 7, 7758 1.1 christos x + i + 3); 7759 1.1 christos } 7760 1.1 christos } 7761 1.1 christos break; 7762 1.1 christos #endif 7763 1.1 christos 7764 1.1 christos case IPF_EXP_UDP_PORT : 7765 1.1 christos case IPF_EXP_TCP_PORT : 7766 1.1 christos for (i = 0; !e && i < x[2]; i++) { 7767 1.1 christos e |= (nat->nat_nsport == x[i + 3]) || 7768 1.1 christos (nat->nat_ndport == x[i + 3]); 7769 1.1 christos } 7770 1.1 christos break; 7771 1.1 christos 7772 1.1 christos case IPF_EXP_UDP_SPORT : 7773 1.1 christos case IPF_EXP_TCP_SPORT : 7774 1.1 christos for (i = 0; !e && i < x[2]; i++) { 7775 1.1 christos e |= (nat->nat_nsport == x[i + 3]); 7776 1.1 christos } 7777 1.1 christos break; 7778 1.1 christos 7779 1.1 christos case IPF_EXP_UDP_DPORT : 7780 1.1 christos case IPF_EXP_TCP_DPORT : 7781 1.1 christos for (i = 0; !e && i < x[2]; i++) { 7782 1.1 christos e |= (nat->nat_ndport == x[i + 3]); 7783 1.1 christos } 7784 1.1 christos break; 7785 1.1 christos 7786 1.1 christos case IPF_EXP_TCP_STATE : 7787 1.1 christos for (i = 0; !e && i < x[2]; i++) { 7788 1.1 christos e |= (nat->nat_tcpstate[0] == x[i + 3]) || 7789 1.1 christos (nat->nat_tcpstate[1] == x[i + 3]); 7790 1.1 christos } 7791 1.1 christos break; 7792 1.1 christos 7793 1.1 christos case IPF_EXP_IDLE_GT : 7794 1.1 christos e |= (ticks - nat->nat_touched > x[3]); 7795 1.1 christos break; 7796 1.1 christos } 7797 1.1 christos e ^= x[1]; 7798 1.1 christos 7799 1.1 christos if (!e) 7800 1.1 christos break; 7801 1.1 christos } 7802 1.1 christos 7803 1.1 christos return e; 7804 1.1 christos } 7805 1.1 christos 7806 1.1 christos 7807 1.1 christos /* ------------------------------------------------------------------------ */ 7808 1.1 christos /* Function: ipf_nat_gettable */ 7809 1.1 christos /* Returns: int - 0 = success, else error */ 7810 1.3 darrenr /* Parameters: softc(I) - pointer to soft context main structure */ 7811 1.3 darrenr /* softn(I) - pointer to NAT context structure */ 7812 1.3 darrenr /* data(I) - pointer to ioctl data */ 7813 1.1 christos /* */ 7814 1.1 christos /* This function handles ioctl requests for tables of nat information. */ 7815 1.1 christos /* At present the only table it deals with is the hash bucket statistics. */ 7816 1.1 christos /* ------------------------------------------------------------------------ */ 7817 1.1 christos static int 7818 1.2 christos ipf_nat_gettable(ipf_main_softc_t *softc, ipf_nat_softc_t *softn, char *data) 7819 1.1 christos { 7820 1.1 christos ipftable_t table; 7821 1.1 christos int error; 7822 1.1 christos 7823 1.1 christos error = ipf_inobj(softc, data, NULL, &table, IPFOBJ_GTABLE); 7824 1.1 christos if (error != 0) 7825 1.1 christos return error; 7826 1.1 christos 7827 1.1 christos switch (table.ita_type) 7828 1.1 christos { 7829 1.1 christos case IPFTABLE_BUCKETS_NATIN : 7830 1.1 christos error = COPYOUT(softn->ipf_nat_stats.ns_side[0].ns_bucketlen, 7831 1.1 christos table.ita_table, 7832 1.3 darrenr softn->ipf_nat_table_sz * sizeof(u_int)); 7833 1.1 christos break; 7834 1.1 christos 7835 1.1 christos case IPFTABLE_BUCKETS_NATOUT : 7836 1.1 christos error = COPYOUT(softn->ipf_nat_stats.ns_side[1].ns_bucketlen, 7837 1.1 christos table.ita_table, 7838 1.3 darrenr softn->ipf_nat_table_sz * sizeof(u_int)); 7839 1.1 christos break; 7840 1.1 christos 7841 1.1 christos default : 7842 1.1 christos IPFERROR(60058); 7843 1.1 christos return EINVAL; 7844 1.1 christos } 7845 1.1 christos 7846 1.1 christos if (error != 0) { 7847 1.1 christos IPFERROR(60059); 7848 1.1 christos error = EFAULT; 7849 1.1 christos } 7850 1.1 christos return error; 7851 1.1 christos } 7852 1.1 christos 7853 1.1 christos 7854 1.1 christos /* ------------------------------------------------------------------------ */ 7855 1.1 christos /* Function: ipf_nat_settimeout */ 7856 1.1 christos /* Returns: int - 0 = success, else failure */ 7857 1.3 darrenr /* Parameters: softc(I) - pointer to soft context main structure */ 7858 1.3 darrenr /* t(I) - pointer to tunable */ 7859 1.1 christos /* p(I) - pointer to new tuning data */ 7860 1.1 christos /* */ 7861 1.1 christos /* Apply the timeout change to the NAT timeout queues. */ 7862 1.1 christos /* ------------------------------------------------------------------------ */ 7863 1.1 christos int 7864 1.2 christos ipf_nat_settimeout(struct ipf_main_softc_s *softc, ipftuneable_t *t, 7865 1.2 christos ipftuneval_t *p) 7866 1.1 christos { 7867 1.1 christos ipf_nat_softc_t *softn = softc->ipf_nat_soft; 7868 1.1 christos 7869 1.1 christos if (!strncmp(t->ipft_name, "tcp_", 4)) 7870 1.1 christos return ipf_settimeout_tcp(t, p, softn->ipf_nat_tcptq); 7871 1.1 christos 7872 1.1 christos if (!strcmp(t->ipft_name, "udp_timeout")) { 7873 1.1 christos ipf_apply_timeout(&softn->ipf_nat_udptq, p->ipftu_int); 7874 1.1 christos } else if (!strcmp(t->ipft_name, "udp_ack_timeout")) { 7875 1.1 christos ipf_apply_timeout(&softn->ipf_nat_udpacktq, p->ipftu_int); 7876 1.1 christos } else if (!strcmp(t->ipft_name, "icmp_timeout")) { 7877 1.1 christos ipf_apply_timeout(&softn->ipf_nat_icmptq, p->ipftu_int); 7878 1.1 christos } else if (!strcmp(t->ipft_name, "icmp_ack_timeout")) { 7879 1.1 christos ipf_apply_timeout(&softn->ipf_nat_icmpacktq, p->ipftu_int); 7880 1.1 christos } else if (!strcmp(t->ipft_name, "ip_timeout")) { 7881 1.1 christos ipf_apply_timeout(&softn->ipf_nat_iptq, p->ipftu_int); 7882 1.1 christos } else { 7883 1.1 christos IPFERROR(60062); 7884 1.1 christos return ESRCH; 7885 1.1 christos } 7886 1.1 christos return 0; 7887 1.1 christos } 7888 1.1 christos 7889 1.1 christos 7890 1.1 christos /* ------------------------------------------------------------------------ */ 7891 1.1 christos /* Function: ipf_nat_rehash */ 7892 1.1 christos /* Returns: int - 0 = success, else failure */ 7893 1.3 darrenr /* Parameters: softc(I) - pointer to soft context main structure */ 7894 1.3 darrenr /* t(I) - pointer to tunable */ 7895 1.1 christos /* p(I) - pointer to new tuning data */ 7896 1.1 christos /* */ 7897 1.1 christos /* To change the size of the basic NAT table, we need to first allocate the */ 7898 1.1 christos /* new tables (lest it fails and we've got nowhere to store all of the NAT */ 7899 1.1 christos /* sessions currently active) and then walk through the entire list and */ 7900 1.1 christos /* insert them into the table. There are two tables here: an inbound one */ 7901 1.1 christos /* and an outbound one. Each NAT entry goes into each table once. */ 7902 1.1 christos /* ------------------------------------------------------------------------ */ 7903 1.1 christos int 7904 1.2 christos ipf_nat_rehash(ipf_main_softc_t *softc, ipftuneable_t *t, ipftuneval_t *p) 7905 1.1 christos { 7906 1.1 christos ipf_nat_softc_t *softn = softc->ipf_nat_soft; 7907 1.1 christos nat_t **newtab[2], *nat, **natp; 7908 1.1 christos u_int *bucketlens[2]; 7909 1.1 christos u_int maxbucket; 7910 1.1 christos u_int newsize; 7911 1.3 darrenr int error; 7912 1.1 christos u_int hv; 7913 1.1 christos int i; 7914 1.1 christos 7915 1.1 christos newsize = p->ipftu_int; 7916 1.1 christos /* 7917 1.1 christos * In case there is nothing to do... 7918 1.1 christos */ 7919 1.1 christos if (newsize == softn->ipf_nat_table_sz) 7920 1.1 christos return 0; 7921 1.1 christos 7922 1.3 darrenr newtab[0] = NULL; 7923 1.3 darrenr newtab[1] = NULL; 7924 1.3 darrenr bucketlens[0] = NULL; 7925 1.3 darrenr bucketlens[1] = NULL; 7926 1.1 christos /* 7927 1.1 christos * 4 tables depend on the NAT table size: the inbound looking table, 7928 1.1 christos * the outbound lookup table and the hash chain length for each. 7929 1.1 christos */ 7930 1.1 christos KMALLOCS(newtab[0], nat_t **, newsize * sizeof(nat_t *)); 7931 1.11 joerg if (newtab[0] == NULL) { 7932 1.3 darrenr error = 60063; 7933 1.3 darrenr goto badrehash; 7934 1.1 christos } 7935 1.1 christos 7936 1.1 christos KMALLOCS(newtab[1], nat_t **, newsize * sizeof(nat_t *)); 7937 1.11 joerg if (newtab[1] == NULL) { 7938 1.3 darrenr error = 60064; 7939 1.3 darrenr goto badrehash; 7940 1.1 christos } 7941 1.1 christos 7942 1.1 christos KMALLOCS(bucketlens[0], u_int *, newsize * sizeof(u_int)); 7943 1.1 christos if (bucketlens[0] == NULL) { 7944 1.3 darrenr error = 60065; 7945 1.3 darrenr goto badrehash; 7946 1.1 christos } 7947 1.1 christos 7948 1.1 christos KMALLOCS(bucketlens[1], u_int *, newsize * sizeof(u_int)); 7949 1.1 christos if (bucketlens[1] == NULL) { 7950 1.3 darrenr error = 60066; 7951 1.3 darrenr goto badrehash; 7952 1.1 christos } 7953 1.1 christos 7954 1.1 christos /* 7955 1.1 christos * Recalculate the maximum length based on the new size. 7956 1.1 christos */ 7957 1.1 christos for (maxbucket = 0, i = newsize; i > 0; i >>= 1) 7958 1.1 christos maxbucket++; 7959 1.1 christos maxbucket *= 2; 7960 1.1 christos 7961 1.1 christos bzero((char *)newtab[0], newsize * sizeof(nat_t *)); 7962 1.1 christos bzero((char *)newtab[1], newsize * sizeof(nat_t *)); 7963 1.1 christos bzero((char *)bucketlens[0], newsize * sizeof(u_int)); 7964 1.1 christos bzero((char *)bucketlens[1], newsize * sizeof(u_int)); 7965 1.1 christos 7966 1.1 christos WRITE_ENTER(&softc->ipf_nat); 7967 1.1 christos 7968 1.1 christos if (softn->ipf_nat_table[0] != NULL) { 7969 1.1 christos KFREES(softn->ipf_nat_table[0], 7970 1.1 christos softn->ipf_nat_table_sz * 7971 1.1 christos sizeof(*softn->ipf_nat_table[0])); 7972 1.1 christos } 7973 1.1 christos softn->ipf_nat_table[0] = newtab[0]; 7974 1.1 christos 7975 1.1 christos if (softn->ipf_nat_table[1] != NULL) { 7976 1.1 christos KFREES(softn->ipf_nat_table[1], 7977 1.1 christos softn->ipf_nat_table_sz * 7978 1.1 christos sizeof(*softn->ipf_nat_table[1])); 7979 1.1 christos } 7980 1.1 christos softn->ipf_nat_table[1] = newtab[1]; 7981 1.1 christos 7982 1.1 christos if (softn->ipf_nat_stats.ns_side[0].ns_bucketlen != NULL) { 7983 1.1 christos KFREES(softn->ipf_nat_stats.ns_side[0].ns_bucketlen, 7984 1.1 christos softn->ipf_nat_table_sz * sizeof(u_int)); 7985 1.1 christos } 7986 1.1 christos softn->ipf_nat_stats.ns_side[0].ns_bucketlen = bucketlens[0]; 7987 1.1 christos 7988 1.1 christos if (softn->ipf_nat_stats.ns_side[1].ns_bucketlen != NULL) { 7989 1.1 christos KFREES(softn->ipf_nat_stats.ns_side[1].ns_bucketlen, 7990 1.1 christos softn->ipf_nat_table_sz * sizeof(u_int)); 7991 1.1 christos } 7992 1.1 christos softn->ipf_nat_stats.ns_side[1].ns_bucketlen = bucketlens[1]; 7993 1.1 christos 7994 1.1 christos softn->ipf_nat_maxbucket = maxbucket; 7995 1.1 christos softn->ipf_nat_table_sz = newsize; 7996 1.1 christos /* 7997 1.1 christos * Walk through the entire list of NAT table entries and put them 7998 1.1 christos * in the new NAT table, somewhere. Because we have a new table, 7999 1.1 christos * we need to restart the counter of how many chains are in use. 8000 1.1 christos */ 8001 1.1 christos softn->ipf_nat_stats.ns_side[0].ns_inuse = 0; 8002 1.1 christos softn->ipf_nat_stats.ns_side[1].ns_inuse = 0; 8003 1.1 christos 8004 1.1 christos for (nat = softn->ipf_nat_instances; nat != NULL; nat = nat->nat_next) { 8005 1.1 christos nat->nat_hnext[0] = NULL; 8006 1.1 christos nat->nat_phnext[0] = NULL; 8007 1.1 christos hv = nat->nat_hv[0] % softn->ipf_nat_table_sz; 8008 1.1 christos 8009 1.1 christos natp = &softn->ipf_nat_table[0][hv]; 8010 1.1 christos if (*natp) { 8011 1.1 christos (*natp)->nat_phnext[0] = &nat->nat_hnext[0]; 8012 1.1 christos } else { 8013 1.1 christos NBUMPSIDE(0, ns_inuse); 8014 1.1 christos } 8015 1.1 christos nat->nat_phnext[0] = natp; 8016 1.1 christos nat->nat_hnext[0] = *natp; 8017 1.1 christos *natp = nat; 8018 1.1 christos NBUMPSIDE(0, ns_bucketlen[hv]); 8019 1.1 christos 8020 1.1 christos nat->nat_hnext[1] = NULL; 8021 1.1 christos nat->nat_phnext[1] = NULL; 8022 1.1 christos hv = nat->nat_hv[1] % softn->ipf_nat_table_sz; 8023 1.1 christos 8024 1.1 christos natp = &softn->ipf_nat_table[1][hv]; 8025 1.1 christos if (*natp) { 8026 1.1 christos (*natp)->nat_phnext[1] = &nat->nat_hnext[1]; 8027 1.1 christos } else { 8028 1.1 christos NBUMPSIDE(1, ns_inuse); 8029 1.1 christos } 8030 1.1 christos nat->nat_phnext[1] = natp; 8031 1.1 christos nat->nat_hnext[1] = *natp; 8032 1.1 christos *natp = nat; 8033 1.1 christos NBUMPSIDE(1, ns_bucketlen[hv]); 8034 1.1 christos } 8035 1.1 christos RWLOCK_EXIT(&softc->ipf_nat); 8036 1.1 christos 8037 1.1 christos return 0; 8038 1.3 darrenr 8039 1.3 darrenr badrehash: 8040 1.3 darrenr if (bucketlens[1] != NULL) { 8041 1.3 darrenr KFREES(bucketlens[0], newsize * sizeof(u_int)); 8042 1.3 darrenr } 8043 1.3 darrenr if (bucketlens[0] != NULL) { 8044 1.3 darrenr KFREES(bucketlens[0], newsize * sizeof(u_int)); 8045 1.3 darrenr } 8046 1.3 darrenr if (newtab[0] != NULL) { 8047 1.3 darrenr KFREES(newtab[0], newsize * sizeof(nat_t *)); 8048 1.3 darrenr } 8049 1.3 darrenr if (newtab[1] != NULL) { 8050 1.3 darrenr KFREES(newtab[1], newsize * sizeof(nat_t *)); 8051 1.3 darrenr } 8052 1.3 darrenr IPFERROR(error); 8053 1.3 darrenr return ENOMEM; 8054 1.1 christos } 8055 1.1 christos 8056 1.1 christos 8057 1.1 christos /* ------------------------------------------------------------------------ */ 8058 1.1 christos /* Function: ipf_nat_rehash_rules */ 8059 1.1 christos /* Returns: int - 0 = success, else failure */ 8060 1.3 darrenr /* Parameters: softc(I) - pointer to soft context main structure */ 8061 1.3 darrenr /* t(I) - pointer to tunable */ 8062 1.1 christos /* p(I) - pointer to new tuning data */ 8063 1.1 christos /* */ 8064 1.1 christos /* All of the NAT rules hang off of a hash table that is searched with a */ 8065 1.1 christos /* hash on address after the netmask is applied. There is a different table*/ 8066 1.1 christos /* for both inbound rules (rdr) and outbound (map.) The resizing will only */ 8067 1.1 christos /* affect one of these two tables. */ 8068 1.1 christos /* ------------------------------------------------------------------------ */ 8069 1.1 christos int 8070 1.2 christos ipf_nat_rehash_rules(ipf_main_softc_t *softc, ipftuneable_t *t, ipftuneval_t *p) 8071 1.1 christos { 8072 1.1 christos ipf_nat_softc_t *softn = softc->ipf_nat_soft; 8073 1.1 christos ipnat_t **newtab, *np, ***old, **npp; 8074 1.1 christos u_int newsize; 8075 1.1 christos u_int mask; 8076 1.1 christos u_int hv; 8077 1.1 christos 8078 1.1 christos newsize = p->ipftu_int; 8079 1.1 christos /* 8080 1.1 christos * In case there is nothing to do... 8081 1.1 christos */ 8082 1.1 christos if (newsize == *t->ipft_pint) 8083 1.1 christos return 0; 8084 1.1 christos 8085 1.1 christos /* 8086 1.1 christos * All inbound rules have the NAT_REDIRECT bit set in in_redir and 8087 1.1 christos * all outbound rules have either NAT_MAP or MAT_MAPBLK set. 8088 1.1 christos * This if statement allows for some more generic code to be below, 8089 1.1 christos * rather than two huge gobs of code that almost do the same thing. 8090 1.1 christos */ 8091 1.1 christos if (t->ipft_pint == &softn->ipf_nat_rdrrules_sz) { 8092 1.1 christos old = &softn->ipf_nat_rdr_rules; 8093 1.1 christos mask = NAT_REDIRECT; 8094 1.1 christos } else { 8095 1.1 christos old = &softn->ipf_nat_map_rules; 8096 1.1 christos mask = NAT_MAP|NAT_MAPBLK; 8097 1.1 christos } 8098 1.1 christos 8099 1.1 christos KMALLOCS(newtab, ipnat_t **, newsize * sizeof(ipnat_t *)); 8100 1.1 christos if (newtab == NULL) { 8101 1.1 christos IPFERROR(60067); 8102 1.1 christos return ENOMEM; 8103 1.1 christos } 8104 1.1 christos 8105 1.1 christos bzero((char *)newtab, newsize * sizeof(ipnat_t *)); 8106 1.1 christos 8107 1.1 christos WRITE_ENTER(&softc->ipf_nat); 8108 1.1 christos 8109 1.1 christos if (*old != NULL) { 8110 1.1 christos KFREES(*old, *t->ipft_pint * sizeof(ipnat_t **)); 8111 1.1 christos } 8112 1.1 christos *old = newtab; 8113 1.1 christos *t->ipft_pint = newsize; 8114 1.1 christos 8115 1.1 christos for (np = softn->ipf_nat_list; np != NULL; np = np->in_next) { 8116 1.1 christos if ((np->in_redir & mask) == 0) 8117 1.1 christos continue; 8118 1.1 christos 8119 1.3 darrenr if (np->in_redir & NAT_REDIRECT) { 8120 1.3 darrenr np->in_rnext = NULL; 8121 1.3 darrenr hv = np->in_hv[0] % newsize; 8122 1.3 darrenr for (npp = newtab + hv; *npp != NULL; ) 8123 1.3 darrenr npp = &(*npp)->in_rnext; 8124 1.3 darrenr np->in_prnext = npp; 8125 1.3 darrenr *npp = np; 8126 1.3 darrenr } 8127 1.3 darrenr if (np->in_redir & NAT_MAP) { 8128 1.3 darrenr np->in_mnext = NULL; 8129 1.3 darrenr hv = np->in_hv[1] % newsize; 8130 1.3 darrenr for (npp = newtab + hv; *npp != NULL; ) 8131 1.3 darrenr npp = &(*npp)->in_mnext; 8132 1.3 darrenr np->in_pmnext = npp; 8133 1.3 darrenr *npp = np; 8134 1.1 christos } 8135 1.1 christos 8136 1.1 christos } 8137 1.1 christos RWLOCK_EXIT(&softc->ipf_nat); 8138 1.1 christos 8139 1.1 christos return 0; 8140 1.1 christos } 8141 1.1 christos 8142 1.1 christos 8143 1.1 christos /* ------------------------------------------------------------------------ */ 8144 1.1 christos /* Function: ipf_nat_hostmap_rehash */ 8145 1.1 christos /* Returns: int - 0 = success, else failure */ 8146 1.3 darrenr /* Parameters: softc(I) - pointer to soft context main structure */ 8147 1.3 darrenr /* t(I) - pointer to tunable */ 8148 1.1 christos /* p(I) - pointer to new tuning data */ 8149 1.1 christos /* */ 8150 1.1 christos /* Allocate and populate a new hash table that will contain a reference to */ 8151 1.1 christos /* all of the active IP# translations currently in place. */ 8152 1.1 christos /* ------------------------------------------------------------------------ */ 8153 1.1 christos int 8154 1.2 christos ipf_nat_hostmap_rehash(ipf_main_softc_t *softc, ipftuneable_t *t, 8155 1.2 christos ipftuneval_t *p) 8156 1.1 christos { 8157 1.1 christos ipf_nat_softc_t *softn = softc->ipf_nat_soft; 8158 1.1 christos hostmap_t *hm, **newtab; 8159 1.1 christos u_int newsize; 8160 1.1 christos u_int hv; 8161 1.1 christos 8162 1.1 christos newsize = p->ipftu_int; 8163 1.1 christos /* 8164 1.1 christos * In case there is nothing to do... 8165 1.1 christos */ 8166 1.1 christos if (newsize == *t->ipft_pint) 8167 1.1 christos return 0; 8168 1.1 christos 8169 1.1 christos KMALLOCS(newtab, hostmap_t **, newsize * sizeof(hostmap_t *)); 8170 1.1 christos if (newtab == NULL) { 8171 1.1 christos IPFERROR(60068); 8172 1.1 christos return ENOMEM; 8173 1.1 christos } 8174 1.1 christos 8175 1.1 christos bzero((char *)newtab, newsize * sizeof(hostmap_t *)); 8176 1.1 christos 8177 1.1 christos WRITE_ENTER(&softc->ipf_nat); 8178 1.1 christos if (softn->ipf_hm_maptable != NULL) { 8179 1.1 christos KFREES(softn->ipf_hm_maptable, 8180 1.1 christos softn->ipf_nat_hostmap_sz * sizeof(hostmap_t *)); 8181 1.1 christos } 8182 1.1 christos softn->ipf_hm_maptable = newtab; 8183 1.1 christos softn->ipf_nat_hostmap_sz = newsize; 8184 1.1 christos 8185 1.1 christos for (hm = softn->ipf_hm_maplist; hm != NULL; hm = hm->hm_next) { 8186 1.1 christos hv = hm->hm_hv % softn->ipf_nat_hostmap_sz; 8187 1.1 christos hm->hm_hnext = softn->ipf_hm_maptable[hv]; 8188 1.1 christos hm->hm_phnext = softn->ipf_hm_maptable + hv; 8189 1.1 christos if (softn->ipf_hm_maptable[hv] != NULL) 8190 1.1 christos softn->ipf_hm_maptable[hv]->hm_phnext = &hm->hm_hnext; 8191 1.1 christos softn->ipf_hm_maptable[hv] = hm; 8192 1.1 christos } 8193 1.1 christos RWLOCK_EXIT(&softc->ipf_nat); 8194 1.1 christos 8195 1.1 christos return 0; 8196 1.1 christos } 8197 1.1 christos 8198 1.1 christos 8199 1.1 christos /* ------------------------------------------------------------------------ */ 8200 1.1 christos /* Function: ipf_nat_add_tq */ 8201 1.1 christos /* Parameters: softc(I) - pointer to soft context main structure */ 8202 1.1 christos /* */ 8203 1.1 christos /* ------------------------------------------------------------------------ */ 8204 1.1 christos ipftq_t * 8205 1.2 christos ipf_nat_add_tq(ipf_main_softc_t *softc, int ttl) 8206 1.1 christos { 8207 1.1 christos ipf_nat_softc_t *softs = softc->ipf_nat_soft; 8208 1.1 christos 8209 1.1 christos return ipf_addtimeoutqueue(softc, &softs->ipf_nat_utqe, ttl); 8210 1.1 christos } 8211 1.1 christos 8212 1.1 christos /* ------------------------------------------------------------------------ */ 8213 1.3 darrenr /* Function: ipf_nat_uncreate */ 8214 1.1 christos /* Returns: Nil */ 8215 1.1 christos /* Parameters: fin(I) - pointer to packet information */ 8216 1.1 christos /* */ 8217 1.1 christos /* This function is used to remove a NAT entry from the NAT table when we */ 8218 1.1 christos /* decide that the create was actually in error. It is thus assumed that */ 8219 1.1 christos /* fin_flx will have both FI_NATED and FI_NATNEW set. Because we're dealing */ 8220 1.1 christos /* with the translated packet (not the original), we have to reverse the */ 8221 1.1 christos /* lookup. Although doing the lookup is expensive (relatively speaking), it */ 8222 1.1 christos /* is not anticipated that this will be a frequent occurance for normal */ 8223 1.1 christos /* traffic patterns. */ 8224 1.1 christos /* ------------------------------------------------------------------------ */ 8225 1.1 christos void 8226 1.2 christos ipf_nat_uncreate(fr_info_t *fin) 8227 1.1 christos { 8228 1.1 christos ipf_main_softc_t *softc = fin->fin_main_soft; 8229 1.1 christos ipf_nat_softc_t *softn = softc->ipf_nat_soft; 8230 1.1 christos int nflags; 8231 1.1 christos nat_t *nat; 8232 1.1 christos 8233 1.1 christos switch (fin->fin_p) 8234 1.1 christos { 8235 1.1 christos case IPPROTO_TCP : 8236 1.1 christos nflags = IPN_TCP; 8237 1.1 christos break; 8238 1.1 christos case IPPROTO_UDP : 8239 1.1 christos nflags = IPN_UDP; 8240 1.1 christos break; 8241 1.1 christos default : 8242 1.1 christos nflags = 0; 8243 1.1 christos break; 8244 1.1 christos } 8245 1.1 christos 8246 1.1 christos WRITE_ENTER(&softc->ipf_nat); 8247 1.1 christos 8248 1.1 christos if (fin->fin_out == 0) { 8249 1.1 christos nat = ipf_nat_outlookup(fin, nflags, (u_int)fin->fin_p, 8250 1.1 christos fin->fin_dst, fin->fin_src); 8251 1.1 christos } else { 8252 1.1 christos nat = ipf_nat_inlookup(fin, nflags, (u_int)fin->fin_p, 8253 1.1 christos fin->fin_src, fin->fin_dst); 8254 1.1 christos } 8255 1.1 christos 8256 1.1 christos if (nat != NULL) { 8257 1.1 christos NBUMPSIDE(fin->fin_out, ns_uncreate[0]); 8258 1.1 christos ipf_nat_delete(softc, nat, NL_DESTROY); 8259 1.1 christos } else { 8260 1.1 christos NBUMPSIDE(fin->fin_out, ns_uncreate[1]); 8261 1.1 christos } 8262 1.1 christos 8263 1.1 christos RWLOCK_EXIT(&softc->ipf_nat); 8264 1.1 christos } 8265 1.2 christos 8266 1.2 christos 8267 1.2 christos /* ------------------------------------------------------------------------ */ 8268 1.2 christos /* Function: ipf_nat_cmp_rules */ 8269 1.2 christos /* Returns: int - 0 == success, else rules do not match. */ 8270 1.2 christos /* Parameters: n1(I) - first rule to compare */ 8271 1.2 christos /* n2(I) - first rule to compare */ 8272 1.2 christos /* */ 8273 1.2 christos /* Compare two rules using pointers to each rule. A straight bcmp will not */ 8274 1.2 christos /* work as some fields (such as in_dst, in_pkts) actually do change once */ 8275 1.2 christos /* the rule has been loaded into the kernel. Whilst this function returns */ 8276 1.2 christos /* various non-zero returns, they're strictly to aid in debugging. Use of */ 8277 1.2 christos /* this function should simply care if the result is zero or not. */ 8278 1.2 christos /* ------------------------------------------------------------------------ */ 8279 1.2 christos static int 8280 1.4 darrenr ipf_nat_cmp_rules(ipnat_t *n1, ipnat_t *n2) 8281 1.2 christos { 8282 1.2 christos if (n1->in_size != n2->in_size) 8283 1.2 christos return 1; 8284 1.2 christos 8285 1.2 christos if (bcmp((char *)&n1->in_v, (char *)&n2->in_v, 8286 1.2 christos offsetof(ipnat_t, in_ndst) - offsetof(ipnat_t, in_v)) != 0) 8287 1.2 christos return 2; 8288 1.2 christos 8289 1.2 christos if (bcmp((char *)&n1->in_tuc, (char *)&n2->in_tuc, 8290 1.3 darrenr n1->in_size - offsetof(ipnat_t, in_tuc)) != 0) 8291 1.2 christos return 3; 8292 1.2 christos if (n1->in_ndst.na_atype != n2->in_ndst.na_atype) 8293 1.2 christos return 5; 8294 1.2 christos if (n1->in_ndst.na_function != n2->in_ndst.na_function) 8295 1.2 christos return 6; 8296 1.2 christos if (bcmp((char *)&n1->in_ndst.na_addr, (char *)&n2->in_ndst.na_addr, 8297 1.2 christos sizeof(n1->in_ndst.na_addr))) 8298 1.2 christos return 7; 8299 1.2 christos if (n1->in_nsrc.na_atype != n2->in_nsrc.na_atype) 8300 1.2 christos return 8; 8301 1.2 christos if (n1->in_nsrc.na_function != n2->in_nsrc.na_function) 8302 1.2 christos return 9; 8303 1.2 christos if (bcmp((char *)&n1->in_nsrc.na_addr, (char *)&n2->in_nsrc.na_addr, 8304 1.2 christos sizeof(n1->in_nsrc.na_addr))) 8305 1.2 christos return 10; 8306 1.2 christos if (n1->in_odst.na_atype != n2->in_odst.na_atype) 8307 1.2 christos return 11; 8308 1.2 christos if (n1->in_odst.na_function != n2->in_odst.na_function) 8309 1.2 christos return 12; 8310 1.2 christos if (bcmp((char *)&n1->in_odst.na_addr, (char *)&n2->in_odst.na_addr, 8311 1.2 christos sizeof(n1->in_odst.na_addr))) 8312 1.2 christos return 13; 8313 1.2 christos if (n1->in_osrc.na_atype != n2->in_osrc.na_atype) 8314 1.2 christos return 14; 8315 1.2 christos if (n1->in_osrc.na_function != n2->in_osrc.na_function) 8316 1.2 christos return 15; 8317 1.2 christos if (bcmp((char *)&n1->in_osrc.na_addr, (char *)&n2->in_osrc.na_addr, 8318 1.2 christos sizeof(n1->in_osrc.na_addr))) 8319 1.2 christos return 16; 8320 1.2 christos return 0; 8321 1.2 christos } 8322 1.3 darrenr 8323 1.3 darrenr 8324 1.3 darrenr /* ------------------------------------------------------------------------ */ 8325 1.3 darrenr /* Function: ipf_nat_rule_init */ 8326 1.3 darrenr /* Returns: int - 0 == success, else rules do not match. */ 8327 1.3 darrenr /* Parameters: softc(I) - pointer to soft context main structure */ 8328 1.3 darrenr /* softn(I) - pointer to NAT context structure */ 8329 1.3 darrenr /* n(I) - first rule to compare */ 8330 1.3 darrenr /* */ 8331 1.3 darrenr /* ------------------------------------------------------------------------ */ 8332 1.3 darrenr static int 8333 1.3 darrenr ipf_nat_rule_init(ipf_main_softc_t *softc, ipf_nat_softc_t *softn, ipnat_t *n) 8334 1.3 darrenr { 8335 1.3 darrenr int error = 0; 8336 1.3 darrenr 8337 1.3 darrenr if ((n->in_flags & IPN_SIPRANGE) != 0) 8338 1.3 darrenr n->in_nsrcatype = FRI_RANGE; 8339 1.3 darrenr 8340 1.3 darrenr if ((n->in_flags & IPN_DIPRANGE) != 0) 8341 1.3 darrenr n->in_ndstatype = FRI_RANGE; 8342 1.3 darrenr 8343 1.3 darrenr if ((n->in_flags & IPN_SPLIT) != 0) 8344 1.3 darrenr n->in_ndstatype = FRI_SPLIT; 8345 1.3 darrenr 8346 1.3 darrenr if ((n->in_redir & (NAT_MAP|NAT_REWRITE|NAT_DIVERTUDP)) != 0) 8347 1.3 darrenr n->in_spnext = n->in_spmin; 8348 1.3 darrenr 8349 1.3 darrenr if ((n->in_redir & (NAT_REWRITE|NAT_DIVERTUDP)) != 0) { 8350 1.3 darrenr n->in_dpnext = n->in_dpmin; 8351 1.3 darrenr } else if (n->in_redir == NAT_REDIRECT) { 8352 1.3 darrenr n->in_dpnext = n->in_dpmin; 8353 1.3 darrenr } 8354 1.3 darrenr 8355 1.3 darrenr n->in_stepnext = 0; 8356 1.3 darrenr 8357 1.3 darrenr switch (n->in_v[0]) 8358 1.3 darrenr { 8359 1.3 darrenr case 4 : 8360 1.3 darrenr error = ipf_nat_ruleaddrinit(softc, softn, n); 8361 1.3 darrenr if (error != 0) 8362 1.3 darrenr return error; 8363 1.3 darrenr break; 8364 1.3 darrenr #ifdef USE_INET6 8365 1.3 darrenr case 6 : 8366 1.3 darrenr error = ipf_nat6_ruleaddrinit(softc, softn, n); 8367 1.3 darrenr if (error != 0) 8368 1.3 darrenr return error; 8369 1.3 darrenr break; 8370 1.3 darrenr #endif 8371 1.3 darrenr default : 8372 1.3 darrenr break; 8373 1.3 darrenr } 8374 1.3 darrenr 8375 1.3 darrenr if (n->in_redir == (NAT_DIVERTUDP|NAT_MAP)) { 8376 1.3 darrenr /* 8377 1.3 darrenr * Prerecord whether or not the destination of the divert 8378 1.3 darrenr * is local or not to the interface the packet is going 8379 1.3 darrenr * to be sent out. 8380 1.3 darrenr */ 8381 1.3 darrenr n->in_dlocal = ipf_deliverlocal(softc, n->in_v[1], 8382 1.3 darrenr n->in_ifps[1], &n->in_ndstip6); 8383 1.3 darrenr } 8384 1.3 darrenr 8385 1.3 darrenr return error; 8386 1.3 darrenr } 8387 1.3 darrenr 8388 1.3 darrenr 8389 1.3 darrenr /* ------------------------------------------------------------------------ */ 8390 1.3 darrenr /* Function: ipf_nat_rule_fini */ 8391 1.3 darrenr /* Returns: int - 0 == success, else rules do not match. */ 8392 1.3 darrenr /* Parameters: softc(I) - pointer to soft context main structure */ 8393 1.3 darrenr /* n(I) - rule to work on */ 8394 1.3 darrenr /* */ 8395 1.3 darrenr /* This function is used to release any objects that were referenced during */ 8396 1.3 darrenr /* the rule initialisation. This is useful both when free'ing the rule and */ 8397 1.3 darrenr /* when handling ioctls that need to initialise these fields but not */ 8398 1.3 darrenr /* actually use them after the ioctl processing has finished. */ 8399 1.3 darrenr /* ------------------------------------------------------------------------ */ 8400 1.3 darrenr static void 8401 1.3 darrenr ipf_nat_rule_fini(ipf_main_softc_t *softc, ipnat_t *n) 8402 1.3 darrenr { 8403 1.3 darrenr if (n->in_odst.na_atype == FRI_LOOKUP && n->in_odst.na_ptr != NULL) 8404 1.3 darrenr ipf_lookup_deref(softc, n->in_odst.na_type, n->in_odst.na_ptr); 8405 1.3 darrenr 8406 1.3 darrenr if (n->in_osrc.na_atype == FRI_LOOKUP && n->in_osrc.na_ptr != NULL) 8407 1.3 darrenr ipf_lookup_deref(softc, n->in_osrc.na_type, n->in_osrc.na_ptr); 8408 1.3 darrenr 8409 1.3 darrenr if (n->in_ndst.na_atype == FRI_LOOKUP && n->in_ndst.na_ptr != NULL) 8410 1.3 darrenr ipf_lookup_deref(softc, n->in_ndst.na_type, n->in_ndst.na_ptr); 8411 1.3 darrenr 8412 1.3 darrenr if (n->in_nsrc.na_atype == FRI_LOOKUP && n->in_nsrc.na_ptr != NULL) 8413 1.3 darrenr ipf_lookup_deref(softc, n->in_nsrc.na_type, n->in_nsrc.na_ptr); 8414 1.3 darrenr 8415 1.3 darrenr if (n->in_divmp != NULL) 8416 1.3 darrenr FREE_MB_T(n->in_divmp); 8417 1.3 darrenr } 8418