]> git.ipfire.org Git - ipfire-2.x.git/blobdiff - html/cgi-bin/dhcp.cgi
mympd: remove create config start
[ipfire-2.x.git] / html / cgi-bin / dhcp.cgi
index e75207a21913f1b44d507f782b514f159bea7f88..be00f199a8b8215632307789d37e212b2dc2f6d8 100644 (file)
@@ -2,7 +2,7 @@
 ###############################################################################
 #                                                                             #
 # IPFire.org - A linux based firewall                                         #
-# Copyright (C) 2007  Michael Tremer & Christian Schmidt                      #
+# Copyright (C) 2007-2024  IPFire Team  <info@ipfire.org>                     #
 #                                                                             #
 # 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        #
@@ -20,6 +20,7 @@
 ###############################################################################
 
 use strict;
+use experimental 'smartmatch';
 
 # enable only the following on debugging purpose
 #use warnings;
@@ -46,8 +47,8 @@ my $warnNTPmessage = '';
 my @nosaved=();
 my %color = ();
 
-#Basic syntax allowed for new Option definition. Not implemented: RECORDS & array of RECORDS 
-our $OptionTypes = 'boolean|((un)?signed )?integer (8|16|32)|ip-address|text|string|encapsulate \w+|array of ip-address';
+#Basic syntax allowed for new Option definition. Not implemented: RECORDS & array of RECORDS
+our $OptionTypes = 'boolean|((un)?signed )?integer (8|16|32)|ip-address|text|string|encapsulate \w+|array of (ip-address|integer (8|16|32))';
 
 &Header::showhttpheaders();
 our @ITFs=('GREEN');
@@ -70,11 +71,18 @@ foreach my $itf (@ITFs) {
     $dhcpsettings{"NTP2_${itf}"} = '';
     $dhcpsettings{"NEXT_${itf}"} = '';
     $dhcpsettings{"FILE_${itf}"} = '';
+    $dhcpsettings{"DNS_UPDATE_KEY_NAME_${itf}"} = '';
+    $dhcpsettings{"DNS_UPDATE_KEY_SECRET_${itf}"} = '';
+    $dhcpsettings{"DNS_UPDATE_KEY_ALGO_${itf}"} = '';
+    $dhcpsettings{"DENY_KNOWN_CLIENTS_${itf}"} = 'off';
 }
 
 $dhcpsettings{'SORT_FLEASELIST'} = 'FIPADDR';
 $dhcpsettings{'SORT_LEASELIST'} = 'IPADDR';
 
+# DNS Update settings
+$dhcpsettings{'DNS_UPDATE_ENABLED'} = 'off';
+
 #Settings2 for editing the multi-line list
 #Must not be saved with writehash !
 $dhcpsettings{'FIX_MAC'} = '';
@@ -103,7 +111,7 @@ foreach my $itf (@ITFs) {
 &General::readhash("${General::swroot}/ethernet/settings", \%netsettings);
 &General::readhash("${General::swroot}/main/settings", \%mainsettings);
 &General::readhash("${General::swroot}/time/settings", \%timesettings);
-&General::readhash("/srv/web/ipfire/html/themes/".$mainsettings{'THEME'}."/include/colors.txt", \%color);
+&General::readhash("/srv/web/ipfire/html/themes/ipfire/include/colors.txt", \%color);
 
 #Get GUI values
 &Header::getcgihash(\%dhcpsettings);
@@ -122,6 +130,15 @@ open(FILE, "$filename2") or die 'Unable to open fixed leases file.';
 our @current2 = <FILE>;
 close(FILE);
 
+# Open and read-in file which contains the list of allowed advanced options.
+open(FILE, $filename3) or die "Could not open $filename3. $!\n";
+
+# Grab file content.
+my @advoptions_list = <FILE>;
+
+# Close file handle.
+close(FILE);
+
 # Check Settings1 first because they are needed by &buildconf
 if ($dhcpsettings{'ACTION'} eq $Lang::tr{'save'}) {
     foreach my $itf (@ITFs) {
@@ -136,14 +153,14 @@ if ($dhcpsettings{'ACTION'} eq $Lang::tr{'save'}) {
                    $errormessage = "DHCP on ${itf}: " . $Lang::tr{'invalid end address'};
                    goto ERROR;
                }
-               if (! &General::IpInSubnet ( $dhcpsettings{"START_ADDR_${itf}"}, 
+               if (! &General::IpInSubnet ( $dhcpsettings{"START_ADDR_${itf}"},
                                    $netsettings{"${itf}_NETADDRESS"},
                                    $netsettings{"${itf}_NETMASK"})) {
                    $errormessage = "DHCP on ${itf}: " . $Lang::tr{'invalid start address'};
                    goto ERROR;
                }
            }
-           
+
            if ($dhcpsettings{"END_ADDR_${itf}"}) {
                if (!(&General::validip($dhcpsettings{"END_ADDR_${itf}"}))) {
                    $errormessage = "DHCP on ${itf}: " . $Lang::tr{'invalid end address'};
@@ -153,9 +170,9 @@ if ($dhcpsettings{'ACTION'} eq $Lang::tr{'save'}) {
                    $errormessage = "DHCP on ${itf}: " . $Lang::tr{'invalid start address'};
                    goto ERROR;
                }
-               if (! &General::IpInSubnet ( $dhcpsettings{"END_ADDR_${itf}"}, 
+               if (! &General::IpInSubnet ( $dhcpsettings{"END_ADDR_${itf}"},
                                    $netsettings{"${itf}_NETADDRESS"},
-                                   $netsettings{"${itf}_NETMASK"})) { 
+                                   $netsettings{"${itf}_NETMASK"})) {
                    $errormessage = "DHCP on ${itf}: " . $Lang::tr{'invalid end address'};
                    goto ERROR;
                }
@@ -168,6 +185,13 @@ if ($dhcpsettings{'ACTION'} eq $Lang::tr{'save'}) {
                }
            }
 
+           if ($dhcpsettings{"DENY_KNOWN_CLIENTS_${itf}"} eq 'on') {
+               if (($dhcpsettings{"START_ADDR_${itf}"}) eq '' && ($dhcpsettings{"END_ADDR_${itf}"}) eq '') {
+                       $errormessage = "DHCP on ${itf}: " . $Lang::tr{'dhcp valid range required when deny known clients checked'};
+                       goto ERROR;
+               }
+           }
+
            if (!($dhcpsettings{"DEFAULT_LEASE_TIME_${itf}"} =~ /^\d+$/)) {
                $errormessage = "DHCP on ${itf}: " . $Lang::tr{'invalid default lease time'} . $dhcpsettings{'DEFAULT_LEASE_TIME_${itf}'};
                goto ERROR;
@@ -190,7 +214,7 @@ if ($dhcpsettings{'ACTION'} eq $Lang::tr{'save'}) {
                        goto ERROR;
                }
                if (! $dhcpsettings{"DNS1_${itf}"}) {
-                       $errormessage = "DHCP on ${itf}: " . $Lang::tr{'cannot specify secondary dns without specifying primary'}; 
+                       $errormessage = "DHCP on ${itf}: " . $Lang::tr{'cannot specify secondary dns without specifying primary'};
                        goto ERROR;
                }
            }
@@ -209,7 +233,7 @@ if ($dhcpsettings{'ACTION'} eq $Lang::tr{'save'}) {
                if (! $dhcpsettings{"WINS1_${itf}"} ) {
                        $errormessage = "DHCP on ${itf}: " . $Lang::tr{'cannot specify secondary wins without specifying primary'};
                        goto ERROR;
-               }               
+               }
            }
            if ($dhcpsettings{"NEXT_${itf}"}) {
                if (!(&General::validip($dhcpsettings{"NEXT_${itf}"}))) {
@@ -244,7 +268,7 @@ if ($dhcpsettings{'ACTION'} eq $Lang::tr{'save'}) {
        } # enabled
     }#loop interface verify
 
-    map (delete ($dhcpsettings{$_}) ,@nosaved,'ACTION','KEY1','KEY2'); # Must not be saved 
+    map (delete ($dhcpsettings{$_}) ,@nosaved,'ACTION','KEY1','KEY2','q');     # Must not be saved
     &General::writehash($setting, \%dhcpsettings);             # Save good settings
     $dhcpsettings{'ACTION'} = $Lang::tr{'save'};               # create an 'ACTION'
     map ($dhcpsettings{$_} = '',@nosaved,'KEY1','KEY2');       # and reinit vars to empty
@@ -267,18 +291,18 @@ if ($ENV{'QUERY_STRING'} =~ /^FETHER|^FIPADDR/ ) {
        $newsort.=$Rev;
     }
     $dhcpsettings{'SORT_FLEASELIST'}=$newsort;
-    map (delete ($dhcpsettings{$_}) ,@nosaved,'ACTION','KEY1','KEY2'); # Must never be saved 
+    map (delete ($dhcpsettings{$_}) ,@nosaved,'ACTION','KEY1','KEY2', 'q');    # Must never be saved
     &General::writehash($setting, \%dhcpsettings);
     &sortcurrent2;
     $dhcpsettings{'ACTION'} = 'SORT';                  # create an 'ACTION'
-    map ($dhcpsettings{$_} = '',@nosaved,'KEY1','KEY2');# and reinit vars to empty 
+    map ($dhcpsettings{$_} = '',@nosaved,'KEY1','KEY2');# and reinit vars to empty
 }
 
 #Sorting of allocated leases
 &Header::CheckSortOrder;
 
 
-## Now manipulate the two multi-line list with Settings2. 
+## Now manipulate the two multi-line list with Settings2.
 #  '1' suffix is for ADVANCED OPTIONS
 #  '2' suffix is for FIXED LEASES
 
@@ -295,12 +319,12 @@ if ($dhcpsettings{'ACTION'} eq $Lang::tr{'toggle enable disable'}.'1') {
     open(FILE, ">$filename1") or die 'Unable to open dhcp advanced options file.';
     print FILE @current1;
     close(FILE);
-       
+
     #Write changes to dhcpd.conf.
     &buildconf;
 }
 
-    
+
 
 if ($dhcpsettings{'ACTION'} eq $Lang::tr{'add'}.'1' &&
        $dhcpsettings{'SUBMIT'} ne $Lang::tr{'dhcp advopt help'}) {
@@ -310,7 +334,7 @@ if ($dhcpsettings{'ACTION'} eq $Lang::tr{'add'}.'1' &&
     if ($dhcpsettings{'ADVOPT_DATA'} eq '') {
        $errormessage=$Lang::tr{'dhcp advopt blank value'};
     }
-    
+
     # Test for a new option definition string (join field name & data)
     if (ExistNewOptionDefinition ($dhcpsettings{'ADVOPT_NAME'} . ' ' . $dhcpsettings{'ADVOPT_DATA'})) {
        #only edit permitted if option definition exists
@@ -323,12 +347,12 @@ if ($dhcpsettings{'ACTION'} eq $Lang::tr{'add'}.'1' &&
        map ($dhcpsettings{"ADVOPT_SCOPE_$_"} = 'off', @ITFs);  # force global
     } elsif (ValidNewOption ($dhcpsettings{'ADVOPT_NAME'} . ' ' . $dhcpsettings{'ADVOPT_DATA'})) {
        #was a new option
-    } elsif (! `grep "\$option $dhcpsettings{'ADVOPT_NAME'} " $filename3`) {
+    } elsif (! grep(/option $dhcpsettings{'ADVOPT_NAME'}/, @advoptions_list)) {
        $errormessage=$Lang::tr{'dhcp advopt unknown'}.': '.$dhcpsettings{'ADVOPT_NAME'};
     }
 
     unless ($errormessage) {
-       
+
        my $scope = '';
        foreach my $itf (@ITFs) {  # buils "RED,GREEN,ORANGE,... based on selection
            $scope .= $dhcpsettings{"ADVOPT_SCOPE_${itf}"} eq 'on' ? "\t$itf" : "\toff" ;
@@ -363,7 +387,7 @@ if ($dhcpsettings{'ACTION'} eq $Lang::tr{'edit'}.'1') {
        if ($itf ne 'off') # Only is an interface name is read
        {
            $dhcpsettings{"ADVOPT_SCOPE_${itf}"} = 'on';
-       }    
+       }
     }
 }
 
@@ -392,7 +416,7 @@ if ($dhcpsettings{'ACTION'} eq $Lang::tr{'toggle enable disable'}.'2') {
     open(FILE, ">$filename2") or die 'Unable to open fixed leases file.';
     print FILE @current2;
     close(FILE);
-       
+
     #Write changes to dhcpd.conf.
     &buildconf;
 }
@@ -404,7 +428,7 @@ if ($dhcpsettings{'ACTION'} eq $Lang::tr{'add'}.'2') {
     if ($dhcpsettings{'FIX_NEXTADDR'}) {
         unless(&General::validip($dhcpsettings{'FIX_NEXTADDR'})) { $errormessage = $Lang::tr{'invalid fixed ip address'}; }
     }
-       
+
     my $key = 0;
     CHECK:foreach my $line (@current2) {
         my @temp = split(/\,/,$line);
@@ -414,13 +438,13 @@ if ($dhcpsettings{'ACTION'} eq $Lang::tr{'add'}.'2') {
            # Also it may be needed to put duplicate fixed lease in their right subnet definition..
            foreach my $itf (@ITFs) {
                my $scoped = &General::IpInSubnet($dhcpsettings{'FIX_ADDR'},
-                                                 $netsettings{"${itf}_NETADDRESS"}, 
+                                                 $netsettings{"${itf}_NETADDRESS"},
                                                  $netsettings{"${itf}_NETMASK"}) &&
                                                  $dhcpsettings{"ENABLE_${itf}"} eq 'on';
                if ( $scoped &&
                    (lc($dhcpsettings{'FIX_MAC'}) eq lc($temp[0])) &&
                    &General::IpInSubnet($temp[1],
-                                        $netsettings{"${itf}_NETADDRESS"}, 
+                                        $netsettings{"${itf}_NETADDRESS"},
                                         $netsettings{"${itf}_NETMASK"})) {
                    $errormessage = "$Lang::tr{'mac address in use'} $dhcpsettings{'FIX_MAC'}";
                    last CHECK;
@@ -437,15 +461,23 @@ if ($dhcpsettings{'ACTION'} eq $Lang::tr{'add'}.'2') {
        $dhcpsettings{'FIX_ROOTPATH'} = &Header::cleanhtml($dhcpsettings{'FIX_ROOTPATH'});
        if ($dhcpsettings{'KEY2'} eq '') { #add or edit ?
            unshift (@current2, "$dhcpsettings{'FIX_MAC'},$dhcpsettings{'FIX_ADDR'},$dhcpsettings{'FIX_ENABLED'},$dhcpsettings{'FIX_NEXTADDR'},$dhcpsettings{'FIX_FILENAME'},$dhcpsettings{'FIX_ROOTPATH'},$dhcpsettings{'FIX_REMARK'}\n");
+           open(FILE, ">$filename2") or die 'Unable to open fixed lease file.';
+           print FILE @current2;
+           close(FILE);
            &General::log($Lang::tr{'fixed ip lease added'});
+
+           # Enter edit mode
+           $dhcpsettings{'KEY2'} = 0;
        } else {
            @current2[$dhcpsettings{'KEY2'}] = "$dhcpsettings{'FIX_MAC'},$dhcpsettings{'FIX_ADDR'},$dhcpsettings{'FIX_ENABLED'},$dhcpsettings{'FIX_NEXTADDR'},$dhcpsettings{'FIX_FILENAME'},$dhcpsettings{'FIX_ROOTPATH'},$dhcpsettings{'FIX_REMARK'}\n";
            $dhcpsettings{'KEY2'} = '';       # End edit mode
            &General::log($Lang::tr{'fixed ip lease modified'});
+
+           # sort newly added/modified entry
+           &sortcurrent2;
        }
 
         #Write changes to dhcpd.conf.
-        &sortcurrent2;    # sort newly added/modified entry
         &buildconf;       # before calling buildconf which use fixed lease file !
     }
 }
@@ -512,9 +544,11 @@ if ($dhcpsettings{'ACTION'} eq '' ) { # First launch from GUI
        }
     }
     $dhcpsettings{'FIX_ENABLED'} = 'on';
-}
+    $dhcpsettings{'ADVOPT_ENABLED'} = 'on';
+    }
 
-&Header::openpage($Lang::tr{'dhcp configuration'}, 1, '');
+### START PAGE ###
+&Header::openpage($Lang::tr{'dhcp configuration'}, 1, $Header::extraHead);
 &Header::openbigbox('100%', 'left', '', $errormessage);
 
 if ($errormessage) {
@@ -533,6 +567,7 @@ foreach my $itf (@ITFs) {
     my %checked=();
     $checked{'ENABLE'}{'on'} = ( $dhcpsettings{"ENABLE_${itf}"} ne 'on') ? '' : "checked='checked'";
     $checked{'ENABLEBOOTP'}{'on'} = ( $dhcpsettings{"ENABLEBOOTP_${itf}"} ne 'on') ? '' : "checked='checked'";
+    $checked{'DENY_KNOWN_CLIENTS'}{'on'} = ( $dhcpsettings{"DENY_KNOWN_CLIENTS_${itf}"} ne 'on') ? '' : "checked='checked'";
 
     if ($netsettings{"${itf}_DEV"} ne '' ) { # Show only defined interface
        my $lc_itf=lc($itf);
@@ -544,39 +579,42 @@ print <<END
     <input type='checkbox' name='ENABLE_${itf}' $checked{'ENABLE'}{'on'} /></td>
     <td width='25%' class='base'>$Lang::tr{'ip address'}<br />$Lang::tr{'netmask'}:</td><td><b>$netsettings{"${itf}_ADDRESS"}<br />$netsettings{"${itf}_NETMASK"}</b></td>
 </tr><tr>
-    <td width='25%' class='base'>$Lang::tr{'start address'}</td>
+    <td width='25%' class='base'>$Lang::tr{'start address'}&nbsp;<img src='/blob.gif' alt='*' /></td>
     <td width='25%'><input type='text' name='START_ADDR_${itf}' value='$dhcpsettings{"START_ADDR_${itf}"}' /></td>
-    <td width='25%' class='base'>$Lang::tr{'end address'}</td>
+    <td width='25%' class='base'>$Lang::tr{'end address'}&nbsp;<img src='/blob.gif' alt='*' /></td>
     <td width='25%'><input type='text' name='END_ADDR_${itf}' value='$dhcpsettings{"END_ADDR_${itf}"}' /></td>
 </tr><tr>
-    <td class='base'>$Lang::tr{'default lease time'}</td>
+    <td class='base'>$Lang::tr{'dhcp deny known clients:'}</td>
+    <td><input type='checkbox' name='DENY_KNOWN_CLIENTS_${itf}' $checked{'DENY_KNOWN_CLIENTS'}{'on'} /></td>
+</tr><tr>
+    <td class='base'>$Lang::tr{'default lease time'}&nbsp;<img src='/blob.gif' alt='*' /></td>
     <td><input type='text' name='DEFAULT_LEASE_TIME_${itf}' value='$dhcpsettings{"DEFAULT_LEASE_TIME_${itf}"}' /></td>
-    <td class='base'>$Lang::tr{'max lease time'}</td>
+    <td class='base'>$Lang::tr{'max lease time'}&nbsp;<img src='/blob.gif' alt='*' /></td>
     <td><input type='text' name='MAX_LEASE_TIME_${itf}' value='$dhcpsettings{"MAX_LEASE_TIME_${itf}"}' /></td>
 </tr><tr>
-    <td class='base'>$Lang::tr{'domain name suffix'}&nbsp;<img src='/blob.gif' alt='*' /></td>
+    <td class='base'>$Lang::tr{'domain name suffix'}</td>
     <td><input type='text' name='DOMAIN_NAME_${itf}' value='$dhcpsettings{"DOMAIN_NAME_${itf}"}' /></td>
     <td>$Lang::tr{'dhcp allow bootp'}:</td>
     <td><input type='checkbox' name='ENABLEBOOTP_${itf}' $checked{'ENABLEBOOTP'}{'on'} /></td>
 </tr><tr>
-    <td class='base'>$Lang::tr{'primary dns'}</td>
+    <td class='base'>$Lang::tr{'primary dns'}&nbsp;<img src='/blob.gif' alt='*' /></td>
     <td><input type='text' name='DNS1_${itf}' value='$dhcpsettings{"DNS1_${itf}"}' /></td>
-    <td class='base'>$Lang::tr{'secondary dns'}&nbsp;<img src='/blob.gif' alt='*' /></td>
+    <td class='base'>$Lang::tr{'secondary dns'}</td>
     <td><input type='text' name='DNS2_${itf}' value='$dhcpsettings{"DNS2_${itf}"}' /></td>
 </tr><tr>
-    <td class='base'>$Lang::tr{'primary ntp server'}:&nbsp;<img src='/blob.gif' alt='*' /></td>
+    <td class='base'>$Lang::tr{'primary ntp server'}:</td>
     <td><input type='text' name='NTP1_${itf}' value='$dhcpsettings{"NTP1_${itf}"}' /></td>
-    <td class='base'>$Lang::tr{'secondary ntp server'}:&nbsp;<img src='/blob.gif' alt='*' /></td>
+    <td class='base'>$Lang::tr{'secondary ntp server'}:</td>
     <td><input type='text' name='NTP2_${itf}' value='$dhcpsettings{"NTP2_${itf}"}' /></td>
 </tr><tr>
-    <td class='base'>$Lang::tr{'primary wins server address'}:&nbsp;<img src='/blob.gif' alt='*' /></td>
+    <td class='base'>$Lang::tr{'primary wins server address'}:</td>
     <td><input type='text' name='WINS1_${itf}' value='$dhcpsettings{"WINS1_${itf}"}' /></td>
-    <td class='base'>$Lang::tr{'secondary wins server address'}:&nbsp;<img src='/blob.gif' alt='*' /></td>
+    <td class='base'>$Lang::tr{'secondary wins server address'}:</td>
     <td><input type='text' name='WINS2_${itf}' value='$dhcpsettings{"WINS2_${itf}"}' /></td>
 </tr><tr>
-    <td class='base'>next-server:&nbsp;<img src='/blob.gif' alt='*' /></td>
+    <td class='base'>next-server:</td>
     <td><input type='text' name='NEXT_${itf}' value='$dhcpsettings{"NEXT_${itf}"}' /></td>
-    <td class='base'>filename:&nbsp;<img src='/blob.gif' alt='*' /></td>
+    <td class='base'>filename:</td>
     <td><input type='text' name='FILE_${itf}' value='$dhcpsettings{"FILE_${itf}"}' /></td>
 </tr>
 </table>
@@ -588,11 +626,83 @@ END
 print <<END
 <table width='100%'>
 <tr>
-    <td class='base' width='25%'><img src='/blob.gif' align='top' alt='*' />&nbsp;$Lang::tr{'this field may be blank'}</td>
+    <td class='base' width='25%'><img src='/blob.gif' align='top' alt='*' />&nbsp;$Lang::tr{'required field'}</td>
     <td class='base' width='30%'>$warnNTPmessage</td>
     <td width='40%' align='right'><input type='submit' name='ACTION' value='$Lang::tr{'save'}' /></td>
 </tr>
 </table>
+END
+;
+&Header::closebox();
+
+# DHCP DNS update support (RFC2136)
+&Header::openbox('100%', 'left', $Lang::tr{'dhcp dns update'});
+
+my %checked = ();
+$checked{'DNS_UPDATE_ENABLED'}{'on'} = ( $dhcpsettings{'DNS_UPDATE_ENABLED'} ne 'on') ? '' : "checked='checked'";
+
+print <<END
+<table  width='100%'>
+       <tr>
+               <td width='30%' class='boldbase'>$Lang::tr{'dhcp dns enable update'}</td>
+               <td class='base'><input type='checkbox' name='DNS_UPDATE_ENABLED' $checked{'DNS_UPDATE_ENABLED'}{'on'}>
+               </td>
+       <tr>
+</table>
+
+<table width='100%'>
+END
+;
+       my @domains = ();
+
+       # Print options for each interface.
+       foreach my $itf (@ITFs) {
+               # Check if DHCP for this interface is enabled.
+               if ($dhcpsettings{"ENABLE_${itf}"} eq 'on') {
+                       # Check for same domain name.
+                       next if ($dhcpsettings{"DOMAIN_NAME_${itf}"} ~~ @domains);
+                       my $lc_itf = lc($itf);
+
+                       # Select previously configured update algorithm.
+                       my %selected = ();
+                       $selected{'DNS_UPDATE_ALGO_${inf}'}{$dhcpsettings{'DNS_UPDATE_ALGO_${inf}'}} = 'selected';
+
+print <<END
+       <tr>
+               <td colspan='6'>&nbsp;</td>
+       </tr>
+       <tr>
+               <td colspan='6' class='boldbase'><b>$dhcpsettings{"DOMAIN_NAME_${itf}"}</b></td>
+       </tr>
+       <tr>
+               <td width='10%' class='boldbase'>$Lang::tr{'dhcp dns key name'}:</td>
+               <td width='20%'><input type='text' name='DNS_UPDATE_KEY_NAME_${itf}' value='$dhcpsettings{"DNS_UPDATE_KEY_NAME_${itf}"}'></td>
+               <td width='10%' class='boldbase' align='right'>$Lang::tr{'dhcp dns update secret'}:&nbsp;&nbsp;</td>
+               <td width='20%'><input type='password' name='DNS_UPDATE_KEY_SECRET_${itf}' value='$dhcpsettings{"DNS_UPDATE_KEY_SECRET_${itf}"}'></td>
+               <td width='10%' class='boldbase' align='right'>$Lang::tr{'dhcp dns update algo'}:&nbsp;&nbsp;</td>
+               <td width='20%'>
+                       <select name='DNS_UPDATE_KEY_ALGO_${itf}'>
+                               <!-- <option value='hmac-sha1' $selected{'DNS_UPDATE_KEY_ALGO_${itf}'}{'hmac-sha1'}>HMAC-SHA1</option> -->
+                               <option value='hmac-md5' $selected{'DNS_UPDATE_KEY_ALGO_${itf}'}{'hmac-md5'}>HMAC-MD5</option>
+                       </select>
+               </td>
+       </tr>
+END
+;
+       }
+
+       # Store configured domain based on the interface
+       # in the temporary variable.
+       push(@domains, $dhcpsettings{"DOMAIN_NAME_${itf}"});
+}
+print <<END
+</table>
+<hr>
+<table width='100%'>
+       <tr>
+               <td align='right'><input type='submit' name='ACTION' value='$Lang::tr{'save'}' /></td>
+       </tr>
+</table>
 </form>
 END
 ;
@@ -614,7 +724,20 @@ if ($dhcpsettings{'KEY1'} ne '') {
 }
 
 #search if the 'option' is in the list and print the syntax model
-my $opt = `grep "\$option $dhcpsettings{'ADVOPT_NAME'} " $filename3`;
+my $opt;
+
+# Check if a advanced option name is set.
+if ($dhcpsettings{'ADVOPT_NAME'}) {
+       # Check if the name is part of the list and grab syntax.
+       my @opt = grep(/option $dhcpsettings{'ADVOPT_NAME'}/, @advoptions_list);
+
+       # Assign array element to variable.
+       $opt = @opt[0];
+
+       # Remove newlines.
+       chomp($opt);
+}
+
 if ($opt ne '') {
    $opt =~ s/option $dhcpsettings{'ADVOPT_NAME'}/Syntax:/;  # "option xyz abc" => "syntax: abc"
    $opt =~ s/;//;
@@ -622,21 +745,21 @@ if ($opt ne '') {
 }
 print <<END
 <tr>
-    <td class='base'>$Lang::tr{'dhcp advopt name'}:</td>
+    <td class='base'>$Lang::tr{'dhcp advopt name'}:&nbsp;<img src='/blob.gif' alt='*' /></td>
     <td><input type='text' name='ADVOPT_NAME' value='$dhcpsettings{'ADVOPT_NAME'}' size='18' /></td>
-    <td class='base'>$Lang::tr{'dhcp advopt value'}:</td>
+    <td class='base'>$Lang::tr{'dhcp advopt value'}:&nbsp;<img src='/blob.gif' alt='*' /></td>
     <td><input type='text' name='ADVOPT_DATA' value='$dhcpsettings{'ADVOPT_DATA'}' size='40' /></td>
 </tr>$opt<tr>
     <td class='base'>$Lang::tr{'enabled'}</td><td><input type='checkbox' name='ADVOPT_ENABLED' $checked{'ADVOPT_ENABLED'}{'on'} /></td>
-    <td class='base'>$Lang::tr{'dhcp advopt scope'}:&nbsp;<img src='/blob.gif' alt='*' /></td>
+    <td class='base'>$Lang::tr{'dhcp advopt scope'}:</td>
     <td>
 END
 ;
 
-# Put a checkbox for each interface. Checkbox visible disabled if interface is disabled  
+# Put a checkbox for each interface. Checkbox visible disabled if interface is disabled
 foreach my $itf (@ITFs) {
     my $lc_itf=lc($itf);
-    $checked{'ADVOPT_SCOPE_${itf}'}{'on'} = $dhcpsettings{"ADVOPT_SCOPE_${itf}"} ne 'on' ? '' : "checked='checked'";    
+    $checked{'ADVOPT_SCOPE_${itf}'}{'on'} = $dhcpsettings{"ADVOPT_SCOPE_${itf}"} ne 'on' ? '' : "checked='checked'";
     print "$Lang::tr{\"${lc_itf}\"} <input type='checkbox' name='ADVOPT_SCOPE_${itf}' $checked{'ADVOPT_SCOPE_${itf}'}{'on'} ";
     print $dhcpsettings{"ENABLE_${itf}"} eq 'on' ? "/>" : "disabled='disabled' />";
     print "&nbsp; &nbsp;";
@@ -649,7 +772,7 @@ print <<END
 <hr />
 <table width='100%'>
 <tr>
-    <td class='base' width='50%'><img src='/blob.gif' align='top' alt='*' />&nbsp;$Lang::tr{'dhcp advopt scope help'}</td>
+    <td class='base' width='50%'>$Lang::tr{'dhcp advopt scope help'}</td>
     <td width='50%' align='right'>
     <input type='hidden' name='ACTION' value='$Lang::tr{'add'}1' />
     <input type='submit' name='SUBMIT' value='$buttontext' />
@@ -678,6 +801,7 @@ if ($dhcpsettings{'SUBMIT'} eq $Lang::tr{'dhcp advopt help'}) {
     print "<tr><td colspan='2'><hr /></td></tr>\n";
     print '<tr><td>string type</td><td>"quoted string" or 00:01:FF...</td></tr>';
     print '<tr><td>ip-address type </td><td>10.0.0.1 | www.dot.com</td></tr>';
+    print '<tr><td>domain-list type </td><td>"example.com", "eng.example.com", "sales.example.com"</td></tr>';
     print '<tr><td>int,uint types</td><td>numbers</td></tr>';
     print '<tr><td>flag type</td><td>on | off</td></tr>';
     print '</table>';
@@ -690,7 +814,7 @@ if ($dhcpsettings{'SUBMIT'} eq $Lang::tr{'dhcp advopt help'}) {
     print '<tr><td>wpad</td><td>code 252=text</td></tr>';
     print '<tr><td>wpad</td><td>"http://www.server.fr/path-to/proxy.pac"</td></tr>';
     print '</table>';
+
 }
 
 print <<END
@@ -716,15 +840,15 @@ foreach my $line (@current1) {
        $gdesc = $Lang::tr{'click to disable'};
     } else {
        $gif = 'off.gif';
-       $gdesc = $Lang::tr{'click to enable'}; 
+       $gdesc = $Lang::tr{'click to enable'};
     }
 
     if ($dhcpsettings{'KEY1'} eq $key) {
-       print "<tr bgcolor='${Header::colouryellow}'>";
+       print "<tr class='colouryellow'>";
     } elsif ($key % 2) {
-       print "<tr bgcolor='$color{'color22'}'>";
+       print "<tr class='color22'>";
     } else {
-       print "<tr bgcolor='$color{'color20'}'>"; 
+       print "<tr class='color20'>";
     }
 
     print <<END
@@ -745,8 +869,8 @@ END
     } else {
        $global = $Lang::tr{'dhcp advopt scope global'};
     }
-    
-    
+
+
     # Print each checked interface
     for (my $key=0; $key<@ITFs; $key++) {
        my $itf = $temp[3+$key];
@@ -827,29 +951,29 @@ if ($dhcpsettings{'KEY2'} ne '') {
 }
 print <<END
 <tr>
-    <td class='base'>$Lang::tr{'mac address'}:</td>
+    <td class='base'>$Lang::tr{'mac address'}:&nbsp;<img src='/blob.gif' alt='*' /></td>
     <td><input type='text' name='FIX_MAC' value='$dhcpsettings{'FIX_MAC'}' size='18' /></td>
-    <td class='base'>$Lang::tr{'ip address'}:</td>
+    <td class='base'>$Lang::tr{'ip address'}:&nbsp;<img src='/blob.gif' alt='*' /></td>
     <td><input type='text' name='FIX_ADDR' value='$dhcpsettings{'FIX_ADDR'}' size='18' /></td>
-    <td class='base'>$Lang::tr{'remark'}:&nbsp;<img src='/blob.gif' alt='*' /></td>
+    <td class='base'>$Lang::tr{'remark'}:</td>
     <td><input type='text' name='FIX_REMARK' value='$dhcpsettings{'FIX_REMARK'}' size='18' /></td>
 </tr><tr>
     <td class='base'>$Lang::tr{'enabled'}</td><td><input type='checkbox' name='FIX_ENABLED' $checked{'FIX_ENABLED'}{'on'} /></td>
 </tr><tr>
     <td colspan = '3'><b>$Lang::tr{'dhcp bootp pxe data'}</b></td>
 </tr><tr>
-    <td class='base'>next-server:&nbsp;<img src='/blob.gif' alt='*' /></td>
+    <td class='base'>next-server:</td>
     <td><input type='text' name='FIX_NEXTADDR' value='$dhcpsettings{'FIX_NEXTADDR'}' size='18' /></td>
-    <td class='base'>filename:&nbsp;<img src='/blob.gif' alt='*' /></td>
+    <td class='base'>filename:</td>
     <td><input type='text' name='FIX_FILENAME' value='$dhcpsettings{'FIX_FILENAME'}' size='18' /></td>
-    <td class='base'>root path:&nbsp;<img src='/blob.gif' alt='*' /></td>
+    <td class='base'>root path:</td>
     <td><input type='text' name='FIX_ROOTPATH' value='$dhcpsettings{'FIX_ROOTPATH'}' size='18' /></td>
 </tr>
 </table>
 <hr />
 <table width='100%'>
 <tr>
-    <td class='base' width='50%'><img src='/blob.gif' align='top' alt='*' />&nbsp;$Lang::tr{'this field may be blank'}</td>
+    <td class='base' width='50%'><img src='/blob.gif' align='top' alt='*' />&nbsp;$Lang::tr{'required field'}</td>
     <td width='50%' align='right'>
        <input type='hidden' name='ACTION' value='$Lang::tr{'add'}2' />
        <input type='submit' name='SUBMIT' value='$buttontext' />
@@ -857,7 +981,6 @@ print <<END
 </tr>
 </table>
 </form>
-<hr />
 END
 ;
 #Edited line number (KEY2) passed until cleared by 'save' or 'remove' or 'new sort order'
@@ -898,26 +1021,34 @@ my $ipdup = 0;
 my %ipinuse = ();
 my %macdupl = (); # Duplicate MACs have to be on different subnets
 my %ipoutside = ();
+my %ipinrange = ();
 
-# mark duplicate ip or duplicate MAC
+# mark duplicate IP, duplicate MAC or IP in dynamic range
 foreach my $line (@current2) {
     my @temp = split(/\,/,$line);
     $macdupl{$temp[0]} += 1;
-    if ($macdupl{$temp[0]} > 1) { 
+    if ($macdupl{$temp[0]} > 1) {
        $ipdup = 1;     # Flag up duplicates for use later
     }
     $ipinuse{$temp[1]} += 1;
-    if ($ipinuse{$temp[1]} > 1) { 
+    if ($ipinuse{$temp[1]} > 1) {
        $ipdup = 1;     # Flag up duplicates for use later
     }
-    # Mark IP addresses outwith known subnets
     $ipoutside{$temp[1]} = 1;
+    $ipinrange{$temp[1]} = 0;
     foreach my $itf (@ITFs) {
-        if ( &General::IpInSubnet($temp[1],
-                $netsettings{"${itf}_NETADDRESS"}, 
-                $netsettings{"${itf}_NETMASK"})) {
-            $ipoutside{$temp[1]} = 0;
-        }
+    # Mark IP addresses outwith known subnets
+               if ( &General::IpInSubnet($temp[1],
+                       $netsettings{"${itf}_NETADDRESS"},
+                       $netsettings{"${itf}_NETMASK"})) {
+                  $ipoutside{$temp[1]} = 0;
+               }
+    # Mark IP addresses that overlap with dynamic range
+               if (&Network::ip_address_in_range($temp[1],
+                       $dhcpsettings{"START_ADDR_${itf}"},
+                       $dhcpsettings{"END_ADDR_${itf}"})) {
+                  $ipinrange{$temp[1]} = 1;
+               }        
     }
 }
 
@@ -934,44 +1065,50 @@ foreach my $line (@current2) {
        $gdesc = $Lang::tr{'click to disable'};
     } else {
        $gif = 'off.gif';
-       $gdesc = $Lang::tr{'click to enable'}; 
+       $gdesc = $Lang::tr{'click to enable'};
     }
 
     # Skip all entries that do not match the search query
     if ($search_query ne "") {
-       next if (!grep(/$search_query/, @temp));
+       if (!grep(/$search_query/, @temp)) {
+               $key++;
+               next;
+       }
     }
 
     if ($dhcpsettings{'KEY2'} eq $key) {
        print "<tr>";
-       $col="bgcolor='${Header::colouryellow}'";
+       $col="class='colouryellow'";
     } elsif ($key % 2) {
        print "<tr>";
-       $col="bgcolor='$color{'color20'}'";
+       $col="class='color20'";
     } else {
        print "<tr>";
-       $col="bgcolor='$color{'color22'}'";
+       $col="class='color22'";
     }
     my $TAG0 = '';
     my $TAG1 = '';
     my $TAG2 = '';
     my $TAG3 = '';
     my $TAG4 = '';
-    if ($ipinuse{$temp[1]} > 1) { 
+    if ($ipinuse{$temp[1]} > 1) {
        $TAG0 = '<b>';
        $TAG1 = '</b>';
     }
-    if ($macdupl{$temp[0]} > 1) { 
+    if ($macdupl{$temp[0]} > 1) {
        $TAG2 = '<b>';
        $TAG3 = '</b>';
     }
-    if ($ipoutside{$temp[1]} > 0) { 
-       $TAG4 = "bgcolor='orange'" if ($dhcpsettings{'KEY2'} ne $key);
+    if ($ipoutside{$temp[1]} > 0) {
+       $TAG4 = "class='orange'" if ($dhcpsettings{'KEY2'} ne $key);
+    }
+    if ($ipinrange{$temp[1]} > 0) { 
+       $TAG4 = "class='red'" if ($dhcpsettings{'KEY2'} ne $key);
     }
 
     print <<END
 <td align='center' $col>$TAG2$temp[0]$TAG3</td>
-<td align='center' $col $TAG4>$TAG0$temp[1]$TAG1</td>
+<td align='center' $TAG4 $col>$TAG0$temp[1]$TAG1</td>
 <td align='center' $col>$temp[6]&nbsp;</td>
 <td align='center' $col>$temp[3]&nbsp;</td>
 <td align='center' $col>$temp[4]&nbsp;</td>
@@ -1016,7 +1153,6 @@ print <<END
        <td class='boldbase'>&nbsp;<b>$Lang::tr{'legend'}:&nbsp;</b></td>
        <td><img src='/images/on.gif' alt='$Lang::tr{'click to disable'}' /></td>
        <td class='base'>$Lang::tr{'click to disable'}</td>
-       <td>&nbsp;&nbsp;</td>
        <td><img src='/images/off.gif' alt='$Lang::tr{'click to enable'}' /></td>
        <td class='base'>$Lang::tr{'click to enable'}</td>
        <td>&nbsp;&nbsp;</td>
@@ -1028,8 +1164,10 @@ print <<END
 </tr>
 <tr>
        <td>&nbsp;</td>
-       <td bgcolor='orange'>&nbsp;</td>
-       <td class='base'>$Lang::tr{'ip address outside subnets'}</td>
+       <td class='base orange'>&nbsp;</td>
+       <td class='base'>&nbsp;$Lang::tr{'ip address outside subnets'}&emsp;</td>
+       <td class='base red'>&nbsp;</td>
+       <td class='base'>&nbsp;$Lang::tr{'dhcp fixed ip address in dynamic range'}</td>
        <td>&nbsp;</td>
        <td>&nbsp;</td>
        $dup
@@ -1106,7 +1244,7 @@ sub sortcurrent2
        # use combination of ether & IP as key to allow duplicates in either but not both
        $entries{$record->{FETHER} . $record->{FIPADDR}} = $record; # add this to a hash of hashes
     }
-    
+
     open(FILE, ">$filename2") or die 'Unable to open fixed lease file.';
     foreach my $entry ( sort fixedleasesort keys %entries) {
        print FILE "$entries{$entry}->{FETHER},$entries{$entry}->{FIPADDR},$entries{$entry}->{DATA}\n";
@@ -1119,17 +1257,27 @@ sub sortcurrent2
     close (FILE);
     undef (%entries);  #This array is reused latter. Clear it.
 }
-                                                   
+
 # Build the configuration file mixing  settings, fixed leases and advanced options
 sub buildconf {
     open(FILE, ">/${General::swroot}/dhcp/dhcpd.conf") or die "Unable to write dhcpd.conf file";
     flock(FILE, 2);
 
     # Global settings
-    print FILE "ddns-update-style none;\n";
     print FILE "deny bootp;    #default\n";
     print FILE "authoritative;\n";
-    
+
+    # DNS Update settings
+    if ($dhcpsettings{'DNS_UPDATE_ENABLED'} eq 'on') {
+        print FILE "ddns-updates           on;\n";
+        print FILE "ddns-update-style      interim;\n";
+        print FILE "ddns-ttl               60; # 1 min\n";
+        print FILE "ignore                 client-updates;\n";
+        print FILE "update-static-leases   on;\n";
+    } else {
+        print FILE "ddns-update-style none;\n";
+    }
+
     # Write first new option definition
     foreach my $line (@current1) {
        chomp($line);   # remove newline
@@ -1142,7 +1290,7 @@ sub buildconf {
     foreach my $line (@current1) {
        chomp($line);   # remove newline
        my @temp = split(/\t/,$line);
-       
+
        if ($temp[0] eq 'on' && !ExistNewOptionDefinition ($temp[1] . ' ' . $temp[2])){ # active & !definition
            my $global=1;
            for (my $key=0; $key<@ITFs; $key++) {
@@ -1155,16 +1303,22 @@ sub buildconf {
            if ($global) {
                print FILE "option $temp[1] $temp[2];\n";
            }
-       }# on    
+       }# on
     }# foreach line
+    print FILE "\n";
 
     #Subnet range definition
     foreach my $itf (@ITFs) {
        my $lc_itf=lc($itf);
        if ($dhcpsettings{"ENABLE_${itf}"} eq 'on' ){
-           print FILE "\nsubnet " . $netsettings{"${itf}_NETADDRESS"} . " netmask ". $netsettings{"${itf}_NETMASK"} . " #$itf\n";
+           print FILE "subnet " . $netsettings{"${itf}_NETADDRESS"} . " netmask ". $netsettings{"${itf}_NETMASK"} . " #$itf\n";
            print FILE "{\n";
-           print FILE "\trange " . $dhcpsettings{"START_ADDR_${itf}"} . ' ' . $dhcpsettings{"END_ADDR_${itf}"}.";\n" if ($dhcpsettings{"START_ADDR_${itf}"});
+           if ($dhcpsettings{"START_ADDR_${itf}"}) {
+               print FILE "pool {\n";
+               print FILE "\trange " . $dhcpsettings{"START_ADDR_${itf}"} . ' ' . $dhcpsettings{"END_ADDR_${itf}"}.";\n";
+               print FILE "\tdeny known-clients;\n" if ($dhcpsettings{"DENY_KNOWN_CLIENTS_${itf}"} eq 'on');
+               print FILE "     }\n"; # pool
+           }
            print FILE "\toption subnet-mask "   . $netsettings{"${itf}_NETMASK"} . ";\n";
            print FILE "\toption domain-name \"" . $dhcpsettings{"DOMAIN_NAME_${itf}"} . "\";\n";
            print FILE "\toption routers " . $netsettings{"${itf}_ADDRESS"} . ";\n";
@@ -1178,7 +1332,7 @@ sub buildconf {
            print FILE ", " . $dhcpsettings{"WINS2_${itf}"}                            if ($dhcpsettings{"WINS2_${itf}"});
            print FILE ";\n"                                                           if ($dhcpsettings{"WINS1_${itf}"});
            print FILE "\tnext-server " . $dhcpsettings{"NEXT_${itf}"} . ";\n" if ($dhcpsettings{"NEXT_${itf}"});
-           print FILE "\tfilename \"" . $dhcpsettings{"FILE_${itf}"} . "\";\n" if ($dhcpsettings{"FILE_${itf}"});
+           print FILE "\tfilename \"" . &EscapeFilename($dhcpsettings{"FILE_${itf}"}) . "\";\n" if ($dhcpsettings{"FILE_${itf}"});
            print FILE "\tdefault-lease-time " . ($dhcpsettings{"DEFAULT_LEASE_TIME_${itf}"} * 60). ";\n";
            print FILE "\tmax-lease-time "     . ($dhcpsettings{"MAX_LEASE_TIME_${itf}"} * 60)    . ";\n";
            print FILE "\tallow bootp;\n" if ($dhcpsettings{"ENABLEBOOTP_${itf}"} eq 'on');
@@ -1189,7 +1343,7 @@ sub buildconf {
            foreach my $line (@current1) {
                chomp($line);   # remove newline
                my @temp = split(/\t/,$line);           # Use TAB separator !
-       
+
                if ($temp[0] eq 'on'){
                    for (my $key=0; $key<@ITFs; $key++) {
                        if ($itf eq $temp[3+$key]) # Only is an interface name is read
@@ -1197,11 +1351,22 @@ sub buildconf {
                            print FILE "\toption $temp[1] $temp[2];\n";
                        }
                    }
-               }# on    
+               }# on
            }# foreach line
-           print FILE "} #$itf\n";
+           print FILE "} #$itf\n\n";
+
+           if (($dhcpsettings{"DNS_UPDATE_ENABLED"} eq "on") && ($dhcpsettings{"DNS_UPDATE_KEY_NAME_${itf}"} ne "")) {
+               print FILE "key " . $dhcpsettings{"DNS_UPDATE_KEY_NAME_${itf}"} . " {\n";
+               print FILE "\talgorithm " . $dhcpsettings{"DNS_UPDATE_KEY_ALGO_${itf}"} . ";\n";
+               print FILE "\tsecret \"" . $dhcpsettings{"DNS_UPDATE_KEY_SECRET_${itf}"} . "\";\n";
+               print FILE "};\n\n";
+
+               print FILE "zone " . $dhcpsettings{"DOMAIN_NAME_${itf}"} . ". {\n";
+               print FILE "\tkey " . $dhcpsettings{"DNS_UPDATE_KEY_NAME_${itf}"} . ";\n";
+               print FILE "}\n\n";
+           }
 
-           system ('/usr/bin/touch', "${General::swroot}/dhcp/enable_${lc_itf}");
+           &General::system('/usr/bin/touch', "${General::swroot}/dhcp/enable_${lc_itf}");
            &General::log("DHCP on ${itf}: " . $Lang::tr{'dhcp server enabled'})
        } else {
            unlink "${General::swroot}/dhcp/enable_${lc_itf}";
@@ -1220,7 +1385,7 @@ sub buildconf {
            print FILE "\thardware ethernet $temp[0];\n";
            print FILE "\tfixed-address $temp[1];\n";
            print FILE "\tnext-server $temp[3];\n"          if ($temp[3]);
-           print FILE "\tfilename \"$temp[4]\";\n"         if ($temp[4]);
+           print FILE "\tfilename \"" . &EscapeFilename($temp[4]) . "\";\n" if ($temp[4]);
            print FILE "\toption root-path \"$temp[5]\";\n" if ($temp[5]);
            print FILE "}\n";
            $key++;
@@ -1228,9 +1393,9 @@ sub buildconf {
     }
     print FILE "include \"${General::swroot}/dhcp/dhcpd.conf.local\";\n";
     close FILE;
-    if ( $dhcpsettings{"ENABLE_GREEN"} eq 'on' || $dhcpsettings{"ENABLE_BLUE"} eq 'on' ) {system '/usr/local/bin/dhcpctrl enable >/dev/null 2>&1';}
-    else {system '/usr/local/bin/dhcpctrl disable >/dev/null 2>&1';}
-    system '/usr/local/bin/dhcpctrl restart >/dev/null 2>&1';
+    if ( $dhcpsettings{"ENABLE_GREEN"} eq 'on' || $dhcpsettings{"ENABLE_BLUE"} eq 'on' ) {&General::system('/usr/local/bin/dhcpctrl', 'enable');}
+    else {&General::system('/usr/local/bin/dhcpctrl', 'disable');}
+    &General::system_background('/usr/local/bin/dhcpctrl', 'restart');
 }
 
 #
@@ -1287,3 +1452,12 @@ sub IsUsedNewOptionDefinition {
     }
     return 0;
 }
+
+sub EscapeFilename($) {
+       my $filename = shift;
+
+       # Replace all single / by \/
+       $filename =~ s/\//\\\//g;
+
+       return $filename;
+}