1 /* 2 * Copyright (c) 1990 Jan-Simon Pendry 3 * Copyright (c) 1990 Imperial College of Science, Technology & Medicine 4 * Copyright (c) 1990, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * This code is derived from software contributed to Berkeley by 8 * Jan-Simon Pendry at Imperial College, London. 9 * 10 * %sccs.include.redist.c% 11 * 12 * @(#)wire.c 8.1 (Berkeley) 06/06/93 13 * 14 * $Id: wire.c,v 5.2.2.1 1992/02/09 15:09:15 jsp beta $ 15 * 16 */ 17 18 /* 19 * This function returns the subnet (address&netmask) for the primary network 20 * interface. If the resulting address has an entry in the hosts file, the 21 * corresponding name is retuned, otherwise the address is returned in 22 * standard internet format. 23 * As a side-effect, a list of local IP/net address is recorded for use 24 * by the islocalnet() function. 25 * 26 * Derived from original by Paul Anderson (23/4/90) 27 * Updates from Dirk Grunwald (11/11/91) 28 */ 29 30 #include "am.h" 31 32 #include <sys/ioctl.h> 33 34 #define NO_SUBNET "notknown" 35 36 /* 37 * List of locally connected networks 38 */ 39 typedef struct addrlist addrlist; 40 struct addrlist { 41 addrlist *ip_next; 42 unsigned long ip_addr; 43 unsigned long ip_mask; 44 }; 45 static addrlist *localnets = 0; 46 47 #ifdef SIOCGIFFLAGS 48 #ifdef STELLIX 49 #include <sys/sema.h> 50 #endif /* STELLIX */ 51 #include <net/if.h> 52 #include <netdb.h> 53 54 #if defined(IFF_LOCAL_LOOPBACK) && !defined(IFF_LOOPBACK) 55 #define IFF_LOOPBACK IFF_LOCAL_LOOPBACK 56 #endif 57 58 #define GFBUFLEN 1024 59 #define clist (ifc.ifc_ifcu.ifcu_req) 60 #define count (ifc.ifc_len/sizeof(struct ifreq)) 61 62 char *getwire P((void)); 63 char *getwire() 64 { 65 struct hostent *hp; 66 struct netent *np; 67 struct ifconf ifc; 68 struct ifreq *ifr; 69 caddr_t cp, cplim; 70 unsigned long address, netmask, subnet; 71 char buf[GFBUFLEN], *s; 72 int sk = -1; 73 char *netname = 0; 74 75 /* 76 * Get suitable socket 77 */ 78 if ((sk = socket(AF_INET, SOCK_DGRAM, 0)) < 0) 79 goto out; 80 81 /* 82 * Fill in ifconf details 83 */ 84 ifc.ifc_len = sizeof buf; 85 ifc.ifc_buf = buf; 86 87 /* 88 * Get network interface configurations 89 */ 90 if (ioctl(sk, SIOCGIFCONF, (caddr_t) &ifc) < 0) 91 goto out; 92 93 /* 94 * Upper bound on array 95 */ 96 cplim = buf + ifc.ifc_len; 97 98 /* 99 * This is some magic to cope with both "traditional" and the 100 * new 4.4BSD-style struct sockaddrs. The new structure has 101 * variable length and a size field to support longer addresses. 102 * AF_LINK is a new definition for 4.4BSD. 103 */ 104 #ifdef AF_LINK 105 #define max(a, b) ((a) > (b) ? (a) : (b)) 106 #define size(ifr) (max((ifr)->ifr_addr.sa_len, sizeof((ifr)->ifr_addr)) + sizeof(ifr->ifr_name)) 107 #else 108 #define size(ifr) sizeof(*ifr) 109 #endif 110 /* 111 * Scan the list looking for a suitable interface 112 */ 113 for (cp = buf; cp < cplim; cp += size(ifr)) { 114 addrlist *al; 115 ifr = (struct ifreq *) cp; 116 117 if (ifr->ifr_addr.sa_family != AF_INET) 118 continue; 119 else 120 address = ((struct sockaddr_in *) &ifr->ifr_addr)->sin_addr.s_addr; 121 122 /* 123 * Get interface flags 124 */ 125 if (ioctl(sk, SIOCGIFFLAGS, (caddr_t) ifr) < 0) 126 continue; 127 128 /* 129 * If the interface is a loopback, or its not running 130 * then ignore it. 131 */ 132 if ((ifr->ifr_flags & IFF_LOOPBACK) != 0) 133 continue; 134 if ((ifr->ifr_flags & IFF_RUNNING) == 0) 135 continue; 136 137 /* 138 * Get the netmask of this interface 139 */ 140 if (ioctl(sk, SIOCGIFNETMASK, (caddr_t) ifr) < 0) 141 continue; 142 143 netmask = ((struct sockaddr_in *) &ifr->ifr_addr)->sin_addr.s_addr; 144 145 /* 146 * Add interface to local network list 147 */ 148 al = ALLOC(addrlist); 149 al->ip_addr = address; 150 al->ip_mask = netmask; 151 al->ip_next = localnets; 152 localnets = al; 153 154 if (netname == 0) { 155 unsigned long net; 156 unsigned long mask; 157 unsigned long subnetshift; 158 /* 159 * Figure out the subnet's network address 160 */ 161 subnet = address & netmask; 162 163 #ifdef IN_CLASSA 164 subnet = ntohl(subnet); 165 166 if (IN_CLASSA(subnet)) { 167 mask = IN_CLASSA_NET; 168 subnetshift = 8; 169 } else if (IN_CLASSB(subnet)) { 170 mask = IN_CLASSB_NET; 171 subnetshift = 8; 172 } else { 173 mask = IN_CLASSC_NET; 174 subnetshift = 4; 175 } 176 177 /* 178 * If there are more bits than the standard mask 179 * would suggest, subnets must be in use. 180 * Guess at the subnet mask, assuming reasonable 181 * width subnet fields. 182 * XXX: Or-in at least 1 byte's worth of 1s to make 183 * sure the top bits remain set. 184 */ 185 while (subnet &~ mask) 186 mask = (mask >> subnetshift) | 0xff000000; 187 188 net = subnet & mask; 189 while ((mask & 1) == 0) 190 mask >>= 1, net >>= 1; 191 192 /* 193 * Now get a usable name. 194 * First use the network database, 195 * then the host database, 196 * and finally just make a dotted quad. 197 */ 198 199 np = getnetbyaddr(net, AF_INET); 200 #else 201 /* This is probably very wrong. */ 202 np = getnetbyaddr(subnet, AF_INET); 203 #endif /* IN_CLASSA */ 204 if (np) 205 s = np->n_name; 206 else { 207 subnet = address & netmask; 208 hp = gethostbyaddr((char *) &subnet, 4, AF_INET); 209 if (hp) 210 s = hp->h_name; 211 else 212 s = inet_dquad(buf, subnet); 213 } 214 netname = strdup(s); 215 } 216 } 217 218 out: 219 if (sk >= 0) 220 (void) close(sk); 221 if (netname) 222 return netname; 223 return strdup(NO_SUBNET); 224 } 225 226 #else 227 228 char *getwire P((void)); 229 char *getwire() 230 { 231 return strdup(NO_SUBNET); 232 } 233 #endif /* SIOCGIFFLAGS */ 234 235 /* 236 * Determine whether a network is on a local network 237 * (addr) is in network byte order. 238 */ 239 int islocalnet P((unsigned long addr)); 240 int islocalnet(addr) 241 unsigned long addr; 242 { 243 addrlist *al; 244 245 for (al = localnets; al; al = al->ip_next) 246 if (((addr ^ al->ip_addr) & al->ip_mask) == 0) 247 return TRUE; 248 249 #ifdef DEBUG 250 { char buf[16]; 251 plog(XLOG_INFO, "%s is on a remote network", inet_dquad(buf, addr)); 252 } 253 #endif 254 return FALSE; 255 } 256