VirtualBox

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

最後變更 在這個檔案從52822是 51574,由 vboxsync 提交於 10 年 前

NAT/Net: #define LOG_GROUP LOG_GROUP_NAT_SERVICE

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

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