/****************************************************************************
**
** File: dynports.c
**
** Author: Mike Borella
**
** Comments: Support for dynamic port mapping. This allows a protocol to
** to listened for on a non-standard port. Each mapping is assigned a
** duration. Mappings that are user defined via the command line are
** considered permanent. Mappings that are made by protocols will time out
** in DYNPORTS_DURATION seconds unless they are refreshed.
**
** $Id: dynports.c,v 1.7 2002/01/02 18:16:39 mborella Exp $
**
** This program is free software; you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation; either version 2 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU Library General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program; if not, write to the Free Software
** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
**
*****************************************************************************/
#include "dynports.h"
#include "error.h"
#include "limits.h"
#define DYNPORTS_NUM 256/* max number of dynamic ports on the system */
#define DYNPORTS_DURATION 5 /* # of seconds that nonpermanent mappings stay */
typedef struct portmap
{
u_int16_t port;
service_func_t f;
unsigned long t;
} portmap_t;
static portmap_t dynport_map[DYNPORTS_NUM];
static int current_ptr = 0;
/*----------------------------------------------------------------------------
**
** dynports_add()
**
** Adds a dynamic port mapping
**
**----------------------------------------------------------------------------
*/
void dynports_add(u_int16_t port, service_func_t f, unsigned long t)
{
if (current_ptr >= DYNPORTS_NUM)
error_fatal("too many dynamic port mappings");
dynport_map[current_ptr].port = port;
dynport_map[current_ptr].f = f;
dynport_map[current_ptr].t = t;
current_ptr++;
}
/*----------------------------------------------------------------------------
**
** dynports_refresh()
**
** Refreshes dynamic port mapping, by adding the mapping again with the
** current time.
**
**----------------------------------------------------------------------------
*/
void dynports_refresh(u_int16_t port, service_func_t f)
{
struct timeval t;
int i;
/* get the current time */
gettimeofday(&t, NULL);
/* refresh the dynamic port mapping with the current time */
for (i=0; i<current_ptr; i++)
if (dynport_map[i].port == port)
{
dynport_map[i].t = t.tv_sec;
break;
}
/*
* If the dynamic mapping is not found, we just fall through. This is done
* for a reason...if we don't certain mapping in which we try to capture
* both source and dest ports might break. See the TFTP module for an
* example.
*/
}
/*----------------------------------------------------------------------------
**
** dynports_parse()
**
** Parses a string of the form 'protocol=port', such as rtp=12341.
**
**----------------------------------------------------------------------------
*/
void dynports_parse(char *s)
{
char * ptr;
u_int16_t port;
service_func_t f = NULL;
/* find = */
ptr = strchr(s,'=');
if (ptr == NULL)
error_system("unable to parse dynamic port assignment %s", s);
/* determine port # */
port = (u_int16_t) atoi(ptr+1);
/* determine protocol */
*ptr = '\0';
f = NULL;
if (!strcmp(s, "dhcp"))
f = dump_dhcp;
if (!strcmp(s, "dns"))
f = dump_dns;
if (!strcmp(s, "http"))
f = dump_http;
if (!strcmp(s, "isakmp"))
f = dump_isakmp;
if (!strcmp(s, "l2tp"))
f = dump_l2tp;
if (!strcmp(s, "mgcp"))
f = dump_mgcp;
if (!strcmp(s, "mobileip"))
f = dump_mobileip;
if (!strcmp(s, "netbios_ns"))
f = dump_netbios_ns;
if (!strcmp(s, "pptp"))
f = dump_pptp;
if (!strcmp(s, "rip"))
f = dump_rip;
if (!strcmp(s, "ripng"))
f = dump_ripng;
if (!strcmp(s, "rtp"))
f = dump_rtp;
if (!strcmp(s, "sip"))
f = dump_sip;
if (!strcmp(s, "snmp"))
f = dump_snmp;
if (!strcmp(s, "slp"))
f = dump_slp;
if (!strcmp(s, "ftpctrl"))
f = dump_ftpctrl;
if (f==NULL)
error_fatal("dynamic port assignment to unknown protocol %s", s);
/* Add the port assignment with an infinite duration */
dynports_add(port, f, ULONG_MAX);
/* If we're adding an RTP port, add an RTCP port as well. */
if (!strcmp(s, "rtp"))
dynports_add(port+1, dump_rtcp, ULONG_MAX);
}
/*----------------------------------------------------------------------------
**
** dynports_find()
**
** Find a protocol function pointer given the port number. Returns the
** function pointer or null if not found.
**
**----------------------------------------------------------------------------
*/
service_func_t dynports_find(u_int16_t port)
{
int i;
for (i=0; i<current_ptr; i++)
if (dynport_map[i].port == port)
return dynport_map[i].f;
return NULL;
}
/*----------------------------------------------------------------------------
**
** dynports_timeout()
**
** Time out stale dynamic port mappings.
**
**----------------------------------------------------------------------------
*/
void dynports_timeout(void)
{
int i;
struct timeval t;
/* get the current time */
gettimeofday(&t, NULL);
for (i=0; i<current_ptr; i++)
if (dynport_map[i].t < ULONG_MAX &&
dynport_map[i].t + DYNPORTS_DURATION < t.tv_sec)
{
dynport_map[i].f = NULL;
dynport_map[i].t = 0;
}
}
syntax highlighted by Code2HTML, v. 0.9.1