def drop(self): # If we don't have a hijack_tuple, then we can't release it. # This shouldn't happen, so we note this. # if not self.hijack_tuple: print 'WARNING: TCPHijack.drop() called on non-hijacked conn' return TCPHijack.hijack_manager.unregister_tuple(self.hijack_tuple) # Send a RST to the listener of the hijack # in case it hasn't dropped this flow yet if not self.next_seq is None: (fsrc, fsport, fdst, fdport) = self.flow_tuple rst = dpkt.ip.IP(src=fsrc, dst=fdst, p=dpkt.ip.IP_PROTO_TCP, data=dpkt.tcp.TCP(sport=fsport, dport=fdport, flags=dpkt.tcp.TH_RST, seq=self.next_seq, ack=self.last_ack)) rst.len += len(rst.data) self.traffic_from_client(Packet(str(rst), read_only=False), buffer=False) # TODO: This might be endian-specific. Investigate. # dotted_quad = '.'.join(['%d' % ord(x) for x in self.hijack_tuple[0]]) TCPHijack.free_srcs.free_src((dotted_quad, self.hijack_tuple[1]))
def __init__(self, opts): self.tuples = {} self.opts = opts self.log = logging.getLogger('cb.tcphijack.hijackmgr') self.tun = TwistedTUN( lambda x: self.traffic_to_client(Packet(x, read_only=False)), '', self.opts['tun_ip'], self.opts['tun_netmask'])
def tcp_timestamp_test(): p = Packet(tlspkt) (bef_tsval, _, _) = p.parse_timestamp() p.offset_timestamp(4, True) (after_tsval, _, _) = p.parse_timestamp() assert (bef_tsval + 4 == after_tsval) # Verify the TCP checksum before = p.get_tcp_cksum() p.update_cksum() after = p.get_tcp_cksum() assert (abs(after - before) == 4)
def tcp_attrib_test(): p = Packet(tlspkt) assert (p.get_sport() == 443) assert (p.get_dport() == 59320) assert (p.get_tcp_cksum() == 0xb8b0) assert (p.thl == 32) assert (p.get_opts() == '\x01\x01\x08\x0a\x44\x4e\x98\x3d\x0b\x63\x5a\xdb') assert (p.get_payload_len() == 95) assert (p.get_seq() == 0xbdb8019a) assert (p.get_ack() == 0xa72449c8) assert (p.get_flags() == 0x18) old_seq = p.get_seq() p.set_seq(old_seq + 1) assert (p.get_seq() == old_seq + 1) assert (p.get_ack() == 0xa72449c8) old_ack = p.get_ack() p.set_ack(old_ack + 1) assert (p.get_ack() == old_ack + 1)
def tun_callback(rawpkt): """ Callback when pkts arrive from the TUN Figure out which client should receive the packet, and forward it along along that client connection. """ msg = VpnMsgWrapper.pkt_msg(rawpkt) pkt = Packet(rawpkt, read_only=True) des_ip = pkt.get_dst() # Lookup the client to which this pkt should be sent. # try: point = VpnServerState.CLIENTS[des_ip] point.transport.write(msg.pack()) except KeyError: logging.getLogger('cb.vpn_dp').debug('no client, dropping') print 'no client, dropping'
def ack_synack(self, pkt): """ ack_synack: Respond to a synack with an ack """ (src, sport, dst, dport) = self.flow_tuple DEBUG and log_debug("tcphijack.ack_synack: %s" % str(self.flow_tuple)) ack = dpkt.ip.IP(src=src, dst=dst, p=dpkt.ip.IP_PROTO_TCP, data=dpkt.tcp.TCP(sport=sport, dport=dport, flags=dpkt.tcp.TH_ACK, seq=pkt.get_ack(), ack=pkt.get_seq() + 1)) (tsv, tsr, index) = pkt.parse_timestamp() if not tsv is None: timestamp = pkt.buff[index:index + 10] opts = [] (typ, length, tsval, tsecr) = struct.unpack('>BBII', timestamp) # Just reuse our original tsval, but do echo the engine's reply = struct.pack('>BBII', typ, length, tsecr, tsval) opts.append(reply) nop = struct.pack('>B', dpkt.tcp.TCP_OPT_NOP) opts.append(nop) opts.append(nop) ack.data.opts = ''.join(opts) ack.data.off = (20 + len(ack.data.opts)) >> 2 ack.len += len(ack.data) self.traffic_from_client(Packet(str(ack), read_only=False), buffer=False)
class VpnDpSrcProtocol(Protocol): """ VPN source protocol: receive VPN messages from the clients and respond (typically by forwarding them through the TUN) """ def __init__(self): self.log = logging.getLogger('cb.vpn_dp') self.log.debug('VpnDpSrcProtocol init') self._recv_buffer = '' self._opened_session = False self._client_ipaddr = None def dstAccept(self, _protocol): """ accept method for new connections. (Is this method actually used?) """ self.log.debug('VpnDpSrcProtocol dstAccept') def dataReceived(self, new_data): """ Respond to data arriving from a client Parse the data into as many messages as possible (buffering any leftovers for later), and then process each message. """ self.log.debug('dataReceived') self._recv_buffer += new_data try: (msgs, self._recv_buffer) = VpnMsgWrapper.recv_from_buffer( self._recv_buffer) except BaseException, exc: # FIXME: recv_from_buffer can raise an exception. If this happens, # we must drop the connection. # return for msg in msgs: msg_type = msg.get_msg_type() self.log.debug('dataReceived ' + str(msg)) # TODO # should check that the msg makes sense, and the packet # we're about to forward isn't spoofed, forged, bogus... # if msg_type == cb.vpn.vpn_msg.FORWARD_PKT: msg_text = msg.get_msg_text() parsed_pkt = Packet(msg_text, read_only=True) src_ip = parsed_pkt.get_src() if src_ip != self._client_ipaddr: self.log.warn('incorrect src for %d.%d.%d.%d' % ( ord(src_ip[0]), ord(src_ip[1]), ord(src_ip[2]), ord(src_ip[3]))) # FIXME: bad packet == bad client; drop client else: _written = VpnServerState.TUN.write(msg_text) elif msg_type == cb.vpn.vpn_msg.OPEN_SESSION: if self._opened_session: self.log.warn('multiple OPEN_SESSION requests') # FIXME: This client is bad, and should be dropped else: self._opened_session = True next_addr = VpnServerState.TUN_ADDR_POOL.alloc() next_client_addr_str = str(next_addr) # Smoosh the client ipaddr into binary, and then # add the mapping from the binary ipaddr to ourselves for # future error checking that src addrs are correct. # octets = next_client_addr_str.split('.') ipaddr_binary = ''.join([chr(int(x)) for x in octets]) VpnServerState.CLIENTS[ipaddr_binary] = self self._client_ipaddr = ipaddr_binary self.log.info('assigning src_ip %s' % (next_client_addr_str,)) info_msg = VpnMsgWrapper.info_msg(next_client_addr_str, str(VpnServerState.TUN_NETWORK.netmask), VpnServerState.DNS_SERVERS) self.transport.write(info_msg.pack()) elif msg_type == cb.vpn.vpn_msg.CLOSE_SESSION: self.log.info('CLOSE_SESSION request') # FIXME: actually close the session else: self.log.warn('unknown msg type (%d)' % (msg_type,))
def init_hijack(self, pkt, isn=None): """ init_hijack: Initialize a hijack This function allocates an internal addr/port to use for communication with the kernel. It then sends a syn packet to initiate a TCP connection with the kernel. """ # FIXME: no longer have to guess in the symmetric case # GUESS THE TCP/IP OPTIONS opts = [] # assume we're using SACK opts.append('\x04\x02') # SACKOK # assume the MSS is 1460 opts.append(struct.pack('>BBH', dpkt.tcp.TCP_OPT_MSS, 4, 1460)) nop = struct.pack('>B', dpkt.tcp.TCP_OPT_NOP) (tsv, tsecr, index) = pkt.parse_timestamp() if not index is None: timestamp = pkt.buff[index:index + 10] if tsv: opts.append(timestamp) self.decoy_time = tsecr # for earlier kernels, we ignored window scale. Don't ignore now. # guess the window scale size by looking at the initial window size scale = 1 while pow(2, scale) * pkt.get_window() < 10000: scale += 1 opts.append(struct.pack('>BBB', dpkt.tcp.TCP_OPT_WSCALE, 3, scale)) while len(''.join(opts)) % 4 != 0: opts.append(nop) if isn is None: isn = pkt.get_seq() - 1 # CREATE THE SYN PACKET syn = dpkt.ip.IP(src=self.flow_tuple[0], dst=self.flow_tuple[2], p=dpkt.ip.IP_PROTO_TCP, data=dpkt.tcp.TCP(sport=self.flow_tuple[1], dport=self.flow_tuple[3], seq=isn, flags=dpkt.tcp.TH_SYN, opts=''.join(opts))) syn.data.off = (20 + len(syn.data.opts)) >> 2 syn.len += len(syn.data) self.buffer = [pkt] if self.log.getEffectiveLevel() <= logging.DEBUG: DEBUG and log_debug("Sending to c2d_nat -> %s" % cb.util.dpkt_util.dpkt_to_str(syn)) self.traffic_from_client(Packet(str(syn), read_only=False), buffer=False)
def tcp_cksum_test(): p = Packet(tlspkt) before = p.get_tcp_cksum() p.update_cksum() after = p.get_tcp_cksum() assert (before == after)
def payload_test(): p = Packet(tlspkt) payload = p.get_payload() assert (payload == tlspayload)
def ip_attrib_test(): p = Packet(tlspkt) assert (p.get_src() == '\x48\x0E\xCC\x67') assert (p.get_dst() == '\x80\x59\x50\xF8') assert (p.get_ip_cksum() == 0xc3a7) assert (p.protocol == 6)
def tcp_test(): p = Packet(tlspkt) assert (p.protocol == 6)
def load_test(): p = Packet(tlspkt)