Annotation of embedaddon/pimd/routesock.c, revision 1.1.1.1
1.1 misho 1: /*
2: * Copyright (c) 1998-2001
3: * University of Southern California/Information Sciences Institute.
4: * All rights reserved.
5: *
6: * Redistribution and use in source and binary forms, with or without
7: * modification, are permitted provided that the following conditions
8: * are met:
9: * 1. Redistributions of source code must retain the above copyright
10: * notice, this list of conditions and the following disclaimer.
11: * 2. Redistributions in binary form must reproduce the above copyright
12: * notice, this list of conditions and the following disclaimer in the
13: * documentation and/or other materials provided with the distribution.
14: * 3. Neither the name of the project nor the names of its contributors
15: * may be used to endorse or promote products derived from this software
16: * without specific prior written permission.
17: *
18: * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
19: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21: * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
22: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28: * SUCH DAMAGE.
29: */
30: /*
31: * Part of this program has been derived from mrouted.
32: * The mrouted program is covered by the license in the accompanying file
33: * named "LICENSE.mrouted".
34: *
35: * The mrouted program is COPYRIGHT 1989 by The Board of Trustees of
36: * Leland Stanford Junior University.
37: *
38: */
39:
40: #include <sys/param.h>
41: #include <sys/file.h>
42: #include "defs.h"
43: #include <sys/socket.h>
44: #include <net/route.h>
45: #ifdef HAVE_ROUTING_SOCKETS
46: #include <net/if_dl.h>
47: #endif
48: #include <arpa/inet.h>
49: #include <netdb.h>
50: #include <stdlib.h>
51:
52: /* All the BSDs have routing sockets (not Netlink), but only Linux seems
53: * to have SIOCGETRPF, which is used in the #else below ... the original
54: * authors wanted to merge routesock.c and netlink.c, but I don't know
55: * anymore. --Joachim */
56: #ifdef HAVE_ROUTING_SOCKETS
57: union sockunion {
58: struct sockaddr sa;
59: struct sockaddr_in sin;
60: struct sockaddr_dl sdl;
61: } so_dst, so_ifp;
62: typedef union sockunion *sup;
63: int routing_socket = -1;
64: int rtm_addrs;
65: static pid_t pid;
66: struct rt_metrics rt_metrics;
67: uint32_t rtm_inits;
68:
69: struct {
70: struct rt_msghdr m_rtm;
71: char m_space[512];
72: } m_rtmsg;
73:
74: /*
75: * Local functions definitions.
76: */
77: static int getmsg(struct rt_msghdr *, int, struct rpfctl *rpfinfo);
78:
79: /*
80: * TODO: check again!
81: */
82: #ifdef IRIX
83: #define ROUNDUP(a) ((a) > 0 ? (1 + (((a) - 1) | (sizeof(__uint64_t) - 1))) \
84: : sizeof(__uint64_t))
85: #else
86: #define ROUNDUP(a) ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) \
87: : sizeof(long))
88: #endif /* IRIX */
89:
90: #ifdef HAVE_SA_LEN
91: #define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
92: #else
93: #define ADVANCE(x, n) (x += ROUNDUP(sizeof(*(n)))) /* XXX: sizeof(struct sockaddr) */
94: #endif
95:
96: /* Open and initialize the routing socket */
97: int init_routesock(void)
98: {
99: #if 0
100: int on = 0;
101: #endif
102:
103: routing_socket = socket(PF_ROUTE, SOCK_RAW, 0);
104: if (routing_socket < 0) {
105: logit(LOG_ERR, errno, "Failed creating routing socket");
106: return -1;
107: }
108:
109: if (fcntl(routing_socket, F_SETFL, O_NONBLOCK) == -1) {
110: logit(LOG_ERR, errno, "Failed setting routing socket as non-blocking");
111: return -1;
112: }
113:
114: #if 0
115: /* XXX: if it is OFF, no queries will succeed (!?) */
116: if (setsockopt(routing_socket, SOL_SOCKET, SO_USELOOPBACK, (char *)&on, sizeof(on)) < 0) {
117: logit(LOG_ERR, errno , "setsockopt(SO_USELOOPBACK, 0)");
118: return -1;
119: }
120: #endif
121:
122: return 0;
123: }
124:
125: /* get the rpf neighbor info */
126: int k_req_incoming(uint32_t source, struct rpfctl *rpfp)
127: {
128: int rlen, l, flags = RTF_STATIC, retry_count = 3;
129: sup su;
130: static int seq;
131: char *cp = m_rtmsg.m_space;
132: struct rpfctl rpfinfo;
133:
134: /* TODO: a hack!!!! */
135: #ifdef HAVE_SA_LEN
136: #define NEXTADDR(w, u) \
137: if (rtm_addrs & (w)) { \
138: l = ROUNDUP(u.sa.sa_len); \
139: memcpy(cp, &(u), l); \
140: cp += l; \
141: }
142: #else
143: #define NEXTADDR(w, u) \
144: if (rtm_addrs & (w)) { \
145: l = ROUNDUP(sizeof(struct sockaddr)); \
146: memcpy(cp, &(u), l); \
147: cp += l; \
148: }
149: #endif /* HAVE_SA_LEN */
150:
151: /* initialize */
152: rpfp->rpfneighbor.s_addr = INADDR_ANY_N;
153: rpfp->source.s_addr = source;
154:
155: /* check if local address or directly connected before calling the
156: * routing socket
157: */
158: if ((rpfp->iif = find_vif_direct_local(source)) != NO_VIF) {
159: rpfp->rpfneighbor.s_addr = source;
160: return TRUE;
161: }
162:
163: /* prepare the routing socket params */
164: rtm_addrs |= RTA_DST;
165: rtm_addrs |= RTA_IFP;
166: su = &so_dst;
167: su->sin.sin_family = AF_INET;
168: #ifdef HAVE_SA_LEN
169: su->sin.sin_len = sizeof(struct sockaddr_in);
170: #endif
171: su->sin.sin_addr.s_addr = source;
172:
173: if (inet_lnaof(su->sin.sin_addr) == INADDR_ANY) {
174: IF_DEBUG(DEBUG_RPF) {
175: logit(LOG_DEBUG, 0, "k_req_incoming: Invalid source %s",
176: inet_fmt(source, s1, sizeof(s1)));
177: }
178:
179: return FALSE;
180: }
181:
182: so_ifp.sa.sa_family = AF_LINK;
183: #ifdef HAVE_SA_LEN
184: so_ifp.sa.sa_len = sizeof(struct sockaddr_dl);
185: #endif
186: flags |= RTF_UP;
187: flags |= RTF_HOST;
188: flags |= RTF_GATEWAY;
189: errno = 0;
190: memset (&m_rtmsg, 0, sizeof(m_rtmsg));
191:
192: #define rtm m_rtmsg.m_rtm
193: rtm.rtm_type = RTM_GET;
194: rtm.rtm_flags = flags;
195: rtm.rtm_version = RTM_VERSION;
196: rtm.rtm_seq = ++seq;
197: rtm.rtm_addrs = rtm_addrs;
198: rtm.rtm_rmx = rt_metrics;
199: rtm.rtm_inits = rtm_inits;
200:
201: NEXTADDR(RTA_DST, so_dst);
202: NEXTADDR(RTA_IFP, so_ifp);
203: rtm.rtm_msglen = l = cp - (char *)&m_rtmsg;
204:
205: rlen = write(routing_socket, &m_rtmsg, l);
206: if (rlen <= 0) {
207: IF_DEBUG(DEBUG_RPF | DEBUG_KERN) {
208: if (errno == ESRCH)
209: logit(LOG_DEBUG, 0, "Writing to routing socket: no such route");
210: else
211: logit(LOG_DEBUG, 0, "Error writing to routing socket");
212: }
213:
214: return FALSE;
215: }
216:
217: pid = getpid();
218:
219: while (1) {
220: rlen = read(routing_socket, &m_rtmsg, sizeof(m_rtmsg));
221: if (rlen < 0) {
222: if (errno == EINTR)
223: continue; /* Signalled, retry syscall. */
224: if (errno == EAGAIN && retry_count--) {
225: logit(LOG_DEBUG, 0, "Kernel busy, retrying (%d/3) routing socket read in one sec ...", 3 - retry_count);
226: sleep(1);
227: continue;
228: }
229:
230: IF_DEBUG(DEBUG_RPF | DEBUG_KERN)
231: logit(LOG_DEBUG, errno, "Read from routing socket failed");
232:
233: return FALSE;
234: }
235:
236: if (rlen > 0 && (rtm.rtm_seq != seq || rtm.rtm_pid != pid))
237: continue;
238:
239: break;
240: }
241:
242: memset(&rpfinfo, 0, sizeof(rpfinfo));
243: if (getmsg(&rtm, l, &rpfinfo)) {
244: rpfp->rpfneighbor.s_addr = rpfinfo.rpfneighbor.s_addr;
245: rpfp->iif = rpfinfo.iif;
246: }
247: #undef rtm
248:
249: return TRUE;
250: }
251:
252: static void find_sockaddrs(struct rt_msghdr *rtm, struct sockaddr **dst, struct sockaddr **gate,
253: struct sockaddr **mask, struct sockaddr_dl **ifp)
254: {
255: int i;
256: char *cp = (char *)(rtm + 1);
257: struct sockaddr *sa;
258:
259: if (rtm->rtm_addrs) {
260: for (i = 1; i; i <<= 1) {
261: if (i & rtm->rtm_addrs) {
262: sa = (struct sockaddr *)cp;
263:
264: switch (i) {
265: case RTA_DST:
266: *dst = sa;
267: break;
268:
269: case RTA_GATEWAY:
270: *gate = sa;
271: break;
272:
273: case RTA_NETMASK:
274: *mask = sa;
275: break;
276:
277: case RTA_IFP:
278: if (sa->sa_family == AF_LINK && ((struct sockaddr_dl *)sa)->sdl_nlen)
279: *ifp = (struct sockaddr_dl *)sa;
280: break;
281: }
282: ADVANCE(cp, sa);
283: }
284: }
285: }
286: }
287:
288: /*
289: * Returns TRUE on success, FALSE otherwise. rpfinfo contains the result.
290: */
291: static int getmsg(struct rt_msghdr *rtm, int msglen __attribute__((unused)), struct rpfctl *rpf)
292: {
293: struct sockaddr *dst = NULL, *gate = NULL, *mask = NULL;
294: struct sockaddr_dl *ifp = NULL;
295: struct in_addr in;
296: vifi_t vifi;
297: struct uvif *v;
298:
299: if (!rpf) {
300: logit(LOG_WARNING, 0, "Missing rpf pointer to routesock.c:getmsg()!");
301: return FALSE;
302: }
303:
304: rpf->iif = NO_VIF;
305: rpf->rpfneighbor.s_addr = INADDR_ANY;
306:
307: in = ((struct sockaddr_in *)&so_dst)->sin_addr;
308: IF_DEBUG(DEBUG_RPF)
309: logit(LOG_DEBUG, 0, "route to: %s", inet_fmt(in.s_addr, s1, sizeof(s1)));
310:
311: find_sockaddrs(rtm, &dst, &gate, &mask, &ifp);
312:
313: if (!ifp) { /* No incoming interface */
314: IF_DEBUG(DEBUG_RPF)
315: logit(LOG_DEBUG, 0, "No incoming interface for destination %s", inet_fmt(in.s_addr, s1, sizeof(s1)));
316:
317: return FALSE;
318: }
319:
320: if (dst && mask)
321: mask->sa_family = dst->sa_family;
322:
323: if (dst) {
324: in = ((struct sockaddr_in *)dst)->sin_addr;
325: IF_DEBUG(DEBUG_RPF)
326: logit(LOG_DEBUG, 0, " destination is: %s", inet_fmt(in.s_addr, s1, sizeof(s1)));
327: }
328:
329: if (gate && (rtm->rtm_flags & RTF_GATEWAY)) {
330: in = ((struct sockaddr_in *)gate)->sin_addr;
331: IF_DEBUG(DEBUG_RPF)
332: logit(LOG_DEBUG, 0, " gateway is: %s", inet_fmt(in.s_addr, s1, sizeof(s1)));
333:
334: rpf->rpfneighbor = in;
335: }
336:
337: for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) {
338: /* get the number of the interface by matching the name */
339: if ((strlen(v->uv_name) == ifp->sdl_nlen)
340: && !(strncmp(v->uv_name, ifp->sdl_data, ifp->sdl_nlen)))
341: break;
342: }
343:
344: /* Found inbound interface in vifi */
345: rpf->iif = vifi;
346:
347: IF_DEBUG(DEBUG_RPF)
348: logit(LOG_DEBUG, 0, " iif is %d", vifi);
349:
350: if (vifi >= numvifs) {
351: IF_DEBUG(DEBUG_RPF)
352: logit(LOG_DEBUG, 0, "Invalid incoming interface for destination %s, because of invalid virtual interface",
353: inet_fmt(in.s_addr, s1, sizeof(s1)));
354:
355: return FALSE; /* invalid iif */
356: }
357:
358: return TRUE;
359: }
360:
361:
362: #else /* !HAVE_ROUTING_SOCKETS -- if we want to run on Linux without Netlink */
363:
364: /* API compat dummy. */
365: int init_routesock(void)
366: {
367: return dup(udp_socket);
368: }
369:
370: /*
371: * Return in rpfcinfo the incoming interface and the next hop router
372: * toward source.
373: */
374: /* TODO: check whether next hop router address is in network or host order */
375: int k_req_incoming(uint32_t source, struct rpfctl *rpfcinfo)
376: {
377: rpfcinfo->source.s_addr = source;
378: rpfcinfo->iif = NO_VIF; /* Initialize, will be changed in kernel */
379: rpfcinfo->rpfneighbor.s_addr = INADDR_ANY; /* Initialize */
380:
381: if (ioctl(udp_socket, SIOCGETRPF, (char *) rpfcinfo) < 0) {
382: logit(LOG_WARNING, errno, "Failed ioctl SIOCGETRPF in k_req_incoming()");
383: return FALSE;
384: }
385:
386: return TRUE;
387: }
388: #endif /* HAVE_ROUTING_SOCKETS */
389:
390: /**
391: * Local Variables:
392: * version-control: t
393: * indent-tabs-mode: t
394: * c-file-style: "ellemtel"
395: * c-basic-offset: 4
396: * End:
397: */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>