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 = layers.packet.Packet(frags[0]) packet2 = layers.packet.Packet(frags[1]) 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 = layers.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 = layers.packet.Packet(IP(nfpacket.get_payload())) if self.save_seen_packets: 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.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 if self.forwarder: nfpacket.drop() self.handle_packet(packet) 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()
def is_applicable(self, packet, logger): """ Checks if this trigger is applicable to a given packet. """ will_run = False self.num_seen += 1 if not packet.haslayer(self.trigger_proto): return False packet_value = packet.get(self.trigger_proto, self.trigger_field) if self.has_wildcard: will_run = (self.trigger_value in packet_value) else: will_run = (self.trigger_value == packet_value) # Track if this action is used if (not GAS_ENABLED or self.gas_remaining is None) and will_run: self.ran = True # If this is a normal trigger and we are out of gas, do not run elif not self.bomb_trigger and will_run and self.gas_remaining == 0: will_run = False # If this is a bomb trigger, run once gas hits zero elif self.bomb_trigger and will_run and self.gas_remaining == 0: self.ran = True # If this is a normal trigger and we still have gas remaining, run and # decrement the gas elif will_run and self.gas_remaining > 0: # Gas is enabled and we haven't run out yet, subtract one from our gas self.gas_remaining -= 1 self.ran = True # A bomb trigger has negative gas - it does not allow the action to run until the trigger # matches x times elif will_run and self.gas_remaining < 0: self.gas_remaining += 1 will_run = False return will_run
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 overlap is specified, it will select n bytes from the second packet and append them to the first, and increment the sequence number accordingly """ 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 # Make sure we don't go out of bounds by choosing the min overlap_bytes = min(len(payload[fragsize:]), self.overlap) # Attach these bytes to the first packet pkt1 = IP(packet["IP"]) / payload[:fragsize + overlap_bytes] 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 = layers.packet.Packet(pkt1) packet2 = layers.packet.Packet(pkt2) # Reset packet2's SYN number if packet2["TCP"].seq + fragsize > MAX_UINT: # Wrap sequence numbers around if greater than MAX_UINT packet2["TCP"].seq = packet2["TCP"].seq + fragsize - MAX_UINT - 1 else: 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]