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:
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;