How to write custom module for ebtables? - linux

Basically, I want to write a kernel module that adds a possible filter to ebtables. Then I need to tell ebtables to use my filter on a bridge I have set up.
The reason I need to write my own module is that I want to introduce delay between consecutive packages (for some testing reason). To demonstrate, my network originally has a traffic like this:
+++-----------------+++-----------------+++-----------------+++-----------------
where + shows traffic of a package and - means no package on the line. I want to put a bridge in between so that the pattern of the packets would change to this:
+----+----+---------+----+----+---------+----+----+---------+----+----+---------
This means that I would make sure there would be a certain amount of delay between arrival of each packet.
Now I have written the following simple code which I basically took from linux-source/net/bridge/netfilter/ebt_ip.c:
static bool match(const struct sk_buff *skb, const struct xt_match_param *par)
{
printk(KERN_INFO"match called\n");
return true; // match everything!
}
static bool check(const struct xt_mtchk_param *par)
{
printk(KERN_INFO"check called\n");
return true; // pass everything!
}
static struct xt_match reg __read_mostly = {
.name = "any", // I made this up, but I tried also putting ip for example which didn't change anything.
.revision = 0,
.family = NFPROTO_BRIDGE,
.match = match,
.checkentry = check,
.matchsize = XT_ALIGN(4), // don't know what this is, so I just gave it an `int`
.me = THIS_MODULE
};
int init_module(void)
{
return xt_register_match(&reg);
}
void cleanup_module(void)
{
xt_unregister_match(&reg);
}
I successfully load the module. But it's as if it's not there. I'm not getting the logs inside match and check functions so the bridge is clearly not considering my filter. What am I doing wrong?
I have tried many combinations of loading my filter first, setting up the bridge first or setting ebtables rules first, but none of them change anything.
P.S. The bridge itself works. I am certain that ebtables is also in effect because if I add a policy to drop packages, I don't receive them on the final computer. What I can't figure out is how to tell ebtables to consider my filter also.

I got this working, not in the most elegant way, but anyway, I am writing it here for a future wanderer:
Let's say your filter name is: "any"
User-space plugin
You need headers that are not available outside the ebtables source. So, get the source code, and go to extensions folder. In the Makefile, add any to EXT_FUNC (that is targets to be built) and write the source file ebt_any.c like the following:
#include <stdio.h>
#include <getopt.h>
#include "../include/ebtables_u.h"
/*struct whatever
{
int a;
};*/
static struct option _any_opts[] =
{
{"use-any", required_argument, 0, 0},
{'\0'}
};
static void _any_help(void)
{
printf("any match options: nothing!\n");
}
static void _any_init(struct ebt_entry_match *match)
{
printf("any_init\n");
}
static void _any_check(const struct ebt_u_entry *entry, const struct ebt_entry_match *match, const char *name,
unsigned int hookmask, unsigned int time)
{
printf("any_check\n");
}
static int _any_parse(int c, char **argv, int argc, const struct ebt_u_entry *entry, unsigned int *flags, struct ebt_entry_match **match)
{
printf("any_parse: %d\n", c);
if (c == 0)
return 1;
return 0; // return true for anything
}
static int _any_compare(const struct ebt_entry_match *m1, const struct ebt_entry_match *m2)
{
/* struct whatever *w1 = (struct whatever *)m1->data;
struct whatever *w2 = (struct whatever *)m2->data;
if (w1->a != w2->a)
return 0;*/
return 1;
}
static void _any_print(const struct ebt_u_entry *entry, const struct ebt_entry_match *match)
{
printf("any_print");
}
static struct ebt_u_match _reg = {
.name = "any",
// .size = sizeof(struct whatever),
.help = _any_help,
.init = _any_init,
.parse = _any_parse,
.final_check = _any_check,
.print = _any_print,
.compare = _any_compare,
.extra_ops = _any_opts,
};
void _init(void)
{
ebt_register_match(&_reg);
}
Note: if you have data going from user-space to kernel space, write something instead of struct whatever. I have commented it out because I am not using anything.
Note: even if your program doesn't require an option (such as mine which was supposed to match everything), you need to give an option anyway because that's how ebtables knows to use your filter.
Note: some of these functions seem unnecessary, but if you don't write them, you get a "BUG: bad merge" error.
Kernel-space module
The kernel-space module is simpler:
#include <linux/netfilter/x_tables.h>
#include <linux/module.h>
#include <linux/kernel.h>
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Shahbaz Youssefi");
MODULE_ALIAS("ebt_any");
/*struct whatever
{
int a;
};*/
static bool match(const struct sk_buff *skb, const struct xt_match_param *par)
{
printk(KERN_INFO"Matching\n");
return true;
}
static bool check(const struct xt_mtchk_param *par)
{
printk(KERN_INFO"Checking\n");
return true;
}
static struct xt_match reg __read_mostly = {
.name = "any",
.match = match,
// .matchsize = sizeof(struct whatever),
.checkentry = check,
.me = THIS_MODULE
};
int init_module(void)
{
int ret = 0;
printk("Bridge initializing...\n");
ret = xt_register_match(&reg);
printk("Bridge initializing...done!\n");
return ret;
}
void cleanup_module(void)
{
printk("Bridge exiting...\n");
xt_unregister_match(&reg);
printk("Bridge exiting...done!\n");
}
Note: if you use struct whatever in user-space, you must use the same in kernel-space.
Note: unlike user-space plugin that use ebtables headers/functions, the kernel module uses xtables instead!!
Compile the module (fairly standard) and install it for automatic loading. Alternatively, you can insmod and rmmod the module yourself before adding/after removing ebtables rules.
How to make ebtables use your filter
Just add a rule that contains --use-any some_value and you're good. For example:
ebtables -A FORWARD --use-any 1 -j ACCEPT
Note: this --use-any is the option that was given in ebt_u_match reg.extra_ops (which was defined in array _any_opts) in the user space plugin.

To use a kernel module, you also need to write an appropriate plugin for the userspace program, and afterwards, insert a rule invoking it.
If you do not have any options, do not specify any .matchsize parameter in struct xt_match (equal to specifying 0).

Related

Does Arduino support the struct hack or similar solution in lieu of flexible array elements?

I coded an Arduino project for my son and learned about C in the process. All works fine but after dividing up the code into ten files and grouping the variables into structs in each file I'm not able to solve one wish for clarity. We need to empirically determine the best size of an array for storing and averaging port reads so this is what I want:
struct Alarms {
// Configurable parameters
const unsigned int number_of_reads = 24;
// State variables
int reads[number_of_reads]; // Error: invalid use of non-static data member 'Alarms::num_of_reads'
};
It’s simple but doesn't work. I tried flexible array members until I found that that feature is not supported in C++. Arduino compiles with C++. I tried many examples of the 'struct hack' but they all returned errors like this one:
struct Alarms {
// Configurable parameters
int number_of_reads = 24;
// State variables
int reads[];
} ar;
void setup_alarm() {
ar.reads = malloc(sizeof(int) * ar.number_of_reads); // Error: incompatible types in assignment of 'void*' to 'int [0]'
}
That looked promising but I suspect my ignorance is glowing brightly. Most struct hack examples call for declaring the struct and later initializing the struct variables. I’m hoping to not duplicate the struct.
I considered splitting the struct but that would be error prone and, well, another compile error:
struct Alarms2 {
int reads[ar.num_of_reads]; // Error: array bound is not an integer constant before ']' token
} ar2;
An alternative is to size the array and get the size later but it needs an explanation:
struct Alarms {
// Configurable parameters
int reads[ 24 ]; // Put number of reads to average between brackets
// State variables
int number_of_reads;
};
void setup_alarm() {
ar.number_of_reads = sizeof(ar.reads) / sizeof(ar.reads[0]); // this works
}
Is there a way to work the struct hack or some similar solution in Arduino to like achieve the first example?
The size of the struct must be known at compilation time. Const data types in structs can change per instance of the structure, that is why you are getting the invalid use of non-static data member 'Alarms::num_of_reads' when you try to initialize your array. The best way to solve this is to have an init_alarm and destroy_alarm functions. Like so ...
#include <stdio.h>
#include <stdlib.h>
#define DEFAULT_NUM_OF_READS (24)
struct alarm {
// Configurable parameters
const int number_of_reads;
// State variables
int *reads;
};
void init_alarm(struct alarm *alarm)
{
alarm->reads = (int *) malloc(alarm->number_of_reads * sizeof(int));
}
void destroy_alarm(struct alarm *alarm)
{
free(alarm->reads);
}
int main(int argc, char **argv)
{
// When we create our struct, set number_of_reads to default
struct alarm alarm = {.number_of_reads = DEFAULT_NUM_OF_READS, .reads = NULL};
init_alarm(&alarm);
alarm.reads[0] = 13;
alarm.reads[23] = 100;
printf("alarm.reads[0] = %d, alarm.reads[23] = %d\n", alarm.reads[0], alarm.reads[23]);
destroy_alarm(&alarm);
return 0;
}
Note: Inorder to use the designated initializer to initialize a structure you must compile with ANSI (C99) like so ...
gcc --std=c99 test.c -o test

memory corruption while executing my code

# include "stdafx.h"
# include <iostream>
#include <ctype.h>
using namespace std;
class a
{
protected:
int d;
public:
virtual void assign(int A) = 0;
int get();
};
class b : a
{
char* n;
public:
b()
{
n=NULL;
}
virtual ~b()
{
delete n;
}
void assign(int A)
{
d=A;
}
void assignchar(char *c)
{
n=c;
}
int get()
{
return d;
}
char* getchart()
{
return n;
}
};
class c : b
{
b *pB;
int e;
public:
c()
{
pB=new b();
}
~c()
{
delete pB;
}
void assign(int A)
{
e=A;
pB->assign(A);
}
int get()
{
return e;
}
b* getp()
{
return pB;
}
};
int _tmain(int argc, _TCHAR* argv[])
{
c *pC=new c();
pC->assign(10);
b *p=pC->getp();
p->assignchar("a");
char *abc=p->getchart();
delete pC;
cout<<*abc<<endl;
getchar();
}
i'm a noob at c++ and was experimenting when i got to this point. I don't understand why i keep getting a memory corruption message from VS2010. I am trying to replicate a problem which is at a higher level by breaking it down into smaller bits, any help would be appreciated.
From a cursory glance, you are passing a static char array to AssignChar that cannot be deleted (ie when you type "A" into your code, its a special block of memory the compiler allocates for you).
You need to understand what assignment of a char* does (or any pointer to type). When you call n=c you are just assigning the pointer, the memory that pointer points to remains where it is. So, unless this is exactly what you meant to do, you will have 2 pointers pointing to the same block of memory.. and you need to decide which to delete (you can't delete it twice, that'd be bad).
My advice here is to start using C++, so no more char* types, use std::string instead. Using char* is C programming. Note that if you did use a std::string, and passed one to assignChars, it would copy as you expected (and there is no need to free std::string objects in your destructor, they handle all that for you).
The problem occurs when you're trying to delete pC.
When ~c() destructor calls ~b() destructor - you're trying to delete n;.
The problem is that after assignchar(), n points to a string literal which was given to it as an argument ("a").
That string is not dynamically allocated, and should not be freed, meaning you should either remove the 'delete n;' line, or give a dynamically-allocated string to assignchar() as an argument.

IOCTL Method - Linux

I have an exam question and I can't quite see how to solve it.
A driver that needs the ioctl method to be implemented and tested.
I have to write the ioctl() method, the associated test program as well as the common IOCTL definitions.
The ioctl() method should only handle one command. In this command, I need to transmit a data structure from user space to kernel space.
Below is the structure shown:
struct data
{
     char label [10];
     int value;
}
The driver must print the IOCTL command data, using printk();
Device name is "/dev/mydevice"
The test program must validate driver mode using an initialized data structure.
Hope there are some that can help
thanks in advance
My suggestion:
static int f_on_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
unsigned long arg)
{
int ret;
switch (cmd)
{
case PASS_STRUCT:
struct data pass_data;
ret = copy_from_user(&pass_data, arg, sizeof(*pass_data));
if(ret < 0)
{
printk("PASS_STRUCT\n");
return -1;
}
printk(KERN ALERT "Message PASS_STRUCT : %d and %c\n",pass_data.value, pass_data.label);
break;
default:
return ENOTTY;
}
return 0;
}
Definitions:
Common.h
#define SYSLED_IOC_MAGIC 'k'
#define PASS_STRUCT _IOW(SYSLED_IOC_MAGIC, 1, struct data)
The test program:
int main()
{
int fd = open("/dev/mydevice", O_RDWR);
data data_pass;
data_pass.value = 2;
data_pass.label = "hej";
ioctl(fd, PASS_STRUCT, &data_pass);
close(fd);
return 0;
}
Is this completely wrong??

Which is the correct way to register a new net_device?

i'm trying to register a new net_device in linux...i can alloc and register it correctly and ifconfig shows it. The problem arrives when i try to put the interface up:
ifconfig my_dev up
A kernel freeze occurs...the problem is present only on x86 machines and i can't figure out the reason...on a pcc machine all works well. The code is very simple:
static struct net_device *my_dev;
static int veth_dev_init(struct net_device *dev);
static int veth_open(struct net_device *dev);
static int veth_close(struct net_device *dev);
static int veth_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd);
static struct veth_priv
{
...
};
static struct net_device_ops veth_ops =
{
.ndo_init = veth_dev_init,
.ndo_open = veth_open,
.ndo_stop = veth_close,
.ndo_do_ioctl = veth_ioctl
};
static int __init veth_init()
{
my_dev = alloc_netdev(sizeof(struct veth_priv), "my_dev", ether_setup);
if (my_dev == NULL)
return -ENOMEM;
my_dev->netdev_ops = &veth_ops;
register_netdev(my_dev);
return 0;
}
static void __exit veth_exit()
{
unregister_netdev(my_dev);
free_netdev(my_dev);
}
module_init(veth_init);
module_exit(veth_exit);
The first four functions veth_dev_init, veth_open, veth_close and veth_ioctl simply return 0.
Maybe is there a missing field in veth_ops structure?
Thank you all!
Yea, you missed one element in struct net_device_ops
Add .ndo_start_xmit also, And the function must return NETDEV_TX_OK or NETDEV_TX_BUSY.
use as follows
static netdev_tx_t veth_xmit(struct sk_buff *skb, struct net_device *dev)
{
return NETDEV_TX_OK;
}
And also change the open as
static int veth_open(struct net_device *dev)
{
memcpy(dev->dev_addr, "\0ABCD0", ETH_ALEN);
netif_start_queue(dev);
return 0;
}
Then in veth_ops
static struct net_device_ops veth_ops = {
.ndo_init = veth_dev_init,
.ndo_open = veth_open,
.ndo_stop = veth_close,
.ndo_start_xmit = veth_xmit,
.ndo_do_ioctl = veth_ioctl,
};
Then after inserting the module
give ifconfig my_dev 192.168.10.98 ...

Getting list of network devices inside the Linux kernel

I've been looking through net/core/dev.c and other files to try to find out how to get the list of network devices that are currently configured and it's proving to be a little difficult to find.
The end goal is to be able to get network device statistics using dev_get_stats in dev.c, but I need to know the current interfaces so I can grab the net_device struct to pass in. I'm having to do this inside the kernel as I'm writing a module which adds in a new /proc/ entry which relates to some statistics from the current network devices so from what I can gather this must be done inside the kernel.
If someone could point me to how to get the interfaces it would be much appreciated.
This ought to do the trick:
#include <linux/netdevice.h>
struct net_device *dev;
read_lock(&dev_base_lock);
dev = first_net_device(&init_net);
while (dev) {
printk(KERN_INFO "found [%s]\n", dev->name);
dev = next_net_device(dev);
}
read_unlock(&dev_base_lock);
Given a struct net *net identifying the net namespace that you are interested in, you should grab the dev_base_lock and use for_each_netdev():
read_lock(&dev_base_lock);
for_each_netdev(net, dev) {
/* Inspect dev */
}
read_unlock(&dev_base_lock);
(In newer kernels, you can use RCU instead, but that is probably an overcomplication in this case).
To obtain the net namespace to use, you should be registering your proc file with register_pernet_subsys():
static const struct file_operations foostats_seq_fops = {
.owner = THIS_MODULE,
.open = foostats_seq_open,
.read = seq_read,
.llseek = seq_lseek,
.release = foostats_seq_release,
};
static int foo_proc_init_net(struct net *net)
{
if (!proc_net_fops_create(net, "foostats", S_IRUGO,
&foostats_seq_fops))
return -ENOMEM;
return 0;
}
static void foo_proc_exit_net(struct net *net)
{
proc_net_remove(net, "foostats");
}
static struct pernet_operations foo_proc_ops = {
.init = foo_proc_init_net,
.exit = foo_proc_exit_net,
};
register_pernet_subsys(&foo_proc_ops)
In your foostats_seq_open() function, you take a reference on the net namespace, and drop it in the release function:
static int foostats_seq_open(struct inode *inode, struct file *file)
{
int err;
struct net *net;
err = -ENXIO;
net = get_proc_net(inode);
if (net == NULL)
goto err_net;
err = single_open(file, foostats_seq_show, net);
if (err < 0)
goto err_open;
return 0;
err_open:
put_net(net);
err_net:
return err;
}
static int foostats_seq_release(struct inode *inode, struct file *file)
{
struct net *net = ((struct seq_file *)file->private_data)->private;
put_net(net);
return single_release(inode, file);
}
The foostats_seq_show() function can then obtain the net, walk the devices, gather the statistics and produce the output:
static int sockstat6_seq_show(struct seq_file *seq, void *v)
{
struct net *net = seq->private;
struct net_device *dev;
int foostat, barstat;
read_lock(&dev_base_lock);
for_each_netdev(net, dev) {
/* Inspect dev */
}
read_unlock(&dev_base_lock);
seq_printf(seq, "Foo: %d\n", foostat);
seq_printf(seq, "Bar: %d\n", barstat);
return 0;
}

Resources