xref: /original-bsd/usr.sbin/amd/amd/wire.c (revision 4092c5cc)
1328a4970Spendry /*
2328a4970Spendry  * Copyright (c) 1990 Jan-Simon Pendry
3328a4970Spendry  * Copyright (c) 1990 Imperial College of Science, Technology & Medicine
4*4092c5ccSbostic  * Copyright (c) 1990, 1993
5*4092c5ccSbostic  *	The Regents of the University of California.  All rights reserved.
6328a4970Spendry  *
7328a4970Spendry  * This code is derived from software contributed to Berkeley by
8328a4970Spendry  * Jan-Simon Pendry at Imperial College, London.
9328a4970Spendry  *
108a89c22cSpendry  * %sccs.include.redist.c%
11328a4970Spendry  *
12*4092c5ccSbostic  *	@(#)wire.c	8.1 (Berkeley) 06/06/93
13c626267eSpendry  *
14cc0207dcSpendry  * $Id: wire.c,v 5.2.2.1 1992/02/09 15:09:15 jsp beta $
15c626267eSpendry  *
16328a4970Spendry  */
17328a4970Spendry 
18328a4970Spendry /*
19cc0207dcSpendry  * This function returns the subnet (address&netmask) for the primary network
20328a4970Spendry  * interface.  If the resulting address has an entry in the hosts file, the
21328a4970Spendry  * corresponding name is retuned, otherwise the address is returned in
22328a4970Spendry  * standard internet format.
23cc0207dcSpendry  * As a side-effect, a list of local IP/net address is recorded for use
24cc0207dcSpendry  * by the islocalnet() function.
25328a4970Spendry  *
26cc0207dcSpendry  * Derived from original by Paul Anderson (23/4/90)
27cc0207dcSpendry  * Updates from Dirk Grunwald (11/11/91)
28328a4970Spendry  */
29328a4970Spendry 
30328a4970Spendry #include "am.h"
31328a4970Spendry 
32328a4970Spendry #include <sys/ioctl.h>
33328a4970Spendry 
34328a4970Spendry #define NO_SUBNET "notknown"
35328a4970Spendry 
36cc0207dcSpendry /*
37cc0207dcSpendry  * List of locally connected networks
38cc0207dcSpendry  */
39cc0207dcSpendry typedef struct addrlist addrlist;
40cc0207dcSpendry struct addrlist {
41cc0207dcSpendry 	addrlist *ip_next;
42cc0207dcSpendry 	unsigned long ip_addr;
43cc0207dcSpendry 	unsigned long ip_mask;
44cc0207dcSpendry };
45cc0207dcSpendry static addrlist *localnets = 0;
46cc0207dcSpendry 
47328a4970Spendry #ifdef SIOCGIFFLAGS
48cc0207dcSpendry #ifdef STELLIX
49cc0207dcSpendry #include <sys/sema.h>
50cc0207dcSpendry #endif /* STELLIX */
51328a4970Spendry #include <net/if.h>
52328a4970Spendry #include <netdb.h>
53328a4970Spendry 
54328a4970Spendry #if defined(IFF_LOCAL_LOOPBACK) && !defined(IFF_LOOPBACK)
55328a4970Spendry #define IFF_LOOPBACK IFF_LOCAL_LOOPBACK
56328a4970Spendry #endif
57328a4970Spendry 
58328a4970Spendry #define GFBUFLEN 1024
59328a4970Spendry #define clist (ifc.ifc_ifcu.ifcu_req)
60328a4970Spendry #define count (ifc.ifc_len/sizeof(struct ifreq))
61328a4970Spendry 
62328a4970Spendry char *getwire P((void));
getwire()63328a4970Spendry char *getwire()
64328a4970Spendry {
65328a4970Spendry 	struct hostent *hp;
66328a4970Spendry 	struct netent *np;
67328a4970Spendry 	struct ifconf ifc;
68328a4970Spendry 	struct ifreq *ifr;
69328a4970Spendry 	caddr_t cp, cplim;
70328a4970Spendry 	unsigned long address, netmask, subnet;
71328a4970Spendry 	char buf[GFBUFLEN], *s;
72328a4970Spendry 	int sk = -1;
73cc0207dcSpendry 	char *netname = 0;
74328a4970Spendry 
75328a4970Spendry 	/*
76328a4970Spendry 	 * Get suitable socket
77328a4970Spendry 	 */
78328a4970Spendry 	if ((sk = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
79328a4970Spendry 		goto out;
80328a4970Spendry 
81328a4970Spendry 	/*
82328a4970Spendry 	 * Fill in ifconf details
83328a4970Spendry 	 */
84328a4970Spendry 	ifc.ifc_len = sizeof buf;
85328a4970Spendry 	ifc.ifc_buf = buf;
86328a4970Spendry 
87328a4970Spendry 	/*
88328a4970Spendry 	 * Get network interface configurations
89328a4970Spendry 	 */
90328a4970Spendry 	if (ioctl(sk, SIOCGIFCONF, (caddr_t) &ifc) < 0)
91328a4970Spendry 		goto out;
92328a4970Spendry 
93328a4970Spendry 	/*
94328a4970Spendry 	 * Upper bound on array
95328a4970Spendry 	 */
96328a4970Spendry 	cplim = buf + ifc.ifc_len;
97328a4970Spendry 
98328a4970Spendry 	/*
99328a4970Spendry 	 * This is some magic to cope with both "traditional" and the
100328a4970Spendry 	 * new 4.4BSD-style struct sockaddrs.  The new structure has
101328a4970Spendry 	 * variable length and a size field to support longer addresses.
102328a4970Spendry 	 * AF_LINK is a new definition for 4.4BSD.
103328a4970Spendry 	 */
104328a4970Spendry #ifdef AF_LINK
105328a4970Spendry #define max(a, b) ((a) > (b) ? (a) : (b))
106c626267eSpendry #define size(ifr) (max((ifr)->ifr_addr.sa_len, sizeof((ifr)->ifr_addr)) + sizeof(ifr->ifr_name))
107328a4970Spendry #else
108c626267eSpendry #define size(ifr) sizeof(*ifr)
109328a4970Spendry #endif
110328a4970Spendry 	/*
111328a4970Spendry 	 * Scan the list looking for a suitable interface
112328a4970Spendry 	 */
113c626267eSpendry 	for (cp = buf; cp < cplim; cp += size(ifr)) {
114cc0207dcSpendry 		addrlist *al;
115328a4970Spendry 		ifr = (struct ifreq *) cp;
116328a4970Spendry 
117328a4970Spendry 		if (ifr->ifr_addr.sa_family != AF_INET)
118328a4970Spendry 			continue;
119328a4970Spendry 		else
120328a4970Spendry 			address = ((struct sockaddr_in *) &ifr->ifr_addr)->sin_addr.s_addr;
121328a4970Spendry 
122328a4970Spendry 		/*
123328a4970Spendry 		 * Get interface flags
124328a4970Spendry 		 */
125328a4970Spendry 		if (ioctl(sk, SIOCGIFFLAGS, (caddr_t) ifr) < 0)
126cc0207dcSpendry 			continue;
127328a4970Spendry 
128328a4970Spendry 		/*
129328a4970Spendry 		 * If the interface is a loopback, or its not running
130328a4970Spendry 		 * then ignore it.
131328a4970Spendry 		 */
132328a4970Spendry 		if ((ifr->ifr_flags & IFF_LOOPBACK) != 0)
133328a4970Spendry 			continue;
134328a4970Spendry 		if ((ifr->ifr_flags & IFF_RUNNING) == 0)
135328a4970Spendry 			continue;
136328a4970Spendry 
137328a4970Spendry 		/*
138328a4970Spendry 		 * Get the netmask of this interface
139328a4970Spendry 		 */
140328a4970Spendry 		if (ioctl(sk, SIOCGIFNETMASK, (caddr_t) ifr) < 0)
141cc0207dcSpendry 			continue;
142328a4970Spendry 
143328a4970Spendry 		netmask = ((struct sockaddr_in *) &ifr->ifr_addr)->sin_addr.s_addr;
144328a4970Spendry 
145cc0207dcSpendry 		/*
146cc0207dcSpendry 		 * Add interface to local network list
147cc0207dcSpendry 		 */
148cc0207dcSpendry 		al = ALLOC(addrlist);
149cc0207dcSpendry 		al->ip_addr = address;
150cc0207dcSpendry 		al->ip_mask = netmask;
151cc0207dcSpendry 		al->ip_next = localnets;
152cc0207dcSpendry 		localnets = al;
153328a4970Spendry 
154cc0207dcSpendry 		if (netname == 0) {
155cc0207dcSpendry 			unsigned long net;
156cc0207dcSpendry 			unsigned long mask;
157cc0207dcSpendry 			unsigned long subnetshift;
158328a4970Spendry 			/*
159328a4970Spendry 			 * Figure out the subnet's network address
160328a4970Spendry 			 */
161328a4970Spendry 			subnet = address & netmask;
162cc0207dcSpendry 
163c626267eSpendry #ifdef IN_CLASSA
164cc0207dcSpendry 			subnet = ntohl(subnet);
165cc0207dcSpendry 
166cc0207dcSpendry 			if (IN_CLASSA(subnet)) {
167cc0207dcSpendry 				mask = IN_CLASSA_NET;
168cc0207dcSpendry 				subnetshift = 8;
169cc0207dcSpendry 			} else if (IN_CLASSB(subnet)) {
170cc0207dcSpendry 				mask = IN_CLASSB_NET;
171cc0207dcSpendry 				subnetshift = 8;
172cc0207dcSpendry 			} else {
173cc0207dcSpendry 				mask = IN_CLASSC_NET;
174cc0207dcSpendry 				subnetshift = 4;
175cc0207dcSpendry 			}
176cc0207dcSpendry 
177cc0207dcSpendry 			/*
178cc0207dcSpendry 			 * If there are more bits than the standard mask
179cc0207dcSpendry 			 * would suggest, subnets must be in use.
180cc0207dcSpendry 			 * Guess at the subnet mask, assuming reasonable
181cc0207dcSpendry 			 * width subnet fields.
182193d5679Spendry 			 * XXX: Or-in at least 1 byte's worth of 1s to make
183193d5679Spendry 			 * sure the top bits remain set.
184cc0207dcSpendry 			 */
185cc0207dcSpendry 			while (subnet &~ mask)
186193d5679Spendry 				mask = (mask >> subnetshift) | 0xff000000;
187cc0207dcSpendry 
188cc0207dcSpendry 			net = subnet & mask;
189cc0207dcSpendry 			while ((mask & 1) == 0)
190cc0207dcSpendry 				mask >>= 1, net >>= 1;
191cc0207dcSpendry 
192328a4970Spendry 			/*
193328a4970Spendry 			 * Now get a usable name.
194328a4970Spendry 			 * First use the network database,
195328a4970Spendry 			 * then the host database,
196328a4970Spendry 			 * and finally just make a dotted quad.
197328a4970Spendry 			 */
198cc0207dcSpendry 
199cc0207dcSpendry 			np = getnetbyaddr(net, AF_INET);
200cc0207dcSpendry #else
201cc0207dcSpendry 			/* This is probably very wrong. */
202328a4970Spendry 			np = getnetbyaddr(subnet, AF_INET);
203cc0207dcSpendry #endif /* IN_CLASSA */
204328a4970Spendry 			if (np)
205328a4970Spendry 				s = np->n_name;
206328a4970Spendry 			else {
207c626267eSpendry 				subnet = address & netmask;
208328a4970Spendry 				hp = gethostbyaddr((char *) &subnet, 4, AF_INET);
209328a4970Spendry 				if (hp)
210328a4970Spendry 					s = hp->h_name;
211328a4970Spendry 				else
212328a4970Spendry 					s = inet_dquad(buf, subnet);
213328a4970Spendry 			}
214cc0207dcSpendry 			netname = strdup(s);
215cc0207dcSpendry 		}
216328a4970Spendry 	}
217328a4970Spendry 
218328a4970Spendry out:
219328a4970Spendry 	if (sk >= 0)
220328a4970Spendry 		(void) close(sk);
221cc0207dcSpendry 	if (netname)
222cc0207dcSpendry 		return netname;
223328a4970Spendry 	return strdup(NO_SUBNET);
224328a4970Spendry }
225328a4970Spendry 
226328a4970Spendry #else
227328a4970Spendry 
228328a4970Spendry char *getwire P((void));
getwire()229328a4970Spendry char *getwire()
230328a4970Spendry {
231328a4970Spendry 	return strdup(NO_SUBNET);
232328a4970Spendry }
233328a4970Spendry #endif /* SIOCGIFFLAGS */
234cc0207dcSpendry 
235cc0207dcSpendry /*
236cc0207dcSpendry  * Determine whether a network is on a local network
237cc0207dcSpendry  * (addr) is in network byte order.
238cc0207dcSpendry  */
239cc0207dcSpendry int islocalnet P((unsigned long addr));
islocalnet(addr)240cc0207dcSpendry int islocalnet(addr)
241cc0207dcSpendry unsigned long addr;
242cc0207dcSpendry {
243cc0207dcSpendry 	addrlist *al;
244cc0207dcSpendry 
245cc0207dcSpendry 	for (al = localnets; al; al = al->ip_next)
246cc0207dcSpendry 		if (((addr ^ al->ip_addr) & al->ip_mask) == 0)
247cc0207dcSpendry 			return TRUE;
248cc0207dcSpendry 
249cc0207dcSpendry #ifdef DEBUG
250cc0207dcSpendry 	{ char buf[16];
251cc0207dcSpendry 	plog(XLOG_INFO, "%s is on a remote network", inet_dquad(buf, addr));
252cc0207dcSpendry 	}
253cc0207dcSpendry #endif
254cc0207dcSpendry 	return FALSE;
255cc0207dcSpendry }
256