2008-02-29 22:27:19 +00:00
|
|
|
/*-
|
|
|
|
* Copyright (c) 2008 Paolo Pisati
|
|
|
|
* All rights reserved.
|
|
|
|
*
|
|
|
|
* Redistribution and use in source and binary forms, with or without
|
|
|
|
* modification, are permitted provided that the following conditions
|
|
|
|
* are met:
|
|
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer.
|
|
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
|
|
* documentation and/or other materials provided with the distribution.
|
|
|
|
*
|
|
|
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
|
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
|
|
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
|
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
|
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
|
|
* SUCH DAMAGE.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <sys/cdefs.h>
|
|
|
|
__FBSDID("$FreeBSD$");
|
|
|
|
|
|
|
|
#include <sys/param.h>
|
|
|
|
#include <sys/systm.h>
|
|
|
|
#include <sys/eventhandler.h>
|
|
|
|
#include <sys/malloc.h>
|
2013-10-26 17:58:36 +00:00
|
|
|
#include <sys/mbuf.h>
|
2008-02-29 22:27:19 +00:00
|
|
|
#include <sys/kernel.h>
|
|
|
|
#include <sys/lock.h>
|
|
|
|
#include <sys/module.h>
|
|
|
|
#include <sys/rwlock.h>
|
2014-10-04 11:40:35 +00:00
|
|
|
#include <sys/rmlock.h>
|
2008-02-29 22:27:19 +00:00
|
|
|
|
|
|
|
#include <netinet/libalias/alias.h>
|
|
|
|
#include <netinet/libalias/alias_local.h>
|
|
|
|
|
|
|
|
#include <net/if.h>
|
2013-10-26 17:58:36 +00:00
|
|
|
#include <net/if_var.h>
|
2008-02-29 22:27:19 +00:00
|
|
|
#include <netinet/in.h>
|
|
|
|
#include <netinet/ip.h>
|
|
|
|
#include <netinet/ip_var.h>
|
|
|
|
#include <netinet/ip_fw.h>
|
|
|
|
#include <netinet/tcp.h>
|
|
|
|
#include <netinet/udp.h>
|
|
|
|
|
2012-09-14 11:51:49 +00:00
|
|
|
#include <netpfil/ipfw/ip_fw_private.h>
|
|
|
|
|
2008-02-29 22:27:19 +00:00
|
|
|
#include <machine/in_cksum.h> /* XXX for in_cksum */
|
|
|
|
|
2014-09-07 18:30:29 +00:00
|
|
|
struct cfg_spool {
|
|
|
|
LIST_ENTRY(cfg_spool) _next; /* chain of spool instances */
|
|
|
|
struct in_addr addr;
|
|
|
|
uint16_t port;
|
|
|
|
};
|
|
|
|
|
|
|
|
/* Nat redirect configuration. */
|
|
|
|
struct cfg_redir {
|
|
|
|
LIST_ENTRY(cfg_redir) _next; /* chain of redir instances */
|
|
|
|
uint16_t mode; /* type of redirect mode */
|
|
|
|
uint16_t proto; /* protocol: tcp/udp */
|
|
|
|
struct in_addr laddr; /* local ip address */
|
|
|
|
struct in_addr paddr; /* public ip address */
|
|
|
|
struct in_addr raddr; /* remote ip address */
|
|
|
|
uint16_t lport; /* local port */
|
|
|
|
uint16_t pport; /* public port */
|
|
|
|
uint16_t rport; /* remote port */
|
|
|
|
uint16_t pport_cnt; /* number of public ports */
|
|
|
|
uint16_t rport_cnt; /* number of remote ports */
|
|
|
|
struct alias_link **alink;
|
|
|
|
u_int16_t spool_cnt; /* num of entry in spool chain */
|
|
|
|
/* chain of spool instances */
|
|
|
|
LIST_HEAD(spool_chain, cfg_spool) spool_chain;
|
|
|
|
};
|
|
|
|
|
|
|
|
/* Nat configuration data struct. */
|
|
|
|
struct cfg_nat {
|
|
|
|
/* chain of nat instances */
|
|
|
|
LIST_ENTRY(cfg_nat) _next;
|
|
|
|
int id; /* nat id */
|
|
|
|
struct in_addr ip; /* nat ip address */
|
|
|
|
struct libalias *lib; /* libalias instance */
|
|
|
|
int mode; /* aliasing mode */
|
|
|
|
int redir_cnt; /* number of entry in spool chain */
|
|
|
|
/* chain of redir instances */
|
|
|
|
LIST_HEAD(redir_chain, cfg_redir) redir_chain;
|
|
|
|
char if_name[IF_NAMESIZE]; /* interface name */
|
|
|
|
};
|
|
|
|
|
2013-08-24 11:59:51 +00:00
|
|
|
static eventhandler_tag ifaddr_event_tag;
|
2008-02-29 22:27:19 +00:00
|
|
|
|
mostly style changes, such as removal of trailing whitespace,
reformatting to avoid unnecessary line breaks, small block
restructuring to avoid unnecessary nesting, replace macros
with function calls, etc.
As a side effect of code restructuring, this commit fixes one bug:
previously, if a realloc() failed, memory was leaked. Now, the
realloc is not there anymore, as we first count how much memory
we need and then do a single malloc.
2009-12-23 18:53:11 +00:00
|
|
|
static void
|
2008-02-29 22:27:19 +00:00
|
|
|
ifaddr_change(void *arg __unused, struct ifnet *ifp)
|
|
|
|
{
|
|
|
|
struct cfg_nat *ptr;
|
|
|
|
struct ifaddr *ifa;
|
2009-12-23 12:15:21 +00:00
|
|
|
struct ip_fw_chain *chain;
|
2008-02-29 22:27:19 +00:00
|
|
|
|
2013-08-24 11:59:51 +00:00
|
|
|
KASSERT(curvnet == ifp->if_vnet,
|
|
|
|
("curvnet(%p) differs from iface vnet(%p)", curvnet, ifp->if_vnet));
|
2009-12-23 12:15:21 +00:00
|
|
|
chain = &V_layer3_chain;
|
2015-01-16 10:49:27 +00:00
|
|
|
IPFW_UH_WLOCK(chain);
|
2008-02-29 22:27:19 +00:00
|
|
|
/* Check every nat entry... */
|
2009-12-23 12:15:21 +00:00
|
|
|
LIST_FOREACH(ptr, &chain->nat, _next) {
|
2008-02-29 22:27:19 +00:00
|
|
|
/* ...using nic 'ifp->if_xname' as dynamic alias address. */
|
2014-01-11 18:27:34 +00:00
|
|
|
if (strncmp(ptr->if_name, ifp->if_xname, IF_NAMESIZE) != 0)
|
mostly style changes, such as removal of trailing whitespace,
reformatting to avoid unnecessary line breaks, small block
restructuring to avoid unnecessary nesting, replace macros
with function calls, etc.
As a side effect of code restructuring, this commit fixes one bug:
previously, if a realloc() failed, memory was leaked. Now, the
realloc is not there anymore, as we first count how much memory
we need and then do a single malloc.
2009-12-23 18:53:11 +00:00
|
|
|
continue;
|
|
|
|
if_addr_rlock(ifp);
|
|
|
|
TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
|
|
|
|
if (ifa->ifa_addr == NULL)
|
|
|
|
continue;
|
|
|
|
if (ifa->ifa_addr->sa_family != AF_INET)
|
|
|
|
continue;
|
2015-01-16 10:49:27 +00:00
|
|
|
IPFW_WLOCK(chain);
|
mostly style changes, such as removal of trailing whitespace,
reformatting to avoid unnecessary line breaks, small block
restructuring to avoid unnecessary nesting, replace macros
with function calls, etc.
As a side effect of code restructuring, this commit fixes one bug:
previously, if a realloc() failed, memory was leaked. Now, the
realloc is not there anymore, as we first count how much memory
we need and then do a single malloc.
2009-12-23 18:53:11 +00:00
|
|
|
ptr->ip = ((struct sockaddr_in *)
|
|
|
|
(ifa->ifa_addr))->sin_addr;
|
|
|
|
LibAliasSetAddress(ptr->lib, ptr->ip);
|
2015-01-16 10:49:27 +00:00
|
|
|
IPFW_WUNLOCK(chain);
|
2008-02-29 22:27:19 +00:00
|
|
|
}
|
mostly style changes, such as removal of trailing whitespace,
reformatting to avoid unnecessary line breaks, small block
restructuring to avoid unnecessary nesting, replace macros
with function calls, etc.
As a side effect of code restructuring, this commit fixes one bug:
previously, if a realloc() failed, memory was leaked. Now, the
realloc is not there anymore, as we first count how much memory
we need and then do a single malloc.
2009-12-23 18:53:11 +00:00
|
|
|
if_addr_runlock(ifp);
|
2008-02-29 22:27:19 +00:00
|
|
|
}
|
2015-01-16 10:49:27 +00:00
|
|
|
IPFW_UH_WUNLOCK(chain);
|
2008-02-29 22:27:19 +00:00
|
|
|
}
|
|
|
|
|
2009-12-23 12:15:21 +00:00
|
|
|
/*
|
|
|
|
* delete the pointers for nat entry ix, or all of them if ix < 0
|
|
|
|
*/
|
2008-02-29 22:27:19 +00:00
|
|
|
static void
|
2009-12-23 12:15:21 +00:00
|
|
|
flush_nat_ptrs(struct ip_fw_chain *chain, const int ix)
|
2008-02-29 22:27:19 +00:00
|
|
|
{
|
2009-12-23 12:15:21 +00:00
|
|
|
int i;
|
mostly style changes, such as removal of trailing whitespace,
reformatting to avoid unnecessary line breaks, small block
restructuring to avoid unnecessary nesting, replace macros
with function calls, etc.
As a side effect of code restructuring, this commit fixes one bug:
previously, if a realloc() failed, memory was leaked. Now, the
realloc is not there anymore, as we first count how much memory
we need and then do a single malloc.
2009-12-23 18:53:11 +00:00
|
|
|
ipfw_insn_nat *cmd;
|
2008-02-29 22:27:19 +00:00
|
|
|
|
2009-12-23 12:15:21 +00:00
|
|
|
IPFW_WLOCK_ASSERT(chain);
|
|
|
|
for (i = 0; i < chain->n_rules; i++) {
|
mostly style changes, such as removal of trailing whitespace,
reformatting to avoid unnecessary line breaks, small block
restructuring to avoid unnecessary nesting, replace macros
with function calls, etc.
As a side effect of code restructuring, this commit fixes one bug:
previously, if a realloc() failed, memory was leaked. Now, the
realloc is not there anymore, as we first count how much memory
we need and then do a single malloc.
2009-12-23 18:53:11 +00:00
|
|
|
cmd = (ipfw_insn_nat *)ACTION_PTR(chain->map[i]);
|
|
|
|
/* XXX skip log and the like ? */
|
2009-12-23 12:15:21 +00:00
|
|
|
if (cmd->o.opcode == O_NAT && cmd->nat != NULL &&
|
|
|
|
(ix < 0 || cmd->nat->id == ix))
|
2008-02-29 22:27:19 +00:00
|
|
|
cmd->nat = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
del_redir_spool_cfg(struct cfg_nat *n, struct redir_chain *head)
|
|
|
|
{
|
|
|
|
struct cfg_redir *r, *tmp_r;
|
|
|
|
struct cfg_spool *s, *tmp_s;
|
|
|
|
int i, num;
|
|
|
|
|
|
|
|
LIST_FOREACH_SAFE(r, head, _next, tmp_r) {
|
|
|
|
num = 1; /* Number of alias_link to delete. */
|
|
|
|
switch (r->mode) {
|
2014-09-07 18:30:29 +00:00
|
|
|
case NAT44_REDIR_PORT:
|
2008-02-29 22:27:19 +00:00
|
|
|
num = r->pport_cnt;
|
|
|
|
/* FALLTHROUGH */
|
2014-09-07 18:30:29 +00:00
|
|
|
case NAT44_REDIR_ADDR:
|
|
|
|
case NAT44_REDIR_PROTO:
|
2008-02-29 22:27:19 +00:00
|
|
|
/* Delete all libalias redirect entry. */
|
|
|
|
for (i = 0; i < num; i++)
|
|
|
|
LibAliasRedirectDelete(n->lib, r->alink[i]);
|
|
|
|
/* Del spool cfg if any. */
|
|
|
|
LIST_FOREACH_SAFE(s, &r->spool_chain, _next, tmp_s) {
|
|
|
|
LIST_REMOVE(s, _next);
|
|
|
|
free(s, M_IPFW);
|
|
|
|
}
|
|
|
|
free(r->alink, M_IPFW);
|
|
|
|
LIST_REMOVE(r, _next);
|
|
|
|
free(r, M_IPFW);
|
|
|
|
break;
|
|
|
|
default:
|
mostly style changes, such as removal of trailing whitespace,
reformatting to avoid unnecessary line breaks, small block
restructuring to avoid unnecessary nesting, replace macros
with function calls, etc.
As a side effect of code restructuring, this commit fixes one bug:
previously, if a realloc() failed, memory was leaked. Now, the
realloc is not there anymore, as we first count how much memory
we need and then do a single malloc.
2009-12-23 18:53:11 +00:00
|
|
|
printf("unknown redirect mode: %u\n", r->mode);
|
2008-02-29 22:27:19 +00:00
|
|
|
/* XXX - panic?!?!? */
|
mostly style changes, such as removal of trailing whitespace,
reformatting to avoid unnecessary line breaks, small block
restructuring to avoid unnecessary nesting, replace macros
with function calls, etc.
As a side effect of code restructuring, this commit fixes one bug:
previously, if a realloc() failed, memory was leaked. Now, the
realloc is not there anymore, as we first count how much memory
we need and then do a single malloc.
2009-12-23 18:53:11 +00:00
|
|
|
break;
|
2008-02-29 22:27:19 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-09-07 18:30:29 +00:00
|
|
|
static int
|
2008-02-29 22:27:19 +00:00
|
|
|
add_redir_spool_cfg(char *buf, struct cfg_nat *ptr)
|
|
|
|
{
|
2014-09-07 18:30:29 +00:00
|
|
|
struct cfg_redir *r;
|
|
|
|
struct cfg_spool *s;
|
|
|
|
struct nat44_cfg_redir *ser_r;
|
|
|
|
struct nat44_cfg_spool *ser_s;
|
|
|
|
|
2008-02-29 22:27:19 +00:00
|
|
|
int cnt, off, i;
|
|
|
|
|
|
|
|
for (cnt = 0, off = 0; cnt < ptr->redir_cnt; cnt++) {
|
2014-09-07 18:30:29 +00:00
|
|
|
ser_r = (struct nat44_cfg_redir *)&buf[off];
|
|
|
|
r = malloc(sizeof(*r), M_IPFW, M_WAITOK | M_ZERO);
|
|
|
|
r->mode = ser_r->mode;
|
|
|
|
r->laddr = ser_r->laddr;
|
|
|
|
r->paddr = ser_r->paddr;
|
|
|
|
r->raddr = ser_r->raddr;
|
|
|
|
r->lport = ser_r->lport;
|
|
|
|
r->pport = ser_r->pport;
|
|
|
|
r->rport = ser_r->rport;
|
|
|
|
r->pport_cnt = ser_r->pport_cnt;
|
|
|
|
r->rport_cnt = ser_r->rport_cnt;
|
|
|
|
r->proto = ser_r->proto;
|
|
|
|
r->spool_cnt = ser_r->spool_cnt;
|
|
|
|
//memcpy(r, ser_r, SOF_REDIR);
|
2008-02-29 22:27:19 +00:00
|
|
|
LIST_INIT(&r->spool_chain);
|
2014-09-07 18:30:29 +00:00
|
|
|
off += sizeof(struct nat44_cfg_redir);
|
2008-02-29 22:27:19 +00:00
|
|
|
r->alink = malloc(sizeof(struct alias_link *) * r->pport_cnt,
|
|
|
|
M_IPFW, M_WAITOK | M_ZERO);
|
|
|
|
switch (r->mode) {
|
2014-09-07 18:30:29 +00:00
|
|
|
case NAT44_REDIR_ADDR:
|
2008-02-29 22:27:19 +00:00
|
|
|
r->alink[0] = LibAliasRedirectAddr(ptr->lib, r->laddr,
|
|
|
|
r->paddr);
|
|
|
|
break;
|
2014-09-07 18:30:29 +00:00
|
|
|
case NAT44_REDIR_PORT:
|
2008-02-29 22:27:19 +00:00
|
|
|
for (i = 0 ; i < r->pport_cnt; i++) {
|
|
|
|
/* If remotePort is all ports, set it to 0. */
|
|
|
|
u_short remotePortCopy = r->rport + i;
|
|
|
|
if (r->rport_cnt == 1 && r->rport == 0)
|
|
|
|
remotePortCopy = 0;
|
|
|
|
r->alink[i] = LibAliasRedirectPort(ptr->lib,
|
|
|
|
r->laddr, htons(r->lport + i), r->raddr,
|
mostly style changes, such as removal of trailing whitespace,
reformatting to avoid unnecessary line breaks, small block
restructuring to avoid unnecessary nesting, replace macros
with function calls, etc.
As a side effect of code restructuring, this commit fixes one bug:
previously, if a realloc() failed, memory was leaked. Now, the
realloc is not there anymore, as we first count how much memory
we need and then do a single malloc.
2009-12-23 18:53:11 +00:00
|
|
|
htons(remotePortCopy), r->paddr,
|
2008-02-29 22:27:19 +00:00
|
|
|
htons(r->pport + i), r->proto);
|
|
|
|
if (r->alink[i] == NULL) {
|
|
|
|
r->alink[0] = NULL;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
2014-09-07 18:30:29 +00:00
|
|
|
case NAT44_REDIR_PROTO:
|
2008-02-29 22:27:19 +00:00
|
|
|
r->alink[0] = LibAliasRedirectProto(ptr->lib ,r->laddr,
|
|
|
|
r->raddr, r->paddr, r->proto);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
printf("unknown redirect mode: %u\n", r->mode);
|
mostly style changes, such as removal of trailing whitespace,
reformatting to avoid unnecessary line breaks, small block
restructuring to avoid unnecessary nesting, replace macros
with function calls, etc.
As a side effect of code restructuring, this commit fixes one bug:
previously, if a realloc() failed, memory was leaked. Now, the
realloc is not there anymore, as we first count how much memory
we need and then do a single malloc.
2009-12-23 18:53:11 +00:00
|
|
|
break;
|
|
|
|
}
|
2014-09-07 18:30:29 +00:00
|
|
|
if (r->alink[0] == NULL) {
|
|
|
|
printf("LibAliasRedirect* returned NULL\n");
|
2015-04-27 05:44:09 +00:00
|
|
|
free(r->alink, M_IPFW);
|
|
|
|
free(r, M_IPFW);
|
2014-09-07 18:30:29 +00:00
|
|
|
return (EINVAL);
|
|
|
|
}
|
mostly style changes, such as removal of trailing whitespace,
reformatting to avoid unnecessary line breaks, small block
restructuring to avoid unnecessary nesting, replace macros
with function calls, etc.
As a side effect of code restructuring, this commit fixes one bug:
previously, if a realloc() failed, memory was leaked. Now, the
realloc is not there anymore, as we first count how much memory
we need and then do a single malloc.
2009-12-23 18:53:11 +00:00
|
|
|
/* LSNAT handling. */
|
|
|
|
for (i = 0; i < r->spool_cnt; i++) {
|
2014-09-07 18:30:29 +00:00
|
|
|
ser_s = (struct nat44_cfg_spool *)&buf[off];
|
|
|
|
s = malloc(sizeof(*s), M_IPFW, M_WAITOK | M_ZERO);
|
|
|
|
s->addr = ser_s->addr;
|
|
|
|
s->port = ser_s->port;
|
mostly style changes, such as removal of trailing whitespace,
reformatting to avoid unnecessary line breaks, small block
restructuring to avoid unnecessary nesting, replace macros
with function calls, etc.
As a side effect of code restructuring, this commit fixes one bug:
previously, if a realloc() failed, memory was leaked. Now, the
realloc is not there anymore, as we first count how much memory
we need and then do a single malloc.
2009-12-23 18:53:11 +00:00
|
|
|
LibAliasAddServer(ptr->lib, r->alink[0],
|
|
|
|
s->addr, htons(s->port));
|
2014-09-07 18:30:29 +00:00
|
|
|
off += sizeof(struct nat44_cfg_spool);
|
mostly style changes, such as removal of trailing whitespace,
reformatting to avoid unnecessary line breaks, small block
restructuring to avoid unnecessary nesting, replace macros
with function calls, etc.
As a side effect of code restructuring, this commit fixes one bug:
previously, if a realloc() failed, memory was leaked. Now, the
realloc is not there anymore, as we first count how much memory
we need and then do a single malloc.
2009-12-23 18:53:11 +00:00
|
|
|
/* Hook spool entry. */
|
|
|
|
LIST_INSERT_HEAD(&r->spool_chain, s, _next);
|
2008-02-29 22:27:19 +00:00
|
|
|
}
|
|
|
|
/* And finally hook this redir entry. */
|
2009-12-23 12:15:21 +00:00
|
|
|
LIST_INSERT_HEAD(&ptr->redir_chain, r, _next);
|
2008-02-29 22:27:19 +00:00
|
|
|
}
|
2014-09-07 18:30:29 +00:00
|
|
|
|
|
|
|
return (0);
|
2008-02-29 22:27:19 +00:00
|
|
|
}
|
|
|
|
|
2015-04-27 09:16:22 +00:00
|
|
|
static void
|
|
|
|
free_nat_instance(struct cfg_nat *ptr)
|
|
|
|
{
|
|
|
|
|
|
|
|
del_redir_spool_cfg(ptr, &ptr->redir_chain);
|
|
|
|
LibAliasUninit(ptr->lib);
|
|
|
|
free(ptr, M_IPFW);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-10-22 19:22:31 +00:00
|
|
|
/*
|
|
|
|
* ipfw_nat - perform mbuf header translation.
|
|
|
|
*
|
|
|
|
* Note V_layer3_chain has to be locked while calling ipfw_nat() in
|
|
|
|
* 'global' operation mode (t == NULL).
|
|
|
|
*
|
|
|
|
*/
|
2008-02-29 22:27:19 +00:00
|
|
|
static int
|
|
|
|
ipfw_nat(struct ip_fw_args *args, struct cfg_nat *t, struct mbuf *m)
|
|
|
|
{
|
|
|
|
struct mbuf *mcl;
|
|
|
|
struct ip *ip;
|
|
|
|
/* XXX - libalias duct tape */
|
2011-06-14 13:35:24 +00:00
|
|
|
int ldt, retval, found;
|
|
|
|
struct ip_fw_chain *chain;
|
2008-02-29 22:27:19 +00:00
|
|
|
char *c;
|
|
|
|
|
|
|
|
ldt = 0;
|
|
|
|
retval = 0;
|
mostly style changes, such as removal of trailing whitespace,
reformatting to avoid unnecessary line breaks, small block
restructuring to avoid unnecessary nesting, replace macros
with function calls, etc.
As a side effect of code restructuring, this commit fixes one bug:
previously, if a realloc() failed, memory was leaked. Now, the
realloc is not there anymore, as we first count how much memory
we need and then do a single malloc.
2009-12-23 18:53:11 +00:00
|
|
|
mcl = m_megapullup(m, m->m_pkthdr.len);
|
|
|
|
if (mcl == NULL) {
|
|
|
|
args->m = NULL;
|
|
|
|
return (IP_FW_DENY);
|
|
|
|
}
|
2008-02-29 22:27:19 +00:00
|
|
|
ip = mtod(mcl, struct ip *);
|
|
|
|
|
mostly style changes, such as removal of trailing whitespace,
reformatting to avoid unnecessary line breaks, small block
restructuring to avoid unnecessary nesting, replace macros
with function calls, etc.
As a side effect of code restructuring, this commit fixes one bug:
previously, if a realloc() failed, memory was leaked. Now, the
realloc is not there anymore, as we first count how much memory
we need and then do a single malloc.
2009-12-23 18:53:11 +00:00
|
|
|
/*
|
2008-02-29 22:27:19 +00:00
|
|
|
* XXX - Libalias checksum offload 'duct tape':
|
|
|
|
*
|
mostly style changes, such as removal of trailing whitespace,
reformatting to avoid unnecessary line breaks, small block
restructuring to avoid unnecessary nesting, replace macros
with function calls, etc.
As a side effect of code restructuring, this commit fixes one bug:
previously, if a realloc() failed, memory was leaked. Now, the
realloc is not there anymore, as we first count how much memory
we need and then do a single malloc.
2009-12-23 18:53:11 +00:00
|
|
|
* locally generated packets have only pseudo-header checksum
|
|
|
|
* calculated and libalias will break it[1], so mark them for
|
|
|
|
* later fix. Moreover there are cases when libalias modifies
|
|
|
|
* tcp packet data[2], mark them for later fix too.
|
|
|
|
*
|
|
|
|
* [1] libalias was never meant to run in kernel, so it does
|
|
|
|
* not have any knowledge about checksum offloading, and
|
|
|
|
* expects a packet with a full internet checksum.
|
|
|
|
* Unfortunately, packets generated locally will have just the
|
|
|
|
* pseudo header calculated, and when libalias tries to adjust
|
|
|
|
* the checksum it will actually compute a wrong value.
|
2008-02-29 22:27:19 +00:00
|
|
|
*
|
mostly style changes, such as removal of trailing whitespace,
reformatting to avoid unnecessary line breaks, small block
restructuring to avoid unnecessary nesting, replace macros
with function calls, etc.
As a side effect of code restructuring, this commit fixes one bug:
previously, if a realloc() failed, memory was leaked. Now, the
realloc is not there anymore, as we first count how much memory
we need and then do a single malloc.
2009-12-23 18:53:11 +00:00
|
|
|
* [2] when libalias modifies tcp's data content, full TCP
|
|
|
|
* checksum has to be recomputed: the problem is that
|
|
|
|
* libalias does not have any idea about checksum offloading.
|
|
|
|
* To work around this, we do not do checksumming in LibAlias,
|
|
|
|
* but only mark the packets in th_x2 field. If we receive a
|
|
|
|
* marked packet, we calculate correct checksum for it
|
|
|
|
* aware of offloading. Why such a terrible hack instead of
|
|
|
|
* recalculating checksum for each packet?
|
|
|
|
* Because the previous checksum was not checked!
|
|
|
|
* Recalculating checksums for EVERY packet will hide ALL
|
|
|
|
* transmission errors. Yes, marked packets still suffer from
|
|
|
|
* this problem. But, sigh, natd(8) has this problem, too.
|
2008-02-29 22:27:19 +00:00
|
|
|
*
|
|
|
|
* TODO: -make libalias mbuf aware (so
|
|
|
|
* it can handle delayed checksum and tso)
|
|
|
|
*/
|
|
|
|
|
mostly style changes, such as removal of trailing whitespace,
reformatting to avoid unnecessary line breaks, small block
restructuring to avoid unnecessary nesting, replace macros
with function calls, etc.
As a side effect of code restructuring, this commit fixes one bug:
previously, if a realloc() failed, memory was leaked. Now, the
realloc is not there anymore, as we first count how much memory
we need and then do a single malloc.
2009-12-23 18:53:11 +00:00
|
|
|
if (mcl->m_pkthdr.rcvif == NULL &&
|
|
|
|
mcl->m_pkthdr.csum_flags & CSUM_DELAY_DATA)
|
2008-02-29 22:27:19 +00:00
|
|
|
ldt = 1;
|
|
|
|
|
|
|
|
c = mtod(mcl, char *);
|
2011-06-14 13:35:24 +00:00
|
|
|
|
|
|
|
/* Check if this is 'global' instance */
|
|
|
|
if (t == NULL) {
|
|
|
|
if (args->oif == NULL) {
|
|
|
|
/* Wrong direction, skip processing */
|
|
|
|
args->m = mcl;
|
|
|
|
return (IP_FW_NAT);
|
|
|
|
}
|
|
|
|
|
|
|
|
found = 0;
|
|
|
|
chain = &V_layer3_chain;
|
2012-11-05 22:54:00 +00:00
|
|
|
IPFW_RLOCK_ASSERT(chain);
|
2011-06-14 13:35:24 +00:00
|
|
|
/* Check every nat entry... */
|
|
|
|
LIST_FOREACH(t, &chain->nat, _next) {
|
|
|
|
if ((t->mode & PKT_ALIAS_SKIP_GLOBAL) != 0)
|
|
|
|
continue;
|
|
|
|
retval = LibAliasOutTry(t->lib, c,
|
|
|
|
mcl->m_len + M_TRAILINGSPACE(mcl), 0);
|
|
|
|
if (retval == PKT_ALIAS_OK) {
|
|
|
|
/* Nat instance recognises state */
|
|
|
|
found = 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (found != 1) {
|
|
|
|
/* No instance found, return ignore */
|
|
|
|
args->m = mcl;
|
|
|
|
return (IP_FW_NAT);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (args->oif == NULL)
|
|
|
|
retval = LibAliasIn(t->lib, c,
|
|
|
|
mcl->m_len + M_TRAILINGSPACE(mcl));
|
|
|
|
else
|
|
|
|
retval = LibAliasOut(t->lib, c,
|
|
|
|
mcl->m_len + M_TRAILINGSPACE(mcl));
|
|
|
|
}
|
2011-06-07 06:42:29 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* We drop packet when:
|
|
|
|
* 1. libalias returns PKT_ALIAS_ERROR;
|
|
|
|
* 2. For incoming packets:
|
|
|
|
* a) for unresolved fragments;
|
|
|
|
* b) libalias returns PKT_ALIAS_IGNORED and
|
|
|
|
* PKT_ALIAS_DENY_INCOMING flag is set.
|
|
|
|
*/
|
|
|
|
if (retval == PKT_ALIAS_ERROR ||
|
|
|
|
(args->oif == NULL && (retval == PKT_ALIAS_UNRESOLVED_FRAGMENT ||
|
|
|
|
(retval == PKT_ALIAS_IGNORED &&
|
2011-06-14 13:35:24 +00:00
|
|
|
(t->mode & PKT_ALIAS_DENY_INCOMING) != 0)))) {
|
2008-02-29 22:27:19 +00:00
|
|
|
/* XXX - should i add some logging? */
|
|
|
|
m_free(mcl);
|
|
|
|
args->m = NULL;
|
|
|
|
return (IP_FW_DENY);
|
|
|
|
}
|
2011-06-07 06:42:29 +00:00
|
|
|
|
|
|
|
if (retval == PKT_ALIAS_RESPOND)
|
2012-02-22 04:19:33 +00:00
|
|
|
mcl->m_flags |= M_SKIP_FIREWALL;
|
mostly style changes, such as removal of trailing whitespace,
reformatting to avoid unnecessary line breaks, small block
restructuring to avoid unnecessary nesting, replace macros
with function calls, etc.
As a side effect of code restructuring, this commit fixes one bug:
previously, if a realloc() failed, memory was leaked. Now, the
realloc is not there anymore, as we first count how much memory
we need and then do a single malloc.
2009-12-23 18:53:11 +00:00
|
|
|
mcl->m_pkthdr.len = mcl->m_len = ntohs(ip->ip_len);
|
2008-02-29 22:27:19 +00:00
|
|
|
|
mostly style changes, such as removal of trailing whitespace,
reformatting to avoid unnecessary line breaks, small block
restructuring to avoid unnecessary nesting, replace macros
with function calls, etc.
As a side effect of code restructuring, this commit fixes one bug:
previously, if a realloc() failed, memory was leaked. Now, the
realloc is not there anymore, as we first count how much memory
we need and then do a single malloc.
2009-12-23 18:53:11 +00:00
|
|
|
/*
|
|
|
|
* XXX - libalias checksum offload
|
|
|
|
* 'duct tape' (see above)
|
2008-02-29 22:27:19 +00:00
|
|
|
*/
|
|
|
|
|
mostly style changes, such as removal of trailing whitespace,
reformatting to avoid unnecessary line breaks, small block
restructuring to avoid unnecessary nesting, replace macros
with function calls, etc.
As a side effect of code restructuring, this commit fixes one bug:
previously, if a realloc() failed, memory was leaked. Now, the
realloc is not there anymore, as we first count how much memory
we need and then do a single malloc.
2009-12-23 18:53:11 +00:00
|
|
|
if ((ip->ip_off & htons(IP_OFFMASK)) == 0 &&
|
2008-02-29 22:27:19 +00:00
|
|
|
ip->ip_p == IPPROTO_TCP) {
|
mostly style changes, such as removal of trailing whitespace,
reformatting to avoid unnecessary line breaks, small block
restructuring to avoid unnecessary nesting, replace macros
with function calls, etc.
As a side effect of code restructuring, this commit fixes one bug:
previously, if a realloc() failed, memory was leaked. Now, the
realloc is not there anymore, as we first count how much memory
we need and then do a single malloc.
2009-12-23 18:53:11 +00:00
|
|
|
struct tcphdr *th;
|
2008-02-29 22:27:19 +00:00
|
|
|
|
|
|
|
th = (struct tcphdr *)(ip + 1);
|
mostly style changes, such as removal of trailing whitespace,
reformatting to avoid unnecessary line breaks, small block
restructuring to avoid unnecessary nesting, replace macros
with function calls, etc.
As a side effect of code restructuring, this commit fixes one bug:
previously, if a realloc() failed, memory was leaked. Now, the
realloc is not there anymore, as we first count how much memory
we need and then do a single malloc.
2009-12-23 18:53:11 +00:00
|
|
|
if (th->th_x2)
|
2008-02-29 22:27:19 +00:00
|
|
|
ldt = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ldt) {
|
|
|
|
struct tcphdr *th;
|
|
|
|
struct udphdr *uh;
|
After r241245 it appeared that in_delayed_cksum(), which still expects
host byte order, was sometimes called with net byte order. Since we are
moving towards net byte order throughout the stack, the function was
converted to expect net byte order, and its consumers fixed appropriately:
- ip_output(), ipfilter(4) not changed, since already call
in_delayed_cksum() with header in net byte order.
- divert(4), ng_nat(4), ipfw_nat(4) now don't need to swap byte order
there and back.
- mrouting code and IPv6 ipsec now need to switch byte order there and
back, but I hope, this is temporary solution.
- In ipsec(4) shifted switch to net byte order prior to in_delayed_cksum().
- pf_route() catches up on r241245 changes to ip_output().
2012-10-08 08:03:58 +00:00
|
|
|
uint16_t ip_len, cksum;
|
2008-02-29 22:27:19 +00:00
|
|
|
|
After r241245 it appeared that in_delayed_cksum(), which still expects
host byte order, was sometimes called with net byte order. Since we are
moving towards net byte order throughout the stack, the function was
converted to expect net byte order, and its consumers fixed appropriately:
- ip_output(), ipfilter(4) not changed, since already call
in_delayed_cksum() with header in net byte order.
- divert(4), ng_nat(4), ipfw_nat(4) now don't need to swap byte order
there and back.
- mrouting code and IPv6 ipsec now need to switch byte order there and
back, but I hope, this is temporary solution.
- In ipsec(4) shifted switch to net byte order prior to in_delayed_cksum().
- pf_route() catches up on r241245 changes to ip_output().
2012-10-08 08:03:58 +00:00
|
|
|
ip_len = ntohs(ip->ip_len);
|
2010-09-06 13:17:01 +00:00
|
|
|
cksum = in_pseudo(ip->ip_src.s_addr, ip->ip_dst.s_addr,
|
After r241245 it appeared that in_delayed_cksum(), which still expects
host byte order, was sometimes called with net byte order. Since we are
moving towards net byte order throughout the stack, the function was
converted to expect net byte order, and its consumers fixed appropriately:
- ip_output(), ipfilter(4) not changed, since already call
in_delayed_cksum() with header in net byte order.
- divert(4), ng_nat(4), ipfw_nat(4) now don't need to swap byte order
there and back.
- mrouting code and IPv6 ipsec now need to switch byte order there and
back, but I hope, this is temporary solution.
- In ipsec(4) shifted switch to net byte order prior to in_delayed_cksum().
- pf_route() catches up on r241245 changes to ip_output().
2012-10-08 08:03:58 +00:00
|
|
|
htons(ip->ip_p + ip_len - (ip->ip_hl << 2)));
|
mostly style changes, such as removal of trailing whitespace,
reformatting to avoid unnecessary line breaks, small block
restructuring to avoid unnecessary nesting, replace macros
with function calls, etc.
As a side effect of code restructuring, this commit fixes one bug:
previously, if a realloc() failed, memory was leaked. Now, the
realloc is not there anymore, as we first count how much memory
we need and then do a single malloc.
2009-12-23 18:53:11 +00:00
|
|
|
|
2008-02-29 22:27:19 +00:00
|
|
|
switch (ip->ip_p) {
|
|
|
|
case IPPROTO_TCP:
|
|
|
|
th = (struct tcphdr *)(ip + 1);
|
mostly style changes, such as removal of trailing whitespace,
reformatting to avoid unnecessary line breaks, small block
restructuring to avoid unnecessary nesting, replace macros
with function calls, etc.
As a side effect of code restructuring, this commit fixes one bug:
previously, if a realloc() failed, memory was leaked. Now, the
realloc is not there anymore, as we first count how much memory
we need and then do a single malloc.
2009-12-23 18:53:11 +00:00
|
|
|
/*
|
|
|
|
* Maybe it was set in
|
|
|
|
* libalias...
|
2008-02-29 22:27:19 +00:00
|
|
|
*/
|
|
|
|
th->th_x2 = 0;
|
|
|
|
th->th_sum = cksum;
|
mostly style changes, such as removal of trailing whitespace,
reformatting to avoid unnecessary line breaks, small block
restructuring to avoid unnecessary nesting, replace macros
with function calls, etc.
As a side effect of code restructuring, this commit fixes one bug:
previously, if a realloc() failed, memory was leaked. Now, the
realloc is not there anymore, as we first count how much memory
we need and then do a single malloc.
2009-12-23 18:53:11 +00:00
|
|
|
mcl->m_pkthdr.csum_data =
|
2008-02-29 22:27:19 +00:00
|
|
|
offsetof(struct tcphdr, th_sum);
|
|
|
|
break;
|
|
|
|
case IPPROTO_UDP:
|
|
|
|
uh = (struct udphdr *)(ip + 1);
|
|
|
|
uh->uh_sum = cksum;
|
mostly style changes, such as removal of trailing whitespace,
reformatting to avoid unnecessary line breaks, small block
restructuring to avoid unnecessary nesting, replace macros
with function calls, etc.
As a side effect of code restructuring, this commit fixes one bug:
previously, if a realloc() failed, memory was leaked. Now, the
realloc is not there anymore, as we first count how much memory
we need and then do a single malloc.
2009-12-23 18:53:11 +00:00
|
|
|
mcl->m_pkthdr.csum_data =
|
2008-02-29 22:27:19 +00:00
|
|
|
offsetof(struct udphdr, uh_sum);
|
mostly style changes, such as removal of trailing whitespace,
reformatting to avoid unnecessary line breaks, small block
restructuring to avoid unnecessary nesting, replace macros
with function calls, etc.
As a side effect of code restructuring, this commit fixes one bug:
previously, if a realloc() failed, memory was leaked. Now, the
realloc is not there anymore, as we first count how much memory
we need and then do a single malloc.
2009-12-23 18:53:11 +00:00
|
|
|
break;
|
2008-02-29 22:27:19 +00:00
|
|
|
}
|
mostly style changes, such as removal of trailing whitespace,
reformatting to avoid unnecessary line breaks, small block
restructuring to avoid unnecessary nesting, replace macros
with function calls, etc.
As a side effect of code restructuring, this commit fixes one bug:
previously, if a realloc() failed, memory was leaked. Now, the
realloc is not there anymore, as we first count how much memory
we need and then do a single malloc.
2009-12-23 18:53:11 +00:00
|
|
|
/* No hw checksum offloading: do it ourselves */
|
|
|
|
if ((mcl->m_pkthdr.csum_flags & CSUM_DELAY_DATA) == 0) {
|
2008-02-29 22:27:19 +00:00
|
|
|
in_delayed_cksum(mcl);
|
mostly style changes, such as removal of trailing whitespace,
reformatting to avoid unnecessary line breaks, small block
restructuring to avoid unnecessary nesting, replace macros
with function calls, etc.
As a side effect of code restructuring, this commit fixes one bug:
previously, if a realloc() failed, memory was leaked. Now, the
realloc is not there anymore, as we first count how much memory
we need and then do a single malloc.
2009-12-23 18:53:11 +00:00
|
|
|
mcl->m_pkthdr.csum_flags &= ~CSUM_DELAY_DATA;
|
2008-02-29 22:27:19 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
args->m = mcl;
|
|
|
|
return (IP_FW_NAT);
|
|
|
|
}
|
|
|
|
|
2009-12-15 16:15:14 +00:00
|
|
|
static struct cfg_nat *
|
|
|
|
lookup_nat(struct nat_list *l, int nat_id)
|
|
|
|
{
|
|
|
|
struct cfg_nat *res;
|
|
|
|
|
mostly style changes, such as removal of trailing whitespace,
reformatting to avoid unnecessary line breaks, small block
restructuring to avoid unnecessary nesting, replace macros
with function calls, etc.
As a side effect of code restructuring, this commit fixes one bug:
previously, if a realloc() failed, memory was leaked. Now, the
realloc is not there anymore, as we first count how much memory
we need and then do a single malloc.
2009-12-23 18:53:11 +00:00
|
|
|
LIST_FOREACH(res, l, _next) {
|
|
|
|
if (res->id == nat_id)
|
|
|
|
break;
|
|
|
|
}
|
2009-12-15 16:15:14 +00:00
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2014-09-07 18:30:29 +00:00
|
|
|
static struct cfg_nat *
|
|
|
|
lookup_nat_name(struct nat_list *l, char *name)
|
2008-02-29 22:27:19 +00:00
|
|
|
{
|
2014-09-07 18:30:29 +00:00
|
|
|
struct cfg_nat *res;
|
|
|
|
int id;
|
|
|
|
char *errptr;
|
2008-02-29 22:27:19 +00:00
|
|
|
|
2014-09-07 18:30:29 +00:00
|
|
|
id = strtol(name, &errptr, 10);
|
|
|
|
if (id == 0 || *errptr != '\0')
|
|
|
|
return (NULL);
|
2011-04-19 15:06:33 +00:00
|
|
|
|
2014-09-07 18:30:29 +00:00
|
|
|
LIST_FOREACH(res, l, _next) {
|
|
|
|
if (res->id == id)
|
|
|
|
break;
|
2011-04-19 15:06:33 +00:00
|
|
|
}
|
2014-09-07 18:30:29 +00:00
|
|
|
return (res);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* IP_FW3 configuration routines */
|
|
|
|
|
|
|
|
static void
|
|
|
|
nat44_config(struct ip_fw_chain *chain, struct nat44_cfg_nat *ucfg)
|
|
|
|
{
|
|
|
|
struct cfg_nat *ptr, *tcfg;
|
|
|
|
int gencnt;
|
2008-02-29 22:27:19 +00:00
|
|
|
|
mostly style changes, such as removal of trailing whitespace,
reformatting to avoid unnecessary line breaks, small block
restructuring to avoid unnecessary nesting, replace macros
with function calls, etc.
As a side effect of code restructuring, this commit fixes one bug:
previously, if a realloc() failed, memory was leaked. Now, the
realloc is not there anymore, as we first count how much memory
we need and then do a single malloc.
2009-12-23 18:53:11 +00:00
|
|
|
/*
|
2008-02-29 22:27:19 +00:00
|
|
|
* Find/create nat rule.
|
|
|
|
*/
|
2014-09-07 18:30:29 +00:00
|
|
|
IPFW_UH_WLOCK(chain);
|
2011-04-19 15:06:33 +00:00
|
|
|
gencnt = chain->gencnt;
|
2014-09-07 18:30:29 +00:00
|
|
|
ptr = lookup_nat_name(&chain->nat, ucfg->name);
|
2008-02-29 22:27:19 +00:00
|
|
|
if (ptr == NULL) {
|
2014-09-07 18:30:29 +00:00
|
|
|
IPFW_UH_WUNLOCK(chain);
|
2008-02-29 22:27:19 +00:00
|
|
|
/* New rule: allocate and init new instance. */
|
2011-04-18 20:07:08 +00:00
|
|
|
ptr = malloc(sizeof(struct cfg_nat), M_IPFW, M_WAITOK | M_ZERO);
|
2008-02-29 22:27:19 +00:00
|
|
|
ptr->lib = LibAliasInit(NULL);
|
|
|
|
LIST_INIT(&ptr->redir_chain);
|
|
|
|
} else {
|
2011-04-19 15:06:33 +00:00
|
|
|
/* Entry already present: temporarily unhook it. */
|
2014-09-07 18:30:29 +00:00
|
|
|
IPFW_WLOCK(chain);
|
2009-12-23 12:15:21 +00:00
|
|
|
LIST_REMOVE(ptr, _next);
|
2014-09-07 18:30:29 +00:00
|
|
|
flush_nat_ptrs(chain, ptr->id);
|
2011-04-18 20:07:08 +00:00
|
|
|
IPFW_WUNLOCK(chain);
|
2014-09-07 18:30:29 +00:00
|
|
|
IPFW_UH_WUNLOCK(chain);
|
2008-02-29 22:27:19 +00:00
|
|
|
}
|
|
|
|
|
mostly style changes, such as removal of trailing whitespace,
reformatting to avoid unnecessary line breaks, small block
restructuring to avoid unnecessary nesting, replace macros
with function calls, etc.
As a side effect of code restructuring, this commit fixes one bug:
previously, if a realloc() failed, memory was leaked. Now, the
realloc is not there anymore, as we first count how much memory
we need and then do a single malloc.
2009-12-23 18:53:11 +00:00
|
|
|
/*
|
2014-09-07 18:30:29 +00:00
|
|
|
* Basic nat (re)configuration.
|
2008-02-29 22:27:19 +00:00
|
|
|
*/
|
2014-09-07 18:30:29 +00:00
|
|
|
ptr->id = strtol(ucfg->name, NULL, 10);
|
mostly style changes, such as removal of trailing whitespace,
reformatting to avoid unnecessary line breaks, small block
restructuring to avoid unnecessary nesting, replace macros
with function calls, etc.
As a side effect of code restructuring, this commit fixes one bug:
previously, if a realloc() failed, memory was leaked. Now, the
realloc is not there anymore, as we first count how much memory
we need and then do a single malloc.
2009-12-23 18:53:11 +00:00
|
|
|
/*
|
|
|
|
* XXX - what if this rule doesn't nat any ip and just
|
|
|
|
* redirect?
|
2008-02-29 22:27:19 +00:00
|
|
|
* do we set aliasaddress to 0.0.0.0?
|
|
|
|
*/
|
2014-09-07 18:30:29 +00:00
|
|
|
ptr->ip = ucfg->ip;
|
|
|
|
ptr->redir_cnt = ucfg->redir_cnt;
|
|
|
|
ptr->mode = ucfg->mode;
|
|
|
|
strlcpy(ptr->if_name, ucfg->if_name, sizeof(ptr->if_name));
|
|
|
|
LibAliasSetMode(ptr->lib, ptr->mode, ~0);
|
2008-02-29 22:27:19 +00:00
|
|
|
LibAliasSetAddress(ptr->lib, ptr->ip);
|
|
|
|
|
mostly style changes, such as removal of trailing whitespace,
reformatting to avoid unnecessary line breaks, small block
restructuring to avoid unnecessary nesting, replace macros
with function calls, etc.
As a side effect of code restructuring, this commit fixes one bug:
previously, if a realloc() failed, memory was leaked. Now, the
realloc is not there anymore, as we first count how much memory
we need and then do a single malloc.
2009-12-23 18:53:11 +00:00
|
|
|
/*
|
2008-02-29 22:27:19 +00:00
|
|
|
* Redir and LSNAT configuration.
|
|
|
|
*/
|
|
|
|
/* Delete old cfgs. */
|
|
|
|
del_redir_spool_cfg(ptr, &ptr->redir_chain);
|
|
|
|
/* Add new entries. */
|
2014-09-07 18:30:29 +00:00
|
|
|
add_redir_spool_cfg((char *)(ucfg + 1), ptr);
|
|
|
|
IPFW_UH_WLOCK(chain);
|
2011-04-19 15:06:33 +00:00
|
|
|
|
|
|
|
/* Extra check to avoid race with another ipfw_nat_cfg() */
|
2014-09-07 18:30:29 +00:00
|
|
|
tcfg = NULL;
|
|
|
|
if (gencnt != chain->gencnt)
|
|
|
|
tcfg = lookup_nat_name(&chain->nat, ucfg->name);
|
|
|
|
IPFW_WLOCK(chain);
|
|
|
|
if (tcfg != NULL)
|
|
|
|
LIST_REMOVE(tcfg, _next);
|
2009-12-23 12:15:21 +00:00
|
|
|
LIST_INSERT_HEAD(&chain->nat, ptr, _next);
|
2014-09-07 18:30:29 +00:00
|
|
|
IPFW_WUNLOCK(chain);
|
2011-04-19 15:06:33 +00:00
|
|
|
chain->gencnt++;
|
2014-09-07 18:30:29 +00:00
|
|
|
|
|
|
|
IPFW_UH_WUNLOCK(chain);
|
|
|
|
|
|
|
|
if (tcfg != NULL)
|
2015-04-27 09:16:22 +00:00
|
|
|
free_nat_instance(ptr);
|
2014-09-07 18:30:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Creates/configure nat44 instance
|
|
|
|
* Data layout (v0)(current):
|
|
|
|
* Request: [ ipfw_obj_header nat44_cfg_nat .. ]
|
|
|
|
*
|
|
|
|
* Returns 0 on success
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
nat44_cfg(struct ip_fw_chain *chain, ip_fw3_opheader *op3,
|
|
|
|
struct sockopt_data *sd)
|
|
|
|
{
|
|
|
|
ipfw_obj_header *oh;
|
|
|
|
struct nat44_cfg_nat *ucfg;
|
|
|
|
int id;
|
|
|
|
size_t read;
|
|
|
|
char *errptr;
|
|
|
|
|
|
|
|
/* Check minimum header size */
|
|
|
|
if (sd->valsize < (sizeof(*oh) + sizeof(*ucfg)))
|
|
|
|
return (EINVAL);
|
|
|
|
|
|
|
|
oh = (ipfw_obj_header *)sd->kbuf;
|
|
|
|
|
|
|
|
/* Basic length checks for TLVs */
|
|
|
|
if (oh->ntlv.head.length != sizeof(oh->ntlv))
|
|
|
|
return (EINVAL);
|
|
|
|
|
|
|
|
ucfg = (struct nat44_cfg_nat *)(oh + 1);
|
|
|
|
|
|
|
|
/* Check if name is properly terminated and looks like number */
|
|
|
|
if (strnlen(ucfg->name, sizeof(ucfg->name)) == sizeof(ucfg->name))
|
|
|
|
return (EINVAL);
|
|
|
|
id = strtol(ucfg->name, &errptr, 10);
|
|
|
|
if (id == 0 || *errptr != '\0')
|
|
|
|
return (EINVAL);
|
|
|
|
|
|
|
|
read = sizeof(*oh) + sizeof(*ucfg);
|
|
|
|
/* Check number of redirs */
|
|
|
|
if (sd->valsize < read + ucfg->redir_cnt*sizeof(struct nat44_cfg_redir))
|
|
|
|
return (EINVAL);
|
|
|
|
|
|
|
|
nat44_config(chain, ucfg);
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Destroys given nat instances.
|
|
|
|
* Data layout (v0)(current):
|
|
|
|
* Request: [ ipfw_obj_header ]
|
|
|
|
*
|
|
|
|
* Returns 0 on success
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
nat44_destroy(struct ip_fw_chain *chain, ip_fw3_opheader *op3,
|
|
|
|
struct sockopt_data *sd)
|
|
|
|
{
|
|
|
|
ipfw_obj_header *oh;
|
|
|
|
struct cfg_nat *ptr;
|
|
|
|
ipfw_obj_ntlv *ntlv;
|
|
|
|
|
|
|
|
/* Check minimum header size */
|
|
|
|
if (sd->valsize < sizeof(*oh))
|
|
|
|
return (EINVAL);
|
|
|
|
|
|
|
|
oh = (ipfw_obj_header *)sd->kbuf;
|
|
|
|
|
|
|
|
/* Basic length checks for TLVs */
|
|
|
|
if (oh->ntlv.head.length != sizeof(oh->ntlv))
|
|
|
|
return (EINVAL);
|
|
|
|
|
|
|
|
ntlv = &oh->ntlv;
|
|
|
|
/* Check if name is properly terminated */
|
|
|
|
if (strnlen(ntlv->name, sizeof(ntlv->name)) == sizeof(ntlv->name))
|
|
|
|
return (EINVAL);
|
|
|
|
|
|
|
|
IPFW_UH_WLOCK(chain);
|
|
|
|
ptr = lookup_nat_name(&chain->nat, ntlv->name);
|
|
|
|
if (ptr == NULL) {
|
|
|
|
IPFW_UH_WUNLOCK(chain);
|
|
|
|
return (ESRCH);
|
|
|
|
}
|
|
|
|
IPFW_WLOCK(chain);
|
|
|
|
LIST_REMOVE(ptr, _next);
|
|
|
|
flush_nat_ptrs(chain, ptr->id);
|
2009-12-23 12:15:21 +00:00
|
|
|
IPFW_WUNLOCK(chain);
|
2014-09-07 18:30:29 +00:00
|
|
|
IPFW_UH_WUNLOCK(chain);
|
|
|
|
|
2015-04-27 09:16:22 +00:00
|
|
|
free_nat_instance(ptr);
|
2014-09-07 18:30:29 +00:00
|
|
|
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
export_nat_cfg(struct cfg_nat *ptr, struct nat44_cfg_nat *ucfg)
|
|
|
|
{
|
|
|
|
|
|
|
|
snprintf(ucfg->name, sizeof(ucfg->name), "%d", ptr->id);
|
|
|
|
ucfg->ip = ptr->ip;
|
|
|
|
ucfg->redir_cnt = ptr->redir_cnt;
|
|
|
|
ucfg->mode = ptr->mode;
|
|
|
|
strlcpy(ucfg->if_name, ptr->if_name, sizeof(ucfg->if_name));
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Gets config for given nat instance
|
|
|
|
* Data layout (v0)(current):
|
|
|
|
* Request: [ ipfw_obj_header nat44_cfg_nat .. ]
|
|
|
|
*
|
|
|
|
* Returns 0 on success
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
nat44_get_cfg(struct ip_fw_chain *chain, ip_fw3_opheader *op3,
|
|
|
|
struct sockopt_data *sd)
|
|
|
|
{
|
|
|
|
ipfw_obj_header *oh;
|
|
|
|
struct nat44_cfg_nat *ucfg;
|
|
|
|
struct cfg_nat *ptr;
|
|
|
|
struct cfg_redir *r;
|
|
|
|
struct cfg_spool *s;
|
|
|
|
struct nat44_cfg_redir *ser_r;
|
|
|
|
struct nat44_cfg_spool *ser_s;
|
|
|
|
size_t sz;
|
|
|
|
|
|
|
|
sz = sizeof(*oh) + sizeof(*ucfg);
|
|
|
|
/* Check minimum header size */
|
|
|
|
if (sd->valsize < sz)
|
|
|
|
return (EINVAL);
|
|
|
|
|
|
|
|
oh = (struct _ipfw_obj_header *)ipfw_get_sopt_header(sd, sz);
|
|
|
|
|
|
|
|
/* Basic length checks for TLVs */
|
|
|
|
if (oh->ntlv.head.length != sizeof(oh->ntlv))
|
|
|
|
return (EINVAL);
|
|
|
|
|
|
|
|
ucfg = (struct nat44_cfg_nat *)(oh + 1);
|
|
|
|
|
|
|
|
/* Check if name is properly terminated */
|
|
|
|
if (strnlen(ucfg->name, sizeof(ucfg->name)) == sizeof(ucfg->name))
|
|
|
|
return (EINVAL);
|
|
|
|
|
|
|
|
IPFW_UH_RLOCK(chain);
|
|
|
|
ptr = lookup_nat_name(&chain->nat, ucfg->name);
|
|
|
|
if (ptr == NULL) {
|
|
|
|
IPFW_UH_RUNLOCK(chain);
|
|
|
|
return (ESRCH);
|
|
|
|
}
|
|
|
|
|
|
|
|
export_nat_cfg(ptr, ucfg);
|
|
|
|
|
|
|
|
/* Estimate memory amount */
|
2015-02-05 14:54:53 +00:00
|
|
|
sz = sizeof(ipfw_obj_header) + sizeof(struct nat44_cfg_nat);
|
2014-09-07 18:30:29 +00:00
|
|
|
LIST_FOREACH(r, &ptr->redir_chain, _next) {
|
|
|
|
sz += sizeof(struct nat44_cfg_redir);
|
|
|
|
LIST_FOREACH(s, &r->spool_chain, _next)
|
|
|
|
sz += sizeof(struct nat44_cfg_spool);
|
|
|
|
}
|
|
|
|
|
|
|
|
ucfg->size = sz;
|
2015-02-05 14:54:53 +00:00
|
|
|
if (sd->valsize < sz) {
|
2014-09-07 18:30:29 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Submitted buffer size is not enough.
|
|
|
|
* WE've already filled in @ucfg structure with
|
|
|
|
* relevant info including size, so we
|
|
|
|
* can return. Buffer will be flushed automatically.
|
|
|
|
*/
|
|
|
|
IPFW_UH_RUNLOCK(chain);
|
|
|
|
return (ENOMEM);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Size OK, let's copy data */
|
|
|
|
LIST_FOREACH(r, &ptr->redir_chain, _next) {
|
|
|
|
ser_r = (struct nat44_cfg_redir *)ipfw_get_sopt_space(sd,
|
|
|
|
sizeof(*ser_r));
|
|
|
|
ser_r->mode = r->mode;
|
|
|
|
ser_r->laddr = r->laddr;
|
|
|
|
ser_r->paddr = r->paddr;
|
|
|
|
ser_r->raddr = r->raddr;
|
|
|
|
ser_r->lport = r->lport;
|
|
|
|
ser_r->pport = r->pport;
|
|
|
|
ser_r->rport = r->rport;
|
|
|
|
ser_r->pport_cnt = r->pport_cnt;
|
|
|
|
ser_r->rport_cnt = r->rport_cnt;
|
|
|
|
ser_r->proto = r->proto;
|
|
|
|
ser_r->spool_cnt = r->spool_cnt;
|
|
|
|
|
|
|
|
LIST_FOREACH(s, &r->spool_chain, _next) {
|
|
|
|
ser_s = (struct nat44_cfg_spool *)ipfw_get_sopt_space(
|
|
|
|
sd, sizeof(*ser_s));
|
|
|
|
|
|
|
|
ser_s->addr = s->addr;
|
|
|
|
ser_s->port = s->port;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
IPFW_UH_RUNLOCK(chain);
|
|
|
|
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Lists all nat44 instances currently available in kernel.
|
|
|
|
* Data layout (v0)(current):
|
|
|
|
* Request: [ ipfw_obj_lheader ]
|
|
|
|
* Reply: [ ipfw_obj_lheader nat44_cfg_nat x N ]
|
|
|
|
*
|
|
|
|
* Returns 0 on success
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
nat44_list_nat(struct ip_fw_chain *chain, ip_fw3_opheader *op3,
|
|
|
|
struct sockopt_data *sd)
|
|
|
|
{
|
|
|
|
ipfw_obj_lheader *olh;
|
|
|
|
struct nat44_cfg_nat *ucfg;
|
|
|
|
struct cfg_nat *ptr;
|
|
|
|
int nat_count;
|
|
|
|
|
|
|
|
/* Check minimum header size */
|
|
|
|
if (sd->valsize < sizeof(ipfw_obj_lheader))
|
|
|
|
return (EINVAL);
|
|
|
|
|
|
|
|
olh = (ipfw_obj_lheader *)ipfw_get_sopt_header(sd, sizeof(*olh));
|
|
|
|
IPFW_UH_RLOCK(chain);
|
|
|
|
nat_count = 0;
|
|
|
|
LIST_FOREACH(ptr, &chain->nat, _next)
|
|
|
|
nat_count++;
|
|
|
|
|
|
|
|
olh->count = nat_count;
|
|
|
|
olh->objsize = sizeof(struct nat44_cfg_nat);
|
|
|
|
olh->size = sizeof(*olh) + olh->count * olh->objsize;
|
|
|
|
|
|
|
|
if (sd->valsize < olh->size) {
|
|
|
|
IPFW_UH_RUNLOCK(chain);
|
|
|
|
return (ENOMEM);
|
|
|
|
}
|
|
|
|
|
|
|
|
LIST_FOREACH(ptr, &chain->nat, _next) {
|
|
|
|
ucfg = (struct nat44_cfg_nat *)ipfw_get_sopt_space(sd,
|
|
|
|
sizeof(*ucfg));
|
|
|
|
export_nat_cfg(ptr, ucfg);
|
|
|
|
}
|
|
|
|
|
|
|
|
IPFW_UH_RUNLOCK(chain);
|
|
|
|
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Gets log for given nat instance
|
|
|
|
* Data layout (v0)(current):
|
|
|
|
* Request: [ ipfw_obj_header nat44_cfg_nat ]
|
|
|
|
* Reply: [ ipfw_obj_header nat44_cfg_nat LOGBUFFER ]
|
|
|
|
*
|
|
|
|
* Returns 0 on success
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
nat44_get_log(struct ip_fw_chain *chain, ip_fw3_opheader *op3,
|
|
|
|
struct sockopt_data *sd)
|
|
|
|
{
|
|
|
|
ipfw_obj_header *oh;
|
|
|
|
struct nat44_cfg_nat *ucfg;
|
|
|
|
struct cfg_nat *ptr;
|
|
|
|
void *pbuf;
|
|
|
|
size_t sz;
|
|
|
|
|
|
|
|
sz = sizeof(*oh) + sizeof(*ucfg);
|
|
|
|
/* Check minimum header size */
|
|
|
|
if (sd->valsize < sz)
|
|
|
|
return (EINVAL);
|
|
|
|
|
|
|
|
oh = (struct _ipfw_obj_header *)ipfw_get_sopt_header(sd, sz);
|
|
|
|
|
|
|
|
/* Basic length checks for TLVs */
|
|
|
|
if (oh->ntlv.head.length != sizeof(oh->ntlv))
|
|
|
|
return (EINVAL);
|
|
|
|
|
|
|
|
ucfg = (struct nat44_cfg_nat *)(oh + 1);
|
|
|
|
|
|
|
|
/* Check if name is properly terminated */
|
|
|
|
if (strnlen(ucfg->name, sizeof(ucfg->name)) == sizeof(ucfg->name))
|
|
|
|
return (EINVAL);
|
|
|
|
|
|
|
|
IPFW_UH_RLOCK(chain);
|
|
|
|
ptr = lookup_nat_name(&chain->nat, ucfg->name);
|
|
|
|
if (ptr == NULL) {
|
|
|
|
IPFW_UH_RUNLOCK(chain);
|
|
|
|
return (ESRCH);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ptr->lib->logDesc == NULL) {
|
|
|
|
IPFW_UH_RUNLOCK(chain);
|
|
|
|
return (ENOENT);
|
|
|
|
}
|
|
|
|
|
|
|
|
export_nat_cfg(ptr, ucfg);
|
|
|
|
|
|
|
|
/* Estimate memory amount */
|
|
|
|
ucfg->size = sizeof(struct nat44_cfg_nat) + LIBALIAS_BUF_SIZE;
|
|
|
|
if (sd->valsize < sz + sizeof(*oh)) {
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Submitted buffer size is not enough.
|
|
|
|
* WE've already filled in @ucfg structure with
|
|
|
|
* relevant info including size, so we
|
|
|
|
* can return. Buffer will be flushed automatically.
|
|
|
|
*/
|
|
|
|
IPFW_UH_RUNLOCK(chain);
|
|
|
|
return (ENOMEM);
|
|
|
|
}
|
|
|
|
|
|
|
|
pbuf = (void *)ipfw_get_sopt_space(sd, LIBALIAS_BUF_SIZE);
|
|
|
|
memcpy(pbuf, ptr->lib->logDesc, LIBALIAS_BUF_SIZE);
|
|
|
|
|
|
|
|
IPFW_UH_RUNLOCK(chain);
|
|
|
|
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct ipfw_sopt_handler scodes[] = {
|
|
|
|
{ IP_FW_NAT44_XCONFIG, 0, HDIR_SET, nat44_cfg },
|
|
|
|
{ IP_FW_NAT44_DESTROY, 0, HDIR_SET, nat44_destroy },
|
|
|
|
{ IP_FW_NAT44_XGETCONFIG, 0, HDIR_GET, nat44_get_cfg },
|
|
|
|
{ IP_FW_NAT44_LIST_NAT, 0, HDIR_GET, nat44_list_nat },
|
|
|
|
{ IP_FW_NAT44_XGETLOG, 0, HDIR_GET, nat44_get_log },
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Legacy configuration routines
|
|
|
|
*/
|
|
|
|
|
|
|
|
struct cfg_spool_legacy {
|
|
|
|
LIST_ENTRY(cfg_spool_legacy) _next;
|
|
|
|
struct in_addr addr;
|
|
|
|
u_short port;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct cfg_redir_legacy {
|
|
|
|
LIST_ENTRY(cfg_redir) _next;
|
|
|
|
u_int16_t mode;
|
|
|
|
struct in_addr laddr;
|
|
|
|
struct in_addr paddr;
|
|
|
|
struct in_addr raddr;
|
|
|
|
u_short lport;
|
|
|
|
u_short pport;
|
|
|
|
u_short rport;
|
|
|
|
u_short pport_cnt;
|
|
|
|
u_short rport_cnt;
|
|
|
|
int proto;
|
|
|
|
struct alias_link **alink;
|
|
|
|
u_int16_t spool_cnt;
|
|
|
|
LIST_HEAD(, cfg_spool_legacy) spool_chain;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct cfg_nat_legacy {
|
|
|
|
LIST_ENTRY(cfg_nat_legacy) _next;
|
|
|
|
int id;
|
|
|
|
struct in_addr ip;
|
|
|
|
char if_name[IF_NAMESIZE];
|
|
|
|
int mode;
|
|
|
|
struct libalias *lib;
|
|
|
|
int redir_cnt;
|
|
|
|
LIST_HEAD(, cfg_redir_legacy) redir_chain;
|
|
|
|
};
|
|
|
|
|
|
|
|
static int
|
|
|
|
ipfw_nat_cfg(struct sockopt *sopt)
|
|
|
|
{
|
|
|
|
struct cfg_nat_legacy *cfg;
|
|
|
|
struct nat44_cfg_nat *ucfg;
|
|
|
|
struct cfg_redir_legacy *rdir;
|
|
|
|
struct nat44_cfg_redir *urdir;
|
|
|
|
char *buf;
|
|
|
|
size_t len, len2;
|
|
|
|
int error, i;
|
|
|
|
|
|
|
|
len = sopt->sopt_valsize;
|
|
|
|
len2 = len + 128;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Allocate 2x buffer to store converted structures.
|
|
|
|
* new redir_cfg has shrinked, so we're sure that
|
|
|
|
* new buffer size is enough.
|
|
|
|
*/
|
|
|
|
buf = malloc(roundup2(len, 8) + len2, M_TEMP, M_WAITOK | M_ZERO);
|
|
|
|
error = sooptcopyin(sopt, buf, len, sizeof(struct cfg_nat_legacy));
|
|
|
|
if (error != 0)
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
cfg = (struct cfg_nat_legacy *)buf;
|
|
|
|
if (cfg->id < 0) {
|
|
|
|
error = EINVAL;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
ucfg = (struct nat44_cfg_nat *)&buf[roundup2(len, 8)];
|
|
|
|
snprintf(ucfg->name, sizeof(ucfg->name), "%d", cfg->id);
|
|
|
|
strlcpy(ucfg->if_name, cfg->if_name, sizeof(ucfg->if_name));
|
|
|
|
ucfg->ip = cfg->ip;
|
|
|
|
ucfg->mode = cfg->mode;
|
|
|
|
ucfg->redir_cnt = cfg->redir_cnt;
|
|
|
|
|
|
|
|
if (len < sizeof(*cfg) + cfg->redir_cnt * sizeof(*rdir)) {
|
|
|
|
error = EINVAL;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
urdir = (struct nat44_cfg_redir *)(ucfg + 1);
|
|
|
|
rdir = (struct cfg_redir_legacy *)(cfg + 1);
|
|
|
|
for (i = 0; i < cfg->redir_cnt; i++) {
|
|
|
|
urdir->mode = rdir->mode;
|
|
|
|
urdir->laddr = rdir->laddr;
|
|
|
|
urdir->paddr = rdir->paddr;
|
|
|
|
urdir->raddr = rdir->raddr;
|
|
|
|
urdir->lport = rdir->lport;
|
|
|
|
urdir->pport = rdir->pport;
|
|
|
|
urdir->rport = rdir->rport;
|
|
|
|
urdir->pport_cnt = rdir->pport_cnt;
|
|
|
|
urdir->rport_cnt = rdir->rport_cnt;
|
|
|
|
urdir->proto = rdir->proto;
|
|
|
|
urdir->spool_cnt = rdir->spool_cnt;
|
|
|
|
|
|
|
|
urdir++;
|
|
|
|
rdir++;
|
|
|
|
}
|
|
|
|
|
|
|
|
nat44_config(&V_layer3_chain, ucfg);
|
2011-04-19 15:06:33 +00:00
|
|
|
|
|
|
|
out:
|
|
|
|
free(buf, M_TEMP);
|
|
|
|
return (error);
|
2008-02-29 22:27:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
ipfw_nat_del(struct sockopt *sopt)
|
|
|
|
{
|
|
|
|
struct cfg_nat *ptr;
|
2009-12-23 12:15:21 +00:00
|
|
|
struct ip_fw_chain *chain = &V_layer3_chain;
|
2008-02-29 22:27:19 +00:00
|
|
|
int i;
|
mostly style changes, such as removal of trailing whitespace,
reformatting to avoid unnecessary line breaks, small block
restructuring to avoid unnecessary nesting, replace macros
with function calls, etc.
As a side effect of code restructuring, this commit fixes one bug:
previously, if a realloc() failed, memory was leaked. Now, the
realloc is not there anymore, as we first count how much memory
we need and then do a single malloc.
2009-12-23 18:53:11 +00:00
|
|
|
|
2008-02-29 22:27:19 +00:00
|
|
|
sooptcopyin(sopt, &i, sizeof i, sizeof i);
|
mostly style changes, such as removal of trailing whitespace,
reformatting to avoid unnecessary line breaks, small block
restructuring to avoid unnecessary nesting, replace macros
with function calls, etc.
As a side effect of code restructuring, this commit fixes one bug:
previously, if a realloc() failed, memory was leaked. Now, the
realloc is not there anymore, as we first count how much memory
we need and then do a single malloc.
2009-12-23 18:53:11 +00:00
|
|
|
/* XXX validate i */
|
2014-09-07 18:30:29 +00:00
|
|
|
IPFW_UH_WLOCK(chain);
|
mostly style changes, such as removal of trailing whitespace,
reformatting to avoid unnecessary line breaks, small block
restructuring to avoid unnecessary nesting, replace macros
with function calls, etc.
As a side effect of code restructuring, this commit fixes one bug:
previously, if a realloc() failed, memory was leaked. Now, the
realloc is not there anymore, as we first count how much memory
we need and then do a single malloc.
2009-12-23 18:53:11 +00:00
|
|
|
ptr = lookup_nat(&chain->nat, i);
|
2008-02-29 22:27:19 +00:00
|
|
|
if (ptr == NULL) {
|
2014-09-07 18:30:29 +00:00
|
|
|
IPFW_UH_WUNLOCK(chain);
|
2008-02-29 22:27:19 +00:00
|
|
|
return (EINVAL);
|
|
|
|
}
|
2014-09-07 18:30:29 +00:00
|
|
|
IPFW_WLOCK(chain);
|
2009-12-23 12:15:21 +00:00
|
|
|
LIST_REMOVE(ptr, _next);
|
|
|
|
flush_nat_ptrs(chain, i);
|
|
|
|
IPFW_WUNLOCK(chain);
|
2014-09-07 18:30:29 +00:00
|
|
|
IPFW_UH_WUNLOCK(chain);
|
2015-04-27 09:16:22 +00:00
|
|
|
free_nat_instance(ptr);
|
2008-02-29 22:27:19 +00:00
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
ipfw_nat_get_cfg(struct sockopt *sopt)
|
mostly style changes, such as removal of trailing whitespace,
reformatting to avoid unnecessary line breaks, small block
restructuring to avoid unnecessary nesting, replace macros
with function calls, etc.
As a side effect of code restructuring, this commit fixes one bug:
previously, if a realloc() failed, memory was leaked. Now, the
realloc is not there anymore, as we first count how much memory
we need and then do a single malloc.
2009-12-23 18:53:11 +00:00
|
|
|
{
|
2011-04-19 15:06:33 +00:00
|
|
|
struct ip_fw_chain *chain = &V_layer3_chain;
|
2008-02-29 22:27:19 +00:00
|
|
|
struct cfg_nat *n;
|
2014-09-07 18:30:29 +00:00
|
|
|
struct cfg_nat_legacy *ucfg;
|
2008-02-29 22:27:19 +00:00
|
|
|
struct cfg_redir *r;
|
|
|
|
struct cfg_spool *s;
|
2014-09-07 18:30:29 +00:00
|
|
|
struct cfg_redir_legacy *ser_r;
|
|
|
|
struct cfg_spool_legacy *ser_s;
|
2011-04-19 15:06:33 +00:00
|
|
|
char *data;
|
|
|
|
int gencnt, nat_cnt, len, error;
|
2009-12-23 12:15:21 +00:00
|
|
|
|
2008-02-29 22:27:19 +00:00
|
|
|
nat_cnt = 0;
|
2011-04-19 15:06:33 +00:00
|
|
|
len = sizeof(nat_cnt);
|
2008-02-29 22:27:19 +00:00
|
|
|
|
2014-09-07 18:30:29 +00:00
|
|
|
IPFW_UH_RLOCK(chain);
|
2011-04-19 15:06:33 +00:00
|
|
|
retry:
|
|
|
|
gencnt = chain->gencnt;
|
|
|
|
/* Estimate memory amount */
|
2009-12-23 12:15:21 +00:00
|
|
|
LIST_FOREACH(n, &chain->nat, _next) {
|
2008-02-29 22:27:19 +00:00
|
|
|
nat_cnt++;
|
2014-09-07 18:30:29 +00:00
|
|
|
len += sizeof(struct cfg_nat_legacy);
|
2011-04-19 15:06:33 +00:00
|
|
|
LIST_FOREACH(r, &n->redir_chain, _next) {
|
2014-09-07 18:30:29 +00:00
|
|
|
len += sizeof(struct cfg_redir_legacy);
|
2011-04-19 15:06:33 +00:00
|
|
|
LIST_FOREACH(s, &r->spool_chain, _next)
|
2014-09-07 18:30:29 +00:00
|
|
|
len += sizeof(struct cfg_spool_legacy);
|
2011-04-19 15:06:33 +00:00
|
|
|
}
|
|
|
|
}
|
2014-09-07 18:30:29 +00:00
|
|
|
IPFW_UH_RUNLOCK(chain);
|
2011-04-19 15:06:33 +00:00
|
|
|
|
|
|
|
data = malloc(len, M_TEMP, M_WAITOK | M_ZERO);
|
|
|
|
bcopy(&nat_cnt, data, sizeof(nat_cnt));
|
|
|
|
|
|
|
|
nat_cnt = 0;
|
|
|
|
len = sizeof(nat_cnt);
|
|
|
|
|
2014-09-07 18:30:29 +00:00
|
|
|
IPFW_UH_RLOCK(chain);
|
2011-04-19 15:06:33 +00:00
|
|
|
if (gencnt != chain->gencnt) {
|
|
|
|
free(data, M_TEMP);
|
|
|
|
goto retry;
|
|
|
|
}
|
|
|
|
/* Serialize all the data. */
|
|
|
|
LIST_FOREACH(n, &chain->nat, _next) {
|
2014-09-07 18:30:29 +00:00
|
|
|
ucfg = (struct cfg_nat_legacy *)&data[len];
|
|
|
|
ucfg->id = n->id;
|
|
|
|
ucfg->ip = n->ip;
|
|
|
|
ucfg->redir_cnt = n->redir_cnt;
|
|
|
|
ucfg->mode = n->mode;
|
|
|
|
strlcpy(ucfg->if_name, n->if_name, sizeof(ucfg->if_name));
|
|
|
|
len += sizeof(struct cfg_nat_legacy);
|
mostly style changes, such as removal of trailing whitespace,
reformatting to avoid unnecessary line breaks, small block
restructuring to avoid unnecessary nesting, replace macros
with function calls, etc.
As a side effect of code restructuring, this commit fixes one bug:
previously, if a realloc() failed, memory was leaked. Now, the
realloc is not there anymore, as we first count how much memory
we need and then do a single malloc.
2009-12-23 18:53:11 +00:00
|
|
|
LIST_FOREACH(r, &n->redir_chain, _next) {
|
2014-09-07 18:30:29 +00:00
|
|
|
ser_r = (struct cfg_redir_legacy *)&data[len];
|
|
|
|
ser_r->mode = r->mode;
|
|
|
|
ser_r->laddr = r->laddr;
|
|
|
|
ser_r->paddr = r->paddr;
|
|
|
|
ser_r->raddr = r->raddr;
|
|
|
|
ser_r->lport = r->lport;
|
|
|
|
ser_r->pport = r->pport;
|
|
|
|
ser_r->rport = r->rport;
|
|
|
|
ser_r->pport_cnt = r->pport_cnt;
|
|
|
|
ser_r->rport_cnt = r->rport_cnt;
|
|
|
|
ser_r->proto = r->proto;
|
|
|
|
ser_r->spool_cnt = r->spool_cnt;
|
|
|
|
len += sizeof(struct cfg_redir_legacy);
|
mostly style changes, such as removal of trailing whitespace,
reformatting to avoid unnecessary line breaks, small block
restructuring to avoid unnecessary nesting, replace macros
with function calls, etc.
As a side effect of code restructuring, this commit fixes one bug:
previously, if a realloc() failed, memory was leaked. Now, the
realloc is not there anymore, as we first count how much memory
we need and then do a single malloc.
2009-12-23 18:53:11 +00:00
|
|
|
LIST_FOREACH(s, &r->spool_chain, _next) {
|
2014-09-07 18:30:29 +00:00
|
|
|
ser_s = (struct cfg_spool_legacy *)&data[len];
|
|
|
|
ser_s->addr = s->addr;
|
|
|
|
ser_s->port = s->port;
|
|
|
|
len += sizeof(struct cfg_spool_legacy);
|
2008-02-29 22:27:19 +00:00
|
|
|
}
|
mostly style changes, such as removal of trailing whitespace,
reformatting to avoid unnecessary line breaks, small block
restructuring to avoid unnecessary nesting, replace macros
with function calls, etc.
As a side effect of code restructuring, this commit fixes one bug:
previously, if a realloc() failed, memory was leaked. Now, the
realloc is not there anymore, as we first count how much memory
we need and then do a single malloc.
2009-12-23 18:53:11 +00:00
|
|
|
}
|
2008-02-29 22:27:19 +00:00
|
|
|
}
|
2014-09-07 18:30:29 +00:00
|
|
|
IPFW_UH_RUNLOCK(chain);
|
2011-04-19 15:06:33 +00:00
|
|
|
|
|
|
|
error = sooptcopyout(sopt, data, len);
|
|
|
|
free(data, M_TEMP);
|
|
|
|
|
|
|
|
return (error);
|
2008-02-29 22:27:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
ipfw_nat_get_log(struct sockopt *sopt)
|
|
|
|
{
|
|
|
|
uint8_t *data;
|
|
|
|
struct cfg_nat *ptr;
|
mostly style changes, such as removal of trailing whitespace,
reformatting to avoid unnecessary line breaks, small block
restructuring to avoid unnecessary nesting, replace macros
with function calls, etc.
As a side effect of code restructuring, this commit fixes one bug:
previously, if a realloc() failed, memory was leaked. Now, the
realloc is not there anymore, as we first count how much memory
we need and then do a single malloc.
2009-12-23 18:53:11 +00:00
|
|
|
int i, size;
|
2009-12-23 12:15:21 +00:00
|
|
|
struct ip_fw_chain *chain;
|
2014-10-04 11:40:35 +00:00
|
|
|
IPFW_RLOCK_TRACKER;
|
2008-02-29 22:27:19 +00:00
|
|
|
|
2009-12-23 12:15:21 +00:00
|
|
|
chain = &V_layer3_chain;
|
2008-02-29 22:27:19 +00:00
|
|
|
|
2009-12-23 12:15:21 +00:00
|
|
|
IPFW_RLOCK(chain);
|
mostly style changes, such as removal of trailing whitespace,
reformatting to avoid unnecessary line breaks, small block
restructuring to avoid unnecessary nesting, replace macros
with function calls, etc.
As a side effect of code restructuring, this commit fixes one bug:
previously, if a realloc() failed, memory was leaked. Now, the
realloc is not there anymore, as we first count how much memory
we need and then do a single malloc.
2009-12-23 18:53:11 +00:00
|
|
|
/* one pass to count, one to copy the data */
|
|
|
|
i = 0;
|
2009-12-23 12:15:21 +00:00
|
|
|
LIST_FOREACH(ptr, &chain->nat, _next) {
|
mostly style changes, such as removal of trailing whitespace,
reformatting to avoid unnecessary line breaks, small block
restructuring to avoid unnecessary nesting, replace macros
with function calls, etc.
As a side effect of code restructuring, this commit fixes one bug:
previously, if a realloc() failed, memory was leaked. Now, the
realloc is not there anymore, as we first count how much memory
we need and then do a single malloc.
2009-12-23 18:53:11 +00:00
|
|
|
if (ptr->lib->logDesc == NULL)
|
|
|
|
continue;
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
size = i * (LIBALIAS_BUF_SIZE + sizeof(int));
|
|
|
|
data = malloc(size, M_IPFW, M_NOWAIT | M_ZERO);
|
|
|
|
if (data == NULL) {
|
|
|
|
IPFW_RUNLOCK(chain);
|
|
|
|
return (ENOSPC);
|
|
|
|
}
|
|
|
|
i = 0;
|
|
|
|
LIST_FOREACH(ptr, &chain->nat, _next) {
|
|
|
|
if (ptr->lib->logDesc == NULL)
|
2008-02-29 22:27:19 +00:00
|
|
|
continue;
|
|
|
|
bcopy(&ptr->id, &data[i], sizeof(int));
|
|
|
|
i += sizeof(int);
|
mostly style changes, such as removal of trailing whitespace,
reformatting to avoid unnecessary line breaks, small block
restructuring to avoid unnecessary nesting, replace macros
with function calls, etc.
As a side effect of code restructuring, this commit fixes one bug:
previously, if a realloc() failed, memory was leaked. Now, the
realloc is not there anymore, as we first count how much memory
we need and then do a single malloc.
2009-12-23 18:53:11 +00:00
|
|
|
bcopy(ptr->lib->logDesc, &data[i], LIBALIAS_BUF_SIZE);
|
|
|
|
i += LIBALIAS_BUF_SIZE;
|
2008-02-29 22:27:19 +00:00
|
|
|
}
|
2009-12-23 12:15:21 +00:00
|
|
|
IPFW_RUNLOCK(chain);
|
2008-02-29 22:27:19 +00:00
|
|
|
sooptcopyout(sopt, data, size);
|
|
|
|
free(data, M_IPFW);
|
|
|
|
return(0);
|
|
|
|
}
|
|
|
|
|
2013-08-24 11:59:51 +00:00
|
|
|
static int
|
|
|
|
vnet_ipfw_nat_init(const void *arg __unused)
|
|
|
|
{
|
|
|
|
|
|
|
|
V_ipfw_nat_ready = 1;
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
vnet_ipfw_nat_uninit(const void *arg __unused)
|
|
|
|
{
|
|
|
|
struct cfg_nat *ptr, *ptr_temp;
|
|
|
|
struct ip_fw_chain *chain;
|
|
|
|
|
|
|
|
chain = &V_layer3_chain;
|
|
|
|
IPFW_WLOCK(chain);
|
|
|
|
LIST_FOREACH_SAFE(ptr, &chain->nat, _next, ptr_temp) {
|
|
|
|
LIST_REMOVE(ptr, _next);
|
2015-04-27 09:16:22 +00:00
|
|
|
free_nat_instance(ptr);
|
2013-08-24 11:59:51 +00:00
|
|
|
}
|
|
|
|
flush_nat_ptrs(chain, -1 /* flush all */);
|
|
|
|
V_ipfw_nat_ready = 0;
|
|
|
|
IPFW_WUNLOCK(chain);
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
2008-02-29 22:27:19 +00:00
|
|
|
static void
|
|
|
|
ipfw_nat_init(void)
|
|
|
|
{
|
|
|
|
|
|
|
|
/* init ipfw hooks */
|
|
|
|
ipfw_nat_ptr = ipfw_nat;
|
2009-12-15 16:15:14 +00:00
|
|
|
lookup_nat_ptr = lookup_nat;
|
2008-02-29 22:27:19 +00:00
|
|
|
ipfw_nat_cfg_ptr = ipfw_nat_cfg;
|
|
|
|
ipfw_nat_del_ptr = ipfw_nat_del;
|
|
|
|
ipfw_nat_get_cfg_ptr = ipfw_nat_get_cfg;
|
|
|
|
ipfw_nat_get_log_ptr = ipfw_nat_get_log;
|
2014-09-07 18:30:29 +00:00
|
|
|
IPFW_ADD_SOPT_HANDLER(1, scodes);
|
2013-08-24 11:59:51 +00:00
|
|
|
|
|
|
|
ifaddr_event_tag = EVENTHANDLER_REGISTER(ifaddr_event, ifaddr_change,
|
2008-02-29 22:27:19 +00:00
|
|
|
NULL, EVENTHANDLER_PRI_ANY);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
ipfw_nat_destroy(void)
|
|
|
|
{
|
2009-12-23 12:15:21 +00:00
|
|
|
|
2013-08-24 11:59:51 +00:00
|
|
|
EVENTHANDLER_DEREGISTER(ifaddr_event, ifaddr_event_tag);
|
2008-02-29 22:27:19 +00:00
|
|
|
/* deregister ipfw_nat */
|
2014-09-07 18:30:29 +00:00
|
|
|
IPFW_DEL_SOPT_HANDLER(1, scodes);
|
2008-02-29 22:27:19 +00:00
|
|
|
ipfw_nat_ptr = NULL;
|
2009-12-15 16:15:14 +00:00
|
|
|
lookup_nat_ptr = NULL;
|
|
|
|
ipfw_nat_cfg_ptr = NULL;
|
|
|
|
ipfw_nat_del_ptr = NULL;
|
|
|
|
ipfw_nat_get_cfg_ptr = NULL;
|
|
|
|
ipfw_nat_get_log_ptr = NULL;
|
2008-02-29 22:27:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
ipfw_nat_modevent(module_t mod, int type, void *unused)
|
|
|
|
{
|
|
|
|
int err = 0;
|
|
|
|
|
|
|
|
switch (type) {
|
|
|
|
case MOD_LOAD:
|
|
|
|
break;
|
|
|
|
|
|
|
|
case MOD_UNLOAD:
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
return EOPNOTSUPP;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
static moduledata_t ipfw_nat_mod = {
|
|
|
|
"ipfw_nat",
|
|
|
|
ipfw_nat_modevent,
|
2012-10-10 08:36:38 +00:00
|
|
|
0
|
2008-02-29 22:27:19 +00:00
|
|
|
};
|
|
|
|
|
2013-08-24 11:59:51 +00:00
|
|
|
/* Define startup order. */
|
2014-04-26 08:05:16 +00:00
|
|
|
#define IPFW_NAT_SI_SUB_FIREWALL SI_SUB_PROTO_IFATTACHDOMAIN
|
|
|
|
#define IPFW_NAT_MODEVENT_ORDER (SI_ORDER_ANY - 128) /* after ipfw */
|
2013-08-24 11:59:51 +00:00
|
|
|
#define IPFW_NAT_MODULE_ORDER (IPFW_NAT_MODEVENT_ORDER + 1)
|
|
|
|
#define IPFW_NAT_VNET_ORDER (IPFW_NAT_MODEVENT_ORDER + 2)
|
|
|
|
|
|
|
|
DECLARE_MODULE(ipfw_nat, ipfw_nat_mod, IPFW_NAT_SI_SUB_FIREWALL, SI_ORDER_ANY);
|
2008-02-29 22:27:19 +00:00
|
|
|
MODULE_DEPEND(ipfw_nat, libalias, 1, 1, 1);
|
2014-10-09 16:12:01 +00:00
|
|
|
MODULE_DEPEND(ipfw_nat, ipfw, 3, 3, 3);
|
2008-02-29 22:27:19 +00:00
|
|
|
MODULE_VERSION(ipfw_nat, 1);
|
2013-08-24 11:59:51 +00:00
|
|
|
|
|
|
|
SYSINIT(ipfw_nat_init, IPFW_NAT_SI_SUB_FIREWALL, IPFW_NAT_MODULE_ORDER,
|
|
|
|
ipfw_nat_init, NULL);
|
|
|
|
VNET_SYSINIT(vnet_ipfw_nat_init, IPFW_NAT_SI_SUB_FIREWALL, IPFW_NAT_VNET_ORDER,
|
|
|
|
vnet_ipfw_nat_init, NULL);
|
|
|
|
|
|
|
|
SYSUNINIT(ipfw_nat_destroy, IPFW_NAT_SI_SUB_FIREWALL, IPFW_NAT_MODULE_ORDER,
|
|
|
|
ipfw_nat_destroy, NULL);
|
|
|
|
VNET_SYSUNINIT(vnet_ipfw_nat_uninit, IPFW_NAT_SI_SUB_FIREWALL,
|
|
|
|
IPFW_NAT_VNET_ORDER, vnet_ipfw_nat_uninit, NULL);
|
|
|
|
|
2009-12-16 10:48:40 +00:00
|
|
|
/* end of file */
|