実行を遅らせるか、パイプライン内から出る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と、2番目は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パイプからデータを受信するまで、2番目の呼び出しを何らかの方法で遅延させることができることを願っています。おそらく関数などでラップして実行できます。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で応答するので、2番目のパイプが起動することがわかりました。ただ入るべきだと思いますsocat

関連情報