-
Notifications
You must be signed in to change notification settings - Fork 1
/
abnf_01-spf_test.go
128 lines (113 loc) · 4.97 KB
/
abnf_01-spf_test.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
package abnf
import (
"testing"
)
func Test_ABNF_SPF(t *testing.T) {
sorted_ABNF_SPF := normalize(ABNF_SPF)
valid_ABNF,target := ABNF().Valid([ ]byte(sorted_ABNF_SPF))
if !valid_ABNF {
t.Errorf("errors found in \n---------\n%s\n---------\n", sorted_ABNF_SPF)
}
spf := ABNF().Compile(target,"record")
tested_ABNF := spf.String()
if tested_ABNF != sorted_ABNF_SPF {
t.Errorf("difference between \n---------\n%s\n---------\nand\n---------\n%s\n---------\n ", sorted_ABNF_SPF, tested_ABNF)
}
log_test := log_if_invalid(t)
log_test(spf.Valid([]byte("v=spf1")))
log_test(spf.Valid([]byte("v=spf1 +all")))
log_test(spf.Valid([]byte("v=spf1 a -all")))
log_test(spf.Valid([]byte("v=spf1 a:example.org -all")))
log_test(spf.Valid([]byte("v=spf1 mx -all")))
log_test(spf.Valid([]byte("v=spf1 mx:example.org -all")))
log_test(spf.Valid([]byte("v=spf1 mx mx:example.org -all")))
log_test(spf.Valid([]byte("v=spf1 mx/30 mx:example.org/30 -all")))
log_test(spf.Valid([]byte("v=spf1 ptr -all")))
log_test(spf.Valid([]byte("v=spf1 ip4:192.0.2.128/28 -all")))
log_test(spf.Valid([]byte("v=spf1 include:example.com include:example.net -all")))
log_test(spf.Valid([]byte("v=spf1 mx include:mobile-users._spf.%{d} include:remote-users._spf.%{d} -all")))
log_test(spf.Valid([]byte("v=spf1 exists:%{ir}.%{l1r+}.%{d}")))
}
func log_if_invalid(t *testing.T) func(bool,Target){
return func(valid bool, tree Target) {
if !valid {
t.Errorf("valid SPF is not valid !")
for _,c := range tree.Childs {
t.Logf("[%s]\n", c.String())
}
t.Logf("--[%s]--\n", string(tree.Value))
} else {
tgt := tree.Drop("sp").Merge("","macro-literal","digit","alpha","qnum")
for _,c := range tgt.Childs {
t.Logf("[%s]\n", c.String())
}
}
}
}
//domain-spec = macro-string domain-end
//domain-end = ("." toplabel [ "." ]) / macro-expand
var ABNF_SPF string = `record = Version Terms *sp
version = "v=spf1"
terms = *(1*sp (Directive / Modifier))
directive = [ qualifier ] Mechanism
qualifier = "+" / "-" / "?" / "~"
mechanism = (Include / A / All / MX / PTR / IP4 / IP6 / Exists)
all = "all"
include = "include" ":" Domain-spec
A = "a" [ ":" Domain-spec ] [ dual-cidr-length ]
MX = "mx" [ ":" Domain-spec ] [ dual-cidr-length ]
PTR = "ptr" [ ":" Domain-spec ]
IP4 = "ip4" ":" Ip4-network [ ip4-cidr-length ]
IP6 = "ip6" ":" Ip6-network [ ip6-cidr-length ]
exists = "exists" ":" Domain-spec
modifier = Redirect / Explanation / unknown-modifier
redirect = "redirect" "=" Domain-spec
explanation = "exp" "=" Domain-spec
unknown-modifier = name "=" macro-string
ip4-cidr-length = "/" 1*digit
ip6-cidr-length = "/" 1*digit
dual-cidr-length = [ ip4-cidr-length ] [ "/" ip6-cidr-length ]
ip4-network = qnum "." qnum "." qnum "." qnum
qnum = digit / %x31-39 digit / "1" 2digit / "2" %x30-34 digit / "25" %x30-35
ip6-network = 6(h16 ":") ls32 / "::" 5(h16 ":") ls32 / [ h16 ] "::" 4(h16 ":") ls32 / [ *1(h16 ":") h16 ] "::" 3(h16 ":") ls32 / [ *2(h16 ":") h16 ] "::" 2(h16 ":") ls32 / [ *3(h16 ":") h16 ] "::" h16 ":" ls32 / [ *4(h16 ":") h16 ] "::" ls32 / [ *5(h16 ":") h16 ] "::" h16 / [ *6(h16 ":") h16 ] "::"
h16 = 1*4hexdig
ls32 = (h16 ":" h16) / ip4-network
domain-spec = macro-string *("." macro-string) [ "." ]
toplabel = (*alphanum alpha *alphanum) / (1*alphanum "-" *(alphanum / "-") alphanum)
alphanum = alpha / digit
explain-string = *(macro-string / sp)
macro-string = *(macro-expand / macro-literal)
macro-expand = ("%{" macro-letter transformers *delimiter "}") / "%%" / "%_" / "%-"
macro-literal = %x21-24 / %x26-7E
macro-letter = "s" / "l" / "o" / "d" / "i" / "p" / "h" / "c" / "r" / "t"
transformers = *digit [ "r" ]
delimiter = "." / "-" / "+" / "," / "/" / "_" / "="
name = alpha *(alpha / digit / "-" / "_" / ".")
header-field = "Received-SPF:" [ cfws ] result fws [ comment fws ] [ key-value-list ] crlf
result = "Pass" / "Fail" / "SoftFail" / "Neutral" / "None" / "TempError" / "PermError"
key-value-list = key-value-pair *(";" [ cfws ] key-value-pair) [ ";" ]
key-value-pair = key [ cfws ] "=" (dot-atom / quoted-string)
key = "client-ip" / "envelope-from" / "helo" / "problem" / "receiver" / "identity" / mechanism / "x-" name / name
identity = "mailfrom" / "helo" / name
alpha = %x41-5A / %x61-7A
digit = %x30-39
lf = %x0A
cr = %x0D
crlf = cr lf
sp = %x20 / %x09
hexdig = digit / "A" / "B" / "C" / "D" / "E" / "F"
fws = ([ *sp crlf ] 1*sp) / obs-fws
obs-fws = 1*sp *(crlf 1*sp)
ctext = no-ws-ctl / %x21-27 / %x2A-5B / %x5D-7E
ccontent = ctext / quoted-pair / comment
comment = "(" *([ fws ] ccontent) [ fws ] ")"
cfws = *([ fws ] comment) (([ fws ] comment) / fws)
quoted-pair = ("\" text) / obs-qp
obs-qp = "\" (%x00-7F)
no-ws-ctl = %x01-08 / %x0B / %x0C / %x0E-1F / %x7F
quoted-string = [ cfws ] DQUOTE *([ fws ] qcontent) [ fws ] DQUOTE [ cfws ]
qtext = no-ws-ctl / %x21 / %x23-5B / %x5D-7E
qcontent = qtext / quoted-pair
dot-atom = [ cfws ] dot-atom-text [ cfws ]
dot-atom-text = 1*atext *("." 1*atext)
atext = alpha / digit / "!" / "#" / "$" / "%" / "&" / "'" / "*" / "+" / "-" / "/" / "=" / "?" / "^" / "_" / %x60 / "{" / "|" / "}" / "~"`