Iam currently trying to implement a parser for spf . to achive this I took the
grammar defined in RFC 4408 and added some parts of RFC 2234 and RFC2822. I use
aparse 2.5 to build my parser. I used the following grammar.
record = version terms *SP ;
version = "v=spf1" ;
terms = *( 1*SP ( directive / modifier ) ) ;
directive = [ qualifier ] mechanism ;
qualifier = "+" / "-" / "?" / "~" ;
mechanism = ( all / include / A / 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 = "<as per [RFC 3513], section 2.2>" ;
domain-spec = macro-string domain-end ;
domain-end = ( "." toplabel [ "." ] ) / macro-expand ;
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 ;
BIT = "0" / "1" ;
CHAR = %x01-7F ;
CR = %x0D ;
CRLF = CR LF ;
CTL = %x00-1F / %x7F ;
DIGIT = %x30-39 ;
DQUOTE = %x22 ;
HEXDIG = DIGIT / "A" / "B" / "C" / "D" / "E" / "F" ;
HTAB = %x09 ;
LF = %x0A ;
LWSP = *(WSP / CRLF WSP) ;
OCTET = %x00-FF ;
SP = %x20 ;
VCHAR = %x21-7E ;
WSP = SP / HTAB ;
NO-WS-CTL = %d1-8 / %d11 / %d12 / %d14-31 / %d127 ;
text = %d1-9 / %d11 / %d12 / %d14-127 / obs-text ;
specials = "(" / ")" / "<" / ">" / "[" / "]" / ":" / ";" / "@" /
"\" / "," / "." / DQUOTE ;
quoted-pair = ("\" text) / obs-qp ;
FWS = ([*WSP CRLF] 1*WSP) / obs-FWS ;
ctext = NO-WS-CTL / %d33-39 / %d42-91 / %d93-126 ;
ccontent = ctext / quoted-pair / comment ;
comment = "(" *([FWS] ccontent) [FWS] ")" ;
CFWS = *([FWS] comment) (([FWS] comment) / FWS) ;
atext = ALPHA / DIGIT / "!" / "#" / "$" / "%" / "&" / "'" /
"*" / "+" / "-" / "/" / "=" / "?" / "^" / "_" / "`" / "{" / "|" / "}" / "~" ;
atom = [CFWS] 1*atext [CFWS] ;
dot-atom = [CFWS] dot-atom-text [CFWS] ;
dot-atom-text = 1*atext *("." 1*atext) ;
qtext = NO-WS-CTL / %d33 / %d35-91 / %d93-126 ;
qcontent = qtext / quoted-pair ;
quoted-string = [CFWS] DQUOTE *([FWS] qcontent) [FWS] DQUOTE [CFWS] ;
obs-FWS = 1*WSP *(CRLF 1*WSP) ;
obs-qp = "\" (%d0-127) ;
obs-text = *LF *CR *(obs-char *LF *CR) ;
obs-char = %d0-9 / %d11 / %d12 / %d14-127 ;
I know that my grammer is incomplete and not able to parse ip6 mechanisms., but
the RFC3513 dose not contain any grammar at all.
But the following string
v=spf1 mx mx:example.org -all
should be parseable with the given grammar.
The parser generated with aparse dose not seem to recognize the end of the
domain.
Is this a Problem with the grammer or the parser generator ?
If this is a generator problem can anybody recomend a alternative to aparse ?