Subject: Problem with RFC 4408

From: [email-masked]
Date: Wed, 15 Jul 2015 13:54:32 -0400

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 ?

---

From: Scott Kitterman <[email-masked]>
Date: Wed, 15 Jul 2015 14:08:16 -0400

On July 15, 2015 1:54:32 PM EDT, [email-masked] wrote:
>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. 

I would recommend using RFC 7208 instead.  There were some ABNF changes made, so maybe that will help and even if it doesn't, you'll be working off the current version.

Scott K