VirtualBox

source: vbox/trunk/src/VBox/NetworkServices/NAT/rtmon_linux.c@ 48956

Last change on this file since 48956 was 48956, checked in by vboxsync, 11 years ago

NetworkServices: Whitespace (including tabs!) and svn:keywords cleanups by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 6.2 KB
Line 
1/* -*- indent-tabs-mode: nil; -*- */
2#include "proxytest.h"
3
4#include <sys/types.h> /* must come before linux/netlink */
5#include <sys/socket.h>
6
7#include <asm/types.h>
8#include <linux/netlink.h>
9#include <linux/rtnetlink.h>
10
11#include <errno.h>
12#include <string.h>
13#include <unistd.h>
14
15
16static int rtmon_check_defaults(const void *buf, size_t len);
17
18
19/**
20 * Read IPv6 routing table - Linux rtnetlink version.
21 *
22 * XXX: TODO: To avoid re-reading the table we should subscribe to
23 * updates by binding a monitoring NETLINK_ROUTE socket to
24 * sockaddr_nl::nl_groups = RTMGRP_IPV6_ROUTE.
25 *
26 * But that will provide updates only. Documentation is scarce, but
27 * from what I've seen it seems that to get accurate routing info the
28 * monitoring socket needs to be created first, then full routing
29 * table requested (easier to do via spearate socket), then monitoring
30 * socket polled for input. The first update(s) of the monitoring
31 * socket may happen before full table is returned, so we can't just
32 * count the defaults, we need to keep track of their { oif, gw } to
33 * correctly ignore updates that are reported via monitoring socket,
34 * but that are already reflected in the full routing table returned
35 * in response to our request.
36 */
37int
38rtmon_get_defaults(void)
39{
40 int rtsock;
41 ssize_t nsent, ssize;
42 int ndefrts;
43
44 char *buf = NULL;
45 size_t bufsize;
46
47 struct {
48 struct nlmsghdr nh;
49 struct rtmsg rtm;
50 char attrbuf[512];
51 } rtreq;
52
53 memset(&rtreq, 0, sizeof(rtreq));
54 rtreq.nh.nlmsg_type = RTM_GETROUTE;
55 rtreq.nh.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
56 rtreq.rtm.rtm_family = AF_INET6;
57 rtreq.rtm.rtm_table = RT_TABLE_MAIN;
58 rtreq.rtm.rtm_protocol = RTPROT_UNSPEC;
59
60 rtreq.nh.nlmsg_len = NLMSG_SPACE(sizeof(rtreq.rtm));
61
62 bufsize = 1024;
63 ssize = bufsize;
64 for (;;) {
65 char *newbuf;
66 int recverr;
67
68 newbuf = (char *)realloc(buf, ssize);
69 if (newbuf == NULL) {
70 DPRINTF0(("rtmon: failed to %sallocate buffer\n",
71 buf == NULL ? "" : "re"));
72 free(buf);
73 return -1;
74 }
75
76 buf = newbuf;
77 bufsize = ssize;
78
79 /* it's easier to reopen than to flush */
80 rtsock = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
81 if (rtsock < 0) {
82 DPRINTF0(("rtmon: failed to create netlink socket: %s", strerror(errno)));
83 free(buf);
84 return -1;
85 }
86
87 nsent = send(rtsock, &rtreq, rtreq.nh.nlmsg_len, 0);
88 if (nsent < 0) {
89 DPRINTF0(("rtmon: RTM_GETROUTE failed: %s", strerror(errno)));
90 close (rtsock);
91 free(buf);
92 return -1;
93 }
94
95 ssize = recv(rtsock, buf, bufsize, MSG_TRUNC);
96 recverr = errno;
97 close (rtsock);
98
99 if (ssize < 0) {
100 DPRINTF(("rtmon: failed to read RTM_GETROUTE response: %s",
101 strerror(recverr)));
102 free(buf);
103 return -1;
104 }
105
106 if ((size_t)ssize <= bufsize) {
107 DPRINTF2(("rtmon: RTM_GETROUTE: %lu bytes\n",
108 (unsigned long)ssize));
109 break;
110 }
111
112 DPRINTF2(("rtmon: RTM_GETROUTE: truncated %lu to %lu bytes, retrying\n",
113 (unsigned long)ssize, (unsigned long)bufsize));
114 /* try again with larger buffer */
115 }
116
117 ndefrts = rtmon_check_defaults(buf, (size_t)ssize);
118 free(buf);
119
120 if (ndefrts == 0) {
121 DPRINTF(("rtmon: no IPv6 default routes found\n"));
122 }
123 else {
124 DPRINTF(("rtmon: %d IPv6 default route%s found\n",
125 ndefrts,
126 ndefrts == 1 || ndefrts == -1 ? "" : "s"));
127 }
128
129 return ndefrts;
130}
131
132
133/**
134 * Scan netlink message in the buffer for IPv6 default route changes.
135 */
136static int
137rtmon_check_defaults(const void *buf, size_t len)
138{
139 struct nlmsghdr *nh;
140 int dfltdiff = 0;
141
142 for (nh = (struct nlmsghdr *)buf;
143 NLMSG_OK(nh, len);
144 nh = NLMSG_NEXT(nh, len))
145 {
146 struct rtmsg *rtm;
147 struct rtattr *rta;
148 int attrlen;
149 int delta = 0;
150 const void *gwbuf;
151 size_t gwlen;
152 int oif;
153
154 DPRINTF2(("nlmsg type %d flags 0x%x\n",
155 nh->nlmsg_seq, nh->nlmsg_type, nh->nlmsg_flags));
156
157 if (nh->nlmsg_type == NLMSG_DONE) {
158 break;
159 }
160
161 if (nh->nlmsg_type == NLMSG_ERROR) {
162 struct nlmsgerr *ne = (struct nlmsgerr *)NLMSG_DATA(nh);
163 DPRINTF2(("> error %d\n", ne->error));
164 LWIP_UNUSED_ARG(ne);
165 break;
166 }
167
168 if (nh->nlmsg_type < RTM_BASE || RTM_MAX <= nh->nlmsg_type) {
169 /* shouldn't happen */
170 DPRINTF2(("> not an RTM message!\n"));
171 continue;
172 }
173
174
175 rtm = (struct rtmsg *)NLMSG_DATA(nh);
176 attrlen = RTM_PAYLOAD(nh);
177
178 if (nh->nlmsg_type == RTM_NEWROUTE) {
179 delta = +1;
180 }
181 else if (nh->nlmsg_type == RTM_DELROUTE) {
182 delta = -1;
183 }
184 else {
185 /* shouldn't happen */
186 continue;
187 }
188
189 /*
190 * Is this an IPv6 default route in the main table? (Local
191 * table always has ::/0 reject route, hence the last check).
192 */
193 if (rtm->rtm_family == AF_INET6 /* should always be true */
194 && rtm->rtm_dst_len == 0
195 && rtm->rtm_table == RT_TABLE_MAIN)
196 {
197 dfltdiff += delta;
198 }
199 else {
200 /* some other route change */
201 continue;
202 }
203
204
205 gwbuf = NULL;
206 gwlen = 0;
207 oif = -1;
208
209 for (rta = RTM_RTA(rtm);
210 RTA_OK(rta, attrlen);
211 rta = RTA_NEXT(rta, attrlen))
212 {
213 if (rta->rta_type == RTA_GATEWAY) {
214 gwbuf = RTA_DATA(rta);
215 gwlen = RTA_PAYLOAD(rta);
216 }
217 else if (rta->rta_type == RTA_OIF) {
218 /* assert RTA_PAYLOAD(rta) == 4 */
219 memcpy(&oif, RTA_DATA(rta), sizeof(oif));
220 }
221 }
222
223 /* XXX: TODO: note that { oif, gw } was added/removed */
224 LWIP_UNUSED_ARG(gwbuf);
225 LWIP_UNUSED_ARG(gwlen);
226 LWIP_UNUSED_ARG(oif);
227 }
228
229 return dfltdiff;
230}
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette