Skip to content

Commit 1829ede

Browse files
committed
Implementation of vwifi-tool
Implement a userspace tool called vwifi-tool to provide more flexibility and customization for users. Currently supporting features: * Display the status of vwifi driver * Configure user-specific blocklist We let vwifi-tool check on vwifi driver's status before user can specify any action on it by reading from `/sys/module/vwifi/initstate` to get the status of vwifi driver status. Support user-specific 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. Users can use vwifi-tool with command line options to specify their own blocklist pair, then vwifi-tool will copy their destination and source interfaces pair into a message buffer, and use netlink socket to communicate with kernel to allow the ability to dynamically alter the blocklist maintaining in vwifi kernel module. According to #48, we implement a tool `vwifi-tool` to set blocklist in order to filter packet which is unwanted and discard it when AP is forwarding the package also it can display the status of vwifi driver. So far the discarded package are simply being ignored by the program, we may need future improvement to delete them thoroughly. Resolves: #48
1 parent e5eb949 commit 1829ede

File tree

4 files changed

+363
-3
lines changed

4 files changed

+363
-3
lines changed

Makefile

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,17 @@ ccflags-y := -std=gnu99 -Wno-declaration-after-statement
55
KDIR ?= /lib/modules/$(shell uname -r)/build
66
GIT_HOOKS := .git/hooks/applied
77

8-
all:
8+
all: kmod vwifi-tool
9+
10+
kmod:
911
$(MAKE) -C $(KDIR) M=$(shell pwd) modules
1012

13+
vwifi-tool: vwifi-tool.c
14+
$(CC) $(ccflags-y) -o $@ $<
15+
1116
clean:
1217
$(MAKE) -C $(KDIR) M=$(shell pwd) clean
18+
$(RM) vwifi-tool
1319

1420
check: all
15-
@scripts/verify.sh
21+
@scripts/verify.sh

README.md

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -344,7 +344,70 @@ PING 10.0.0.1 (10.0.0.1) 56(84) bytes of data.
344344
4 packets transmitted, 4 received, 0% packet loss, time 3058ms
345345
rtt min/avg/max/mdev = 0.054/0.141/0.342/0.117 ms
346346
```
347+
### vwifi-tool
348+
A userspace tool which supports more user-specific utilization for vwifi.
349+
Aiming to provide more flexibility and customization for users of vwifi.
350+
Currently supporting feature:
351+
* display the status of vwifi driver
352+
* Use netlink socket to communicate with vwifi driver allowing user to configure user-specific block list
347353

354+
#### Status checking
355+
We can use `vwifi-tool` to check the status of vwifi driver by executing the following command:
356+
```
357+
$ ./vwifi-tool
358+
```
359+
If vwifi is loaded into kernel, you should see the following output:
360+
```
361+
vwifi status : live
362+
```
363+
Otherwise, vwifi isn't loaded into kernel yet, the output will be:
364+
```
365+
vwifi status : not loaded
366+
```
367+
368+
#### Blocklist test
369+
vwifi also supports blocklist ability to allow some interfaces to block packets from certain interfaces.
370+
We can use `vwifi-tool` to set or unset blocklist for vwifi, multiple options are explained as below
371+
* `-d` : specify the destination interface for a blocklist pair
372+
* `-s` : specify the source interface for a blocklist pair
373+
* `-c` : `1` means to unset the blocklist in vwifi, default as `0`
374+
375+
Set the blocklist pair using vwifi-tool like the following
376+
```
377+
$ ./vwifi-tool -d owl2 -s owl1
378+
```
379+
You should see the following output, including your blocklist which will be sent to vwifi
380+
```
381+
vwifi status : live
382+
blocklist:
383+
owl2 blocks owl1
384+
Configuring blocklist for vwifi...
385+
Message from vwifi: vwifi has received your blocklist
386+
```
387+
Then you can try to do the ping test again
388+
```
389+
$ sudo ip netns exec ns1 ping -c 4 10.0.0.3
390+
```
391+
You should see the following output:
392+
```
393+
PING 10.0.0.3 (10.0.0.3) 56(84) bytes of data.
394+
395+
--- 10.0.0.3 ping statistics ---
396+
4 packets transmitted, 0 received, 100% packet loss, time 3053ms
397+
```
398+
You can adjust the content of your blacklist and load it into vwifi anytime.
399+
400+
If you want to unset the blocklist in vwifi, simply add the option `-c` with vwifi-tool
401+
```
402+
$ ./vwifi-tool -c
403+
```
404+
You'll see the following output
405+
```
406+
vwifi status : live
407+
Unset blocklist for vwifi...
408+
Configuring blocklist for vwifi...
409+
Message from vwifi: vwifi has received your blocklist
410+
```
348411
## Testing environment (virtio)
349412
Below is our testing environment with virtio feature:
350413

vwifi-tool.c

Lines changed: 191 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,191 @@
1+
#include <getopt.h>
2+
#include <linux/netlink.h>
3+
#include <stdbool.h>
4+
#include <stdio.h>
5+
#include <stdlib.h>
6+
#include <string.h>
7+
#include <sys/socket.h>
8+
#include <unistd.h>
9+
10+
#define MAX_PAYLOAD 1024
11+
#define LINE_LENGTH 20
12+
#define MAX_BLOCKLIST_PAIR 5
13+
#define VWIFI_STATUS_FILE "/sys/module/vwifi/initstate"
14+
15+
16+
/* The function aims to check the status of vwifi kernel module */
17+
bool vwifi_status_check()
18+
{
19+
FILE *fp = fopen(VWIFI_STATUS_FILE, "r");
20+
if (!fp) {
21+
printf("vwifi status : not loaded\n");
22+
return false;
23+
}
24+
25+
char read_buf[LINE_LENGTH];
26+
fgets(read_buf, LINE_LENGTH, fp);
27+
read_buf[strcspn(read_buf, "\n")] =
28+
0; /* Remove newline character from string */
29+
if (!strcmp("live", read_buf))
30+
printf("vwifi status : live\n");
31+
else {
32+
printf("vwifi status : %s\n", read_buf);
33+
return false;
34+
}
35+
return true;
36+
}
37+
38+
/* Check if command line options are specified */
39+
bool opt_set(int d, int s, int c)
40+
{
41+
return d || s || c;
42+
}
43+
44+
/* Check whether the number of source interfaces matches with the number of
45+
* destination interfaces */
46+
bool blocklist_pair_check(int src_len, int dest_len)
47+
{
48+
return src_len == dest_len;
49+
}
50+
51+
/* Copy destination and source interface pair into blocklist buffer */
52+
bool blocklist_make(char *blocklist,
53+
char *dest[],
54+
char *src[],
55+
int blocklist_len)
56+
{
57+
for (int i = 0; i < blocklist_len; i++) {
58+
char tmp[LINE_LENGTH] = {'\0'};
59+
snprintf(tmp, LINE_LENGTH, "%s %s %s\n", dest[i], "blocks", src[i]);
60+
if (strlen(tmp) + strlen(blocklist) < NLMSG_SPACE(MAX_PAYLOAD))
61+
strcat(blocklist, tmp);
62+
else {
63+
printf(
64+
"Error: Blocklist size exceeds the maximum size of buffer\n");
65+
return false;
66+
}
67+
}
68+
return true;
69+
}
70+
71+
/* Send blocklist to kernel using netlink socket */
72+
bool blocklist_send(char *blocklist)
73+
{
74+
int sock_fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_USERSOCK);
75+
if (sock_fd < 0) {
76+
printf("Error: Can't open socket\n");
77+
return false;
78+
}
79+
80+
struct sockaddr_nl src_addr = {
81+
.nl_family = AF_NETLINK,
82+
.nl_pid = getpid(),
83+
};
84+
85+
bind(sock_fd, (struct sockaddr *) &src_addr, sizeof(src_addr));
86+
87+
struct sockaddr_nl dest_addr = {
88+
.nl_family = AF_NETLINK,
89+
.nl_pid = 0,
90+
.nl_groups = 0,
91+
};
92+
93+
struct nlmsghdr *nlh =
94+
(struct nlmsghdr *) calloc(1, NLMSG_SPACE(MAX_PAYLOAD));
95+
nlh->nlmsg_len = NLMSG_SPACE(MAX_PAYLOAD);
96+
nlh->nlmsg_pid = getpid();
97+
nlh->nlmsg_flags = 0;
98+
99+
strncpy(NLMSG_DATA(nlh), blocklist, NLMSG_SPACE(MAX_PAYLOAD));
100+
101+
struct iovec iov = {
102+
.iov_base = (void *) nlh,
103+
.iov_len = nlh->nlmsg_len,
104+
};
105+
106+
struct msghdr msg = {
107+
.msg_name = (void *) &dest_addr,
108+
.msg_namelen = sizeof(dest_addr),
109+
.msg_iov = &iov,
110+
.msg_iovlen = 1,
111+
};
112+
113+
printf("Configuring blocklist for vwifi...\n");
114+
sendmsg(sock_fd, &msg, 0);
115+
116+
recvmsg(sock_fd, &msg, 0);
117+
printf("Message from vwifi: %s\n", (char *) NLMSG_DATA(nlh));
118+
119+
close(sock_fd);
120+
121+
return true;
122+
}
123+
124+
int main(int argc, char *argv[])
125+
{
126+
/* Get opt arguments from command line to configure blocklist */
127+
char *dest[MAX_BLOCKLIST_PAIR], *src[MAX_BLOCKLIST_PAIR],
128+
blocklist_pair[MAX_BLOCKLIST_PAIR][LINE_LENGTH];
129+
int blocklist_len = 0, dest_len = 0, src_len = 0, clear = 0;
130+
int c;
131+
132+
while ((c = getopt(argc, argv, "d:s:ch")) != -1) {
133+
switch (c) {
134+
case 'd':
135+
dest[dest_len++] = optarg;
136+
break;
137+
case 's':
138+
src[src_len++] = optarg;
139+
break;
140+
case 'c':
141+
clear = 1;
142+
break;
143+
case 'h':
144+
printf(
145+
"vwifi-tool: A userspace tool which supports more "
146+
"user-specific utilization for vwifi\n\n");
147+
printf("Usage:\n\n");
148+
printf("\tvwifi-tool [arguments]\n\n");
149+
printf("The arguments are:\n\n");
150+
printf("\t-d Destination interface name\n");
151+
printf("\t-s Source interface name\n");
152+
printf("\t-c Clear blocklist\n");
153+
return 0;
154+
default:
155+
printf("Invalid arguments\n");
156+
break;
157+
}
158+
}
159+
160+
if (!vwifi_status_check())
161+
exit(1);
162+
163+
/* When no options are specified, simply display the status of vwifi */
164+
if (!opt_set(dest_len, src_len, clear))
165+
return 0;
166+
167+
if (!clear && !blocklist_pair_check(src_len, dest_len)) {
168+
printf("Destination number doesn't match with Source number\n");
169+
exit(1);
170+
}
171+
172+
blocklist_len =
173+
clear ? 0
174+
: (dest_len < MAX_BLOCKLIST_PAIR ? dest_len : MAX_BLOCKLIST_PAIR);
175+
176+
/* Copy blocklist pair into message buffer */
177+
char buffer[NLMSG_SPACE(MAX_PAYLOAD)];
178+
memset(buffer, '\0', sizeof(buffer));
179+
180+
if (!blocklist_make(buffer, dest, src, blocklist_len))
181+
exit(1);
182+
183+
if (!clear)
184+
printf("blocklist:\n%s", buffer);
185+
186+
/* Send blocklist buffer to kernel */
187+
if (!blocklist_send(buffer))
188+
exit(1);
189+
190+
return 0;
191+
}

0 commit comments

Comments
 (0)