-1

This is the configuration I have, and I'm trying to consolidate this into a single route command that i could paste into a Cisco ASA.

set device "internal"
set dst 13.13.13.13 255.255.255.255
set gateway 172.16.1.1

set device "internal"
set dst 14.14.14.14 255.255.255.255
set gateway 172.16.1.1

set device "internal"
set dst 15.15.15.15 255.255.255.255
set gateway 172.16.1.1

Join it to a single device, then modify it accordingly to end up looking something like this

route internal 13.13.13.13 255.255.255.255 172.161.1.1

then the other 3 lines can go away.

I'd like to do this in Perl since i'm writing other scripts to do other portions of the source configuration

PhobicSTI
  • 1
  • 3
  • I assume its a typo that you want `172.161.1.1` in your output, when the only thing close to that in your input is `172.16.1.1`? – TLP Mar 07 '12 at 23:18
  • You are correct, typo, sorry about that, – PhobicSTI Mar 07 '12 at 23:19
  • Is it your wish to use the first "dst" that appears, i.e. `13.13.13.13`, or do you have some other means of selecting that particular one for your output? – TLP Mar 07 '12 at 23:21
  • Basically, i'm trying to take all 3 lines, and combine them into one line that looks like the desired line above with the route internal. I'm converting a fw with around 100 routes, that are 3 lines a piece – PhobicSTI Mar 07 '12 at 23:39

3 Answers3

0

Assuming that your order is always device,dst,gateway then this works:

use strict;
use warnings;


my @devices=(); #Array to store device strings
my $current_device=""; #String to capture current device.

while(<DATA>)
{
    chomp;
    if(/^set (\w+) (.+)$/)
    {
        if($1 eq "device")
        {
            $current_device="route $2";
            $current_device=~s/"//g;
        }
        elsif($1 eq "dst")
        {
            $current_device.=" $2";
        }
        elsif($1 eq "gateway")
        {
            $current_device.=" $2";
            push @devices,$current_device;
        }
    }
}

print "$_\n" foreach(@devices);




__DATA__
set device "internal"
set dst 13.13.13.13 255.255.255.255
set gateway 172.16.1.1

set device "internal"
set dst 14.14.14.14 255.255.255.255
set gateway 172.16.1.1

set device "internal"
set dst 15.15.15.15 255.255.255.255
set gateway 172.16.1.1

The output is:

route internal 13.13.13.13 255.255.255.255 172.16.1.1
route internal 14.14.14.14 255.255.255.255 172.16.1.1
route internal 15.15.15.15 255.255.255.255 172.16.1.1
  • This works Awesome, How would i hack this about a inch or so, to have the input be a source file, and the output be a destination file. – PhobicSTI Mar 07 '12 at 23:51
  • You can either a) [`open`](http://perldoc.perl.org/functions/open.html) filehandles from the source file and to the output file, reading from the former and writing to the latter, or b) have the script read from `STDIN` and redirect from the command line, eg `perl my_script.pl < input_file > output_file`. –  Mar 08 '12 at 00:08
  • I tried to muck with the file handles like i did below, and was reading up on the whole bareword filehands bashes $_. I'm not having luck getting it to work from a file. but i'll keep mucking with it. I am still learning the proper method of use for strict and file handles accordingly. – PhobicSTI Mar 08 '12 at 05:07
0

If your configuration file consists of "paragraphs" (stanzas) separated by blank lines as your input suggests, you might do:

#!/usr/bin/env perl
use strict;
use warnings;
local $/ = ""; #...paragraph mode...
while (<>) {
    chomp;
    m{^set.+"internal".+dst\s*([\d\.\s]+$).+gateway\s*(.+)$}ms and
        print "route internal $1 $2\n";
}
JRFerguson
  • 7,426
  • 2
  • 32
  • 36
  • didn't seem to work for me. I added this `open SRCFILE, "<", $ARGV[0] or die $!; open DSTFILE, ">", $ARGV[1] or die $!;` – PhobicSTI Mar 07 '12 at 23:42
  • @PhobicSTI - FYI, [bareword filehandles are bad](http://stackoverflow.com/questions/1479741/why-is-three-argument-open-calls-with-lexical-filehandles-a-perl-best-practice). –  Mar 08 '12 at 00:25
  • @PhobicSTI - No need for an explicit `open` as every command line argument is assumed to be a file name. As I said, this assumes your configuration file consists of paragraphs separated by empty or whitespace-only lines. – JRFerguson Mar 08 '12 at 13:07
0

Quick hack. This will read in a set of values (separated by two consecutive newlines), put it in a hash, then push that hash onto an array. Using input record separator $/ to read records. Setting $/ to "" the empty string is somewhat like setting it to "\n\n", read more in the documentation linked above.

Not quite sure what you need here. If its just one line merged, simply store the hash without pushing it to an array. It will "remember" the first record.

use strict;
use warnings;

$/ = "";   # paragraph mode
my @sets;
while (<DATA>) {
    my %set;
    chomp;               # this actually removes "\n\n" -- the value of $/
    for (split /\n/) {   # split each record into lines
        my ($set,$what,$value) = split ' ', $_, 3;  # max 3 fields
        $set{$what} //= $value;        # //= means do not overwrite
    }
    $set{device} =~ s/^"|"$//g;        # remove quotes
    push @sets, \%set;
}

for my $set (@sets) {  # each $set is a hash ref
    my $string = join " ", "route", 
        @{$set}{"device","dst","gateway"};  # using hash slice
    print "$string\n";
}

__DATA__
set device "internal"
set dst 13.13.13.13 255.255.255.255
set gateway 172.16.1.1

set device "internal"
set dst 14.14.14.14 255.255.255.255
set gateway 172.16.1.1

set device "internal"
set dst 15.15.15.15 255.255.255.255
set gateway 172.16.1.1

Output:

route internal 13.13.13.13 255.255.255.255 172.16.1.1
route internal 14.14.14.14 255.255.255.255 172.16.1.1
route internal 15.15.15.15 255.255.255.255 172.16.1.1
TLP
  • 66,756
  • 10
  • 92
  • 149