Index: sbin/ifconfig/af_inet.c =================================================================== --- sbin/ifconfig/af_inet.c +++ sbin/ifconfig/af_inet.c @@ -54,11 +54,14 @@ static struct in_aliasreq in_addreq; static struct ifreq in_ridreq; +static char addr_buf[MAXHOSTNAMELEN *2 + 1]; /*for getnameinfo()*/ +extern char *f_inet, *f_addr; static void in_status(int s __unused, const struct ifaddrs *ifa) { struct sockaddr_in *sin, null_sin; + int error, n_flags; memset(&null_sin, 0, sizeof(null_sin)); @@ -66,19 +69,47 @@ if (sin == NULL) return; - printf("\tinet %s ", inet_ntoa(sin->sin_addr)); + if (f_addr != NULL && strcmp(f_addr, "fqdn") == 0) + n_flags = 0; + else if (f_addr != NULL && strcmp(f_addr, "host") == 0) + n_flags = NI_NOFQDN; + else + n_flags = NI_NUMERICHOST; + + error = getnameinfo((struct sockaddr *)sin, sin->sin_len, addr_buf, + sizeof(addr_buf), NULL, 0, n_flags); + + if (error) + inet_ntop(AF_INET, &sin->sin_addr, addr_buf, sizeof(addr_buf)); + + printf("\tinet %s", addr_buf); if (ifa->ifa_flags & IFF_POINTOPOINT) { sin = (struct sockaddr_in *)ifa->ifa_dstaddr; if (sin == NULL) sin = &null_sin; - printf("--> %s ", inet_ntoa(sin->sin_addr)); + printf(" --> %s ", inet_ntoa(sin->sin_addr)); } sin = (struct sockaddr_in *)ifa->ifa_netmask; if (sin == NULL) sin = &null_sin; - printf("netmask 0x%lx ", (unsigned long)ntohl(sin->sin_addr.s_addr)); + if (f_inet != NULL && strcmp(f_inet, "cidr") == 0) { + int cidr = 32; + unsigned long smask; + + smask = ntohl(sin->sin_addr.s_addr); + while ((smask & 1) == 0) { + smask = smask >> 1; + cidr--; + if (cidr == 0) + break; + } + printf("/%d ", cidr); + } else if (f_inet != NULL && strcmp(f_inet, "dotted") == 0) + printf(" netmask %s ", inet_ntoa(sin->sin_addr)); + else + printf(" netmask 0x%lx ", (unsigned long)ntohl(sin->sin_addr.s_addr)); if (ifa->ifa_flags & IFF_BROADCAST) { sin = (struct sockaddr_in *)ifa->ifa_broadaddr; Index: sbin/ifconfig/af_inet6.c =================================================================== --- sbin/ifconfig/af_inet6.c +++ sbin/ifconfig/af_inet6.c @@ -65,6 +65,7 @@ static int prefix(void *, int); static char *sec2str(time_t); static int explicit_prefix = 0; +extern char *f_inet6, *f_addr, *f_scope; extern void setnd6flags(const char *, int, int, const struct afswtch *); extern void setnd6defif(const char *, int, int, const struct afswtch *); @@ -172,9 +173,10 @@ struct in6_ifreq ifr6; int s6; u_int32_t flags6; + const u_int16_t *a; struct in6_addrlifetime lifetime; struct timespec now; - int error; + int error, n_flags, i; clock_gettime(CLOCK_MONOTONIC_FAST, &now); @@ -206,12 +208,30 @@ lifetime = ifr6.ifr_ifru.ifru_lifetime; close(s6); - error = getnameinfo((struct sockaddr *)sin, sin->sin6_len, addr_buf, - sizeof(addr_buf), NULL, 0, NI_NUMERICHOST); - if (error != 0) - inet_ntop(AF_INET6, &sin->sin6_addr, addr_buf, - sizeof(addr_buf)); - printf("\tinet6 %s ", addr_buf); + if (f_addr != NULL && strcmp(f_addr, "full") == 0) { + a = (const u_int16_t *)&sin->sin6_addr; + printf("\tinet6 "); + for (i = 0; i < 8; i++) { + printf("%04hx", ntohs(*(a + i))); + if (i < 7) + printf(":"); + } + } else { + if (f_addr != NULL && strcmp(f_addr, "fqdn") == 0) + n_flags = 0; + else if (f_addr != NULL && strcmp(f_addr, "host") == 0) + n_flags = NI_NOFQDN; + else + n_flags = NI_NUMERICHOST; + error = getnameinfo((struct sockaddr *)sin, sin->sin6_len, + addr_buf, sizeof(addr_buf), NULL, 0, + n_flags); + if (error != 0 || + (f_scope != NULL && strcmp(f_scope, "none") == 0)) + inet_ntop(AF_INET6, &sin->sin6_addr, addr_buf, + sizeof(addr_buf)); + printf("\tinet6 %s", addr_buf); + } if (ifa->ifa_flags & IFF_POINTOPOINT) { sin = (struct sockaddr_in6 *)ifa->ifa_dstaddr; @@ -229,15 +249,19 @@ if (error != 0) inet_ntop(AF_INET6, &sin->sin6_addr, addr_buf, sizeof(addr_buf)); - printf("--> %s ", addr_buf); + printf(" --> %s ", addr_buf); } } sin = (struct sockaddr_in6 *)ifa->ifa_netmask; if (sin == NULL) sin = &null_sin; - printf("prefixlen %d ", prefix(&sin->sin6_addr, - sizeof(struct in6_addr))); + if (f_inet6 != NULL && strcmp(f_inet6, "cidr") == 0) + printf("/%d ", prefix(&sin->sin6_addr, + sizeof(struct in6_addr))); + else + printf(" prefixlen %d ", prefix(&sin->sin6_addr, + sizeof(struct in6_addr))); if ((flags6 & IN6_IFF_ANYCAST) != 0) printf("anycast "); @@ -256,7 +280,8 @@ if ((flags6 & IN6_IFF_PREFER_SOURCE) != 0) printf("prefer_source "); - if (((struct sockaddr_in6 *)(ifa->ifa_addr))->sin6_scope_id) + if ((f_scope == NULL || strcmp(f_scope, "none") != 0) && + ((struct sockaddr_in6 *)(ifa->ifa_addr))->sin6_scope_id) printf("scopeid 0x%x ", ((struct sockaddr_in6 *)(ifa->ifa_addr))->sin6_scope_id); Index: sbin/ifconfig/af_link.c =================================================================== --- sbin/ifconfig/af_link.c +++ sbin/ifconfig/af_link.c @@ -51,19 +51,31 @@ static struct ifreq link_ridreq; +extern char *f_ether; + static void link_status(int s __unused, const struct ifaddrs *ifa) { /* XXX no const 'cuz LLADDR is defined wrong */ struct sockaddr_dl *sdl = (struct sockaddr_dl *) ifa->ifa_addr; + char *ether_format; + int i; if (sdl != NULL && sdl->sdl_alen > 0) { if ((sdl->sdl_type == IFT_ETHER || sdl->sdl_type == IFT_L2VLAN || sdl->sdl_type == IFT_BRIDGE) && sdl->sdl_alen == ETHER_ADDR_LEN) - printf("\tether %s\n", - ether_ntoa((struct ether_addr *)LLADDR(sdl))); + if (f_ether != NULL && strcmp(f_ether, "dash") == 0) { + ether_format = ether_ntoa((struct ether_addr *)LLADDR(sdl)); + for (i = 0; i < strlen(ether_format); i++) { + if (ether_format[i] == ':') + ether_format[i] = '-'; + } + printf("\tether %s\n", ether_format); + } else + printf("\tether %s\n", + ether_ntoa((struct ether_addr *)LLADDR(sdl))); else { int n = sdl->sdl_nlen > 0 ? sdl->sdl_nlen + 1 : 0; Index: sbin/ifconfig/ifconfig.8 =================================================================== --- sbin/ifconfig/ifconfig.8 +++ sbin/ifconfig/ifconfig.8 @@ -28,7 +28,7 @@ .\" From: @(#)ifconfig.8 8.3 (Berkeley) 1/5/94 .\" $FreeBSD$ .\" -.Dd November 6, 2015 +.Dd May 29, 2016 .Dt IFCONFIG 8 .Os .Sh NAME @@ -36,6 +36,7 @@ .Nd configure network interface parameters .Sh SYNOPSIS .Nm +.Op Fl f Ar type:format Ns Op Ar ,type:format .Op Fl L .Op Fl k .Op Fl m @@ -194,6 +195,102 @@ List the interfaces in the given group. .El .Pp +The output format of +.Nm +can be controlled using the +.Fl f +flag or the +.Ev IFCONFIG_FORMAT +environment variable. +The format is specified as a comma separated list of +.Sy type:format +pairs. +See the +.Sx EXAMPLES +section for more information. +The +.Sy types +and their associated +.Sy format +strings are: +.Bl -tag -width scope +.It Sy addr +Adjust the display of inet and inet6 addresses +.Bl -tag -width default +.It Sy default +Display inet and inet6 addresses in the default format, +.Sy numeric +.It Sy fqdn +Display inet and inet6 addresses as fully qualified domain names +.Pq FQDN +.It Sy full +Display inet6 addresses without suppressing zeroes. +Only applicable to inet6 +.It Sy host +Display inet and inet6 addresses as unqualified hostnames +.It Sy numeric +Display inet and inet6 addresses in numeric format +.El +.It Sy ether +Adjust the display of link-level ethernet (MAC) addresses +.Bl -tag -width default +.It Sy colon +Separate address segments with a colon +.It Sy dash +Separate address segments with a dash +.It Sy default +Display ethernet addresses in the default format, +.Sy colon +.El +.It Sy inet +Adjust the display of inet address subnet masks: +.Bl -tag -width default +.It Sy cidr +Display subnet masks in CIDR notation, for example: +.br +10.0.0.0/8 or 203.0.113.224/26 +.It Sy default +Display subnet masks in the default format, +.Sy hex +.It Sy dotted +Display subnet masks in dotted quad notation, for example: +.br +255.255.0.0 or 255.255.255.192 +.It Sy hex +Display subnet masks in hexidecimal, for example: +.br +0xffff0000 or 0xffffffc0 +.El +.It Sy inet6 +Adjust the display of inet6 address prefixes (subnet masks): +.Bl -tag -width default +.It Sy cidr +Display subnet prefix in CIDR notation, for example: +.br +::1/128 or fe80::1%lo0/64 +.It Sy default +Display subnet prefix in the default format +.Sy numeric +.It Sy numeric +Display subnet prefix in integer format, for example: +.br +prefixlen 64 +.El +.It Sy scope +Controls the display of the interface scope as part of the address. +Only applicable to inet6 addresses. +.Bl -tag -width default +.It Sy default +The interface scope and scopeid are included in the address, for example: +.br +inet6 fe80::1%lo0 prefixlen 64 scopeid 0x7 +.It Sy none +The interface scope and scopeid are not displayed, for example: +.br +inet6 fe80::1 prefixlen 64 +.El +.El +.Pp The following parameters may be set with .Nm : .Bl -tag -width indent @@ -2843,6 +2940,9 @@ Display available wireless networks using .Li wlan0 : .Dl # ifconfig wlan0 list scan +.Pp +Display inet and inet6 address subnet masks in CIDR notation +.Dl # ifconfig -f inet:cidr,inet6:cidr .Sh DIAGNOSTICS Messages indicating the specified interface does not exist, the requested address is unknown, or the user is not privileged and Index: sbin/ifconfig/ifconfig.c =================================================================== --- sbin/ifconfig/ifconfig.c +++ sbin/ifconfig/ifconfig.c @@ -98,6 +98,9 @@ int supmedia = 0; int printkeys = 0; /* Print keying material for interfaces. */ +/* Formatter Strings */ +char *f_inet, *f_inet6, *f_ether, *f_addr, *f_scope; + static int ifconfig(int argc, char *const *argv, int iscreate, const struct afswtch *afp); static void status(const struct afswtch *afp, const struct sockaddr_dl *sdl, @@ -143,8 +146,8 @@ } fprintf(stderr, - "usage: ifconfig %sinterface address_family [address [dest_address]]\n" - " [parameters]\n" + "usage: ifconfig [-f type:format] %sinterface address_family\n" + " [address [dest_address]] [parameters]\n" " ifconfig interface create\n" " ifconfig -a %s[-d] [-m] [-u] [-v] [address_family]\n" " ifconfig -l [-d] [-u] [address_family]\n" @@ -243,6 +246,52 @@ return (0); } +static void freeformat(void) +{ + + if (f_inet != NULL) + free(f_inet); + if (f_inet6 != NULL) + free(f_inet6); + if (f_ether != NULL) + free(f_ether); + if (f_addr != NULL) + free(f_addr); + if (f_scope != NULL) + free(f_scope); +} + +static void setformat(char *input) +{ + char *formatstr, *category, *modifier; + + formatstr = strdup(input); + while ((category = strsep(&formatstr, ",")) != NULL) { + modifier = strchr(category, ':'); + if (modifier == NULL || modifier[1] == '\0') { + warnx("Skipping invalid format specification: %s\n", + category); + continue; + } + + /* Split the string on the separator, then seek past it */ + modifier[0] = '\0'; + modifier++; + + if (strcmp(category, "addr") == 0) + f_addr = strdup(modifier); + else if (strcmp(category, "ether") == 0) + f_ether = strdup(modifier); + else if (strcmp(category, "inet") == 0) + f_inet = strdup(modifier); + else if (strcmp(category, "inet6") == 0) + f_inet6 = strdup(modifier); + else if (strcmp(category, "scope") == 0) + f_scope = strdup(modifier); + } + free(formatstr); +} + #undef ORDERS_SIZE static struct ifaddrs * @@ -315,7 +364,7 @@ struct ifaddrs *ifap, *sifap, *ifa; struct ifreq paifr; const struct sockaddr_dl *sdl; - char options[1024], *cp, *namecp = NULL; + char options[1024], *cp, *envformat, *namecp = NULL; struct ifa_queue q = TAILQ_HEAD_INITIALIZER(q); struct ifa_order_elt *cur, *tmp; const char *ifname; @@ -323,7 +372,12 @@ size_t iflen; all = downonly = uponly = namesonly = noload = verbose = 0; - + f_inet = f_inet6 = f_ether = f_addr = f_scope = NULL; + + envformat = getenv("IFCONFIG_FORMAT"); + if (envformat != NULL) + setformat(envformat); + /* * Ensure we print interface name when expected to, * even if we terminate early due to error. @@ -331,7 +385,7 @@ atexit(printifnamemaybe); /* Parse leading line options */ - strlcpy(options, "adklmnuv", sizeof(options)); + strlcpy(options, "f:adklmnuv", sizeof(options)); for (p = opts; p != NULL; p = p->next) strlcat(options, p->opt, sizeof(options)); while ((c = getopt(argc, argv, options)) != -1) { @@ -342,6 +396,11 @@ case 'd': /* restrict scan to "down" interfaces */ downonly++; break; + case 'f': + if (optarg == NULL) + usage(); + setformat(optarg); + break; case 'k': printkeys++; break; @@ -539,6 +598,7 @@ printf("\n"); freeifaddrs(ifap); + freeformat(); exit(0); }