이것이 맞는지 잘 모르겠습니다.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
.