/* Spam cleverly-constructed fake filter requests to block "from". These should be dropped by the router, as they do not have legitimate nonces. */ func sendFakeRequests(from, to net.IP) { req := filter.Request{ Type: filter.FilterReq, SrcIP: to, DstIP: from, Flow: routerecord.RouteRecord{ Protocol: byte(layers.IPProtocolTCP), Path: []routerecord.Router{ { IP: net.ParseIP("10.4.32.3"), Nonce: [8]byte{5, 5, 5, 5, 5, 5, 5, 5}, }, { IP: net.ParseIP("10.4.32.2"), Nonce: [8]byte{1, 2, 3, 4, 5, 6, 7, 8}, }, }, }, } for _ = range time.Tick(time.Second) { log.Println("Sending illigitimate filter request:", req) req.Send(req.Flow.Path[0].IP) } }
/*listenForRouteRecords intercepts all incoming packets to this host and removes their route records before letting the operating system process them. If listenForRouteRecords is true, it also sends filter requests whenever an ICMP packet from 10.4.32.4 arrives. */ func listenForRouteRecords(sendFilterRequests bool) { routerecord.Init() nfq, err := netfilter.NewNFQueue(0, 100000, 0xffff) if err != nil { log.Fatal(err) } defer nfq.Close() for packet := range nfq.GetPackets() { var ipLayer *layers.IPv4 if layer := packet.Packet.Layer(layers.LayerTypeIPv4); layer != nil { ipLayer = layer.(*layers.IPv4) } else { packet.SetVerdict(netfilter.NF_ACCEPT) continue } if routerecord.Shimmed(ipLayer) { /*If the IP layer has a shim, remove it.*/ log.Println("Got AITF shimmed packet from", aitf.Hostname(ipLayer.SrcIP)) rr := routerecord.Unshim(ipLayer) log.Println(rr) if sendFilterRequests { /*If this is a malicious packet, construct a filter request to stop any future undesired traffic from this flow. The policy module simply considers any ICMP traffic from the attacker to be "malicous".*/ if ipLayer.Protocol == layers.IPProtocolICMPv4 && ipLayer.SrcIP.Equal(net.ParseIP("10.4.32.4")) { log.Println("Malicious packet detected from", aitf.Hostname(ipLayer.SrcIP)) req := filter.Request{ Type: filter.FilterReq, SrcIP: ipLayer.SrcIP, DstIP: ipLayer.DstIP, Flow: *rr, } req.Send(rr.Path[len(rr.Path)-1].IP) } } /*Serialize the IP packet. Assuming this is successful, accept it.*/ b, err := routerecord.Serialize(ipLayer) if err != nil { log.Println(err) packet.SetVerdict(netfilter.NF_DROP) } else { packet.SetResult(netfilter.NF_ACCEPT, b) } } else { /*Any packets without a shim can be accepted as-is.*/ log.Println("Got", ipLayer.Protocol, "packet from", aitf.Hostname(ipLayer.SrcIP)) packet.SetVerdict(netfilter.NF_ACCEPT) } } }
/* listenForFilterRequest waits for a filter request from a client to come. Then, it verifies the authenticity of the request and takes the appropriate action based on the AITF filter request protocol. */ func listenForFilterRequest(mode complianceMode) { if handshakes == nil { handshakes = make(map[uint64](*filter.Request)) } /*Open up a UDP server on the filter request port and handle any messages that arrive.*/ serverAddr, err := net.ResolveUDPAddr("udp", ":54321") if err != nil { log.Fatal(err) } serverConn, err := net.ListenUDP("udp", serverAddr) if err != nil { log.Fatal(err) } defer serverConn.Close() buf := make([]byte, 5000) for { n, addr, _ := serverConn.ReadFromUDP(buf) /*Read a request from the UDP connection*/ var req filter.Request _, err := req.ReadFrom(bytes.NewBuffer(buf[:n])) if err != nil { log.Println(err) continue } /*Throw the request away if it is not authentic.*/ if !req.Authentic() { log.Println("Received a forged filter request!") continue } log.Println("Got", req.Type, "from", aitf.Hostname(addr.IP)) switch req.Type { case filter.FilterReq: /*When we receive a filter request, install a temporary filter and begin a counter-connection with the attacker's router. Also let the victim know that the attack should have stopped with a filter ACK. The filter is installed for the full filter time instead of the temporary time, but is automatically removed when we get a filter ACK.*/ filter.InstallFilter(req, filter.LongFilterTime, true) req.Type = filter.FilterAck req.Send(addr.IP) /*If we've blocked this filter before and it's still happening, escalate the filter and just block it here.*/ for _, req2 := range shadowFilters { if req2.SrcIP.Equal(req.SrcIP) && req2.DstIP.Equal(req.DstIP) { log.Println("Escalating request.") return } } req.Type = filter.CounterConnectionSyn req.Send(req.Flow.Path[0].IP) case filter.CounterConnectionSyn: if mode == comply || mode == lie { /*When we get a counter-connection SYN, continue the three-way handshake with a SYN-ACK. We don't install a filter until we get an ACK back with the right nonce.*/ req.Type = filter.CounterConnectionSynAck req.Nonce = uint64(rand.Int63()) handshakes[req.Nonce] = &req req.Send(addr.IP) } case filter.CounterConnectionSynAck: if mode == comply || mode == lie { /*When we receive a response to a counter-connection, complete the three-way handshake.*/ req.Type = filter.CounterConnectionAck req.Send(addr.IP) } case filter.CounterConnectionAck: if mode == comply || mode == lie { /*When we receive a counter-connection ACK, make sure we're actually waiting for a response to that handshake, then install a temporary filter.*/ originalReq := handshakes[req.Nonce] if originalReq == nil { log.Println("Received a forged three-way handshake:", req) continue } else { delete(handshakes, req.Nonce) } } if mode == comply { /*The filter is installed for the full filter time instead of the temporary time, but is automatically removed when we get a filter ACK.*/ filter.InstallFilter(req, filter.LongFilterTime, true) /*The attacker should be informed of its wrongdoing, and the victim's router should be informed that this router is complying with the request.*/ req.Type = filter.FilterReq req.Send(req.SrcIP) req.Type = filter.FilterAck req.Send(addr.IP) } case filter.FilterAck: if mode == comply { /*When we get acknowledgement of compliance with a filter, we can remove our temporary filter. Nobody lies on the internet.*/ filter.UninstallFilter(req, true) shadowFilters = append(shadowFilters, req) } } } }
/* listenForFilterRequest waits for a filter request from a router to come. Then, it verifies the authenticity of the request and takes some action. If action is comply, it filters the attack. If action is ignore, it logs the request but does nothing about it.comply If action is lie, it complies with the request but doesn't actually add a filter. */ func listenForFilterRequest(mode complianceMode) { /*Open up a UDP server on the filter request port and handle any messages that arrive.*/ serverAddr, err := net.ResolveUDPAddr("udp", ":54321") if err != nil { log.Fatal(err) } serverConn, err := net.ListenUDP("udp", serverAddr) if err != nil { log.Fatal(err) } defer serverConn.Close() buf := make([]byte, 5000) for { n, addr, _ := serverConn.ReadFromUDP(buf) /*Read a request from the UDP connection*/ var req filter.Request _, err := req.ReadFrom(bytes.NewBuffer(buf[:n])) if err != nil { log.Println(err) continue } log.Println("Got", req.Type, "from", aitf.Hostname(addr.IP)) switch req.Type { case filter.FilterReq: switch mode { case comply: log.Println("Complying with filter request...") /*If this host is okay with filter requests, add a firewall rule to block the requested flow and respond with an acknowledgement.*/ filter.InstallFilter(req, filter.LongFilterTime, false) req.Type = filter.FilterAck req.Send(addr.IP) case ignore: log.Println("Ignoring filter request...") case lie: log.Println("Pretending to comply with filter request...") /*If this host is a lier, send an acknowledgement without actually installing a filter rule.*/ req.Type = filter.FilterAck req.Send(addr.IP) } case filter.FilterAck: /*Do nothing. The routers should take care of mitigating the attack from now on.*/ default: /*Hosts shouldn't get any of the other message types.*/ log.Println("Unexpected filter request:", req) } } }