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