minor fix to return E_USAGE on -V instead of exit(0);
[oss-qm-packages.git] / lib / inet_sr.c
blob6d010d560468737fb7866abe971d8dcacb8891ab
1 /*
2 Modifications:
3 1998-07-01 - Arnaldo Carvalho de Melo - GNU gettext instead of catgets
4 1999-10-07 - Kurt Garloff - for -host and gws: prefer host names
5 over networks (or even reject)
6 */
8 #include "config.h"
10 #if HAVE_AFINET
11 #include <asm/types.h>
12 #include <sys/param.h>
13 #include <sys/types.h>
14 #include <sys/socket.h>
15 #include <netinet/in.h>
16 #include <arpa/inet.h>
17 #include <arpa/nameser.h>
18 #include <net/route.h> /* realy broken */
19 #include <sys/ioctl.h>
20 #include <ctype.h>
21 #include <errno.h>
22 #include <netdb.h>
23 #include <resolv.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <stdio.h>
27 #include <unistd.h>
28 #include "version.h"
29 #include "net-support.h"
30 #include "pathnames.h"
31 #include "intl.h"
32 #include "net-features.h"
33 #include "util.h"
35 #if HAVE_NEW_ADDRT
36 #define mask_in_addr(x) (((struct sockaddr_in *)&((x).rt_genmask))->sin_addr.s_addr)
37 #define full_mask(x) (x)
38 #else
39 #define mask_in_addr(x) ((x).rt_genmask)
40 #define full_mask(x) (((struct sockaddr_in *)&(x))->sin_addr.s_addr)
41 #endif
43 extern struct aftype inet_aftype;
45 static int skfd = -1;
48 static int usage(void)
50 fprintf(stderr, _("Usage: inet_route [-vF] del {-host|-net} Target[/prefix] [gw Gw] [metric M] [[dev] If]\n"));
51 fprintf(stderr, _(" inet_route [-vF] add {-host|-net} Target[/prefix] [gw Gw] [metric M]\n"));
52 fprintf(stderr, _(" [netmask N] [mss Mss] [window W] [irtt I]\n"));
53 fprintf(stderr, _(" [mod] [dyn] [reinstate] [[dev] If]\n"));
54 fprintf(stderr, _(" inet_route [-vF] add {-host|-net} Target[/prefix] [metric M] reject\n"));
55 fprintf(stderr, _(" inet_route [-FC] flush NOT supported\n"));
56 return (E_USAGE);
59 static int INET_setroute(int action, int options, char **args)
61 struct rtentry rt;
62 char target[128], gateway[128] = "NONE", netmask[128] = "default";
63 int xflag, isnet;
65 xflag = 0;
67 if (!strcmp(*args, "#net")) {
68 xflag = 1;
69 args++;
70 } else if (!strcmp(*args, "#host")) {
71 xflag = 2;
72 args++;
74 if (*args == NULL)
75 return (usage());
77 safe_strncpy(target, *args++, (sizeof target));
79 /* Clean out the RTREQ structure. */
80 memset((char *) &rt, 0, sizeof(struct rtentry));
82 /* Special hack for /prefix syntax */
84 union {
85 struct sockaddr_in m;
86 struct sockaddr d;
87 } mask;
88 int n;
90 n = inet_aftype.getmask(target, &mask.d, netmask);
91 if (n < 0)
92 return usage();
93 else if (n)
94 rt.rt_genmask = full_mask(mask.d);
97 /* Prefer hostname lookup is -host flag was given */
98 if ((isnet = inet_aftype.input((xflag!=2? 0: 256), target, &rt.rt_dst)) < 0) {
99 inet_aftype.herror(target);
100 return (1);
102 switch (xflag) {
103 case 1:
104 isnet = 1; break;
105 case 2:
106 isnet = 0; break;
107 default:
110 /* Fill in the other fields. */
111 rt.rt_flags = (RTF_UP | RTF_HOST);
112 if (isnet)
113 rt.rt_flags &= ~RTF_HOST;
115 while (*args) {
116 if (!strcmp(*args, "metric")) {
117 int metric;
119 args++;
120 if (!*args || !isdigit(**args))
121 return (usage());
122 metric = atoi(*args);
123 #if HAVE_NEW_ADDRT
124 rt.rt_metric = metric + 1;
125 #else
126 ENOSUPP("inet_setroute", "NEW_ADDRT (metric)");
127 #endif
128 args++;
129 continue;
131 if (!strcmp(*args, "netmask")) {
132 struct sockaddr mask;
134 args++;
135 if (!*args || mask_in_addr(rt))
136 return (usage());
137 safe_strncpy(netmask, *args, (sizeof netmask));
138 if ((isnet = inet_aftype.input(0, netmask, &mask)) < 0) {
139 inet_aftype.herror(netmask);
140 return (E_LOOKUP);
142 rt.rt_genmask = full_mask(mask);
143 args++;
144 continue;
146 if (!strcmp(*args, "gw") || !strcmp(*args, "gateway")) {
147 args++;
148 if (!*args)
149 return (usage());
150 if (rt.rt_flags & RTF_GATEWAY)
151 return (usage());
152 safe_strncpy(gateway, *args, (sizeof gateway));
153 if ((isnet = inet_aftype.input(256, gateway, &rt.rt_gateway)) < 0) {
154 inet_aftype.herror(gateway);
155 return (E_LOOKUP);
157 if (isnet) {
158 fprintf(stderr, _("route: %s: cannot use a NETWORK as gateway!\n"),
159 gateway);
160 return (E_OPTERR);
162 rt.rt_flags |= RTF_GATEWAY;
163 args++;
164 continue;
166 if (!strcmp(*args, "mss") || !strcmp(*args,"mtu")) {
167 args++;
168 rt.rt_flags |= RTF_MSS;
169 if (!*args)
170 return (usage());
171 rt.rt_mss = atoi(*args);
172 args++;
173 if (rt.rt_mss < 64 || rt.rt_mss > 65536) {
174 fprintf(stderr, _("route: Invalid MSS/MTU.\n"));
175 return (E_OPTERR);
177 continue;
179 if (!strcmp(*args, "window")) {
180 args++;
181 if (!*args)
182 return (usage());
183 rt.rt_flags |= RTF_WINDOW;
184 rt.rt_window = atoi(*args);
185 args++;
186 if (rt.rt_window < 128) {
187 fprintf(stderr, _("route: Invalid window.\n"));
188 return (E_OPTERR);
190 continue;
192 if (!strcmp(*args, "irtt")) {
193 args++;
194 if (!*args)
195 return (usage());
196 args++;
197 #if HAVE_RTF_IRTT
198 rt.rt_flags |= RTF_IRTT;
199 rt.rt_irtt = atoi(*(args - 1));
200 rt.rt_irtt *= (HZ / 100); /* FIXME */
201 #if 0 /* FIXME: do we need to check anything of this? */
202 if (rt.rt_irtt < 1 || rt.rt_irtt > (120 * HZ)) {
203 fprintf(stderr, _("route: Invalid initial rtt.\n"));
204 return (E_OPTERR);
206 #endif
207 #else
208 ENOSUPP("inet_setroute", "RTF_IRTT");
209 #endif
210 continue;
212 if (!strcmp(*args, "reject")) {
213 args++;
214 #if HAVE_RTF_REJECT
215 rt.rt_flags |= RTF_REJECT;
216 #else
217 ENOSUPP("inet_setroute", "RTF_REJECT");
218 #endif
219 continue;
221 if (!strcmp(*args, "mod")) {
222 args++;
223 rt.rt_flags |= RTF_MODIFIED;
224 continue;
226 if (!strcmp(*args, "dyn")) {
227 args++;
228 rt.rt_flags |= RTF_DYNAMIC;
229 continue;
231 if (!strcmp(*args, "reinstate")) {
232 args++;
233 rt.rt_flags |= RTF_REINSTATE;
234 continue;
236 if (!strcmp(*args, "device") || !strcmp(*args, "dev")) {
237 args++;
238 if (rt.rt_dev || *args == NULL)
239 return usage();
240 rt.rt_dev = *args++;
241 continue;
243 /* nothing matches */
244 if (!rt.rt_dev) {
245 rt.rt_dev = *args++;
246 if (*args)
247 return usage(); /* must be last to catch typos */
248 } else
249 return usage();
252 #if HAVE_RTF_REJECT
253 if ((rt.rt_flags & RTF_REJECT) && !rt.rt_dev)
254 rt.rt_dev = "lo";
255 #endif
257 /* sanity checks.. */
258 if (mask_in_addr(rt)) {
259 __u32 mask = ~ntohl(mask_in_addr(rt));
260 if ((rt.rt_flags & RTF_HOST) && mask != 0xffffffff) {
261 fprintf(stderr, _("route: netmask %.8x doesn't make sense with host route\n"), mask);
262 return (E_OPTERR);
264 if (mask & (mask + 1)) {
265 fprintf(stderr, _("route: bogus netmask %s\n"), netmask);
266 return (E_OPTERR);
268 mask = ((struct sockaddr_in *) &rt.rt_dst)->sin_addr.s_addr;
269 if (mask & ~mask_in_addr(rt)) {
270 fprintf(stderr, _("route: netmask doesn't match route address\n"));
271 return (E_OPTERR);
274 /* Fill out netmask if still unset */
275 if ((action == RTACTION_ADD) && rt.rt_flags & RTF_HOST)
276 mask_in_addr(rt) = 0xffffffff;
278 /* Create a socket to the INET kernel. */
279 if ((skfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
280 perror("socket");
281 return (E_SOCK);
283 /* Tell the kernel to accept this route. */
284 if (action == RTACTION_DEL) {
285 if (ioctl(skfd, SIOCDELRT, &rt) < 0) {
286 perror("SIOCDELRT");
287 close(skfd);
288 return (E_SOCK);
290 } else {
291 if (ioctl(skfd, SIOCADDRT, &rt) < 0) {
292 perror("SIOCADDRT");
293 close(skfd);
294 return (E_SOCK);
298 /* Close the socket. */
299 (void) close(skfd);
300 return (0);
303 int INET_rinput(int action, int options, char **args)
305 if (action == RTACTION_FLUSH) {
306 fprintf(stderr, _("Flushing `inet' routing table not supported\n"));
307 return (usage());
309 if (options & FLAG_CACHE) {
310 fprintf(stderr, _("Modifying `inet' routing cache not supported\n"));
311 return (usage());
313 if ((*args == NULL) || (action == RTACTION_HELP))
314 return (usage());
316 return (INET_setroute(action, options, args));
318 #endif /* HAVE_AFINET */