Skip to content

Commit

Permalink
Implement HW2
Browse files Browse the repository at this point in the history
  • Loading branch information
itaispiegel committed Jan 7, 2024
1 parent 82f39b5 commit 6e35a54
Show file tree
Hide file tree
Showing 10 changed files with 299 additions and 50 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,5 @@ Module.symvers
modules.order

.mypy_cache

user/fwsummary
17 changes: 17 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,20 @@ My homework submission for Infosec Workshop at TAU, 2024 Fall Semester
In this exercise, we implemented a very basic firewall, which uses the [Linux Netfilter](https://en.wikipedia.org/wiki/Netfilter) framework, to hook on FORWARD and INPUT packets, and do:
- Block FORWARD packets, and log the message `*** Packet Dropped ***`.
- Accept local INPUT and OUTPUT packets, and log the message `*** Packet Accepted ***`.

## HW2
In this exercise, we extended the kernel module from the previous step, by adding a [sysfs](https://docs.kernel.org/filesystems/sysfs.html) interface for interacting with the kernel module from the userspace.
Then, we used this interface to implement the tool `fwsummary` which prints the packets counts.
Example:
```bash
./fwsummary
Firewall Packets Summary:
Number of accepted packets: 57
Number of dropped packets: 42
Total number of packets: 99
```

It's also possible to reset the counters by running:
```bash
./fwsummary 0
```
49 changes: 0 additions & 49 deletions hw1secws.c

This file was deleted.

22 changes: 22 additions & 0 deletions infosec-workshop.code-workspace
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
"folders": [
{
"path": "."
},
{
"path": "module"
},
{
"path": "user"
}
],
"settings": {
"files.exclude": {
"module": true,
"user": true
},
"files.associations": {
"*.h": "c",
}
}
}
File renamed without changes.
2 changes: 1 addition & 1 deletion Makefile → module/Makefile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
obj-m += hw1secws.o
obj-m += hw2secws.o

all:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
Expand Down
179 changes: 179 additions & 0 deletions module/hw2secws.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/netfilter.h>

#define MOD_NAME "hw2secws"

static unsigned int accepted_pkts_count = 0;
static unsigned int dropped_pkts_count = 0;

static unsigned int drop_pkt_hook_fn(void *, struct sk_buff *,
const struct nf_hook_state *);

static unsigned int accept_pkt_hook_fn(void *, struct sk_buff *,
const struct nf_hook_state *);

ssize_t accepted_pkts_count_show(struct device *, struct device_attribute *,
char *);

ssize_t dropped_pkts_count_show(struct device *, struct device_attribute *,
char *);

ssize_t reset_counters_store(struct device *, struct device_attribute *,
const char *, size_t);

static int major;
static struct class *sysfs_class;
static struct device *sysfs_device;

static struct file_operations fops = {
.owner = THIS_MODULE,
};

static DEVICE_ATTR(accepted_pkts_count, S_IRUGO, accepted_pkts_count_show,
NULL);
static DEVICE_ATTR(dropped_pkts_count, S_IRUGO, dropped_pkts_count_show, NULL);
static DEVICE_ATTR(reset_counters, S_IWUSR, NULL, reset_counters_store);

static const struct nf_hook_ops hooks[] = {
{.hook = drop_pkt_hook_fn, .pf = NFPROTO_IPV4, .hooknum = NF_INET_FORWARD},
{.hook = accept_pkt_hook_fn,
.pf = NFPROTO_IPV4,
.hooknum = NF_INET_LOCAL_IN},
{.hook = accept_pkt_hook_fn,
.pf = NFPROTO_IPV4,
.hooknum = NF_INET_LOCAL_OUT}};

static unsigned int drop_pkt_hook_fn(void *priv, struct sk_buff *skb,
const struct nf_hook_state *state) {
printk(KERN_INFO "*** Packet Dropped ***\n");
++dropped_pkts_count;
return NF_DROP;
}

static unsigned int accept_pkt_hook_fn(void *priv, struct sk_buff *skb,
const struct nf_hook_state *state) {
printk(KERN_INFO "*** Packet Accepted ***\n");
++accepted_pkts_count;
return NF_ACCEPT;
}

ssize_t accepted_pkts_count_show(struct device *dev,
struct device_attribute *attr, char *buf) {
return scnprintf(buf, PAGE_SIZE, "%u\n", accepted_pkts_count);
}

ssize_t dropped_pkts_count_show(struct device *dev,
struct device_attribute *attr, char *buf) {
return scnprintf(buf, PAGE_SIZE, "%u\n", dropped_pkts_count);
}

ssize_t reset_counters_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count) {
accepted_pkts_count = 0;
dropped_pkts_count = 0;
return count;
}

static int __init init(void) {
if (nf_register_net_hooks(&init_net, hooks, 2)) {
printk(KERN_ERR "Failed to register net hooks\n");
return -1;
}
printk(KERN_INFO "Successfully registered net hooks\n");

major = register_chrdev(0, MOD_NAME, &fops);
if (major < 0) {
printk(KERN_ERR "Failed to register character device\n");
nf_unregister_net_hooks(&init_net, hooks, 2);
return -1;
}
printk(KERN_INFO "Successfully registered chrdev\n");

sysfs_class = class_create(THIS_MODULE, MOD_NAME);
if (IS_ERR(sysfs_class)) {
printk(KERN_ERR "Failed to create sysfs class\n");
unregister_chrdev(major, MOD_NAME);
nf_unregister_net_hooks(&init_net, hooks, 2);
return -1;
}
printk(KERN_INFO "Successfully created sysfs class\n");

sysfs_device =
device_create(sysfs_class, NULL, MKDEV(major, 0), NULL, MOD_NAME);
if (IS_ERR(sysfs_device)) {
class_destroy(sysfs_class);
unregister_chrdev(major, MOD_NAME);
nf_unregister_net_hooks(&init_net, hooks, 2);
return -1;
}
printk(KERN_INFO "Successfully created sysfs device\n");

if (device_create_file(sysfs_device,
(const struct device_attribute
*)&dev_attr_accepted_pkts_count.attr)) {
device_destroy(sysfs_class, MKDEV(major, 0));
class_destroy(sysfs_class);
unregister_chrdev(major, MOD_NAME);
nf_unregister_net_hooks(&init_net, hooks, 2);
return -1;
}
printk(KERN_INFO "Successfully created sysfs accepted_pkts_count\n");

if (device_create_file(sysfs_device,
(const struct device_attribute
*)&dev_attr_dropped_pkts_count.attr)) {
device_remove_file(sysfs_device,
(const struct device_attribute
*)&dev_attr_accepted_pkts_count.attr);
device_destroy(sysfs_class, MKDEV(major, 0));
class_destroy(sysfs_class);
unregister_chrdev(major, MOD_NAME);
nf_unregister_net_hooks(&init_net, hooks, 2);
return -1;
}
printk(KERN_INFO "Successfully created sysfs dropped_pkts_count\n");

if (device_create_file(
sysfs_device,
(const struct device_attribute *)&dev_attr_reset_counters.attr)) {
device_remove_file(
sysfs_device,
(const struct device_attribute *)&dev_attr_dropped_pkts_count.attr);
device_remove_file(sysfs_device,
(const struct device_attribute
*)&dev_attr_accepted_pkts_count.attr);
device_destroy(sysfs_class, MKDEV(major, 0));
class_destroy(sysfs_class);
unregister_chrdev(major, MOD_NAME);
nf_unregister_net_hooks(&init_net, hooks, 2);
return -1;
}
printk(KERN_INFO "Successfully created sysfs reset_counters\n");

return 0;
}

static void __exit exit(void) {
device_remove_file(
sysfs_device,
(const struct device_attribute *)&dev_attr_reset_counters.attr);
device_remove_file(
sysfs_device,
(const struct device_attribute *)&dev_attr_dropped_pkts_count.attr);
device_remove_file(
sysfs_device,
(const struct device_attribute *)&dev_attr_accepted_pkts_count.attr);
device_destroy(sysfs_class, MKDEV(major, 0));
class_destroy(sysfs_class);
unregister_chrdev(major, MOD_NAME);
nf_unregister_net_hooks(&init_net, hooks, 2);
printk(KERN_INFO "Exiting hw2secws kernel module\n");
}

module_init(init);
module_exit(exit);

MODULE_AUTHOR("Itai Spiegel");
MODULE_LICENSE("GPL");
3 changes: 3 additions & 0 deletions user/.vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"C_Cpp.default.compilerPath": "/usr/bin/gcc"
}
9 changes: 9 additions & 0 deletions user/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
CC = gcc
CFLAGS = -Wall -Wextra -Werror -pedantic -std=c99

fwsummary: fwsummary.c
$(CC) $(CFLAGS) -o $@ $^

.PHONY: clean
clean:
rm -f fwsummary
66 changes: 66 additions & 0 deletions user/fwsummary.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MODULE_NAME "hw2secws"
#define SYSFS_BASE_PATH "/sys/class/" MODULE_NAME "/" MODULE_NAME "/"
#define ACCEPTED_PKTS_COUNT_FILENAME SYSFS_BASE_PATH "accepted_pkts_count"
#define DROPPED_PKTS_COUNT_FILENAME SYSFS_BASE_PATH "dropped_pkts_count"
#define RESET_COUNTERS_FILENAME SYSFS_BASE_PATH "reset_counters"

static unsigned int read_unsigned_int_from_file(const char *filename) {
FILE *fp;
unsigned int value;

if ((fp = fopen(filename, "r")) == NULL) {
printf("Error opening file %s\n", RESET_COUNTERS_FILENAME);
exit(1);
}
fscanf(fp, "%u", &value);
fclose(fp);

return value;
}

static unsigned int get_accepted_pkts_count() {
return read_unsigned_int_from_file(ACCEPTED_PKTS_COUNT_FILENAME);
}

static unsigned int get_dropped_pkts_count() {
return read_unsigned_int_from_file(DROPPED_PKTS_COUNT_FILENAME);
}

static void reset_counters() {
FILE *fp;

if ((fp = fopen(RESET_COUNTERS_FILENAME, "w")) == NULL) {
printf("Error opening file %s\n", RESET_COUNTERS_FILENAME);
exit(1);
}

fprintf(fp, "1");
fclose(fp);
}

int main(int argc, char **argv) {
unsigned int accepted_pkts_count;
unsigned int dropped_pkts_count;
unsigned int total_pkts;

if (argc > 2 || (argc == 2 && strncmp(argv[1], "0", 1) != 0)) {
printf("Usage: %s [arg]\n", argv[0]);
return 1;
} else if (argc == 1) {
accepted_pkts_count = get_accepted_pkts_count();
dropped_pkts_count = get_dropped_pkts_count();
total_pkts = accepted_pkts_count + dropped_pkts_count;

printf("Firewall Packets Summary:\n");
printf("Number of accepted packets: %u\n", accepted_pkts_count);
printf("Number of dropped packets: %u\n", dropped_pkts_count);
printf("Total number of packets: %u\n", total_pkts);
} else {
reset_counters();
}
return 0;
}

0 comments on commit 6e35a54

Please sign in to comment.