def ip_fragment(self, packet, logger): """ Perform IP fragmentation. """ if not packet.haslayer("IP") or not hasattr(packet["IP"], "load"): return packet, packet.copy( ) # duplicate if no TCP or no payload to segment load = "" if packet.haslayer("TCP"): load = bytes(packet["TCP"]) elif packet.haslayer("UDP"): load = bytes(packet["UDP"]) else: load = bytes(packet["IP"].load) # If there is no load, duplicate the packet if not load: return packet, packet.copy() if self.fragsize == -1 or (self.fragsize * 8) > len(load) or len(load) <= 8: fragsize = int(int(((int(len(load) / 2)) / 8)) * 8) frags = self.fragment(packet.copy().packet, fragsize=fragsize) else: # packet can be fragmented as requested frags = self.fragment(packet.copy().packet, fragsize=self.fragsize * 8) packet1 = actions.packet.Packet(frags[0]) packet2 = actions.packet.Packet(frags[1]) if self.correct_order: return packet1, packet2 else: return packet2, packet1
def handle_inbound_packet(self, divert_packet): """ Handles inbound packets. Process the packet and forward it to the strategy if needed. """ packet = actions.packet.Packet(IP(divert_packet.raw.tobytes())) self.seen_packets.append(packet) self.logger.debug("Received packet: %s", str(packet)) # Run the given strategy packets = self.strategy.act_on_packet(packet, self.logger, direction="in") # GFW will send RA packets to disrupt a TCP stream if packet.haslayer("TCP") and packet.get("TCP", "flags") == "RA": self.logger.debug("Detected GFW censorship - strategy failed.") self.censorship_detected = True # Branching is disabled for the in direction, so we can only ever get # back 1 or 0 packets. If zero, return and do not send packet. if not packets: return # If the strategy requested us to sleep before accepting on this packet, do so here if packets[0].sleep: time.sleep(packets[0].sleep) # Accept the modified packet self.mysend(packets[0], Direction.INBOUND)
def tcp_segment(self, packet, logger): """ Segments a packet into two, given the size of the first packet (0:fragsize) Always returns two packets, since fragment is a branching action, so if we are unable to segment, it will duplicate the packet. """ if not packet.haslayer("TCP") or not hasattr( packet["TCP"], "load") or not packet["TCP"].load: return packet, packet.copy( ) # duplicate if no TCP or no payload to segment # Get the original payload and delete it from the packet so it # doesn't come along when copying the TCP layer payload = packet["TCP"].load del (packet["TCP"].load) fragsize = self.fragsize if self.fragsize == -1 or self.fragsize > len(payload) - 1: fragsize = int(len(payload) / 2) # Craft new packets pkt1 = IP(packet["IP"]) / payload[:fragsize] pkt2 = IP(packet["IP"]) / payload[fragsize:] # We cannot rely on scapy's native parsing here - if a previous action has changed the # fragment offset, scapy will not identify this as TCP, so we must do it for scapy if not pkt1.haslayer("TCP"): pkt1 = IP(packet["IP"]) / TCP(bytes(pkt1["IP"].load)) if not pkt2.haslayer("TCP"): pkt2 = IP(packet["IP"]) / TCP(bytes(pkt2["IP"].load)) packet1 = actions.packet.Packet(pkt1) packet2 = actions.packet.Packet(pkt2) # Reset packet2's SYN number packet2["TCP"].seq += fragsize del packet1["IP"].chksum del packet2["IP"].chksum del packet1["IP"].len del packet2["IP"].len del packet1["TCP"].chksum del packet2["TCP"].chksum del packet1["TCP"].dataofs del packet2["TCP"].dataofs if self.correct_order: return [packet1, packet2] else: return [packet2, packet1]
def __packet_callback(self, scapy_packet): """ This callback is called whenever a packet is applied. Returns true if it should finish, otherwise, returns false. """ packet = actions.packet.Packet(scapy_packet) for proto in ["TCP", "UDP"]: if (packet.haslayer(proto) and ((packet[proto].sport == self.port) or (packet[proto].dport == self.port))): break else: return self.stop_sniffing_flag self.logger.debug(str(packet)) self.packet_dumper.write(scapy_packet) return self.stop_sniffing_flag
def in_callback(self, nfpacket): """ Callback bound to the incoming nfqueue rule. Since we can't manually send packets to ourself, process the given packet here. """ if not self.running_nfqueue: return packet = actions.packet.Packet(IP(nfpacket.get_payload())) self.seen_packets.append(packet) self.logger.debug("Received packet: %s", str(packet)) # Run the given strategy packets = self.strategy.act_on_packet(packet, self.logger, direction="in") # GFW will send RA packets to disrupt a TCP stream if packet.haslayer("TCP") and packet.get("TCP", "flags") == "RA": self.logger.debug("Detected GFW censorship - strategy failed.") self.censorship_detected = True # Branching is disabled for the in direction, so we can only ever get # back 1 or 0 packets. If zero, drop the packet. if not packets: nfpacket.drop() return # Otherwise, overwrite this packet with the packet the action trees gave back nfpacket.set_payload(bytes(packets[0])) # If the strategy requested us to sleep before accepting on this packet, do so here if packets[0].sleep: time.sleep(packets[0].sleep) # Accept the modified packet nfpacket.accept()