실행을 지연하거나 파이프라인 내에서 나가는 netcat 연결을 연기할 수 있습니까?

실행을 지연하거나 파이프라인 내에서 나가는 netcat 연결을 연기할 수 있습니까?

이것이 맞는지 잘 모르겠습니다.XY 문제, 하지만 최신 메일 서버와 제대로 통신하지 못하는 끔찍한 소프트웨어를 지원해야 합니다. SMTP만 수행할 수 있으며 AUTH ...릴레이 서버가 이를 제공하지 않거나 요구하지 않더라도 프로토콜의 별도 필드에 있더라도 사용자 이름을 기반으로 보낸 사람 주소를 설정하면 단순히 연결이 끊어집니다. 250-AUTH PLAIN ...서버 에서 입력하지 않은 경우 올바른 응답입니다 EHLO. 온라인에는 이 소프트웨어에 대해 해결되지 않은 불만 사항이 많이 있으므로 해당 공급업체가 아무런 도움도 되지 않을 것이라는 것을 알고 있습니다. SMTP 서버(Postfix)에 sasl 인증을 추가하려고 시도했지만 성공하지 못했습니다. 자격 증명을 검증할 수 없으며 relayhost이를 거부하는 사람에게 자격 증명이 전달될까 봐 걱정됩니다. 또한 보낸 자격 증명을 무시하도록 Postfix에 지시하는 방법도 찾을 수 없습니다.

이러한 모든 문제를 시도하고 해결하기 위해 자체 포트에서 수신 대기하고 SMTP 트래픽을 프록시하여 프로세스에서 일부 임의 자격 증명의 유효성을 검사하는 기본 스크립트를 작성했습니다.

#!/bin/bash

user=<<REDACTED from>>
pw=<<REDACTED password>>

function reset {
    send_auth=1
    authing=0
    ok=1
    p=/tmp/smtp_backpipe
    if [[ -p $p ]]; then
        # drain pipe
        dd if=$p iflag=nonblock of=/dev/null 2>/dev/null
    else
        mkfifo $p
    fi
}

function pw_check {
    if [[ "${1%%[[:space:]]}" == "${auth%%[[:space:]]}" ]]; then
        echo 235 2.7.0 Authentication successful > $p
    else
        echo 535 5.7.0 Authentication failed > $p
        ok=0
    fi
}

function changeo {
    while (( ok )) && IFS= read -r line; do
        case $1 in
            in)
                if (( authing )); then
                    >&2 printf '%s\n' "$line"
                    pw_check "$line"
                    authing=0
                elif [[ "$line" =~ ^AUTH[[:space:]]+PLAIN([[:space:]]+([^[:space:]]+))?[[:space:]]*$ ]]; then
                    if [[ "${BASH_REMATCH[1]}" ]]; then
                        >&2 printf '%s\n' "$line"
                        pw_check "${BASH_REMATCH[2]}"
                    else
                        authing=1
                        echo 334 | tee -a /dev/stderr > $p
                    fi
                else
                    printf '%s\n' "$line"
                fi
                ;;
            out)
                if [[ ! "$line" =~ ^250[^[:alpha:]]+AUTH[[:space:]] ]]; then
                    printf '%s\n' "$line"
                    if (( send_auth )) && [[ "$line" =~ ^250[^[:alpha:]] ]]; then
                        send_auth=0
                        echo 250-AUTH PLAIN
                    fi
                fi
                ;;
        esac
        if ! (( ok )); then
            exit 1
        fi
    done
}

auth="`printf '\0%s\0%s' "$user" "$pw" | base64`"
i=0
while true; do
    >&2 echo "$(( ++i ))"
    reset
    cat $p | tee -a /dev/stderr | netcat -4Clp $1 | changeo in | tee -a /dev/stderr | nc -4C 127.0.0.1 25 | changeo out > $p
done

실행해 ./smtp_proxy 9025보니 두 번째가 nc즉시 실제 SMTP 서버에 연결되어 시간 초과되는 트랜잭션을 시작한다는 점을 제외하고는 잘 작동합니다.

$ ./smtp_proxy 9025
1
220 <<REDACTED host>> ESMTP Postfix
EHLO [10.0.0.99]
250-<<REDACTED host>>
250-AUTH PLAIN
250-PIPELINING
250-SIZE 10240000
250-VRFY
250-ETRN
250-ENHANCEDSTATUSCODES
250-8BITMIME
250-DSN
250-SMTPUTF8
250 CHUNKING
AUTH PLAIN <<REDACTED auth>>
235 2.7.0 Authentication successful
MAIL FROM:<<<REDACTED from>>>
250 2.1.0 Ok
RCPT TO:<<<REDACTED to>>>
250 2.1.5 Ok
DATA
354 End data with <CR><LF>.<CR><LF>
From: <<REDACTED from>>
Subject: hi
To: <<REDACTED to>>
Content-Type: text/plain; charset=windows-1252; format=flowed
Content-Transfer-Encoding: 7bit

there
.
250 2.0.0 Ok: queued as F23DFE0A1B
QUIT
221 2.0.0 Bye
2
220 <<REDACTED host>> ESMTP Postfix
421 4.4.2 <<REDACTED host>> Error: timeout exceeded

nc파이프에서 데이터를 수신할 때까지 두 번째 호출을 어떻게든 지연시킬 수 있기를 바라고 있습니다 . 아마도 함수 등으로 래핑하여 수행할 수 있을 것입니다. socat수정되지 않은 연결에서 이 작업을 수행하는 것 같습니다.

socat -v tcp4-l:9025,crlf tcp4:127.0.0.1:25,crlf

...하지만 스트림을 파이프에 넣어 수정하려고 하면 nc즉시 SMTP 서버에 연결하는 것과 동일한 작업이 수행됩니다. ( nc위의 s를 각각 socat TCP4-LISTEN:$1,crlf -및 로 바꾸십시오 socat - TCP4:127.0.0.1:25,crlf.)

답변1

@muru에 연결된 답변 중 일부와 read입력이 개행으로 끝나지 않을 때 false 반환을 극복하는 것에 대한 보다 일반적인 답변을 바탕으로 입력이 수신될 때까지 프로그램 시작을 실제로 지연시키는 함수를 생각해냈습니다.

function until_input {
    >&2 echo waiting for input # debug only, remove this line
    local line
    local nl=0
    local format='%s'
    while IFS= read -r line; do
        nl=1
        format='%s\n'
        break
    done
    >&2 echo done waiting # debug only, remove this line
    if (( nl )) || [[ "$line" ]]; then
        >&2 echo was input # debug only, remove this line
        { printf "$format" "$line"; cat; } | "$@"
    fi
}

작동하는지 확인하려면 다음 테스트를 참조하세요. 이 테스트는 초기 명령문 그룹을 보여주고 until_input예상대로 병렬로 시작되지만 지연된 작업(여기서는 cat)은 입력이 시작된 후에야 시작됩니다.

{ echo wait >&2; sleep 2; echo go >&2; echo -n pipe$'\n'it baby; } | until_input cat

이것이 입력을 기다리는 일반적인 문제에 대한 좋은 해결책처럼 보이지만 불행히도 내 문제는 해결되지 않았습니다. 나는 until_input nc -4C 127.0.0.1 25파이프를 넣고 netcat누군가가 첫 번째 파이프에 연결하자마자 행이 전송되기 전에 서버가 SMTP에서 먼저 응답하기 때문에 두 번째 파이프가 시작된다는 것을 알았습니다. 그냥 들어가야 할 것 같아요 socat.

관련 정보