Skip to content

Commit ea22051

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 ea22051

File tree

5 files changed

+232
-1
lines changed

5 files changed

+232
-1
lines changed

Makefile

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,9 @@ clean:
1313

1414
check: all
1515
@scripts/verify.sh
16+
17+
CC := gcc
18+
BLOCKLIST := blocklist_user
19+
20+
blocklist:
21+
$(CC) ./$(BLOCKLIST).c -o ./$(BLOCKLIST).o

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

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

810+
/* Don't send packet from dest_vif's blocklist */
811+
if (blocklist_check(dest_vif->ndev->name, src_vif->ndev->name))
812+
continue;
813+
725814
if (__owl_ndo_start_xmit(vif, dest_vif, skb))
726815
count++;
727816
}
@@ -731,7 +820,9 @@ static netdev_tx_t owl_ndo_start_xmit(struct sk_buff *skb,
731820
list_for_each_entry (dest_vif, &vif->bss_list, bss_list) {
732821
if (ether_addr_equal(eth_hdr->h_dest,
733822
dest_vif->ndev->dev_addr)) {
734-
if (__owl_ndo_start_xmit(vif, dest_vif, skb))
823+
if (!blocklist_check(dest_vif->ndev->name,
824+
src_vif->ndev->name) &&
825+
__owl_ndo_start_xmit(vif, dest_vif, skb))
735826
count++;
736827
break;
737828
}
@@ -1782,6 +1873,7 @@ static void owl_free(void)
17821873
list_for_each_entry_safe (vif, safe, &owl->vif_list, list)
17831874
owl_delete_interface(vif);
17841875

1876+
kfree(owl->blocklist);
17851877
kfree(owl);
17861878
}
17871879

@@ -2832,6 +2924,7 @@ static int __init vwifi_init(void)
28322924
mutex_init(&owl->lock);
28332925
INIT_LIST_HEAD(&owl->vif_list);
28342926
INIT_LIST_HEAD(&owl->ap_list);
2927+
owl->blocklist = kmalloc(sizeof(char) * MAX_BLACKLIST_SIZE, GFP_KERNEL);
28352928

28362929
for (int i = 0; i < station; i++) {
28372930
struct wiphy *wiphy = owcfg80211_add();
@@ -2841,6 +2934,12 @@ static int __init vwifi_init(void)
28412934
goto interface_add;
28422935
}
28432936

2937+
nl_sk = netlink_kernel_create(&init_net, MAX_LINKS, &nl_config);
2938+
if (!nl_sk) {
2939+
pr_info("Error creating netlink socket\n");
2940+
goto cfg80211_add;
2941+
}
2942+
28442943
err = register_virtio_driver(&virtio_vwifi);
28452944
if (err)
28462945
goto err_register_virtio_driver;
@@ -2864,6 +2963,7 @@ static void __exit vwifi_exit(void)
28642963

28652964
unregister_virtio_driver(&virtio_vwifi);
28662965
owl_free();
2966+
netlink_kernel_release(nl_sk);
28672967
}
28682968

28692969
module_init(vwifi_init);

0 commit comments

Comments
 (0)