--- /dev/null
+#define PERL_NO_GET_CONTEXT
+#include "EXTERN.h"
+#include "perl.h"
+#include "XSUB.h"
+
+#include <stdio.h>
+#include <string.h>
+
+#include <libipset/ipset.h>
+#include <libipset/data.h>
+#include <libipset/session.h>
+#include <libipset/types.h>
+
+MODULE = IPSet PACKAGE = IPSet
+
+struct ipset_session *
+init()
+ CODE:
+ struct ipset_session *session;
+
+ // Load IPSet types.
+ ipset_load_types();
+
+ // Init a new IPSet session
+ session = ipset_session_init(NULL, NULL);
+
+
+ // Abort if the session could not be initialized.
+ if (!session) {
+ croak("Cannot initialize ipset session.\n");
+ }
+
+ RETVAL = session;
+ OUTPUT:
+ RETVAL
+
+#
+# Functions to directly deal with sets.
+#
+bool create_set(session, setname, typename, hashsize, maxelem)
+ struct ipset_session *session;
+ const char *setname;
+ const char *typename;
+ int hashsize;
+ int maxelem;
+
+ PREINIT:
+ const struct ipset_type *type;
+
+ // Family current is hardcoded to IPv4.
+ int family = NFPROTO_IPV4;
+
+ CODE:
+ // Load everything
+ ipset_load_types();
+
+ // Assin the setname to the session data.
+ int r = ipset_session_data_set(session, IPSET_SETNAME, setname);
+ if (r < 0) {
+ printf("Could not set ipset name: %s\n",
+ ipset_session_report_msg(session));
+
+ return;
+ }
+
+ // Assign additinal options to the session data.
+ r = ipset_parse_typename(session, IPSET_OPT_TYPE, typename);
+ if (r < 0) {
+ printf("Could not set set type: %s\n",
+ ipset_session_report_msg(session));
+
+ return;
+ }
+
+ type = ipset_type_get(session, IPSET_CMD_CREATE);
+ if (!type) {
+ printf("Could not get hash type.\n");
+
+ return;
+ }
+
+ r = ipset_session_data_set(session, IPSET_OPT_FAMILY, &family);
+ if (r < 0) {
+ printf("Could not set family: %s\n",
+ ipset_session_report_msg(session));
+
+ return;
+ }
+
+ r = ipset_session_data_set(session, IPSET_OPT_HASHSIZE, &hashsize);
+ if (r < 0) {
+ printf("Could not set hashsize: %s\n",
+ ipset_session_report_msg(session));
+
+ return;
+ }
+
+ r = ipset_session_data_set(session, IPSET_OPT_MAXELEM, &maxelem);
+ if (r < 0) {
+ printf("Could not set maxelem: %s\n",
+ ipset_session_report_msg(session));
+
+ return;
+ }
+
+ r = ipset_cmd(session, IPSET_CMD_CREATE, 0);
+ if (r < 0) {
+ printf("Command failed: %s\n",
+ ipset_session_report_msg(session));
+
+ RETVAL = false;
+ }
+
+ RETVAL = true;
+
+ OUTPUT:
+ RETVAL
+
+
+bool
+setname_exists(session, setname)
+ struct ipset_session *session;
+ const char *setname;
+
+ PREINIT:
+ enum ipset_cmd cmd = IPSET_CMD_HEADER;
+
+ CODE:
+ // Assign the setname as session data.
+ int r = ipset_session_data_set(session, IPSET_SETNAME, setname);
+ if (r < 0) {
+ printf("Could not set setname: %s\n",
+ ipset_session_report_msg(session));
+ }
+
+ r = ipset_cmd(session, cmd, 0);
+ if (r < 0 ) {
+ printf("Command failed: %s\n",
+ ipset_session_report_msg(session));
+
+ RETVAL = false;
+ }
+
+ RETVAL = true;
+
+ OUTPUT:
+ RETVAL
+
+
+void
+DESTROY(session)
+ struct ipset_session *session;
+
+ CODE:
+ // Release IPSet session
+ ipset_session_fini(session);
--- /dev/null
+use ExtUtils::MakeMaker;
+# See lib/ExtUtils/MakeMaker.pm for details of how to influence
+# the contents of the Makefile that is written.
+WriteMakefile(
+ NAME => 'IPSet',
+ VERSION_FROM => 'lib/IPSet.pm',
+ PREREQ_PM => {},
+ ABSTRACT_FROM => 'lib/IPSet.pm',
+ AUTHOR => 'Stefan Schantl <stefan.schantl@ipfire.org>',
+ LICENSE => 'lgpl',
+ LIBS => ['-lipset', '-lmnl'],
+ DEFINE => '', # e.g., '-DHAVE_SOMETHING'
+ #INC => '-I. -I../../',
+ # Un-comment this if you add C files to link with later:
+ # OBJECT => '$(O_FILES)', # link all the C files too
+);
--- /dev/null
+package IPSet;
+
+use 5.028001;
+use strict;
+use warnings;
+
+require Exporter;
+
+our @ISA = qw(Exporter);
+
+# Items to export into callers namespace by default. Note: do not export
+# names by default without a very good reason. Use EXPORT_OK instead.
+# Do not simply export all your public functions/methods/constants.
+
+# This allows declaration use Location ':all';
+# If you do not need this, moving things directly into @EXPORT or @EXPORT_OK
+# will save memory.
+our %EXPORT_TAGS = ( 'all' => [ qw() ] );
+
+our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );
+
+our @EXPORT = qw();
+
+our $VERSION = '0.01';
+
+require XSLoader;
+XSLoader::load('IPSet', $VERSION);
+
+# Preloaded methods go here.
+
+1;
+__END__
+
+=head1 NAME
+
+perl-ipset - Provides a simple interface to kernel IPSet framework using libipset.
+
+=head1 SYNOPSIS
+
+ use IPSet;
+
+=head1 DESCRIPTION
+
+perl-ipset is a simple interface to the kernel IPset subsystem, provided by the Netfilter framework.
+
+More details on the project website of IPSet: https://ipset.netfilter.org/
+
+=head2 EXPORT
+
+None by default.
+
+=head1 SEE ALSO
+
+https://git.ipfire.org/?p=people/stevee/perl-ipset.git;a=summary
+
+=head1 AUTHOR
+
+Stefan Schantl, stefan.schantl@ipfire.org
+
+=head1 COPYRIGHT AND LICENSE
+
+Copyright (C) 2022 by Stefan Schantl
+
+This library is free software; you can redistribute it and/or modify
+it under the same terms as Perl itself, either Perl version 5.28.1 or,
+at your option, any later version of Perl 5 you may have available.
+
+
+=cut
--- /dev/null
+# Before 'make install' is performed this script should be runnable with
+# 'make test'. After 'make install' it should work as 'perl Location.t'
+
+#########################
+
+# change 'tests => 1' to 'tests => last_test_to_print';
+
+use strict;
+use warnings;
+
+use Test::More tests => 3;
+BEGIN { use_ok('IPSet') };
+
+#########################
+
+# Insert your test code below, the Test::More module is use()ed here so read
+# its man page ( perldoc Test::More ) for help writing this test script.
+
+# Name of the testset.
+my $setname = "TEST";
+
+# Init the IPSet module and create a session.
+my $session = &IPSet::init();
+
+# Create new IPSet.
+my $create_set = &IPSet::create_set($session, $setname, "hash:ip", "1024", "10");
+ok($create_set, "Sucessfully created set: $setname.");
+
+# Check if the testset exists.
+my $exists = &IPSet::setname_exists($session, $setname);
+ok($exists, "The testset exists.");