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
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
|
/* Description: testcase for netlink sockets migration.
* e.g.
* ip rule show
* ip rule add
* ip rule show
* ip rule del
* in a loop
*/
#include <asm/types.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <linux/netlink.h>
#include <string.h>
#include <linux/rtnetlink.h>
#include <stdlib.h>
#include <errno.h>
#include <signal.h>
#include <sys/wait.h>
#include <unistd.h>
#include "zdtmtst.h"
#undef DEBUG
//#define DEBUG
const char *test_doc = "Netlink socket loop";
const char *test_author = "Andrew Vagin (avagin@parallels.com)";
//buffer to hold the RTNETLINK request
struct {
struct nlmsghdr nl;
struct rtmsg rt;
char buf[8192];
} req;
// variables used for
// socket communications
int fd;
struct sockaddr_nl la;
struct sockaddr_nl pa;
struct msghdr msg;
struct iovec iov;
int rtn;
// buffer to hold the RTNETLINK reply(ies)
char buf[8192];
char dsts[24] = "192.168.0.255";
int pn = 32;//network prefix
// RTNETLINK message pointers & lengths
// used when processing messages
struct nlmsghdr *nlp;
int nll;
struct rtmsg *rtp;
int rtl;
struct rtattr *rtap;
int send_request(void);
int recv_reply(void);
int form_request_add(void);
int form_request_del(void);
int read_reply(void);
typedef int (*cmd_t)(void);
#define CMD_NUM 2
cmd_t cmd[CMD_NUM]={form_request_add, form_request_del};
int main(int argc, char *argv[])
{
int i;
test_init(argc, argv);
fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
if (fd<0){
pr_perror("socket");
goto out;
}
// setup local address & bind using
// this address
bzero(&la, sizeof(la));
la.nl_family = AF_NETLINK;
la.nl_pid = getpid();
if (bind(fd, (struct sockaddr*) &la, sizeof(la))){
pr_perror("bind failed");
goto out;
}
//Preparation:
form_request_del();
send_request();
recv_reply();
test_daemon();
while (test_go()){
for (i=0; i < CMD_NUM; i++){
cmd[i]();
if (send_request() < 0){
fail("send_request failed");
goto out;
};
if (recv_reply() < 0){
fail("RTNETLINK answers: %m");
goto out;
};
#ifdef DEBUG
if (read_reply() < 0){
fail("read_reply failed");
goto out;
}
#endif
}
}
pass();
out:
return 0;
}
int send_request(void)
{
// create the remote address
// to communicate
bzero(&pa, sizeof(pa));
pa.nl_family = AF_NETLINK;
// initialize & create the struct msghdr supplied
// to the sendmsg() function
bzero(&msg, sizeof(msg));
msg.msg_name = (void *) &pa;
msg.msg_namelen = sizeof(pa);
// place the pointer & size of the RTNETLINK
// message in the struct msghdr
iov.iov_base = (void *) &req.nl;
iov.iov_len = req.nl.nlmsg_len;
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
// send the RTNETLINK message to kernel
rtn = sendmsg(fd, &msg, 0);
if (rtn<0){
pr_perror("sendmsg failed");
return -1;
}
return 0;
}
int recv_reply(void)
{
char *p;
// initialize the socket read buffer
bzero(buf, sizeof(buf));
p = buf;
nll = 0;
// read from the socket until the NLMSG_DONE is
// returned in the type of the RTNETLINK message
// or if it was a monitoring socket
while(1) {
rtn = recv(fd, p, sizeof(buf) - nll, 0);
if (rtn < 0) {
pr_perror("recv failed");
return -1;
}
if (rtn == 0) {
pr_err("EOF on netlink\n");
return -1;
}
nlp = (struct nlmsghdr *) p;
if(nlp->nlmsg_type == NLMSG_DONE)
return 0;
if (nlp->nlmsg_type == NLMSG_ERROR) {
struct nlmsgerr *err = (struct nlmsgerr*)NLMSG_DATA(nlp);
errno=-err->error;
if (errno) {
return -1;
}
return 0;
}
// increment the buffer pointer to place
// next message
p += rtn;
// increment the total size by the size of
// the last received message
nll += rtn;
if((la.nl_groups & RTMGRP_IPV4_ROUTE)
== RTMGRP_IPV4_ROUTE)
break;
}
return 0;
}
int read_reply(void)
{
//string to hold content of the route
// table (i.e. one entry)
char dsts[24], gws[24], ifs[16], ms[24];
// outer loop: loops thru all the NETLINK
// headers that also include the route entry
// header
nlp = (struct nlmsghdr *) buf;
for(; NLMSG_OK(nlp, nll); nlp = NLMSG_NEXT(nlp, nll))
{
// get route entry header
rtp = (struct rtmsg *) NLMSG_DATA(nlp);
// we are only concerned about the
// main route table
if(rtp->rtm_table != RT_TABLE_MAIN)
continue;
// init all the strings
bzero(dsts, sizeof(dsts));
bzero(gws, sizeof(gws));
bzero(ifs, sizeof(ifs));
bzero(ms, sizeof(ms));
// inner loop: loop thru all the attributes of
// one route entry
rtap = (struct rtattr *) RTM_RTA(rtp);
rtl = RTM_PAYLOAD(nlp);
for( ; RTA_OK(rtap, rtl); rtap = RTA_NEXT(rtap,rtl))
{
switch(rtap->rta_type)
{
// destination IPv4 address
case RTA_DST:
inet_ntop(AF_INET, RTA_DATA(rtap),
dsts, 24);
break;
// next hop IPv4 address
case RTA_GATEWAY:
inet_ntop(AF_INET, RTA_DATA(rtap),
gws, 24);
break;
// unique ID associated with the network
// interface
case RTA_OIF:
sprintf(ifs, "%d",
*((int *) RTA_DATA(rtap)));
default:
break;
}
}
sprintf(ms, "%d", rtp->rtm_dst_len);
test_msg("dst %s/%s gw %s if %s\n",
dsts, ms, gws, ifs);
}
return 0;
}
#define NLMSG_TAIL(nmsg) \
((struct rtattr *) (((void *) (nmsg)) + NLMSG_ALIGN((nmsg)->nlmsg_len)))
int form_request_del(void)
{
bzero(&req, sizeof(req));
req.nl.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
rtap = NLMSG_TAIL(&req.nl);
rtap->rta_type = RTA_DST;
rtap->rta_len = RTA_LENGTH(4);
inet_pton(AF_INET, dsts,
((char *)rtap) + sizeof(struct rtattr));
req.nl.nlmsg_len = NLMSG_ALIGN(req.nl.nlmsg_len) + RTA_ALIGN(rtap->rta_len);
req.nl.nlmsg_flags = NLM_F_CREATE | NLM_F_ACK | NLM_F_REQUEST;
req.nl.nlmsg_type = RTM_DELROUTE;
req.rt.rtm_family = AF_INET;
req.rt.rtm_table = RT_TABLE_MAIN;
req.rt.rtm_protocol = RTPROT_STATIC;
req.rt.rtm_scope = RT_SCOPE_UNIVERSE;
req.rt.rtm_type = RTN_UNICAST;
req.rt.rtm_dst_len = pn;
return 0;
}
int form_request_add(void)
{
int ifcn = 1; //interface number
bzero(&req, sizeof(req));
req.nl.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
rtap = NLMSG_TAIL(&req.nl);
rtap->rta_type = RTA_DST;
rtap->rta_len = RTA_LENGTH(4);
inet_pton(AF_INET, dsts,
((char *)rtap) + sizeof(struct rtattr));
req.nl.nlmsg_len = NLMSG_ALIGN(req.nl.nlmsg_len) + RTA_ALIGN(rtap->rta_len);
rtap = NLMSG_TAIL(&req.nl);
rtap->rta_type = RTA_OIF;//Output interface index
rtap->rta_len = RTA_LENGTH(sizeof(int));
memcpy(((char *)rtap) + sizeof(struct rtattr),
&ifcn, sizeof(int));
req.nl.nlmsg_len = NLMSG_ALIGN(req.nl.nlmsg_len) + RTA_ALIGN(rtap->rta_len);
req.nl.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_ACK;
req.nl.nlmsg_type = RTM_NEWROUTE;
req.rt.rtm_family = AF_INET;
req.rt.rtm_table = RT_TABLE_MAIN;
req.rt.rtm_protocol = RTPROT_STATIC;
req.rt.rtm_scope = RT_SCOPE_UNIVERSE;
req.rt.rtm_type = RTN_UNICAST;
req.rt.rtm_dst_len = pn;
return 0;
}
|