aboutsummaryrefslogtreecommitdiffstats
path: root/KAME/getnameinfo.c
blob: 62dee36b5f4241d8fb725c91a7b7d1dc2856386a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
/*	$KAME: getnameinfo.c,v 1.72 2005/01/13 04:12:03 itojun Exp $	*/

/*
 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. Neither the name of the project nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */

/*
 * Issues to be discussed:
 * - RFC2553 says that we should raise error on short buffer.  X/Open says
 *   we need to truncate the result.  We obey RFC2553 (and X/Open should be
 *   modified).  ipngwg rough consensus seems to follow RFC2553.  RFC3493 says
 *   nothing about it, but defines a new error code EAI_OVERFLOW which seems
 *   to be intended the code for this case.
 * - What is "local" in NI_NOFQDN?  (see comments in the code)
 * - NI_NAMEREQD and NI_NUMERICHOST conflict with each other.
 * - (KAME extension) always attach textual scopeid (fe80::1%lo0), if
 *   sin6_scope_id is filled - standardization status?
 * - what should we do if we should do getservbyport("sctp")?
 */

/*
 * Considerations about thread-safeness
 *   The code in this file is thread-safe, and so the thread-safeness of
 *   getnameinfo() depends on the property of backend functions.
 *     - getservbyport() is not thread safe for most systems we are targeting.
 *     - getipnodebyaddr() is thread safe.  However, many resolver libraries
 *       used in the function are not thread safe.
 *     - gethostbyaddr() is usually not thread safe.
 */

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#ifndef HAVE_GETNAMEINFO

#include <sys/types.h>
#include <sys/socket.h>
#include <net/if.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <arpa/nameser.h>
#include <netdb.h>
#include <resolv.h>
#include <string.h>
#include <stddef.h>
#include <errno.h>

#ifdef HAVE_INTTYPES_H
#include <inttypes.h>
#endif
#include "fetchmail.h"
#include "getaddrinfo.h"

static const struct afd {
	int a_af;
	int a_addrlen;
	int a_socklen;
	int a_off;
	int a_portoff;
} afdl [] = {
#ifdef INET6
	{PF_INET6, sizeof(struct in6_addr), sizeof(struct sockaddr_in6),
	 offsetof(struct sockaddr_in6, sin6_addr),
	 offsetof(struct sockaddr_in6, sin6_port)},
#endif
	{PF_INET, sizeof(struct in_addr), sizeof(struct sockaddr_in),
	 offsetof(struct sockaddr_in, sin_addr),
	 offsetof(struct sockaddr_in, sin_port)},
	{0, 0, 0, 0, 0},
};

#ifdef INET6
static int ip6_parsenumeric __P((const struct sockaddr *, const char *, char *,
				 size_t, int));
static int ip6_sa2str __P((const struct sockaddr_in6 *, char *, size_t, int));
#endif

int
getnameinfo(sa, salen, host, hostlen, serv, servlen, flags)
	const struct sockaddr *sa;
#ifdef HAVE_SOCKLEN_T
	socklen_t salen;
#else
	unsigned int salen;
#endif
	char *host;
	size_t hostlen;
	char *serv;
	size_t servlen;
	int flags;
{
	const struct afd *afd;
	struct servent *sp;
	struct hostent *hp;
	u_short port;
	int family, i;
	const char *addr;
	u_int32_t v4a;
	int h_error;
	char numserv[512];
	char numaddr[512];

	if (sa == NULL)
		return EAI_FAIL;

#ifdef HAVE_SA_LEN	/*XXX*/
	if (sa->sa_len != salen)
		return EAI_FAIL;
#endif

	family = sa->sa_family;
	for (i = 0; afdl[i].a_af; i++)
		if (afdl[i].a_af == family) {
			afd = &afdl[i];
			goto found;
		}
	return EAI_FAMILY;

 found:
	if (salen != afd->a_socklen)
		return EAI_FAIL;

	/* network byte order */
	memcpy(&port, (const char *)sa + afd->a_portoff, sizeof(port));
	addr = (const char *)sa + afd->a_off;

	if (serv == NULL || servlen == 0) {
		/*
		 * do nothing in this case.
		 * in case you are wondering if "&&" is more correct than
		 * "||" here: RFC3493 says that serv == NULL OR servlen == 0
		 * means that the caller does not want the result.
		 */
	} else {
		if (flags & NI_NUMERICSERV)
			sp = NULL;
		else {
			sp = getservbyport(port,
				(flags & NI_DGRAM) ? "udp" : "tcp");
		}
		if (sp) {
			if (strlen(sp->s_name) + 1 > servlen)
				return EAI_OVERFLOW;
			strlcpy(serv, sp->s_name, servlen);
		} else {
			snprintf(numserv, sizeof(numserv), "%u", ntohs(port));
			if (strlen(numserv) + 1 > servlen)
				return EAI_OVERFLOW;
			strlcpy(serv, numserv, servlen);
		}
	}

	switch (sa->sa_family) {
	case AF_INET:
		v4a = (u_int32_t)
		    ntohl(((const struct sockaddr_in *)sa)->sin_addr.s_addr);
		if (IN_MULTICAST(v4a) || IN_EXPERIMENTAL(v4a))
			flags |= NI_NUMERICHOST;
		v4a >>= IN_CLASSA_NSHIFT;
		if (v4a == 0)
			flags |= NI_NUMERICHOST;
		break;
#ifdef INET6
	case AF_INET6:
	    {
		const struct sockaddr_in6 *sin6;
		sin6 = (const struct sockaddr_in6 *)sa;
		switch (sin6->sin6_addr.s6_addr[0]) {
		case 0x00:
			if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr))
				;
			else if (IN6_IS_ADDR_LOOPBACK(&sin6->sin6_addr))
				;
			else
				flags |= NI_NUMERICHOST;
			break;
		default:
			if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr))
				flags |= NI_NUMERICHOST;
			else if (IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr))
				flags |= NI_NUMERICHOST;
			break;
		}
	    }
		break;
#endif
	}
	if (host == NULL || hostlen == 0) {
		/*
		 * do nothing in this case.
		 * in case you are wondering if "&&" is more correct than
		 * "||" here: RFC3493 says that host == NULL or hostlen == 0
		 * means that the caller does not want the result.
		 */
	} else if (flags & NI_NUMERICHOST) {
		/* NUMERICHOST and NAMEREQD conflicts with each other */
		if (flags & NI_NAMEREQD)
			return EAI_NONAME;

		goto numeric;
	} else {
#ifdef USE_GETIPNODEBY
		hp = getipnodebyaddr(addr, afd->a_addrlen, afd->a_af, &h_error);
#else
		hp = gethostbyaddr(addr, afd->a_addrlen, afd->a_af);
#ifdef HAVE_H_ERRNO
		h_error = h_errno;
#else
		h_error = EINVAL;
#endif
#endif

		if (hp) {
#if 0
			if (flags & NI_NOFQDN) {
				/*
				 * According to RFC3493 section 6.2, NI_NOFQDN
				 * means "node name portion of the FQDN shall
				 * be returned for local hosts."  The following
				 * code tries to implement it by returning the
				 * first label (the part before the first
				 * period) of the FQDN.  However, it is not
				 * clear if this always makes sense, since the
				 * given address may be outside of "local
				 * hosts."  Due to the unclear description, we
				 * disable the code in this implementation.
				 */
				char *p;
				p = strchr(hp->h_name, '.');
				if (p)
					*p = '\0';
			}
#endif
			if (strlen(hp->h_name) + 1 > hostlen) {
#ifdef USE_GETIPNODEBY
				freehostent(hp);
#endif
				return EAI_OVERFLOW;
			}
			strlcpy(host, hp->h_name, hostlen);
#ifdef USE_GETIPNODEBY
			freehostent(hp);
#endif
		} else {
			if (flags & NI_NAMEREQD)
				return EAI_NONAME;

		  numeric:
			switch(afd->a_af) {
#ifdef INET6
			case AF_INET6:
			{
				int error;

				if ((error = ip6_parsenumeric(sa, addr, host,
							      hostlen,
							      flags)) != 0)
					return(error);
				break;
			}
#endif
			default:
#ifdef HAVE_INET_NTOP
				if (inet_ntop(afd->a_af, addr, host,
				    hostlen) == NULL)
					return EAI_SYSTEM;
#else
				if (afd->a_af == AF_INET) {
				    struct in_addr addr_tmp;
				    addr_tmp.s_addr = addr;
				    strlcpy(host, inet_ntoa(addr_tmp), hostlen);
				}
				else
				    return EAI_FAMILY;
#endif
				break;
			}
		}
	}
	return(0);
}

#ifdef INET6
static int
ip6_parsenumeric(sa, addr, host, hostlen, flags)
	const struct sockaddr *sa;
	const char *addr;
	char *host;
	size_t hostlen;
	int flags;
{
	int numaddrlen;
	char numaddr[512];

	if (inet_ntop(AF_INET6, addr, numaddr, sizeof(numaddr)) == NULL)
		return EAI_SYSTEM;

	numaddrlen = strlen(numaddr);
	if (numaddrlen + 1 > hostlen) /* don't forget terminator */
		return EAI_OVERFLOW;
	strlcpy(host, numaddr, hostlen);

	if (((const struct sockaddr_in6 *)sa)->sin6_scope_id) {
		char zonebuf[MAXHOSTNAMELEN];
		int zonelen;

		zonelen = ip6_sa2str(
		    (const struct sockaddr_in6 *)(const void *)sa,
		    zonebuf, sizeof(zonebuf), flags);
		if (zonelen < 0)
			return EAI_OVERFLOW;
		if (zonelen + 1 + numaddrlen + 1 > hostlen)
			return EAI_OVERFLOW;

		/* construct <numeric-addr><delim><zoneid> */
		memcpy(host + numaddrlen + 1, zonebuf,
		    (size_t)zonelen);
		host[numaddrlen] = SCOPE_DELIMITER;
		host[numaddrlen + 1 + zonelen] = '\0';
	}

	return 0;
}

/* ARGSUSED */
static int
ip6_sa2str(sa6, buf, bufsiz, flags)
	const struct sockaddr_in6 *sa6;
	char *buf;
	size_t bufsiz;
	int flags;
{
	unsigned int ifindex;
	const struct in6_addr *a6;
	int n;

	ifindex = (unsigned int)sa6->sin6_scope_id;
	a6 = &sa6->sin6_addr;

#ifdef NI_NUMERICSCOPE
	if ((flags & NI_NUMERICSCOPE) != 0) {
		n = snprintf(buf, bufsiz, "%u", sa6->sin6_scope_id);
		if (n < 0 || n >= bufsiz)
			return -1;
		else
			return n;
	}
#endif

	/* if_indextoname() does not take buffer size.  not a good api... */
	if ((IN6_IS_ADDR_LINKLOCAL(a6) || IN6_IS_ADDR_MC_LINKLOCAL(a6) ||
	     IN6_IS_ADDR_MC_NODELOCAL(a6)) && bufsiz >= IF_NAMESIZE) {
		char *p = if_indextoname(ifindex, buf);
		if (p)
			return (strlen(p));
	}

	/* last resort */
	n = snprintf(buf, bufsiz, "%u", sa6->sin6_scope_id);
	if (n < 0 || n >= bufsiz)
		return -1;
	else
		return n;
}
#endif /* INET6 */
#endif
an> sizeof(ifaddr)); kvm_read(kvmfd, (u_long)ifaddr.ifa_addr, &sa, sizeof(sa)); if (sa.sa_family != AF_INET) { #if __FreeBSD_version >= 300001 ifaddr_addr = (u_long) ifaddr.ifa_link.tqe_next; #else ifaddr_addr = (u_long) ifaddr.ifa_next; #endif continue; } ifinfo->addr.s_addr = *(u_long *)(sa.sa_data + 2); kvm_read(kvmfd, (u_long)ifaddr.ifa_dstaddr, &sa, sizeof(sa)); ifinfo->dstaddr.s_addr = *(u_long *)(sa.sa_data + 2); kvm_read(kvmfd, (u_long)ifaddr.ifa_netmask, &sa, sizeof(sa)); ifinfo->netmask.s_addr = *(u_long *)(sa.sa_data + 2); if (if_egid) setegid(if_rgid); return 1; } if (if_egid) setegid(if_rgid); return 0; } #if __FreeBSD_version >= 300001 ifnet_addr = (u_long) ifnet.if_link.tqe_next; #else ifnet_addr = (unsigned long) ifnet.if_next; #endif } if (if_egid) setegid(if_rgid); return 0; } #else /* Do not use KVM on FreeBSD */ /* * Expand the compacted form of addresses as returned via the * configuration read via sysctl(). */ static void rt_xaddrs(caddr_t cp, caddr_t cplim, struct rt_addrinfo *rtinfo) { struct sockaddr *sa; int i; #define ROUNDUP(a) \ ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long)) #define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len)) memset(rtinfo->rti_info, 0, sizeof(rtinfo->rti_info)); for (i = 0; (i < RTAX_MAX) && (cp < cplim); i++) { if ((rtinfo->rti_addrs & (1 << i)) == 0) continue; rtinfo->rti_info[i] = sa = (struct sockaddr *)cp; ADVANCE(cp, sa); } #undef ROUNDUP #undef ADVANCE } static int get_ifinfo(const char *ifname, ifinfo_t *ifinfo) { uint i; int rc = 0; int ifindex = -1; size_t needed; char *buf = NULL; char *lim = NULL; char *next = NULL; struct if_msghdr *ifm; struct ifa_msghdr *ifam; struct sockaddr_in *sin; struct sockaddr_dl *sdl; struct rt_addrinfo info; char iname[16]; int mib[6]; memset(ifinfo, 0, sizeof(ifinfo)); /* trim interface name */ for (i = 0; i < sizeof(iname) && ifname[i] && ifname[i] != '/'; i++) iname[i] = ifname[i]; if (i == 0 || i == sizeof(iname)) { report(stderr, GT_("Unable to parse interface name from %s"), ifname); return 0; } iname[i] = 0; /* get list of existing interfaces */ mib[0] = CTL_NET; mib[1] = PF_ROUTE; mib[2] = 0; mib[3] = AF_INET; /* Only IP addresses please. */ mib[4] = NET_RT_IFLIST; mib[5] = 0; /* List all interfaces. */ /* Get interface data. */ if (sysctl(mib, 6, NULL, &needed, NULL, 0) == -1) { report(stderr, GT_("get_ifinfo: sysctl (iflist estimate) failed")); exit(1); } if ((buf = malloc(needed)) == NULL) { report(stderr, GT_("get_ifinfo: malloc failed")); exit(1); } if (sysctl(mib, 6, buf, &needed, NULL, 0) == -1) { report(stderr, GT_("get_ifinfo: sysctl (iflist) failed")); exit(1); } lim = buf+needed; /* first look for the interface information */ next = buf; while (next < lim) { ifm = (struct if_msghdr *)next; next += ifm->ifm_msglen; if (ifm->ifm_version != RTM_VERSION) { report(stderr, GT_("Routing message version %d not understood."), ifm->ifm_version); exit(1); } if (ifm->ifm_type == RTM_IFINFO) { sdl = (struct sockaddr_dl *)(ifm + 1); if (!(strlen(iname) == sdl->sdl_nlen && strncmp(iname, sdl->sdl_data, sdl->sdl_nlen) == 0)) { continue; } if ( !(ifm->ifm_flags & IFF_UP) ) { /* the interface is down */ goto get_ifinfo_end; } ifindex = ifm->ifm_index; ifinfo->rx_packets = ifm->ifm_data.ifi_ipackets; ifinfo->tx_packets = ifm->ifm_data.ifi_opackets; break; } } if (ifindex < 0) { /* we did not find an interface with a matching name */ report(stderr, GT_("No interface found with name %s"), iname); goto get_ifinfo_end; } /* now look for the interface's IP address */ next = buf; while (next < lim) { ifam = (struct ifa_msghdr *)next; next += ifam->ifam_msglen; if (ifindex > 0 && ifam->ifam_type == RTM_NEWADDR && ifam->ifam_index == ifindex) { /* Expand the compacted addresses */ info.rti_addrs = ifam->ifam_addrs; rt_xaddrs((char *)(ifam + 1), ifam->ifam_msglen + (char *)ifam, &info); /* Check for IPv4 address information only */ if (info.rti_info[RTAX_IFA]->sa_family != AF_INET) { continue; } rc = 1; sin = (struct sockaddr_in *)info.rti_info[RTAX_IFA]; if (sin) { ifinfo->addr = sin->sin_addr; } sin = (struct sockaddr_in *)info.rti_info[RTAX_NETMASK]; if (!sin) { ifinfo->netmask = sin->sin_addr; } /* note: RTAX_BRD contains the address at the other * end of a point-to-point link or the broadcast address * of non point-to-point link */ sin = (struct sockaddr_in *)info.rti_info[RTAX_BRD]; if (!sin) { ifinfo->dstaddr = sin->sin_addr; } break; } } if (rc == 0) { report(stderr, GT_("No IP address found for %s"), iname); } get_ifinfo_end: free(buf); return rc; } #endif /* __FREEBSD_USE_SYSCTL_GET_IFFINFO */ #endif /* defined __FreeBSD__ */ #ifndef HAVE_INET_ATON /* * Note: This is not a true replacement for inet_aton(), as it won't * do the right thing on "255.255.255.255" (which translates to -1 on * most machines). Fortunately this code will be used only if you're * on an older Linux that lacks a real implementation. */ #ifdef HAVE_NETINET_IN_SYSTM_H # include <sys/types.h> # include <netinet/in_systm.h> #endif #include <netinet/in.h> #include <netinet/ip.h> #include <arpa/inet.h> #include <string.h> static int inet_aton(const char *cp, struct in_addr *inp) { long addr; addr = inet_addr(cp); if (addr == ((long) -1)) return 0; memcpy(inp, &addr, sizeof(addr)); return 1; } #endif /* HAVE_INET_ATON */ void interface_parse(char *buf, struct hostdata *hp) /* parse 'interface' specification */ { char *cp1, *cp2; hp->interface = xstrdup(buf); /* find and isolate just the IP address */ if (!(cp1 = strchr(buf, '/'))) { (void) report(stderr, GT_("missing IP interface address\n")); exit(PS_SYNTAX); } *cp1++ = '\000'; /* find and isolate just the netmask */ if (!(cp2 = strchr(cp1, '/'))) cp2 = "255.255.255.255"; else *cp2++ = '\000'; /* convert IP address and netmask */ hp->interface_pair = (struct interface_pair_s *)xmalloc(sizeof(struct interface_pair_s)); if (!inet_aton(cp1, &hp->interface_pair->interface_address)) { (void) report(stderr, GT_("invalid IP interface address\n")); exit(PS_SYNTAX); } if (!inet_aton(cp2, &hp->interface_pair->interface_mask)) { (void) report(stderr, GT_("invalid IP interface mask\n")); exit(PS_SYNTAX); } /* apply the mask now to the IP address (range) required */ hp->interface_pair->interface_address.s_addr &= hp->interface_pair->interface_mask.s_addr; /* restore original interface string (for configuration dumper) */ *--cp1 = '/'; return; } void interface_note_activity(struct hostdata *hp) /* save interface I/O counts */ { ifinfo_t ifinfo; struct query *ctl; /* if not monitoring link, all done */ if (!hp->monitor) return; /* get the current I/O stats for the monitored link */ if (get_ifinfo(hp->monitor, &ifinfo)) /* update this and preceeding host entries using the link (they were already set during this pass but the I/O count has now changed and they need to be re-updated) */ for (ctl = querylist; ctl; ctl = ctl->next) { if (ctl->server.monitor && !strcmp(hp->monitor, ctl->server.monitor)) ctl->server.monitor_io = ifinfo.rx_packets + ifinfo.tx_packets; /* do NOT update host entries following this one */ if (&ctl->server == hp) break; } #ifdef ACTIVITY_DEBUG (void) report(stdout, GT_("activity on %s -noted- as %d\n"), hp->monitor, hp->monitor_io); #endif } int interface_approve(struct hostdata *hp, flag domonitor) /* return TRUE if OK to poll, FALSE otherwise */ { ifinfo_t ifinfo; /* check interface IP address (range), if specified */ if (hp->interface) { /* get interface info */ if (!get_ifinfo(hp->interface, &ifinfo)) { (void) report(stdout, GT_("skipping poll of %s, %s down\n"), hp->pollname, hp->interface); return(FALSE); } /* check the IP addresses (range) */ if (!( /* check remote IP address */ ((ifinfo.dstaddr.s_addr != 0) && (ifinfo.dstaddr.s_addr & hp->interface_pair->interface_mask.s_addr) == hp->interface_pair->interface_address.s_addr) || /* check local IP address */ ((ifinfo.addr.s_addr & hp->interface_pair->interface_mask.s_addr) == hp->interface_pair->interface_address.s_addr) ) ) { (void) report(stdout, GT_("skipping poll of %s, %s IP address excluded\n"), hp->pollname, hp->interface); return(FALSE); } } /* if not monitoring link, all done */ if (!domonitor || !hp->monitor) return(TRUE); #ifdef ACTIVITY_DEBUG (void) report(stdout, GT_("activity on %s checked as %d\n"), hp->monitor, hp->monitor_io); #endif /* if monitoring, check link for activity if it is up */ if (get_ifinfo(hp->monitor, &ifinfo)) { int diff = (ifinfo.rx_packets + ifinfo.tx_packets) - hp->monitor_io; /* * There are three cases here: * * (a) If the new packet count is less than the recorded one, * probably pppd was restarted while fetchmail was running. * Don't skip. * * (b) newpacket count is greater than the old packet count, * but the difference is small and may just reflect the overhead * of a link shutdown. Skip. * * (c) newpacket count is greater than the old packet count, * and the difference is large. Connection is live. Don't skip. */ if (diff >= 0 && diff <= MONITOR_SLOP) { (void) report(stdout, GT_("skipping poll of %s, %s inactive\n"), hp->pollname, hp->monitor); return(FALSE); } } #ifdef ACTIVITY_DEBUG report(stdout, GT_("activity on %s was %d, is %d\n"), hp->monitor, hp->monitor_io, ifinfo.rx_packets + ifinfo.tx_packets); #endif return(TRUE); } #endif /* (defined(linux) && !defined(INET6_ENABLE)) || defined(__FreeBSD__) */