From 4bfc85868b69cd991cf98aae8dabf7284925a3e1 Mon Sep 17 00:00:00 2001 From: Soner Tari Date: Thu, 3 Aug 2017 14:55:57 +0300 Subject: [PATCH] Add support for pop3 (p3scan pop3 proxy) Send sslproxy info only once, in the first packet only Clean-up --- opts.c | 32 ++++++++++++++---------- opts.h | 1 + pxyconn.c | 74 ++++++++++++++++++++++++++++++++++++++++++------------- pxyconn.h | 2 ++ 4 files changed, 79 insertions(+), 30 deletions(-) diff --git a/opts.c b/opts.c index 92f2834..93638ae 100644 --- a/opts.c +++ b/opts.c @@ -298,35 +298,38 @@ proxyspec_parse(int *argc, char **argv[], const char *natengine) switch (state) { default: case 0: - /* tcp | ssl | http | https | autossl */ + /* tcp | ssl | http | https | autossl | mail | mails */ curspec = malloc(sizeof(proxyspec_t)); memset(curspec, 0, sizeof(proxyspec_t)); curspec->next = spec; spec = curspec; + // Defaults + spec->ssl = 0; + spec->http = 0; + spec->upgrade = 0; + spec->mail = 0; if (!strcmp(**argv, "tcp")) { - spec->ssl = 0; - spec->http = 0; - spec->upgrade = 0; + // use defaults } else if (!strcmp(**argv, "ssl")) { spec->ssl = 1; - spec->http = 0; - spec->upgrade = 0; } else if (!strcmp(**argv, "http")) { - spec->ssl = 0; spec->http = 1; - spec->upgrade = 0; } else if (!strcmp(**argv, "https")) { spec->ssl = 1; spec->http = 1; - spec->upgrade = 0; } else if (!strcmp(**argv, "autossl")) { - spec->ssl = 0; - spec->http = 0; spec->upgrade = 1; + } else + if (!strcmp(**argv, "mail")) { + spec->mail = 1; + } else + if (!strcmp(**argv, "mails")) { + spec->ssl = 1; + spec->mail = 1; } else { fprintf(stderr, "Unknown connection " "type '%s'\n", **argv); @@ -396,7 +399,9 @@ proxyspec_parse(int *argc, char **argv[], const char *natengine) !strcmp(**argv, "ssl") || !strcmp(**argv, "http") || !strcmp(**argv, "https") || - !strcmp(**argv, "autossl")) { + !strcmp(**argv, "autossl") || + !strcmp(**argv, "mail") || + !strcmp(**argv, "mails")) { /* implicit default natengine */ (*argv)--; (*argc)++; /* rewind */ state = 0; @@ -541,10 +546,11 @@ proxyspec_str(proxyspec_t *spec) return NULL; } } - if (asprintf(&s, "listen=[%s]:%s %s%s%s %s%s%s", lhbuf, lpbuf, + if (asprintf(&s, "listen=[%s]:%s %s%s%s%s %s%s%s", lhbuf, lpbuf, (spec->ssl ? "ssl" : "tcp"), (spec->upgrade ? "|upgrade" : ""), (spec->http ? "|http" : ""), + (spec->mail ? "|mail" : ""), (spec->natengine ? spec->natengine : cbuf), (pdstbuf), (csrcbuf)) < 0) { diff --git a/opts.h b/opts.h index 6e99163..b303dde 100644 --- a/opts.h +++ b/opts.h @@ -40,6 +40,7 @@ typedef struct proxyspec { unsigned int ssl : 1; unsigned int http : 1; unsigned int upgrade: 1; + unsigned int mail : 1; unsigned int dns : 1; /* set if spec needs DNS lookups */ struct sockaddr_storage listen_addr; socklen_t listen_addrlen; diff --git a/pxyconn.c b/pxyconn.c index ba54819..404bf44 100644 --- a/pxyconn.c +++ b/pxyconn.c @@ -114,6 +114,8 @@ typedef struct pxy_conn_lproc_desc { #define SSLPROXY_ADDR_KEY_LEN strlen(SSLPROXY_ADDR_KEY) #define SSLPROXY_SRCADDR_KEY "SSLproxy-SrcAddr:" #define SSLPROXY_SRCADDR_KEY_LEN strlen(SSLPROXY_SRCADDR_KEY) +#define SSLPROXY_DSTADDR_KEY "SSLproxy-DstAddr:" +#define SSLPROXY_DSTADDR_KEY_LEN strlen(SSLPROXY_DSTADDR_KEY) static pxy_conn_ctx_t * MALLOC NONNULL(2,3,4) pxy_conn_ctx_new(evutil_socket_t fd, @@ -437,6 +439,9 @@ pxy_conn_ctx_free(pxy_conn_ctx_t *ctx, int by_requestor) if (ctx->src_addr_str) { free(ctx->src_addr_str); } + if (ctx->dst_addr_str) { + free(ctx->dst_addr_str); + } if (ctx->srv_dst_ssl_version) { free(ctx->srv_dst_ssl_version); } @@ -1503,6 +1508,7 @@ pxy_http_reqhdr_filter_line(const char *line, pxy_conn_ctx_t *ctx, int child) return NULL; } else if (child && (!strncasecmp(line, SSLPROXY_ADDR_KEY, SSLPROXY_ADDR_KEY_LEN) || !strncasecmp(line, SSLPROXY_SRCADDR_KEY, SSLPROXY_SRCADDR_KEY_LEN) || + !strncasecmp(line, SSLPROXY_DSTADDR_KEY, SSLPROXY_DSTADDR_KEY_LEN) || // @attention flickr keeps redirecting to https with 301 unless we remove the Via line of squid // Apparently flickr assumes the existence of Via header field or squid keyword a sign of plain http, even if we are using https !strncasecmp(line, "Via:", 4) || @@ -2111,9 +2117,10 @@ pxy_bev_readcb(struct bufferevent *bev, void *arg) size_t child_addr_len = strlen(ctx->child_addr_str); size_t src_addr_len = strlen(ctx->src_addr_str); + size_t dst_addr_len = strlen(ctx->dst_addr_str); size_t packet_size = evbuffer_get_length(inbuf); // +2 is for \r\n - char *packet = malloc(packet_size + child_addr_len + 2 + src_addr_len + 2); + char *packet = malloc(packet_size + child_addr_len + 2 + src_addr_len + 2 + dst_addr_len + 2); if (!packet) { // @todo Should we just set enomem? ctx->enomem = 1; @@ -2128,24 +2135,39 @@ pxy_bev_readcb(struct bufferevent *bev, void *arg) log_dbg_level_printf(LOG_DBG_MODE_FINEST, ">>>>>,,,,,,,,,,,,,,,,,,,,,,, pxy_bev_readcb: src ORIG packet (size=%lu), fd=%d:\n%.*s\n", packet_size, ctx->fd, (int)packet_size, packet); - // XXX: We insert our special header line to each packet we get, right after the first \r\n, hence the target may get multiple copies - // @todo To insert our header line to the first packet only, should we look for GET/POST or Host header lines to detect the first packet? - // But there is no guarantie that they will exist, due to fragmentation - + // We insert our special header line to the first packet we get, e.g. right after the first \r\n + // @todo Should we look for GET/POST or Host header lines to detect the first packet? + // But there is no guarantie that they will exist, due to fragmentation. // @attention We cannot append the ssl proxy address at the end of the packet or in between the header and the content, // because (1) the packet may be just the first fragment split somewhere not appropriate for appending a header, - // and (2) there may not be any content + // and (2) there may not be any content. + // And we are dealing pop3 and smtp also, not just http. // @attention Cannot use string manipulation functions; we are dealing with binary arrays here, not NULL-terminated strings - char *pos = memmem(packet, packet_size, "\r\n", 2); - if (pos) { - memmove(pos + 2 + child_addr_len + 2 + src_addr_len, pos, packet_size - (pos - packet)); - memcpy(pos + 2, ctx->child_addr_str, child_addr_len); - memcpy(pos + 2 + child_addr_len, "\r\n", 2); - memcpy(pos + 2 + child_addr_len + 2, ctx->src_addr_str, src_addr_len); - packet_size+= child_addr_len + 2 + src_addr_len + 2; - } else { - log_dbg_level_printf(LOG_DBG_MODE_FINEST, ">>>>>,,,,,,,,,,,,,,,,,,,,,,, pxy_bev_readcb: No CRLF in packet\n"); + if (!ctx->sent_addr_info) { + if (ctx->spec->mail) { + memmove(packet + child_addr_len + 2 + src_addr_len + 2 + dst_addr_len + 2, packet, packet_size); + memcpy(packet, ctx->child_addr_str, child_addr_len); + memcpy(packet + child_addr_len, "\r\n", 2); + memcpy(packet + child_addr_len + 2, ctx->src_addr_str, src_addr_len); + memcpy(packet + child_addr_len + 2 + src_addr_len, "\r\n", 2); + memcpy(packet + child_addr_len + 2 + src_addr_len + 2, ctx->dst_addr_str, src_addr_len); + memcpy(packet + child_addr_len + 2 + src_addr_len + 2 + dst_addr_len, "\r\n", 2); + packet_size+= child_addr_len + 2 + src_addr_len + 2 + dst_addr_len + 2; + ctx->sent_addr_info = 1; + } else { + char *pos = memmem(packet, packet_size, "\r\n", 2); + if (pos) { + memmove(pos + 2 + child_addr_len + 2 + src_addr_len, pos, packet_size - (pos - packet)); + memcpy(pos + 2, ctx->child_addr_str, child_addr_len); + memcpy(pos + 2 + child_addr_len, "\r\n", 2); + memcpy(pos + 2 + child_addr_len + 2, ctx->src_addr_str, src_addr_len); + packet_size+= child_addr_len + 2 + src_addr_len + 2; + ctx->sent_addr_info = 1; + } else { + log_dbg_level_printf(LOG_DBG_MODE_FINEST, ">>>>>,,,,,,,,,,,,,,,,,,,,,,, pxy_bev_readcb: No CRLF in packet\n"); + } + } } if (evbuffer_add(outbuf, packet, packet_size) < 0) { @@ -2293,6 +2315,15 @@ pxy_bev_readcb_child(struct bufferevent *bev, void *arg) log_dbg_level_printf(LOG_DBG_MODE_FINEST, ">>>>>....................... pxy_bev_readcb_child: <<<<<<<<<<<<<<<<<<<<<<<<<<<<< REMOVED SSLproxy-SrcAddr\n"); } + // @todo Combine dst_addr removal with src_addr removal? + size_t dst_addr_len = strlen(parent->dst_addr_str); + pos = memmem(packet, packet_size, parent->dst_addr_str, dst_addr_len); + if (pos) { + memmove(pos, pos + dst_addr_len + 2, packet_size - (pos - packet) - (dst_addr_len + 2)); + packet_size-= dst_addr_len + 2; + log_dbg_level_printf(LOG_DBG_MODE_FINEST, ">>>>>....................... pxy_bev_readcb_child: <<<<<<<<<<<<<<<<<<<<<<<<<<<<< REMOVED SSLproxy-DstAddr\n"); + } + if (evbuffer_add(outbuf, packet, packet_size) < 0) { log_err_printf("ERROR: evbuffer_add failed\n"); } @@ -2655,8 +2686,8 @@ pxy_connected_enable(struct bufferevent *bev, pxy_conn_ctx_t *ctx, char *event_n pxy_conn_desc_t *srv_dst = &ctx->srv_dst; if (srv_dst->bev) { log_dbg_level_printf(LOG_DBG_MODE_FINER, ">>>>>=================================== pxy_connected_enable: evutil_closesocket srv_dst->bev, fd=%d\n", bufferevent_getfd(srv_dst->bev)); - // @attention Since both eventcb and writecb for srv_dst are enabled, never free srv_dst bev here. But, just close its fd. - // Otherwise, either eventcb or writecb may get a NULL srv_dst bev, causing a crash with signal 10. pxy_conn_free() will free its bev later on. + // @attention Since both eventcb and writecb for srv_dst are enabled, either eventcb or writecb may get a NULL srv_dst bev, causing a crash with signal 10. + // So, from this point on, we should check if srv_dst in NULL or not. bufferevent_free_and_close_fd(srv_dst->bev, ctx); srv_dst->bev = NULL; srv_dst->closed = 1; @@ -2731,6 +2762,15 @@ pxy_connected_enable(struct bufferevent *bev, pxy_conn_ctx_t *ctx, char *event_n } snprintf(ctx->src_addr_str, src_addr_len, "%s [%s]:%s,%s", SSLPROXY_SRCADDR_KEY, ctx->srchost_str, ctx->srcport_str, ctx->spec->ssl ? "s":"p"); + // SSLproxy-DstAddr: [192.168.3.23]:49260,s + int dst_addr_len = SSLPROXY_DSTADDR_KEY_LEN + 2 + strlen(ctx->dsthost_str) + 2 + strlen(ctx->dstport_str) + 1 + 1 + 1; + ctx->dst_addr_str = malloc(dst_addr_len); + if (!ctx->dst_addr_str) { + pxy_conn_free(ctx, 1); + return 0; + } + snprintf(ctx->dst_addr_str, dst_addr_len, "%s [%s]:%s,%s", SSLPROXY_DSTADDR_KEY, ctx->dsthost_str, ctx->dstport_str, ctx->spec->ssl ? "s":"p"); + log_dbg_level_printf(LOG_DBG_MODE_FINER, ">>>>>=================================== pxy_connected_enable: ENABLE src, child_addr= %s, fd=%d, child_fd=%d\n", ctx->child_addr_str, fd, ctx->child_fd); // Now open the gates diff --git a/pxyconn.h b/pxyconn.h index 551e452..6097b8e 100644 --- a/pxyconn.h +++ b/pxyconn.h @@ -145,6 +145,8 @@ struct pxy_conn_ctx { // SSL proxy return address: The IP:port address the children are listening to char *child_addr_str; char *src_addr_str; + char *dst_addr_str; + int sent_addr_info; // Child list of the conn pxy_conn_child_ctx_t *children;