From owner-svn-src-vendor@FreeBSD.ORG Fri Aug 16 07:03:29 2013 Return-Path: Delivered-To: svn-src-vendor@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) (using TLSv1 with cipher ADH-AES256-SHA (256/256 bits)) (No client certificate requested) by hub.freebsd.org (Postfix) with ESMTP id 52A59422; Fri, 16 Aug 2013 07:03:29 +0000 (UTC) (envelope-from cy@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:1900:2254:2068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mx1.freebsd.org (Postfix) with ESMTPS id 3EB2C2462; Fri, 16 Aug 2013 07:03:29 +0000 (UTC) Received: from svn.freebsd.org ([127.0.1.70]) by svn.freebsd.org (8.14.7/8.14.7) with ESMTP id r7G73TvE040727; Fri, 16 Aug 2013 07:03:29 GMT (envelope-from cy@svn.freebsd.org) Received: (from cy@localhost) by svn.freebsd.org (8.14.7/8.14.5/Submit) id r7G73Tvb040724; Fri, 16 Aug 2013 07:03:29 GMT (envelope-from cy@svn.freebsd.org) Message-Id: <201308160703.r7G73Tvb040724@svn.freebsd.org> From: Cy Schubert Date: Fri, 16 Aug 2013 07:03:28 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-vendor@freebsd.org Subject: svn commit: r254401 - vendor-sys/ipfilter/dist/netinet X-SVN-Group: vendor-sys MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-vendor@freebsd.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: SVN commit messages for the vendor work area tree List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 16 Aug 2013 07:03:29 -0000 Author: cy Date: Fri Aug 16 07:03:28 2013 New Revision: 254401 URL: http://svnweb.freebsd.org/changeset/base/254401 Log: Include three new files that should be in vendor-sys branch too. Approved by: glebius (Mentor) Added: vendor-sys/ipfilter/dist/netinet/ip_dns_pxy.c vendor-sys/ipfilter/dist/netinet/ip_nat6.c vendor-sys/ipfilter/dist/netinet/ip_tftp_pxy.c Added: vendor-sys/ipfilter/dist/netinet/ip_dns_pxy.c ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ vendor-sys/ipfilter/dist/netinet/ip_dns_pxy.c Fri Aug 16 07:03:28 2013 (r254401) @@ -0,0 +1,402 @@ +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * $Id: ip_dns_pxy.c,v 1.1.2.10 2012/07/22 08:04:23 darren_r Exp $ + */ + +#define IPF_DNS_PROXY + +/* + * map ... proxy port dns/udp 53 { block .cnn.com; } + */ +typedef struct ipf_dns_filter { + struct ipf_dns_filter *idns_next; + char *idns_name; + int idns_namelen; + int idns_pass; +} ipf_dns_filter_t; + + +typedef struct ipf_dns_softc_s { + ipf_dns_filter_t *ipf_p_dns_list; + ipfrwlock_t ipf_p_dns_rwlock; + u_long ipf_p_dns_compress; + u_long ipf_p_dns_toolong; + u_long ipf_p_dns_nospace; +} ipf_dns_softc_t; + +int ipf_p_dns_allow_query __P((ipf_dns_softc_t *, dnsinfo_t *)); +int ipf_p_dns_ctl __P((ipf_main_softc_t *, void *, ap_ctl_t *)); +int ipf_p_dns_del __P((ipf_main_softc_t *, ap_session_t *)); +int ipf_p_dns_get_name __P((ipf_dns_softc_t *, char *, int, char *, int)); +int ipf_p_dns_inout __P((void *, fr_info_t *, ap_session_t *, nat_t *)); +int ipf_p_dns_match __P((fr_info_t *, ap_session_t *, nat_t *)); +int ipf_p_dns_match_names __P((ipf_dns_filter_t *, char *, int)); +int ipf_p_dns_new __P((void *, fr_info_t *, ap_session_t *, nat_t *)); +void *ipf_p_dns_soft_create __P((ipf_main_softc_t *)); +void ipf_p_dns_soft_destroy __P((ipf_main_softc_t *, void *)); + +typedef struct { + u_char dns_id[2]; + u_short dns_ctlword; + u_short dns_qdcount; + u_short dns_ancount; + u_short dns_nscount; + u_short dns_arcount; +} ipf_dns_hdr_t; + +#define DNS_QR(x) ((ntohs(x) & 0x8000) >> 15) +#define DNS_OPCODE(x) ((ntohs(x) & 0x7800) >> 11) +#define DNS_AA(x) ((ntohs(x) & 0x0400) >> 10) +#define DNS_TC(x) ((ntohs(x) & 0x0200) >> 9) +#define DNS_RD(x) ((ntohs(x) & 0x0100) >> 8) +#define DNS_RA(x) ((ntohs(x) & 0x0080) >> 7) +#define DNS_Z(x) ((ntohs(x) & 0x0070) >> 4) +#define DNS_RCODE(x) ((ntohs(x) & 0x000f) >> 0) + + +void * +ipf_p_dns_soft_create(softc) + ipf_main_softc_t *softc; +{ + ipf_dns_softc_t *softd; + + KMALLOC(softd, ipf_dns_softc_t *); + if (softd == NULL) + return NULL; + + bzero((char *)softd, sizeof(*softd)); + RWLOCK_INIT(&softd->ipf_p_dns_rwlock, "ipf dns rwlock"); + + return softd; +} + + +void +ipf_p_dns_soft_destroy(softc, arg) + ipf_main_softc_t *softc; + void *arg; +{ + ipf_dns_softc_t *softd = arg; + ipf_dns_filter_t *idns; + + while ((idns = softd->ipf_p_dns_list) != NULL) { + KFREES(idns->idns_name, idns->idns_namelen); + idns->idns_name = NULL; + idns->idns_namelen = 0; + softd->ipf_p_dns_list = idns->idns_next; + KFREE(idns); + } + RW_DESTROY(&softd->ipf_p_dns_rwlock); + + KFREE(softd); +} + + +int +ipf_p_dns_ctl(softc, arg, ctl) + ipf_main_softc_t *softc; + void *arg; + ap_ctl_t *ctl; +{ + ipf_dns_softc_t *softd = arg; + ipf_dns_filter_t *tmp, *idns, **idnsp; + int error = 0; + + /* + * To make locking easier. + */ + KMALLOC(tmp, ipf_dns_filter_t *); + + WRITE_ENTER(&softd->ipf_p_dns_rwlock); + for (idnsp = &softd->ipf_p_dns_list; (idns = *idnsp) != NULL; + idnsp = &idns->idns_next) { + if (idns->idns_namelen != ctl->apc_dsize) + continue; + if (!strncmp(ctl->apc_data, idns->idns_name, + idns->idns_namelen)) + break; + } + + switch (ctl->apc_cmd) + { + case APC_CMD_DEL : + if (idns == NULL) { + IPFERROR(80006); + error = ESRCH; + break; + } + *idnsp = idns->idns_next; + idns->idns_next = NULL; + KFREES(idns->idns_name, idns->idns_namelen); + idns->idns_name = NULL; + idns->idns_namelen = 0; + KFREE(idns); + break; + case APC_CMD_ADD : + if (idns != NULL) { + IPFERROR(80007); + error = EEXIST; + break; + } + if (tmp == NULL) { + IPFERROR(80008); + error = ENOMEM; + break; + } + idns = tmp; + tmp = NULL; + idns->idns_namelen = ctl->apc_dsize; + idns->idns_name = ctl->apc_data; + idns->idns_pass = ctl->apc_arg; + idns->idns_next = NULL; + *idnsp = idns; + ctl->apc_data = NULL; + ctl->apc_dsize = 0; + break; + default : + IPFERROR(80009); + error = EINVAL; + break; + } + RWLOCK_EXIT(&softd->ipf_p_dns_rwlock); + + if (tmp != NULL) { + KFREE(tmp); + tmp = NULL; + } + + return error; +} + + +/* ARGSUSED */ +int +ipf_p_dns_new(arg, fin, aps, nat) + void *arg; + fr_info_t *fin; + ap_session_t *aps; + nat_t *nat; +{ + dnsinfo_t *di; + int dlen; + + if (fin->fin_v != 4) + return -1; + + dlen = fin->fin_dlen - sizeof(udphdr_t); + if (dlen < sizeof(ipf_dns_hdr_t)) { + /* + * No real DNS packet is smaller than that. + */ + return -1; + } + + aps->aps_psiz = sizeof(dnsinfo_t); + KMALLOCS(di, dnsinfo_t *, sizeof(dnsinfo_t)); + if (di == NULL) { + printf("ipf_dns_new:KMALLOCS(%d) failed\n", sizeof(*di)); + return -1; + } + + MUTEX_INIT(&di->dnsi_lock, "dns lock"); + + aps->aps_data = di; + + dlen = fin->fin_dlen - sizeof(udphdr_t); + COPYDATA(fin->fin_m, fin->fin_hlen + sizeof(udphdr_t), + MIN(dlen, sizeof(di->dnsi_buffer)), di->dnsi_buffer); + di->dnsi_id = (di->dnsi_buffer[0] << 8) | di->dnsi_buffer[1]; + return 0; +} + + +/* ARGSUSED */ +int +ipf_p_dns_del(softc, aps) + ipf_main_softc_t *softc; + ap_session_t *aps; +{ +#ifdef USE_MUTEXES + dnsinfo_t *di = aps->aps_data; + + MUTEX_DESTROY(&di->dnsi_lock); +#endif + KFREES(aps->aps_data, aps->aps_psiz); + aps->aps_data = NULL; + aps->aps_psiz = 0; + return 0; +} + + +/* + * Tries to match the base string (in our ACL) with the query from a packet. + */ +int +ipf_p_dns_match_names(idns, query, qlen) + ipf_dns_filter_t *idns; + char *query; + int qlen; +{ + int blen; + char *base; + + blen = idns->idns_namelen; + base = idns->idns_name; + + if (blen > qlen) + return 1; + + if (blen == qlen) + return strncasecmp(base, query, qlen); + + /* + * If the base string string is shorter than the query, allow the + * tail of the base to match the same length tail of the query *if*: + * - the base string starts with a '*' (*cnn.com) + * - the base string represents a domain (.cnn.com) + * as otherwise it would not be possible to block just "cnn.com" + * without also impacting "foocnn.com", etc. + */ + if (*base == '*') { + base++; + blen--; + } else if (*base != '.') + return 1; + + return strncasecmp(base, query + qlen - blen, blen); +} + + +int +ipf_p_dns_get_name(softd, start, len, buffer, buflen) + ipf_dns_softc_t *softd; + char *start; + int len; + char *buffer; + int buflen; +{ + char *s, *t, clen; + int slen, blen; + + s = start; + t = buffer; + slen = len; + blen = buflen - 1; /* Always make room for trailing \0 */ + + while (*s != '\0') { + clen = *s; + if ((clen & 0xc0) == 0xc0) { /* Doesn't do compression */ + softd->ipf_p_dns_compress++; + return 0; + } + if (clen > slen) { + softd->ipf_p_dns_toolong++; + return 0; /* Does the name run off the end? */ + } + if ((clen + 1) > blen) { + softd->ipf_p_dns_nospace++; + return 0; /* Enough room for name+.? */ + } + s++; + bcopy(s, t, clen); + t += clen; + s += clen; + *t++ = '.'; + slen -= clen; + blen -= (clen + 1); + } + + *(t - 1) = '\0'; + return s - start; +} + + +int +ipf_p_dns_allow_query(softd, dnsi) + ipf_dns_softc_t *softd; + dnsinfo_t *dnsi; +{ + ipf_dns_filter_t *idns; + int len; + + len = strlen(dnsi->dnsi_buffer); + + for (idns = softd->ipf_p_dns_list; idns != NULL; idns = idns->idns_next) + if (ipf_p_dns_match_names(idns, dnsi->dnsi_buffer, len) == 0) + return idns->idns_pass; + return 0; +} + + +/* ARGSUSED */ +int +ipf_p_dns_inout(arg, fin, aps, nat) + void *arg; + fr_info_t *fin; + ap_session_t *aps; + nat_t *nat; +{ + ipf_dns_softc_t *softd = arg; + ipf_dns_hdr_t *dns; + dnsinfo_t *di; + char *data; + int dlen, q, rc = 0; + + if (fin->fin_dlen < sizeof(*dns)) + return APR_ERR(1); + + dns = (ipf_dns_hdr_t *)((char *)fin->fin_dp + sizeof(udphdr_t)); + + q = dns->dns_qdcount; + + data = (char *)(dns + 1); + dlen = fin->fin_dlen - sizeof(*dns) - sizeof(udphdr_t); + + di = aps->aps_data; + + READ_ENTER(&softd->ipf_p_dns_rwlock); + MUTEX_ENTER(&di->dnsi_lock); + + for (; (dlen > 0) && (q > 0); q--) { + int len; + + len = ipf_p_dns_get_name(softd, data, dlen, di->dnsi_buffer, + sizeof(di->dnsi_buffer)); + if (len == 0) { + rc = 1; + break; + } + rc = ipf_p_dns_allow_query(softd, di); + if (rc != 0) + break; + data += len; + dlen -= len; + } + MUTEX_EXIT(&di->dnsi_lock); + RWLOCK_EXIT(&softd->ipf_p_dns_rwlock); + + return APR_ERR(rc); +} + + +/* ARGSUSED */ +int +ipf_p_dns_match(fin, aps, nat) + fr_info_t *fin; + ap_session_t *aps; + nat_t *nat; +{ + dnsinfo_t *di = aps->aps_data; + ipf_dns_hdr_t *dnh; + + if ((fin->fin_dlen < sizeof(u_short)) || (fin->fin_flx & FI_FRAG)) + return -1; + + dnh = (ipf_dns_hdr_t *)((char *)fin->fin_dp + sizeof(udphdr_t)); + if (((dnh->dns_id[0] << 8) | dnh->dns_id[1]) != di->dnsi_id) + return -1; + return 0; +} Added: vendor-sys/ipfilter/dist/netinet/ip_nat6.c ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ vendor-sys/ipfilter/dist/netinet/ip_nat6.c Fri Aug 16 07:03:28 2013 (r254401) @@ -0,0 +1,4098 @@ +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + */ +#if defined(KERNEL) || defined(_KERNEL) +# undef KERNEL +# undef ipf_nat6_KERNEL +# define KERNEL 1 +# define ipf_nat6_KERNEL 1 +#endif +#include +#include +#include +#include +#include +#if defined(_KERNEL) && defined(__NetBSD_Version__) && \ + (__NetBSD_Version__ >= 399002000) +# include +#endif +#if !defined(_KERNEL) +# include +# include +# include +# define ipf_nat6_KERNEL +# ifdef ipf_nat6__OpenBSD__ +struct file; +# endif +# include +# undef ipf_nat6_KERNEL +#endif +#if defined(_KERNEL) && (__FreeBSD_version >= 220000) +# include +# include +#else +# include +#endif +#if !defined(AIX) +# include +#endif +#if !defined(linux) +# include +#endif +#include +#if defined(_KERNEL) +# include +# if !defined(__SVR4) && !defined(__svr4__) +# include +# endif +#endif +#if defined(__SVR4) || defined(__svr4__) +# include +# include +# ifdef ipf_nat6_KERNEL +# include +# endif +# include +# include +#endif +#if ipf_nat6__FreeBSD_version >= 300000 +# include +#endif +#include +#if ipf_nat6__FreeBSD_version >= 300000 +# include +#endif +#ifdef sun +# include +#endif +#include +#include +#include +#include + +#ifdef RFC1825 +# include +# include +extern struct ifnet vpnif; +#endif + +#if !defined(linux) +# include +#endif +#include +#include +#include +#include "netinet/ip_compat.h" +#include +#include "netinet/ip_fil.h" +#include "netinet/ip_nat.h" +#include "netinet/ip_frag.h" +#include "netinet/ip_state.h" +#include "netinet/ip_proxy.h" +#include "netinet/ip_lookup.h" +#include "netinet/ip_dstlist.h" +#include "netinet/ip_sync.h" +#if (__FreeBSD_version >= 300000) +# include +#endif +#ifdef HAS_SYS_MD5_H +# include +#else +# include "md5.h" +#endif +/* END OF INCLUDES */ + +#undef SOCKADDR_IN +#define SOCKADDR_IN struct sockaddr_in + +#if !defined(lint) +static const char rcsid[] = "@(#)$Id: ip_nat6.c,v 1.22.2.20 2012/07/22 08:04:23 darren_r Exp $"; +#endif + +#ifdef USE_INET6 +static struct hostmap *ipf_nat6_hostmap __P((ipf_nat_softc_t *, ipnat_t *, + i6addr_t *, i6addr_t *, + i6addr_t *, u_32_t)); +static int ipf_nat6_match __P((fr_info_t *, ipnat_t *)); +static void ipf_nat6_tabmove __P((ipf_nat_softc_t *, nat_t *)); +static int ipf_nat6_decap __P((fr_info_t *, nat_t *)); +static int ipf_nat6_nextaddr __P((fr_info_t *, nat_addr_t *, i6addr_t *, + i6addr_t *)); +static int ipf_nat6_icmpquerytype __P((int)); +static int ipf_nat6_out __P((fr_info_t *, nat_t *, int, u_32_t)); +static int ipf_nat6_in __P((fr_info_t *, nat_t *, int, u_32_t)); +static int ipf_nat6_builddivertmp __P((ipf_nat_softc_t *, ipnat_t *)); +static int ipf_nat6_nextaddrinit __P((ipf_main_softc_t *, char *, + nat_addr_t *, int, void *)); +static int ipf_nat6_insert __P((ipf_main_softc_t *, ipf_nat_softc_t *, + nat_t *)); + + +#define NINCLSIDE6(y,x) ATOMIC_INCL(softn->ipf_nat_stats.ns_side6[y].x) +#define NBUMPSIDE(y,x) softn->ipf_nat_stats.ns_side[y].x++ +#define NBUMPSIDE6(y,x) softn->ipf_nat_stats.ns_side6[y].x++ +#define NBUMPSIDE6D(y,x) \ + do { \ + softn->ipf_nat_stats.ns_side6[y].x++; \ + DT(x); \ + } while (0) +#define NBUMPSIDE6DX(y,x,z) \ + do { \ + softn->ipf_nat_stats.ns_side6[y].x++; \ + DT(z); \ + } while (0) + + +/* ------------------------------------------------------------------------ */ +/* Function: ipf_nat6_ruleaddrinit */ +/* Returns: int - 0 == success, else failure */ +/* Parameters: in(I) - NAT rule that requires address fields to be init'd */ +/* */ +/* For each of the source/destination address fields in a NAT rule, call */ +/* ipf_nat6_nextaddrinit() to prepare the structure for active duty. Other */ +/* IPv6 specific actions can also be taken care of here. */ +/* ------------------------------------------------------------------------ */ +int +ipf_nat6_ruleaddrinit(softc, softn, n) + ipf_main_softc_t *softc; + ipf_nat_softc_t *softn; + ipnat_t *n; +{ + int idx, error; + + if (n->in_redir == NAT_BIMAP) { + n->in_ndstip6 = n->in_osrcip6; + n->in_ndstmsk6 = n->in_osrcmsk6; + n->in_odstip6 = n->in_nsrcip6; + n->in_odstmsk6 = n->in_nsrcmsk6; + + } + + if (n->in_redir & NAT_REDIRECT) + idx = 1; + else + idx = 0; + /* + * Initialise all of the address fields. + */ + error = ipf_nat6_nextaddrinit(softc, n->in_names, &n->in_osrc, 1, + n->in_ifps[idx]); + if (error != 0) + return error; + + error = ipf_nat6_nextaddrinit(softc, n->in_names, &n->in_odst, 1, + n->in_ifps[idx]); + if (error != 0) + return error; + + error = ipf_nat6_nextaddrinit(softc, n->in_names, &n->in_nsrc, 1, + n->in_ifps[idx]); + if (error != 0) + return error; + + error = ipf_nat6_nextaddrinit(softc, n->in_names, &n->in_ndst, 1, + n->in_ifps[idx]); + if (error != 0) + return error; + + if (n->in_redir & NAT_DIVERTUDP) + ipf_nat6_builddivertmp(softn, n); + return 0; +} + + +/* ------------------------------------------------------------------------ */ +/* Function: ipf_nat6_addrdr */ +/* Returns: Nil */ +/* Parameters: n(I) - pointer to NAT rule to add */ +/* */ +/* Adds a redirect rule to the hash table of redirect rules and the list of */ +/* loaded NAT rules. Updates the bitmask indicating which netmasks are in */ +/* use by redirect rules. */ +/* ------------------------------------------------------------------------ */ +void +ipf_nat6_addrdr(softn, n) + ipf_nat_softc_t *softn; + ipnat_t *n; +{ + i6addr_t *mask; + ipnat_t **np; + i6addr_t j; + u_int hv; + int k; + + if ((n->in_redir & NAT_BIMAP) == NAT_BIMAP) { + k = count6bits(n->in_nsrcmsk6.i6); + mask = &n->in_nsrcmsk6; + IP6_AND(&n->in_odstip6, &n->in_odstmsk6, &j); + hv = NAT_HASH_FN6(&j, 0, softn->ipf_nat_rdrrules_sz); + + } else if (n->in_odstatype == FRI_NORMAL) { + k = count6bits(n->in_odstmsk6.i6); + mask = &n->in_odstmsk6; + IP6_AND(&n->in_odstip6, &n->in_odstmsk6, &j); + hv = NAT_HASH_FN6(&j, 0, softn->ipf_nat_rdrrules_sz); + } else { + k = 0; + hv = 0; + mask = NULL; + } + ipf_inet6_mask_add(k, mask, &softn->ipf_nat6_rdr_mask); + + np = softn->ipf_nat_rdr_rules + hv; + while (*np != NULL) + np = &(*np)->in_rnext; + n->in_rnext = NULL; + n->in_prnext = np; + n->in_hv[0] = hv; + n->in_use++; + *np = n; +} + + +/* ------------------------------------------------------------------------ */ +/* Function: ipf_nat6_addmap */ +/* Returns: Nil */ +/* Parameters: n(I) - pointer to NAT rule to add */ +/* */ +/* Adds a NAT map rule to the hash table of rules and the list of loaded */ +/* NAT rules. Updates the bitmask indicating which netmasks are in use by */ +/* redirect rules. */ +/* ------------------------------------------------------------------------ */ +void +ipf_nat6_addmap(softn, n) + ipf_nat_softc_t *softn; + ipnat_t *n; +{ + i6addr_t *mask; + ipnat_t **np; + i6addr_t j; + u_int hv; + int k; + + if (n->in_osrcatype == FRI_NORMAL) { + k = count6bits(n->in_osrcmsk6.i6); + mask = &n->in_osrcmsk6; + IP6_AND(&n->in_osrcip6, &n->in_osrcmsk6, &j); + hv = NAT_HASH_FN6(&j, 0, softn->ipf_nat_maprules_sz); + } else { + k = 0; + hv = 0; + mask = NULL; + } + ipf_inet6_mask_add(k, mask, &softn->ipf_nat6_map_mask); + + np = softn->ipf_nat_map_rules + hv; + while (*np != NULL) + np = &(*np)->in_mnext; + n->in_mnext = NULL; + n->in_pmnext = np; + n->in_hv[1] = hv; + n->in_use++; + *np = n; +} + + +/* ------------------------------------------------------------------------ */ +/* Function: ipf_nat6_del_rdr */ +/* Returns: Nil */ +/* Parameters: n(I) - pointer to NAT rule to delete */ +/* */ +/* Removes a NAT rdr rule from the hash table of NAT rdr rules. */ +/* ------------------------------------------------------------------------ */ +void +ipf_nat6_delrdr(softn, n) + ipf_nat_softc_t *softn; + ipnat_t *n; +{ + i6addr_t *mask; + int k; + + if ((n->in_redir & NAT_BIMAP) == NAT_BIMAP) { + k = count6bits(n->in_nsrcmsk6.i6); + mask = &n->in_nsrcmsk6; + } else if (n->in_odstatype == FRI_NORMAL) { + k = count6bits(n->in_odstmsk6.i6); + mask = &n->in_odstmsk6; + } else { + k = 0; + mask = NULL; + } + ipf_inet6_mask_del(k, mask, &softn->ipf_nat6_rdr_mask); + + if (n->in_rnext != NULL) + n->in_rnext->in_prnext = n->in_prnext; + *n->in_prnext = n->in_rnext; + n->in_use--; +} + + +/* ------------------------------------------------------------------------ */ +/* Function: ipf_nat6_delmap */ +/* Returns: Nil */ +/* Parameters: n(I) - pointer to NAT rule to delete */ +/* */ +/* Removes a NAT map rule from the hash table of NAT map rules. */ +/* ------------------------------------------------------------------------ */ +void +ipf_nat6_delmap(softn, n) + ipf_nat_softc_t *softn; + ipnat_t *n; +{ + i6addr_t *mask; + int k; + + if (n->in_osrcatype == FRI_NORMAL) { + k = count6bits(n->in_osrcmsk6.i6); + mask = &n->in_osrcmsk6; + } else { + k = 0; + mask = NULL; + } + ipf_inet6_mask_del(k, mask, &softn->ipf_nat6_map_mask); + + if (n->in_mnext != NULL) + n->in_mnext->in_pmnext = n->in_pmnext; + *n->in_pmnext = n->in_mnext; + n->in_use--; +} + + +/* ------------------------------------------------------------------------ */ +/* Function: ipf_nat6_hostmap */ +/* Returns: struct hostmap* - NULL if no hostmap could be created, */ +/* else a pointer to the hostmapping to use */ +/* Parameters: np(I) - pointer to NAT rule */ +/* real(I) - real IP address */ +/* map(I) - mapped IP address */ +/* port(I) - destination port number */ +/* Write Locks: ipf_nat */ +/* */ +/* Check if an ip address has already been allocated for a given mapping */ +/* that is not doing port based translation. If is not yet allocated, then */ +/* create a new entry if a non-NULL NAT rule pointer has been supplied. */ +/* ------------------------------------------------------------------------ */ +static struct hostmap * +ipf_nat6_hostmap(softn, np, src, dst, map, port) + ipf_nat_softc_t *softn; + ipnat_t *np; + i6addr_t *src, *dst, *map; + u_32_t port; +{ + hostmap_t *hm; + u_int hv; + + hv = (src->i6[3] ^ dst->i6[3]); + hv += (src->i6[2] ^ dst->i6[2]); + hv += (src->i6[1] ^ dst->i6[1]); + hv += (src->i6[0] ^ dst->i6[0]); + hv += src->i6[3]; + hv += src->i6[2]; + hv += src->i6[1]; + hv += src->i6[0]; + hv += dst->i6[3]; + hv += dst->i6[2]; + hv += dst->i6[1]; + hv += dst->i6[0]; + hv %= HOSTMAP_SIZE; + for (hm = softn->ipf_hm_maptable[hv]; hm; hm = hm->hm_next) + if (IP6_EQ(&hm->hm_osrc6, src) && + IP6_EQ(&hm->hm_odst6, dst) && + ((np == NULL) || (np == hm->hm_ipnat)) && + ((port == 0) || (port == hm->hm_port))) { + softn->ipf_nat_stats.ns_hm_addref++; + hm->hm_ref++; + return hm; + } + + if (np == NULL) { + softn->ipf_nat_stats.ns_hm_nullnp++; + return NULL; + } + + KMALLOC(hm, hostmap_t *); + if (hm) { + hm->hm_next = softn->ipf_hm_maplist; + hm->hm_pnext = &softn->ipf_hm_maplist; + if (softn->ipf_hm_maplist != NULL) + softn->ipf_hm_maplist->hm_pnext = &hm->hm_next; + softn->ipf_hm_maplist = hm; + hm->hm_hnext = softn->ipf_hm_maptable[hv]; + hm->hm_phnext = softn->ipf_hm_maptable + hv; + if (softn->ipf_hm_maptable[hv] != NULL) + softn->ipf_hm_maptable[hv]->hm_phnext = &hm->hm_hnext; + softn->ipf_hm_maptable[hv] = hm; + hm->hm_ipnat = np; + np->in_use++; + hm->hm_osrcip6 = *src; + hm->hm_odstip6 = *dst; + hm->hm_nsrcip6 = *map; + hm->hm_ndstip6.i6[0] = 0; + hm->hm_ndstip6.i6[1] = 0; + hm->hm_ndstip6.i6[2] = 0; + hm->hm_ndstip6.i6[3] = 0; + hm->hm_ref = 1; + hm->hm_port = port; + hm->hm_hv = hv; + hm->hm_v = 6; + softn->ipf_nat_stats.ns_hm_new++; + } else { + softn->ipf_nat_stats.ns_hm_newfail++; + } + return hm; +} + + +/* ------------------------------------------------------------------------ */ +/* Function: ipf_nat6_newmap */ +/* Returns: int - -1 == error, 0 == success */ +/* Parameters: fin(I) - pointer to packet information */ +/* nat(I) - pointer to NAT entry */ +/* ni(I) - pointer to structure with misc. information needed */ +/* to create new NAT entry. */ +/* */ +/* Given an empty NAT structure, populate it with new information about a */ +/* new NAT session, as defined by the matching NAT rule. */ +/* ni.nai_ip is passed in uninitialised and must be set, in host byte order,*/ +/* to the new IP address for the translation. */ +/* ------------------------------------------------------------------------ */ +int +ipf_nat6_newmap(fin, nat, ni) + fr_info_t *fin; + nat_t *nat; + natinfo_t *ni; +{ + ipf_main_softc_t *softc = fin->fin_main_soft; + ipf_nat_softc_t *softn = softc->ipf_nat_soft; + u_short st_port, dport, sport, port, sp, dp; + i6addr_t in, st_ip; + hostmap_t *hm; + u_32_t flags; + ipnat_t *np; + nat_t *natl; + int l; + + /* + * If it's an outbound packet which doesn't match any existing + * record, then create a new port + */ + l = 0; + hm = NULL; + np = ni->nai_np; + st_ip = np->in_snip6; + st_port = np->in_spnext; + flags = nat->nat_flags; + + if (flags & IPN_ICMPQUERY) { + sport = fin->fin_data[1]; + dport = 0; + } else { + sport = htons(fin->fin_data[0]); + dport = htons(fin->fin_data[1]); + } + + /* + * Do a loop until we either run out of entries to try or we find + * a NAT mapping that isn't currently being used. This is done + * because the change to the source is not (usually) being fixed. + */ + do { + port = 0; + in = np->in_nsrc.na_nextaddr; + if (l == 0) { + /* + * Check to see if there is an existing NAT + * setup for this IP address pair. + */ + hm = ipf_nat6_hostmap(softn, np, &fin->fin_src6, + &fin->fin_dst6, &in, 0); + if (hm != NULL) + in = hm->hm_nsrcip6; + } else if ((l == 1) && (hm != NULL)) { + ipf_nat_hostmapdel(softc, &hm); + } + + nat->nat_hm = hm; + + if (IP6_ISONES(&np->in_nsrcmsk6) && (np->in_spnext == 0)) { + if (l > 0) { + NBUMPSIDE6DX(1, ns_exhausted, ns_exhausted_1); + return -1; + } + } + + if ((np->in_redir == NAT_BIMAP) && + IP6_EQ(&np->in_osrcmsk6, &np->in_nsrcmsk6)) { + i6addr_t temp; + /* + * map the address block in a 1:1 fashion + */ + temp.i6[0] = fin->fin_src6.i6[0] & + ~np->in_osrcmsk6.i6[0]; + temp.i6[1] = fin->fin_src6.i6[1] & + ~np->in_osrcmsk6.i6[1]; + temp.i6[2] = fin->fin_src6.i6[2] & + ~np->in_osrcmsk6.i6[0]; + temp.i6[3] = fin->fin_src6.i6[3] & + ~np->in_osrcmsk6.i6[3]; + in = np->in_nsrcip6; + IP6_MERGE(&in, &temp, &np->in_osrc); + +#ifdef NEED_128BIT_MATH + } else if (np->in_redir & NAT_MAPBLK) { + if ((l >= np->in_ppip) || ((l > 0) && + !(flags & IPN_TCPUDP))) { + NBUMPSIDE6DX(1, ns_exhausted, ns_exhausted_2); + return -1; + } + /* + * map-block - Calculate destination address. + */ + IP6_MASK(&in, &fin->fin_src6, &np->in_osrcmsk6); + in = ntohl(in); + inb = in; + in.s_addr /= np->in_ippip; + in.s_addr &= ntohl(~np->in_nsrcmsk6); + in.s_addr += ntohl(np->in_nsrcaddr6); + /* + * Calculate destination port. + */ + if ((flags & IPN_TCPUDP) && + (np->in_ppip != 0)) { + port = ntohs(sport) + l; + port %= np->in_ppip; + port += np->in_ppip * + (inb.s_addr % np->in_ippip); + port += MAPBLK_MINPORT; + port = htons(port); + } +#endif + + } else if (IP6_ISZERO(&np->in_nsrcaddr) && + IP6_ISONES(&np->in_nsrcmsk)) { + /* + * 0/32 - use the interface's IP address. + */ + if ((l > 0) || + ipf_ifpaddr(softc, 6, FRI_NORMAL, fin->fin_ifp, + &in, NULL) == -1) { + NBUMPSIDE6DX(1, ns_new_ifpaddr, + ns_new_ifpaddr_1); + return -1; + } + + } else if (IP6_ISZERO(&np->in_nsrcip6) && + IP6_ISZERO(&np->in_nsrcmsk6)) { + /* + * 0/0 - use the original source address/port. + */ + if (l > 0) { + NBUMPSIDE6DX(1, ns_exhausted, ns_exhausted_3); *** DIFF OUTPUT TRUNCATED AT 1000 LINES ***