Last active
December 12, 2015 10:09
-
-
Save ql-owo-lp/4756895 to your computer and use it in GitHub Desktop.
CIS644_Lab2_LKM
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This is for CIS644_Lab2_LKM part, also the optional part |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* LKM Lab2 Optional task - LWFW++ - by Kevin, 2/8/2013 | |
* | |
* Based on LWFW written by Owen Klan | |
*/ | |
#include <linux/string.h> | |
#include <linux/list.h> | |
#include <linux/module.h> | |
#include <linux/kernel.h> | |
#include <linux/types.h> | |
#include <linux/net.h> | |
#include <linux/skbuff.h> | |
#include <linux/netdevice.h> | |
#include <linux/netfilter.h> | |
#include <linux/netfilter_ipv4.h> | |
#include <linux/ip.h> | |
#include <linux/tcp.h> | |
#include <linux/udp.h> | |
#include <linux/icmp.h> | |
#include <linux/inet.h> | |
#include <asm/errno.h> | |
#include <asm/uaccess.h> | |
#include "lwfw.h" | |
// firewall rules | |
struct firewall_rule { | |
struct list_head list; // manage a list of rules using list_head | |
struct iphdr *ip; // an ip header struture, used for matching src and dst | |
struct tcphdr *tcp; | |
struct udphdr *udp; | |
unsigned int drop; | |
unsigned int accept; | |
} rules; | |
/* Local function prototypes */ | |
static int read_rules(void); | |
static int append_rule(struct firewall_rule *rule); | |
static int delete_rule(struct firewall_rule *rule); | |
static int traverse_firewall_chain(struct sk_buff *skb); | |
static const char* inet_ntoa(char* ipaddr, unsigned int ip); | |
/* Some function prototypes to be used by lwfw_fops below. */ | |
static long lwfw_ioctl(struct file *file, unsigned int cmd, unsigned long arg); // changed for Kernel2.6.x | |
static int lwfw_open(struct inode *inode, struct file *file); | |
static int lwfw_release(struct inode *inode, struct file *file); | |
/* Various flags used by the module */ | |
/* This flag makes sure that only one instance of the lwfw device | |
* can be in use at any one time. */ | |
static int lwfw_ctrl_in_use = 0; | |
/* This flag marks whether LWFW should actually attempt rule checking. | |
* If this is zero then LWFW automatically allows all packets. */ | |
static int active = 1; | |
static int major = 0; /* Control device major number */ | |
/* This struct will describe our hook procedure. */ | |
struct nf_hook_ops lwfw_hook_in, lwfw_hook_out; | |
/* Actual rule 'definitions'. */ | |
/* TODO: One day LWFW might actually support many simultaneous rules. | |
* Just as soon as I figure out the list_head mechanism... */ | |
static unsigned int deny_ip = 0x00000000; /* IP address to deny */ | |
static unsigned short deny_port = 0x0000; /* TCP port to deny */ | |
/* | |
* This is the interface device's file_operations structure | |
*/ | |
struct file_operations lwfw_fops; | |
MODULE_AUTHOR("Kevin Wang"); | |
MODULE_DESCRIPTION("(Light-Weight Firewall)++ for Linux 2.4"); | |
MODULE_LICENSE("GPLv3"); | |
/* | |
* This is the function that will be called by the hook | |
*/ | |
unsigned int lwfw_hookfn(unsigned int hooknum, struct sk_buff *skb, const struct net_device *in, const struct net_device *out, int (*okfn)(struct sk_buff *)) { | |
unsigned int ret = NF_ACCEPT; | |
/* If LWFW is not currently active, immediately return ACCEPT */ | |
if (!active) return NF_ACCEPT; | |
if (!skb) { | |
printk("\nLWFW: Unable to load packet"); | |
return NF_ACCEPT; | |
} | |
// check IP layer | |
ret = traverse_firewall_chain(skb); | |
return ret; /* We are happy to keep the packet */ | |
} | |
// do filter | |
static int traverse_firewall_chain(struct sk_buff *skb) | |
{ | |
char ip_src[16],ip_dst[16]; | |
struct firewall_rule *tmp_rule; | |
// get ip header | |
struct iphdr * ip = ip_hdr(skb); | |
struct udphdr *udp; | |
struct tcphdr *tcp; | |
unsigned int sport, dport, defaultAction = NF_ACCEPT; | |
if (!ip) { | |
printk("\nLWFW: Not IP packet"); | |
return NF_ACCEPT; | |
} | |
inet_ntoa(ip_src, ip->saddr); | |
inet_ntoa(ip_dst, ip->daddr); | |
printk("\nLWFW: checking IP src: %s, dst: %s", ip_src, ip_dst); | |
list_for_each_entry(tmp_rule, &rules.list, list) { | |
if (!tmp_rule->ip) | |
continue; | |
// match ip address | |
if (tmp_rule->ip->saddr == ip->saddr) | |
printk(" IP src(%s) matches.", ip_src); | |
else if (tmp_rule->ip->saddr != 0) // address mismatch, accpet packet | |
continue; | |
if (tmp_rule->ip->daddr == ip->daddr) | |
printk(" IP dst(%s) matches.", ip_dst); | |
else if (tmp_rule->ip->daddr != 0) // address mismatch, accpet packet | |
continue; | |
// start to check Layer 4 protocol: TCP/UDP/ICMP | |
switch (ip->protocol) { | |
case IPPROTO_UDP: | |
if (!tmp_rule->udp) | |
break; | |
udp = udp_hdr(skb); | |
sport = ntohs(udp->source); | |
dport = ntohs(udp->dest); | |
printk("\nLWFW: checking UDP sport: %d, dport: %d", sport, dport); | |
// match ports | |
if (tmp_rule->udp->dest == udp->dest) | |
printk(" UDP dport(%d) matches.", dport); | |
else if (tmp_rule->udp->dest != 0) // port mismatch, accpet packet | |
continue; | |
if (tmp_rule->udp->source == udp->source) | |
printk(" UDP sport(%d) matches.", sport); | |
else if (tmp_rule->udp->source != 0) // port mismatch, accpet packet | |
continue; | |
break; | |
case IPPROTO_TCP: | |
if (!tmp_rule->tcp) | |
break; | |
tcp = tcp_hdr(skb); | |
sport = ntohs(tcp->source); | |
dport = ntohs(tcp->dest); | |
printk("\nLWFW: checking TCP sport: %d, dport: %d", sport, dport); | |
// match ports | |
if (tmp_rule->tcp->dest == tcp->dest) | |
printk(" TCP dport(%d) matches.", dport); | |
else if (tmp_rule->tcp->dest != 0) // port mismatch, accpet packet | |
continue; | |
if (tmp_rule->tcp->source == tcp->source) | |
printk(" TCP sport(%d) matches.", sport); | |
else if (tmp_rule->tcp->source != 0) // port mismatch, accpet packet | |
continue; | |
break; | |
default: | |
break; // do nothing | |
} | |
// well, seems this rule match the packet, drop it | |
return NF_DROP; | |
} | |
return defaultAction; | |
} | |
// get ip address from int (linux/inet.h does not provide this function) | |
static const char* inet_ntoa(char* ipaddr, unsigned int ip) { | |
sprintf(ipaddr,"%d.%d.%d.%d",ip & 0x000000FF, (ip & 0x0000FF00) >> 8, | |
(ip & 0x00FF0000) >> 16, (ip & 0xFF000000) >> 24); | |
return ipaddr; | |
} | |
static int append_rule(struct firewall_rule *rule) { | |
list_add_tail(&(rule->list), &(rules.list)); | |
return 0; | |
} | |
static int delete_rule(struct firewall_rule *rule) { | |
list_del(&(rule->list)); | |
if (rule->ip) | |
kfree(rule->ip); | |
if (rule->tcp) | |
kfree(rule->tcp); | |
if (rule->udp) | |
kfree(rule->udp); | |
kfree(rule); | |
return 0; | |
} | |
/*********************************************/ | |
/* | |
* File operations functions for control device | |
*/ | |
static long lwfw_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | |
{ | |
int ret = 0; | |
switch (cmd) { | |
case LWFW_GET_VERS: | |
return LWFW_VERS; | |
case LWFW_ACTIVATE: | |
active = 1; | |
printk("\nLWFW: Activated."); | |
if (!deny_ip && !deny_port) | |
printk("\nLWFW: No deny options set."); | |
break; | |
case LWFW_DEACTIVATE: | |
active ^= active; | |
printk("\nLWFW: Deactivated."); | |
break; | |
default: | |
ret = -EBADRQC; | |
}; | |
return ret; | |
} | |
/* Called whenever open() is called on the device file */ | |
static int lwfw_open(struct inode *inode, struct file *file) | |
{ | |
if (lwfw_ctrl_in_use) { | |
return -EBUSY; | |
} else { | |
// MOD_INC_USE_COUNT; | |
lwfw_ctrl_in_use++; | |
return 0; | |
} | |
return 0; | |
} | |
/* Called whenever close() is called on the device file */ | |
static int lwfw_release(struct inode *inode, struct file *file) { | |
lwfw_ctrl_in_use ^= lwfw_ctrl_in_use; | |
return 0; | |
} | |
static int read_rules(void) { | |
struct firewall_rule *tmp_rule; | |
// insert hard-coded rules here. actually we can read from cmd as well | |
// rule#1 ufw deny out to 66.220.152.19 port 80 proto tcp | |
tmp_rule = (struct firewall_rule *) kmalloc(sizeof(struct firewall_rule), GFP_KERNEL); | |
memset(&tmp_rule, 0, sizeof(struct firewall_rule)); | |
if (!tmp_rule) // memory allocation fail | |
return 0; | |
INIT_LIST_HEAD(&tmp_rule->list); | |
tmp_rule->ip = (struct iphdr *) kmalloc(sizeof(struct iphdr), GFP_KERNEL); | |
memset(&tmp_rule->ip, 0, sizeof(struct iphdr)); | |
tmp_rule->ip->daddr = in_aton("66.220.152.19"); | |
tmp_rule->tcp = (struct tcphdr *) kmalloc(sizeof(struct tcphdr), GFP_KERNEL); | |
memset(&tmp_rule->tcp, 0, sizeof(struct tcphdr)); | |
tmp_rule->tcp->dest = htons(80); | |
append_rule(tmp_rule); | |
// rule#2 ufw deny out to 66.220.152.19 port 443 proto tcp | |
tmp_rule = (struct firewall_rule *) kmalloc(sizeof(struct firewall_rule), GFP_KERNEL); | |
memset(&tmp_rule, 0, sizeof(struct firewall_rule)); | |
if (!tmp_rule) // memory allocation fail | |
return 0; | |
INIT_LIST_HEAD(&tmp_rule->list); | |
tmp_rule->ip = (struct iphdr *) kmalloc(sizeof(struct iphdr), GFP_KERNEL); | |
memset(&tmp_rule->ip, 0, sizeof(struct iphdr)); | |
tmp_rule->ip->daddr = in_aton("66.220.152.19"); | |
tmp_rule->tcp = (struct tcphdr *) kmalloc(sizeof(struct tcphdr), GFP_KERNEL); | |
memset(&tmp_rule->tcp, 0, sizeof(struct tcphdr)); | |
tmp_rule->tcp->dest = htons(443); | |
append_rule(tmp_rule); | |
// rule#3 ufw deny from 10.219.219.203 to 192.168.1.2 port 23 proto tcp | |
tmp_rule = (struct firewall_rule *) kmalloc(sizeof(struct firewall_rule), GFP_KERNEL); | |
memset(&tmp_rule, 0, sizeof(struct firewall_rule)); | |
if (!tmp_rule) // memory allocation fail | |
return 0; | |
INIT_LIST_HEAD(&tmp_rule->list); | |
tmp_rule->ip = (struct iphdr *) kmalloc(sizeof(struct iphdr), GFP_KERNEL); | |
memset(&tmp_rule->ip, 0, sizeof(struct iphdr)); | |
tmp_rule->ip->saddr = in_aton("10.219.219.203"); | |
tmp_rule->ip->daddr = in_aton("192.168.1.2"); | |
tmp_rule->tcp = (struct tcphdr *) kmalloc(sizeof(struct tcphdr), GFP_KERNEL); | |
memset(&tmp_rule->tcp, 0, sizeof(struct tcphdr)); | |
tmp_rule->tcp->dest = htons(23); | |
append_rule(tmp_rule); | |
// rule#4 ufw deny out to 10.219.219.203 port 23 proto tcp | |
tmp_rule = (struct firewall_rule *) kmalloc(sizeof(struct firewall_rule), GFP_KERNEL); | |
memset(&tmp_rule, 0, sizeof(struct firewall_rule)); | |
if (!tmp_rule) // memory allocation fail | |
return 0; | |
INIT_LIST_HEAD(&tmp_rule->list); | |
tmp_rule->ip = (struct iphdr *) kmalloc(sizeof(struct iphdr), GFP_KERNEL); | |
memset(&tmp_rule->ip, 0, sizeof(struct iphdr)); | |
tmp_rule->ip->daddr = in_aton("10.219.219.203"); | |
tmp_rule->tcp = (struct tcphdr *) kmalloc(sizeof(struct tcphdr), GFP_KERNEL); | |
memset(&tmp_rule->tcp, 0, sizeof(struct tcphdr)); | |
tmp_rule->tcp->dest = htons(23); | |
append_rule(tmp_rule); | |
// rule#1 ufw deny out to 8.8.8.8 port 53 proto ucp | |
// a sample rule for block DNS service of 8.8.8.8 | |
tmp_rule = (struct firewall_rule *) kmalloc(sizeof(struct firewall_rule), GFP_KERNEL); | |
memset(&tmp_rule, 0, sizeof(struct firewall_rule)); | |
if (!tmp_rule) // memory allocation fail | |
return 0; | |
INIT_LIST_HEAD(&tmp_rule->list); | |
tmp_rule->ip = (struct iphdr *) kmalloc(sizeof(struct iphdr), GFP_KERNEL); | |
memset(&tmp_rule->ip, 0, sizeof(struct iphdr)); | |
tmp_rule->ip->daddr = in_aton("8.8.8.8"); | |
tmp_rule->udp = (struct udphdr *) kmalloc(sizeof(struct udphdr), GFP_KERNEL); | |
memset(&tmp_rule->udp, 0, sizeof(struct udphdr)); | |
tmp_rule->udp->dest = htons(53); | |
append_rule(tmp_rule); | |
return 0; | |
} | |
/*********************************************/ | |
/* | |
* Module initialisation and cleanup follow... | |
*/ | |
int init_module() { | |
lwfw_fops.unlocked_ioctl= &lwfw_ioctl; | |
lwfw_fops.open=&lwfw_open; | |
lwfw_fops.release=&lwfw_release; | |
/* Attempt to register the LWFW control device */ | |
if ((major = register_chrdev(LWFW_MAJOR, LWFW_NAME, &lwfw_fops)) < 0) { | |
printk("\nLWFW: Failed registering control device!"); | |
printk("\nLWFW: Module installation aborted."); | |
return major; | |
} | |
/* Make sure the usage marker for the control device is cleared */ | |
lwfw_ctrl_in_use ^= lwfw_ctrl_in_use; | |
printk("\nLWFW: Control device successfully registered."); | |
/* Now register the network hooks */ | |
lwfw_hook_in.hook = lwfw_hookfn; | |
lwfw_hook_in.hooknum = NF_INET_PRE_ROUTING; | |
lwfw_hook_in.pf = PF_INET; | |
lwfw_hook_in.priority = NF_IP_PRI_FIRST; | |
nf_register_hook(&lwfw_hook_in); | |
lwfw_hook_out.hook = lwfw_hookfn; | |
lwfw_hook_out.hooknum = NF_INET_POST_ROUTING; | |
lwfw_hook_out.pf = PF_INET; | |
lwfw_hook_out.priority = NF_IP_PRI_FIRST; | |
nf_register_hook(&lwfw_hook_out); | |
// init rules | |
printk("\nLWFW: Init firewall rules."); | |
INIT_LIST_HEAD(&rules.list); | |
read_rules(); | |
printk("\nLWFW: Module installation successful."); | |
return 0; | |
} | |
void cleanup_module() { | |
struct list_head *pos, *q; | |
/* Remove IPV4 hook */ | |
nf_unregister_hook(&lwfw_hook_in); | |
nf_unregister_hook(&lwfw_hook_out); | |
// free firewall rules chain | |
printk("\nLWFW: Empty firewall rules."); | |
list_for_each_safe(pos, q, &rules.list) | |
delete_rule(list_entry(pos, struct firewall_rule, list)); | |
/* Now unregister control device */ | |
unregister_chrdev(LWFW_MAJOR, LWFW_NAME); | |
printk("\nLWFW: Removal of module successful."); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* Include file for the Light-weight Fire Wall LKM. | |
* | |
* A very simple Netfilter module that drops backets based on either | |
* their incoming interface or source IP address. | |
* | |
* Written by Owen Klan - March 2003 | |
*/ | |
#ifndef __LWFW_INCLUDE__ | |
# define __LWFW_INCLUDE__ | |
/* NOTE: The LWFW_MAJOR symbol is only made available for kernel code. | |
* Userspace code has no business knowing about it. */ | |
# define LWFW_NAME "lwfw" | |
/* Version of LWFW */ | |
# define LWFW_VERS 0x0001 /* 0.1 */ | |
/* Definition of the LWFW_TALKATIVE symbol controls whether LWFW will | |
* print anything with printk(). This is included for debugging purposes. | |
*/ | |
#define LWFW_TALKATIVE | |
/* These are the IOCTL codes used for the control device */ | |
#define LWFW_CTRL_SET 0xFEED0000 /* The 0xFEED... prefix is arbitrary */ | |
#define LWFW_GET_VERS 0xFEED0001 /* Get the version of LWFM */ | |
#define LWFW_ACTIVATE 0xFEED0002 | |
#define LWFW_DEACTIVATE 0xFEED0003 | |
#define LWFW_GET_STATS 0xFEED0004 | |
#define LWFW_DENY_IP 0xFEED0006 | |
#define LWFW_DENY_PORT 0xFEED0007 | |
/* Control flags/Options */ | |
#define LWFW_IP_DENY_ACTIVE 0x00000002 | |
#define LWFW_PORT_DENY_ACTIVE 0x00000004 | |
/* | |
* From here on is used solely for the actual kernel module | |
*/ | |
#ifdef __KERNEL__ | |
# define LWFW_MAJOR 241 /* This exists in the experimental range */ | |
/* This macro is used to prevent dereferencing of NULL pointers. If | |
* a pointer argument is NULL, this will return -EINVAL */ | |
#define NULL_CHECK(ptr) \ | |
if ((ptr) == NULL) return -EINVAL | |
/* Macros for accessing options */ | |
#define DENY_IP_ACTIVE (lwfw_options & LWFW_IP_DENY_ACTIVE) | |
#define DENY_PORT_ACTIVE (lwfw_options & LWFW_PORT_DENY_ACTIVE) | |
#endif /* __KERNEL__ */ | |
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
obj-m += lwfw.o | |
#EXTRA_CFLAGS += -I/usr/include | |
all: | |
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules | |
clean: | |
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment