: add config-variables to OpenVPN-1.3.2
PATCH 1/1 : add config-variables to OpenVPN-1.3.2
Hi, Jim,
here is another one:
I've added variable-expandion to config-values and the keywords "set" and "unset". With this technique you can easily split configuration of one peer across two files:
one with the specific and one with the common config values in a way that can help to minimize the number of "configuration-knobs".
An example:
/etc/openvpn/customer_123.conf:
# specific configuration for customer #123
set CUSTNO 123
config ./customers.common
/etc/openvpn/customer.common:
# meta-configuration for all customers
dev-name vpn_$(CUSTNO) # vpn_001 to vpn_255
port 5$(CUSTNO) # 5001 to 5255
ifconfig 10.0.0.1 10.0.$(CUSTNO).1 # 10.0.001.1 to 10.0.255.1
dev-type tun # other stuff ...
.
.
.These are the same variable-expansion routines I committed to the Snort-IDS some time ago.
The syntax is follows:
set name value define the variable "name" containing "value".
unset name undefine the variable "name".
$(name) replace with the contents of variable "name".
$(name:-default) replace with the contents of the variable "name" or with
"default" if "name" is undefined.
$(name:?message) replace with the contents of variable "name" or print out
the error message "message" and exit.
The next thing could be something like $(( expression or calculation )).
As before, the patch is quite young and certanly needs more testing :-)
Regards,
Christian Lademann <[email protected]...>
Signature · 5 lines
* Christian A. Lademann, ZLS Software GmbH mailto:[email protected]... * ZLS Software GmbH * Frankfurter Strasse 59 Postfach 1628 mailto:[email protected]... * D-65779 Kelkheim D-65766 Kelkheim http://www.zls.de * Telefon +49-6195-9902-0 Telefax +49-6195-900600
options.c +344 -2
@@ -38,6 +38,22 @@#include "memdbg.h" + +struct VarEntry { +char *name; +char *value; +struct VarEntry *prev; +struct VarEntry *next; +}; + +struct VarEntry *VarHead =NULL ; +void VarDefine (char *,char *); +void VarDelete (char *); +char *ExpandVars (char *); + +char *VarFile =NULL ; +int VarLine =0 ; +static const char usage_message[] ="%s\n" "\n"
@@ -45,6 +61,8 @@"--help : Show options.\n" "--version : Show copyright and version information.\n" "--config file : Read configuration options from file.\n" +"--set name value: Set config-variable.\n" +"--unset name : Unset config-variable.\n" "\n" "Tunnel Options:\n" "--local host : Local host name or ip address.\n"
@@ -618,10 +636,38 @@ }static int -add_option (struct options *options,int i,char *p1,char *p2,char *p3, +add_option (struct options *options,int i,char *p1,char *p2r,char *p3r,const char * file,int line,int level) { -if (!file) +char *p2 = p2r; +char *p3 = p3r; + +char pd[1024 ]; + + +if (file) + { + + VarFile = (char *)file; + VarLine = line; + +if (p2r) + { +memset (pd,0 ,sizeof (pd)); +strncpy (pd,ExpandVars (p2r),sizeof (pd)); + p2 =gc_malloc (strlen (pd) +1 ); +strncpy (p2, pd,strlen (pd)); + } + +if (p3r) + { +memset (pd,0 ,sizeof (pd)); +strncpy (pd,ExpandVars (p3r),sizeof (pd)); + p3 =gc_malloc (strlen (pd) +1 ); +strncpy (p3, pd,strlen (pd)); + } + } +else { file ="[CMD-LINE]" ; line =1 ;
@@ -1062,6 +1108,16 @@ options->persist_mode =1 ; }#endif + else if (streq (p1, "set") && p2 && p3) + { + i +=2 ; +VarDefine (p2, p3); + } + else if (streq (p1, "unset") && p2) + { + ++i; +VarDelete (p2); + } else {if (file)
@@ -1109,4 +1165,290 @@ } i =add_option (options, i, p1, p2, p3,NULL ,0 ,0 ); } +} + + +/**************************************************************************** +* +* Function: VarAlloc() +* +* Purpose: allocates memory for a variable +* +* Arguments: none +* +* Returns: pointer to new VarEntry +* +***************************************************************************/ +struct VarEntry * +VarAlloc () { +struct VarEntry *new; + + +if ((new = (struct VarEntry *)malloc (sizeof (struct VarEntry ))) ==NULL ) { +fprintf (stderr,"ERROR: cannot allocate memory for VarEntry." ); +exit (1 ); + } + + new->name =NULL ; + new->value =NULL ; + new->prev =NULL ; + new->next =NULL ; + +return (new); +} + + +/**************************************************************************** +* +* Function: VarDefine(char *, char *) +* +* Purpose: define the contents of a variable +* +* Arguments: name => the name of the variable +* value => the contents of the variable +* +* Returns: void function +* +***************************************************************************/ +void +VarDefine (char *name,char *value) { +struct VarEntry *p; +int found =0 ; + + +if (! VarHead) { + p =VarAlloc (); + p->name =strdup (name); + p->value =strdup (value); + p->prev = p; + p->next = p; + + VarHead = p; + +return ; + } + + p = VarHead; +do { +if (strcasecmp (p->name, name) ==0 ) { + found =1 ; +break ; + } + + p = p->next; + }while (p != VarHead); + +if (found) { +if (p->value) +free (p->value); + + p->value =strdup (value); + }else { + p =VarAlloc (); + p->name =strdup (name); + p->value =strdup (value); + p->prev = VarHead; + p->next = VarHead->next; + p->next->prev = p; + VarHead->next = p; + } +} + + +/**************************************************************************** +* +* Function: VarDelete(char *) +* +* Purpose: deletes a defined variable +* +* Arguments: name => the name of the variable +* +* Returns: void function +* +***************************************************************************/ +void +VarDelete (char *name) { +struct VarEntry *p; + + +if (! VarHead) +return ; + + p = VarHead; +do { +if (strcasecmp (p->name, name) ==0 ) { + p->prev->next = p->next; + p->next->prev = p->prev; + +if (VarHead == p) +if ((VarHead = p->next) == p) + VarHead =NULL ; + +if (p->name) +free (p->name); + +if (p->value) +free (p->value); + +free (p); + +return ; + } + + p = p->next; + }while (p != VarHead); +} + + +/**************************************************************************** +* +* Function: VarGet(char *) +* +* Purpose: get the contents of a variable +* +* Arguments: name => the name of the variable +* +* Returns: char * to contents of variable or NULL +* +***************************************************************************/ +char * +VarGet (char *name) { +struct VarEntry *p; + + +if (! VarHead) +return (NULL ); + + p = VarHead; +do { +if (strcasecmp (p->name, name) ==0 ) +return (p->value); + + p = p->next; + }while (p != VarHead); + +return (NULL ); +} + + +/**************************************************************************** +* +* Function: ExpandVars(char *) +* +* Purpose: expand all variables in a string +* +* Arguments: string => the name of the variable +* +* Returns: char * to the expanded string +* +***************************************************************************/ +char * +ExpandVars (char *string) { +static char estring[1024 ]; +char rawvarname[128 ], + varname[128 ], + varaux[128 ], + varbuffer[128 ], + varmodifier, + *varcontents; +int varname_completed, + c, i, j, iv, jv, + l_string, + name_only; + + +if (!string || ! *string || !strchr (string,'$' )) +return (string); + + +bzero (estring,sizeof (estring)); + + i = j =0 ; + l_string =strlen (string); +while (i < l_string && j <sizeof (estring) -1 ) { + c = string[i++]; +if (c =='$' ) { +bzero (rawvarname,sizeof (rawvarname)); + varname_completed =0 ; + name_only =1 ; + iv = i; + jv =0 ; + +if (string[i] =='(' ) { + name_only =0 ; + iv = i +1 ; + } + +while (!varname_completed && iv < l_string && jv <sizeof (rawvarname) -1 ) { + c = string[iv++]; +if ((name_only && !(isalnum (c) || c =='_' )) || (! name_only && c ==')' )) { + varname_completed =1 ; + +if (name_only) + iv--; + }else { + rawvarname[jv++] = c; + } + } + +if (varname_completed) { +char *p; + + i = iv; + + varcontents =NULL ; + +bzero (varname,sizeof (varname)); +bzero (varaux,sizeof (varaux)); + varmodifier =' ' ; + +if ((p =strchr (rawvarname,':' ))) { +strncpy (varname, rawvarname, p - rawvarname); + +if (strlen (p) >=2 ) { + varmodifier = *(p +1 ); +strcpy (varaux, p +2 ); + } + }else +strcpy (varname, rawvarname); + +bzero (varbuffer,sizeof (varbuffer)); + + varcontents =VarGet (varname); + +switch (varmodifier) { +case '-' : +if (! varcontents || !strlen (varcontents)) + varcontents = varaux; +break ; + +case '?' : +if (! varcontents || !strlen (varcontents)) { +fprintf (stderr,"ERROR Line %s (%d): " , (VarFile ? VarFile :"<stdin>" ), VarLine); + +if (strlen (varaux)) +fprintf (stderr,"%s\n" , varaux); +else +fprintf (stderr,"Undefined variable \"%s\"\n" , varname); + +exit (1 ); + } + +break ; + } + +if (varcontents) { +int l_varcontents =strlen (varcontents); + + iv =0 ; +while (iv < l_varcontents && j <sizeof (estring) -1 ) + estring[j++] = varcontents[iv++]; + } + }else + estring[j++] ='$' ; + }else + estring[j++] = c; + } + +return (estring); }
Christian,
Rather than put a lot of scripting language infrastructure into OpenVPN's config file parser, why not just use a shell script, i.e.:
openvpn --dev-name vpn_${CUSTNO} \
--port 5${CUSTNO} \
--ifconfig 10.0.0.1 10.0.${CUSTNO}.1 \
--dev-type tun \
[ ... ]After all, isn't this exactly the sort of problem that shell scripting languages were supposed to solve?
James
Quoted 5 lines · ZLS Software GmbH
Hi, Jim,
here is another one:
I've added variable-expandion to config-values and the keywords "set" and
"unset".
Quoted 1 line
With this technique you can easily split configuration of one peer across
two files:
Quoted 1 line
one with the specific and one with the common config values in a way that
can help to
Quoted 23 lines
minimize the number of "configuration-knobs".
An example:
/etc/openvpn/customer_123.conf: # specific configuration for customer #123 set CUSTNO 123 config ./customers.common /etc/openvpn/customer.common: # meta-configuration for all customers dev-name vpn_$(CUSTNO) # vpn_001 to vpn_255 port 5$(CUSTNO) # 5001 to 5255 ifconfig 10.0.0.1 10.0.$(CUSTNO).1 # 10.0.001.1 to 10.0.255.1 dev-type tun # other stuff ... . . .
Quoted 1 line
These are the same variable-expansion routines I committed to the Snort-IDS
some time ago.
Quoted 33 lines
The syntax is follows:
set name value define the variable "name" containing "value".
unset name undefine the variable "name".$(name) replace with the contents of variable "name".
$(name:-default) replace with the contents of the variable "name" or with
"default" if "name" is undefined.$(name:?message) replace with the contents of variable "name" or print out
the error message "message" and exit.The next thing could be something like $(( expression or calculation )).
As before, the patch is quite young and certanly needs more testing :-)
Regards,
Christian Lademann <[email protected]...>
Signature · 5 lines
* Christian A. Lademann, ZLS Software GmbH mailto:[email protected]... * ZLS Software GmbH * Frankfurter Strasse 59 Postfach 1628 mailto:[email protected]... * D-65779 Kelkheim D-65766 Kelkheim http://www.zls.de * Telefon +49-6195-9902-0 Telefax +49-6195-900600