2 * Copyright (c) 1997-1999 Erez Zadok
3 * Copyright (c) 1990 Jan-Simon Pendry
4 * Copyright (c) 1990 Imperial College of Science, Technology & Medicine
5 * Copyright (c) 1990 The Regents of the University of California.
8 * This code is derived from software contributed to Berkeley by
9 * Jan-Simon Pendry at Imperial College, London.
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. All advertising materials mentioning features or use of this software
20 * must display the following acknowledgment:
21 * This product includes software developed by the University of
22 * California, Berkeley and its contributors.
23 * 4. Neither the name of the University nor the names of its contributors
24 * may be used to endorse or promote products derived from this software
25 * without specific prior written permission.
27 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
28 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
31 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
33 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
36 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
41 * $Id: wire.c,v 1.5 1999/09/08 23:36:52 ezk Exp $
46 * This function returns the subnet (address&netmask) for the primary network
47 * interface. If the resulting address has an entry in the hosts file, the
48 * corresponding name is returned, otherwise the address is returned in
49 * standard internet format.
50 * As a side-effect, a list of local IP/net address is recorded for use
51 * by the islocalnet() function.
53 * Derived from original by Paul Anderson (23/4/90)
54 * Updates from Dirk Grunwald (11/11/91)
59 #endif /* HAVE_CONFIG_H */
66 #endif /* HAVE_IFADDRS_H */
70 #endif /* HAVE_IRS_H */
73 * List of locally connected networks
75 typedef struct addrlist addrlist
;
78 u_long ip_addr
; /* address of network */
80 char *ip_net_num
; /* number of network */
81 char *ip_net_name
; /* name of network */
83 static addrlist
*localnets
= NULL
;
85 #if defined(IFF_LOCAL_LOOPBACK) && !defined(IFF_LOOPBACK)
86 # define IFF_LOOPBACK IFF_LOCAL_LOOPBACK
87 #endif /* defined(IFF_LOCAL_LOOPBACK) && !defined(IFF_LOOPBACK) */
89 #define C(x) ((x) & 0xff)
91 #define S2IN(s) (((struct sockaddr_in *)(s))->sin_addr.s_addr)
94 /* return malloc'ed buffer. caller must free it */
110 sprintf(buf
, "No networks.\n");
113 /* check if there's more than one network */
114 if (!localnets
->ip_next
) {
116 "Network: wire=\"%s\" (netnumber=%s).\n",
117 localnets
->ip_net_name
, localnets
->ip_net_num
);
120 buf
[0] = '\0'; /* null out buffer before appending */
121 for (i
= 1, al
= localnets
; al
; al
= al
->ip_next
, i
++) {
122 sprintf(s
, "Network %d: wire=\"%s\" (netnumber=%s).\n",
123 i
, al
->ip_net_name
, al
->ip_net_num
);
124 bufcount
+= strlen(s
);
125 if (bufcount
> buf_size
) {
127 buf
= xrealloc(buf
, buf_size
);
135 static struct addrlist
*
136 getwire_lookup(u_long address
, u_long netmask
, int ishost
)
140 char netNumberBuf
[64];
141 char buf
[GFBUFLEN
], *s
;
144 #else /* not HAVE_IRS_H */
146 #endif /* not HAVE_IRS_H */
149 * Add interface to local network singly linked list
151 al
= ALLOC(struct addrlist
);
152 al
->ip_addr
= address
;
153 al
->ip_mask
= netmask
;
154 al
->ip_net_name
= NO_SUBNET
; /* fill in a bit later */
155 al
->ip_net_num
= "0.0.0.0"; /* fill in a bit later */
158 subnet
= ntohl(address
) & ntohl(netmask
);
164 u_long mask
= ntohl(netmask
);
165 static struct irs_acc
*irs_gen
;
166 static struct irs_nw
*irs_nw
;
172 irs_gen
= irs_gen_acc("");
173 if (irs_gen
&& irs_nw
== NULL
)
174 irs_nw
= (*irs_gen
->nw_map
)(irs_gen
);
175 net
= ntohl(address
) & (mask
= ntohl(netmask
));
176 addr
[0] = (0xFF000000 & net
) >> 24;
177 addr
[1] = (0x00FF0000 & net
) >> 16;
178 addr
[2] = (0x0000FF00 & net
) >> 8;
179 addr
[3] = (0x000000FF & net
);
180 for (maskbits
= 32; !(mask
& 1); mask
>>= 1)
182 np
= (*irs_nw
->byaddr
)(irs_nw
, addr
, maskbits
, AF_INET
);
183 #else /* not HAVE_IRS_H */
184 np
= getnetbyaddr(subnet
, AF_INET
);
186 * Some systems (IRIX 6.4) cannot getnetbyaddr on networks such as
187 * "128.59.16.0". Instead, they need to look for the short form of
188 * the network, "128.59.16". So if the first getnetbyaddr failed, we
189 * shift the subnet way from zeros and try again.
192 u_long short_subnet
= subnet
;
193 while(short_subnet
&& (short_subnet
& 0x000000ff) == 0)
195 np
= getnetbyaddr(short_subnet
, AF_INET
);
197 plog(XLOG_WARNING
, "getnetbyaddr failed on 0x%x, succeeded on 0x%x",
198 (u_int
) subnet
, (u_int
) short_subnet
);
200 #endif /* not HAVE_IRS_H */
203 if ((subnet
& 0xffffff) == 0) {
204 sprintf(netNumberBuf
, "%lu", C(subnet
>> 24));
205 } else if ((subnet
& 0xffff) == 0) {
206 sprintf(netNumberBuf
, "%lu.%lu",
207 C(subnet
>> 24), C(subnet
>> 16));
208 } else if ((subnet
& 0xff) == 0) {
209 sprintf(netNumberBuf
, "%lu.%lu.%lu",
210 C(subnet
>> 24), C(subnet
>> 16),
213 sprintf(netNumberBuf
, "%lu.%lu.%lu.%lu",
214 C(subnet
>> 24), C(subnet
>> 16),
215 C(subnet
>> 8), C(subnet
));
218 /* fill in network number (string) */
219 al
->ip_net_num
= strdup(netNumberBuf
);
226 subnet
= address
& netmask
;
227 hp
= gethostbyaddr((char *) &subnet
, 4, AF_INET
);
229 s
= (char *) hp
->h_name
;
231 s
= inet_dquad(buf
, subnet
);
234 /* fill in network name (string) */
235 al
->ip_net_name
= strdup(s
);
242 * Make a dotted quad from a 32bit IP address
243 * addr is in network byte order.
244 * sizeof(buf) needs to be at least 16.
247 inet_dquad(char *buf
, u_long addr
)
250 sprintf(buf
, "%ld.%ld.%ld.%ld",
251 ((addr
>> 24) & 0xff),
252 ((addr
>> 16) & 0xff),
253 ((addr
>> 8) & 0xff),
254 ((addr
>> 0) & 0xff));
260 * Determine whether a network is on a local network
261 * (addr) is in network byte order.
264 islocalnet(u_long addr
)
271 for (al
= localnets
; al
; al
= al
->ip_next
)
272 if (((addr
^ al
->ip_addr
) & al
->ip_mask
) == 0)
276 plog(XLOG_INFO
, "%s is on a remote network", inet_dquad(buf
, addr
));
284 * Determine whether a network name is one of the local networks
288 is_network_member(const char *net
)
292 for (al
= localnets
; al
; al
= al
->ip_next
)
293 if (STREQ(net
, al
->ip_net_name
) || STREQ(net
, al
->ip_net_num
))
300 #ifdef HAVE_GETIFADDRS
302 getwire(char **name1
, char **number1
)
304 addrlist
*al
= NULL
, *tail
= NULL
;
305 struct ifaddrs
*ifaddrs
, *ifap
;
306 #ifndef HAVE_FIELD_STRUCT_IFADDRS_IFA_NEXT
308 #endif /* not HAVE_FIELD_STRUCT_IFADDRS_IFA_NEXT */
311 #ifdef HAVE_FIELD_STRUCT_IFADDRS_IFA_NEXT
312 if (getifaddrs(&ifaddrs
) < 0)
315 for (ifap
= ifaddrs
; ifap
!= NULL
; ifap
= ifap
->ifa_next
) {
316 #else /* not HAVE_FIELD_STRUCT_IFADDRS_IFA_NEXT */
317 if (getifaddrs(&ifaddrs
, &count
) < 0)
320 for (i
= 0,ifap
= ifaddrs
; i
< count
; ifap
++, i
++) {
321 #endif /* HAVE_FIELD_STRUCT_IFADDRS_IFA_NEXT */
323 if (!ifap
|| !ifap
->ifa_addr
|| ifap
->ifa_addr
->sa_family
!= AF_INET
)
327 * If the interface is a loopback, or its not running
330 if ((ifap
->ifa_flags
& IFF_LOOPBACK
) != 0)
332 if ((ifap
->ifa_flags
& IFF_RUNNING
) == 0)
335 if ((ifap
->ifa_flags
& IFF_POINTOPOINT
) == 0)
336 al
= getwire_lookup(S2IN(ifap
->ifa_addr
), S2IN(ifap
->ifa_netmask
), 0);
338 al
= getwire_lookup(S2IN(ifap
->ifa_dstaddr
), 0xffffffff, 1);
340 /* append to the end of the list */
342 localnets
= tail
= al
;
343 tail
->ip_next
= NULL
;
355 *name1
= localnets
->ip_net_name
;
356 *number1
= localnets
->ip_net_num
;
359 *number1
= "0.0.0.0";
363 #else /* not HAVE_GETIFADDRS */
365 #if defined(HAVE_FIELD_STRUCT_IFREQ_IFR_ADDR) && defined(HAVE_FIELD_STRUCT_SOCKADDR_SA_LEN)
366 # define SIZE(ifr) (MAX((ifr)->ifr_addr.sa_len, sizeof((ifr)->ifr_addr)) + sizeof(ifr->ifr_name))
367 #else /* not defined(HAVE_FIELD_STRUCT_IFREQ_IFR_ADDR) && defined(HAVE_FIELD_STRUCT_SOCKADDR_SA_LEN) */
368 # define SIZE(ifr) sizeof(struct ifreq)
369 #endif /* not defined(HAVE_FIELD_STRUCT_IFREQ_IFR_ADDR) && defined(HAVE_FIELD_STRUCT_SOCKADDR_SA_LEN) */
371 #define clist (ifc.ifc_ifcu.ifcu_req)
372 #define count (ifc.ifc_len/sizeof(struct ifreq))
376 getwire(char **name1
, char **number1
)
383 addrlist
*al
= NULL
, *tail
= NULL
;
389 char buf
[GFBUFLEN
], *s
;
393 /* if cannot get interface flags, return nothing */
394 plog(XLOG_ERROR
, "getwire unable to get interface flags");
397 #endif /* not SIOCGIFFLAGS */
400 * Get suitable socket
402 if ((fd
= socket(AF_INET
, SOCK_DGRAM
, 0)) < 0)
406 * Fill in ifconf details
408 memset(&buf
[0], 0, GFBUFLEN
);
409 ifc
.ifc_len
= sizeof(buf
);
413 * Get network interface configurations
415 if (ioctl(fd
, SIOCGIFCONF
, (caddr_t
) & ifc
) < 0)
419 * Upper bound on array
421 cplim
= buf
+ ifc
.ifc_len
;
424 * This is some magic to cope with both "traditional" and the
425 * new 4.4BSD-style struct sockaddrs. The new structure has
426 * variable length and a size field to support longer addresses.
427 * AF_LINK is a new definition for 4.4BSD.
431 * Scan the list looking for a suitable interface
433 for (cp
= buf
; cp
< cplim
; cp
+= SIZE(ifr
)) {
434 ifr
= (struct ifreq
*) cp
;
436 if (ifr
->ifr_addr
.sa_family
!= AF_INET
)
439 address
= ((struct sockaddr_in
*) &ifr
->ifr_addr
)->sin_addr
.s_addr
;
442 * Get interface flags
444 if (ioctl(fd
, SIOCGIFFLAGS
, (caddr_t
) ifr
) < 0)
448 * If the interface is a loopback, or its not running
452 if ((ifr
->ifr_flags
& IFF_LOOPBACK
) != 0)
454 #endif /* IFF_LOOPBACK */
456 * Fix for 0.0.0.0 loopback on SunOS 3.X which defines IFF_ROUTE
457 * instead of IFF_LOOPBACK.
460 if (ifr
->ifr_flags
== (IFF_UP
|IFF_RUNNING
))
462 #endif /* IFF_ROUTE */
464 /* if the interface is not UP or not RUNNING, skip it */
465 if ((ifr
->ifr_flags
& IFF_RUNNING
) == 0 ||
466 (ifr
->ifr_flags
& IFF_UP
) == 0)
469 if ((ifr
->ifr_flags
& IFF_POINTOPOINT
) == 0) {
471 * Get the netmask of this interface
473 if (ioctl(fd
, SIOCGIFNETMASK
, (caddr_t
) ifr
) < 0)
476 al
= getwire_lookup(address
, S2IN(&ifr
->ifr_addr
), 0);
478 al
= getwire_lookup(address
, 0xffffffff, 1);
480 /* append to the end of the list */
482 localnets
= tail
= al
;
483 tail
->ip_next
= NULL
;
494 *name1
= localnets
->ip_net_name
;
495 *number1
= localnets
->ip_net_num
;
498 *number1
= "0.0.0.0";
501 #endif /* not HAVE_GETIFADDRS */