Skip to content

Commit 54b19ec

Browse files
committed
Implement userspace tool : vwifi-tool
An userspace tool vwifi-tool which can display the status of driver and allow users to specify blocklist. According to #48, we want a tool which can configure user-specific blocklist to filter unwanted packets from certain interfaces. This tool will show the status of vwifi driver by reading from `/sys/module/vwifi/initstate`, users can only set blocklist for vwifi driver when it's loaded. Users can use vwifi-tool with command line options which is enabled by `getopt()` to set or unset user-specific blocklist pair. The blocklist will be coppied and sent to the vwifi driver via netlink socket. Resolves: #48
1 parent e5eb949 commit 54b19ec

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)