5 kx /*
5 kx Unix SMB/Netbios implementation.
5 kx Version 1.9.
5 kx code to query kernel netmask
5 kx
5 kx Copyright (C) Andrew Tridgell 1998
5 kx
5 kx Copyright (C) 2011-2014
5 kx Free Software Foundation, Inc.
5 kx
5 kx This file is part of the Midnight Commander.
5 kx
5 kx The Midnight Commander is free software: you can redistribute it
5 kx and/or modify it under the terms of the GNU General Public License as
5 kx published by the Free Software Foundation, either version 3 of the License,
5 kx or (at your option) any later version.
5 kx
5 kx The Midnight Commander is distributed in the hope that it will be useful,
5 kx but WITHOUT ANY WARRANTY; without even the implied warranty of
5 kx MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
5 kx GNU General Public License for more details.
5 kx
5 kx You should have received a copy of the GNU General Public License
5 kx along with this program. If not, see <http://www.gnu.org/licenses/>.
5 kx */
5 kx
5 kx
5 kx /* working out the netmask for an interface is an incredibly non-portable
5 kx thing. We have several possible implementations below, and autoconf
5 kx tries each of them to see what works
5 kx
5 kx Note that this file does _not_ include includes.h. That is so this code
5 kx can be called directly from the autoconf tests. That also means
5 kx this code cannot use any of the normal Samba debug stuff or defines.
5 kx This is standalone code.
5 kx
5 kx */
5 kx
5 kx #ifndef AUTOCONF
5 kx #include "config.h"
5 kx #endif
5 kx
5 kx #include <stdlib.h>
5 kx #include <string.h>
5 kx
5 kx #ifdef HAVE_NETMASK_IFCONF
5 kx
5 kx #include <stdio.h>
5 kx #include <unistd.h>
5 kx #include <sys/types.h>
5 kx #include <sys/socket.h>
5 kx #include <netinet/in.h>
5 kx #include <arpa/inet.h>
5 kx #include <netdb.h>
5 kx #include <sys/ioctl.h>
5 kx #include <net/if.h>
5 kx
5 kx #ifndef SIOCGIFCONF
5 kx #include <sys/sockio.h>
5 kx #endif
5 kx
5 kx /*
5 kx * Prototype for gcc in fussy mode.
5 kx */
5 kx
5 kx int get_netmask (struct in_addr *ipaddr, struct in_addr *nmask);
5 kx
5 kx /****************************************************************************
5 kx get the netmask address for a local interface
5 kx ****************************************************************************/
5 kx int
5 kx get_netmask (struct in_addr *ipaddr, struct in_addr *nmask)
5 kx {
5 kx struct ifconf ifc;
5 kx char buff[2048];
5 kx int fd, i, n;
5 kx struct ifreq *ifr = NULL;
5 kx
5 kx if ((fd = socket (AF_INET, SOCK_DGRAM, 0)) == -1)
5 kx {
5 kx #ifdef DEBUG
5 kx fprintf (stderr, "socket failed\n");
5 kx #endif
5 kx return -1;
5 kx }
5 kx
5 kx ifc.ifc_len = sizeof (buff);
5 kx ifc.ifc_buf = buff;
5 kx if (ioctl (fd, SIOCGIFCONF, &ifc) != 0)
5 kx {
5 kx #ifdef DEBUG
5 kx fprintf (stderr, "SIOCGIFCONF failed\n");
5 kx #endif
5 kx close (fd);
5 kx return -1;
5 kx }
5 kx
5 kx ifr = ifc.ifc_req;
5 kx
5 kx n = ifc.ifc_len / sizeof (struct ifreq);
5 kx
5 kx #ifdef DEBUG
5 kx fprintf (stderr, "%d interfaces - looking for %s\n", n, inet_ntoa (*ipaddr));
5 kx #endif
5 kx
5 kx /* Loop through interfaces, looking for given IP address */
5 kx for (i = n - 1; i >= 0; i--)
5 kx {
5 kx if (ioctl (fd, SIOCGIFADDR, &ifr[i]) != 0)
5 kx {
5 kx #ifdef DEBUG
5 kx fprintf (stderr, "SIOCGIFADDR failed\n");
5 kx #endif
5 kx continue;
5 kx }
5 kx
5 kx #ifdef DEBUG
5 kx fprintf (stderr, "interface %s\n",
5 kx inet_ntoa ((*(struct sockaddr_in *) &ifr[i].ifr_addr).sin_addr));
5 kx #endif
5 kx if (ipaddr->s_addr != (*(struct sockaddr_in *) &ifr[i].ifr_addr).sin_addr.s_addr)
5 kx {
5 kx continue;
5 kx }
5 kx
5 kx if (ioctl (fd, SIOCGIFNETMASK, &ifr[i]) != 0)
5 kx {
5 kx #ifdef DEBUG
5 kx fprintf (stderr, "SIOCGIFNETMASK failed\n");
5 kx #endif
5 kx close (fd);
5 kx return -1;
5 kx }
5 kx close (fd);
5 kx (*nmask) = ((struct sockaddr_in *) &ifr[i].ifr_addr)->sin_addr;
5 kx #ifdef DEBUG
5 kx fprintf (stderr, "netmask %s\n", inet_ntoa (*nmask));
5 kx #endif
5 kx return 0;
5 kx }
5 kx
5 kx #ifdef DEBUG
5 kx fprintf (stderr, "interface not found\n");
5 kx #endif
5 kx
5 kx close (fd);
5 kx return -1;
5 kx }
5 kx
5 kx #elif defined(HAVE_NETMASK_IFREQ)
5 kx
5 kx #include <stdio.h>
5 kx #include <sys/types.h>
5 kx #include <sys/socket.h>
5 kx #include <netinet/in.h>
5 kx #include <arpa/inet.h>
5 kx #include <netdb.h>
5 kx #include <sys/ioctl.h>
5 kx #include <net/if.h>
5 kx
5 kx #ifndef SIOCGIFCONF
5 kx #include <sys/sockio.h>
5 kx #endif
5 kx
5 kx #ifndef I_STR
5 kx #include <sys/stropts.h>
5 kx #endif
5 kx
5 kx
5 kx /****************************************************************************
5 kx this should cover most of the rest of systems
5 kx ****************************************************************************/
5 kx int
5 kx get_netmask (struct in_addr *ipaddr, struct in_addr *nmask)
5 kx {
5 kx struct ifreq ifreq;
5 kx struct strioctl strioctl;
5 kx struct ifconf *ifc;
5 kx char buff[2048];
5 kx int fd, i, n;
5 kx struct ifreq *ifr = NULL;
5 kx
5 kx if ((fd = socket (AF_INET, SOCK_DGRAM, 0)) == -1)
5 kx {
5 kx #ifdef DEBUG
5 kx fprintf (stderr, "socket failed\n");
5 kx #endif
5 kx return -1;
5 kx }
5 kx
5 kx ifc = (struct ifconf *) buff;
5 kx ifc->ifc_len = BUFSIZ - sizeof (struct ifconf);
5 kx strioctl.ic_cmd = SIOCGIFCONF;
5 kx strioctl.ic_dp = (char *) ifc;
5 kx strioctl.ic_len = sizeof (buff);
5 kx if (ioctl (fd, I_STR, &strioctl) < 0)
5 kx {
5 kx #ifdef DEBUG
5 kx fprintf (stderr, "SIOCGIFCONF failed\n");
5 kx #endif
5 kx close (fd);
5 kx return -1;
5 kx }
5 kx
5 kx ifr = (struct ifreq *) ifc->ifc_req;
5 kx
5 kx /* Loop through interfaces, looking for given IP address */
5 kx n = ifc->ifc_len / sizeof (struct ifreq);
5 kx
5 kx for (i = 0; i < n; i++, ifr++)
5 kx {
5 kx #ifdef DEBUG
5 kx fprintf (stderr, "interface %s\n",
5 kx inet_ntoa ((*(struct sockaddr_in *) &ifr->ifr_addr).sin_addr.s_addr));
5 kx #endif
5 kx if (ipaddr->s_addr == (*(struct sockaddr_in *) &ifr->ifr_addr).sin_addr.s_addr)
5 kx {
5 kx break;
5 kx }
5 kx }
5 kx
5 kx #ifdef DEBUG
5 kx if (i == n)
5 kx {
5 kx fprintf (stderr, "interface not found\n");
5 kx close (fd);
5 kx return -1;
5 kx }
5 kx #endif
5 kx
5 kx ifreq = *ifr;
5 kx
5 kx strioctl.ic_cmd = SIOCGIFNETMASK;
5 kx strioctl.ic_dp = (char *) &ifreq;
5 kx strioctl.ic_len = sizeof (struct ifreq);
5 kx if (ioctl (fd, I_STR, &strioctl) != 0)
5 kx {
5 kx #ifdef DEBUG
5 kx fprintf (stderr, "Failed SIOCGIFNETMASK\n");
5 kx #endif
5 kx close (fd);
5 kx return -1;
5 kx }
5 kx
5 kx close (fd);
5 kx *nmask = ((struct sockaddr_in *) &ifreq.ifr_addr)->sin_addr;
5 kx #ifdef DEBUG
5 kx fprintf (stderr, "netmask %s\n", inet_ntoa (*nmask));
5 kx #endif
5 kx return 0;
5 kx }
5 kx
5 kx #elif defined(HAVE_NETMASK_AIX)
5 kx
5 kx #include <stdio.h>
5 kx #include <unistd.h> /* close() declaration for gcc in fussy mode */
5 kx #include <sys/types.h>
5 kx #include <sys/socket.h>
5 kx #include <netinet/in.h>
5 kx #include <arpa/inet.h>
5 kx #include <netdb.h>
5 kx #include <sys/ioctl.h>
5 kx #include <net/if.h>
5 kx
5 kx #ifndef SIOCGIFCONF
5 kx #include <sys/sockio.h>
5 kx #endif
5 kx
5 kx /*
5 kx * Prototype for gcc in fussy mode.
5 kx */
5 kx
5 kx int get_netmask (struct in_addr *ipaddr, struct in_addr *nmask);
5 kx
5 kx /****************************************************************************
5 kx this one is for AIX
5 kx ****************************************************************************/
5 kx
5 kx int
5 kx get_netmask (struct in_addr *ipaddr, struct in_addr *nmask)
5 kx {
5 kx char buff[2048];
5 kx int fd, i;
5 kx struct ifconf ifc;
5 kx struct ifreq *ifr = NULL;
5 kx
5 kx if ((fd = socket (AF_INET, SOCK_DGRAM, 0)) == -1)
5 kx {
5 kx #ifdef DEBUG
5 kx fprintf (stderr, "socket failed\n");
5 kx #endif
5 kx return -1;
5 kx }
5 kx
5 kx
5 kx ifc.ifc_len = sizeof (buff);
5 kx ifc.ifc_buf = buff;
5 kx
5 kx if (ioctl (fd, SIOCGIFCONF, &ifc) != 0)
5 kx {
5 kx #ifdef DEBUG
5 kx fprintf (stderr, "SIOCGIFCONF failed\n");
5 kx #endif
5 kx close (fd);
5 kx return -1;
5 kx }
5 kx
5 kx ifr = ifc.ifc_req;
5 kx /* Loop through interfaces, looking for given IP address */
5 kx i = ifc.ifc_len;
5 kx while (i > 0)
5 kx {
5 kx #ifdef DEBUG
5 kx fprintf (stderr, "interface %s\n",
5 kx inet_ntoa ((*(struct sockaddr_in *) &ifr->ifr_addr).sin_addr));
5 kx #endif
5 kx if (ipaddr->s_addr == (*(struct sockaddr_in *) &ifr->ifr_addr).sin_addr.s_addr)
5 kx {
5 kx break;
5 kx }
5 kx i -= ifr->ifr_addr.sa_len + IFNAMSIZ;
5 kx ifr = (struct ifreq *) ((char *) ifr + ifr->ifr_addr.sa_len + IFNAMSIZ);
5 kx }
5 kx
5 kx
5 kx #ifdef DEBUG
5 kx if (i <= 0)
5 kx {
5 kx fprintf (stderr, "interface not found\n");
5 kx close (fd);
5 kx return -1;
5 kx }
5 kx #endif
5 kx
5 kx if (ioctl (fd, SIOCGIFNETMASK, ifr) != 0)
5 kx {
5 kx #ifdef DEBUG
5 kx fprintf (stderr, "SIOCGIFNETMASK failed\n");
5 kx #endif
5 kx close (fd);
5 kx return -1;
5 kx }
5 kx
5 kx close (fd);
5 kx
5 kx (*nmask) = ((struct sockaddr_in *) &ifr->ifr_addr)->sin_addr;
5 kx #ifdef DEBUG
5 kx fprintf (stderr, "netmask %s\n", inet_ntoa (*nmask));
5 kx #endif
5 kx return 0;
5 kx }
5 kx
5 kx #else /* a dummy version */
5 kx struct in_addr; /* it may not have been declared before */
5 kx int get_netmask (struct in_addr *ipaddr, struct in_addr *nmask);
5 kx int
5 kx get_netmask (struct in_addr *ipaddr, struct in_addr *nmask)
5 kx {
5 kx return -1;
5 kx }
5 kx #endif
5 kx
5 kx
5 kx #ifdef AUTOCONF
5 kx /* this is the autoconf driver to test get_netmask() */
5 kx
5 kx int main ()
5 kx {
5 kx char buf[1024];
5 kx struct hostent *hp;
5 kx struct in_addr ip, nmask;
5 kx
5 kx if (gethostname (buf, sizeof (buf) - 1) != 0)
5 kx {
5 kx fprintf (stderr, "gethostname failed\n");
5 kx exit (1);
5 kx }
5 kx
5 kx hp = gethostbyname (buf);
5 kx
5 kx if (!hp)
5 kx {
5 kx fprintf (stderr, "gethostbyname failed\n");
5 kx exit (1);
5 kx }
5 kx
5 kx memcpy ((char *) &ip, (char *) hp->h_addr, hp->h_length);
5 kx
5 kx if (get_netmask (&ip, &nmask) == 0)
5 kx exit (0);
5 kx
5 kx fprintf (stderr, "get_netmask failed\n");
5 kx exit (1);
5 kx }
5 kx #endif