From 2bf693c353558f73be67eac78ae864458d84258b Mon Sep 17 00:00:00 2001 From: "Eric S. Raymond" Date: Tue, 24 Dec 1996 21:28:41 +0000 Subject: Initial revision svn path=/trunk/; revision=686 --- interface.c | 191 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 191 insertions(+) create mode 100644 interface.c diff --git a/interface.c b/interface.c new file mode 100644 index 00000000..9520f1c5 --- /dev/null +++ b/interface.c @@ -0,0 +1,191 @@ +/* + * interface.c -- implements fetchmail 'interface' and 'monitor' commands + * + * This module was implemented by George M. Sipe and is + * + * Copyright (c) 1996 by George M. Sipe - ALL RIGHTS RESERVED + * + * This is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free + * Software Foundation; version 2, or (at your option) any later version. + */ + +#ifdef linux + +#include +#include +#include +#include +#include +#include +#include "fetchmail.h" + +static struct in_addr interface_address; +static struct in_addr interface_mask; + +static int monitor_io = 0; + +typedef struct { + struct in_addr addr, dstaddr, netmask; + int rx_packets, tx_packets; +} ifinfo_t; + +/* Get active network interface information. Return non-zero upon success. */ + +static int _get_ifinfo_(int socket_fd, FILE *stats_file, const char *ifname, + ifinfo_t *ifinfo) +{ + int namelen = strlen(ifname); + struct ifreq request; + char *cp, buffer[256]; + + /* initialize result */ + memset((char *) ifinfo, 0, sizeof(ifinfo_t)); + + /* see if the interface is up */ + strcpy(request.ifr_name, ifname); + if (ioctl(socket_fd, SIOCGIFFLAGS, &request) < 0) + return(FALSE); + if (!(request.ifr_flags & IFF_RUNNING)) + return(FALSE); + + /* get the IP address */ + strcpy(request.ifr_name, ifname); + if (ioctl(socket_fd, SIOCGIFADDR, &request) < 0) + return(FALSE); + ifinfo->addr = ((struct sockaddr_in *) (&request.ifr_addr))->sin_addr; + + /* get the PPP destination IP address */ + strcpy(request.ifr_name, ifname); + if (ioctl(socket_fd, SIOCGIFDSTADDR, &request) >= 0) + ifinfo->dstaddr = ((struct sockaddr_in *) + (&request.ifr_dstaddr))->sin_addr; + + /* get the netmask */ + strcpy(request.ifr_name, ifname); + if (ioctl(socket_fd, SIOCGIFNETMASK, &request) >= 0) + ifinfo->netmask = ((struct sockaddr_in *) + (&request.ifr_netmask))->sin_addr; + + /* get the packet I/O counts */ + while (fgets(buffer, sizeof(buffer) - 1, stats_file)) { + for (cp = buffer; *cp && *cp == ' '; ++cp); + if (!strncmp(cp, ifname, namelen) && + cp[namelen] == ':') { + cp += namelen + 1; + sscanf(cp, "%d %*d %*d %*d %*d %d %*d %*d %*d %*d %*d", + &ifinfo->rx_packets, &ifinfo->tx_packets); + return(TRUE); + } + } + return(FALSE); +} + +static int get_ifinfo(const char *ifname, ifinfo_t *ifinfo) +{ + int socket_fd = socket(AF_INET, SOCK_DGRAM, 0); + FILE *stats_file = fopen("/proc/net/dev", "r"); + int result; + + if (socket_fd < 0 || !stats_file) + result = -1; + else + result = _get_ifinfo_(socket_fd, stats_file, ifname, ifinfo); + if (socket_fd >= 0) + close(socket_fd); + if (stats_file) + fclose(stats_file); + return(result); +} + +/* Parse 'interface' specification. */ + +void interface_parse(void) +{ + char *cp1, *cp2; + + /* in the event we point to a null string, make pointer null */ + if (interface && !*interface) + interface = NULL; + if (monitor && !*monitor) + monitor = NULL; + + /* if no interface specification present, all done */ + if (!interface) + return; + + /* find and isolate just the IP address */ + if (!(cp1 = strchr(interface, '/'))) { + (void) fprintf(stderr, "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 */ + if (!inet_aton(cp1, &interface_address)) { + (void) fprintf(stderr, "invalid IP interface address\n"); + exit(PS_SYNTAX); + } + if (!inet_aton(cp2, &interface_mask)) { + (void) fprintf(stderr, "invalid IP interface mask\n"); + exit(PS_SYNTAX); + } + /* apply the mask now to the IP address (range) required */ + interface_address.s_addr &= interface_mask.s_addr; + return; +} + +/* Save interface I/O counts. */ + +void interface_note_activity(void) +{ + ifinfo_t ifinfo; + + sleep(3); /* allow some time for the link to quiesce */ + + /* get the current I/O stats for the monitored link */ + if (monitor && get_ifinfo(monitor, &ifinfo)) + monitor_io = ifinfo.rx_packets + ifinfo.tx_packets; +} + +/* Return TRUE if OK to poll, FALSE otherwise. */ + +int interface_approve(void) +{ + ifinfo_t ifinfo; + + /* check interface IP address (range), if specified */ + if (interface) { + /* get interface info */ + if (!get_ifinfo(interface, &ifinfo)) { + fprintf(stderr, "fetchmail: skipping poll, %s down\n", + interface); + return(FALSE); + } + /* check the IP address (range) */ + if ((ifinfo.addr.s_addr & interface_mask.s_addr) != + interface_address.s_addr) { + fprintf(stderr, + "fetchmail: skipping poll, %s IP address excluded\n", + interface); + return(FALSE); + } + } + + /* if monitoring, check link for activity if it is up */ + if (monitor && get_ifinfo(monitor, &ifinfo) && + monitor_io == ifinfo.rx_packets + ifinfo.tx_packets) { + fprintf(stderr, "fetchmail: skipping poll, %s inactive\n", + monitor); + return(FALSE); + } + + return(TRUE); +} +#endif /* linux */ -- cgit v1.2.3