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));
getwire()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));
getwire()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));
islocalnet(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