unexpected reply "/" in initial handshake
Hello,
Postfix 3.0.2 returns the following when running pypolicyd-spf 1.3.1:
> ... postfix/
> ... postfix/
The configuration is as follows.
master.cf:
policy-spf unix - n n - 0 spawn
user=nobody argv=/opt/
main.cf:
policy-
spf_milter = unix:private/
smtpd_milters = ${spf_milter}, [...]
policyd-spf.conf:
# Do not reject, just write the header.
#
defaultSeedOnly = 0
Lookup_Time = 20
Void_Limit = 2
Header_Type = AR
No_Mail = False
TempError_Defer = True
PermError_reject = False
HELO_reject = False
Mail_From_reject = False
skip_addresses = 127.0.0.
Whitelist =
Domain_Whitelist =
Domain_
Reject_
debugLevel = 5
Available for testing. Thank you for what you can do.
Question information
- Language:
- English Edit question
- Status:
- Solved
- Assignee:
- No assignee Edit question
- Solved by:
- )-:-(
- Solved:
- Last query:
- Last reply:
Related bugs
Related FAQ:
None Link to a FAQ
Revision history for this message
|
#1 |
pypolicyd-spf isn't a milter, it's a policy server, so you've got it set up all wrong. see the installed documentation, man policyd-spf, for information on how to correctly integrate it with Postfix.
Revision history for this message
|
#2 |
pypolicyd-spf isn't a milter, it's a policy server, so you've got it set up all wrong. see the installed documentation, man policyd-spf, for information on how to correctly integrate it with Postfix.
Revision history for this message
|
#3 |
This is the new configuration, using the official instructions:
Both master.cf and policyd-spf.conf are as above.
master.cf:
policy-spf unix - n n - 0 spawn
user=nobody argv=/opt/
main.cf (relevant part of):
#spf_milter = unix:private/
#smtpd_milters = ${spf_milter}, [...]
smtpd_relay_
permit_
permit_
reject_
smtpd_recipient
reject_
reject_
warn_if_reject check_policy_
policy-
policyd-spf.conf:
# Do not reject, just write the header.
#
defaultSeedOnly = 0
Lookup_Time = 20
Void_Limit = 2
Header_Type = AR
No_Mail = False
TempError_Defer = True
PermError_reject = False
HELO_reject = False
Mail_From_reject = False
skip_addresses = 127.0.0.
Whitelist =
Domain_Whitelist =
Domain_
Reject_
debugLevel = 5
The result is a 451 error:
> [...] postfix/
> [...] postfix/
Despite the "debugLevel = 5", the logs are clear of relevant details.
PS. Most of the links on "http://
Revision history for this message
|
#4 |
Since it doesn't show anything in the logs for the policy service, that means it never gets started. Here are a suggestion on the next step to troubleshoot:
Try running the policy server by hand:
/opt/python/
If you get no response to that hit enter and you should see a dunno reply. If you get that, then permissions and paths are correct and you can then use control-c to terminate it. If you get an error, then that's your problem and you'll need to trouble shoot that.
Let me know how that goes.
Revision history for this message
|
#5 |
>/opt/python/
action=dunno
Yes, it works.
Revision history for this message
|
#6 |
OK. Next thing I would try is:
Change your /etc/policyd-
defaultSeedOnly = 1
That will make it so it only logs results and never rejects any mail.
Then remove warn_if_reject from smtpd_recipient
The reload postfix and see what happens. Check the logs right after the reload for any unused parameter warnings.
Revision history for this message
|
#7 |
looking better...
postfix/
postfix/
postfix/
postfix/
Revision history for this message
|
#8 |
Do you have the python authres module installed? You need that for header type AR. If not, I think installing that will solve it.
Revision history for this message
|
#9 |
I have the whole python bloatware installed, including py3dns, PyYAML, authres and pyspf, summing to 110 MB of stuff I would rather *not* have on a production server. All this, just to get an up-to-date "Authentication
>ls -l /opt/python/
total 192
-rw-rw-r-- 1 root wheel 8678 Mar 10 03:19 __init__.py
-rw-rw-r-- 1 root wheel 1116 Mar 10 02:57 __main__.py
drwxr-xr-x 11 root wheel 374 Aug 3 00:00 __pycache__
-rw-rw-r-- 1 root wheel 32178 Mar 10 02:57 core.py
-rw-rw-r-- 1 root wheel 1961 Mar 10 02:58 dkim_adsp.py
-rw-rw-r-- 1 root wheel 2896 Mar 10 02:57 dkim_b.py
-rw-rw-r-- 1 root wheel 2001 Mar 10 02:58 dmarc.py
-rw-rw-r-- 1 root wheel 1999 Mar 10 03:34 rrvs.py
-rw-rw-r-- 1 root wheel 3742 Mar 10 02:57 smime.py
-rw-rw-r-- 1 root wheel 23498 Mar 10 03:35 tests
-rw-rw-r-- 1 root wheel 2307 Mar 10 02:57 vbr.py
I also have
Revision history for this message
|
#10 |
OK. You didn't say what OS you're using. I'm guessing one of the BSDs and I'm not that familiar with Python layouts on those systems. I am wondering (and I freely admit it's a guess) if it's just not seeing the module then.
If you open a python3 interpreter (python3 in your shell) then then try:
import sys
print(sys.path)
Is /opt/python/
Revision history for this message
|
#11 |
>Is /opt/python/
Yes.
Revision history for this message
|
#12 |
OK. Let's try and get some more information about what's going on in the policy server.
Go back and start the policy server by hand (where you got the dunno) and do that again. After you hit enter and it replies dunno (to verify it's running), paste this (including a blank line at the end):
request=
client_
helo_name=
<email address hidden>
<email address hidden>
Let me know both what's the reply in the terminal and what's in your mail log.
Revision history for this message
|
#13 |
It says:
action=prepend
The log says:
Aug 12 18:34:24 localhost postfix/
Aug 12 18:34:24 localhost postfix/
Revision history for this message
|
#14 |
The log is also saying the following when sending mail from own addresses to own addresses (port 465):
Aug 12 18:46:01 localhost postfix/
Aug 12 18:46:01 localhost postfix/
Aug 12 18:46:01 localhost postfix/
Aug 12 18:46:01 localhost postfix/
Revision history for this message
|
#15 |
Incidentally, pypolicyd-spf should *not* run for port 465.
Revision history for this message
|
#16 |
The way you avoid port 465 is to do per service recipient restrictions in master.cf instead of globally in main.cf.
There should be significantly more information in the mail log. For some reason, I don't think your python syslog module is working correctly, but I've no idea how to troubleshoot that.
It should have the content of the AR header after prepend, so that's definitely a problem. Comment out the Header_Type entry in the config file and then try the copy/paste again from the command line. It should give you a traditional Received SPF header field. If that works, then we've narrowed it down a bit.
Revision history for this message
|
#17 |
Gotcha!
action=prepend Received-SPF: Pass (sender SPF authorized) identity=mailfrom; client-
Revision history for this message
|
#18 |
This is the resulting header in an administrative message from google:
Received-Spf: Temperror (SPF Temporary Error: DNS No working name servers discovered) identity=mailfrom; client-
I have unbound on 127.0.0.1:53 and "nameserver 127.0.0.1" on /etc/resolv.conf.
Revision history for this message
|
#19 |
What version of py3dns do you have installed? I would expect the python DNS module to either work always or never, so I suspect the temperror is something external to the python stack.
Revision history for this message
|
#20 |
Also, I can replicate the bare prepend problem here, so that's a bug related to this specific configuration.
If the reason you want the SPF result header is to feed it into opendmarc for DMARC processing, opendmarc will process SPF-Received as well as AR, so you can leave it for now.
Revision history for this message
|
#21 |
Figured it out.
Your config is missing the Authserv_Id parameter. This is mandatory for AR header fields. My bad for having no error message for this. See man 5 policyd-spf.conf for info on the format. Also RFC 7001.
Revision history for this message
|
#22 |
I am happy to confirm that the header appears in the mail.
However, failure with the DNS makes it useless.
I have pydns 3.1.0, and its tests are OK.
The above manual test on pypolicyd-spf shows that the DNS is working.
However, live headers fail.
Authentication-
Revision history for this message
|
#23 |
This is the log:
... postfix/
policy_
name=
max_idle=300 max_ttl=1000 request_limit=0 retry_delay=1 timeout=100 try_limit=2
... postfix/
... postfix/
... postfix/
... postfix/
... postfix/
prepend Authentication-
(SPF Temporary Error: DNS No working name servers discovered) smtp.mailfrom=... <------
(
... postfix/
... postfix/
unix:
spf=temperror (SPF Temporary Error: DNS No working name servers discovered) <------
smtp.
Revision history for this message
|
#24 |
The DNS is a well configured, reliable, and performant unbound on 127.0.0.1:53.
Many other local clients use it without any problem.
I suspect the temperror is something either in py3dns or its call from pypolicyd-spf.
Revision history for this message
|
#25 |
What pyspf version do you have?
It'll probably be tomorrow before I can work on this much, but I will keep helping you work through it.
Revision history for this message
|
#27 |
What are the permissions on /etc/resolv.conf? Can user nobody open the file for reading?
You might also try running this script:
#! /usr/bin/python3
resolv_
lines = []
with open(resolv_path, 'r') as stream:
for line in stream:
print(line)
print(lines)
for line in lines:
line = line.strip()
if not line or line[0]==';' or line[0]=='#':
continue
fields=
if len(fields) < 2:
continue
if fields[0]=='domain' and len(fields) > 1:
if fields[
pass
if fields[
pass
if fields[
pass
if fields[
This is essentially the py3dns DNS nameserver discovery code extracted into a script. It should echo your /etc/resolv.conf line by line, then show its contents in a python list, and then finally print out the IP address of the discovered name server like this (run on my Debian box):
# Dynamic resolv.conf(5) file for glibc resolver(3) generated by resolvconf(8)
# DO NOT EDIT THIS FILE BY HAND -- YOUR CHANGES WILL BE OVERWRITTEN
nameserver 127.0.0.1
['# Dynamic resolv.conf(5) file for glibc resolver(3) generated by resolvconf(8)\n', '# DO NOT EDIT THIS FILE BY HAND -- YOUR CHANGES WILL BE OVERWRITTEN\n', 'nameserver 127.0.0.1\n']
127.0.0.1
Revision history for this message
|
#28 |
>ls -l /etc/resolv.conf
-rw-r--r-- 1 root daemon 21 Aug 8 23:57 /etc/resolv.conf
>./py3dns-test.py
nameserver 127.0.0.1
['nameserver 127.0.0.1\n']
127.0.0.1
>
Revision history for this message
|
#29 |
If you were on Linux, at this point I'd be asking you if you were running SELinux or apparmor since it seems like there's some kind of context dependent access restriction that's making it impossible for the python DNS module to read /etc/resolv.conf. There isn't some BSD equivalent access restriction technology you're using is there?
It seems like the code does what it's supposed to, but can't get the information in some cases.
Revision history for this message
|
#30 |
> If you were on Linux, at this point I'd be asking you if you were running SELinux or apparmor
No no, this is a BSD system.
> since it seems like there's some kind of context dependent access restriction that's making
> it impossible for the python DNS module to read /etc/resolv.conf.
You lost me here. The above py3dns test is reading /etc/resolv.conf after all.
> There isn't some BSD equivalent access restriction technology you're using is there?
>
> It seems like the code does what it's supposed to, but can't get the information in some cases.
The same DNS is filtering away a short list of addresses that are known to inject advertisements
in web pages. However, I can ping the IP addresses of our tests above, so I must be something else.
Since py3dns is working, then the problem is uphill.
Anyway, pypolicy-spf is working per-se, and I do not want to take your time for side-bugs.
Thanks a lot, and happy holiday!