28#include "timeoutconn.h"
38#define WHO "sslclient"
41 logmsg(
WHO,111,FATAL,
"out of memory");
43void env(
const char *s,
const char *t) {
44 if (!pathexec_env(s,t))
nomem();
48 logmsg(
WHO,100,USAGE,
"sslclient \
49[ -463hHrRdDiqQveEsSnNxX ] \
81char iplocal[16] = { 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0 };
91static stralloc addresses;
92static stralloc certname;
93static stralloc moreaddresses;
97static char strnum[FMT_ULONG];
98static char ipstr[IP6_FMT];
127 logmsg(
WHO,111,ERROR,B(
"unable to read password from: ",
keypass));
131 logmsg(
WHO,111,ERROR,B(
"unable to read password from: ",
keypass));
141 logmsg(
WHO,111,ERROR,
"unable to read password from FD3");
149 logmsg(
WHO,111,ERROR,
"password too long");
155int main(
int argc,
char *
const *argv)
168 dns_random_init(
seed);
172 sig_ignore(sig_pipe);
174 while ((opt = getoptb(argc,(
char **)argv,
"dDvqQhHrRimM:p:t:T:l:a:A:c:z:k:K:V:346eEsSnN0xXw:")) != opteof)
176 case '4': ipflag = 1;
break;
177 case '6': ipflag = 0;
break;
190 case 't': scan_ulong(optarg,&
itimeout);
break;
191 case 'T': j = scan_ulong(optarg,&
ctimeout[0]);
192 if (optarg[j] ==
'+') ++j;
193 scan_ulong(optarg + j,&
ctimeout[1]);
break;
195 case 'i':
if (!ip6_scan(optarg,
iplocal))
usage();
break;
196 case 'I':
netif = socket_getifidx(optarg);
break;
197 case 'p': scan_ulong(optarg,&u);
portlocal = u;
break;
198 case 'a':
cafile = optarg;
break;
199 case 'A':
cadir = optarg;
break;
201 case 'z':
ciphers = optarg;
break;
202 case 'k':
keyfile = optarg;
break;
203 case 'K':
keypass = optarg;
break;
204 case 'V': scan_ulong(optarg,&u);
verifydepth = u;
break;
205 case '3':
flag3 = 1;
break;
227 if (!x[scan_ulong(x,&u)])
231 se = getservbyname(x,
"tcp");
233 logmsg(
WHO,111,FATAL,B(
"unable to figure out port number for ",x));
234 uint16_unpack_big((
char*)&se->s_port,&
portremote);
248 if (!*++argv)
usage();
253 if (!stralloc_copyb(&addresses,(
char *)V4mappedprefix,12))
nomem();
255 byte_copy(
iplocal,16,addresses.s);
258 byte_copy(
iplocal,16,addresses.s);
261 if (addresses.len < 4) {
263 dns_ip_qualify(&addresses,&fqdn,&tmp);
264 if (addresses.len < 16)
265 logmsg(
WHO,111,ERROR,B(
"No IP address for: ",
hostname));
268 if (addresses.len == 16) {
273 for (cloop = 0; cloop < 2; ++cloop) {
274 if (!stralloc_copys(&moreaddresses,
""))
nomem();
275 for (j = 0; j + 16 <= addresses.len; j += 16) {
276 if (ipflag == 1 || ip6_isv4mapped(addresses.s + j)) {
278 if (s == -1) logmsg(
WHO,111,FATAL,
"unable to create socket");
282 if (s == -1) logmsg(
WHO,111,FATAL,
"unable to create socket");
286 if (r == -1) logmsg(
WHO,111,FATAL,B(
"unable to bind to socket for local port: ",strnum));
290 if (!cloop &&
ctimeout[1] && (errno == ETIMEDOUT)) {
291 if (!stralloc_catb(&moreaddresses,addresses.s + j,16))
nomem();
295 if (ip6_isv4mapped(addresses.s + j))
296 ipstr[ip4_fmt(ipstr,addresses.s + j + 12)] = 0;
298 ipstr[ip6_fmt(ipstr,addresses.s + j)] = 0;
301 if (!stralloc_copy(&addresses,&moreaddresses))
nomem();
303 logmsg(
WHO,110,DROP,B(
"unable to connect to: ",ipstr,
" port: ",strnum));
312 logmsg(
WHO,111,FATAL,
"unable to get local address");
316 ipstr[ip4_fmt(ipstr,
iplocal + 12)] = 0;
320 ipstr[ip6_fmt(ipstr,
iplocal)] = 0;
323 env(
"SSLLOCALIP",ipstr);
327 env(
"SSLLOCALPORT",strnum);
332 if (dns_name(&tmp,
iplocal) >= 0) {
333 if (!stralloc_0(&tmp))
nomem();
336 env(
"SSLLOCALHOST",x);
342 logmsg(
WHO,111,FATAL,
"unable to get remote address");
345 ipstr[ip4_fmt(ipstr,
ipremote + 12)] = 0;
349 env(
"SSLREMOTEIP",ipstr);
353 env(
"SSLREMOTEPORT",strnum);
359 if (!stralloc_0(&tmp))
nomem();
363 env(
"SSLREMOTEHOST",x);
369 if (!stralloc_0(&tmp))
nomem();
372 env(
"SSLREMOTEINFO",x);
380 logmsg(
WHO,111,FATAL,
"unable to create TLS context");
383 case -1: logmsg(
WHO,111,ERROR,
"unable to load certificate");
384 case -2: logmsg(
WHO,111,ERROR,
"unable to load key pair");
385 case -3: logmsg(
WHO,111,ERROR,
"key does not match certificate");
390 logmsg(
WHO,111,ERROR,
"unable to load CA list");
393 logmsg(
WHO,111,ERROR,
"unable to set cipher list");
396 if (!ssl) logmsg(
WHO,111,FATAL,
"unable to create TLS instance");
399 if (!SSL_set_tlsext_host_name(ssl,
hostname))
400 logmsg(
WHO,111,FATAL,B(
"unable to set TLS SNI extensions for hostname: ",(
char *)
hostname));
402 for (cloop = 0; cloop < 2; ++cloop) {
404 if (!cloop &&
ctimeout[1])
continue;
405 logmsg(
WHO,111,FATAL,
"unable to TLS connect");
417 logmsg(
WHO,110,ERROR,
"no server certificate");
419 logmsg(
WHO,110,ERROR,
"missing credentials (CA) or unable to validate server certificate");
421 if (!stralloc_0(&certname))
nomem();
423 logmsg(
WHO,110,ERROR,B(
"server hostname does not match certificate: ",(
char *)
hostname,
" <=> ",certname.s));
428 log_who(
WHO,B(
"tls connected to: ",ipstr,
" port: ",strnum));
431 socket_tcpnodelay(s);
433 if (pipe(
pi) == -1) logmsg(
WHO,111,FATAL,
"unable to create pipe");
434 if (pipe(
po) == -1) logmsg(
WHO,111,FATAL,
"unable to create pipe");
436 if (pipe(
pt) == -1) logmsg(
WHO,111,FATAL,
"unable to create pipe");
437 close(
pi[0]); close(
pi[1]);
441 if (pipe(
pt) == -1) logmsg(
WHO,111,FATAL,
"unable to create pipe");
442 close(
po[0]); close(
po[1]);
446 switch (opt = fork()) {
448 logmsg(
WHO,111,FATAL,
"unable to fork");
452 close(
pi[0]); close(
po[1]);
454 logmsg(
WHO,110,DROP,
"unable to speak TLS");
456 wait_pid(&wstat,opt);
460 if (wait_pid(&wstat,opt) > 0)
461 _exit(wait_exitcode(wstat));
468 if (fd_move(6,
pi[0]) == -1)
469 logmsg(
WHO,111,FATAL,
"unable to set up descriptor 6");
470 if (fd_move(7,
po[1]) == -1)
471 logmsg(
WHO,111,FATAL,
"unable to set up descriptor 7");
472 sig_uncatch(sig_pipe);
475 logmsg(
WHO,111,FATAL,B(
"unable to run: ",*argv));
const char auto_ciphers[]
int remoteinfo(stralloc *out, char ipremote[16], uint16 portremote, char iplocal[16], uint16 portlocal, unsigned int timeout, uint32 netif)
int ssl_ca(SSL_CTX *ctx, const char *certfile, const char *certdir, int d)
int ssl_certkey(SSL_CTX *ctx, const char *certfile, const char *keyfile, pem_password_cb *passwd_cb)
int ssl_ciphers(SSL_CTX *ctx, const char *ciphers)
int ssl_client_env(SSL *ssl, stralloc *sa)
int ssl_io(SSL *ssl, int fdleft, int fdright, unsigned int timeout)
SSL * ssl_new(SSL_CTX *ctx, int s)
int ssl_timeoutconn(SSL *ssl, unsigned int timeout)
int ssl_verify(SSL *ssl, const char *hostname, stralloc *dnsout)
unsigned long ctimeout[2]
void env(const char *s, const char *t)
int passwd_cb(char *buf, int size, int rwflag, void *userdata)
Header file to be used with sqmail; previously called ssl.h. (name clash)