-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathnetlink.cpp
139 lines (111 loc) · 3.76 KB
/
netlink.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
#include <netinet/in.h>
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
#include <net/if.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <QDebug>
#include "netlink.h"
bool Netlink::parse_route(struct nlmsghdr *nlh)
{
struct rtmsg *r = (struct rtmsg *) NLMSG_DATA(nlh);
int route_attribute_len = RTM_PAYLOAD(nlh);
if (r->rtm_table != RT_TABLE_MAIN) return false;
if (r->rtm_family != AF_INET) return false;
struct rtattr *route_attribute = (struct rtattr *) RTM_RTA(r);
for ( ; RTA_OK(route_attribute, route_attribute_len);
route_attribute = RTA_NEXT(route_attribute, route_attribute_len))
{
switch (route_attribute->rta_type) {
case RTA_SRC: // if route has any of these
case RTA_DST: // it isn't a default route
case RTA_IIF: // so return false.
return false;
default:
break;
}
}
return true;
}
void Netlink::run() {
qDebug("Netlink: Waiting for default route...");
struct sockaddr_nl addr;
int monsock, dumpsock, len;
char buffer[4096];
struct nlmsghdr *nlh;
if ((monsock = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE)) == -1) {
qDebug("Netlink: Unable to open netlink socket.");
return;
}
memset(&addr, 0, sizeof(addr));
addr.nl_family = AF_NETLINK;
addr.nl_groups = RTMGRP_IPV4_ROUTE;
if (bind(monsock, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
qDebug("Netlink: Unable to bind netlink socket.");
close(monsock);
return;
}
if ((dumpsock = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE)) == -1) {
qDebug("Netlink: Unable to open netlink socket.");
close(monsock);
return;
}
struct nlmsghdr *nlMsg;
char msgBuf[2048];
/* Initialize the buffer */
memset(msgBuf, 0, 2048);
/* point the header and the msg structure pointers into the buffer */
nlMsg = (struct nlmsghdr *)msgBuf;
/* Fill in the nlmsg header */
nlMsg->nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)); // Length of message.
nlMsg->nlmsg_type = RTM_GETROUTE; // Get the routes from kernel routing table .
nlMsg->nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST; // The message is a request for dump.
nlMsg->nlmsg_seq = 0; // Sequence of the message packet.
nlMsg->nlmsg_pid = getpid(); // PID of process sending the request.
/* Send the request */
if (send(dumpsock, nlMsg, nlMsg->nlmsg_len, 0) < 0) {
qDebug("Netlink: Unable to send netlink message.");
close(monsock);
close(dumpsock);
return;
}
nlh = (struct nlmsghdr *)buffer;
int done = 0;
while(!done) {
len = recv(dumpsock, nlh, 4096, 0);
while (NLMSG_OK(nlh, len)) {
if (nlh->nlmsg_type == RTM_NEWROUTE) {
if(parse_route(nlh)) {
close(dumpsock);
close(monsock);
qDebug("Netlink: Pre-existing default route.");
return;
}
} else if (nlh->nlmsg_type == NLMSG_DONE) {
done = 1;
}
nlh = NLMSG_NEXT(nlh, len);
}
}
close(dumpsock);
done = 0;
while(1) {
len = recv(monsock, nlh, 4096, 0);
while (!done && NLMSG_OK(nlh, len)) {
if (nlh->nlmsg_type == RTM_NEWROUTE) {
if(parse_route(nlh)) {
close(monsock);
qDebug("Netlink: Default route added.");
return;
}
} else if (nlh->nlmsg_type != NLMSG_DONE) {
done = 1;
}
nlh = NLMSG_NEXT(nlh, len);
}
}
qDebug("Netlink: Unreachable.");
return;
}