opnsense-src/sys/netinet/libalias/alias_db.c

2484 lines
56 KiB
C
Raw Normal View History

/*-
* SPDX-License-Identifier: BSD-2-Clause-FreeBSD
*
* Copyright (c) 2001 Charles Mott <cm@linktel.net>
* 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.
*/
2001-09-30 17:03:33 -04:00
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#ifdef _KERNEL
Summer of Code 2005: improve libalias - part 1 of 2 With the first part of my previous Summer of Code work, we get: -made libalias modular: -support for 'particular' protocols (like ftp/irc/etcetc) is no more hardcoded inside libalias, but it's available through external modules loadable at runtime -modules are available both in kernel (/boot/kernel/alias_*.ko) and user land (/lib/libalias_*) -protocols/applications modularized are: cuseeme, ftp, irc, nbt, pptp, skinny and smedia -added logging support for kernel side -cleanup After a buildworld, do a 'mergemaster -i' to install the file libalias.conf in /etc or manually copy it. During startup (and after every HUP signal) user land applications running the new libalias will try to read a file in /etc called libalias.conf: that file contains the list of modules to load. User land applications affected by this commit are ppp and natd: if libalias.conf is present in /etc you won't notice any difference. The only kernel land bit affected by this commit is ng_nat: if you are using ng_nat, and it doesn't correctly handle ftp/irc/etcetc sessions anymore, remember to kldload the correspondent module (i.e. kldload alias_ftp). General information and details about the inner working are available in the libalias man page under the section 'MODULAR ARCHITECTURE (AND ipfw(4) SUPPORT)'. NOTA BENE: this commit affects _ONLY_ libalias, ipfw in-kernel nat support will be part of the next libalias-related commit. Approved by: glebius Reviewed by: glebius, ru
2006-09-26 19:26:53 -04:00
#include <machine/stdarg.h>
#include <sys/param.h>
#include <sys/kernel.h>
#include <sys/systm.h>
Conditionally compile out V_ globals while instantiating the appropriate container structures, depending on VIMAGE_GLOBALS compile time option. Make VIMAGE_GLOBALS a new compile-time option, which by default will not be defined, resulting in instatiations of global variables selected for V_irtualization (enclosed in #ifdef VIMAGE_GLOBALS blocks) to be effectively compiled out. Instantiate new global container structures to hold V_irtualized variables: vnet_net_0, vnet_inet_0, vnet_inet6_0, vnet_ipsec_0, vnet_netgraph_0, and vnet_gif_0. Update the VSYM() macro so that depending on VIMAGE_GLOBALS the V_ macros resolve either to the original globals, or to fields inside container structures, i.e. effectively #ifdef VIMAGE_GLOBALS #define V_rt_tables rt_tables #else #define V_rt_tables vnet_net_0._rt_tables #endif Update SYSCTL_V_*() macros to operate either on globals or on fields inside container structs. Extend the internal kldsym() lookups with the ability to resolve selected fields inside the virtualization container structs. This applies only to the fields which are explicitly registered for kldsym() visibility via VNET_MOD_DECLARE() and vnet_mod_register(), currently this is done only in sys/net/if.c. Fix a few broken instances of MODULE_GLOBAL() macro use in SCTP code, and modify the MODULE_GLOBAL() macro to resolve to V_ macros, which in turn result in proper code being generated depending on VIMAGE_GLOBALS. De-virtualize local static variables in sys/contrib/pf/net/pf_subr.c which were prematurely V_irtualized by automated V_ prepending scripts during earlier merging steps. PF virtualization will be done separately, most probably after next PF import. Convert a few variable initializations at instantiation to initialization in init functions, most notably in ipfw. Also convert TUNABLE_INT() initializers for V_ variables to TUNABLE_FETCH_INT() in initializer functions. Discussed at: devsummit Strassburg Reviewed by: bz, julian Approved by: julian (mentor) Obtained from: //depot/projects/vimage-commit2/... X-MFC after: never Sponsored by: NLnet Foundation, The FreeBSD Foundation
2008-12-10 18:12:39 -05:00
#include <sys/lock.h>
#include <sys/module.h>
Conditionally compile out V_ globals while instantiating the appropriate container structures, depending on VIMAGE_GLOBALS compile time option. Make VIMAGE_GLOBALS a new compile-time option, which by default will not be defined, resulting in instatiations of global variables selected for V_irtualization (enclosed in #ifdef VIMAGE_GLOBALS blocks) to be effectively compiled out. Instantiate new global container structures to hold V_irtualized variables: vnet_net_0, vnet_inet_0, vnet_inet6_0, vnet_ipsec_0, vnet_netgraph_0, and vnet_gif_0. Update the VSYM() macro so that depending on VIMAGE_GLOBALS the V_ macros resolve either to the original globals, or to fields inside container structures, i.e. effectively #ifdef VIMAGE_GLOBALS #define V_rt_tables rt_tables #else #define V_rt_tables vnet_net_0._rt_tables #endif Update SYSCTL_V_*() macros to operate either on globals or on fields inside container structs. Extend the internal kldsym() lookups with the ability to resolve selected fields inside the virtualization container structs. This applies only to the fields which are explicitly registered for kldsym() visibility via VNET_MOD_DECLARE() and vnet_mod_register(), currently this is done only in sys/net/if.c. Fix a few broken instances of MODULE_GLOBAL() macro use in SCTP code, and modify the MODULE_GLOBAL() macro to resolve to V_ macros, which in turn result in proper code being generated depending on VIMAGE_GLOBALS. De-virtualize local static variables in sys/contrib/pf/net/pf_subr.c which were prematurely V_irtualized by automated V_ prepending scripts during earlier merging steps. PF virtualization will be done separately, most probably after next PF import. Convert a few variable initializations at instantiation to initialization in init functions, most notably in ipfw. Also convert TUNABLE_INT() initializers for V_ variables to TUNABLE_FETCH_INT() in initializer functions. Discussed at: devsummit Strassburg Reviewed by: bz, julian Approved by: julian (mentor) Obtained from: //depot/projects/vimage-commit2/... X-MFC after: never Sponsored by: NLnet Foundation, The FreeBSD Foundation
2008-12-10 18:12:39 -05:00
#include <sys/rwlock.h>
Summer of Code 2005: improve libalias - part 1 of 2 With the first part of my previous Summer of Code work, we get: -made libalias modular: -support for 'particular' protocols (like ftp/irc/etcetc) is no more hardcoded inside libalias, but it's available through external modules loadable at runtime -modules are available both in kernel (/boot/kernel/alias_*.ko) and user land (/lib/libalias_*) -protocols/applications modularized are: cuseeme, ftp, irc, nbt, pptp, skinny and smedia -added logging support for kernel side -cleanup After a buildworld, do a 'mergemaster -i' to install the file libalias.conf in /etc or manually copy it. During startup (and after every HUP signal) user land applications running the new libalias will try to read a file in /etc called libalias.conf: that file contains the list of modules to load. User land applications affected by this commit are ppp and natd: if libalias.conf is present in /etc you won't notice any difference. The only kernel land bit affected by this commit is ng_nat: if you are using ng_nat, and it doesn't correctly handle ftp/irc/etcetc sessions anymore, remember to kldload the correspondent module (i.e. kldload alias_ftp). General information and details about the inner working are available in the libalias man page under the section 'MODULAR ARCHITECTURE (AND ipfw(4) SUPPORT)'. NOTA BENE: this commit affects _ONLY_ libalias, ipfw in-kernel nat support will be part of the next libalias-related commit. Approved by: glebius Reviewed by: glebius, ru
2006-09-26 19:26:53 -04:00
#include <sys/syslog.h>
#else
#include <stdarg.h>
#include <stdlib.h>
#include <stdio.h>
Summer of Code 2005: improve libalias - part 1 of 2 With the first part of my previous Summer of Code work, we get: -made libalias modular: -support for 'particular' protocols (like ftp/irc/etcetc) is no more hardcoded inside libalias, but it's available through external modules loadable at runtime -modules are available both in kernel (/boot/kernel/alias_*.ko) and user land (/lib/libalias_*) -protocols/applications modularized are: cuseeme, ftp, irc, nbt, pptp, skinny and smedia -added logging support for kernel side -cleanup After a buildworld, do a 'mergemaster -i' to install the file libalias.conf in /etc or manually copy it. During startup (and after every HUP signal) user land applications running the new libalias will try to read a file in /etc called libalias.conf: that file contains the list of modules to load. User land applications affected by this commit are ppp and natd: if libalias.conf is present in /etc you won't notice any difference. The only kernel land bit affected by this commit is ng_nat: if you are using ng_nat, and it doesn't correctly handle ftp/irc/etcetc sessions anymore, remember to kldload the correspondent module (i.e. kldload alias_ftp). General information and details about the inner working are available in the libalias man page under the section 'MODULAR ARCHITECTURE (AND ipfw(4) SUPPORT)'. NOTA BENE: this commit affects _ONLY_ libalias, ipfw in-kernel nat support will be part of the next libalias-related commit. Approved by: glebius Reviewed by: glebius, ru
2006-09-26 19:26:53 -04:00
#include <sys/errno.h>
#include <sys/time.h>
#include <unistd.h>
#endif
Summer of Code 2005: improve libalias - part 1 of 2 With the first part of my previous Summer of Code work, we get: -made libalias modular: -support for 'particular' protocols (like ftp/irc/etcetc) is no more hardcoded inside libalias, but it's available through external modules loadable at runtime -modules are available both in kernel (/boot/kernel/alias_*.ko) and user land (/lib/libalias_*) -protocols/applications modularized are: cuseeme, ftp, irc, nbt, pptp, skinny and smedia -added logging support for kernel side -cleanup After a buildworld, do a 'mergemaster -i' to install the file libalias.conf in /etc or manually copy it. During startup (and after every HUP signal) user land applications running the new libalias will try to read a file in /etc called libalias.conf: that file contains the list of modules to load. User land applications affected by this commit are ppp and natd: if libalias.conf is present in /etc you won't notice any difference. The only kernel land bit affected by this commit is ng_nat: if you are using ng_nat, and it doesn't correctly handle ftp/irc/etcetc sessions anymore, remember to kldload the correspondent module (i.e. kldload alias_ftp). General information and details about the inner working are available in the libalias man page under the section 'MODULAR ARCHITECTURE (AND ipfw(4) SUPPORT)'. NOTA BENE: this commit affects _ONLY_ libalias, ipfw in-kernel nat support will be part of the next libalias-related commit. Approved by: glebius Reviewed by: glebius, ru
2006-09-26 19:26:53 -04:00
#include <sys/socket.h>
#include <netinet/tcp.h>
#ifdef _KERNEL
#include <netinet/libalias/alias.h>
#include <netinet/libalias/alias_local.h>
Summer of Code 2005: improve libalias - part 1 of 2 With the first part of my previous Summer of Code work, we get: -made libalias modular: -support for 'particular' protocols (like ftp/irc/etcetc) is no more hardcoded inside libalias, but it's available through external modules loadable at runtime -modules are available both in kernel (/boot/kernel/alias_*.ko) and user land (/lib/libalias_*) -protocols/applications modularized are: cuseeme, ftp, irc, nbt, pptp, skinny and smedia -added logging support for kernel side -cleanup After a buildworld, do a 'mergemaster -i' to install the file libalias.conf in /etc or manually copy it. During startup (and after every HUP signal) user land applications running the new libalias will try to read a file in /etc called libalias.conf: that file contains the list of modules to load. User land applications affected by this commit are ppp and natd: if libalias.conf is present in /etc you won't notice any difference. The only kernel land bit affected by this commit is ng_nat: if you are using ng_nat, and it doesn't correctly handle ftp/irc/etcetc sessions anymore, remember to kldload the correspondent module (i.e. kldload alias_ftp). General information and details about the inner working are available in the libalias man page under the section 'MODULAR ARCHITECTURE (AND ipfw(4) SUPPORT)'. NOTA BENE: this commit affects _ONLY_ libalias, ipfw in-kernel nat support will be part of the next libalias-related commit. Approved by: glebius Reviewed by: glebius, ru
2006-09-26 19:26:53 -04:00
#include <netinet/libalias/alias_mod.h>
#include <net/if.h>
#else
#include "alias.h"
#include "alias_local.h"
Summer of Code 2005: improve libalias - part 1 of 2 With the first part of my previous Summer of Code work, we get: -made libalias modular: -support for 'particular' protocols (like ftp/irc/etcetc) is no more hardcoded inside libalias, but it's available through external modules loadable at runtime -modules are available both in kernel (/boot/kernel/alias_*.ko) and user land (/lib/libalias_*) -protocols/applications modularized are: cuseeme, ftp, irc, nbt, pptp, skinny and smedia -added logging support for kernel side -cleanup After a buildworld, do a 'mergemaster -i' to install the file libalias.conf in /etc or manually copy it. During startup (and after every HUP signal) user land applications running the new libalias will try to read a file in /etc called libalias.conf: that file contains the list of modules to load. User land applications affected by this commit are ppp and natd: if libalias.conf is present in /etc you won't notice any difference. The only kernel land bit affected by this commit is ng_nat: if you are using ng_nat, and it doesn't correctly handle ftp/irc/etcetc sessions anymore, remember to kldload the correspondent module (i.e. kldload alias_ftp). General information and details about the inner working are available in the libalias man page under the section 'MODULAR ARCHITECTURE (AND ipfw(4) SUPPORT)'. NOTA BENE: this commit affects _ONLY_ libalias, ipfw in-kernel nat support will be part of the next libalias-related commit. Approved by: glebius Reviewed by: glebius, ru
2006-09-26 19:26:53 -04:00
#include "alias_mod.h"
#endif
#include "alias_db.h"
static LIST_HEAD(, libalias) instancehead = LIST_HEAD_INITIALIZER(instancehead);
int LibAliasTime;
/* Kernel module definition. */
#ifdef _KERNEL
MALLOC_DEFINE(M_ALIAS, "libalias", "packet aliasing");
MODULE_VERSION(libalias, 1);
static int
alias_mod_handler(module_t mod, int type, void *data)
{
switch (type) {
case MOD_QUIESCE:
case MOD_UNLOAD:
finishoff();
case MOD_LOAD:
return (0);
default:
return (EINVAL);
}
}
static moduledata_t alias_mod = {
"alias", alias_mod_handler, NULL
};
DECLARE_MODULE(alias, alias_mod, SI_SUB_DRIVERS, SI_ORDER_SECOND);
#endif
SPLAY_GENERATE(splay_out, alias_link, all.out, cmp_out);
SPLAY_GENERATE(splay_in, group_in, in, cmp_in);
static struct group_in *
StartPointIn(struct libalias *la,
struct in_addr alias_addr, u_short alias_port, int link_type,
int create)
{
struct group_in *grp;
struct group_in needle = {
.alias_addr = alias_addr,
.alias_port = alias_port,
.link_type = link_type
};
grp = SPLAY_FIND(splay_in, &la->linkSplayIn, &needle);
if (grp != NULL || !create || (grp = malloc(sizeof(*grp))) == NULL)
return (grp);
grp->alias_addr = alias_addr;
grp->alias_port = alias_port;
grp->link_type = link_type;
LIST_INIT(&grp->full);
LIST_INIT(&grp->partial);
SPLAY_INSERT(splay_in, &la->linkSplayIn, grp);
return (grp);
}
static int
SeqDiff(u_long x, u_long y)
{
/* Return the difference between two TCP sequence numbers
* This function is encapsulated in case there are any unusual
* arithmetic conditions that need to be considered.
*/
return (ntohl(y) - ntohl(x));
}
Summer of Code 2005: improve libalias - part 1 of 2 With the first part of my previous Summer of Code work, we get: -made libalias modular: -support for 'particular' protocols (like ftp/irc/etcetc) is no more hardcoded inside libalias, but it's available through external modules loadable at runtime -modules are available both in kernel (/boot/kernel/alias_*.ko) and user land (/lib/libalias_*) -protocols/applications modularized are: cuseeme, ftp, irc, nbt, pptp, skinny and smedia -added logging support for kernel side -cleanup After a buildworld, do a 'mergemaster -i' to install the file libalias.conf in /etc or manually copy it. During startup (and after every HUP signal) user land applications running the new libalias will try to read a file in /etc called libalias.conf: that file contains the list of modules to load. User land applications affected by this commit are ppp and natd: if libalias.conf is present in /etc you won't notice any difference. The only kernel land bit affected by this commit is ng_nat: if you are using ng_nat, and it doesn't correctly handle ftp/irc/etcetc sessions anymore, remember to kldload the correspondent module (i.e. kldload alias_ftp). General information and details about the inner working are available in the libalias man page under the section 'MODULAR ARCHITECTURE (AND ipfw(4) SUPPORT)'. NOTA BENE: this commit affects _ONLY_ libalias, ipfw in-kernel nat support will be part of the next libalias-related commit. Approved by: glebius Reviewed by: glebius, ru
2006-09-26 19:26:53 -04:00
#ifdef _KERNEL
static void
AliasLog(char *str, const char *format, ...)
{
Summer of Code 2005: improve libalias - part 1 of 2 With the first part of my previous Summer of Code work, we get: -made libalias modular: -support for 'particular' protocols (like ftp/irc/etcetc) is no more hardcoded inside libalias, but it's available through external modules loadable at runtime -modules are available both in kernel (/boot/kernel/alias_*.ko) and user land (/lib/libalias_*) -protocols/applications modularized are: cuseeme, ftp, irc, nbt, pptp, skinny and smedia -added logging support for kernel side -cleanup After a buildworld, do a 'mergemaster -i' to install the file libalias.conf in /etc or manually copy it. During startup (and after every HUP signal) user land applications running the new libalias will try to read a file in /etc called libalias.conf: that file contains the list of modules to load. User land applications affected by this commit are ppp and natd: if libalias.conf is present in /etc you won't notice any difference. The only kernel land bit affected by this commit is ng_nat: if you are using ng_nat, and it doesn't correctly handle ftp/irc/etcetc sessions anymore, remember to kldload the correspondent module (i.e. kldload alias_ftp). General information and details about the inner working are available in the libalias man page under the section 'MODULAR ARCHITECTURE (AND ipfw(4) SUPPORT)'. NOTA BENE: this commit affects _ONLY_ libalias, ipfw in-kernel nat support will be part of the next libalias-related commit. Approved by: glebius Reviewed by: glebius, ru
2006-09-26 19:26:53 -04:00
va_list ap;
Summer of Code 2005: improve libalias - part 1 of 2 With the first part of my previous Summer of Code work, we get: -made libalias modular: -support for 'particular' protocols (like ftp/irc/etcetc) is no more hardcoded inside libalias, but it's available through external modules loadable at runtime -modules are available both in kernel (/boot/kernel/alias_*.ko) and user land (/lib/libalias_*) -protocols/applications modularized are: cuseeme, ftp, irc, nbt, pptp, skinny and smedia -added logging support for kernel side -cleanup After a buildworld, do a 'mergemaster -i' to install the file libalias.conf in /etc or manually copy it. During startup (and after every HUP signal) user land applications running the new libalias will try to read a file in /etc called libalias.conf: that file contains the list of modules to load. User land applications affected by this commit are ppp and natd: if libalias.conf is present in /etc you won't notice any difference. The only kernel land bit affected by this commit is ng_nat: if you are using ng_nat, and it doesn't correctly handle ftp/irc/etcetc sessions anymore, remember to kldload the correspondent module (i.e. kldload alias_ftp). General information and details about the inner working are available in the libalias man page under the section 'MODULAR ARCHITECTURE (AND ipfw(4) SUPPORT)'. NOTA BENE: this commit affects _ONLY_ libalias, ipfw in-kernel nat support will be part of the next libalias-related commit. Approved by: glebius Reviewed by: glebius, ru
2006-09-26 19:26:53 -04:00
va_start(ap, format);
vsnprintf(str, LIBALIAS_BUF_SIZE, format, ap);
va_end(ap);
}
#else
static void
AliasLog(FILE *stream, const char *format, ...)
{
va_list ap;
Summer of Code 2005: improve libalias - part 1 of 2 With the first part of my previous Summer of Code work, we get: -made libalias modular: -support for 'particular' protocols (like ftp/irc/etcetc) is no more hardcoded inside libalias, but it's available through external modules loadable at runtime -modules are available both in kernel (/boot/kernel/alias_*.ko) and user land (/lib/libalias_*) -protocols/applications modularized are: cuseeme, ftp, irc, nbt, pptp, skinny and smedia -added logging support for kernel side -cleanup After a buildworld, do a 'mergemaster -i' to install the file libalias.conf in /etc or manually copy it. During startup (and after every HUP signal) user land applications running the new libalias will try to read a file in /etc called libalias.conf: that file contains the list of modules to load. User land applications affected by this commit are ppp and natd: if libalias.conf is present in /etc you won't notice any difference. The only kernel land bit affected by this commit is ng_nat: if you are using ng_nat, and it doesn't correctly handle ftp/irc/etcetc sessions anymore, remember to kldload the correspondent module (i.e. kldload alias_ftp). General information and details about the inner working are available in the libalias man page under the section 'MODULAR ARCHITECTURE (AND ipfw(4) SUPPORT)'. NOTA BENE: this commit affects _ONLY_ libalias, ipfw in-kernel nat support will be part of the next libalias-related commit. Approved by: glebius Reviewed by: glebius, ru
2006-09-26 19:26:53 -04:00
va_start(ap, format);
vfprintf(stream, format, ap);
va_end(ap);
fflush(stream);
}
#endif
static void
ShowAliasStats(struct libalias *la)
{
LIBALIAS_LOCK_ASSERT(la);
/* Used for debugging */
Summer of Code 2005: improve libalias - part 1 of 2 With the first part of my previous Summer of Code work, we get: -made libalias modular: -support for 'particular' protocols (like ftp/irc/etcetc) is no more hardcoded inside libalias, but it's available through external modules loadable at runtime -modules are available both in kernel (/boot/kernel/alias_*.ko) and user land (/lib/libalias_*) -protocols/applications modularized are: cuseeme, ftp, irc, nbt, pptp, skinny and smedia -added logging support for kernel side -cleanup After a buildworld, do a 'mergemaster -i' to install the file libalias.conf in /etc or manually copy it. During startup (and after every HUP signal) user land applications running the new libalias will try to read a file in /etc called libalias.conf: that file contains the list of modules to load. User land applications affected by this commit are ppp and natd: if libalias.conf is present in /etc you won't notice any difference. The only kernel land bit affected by this commit is ng_nat: if you are using ng_nat, and it doesn't correctly handle ftp/irc/etcetc sessions anymore, remember to kldload the correspondent module (i.e. kldload alias_ftp). General information and details about the inner working are available in the libalias man page under the section 'MODULAR ARCHITECTURE (AND ipfw(4) SUPPORT)'. NOTA BENE: this commit affects _ONLY_ libalias, ipfw in-kernel nat support will be part of the next libalias-related commit. Approved by: glebius Reviewed by: glebius, ru
2006-09-26 19:26:53 -04:00
if (la->logDesc) {
int tot = la->icmpLinkCount + la->udpLinkCount +
(la->sctpLinkCount>>1) + /* sctp counts half associations */
la->tcpLinkCount + la->pptpLinkCount +
la->protoLinkCount + la->fragmentIdLinkCount +
la->fragmentPtrLinkCount;
Summer of Code 2005: improve libalias - part 1 of 2 With the first part of my previous Summer of Code work, we get: -made libalias modular: -support for 'particular' protocols (like ftp/irc/etcetc) is no more hardcoded inside libalias, but it's available through external modules loadable at runtime -modules are available both in kernel (/boot/kernel/alias_*.ko) and user land (/lib/libalias_*) -protocols/applications modularized are: cuseeme, ftp, irc, nbt, pptp, skinny and smedia -added logging support for kernel side -cleanup After a buildworld, do a 'mergemaster -i' to install the file libalias.conf in /etc or manually copy it. During startup (and after every HUP signal) user land applications running the new libalias will try to read a file in /etc called libalias.conf: that file contains the list of modules to load. User land applications affected by this commit are ppp and natd: if libalias.conf is present in /etc you won't notice any difference. The only kernel land bit affected by this commit is ng_nat: if you are using ng_nat, and it doesn't correctly handle ftp/irc/etcetc sessions anymore, remember to kldload the correspondent module (i.e. kldload alias_ftp). General information and details about the inner working are available in the libalias man page under the section 'MODULAR ARCHITECTURE (AND ipfw(4) SUPPORT)'. NOTA BENE: this commit affects _ONLY_ libalias, ipfw in-kernel nat support will be part of the next libalias-related commit. Approved by: glebius Reviewed by: glebius, ru
2006-09-26 19:26:53 -04:00
AliasLog(la->logDesc,
"icmp=%u, udp=%u, tcp=%u, sctp=%u, pptp=%u, proto=%u, frag_id=%u frag_ptr=%u / tot=%u",
la->icmpLinkCount,
la->udpLinkCount,
la->tcpLinkCount,
la->sctpLinkCount>>1, /* sctp counts half associations */
la->pptpLinkCount,
la->protoLinkCount,
la->fragmentIdLinkCount,
la->fragmentPtrLinkCount,
tot);
Summer of Code 2005: improve libalias - part 1 of 2 With the first part of my previous Summer of Code work, we get: -made libalias modular: -support for 'particular' protocols (like ftp/irc/etcetc) is no more hardcoded inside libalias, but it's available through external modules loadable at runtime -modules are available both in kernel (/boot/kernel/alias_*.ko) and user land (/lib/libalias_*) -protocols/applications modularized are: cuseeme, ftp, irc, nbt, pptp, skinny and smedia -added logging support for kernel side -cleanup After a buildworld, do a 'mergemaster -i' to install the file libalias.conf in /etc or manually copy it. During startup (and after every HUP signal) user land applications running the new libalias will try to read a file in /etc called libalias.conf: that file contains the list of modules to load. User land applications affected by this commit are ppp and natd: if libalias.conf is present in /etc you won't notice any difference. The only kernel land bit affected by this commit is ng_nat: if you are using ng_nat, and it doesn't correctly handle ftp/irc/etcetc sessions anymore, remember to kldload the correspondent module (i.e. kldload alias_ftp). General information and details about the inner working are available in the libalias man page under the section 'MODULAR ARCHITECTURE (AND ipfw(4) SUPPORT)'. NOTA BENE: this commit affects _ONLY_ libalias, ipfw in-kernel nat support will be part of the next libalias-related commit. Approved by: glebius Reviewed by: glebius, ru
2006-09-26 19:26:53 -04:00
#ifndef _KERNEL
AliasLog(la->logDesc, " (sock=%u)\n", la->sockCount);
Summer of Code 2005: improve libalias - part 1 of 2 With the first part of my previous Summer of Code work, we get: -made libalias modular: -support for 'particular' protocols (like ftp/irc/etcetc) is no more hardcoded inside libalias, but it's available through external modules loadable at runtime -modules are available both in kernel (/boot/kernel/alias_*.ko) and user land (/lib/libalias_*) -protocols/applications modularized are: cuseeme, ftp, irc, nbt, pptp, skinny and smedia -added logging support for kernel side -cleanup After a buildworld, do a 'mergemaster -i' to install the file libalias.conf in /etc or manually copy it. During startup (and after every HUP signal) user land applications running the new libalias will try to read a file in /etc called libalias.conf: that file contains the list of modules to load. User land applications affected by this commit are ppp and natd: if libalias.conf is present in /etc you won't notice any difference. The only kernel land bit affected by this commit is ng_nat: if you are using ng_nat, and it doesn't correctly handle ftp/irc/etcetc sessions anymore, remember to kldload the correspondent module (i.e. kldload alias_ftp). General information and details about the inner working are available in the libalias man page under the section 'MODULAR ARCHITECTURE (AND ipfw(4) SUPPORT)'. NOTA BENE: this commit affects _ONLY_ libalias, ipfw in-kernel nat support will be part of the next libalias-related commit. Approved by: glebius Reviewed by: glebius, ru
2006-09-26 19:26:53 -04:00
#endif
}
}
void SctpShowAliasStats(struct libalias *la)
{
ShowAliasStats(la);
}
/* get random port in network byte order */
static u_short
_RandomPort(struct libalias *la) {
u_short port;
port = la->aliasPortLower +
arc4random_uniform(la->aliasPortLength);
return ntohs(port);
}
/* GetNewPort() allocates port numbers. Note that if a port number
is already in use, that does not mean that it cannot be used by
another link concurrently. This is because GetNewPort() looks for
unused triplets: (dest addr, dest port, alias port). */
static int
GetNewPort(struct libalias *la, struct alias_link *lnk, int alias_port_param)
{
int i;
int max_trials;
u_short port;
LIBALIAS_LOCK_ASSERT(la);
/*
* Description of alias_port_param for GetNewPort(). When
* this parameter is zero or positive, it precisely specifies
* the port number. GetNewPort() will return this number
* without check that it is in use.
*
* The aliasing port is automatically selected by one of
* two methods below:
*
* When this parameter is GET_ALIAS_PORT, it indicates to get
* a randomly selected port number.
*/
if (alias_port_param >= 0 && alias_port_param < 0x10000) {
lnk->alias_port = (u_short) alias_port_param;
return (0);
}
if (alias_port_param != GET_ALIAS_PORT) {
#ifdef LIBALIAS_DEBUG
fprintf(stderr, "PacketAlias/GetNewPort(): ");
fprintf(stderr, "input parameter error\n");
#endif
return (-1);
}
max_trials = GET_NEW_PORT_MAX_ATTEMPTS;
/*
* When the PKT_ALIAS_SAME_PORTS option is chosen,
* the first try will be the actual source port. If
* this is already in use, the remainder of the
* trials will be random.
*/
port = (la->packetAliasMode & PKT_ALIAS_SAME_PORTS)
? lnk->src_port
: _RandomPort(la);
/* Port number search */
for (i = 0; i < max_trials; i++, port = _RandomPort(la)) {
struct group_in *grp;
struct alias_link *search_result;
grp = StartPointIn(la, lnk->alias_addr, port, lnk->link_type, 0);
if (grp == NULL)
break;
LIST_FOREACH(search_result, &grp->full, all.in) {
if (lnk->dst_addr.s_addr == search_result->dst_addr.s_addr &&
lnk->dst_port == search_result->dst_port)
break; /* found match */
}
if (search_result == NULL)
break;
}
if (i >= max_trials) {
#ifdef LIBALIAS_DEBUG
fprintf(stderr, "PacketAlias/GetNewPort(): ");
fprintf(stderr, "could not find free port\n");
#endif
return (-1);
}
#ifndef NO_USE_SOCKETS
if ((la->packetAliasMode & PKT_ALIAS_USE_SOCKETS) &&
(lnk->flags & LINK_PARTIALLY_SPECIFIED) &&
((lnk->link_type == LINK_TCP) ||
(lnk->link_type == LINK_UDP))) {
if (!GetSocket(la, port, &lnk->sockfd, lnk->link_type)) {
return (-1);
}
}
#endif
lnk->alias_port = port;
return (0);
}
#ifndef NO_USE_SOCKETS
static u_short
GetSocket(struct libalias *la, u_short port_net, int *sockfd, int link_type)
{
int err;
int sock;
struct sockaddr_in sock_addr;
LIBALIAS_LOCK_ASSERT(la);
if (link_type == LINK_TCP)
sock = socket(AF_INET, SOCK_STREAM, 0);
else if (link_type == LINK_UDP)
sock = socket(AF_INET, SOCK_DGRAM, 0);
else {
#ifdef LIBALIAS_DEBUG
fprintf(stderr, "PacketAlias/GetSocket(): ");
fprintf(stderr, "incorrect link type\n");
#endif
return (0);
}
if (sock < 0) {
#ifdef LIBALIAS_DEBUG
fprintf(stderr, "PacketAlias/GetSocket(): ");
fprintf(stderr, "socket() error %d\n", *sockfd);
#endif
return (0);
}
sock_addr.sin_family = AF_INET;
sock_addr.sin_addr.s_addr = htonl(INADDR_ANY);
sock_addr.sin_port = port_net;
err = bind(sock,
(struct sockaddr *)&sock_addr,
sizeof(sock_addr));
if (err == 0) {
la->sockCount++;
*sockfd = sock;
return (1);
} else {
close(sock);
return (0);
}
}
#endif
2002-07-01 07:19:40 -04:00
/* FindNewPortGroup() returns a base port number for an available
range of contiguous port numbers. Note that if a port number
is already in use, that does not mean that it cannot be used by
another link concurrently. This is because FindNewPortGroup()
looks for unused triplets: (dest addr, dest port, alias port). */
int
FindNewPortGroup(struct libalias *la,
struct in_addr dst_addr,
struct in_addr alias_addr,
u_short src_port,
u_short dst_port,
u_short port_count,
u_char proto,
u_char align)
{
int i, j;
int max_trials;
u_short port;
int link_type;
LIBALIAS_LOCK_ASSERT(la);
/*
* Get link_type from protocol
*/
switch (proto) {
case IPPROTO_UDP:
link_type = LINK_UDP;
break;
case IPPROTO_TCP:
link_type = LINK_TCP;
break;
default:
return (0);
break;
}
/*
* The aliasing port is automatically selected by one of two
* methods below:
*/
max_trials = GET_NEW_PORT_MAX_ATTEMPTS;
if (la->packetAliasMode & PKT_ALIAS_SAME_PORTS) {
/*
* When the ALIAS_SAME_PORTS option is chosen, the first
* try will be the actual source port. If this is already
* in use, the remainder of the trials will be random.
*/
port = src_port;
} else {
port = _RandomPort(la);
}
/* Port number search */
for (i = 0; i < max_trials; i++, port = _RandomPort(la)) {
struct alias_link *search_result;
if (align)
port &= htons(0xfffe);
for (j = 0; j < port_count; j++) {
u_short port_j = ntohs(port) + j;
if ((search_result = FindLinkIn(la, dst_addr,
alias_addr, dst_port, htons(port_j),
link_type, 0)) != NULL)
break;
}
/* Found a good range, return base */
if (j == port_count)
return (port);
}
#ifdef LIBALIAS_DEBUG
fprintf(stderr, "PacketAlias/FindNewPortGroup(): ");
fprintf(stderr, "could not find free port(s)\n");
#endif
return (0);
}
static void
CleanupAliasData(struct libalias *la, int deletePermanent)
{
struct alias_link *lnk, *lnk_tmp;
LIBALIAS_LOCK_ASSERT(la);
/* permanent entries may stay */
TAILQ_FOREACH_SAFE(lnk, &la->checkExpire, expire.list, lnk_tmp)
DeleteLink(&lnk, deletePermanent);
}
static void
CleanupLink(struct libalias *la, struct alias_link **lnk, int deletePermanent)
{
LIBALIAS_LOCK_ASSERT(la);
if (lnk == NULL || *lnk == NULL)
return;
if (LibAliasTime - (*lnk)->timestamp > (*lnk)->expire.time) {
DeleteLink(lnk, deletePermanent);
if ((*lnk) == NULL)
return;
}
/* move to end, swap may fail on a single entry list */
TAILQ_REMOVE(&la->checkExpire, (*lnk), expire.list);
TAILQ_INSERT_TAIL(&la->checkExpire, (*lnk), expire.list);
}
static struct alias_link *
UseLink(struct libalias *la, struct alias_link *lnk)
{
CleanupLink(la, &lnk, 0);
if (lnk != NULL)
lnk->timestamp = LibAliasTime;
return (lnk);
}
static void
DeleteLink(struct alias_link **plnk, int deletePermanent)
{
struct alias_link *lnk = *plnk;
struct libalias *la = lnk->la;
LIBALIAS_LOCK_ASSERT(la);
/* Don't do anything if the link is marked permanent */
if (!deletePermanent && (lnk->flags & LINK_PERMANENT))
return;
#ifndef NO_FW_PUNCH
/* Delete associated firewall hole, if any */
ClearFWHole(lnk);
#endif
switch (lnk->link_type) {
case LINK_PPTP:
LIST_REMOVE(lnk, pptp.list);
break;
default: {
struct group_in *grp;
/* Free memory allocated for LSNAT server pool */
if (lnk->server != NULL) {
struct server *head, *curr, *next;
head = curr = lnk->server;
do {
next = curr->next;
free(curr);
} while ((curr = next) != head);
} else {
/* Adjust output table pointers */
SPLAY_REMOVE(splay_out, &la->linkSplayOut, lnk);
}
/* Adjust input table pointers */
LIST_REMOVE(lnk, all.in);
/* Remove intermediate node, if empty */
grp = StartPointIn(la, lnk->alias_addr, lnk->alias_port, lnk->link_type, 0);
if (grp != NULL &&
LIST_EMPTY(&grp->full) &&
LIST_EMPTY(&grp->partial)) {
SPLAY_REMOVE(splay_in, &la->linkSplayIn, grp);
free(grp);
}
}
break;
}
/* remove from housekeeping */
TAILQ_REMOVE(&la->checkExpire, lnk, expire.list);
#ifndef NO_USE_SOCKETS
/* Close socket, if one has been allocated */
if (lnk->sockfd != -1) {
la->sockCount--;
close(lnk->sockfd);
}
#endif
/* Link-type dependent cleanup */
switch (lnk->link_type) {
case LINK_ICMP:
la->icmpLinkCount--;
break;
case LINK_UDP:
la->udpLinkCount--;
break;
case LINK_TCP:
la->tcpLinkCount--;
free(lnk->data.tcp);
break;
case LINK_PPTP:
la->pptpLinkCount--;
break;
case LINK_FRAGMENT_ID:
la->fragmentIdLinkCount--;
break;
case LINK_FRAGMENT_PTR:
la->fragmentPtrLinkCount--;
if (lnk->data.frag_ptr != NULL)
free(lnk->data.frag_ptr);
break;
case LINK_ADDR:
break;
default:
la->protoLinkCount--;
break;
}
/* Free memory */
free(lnk);
*plnk = NULL;
/* Write statistics, if logging enabled */
if (la->packetAliasMode & PKT_ALIAS_LOG) {
ShowAliasStats(la);
}
}
struct alias_link *
AddLink(struct libalias *la, struct in_addr src_addr, struct in_addr dst_addr,
struct in_addr alias_addr, u_short src_port, u_short dst_port,
int alias_port_param, int link_type)
{
struct alias_link *lnk;
LIBALIAS_LOCK_ASSERT(la);
lnk = malloc(sizeof(struct alias_link));
if (lnk == NULL) {
#ifdef LIBALIAS_DEBUG
fprintf(stderr, "PacketAlias/AddLink(): ");
fprintf(stderr, "malloc() call failed.\n");
#endif
return (NULL);
}
/* Basic initialization */
lnk->la = la;
lnk->src_addr = src_addr;
lnk->dst_addr = dst_addr;
lnk->alias_addr = alias_addr;
lnk->proxy_addr.s_addr = INADDR_ANY;
lnk->src_port = src_port;
lnk->dst_port = dst_port;
lnk->proxy_port = 0;
lnk->server = NULL;
lnk->link_type = link_type;
#ifndef NO_USE_SOCKETS
lnk->sockfd = -1;
#endif
lnk->flags = 0;
lnk->pflags = 0;
lnk->timestamp = LibAliasTime;
/* Expiration time */
switch (link_type) {
case LINK_ICMP:
lnk->expire.time = ICMP_EXPIRE_TIME;
break;
case LINK_UDP:
lnk->expire.time = UDP_EXPIRE_TIME;
break;
case LINK_TCP:
lnk->expire.time = TCP_EXPIRE_INITIAL;
break;
case LINK_FRAGMENT_ID:
lnk->expire.time = FRAGMENT_ID_EXPIRE_TIME;
break;
case LINK_FRAGMENT_PTR:
lnk->expire.time = FRAGMENT_PTR_EXPIRE_TIME;
break;
default:
lnk->expire.time = PROTO_EXPIRE_TIME;
break;
}
/* Determine alias flags */
if (dst_addr.s_addr == INADDR_ANY)
lnk->flags |= LINK_UNKNOWN_DEST_ADDR;
if (dst_port == 0)
lnk->flags |= LINK_UNKNOWN_DEST_PORT;
/* Determine alias port */
if (GetNewPort(la, lnk, alias_port_param) != 0) {
free(lnk);
return (NULL);
}
/* Link-type dependent initialization */
switch (link_type) {
case LINK_ICMP:
la->icmpLinkCount++;
break;
case LINK_UDP:
la->udpLinkCount++;
break;
case LINK_TCP: {
struct tcp_dat *aux_tcp;
int i;
aux_tcp = malloc(sizeof(struct tcp_dat));
if (aux_tcp == NULL) {
#ifdef LIBALIAS_DEBUG
fprintf(stderr, "PacketAlias/AddLink: ");
fprintf(stderr, " cannot allocate auxiliary TCP data\n");
#endif
free(lnk);
return (NULL);
}
la->tcpLinkCount++;
aux_tcp->state.in = ALIAS_TCP_STATE_NOT_CONNECTED;
aux_tcp->state.out = ALIAS_TCP_STATE_NOT_CONNECTED;
aux_tcp->state.index = 0;
aux_tcp->state.ack_modified = 0;
for (i = 0; i < N_LINK_TCP_DATA; i++)
aux_tcp->ack[i].active = 0;
aux_tcp->fwhole = -1;
lnk->data.tcp = aux_tcp;
}
break;
case LINK_PPTP:
la->pptpLinkCount++;
break;
case LINK_FRAGMENT_ID:
la->fragmentIdLinkCount++;
break;
case LINK_FRAGMENT_PTR:
la->fragmentPtrLinkCount++;
break;
case LINK_ADDR:
break;
default:
la->protoLinkCount++;
break;
}
switch (link_type) {
case LINK_PPTP:
LIST_INSERT_HEAD(&la->pptpList, lnk, pptp.list);
break;
default: {
struct group_in *grp;
grp = StartPointIn(la, alias_addr, lnk->alias_port, link_type, 1);
if (grp == NULL) {
free(lnk);
return (NULL);
}
/* Set up pointers for output lookup table */
SPLAY_INSERT(splay_out, &la->linkSplayOut, lnk);
/* Set up pointers for input lookup table */
if (lnk->flags & LINK_PARTIALLY_SPECIFIED)
LIST_INSERT_HEAD(&grp->partial, lnk, all.in);
else
LIST_INSERT_HEAD(&grp->full, lnk, all.in);
}
break;
}
/* Include the element into the housekeeping list */
TAILQ_INSERT_TAIL(&la->checkExpire, lnk, expire.list);
if (la->packetAliasMode & PKT_ALIAS_LOG)
ShowAliasStats(la);
return (lnk);
}
/*
* If alias_port_param is less than zero, alias port will be automatically
* chosen. If greater than zero, equal to alias port
*/
static struct alias_link *
ReLink(struct alias_link *old_lnk,
struct in_addr src_addr,
struct in_addr dst_addr,
struct in_addr alias_addr,
u_short src_port,
u_short dst_port,
int alias_port_param,
int link_type,
int deletePermanent)
{
struct alias_link *new_lnk;
struct libalias *la = old_lnk->la;
LIBALIAS_LOCK_ASSERT(la);
new_lnk = AddLink(la, src_addr, dst_addr, alias_addr,
src_port, dst_port, alias_port_param,
link_type);
#ifndef NO_FW_PUNCH
if (new_lnk != NULL &&
old_lnk->link_type == LINK_TCP &&
old_lnk->data.tcp->fwhole > 0) {
PunchFWHole(new_lnk);
}
#endif
DeleteLink(&old_lnk, deletePermanent);
return (new_lnk);
}
static struct alias_link *
_SearchLinkOut(struct libalias *la, struct in_addr src_addr,
struct in_addr dst_addr,
u_short src_port,
u_short dst_port,
int link_type) {
struct alias_link *lnk;
struct alias_link needle = {
.src_addr = src_addr,
.dst_addr = dst_addr,
.src_port = src_port,
.dst_port = dst_port,
.link_type = link_type
};
lnk = SPLAY_FIND(splay_out, &la->linkSplayOut, &needle);
return (UseLink(la, lnk));
}
static struct alias_link *
_FindLinkOut(struct libalias *la, struct in_addr src_addr,
struct in_addr dst_addr,
u_short src_port,
u_short dst_port,
int link_type,
int replace_partial_links)
{
struct alias_link *lnk;
LIBALIAS_LOCK_ASSERT(la);
lnk = _SearchLinkOut(la, src_addr, dst_addr, src_port, dst_port, link_type);
if (lnk != NULL || !replace_partial_links)
return (lnk);
/* Search for partially specified links. */
if (dst_port != 0 && dst_addr.s_addr != INADDR_ANY) {
lnk = _SearchLinkOut(la, src_addr, dst_addr, src_port, 0,
link_type);
if (lnk == NULL)
lnk = _SearchLinkOut(la, src_addr, ANY_ADDR, src_port,
dst_port, link_type);
}
if (lnk == NULL &&
(dst_port != 0 || dst_addr.s_addr != INADDR_ANY)) {
lnk = _SearchLinkOut(la, src_addr, ANY_ADDR, src_port, 0,
link_type);
}
if (lnk != NULL) {
lnk = ReLink(lnk,
src_addr, dst_addr, lnk->alias_addr,
src_port, dst_port, lnk->alias_port,
link_type, 0);
}
return (lnk);
}
static struct alias_link *
FindLinkOut(struct libalias *la, struct in_addr src_addr,
struct in_addr dst_addr,
u_short src_port,
u_short dst_port,
int link_type,
int replace_partial_links)
{
struct alias_link *lnk;
LIBALIAS_LOCK_ASSERT(la);
lnk = _FindLinkOut(la, src_addr, dst_addr, src_port, dst_port,
link_type, replace_partial_links);
if (lnk == NULL) {
/*
* The following allows permanent links to be specified as
* using the default source address (i.e. device interface
* address) without knowing in advance what that address
* is.
*/
if (la->aliasAddress.s_addr != INADDR_ANY &&
src_addr.s_addr == la->aliasAddress.s_addr) {
lnk = _FindLinkOut(la, ANY_ADDR, dst_addr, src_port, dst_port,
link_type, replace_partial_links);
}
}
return (lnk);
}
static struct alias_link *
_FindLinkIn(struct libalias *la, struct in_addr dst_addr,
struct in_addr alias_addr,
u_short dst_port,
u_short alias_port,
int link_type,
int replace_partial_links)
{
int flags_in;
struct group_in *grp;
struct alias_link *lnk;
struct alias_link *lnk_unknown_all;
struct alias_link *lnk_unknown_dst_addr;
struct alias_link *lnk_unknown_dst_port;
struct in_addr src_addr;
u_short src_port;
LIBALIAS_LOCK_ASSERT(la);
/* Initialize pointers */
lnk_unknown_all = NULL;
lnk_unknown_dst_addr = NULL;
lnk_unknown_dst_port = NULL;
/* If either the dest addr or port is unknown, the search
* loop will have to know about this. */
flags_in = 0;
if (dst_addr.s_addr == INADDR_ANY)
flags_in |= LINK_UNKNOWN_DEST_ADDR;
if (dst_port == 0)
flags_in |= LINK_UNKNOWN_DEST_PORT;
/* Search loop */
grp = StartPointIn(la, alias_addr, alias_port, link_type, 0);
if (grp == NULL)
return (NULL);
switch (flags_in) {
case 0:
LIST_FOREACH(lnk, &grp->full, all.in) {
if (lnk->dst_addr.s_addr == dst_addr.s_addr &&
lnk->dst_port == dst_port)
return (UseLink(la, lnk));
}
break;
case LINK_UNKNOWN_DEST_PORT:
LIST_FOREACH(lnk, &grp->full, all.in) {
if(lnk->dst_addr.s_addr == dst_addr.s_addr) {
lnk_unknown_dst_port = lnk;
break;
}
}
break;
case LINK_UNKNOWN_DEST_ADDR:
LIST_FOREACH(lnk, &grp->full, all.in) {
if(lnk->dst_port == dst_port) {
lnk_unknown_dst_addr = lnk;
break;
}
}
break;
case LINK_PARTIALLY_SPECIFIED:
lnk_unknown_all = LIST_FIRST(&grp->full);
break;
}
if (lnk_unknown_dst_port == NULL) {
LIST_FOREACH(lnk, &grp->partial, all.in) {
int flags = (flags_in | lnk->flags) & LINK_PARTIALLY_SPECIFIED;
if (flags == LINK_PARTIALLY_SPECIFIED &&
lnk_unknown_all == NULL)
lnk_unknown_all = lnk;
if (flags == LINK_UNKNOWN_DEST_ADDR &&
lnk->dst_port == dst_port &&
lnk_unknown_dst_addr == NULL)
lnk_unknown_dst_addr = lnk;
if (flags == LINK_UNKNOWN_DEST_PORT &&
lnk->dst_addr.s_addr == dst_addr.s_addr) {
lnk_unknown_dst_port = lnk;
break;
}
}
}
lnk = (lnk_unknown_dst_port != NULL) ? lnk_unknown_dst_port
: (lnk_unknown_dst_addr != NULL) ? lnk_unknown_dst_addr
: lnk_unknown_all;
if (lnk == NULL || !replace_partial_links)
return (lnk);
if (lnk->server != NULL) { /* LSNAT link */
src_addr = lnk->server->addr;
src_port = lnk->server->port;
lnk->server = lnk->server->next;
} else {
src_addr = lnk->src_addr;
src_port = lnk->src_port;
}
if (link_type == LINK_SCTP) {
lnk->src_addr = src_addr;
lnk->src_port = src_port;
} else {
lnk = ReLink(lnk,
src_addr, dst_addr, alias_addr,
src_port, dst_port, alias_port,
link_type, 0);
}
return (lnk);
}
static struct alias_link *
FindLinkIn(struct libalias *la, struct in_addr dst_addr,
struct in_addr alias_addr,
u_short dst_port,
u_short alias_port,
int link_type,
int replace_partial_links)
{
struct alias_link *lnk;
LIBALIAS_LOCK_ASSERT(la);
lnk = _FindLinkIn(la, dst_addr, alias_addr, dst_port, alias_port,
link_type, replace_partial_links);
if (lnk == NULL) {
/*
* The following allows permanent links to be specified as
* using the default aliasing address (i.e. device
* interface address) without knowing in advance what that
* address is.
*/
if (la->aliasAddress.s_addr != INADDR_ANY &&
alias_addr.s_addr == la->aliasAddress.s_addr) {
lnk = _FindLinkIn(la, dst_addr, ANY_ADDR, dst_port, alias_port,
link_type, replace_partial_links);
}
}
return (lnk);
}
/* External routines for finding/adding links
-- "external" means outside alias_db.c, but within alias*.c --
FindIcmpIn(), FindIcmpOut()
FindFragmentIn1(), FindFragmentIn2()
AddFragmentPtrLink(), FindFragmentPtr()
FindProtoIn(), FindProtoOut()
FindUdpTcpIn(), FindUdpTcpOut()
AddPptp(), FindPptpOutByCallId(), FindPptpInByCallId(),
FindPptpOutByPeerCallId(), FindPptpInByPeerCallId()
FindOriginalAddress(), FindAliasAddress()
(prototypes in alias_local.h)
*/
struct alias_link *
FindIcmpIn(struct libalias *la, struct in_addr dst_addr,
struct in_addr alias_addr,
u_short id_alias,
int create)
{
struct alias_link *lnk;
LIBALIAS_LOCK_ASSERT(la);
lnk = FindLinkIn(la, dst_addr, alias_addr,
NO_DEST_PORT, id_alias,
LINK_ICMP, 0);
if (lnk == NULL && create && !(la->packetAliasMode & PKT_ALIAS_DENY_INCOMING)) {
struct in_addr target_addr;
target_addr = FindOriginalAddress(la, alias_addr);
lnk = AddLink(la, target_addr, dst_addr, alias_addr,
id_alias, NO_DEST_PORT, id_alias,
LINK_ICMP);
}
return (lnk);
}
struct alias_link *
FindIcmpOut(struct libalias *la, struct in_addr src_addr,
struct in_addr dst_addr,
u_short id,
int create)
{
struct alias_link *lnk;
LIBALIAS_LOCK_ASSERT(la);
lnk = FindLinkOut(la, src_addr, dst_addr,
id, NO_DEST_PORT,
LINK_ICMP, 0);
if (lnk == NULL && create) {
struct in_addr alias_addr;
alias_addr = FindAliasAddress(la, src_addr);
lnk = AddLink(la, src_addr, dst_addr, alias_addr,
id, NO_DEST_PORT, GET_ALIAS_ID,
LINK_ICMP);
}
return (lnk);
}
struct alias_link *
FindFragmentIn1(struct libalias *la, struct in_addr dst_addr,
struct in_addr alias_addr,
u_short ip_id)
{
struct alias_link *lnk;
LIBALIAS_LOCK_ASSERT(la);
lnk = FindLinkIn(la, dst_addr, alias_addr,
NO_DEST_PORT, ip_id,
LINK_FRAGMENT_ID, 0);
if (lnk == NULL) {
lnk = AddLink(la, ANY_ADDR, dst_addr, alias_addr,
NO_SRC_PORT, NO_DEST_PORT, ip_id,
LINK_FRAGMENT_ID);
}
return (lnk);
}
/* Doesn't add a link if one is not found. */
struct alias_link *
FindFragmentIn2(struct libalias *la, struct in_addr dst_addr,
struct in_addr alias_addr, u_short ip_id)
{
LIBALIAS_LOCK_ASSERT(la);
return FindLinkIn(la, dst_addr, alias_addr,
NO_DEST_PORT, ip_id,
LINK_FRAGMENT_ID, 0);
}
struct alias_link *
AddFragmentPtrLink(struct libalias *la, struct in_addr dst_addr,
u_short ip_id)
{
LIBALIAS_LOCK_ASSERT(la);
return AddLink(la, ANY_ADDR, dst_addr, ANY_ADDR,
NO_SRC_PORT, NO_DEST_PORT, ip_id,
LINK_FRAGMENT_PTR);
}
struct alias_link *
FindFragmentPtr(struct libalias *la, struct in_addr dst_addr,
u_short ip_id)
{
LIBALIAS_LOCK_ASSERT(la);
return FindLinkIn(la, dst_addr, ANY_ADDR,
NO_DEST_PORT, ip_id,
LINK_FRAGMENT_PTR, 0);
}
struct alias_link *
FindProtoIn(struct libalias *la, struct in_addr dst_addr,
struct in_addr alias_addr,
u_char proto)
{
struct alias_link *lnk;
LIBALIAS_LOCK_ASSERT(la);
lnk = FindLinkIn(la, dst_addr, alias_addr,
NO_DEST_PORT, 0,
proto, 1);
if (lnk == NULL && !(la->packetAliasMode & PKT_ALIAS_DENY_INCOMING)) {
struct in_addr target_addr;
target_addr = FindOriginalAddress(la, alias_addr);
lnk = AddLink(la, target_addr, dst_addr, alias_addr,
NO_SRC_PORT, NO_DEST_PORT, 0,
proto);
}
return (lnk);
}
struct alias_link *
FindProtoOut(struct libalias *la, struct in_addr src_addr,
struct in_addr dst_addr,
u_char proto)
{
struct alias_link *lnk;
LIBALIAS_LOCK_ASSERT(la);
lnk = FindLinkOut(la, src_addr, dst_addr,
NO_SRC_PORT, NO_DEST_PORT,
proto, 1);
if (lnk == NULL) {
struct in_addr alias_addr;
alias_addr = FindAliasAddress(la, src_addr);
lnk = AddLink(la, src_addr, dst_addr, alias_addr,
NO_SRC_PORT, NO_DEST_PORT, 0,
proto);
}
return (lnk);
}
struct alias_link *
FindUdpTcpIn(struct libalias *la, struct in_addr dst_addr,
struct in_addr alias_addr,
u_short dst_port,
u_short alias_port,
u_char proto,
int create)
{
int link_type;
struct alias_link *lnk;
LIBALIAS_LOCK_ASSERT(la);
switch (proto) {
case IPPROTO_UDP:
link_type = LINK_UDP;
break;
case IPPROTO_TCP:
link_type = LINK_TCP;
break;
default:
2004-07-05 06:55:23 -04:00
return (NULL);
break;
}
lnk = FindLinkIn(la, dst_addr, alias_addr,
dst_port, alias_port,
link_type, create);
if (lnk == NULL && create && !(la->packetAliasMode & PKT_ALIAS_DENY_INCOMING)) {
struct in_addr target_addr;
target_addr = FindOriginalAddress(la, alias_addr);
lnk = AddLink(la, target_addr, dst_addr, alias_addr,
alias_port, dst_port, alias_port,
link_type);
}
return (lnk);
}
struct alias_link *
FindUdpTcpOut(struct libalias *la, struct in_addr src_addr,
struct in_addr dst_addr,
u_short src_port,
u_short dst_port,
u_char proto,
int create)
{
int link_type;
struct alias_link *lnk;
LIBALIAS_LOCK_ASSERT(la);
switch (proto) {
case IPPROTO_UDP:
link_type = LINK_UDP;
break;
case IPPROTO_TCP:
link_type = LINK_TCP;
break;
default:
2004-07-05 06:55:23 -04:00
return (NULL);
break;
}
lnk = FindLinkOut(la, src_addr, dst_addr, src_port, dst_port, link_type, create);
if (lnk == NULL && create) {
struct in_addr alias_addr;
alias_addr = FindAliasAddress(la, src_addr);
lnk = AddLink(la, src_addr, dst_addr, alias_addr,
src_port, dst_port, GET_ALIAS_PORT,
link_type);
}
return (lnk);
}
struct alias_link *
AddPptp(struct libalias *la, struct in_addr src_addr,
struct in_addr dst_addr,
struct in_addr alias_addr,
u_int16_t src_call_id)
{
struct alias_link *lnk;
LIBALIAS_LOCK_ASSERT(la);
lnk = AddLink(la, src_addr, dst_addr, alias_addr,
src_call_id, 0, GET_ALIAS_PORT,
LINK_PPTP);
return (lnk);
}
struct alias_link *
FindPptpOutByCallId(struct libalias *la, struct in_addr src_addr,
struct in_addr dst_addr,
u_int16_t src_call_id)
{
struct alias_link *lnk;
LIBALIAS_LOCK_ASSERT(la);
LIST_FOREACH(lnk, &la->pptpList, pptp.list)
if (lnk->src_addr.s_addr == src_addr.s_addr &&
lnk->dst_addr.s_addr == dst_addr.s_addr &&
lnk->src_port == src_call_id)
break;
return (UseLink(la, lnk));
}
struct alias_link *
FindPptpOutByPeerCallId(struct libalias *la, struct in_addr src_addr,
struct in_addr dst_addr,
u_int16_t dst_call_id)
{
struct alias_link *lnk;
LIBALIAS_LOCK_ASSERT(la);
LIST_FOREACH(lnk, &la->pptpList, pptp.list)
if (lnk->src_addr.s_addr == src_addr.s_addr &&
lnk->dst_addr.s_addr == dst_addr.s_addr &&
lnk->dst_port == dst_call_id)
break;
return (UseLink(la, lnk));
}
struct alias_link *
FindPptpInByCallId(struct libalias *la, struct in_addr dst_addr,
struct in_addr alias_addr,
u_int16_t dst_call_id)
{
struct alias_link *lnk;
LIBALIAS_LOCK_ASSERT(la);
LIST_FOREACH(lnk, &la->pptpList, pptp.list)
if (lnk->dst_port == dst_call_id &&
lnk->dst_addr.s_addr == dst_addr.s_addr &&
lnk->alias_addr.s_addr == alias_addr.s_addr)
break;
return (UseLink(la, lnk));
}
struct alias_link *
FindPptpInByPeerCallId(struct libalias *la, struct in_addr dst_addr,
struct in_addr alias_addr,
u_int16_t alias_call_id)
{
struct alias_link *lnk;
LIBALIAS_LOCK_ASSERT(la);
LIST_FOREACH(lnk, &la->pptpList, pptp.list)
if (lnk->alias_port == alias_call_id &&
lnk->dst_addr.s_addr == dst_addr.s_addr &&
lnk->alias_addr.s_addr == alias_addr.s_addr)
break;
return (lnk);
}
2002-07-01 07:19:40 -04:00
struct alias_link *
FindRtspOut(struct libalias *la, struct in_addr src_addr,
struct in_addr dst_addr,
u_short src_port,
u_short alias_port,
u_char proto)
{
int link_type;
struct alias_link *lnk;
LIBALIAS_LOCK_ASSERT(la);
switch (proto) {
case IPPROTO_UDP:
link_type = LINK_UDP;
break;
case IPPROTO_TCP:
link_type = LINK_TCP;
break;
default:
2004-07-05 06:55:23 -04:00
return (NULL);
break;
}
lnk = FindLinkOut(la, src_addr, dst_addr, src_port, 0, link_type, 1);
if (lnk == NULL) {
struct in_addr alias_addr;
alias_addr = FindAliasAddress(la, src_addr);
lnk = AddLink(la, src_addr, dst_addr, alias_addr,
src_port, 0, alias_port,
link_type);
}
return (lnk);
}
struct in_addr
FindOriginalAddress(struct libalias *la, struct in_addr alias_addr)
{
struct alias_link *lnk;
LIBALIAS_LOCK_ASSERT(la);
lnk = FindLinkIn(la, ANY_ADDR, alias_addr,
0, 0, LINK_ADDR, 0);
if (lnk == NULL) {
if (la->targetAddress.s_addr == INADDR_ANY)
2004-07-05 06:55:23 -04:00
return (alias_addr);
else if (la->targetAddress.s_addr == INADDR_NONE)
return (la->aliasAddress.s_addr != INADDR_ANY) ?
la->aliasAddress : alias_addr;
else
2004-07-05 06:55:23 -04:00
return (la->targetAddress);
} else {
if (lnk->server != NULL) { /* LSNAT link */
struct in_addr src_addr;
src_addr = lnk->server->addr;
lnk->server = lnk->server->next;
return (src_addr);
} else if (lnk->src_addr.s_addr == INADDR_ANY)
return (la->aliasAddress.s_addr != INADDR_ANY) ?
la->aliasAddress : alias_addr;
else
return (lnk->src_addr);
}
}
struct in_addr
FindAliasAddress(struct libalias *la, struct in_addr original_addr)
{
struct alias_link *lnk;
2002-07-01 07:19:40 -04:00
LIBALIAS_LOCK_ASSERT(la);
lnk = FindLinkOut(la, original_addr, ANY_ADDR,
0, 0, LINK_ADDR, 0);
if (lnk == NULL) {
return (la->aliasAddress.s_addr != INADDR_ANY) ?
la->aliasAddress : original_addr;
} else {
if (lnk->alias_addr.s_addr == INADDR_ANY)
return (la->aliasAddress.s_addr != INADDR_ANY) ?
la->aliasAddress : original_addr;
else
return (lnk->alias_addr);
}
}
/* External routines for getting or changing link data
(external to alias_db.c, but internal to alias*.c)
SetFragmentData(), GetFragmentData()
SetFragmentPtr(), GetFragmentPtr()
SetStateIn(), SetStateOut(), GetStateIn(), GetStateOut()
GetOriginalAddress(), GetDestAddress(), GetAliasAddress()
GetOriginalPort(), GetAliasPort()
SetAckModified(), GetAckModified()
GetDeltaAckIn(), GetDeltaSeqOut(), AddSeq()
SetProtocolFlags(), GetProtocolFlags()
SetDestCallId()
*/
void
SetFragmentAddr(struct alias_link *lnk, struct in_addr src_addr)
{
lnk->data.frag_addr = src_addr;
}
void
GetFragmentAddr(struct alias_link *lnk, struct in_addr *src_addr)
{
*src_addr = lnk->data.frag_addr;
}
void
SetFragmentPtr(struct alias_link *lnk, void *fptr)
{
lnk->data.frag_ptr = fptr;
}
void
GetFragmentPtr(struct alias_link *lnk, void **fptr)
{
*fptr = lnk->data.frag_ptr;
}
void
SetStateIn(struct alias_link *lnk, int state)
{
/* TCP input state */
switch (state) {
case ALIAS_TCP_STATE_DISCONNECTED:
if (lnk->data.tcp->state.out != ALIAS_TCP_STATE_CONNECTED)
lnk->expire.time = TCP_EXPIRE_DEAD;
else
lnk->expire.time = TCP_EXPIRE_SINGLEDEAD;
break;
case ALIAS_TCP_STATE_CONNECTED:
if (lnk->data.tcp->state.out == ALIAS_TCP_STATE_CONNECTED)
lnk->expire.time = TCP_EXPIRE_CONNECTED;
break;
default:
#ifdef _KERNEL
panic("libalias:SetStateIn() unknown state");
#else
abort();
#endif
}
lnk->data.tcp->state.in = state;
}
void
SetStateOut(struct alias_link *lnk, int state)
{
/* TCP output state */
switch (state) {
case ALIAS_TCP_STATE_DISCONNECTED:
if (lnk->data.tcp->state.in != ALIAS_TCP_STATE_CONNECTED)
lnk->expire.time = TCP_EXPIRE_DEAD;
else
lnk->expire.time = TCP_EXPIRE_SINGLEDEAD;
break;
case ALIAS_TCP_STATE_CONNECTED:
if (lnk->data.tcp->state.in == ALIAS_TCP_STATE_CONNECTED)
lnk->expire.time = TCP_EXPIRE_CONNECTED;
break;
default:
#ifdef _KERNEL
panic("libalias:SetStateOut() unknown state");
#else
abort();
#endif
}
lnk->data.tcp->state.out = state;
}
int
GetStateIn(struct alias_link *lnk)
{
/* TCP input state */
return (lnk->data.tcp->state.in);
}
int
GetStateOut(struct alias_link *lnk)
{
/* TCP output state */
return (lnk->data.tcp->state.out);
}
struct in_addr
GetOriginalAddress(struct alias_link *lnk)
{
if (lnk->src_addr.s_addr == INADDR_ANY)
return (lnk->la->aliasAddress);
else
return (lnk->src_addr);
}
struct in_addr
GetDestAddress(struct alias_link *lnk)
{
return (lnk->dst_addr);
}
struct in_addr
GetAliasAddress(struct alias_link *lnk)
{
if (lnk->alias_addr.s_addr == INADDR_ANY)
return (lnk->la->aliasAddress);
else
return (lnk->alias_addr);
}
struct in_addr
GetDefaultAliasAddress(struct libalias *la)
{
LIBALIAS_LOCK_ASSERT(la);
2004-07-05 06:55:23 -04:00
return (la->aliasAddress);
}
void
SetDefaultAliasAddress(struct libalias *la, struct in_addr alias_addr)
{
LIBALIAS_LOCK_ASSERT(la);
la->aliasAddress = alias_addr;
}
u_short
GetOriginalPort(struct alias_link *lnk)
{
return (lnk->src_port);
}
u_short
GetAliasPort(struct alias_link *lnk)
{
return (lnk->alias_port);
}
#ifndef NO_FW_PUNCH
static u_short
GetDestPort(struct alias_link *lnk)
{
return (lnk->dst_port);
}
#endif
/* Indicate that ACK numbers have been modified in a TCP connection */
void
SetAckModified(struct alias_link *lnk)
{
lnk->data.tcp->state.ack_modified = 1;
}
struct in_addr
GetProxyAddress(struct alias_link *lnk)
{
return (lnk->proxy_addr);
}
void
SetProxyAddress(struct alias_link *lnk, struct in_addr addr)
{
lnk->proxy_addr = addr;
}
u_short
GetProxyPort(struct alias_link *lnk)
{
return (lnk->proxy_port);
}
void
SetProxyPort(struct alias_link *lnk, u_short port)
{
lnk->proxy_port = port;
}
/* See if ACK numbers have been modified */
int
GetAckModified(struct alias_link *lnk)
{
return (lnk->data.tcp->state.ack_modified);
}
/*
* Find out how much the ACK number has been altered for an
* incoming TCP packet. To do this, a circular list of ACK
* numbers where the TCP packet size was altered is searched.
*/
// XXX ip free
int
GetDeltaAckIn(u_long ack, struct alias_link *lnk)
{
int i, j;
int delta, ack_diff_min;
delta = 0;
ack_diff_min = -1;
i = lnk->data.tcp->state.index;
for (j = 0; j < N_LINK_TCP_DATA; j++) {
struct ack_data_record x;
if (i == 0)
i = N_LINK_TCP_DATA;
i--;
x = lnk->data.tcp->ack[i];
if (x.active == 1) {
int ack_diff;
ack_diff = SeqDiff(x.ack_new, ack);
if (ack_diff >= 0) {
if (ack_diff_min >= 0) {
if (ack_diff < ack_diff_min) {
delta = x.delta;
ack_diff_min = ack_diff;
}
} else {
delta = x.delta;
ack_diff_min = ack_diff;
}
}
}
}
return (delta);
}
/*
* Find out how much the sequence number has been altered for an
* outgoing TCP packet. To do this, a circular list of ACK numbers
* where the TCP packet size was altered is searched.
*/
// XXX ip free
int
GetDeltaSeqOut(u_long seq, struct alias_link *lnk)
{
int i, j;
int delta, seq_diff_min;
delta = 0;
seq_diff_min = -1;
i = lnk->data.tcp->state.index;
for (j = 0; j < N_LINK_TCP_DATA; j++) {
struct ack_data_record x;
if (i == 0)
i = N_LINK_TCP_DATA;
i--;
x = lnk->data.tcp->ack[i];
if (x.active == 1) {
int seq_diff;
seq_diff = SeqDiff(x.ack_old, seq);
if (seq_diff >= 0) {
if (seq_diff_min >= 0) {
if (seq_diff < seq_diff_min) {
delta = x.delta;
seq_diff_min = seq_diff;
}
} else {
delta = x.delta;
seq_diff_min = seq_diff;
}
}
}
}
return (delta);
}
/*
* When a TCP packet has been altered in length, save this
* information in a circular list. If enough packets have been
* altered, then this list will begin to overwrite itself.
*/
// XXX ip free
void
AddSeq(struct alias_link *lnk, int delta, u_int ip_hl, u_short ip_len,
u_long th_seq, u_int th_off)
{
struct ack_data_record x;
int hlen, tlen, dlen;
int i;
hlen = (ip_hl + th_off) << 2;
tlen = ntohs(ip_len);
dlen = tlen - hlen;
x.ack_old = htonl(ntohl(th_seq) + dlen);
x.ack_new = htonl(ntohl(th_seq) + dlen + delta);
x.delta = delta;
x.active = 1;
i = lnk->data.tcp->state.index;
lnk->data.tcp->ack[i] = x;
i++;
if (i == N_LINK_TCP_DATA)
lnk->data.tcp->state.index = 0;
else
lnk->data.tcp->state.index = i;
}
void
SetExpire(struct alias_link *lnk, int expire)
{
if (expire == 0) {
lnk->flags &= ~LINK_PERMANENT;
DeleteLink(&lnk, 0);
} else if (expire == -1) {
lnk->flags |= LINK_PERMANENT;
} else if (expire > 0) {
lnk->expire.time = expire;
} else {
#ifdef LIBALIAS_DEBUG
fprintf(stderr, "PacketAlias/SetExpire(): ");
fprintf(stderr, "error in expire parameter\n");
#endif
}
}
void
SetProtocolFlags(struct alias_link *lnk, int pflags)
{
lnk->pflags = pflags;
}
int
GetProtocolFlags(struct alias_link *lnk)
{
return (lnk->pflags);
}
void
SetDestCallId(struct alias_link *lnk, u_int16_t cid)
{
LIBALIAS_LOCK_ASSERT(lnk->la);
ReLink(lnk, lnk->src_addr, lnk->dst_addr, lnk->alias_addr,
lnk->src_port, cid, lnk->alias_port, lnk->link_type, 1);
}
/* Miscellaneous Functions
HouseKeeping()
InitPacketAliasLog()
UninitPacketAliasLog()
*/
/*
Whenever an outgoing or incoming packet is handled, HouseKeeping()
is called to find and remove timed-out aliasing links. Logic exists
to sweep through the entire table and linked list structure
every 60 seconds.
(prototype in alias_local.h)
*/
void
HouseKeeping(struct libalias *la)
{
static unsigned int packets = 0;
static unsigned int packet_limit = 1000;
LIBALIAS_LOCK_ASSERT(la);
packets++;
/*
* User space time/gettimeofday/... is very expensive.
* Kernel space cache trashing is unnecessary.
*
* Save system time (seconds) in global variable LibAliasTime
* for use by other functions. This is done so as not to
* unnecessarily waste timeline by making system calls.
*
* Reduce the amount of house keeping work substantially by
* sampling over the packets.
*/
if (packet_limit <= 1 || packets % packet_limit == 0) {
time_t now;
#ifdef _KERNEL
now = time_uptime;
#else
now = time(NULL);
#endif
if (now != LibAliasTime) {
/* retry three times a second */
packet_limit = packets / 3;
packets = 0;
LibAliasTime = now;
}
}
/* Do a cleanup for the first packets of the new second only */
if (packets < (la->udpLinkCount + la->tcpLinkCount)) {
struct alias_link * lnk = TAILQ_FIRST(&la->checkExpire);
CleanupLink(la, &lnk, 0);
}
}
/* Init the log file and enable logging */
Summer of Code 2005: improve libalias - part 1 of 2 With the first part of my previous Summer of Code work, we get: -made libalias modular: -support for 'particular' protocols (like ftp/irc/etcetc) is no more hardcoded inside libalias, but it's available through external modules loadable at runtime -modules are available both in kernel (/boot/kernel/alias_*.ko) and user land (/lib/libalias_*) -protocols/applications modularized are: cuseeme, ftp, irc, nbt, pptp, skinny and smedia -added logging support for kernel side -cleanup After a buildworld, do a 'mergemaster -i' to install the file libalias.conf in /etc or manually copy it. During startup (and after every HUP signal) user land applications running the new libalias will try to read a file in /etc called libalias.conf: that file contains the list of modules to load. User land applications affected by this commit are ppp and natd: if libalias.conf is present in /etc you won't notice any difference. The only kernel land bit affected by this commit is ng_nat: if you are using ng_nat, and it doesn't correctly handle ftp/irc/etcetc sessions anymore, remember to kldload the correspondent module (i.e. kldload alias_ftp). General information and details about the inner working are available in the libalias man page under the section 'MODULAR ARCHITECTURE (AND ipfw(4) SUPPORT)'. NOTA BENE: this commit affects _ONLY_ libalias, ipfw in-kernel nat support will be part of the next libalias-related commit. Approved by: glebius Reviewed by: glebius, ru
2006-09-26 19:26:53 -04:00
static int
InitPacketAliasLog(struct libalias *la)
{
LIBALIAS_LOCK_ASSERT(la);
Summer of Code 2005: improve libalias - part 1 of 2 With the first part of my previous Summer of Code work, we get: -made libalias modular: -support for 'particular' protocols (like ftp/irc/etcetc) is no more hardcoded inside libalias, but it's available through external modules loadable at runtime -modules are available both in kernel (/boot/kernel/alias_*.ko) and user land (/lib/libalias_*) -protocols/applications modularized are: cuseeme, ftp, irc, nbt, pptp, skinny and smedia -added logging support for kernel side -cleanup After a buildworld, do a 'mergemaster -i' to install the file libalias.conf in /etc or manually copy it. During startup (and after every HUP signal) user land applications running the new libalias will try to read a file in /etc called libalias.conf: that file contains the list of modules to load. User land applications affected by this commit are ppp and natd: if libalias.conf is present in /etc you won't notice any difference. The only kernel land bit affected by this commit is ng_nat: if you are using ng_nat, and it doesn't correctly handle ftp/irc/etcetc sessions anymore, remember to kldload the correspondent module (i.e. kldload alias_ftp). General information and details about the inner working are available in the libalias man page under the section 'MODULAR ARCHITECTURE (AND ipfw(4) SUPPORT)'. NOTA BENE: this commit affects _ONLY_ libalias, ipfw in-kernel nat support will be part of the next libalias-related commit. Approved by: glebius Reviewed by: glebius, ru
2006-09-26 19:26:53 -04:00
if (~la->packetAliasMode & PKT_ALIAS_LOG) {
#ifdef _KERNEL
if ((la->logDesc = malloc(LIBALIAS_BUF_SIZE)))
;
#else
Summer of Code 2005: improve libalias - part 1 of 2 With the first part of my previous Summer of Code work, we get: -made libalias modular: -support for 'particular' protocols (like ftp/irc/etcetc) is no more hardcoded inside libalias, but it's available through external modules loadable at runtime -modules are available both in kernel (/boot/kernel/alias_*.ko) and user land (/lib/libalias_*) -protocols/applications modularized are: cuseeme, ftp, irc, nbt, pptp, skinny and smedia -added logging support for kernel side -cleanup After a buildworld, do a 'mergemaster -i' to install the file libalias.conf in /etc or manually copy it. During startup (and after every HUP signal) user land applications running the new libalias will try to read a file in /etc called libalias.conf: that file contains the list of modules to load. User land applications affected by this commit are ppp and natd: if libalias.conf is present in /etc you won't notice any difference. The only kernel land bit affected by this commit is ng_nat: if you are using ng_nat, and it doesn't correctly handle ftp/irc/etcetc sessions anymore, remember to kldload the correspondent module (i.e. kldload alias_ftp). General information and details about the inner working are available in the libalias man page under the section 'MODULAR ARCHITECTURE (AND ipfw(4) SUPPORT)'. NOTA BENE: this commit affects _ONLY_ libalias, ipfw in-kernel nat support will be part of the next libalias-related commit. Approved by: glebius Reviewed by: glebius, ru
2006-09-26 19:26:53 -04:00
if ((la->logDesc = fopen("/var/log/alias.log", "w")))
fprintf(la->logDesc, "PacketAlias/InitPacketAliasLog: Packet alias logging enabled.\n");
Summer of Code 2005: improve libalias - part 1 of 2 With the first part of my previous Summer of Code work, we get: -made libalias modular: -support for 'particular' protocols (like ftp/irc/etcetc) is no more hardcoded inside libalias, but it's available through external modules loadable at runtime -modules are available both in kernel (/boot/kernel/alias_*.ko) and user land (/lib/libalias_*) -protocols/applications modularized are: cuseeme, ftp, irc, nbt, pptp, skinny and smedia -added logging support for kernel side -cleanup After a buildworld, do a 'mergemaster -i' to install the file libalias.conf in /etc or manually copy it. During startup (and after every HUP signal) user land applications running the new libalias will try to read a file in /etc called libalias.conf: that file contains the list of modules to load. User land applications affected by this commit are ppp and natd: if libalias.conf is present in /etc you won't notice any difference. The only kernel land bit affected by this commit is ng_nat: if you are using ng_nat, and it doesn't correctly handle ftp/irc/etcetc sessions anymore, remember to kldload the correspondent module (i.e. kldload alias_ftp). General information and details about the inner working are available in the libalias man page under the section 'MODULAR ARCHITECTURE (AND ipfw(4) SUPPORT)'. NOTA BENE: this commit affects _ONLY_ libalias, ipfw in-kernel nat support will be part of the next libalias-related commit. Approved by: glebius Reviewed by: glebius, ru
2006-09-26 19:26:53 -04:00
#endif
else
Summer of Code 2005: improve libalias - part 1 of 2 With the first part of my previous Summer of Code work, we get: -made libalias modular: -support for 'particular' protocols (like ftp/irc/etcetc) is no more hardcoded inside libalias, but it's available through external modules loadable at runtime -modules are available both in kernel (/boot/kernel/alias_*.ko) and user land (/lib/libalias_*) -protocols/applications modularized are: cuseeme, ftp, irc, nbt, pptp, skinny and smedia -added logging support for kernel side -cleanup After a buildworld, do a 'mergemaster -i' to install the file libalias.conf in /etc or manually copy it. During startup (and after every HUP signal) user land applications running the new libalias will try to read a file in /etc called libalias.conf: that file contains the list of modules to load. User land applications affected by this commit are ppp and natd: if libalias.conf is present in /etc you won't notice any difference. The only kernel land bit affected by this commit is ng_nat: if you are using ng_nat, and it doesn't correctly handle ftp/irc/etcetc sessions anymore, remember to kldload the correspondent module (i.e. kldload alias_ftp). General information and details about the inner working are available in the libalias man page under the section 'MODULAR ARCHITECTURE (AND ipfw(4) SUPPORT)'. NOTA BENE: this commit affects _ONLY_ libalias, ipfw in-kernel nat support will be part of the next libalias-related commit. Approved by: glebius Reviewed by: glebius, ru
2006-09-26 19:26:53 -04:00
return (ENOMEM); /* log initialization failed */
la->packetAliasMode |= PKT_ALIAS_LOG;
}
Summer of Code 2005: improve libalias - part 1 of 2 With the first part of my previous Summer of Code work, we get: -made libalias modular: -support for 'particular' protocols (like ftp/irc/etcetc) is no more hardcoded inside libalias, but it's available through external modules loadable at runtime -modules are available both in kernel (/boot/kernel/alias_*.ko) and user land (/lib/libalias_*) -protocols/applications modularized are: cuseeme, ftp, irc, nbt, pptp, skinny and smedia -added logging support for kernel side -cleanup After a buildworld, do a 'mergemaster -i' to install the file libalias.conf in /etc or manually copy it. During startup (and after every HUP signal) user land applications running the new libalias will try to read a file in /etc called libalias.conf: that file contains the list of modules to load. User land applications affected by this commit are ppp and natd: if libalias.conf is present in /etc you won't notice any difference. The only kernel land bit affected by this commit is ng_nat: if you are using ng_nat, and it doesn't correctly handle ftp/irc/etcetc sessions anymore, remember to kldload the correspondent module (i.e. kldload alias_ftp). General information and details about the inner working are available in the libalias man page under the section 'MODULAR ARCHITECTURE (AND ipfw(4) SUPPORT)'. NOTA BENE: this commit affects _ONLY_ libalias, ipfw in-kernel nat support will be part of the next libalias-related commit. Approved by: glebius Reviewed by: glebius, ru
2006-09-26 19:26:53 -04:00
return (1);
}
/* Close the log-file and disable logging. */
static void
UninitPacketAliasLog(struct libalias *la)
{
LIBALIAS_LOCK_ASSERT(la);
if (la->logDesc) {
Summer of Code 2005: improve libalias - part 1 of 2 With the first part of my previous Summer of Code work, we get: -made libalias modular: -support for 'particular' protocols (like ftp/irc/etcetc) is no more hardcoded inside libalias, but it's available through external modules loadable at runtime -modules are available both in kernel (/boot/kernel/alias_*.ko) and user land (/lib/libalias_*) -protocols/applications modularized are: cuseeme, ftp, irc, nbt, pptp, skinny and smedia -added logging support for kernel side -cleanup After a buildworld, do a 'mergemaster -i' to install the file libalias.conf in /etc or manually copy it. During startup (and after every HUP signal) user land applications running the new libalias will try to read a file in /etc called libalias.conf: that file contains the list of modules to load. User land applications affected by this commit are ppp and natd: if libalias.conf is present in /etc you won't notice any difference. The only kernel land bit affected by this commit is ng_nat: if you are using ng_nat, and it doesn't correctly handle ftp/irc/etcetc sessions anymore, remember to kldload the correspondent module (i.e. kldload alias_ftp). General information and details about the inner working are available in the libalias man page under the section 'MODULAR ARCHITECTURE (AND ipfw(4) SUPPORT)'. NOTA BENE: this commit affects _ONLY_ libalias, ipfw in-kernel nat support will be part of the next libalias-related commit. Approved by: glebius Reviewed by: glebius, ru
2006-09-26 19:26:53 -04:00
#ifdef _KERNEL
free(la->logDesc);
Summer of Code 2005: improve libalias - part 1 of 2 With the first part of my previous Summer of Code work, we get: -made libalias modular: -support for 'particular' protocols (like ftp/irc/etcetc) is no more hardcoded inside libalias, but it's available through external modules loadable at runtime -modules are available both in kernel (/boot/kernel/alias_*.ko) and user land (/lib/libalias_*) -protocols/applications modularized are: cuseeme, ftp, irc, nbt, pptp, skinny and smedia -added logging support for kernel side -cleanup After a buildworld, do a 'mergemaster -i' to install the file libalias.conf in /etc or manually copy it. During startup (and after every HUP signal) user land applications running the new libalias will try to read a file in /etc called libalias.conf: that file contains the list of modules to load. User land applications affected by this commit are ppp and natd: if libalias.conf is present in /etc you won't notice any difference. The only kernel land bit affected by this commit is ng_nat: if you are using ng_nat, and it doesn't correctly handle ftp/irc/etcetc sessions anymore, remember to kldload the correspondent module (i.e. kldload alias_ftp). General information and details about the inner working are available in the libalias man page under the section 'MODULAR ARCHITECTURE (AND ipfw(4) SUPPORT)'. NOTA BENE: this commit affects _ONLY_ libalias, ipfw in-kernel nat support will be part of the next libalias-related commit. Approved by: glebius Reviewed by: glebius, ru
2006-09-26 19:26:53 -04:00
#else
fclose(la->logDesc);
Summer of Code 2005: improve libalias - part 1 of 2 With the first part of my previous Summer of Code work, we get: -made libalias modular: -support for 'particular' protocols (like ftp/irc/etcetc) is no more hardcoded inside libalias, but it's available through external modules loadable at runtime -modules are available both in kernel (/boot/kernel/alias_*.ko) and user land (/lib/libalias_*) -protocols/applications modularized are: cuseeme, ftp, irc, nbt, pptp, skinny and smedia -added logging support for kernel side -cleanup After a buildworld, do a 'mergemaster -i' to install the file libalias.conf in /etc or manually copy it. During startup (and after every HUP signal) user land applications running the new libalias will try to read a file in /etc called libalias.conf: that file contains the list of modules to load. User land applications affected by this commit are ppp and natd: if libalias.conf is present in /etc you won't notice any difference. The only kernel land bit affected by this commit is ng_nat: if you are using ng_nat, and it doesn't correctly handle ftp/irc/etcetc sessions anymore, remember to kldload the correspondent module (i.e. kldload alias_ftp). General information and details about the inner working are available in the libalias man page under the section 'MODULAR ARCHITECTURE (AND ipfw(4) SUPPORT)'. NOTA BENE: this commit affects _ONLY_ libalias, ipfw in-kernel nat support will be part of the next libalias-related commit. Approved by: glebius Reviewed by: glebius, ru
2006-09-26 19:26:53 -04:00
#endif
la->logDesc = NULL;
}
la->packetAliasMode &= ~PKT_ALIAS_LOG;
}
/* Outside world interfaces
-- "outside world" means other than alias*.c routines --
PacketAliasRedirectPort()
PacketAliasAddServer()
PacketAliasRedirectProto()
PacketAliasRedirectAddr()
PacketAliasRedirectDynamic()
PacketAliasRedirectDelete()
PacketAliasSetAddress()
PacketAliasInit()
PacketAliasUninit()
PacketAliasSetMode()
(prototypes in alias.h)
*/
/* Redirection from a specific public addr:port to a
private addr:port */
struct alias_link *
LibAliasRedirectPort(struct libalias *la, struct in_addr src_addr, u_short src_port,
struct in_addr dst_addr, u_short dst_port,
struct in_addr alias_addr, u_short alias_port,
u_char proto)
{
int link_type;
struct alias_link *lnk;
LIBALIAS_LOCK(la);
switch (proto) {
case IPPROTO_UDP:
link_type = LINK_UDP;
break;
case IPPROTO_TCP:
link_type = LINK_TCP;
break;
case IPPROTO_SCTP:
link_type = LINK_SCTP;
break;
default:
#ifdef LIBALIAS_DEBUG
fprintf(stderr, "PacketAliasRedirectPort(): ");
fprintf(stderr, "only SCTP, TCP and UDP protocols allowed\n");
#endif
lnk = NULL;
goto getout;
}
lnk = AddLink(la, src_addr, dst_addr, alias_addr,
src_port, dst_port, alias_port,
link_type);
if (lnk != NULL) {
lnk->flags |= LINK_PERMANENT;
}
#ifdef LIBALIAS_DEBUG
else {
fprintf(stderr, "PacketAliasRedirectPort(): "
"call to AddLink() failed\n");
}
#endif
getout:
LIBALIAS_UNLOCK(la);
return (lnk);
}
/* Add server to the pool of servers */
int
LibAliasAddServer(struct libalias *la, struct alias_link *lnk, struct in_addr addr, u_short port)
{
struct server *server;
int res;
LIBALIAS_LOCK(la);
(void)la;
switch (lnk->link_type) {
case LINK_PPTP:
server = NULL;
break;
default:
server = malloc(sizeof(struct server));
break;
}
if (server != NULL) {
struct server *head;
server->addr = addr;
server->port = port;
head = lnk->server;
if (head == NULL) {
server->next = server;
/* not usable for outgoing connections */
SPLAY_REMOVE(splay_out, &la->linkSplayOut, lnk);
} else {
struct server *s;
for (s = head; s->next != head; s = s->next)
;
s->next = server;
server->next = head;
}
lnk->server = server;
res = 0;
} else
res = -1;
LIBALIAS_UNLOCK(la);
return (res);
}
/* Redirect packets of a given IP protocol from a specific
public address to a private address */
struct alias_link *
LibAliasRedirectProto(struct libalias *la, struct in_addr src_addr,
struct in_addr dst_addr,
struct in_addr alias_addr,
u_char proto)
{
struct alias_link *lnk;
LIBALIAS_LOCK(la);
lnk = AddLink(la, src_addr, dst_addr, alias_addr,
NO_SRC_PORT, NO_DEST_PORT, 0,
proto);
if (lnk != NULL) {
lnk->flags |= LINK_PERMANENT;
}
#ifdef LIBALIAS_DEBUG
else {
fprintf(stderr, "PacketAliasRedirectProto(): "
"call to AddLink() failed\n");
}
#endif
LIBALIAS_UNLOCK(la);
return (lnk);
}
/* Static address translation */
struct alias_link *
LibAliasRedirectAddr(struct libalias *la, struct in_addr src_addr,
struct in_addr alias_addr)
{
struct alias_link *lnk;
LIBALIAS_LOCK(la);
lnk = AddLink(la, src_addr, ANY_ADDR, alias_addr,
0, 0, 0,
LINK_ADDR);
if (lnk != NULL) {
lnk->flags |= LINK_PERMANENT;
}
#ifdef LIBALIAS_DEBUG
else {
fprintf(stderr, "PacketAliasRedirectAddr(): "
"call to AddLink() failed\n");
}
#endif
LIBALIAS_UNLOCK(la);
return (lnk);
}
/* Mark the aliasing link dynamic */
int
LibAliasRedirectDynamic(struct libalias *la, struct alias_link *lnk)
{
int res;
LIBALIAS_LOCK(la);
(void)la;
if (lnk->flags & LINK_PARTIALLY_SPECIFIED)
res = -1;
else {
lnk->flags &= ~LINK_PERMANENT;
res = 0;
}
LIBALIAS_UNLOCK(la);
return (res);
}
/* This is a dangerous function to put in the API,
because an invalid pointer can crash the program. */
void
LibAliasRedirectDelete(struct libalias *la, struct alias_link *lnk)
{
LIBALIAS_LOCK(la);
(void)la;
DeleteLink(&lnk, 1);
LIBALIAS_UNLOCK(la);
}
void
LibAliasSetAddress(struct libalias *la, struct in_addr addr)
{
LIBALIAS_LOCK(la);
if (la->packetAliasMode & PKT_ALIAS_RESET_ON_ADDR_CHANGE
&& la->aliasAddress.s_addr != addr.s_addr)
CleanupAliasData(la, 0);
la->aliasAddress = addr;
LIBALIAS_UNLOCK(la);
}
void
LibAliasSetAliasPortRange(struct libalias *la, u_short port_low,
u_short port_high)
{
LIBALIAS_LOCK(la);
if (port_low) {
la->aliasPortLower = port_low;
/* Add 1 to the aliasPortLength as modulo has range of 1 to n-1 */
la->aliasPortLength = port_high - port_low + 1;
} else {
/* Set default values */
la->aliasPortLower = 0x8000;
la->aliasPortLength = 0x8000;
}
LIBALIAS_UNLOCK(la);
}
void
LibAliasSetTarget(struct libalias *la, struct in_addr target_addr)
{
LIBALIAS_LOCK(la);
la->targetAddress = target_addr;
LIBALIAS_UNLOCK(la);
}
static void
finishoff(void)
{
while (!LIST_EMPTY(&instancehead))
LibAliasUninit(LIST_FIRST(&instancehead));
}
struct libalias *
LibAliasInit(struct libalias *la)
{
if (la == NULL) {
#ifdef _KERNEL
#undef malloc /* XXX: ugly */
la = malloc(sizeof *la, M_ALIAS, M_WAITOK | M_ZERO);
#else
la = calloc(sizeof *la, 1);
if (la == NULL)
return (la);
#endif
#ifndef _KERNEL
/* kernel cleans up on module unload */
if (LIST_EMPTY(&instancehead))
atexit(finishoff);
#endif
LIST_INSERT_HEAD(&instancehead, la, instancelist);
#ifdef _KERNEL
LibAliasTime = time_uptime;
#else
LibAliasTime = time(NULL);
#endif
SPLAY_INIT(&la->linkSplayIn);
SPLAY_INIT(&la->linkSplayOut);
LIST_INIT(&la->pptpList);
TAILQ_INIT(&la->checkExpire);
#ifdef _KERNEL
AliasSctpInit(la);
#endif
LIBALIAS_LOCK_INIT(la);
LIBALIAS_LOCK(la);
} else {
LIBALIAS_LOCK(la);
CleanupAliasData(la, 1);
#ifdef _KERNEL
AliasSctpTerm(la);
AliasSctpInit(la);
#endif
}
la->aliasAddress.s_addr = INADDR_ANY;
la->targetAddress.s_addr = INADDR_ANY;
la->aliasPortLower = 0x8000;
la->aliasPortLength = 0x8000;
la->icmpLinkCount = 0;
la->udpLinkCount = 0;
la->tcpLinkCount = 0;
la->sctpLinkCount = 0;
la->pptpLinkCount = 0;
la->protoLinkCount = 0;
la->fragmentIdLinkCount = 0;
la->fragmentPtrLinkCount = 0;
la->sockCount = 0;
la->packetAliasMode = PKT_ALIAS_SAME_PORTS
#ifndef NO_USE_SOCKETS
| PKT_ALIAS_USE_SOCKETS
#endif
| PKT_ALIAS_RESET_ON_ADDR_CHANGE;
#ifndef NO_FW_PUNCH
la->fireWallFD = -1;
Summer of Code 2005: improve libalias - part 1 of 2 With the first part of my previous Summer of Code work, we get: -made libalias modular: -support for 'particular' protocols (like ftp/irc/etcetc) is no more hardcoded inside libalias, but it's available through external modules loadable at runtime -modules are available both in kernel (/boot/kernel/alias_*.ko) and user land (/lib/libalias_*) -protocols/applications modularized are: cuseeme, ftp, irc, nbt, pptp, skinny and smedia -added logging support for kernel side -cleanup After a buildworld, do a 'mergemaster -i' to install the file libalias.conf in /etc or manually copy it. During startup (and after every HUP signal) user land applications running the new libalias will try to read a file in /etc called libalias.conf: that file contains the list of modules to load. User land applications affected by this commit are ppp and natd: if libalias.conf is present in /etc you won't notice any difference. The only kernel land bit affected by this commit is ng_nat: if you are using ng_nat, and it doesn't correctly handle ftp/irc/etcetc sessions anymore, remember to kldload the correspondent module (i.e. kldload alias_ftp). General information and details about the inner working are available in the libalias man page under the section 'MODULAR ARCHITECTURE (AND ipfw(4) SUPPORT)'. NOTA BENE: this commit affects _ONLY_ libalias, ipfw in-kernel nat support will be part of the next libalias-related commit. Approved by: glebius Reviewed by: glebius, ru
2006-09-26 19:26:53 -04:00
#endif
#ifndef _KERNEL
LibAliasRefreshModules();
#endif
LIBALIAS_UNLOCK(la);
return (la);
}
void
LibAliasUninit(struct libalias *la)
{
LIBALIAS_LOCK(la);
#ifdef _KERNEL
AliasSctpTerm(la);
#endif
CleanupAliasData(la, 1);
UninitPacketAliasLog(la);
#ifndef NO_FW_PUNCH
UninitPunchFW(la);
#endif
LIST_REMOVE(la, instancelist);
LIBALIAS_UNLOCK(la);
LIBALIAS_LOCK_DESTROY(la);
free(la);
}
/* Change mode for some operations */
unsigned int
LibAliasSetMode(
struct libalias *la,
unsigned int flags, /* Which state to bring flags to */
unsigned int mask /* Mask of which flags to affect (use 0 to
* do a probe for flag values) */
)
{
int res = -1;
LIBALIAS_LOCK(la);
if (flags & mask & PKT_ALIAS_LOG) {
/* Enable logging */
Summer of Code 2005: improve libalias - part 1 of 2 With the first part of my previous Summer of Code work, we get: -made libalias modular: -support for 'particular' protocols (like ftp/irc/etcetc) is no more hardcoded inside libalias, but it's available through external modules loadable at runtime -modules are available both in kernel (/boot/kernel/alias_*.ko) and user land (/lib/libalias_*) -protocols/applications modularized are: cuseeme, ftp, irc, nbt, pptp, skinny and smedia -added logging support for kernel side -cleanup After a buildworld, do a 'mergemaster -i' to install the file libalias.conf in /etc or manually copy it. During startup (and after every HUP signal) user land applications running the new libalias will try to read a file in /etc called libalias.conf: that file contains the list of modules to load. User land applications affected by this commit are ppp and natd: if libalias.conf is present in /etc you won't notice any difference. The only kernel land bit affected by this commit is ng_nat: if you are using ng_nat, and it doesn't correctly handle ftp/irc/etcetc sessions anymore, remember to kldload the correspondent module (i.e. kldload alias_ftp). General information and details about the inner working are available in the libalias man page under the section 'MODULAR ARCHITECTURE (AND ipfw(4) SUPPORT)'. NOTA BENE: this commit affects _ONLY_ libalias, ipfw in-kernel nat support will be part of the next libalias-related commit. Approved by: glebius Reviewed by: glebius, ru
2006-09-26 19:26:53 -04:00
if (InitPacketAliasLog(la) == ENOMEM)
goto getout;
} else if (~flags & mask & PKT_ALIAS_LOG)
/* _Disable_ logging */
UninitPacketAliasLog(la);
#ifndef NO_FW_PUNCH
if (flags & mask & PKT_ALIAS_PUNCH_FW)
/* Start punching holes in the firewall? */
InitPunchFW(la);
else if (~flags & mask & PKT_ALIAS_PUNCH_FW)
/* Stop punching holes in the firewall? */
UninitPunchFW(la);
#endif
/* Other flags can be set/cleared without special action */
la->packetAliasMode = (flags & mask) | (la->packetAliasMode & ~mask);
res = la->packetAliasMode;
getout:
LIBALIAS_UNLOCK(la);
return (res);
}
#ifndef NO_FW_PUNCH
/*****************
Code to support firewall punching. This shouldn't really be in this
file, but making variables global is evil too.
****************/
/* Firewall include files */
#include <net/if.h>
#include <netinet/ip_fw.h>
#include <string.h>
#include <err.h>
The new ipfw code. This code makes use of variable-size kernel representation of rules (exactly the same concept of BPF instructions, as used in the BSDI's firewall), which makes firewall operation a lot faster, and the code more readable and easier to extend and debug. The interface with the rest of the system is unchanged, as witnessed by this commit. The only extra kernel files that I am touching are if_fw.h and ip_dummynet.c, which is quite tied to ipfw. In userland I only had to touch those programs which manipulate the internal representation of firewall rules). The code is almost entirely new (and I believe I have written the vast majority of those sections which were taken from the former ip_fw.c), so rather than modifying the old ip_fw.c I decided to create a new file, sys/netinet/ip_fw2.c . Same for the user interface, which is in sbin/ipfw/ipfw2.c (it still compiles to /sbin/ipfw). The old files are still there, and will be removed in due time. I have not renamed the header file because it would have required touching a one-line change to a number of kernel files. In terms of user interface, the new "ipfw" is supposed to accepts the old syntax for ipfw rules (and produce the same output with "ipfw show". Only a couple of the old options (out of some 30 of them) has not been implemented, but they will be soon. On the other hand, the new code has some very powerful extensions. First, you can put "or" connectives between match fields (and soon also between options), and write things like ipfw add allow ip from { 1.2.3.4/27 or 5.6.7.8/30 } 10-23,25,1024-3000 to any This should make rulesets slightly more compact (and lines longer!), by condensing 2 or more of the old rules into single ones. Also, as an example of how easy the rules can be extended, I have implemented an 'address set' match pattern, where you can specify an IP address in a format like this: 10.20.30.0/26{18,44,33,22,9} which will match the set of hosts listed in braces belonging to the subnet 10.20.30.0/26 . The match is done using a bitmap, so it is essentially a constant time operation requiring a handful of CPU instructions (and a very small amount of memmory -- for a full /24 subnet, the instruction only consumes 40 bytes). Again, in this commit I have focused on functionality and tried to minimize changes to the other parts of the system. Some performance improvement can be achieved with minor changes to the interface of ip_fw_chk_t. This will be done later when this code is settled. The code is meant to compile unmodified on RELENG_4 (once the PACKET_TAG_* changes have been merged), for this reason you will see #ifdef __FreeBSD_version in a couple of places. This should minimize errors when (hopefully soon) it will be time to do the MFC.
2002-06-27 19:02:18 -04:00
/*
* helper function, updates the pointer to cmd with the length
* of the current command, and also cleans up the first word of
* the new command in case it has been clobbered before.
*/
static ipfw_insn *
next_cmd(ipfw_insn * cmd)
The new ipfw code. This code makes use of variable-size kernel representation of rules (exactly the same concept of BPF instructions, as used in the BSDI's firewall), which makes firewall operation a lot faster, and the code more readable and easier to extend and debug. The interface with the rest of the system is unchanged, as witnessed by this commit. The only extra kernel files that I am touching are if_fw.h and ip_dummynet.c, which is quite tied to ipfw. In userland I only had to touch those programs which manipulate the internal representation of firewall rules). The code is almost entirely new (and I believe I have written the vast majority of those sections which were taken from the former ip_fw.c), so rather than modifying the old ip_fw.c I decided to create a new file, sys/netinet/ip_fw2.c . Same for the user interface, which is in sbin/ipfw/ipfw2.c (it still compiles to /sbin/ipfw). The old files are still there, and will be removed in due time. I have not renamed the header file because it would have required touching a one-line change to a number of kernel files. In terms of user interface, the new "ipfw" is supposed to accepts the old syntax for ipfw rules (and produce the same output with "ipfw show". Only a couple of the old options (out of some 30 of them) has not been implemented, but they will be soon. On the other hand, the new code has some very powerful extensions. First, you can put "or" connectives between match fields (and soon also between options), and write things like ipfw add allow ip from { 1.2.3.4/27 or 5.6.7.8/30 } 10-23,25,1024-3000 to any This should make rulesets slightly more compact (and lines longer!), by condensing 2 or more of the old rules into single ones. Also, as an example of how easy the rules can be extended, I have implemented an 'address set' match pattern, where you can specify an IP address in a format like this: 10.20.30.0/26{18,44,33,22,9} which will match the set of hosts listed in braces belonging to the subnet 10.20.30.0/26 . The match is done using a bitmap, so it is essentially a constant time operation requiring a handful of CPU instructions (and a very small amount of memmory -- for a full /24 subnet, the instruction only consumes 40 bytes). Again, in this commit I have focused on functionality and tried to minimize changes to the other parts of the system. Some performance improvement can be achieved with minor changes to the interface of ip_fw_chk_t. This will be done later when this code is settled. The code is meant to compile unmodified on RELENG_4 (once the PACKET_TAG_* changes have been merged), for this reason you will see #ifdef __FreeBSD_version in a couple of places. This should minimize errors when (hopefully soon) it will be time to do the MFC.
2002-06-27 19:02:18 -04:00
{
cmd += F_LEN(cmd);
bzero(cmd, sizeof(*cmd));
2004-07-05 06:55:23 -04:00
return (cmd);
The new ipfw code. This code makes use of variable-size kernel representation of rules (exactly the same concept of BPF instructions, as used in the BSDI's firewall), which makes firewall operation a lot faster, and the code more readable and easier to extend and debug. The interface with the rest of the system is unchanged, as witnessed by this commit. The only extra kernel files that I am touching are if_fw.h and ip_dummynet.c, which is quite tied to ipfw. In userland I only had to touch those programs which manipulate the internal representation of firewall rules). The code is almost entirely new (and I believe I have written the vast majority of those sections which were taken from the former ip_fw.c), so rather than modifying the old ip_fw.c I decided to create a new file, sys/netinet/ip_fw2.c . Same for the user interface, which is in sbin/ipfw/ipfw2.c (it still compiles to /sbin/ipfw). The old files are still there, and will be removed in due time. I have not renamed the header file because it would have required touching a one-line change to a number of kernel files. In terms of user interface, the new "ipfw" is supposed to accepts the old syntax for ipfw rules (and produce the same output with "ipfw show". Only a couple of the old options (out of some 30 of them) has not been implemented, but they will be soon. On the other hand, the new code has some very powerful extensions. First, you can put "or" connectives between match fields (and soon also between options), and write things like ipfw add allow ip from { 1.2.3.4/27 or 5.6.7.8/30 } 10-23,25,1024-3000 to any This should make rulesets slightly more compact (and lines longer!), by condensing 2 or more of the old rules into single ones. Also, as an example of how easy the rules can be extended, I have implemented an 'address set' match pattern, where you can specify an IP address in a format like this: 10.20.30.0/26{18,44,33,22,9} which will match the set of hosts listed in braces belonging to the subnet 10.20.30.0/26 . The match is done using a bitmap, so it is essentially a constant time operation requiring a handful of CPU instructions (and a very small amount of memmory -- for a full /24 subnet, the instruction only consumes 40 bytes). Again, in this commit I have focused on functionality and tried to minimize changes to the other parts of the system. Some performance improvement can be achieved with minor changes to the interface of ip_fw_chk_t. This will be done later when this code is settled. The code is meant to compile unmodified on RELENG_4 (once the PACKET_TAG_* changes have been merged), for this reason you will see #ifdef __FreeBSD_version in a couple of places. This should minimize errors when (hopefully soon) it will be time to do the MFC.
2002-06-27 19:02:18 -04:00
}
/*
* A function to fill simple commands of size 1.
* Existing flags are preserved.
*/
static ipfw_insn *
fill_cmd(ipfw_insn * cmd, enum ipfw_opcodes opcode, int size,
int flags, u_int16_t arg)
The new ipfw code. This code makes use of variable-size kernel representation of rules (exactly the same concept of BPF instructions, as used in the BSDI's firewall), which makes firewall operation a lot faster, and the code more readable and easier to extend and debug. The interface with the rest of the system is unchanged, as witnessed by this commit. The only extra kernel files that I am touching are if_fw.h and ip_dummynet.c, which is quite tied to ipfw. In userland I only had to touch those programs which manipulate the internal representation of firewall rules). The code is almost entirely new (and I believe I have written the vast majority of those sections which were taken from the former ip_fw.c), so rather than modifying the old ip_fw.c I decided to create a new file, sys/netinet/ip_fw2.c . Same for the user interface, which is in sbin/ipfw/ipfw2.c (it still compiles to /sbin/ipfw). The old files are still there, and will be removed in due time. I have not renamed the header file because it would have required touching a one-line change to a number of kernel files. In terms of user interface, the new "ipfw" is supposed to accepts the old syntax for ipfw rules (and produce the same output with "ipfw show". Only a couple of the old options (out of some 30 of them) has not been implemented, but they will be soon. On the other hand, the new code has some very powerful extensions. First, you can put "or" connectives between match fields (and soon also between options), and write things like ipfw add allow ip from { 1.2.3.4/27 or 5.6.7.8/30 } 10-23,25,1024-3000 to any This should make rulesets slightly more compact (and lines longer!), by condensing 2 or more of the old rules into single ones. Also, as an example of how easy the rules can be extended, I have implemented an 'address set' match pattern, where you can specify an IP address in a format like this: 10.20.30.0/26{18,44,33,22,9} which will match the set of hosts listed in braces belonging to the subnet 10.20.30.0/26 . The match is done using a bitmap, so it is essentially a constant time operation requiring a handful of CPU instructions (and a very small amount of memmory -- for a full /24 subnet, the instruction only consumes 40 bytes). Again, in this commit I have focused on functionality and tried to minimize changes to the other parts of the system. Some performance improvement can be achieved with minor changes to the interface of ip_fw_chk_t. This will be done later when this code is settled. The code is meant to compile unmodified on RELENG_4 (once the PACKET_TAG_* changes have been merged), for this reason you will see #ifdef __FreeBSD_version in a couple of places. This should minimize errors when (hopefully soon) it will be time to do the MFC.
2002-06-27 19:02:18 -04:00
{
cmd->opcode = opcode;
cmd->len = ((cmd->len | flags) & (F_NOT | F_OR)) | (size & F_LEN_MASK);
cmd->arg1 = arg;
return next_cmd(cmd);
}
static ipfw_insn *
fill_ip(ipfw_insn * cmd1, enum ipfw_opcodes opcode, u_int32_t addr)
{
ipfw_insn_ip *cmd = (ipfw_insn_ip *)cmd1;
cmd->addr.s_addr = addr;
return fill_cmd(cmd1, opcode, F_INSN_SIZE(ipfw_insn_u32), 0, 0);
The new ipfw code. This code makes use of variable-size kernel representation of rules (exactly the same concept of BPF instructions, as used in the BSDI's firewall), which makes firewall operation a lot faster, and the code more readable and easier to extend and debug. The interface with the rest of the system is unchanged, as witnessed by this commit. The only extra kernel files that I am touching are if_fw.h and ip_dummynet.c, which is quite tied to ipfw. In userland I only had to touch those programs which manipulate the internal representation of firewall rules). The code is almost entirely new (and I believe I have written the vast majority of those sections which were taken from the former ip_fw.c), so rather than modifying the old ip_fw.c I decided to create a new file, sys/netinet/ip_fw2.c . Same for the user interface, which is in sbin/ipfw/ipfw2.c (it still compiles to /sbin/ipfw). The old files are still there, and will be removed in due time. I have not renamed the header file because it would have required touching a one-line change to a number of kernel files. In terms of user interface, the new "ipfw" is supposed to accepts the old syntax for ipfw rules (and produce the same output with "ipfw show". Only a couple of the old options (out of some 30 of them) has not been implemented, but they will be soon. On the other hand, the new code has some very powerful extensions. First, you can put "or" connectives between match fields (and soon also between options), and write things like ipfw add allow ip from { 1.2.3.4/27 or 5.6.7.8/30 } 10-23,25,1024-3000 to any This should make rulesets slightly more compact (and lines longer!), by condensing 2 or more of the old rules into single ones. Also, as an example of how easy the rules can be extended, I have implemented an 'address set' match pattern, where you can specify an IP address in a format like this: 10.20.30.0/26{18,44,33,22,9} which will match the set of hosts listed in braces belonging to the subnet 10.20.30.0/26 . The match is done using a bitmap, so it is essentially a constant time operation requiring a handful of CPU instructions (and a very small amount of memmory -- for a full /24 subnet, the instruction only consumes 40 bytes). Again, in this commit I have focused on functionality and tried to minimize changes to the other parts of the system. Some performance improvement can be achieved with minor changes to the interface of ip_fw_chk_t. This will be done later when this code is settled. The code is meant to compile unmodified on RELENG_4 (once the PACKET_TAG_* changes have been merged), for this reason you will see #ifdef __FreeBSD_version in a couple of places. This should minimize errors when (hopefully soon) it will be time to do the MFC.
2002-06-27 19:02:18 -04:00
}
static ipfw_insn *
fill_one_port(ipfw_insn * cmd1, enum ipfw_opcodes opcode, u_int16_t port)
The new ipfw code. This code makes use of variable-size kernel representation of rules (exactly the same concept of BPF instructions, as used in the BSDI's firewall), which makes firewall operation a lot faster, and the code more readable and easier to extend and debug. The interface with the rest of the system is unchanged, as witnessed by this commit. The only extra kernel files that I am touching are if_fw.h and ip_dummynet.c, which is quite tied to ipfw. In userland I only had to touch those programs which manipulate the internal representation of firewall rules). The code is almost entirely new (and I believe I have written the vast majority of those sections which were taken from the former ip_fw.c), so rather than modifying the old ip_fw.c I decided to create a new file, sys/netinet/ip_fw2.c . Same for the user interface, which is in sbin/ipfw/ipfw2.c (it still compiles to /sbin/ipfw). The old files are still there, and will be removed in due time. I have not renamed the header file because it would have required touching a one-line change to a number of kernel files. In terms of user interface, the new "ipfw" is supposed to accepts the old syntax for ipfw rules (and produce the same output with "ipfw show". Only a couple of the old options (out of some 30 of them) has not been implemented, but they will be soon. On the other hand, the new code has some very powerful extensions. First, you can put "or" connectives between match fields (and soon also between options), and write things like ipfw add allow ip from { 1.2.3.4/27 or 5.6.7.8/30 } 10-23,25,1024-3000 to any This should make rulesets slightly more compact (and lines longer!), by condensing 2 or more of the old rules into single ones. Also, as an example of how easy the rules can be extended, I have implemented an 'address set' match pattern, where you can specify an IP address in a format like this: 10.20.30.0/26{18,44,33,22,9} which will match the set of hosts listed in braces belonging to the subnet 10.20.30.0/26 . The match is done using a bitmap, so it is essentially a constant time operation requiring a handful of CPU instructions (and a very small amount of memmory -- for a full /24 subnet, the instruction only consumes 40 bytes). Again, in this commit I have focused on functionality and tried to minimize changes to the other parts of the system. Some performance improvement can be achieved with minor changes to the interface of ip_fw_chk_t. This will be done later when this code is settled. The code is meant to compile unmodified on RELENG_4 (once the PACKET_TAG_* changes have been merged), for this reason you will see #ifdef __FreeBSD_version in a couple of places. This should minimize errors when (hopefully soon) it will be time to do the MFC.
2002-06-27 19:02:18 -04:00
{
ipfw_insn_u16 *cmd = (ipfw_insn_u16 *)cmd1;
cmd->ports[0] = cmd->ports[1] = port;
return fill_cmd(cmd1, opcode, F_INSN_SIZE(ipfw_insn_u16), 0, 0);
The new ipfw code. This code makes use of variable-size kernel representation of rules (exactly the same concept of BPF instructions, as used in the BSDI's firewall), which makes firewall operation a lot faster, and the code more readable and easier to extend and debug. The interface with the rest of the system is unchanged, as witnessed by this commit. The only extra kernel files that I am touching are if_fw.h and ip_dummynet.c, which is quite tied to ipfw. In userland I only had to touch those programs which manipulate the internal representation of firewall rules). The code is almost entirely new (and I believe I have written the vast majority of those sections which were taken from the former ip_fw.c), so rather than modifying the old ip_fw.c I decided to create a new file, sys/netinet/ip_fw2.c . Same for the user interface, which is in sbin/ipfw/ipfw2.c (it still compiles to /sbin/ipfw). The old files are still there, and will be removed in due time. I have not renamed the header file because it would have required touching a one-line change to a number of kernel files. In terms of user interface, the new "ipfw" is supposed to accepts the old syntax for ipfw rules (and produce the same output with "ipfw show". Only a couple of the old options (out of some 30 of them) has not been implemented, but they will be soon. On the other hand, the new code has some very powerful extensions. First, you can put "or" connectives between match fields (and soon also between options), and write things like ipfw add allow ip from { 1.2.3.4/27 or 5.6.7.8/30 } 10-23,25,1024-3000 to any This should make rulesets slightly more compact (and lines longer!), by condensing 2 or more of the old rules into single ones. Also, as an example of how easy the rules can be extended, I have implemented an 'address set' match pattern, where you can specify an IP address in a format like this: 10.20.30.0/26{18,44,33,22,9} which will match the set of hosts listed in braces belonging to the subnet 10.20.30.0/26 . The match is done using a bitmap, so it is essentially a constant time operation requiring a handful of CPU instructions (and a very small amount of memmory -- for a full /24 subnet, the instruction only consumes 40 bytes). Again, in this commit I have focused on functionality and tried to minimize changes to the other parts of the system. Some performance improvement can be achieved with minor changes to the interface of ip_fw_chk_t. This will be done later when this code is settled. The code is meant to compile unmodified on RELENG_4 (once the PACKET_TAG_* changes have been merged), for this reason you will see #ifdef __FreeBSD_version in a couple of places. This should minimize errors when (hopefully soon) it will be time to do the MFC.
2002-06-27 19:02:18 -04:00
}
static int
fill_rule(void *buf, int bufsize, int rulenum,
enum ipfw_opcodes action, int proto,
struct in_addr sa, u_int16_t sp, struct in_addr da, u_int16_t dp)
The new ipfw code. This code makes use of variable-size kernel representation of rules (exactly the same concept of BPF instructions, as used in the BSDI's firewall), which makes firewall operation a lot faster, and the code more readable and easier to extend and debug. The interface with the rest of the system is unchanged, as witnessed by this commit. The only extra kernel files that I am touching are if_fw.h and ip_dummynet.c, which is quite tied to ipfw. In userland I only had to touch those programs which manipulate the internal representation of firewall rules). The code is almost entirely new (and I believe I have written the vast majority of those sections which were taken from the former ip_fw.c), so rather than modifying the old ip_fw.c I decided to create a new file, sys/netinet/ip_fw2.c . Same for the user interface, which is in sbin/ipfw/ipfw2.c (it still compiles to /sbin/ipfw). The old files are still there, and will be removed in due time. I have not renamed the header file because it would have required touching a one-line change to a number of kernel files. In terms of user interface, the new "ipfw" is supposed to accepts the old syntax for ipfw rules (and produce the same output with "ipfw show". Only a couple of the old options (out of some 30 of them) has not been implemented, but they will be soon. On the other hand, the new code has some very powerful extensions. First, you can put "or" connectives between match fields (and soon also between options), and write things like ipfw add allow ip from { 1.2.3.4/27 or 5.6.7.8/30 } 10-23,25,1024-3000 to any This should make rulesets slightly more compact (and lines longer!), by condensing 2 or more of the old rules into single ones. Also, as an example of how easy the rules can be extended, I have implemented an 'address set' match pattern, where you can specify an IP address in a format like this: 10.20.30.0/26{18,44,33,22,9} which will match the set of hosts listed in braces belonging to the subnet 10.20.30.0/26 . The match is done using a bitmap, so it is essentially a constant time operation requiring a handful of CPU instructions (and a very small amount of memmory -- for a full /24 subnet, the instruction only consumes 40 bytes). Again, in this commit I have focused on functionality and tried to minimize changes to the other parts of the system. Some performance improvement can be achieved with minor changes to the interface of ip_fw_chk_t. This will be done later when this code is settled. The code is meant to compile unmodified on RELENG_4 (once the PACKET_TAG_* changes have been merged), for this reason you will see #ifdef __FreeBSD_version in a couple of places. This should minimize errors when (hopefully soon) it will be time to do the MFC.
2002-06-27 19:02:18 -04:00
{
struct ip_fw *rule = (struct ip_fw *)buf;
ipfw_insn *cmd = (ipfw_insn *)rule->cmd;
The new ipfw code. This code makes use of variable-size kernel representation of rules (exactly the same concept of BPF instructions, as used in the BSDI's firewall), which makes firewall operation a lot faster, and the code more readable and easier to extend and debug. The interface with the rest of the system is unchanged, as witnessed by this commit. The only extra kernel files that I am touching are if_fw.h and ip_dummynet.c, which is quite tied to ipfw. In userland I only had to touch those programs which manipulate the internal representation of firewall rules). The code is almost entirely new (and I believe I have written the vast majority of those sections which were taken from the former ip_fw.c), so rather than modifying the old ip_fw.c I decided to create a new file, sys/netinet/ip_fw2.c . Same for the user interface, which is in sbin/ipfw/ipfw2.c (it still compiles to /sbin/ipfw). The old files are still there, and will be removed in due time. I have not renamed the header file because it would have required touching a one-line change to a number of kernel files. In terms of user interface, the new "ipfw" is supposed to accepts the old syntax for ipfw rules (and produce the same output with "ipfw show". Only a couple of the old options (out of some 30 of them) has not been implemented, but they will be soon. On the other hand, the new code has some very powerful extensions. First, you can put "or" connectives between match fields (and soon also between options), and write things like ipfw add allow ip from { 1.2.3.4/27 or 5.6.7.8/30 } 10-23,25,1024-3000 to any This should make rulesets slightly more compact (and lines longer!), by condensing 2 or more of the old rules into single ones. Also, as an example of how easy the rules can be extended, I have implemented an 'address set' match pattern, where you can specify an IP address in a format like this: 10.20.30.0/26{18,44,33,22,9} which will match the set of hosts listed in braces belonging to the subnet 10.20.30.0/26 . The match is done using a bitmap, so it is essentially a constant time operation requiring a handful of CPU instructions (and a very small amount of memmory -- for a full /24 subnet, the instruction only consumes 40 bytes). Again, in this commit I have focused on functionality and tried to minimize changes to the other parts of the system. Some performance improvement can be achieved with minor changes to the interface of ip_fw_chk_t. This will be done later when this code is settled. The code is meant to compile unmodified on RELENG_4 (once the PACKET_TAG_* changes have been merged), for this reason you will see #ifdef __FreeBSD_version in a couple of places. This should minimize errors when (hopefully soon) it will be time to do the MFC.
2002-06-27 19:02:18 -04:00
bzero(buf, bufsize);
rule->rulenum = rulenum;
The new ipfw code. This code makes use of variable-size kernel representation of rules (exactly the same concept of BPF instructions, as used in the BSDI's firewall), which makes firewall operation a lot faster, and the code more readable and easier to extend and debug. The interface with the rest of the system is unchanged, as witnessed by this commit. The only extra kernel files that I am touching are if_fw.h and ip_dummynet.c, which is quite tied to ipfw. In userland I only had to touch those programs which manipulate the internal representation of firewall rules). The code is almost entirely new (and I believe I have written the vast majority of those sections which were taken from the former ip_fw.c), so rather than modifying the old ip_fw.c I decided to create a new file, sys/netinet/ip_fw2.c . Same for the user interface, which is in sbin/ipfw/ipfw2.c (it still compiles to /sbin/ipfw). The old files are still there, and will be removed in due time. I have not renamed the header file because it would have required touching a one-line change to a number of kernel files. In terms of user interface, the new "ipfw" is supposed to accepts the old syntax for ipfw rules (and produce the same output with "ipfw show". Only a couple of the old options (out of some 30 of them) has not been implemented, but they will be soon. On the other hand, the new code has some very powerful extensions. First, you can put "or" connectives between match fields (and soon also between options), and write things like ipfw add allow ip from { 1.2.3.4/27 or 5.6.7.8/30 } 10-23,25,1024-3000 to any This should make rulesets slightly more compact (and lines longer!), by condensing 2 or more of the old rules into single ones. Also, as an example of how easy the rules can be extended, I have implemented an 'address set' match pattern, where you can specify an IP address in a format like this: 10.20.30.0/26{18,44,33,22,9} which will match the set of hosts listed in braces belonging to the subnet 10.20.30.0/26 . The match is done using a bitmap, so it is essentially a constant time operation requiring a handful of CPU instructions (and a very small amount of memmory -- for a full /24 subnet, the instruction only consumes 40 bytes). Again, in this commit I have focused on functionality and tried to minimize changes to the other parts of the system. Some performance improvement can be achieved with minor changes to the interface of ip_fw_chk_t. This will be done later when this code is settled. The code is meant to compile unmodified on RELENG_4 (once the PACKET_TAG_* changes have been merged), for this reason you will see #ifdef __FreeBSD_version in a couple of places. This should minimize errors when (hopefully soon) it will be time to do the MFC.
2002-06-27 19:02:18 -04:00
cmd = fill_cmd(cmd, O_PROTO, F_INSN_SIZE(ipfw_insn), 0, proto);
cmd = fill_ip(cmd, O_IP_SRC, sa.s_addr);
cmd = fill_one_port(cmd, O_IP_SRCPORT, sp);
cmd = fill_ip(cmd, O_IP_DST, da.s_addr);
cmd = fill_one_port(cmd, O_IP_DSTPORT, dp);
The new ipfw code. This code makes use of variable-size kernel representation of rules (exactly the same concept of BPF instructions, as used in the BSDI's firewall), which makes firewall operation a lot faster, and the code more readable and easier to extend and debug. The interface with the rest of the system is unchanged, as witnessed by this commit. The only extra kernel files that I am touching are if_fw.h and ip_dummynet.c, which is quite tied to ipfw. In userland I only had to touch those programs which manipulate the internal representation of firewall rules). The code is almost entirely new (and I believe I have written the vast majority of those sections which were taken from the former ip_fw.c), so rather than modifying the old ip_fw.c I decided to create a new file, sys/netinet/ip_fw2.c . Same for the user interface, which is in sbin/ipfw/ipfw2.c (it still compiles to /sbin/ipfw). The old files are still there, and will be removed in due time. I have not renamed the header file because it would have required touching a one-line change to a number of kernel files. In terms of user interface, the new "ipfw" is supposed to accepts the old syntax for ipfw rules (and produce the same output with "ipfw show". Only a couple of the old options (out of some 30 of them) has not been implemented, but they will be soon. On the other hand, the new code has some very powerful extensions. First, you can put "or" connectives between match fields (and soon also between options), and write things like ipfw add allow ip from { 1.2.3.4/27 or 5.6.7.8/30 } 10-23,25,1024-3000 to any This should make rulesets slightly more compact (and lines longer!), by condensing 2 or more of the old rules into single ones. Also, as an example of how easy the rules can be extended, I have implemented an 'address set' match pattern, where you can specify an IP address in a format like this: 10.20.30.0/26{18,44,33,22,9} which will match the set of hosts listed in braces belonging to the subnet 10.20.30.0/26 . The match is done using a bitmap, so it is essentially a constant time operation requiring a handful of CPU instructions (and a very small amount of memmory -- for a full /24 subnet, the instruction only consumes 40 bytes). Again, in this commit I have focused on functionality and tried to minimize changes to the other parts of the system. Some performance improvement can be achieved with minor changes to the interface of ip_fw_chk_t. This will be done later when this code is settled. The code is meant to compile unmodified on RELENG_4 (once the PACKET_TAG_* changes have been merged), for this reason you will see #ifdef __FreeBSD_version in a couple of places. This should minimize errors when (hopefully soon) it will be time to do the MFC.
2002-06-27 19:02:18 -04:00
rule->act_ofs = (u_int32_t *)cmd - (u_int32_t *)rule->cmd;
cmd = fill_cmd(cmd, action, F_INSN_SIZE(ipfw_insn), 0, 0);
2002-07-01 07:19:40 -04:00
rule->cmd_len = (u_int32_t *)cmd - (u_int32_t *)rule->cmd;
The new ipfw code. This code makes use of variable-size kernel representation of rules (exactly the same concept of BPF instructions, as used in the BSDI's firewall), which makes firewall operation a lot faster, and the code more readable and easier to extend and debug. The interface with the rest of the system is unchanged, as witnessed by this commit. The only extra kernel files that I am touching are if_fw.h and ip_dummynet.c, which is quite tied to ipfw. In userland I only had to touch those programs which manipulate the internal representation of firewall rules). The code is almost entirely new (and I believe I have written the vast majority of those sections which were taken from the former ip_fw.c), so rather than modifying the old ip_fw.c I decided to create a new file, sys/netinet/ip_fw2.c . Same for the user interface, which is in sbin/ipfw/ipfw2.c (it still compiles to /sbin/ipfw). The old files are still there, and will be removed in due time. I have not renamed the header file because it would have required touching a one-line change to a number of kernel files. In terms of user interface, the new "ipfw" is supposed to accepts the old syntax for ipfw rules (and produce the same output with "ipfw show". Only a couple of the old options (out of some 30 of them) has not been implemented, but they will be soon. On the other hand, the new code has some very powerful extensions. First, you can put "or" connectives between match fields (and soon also between options), and write things like ipfw add allow ip from { 1.2.3.4/27 or 5.6.7.8/30 } 10-23,25,1024-3000 to any This should make rulesets slightly more compact (and lines longer!), by condensing 2 or more of the old rules into single ones. Also, as an example of how easy the rules can be extended, I have implemented an 'address set' match pattern, where you can specify an IP address in a format like this: 10.20.30.0/26{18,44,33,22,9} which will match the set of hosts listed in braces belonging to the subnet 10.20.30.0/26 . The match is done using a bitmap, so it is essentially a constant time operation requiring a handful of CPU instructions (and a very small amount of memmory -- for a full /24 subnet, the instruction only consumes 40 bytes). Again, in this commit I have focused on functionality and tried to minimize changes to the other parts of the system. Some performance improvement can be achieved with minor changes to the interface of ip_fw_chk_t. This will be done later when this code is settled. The code is meant to compile unmodified on RELENG_4 (once the PACKET_TAG_* changes have been merged), for this reason you will see #ifdef __FreeBSD_version in a couple of places. This should minimize errors when (hopefully soon) it will be time to do the MFC.
2002-06-27 19:02:18 -04:00
return ((char *)cmd - (char *)buf);
The new ipfw code. This code makes use of variable-size kernel representation of rules (exactly the same concept of BPF instructions, as used in the BSDI's firewall), which makes firewall operation a lot faster, and the code more readable and easier to extend and debug. The interface with the rest of the system is unchanged, as witnessed by this commit. The only extra kernel files that I am touching are if_fw.h and ip_dummynet.c, which is quite tied to ipfw. In userland I only had to touch those programs which manipulate the internal representation of firewall rules). The code is almost entirely new (and I believe I have written the vast majority of those sections which were taken from the former ip_fw.c), so rather than modifying the old ip_fw.c I decided to create a new file, sys/netinet/ip_fw2.c . Same for the user interface, which is in sbin/ipfw/ipfw2.c (it still compiles to /sbin/ipfw). The old files are still there, and will be removed in due time. I have not renamed the header file because it would have required touching a one-line change to a number of kernel files. In terms of user interface, the new "ipfw" is supposed to accepts the old syntax for ipfw rules (and produce the same output with "ipfw show". Only a couple of the old options (out of some 30 of them) has not been implemented, but they will be soon. On the other hand, the new code has some very powerful extensions. First, you can put "or" connectives between match fields (and soon also between options), and write things like ipfw add allow ip from { 1.2.3.4/27 or 5.6.7.8/30 } 10-23,25,1024-3000 to any This should make rulesets slightly more compact (and lines longer!), by condensing 2 or more of the old rules into single ones. Also, as an example of how easy the rules can be extended, I have implemented an 'address set' match pattern, where you can specify an IP address in a format like this: 10.20.30.0/26{18,44,33,22,9} which will match the set of hosts listed in braces belonging to the subnet 10.20.30.0/26 . The match is done using a bitmap, so it is essentially a constant time operation requiring a handful of CPU instructions (and a very small amount of memmory -- for a full /24 subnet, the instruction only consumes 40 bytes). Again, in this commit I have focused on functionality and tried to minimize changes to the other parts of the system. Some performance improvement can be achieved with minor changes to the interface of ip_fw_chk_t. This will be done later when this code is settled. The code is meant to compile unmodified on RELENG_4 (once the PACKET_TAG_* changes have been merged), for this reason you will see #ifdef __FreeBSD_version in a couple of places. This should minimize errors when (hopefully soon) it will be time to do the MFC.
2002-06-27 19:02:18 -04:00
}
static void
InitPunchFW(struct libalias *la)
{
la->fireWallField = malloc(la->fireWallNumNums);
if (la->fireWallField) {
memset(la->fireWallField, 0, la->fireWallNumNums);
if (la->fireWallFD < 0) {
la->fireWallFD = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
}
ClearAllFWHoles(la);
la->fireWallActiveNum = la->fireWallBaseNum;
}
}
static void
UninitPunchFW(struct libalias *la)
{
ClearAllFWHoles(la);
if (la->fireWallFD >= 0)
close(la->fireWallFD);
la->fireWallFD = -1;
if (la->fireWallField)
free(la->fireWallField);
la->fireWallField = NULL;
la->packetAliasMode &= ~PKT_ALIAS_PUNCH_FW;
}
/* Make a certain link go through the firewall */
void
PunchFWHole(struct alias_link *lnk)
{
struct libalias *la;
int r; /* Result code */
struct ip_fw rule; /* On-the-fly built rule */
int fwhole; /* Where to punch hole */
la = lnk->la;
/* Don't do anything unless we are asked to */
if (!(la->packetAliasMode & PKT_ALIAS_PUNCH_FW) ||
la->fireWallFD < 0 ||
lnk->link_type != LINK_TCP)
return;
memset(&rule, 0, sizeof rule);
/** Build rule **/
/* Find empty slot */
for (fwhole = la->fireWallActiveNum;
fwhole < la->fireWallBaseNum + la->fireWallNumNums &&
fw_tstfield(la, la->fireWallField, fwhole);
fwhole++);
if (fwhole == la->fireWallBaseNum + la->fireWallNumNums) {
for (fwhole = la->fireWallBaseNum;
fwhole < la->fireWallActiveNum &&
fw_tstfield(la, la->fireWallField, fwhole);
fwhole++);
if (fwhole == la->fireWallActiveNum) {
/* No rule point empty - we can't punch more holes. */
la->fireWallActiveNum = la->fireWallBaseNum;
#ifdef LIBALIAS_DEBUG
fprintf(stderr, "libalias: Unable to create firewall hole!\n");
#endif
return;
}
}
/* Start next search at next position */
la->fireWallActiveNum = fwhole + 1;
/*
* generate two rules of the form
2004-07-05 06:53:28 -04:00
*
* add fwhole accept tcp from OAddr OPort to DAddr DPort add fwhole
* accept tcp from DAddr DPort to OAddr OPort
*/
if (GetOriginalPort(lnk) != 0 && GetDestPort(lnk) != 0) {
u_int32_t rulebuf[255];
int i;
i = fill_rule(rulebuf, sizeof(rulebuf), fwhole,
O_ACCEPT, IPPROTO_TCP,
GetOriginalAddress(lnk), ntohs(GetOriginalPort(lnk)),
GetDestAddress(lnk), ntohs(GetDestPort(lnk)));
r = setsockopt(la->fireWallFD, IPPROTO_IP, IP_FW_ADD, rulebuf, i);
if (r)
err(1, "alias punch inbound(1) setsockopt(IP_FW_ADD)");
i = fill_rule(rulebuf, sizeof(rulebuf), fwhole,
O_ACCEPT, IPPROTO_TCP,
GetDestAddress(lnk), ntohs(GetDestPort(lnk)),
GetOriginalAddress(lnk), ntohs(GetOriginalPort(lnk)));
r = setsockopt(la->fireWallFD, IPPROTO_IP, IP_FW_ADD, rulebuf, i);
if (r)
err(1, "alias punch inbound(2) setsockopt(IP_FW_ADD)");
}
/* Indicate hole applied */
lnk->data.tcp->fwhole = fwhole;
fw_setfield(la, la->fireWallField, fwhole);
}
/* Remove a hole in a firewall associated with a particular alias
lnk. Calling this too often is harmless. */
static void
ClearFWHole(struct alias_link *lnk)
{
struct libalias *la;
la = lnk->la;
if (lnk->link_type == LINK_TCP) {
int fwhole = lnk->data.tcp->fwhole; /* Where is the firewall hole? */
struct ip_fw rule;
if (fwhole < 0)
return;
memset(&rule, 0, sizeof rule); /* useless for ipfw2 */
while (!setsockopt(la->fireWallFD, IPPROTO_IP, IP_FW_DEL,
&fwhole, sizeof fwhole));
fw_clrfield(la, la->fireWallField, fwhole);
lnk->data.tcp->fwhole = -1;
}
}
/* Clear out the entire range dedicated to firewall holes. */
static void
ClearAllFWHoles(struct libalias *la)
{
struct ip_fw rule; /* On-the-fly built rule */
int i;
2002-07-01 07:19:40 -04:00
if (la->fireWallFD < 0)
return;
memset(&rule, 0, sizeof rule);
for (i = la->fireWallBaseNum; i < la->fireWallBaseNum + la->fireWallNumNums; i++) {
int r = i;
while (!setsockopt(la->fireWallFD, IPPROTO_IP, IP_FW_DEL, &r, sizeof r));
}
/* XXX: third arg correct here ? /phk */
memset(la->fireWallField, 0, la->fireWallNumNums);
}
#endif /* !NO_FW_PUNCH */
void
LibAliasSetFWBase(struct libalias *la, unsigned int base, unsigned int num)
{
LIBALIAS_LOCK(la);
#ifndef NO_FW_PUNCH
la->fireWallBaseNum = base;
la->fireWallNumNums = num;
#endif
LIBALIAS_UNLOCK(la);
}
void
LibAliasSetSkinnyPort(struct libalias *la, unsigned int port)
{
LIBALIAS_LOCK(la);
la->skinnyPort = port;
LIBALIAS_UNLOCK(la);
}
/*
* Find the address to redirect incoming packets
*/
struct in_addr
FindSctpRedirectAddress(struct libalias *la, struct sctp_nat_msg *sm)
{
struct alias_link *lnk;
struct in_addr redir;
LIBALIAS_LOCK_ASSERT(la);
lnk = FindLinkIn(la, sm->ip_hdr->ip_src, sm->ip_hdr->ip_dst,
sm->sctp_hdr->dest_port,sm->sctp_hdr->dest_port, LINK_SCTP, 1);
if (lnk != NULL) {
/* port redirect */
return (lnk->src_addr);
} else {
redir = FindOriginalAddress(la,sm->ip_hdr->ip_dst);
if (redir.s_addr == la->aliasAddress.s_addr ||
redir.s_addr == la->targetAddress.s_addr) {
/* No address found */
lnk = FindLinkIn(la, sm->ip_hdr->ip_src, sm->ip_hdr->ip_dst,
NO_DEST_PORT, 0, LINK_SCTP, 1);
if (lnk != NULL)
/* redirect proto */
return (lnk->src_addr);
}
return (redir); /* address redirect */
}
}