+/*
+ * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * The contents of this file constitute Original Code as defined in and
+ * are subject to the Apple Public Source License Version 1.1 (the
+ * "License"). You may not use this file except in compliance with the
+ * License. Please obtain a copy of the License at
+ * http://www.apple.com/publicsource and read it before using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
/*
* natd - Network Address Translation Daemon for FreeBSD.
*
*
* Ari Suutari <suutari@iki.fi>
*
- * $Id: natd.c,v 1.1.1.1 2000/01/11 01:48:51 wsanchez Exp $
+ * Based upon:
+ * $FreeBSD: src/sbin/natd/natd.c,v 1.25.2.3 2000/07/11 20:00:57 ru Exp $
*/
#define SYSLOG_NAMES
#include <sys/types.h>
#include <sys/socket.h>
+#include <net/if.h>
+#include <ifaddrs.h>
+#include <sys/sysctl.h>
#include <sys/time.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <netinet/udp.h>
#include <netinet/ip_icmp.h>
-#include <sys/ioctl.h>
#include <net/if.h>
+#include <net/if_dl.h>
#include <net/route.h>
#include <arpa/inet.h>
#include <alias.h>
+void DumpInfo(void);
+
#include <ctype.h>
#include <err.h>
#include <errno.h>
#include <string.h>
#include <syslog.h>
#include <unistd.h>
+#include <fcntl.h>
+#include <mach/mach_time.h>
+#include <mach/clock_types.h>
#include "natd.h"
* NOTES: - Port values are not stored in network byte order.
*/
-typedef u_long port_range;
+typedef uint32_t port_range;
#define GETLOPORT(x) ((x) >> 0x10)
#define GETNUMPORTS(x) ((x) & 0x0000ffff)
static char* FormatPacket (struct ip*);
static void PrintPacket (struct ip*);
static void SyslogPacket (struct ip*, int priority, const char *label);
-static void SetAliasAddressFromIfName (char* ifName);
+static void SetAliasAddressFromIfName (const char *ifName);
static void InitiateShutdown (int);
static void Shutdown (int);
static void RefreshAddr (int);
-static void ParseOption (const char* option, const char* parms, int cmdLine);
+static void HandleInfo (int);
+static void ParseOption (const char* option, const char* parms);
static void ReadConfigFile (const char* fileName);
static void SetupPortRedirect (const char* parms);
+static void SetupProtoRedirect(const char* parms);
static void SetupAddressRedirect (const char* parms);
-static void SetupPptpAlias (const char* parms);
static void StrToAddr (const char* str, struct in_addr* addr);
static u_short StrToPort (const char* str, const char* proto);
static int StrToPortRange (const char* str, const char* proto, port_range *portRange);
static int StrToAddrAndPortRange (const char* str, struct in_addr* addr, char* proto, port_range *portRange);
static void ParseArgs (int argc, char** argv);
static void FlushPacketBuffer (int fd);
+static void DiscardIncomingPackets (int fd);
+static void SetupPunchFW(const char *strValue);
/*
* Globals.
static u_short inOutPort;
static struct in_addr aliasAddr;
static int dynamicMode;
+static int clampMSS;
static int ifMTU;
static int aliasOverhead;
static int icmpSock;
static int dropIgnoredIncoming;
static int logDropped;
static int logFacility;
+static int dumpinfo;
+
+#define NATPORTMAP 1
+
+#ifdef NATPORTMAP
+
+/*
+ * Note: more details on NAT-PMP can be found at :
+ * <http://files.dns-sd.org/draft-cheshire-nat-pmp.txt>
+ */
+
+#define NATPMP_ANNOUNCEMENT_PORT 5350
+#define NATPMP_PORT 5351
+
+#define NATPMVERSION 0
+#define PUBLICADDRREQ 0
+#define MAPUDPREQ 1
+#define MAPTCPREQ 2
+#define MAPUDPTCPREQ 3
+#define SERVERREPLYOP 128
+
+#define SUCCESS 0
+#define NOTSUPPORTEDVERSION 1
+#define NOTAUTHORIZED 2
+#define NETWORKFAILURE 3
+#define OUTOFRESOURCES 4
+#define UNSUPPORTEDOPCODE 5
+
+#define MAXRETRY 10
+#define TIMER_RATE 250000
+
+#define FAILED -1
+
+typedef struct stdportmaprequest {
+ uint8_t version;
+ uint8_t opcode;
+} stdportmaprequest;
+
+typedef struct publicportreq {
+ uint8_t version;
+ uint8_t opcode;
+ uint16_t reserved;
+ uint16_t privateport;
+ uint16_t publicport;
+ uint32_t lifetime; /* in seconds */
+} publicportreq;
+
+typedef struct publicaddrreply {
+ uint8_t version;
+ uint8_t opcode;
+ uint16_t result;
+ uint32_t epoch;
+ struct in_addr addr;
+} publicaddrreply;
+
+typedef struct publicportreply {
+ uint8_t version;
+ uint8_t opcode;
+ uint16_t result;
+ uint32_t epoch;
+ uint16_t privateport;
+ uint16_t publicport;
+ uint32_t lifetime; /* in seconds */
+} publicportreply;
+
+typedef struct stderrreply {
+ uint8_t version;
+ uint8_t opcode;
+ uint16_t result;
+ uint32_t epoch;
+} stderrreply;
+
+
+static int enable_natportmap = 0;
+static struct in_addr lastassignaliasAddr;
+static int portmapSock = -1;
+static struct in_addr *forwardedinterfaceaddr;
+static char **forwardedinterfacename;
+static int numofinterfaces = 0; /* has to be at least one */
+static int numoftries=MAXRETRY;
+static struct itimerval itval;
+static int Natdtimerset = 0;
+static double secdivisor;
+
+
+static void HandlePortMap( int fd );
+static void SendPortMapResponse( int fd, struct sockaddr_in *clientaddr, int clientaddrlen, unsigned char origopcode, unsigned short result);
+static void SendPublicAddress( int fd, struct sockaddr_in *clientaddr, int clientaddrlen );
+static void SendPublicPortResponse( int fd, struct sockaddr_in *clientaddr, int clientaddrlen, publicportreq *reply, u_short publicport, int result);
+static void Doubletime( struct timeval *tvp);
+static void Stoptimer();
+static void Natdtimer();
+static void SendPortMapMulti( );
+static void NotifyPublicAddress();
+static void DoPortMapping( int fd, struct sockaddr_in *clientaddr, int clientaddrlen, publicportreq *req);
+static void NatPortMapPInit();
+
+extern int FindAliasPortOut(struct in_addr src_addr, struct in_addr dst_addr, u_short src_port, u_short pub_port, u_char proto, int lifetime, char addmapping);
+
+#endif /* NATPORTMAP */
int main (int argc, char** argv)
{
fd_set readMask;
fd_set writeMask;
int fdMax;
+ int fdFlags;
/*
* Initialize packet aliasing software.
* Done already here to be able to alter option bits
running = 1;
assignAliasAddr = 0;
aliasAddr.s_addr = INADDR_NONE;
+#ifdef NATPORTMAP
+ lastassignaliasAddr.s_addr = INADDR_NONE;
+#endif
aliasOverhead = 12;
dynamicMode = 0;
logDropped = 0;
/*
* Open syslog channel.
*/
- openlog ("natd", LOG_CONS | LOG_PID, logFacility);
+ openlog ("natd", LOG_CONS | LOG_PID | (verbose ? LOG_PERROR : 0),
+ logFacility);
/*
* Check that valid aliasing address has been given.
*/
if (aliasAddr.s_addr == INADDR_NONE && ifName == NULL)
errx (1, "aliasing address not given");
- if (aliasAddr.s_addr != INADDR_NONE && ifName != NULL)
- errx (1, "both alias address and interface "
- "name are not allowed");
/*
* Check that valid port number is known.
*/
errx (1, "both input and output ports are required");
if (inPort == 0 && outPort == 0 && inOutPort == 0)
- ParseOption ("port", DEFAULT_SERVICE, 0);
+ ParseOption ("port", DEFAULT_SERVICE);
/*
* Check if ignored packets should be dropped.
Quit ("Unable to bind outgoing divert socket.");
}
/*
- * Create routing socket if interface name specified.
+ * Create routing socket if interface name specified and in dynamic mode.
*/
- if (ifName && dynamicMode) {
+ routeSock = -1;
+ if (ifName) {
+ if (dynamicMode) {
- routeSock = socket (PF_ROUTE, SOCK_RAW, 0);
- if (routeSock == -1)
- Quit ("Unable to create routing info socket.");
+ routeSock = socket (PF_ROUTE, SOCK_RAW, 0);
+ if (routeSock == -1)
+ Quit ("Unable to create routing info socket.");
+
+ assignAliasAddr = 1;
+ }
+ else{
+ SetAliasAddressFromIfName (ifName);
+ }
}
- else
- routeSock = -1;
/*
* Create socket for sending ICMP messages.
*/
if (icmpSock == -1)
Quit ("Unable to create ICMP socket.");
-/*
- * And disable reads for the socket, otherwise it slowly fills
- * up with received icmps which we do not use.
- */
- shutdown(icmpSock, SHUT_RD);
+ if ((fdFlags = fcntl(icmpSock, F_GETFL, 0)) == -1)
+ Quit ("fcntl F_GETFL ICMP socket.");
+ fdFlags |= O_NONBLOCK;
+ if (fcntl(icmpSock, F_SETFL, fdFlags) == -1)
+ Quit ("fcntl F_SETFL ICMP socket.");
+
+#if NATPORTMAP
+ if ( enable_natportmap )
+ {
+ /* create socket to listen for port mapping */
+ portmapSock = socket( AF_INET, SOCK_DGRAM, 0);
+ if ( portmapSock != -1 )
+ {
+ addr.sin_family = AF_INET;
+ addr.sin_addr.s_addr = INADDR_ANY;
+ addr.sin_port = htons(NATPMP_PORT);
+
+ if (bind ( portmapSock,
+ (struct sockaddr*) &addr,
+ sizeof addr) == -1)
+ printf("Binding to NATPM port failed!\n");
+
+ /* NATPORTMAPP initial set up */
+ NatPortMapPInit();
+ }
+ if ( !Natdtimerset ){
+ Natdtimerset = 1;
+ signal(SIGALRM, Natdtimer);
+ }
+ }
+#endif /* NATPORTMAP */
/*
* Become a daemon unless verbose mode was requested.
* Catch signals to manage shutdown and
* refresh of interface address.
*/
+ siginterrupt(SIGTERM, 1);
+ siginterrupt(SIGHUP, 1);
signal (SIGTERM, InitiateShutdown);
signal (SIGHUP, RefreshAddr);
+ signal (SIGINFO, HandleInfo);
/*
* Set alias address if it has been given.
*/
if (aliasAddr.s_addr != INADDR_NONE)
+ {
PacketAliasSetAddress (aliasAddr);
+#ifdef NATPORTMAP
+ if ( (enable_natportmap) && (aliasAddr.s_addr != lastassignaliasAddr.s_addr) ){
+ lastassignaliasAddr.s_addr = aliasAddr.s_addr;
+ NotifyPublicAddress();
+ }
+#endif
+ }
/*
* We need largest descriptor number for select.
*/
if (routeSock > fdMax)
fdMax = routeSock;
+ if (icmpSock > fdMax)
+ fdMax = icmpSock;
+
+#ifdef NATPORTMAP
+ if ( portmapSock > fdMax )
+ fdMax = portmapSock;
+
+#endif
+
while (running) {
if (divertInOut != -1 && !ifName && packetSock == -1) {
if (divertInOut != -1)
FD_SET (divertInOut, &readMask);
+
+ if (icmpSock != -1)
+ FD_SET(icmpSock, &readMask);
}
/*
* Routing info is processed always.
*/
if (routeSock != -1)
FD_SET (routeSock, &readMask);
-
+#ifdef NATPORTMAP
+ if ( portmapSock != -1 )
+ FD_SET (portmapSock, &readMask);
+#endif
if (select (fdMax + 1,
&readMask,
&writeMask,
NULL,
NULL) == -1) {
- if (errno == EINTR)
+ if (errno == EINTR) {
+ if (dumpinfo) {
+ DumpInfo();
+ dumpinfo = 0;
+ }
continue;
-
+ }
Quit ("Select failed.");
}
if (routeSock != -1)
if (FD_ISSET (routeSock, &readMask))
HandleRoutingInfo (routeSock);
+
+ if (icmpSock != -1)
+ if (FD_ISSET (icmpSock, &readMask))
+ DiscardIncomingPackets (icmpSock);
+
+#ifdef NATPORTMAP
+ if ( portmapSock != -1)
+ if (FD_ISSET (portmapSock, &readMask))
+ HandlePortMap( portmapSock );
+#endif
}
if (background)
fprintf (pidFile, "%d\n", getpid ());
fclose (pidFile);
}
+
+#ifdef DEBUG
+#include <fcntl.h>
+ {
+ int fd;
+
+ fd = open("/var/run/natd.log", O_WRONLY|O_CREAT|O_TRUNC, 0644);
+ if (fd >= 0) {
+ if (fd != STDOUT_FILENO) {
+ dup2(fd, STDOUT_FILENO);
+ close(fd);
+ }
+ dup2(STDOUT_FILENO, STDERR_FILENO);
+ }
+ }
+#endif
}
static void ParseArgs (int argc, char** argv)
{
int arg;
- char* parm;
char* opt;
char parmBuf[256];
+ int len; /* bounds checking */
for (arg = 1; arg < argc; arg++) {
Usage ();
}
- parm = NULL;
parmBuf[0] = '\0';
+ len = 0;
while (arg < argc - 1) {
if (argv[arg + 1][0] == '-')
break;
- if (parm)
- strcat (parmBuf, " ");
+ if (len) {
+ strncat (parmBuf, " ", sizeof(parmBuf) - (len + 1));
+ len += strlen(parmBuf + len);
+ }
++arg;
- parm = parmBuf;
- strcat (parmBuf, argv[arg]);
+ strncat (parmBuf, argv[arg], sizeof(parmBuf) - (len + 1));
+ len += strlen(parmBuf + len);
+
}
- ParseOption (opt + 1, parm, 1);
+ ParseOption (opt + 1, (len ? parmBuf : NULL));
+
}
}
int bytes;
int origBytes;
int status;
- int addrSize;
- struct ip* ip;
+ socklen_t addrSize;
+ struct ip* ip;
if (assignAliasAddr) {
* This is a IP packet.
*/
ip = (struct ip*) packetBuf;
- if (direction == DONT_KNOW)
+ if (direction == DONT_KNOW) {
if (packetAddr.sin_addr.s_addr == INADDR_ANY)
direction = OUTPUT;
else
direction = INPUT;
+ }
if (verbose) {
-
/*
* Print packet direction and protocol type.
*/
}
if (verbose)
- printf ("Routing message %X received.\n", ifMsg.ifm_type);
+ printf ("Routing message %#x received.\n", ifMsg.ifm_type);
+
+ if ((ifMsg.ifm_type == RTM_NEWADDR || ifMsg.ifm_type == RTM_IFINFO) &&
+ ifMsg.ifm_index == ifIndex) {
+ if (verbose)
+ printf("Interface address/MTU has probably changed.\n");
+ assignAliasAddr = 1;
+ }
+}
+
+static void DiscardIncomingPackets (int fd)
+{
+ struct sockaddr_in sin;
+ char buffer[80];
+ socklen_t slen = sizeof(sin);
+
+ while (recvfrom(fd, buffer, sizeof(buffer), 0, (struct sockaddr *)&sin, &slen) != -1) {
+ ;
+ }
+}
+
+#ifdef NATPORTMAP
+
+void getdivisor()
+{
+ struct mach_timebase_info info;
+
+ (void) mach_timebase_info (&info);
+
+ secdivisor = ( (double)info.denom / (double)info.numer) * 1000;
+
+}
+
+uint32_t getuptime()
+{
+ uint64_t now;
+ uint32_t epochtime;
+
+ now = mach_absolute_time();
+ epochtime = (now / secdivisor) / USEC_PER_SEC;
+ return ( epochtime );
+
+}
+
+/* set up neccessary info for doing NatPortMapP */
+static void NatPortMapPInit()
+{
+ int i;
+ struct ifaddrs *ifap, *ifa;
+
+ forwardedinterfaceaddr = (struct in_addr *)
+ malloc(numofinterfaces * sizeof(*forwardedinterfaceaddr));
+ bzero(forwardedinterfaceaddr,
+ numofinterfaces * sizeof(*forwardedinterfaceaddr));
+ /* interface address hasn't been set up, get interface address */
+
+ if (getifaddrs(&ifap) == -1)
+ Quit ("getifaddrs failed.");
+
+ for ( ifa= ifap; ifa; ifa=ifa->ifa_next)
+ {
+ struct sockaddr_in * a;
+ if (ifa->ifa_addr->sa_family != AF_INET)
+ {
+ continue;
+ }
+ a = (struct sockaddr_in *)ifa->ifa_addr;
+ for ( i = 0; i < numofinterfaces; i++ )
+ {
+ if (strcmp(ifa->ifa_name, forwardedinterfacename[i]))
+ {
+ continue;
+ }
+ if (forwardedinterfaceaddr[i].s_addr == 0)
+ {
+ /* copy the first IP address */
+ forwardedinterfaceaddr[i] = a->sin_addr;
+ }
+ break;
+ }
+ }
+ freeifaddrs( ifap );
+ getdivisor();
+}
+
+/* SendPortMapResponse */
+/* send generic reponses to NATPORTMAP requests */
+static void SendPortMapResponse( int fd, struct sockaddr_in *clientaddr, int clientaddrlen, unsigned char origopcode, unsigned short result)
+{
+ stderrreply reply;
+ int bytes;
+
+ reply.version = NATPMVERSION;
+ reply.opcode = origopcode + SERVERREPLYOP;
+ reply.result = htons(result);
+ reply.epoch = htonl(getuptime());
+ bytes = sendto( fd, (void*)&reply, sizeof(reply), 0, (struct sockaddr*)clientaddr, clientaddrlen );
+ if ( bytes != sizeof(reply) )
+ printf( "PORTMAP::problem sending portmap reply - opcode %d\n", reply.opcode );
+}
+
+/* SendPublicAddress */
+/* return public address to requestor */
+static void SendPublicAddress( int fd, struct sockaddr_in *clientaddr, int clientaddrlen )
+{
+
+ publicaddrreply reply;
+ int bytes;
+
+ reply.version = NATPMVERSION;
+ reply.opcode = SERVERREPLYOP + PUBLICADDRREQ;
+ reply.result = SUCCESS;
+ reply.addr = lastassignaliasAddr;
+ reply.epoch = htonl(getuptime());
+
+ bytes = sendto (fd, (void*)&reply, sizeof(reply), 0, (struct sockaddr*)clientaddr, clientaddrlen);
+ if ( bytes != sizeof(reply) )
+ printf( "PORTMAP::problem sending portmap reply - opcode %d\n", reply.opcode );
+}
+
+/* SendPublicPortResponse */
+/* response for portmap request and portmap removal request */
+/* publicport <= 0 means error */
+static void SendPublicPortResponse( int fd, struct sockaddr_in *clientaddr, int clientaddrlen, publicportreq *req, u_short publicport, int result)
+{
+
+ int bytes;
+ publicportreply reply;
+
+ bzero(&reply, sizeof(publicportreply));
+ reply.version = NATPMVERSION;
+ reply.opcode = SERVERREPLYOP + req->opcode;
+ if (result)
+ /* error in port mapping */
+ reply.result = htons(OUTOFRESOURCES);
+ else
+ reply.result = SUCCESS;
+
+ reply.epoch = htonl(getuptime());
+
+ reply.privateport = req->privateport;
+
+ /* adding or renewing a mapping */
+ if ( req->lifetime ) {
+ reply.publicport = publicport;
+ reply.lifetime = req->lifetime;
+ }
+ bytes = sendto (fd, (void*)&reply, sizeof(publicportreply), 0, (struct sockaddr*)clientaddr, clientaddrlen);
+ if ( bytes != sizeof(publicportreply) )
+ printf( "PORTMAP::problem sending portmap reply - opcode %d\n", req->opcode );
+}
+
+/* SendPortMapMulti */
+/* send multicast to local network for new alias address */
+static void SendPortMapMulti()
+{
+
+ publicaddrreply reply;
+ int bytes;
+ struct sockaddr_in multiaddr;
+ int multisock;
+ int i;
+
+#define LOCALGROUP "224.0.0.1"
+ numoftries++;
+ memset(&multiaddr,0,sizeof(struct sockaddr_in));
+ multiaddr.sin_family=AF_INET;
+ multiaddr.sin_addr.s_addr=inet_addr(LOCALGROUP);
+ multiaddr.sin_port=htons(NATPMP_ANNOUNCEMENT_PORT);
+ reply.version = NATPMVERSION;
+ reply.opcode = SERVERREPLYOP + PUBLICADDRREQ;
+ reply.result = SUCCESS;
+ reply.addr = lastassignaliasAddr;
+ reply.epoch = 0;
+
+ /* send multicast to all forwarded interfaces */
+ for ( i = 0; i < numofinterfaces; i++)
+ {
+ if (forwardedinterfaceaddr[i].s_addr == 0)
+ {
+ continue;
+ }
+ multisock = socket( AF_INET, SOCK_DGRAM, 0);
+
+ if ( multisock == -1 )
+ {
+ printf("cannot get socket for sending multicast\n");
+ return;
+ }
+ if (setsockopt(multisock, IPPROTO_IP, IP_MULTICAST_IF, &forwardedinterfaceaddr[i], sizeof(struct in_addr)) < 0)
+ {
+ printf("setsockopt failed\n");
+ close(multisock);
+ continue;
+ }
+ bytes = sendto (multisock, (void*)&reply, sizeof(reply), 0, (struct sockaddr*)&multiaddr, sizeof(multiaddr));
+ if ( bytes != sizeof(reply) )
+ printf( "PORTMAP::problem sending multicast alias address - opcode %d\n", reply.opcode );
+ close(multisock);
+ }
+
+}
+
+/* double the time value */
+static void Doubletime( struct timeval *tvp)
+{
+
+ timeradd(tvp, tvp, tvp);
+
+}
- if (ifMsg.ifm_type != RTM_NEWADDR)
+/* stop running natd timer */
+static void Stoptimer()
+{
+ itval.it_value.tv_sec = 0;
+ itval.it_value.tv_usec = 0;
+ if (setitimer(ITIMER_REAL, &itval, (struct itimerval *)NULL) < 0)
+ printf( "setitimer err: %d\n", errno);
+}
+
+/* natdtimer */
+/* timer routine to send new public IP address */
+static void Natdtimer()
+{
+ if ( !enable_natportmap )
+ return;
+
+ SendPortMapMulti();
+
+ if ( numoftries < MAXRETRY ){
+ Doubletime( &itval.it_value);
+ itval.it_interval.tv_sec = 0;
+ itval.it_interval.tv_usec = 0;
+ if (setitimer(ITIMER_REAL, &itval, (struct itimerval *)NULL) < 0)
+ printf( "setitimer err: %d\n", errno);
+ }
+ else
+ {
+ Stoptimer();
return;
+ }
+
+}
- if (verbose && ifMsg.ifm_index == ifIndex)
- printf ("Interface address has changed.\n");
+/* NotifyPublicAddress */
+/* Advertise new public address */
+static void NotifyPublicAddress()
+{
+ if ( numoftries < MAXRETRY)
+ {
+ /* there is an old timer running, cancel it */
+ Stoptimer();
+ }
+ /* send up new timer */
+ numoftries = 0;
+ SendPortMapMulti();
+ itval.it_value.tv_sec = 0;
+ itval.it_value.tv_usec = TIMER_RATE;
+ itval.it_interval.tv_sec = 0;
+ itval.it_interval.tv_usec = 0;
+ if (setitimer(ITIMER_REAL, &itval, (struct itimerval *)NULL) < 0)
+ printf( "setitimer err: %d\n", errno);
- if (ifMsg.ifm_index == ifIndex)
- assignAliasAddr = 1;
}
+/* DoPortMapping */
+/* find/add/remove port mapping from alias manager */
+void DoPortMapping( int fd, struct sockaddr_in *clientaddr, int clientaddrlen, publicportreq *req)
+{
+ u_char proto = IPPROTO_TCP;
+ int aliasport;
+ struct in_addr inany = { INADDR_ANY };
+
+ if ( req->opcode == MAPUDPREQ)
+ proto = IPPROTO_UDP;
+ if ( req->lifetime == 0)
+ {
+ /* remove port mapping */
+ if ( !FindAliasPortOut( clientaddr->sin_addr,
+ inany,
+ req->privateport,
+ req->publicport,
+ proto,
+ ntohl(req->lifetime),
+ 0) )
+ /* FindAliasPortOut returns no error, port successfully removed, return no error response to client */
+ SendPublicPortResponse( fd, clientaddr, clientaddrlen, req, 0, 0 );
+ else
+ /* deleting port fails, return error */
+ SendPublicPortResponse( fd, clientaddr, clientaddrlen, req, 0, -1 );
+ }
+ else
+ {
+ /* look for port mapping - public port is ignored in this case */
+ /* create port mapping - map provided public port to private port if public port is not 0 */
+ aliasport = FindAliasPortOut( clientaddr->sin_addr,
+ inany, /* lastassignaliasAddr */
+ req->privateport,
+ 0,
+ proto,
+ ntohl(req->lifetime),
+ 1);
+ /* aliasport should be non zero if mapping is successfully, else -1 is returned, alias port shouldn't be zero???? */
+ SendPublicPortResponse( fd, clientaddr, clientaddrlen, req, aliasport, 0 );
+
+ }
+}
+
+/* HandlePortMap */
+/* handle all packets sent to NATPORTMAP port */
+static void HandlePortMap( int fd )
+{
+ #define MAXBUFFERSIZE 100
+
+ struct sockaddr_in clientaddr;
+ socklen_t clientaddrlen;
+ unsigned char buffer[MAXBUFFERSIZE];
+ int bytes;
+ unsigned short result = SUCCESS;
+ struct stdportmaprequest *req;
+
+ clientaddrlen = sizeof( clientaddr );
+ bytes = recvfrom( fd, buffer, sizeof(buffer), 0, (struct sockaddr*)&clientaddr, &clientaddrlen);
+ if ( bytes == -1 )
+ {
+ printf( "Read NATPM port error\n");
+ return;
+ }
+ else if ( bytes < sizeof(stdportmaprequest) )
+ {
+ /* drop any requests that are too short */
+ return;
+ }
+
+ req = (struct stdportmaprequest*)buffer;
+
+ #ifdef DEBUG
+ {
+ int i;
+
+ printf("HandlePortMap from %s:%u length= %d: ", inet_ntoa(clientaddr.sin_addr), clientaddr.sin_port, bytes);
+ for ( i = 0; i<bytes; i++)
+ {
+ printf("%02x", buffer[i]);
+ }
+ printf("\n");
+ }
+ #endif
+
+ /* drop any reply packets that we receive on the floor */
+ if ( req->opcode >= SERVERREPLYOP )
+ {
+ return;
+ }
+
+ /* check client version */
+ if ( req->version > NATPMVERSION )
+ result = NOTSUPPORTEDVERSION;
+ else if ( !enable_natportmap )
+ /* natd wasn't launched with portmapping enabled */
+ result = NOTAUTHORIZED;
+
+ if ( result )
+ {
+ SendPortMapResponse( fd, &clientaddr, clientaddrlen, req->opcode, result );
+ return;
+ }
+
+ switch ( req->opcode )
+ {
+ case PUBLICADDRREQ:
+ {
+ if ( bytes == sizeof(stdportmaprequest) )
+ SendPublicAddress(fd, &clientaddr, clientaddrlen);
+ break;
+ }
+
+ case MAPUDPREQ:
+ case MAPTCPREQ:
+ case MAPUDPTCPREQ:
+ {
+ if ( bytes == sizeof(publicportreq) )
+ DoPortMapping( fd, &clientaddr, clientaddrlen, (publicportreq*)req);
+ break;
+ }
+
+
+ default:
+ SendPortMapResponse( fd, &clientaddr, clientaddrlen, req->opcode, UNSUPPORTEDOPCODE );
+ }
+
+}
+
+#endif /* NATPORTMAP */
+
static void PrintPacket (struct ip* ip)
{
printf ("%s", FormatPacket (ip));
return buf;
}
-static void SetAliasAddressFromIfName (char* ifn)
+static void
+SetAliasAddressFromIfName(const char *ifn)
{
- struct ifconf cf;
- struct ifreq buf[32];
- char msg[80];
- struct ifreq* ifPtr;
- int extra;
- int helperSock;
- int bytes;
- struct sockaddr_in* addr;
- int found;
- struct ifreq req;
- char last[10];
-/*
- * Create a dummy socket to access interface information.
- */
- helperSock = socket (AF_INET, SOCK_DGRAM, 0);
- if (helperSock == -1) {
-
- Quit ("Failed to create helper socket.");
- exit (1);
- }
-
- cf.ifc_len = sizeof (buf);
- cf.ifc_req = buf;
+ size_t needed;
+ int mib[6];
+ char *buf, *lim, *next;
+ struct if_msghdr *ifm;
+ struct ifa_msghdr *ifam;
+ struct sockaddr_dl *sdl;
+ struct sockaddr_in *sin;
+
+ mib[0] = CTL_NET;
+ mib[1] = PF_ROUTE;
+ mib[2] = 0;
+ mib[3] = AF_INET; /* Only IP addresses please */
+ mib[4] = NET_RT_IFLIST;
+ mib[5] = 0; /* ifIndex??? */
/*
* Get interface data.
*/
- if (ioctl (helperSock, SIOCGIFCONF, &cf) == -1) {
-
- Quit ("Ioctl SIOCGIFCONF failed.");
- exit (1);
- }
-
- ifIndex = 0;
- ifPtr = buf;
- bytes = cf.ifc_len;
- found = 0;
- last[0] = '\0';
+ if (sysctl(mib, 6, NULL, &needed, NULL, 0) == -1)
+ err(1, "iflist-sysctl-estimate");
+ if ((buf = malloc(needed)) == NULL)
+ errx(1, "malloc failed");
+ if (sysctl(mib, 6, buf, &needed, NULL, 0) == -1)
+ err(1, "iflist-sysctl-get");
+ lim = buf + needed;
/*
* Loop through interfaces until one with
* given name is found. This is done to
* find correct interface index for routing
* message processing.
*/
- while (bytes) {
-
- if (ifPtr->ifr_addr.sa_family == AF_INET &&
- !strcmp (ifPtr->ifr_name, ifn)) {
-
- found = 1;
- break;
+ ifIndex = 0;
+ next = buf;
+ while (next < lim) {
+ ifm = (struct if_msghdr *)next;
+ next += ifm->ifm_msglen;
+ if (ifm->ifm_version != RTM_VERSION) {
+ if (verbose)
+ warnx("routing message version %d "
+ "not understood", ifm->ifm_version);
+ continue;
}
-
- if (strcmp (last, ifPtr->ifr_name)) {
-
- strcpy (last, ifPtr->ifr_name);
- ++ifIndex;
+ if (ifm->ifm_type == RTM_IFINFO) {
+ sdl = (struct sockaddr_dl *)(ifm + 1);
+ if (strlen(ifn) == sdl->sdl_nlen &&
+ strncmp(ifn, sdl->sdl_data, sdl->sdl_nlen) == 0) {
+ ifIndex = ifm->ifm_index;
+ ifMTU = ifm->ifm_data.ifi_mtu;
+ if (clampMSS)
+ PacketAliasClampMSS(ifMTU - sizeof(struct tcphdr) - sizeof(struct ip));
+ break;
+ }
}
-
- extra = ifPtr->ifr_addr.sa_len - sizeof (struct sockaddr);
-
- ifPtr++;
- ifPtr = (struct ifreq*) ((char*) ifPtr + extra);
- bytes -= sizeof (struct ifreq) + extra;
}
-
- if (!found) {
-
- close (helperSock);
- sprintf (msg, "Unknown interface name %s.\n", ifn);
- Quit (msg);
- }
-/*
- * Get MTU size.
- */
- strcpy (req.ifr_name, ifn);
-
- if (ioctl (helperSock, SIOCGIFMTU, &req) == -1)
- Quit ("Cannot get interface mtu size.");
-
- ifMTU = req.ifr_mtu;
+ if (!ifIndex)
+ errx(1, "unknown interface name %s", ifn);
/*
* Get interface address.
*/
- if (ioctl (helperSock, SIOCGIFADDR, &req) == -1)
- Quit ("Cannot get interface address.");
-
- addr = (struct sockaddr_in*) &req.ifr_addr;
- PacketAliasSetAddress (addr->sin_addr);
- syslog (LOG_INFO, "Aliasing to %s, mtu %d bytes",
- inet_ntoa (addr->sin_addr),
- ifMTU);
+ if (aliasAddr.s_addr == INADDR_NONE) {
+ sin = NULL;
+ while (next < lim) {
+ ifam = (struct ifa_msghdr *)next;
+ next += ifam->ifam_msglen;
+ if (ifam->ifam_version != RTM_VERSION) {
+ if (verbose)
+ warnx("routing message version %d "
+ "not understood", ifam->ifam_version);
+ continue;
+ }
+ if (ifam->ifam_type != RTM_NEWADDR)
+ break;
+ if (ifam->ifam_addrs & RTA_IFA) {
+ int i;
+ char *cp = (char *)(ifam + 1);
+
+#define ROUNDUP(a) \
+ ((a) > 0 ? (1 + (((a) - 1) | (sizeof(uint32_t) - 1))) : sizeof(uint32_t))
+#define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
+
+ for (i = 1; i < RTA_IFA; i <<= 1)
+ if (ifam->ifam_addrs & i)
+ ADVANCE(cp, (struct sockaddr *)cp);
+ if (((struct sockaddr *)cp)->sa_family == AF_INET) {
+ sin = (struct sockaddr_in *)cp;
+ break;
+ }
+ }
+ }
+ if (sin == NULL)
+ errx(1, "%s: cannot get interface address", ifn);
+
+ PacketAliasSetAddress(sin->sin_addr);
+#ifdef NATPORTMAP
+ if ( (enable_natportmap) && (sin->sin_addr.s_addr != lastassignaliasAddr.s_addr) )
+ {
+ lastassignaliasAddr.s_addr = sin->sin_addr.s_addr;
+ /* make sure the timer handler was set before setting timer */
+ if ( !Natdtimerset ){
+ Natdtimerset = 1;
+ signal(SIGALRM, Natdtimer);
+ }
+ NotifyPublicAddress();
+ }
+#endif
+ syslog(LOG_INFO, "Aliasing to %s, mtu %d bytes",
+ inet_ntoa(sin->sin_addr), ifMTU);
+ }
- close (helperSock);
+ free(buf);
}
void Quit (const char* msg)
if (background)
syslog (LOG_ALERT, "%s (%m)", msg);
else
- warn (msg);
+ warn ("%s", msg);
}
static void RefreshAddr (int sig)
{
- signal (SIGHUP, RefreshAddr);
if (ifName)
assignAliasAddr = 1;
}
* shutdown existing connections when system
* is shut down.
*/
+ siginterrupt(SIGALRM, 1);
signal (SIGALRM, Shutdown);
alarm (10);
}
running = 0;
}
+static void HandleInfo (int sig)
+{
+ dumpinfo++;
+}
+
/*
* Different options recognized by this program.
*/
OutPort,
Port,
AliasAddress,
+ TargetAddress,
InterfaceName,
RedirectPort,
+ RedirectProto,
RedirectAddress,
ConfigFile,
DynamicMode,
- PptpAlias,
+ ClampMSS,
ProxyRule,
LogDenied,
- LogFacility
+ LogFacility,
+ PunchFW,
+#ifdef NATPORTMAP
+ NATPortMap,
+ ToInterfaceName
+#endif
};
enum Param {
"dynamic",
NULL },
+ { ClampMSS,
+ 0,
+ YesNo,
+ "[yes|no]",
+ "enable TCP MSS clamping",
+ "clamp_mss",
+ NULL },
+
{ InPort,
0,
Service,
"alias_address",
"a" },
+ { TargetAddress,
+ 0,
+ Address,
+ "x.x.x.x",
+ "address to use for incoming sessions",
+ "target_address",
+ "t" },
+
{ InterfaceName,
0,
String,
{ RedirectPort,
0,
String,
- "tcp|udp local_addr:local_port_range [public_addr:]public_port_range"
+ "tcp|udp local_addr:local_port_range[,...] [public_addr:]public_port_range"
" [remote_addr[:remote_port_range]]",
"redirect a port (or ports) for incoming traffic",
"redirect_port",
NULL },
- { RedirectAddress,
+ { RedirectProto,
0,
String,
- "local_addr public_addr",
- "define mapping between local and public addresses",
- "redirect_address",
+ "proto local_addr [public_addr] [remote_addr]",
+ "redirect packets of a given proto",
+ "redirect_proto",
NULL },
- { PptpAlias,
+ { RedirectAddress,
0,
String,
- "src",
- "define inside machine for PPTP traffic",
- "pptpalias",
+ "local_addr[,...] public_addr",
+ "define mapping between local and public addresses",
+ "redirect_address",
NULL },
{ ConfigFile,
"facility",
"name of syslog facility to use for logging",
"log_facility",
- NULL }
+ NULL },
+ { PunchFW,
+ 0,
+ String,
+ "basenumber:count",
+ "punch holes in the firewall for incoming FTP/IRC DCC connections",
+ "punch_fw",
+ NULL },
+
+#ifdef NATPORTMAP
+ { NATPortMap,
+ 0,
+ YesNo,
+ "[yes|no]",
+ "enable NATPortMap protocol",
+ "enable_natportmap",
+ NULL },
+
+ { ToInterfaceName,
+ 0,
+ String,
+ "network_if_name",
+ "take aliasing address to interface",
+ "natportmap_interface",
+ NULL },
+
+#endif
};
-static void ParseOption (const char* option, const char* parms, int cmdLine)
+static void ParseOption (const char* option, const char* parms)
{
int i;
struct OptionInfo* info;
dynamicMode = yesNoValue;
break;
+ case ClampMSS:
+ clampMSS = yesNoValue;
+ break;
+
case InPort:
inPort = uNumValue;
break;
memcpy (&aliasAddr, &addrValue, sizeof (struct in_addr));
break;
+ case TargetAddress:
+ PacketAliasSetTarget(addrValue);
+ break;
+
case RedirectPort:
SetupPortRedirect (strValue);
break;
- case RedirectAddress:
- SetupAddressRedirect (strValue);
+ case RedirectProto:
+ SetupProtoRedirect(strValue);
break;
- case PptpAlias:
- SetupPptpAlias (strValue);
+ case RedirectAddress:
+ SetupAddressRedirect (strValue);
break;
case ProxyRule:
free (ifName);
ifName = strdup (strValue);
- assignAliasAddr = 1;
break;
case ConfigFile:
errx(1, "Unknown log facility name: %s", strValue);
break;
+
+ case PunchFW:
+ SetupPunchFW(strValue);
+ break;
+
+#ifdef NATPORTMAP
+ case NATPortMap:
+ enable_natportmap = yesNoValue;
+ break;
+
+
+ case ToInterfaceName:
+ {
+ if (forwardedinterfacename != NULL)
+ {
+ if ( (forwardedinterfacename = realloc( forwardedinterfacename, (numofinterfaces+1) * sizeof(*forwardedinterfacename ))) == NULL ){
+ printf("realloc error, cannot allocate memory for fowarded interface name.\n");
+ return;
+ }
+ }
+ else {
+ if ( (forwardedinterfacename = malloc( sizeof(*forwardedinterfacename) )) == NULL ){
+ printf("malloc error, cannot allocate memory for fowarded interface name.\n");
+ return;
+ }
+ }
+
+ forwardedinterfacename[numofinterfaces] = strdup(strValue);
+ numofinterfaces++;
+
+ break;
+ }
+
+#endif
+
}
}
void ReadConfigFile (const char* fileName)
{
FILE* file;
- char buf[128];
- char* ptr;
+ char *buf;
+ size_t len;
+ char *ptr, *p;
char* option;
file = fopen (fileName, "r");
- if (!file) {
-
- sprintf (buf, "Cannot open config file %s.\n", fileName);
- Quit (buf);
- }
-
- while (fgets (buf, sizeof (buf), file)) {
+ if (!file)
+ err(1, "cannot open config file %s", fileName);
- ptr = strchr (buf, '\n');
- if (!ptr)
- errx (1, "config line too long: %s", buf);
-
- *ptr = '\0';
- if (buf[0] == '#')
- continue;
+ while ((buf = fgetln(file, &len)) != NULL) {
+ if (buf[len - 1] == '\n')
+ buf[len - 1] = '\0';
+ else
+ errx(1, "config file format error: "
+ "last line should end with newline");
- ptr = buf;
/*
- * Skip white space at beginning of line.
+ * Check for comments, strip off trailing spaces.
*/
- while (*ptr && isspace (*ptr))
- ++ptr;
-
+ if ((ptr = strchr(buf, '#')))
+ *ptr = '\0';
+ for (ptr = buf; isspace(*ptr); ++ptr)
+ continue;
if (*ptr == '\0')
continue;
+ for (p = strchr(buf, '\0'); isspace(*--p);)
+ continue;
+ *++p = '\0';
+
/*
* Extract option name.
*/
while (*ptr && isspace (*ptr))
++ptr;
- ParseOption (option, *ptr ? ptr : NULL, 0);
+ ParseOption (option, *ptr ? ptr : NULL);
}
fclose (file);
exit (1);
}
-void SetupPptpAlias (const char* parms)
-{
- char buf[128];
- char* ptr;
- struct in_addr srcAddr;
-
- strcpy (buf, parms);
-
-/*
- * Extract source address.
- */
- ptr = strtok (buf, " \t");
- if (!ptr)
- errx(1, "pptpalias: missing src address");
-
- StrToAddr (ptr, &srcAddr);
- PacketAliasPptp (srcAddr);
-}
-
void SetupPortRedirect (const char* parms)
{
char buf[128];
char* ptr;
+ char* serverPool;
struct in_addr localAddr;
struct in_addr publicAddr;
struct in_addr remoteAddr;
char* protoName;
char* separator;
int i;
+ struct alias_link *link = NULL;
strcpy (buf, parms);
/*
if (!ptr)
errx (1, "redirect_port: missing local address");
- if ( StrToAddrAndPortRange (ptr, &localAddr, protoName, &portRange) != 0 )
- errx (1, "redirect_port: invalid local port range");
-
- localPort = GETLOPORT(portRange);
- numLocalPorts = GETNUMPORTS(portRange);
+ separator = strchr(ptr, ',');
+ if (separator) { /* LSNAT redirection syntax. */
+ localAddr.s_addr = INADDR_NONE;
+ localPort = ~0;
+ numLocalPorts = 1;
+ serverPool = ptr;
+ } else {
+ if ( StrToAddrAndPortRange (ptr, &localAddr, protoName, &portRange) != 0 )
+ errx (1, "redirect_port: invalid local port range");
+
+ localPort = GETLOPORT(portRange);
+ numLocalPorts = GETNUMPORTS(portRange);
+ serverPool = NULL;
+ }
/*
- * Extract public port and optinally address.
+ * Extract public port and optionally address.
*/
ptr = strtok (NULL, " \t");
if (!ptr)
ptr = strtok (NULL, " \t");
if (ptr) {
separator = strchr (ptr, ':');
- if (separator)
+ if (separator) {
if (StrToAddrAndPortRange (ptr, &remoteAddr, protoName, &portRange) != 0)
errx (1, "redirect_port: invalid remote port range");
- else {
+ } else {
SETLOPORT(portRange, 0);
SETNUMPORTS(portRange, 1);
StrToAddr (ptr, &remoteAddr);
errx (1, "redirect_port: port ranges must be equal in size");
/* Remote port range is allowed to be '0' which means all ports. */
- if (numRemotePorts != numLocalPorts && numRemotePorts != 1 && remotePort != 0)
+ if (numRemotePorts != numLocalPorts && (numRemotePorts != 1 || remotePort != 0))
errx (1, "redirect_port: remote port must be 0 or equal to local port range in size");
for (i = 0 ; i < numPublicPorts ; ++i) {
if (numRemotePorts == 1 && remotePort == 0)
remotePortCopy = 0;
- PacketAliasRedirectPort (localAddr,
- htons(localPort + i),
- remoteAddr,
- htons(remotePortCopy),
- publicAddr,
- htons(publicPort + i),
- proto);
+ link = PacketAliasRedirectPort (localAddr,
+ htons(localPort + i),
+ remoteAddr,
+ htons(remotePortCopy),
+ publicAddr,
+ htons(publicPort + i),
+ proto);
+ }
+
+/*
+ * Setup LSNAT server pool.
+ */
+ if (serverPool != NULL && link != NULL) {
+ ptr = strtok(serverPool, ",");
+ while (ptr != NULL) {
+ if (StrToAddrAndPortRange(ptr, &localAddr, protoName, &portRange) != 0)
+ errx(1, "redirect_port: invalid local port range");
+
+ localPort = GETLOPORT(portRange);
+ if (GETNUMPORTS(portRange) != 1)
+ errx(1, "redirect_port: local port must be single in this context");
+ PacketAliasAddServer(link, localAddr, htons(localPort));
+ ptr = strtok(NULL, ",");
+ }
}
}
+void
+SetupProtoRedirect(const char* parms)
+{
+ char buf[128];
+ char* ptr;
+ struct in_addr localAddr;
+ struct in_addr publicAddr;
+ struct in_addr remoteAddr;
+ int proto;
+ char* protoName;
+ struct protoent *protoent;
+
+ strcpy (buf, parms);
+/*
+ * Extract protocol.
+ */
+ protoName = strtok(buf, " \t");
+ if (!protoName)
+ errx(1, "redirect_proto: missing protocol");
+
+ protoent = getprotobyname(protoName);
+ if (protoent == NULL)
+ errx(1, "redirect_proto: unknown protocol %s", protoName);
+ else
+ proto = protoent->p_proto;
+/*
+ * Extract local address.
+ */
+ ptr = strtok(NULL, " \t");
+ if (!ptr)
+ errx(1, "redirect_proto: missing local address");
+ else
+ StrToAddr(ptr, &localAddr);
+/*
+ * Extract optional public address.
+ */
+ ptr = strtok(NULL, " \t");
+ if (ptr)
+ StrToAddr(ptr, &publicAddr);
+ else
+ publicAddr.s_addr = INADDR_ANY;
+/*
+ * Extract optional remote address.
+ */
+ ptr = strtok(NULL, " \t");
+ if (ptr)
+ StrToAddr(ptr, &remoteAddr);
+ else
+ remoteAddr.s_addr = INADDR_ANY;
+/*
+ * Create aliasing link.
+ */
+ (void)PacketAliasRedirectProto(localAddr, remoteAddr, publicAddr,
+ proto);
+}
+
void SetupAddressRedirect (const char* parms)
{
char buf[128];
char* ptr;
+ char* separator;
struct in_addr localAddr;
struct in_addr publicAddr;
+ char* serverPool;
+ struct alias_link *link;
strcpy (buf, parms);
/*
if (!ptr)
errx (1, "redirect_address: missing local address");
- StrToAddr (ptr, &localAddr);
+ separator = strchr(ptr, ',');
+ if (separator) { /* LSNAT redirection syntax. */
+ localAddr.s_addr = INADDR_NONE;
+ serverPool = ptr;
+ } else {
+ StrToAddr (ptr, &localAddr);
+ serverPool = NULL;
+ }
/*
* Extract public address.
*/
errx (1, "redirect_address: missing public address");
StrToAddr (ptr, &publicAddr);
- PacketAliasRedirectAddr (localAddr, publicAddr);
+ link = PacketAliasRedirectAddr(localAddr, publicAddr);
+
+/*
+ * Setup LSNAT server pool.
+ */
+ if (serverPool != NULL && link != NULL) {
+ ptr = strtok(serverPool, ",");
+ while (ptr != NULL) {
+ StrToAddr(ptr, &localAddr);
+ PacketAliasAddServer(link, localAddr, htons(~0));
+ ptr = strtok(NULL, ",");
+ }
+ }
}
void StrToAddr (const char* str, struct in_addr* addr)
StrToAddr (str, addr);
return StrToPortRange (ptr, proto, portRange);
}
+
+static void
+SetupPunchFW(const char *strValue)
+{
+ unsigned int base, num;
+
+ if (sscanf(strValue, "%u:%u", &base, &num) != 2)
+ errx(1, "punch_fw: basenumber:count parameter required");
+
+ PacketAliasSetFWBase(base, num);
+ (void)PacketAliasSetMode(PKT_ALIAS_PUNCH_FW, PKT_ALIAS_PUNCH_FW);
+}