commit 02e0d456dafc376e3f2e3b94f651ce756e12e8da
parent cdbc7bc368ba3d459181b8307c9949c7f578fdb6
Author: Ellenor Malik <ellenor@umbrellix.net>
Date: Thu, 6 Oct 2022 01:40:44 +0000
egh, i'm trying, please
Diffstat:
14 files changed, 999 insertions(+), 187 deletions(-)
diff --git a/src/mxf-remote/NOTES-mxfr.md b/src/mxf-remote/NOTES-mxfr.md
@@ -17,23 +17,15 @@ Global variables, save for buffer_2_, start with a Capital Letter. Typedefs alwa
## Data structures
-protocol_t is a typedef struct containing the following fields.
+protocol_t is a typedef struct containing a bunch of fields. They are NOT documented here.
- typedef struct {
- char srvservice[MAXSRVLEN]; // by happy coincidence we can also use this as the prefix for control/<service>routes filenames
- uint16_t defport; // default port
- signed char slice; // plain mx = 0
- unsigned int tls:1; // TLSC
- unsigned int starttls:1; // UCSPITLSC
- char app[PATH_MAX];
- struct constmap maproutes; // control/<service>routes
- } protocol_t;
+### A word on protocol_t
-(data of type protocol_t).maproutes serves the same purpose as global struct constmap maproutes in qmail-remote.c. It is fetched at the time of inserting the protocol onto the end of genalloc Protocols.
+This struct has grown to accomodate dynamically allocated pointers to DNS (SRV, MX, AAAA and A) results. A stralloc pointer to mxresult_t[] in each protocol gets sorted using qsort once DNS is done.
## A word on type management with genallocs.
-genallocs are just strallocs, and they don't contain any type information.
+genallocs are just strallocs, and they don't contain any type information. Because of this, they are wholly unsuitable for the purpose at hand. They are only used here in interactions with skadns, the DNS resolver.
## mxf-remote.c:0010 - Address mangling
diff --git a/src/mxf-remote/all.do b/src/mxf-remote/all.do
@@ -0,0 +1,2 @@
+#!/bin/sh
+redo-ifchange mxf-remote
diff --git a/src/mxf-remote/build.env b/src/mxf-remote/build.env
@@ -0,0 +1,2 @@
+CFLAGS="-DUSING_SKALIBS -Werror=all -Werror=pedantic -ferror-limit=60 -Wno-unused-variable -DREMOTEDEBUG"
+INCLUDES="-I/package/prog/skalibs/include -I/package/web/s6-dns/include -I. -I../../include"
diff --git a/src/mxf-remote/default.obj.do b/src/mxf-remote/default.obj.do
@@ -0,0 +1,4 @@
+#!/bin/sh
+redo-ifchange "${2}.c" "${2}.h"
+redo-ifcreate "${2}.c" "${2}.h"
+${CC:-cc} -c -o "${3}" "${2}.c" "${CFLAGS}" "${INCLUDES}"
diff --git a/src/mxf-remote/errs.c b/src/mxf-remote/errs.c
@@ -1,19 +1,19 @@
#include "mxf-remote.h"
#include <stdlib.h>
-extern stralloc host;
+extern stralloc Host;
extern buffer buffer_2_;
#define _HSC {
-void out(char *s) _HSC
- if (buffer_puts(buffer_2_,s) == -1) _exit(0);
+void out(const char *s) _HSC
+ if (buffer_puts(&buffer_2_,s) == -1) _exit(0);
}
void zero() _HSC
- if (buffer_put(buffer_2_,"\0",1) == -1) _exit(0);
+ if (buffer_put(&buffer_2_,"\0",1) == -1) _exit(0);
}
void _noreturn_ zerodie() _HSC
zero();
- buffer_flush(buffer_2_);
+ buffer_flush(&buffer_2_);
_exit(0);
}
void outsafe(stralloc *sa) _HSC
@@ -22,97 +22,139 @@ void outsafe(stralloc *sa) _HSC
ch = sa->s[i];
if (ch < 33) ch = '?';
if (ch > 126) ch = '?';
- if (buffer_put(buffer_2_,&ch,1) == -1) _exit(0);
+ if (buffer_put(&buffer_2_,&ch,1) == -1) _exit(0);
}
}
void _noreturn_ temp_nomem() _HSC
- out("ZOut of memory. (#4.3.0)\n");
+ out("Z4.3.0 Out of memory or limits exceeded.\n");
zerodie();
}
void _noreturn_ temp_fault() _HSC
- out("ZGeneral protection violation in iopause. Attempting to dump core now. (#4.3.0)\n");
+ out("Z4.3.0 General protection violation in iopause. Attempting to dump core now.\n");
zero();
- buffer_flush(buffer_2_);
+ buffer_flush(&buffer_2_);
abort();
}
void _noreturn_ temp_runfds() _HSC
- out("Zrun_fds called without any descriptors? (#4.3.0)\n");
+ out("Z4.3.0 run_fds called without any descriptors?\n");
zerodie();
}
void _noreturn_ temp_bug() _HSC
- out("ZOS gave us EINVAL that we don't know what to do with. Attempting to dump core now. (#4.3.0)\n");
+ out("Z4.3.0 OS gave us EINVAL that we don't know what to do with. Attempting to dump core now.\n");
zero();
- buffer_flush(buffer_2_);
+ buffer_flush(&buffer_2_);
abort();
}
void _noreturn_ temp_intr() _HSC
- out("ZSignal interruption in iopause. (#4.3.0)\n");
+ out("Z4.3.0 Signal interruption in iopause.\n");
zerodie();
}
void _noreturn_ temp_oserr() _HSC
- out("ZSystem resources temporarily unavailable. (#4.3.0)\n");
+ out("Z4.3.0 System resources temporarily unavailable.\n");
zerodie();
}
void _noreturn_ temp_hasherr() _HSC
- out("Zmxf-remote tried to add an element to a hash table which already existed in that hash table. This is an embarrassing programming error. Attempting to dump core now. (#4.3.0)\n");
+ out("Z4.3.0 mxf-remote HASH_ADD dup key. Attempting to dump core now.\n");
zero();
- buffer_flush(buffer_2_);
+ buffer_flush(&buffer_2_);
abort();
}
void _noreturn_ temp_finderr() _HSC
- out("Zmxf-remote tried to find an element to a hash table which did not exist in that hash table. This is an embarrassing programming error. Attempting to dump core now. (#4.3.0)\n");
+ out("Z4.3.0 mxf-remote HASH_FIND no entry. Attempting to dump core now.\n");
zero();
- buffer_flush(buffer_2_);
+ buffer_flush(&buffer_2_);
abort();
}
void _noreturn_ temp_noconn() _HSC
- out("ZSorry, I wasn't able to establish a connection to the target mail exchanger. (#4.4.1)\n");
+ out("Z4.4.1 Sorry, I wasn't able to establish a connection to the target mail exchanger.\n");
+ zerodie();
+}
+void _noreturn_ temp_dnsupd() _HSC
+ out("Z4.0.0 DNSUPD Sorry, selecting on my DNS resolver gave me an error: \"");
+ out(error_str(errno));
+ out("\"\n");
+ zerodie();
+}
+void _noreturn_ temp_wtf(char const *my) _HSC
+ out("Z4.0.0 WTF Sorry, "); out(my); out(" referred me to errno: \"");
+ out(error_str(errno));
+ out("\"");
zerodie();
}
void _noreturn_ temp_read() _HSC
- out("ZUnable to read message. (#4.3.0)\n");
+ out("Z4.3.0 Unable to read message.\n");
zerodie();
}
void _noreturn_ temp_dnscanon() _HSC
- out("ZCNAME lookup failed temporarily. (#4.4.3)\n");
+ out("Z4.4.3 CNAME lookup failed temporarily.\n");
zerodie();
}
void _noreturn_ temp_dns() _HSC
- out("ZSorry, I couldn't find any host by that name. (#4.1.2)\n");
+ out("Z4.1.2 Sorry, I couldn't find any host by that name.\n");
zerodie();
}
void _noreturn_ temp_chdir() _HSC
- out("ZUnable to switch to home directory. (#4.3.0)\n");
+ out("Z4.3.0 Unable to switch to home directory.\n");
zerodie();
}
void _noreturn_ temp_control() _HSC
- out("ZMissing or malformed control files. (#4.3.0)\n");
+ out("Z4.3.0 Missing or malformed control files.\n");
zerodie();
}
// The next one belongs in -smtpc only, but is retained here.
void _noreturn_ perm_partialline() _HSC
- out("DSMTP cannot transfer messages with partial final lines. (#5.6.2)\n");
- zerodie();
+ out("D5.6.2 SMTP cannot transfer messages with partial final lines.\n");
+ zerodie();
}
void _noreturn_ perm_usage() _HSC
- out("DI (");
- out(&progname);
- out(") was invoked improperly. If this occurs in mxf-remote-qmtpc or mxf-remote-smtpc, that means there is a bug in mxf-remote - contact the developers to report this! (#5.3.5)\n");
+ out("D5.3.5 I (");
+ out(PROG);
+ out(") was invoked improperly. If this occurs in mxf-remote-qmtpc or mxf-remote-smtpc, that means there is a bug in mxf-remote - contact the developers to report this!\n");
zerodie();
}
void _noreturn_ perm_dns() _HSC
- out("DSorry, I couldn't find any host named ");
- outsafe(&host);
- out(". (#5.1.2)\n");
+ out("D5.1.2 Sorry, I couldn't find any host named ");
+ outsafe(&Host);
+ out(".\n");
zerodie();
}
void _noreturn_ perm_nomx() _HSC
- out("DSorry, I couldn't find a mail exchanger, SRV _smtp._tcp or IP address. (#5.4.4)\n");
+ out("D5.4.4 Sorry, I couldn't find a mail exchanger, SRV _smtp._tcp or IP address.\n");
zerodie();
}
void _noreturn_ perm_ambigmx() _HSC
- out("DSorry. Although I'm listed as a best-preference MX or A for that host,\n" // this is legal nowadays, so we do it fbo highlighters
- "it isn't in my control/locals file, so I don't treat it as local. (#5.4.6)\n");
+ out("D5.4.6 Sorry. Although I'm listed as a best-preference MX or A for that host,\n" // this is legal nowadays, so we do it fbo highlighters
+ "it isn't in my control/locals file, so I don't treat it as local.\n");
zerodie();
}
+#ifdef REMOTEDEBUG
+void info_dbg(stralloc *info) _HSC
+ out("I");
+ buffer_put(&buffer_2_, info->s, info->len);
+ out("\n");
+ return;
+}
+void info_dbgs(const char *info) _HSC
+ out("I");
+ buffer_puts(&buffer_2_, info);
+ out("\n");
+ return;
+}
+void info_wtfs(const char *info) _HSC
+ out("I3.0.0 FYI: "); out(info); out(" referred me to errno: \"");
+ out(error_str(errno));
+ out("\"");
+ return;
+}
+#else
+void info_dbg(stralloc *info) _HSC
+ return;
+}
+void info_dbgs(const char *info) _HSC
+ return;
+}
+void info_wtfs(const char *info) _HSC
+ return;
+}
+#endif // RESOLVDEBUGC
diff --git a/src/mxf-remote/errs.h b/src/mxf-remote/errs.h
@@ -1,8 +1,10 @@
+#ifndef MXFR_ERRS_H
+#define MXFR_ERRS_H
#include <skalibs/stralloc.h>
#define _HSC ;
-void out(char *s) _HSC
+void out(const char *s) _HSC
void zero() _HSC
void _noreturn_ zerodie() _HSC
void outsafe(stralloc *sa) _HSC
@@ -12,15 +14,32 @@ void _noreturn_ temp_hasherr() _HSC
void _noreturn_ temp_finderr() _HSC
void _noreturn_ temp_fault() _HSC
void _noreturn_ temp_intr() _HSC
+void _noreturn_ temp_bug() _HSC
void _noreturn_ temp_noconn() _HSC
void _noreturn_ temp_read() _HSC
void _noreturn_ temp_runfds() _HSC
void _noreturn_ temp_dnscanon() _HSC
void _noreturn_ temp_dns() _HSC
+void _noreturn_ temp_dnsupd() _HSC
+void _noreturn_ temp_wtf(char const *my) _HSC
+void _noreturn_ temp_esc(int b, int c, char const *my) _HSC
void _noreturn_ temp_chdir() _HSC
void _noreturn_ temp_control() _HSC
+//void _noreturn_ temp_custom(char *) _HSC
void _noreturn_ perm_partialline() _HSC
void _noreturn_ perm_usage() _HSC
void _noreturn_ perm_dns() _HSC
void _noreturn_ perm_nomx() _HSC
void _noreturn_ perm_ambigmx() _HSC
+void _noreturn_ temp_wtf(char const *my) _HSC
+void _noreturn_ perm_esc(int b, int c, char const *my) _HSC
+#ifdef REMOTEDEBUG
+void info_dbg(stralloc *info) _HSC
+void info_dbgs(const char *info) _HSC
+void info_wtfs(const char *info) _HSC
+#else
+void info_dbg(stralloc *info) _HSC
+void info_dbgs(const char *info) _HSC
+void info_wtfs(const char *info) _HSC
+#endif // REMOTEDEBUG
+#endif // MXFR_ERRS_H
diff --git a/src/mxf-remote/mxf-remote.c b/src/mxf-remote/mxf-remote.c
@@ -1,16 +1,20 @@
/* src/mxf-remote/mxf-remote.c
- * requires skalibs, s6-networking and s6-dns; if not, you must
- * use regular qmail-remote with the attendant loss of
- * functionality with qmtp, tls and ipv6.
- */
-
+ * requires skalibs, s6-networking and s6-dns; if not, you must
+ * use regular qmail-remote with the attendant loss of
+ * functionality with qmtp, tls and ipv6.
+ */
+#ifndef mxf_remote_c
+#define mxf_remote_c
#include "mxf-remote.h"
#include "errs.h"
//#include <s6-dns/skadns.h>
-tain Deadline, Stamp;
+tain Deadline, Stamp, Limit;
//protocol_t protocols[SLICE_LAST];
-genalloc Protocols = GENALLOC_ZERO; // genalloc_*(protocol_t
+//TypeAlloc_typedef(protoAlloc,protocol_t,pt,len,a)
+//TypeAlloc_readyplus(protoAlloc,protocol_t,pt,len,a,10,protoalloc_readyplus)
+//TypeAlloc_append(protoAlloc,protocol_t,pt,len,a,10,protoalloc_readyplus,protoalloc_catp)
+protoAlloc Protocols = TA_ZERO; // genalloc_*(protocol_t
//genalloc maproutes = GENALLOC_ZERO; // genalloc_*(constmap
char Errbuf[512];
buffer buffer_2_ = BUFFER_INIT(&buffer_write, 2, Errbuf, 512);
@@ -27,13 +31,27 @@ stralloc Ucspitlsclient = STRALLOC_ZERO, Tlsclient = STRALLOC_ZERO;
char PROTOMAPTEXT[] = "qmtps 6209 3 Y N mxf-remote-qmtpc\n" \
"qmtp 209 1 N N mxf-remote-qmtpc\n" \
"smtp 25 0 N Y mxf-remote-smtpc\n";
-protocol_t Slicemap[MAXSLICES]; // quite a bloated thing really; maybe should use a UTHash
+protocol_t *Slicemap[MAXSLICES];
//genalloc Descriptors; // of type descriptor_t
+//TypeAlloc_typedef(saAlloc,stralloc,sa,len,a)
+//TypeAlloc_readyplus(saAlloc,stralloc,sa,len,a,10,saalloc_readyplus)
+//TypeAlloc_append(saAlloc,stralloc,sa,len,a,10,saalloc_readyplus,saalloc_catsa)
+//TypeAlloc_typedef(pfdAlloc,struct pollfd,pfd,len,a)
+//TypeAlloc_readyplus(pfdAlloc,struct pollfd,pfd,len,a,10,pfdalloc_readyplus)
+//TypeAlloc_append(pfdAlloc,struct pollfd,pfd,len,a,10,pfdalloc_readyplus,pfdalloc_catpfd)
+saAlloc Rcptlist = TA_ZERO;
int Sigfd;
+signed int ReadyToSend = 0; /*
+ * Set this to -1 when the remote domain doesn't accept mail, or 1 when
+ * we have a complete (unsorted) picture of how they do.
+ */
+
descriptor_t *Descriptortab = NULL; // NOTES-mxfr - A word on memory management - strong pointers
process_t *Protegetab = NULL; // NOTES-mxfr - A word on memory management
dnsq_t *Dnsqtab = NULL; // NOTES-mxfs - A word on memory management
+void getroutes (protocol_t *protocol);
+
// in order: pollfd (single entry), opaque (may be NULL), fdcb(descriptor_t*, void*)
int descriptor_add (struct pollfd fd, void* opaque,
int (*fdcb)(descriptor_t*, short, void*))
@@ -41,7 +59,7 @@ int descriptor_add (struct pollfd fd, void* opaque,
descriptor_t *descriptor = NULL;
HASH_FIND_INT(Descriptortab, &(fd.fd), descriptor);
- if (descriptor != NULL) temp_hasherr();
+ if (descriptor != NULL) return (errno = ENOENT, FALSE);
// Otherwise...
descriptor = malloc(sizeof(descriptor_t)); // strong pointer; if we cannot add this to the hash, we must free it
descriptor->fd = fd;
@@ -88,24 +106,25 @@ int protege_del (pid_t pid)
process_t *protege = NULL;
HASH_FIND(hh, Protegetab, &(pid), sizeof(pid_t), protege);
- if (protege == NULL) return FALSE;
+ if (protege == NULL) return (errno = ENOENT, FALSE);
HASH_DEL(Protegetab, protege);
free(protege);
return TRUE;
}
// in order: dnsqtab, process ID, opaque to be passed to the report callback, report callback
-int dnsq_add (uint16_t dnsqid, void* opaque,
- int (*qcb)(skadns_t*, dnsq_t*, void*))
+int dnsq_add (uint16_t dnsqid, void* opaque, void* opaque2,
+ int (*qcb)(skadns_t*, dnsq_t*, void*, void*))
{
dnsq_t *dnsq = NULL;
- HASH_FIND(hh, Dnsqtab, &pid, sizeof(uint16_t), dnsq);
+ HASH_FIND(hh, Dnsqtab, &dnsqid, sizeof(uint16_t), dnsq);
if (dnsq != NULL) temp_hasherr();
// Otherwise...
- dnsq = malloc(sizeof(descriptor_t)); // strong pointer; if we cannot add this to the hash, we must free it
+ dnsq = malloc(sizeof(dnsq_t)); // strong pointer; if we cannot add this to the hash, we must free it
dnsq->dnsq = dnsqid;
dnsq->opaque = opaque;
+ dnsq->opaque2 = opaque2;
dnsq->qcb = qcb;
HASH_ADD(hh, Dnsqtab, dnsq, sizeof(uint16_t), dnsq);
return TRUE; // if we are returning at all, we have succeeded.
@@ -117,7 +136,7 @@ int dnsq_del (uint16_t dnsqid)
dnsq_t *dnsq = NULL;
HASH_FIND(hh, Dnsqtab, &(dnsqid), sizeof(uint16_t), dnsq);
- if (dnsq == NULL) return FALSE;
+ if (dnsq == NULL) return (errno = ENOENT, FALSE);
HASH_DEL(Dnsqtab, dnsq);
free(dnsq);
return TRUE;
@@ -125,18 +144,18 @@ int dnsq_del (uint16_t dnsqid)
int run_fds (tain *deadline, tain *stamp)
{
- genalloc fds = GENALLOC_ZERO; // pollfd
+ pfdAlloc fds = TA_ZERO; // pollfd
descriptor_t *des = NULL, *tmp = NULL;
- struct pollfd *pfds = NULL; size_t pfdsiz = 0, size_t i = 0;
+ struct pollfd *pfds = NULL; size_t pfdsiz = 0; size_t i = 0;
int pollret = 0;
HASH_ITER(hh, Descriptortab, des, tmp) {
- if (!genalloc_catb((struct pollfd), &fds, des->fd, 1)) temp_nomem();
+ if (!pfdalloc_catpfd(&fds, &(des->fd))) temp_nomem();
des->fd.revents = 0;
++pfdsiz;
}
if (pfdsiz == 0) temp_runfds();
des = NULL; tmp = NULL;
- pfds = (struct pollfd *)fds.s;
+ pfds = (struct pollfd *)(fds.pfd);
pollret = iopause_stamp(pfds, pfdsiz, deadline, stamp);
// and then we wait for iopause to do its thing
// and then iopause wakes us up
@@ -163,28 +182,23 @@ int run_fds (tain *deadline, tain *stamp)
}
default :
for (i = 0; i < pfdsiz; i++) {
- HASH_FIND_INT(Descriptortab, &(pfds[i]->fd), des);
+ HASH_FIND_INT(Descriptortab, &(pfds[i].fd), des);
if (des == NULL) {
temp_finderr(); // could not find the file descriptor in our tables - what kind of wiseguy do we have on here?
}
- if ((pfds[i]->fd.revents & POLLNVAL) != 0) {
+ if (((pfds[i]).revents & POLLNVAL) != 0) {
// file descriptor is not known to the system; bug
temp_bug();
- } else if (pfds[i]->fd.revents != 0) {
- (*(des->fdcb))(des, pfds[i]->fd.revents, des->opaque);
+ } else if ((pfds[i]).revents != 0) {
+ (*(des->fdcb))(des, (pfds[i]).revents, des->opaque);
}
}
}
// done with fds now? right, we return the number of FDs we processed.
- genalloc_free((struct pollfd), fds)
+ free((fds.pfd));
return pollret;
}
-int protocol_run (protocol_t *proto, int mtpfd)
-{
- // we'll have to use a selfpipe of some description elsewhere to understand process termination
-}
-
int handledeadprocess ()
{
process_t *protege = NULL;
@@ -199,7 +213,7 @@ int handledeadprocess ()
return TRUE;
}
-int checksignals (descriptor_t *descr, int revents, void* unused)
+int checksignals (descriptor_t *descr, short revents, void* unused)
{
int sig;
sig = selfpipe_read();
@@ -213,7 +227,7 @@ int checksignals (descriptor_t *descr, int revents, void* unused)
}
}
-int protocols_init (genalloc *protos, char *protomaptext, size_t length)
+int protocols_init (protoAlloc *protos, char *protomaptext, size_t length)
{
size_t i = 0;
char field = 0; /* there are six fields, numbered zero to five
@@ -221,11 +235,10 @@ int protocols_init (genalloc *protos, char *protomaptext, size_t length)
* protoname, port, protoslice, cantls, musttls, executable-filename
*/
size_t lpos = 0, fpos = 0; // record the position we are at in the line
- char comment = 0; //true if line is comment
+ char comment = 0; char s[15]; //true if line is comment
for (i = 0; i < MAXSLICES; i++) {
- memset(&(Slicemap[i]), 0, sizeof(protocol_t));
- (Slicemap[i]).slice = -1;
+ Slicemap[i] = NULL;
}
if (length == 0) {
protomaptext = PROTOMAPTEXT;
@@ -235,7 +248,8 @@ int protocols_init (genalloc *protos, char *protomaptext, size_t length)
memset(&proto, 0, sizeof(protocol_t));
proto.slice = -1;
- for {i = lpos = fpos = 0; i < length; ++i) {
+ for (i = lpos = fpos = 0; i < length; ++i) {
+ buffer_put(buffer_2, &(protomaptext[i]), 1);
switch (protomaptext[i]) {
/* case '\r': // activate this when we have our own control_readfile; until then it's no use
continue; */ // probably DOS; tolerate bad input. If the user is really using a CR in a filename or w/e, it'll be eaten up by a \ doing runahead.
@@ -249,8 +263,9 @@ int protocols_init (genalloc *protos, char *protomaptext, size_t length)
field = 0;
comment = 0;
getroutes(&proto);
- if (proto.srvservice[0] != 0) if (!genalloc_catb(protocol_t, protos, &proto, 1)) return 0;
- if (proto.slice > -1 && proto.slice < 16) memcpy(&(Slicemap[proto.slice]), &proto, sizeof(protocol_t));
+ if (!stralloc_0(&(proto.app))) temp_nomem();
+ if (proto.srvservice[0] != 0) if (!protoalloc_catp(protos, &proto)) temp_nomem();
+ if (proto.slice > -1 && proto.slice < MAXSLICES) Slicemap[proto.slice] = protos->pt + protos->len-1;
memset(&proto, 0, sizeof(protocol_t));
proto.slice = -1;
break;
@@ -261,11 +276,12 @@ int protocols_init (genalloc *protos, char *protomaptext, size_t length)
}
switch (field) {
case 5:
+ if (!stralloc_catb(&(proto.app), &(protomaptext[i]), 1)) temp_nomem();
break;
case 0:
switch (fpos) {
case 0:
- ++comment
+ ++comment;
break;
default :
proto.srvservice[fpos] = 0; // nullcap the srvservice
@@ -277,7 +293,7 @@ int protocols_init (genalloc *protos, char *protomaptext, size_t length)
case 2:
case 3:
case 4:
- fpos = 0;
+ fpos = -1;
++field;
break;
}
@@ -293,7 +309,7 @@ int protocols_init (genalloc *protos, char *protomaptext, size_t length)
if (fpos > PATH_MAX) temp_control(); // malformed
if (i >= length) temp_control(); // malformed
if (protomaptext[i] == 0) temp_control(); // malformed
- proto.app[fpos] = protomaptext[i]; // there is no conceivable reason to have a backslash unless it's part of your fname, so we don't eat it.
+ if (!stralloc_catb(&(proto.app), &(protomaptext[i]), 1)) temp_nomem(); // there is no conceivable reason to have a backslash unless it's part of your fname, so we don't eat it.
break;
case 0:
proto.srvservice[fpos] = protomaptext[++i];
@@ -317,7 +333,7 @@ int protocols_init (genalloc *protos, char *protomaptext, size_t length)
if (fpos < MAXSRVLEN) proto.srvservice[fpos] = protomaptext[i];
break;
case 5: // protoprog (app)
- if (fpos < PATH_MAX) proto.app[fpos] = protomaptext[i];
+ if (fpos < PATH_MAX) if (!stralloc_catb(&(proto.app), &(protomaptext[i]), 1)) temp_nomem(); // there is no conceivable reason to have a backslash unless it's part of your fname, so we don't eat it.
break;
case 1: // defport
if (protomaptext[i] < '0') temp_control();
@@ -325,14 +341,24 @@ int protocols_init (genalloc *protos, char *protomaptext, size_t length)
proto.defport = (proto.defport * 10) + (protomaptext[i] - '0');
break;
case 2: // MXPS slice, DECIMAL
- if (fpos = 0 && !(protomaptext[i] == '-')) proto.slice = 0; // reset slice to 0 as it is -1
+ buffer_puts(buffer_2, " field:");
+ s[fmt_ulong(s, field)] = 0;
+ buffer_puts(buffer_2, s);
+ buffer_puts(buffer_2, " fpos:");
+ s[fmt_ulong(s, fpos)] = 0;
+ buffer_puts(buffer_2, s);
+ buffer_puts(buffer_2, " ");
+ if (fpos == 0 && !(protomaptext[i] == '-')) proto.slice = 0; // reset slice to 0 as it is -1
+ buffer_puts(buffer_2, s);
if (proto.slice != -1) { // a slice of -1 means we are not using a slice and this is a SRV only protocol
- switch (protomaptext[i]) {
- case '0': case '1': case '2': case '3':
- case '4': case '5': case '6': case '7':
- case '8': case '9':
- proto.defport = (proto.defport * 10) + (protomaptext[i] - '0');
- default : temp_control();
+ if (!(protomaptext[i] < '0' || protomaptext[i] > '9')) {
+ proto.slice = (proto.slice * 10) + (protomaptext[i] - '0');
+ } else {
+ info_dbgs("detected non-numeric character in slice number ");
+ out("it was ");
+ buffer_put(buffer_2, &protomaptext[i], 1);
+ info_dbgs("");
+ temp_control();
}
}
break;
@@ -375,17 +401,17 @@ int protocols_init (genalloc *protos, char *protomaptext, size_t length)
}
}
++lpos; ++fpos; // if comment notreached; lpos and fpos don't run if we are in a comment.
- // lpos and fpos only increase 1 for every 2 characters if every first character is a \
+ // lpos and fpos only increase 1 for every 2 characters if every first character is a backstroke
}
// the music is over. we're at the end of the file, on a partial line. hopefully app is at least an app we can try.
- if (proto.app[0] != 0) {
+ if (proto.app.len > 1) {
getroutes(&proto);
- if (!genalloc_catb(protocol_t, protos, &proto, 1)) return 0;
+ if (!protoalloc_catp(protos, &proto)) return 0;
}
return 1;
-
}
+
// imported from qmail-remote
// inputs: controlfiles from the filesystem
// outputs: none
@@ -396,7 +422,7 @@ void getcontrols()
if (control_init() == -1) temp_control();
//if (control_readint(&timeout,"control/timeoutremote") == -1) temp_control();
// The client application is responsible for this.
- if (control_readint(&Timeoutconnect,"control/Timeoutconnect") == -1)
+ if (control_readint(&Timeoutconnect,"control/timeoutconnect") == -1)
temp_control();
// if (control_rldef(&helohost,"control/helohost",1,NULL) != 1)
// temp_control();
@@ -410,7 +436,7 @@ void getcontrols()
case 0:
if (!protocols_init(&(Protocols),"",0)) temp_nomem(); break;
case 1:
- if (!protocols_init(&(Protocols),protocolsraw.s,protocolsraw.len)) temp_nomem(); break;
+ if (!protocols_init(&(Protocols),Protocolsraw.s,Protocolsraw.len)) temp_nomem(); break;
}
// It strikes me that Protocolsraw is used nowhere else in the file.
}
@@ -432,11 +458,30 @@ void getroutes (protocol_t *protocol)
stralloc_free(&ctrl);
}
-int checkdns (descriptor_t *descr, int revents, void* dnsresv)
+int checkdns (descriptor_t *descr, short revents, void* dnsresv)
{
skadns_t *dnsres = (skadns_t *)dnsresv;
- int upd;
+ int upd; size_t dnsqlen = 0, i = 0;
+ uint16_t *dnsqs = NULL; dnsq_t *dnsq = NULL;
upd = skadns_update(dnsres);
+ switch (upd) {
+ case -1:
+ temp_dnsupd();
+ return FALSE; // NOTREACHED we should not be here but...
+ break;
+ default : // there either has, or has not been, a response to collect. let's do that now.
+ dnsqs = genalloc_s(uint16_t, &dnsres->list); // have to use genalloc here as that's what Ska uses in skadns
+ dnsqlen = genalloc_len(uint16_t, &dnsres->list);
+ for (i = 0; i < dnsqlen; ++i) {
+ // we must now call the callback and delete the query from the list
+ HASH_FIND(hh, Dnsqtab, (dnsqs + i), sizeof(uint16_t), dnsq);
+ (*dnsq->qcb)(dnsres, dnsq, (dnsq->opaque), (dnsq->opaque2)); // not exactly sure the use of passing the full query if we'll just delet it
+ skadns_release(dnsres, dnsqs[i]);
+ dnsq_del(dnsqs[i]);
+ dnsq = NULL;
+ }
+ }
+ return TRUE;
}
void startdns (skadns_t *dnsres) {
@@ -447,31 +492,539 @@ void startdns (skadns_t *dnsres) {
}
}
+int ipisme (const ipmx_t *ip) {
+ // wrapper around ipme and ip6me
+ const ip46full *ix = &(ip->ip);
+ struct ip_address i4;
+ struct ip6_address i6;
+ if (ix->is6) {
+ memcpy(&(i6.d), &(ix->ip), 16);
+ return ip6me_is(i6);
+ } else {
+ memcpy(&(i4.d), &(ix->ip), 4);
+ return ipme_is(i4);
+ }
+}
+
void stopdns (skadns_t *dnsres) {
skadns_end(dnsres);
}
+/* les noms de ces procs sont misleading.
+ * They should not be thought of as "we definitely have our response"
+ * but as "we MAY have our response."
+ */
+int dns_havea (skadns_t *dnsres, dnsq_t *dnsq, void* mxresultp, void* unused)
+{
+ //protocol_t *proto = (protocol_t *)protop;
+ mxresult_t *mxresult = (mxresult_t *)mxresultp;
+ //mxrAlloc *mxres = &(proto->mxresults);
+ //ipmxAlloc *ipmxres = &(mxres->ipmx);
+ ipmx_t ipmx = {IP46FULL_ZERO};
+ ipmx.ip.is6 = 0;
+ stralloc rrs = STRALLOC_ZERO;
+ char const *dnsresponse; int dnsresplen, i = 0;
+ s6dns_message_header_t dnsmh;
+
+ if ((dnsresponse = skadns_packet(dnsres, dnsq->dnsq)) == NULL) temp_wtf("skadns_packet in dns_haveaaaa");
+ if ((dnsresplen = skadns_packetlen(dnsres, dnsq->dnsq)) == -1) temp_wtf("skadns_packetlen in dns_haveaaaa"); // this should succeed if the above didn't fail
+ if (dnsresplen < 12) { errno = EINVAL; temp_wtf("skadns_packetlen gave dns_haveaaaa less than even a header"); }
+ // s6dns_message_header_unpack(dnsresponse, dnsmh);
+ switch (s6dns_message_parse(&dnsmh, dnsresponse, dnsresplen, &s6dns_message_parse_answer_aaaa, &rrs)) {
+ case -1:
+ temp_wtf("s6dns_message_parse in dns_haveaaaa - local error");
+ break;
+ case 0:
+ info_wtfs("s6dns_message_parse in dns_haveaaaa - rcode - maybe should continue");
+ mxresult->lookupdone = 1;
+ mxresult->hasresults = 0;
+ break;
+ case 1:
+#ifdef REMOTEDEBUG
+ info_dbgs("s6dns_message_parse in dns_haveaaaa - success no answer");
+#endif // REMOTEDEBUG
+ mxresult->lookupdone = 1;
+ mxresult->hasresults = 0;
+ break;
+ case 2:
+#ifdef REMOTEDEBUG
+ info_dbgs("s6dns_message_parse in dns_haveaaaa - success answer");
+#endif // REMOTEDEBUG
+ mxresult->lookupdone = 1;
+ mxresult->hasresults = 1;
+ for (i = 0; i < rrs.len/4; ++i) {
+ memcpy(&(ipmx.ip.ip), (rrs.s + (i * 4)), 4);
+ if (!ipmxalloc_catip(&(mxresult->ipmx), &ipmx)) temp_nomem();
+ if (ipisme(&ipmx)) mxresult->isme = 1;
+ memset(&ipmx, 0, sizeof(ipmx_t)); ipmx.ip.is6 = 0;
+ }
+ break;
+ }
+ return TRUE;
+}
+int dns_haveaaaa (skadns_t *dnsres, dnsq_t *dnsq, void* mxresultp, void* unused)
+{
+ //protocol_t *proto = (protocol_t *)protop;
+ mxresult_t *mxresult = (mxresult_t *)mxresultp;
+ //mxrAlloc *mxres = &(proto->mxresults);
+ //ipmxAlloc *ipmxres = &(mxres->ipmx);
+ ipmx_t ipmx = {IP46FULL_ZERO};
+ ipmx.ip.is6 = 1;
+ stralloc rrs = STRALLOC_ZERO;
+ char const *dnsresponse; int dnsresplen, i = 0;
+ s6dns_message_header_t dnsmh;
+
+ if ((dnsresponse = skadns_packet(dnsres, dnsq->dnsq)) == NULL) temp_wtf("skadns_packet in dns_haveaaaa");
+ if ((dnsresplen = skadns_packetlen(dnsres, dnsq->dnsq)) == -1) temp_wtf("skadns_packetlen in dns_haveaaaa"); // this should succeed if the above didn't fail
+ if (dnsresplen < 12) { errno = EINVAL; temp_wtf("skadns_packetlen gave dns_haveaaaa less than even a header"); }
+ // s6dns_message_header_unpack(dnsresponse, dnsmh);
+ switch (s6dns_message_parse(&dnsmh, dnsresponse, dnsresplen, &s6dns_message_parse_answer_aaaa, &rrs)) {
+ case -1:
+ temp_wtf("s6dns_message_parse in dns_haveaaaa - local error");
+ break;
+ case 0:
+ info_wtfs("s6dns_message_parse in dns_haveaaaa - rcode - maybe should continue");
+ mxresult->lookupdone = 1;
+ mxresult->hasresults = 0;
+ break;
+ case 1:
+#ifdef REMOTEDEBUG
+ info_dbgs("s6dns_message_parse in dns_haveaaaa - success no answer");
+#endif // REMOTEDEBUG
+ mxresult->lookupdone = 1;
+ mxresult->hasresults = 0;
+ break;
+ case 2:
+#ifdef REMOTEDEBUG
+ info_dbgs("s6dns_message_parse in dns_haveaaaa - success answer");
+#endif // REMOTEDEBUG
+#ifdef SKALIBS_IPV6_ENABLED
+ mxresult->lookupdone = 1;
+ mxresult->hasresults = 1;
+ for (i = 0; i < rrs.len/16; ++i) {
+ memcpy(&(ipmx.ip.ip), (rrs.s + (i * 16)), 16);
+ if (!ipmxalloc_catip(&(mxresult->ipmx), &ipmx)) temp_nomem();
+ if (ipisme(&ipmx)) mxresult->isme = 1;
+ memset(&ipmx, 0, sizeof(ipmx_t)); ipmx.ip.is6 = 1;
+ }
+#endif // SKALIBS_IPV6_ENABLED
+ break;
+ }
+ return TRUE;
+}
+
+int dns_havesrv (skadns_t *dnsres, dnsq_t *dnsq, void* protop, void* unused)
+{
+ protocol_t *proto = (protocol_t *)protop;
+ mxrAlloc *mxres = &(proto->mxresults);
+ mxresult_t mxr = MXRESULT_SRV_ZERO;
+ genalloc rrs = GENALLOC_ZERO;
+ const char *dnsresponse; int dnsresplen, i = 0;
+ s6dns_message_header_t dnsmh;
+ s6dns_message_rr_srv_t *rr = NULL;
+ uint16_t qid4, qid6;
+
+ if ((dnsresponse = skadns_packet(dnsres, dnsq->dnsq)) == NULL) temp_wtf("skadns_packet in dns_havesrv");
+ if ((dnsresplen = skadns_packetlen(dnsres, dnsq->dnsq)) == -1) temp_wtf("skadns_packetlen in dns_havesrv"); // this should succeed if the above didn't fail
+ if (dnsresplen < 12) { errno = EINVAL; temp_wtf("skadns_packetlen gave dns_havesrv less than even a header"); }
+ // s6dns_message_header_unpack(dnsresponse, dnsmh);
+ switch (s6dns_message_parse(&dnsmh, dnsresponse, dnsresplen, &s6dns_message_parse_answer_srv, &rrs)) {
+ case -1:
+ temp_wtf("s6dns_message_parse in dns_havesrv - local error");
+ break;
+ case 0:
+ info_wtfs("s6dns_message_parse in dns_havesrv - maybe should continue");
+ break;
+ case 1:
+#ifdef REMOTEDEBUG
+ info_dbgs("s6dns_message_parse in dns_havesrv - success no answer");
+#endif // REMOTEDEBUG
+ proto->lookupdone = 1;
+ proto->hasresults = 0;
+ break;
+ case 2:
+#ifdef REMOTEDEBUG
+ info_dbgs("s6dns_message_parse in dns_havesrv - success answer");
+#endif // REMOTEDEBUG
+ proto->lookupdone = 1;
+ proto->hasresults = 1;
+ for (i = 0; i < genalloc_len(s6dns_message_rr_srv_t, &rrs); ++i) {
+ rr = (s6dns_message_rr_srv_t *)(rrs.s) + (i * sizeof(s6dns_message_rr_srv_t));
+ mxr.lookupdone = TRUE;
+ mxr.port = rr->port;
+ mxr.prio = rr->priority;
+ mxr.weight = rr->weight;
+ if (!stralloc_readyplus(&(mxr.name), rr->target.len+3)) temp_nomem();
+ if (!(mxr.name.len = s6dns_domain_tostring(mxr.name.s, rr->target.len+3, &(rr->target)))) temp_wtf("s6dns_domain_tostring in dns_havesrv");
+ if (!tain_addsec(&Limit, &Stamp, Timeoutconnect)) temp_wtf("tain_addsec in dns_havesrv (Doctor?)");
+ if (!tain_addsec(&Deadline, &Stamp, 1)) temp_wtf("tain_addsec in dns_havesrv (Doctor?)");
+ if (!mxralloc_catmxr(mxres, &mxr)) temp_nomem();
+ if (mxr.name.len > 1) { // No point if it's just a dot
+ if (!skadns_send(&Dnsres, &qid4, &(rr->target), S6DNS_T_A, &Limit, &Deadline, &Stamp)) temp_wtf("skadns_send in dns_havesrv");
+ if (!dnsq_add(qid4, &(mxres->mxr[(mxres->len)-1]), NULL, dns_havea)) temp_wtf("dnsq_add in dns_havesrv");
+ if (!skadns_send(&Dnsres, &qid6, &(rr->target), S6DNS_T_AAAA, &Limit, &Deadline, &Stamp)) temp_wtf("skadns_send in dns_havesrv");
+ if (!dnsq_add(qid6, &(mxres->mxr[(mxres->len)-1]), NULL, dns_haveaaaa)) temp_wtf("dnsq_add in dns_havesrv");
+ }
+ mxresult_t mxr = MXRESULT_SRV_ZERO;
+ }
+ break;
+ }
+ return TRUE;
+}
+int dns_havemx (skadns_t *dnsres, dnsq_t *dnsq, void* protop, void* unused)
+{
+ // XX - should probably pass the whole protoalloc as protop
+ protocol_t *proto = (protocol_t *)protop, *smproto;
+ mxrAlloc *mxres = NULL;
+ mxresult_t mxr = MXRESULT_MX_ZERO;
+ genalloc rrs = GENALLOC_ZERO;
+ char const *dnsresponse; int dnsresplen, i = 0;
+ s6dns_message_header_t dnsmh;
+ s6dns_message_rr_mx_t *rr = NULL;
+ uint16_t qid4, qid6;
+
+ if ((dnsresponse = skadns_packet(dnsres, dnsq->dnsq)) == NULL) temp_wtf("skadns_packet in dns_havemx");
+ if ((dnsresplen = skadns_packetlen(dnsres, dnsq->dnsq)) == -1) temp_wtf("skadns_packetlen in dns_havemx"); // this should succeed if the above didn't fail
+ if (dnsresplen < 12) { errno = EINVAL; temp_wtf("skadns_packetlen gave dns_havemx less than even a header"); }
+ // s6dns_message_header_unpack(dnsresponse, dnsmh);
+ switch (s6dns_message_parse(&dnsmh, dnsresponse, dnsresplen, &s6dns_message_parse_answer_mx, &rrs)) {
+ case -1:
+ temp_wtf("s6dns_message_parse in dns_havemx - local error");
+ break;
+ case 0:
+ info_wtfs("s6dns_message_parse in dns_havemx - maybe should continue");
+ break;
+ case 1:
+#ifdef REMOTEDEBUG
+ buffer_puts(&buffer_2_, "Is6dns_message_parse in dns_havemx - success no answer\n");
+#endif // REMOTEDEBUG
+
+ break;
+ case 2:
+#ifdef REMOTEDEBUG
+ buffer_puts(&buffer_2_, "Is6dns_message_parse in dns_havemx - success answer\n");
+#endif // REMOTEDEBUG
+ for (i = 0; i < genalloc_len(s6dns_message_rr_mx_t, &rrs); ++i) {
+ rr = (s6dns_message_rr_mx_t *)(rrs.s) + (i * sizeof(s6dns_message_rr_mx_t));
+ mxr.lookupdone = TRUE;
+ if (_is_mxps(rr->preference)) {
+ if ((proto = Slicemap[_mxps_slice(rr->preference)]) == NULL) proto = Slicemap[NOMXPS_SLICE];
+ mxr.prio = _mxps_prio(rr->preference);
+ } else {
+ proto = Slicemap[NOMXPS_SLICE];
+ mxr.prio = rr->preference;
+ }
+ if (proto == NULL) {errno = EINVAL; temp_wtf("dns_havemx - postmanager has not configured a zero MXPS slice, and this is necessary.");}
+ proto->hasresults = 1;
+ mxres = &(proto->mxresults);
+ mxr.port = proto->defport;
+ mxr.weight = 0;
+ if (!stralloc_readyplus(&(mxr.name), rr->exchange.len+3)) temp_nomem();
+ if (!(mxr.name.len = s6dns_domain_tostring(mxr.name.s, rr->exchange.len+3, &(rr->exchange)))) temp_wtf("s6dns_domain_tostring in dns_havemx");
+ if (!tain_addsec(&Limit, &Stamp, Timeoutconnect)) temp_wtf("tain_addsec in dns_havemx (Doctor?)");
+ if (!tain_addsec(&Deadline, &Stamp, 1)) temp_wtf("tain_addsec in dns_havemx (Doctor?)");
+ if (!mxralloc_catmxr(mxres, &mxr)) temp_nomem();
+ if (mxr.name.len > 1) { // No point if it's just a dot, NPI.
+ if (!skadns_send(&Dnsres, &qid4, &(rr->exchange), S6DNS_T_A, &Limit, &Deadline, &Stamp)) temp_wtf("skadns_send in dns_havemx");
+ if (!dnsq_add(qid4, &(mxres->mxr[(mxres->len)-1]), NULL, dns_havea)) temp_wtf("dnsq_add in dns_havemx");
+ if (!skadns_send(&Dnsres, &qid6, &(rr->exchange), S6DNS_T_AAAA, &Limit, &Deadline, &Stamp)) temp_wtf("skadns_send in dns_havemx");
+ if (!dnsq_add(qid6, &(mxres->mxr[(mxres->len)-1]), NULL, dns_haveaaaa)) temp_wtf("dnsq_add in dns_havemx");
+ }
+ mxresult_t mxr = MXRESULT_MX_ZERO;
+ }
+ break;
+ }
+ return TRUE;
+}
+/*
+int dns_havecname (skadns_t *dnsres, dnsq_t *dnsq, void* protop, void *unused)
+{
+ // We should only encounter this guy if we are using relayhost.
+ protocol_t *proto = (protocol_t *)protop;
+ mxrAlloc *mxres = &(proto->mxresults);
+ mxresult_t mxr = {0, 0, 0, FALSE, FALSE, STRALLOC_ZERO, TA_ZERO};
+ genalloc rrs;
+ char const *dnsresponse; int dnsresplen;
+ s6dns_message_header_t dnsmh;
+}
+*/
+
+/*
+int protocol_want_srvmx (protocol_t *proto,
+int protocol_have_mx (protocol_t *proto,
+int protocol_want_ip (protocol_t *proto,
+int protocol_have_mxip (protocol_t *proto,
+int protocol_wantfd (protocol_t *proto, int mtpfd)
+{
+ // we'll have to use a selfpipe of some description elsewhere to understand process termination
+}
+ *
+int protocol_spin (protocol_t *proto, char stage, unsigned long port,
+ char **rrecips, char *relayhost, size_t nprotos)
+{
+}*/
+
+// offset is needed in case we're skipping the first protocol for some reason.
+// until then, it should always be zero
+// nproto is the number of protocols we're doing
+// mxralloc is inside the protocol, so
+int dns_wantsrv (protocol_t *protos, size_t nproto)
+{
+ int i = 0;
+ uint16_t qtype = S6DNS_T_SRV, id = 0;
+ s6dns_domain_t dnsdomain;
+ stralloc domain = STRALLOC_ZERO;
+ //mxresult_t mxr = {0, 0, 0, STRALLOC_ZERO, TA_ZERO};
+ //mxrAlloc *mxrs;
+ //tain limit, dl;
+
+ for (i = 0; i < nproto; ++i) {
+ //mxrs = protos[i].mxresults.mxr;
+ if (!stralloc_copys(&domain, "_")) temp_nomem();
+ if (!stralloc_cats(&domain, protos[i].srvservice)) temp_nomem();
+ if (!stralloc_cats(&domain, "._tcp.")) temp_nomem();
+ if (!stralloc_cats(&domain, Host.s)) temp_nomem();
+ //if (!stralloc_0(&domain)) temp_nomem();
+ if (!s6dns_domain_fromstring_noqualify_encode(&dnsdomain, domain.s, domain.len)) temp_wtf("s6dns_domain_fromstring_noqualify_encode in dns_wantsrv");
+ if (!tain_addsec(&Limit, &Stamp, Timeoutconnect)) temp_wtf("tain_addsec in dns_wantsrv (Doctor?)");
+ if (!tain_addsec(&Deadline, &Stamp, 1)) temp_wtf("tain_addsec in dns_wantsrv (Doctor?)");
+ if (!skadns_send(&Dnsres, &id, &dnsdomain, qtype, &Limit, &Deadline, &Stamp)) temp_wtf("skadns_send in dns_wantsrv");
+ if (!dnsq_add(id, (protos + i), NULL, dns_havesrv)) temp_wtf("dnsq_add in dns_wantsrv");
+ }
+ stralloc_free(&domain);
+ return TRUE; // not used
+}
+
+int dns_wantmx (protocol_t *protos, size_t nproto)
+{
+ int i = 0;
+ uint16_t qtype = S6DNS_T_MX, id = 0;
+ s6dns_domain_t dnsdomain;
+ stralloc domain = STRALLOC_ZERO;
+ //tain limit, dl;
+ // mxresult_t mxr = {0, 0, 0, FALSE, FALSE, TRUE, STRALLOC_ZERO, TA_ZERO};
+
+ if (!stralloc_cats(&domain, Host.s)) temp_nomem();
+ //if (!stralloc_0(&domain)) temp_nomem();
+ if (!s6dns_domain_fromstring_noqualify_encode(&dnsdomain, domain.s, domain.len)) temp_wtf("s6dns_domain_fromstring_noqualify_encode in dns_wantmx");
+ if (!tain_addsec(&Limit, &Stamp, Timeoutconnect)) temp_wtf("tain_addsec in dns_wantmx (Doctor?)");
+ if (!tain_addsec(&Deadline, &Stamp, 1)) temp_wtf("tain_addsec in dns_wantmx (Doctor?)");
+ if (!skadns_send(&Dnsres, &id, &dnsdomain, qtype, &Limit, &Deadline, &Stamp)) temp_wtf("skadns_send in dns_wantmx");
+ if (!dnsq_add(id, protos, NULL, dns_havemx)) temp_wtf("dnsq_add in dns_wantmx");
+ stralloc_free(&domain);
+ return TRUE; // not used
+}
+
+// the only entrypoint to this is a DNS relayhost
+int dns_wantip (protocol_t *proto, uint16_t port, char *relayhost)
+{
+ int i = 0;
+ uint16_t qid4 = 0, qid6 = 0;
+ s6dns_domain_t dnsdomain;
+ stralloc domain = STRALLOC_ZERO;
+ //tain limit, dl; &(mxres->mxr[(mxres->len)-1])
+ mxresult_t mxr = MXRESULT_SRV_ZERO;
+ mxrAlloc *mxres = &(proto->mxresults);
+
+ mxr.port = port;
+
+ if (!stralloc_cats(&domain, relayhost)) temp_nomem();
+ //if (!stralloc_0(&domain)) temp_nomem();
+ if (!s6dns_domain_fromstring_noqualify_encode(&dnsdomain, domain.s, domain.len)) temp_wtf("s6dns_domain_fromstring_noqualify_encode in dns_wantip");
+ if (!tain_addsec(&Limit, &Stamp, Timeoutconnect)) temp_wtf("tain_addsec in dns_wantip (Doctor?)");
+ if (!tain_addsec(&Deadline, &Stamp, 1)) temp_wtf("tain_addsec in dns_wantip (Doctor?)");
+ if (!mxralloc_catmxr(mxres, &mxr)) temp_nomem();
+ if (!skadns_send(&Dnsres, &qid6, &dnsdomain, S6DNS_T_AAAA, &Limit, &Deadline, &Stamp)) temp_wtf("skadns_send in dns_wantip");
+ if (!dnsq_add(qid6, &(mxres->mxr[(mxres->len)-1]), NULL, dns_haveaaaa)) temp_wtf("dnsq_add in dns_wantip");
+ if (!skadns_send(&Dnsres, &qid4, &dnsdomain, S6DNS_T_A, &Limit, &Deadline, &Stamp)) temp_wtf("skadns_send in dns_wantip");
+ if (!dnsq_add(qid4, &(mxres->mxr[(mxres->len)-1]), NULL, dns_havea)) temp_wtf("dnsq_add in dns_wantip");
+ stralloc_free(&domain);
+ return TRUE; // not used
+}
+
+int lookupsdone (protocol_t *proto) {
+ //protocol_t *proto = NULL;
+ mxresult_t *mxr = NULL;
+ int i = 0;
+ if (proto->lookupdone == 0) return FALSE;
+ for (i = 0; i < proto->mxresults.len; ++i) {
+ mxr = (mxresult_t *)((proto->mxresults.mxr) + (i * sizeof(protocol_t)));
+ if (mxr->lookupdone == 0) return FALSE;
+ }
+ return TRUE; // if we have not returned false by now, all lookups are done
+}
+
+// comparator for qsort
+int mxworse (void* mx1p, void* mx2p) {
+ // These get sorted in ascending order.
+ // If mx1 is less preferable than mx2, it is greater (TRUE).
+ // If it is equally preferable, it is equal (FALSE).
+ // If it is more preferable, it is lesser (-1).
+ mxresult_t *mx1 = (mxresult_t *)mx1p;
+ mxresult_t *mx2 = (mxresult_t *)mx2p;
+
+ if ((mx1->ismx) && !(mx2->ismx)) {
+ // literally need do nothing else, we prefer mx2
+ return TRUE;
+ }
+
+ if (mx1->prio > mx2->prio) {
+ // mx1 prio is higher (less prior) than mx2 prio, so true.
+ return TRUE;
+ }
+
+ if (mx1->prio == mx2->prio) {
+ // mx1 prio is equal to mx2 prio, so false, unless weight higher.
+ if (mx1->weight > mx2->weight) return -1; // mx1 is heavier, so more pref (better)
+ if (mx1->weight < mx2->weight) return TRUE; // mx1 is lighter, so less pref (worse)
+ return FALSE;
+ }
+
+ if (mx1->prio < mx2->prio) {
+ // mx1 prio is lower (less prior) than mx2 prio, so true.
+ return -1;
+ }
+ return FALSE; // Not reached.
+}
+
+void printprotos () {
+ protocol_t *proto = NULL;
+ mxresult_t *mxr = NULL;
+ ipmx_t *ipmx = NULL;
+ char s[48]; int i = 0, j = 0; unsigned long l = 0;
+ memset(&s, 0, 48);
+ if (Protocols.len < 1) {
+ info_dbgs("3.3.0 No protocols on the protocol array!");
+ } else {
+ for (i = 0; i < Protocols.len; ++i) {
+ proto = (protocol_t *)((Protocols.pt) + (i * sizeof(protocol_t)));
+ out("I3.0.0 ");
+ out("Protocol element #");
+ fmt_ulong(s, i);
+ out(s);
+ out(": \n srvservice: ");
+ out(proto->srvservice);
+ out("\n defport: ");
+ fmt_uint(s, proto->defport);
+ out(s);
+ if (proto->slice < 0)
+ out("\n no MXPS slice for this protocol");
+ else {
+ l = proto->slice;
+ out("\n slice: ");
+ fmt_uint(s, l);
+ out(s);
+ }
+ switch (proto->tls) {
+ case 1:
+ out("\n will use TLS");
+ break;
+ case 0:
+ switch (proto->starttls) {
+ case 1:
+ out("\n can use TLS");
+ break;
+ case 0:
+ out("\n cannot use TLS");
+ break;
+ }
+ }
+ if (proto->maproutes.num != 0) {
+ out("\n has ");
+ out(proto->srvservice);
+ out("routes");
+ } else {
+ out("\n does not have ");
+ out(proto->srvservice);
+ out("routes");
+ }
+ switch (proto->lookupdone) {
+ case 0:
+ out("\n DNS lookups have not been done");
+ break;
+ case 1:
+ switch (proto->hasresults) {
+ case 3:
+ case 2:
+ out("\n direct A results exist");
+ break;
+ case 1:
+ out("\n MX or SRVmail results exist");
+ for (j = 0; j < proto->mxresults.len; ++j) {
+ out("\n port: ");
+ fmt_uint(s, proto->mxresults.mxr[j].port);
+ out(s);
+ out(" prio: ");
+ fmt_uint(s, proto->mxresults.mxr[j].prio);
+ out(s);
+ out(" weight: ");
+ fmt_uint(s, proto->mxresults.mxr[j].weight);
+ out(s);
+ out(" SRV/MX: ");
+ out(proto->mxresults.mxr[j].ismx ? "MX" : "SRV");
+ out(" lookupdone: ");
+ out(proto->mxresults.mxr[j].lookupdone == 1 ? "yes" : "no");
+ out(" has results: ");
+ out(proto->mxresults.mxr[j].hasresults == 1 ? "yes" : proto->mxresults.mxr[j].hasresults > 1 ? "literal IP " : "no");
+ out(" name: ");
+ buffer_put(buffer_2, proto->mxresults.mxr[j].name.s, proto->mxresults.mxr[j].name.len);
+ if (proto->mxresults.mxr[j].ipmx.len > 0) {
+ out("\n first IP result: ");
+ s[ip46full_fmt(s, &(proto->mxresults.mxr[j].ipmx.ipmx[0].ip))] = 0;
+ out(s);
+ }
+ }
+ break;
+ case 0:
+ out("\n MX or SRVmail results do not exist");
+ break;
+ }
+ }
+ out("\n app: ");
+ buffer_put(buffer_2, proto->app.s, proto->app.len);
+ out("\n\n");
+ buffer_flush(buffer_2);
+ }
+ }
+}
+
+int lookupsdone_all (protocol_t *protos, int nprotos)
+{
+ // protos should be a pointer to the beginning of the protocol list as we are using it.
+ int i = 0;
+ for (; i < nprotos; ++i) {
+ if (!lookupsdone((protos + i))) return FALSE;
+ }
+ return TRUE;
+}
+
// so we need to deduce the hostname to feed to tcpclient, then we need to launch tcpclient (s/qmtpc), wait on its exit, and maybe try again with a different hostname
// we could also, if we wanted, be tcpclient ourselves, and just launch things under ucspitlsclient as relevant
int main (int argcount, char **args)
{
- char **rrecips, *relayhost; int ;
- int i, port; char skipmx = 0; protocol_t *routesproto = NULL, *proto = NULL;
- sigset_t sigset;
+ char **rrecips, *relayhost;
+ int i = 0, offset = 0, nprotos = 0; unsigned long port; char skipmx = 0, fullresults = 0;
+ protocol_t *routesproto = NULL, *proto = NULL; ipmx_t ipmx = {IP46FULL_ZERO};
+ sigset_t sigset; mxresult_t rhmxr = MXRESULT_SLIP_ZERO; mxrAlloc mxres = TA_ZERO; // mxresu is unsorted
+ tain shortdl;
PROG = "mxf-remote";
tain_now(&Stamp);
- tain_addsecond_deadline(&Deadline, &Stamp, 2); // eh, the manpages at skarnet's website said to do this so I will
+ tain_addsec(&Deadline, &Stamp, 2); // eh, the manpages at skarnet's website said to do this so I will
// check basic configuration
if (argcount < 4) perm_usage();
if (chdir(auto_qmail) == -1) temp_chdir();
if (!stralloc_copys(&Host,args[1])) temp_nomem();
+ //if (!stralloc_0(&Host)) temp_nomem();
if (!stralloc_copys(&Sender,args[2])) temp_nomem();
+ //if (!stralloc_0(&Sender)) temp_nomem();
getcontrols();
+ ipme_init();
+ ip6me_init();
// trap signals
sig_ignore(SIGPIPE);
@@ -485,6 +1038,7 @@ int main (int argcount, char **args)
sigpfd.revents = 0;
descriptor_add(sigpfd, (void *)&Protegetab, &checksignals);
+ printprotos();
/* Of interest here is that ... NOTES-mxfr #0010 */
/* So at this stage we know what the protocols are and we can decide
@@ -494,8 +1048,17 @@ int main (int argcount, char **args)
* will have the scoop.
* ga_foreach doesn't support non-pointer structs, so we make a pointer here.
*/
- ga_foreach (protocol_t, &(Protocols), i) {
- proto = Protocols.s + (i * sizeof(protocol_t));
+ startdns(&Dnsres);
+ struct pollfd dnspfd;
+ dnspfd.fd = skadns_fd(&Dnsres);
+ dnspfd.events = POLLIN;
+ dnspfd.revents = 0;
+ descriptor_add(dnspfd, (void *)&Dnsres, &checkdns);
+ rrecips = args + 3;
+
+ for (i = 0; i < Protocols.len; i++) {
+ // proto = (protocol_t *)((Protocols.pt) + (offset = (i * sizeof(protocol_t))) ); // fallback version
+ proto = (protocol_t *)&(Protocols.pt[i]);
// This is lifted from qmail-remote.c:333 with minimal changes
// to fit the new system.
// I do not purport to understand it.
@@ -504,6 +1067,7 @@ int main (int argcount, char **args)
if ((relayhost = constmap(&(proto->maproutes),Host.s + i,Host.len - i))) {
skipmx = 1;
routesproto = proto;
+ nprotos = 1;
}
}
if (relayhost && !*relayhost) relayhost = 0;
@@ -516,21 +1080,54 @@ int main (int argcount, char **args)
}
if (!stralloc_copys(&Host,relayhost)) temp_nomem();
}
+
+ if (!port) port = routesproto->defport;
if (skipmx) break;
}
- startdns(&Dnsres);
- struct pollfd dnspfd;
- dnspfd.fd = skadns_fd(&Dnsres);
- dnspfd.events = POLLIN;
- dnspfd.revents = 0;
- descriptor_add(dnspfd, (void *)&Dnsres, &checkdns);
- switch (skipmx) {
- case 0:
- case 1:
+ // fire off the SRV/MX DNS volley; wait Timeoutconnect seconds from when
+ // we're finished bowling to when we give up on run_fds
+ // also break if a foreach loop of lookupsdone(Protocols.pt[i]) does not return false
+ if (!skipmx) {
+ proto = (protocol_t *)((Protocols.pt) + (offset = 0)); // reset the proto pointer
+ nprotos = Protocols.len; // it's 1 if we are skipping MX and SRVmail
+ }
+
+ if (relayhost) {
+ if (!ip46_scan(relayhost, &(ipmx.ip))) {
+ dns_wantip(routesproto, port, relayhost);
+ } else {
+ routesproto->hasresults = 1;
+ routesproto->lookupdone = 1;
+ // I guess we're building an mxr then...
+ rhmxr.port = port;
+ rhmxr.hasresults = 2;
+ // prio/wt dealt with
+ if (!stralloc_copys(&(rhmxr.name), relayhost)) temp_nomem();
+ if (!stralloc_0(&(rhmxr.name))) temp_nomem();
+ if (!ipmxalloc_catip(&(rhmxr.ipmx), &ipmx)) temp_nomem();
+ }
+ } else {
+ // our DNS volley
+ dns_wantsrv(proto, nprotos);
+ dns_wantmx(proto, nprotos);
}
- //for (i = 0; i * sizeof(protocol_t) <
+ tain_now(&Stamp);
+ tain_addsec(&Deadline, &Stamp, Timeoutconnect);
+ tain_addsec(&shortdl, &Stamp, 3);
+
+ while (!lookupsdone_all(proto, nprotos)) {
+ if (run_fds(&shortdl, &Stamp) == 0) info_dbgs("curious, iopause got nothing but the loop went around"); // This'll update the stamp and run callbacks automatically.
+ tain_addsec(&shortdl, &Stamp, 3);
+ if (!tain_less(&Stamp, &Deadline)) {
+ errno = ETIMEDOUT;
+ skadns_end(&Dnsres);
+ temp_wtf("DNS lookup event loop took too long - mostly orderly shutdown executed"); // cut...
+ }
+ } // should not run if lookupsdone_all already (SLIP relayhost)
+
+ printprotos();
/* TODO: actually send the letter */
}
diff --git a/src/mxf-remote/mxf-remote.do b/src/mxf-remote/mxf-remote.do
@@ -0,0 +1,3 @@
+#!/bin/sh
+redo-ifchange errs.obj mxf-remote.obj typeallocs.obj
+${CCLD:-${CC:-cc}} -o "$3" "${2}.c" "${INCLUDES}" "${CFLAGS}"
diff --git a/src/mxf-remote/mxf-remote.h b/src/mxf-remote/mxf-remote.h
@@ -1,31 +1,38 @@
#ifndef MXF_REMOTE_H
#define MXF_REMOTE_H
-#include "ga_foreach.h"
+#include <ga_foreach.h>
-#include "typeallocdefs.h"
-#include "typealloc.h"
+#include <typeallocdefs.h>
+#include <typealloc.h>
// I fold, I will use TypeAlloc
-#include "controls.h"
+#include <noreturn.h>
+#include <control.h>
// Needs control.o from NMMail
-#include "netstrings.h"
+#include <netstrings.h>
// Needs netstrings.o from NMMail
-#include "auto_qmail.h"
+#include <str.h>
+// Needs str from NMMail
+
+#include <auto_qmail.h>
// Needs auto-qmail from NMMail
-#include "constmap.h"
+#include <constmap.h>
// Needs constmap from NMMail
-#include "ipme.h"
+#include <ipme.h>
// Needs IPMe from NMMail
-#include "scan.h"
+#include <scan.h>
// Needs scan from NMMail
-#include "uthash.h"
+#include <fmt.h>
+// Needs fmt from NMMail
+
+#include <uthash.h>
#undef uthash_fatal
#define uthash_fatal(msg) temp_nomem()
// Special - needs UTHash for mutable hash tables.
@@ -33,11 +40,13 @@
#error "You must use skalibs, s6-networking and s6-dns for Nightmare Remote."
#else
#include <stdlib.h>
+#include <unistd.h>
#include <signal.h>
#include <poll.h>
#include <limits.h>
#include <skalibs/tai.h>
#include <sys/types.h>
+#include <skalibs/djbunix.h>
#include <skalibs/types.h>
#include <skalibs/iopause.h>
#include <skalibs/stralloc.h>
@@ -49,7 +58,7 @@
#include <skalibs/ip46.h>
#include <s6-dns/s6dns.h>
#include <s6-dns/skadns.h>
-
+#endif
#ifndef UCSPITLSC
#define UCSPITLSC "/package/net/s6-networking/command/s6-ucspitlsc"
@@ -113,29 +122,57 @@
#define QMTP_PORT 209
#define QMTPS_PORT 6209 // Not extinct at all; QMTP has no STARTTLS support and will never grow it.
*/
+#define BREAK -1 // call this from an event callback to break the loop
#define FALSE 0
#define TRUE 1
#define MAXSRVLEN 64
-typedef struct {
- char srvservice[MAXSRVLEN]; // by happy coincidence we can also use this as the prefix for control/<service>routes filenames
- uint16_t defport; // default port
- signed char slice; // plain mx = 0
- unsigned int tls:1; // TLSC
- unsigned int starttls:1; // UCSPITLSC
- char app[PATH_MAX];
- struct constmap maproutes; // control/<service>routes
-} protocol_t;
+/* stages of the general automaton
+ */
+//#define
struct descriptor_t_s;
typedef struct descriptor_t_s descriptor_t;
+struct protocol_t_s;
+typedef struct protocol_t_s protocol_t;
+
struct process_t_s;
typedef struct process_t_s process_t;
struct dnsq_t_s;
typedef struct dnsq_t_s dnsq_t;
+typedef struct {
+ ip46full ip; // ip46full from skalibs
+} ipmx_t;
+
+TypeAlloc_typedef(ipmxAlloc,ipmx_t,ipmx,len,a)
+
+#define MXRESULT_SRV_ZERO {0, 0, 0, FALSE, FALSE, FALSE, FALSE, STRALLOC_ZERO, TA_ZERO}
+#define MXRESULT_MX_ZERO {0, 0, 0, FALSE, FALSE, TRUE, FALSE, STRALLOC_ZERO, TA_ZERO}
+#define MXRESULT_SLIP_ZERO {0, 0, 0, TRUE, TRUE, FALSE, FALSE, STRALLOC_ZERO, TA_ZERO}
+
+typedef struct {
+ uint16_t port;
+ uint16_t prio; // 0 for A/AAAA and SLIP; as published for MX and SRV
+ uint16_t weight; // 0 for MX, A/AAAA, and SLIP; as published for SRV
+ unsigned int lookupdone:1; // dns - 1 if SLIP - means ip lookups were done
+ unsigned int hasresults:2; // dns - >1 if SLIP - means has IPs
+ unsigned int ismx:1; // dns - 0 (SRV or SLIP) is better
+ unsigned int isme:1; // if, by some tragedy, after prefsorting, this comes to be the first item in a protocol, balk.
+ stralloc name; // may be a hostname or a SLIP; will not contain ports or priorities.
+ ipmxAlloc ipmx; // this'll contain the IPs of this !!single hostname!!
+} mxresult_t; // stores processed results; SRV hostnames and ports, MX hostnames and ports, IPs (A/AAAA legacy, string literal IPs)
+
+//TypeAlloc_typedef(dnslAlloc,dnsl_t,dnsl,len,a)
+TypeAlloc_typedef(mxrAlloc,mxresult_t,mxr,len,a)
+TypeAlloc_typedef(protoAlloc,protocol_t,pt,len,a)
+TypeAlloc_typedef(saAlloc,stralloc,sa,len,a)
+TypeAlloc_typedef(pfdAlloc,struct pollfd,pfd,len,a)
+
+#include <typeallocs.h>
+
struct descriptor_t_s {
struct pollfd fd; // stored directly in this struct; used solely as an index for the uthash
void* opaque; // a WEAK pointer to an opaque; may be anything or NULL
@@ -150,24 +187,39 @@ struct process_t_s {
UT_hash_handle hh;
}; // callback when a protegé reports ("child dies")
+struct protocol_t_s {
+ char srvservice[MAXSRVLEN]; // by happy coincidence we can also use this as the prefix for control/<service>routes filenames
+ uint16_t defport; // default port
+ signed char slice; // plain mx = 0
+ unsigned int tls:1; // TLSC
+ unsigned int starttls:1; // UCSPITLSC
+ unsigned int lookupdone:1; // dns - means lookups were done
+ unsigned int hasresults:1; // dns - means has names
+ stralloc app;
+ struct constmap maproutes; // control/<service>routes
+ mxrAlloc mxresults; // results of MX DNS lookups
+};
+
struct dnsq_t_s {
uint16_t dnsq;
void* opaque; // a WEAK pointer to an opaque
- int (*qcb) (skadns_t *, dnsq_t *, void *);
+ void* opaque2; // a WEAK pointer to an opaque
+ int (*qcb) (skadns_t *, dnsq_t *, void *, void *);
UT_hash_handle hh;
-};
-
-typedef struct {
- uint16_t port;
- uint16_t weight; // 0 for MX, A/AAAA, and SLIP; as published for SRV
- char name[256]; // may be a hostname or an IP; will not contain ports or priorities.
- //unsigned int isv6:1;
-} mxresult_t; // stores processed results; SRV hostnames and ports, MX hostnames and ports, IPs (A/AAAA legacy, string literal IPs)
+}; /* this is our ephemeral dns query structure
+ * opaque should probably be a dnsl_t
+ */
+/*
+struct dnsl_t_s {
+ protocol_t *proto; // ptr to the protocol this dnsl relates to
+ char success; // 0 if not, 1 if so
+ mxrAlloc mxr; // mxr->len ptrs to mxresult_t structures
+}; */
-typedef struct {
+/* typedef struct {
uint32_t prio; // lower is to try sooner
genalloc mxresults; // &(mxresults.s) is of type mxresult_t
-} mxprio_t;
+} mxprio_t; */
//extern protocol_t protocols; // 16 slices, plus the 4 SRV pseudo slices plus unknown more
//extern buffer errbuf, errbufsmall;
diff --git a/src/mxf-remote/typealloc.h b/src/mxf-remote/typealloc.h
@@ -2,6 +2,8 @@
#define TypeAlloc_H
#define TypeAlloc_typedef(ta,type,field,len,a) \
- typedef struct ta { type *field; unsigned int len; unsigned int a; } ta;
+ typedef struct ta { type *field; size_t len; size_t a; } ta;
+
+#define TA_ZERO {NULL, 0, 0}
#endif
diff --git a/src/mxf-remote/typeallocdefs.h b/src/mxf-remote/typeallocdefs.h
@@ -10,46 +10,24 @@
// unclear
#define TypeAlloc_readyplus(ta,type,field,len,a,base,ta_rplus) \
-static int ta_rplus ## _internal (ta *x, unsigned int n, unsigned int pluslen) \
-{ \
- unsigned int nlen; \
- errno = error_nomem; \
- if (x->field) { \
- unsigned int nnum; \
- type *nfield; \
- if (__builtin_add_overflow(n, pluslen, &n)) \
- return 0; \
- if (n <= x->a) \
- return 1; \
- if (__builtin_add_overflow(n, (n >> 3) + base, &nnum)) \
- return 0; \
- if (__builtin_mul_overflow(nnum, sizeof(type), &nlen)) \
- return 0; \
- nfield = realloc(x->field, nlen); \
- if (nfield == NULL) \
- return 0; \
- x->field = nfield; \
- x->a = nnum; \
- return 1; } \
- x->len = 0; \
- if (__builtin_mul_overflow(n, sizeof(type), &nlen)) \
- return 0; \
- x->field = (type *) malloc(nlen); \
- if (!x->field) \
- return 0; \
- x->a = n; \
- return 1; } \
-int ta_rplus(ta *x, unsigned int n) \
-{ return ta_rplus ## _internal (x, n, x->len); }
+int ta_rplus(ta *x, size_t n);
/* this needs a TypeAlloc_readyplus call before as it reuses the internal helper
* function. */
#define TypeAlloc_ready(ta,type,field,len,a,base,ta_ready) \
-int ta_ready(ta *x, unsigned int n) \
-{ return ta_ready ## plus_internal (x, n, 0); }
+int ta_ready(ta *x, size_t n);
#define TypeAlloc_append(ta,type,field,len,a,base,ta_rplus,ta_append) \
-int ta_append(ta *x, type *i) \
-{ if (!ta_rplus(x,1)) return 0; x->field[x->len++] = *i; return 1; }
+int ta_append(ta *x, type *i);
+
+#define TypeAlloc_appendentries(ta,type,field,len,a,base,ta_rplus,ta_cat) \
+int ta_cat(ta *x, type *i, size_t n);
+
+// example usage -> ta_copy(saa, saa);
+#define TypeAlloc_copy(ta,type,field,len,a,base,ta_ready,ta_copy) \
+int ta_copy(ta *x, ta *y);
+
+#define TypeAlloc_free(ta,type,field,len,a,base,ta_free) \
+int ta_free(ta *x);
#endif
diff --git a/src/mxf-remote/typealloclib.h b/src/mxf-remote/typealloclib.h
@@ -0,0 +1,69 @@
+#ifndef TypeAlloc_DEFS_H
+#define TypeAlloc_DEFS_H
+/* note - this is to make sure this overrides defs if both are included. */
+/* de https://github.com/notqmail/notqmail */
+
+//#include "alloc.h"
+#include "error.h"
+// needed from qmail
+
+#include "oflops.h"
+// unclear
+
+#define TypeAlloc_readyplus(ta,type,field,len,a,base,ta_rplus) \
+static int ta_rplus ## _internal (ta *x, size_t n, size_t pluslen) \
+{ \
+ size_t nlen; \
+ errno = error_nomem; \
+ if (x->field) { \
+ size_t nnum; \
+ type *nfield; \
+ if (__builtin_add_overflow(n, pluslen, &n)) \
+ return 0; \
+ if (n <= x->a) \
+ return 1; \
+ if (__builtin_add_overflow(n, (n >> 3) + base, &nnum)) \
+ return 0; \
+ if (__builtin_mul_overflow(nnum, sizeof(type), &nlen)) \
+ return 0; \
+ nfield = realloc(x->field, nlen); \
+ if (nfield == NULL) \
+ return 0; \
+ x->field = nfield; \
+ x->a = nnum; \
+ return 1; } \
+ x->len = 0; \
+ if (__builtin_mul_overflow(n, sizeof(type), &nlen)) \
+ return 0; \
+ x->field = (type *) malloc(nlen); \
+ if (!x->field) \
+ return 0; \
+ x->a = n; \
+ return 1; } \
+int ta_rplus(ta *x, size_t n) \
+{ return ta_rplus ## _internal (x, n, x->len); }
+
+/* this needs a TypeAlloc_readyplus call before as it reuses the internal helper
+ * function. */
+#define TypeAlloc_ready(ta,type,field,len,a,base,ta_ready) \
+int ta_ready(ta *x, size_t n) \
+{ return ta_ready ## plus_internal (x, n, 0); }
+
+#define TypeAlloc_append(ta,type,field,len,a,base,ta_rplus,ta_append) \
+int ta_append(ta *x, type *i) \
+{ if (!ta_rplus(x,1)) return 0; x->field[x->len++] = *i; return 1; }
+
+#define TypeAlloc_appendentries(ta,type,field,len,a,base,ta_rplus,ta_cat) \
+int ta_cat(ta *x, type *i, size_t n) \
+{ if (!ta_rplus(x,n)) return 0; for (int j = 0; j < n; ++j) x->field[x->len++] = *(i + j); return 1; }
+
+// example usage -> ta_copy(saa, saa);
+#define TypeAlloc_copy(ta,type,field,len,a,base,ta_ready,ta_copy) \
+int ta_copy(ta *x, ta *y) \
+{ if (!ta_ready(x,y->len)) return 0; x->len = 0; for (int j = 0; j < y->len; ++j) x->field[x->len++] = *(y->field + j); return 1; }
+
+#define TypeAlloc_free(ta,type,field,len,a,base,ta_free) \
+int ta_free(ta *x) \
+{ free(x->field); x->field = NULL; x->a = x->len = 0; return 1; }
+
+#endif
diff --git a/src/mxf-remote/typeallocs.c b/src/mxf-remote/typeallocs.c
@@ -0,0 +1,26 @@
+#ifndef TYPEALLOCS_H
+#define TYPEALLOCS_H
+// ugly hack required to avoid redefining
+#include <typealloc.h>
+#include <typealloclib.h>
+//#include <typeallocs.h>
+#include <mxf-remote.h>
+
+TypeAlloc_readyplus(protoAlloc,protocol_t,pt,len,a,10,protoalloc_readyplus)
+TypeAlloc_append(protoAlloc,protocol_t,pt,len,a,10,protoalloc_readyplus,protoalloc_catp)
+
+TypeAlloc_readyplus(saAlloc,stralloc,sa,len,a,10,saalloc_readyplus)
+TypeAlloc_append(saAlloc,stralloc,sa,len,a,10,saalloc_readyplus,saalloc_catsa)
+
+TypeAlloc_readyplus(pfdAlloc,struct pollfd,pfd,len,a,10,pfdalloc_readyplus)
+TypeAlloc_append(pfdAlloc,struct pollfd,pfd,len,a,10,pfdalloc_readyplus,pfdalloc_catpfd)
+
+//TypeAlloc_readyplus(dnslAlloc,dnsl_t,dnsl,len,a,10,dnslalloc_readyplus)
+//TypeAlloc_append(dnslAlloc,dnsl_t,dnsl,len,a,10,dnslalloc_readyplus,dnslalloc_catdnsl)
+
+TypeAlloc_readyplus(ipmxAlloc,ipmx_t,ipmx,len,a,10,ipmxalloc_readyplus)
+TypeAlloc_append(ipmxAlloc,ipmx_t,ipmx,len,a,10,ipmxalloc_readyplus,ipmxalloc_catip)
+
+TypeAlloc_readyplus(mxrAlloc,mxresult_t,mxr,len,a,10,mxralloc_readyplus)
+TypeAlloc_append(mxrAlloc,mxresult_t,mxr,len,a,10,mxralloc_readyplus,mxralloc_catmxr)
+#endif
diff --git a/src/mxf-remote/typeallocs.h b/src/mxf-remote/typeallocs.h
@@ -0,0 +1,24 @@
+#ifndef TYPEALLOCS_H
+#define TYPEALLOCS_H
+#include <typealloc.h>
+#include <typeallocdefs.h>
+#include <mxf-remote.h>
+
+TypeAlloc_readyplus(protoAlloc,protocol_t,pt,len,a,10,protoalloc_readyplus)
+TypeAlloc_append(protoAlloc,protocol_t,pt,len,a,10,protoalloc_readyplus,protoalloc_catp)
+
+TypeAlloc_readyplus(saAlloc,stralloc,sa,len,a,10,saalloc_readyplus)
+TypeAlloc_append(saAlloc,stralloc,sa,len,a,10,saalloc_readyplus,saalloc_catsa)
+
+TypeAlloc_readyplus(pfdAlloc,struct pollfd,pfd,len,a,10,pfdalloc_readyplus)
+TypeAlloc_append(pfdAlloc,struct pollfd,pfd,len,a,10,pfdalloc_readyplus,pfdalloc_catpfd)
+
+//TypeAlloc_readyplus(dnslAlloc,dnsl_t,dnsl,len,a,10,dnslalloc_readyplus)
+//TypeAlloc_append(dnslAlloc,dnsl_t,dnsl,len,a,10,dnslalloc_readyplus,dnslalloc_catdnsl)
+
+TypeAlloc_readyplus(ipmxAlloc,ipmx_t,ipmx,len,a,10,ipmxalloc_readyplus)
+TypeAlloc_append(ipmxAlloc,ipmx_t,ipmx,len,a,10,ipmxalloc_readyplus,ipmxalloc_catip)
+
+TypeAlloc_readyplus(mxrAlloc,mxresult_t,mxr,len,a,10,mxralloc_readyplus)
+TypeAlloc_append(mxrAlloc,mxresult_t,mxr,len,a,10,mxralloc_readyplus,mxralloc_catmxr)
+#endif