enable -fno-strict-aliasing until the code base gets a hefty clean up to fix all...
[platform/upstream/net-tools.git] / lib / inet6_sr.c
1 /*
2    Modifications:
3    1998-07-01 - Arnaldo Carvalho de Melo - GNU gettext instead of catgets
4  */
5
6 #include "config.h"
7
8 #if HAVE_AFINET6
9 #include <asm/types.h>
10 #include <sys/param.h>
11 #include <sys/types.h>
12 #include <sys/socket.h>
13 #include <netinet/in.h>
14 #include <arpa/inet.h>
15 #include <arpa/nameser.h>
16 #include <net/if.h>
17 #include <sys/ioctl.h>
18 #include <ctype.h>
19 #include <errno.h>
20 #include <netdb.h>
21 #include <resolv.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <stdio.h>
25 #include <unistd.h>
26 #ifdef __GLIBC__
27 #include <net/route.h>
28 #else
29 #include <netinet6/ipv6_route.h>        /* glibc does not have this */
30 #endif
31 #include "version.h"
32 #include "net-support.h"
33 #include "pathnames.h"
34 #include "intl.h"
35 #include "net-features.h"
36
37
38
39 extern struct aftype inet6_aftype;
40
41 static int skfd = -1;
42
43
44 static int usage(void)
45 {
46     fprintf(stderr, _("Usage: inet6_route [-vF] del Target\n"));
47     fprintf(stderr, _("       inet6_route [-vF] add Target [gw Gw] [metric M] [[dev] If]\n"));
48     fprintf(stderr, _("       inet6_route [-FC] flush      NOT supported\n"));
49     return (E_USAGE);
50 }
51
52
53 static int INET6_setroute(int action, int options, char **args)
54 {
55     struct in6_rtmsg rt;
56     struct ifreq ifr;
57     struct sockaddr_in6 sa6;
58     char target[128], gateway[128] = "NONE";
59     int metric, prefix_len;
60     char *devname = NULL;
61     char *cp;
62
63     if (*args == NULL)
64         return (usage());
65
66     strcpy(target, *args++);
67     if (!strcmp(target, "default")) {
68         prefix_len = 0;
69         memset(&sa6, 0, sizeof(sa6));
70     } else {
71         if ((cp = strchr(target, '/'))) {
72             prefix_len = atol(cp + 1);
73             if ((prefix_len < 0) || (prefix_len > 128))
74                 usage();
75             *cp = 0;
76         } else {
77             prefix_len = 128;
78         }
79         if (inet6_aftype.input(1, target, (struct sockaddr *) &sa6) < 0
80             && inet6_aftype.input(0, target, (struct sockaddr *) &sa6) < 0) {
81             inet6_aftype.herror(target);
82             return (1);
83         }
84     }
85
86     /* Clean out the RTREQ structure. */
87     memset((char *) &rt, 0, sizeof(struct in6_rtmsg));
88
89     memcpy(&rt.rtmsg_dst, sa6.sin6_addr.s6_addr, sizeof(struct in6_addr));
90
91     /* Fill in the other fields. */
92     rt.rtmsg_flags = RTF_UP;
93     if (prefix_len == 128)
94         rt.rtmsg_flags |= RTF_HOST;
95     rt.rtmsg_metric = 1;
96     rt.rtmsg_dst_len = prefix_len;
97
98     while (*args) {
99         if (!strcmp(*args, "metric")) {
100
101             args++;
102             if (!*args || !isdigit(**args))
103                 return (usage());
104             metric = atoi(*args);
105             rt.rtmsg_metric = metric;
106             args++;
107             continue;
108         }
109         if (!strcmp(*args, "gw") || !strcmp(*args, "gateway")) {
110             args++;
111             if (!*args)
112                 return (usage());
113             if (rt.rtmsg_flags & RTF_GATEWAY)
114                 return (usage());
115             strcpy(gateway, *args);
116             if (inet6_aftype.input(1, gateway,
117                                    (struct sockaddr *) &sa6) < 0) {
118                 inet6_aftype.herror(gateway);
119                 return (E_LOOKUP);
120             }
121             memcpy(&rt.rtmsg_gateway, sa6.sin6_addr.s6_addr,
122                    sizeof(struct in6_addr));
123             rt.rtmsg_flags |= RTF_GATEWAY;
124             args++;
125             continue;
126         }
127         if (!strcmp(*args, "mod")) {
128             args++;
129             rt.rtmsg_flags |= RTF_MODIFIED;
130             continue;
131         }
132         if (!strcmp(*args, "dyn")) {
133             args++;
134             rt.rtmsg_flags |= RTF_DYNAMIC;
135             continue;
136         }
137         if (!strcmp(*args, "device") || !strcmp(*args, "dev")) {
138             args++;
139             if (!*args)
140                 return (usage());
141         } else if (args[1])
142             return (usage());
143
144         devname = *args;
145         args++;
146     }
147
148     /* Create a socket to the INET6 kernel. */
149     if ((skfd = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
150         perror("socket");
151         return (E_SOCK);
152     }
153     if (devname) {
154         memset(&ifr, 0, sizeof(ifr));
155         strcpy(ifr.ifr_name, devname);
156
157         if (ioctl(skfd, SIOGIFINDEX, &ifr) < 0) {
158             perror("SIOGIFINDEX");
159             return (E_SOCK);
160         }
161         rt.rtmsg_ifindex = ifr.ifr_ifindex;
162     } else
163         rt.rtmsg_ifindex = 0;
164
165     /* Tell the kernel to accept this route. */
166     if (action == RTACTION_DEL) {
167         if (ioctl(skfd, SIOCDELRT, &rt) < 0) {
168             perror("SIOCDELRT");
169             close(skfd);
170             return (E_SOCK);
171         }
172     } else {
173         if (ioctl(skfd, SIOCADDRT, &rt) < 0) {
174             perror("SIOCADDRT");
175             close(skfd);
176             return (E_SOCK);
177         }
178     }
179
180     /* Close the socket. */
181     (void) close(skfd);
182     return (0);
183 }
184
185 int INET6_rinput(int action, int options, char **args)
186 {
187     if (action == RTACTION_FLUSH) {
188         fprintf(stderr, _("Flushing `inet6' routing table not supported\n"));
189         return (usage());
190     }
191     if ((*args == NULL) || (action == RTACTION_HELP))
192         return (usage());
193
194     return (INET6_setroute(action, options, args));
195 }
196 #endif                          /* HAVE_AFINET6 */