1 /* 2 * Copyright (c) 1990 Jan-Simon Pendry 3 * Copyright (c) 1990 Imperial College of Science, Technology & Medicine 4 * Copyright (c) 1990 The Regents of the University of California. 5 * 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 5.4 (Berkeley) 02/09/92 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 */ 183 while (subnet &~ mask) 184 mask = (long)mask >> subnetshift; 185 186 net = subnet & mask; 187 while ((mask & 1) == 0) 188 mask >>= 1, net >>= 1; 189 190 /* 191 * Now get a usable name. 192 * First use the network database, 193 * then the host database, 194 * and finally just make a dotted quad. 195 */ 196 197 np = getnetbyaddr(net, AF_INET); 198 #else 199 /* This is probably very wrong. */ 200 np = getnetbyaddr(subnet, AF_INET); 201 #endif /* IN_CLASSA */ 202 if (np) 203 s = np->n_name; 204 else { 205 subnet = address & netmask; 206 hp = gethostbyaddr((char *) &subnet, 4, AF_INET); 207 if (hp) 208 s = hp->h_name; 209 else 210 s = inet_dquad(buf, subnet); 211 } 212 netname = strdup(s); 213 } 214 } 215 216 out: 217 if (sk >= 0) 218 (void) close(sk); 219 if (netname) 220 return netname; 221 return strdup(NO_SUBNET); 222 } 223 224 #else 225 226 char *getwire P((void)); 227 char *getwire() 228 { 229 return strdup(NO_SUBNET); 230 } 231 #endif /* SIOCGIFFLAGS */ 232 233 /* 234 * Determine whether a network is on a local network 235 * (addr) is in network byte order. 236 */ 237 int islocalnet P((unsigned long addr)); 238 int islocalnet(addr) 239 unsigned long addr; 240 { 241 addrlist *al; 242 243 for (al = localnets; al; al = al->ip_next) 244 if (((addr ^ al->ip_addr) & al->ip_mask) == 0) 245 return TRUE; 246 247 #ifdef DEBUG 248 { char buf[16]; 249 plog(XLOG_INFO, "%s is on a remote network", inet_dquad(buf, addr)); 250 } 251 #endif 252 return FALSE; 253 } 254