home *** CD-ROM | disk | FTP | other *** search
/ Il CD di internet / CD.iso / SOURCE / N / TCPIP / NNTP-1.000 / NNTP-1 / nntp.1.5.11t / server / subnet.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-10-17  |  6.4 KB  |  257 lines

  1. #ifndef lint
  2. static    char    *sccsid = "@(#)$Header: subnet.c,v 1.8 90/12/12 02:21:38 sob Exp $";
  3. #endif
  4.  
  5. #include "../common/conf.h"
  6.  
  7. #ifdef SUBNET
  8.  
  9. #include <sys/types.h>
  10. #include <sys/socket.h>
  11. #include <netinet/in.h>
  12. #ifndef NETMASK
  13. #include <net/if.h>
  14. #endif
  15. #include <sys/ioctl.h>
  16.  
  17. /*
  18.  * The following routines provide a general interface for
  19.  * subnet support.  Like the library function "inet_netof",
  20.  * which returns the standard (i.e., non-subnet) network
  21.  * portion of an internet address, "inet_snetof" returns
  22.  * the subnetwork portion -- if there is one.  If there
  23.  * isn't, it returns 0.
  24.  *
  25.  * Subnets, under 4.3, are specific to a given set of
  26.  * machines -- right down to the network interfaces.
  27.  * Because of this, the function "getifconf" must be
  28.  * called first.  This routine builds a table listing
  29.  * all the (internet) interfaces present on a machine,
  30.  * along with their subnet masks.  Then when inet_snetof
  31.  * is called, it can quickly scan this table.
  32.  *
  33.  * Unfortunately, there "ain't no graceful way" to handle
  34.  * certain situations.  For example, the kernel permits
  35.  * arbitrary subnet bits -- that is, you could have a
  36.  * 22 bit network field and a 10 bit subnet field.
  37.  * However, due to braindamage at the user level, in
  38.  * such sterling routines as getnetbyaddr, you need to
  39.  * have a subnet mask which is an even multiple of 8.
  40.  * Unless you are running with class C subnets, in which
  41.  * case it should be a multiple of 4.  Because of this rot,
  42.  * if you have non-multiples of 4 bits of subnet, you should
  43.  * define DAMAGED_NETMASK when you compile.  This will round
  44.  * things off to a multiple of 8 bits.
  45.  *
  46.  * Finally, you may want subnet support even if your system doesn't
  47.  * support the ioctls to get subnet mask information.  If you want
  48.  * such a thing, you can define NETMASK to be a constant that is
  49.  * the subnet mask for your network.
  50.  *
  51.  * And don't *even* get me started on how the definitions of the inet_foo()
  52.  * routines changed between 4.2 and 4.3, making internet addresses
  53.  * be unsigned long vs. struct in_addr.  Don't blame me if this
  54.  * won't lint...
  55.  */
  56.  
  57. /*
  58.  * One structure for each interface, containing
  59.  * the network number and subnet mask, stored in HBO.
  60.  */
  61. struct in_if {
  62.     u_long    i_net;        /* Network number, shifted right */
  63.     u_long    i_subnetmask;    /* Subnet mask for this if */
  64.     int    i_bitshift;    /* How many bits right for outside */
  65. };
  66.  
  67. /*
  68.  * Table (eventually, once we malloc) of
  69.  * internet interface subnet information.
  70.  */
  71. static    struct in_if    *in_ifsni;
  72.  
  73. static    int        if_count;
  74.  
  75. /*
  76.  * Get the network interface configuration,
  77.  * and squirrel away the network numbers and
  78.  * subnet masks of each interface.  Return
  79.  * number of interfaces found, or -1 on error.
  80.  * N.B.: don't call this more than once...
  81.  */
  82.  
  83. getifconf()
  84. {
  85. #ifndef NETMASK
  86.     register int    i, j;
  87.     int        s;
  88.     struct ifconf    ifc;
  89.     char        buf[1024];
  90.     register struct ifreq    *ifr;
  91.         int        inet_netof();
  92.     u_long        addr;
  93.  
  94.     /*
  95.      * Find out how many interfaces we have, and malloc
  96.      * room for information about each one.
  97.      */
  98.  
  99.     s = socket(AF_INET, SOCK_DGRAM, 0);
  100.     if (s < 0)
  101.         return (-1);
  102.  
  103.     ifc.ifc_buf = buf;
  104.     ifc.ifc_len = sizeof (buf);
  105.  
  106.     if (ioctl(s, SIOCGIFCONF, &ifc) < 0) {
  107.         (void) close(s);
  108.         return (-1);
  109.     }
  110.  
  111.     /*
  112.      * if_count here is the count of possible
  113.      * interfaces we may be interested in... actual
  114.      * interfaces may be less (some may not be internet,
  115.      * not all are necessarily up, etc.)
  116.      */
  117.  
  118.     if_count = ifc.ifc_len / sizeof (struct ifreq);
  119.  
  120.     in_ifsni = (struct in_if *)
  121.         malloc((unsigned) if_count * sizeof (struct in_if));
  122.     if (in_ifsni == 0) {
  123.         (void) close(s);
  124.         return (-1);
  125.     }
  126.  
  127.     for (i = j = 0; i < if_count; ++i) {
  128.         struct sockaddr_in *s_in;
  129.  
  130.         ifr = &ifc.ifc_req[i];
  131.         if (ioctl(s, SIOCGIFFLAGS, ifr) < 0)
  132.             continue;
  133.         if ((ifr->ifr_flags & IFF_UP) == 0)
  134.             continue;
  135.         if (ioctl(s, SIOCGIFADDR, ifr) < 0)
  136.             continue;
  137.         if (ifr->ifr_addr.sa_family != AF_INET)
  138.             continue;
  139.         s_in = (struct sockaddr_in *) &ifr->ifr_addr;
  140.         addr = s_in->sin_addr.s_addr;
  141.         in_ifsni[j].i_net = inet_netof(s_in->sin_addr);
  142.         if (ioctl(s, SIOCGIFNETMASK, ifr) < 0)
  143.             continue;
  144.         s_in = (struct sockaddr_in *) &ifr->ifr_addr;
  145.         in_ifsni[j].i_subnetmask = ntohl(s_in->sin_addr.s_addr);
  146.         /*
  147.          * The following should "never happen".  But under SunOS
  148.          * 3.4, along with the rest of their broken networking code,
  149.          * SIOCGIFNETMASK can get a netmask which is 0.  There
  150.          * really isn't anything that "right" that we can do
  151.          * about it, so we'll set their subnet mask to be their
  152.          * *net*work mask.  Which may or may not be right.
  153.          */
  154.         if (in_ifsni[j].i_subnetmask == 0) {
  155.             addr = ntohl(addr);
  156.             if (IN_CLASSA(addr))
  157.                 in_ifsni[j].i_subnetmask = IN_CLASSA_NET;
  158.             else if (IN_CLASSB(addr))
  159.                 in_ifsni[j].i_subnetmask = IN_CLASSB_NET;
  160.             else if (IN_CLASSC(addr))
  161.                 in_ifsni[j].i_subnetmask = IN_CLASSC_NET;
  162.             else            /* what to do ... */
  163.                 in_ifsni[j].i_subnetmask = IN_CLASSC_NET;
  164.         } else
  165.             in_ifsni[j].i_bitshift = bsr(in_ifsni[j].i_subnetmask);
  166.         j++;
  167.     }
  168.  
  169.     if_count = j;
  170.  
  171.     (void) close(s);
  172.  
  173.     return (if_count);
  174.  
  175. #else    /* hard-coded subnets */
  176.  
  177.     if_count = 1;
  178.  
  179.     in_ifsni = (struct in_if *) malloc(if_count * sizeof (struct in_if));
  180.     if (in_ifsni == 0) {
  181.         return (-1);
  182.     }
  183.     in_ifsni[0].i_net = 0;
  184.     in_ifsni[0].i_subnetmask = NETMASK;
  185.     in_ifsni[0].i_bitshift = bsr(in_ifsni[0].i_subnetmask);
  186.     return (if_count);
  187. #endif
  188. }
  189.  
  190.  
  191. /*
  192.  * Return the (sub)network number from an internet address.
  193.  * "in" is in NBO, return value in host byte order.
  194.  * If "in" is not a subnet, return 0.
  195.  */
  196.  
  197. u_long
  198. inet_snetof(in)
  199.     u_long    in;
  200. {
  201.     register int    j;
  202.     register u_long    i = ntohl(in);
  203.     register u_long    net;
  204.     int        inet_netof(), inet_lnaof();
  205.     struct in_addr in_a;
  206.  
  207.     in_a.s_addr = in;
  208.     net = inet_netof(in_a);
  209.  
  210.     /*
  211.      * Check whether network is a subnet;
  212.      * if so, return subnet number.
  213.      */
  214.     for (j = 0; j < if_count; ++j)
  215. #ifdef NETMASK
  216.         if (1) {
  217. #else
  218.         if (net == in_ifsni[j].i_net) {
  219. #endif
  220.             net = i & in_ifsni[j].i_subnetmask;
  221.             in_a.s_addr = htonl(net);
  222.             if (inet_lnaof(in_a) == 0)
  223.                 return (0);
  224.             else
  225.                 return (net >> in_ifsni[j].i_bitshift);
  226.         }
  227.  
  228.     return (0);
  229. }
  230.  
  231.  
  232. /*
  233.  * Return the number of bits required to
  234.  * shift right a mask into a getnetent-able entity.
  235.  */
  236.  
  237. bsr(mask)
  238.     register long    mask;
  239. {
  240.     register int    count = 0;
  241.  
  242.     if (mask == 0)        /* "never happen", except with SunOS 3.4 */
  243.         return (0);
  244.  
  245.     while ((mask & 1) == 0) {
  246.         ++count;
  247.         mask >>= 1;
  248.     }
  249. #ifdef DAMAGED_NETMASK
  250.     count /= 8;            /* XXX gag retch puke barf */
  251.     count *= 8;
  252. #endif
  253.     return (count);
  254. }
  255.  
  256. #endif
  257.