Files
2026-07-30 11:19:44 +05:30

854 lines
24 KiB
C

/*
******************************************************************************
* SOURCE FILE
*
* Document no: @(#) $Name: VXWORKS_ITER40_2019102207 $ $RCSfile: ipdhcps_example.c,v $ $Revision $
* $Source: /home/interpeak/CVSRoot/ipdhcps/config/ipdhcps_example.c,v $
* $Author: kenneth $
* $State: Exp $ $Locker: $
*
* INTERPEAK_COPYRIGHT_STRING
*
* Design and implementation by Jonas Rendel <jonas@interpeak.se>
******************************************************************************
*/
/*
****************************************************************************
* 1 DESCRIPTION
****************************************************************************
* Example file on :
* 1. How to save lease database at shutdown.
* 2. How to restore lease database at startup
*/
/*
****************************************************************************
* 2 CONFIGURATION
****************************************************************************
*/
#include <ipcom_config.h>
#if defined(IP_WB_BUILD) && defined(IPCOM_USE_CLIB_PROTO)
#undef IPCOM_USE_CLIB_PROTO
#endif
/*
****************************************************************************
* 3 INCLUDE FILES
****************************************************************************
*/
#define IPCOM_USE_CLIB_PROTO
#include <ipcom_clib.h>
#include <ipcom_clib2.h>
#include <ipcom_strlib.h>
#include <ipcom_os.h>
#include <ipcom_err.h>
#include <ipcom_tmo.h>
#include <ipcom_shell.h>
#include <ipcom_syslog.h>
#include <ipcom_file.h>
#include "ipdhcps.h"
/*
****************************************************************************
* 4 DEFINES
****************************************************************************
*/
/*
****************************************************************************
* 5 TYPES
****************************************************************************
*/
/*
****************************************************************************
* 6 EXTERN PROTOTYPES
****************************************************************************
*/
/*
****************************************************************************
* 7 LOCAL PROTOTYPES
****************************************************************************
*/
IP_STATIC int example_restore_lease_db(void);
IP_STATIC int example_dump_lease_db(void);
IP_STATIC Ip_s32 example_lease_dump_tmo_func(struct Ipcom_tmo_struct *tmo,
void *cookie);
/* IPCOM timeout handler used in the configuration example below. */
IP_STATIC Ipcom_tmo lease_dump_tmo;
#if (defined(IP_WB_BUILD) && defined(IPDHCPS_UNSUPPORTED_EXAMPLE)) || !defined(IP_WB_BUILD)
/*
****************************************************************************
* 8 DATA
****************************************************************************
*/
/*
****************************************************************************
* 9 LOCAL FUNCTIONS
****************************************************************************
*/
/*
****************************************************************************
* 10 GLOBAL FUNCTIONS
****************************************************************************
*/
#ifdef IPDHCPS_USE_EXAMPLE
/*
*===========================================================================
* restore_lease_db
*===========================================================================
* Description: This is an example on how the contents of the IPDHCPS
* lease database can be restored by initializing it with
* data stored in a file system.
*
* Parameters: -
* Returns: 0 - success
* -1 - failure
*
*/
IP_STATIC int
example_restore_lease_db(void)
{
int retval = -1;
IP_FILE *fd = IP_NULL;
struct Ip_stat statbuf;
void *buf = IP_NULL;
if(ipcom_stat("/home/jonas/dumpfile", &statbuf) == -1)
goto leave;
if((fd = ipcom_fopen("/home/jonas/dumpfile", "r")) == 0)
goto leave;
if((buf = ipcom_malloc(statbuf.st_size)) == IP_NULL)
goto leave;
if(ipcom_fread(buf, statbuf.st_size, 1, fd) <= 0)
goto leave;
ipdhcps_lease_db_restore(buf);
retval = 0;
leave:
if(fd)
ipcom_fclose(fd);
if(buf != IP_NULL)
ipcom_free(buf);
return retval;
}
/*
*===========================================================================
* dump_lease_db
*===========================================================================
* Description: This is an example on how to save the current contents
* of the IPDHCPS lease database to a file system.
* The routine is adapted for a UNIX file system.
*
* Parameters: -
* Returns: 0 - success
* -1 - failure
*/
IP_STATIC int
example_dump_lease_db(void)
{
int retval = -1;
void *buf = IP_NULL;
IP_FILE *fd = IP_NULL;
int n;
if((n = ipdhcps_lease_db_dump(&buf)) < 0)
goto leave;
if((fd = ipcom_fopen("/home/jonas/dumpfile","w+")) == 0)
goto leave;
if((ipcom_fwrite(buf, n, 1, fd)) <= 0)
goto leave;
retval = 0;
leave:
if(fd)
ipcom_fclose(fd);
if(buf != IP_NULL)
ipcom_free(buf);
return retval;
}
/*
*===========================================================================
* lease_dump_tmo_func
*===========================================================================
* Description: This is an example on how the contents of the lease
* database can be dumped periodically to a file during
* execution of IPDHCPS.
*
* Parameters: -
* Returns: 0 - success
* -1 - failure
*/
IP_STATIC Ip_s32
example_lease_dump_tmo_func(struct Ipcom_tmo_struct *tmo, void *cookie)
{
if(example_dump_lease_db() == 0)
return 1;
else
return 0;
}
#endif /* IPDHCPS_USE_EXAMPLE */
#if defined (IPDHCPS_INCLUDE_CMD) && defined (IPDHCPS_INCLUDE_ISC_EXAMPLE)
IP_GLOBAL int ipdhcps_cmd_dhcps(int argc, char **argv);
typedef struct _example_token_buffer
{
char *llines;
char *lines;
char *ltokens;
char *tokens;
/**/
char *spec;
/**/
Ip_bool eof;
int curline;
} example_token_buffer_t;
/*
*===========================================================================
* example_do_command
*===========================================================================
* Description: Execute a DHCPS command containing the parameters we're
* interested in adding to the configuration.
* Parameters: format - The format string
* ... - The arguments for the format string
* Returns:
*
*/
IP_STATIC void
example_do_command(const char *format, ...)
{
va_list vargs;
char *cmd;
int argc;
char **argv = IP_NULL;
if ((cmd = ipcom_malloc(256)) != IP_NULL)
{
va_start(vargs, format);
ipcom_vsnprintf(cmd, 256, format, vargs);
va_end(vargs);
IPCOM_LOG1(INFO,"DHCP Executing '%s'", cmd);
if(ipcom_parse_argstr(cmd, (int*)&argc, &argv) != IPCOM_SUCCESS)
{
IPCOM_LOG1(ERR,"failed to parse command '%s'", cmd);
goto out;
}
if(ipdhcps_cmd_dhcps(argc, argv) != IPCOM_SUCCESS)
{
IPCOM_LOG1(ERR,"failed to execute command '%s'", cmd);
goto out;
}
out:
if (argv != IP_NULL)
ipcom_free(argv);
if (cmd)
ipcom_free(cmd);
}
}
/*
*===========================================================================
* example_get_line
*===========================================================================
* Description: Fetch the next available line into the tokenizer buffer
* Parameters: tok - The tokenizer buffer
* Returns: IP_TRUE on success, IP_FALSE if we're at EOF.
*
*/
IP_STATIC Ip_bool
example_get_line(example_token_buffer_t *tok)
{
char *line;
char *t;
restart:
/* Already EOF */
if (tok->eof)
return IP_FALSE;
/* Get next */
line = ipcom_strtok_r(tok->lines, "\r\n", &tok->llines);
tok->curline++;
tok->lines = IP_NULL;
/* No more lines? */
if (line == IP_NULL)
{
tok->eof = IP_TRUE;
return IP_FALSE;
}
/* Discard comments */
t = ipcom_strchr(line, '#');
if (t)
*t = '\0';
/* Empty line; restart */
if (ipcom_strlen(line) == 0)
goto restart;
/* Set the tokens; discard any stored values */
tok->tokens = line;
tok->spec = IP_NULL;
return IP_TRUE;
}
/*
*===========================================================================
* example_get_token
*===========================================================================
* Description: Get the next token from the tokenizer
* Parameters: tok - The tokenizer buffer
* nl - IP_TRUE if we're allowed to consume newlines
* Returns: A token if one is available, IP_NULL otherwise.
*
*/
IP_STATIC char *
example_get_token(example_token_buffer_t *tok, Ip_bool nl)
{
char *token;
if (tok->eof)
{
/* We're out of tokens */
return IP_FALSE;
}
else if (tok->spec)
{
/* There's a special token stored. ';' */
token = tok->spec;
tok->spec = IP_NULL;
}
else
{
char *t;
while ((token = ipcom_strtok_r(tok->tokens, ",\t ", &tok->ltokens)) == IP_NULL)
{
if (nl && example_get_line(tok))
continue;
return IP_NULL;
}
/* Clear the tokens buffer */
tok->tokens = IP_NULL;
/* Need to separate semicolons; they're used as 'eol' */
if (ipcom_strchr(token, ';') != IP_NULL)
tok->spec = ";";
token = ipcom_strtok_r(token, ";", &t);
}
return token;
}
/*
*===========================================================================
* example_check_token
*===========================================================================
* Description: Check that the next token matches what is required.
* Parameters: tok - The tokenizer buffer
* req - The required token
* nl - IP_TRUE if we're allowed to consume newlines
* Returns: IP_TRUE on success, IP_FALSE otherwise
*
*/
IP_STATIC Ip_bool
example_check_token(example_token_buffer_t *tok, const char *req, Ip_bool nl)
{
char *token = example_get_token(tok, nl);
if (token)
{
if (req && ipcom_strcasecmp(token, req) == 0)
return IP_TRUE;
return IP_FALSE;
}
return req? IP_FALSE : IP_TRUE;
}
/*
*===========================================================================
* example_concatenate_tokens
*===========================================================================
* Description: Concatenate all options on this line
* Parameters: tok - The tokenizer buffer
* Returns: A dynamically allocated memory buffer containing all the
* tokenized options on success, IP_NULL otherwise.
*
*/
IP_STATIC char *
example_concatenate_tokens(example_token_buffer_t *tok)
{
char *value;
char *conc = ipcom_malloc(256);
if (conc != IP_NULL)
{
int no_values = 0;
conc[0] = '\0';
while ((value = example_get_token(tok, IP_FALSE)) != IP_NULL)
{
if (ipcom_strcasecmp(value, ";") == 0)
break;
no_values++;
ipcom_strncat(conc, value, 256);
ipcom_strncat(conc, " ", 256);
}
/* No semicolon or no values */
if (no_values == 0 || value == IP_NULL)
{
ipcom_free(conc);
return IP_NULL;
}
return conc;
}
return IP_NULL;
}
/*
*===========================================================================
* example_parse_option
*===========================================================================
* Description: Parse a ISC option string
* Parameters: tok - The tokenizer buffer
* context - The context the option resides in
* Returns: 0 on success.
*
*/
IP_STATIC Ip_s32
example_parse_option(example_token_buffer_t *tok, const char *context)
{
/* Retrieve the option name */
char *option = example_get_token(tok, IP_FALSE);
if (option == IP_NULL)
{
IPCOM_LOG1(ERR,
"DHCPS(%d): no option name specified",
tok->curline);
return -1;
}
if (ipcom_strcasecmp(option, "domain-name-servers") == 0)
{
/* DNS servers option; retrieve the list of servers and pass it
* to our dhcps command */
char *value = example_concatenate_tokens(tok);
if (value == IP_NULL)
{
IPCOM_LOG1(ERR,
"DHCPS(%d): No servers specified or lacking ';' in domain-name-servers option",
tok->curline);
return -1;
}
example_do_command("dhcps option add %s 5 %s", context, value);
ipcom_free(value);
}
else if (ipcom_strcasecmp(option, "domain-name") == 0)
{
/* A domain name */
char *value = example_get_token(tok, IP_FALSE);
if (!example_check_token(tok, ";", IP_FALSE))
{
IPCOM_LOG1(ERR,
"DHCPS(%d): No domain name specified or lacking ';' in domain-name option",
tok->curline);
return -1;
}
example_do_command("dhcps option add %s 15 %s", context, value);
}
else if (ipcom_strcasecmp(option, "routers") == 0)
{
/* One or many routers */
char *value = example_concatenate_tokens(tok);
if (value == IP_NULL)
{
IPCOM_LOG1(ERR,
"DHCPS(%d): No servers specified or lacking ';' in routers option",
tok->curline);
return -1;
}
example_do_command("dhcps option add %s 3 %s", context, value);
ipcom_free(value);
}
else
{
/* Unknown or unhandled option */
IPCOM_LOG2(WARNING,
"DHCPS(%d): Unknown option %s",
tok->curline,
option);
return -1;
}
return 0;
}
/*
*===========================================================================
* example_parse_subnet
*===========================================================================
* Description: Parse an ISC subnet directive
* Parameters: tok - The tokenizer buffer.
* Returns: 0 on success
*
*/
IP_STATIC Ip_s32
example_parse_subnet(example_token_buffer_t *tok)
{
/* address NETMASK netmask { */
char *address, *netmask;
char *token;
/* We need to retrieve the address, the NETMASK keyword and the
* netmask value */
address = example_get_token(tok, IP_FALSE);
if (!example_check_token(tok, "netmask", IP_FALSE))
return -1;
netmask = example_get_token(tok, IP_FALSE);
/**/
if (address == IP_NULL || netmask == IP_NULL)
return -1;
/* The subnet block starts with a left bracer */
if (!example_check_token(tok, "{", IP_TRUE))
return -1;
/* Add the subnet command */
example_do_command("dhcps subnet add %s %s", address, netmask);
/* Go through the subnet */
while ((token = example_get_token(tok, IP_TRUE)) != IP_NULL)
{
int retval;
/* End of subnet is a right bracer, exit successfully if found */
if (ipcom_strcasecmp(token, "}") == 0)
return 0;
else if (ipcom_strcasecmp(token, "option") == 0)
{
/* Parse a subnet specific option */
if ((retval = example_parse_option(tok, address)) != 0)
return retval;
}
else if (ipcom_strcasecmp(token, "range") == 0)
{
/* Parse a pool range */
char *start, *end;
start = example_get_token(tok, IP_FALSE);
end = example_get_token(tok, IP_FALSE);
if (!example_check_token(tok, ";", IP_FALSE))
{
IPCOM_LOG1(ERR,
"DHCPS(%d): Missing range start, end or ';' in range directive",
tok->curline);
return -1;
}
example_do_command("dhcps pool add %s %s %s", address, start, end);
}
else if (ipcom_strcasecmp(token, "default-lease-time") == 0)
{
char *lease;
lease = example_get_token(tok, IP_FALSE);
if (!example_check_token(tok, ";", IP_FALSE))
{
IPCOM_LOG1(ERR,
"DHCPS(%d): lease time specified or ';' missing in default-lease-time directive",
tok->curline);
return -1;
}
example_do_command("dhcps config set %s default-lease-time %s", address, lease);
}
else if (ipcom_strcasecmp(token, "max-lease-time") == 0)
{
char *lease;
lease = example_get_token(tok, IP_FALSE);
if (!example_check_token(tok, ";", IP_FALSE))
{
IPCOM_LOG1(ERR,
"DHCPS(%d): lease time specified or ';' missing in max-lease-time directive",
tok->curline);
return -1;
}
example_do_command("dhcps config set %s max-lease-time %s", address, lease);
}
}
}
/*
*===========================================================================
* example_parse_base
*===========================================================================
* Description: Parse top-level ISC configuration items
* Parameters: tok - The tokenizer buffer
* Returns: 0 on success
*
*/
IP_STATIC Ip_s32
example_parse_base(example_token_buffer_t *tok)
{
for (;;)
{
char *token = example_get_token(tok, IP_TRUE);
char *value;
int ret;
/* EOF; We've read the entire file - exit */
if (token == IP_NULL)
return 0;
/* Check the token and see if we know it */
if (ipcom_strcasecmp(token, "subnet") == 0)
{
ret = example_parse_subnet(tok);
}
else if (ipcom_strcasecmp(token, "option") == 0)
{
ret = example_parse_option(tok, "default");
}
else if (ipcom_strcasecmp(token, "default-lease-time") == 0)
{
value = example_get_token(tok, IP_FALSE);
if (!example_check_token(tok, ";", IP_FALSE))
{
IPCOM_LOG1(ERR,
"DHCPS(%d): lease time specified or ';' missing in default-lease-time directive",
tok->curline);
return -1;
}
example_do_command("dhcps config set default default-lease-time %s", value);
}
else if (ipcom_strcasecmp(token, "max-lease-time") == 0)
{
value = example_get_token(tok, IP_FALSE);
if (!example_check_token(tok, ";", IP_FALSE))
{
IPCOM_LOG1(ERR,
"DHCPS(%d): lease time specified or ';' missing in max-lease-time directive",
tok->curline);
return -1;
}
example_do_command("dhcps config set default max-lease-time %s", value);
}
else if (ipcom_strcasecmp(token, "authoritative") == 0 ||
ipcom_strcasecmp(token, "ddns-update-style") == 0 ||
ipcom_strcasecmp(token, "log-facility") == 0)
{
/* Unsupported ISC directives
* Consume this line
*/
IPCOM_LOG2(WARNING,
"DHCPS(%d): Unhandled directive %s specified",
tok->curline,
token);
example_get_line(tok);
}
}
}
/*
*===========================================================================
* example_cfgfile
*===========================================================================
* Description: Read an ISC DHCP configuration file
* Parameters: cfgfile - The configuration file
* Returns: 0 on success, -1 or errorcode otherwise.
*
*/
IP_GLOBAL Ip_s32
example_isc_config(const char *cfgfile)
{
int retval = -1;
char *buf = IP_NULL;
IP_FILE *fd = IP_NULL;
struct Ip_stat st;
example_token_buffer_t tbuf;
/* Failed to read */
if (ipcom_stat(cfgfile, &st) != 0)
{
IPCOM_LOG1(ERR,
"DHCPS: Failed to stat configuration file %s",
cfgfile);
goto leave;
}
/* Failed to open */
if((fd = ipcom_fopen(cfgfile,"r")) == 0)
{
IPCOM_LOG1(ERR,
"DHCPS: Failed to open configuration file %s",
cfgfile);
goto leave;
}
/* Allocate buffer */
if ((buf = ipcom_malloc(st.st_size + 1)) == IP_NULL)
{
IPCOM_LOG1(ERR,
"DHCPS: Failed to allocate memory for configuration file %s",
cfgfile);
goto leave;
}
/* Read entire file */
if((ipcom_fread(buf, 1, st.st_size, fd)) != st.st_size)
{
IPCOM_LOG1(ERR,
"DHCPS: Failed to read configuration file %s",
cfgfile);
goto leave;
}
/* Zero terminate; */
buf[st.st_size] = '\0';
/* Do parse the configuration file */
ipcom_memset(&tbuf, 0, sizeof(tbuf));
tbuf.lines = buf;
example_get_line(&tbuf);
/* Parse the file */
retval = example_parse_base(&tbuf);
leave:
if (fd)
ipcom_fclose(fd);
if(buf != IP_NULL)
ipcom_free(buf);
return retval;
}
#endif /* defined (IPDHCPS_INCLUDE_CMD) && defined (IPDHCPS_INCLUDE_ISC_EXAMPLE) */
/******************************************************************************
*
* ipdhcps_example_start_hook - example dhcps startup callback routine
*
* This is an example implementation of the callback routine that is called
* by the DHCP server startup.
*
* RETURNS:
* 0 if success or -1 if failure
*
* NOMANUAL
*/
IP_GLOBAL int ipdhcps_example_start_hook (void)
{
#ifdef IPDHCPS_USE_EXAMPLE
/* Restore lease database */
example_restore_lease_db ();
ipcom_tmo_request (&lease_dump_tmo,
example_lease_dump_tmo_func,
&lease_dump_tmo,
10*60*60*1000);
#endif /* IPDHCPS_USE_EXAMPLE */
#if defined (IPDHCPS_INCLUDE_CMD) && defined (IPDHCPS_INCLUDE_ISC_EXAMPLE)
{
char *cfgfile = ipcom_sysvar_get("ipdhcps.iscfile", IP_NULL, IP_NULL);
if (cfgfile)
{
ret = example_isc_config(cfgfile);
ipcom_free(cfgfile);
}
}
#endif
return 0;
}
/******************************************************************************
*
* ipdhcps_example_stop_hook - example dhcp server terminate callback routine
*
* This is an example implementation of the callback routine that is called
* by the DHCP server upon termination.
*
* RETURNS:
* 0 if success or -1 if failure
*
* NOMANUAL
*/
IP_GLOBAL int ipdhcps_example_stop_hook (void)
{
(void)ipcom_tmo_cancel (&lease_dump_tmo);
example_dump_lease_db ();
return 0;
}
#endif /* IPDHCPS_UNSUPPORTED_EXAMPLE */
/*
****************************************************************************
* END OF FILE
****************************************************************************
*/