#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
+#include <syslog.h>
#include <sys/queue.h>
#include <sys/socket.h>
#define GET_NEW_PORT_MAX_ATTEMPTS 20
#define GET_ALIAS_PORT -1
+#define GET_ALIAS_EPHEMERAL_PORT -2
#define GET_ALIAS_ID GET_ALIAS_PORT
#define FIND_EVEN_ALIAS_BASE 1
another link concurrently. This is because GetNewPort() looks for
unused triplets: (dest addr, dest port, alias port). */
+static int
+GetEphemeralPort(struct alias_link *link)
+{
+ int i;
+
+ /* Port number search */
+ for (i=0; i < GET_NEW_PORT_MAX_ATTEMPTS; i++)
+ {
+ struct sockaddr_in sock_addr;
+ socklen_t salen;
+ u_short port_net;
+ struct alias_link *search_result;
+
+ if (GetSocket(0, &link->sockfd, link->link_type) == 0)
+ return -1;
+ salen = sizeof(struct sockaddr_in);
+ if (getsockname(link->sockfd, (struct sockaddr *)&sock_addr, &salen) == -1)
+ return -1;
+ port_net = sock_addr.sin_port;
+
+ search_result = FindLinkIn(link->dst_addr, link->alias_addr,
+ link->dst_port, port_net,
+ link->link_type, 0);
+
+ if (search_result == NULL) {
+ link->alias_port = port_net;
+ return(0);
+ }
+ close(link->sockfd);
+ link->sockfd = -1;
+ }
+ #ifdef DEBUG
+ fprintf(stderr, "PacketAlias/GetEphemeralPort(): ");
+ fprintf(stderr, "could not find free port\n");
+ #endif
+
+ return(-1);
+}
+
static int
GetNewPort(struct alias_link *link, int alias_port_param)
{
u_short port_sys;
u_short port_net;
+ if (alias_port_param == GET_ALIAS_EPHEMERAL_PORT)
+ return GetEphemeralPort(link);
+
/*
Description of alias_port_param for GetNewPort(). When
this parameter is zero or positive, it precisely specifies
link_type = LINK_TCP;
break;
default:
- return NULL;
+ return 0;
break;
}
#ifdef DEBUG
{
- int icount;
+ int icount = 0;
- printf("PORTMAP::srcaddr = 0x%x.%d, dstaddr = 0x%x.%d link_type = %d, lifetime = %d\n",
- src_addr.s_addr, src_port, dst_addr.s_addr, pub_port, link_type, lifetime);
+ printf("FindAliasPortOut:: srcaddr= %s:%u, ",
+ inet_ntoa(src_addr), ntohs(src_port));
+ printf("dstadd= %s:%u link_type= %d, lifetime= %d\n",
+ inet_ntoa(dst_addr), ntohs(pub_port), link_type, lifetime);
for (i=0; i<LINK_TABLE_OUT_SIZE; i++)
{
while (link != NULL)
{
struct alias_link *link_next;
-
- printf("PORTMAP:: linksrcaddr = 0x%x.%d, linkdstaddr = 0x%x.%d, aliasaddr=0x%x.%d, linktype = %d\n",
- link->src_addr.s_addr,link->src_port,link->dst_addr.s_addr,link->dst_port, link->alias_addr.s_addr,link->alias_port,
- link->link_type);
-
+ char src_str[32], dst_str[32], alias_str[32];
+
+ snprintf(src_str, sizeof(src_str), "%s:%u",
+ inet_ntoa(link->src_addr), ntohs(link->src_port));
+ snprintf(dst_str, sizeof(dst_str), "%s:%u",
+ inet_ntoa(link->dst_addr), ntohs(link->dst_port));
+ snprintf(alias_str, sizeof(alias_str), "%s:%u",
+ inet_ntoa(link->alias_addr), ntohs(link->alias_port));
+
+ printf(" linkTableOut[%d:%d] src= %s dst= %s alias= %s flags= 0x%x linktype= %d ts= %d exp= %d fd= %d",
+ i, icount, src_str, dst_str, alias_str,
+ link->flags, link->link_type, link->timestamp, link->expire_time, link->sockfd);
+
link_next = LIST_NEXT(link, list_out);
icount++;
link = link_next;
{
struct in_addr alias_addr;
#ifdef DEBUG
- printf("PORTMAP:: cannot find mapping, adding mapping private port =%d, public port = %d\n",src_port, pub_port);
+ printf("PORTMAP:: cannot find mapping, adding mapping private port =%d, public port = %d\n",
+ src_port, pub_port);
#endif
/* address/port in not in list, create new mapping */
alias_addr = FindAliasAddress(src_addr);
/* create new mapping */
- if ( !pub_port )
- pub_port = GET_ALIAS_PORT;
link = AddLink(src_addr, dst_addr, alias_addr,
- src_port, 0, pub_port,
+ src_port, 0, GET_ALIAS_EPHEMERAL_PORT,
link_type);
- if ( link != NULL )
+ if ( link != NULL ) {
/* link was create, set new lifetime */
SetExpire(link, lifetime);
+ /* Prevent link deletion when incoming connection arrive */
+ link->flags |= LINK_CONE;
+ }
}
if ( link )
{
fireWallNumNums = num;
#endif
}
+
+void
+DumpInfo(void)
+{
+ int i, icount = 0;
+ struct alias_link *link;
+
+ for (i=0; i<LINK_TABLE_OUT_SIZE; i++)
+ {
+ link = LIST_FIRST(&linkTableOut[i]);
+ while (link != NULL)
+ {
+ struct alias_link *link_next;
+ char src_str[32], dst_str[32], alias_str[32];
+
+ snprintf(src_str, sizeof(src_str), "%s:%u",
+ inet_ntoa(link->src_addr), ntohs(link->src_port));
+ snprintf(dst_str, sizeof(dst_str), "%s:%u",
+ inet_ntoa(link->dst_addr), ntohs(link->dst_port));
+ snprintf(alias_str, sizeof(alias_str), "%s:%u",
+ inet_ntoa(link->alias_addr), ntohs(link->alias_port));
+
+ syslog(LOG_ERR, " linkTableOut[%d:%d] src= %s dst= %s alias= %s flags= 0x%x linktype= %d ts= %d exp= %d fd= %d",
+ i, icount, src_str, dst_str, alias_str,
+ link->flags, link->link_type, link->timestamp, link->expire_time, link->sockfd);
+
+ link_next = LIST_NEXT(link, list_out);
+ icount++;
+ link = link_next;
+ }
+ }
+
+}
static void InitiateShutdown (int);
static void Shutdown (int);
static void RefreshAddr (int);
+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 int dropIgnoredIncoming;
static int logDropped;
static int logFacility;
+static int dumpinfo;
#define NATPORTMAP 1
#define OUTOFRESOURCES 4
#define UNSUPPORTEDOPCODE 5
#define MAXRETRY 10
-#define TIMER_RATE 250
+#define TIMER_RATE 250000
#define FAILED -1
-typedef struct stdportmaprequest{
- char version;
- unsigned char opcode;
- unsigned short result;
- char data[4];
- }stdportmaprequest;
-
-typedef struct publicaddrreply{
- char version;
- unsigned char opcode;
- unsigned short result;
- unsigned int epoch;
- struct in_addr addr;
- }publicaddrreply;
-typedef struct publicportreq{
- char version;
- unsigned char opcode;
- unsigned short result;
- unsigned short privateport;
- unsigned short publicport;
- int lifetime; /* in second */
- }publicportreq;
-typedef struct publicportreply{
- char version;
- unsigned char opcode;
- unsigned short result;
- unsigned int epoch;
- unsigned short privateport;
- unsigned short publicport;
- int lifetime; /* in second */
- }publicportreply;
-typedef struct stderrreply{
- char version;
- unsigned char opcode;
- unsigned short result;
- unsigned int epoch;
- }stderrreply;
+typedef struct stdportmaprequest {
+ char version;
+ unsigned char opcode;
+ unsigned short result;
+ char data[4];
+} stdportmaprequest;
+
+typedef struct publicaddrreply {
+ char version;
+ unsigned char opcode;
+ unsigned short result;
+ unsigned int epoch;
+ struct in_addr addr;
+ } publicaddrreply;
+
+typedef struct publicportreq {
+ char version;
+ unsigned char opcode;
+ unsigned short result;
+ unsigned short privateport;
+ unsigned short publicport;
+ int lifetime; /* in second */
+} publicportreq;
+
+typedef struct publicportreply {
+ char version;
+ unsigned char opcode;
+ unsigned short result;
+ unsigned int epoch;
+ unsigned short privateport;
+ unsigned short publicport;
+ int lifetime; /* in second */
+} publicportreply;
+
+typedef struct stderrreply {
+ char version;
+ unsigned char opcode;
+ unsigned short result;
+ unsigned int epoch;
+} stderrreply;
static int enable_natportmap = 0;
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, int publicport);
+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();
siginterrupt(SIGHUP, 1);
signal (SIGTERM, InitiateShutdown);
signal (SIGHUP, RefreshAddr);
+ signal (SIGINFO, HandleInfo);
/*
* Set alias address if it has been given.
*/
NULL,
NULL) == -1) {
- if (errno == EINTR)
+ if (errno == EINTR) {
+ if (dumpinfo) {
+ DumpInfo();
+ dumpinfo = 0;
+ }
continue;
-
+ }
Quit ("Select failed.");
}
int bytes;
int origBytes;
int status;
- int addrSize;
- struct ip* ip;
+ socklen_t addrSize;
+ struct ip* ip;
if (assignAliasAddr) {
reply.opcode = SERVERREPLYOP + PUBLICADDRREQ;
reply.result = SUCCESS;
reply.addr = lastassignaliasAddr;
- reply.epoch = getuptime();
+ reply.epoch = getuptime();
bytes = sendto (fd, (void*)&reply, sizeof(reply), 0, (struct sockaddr*)clientaddr, clientaddrlen);
if ( bytes != sizeof(reply) )
/* 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, int publicport)
+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 ( publicport <= 0)
+ if (result)
/* error in port mapping */
reply.result = OUTOFRESOURCES;
else
reply.result = SUCCESS;
- reply.epoch = getuptime();
+
+ reply.epoch = getuptime();
+
+ reply.privateport = req->privateport;
- if ( req->lifetime ){ /* not delete mapping */
- 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) )
/* double the time value */
static void Doubletime( struct timeval *tvp)
{
-
- if ( tvp->tv_sec )
- tvp->tv_sec *= 2;
- if ( tvp->tv_usec )
- tvp->tv_usec *= 2;
- if (tvp->tv_usec >= 1000000) {
- tvp->tv_sec += tvp->tv_usec / 1000000;
- tvp->tv_usec = tvp->tv_usec % 1000000;
- }
+
+ timeradd(tvp, tvp, tvp);
+
}
/* stop running natd timer */
static void Stoptimer()
{
- itval.it_value.tv_usec = 0;
- if (setitimer(ITIMER_REAL, &itval, (struct itimerval *)NULL) < 0)
- printf( "setitimer err: %d\n", errno);
+ 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 */
if ( numoftries < MAXRETRY ){
Doubletime( &itval.it_value);
- itval.it_interval = 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);
}
itval.it_value.tv_sec = 0;
itval.it_value.tv_usec = TIMER_RATE;
itval.it_interval.tv_sec = 0;
- itval.it_interval.tv_usec = TIMER_RATE;
+ itval.it_interval.tv_usec = 0;
if (setitimer(ITIMER_REAL, &itval, (struct itimerval *)NULL) < 0)
printf( "setitimer err: %d\n", errno);
{
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, lastassignaliasAddr, req->privateport, req->publicport, proto, req->lifetime, 0))
+ if ( !FindAliasPortOut( clientaddr->sin_addr, inany , req->privateport, req->publicport, proto, req->lifetime, 0))
/* FindAliasPortOut returns no error, port successfully removed, return no error response to client */
- SendPublicPortResponse( fd, clientaddr, clientaddrlen, req, 1 );
+ SendPublicPortResponse( fd, clientaddr, clientaddrlen, req, 0, 0 );
else
/* deleting port fails, return error */
- SendPublicPortResponse( fd, clientaddr, clientaddrlen, req, -1 );
+ 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, lastassignaliasAddr, req->privateport, req->publicport, proto, req->lifetime, 1);
+ aliasport = FindAliasPortOut( clientaddr->sin_addr,
+ inany, /* lastassignaliasAddr */
+ req->privateport,
+ 0,
+ proto,
+ 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 );
+ SendPublicPortResponse( fd, clientaddr, clientaddrlen, req, aliasport, 0 );
}
}
/* handle all packets sent to NATPORTMAP port */
static void HandlePortMap( int fd )
{
-#define MAXBUFFERSIZE 100
-
- struct sockaddr_in clientaddr;
- int 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;
- }
- req = (struct stdportmaprequest*)buffer;
+ #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;
+ }
+ req = (struct stdportmaprequest*)buffer;
+
+ #ifdef DEBUG
+ {
+ int i;
-#ifdef DEBUG
+ printf("HandlePortMap from %s:%u length= %d: ", inet_ntoa(clientaddr.sin_addr), clientaddr.sin_port, bytes);
+ for ( i = 0; i<bytes; i++)
{
- int i;
-
- for ( i = 0; i<bytes; i++)
- {
- printf("%d", buffer[i]);
- }
- printf("\n");
+ printf("%02x", buffer[i]);
}
-#endif
- /* check client version */
- if ( req->version > NATPMVERSION )
- result = NOTSUPPORTEDVERSION;
- else if ( !enable_natportmap )
- /* natd wasn't launched with portmapping enabled */
- result = NOTAUTHORIZED;
-
- if ( result )
+ printf("\n");
+ }
+ #endif
+ /* 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:
{
- SendPortMapResponse( fd, &clientaddr, clientaddrlen, req->opcode, result );
- return;
+ SendPublicAddress(fd, &clientaddr, clientaddrlen);
+ break;
}
-
- switch ( req->opcode )
+
+ case MAPUDPREQ:
+ case MAPTCPREQ:
+ case MAPUDPTCPREQ:
{
- case PUBLICADDRREQ:
- {
- SendPublicAddress(fd, &clientaddr, clientaddrlen);
- break;
- }
-
- case MAPUDPREQ:
- case MAPTCPREQ:
- case MAPUDPTCPREQ:
- {
- DoPortMapping( fd, &clientaddr, clientaddrlen, (publicportreq*)req);
- break;
- }
-
-
- default:
- SendPortMapResponse( fd, &clientaddr, clientaddrlen, req->opcode, UNSUPPORTEDOPCODE );
+ DoPortMapping( fd, &clientaddr, clientaddrlen, (publicportreq*)req);
+ break;
}
-
+
+
+ default:
+ SendPortMapResponse( fd, &clientaddr, clientaddrlen, req->opcode, UNSUPPORTEDOPCODE );
+ }
+
}
running = 0;
}
+static void HandleInfo (int sig)
+{
+ dumpinfo++;
+}
+
/*
* Different options recognized by this program.
*/