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 #include "ifconfig_netlink.h" 57 58 static struct in_aliasreq in_addreq; 59 static struct ifreq in_ridreq; 60 static char addr_buf[NI_MAXHOST]; /*for getnameinfo()*/ 61 extern char *f_inet, *f_addr; 62 63 static void 64 print_addr(struct sockaddr_in *sin) 65 { 66 int error, n_flags; 67 68 if (f_addr != NULL && strcmp(f_addr, "fqdn") == 0) 69 n_flags = 0; 70 else if (f_addr != NULL && strcmp(f_addr, "host") == 0) 71 n_flags = NI_NOFQDN; 72 else 73 n_flags = NI_NUMERICHOST; 74 75 error = getnameinfo((struct sockaddr *)sin, sin->sin_len, addr_buf, 76 sizeof(addr_buf), NULL, 0, n_flags); 77 78 if (error) 79 inet_ntop(AF_INET, &sin->sin_addr, addr_buf, sizeof(addr_buf)); 80 81 printf("\tinet %s", addr_buf); 82 } 83 84 #ifdef WITHOUT_NETLINK 85 static void 86 in_status(int s __unused, const struct ifaddrs *ifa) 87 { 88 struct sockaddr_in *sin, null_sin = {}; 89 90 sin = (struct sockaddr_in *)ifa->ifa_addr; 91 if (sin == NULL) 92 return; 93 94 print_addr(sin); 95 96 if (ifa->ifa_flags & IFF_POINTOPOINT) { 97 sin = (struct sockaddr_in *)ifa->ifa_dstaddr; 98 if (sin == NULL) 99 sin = &null_sin; 100 printf(" --> %s", inet_ntoa(sin->sin_addr)); 101 } 102 103 sin = (struct sockaddr_in *)ifa->ifa_netmask; 104 if (sin == NULL) 105 sin = &null_sin; 106 if (f_inet != NULL && strcmp(f_inet, "cidr") == 0) { 107 int cidr = 32; 108 unsigned long smask; 109 110 smask = ntohl(sin->sin_addr.s_addr); 111 while ((smask & 1) == 0) { 112 smask = smask >> 1; 113 cidr--; 114 if (cidr == 0) 115 break; 116 } 117 printf("/%d", cidr); 118 } else if (f_inet != NULL && strcmp(f_inet, "dotted") == 0) 119 printf(" netmask %s", inet_ntoa(sin->sin_addr)); 120 else 121 printf(" netmask 0x%lx", (unsigned long)ntohl(sin->sin_addr.s_addr)); 122 123 if (ifa->ifa_flags & IFF_BROADCAST) { 124 sin = (struct sockaddr_in *)ifa->ifa_broadaddr; 125 if (sin != NULL && sin->sin_addr.s_addr != 0) 126 printf(" broadcast %s", inet_ntoa(sin->sin_addr)); 127 } 128 129 print_vhid(ifa, " "); 130 131 putchar('\n'); 132 } 133 134 #else 135 static struct in_addr 136 get_mask(int plen) 137 { 138 struct in_addr a; 139 140 a.s_addr = htonl(plen ? ~((1 << (32 - plen)) - 1) : 0); 141 142 return (a); 143 } 144 145 static struct sockaddr_in * 146 satosin(struct sockaddr *sa) 147 { 148 return ((struct sockaddr_in *)(void *)sa); 149 } 150 151 static void 152 in_status_nl(struct ifconfig_args *args __unused, struct io_handler *h, 153 if_link_t *link, if_addr_t *ifa) 154 { 155 struct sockaddr_in *sin = satosin(ifa->ifa_local); 156 int plen = ifa->ifa_prefixlen; 157 158 print_addr(sin); 159 160 if (link->ifi_flags & IFF_POINTOPOINT) { 161 struct sockaddr_in *dst = satosin(ifa->ifa_address); 162 163 printf(" --> %s", inet_ntoa(dst->sin_addr)); 164 } 165 if (f_inet != NULL && strcmp(f_inet, "cidr") == 0) { 166 printf("/%d", plen); 167 } else if (f_inet != NULL && strcmp(f_inet, "dotted") == 0) 168 printf(" netmask %s", inet_ntoa(get_mask(plen))); 169 else 170 printf(" netmask 0x%lx", (unsigned long)ntohl(get_mask(plen).s_addr)); 171 172 if ((link->ifi_flags & IFF_BROADCAST) && plen != 0) { 173 struct sockaddr_in *brd = satosin(ifa->ifa_broadcast); 174 if (brd != NULL) 175 printf(" broadcast %s", inet_ntoa(brd->sin_addr)); 176 } 177 178 if (ifa->ifaf_vhid != 0) 179 printf(" vhid %d", ifa->ifaf_vhid); 180 181 putchar('\n'); 182 } 183 #endif 184 185 #define SIN(x) ((struct sockaddr_in *) &(x)) 186 static struct sockaddr_in *sintab[] = { 187 SIN(in_ridreq.ifr_addr), SIN(in_addreq.ifra_addr), 188 SIN(in_addreq.ifra_mask), SIN(in_addreq.ifra_broadaddr) 189 }; 190 191 static void 192 in_getaddr(const char *s, int which) 193 { 194 struct sockaddr_in *sin = sintab[which]; 195 struct hostent *hp; 196 struct netent *np; 197 198 sin->sin_len = sizeof(*sin); 199 sin->sin_family = AF_INET; 200 201 if (which == ADDR) { 202 char *p = NULL; 203 204 if((p = strrchr(s, '/')) != NULL) { 205 const char *errstr; 206 /* address is `name/masklen' */ 207 int masklen; 208 struct sockaddr_in *min = sintab[MASK]; 209 *p = '\0'; 210 if (!isdigit(*(p + 1))) 211 errstr = "invalid"; 212 else 213 masklen = (int)strtonum(p + 1, 0, 32, &errstr); 214 if (errstr != NULL) { 215 *p = '/'; 216 errx(1, "%s: bad value (width %s)", s, errstr); 217 } 218 min->sin_family = AF_INET; 219 min->sin_len = sizeof(*min); 220 min->sin_addr.s_addr = htonl(~((1LL << (32 - masklen)) - 1) & 221 0xffffffff); 222 } 223 } 224 225 if (inet_aton(s, &sin->sin_addr)) 226 return; 227 if ((hp = gethostbyname(s)) != NULL) 228 bcopy(hp->h_addr, (char *)&sin->sin_addr, 229 MIN((size_t)hp->h_length, sizeof(sin->sin_addr))); 230 else if ((np = getnetbyname(s)) != NULL) 231 sin->sin_addr = inet_makeaddr(np->n_net, INADDR_ANY); 232 else 233 errx(1, "%s: bad value", s); 234 } 235 236 static void 237 in_postproc(int s, const struct afswtch *afp, int newaddr, int ifflags) 238 { 239 if (sintab[ADDR]->sin_len != 0 && sintab[MASK]->sin_len == 0 && 240 newaddr && (ifflags & (IFF_POINTOPOINT | IFF_LOOPBACK)) == 0) { 241 warnx("WARNING: setting interface address without mask " 242 "is deprecated,\ndefault mask may not be correct."); 243 } 244 } 245 246 static void 247 in_status_tunnel(int s) 248 { 249 char src[NI_MAXHOST]; 250 char dst[NI_MAXHOST]; 251 struct ifreq ifr; 252 const struct sockaddr *sa = (const struct sockaddr *) &ifr.ifr_addr; 253 254 memset(&ifr, 0, sizeof(ifr)); 255 strlcpy(ifr.ifr_name, name, IFNAMSIZ); 256 257 if (ioctl(s, SIOCGIFPSRCADDR, (caddr_t)&ifr) < 0) 258 return; 259 if (sa->sa_family != AF_INET) 260 return; 261 if (getnameinfo(sa, sa->sa_len, src, sizeof(src), 0, 0, NI_NUMERICHOST) != 0) 262 src[0] = '\0'; 263 264 if (ioctl(s, SIOCGIFPDSTADDR, (caddr_t)&ifr) < 0) 265 return; 266 if (sa->sa_family != AF_INET) 267 return; 268 if (getnameinfo(sa, sa->sa_len, dst, sizeof(dst), 0, 0, NI_NUMERICHOST) != 0) 269 dst[0] = '\0'; 270 271 printf("\ttunnel inet %s --> %s\n", src, dst); 272 } 273 274 static void 275 in_set_tunnel(int s, struct addrinfo *srcres, struct addrinfo *dstres) 276 { 277 struct in_aliasreq addreq; 278 279 memset(&addreq, 0, sizeof(addreq)); 280 strlcpy(addreq.ifra_name, name, IFNAMSIZ); 281 memcpy(&addreq.ifra_addr, srcres->ai_addr, srcres->ai_addr->sa_len); 282 memcpy(&addreq.ifra_dstaddr, dstres->ai_addr, dstres->ai_addr->sa_len); 283 284 if (ioctl(s, SIOCSIFPHYADDR, &addreq) < 0) 285 warn("SIOCSIFPHYADDR"); 286 } 287 288 static void 289 in_set_vhid(int vhid) 290 { 291 in_addreq.ifra_vhid = vhid; 292 } 293 294 295 static struct afswtch af_inet = { 296 .af_name = "inet", 297 .af_af = AF_INET, 298 #ifdef WITHOUT_NETLINK 299 .af_status = in_status, 300 #else 301 .af_status_nl = in_status_nl, 302 #endif 303 .af_getaddr = in_getaddr, 304 .af_postproc = in_postproc, 305 .af_status_tunnel = in_status_tunnel, 306 .af_settunnel = in_set_tunnel, 307 .af_setvhid = in_set_vhid, 308 .af_difaddr = SIOCDIFADDR, 309 .af_aifaddr = SIOCAIFADDR, 310 .af_ridreq = &in_ridreq, 311 .af_addreq = &in_addreq, 312 }; 313 314 static __constructor void 315 inet_ctor(void) 316 { 317 318 #ifndef RESCUE 319 if (!feature_present("inet")) 320 return; 321 #endif 322 af_register(&af_inet); 323 } 324