|
|
DataMuseum.dkPresents historical artifacts from the history of: DKUUG/EUUG Conference tapes |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about DKUUG/EUUG Conference tapes Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - downloadIndex: T s
Length: 6503 (0x1967)
Types: TextFile
Names: »subnet.c«
└─⟦9ae75bfbd⟧ Bits:30007242 EUUGD3: Starter Kit
└─⟦5cced586a⟧ »EurOpenD3/news/nntp/nntp.1.5.7.tar.Z«
└─⟦7340f105e⟧
└─⟦this⟧ »./server/subnet.c«
#ifndef lint
static char *sccsid = "@(#)subnet.c 1.6 (Berkeley) 8/27/89";
#endif
#include "../common/conf.h"
#ifdef SUBNET
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#ifndef NETMASK
#include <net/if.h>
#endif
#include <sys/ioctl.h>
/*
* The following routines provide a general interface for
* subnet support. Like the library function "inet_netof",
* which returns the standard (i.e., non-subnet) network
* portion of an internet address, "inet_snetof" returns
* the subnetwork portion -- if there is one. If there
* isn't, it returns 0.
*
* Subnets, under 4.3, are specific to a given set of
* machines -- right down to the network interfaces.
* Because of this, the function "getifconf" must be
* called first. This routine builds a table listing
* all the (internet) interfaces present on a machine,
* along with their subnet masks. Then when inet_snetof
* is called, it can quickly scan this table.
*
* Unfortunately, there "ain't no graceful way" to handle
* certain situations. For example, the kernel permits
* arbitrary subnet bits -- that is, you could have a
* 22 bit network field and a 10 bit subnet field.
* However, due to braindamage at the user level, in
* such sterling routines as getnetbyaddr, you need to
* have a subnet mask which is an even multiple of 8.
* Unless you are running with class C subnets, in which
* case it should be a multiple of 4. Because of this rot,
* if you have non-multiples of 4 bits of subnet, you should
* define DAMAGED_NETMASK when you compile. This will round
* things off to a multiple of 8 bits.
*
* Finally, you may want subnet support even if your system doesn't
* support the ioctls to get subnet mask information. If you want
* such a thing, you can define NETMASK to be a constant that is
* the subnet mask for your network.
*
* And don't *even* get me started on how the definitions of the inet_foo()
* routines changed between 4.2 and 4.3, making internet addresses
* be unsigned long vs. struct in_addr. Don't blame me if this
* won't lint...
*/
/*
* One structure for each interface, containing
* the network number and subnet mask, stored in HBO.
*/
struct in_if {
u_long i_net; /* Network number, shifted right */
u_long i_subnetmask; /* Subnet mask for this if */
int i_bitshift; /* How many bits right for outside */
};
/*
* Table (eventually, once we malloc) of
* internet interface subnet informaiton.
*/
static struct in_if *in_ifsni;
static int if_count;
/*
* Get the network interface configuration,
* and squirrel away the network numbers and
* subnet masks of each interface. Return
* number of interfaces found, or -1 on error.
* N.B.: don't call this more than once...
*/
getifconf()
{
#ifndef NETMASK
register int i, j;
int s;
struct ifconf ifc;
char buf[1024];
register struct ifreq *ifr;
u_long inet_netof();
u_long addr;
/*
* Find out how many interfaces we have, and malloc
* room for information about each one.
*/
s = socket(AF_INET, SOCK_DGRAM, 0);
if (s < 0)
return (-1);
ifc.ifc_buf = buf;
ifc.ifc_len = sizeof (buf);
if (ioctl(s, SIOCGIFCONF, &ifc) < 0) {
(void) close(s);
return (-1);
}
/*
* if_count here is the count of possible
* interfaces we may be interested in... actual
* interfaces may be less (some may not be internet,
* not all are necessarily up, etc.)
*/
if_count = ifc.ifc_len / sizeof (struct ifreq);
in_ifsni = (struct in_if *)
malloc((unsigned) if_count * sizeof (struct in_if));
if (in_ifsni == 0) {
(void) close(s);
return (-1);
}
for (i = j = 0; i < if_count; ++i) {
struct sockaddr_in *s_in;
ifr = &ifc.ifc_req[i];
if (ioctl(s, SIOCGIFFLAGS, ifr) < 0)
continue;
if ((ifr->ifr_flags & IFF_UP) == 0)
continue;
if (ioctl(s, SIOCGIFADDR, ifr) < 0)
continue;
if (ifr->ifr_addr.sa_family != AF_INET)
continue;
s_in = (struct sockaddr_in *) &ifr->ifr_addr;
addr = s_in->sin_addr.s_addr;
in_ifsni[j].i_net = inet_netof(s_in->sin_addr);
if (ioctl(s, SIOCGIFNETMASK, ifr) < 0)
continue;
s_in = (struct sockaddr_in *) &ifr->ifr_addr;
in_ifsni[j].i_subnetmask = ntohl(s_in->sin_addr.s_addr);
/*
* The following should "never happen". But under SunOs
* 3.4, along with the rest of their broken networking code,
* SIOCGIFNETMASK can get a netmask which is 0. There
* really isn't anything that "right" that we can do
* about it, so we'll set their subnet mask to be their
* *net*work mask. Which may or may not be right.
*/
if (in_ifsni[j].i_subnetmask == 0) {
addr = ntohl(addr);
if (IN_CLASSA(addr))
in_ifsni[j].i_subnetmask = IN_CLASSA_NET;
else if (IN_CLASSB(addr))
in_ifsni[j].i_subnetmask = IN_CLASSB_NET;
else if (IN_CLASSC(addr))
in_ifsni[j].i_subnetmask = IN_CLASSC_NET;
else /* what to do ... */
in_ifsni[j].i_subnetmask = IN_CLASSC_NET;
} else
in_ifsni[j].i_bitshift = bsr(in_ifsni[j].i_subnetmask);
j++;
}
if_count = j;
(void) close(s);
return (if_count);
#else /* hard-coded subnets */
if_count = 1;
in_ifsni = (struct in_if *) malloc(if_count * sizeof (struct in_if));
if (in_ifsni == 0) {
return (-1);
}
in_ifsni[0].i_net = 0;
in_ifsni[0].i_subnetmask = NETMASK;
in_ifsni[0].i_bitshift = bsr(in_ifsni[0].i_subnetmask);
return (if_count);
#endif
}
/*
* Return the (sub)network number from an internet address.
* "in" is in NBO, return value in host byte order.
* If "in" is not a subnet, return 0.
*/
u_long
inet_snetof(in)
u_long in;
{
register int j;
register u_long i = ntohl(in);
register u_long net;
u_long inet_netof(), inet_lnaof();
struct in_addr in_a;
in_a.s_addr = in;
net = inet_netof(in_a);
/*
* Check whether network is a subnet;
* if so, return subnet number.
*/
for (j = 0; j < if_count; ++j)
#ifdef NETMASK
if (1) {
#else
if (net == in_ifsni[j].i_net) {
#endif
net = i & in_ifsni[j].i_subnetmask;
in_a.s_addr = htonl(net);
if (inet_lnaof(in_a) == 0)
return (0);
else
return (net >> in_ifsni[j].i_bitshift);
}
return (0);
}
/*
* Return the number of bits required to
* shift right a mask into a getnetent-able entitity.
*/
bsr(mask)
register long mask;
{
register int count = 0;
if (mask == 0) /* "never happen", except with SunOs 3.4 */
return (0);
while ((mask & 1) == 0) {
++count;
mask >>= 1;
}
#ifdef DAMAGED_NETMASK
count /= 8; /* XXX gag retch puke barf */
count *= 8;
#endif
return (count);
}
#endif