2 * Copyright (c) 1997-2004 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.8.2.10 2004/01/06 03:15:24 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 */
65 #endif /* HAVE_IFADDRS_H */
69 #endif /* HAVE_IRS_H */
72 * List of locally connected networks
74 typedef struct addrlist addrlist;
77 u_long ip_addr; /* address of network */
79 char *ip_net_num; /* number of network */
80 char *ip_net_name; /* name of network */
82 static addrlist *localnets = NULL;
84 #if defined(IFF_LOCAL_LOOPBACK) && !defined(IFF_LOOPBACK)
85 # define IFF_LOOPBACK IFF_LOCAL_LOOPBACK
86 #endif /* defined(IFF_LOCAL_LOOPBACK) && !defined(IFF_LOOPBACK) */
88 #define C(x) ((x) & 0xff)
90 #define S2IN(s) (((struct sockaddr_in *)(s))->sin_addr.s_addr)
93 /* return malloc'ed buffer. caller must free it */
109 sprintf(buf, "No networks.\n");
112 /* check if there's more than one network */
113 if (!localnets->ip_next) {
115 "Network: wire=\"%s\" (netnumber=%s).\n",
116 localnets->ip_net_name, localnets->ip_net_num);
119 buf[0] = '\0'; /* null out buffer before appending */
120 for (i = 1, al = localnets; al; al = al->ip_next, i++) {
121 sprintf(s, "Network %d: wire=\"%s\" (netnumber=%s).\n",
122 i, al->ip_net_name, al->ip_net_num);
123 bufcount += strlen(s);
124 if (bufcount > buf_size) {
126 buf = xrealloc(buf, buf_size);
134 static struct addrlist *
135 getwire_lookup(u_long address, u_long netmask, int ishost)
139 char netNumberBuf[64];
140 char buf[GFBUFLEN], *s;
143 #else /* not HAVE_IRS_H */
145 #endif /* not HAVE_IRS_H */
148 * Add interface to local network singly linked list
150 al = ALLOC(struct addrlist);
151 al->ip_addr = address;
152 al->ip_mask = netmask;
153 al->ip_net_name = NO_SUBNET; /* fill in a bit later */
154 al->ip_net_num = "0.0.0.0"; /* fill in a bit later */
157 subnet = ntohl(address) & ntohl(netmask);
163 u_long mask = ntohl(netmask);
164 static struct irs_acc *irs_gen;
165 static struct irs_nw *irs_nw;
173 * bsdi4 added another argument to this function, without changing
174 * its name. The irs_irp_acc is the one (hacky) distinguishing
175 * feature found in <irs.h> that can differentiate between bsdi3 and
178 irs_gen = irs_gen_acc("", NULL);
179 #else /* not irs_irp_acc */
180 irs_gen = irs_gen_acc("");
181 #endif /* not irs_irp_acc */
182 if (irs_gen && irs_nw == NULL)
183 irs_nw = (*irs_gen->nw_map)(irs_gen);
184 net = ntohl(address) & (mask = ntohl(netmask));
185 addr[0] = (0xFF000000 & net) >> 24;
186 addr[1] = (0x00FF0000 & net) >> 16;
187 addr[2] = (0x0000FF00 & net) >> 8;
188 addr[3] = (0x000000FF & net);
189 for (maskbits = 32; !(mask & 1); mask >>= 1)
191 np = (*irs_nw->byaddr)(irs_nw, addr, maskbits, AF_INET);
192 #else /* not HAVE_IRS_H */
193 np = getnetbyaddr(subnet, AF_INET);
195 * Some systems (IRIX 6.4) cannot getnetbyaddr on networks such as
196 * "128.59.16.0". Instead, they need to look for the short form of
197 * the network, "128.59.16". So if the first getnetbyaddr failed, we
198 * shift the subnet way from zeros and try again.
201 u_long short_subnet = subnet;
202 while(short_subnet && (short_subnet & 0x000000ff) == 0)
204 np = getnetbyaddr(short_subnet, AF_INET);
206 plog(XLOG_WARNING, "getnetbyaddr failed on 0x%x, succeeded on 0x%x",
207 (u_int) subnet, (u_int) short_subnet);
209 #endif /* not HAVE_IRS_H */
212 if ((subnet & 0xffffff) == 0) {
213 sprintf(netNumberBuf, "%lu", C(subnet >> 24));
214 } else if ((subnet & 0xffff) == 0) {
215 sprintf(netNumberBuf, "%lu.%lu",
216 C(subnet >> 24), C(subnet >> 16));
217 } else if ((subnet & 0xff) == 0) {
218 sprintf(netNumberBuf, "%lu.%lu.%lu",
219 C(subnet >> 24), C(subnet >> 16),
222 sprintf(netNumberBuf, "%lu.%lu.%lu.%lu",
223 C(subnet >> 24), C(subnet >> 16),
224 C(subnet >> 8), C(subnet));
227 /* fill in network number (string) */
228 al->ip_net_num = strdup(netNumberBuf);
235 subnet = address & netmask;
236 hp = gethostbyaddr((char *) &subnet, 4, AF_INET);
238 s = (char *) hp->h_name;
240 s = inet_dquad(buf, subnet);
243 /* fill in network name (string) */
244 al->ip_net_name = strdup(s);
245 /* Let's be cautious here about buffer overflows -Ion */
246 if (strlen(s) > MAXHOSTNAMELEN) {
247 al->ip_net_name[MAXHOSTNAMELEN] = '\0';
248 plog(XLOG_WARNING, "Long hostname %s truncated to %d characters",
257 * Make a dotted quad from a 32bit IP address
258 * addr is in network byte order.
259 * sizeof(buf) needs to be at least 16.
262 inet_dquad(char *buf, u_long addr)
265 sprintf(buf, "%ld.%ld.%ld.%ld",
266 ((addr >> 24) & 0xff),
267 ((addr >> 16) & 0xff),
268 ((addr >> 8) & 0xff),
269 ((addr >> 0) & 0xff));
275 * Determine whether a network is on a local network
276 * (addr) is in network byte order.
279 islocalnet(u_long addr)
286 for (al = localnets; al; al = al->ip_next)
287 if (((addr ^ al->ip_addr) & al->ip_mask) == 0)
291 plog(XLOG_INFO, "%s is on a remote network", inet_dquad(buf, addr));
299 * Determine whether a network name is one of the local networks
303 is_network_member(const char *net)
308 * If the network name string does not contain a '/', use old behavior.
309 * If it does contain a '/' then interpret the string as a network/netmask
310 * pair. If "netmask" doesn't exist, use the interface's own netmask.
311 * Also support fully explicit netmasks such as 255.255.255.0 as well as
312 * bit-length netmask such as /24 (hex formats such 0xffffff00 work too).
314 if (strchr(net, '/') == NULL) {
315 for (al = localnets; al; al = al->ip_next)
316 if (STREQ(net, al->ip_net_name) || STREQ(net, al->ip_net_num))
319 char *netstr = strdup(net), *maskstr;
320 u_long netnum, masknum = 0;
321 maskstr = strchr(netstr, '/');
323 maskstr[-1] = '\0'; /* null terminate netstr */
324 if (*maskstr == '\0') /* if empty string, make it NULL */
326 /* check if netmask uses a dotted-quad or bit-length, or not defined at all */
328 if (strchr(maskstr, '.')) {
329 masknum = inet_addr(maskstr);
330 if (masknum < 0) /* can be invalid (-1) or all-1s */
331 masknum = 0xffffffff;
332 } else if (NSTRCEQ(maskstr, "0x", 2)) {
333 masknum = strtoul(maskstr, NULL, 16);
335 int bits = atoi(maskstr);
340 masknum = 0xffffffff << (32-bits);
343 netnum = inet_addr(netstr); /* not checking return value, b/c -1 (0xffffffff) is valid */
344 XFREE(netstr); /* netstr not needed any longer */
346 /* now check against each local interface */
347 for (al = localnets; al; al = al->ip_next) {
348 if ((al->ip_addr & (maskstr ? masknum : al->ip_mask)) == netnum)
357 #ifdef HAVE_GETIFADDRS
359 getwire(char **name1, char **number1)
361 addrlist *al = NULL, *tail = NULL;
362 struct ifaddrs *ifaddrs, *ifap;
363 #ifndef HAVE_STRUCT_IFADDRS_IFA_NEXT
365 #endif /* not HAVE_STRUCT_IFADDRS_IFA_NEXT */
368 #ifdef HAVE_STRUCT_IFADDRS_IFA_NEXT
369 if (getifaddrs(&ifaddrs) < 0)
372 for (ifap = ifaddrs; ifap != NULL; ifap = ifap->ifa_next) {
373 #else /* not HAVE_STRUCT_IFADDRS_IFA_NEXT */
374 if (getifaddrs(&ifaddrs, &count) < 0)
377 for (i = 0,ifap = ifaddrs; i < count; ifap++, i++) {
378 #endif /* HAVE_STRUCT_IFADDRS_IFA_NEXT */
380 if (!ifap || !ifap->ifa_addr || ifap->ifa_addr->sa_family != AF_INET)
384 * If the interface is a loopback, or its not running
387 if ((ifap->ifa_flags & IFF_LOOPBACK) != 0)
389 if ((ifap->ifa_flags & IFF_RUNNING) == 0)
392 if ((ifap->ifa_flags & IFF_POINTOPOINT) == 0)
393 al = getwire_lookup(S2IN(ifap->ifa_addr), S2IN(ifap->ifa_netmask), 0);
395 al = getwire_lookup(S2IN(ifap->ifa_dstaddr), 0xffffffff, 1);
397 /* append to the end of the list */
399 localnets = tail = al;
400 tail->ip_next = NULL;
412 *name1 = localnets->ip_net_name;
413 *number1 = localnets->ip_net_num;
416 *number1 = "0.0.0.0";
420 #else /* not HAVE_GETIFADDRS */
422 #if defined(HAVE_STRUCT_IFREQ_IFR_ADDR) && defined(HAVE_STRUCT_SOCKADDR_SA_LEN)
423 # define SIZE(ifr) (MAX((ifr)->ifr_addr.sa_len, sizeof((ifr)->ifr_addr)) + sizeof(ifr->ifr_name))
424 #else /* not defined(HAVE_STRUCT_IFREQ_IFR_ADDR) && defined(HAVE_STRUCT_SOCKADDR_SA_LEN) */
425 # define SIZE(ifr) sizeof(struct ifreq)
426 #endif /* not defined(HAVE_STRUCT_IFREQ_IFR_ADDR) && defined(HAVE_STRUCT_SOCKADDR_SA_LEN) */
428 #define clist (ifc.ifc_ifcu.ifcu_req)
429 #define count (ifc.ifc_len/sizeof(struct ifreq))
433 getwire(char **name1, char **number1)
436 struct ifreq *ifr, ifrpool;
440 addrlist *al = NULL, *tail = NULL;
446 char buf[GFBUFLEN], *s;
450 /* if cannot get interface flags, return nothing */
451 plog(XLOG_ERROR, "getwire unable to get interface flags");
454 #endif /* not SIOCGIFFLAGS */
457 * Get suitable socket
459 if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
463 * Fill in ifconf details
465 memset(&buf[0], 0, GFBUFLEN);
466 ifc.ifc_len = sizeof(buf);
470 * Get network interface configurations
472 if (ioctl(fd, SIOCGIFCONF, (caddr_t) & ifc) < 0)
476 * Upper bound on array
478 cplim = buf + ifc.ifc_len;
481 * This is some magic to cope with both "traditional" and the
482 * new 4.4BSD-style struct sockaddrs. The new structure has
483 * variable length and a size field to support longer addresses.
484 * AF_LINK is a new definition for 4.4BSD.
488 * Scan the list looking for a suitable interface
490 for (cp = buf; cp < cplim; /* increment in the loop body */) {
491 memcpy(&ifrpool, cp, sizeof(ifrpool));
495 if (ifr->ifr_addr.sa_family != AF_INET)
498 address = ((struct sockaddr_in *) &ifr->ifr_addr)->sin_addr.s_addr;
501 * Get interface flags
503 if (ioctl(fd, SIOCGIFFLAGS, (caddr_t) ifr) < 0)
507 * If the interface is a loopback, or its not running
511 if ((ifr->ifr_flags & IFF_LOOPBACK) != 0)
513 #endif /* IFF_LOOPBACK */
515 * Fix for 0.0.0.0 loopback on SunOS 3.X which defines IFF_ROUTE
516 * instead of IFF_LOOPBACK.
519 if (ifr->ifr_flags == (IFF_UP|IFF_RUNNING))
521 #endif /* IFF_ROUTE */
523 /* if the interface is not UP or not RUNNING, skip it */
524 if ((ifr->ifr_flags & IFF_RUNNING) == 0 ||
525 (ifr->ifr_flags & IFF_UP) == 0)
528 if ((ifr->ifr_flags & IFF_POINTOPOINT) == 0) {
530 * Get the netmask of this interface
532 if (ioctl(fd, SIOCGIFNETMASK, (caddr_t) ifr) < 0)
535 al = getwire_lookup(address, S2IN(&ifr->ifr_addr), 0);
537 al = getwire_lookup(address, 0xffffffff, 1);
539 /* append to the end of the list */
541 localnets = tail = al;
542 tail->ip_next = NULL;
553 *name1 = localnets->ip_net_name;
554 *number1 = localnets->ip_net_num;
557 *number1 = "0.0.0.0";
560 #endif /* not HAVE_GETIFADDRS */