#!/usr/bin/env raku
# Zig Glue
###########
use NativeCall;
enum Action <ALLOW DENY REJECT>;
enum Proto <TCP UDP>;
class Rule is repr('CStruct') {
has uint8 $!action;
has uint8 $!proto;
has uint32 $!port;
method gist { (Action($!action), Proto($!proto), $!port).join(' ') }
method to-hex { nativecast(CArray[uint8], self)[^nativesizeof(self)].fmt("%02x", "") }
submethod TWEAK(*%opt) { ($!action, $!proto, $!port) = %opt<action proto port> }
}
sub apply_rule(Rule --> bool) is native('./libfirewall.so') {*}
# Firewall Config Grammar
#########################
grammar Firewall {
token TOP { <rule>+ %% \n+ }
token rule { <action> \s+ <proto> \s+ <port> }
token action { 'ALLOW' | 'DENY' | 'REJECT' }
token proto { 'TCP' | 'UDP' }
token port { \d+ }
}
class FirewallAction {
method TOP($/) { make $<rule>>>.made }
method rule($/) {
make Rule.new(
:action(Action::{$<action>}),
:proto(Proto::{$<proto>}),
:port($<port>.Int)
);
}
}
# CLI Handling
##############
sub MAIN (
$file where *.IO.f, #= Firewall Config File
) {
my @rules = Firewall.parse($file.IO.slurp, :actions(FirewallAction.new)).made;
@rules.map: { say "[R] ", $^rule, " => ", $^rule.to-hex and apply_rule($^rule) };
}