diff options
-rw-r--r-- | NEWS | 9 | ||||
-rw-r--r-- | fetchmail.c | 173 | ||||
-rw-r--r-- | fetchmail.h | 16 | ||||
-rw-r--r-- | fetchmail.man | 14 | ||||
-rw-r--r-- | interface.c | 86 | ||||
-rw-r--r-- | options.c | 4 | ||||
-rw-r--r-- | rcfile_y.y | 16 | ||||
-rw-r--r-- | sample.rcfile | 16 |
8 files changed, 153 insertions, 181 deletions
@@ -1,13 +1,12 @@ - To Do: - -Try to change the daemon-mode loop so the poll comes before the wait, -not after it. - Release Notes: ------------------------------------------------------------------------------ fetchmail-2.9 () +features -- + +* `interface' and `monitor' options are now per-server. + bugs -- * Stricter parsing of greeting message for the host name; eliminates some diff --git a/fetchmail.c b/fetchmail.c index 529f18ec..d0865dcf 100644 --- a/fetchmail.c +++ b/fetchmail.c @@ -61,10 +61,6 @@ int check_only; /* if --probe was set */ int cmd_batchlimit; /* if --batchlimit was set */ int cmd_fetchlimit; /* if --fetchlimit was set */ char *cmd_logfile; /* if --logfile was set */ -char *interface; /* interface required specification */ -char *cmd_interface; /* if --interface was set */ -char *monitor; /* monitored interface for activity */ -char *cmd_monitor; /* if --monitor was set */ /* miscellaneous global controls */ char *rcfile; /* path name of rc file */ @@ -178,16 +174,6 @@ int main (int argc, char **argv) printf("SMTP message batch limit is %d.\n", batchlimit); else if (outlevel == O_VERBOSE) printf("No SMTP message batch limit.\n"); -#ifdef linux - if (interface) - printf("TCP/IP interface requirements for %s.\n", interface); - else if (outlevel == O_VERBOSE) - printf("No TCP/IP interface requirements specified.\n"); - if (monitor) - printf("Polling loop will monitor %s.\n", monitor); - else if (outlevel == O_VERBOSE) - printf("No monitor interface specified.\n"); -#endif for (ctl = querylist; ctl; ctl = ctl->next) { if (ctl->active && !(implicitmode && ctl->server.skip)) dump_params(ctl); @@ -374,69 +360,6 @@ int main (int argc, char **argv) * reflect the status of that transaction. */ do { - if (poll_interval) - { -#ifdef linux - if (monitor) - { - /* - * Allow some time for the link to quiesce. - * Note: this delay is important! Don't remove it casually! - */ - sleep(3); - interface_note_activity(); - } -#endif - if (outlevel == O_VERBOSE) - { - time_t now; - - time(&now); - fprintf(stderr, "fetchmail: sleeping at %s", ctime(&now)); - } - - /* - * We can't use sleep(3) here because we need an alarm(3) - * equivalent in order to implement server nonresponse timeout. - * We'll just assume setitimer(2) is available since fetchmail - * has to have a BSDoid socket layer to work at all. - */ - { - struct itimerval ntimeout; - - ntimeout.it_interval.tv_sec = ntimeout.it_interval.tv_usec = 0; - ntimeout.it_value.tv_sec = poll_interval; - ntimeout.it_value.tv_usec = 0; - - setitimer(ITIMER_REAL,&ntimeout,NULL); - signal(SIGALRM, donothing); - pause(); - signal(SIGALRM, SIG_IGN); - if (lastsig == SIGUSR1 - || ((poll_interval && !getuid()) && lastsig == SIGHUP)) - { -#ifdef SYS_SIGLIST_DECLARED - error(0, 0, "awakened by %s", sys_siglist[lastsig]); -#else - error(0, 0, "awakened by signal %d", lastsig); -#endif - } - } - - if (outlevel == O_VERBOSE) - { - time_t now; - - time(&now); - fprintf(stderr, "fetchmail: awakened at %s", ctime(&now)); - } - } - -#ifdef linux - if (!interface_approve()) - continue; -#endif - #ifdef HAVE_RES_SEARCH sethostent(TRUE); /* use TCP/IP for mailserver queries */ #endif /* HAVE_RES_SEARCH */ @@ -446,6 +369,12 @@ int main (int argc, char **argv) { if (ctl->active && !(implicitmode && ctl->server.skip)) { +#ifdef linux + /* interface_check does its own error logging */ + if (!interface_check(&ctl->server)) + continue; +#endif /* linux */ + #ifdef HAVE_GETHOSTBYNAME /* * This functions partly as an optimization and partly @@ -508,6 +437,56 @@ int main (int argc, char **argv) fclose(ctl->smtp_sockfp); ctl->smtp_sockfp = (FILE *)NULL; } + + /* + * OK, we've polled. Now sleep. + */ + if (poll_interval) + { + if (outlevel == O_VERBOSE) + { + time_t now; + + time(&now); + fprintf(stderr, "fetchmail: sleeping at %s", ctime(&now)); + } + + /* + * We can't use sleep(3) here because we need an alarm(3) + * equivalent in order to implement server nonresponse timeout. + * We'll just assume setitimer(2) is available since fetchmail + * has to have a BSDoid socket layer to work at all. + */ + { + struct itimerval ntimeout; + + ntimeout.it_interval.tv_sec = ntimeout.it_interval.tv_usec = 0; + ntimeout.it_value.tv_sec = poll_interval; + ntimeout.it_value.tv_usec = 0; + + setitimer(ITIMER_REAL,&ntimeout,NULL); + signal(SIGALRM, donothing); + pause(); + signal(SIGALRM, SIG_IGN); + if (lastsig == SIGUSR1 + || ((poll_interval && !getuid()) && lastsig == SIGHUP)) + { +#ifdef SYS_SIGLIST_DECLARED + error(0, 0, "awakened by %s", sys_siglist[lastsig]); +#else + error(0, 0, "awakened by signal %d", lastsig); +#endif + } + } + + if (outlevel == O_VERBOSE) + { + time_t now; + + time(&now); + fprintf(stderr, "fetchmail: awakened at %s", ctime(&now)); + } + } } while (poll_interval); @@ -649,6 +628,11 @@ static int load_params(int argc, char **argv, int optind) if (ctl->server.envelope == (char *)NULL) ctl->server.envelope = "X-Envelope-To:"; +#ifdef linux + /* interface_check does its own error logging */ + interface_parse(&ctl->server); +#endif /* linux */ + /* sanity checks */ if (ctl->server.port < 0) { @@ -674,31 +658,6 @@ static int load_params(int argc, char **argv, int optind) if (cmd_logfile) logfile = cmd_logfile; - /* if cmd_interface was explicitly set, use it to override interface */ - if (cmd_interface) - interface = cmd_interface; - - /* if cmd_monitor was explicitly set, use it to override monitor */ - if (cmd_monitor) - monitor = cmd_monitor; - - if (interface) -#ifdef linux - interface_parse(); -#else - { - (void) fprintf(stderr, - "interface specification supported only on Linux\n"); - exit(PS_SYNTAX); - } - if (monitor) - { - (void) fprintf(stderr, - "monitor supported only on Linux\n"); - exit(PS_SYNTAX); - } -#endif - return(implicitmode); } @@ -904,6 +863,16 @@ void dump_params (struct query *ctl) if (count > 1) printf(" Envelope header is assumed to be: %s\n", ctl->server.envelope); } +#ifdef linux + if (ctl->server.interface) + printf("TCP/IP interface requirements for %s.\n", ctl->server.interface); + else if (outlevel == O_VERBOSE) + printf("No TCP/IP interface requirements specified.\n"); + if (ctl->server.monitor) + printf("Polling loop will monitor %s.\n", ctl->server.monitor); + else if (outlevel == O_VERBOSE) + printf("No monitor interface specified.\n"); +#endif if (ctl->server.protocol > P_POP2) if (!ctl->oldsaved) diff --git a/fetchmail.h b/fetchmail.h index d969945c..b7f64fff 100644 --- a/fetchmail.h +++ b/fetchmail.h @@ -68,6 +68,13 @@ struct hostdata /* shared among all user connections to given server */ char *envelope; int skip; +#ifdef linux + char *interface; + char *monitor; + int monitor_io; + struct ipair *inter; +#endif /* linux */ + /* computed for internal use */ #ifdef HAVE_GETHOSTBYNAME char *canonical_name; /* DNS canonical name of server host */ @@ -150,10 +157,6 @@ extern int quitmode; /* if --quit was set */ extern int check_only; /* if --check was set */ extern int cmd_batchlimit; /* if --batchlimit was set */ extern char *cmd_logfile; /* if --logfile was set */ -extern char *interface; /* interface required specification */ -extern char *cmd_interface; /* if --interface was set */ -extern char *monitor; /* monitored interface for activity */ -extern char *cmd_monitor; /* if --monitor was set */ /* these get computed */ extern int batchlimit; /* if --batchlimit was set */ @@ -219,9 +222,8 @@ int daemonize(const char *, void (*)(int)); int prc_parse_file(const char *); int prc_filecheck(const char *); -void interface_parse(void); -void interface_note_activity(void); -int interface_approve(void); +void interface_parse(struct hostdata *); +int interface_check(struct hostdata *); char *getpassword(char *); diff --git a/fetchmail.man b/fetchmail.man index 0460dc8a..db92a7a0 100644 --- a/fetchmail.man +++ b/fetchmail.man @@ -544,6 +544,8 @@ Legal server options are: timeout envelope aka + interface + monitor Legal user options are @@ -650,13 +652,11 @@ or reverse it by saying `user esr here is eric there' .PP For backward compatibility, the word `server' is a synonym for `poll'. .PP -There are currently four valid global option statements; -\&`set batchlimit = ' followed by a number and sets the same global -specified by the --batchlimit option, `set logfile = ' followed by a -string sets the same global specified by --logfile, `set interface = ' -followed by a string sets the same global specified by --interface, and -`set monitor = ' followed by a string sets the same global specified by ---monitor. In all cases, a command-line option will override. +There are currently two valid global option statements; \&`set +batchlimit = ' followed by a number and sets the same global specified +by the --batchlimit option, and `set logfile = ' followed by a string +sets the same global specified by --logfile. In both cases, a +command-line option will override. .PP Basic format is: diff --git a/interface.c b/interface.c index dce5267e..abfe2e6d 100644 --- a/interface.c +++ b/interface.c @@ -21,16 +21,16 @@ #include <linux/netdevice.h> #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; +struct ipair { + struct in_addr interface_address; + struct in_addr interface_mask; +}; + /* Get active network interface information. Return non-zero upon success. */ static int _get_ifinfo_(int socket_fd, FILE *stats_file, const char *ifname, @@ -99,34 +99,27 @@ static int get_ifinfo(const char *ifname, ifinfo_t *ifinfo) return(result); } -/* Parse 'interface' specification. */ - -void interface_parse(void) +void interface_parse(struct hostdata *hp) +/* parse 'interface' specification. */ { - int socket_fd = socket(AF_INET, SOCK_DGRAM, 0); + int socket_fd; char *cp1, *cp2; struct ifreq request; - /* 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; + if (!hp->interface) + return; /* find and isolate just the IP address */ - if (!(cp1 = strchr(interface, '/'))) + if (!(cp1 = strchr(hp->interface, '/'))) (void) error(PS_SYNTAX, 0, "missing IP interface address"); *cp1++ = '\000'; /* validate specified interface exists */ - strcpy(request.ifr_name, interface); + strcpy(request.ifr_name, hp->interface); + socket_fd = socket(AF_INET, SOCK_DGRAM, 0); if (ioctl(socket_fd, SIOCGIFFLAGS, &request) < 0) (void) error(PS_SYNTAX, 0, "no such interface device '%s'", - interface); + hp->interface); close(socket_fd); /* find and isolate just the netmask */ @@ -136,57 +129,52 @@ void interface_parse(void) *cp2++ = '\000'; /* convert IP address and netmask */ - if (!inet_aton(cp1, &interface_address)) + hp->inter = xmalloc(sizeof(struct ipair)); + if (!inet_aton(cp1, &hp->inter->interface_address)) (void) error(PS_SYNTAX, 0, "invalid IP interface address"); - if (!inet_aton(cp2, &interface_mask)) + if (!inet_aton(cp2, &hp->inter->interface_mask)) (void) error(PS_SYNTAX, 0, "invalid IP interface mask"); /* apply the mask now to the IP address (range) required */ - interface_address.s_addr &= interface_mask.s_addr; + hp->inter->interface_address.s_addr &= hp->inter->interface_mask.s_addr; return; } -/* Save interface I/O counts. */ - -void interface_note_activity(void) -{ - ifinfo_t ifinfo; - - /* 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) +int interface_check(struct hostdata *hp) +/* return TRUE if OK to poll, FALSE otherwise */ { ifinfo_t ifinfo; /* check interface IP address (range), if specified */ - if (interface) { + if (hp->interface) { /* get interface info */ - if (!get_ifinfo(interface, &ifinfo)) { - (void) error(0, 0, "skipping poll, %s down", - interface); + if (!get_ifinfo(hp->interface, &ifinfo)) { + (void) error(0, 0, "skipping poll of %s, %s down", + hp->names->id, hp->interface); return(FALSE); } /* check the IP address (range) */ - if ((ifinfo.addr.s_addr & interface_mask.s_addr) != - interface_address.s_addr) { + if ((ifinfo.addr.s_addr & hp->inter->interface_mask.s_addr) != + hp->inter->interface_address.s_addr) { (void) error(0, 0, - "skipping poll, %s IP address excluded", - interface); + "skipping poll of %s, %s IP address excluded", + hp->names->id, hp->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) { - (void) error(0, 0, "skipping poll, %s inactive", monitor); + if (hp->monitor && get_ifinfo(hp->monitor, &ifinfo) && + hp->monitor_io == ifinfo.rx_packets + ifinfo.tx_packets) { + (void) error(0, 0, + "skipping poll of %s, %s inactive", + hp->names->id, hp->monitor); return(FALSE); } + /* get the current I/O stats for the monitored link */ + if (hp->monitor && get_ifinfo(hp->monitor, &ifinfo)) + hp->monitor_io = ifinfo.rx_packets + ifinfo.tx_packets; + return(TRUE); } #endif /* linux */ @@ -268,11 +268,11 @@ struct query *ctl; /* option record to be initialized */ #ifdef linux case 'I': case LA_INTERFACE: - cmd_interface = optarg; + ctl->server.interface = xstrdup(optarg); break; case 'M': case LA_MONITOR: - cmd_monitor = optarg; + ctl->server.monitor = xstrdup(optarg); break; #endif @@ -68,8 +68,6 @@ statement_list : statement /* future global options should also have the form SET <name> <value> */ statement : SET BATCHLIMIT MAP NUMBER {batchlimit = $4;} | SET LOGFILE MAP STRING {logfile = xstrdup($4);} - | SET INTERFACE MAP STRING {interface = xstrdup($4);} - | SET MONITOR MAP STRING {monitor = xstrdup($4);} /* * The way the next two productions are written depends on the fact that @@ -117,6 +115,20 @@ serv_option : AKA alias_list | AUTHENTICATE KERBEROS {current.server.authenticate = A_KERBEROS;} | TIMEOUT NUMBER {current.server.timeout = $2;} | ENVELOPE STRING {current.server.envelope = xstrdup($2);} + | INTERFACE STRING { +#ifdef linux + current.server.interface = xstrdup($2); +#else + fprintf(stderr, "fetchmail: interface option is only supported under Linux\n"); +#endif /* linux */ + } + | MONITOR STRING { +#ifdef linux + current.server.monitor = xstrdup($2); +#else + fprintf(stderr, "fetchmail: monitor option is only supported under Linux\n"); +#endif /* linux */ + } ; /* diff --git a/sample.rcfile b/sample.rcfile index d9822f01..c6da6f4b 100644 --- a/sample.rcfile +++ b/sample.rcfile @@ -28,6 +28,8 @@ # envelope -- must be followed by an envelope header name # aka -- must be followed by one or more server aliases # localdomains -- must be followed by one or more domain names +# interface -- must be followed by device/IP address/mask +# monitor -- must be followed by IP address # # username (or user) -- must be followed by a name # is -- must be followed by one or more names @@ -63,8 +65,6 @@ # # set batchlimit = -- must be followed by a number # set logfile = -- must be followed by a string -# set interface = -- must be followed by IP address -# set monitor = -- must be followed by IP address # # The noise keywords `and', `with', `has', `wants', and `options' are ignored # anywhere in an entry; they can be used to make it resemble English. The @@ -76,18 +76,20 @@ # This is what the developer's .fetchmailrc looks like: set batchlimit = 0 # I forward to sendmail -set interface = sl0/10.0.2.15 # SLIRP's default IP address -defaults password not_blowing_my_cover; +defaults + interface "sl0/10.0.2.15" # SLIRP standard address + user esr is esr fetchmail-friends magic-numbers here + fetchall # Use this for production poll locke.ccil.org with protocol APOP: - user esr there with password my_apop_secret is esr here; + password my_apop_secret; # Use this to test IMAP skip locke protocol IMAP: - user esr here is esr there; + password my_remote_password; # Use this to test against POP2 using a local server skip localhost protocol pop2: - user esr here is esr there; + password my_local_password; |