I write Linux kernel module with netfilter hook. I want to block any packet that is not from my subnet.
Is there any simple method to get netmask of the interface in kernel-mode? I found only the way to get it using ioctl()
in user-mode.
There is a pretty easy way to get it.
Network device is described by struct net_device
.
<linux/netdevice.h>
:
struct net_device {
...
struct in_device __rcu *ip_ptr;
...
net_device
has a pointer to "inet" device (in_device
).
struct in_device {
...
struct in_ifaddr *ifa_list; /* IP ifaddr chain */
...
which finnaly points to chain of in_ifaddr
that contains all the interface info:
struct in_ifaddr {
struct hlist_node hash;
struct in_ifaddr *ifa_next;
struct in_device *ifa_dev;
struct rcu_head rcu_head;
__be32 ifa_local;
__be32 ifa_address;
__be32 ifa_mask;
__u32 ifa_rt_priority;
__be32 ifa_broadcast;
unsigned char ifa_scope;
unsigned char ifa_prefixlen;
__u32 ifa_flags;
char ifa_label[IFNAMSIZ];
/* In seconds, relative to tstamp. Expiry is at tstamp + HZ * lft. */
__u32 ifa_valid_lft;
__u32 ifa_preferred_lft;
unsigned long ifa_cstamp; /* created timestamp */
unsigned long ifa_tstamp; /* updated timestamp */
};
To make my answer more versatile, here is an abstract example (without binding to netfilter and skb devices logic):
struct in_ifaddr *ifa;
struct net_device *dev = dev_get_by_name(&init_net, "wlp7s0");
if(!dev) {
printk(KERN_ERR "Can't obtain device\n");
return;
}
// roughly
rcu_read_lock();
for(ifa = rcu_dereference(dev->ip_ptr->ifa_list);
ifa;
ifa = rcu_dereference(ifa->ifa_next))
printk("address: %pI4, mask: %pI4\n", &ifa->ifa_address, &ifa->ifa_mask);
rcu_read_unlock();
From example you can see that you can handle the whole chain(that @larsks mentioned in comment) depending on some specific logic.
P.S. don't forget to include <linux/netdevice.h>
and <linux/inetdevice.h>
.