Skip to content

Commit 282b735

Browse files
committed
Support blocklist in vwifi
Enable ability to use blocklist to block packets from specified interface. Support blocklist in vwifi kernel module, used as interfaces pair such as "owl2 blocks owl1", allow maximum blocklist size to be 1024 bytes now and maintained as global content within struct owl_content. When we detect the packet's source interface and destination interface is in the blocklist, we discard the packet. Using userspace program with netlink to communicate with kernel and allow the ability to dynamically alter the blocklist maintaining in vwifi kernel module.
1 parent e5eb949 commit 282b735

File tree

4 files changed

+228
-1
lines changed

4 files changed

+228
-1
lines changed

README.md

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -345,6 +345,39 @@ PING 10.0.0.1 (10.0.0.1) 56(84) bytes of data.
345345
rtt min/avg/max/mdev = 0.054/0.141/0.342/0.117 ms
346346
```
347347

348+
### Blocklist test
349+
Additionally, vwifi also supports blocklist ability to allow some interfaces to block packets from certain interfaces.
350+
First, compile blocklist user program
351+
```
352+
$ gcc blocklist_user.c -o ./blocklist.o
353+
```
354+
Second, prepare your blocklist.txt and use it as the input of blocklist user program.
355+
```
356+
$ cat <path-of-blocklist>
357+
owl2 blocks owl1
358+
owl1 blocks owl2
359+
```
360+
```
361+
$ ./blocklist.o <path-of-blocklist>
362+
```
363+
You should expect the following output:
364+
```
365+
<content-of-blocklist>
366+
Configuring blocklist for vwifi...
367+
Message from vwifi: vwifi has received your blocklist
368+
```
369+
Then you can try to do the ping test again
370+
```
371+
$ sudo ip netns exec ns1 ping -c 4 10.0.0.3
372+
```
373+
You should see the following output:
374+
```
375+
PING 10.0.0.3 (10.0.0.3) 56(84) bytes of data.
376+
377+
--- 10.0.0.3 ping statistics ---
378+
4 packets transmitted, 0 received, 100% packet loss, time 3053ms
379+
```
380+
You can adjust the content of your blacklist and load it into vwifi anytime.
348381
## Testing environment (virtio)
349382
Below is our testing environment with virtio feature:
350383

blocklist_user.c

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
#include <linux/netlink.h>
2+
#include <stdio.h>
3+
#include <stdlib.h>
4+
#include <string.h>
5+
#include <sys/socket.h>
6+
#include <unistd.h>
7+
8+
#define MAX_PAYLOAD 1024
9+
#define LINE_LENGTH 20
10+
#define MAX_NETLINK_USER 31
11+
12+
int main(int argc, char *argv[])
13+
{
14+
/* Read interface pair from blocklist.txt */
15+
if (argc != 2) {
16+
printf("Error: Unspecified file name\n");
17+
exit(1);
18+
}
19+
char *filename = argv[1];
20+
FILE *fp = fopen(filename, "r");
21+
if (!fp) {
22+
printf("Error: Couldn't open file %s\n", filename);
23+
exit(1);
24+
}
25+
26+
char buffer[NLMSG_SPACE(MAX_PAYLOAD)];
27+
char read_buf[LINE_LENGTH];
28+
memset(buffer, '\0', sizeof(buffer));
29+
30+
for (int i = 1; fgets(read_buf, LINE_LENGTH, fp); i++) {
31+
if (strlen(read_buf) + strlen(buffer) < NLMSG_SPACE(MAX_PAYLOAD))
32+
strcat(buffer, read_buf);
33+
else {
34+
printf(
35+
"Error: Blocklist size exceeds the maximum size of buffer\n");
36+
exit(1);
37+
}
38+
}
39+
fclose(fp);
40+
41+
printf("%s\n", buffer);
42+
43+
int sock_fd = socket(PF_NETLINK, SOCK_RAW, MAX_NETLINK_USER);
44+
if (sock_fd < 0) {
45+
printf("Error: Can't open socket\n");
46+
exit(1);
47+
}
48+
49+
struct sockaddr_nl src_addr = {
50+
.nl_family = AF_NETLINK,
51+
.nl_pid = getpid(),
52+
};
53+
54+
bind(sock_fd, (struct sockaddr *) &src_addr, sizeof(src_addr));
55+
56+
struct sockaddr_nl dest_addr = {
57+
.nl_family = AF_NETLINK,
58+
.nl_pid = 0,
59+
.nl_groups = 0,
60+
};
61+
62+
struct nlmsghdr *nlh =
63+
(struct nlmsghdr *) calloc(1, NLMSG_SPACE(MAX_PAYLOAD));
64+
nlh->nlmsg_len = NLMSG_SPACE(MAX_PAYLOAD);
65+
nlh->nlmsg_pid = getpid();
66+
nlh->nlmsg_flags = 0;
67+
68+
strncpy(NLMSG_DATA(nlh), buffer, NLMSG_SPACE(MAX_PAYLOAD));
69+
70+
struct iovec iov = {
71+
.iov_base = (void *) nlh,
72+
.iov_len = nlh->nlmsg_len,
73+
};
74+
75+
struct msghdr msg = {
76+
.msg_name = (void *) &dest_addr,
77+
.msg_namelen = sizeof(dest_addr),
78+
.msg_iov = &iov,
79+
.msg_iovlen = 1,
80+
};
81+
82+
printf("Configuring blocklist for vwifi...\n");
83+
sendmsg(sock_fd, &msg, 0);
84+
85+
recvmsg(sock_fd, &msg, 0);
86+
printf("Message from vwifi: %s\n", NLMSG_DATA(nlh));
87+
88+
close(sock_fd);
89+
90+
return 0;
91+
}

scripts/blocklist.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
owl2 blocks owl1
2+
owl1 blocks owl2

vwifi.c

Lines changed: 102 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@
1414
#include <net/cfg80211.h>
1515
#include <uapi/linux/virtio_net.h>
1616

17+
#include <linux/netlink.h>
18+
#include <net/sock.h>
19+
1720
MODULE_LICENSE("Dual MIT/GPL");
1821
MODULE_AUTHOR("National Cheng Kung University, Taiwan");
1922
MODULE_DESCRIPTION("virtual cfg80211 driver");
@@ -60,6 +63,7 @@ struct owl_context {
6063
enum vwifi_state state; /**< indicate the program state */
6164
struct list_head vif_list; /**< maintaining all interfaces */
6265
struct list_head ap_list; /**< maintaining multiple AP */
66+
char *blocklist; /**< maintaining the blocklist */
6367
};
6468

6569
/* SME stands for "station management entity" */
@@ -150,6 +154,81 @@ MODULE_PARM_DESC(station, "Number of virtual interfaces running in STA mode.");
150154
/* Global context */
151155
static struct owl_context *owl = NULL;
152156

157+
/* Blocklist content */
158+
#define MAX_NETLINK_USER 31
159+
#define MAX_BLACKLIST_SIZE 1024
160+
161+
static struct sock *nl_sk = NULL;
162+
163+
static int blocklist_check(char *dest, char *source)
164+
{
165+
if (!owl->blocklist || !*(owl->blocklist))
166+
return 0;
167+
168+
char *user_input =
169+
kmalloc(sizeof(char) * (strlen(owl->blocklist) + 1), GFP_KERNEL);
170+
strncpy(user_input, owl->blocklist, strlen(owl->blocklist));
171+
172+
char *token = strsep(&user_input, "\n");
173+
while (token != NULL) {
174+
char *blacklist_dest = strsep(&token, " ");
175+
strsep(&token, " ");
176+
char *blacklist_source = token;
177+
if (!strcmp(dest, blacklist_dest) &&
178+
!strcmp(source, blacklist_source)) {
179+
kfree(user_input);
180+
return 1;
181+
}
182+
token = strsep(&user_input, "\n");
183+
}
184+
kfree(user_input);
185+
186+
return 0;
187+
}
188+
189+
static void blocklist_load(char *blist)
190+
{
191+
if (!owl->blocklist) {
192+
pr_info("owl->blocklist have to be kmalloc first\n");
193+
return;
194+
}
195+
memset(owl->blocklist, '\0', MAX_BLACKLIST_SIZE); /* clear the blocklist */
196+
strncpy(owl->blocklist, blist, strlen(blist));
197+
}
198+
199+
static void blocklist_nl_recv(struct sk_buff *skb)
200+
{
201+
struct nlmsghdr *nlh; /* netlink message header */
202+
int pid;
203+
struct sk_buff *skb_out;
204+
char *msg = "vwifi has received your blocklist";
205+
int msg_size = strlen(msg);
206+
207+
nlh = (struct nlmsghdr *) skb->data;
208+
209+
blocklist_load((char *) nlmsg_data(nlh));
210+
211+
/* pid of sending process */
212+
pid = nlh->nlmsg_pid;
213+
214+
skb_out = nlmsg_new(msg_size, 0);
215+
if (!skb_out) {
216+
pr_info("netlink: Failed to allocate new skb\n");
217+
return;
218+
}
219+
220+
nlh = nlmsg_put(skb_out, 0, 0, NLMSG_DONE, msg_size, 0);
221+
NETLINK_CB(skb_out).dst_group = 0; /* unicast group */
222+
strncpy(nlmsg_data(nlh), msg, msg_size);
223+
224+
if (nlmsg_unicast(nl_sk, skb_out, pid) < 0)
225+
pr_info("netlink: Error while sending back to user\n");
226+
}
227+
228+
struct netlink_kernel_cfg nl_config = {
229+
.input = blocklist_nl_recv,
230+
};
231+
153232
/**
154233
* enum virtio_vqs - queues for virtio frame transmission and receivement
155234
*
@@ -713,6 +792,13 @@ static netdev_tx_t owl_ndo_start_xmit(struct sk_buff *skb,
713792
}
714793
/* TX by interface of AP mode */
715794
else if (vif->wdev.iftype == NL80211_IFTYPE_AP) {
795+
/* Find the source interface */
796+
struct owl_vif *src_vif;
797+
list_for_each_entry (src_vif, &vif->bss_list, bss_list) {
798+
if (ether_addr_equal(eth_hdr->h_source, src_vif->ndev->dev_addr))
799+
break;
800+
}
801+
716802
/* Check if the packet is broadcasting */
717803
if (is_broadcast_ether_addr(eth_hdr->h_dest)) {
718804
list_for_each_entry (dest_vif, &vif->bss_list, bss_list) {
@@ -722,6 +808,10 @@ static netdev_tx_t owl_ndo_start_xmit(struct sk_buff *skb,
722808
dest_vif->ndev->dev_addr))
723809
continue;
724810

811+
/* Don't send packet from dest_vif's blocklist */
812+
if (blocklist_check(dest_vif->ndev->name, src_vif->ndev->name))
813+
continue;
814+
725815
if (__owl_ndo_start_xmit(vif, dest_vif, skb))
726816
count++;
727817
}
@@ -731,7 +821,9 @@ static netdev_tx_t owl_ndo_start_xmit(struct sk_buff *skb,
731821
list_for_each_entry (dest_vif, &vif->bss_list, bss_list) {
732822
if (ether_addr_equal(eth_hdr->h_dest,
733823
dest_vif->ndev->dev_addr)) {
734-
if (__owl_ndo_start_xmit(vif, dest_vif, skb))
824+
if (!blocklist_check(dest_vif->ndev->name,
825+
src_vif->ndev->name) &&
826+
__owl_ndo_start_xmit(vif, dest_vif, skb))
735827
count++;
736828
break;
737829
}
@@ -1782,6 +1874,7 @@ static void owl_free(void)
17821874
list_for_each_entry_safe (vif, safe, &owl->vif_list, list)
17831875
owl_delete_interface(vif);
17841876

1877+
kfree(owl->blocklist);
17851878
kfree(owl);
17861879
}
17871880

@@ -2832,6 +2925,7 @@ static int __init vwifi_init(void)
28322925
mutex_init(&owl->lock);
28332926
INIT_LIST_HEAD(&owl->vif_list);
28342927
INIT_LIST_HEAD(&owl->ap_list);
2928+
owl->blocklist = kmalloc(sizeof(char) * MAX_BLACKLIST_SIZE, GFP_KERNEL);
28352929

28362930
for (int i = 0; i < station; i++) {
28372931
struct wiphy *wiphy = owcfg80211_add();
@@ -2841,6 +2935,12 @@ static int __init vwifi_init(void)
28412935
goto interface_add;
28422936
}
28432937

2938+
nl_sk = netlink_kernel_create(&init_net, MAX_NETLINK_USER, &nl_config);
2939+
if (!nl_sk) {
2940+
pr_info("Error creating netlink socket\n");
2941+
goto cfg80211_add;
2942+
}
2943+
28442944
err = register_virtio_driver(&virtio_vwifi);
28452945
if (err)
28462946
goto err_register_virtio_driver;
@@ -2864,6 +2964,7 @@ static void __exit vwifi_exit(void)
28642964

28652965
unregister_virtio_driver(&virtio_vwifi);
28662966
owl_free();
2967+
netlink_kernel_release(nl_sk);
28672968
}
28682969

28692970
module_init(vwifi_init);

0 commit comments

Comments
 (0)