4 * Copyright (c) 1997-2009 Erez Zadok
5 * Copyright (c) 1990 Jan-Simon Pendry
6 * Copyright (c) 1990 Imperial College of Science, Technology & Medicine
7 * Copyright (c) 1990 The Regents of the University of California.
10 * This code is derived from software contributed to Berkeley by
11 * Jan-Simon Pendry at Imperial College, London.
13 * Redistribution and use in source and binary forms, with or without
14 * modification, are permitted provided that the following conditions
16 * 1. Redistributions of source code must retain the above copyright
17 * notice, this list of conditions and the following disclaimer.
18 * 2. Redistributions in binary form must reproduce the above copyright
19 * notice, this list of conditions and the following disclaimer in the
20 * documentation and/or other materials provided with the distribution.
21 * 3. All advertising materials mentioning features or use of this software
22 * must display the following acknowledgment:
23 * This product includes software developed by the University of
24 * California, Berkeley and its contributors.
25 * 4. Neither the name of the University nor the names of its contributors
26 * may be used to endorse or promote products derived from this software
27 * without specific prior written permission.
29 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
30 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
31 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
32 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
33 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
34 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
35 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
36 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
37 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
38 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
42 * File: am-utils/libamu/wire.c
47 * This function returns the subnet (address&netmask) for the primary network
48 * interface. If the resulting address has an entry in the hosts file, the
49 * corresponding name is returned, otherwise the address is returned in
50 * standard internet format.
51 * As a side-effect, a list of local IP/net address is recorded for use
52 * by the islocalnet() function.
54 * Derived from original by Paul Anderson (23/4/90)
55 * Updates from Dirk Grunwald (11/11/91)
60 #endif /* HAVE_CONFIG_H */
67 #endif /* HAVE_IFADDRS_H */
71 #endif /* HAVE_IRS_H */
74 * List of locally connected networks
76 typedef struct addrlist addrlist
;
79 u_long ip_addr
; /* address of network */
81 char *ip_net_num
; /* number of network */
82 char *ip_net_name
; /* name of network */
84 static addrlist
*localnets
= NULL
;
86 #if defined(IFF_LOCAL_LOOPBACK) && !defined(IFF_LOOPBACK)
87 # define IFF_LOOPBACK IFF_LOCAL_LOOPBACK
88 #endif /* defined(IFF_LOCAL_LOOPBACK) && !defined(IFF_LOOPBACK) */
90 #define C(x) ((x) & 0xff)
92 #define S2IN(s) (((struct sockaddr_in *)(s))->sin_addr.s_addr)
95 /* return malloc'ed buffer. caller must free it */
106 buf
= SALLOC(buf_size
); /* initial allocation (may grow!) */
111 xstrlcpy(buf
, "No networks\n", buf_size
);
114 /* check if there's more than one network */
115 if (!localnets
->ip_next
) {
116 /* use buf_size for sizeof(buf) because of the realloc() below */
117 xsnprintf(buf
, buf_size
,
118 "Network: wire=\"%s\" (netnumber=%s).\n",
119 localnets
->ip_net_name
, localnets
->ip_net_num
);
122 buf
[0] = '\0'; /* null out buffer before appending */
123 for (i
= 1, al
= localnets
; al
; al
= al
->ip_next
, i
++) {
124 xsnprintf(s
, sizeof(s
), "Network %d: wire=\"%s\" (netnumber=%s).\n",
125 i
, al
->ip_net_name
, al
->ip_net_num
);
126 bufcount
+= strlen(s
);
127 if (bufcount
> buf_size
) {
129 buf
= xrealloc(buf
, buf_size
);
131 xstrlcat(buf
, s
, buf_size
);
137 static struct addrlist
*
138 getwire_lookup(u_long address
, u_long netmask
, int ishost
)
142 char netNumberBuf
[64];
143 char buf
[GFBUFLEN
], *s
;
146 #else /* not HAVE_IRS_H */
148 #endif /* not HAVE_IRS_H */
151 * Add interface to local network singly linked list
153 al
= ALLOC(struct addrlist
);
154 al
->ip_addr
= address
;
155 al
->ip_mask
= netmask
;
156 al
->ip_net_name
= NO_SUBNET
; /* fill in a bit later */
157 al
->ip_net_num
= "0.0.0.0"; /* fill in a bit later */
160 subnet
= ntohl(address
) & ntohl(netmask
);
166 u_long mask
= ntohl(netmask
);
167 static struct irs_acc
*irs_gen
;
168 static struct irs_nw
*irs_nw
;
176 * bsdi4 added another argument to this function, without changing
177 * its name. The irs_irp_acc is the one (hacky) distinguishing
178 * feature found in <irs.h> that can differentiate between bsdi3 and
181 irs_gen
= irs_gen_acc("", NULL
);
182 #else /* not irs_irp_acc */
183 irs_gen
= irs_gen_acc("");
184 #endif /* not irs_irp_acc */
185 if (irs_gen
&& irs_nw
== NULL
)
186 irs_nw
= (*irs_gen
->nw_map
)(irs_gen
);
187 net
= ntohl(address
) & (mask
= ntohl(netmask
));
188 addr
[0] = (0xFF000000 & net
) >> 24;
189 addr
[1] = (0x00FF0000 & net
) >> 16;
190 addr
[2] = (0x0000FF00 & net
) >> 8;
191 addr
[3] = (0x000000FF & net
);
192 for (maskbits
= 32; !(mask
& 1); mask
>>= 1)
194 np
= (*irs_nw
->byaddr
)(irs_nw
, addr
, maskbits
, AF_INET
);
195 #else /* not HAVE_IRS_H */
196 np
= getnetbyaddr(subnet
, AF_INET
);
198 * Some systems (IRIX 6.4) cannot getnetbyaddr on networks such as
199 * "128.59.16.0". Instead, they need to look for the short form of
200 * the network, "128.59.16". So if the first getnetbyaddr failed, we
201 * shift the subnet way from zeros and try again.
204 u_long short_subnet
= subnet
;
205 while (short_subnet
&& (short_subnet
& 0x000000ff) == 0)
207 np
= getnetbyaddr(short_subnet
, AF_INET
);
209 plog(XLOG_WARNING
, "getnetbyaddr failed on 0x%x, succeeded on 0x%x",
210 (u_int
) subnet
, (u_int
) short_subnet
);
212 #endif /* not HAVE_IRS_H */
215 if ((subnet
& 0xffffff) == 0) {
216 xsnprintf(netNumberBuf
, sizeof(netNumberBuf
), "%lu", C(subnet
>> 24));
217 } else if ((subnet
& 0xffff) == 0) {
218 xsnprintf(netNumberBuf
, sizeof(netNumberBuf
), "%lu.%lu",
219 C(subnet
>> 24), C(subnet
>> 16));
220 } else if ((subnet
& 0xff) == 0) {
221 xsnprintf(netNumberBuf
, sizeof(netNumberBuf
), "%lu.%lu.%lu",
222 C(subnet
>> 24), C(subnet
>> 16),
225 xsnprintf(netNumberBuf
, sizeof(netNumberBuf
), "%lu.%lu.%lu.%lu",
226 C(subnet
>> 24), C(subnet
>> 16),
227 C(subnet
>> 8), C(subnet
));
230 /* fill in network number (string) */
231 al
->ip_net_num
= strdup(netNumberBuf
);
238 subnet
= address
& netmask
;
239 hp
= gethostbyaddr((char *) &subnet
, 4, AF_INET
);
241 s
= (char *) hp
->h_name
;
243 s
= inet_dquad(buf
, sizeof(buf
), subnet
);
246 /* fill in network name (string) */
247 al
->ip_net_name
= strdup(s
);
248 /* Let's be cautious here about buffer overflows -Ion */
249 if (strlen(s
) > MAXHOSTNAMELEN
) {
250 al
->ip_net_name
[MAXHOSTNAMELEN
] = '\0';
251 plog(XLOG_WARNING
, "Long hostname %s truncated to %d characters",
260 * Make a dotted quad from a 32bit IP address
261 * addr is in network byte order.
262 * sizeof(buf) needs to be at least 16.
265 inet_dquad(char *buf
, size_t l
, u_long addr
)
268 xsnprintf(buf
, l
, "%ld.%ld.%ld.%ld",
269 ((addr
>> 24) & 0xff),
270 ((addr
>> 16) & 0xff),
271 ((addr
>> 8) & 0xff),
272 ((addr
>> 0) & 0xff));
278 * Determine whether a network is on a local network
279 * (addr) is in network byte order.
282 islocalnet(u_long addr
)
286 for (al
= localnets
; al
; al
= al
->ip_next
)
287 if (((addr
^ al
->ip_addr
) & al
->ip_mask
) == 0)
293 plog(XLOG_INFO
, "%s is on a remote network",
294 inet_dquad(buf
, sizeof(buf
), addr
));
303 * Determine whether a network name is one of the local networks
307 is_network_member(const char *net
)
312 * If the network name string does not contain a '/', use old behavior.
313 * If it does contain a '/' then interpret the string as a network/netmask
314 * pair. If "netmask" doesn't exist, use the interface's own netmask.
315 * Also support fully explicit netmasks such as 255.255.255.0 as well as
316 * bit-length netmask such as /24 (hex formats such 0xffffff00 work too).
318 if (strchr(net
, '/') == NULL
) {
319 for (al
= localnets
; al
; al
= al
->ip_next
)
320 if (STREQ(net
, al
->ip_net_name
) || STREQ(net
, al
->ip_net_num
))
323 char *netstr
= strdup(net
), *maskstr
;
324 u_long netnum
, masknum
= 0;
325 maskstr
= strchr(netstr
, '/');
326 maskstr
[0] = '\0'; /* null terminate netstr */
328 if (*maskstr
== '\0') /* if empty string, make it NULL */
330 /* check if netmask uses a dotted-quad or bit-length, or not defined at all */
332 if (strchr(maskstr
, '.')) {
333 /* XXX: inet_addr is obsolste, convert to inet_aton() */
334 masknum
= inet_addr(maskstr
);
335 if (masknum
== INADDR_NONE
) /* can be invalid (-1) or all-1s */
336 masknum
= 0xffffffff;
337 } else if (NSTRCEQ(maskstr
, "0x", 2)) {
338 masknum
= strtoul(maskstr
, NULL
, 16);
340 int bits
= atoi(maskstr
);
345 masknum
= 0xffffffff << (32-bits
);
348 netnum
= inet_addr(netstr
); /* not checking return value, b/c -1 (0xffffffff) is valid */
349 XFREE(netstr
); /* netstr not needed any longer */
351 /* now check against each local interface */
352 for (al
= localnets
; al
; al
= al
->ip_next
) {
353 if ((al
->ip_addr
& (maskstr
? masknum
: al
->ip_mask
)) == netnum
)
363 * Determine whether a IP address (netnum) is one of the local interfaces,
364 * returns TRUE/FALSE.
365 * Does not include the loopback interface: caller needs to check that.
368 is_interface_local(u_long netnum
)
372 for (al
= localnets
; al
; al
= al
->ip_next
) {
373 if (al
->ip_addr
== netnum
)
380 #ifdef HAVE_GETIFADDRS
382 getwire(char **name1
, char **number1
)
384 addrlist
*al
= NULL
, *tail
= NULL
;
385 struct ifaddrs
*ifaddrs
, *ifap
;
386 #ifndef HAVE_STRUCT_IFADDRS_IFA_NEXT
388 #endif /* not HAVE_STRUCT_IFADDRS_IFA_NEXT */
391 #ifdef HAVE_STRUCT_IFADDRS_IFA_NEXT
392 if (getifaddrs(&ifaddrs
) < 0)
395 for (ifap
= ifaddrs
; ifap
!= NULL
; ifap
= ifap
->ifa_next
) {
396 #else /* not HAVE_STRUCT_IFADDRS_IFA_NEXT */
397 if (getifaddrs(&ifaddrs
, &count
) < 0)
400 for (i
= 0,ifap
= ifaddrs
; i
< count
; ifap
++, i
++) {
401 #endif /* HAVE_STRUCT_IFADDRS_IFA_NEXT */
403 if (!ifap
|| !ifap
->ifa_addr
|| ifap
->ifa_addr
->sa_family
!= AF_INET
)
407 * If the interface is the loopback, or it's not running,
410 if (S2IN(ifap
->ifa_addr
) == htonl(INADDR_LOOPBACK
))
412 if ((ifap
->ifa_flags
& IFF_RUNNING
) == 0)
415 if ((ifap
->ifa_flags
& IFF_POINTOPOINT
) == 0)
416 al
= getwire_lookup(S2IN(ifap
->ifa_addr
), S2IN(ifap
->ifa_netmask
), 0);
418 al
= getwire_lookup(S2IN(ifap
->ifa_dstaddr
), 0xffffffff, 1);
420 /* append to the end of the list */
421 if (!localnets
|| tail
== NULL
) {
422 localnets
= tail
= al
;
423 tail
->ip_next
= NULL
;
435 *name1
= localnets
->ip_net_name
;
436 *number1
= localnets
->ip_net_num
;
439 *number1
= "0.0.0.0";
443 #else /* not HAVE_GETIFADDRS */
445 #if defined(HAVE_STRUCT_IFREQ_IFR_ADDR) && defined(HAVE_STRUCT_SOCKADDR_SA_LEN)
446 # define SIZE(ifr) (MAX((ifr)->ifr_addr.sa_len, sizeof((ifr)->ifr_addr)) + sizeof(ifr->ifr_name))
447 #else /* not defined(HAVE_STRUCT_IFREQ_IFR_ADDR) && defined(HAVE_STRUCT_SOCKADDR_SA_LEN) */
448 # define SIZE(ifr) sizeof(struct ifreq)
449 #endif /* not defined(HAVE_STRUCT_IFREQ_IFR_ADDR) && defined(HAVE_STRUCT_SOCKADDR_SA_LEN) */
451 #define clist (ifc.ifc_ifcu.ifcu_req)
452 #define count (ifc.ifc_len/sizeof(struct ifreq))
456 getwire(char **name1
, char **number1
)
459 struct ifreq
*ifr
, ifrpool
;
463 addrlist
*al
= NULL
, *tail
= NULL
;
467 /* if cannot get interface flags, return nothing */
468 plog(XLOG_ERROR
, "getwire unable to get interface flags");
471 #endif /* not SIOCGIFFLAGS */
474 * Get suitable socket
476 if ((fd
= socket(AF_INET
, SOCK_DGRAM
, 0)) < 0)
480 * Fill in ifconf details
482 memset(&buf
[0], 0, GFBUFLEN
);
483 ifc
.ifc_len
= sizeof(buf
);
487 * Get network interface configurations
489 if (ioctl(fd
, SIOCGIFCONF
, (caddr_t
) & ifc
) < 0)
493 * Upper bound on array
495 cplim
= buf
+ ifc
.ifc_len
;
498 * This is some magic to cope with both "traditional" and the
499 * new 4.4BSD-style struct sockaddrs. The new structure has
500 * variable length and a size field to support longer addresses.
501 * AF_LINK is a new definition for 4.4BSD.
505 * Scan the list looking for a suitable interface
507 for (cp
= buf
; cp
< cplim
; /* increment in the loop body */) {
508 memcpy(&ifrpool
, cp
, sizeof(ifrpool
));
512 if (ifr
->ifr_addr
.sa_family
!= AF_INET
)
515 address
= ((struct sockaddr_in
*) &ifr
->ifr_addr
)->sin_addr
.s_addr
;
518 * Get interface flags
520 if (ioctl(fd
, SIOCGIFFLAGS
, (caddr_t
) ifr
) < 0)
524 * If the interface is the loopback, or it's not running,
527 if (address
== htonl(INADDR_LOOPBACK
))
530 * Fix for 0.0.0.0 loopback on SunOS 3.X which defines IFF_ROUTE
531 * instead of IFF_LOOPBACK.
534 if (ifr
->ifr_flags
== (IFF_UP
|IFF_RUNNING
))
536 #endif /* IFF_ROUTE */
538 /* if the interface is not UP or not RUNNING, skip it */
539 if ((ifr
->ifr_flags
& IFF_RUNNING
) == 0 ||
540 (ifr
->ifr_flags
& IFF_UP
) == 0)
543 if ((ifr
->ifr_flags
& IFF_POINTOPOINT
) == 0) {
545 * Get the netmask of this interface
547 if (ioctl(fd
, SIOCGIFNETMASK
, (caddr_t
) ifr
) < 0)
550 al
= getwire_lookup(address
, S2IN(&ifr
->ifr_addr
), 0);
552 al
= getwire_lookup(address
, 0xffffffff, 1);
554 /* append to the end of the list */
556 localnets
= tail
= al
;
557 tail
->ip_next
= NULL
;
568 *name1
= localnets
->ip_net_name
;
569 *number1
= localnets
->ip_net_num
;
572 *number1
= "0.0.0.0";
575 #endif /* not HAVE_GETIFADDRS */