Annotation of embedaddon/libpdel/net/uroute.c, revision 1.1.1.1
1.1 misho 1:
2: /*
3: * Copyright (c) 2001-2002 Packet Design, LLC.
4: * All rights reserved.
5: *
6: * Subject to the following obligations and disclaimer of warranty,
7: * use and redistribution of this software, in source or object code
8: * forms, with or without modifications are expressly permitted by
9: * Packet Design; provided, however, that:
10: *
11: * (i) Any and all reproductions of the source or object code
12: * must include the copyright notice above and the following
13: * disclaimer of warranties; and
14: * (ii) No rights are granted, in any manner or form, to use
15: * Packet Design trademarks, including the mark "PACKET DESIGN"
16: * on advertising, endorsements, or otherwise except as such
17: * appears in the above copyright notice or in the software.
18: *
19: * THIS SOFTWARE IS BEING PROVIDED BY PACKET DESIGN "AS IS", AND
20: * TO THE MAXIMUM EXTENT PERMITTED BY LAW, PACKET DESIGN MAKES NO
21: * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING
22: * THIS SOFTWARE, INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED
23: * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE,
24: * OR NON-INFRINGEMENT. PACKET DESIGN DOES NOT WARRANT, GUARANTEE,
25: * OR MAKE ANY REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS
26: * OF THE USE OF THIS SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY,
27: * RELIABILITY OR OTHERWISE. IN NO EVENT SHALL PACKET DESIGN BE
28: * LIABLE FOR ANY DAMAGES RESULTING FROM OR ARISING OUT OF ANY USE
29: * OF THIS SOFTWARE, INCLUDING WITHOUT LIMITATION, ANY DIRECT,
30: * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, PUNITIVE, OR CONSEQUENTIAL
31: * DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, LOSS OF
32: * USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY THEORY OF
33: * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
35: * THE USE OF THIS SOFTWARE, EVEN IF PACKET DESIGN IS ADVISED OF
36: * THE POSSIBILITY OF SUCH DAMAGE.
37: *
38: * Author: Archie Cobbs <archie@freebsd.org>
39: */
40:
41: #include <sys/types.h>
42: #include <sys/param.h>
43: #include <sys/socket.h>
44: #include <sys/sysctl.h>
45: #include <sys/sockio.h>
46: #include <sys/ioctl.h>
47:
48: #include <net/if.h>
49: #include <net/if_dl.h>
50: #include <net/if_types.h>
51: #include <net/route.h>
52:
53: #include <netinet/in.h>
54: #include <netinet/if_ether.h>
55: #include <arpa/inet.h>
56:
57: #include <stdio.h>
58: #include <stdlib.h>
59: #include <stdarg.h>
60: #include <unistd.h>
61: #include <assert.h>
62: #include <string.h>
63: #include <errno.h>
64: #include <err.h>
65:
66: #include "structs/structs.h"
67: #include "structs/type/array.h"
68:
69: #include "net/route_msg.h"
70: #include "net/uroute.h"
71: #include "util/typed_mem.h"
72:
73: #define ROUNDUP(a) \
74: ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
75: #define ADVANCE(x, n) ((x) += ROUNDUP((n)->sa_len))
76:
77: #ifdef RTF_CLONING
78: #define WRITABLE_FLAGS (RTF_STATIC | RTF_LLINFO | RTF_REJECT | RTF_BLACKHOLE \
79: | RTF_PROTO1 | RTF_PROTO2 | RTF_CLONING \
80: | RTF_XRESOLVE | RTF_UP | RTF_GATEWAY)
81: #else
82: #define WRITABLE_FLAGS (RTF_STATIC | RTF_REJECT | RTF_BLACKHOLE \
83: | RTF_PROTO1 | RTF_PROTO2 \
84: | RTF_XRESOLVE | RTF_UP | RTF_GATEWAY)
85: #endif
86:
87: struct route_flag {
88: const char *name;
89: int bit;
90: };
91:
92: static const struct route_flag route_flags[] = {
93: #define FLAG(x) { #x, RTF_ ## x }
94: FLAG(UP),
95: FLAG(GATEWAY),
96: FLAG(HOST),
97: FLAG(REJECT),
98: FLAG(DYNAMIC),
99: FLAG(MODIFIED),
100: FLAG(DONE),
101: #ifdef RTF_CLONING
102: FLAG(CLONING),
103: #endif
104: FLAG(XRESOLVE),
105: #ifdef RTF_LLINFO
106: FLAG(LLINFO),
107: #endif
108: FLAG(STATIC),
109: FLAG(BLACKHOLE),
110: FLAG(PROTO2),
111: FLAG(PROTO1),
112: FLAG(PRCLONING),
113: #ifdef RTF_WASCLONED
114: FLAG(WASCLONED),
115: #endif
116: FLAG(PROTO3),
117: FLAG(PINNED),
118: FLAG(LOCAL),
119: FLAG(BROADCAST),
120: FLAG(MULTICAST),
121: #undef FLAG
122: { NULL, 0 }
123: };
124:
125: /* Route structure */
126: struct uroute {
127: int flags;
128: struct sockaddr *dest;
129: struct sockaddr *gateway;
130: struct sockaddr *netmask;
131: };
132:
133: /*
134: * Internal functions
135: */
136: static int uroute_do_route(struct uroute *route, int sock, int type);
137: static const char *uroute_sockaddr_string(const struct sockaddr *sa);
138:
139: /*
140: * Create a new route.
141: */
142: struct uroute *
143: uroute_create(const struct sockaddr *dest, const struct sockaddr *gateway,
144: const struct sockaddr *netmask)
145: {
146: struct uroute *route;
147:
148: if (dest == NULL || gateway == NULL) {
149: errno = EINVAL;
150: return (NULL);
151: }
152: if ((route = MALLOC("uroute", sizeof(*route))) == NULL)
153: return (NULL);
154: memset(route, 0, sizeof(*route));
155: if ((route->dest = MALLOC("uroute.dest", dest->sa_len)) == NULL)
156: goto fail;
157: memcpy(route->dest, dest, dest->sa_len);
158: if ((route->gateway = MALLOC("uroute.gateway",
159: gateway->sa_len)) == NULL)
160: goto fail;
161: memcpy(route->gateway, gateway, gateway->sa_len);
162: if (netmask != NULL) {
163: if ((route->netmask = MALLOC("uroute.netmask",
164: netmask->sa_len)) == NULL)
165: goto fail;
166: memcpy(route->netmask, netmask, netmask->sa_len);
167: }
168: route->flags = RTF_STATIC;
169: return (route);
170:
171: fail:
172: /* Clean up */
173: uroute_destroy(&route);
174: return (NULL);
175: }
176:
177: /*
178: * Free a route.
179: */
180: void
181: uroute_destroy(struct uroute **routep)
182: {
183: struct uroute *const route = *routep;
184:
185: if (route == NULL)
186: return;
187: FREE("uroute.dest", route->dest);
188: FREE("uroute.gateway", route->gateway);
189: FREE("uroute.netmask", route->netmask);
190: FREE("uroute", route);
191: *routep = NULL;
192: }
193:
194: /*
195: * Get the destination address.
196: */
197: const struct sockaddr *
198: uroute_get_dest(struct uroute *route)
199: {
200: return (route->dest);
201: }
202:
203: /*
204: * Get the gateway address.
205: */
206: const struct sockaddr *
207: uroute_get_gateway(struct uroute *route)
208: {
209: return (route->gateway);
210: }
211:
212: /*
213: * Get the netmask.
214: *
215: * Returns NULL for a host route.
216: */
217: const struct sockaddr *
218: uroute_get_netmask(struct uroute *route)
219: {
220: return (route->netmask);
221: }
222:
223: /*
224: * Get the flags.
225: */
226: int
227: uroute_get_flags(struct uroute *route)
228: {
229: return (route->flags);
230: }
231:
232: /*
233: * Set the flags.
234: */
235: void
236: uroute_set_flags(struct uroute *route, int flags)
237: {
238: route->flags = flags;
239: }
240:
241: /*
242: * Add route to the kernel routing table.
243: */
244: int
245: uroute_add(struct uroute *route)
246: {
247: return (uroute_do_route(route, -1, RTM_ADD));
248: }
249:
250: /*
251: * Delete a route.
252: */
253: int
254: uroute_delete(struct uroute *route)
255: {
256: return (uroute_do_route(route, -1, RTM_DELETE));
257: }
258:
259: /*
260: * Get the installed kernel route that matches the destination "dest".
261: */
262: struct uroute *
263: uroute_get(const struct sockaddr *dest)
264: {
265: struct uroute *route = NULL;
266: struct route_msg *msg = NULL;
267: struct route_msg **list = NULL;
268: struct sockaddr_dl sdl;
269: int errno_save;
270: int sock = -1;
271: int num = 0;
272: int seq;
273: int i;
274:
275: /* Build new route message */
276: if ((msg = route_msg_create()) == NULL)
277: goto fail;
278: seq = route_msg_get_seq(msg);
279: route_msg_set_type(msg, RTM_GET);
280: if (route_msg_set_dest(msg, dest) == -1)
281: goto fail;
282: memset(&sdl, 0, sizeof(sdl));
283: sdl.sdl_type = IFT_OTHER;
284: sdl.sdl_len = 8;
285: sdl.sdl_family = AF_LINK;
286: if (route_msg_set_ifp(msg, (struct sockaddr *)&sdl) == -1)
287: goto fail;
288: route_msg_set_flags(msg, RTF_UP|RTF_GATEWAY|RTF_HOST|RTF_STATIC);
289:
290: /* Send request */
291: if ((sock = socket(PF_ROUTE, SOCK_RAW, 0)) == -1)
292: goto fail;
293: if (route_msg_send(msg, sock) == -1)
294: goto fail;
295: route_msg_destroy(&msg);
296: msg = NULL;
297:
298: /* Get response */
299: while (1) {
300:
301: /* Decode it */
302: if ((num = route_msg_recv(&list, sock, TYPED_MEM_TEMP)) == -1)
303: goto fail;
304:
305: /* Check returned messages for a match */
306: for (i = 0; i < num; i++) {
307: struct route_msg *const msg = list[i];
308:
309: if (route_msg_get_pid(msg) == getpid()
310: && route_msg_get_seq(msg) == seq) {
311: if ((route = uroute_create(route_msg_get_dest(
312: msg), route_msg_get_gateway(msg),
313: route_msg_get_netmask(msg))) == NULL)
314: goto fail;
315: break;
316: }
317: }
318: if (route != NULL)
319: break;
320:
321: /* Free list and try again */
322: for (i = 0; i < num; i++)
323: route_msg_destroy(&list[i]);
324: FREE(TYPED_MEM_TEMP, list);
325: list = NULL;
326: }
327:
328: fail:
329: /* Clean up and exit */
330: errno_save = errno;
331: if (sock != -1)
332: (void)close(sock);
333: if (msg != NULL)
334: route_msg_destroy(&msg);
335: if (list != NULL) {
336: for (i = 0; i < num; i++)
337: route_msg_destroy(&list[i]);
338: FREE(TYPED_MEM_TEMP, list);
339: }
340: errno = errno_save;
341: return (route);
342: }
343:
344: /*
345: * Build and send a route message by type.
346: */
347: static int
348: uroute_do_route(struct uroute *route, int sock, int type)
349: {
350: struct route_msg *msg;
351: int close_sock = 0;
352: int r = -1;
353: int flags;
354:
355: /* Create new route message */
356: if ((msg = route_msg_create()) == NULL)
357: return (-1);
358:
359: /* Open socket if requested */
360: if (sock == -1) {
361: if ((sock = socket(PF_ROUTE, SOCK_RAW, 0)) == -1)
362: goto fail;
363: close_sock = 1;
364: }
365:
366: /* Build message */
367: route_msg_set_type(msg, type);
368: flags = route->flags & WRITABLE_FLAGS;
369: flags |= RTF_UP;
370: if (route->gateway->sa_family != AF_LINK)
371: flags |= RTF_GATEWAY;
372: if (route->netmask == NULL)
373: flags |= RTF_HOST;
374: else
375: flags &= ~RTF_HOST;
376: route_msg_set_flags(msg, flags);
377: if (route_msg_set_dest(msg, route->dest) == -1)
378: goto fail;
379: if (route_msg_set_gateway(msg, route->gateway) == -1)
380: goto fail;
381: if (route_msg_set_netmask(msg, route->netmask) == -1)
382: goto fail;
383:
384: /* Send messsage */
385: r = route_msg_send(msg, sock);
386:
387: fail:
388: /* Clean up */
389: route_msg_destroy(&msg);
390: if (close_sock)
391: (void)close(sock);
392:
393: /* Done */
394: return (r);
395: }
396:
397: /*
398: * Get the entire routing table.
399: */
400: int
401: uroute_get_all(struct uroute ***listp, const char *mtype)
402: {
403: static int oid[6] = { CTL_NET, PF_ROUTE, 0, 0, NET_RT_DUMP, 0 };
404: static const int noid = sizeof(oid) / sizeof(*oid);
405: struct route_msg **list = NULL;
406: struct uroute **routes = NULL;
407: u_char *buf = NULL;
408: size_t actual;
409: size_t needed;
410: int num = 0;
411: int i;
412:
413: /* Get size estimate */
414: if (sysctl(oid, noid, NULL, &needed, NULL, 0) < 0)
415: goto fail;
416:
417: /* Allocate buffer for returned value */
418: if ((buf = MALLOC(TYPED_MEM_TEMP, needed)) == NULL)
419: goto fail;
420:
421: /* Get actual data */
422: actual = needed;
423: if (sysctl(oid, noid, buf, &actual, NULL, 0) < 0)
424: goto fail;
425:
426: /* Decode route messages */
427: if ((num = route_msg_decode(buf, actual, &list, TYPED_MEM_TEMP)) == -1)
428: goto fail;
429:
430: /* Create routes array from route message array */
431: if ((routes = MALLOC(mtype, num * sizeof(*routes))) == NULL)
432: goto fail;
433: memset(routes, 0, num * sizeof(*routes));
434: for (i = 0; i < num; i++) {
435: struct route_msg *const msg = list[i];
436:
437: if ((routes[i] = uroute_create(route_msg_get_dest(msg),
438: route_msg_get_gateway(msg),
439: route_msg_get_netmask(msg))) == NULL) {
440: while (i > 0)
441: uroute_destroy(&routes[--i]);
442: FREE(mtype, routes);
443: routes = NULL;
444: goto fail;
445: }
446: routes[i]->flags = route_msg_get_flags(msg);
447: }
448:
449: fail:
450: /* Clean up and exit */
451: if (buf != NULL)
452: FREE(TYPED_MEM_TEMP, buf);
453: if (list != NULL) {
454: for (i = 0; i < num; i++)
455: route_msg_destroy(&list[i]);
456: FREE(TYPED_MEM_TEMP, list);
457: }
458: if (routes != NULL) {
459: *listp = routes;
460: return (num);
461: }
462: return (-1);
463: }
464:
465: /*
466: * Print a route.
467: */
468: void
469: uroute_print(struct uroute *route, FILE *fp)
470: {
471: int didflag;
472: int i;
473:
474: fprintf(fp, "dest %s gateway %s",
475: uroute_sockaddr_string(route->dest),
476: uroute_sockaddr_string(route->gateway));
477: if (route->netmask != NULL) {
478: fprintf(fp, " netmask %s",
479: uroute_sockaddr_string(route->netmask));
480: }
481: fprintf(fp, " flags=<");
482: for (i = didflag = 0; route_flags[i].name != NULL; i++) {
483: if ((route->flags & route_flags[i].bit) != 0) {
484: if (didflag)
485: fprintf(fp, ",");
486: didflag = 1;
487: fprintf(fp, "%s", route_flags[i].name);
488: }
489: }
490: fprintf(fp, ">");
491: }
492:
493: static const char *
494: uroute_sockaddr_string(const struct sockaddr *sa)
495: {
496: static char buf[2][256];
497: static int n;
498: int i;
499:
500: n ^= 1;
501: switch (sa->sa_family) {
502: case AF_INET:
503: strlcpy(buf[n], inet_ntoa(((struct sockaddr_in *)(void *)
504: sa)->sin_addr), sizeof(buf[n]));
505: break;
506: case AF_LINK:
507: /* XXX implement me */
508: default:
509: snprintf(buf[n], sizeof(buf[n]), "{ len=%d af=%d data=[",
510: sa->sa_len, sa->sa_family);
511: for (i = 2; i < sa->sa_len; i++) {
512: snprintf(buf[n] + strlen(buf[n]),
513: sizeof(buf[n]) - strlen(buf[n]),
514: " %02X", ((u_char *)sa)[i]);
515: }
516: strlcat(buf[n], " ] }", sizeof(buf[n]));
517: }
518: return (buf[n]);
519: }
520:
521:
522: #ifdef UROUTE_TEST
523:
524: int
525: main(int ac, char **av)
526: {
527: struct sockaddr_in dest;
528: struct sockaddr_in gateway;
529: struct sockaddr_in netmask;
530: struct uroute *route = NULL;
531: int do_netmask = 0;
532: int fail = 0;
533: int cmd = 0;
534:
535: memset(&dest, 0, sizeof(dest));
536: dest.sin_family = AF_INET;
537: dest.sin_len = sizeof(dest);
538: memset(&gateway, 0, sizeof(gateway));
539: gateway.sin_family = AF_INET;
540: gateway.sin_len = sizeof(gateway);
541: memset(&netmask, 0, sizeof(netmask));
542: netmask.sin_family = AF_INET;
543: netmask.sin_len = sizeof(netmask);
544:
545: av++;
546: ac--;
547: switch (ac) {
548: case 4:
549: if (inet_aton(av[3], &netmask.sin_addr))
550: ;
551: else {
552: u_long haddr;
553:
554: if (sscanf(av[3], "%lu", &haddr) != 1)
555: err(1, "invalid netmask \"%s\"", av[3]);
556: netmask.sin_addr.s_addr = htonl(haddr);
557: }
558: do_netmask = 1;
559: // fall through
560: case 3:
561: if (!inet_aton(av[2], &gateway.sin_addr))
562: err(1, "invalid IP address \"%s\"", av[2]);
563: if (!strcmp(av[0], "add"))
564: cmd = 1;
565: else if (!strcmp(av[0], "delete"))
566: cmd = 2;
567: else {
568: fail = 1;
569: break;
570: }
571: if (!inet_aton(av[1], &dest.sin_addr))
572: err(1, "invalid IP address \"%s\"", av[1]);
573: if ((route = uroute_create((struct sockaddr *)&dest,
574: (struct sockaddr *)&gateway,
575: do_netmask ? (struct sockaddr *)&netmask : NULL)) == NULL)
576: err(1, "uroute_create");
577: break;
578: case 2:
579: if (strcmp(av[0], "get") != 0) {
580: fail = 1;
581: break;
582: }
583: if (!inet_aton(av[1], &dest.sin_addr))
584: err(1, "invalid IP address \"%s\"", av[1]);
585: break;
586: case 1:
587: if (strcmp(av[0], "list") != 0) {
588: fail = 1;
589: break;
590: }
591: // fall through
592: case 0:
593: cmd = 3;
594: break;
595: default:
596: fail = 1;
597: break;
598: }
599: if (fail) {
600: fprintf(stderr, "Usage: uroute <add | delete | get | list>"
601: " [dest [ gateway [netmask] ]]\n");
602: exit(1);
603: }
604:
605: switch (cmd) {
606: case 0: // get
607: if ((route = uroute_get((struct sockaddr *)&dest)) == NULL)
608: err(1, "uroute_get");
609: uroute_print(route, stdout);
610: printf("\n");
611: uroute_destroy(&route);
612: break;
613: case 1: // add
614: if (uroute_add(route) == -1)
615: err(1, "uroute_add");
616: uroute_destroy(&route);
617: break;
618: case 2: // delete
619: if (uroute_delete(route) == -1)
620: err(1, "uroute_delete");
621: uroute_destroy(&route);
622: break;
623: case 3: // list
624: {
625: struct uroute **list;
626: int num;
627: int i;
628:
629: if ((num = uroute_get_all(&list, "main")) == -1)
630: err(1, "uroute_get_all");
631: for (i = 0; i < num; i++) {
632: uroute_print(list[i], stdout);
633: printf("\n");
634: }
635: for (i = 0; i < num; i++)
636: uroute_destroy(&list[i]);
637: FREE("main", list);
638: break;
639: }
640: default:
641: assert(0);
642: }
643:
644: /* Done */
645: typed_mem_dump(stdout);
646: return (0);
647: }
648: #endif
649:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>