Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
A
aix-pm
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Wiki
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Build
Pipelines
Jobs
Pipeline schedules
Artifacts
Deploy
Releases
Package registry
Container registry
Model registry
Operate
Environments
Terraform modules
Monitor
Incidents
Service Desk
Analyze
Value stream analytics
Contributor analytics
CI/CD analytics
Repository analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Terms and privacy
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
Gerhard Gonter
aix-pm
Commits
feaf121c
Commit
feaf121c
authored
1 month ago
by
Gerhard Gonter
Browse files
Options
Downloads
Patches
Plain Diff
utility module to work with ufw
parent
3f474e0b
No related branches found
No related tags found
No related merge requests found
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
modules/util/Util/ufw.pm
+328
-0
328 additions, 0 deletions
modules/util/Util/ufw.pm
with
328 additions
and
0 deletions
modules/util/Util/ufw.pm
0 → 100644
+
328
−
0
View file @
feaf121c
#!/usr/bin/perl
use
strict
;
package
Util::
ufw
;
sub
new
{
my
$class
=
shift
;
my
$self
=
{
status
=>
undef
,
};
bless
$self
,
$class
;
$self
->
set
(
@
_
);
$self
;
}
sub
set
{
my
$self
=
shift
;
my
%pars
=
@_
;
foreach
my
$par
(
keys
%pars
)
{
$self
->
{
$par
}
=
$pars
{
$par
};
}
}
sub
status
{
my
$self
=
shift
;
$self
=
Util::
ufw
->
new
(
@
_
)
if
(
$self
eq
'
Util::ufw
');
open
(
UFW
,
'
-|:utf8
',
'
ufw
',
'
status
',
'
numbered
')
or
die
;
my
$st
=
0
;
my
@rules
=
();
$self
->
{
rules
}
=
\
@rules
;
my
%si4
=
();
$self
->
{
src_ipv4
}
=
\
%si4
;
my
%si4c
=
();
$self
->
{
src_ipv4_cidr
}
=
\
%si4c
;
my
(
$rule_number
,
$text
);
while
(
<
UFW
>
)
{
chop
;
# print __LINE__, " ufw: st=[$st] [$_]\n";
if
(
$st
==
0
)
{
if
(
$_
=~
/^Status: (.+)/
)
{
$self
->
{
status
}
=
$
1
;
}
$st
++
;
}
elsif
(
$st
==
1
)
{
if
(
$_
=~
/^[ \-]+$/
)
{
$st
=
2
;
}
}
elsif
(
$st
==
2
)
# rules section
{
if
(
$_
eq
'')
{
$st
=
3
;
}
elsif
(
$_
=~
/^\[\s*(\d+)\]\s*(.*)/
)
{
(
$rule_number
,
$text
)
=
(
$
1
,
$
2
);
my
%rule
=
(
rule_number
=>
$rule_number
,
line
=>
$_
,
addressing
=>
'
ipv4
'
);
my
@t
=
split
('
',
$text
);
my
$rst
=
0
;
while
(
my
$t
=
shift
(
@t
))
{
if
(
$rst
==
0
)
{
$rule
{
dst
}
=
$t
;
if
(
$t
[
0
]
eq
'
(v6)
')
{
$rule
{
addressing
}
=
'
ipv6
';
shift
(
@t
);
}
$rst
=
1
;
}
elsif
(
$rst
==
1
)
{
$t
.=
'
'
.
shift
(
@t
)
if
(
$t
[
0
]
eq
'
IN
'
||
$t
[
0
]
eq
'
OUT
');
my
$policy
=
'
unknown
';
if
(
$t
eq
'
DENY IN
')
{
$policy
=
'
deny
'
}
elsif
(
$t
eq
'
REJECT IN
')
{
$policy
=
'
reject
'
}
elsif
(
$t
eq
'
ALLOW IN
')
{
$policy
=
'
allow
'
}
$rule
{
action
}
=
$t
;
$rule
{
policy
}
=
$policy
;
$rst
=
2
;
}
elsif
(
$rst
==
2
)
{
$rule
{
src
}
=
$t
;
if
(
$t
[
0
]
eq
'
(v6)
')
{
$rule
{
addressing
}
=
'
ipv6
';
shift
(
@t
);
}
if
(
$t
=~
/^[\d\.\/]+$/
)
{
if
(
$t
=~
/\//
)
{
$rule
{
is_ipv4_cidr
}
=
1
;
push
(
@
{
$si4c
{
$t
}},
$rule_number
);
}
else
{
$rule
{
is_ipv4
}
=
1
;
push
(
@
{
$si4
{
$t
}},
$rule_number
);
}
}
elsif
(
$t
eq
'
Anywhere
')
{
$rule
{
is_world
}
=
1
;
}
else
{
$rule
{
unkown_src
}
=
1
;
}
$rst
=
3
;
}
elsif
(
$rst
==
3
)
{
if
(
$t
eq
'
(log)
')
{
$rule
{
log
}
=
1
;
}
else
{
push
(
@
{
$rule
{
junk
}},
$t
)
}
}
}
push
(
@rules
,
\
%rule
);
}
else
{
print
__LINE__
,
"
unknown line=[
$_
]
\n
";
}
}
}
$self
;
}
sub
has_rules_ipv4
{
my
$self
=
shift
;
my
$ipv4
=
shift
;
if
(
exists
(
$self
->
{
src_ipv4
}
->
{
$ipv4
}))
{
return
(
$self
->
{
src_ipv4
}
->
{
$ipv4
});
}
return
undef
;
}
sub
get_rule
{
my
$self
=
shift
;
my
$number
=
shift
;
return
(
$self
->
{
rules
}
->
[
$number
-
1
]);
}
sub
block
{
my
$self
=
shift
;
my
$ip
=
shift
;
my
$c
=
$self
->
{
config
};
# print __LINE__, " c: ", main::Dumper($c);
ufw
(
$c
->
{
block_policy
},
$ip
,
$c
->
{
log
},
$c
->
{
insert_position
});
}
sub
remove_rule
{
my
$self
=
shift
;
my
$num
=
shift
;
my
@cmd
=
('
/usr/sbin/ufw
',
'
--force
',
'
delete
',
$num
);
print
__LINE__
,
"
remove_rule:
",
join
('
',
@cmd
),
"
\n
";
system
(
@cmd
);
}
sub
ufw
{
my
$action
=
shift
;
my
$ip
=
shift
;
my
$log
=
shift
;
my
$pos
=
shift
;
my
@cmd
=
('
/usr/sbin/ufw
');
push
(
@cmd
,
'
insert
',
$pos
)
if
(
defined
(
$pos
));
push
(
@cmd
,
$action
);
push
(
@cmd
,
'
log
')
if
(
$log
);
push
(
@cmd
,
'
from
',
$ip
);
print
__LINE__
,
'
',
scalar
localtime
(
time
()),
'
cmd:
',
join
('
',
@cmd
),
"
\n
";
system
(
@cmd
);
}
=head2 $rule_number_list= $self->in_firewall_rules($addr);
Check if a given address is listed in the firwall rules and return the
list of rules, if something matches.
TODO: we need probably another element in the return values indication
what type of match this was, e.g. if $addr was a cidr block and it matched
cidr blocks or "collected" several explicit ip addresses or even both.
Also, if $addr was a plain ipv4 address and it matches one or more
existiing cidr rules whould be of interesst. Maybe this is getting too
complicated after all and should be handled in different methods instead
of just one.
=cut
sub
in_firewall_rules
{
my
$self
=
shift
;
my
$ip
=
shift
;
my
@rule_list
;
if
(
$ip
=~
/^[\d\.\/]+$/
)
{
if
(
$ip
=~
/\//
)
{
# TODO: addr to check is cidr
# later...
if
(
exists
(
$self
->
{
src_ipv4_cidr
}
->
{
$ip
}))
{
my
$rule_number_list
=
$self
->
{
src_ipv4_cidr
}
->
{
$ip
};
push
(
@rule_list
,
@$rule_number_list
);
}
# TO CONSIDER: collect all matching IPv4 addresses and deliver them?
}
else
{
# plain vanilla ipv4 address
# print __LINE__, " ip=[$ip]\n";
if
(
exists
(
$self
->
{
src_ipv4
}
->
{
$ip
}))
{
my
$rule_number_list
=
$self
->
{
src_ipv4
}
->
{
$ip
};
push
(
@rule_list
,
@$rule_number_list
);
}
# TODO: also check if the ipv4 address to check is convered by a ipv4 cidr block
my
$sc
=
$self
->
{
src_ipv4_cidr
};
if
(
defined
(
$sc
))
{
my
@sc
=
keys
%$sc
;
foreach
my
$cidr
(
@sc
)
{
my
$res
=
Net::CIDR::
cidrlookup
(
$ip
,
$cidr
);
if
(
$res
)
{
push
(
@rule_list
,
@
{
$sc
->
{
$cidr
}});
}
# could the be more than one match?
}
}
}
}
\
@rule_list
;
}
sub
in_whitelist
{
my
$self
=
shift
;
my
$ip
=
shift
;
$self
->
load_whitelists
()
unless
(
$self
->
{
_whitelists_loaded
});
if
(
$ip
=~
/^[\d\.\/]+$/
)
{
if
(
$ip
=~
/\//
)
{
# CIDR .... later...
}
else
{
if
(
exists
(
$self
->
{
whitelist_ipv4
})
&&
exists
(
$self
->
{
whitelist_ipv4
}
->
{
$ip
}))
{
return
'
ipv4
';
}
my
$wl_cidr
=
$self
->
{
whitelist_ipv4_cidr
};
if
(
defined
(
$wl_cidr
))
{
my
$res
=
Net::CIDR::
cidrlookup
(
$ip
,
keys
%$wl_cidr
);
return
'
ipv4_cidr
'
if
(
$res
);
}
}
}
undef
;
}
sub
load_whitelists
{
my
$self
=
shift
;
my
$c
=
$self
->
{
config
};
return
undef
unless
(
defined
(
$c
));
if
(
exists
(
$c
->
{
whitelist
}))
{
$self
->
add_to_whitelist
(
@
{
$c
->
{
whitelist
}});
}
if
(
exists
(
$c
->
{
whitelist_file
}))
{
if
(
open
(
FI
,
'
<:utf8
',
$c
->
{
whitelist_file
}))
{
my
@ips
;
while
(
<
FI
>
)
{
chop
;
next
if
(
$_
=~
/^#/
);
$_
=~
s/[ #].*//
;
push
(
@ips
,
$_
);
}
$self
->
add_to_whitelist
(
@ips
);
}
else
{
# no reason to die
print
__LINE__
,
"
can't read whitlist_file=[
$c
->{whitelist_file}]
\
m
";
}
}
$self
->
{
_whitelists_loaded
}
=
1
;
}
sub
add_to_whitelist
{
my
$self
=
shift
;
my
@addr
=
@_
;
foreach
my
$ip
(
@addr
)
{
if
(
$ip
=~
/^[\d\.]+\/\d+$/
)
{
$self
->
{
whitelist_ipv4_cidr
}
->
{
$ip
}
++
;
}
elsif
(
$ip
=~
/^[\d\.]+$/
)
{
$self
->
{
whitelist_ipv4
}
->
{
$ip
}
++
;
}
else
{
print
__LINE__
,
"
unknown address format: [
$ip
]
\n
";
}
}
}
1
;
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment