diff options
author | John Denker <jsd@av8n.com> | 2012-07-30 14:34:05 -0700 |
---|---|---|
committer | John Denker <jsd@av8n.com> | 2012-07-30 14:34:05 -0700 |
commit | 7024dc330299921af649330c45b99c21c3d7f022 (patch) | |
tree | 9f747a0423647b016376fe353ceea197a5848cbf | |
parent | ce0dbe5332d4eb921c09cc48cc52634211d7089a (diff) | |
parent | f8be4baf5a2318363b42f8883f66ed8a976dfc79 (diff) |
Merge branch 'master' of ephedra:usr/src/qmail into e_master
Conflicts:
tools/makefile
72 files changed, 2073 insertions, 426 deletions
@@ -10,6 +10,7 @@ *#[0-9]* \#*# +ucspi-tcp-0.88-ipv6.patch has?????.h auto-gid auto-int @@ -162,3 +163,4 @@ data.tar.gz dummy-mail-transfer-agent_all.deb bash-c wripper +ltgrey diff --git a/tools/filters.conf b/tools/filters.conf index bd8eb33..3cbd5bf 100644 --- a/tools/filters.conf +++ b/tools/filters.conf @@ -1,5 +1,5 @@ # configuration file for hi-q -series /var/qmail/bin/skrewt +series /var/qmail/bin/skrewt -err stub /var/qmail/bin/greylist -check -v sa /usr/local/bin/spamc -Y 0 -s 1000000 -x qq /var/qmail/bin/qmail-queue diff --git a/tools/greylist.c b/tools/greylist.c index 89396e7..9af70eb 100644 --- a/tools/greylist.c +++ b/tools/greylist.c @@ -22,7 +22,6 @@ #include <string.h> /* for memset() */ #include <arpa/inet.h> /* for inet_ntop() */ - using namespace std; const int minute(60); @@ -33,18 +32,7 @@ const int minimum_age(15*minute); const int maximum_age(32*day); const int probation(4*hour); -// error exit codes, mostly as stated in qmail.c -#define foo(name, num) const int ex_ ## name = num -#define bar foo(good, 0) ;\ -foo(spam, 21) ;\ -foo(penaltybox, 22) ;\ -foo(badDNS, 23) ;\ -foo(greylisting, 70) ;\ -foo(syserr, 71) ;\ -foo(comerr, 74) ; - -bar -#undef foo +#include "qq_exit_codes.h" pid_t mypid; string progname; @@ -58,14 +46,6 @@ void dump(const string var){ else cerr << " is not set." << endl; } - -//////////////// -// little utility to help with argument parsing: -// -int prefix(const string shorter, const string longer){ - return shorter == longer.substr(0, shorter.length()); -} - void exeunt(const int sts){ if (sts == ex_good) exit(sts); @@ -93,6 +73,8 @@ void exeunt(const int sts){ exit(sts); } +#include "utils.h" + class whatsit{ public: string dirname; @@ -126,12 +108,6 @@ public: int check_dns_sub(string &addr, string &host, vector<string> &checked); }; -string basename(const string path){ - size_t where = path.rfind("/"); - if (where != string::npos) return path.substr(1+where); - return path; -} - int whatsit::setup(){ stringstream foo; foo << basename(progname) << suffix @@ -145,26 +121,6 @@ int whatsit::setup(){ return 0; } -string time_out(const int _ttt){ - int ttt(abs(_ttt)); - int sec(ttt % 60); - int min((ttt / 60) % 60); - int hr(ttt / 3600); - stringstream foo; - int didsome(0); - if (_ttt < 0) foo << "-"; - if (hr) { - foo << hr << ":"; - didsome++; - } - if (didsome || min){ - foo << setw(didsome?2:1) << setfill('0') << min << ":"; - didsome++; - } - foo << setw(didsome?2:1) << setfill('0') << sec; - return foo.str(); -} - void scan(const string progid, const string p, const int copies=1){ timeval now; gettimeofday(&now, NULL); diff --git a/tools/hi-q.c b/tools/hi-q.c index 502de69..59cad5d 100644 --- a/tools/hi-q.c +++ b/tools/hi-q.c @@ -144,7 +144,7 @@ int Execve(char const * fn, int fork_and_wait(const jobber job){ pid_t kidpid = fork(); if (kidpid == -1) { - cerr << "hi-q: fork failed : "; + cerr << progid << " fork failed : "; perror(0); exit(ex_syserr); } @@ -157,9 +157,9 @@ int fork_and_wait(const jobber job){ if (!kidpid){ /*** child code ***/ - int rslt; - rslt = Execve(prog[0], prog, environ); - fprintf(stderr, "hi-q: failed to exec '%s': ", prog[0]); + Execve(prog[0], prog, environ); + cerr << progid << " failed to exec '" + << prog[0] << "' : " << endl; perror(0); exit(ex_syserr); } else { @@ -167,6 +167,11 @@ int fork_and_wait(const jobber job){ int kidstatus; pid_t somekid; somekid = waitpid(kidpid, &kidstatus, WUNTRACED); + if (somekid < 0) { + cerr << progid << " ??? waitpid failed : "; + perror(0); + return(ex_syserr); + } if (WIFEXITED(kidstatus)) { int sts = WEXITSTATUS(kidstatus); if (sts != ex_good && sts != ex_spam) { @@ -179,7 +184,7 @@ int fork_and_wait(const jobber job){ } else if (WIFSIGNALED(kidstatus)) { int sig = WTERMSIG(kidstatus); if (sig == SIGUSR1) {/* normal, no logging required */} - else cerr << "hi-q: job " << prog[0] + else cerr << progid << " job " << prog[0] << " killed by signal " << sig << endl; return(ex_syserr); } else { @@ -199,8 +204,8 @@ int fork_and_wait(vector<jobber> post){ } void exeunt(const int sts) { - // FIXME: stop other children - //xxxx cerr << "hi-q: exeunt called with " << sts << endl; + // FIXME: stop other children, maybe? + //xxxx cerr << progid << " exeunt called with " << sts << endl; if (sts == ex_spam) fork_and_wait(post); if (sts == ex_penaltybox) exit(ex_spam); exit(sts); @@ -336,7 +341,9 @@ void attach(const int pipe_end, const int fd, const int kidno){ if (pipe_end != fd) { int rslt = dup2(pipe_end, fd); if (rslt < 0) { - fprintf(stderr, "hi-q: dup2(%d,%d) failed for kid %d : ", pipe_end, fd, kidno); + cerr << progid << " dup2(" << pipe_end + << "," << fd << ")" + " failed for kid " << kidno << " : "; perror(0); exit(ex_syserr); } @@ -394,7 +401,7 @@ bar ifstream conf; conf.open(conf_name); if (! conf.good()) { - cerr << "hi-q: could not open filter.conf file '" + cerr << progid << " could not open filter.conf file '" << conf_name << "'" << endl; exit(1); } @@ -431,7 +438,7 @@ bar if (nkids == 0) exit(0); // nothing to do if (verbose) for (unsigned int ii = 0; ii < nkids; ii++) { - cerr << "hi-q filter[" << ii << "] :; "; + cerr << progid << " filter[" << ii << "] :; "; for (VS::const_iterator token = filter[ii].cmd.begin(); token != filter[ii].cmd.end(); token++){ cerr << *token << " "; @@ -508,7 +515,7 @@ bar block_fd(blockme); rslt = pipe(datapipe); if (rslt < 0) { - fprintf(stderr, "hi-q: could not create datapipe: "); + cerr << progid << " could not create datapipe : "; perror(0); exeunt(ex_syserr); } @@ -559,7 +566,7 @@ bar kidpid[ii] = fork(); if (kidpid[ii] == -1) { - cerr << "hi-q: fork failed : "; + cerr << progid << " fork failed : "; perror(0); exit(ex_syserr); } @@ -657,14 +664,15 @@ bar exit(1); } rslt = Execve(prog[0], prog, environ); - fprintf(stderr, "hi-q: failed to exec '%s': ", prog[0]); + cerr << progid << " failed to exec '" + << prog[0] << "' : "; perror(0); exit(ex_syserr); } /*** parent code ***/ if (kidpid[ii] < 0) { - fprintf(stderr, "hi-q: failure to fork kid#%d: ", ii); + cerr << " failure to fork kid#" << ii << " : "; perror(0); exeunt(ex_syserr); } @@ -714,7 +722,7 @@ bar // so we don't need it. if (verbose) for (unsigned int ii = 0; ii < nkids; ii++) { - cerr << "hi-q filter[" << ii << "] " + cerr << progid << " filter[" << ii << "] " << kidpid[ii] << " :; "; for (VS::const_iterator token = filter[ii].cmd.begin(); @@ -736,7 +744,7 @@ bar // do not decrement the "alive" counter // since that only applies to non-special kids if (WIFEXITED(kidstatus)) { - cerr << "hi-q: special kid exited early, status " + cerr << progid << " special kid exited early, status " << WEXITSTATUS(kidstatus) << " with " << alive << " kids still alive" << endl; @@ -745,7 +753,7 @@ bar int sig = WTERMSIG(kidstatus); if (sig == SIGUSR1) {/* normal, no logging required */} else { - cerr << "hi-q: special kid killed by signal " + cerr << progid << " special kid killed by signal " << sig << endl; // this is not normal return(ex_syserr); @@ -795,7 +803,7 @@ bar if (sts == 0){ // should never get here // should be no accounting for blame if there was no blame - cerr << "hi-q: should never happen: no child to blame" << endl; + cerr << progid << " should never happen: no child to blame" << endl; exeunt(ex_syserr); } diff --git a/tools/hi-test.c b/tools/hi-test.c index 0661ada..cd0152c 100644 --- a/tools/hi-test.c +++ b/tools/hi-test.c @@ -6,6 +6,7 @@ #include <sstream> #include <stdio.h> /* perror() */ +#include "utils.h" using namespace std; @@ -16,13 +17,6 @@ const int sa_usage(64); int verbosity(0); -//////////////// -// little utility to help with argument parsing: -// -int prefix(const string shorter, const string longer){ - return shorter == longer.substr(0, shorter.length()); -} - void exeunt(const int sts){ if (sts == sa_good) exit(sts); @@ -69,12 +63,6 @@ void countsome(const int unit){ << " read " << total << " bytes from unit " << unit << endl; } -string basename(const string path){ - size_t where = path.rfind("/"); - if (where != string::npos) return path.substr(1+where); - return path; -} - int main(int _argc, const char** _argv){ int snooze(0); int status(0); diff --git a/tools/libltgrey.c b/tools/libltgrey.c new file mode 100644 index 0000000..4e92665 --- /dev/null +++ b/tools/libltgrey.c @@ -0,0 +1,508 @@ +#include <stdlib.h> /* for exit(), getenv() */ +#include <iostream> +#include <iomanip> +#include <string> + +#include <sys/types.h> /* for stat(), getaddrinfo() */ +#include <sys/stat.h> /* for stat() */ +#include <unistd.h> /* for stat() */ +#include <stdio.h> /* for perror */ +#include <errno.h> /* for ENOENT */ +#include <fstream> /* for ofstream() */ +#include <fcntl.h> /* for creat() */ +#include <sys/time.h> /* for gettimeofday() */ +#include <sstream> /* for stringstream */ +#include <signal.h> /* for kill(), SIGUSR1 */ + +// requires apt-get install libboost-filesystem-dev: +#include <boost/filesystem.hpp> + +#include <sys/socket.h> /* for getaddrinfo() */ +#include <netdb.h> /* for getaddrinfo() */ +#include <string.h> /* for memset() */ +#include <arpa/inet.h> /* 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 <sys/time.h> /* for gettimeofday */ +#include <iomanip> /* for setw */ +#include <unistd.h> /* for stat */ +#include <sys/types.h> /* for stat, creat */ +#include <sys/stat.h> /* for stat, creat */ +#include <fcntl.h> /* for creat */ +#include <fstream> /* for ofstream() */ + +#include "libltgrey.h" +#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()), + verbosity(0) +{ +// expand the codes to make some <const int> names: +# define foo(name) decode_40[name] = #name; + state_40_macro +# undef foo +} + +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(); + + 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){ + 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; +} +#endif + +int whatsit::maybe_mkdir(const string somedir, const string msg){ +// see if our directory exists: + struct stat dirstat; + int rslt = stat(somedir.c_str(), &dirstat); + if (rslt != 0){ + if (errno != ENOENT) { + cerr << progid << " stat failed for " + << msg + << " '" << somedir << "' : "; + perror(0); + } + rslt = mkdir(somedir.c_str(), 0755); + if (rslt != 0) { + cerr << progid + << "uid " << getuid() + << " 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; + 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; +} +#endif + +typedef vector<unsigned char> 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(const char* ipvar, const char* namevar){ + if (!ipvar) { + cerr << progid << " check_dns: no addr specified." << endl; + return ex_syserr; + } + string addr("()"), host("()"); + vector<string> checked; + int rslt = check_dns_sub(ipvar, namevar, addr, host, checked); + int sts = rslt; +#if 1 + sts = 0; // demote badDNS to just a warning +#endif + 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<string>::const_iterator chk = checked.begin(); + chk != checked.end(); chk++) cerr << " " << *chk; + cerr << endl; + } + return sts; +} + +int whatsit::check_dns_sub(const char* ipvar, const char* namevar, + string &addr, string &host, vector<string> &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 + +// 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 + 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; + } + +// reconvert from bits to string + family info + VUx ipAddr = parse_sockaddr(ipresult->ai_addr); + addr = ipAddr.str(); + + 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(namevar, 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; +} + +state_40 whatsit::get40(const string mid){ + 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) { + if (errno == ENOENT) return unseen; + cerr << progid << " stat: unexpected failure for '" + << fname << "' : "; + perror(0); + return fail; + } + 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; + if (mod_age < probation) return ripe; + return spoiled; +} + +int whatsit::set40(const string mid, const int shift){ + 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 '" + << 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; +} + +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 new file mode 100644 index 0000000..14ed144 --- /dev/null +++ b/tools/libltgrey.h @@ -0,0 +1,51 @@ +#include <string> +#include <sys/time.h> /* for gettimeofday(), timeval */ +#include <vector> +#include <map> + +// 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) \ +foo(ripe) \ +foo(spoiled) \ +foo(fail) + +// expand the codes to make some <const int> 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; + std::string suffix; + std::string progid; + int verbosity; + std::map<state_40,std::string> decode_40; + + 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(const char* ipvar, const char* namevar); + int check_dns_sub(const char* ipvar, const char* namevar, + std::string &addr, std::string &host, + std::vector<std::string> &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); + 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 new file mode 100644 index 0000000..1494338 --- /dev/null +++ b/tools/ltgrey.c @@ -0,0 +1,109 @@ +#include <iostream> +#include <stdlib.h> /* for exit(), atoi() */ + +#include "libltgrey.h" +#include "utils.h" +#include "qq_exit_codes.h" + +using namespace std; +pid_t mypid; +string progname; + +#define exeunt exit + +// forward reference: +void scan(const string progid, const string p, const int copies=1); + + +int main(int _argc, char** _argv){ + std::string hostname; + std::string ipname; + + mypid = getpid(); + int argc(_argc); + char** argv(_argv); + const string parent_dir("/var/qmail/ltgrey"); + whatsit foo(argv[0], parent_dir); argc--; argv++; + int scanmode(0); + int copies(1); + int shift(0); + 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, "-scan40")) { + scanmode++; + } else if (prefix(arg, "-copy")) { + copies++; + } else if (prefix(arg, "-verbose")) { + foo.verbosity++; + } 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); + } + 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){ + 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); + } + stain = atoi(*argv++); argc--; + } else if (prefix(arg, "-suffix")) { + if (!argc){ + cerr << "Option '" << arg << "' requires an argument" << endl; + exeunt(ex_syserr); + } + foo.suffix += *argv++; argc--; + } else { + cerr << "Unrecognized arg: " << arg << endl; + exeunt(ex_syserr); + } + } + if (foo.setup()) return ex_syserr; + +// 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 (set40_mid.length()){ + return foo.set40(set40_mid, shift); + } + + if (scanmode) { + foo.scan40(copies); + return 0; + } + + int sts = foo.doit(shift, stain); + return sts; + +} diff --git a/tools/mail-scan.c b/tools/mail-scan.c index 0cda6e5..b0c4137 100644 --- a/tools/mail-scan.c +++ b/tools/mail-scan.c @@ -31,7 +31,7 @@ #include <stdio.h> /* perror */ #include <boost/regex.hpp> -////#include <boost/lexical_cast.hpp> +#include "utils.h" using namespace std; @@ -105,30 +105,6 @@ int cmp_casefold(const std::string& a, const std::string& b) { return 0; } - -string toLower(const std::string& a){ - string rslt = a; - string::iterator rr; - for (rr = rslt.begin(); rr != rslt.end(); rr++){ - *rr = tolower(*rr); - } - return rslt; -} - -//////////////// -string ltrim(string foo){ - size_t where = foo.find_first_not_of(" \t\r\n"); - if (where == foo.npos) return foo; - return foo.substr(where); -} - -//////////////// -// little utility to help with argument parsing: -// -int prefix(const string shorter, const string longer){ - return shorter == longer.substr(0, shorter.length()); -} - void exeunt(const int sts){ if (sts == sa_good) exit(sts); @@ -183,6 +159,16 @@ public: } }; +string noCR(const string bar){ + string foo(bar); + int len = foo.length(); + if (len){ + if (foo[len-1] == '\r') { + foo.erase(len-1); + } + } + return foo; +} //////////////////////////////////////////////////////////// int main(int _argc, const char** _argv){ @@ -268,6 +254,7 @@ int main(int _argc, const char** _argv){ return 1; } if (getline(infile, line).fail()) continue; + line = noCR(line); Header.push_back(line); msgsize += line.length()+1; if (msgsize > maxsize) { @@ -335,9 +322,9 @@ int main(int _argc, const char** _argv){ break; } } // end loop over matching records in this file + if (vflag && !foundsome_infile) { - cout << foundsome_infile - << " ... " << *file << endl; + cout << *file << endl; didprint++; } if (group_flag && didprint) cout << endl; diff --git a/tools/makefile b/tools/makefile index 76df23b..6594ca8 100644 --- a/tools/makefile +++ b/tools/makefile @@ -15,10 +15,10 @@ qmain = pido.c hi-q.c skrewt.c hi-test.c mail-scan.c greylist.c wripper.c qprogs = $(qmain:%.c=%) # sources for other main programs: -moremain = wripper.c bash-c.c +moremain = wripper.c bash-c.c ltgrey.c moreprogs = $(moremain:%.c=%) -nonmain = +nonmain = libltgrey.c sources = $(qmain) $(moremain) $(nonmain) @@ -37,17 +37,24 @@ all: $(qprogs) $(moreprogs) show: : --- $(qprogs) +++ $(moreprogs) -greylist: greylist.o - $(CC) $< -lboost_filesystem-mt -lboost_system -o $@ +skrewt: skrewt.o utils.o + $(CC) $^ -lboost_filesystem-mt -lboost_system -o $@ -# $(CC) $< -lboost_filesystem -o $@ +greylist: greylist.o utils.o + $(CC) $^ -lboost_filesystem-mt -lboost_system -o $@ + +ltgrey: ltgrey.o utils.o libltgrey.o + $(CC) $^ -lboost_filesystem-mt -lboost_system -o $@ wripper: wripper.o - $(CC) $< -o $@ + $(CC) $^ -o $@ chgrp daemon $@ && chmod g+s $@ || true -mail-scan: mail-scan.o - $(CC) $< -lboost_regex -o $@ +mail-scan: mail-scan.o utils.o + $(CC) $^ -lboost_regex -o $@ + +hi-test: hi-test.o utils.o + $(CC) $^ -lboost_regex -o $@ install: install $(qprogs) /var/qmail/bin/ diff --git a/tools/qq_exit_codes.h b/tools/qq_exit_codes.h new file mode 100644 index 0000000..2af6848 --- /dev/null +++ b/tools/qq_exit_codes.h @@ -0,0 +1,15 @@ +// error exit codes, mostly as stated in qmail.c +#define qq_exit_codes \ +foo(good, 0) ;\ +foo(spam, 21) ;\ +foo(penaltybox, 22) ;\ +foo(badDNS, 23) ;\ +foo(usage, 39) ;\ +foo(greylisting, 70) ;\ +foo(syserr, 71) ;\ +foo(comerr, 74) ; + +// expand the codes to make some <const int> names: +#define foo(name, num) const int ex_ ## name = num +qq_exit_codes +#undef foo diff --git a/tools/skrewt.c b/tools/skrewt.c index d2e1bbc..6749a01 100644 --- a/tools/skrewt.c +++ b/tools/skrewt.c @@ -1,4 +1,4 @@ -/////////////////// +////////////////// // skrewt.c // // scrutinize email @@ -13,6 +13,7 @@ #include <stdio.h> /* perror */ #include <sstream> #include <vector> +#include <list> using namespace std; @@ -28,6 +29,7 @@ void usage(const int sts){ " Options\n" " -help print this msg (and exit immediately).\n" " -maxsize ii msg size in bytes; anything bigger will be rejected.\n" +" -error-exit exit early if errors have been detected.\n" "\n" " Messages containing the string '-please-bounce-this-' will be rejected.\n" " Messages with no date will be rejected.\n" @@ -35,20 +37,8 @@ void usage(const int sts){ exit(sts); } -// error exit codes, mostly as stated in qmail.c -#define bar \ -foo(good, 0) ;\ -foo(spam, 21) ;\ -foo(permerr, 31) ;\ -foo(usage, 39) ;\ -foo(greylisting, 70) ;\ -foo(syserr, 71) ;\ -foo(comerr, 74) ; - -#define foo(name, num) const int ex_ ## name = num -bar -#undef foo - +#include "qq_exit_codes.h" +#include "utils.h" ///////////////////////////////////////////////////////// // Case insensitive comparison of strings @@ -93,31 +83,19 @@ int cmp_casefold(const std::string& a, const std::string& b) { return 0; } - -string toLower(const std::string& a){ - string rslt = a; - string::iterator rr; - for (rr = rslt.begin(); rr != rslt.end(); rr++){ - *rr = tolower(*rr); +string noCR(const string bar){ + string foo(bar); + int len = foo.length(); + if (len){ + if (foo[len-1] == '\r') { + foo.erase(len-1); + } } - return rslt; + return foo; } -//////////////// -string ltrim(string foo){ - size_t where = foo.find_first_not_of(" \t\r\n"); - if (where == foo.npos) return foo; - return foo.substr(where); -} - -//////////////// -// little utility to help with argument parsing: -// -int prefix(const string shorter, const string longer){ - return shorter == longer.substr(0, shorter.length()); -} - -void exeunt(const int sts){ +void maybe_exeunt(const int sts, const int really){ + if (!really) return; if (sts == ex_good) exit(sts); const char* foo = getenv("HI_Q_GROUP"); @@ -136,10 +114,8 @@ void exeunt(const int sts){ exit(sts); } -string basename(const string path){ - size_t where = path.rfind("/"); - if (where != string::npos) return path.substr(1+where); - return path; +void exeunt(const int sts){ + maybe_exeunt(sts, 1); } string progname, progid; @@ -149,7 +125,7 @@ int mypid; /* Content-Type: multipart/mixed; boundary="1170861315-1262462055-1341954763=:92165" */ // void parse_content(const string type_spec_line, string &maintype, string &boundary) { - cerr << "parser called with: " << type_spec_line << endl; + //xxx cerr << "parser called with: " << type_spec_line << endl; string get_type(type_spec_line); size_t where = get_type.find_first_of(" \t;\n"); @@ -192,6 +168,15 @@ void parse_content(const string type_spec_line, string &maintype, string &bounda } } +string join(const string sep, const list<string> stuff){ + string rslt; + for (list<string>::const_iterator ptr = stuff.begin(); + ptr != stuff.end(); ptr++){ + if (rslt.length()) rslt += sep; + rslt += *ptr; + } + return rslt; +} //////////////////////////////////////////////////////////// int main(int _argc, const char** _argv){ @@ -209,6 +194,8 @@ int main(int _argc, const char** _argv){ } int maxsize(1000*1000); + int error_exit(0); + int mid_required(0); while (argc) { string arg(*argv); argv++; argc--; @@ -216,14 +203,18 @@ int main(int _argc, const char** _argv){ if (prefix(arg, "-help")) { usage(0); } - if (prefix(arg, "-maxsize")) { + if (0) { + } else if (prefix(arg, "-mid-required")) { + mid_required++; + } else if (prefix(arg, "-error-exit")) { + error_exit++; + } else if (prefix(arg, "-maxsize")) { if (!argc) { cerr << "Option -maxsize requires an argument" << endl; exit(ex_usage); } maxsize = atoi(*argv); argv++; argc--; - } - if (arg.substr(0,1) == "-") { + } else if (arg.substr(0,1) == "-") { cerr << "Unrecognized option '" << arg << "'" << endl; cerr << "For help, try: " << progname << " -help" << endl; exit(ex_usage); @@ -236,28 +227,32 @@ int main(int _argc, const char** _argv){ int saw_blank_line(0); string boundary("x-xx-x"); - string date; + string to; + string from; string subject; - string content_type; + string date; string message_id; + string content_type; int msgsize(0); vector<string> bigbuf; - cerr << "hi there" << endl; + int recno(0); + //xxxx cerr << progid << " begins" << endl; for (;;){ // outer loop over all records in the header if (cin.eof()) break; if (cin.bad()) return 1; - string headrec; + string line; // on fail, go back to top of outer loop and check for eof versus bad - if (getline(cin, headrec).fail()) continue; - msgsize += headrec.length()+1; + if (getline(cin, line).fail()) continue; + msgsize += line.length()+1; if (msgsize > maxsize) { cerr << progid << " rejection: bigger than " << maxsize << endl; exeunt(ex_spam); } - cout << headrec << endl; - bigbuf.push_back(headrec); // for a folded record, this is the first line + cout << line << endl; + bigbuf.push_back(line); + string headrec = noCR(line); // for a folded record, this is the first line for (;;) { // inner loop to build a multi-line record e.g. folded record: if (cin.eof()) break; @@ -276,16 +271,11 @@ int main(int _argc, const char** _argv){ } cout << line << endl; bigbuf.push_back(line); - string cooked(line); - if (cooked.length()){ - string::iterator ptr = cooked.end()-1; - if (*ptr == '\r') cooked.erase(ptr); - } - headrec += "\n" + cooked; + headrec += "\n" + noCR(line); } // here with a fully assembled header record +// headrec (unlike line) contains no DOS CR characters int len = headrec.length(); - if (len && headrec[len-1] == '\r') len--; // reduced length, not counting <cr> if (len == 0) { saw_blank_line = 1; break; // no more headers in this message @@ -301,6 +291,12 @@ int main(int _argc, const char** _argv){ } headword = toLower(headword); if (0){ + } else if (headword == "from") { + from = rest; + } else if (headword == "to") { + to = rest; + } else if (headword == "message-id") { + message_id = rest; } else if (headword == "date") { date = rest; } else if (headword == "subject") { @@ -309,30 +305,50 @@ int main(int _argc, const char** _argv){ content_type = rest; } //xxxx cout << headrec.length() << " ... "; + recno++; + if (0) if (recno <= 6) cerr << progid << "#" << recno + << " " << headrec << endl; } - cerr << "headers are done. Delimited: " << saw_blank_line << endl; + if (saw_blank_line) {/* ignore */} + cerr << progid <<" Mid '" << message_id << "'" << endl; // Headers are done. // Do some early-stage thinking. + list<string> badnews; + if (subject.find("-please-bounce-this-") != string::npos) { - cerr << progid << " rejection: by request" << endl; - exeunt(ex_spam); + badnews.push_back("by request"); } if (!date.length()) { - cerr << progid << " rejection: no date" << endl; - exeunt(ex_spam); // disallow mail with no date + badnews.push_back("no date"); + } + + if (mid_required && !message_id.length()) { + badnews.push_back("no message-id"); + } + + if (badnews.size()){ + cerr << progid << " " << join(", ", badnews) << endl; + if (error_exit){ + cerr << progid << " '" << from + << "' to '" << to + << "'" << endl; + exeunt(ex_spam); + } } string main_contype; - parse_content(content_type, main_contype, boundary); + if (content_type.length()) + parse_content(content_type, main_contype, boundary); +// some slightly-useful booleans: int currently_text = main_contype == "text"; int main_multipart = main_contype == "multipart"; // early-stage thinking has been done. // Now spew the rest of the message - cerr << "body begins: " << main_contype << " " << currently_text << " " << boundary << endl; + //xxxx cerr << "body begins: " << main_contype << " " << currently_text << " " << boundary << endl; int in_subheads(0); int textlines(0); @@ -345,7 +361,7 @@ int main(int _argc, const char** _argv){ msgsize += line.length()+1; if (msgsize > maxsize) { cerr << progid << " rejection: bigger than " << maxsize << endl; - exeunt(ex_spam); + maybe_exeunt(ex_spam, error_exit); } bigbuf.push_back(line); cout << line << endl; @@ -368,7 +384,7 @@ int main(int _argc, const char** _argv){ if (headword == "content-type") { parse_content(rest, sub_contype, junk); currently_text = sub_contype == "text"; - cerr << "setting contype '" << sub_contype << "' " << currently_text << " ... " << textlines << endl; + //xxxx cerr << "setting contype '" << sub_contype << "' " << currently_text << " ... " << textlines << endl; } } else { if (main_multipart && line == "--" + boundary) { @@ -380,10 +396,10 @@ int main(int _argc, const char** _argv){ } } - if (1) cerr << "textlines: " << textlines << endl; + if (0) cerr << "textlines: " << textlines << endl; if (1 && !textlines) { cerr << progid << " rejection: no text" << endl; -// exeunt(ex_spam); +// maybe_exeunt(ex_spam, error_exit); } cerr << progid << " normal completion" << endl; exit(ex_good); diff --git a/tools/utils.c b/tools/utils.c new file mode 100644 index 0000000..c544f20 --- /dev/null +++ b/tools/utils.c @@ -0,0 +1,76 @@ +#include <string> +#include <sstream> +#include <iomanip> +//#include <stdlib.h> /* for abs() */ +#include <cmath> +#include <ctype.h> /* for isalnum() */ + +// strip off the directory part of a path, leaving just +// the basic filename +std::string basename(const std::string path){ + size_t where = path.rfind("/"); + if (where != std::string::npos) return path.substr(1+where); + return path; +} + +//////////////// +// little utility to help with argument parsing: +// +int prefix(const std::string shorter, const std::string longer){ + return shorter == longer.substr(0, shorter.length()); +} + +/////////////// +// print a time as (-)hh:mm:ss +// +std::string time_out(const int _ttt){ +using namespace std; + int ttt(abs(_ttt)); + int sec(ttt % 60); + int min((ttt / 60) % 60); + int hr(ttt / 3600); + stringstream foo; + int didsome(0); + if (_ttt < 0) foo << "-"; + if (hr) { + foo << hr << ":"; + didsome++; + } + if (didsome || min){ + foo << setw(didsome?2:1) << setfill('0') << min << ":"; + didsome++; + } + foo << setw(didsome?2:1) << setfill('0') << sec; + return foo.str(); +} + +std::string toLower(const std::string a){ + std::string rslt = a; + std::string::iterator rr; + for (rr = rslt.begin(); rr != rslt.end(); rr++){ + *rr = tolower(*rr); + } + return rslt; +} + +//////////////// +std::string ltrim(const std::string foo){ + size_t where = foo.find_first_not_of(" \t\r\n"); + 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 new file mode 100644 index 0000000..cbcb795 --- /dev/null +++ b/tools/utils.h @@ -0,0 +1,7 @@ +std::string basename(const std::string path); +int prefix(const std::string shorter, const std::string longer); +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); diff --git a/ucspi-tcp-0.88/FILES b/ucspi-tcp-0.88/FILES index cfb38a5..142aed9 100644 --- a/ucspi-tcp-0.88/FILES +++ b/ucspi-tcp-0.88/FILES @@ -216,3 +216,40 @@ wait_pid.c warn-auto.sh warn-shsgr x86cpuid.c +dns_ip6.c +dns_ipq6.c +dns_nd6.c +dns_sortip6.c +fmt_xlong.c +ip6_fmt.c +ip6_scan.c +scan_0x.c +socket_accept6.c +socket_bind6.c +socket_conn6.c +socket_local6.c +socket_recv6.c +socket_remote6.c +socket_send6.c +socket_tcp6.c +timeoutconn6.c +tryip6.c +haveip6.h2 +haveip6.h1 +remoteinfo6.c +addcr.1 +argv0.1 +date@.1 +delcr.1 +finger@.1 +fixcr.1 +http@.1 +mconnect.1 +recordio.1 +tcp-environ.5 +tcpcat.1 +tcpclient.1 +tcprules.1 +tcprulescheck.1 +tcpserver.1 +who@.1 diff --git a/ucspi-tcp-0.88/Makefile b/ucspi-tcp-0.88/Makefile index a67b0cb..1b7c9dc 100644 --- a/ucspi-tcp-0.88/Makefile +++ b/ucspi-tcp-0.88/Makefile @@ -76,12 +76,14 @@ byte.a: \ makelib byte_chr.o byte_copy.o byte_cr.o byte_diff.o byte_rchr.o \ byte_zero.o case_diffb.o case_diffs.o fmt_ulong.o ip4_fmt.o \ ip4_scan.o scan_ulong.o str_chr.o str_diff.o str_len.o str_start.o \ -uint16_pack.o uint16_unpack.o uint32_pack.o uint32_unpack.o +uint16_pack.o uint16_unpack.o uint32_pack.o uint32_unpack.o \ +ip6_fmt.o scan_ip6.o scan_xlong.o fmt_xlong.o ./makelib byte.a byte_chr.o byte_copy.o byte_cr.o \ byte_diff.o byte_rchr.o byte_zero.o case_diffb.o \ case_diffs.o fmt_ulong.o ip4_fmt.o ip4_scan.o scan_ulong.o \ str_chr.o str_diff.o str_len.o str_start.o uint16_pack.o \ - uint16_unpack.o uint32_pack.o uint32_unpack.o + uint16_unpack.o uint32_pack.o uint32_unpack.o ip6_fmt.o \ + scan_ip6.o scan_xlong.o fmt_xlong.o byte_chr.o: \ compile byte_chr.c byte.h @@ -181,11 +183,13 @@ compile delcr.c buffer.h exit.h dns.a: \ makelib dns_dfd.o dns_domain.o dns_dtda.o dns_ip.o dns_ipq.o \ dns_name.o dns_nd.o dns_packet.o dns_random.o dns_rcip.o dns_rcrw.o \ -dns_resolve.o dns_sortip.o dns_transmit.o dns_txt.o +dns_resolve.o dns_sortip.o dns_transmit.o dns_txt.o dns_ip6.o \ +dns_sortip6.o dns_nd6.o dns_ipq6.o ./makelib dns.a dns_dfd.o dns_domain.o dns_dtda.o dns_ip.o \ dns_ipq.o dns_name.o dns_nd.o dns_packet.o dns_random.o \ dns_rcip.o dns_rcrw.o dns_resolve.o dns_sortip.o \ - dns_transmit.o dns_txt.o + dns_transmit.o dns_txt.o dns_ip6.o dns_sortip6.o dns_nd6.o \ + dns_ipq6.o dns_dfd.o: \ compile dns_dfd.c error.h alloc.h byte.h dns.h stralloc.h gen_alloc.h \ @@ -257,7 +261,7 @@ taia.h tai.h uint64.h taia.h dns_transmit.o: \ compile dns_transmit.c socket.h uint16.h alloc.h error.h byte.h \ readwrite.h uint16.h dns.h stralloc.h gen_alloc.h iopause.h taia.h \ -tai.h uint64.h taia.h +tai.h uint64.h taia.h uint32.h ./compile dns_transmit.c dns_txt.o: \ @@ -498,9 +502,15 @@ exit.h fmt.h iopause.h taia.h tai.h uint64.h pathexec.h remoteinfo.o: \ compile remoteinfo.c fmt.h buffer.h socket.h uint16.h error.h \ iopause.h taia.h tai.h uint64.h timeoutconn.h uint16.h remoteinfo.h \ -stralloc.h gen_alloc.h uint16.h +stralloc.h gen_alloc.h uint16.h uint32.h ./compile remoteinfo.c +remoteinfo6.o: \ +compile remoteinfo6.c fmt.h buffer.h socket.h uint16.h error.h \ +iopause.h taia.h tai.h uint64.h timeoutconn.h uint16.h remoteinfo.h \ +stralloc.h gen_alloc.h uint16.h uint32.h + ./compile remoteinfo6.c + rts: \ warn-auto.sh rts.sh conf-home cat warn-auto.sh rts.sh \ @@ -557,43 +567,43 @@ trylsock.c compile load rm -f trylsock.o trylsock socket_accept.o: \ -compile socket_accept.c byte.h socket.h uint16.h +compile socket_accept.c byte.h socket.h uint16.h uint32.h ./compile socket_accept.c socket_bind.o: \ -compile socket_bind.c byte.h socket.h uint16.h +compile socket_bind.c byte.h socket.h uint16.h uint32.h ./compile socket_bind.c socket_conn.o: \ -compile socket_conn.c readwrite.h byte.h socket.h uint16.h +compile socket_conn.c readwrite.h byte.h socket.h uint16.h uint32.h ./compile socket_conn.c socket_delay.o: \ -compile socket_delay.c socket.h uint16.h +compile socket_delay.c socket.h uint16.h uint32.h ./compile socket_delay.c socket_listen.o: \ -compile socket_listen.c socket.h uint16.h +compile socket_listen.c socket.h uint16.h uint32.h ./compile socket_listen.c socket_local.o: \ -compile socket_local.c byte.h socket.h uint16.h +compile socket_local.c byte.h socket.h uint16.h uint32.h ./compile socket_local.c socket_opts.o: \ -compile socket_opts.c socket.h uint16.h +compile socket_opts.c socket.h uint16.h uint32.h ./compile socket_opts.c socket_remote.o: \ -compile socket_remote.c byte.h socket.h uint16.h +compile socket_remote.c byte.h socket.h uint16.h uint32.h ./compile socket_remote.c socket_tcp.o: \ -compile socket_tcp.c ndelay.h socket.h uint16.h +compile socket_tcp.c ndelay.h socket.h uint16.h uint32.h ./compile socket_tcp.c socket_udp.o: \ -compile socket_udp.c ndelay.h socket.h uint16.h +compile socket_udp.c ndelay.h socket.h uint16.h uint32.h ./compile socket_udp.c str_chr.o: \ @@ -710,9 +720,9 @@ warn-auto.sh tcpcat.sh conf-home chmod 755 tcpcat tcpclient: \ -load tcpclient.o remoteinfo.o timeoutconn.o dns.a time.a unix.a \ -byte.a socket.lib - ./load tcpclient remoteinfo.o timeoutconn.o dns.a time.a \ +load tcpclient.o remoteinfo6.o dns.a time.a unix.a \ +byte.a socket.lib byte.h timeoutconn6.o + ./load tcpclient remoteinfo6.o timeoutconn6.o dns.a time.a \ unix.a byte.a `cat socket.lib` tcpclient.o: \ @@ -720,7 +730,7 @@ compile tcpclient.c sig.h exit.h sgetopt.h subgetopt.h uint16.h fmt.h \ scan.h str.h ip4.h uint16.h socket.h uint16.h fd.h stralloc.h \ gen_alloc.h buffer.h error.h strerr.h pathexec.h timeoutconn.h \ uint16.h remoteinfo.h stralloc.h uint16.h dns.h stralloc.h iopause.h \ -taia.h tai.h uint64.h taia.h +taia.h tai.h uint64.h taia.h uint32.h ./compile tcpclient.c tcprules: \ @@ -742,9 +752,9 @@ stralloc.h gen_alloc.h ./compile tcprulescheck.c tcpserver: \ -load tcpserver.o rules.o remoteinfo.o timeoutconn.o cdb.a dns.a \ +load tcpserver.o rules.o remoteinfo6.o timeoutconn6.o cdb.a dns.a \ time.a unix.a byte.a socket.lib - ./load tcpserver rules.o remoteinfo.o timeoutconn.o cdb.a \ + ./load tcpserver rules.o remoteinfo6.o timeoutconn6.o cdb.a \ dns.a time.a unix.a byte.a `cat socket.lib` tcpserver.o: \ @@ -753,7 +763,7 @@ exit.h env.h prot.h open.h wait.h readwrite.h stralloc.h gen_alloc.h \ alloc.h buffer.h error.h strerr.h sgetopt.h subgetopt.h pathexec.h \ socket.h uint16.h ndelay.h remoteinfo.h stralloc.h uint16.h rules.h \ stralloc.h sig.h dns.h stralloc.h iopause.h taia.h tai.h uint64.h \ -taia.h +taia.h uint32.h ./compile tcpserver.c time.a: \ @@ -765,9 +775,14 @@ taia_less.o taia_now.o taia_pack.o taia_sub.o taia_uint.o timeoutconn.o: \ compile timeoutconn.c ndelay.h socket.h uint16.h iopause.h taia.h \ -tai.h uint64.h error.h timeoutconn.h uint16.h +tai.h uint64.h error.h timeoutconn.h uint16.h uint32.h ./compile timeoutconn.c +timeoutconn6.o: \ +compile timeoutconn6.c ndelay.h socket.h uint16.h iopause.h taia.h \ +tai.h uint64.h error.h timeoutconn.h uint16.h uint32.h + ./compile timeoutconn6.c + uint16_pack.o: \ compile uint16_pack.c uint16.h ./compile uint16_pack.c @@ -806,7 +821,12 @@ socket_conn.o socket_delay.o socket_listen.o socket_local.o \ socket_opts.o socket_remote.o socket_tcp.o socket_udp.o \ stralloc_cat.o stralloc_catb.o stralloc_cats.o stralloc_copy.o \ stralloc_eady.o stralloc_opyb.o stralloc_opys.o stralloc_pend.o \ -strerr_die.o strerr_sys.o subgetopt.o wait_nohang.o wait_pid.o +strerr_die.o strerr_sys.o subgetopt.o wait_nohang.o wait_pid.o \ +socket_conn6.o socket_bind6.o socket_accept6.o socket_recv6.o \ +socket_send6.o socket_local6.o socket_remote6.o socket_tcp6.o \ +socket_getifname.o socket_getifidx.o socket_v4mappedprefix.o \ +socket_ip4loopback.o socket_v6any.o socket_v6loopback.o \ +socket_udp6.o ./makelib unix.a alloc.o alloc_re.o buffer.o buffer_0.o \ buffer_1.o buffer_2.o buffer_copy.o buffer_get.o \ buffer_put.o env.o error.o error_str.o fd_copy.o fd_move.o \ @@ -819,7 +839,12 @@ strerr_die.o strerr_sys.o subgetopt.o wait_nohang.o wait_pid.o socket_udp.o stralloc_cat.o stralloc_catb.o stralloc_cats.o \ stralloc_copy.o stralloc_eady.o stralloc_opyb.o \ stralloc_opys.o stralloc_pend.o strerr_die.o strerr_sys.o \ - subgetopt.o wait_nohang.o wait_pid.o + subgetopt.o wait_nohang.o wait_pid.o socket_conn6.o \ + socket_bind6.o socket_accept6.o socket_recv6.o socket_send6.o \ + socket_local6.o socket_remote6.o socket_tcp6.o \ + socket_getifname.o socket_getifidx.o socket_v4mappedprefix.o \ + socket_ip4loopback.o socket_v6any.o socket_v6loopback.o \ + socket_udp6.o wait_nohang.o: \ compile wait_nohang.c haswaitp.h @@ -835,3 +860,110 @@ warn-auto.sh who@.sh conf-home | sed s}HOME}"`head -1 conf-home`"}g \ > who@ chmod 755 who@ + +socket_conn6.o: \ +compile socket_conn6.c socket.h uint16.h haveip6.h error.h ip6.h \ +uint32.h + ./compile socket_conn6.c + +socket_bind6.o: \ +compile socket_bind6.c socket.h uint16.h haveip6.h error.h ip6.h \ +uint32.h + ./compile socket_bind6.c + +socket_accept6.o: \ +compile socket_accept6.c socket.h uint16.h haveip6.h error.h ip6.h \ +uint32.h + ./compile socket_accept6.c + +socket_recv6.o: \ +compile socket_recv6.c socket.h uint16.h haveip6.h error.h ip6.h \ +uint32.h + ./compile socket_recv6.c + +socket_send6.o: \ +compile socket_send6.c socket.h uint16.h haveip6.h error.h uint32.h + ./compile socket_send6.c + +socket_local6.o: \ +compile socket_local6.c socket.h uint16.h haveip6.h error.h uint32.h + ./compile socket_local6.c + +socket_remote6.o: \ +compile socket_remote6.c socket.h uint16.h haveip6.h error.h uint32.h + ./compile socket_remote6.c + +dns_sortip6.o: \ +compile dns_sortip6.c byte.h dns.h stralloc.h gen_alloc.h iopause.h \ +taia.h tai.h uint64.h taia.h + ./compile dns_sortip6.c + +dns_nd6.o: \ +compile dns_nd6.c byte.h fmt.h dns.h stralloc.h gen_alloc.h iopause.h \ +taia.h tai.h uint64.h taia.h + ./compile dns_nd6.c + +dns_ipq6.o: \ +compile dns_ipq6.c stralloc.h gen_alloc.h case.h byte.h str.h dns.h \ +stralloc.h iopause.h taia.h tai.h uint64.h taia.h ip6.h + ./compile dns_ipq6.c + +dns_ip6.o: \ +compile dns_ip6.c stralloc.h gen_alloc.h uint16.h byte.h dns.h \ +stralloc.h iopause.h taia.h tai.h uint64.h taia.h + ./compile dns_ip6.c + +fmt_xlong.o: \ +compile fmt_xlong.c scan.h + ./compile fmt_xlong.c + +scan_xlong.o: \ +compile scan_xlong.c scan.h + ./compile scan_xlong.c + +ip6_fmt.o: \ +compile ip6_fmt.c fmt.h ip6.h + ./compile ip6_fmt.c + +scan_ip6.o: \ +compile scan_ip6.c scan.h ip6.h + ./compile scan_ip6.c + +socket_tcp6.o: \ +compile socket_tcp6.c ndelay.h socket.h uint16.h haveip6.h uint32.h + ./compile socket_tcp6.c + +socket_udp6.o: \ +compile socket_udp6.c ndelay.h socket.h uint16.h haveip6.h uint32.h + ./compile socket_udp6.c + +haveip6.h: \ +tryip6.c choose compile haveip6.h1 haveip6.h2 + ./choose c tryip6 haveip6.h1 haveip6.h2 > haveip6.h + +socket_getifname.o: \ +compile socket_getifname.c socket.h uint16.h uint32.h + ./compile socket_getifname.c + +socket_getifidx.o: \ +compile socket_getifidx.c socket.h uint16.h uint32.h + ./compile socket_getifidx.c + +socket_ip4loopback.o: \ +compile socket_ip4loopback.c + ./compile socket_ip4loopback.c + +socket_v4mappedprefix.o: \ +compile socket_v4mappedprefix.c + ./compile socket_v4mappedprefix.c + +socket_v6any.o: \ +compile socket_v6any.c + ./compile socket_v6any.c + +socket_v6loopback.o: \ +compile socket_v6loopback.c + ./compile socket_v6loopback.c + +clean: + rm -f `cat TARGETS` diff --git a/ucspi-tcp-0.88/TARGETS b/ucspi-tcp-0.88/TARGETS index 4d1f2a0..0385f96 100644 --- a/ucspi-tcp-0.88/TARGETS +++ b/ucspi-tcp-0.88/TARGETS @@ -169,3 +169,31 @@ instcheck it setup check +dns_ip6.o +dns_ipq6.o +dns_nd6.o +dns_sortip6.o +fmt_xlong.o +ip6_fmt.o +ip6_scan.o +scan_0x.o +socket_accept6.o +socket_bind6.o +socket_conn6.o +socket_local6.o +socket_recv6.o +socket_remote6.o +socket_send6.o +socket_tcp6.o +timeoutconn6.o +haveip6.h +remoteinfo6.o +socket_getifidx.o +socket_getifname.o +scan_ip6.o +scan_xlong.o +socket_ip4loopback.o +socket_udp6.o +socket_v4mappedprefix.o +socket_v6any.o +socket_v6loopback.o diff --git a/ucspi-tcp-0.88/addcr.1 b/ucspi-tcp-0.88/addcr.1 new file mode 100644 index 0000000..3bae1f7 --- /dev/null +++ b/ucspi-tcp-0.88/addcr.1 @@ -0,0 +1,22 @@ +.TH addcr 1 +.SH NAME +addcr \- add a CR before each LF +.SH SYNOPSIS +.B addcr +.SH DESCRIPTION +.B addcr +inserts CR at the end of each line of input. +It does not insert CR at the end of a partial final line. +.SH COMPATIBILITY +Some vendors ship +.B unix2dos +or +.B bsd2dos +tools similar to +.BR addcr . +Those tools often blow up on long lines and nulls. +.B addcr +has no trouble with long lines and nulls. +.SH "SEE ALSO" +delcr(1), +fixcr(1) diff --git a/ucspi-tcp-0.88/argv0.1 b/ucspi-tcp-0.88/argv0.1 new file mode 100644 index 0000000..ad9634d --- /dev/null +++ b/ucspi-tcp-0.88/argv0.1 @@ -0,0 +1,47 @@ +.TH argv0 1 +.SH NAME +argv0 \- run a program with a specified 0th argument +.SH SYNOPSIS +.B argv0 +.I realname +.I zero +[ +.I arg ... +] +.SH DESCRIPTION +.B argv0 +runs +the program stored as +.I realname +on disk, +with the given +arguments. +It sets the 0th argument of +the program to +.IR zero . + +For example, + +.EX + argv0 /bin/csh -bin/csh +.EE + +runs +.B /bin/csh +with a 0th argument of +.BR -bin/csh . +.B csh +will think it is a login shell +and behave accordingly. + +.B argv0 +can be used to run some +.B inetd +wrappers under +.BR tcpserver . +.SH "SEE ALSO" +csh(1), +tcpserver(1), +execve(2), +execvp(3), +inetd(8) diff --git a/ucspi-tcp-0.88/date@.1 b/ucspi-tcp-0.88/date@.1 new file mode 100644 index 0000000..fa0ba98 --- /dev/null +++ b/ucspi-tcp-0.88/date@.1 @@ -0,0 +1,32 @@ +.TH date@ 1 +.SH NAME +date@ \- print the date on a host +.SH SYNTAX +.B date@ +[ +.I host +] +.SH DESCRIPTION +.B date@ +connects to TCP port 13 (Daytime) on +.I host +and prints any data it receives. +It removes CR and converts unprintable characters to a visible format. + +If +.I host +is not supplied, +.B date@ +connects to the local host. + +Some computers respond to port 13 with a human-readable date. +For example, they may be running + +.EX + tcpserver 0 13 date & +.EE +.SH "SEE ALSO" +cat(1), +delcr(1), +tcpclient(1), +tcpserver(1) diff --git a/ucspi-tcp-0.88/delcr.1 b/ucspi-tcp-0.88/delcr.1 new file mode 100644 index 0000000..18ea736 --- /dev/null +++ b/ucspi-tcp-0.88/delcr.1 @@ -0,0 +1,30 @@ +.TH delcr 1 +.SH NAME +delcr \- remove a CR before each LF +.SH SYNOPSIS +.B delcr +.SH DESCRIPTION +.B delcr +removes a CR at the end of each line of input, +if a CR is present. +It also removes a CR at the end of a partial final line. + +The pipeline + +.EX + addcr | delcr +.EE + +prints an exact copy of its input. +.SH COMPATIBILITY +Some vendors ship +.B dos2unix +or +.B dos2bsd +tools similar to +.BR delcr . +Those tools often blow up on long lines and nulls. +.B delcr +has no trouble with long lines and nulls. +.SH "SEE ALSO" +addcr(1) diff --git a/ucspi-tcp-0.88/dns.h b/ucspi-tcp-0.88/dns.h index 0948b1a..f06c5a8 100644 --- a/ucspi-tcp-0.88/dns.h +++ b/ucspi-tcp-0.88/dns.h @@ -34,51 +34,60 @@ struct dns_transmit { unsigned int curserver; struct taia deadline; unsigned int pos; - char *servers; - char localip[4]; + const char *servers; + char localip[16]; + unsigned int scope_id; char qtype[2]; } ; -extern void dns_random_init(char *); +extern void dns_random_init(const char *); extern unsigned int dns_random(unsigned int); extern void dns_sortip(char *,unsigned int); +extern void dns_sortip6(char *,unsigned int); extern void dns_domain_free(char **); -extern int dns_domain_copy(char **,char *); -extern unsigned int dns_domain_length(char *); -extern int dns_domain_equal(char *,char *); -extern char *dns_domain_suffix(char *,char *); -extern int dns_domain_fromdot(char **,char *,unsigned int); -extern int dns_domain_todot_cat(stralloc *,char *); +extern int dns_domain_copy(char **,const char *); +extern unsigned int dns_domain_length(const char *); +extern int dns_domain_equal(const char *,const char *); +extern int dns_domain_suffix(const char *,const char *); +extern unsigned int dns_domain_suffixpos(const char *,const char *); +extern int dns_domain_fromdot(char **,const char *,unsigned int); +extern int dns_domain_todot_cat(stralloc *,const char *); -extern unsigned int dns_packet_copy(char *,unsigned int,unsigned int,char *,unsigned int); -extern unsigned int dns_packet_getname(char *,unsigned int,unsigned int,char **); -extern unsigned int dns_packet_skipname(char *,unsigned int,unsigned int); -extern int dns_packet_nameequal(char *,unsigned int,unsigned int,char *,unsigned int,unsigned int); +extern unsigned int dns_packet_copy(const char *,unsigned int,unsigned int,char *,unsigned int); +extern unsigned int dns_packet_getname(const char *,unsigned int,unsigned int,char **); +extern unsigned int dns_packet_skipname(const char *,unsigned int,unsigned int); -extern int dns_transmit_start(struct dns_transmit *,char *,int,char *,char *,char *); +extern int dns_transmit_start(struct dns_transmit *,const char *,int,const char *,const char *,const char *); extern void dns_transmit_free(struct dns_transmit *); extern void dns_transmit_io(struct dns_transmit *,iopause_fd *,struct taia *); -extern int dns_transmit_get(struct dns_transmit *,iopause_fd *,struct taia *); +extern int dns_transmit_get(struct dns_transmit *,const iopause_fd *,const struct taia *); extern int dns_resolvconfip(char *); -extern int dns_resolve(char *,char *); +extern int dns_resolve(const char *,const char *); extern struct dns_transmit dns_resolve_tx; -extern int dns_ip4_packet(stralloc *,char *,unsigned int); -extern int dns_ip4(stralloc *,stralloc *); -extern int dns_name_packet(stralloc *,char *,unsigned int); -extern void dns_name4_domain(char *,char *); +extern int dns_ip4_packet(stralloc *,const char *,unsigned int); +extern int dns_ip4(stralloc *,const stralloc *); +extern int dns_ip6_packet(stralloc *,const char *,unsigned int); +extern int dns_ip6(stralloc *,stralloc *); +extern int dns_name_packet(stralloc *,const char *,unsigned int); +extern void dns_name4_domain(char *,const char *); #define DNS_NAME4_DOMAIN 31 -extern int dns_name4(stralloc *,char *); -extern int dns_txt_packet(stralloc *,char *,unsigned int); -extern int dns_txt(stralloc *,stralloc *); -extern int dns_mx_packet(stralloc *,char *,unsigned int); -extern int dns_mx(stralloc *,stralloc *); +extern int dns_name4(stralloc *,const char *); +extern int dns_txt_packet(stralloc *,const char *,unsigned int); +extern int dns_txt(stralloc *,const stralloc *); +extern int dns_mx_packet(stralloc *,const char *,unsigned int); +extern int dns_mx(stralloc *,const stralloc *); extern int dns_resolvconfrewrite(stralloc *); -extern int dns_ip4_qualify_rules(stralloc *,stralloc *,stralloc *,stralloc *); -extern int dns_ip4_qualify(stralloc *,stralloc *,stralloc *); +extern int dns_ip4_qualify_rules(stralloc *,stralloc *,const stralloc *,const stralloc *); +extern int dns_ip4_qualify(stralloc *,stralloc *,const stralloc *); +extern int dns_ip6_qualify_rules(stralloc *,stralloc *,const stralloc *,const stralloc *); +extern int dns_ip6_qualify(stralloc *,stralloc *,const stralloc *); + +extern int dns_name6_domain(char *,char *); +#define DNS_NAME6_DOMAIN (4*16+11) #endif diff --git a/ucspi-tcp-0.88/dns_dfd.c b/ucspi-tcp-0.88/dns_dfd.c index 14a29d8..c924718 100644 --- a/ucspi-tcp-0.88/dns_dfd.c +++ b/ucspi-tcp-0.88/dns_dfd.c @@ -1,9 +1,10 @@ -#include "error.h" -#include "alloc.h" +#include <stdlib.h> +#include <errno.h> #include "byte.h" #include "dns.h" +#include "error.h" -int dns_domain_fromdot(char **out,char *buf,unsigned int n) +int dns_domain_fromdot(char **out,const char *buf,unsigned int n) { char label[63]; unsigned int labellen = 0; /* <= sizeof label */ @@ -59,11 +60,11 @@ int dns_domain_fromdot(char **out,char *buf,unsigned int n) if (namelen + 1 > sizeof name) return 0; name[namelen++] = 0; - x = alloc(namelen); + x = malloc(namelen); if (!x) return 0; byte_copy(x,namelen,name); - if (*out) alloc_free(*out); + if (*out) free(*out); *out = x; return 1; } diff --git a/ucspi-tcp-0.88/dns_domain.c b/ucspi-tcp-0.88/dns_domain.c index f898485..80ac5ea 100644 --- a/ucspi-tcp-0.88/dns_domain.c +++ b/ucspi-tcp-0.88/dns_domain.c @@ -1,16 +1,15 @@ -#include "error.h" -#include "alloc.h" +#include <stdlib.h> #include "case.h" #include "byte.h" #include "dns.h" -unsigned int dns_domain_length(char *dn) +unsigned int dns_domain_length(const char *dn) { - char *x; + const char *x; unsigned char c; x = dn; - while (c = *x++) + while ((c = *x++)) x += (unsigned int) c; return x - dn; } @@ -18,26 +17,26 @@ unsigned int dns_domain_length(char *dn) void dns_domain_free(char **out) { if (*out) { - alloc_free(*out); + free(*out); *out = 0; } } -int dns_domain_copy(char **out,char *in) +int dns_domain_copy(char **out,const char *in) { unsigned int len; char *x; len = dns_domain_length(in); - x = alloc(len); + x = malloc(len); if (!x) return 0; byte_copy(x,len,in); - if (*out) alloc_free(*out); + if (*out) free(*out); *out = x; return 1; } -int dns_domain_equal(char *dn1,char *dn2) +int dns_domain_equal(const char *dn1,const char *dn2) { unsigned int len; @@ -48,12 +47,25 @@ int dns_domain_equal(char *dn1,char *dn2) return 1; } -char *dns_domain_suffix(char *big,char *little) +int dns_domain_suffix(const char *big,const char *little) +{ + unsigned char c; + + for (;;) { + if (dns_domain_equal(big,little)) return 1; + c = *big++; + if (!c) return 0; + big += c; + } +} + +unsigned int dns_domain_suffixpos(const char *big,const char *little) { + const char *orig = big; unsigned char c; for (;;) { - if (dns_domain_equal(big,little)) return big; + if (dns_domain_equal(big,little)) return big - orig; c = *big++; if (!c) return 0; big += c; diff --git a/ucspi-tcp-0.88/dns_dtda.c b/ucspi-tcp-0.88/dns_dtda.c index 00b41a1..ba1db4f 100644 --- a/ucspi-tcp-0.88/dns_dtda.c +++ b/ucspi-tcp-0.88/dns_dtda.c @@ -1,7 +1,7 @@ #include "stralloc.h" #include "dns.h" -int dns_domain_todot_cat(stralloc *out,char *d) +int dns_domain_todot_cat(stralloc *out,const char *d) { char ch; char ch2; diff --git a/ucspi-tcp-0.88/dns_ip.c b/ucspi-tcp-0.88/dns_ip.c index fb0526c..e7c3a9a 100644 --- a/ucspi-tcp-0.88/dns_ip.c +++ b/ucspi-tcp-0.88/dns_ip.c @@ -3,7 +3,7 @@ #include "byte.h" #include "dns.h" -int dns_ip4_packet(stralloc *out,char *buf,unsigned int len) +int dns_ip4_packet(stralloc *out,const char *buf,unsigned int len) { unsigned int pos; char header[12]; @@ -36,7 +36,7 @@ int dns_ip4_packet(stralloc *out,char *buf,unsigned int len) static char *q = 0; -int dns_ip4(stralloc *out,stralloc *fqdn) +int dns_ip4(stralloc *out,const stralloc *fqdn) { unsigned int i; char code; diff --git a/ucspi-tcp-0.88/dns_ip6.c b/ucspi-tcp-0.88/dns_ip6.c new file mode 100644 index 0000000..1a2ce08 --- /dev/null +++ b/ucspi-tcp-0.88/dns_ip6.c @@ -0,0 +1,103 @@ +#include "stralloc.h" +#include "uint16.h" +#include "byte.h" +#include "dns.h" +#include "ip4.h" +#include "ip6.h" + +static int dns_ip6_packet_add(stralloc *out,const char *buf,unsigned int len) +{ + unsigned int pos; + char header[16]; + uint16 numanswers; + uint16 datalen; + + pos = dns_packet_copy(buf,len,0,header,12); if (!pos) return -1; + uint16_unpack_big(header + 6,&numanswers); + pos = dns_packet_skipname(buf,len,pos); if (!pos) return -1; + pos += 4; + + while (numanswers--) { + pos = dns_packet_skipname(buf,len,pos); if (!pos) return -1; + pos = dns_packet_copy(buf,len,pos,header,10); if (!pos) return -1; + uint16_unpack_big(header + 8,&datalen); + if (byte_equal(header,2,DNS_T_AAAA)) { + if (byte_equal(header + 2,2,DNS_C_IN)) + if (datalen == 16) { + if (!dns_packet_copy(buf,len,pos,header,16)) return -1; + if (!stralloc_catb(out,header,16)) return -1; + } + } else if (byte_equal(header,2,DNS_T_A)) + if (byte_equal(header + 2,2,DNS_C_IN)) + if (datalen == 4) { + byte_copy(header,12,V4mappedprefix); + if (!dns_packet_copy(buf,len,pos,header+12,4)) return -1; + if (!stralloc_catb(out,header,16)) return -1; + } + pos += datalen; + } + + dns_sortip6(out->s,out->len); + return 0; +} + +int dns_ip6_packet(stralloc *out,const char *buf,unsigned int len) { + if (!stralloc_copys(out,"")) return -1; + return dns_ip6_packet_add(out,buf,len); +} + +static char *q = 0; + +int dns_ip6(stralloc *out,stralloc *fqdn) +{ + unsigned int i; + char code; + char ch; + char ip[16]; + + if (!stralloc_copys(out,"")) return -1; + if (!stralloc_readyplus(fqdn,1)) return -1; + fqdn->s[fqdn->len]=0; + if ((i=scan_ip6(fqdn->s,ip))) { + if (fqdn->s[i]) return -1; + stralloc_copyb(out,ip,16); + return 0; + } + code = 0; + for (i = 0;i <= fqdn->len;++i) { + if (i < fqdn->len) + ch = fqdn->s[i]; + else + ch = '.'; + + if ((ch == '[') || (ch == ']')) continue; + if (ch == '.') { + if (!stralloc_append(out,&code)) return -1; + code = 0; + continue; + } + if ((ch >= '0') && (ch <= '9')) { + code *= 10; + code += ch - '0'; + continue; + } + + if (!dns_domain_fromdot(&q,fqdn->s,fqdn->len)) return -1; + if (!stralloc_copys(out,"")) return -1; + if (dns_resolve(q,DNS_T_AAAA) != -1) + if (dns_ip6_packet_add(out,dns_resolve_tx.packet,dns_resolve_tx.packetlen) != -1) { + dns_transmit_free(&dns_resolve_tx); + dns_domain_free(&q); + } + if (!dns_domain_fromdot(&q,fqdn->s,fqdn->len)) return -1; + if (dns_resolve(q,DNS_T_A) != -1) + if (dns_ip6_packet_add(out,dns_resolve_tx.packet,dns_resolve_tx.packetlen) != -1) { + dns_transmit_free(&dns_resolve_tx); + dns_domain_free(&q); + } + return out->a>0?0:-1; + } + + out->len &= ~3; + return 0; +} diff --git a/ucspi-tcp-0.88/dns_ipq.c b/ucspi-tcp-0.88/dns_ipq.c index 8181ab7..5b65e23 100644 --- a/ucspi-tcp-0.88/dns_ipq.c +++ b/ucspi-tcp-0.88/dns_ipq.c @@ -4,7 +4,7 @@ #include "str.h" #include "dns.h" -static int doit(stralloc *work,char *rule) +static int doit(stralloc *work,const char *rule) { char ch; unsigned int colon; @@ -30,7 +30,7 @@ static int doit(stralloc *work,char *rule) return stralloc_cats(work,rule + colon + 1); } -int dns_ip4_qualify_rules(stralloc *out,stralloc *fqdn,stralloc *in,stralloc *rules) +int dns_ip4_qualify_rules(stralloc *out,stralloc *fqdn,const stralloc *in,const stralloc *rules) { unsigned int i; unsigned int j; @@ -63,7 +63,7 @@ int dns_ip4_qualify_rules(stralloc *out,stralloc *fqdn,stralloc *in,stralloc *ru } } -int dns_ip4_qualify(stralloc *out,stralloc *fqdn,stralloc *in) +int dns_ip4_qualify(stralloc *out,stralloc *fqdn,const stralloc *in) { static stralloc rules; if (dns_resolvconfrewrite(&rules) == -1) return -1; diff --git a/ucspi-tcp-0.88/dns_ipq6.c b/ucspi-tcp-0.88/dns_ipq6.c new file mode 100644 index 0000000..d5cea12 --- /dev/null +++ b/ucspi-tcp-0.88/dns_ipq6.c @@ -0,0 +1,72 @@ +#include "stralloc.h" +#include "case.h" +#include "byte.h" +#include "str.h" +#include "dns.h" + +static int doit(stralloc *work,const char *rule) +{ + char ch; + unsigned int colon; + unsigned int prefixlen; + + ch = *rule++; + if ((ch != '?') && (ch != '=') && (ch != '*') && (ch != '-')) return 1; + colon = str_chr(rule,':'); + if (!rule[colon]) return 1; + + if (work->len < colon) return 1; + prefixlen = work->len - colon; + if ((ch == '=') && prefixlen) return 1; + if (case_diffb(rule,colon,work->s + prefixlen)) return 1; + if (ch == '?') { + if (byte_chr(work->s,prefixlen,'.') < prefixlen) return 1; + if (byte_chr(work->s,prefixlen,':') < prefixlen) return 1; + if (byte_chr(work->s,prefixlen,'[') < prefixlen) return 1; + if (byte_chr(work->s,prefixlen,']') < prefixlen) return 1; + } + + work->len = prefixlen; + if (ch == '-') work->len = 0; + return stralloc_cats(work,rule + colon + 1); +} + +int dns_ip6_qualify_rules(stralloc *out,stralloc *fqdn,const stralloc *in,const stralloc *rules) +{ + unsigned int i; + unsigned int j; + unsigned int plus; + unsigned int fqdnlen; + + if (!stralloc_copy(fqdn,in)) return -1; + + for (j = i = 0;j < rules->len;++j) + if (!rules->s[j]) { + if (!doit(fqdn,rules->s + i)) return -1; + i = j + 1; + } + + fqdnlen = fqdn->len; + plus = byte_chr(fqdn->s,fqdnlen,'+'); + if (plus >= fqdnlen) + return dns_ip6(out,fqdn); + + i = plus + 1; + for (;;) { + j = byte_chr(fqdn->s + i,fqdnlen - i,'+'); + byte_copy(fqdn->s + plus,j,fqdn->s + i); + fqdn->len = plus + j; + if (dns_ip6(out,fqdn) == -1) return -1; + if (out->len) return 0; + i += j; + if (i >= fqdnlen) return 0; + ++i; + } +} + +int dns_ip6_qualify(stralloc *out,stralloc *fqdn,const stralloc *in) +{ + static stralloc rules; + if (dns_resolvconfrewrite(&rules) == -1) return -1; + return dns_ip6_qualify_rules(out,fqdn,in,&rules); +} diff --git a/ucspi-tcp-0.88/dns_name.c b/ucspi-tcp-0.88/dns_name.c index dcb10c7..1f03186 100644 --- a/ucspi-tcp-0.88/dns_name.c +++ b/ucspi-tcp-0.88/dns_name.c @@ -2,10 +2,11 @@ #include "uint16.h" #include "byte.h" #include "dns.h" +#include "ip6.h" static char *q = 0; -int dns_name_packet(stralloc *out,char *buf,unsigned int len) +int dns_name_packet(stralloc *out,const char *buf,unsigned int len) { unsigned int pos; char header[12]; @@ -35,7 +36,7 @@ int dns_name_packet(stralloc *out,char *buf,unsigned int len) return 0; } -int dns_name4(stralloc *out,char ip[4]) +int dns_name4(stralloc *out,const char ip[4]) { char name[DNS_NAME4_DOMAIN]; @@ -46,3 +47,17 @@ int dns_name4(stralloc *out,char ip[4]) dns_domain_free(&q); return 0; } + +int dns_name6(stralloc *out,char ip[16]) +{ + char name[DNS_NAME6_DOMAIN]; + + if (ip6_isv4mapped(ip)) + return dns_name4(out,ip+12); + dns_name6_domain(name,ip); + if (dns_resolve(name,DNS_T_PTR) == -1) return -1; + if (dns_name_packet(out,dns_resolve_tx.packet,dns_resolve_tx.packetlen) == -1) return -1; + dns_transmit_free(&dns_resolve_tx); + dns_domain_free(&q); + return 0; +} diff --git a/ucspi-tcp-0.88/dns_nd.c b/ucspi-tcp-0.88/dns_nd.c index 279d74d..aa54e5d 100644 --- a/ucspi-tcp-0.88/dns_nd.c +++ b/ucspi-tcp-0.88/dns_nd.c @@ -2,7 +2,7 @@ #include "fmt.h" #include "dns.h" -void dns_name4_domain(char name[DNS_NAME4_DOMAIN],char ip[4]) +void dns_name4_domain(char name[DNS_NAME4_DOMAIN],const char ip[4]) { unsigned int namelen; unsigned int i; diff --git a/ucspi-tcp-0.88/dns_nd6.c b/ucspi-tcp-0.88/dns_nd6.c new file mode 100644 index 0000000..fb1da88 --- /dev/null +++ b/ucspi-tcp-0.88/dns_nd6.c @@ -0,0 +1,28 @@ +#include "byte.h" +#include "fmt.h" +#include "dns.h" + +/* RFC1886: + * 4321:0:1:2:3:4:567:89ab + * -> + * b.a.9.8.7.6.5.0.4.0.0.0.3.0.0.0.2.0.0.0.1.0.0.0.0.0.0.0.1.2.3.4.IP6.INT. + */ + +static inline char tohex(char c) { + return c>=10?c-10+'a':c+'0'; +} + +int dns_name6_domain(char name[DNS_NAME6_DOMAIN],char ip[16]) +{ + unsigned int j; + + for (j=0; j<16; j++) { + name[j*4]=1; + name[j*4+1]=tohex(ip[15-j] & 15); + name[j*4+2]=1; + name[j*4+3]=tohex((unsigned char)ip[15-j] >> 4); + } + byte_copy(name + 4*16,10,"\3ip6\4arpa\0"); + return 4*16+10; +} + diff --git a/ucspi-tcp-0.88/dns_packet.c b/ucspi-tcp-0.88/dns_packet.c index 04a2cc8..72cfb35 100644 --- a/ucspi-tcp-0.88/dns_packet.c +++ b/ucspi-tcp-0.88/dns_packet.c @@ -2,10 +2,11 @@ DNS should have used LZ77 instead of its own sophomoric compression algorithm. */ -#include "error.h" +#include <errno.h> #include "dns.h" +#include "error.h" -unsigned int dns_packet_copy(char *buf,unsigned int len,unsigned int pos,char *out,unsigned int outlen) +unsigned int dns_packet_copy(const char *buf,unsigned int len,unsigned int pos,char *out,unsigned int outlen) { while (outlen) { if (pos >= len) { errno = error_proto; return 0; } @@ -15,7 +16,7 @@ unsigned int dns_packet_copy(char *buf,unsigned int len,unsigned int pos,char *o return pos; } -unsigned int dns_packet_skipname(char *buf,unsigned int len,unsigned int pos) +unsigned int dns_packet_skipname(const char *buf,unsigned int len,unsigned int pos) { unsigned char ch; @@ -32,7 +33,7 @@ unsigned int dns_packet_skipname(char *buf,unsigned int len,unsigned int pos) return 0; } -unsigned int dns_packet_getname(char *buf,unsigned int len,unsigned int pos,char **d) +unsigned int dns_packet_getname(const char *buf,unsigned int len,unsigned int pos,char **d) { unsigned int loop = 0; unsigned int state = 0; diff --git a/ucspi-tcp-0.88/dns_random.c b/ucspi-tcp-0.88/dns_random.c index b9892b4..2158ed4 100644 --- a/ucspi-tcp-0.88/dns_random.c +++ b/ucspi-tcp-0.88/dns_random.c @@ -1,3 +1,4 @@ +#include <unistd.h> #include "dns.h" #include "taia.h" #include "uint32.h" @@ -29,7 +30,7 @@ static void surf(void) } } -void dns_random_init(char data[128]) +void dns_random_init(const char data[128]) { int i; struct taia t; diff --git a/ucspi-tcp-0.88/dns_rcip.c b/ucspi-tcp-0.88/dns_rcip.c index 2356c8b..794f6be 100644 --- a/ucspi-tcp-0.88/dns_rcip.c +++ b/ucspi-tcp-0.88/dns_rcip.c @@ -2,12 +2,13 @@ #include "openreadclose.h" #include "byte.h" #include "ip4.h" -#include "env.h" +#include "ip6.h" #include "dns.h" +#include "env.h" static stralloc data = {0}; -static int init(char ip[64]) +static int init(char ip[256]) { int i; int j; @@ -16,15 +17,16 @@ static int init(char ip[64]) x = env_get("DNSCACHEIP"); if (x) - while (iplen <= 60) + while (iplen <= 60) { if (*x == '.') ++x; else { - i = ip4_scan(x,ip + iplen); + i = scan_ip6(x,ip + iplen); if (!i) break; x += i; - iplen += 4; + iplen += 16; } + } if (!iplen) { i = openreadclose("/etc/resolv.conf",&data,64); @@ -39,8 +41,9 @@ static int init(char ip[64]) while ((data.s[i] == ' ') || (data.s[i] == '\t')) ++i; if (iplen <= 60) - if (ip4_scan(data.s + i,ip + iplen)) - iplen += 4; + if (scan_ip6(data.s + i,ip + iplen)) { + iplen += 16; + } } i = j + 1; } @@ -48,19 +51,19 @@ static int init(char ip[64]) } if (!iplen) { - byte_copy(ip,4,"\177\0\0\1"); - iplen = 4; + byte_copy(ip,16,"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\1"); + iplen = 16; } - byte_zero(ip + iplen,64 - iplen); + byte_zero(ip + iplen,256 - iplen); return 0; } static int ok = 0; static unsigned int uses; static struct taia deadline; -static char ip[64]; /* defined if ok */ +static char ip[256]; /* defined if ok */ -int dns_resolvconfip(char s[64]) +int dns_resolvconfip(char s[256]) { struct taia now; @@ -77,6 +80,6 @@ int dns_resolvconfip(char s[64]) } --uses; - byte_copy(s,64,ip); + byte_copy(s,256,ip); return 0; } diff --git a/ucspi-tcp-0.88/dns_rcrw.c b/ucspi-tcp-0.88/dns_rcrw.c index 6f215ac..b0c8e6d 100644 --- a/ucspi-tcp-0.88/dns_rcrw.c +++ b/ucspi-tcp-0.88/dns_rcrw.c @@ -1,16 +1,17 @@ +#include <unistd.h> #include "taia.h" -#include "env.h" #include "byte.h" #include "str.h" #include "openreadclose.h" #include "dns.h" +#include "env.h" static stralloc data = {0}; static int init(stralloc *rules) { char host[256]; - char *x; + const char *x; int i; int j; int k; diff --git a/ucspi-tcp-0.88/dns_resolve.c b/ucspi-tcp-0.88/dns_resolve.c index 3365c00..82b5bbb 100644 --- a/ucspi-tcp-0.88/dns_resolve.c +++ b/ucspi-tcp-0.88/dns_resolve.c @@ -2,19 +2,20 @@ #include "taia.h" #include "byte.h" #include "dns.h" +#include "ip6.h" struct dns_transmit dns_resolve_tx = {0}; -int dns_resolve(char *q,char qtype[2]) +int dns_resolve(const char *q,const char qtype[2]) { struct taia stamp; struct taia deadline; - char servers[64]; + char servers[256]; iopause_fd x[1]; int r; if (dns_resolvconfip(servers) == -1) return -1; - if (dns_transmit_start(&dns_resolve_tx,servers,1,q,qtype,"\0\0\0\0") == -1) return -1; + if (dns_transmit_start(&dns_resolve_tx,servers,1,q,qtype,V6any) == -1) return -1; for (;;) { taia_now(&stamp); diff --git a/ucspi-tcp-0.88/dns_sortip6.c b/ucspi-tcp-0.88/dns_sortip6.c new file mode 100644 index 0000000..7e752e9 --- /dev/null +++ b/ucspi-tcp-0.88/dns_sortip6.c @@ -0,0 +1,20 @@ +#include "byte.h" +#include "dns.h" + +/* XXX: sort servers by configurable notion of closeness? */ +/* XXX: pay attention to competence of each server? */ + +void dns_sortip6(char *s,unsigned int n) +{ + unsigned int i; + char tmp[16]; + + n >>= 4; + while (n > 1) { + i = dns_random(n); + --n; + byte_copy(tmp,16,s + (i << 4)); + byte_copy(s + (i << 4),16,s + (n << 4)); + byte_copy(s + (n << 4),16,tmp); + } +} diff --git a/ucspi-tcp-0.88/dns_transmit.c b/ucspi-tcp-0.88/dns_transmit.c index df12826..9511511 100644 --- a/ucspi-tcp-0.88/dns_transmit.c +++ b/ucspi-tcp-0.88/dns_transmit.c @@ -1,12 +1,15 @@ +#include <sys/types.h> +#include <sys/socket.h> +#include <unistd.h> +#include <stdlib.h> #include "socket.h" -#include "alloc.h" -#include "error.h" +#include <errno.h> #include "byte.h" -#include "readwrite.h" #include "uint16.h" #include "dns.h" +#include "ip6.h" -static int serverwantstcp(char *buf,unsigned int len) +static int serverwantstcp(const char *buf,unsigned int len) { char out[12]; @@ -15,7 +18,7 @@ static int serverwantstcp(char *buf,unsigned int len) return 0; } -static int serverfailed(char *buf,unsigned int len) +static int serverfailed(const char *buf,unsigned int len) { char out[12]; unsigned int rcode; @@ -23,11 +26,11 @@ static int serverfailed(char *buf,unsigned int len) if (!dns_packet_copy(buf,len,0,out,12)) return 1; rcode = out[3]; rcode &= 15; - if (rcode && (rcode != 3)) { errno = error_again; return 1; } + if (rcode && (rcode != 3)) { errno = EAGAIN; return 1; } return 0; } -static int irrelevant(struct dns_transmit *d,char *buf,unsigned int len) +static int irrelevant(const struct dns_transmit *d,const char *buf,unsigned int len) { char out[12]; char *dn; @@ -40,8 +43,8 @@ static int irrelevant(struct dns_transmit *d,char *buf,unsigned int len) dn = 0; pos = dns_packet_getname(buf,len,pos,&dn); if (!pos) return 1; - if (!dns_domain_equal(dn,d->query + 14)) { alloc_free(dn); return 1; } - alloc_free(dn); + if (!dns_domain_equal(dn,d->query + 14)) { free(dn); return 1; } + free(dn); pos = dns_packet_copy(buf,len,pos,out,4); if (!pos) return 1; if (byte_diff(out,2,d->qtype)) return 1; @@ -53,14 +56,14 @@ static int irrelevant(struct dns_transmit *d,char *buf,unsigned int len) static void packetfree(struct dns_transmit *d) { if (!d->packet) return; - alloc_free(d->packet); + free(d->packet); d->packet = 0; } static void queryfree(struct dns_transmit *d) { if (!d->query) return; - alloc_free(d->query); + free(d->query); d->query = 0; } @@ -83,9 +86,9 @@ static int randombind(struct dns_transmit *d) int j; for (j = 0;j < 10;++j) - if (socket_bind4(d->s1 - 1,d->localip,1025 + dns_random(64510)) == 0) + if (socket_bind6(d->s1 - 1,d->localip,1025 + dns_random(64510),d->scope_id) == 0) return 0; - if (socket_bind4(d->s1 - 1,d->localip,0) == 0) + if (socket_bind6(d->s1 - 1,d->localip,0,d->scope_id) == 0) return 0; return -1; } @@ -94,22 +97,22 @@ static const int timeouts[4] = { 1, 3, 11, 45 }; static int thisudp(struct dns_transmit *d) { - char *ip; + const char *ip; socketfree(d); while (d->udploop < 4) { for (;d->curserver < 16;++d->curserver) { - ip = d->servers + 4 * d->curserver; - if (byte_diff(ip,4,"\0\0\0\0")) { + ip = d->servers + 16 * d->curserver; + if (byte_diff(ip,16,V6any)) { d->query[2] = dns_random(256); d->query[3] = dns_random(256); - d->s1 = 1 + socket_udp(); + d->s1 = 1 + socket_udp6(); if (!d->s1) { dns_transmit_free(d); return -1; } if (randombind(d) == -1) { dns_transmit_free(d); return -1; } - if (socket_connect4(d->s1 - 1,ip,53) == 0) + if (socket_connect6(d->s1 - 1,ip,53,d->scope_id) == 0) if (send(d->s1 - 1,d->query + 2,d->querylen - 2,0) == d->querylen - 2) { struct taia now; taia_now(&now); @@ -145,29 +148,29 @@ static int nextudp(struct dns_transmit *d) static int thistcp(struct dns_transmit *d) { struct taia now; - char *ip; + const char *ip; socketfree(d); packetfree(d); for (;d->curserver < 16;++d->curserver) { - ip = d->servers + 4 * d->curserver; - if (byte_diff(ip,4,"\0\0\0\0")) { + ip = d->servers + 16 * d->curserver; + if (byte_diff(ip,16,V6any)) { d->query[2] = dns_random(256); d->query[3] = dns_random(256); - d->s1 = 1 + socket_tcp(); + d->s1 = 1 + socket_tcp6(); if (!d->s1) { dns_transmit_free(d); return -1; } if (randombind(d) == -1) { dns_transmit_free(d); return -1; } taia_now(&now); taia_uint(&d->deadline,10); taia_add(&d->deadline,&d->deadline,&now); - if (socket_connect4(d->s1 - 1,ip,53) == 0) { + if (socket_connect6(d->s1 - 1,ip,53,d->scope_id) == 0) { d->tcpstate = 2; return 0; } - if ((errno == error_inprogress) || (errno == error_wouldblock)) { + if ((errno == EINPROGRESS) || (errno == EWOULDBLOCK)) { d->tcpstate = 1; return 0; } @@ -191,16 +194,16 @@ static int nexttcp(struct dns_transmit *d) return thistcp(d); } -int dns_transmit_start(struct dns_transmit *d,char servers[64],int flagrecursive,char *q,char qtype[2],char localip[4]) +int dns_transmit_start(struct dns_transmit *d,const char servers[256],int flagrecursive,const char *q,const char qtype[2],const char localip[16]) { unsigned int len; dns_transmit_free(d); - errno = error_io; + errno = EIO; len = dns_domain_length(q); d->querylen = len + 18; - d->query = alloc(d->querylen); + d->query = malloc(d->querylen); if (!d->query) return -1; uint16_pack_big(d->query,len + 16); @@ -211,7 +214,7 @@ int dns_transmit_start(struct dns_transmit *d,char servers[64],int flagrecursive byte_copy(d->qtype,2,qtype); d->servers = servers; - byte_copy(d->localip,4,localip); + byte_copy(d->localip,16,localip); d->udploop = flagrecursive ? 1 : 0; @@ -236,19 +239,19 @@ void dns_transmit_io(struct dns_transmit *d,iopause_fd *x,struct taia *deadline) *deadline = d->deadline; } -int dns_transmit_get(struct dns_transmit *d,iopause_fd *x,struct taia *when) +int dns_transmit_get(struct dns_transmit *d,const iopause_fd *x,const struct taia *when) { char udpbuf[513]; unsigned char ch; int r; int fd; - errno = error_io; + errno = EIO; fd = d->s1 - 1; if (!x->revents) { if (taia_less(when,&d->deadline)) return 0; - errno = error_timeout; + errno = ETIMEDOUT; if (d->tcpstate == 0) return nextudp(d); return nexttcp(d); } @@ -260,7 +263,7 @@ have sent query to curserver on UDP socket s */ r = recv(fd,udpbuf,sizeof udpbuf,0); if (r <= 0) { - if (d->udploop == 2) return 0; + if (errno == ECONNREFUSED) if (d->udploop == 2) return 0; return nextudp(d); } if (r + 1 > sizeof udpbuf) return 0; @@ -274,7 +277,7 @@ have sent query to curserver on UDP socket s socketfree(d); d->packetlen = r; - d->packet = alloc(d->packetlen); + d->packet = malloc(d->packetlen); if (!d->packet) { dns_transmit_free(d); return -1; } byte_copy(d->packet,d->packetlen,udpbuf); queryfree(d); @@ -334,7 +337,7 @@ have received one byte of packet length into packetlen d->packetlen += ch; d->tcpstate = 5; d->pos = 0; - d->packet = alloc(d->packetlen); + d->packet = malloc(d->packetlen); if (!d->packet) { dns_transmit_free(d); return -1; } return 0; } diff --git a/ucspi-tcp-0.88/dns_txt.c b/ucspi-tcp-0.88/dns_txt.c index 263b641..44deafe 100644 --- a/ucspi-tcp-0.88/dns_txt.c +++ b/ucspi-tcp-0.88/dns_txt.c @@ -3,7 +3,7 @@ #include "byte.h" #include "dns.h" -int dns_txt_packet(stralloc *out,char *buf,unsigned int len) +int dns_txt_packet(stralloc *out,const char *buf,unsigned int len) { unsigned int pos; char header[12]; @@ -48,7 +48,7 @@ int dns_txt_packet(stralloc *out,char *buf,unsigned int len) static char *q = 0; -int dns_txt(stralloc *out,stralloc *fqdn) +int dns_txt(stralloc *out,const stralloc *fqdn) { if (!dns_domain_fromdot(&q,fqdn->s,fqdn->len)) return -1; if (dns_resolve(q,DNS_T_TXT) == -1) return -1; diff --git a/ucspi-tcp-0.88/finger@.1 b/ucspi-tcp-0.88/finger@.1 new file mode 100644 index 0000000..93b6288 --- /dev/null +++ b/ucspi-tcp-0.88/finger@.1 @@ -0,0 +1,45 @@ +.TH finger@ 1 +.SH NAME +finger@ \- get user information from a host +.SH SYNTAX +.B finger@ +[ +.I host +[ +.I user +] +] +.SH DESCRIPTION +.B finger@ +connects to TCP port 79 (Finger) on +.IR host , +sends +.I user +(with an extra CR) +to +.IR host , +and prints any data it receives. +It removes CR and converts unprintable characters to a visible format. +Some computers respond to port 79 with information about +.IR user . + +If +.I user +is not supplied, +.B finger@ +sends a blank line to +.IR host . +Some computers respond with information about +all the users who are logged in. + +If +.I host +is not supplied, +.B finger@ +connects to the local host. +.SH "SEE ALSO" +addcr(1), +cat(1), +delcr(1), +finger(1), +tcpclient(1) diff --git a/ucspi-tcp-0.88/fixcr.1 b/ucspi-tcp-0.88/fixcr.1 new file mode 100644 index 0000000..ebb8b53 --- /dev/null +++ b/ucspi-tcp-0.88/fixcr.1 @@ -0,0 +1,11 @@ +.TH fixcr 1 +.SH NAME +fixcr \- make sure that there is a CR before each LF +.SH SYNOPSIS +.B fixcr +.SH DESCRIPTION +.B fixcr +inserts CR at the end of each line of input where a CR is not already present. +It does not insert CR at the end of a partial final line. +.SH "SEE ALSO" +addcr(1) diff --git a/ucspi-tcp-0.88/fmt_xlong.c b/ucspi-tcp-0.88/fmt_xlong.c new file mode 100644 index 0000000..332fc9a --- /dev/null +++ b/ucspi-tcp-0.88/fmt_xlong.c @@ -0,0 +1,22 @@ +#include "fmt.h" + +char tohex(char num) { + if (num<10) + return num+'0'; + else if (num<16) + return num-10+'a'; + else + return -1; +} + +unsigned int fmt_xlong(register char *s,register unsigned long u) +{ + register unsigned int len; register unsigned long q; + len = 1; q = u; + while (q > 15) { ++len; q /= 16; } + if (s) { + s += len; + do { *--s = tohex(u % 16); u /= 16; } while(u); /* handles u == 0 */ + } + return len; +} diff --git a/ucspi-tcp-0.88/haveip6.h b/ucspi-tcp-0.88/haveip6.h new file mode 100644 index 0000000..5564de9 --- /dev/null +++ b/ucspi-tcp-0.88/haveip6.h @@ -0,0 +1 @@ +#define LIBC_HAS_IP6 1 diff --git a/ucspi-tcp-0.88/haveip6.h1 b/ucspi-tcp-0.88/haveip6.h1 new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/ucspi-tcp-0.88/haveip6.h1 @@ -0,0 +1 @@ + diff --git a/ucspi-tcp-0.88/haveip6.h2 b/ucspi-tcp-0.88/haveip6.h2 new file mode 100644 index 0000000..5564de9 --- /dev/null +++ b/ucspi-tcp-0.88/haveip6.h2 @@ -0,0 +1 @@ +#define LIBC_HAS_IP6 1 diff --git a/ucspi-tcp-0.88/hier.c b/ucspi-tcp-0.88/hier.c index 5663ada..546cc6d 100644 --- a/ucspi-tcp-0.88/hier.c +++ b/ucspi-tcp-0.88/hier.c @@ -4,6 +4,9 @@ void hier() { h(auto_home,-1,-1,02755); d(auto_home,"bin",-1,-1,02755); + d(auto_home,"man",-1,-1,02755); + d(auto_home,"man/man1",-1,-1,02755); + d(auto_home,"man/man5",-1,-1,02755); c(auto_home,"bin","tcpserver",-1,-1,0755); c(auto_home,"bin","tcprules",-1,-1,0755); @@ -22,4 +25,20 @@ void hier() c(auto_home,"bin","delcr",-1,-1,0755); c(auto_home,"bin","fixcrio",-1,-1,0755); c(auto_home,"bin","rblsmtpd",-1,-1,0755); + + c(auto_home,"man/man1","tcpclient.1",-1,-1,0644); + c(auto_home,"man/man1","tcpserver.1",-1,-1,0644); + c(auto_home,"man/man1","tcprules.1",-1,-1,0644); + c(auto_home,"man/man1","tcprulescheck.1",-1,-1,0644); + c(auto_home,"man/man1","fixcr.1",-1,-1,0644); + c(auto_home,"man/man1","addcr.1",-1,-1,0644); + c(auto_home,"man/man1","delcr.1",-1,-1,0644); + c(auto_home,"man/man1","who@.1",-1,-1,0644); + c(auto_home,"man/man1","date@.1",-1,-1,0644); + c(auto_home,"man/man1","finger@.1",-1,-1,0644); + c(auto_home,"man/man1","http@.1",-1,-1,0644); + c(auto_home,"man/man1","mconnect.1",-1,-1,0644); + c(auto_home,"man/man1","argv0.1",-1,-1,0644); + c(auto_home,"man/man1","recordio.1",-1,-1,0644); + c(auto_home,"man/man5","tcp-environ.5",-1,-1,0644); } diff --git a/ucspi-tcp-0.88/http@.1 b/ucspi-tcp-0.88/http@.1 new file mode 100644 index 0000000..4861b34 --- /dev/null +++ b/ucspi-tcp-0.88/http@.1 @@ -0,0 +1,52 @@ +.TH http@ 1 +.SH NAME +http@ \- get a web page from a host through HTTP +.SH SYNTAX +.B http@ +[ +.I host +[ +.I page +[ +.I port +] +] +] +.SH DESCRIPTION +.B http@ +connects to +.I port +on +.IR host , +sends +.B GET /\fIpage +(with an extra CR) +to +.IR host , +and prints any data it receives, +removing CR from the end of each line. + +If +.I port +is not supplied, +.B http@ +uses port 80 (HTTP). + +If +.I page +is not supplied, +.B http@ +sends +.B GET / +to +.IR host . + +If +.I host +is not supplied, +.B http@ +connects to the local host. +.SH "SEE ALSO" +addcr(1), +delcr(1), +tcpclient(1) diff --git a/ucspi-tcp-0.88/ip4.h b/ucspi-tcp-0.88/ip4.h index 64a7c1e..b906557 100644 --- a/ucspi-tcp-0.88/ip4.h +++ b/ucspi-tcp-0.88/ip4.h @@ -6,4 +6,6 @@ extern unsigned int ip4_fmt(char *,char *); #define IP4_FMT 20 +extern const char ip4loopback[4]; /* = {127,0,0,1}; */ + #endif diff --git a/ucspi-tcp-0.88/ip6.h b/ucspi-tcp-0.88/ip6.h new file mode 100644 index 0000000..88ff120 --- /dev/null +++ b/ucspi-tcp-0.88/ip6.h @@ -0,0 +1,28 @@ +#ifndef IP6_H +#define IP6_H + +#include "byte.h" + +extern unsigned int scan_ip6(const char *src,char *ip); +extern unsigned int fmt_ip6(char *dest,const char *ip); + +extern unsigned int scan_ip6_flat(const char *src,char *); +extern unsigned int fmt_ip6_flat(char *dest,const char *); + +/* + ip6 address syntax: (h = hex digit), no leading '0' required + 1. hhhh:hhhh:hhhh:hhhh:hhhh:hhhh:hhhh:hhhh + 2. any number of 0000 may be abbreviated as "::", but only once + flat ip6 address syntax: + hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh + */ + +#define IP6_FMT 40 + +extern const unsigned char V4mappedprefix[12]; /*={0,0,0,0,0,0,0,0,0,0,0xff,0xff}; */ +extern const unsigned char V6loopback[16]; /*={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1}; */ +extern const unsigned char V6any[16]; /*={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; */ + +#define ip6_isv4mapped(ip) (byte_equal(ip,12,V4mappedprefix)) + +#endif diff --git a/ucspi-tcp-0.88/pathexec.h b/ucspi-tcp-0.88/pathexec.h index 6fcbb89..bef93b4 100644 --- a/ucspi-tcp-0.88/pathexec.h +++ b/ucspi-tcp-0.88/pathexec.h @@ -2,7 +2,7 @@ #define PATHEXEC_H extern void pathexec_run(char *,char **,char **); -extern int pathexec_env(char *,char *); +extern int pathexec_env(const char *,const char *); extern void pathexec(char **); #endif diff --git a/ucspi-tcp-0.88/pathexec_env.c b/ucspi-tcp-0.88/pathexec_env.c index 48bba7e..157e71b 100644 --- a/ucspi-tcp-0.88/pathexec_env.c +++ b/ucspi-tcp-0.88/pathexec_env.c @@ -8,7 +8,7 @@ static stralloc plus; static stralloc tmp; -int pathexec_env(char *s,char *t) +int pathexec_env(const char *s,const char *t) { if (!s) return 1; if (!stralloc_copys(&tmp,s)) return 0; @@ -22,7 +22,6 @@ int pathexec_env(char *s,char *t) void pathexec(char **argv) { - char *path; char **e; unsigned int elen; unsigned int i; diff --git a/ucspi-tcp-0.88/rblsmtpd.c b/ucspi-tcp-0.88/rblsmtpd.c index cc8ba2e..200a345 100644 --- a/ucspi-tcp-0.88/rblsmtpd.c +++ b/ucspi-tcp-0.88/rblsmtpd.c @@ -25,26 +25,58 @@ void usage(void) strerr_die1x(100,"rblsmtpd: usage: rblsmtpd [ -b ] [ -R ] [ -t timeout ] [ -r base ] [ -a base ] smtpd [ arg ... ]"); } +char *tcp_proto; char *ip_env; static stralloc ip_reverse; +static inline char tohex(char c) { + return c>=10?c-10+'a':c+'0'; +} + void ip_init(void) { unsigned int i; unsigned int j; + unsigned char remoteip[16]; + char hexval; + tcp_proto = env_get("PROTO"); + if (!tcp_proto) tcp_proto = ""; ip_env = env_get("TCPREMOTEIP"); if (!ip_env) ip_env = ""; if (!stralloc_copys(&ip_reverse,"")) nomem(); i = str_len(ip_env); - while (i) { - for (j = i;j > 0;--j) if (ip_env[j - 1] == '.') break; - if (!stralloc_catb(&ip_reverse,ip_env + j,i - j)) nomem(); - if (!stralloc_cats(&ip_reverse,".")) nomem(); - if (!j) break; - i = j - 1; + if (str_diff(tcp_proto, "TCP6") != 0) + { + // IPv4 + while (i) { + for (j = i;j > 0;--j) if (ip_env[j - 1] == '.') break; + if (!stralloc_catb(&ip_reverse,ip_env + j,i - j)) nomem(); + if (!stralloc_cats(&ip_reverse,".")) nomem(); + if (!j) break; + i = j - 1; + } + } + else + { + // IPv6 + if ((i=scan_ip6(ip_env, remoteip))==0) + return; + + for (j=16; j>0; j--) + { + hexval=tohex(remoteip[j-1] & 15); + if(!stralloc_catb(&ip_reverse, &hexval, 1)) nomem(); + if(!stralloc_cats(&ip_reverse, ".")) nomem(); + + hexval=tohex(remoteip[j-1] >> 4); + if(!stralloc_catb(&ip_reverse, &hexval, 1)) nomem(); + if(!stralloc_cats(&ip_reverse, ".")) nomem(); + } + + if(!stralloc_cats(&ip_reverse, "ipv6.")) nomem(); } } @@ -190,7 +222,7 @@ main(int argc,char **argv,char **envp) argv += optind; if (!*argv) usage(); - if (flagwantdefaultrbl) rbl("rbl.maps.vix.com"); + if (flagwantdefaultrbl) rbl("zen.spamhaus.org"); if (decision >= 2) rblsmtpd(); pathexec_run(*argv,argv,envp); diff --git a/ucspi-tcp-0.88/remoteinfo.h b/ucspi-tcp-0.88/remoteinfo.h index 2ca779d..0884cc1 100644 --- a/ucspi-tcp-0.88/remoteinfo.h +++ b/ucspi-tcp-0.88/remoteinfo.h @@ -5,5 +5,6 @@ #include "uint16.h" extern int remoteinfo(stralloc *,char *,uint16,char *,uint16,unsigned int); +extern int remoteinfo6(stralloc *,char *,uint16,char *,uint16,unsigned int,uint32); #endif diff --git a/ucspi-tcp-0.88/rules.c b/ucspi-tcp-0.88/rules.c index 1840360..4fc2354 100644 --- a/ucspi-tcp-0.88/rules.c +++ b/ucspi-tcp-0.88/rules.c @@ -64,7 +64,7 @@ static int doit(void (*callback)(char *,unsigned int),char *ip,char *host,char * if (!stralloc_copys(&rules_name,ip)) return -1; while (rules_name.len > 0) { - if (ip[rules_name.len - 1] == '.') { + if (ip[rules_name.len - 1] == '.' || ip[rules_name.len - 1] == ':') { r = dorule(callback); if (r) return r; } diff --git a/ucspi-tcp-0.88/socket.h b/ucspi-tcp-0.88/socket.h index 80fb260..4fba762 100644 --- a/ucspi-tcp-0.88/socket.h +++ b/ucspi-tcp-0.88/socket.h @@ -2,21 +2,52 @@ #define SOCKET_H #include "uint16.h" +#include "uint32.h" extern int socket_tcp(void); extern int socket_udp(void); +extern int socket_tcp6(void); +extern int socket_udp6(void); -extern int socket_connect4(int,char *,uint16); +extern int socket_connect4(int,const char *,uint16); +extern int socket_connect6(int s,const char *ip,uint16 port,uint32 scope_id); extern int socket_connected(int); -extern int socket_bind4(int,char *,uint16); -extern int socket_bind4_reuse(int,char *,uint16); +extern int socket_bind4(int,const char *,uint16); +extern int socket_bind4_reuse(int,const char *,uint16); +extern int socket_bind6(int s,const char *ip,uint16 port,uint32 scope_id); +extern int socket_bind6_reuse(int s,const char *ip,uint16 port,uint32 scope_id); extern int socket_listen(int,int); extern int socket_accept4(int,char *,uint16 *); +extern int socket_accept6(int s,char *ip,uint16 *port,uint32 *scope_id); extern int socket_recv4(int,char *,int,char *,uint16 *); -extern int socket_send4(int,char *,int,char *,uint16); +extern int socket_send4(int,const char *,int,const char *,uint16); +extern int socket_recv6(int s,char *buf,unsigned int len,char *ip,uint16 *port,uint32 *scope_id); +extern int socket_send6(int s,const char *buf,unsigned int len,const char *ip,uint16 port,uint32 scope_id); extern int socket_local4(int,char *,uint16 *); extern int socket_remote4(int,char *,uint16 *); +extern int socket_local6(int s,char *ip,uint16 *port,uint32 *scope_id); +extern int socket_remote6(int s,char *ip,uint16 *port,uint32 *scope_id); + +/* enable sending udp packets to the broadcast address */ +extern int socket_broadcast(int); +/* join a multicast group on the given interface */ +extern int socket_mcjoin4(int,char *,char *); +extern int socket_mcjoin6(int,char *,int); +/* leave a multicast group on the given interface */ +extern int socket_mcleave4(int,char *); +extern int socket_mcleave6(int,char *); +/* set multicast TTL/hop count for outgoing packets */ +extern int socket_mcttl4(int,char); +extern int socket_mcttl6(int,char); +/* enable multicast loopback */ +extern int socket_mcloop4(int,char); +extern int socket_mcloop6(int,char); + +extern const char* socket_getifname(uint32 interface); +extern uint32 socket_getifidx(const char *ifname); extern void socket_tryreservein(int,int); +extern int noipv6; + #endif diff --git a/ucspi-tcp-0.88/socket_bind.c b/ucspi-tcp-0.88/socket_bind.c index 20830a4..067b4a8 100644 --- a/ucspi-tcp-0.88/socket_bind.c +++ b/ucspi-tcp-0.88/socket_bind.c @@ -5,7 +5,7 @@ #include "byte.h" #include "socket.h" -int socket_bind4(int s,char ip[4],uint16 port) +int socket_bind4(int s,const char ip[4],uint16 port) { struct sockaddr_in sa; @@ -17,7 +17,7 @@ int socket_bind4(int s,char ip[4],uint16 port) return bind(s,(struct sockaddr *) &sa,sizeof sa); } -int socket_bind4_reuse(int s,char ip[4],uint16 port) +int socket_bind4_reuse(int s,const char ip[4],uint16 port) { int opt = 1; setsockopt(s,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof opt); diff --git a/ucspi-tcp-0.88/socket_conn.c b/ucspi-tcp-0.88/socket_conn.c index 35adac4..dcc93ac 100644 --- a/ucspi-tcp-0.88/socket_conn.c +++ b/ucspi-tcp-0.88/socket_conn.c @@ -6,7 +6,7 @@ #include "byte.h" #include "socket.h" -int socket_connect4(int s,char ip[4],uint16 port) +int socket_connect4(int s,const char ip[4],uint16 port) { struct sockaddr_in sa; diff --git a/ucspi-tcp-0.88/str.h b/ucspi-tcp-0.88/str.h index ab4aedd..a2a4b75 100644 --- a/ucspi-tcp-0.88/str.h +++ b/ucspi-tcp-0.88/str.h @@ -1,13 +1,13 @@ #ifndef STR_H #define STR_H -extern unsigned int str_copy(char *,char *); -extern int str_diff(char *,char *); -extern int str_diffn(char *,char *,unsigned int); -extern unsigned int str_len(char *); -extern unsigned int str_chr(char *,int); -extern unsigned int str_rchr(char *,int); -extern int str_start(char *,char *); +extern unsigned int str_copy(char *,const char *); +extern int str_diff(const char *,const char *); +extern int str_diffn(const char *,const char *,unsigned int); +extern unsigned int str_len(const char *); +extern unsigned int str_chr(const char *,int); +extern unsigned int str_rchr(const char *,int); +extern int str_start(const char *,const char *); #define str_equal(s,t) (!str_diff((s),(t))) diff --git a/ucspi-tcp-0.88/str_chr.c b/ucspi-tcp-0.88/str_chr.c index 886d6b6..042dfa2 100644 --- a/ucspi-tcp-0.88/str_chr.c +++ b/ucspi-tcp-0.88/str_chr.c @@ -1,9 +1,9 @@ #include "str.h" -unsigned int str_chr(register char *s,int c) +unsigned int str_chr(register const char *s,int c) { register char ch; - register char *t; + register const char *t; ch = c; t = s; diff --git a/ucspi-tcp-0.88/str_diff.c b/ucspi-tcp-0.88/str_diff.c index 037dcdf..071e7f5 100644 --- a/ucspi-tcp-0.88/str_diff.c +++ b/ucspi-tcp-0.88/str_diff.c @@ -1,6 +1,6 @@ #include "str.h" -int str_diff(register char *s,register char *t) +int str_diff(register const char *s,register const char *t) { register char x; diff --git a/ucspi-tcp-0.88/str_len.c b/ucspi-tcp-0.88/str_len.c index 5bd3f62..8411ebf 100644 --- a/ucspi-tcp-0.88/str_len.c +++ b/ucspi-tcp-0.88/str_len.c @@ -1,8 +1,8 @@ #include "str.h" -unsigned int str_len(char *s) +unsigned int str_len(const char *s) { - register char *t; + register const char *t; t = s; for (;;) { diff --git a/ucspi-tcp-0.88/str_start.c b/ucspi-tcp-0.88/str_start.c index 43430bb..757189d 100644 --- a/ucspi-tcp-0.88/str_start.c +++ b/ucspi-tcp-0.88/str_start.c @@ -1,6 +1,6 @@ #include "str.h" -int str_start(register char *s,register char *t) +int str_start(register const char *s,register const char *t) { register char x; diff --git a/ucspi-tcp-0.88/stralloc.h b/ucspi-tcp-0.88/stralloc.h index 7866812..cc17048 100644 --- a/ucspi-tcp-0.88/stralloc.h +++ b/ucspi-tcp-0.88/stralloc.h @@ -9,18 +9,20 @@ extern int stralloc_ready(stralloc *,unsigned int); extern int stralloc_readyplus(stralloc *,unsigned int); extern int stralloc_copy(stralloc *,stralloc *); extern int stralloc_cat(stralloc *,stralloc *); -extern int stralloc_copys(stralloc *,char *); -extern int stralloc_cats(stralloc *,char *); -extern int stralloc_copyb(stralloc *,char *,unsigned int); -extern int stralloc_catb(stralloc *,char *,unsigned int); +extern int stralloc_copys(stralloc *,const char *); +extern int stralloc_cats(stralloc *,const char *); +extern int stralloc_copyb(stralloc *,const char *,unsigned int); +extern int stralloc_catb(stralloc *,const char *,unsigned int); extern int stralloc_append(stralloc *,char *); /* beware: this takes a pointer to 1 char */ -extern int stralloc_starts(stralloc *,char *); +extern int stralloc_starts(stralloc *,const char *); #define stralloc_0(sa) stralloc_append(sa,"") extern int stralloc_catulong0(stralloc *,unsigned long,unsigned int); extern int stralloc_catlong0(stralloc *,long,unsigned int); +extern void stralloc_free(stralloc *); + #define stralloc_catlong(sa,l) (stralloc_catlong0((sa),(l),0)) #define stralloc_catuint0(sa,i,n) (stralloc_catulong0((sa),(i),(n))) #define stralloc_catint0(sa,i,n) (stralloc_catlong0((sa),(i),(n))) diff --git a/ucspi-tcp-0.88/stralloc_catb.c b/ucspi-tcp-0.88/stralloc_catb.c index b739bed..b606e32 100644 --- a/ucspi-tcp-0.88/stralloc_catb.c +++ b/ucspi-tcp-0.88/stralloc_catb.c @@ -1,7 +1,7 @@ #include "stralloc.h" #include "byte.h" -int stralloc_catb(stralloc *sa,char *s,unsigned int n) +int stralloc_catb(stralloc *sa,const char *s,unsigned int n) { if (!sa->s) return stralloc_copyb(sa,s,n); if (!stralloc_readyplus(sa,n + 1)) return 0; diff --git a/ucspi-tcp-0.88/stralloc_cats.c b/ucspi-tcp-0.88/stralloc_cats.c index 8b11e94..92cb66e 100644 --- a/ucspi-tcp-0.88/stralloc_cats.c +++ b/ucspi-tcp-0.88/stralloc_cats.c @@ -2,7 +2,7 @@ #include "str.h" #include "stralloc.h" -int stralloc_cats(stralloc *sa,char *s) +int stralloc_cats(stralloc *sa,const char *s) { return stralloc_catb(sa,s,str_len(s)); } diff --git a/ucspi-tcp-0.88/stralloc_opyb.c b/ucspi-tcp-0.88/stralloc_opyb.c index 46b99fc..593029d 100644 --- a/ucspi-tcp-0.88/stralloc_opyb.c +++ b/ucspi-tcp-0.88/stralloc_opyb.c @@ -1,7 +1,7 @@ #include "stralloc.h" #include "byte.h" -int stralloc_copyb(stralloc *sa,char *s,unsigned int n) +int stralloc_copyb(stralloc *sa,const char *s,unsigned int n) { if (!stralloc_ready(sa,n + 1)) return 0; byte_copy(sa->s,n,s); diff --git a/ucspi-tcp-0.88/stralloc_opys.c b/ucspi-tcp-0.88/stralloc_opys.c index 78594b0..860c7e0 100644 --- a/ucspi-tcp-0.88/stralloc_opys.c +++ b/ucspi-tcp-0.88/stralloc_opys.c @@ -2,7 +2,7 @@ #include "str.h" #include "stralloc.h" -int stralloc_copys(stralloc *sa,char *s) +int stralloc_copys(stralloc *sa,const char *s) { return stralloc_copyb(sa,s,str_len(s)); } diff --git a/ucspi-tcp-0.88/tcpclient.c b/ucspi-tcp-0.88/tcpclient.c index 9f6d7f2..77b1ad5 100644 --- a/ucspi-tcp-0.88/tcpclient.c +++ b/ucspi-tcp-0.88/tcpclient.c @@ -9,6 +9,7 @@ #include "scan.h" #include "str.h" #include "ip4.h" +#include "ip6.h" #include "uint16.h" #include "socket.h" #include "fd.h" @@ -20,6 +21,7 @@ #include "timeoutconn.h" #include "remoteinfo.h" #include "dns.h" +#include "byte.h" #define FATAL "tcpclient: fatal: " #define CONNECT "tcpclient: unable to connect to " @@ -31,27 +33,30 @@ void nomem(void) void usage(void) { strerr_die1x(100,"tcpclient: usage: tcpclient \ -[ -hHrRdDqQv ] \ +[ -46hHrRdDqQv ] \ [ -i localip ] \ [ -p localport ] \ [ -T timeoutconn ] \ [ -l localname ] \ [ -t timeoutinfo ] \ +[ -I interface ] \ host port program"); } +int forcev6 = 0; int verbosity = 1; int flagdelay = 1; int flagremoteinfo = 1; int flagremotehost = 1; unsigned long itimeout = 26; unsigned long ctimeout[2] = { 2, 58 }; +uint32 netif = 0; -char iplocal[4] = { 0,0,0,0 }; +char iplocal[16] = { 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0 }; uint16 portlocal = 0; char *forcelocal = 0; -char ipremote[4]; +char ipremote[16]; uint16 portremote; char *hostname; @@ -61,12 +66,13 @@ static stralloc moreaddresses; static stralloc tmp; static stralloc fqdn; char strnum[FMT_ULONG]; -char ipstr[IP4_FMT]; +char ipstr[IP6_FMT]; char seed[128]; main(int argc,char **argv) { + int fakev4=0; unsigned long u; int opt; char *x; @@ -80,8 +86,10 @@ main(int argc,char **argv) close(7); sig_ignore(sig_pipe); - while ((opt = getopt(argc,argv,"dDvqQhHrRi:p:t:T:l:")) != opteof) + while ((opt = getopt(argc,argv,"46dDvqQhHrRi:p:t:T:l:I:")) != opteof) switch(opt) { + case '4': noipv6 = 1; break; + case '6': forcev6 = 1; break; case 'd': flagdelay = 1; break; case 'D': flagdelay = 0; break; case 'v': verbosity = 2; break; @@ -97,7 +105,8 @@ main(int argc,char **argv) if (optarg[j] == '+') ++j; scan_ulong(optarg + j,&ctimeout[1]); break; - case 'i': if (!ip4_scan(optarg,iplocal)) usage(); break; + case 'i': if (!scan_ip6(optarg,iplocal)) usage(); break; + case 'I': netif=socket_getifidx(optarg); break; case 'p': scan_ulong(optarg,&u); portlocal = u; break; default: usage(); } @@ -108,8 +117,8 @@ main(int argc,char **argv) hostname = *argv; if (!hostname) usage(); - if (str_equal(hostname,"")) hostname = "127.0.0.1"; - if (str_equal(hostname,"0")) hostname = "127.0.0.1"; + if (!hostname[0] || str_equal(hostname,"0")) + hostname = (noipv6?"127.0.0.1":"::1"); x = *++argv; if (!x) usage(); @@ -127,33 +136,36 @@ main(int argc,char **argv) if (!*++argv) usage(); if (!stralloc_copys(&tmp,hostname)) nomem(); - if (dns_ip4_qualify(&addresses,&fqdn,&tmp) == -1) + if (dns_ip6_qualify(&addresses,&fqdn,&tmp) == -1) strerr_die4sys(111,FATAL,"temporarily unable to figure out IP address for ",hostname,": "); - if (addresses.len < 4) + if (addresses.len < 16) strerr_die3x(111,FATAL,"no IP address for ",hostname); - if (addresses.len == 4) { + if (addresses.len == 16) { ctimeout[0] += ctimeout[1]; ctimeout[1] = 0; } for (cloop = 0;cloop < 2;++cloop) { if (!stralloc_copys(&moreaddresses,"")) nomem(); - for (j = 0;j + 4 <= addresses.len;j += 4) { - s = socket_tcp(); + for (j = 0;j + 16 <= addresses.len;j += 4) { + s = socket_tcp6(); if (s == -1) strerr_die2sys(111,FATAL,"unable to create socket: "); - if (socket_bind4(s,iplocal,portlocal) == -1) + if (socket_bind6(s,iplocal,portlocal,netif) == -1) strerr_die2sys(111,FATAL,"unable to bind socket: "); - if (timeoutconn(s,addresses.s + j,portremote,ctimeout[cloop]) == 0) + if (timeoutconn6(s,addresses.s + j,portremote,ctimeout[cloop],netif) == 0) goto CONNECTED; close(s); if (!cloop && ctimeout[1] && (errno == error_timeout)) { - if (!stralloc_catb(&moreaddresses,addresses.s + j,4)) nomem(); + if (!stralloc_catb(&moreaddresses,addresses.s + j,16)) nomem(); } else { strnum[fmt_ulong(strnum,portremote)] = 0; - ipstr[ip4_fmt(ipstr,addresses.s + j)] = 0; + if (ip6_isv4mapped(addresses.s+j)) + ipstr[ip4_fmt(ipstr,addresses.s + j + 12)] = 0; + else + ipstr[ip6_fmt(ipstr,addresses.s + j)] = 0; strerr_warn5(CONNECT,ipstr," port ",strnum,": ",&strerr_sys); } } @@ -169,37 +181,46 @@ main(int argc,char **argv) if (!flagdelay) socket_tcpnodelay(s); /* if it fails, bummer */ - if (!pathexec_env("PROTO","TCP")) nomem(); - - if (socket_local4(s,iplocal,&portlocal) == -1) + if (socket_local6(s,iplocal,&portlocal,&netif) == -1) strerr_die2sys(111,FATAL,"unable to get local address: "); + if (!forcev6 && (ip6_isv4mapped(iplocal) || byte_equal(iplocal,16,V6any))) + fakev4=1; + + if (!pathexec_env("PROTO",fakev4?"TCP":"TCP6")) nomem(); + strnum[fmt_ulong(strnum,portlocal)] = 0; if (!pathexec_env("TCPLOCALPORT",strnum)) nomem(); - ipstr[ip4_fmt(ipstr,iplocal)] = 0; + if (fakev4) + ipstr[ip4_fmt(ipstr,iplocal+12)] = 0; + else + ipstr[ip6_fmt(ipstr,iplocal)] = 0; if (!pathexec_env("TCPLOCALIP",ipstr)) nomem(); x = forcelocal; if (!x) - if (dns_name4(&tmp,iplocal) == 0) { + if (dns_name6(&tmp,iplocal) == 0) { if (!stralloc_0(&tmp)) nomem(); x = tmp.s; } if (!pathexec_env("TCPLOCALHOST",x)) nomem(); - if (socket_remote4(s,ipremote,&portremote) == -1) + if (socket_remote6(s,ipremote,&portremote,&netif) == -1) strerr_die2sys(111,FATAL,"unable to get remote address: "); strnum[fmt_ulong(strnum,portremote)] = 0; if (!pathexec_env("TCPREMOTEPORT",strnum)) nomem(); - ipstr[ip4_fmt(ipstr,ipremote)] = 0; + if (fakev4) + ipstr[ip4_fmt(ipstr,ipremote+12)] = 0; + else + ipstr[ip6_fmt(ipstr,ipremote)] = 0; if (!pathexec_env("TCPREMOTEIP",ipstr)) nomem(); if (verbosity >= 2) strerr_warn4("tcpclient: connected to ",ipstr," port ",strnum,0); x = 0; if (flagremotehost) - if (dns_name4(&tmp,ipremote) == 0) { + if (dns_name6(&tmp,ipremote) == 0) { if (!stralloc_0(&tmp)) nomem(); x = tmp.s; } @@ -207,7 +228,7 @@ main(int argc,char **argv) x = 0; if (flagremoteinfo) - if (remoteinfo(&tmp,ipremote,portremote,iplocal,portlocal,itimeout) == 0) { + if (remoteinfo6(&tmp,ipremote,portremote,iplocal,portlocal,itimeout,netif) == 0) { if (!stralloc_0(&tmp)) nomem(); x = tmp.s; } diff --git a/ucspi-tcp-0.88/tcprules.c b/ucspi-tcp-0.88/tcprules.c index a684ac5..83519c8 100644 --- a/ucspi-tcp-0.88/tcprules.c +++ b/ucspi-tcp-0.88/tcprules.c @@ -123,8 +123,15 @@ main(int argc,char **argv) } line.len = len; /* for die_bad() */ - colon = byte_chr(x,len,':'); - if (colon == len) continue; + colon = 0; + for (;;) { + int tmp; + tmp = byte_chr(x + colon,len - colon,':'); + colon += tmp; + if (colon == len) continue; + if (byte_equal(x+colon+1,4,"deny") || byte_equal(x+colon+1,5,"allow")) break; + ++colon; + } if (!stralloc_copyb(&address,x,colon)) nomem(); if (!stralloc_copys(&data,"")) nomem(); diff --git a/ucspi-tcp-0.88/tcpserver.c b/ucspi-tcp-0.88/tcpserver.c index 979a0be..aab637f 100644 --- a/ucspi-tcp-0.88/tcpserver.c +++ b/ucspi-tcp-0.88/tcpserver.c @@ -7,6 +7,7 @@ #include "fmt.h" #include "scan.h" #include "ip4.h" +#include "ip6.h" #include "fd.h" #include "exit.h" #include "env.h" @@ -28,6 +29,7 @@ #include "sig.h" #include "dns.h" +int forcev6 = 0; int verbosity = 1; int flagkillopts = 1; int flagdelay = 1; @@ -36,20 +38,21 @@ int flagremoteinfo = 1; int flagremotehost = 1; int flagparanoid = 0; unsigned long timeout = 26; +uint32 netif = 0; static stralloc tcpremoteinfo; uint16 localport; char localportstr[FMT_ULONG]; -char localip[4]; -char localipstr[IP4_FMT]; +char localip[16]; +char localipstr[IP6_FMT]; static stralloc localhostsa; char *localhost = 0; uint16 remoteport; char remoteportstr[FMT_ULONG]; -char remoteip[4]; -char remoteipstr[IP4_FMT]; +char remoteip[16]; +char remoteipstr[IP6_FMT]; static stralloc remotehostsa; char *remotehost = 0; @@ -96,12 +99,12 @@ void safecats(char *s) if (ch < 33) ch = '?'; if (ch > 126) ch = '?'; if (ch == '%') ch = '?'; /* logger stupidity */ - if (ch == ':') ch = '?'; +/* if (ch == ':') ch = '?'; */ append(&ch); } cats("..."); } -void env(char *s,char *t) +void env(const char *s,const char *t) { if (!pathexec_env(s,t)) drop_nomem(); } @@ -135,9 +138,16 @@ void found(char *data,unsigned int datalen) void doit(int t) { + int fakev4=0; int j; + uint32 scope_id; - remoteipstr[ip4_fmt(remoteipstr,remoteip)] = 0; + if (!forcev6 && ip6_isv4mapped(remoteip)) + fakev4=1; + if (fakev4) + remoteipstr[ip4_fmt(remoteipstr,remoteip+12)] = 0; + else + remoteipstr[ip6_fmt(remoteipstr,remoteip)] = 0; if (verbosity >= 2) { strnum[fmt_ulong(strnum,getpid())] = 0; @@ -155,30 +165,40 @@ void doit(int t) strerr_die2sys(111,DROP,"unable to print banner: "); } - if (socket_local4(t,localip,&localport) == -1) + if (socket_local6(t,localip,&localport,&scope_id) == -1) strerr_die2sys(111,DROP,"unable to get local address: "); - localipstr[ip4_fmt(localipstr,localip)] = 0; + if (fakev4) + localipstr[ip4_fmt(localipstr,localip+12)] = 0; + else + localipstr[ip6_fmt(localipstr,localip)] = 0; remoteportstr[fmt_ulong(remoteportstr,remoteport)] = 0; if (!localhost) - if (dns_name4(&localhostsa,localip) == 0) + if (dns_name6(&localhostsa,localip) == 0) if (localhostsa.len) { if (!stralloc_0(&localhostsa)) drop_nomem(); localhost = localhostsa.s; } - env("PROTO","TCP"); + env("PROTO",fakev4?"TCP":"TCP6"); env("TCPLOCALIP",localipstr); + localipstr[ip6_fmt(localipstr,localip)]=0; + env("TCP6LOCALIP",localipstr); + env("TCPLOCALPORT",localportstr); + env("TCP6LOCALPORT",localportstr); env("TCPLOCALHOST",localhost); + env("TCP6LOCALHOST",localhost); + if (!fakev4 && scope_id) + env("TCP6INTERFACE",socket_getifname(scope_id)); if (flagremotehost) - if (dns_name4(&remotehostsa,remoteip) == 0) + if (dns_name6(&remotehostsa,remoteip) == 0) if (remotehostsa.len) { if (flagparanoid) - if (dns_ip4(&tmp,&remotehostsa) == 0) - for (j = 0;j + 4 <= tmp.len;j += 4) - if (byte_equal(remoteip,4,tmp.s + j)) { + if (dns_ip6(&tmp,&remotehostsa) == 0) + for (j = 0;j + 16 <= tmp.len;j += 16) + if (byte_equal(remoteip,16,tmp.s + j)) { flagparanoid = 0; break; } @@ -188,15 +208,20 @@ void doit(int t) } } env("TCPREMOTEIP",remoteipstr); + remoteipstr[ip6_fmt(remoteipstr,remoteip)]=0; + env("TCP6REMOTEIP",remoteipstr); env("TCPREMOTEPORT",remoteportstr); + env("TCP6REMOTEPORT",remoteportstr); env("TCPREMOTEHOST",remotehost); + env("TCP6REMOTEHOST",remotehost); if (flagremoteinfo) { - if (remoteinfo(&tcpremoteinfo,remoteip,remoteport,localip,localport,timeout) == -1) + if (remoteinfo6(&tcpremoteinfo,remoteip,remoteport,localip,localport,timeout,netif) == -1) flagremoteinfo = 0; if (!stralloc_0(&tcpremoteinfo)) drop_nomem(); } env("TCPREMOTEINFO",flagremoteinfo ? tcpremoteinfo.s : 0); + env("TCP6REMOTEINFO",flagremoteinfo ? tcpremoteinfo.s : 0); if (fnrules) { int fdrules; @@ -206,7 +231,15 @@ void doit(int t) if (!flagallownorules) drop_rules(); } else { - if (rules(found,fdrules,remoteipstr,remotehost,flagremoteinfo ? tcpremoteinfo.s : 0) == -1) drop_rules(); + int fakev4=0; + char* temp; + if (!forcev6 && ip6_isv4mapped(remoteip)) + fakev4=1; + if (fakev4) + temp=remoteipstr+7; + else + temp=remoteipstr; + if (rules(found,fdrules,temp,remotehost,flagremoteinfo ? tcpremoteinfo.s : 0) == -1) drop_rules(); close(fdrules); } } @@ -240,7 +273,7 @@ void usage(void) { strerr_warn1("\ tcpserver: usage: tcpserver \ -[ -1UXpPhHrRoOdDqQv ] \ +[ -461UXpPhHrRoOdDqQv ] \ [ -c limit ] \ [ -x rules.cdb ] \ [ -B banner ] \ @@ -249,6 +282,7 @@ tcpserver: usage: tcpserver \ [ -b backlog ] \ [ -l localname ] \ [ -t timeout ] \ +[ -I interface ] \ host port program",0); _exit(100); } @@ -299,8 +333,8 @@ main(int argc,char **argv) unsigned long u; int s; int t; - - while ((opt = getopt(argc,argv,"dDvqQhHrR1UXx:t:u:g:l:b:B:c:pPoO")) != opteof) + + while ((opt = getopt(argc,argv,"46dDvqQhHrR1UXx:t:u:g:l:b:B:c:I:pPoO")) != opteof) switch(opt) { case 'b': scan_ulong(optarg,&backlog); break; case 'c': scan_ulong(optarg,&limit); break; @@ -325,7 +359,10 @@ main(int argc,char **argv) x = env_get("GID"); if (x) scan_ulong(x,&gid); break; case 'u': scan_ulong(optarg,&uid); break; case 'g': scan_ulong(optarg,&gid); break; + case 'I': netif=socket_getifidx(optarg); break; case '1': flag1 = 1; break; + case '4': noipv6 = 1; break; + case '6': forcev6 = 1; break; case 'l': localhost = optarg; break; default: usage(); } @@ -337,8 +374,7 @@ main(int argc,char **argv) hostname = *argv++; if (!hostname) usage(); - if (str_equal(hostname,"")) hostname = "0.0.0.0"; - if (str_equal(hostname,"0")) hostname = "0.0.0.0"; + if (str_equal(hostname,"")) hostname = "0"; x = *argv++; if (!x) usage(); @@ -348,7 +384,7 @@ main(int argc,char **argv) se = getservbyname(x,"tcp"); if (!se) strerr_die3x(111,FATAL,"unable to figure out port number for ",x); - localport = ntohs(se->s_port); + uint16_unpack_big((char*)&se->s_port,&localport); } if (!*argv) usage(); @@ -358,20 +394,26 @@ main(int argc,char **argv) sig_catch(sig_term,sigterm); sig_ignore(sig_pipe); - if (!stralloc_copys(&tmp,hostname)) - strerr_die2x(111,FATAL,"out of memory"); - if (dns_ip4_qualify(&addresses,&fqdn,&tmp) == -1) - strerr_die4sys(111,FATAL,"temporarily unable to figure out IP address for ",hostname,": "); - if (addresses.len < 4) - strerr_die3x(111,FATAL,"no IP address for ",hostname); - byte_copy(localip,4,addresses.s); - - s = socket_tcp(); + if (str_equal(hostname,"0")) { + byte_zero(localip,sizeof localip); + } else { + if (!stralloc_copys(&tmp,hostname)) + strerr_die2x(111,FATAL,"out of memory"); + if (dns_ip6_qualify(&addresses,&fqdn,&tmp) == -1) + strerr_die4sys(111,FATAL,"temporarily unable to figure out IP address for ",hostname,": "); + if (addresses.len < 16) + strerr_die3x(111,FATAL,"no IP address for ",hostname); + byte_copy(localip,16,addresses.s); + if (ip6_isv4mapped(localip)) + noipv6=1; + } + + s = socket_tcp6(); if (s == -1) strerr_die2sys(111,FATAL,"unable to create socket: "); - if (socket_bind4_reuse(s,localip,localport) == -1) + if (socket_bind6_reuse(s,localip,localport,netif) == -1) strerr_die2sys(111,FATAL,"unable to bind: "); - if (socket_local4(s,localip,&localport) == -1) + if (socket_local6(s,localip,&localport,&netif) == -1) strerr_die2sys(111,FATAL,"unable to get local address: "); if (socket_listen(s,backlog) == -1) strerr_die2sys(111,FATAL,"unable to listen: "); @@ -399,7 +441,7 @@ main(int argc,char **argv) while (numchildren >= limit) sig_pause(); sig_unblock(sig_child); - t = socket_accept4(s,remoteip,&remoteport); + t = socket_accept6(s,remoteip,&remoteport,&netif); sig_block(sig_child); if (t == -1) continue; diff --git a/ucspi-tcp-0.88/timeoutconn.h b/ucspi-tcp-0.88/timeoutconn.h index 7f9dcc9..01e6a75 100644 --- a/ucspi-tcp-0.88/timeoutconn.h +++ b/ucspi-tcp-0.88/timeoutconn.h @@ -2,7 +2,9 @@ #define TIMEOUTCONN_H #include "uint16.h" +#include "uint32.h" extern int timeoutconn(int,char *,uint16,unsigned int); +extern int timeoutconn6(int,char *,uint16,unsigned int,uint32); #endif |