mxf-remote.c (41863B)
1 /* src/mxf-remote/mxf-remote.c 2 * requires skalibs, s6-networking and s6-dns; if not, you must 3 * use regular qmail-remote with the attendant loss of 4 * functionality with qmtp, tls and ipv6. 5 */ 6 #ifndef mxf_remote_c 7 #define mxf_remote_c 8 #include "mxf-remote.h" 9 #include "errs.h" 10 //#include <s6-dns/skadns.h> 11 12 tain Deadline, Stamp, Limit; 13 //protocol_t protocols[SLICE_LAST]; 14 //TypeAlloc_typedef(protoAlloc,protocol_t,pt,len,a) 15 //TypeAlloc_readyplus(protoAlloc,protocol_t,pt,len,a,10,protoalloc_readyplus) 16 //TypeAlloc_append(protoAlloc,protocol_t,pt,len,a,10,protoalloc_readyplus,protoalloc_catp) 17 protoAlloc Protocols = TA_ZERO; // genalloc_*(protocol_t 18 //genalloc maproutes = GENALLOC_ZERO; // genalloc_*(constmap 19 char Errbuf[512]; 20 buffer buffer_2_ = BUFFER_INIT(&buffer_write, 2, Errbuf, 512); 21 //char Errbufsmall[256]; // no use yet 22 skadns_t Dnsres = SKADNS_ZERO; 23 //char namechosen[513]; // That's more bytes than we will ever need. 24 //char progname[61] = "mxf-remote"; 25 //stralloc sa = STRALLOC_ZERO; // ? 26 int Timeoutconnect = 60; int Mtpfd; 27 stralloc Host = STRALLOC_ZERO, Sender = STRALLOC_ZERO, Protocolsraw = STRALLOC_ZERO; 28 stralloc Ucspitlsclient = STRALLOC_ZERO, Tlsclient = STRALLOC_ZERO; 29 //genalloc recips = GENALLOC_ZERO; // will be filled with strallocs 30 //struct constmap maproutes[SLICE_LAST]; 31 char PROTOMAPTEXT[] = "qmtps 6209 3 Y N mxf-remote-qmtpc\n" \ 32 "qmtp 209 1 N N mxf-remote-qmtpc\n" \ 33 "smtp 25 0 N Y mxf-remote-smtpc\n"; 34 protocol_t *Slicemap[MAXSLICES]; 35 //genalloc Descriptors; // of type descriptor_t 36 //TypeAlloc_typedef(saAlloc,stralloc,sa,len,a) 37 //TypeAlloc_readyplus(saAlloc,stralloc,sa,len,a,10,saalloc_readyplus) 38 //TypeAlloc_append(saAlloc,stralloc,sa,len,a,10,saalloc_readyplus,saalloc_catsa) 39 //TypeAlloc_typedef(pfdAlloc,struct pollfd,pfd,len,a) 40 //TypeAlloc_readyplus(pfdAlloc,struct pollfd,pfd,len,a,10,pfdalloc_readyplus) 41 //TypeAlloc_append(pfdAlloc,struct pollfd,pfd,len,a,10,pfdalloc_readyplus,pfdalloc_catpfd) 42 saAlloc Rcptlist = TA_ZERO; 43 int Sigfd; 44 signed int ReadyToSend = 0; /* 45 * Set this to -1 when the remote domain doesn't accept mail, or 1 when 46 * we have a complete (unsorted) picture of how they do. 47 */ 48 49 descriptor_t *Descriptortab = NULL; // NOTES-mxfr - A word on memory management - strong pointers 50 process_t *Protegetab = NULL; // NOTES-mxfr - A word on memory management 51 dnsq_t *Dnsqtab = NULL; // NOTES-mxfs - A word on memory management 52 53 void getroutes (protocol_t *protocol); 54 55 // in order: pollfd (single entry), opaque (may be NULL), fdcb(descriptor_t*, void*) 56 int descriptor_add (struct pollfd fd, void* opaque, 57 int (*fdcb)(descriptor_t*, short, void*)) 58 { 59 descriptor_t *descriptor = NULL; 60 61 HASH_FIND_INT(Descriptortab, &(fd.fd), descriptor); 62 if (descriptor != NULL) return (errno = ENOENT, FALSE); 63 // Otherwise... 64 descriptor = malloc(sizeof(descriptor_t)); // strong pointer; if we cannot add this to the hash, we must free it 65 descriptor->fd = fd; 66 descriptor->opaque = opaque; 67 descriptor->fdcb = fdcb; 68 HASH_ADD_INT(Descriptortab, fd.fd, descriptor); 69 return 1; // if we are returning at all, we have succeeded. 70 } 71 72 // in order: descriptortab, pollfd (single entry) 73 // returns true on success, false on nonexistent 74 int descriptor_del (struct pollfd fd) 75 { 76 descriptor_t *descriptor = NULL; 77 78 HASH_FIND_INT(Descriptortab, &(fd.fd), descriptor); 79 if (descriptor == NULL) return FALSE; 80 // Otherwise... 81 HASH_DEL(Descriptortab, descriptor); 82 free(descriptor); 83 return TRUE; // if we are returning at all, we have succeeded. 84 } 85 86 // in order: processtab, process ID, opaque to be passed to the report callback, report callback 87 int protege_add (pid_t pid, void* opaque, 88 int (*pdiecb)(process_t*, int, void*)) 89 { 90 process_t *protege = NULL; 91 92 HASH_FIND(hh, Protegetab, &pid, sizeof(pid_t), protege); 93 if (protege != NULL) temp_hasherr(); 94 // Otherwise... 95 protege = malloc(sizeof(descriptor_t)); // strong pointer; if we cannot add this to the hash, we must free it 96 protege->pid = pid; 97 protege->opaque = opaque; 98 protege->pdiecb = pdiecb; 99 HASH_ADD(hh, Protegetab, pid, sizeof(pid_t), protege); 100 return 1; // if we are returning at all, we have succeeded. 101 } 102 // in order: descriptortab, pollfd (single entry) 103 // returns true on success, false on nonexistent 104 int protege_del (pid_t pid) 105 { 106 process_t *protege = NULL; 107 108 HASH_FIND(hh, Protegetab, &(pid), sizeof(pid_t), protege); 109 if (protege == NULL) return (errno = ENOENT, FALSE); 110 HASH_DEL(Protegetab, protege); 111 free(protege); 112 return TRUE; 113 } 114 115 // in order: dnsqtab, process ID, opaque to be passed to the report callback, report callback 116 int dnsq_add (uint16_t dnsqid, void* opaque, void* opaque2, 117 int (*qcb)(skadns_t*, dnsq_t*, void*, void*)) 118 { 119 dnsq_t *dnsq = NULL; 120 121 HASH_FIND(hh, Dnsqtab, &dnsqid, sizeof(uint16_t), dnsq); 122 if (dnsq != NULL) temp_hasherr(); 123 // Otherwise... 124 dnsq = malloc(sizeof(dnsq_t)); // strong pointer; if we cannot add this to the hash, we must free it 125 dnsq->dnsq = dnsqid; 126 dnsq->opaque = opaque; 127 dnsq->opaque2 = opaque2; 128 dnsq->qcb = qcb; 129 HASH_ADD(hh, Dnsqtab, dnsq, sizeof(uint16_t), dnsq); 130 return TRUE; // if we are returning at all, we have succeeded. 131 } 132 // in order: dnsqtab, pollfd (single entry) 133 // returns true on success, false on nonexistent 134 int dnsq_del (uint16_t dnsqid) 135 { 136 dnsq_t *dnsq = NULL; 137 138 HASH_FIND(hh, Dnsqtab, &(dnsqid), sizeof(uint16_t), dnsq); 139 if (dnsq == NULL) return (errno = ENOENT, FALSE); 140 HASH_DEL(Dnsqtab, dnsq); 141 free(dnsq); 142 return TRUE; 143 } 144 145 int run_fds (tain *deadline, tain *stamp) 146 { 147 pfdAlloc fds = TA_ZERO; // pollfd 148 descriptor_t *des = NULL, *tmp = NULL; 149 struct pollfd *pfds = NULL; size_t pfdsiz = 0; size_t i = 0; 150 int pollret = 0; 151 HASH_ITER(hh, Descriptortab, des, tmp) { 152 if (!pfdalloc_catpfd(&fds, (des->fd))) temp_nomem(); 153 des->fd.revents = 0; 154 ++pfdsiz; 155 } 156 if (pfdsiz == 0) temp_runfds(); 157 des = NULL; tmp = NULL; 158 pfds = (struct pollfd *)(fds.pfd); 159 pollret = iopause_stamp(pfds, pfdsiz, deadline, stamp); 160 // and then we wait for iopause to do its thing 161 // and then iopause wakes us up 162 switch (pollret) { 163 case 0: 164 // we literally have nothing to do. we return. this isn't an error state. 165 return pollret; 166 break; 167 case -1: 168 // errors AGAIN, FAULT, INTR, INVAL 169 switch (errno) { 170 case EAGAIN: 171 return 0; // we will just get called again 172 break; 173 case EFAULT: 174 temp_fault(); 175 break; 176 case EINTR: 177 temp_intr(); // an uncaught signal has come our way 178 break; 179 case EINVAL: 180 temp_bug(); // invalid data 181 break; 182 } 183 default : 184 for (i = 0; i < pfdsiz; i++) { 185 HASH_FIND_INT(Descriptortab, &(pfds[i].fd), des); 186 if (des == NULL) { 187 temp_finderr(); // could not find the file descriptor in our tables - what kind of wiseguy do we have on here? 188 } 189 if (((pfds[i]).revents & POLLNVAL) != 0) { 190 // file descriptor is not known to the system; bug 191 temp_bug(); 192 } else if ((pfds[i]).revents != 0) { 193 (*(des->fdcb))(des, (pfds[i]).revents, des->opaque); 194 } 195 } 196 } 197 // done with fds now? right, we return the number of FDs we processed. 198 free((fds.pfd)); 199 return pollret; 200 } 201 202 int handledeadprocess () 203 { 204 process_t *protege = NULL; 205 pid_t pid = 0; 206 int wstat; 207 while ((pid = wait_nohang(&wstat)) > 0) { 208 HASH_FIND(hh, Protegetab, &pid, sizeof(pid_t), protege); 209 if (protege == NULL) continue; // doesn't really matter 210 (*protege->pdiecb)(protege, wstat, protege->opaque); 211 protege_del(pid); 212 } 213 return TRUE; 214 } 215 216 int checksignals (descriptor_t *descr, short revents, void* unused) 217 { 218 int sig; 219 sig = selfpipe_read(); 220 221 switch (sig) { 222 case SIGCHLD: 223 return handledeadprocess(); 224 break; 225 default : 226 return FALSE;// Advanced wiseguy shit 227 } 228 } 229 230 int protocols_init (protoAlloc *protos, char *protomaptext, size_t length) 231 { 232 size_t i = 0; 233 char field = 0; /* there are six fields, numbered zero to five 234 * their identities are: 235 * protoname, port, protoslice, cantls, musttls, executable-filename 236 */ 237 size_t lpos = 0, fpos = 0; // record the position we are at in the line 238 char comment = 0; char s[15]; //true if line is comment 239 240 for (i = 0; i < MAXSLICES; i++) { 241 Slicemap[i] = NULL; 242 } 243 if (length == 0) { 244 protomaptext = PROTOMAPTEXT; 245 length = strlen(PROTOMAPTEXT); // that string has no funny business with nulls so we can do this 246 } 247 protocol_t proto; 248 memset(&proto, 0, sizeof(protocol_t)); 249 proto.slice = -1; 250 251 for (i = lpos = fpos = 0; i < length; ++i) { 252 buffer_put(buffer_2, &(protomaptext[i]), 1); 253 switch (protomaptext[i]) { 254 /* case '\r': // activate this when we have our own control_readfile; until then it's no use 255 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. 256 case '\n': // still needed by the default protomap 257 case 0: 258 switch (fpos) { 259 case 0: continue; // it was an empty line 260 default : break; 261 } 262 fpos = -1; 263 lpos = 0; 264 field = 0; 265 comment = 0; 266 getroutes(&proto); 267 if (!stralloc_0(&(proto.app))) temp_nomem(); 268 buffer_puts(buffer_2, proto.srvservice[0] != 0 ? "srvservice[0] is not null\n" :"srvservice[0] is null\n"); 269 if (proto.srvservice[0] != 0) if (!protoalloc_catp(protos, proto)) temp_nomem(); 270 if (proto.slice > -1 && proto.slice < MAXSLICES) Slicemap[proto.slice] = protos->pt + protos->len-1; 271 buffer_puts(buffer_2, "reset\n"); 272 memset(&proto, 0, sizeof(protocol_t)); 273 proto.slice = -1; 274 break; 275 case ' ': 276 switch (comment) { 277 case 1: continue; 278 default : break; 279 } 280 switch (field) { 281 case 5: 282 if (!stralloc_catb(&(proto.app), &(protomaptext[i]), 1)) temp_nomem(); 283 break; 284 case 0: 285 switch (fpos) { 286 case 0: 287 ++comment; 288 break; 289 default : 290 proto.srvservice[fpos] = 0; // nullcap the srvservice 291 fpos = 0; 292 ++field; 293 } 294 break; 295 case 1: 296 case 2: 297 case 3: 298 case 4: 299 fpos = -1; 300 ++field; 301 break; 302 } 303 break; 304 case '\\': 305 switch (comment) { 306 case 1: continue; 307 default : break; 308 } 309 // The synopsis of \ is: Take next character verbatim into current field, no matter what it is. 310 switch (field) { 311 case 5: 312 if (fpos > PATH_MAX) temp_control(); // malformed 313 if (i >= length) temp_control(); // malformed 314 if (protomaptext[i] == 0) temp_control(); // malformed 315 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. 316 break; 317 case 0: 318 proto.srvservice[fpos] = protomaptext[++i]; 319 case 1: // It is ignorable in fields 2-5. 320 case 2: 321 case 3: 322 case 4: 323 if (i >= length) temp_control(); // malformed 324 if (protomaptext[i] == 0) temp_control(); // malformed 325 ++lpos; 326 break; 327 } 328 break; 329 default : 330 switch (comment) { 331 case 1: continue; 332 default : break; 333 } 334 switch (field) { 335 case 0: // protoname 336 if (fpos < MAXSRVLEN) proto.srvservice[fpos] = protomaptext[i]; 337 break; 338 case 5: // protoprog (app) 339 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. 340 break; 341 case 1: // defport 342 if (protomaptext[i] < '0') temp_control(); 343 if (protomaptext[i] > '9') temp_control(); 344 proto.defport = (proto.defport * 10) + (protomaptext[i] - '0'); 345 break; 346 case 2: // MXPS slice, DECIMAL 347 buffer_puts(buffer_2, " field:"); 348 s[fmt_ulong(s, field)] = 0; 349 buffer_puts(buffer_2, s); 350 if (fpos == 0 && !(protomaptext[i] == '-')) proto.slice = 0; // reset slice to 0 as it is -1 351 if (proto.slice != -1) { // a slice of -1 means we are not using a slice and this is a SRV only protocol 352 if (!(protomaptext[i] < '0' || protomaptext[i] > '9')) { 353 proto.slice = (proto.slice * 10) + (protomaptext[i] - '0'); 354 s[fmt_ulong(s, proto.slice)] = 0; 355 buffer_puts(buffer_2, " slice:"); 356 buffer_puts(buffer_2, s); 357 buffer_puts(buffer_2, " "); 358 } else { 359 info_dbgs("detected non-numeric character in slice number "); 360 out("it was "); 361 buffer_put(buffer_2, &protomaptext[i], 1); 362 info_dbgs(""); 363 temp_control(); 364 } 365 } 366 break; 367 case 3: // is TLS 368 switch (fpos) { 369 case 0: // we only care about char 1 370 if ( 371 protomaptext[i] == '0' 372 || protomaptext[i] == 'n' 373 || protomaptext[i] == 'N' 374 || protomaptext[i] == 'f' 375 || protomaptext[i] == 'F' 376 ) proto.tls = 0; 377 else if ( 378 protomaptext[i] == '1' 379 || protomaptext[i] == 'y' 380 || protomaptext[i] == 'Y' 381 || protomaptext[i] == 't' 382 || protomaptext[i] == 'T' 383 ) proto.tls = 1; 384 else temp_control(); 385 // in default of a valid choice, we have no choice but to blow up. 386 default : break; 387 } 388 break; 389 case 4: // can TLS (irrelevant if is TLS) 390 switch (fpos + proto.tls) { 391 case 0: // we only care about char 1 392 if ( 393 protomaptext[i] == '0' 394 || protomaptext[i] == 'n' 395 || protomaptext[i] == 'N' 396 || protomaptext[i] == 'f' 397 || protomaptext[i] == 'F' 398 ) proto.tls = 0; 399 else if ( 400 protomaptext[i] == '1' 401 || protomaptext[i] == 'y' 402 || protomaptext[i] == 'Y' 403 || protomaptext[i] == 't' 404 || protomaptext[i] == 'T' 405 ) proto.tls = 1; 406 else temp_control(); 407 // in default of a valid choice, we have no choice but to blow up. 408 default : break; 409 } 410 break; 411 } 412 } 413 ++lpos; ++fpos; // if comment notreached; lpos and fpos don't run if we are in a comment. 414 // lpos and fpos only increase 1 for every 2 characters if every first character is a backstroke 415 } 416 // 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. 417 if (proto.app.len > 1) { 418 getroutes(&proto); 419 if (!protoalloc_catp(protos, proto)) return 0; 420 } 421 return 1; 422 } 423 424 425 // imported from qmail-remote 426 // inputs: controlfiles from the filesystem 427 // outputs: none 428 // SE: reads control files 429 430 void getcontrols() 431 { 432 if (control_init() == -1) temp_control(); 433 //if (control_readint(&timeout,"control/timeoutremote") == -1) temp_control(); 434 // The client application is responsible for this. 435 if (control_readint(&Timeoutconnect,"control/timeoutconnect") == -1) 436 temp_control(); 437 // if (control_rldef(&helohost,"control/helohost",1,NULL) != 1) 438 // temp_control(); 439 if (control_rldef(&Ucspitlsclient,"control/ucspitlsclient",0,UCSPITLSC) != 1) 440 temp_control(); 441 if (control_rldef(&Ucspitlsclient,"control/tlsclient",0,TLSC) != 1) 442 temp_control(); 443 switch(control_readfile(&Protocolsraw,"control/protocols",0)) { 444 case -1: 445 temp_control(); 446 case 0: 447 if (!protocols_init(&(Protocols),"",0)) temp_nomem(); break; 448 case 1: 449 if (!protocols_init(&(Protocols),Protocolsraw.s,Protocolsraw.len)) temp_nomem(); break; 450 } 451 // It strikes me that Protocolsraw is used nowhere else in the file. 452 } 453 454 void getroutes (protocol_t *protocol) 455 { 456 stralloc ctrl = STRALLOC_ZERO, routes = STRALLOC_ZERO; 457 stralloc_copys(&ctrl, "control/"); 458 stralloc_cats(&ctrl, protocol->srvservice); 459 stralloc_cats(&ctrl, "routes"); 460 stralloc_0(&ctrl); 461 switch(control_readfile(&routes,ctrl.s,0)) { 462 case -1: temp_control(); 463 case 0: 464 if (!constmap_init(&(protocol->maproutes),"",0,1)) temp_nomem(); break; 465 case 1: 466 if (!constmap_init(&(protocol->maproutes),routes.s,routes.len,1)) temp_nomem(); break; 467 } 468 stralloc_free(&ctrl); 469 } 470 471 int checkdns (descriptor_t *descr, short revents, void* dnsresv) 472 { 473 skadns_t *dnsres = (skadns_t *)dnsresv; 474 int upd; size_t dnsqlen = 0, i = 0; 475 uint16_t *dnsqs = NULL; dnsq_t *dnsq = NULL; 476 upd = skadns_update(dnsres); 477 switch (upd) { 478 case -1: 479 temp_dnsupd(); 480 return FALSE; // NOTREACHED we should not be here but... 481 break; 482 default : // there either has, or has not been, a response to collect. let's do that now. 483 dnsqs = genalloc_s(uint16_t, &dnsres->list); // have to use genalloc here as that's what Ska uses in skadns 484 dnsqlen = genalloc_len(uint16_t, &dnsres->list); 485 for (i = 0; i < dnsqlen; ++i) { 486 // we must now call the callback and delete the query from the list 487 HASH_FIND(hh, Dnsqtab, (dnsqs + i), sizeof(uint16_t), dnsq); 488 (*dnsq->qcb)(dnsres, dnsq, (dnsq->opaque), (dnsq->opaque2)); // not exactly sure the use of passing the full query if we'll just delet it 489 skadns_release(dnsres, dnsqs[i]); 490 dnsq_del(dnsqs[i]); 491 dnsq = NULL; 492 } 493 } 494 return TRUE; 495 } 496 497 void startdns (skadns_t *dnsres) { 498 if (!skadns_startf(dnsres, &Deadline, &Stamp)) { 499 buffer_puts(buffer_2, "ZDNS resolution startup timeout\n"); 500 buffer_flush(buffer_2); 501 exit(111); 502 } 503 } 504 505 int ipisme (const ipmx_t *ip) { 506 // wrapper around ipme and ip6me 507 const ip46full *ix = &(ip->ip); 508 struct ip_address i4; 509 struct ip6_address i6; 510 if (ix->is6) { 511 memcpy(&(i6.d), &(ix->ip), 16); 512 return ip6me_is(i6); 513 } else { 514 memcpy(&(i4.d), &(ix->ip), 4); 515 return ipme_is(i4); 516 } 517 } 518 519 void stopdns (skadns_t *dnsres) { 520 skadns_end(dnsres); 521 } 522 523 /* les noms de ces procs sont misleading. 524 * They should not be thought of as "we definitely have our response" 525 * but as "we MAY have our response." 526 */ 527 int dns_havea (skadns_t *dnsres, dnsq_t *dnsq, void* mxresultp, void* protop) 528 { 529 protocol_t *proto = (protocol_t *)protop; 530 mxresult_t *mxresult = (mxresult_t *)mxresultp; 531 //mxrAlloc *mxres = &(proto->mxresults); 532 //ipmxAlloc *ipmxres = &(mxres->ipmx); 533 ipmx_t ipmx = {IP46FULL_ZERO}; 534 ipmx.ip.is6 = 0; 535 stralloc rrs = STRALLOC_ZERO; 536 char const *dnsresponse; int dnsresplen, i = 0; 537 s6dns_message_header_t dnsmh; 538 539 if ((dnsresponse = skadns_packet(dnsres, dnsq->dnsq)) == NULL) { 540 proto->lookupdone = 1; 541 info_wtfs("skadns_packet in dns_havea"); 542 return FALSE; 543 } 544 if ((dnsresplen = skadns_packetlen(dnsres, dnsq->dnsq)) == -1) temp_wtf("skadns_packetlen in dns_havea"); // this should succeed if the above didn't fail 545 if (dnsresplen < 12) { errno = EINVAL; temp_wtf("skadns_packetlen gave dns_havea less than even a header"); } 546 // s6dns_message_header_unpack(dnsresponse, dnsmh); 547 switch (s6dns_message_parse(&dnsmh, dnsresponse, dnsresplen, &s6dns_message_parse_answer_a, &rrs)) { 548 case -1: 549 temp_wtf("s6dns_message_parse in dns_havea - local error"); 550 break; 551 case 0: 552 info_wtfs("s6dns_message_parse in dns_havea - rcode - maybe should continue"); 553 mxresult->lookupdone = 1; 554 mxresult->hasresults = 0; 555 proto->lookupdone = 1; 556 break; 557 case 1: 558 #ifdef REMOTEDEBUG 559 info_dbgs("s6dns_message_parse in dns_havea - success no answer"); 560 #endif // REMOTEDEBUG 561 mxresult->lookupdone = 1; 562 mxresult->hasresults = 0; 563 proto->lookupdone = 1; 564 break; 565 case 2: 566 #ifdef REMOTEDEBUG 567 info_dbgs("s6dns_message_parse in dns_havea - success answer"); 568 #endif // REMOTEDEBUG 569 mxresult->lookupdone = 1; 570 mxresult->hasresults = 1; 571 proto->lookupdone = 1; 572 proto->hasresults = 1; 573 for (i = 0; i < rrs.len/4; ++i) { 574 memcpy(&(ipmx.ip.ip), (rrs.s + (i * 4)), 4); 575 if (!ipmxalloc_catip(&(mxresult->ipmx), ipmx)) temp_nomem(); 576 if (ipisme(&ipmx)) mxresult->isme = 1; 577 memset(&ipmx, 0, sizeof(ipmx_t)); ipmx.ip.is6 = 0; 578 } 579 break; 580 } 581 return TRUE; 582 } 583 int dns_haveaaaa (skadns_t *dnsres, dnsq_t *dnsq, void* mxresultp, void* protop) 584 { 585 protocol_t *proto = (protocol_t *)protop; 586 mxresult_t *mxresult = (mxresult_t *)mxresultp; 587 //mxrAlloc *mxres = &(proto->mxresults); 588 //ipmxAlloc *ipmxres = &(mxres->ipmx); 589 ipmx_t ipmx = {IP46FULL_ZERO}; 590 ipmx.ip.is6 = 1; 591 stralloc rrs = STRALLOC_ZERO; 592 char const *dnsresponse; int dnsresplen, i = 0; 593 s6dns_message_header_t dnsmh; 594 595 if ((dnsresponse = skadns_packet(dnsres, dnsq->dnsq)) == NULL) { 596 info_wtfs("skadns_packet in dns_haveaaaa"); 597 proto->lookupdone = 1; 598 mxresult->lookupdone = 1; 599 return FALSE; 600 } 601 if ((dnsresplen = skadns_packetlen(dnsres, dnsq->dnsq)) == -1) temp_wtf("skadns_packetlen in dns_haveaaaa"); // this should succeed if the above didn't fail 602 if (dnsresplen < 12) { errno = EINVAL; temp_wtf("skadns_packetlen gave dns_haveaaaa less than even a header"); } 603 // s6dns_message_header_unpack(dnsresponse, dnsmh); 604 switch (s6dns_message_parse(&dnsmh, dnsresponse, dnsresplen, &s6dns_message_parse_answer_aaaa, &rrs)) { 605 case -1: 606 temp_wtf("s6dns_message_parse in dns_haveaaaa - local error"); 607 break; 608 case 0: 609 info_wtfs("s6dns_message_parse in dns_haveaaaa - rcode - maybe should continue"); 610 mxresult->lookupdone = 1; 611 proto->lookupdone = 1; 612 break; 613 case 1: 614 #ifdef REMOTEDEBUG 615 info_dbgs("s6dns_message_parse in dns_haveaaaa - success no answer"); 616 #endif // REMOTEDEBUG 617 mxresult->lookupdone = 1; 618 proto->lookupdone = 1; 619 break; 620 case 2: 621 #ifdef REMOTEDEBUG 622 info_dbgs("s6dns_message_parse in dns_haveaaaa - success answer"); 623 #endif // REMOTEDEBUG 624 #ifdef SKALIBS_IPV6_ENABLED 625 mxresult->lookupdone = 1; 626 mxresult->hasresults = 1; 627 proto->lookupdone = 1; 628 proto->hasresults = 1; 629 for (i = 0; i < rrs.len/16; ++i) { 630 memcpy(&(ipmx.ip.ip), (rrs.s + (i * 16)), 16); 631 if (!ipmxalloc_catip(&(mxresult->ipmx), ipmx)) temp_nomem(); 632 if (ipisme(&ipmx)) mxresult->isme = 1; 633 memset(&ipmx, 0, sizeof(ipmx_t)); ipmx.ip.is6 = 1; 634 } 635 #endif // SKALIBS_IPV6_ENABLED 636 break; 637 } 638 return TRUE; 639 } 640 641 int dns_havesrv (skadns_t *dnsres, dnsq_t *dnsq, void* protop, void* unused) 642 { 643 protocol_t *proto = (protocol_t *)protop; 644 mxrAlloc *mxres = &(proto->mxresults); 645 mxresult_t mxr = MXRESULT_SRV_ZERO; 646 genalloc rrs = GENALLOC_ZERO; 647 tain shortdl; 648 const char *dnsresponse; char ds[256]; int dnsresplen = 0, dsl = 0, i = 0; 649 s6dns_message_header_t dnsmh; 650 s6dns_message_rr_srv_t *rr = NULL; 651 uint16_t qid4, qid6; 652 653 if ((dnsresponse = skadns_packet(dnsres, dnsq->dnsq)) == NULL) { 654 info_wtfs("skadns_packet in dns_havesrv"); 655 proto->lookupdone = 1; 656 return FALSE; 657 } 658 if ((dnsresplen = skadns_packetlen(dnsres, dnsq->dnsq)) == -1) temp_wtf("skadns_packetlen in dns_havesrv"); // this should succeed if the above didn't fail 659 if (dnsresplen < 12) { errno = EINVAL; temp_wtf("skadns_packetlen gave dns_havesrv less than even a header"); } 660 // s6dns_message_header_unpack(dnsresponse, dnsmh); 661 switch (s6dns_message_parse(&dnsmh, dnsresponse, dnsresplen, &s6dns_message_parse_answer_srv, &rrs)) { 662 case -1: 663 temp_wtf("s6dns_message_parse in dns_havesrv - local error"); 664 break; 665 case 0: 666 info_wtfs("s6dns_message_parse in dns_havesrv - maybe should continue"); 667 proto->lookupdone = 1; 668 break; 669 case 1: 670 #ifdef REMOTEDEBUG 671 info_dbgs("s6dns_message_parse in dns_havesrv - success no answer"); 672 #endif // REMOTEDEBUG 673 proto->lookupdone = 1; 674 proto->hasresults = 0; 675 break; 676 case 2: 677 #ifdef REMOTEDEBUG 678 info_dbgs("s6dns_message_parse in dns_havesrv - success answer"); 679 #endif // REMOTEDEBUG 680 proto->lookupdone = 1; 681 proto->hasresults = 1; 682 for (i = 0; i < genalloc_len(s6dns_message_rr_srv_t, &rrs); ++i) { 683 // rr = (s6dns_message_rr_srv_t *)((rrs.s) + (i * sizeof(s6dns_message_rr_srv_t))); 684 rr = genalloc_s(s6dns_message_rr_srv_t, &rrs) + i; 685 mxr.lookupdone = TRUE; 686 mxr.port = rr->port; 687 mxr.prio = rr->priority; 688 mxr.weight = rr->weight; 689 if (!(dsl = s6dns_domain_tostring(ds, 255, &(rr->target)))) temp_wtf("s6dns_domain_tostring in dns_havesrv"); 690 if (!stralloc_readyplus(&(mxr.name), dsl)) temp_nomem(); 691 if (!stralloc_copyb(&(mxr.name), ds, dsl)) temp_nomem(); 692 if (!stralloc_0(&(mxr.name))) temp_nomem(); 693 if (!tain_addsec(&Limit, &Stamp, Timeoutconnect)) temp_wtf("tain_addsec in dns_havesrv (Doctor?)"); 694 if (!tain_addsec(&shortdl, &Stamp, Timeoutconnect)) temp_wtf("tain_addsec in dns_havesrv (Doctor?)"); 695 if (!mxralloc_catmxr(mxres, mxr)) temp_nomem(); 696 if (mxr.name.len > 1) { // No point if it's just a dot 697 if (!skadns_send(&Dnsres, &qid4, &(rr->target), S6DNS_T_A, &Limit, &shortdl, &Stamp)) temp_wtf("skadns_send in dns_havesrv"); 698 if (!dnsq_add(qid4, &(mxres->mxr[(mxres->len)-1]), proto, dns_havea)) temp_wtf("dnsq_add in dns_havesrv"); 699 if (!skadns_send(&Dnsres, &qid6, &(rr->target), S6DNS_T_AAAA, &Limit, &shortdl, &Stamp)) temp_wtf("skadns_send in dns_havesrv"); 700 if (!dnsq_add(qid6, &(mxres->mxr[(mxres->len)-1]), proto, dns_haveaaaa)) temp_wtf("dnsq_add in dns_havesrv"); 701 } 702 memset(&mxr, 0, sizeof(mxresult_t)); 703 } 704 break; 705 } 706 return TRUE; 707 } 708 709 int dns_havemx (skadns_t *dnsres, dnsq_t *dnsq, void* protop, void* unused) 710 { 711 // XX - should probably pass the whole protoalloc as protop 712 protocol_t *proto = (protocol_t *)protop, *smproto; 713 mxrAlloc *mxres = NULL; 714 mxresult_t mxr = MXRESULT_MX_ZERO; 715 genalloc rrs = GENALLOC_ZERO; 716 tain shortdl; 717 char const *dnsresponse; char ds[256]; int dnsresplen = 0, dsl = 0, i = 0; 718 s6dns_message_header_t dnsmh; 719 s6dns_message_rr_mx_t *rr = NULL; 720 uint16_t qid4, qid6; 721 722 if ((dnsresponse = skadns_packet(dnsres, dnsq->dnsq)) == NULL) { 723 info_wtfs("skadns_packet in dns_havemx"); 724 return FALSE; 725 } 726 if ((dnsresplen = skadns_packetlen(dnsres, dnsq->dnsq)) == -1) temp_wtf("skadns_packetlen in dns_havemx"); // this should succeed if the above didn't fail 727 if (dnsresplen < 12) { errno = EINVAL; temp_wtf("skadns_packetlen gave dns_havemx less than even a header"); } 728 // s6dns_message_header_unpack(dnsresponse, dnsmh); 729 switch (s6dns_message_parse(&dnsmh, dnsresponse, dnsresplen, &s6dns_message_parse_answer_mx, &rrs)) { 730 case -1: 731 temp_wtf("s6dns_message_parse in dns_havemx - local error"); 732 break; 733 case 0: 734 info_wtfs("s6dns_message_parse in dns_havemx - maybe should continue"); 735 proto->lookupdone = 1; 736 break; 737 case 1: 738 #ifdef REMOTEDEBUG 739 buffer_puts(&buffer_2_, "Is6dns_message_parse in dns_havemx - success no answer\n"); 740 #endif // REMOTEDEBUG 741 break; 742 case 2: 743 #ifdef REMOTEDEBUG 744 buffer_puts(&buffer_2_, "Is6dns_message_parse in dns_havemx - success answer\n"); 745 #endif // REMOTEDEBUG 746 for (i = 0; i < genalloc_len(s6dns_message_rr_mx_t, &rrs); ++i) { 747 //rr = (s6dns_message_rr_mx_t *)((rrs.s) + (i * sizeof(s6dns_message_rr_mx_t))); 748 rr = genalloc_s(s6dns_message_rr_mx_t, &rrs) + i; 749 mxr.lookupdone = TRUE; 750 if (_is_mxps(rr->preference)) { 751 if ((proto = Slicemap[_mxps_slice(rr->preference)]) == NULL) proto = Slicemap[NOMXPS_SLICE]; 752 mxr.prio = _mxps_prio(rr->preference); 753 } else { 754 proto = Slicemap[NOMXPS_SLICE]; 755 mxr.prio = rr->preference; 756 } 757 if (proto == NULL) {errno = EINVAL; temp_wtf("dns_havemx - postmanager has not configured a zero MXPS slice, and this is necessary.");} 758 proto->lookupdone = 1; 759 proto->hasresults = 1; 760 mxres = &(proto->mxresults); 761 mxr.port = proto->defport; 762 mxr.weight = 0; 763 if (!(dsl = s6dns_domain_tostring(ds, 255, &(rr->exchange)))) temp_wtf("s6dns_domain_tostring in dns_havemx"); 764 ds[dsl] = 0; 765 if (!stralloc_readyplus(&(mxr.name), dsl+1)) temp_nomem(); 766 if (!stralloc_copyb(&(mxr.name), ds, dsl)) temp_nomem(); 767 if (!stralloc_0(&(mxr.name))) temp_nomem(); 768 if (!tain_addsec(&Limit, &Stamp, Timeoutconnect)) temp_wtf("tain_addsec in dns_havemx (Doctor?)"); 769 if (!tain_addsec(&shortdl, &Stamp, Timeoutconnect)) temp_wtf("tain_addsec in dns_havemx (Doctor?)"); 770 if (!mxralloc_catmxr(mxres, mxr)) temp_nomem(); 771 if (mxr.name.len > 1) { // No point if it's just a dot, NPI. 772 if (!skadns_send(&Dnsres, &qid4, &(rr->exchange), S6DNS_T_A, &Limit, &shortdl, &Stamp)) temp_wtf("skadns_send in dns_havemx"); 773 if (!dnsq_add(qid4, &(mxres->mxr[(mxres->len)-1]), proto, dns_havea)) temp_wtf("dnsq_add in dns_havemx"); 774 if (!skadns_send(&Dnsres, &qid6, &(rr->exchange), S6DNS_T_AAAA, &Limit, &shortdl, &Stamp)) temp_wtf("skadns_send in dns_havemx"); 775 if (!dnsq_add(qid6, &(mxres->mxr[(mxres->len)-1]), proto, dns_haveaaaa)) temp_wtf("dnsq_add in dns_havemx"); 776 } 777 memset(&mxr, 0, sizeof(mxresult_t)); 778 mxr.ismx = TRUE; 779 } 780 break; 781 } 782 return TRUE; 783 } 784 /* 785 int dns_havecname (skadns_t *dnsres, dnsq_t *dnsq, void* protop, void *unused) 786 { 787 // We should only encounter this guy if we are using relayhost. 788 protocol_t *proto = (protocol_t *)protop; 789 mxrAlloc *mxres = &(proto->mxresults); 790 mxresult_t mxr = {0, 0, 0, FALSE, FALSE, STRALLOC_ZERO, TA_ZERO}; 791 genalloc rrs; 792 char const *dnsresponse; int dnsresplen; 793 s6dns_message_header_t dnsmh; 794 } 795 */ 796 797 /* 798 int protocol_want_srvmx (protocol_t *proto, 799 int protocol_have_mx (protocol_t *proto, 800 int protocol_want_ip (protocol_t *proto, 801 int protocol_have_mxip (protocol_t *proto, 802 int protocol_wantfd (protocol_t *proto, int mtpfd) 803 { 804 // we'll have to use a selfpipe of some description elsewhere to understand process termination 805 } 806 * 807 int protocol_spin (protocol_t *proto, char stage, unsigned long port, 808 char **rrecips, char *relayhost, size_t nprotos) 809 { 810 }*/ 811 812 // offset is needed in case we're skipping the first protocol for some reason. 813 // until then, it should always be zero 814 // nproto is the number of protocols we're doing 815 // mxralloc is inside the protocol, so 816 int dns_wantsrv (protocol_t *protos, size_t nproto) 817 { 818 int i = 0; 819 uint16_t qtype = S6DNS_T_SRV, id = 0; 820 s6dns_domain_t dnsdomain; 821 stralloc domain = STRALLOC_ZERO; 822 //mxresult_t mxr = {0, 0, 0, STRALLOC_ZERO, TA_ZERO}; 823 //mxrAlloc *mxrs; 824 //tain limit, dl; 825 826 for (i = 0; i < nproto; ++i) { 827 //mxrs = protos[i].mxresults.mxr; 828 if (!stralloc_copys(&domain, "_")) temp_nomem(); 829 if (!stralloc_cats(&domain, protos[i].srvservice)) temp_nomem(); 830 if (!stralloc_cats(&domain, "._tcp.")) temp_nomem(); 831 if (!stralloc_cats(&domain, Host.s)) temp_nomem(); 832 //if (!stralloc_0(&domain)) temp_nomem(); 833 if (!s6dns_domain_fromstring_noqualify_encode(&dnsdomain, domain.s, domain.len)) temp_wtf("s6dns_domain_fromstring_noqualify_encode in dns_wantsrv"); 834 if (!tain_addsec(&Limit, &Stamp, Timeoutconnect)) temp_wtf("tain_addsec in dns_wantsrv (Doctor?)"); 835 if (!tain_addsec(&Deadline, &Stamp, 1)) temp_wtf("tain_addsec in dns_wantsrv (Doctor?)"); 836 if (!skadns_send(&Dnsres, &id, &dnsdomain, qtype, &Limit, &Deadline, &Stamp)) temp_wtf("skadns_send in dns_wantsrv"); 837 if (!dnsq_add(id, (protos + i), NULL, dns_havesrv)) temp_wtf("dnsq_add in dns_wantsrv"); 838 } 839 stralloc_free(&domain); 840 return TRUE; // not used 841 } 842 843 int dns_wantmx (protocol_t *protos, size_t nproto) 844 { 845 int i = 0; 846 uint16_t qtype = S6DNS_T_MX, id = 0; 847 s6dns_domain_t dnsdomain; 848 stralloc domain = STRALLOC_ZERO; 849 //tain limit, dl; 850 // mxresult_t mxr = {0, 0, 0, FALSE, FALSE, TRUE, STRALLOC_ZERO, TA_ZERO}; 851 852 if (!stralloc_cats(&domain, Host.s)) temp_nomem(); 853 //if (!stralloc_0(&domain)) temp_nomem(); 854 if (!s6dns_domain_fromstring_noqualify_encode(&dnsdomain, domain.s, domain.len)) temp_wtf("s6dns_domain_fromstring_noqualify_encode in dns_wantmx"); 855 if (!tain_addsec(&Limit, &Stamp, Timeoutconnect)) temp_wtf("tain_addsec in dns_wantmx (Doctor?)"); 856 if (!tain_addsec(&Deadline, &Stamp, 1)) temp_wtf("tain_addsec in dns_wantmx (Doctor?)"); 857 if (!skadns_send(&Dnsres, &id, &dnsdomain, qtype, &Limit, &Deadline, &Stamp)) temp_wtf("skadns_send in dns_wantmx"); 858 if (!dnsq_add(id, protos, NULL, dns_havemx)) temp_wtf("dnsq_add in dns_wantmx"); 859 stralloc_free(&domain); 860 return TRUE; // not used 861 } 862 863 // the only entrypoint to this is a DNS relayhost 864 int dns_wantip (protocol_t *proto, uint16_t port, char *relayhost) 865 { 866 int i = 0; 867 uint16_t qid4 = 0, qid6 = 0; 868 s6dns_domain_t dnsdomain; 869 stralloc domain = STRALLOC_ZERO; 870 //tain limit, dl; &(mxres->mxr[(mxres->len)-1]) 871 mxresult_t mxr = MXRESULT_SRV_ZERO; 872 mxrAlloc *mxres = &(proto->mxresults); 873 874 mxr.port = port; 875 876 if (!stralloc_cats(&domain, relayhost)) temp_nomem(); 877 //if (!stralloc_0(&domain)) temp_nomem(); 878 if (!s6dns_domain_fromstring_noqualify_encode(&dnsdomain, domain.s, domain.len)) temp_wtf("s6dns_domain_fromstring_noqualify_encode in dns_wantip"); 879 if (!tain_addsec(&Limit, &Stamp, Timeoutconnect)) temp_wtf("tain_addsec in dns_wantip (Doctor?)"); 880 if (!tain_addsec(&Deadline, &Stamp, 1)) temp_wtf("tain_addsec in dns_wantip (Doctor?)"); 881 if (!mxralloc_catmxr(mxres, mxr)) temp_nomem(); 882 if (!skadns_send(&Dnsres, &qid6, &dnsdomain, S6DNS_T_AAAA, &Limit, &Deadline, &Stamp)) temp_wtf("skadns_send in dns_wantip"); 883 if (!dnsq_add(qid6, &(mxres->mxr[(mxres->len)-1]), NULL, dns_haveaaaa)) temp_wtf("dnsq_add in dns_wantip"); 884 if (!skadns_send(&Dnsres, &qid4, &dnsdomain, S6DNS_T_A, &Limit, &Deadline, &Stamp)) temp_wtf("skadns_send in dns_wantip"); 885 if (!dnsq_add(qid4, &(mxres->mxr[(mxres->len)-1]), NULL, dns_havea)) temp_wtf("dnsq_add in dns_wantip"); 886 stralloc_free(&domain); 887 return TRUE; // not used 888 } 889 890 int lookupsdone (protocol_t *proto) { 891 //protocol_t *proto = NULL; 892 mxresult_t *mxr = NULL; 893 int i = 0; 894 if (proto->lookupdone == 0) return FALSE; 895 for (i = 0; i < proto->mxresults.len; ++i) { 896 mxr = (mxresult_t *)((proto->mxresults.mxr) + (i * sizeof(mxresult_t))); 897 if (mxr->lookupdone == 0) return FALSE; 898 } 899 return TRUE; // if we have not returned false by now, all lookups are done 900 } 901 902 // comparator for qsort 903 int mxworse (void* mx1p, void* mx2p) { 904 // These get sorted in ascending order. 905 // If mx1 is less preferable than mx2, it is greater (TRUE). 906 // If it is equally preferable, it is equal (FALSE). 907 // If it is more preferable, it is lesser (-1). 908 mxresult_t *mx1 = (mxresult_t *)mx1p; 909 mxresult_t *mx2 = (mxresult_t *)mx2p; 910 911 if ((mx1->ismx) && !(mx2->ismx)) { 912 // literally need do nothing else, we prefer mx2 913 return TRUE; 914 } 915 916 if (mx1->prio > mx2->prio) { 917 // mx1 prio is higher (less prior) than mx2 prio, so true. 918 return TRUE; 919 } 920 921 if (mx1->prio == mx2->prio) { 922 // mx1 prio is equal to mx2 prio, so false, unless weight higher. 923 if (mx1->weight > mx2->weight) return -1; // mx1 is heavier, so more pref (better) 924 if (mx1->weight < mx2->weight) return TRUE; // mx1 is lighter, so less pref (worse) 925 return FALSE; 926 } 927 928 if (mx1->prio < mx2->prio) { 929 // mx1 prio is lower (less prior) than mx2 prio, so true. 930 return -1; 931 } 932 return FALSE; // Not reached. 933 } 934 935 void printprotos () { 936 protocol_t *proto = NULL; 937 mxresult_t *mxr = NULL; 938 ipmx_t *ipmx = NULL; 939 char s[48]; int i = 0, j = 0; unsigned long l = 0; 940 memset(&s, 0, 48); 941 out("I3.0.0 "); 942 out("Protocol element count: "); 943 s[fmt_ulong(s, Protocols.len)] = 0; 944 out(s); 945 out(" Protocol element allocation count: "); 946 s[fmt_ulong(s, Protocols.a)] = 0; 947 out(s); 948 out("\n"); 949 if (Protocols.len < 1) { 950 info_dbgs("3.3.0 No protocols on the protocol array!"); 951 } else { 952 for (i = 0; i < Protocols.len; ++i) { 953 proto = (protocol_t *)&(Protocols.pt[i]); 954 // + (i * sizeof(protocol_t))); 955 out("I3.0.0 "); 956 out("Protocol element #"); 957 s[fmt_ulong(s, i)] = 0; 958 out(s); 959 out(": \n srvservice: "); 960 out(proto->srvservice); 961 out("\n defport: "); 962 s[fmt_uint(s, proto->defport)] = 0; 963 out(s); 964 if (proto->slice < 0) 965 out("\n no MXPS slice for this protocol"); 966 else { 967 l = proto->slice; 968 out("\n slice: "); 969 s[fmt_uint(s, l)] = 0; 970 out(s); 971 } 972 switch (proto->tls) { 973 case 1: 974 out("\n will use TLS"); 975 break; 976 case 0: 977 switch (proto->starttls) { 978 case 1: 979 out("\n can use TLS"); 980 break; 981 case 0: 982 out("\n cannot use TLS"); 983 break; 984 } 985 } 986 if (proto->maproutes.num != 0) { 987 out("\n has "); 988 out(proto->srvservice); 989 out("routes"); 990 } else { 991 out("\n does not have "); 992 out(proto->srvservice); 993 out("routes"); 994 } 995 switch (proto->lookupdone) { 996 case 0: 997 out("\n DNS lookups have not been done"); 998 break; 999 case 1: 1000 switch (proto->hasresults) { 1001 case 3: 1002 case 2: 1003 out("\n direct A results exist"); 1004 break; 1005 case 1: 1006 out("\n MX or SRVmail results exist"); 1007 for (j = 0; j < proto->mxresults.len; ++j) { 1008 out("\n port: "); 1009 s[fmt_uint(s, proto->mxresults.mxr[j].port)] = 0; 1010 out(s); 1011 out(" prio: "); 1012 s[fmt_uint(s, proto->mxresults.mxr[j].prio)] = 0; 1013 out(s); 1014 out(" weight: "); 1015 s[fmt_uint(s, proto->mxresults.mxr[j].weight)] = 0; 1016 out(s); 1017 out(" SRV/MX: "); 1018 out(proto->mxresults.mxr[j].ismx ? "MX" : "SRV"); 1019 out(" lookupdone: "); 1020 out(proto->mxresults.mxr[j].lookupdone == 1 ? "yes" : "no"); 1021 out(" has results: "); 1022 out(proto->mxresults.mxr[j].hasresults == 1 ? "yes" : proto->mxresults.mxr[j].hasresults > 1 ? "literal IP " : "no"); 1023 out(" name: "); 1024 buffer_put(buffer_2, proto->mxresults.mxr[j].name.s, proto->mxresults.mxr[j].name.len); 1025 if (proto->mxresults.mxr[j].ipmx.len > 0) { 1026 out("\n first IP result: "); 1027 s[ip46full_fmt(s, &(proto->mxresults.mxr[j].ipmx.ipmx[0].ip))] = 0; 1028 out(s); 1029 } 1030 } 1031 break; 1032 case 0: 1033 out("\n MX or SRVmail results do not exist"); 1034 break; 1035 } 1036 } 1037 out("\n app: "); 1038 buffer_put(buffer_2, proto->app.s, proto->app.len); 1039 out("\n\n"); 1040 buffer_flush(buffer_2); 1041 } 1042 buffer_flush(buffer_2); 1043 } 1044 } 1045 1046 int lookupsdone_all (protocol_t *protos, int nprotos) 1047 { 1048 // protos should be a pointer to the beginning of the protocol list as we are using it. 1049 int i = 0; 1050 for (; i < nprotos; ++i) { 1051 if (!lookupsdone((protos + i))) return FALSE; 1052 } 1053 return TRUE; 1054 } 1055 1056 // 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 1057 // we could also, if we wanted, be tcpclient ourselves, and just launch things under ucspitlsclient as relevant 1058 1059 int main (int argcount, char **args) 1060 { 1061 char **rrecips, *relayhost; 1062 int i = 0, offset = 0, nprotos = 0; unsigned long port; char skipmx = 0, fullresults = 0; 1063 protocol_t *routesproto = NULL, *proto = NULL; ipmx_t ipmx = {IP46FULL_ZERO}; 1064 sigset_t sigset; mxresult_t rhmxr = MXRESULT_SLIP_ZERO; mxrAlloc mxres = TA_ZERO; // mxresu is unsorted 1065 tain shortdl; 1066 1067 PROG = "mxf-remote"; 1068 1069 tain_now(&Stamp); 1070 tain_addsec(&Deadline, &Stamp, 2); // eh, the manpages at skarnet's website said to do this so I will 1071 1072 // check basic configuration 1073 if (argcount < 4) perm_usage(); 1074 if (chdir(auto_qmail) == -1) temp_chdir(); 1075 if (!stralloc_copys(&Host,args[1])) temp_nomem(); 1076 //if (!stralloc_0(&Host)) temp_nomem(); 1077 if (!stralloc_copys(&Sender,args[2])) temp_nomem(); 1078 //if (!stralloc_0(&Sender)) temp_nomem(); 1079 1080 getcontrols(); 1081 ipme_init(); 1082 ip6me_init(); 1083 1084 // trap signals 1085 sig_ignore(SIGPIPE); 1086 Sigfd = selfpipe_init(); // selfpipe.h 1087 sigemptyset(&sigset); 1088 sigaddset(&sigset, SIGCHLD); 1089 if (0 == selfpipe_trapset(&sigset)) temp_oserr(); 1090 struct pollfd sigpfd; 1091 sigpfd.fd = Sigfd; 1092 sigpfd.events = POLLIN; 1093 sigpfd.revents = 0; 1094 descriptor_add(sigpfd, (void *)&Protegetab, &checksignals); 1095 1096 printprotos(); 1097 /* Of interest here is that ... NOTES-mxfr #0010 */ 1098 1099 /* So at this stage we know what the protocols are and we can decide 1100 * whether we want to skip SRV and MX. 1101 * 1102 * If we do, it's because we have a <protocol>routes file. protocol->maproutes 1103 * will have the scoop. 1104 * ga_foreach doesn't support non-pointer structs, so we make a pointer here. 1105 */ 1106 startdns(&Dnsres); 1107 struct pollfd dnspfd; 1108 dnspfd.fd = skadns_fd(&Dnsres); 1109 dnspfd.events = POLLIN; 1110 dnspfd.revents = 0; 1111 descriptor_add(dnspfd, (void *)&Dnsres, &checkdns); 1112 rrecips = args + 3; 1113 1114 for (i = 0; i < Protocols.len; i++) { 1115 // proto = (protocol_t *)((Protocols.pt) + (offset = (i * sizeof(protocol_t))) ); // fallback version 1116 proto = (protocol_t *)&(Protocols.pt[i]); 1117 // This is lifted from qmail-remote.c:333 with minimal changes 1118 // to fit the new system. 1119 // I do not purport to understand it. 1120 for (i = 0;i <= Host.len;++i) { 1121 if ((i == 0) || (i == Host.len) || (Host.s[i] == '.')) 1122 if ((relayhost = constmap(&(proto->maproutes),Host.s + i,Host.len - i))) { 1123 skipmx = 1; 1124 routesproto = proto; 1125 nprotos = 1; 1126 } 1127 } 1128 if (relayhost && !*relayhost) relayhost = 0; 1129 1130 if (relayhost) { 1131 i = str_chr(relayhost,':'); 1132 if (relayhost[i]) { 1133 scan_ulong(relayhost + i + 1,&port); 1134 relayhost[i] = 0; 1135 } 1136 if (!stralloc_copys(&Host,relayhost)) temp_nomem(); 1137 } 1138 1139 if (skipmx) { 1140 if (!port) port = routesproto->defport; 1141 break; 1142 } 1143 } 1144 1145 // fire off the SRV/MX DNS volley; wait Timeoutconnect seconds from when 1146 // we're finished bowling to when we give up on run_fds 1147 // also break if a foreach loop of lookupsdone(Protocols.pt[i]) does not return false 1148 if (!skipmx) { 1149 proto = (protocol_t *)((Protocols.pt) + (offset = 0)); // reset the proto pointer 1150 nprotos = Protocols.len; // it's 1 if we are skipping MX and SRVmail 1151 } 1152 1153 if (relayhost) { 1154 if (!ip46_scan(relayhost, &(ipmx.ip))) { 1155 dns_wantip(routesproto, port, relayhost); 1156 } else { 1157 routesproto->hasresults = 1; 1158 routesproto->lookupdone = 1; 1159 // I guess we're building an mxr then... 1160 rhmxr.port = port; 1161 rhmxr.hasresults = 2; 1162 // prio/wt dealt with 1163 if (!stralloc_copys(&(rhmxr.name), relayhost)) temp_nomem(); 1164 if (!stralloc_0(&(rhmxr.name))) temp_nomem(); 1165 if (!ipmxalloc_catip(&(rhmxr.ipmx), ipmx)) temp_nomem(); 1166 } 1167 } else { 1168 // our DNS volley 1169 dns_wantsrv(proto, nprotos); 1170 dns_wantmx(proto, nprotos); 1171 out("regular DNS...\n"); 1172 } 1173 1174 tain_now(&Stamp); 1175 tain_addsec(&Deadline, &Stamp, Timeoutconnect); 1176 tain_addsec(&shortdl, &Stamp, 3); 1177 1178 while (!lookupsdone_all(proto, nprotos)) { 1179 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. 1180 tain_addsec(&shortdl, &Stamp, 3); 1181 if (!tain_less(&Stamp, &Deadline)) { 1182 errno = ETIMEDOUT; 1183 skadns_end(&Dnsres); 1184 info_wtfs("DNS lookup event loop took too long - mostly orderly shutdown executed"); // cut... 1185 break; 1186 } 1187 } // should not run if lookupsdone_all already (SLIP relayhost) 1188 1189 printprotos(); 1190 /* TODO: actually send the letter */ 1191 1192 } 1193 #endif