unexpected EOF while looking for matching `' ' - regex

#!/usr/bin/perl
use warnings;
while(1){
system ( "dialog --menu Customize 30 80 60 "
. "'Show rules' 'Show all the current rules' "
. "'Flush rules' 'Flush all the tables' "
. "Allow IP' 'Block all except one IP' "
. "'Block IP' 'Block all the packets from an IP' "
. "'Block MAC' 'Block using the hardware address' "
. "'Private networking' 'Allow only one network and block other networks' "
. "'Allow lo' 'Allow local network interface' "
. "'Save' 'Save customized rules' "
. "'Exit' 'Close the program' "
. "'more options' '........' 2> /tmp/customize.txt");
open FILE4, "/tmp/customize.txt" or die $!;
chomp(my $customize = <FILE4>);
#SHOW RULES
if($customize =~ /Show rules/){
`iptables -nvL | tee /tmp/nvl.txt`;
system ("dialog --textbox /tmp/nvl.txt 22 70");
}
#FLUSH RULES
elsif($customize =~ /Flush rules/){
`iptables -F`;
system ("dialog --infobox 'All tables have been flushed.' 05 35");
sleep 2;
}
#ALLOW IP
elsif($customize =~ /Allow IP/){
system ("dialog --inputbox 'Enter the IP address of the sysetm which you want to allow:' 15 40 2> /tmp/allowIP.txt");
open FILE7, "/tmp/allowIP.txt" or die $!;
chomp(my $aip = <FILE7>);
`iptables -I INPUT -s $aip -j DROP`;
system ("dialog --infobox 'IP address $aip is allowed and rest are blocked' 05 45");
sleep 2;
}
#BLOCK IP
elsif($customize =~ /Block IP/){
system ("dialog --inputbox 'Enter the IP address of the system which you want to block:' 15 40 2> /tmp/blockIP.txt");
open FILE5, "/tmp/blockIP.txt" or die $!;
chomp(my $ip = <FILE5>);
`iptables -A INPUT -s $ip -j DROP`;
system ("dialog --infobox 'IP address $ip has been blocked!' 05 35");
sleep 2;
}
#PRIVATE NETWORK
elsif($customize =~ /Private networking/){
system ("dialog --inputbox 'Enter the network address which you want to allow (eg. 192.168.0.0/24)' 15 40 2> /tmp/network.txt");
open FILE6, "/tmp/network.txt" or die $!;
chomp(my $network = <FILE6>);
`iptables -I INPUT -s $network -j ACCEPT`;
system ("dialog --infobox 'Network $network is allowed and rest networks are blocked' 05 35");
sleep 2;
}
#ALLOW LO
elsif($customize =~ /Allow lo/){
`iptables -I INPUT -i lo -j ACCEPT`;
system ("dialog --infobox 'Local interface is allowed.' 05 35");
sleep 2;
}
#SAVE
elsif($customize =~ /Save/){
`service iptables save`;
system ("dialog --infobox 'All rules have been saved successfully' 05 45");
sleep 2;
}
#EXIT
elsif($customize =~ /Exit/){
system ("dialog --infobox 'Closing application.' 05 35");
sleep 2;
exit 0;
}
else{
exit;
}
}
perl file.plx
error:
sh: -c: line 0: unexpected EOF while looking for matching `''
sh: -c: line 1: syntax error: unexpected end of file
How do I resolve this error?

Missing ' here: "Allow IP'

Your forgot a ' in
. "Allow IP' 'Block all except one IP' "
before Allow IP' in line 7 of your Perl code.

Related

Read a file untill a string in matched

My input file contains:
Startoffile
Host status
Server1
Server2
Server3
Pending Device
Device1
Device2
..
Devic100
Endoffile
How to write a simple PowerShell script which will read the files until the line "Pending Device"?
without knowing much about your desired action, try this:
$file = Get-Content "C:\Users\user\Downloads\file.txt"
foreach ($line in $file) {
if ($line -match "Pending Device") {
Write-Host "Reached 'Pending Device'" -ForegroundColor Red
}
else {
Write-Host "No 'Pending Device' yet"
}
}

perl loop avoid print duplicate in regex match

I Search, and research for a solution but without successful.
The file.txt:
Name Server: NS1.SERVER.COM
Name Server: NS2.SERVER.COM
..........................
..........................
Name Server: NS1.SERVER.COM
Name Server: NS2.SERVER.COM
Whois server: whois.directnic.com!
..........................
..........................
Name Server: NS1.SERVER.COM
Name Server: NS2.SERVER.COM
Whois server: whois.directnic.com!
..........................
..........................
When I run:
use strict;
use warnings;
my $filename = 'file.txt';
open(my $fh, '<:encoding(UTF-8)', $filename)
or die "Could not open file '$filename' $!";
while (my $row = <$fh>) {
if ($row =~ /^Name\sServer:\s+(.*+)?/) {
print "dns $1\n";
}
if ($row =~ /Whois.+server:.(.*)/) {
print "whois server: $1\n";
}
}
The output:
dns NS1.SERVER.COM
dns NS2.SERVER.COM
dns NS1.SERVER.COM
dns NS2.SERVER.COM
whois server: whois.directnic.com!
dns NS1.SERVER.COM
dns NS2.SERVER.COM
whois server: whois.directnic.com!
I want to get like this:
dns NS1.SERVER.COM
dns NS2.SERVER.COM
whois server: whois.directnic.com!
I know I can use Last
(If you’ve used the “break” operator in C or a similar language, it’s like that.)
If I set last; in the first condition I get this:
dns NS1.SERVER.COM
If I set last; in the second condition I get this:
dns NS1.SERVER.COM
dns NS2.SERVER.COM
dns NS1.SERVER.COM
dns NS2.SERVER.COM
whois server: whois.directnic.com!
I find a solution but using hash, while, increase count and grep, like this:
my %count_of;
my %count_of_two;
while (my $row = <$fh>) {
if ($row =~ /^Name\sServer:\s+(.*+)?$/) {
$count_of{$row}++;
}
if ($row =~ /Whois.+Server:.(.*)/) {
$count_of_two{$row}++;
}
}
print join "\n", grep { $count_of{$_} > 1 } keys %count_of;
print join "\n", grep { $count_of_two{$_} == 1 } keys %count_of_two;
¿How can I do this with while or foreach?
Note: I think I know why while loop print duplicate because that the functionality, but maybe exist another way.
I research about this but I can't find a solution.
Thanks for your patience.
The easiest approach is probably to use a hash (called %seen in my example below) which keeps track of the strings you have ever seen.
Making the smallest changes to your code, we get:
use strict;
use warnings;
my $filename = 'file.txt';
open(my $fh, '<:encoding(UTF-8)', $filename)
or die "Could not open file '$filename' $!";
my %seen;
while (my $row = <$fh>) {
if ($row =~ /^Name\sServer:\s+(.*+)?/) {
print "dns $1\n" unless $seen{$1}++;
}
if ($row =~ /Whois.+server:.(.*)/) {
print "whois server: $1\n" unless $seen{$1}++;
}
}

How can I calculate time different from file in perl

this is my first post so please bear with me, I want to calculate the time different from ssh log file which have format like this
Jan 10 hr:min:sec Failed password for invalid user root from "ip" port xxx ssh2
Jan 10 hr:min:sec sshd[]: User root from "ip" not allowed because none of user's groups are listed in AllowGroups
The script will alert when user fail to login x times within 10 minutes, any can please teach me how to do this?
Thanks!!
Your specification is a little ambiguous - presumably there are going to be more than two lines in your log file - do you want the time difference between successive lines? Do you want a line parsed searching for a keyword (such as "failed login") and then the time difference to a different line similarly parsed?
Since I can't tell from what you've provided, I'm simply going to presume that there are two lines in a file which have a date at the start of each line and you want the time difference between those dates. You can then manipulate to do what you want. Alternatively, add to your question and define exactly what a "failed login" is.
There are many ways to skin this cat but I prefer the strptime function from DateTime::Format::Strptime which is described as;
This module implements most of strptime(3), the POSIX function that is the reverse of strftime(3), for DateTime. While strftime takes a DateTime and a pattern and returns a string, strptime takes a string and a pattern and returns the DateTime object associated.
This will do as I've described above;
use v5.12;
use DateTime::Format::Strptime;
my $logfile = "ssh.log";
open(my $fh, '<', $logfile) or die "$logfile: $!";
my $strp = DateTime::Format::Strptime->new(
pattern => '%h %d %T ',
time_zone => 'local',
on_error => 'croak',
);
my $dt1 = $strp->parse_datetime(scalar <$fh>);
my $dt2 = $strp->parse_datetime(scalar <$fh>);
my $duration = $dt2->subtract_datetime_absolute($dt1);
say "Number of seconds difference is: ", $duration->seconds ;
#
# Input
# Jan 10 14:03:18 Failed password for invalid user root from "ip" port xxx ssh2
# Jan 10 14:03:22 sshd[]: User root from "ip" not allowed because none of user's groups are listed in AllowGroups
#
# Outputs:
# Number of seconds difference is: 4
A more comprehensive answer (making even more assumptions) is below:
use v5.12;
use DateTime::Format::Strptime;
use DateTime::Duration;
my $logfile = "ssh.log";
my $maximum_failures_allowed = 3 ;
my $minimum_time_frame = 10 * 60; # in seconds
my $limit = $maximum_failures_allowed - 1 ;
# The following is a list of rules indicating a
# failed login for the username captured in $1
my #rules = (
qr/Failed password for user (\S+) / ,
qr/User (\S+) from [\d\.]+ not allowed/
);
my $strp = DateTime::Format::Strptime->new(
pattern => '%h %d %T ',
time_zone => 'local',
on_error => 'croak',
);
my %usernames ;
open(my $fh, '<', $logfile) or die "$logfile: $!";
while (<$fh>) {
for my $rx (#rules) {
if ( /$rx/ ) {
# rule matched -> login fail for $1. Save log line.
my $user = $1 ;
push #{ $usernames{$user} } , $_ ;
# No point checking other rules...
last ;
}
}
}
close $fh ;
for my $user (keys %usernames) {
my #failed_logins = #{ $usernames{$user} };
# prime the loop; we know there is at least one failed login
my $this_line = shift #failed_logins ;
while ( #failed_logins > $limit ) {
my $other_line = $failed_logins[ $limit ] ;
my $this_time = $strp->parse_datetime($this_line) ;
my $other_time = $strp->parse_datetime($other_line) ;
# this produces a DateTime::Duration object with the difference in seconds
my $time_frame = $other_time->subtract_datetime_absolute( $this_time );
if ($time_frame->seconds < $minimum_time_frame) {
say "User $user had login failures at the following times:" ;
print " $_" for $this_line, #failed_logins[ 0 .. $limit ] ;
# (s)he may have more failures but let's not labour the point
last ;
}
# Here if user had too many failures but within a reasonable time frame
# Continue to move through the array of failures checking time frames
$this_line = shift #failed_logins ;
}
}
exit 0;
Ran on this data;
Jan 10 14:03:18 sshd[15798]: Failed password for user root from "ip" port xxx ssh2
Jan 10 14:03:22 sshd[15798]: User root from 188.124.3.41 not allowed because none of user's groups are listed in AllowGroups
Jan 10 20:31:12 sshd[15798]: Connection from 188.124.3.41 port 32889
Jan 10 20:31:14 sshd[15798]: Failed password for user root from 188.124.3.41 port 32889 ssh2
Jan 10 20:31:14 sshd[29323]: Received disconnect from 188.124.3.41: 11: Bye Bye
Jan 10 22:04:56 sshd[25438]: Connection from 200.54.84.233 port 45196
Jan 10 22:04:58 sshd[25438]: Failed password for user root from 200.54.84.233 port 45196 ssh2
Jan 10 22:04:58 sshd[30487]: Received disconnect from 200.54.84.233: 11: Bye Bye
Jan 10 22:04:59 sshd[21358]: Connection from 200.54.84.233 port 45528
Jan 10 22:05:01 sshd[21358]: Failed password for user root from 200.54.84.233 port 45528 ssh2
Jan 10 22:05:02 sshd[2624]: Received disconnect from 200.54.84.233: 11: Bye Bye
Jan 10 22:05:29 sshd[21358]: Connection from 200.54.84.233 port 45528
Jan 10 22:05:30 sshd[21358]: Failed password for user root from 200.54.84.233 port 45528 ssh2
Jan 10 22:05:33 sshd[2624]: Received disconnect from 200.54.84.233: 11: Bye Bye
Jan 10 22:06:49 sshd[21358]: Connection from 200.54.84.233 port 45528
Jan 10 22:06:51 sshd[21358]: Failed password for user root from 200.54.84.233 port 45528 ssh2
Jan 10 22:06:51 sshd[2624]: Received disconnect from 200.54.84.233: 11: Bye Bye
... it produces this output;
User root had login failures at the following times:
Jan 10 22:04:58 sshd[25438]: Failed password for user root from 200.54.84.233 port 45196 ssh2
Jan 10 22:05:01 sshd[21358]: Failed password for user root from 200.54.84.233 port 45528 ssh2
Jan 10 22:05:30 sshd[21358]: Failed password for user root from 200.54.84.233 port 45528 ssh2
Jan 10 22:06:51 sshd[21358]: Failed password for user root from 200.54.84.233 port 45528 ssh2
Note that the timezone and/or offset is not present in the logfile data - so, there is no way for this script to work correctly on the day you enter or leave "Daylight Savings."

How do you find something in an array that would match keywords from a text file and while doing a regex in perl

I'm at a loss at trying to find out how to match the keywords in my keywords text which are:
NetworkManager
dhclient
dbus
My code currently looks like this:
#!/usr/bin/perl
use strict;
use warnings;
use File::Compare;
my $syslogFile = 'syslog';
open (my $syslogInfo, '<', $syslogFile) or die "Could not open $syslogFile";
my $keywordFile = 'keyword';
open (my $keywordInfo, '<', $keywordFile) or die "Could not open $keywordFile";
while(my #keywordArray = <$keywordInfo>)
{
print "#keywordArray\n";
}
while(my #syslogLine = <$syslogInfo>)
{
print "#syslogLine\n";
}
and now I am stuck on how to get these 2 text files to work together and get the desired result.
What Im trying to do is to have things in my syslog txt for example:
Dec 27 21:17:52 osboxes rsyslogd: [origin software="rsyslogd" swVersion="8.12.0" x-pid="695" x-info="http://www.rsyslog.com"] rsyslogd was HUPed
Dec 27 21:18:05 osboxes anacron[634]: Job `cron.daily' terminated
Dec 27 21:18:05 osboxes anacron[634]: Normal exit (1 job run)
Dec 27 21:22:29 osboxes NetworkManager[686]: <info> lease time 1800
Dec 27 21:22:29 osboxes NetworkManager[686]: <info> domain name 'localdomain'
To have it matched with the keywords and only print the lines that have the keywords in it so that it will only print:
Dec 27 21:22:29 osboxes NetworkManager[686]: <info> lease time 1800
Dec 27 21:22:29 osboxes NetworkManager[686]: <info> domain name 'localdomain'
I have tried out using IF by doing this:
if(my #syslogLine = (/^[a-zA-Z][a-zA-Z][a-zA-Z]\s(\d\d)\s(\d\d):(\d\d):(\d\d)\s[a-zA-Z]*\s(#keywordArray).*/s))
{
open(outputFile, ">>output");
print outputFile "#syslogLine\n";
}
but this gives me the errors:
Possible unintended of #keywordArray
Global symbol "#keywordArray requires explict package name
Im guessing that perl doesn't like having an array in the regex?
I just couldn't get my head around this problem.
The common approach is to build a regex from the keywords, then read the second file and match each line against the keyword:
#!/usr/bin/perl
use warnings;
use strict;
my $keywordFile = 'keyword';
open my $KW, '<', $keywordFile or die "Could not open $keywordFile";
chomp( my #keywords = <$KW> );
my $regex = join '|', map quotemeta, #keywords;
my $syslogFile = 'syslog';
open my $SYS, '<', $syslogFile or die "Could not open $syslogFile";
while(<$SYS>) {
print if /$regex/;
}

Perl file copy duplicating output

I'm attempting to write a menu driven modular perl script that will capture user input and automate the network configuration process. This script has to be able to install required Arch packages, configure AP mode, configure either DHCP or a static address for the user selected interface and give an option to enable bridging. (EDIT: The script also needs to be able to enable and configure the dhcpd service)
The part I'm stuck on right now is creating a backup of the rc.conf file, reading the file and editing the lines that need to be modified if a network interface has already been statically configured. This script is for use in ArchLinux, I did some searching around and didn't find anything that met my needs specifically.
Using generic input for
$ip = 1.1.1.1; $Bcast = 2.2.2.2; $netmask = 3.3.3.3; $GW = 4.4.4.4;
I've spent about two hours reading about file I/O and tried several things that didn't work including scrapping the multiple file IO method and using something similar to: while(<IS>){s/^interface.?=(.*)$/"interface=#if[0] \n"/;} with inputs for each of the values that need to be replaced and couldn't get it to actually do anything.
if (system ("cat","/etc/rc.conf","|","grep","interface")){
use File::Copy "cp";
$filename = "/etc/rc.conf";
$tempfile = "/etc/rc.tmp";
$bak = "/etc/rc.bak";
cp($filename,$bak);
open(IS, $filename);
open(OS, ">$tempfile");
while(<IS>){
if($_ =~ /^interface.?=(.*)$/){ print OS"interface=#if[0] \n";}
if($_ =~ /^address.?=(.*)$/){ print OS "address=$ip\n";}
if($_ =~/^netmask.?=(.*)$/){ print OS "netmask=$netmask\n";}
if($_ =~/^broadcast.?=(.*)$/){ print OS "broadcast=$Bcast\n";}
if($_ =~/^gateway.?=(.*)$/){ print OS "gateway=$GW\n"; }
else {print OS $_;}
}
close(IS); close(OS);
unlink($filename); rename($tempfile, $filename);
}
rc.conf before
#
# /etc/rc.conf - Main Configuration for Arch Linux
. /etc/archiso/functions
LOCALE_DEFAULT="en_US.UTF-8"
DAEMON_LOCALE_DEFAULT="no"
CLOCK_DEFAULT="UTC"
TIMEZONE_DEFAULT="Canada/Pacific"
KEYMAP_DEFAULT="us"
CONSOLEFONT_DEFAULT=
CONSOLEMAP_DEFAULT=
USECOLOR_DEFAULT="yes"
LOCALE="$(kernel_cmdline locale ${LOCALE_DEFAULT})"
DAEMON_LOCALE="$(kernel_cmdline daemon_locale ${DAEMON_LOCALE_DEFAULT})"
HARDWARECLOCK="$(kernel_cmdline clock ${CLOCK_DEFAULT})"
TIMEZONE="$(kernel_cmdline timezone ${TIMEZONE_DEFAULT})"
KEYMAP="$(kernel_cmdline keymap ${KEYMAP_DEFAULT})"
CONSOLEFONT="$(kernel_cmdline consolefont ${CONSOLEFONT_DEFAULT})"
CONSOLEMAP="$(kernel_cmdline consolemap ${CONSOLEMAP_DEFAULT})"
USECOLOR="$(kernel_cmdline usecolor ${USECOLOR_DEFAULT})"
MODULES=()
UDEV_TIMEOUT=30
USEDMRAID="no"
USEBTRFS="no"
USELVM="no"
HOSTNAME="archiso"
DAEMONS=(hwclock syslog-ng)
interface=eth0
address=192.168.0.99
netmask=255.255.255.0
broadcast=192.168.0.255
gateway=192.168.0.1
rc.conf after
#
# /etc/rc.conf - Main Configuration for Arch Linux
. /etc/archiso/functions
LOCALE_DEFAULT="en_US.UTF-8"
DAEMON_LOCALE_DEFAULT="no"
CLOCK_DEFAULT="UTC"
TIMEZONE_DEFAULT="Canada/Pacific"
KEYMAP_DEFAULT="us"
CONSOLEFONT_DEFAULT=
CONSOLEMAP_DEFAULT=
USECOLOR_DEFAULT="yes"
LOCALE="$(kernel_cmdline locale ${LOCALE_DEFAULT})"
DAEMON_LOCALE="$(kernel_cmdline daemon_locale ${DAEMON_LOCALE_DEFAULT})"
HARDWARECLOCK="$(kernel_cmdline clock ${CLOCK_DEFAULT})"
TIMEZONE="$(kernel_cmdline timezone ${TIMEZONE_DEFAULT})"
KEYMAP="$(kernel_cmdline keymap ${KEYMAP_DEFAULT})"
CONSOLEFONT="$(kernel_cmdline consolefont ${CONSOLEFONT_DEFAULT})"
CONSOLEMAP="$(kernel_cmdline consolemap ${CONSOLEMAP_DEFAULT})"
USECOLOR="$(kernel_cmdline usecolor ${USECOLOR_DEFAULT})"
MODULES=()
UDEV_TIMEOUT=30
USEDMRAID="no"
USEBTRFS="no"
USELVM="no"
HOSTNAME="archiso"
DAEMONS=(hwclock syslog-ng)
interface=eth0
interface=eth0
address=1.1.1.1
address=192.168.0.99
netmask=3.3.3.3
netmask=255.255.255.0
broadcast=2.2.2.2
broadcast=192.168.0.255
gateway=4.4.4.4
I am not going to comment on the wisdom of the rest of your script, but you have:
if (system ("cat","/etc/rc.conf","|","grep","interface")){
system returns 0 on success.
So, you'll enter the block only if that system call fails.
If fact, I am on a Windows system right now with no /etc/rc.conf (but cat and grep thanks to Cygwin. Running the following script:
#!/usr/bin/env perl
use strict; use warnings;
if (system ("cat","/etc/rc.conf","|","grep","interface")){
print "*** it worked! ***\n";
if ($? == -1) {
print "failed to execute: $!\n";
}
elsif ($? & 127) {
printf "child died with signal %d, %s coredump\n",
($? & 127), ($? & 128) ? 'with' : 'without';
}
else {
printf "child exited with value %d\n", $? >> 8;
}
}
produces the output:
cat: /etc/rc.conf: No such file or directory
cat: |: No such file or directory
cat: grep: No such file or directory
cat: interface: No such file or directory
*** it worked! ***
child exited with value 1
That means system returned a failure code. Now, if you want to use shell piping and redirection, you should pass system a string, not a list, and check like this:
if (system ('cat /etc/rc.conf | grep interface') == 0) {
On the other hand, I would rather not trust shells propagating exit status.
The following should point you in a better direction:
#!/usr/bin/env perl
use strict;use warnings;
my %lookup = (
eth0 => {
address => '1.1.1.1',
broadcast => '2.2.2.2',
netmask => '3.3.3.3',
gateway => '4.4.4.4',
},
wlan0 => {
address => '5.5.5.5',
broadcast => '6.6.6.6',
netmask => '7.7.7.7',
gateway => '8.8.8.8',
},
);
while (my $line = <DATA>) {
if (my ($interface) = ($line =~ /^interface=(\S+)/)) {
print $line;
if (exists $lookup{$interface}) {
$line = process_interface(\*DATA, $lookup{$interface});
redo;
}
}
else {
print $line;
}
}
sub process_interface {
my ($fh, $lookup) = #_;
my $keys = join '|', sort keys %$lookup;
while (my $line = <DATA>) {
$line =~ s/\A($keys)=.+/$1=$lookup->{$1}/
or return $line;
print $line;
}
return;
}
__DATA__
#
# /etc/rc.conf - Main Configuration for Arch Linux
. /etc/archiso/functions
# stuff
interface=eth0
address=192.168.0.99
netmask=255.255.255.0
broadcast=192.168.0.255
gateway=192.168.0.1
interface=wlan0
address=192.168.0.99
netmask=255.255.255.0
broadcast=192.168.0.255
gateway=192.168.0.1
Output:
#
# /etc/rc.conf - Main Configuration for Arch Linux
. /etc/archiso/functions
# stuff
interface=eth0
address=1.1.1.1
netmask=3.3.3.3
broadcast=2.2.2.2
gateway=4.4.4.4
interface=wlan0
address=5.5.5.5
netmask=7.7.7.7
broadcast=6.6.6.6
gateway=8.8.8.8
The problem is your if/if/if/if/if/else chain, which should be an if/elsif/elsif/elsif/elsif/else chain. The else { print OS $_ } triggers on every line that doesn't match gateway=, including the ones that match interface, address, etc.