minor fix to return E_USAGE on -V instead of exit(0);
[oss-qm-packages.git] / lib / inet6_sr.c
blobfbfe033905de4cf7bd97b6fc1c90e4ff35a5752a
1 /*
2 Modifications:
3 1998-07-01 - Arnaldo Carvalho de Melo - GNU gettext instead of catgets
4 */
6 #include "config.h"
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"
39 extern struct aftype inet6_aftype;
41 static int skfd = -1;
44 static int usage(void)
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);
53 static int INET6_setroute(int action, int options, char **args)
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;
63 if (*args == NULL)
64 return (usage());
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;
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);
86 /* Clean out the RTREQ structure. */
87 memset((char *) &rt, 0, sizeof(struct in6_rtmsg));
89 memcpy(&rt.rtmsg_dst, sa6.sin6_addr.s6_addr, sizeof(struct in6_addr));
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;
98 while (*args) {
99 if (!strcmp(*args, "metric")) {
101 args++;
102 if (!*args || !isdigit(**args))
103 return (usage());
104 metric = atoi(*args);
105 rt.rtmsg_metric = metric;
106 args++;
107 continue;
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);
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;
127 if (!strcmp(*args, "mod")) {
128 args++;
129 rt.rtmsg_flags |= RTF_MODIFIED;
130 continue;
132 if (!strcmp(*args, "dyn")) {
133 args++;
134 rt.rtmsg_flags |= RTF_DYNAMIC;
135 continue;
137 if (!strcmp(*args, "device") || !strcmp(*args, "dev")) {
138 args++;
139 if (!*args)
140 return (usage());
141 } else if (args[1])
142 return (usage());
144 devname = *args;
145 args++;
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);
153 if (devname) {
154 memset(&ifr, 0, sizeof(ifr));
155 strcpy(ifr.ifr_name, devname);
157 if (ioctl(skfd, SIOGIFINDEX, &ifr) < 0) {
158 perror("SIOGIFINDEX");
159 return (E_SOCK);
161 rt.rtmsg_ifindex = ifr.ifr_ifindex;
162 } else
163 rt.rtmsg_ifindex = 0;
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);
172 } else {
173 if (ioctl(skfd, SIOCADDRT, &rt) < 0) {
174 perror("SIOCADDRT");
175 close(skfd);
176 return (E_SOCK);
180 /* Close the socket. */
181 (void) close(skfd);
182 return (0);
185 int INET6_rinput(int action, int options, char **args)
187 if (action == RTACTION_FLUSH) {
188 fprintf(stderr, _("Flushing `inet6' routing table not supported\n"));
189 return (usage());
191 if ((*args == NULL) || (action == RTACTION_HELP))
192 return (usage());
194 return (INET6_setroute(action, options, args));
196 #endif /* HAVE_AFINET6 */