xref: /original-bsd/sbin/route/route.c (revision aba77441)
1 /*
2  * Copyright (c) 1983 Regents of the University of California.
3  * All rights reserved.  The Berkeley software License Agreement
4  * specifies the terms and conditions for redistribution.
5  */
6 
7 #ifndef lint
8 char copyright[] =
9 "@(#) Copyright (c) 1983 Regents of the University of California.\n\
10  All rights reserved.\n";
11 #endif not lint
12 
13 #ifndef lint
14 static char sccsid[] = "@(#)route.c	5.1 (Berkeley) 06/04/85";
15 #endif not lint
16 
17 #include <sys/types.h>
18 #include <sys/socket.h>
19 #include <sys/ioctl.h>
20 #include <sys/mbuf.h>
21 
22 #include <net/route.h>
23 #include <netinet/in.h>
24 
25 #include <stdio.h>
26 #include <errno.h>
27 #include <ctype.h>
28 #include <netdb.h>
29 
30 struct	rtentry route;
31 int	s;
32 int	forcehost, forcenet;
33 struct	sockaddr_in sin = { AF_INET };
34 struct	in_addr inet_makeaddr();
35 
36 main(argc, argv)
37 	int argc;
38 	char *argv[];
39 {
40 
41 	if (argc < 2)
42 		printf("usage: route [ -f ] [ [ -h ] [ -n ] cmd args ]\n"),
43 		exit(1);
44 	s = socket(AF_INET, SOCK_RAW, 0);
45 	if (s < 0) {
46 		perror("route: socket");
47 		exit(1);
48 	}
49 	argc--, argv++;
50 	for (; argc >  0 && argv[0][0] == '-'; argc--, argv++) {
51 		for (argv[0]++; *argv[0]; argv[0]++)
52 			switch (*argv[0]) {
53 			case 'f':
54 				flushroutes();
55 				break;
56 			case 'h':
57 				forcehost++;
58 				break;
59 			case 'n':
60 				forcenet++;
61 				break;
62 			}
63 	}
64 	if (forcehost && forcenet) {
65 		fprintf(stderr, "-n and -h are incompatible\n");
66 		exit(1);
67 	}
68 	if (argc > 0) {
69 		if (strcmp(*argv, "add") == 0)
70 			newroute(argc, argv);
71 		else if (strcmp(*argv, "delete") == 0)
72 			newroute(argc, argv);
73 		else if (strcmp(*argv, "change") == 0)
74 			changeroute(argc-1, argv+1);
75 		else
76 			printf("%s: huh?\n", *argv);
77 	}
78 }
79 
80 /*
81  * Purge all entries in the routing tables not
82  * associated with network interfaces.
83  */
84 #include <nlist.h>
85 
86 struct nlist nl[] = {
87 #define	N_RTHOST	0
88 	{ "_rthost" },
89 #define	N_RTNET		1
90 	{ "_rtnet" },
91 #define N_RTHASHSIZE	2
92 	{ "_rthashsize" },
93 	"",
94 };
95 
96 flushroutes()
97 {
98 	struct mbuf mb;
99 	register struct rtentry *rt;
100 	register struct mbuf *m;
101 	struct mbuf **routehash;
102 	int rthashsize, i, doinghost = 1, kmem;
103 	char *routename();
104 
105 	nlist("/vmunix", nl);
106 	if (nl[N_RTHOST].n_value == 0) {
107 		printf("route: \"rthost\", symbol not in namelist\n");
108 		exit(1);
109 	}
110 	if (nl[N_RTNET].n_value == 0) {
111 		printf("route: \"rtnet\", symbol not in namelist\n");
112 		exit(1);
113 	}
114 	if (nl[N_RTHASHSIZE].n_value == 0) {
115 		printf("route: \"rthashsize\", symbol not in namelist\n");
116 		exit(1);
117 	}
118 	kmem = open("/dev/kmem", 0);
119 	if (kmem < 0) {
120 		perror("route: /dev/kmem");
121 		exit(1);
122 	}
123 	lseek(kmem, nl[N_RTHASHSIZE].n_value, 0);
124 	read(kmem, &rthashsize, sizeof (rthashsize));
125 	routehash = (struct mbuf **)malloc(rthashsize*sizeof (struct mbuf *));
126 
127 	lseek(kmem, nl[N_RTHOST].n_value, 0);
128 	read(kmem, routehash, rthashsize*sizeof (struct mbuf *));
129 	printf("Flushing routing tables:\n");
130 again:
131 	for (i = 0; i < rthashsize; i++) {
132 		if (routehash[i] == 0)
133 			continue;
134 		m = routehash[i];
135 		while (m) {
136 			lseek(kmem, m, 0);
137 			read(kmem, &mb, sizeof (mb));
138 			rt = mtod(&mb, struct rtentry *);
139 			if (rt->rt_flags & RTF_GATEWAY) {
140 				struct sockaddr_in *sin;
141 
142 				sin = (struct sockaddr_in *)&rt->rt_dst;
143 				printf("%-15.15s ", routename(sin->sin_addr));
144 				sin = (struct sockaddr_in *)&rt->rt_gateway;
145 				printf("%-15.15s ", routename(sin->sin_addr));
146 				if (ioctl(s, SIOCDELRT, (caddr_t)rt) < 0)
147 					error("delete");
148 				else
149 					printf("done\n");
150 			}
151 			m = mb.m_next;
152 		}
153 	}
154 	if (doinghost) {
155 		lseek(kmem, nl[N_RTNET].n_value, 0);
156 		read(kmem, routehash, rthashsize*sizeof (struct mbuf *));
157 		doinghost = 0;
158 		goto again;
159 	}
160 	close(kmem);
161 	free(routehash);
162 }
163 
164 char *
165 routename(in)
166 	struct in_addr in;
167 {
168 	char *cp = 0;
169 	static char line[50];
170 	struct hostent *hp;
171 	struct netent *np;
172 	int lna, net;
173 
174 	net = inet_netof(in);
175 	lna = inet_lnaof(in);
176 	if (in.s_addr == INADDR_ANY)
177 		cp = "default";
178 	if (cp == 0 && (lna == INADDR_ANY || forcenet)) {
179 		np = getnetbyaddr(net, AF_INET);
180 		if (np)
181 			cp = np->n_name;
182 	}
183 	if (cp == 0) {
184 		hp = gethostbyaddr(&in, sizeof (struct in_addr), AF_INET);
185 		if (hp)
186 			cp = hp->h_name;
187 	}
188 	if (cp)
189 		strcpy(line, cp);
190 	else {
191 		u_char *ucp = (u_char *)&in;
192 		if (lna == INADDR_ANY)
193 			sprintf(line, "%u.%u.%u", ucp[0], ucp[1], ucp[2]);
194 		else
195 			sprintf(line, "%u.%u.%u.%u", ucp[0], ucp[1],
196 				ucp[2], ucp[3]);
197 	}
198 	return (line);
199 }
200 
201 newroute(argc, argv)
202 	int argc;
203 	char *argv[];
204 {
205 	struct sockaddr_in *sin;
206 	char *cmd;
207 	int ishost, metric = 0;
208 
209 	cmd = argv[0];
210 	if (*cmd == 'a') {
211 		if (argc != 4) {
212 			printf("usage: %s destination gateway metric\n", cmd);
213 			printf("(metric of 0 if gateway is this host)\n");
214 			return;
215 		}
216 		metric = atoi(argv[3]);
217 	} else {
218 		if (argc != 3) {
219 			printf("usage: %s destination gateway\n", cmd);
220 			return;
221 		}
222 	}
223 	ishost = getaddr(argv[1], &route.rt_dst);
224 	if (forcehost)
225 		ishost = 1;
226 	if (forcenet)
227 		ishost = 0;
228 	(void) getaddr(argv[2], &route.rt_gateway);
229 	sin = (struct sockaddr_in *)&route.rt_dst;
230 	route.rt_flags = RTF_UP;
231 	if (ishost)
232 		route.rt_flags |= RTF_HOST;
233 	if (metric > 0)
234 		route.rt_flags |= RTF_GATEWAY;
235 	printf("%s %s: gateway ", cmd, routename(sin->sin_addr));
236 	sin = (struct sockaddr_in *)&route.rt_gateway;
237 	printf("%s, flags %x\n", routename(sin->sin_addr), route.rt_flags);
238 	if (ioctl(s, *cmd == 'a' ? SIOCADDRT : SIOCDELRT, (caddr_t)&route))
239 		error(cmd);
240 }
241 
242 changeroute(argc, argv)
243 	int argc;
244 	char *argv[];
245 {
246 	printf("not supported\n");
247 }
248 
249 error(cmd)
250 	char *cmd;
251 {
252 	extern int errno;
253 
254 	if (errno == ESRCH)
255 		fprintf(stderr, "not in table\n");
256 	else if (errno == EBUSY)
257 		fprintf(stderr, "entry in use\n");
258 	else if (errno == ENOBUFS)
259 		fprintf(stderr, "routing table overflow\n");
260 	else
261 		perror(cmd);
262 }
263 
264 /*
265  * Interpret an argument as a network address of some kind,
266  * returning 1 if a host address, 0 if a network address.
267  */
268 getaddr(s, sin)
269 	char *s;
270 	struct sockaddr_in *sin;
271 {
272 	struct hostent *hp;
273 	struct netent *np;
274 	u_long val;
275 
276 	if (strcmp(s, "default") == 0) {
277 		sin->sin_family = AF_INET;
278 		sin->sin_addr = inet_makeaddr(0, INADDR_ANY);
279 		return(0);
280 	}
281 	np = getnetbyname(s);
282 	if (np) {
283 		sin->sin_family = np->n_addrtype;
284 		sin->sin_addr = inet_makeaddr(np->n_net, INADDR_ANY);
285 		return(0);
286 	}
287 	hp = gethostbyname(s);
288 	if (hp) {
289 		sin->sin_family = hp->h_addrtype;
290 		bcopy(hp->h_addr, &sin->sin_addr, hp->h_length);
291 		return(1);
292 	}
293 	sin->sin_family = AF_INET;
294 	val = inet_addr(s);
295 	if (val != -1) {
296 		sin->sin_addr.s_addr = val;
297 		return(inet_lnaof(sin->sin_addr) != INADDR_ANY);
298 	}
299 	val = inet_network(s);
300 	if (val != -1) {
301 		sin->sin_addr = inet_makeaddr(val, INADDR_ANY);
302 		return(0);
303 	}
304 	fprintf(stderr, "%s: bad value\n", s);
305 	exit(1);
306 }
307