master xplshn/aruu / cmd / net / ifconfig.c
  1/* See LICENSE file for copyright and license details. */
  2
  3
  4#include <arpa/inet.h>
  5#include <ctype.h>
  6#include <errno.h>
  7#include <net/if.h>
  8#include <stdio.h>
  9#include <stdlib.h>
 10#include <string.h>
 11#include <sys/ioctl.h>
 12#include <sys/socket.h>
 13#include <sys/types.h>
 14#include <unistd.h>
 15
 16#include "util.h"
 17
 18int net_get_interfaces(struct NetInterface **, int *);
 19int net_get_stats(const char *, struct NetStats *);
 20int net_set_txqueuelen(const char *, int);
 21
 22static void
 23usage(void)
 24{
 25	eprintf("usage: %s [-a] [interface [action ...]]\n", argv0);
 26}
 27
 28static void
 29display_interface(const struct NetInterface *iface)
 30{
 31	struct NetStats stats;
 32	char ipv6_str[INET6_ADDRSTRLEN];
 33
 34	printf("%-9s Link encap:", iface->name);
 35	if (iface->has_mac) {
 36		printf("Ethernet  HWaddr %02x:%02x:%02x:%02x:%02x:%02x\n",
 37		       iface->mac[0], iface->mac[1], iface->mac[2],
 38		       iface->mac[3], iface->mac[4], iface->mac[5]);
 39	} else if (iface->flags & IFF_LOOPBACK) {
 40		printf("Local Loopback\n");
 41	} else {
 42		printf("UNSPEC\n");
 43	}
 44
 45	if (iface->has_ipv4) {
 46		printf("        inet addr:%s", inet_ntoa(iface->ipv4_addr.sin_addr));
 47		printf("  Bcast:%s", inet_ntoa(iface->ipv4_brd.sin_addr));
 48		printf("  Mask:%s\n", inet_ntoa(iface->ipv4_mask.sin_addr));
 49	}
 50
 51	if (iface->has_ipv6) {
 52		if (inet_ntop(AF_INET6, &iface->ipv6_addr.sin6_addr, ipv6_str, sizeof(ipv6_str))) {
 53			printf("        inet6 addr: %s\n", ipv6_str);
 54		}
 55	}
 56
 57	printf("        ");
 58	if (iface->flags & IFF_UP) printf("UP ");
 59	if (iface->flags & IFF_BROADCAST) printf("BROADCAST ");
 60	if (iface->flags & IFF_DEBUG) printf("DEBUG ");
 61	if (iface->flags & IFF_LOOPBACK) printf("LOOPBACK ");
 62	if (iface->flags & IFF_POINTOPOINT) printf("POINTOPOINT ");
 63	if (iface->flags & IFF_RUNNING) printf("RUNNING ");
 64	if (iface->flags & IFF_NOARP) printf("NOARP ");
 65	if (iface->flags & IFF_PROMISC) printf("PROMISC ");
 66	if (iface->flags & IFF_ALLMULTI) printf("ALLMULTI ");
 67	if (iface->flags & IFF_MULTICAST) printf("MULTICAST ");
 68
 69	printf(" MTU:%d  Metric:%d\n", iface->mtu, iface->metric);
 70
 71	if (net_get_stats(iface->name, &stats) >= 0) {
 72		printf("        RX packets:%llu errors:%llu dropped:%llu overruns:0 frame:0\n",
 73		       stats.rx_packets, stats.rx_errs, stats.rx_drop);
 74		printf("        TX packets:%llu errors:%llu dropped:%llu overruns:0 carrier:0\n",
 75		       stats.tx_packets, stats.tx_errs, stats.tx_drop);
 76		printf("        RX bytes:%llu  TX bytes:%llu\n",
 77		       stats.rx_bytes, stats.tx_bytes);
 78	}
 79	printf("\n");
 80}
 81
 82static void
 83list_interfaces(int all)
 84{
 85	struct NetInterface *ifaces = NULL;
 86	int count = 0;
 87	int i;
 88
 89	if (net_get_interfaces(&ifaces, &count) < 0)
 90		eprintf("net_get_interfaces:");
 91
 92	for (i = 0; i < count; i++) {
 93		if (all || (ifaces[i].flags & IFF_UP)) {
 94			display_interface(&ifaces[i]);
 95		}
 96	}
 97	free(ifaces);
 98}
 99
100// ?man ifconfig: configure network interfaces
101// ?man arguments: interface [action ...
102// ?man configure network interface parameters and view stats
103int
104main(int argc, char *argv[])
105{
106	struct NetInterface *ifaces = NULL;
107	const struct NetInterface *iface = NULL;
108	struct ifreq ifr;
109	struct sockaddr_in *sin;
110	char *name;
111	char *arg;
112	char *slash;
113	int aflag = 0;
114	int sock = -1;
115	int i = 1;
116	int prefix;
117	int count = 0;
118	unsigned int mask;
119
120	ARGBEGIN {
121	// ?man -a: print or show all entries
122	case 'a':
123		aflag = 1;
124		break;
125	default:
126		usage();
127	} ARGEND
128
129	if (argc == 0) {
130		list_interfaces(aflag);
131		return 0;
132	}
133
134	name = argv[0];
135
136	if (net_get_interfaces(&ifaces, &count) < 0)
137		eprintf("net_get_interfaces:");
138
139	for (prefix = 0; prefix < count; prefix++) {
140		if (strcmp(ifaces[prefix].name, name) == 0) {
141			iface = &ifaces[prefix];
142			break;
143		}
144	}
145
146	if (argc == 1) {
147		if (!iface)
148			eprintf("interface %s not found\n", name);
149		display_interface(iface);
150		free(ifaces);
151		return 0;
152	}
153
154	sock = socket(AF_INET, SOCK_DGRAM, 0);
155	if (sock < 0)
156		eprintf("socket:");
157
158	memset(&ifr, 0, sizeof(ifr));
159	strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
160
161	while (i < argc) {
162		arg = argv[i];
163
164		if (strcmp(arg, "up") == 0) {
165			if (ioctl(sock, SIOCGIFFLAGS, &ifr) < 0) eprintf("ioctl SIOCGIFFLAGS:");
166			ifr.ifr_flags |= IFF_UP | IFF_RUNNING;
167			if (ioctl(sock, SIOCSIFFLAGS, &ifr) < 0) eprintf("ioctl SIOCSIFFLAGS:");
168			i++;
169		} else if (strcmp(arg, "down") == 0) {
170			if (ioctl(sock, SIOCGIFFLAGS, &ifr) < 0) eprintf("ioctl SIOCGIFFLAGS:");
171			ifr.ifr_flags &= ~IFF_UP;
172			if (ioctl(sock, SIOCSIFFLAGS, &ifr) < 0) eprintf("ioctl SIOCSIFFLAGS:");
173			i++;
174		} else if (strcmp(arg, "netmask") == 0) {
175			if (i + 1 >= argc) eprintf("netmask needs an address\n");
176			sin = (struct sockaddr_in *)&ifr.ifr_netmask;
177			sin->sin_family = AF_INET;
178			if (inet_pton(AF_INET, argv[i + 1], &sin->sin_addr) <= 0)
179				eprintf("invalid address: %s\n", argv[i + 1]);
180			if (ioctl(sock, SIOCSIFNETMASK, &ifr) < 0) eprintf("ioctl SIOCSIFNETMASK:");
181			i += 2;
182		} else if (strcmp(arg, "broadcast") == 0) {
183			if (i + 1 >= argc) eprintf("broadcast needs an address\n");
184			sin = (struct sockaddr_in *)&ifr.ifr_broadaddr;
185			sin->sin_family = AF_INET;
186			if (inet_pton(AF_INET, argv[i + 1], &sin->sin_addr) <= 0)
187				eprintf("invalid address: %s\n", argv[i + 1]);
188			if (ioctl(sock, SIOCSIFBRDADDR, &ifr) < 0) eprintf("ioctl SIOCSIFBRDADDR:");
189			if (ioctl(sock, SIOCGIFFLAGS, &ifr) < 0) eprintf("ioctl SIOCGIFFLAGS:");
190			ifr.ifr_flags |= IFF_BROADCAST;
191			if (ioctl(sock, SIOCSIFFLAGS, &ifr) < 0) eprintf("ioctl SIOCSIFFLAGS:");
192			i += 2;
193		} else if (strcmp(arg, "mtu") == 0) {
194			if (i + 1 >= argc) eprintf("mtu needs a value\n");
195			ifr.ifr_mtu = atoi(argv[i + 1]);
196			if (ioctl(sock, SIOCSIFMTU, &ifr) < 0) eprintf("ioctl SIOCSIFMTU:");
197			i += 2;
198		} else if (strcmp(arg, "metric") == 0) {
199			if (i + 1 >= argc) eprintf("metric needs a value\n");
200			ifr.ifr_metric = atoi(argv[i + 1]);
201			if (ioctl(sock, SIOCSIFMETRIC, &ifr) < 0) eprintf("ioctl SIOCSIFMETRIC:");
202			i += 2;
203		} else if (strcmp(arg, "txqueuelen") == 0) {
204			if (i + 1 >= argc) eprintf("txqueuelen needs a value\n");
205			if (net_set_txqueuelen(name, atoi(argv[i + 1])) < 0)
206				eprintf("net_set_txqueuelen:");
207			i += 2;
208		} else if (strcmp(arg, "dstaddr") == 0 || strcmp(arg, "pointopoint") == 0) {
209			if (i + 1 >= argc) eprintf("%s needs an address\n", arg);
210			sin = (struct sockaddr_in *)&ifr.ifr_dstaddr;
211			sin->sin_family = AF_INET;
212			if (inet_pton(AF_INET, argv[i + 1], &sin->sin_addr) <= 0)
213				eprintf("invalid address: %s\n", argv[i + 1]);
214			if (ioctl(sock, SIOCSIFDSTADDR, &ifr) < 0) eprintf("ioctl SIOCSIFDSTADDR:");
215			if (ioctl(sock, SIOCGIFFLAGS, &ifr) < 0) eprintf("ioctl SIOCGIFFLAGS:");
216			ifr.ifr_flags |= IFF_POINTOPOINT;
217			if (ioctl(sock, SIOCSIFFLAGS, &ifr) < 0) eprintf("ioctl SIOCSIFFLAGS:");
218			i += 2;
219		} else if (strcmp(arg, "arp") == 0) {
220			if (ioctl(sock, SIOCGIFFLAGS, &ifr) < 0) eprintf("ioctl SIOCGIFFLAGS:");
221			ifr.ifr_flags &= ~IFF_NOARP;
222			if (ioctl(sock, SIOCSIFFLAGS, &ifr) < 0) eprintf("ioctl SIOCSIFFLAGS:");
223			i++;
224		} else if (strcmp(arg, "-arp") == 0) {
225			if (ioctl(sock, SIOCGIFFLAGS, &ifr) < 0) eprintf("ioctl SIOCGIFFLAGS:");
226			ifr.ifr_flags |= IFF_NOARP;
227			if (ioctl(sock, SIOCSIFFLAGS, &ifr) < 0) eprintf("ioctl SIOCSIFFLAGS:");
228			i++;
229		} else if (strcmp(arg, "promisc") == 0) {
230			if (ioctl(sock, SIOCGIFFLAGS, &ifr) < 0) eprintf("ioctl SIOCGIFFLAGS:");
231			ifr.ifr_flags |= IFF_PROMISC;
232			if (ioctl(sock, SIOCSIFFLAGS, &ifr) < 0) eprintf("ioctl SIOCSIFFLAGS:");
233			i++;
234		} else if (strcmp(arg, "-promisc") == 0) {
235			if (ioctl(sock, SIOCGIFFLAGS, &ifr) < 0) eprintf("ioctl SIOCGIFFLAGS:");
236			ifr.ifr_flags &= ~IFF_PROMISC;
237			if (ioctl(sock, SIOCSIFFLAGS, &ifr) < 0) eprintf("ioctl SIOCSIFFLAGS:");
238			i++;
239		} else if (strcmp(arg, "allmulti") == 0) {
240			if (ioctl(sock, SIOCGIFFLAGS, &ifr) < 0) eprintf("ioctl SIOCGIFFLAGS:");
241			ifr.ifr_flags |= IFF_ALLMULTI;
242			if (ioctl(sock, SIOCSIFFLAGS, &ifr) < 0) eprintf("ioctl SIOCSIFFLAGS:");
243			i++;
244		} else if (strcmp(arg, "-allmulti") == 0) {
245			if (ioctl(sock, SIOCGIFFLAGS, &ifr) < 0) eprintf("ioctl SIOCGIFFLAGS:");
246			ifr.ifr_flags &= ~IFF_ALLMULTI;
247			if (ioctl(sock, SIOCSIFFLAGS, &ifr) < 0) eprintf("ioctl SIOCSIFFLAGS:");
248			i++;
249		} else if (strcmp(arg, "multicast") == 0) {
250			if (ioctl(sock, SIOCGIFFLAGS, &ifr) < 0) eprintf("ioctl SIOCGIFFLAGS:");
251			ifr.ifr_flags |= IFF_MULTICAST;
252			if (ioctl(sock, SIOCSIFFLAGS, &ifr) < 0) eprintf("ioctl SIOCSIFFLAGS:");
253			i++;
254		} else if (strcmp(arg, "-multicast") == 0) {
255			if (ioctl(sock, SIOCGIFFLAGS, &ifr) < 0) eprintf("ioctl SIOCGIFFLAGS:");
256			ifr.ifr_flags &= ~IFF_MULTICAST;
257			if (ioctl(sock, SIOCSIFFLAGS, &ifr) < 0) eprintf("ioctl SIOCSIFFLAGS:");
258			i++;
259		} else {
260			sin = (struct sockaddr_in *)&ifr.ifr_addr;
261			sin->sin_family = AF_INET;
262			slash = strchr(arg, '/');
263			prefix = -1;
264			if (slash) {
265				*slash = '\0';
266				prefix = atoi(slash + 1);
267			}
268			if (inet_pton(AF_INET, arg, &sin->sin_addr) <= 0) {
269				eprintf("unknown action or invalid address: %s\n", arg);
270			}
271			if (ioctl(sock, SIOCSIFADDR, &ifr) < 0) eprintf("ioctl SIOCSIFADDR:");
272
273			if (prefix >= 0) {
274				mask = 0;
275				if (prefix > 0)
276					mask = htonl(~0U << (32 - prefix));
277				sin = (struct sockaddr_in *)&ifr.ifr_netmask;
278				sin->sin_family = AF_INET;
279				sin->sin_addr.s_addr = mask;
280				if (ioctl(sock, SIOCSIFNETMASK, &ifr) < 0) eprintf("ioctl SIOCSIFNETMASK:");
281			}
282
283			if (ioctl(sock, SIOCGIFFLAGS, &ifr) < 0) eprintf("ioctl SIOCGIFFLAGS:");
284			ifr.ifr_flags |= IFF_UP | IFF_RUNNING;
285			if (ioctl(sock, SIOCSIFFLAGS, &ifr) < 0) eprintf("ioctl SIOCSIFFLAGS:");
286
287			i++;
288		}
289	}
290
291	free(ifaces);
292	close(sock);
293
294	if (fshut(stdin, "<stdin>") | fshut(stdout, "<stdout>"))
295		return 1;
296
297	return 0;
298}