1/* 2 * Interface looking up by ioctl (). 3 * Copyright (C) 1997, 98 Kunihiro Ishiguro 4 * 5 * This file is part of GNU Zebra. 6 * 7 * GNU Zebra is free software; you can redistribute it and/or modify it 8 * under the terms of the GNU General Public License as published by the 9 * Free Software Foundation; either version 2, or (at your option) any 10 * later version. 11 * 12 * GNU Zebra is distributed in the hope that it will be useful, but 13 * WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 * General Public License for more details. 16 * 17 * You should have received a copy of the GNU General Public License 18 * along with GNU Zebra; see the file COPYING. If not, write to the Free 19 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 20 * 02111-1307, USA. 21 */ 22 23#include <zebra.h> 24 25#include "if.h" 26#include "sockunion.h" 27#include "prefix.h" 28#include "ioctl.h" 29#include "connected.h" 30#include "memory.h" 31#include "log.h" 32 33#include "zebra/interface.h" 34 35/* Interface looking up using infamous SIOCGIFCONF. */ 36static int 37interface_list_ioctl (void) 38{ 39 int ret; 40 int sock; 41#define IFNUM_BASE 32 42 int ifnum; 43 struct ifreq *ifreq; 44 struct ifconf ifconf; 45 struct interface *ifp; 46 int n; 47 int lastlen; 48 49 /* Normally SIOCGIFCONF works with AF_INET socket. */ 50 sock = socket (AF_INET, SOCK_DGRAM, 0); 51 if (sock < 0) 52 { 53 zlog_warn ("Can't make AF_INET socket stream: %s", safe_strerror (errno)); 54 return -1; 55 } 56 57 /* Set initial ifreq count. This will be double when SIOCGIFCONF 58 fail. Solaris has SIOCGIFNUM. */ 59#ifdef SIOCGIFNUM 60 ret = ioctl (sock, SIOCGIFNUM, &ifnum); 61 if (ret < 0) 62 ifnum = IFNUM_BASE; 63 else 64 ifnum++; 65#else 66 ifnum = IFNUM_BASE; 67#endif /* SIOCGIFNUM */ 68 69 ifconf.ifc_buf = NULL; 70 71 lastlen = 0; 72 /* Loop until SIOCGIFCONF success. */ 73 for (;;) 74 { 75 ifconf.ifc_len = sizeof (struct ifreq) * ifnum; 76 ifconf.ifc_buf = XREALLOC(MTYPE_TMP, ifconf.ifc_buf, ifconf.ifc_len); 77 78 ret = ioctl(sock, SIOCGIFCONF, &ifconf); 79 80 if (ret < 0) 81 { 82 zlog_warn ("SIOCGIFCONF: %s", safe_strerror(errno)); 83 goto end; 84 } 85 /* Repeatedly get info til buffer fails to grow. */ 86 if (ifconf.ifc_len > lastlen) 87 { 88 lastlen = ifconf.ifc_len; 89 ifnum += 10; 90 continue; 91 } 92 /* Success. */ 93 break; 94 } 95 96 /* Allocate interface. */ 97 ifreq = ifconf.ifc_req; 98 99#ifdef OPEN_BSD 100 for (n = 0; n < ifconf.ifc_len; ) 101 { 102 int size; 103 104 ifreq = (struct ifreq *)((caddr_t) ifconf.ifc_req + n); 105 ifp = if_get_by_name_len(ifreq->ifr_name, 106 strnlen(ifreq->ifr_name, 107 sizeof(ifreq->ifr_name))); 108 if_add_update (ifp); 109 size = ifreq->ifr_addr.sa_len; 110 if (size < sizeof (ifreq->ifr_addr)) 111 size = sizeof (ifreq->ifr_addr); 112 size += sizeof (ifreq->ifr_name); 113 n += size; 114 } 115#else 116 for (n = 0; n < ifconf.ifc_len; n += sizeof(struct ifreq)) 117 { 118 ifp = if_get_by_name_len(ifreq->ifr_name, 119 strnlen(ifreq->ifr_name, 120 sizeof(ifreq->ifr_name))); 121 if_add_update (ifp); 122 ifreq++; 123 } 124#endif /* OPEN_BSD */ 125 126 end: 127 close (sock); 128 XFREE (MTYPE_TMP, ifconf.ifc_buf); 129 130 return ret; 131} 132 133/* Get interface's index by ioctl. */ 134static int 135if_get_index (struct interface *ifp) 136{ 137#if defined(HAVE_IF_NAMETOINDEX) 138 /* Modern systems should have if_nametoindex(3). */ 139 ifp->ifindex = if_nametoindex(ifp->name); 140#elif defined(SIOCGIFINDEX) && !defined(HAVE_BROKEN_ALIASES) 141 /* Fall-back for older linuxes. */ 142 int ret; 143 struct ifreq ifreq; 144 static int if_fake_index; 145 146 ifreq_set_name (&ifreq, ifp); 147 148 ret = if_ioctl (SIOCGIFINDEX, (caddr_t) &ifreq); 149 if (ret < 0) 150 { 151 /* Linux 2.0.X does not have interface index. */ 152 ifp->ifindex = if_fake_index++; 153 return ifp->ifindex; 154 } 155 156 /* OK we got interface index. */ 157#ifdef ifr_ifindex 158 ifp->ifindex = ifreq.ifr_ifindex; 159#else 160 ifp->ifindex = ifreq.ifr_index; 161#endif 162 163#else 164/* Linux 2.2.X does not provide individual interface index 165 for aliases and we know it. For others issue a warning. */ 166#if !defined(HAVE_BROKEN_ALIASES) 167#warning "Using if_fake_index. You may want to add appropriate" 168#warning "mapping from ifname to ifindex for your system..." 169#endif 170 /* This branch probably won't provide usable results, but anyway... */ 171 static int if_fake_index = 1; 172 ifp->ifindex = if_fake_index++; 173#endif 174 175 return ifp->ifindex; 176} 177 178#ifdef SIOCGIFHWADDR 179static int 180if_get_hwaddr (struct interface *ifp) 181{ 182 int ret; 183 struct ifreq ifreq; 184 int i; 185 186 strncpy (ifreq.ifr_name, ifp->name, IFNAMSIZ); 187 ifreq.ifr_addr.sa_family = AF_INET; 188 189 /* Fetch Hardware address if available. */ 190 ret = if_ioctl (SIOCGIFHWADDR, (caddr_t) &ifreq); 191 if (ret < 0) 192 ifp->hw_addr_len = 0; 193 else 194 { 195 memcpy (ifp->hw_addr, ifreq.ifr_hwaddr.sa_data, 6); 196 197 for (i = 0; i < 6; i++) 198 if (ifp->hw_addr[i] != 0) 199 break; 200 201 if (i == 6) 202 ifp->hw_addr_len = 0; 203 else 204 ifp->hw_addr_len = 6; 205 } 206 return 0; 207} 208#endif /* SIOCGIFHWADDR */ 209 210#ifdef HAVE_GETIFADDRS 211#include <ifaddrs.h> 212 213static int 214if_getaddrs (void) 215{ 216 int ret; 217 struct ifaddrs *ifap; 218 struct ifaddrs *ifapfree; 219 struct interface *ifp; 220 int prefixlen; 221 222 ret = getifaddrs (&ifap); 223 if (ret != 0) 224 { 225 zlog_err ("getifaddrs(): %s", safe_strerror (errno)); 226 return -1; 227 } 228 229 for (ifapfree = ifap; ifap; ifap = ifap->ifa_next) 230 { 231 if (ifap->ifa_addr == NULL) 232 { 233 zlog_err ("%s: nonsensical ifaddr with NULL ifa_addr, ifname %s", 234 __func__, (ifap->ifa_name ? ifap->ifa_name : "(null)")); 235 continue; 236 } 237 238 ifp = if_lookup_by_name (ifap->ifa_name); 239 if (ifp == NULL) 240 { 241 zlog_err ("if_getaddrs(): Can't lookup interface %s\n", 242 ifap->ifa_name); 243 continue; 244 } 245 246 if (ifap->ifa_addr->sa_family == AF_INET) 247 { 248 struct sockaddr_in *addr; 249 struct sockaddr_in *mask; 250 struct sockaddr_in *dest; 251 struct in_addr *dest_pnt; 252 int flags = 0; 253 254 addr = (struct sockaddr_in *) ifap->ifa_addr; 255 mask = (struct sockaddr_in *) ifap->ifa_netmask; 256 prefixlen = ip_masklen (mask->sin_addr); 257 258 dest_pnt = NULL; 259 260 if (ifap->ifa_dstaddr && 261 !IPV4_ADDR_SAME(&addr->sin_addr, 262 &((struct sockaddr_in *) 263 ifap->ifa_dstaddr)->sin_addr)) 264 { 265 dest = (struct sockaddr_in *) ifap->ifa_dstaddr; 266 dest_pnt = &dest->sin_addr; 267 flags = ZEBRA_IFA_PEER; 268 } 269 else if (ifap->ifa_broadaddr && 270 !IPV4_ADDR_SAME(&addr->sin_addr, 271 &((struct sockaddr_in *) 272 ifap->ifa_broadaddr)->sin_addr)) 273 { 274 dest = (struct sockaddr_in *) ifap->ifa_broadaddr; 275 dest_pnt = &dest->sin_addr; 276 } 277 278 connected_add_ipv4 (ifp, flags, &addr->sin_addr, 279 prefixlen, dest_pnt, NULL); 280 } 281#ifdef HAVE_IPV6 282 if (ifap->ifa_addr->sa_family == AF_INET6) 283 { 284 struct sockaddr_in6 *addr; 285 struct sockaddr_in6 *mask; 286 struct sockaddr_in6 *dest; 287 struct in6_addr *dest_pnt; 288 int flags = 0; 289 290 addr = (struct sockaddr_in6 *) ifap->ifa_addr; 291 mask = (struct sockaddr_in6 *) ifap->ifa_netmask; 292 prefixlen = ip6_masklen (mask->sin6_addr); 293 294 dest_pnt = NULL; 295 296 if (ifap->ifa_dstaddr && 297 !IPV6_ADDR_SAME(&addr->sin6_addr, 298 &((struct sockaddr_in6 *) 299 ifap->ifa_dstaddr)->sin6_addr)) 300 { 301 dest = (struct sockaddr_in6 *) ifap->ifa_dstaddr; 302 dest_pnt = &dest->sin6_addr; 303 flags = ZEBRA_IFA_PEER; 304 } 305 else if (ifap->ifa_broadaddr && 306 !IPV6_ADDR_SAME(&addr->sin6_addr, 307 &((struct sockaddr_in6 *) 308 ifap->ifa_broadaddr)->sin6_addr)) 309 { 310 dest = (struct sockaddr_in6 *) ifap->ifa_broadaddr; 311 dest_pnt = &dest->sin6_addr; 312 } 313 314#if defined(KAME) 315 if (IN6_IS_ADDR_LINKLOCAL(&addr->sin6_addr)) 316 { 317 addr->sin6_scope_id = 318 ntohs(*(u_int16_t *)&addr->sin6_addr.s6_addr[2]); 319 addr->sin6_addr.s6_addr[2] = addr->sin6_addr.s6_addr[3] = 0; 320 } 321#endif 322 323 connected_add_ipv6 (ifp, flags, &addr->sin6_addr, prefixlen, 324 dest_pnt, NULL); 325 } 326#endif /* HAVE_IPV6 */ 327 } 328 329 freeifaddrs (ifapfree); 330 331 return 0; 332} 333#else /* HAVE_GETIFADDRS */ 334/* Interface address lookup by ioctl. This function only looks up 335 IPv4 address. */ 336int 337if_get_addr (struct interface *ifp) 338{ 339 int ret; 340 struct ifreq ifreq; 341 struct sockaddr_in addr; 342 struct sockaddr_in mask; 343 struct sockaddr_in dest; 344 struct in_addr *dest_pnt; 345 u_char prefixlen; 346 int flags = 0; 347 348 /* Interface's name and address family. */ 349 strncpy (ifreq.ifr_name, ifp->name, IFNAMSIZ); 350 ifreq.ifr_addr.sa_family = AF_INET; 351 352 /* Interface's address. */ 353 ret = if_ioctl (SIOCGIFADDR, (caddr_t) &ifreq); 354 if (ret < 0) 355 { 356 if (errno != EADDRNOTAVAIL) 357 { 358 zlog_warn ("SIOCGIFADDR fail: %s", safe_strerror (errno)); 359 return ret; 360 } 361 return 0; 362 } 363 memcpy (&addr, &ifreq.ifr_addr, sizeof (struct sockaddr_in)); 364 365 /* Interface's network mask. */ 366 ret = if_ioctl (SIOCGIFNETMASK, (caddr_t) &ifreq); 367 if (ret < 0) 368 { 369 if (errno != EADDRNOTAVAIL) 370 { 371 zlog_warn ("SIOCGIFNETMASK fail: %s", safe_strerror (errno)); 372 return ret; 373 } 374 return 0; 375 } 376#ifdef ifr_netmask 377 memcpy (&mask, &ifreq.ifr_netmask, sizeof (struct sockaddr_in)); 378#else 379 memcpy (&mask, &ifreq.ifr_addr, sizeof (struct sockaddr_in)); 380#endif /* ifr_netmask */ 381 prefixlen = ip_masklen (mask.sin_addr); 382 383 /* Point to point or borad cast address pointer init. */ 384 dest_pnt = NULL; 385 386 ret = if_ioctl (SIOCGIFDSTADDR, (caddr_t) &ifreq); 387 if (ret < 0) 388 { 389 if (errno != EADDRNOTAVAIL) 390 zlog_warn ("SIOCGIFDSTADDR fail: %s", safe_strerror (errno)); 391 } 392 else if (!IPV4_ADDR_SAME(&addr.sin_addr, &ifreq.ifr_dstaddr.sin_addr)) 393 { 394 memcpy (&dest, &ifreq.ifr_dstaddr, sizeof (struct sockaddr_in)); 395 dest_pnt = &dest.sin_addr; 396 flags = ZEBRA_IFA_PEER; 397 } 398 if (!dest_pnt) 399 { 400 ret = if_ioctl (SIOCGIFBRDADDR, (caddr_t) &ifreq); 401 if (ret < 0) 402 { 403 if (errno != EADDRNOTAVAIL) 404 zlog_warn ("SIOCGIFBRDADDR fail: %s", safe_strerror (errno)); 405 } 406 else if (!IPV4_ADDR_SAME(&addr.sin_addr, &ifreq.ifr_broadaddr.sin_addr)) 407 { 408 memcpy (&dest, &ifreq.ifr_broadaddr, sizeof (struct sockaddr_in)); 409 dest_pnt = &dest.sin_addr; 410 } 411 } 412 413 414 /* Set address to the interface. */ 415 connected_add_ipv4 (ifp, flags, &addr.sin_addr, prefixlen, dest_pnt, NULL); 416 417 return 0; 418} 419#endif /* HAVE_GETIFADDRS */ 420 421/* Fetch interface information via ioctl(). */ 422static void 423interface_info_ioctl () 424{ 425 struct listnode *node, *nnode; 426 struct interface *ifp; 427 428 for (ALL_LIST_ELEMENTS (iflist, node, nnode, ifp)) 429 { 430 if_get_index (ifp); 431#ifdef SIOCGIFHWADDR 432 if_get_hwaddr (ifp); 433#endif /* SIOCGIFHWADDR */ 434 if_get_flags (ifp); 435#ifndef HAVE_GETIFADDRS 436 if_get_addr (ifp); 437#endif /* ! HAVE_GETIFADDRS */ 438 if_get_mtu (ifp); 439 if_get_metric (ifp); 440 } 441} 442 443/* Lookup all interface information. */ 444void 445interface_list () 446{ 447 /* Linux can do both proc & ioctl, ioctl is the only way to get 448 interface aliases in 2.2 series kernels. */ 449#ifdef HAVE_PROC_NET_DEV 450 interface_list_proc (); 451#endif /* HAVE_PROC_NET_DEV */ 452 interface_list_ioctl (); 453 454 /* After listing is done, get index, address, flags and other 455 interface's information. */ 456 interface_info_ioctl (); 457 458#ifdef HAVE_GETIFADDRS 459 if_getaddrs (); 460#endif /* HAVE_GETIFADDRS */ 461 462#if defined(HAVE_IPV6) && defined(HAVE_PROC_NET_IF_INET6) 463 /* Linux provides interface's IPv6 address via 464 /proc/net/if_inet6. */ 465 ifaddr_proc_ipv6 (); 466#endif /* HAVE_IPV6 && HAVE_PROC_NET_IF_INET6 */ 467} 468