package asaModels import ( "fmt" "regexp" "strings" "bytes" "github.rackspace.com/gorax/tools/util" ) var ( // Original: OBJGRPRE = regexp.MustCompile(`(?i)(o|)bject-group\s+(icmp.*?|network|service)\s+(.*?)\n(.|\n)*?(\n\w|$)`) OBJGRPRE = regexp.MustCompile(`(?i)object-group\s(icmp-type|service|network)\s(\S+)(\s\S+|)(?:.|\n\s)*`) /* (?i)object-group object-group \s space (icmp-type|service|network) type \s space (\S+) name (\s\S+|) protocol or none (?:.|\n\s)* Non-matching group, match any character or a new-line with a space after it, repeat */ DESCRE = regexp.MustCompile(`(?i)description\s+(.*?)(\n|$)`) OBJGRPTYPERE = regexp.MustCompile(`(group-object|network-object)\s+(.*?)(\n|$)`) ICMPOBJRE = regexp.MustCompile(`(icmp-object)\s+(.*?)(\n|$)`) PORTOBJRE = regexp.MustCompile(`(?i)port-object\s((eq|lt|gt|neg)\s\S+|range\s\S+\s\S+)`) GROUPOBJRE = regexp.MustCompile(`(?i)(group-object)\s(\S+)`) KEYVALRE = regexp.MustCompile(`(\S+)\s+(\S+)`) SERVICEPROTORE = regexp.MustCompile(`(?i)service-object\s(tcp-udp|tcp|udp|icmp)`) SERVICESRCRE = regexp.MustCompile(`(?i)source\s(?:(eq|gt|lt|neg)\s(\S+)|(range)\s(\S+\s\S+))`) SERVICEDSTRE = regexp.MustCompile(`(?i)destination\s(?:(eq|gt|lt|neg)\s(\S+)|(range)\s(\S+\s\S+))`) SERVICEICMPRE = regexp.MustCompile(`(?i)icmp\s+(\S+)`) ) type ( // ObjectGroups is a structure for containing all object-group types ObjectGroups struct { Icmp []*IcmpObjGroup `json:"icmp"` Network []*NetworkObjGroup `json:"network"` Service []*ServiceObjGroup `json:"service"` } // IcmpObjGroup is a structure for object-group icmp groups IcmpObjGroup struct { Name *string `json:"name"` Desc *string `json:"description"` IcmpObj []*IcmpObj `json:"object"` } IcmpObj struct { Type *string `json:"type"` Name *string `json:"name"` } // NetworkObjGroup is a structure for object-group network groups NetworkObjGroup struct { Name *string `json:"name"` Desc *string `json:"description"` NetworkObj []*NetworkObj `json:"object"` } // ServiceObjGroup is a structure for object-group service groups ServiceObjGroup struct { Name *string `json:"name"` Desc *string `json:"description"` Proto *string `json:"protocol"` ServiceObj []*ServiceObj `json:"object"` } // NetworkObj is a structure for object-group network members NetworkObj struct { Type string `json:"type"` Network *string `json:"network"` Mask *string `json:"netmask"` Name *string `json:"name"` } // ServiceObj is a structure for object-group service members ServiceObj struct { Type string `json:"type"` Name string `json:"name,omitempty"` MatchType string `json:"match_type,omitempty"` MatchItem string `json:"match_item,omitempty"` Proto string `json:"protocol,omitempty"` SourceType string `json:"source_type,omitempty"` SourceItem string `json:"source_item,omitempty"` DestType string `json:"dest_type,omitempty"` DestItem string `json:"dest_item,omitempty"` } ) func (n NetworkObj) String() string { if n.Type == "group-object" { return fmt.Sprintf("%s %s", n.Type, *n.Name) } var out bytes.Buffer out.WriteString(n.Type) if n.Network != nil { out.WriteString(" " + *n.Network) } if n.Mask != nil { out.WriteString(" " + *n.Mask) } return out.String() } func ParseObjectGroups(s string) *ObjectGroups { og := new(ObjectGroups) og.Parse(s) return og } // IsEmpty returns true if there are no object-groups in memory func (o *ObjectGroups) IsEmpty() bool { if len(o.Network) == 0 && len(o.Icmp) == 0 && len(o.Service) == 0 { return true } return false } // Exists checks if an object-group exists with the given type (t) and name (n) func (o *ObjectGroups) Exists(t string, n string) bool { // var og asaModels.ObjectGroups // a.Config.ObjectGroups = og // a.GetObjectGroups() switch t { case "network": for _, objectGroup := range o.Network { if *objectGroup.Name == n { return true } } case "icmp": for _, objectGroup := range o.Icmp { if *objectGroup.Name == n { return true } } case "service": for _, objectGroup := range o.Service { if *objectGroup.Name == n { return true } } } return false } // IsEmpty returns true if the network object is empty func (o *NetworkObjGroup) IsEmpty() bool { if len(o.NetworkObj) == 0 { return true } return false } // IsEmpty returns true if the service object is empty func (o *ServiceObjGroup) IsEmpty() bool { if len(o.ServiceObj) == 0 { return true } return false } // IsEmpty returns true if the icmp object is empty func (o *IcmpObjGroup) IsEmpty() bool { if len(o.IcmpObj) == 0 { return true } return false } // Parse steps through the object groups and calls the correct parser func (o *ObjectGroups) Parse(s string) { for _, v := range OBJGRPRE.FindAllStringSubmatch(s, -1) { switch v[1] { case "network": o.NetParse(v[0], &v[2]) case "icmp-type": o.IcmpParse(v[0], &v[2]) case "service": if v[3] != "" { p := strings.TrimSpace(v[3]) o.ServiceParse(v[0], &v[2], &p) } else { o.ServiceParse(v[0], &v[2], nil) } } } } // NetParse parses an 'object-group network' in to the proper structure. func (o *ObjectGroups) NetParse(raw string, name *string) { var n NetworkObjGroup n.Name = name n.Desc = util.RegexpFindStringPtr(DESCRE, raw) if n.Desc != nil { d := strings.Trim(*n.Desc, "\"") n.Desc = &d } n.NetObjects(raw) o.Network = append(o.Network, &n) } // NetObjects creates a network object that is appended to the Network structure func (o *NetworkObjGroup) NetObjects(s string) { obj := OBJGRPTYPERE.FindAllStringSubmatch(s, -1) if len(obj) == 0 { return } for _, v := range obj { switch v[1] { case "group-object": o.NetworkObj = append(o.NetworkObj, &NetworkObj{ Type: "group-object", Name: &v[2], }) default: t := KEYVALRE.FindStringSubmatch(v[2]) if len(t) == 0 { continue } switch t[1] { case "host": o.NetworkObj = append(o.NetworkObj, &NetworkObj{ Type: "host", Network: &t[2], }) case "object": o.NetworkObj = append(o.NetworkObj, &NetworkObj{ Type: "object", Name: &t[2], }) default: o.NetworkObj = append(o.NetworkObj, &NetworkObj{ Type: "network", Network: &t[1], Mask: &t[2], }) } } } } // ServiceParse parses an object-group service in to the proper structure and appends it to the list of service object groups func (o *ObjectGroups) ServiceParse(raw string, name *string, proto *string) { var sg ServiceObjGroup sg.Name = name sg.Proto = proto sg.Desc = util.RegexpFindStringPtr(DESCRE, raw) if sg.Desc != nil { d := strings.Trim(*sg.Desc, "\"") sg.Desc = &d } sg.serviceObjects(raw) o.Service = append(o.Service, &sg) } func (o *ServiceObjGroup) serviceObjects(s string) { for i, line := range strings.Split(s, "\n") { if i == 0 { continue } var so ServiceObj clean := strings.TrimSpace(line) switch strings.Split(clean, " ")[0] { case "port-object": so.Type = "port-object" c := PORTOBJRE.FindStringSubmatch(clean) if c != nil { split := strings.Split(c[1], " ") so.MatchType = split[0] so.MatchItem = strings.Join(split[1:], " ") o.ServiceObj = append(o.ServiceObj, &so) } case "group-object": so.Type = "group-object" c := GROUPOBJRE.FindStringSubmatch(clean) if c != nil { so.Name = c[2] o.ServiceObj = append(o.ServiceObj, &so) } case "service-object": so.Type = "service-object" portmatch := SERVICEPROTORE.FindStringSubmatch(clean) if len(portmatch) != 0 { so.Proto = portmatch[1] } if so.Proto == "icmp" { d := SERVICEICMPRE.FindStringSubmatch(clean) if d != nil { so.DestItem = d[1] } } else { src := SERVICESRCRE.FindStringSubmatch(clean) split := strings.Split(clean, " ") if len(split) == 2 { so.Proto = split[1] o.ServiceObj = append(o.ServiceObj, &so) return } if src != nil { if src[1] != "" { // eq|gt|lt|neg has been specified so.SourceType = src[1] so.SourceItem = src[2] } if src[3] != "" { // Range has been specified so.SourceType = src[3] so.SourceItem = src[4] } } dst := SERVICEDSTRE.FindStringSubmatch(clean) if dst != nil { if dst[1] != "" { so.DestType = dst[1] so.DestItem = dst[2] } if dst[3] != "" { so.DestType = dst[3] so.DestItem = dst[4] } } } o.ServiceObj = append(o.ServiceObj, &so) } } } func (o *ObjectGroups) IcmpParse(raw string, name *string) { var i IcmpObjGroup i.Name = name i.Desc = util.RegexpFindStringPtr(DESCRE, raw) if i.Desc != nil { d := strings.Trim(*i.Desc, "\"") i.Desc = &d } i.icmpObjects(raw) o.Icmp = append(o.Icmp, &i) } func (o *IcmpObjGroup) icmpObjects(s string) { for _, v := range ICMPOBJRE.FindAllStringSubmatch(s, -1) { var icmpOBJ IcmpObj icmpOBJ.Type = &v[1] icmpOBJ.Name = &v[2] o.IcmpObj = append(o.IcmpObj, &icmpOBJ) } for _, v := range GROUPOBJRE.FindAllStringSubmatch(s, -1) { var icmpOBJ IcmpObj icmpOBJ.Type = &v[1] icmpOBJ.Name = &v[2] o.IcmpObj = append(o.IcmpObj, &icmpOBJ) } } // NetworkObject returns a NetworkObjGroup with given name func (o *ObjectGroups) NetworkObject(name string) *NetworkObjGroup { return FindNetworkObject(name, o.Network) } // FindNetworkObject looks for an object with specified name and returns it. func FindNetworkObject(name string, o []*NetworkObjGroup) *NetworkObjGroup { for _, O := range o { if name == *O.Name { return O } } return nil } // FindGroup is a wrapper for FindObjType, used to find object-groups func (o *ObjectGroups) FindGroup(groupName string) []*NetworkObjGroup { return FindObjType("object-group", groupName, o.Network) } // FindObject is a wrapper for FindObjType, used to find object func (o *ObjectGroups) FindObject(objName string) []*NetworkObjGroup { return FindObjType("object", objName, o.Network) } // FindObjType returns a list of network objects where the type and name are found func FindObjType(objType, objName string, o []*NetworkObjGroup) (matches []*NetworkObjGroup) { for _, obj := range o { for _, item := range obj.NetworkObj { if item.Type == objType { if *item.Name == objName { matches = append(matches, &NetworkObjGroup{ Name: obj.Name, Desc: obj.Desc, NetworkObj: []*NetworkObj{item}, }) } } } } return } // FindHost is a wrapper for func FindHost() func (o *ObjectGroups) FindHost(host string) (matches []*NetworkObjGroup) { return FindHost(host, o.Network) } // FindHost returns a list of networks where an address is found func FindHost(host string, o []*NetworkObjGroup) (matches []*NetworkObjGroup) { for _, obj := range o { for _, item := range obj.NetworkObj { if item.Type == "host" { if *item.Network == host { matches = append(matches, &NetworkObjGroup{ Name: obj.Name, Desc: obj.Desc, NetworkObj: []*NetworkObj{item}, }) } } } } return } // RemoveGroup is a wrapper for removing a object-group from object-groups func (o *ObjectGroups) RemoveGroup(groupName string) { RemoveObjType("object-group", groupName, o.Network) } // RemoveObject is a wrapper for removing a object-group from object func (o *ObjectGroups) RemoveObject(objName string) { RemoveObjType("object", objName, o.Network) } // RemoveObjType removes object/object-groups from the object-groups network list func RemoveObjType(objType, objName string, o []*NetworkObjGroup) { for _, obj := range o { var newObj []*NetworkObj for _, item := range obj.NetworkObj { if item.Type == objType { if *item.Name == objName { continue } } newObj = append(newObj, item) } obj.NetworkObj = newObj } } // RemoveHost is a wrapper for func RemoveHost() func (o *ObjectGroups) RemoveHost(host string) { RemoveHost(host, o.Network) } // RemoveHost removes a host form the object-groups host entries func RemoveHost(host string, o []*NetworkObjGroup) { for _, obj := range o { var newObj []*NetworkObj for _, item := range obj.NetworkObj { if item.Type == "host" { if *item.Network == host { continue } } newObj = append(newObj, item) } obj.NetworkObj = newObj } } // GetEmptyNetworkGroups is a wrapper for func GetEmptyNetworkGroups() func (o *ObjectGroups) GetEmptyNetworkGroups() (empty []*NetworkObjGroup) { return GetEmptyNetworkGroups(o.Network) } // GetEmptyNetworkGroups returns a list of empty network group names func GetEmptyNetworkGroups(o []*NetworkObjGroup) (empty []*NetworkObjGroup) { for _, obj := range o { if len(obj.NetworkObj) == 0 { empty = append(empty, obj) } } return }