package asaModels import ( "fmt" "net" "regexp" "strings" "github.com/sirupsen/logrus" ) var ( staticXlateRe = regexp.MustCompile(`(?is)NAT\s+from\s+(\S+):(.*?)\s+to\s+(\S+):(.*?)\n\s*flags\s+(\S+)\s+idle\s+(\S+)\s+timeout\s+(\S+)`) dynamicXlateRe = regexp.MustCompile(`(?is)(tcp|udp|icmp)\s+pat\s+from\s+(\S+):(\S+)\/(\d+)\s+to\s+(\S+):(\S+)\/(\d+)\s*flags\s+(\S+)\s+idle\s+(\S+)\s+timeout\s+(\S+)`) xlateNetReplacer = strings.NewReplacer("\n", "", " ", "") ) type ( // Xlate type represents the exported complex literal for a parsed xlate // table on an ASA Xlate struct { NAT []XlateNAT `json:"nat"` PAT []XlatePAT `json:"pat"` } // XlateNAT type represents the exported complex literal for a parsed NAT portion // of the xlate results XlateNAT struct { FromIfc string `json:"from_interface"` FromNetwork []*net.IPNet `json:"from_networks"` ToIfc string `json:"to_interface"` ToNetwork []*net.IPNet `json:"to_networks"` Flag flag `json:"flag"` Idle string `json:"idle"` Timeout string `json:"timeout"` } // XlatePAT type represents the exported complex literal for a parsed PAT portion // of the xlate results XlatePAT struct { Type string `json:"type"` FromIfc string `json:"from_interface"` FromNetwork net.IP `json:"from_address"` FromPort string `json:"from_port"` ToIfc string `json:"to_interface"` ToNetwork net.IP `json:"to_address"` ToPort string `json:"to_port"` Flag flag `json:"flag"` Idle string `json:"idle"` Timeout string `json:"timeout"` } flag struct { DNS bool `json:"dns"` Extended bool `json:"extended"` Identity bool `json:"identity"` Dynamic bool `json:"dynamic"` PortMap bool `json:"port_map"` Static bool `json:"static"` Twice bool `json:"twice_nat"` NetToNet bool `json:"net_to_net"` } ) // Parse method is used to take a Xlate pointer receiver, and execute parsing actions // on the passed in string to populate the complex literal func (x *Xlate) Parse(s string) { for _, xlate := range staticXlateRe.FindAllStringSubmatch(s, -1) { x.NAT = append(x.NAT, XlateNAT{ FromIfc: xlate[1], FromNetwork: parseNets(xlate[2]), ToIfc: xlate[3], ToNetwork: parseNets(xlate[4]), Flag: flag{ DNS: strings.Contains(xlate[5], "D"), Extended: strings.Contains(xlate[5], "e"), Identity: strings.Contains(xlate[5], "I"), Dynamic: strings.Contains(xlate[5], "i"), PortMap: strings.Contains(xlate[5], "r"), Static: strings.Contains(xlate[5], "s"), Twice: strings.Contains(xlate[5], "T"), NetToNet: strings.Contains(xlate[5], "N"), }, Idle: xlate[6], Timeout: xlate[7], }) } for _, xlate := range dynamicXlateRe.FindAllStringSubmatch(s, -1) { x.PAT = append(x.PAT, XlatePAT{ Type: xlate[1], FromIfc: xlate[2], FromNetwork: net.ParseIP(xlate[3]), FromPort: xlate[4], ToIfc: xlate[5], ToNetwork: net.ParseIP(xlate[6]), ToPort: xlate[7], Flag: flag{ DNS: strings.Contains(xlate[8], "D"), Extended: strings.Contains(xlate[8], "e"), Identity: strings.Contains(xlate[8], "I"), Dynamic: strings.Contains(xlate[8], "i"), PortMap: strings.Contains(xlate[8], "r"), Static: strings.Contains(xlate[8], "s"), Twice: strings.Contains(xlate[8], "T"), NetToNet: strings.Contains(xlate[8], "N"), }, Idle: xlate[9], Timeout: xlate[10], }) } } func parseNets(s string) (nets []*net.IPNet) { s = xlateNetReplacer.Replace(s) for _, network := range strings.Split(s, ",") { if !strings.Contains(network, "/") { network = fmt.Sprintf("%s/32", network) } _, block, err := net.ParseCIDR(network) if err != nil { logrus.Errorf("asalib:asaModels:xlate:splitNetworks:%s", err) continue } nets = append(nets, block) } return }