1 /*- 2 * SPDX-License-Identifier: BSD-3-Clause 3 * 4 * Copyright (c) 1983, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. Neither the name of the University nor the names of its contributors 16 * may be used to endorse or promote products derived from this software 17 * without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 */ 31 32 #ifndef lint 33 static const char rcsid[] = 34 "$FreeBSD$"; 35 #endif /* not lint */ 36 37 #include <sys/param.h> 38 #include <sys/ioctl.h> 39 #include <sys/socket.h> 40 #include <net/if.h> 41 42 #include <ctype.h> 43 #include <err.h> 44 #include <stdio.h> 45 #include <stdlib.h> 46 #include <string.h> 47 #include <unistd.h> 48 #include <ifaddrs.h> 49 50 #include <netinet/in.h> 51 #include <netinet/in_var.h> 52 #include <arpa/inet.h> 53 #include <netdb.h> 54 55 #include "ifconfig.h" 56 57 static struct in_aliasreq in_addreq; 58 static struct ifreq in_ridreq; 59 static char addr_buf[NI_MAXHOST]; /*for getnameinfo()*/ 60 extern char *f_inet, *f_addr; 61 62 static void 63 print_addr(struct sockaddr_in *sin) 64 { 65 int error, n_flags; 66 67 if (f_addr != NULL && strcmp(f_addr, "fqdn") == 0) 68 n_flags = 0; 69 else if (f_addr != NULL && strcmp(f_addr, "host") == 0) 70 n_flags = NI_NOFQDN; 71 else 72 n_flags = NI_NUMERICHOST; 73 74 error = getnameinfo((struct sockaddr *)sin, sin->sin_len, addr_buf, 75 sizeof(addr_buf), NULL, 0, n_flags); 76 77 if (error) 78 inet_ntop(AF_INET, &sin->sin_addr, addr_buf, sizeof(addr_buf)); 79 80 printf("\tinet %s", addr_buf); 81 } 82 83 static void 84 in_status(int s __unused, const struct ifaddrs *ifa) 85 { 86 struct sockaddr_in *sin, null_sin = {}; 87 88 sin = (struct sockaddr_in *)ifa->ifa_addr; 89 if (sin == NULL) 90 return; 91 92 print_addr(sin); 93 94 if (ifa->ifa_flags & IFF_POINTOPOINT) { 95 sin = (struct sockaddr_in *)ifa->ifa_dstaddr; 96 if (sin == NULL) 97 sin = &null_sin; 98 printf(" --> %s", inet_ntoa(sin->sin_addr)); 99 } 100 101 sin = (struct sockaddr_in *)ifa->ifa_netmask; 102 if (sin == NULL) 103 sin = &null_sin; 104 if (f_inet != NULL && strcmp(f_inet, "cidr") == 0) { 105 int cidr = 32; 106 unsigned long smask; 107 108 smask = ntohl(sin->sin_addr.s_addr); 109 while ((smask & 1) == 0) { 110 smask = smask >> 1; 111 cidr--; 112 if (cidr == 0) 113 break; 114 } 115 printf("/%d", cidr); 116 } else if (f_inet != NULL && strcmp(f_inet, "dotted") == 0) 117 printf(" netmask %s", inet_ntoa(sin->sin_addr)); 118 else 119 printf(" netmask 0x%lx", (unsigned long)ntohl(sin->sin_addr.s_addr)); 120 121 if (ifa->ifa_flags & IFF_BROADCAST) { 122 sin = (struct sockaddr_in *)ifa->ifa_broadaddr; 123 if (sin != NULL && sin->sin_addr.s_addr != 0) 124 printf(" broadcast %s", inet_ntoa(sin->sin_addr)); 125 } 126 127 print_vhid(ifa, " "); 128 129 putchar('\n'); 130 } 131 132 #define SIN(x) ((struct sockaddr_in *) &(x)) 133 static struct sockaddr_in *sintab[] = { 134 SIN(in_ridreq.ifr_addr), SIN(in_addreq.ifra_addr), 135 SIN(in_addreq.ifra_mask), SIN(in_addreq.ifra_broadaddr) 136 }; 137 138 static void 139 in_getaddr(const char *s, int which) 140 { 141 struct sockaddr_in *sin = sintab[which]; 142 struct hostent *hp; 143 struct netent *np; 144 145 sin->sin_len = sizeof(*sin); 146 sin->sin_family = AF_INET; 147 148 if (which == ADDR) { 149 char *p = NULL; 150 151 if((p = strrchr(s, '/')) != NULL) { 152 const char *errstr; 153 /* address is `name/masklen' */ 154 int masklen; 155 struct sockaddr_in *min = sintab[MASK]; 156 *p = '\0'; 157 if (!isdigit(*(p + 1))) 158 errstr = "invalid"; 159 else 160 masklen = (int)strtonum(p + 1, 0, 32, &errstr); 161 if (errstr != NULL) { 162 *p = '/'; 163 errx(1, "%s: bad value (width %s)", s, errstr); 164 } 165 min->sin_family = AF_INET; 166 min->sin_len = sizeof(*min); 167 min->sin_addr.s_addr = htonl(~((1LL << (32 - masklen)) - 1) & 168 0xffffffff); 169 } 170 } 171 172 if (inet_aton(s, &sin->sin_addr)) 173 return; 174 if ((hp = gethostbyname(s)) != NULL) 175 bcopy(hp->h_addr, (char *)&sin->sin_addr, 176 MIN((size_t)hp->h_length, sizeof(sin->sin_addr))); 177 else if ((np = getnetbyname(s)) != NULL) 178 sin->sin_addr = inet_makeaddr(np->n_net, INADDR_ANY); 179 else 180 errx(1, "%s: bad value", s); 181 } 182 183 static void 184 in_postproc(int s, const struct afswtch *afp, int newaddr, int ifflags) 185 { 186 if (sintab[ADDR]->sin_len != 0 && sintab[MASK]->sin_len == 0 && 187 newaddr && (ifflags & (IFF_POINTOPOINT | IFF_LOOPBACK)) == 0) { 188 warnx("WARNING: setting interface address without mask " 189 "is deprecated,\ndefault mask may not be correct."); 190 } 191 } 192 193 static void 194 in_status_tunnel(int s) 195 { 196 char src[NI_MAXHOST]; 197 char dst[NI_MAXHOST]; 198 struct ifreq ifr; 199 const struct sockaddr *sa = (const struct sockaddr *) &ifr.ifr_addr; 200 201 memset(&ifr, 0, sizeof(ifr)); 202 strlcpy(ifr.ifr_name, name, IFNAMSIZ); 203 204 if (ioctl(s, SIOCGIFPSRCADDR, (caddr_t)&ifr) < 0) 205 return; 206 if (sa->sa_family != AF_INET) 207 return; 208 if (getnameinfo(sa, sa->sa_len, src, sizeof(src), 0, 0, NI_NUMERICHOST) != 0) 209 src[0] = '\0'; 210 211 if (ioctl(s, SIOCGIFPDSTADDR, (caddr_t)&ifr) < 0) 212 return; 213 if (sa->sa_family != AF_INET) 214 return; 215 if (getnameinfo(sa, sa->sa_len, dst, sizeof(dst), 0, 0, NI_NUMERICHOST) != 0) 216 dst[0] = '\0'; 217 218 printf("\ttunnel inet %s --> %s\n", src, dst); 219 } 220 221 static void 222 in_set_tunnel(int s, struct addrinfo *srcres, struct addrinfo *dstres) 223 { 224 struct in_aliasreq addreq; 225 226 memset(&addreq, 0, sizeof(addreq)); 227 strlcpy(addreq.ifra_name, name, IFNAMSIZ); 228 memcpy(&addreq.ifra_addr, srcres->ai_addr, srcres->ai_addr->sa_len); 229 memcpy(&addreq.ifra_dstaddr, dstres->ai_addr, dstres->ai_addr->sa_len); 230 231 if (ioctl(s, SIOCSIFPHYADDR, &addreq) < 0) 232 warn("SIOCSIFPHYADDR"); 233 } 234 235 static struct afswtch af_inet = { 236 .af_name = "inet", 237 .af_af = AF_INET, 238 .af_status = in_status, 239 .af_getaddr = in_getaddr, 240 .af_postproc = in_postproc, 241 .af_status_tunnel = in_status_tunnel, 242 .af_settunnel = in_set_tunnel, 243 .af_difaddr = SIOCDIFADDR, 244 .af_aifaddr = SIOCAIFADDR, 245 .af_ridreq = &in_ridreq, 246 .af_addreq = &in_addreq, 247 }; 248 249 static __constructor void 250 inet_ctor(void) 251 { 252 253 #ifndef RESCUE 254 if (!feature_present("inet")) 255 return; 256 #endif 257 af_register(&af_inet); 258 } 259