1: #ifndef lint 2: static char *sccsid = "@(#)subnet.c 1.5 (Berkeley) 1/4/88"; 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 informaiton. 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: u_long 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 *) malloc(if_count * sizeof (struct in_if)); 121: if (in_ifsni == 0) { 122: (void) close(s); 123: return (-1); 124: } 125: 126: for (i = j = 0; i < if_count; ++i) { 127: ifr = &ifc.ifc_req[i]; 128: if (ioctl(s, SIOCGIFFLAGS, ifr) < 0) 129: continue; 130: if ((ifr->ifr_flags & IFF_UP) == 0) 131: continue; 132: if (ioctl(s, SIOCGIFADDR, ifr) < 0) 133: continue; 134: if (ifr->ifr_addr.sa_family != AF_INET) 135: continue; 136: addr = (*(struct sockaddr_in *)&ifr->ifr_addr).sin_addr.s_addr; 137: in_ifsni[j].i_net = inet_netof(addr); 138: if (ioctl(s, SIOCGIFNETMASK, ifr) < 0) 139: continue; 140: in_ifsni[j].i_subnetmask = 141: ntohl((*(struct sockaddr_in *)&ifr->ifr_addr).sin_addr.s_addr); 142: /* 143: * The following should "never happen". But under SunOs 144: * 3.4, along with the rest of their broken networking code, 145: * SIOCGIFNETMASK can get a netmask which is 0. There 146: * really isn't anything that "right" that we can do 147: * about it, so we'll set their subnet mask to be their 148: * *net*work mask. Which may or may not be right. 149: */ 150: if (in_ifsni[j].i_subnetmask == 0) { 151: addr = ntohl(addr); 152: if (IN_CLASSA(addr)) 153: in_ifsni[j].i_subnetmask = IN_CLASSA_NET; 154: else if (IN_CLASSB(addr)) 155: in_ifsni[j].i_subnetmask = IN_CLASSB_NET; 156: else if (IN_CLASSC(addr)) 157: in_ifsni[j].i_subnetmask = IN_CLASSC_NET; 158: else /* what to do ... */ 159: in_ifsni[j].i_subnetmask = IN_CLASSC_NET; 160: } else 161: in_ifsni[j].i_bitshift = bsr(in_ifsni[j].i_subnetmask); 162: j++; 163: } 164: 165: if_count = j; 166: 167: (void) close(s); 168: 169: return (if_count); 170: 171: #else /* hard-coded subnets */ 172: 173: if_count = 1; 174: 175: in_ifsni = (struct in_if *) malloc(if_count * sizeof (struct in_if)); 176: if (in_ifsni == 0) { 177: return (-1); 178: } 179: in_ifsni[0].i_net = 0; 180: in_ifsni[0].i_subnetmask = NETMASK; 181: in_ifsni[0].i_bitshift = bsr(in_ifsni[0].i_subnetmask); 182: return (if_count); 183: #endif 184: } 185: 186: 187: /* 188: * Return the (sub)network number from an internet address. 189: * "in" is in NBO, return value in host byte order. 190: * If "in" is not a subnet, return 0. 191: */ 192: 193: u_long 194: inet_snetof(in) 195: u_long in; 196: { 197: register int j; 198: register u_long i = ntohl(in); 199: register u_long net; 200: u_long inet_netof(), inet_lnaof(); 201: 202: net = inet_netof(in); 203: 204: /* 205: * Check whether network is a subnet; 206: * if so, return subnet number. 207: */ 208: for (j = 0; j < if_count; ++j) 209: #ifdef NETMASK 210: if (1) { 211: #else 212: if (net == in_ifsni[j].i_net) { 213: #endif 214: net = i & in_ifsni[j].i_subnetmask; 215: if (inet_lnaof(htonl(net)) == 0) 216: return (0); 217: else 218: return (net >> in_ifsni[j].i_bitshift); 219: } 220: 221: return (0); 222: } 223: 224: 225: /* 226: * Return the number of bits required to 227: * shift right a mask into a getnetent-able entitity. 228: */ 229: 230: bsr(mask) 231: register int mask; 232: { 233: register int count = 0; 234: 235: if (mask == 0) /* "never happen", except with SunOs 3.4 */ 236: return (0); 237: 238: while ((mask & 1) == 0) { 239: ++count; 240: mask >>= 1; 241: } 242: #ifdef DAMAGED_NETMASK 243: count /= 8; /* XXX gag retch puke barf */ 244: count *= 8; 245: #endif 246: return (count); 247: } 248: 249: #endif