Commit | Line | Data |
---|---|---|
5ff67f98 | 1 | /* |
7b3729cc | 2 | * Copyright (c) 1983, 1989 The Regents of the University of California. |
fca7493d KB |
3 | * All rights reserved. |
4 | * | |
5 | * Redistribution and use in source and binary forms are permitted | |
6 | * provided that the above copyright notice and this paragraph are | |
7 | * duplicated in all such forms and that any documentation, | |
8 | * advertising materials, and other materials related to such | |
9 | * distribution and use acknowledge that the software was developed | |
10 | * by the University of California, Berkeley. The name of the | |
11 | * University may not be used to endorse or promote products derived | |
12 | * from this software without specific prior written permission. | |
13 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR | |
14 | * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED | |
15 | * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. | |
5ff67f98 DF |
16 | */ |
17 | ||
18 | #ifndef lint | |
19 | char copyright[] = | |
7d5f817b | 20 | "@(#) Copyright (c) 1983 The Regents of the University of California.\n\ |
5ff67f98 | 21 | All rights reserved.\n"; |
fca7493d | 22 | #endif /* not lint */ |
5ff67f98 | 23 | |
4bec325f | 24 | #ifndef lint |
7b3729cc | 25 | static char sccsid[] = "@(#)route.c 5.17 (Berkeley) %G%"; |
fca7493d | 26 | #endif /* not lint */ |
4bec325f | 27 | |
7d5f817b | 28 | #include <paths.h> |
a2280e64 | 29 | #include <sys/param.h> |
4bec325f BJ |
30 | #include <sys/socket.h> |
31 | #include <sys/ioctl.h> | |
5c7868a2 | 32 | #include <sys/file.h> |
63c817da | 33 | #include <sys/mbuf.h> |
94a2d2a7 | 34 | |
4bec325f | 35 | #include <net/route.h> |
94a2d2a7 | 36 | #include <netinet/in.h> |
eac76d14 | 37 | #include <netns/ns.h> |
7d5f817b | 38 | #include <netiso/iso.h> |
94a2d2a7 | 39 | |
5c7868a2 | 40 | #include <netdb.h> |
94a2d2a7 | 41 | #include <stdio.h> |
4bec325f BJ |
42 | #include <errno.h> |
43 | #include <ctype.h> | |
44 | ||
57cacc90 | 45 | struct ortentry route; |
7d5f817b KS |
46 | union { |
47 | struct sockaddr sa; | |
48 | struct sockaddr_in sin; | |
49 | struct sockaddr_ns sns; | |
50 | struct sockaddr_iso siso; | |
51 | } so_dst, so_gate, so_mask; | |
4bec325f | 52 | int s; |
7b3729cc | 53 | int forcehost, forcenet, doflush, nflag, xnsflag, qflag, Cflag = 1; |
7d5f817b | 54 | int iflag, osiflag, verbose; |
57cacc90 | 55 | int pid; |
b268b889 | 56 | struct sockaddr_in sin = { sizeof(sin), AF_INET }; |
379dcc38 | 57 | struct in_addr inet_makeaddr(); |
5c7868a2 | 58 | char *malloc(), *vmunix = _PATH_UNIX; |
b268b889 MK |
59 | #define kget(p, d) \ |
60 | (lseek(kmem, (off_t)(p), 0), read(kmem, (char *)&(d), sizeof (d))) | |
4bec325f BJ |
61 | |
62 | main(argc, argv) | |
63 | int argc; | |
64 | char *argv[]; | |
65 | { | |
66 | ||
b268b889 | 67 | char *argvp; |
4bec325f | 68 | if (argc < 2) |
5c7868a2 | 69 | usage: |
b268b889 MK |
70 | fprintf(stderr, |
71 | "usage: route [ -n ] [ -f ] [ cmd [ net | host ] args ]\n"), | |
b3933da8 | 72 | exit(1); |
4bec325f | 73 | argc--, argv++; |
b3933da8 | 74 | for (; argc > 0 && argv[0][0] == '-'; argc--, argv++) { |
b268b889 | 75 | for (argvp = argv[0]++; *argvp; argvp++) |
b3933da8 MK |
76 | switch (*argv[0]) { |
77 | case 'f': | |
a2280e64 | 78 | doflush++; |
b3933da8 MK |
79 | break; |
80 | case 'n': | |
a2280e64 | 81 | nflag++; |
b3933da8 | 82 | break; |
b268b889 MK |
83 | case 'x': |
84 | xnsflag++; | |
85 | break; | |
ae578a19 KS |
86 | case 'q': |
87 | qflag++; | |
88 | break; | |
5c7868a2 KS |
89 | case 'C': |
90 | Cflag++; /* Use old ioctls */ | |
57cacc90 | 91 | break; |
b268b889 MK |
92 | case 'k': |
93 | vmunix = *++argv; | |
94 | argc--; | |
95 | break; | |
57cacc90 KS |
96 | case 'i': |
97 | iflag++; | |
98 | break; | |
7d5f817b KS |
99 | case 'o': |
100 | osiflag++; | |
101 | break; | |
102 | case 'v': | |
103 | verbose++; | |
104 | break; | |
7b3729cc KS |
105 | |
106 | case 'N': | |
107 | Cflag = 0; /* Use routing socket */ | |
b3933da8 MK |
108 | } |
109 | } | |
5c7868a2 KS |
110 | pid = getpid(); |
111 | if (Cflag) | |
57cacc90 | 112 | s = socket(AF_INET, SOCK_RAW, 0); |
5c7868a2 KS |
113 | else |
114 | s = socket(PF_ROUTE, SOCK_RAW, 0); | |
57cacc90 KS |
115 | if (s < 0) { |
116 | perror("route: socket"); | |
117 | exit(1); | |
118 | } | |
119 | if (doflush) { | |
a2280e64 | 120 | flushroutes(); |
57cacc90 KS |
121 | exit(0); |
122 | } | |
63c817da SL |
123 | if (argc > 0) { |
124 | if (strcmp(*argv, "add") == 0) | |
125 | newroute(argc, argv); | |
126 | else if (strcmp(*argv, "delete") == 0) | |
127 | newroute(argc, argv); | |
128 | else if (strcmp(*argv, "change") == 0) | |
129 | changeroute(argc-1, argv+1); | |
5c7868a2 KS |
130 | else if (strcmp(*argv, "monitor") == 0) |
131 | monitor(); | |
63c817da | 132 | else |
b268b889 | 133 | fprintf(stderr, "%s: huh?\n", *argv); |
57cacc90 | 134 | } else |
5c7868a2 | 135 | goto usage; |
63c817da SL |
136 | } |
137 | ||
138 | /* | |
139 | * Purge all entries in the routing tables not | |
140 | * associated with network interfaces. | |
141 | */ | |
142 | #include <nlist.h> | |
143 | ||
144 | struct nlist nl[] = { | |
145 | #define N_RTHOST 0 | |
146 | { "_rthost" }, | |
147 | #define N_RTNET 1 | |
148 | { "_rtnet" }, | |
f508555e MK |
149 | #define N_RTHASHSIZE 2 |
150 | { "_rthashsize" }, | |
b268b889 MK |
151 | #define N_RTREE 3 |
152 | { "_radix_node_head" }, | |
63c817da SL |
153 | "", |
154 | }; | |
155 | ||
b268b889 | 156 | int kmem; |
63c817da SL |
157 | flushroutes() |
158 | { | |
5c7868a2 | 159 | extern int errno; |
57cacc90 | 160 | register struct ortentry *rt; |
63c817da | 161 | register struct mbuf *m; |
5c7868a2 | 162 | struct mbuf mb, **routehash; |
b268b889 | 163 | int rthashsize, i, doinghost = 1; |
5c7868a2 | 164 | char *routename(), *netname(), *strerror(); |
63c817da | 165 | |
b268b889 | 166 | nlist(vmunix, nl); |
5c7868a2 | 167 | kmem = open(_PATH_KMEM, O_RDONLY, 0); |
b268b889 | 168 | if (kmem < 0) { |
5c7868a2 KS |
169 | (void)fprintf(stderr, |
170 | "route: %s: %s\n", _PATH_KMEM, strerror(errno)); | |
b268b889 MK |
171 | exit(1); |
172 | } | |
173 | if (nl[N_RTREE].n_value) | |
174 | return (treestuff(nl[N_RTREE].n_value)); | |
63c817da | 175 | if (nl[N_RTHOST].n_value == 0) { |
b268b889 MK |
176 | fprintf(stderr, |
177 | "route: \"rthost\", symbol not in namelist\n"); | |
63c817da SL |
178 | exit(1); |
179 | } | |
180 | if (nl[N_RTNET].n_value == 0) { | |
b268b889 MK |
181 | fprintf(stderr, |
182 | "route: \"rtnet\", symbol not in namelist\n"); | |
63c817da SL |
183 | exit(1); |
184 | } | |
f508555e | 185 | if (nl[N_RTHASHSIZE].n_value == 0) { |
b268b889 MK |
186 | fprintf(stderr, |
187 | "route: \"rthashsize\", symbol not in namelist\n"); | |
63c817da SL |
188 | exit(1); |
189 | } | |
b268b889 | 190 | kget(nl[N_RTHASHSIZE].n_value, rthashsize); |
f508555e MK |
191 | routehash = (struct mbuf **)malloc(rthashsize*sizeof (struct mbuf *)); |
192 | ||
63c817da | 193 | lseek(kmem, nl[N_RTHOST].n_value, 0); |
f508555e | 194 | read(kmem, routehash, rthashsize*sizeof (struct mbuf *)); |
63c817da SL |
195 | printf("Flushing routing tables:\n"); |
196 | again: | |
f508555e | 197 | for (i = 0; i < rthashsize; i++) { |
63c817da SL |
198 | if (routehash[i] == 0) |
199 | continue; | |
200 | m = routehash[i]; | |
201 | while (m) { | |
b268b889 | 202 | kget(m, mb); |
57cacc90 | 203 | d_ortentry((struct ortentry *)(mb.m_dat), doinghost); |
63c817da SL |
204 | m = mb.m_next; |
205 | } | |
206 | } | |
207 | if (doinghost) { | |
208 | lseek(kmem, nl[N_RTNET].n_value, 0); | |
f508555e | 209 | read(kmem, routehash, rthashsize*sizeof (struct mbuf *)); |
63c817da SL |
210 | doinghost = 0; |
211 | goto again; | |
212 | } | |
213 | close(kmem); | |
f508555e | 214 | free(routehash); |
b268b889 MK |
215 | return; |
216 | } | |
57cacc90 | 217 | typedef u_char blob[128]; |
b268b889 | 218 | |
ae578a19 KS |
219 | struct rtbatch { |
220 | struct rtbatch *nb; | |
221 | int ifree; | |
57cacc90 KS |
222 | struct x { |
223 | struct rtentry rt; | |
224 | union { | |
225 | struct sockaddr sa; | |
226 | blob data; | |
227 | } dst, gate, mask; | |
228 | } x[100]; | |
ae578a19 KS |
229 | } firstbatch, *curbatch = &firstbatch; |
230 | ||
ae578a19 | 231 | w_tree(rn) |
b268b889 MK |
232 | struct radix_node *rn; |
233 | { | |
b268b889 | 234 | |
b268b889 | 235 | struct radix_node rnode; |
57cacc90 KS |
236 | register struct rtentry *rt; |
237 | struct sockaddr *dst; | |
238 | register struct x *x; | |
dc947964 | 239 | |
b268b889 MK |
240 | kget(rn, rnode); |
241 | if (rnode.rn_b < 0) { | |
b268b889 | 242 | if ((rnode.rn_flags & RNF_ROOT) == 0) { |
ae578a19 | 243 | register struct rtbatch *b = curbatch; |
dc947964 MK |
244 | if ((rnode.rn_flags & RNF_ACTIVE) == 0) { |
245 | printf("Dead entry in tree: %x\n", rn); | |
246 | exit(1); | |
247 | } | |
ae578a19 | 248 | if (b->ifree >= 100) { |
57cacc90 | 249 | R_Malloc(b->nb, struct rtbatch *, |
ae578a19 KS |
250 | sizeof (*b)); |
251 | if (b->nb) { | |
252 | b = b->nb; | |
253 | Bzero(b, sizeof(*b)); | |
254 | curbatch = b; | |
255 | } else { | |
256 | printf("out of space\n"); | |
257 | exit(1); | |
258 | } | |
dc947964 | 259 | } |
57cacc90 KS |
260 | x = b->x + b->ifree; |
261 | rt = &x->rt; | |
262 | kget(rn, *rt); | |
263 | dst = &x->dst.sa; | |
264 | kget(rt_key(rt), *dst); | |
265 | if (dst->sa_len > sizeof (*dst)) | |
266 | kget(rt_key(rt), x->dst); | |
267 | rt->rt_nodes->rn_key = (char *)dst; | |
268 | kget(rt->rt_gateway, x->gate.sa); | |
269 | if (x->gate.sa.sa_len > sizeof (*dst)) | |
270 | kget(rt->rt_gateway, x->gate); | |
271 | rt->rt_gateway = &x->gate.sa; | |
5c7868a2 | 272 | if (Cflag == 0) { |
57cacc90 KS |
273 | kget(rt_mask(rt), x->mask.sa); |
274 | if (x->mask.sa.sa_len > sizeof(x->mask.sa)) | |
275 | kget(rt_mask(rt), x->mask); | |
276 | rt->rt_nodes->rn_mask = (char *)&x->mask.sa; | |
277 | } | |
278 | b->ifree++; | |
b268b889 | 279 | } |
ae578a19 KS |
280 | if (rnode.rn_dupedkey) |
281 | w_tree(rnode.rn_dupedkey); | |
b268b889 | 282 | } else { |
ae578a19 KS |
283 | rn = rnode.rn_r; |
284 | w_tree(rnode.rn_l); | |
285 | w_tree(rn); | |
b268b889 | 286 | } |
b268b889 MK |
287 | } |
288 | ||
57cacc90 KS |
289 | treestuff(rtree) |
290 | off_t rtree; | |
291 | { | |
292 | struct radix_node_head *rnh, head; | |
293 | register struct rtbatch *b; | |
294 | register int i; | |
295 | ||
296 | for (kget(rtree, rnh); rnh; rnh = head.rnh_next) { | |
297 | kget(rnh, head); | |
298 | if (head.rnh_af) { | |
299 | w_tree(head.rnh_treetop); | |
300 | } | |
301 | } | |
302 | for (b = &firstbatch; b; b = b->nb) | |
303 | for (i = 0; i < b->ifree; i++) | |
304 | d_rtentry(&(b->x[i].rt)); | |
305 | } | |
306 | ||
307 | d_ortentry(rt) | |
308 | register struct ortentry *rt; | |
b268b889 | 309 | { |
ae578a19 KS |
310 | int doinghost = rt->rt_flags & RTF_HOST; |
311 | ||
b268b889 | 312 | if (rt->rt_flags & RTF_GATEWAY) { |
ae578a19 | 313 | if (qflag == 0) { |
b268b889 MK |
314 | printf("%-20.20s ", doinghost ? |
315 | routename(&rt->rt_dst) : | |
316 | netname(&rt->rt_dst)); | |
317 | printf("%-20.20s ", routename(&rt->rt_gateway)); | |
318 | if (ioctl(s, SIOCDELRT, (caddr_t)rt) < 0) { | |
319 | fflush(stdout); | |
320 | error("delete"); | |
321 | } else | |
322 | printf("done\n"); | |
ae578a19 KS |
323 | } else |
324 | (void) ioctl(s, SIOCDELRT, (caddr_t)rt); | |
b268b889 | 325 | } |
63c817da SL |
326 | } |
327 | ||
57cacc90 KS |
328 | struct ortentry ortentry; |
329 | d_rtentry(rt) | |
330 | register struct rtentry *rt; | |
331 | { | |
332 | int doinghost = rt->rt_flags & RTF_HOST; | |
7d5f817b | 333 | int result; |
57cacc90 KS |
334 | |
335 | ortentry.rt_flags = rt->rt_flags; | |
336 | ortentry.rt_dst = *(rt_key(rt)); | |
337 | ortentry.rt_gateway = *(rt->rt_gateway); | |
338 | if (rt->rt_flags & RTF_GATEWAY) { | |
7d5f817b KS |
339 | if (Cflag == 0) |
340 | result = rtmsg('d', rt_key(rt), rt->rt_gateway, | |
341 | rt_mask(rt), rt->rt_flags); | |
342 | else | |
343 | result = ioctl(s, SIOCDELRT, (caddr_t)&ortentry); | |
344 | if (qflag == 0) { | |
345 | printf("%-20.20s ", doinghost ? | |
346 | routename(rt_key(rt)) : netname(rt_key(rt))); | |
347 | printf("%-20.20s ", routename(rt->rt_gateway)); | |
348 | if (result < 0) { | |
349 | fflush(stdout); | |
350 | error("delete"); | |
351 | } else | |
352 | printf("done\n"); | |
353 | } | |
57cacc90 KS |
354 | } |
355 | } | |
356 | ||
63c817da | 357 | char * |
eac76d14 MK |
358 | routename(sa) |
359 | struct sockaddr *sa; | |
63c817da | 360 | { |
a2280e64 | 361 | register char *cp; |
63c817da | 362 | static char line[50]; |
6edb1941 | 363 | struct hostent *hp; |
a2280e64 MK |
364 | static char domain[MAXHOSTNAMELEN + 1]; |
365 | static int first = 1; | |
366 | char *index(); | |
eac76d14 | 367 | char *ns_print(); |
63c817da | 368 | |
a2280e64 MK |
369 | if (first) { |
370 | first = 0; | |
371 | if (gethostname(domain, MAXHOSTNAMELEN) == 0 && | |
372 | (cp = index(domain, '.'))) | |
373 | (void) strcpy(domain, cp + 1); | |
374 | else | |
375 | domain[0] = 0; | |
376 | } | |
eac76d14 MK |
377 | switch (sa->sa_family) { |
378 | ||
379 | case AF_INET: | |
380 | { struct in_addr in; | |
381 | in = ((struct sockaddr_in *)sa)->sin_addr; | |
382 | ||
383 | cp = 0; | |
384 | if (in.s_addr == INADDR_ANY) | |
385 | cp = "default"; | |
386 | if (cp == 0 && !nflag) { | |
387 | hp = gethostbyaddr(&in, sizeof (struct in_addr), | |
388 | AF_INET); | |
389 | if (hp) { | |
390 | if ((cp = index(hp->h_name, '.')) && | |
391 | !strcmp(cp + 1, domain)) | |
392 | *cp = 0; | |
393 | cp = hp->h_name; | |
394 | } | |
a2280e64 | 395 | } |
eac76d14 MK |
396 | if (cp) |
397 | strcpy(line, cp); | |
398 | else { | |
a2280e64 | 399 | #define C(x) ((x) & 0xff) |
eac76d14 | 400 | in.s_addr = ntohl(in.s_addr); |
9bd38ba8 | 401 | (void)sprintf(line, "%u.%u.%u.%u", C(in.s_addr >> 24), |
eac76d14 MK |
402 | C(in.s_addr >> 16), C(in.s_addr >> 8), C(in.s_addr)); |
403 | } | |
404 | break; | |
405 | } | |
406 | ||
407 | case AF_NS: | |
408 | return (ns_print((struct sockaddr_ns *)sa)); | |
409 | ||
410 | default: | |
411 | { u_short *s = (u_short *)sa->sa_data; | |
412 | ||
57cacc90 | 413 | (void)sprintf(line, "(%d) %x %x %x %x %x %x %x", |
9bd38ba8 | 414 | sa->sa_family, s[0], s[1], s[2], s[3], s[4], s[5], s[6]); |
eac76d14 MK |
415 | break; |
416 | } | |
a2280e64 MK |
417 | } |
418 | return (line); | |
419 | } | |
420 | ||
421 | /* | |
422 | * Return the name of the network whose address is given. | |
423 | * The address is assumed to be that of a net or subnet, not a host. | |
424 | */ | |
425 | char * | |
eac76d14 MK |
426 | netname(sa) |
427 | struct sockaddr *sa; | |
a2280e64 MK |
428 | { |
429 | char *cp = 0; | |
430 | static char line[50]; | |
431 | struct netent *np = 0; | |
432 | u_long net, mask; | |
e2fe1192 | 433 | register u_long i; |
a2280e64 | 434 | int subnetshift; |
a48a48cc | 435 | char *ns_print(); |
a2280e64 | 436 | |
eac76d14 MK |
437 | switch (sa->sa_family) { |
438 | ||
439 | case AF_INET: | |
440 | { struct in_addr in; | |
441 | in = ((struct sockaddr_in *)sa)->sin_addr; | |
442 | ||
e2fe1192 | 443 | i = in.s_addr = ntohl(in.s_addr); |
eac76d14 MK |
444 | if (in.s_addr == 0) |
445 | cp = "default"; | |
446 | else if (!nflag) { | |
447 | if (IN_CLASSA(i)) { | |
448 | mask = IN_CLASSA_NET; | |
449 | subnetshift = 8; | |
450 | } else if (IN_CLASSB(i)) { | |
451 | mask = IN_CLASSB_NET; | |
452 | subnetshift = 8; | |
453 | } else { | |
454 | mask = IN_CLASSC_NET; | |
455 | subnetshift = 4; | |
456 | } | |
457 | /* | |
458 | * If there are more bits than the standard mask | |
459 | * would suggest, subnets must be in use. | |
460 | * Guess at the subnet mask, assuming reasonable | |
461 | * width subnet fields. | |
462 | */ | |
463 | while (in.s_addr &~ mask) | |
464 | mask = (long)mask >> subnetshift; | |
465 | net = in.s_addr & mask; | |
466 | while ((mask & 1) == 0) | |
467 | mask >>= 1, net >>= 1; | |
468 | np = getnetbyaddr(net, AF_INET); | |
469 | if (np) | |
470 | cp = np->n_name; | |
a2280e64 | 471 | } |
eac76d14 MK |
472 | if (cp) |
473 | strcpy(line, cp); | |
474 | else if ((in.s_addr & 0xffffff) == 0) | |
9bd38ba8 | 475 | (void)sprintf(line, "%u", C(in.s_addr >> 24)); |
eac76d14 | 476 | else if ((in.s_addr & 0xffff) == 0) |
9bd38ba8 | 477 | (void)sprintf(line, "%u.%u", C(in.s_addr >> 24), |
eac76d14 MK |
478 | C(in.s_addr >> 16)); |
479 | else if ((in.s_addr & 0xff) == 0) | |
9bd38ba8 | 480 | (void)sprintf(line, "%u.%u.%u", C(in.s_addr >> 24), |
eac76d14 MK |
481 | C(in.s_addr >> 16), C(in.s_addr >> 8)); |
482 | else | |
9bd38ba8 | 483 | (void)sprintf(line, "%u.%u.%u.%u", C(in.s_addr >> 24), |
eac76d14 MK |
484 | C(in.s_addr >> 16), C(in.s_addr >> 8), |
485 | C(in.s_addr)); | |
486 | break; | |
487 | } | |
488 | ||
489 | case AF_NS: | |
490 | return (ns_print((struct sockaddr_ns *)sa)); | |
491 | break; | |
492 | ||
493 | default: | |
494 | { u_short *s = (u_short *)sa->sa_data; | |
495 | ||
9bd38ba8 KB |
496 | (void)sprintf(line, "af %d: %x %x %x %x %x %x %x", |
497 | sa->sa_family, s[0], s[1], s[2], s[3], s[4], s[5], s[6]); | |
eac76d14 MK |
498 | break; |
499 | } | |
63c817da SL |
500 | } |
501 | return (line); | |
4bec325f BJ |
502 | } |
503 | ||
504 | newroute(argc, argv) | |
505 | int argc; | |
506 | char *argv[]; | |
507 | { | |
508 | struct sockaddr_in *sin; | |
57cacc90 | 509 | char *cmd, *dest, *gateway, *mask; |
7d5f817b | 510 | int ishost, metric = 0, ret, attempts, oerrno, flags = 0; |
792b0612 MK |
511 | struct hostent *hp; |
512 | extern int errno; | |
4bec325f | 513 | |
183ef13b | 514 | cmd = argv[0]; |
a2280e64 MK |
515 | if ((strcmp(argv[1], "host")) == 0) { |
516 | forcehost++; | |
517 | argc--, argv++; | |
518 | } else if ((strcmp(argv[1], "net")) == 0) { | |
519 | forcenet++; | |
520 | argc--, argv++; | |
521 | } | |
7d5f817b | 522 | ishost = getaddr(argv[1], &so_dst.sa, &so_mask.sa, |
57cacc90 | 523 | &hp, &dest, forcenet); |
b3933da8 MK |
524 | if (forcehost) |
525 | ishost = 1; | |
526 | if (forcenet) | |
527 | ishost = 0; | |
7d5f817b | 528 | (void) getaddr(argv[2], &so_gate.sa, 0, &hp, &gateway, 0); |
5c7868a2 | 529 | if ((Cflag == 0) && argc == 4) { |
7b3729cc KS |
530 | ret = atoi(argv[3]); |
531 | if (ret == 0) { | |
532 | printf("old usage of trailing 0, assuming route to if\n"); | |
533 | iflag = 1; | |
534 | } else if (ret > 0 && ret < 10) { | |
535 | printf("old usage of trailing digit, "); | |
536 | printf("assuming route via gateway\n"); | |
537 | iflag = 0; | |
538 | } else | |
539 | (void) getaddr(argv[3], &so_mask.sa, 0, &hp, &mask, 0); | |
57cacc90 | 540 | } |
7d5f817b | 541 | flags = RTF_UP; |
6edb1941 | 542 | if (ishost) |
7d5f817b | 543 | flags |= RTF_HOST; |
57cacc90 | 544 | if (iflag == 0) |
7d5f817b | 545 | flags |= RTF_GATEWAY; |
792b0612 MK |
546 | for (attempts = 1; ; attempts++) { |
547 | errno = 0; | |
5c7868a2 | 548 | if (Cflag) { |
7d5f817b KS |
549 | route.rt_flags = flags; |
550 | route.rt_dst = so_dst.sa; | |
551 | route.rt_gateway = so_gate.sa; | |
57cacc90 KS |
552 | if ((ret = ioctl(s, *cmd == 'a' ? SIOCADDRT : SIOCDELRT, |
553 | (caddr_t)&route)) == 0) | |
554 | break; | |
555 | } else { | |
7d5f817b KS |
556 | if ((ret = rtmsg(*cmd, &so_dst.sa, &so_gate.sa, |
557 | (ishost ? 0 : &so_mask.sa), flags)) == 0) | |
57cacc90 KS |
558 | break; |
559 | } | |
792b0612 MK |
560 | if (errno != ENETUNREACH && errno != ESRCH) |
561 | break; | |
562 | if (hp && hp->h_addr_list[1]) { | |
563 | hp->h_addr_list++; | |
7d5f817b | 564 | bcopy(hp->h_addr_list[0], (caddr_t)&so_dst.sin.sin_addr, |
792b0612 MK |
565 | hp->h_length); |
566 | } else | |
567 | break; | |
568 | } | |
569 | oerrno = errno; | |
570 | printf("%s %s %s: gateway %s", cmd, ishost? "host" : "net", | |
571 | dest, gateway); | |
572 | if (attempts > 1 && ret == 0) | |
573 | printf(" (%s)", | |
574 | inet_ntoa(((struct sockaddr_in *)&route.rt_gateway)->sin_addr)); | |
575 | if (ret == 0) | |
576 | printf("\n"); | |
577 | else { | |
578 | printf(": "); | |
579 | fflush(stdout); | |
580 | errno = oerrno; | |
581 | error(0); | |
582 | } | |
4bec325f BJ |
583 | } |
584 | ||
585 | changeroute(argc, argv) | |
586 | int argc; | |
587 | char *argv[]; | |
588 | { | |
589 | printf("not supported\n"); | |
590 | } | |
591 | ||
592 | error(cmd) | |
593 | char *cmd; | |
594 | { | |
a48a48cc | 595 | extern int errno; |
4bec325f | 596 | |
a48a48cc KB |
597 | switch(errno) { |
598 | case ESRCH: | |
ae578a19 | 599 | printf("not in table\n"); |
a48a48cc KB |
600 | break; |
601 | case EBUSY: | |
ae578a19 | 602 | printf("entry in use\n"); |
a48a48cc KB |
603 | break; |
604 | case ENOBUFS: | |
ae578a19 | 605 | printf("routing table overflow\n"); |
a48a48cc KB |
606 | break; |
607 | default: | |
57cacc90 | 608 | printf("ioctl returns %d\n", errno); |
4bec325f | 609 | perror(cmd); |
a48a48cc | 610 | } |
ae578a19 KS |
611 | fflush(stdout); |
612 | errno = 0; | |
4bec325f BJ |
613 | } |
614 | ||
55e026df MK |
615 | char * |
616 | savestr(s) | |
617 | char *s; | |
618 | { | |
619 | char *sav; | |
620 | ||
621 | sav = malloc(strlen(s) + 1); | |
622 | if (sav == NULL) { | |
623 | fprintf("route: out of memory\n"); | |
624 | exit(1); | |
625 | } | |
626 | strcpy(sav, s); | |
627 | return (sav); | |
628 | } | |
629 | ||
5c7868a2 KS |
630 | inet_makenetandmask(net, sin, sockmask) |
631 | u_long net; | |
632 | struct sockaddr_in *sin, *sockmask; | |
57cacc90 KS |
633 | { |
634 | u_long addr; | |
5c7868a2 | 635 | u_long mask = 0; |
57cacc90 KS |
636 | |
637 | if (net == 0) | |
5c7868a2 | 638 | mask = addr = 0; |
57cacc90 KS |
639 | else if (net < 128) { |
640 | addr = net << IN_CLASSA_NSHIFT; | |
5c7868a2 | 641 | mask = IN_CLASSA_NET; |
57cacc90 KS |
642 | } else if (net < 65536) { |
643 | addr = net << IN_CLASSB_NSHIFT; | |
5c7868a2 | 644 | mask = IN_CLASSB_NET; |
57cacc90 KS |
645 | } else if (net < 16777216L) { |
646 | addr = net << IN_CLASSC_NSHIFT; | |
5c7868a2 | 647 | mask = IN_CLASSC_NET; |
57cacc90 KS |
648 | } else { |
649 | addr = net; | |
650 | if ((addr & IN_CLASSA_HOST) == 0) | |
5c7868a2 | 651 | mask = IN_CLASSA_NET; |
57cacc90 | 652 | else if ((addr & IN_CLASSB_HOST) == 0) |
5c7868a2 | 653 | mask = IN_CLASSB_NET; |
57cacc90 | 654 | else if ((addr & IN_CLASSC_HOST) == 0) |
5c7868a2 | 655 | mask = IN_CLASSC_NET; |
57cacc90 | 656 | else |
5c7868a2 KS |
657 | mask = -1; |
658 | } | |
659 | sin->sin_addr.s_addr = (htonl(addr)); | |
660 | if (sockmask) { | |
7d5f817b | 661 | register char *cp = (char *)&(sockmask->sin_port); |
5c7868a2 KS |
662 | register char *cpbase = (char *)&(sockmask->sin_addr); |
663 | ||
664 | sockmask->sin_addr.s_addr = htonl(mask); | |
665 | sockmask->sin_len = 0; | |
666 | sockmask->sin_family = 0; | |
667 | while (--cp >= cpbase) | |
668 | if (*cp) { | |
669 | sockmask->sin_len = 1 + cp - (caddr_t)sockmask; | |
670 | break; | |
671 | } | |
57cacc90 | 672 | } |
57cacc90 KS |
673 | } |
674 | ||
6edb1941 MK |
675 | /* |
676 | * Interpret an argument as a network address of some kind, | |
677 | * returning 1 if a host address, 0 if a network address. | |
678 | */ | |
57cacc90 | 679 | getaddr(s, sin, sockmask, hpp, name, isnet) |
4bec325f | 680 | char *s; |
57cacc90 | 681 | struct sockaddr_in *sin, *sockmask; |
792b0612 | 682 | struct hostent **hpp; |
c28affab | 683 | char **name; |
a2280e64 | 684 | int isnet; |
4bec325f | 685 | { |
b268b889 MK |
686 | struct sockaddr_ns *sns = (struct sockaddr_ns *)sin; |
687 | struct ns_addr ns_addr(); | |
accbc2e3 | 688 | struct hostent *hp; |
379dcc38 | 689 | struct netent *np; |
7d5f817b | 690 | u_long val = 1; |
accbc2e3 | 691 | |
7d5f817b KS |
692 | if (strcmp(s, "default") == 0) { |
693 | val = 0; | |
694 | *name = "default"; | |
695 | } | |
b268b889 MK |
696 | if (xnsflag) |
697 | goto do_xns; | |
7d5f817b KS |
698 | if (osiflag) |
699 | goto do_osi; | |
57cacc90 KS |
700 | sin->sin_family = AF_INET; |
701 | sin->sin_len = sizeof(*sin); | |
7d5f817b | 702 | if (val == 0) |
57cacc90 | 703 | goto out; |
7d5f817b | 704 | *hpp = 0; |
a2280e64 MK |
705 | if (isnet == 0) { |
706 | val = inet_addr(s); | |
707 | if (val != -1) { | |
708 | sin->sin_addr.s_addr = val; | |
709 | *name = s; | |
57cacc90 KS |
710 | if (inet_lnaof(sin->sin_addr) != INADDR_ANY) |
711 | return (1); | |
712 | else | |
713 | goto out; | |
a2280e64 | 714 | } |
792b0612 MK |
715 | } |
716 | val = inet_network(s); | |
717 | if (val != -1) { | |
c28affab | 718 | *name = s; |
5c7868a2 | 719 | goto out; |
792b0612 | 720 | } |
379dcc38 SL |
721 | np = getnetbyname(s); |
722 | if (np) { | |
5c7868a2 | 723 | val = np->n_net; |
55e026df | 724 | *name = savestr(np->n_name); |
5c7868a2 | 725 | goto out; |
379dcc38 | 726 | } |
78160c55 MK |
727 | hp = gethostbyname(s); |
728 | if (hp) { | |
792b0612 | 729 | *hpp = hp; |
78160c55 MK |
730 | sin->sin_family = hp->h_addrtype; |
731 | bcopy(hp->h_addr, &sin->sin_addr, hp->h_length); | |
55e026df | 732 | *name = savestr(hp->h_name); |
57cacc90 | 733 | return (1); |
78160c55 | 734 | } |
379dcc38 SL |
735 | fprintf(stderr, "%s: bad value\n", s); |
736 | exit(1); | |
5c7868a2 KS |
737 | out: |
738 | inet_makenetandmask(val, sin, sockmask); | |
739 | return (0); | |
b268b889 | 740 | do_xns: |
57cacc90 | 741 | bzero((char *)sns, sizeof(*sns)); |
b268b889 | 742 | sns->sns_family = AF_NS; |
57cacc90 | 743 | sns->sns_len = sizeof (*sns); |
7d5f817b KS |
744 | if (val == 0) |
745 | return(0); | |
57cacc90 KS |
746 | if (sockmask) { |
747 | extern short ns_bh[3]; | |
5c7868a2 | 748 | struct sockaddr_ns *sms = (struct sockaddr_ns *)sockmask; |
57cacc90 KS |
749 | bzero((char *)sms, sizeof(*sns)); |
750 | sms->sns_family = 0; | |
751 | sms->sns_len = 6; | |
752 | sms->sns_addr.x_net = *(union ns_net *)ns_bh; | |
753 | } | |
57cacc90 | 754 | *name = s; |
b268b889 MK |
755 | sns->sns_addr = ns_addr(s); |
756 | return (!ns_nullhost(sns->sns_addr)); | |
7d5f817b KS |
757 | do_osi: |
758 | { | |
759 | struct sockaddr_iso *siso = (struct sockaddr_iso *)sin; | |
760 | struct iso_addr iso_addr(); | |
761 | ||
762 | siso->siso_family = AF_ISO; | |
763 | siso->siso_len = sizeof(*siso); | |
764 | if (val == 0) | |
765 | return (0); | |
766 | *name = s; | |
767 | siso->siso_addr = iso_addr(s); | |
768 | return (1); | |
769 | } | |
183ef13b | 770 | } |
eac76d14 MK |
771 | |
772 | short ns_nullh[] = {0,0,0}; | |
773 | short ns_bh[] = {-1,-1,-1}; | |
774 | ||
775 | char * | |
776 | ns_print(sns) | |
777 | struct sockaddr_ns *sns; | |
778 | { | |
779 | struct ns_addr work; | |
780 | union { union ns_net net_e; u_long long_e; } net; | |
781 | u_short port; | |
782 | static char mybuf[50], cport[10], chost[25]; | |
783 | char *host = ""; | |
784 | register char *p; register u_char *q; u_char *q_lim; | |
785 | ||
786 | work = sns->sns_addr; | |
787 | port = ntohs(work.x_port); | |
788 | work.x_port = 0; | |
789 | net.net_e = work.x_net; | |
790 | if (ns_nullhost(work) && net.long_e == 0) { | |
791 | if (port ) { | |
9bd38ba8 | 792 | (void)sprintf(mybuf, "*.%xH", port); |
eac76d14 MK |
793 | upHex(mybuf); |
794 | } else | |
9bd38ba8 | 795 | (void)sprintf(mybuf, "*.*"); |
eac76d14 MK |
796 | return (mybuf); |
797 | } | |
798 | ||
799 | if (bcmp(ns_bh, work.x_host.c_host, 6) == 0) { | |
800 | host = "any"; | |
801 | } else if (bcmp(ns_nullh, work.x_host.c_host, 6) == 0) { | |
802 | host = "*"; | |
803 | } else { | |
804 | q = work.x_host.c_host; | |
9bd38ba8 | 805 | (void)sprintf(chost, "%02x%02x%02x%02x%02x%02xH", |
eac76d14 MK |
806 | q[0], q[1], q[2], q[3], q[4], q[5]); |
807 | for (p = chost; *p == '0' && p < chost + 12; p++); | |
808 | host = p; | |
809 | } | |
810 | if (port) | |
9bd38ba8 | 811 | (void)sprintf(cport, ".%xH", htons(port)); |
eac76d14 MK |
812 | else |
813 | *cport = 0; | |
814 | ||
9bd38ba8 | 815 | (void)sprintf(mybuf,"%xH.%s%s", ntohl(net.long_e), host, cport); |
eac76d14 MK |
816 | upHex(mybuf); |
817 | return(mybuf); | |
818 | } | |
819 | ||
820 | upHex(p0) | |
821 | char *p0; | |
822 | { | |
823 | register char *p = p0; | |
824 | for (; *p; p++) switch (*p) { | |
825 | ||
826 | case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': | |
827 | *p += ('A' - 'a'); | |
828 | } | |
829 | } | |
57cacc90 KS |
830 | |
831 | monitor() | |
832 | { | |
833 | int n; | |
834 | char msg[2048]; | |
835 | for(;;) { | |
836 | n = read(s, msg, 2048); | |
837 | printf("got message of size %d\n", n); | |
838 | print_rtmsg((struct rt_msghdr *)msg, n); | |
839 | } | |
840 | } | |
841 | ||
842 | struct { | |
843 | struct rt_msghdr m_rtm; | |
844 | struct sockaddr_in m_dst, m_gateway, m_mask; | |
845 | } m_rtmsg; | |
846 | ||
847 | rtmsg(cmd, dst, gateway, mask, flags) | |
848 | struct sockaddr_in *dst, *gateway, *mask; | |
849 | { | |
850 | static int seq; | |
851 | int len = sizeof(m_rtmsg), rlen; | |
852 | extern int errno; | |
853 | ||
854 | errno = 0; | |
855 | bzero((char *)&m_rtmsg, sizeof(m_rtmsg)); | |
856 | if (cmd == 'a') | |
857 | cmd = RTM_ADD; | |
858 | else if (cmd == 'c') | |
859 | cmd = RTM_CHANGE; | |
860 | else | |
861 | cmd = RTM_DELETE; | |
862 | m_rtmsg.m_rtm.rtm_flags = flags; | |
863 | m_rtmsg.m_rtm.rtm_version = 1; | |
864 | m_rtmsg.m_rtm.rtm_seq = ++seq; | |
865 | m_rtmsg.m_dst = *dst; | |
866 | m_rtmsg.m_gateway = *gateway; | |
867 | if (mask) { | |
868 | m_rtmsg.m_mask = *mask; | |
869 | m_rtmsg.m_rtm.rtm_count = 3; | |
870 | } else { | |
871 | len -= sizeof (*mask); | |
872 | m_rtmsg.m_rtm.rtm_count = 2; | |
873 | } | |
874 | m_rtmsg.m_rtm.rtm_msglen = len; | |
875 | m_rtmsg.m_rtm.rtm_type = cmd; | |
876 | if ((rlen = write(s, (char *)&m_rtmsg, len)) < 0) { | |
877 | perror("writing to routing socket"); | |
878 | printf("got only %d for rlen\n", rlen); | |
7d5f817b | 879 | return (-1); |
57cacc90 KS |
880 | } |
881 | again: | |
882 | if ((rlen = read(s, (char *)&m_rtmsg, len)) < 0) { | |
883 | perror("reading from routing socket"); | |
884 | printf("got only %d for rlen\n", rlen); | |
7d5f817b | 885 | return (-1); |
57cacc90 KS |
886 | } |
887 | if ((m_rtmsg.m_rtm.rtm_pid != pid) || | |
888 | (m_rtmsg.m_rtm.rtm_seq != seq)) { | |
889 | printf("Got response for somebody else's request"); | |
890 | goto again; | |
891 | } | |
892 | if (qflag == 0) | |
893 | print_rtmsg( &m_rtmsg.m_rtm, rlen); | |
894 | if ((m_rtmsg.m_rtm.rtm_flags & RTF_DONE) == 0) { | |
895 | errno = m_rtmsg.m_rtm.rtm_errno; | |
896 | perror("response from routing socket turned down"); | |
897 | return (-1); | |
898 | } | |
899 | return (0); | |
900 | } | |
901 | ||
902 | char *msgtypes[] = { | |
903 | "", | |
904 | "RTM_ADD: Add Route", | |
905 | "RTM_DELETE: Delete Route", | |
906 | "RTM_CHANGE: Change Metrics or flags", | |
907 | "RTM_GET: Report Metrics", | |
908 | "RTM_LOSING: Kernel Suspects Partitioning", | |
909 | "RTM_REDIRECT: Told to use different route", | |
910 | "RTM_MISS: Lookup failed on this address", | |
911 | "RTM_LOCK: fix specified metrics", | |
912 | "RTM_OLDADD: caused by SIOCADDRT", | |
913 | "RTM_OLDDEL: caused by SIOCDELRT", | |
914 | 0, }; | |
915 | ||
916 | char metricnames[] = | |
917 | "\010rttvar\7rtt\6ssthresh\7sendpipe\4recvpipe\3expire\2hopcount\1mtu"; | |
918 | ||
919 | #define ROUNDUP(a) ((char *)(1 + (((((int)a)) - 1) | (sizeof(long) - 1)))) | |
920 | ||
921 | print_rtmsg(rtm, n) | |
922 | register struct rt_msghdr *rtm; | |
923 | { | |
924 | char *cp; | |
925 | register struct sockaddr *sa; | |
926 | int i = rtm->rtm_count; | |
927 | ||
7d5f817b KS |
928 | if (verbose == 0) |
929 | return; | |
57cacc90 | 930 | if (rtm->rtm_version != 1) { |
5c7868a2 | 931 | printf("routing message version %d not understood\n", |
57cacc90 | 932 | rtm->rtm_version); |
5c7868a2 KS |
933 | } else { |
934 | printf("%s\npid: %d, len %d, seq %d, errno %d, flags:", | |
935 | msgtypes[rtm->rtm_type], rtm->rtm_pid, rtm->rtm_msglen, | |
936 | rtm->rtm_seq, rtm->rtm_errno); | |
937 | bprintf(stdout, rtm->rtm_flags, | |
938 | "\1UP\2GATEWAY\3HOST\5DYNAMIC\6MODIFIED\7DONE\010MASK_PRESENT"); | |
939 | printf("\nlocks: "); bprintf(stdout, rtm->rtm_locks, metricnames); | |
940 | printf(" inits: "); bprintf(stdout, rtm->rtm_inits, metricnames); | |
941 | printf("\n%d sockaddrs: ", i); | |
942 | cp = ((char *)(rtm + 1)); | |
943 | while (i-- > 0) { | |
944 | sa = (struct sockaddr *)cp; | |
945 | printf(" %s", routename(sa)); | |
946 | cp = ROUNDUP(cp + sa->sa_len); | |
947 | } | |
948 | putchar('\n'); | |
57cacc90 | 949 | } |
57cacc90 KS |
950 | fflush(stdout); |
951 | } | |
952 | ||
953 | bprintf(fp, b, s) | |
954 | register FILE *fp; | |
955 | register int b; | |
956 | register u_char *s; | |
957 | { | |
958 | register int i; | |
959 | int gotsome = 0; | |
960 | ||
961 | if (b == 0) | |
962 | return; | |
963 | while (i = *s++) { | |
964 | if (b & (1 << (i-1))) { | |
965 | if (gotsome == 0) i = '<'; else i = ','; | |
966 | putc(i, fp); | |
967 | gotsome = 1; | |
968 | for (; (i = *s) > 32; s++) | |
969 | putc(i, fp); | |
970 | } else | |
971 | while (*s > 32) | |
972 | s++; | |
973 | } | |
974 | if (gotsome) | |
975 | putc('>', fp); | |
976 | } |