github.com/aporeto-inc/trireme-lib@v10.358.0+incompatible/controller/internal/enforcer/nfqdatapath/nflog/nflog_common.go (about) 1 package nflog 2 3 import ( 4 "context" 5 "fmt" 6 "net" 7 "strconv" 8 "strings" 9 10 "go.aporeto.io/enforcerd/trireme-lib/collector" 11 "go.aporeto.io/enforcerd/trireme-lib/controller/pkg/counters" 12 "go.aporeto.io/enforcerd/trireme-lib/controller/pkg/packet" 13 "go.aporeto.io/enforcerd/trireme-lib/controller/pkg/pucontext" 14 "go.aporeto.io/enforcerd/trireme-lib/policy" 15 "go.aporeto.io/enforcerd/trireme-lib/utils/cache" 16 "go.uber.org/zap" 17 ) 18 19 // NFLogger provides an interface for NFLog 20 type NFLogger interface { 21 Run(ctx context.Context) 22 } 23 24 // GetPUContextFunc provides PU information given the id 25 type GetPUContextFunc func(hash string) (*pucontext.PUContext, error) 26 27 func recordCounters(protocol uint8, dstport uint16, srcport uint16, pu *pucontext.PUContext, puIsSource bool) { 28 switch protocol { 29 case packet.IPProtocolTCP: 30 pu.Counters().IncrementCounter(counters.ErrDroppedTCPPackets) 31 case packet.IPProtocolUDP: 32 pu.Counters().IncrementCounter(counters.ErrDroppedUDPPackets) 33 if puIsSource { 34 switch dstport { 35 case 53: 36 pu.Counters().IncrementCounter(counters.ErrDroppedDNSPackets) 37 case 67, 68: 38 pu.Counters().IncrementCounter(counters.ErrDroppedDHCPPackets) 39 case 123: 40 pu.Counters().IncrementCounter(counters.ErrDroppedNTPPackets) 41 } 42 } else { 43 switch srcport { 44 case 53: 45 pu.Counters().IncrementCounter(counters.ErrDroppedDNSPackets) 46 case 67, 68: 47 pu.Counters().IncrementCounter(counters.ErrDroppedDHCPPackets) 48 case 123: 49 pu.Counters().IncrementCounter(counters.ErrDroppedNTPPackets) 50 } 51 } 52 53 case packet.IPProtocolICMP: 54 pu.Counters().IncrementCounter(counters.ErrDroppedICMPPackets) 55 56 } 57 } 58 59 func recordDroppedPacket(payload []byte, protocol uint8, srcIP, dstIP net.IP, srcPort, dstPort uint16, pu *pucontext.PUContext, puIsSource bool) (*collector.PacketReport, error) { 60 61 report := &collector.PacketReport{} 62 63 report.PUID = pu.ManagementID() 64 report.Namespace = pu.ManagementNamespace() 65 ipPacket, err := packet.New(packet.PacketTypeNetwork, payload, "", false) 66 if err == nil { 67 report.Length = int(ipPacket.GetIPLength()) 68 report.PacketID, _ = strconv.Atoi(ipPacket.ID()) 69 70 } else { 71 zap.L().Debug("payload not valid", zap.Error(err)) 72 return nil, err 73 } 74 recordCounters(protocol, dstPort, srcPort, pu, puIsSource) 75 if protocol == packet.IPProtocolTCP || protocol == packet.IPProtocolUDP { 76 report.SourcePort = int(srcPort) 77 report.DestinationPort = int(dstPort) 78 } 79 if protocol == packet.IPProtocolTCP { 80 report.TCPFlags = int(ipPacket.GetTCPFlags()) 81 } 82 report.Protocol = int(protocol) 83 report.DestinationIP = dstIP.String() 84 report.SourceIP = srcIP.String() 85 report.TriremePacket = false 86 report.DropReason = collector.PacketDrop 87 88 if payload == nil { 89 report.Payload = []byte{} 90 return report, nil 91 } 92 if len(payload) <= 64 { 93 report.Payload = make([]byte, len(payload)) 94 copy(report.Payload, payload) 95 96 } else { 97 report.Payload = make([]byte, 64) 98 copy(report.Payload, payload[0:64]) 99 } 100 101 return report, nil 102 } 103 104 func recordFromNFLogData(payload []byte, prefix string, protocol uint8, srcIP, dstIP net.IP, srcPort, dstPort uint16, getPUContext GetPUContextFunc, puIsSource bool) (*collector.FlowRecord, *collector.PacketReport, error) { 105 106 var packetReport *collector.PacketReport 107 var err error 108 109 var hashID string 110 var policyID string 111 var extNetworkID string 112 var ruleName string 113 var encodedAction string 114 115 parts := strings.Split(prefix, ":") 116 switch len(parts) { 117 case 4: 118 // hashID:policyID:extNetworkID:action 119 hashID, policyID, extNetworkID, encodedAction = parts[0], parts[1], parts[2], parts[3] 120 case 5: 121 // hashID:policyID:extNetworkID:ruleName:action 122 hashID, policyID, extNetworkID, ruleName, encodedAction = parts[0], parts[1], parts[2], parts[3], parts[4] 123 default: 124 return nil, nil, fmt.Errorf("nflog: prefix doesn't contain sufficient information: %s", prefix) 125 } 126 127 pu, err := getPUContext(hashID) 128 if err != nil { 129 return nil, nil, err 130 } 131 132 // If we have a rule name, then look up the long version of logging prefix 133 if len(ruleName) > 0 { 134 realPrefix, ok := pu.LookupLogPrefix(policyID + ":" + extNetworkID + ":" + ruleName) 135 if !ok { 136 return nil, nil, fmt.Errorf("nflog: prefix not found in pucontext mapping: %s", prefix) 137 } 138 parts = strings.SplitN(realPrefix, ":", 3) 139 if len(parts) != 3 { 140 return nil, nil, fmt.Errorf("nflog: realPrefix doesn't contain sufficient information: %s", realPrefix) 141 } 142 policyID, extNetworkID, ruleName = parts[0], parts[1], parts[2] 143 } 144 145 if encodedAction == "10" { 146 packetReport, err = recordDroppedPacket(payload, protocol, srcIP, dstIP, srcPort, dstPort, pu, puIsSource) 147 return nil, packetReport, err 148 } 149 150 action, observedActionType, err := policy.EncodedStringToAction(encodedAction) 151 if err != nil { 152 return nil, packetReport, fmt.Errorf("nflog: unable to decode action for context id: %s (%s)", pu.ID(), encodedAction) 153 } 154 155 dropReason := "" 156 if action.Rejected() { 157 dropReason = collector.PolicyDrop 158 } 159 160 // point fix for now. 161 var destination collector.EndPoint 162 if protocol == packet.IPProtocolUDP || protocol == packet.IPProtocolTCP { 163 destination = collector.EndPoint{ 164 IP: dstIP.String(), 165 Port: dstPort, 166 } 167 } else { 168 destination = collector.EndPoint{ 169 IP: dstIP.String(), 170 } 171 } 172 173 record := &collector.FlowRecord{ 174 ContextID: pu.ID(), 175 Source: collector.EndPoint{ 176 IP: srcIP.String(), 177 }, 178 Destination: destination, 179 DropReason: dropReason, 180 PolicyID: policyID, 181 Tags: pu.Annotations().GetSlice(), 182 Action: action | policy.Log, // Add the logging flag back 183 L4Protocol: protocol, 184 Namespace: pu.ManagementNamespace(), 185 Count: 1, 186 RuleName: ruleName, 187 } 188 189 if action.Observed() { 190 record.ObservedAction = action 191 record.ObservedPolicyID = policyID 192 record.ObservedActionType = observedActionType 193 } 194 195 if puIsSource { 196 record.Source.Type = collector.EndPointTypePU 197 record.Source.ID = pu.ManagementID() 198 record.Destination.Type = collector.EndPointTypeExternalIP 199 record.Destination.ID = extNetworkID 200 } else { 201 record.Source.Type = collector.EndPointTypeExternalIP 202 record.Source.ID = extNetworkID 203 record.Destination.Type = collector.EndPointTypePU 204 record.Destination.ID = pu.ManagementID() 205 } 206 207 return record, packetReport, nil 208 } 209 210 func handleFlowReport(flowReportCache cache.DataStore, eventCollector collector.EventCollector, record *collector.FlowRecord, puIsSource bool) { 211 212 if record == nil { 213 return 214 } 215 216 uniqueKey := fmt.Sprintf("%d:%s:%d:%s:%d", 217 record.L4Protocol, record.Source.IP, record.Source.Port, record.Destination.IP, record.Destination.Port) 218 219 // If the flow record is ObserveContinue 220 if record.ObservedActionType.ObserveContinue() { 221 222 // If another observed continue policy is reported, then we ignore it. 223 if _, err := flowReportCache.Get(uniqueKey); err == nil { 224 return 225 } 226 227 // Add the observed policy report to the cache 228 err := flowReportCache.Add(uniqueKey, record) 229 if err != nil { 230 eventCollector.CollectFlowEvent(record) 231 zap.L().Error("handleFlowReport: unable to add flow record to cache", zap.Error(err)) 232 } 233 return 234 } 235 236 // See if there was an ObserveContinue policy 237 value, err := flowReportCache.Get(uniqueKey) 238 if err == nil { 239 report := value.(*collector.FlowRecord) 240 record.ObservedAction = report.ObservedAction 241 record.ObservedPolicyID = report.ObservedPolicyID 242 record.ObservedActionType = report.ObservedActionType 243 if puIsSource { 244 record.Destination.ID = report.Destination.ID 245 record.Destination.Type = report.Destination.Type 246 } else { 247 record.Source.ID = report.Source.ID 248 record.Source.Type = report.Source.Type 249 } 250 err = flowReportCache.Remove(uniqueKey) 251 if err != nil { 252 zap.L().Error("handleFlowReport: failed to remove flow from cache", zap.Error(err)) 253 } 254 } 255 eventCollector.CollectFlowEvent(record) 256 }