xref: /original-bsd/usr.sbin/amd/amd/wire.c (revision 551826b3)
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