ip_nat6.c revision ab073b324433ebc8947d28ade932d29d0e809795
/*
* Copyright (C) 1995-2003 by Darren Reed.
*
* See the IPFILTER.LICENCE file for details on licencing.
*
* Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"$
# define KERNEL 1
# define _KERNEL 1
#endif
defined(_KERNEL)
# include "opt_ipfilter_log.h"
#endif
#if !defined(_KERNEL)
# include <stdio.h>
# include <string.h>
# include <stdlib.h>
# define _KERNEL
# ifdef __OpenBSD__
struct file;
# endif
#endif
#else
#endif
#if !defined(AIX)
#endif
#if !defined(linux)
#endif
#if defined(_KERNEL)
# endif
#endif
# include <sys/byteorder.h>
# ifdef _KERNEL
# include <sys/dditypes.h>
# endif
#endif
#if __FreeBSD_version >= 300000
#endif
#if __FreeBSD_version >= 300000
# if defined(_KERNEL) && !defined(IPFILTER_LKM)
# include "opt_ipfilter.h"
# endif
#endif
#ifdef sun
#endif
#include <netinet/in_systm.h>
#ifdef RFC1825
#endif
#if !defined(linux)
#endif
#include "netinet/ip_compat.h"
#include "netinet/ip_state.h"
#include "netinet/ip_proxy.h"
#include "netinet/ipf_stack.h"
#ifdef IPFILTER_SYNC
#endif
#if (__FreeBSD_version >= 300000)
#endif
/* END OF INCLUDES */
#define SOCKADDR_IN struct sockaddr_in
#if !defined(lint)
#endif
/* ------------------------------------------------------------------------ */
/* Function: 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 nat6_addrdr(n, ifs)
ipnat_t *n;
{
i6addr_t j;
int k;
if ((k >= 0) && (k != 128))
*np = n;
}
/* ------------------------------------------------------------------------ */
/* Function: nat6_addnat */
/* 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 nat6_addnat(n, ifs)
ipnat_t *n;
{
i6addr_t j;
int k;
if ((k >= 0) && (k != 128))
*np = n;
}
/* ------------------------------------------------------------------------ */
/* Function: 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. */
/* ------------------------------------------------------------------------ */
{
hv %= HOSTMAP_SIZE;
return hm;
}
return NULL;
if (hm) {
}
return hm;
}
/* ------------------------------------------------------------------------ */
/* Function: 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 l;
/*
* If it's an outbound packet which doesn't match any existing
* record, then create a new port
*/
l = 0;
/*
* 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;
if (l == 0) {
/*
* Check to see if there is an existing NAT
* setup for this IP address pair.
*/
fr_hostmapdel(&hm);
}
if (l > 0)
return -1;
}
/*
* map the address block in a 1:1 fashion
*/
#ifdef NEED_128BIT_MATH
!(flags & IPN_TCPUDP)))
return -1;
/*
* map-block - Calculate destination address.
*/
/*
* Calculate destination port.
*/
if ((flags & IPN_TCPUDP) &&
port += MAPBLK_MINPORT;
}
#endif
/*
* 0/128 - use the interface's IP address.
*/
if ((l > 0) ||
return -1;
/*
*/
if (l > 0)
return -1;
}
if ((flags & IPN_TCPUDP) &&
/*EMPTY*/;
#ifdef NEED_128BIT_MATH
/*
* XXX "ports auto" (without map-block)
*/
return -1;
}
}
port += MAPBLK_MINPORT;
}
#endif
/*
* Standard port translation. Select next port.
*/
} else {
}
}
}
}
} else {
}
}
/*
* Here we do a lookup of the connection as seen from
* the outside. If an IP# pair already exists, try
* again. So if you have A->B becomes C->B, you can
* also have D->E become C->E but not D->B causing
* another C->B. Also take protocol and ports into
* account when determining whether a pre-existing
* NAT setup will cause an external conflict where
* this is appropriate.
*/
/*
* Has the search wrapped around and come back to the
* start ?
*/
return -1;
l++;
/* Setup the NAT table */
if (flags & IPN_TCPUDP) {
} else if (flags & IPN_ICMPQUERY) {
}
return 0;
}
/* ------------------------------------------------------------------------ */
/* Function: nat6_newrdr */
/* Returns: int - -1 == error, 0 == success (no move), 1 == success and */
/* allow rule to be moved if IPN_ROUNDR is set. */
/* 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. */
/* */
/* ni.nai_ip is passed in uninitialised and must be set, in host byte order,*/
/* to the new IP address for the translation. */
/* ------------------------------------------------------------------------ */
{
int move;
move = 1;
/*
* If the matching rule has IPN_STICKY set, then we want to have the
* same rule kick in as before. Why would this happen? If you have
* a collection of rdr rules with "round-robin sticky", the current
* packet might match a different one to the previous connection but
* we want the same destination to be used.
*/
(IPN_ROUNDR|IPN_STICKY)) {
move = 0;
}
}
/*
* Otherwise, it's an inbound packet. Most likely, we don't
* want to rewrite source ports and source addresses. Instead,
* we want to rewrite to a fixed internal address and fixed
* internal port.
*/
move = 0;
}
}
move = 0;
} else {
}
}
/*
* 0/128 - use the interface's IP address.
*/
return -1;
/*
*/
/*
* map the address block in a 1:1 fashion
*/
} else {
}
else {
/*
* Whilst not optimized for the case where
* pmin == pmax, the gain is not significant.
*/
} else
}
/*
* When the redirect-to address is set to 0.0.0.0, just
* assume a blank `forwarding' of the packet. We don't
* setup any translation for this either.
*/
if (IP6_ISZERO(&in)) {
return -1;
}
/*
* Check to see if this redirect mapping already exists and if
* it does, return "failure" (allowing it to be created will just
* cause one or both of these "connections" to stop working.)
*/
return -1;
if (flags & IPN_TCPUDP) {
} else if (flags & IPN_ICMPQUERY) {
}
return move;
}
/* ------------------------------------------------------------------------ */
/* Function: nat6_new */
/* Returns: nat_t* - NULL == failure to create new NAT structure, */
/* else pointer to new NAT structure */
/* Parameters: fin(I) - pointer to packet information */
/* np(I) - pointer to NAT rule */
/* natsave(I) - pointer to where to store NAT struct pointer */
/* flags(I) - flags describing the current packet */
/* Write Lock: ipf_nat */
/* */
/* Attempts to create a new NAT entry. Does not actually change the packet */
/* in any way. */
/* */
/* This fucntion is in three main parts: (1) deal with creating a new NAT */
/* structure for a "MAP" rule (outgoing NAT translation); (2) deal with */
/* creating a new NAT structure for a "RDR" rule (incoming NAT translation) */
/* and (3) building that structure and putting it into the NAT table(s). */
/* ------------------------------------------------------------------------ */
int direction;
{
int move;
/*
* Trigger automatic call to nat_extraflush() if the
* table has reached capcity specified by hi watermark.
*/
return NULL;
}
move = 1;
nflags &= NAT_FROMRULE;
/* Give me a new nat */
/*
* Try to automatically tune the max # of entries in the
* table allowed to be less than what will cause kmem_alloc()
* to fail and try to eliminate panics due to out of memory
* conditions arising.
*/
printf("ipf_nattable_max reduced to %d\n",
}
return NULL;
}
if (flags & IPN_TCPUDP) {
} else if (flags & IPN_ICMPQUERY) {
/*
* In the ICMP query NAT code, we translate the ICMP id fields
* to make them unique. This is indepedent of the ICMP type
* (e.g. in the unlikely event that a host sends an echo and
* an tstamp request with the same id, both packets will have
*
* The icmp_id field is used by the sender to identify the
* process making the icmp request. (the receiver justs
* copies it back in its response). So, it closely matches
* the concept of source port. We overlay sport, so we can
* maximally reuse the existing code.
*/
}
}
/*
* Search the current table for a match.
*/
if (direction == NAT_OUTBOUND) {
/*
* We can now arrange to call this for the same connection
* because ipf_nat_new doesn't protect the code path into
* this function.
*/
goto done;
}
if (move == -1)
goto badnat;
} else {
/*
* NAT_INBOUND is used only for redirects rules
*/
goto done;
}
if (move == -1)
goto badnat;
}
nat_delrdr(np);
nat_delnat(np);
}
}
goto badnat;
}
goto done;
fr_hostmapdel(&hm);
done:
}
return nat;
}
/* ------------------------------------------------------------------------ */
/* Function: nat6_finalise */
/* Returns: int - 0 == sucess, -1 == failure */
/* 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. */
/* Write Lock: ipf_nat */
/* */
/* This is the tail end of constructing a new NAT entry and is the same */
/* for both IPv4 and IPv6. */
/* ------------------------------------------------------------------------ */
/*ARGSUSED*/
int direction;
{
#ifdef IPFILTER_SYNC
#endif
#ifdef IPF_V6_PROXIES
return -1;
#endif
if (ifs->ifs_nat_logging)
}
return 0;
}
/*
* nat6_insert failed, so cleanup time...
*/
return -1;
}
/* ------------------------------------------------------------------------ */
/* Function: nat6_insert */
/* Returns: int - 0 == sucess, -1 == failure */
/* Parameters: nat(I) - pointer to NAT structure */
/* Write Lock: ipf_nat */
/* */
/* Insert a NAT entry into the hash tables for searching and add it to the */
/* list of active NAT entries. Adjust global counters when complete. */
/* ------------------------------------------------------------------------ */
int rev;
{
/*
* Try and return an error as early as possible, so calculate the hash
* entry numbers first and then proceed.
*/
0xffffffff);
0xffffffff);
} else {
}
ifs->ifs_fr_nat_maxbucket) ||
ifs->ifs_fr_nat_maxbucket)) {
return -1;
}
} else {
}
if (ifs->ifs_nat_instances)
if (*natp)
if (*natp)
return 0;
}
/* ------------------------------------------------------------------------ */
/* Function: nat6_icmperrorlookup */
/* Returns: nat_t* - point to matching NAT structure */
/* Parameters: fin(I) - pointer to packet information */
/* */
/* Check if the ICMP error message is related to an existing TCP, UDP or */
/* ICMP query nat entry. It is assumed that the packet is already of the */
/* the required length. */
/* ------------------------------------------------------------------------ */
int dir;
{
u_int p;
minlen = 40;
/*
* Does it at least have the return (basic) IP header ?
* Only a basic IP header (no options) should be with an ICMP error
* header. Also, if it's not an error type, then return.
*/
return NULL;
/*
* Check packet size
*/
return NULL;
/*
* Is the buffer big enough for all of it ? It's the size of the IP
* header claimed in the encapsulated part which is of concern. It
* may be too big to be in this buffer but not so big that it's
* outside the ICMP packet, leading to TCP deref's causing problems.
* This is possible because we don't know how big oip_hl is when we
* do the pullup early in fr_check() and thus can't gaurantee it is
* all here now.
*/
#ifdef _KERNEL
{
mb_t *m;
# if defined(MENTAT)
return NULL;
# else
return NULL;
# endif
}
#endif
return NULL;
if (p == IPPROTO_TCP)
else if (p == IPPROTO_UDP)
else if (p == IPPROTO_ICMPV6) {
/* see if this is related to an ICMP query */
/*
* NOTE : dir refers to the direction of the original
* ip packet. By definition the icmp error
* message flows in the opposite direction.
*/
if (dir == NAT_INBOUND)
else
return nat;
}
}
if (flags & IPN_TCPUDP) {
return NULL;
if (dir == NAT_INBOUND) {
} else {
}
return nat;
}
if (dir == NAT_INBOUND)
else
}
/* ------------------------------------------------------------------------ */
/* Function: nat6_icmperror */
/* Returns: nat_t* - point to matching NAT structure */
/* Parameters: fin(I) - pointer to packet information */
/* nflags(I) - NAT flags for this packet */
/* */
/* Fix up an ICMP packet which is an error message for an existing NAT */
/* session. This will correct both packet header data and checksums. */
/* */
/* This should *ONLY* be used for incoming ICMP error packets to make sure */
/* a NAT'd ICMP packet gets correctly recognised. */
/* ------------------------------------------------------------------------ */
int dir;
{
int dlen;
return NULL;
/*
* nat6_icmperrorlookup() looks up nat entry associated with the
* offending IP packet and returns pointer to the entry, or NULL
* if packet wasn't natted or for `defective' packets.
*/
return NULL;
sumd1 = 0;
*nflags = IPN_ICMPERR;
/*
* Need to adjust ICMP header to include the real IP#'s and
* port #'s. There are three steps required.
*
* Step 1
* No update needed for ip6 header checksum.
*
* Unlike IPv4, we need to update icmp_cksum for IPv6 address
* changes because there's no ip_sum change to cancel it.
*/
} else {
}
/*
* Step 2
* Perform other adjustments based on protocol of offending packet.
*/
case IPPROTO_TCP :
case IPPROTO_UDP :
/*
* based on the NAT specification.
*
* Advance notice : Now it becomes complicated :-)
*
* Since the port and IP addresse fields are both part
* we need to adjust that checksum as well.
*
* may not be present. We must check to see if the
* length of the data portion is big enough to hold
* the checksum. In the UDP case, a test to determine
* if the checksum is even set is also required.
*
* Any changes to an IP address, port or checksum within
* the ICMP packet requires a change to icmp_cksum.
*
* Be extremely careful here ... The change is dependent
*
* compensate for checksum modification resulting from
* IP address change only. Port change and resulting
* data checksum adjustments cancel each other out.
*
* compensate for port change only. The IP address
* change does not modify anything else in this case.
*/
psum1 = 0;
psum2 = 0;
psumd = 0;
/*
* Translate the source port.
*/
/*
* Translate the destination port.
*/
}
/*
* TCP checksum present.
*
* Adjust data checksum and icmp checksum to
* compensate for any IP address change.
*/
/*
* Also make data checksum adjustment to
* compensate for any port change.
*/
}
/*
* The UDP checksum is present and set.
*
* Adjust data checksum and icmp checksum to
* compensate for any IP address change.
*/
/*
* Also make data checksum adjustment to
* compensate for any port change.
*/
}
} else {
/*
* Data checksum was not present.
*
* Compensate for any port change.
*/
}
break;
case IPPROTO_ICMPV6 :
(dlen >= 8)) {
/*
* Fix ICMP checksum (of the offening ICMP
* query packet) to compensate the change
* in the ICMP id of the offending ICMP
* packet.
*
* Since you modify orgicmp->icmp_id with
* a delta (say x) and you compensate that
* in origicmp->icmp_cksum with a delta
* minus x, you don't have to adjust the
* overall icmp->icmp_cksum
*/
} /* nat_dir can't be NAT_INBOUND for icmp queries */
break;
default :
break;
} /* switch (oip6->ip6_nxt) */
/*
* Step 3
* Make the adjustments to icmp checksum.
*/
if (sumd1 != 0) {
}
return nat;
}
/*
* NB: these lookups don't lock access to the list, it assumed that it has
* already been done!
*/
/* ------------------------------------------------------------------------ */
/* Function: nat6_inlookup */
/* Returns: nat_t* - NULL == no match, */
/* else pointer to matching NAT entry */
/* Parameters: fin(I) - pointer to packet information */
/* flags(I) - NAT flags for this packet */
/* p(I) - protocol for this packet */
/* src(I) - source IP address */
/* mapdst(I) - destination IP address */
/* */
/* we're looking for a table entry, based on the destination address. */
/* */
/* NOTE: THE PACKET BEING CHECKED (IF FOUND) HAS A MAPPING ALREADY. */
/* */
/* NOTE: IT IS ASSUMED THAT ipf_nat IS ONLY HELD WITH A READ LOCK WHEN */
/* THIS FUNCTION IS CALLED WITH NAT_SEARCH SET IN nflags. */
/* */
/* flags -> relevant are IPN_UDP/IPN_TCP/IPN_ICMPQUERY that indicate if */
/* the packet is of said protocol */
/* ------------------------------------------------------------------------ */
{
int nflags;
void *ifp;
else
sport = 0;
dport = 0;
switch (p)
{
case IPPROTO_TCP :
case IPPROTO_UDP :
break;
case IPPROTO_ICMPV6 :
if (flags & IPN_ICMPERR)
else
break;
default :
break;
}
goto find_in_wild_ports;
continue;
continue;
(((p == 0) &&
switch (p)
{
#if 0
case IPPROTO_GRE :
continue;
break;
#endif
case IPPROTO_ICMPV6 :
if ((flags & IPN_ICMPERR) != 0) {
continue;
} else {
continue;
}
break;
case IPPROTO_TCP :
case IPPROTO_UDP :
continue;
continue;
break;
default :
break;
}
#ifdef IPF_V6_PROXIES
continue;
#endif
return nat;
}
}
/*
* So if we didn't find it but there are wildcard members in the hash
* table, go back and look for them. We do this search and update here
* because it is modifying the NAT table and we want to do this only
* for the first packet that matches. The exception, of course, is
* for "dummy" (FI_IGNORE) lookups.
*/
return NULL;
return NULL;
continue;
continue;
continue;
continue;
continue;
NAT_INBOUND) == 1) {
break;
break;
} else {
}
break;
}
}
return nat;
}
/* ------------------------------------------------------------------------ */
/* Function: nat6_tabmove */
/* Returns: Nil */
/* Parameters: nat(I) - pointer to NAT structure */
/* Write Lock: ipf_nat */
/* */
/* original was placed in the table without hashing on the ports and we now */
/* want to include hashing on port numbers. */
/* ------------------------------------------------------------------------ */
{
return;
/*
* Remove the NAT entry from the old location
*/
/*
* Add into the NAT table in the new position
*/
if (*natp)
if (*natp)
}
/* ------------------------------------------------------------------------ */
/* Function: nat6_outlookup */
/* Returns: nat_t* - NULL == no match, */
/* else pointer to matching NAT entry */
/* Parameters: fin(I) - pointer to packet information */
/* flags(I) - NAT flags for this packet */
/* p(I) - protocol for this packet */
/* src(I) - source IP address */
/* dst(I) - destination IP address */
/* rw(I) - 1 == write lock on ipf_nat held, 0 == read lock. */
/* */
/* we're looking for a table entry, based on the source address. */
/* */
/* NOTE: THE PACKET BEING CHECKED (IF FOUND) HAS A MAPPING ALREADY. */
/* */
/* NOTE: IT IS ASSUMED THAT ipf_nat IS ONLY HELD WITH A READ LOCK WHEN */
/* THIS FUNCTION IS CALLED WITH NAT_SEARCH SET IN nflags. */
/* */
/* flags -> relevant are IPN_UDP/IPN_TCP/IPN_ICMPQUERY that indicate if */
/* the packet is of said protocol */
/* ------------------------------------------------------------------------ */
{
int nflags;
void *ifp;
sport = 0;
dport = 0;
switch (p)
{
case IPPROTO_TCP :
case IPPROTO_UDP :
break;
case IPPROTO_ICMPV6 :
if (flags & IPN_ICMPERR)
else
break;
default :
break;
}
goto find_out_wild_ports;
continue;
continue;
switch (p)
{
#if 0
case IPPROTO_GRE :
continue;
break;
#endif
case IPPROTO_TCP :
case IPPROTO_UDP :
continue;
continue;
break;
default :
break;
}
#ifdef IPF_V6_PROXIES
continue;
#endif
return nat;
}
}
/*
* So if we didn't find it but there are wildcard members in the hash
* table, go back and look for them. We do this search and update here
* because it is modifying the NAT table and we want to do this only
* for the first packet that matches. The exception, of course, is
* for "dummy" (FI_IGNORE) lookups.
*/
return NULL;
return NULL;
continue;
continue;
continue;
continue;
continue;
NAT_OUTBOUND) == 1) {
break;
break;
} else {
}
if (nat->nat_outport == 0)
break;
}
}
return nat;
}
/* ------------------------------------------------------------------------ */
/* Function: nat6_lookupredir */
/* Returns: nat_t* - NULL == no match, */
/* else pointer to matching NAT entry */
/* Parameters: np(I) - pointer to description of packet to find NAT table */
/* entry for. */
/* */
/* Lookup the NAT tables to search for a matching redirect */
/* ------------------------------------------------------------------------ */
{
} else {
}
/*
* We can do two sorts of lookups:
* - IPN_IN: we have the `real' and `out' address, look for `in'.
* - default: we have the `in' and `out' address, look for `real'.
*/
}
} else {
/*
* If nl_inip is non null, this is a lookup based on the real
* ip address. Else, we use the fake.
*/
}
}
}
}
return nat;
}
/* ------------------------------------------------------------------------ */
/* Function: nat6_match */
/* Returns: int - 0 == no match, 1 == match */
/* Parameters: fin(I) - pointer to packet information */
/* np(I) - pointer to NAT rule */
/* */
/* Pull the matching of a packet against a NAT rule out of that complex */
/* loop inside fr_checknat6in() and lay it out properly in its own function.*/
/* ------------------------------------------------------------------------ */
{
return 0;
return 0;
return 0;
return 0;
return 0;
} else {
return 0;
return 0;
return 0;
}
return 0;
return 1;
}
}
/* ------------------------------------------------------------------------ */
/* Function: fr_checknat6out */
/* Returns: int - -1 == packet failed NAT checks so block it, */
/* 0 == no packet translation occurred, */
/* 1 == packet was successfully translated. */
/* Parameters: fin(I) - pointer to packet information */
/* passp(I) - pointer to filtering result flags */
/* */
/* Check to see if an outcoming packet should be changed. ICMP packets are */
/* first checked to see if they match an existing entry (if an error), */
/* otherwise a search of the current NAT table is made. If neither results */
/* in a match then a search for a matching NAT rule is made. Create a new */
/* NAT entry if a we matched a NAT rule. Lastly, actually change the */
/* packet header(s) as required. */
/* ------------------------------------------------------------------------ */
{
int natadd = 1;
return 0;
natfailed = 0;
{
case IPPROTO_TCP :
break;
case IPPROTO_UDP :
break;
case IPPROTO_ICMPV6 :
/*
* This is an incoming packet, so the destination is
* the icmp6_id and the source port equals 0
*/
break;
default :
break;
}
#ifdef IPF_V6_PROXIES
if ((nflags & IPN_TCPUDP))
#endif
}
/*EMPTY*/;
natadd = 0;
} else {
int i;
/*
* If there is no current entry in the nat table for this IP#,
* create one for it (if there is a matching rule).
*/
i = 3;
{
continue;
continue;
continue;
continue;
continue;
continue;
continue;
#ifdef IPF_V6_PROXIES
continue;
continue;
}
#endif
NAT_OUTBOUND)) {
break;
} else
natfailed = -1;
}
while (i >= 0) {
while (nmsk) {
if ((nmsk & 0x80000000) != 0) {
nmsk <<= 1;
goto maskloop;
}
nmsk <<= 1;
}
if (i >= 0) {
if (nmsk != 0)
goto maskloop;
}
}
}
}
if (rval == 1) {
}
} else
if (rval == -1) {
}
return rval;
}
/* ------------------------------------------------------------------------ */
/* Function: fr_nat6out */
/* Returns: int - -1 == packet failed NAT checks so block it, */
/* 1 == packet was successfully translated. */
/* Parameters: fin(I) - pointer to packet information */
/* nat(I) - pointer to NAT structure */
/* natadd(I) - flag indicating if it is safe to add frag cache */
/* nflags(I) - NAT flags set for this packet */
/* */
/* Translate a packet coming "out" on an interface. */
/* ------------------------------------------------------------------------ */
int natadd;
{
int i;
#endif
}
}
}
/*
*/
if (nflags & IPN_TCPUDP &&
else
} else {
else
}
}
#ifdef IPFILTER_SYNC
#endif
/* ------------------------------------------------------------- */
/* A few quick notes: */
/* Following are test conditions prior to calling the */
/* appr_check routine. */
/* */
/* with a redirect rule, we attempt to match the packet's */
/* source port against in_dport, otherwise we'd compare the */
/* packet's destination. */
/* ------------------------------------------------------------- */
if (i == 0)
i = 1;
} else
i = 1;
return i;
}
/* ------------------------------------------------------------------------ */
/* Function: fr_checknat6in */
/* Returns: int - -1 == packet failed NAT checks so block it, */
/* 0 == no packet translation occurred, */
/* 1 == packet was successfully translated. */
/* Parameters: fin(I) - pointer to packet information */
/* passp(I) - pointer to filtering result flags */
/* */
/* Check to see if an incoming packet should be changed. ICMP packets are */
/* first checked to see if they match an existing entry (if an error), */
/* otherwise a search of the current NAT table is made. If neither results */
/* in a match then a search for a matching NAT rule is made. Create a new */
/* NAT entry if a we matched a NAT rule. Lastly, actually change the */
/* packet header(s) as required. */
/* ------------------------------------------------------------------------ */
{
return 0;
dport = 0;
natadd = 1;
nflags = 0;
natfailed = 0;
{
case IPPROTO_TCP :
break;
case IPPROTO_UDP :
break;
case IPPROTO_ICMPV6 :
/*
* This is an incoming packet, so the destination is
* the icmp_id and the source port equals 0
*/
} break;
default :
break;
}
if ((nflags & IPN_TCPUDP)) {
}
}
/*EMPTY*/;
natadd = 0;
} else {
int i;
i = 3;
/*
* If there is no current entry in the nat table for this IP#,
* create one for it (if there is a matching rule).
*/
continue;
continue;
continue;
continue;
continue;
} else {
continue;
continue;
}
#ifdef IPF_V6_PROXIES
continue;
}
}
#endif
break;
} else
natfailed = -1;
}
while (i >= 0) {
while (rmsk) {
if ((rmsk & 0x80000000) != 0) {
rmsk <<= 1;
goto maskloop;
}
rmsk <<= 1;
}
if (i >= 0) {
if (rmsk != 0)
goto maskloop;
}
}
}
}
if (rval == 1) {
}
} else
if (rval == -1) {
}
return rval;
}
/* ------------------------------------------------------------------------ */
/* Function: fr_nat6in */
/* Returns: int - -1 == packet failed NAT checks so block it, */
/* 1 == packet was successfully translated. */
/* Parameters: fin(I) - pointer to packet information */
/* nat(I) - pointer to NAT structure */
/* natadd(I) - flag indicating if it is safe to add frag cache */
/* nflags(I) - NAT flags set for this packet */
/* Locks Held: ipf_nat (READ) */
/* */
/* Translate a packet coming "in" on an interface. */
/* ------------------------------------------------------------------------ */
int natadd;
{
#endif
#ifdef IPF_V6_PROXIES
/* ------------------------------------------------------------- */
/* A few quick notes: */
/* Following are test conditions prior to calling the */
/* appr_check routine. */
/* */
/* with a map rule, we attempt to match the packet's */
/* source port against in_dport, otherwise we'd compare the */
/* packet's destination. */
/* ------------------------------------------------------------- */
if (i == -1) {
return -1;
}
}
}
#endif
#ifdef IPFILTER_SYNC
#endif
if (nflags & IPN_TCPUDP)
}
}
}
/*
* In case they are being forwarded, inbound packets always need to have
* their checksum adjusted even if hardware checksum validation said OK.
*/
else
}
if (nflags & IPN_TCPUDP &&
/*
* Need to adjust the partial checksum result stored in
* db_cksum16, which will be used for validation in IP.
* See IP_CKSUM_RECV().
* Adjustment data should be the inverse of the IP address
* changes, because db_cksum16 is supposed to be the complement
* of the pesudo header.
*/
else
}
#endif
return 1;
}
/* ------------------------------------------------------------------------ */
/* Function: nat_icmpquerytype6 */
/* Returns: int - 1 == success, 0 == failure */
/* Parameters: icmptype(I) - ICMP type number */
/* */
/* not. */
/* ------------------------------------------------------------------------ */
int icmptype;
{
/*
* For the ICMP query NAT code, it is essential that both the query
* and the reply match on the NAT rule. Because the NAT structure
* does not keep track of the icmptype, and a single NAT structure
* is used for all icmp types with the same src, dest and id, we
* simply define the replies as queries as well. The funny thing is,
* altough it seems silly to call a reply a query, this is exactly
* as it is defined in the IPv4 specification
*/
switch (icmptype)
{
case ICMP6_ECHO_REPLY:
case ICMP6_ECHO_REQUEST:
/* route aedvertisement/solliciation is currently unsupported: */
/* it would require rewriting the ICMP data section */
case ICMP6_MEMBERSHIP_QUERY:
case ICMP6_MEMBERSHIP_REPORT:
case ICMP6_WRUREQUEST:
case ICMP6_WRUREPLY:
case MLD6_MTRACE_RESP:
case MLD6_MTRACE:
return 1;
default:
return 0;
}
}