xref: /original-bsd/sbin/ifconfig/ifconfig.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[] = "@(#)ifconfig.c	4.12 (Berkeley) 06/06/85";
15 #endif not lint
16 
17 
18 #include <sys/types.h>
19 #include <sys/socket.h>
20 #include <sys/ioctl.h>
21 
22 #include <net/if.h>
23 #include <netinet/in.h>
24 
25 #define	NSIP
26 #include <netns/ns.h>
27 #include <netns/ns_if.h>
28 
29 #include <stdio.h>
30 #include <errno.h>
31 #include <ctype.h>
32 #include <netdb.h>
33 
34 extern int errno;
35 struct	ifreq ifr;
36 struct	sockaddr_in sin = { AF_INET };
37 struct	sockaddr_in broadaddr;
38 struct	sockaddr_in netmask = { AF_INET };
39 struct	sockaddr_in ipdst = { AF_INET };
40 char	name[30];
41 int	flags;
42 int	setaddr;
43 int	setmask;
44 int	setbroadaddr;
45 int	setipdst;
46 int	s;
47 extern	int errno;
48 
49 int	setifflags(), setifaddr(), setifdstaddr(), setifnetmask();
50 int	setifbroadaddr(), setifipdst();
51 
52 #define	NEXTARG		0xffffff
53 
54 struct	cmd {
55 	char	*c_name;
56 	int	c_parameter;		/* NEXTARG means next argv */
57 	int	(*c_func)();
58 } cmds[] = {
59 	{ "up",		IFF_UP,		setifflags } ,
60 	{ "down",	-IFF_UP,	setifflags },
61 	{ "trailers",	-IFF_NOTRAILERS,setifflags },
62 	{ "-trailers",	IFF_NOTRAILERS,	setifflags },
63 	{ "arp",	-IFF_NOARP,	setifflags },
64 	{ "-arp",	IFF_NOARP,	setifflags },
65 #ifdef IFF_LOCAL
66 	{ "local",	IFF_LOCAL,	setifflags },
67 	{ "-local",	-IFF_LOCAL,	setifflags },
68 #endif
69 	{ "debug",	IFF_DEBUG,	setifflags },
70 	{ "-debug",	-IFF_DEBUG,	setifflags },
71 #ifdef notdef
72 #define	EN_SWABIPS	0x1000
73 	{ "swabips",	EN_SWABIPS,	setifflags },
74 	{ "-swabips",	-EN_SWABIPS,	setifflags },
75 #endif
76 	{ "netmask",	NEXTARG,	setifnetmask },
77 	{ "broadcast",	NEXTARG,	setifbroadaddr },
78 	{ "ipdst",	NEXTARG,	setifipdst },
79 	{ 0,		0,		setifaddr },
80 	{ 0,		0,		setifdstaddr },
81 };
82 
83 /*
84  * XNS support liberally adapted from
85  * code written at the University of Maryland
86  * principally by James O'Toole and Chris Torek.
87  */
88 
89 int	in_status(), in_getaddr();
90 int	xns_status(), xns_getaddr();
91 
92 /* Known address families */
93 struct afswtch {
94 	char *af_name;
95 	short af_af;
96 	int (*af_status)();
97 	int (*af_getaddr)();
98 } afs[] = {
99 	{ "inet",	AF_INET,	in_status,	in_getaddr },
100 	{ "ns",		AF_NS,		xns_status,	xns_getaddr },
101 	{ 0,		0,		0,		0 }
102 };
103 
104 struct afswtch *afp;	/*the address family being set or asked about*/
105 
106 main(argc, argv)
107 	int argc;
108 	char *argv[];
109 {
110 	int af = AF_INET;
111 	if (argc < 2) {
112 		fprintf(stderr, "usage: ifconfig interface [ af %s %s %s %s\n",
113 		    "[ address [ dest_addr ] ] [ up ] [ down ]",
114 		    "[ netmask mask ] ]",
115 		    "[ trailers | -trailers ]",
116 		    "[ arp | -arp ] ]");
117 		exit(1);
118 	}
119 	argc--, argv++;
120 	strncpy(name, *argv, sizeof(name - 1));
121 	name[sizeof name - 1] = 0;
122 	strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
123 	argc--, argv++;
124 	if (argc > 0) {
125 		struct afswtch *myafp;
126 
127 		for (myafp = afp = afs; myafp->af_name; myafp++)
128 			if (strcmp(myafp->af_name, *argv) == 0) {
129 				afp = myafp; argc--; argv++;
130 				break;
131 			}
132 		af = ifr.ifr_addr.sa_family = afp->af_af;
133 	}
134 	s = socket(af, SOCK_DGRAM, 0);
135 	if (s < 0) {
136 		perror("ifconfig: socket");
137 		exit(1);
138 	}
139 	if (ioctl(s, SIOCGIFFLAGS, (caddr_t)&ifr) < 0) {
140 		Perror("ioctl (SIOCGIFFLAGS)");
141 		exit(1);
142 	}
143 	strncpy(ifr.ifr_name, name, sizeof ifr.ifr_name);
144 	flags = ifr.ifr_flags;
145 	if (af == AF_INET) {
146 		if (ioctl(s, SIOCGIFNETMASK, (caddr_t)&ifr) < 0) {
147 			if (errno != EADDRNOTAVAIL)
148 				Perror("ioctl (SIOCGIFNETMASK)");
149 		} else
150 			netmask.sin_addr =
151 			      ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr;
152 		strncpy(ifr.ifr_name, name, sizeof ifr.ifr_name);
153 	}
154 	if (argc == 0) {
155 		status();
156 		exit(0);
157 	}
158 	while (argc > 0) {
159 		register struct cmd *p;
160 
161 		for (p = cmds; p->c_name; p++)
162 			if (strcmp(*argv, p->c_name) == 0)
163 				break;
164 		if (p->c_name == 0 && setaddr)
165 			p++;	/* got src, do dst */
166 		if (p->c_func) {
167 			if (p->c_parameter == NEXTARG) {
168 				(*p->c_func)(argv[1]);
169 				argc--, argv++;
170 			} else
171 				(*p->c_func)(*argv, p->c_parameter);
172 		}
173 		argc--, argv++;
174 	}
175 	if ((setmask || setaddr) && (af == AF_INET)){
176 		/*
177 		 * If setting the address and not the mask,
178 		 * clear any existing mask and the kernel will then
179 		 * assign the default.  If setting both,
180 		 * set the mask first, so the address will be
181 		 * interpreted correctly.
182 		 */
183 		ifr.ifr_addr = *(struct sockaddr *)&netmask;
184 		if (ioctl(s, SIOCSIFNETMASK, (caddr_t)&ifr) < 0)
185 			Perror("ioctl (SIOCSIFNETMASK)");
186 	}
187 	if (setipdst && af==AF_NS) {
188 		struct nsip_req rq;
189 		int size = sizeof(rq);
190 
191 		rq.rq_ns = *(struct sockaddr *) &sin;
192 		rq.rq_ip = *(struct sockaddr *) &ipdst;
193 
194 		if (setsockopt(s, 0, SO_NSIP_ROUTE, &rq, size) < 0)
195 			Perror("Encapsulation Routing");
196 		setaddr = 0;
197 	}
198 	if (setaddr) {
199 		ifr.ifr_addr = *(struct sockaddr *) &sin;
200 		if (ioctl(s, SIOCSIFADDR, (caddr_t)&ifr) < 0)
201 			Perror("ioctl (SIOCSIFADDR)");
202 	}
203 	if (setbroadaddr) {
204 		ifr.ifr_addr = *(struct sockaddr *)&broadaddr;
205 		if (ioctl(s, SIOCSIFBRDADDR, (caddr_t)&ifr) < 0)
206 			Perror("ioctl (SIOCSIFBRDADDR)");
207 	}
208 	exit(0);
209 }
210 
211 /*ARGSUSED*/
212 setifaddr(addr, param)
213 	char *addr;
214 	short param;
215 {
216 	/*
217 	 * Delay the ioctl to set the interface addr until flags are all set.
218 	 * The address interpretation may depend on the flags,
219 	 * and the flags may change when the address is set.
220 	 */
221 	setaddr++;
222 	(*afp->af_getaddr)(addr, &sin);
223 }
224 
225 setifnetmask(addr)
226 	char *addr;
227 {
228 	in_getaddr(addr, &netmask);
229 	setmask++;
230 }
231 
232 setifbroadaddr(addr)
233 	char *addr;
234 {
235 	(*afp->af_getaddr)(addr, &broadaddr);
236 	setbroadaddr++;
237 }
238 
239 setifipdst(addr)
240 	char *addr;
241 {
242 	in_getaddr(addr, &ipdst);
243 	setipdst++;
244 }
245 
246 /*ARGSUSED*/
247 setifdstaddr(addr, param)
248 	char *addr;
249 	int param;
250 {
251 
252 	(*afp->af_getaddr)(addr, &ifr.ifr_addr);
253 	if (ioctl(s, SIOCSIFDSTADDR, (caddr_t)&ifr) < 0)
254 		Perror("ioctl (SIOCSIFDSTADDR)");
255 }
256 
257 setifflags(vname, value)
258 	char *vname;
259 	short value;
260 {
261  	if (ioctl(s, SIOCGIFFLAGS, (caddr_t)&ifr) < 0) {
262  		Perror("ioctl (SIOCGIFFLAGS)");
263  		exit(1);
264  	}
265 	strncpy(ifr.ifr_name, name, sizeof (ifr.ifr_name));
266  	flags = ifr.ifr_flags;
267 
268 	if (value < 0) {
269 		value = -value;
270 		flags &= ~value;
271 	} else
272 		flags |= value;
273 	ifr.ifr_flags = flags;
274 	if (ioctl(s, SIOCSIFFLAGS, (caddr_t)&ifr) < 0)
275 		Perror(vname);
276 }
277 
278 /*
279  * Print the status of the interface.  If an address family was
280  * specified, show it and it only; otherwise, show them all.
281  */
282 status()
283 {
284 	register struct afswtch *p = afp;
285 	short af = ifr.ifr_addr.sa_family;
286 
287 	if ((p = afp) != NULL) {
288 		(*p->af_status)();
289 		return;
290 	}
291 	for (p = afs; p->af_name; p++) {
292 		ifr.ifr_addr.sa_family = p->af_af;
293 		(*p->af_status)();
294 	}
295 }
296 
297 #define	IFFBITS \
298 "\020\1UP\2BROADCAST\3DEBUG\4ROUTE\5POINTOPOINT\6NOTRAILERS\7RUNNING\10NOARP\
299 \11LOCAL"
300 
301 in_status()
302 {
303 	struct sockaddr_in *sin;
304 	char *inet_ntoa();
305 
306 	if (ioctl(s, SIOCGIFADDR, (caddr_t)&ifr) < 0) {
307 		if (errno == EADDRNOTAVAIL)
308 			bzero((char *)&ifr.ifr_addr, sizeof(ifr.ifr_addr));
309 		else
310 			Perror("ioctl (SIOCGIFADDR)");
311 	}
312 	strncpy(ifr.ifr_name, name, sizeof (ifr.ifr_name));
313 	sin = (struct sockaddr_in *)&ifr.ifr_addr;
314 	printf("%s: %s ", name, inet_ntoa(sin->sin_addr));
315 	if (flags & IFF_POINTOPOINT) {
316 		if (ioctl(s, SIOCGIFDSTADDR, (caddr_t)&ifr) < 0) {
317 			if (errno == EADDRNOTAVAIL)
318 			    bzero((char *)&ifr.ifr_addr, sizeof(ifr.ifr_addr));
319 			else
320 			    Perror("ioctl (SIOCGIFDSTADDR)");
321 		}
322 		strncpy(ifr.ifr_name, name, sizeof (ifr.ifr_name));
323 		sin = (struct sockaddr_in *)&ifr.ifr_dstaddr;
324 		printf("--> %s ", inet_ntoa(sin->sin_addr));
325 	}
326 	printf("netmask %x ", ntohl(netmask.sin_addr.s_addr));
327 	printb("flags", flags, IFFBITS); putchar('\n');
328 	if (flags & IFF_BROADCAST) {
329 		if (ioctl(s, SIOCGIFBRDADDR, (caddr_t)&ifr) < 0) {
330 			if (errno == EADDRNOTAVAIL)
331 				return;
332 			Perror("ioctl (SIOCGIFADDR)");
333 		}
334 		strncpy(ifr.ifr_name, name, sizeof (ifr.ifr_name));
335 		sin = (struct sockaddr_in *)&ifr.ifr_addr;
336 		printf("broadcast: %s\n", inet_ntoa(sin->sin_addr));
337 	}
338 }
339 
340 
341 xns_status()
342 {
343 	struct sockaddr_ns *sns;
344 	char *xns_ntoa();
345 
346 	close(s);
347 	s = socket(AF_NS, SOCK_DGRAM, 0);
348 	if (s < 0) {
349 		perror("ifconfig: socket");
350 		exit(1);
351 	}
352 	if (ioctl(s, SIOCGIFADDR, (caddr_t)&ifr) < 0) {
353 		if (errno == EAFNOSUPPORT)
354 			return;
355 		Perror("ioctl (SIOCGIFADDR)");
356 	}
357 	strncpy(ifr.ifr_name, name, sizeof ifr.ifr_name);
358 	sns = (struct sockaddr_ns *)&ifr.ifr_addr;
359 	printf("%s: xns %s ", name, xns_ntoa(sns));
360 	printb("flags", flags, IFFBITS);
361 	putchar('\n');
362 }
363 
364 Perror(cmd)
365 	char *cmd;
366 {
367 	extern int errno;
368 
369 	fprintf(stderr, "ifconfig: ");
370 	switch (errno) {
371 
372 	case ENXIO:
373 		fprintf(stderr, "%s: no such interface\n", cmd);
374 		break;
375 
376 	case EPERM:
377 		fprintf(stderr, "%s: permission denied\n", cmd);
378 		break;
379 
380 	default:
381 		perror(cmd);
382 	}
383 	exit(1);
384 }
385 
386 struct	in_addr inet_makeaddr();
387 
388 in_getaddr(s, saddr)
389 	char *s;
390 	struct sockaddr *saddr;
391 {
392 	register struct sockaddr_in *sin = (struct sockaddr_in *)saddr;
393 	struct hostent *hp;
394 	struct netent *np;
395 	int val;
396 
397 	sin->sin_family = AF_INET;
398 	val = inet_addr(s);
399 	if (val != -1) {
400 		sin->sin_addr.s_addr = val;
401 		return;
402 	}
403 	hp = gethostbyname(s);
404 	if (hp) {
405 		sin->sin_family = hp->h_addrtype;
406 		bcopy(hp->h_addr, (char *)&sin->sin_addr, hp->h_length);
407 		return;
408 	}
409 	np = getnetbyname(s);
410 	if (np) {
411 		sin->sin_family = np->n_addrtype;
412 		sin->sin_addr = inet_makeaddr(np->n_net, INADDR_ANY);
413 		return;
414 	}
415 	fprintf(stderr, "%s: bad value\n", s);
416 	exit(1);
417 }
418 
419 /*
420  * Print a value a la the %b format of the kernel's printf
421  */
422 printb(s, v, bits)
423 	char *s;
424 	register char *bits;
425 	register unsigned short v;
426 {
427 	register int i, any = 0;
428 	register char c;
429 
430 	if (bits && *bits == 8)
431 		printf("%s=%o", s, v);
432 	else
433 		printf("%s=%x", s, v);
434 	bits++;
435 	if (bits) {
436 		putchar('<');
437 		while (i = *bits++) {
438 			if (v & (1 << (i-1))) {
439 				if (any)
440 					putchar(',');
441 				any = 1;
442 				for (; (c = *bits) > 32; bits++)
443 					putchar(c);
444 			} else
445 				for (; *bits > 32; bits++)
446 					;
447 		}
448 		putchar('>');
449 	}
450 }
451 
452 #define setxnnet(a,b) {a = * (union ns_net *) &(b);}
453 
454 xns_getaddr(addr, saddr)
455 char *addr;
456 struct sockaddr *saddr;
457 {
458 	register struct sockaddr_ns *sns = (struct sockaddr_ns *)saddr;
459 	u_long netnum;
460 	char *index();
461 	register char *s = index(addr, ':');
462 	register int i;
463 
464 	if (s!=NULL) *s = 0;
465 	netnum = atoi(addr);
466 	netnum = htonl(netnum);
467 	setxnnet(sns->sns_addr.x_net, netnum);
468 	sns->sns_family = AF_NS;
469 
470 	for (i = 0; i < 6; i++) {
471 		if (s == NULL || *++s == 0)
472 			break;
473 		sns->sns_addr.x_host.c_host[i] = xtoi(s);
474 		s = index(s, '.');
475 	}
476 
477 }
478 
479 char *
480 xns_ntoa(sns)
481 register struct sockaddr_ns *sns;
482 {
483 	static char buf[30];
484 
485 	sprintf (buf, "%d:%x.%x.%x.%x.%x.%x",
486 	    ntohl(ns_netof(sns->sns_addr)),
487 	    sns->sns_addr.x_host.c_host[0], sns->sns_addr.x_host.c_host[1],
488 	    sns->sns_addr.x_host.c_host[2], sns->sns_addr.x_host.c_host[3],
489 	    sns->sns_addr.x_host.c_host[4], sns->sns_addr.x_host.c_host[5]);
490 	return (buf);
491 }
492 
493 int xtoi(s)
494 register char *s;
495 {
496 	register int res = 0, delta;
497 	register char *cp;
498 	static char base[] = "0123456789ABCDEFabcdef";
499 
500 	for(; *s; s++) {
501 		cp = index(base, *s);
502 		if (cp==NULL)
503 			break;
504 		if ((delta = cp - base) > 15)
505 			delta -= 6;
506 		res = (res << 4) + delta;
507 	}
508 	return(res);
509 }
510