Solved

re-work an ISC DHCPD.CONF file

Posted on 2011-02-22
27
576 Views
Last Modified: 2012-05-11
Hello,

I am look for some help in creating a way to convert an ISC DHCPD.conf file.

The issue is, where I want to convert there ISC DHCP does not support the word group or failover peer.

I am looking for a way via shell or perl to convert this master file ( attached ) to something like so:

Converted from this master entry from dhcpd.scopes

#
# 10.3.0.0/16 Remote Branch Office Networks.
#
group {
    option domain-name "fs.foo.edu";
 
  subnet 10.3.1.0 netmask 255.255.255.0 {
    option routers 10.3.1.1;
    pool {
      failover peer "dhcp.foo.edu";
      deny dynamic bootp clients;
      range 10.3.1.50 10.3.1.254;
    }
  }
 
  subnet 10.3.2.0 netmask 255.255.255.0 {
    option routers 10.3.2.1;
    pool {
      failover peer "dhcp.foo.edu";
      deny dynamic bootp clients;
      range 10.3.2.50 10.3.2.254;
    }
  }
 
  subnet 10.3.3.0 netmask 255.255.255.0 {
    option routers 10.3.3.1;
    pool {
      failover peer "dhcp.foo.edu";
      deny dynamic bootp clients;
      range 10.3.3.50 10.3.3.254;
    }
  }
}


To this

#
# 10.3.0.0/16 Remote Branch Office Networks.
#
 
 
  subnet 10.3.1.0 netmask 255.255.255.0 {
    option routers 10.3.1.1;
    pool {
      option domain-name "fs.foo.edu";
      deny dynamic bootp clients;
      range 10.3.1.50 10.3.1.254;
    }
  }
 
  subnet 10.3.2.0 netmask 255.255.255.0 {
    option routers 10.3.2.1;
    pool {
      option domain-name "fs.foo.edu";
      deny dynamic bootp clients;
      range 10.3.2.50 10.3.2.254;
    }
  }
 
  subnet 10.3.3.0 netmask 255.255.255.0 {
    option routers 10.3.3.1;
    pool {
      option domain-name "fs.foo.edu";
      deny dynamic bootp clients;
      range 10.3.3.50 10.3.3.254;
    }
  }

Thanks for your help in advance

 dhcpd.scopes.txt
0
Comment
Question by:richsark
  • 10
  • 8
  • 7
27 Comments
 
LVL 8

Expert Comment

by:point_pleasant
ID: 34961142
thisw should do it for the file format you gave,  let me know if you need leading white space stripped

Mike

open FILE, $ARGV[0] or die "can't open $ARGV[0]";
open TMP_FILE, ">/tmp/dhcp_tmp" or die $!;
while ($record = <FILE> )
{
        next if ($record =~ /^group .*\{/ || $record =~ /^}$/ || $record =~ /^.*option domain/);
        print TMP_FILE $record;
}
close(TMP_FILE);
$in_subnet = 0;
open TMP_FILE, "</tmp/dhcp_tmp" or die $!;
while ($record = <TMP_FILE> )
{
        if ($record =~ /^subnet/) {
                $in_subnet = 1;
                print $record;
        } elsif ($record =~ /\}/ && $in_subnet == 1) {
                print "  }\n}";
                $in_subnet = 0;
        } else {
                print $record;
        }
}
close(TMP_FILE);

0
 
LVL 1

Author Comment

by:richsark
ID: 34961890
Hi,
Thanks, will try it now.  Do I need to put the name of the file to open. $record

Do I need to reference perl ?
0
 
LVL 8

Expert Comment

by:point_pleasant
ID: 34961961
execute file by typing

perl filename.pl file_to_open

the file name is given on the command line.  I assumed you might want to use this on more that one file


Mike
0
 
LVL 5

Expert Comment

by:group0
ID: 34963790
The script provided by point_pleasant does not work according to the problem description, it simply drops the group blocks and any directive beginning with "option domain", and the failover directives are not omitted.

Can you please confirm that the option domain-name for each group should be pushed into the subnets they currently enclose?
0
 
LVL 8

Expert Comment

by:point_pleasant
ID: 34963836
you are right 34963790 missed that part
0
 
LVL 1

Author Comment

by:richsark
ID: 34964101
Yes the domain name needs to be passed based on where it was on the master

I will standby for a new code to test

Thanks for catching that
0
 
LVL 5

Expert Comment

by:group0
ID: 34964522
Here's my first run at this, it looks like it should meet the requirements for this example config.  If you're going to run this on other config files, please note that no attempt is made to determine if a pool belonging to a group has an existing option domain-name, so if one is present, a duplicate directive will occur in the resulting output, possibly causing dhcpd to fail to start.  No attempt to reformat the overall indentation level is made when stripping a group block.

The output will just comment out any lines to be dropped for easier auditing of the change.  If you wish to suppress this, just remove any lines matching in the script:
print "#$_";

use strict;

my $block_level = 0;
my $in_group_scope = 0;
my $group_scope_block_level = 0;
my $group_option_domain;
while (<>) {
        next if (/^\s*failover peer/);
        if (/^\s*group\s*{/) {
                $in_group_scope = 1;
                $group_scope_block_level = $block_level;
                $block_level++;
                print "#$_";
                next;
        }
        if ($in_group_scope && /(option\s+domain-name\s+".*";)/) {
                $group_option_domain = $1;
                print "#$_";
                next;
        }
        if (/{\s*$/) {
                $block_level++;
        } elsif (/^\s*}/) {
                $block_level--;
                if ($in_group_scope && $group_scope_block_level == $block_level) {
                        $in_group_scope = 0;
                        $group_scope_block_level = 0;
                        $group_option_domain = '';
                        print "#$_";
                        next;
                }
        }
        print $_;
        if ($in_group_scope && /pool/) {
                print "  " x $block_level . $group_option_domain . "\n";
        }
}

Open in new window


Usage:

perl script.pl < input_file > output_file
0
 
LVL 8

Expert Comment

by:point_pleasant
ID: 34964603
here is the corrected code

open FILE, $ARGV[0] or die "can't open $ARGV[0]";
open TMP_FILE, ">/tmp/dhcp_tmp" or die $!;
$in_group = 0;
$bracket_count = 0;
while ($record = <FILE> )
{
        if ($record =~ /^group .*\{/ ) {
                $in_group = 1;
        }
        elsif ($record =~ /^.*option domain/) {
                $option_domain = $record;
        }
        elsif ($record =~ /^.*pool /) {
                print TMP_FILE $record;
                print TMP_FILE "  $option_domain";
        }
        elsif ($record =~ /\}$/) {
                $bracket_count = $bracket_count + 1;
                if ( $bracket_count == 3 )
                {
                        $bracket_count = 0;
                        $in_group = 0;
                } else {
                        print TMP_FILE $record;
                }
        }
        elsif ($record =~ /subnet/)
        {
                $bracket_count = 0;
                print TMP_FILE $record;
        }
        else {
                print TMP_FILE $record;
        }

}
close(TMP_FILE);
0
 
LVL 8

Expert Comment

by:point_pleasant
ID: 34964638
sorry typo

open FILE, $ARGV[0] or die "can't open $ARGV[0]";
open TMP_FILE, ">/tmp/dhcp_tmp" or die $!;
$in_group = 0;
$bracket_count = 0;
while ($record = <FILE> )
{
        next if ($record =~ /failover peer/);
        if ($record =~ /^group .*\{/ ) {
                $in_group = 1;
        }
        elsif ($record =~ /^.*option domain/) {
                $option_domain = $record;
        }
        elsif ($record =~ /^.*pool /) {
                print TMP_FILE $record;
                print TMP_FILE "  $option_domain";
        }
        elsif ($record =~ /\}$/) {
                $bracket_count = $bracket_count + 1;
                if ( $bracket_count == 3 )
                {
                        $bracket_count = 0;
                        $in_group = 0;
                } else {
                        print TMP_FILE $record;
                }
        }
        elsif ($record =~ /subnet/)
        {
                $bracket_count = 0;
                print TMP_FILE $record;
        }
        else {
                print TMP_FILE $record;
        }

}
close(TMP_FILE);
0
 
LVL 1

Author Comment

by:richsark
ID: 34964932
Thanks point pleasent !

So I would enter my file name here in this variable
while ($record = dhcp.scopes.txt )

Then create perl file named reformat.pl
and ./reformat.pl

Is that right?
0
 
LVL 5

Expert Comment

by:group0
ID: 34965560
@point_pleasant, your new version is still not correct, you're unilaterally using the last option domain-name for any pool that you see, including the non-grouped subnet scopes.  This means that standalone subnets will have their option moved from subnet scope into the pool scope (probably ok, but not documented in the requirements), and those that don't currently have a domain-name specified will inherit from previous scopes (definitely not right).

Please see my previous comment for a script that handles all the cases properly.
0
 
LVL 1

Author Comment

by:richsark
ID: 34966997
Hi, Group0,

I need a way to handle ones that dont have a domain name. What is the best way?
0
6 Surprising Benefits of Threat Intelligence

All sorts of threat intelligence is available on the web. Intelligence you can learn from, and use to anticipate and prepare for future attacks.

 
LVL 5

Expert Comment

by:group0
ID: 34967118
Could you clarify?

You don't want to modify the non-grouped scopes that don't have a domain-name currently?  The script already handles that.

If you need to add a default domain-name for any scopes that are missing one, let me know what you want to insert and where (inside scope block or inside pool block)
0
 
LVL 1

Author Comment

by:richsark
ID: 34967131
ok, I will check and let you know in the morning

Thanks !
0
 
LVL 8

Expert Comment

by:point_pleasant
ID: 34970126
please clarify if you can.  Group0 the following code produces the same out put except for the commented outed lines which a simple diff would show.

open FILE, $ARGV[0] or die "can't open $ARGV[0]";
$in_group = 0;
$bracket_count = 0;
$in_subnet = 0;
while ($record = <FILE> )
{
        next if ($record =~ /failover peer/);
        if ($record =~ /^subnet/){$in_subnet = 1;}
        if ($record =~ /^group .*\{/ ) {
                $in_group = 1;
        }
        elsif ($record =~ /^.*option domain/) {
                $option_domain = $record;
                if ($in_subnet) { print $record;}
        }
        elsif ($record =~ /^.*pool /) {
                if ($in_group == 1) {
                        print $record;
                        print "  $option_domain";
                } else {
                        print $record;
                }
        }
        elsif ($record =~ /\}$/) {
                $bracket_count = $bracket_count + 1;
                if ( $bracket_count == 3 )
                {
                        $bracket_count = 0;
                        $in_group = 0;
                } else {
                        print $record;
                }
        }
        elsif ($record =~ /subnet/)
        {
                $bracket_count = 0;
                print $record;
        }
        else {
                print $record;
        }

}

0
 
LVL 5

Expert Comment

by:group0
ID: 34972481
@point_pleasant, are you asking me to clarify comment 34965560, or are you asking the author for something?
0
 
LVL 8

Expert Comment

by:point_pleasant
ID: 34972997
asking the author to clarify as you had previously asked about the non-grouped sections that don't have a domain name
0
 
LVL 1

Author Comment

by:richsark
ID: 34974802
Hi, I don't need any domains that are not present on the master file.

So if I may ask. Which code should I run?

I see many reversions.  May I get the final code below please ?
0
 
LVL 5

Accepted Solution

by:
group0 earned 250 total points
ID: 34975389
The one I originally posted is the first one to complete all the objectives correctly.  Reposting below.

Usage: perl script.pl < dhcpd.scopes.txt > dhcpd.scopes.new

use strict;

my $block_level = 0;
my $in_group_scope = 0;
my $group_scope_block_level = 0;
my $group_option_domain;
while (<>) {
        next if (/^\s*failover peer/);
        if (/^\s*group\s*{/) {
                $in_group_scope = 1;
                $group_scope_block_level = $block_level;
                $block_level++;
                print "#$_";
                next;
        }
        if ($in_group_scope && /(option\s+domain-name\s+".*";)/) {
                $group_option_domain = $1;
                print "#$_";
                next;
        }
        if (/{\s*$/) {
                $block_level++;
        } elsif (/^\s*}/) {
                $block_level--;
                if ($in_group_scope && $group_scope_block_level == $block_level) {
                        $in_group_scope = 0;
                        $group_scope_block_level = 0;
                        $group_option_domain = '';
                        print "#$_";
                        next;
                }
        }
        print $_;
        if ($in_group_scope && /pool/) {
                print "  " x $block_level . $group_option_domain . "\n";
        }
}

Open in new window

0
 
LVL 1

Author Comment

by:richsark
ID: 34976109
Great.  Thanks for the recap.

Will run it in morning.
0
 
LVL 8

Assisted Solution

by:point_pleasant
point_pleasant earned 250 total points
ID: 34976192
This code works as well you can split the points.  There are many ways to skin a cat

open FILE, $ARGV[0] or die "can't open $ARGV[0]";
$in_group = 0;
$bracket_count = 0;
$in_subnet = 0;
while ($record = <FILE> )
{
        next if ($record =~ /failover peer/);
        if ($record =~ /^subnet/){$in_subnet = 1;}
        if ($record =~ /^group .*\{/ ) {
                $in_group = 1;
        }
        elsif ($record =~ /^.*option domain/) {
                $option_domain = $record;
                if ($in_subnet) { print $record;}
        }
        elsif ($record =~ /^.*pool /) {
                if ($in_group == 1) {
                        print $record;
                        print "  $option_domain";
                } else {
                        print $record;
                }
        }
        elsif ($record =~ /\}$/) {
                $bracket_count = $bracket_count + 1;
                if ( $bracket_count == 3 )
                {
                        $bracket_count = 0;
                        $in_group = 0;
                } else {
                        print $record;
                }
        }
        elsif ($record =~ /subnet/)
        {
                $bracket_count = 0;
                print $record;
        }
        else {
                print $record;
        }

}

0
 
LVL 8

Expert Comment

by:point_pleasant
ID: 34976238
the original question did not ask for deleted lines to be commented out, and for 'auditing' purposes the commented out lines do no good with the added lines.  a simple diff of the orig and final will suffice
0
 
LVL 1

Author Comment

by:richsark
ID: 35083336
Hi, I am truly sorry group0.

I made a mistake when accepting the solution.

Both your solutions worked. I would like to split the 500 between both of you if you find that acceptable.

Again.  Sorry for this as I know you both provided me with an excellent solutions and very timely.


I hope no hard feelings.
0
 
LVL 8

Expert Comment

by:point_pleasant
ID: 35083485
I agree
0
 
LVL 5

Expert Comment

by:group0
ID: 35085019
That'll be fine, thank you.
0

Featured Post

How to run any project with ease

Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
- Combine task lists, docs, spreadsheets, and chat in one
- View and edit from mobile/offline
- Cut down on emails

Join & Write a Comment

I've just discovered very important differences between Windows an Unix formats in Perl,at least 5.xx.. MOST IMPORTANT: Use Unix file format while saving Your script. otherwise it will have ^M s or smth likely weird in the EOL, Then DO NOT use m…
Checking the Alert Log in AWS RDS Oracle can be a pain through their user interface.  I made a script to download the Alert Log, look for errors, and email me the trace files.  In this article I'll describe what I did and share my script.
Learn several ways to interact with files and get file information from the bash shell. ls lists the contents of a directory: Using the -a flag displays hidden files: Using the -l flag formats the output in a long list: The file command gives us mor…
Explain concepts important to validation of email addresses with regular expressions. Applies to most languages/tools that uses regular expressions. Consider email address RFCs: Look at HTML5 form input element (with type=email) regex pattern: T…

760 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

19 Experts available now in Live!

Get 1:1 Help Now