コード例 #1
0
ファイル: smtpd_haproxy.c プロジェクト: Jingeun/tongsu_smtp
int     smtpd_peer_from_haproxy(SMTPD_STATE *state)
{
    const char *myname = "smtpd_peer_from_haproxy";
    MAI_HOSTADDR_STR smtp_client_addr;
    MAI_SERVPORT_STR smtp_client_port;
    MAI_HOSTADDR_STR smtp_server_addr;
    MAI_SERVPORT_STR smtp_server_port;
    const char *proxy_err;
    int     io_err;
    VSTRING *escape_buf;

    /*
     * Note: the haproxy_srvr_parse() routine performs address protocol
     * checks, address and port syntax checks, and converts IPv4-in-IPv6
     * address string syntax (:ffff::1.2.3.4) to IPv4 syntax where permitted
     * by the main.cf:inet_protocols setting, but logs no warnings.
     */
#define ENABLE_DEADLINE	1

    smtp_stream_setup(state->client, var_smtpd_uproxy_tmout, ENABLE_DEADLINE);
    switch (io_err = vstream_setjmp(state->client)) {
    default:
	msg_panic("%s: unhandled I/O error %d", myname, io_err);
    case SMTP_ERR_EOF:
	msg_warn("haproxy read: unexpected EOF");
	return (-1);
    case SMTP_ERR_TIME:
	msg_warn("haproxy read: timeout error");
	return (-1);
    case 0:
	if (smtp_get(state->buffer, state->client, HAPROXY_MAX_LEN,
		     SMTP_GET_FLAG_NONE) != '\n') {
	    msg_warn("haproxy read: line > %d characters", HAPROXY_MAX_LEN);
	    return (-1);
	}
	if ((proxy_err = haproxy_srvr_parse(STR(state->buffer),
				       &smtp_client_addr, &smtp_client_port,
			      &smtp_server_addr, &smtp_server_port)) != 0) {
	    escape_buf = vstring_alloc(HAPROXY_MAX_LEN + 2);
	    escape(escape_buf, STR(state->buffer), LEN(state->buffer));
	    msg_warn("haproxy read: %s: %s", proxy_err, STR(escape_buf));
	    vstring_free(escape_buf);
	    return (-1);
	}
	state->addr = mystrdup(smtp_client_addr.buf);
	if (strrchr(state->addr, ':') != 0) {
	    state->rfc_addr = concatenate(IPV6_COL, state->addr, (char *) 0);
	    state->addr_family = AF_INET6;
	} else {
	    state->rfc_addr = mystrdup(state->addr);
	    state->addr_family = AF_INET;
	}
	state->port = mystrdup(smtp_client_port.buf);

	/*
	 * Avoid surprises in the Dovecot authentication server.
	 */
	state->dest_addr = mystrdup(smtp_server_addr.buf);
	return (0);
    }
}
コード例 #2
0
static void psc_endpt_haproxy_event(int event, char *context)
{
    const char *myname = "psc_endpt_haproxy_event";
    PSC_HAPROXY_STATE *state = (PSC_HAPROXY_STATE *) context;
    int     status = 0;
    MAI_HOSTADDR_STR smtp_client_addr;
    MAI_SERVPORT_STR smtp_client_port;
    MAI_HOSTADDR_STR smtp_server_addr;
    MAI_SERVPORT_STR smtp_server_port;
    int     last_char = 0;
    const char *err;
    VSTRING *escape_buf;
    char    read_buf[HAPROXY_MAX_LEN];
    ssize_t read_len;
    char   *cp;

    /*
     * We must not read(2) past the <CR><LF> that terminates the haproxy
     * line. For efficiency reasons we read the entire haproxy line in one
     * read(2) call when we know that the line is unfragmented. In the rare
     * case that the line is fragmented, we fall back and read(2) it one
     * character at a time.
     */
    switch (event) {
    case EVENT_TIME:
	msg_warn("haproxy read: time limit exceeded");
	status = -1;
	break;
    case EVENT_READ:
	/* Determine the initial VSTREAM read(2) buffer size. */
	if (VSTRING_LEN(state->buffer) == 0) {
	    if ((read_len = recv(vstream_fileno(state->stream),
			      read_buf, sizeof(read_buf) - 1, MSG_PEEK)) > 0
		&& ((cp = memchr(read_buf, '\n', read_len)) != 0)) {
		read_len = cp - read_buf + 1;
	    } else {
		read_len = 1;
	    }
	    vstream_control(state->stream, VSTREAM_CTL_BUFSIZE, read_len,
			    VSTREAM_CTL_END);
	}
	/* Drain the VSTREAM buffer, otherwise this pseudo-thread will hang. */
	do {
	    if ((last_char = VSTREAM_GETC(state->stream)) == VSTREAM_EOF) {
		if (vstream_ferror(state->stream))
		    msg_warn("haproxy read: %m");
		else
		    msg_warn("haproxy read: lost connection");
		status = -1;
		break;
	    }
	    if (VSTRING_LEN(state->buffer) >= HAPROXY_MAX_LEN) {
		msg_warn("haproxy read: line too long");
		status = -1;
		break;
	    }
	    VSTRING_ADDCH(state->buffer, last_char);
	} while (vstream_peek(state->stream) > 0);
	break;
    }

    /*
     * Parse the haproxy line. Note: the haproxy_srvr_parse() routine
     * performs address protocol checks, address and port syntax checks, and
     * converts IPv4-in-IPv6 address string syntax (:ffff::1.2.3.4) to IPv4
     * syntax where permitted by the main.cf:inet_protocols setting.
     */
    if (status == 0 && last_char == '\n') {
	VSTRING_TERMINATE(state->buffer);
	if ((err = haproxy_srvr_parse(vstring_str(state->buffer),
				      &smtp_client_addr, &smtp_client_port,
			      &smtp_server_addr, &smtp_server_port)) != 0) {
	    escape_buf = vstring_alloc(HAPROXY_MAX_LEN + 2);
	    escape(escape_buf, vstring_str(state->buffer),
		   VSTRING_LEN(state->buffer));
	    msg_warn("haproxy read: %s: %s", err, vstring_str(escape_buf));
	    status = -1;
	    vstring_free(escape_buf);
	}
    }

    /*
     * Are we done yet?
     */
    if (status < 0 || last_char == '\n') {
	PSC_CLEAR_EVENT_REQUEST(vstream_fileno(state->stream),
				psc_endpt_haproxy_event, context);
	vstream_control(state->stream,
			VSTREAM_CTL_BUFSIZE, (ssize_t) VSTREAM_BUFSIZE,
			VSTREAM_CTL_END);
	state->notify(status, state->stream,
		      &smtp_client_addr, &smtp_client_port,
		      &smtp_server_addr, &smtp_server_port);
	/* Note: the stream may be closed at this point. */
	vstring_free(state->buffer);
	myfree((char *) state);
    }
}