Skip to content

Commit

Permalink
Merge branch 'teliax-add_security_policies'
Browse files Browse the repository at this point in the history
  • Loading branch information
czerwonk committed Nov 22, 2022
2 parents 7440e5c + 60182d3 commit 629cdda
Show file tree
Hide file tree
Showing 6 changed files with 280 additions and 0 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ The following metrics are supported by now:
* Routing engine statistics
* Storage (total, available and used blocks, used percentage)
* Firewall filters (counters and policers) - needs explicit rights beyond read-only
* Security policy (SRX) statistics
* Statistics about l2circuits (tunnel state, number of tunnels)
* Interface queue statistics
* Power (Power usage)
Expand Down
2 changes: 2 additions & 0 deletions collectors.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import (
"github.com/czerwonk/junos_exporter/pkg/features/rpki"
"github.com/czerwonk/junos_exporter/pkg/features/rpm"
"github.com/czerwonk/junos_exporter/pkg/features/security"
"github.com/czerwonk/junos_exporter/pkg/features/securitypolicies"
"github.com/czerwonk/junos_exporter/pkg/features/storage"
"github.com/czerwonk/junos_exporter/pkg/features/system"
"github.com/czerwonk/junos_exporter/pkg/features/vpws"
Expand Down Expand Up @@ -101,6 +102,7 @@ func (c *collectors) initCollectorsForDevices(device *connector.Device) {
c.addCollectorIfEnabledForDevice(device, "rpki", f.RPKI, rpki.NewCollector)
c.addCollectorIfEnabledForDevice(device, "rpm", f.RPM, rpm.NewCollector)
c.addCollectorIfEnabledForDevice(device, "security", f.Security, security.NewCollector)
c.addCollectorIfEnabledForDevice(device, "security_policies", f.SecurityPolicies, securitypolicies.NewCollector)
c.addCollectorIfEnabledForDevice(device, "storage", f.Storage, storage.NewCollector)
c.addCollectorIfEnabledForDevice(device, "system", f.System, system.NewCollector)
c.addCollectorIfEnabledForDevice(device, "power", f.Power, power.NewCollector)
Expand Down
2 changes: 2 additions & 0 deletions internal/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ type FeatureConfig struct {
Accounting bool `yaml:"accounting,omitempty"`
IPSec bool `yaml:"ipsec,omitempty"`
Security bool `yaml:"security,omitempty"`
SecurityPolicies bool `yaml:"security_policies,omitempty"`
FPC bool `yaml:"fpc,omitempty"`
RPKI bool `yaml:"rpki,omitempty"`
RPM bool `yaml:"rpm,omitempty"`
Expand Down Expand Up @@ -119,6 +120,7 @@ func setDefaultValues(c *Config) {
f.Firewall = true
f.RoutingEngine = true
f.Security = false
f.SecurityPolicies = false
f.Storage = false
f.Accounting = false
f.FPC = false
Expand Down
2 changes: 2 additions & 0 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ var (
interfaceDiagnosticsEnabled = flag.Bool("ifdiag.enabled", true, "Scrape optical interface diagnostic metrics")
ipsecEnabled = flag.Bool("ipsec.enabled", false, "Scrape IPSec metrics")
securityEnabled = flag.Bool("security.enabled", false, "Scrape security metrics")
securityPoliciesEnabled = flag.Bool("security_policies.enabled", false, "Scrape security policy metrics")
storageEnabled = flag.Bool("storage.enabled", true, "Scrape system storage metrics")
fpcEnabled = flag.Bool("fpc.enabled", true, "Scrape line card metrics")
accountingEnabled = flag.Bool("accounting.enabled", false, "Scrape accounting flow metrics")
Expand Down Expand Up @@ -201,6 +202,7 @@ func loadConfigFromFlags() *config.Config {
f.InterfaceQueue = *interfaceQueuesEnabled
f.IPSec = *ipsecEnabled
f.Security = *securityEnabled
f.SecurityPolicies = *securityPoliciesEnabled
f.ISIS = *isisEnabled
f.NAT = *natEnabled
f.NAT2 = *nat2Enabled
Expand Down
180 changes: 180 additions & 0 deletions pkg/features/securitypolicies/collector.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,180 @@
package securitypolicies

import (
"encoding/xml"
"strings"

"github.com/czerwonk/junos_exporter/pkg/collector"
"github.com/czerwonk/junos_exporter/pkg/rpc"
"github.com/prometheus/client_golang/prometheus"
)

const prefix string = "junos_security_policies_"

var (
hitCountDesc *prometheus.Desc
sessionCreationsDesc *prometheus.Desc
sessionDeletionsDesc *prometheus.Desc
inputBytesDesc *prometheus.Desc
outputBytesDesc *prometheus.Desc
inputPacketsDesc *prometheus.Desc
outputPacketsDesc *prometheus.Desc
)

func init() {
la := []string{"target", "from_zone", "to_zone", "policy_name"}
lb := []string{"target", "from_zone", "to_zone", "policy_name", "direction"}

hitCountDesc = prometheus.NewDesc(prefix+"hit_count", "Policy hit count", la, nil)

sessionCreationsDesc = prometheus.NewDesc(prefix+"session_creations", "Policy session creations", la, nil)
sessionDeletionsDesc = prometheus.NewDesc(prefix+"session_deletions", "Policy session deletions", la, nil)

inputBytesDesc = prometheus.NewDesc(prefix+"input_bytes", "Policy input bytes", lb, nil)
outputBytesDesc = prometheus.NewDesc(prefix+"output_bytes", "Policy output bytes", lb, nil)
inputPacketsDesc = prometheus.NewDesc(prefix+"input_packets", "Policy input packets", lb, nil)
outputPacketsDesc = prometheus.NewDesc(prefix+"output_packets", "Policy output packets", lb, nil)
}

type securityPolicyCollector struct {
}

// NewCollector creates a new collector
func NewCollector() collector.RPCCollector {
return &securityPolicyCollector{}
}

// Name returns the name of the collector
func (*securityPolicyCollector) Name() string {
return "Security Policies"
}

// Describe describes the metrics
func (*securityPolicyCollector) Describe(ch chan<- *prometheus.Desc) {
ch <- hitCountDesc
ch <- sessionCreationsDesc
ch <- sessionDeletionsDesc
ch <- inputBytesDesc
ch <- outputBytesDesc
ch <- inputBytesDesc
ch <- outputBytesDesc
}

// Collect collects metrics from JunOS
func (c *securityPolicyCollector) Collect(client *rpc.Client, ch chan<- prometheus.Metric, labelValues []string) error {
err := c.CollectStats(client, ch, labelValues)
if err != nil {
return err
}

err = c.CollectHits(client, ch, labelValues)
if err != nil {
return err
}

return nil
}

func (c *securityPolicyCollector) CollectStats(client *rpc.Client, ch chan<- prometheus.Metric, labelValues []string) error {
var x = statsMultiEngineResult{}
err := client.RunCommandAndParseWithParser("show security policies detail", func(b []byte) error {
return parseStatsXML(b, &x)
})
if err != nil {
return err
}

for _, ctx := range x.Results.RoutingEngines[0].Policies.Contexts {
for _, pol := range ctx.Policies {
if pol.PolicyInformation.StatisticsInformation == nil {
continue
}

var ln, li, lr []string
if ctx.ContextInformation.GlobalContext == nil {
ln = append(labelValues, ctx.ContextInformation.FromZone, ctx.ContextInformation.ToZone)
} else {
ln = append(labelValues, "junos-global", "junos-global")
}
ln = append(ln, pol.PolicyInformation.Name)

li = append(li, ln...)
li = append(li, "initial")
lr = append(lr, ln...)
lr = append(lr, "reply")

ch <- prometheus.MustNewConstMetric(sessionCreationsDesc, prometheus.CounterValue, pol.PolicyInformation.StatisticsInformation.SessionCreations, ln...)
ch <- prometheus.MustNewConstMetric(sessionDeletionsDesc, prometheus.CounterValue, pol.PolicyInformation.StatisticsInformation.SessionDeletions, ln...)
ch <- prometheus.MustNewConstMetric(inputBytesDesc, prometheus.CounterValue, pol.PolicyInformation.StatisticsInformation.InputBytesInit, li...)
ch <- prometheus.MustNewConstMetric(inputBytesDesc, prometheus.CounterValue, pol.PolicyInformation.StatisticsInformation.InputBytesReply, lr...)
ch <- prometheus.MustNewConstMetric(outputBytesDesc, prometheus.CounterValue, pol.PolicyInformation.StatisticsInformation.OutputBytesInit, li...)
ch <- prometheus.MustNewConstMetric(outputBytesDesc, prometheus.CounterValue, pol.PolicyInformation.StatisticsInformation.OutputBytesReply, lr...)
ch <- prometheus.MustNewConstMetric(inputPacketsDesc, prometheus.CounterValue, pol.PolicyInformation.StatisticsInformation.InputPacketsInit, li...)
ch <- prometheus.MustNewConstMetric(inputPacketsDesc, prometheus.CounterValue, pol.PolicyInformation.StatisticsInformation.InputPacketsReply, lr...)
ch <- prometheus.MustNewConstMetric(outputPacketsDesc, prometheus.CounterValue, pol.PolicyInformation.StatisticsInformation.OutputPacketsInit, li...)
ch <- prometheus.MustNewConstMetric(outputPacketsDesc, prometheus.CounterValue, pol.PolicyInformation.StatisticsInformation.OutputPacketsReply, lr...)
}
}

return nil
}

func (c *securityPolicyCollector) CollectHits(client *rpc.Client, ch chan<- prometheus.Metric, labelValues []string) error {
var x = hitsMultiEngineResult{}
err := client.RunCommandAndParseWithParser("show security policies hit-count", func(b []byte) error {
return parseHitsXML(b, &x)
})
if err != nil {
return err
}

for _, pol := range x.MultiRoutingEngineResults.RoutingEngine[0].HitCount.Policies {
ls := append(labelValues, pol.FromZone, pol.ToZone, pol.PolicyName)
ch <- prometheus.MustNewConstMetric(hitCountDesc, prometheus.CounterValue, pol.Count, ls...)
}
return nil
}

func parseStatsXML(b []byte, res *statsMultiEngineResult) error {
if strings.Contains(string(b), "multi-routing-engine-results") {
return xml.Unmarshal(b, res)
}

fi := statsSingleEngineResult{}

err := xml.Unmarshal(b, &fi)
if err != nil {
return err
}

res.Results.RoutingEngines = []statsRoutingEngine{
{
Name: "N/A",
Policies: fi.Policies,
},
}

return nil
}

func parseHitsXML(b []byte, res *hitsMultiEngineResult) error {
if strings.Contains(string(b), "multi-routing-engine-results") {
return xml.Unmarshal(b, res)
}

fi := hitsSingleEngineResult{}

err := xml.Unmarshal(b, &fi)
if err != nil {
return err
}

res.MultiRoutingEngineResults.RoutingEngine = []hitsRoutingEngine{
{
Name: "N/A",
HitCount: fi.HitCount,
},
}

return nil
}
93 changes: 93 additions & 0 deletions pkg/features/securitypolicies/rpc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
package securitypolicies

import "encoding/xml"

type statsMultiEngineResult struct {
XMLName xml.Name `xml:"rpc-reply"`
Results statsMultiRoutingEngineResults `xml:"multi-routing-engine-results"`
}

type statsMultiRoutingEngineResults struct {
RoutingEngines []statsRoutingEngine `xml:"multi-routing-engine-item"`
}

type statsRoutingEngine struct {
Name string `xml:"re-name"`
Policies securityPolicies `xml:"security-policies"`
}

type statsSingleEngineResult struct {
XMLName xml.Name `xml:"rpc-reply"`
Policies securityPolicies `xml:"security-policies"`
}

type securityPolicies struct {
Contexts []securityContext `xml:"security-context"`
}

type securityContext struct {
ContextInformation securityContextInformation `xml:"context-information"`
Policies []securityPolicy `xml:"policies"`
}

type securityContextInformation struct {
FromZone string `xml:"source-zone-name"`
ToZone string `xml:"destination-zone-name"`
GlobalContext *struct{} `xml:"global-context"`
}

type securityPolicy struct {
PolicyInformation securityPolicyInformation `xml:"policy-information"`
}

type securityPolicyInformation struct {
Name string `xml:"policy-name"`
Action struct {
ActionType string `xml:"action-type"`
} `xml:"policy-action"`
StatisticsInformation *securityPolicyStatisticsInformation `xml:"policy-statistics-information"`
}

type securityPolicyStatisticsInformation struct {
InputBytesInit float64 `xml:"input-bytes-init"`
InputBytesReply float64 `xml:"input-bytes-reply"`
OutputBytesInit float64 `xml:"output-bytes-init"`
OutputBytesReply float64 `xml:"output-bytes-reply"`
InputPacketsInit float64 `xml:"input-packets-init"`
InputPacketsReply float64 `xml:"input-packets-reply"`
OutputPacketsInit float64 `xml:"output-packets-init"`
OutputPacketsReply float64 `xml:"output-packets-reply"`
SessionCreations float64 `xml:"session-creations"`
SessionDeletions float64 `xml:"session-deletions"`
}

type hitsMultiEngineResult struct {
XMLName xml.Name `xml:"rpc-reply"`
MultiRoutingEngineResults hitsRoutingEngines `xml:"multi-routing-engine-results"`
}

type hitsRoutingEngines struct {
RoutingEngine []hitsRoutingEngine `xml:"multi-routing-engine-item"`
}

type hitsRoutingEngine struct {
Name string `xml:"re-name"`
HitCount hitCount `xml:"policy-hit-count"`
}

type hitsSingleEngineResult struct {
XMLName xml.Name `xml:"rpc-reply"`
HitCount hitCount `xml:"policy-hit-count"`
}

type hitCount struct {
LSName string `xml:"logical-system-name"`
Policies []hitCountEntry `xml:"policy-hit-count-entry"`
}

type hitCountEntry struct {
PolicyName string `xml:"policy-hit-count-policy-name"`
FromZone string `xml:"policy-hit-count-from-zone"`
ToZone string `xml:"policy-hit-count-to-zone"`
Count float64 `xml:"policy-hit-count-count"`
}

0 comments on commit 629cdda

Please sign in to comment.