github.com/aporeto-inc/trireme-lib@v10.358.0+incompatible/controller/internal/enforcer/nfqdatapath/nfq_linux.go (about) 1 // +build linux 2 3 package nfqdatapath 4 5 // Go libraries 6 import ( 7 "context" 8 "fmt" 9 "strconv" 10 "time" 11 12 "go.aporeto.io/enforcerd/trireme-lib/controller/pkg/connection" 13 "go.aporeto.io/enforcerd/trireme-lib/controller/pkg/counters" 14 "go.aporeto.io/enforcerd/trireme-lib/controller/pkg/packet" 15 "go.aporeto.io/enforcerd/trireme-lib/policy" 16 "go.aporeto.io/enforcerd/trireme-lib/utils/constants" 17 markconstants "go.aporeto.io/enforcerd/trireme-lib/utils/constants" 18 nfqueue "go.aporeto.io/netlink-go/nfqueue" 19 "go.uber.org/zap" 20 ) 21 22 const ( 23 // nfq actions. 24 allow = 1 25 drop = 0 26 repeat = 4 27 ) 28 29 const ( 30 // max 31 maxTriesNfq = 5 32 ) 33 34 func (d *Datapath) errorCallback(err error, _ interface{}) { 35 zap.L().Error("Error while processing packets on queue", zap.Error(err)) 36 } 37 38 func (d *Datapath) callback(packet *nfqueue.NFPacket, _ interface{}) { 39 packet.Mark = packet.Mark - int(packet.QueueHandle.QueueNum)*constants.QueueBalanceFactor 40 41 if packet.Mark == int(constants.DefaultInputMark) { 42 d.processNetworkPacketsFromNFQ(packet) 43 return 44 } 45 46 packet.Mark = packet.Mark / d.filterQueue.GetNumQueues() 47 d.processApplicationPacketsFromNFQ(packet) 48 } 49 50 func (d *Datapath) startInterceptor(ctx context.Context) { 51 52 var err error 53 LOOP: 54 for i := 0; i < d.filterQueue.GetNumQueues(); i++ { 55 // Initialize all the queues 56 for tries := 0; tries < maxTriesNfq; tries++ { 57 if _, err = nfqueue.CreateAndStartNfQueue(ctx, uint16(i), 4096, nfqueue.NfDefaultPacketSize, d.callback, d.errorCallback, nil); err == nil { 58 continue LOOP 59 } 60 61 time.Sleep(1 * time.Second) 62 } 63 64 zap.L().Fatal("Unable to initialize netfilter queue", zap.Error(err)) 65 } 66 } 67 68 // processNetworkPacketsFromNFQ processes packets arriving from the network in an NF queue 69 func (d *Datapath) processNetworkPacketsFromNFQ(p *nfqueue.NFPacket) { 70 var processError error 71 var tcpConn *connection.TCPConnection 72 var udpConn *connection.UDPConnection 73 var processAfterVerdict func() 74 75 netPacket := &packet.Packet{} 76 err := netPacket.NewPacket(packet.PacketTypeNetwork, p.Buffer, strconv.Itoa(p.Mark), true) 77 if err != nil { 78 counters.CounterError(counters.ErrCorruptPacket, err) //nolint 79 zap.L().Debug("Dropping corrupted packet on network path", zap.Error(err)) 80 p.QueueHandle.SetVerdict2(uint32(p.QueueHandle.QueueNum), drop, 0, 0, uint32(p.ID), []byte{0}) 81 return 82 } else if netPacket.IPProto() == packet.IPProtocolTCP { 83 tcpConn, processAfterVerdict, processError = d.processNetworkTCPPackets(netPacket) 84 } else if netPacket.IPProto() == packet.IPProtocolUDP { 85 udpConn, processError = d.ProcessNetworkUDPPacket(netPacket) 86 } else if netPacket.IPProto() == packet.IPProtocolICMP { 87 icmpType, icmpCode := netPacket.GetICMPTypeCode() 88 context, err := d.contextFromIP(false, netPacket.Mark, 0, packet.IPProtocolICMP) 89 90 if err == nil { 91 action := d.processNetworkICMPPacket(context, netPacket, icmpType, icmpCode) 92 if action == icmpAccept { 93 p.QueueHandle.SetVerdict2(uint32(p.QueueHandle.QueueNum), allow, 0, uint32(len(netPacket.GetBuffer(0))), uint32(p.ID), netPacket.GetBuffer(0)) 94 return 95 } 96 } 97 98 p.QueueHandle.SetVerdict2(uint32(p.QueueHandle.QueueNum), drop, 0, uint32(len(netPacket.GetBuffer(0))), uint32(p.ID), netPacket.GetBuffer(0)) 99 zap.L().Debug("dropping Network ICMP Packet", 100 zap.Error(err), 101 zap.String("SourceIP", netPacket.SourceAddress().String()), 102 zap.String("DestinationIP", netPacket.DestinationAddress().String()), 103 zap.Int8("icmp type", icmpType), 104 zap.Int8("icmp code", icmpCode)) 105 106 return 107 } else { 108 processError = counters.CounterError(counters.ErrInvalidProtocol, fmt.Errorf("Invalid Protocol %d", int(netPacket.IPProto()))) 109 } 110 111 // TODO: Use error types and handle it in switch case here 112 113 if processError != nil { 114 if processError != errDropPingNetSynAck && processError != errHandshakePacket && processError != errDropQueuedPacket { 115 zap.L().Debug("Dropping packet on network path", 116 zap.Error(processError), 117 zap.String("SourceIP", netPacket.SourceAddress().String()), 118 zap.String("DestinationIP", netPacket.DestinationAddress().String()), 119 zap.Int("SourcePort", int(netPacket.SourcePort())), 120 zap.Int("DestinationPort", int(netPacket.DestPort())), 121 zap.Int("Protocol", int(netPacket.IPProto())), 122 zap.String("Flags", packet.TCPFlagsToStr(netPacket.GetTCPFlags())), 123 ) 124 } 125 126 p.QueueHandle.SetVerdict2(uint32(p.QueueHandle.QueueNum), drop, uint32(p.Mark), 0, uint32(p.ID), []byte{0}) 127 128 if processError != errDropPingNetSynAck { 129 if netPacket.IPProto() == packet.IPProtocolTCP { 130 d.collectTCPPacket(&debugpacketmessage{ 131 Mark: p.Mark, 132 p: netPacket, 133 tcpConn: tcpConn, 134 udpConn: nil, 135 err: processError, 136 network: true, 137 }) 138 } else if netPacket.IPProto() == packet.IPProtocolUDP { 139 d.collectUDPPacket(&debugpacketmessage{ 140 Mark: p.Mark, 141 p: netPacket, 142 tcpConn: nil, 143 udpConn: udpConn, 144 err: processError, 145 network: true, 146 }) 147 } 148 } 149 150 return 151 } 152 153 if netPacket.IPProto() == packet.IPProtocolTCP { 154 if netPacket.SetConnmark { 155 p.QueueHandle.SetVerdict2(uint32(p.QueueHandle.QueueNum), repeat, markconstants.PacketMarkToSetConnmark, uint32(len(netPacket.GetBuffer(0))), uint32(p.ID), netPacket.GetBuffer(0)) 156 } else { 157 if d.serviceMeshType == policy.Istio { 158 p.QueueHandle.SetVerdict2(uint32(p.QueueHandle.QueueNum), allow, markconstants.IstioPacketMark, uint32(len(netPacket.GetBuffer(0))), uint32(p.ID), netPacket.GetBuffer(0)) 159 } else { 160 p.QueueHandle.SetVerdict2(uint32(p.QueueHandle.QueueNum), allow, 0, uint32(len(netPacket.GetBuffer(0))), uint32(p.ID), netPacket.GetBuffer(0)) 161 } 162 } 163 } else { 164 p.QueueHandle.SetVerdict2(uint32(p.QueueHandle.QueueNum), allow, 0, uint32(len(netPacket.GetBuffer(0))), uint32(p.ID), netPacket.GetBuffer(0)) 165 } 166 167 if processAfterVerdict != nil { 168 processAfterVerdict() 169 } 170 171 if netPacket.IPProto() == packet.IPProtocolTCP { 172 d.collectTCPPacket(&debugpacketmessage{ 173 Mark: p.Mark, 174 p: netPacket, 175 tcpConn: tcpConn, 176 udpConn: nil, 177 err: nil, 178 network: true, 179 }) 180 } else if netPacket.IPProto() == packet.IPProtocolUDP { 181 d.collectUDPPacket(&debugpacketmessage{ 182 Mark: p.Mark, 183 p: netPacket, 184 tcpConn: nil, 185 udpConn: udpConn, 186 err: nil, 187 network: true, 188 }) 189 } 190 191 } 192 193 // processApplicationPackets processes packets arriving from an application and are destined to the network 194 func (d *Datapath) processApplicationPacketsFromNFQ(p *nfqueue.NFPacket) { 195 196 var processError error 197 var tcpConn *connection.TCPConnection 198 var udpConn *connection.UDPConnection 199 200 appPacket := &packet.Packet{} 201 err := appPacket.NewPacket(packet.PacketTypeApplication, p.Buffer, strconv.Itoa(p.Mark), true) 202 203 if err != nil { 204 zap.L().Debug("Dropping corrupted packet on application path", zap.Error(err)) 205 counters.CounterError(counters.ErrCorruptPacket, err) //nolint 206 p.QueueHandle.SetVerdict2(uint32(p.QueueHandle.QueueNum), drop, 0, 0, uint32(p.ID), []byte{0}) 207 return 208 } else if appPacket.IPProto() == packet.IPProtocolTCP { 209 tcpConn, processError = d.processApplicationTCPPackets(appPacket) 210 } else if appPacket.IPProto() == packet.IPProtocolUDP { 211 udpConn, processError = d.ProcessApplicationUDPPacket(appPacket) 212 } else if appPacket.IPProto() == packet.IPProtocolICMP { 213 icmpType, icmpCode := appPacket.GetICMPTypeCode() 214 context, err := d.contextFromIP(true, appPacket.Mark, 0, packet.IPProtocolICMP) 215 216 if err == nil { 217 action := d.processApplicationICMPPacket(context, appPacket, icmpType, icmpCode) 218 if action == icmpAccept { 219 p.QueueHandle.SetVerdict2(uint32(p.QueueHandle.QueueNum), allow, 0, uint32(len(appPacket.GetBuffer(0))), uint32(p.ID), appPacket.GetBuffer(0)) 220 return 221 } 222 } 223 224 p.QueueHandle.SetVerdict2(uint32(p.QueueHandle.QueueNum), drop, 0, uint32(len(appPacket.GetBuffer(0))), uint32(p.ID), appPacket.GetBuffer(0)) 225 zap.L().Debug("dropping Application ICMP Packet", 226 zap.Error(err), 227 zap.String("SourceIP", appPacket.SourceAddress().String()), 228 zap.String("DestinationIP", appPacket.DestinationAddress().String()), 229 zap.Int8("icmp type", icmpType), 230 zap.Int8("icmp code", icmpCode)) 231 232 return 233 } else { 234 processError = counters.CounterError(counters.ErrInvalidProtocol, fmt.Errorf("Invalid Protocol %d", int(appPacket.IPProto()))) 235 } 236 237 if processError != nil { 238 if processError != errHandshakePacket && processError != errDropQueuedPacket { 239 240 zap.L().Debug("Dropping packet on app path", 241 zap.Error(processError), 242 zap.String("SourceIP", appPacket.SourceAddress().String()), 243 zap.String("DestinationIP", appPacket.DestinationAddress().String()), 244 zap.Int("SourcePort", int(appPacket.SourcePort())), 245 zap.Int("DestinationPort", int(appPacket.DestPort())), 246 zap.Int("Protocol", int(appPacket.IPProto())), 247 zap.String("Flags", packet.TCPFlagsToStr(appPacket.GetTCPFlags())), 248 ) 249 } 250 p.QueueHandle.SetVerdict2(uint32(p.QueueHandle.QueueNum), drop, uint32(p.Mark), 0, uint32(p.ID), []byte{0}) 251 252 if appPacket.IPProto() == packet.IPProtocolTCP { 253 d.collectTCPPacket(&debugpacketmessage{ 254 Mark: p.Mark, 255 p: appPacket, 256 tcpConn: tcpConn, 257 udpConn: nil, 258 err: processError, 259 network: false, 260 }) 261 262 } else if appPacket.IPProto() == packet.IPProtocolUDP { 263 d.collectUDPPacket(&debugpacketmessage{ 264 Mark: p.Mark, 265 p: appPacket, 266 tcpConn: nil, 267 udpConn: udpConn, 268 err: processError, 269 network: false, 270 }) 271 } 272 return 273 } 274 275 if appPacket.IPProto() == packet.IPProtocolTCP { 276 if appPacket.SetConnmark { 277 p.QueueHandle.SetVerdict2(uint32(p.QueueHandle.QueueNum), repeat, markconstants.PacketMarkToSetConnmark, uint32(len(appPacket.GetBuffer(0))), uint32(p.ID), appPacket.GetBuffer(0)) 278 } else { 279 if d.serviceMeshType == policy.Istio { 280 p.QueueHandle.SetVerdict2(uint32(p.QueueHandle.QueueNum), allow, markconstants.IstioPacketMark, uint32(len(appPacket.GetBuffer(0))), uint32(p.ID), appPacket.GetBuffer(0)) 281 } else { 282 p.QueueHandle.SetVerdict2(uint32(p.QueueHandle.QueueNum), allow, 0, uint32(len(appPacket.GetBuffer(0))), uint32(p.ID), appPacket.GetBuffer(0)) 283 } 284 } 285 } else { 286 p.QueueHandle.SetVerdict2(uint32(p.QueueHandle.QueueNum), allow, 0, uint32(len(appPacket.GetBuffer(0))), uint32(p.ID), appPacket.GetBuffer(0)) 287 } 288 289 if appPacket.IPProto() == packet.IPProtocolTCP { 290 var id string 291 if tcpConn != nil { 292 id = tcpConn.Context.ID() 293 } else if d.puFromIP != nil { 294 id = d.puFromIP.ID() 295 } 296 297 if _, err = d.packetTracingCache.Get(id); err == nil { 298 d.collectTCPPacket(&debugpacketmessage{ 299 Mark: p.Mark, 300 p: appPacket, 301 tcpConn: tcpConn, 302 udpConn: nil, 303 err: nil, 304 network: false, 305 }) 306 } 307 308 } else if appPacket.IPProto() == packet.IPProtocolUDP { 309 d.collectUDPPacket(&debugpacketmessage{ 310 Mark: p.Mark, 311 p: appPacket, 312 tcpConn: nil, 313 udpConn: udpConn, 314 err: nil, 315 network: false, 316 }) 317 } 318 } 319 320 func (d *Datapath) cleanupPlatform() {}