Improve company productivity with a Business Account.Sign Up

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 598
  • Last Modified:

re-work an ISC DHCPD.CONF file

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
richsark
Asked:
richsark
  • 10
  • 8
  • 7
2 Solutions
 
point_pleasantCommented:
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
 
richsarkAuthor Commented:
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
 
point_pleasantCommented:
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
Upgrade your Question Security!

Your question, your audience. Choose who sees your identity—and your question—with question security.

 
group0Commented:
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
 
point_pleasantCommented:
you are right 34963790 missed that part
0
 
richsarkAuthor Commented:
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
 
group0Commented:
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
 
point_pleasantCommented:
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
 
point_pleasantCommented:
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
 
richsarkAuthor Commented:
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
 
group0Commented:
@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
 
richsarkAuthor Commented:
Hi, Group0,

I need a way to handle ones that dont have a domain name. What is the best way?
0
 
group0Commented:
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
 
richsarkAuthor Commented:
ok, I will check and let you know in the morning

Thanks !
0
 
point_pleasantCommented:
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
 
group0Commented:
@point_pleasant, are you asking me to clarify comment 34965560, or are you asking the author for something?
0
 
point_pleasantCommented:
asking the author to clarify as you had previously asked about the non-grouped sections that don't have a domain name
0
 
richsarkAuthor Commented:
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
 
group0Commented:
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
 
richsarkAuthor Commented:
Great.  Thanks for the recap.

Will run it in morning.
0
 
point_pleasantCommented:
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
 
point_pleasantCommented:
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
 
richsarkAuthor Commented:
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
 
point_pleasantCommented:
I agree
0
 
group0Commented:
That'll be fine, thank you.
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

Join & Write a Comment

Featured Post

Get your problem seen by more experts

Be seen. Boost your question’s priority for more expert views and faster solutions

  • 10
  • 8
  • 7
Tackle projects and never again get stuck behind a technical roadblock.
Join Now