pax_global_header00006660000000000000000000000064132377006740014523gustar00rootroot0000000000000052 comment=3a31f5ed42d2d8a1fc46f1be91fd693bdef2dd52 iprange-0.9.0/000077500000000000000000000000001323770067400131565ustar00rootroot00000000000000iprange-0.9.0/.travis.yml000066400000000000000000000001001323770067400152560ustar00rootroot00000000000000language: go go: - "1.8" - "1.9" script: - "go test -v" iprange-0.9.0/LICENSE000066400000000000000000000021541323770067400141650ustar00rootroot00000000000000MIT License Copyright (c) 2016 José Nieto , Arturo Vergara Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. iprange-0.9.0/README.md000066400000000000000000000020171323770067400144350ustar00rootroot00000000000000# iprange [![GoDoc](https://godoc.org/github.com/malfunkt/iprange?status.svg)](https://godoc.org/github.com/malfunkt/iprange) [![license](https://img.shields.io/github/license/mashape/apistatus.svg)]() [![Build Status](https://travis-ci.org/malfunkt/iprange.svg?branch=master)](https://travis-ci.org/malfunkt/iprange) `iprange` is a library you can use to parse IPv4 addresses from a string in the `nmap` format. It takes a string, and returns a list of `Min`-`Max` pairs, which can then be expanded and normalized automatically by the package. ## Supported Formats `iprange` supports the following formats: * `10.0.0.1` * `10.0.0.0/24` * `10.0.0.*` * `10.0.0.1-10` * `10.0.0.1, 10.0.0.5-10, 192.168.1.*, 192.168.10.0/24` ## Usage ```go package main import ( "log" "github.com/malfunkt/iprange" ) func main() { list, err := iprange.ParseList("10.0.0.1, 10.0.0.5-10, 192.168.1.*, 192.168.10.0/24") if err != nil { log.Printf("error: %s", err) } log.Printf("%+v", list) rng := list.Expand() log.Printf("%s", rng) } ``` iprange-0.9.0/funcs.go000066400000000000000000000032121323770067400146210ustar00rootroot00000000000000package iprange import ( "encoding/binary" "net" "sort" ) func streamRange(lower, upper net.IP) chan net.IP { ipchan := make(chan net.IP, 1) rangeMask := net.IP([]byte{ upper[0] - lower[0], upper[1] - lower[1], upper[2] - lower[2], upper[3] - lower[3], }) go func() { defer close(ipchan) lower32 := binary.BigEndian.Uint32([]byte(lower)) upper32 := binary.BigEndian.Uint32([]byte(upper)) diff := upper32 - lower32 if diff < 0 { panic("Lower address is actually higher than upper address.") } mask := net.IP([]byte{0, 0, 0, 0}) for { ipchan <- net.IP([]byte{ lower[0] + mask[0], lower[1] + mask[1], lower[2] + mask[2], lower[3] + mask[3], }) if mask.Equal(rangeMask) { break } for i := 3; i >= 0; i-- { if rangeMask[i] > 0 { if mask[i] < rangeMask[i] { mask[i] = mask[i] + 1 break } else { mask[i] = mask[i] % rangeMask[i] if i < 1 { break } } } } } }() return ipchan } // Expand expands an address with a mask taken from a stream func (r *AddressRange) Expand() []net.IP { ips := []net.IP{} for ip := range streamRange(r.Min, r.Max) { ips = append(ips, ip) } return ips } // Expand expands and normalizes a set of parsed target specifications func (l AddressRangeList) Expand() []net.IP { var res []net.IP for i := range l { res = append(res, l[i].Expand()...) } return normalize(res) } func normalize(src []net.IP) []net.IP { sort.Sort(asc(src)) dst := make([]net.IP, 1, len(src)) dst[0] = src[0] for i := range src { if !dst[len(dst)-1].Equal(src[i]) { dst = append(dst, src[i]) } } return dst } iprange-0.9.0/ip.y000066400000000000000000000052461323770067400137670ustar00rootroot00000000000000%{ package iprange import ( "encoding/binary" "net" "github.com/pkg/errors" ) type AddressRangeList []AddressRange type AddressRange struct { Min net.IP Max net.IP } type octetRange struct { min byte max byte } %} %union { num byte octRange octetRange addrRange AddressRange result AddressRangeList } %token num %type address target %type term octet_range %type result %% result: target { $$ = append($$, $1) iplex.(*ipLex).output = $$ } | result comma target { $$ = append($1, $3) iplex.(*ipLex).output = $$ } comma: ',' | ',' ' ' target: address '/' num { mask := net.CIDRMask(int($3), 32) min := $1.Min.Mask(mask) maxInt := binary.BigEndian.Uint32([]byte(min)) + 0xffffffff - binary.BigEndian.Uint32([]byte(mask)) maxBytes := make([]byte, 4) binary.BigEndian.PutUint32(maxBytes, maxInt) maxBytes = maxBytes[len(maxBytes)-4:] max := net.IP(maxBytes) $$ = AddressRange { Min: min.To4(), Max: max.To4(), } } | address { $$ = $1 } address: term '.' term '.' term '.' term { $$ = AddressRange { Min: net.IPv4($1.min, $3.min, $5.min, $7.min).To4(), Max: net.IPv4($1.max, $3.max, $5.max, $7.max).To4(), } } term: num { $$ = octetRange { $1, $1 } } | '*' { $$ = octetRange { 0, 255 } } | octet_range { $$ = $1 } octet_range: num '-' num { $$ = octetRange { $1, $3 } } %% // ParseList takes a list of target specifications and returns a list of ranges, // even if the list contains a single element. func ParseList(in string) (AddressRangeList, error) { lex := &ipLex{line: []byte(in)} errCode := ipParse(lex) if errCode != 0 || lex.err != nil { return nil, errors.Wrap(lex.err, "could not parse target") } return lex.output, nil } // Parse takes a single target specification and returns a range. It effectively calls ParseList // and returns the first result func Parse(in string) (*AddressRange, error) { l, err := ParseList(in) if err != nil { return nil, err } return &l[0], nil } iprange-0.9.0/iprange.go000066400000000000000000000001321323770067400151260ustar00rootroot00000000000000//go:generate -command yacc go tool yacc //go:generate yacc -p "ip" ip.y package iprange iprange-0.9.0/iprange_test.go000066400000000000000000000107261323770067400161770ustar00rootroot00000000000000package iprange import ( "net" "testing" "github.com/stretchr/testify/assert" ) func TestSimpleAddress(t *testing.T) { ipRange, err := Parse("192.168.1.1") assert.Nil(t, err) assert.Equal(t, net.IPv4(192, 168, 1, 1).To4(), ipRange.Min) assert.Equal(t, ipRange.Min, ipRange.Max) } func TestCIDRAddress(t *testing.T) { { ipRange, err := Parse("192.168.1.1/24") assert.Nil(t, err) assert.Equal(t, net.IPv4(192, 168, 1, 0).To4(), ipRange.Min) assert.Equal(t, net.IPv4(192, 168, 1, 255).To4(), ipRange.Max) } { ipRange, err := Parse("192.168.2.1/24") assert.Nil(t, err) assert.Equal(t, net.IPv4(192, 168, 2, 0).To4(), ipRange.Min) assert.Equal(t, net.IPv4(192, 168, 2, 255).To4(), ipRange.Max) out := ipRange.Expand() assert.Equal(t, int(0xffffffff-0xffffff00), len(out)-1) for i := 0; i < 256; i++ { assert.Equal(t, net.IP([]byte{192, 168, 2, byte(i)}), out[i]) } } { ipRange, err := Parse("10.1.2.3/16") assert.Nil(t, err) assert.Equal(t, net.IPv4(10, 1, 0, 0).To4(), ipRange.Min) assert.Equal(t, net.IPv4(10, 1, 255, 255).To4(), ipRange.Max) out := ipRange.Expand() assert.Equal(t, int(0xffffffff-0xffff0000), len(out)-1) for i := 0; i < 65536; i++ { assert.Equal(t, net.IP([]byte{10, 1, byte(i / 256), byte(i % 256)}), out[i]) } } { ipRange, err := Parse("10.1.2.3/32") assert.Nil(t, err) assert.Equal(t, net.IPv4(10, 1, 2, 3).To4(), ipRange.Min) assert.Equal(t, ipRange.Min, ipRange.Max) } } func TestWildcardAddress(t *testing.T) { ipRange, err := Parse("192.168.1.*") assert.Nil(t, err) assert.Equal(t, net.IPv4(192, 168, 1, 0).To4(), ipRange.Min) assert.Equal(t, net.IPv4(192, 168, 1, 255).To4(), ipRange.Max) } func TestRangeAddress(t *testing.T) { { ipRange, err := Parse("192.168.1.10-20") assert.Nil(t, err) assert.Equal(t, net.IPv4(192, 168, 1, 10).To4(), ipRange.Min) assert.Equal(t, net.IPv4(192, 168, 1, 20).To4(), ipRange.Max) } { ipRange, err := Parse("192.168.10-20.1") assert.Nil(t, err) assert.Equal(t, net.IPv4(192, 168, 10, 1).To4(), ipRange.Min) assert.Equal(t, net.IPv4(192, 168, 20, 1).To4(), ipRange.Max) } { ipRange, err := Parse("0-255.1.1.1") assert.Nil(t, err) assert.Equal(t, net.IPv4(0, 1, 1, 1).To4(), ipRange.Min) assert.Equal(t, net.IPv4(255, 1, 1, 1).To4(), ipRange.Max) } { ipRange, err := Parse("1-2.3-4.5-6.7-8") assert.Nil(t, err) assert.Equal(t, net.IPv4(1, 3, 5, 7).To4(), ipRange.Min) assert.Equal(t, net.IPv4(2, 4, 6, 8).To4(), ipRange.Max) out := ipRange.Expand() assert.Equal(t, 16, len(out)) assert.Equal(t, out, []net.IP{ net.IP([]byte{1, 3, 5, 7}), net.IP([]byte{1, 3, 5, 8}), net.IP([]byte{1, 3, 6, 7}), net.IP([]byte{1, 3, 6, 8}), net.IP([]byte{1, 4, 5, 7}), net.IP([]byte{1, 4, 5, 8}), net.IP([]byte{1, 4, 6, 7}), net.IP([]byte{1, 4, 6, 8}), net.IP([]byte{2, 3, 5, 7}), net.IP([]byte{2, 3, 5, 8}), net.IP([]byte{2, 3, 6, 7}), net.IP([]byte{2, 3, 6, 8}), net.IP([]byte{2, 4, 5, 7}), net.IP([]byte{2, 4, 5, 8}), net.IP([]byte{2, 4, 6, 7}), net.IP([]byte{2, 4, 6, 8}), }) } } func TestMixedAddress(t *testing.T) { ipRange, err := Parse("192.168.10-20.*/25") assert.Nil(t, err) assert.Equal(t, net.IPv4(192, 168, 10, 0).To4(), ipRange.Min) assert.Equal(t, net.IPv4(192, 168, 10, 127).To4(), ipRange.Max) } func TestList(t *testing.T) { rangeList, err := ParseList("192.168.1.1, 192.168.1.1/24, 192.168.1.*, 192.168.1.10-20") assert.Nil(t, err) assert.Len(t, rangeList, 4) assert.Equal(t, net.IP([]byte{192, 168, 1, 1}), rangeList[0].Min) assert.Equal(t, net.IP([]byte{192, 168, 1, 1}), rangeList[0].Max) assert.Equal(t, net.IP([]byte{192, 168, 1, 0}), rangeList[1].Min) assert.Equal(t, net.IP([]byte{192, 168, 1, 255}), rangeList[1].Max) assert.Equal(t, net.IP([]byte{192, 168, 1, 0}), rangeList[2].Min) assert.Equal(t, net.IP([]byte{192, 168, 1, 255}), rangeList[2].Max) assert.Equal(t, net.IP([]byte{192, 168, 1, 10}), rangeList[3].Min) assert.Equal(t, net.IP([]byte{192, 168, 1, 20}), rangeList[3].Max) } func TestBadAddress(t *testing.T) { ipRange, err := Parse("192.168.10") assert.Nil(t, ipRange) assert.Error(t, err) } func TestBadList(t *testing.T) { rangeList, err := ParseList("192.168.1,, 192.168.1.1/24, 192.168.1.*, 192.168.1.10-20") assert.Error(t, err) assert.Nil(t, rangeList) } func TestListExpansion(t *testing.T) { rangeList, err := ParseList("192.168.1.10, 192.168.1.1-20, 192.168.1.10/29") assert.Nil(t, err) expanded := rangeList.Expand() assert.Len(t, expanded, 20) } iprange-0.9.0/lex.go000066400000000000000000000024651323770067400143040ustar00rootroot00000000000000package iprange import ( "bytes" "errors" "log" "strconv" "unicode/utf8" ) const eof = 0 type ipLex struct { line []byte peek rune output AddressRangeList err error } func (ip *ipLex) Lex(yylval *ipSymType) int { for { c := ip.next() switch c { case eof: return eof case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': return ip.byte(c, yylval) default: return int(c) } } } func (ip *ipLex) byte(c rune, yylval *ipSymType) int { add := func(b *bytes.Buffer, c rune) { if _, err := b.WriteRune(c); err != nil { log.Fatalf("WriteRune: %s", err) } } var b bytes.Buffer add(&b, c) L: for { c = ip.next() switch c { case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': add(&b, c) default: break L } } if c != eof { ip.peek = c } octet, err := strconv.ParseUint(b.String(), 10, 32) if err != nil { log.Printf("badly formatted octet") return eof } yylval.num = byte(octet) return num } func (ip *ipLex) next() rune { if ip.peek != eof { r := ip.peek ip.peek = eof return r } if len(ip.line) == 0 { return eof } c, size := utf8.DecodeRune(ip.line) ip.line = ip.line[size:] if c == utf8.RuneError && size == 1 { log.Print("invalid utf8") return ip.next() } return c } func (ip *ipLex) Error(s string) { ip.err = errors.New(s) } iprange-0.9.0/sortip.go000066400000000000000000000006221323770067400150250ustar00rootroot00000000000000package iprange import ( "math/big" "net" ) // Asc implements sorting in ascending order for IP addresses type asc []net.IP func (a asc) Len() int { return len(a) } func (a asc) Swap(i, j int) { a[i], a[j] = a[j], a[i] } func (a asc) Less(i, j int) bool { bigi := big.NewInt(0).SetBytes(a[i]) bigj := big.NewInt(0).SetBytes(a[j]) if bigi.Cmp(bigj) == -1 { return true } return false } iprange-0.9.0/y.go000066400000000000000000000251201323770067400137550ustar00rootroot00000000000000//line ip.y:2 package iprange import __yyfmt__ "fmt" //line ip.y:3 import ( "encoding/binary" "net" "github.com/pkg/errors" ) type AddressRangeList []AddressRange type AddressRange struct { Min net.IP Max net.IP } type octetRange struct { min byte max byte } //line ip.y:26 type ipSymType struct { yys int num byte octRange octetRange addrRange AddressRange result AddressRangeList } const num = 57346 var ipToknames = [...]string{ "$end", "error", "$unk", "num", "','", "' '", "'/'", "'.'", "'*'", "'-'", } var ipStatenames = [...]string{} const ipEofCode = 1 const ipErrCode = 2 const ipInitialStackSize = 16 //line ip.y:88 // ParseList takes a list of target specifications and returns a list of ranges, // even if the list contains a single element. func ParseList(in string) (AddressRangeList, error) { lex := &ipLex{line: []byte(in)} errCode := ipParse(lex) if errCode != 0 || lex.err != nil { return nil, errors.Wrap(lex.err, "could not parse target") } return lex.output, nil } // Parse takes a single target specification and returns a range. It effectively calls ParseList // and returns the first result func Parse(in string) (*AddressRange, error) { l, err := ParseList(in) if err != nil { return nil, err } return &l[0], nil } //line yacctab:1 var ipExca = [...]int{ -1, 1, 1, -1, -2, 0, } const ipNprod = 12 const ipPrivate = 57344 var ipTokenNames []string var ipStates []string const ipLast = 22 var ipAct = [...]int{ 4, 5, 12, 20, 2, 10, 6, 18, 11, 14, 9, 17, 16, 13, 15, 8, 1, 7, 3, 19, 0, 21, } var ipPact = [...]int{ -3, 5, -1000, -2, 0, -8, -1000, -1000, -3, 3, 10, -3, 7, -1000, -1000, -1000, -1, -1000, -3, -5, -3, -1000, } var ipPgo = [...]int{ 0, 18, 4, 0, 17, 16, 15, } var ipR1 = [...]int{ 0, 5, 5, 6, 6, 2, 2, 1, 3, 3, 3, 4, } var ipR2 = [...]int{ 0, 1, 3, 1, 2, 3, 1, 7, 1, 1, 1, 3, } var ipChk = [...]int{ -1000, -5, -2, -1, -3, 4, 9, -4, -6, 5, 7, 8, 10, -2, 6, 4, -3, 4, 8, -3, 8, -3, } var ipDef = [...]int{ 0, -2, 1, 6, 0, 8, 9, 10, 0, 3, 0, 0, 0, 2, 4, 5, 0, 11, 0, 0, 0, 7, } var ipTok1 = [...]int{ 1, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 6, 3, 3, 3, 3, 3, 3, 3, 3, 3, 9, 3, 5, 10, 8, 7, } var ipTok2 = [...]int{ 2, 3, 4, } var ipTok3 = [...]int{ 0, } var ipErrorMessages = [...]struct { state int token int msg string }{} //line yaccpar:1 /* parser for yacc output */ var ( ipDebug = 0 ipErrorVerbose = false ) type ipLexer interface { Lex(lval *ipSymType) int Error(s string) } type ipParser interface { Parse(ipLexer) int Lookahead() int } type ipParserImpl struct { lval ipSymType stack [ipInitialStackSize]ipSymType char int } func (p *ipParserImpl) Lookahead() int { return p.char } func ipNewParser() ipParser { return &ipParserImpl{} } const ipFlag = -1000 func ipTokname(c int) string { if c >= 1 && c-1 < len(ipToknames) { if ipToknames[c-1] != "" { return ipToknames[c-1] } } return __yyfmt__.Sprintf("tok-%v", c) } func ipStatname(s int) string { if s >= 0 && s < len(ipStatenames) { if ipStatenames[s] != "" { return ipStatenames[s] } } return __yyfmt__.Sprintf("state-%v", s) } func ipErrorMessage(state, lookAhead int) string { const TOKSTART = 4 if !ipErrorVerbose { return "syntax error" } for _, e := range ipErrorMessages { if e.state == state && e.token == lookAhead { return "syntax error: " + e.msg } } res := "syntax error: unexpected " + ipTokname(lookAhead) // To match Bison, suggest at most four expected tokens. expected := make([]int, 0, 4) // Look for shiftable tokens. base := ipPact[state] for tok := TOKSTART; tok-1 < len(ipToknames); tok++ { if n := base + tok; n >= 0 && n < ipLast && ipChk[ipAct[n]] == tok { if len(expected) == cap(expected) { return res } expected = append(expected, tok) } } if ipDef[state] == -2 { i := 0 for ipExca[i] != -1 || ipExca[i+1] != state { i += 2 } // Look for tokens that we accept or reduce. for i += 2; ipExca[i] >= 0; i += 2 { tok := ipExca[i] if tok < TOKSTART || ipExca[i+1] == 0 { continue } if len(expected) == cap(expected) { return res } expected = append(expected, tok) } // If the default action is to accept or reduce, give up. if ipExca[i+1] != 0 { return res } } for i, tok := range expected { if i == 0 { res += ", expecting " } else { res += " or " } res += ipTokname(tok) } return res } func iplex1(lex ipLexer, lval *ipSymType) (char, token int) { token = 0 char = lex.Lex(lval) if char <= 0 { token = ipTok1[0] goto out } if char < len(ipTok1) { token = ipTok1[char] goto out } if char >= ipPrivate { if char < ipPrivate+len(ipTok2) { token = ipTok2[char-ipPrivate] goto out } } for i := 0; i < len(ipTok3); i += 2 { token = ipTok3[i+0] if token == char { token = ipTok3[i+1] goto out } } out: if token == 0 { token = ipTok2[1] /* unknown char */ } if ipDebug >= 3 { __yyfmt__.Printf("lex %s(%d)\n", ipTokname(token), uint(char)) } return char, token } func ipParse(iplex ipLexer) int { return ipNewParser().Parse(iplex) } func (iprcvr *ipParserImpl) Parse(iplex ipLexer) int { var ipn int var ipVAL ipSymType var ipDollar []ipSymType _ = ipDollar // silence set and not used ipS := iprcvr.stack[:] Nerrs := 0 /* number of errors */ Errflag := 0 /* error recovery flag */ ipstate := 0 iprcvr.char = -1 iptoken := -1 // iprcvr.char translated into internal numbering defer func() { // Make sure we report no lookahead when not parsing. ipstate = -1 iprcvr.char = -1 iptoken = -1 }() ipp := -1 goto ipstack ret0: return 0 ret1: return 1 ipstack: /* put a state and value onto the stack */ if ipDebug >= 4 { __yyfmt__.Printf("char %v in %v\n", ipTokname(iptoken), ipStatname(ipstate)) } ipp++ if ipp >= len(ipS) { nyys := make([]ipSymType, len(ipS)*2) copy(nyys, ipS) ipS = nyys } ipS[ipp] = ipVAL ipS[ipp].yys = ipstate ipnewstate: ipn = ipPact[ipstate] if ipn <= ipFlag { goto ipdefault /* simple state */ } if iprcvr.char < 0 { iprcvr.char, iptoken = iplex1(iplex, &iprcvr.lval) } ipn += iptoken if ipn < 0 || ipn >= ipLast { goto ipdefault } ipn = ipAct[ipn] if ipChk[ipn] == iptoken { /* valid shift */ iprcvr.char = -1 iptoken = -1 ipVAL = iprcvr.lval ipstate = ipn if Errflag > 0 { Errflag-- } goto ipstack } ipdefault: /* default state action */ ipn = ipDef[ipstate] if ipn == -2 { if iprcvr.char < 0 { iprcvr.char, iptoken = iplex1(iplex, &iprcvr.lval) } /* look through exception table */ xi := 0 for { if ipExca[xi+0] == -1 && ipExca[xi+1] == ipstate { break } xi += 2 } for xi += 2; ; xi += 2 { ipn = ipExca[xi+0] if ipn < 0 || ipn == iptoken { break } } ipn = ipExca[xi+1] if ipn < 0 { goto ret0 } } if ipn == 0 { /* error ... attempt to resume parsing */ switch Errflag { case 0: /* brand new error */ iplex.Error(ipErrorMessage(ipstate, iptoken)) Nerrs++ if ipDebug >= 1 { __yyfmt__.Printf("%s", ipStatname(ipstate)) __yyfmt__.Printf(" saw %s\n", ipTokname(iptoken)) } fallthrough case 1, 2: /* incompletely recovered error ... try again */ Errflag = 3 /* find a state where "error" is a legal shift action */ for ipp >= 0 { ipn = ipPact[ipS[ipp].yys] + ipErrCode if ipn >= 0 && ipn < ipLast { ipstate = ipAct[ipn] /* simulate a shift of "error" */ if ipChk[ipstate] == ipErrCode { goto ipstack } } /* the current p has no shift on "error", pop stack */ if ipDebug >= 2 { __yyfmt__.Printf("error recovery pops state %d\n", ipS[ipp].yys) } ipp-- } /* there is no state on the stack with an error shift ... abort */ goto ret1 case 3: /* no shift yet; clobber input char */ if ipDebug >= 2 { __yyfmt__.Printf("error recovery discards %s\n", ipTokname(iptoken)) } if iptoken == ipEofCode { goto ret1 } iprcvr.char = -1 iptoken = -1 goto ipnewstate /* try again in the same state */ } } /* reduction by production ipn */ if ipDebug >= 2 { __yyfmt__.Printf("reduce %v in:\n\t%v\n", ipn, ipStatname(ipstate)) } ipnt := ipn ippt := ipp _ = ippt // guard against "declared and not used" ipp -= ipR2[ipn] // ipp is now the index of $0. Perform the default action. Iff the // reduced production is ε, $1 is possibly out of range. if ipp+1 >= len(ipS) { nyys := make([]ipSymType, len(ipS)*2) copy(nyys, ipS) ipS = nyys } ipVAL = ipS[ipp+1] /* consult goto table to find next state */ ipn = ipR1[ipn] ipg := ipPgo[ipn] ipj := ipg + ipS[ipp].yys + 1 if ipj >= ipLast { ipstate = ipAct[ipg] } else { ipstate = ipAct[ipj] if ipChk[ipstate] != -ipn { ipstate = ipAct[ipg] } } // dummy call; replaced with literal code switch ipnt { case 1: ipDollar = ipS[ippt-1 : ippt+1] //line ip.y:41 { ipVAL.result = append(ipVAL.result, ipDollar[1].addrRange) iplex.(*ipLex).output = ipVAL.result } case 2: ipDollar = ipS[ippt-3 : ippt+1] //line ip.y:46 { ipVAL.result = append(ipDollar[1].result, ipDollar[3].addrRange) iplex.(*ipLex).output = ipVAL.result } case 5: ipDollar = ipS[ippt-3 : ippt+1] //line ip.y:54 { mask := net.CIDRMask(int(ipDollar[3].num), 32) min := ipDollar[1].addrRange.Min.Mask(mask) maxInt := binary.BigEndian.Uint32([]byte(min)) + 0xffffffff - binary.BigEndian.Uint32([]byte(mask)) maxBytes := make([]byte, 4) binary.BigEndian.PutUint32(maxBytes, maxInt) maxBytes = maxBytes[len(maxBytes)-4:] max := net.IP(maxBytes) ipVAL.addrRange = AddressRange{ Min: min.To4(), Max: max.To4(), } } case 6: ipDollar = ipS[ippt-1 : ippt+1] //line ip.y:70 { ipVAL.addrRange = ipDollar[1].addrRange } case 7: ipDollar = ipS[ippt-7 : ippt+1] //line ip.y:75 { ipVAL.addrRange = AddressRange{ Min: net.IPv4(ipDollar[1].octRange.min, ipDollar[3].octRange.min, ipDollar[5].octRange.min, ipDollar[7].octRange.min).To4(), Max: net.IPv4(ipDollar[1].octRange.max, ipDollar[3].octRange.max, ipDollar[5].octRange.max, ipDollar[7].octRange.max).To4(), } } case 8: ipDollar = ipS[ippt-1 : ippt+1] //line ip.y:82 { ipVAL.octRange = octetRange{ipDollar[1].num, ipDollar[1].num} } case 9: ipDollar = ipS[ippt-1 : ippt+1] //line ip.y:83 { ipVAL.octRange = octetRange{0, 255} } case 10: ipDollar = ipS[ippt-1 : ippt+1] //line ip.y:84 { ipVAL.octRange = ipDollar[1].octRange } case 11: ipDollar = ipS[ippt-3 : ippt+1] //line ip.y:86 { ipVAL.octRange = octetRange{ipDollar[1].num, ipDollar[3].num} } } goto ipstack /* stack new state and value */ } iprange-0.9.0/y.output000066400000000000000000000045531323770067400147170ustar00rootroot00000000000000 state 0 $accept: .result $end num shift 5 '*' shift 6 . error address goto 3 target goto 2 term goto 4 octet_range goto 7 result goto 1 state 1 $accept: result.$end result: result.comma target $end accept ',' shift 9 . error comma goto 8 state 2 result: target. (1) . reduce 1 (src line 40) state 3 target: address.'/' num target: address. (6) '/' shift 10 . reduce 6 (src line 69) state 4 address: term.'.' term '.' term '.' term '.' shift 11 . error state 5 term: num. (8) octet_range: num.'-' num '-' shift 12 . reduce 8 (src line 82) state 6 term: '*'. (9) . reduce 9 (src line 83) state 7 term: octet_range. (10) . reduce 10 (src line 84) state 8 result: result comma.target num shift 5 '*' shift 6 . error address goto 3 target goto 13 term goto 4 octet_range goto 7 state 9 comma: ','. (3) comma: ','.' ' ' ' shift 14 . reduce 3 (src line 51) state 10 target: address '/'.num num shift 15 . error state 11 address: term '.'.term '.' term '.' term num shift 5 '*' shift 6 . error term goto 16 octet_range goto 7 state 12 octet_range: num '-'.num num shift 17 . error state 13 result: result comma target. (2) . reduce 2 (src line 45) state 14 comma: ',' ' '. (4) . reduce 4 (src line 51) state 15 target: address '/' num. (5) . reduce 5 (src line 53) state 16 address: term '.' term.'.' term '.' term '.' shift 18 . error state 17 octet_range: num '-' num. (11) . reduce 11 (src line 86) state 18 address: term '.' term '.'.term '.' term num shift 5 '*' shift 6 . error term goto 19 octet_range goto 7 state 19 address: term '.' term '.' term.'.' term '.' shift 20 . error state 20 address: term '.' term '.' term '.'.term num shift 5 '*' shift 6 . error term goto 21 octet_range goto 7 state 21 address: term '.' term '.' term '.' term. (7) . reduce 7 (src line 74) 10 terminals, 7 nonterminals 12 grammar rules, 22/2000 states 0 shift/reduce, 0 reduce/reduce conflicts reported 56 working sets used memory: parser 15/30000 5 extra closures 19 shift entries, 1 exceptions 10 goto entries 6 entries saved by goto default Optimizer space used: output 22/30000 22 table entries, 1 zero maximum spread: 10, maximum offset: 20