rp

simple email tools
git clone https://git.parazyd.org/rp
Log | Files | Refs | README | LICENSE

commit 39df0ce52a876559312c2104fcbb1160c5621ba8
parent a27f502661956817f84fd01f5929470a1d6442e3
Author: parazyd <parazyd@dyne.org>
Date:   Sat,  3 Mar 2018 16:08:28 +0100

Add 20h's net.c and refactor.

Diffstat:
MLICENSE | 1+
Mbin/rpsend | 4++--
Mconfig.mk | 4+++-
Mind.c | 31+++++++++++++++++++++++++++++++
Mind.h | 12++++++++++--
Mnet.c | 303+++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------------------
Mnet.h | 14++++++++++++--
Mrohrpost.c | 1-
Atest/Makefile | 17+++++++++++++++++
Atest/nettest.c | 47+++++++++++++++++++++++++++++++++++++++++++++++
Mutil.c | 46+++++++++++++++++++++++++++++++++++++++++-----
11 files changed, 382 insertions(+), 98 deletions(-)

diff --git a/LICENSE b/LICENSE @@ -1,4 +1,5 @@ Copyright (c) 2018 Ivan J. <parazyd@dyne.org> +Copyright (c) 2011-2016 Christoph Lohmann <20h@r-36.net> GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 diff --git a/bin/rpsend b/bin/rpsend @@ -47,11 +47,11 @@ einfo "smtp send via $rimap" if ! [ -f "$profile/smtp-fingerprint" ]; then einfo "no saved tls certificate fingerprint found. going with tofu." - rpnet -f "$(echo $rnet | sed 's/imaps/smtps/')" > "$profile"/smtp-fingerprint + rputil -e getfpr "$rnet" > "$profile"/smtp-fingerprint fi known="$(cat $profile/smtp-fingerprint)" -served="$(rpnet -f "$rnet")" +served="$(rputil -e getfpr "$rnet")" einfo "known fingerprint: $known" einfo "served fingerprint: $served" diff --git a/config.mk b/config.mk @@ -5,8 +5,10 @@ PREFIX = /usr/local SHAREPREFIX = $(PREFIX)/share/rp MANPREFIX = $(PREFIX)/share/man -CFLAGS = -O2 -Wall -pedantic +CFLAGS = -O2 -Wall -pedantic -std=gnu99 LDFLAGS = -static -g -lssl -lcrypto +CC = gcc + .c.o: $(CC) $(CFLAGS) -c $< diff --git a/ind.c b/ind.c @@ -7,6 +7,7 @@ #include <stdarg.h> #include <stdio.h> #include <stdlib.h> +#include <string.h> void edie(char *fmt, ...) { va_list fmtargs; @@ -50,3 +51,33 @@ void info(char *fmt, ...) { vfprintf(stderr, fmt, fmtargs); va_end(fmtargs); } + +void *reallocz(void *p, int l, int z) { + p = realloc(p, l); + if (p == NULL) + edie("realloc"); + if (z) + memset(p, 0, l); + return p; +} + +void *mallocz(int l, int z) { + return reallocz(NULL, l, z); +} + +void *memdup(void *p, int l) { + char *ret; + + ret = reallocz(NULL, l, 2); + memmove(ret, p, l); + + return (void *)ret; +} + +char *vsmprintf(char *fmt, va_list fmtargs, int size) { + char *ret; + ret = reallocz(NULL, ++size, 2); + vsnprintf(ret, size, fmt, fmtargs); + + return ret; +} diff --git a/ind.h b/ind.h @@ -6,13 +6,21 @@ #ifndef __RPIND_H__ #define __RPIND_H__ -#define MAXLINESIZE 1048576 - #define nelem(x) (sizeof(x) / sizeof((x)[0])) +#include <stdarg.h> + +#define MAXLINESIZE 1048576 + void edie(char *fmt, ...); void die(char *fmt, ...); void warn(char *fmt, ...); void info(char *fmt, ...); +void *reallocz(void *p, int l, int z); +void *mallocz(int l, int z); +void *memdup(void *p, int l); + +void *vsmprintf(char *fmt, va_list fmtargs, int size); + #endif diff --git a/net.c b/net.c @@ -5,19 +5,16 @@ #include <stdio.h> #include <stdlib.h> +#include <string.h> #include <unistd.h> #include <netdb.h> #include <openssl/ssl.h> #include <openssl/err.h> -#include <openssl/x509.h> -#include "arg.h" #include "ind.h" #include "net.h" -char *argv0; - /* * net format: * net!addr!service @@ -34,11 +31,6 @@ static char *netnames[] = { [NET_TCPS] = "tcps" }; -void netusage(void) { - die("usage: %s [-f netspec]\n" - " -f: fetch and print ssl certificate fingerprint\n", argv0); -} - int net_gettype(char *str) { int i; @@ -50,123 +42,264 @@ int net_gettype(char *str) { net_t *net_new(char *desc) { net_t *ret; - char *type, *addr, *service;; - - type = strtok(desc, "!"); - addr = strtok(NULL, "!"); - service = strtok(NULL, "!"); - - if ((!type) || (!addr) || (!service)) - die("invalid line fed to net_new\n"); - - ret = malloc(sizeof(net_t)); - - ret->type = net_gettype(type); - ret->addr = addr; - ret->service = service; + int state; + char *tok, *buf, *toks; + + state = -1; + toks = NULL; + ret = NULL; + buf = memdup(desc, strlen(desc)+1); + + tok = strtok_r(buf, "!", &toks); + if (tok == NULL) + goto netnewerror; + + ret = mallocz(sizeof(net_t), 2); + do { + state++; + switch(state) { + case 0: + ret->net = memdup(tok, strlen(tok)+1); + ret->type = net_gettype(ret->net); + break; + case 1: + ret->addr = memdup(tok, strlen(tok)+1); + break; + case 2: + ret->service = memdup(tok, strlen(tok)+1); + break; + case 3: + ret->options = memdup(tok, strlen(tok)+1); + break; + default: + break; + } + } while ((tok = strtok_r(NULL, "!", &toks)) != NULL); + if (state < 2) + goto netnewerror; + free(buf); return ret; -} +netnewerror: + if (buf != NULL) + free(buf); + + switch (state) { + case 1: + free(ret->addr); + case 0: + free(ret->net); + default: + break; + } + if (ret != NULL) + free(ret); -int sslfpr(net_t *net) { - int i; - unsigned int fpr_size; - SSL *sfd; - X509 *cert; + return NULL; +} - const EVP_MD *fpr_type; - unsigned char fpr[EVP_MAX_MD_SIZE]; +void net_free(net_t *net) { + if (net->net != NULL) + free(net->net); + if (net->addr != NULL) + free(net->addr); + if (net->service != NULL) + free(net->service); + free(net); +} +int net_connecttcp(net_t *net) { struct addrinfo hints, *ai, *rp; - /* bzero(&hints, sizeof(hints)); */ memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; hints.ai_protocol = IPPROTO_TCP; - - if (getaddrinfo(net->addr, net->service, &hints, &ai)) return 1; if (ai == NULL) return 1; - SSL_library_init(); - OpenSSL_add_all_algorithms(); - - net->data[1] = SSL_CTX_new(SSLv23_client_method()); - if (net->data[1] == NULL) - goto sslfprerr; - SSL_CTX_set_options((SSL_CTX *)net->data[1], - SSL_OP_NO_SSLv2|SSL_OP_NO_SSLv3); - for (rp = ai; rp != NULL; rp = rp->ai_next) { net->fd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); - if (connect(net->fd, rp->ai_addr, rp->ai_addrlen)) + if (net->fd < 0) + continue; + if (!connect(net->fd, rp->ai_addr, rp->ai_addrlen)) break; + close(net->fd); + } + if (rp == NULL) + return 1; + freeaddrinfo(ai); - if ((sfd = SSL_new((SSL_CTX *)net->data[1])) == NULL) - goto sslfprerr; - SSL_set_fd(sfd, net->fd); - if (SSL_connect(sfd) < 1) - goto sslfprerr; - - - cert = SSL_get_peer_certificate(sfd); - if (cert == NULL) - goto sslfprerr; + return 0; +} - fpr_type = EVP_sha1(); - if (!X509_digest(cert, fpr_type, fpr, &fpr_size)) - goto sslfprerr; +int net_addssl(net_t *net) { + SSL *sfd; - for (i = 0; i < fpr_size; i++) - printf("%02X%c", fpr[i], (i+1 == fpr_size) ? '\n':':'); + SSL_library_init(); + OpenSSL_add_all_algorithms(); + net->data[1] = SSL_CTX_new(SSLv23_method()); + if (net->data[1] == NULL) + goto netaddsslerr; + SSL_CTX_set_options((SSL_CTX *)net->data[1], + SSL_OP_NO_SSLv2|SSL_OP_NO_SSLv3); - X509_free(cert); - SSL_CTX_free(net->data[1]); - SSL_free(sfd); - EVP_cleanup(); - CRYPTO_cleanup_all_ex_data(); - close(net->fd); + if ((sfd = SSL_new((SSL_CTX *)net->data[1])) == NULL) + goto netaddsslerr; + SSL_set_fd(sfd, net->fd); + if (SSL_connect(sfd) < 1) + goto netaddsslerr; + + switch (net->type) { + case NET_NET: + case NET_TCP: + free(net->net); + net->net = memdup("tcps", 5); + net->type = net_gettype(net->net); + case NET_TCPS: + default: + break; } - return 0; + net->data[0] = sfd; -sslfprerr: + return 0; +netaddsslerr: SSL_load_error_strings(); ERR_print_errors_fp(stderr); ERR_free_strings(); return 1; } -int netmain(int argc, char *argv[]) { +int net_connecttcps(net_t *net) { + if (net_connecttcp(net)) + return 1; + if (net_addssl(net)) + return 1; + + return 0; +} - int fflag = 0; +int net_connect(net_t *net) { + switch (net->type) { + case NET_NET: + case NET_TCP: + return net_connecttcp(net); + case NET_TCPS: + return net_connecttcps(net); + default: + return 1; + } - char *netspec; + return 0; +} - netspec = NULL; +void net_closetcp(net_t *net) { + shutdown(net->fd, SHUT_RDWR); + close(net->fd); +} - ARGBEGIN { - case 'f': - netspec = EARGF(netusage()); - fflag = 1; +void net_closetcps(net_t *net) { + SSL_CTX_free((SSL_CTX *)net->data[1]); + SSL_free((SSL *)net->data[0]); + EVP_cleanup(); + CRYPTO_cleanup_all_ex_data(); +} + +void net_close(net_t *net) { + switch (net->type) { + case NET_NET: + case NET_TCP: + net_closetcp(net); + case NET_TCPS: + net_closetcps(net); + default: break; + } +} + +int net_writetcp(net_t *net, char *buf, int len) { + return send(net->fd, buf, len, MSG_NOSIGNAL); +} + +int net_writetcps(net_t *net, char *buf, int len) { + return SSL_write((SSL *)net->data[0], buf, len); +} + +int net_write(net_t *net, char *buf, int len) { + switch (net->type) { + case NET_NET: + case NET_TCP: + return net_writetcp(net, buf, len); + case NET_TCPS: + return net_writetcps(net, buf, len); + default: + return -1; + } + return -1; +} + + +int net_writeall(net_t *net, char *buf, int len) { + + int olen, nlen; + + for (olen = 0; + (nlen = net_write(net, &buf[olen], len-olen)) + && olen < len; olen += nlen); + + return 0; +} + +int net_printf(net_t *net, char *fmt, ...) { + va_list fmtargs; + char *buf; + int len; + + va_start(fmtargs, fmt); + len = vsnprintf(NULL, 0, fmt, fmtargs); + va_end(fmtargs); + + va_start(fmtargs, fmt); + buf = vsmprintf(fmt, fmtargs, len); + va_end(fmtargs); + + len = net_writeall(net, buf, strlen(buf)); + free(buf); + return len; +} + +int net_readtcp(net_t *net, char *buf, int len) { + return recv(net->fd, buf, len, 0); +} + +int net_readtcps(net_t *net, char *buf, int len) { + return SSL_read((SSL *)net->data[0], buf, len); +} + +int net_read(net_t *net, char *buf, int len) { + switch (net->type) { + case NET_NET: + case NET_TCP: + return net_readtcp(net, buf, len); + case NET_TCPS: + return net_readtcps(net, buf, len); default: - netusage(); - } ARGEND; - - if (fflag) { - net_t *net; - net = net_new(netspec); - if (sslfpr(net)) - return 1; - return 0; + return -1; } + return -1; +} + +int net_readall(net_t *net, char *buf, int len) { + int olen, nlen; - netusage(); + for (olen = 0; + (nlen = net_read(net, &buf[olen], len-olen)) + && olen < len; olen += nlen); return 0; } diff --git a/net.h b/net.h @@ -1,6 +1,6 @@ /* * Copy me if you can - * by parazyd + * by 20h and parazyd */ #ifndef __RPNET_H__ @@ -19,6 +19,16 @@ struct net_t { void *data[2]; }; -int netmain(int argc, char *argv[]); +net_t *net_new(char *desc); +void net_free(net_t *net); + +int net_addssl(net_t *net); +int net_connect(net_t *net); +void net_close(net_t *net); +int net_write(net_t *net, char *buf, int len); +int net_writeall(net_t *net, char *buf, int len); +int net_printf(net_t *net, char *fmt, ...); +int net_read(net_t *net, char *buf, int len); +int net_readall(net_t *net, char *buf, int len); #endif diff --git a/rohrpost.c b/rohrpost.c @@ -35,7 +35,6 @@ enum { struct command cmds[] = { {"rpheaders", DOINSTALL, headersmain}, {"rpsieve", DONTINSTALL, sievemain}, - {"rpnet", DOINSTALL, netmain}, {"rputil", DOINSTALL, utilmain}, }; diff --git a/test/Makefile b/test/Makefile @@ -0,0 +1,17 @@ +BIN = \ + nettest + +all: clean alltest +# @echo Possible options are: +# @echo ' * make alltest' +# @echo +# @echo ' * make nettest' + +alltest: $(BIN) + +nettest: + gcc -g -std=gnu99 -Wall -pedantic -I.. -lssl -lcrypto \ + -o nettest nettest.c ../net.c ../ind.c + +clean: + rm -f $(BIN) diff --git a/test/nettest.c b/test/nettest.c @@ -0,0 +1,47 @@ +/* + * Copy me if you can + * by parazyd + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "net.h" + +int main(void) { + net_t *net; + char buf[4097]; + int len; + + memset(&buf, 0, sizeof(buf)); + + printf("net_new tcps!www.facebook.com!https\n"); + net = net_new("tcps!www.facebook.com!https"); + if (net == NULL) { + perror("net_new"); + exit(EXIT_FAILURE); + } + + printf("net_connect\n"); + if (net_connect(net)) { + perror("net_connect"); + exit(EXIT_FAILURE); + } + + printf("net_printf GET / HTTP 1.1 ...\n"); + net_printf(net, "GET / HTTP/1.1\r\nHost: www.facebook.com\r\n" + "Connection: close\r\n\r\n"); + + printf("net_read\n"); + while((len = net_read(net, buf, sizeof(buf)-1)) > 0) + fwrite(buf, len, 1, stdout); + + printf("net_close\n"); + net_close(net); + + printf("net_free\n"); + net_free(net); + + return EXIT_SUCCESS; +} diff --git a/util.c b/util.c @@ -8,7 +8,11 @@ #include <string.h> #include <time.h> +#include <openssl/ssl.h> +#include <openssl/x509.h> + #include "arg.h" +#include "net.h" #include "ind.h" #include "util.h" @@ -23,8 +27,8 @@ void utilusage(void) { " available utils:\n" "\t * genmsgid: generates a Message-ID header\n" "\t * genmimeb: generates a semi-random MIME boundary\n" - "\t * humansize: calculates byte size into human readable " - "and prints it\n", argv0); + "\t * humansize: calculates byte size into human readable\n" + "\t * getfpr: get tls fingerprint of $netspec\n", argv0); } int randint(int max) { @@ -78,6 +82,36 @@ int humansize(unsigned long size) { return 0; } +int getfpr(char *desc) { + net_t *net; + + int i; + unsigned int fpr_size; + X509 *cert; + const EVP_MD *fpr_type; + unsigned char fpr[EVP_MAX_MD_SIZE]; + + net = net_new(desc); + if (net == NULL) + edie("net_new"); + + if (net_connect(net)) + edie("net_connect"); + + cert = SSL_get_peer_certificate(net->data[0]); + fpr_type = EVP_sha1(); + X509_digest(cert, fpr_type, fpr, &fpr_size); + + for (i = 0; i < fpr_size; i++) + printf("%02X%c", fpr[i], (i+1 == fpr_size) ? '\n':':'); + + X509_free(cert); + net_close(net); + net_free(net); + + return 0; +} + int utilmain(int argc, char *argv[]) { char *runcmd, *cmdarg; @@ -88,8 +122,7 @@ int utilmain(int argc, char *argv[]) { case 'e': runcmd = EARGF(utilusage()); if (argc > 1) { - argc--; argv++; - cmdarg = EARGF(utilusage()); + cmdarg = argv[1]; } break; default: @@ -102,9 +135,12 @@ int utilmain(int argc, char *argv[]) { if (!strncmp("genmimeb", runcmd, 8)) return genmimeb(); - if (cmdarg) + if (cmdarg) { if (!strncmp("humansize", runcmd, 9)) return humansize(atol(cmdarg)); + if (!strncmp("getfpr", runcmd, 6)) + return getfpr(cmdarg); + } utilusage(); return 1;