summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Denker <jsd@av8n.com>2012-07-30 14:34:05 -0700
committerJohn Denker <jsd@av8n.com>2012-07-30 14:34:05 -0700
commit7024dc330299921af649330c45b99c21c3d7f022 (patch)
tree9f747a0423647b016376fe353ceea197a5848cbf
parentce0dbe5332d4eb921c09cc48cc52634211d7089a (diff)
parentf8be4baf5a2318363b42f8883f66ed8a976dfc79 (diff)
Merge branch 'master' of ephedra:usr/src/qmail into e_master
Conflicts: tools/makefile
-rw-r--r--.gitignore2
-rw-r--r--tools/filters.conf2
-rw-r--r--tools/greylist.c50
-rw-r--r--tools/hi-q.c44
-rw-r--r--tools/hi-test.c14
-rw-r--r--tools/libltgrey.c508
-rw-r--r--tools/libltgrey.h51
-rw-r--r--tools/ltgrey.c109
-rw-r--r--tools/mail-scan.c41
-rw-r--r--tools/makefile23
-rw-r--r--tools/qq_exit_codes.h15
-rw-r--r--tools/skrewt.c158
-rw-r--r--tools/utils.c76
-rw-r--r--tools/utils.h7
-rw-r--r--ucspi-tcp-0.88/FILES37
-rw-r--r--ucspi-tcp-0.88/Makefile184
-rw-r--r--ucspi-tcp-0.88/TARGETS28
-rw-r--r--ucspi-tcp-0.88/addcr.122
-rw-r--r--ucspi-tcp-0.88/argv0.147
-rw-r--r--ucspi-tcp-0.88/date@.132
-rw-r--r--ucspi-tcp-0.88/delcr.130
-rw-r--r--ucspi-tcp-0.88/dns.h63
-rw-r--r--ucspi-tcp-0.88/dns_dfd.c11
-rw-r--r--ucspi-tcp-0.88/dns_domain.c36
-rw-r--r--ucspi-tcp-0.88/dns_dtda.c2
-rw-r--r--ucspi-tcp-0.88/dns_ip.c4
-rw-r--r--ucspi-tcp-0.88/dns_ip6.c103
-rw-r--r--ucspi-tcp-0.88/dns_ipq.c6
-rw-r--r--ucspi-tcp-0.88/dns_ipq6.c72
-rw-r--r--ucspi-tcp-0.88/dns_name.c19
-rw-r--r--ucspi-tcp-0.88/dns_nd.c2
-rw-r--r--ucspi-tcp-0.88/dns_nd6.c28
-rw-r--r--ucspi-tcp-0.88/dns_packet.c9
-rw-r--r--ucspi-tcp-0.88/dns_random.c3
-rw-r--r--ucspi-tcp-0.88/dns_rcip.c29
-rw-r--r--ucspi-tcp-0.88/dns_rcrw.c5
-rw-r--r--ucspi-tcp-0.88/dns_resolve.c7
-rw-r--r--ucspi-tcp-0.88/dns_sortip6.c20
-rw-r--r--ucspi-tcp-0.88/dns_transmit.c71
-rw-r--r--ucspi-tcp-0.88/dns_txt.c4
-rw-r--r--ucspi-tcp-0.88/finger@.145
-rw-r--r--ucspi-tcp-0.88/fixcr.111
-rw-r--r--ucspi-tcp-0.88/fmt_xlong.c22
-rw-r--r--ucspi-tcp-0.88/haveip6.h1
-rw-r--r--ucspi-tcp-0.88/haveip6.h11
-rw-r--r--ucspi-tcp-0.88/haveip6.h21
-rw-r--r--ucspi-tcp-0.88/hier.c19
-rw-r--r--ucspi-tcp-0.88/http@.152
-rw-r--r--ucspi-tcp-0.88/ip4.h2
-rw-r--r--ucspi-tcp-0.88/ip6.h28
-rw-r--r--ucspi-tcp-0.88/pathexec.h2
-rw-r--r--ucspi-tcp-0.88/pathexec_env.c3
-rw-r--r--ucspi-tcp-0.88/rblsmtpd.c46
-rw-r--r--ucspi-tcp-0.88/remoteinfo.h1
-rw-r--r--ucspi-tcp-0.88/rules.c2
-rw-r--r--ucspi-tcp-0.88/socket.h39
-rw-r--r--ucspi-tcp-0.88/socket_bind.c4
-rw-r--r--ucspi-tcp-0.88/socket_conn.c2
-rw-r--r--ucspi-tcp-0.88/str.h14
-rw-r--r--ucspi-tcp-0.88/str_chr.c4
-rw-r--r--ucspi-tcp-0.88/str_diff.c2
-rw-r--r--ucspi-tcp-0.88/str_len.c4
-rw-r--r--ucspi-tcp-0.88/str_start.c2
-rw-r--r--ucspi-tcp-0.88/stralloc.h12
-rw-r--r--ucspi-tcp-0.88/stralloc_catb.c2
-rw-r--r--ucspi-tcp-0.88/stralloc_cats.c2
-rw-r--r--ucspi-tcp-0.88/stralloc_opyb.c2
-rw-r--r--ucspi-tcp-0.88/stralloc_opys.c2
-rw-r--r--ucspi-tcp-0.88/tcpclient.c73
-rw-r--r--ucspi-tcp-0.88/tcprules.c11
-rw-r--r--ucspi-tcp-0.88/tcpserver.c112
-rw-r--r--ucspi-tcp-0.88/timeoutconn.h2
72 files changed, 2073 insertions, 426 deletions
diff --git a/.gitignore b/.gitignore
index ad1d359..b6369d1 100644
--- a/.gitignore
+++ b/.gitignore
@@ -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