From d2564d25e802d1ee3230cf045c4940e836b5c6a2 Mon Sep 17 00:00:00 2001 From: John Denker Date: Sun, 29 Jul 2012 16:50:11 -0700 Subject: split ltgrey (and libltgrey) off from greylist; put some utility functions into their own file. --- tools/libltgrey.c | 343 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 343 insertions(+) create mode 100644 tools/libltgrey.c (limited to 'tools/libltgrey.c') diff --git a/tools/libltgrey.c b/tools/libltgrey.c new file mode 100644 index 0000000..d4ec0da --- /dev/null +++ b/tools/libltgrey.c @@ -0,0 +1,343 @@ +#include /* for exit(), getenv() */ +#include +#include +#include + +#include /* for stat(), getaddrinfo() */ +#include /* for stat() */ +#include /* for stat() */ +#include /* for perror */ +#include /* for ENOENT */ +#include /* for ofstream() */ +#include /* for creat() */ +#include /* for gettimeofday() */ +#include /* for stringstream */ +#include /* for kill(), SIGUSR1 */ + +// requires apt-get install libboost-filesystem-dev: +#include + +#include /* for getaddrinfo() */ +#include /* for getaddrinfo() */ +#include /* for memset() */ +#include /* for inet_ntop() */ + +using namespace std; + +const int minute(60); +const int hour(60*minute); +const int day(24*hour); + +const int minimum_age(15*minute); +const int maximum_age(32*day); +const int probation(4*hour); + +#if 0 +void exeunt(const int sts){ + if (sts == ex_good) exit(sts); + +#ifndef PENALIZE_SPAMMERS + if (sts == ex_penaltybox) exit(sts); +#endif + +#ifndef KILL_GROUP + exit(sts); +#endif + + const char* foo = getenv("HI_Q_GROUP"); + if (!foo) exit(sts); + +// No point in signalling ourself: + sighandler_t rslt = signal(SIGUSR1, SIG_IGN); + if (rslt == SIG_ERR) { + cerr << "error setting signal" << endl; + } + int k = kill(-atoi(foo), SIGUSR1); + if (k) { + cerr << "kill failed on group " << atoi(foo) << " ... "; + perror(0); + } + exit(sts); +} +#endif + +#include /* for gettimeofday */ +#include /* for setw */ +#include /* for stat */ +#include /* for stat, creat */ +#include /* for stat, creat */ +#include /* for creat */ +#include /* for ofstream() */ + +#include "libltgrey.h" +#include "utils.h" +#include "qq_exit_codes.h" + +void whatsit::dump(const string var){ + char* str = getenv(var.c_str()); + cerr << progname + << "[" << mypid << "] " + << var; + if (str) cerr << " is set to '" << str << "'" << endl; + else cerr << " is not set." << endl; +} + +int whatsit::setup(){ + stringstream foo; + foo << basename(progname) << suffix + << "[" << mypid << "]"; + progid = foo.str(); + + ipvar = getenv("TCPREMOTEIP"); + if (ipvar) ipbase = ipvar; + hostvar = getenv("TCPREMOTEHOST"); + if (hostvar) hostname = hostvar; + return 0; +} + +void whatsit::update(const string msg, const timeval new_mod, + const timeval new_ac, const int penalty, const int stain){ + if (verbosity){ + if (penalty || stain || verbosity>1) cerr << progid << ": "; + if (penalty) cerr << " penalty " << penalty; + if (stain) cerr << " stain " << stain; + if (verbosity > 1) { + if (penalty || stain) cerr << "+"; // separation, punctuation + cerr << msg << ": " << ipbase; + if (hostname.length()) cerr << " " << hostname; + cerr << " mod_age: " << time_out(mod_age) + << " ac_age: " << time_out(ac_age); + } + cerr << endl; + } + timeval pen_mod(new_mod); + timeval stain_ac(new_ac); + if (penalty) { + pen_mod = now; + pen_mod.tv_sec += penalty; + } + if (stain) { + stain_ac = now; + stain_ac.tv_sec -= stain; + } + timeval upd[2] = { +// beware: access illogically comes *before* modification here: + stain_ac, + pen_mod + }; + if (utimes(ipname.c_str(), upd)) + cerr << "oops" << endl; +} + +int whatsit::doit(const int penalty, const int stain){ + + if (!ipvar) { + cerr << progid + << " TCPREMOTEIP not set???" << endl; + // should never happen + // although you can make it happen using a weird test-harness + return(ex_syserr); + } + +// see if our directory exists: + struct stat dirstat; + int rslt = stat(dirname.c_str(), &dirstat); + if (rslt != 0){ + if (errno != ENOENT) { + cerr << progid << ": stat failed for '" + << dirname << "' : "; + perror(0); + } + rslt = mkdir(dirname.c_str(), 0755); + if (rslt != 0) { + cerr << progid + << "uid " << getuid() + << ": mkdir failed for '" + << dirname << "' : "; + perror(0); + return(ex_syserr); + } + } + + ipname = dirname + "/" + ipbase; + struct stat ipstat; + rslt = stat(ipname.c_str(), &ipstat); + if (rslt != 0){ + if (errno != ENOENT) { + cerr << progid << ": stat failed for '" + << ipname << "' : "; + perror(0); + } + ofstream foo; + int fd = creat(ipname.c_str(), 0644); + if (fd < 0){ + cerr << progid << ": create failed for '" + << ipname << "' : "; + perror(0); + } + close(fd); + update("new customer", now, now, penalty, stain); + return(ex_greylisting); + } + +// now for really checking the greylist status: + mod_age = now.tv_sec - ipstat.st_mtime; + ac_age = now.tv_sec - ipstat.st_atime; + timeval mod_orig = {ipstat.st_mtime, 0}; + if (mod_age < 0) { + update("penalty box", mod_orig, now, penalty, stain); + return(ex_penaltybox); + } + if (mod_age < ac_age){ +// when he comes out on parole, he starts over with no reputation: + update("paroled spammer", now, now, penalty, stain); + return(ex_greylisting); + } + if (mod_age < minimum_age) { + update("early bird", mod_orig, now, penalty, stain); + return(ex_greylisting); + } + if (mod_age - ac_age < minimum_age // early bird, or completely unused + && mod_age > probation) { // did not diligently resubmit + update("disprobation", now, now, penalty, stain); + return(ex_greylisting); + } + if (ac_age > maximum_age) { + update("too old, starting over", now, now, penalty, stain); + return(ex_greylisting); + } +// if all checks are passed, must be OK: + update("returning customer", mod_orig, now, penalty, stain); + return 0; +} + +typedef vector VU; + +class VUx{ +public: + VU addr; + sa_family_t fam; + string str(); +}; + +string VUx::str(){ + char msgbuf[INET6_ADDRSTRLEN]; + const char* rslt = inet_ntop(fam, &addr[0], + msgbuf, sizeof(msgbuf)); + if (!rslt) rslt = ""; + return rslt; +} + +VUx parse_sockaddr(const sockaddr* ai_addr) { + void* numericAddress; + VUx rslt; + int addrsize; + rslt.addr = VU(0); + rslt.fam = ((sockaddr *)ai_addr)->sa_family; + switch (rslt.fam) { + case AF_INET: + numericAddress = &(((sockaddr_in *)ai_addr)->sin_addr.s_addr); + addrsize = sizeof(in_addr); + break; + case AF_INET6: + numericAddress = &(((sockaddr_in6 *)ai_addr)->sin6_addr.s6_addr); + addrsize = sizeof(in6_addr); + break; + default: + cerr << "?Unknown address family " << rslt.fam << endl; + return rslt; + } + unsigned char* foo = (unsigned char*) numericAddress; + rslt.addr = VU(foo, foo+addrsize); + return rslt; +} + +int diff(const VU aaa, const VU bbb){ + if(aaa.size() != bbb.size()) return 1; + for (unsigned int ii=0; ii < aaa.size(); ii++){ + if (aaa[ii] != bbb[ii]) return 1; + } + return 0; +} + +int whatsit::check_dns(){ + string addr("()"), host("()"); + vector checked; + int sts = check_dns_sub(addr, host, checked); + if (sts == 0) return sts; + if (sts != ex_badDNS) return sts; // possible ex_syserr +#if 1 + sts = 0; // demote badDNS to just a warning +#endif + cerr << progid; + if (!sts) cerr << " (warning)"; + cerr << " DNS inconsistency: " + << addr << " --> " + << host << " ==>"; + if (!checked.size()) cerr << " ()"; + else for (vector::const_iterator chk = checked.begin(); + chk != checked.end(); chk++) cerr << " " << *chk; + cerr << endl; + + return sts; +} + +int whatsit::check_dns_sub(string &addr, string &host, vector &checked){ + + struct addrinfo *result; + struct addrinfo *ipresult; + struct addrinfo *res; + addrinfo hints; + int error; + + memset(&hints, 0, sizeof(struct addrinfo)); +#if 1 + // restrict to TCP only; otherwise we get N records per address + hints.ai_protocol = IPPROTO_TCP; +#endif + + error = getaddrinfo(ipvar, NULL, &hints, &ipresult); + if (error == EAI_NONAME) return ex_badDNS; + if (error) { // some unexpected error + cerr << progid + << " odd error " << error + << " in getaddrinfo for " << ipvar + << " : " << gai_strerror(error) << endl; + return ex_syserr; + } + if (!ipresult) { + cerr << "should never happen (addr with no addrs?)" << endl; + return ex_syserr; + } + VUx ipAddr = parse_sockaddr(ipresult->ai_addr); + addr = ipAddr.str(); + + char* hostvar = getenv("TCPREMOTEHOST"); + if (hostvar) host = hostvar; + else return(ex_badDNS); + + error = getaddrinfo(hostvar, NULL, &hints, &result); + if (error == EAI_NONAME) return ex_badDNS; + if (error) { + cerr << progid + << " error " << error + << " compare " << EAI_NONAME + << " in getaddrinfo for " << ipvar + << " :: " << gai_strerror(error) << endl; + return ex_syserr; + } + +// loop over all returned results and check for a match. + for (res = result; res != NULL; res = res->ai_next){ + VUx hostAddr = parse_sockaddr(res->ai_addr); + checked.push_back(hostAddr.str()); + if (!diff(hostAddr.addr, ipAddr.addr)) { + ///// cerr << "match! " << ipAddr.addr.size() << endl; + goto done; + } + } + return ex_badDNS; + +done: + return 0; +} -- cgit v1.2.3 From 292a76b35fd16cf11613f79ea38693449e3317f6 Mon Sep 17 00:00:00 2001 From: John Denker Date: Sun, 29 Jul 2012 21:07:01 -0700 Subject: separate dnscheck functionality from other features; clean up a little --- tools/libltgrey.c | 136 ++++++++++++++++++++++++++++++++++++++---------------- tools/libltgrey.h | 23 +++------ tools/ltgrey.c | 43 +++++++++++------ 3 files changed, 132 insertions(+), 70 deletions(-) (limited to 'tools/libltgrey.c') diff --git a/tools/libltgrey.c b/tools/libltgrey.c index d4ec0da..1bf7e9f 100644 --- a/tools/libltgrey.c +++ b/tools/libltgrey.c @@ -73,6 +73,15 @@ void exeunt(const int sts){ #include "utils.h" #include "qq_exit_codes.h" +// constructor +whatsit::whatsit(const std::string name, const std::string _parent_dir) +: parent_dir(_parent_dir), progname(name), mypid(getpid()), + mod_age(0), ac_age(0), + verbosity(0) +{ + gettimeofday(&now, NULL); +} + void whatsit::dump(const string var){ char* str = getenv(var.c_str()); cerr << progname @@ -88,13 +97,14 @@ int whatsit::setup(){ << "[" << mypid << "]"; progid = foo.str(); - ipvar = getenv("TCPREMOTEIP"); - if (ipvar) ipbase = ipvar; - hostvar = getenv("TCPREMOTEHOST"); - if (hostvar) hostname = hostvar; return 0; } +#if 1 +void whatsit::update(const string msg, const timeval new_mod, + const timeval new_ac, const int penalty, const int stain){ +} +#else void whatsit::update(const string msg, const timeval new_mod, const timeval new_ac, const int penalty, const int stain){ if (verbosity){ @@ -128,36 +138,51 @@ void whatsit::update(const string msg, const timeval new_mod, if (utimes(ipname.c_str(), upd)) cerr << "oops" << endl; } +#endif -int whatsit::doit(const int penalty, const int stain){ - - if (!ipvar) { - cerr << progid - << " TCPREMOTEIP not set???" << endl; - // should never happen - // although you can make it happen using a weird test-harness - return(ex_syserr); - } - +int whatsit::maybe_mkdir(const string somedir, const string msg){ // see if our directory exists: struct stat dirstat; - int rslt = stat(dirname.c_str(), &dirstat); + int rslt = stat(somedir.c_str(), &dirstat); if (rslt != 0){ if (errno != ENOENT) { - cerr << progid << ": stat failed for '" - << dirname << "' : "; + cerr << progid << " stat failed for " + << msg + << " '" << somedir << "' : "; perror(0); } - rslt = mkdir(dirname.c_str(), 0755); + rslt = mkdir(somedir.c_str(), 0755); if (rslt != 0) { cerr << progid << "uid " << getuid() - << ": mkdir failed for '" - << dirname << "' : "; + << " mkdir failed for " + << msg + << "' " << somedir << "' : "; perror(0); return(ex_syserr); } } + return 0; +} + +#if 1 +int whatsit::doit(const int penalty, const int stain){ + return ex_syserr; +} + +#else +int whatsit::doit(const int penalty, const int stain){ + if (!ipvar) { + cerr << progid + << " TCPREMOTEIP not set???" << endl; + // should never happen + // although you can make it happen using a weird test-harness + return(ex_syserr); + } + + maybe_mkdir(parent_dir, "parent dir"); + maybe_mkdir(parent_dir + "/quarante", "quarantine dir"); + maybe_mkdir(parent_dir + "/repute", "reputation dir"); ipname = dirname + "/" + ipbase; struct stat ipstat; @@ -210,6 +235,7 @@ int whatsit::doit(const int penalty, const int stain){ update("returning customer", mod_orig, now, penalty, stain); return 0; } +#endif typedef vector VU; @@ -260,29 +286,35 @@ int diff(const VU aaa, const VU bbb){ return 0; } -int whatsit::check_dns(){ +int whatsit::check_dns(const char* ipvar, const char* namevar){ + if (!ipvar) { + cerr << progid << " check_dns: no addr specified." << endl; + return ex_syserr; + } string addr("()"), host("()"); vector checked; - int sts = check_dns_sub(addr, host, checked); - if (sts == 0) return sts; - if (sts != ex_badDNS) return sts; // possible ex_syserr + int rslt = check_dns_sub(ipvar, namevar, addr, host, checked); + int sts = rslt; #if 1 sts = 0; // demote badDNS to just a warning #endif - cerr << progid; - if (!sts) cerr << " (warning)"; - cerr << " DNS inconsistency: " - << addr << " --> " - << host << " ==>"; - if (!checked.size()) cerr << " ()"; - else for (vector::const_iterator chk = checked.begin(); - chk != checked.end(); chk++) cerr << " " << *chk; - cerr << endl; - + if (rslt || verbosity) { + cerr << progid; + if (rslt && !sts) cerr << " (warning)"; + if (rslt) cerr << " DNS inconsistency: "; + else cerr << " DNS OK: "; + cerr << addr << " --> " + << host << " ==>"; + if (!checked.size()) cerr << " ()"; + else for (vector::const_iterator chk = checked.begin(); + chk != checked.end(); chk++) cerr << " " << *chk; + cerr << endl; + } return sts; } -int whatsit::check_dns_sub(string &addr, string &host, vector &checked){ +int whatsit::check_dns_sub(const char* ipvar, const char* namevar, + string &addr, string &host, vector &checked){ struct addrinfo *result; struct addrinfo *ipresult; @@ -296,6 +328,8 @@ int whatsit::check_dns_sub(string &addr, string &host, vector &checked){ hints.ai_protocol = IPPROTO_TCP; #endif +// convert address-as-string to address-as-bits. +// also get information about family error = getaddrinfo(ipvar, NULL, &hints, &ipresult); if (error == EAI_NONAME) return ex_badDNS; if (error) { // some unexpected error @@ -309,14 +343,38 @@ int whatsit::check_dns_sub(string &addr, string &host, vector &checked){ cerr << "should never happen (addr with no addrs?)" << endl; return ex_syserr; } + +// reconvert from bits to string + family info VUx ipAddr = parse_sockaddr(ipresult->ai_addr); addr = ipAddr.str(); - char* hostvar = getenv("TCPREMOTEHOST"); - if (hostvar) host = hostvar; - else return(ex_badDNS); + if (namevar) { + // inverse lookup already done + host = namevar; + } else { + // namevar not specified; do inverse lookup on our own + + char hostname[NI_MAXHOST] = ""; + char service[NI_MAXHOST] = ""; + +#ifdef convert_bits_to_string + const char* rslt = inet_ntop(ipAddr.fam, &ipAddr.addr[0], + msgbuf, sizeof(msgbuf)); + if (rslt) fprintf(stdout, "%s addrsize: %2d --> ", + msgbuf, addrsize); +#endif + error = getnameinfo(ipresult->ai_addr, ipresult->ai_addrlen, + hostname, NI_MAXHOST, service, NI_MAXHOST, 0); + if (error != 0) { + cerr << progid << " reverse DNS lookup failed: " + << gai_strerror(error) << endl; + return (ex_badDNS); + } + namevar = hostname; // a char*, used below + host = hostname; // a string, returned to caller + } - error = getaddrinfo(hostvar, NULL, &hints, &result); + error = getaddrinfo(namevar, NULL, &hints, &result); if (error == EAI_NONAME) return ex_badDNS; if (error) { cerr << progid diff --git a/tools/libltgrey.h b/tools/libltgrey.h index 585ec01..6f516b4 100644 --- a/tools/libltgrey.h +++ b/tools/libltgrey.h @@ -4,35 +4,26 @@ class whatsit{ public: - std::string dirname; + std::string parent_dir; std::string progname; pid_t mypid; timeval now; - char* ipvar; - char* hostvar; - std::string ipbase; - std::string ipname; - std::string hostname; int mod_age; int ac_age; std::string suffix; std::string progid; int verbosity; - whatsit(const std::string name, const std::string _dirname) - : dirname(_dirname), progname(name), mypid(getpid()), - mod_age(0), ac_age(0), - verbosity(0) - { - gettimeofday(&now, NULL); - } + whatsit(const std::string name, const std::string _parent_dir); int doit(const int penalty, const int stain); // access comes after modification: void update(const std::string msg, const timeval new_mod, const timeval new_ac, const int penalty, const int stain); int setup(); - int check_dns(); - int check_dns_sub(std::string &addr, std::string &host, - std::vector &checked); + int check_dns(const char* ipvar, const char* namevar); + int check_dns_sub(const char* ipvar, const char* namevar, + std::string &addr, std::string &host, + std::vector &checked); void dump(const std::string var); + int maybe_mkdir(const std::string somedir, const std::string msg); }; diff --git a/tools/ltgrey.c b/tools/ltgrey.c index afdb4c1..c9f384f 100644 --- a/tools/ltgrey.c +++ b/tools/ltgrey.c @@ -14,17 +14,24 @@ string progname; // forward reference: void scan(const string progid, const string p, const int copies=1); + int main(int _argc, char** _argv){ + char* namevar; + std::string hostname; + char* ipvar; + std::string ipbase; + std::string ipname; + mypid = getpid(); int argc(_argc); char** argv(_argv); - const string dirname("/var/qmail/greylist"); - whatsit foo(argv[0], dirname); argc--; argv++; + const string parent_dir("/var/qmail/ltgrey"); + whatsit foo(argv[0], parent_dir); argc--; argv++; int scanmode(0); int copies(1); int penalty(0); int stain(0); - int check(0); + int dnscheck(0); while (argc > 0) { string arg = argv[0]; argc--; argv++; if (prefix(arg, "-scan")) { @@ -33,8 +40,8 @@ int main(int _argc, char** _argv){ copies++; } else if (prefix(arg, "-verbose")) { foo.verbosity++; - } else if (prefix(arg, "-check")) { - check++; + } else if (prefix(arg, "-dnscheck")) { + dnscheck++; } else if (prefix(arg, "-penalize") || prefix(arg, "-penalty")) { if (!argc){ @@ -61,23 +68,29 @@ int main(int _argc, char** _argv){ } if (foo.setup()) return ex_syserr; +// dnscheck mode ... +// Probably a better design would be to +// (a) make more thorough DNS checks, and +// (b) move all the DNS checking to a separate module + + ipvar = getenv("TCPREMOTEIP"); + if (ipvar) ipbase = ipvar; + namevar = getenv("TCPREMOTEHOST"); + if (namevar) hostname = namevar; + + if (dnscheck) { + exeunt(foo.check_dns(ipvar, namevar)); + } + if (scanmode) { + string dirname = parent_dir + "/quarante"; scan(foo.progid, dirname, copies); return 0; } int sts = foo.doit(penalty, stain); - if (sts == ex_syserr) return sts; - if (!check) return ex_good; - -// check mode ... perform some extra checks. -// Probably a better design would be to -// (a) make more thorough DNS checks, and -// (b) move all the DNS checking to a separate module + return sts; - int dns = foo.check_dns(); - if (dns == ex_syserr || dns == ex_spam) return dns; - exeunt(sts); } ////////////////////////////////////////////////////////////////////// -- cgit v1.2.3 From 67eb4c6c804c728db329a7f4a77d5a3cbd1b993c Mon Sep 17 00:00:00 2001 From: John Denker Date: Sun, 29 Jul 2012 21:55:41 -0700 Subject: get40 seems to be working --- tools/libltgrey.c | 27 ++++++++++++++++++++++++-- tools/libltgrey.h | 20 ++++++++++++++++--- tools/ltgrey.c | 58 ++++++++++++++++++++++++++++++------------------------- 3 files changed, 74 insertions(+), 31 deletions(-) (limited to 'tools/libltgrey.c') diff --git a/tools/libltgrey.c b/tools/libltgrey.c index 1bf7e9f..38657e3 100644 --- a/tools/libltgrey.c +++ b/tools/libltgrey.c @@ -76,10 +76,12 @@ void exeunt(const int sts){ // constructor whatsit::whatsit(const std::string name, const std::string _parent_dir) : parent_dir(_parent_dir), progname(name), mypid(getpid()), - mod_age(0), ac_age(0), verbosity(0) { - gettimeofday(&now, NULL); +// expand the codes to make some names: +# define foo(name) decode_40[name] = #name; + state_40_macro +# undef foo } void whatsit::dump(const string var){ @@ -399,3 +401,24 @@ int whatsit::check_dns_sub(const char* ipvar, const char* namevar, done: return 0; } + +state_40 whatsit::get40(const string mid){ + string fname = parent_dir + "/quarante/mid_" + mid; + cerr << ".... " << fname << endl; + struct stat mid_stat; + int rslt = stat(fname.c_str(), &mid_stat); + if (rslt != 0) { + if (errno == ENOENT) return unseen; + cerr << progid << " stat: unexpected failure for '" + << fname << "' : "; + perror(0); + return fail; + } + timeval now; + gettimeofday(&now, NULL); + int mod_age = now.tv_sec - mid_stat.st_mtime; +// int ac_age = now.tv_sec - mid_stat.st_atime; + if (mod_age < minimum_age) return young; + if (mod_age < probation) return ripe; + return spoiled; +} diff --git a/tools/libltgrey.h b/tools/libltgrey.h index 6f516b4..1724d53 100644 --- a/tools/libltgrey.h +++ b/tools/libltgrey.h @@ -1,18 +1,31 @@ #include #include /* for gettimeofday(), timeval */ #include +#include + +#define state_40_macro \ +foo(unseen) \ +foo(young) \ +foo(ripe) \ +foo(spoiled) \ +foo(fail) + +// expand the codes to make some names: +#define foo(name) name, +typedef enum { + state_40_macro +} state_40; +#undef foo class whatsit{ public: std::string parent_dir; std::string progname; pid_t mypid; - timeval now; - int mod_age; - int ac_age; std::string suffix; std::string progid; int verbosity; + std::map decode_40; whatsit(const std::string name, const std::string _parent_dir); int doit(const int penalty, const int stain); @@ -26,4 +39,5 @@ public: std::vector &checked); void dump(const std::string var); int maybe_mkdir(const std::string somedir, const std::string msg); + state_40 get40(const std::string mid); }; diff --git a/tools/ltgrey.c b/tools/ltgrey.c index c9f384f..7a63b04 100644 --- a/tools/ltgrey.c +++ b/tools/ltgrey.c @@ -16,10 +16,7 @@ void scan(const string progid, const string p, const int copies=1); int main(int _argc, char** _argv){ - char* namevar; std::string hostname; - char* ipvar; - std::string ipbase; std::string ipname; mypid = getpid(); @@ -29,27 +26,35 @@ int main(int _argc, char** _argv){ whatsit foo(argv[0], parent_dir); argc--; argv++; int scanmode(0); int copies(1); - int penalty(0); + int shift(0); int stain(0); - int dnscheck(0); + int dns_mode(0); + string get40_mid; while (argc > 0) { string arg = argv[0]; argc--; argv++; if (prefix(arg, "-scan")) { scanmode++; - } else if (prefix(arg, "-copy")) { + } else if (prefix(arg, "-copy")) { copies++; - } else if (prefix(arg, "-verbose")) { + } else if (prefix(arg, "-verbose")) { foo.verbosity++; - } else if (prefix(arg, "-dnscheck")) { - dnscheck++; - } else if (prefix(arg, "-penalize") - || prefix(arg, "-penalty")) { + } else if (prefix(arg, "-dns_mode")) { + dns_mode++; + } else if (prefix(arg, "-get40")) { if (!argc){ cerr << "Option '" << arg << "' requires an argument" << endl; exeunt(ex_syserr); } - penalty = atoi(*argv++); argc--; - } else if (prefix(arg, "-stain")) { + get40_mid = *argv++; argc--; + + } else if (prefix(arg, "-shift") + || prefix(arg, "-shift")) { + if (!argc){ + cerr << "Option '" << arg << "' requires an argument" << endl; + exeunt(ex_syserr); + } + shift = atoi(*argv++); argc--; + } else if (prefix(arg, "-stain")) { if (!argc){ cerr << "Option '" << arg << "' requires an argument" << endl; exeunt(ex_syserr); @@ -68,27 +73,28 @@ int main(int _argc, char** _argv){ } if (foo.setup()) return ex_syserr; -// dnscheck mode ... -// Probably a better design would be to -// (a) make more thorough DNS checks, and -// (b) move all the DNS checking to a separate module - - ipvar = getenv("TCPREMOTEIP"); - if (ipvar) ipbase = ipvar; - namevar = getenv("TCPREMOTEHOST"); - if (namevar) hostname = namevar; - - if (dnscheck) { +// dns_mode mode ... +// Probably it would be better to make more thorough DNS checks. +// + if (dns_mode) { + char* ipvar = getenv("TCPREMOTEIP"); + char* namevar = getenv("TCPREMOTEHOST"); exeunt(foo.check_dns(ipvar, namevar)); } + if (get40_mid.length()){ + state_40 rslt = foo.get40(get40_mid); + cerr << foo.decode_40[rslt] << endl; + return 0; + } + if (scanmode) { string dirname = parent_dir + "/quarante"; scan(foo.progid, dirname, copies); return 0; } - int sts = foo.doit(penalty, stain); + int sts = foo.doit(shift, stain); return sts; } @@ -116,7 +122,7 @@ void scan(const string progid, const string p, const int copies){ gettimeofday(&now, NULL); using namespace boost::filesystem; - if (is_directory(p)) { + if (is_directory(p)) { for (directory_iterator itr(p); itr!=directory_iterator(); ++itr) { string basename = itr->path().filename(); for (int ii = 0; ii < copies; ii++) -- cgit v1.2.3 From 2f6fd23b841c1f4e3c18d1cbfd228784aa8c3298 Mon Sep 17 00:00:00 2001 From: John Denker Date: Sun, 29 Jul 2012 22:31:03 -0700 Subject: set40 appears to be working --- tools/libltgrey.c | 47 +++++++++++++++++++++++++++++++++++++++++++++-- tools/libltgrey.h | 3 ++- tools/ltgrey.c | 12 +++++++++++- 3 files changed, 58 insertions(+), 4 deletions(-) (limited to 'tools/libltgrey.c') diff --git a/tools/libltgrey.c b/tools/libltgrey.c index 38657e3..3a60daa 100644 --- a/tools/libltgrey.c +++ b/tools/libltgrey.c @@ -32,6 +32,11 @@ const int minimum_age(15*minute); const int maximum_age(32*day); const int probation(4*hour); +// beware: access illogically comes *before* modification +// in the array passed to utimes: +const int upd_ac(0); +const int upd_mod(1); + #if 0 void exeunt(const int sts){ if (sts == ex_good) exit(sts); @@ -195,7 +200,7 @@ int whatsit::doit(const int penalty, const int stain){ << ipname << "' : "; perror(0); } - ofstream foo; +//???!! ofstream foo; int fd = creat(ipname.c_str(), 0644); if (fd < 0){ cerr << progid << ": create failed for '" @@ -418,7 +423,45 @@ state_40 whatsit::get40(const string mid){ gettimeofday(&now, NULL); int mod_age = now.tv_sec - mid_stat.st_mtime; // int ac_age = now.tv_sec - mid_stat.st_atime; - if (mod_age < minimum_age) return young; + if (mod_age < minimum_age) return green; if (mod_age < probation) return ripe; return spoiled; } + +int whatsit::set40(const string mid, const int shift){ + string fname = parent_dir + "/quarante/mid_" + mid; + cerr << ".... " << fname << endl; + int fd = creat(fname.c_str(), 0644); + if (fd < 0){ + cerr << progid << ": create failed for '" + << fname << "' : "; + perror(0); + } + if (!shift) { + close(fd); + return 0; + } + + struct stat mid_stat; + int rslt = fstat(fd, &mid_stat); + close(fd); + if (rslt != 0) { + cerr << progid << " fstat: unexpected failure for '" + << fname << "' : "; + perror(0); + return ex_syserr; + } + + timeval now; + gettimeofday(&now, NULL); + timeval upd[2] = { + now, // access + now // modification + }; + upd[upd_mod].tv_sec += shift; + if (utimes(fname.c_str(), upd)){ + cerr << progid << " utimes failed!" << endl; + return ex_syserr; + } + return 0; +} diff --git a/tools/libltgrey.h b/tools/libltgrey.h index 1724d53..cf744d1 100644 --- a/tools/libltgrey.h +++ b/tools/libltgrey.h @@ -5,7 +5,7 @@ #define state_40_macro \ foo(unseen) \ -foo(young) \ +foo(green) \ foo(ripe) \ foo(spoiled) \ foo(fail) @@ -40,4 +40,5 @@ public: void dump(const std::string var); int maybe_mkdir(const std::string somedir, const std::string msg); state_40 get40(const std::string mid); + int set40(const std::string mid, const int shift); }; diff --git a/tools/ltgrey.c b/tools/ltgrey.c index 7a63b04..bb43b80 100644 --- a/tools/ltgrey.c +++ b/tools/ltgrey.c @@ -30,6 +30,7 @@ int main(int _argc, char** _argv){ int stain(0); int dns_mode(0); string get40_mid; + string set40_mid; while (argc > 0) { string arg = argv[0]; argc--; argv++; if (prefix(arg, "-scan")) { @@ -46,7 +47,12 @@ int main(int _argc, char** _argv){ exeunt(ex_syserr); } get40_mid = *argv++; argc--; - + } else if (prefix(arg, "-set40")) { + if (!argc){ + cerr << "Option '" << arg << "' requires an argument" << endl; + exeunt(ex_syserr); + } + set40_mid = *argv++; argc--; } else if (prefix(arg, "-shift") || prefix(arg, "-shift")) { if (!argc){ @@ -88,6 +94,10 @@ int main(int _argc, char** _argv){ return 0; } + if (set40_mid.length()){ + return foo.set40(set40_mid, shift); + } + if (scanmode) { string dirname = parent_dir + "/quarante"; scan(foo.progid, dirname, copies); -- cgit v1.2.3 From f8be4baf5a2318363b42f8883f66ed8a976dfc79 Mon Sep 17 00:00:00 2001 From: John Denker Date: Sun, 29 Jul 2012 23:26:28 -0700 Subject: scan40 appears to be working, much cleaner than last week's version --- tools/libltgrey.c | 63 +++++++++++++++++++++++++++++++++++++-------- tools/libltgrey.h | 7 +++++ tools/ltgrey.c | 77 ++----------------------------------------------------- tools/utils.c | 16 ++++++++++++ tools/utils.h | 1 + 5 files changed, 78 insertions(+), 86 deletions(-) (limited to 'tools/libltgrey.c') diff --git a/tools/libltgrey.c b/tools/libltgrey.c index 3a60daa..4e92665 100644 --- a/tools/libltgrey.c +++ b/tools/libltgrey.c @@ -32,11 +32,6 @@ const int minimum_age(15*minute); const int maximum_age(32*day); const int probation(4*hour); -// beware: access illogically comes *before* modification -// in the array passed to utimes: -const int upd_ac(0); -const int upd_mod(1); - #if 0 void exeunt(const int sts){ if (sts == ex_good) exit(sts); @@ -408,8 +403,16 @@ done: } state_40 whatsit::get40(const string mid){ - string fname = parent_dir + "/quarante/mid_" + mid; - cerr << ".... " << fname << endl; + timeval junk[2]; + return get40(mid, junk); +} + +state_40 whatsit::get40(const string mid, timeval times[2]){ + timeval now; + gettimeofday(&now, NULL); + times[0] = times[1] = now; // in case of early return + string fname = parent_dir + "/quarante/mid_" + purify(mid); + //xxx cerr << ".... " << fname << endl; struct stat mid_stat; int rslt = stat(fname.c_str(), &mid_stat); if (rslt != 0) { @@ -419,8 +422,10 @@ state_40 whatsit::get40(const string mid){ perror(0); return fail; } - timeval now; - gettimeofday(&now, NULL); + times[upd_ac ].tv_sec = mid_stat.st_atime; + times[upd_ac ].tv_usec = 0; + times[upd_mod].tv_sec = mid_stat.st_mtime; + times[upd_mod].tv_usec = 0; int mod_age = now.tv_sec - mid_stat.st_mtime; // int ac_age = now.tv_sec - mid_stat.st_atime; if (mod_age < minimum_age) return green; @@ -429,8 +434,8 @@ state_40 whatsit::get40(const string mid){ } int whatsit::set40(const string mid, const int shift){ - string fname = parent_dir + "/quarante/mid_" + mid; - cerr << ".... " << fname << endl; + string fname = parent_dir + "/quarante/mid_" + purify(mid); + //xxx cerr << ".... " << fname << endl; int fd = creat(fname.c_str(), 0644); if (fd < 0){ cerr << progid << ": create failed for '" @@ -465,3 +470,39 @@ int whatsit::set40(const string mid, const int shift){ } return 0; } + +void whatsit::scan40(const int copies){ + timeval now; + gettimeofday(&now, NULL); + using namespace boost::filesystem; + + string dir40 = parent_dir + "/quarante"; + + if (is_directory(dir40)) { + for (directory_iterator itr(dir40); itr!=directory_iterator(); ++itr) { + string basename = itr->path().filename(); + if (is_regular_file(itr->status())) { + string tag("mid_"); + if (prefix(tag, basename)) { + for (int ii = 0; ii < copies; ii++) + cout << setw(20) << left << basename; // display filename only + + timeval times[2]; + state_40 rslt = get40(basename.substr(tag.length()), times); + int mod_age = now.tv_sec - times[upd_mod].tv_sec; + int ac_age = now.tv_sec - times[upd_ac ].tv_sec; + cout << setw(10) << right << time_out(mod_age) + << " " << setw(10) << right << time_out(ac_age); + cout << " " << decode_40[rslt]; + cout << endl; + } else { + /* filename does not begin with tag "mid_" */ + } + } + } + } + else { + // starting point is not a directory: + cout << (exists(dir40) ? "Found: " : "Not found: ") << dir40 << '\n'; + } +} diff --git a/tools/libltgrey.h b/tools/libltgrey.h index cf744d1..14ed144 100644 --- a/tools/libltgrey.h +++ b/tools/libltgrey.h @@ -3,6 +3,11 @@ #include #include +// beware: access illogically comes *before* modification +// in the array passed to utimes: +const int upd_ac(0); +const int upd_mod(1); + #define state_40_macro \ foo(unseen) \ foo(green) \ @@ -40,5 +45,7 @@ public: void dump(const std::string var); int maybe_mkdir(const std::string somedir, const std::string msg); state_40 get40(const std::string mid); + state_40 get40(const std::string mid, timeval times[2]); int set40(const std::string mid, const int shift); + void scan40(const int copies); }; diff --git a/tools/ltgrey.c b/tools/ltgrey.c index bb43b80..1494338 100644 --- a/tools/ltgrey.c +++ b/tools/ltgrey.c @@ -33,7 +33,7 @@ int main(int _argc, char** _argv){ string set40_mid; while (argc > 0) { string arg = argv[0]; argc--; argv++; - if (prefix(arg, "-scan")) { + if (prefix(arg, "-scan40")) { scanmode++; } else if (prefix(arg, "-copy")) { copies++; @@ -99,8 +99,7 @@ int main(int _argc, char** _argv){ } if (scanmode) { - string dirname = parent_dir + "/quarante"; - scan(foo.progid, dirname, copies); + foo.scan40(copies); return 0; } @@ -108,75 +107,3 @@ int main(int _argc, char** _argv){ return sts; } - -////////////////////////////////////////////////////////////////////// -// requires apt-get install libboost-filesystem-dev: -#include -#include -#include /* for stat(), getaddrinfo() */ -#include /* for stat() */ -#include /* for stat() */ -#include /* for perror */ -#include - -const int minute(60); -const int hour(60*minute); -const int day(24*hour); - -const int minimum_age(15*minute); -const int maximum_age(32*day); -const int probation(4*hour); - -void scan(const string progid, const string p, const int copies){ - timeval now; - gettimeofday(&now, NULL); - using namespace boost::filesystem; - - if (is_directory(p)) { - for (directory_iterator itr(p); itr!=directory_iterator(); ++itr) { - string basename = itr->path().filename(); - for (int ii = 0; ii < copies; ii++) - cout << setw(20) << left << basename << ' '; // display filename only - if (is_regular_file(itr->status())) { -// cout << " [" << file_size(itr->path()) << ']'; - struct stat mystat; - string fn = p + "/" + basename; - int rslt = stat(fn.c_str(), &mystat); - if (rslt != 0){ - cerr << progid << ": stat failed for '" - << fn << "' : "; - perror(0); - } - int mod_age = now.tv_sec - mystat.st_mtime; - int ac_age = now.tv_sec - mystat.st_atime; - cout << setw(10) << time_out(mod_age) - << " " << setw(10) << time_out(ac_age); - if (0) { - - } else if (mod_age < 0) { - cout << " penalty"; - } else if (mod_age < ac_age) { - cout << " parole"; - } else if (mod_age - ac_age < minimum_age // early bird, or completely unused - && mod_age > probation) { // did not diligently resubmit - cout << " disprobation"; - if (mod_age != ac_age) cout << "!"; - } else if (mod_age < minimum_age) { - cout << " young"; - if (mod_age != ac_age) cout << "!"; - } else if (mod_age == ac_age) { - cout << " unused"; - } else if (mod_age > maximum_age) { - cout << " expired"; - } else { - cout << " OK"; - } - } - cout << '\n'; - } - } - else { - // starting point is not a directory: - cout << (exists(p) ? "Found: " : "Not found: ") << p << '\n'; - } -} diff --git a/tools/utils.c b/tools/utils.c index aecbfda..c544f20 100644 --- a/tools/utils.c +++ b/tools/utils.c @@ -3,6 +3,7 @@ #include //#include /* for abs() */ #include +#include /* for isalnum() */ // strip off the directory part of a path, leaving just // the basic filename @@ -58,3 +59,18 @@ std::string ltrim(const std::string foo){ if (where == foo.npos) return foo; return foo.substr(where); } + +static const std::string Pure_Enough("+-_.,@%~"); + +std::string purify(const std::string arg){ + using namespace std; + string rslt(arg); + for (string::iterator ptr = rslt.begin(); + ptr != rslt.end(); ptr++){ + char ch = *ptr; + if (isalnum(ch)) continue; + if (Pure_Enough.find(ch) != string::npos) continue; + *ptr = '~'; + } + return rslt; +} diff --git a/tools/utils.h b/tools/utils.h index ec467c6..cbcb795 100644 --- a/tools/utils.h +++ b/tools/utils.h @@ -4,3 +4,4 @@ std::string time_out(const int _ttt); std::string toLower(const std::string a); std::string ltrim(const std::string a); +std::string purify(const std::string arg); -- cgit v1.2.3