def decode(self, aBuffer):
        e = ImpactPacket.Ethernet(aBuffer)
        self.set_decoded_protocol(e)
        off = e.get_header_size()
        if e.get_ether_type() == ImpactPacket.IP.ethertype:
            self.ip_decoder = IPDecoder()
            packet = self.ip_decoder.decode(aBuffer[off:])
        elif e.get_ether_type() == IP6.IP6.ethertype:
            self.ip6_decoder = IP6Decoder()
            packet = self.ip6_decoder.decode(aBuffer[off:])
        elif e.get_ether_type() == ImpactPacket.ARP.ethertype:
            self.arp_decoder = ARPDecoder()
            packet = self.arp_decoder.decode(aBuffer[off:])
        elif e.get_ether_type() == eap.DOT1X_AUTHENTICATION:
            self.eapol_decoder = EAPOLDecoder()
            packet = self.eapol_decoder.decode(aBuffer[off:])
        # LLC ?
        elif e.get_ether_type() < 1500:
            self.llc_decoder = LLCDecoder()
            packet = self.llc_decoder.decode(aBuffer[off:])
        else:
            self.data_decoder = DataDecoder()
            packet = self.data_decoder.decode(aBuffer[off:])

        e.contains(packet)
        return e
Ejemplo n.º 2
0
def sendReply(nonce):
    #build ethernet frame
    eth = ImpactPacket.Ethernet()
    eth.set_ether_type(0x88b5)
    eth.set_ether_shost(ETH_MY_MAC)
    eth.set_ether_dhost(ETH_MY_MAC)

    #build ip packet
    ip = ImpactPacket.IP()
    ip.set_ip_v(4)
    ip.set_ip_len(32)
    ip.set_ip_src("127.0.0.1")
    ip.set_ip_dst("127.0.0.1")

    #build UDP packet
    udp = ImpactPacket.UDP()
    udp.set_uh_sport(62001)
    udp.set_uh_dport(62000)
    udp.set_uh_ulen(12)
    payload = nonce
    udp.contains(ImpactPacket.Data(payload))

    ip.contains(udp)
    eth.contains(ip)

    device = findalldevs()[0]

    s = socket.socket(socket.AF_PACKET, socket.SOCK_RAW, socket.htons(0x88b5))
    s.bind(('lo', 0))

    s.send(eth.get_packet())
    print "Sent: " + nonce
    signal.alarm(0)  #disable the alarm
Ejemplo n.º 3
0
    def icmp_reply(self, eth_src, eth_dst, ip_src, ip_dst, i_type, i_code,
                   ip_pkt):
        # TODO: we have access to the personality here
        """Function creates and sends back an ICMP reply
        Args:
            eth_src : ethernet source address
            eth_dst : ethernet destination address
            ip_src : ip source address
            ip_dst : ip destination address
            i_type : type of the icmp reply
            i_code : code of the icmp reply
        """
        # truncate inner packet
        l = ip_pkt.get_ip_len()
        hdr = None
        if l > 1472:  # (MTU) 1500 - (IPv4) 20 - (ICMP) 8 = 1472
            hdr = ip_pkt.get_packet()[:1472]
        else:
            hdr = ip_pkt.get_packet()

        # icmp packet
        reply_icmp = ImpactPacket.ICMP()
        reply_icmp.set_icmp_type(i_type)
        reply_icmp.set_icmp_code(i_code)
        reply_icmp.set_icmp_id(0)
        reply_icmp.set_icmp_seq(0)
        reply_icmp.set_icmp_void(0)
        reply_icmp.contains(ImpactPacket.Data(hdr))
        reply_icmp.calculate_checksum()
        reply_icmp.auto_checksum = 1

        # ip packet
        reply_ip = ImpactPacket.IP()
        reply_ip.set_ip_v(4)
        reply_ip.set_ip_p(1)
        reply_ip.set_ip_rf(False)
        reply_ip.set_ip_df(False)
        reply_ip.set_ip_mf(False)
        reply_ip.set_ip_src(ip_src)
        reply_ip.set_ip_dst(ip_dst)
        reply_ip.set_ip_id(
            random.randint(0, 50000)
        )  # TODO: provide IP IDs according to personality, altough tracepath does not care
        reply_ip.contains(reply_icmp)

        # ethernet frame
        reply_eth = ImpactPacket.Ethernet()
        reply_eth.set_ether_type(0x800)
        eth_src = [int(i, 16) for i in eth_src.split(':')]
        eth_dst = [int(i, 16) for i in eth_dst.split(':')]
        reply_eth.set_ether_shost(eth_src)
        reply_eth.set_ether_dhost(eth_dst)
        reply_eth.contains(reply_ip)

        logger.debug('Sending reply: %s', reply_eth)
        # send raw frame
        try:
            self.pcapy_object.sendpacket(reply_eth.get_packet())
        except pcapy.PcapError as ex:
            logger.exception('Exception: Cannot send reply packet: %s', ex)
Ejemplo n.º 4
0
 def send_ns_packet(self,
                    source_link,
                    send_frequency,
                    target_address,
                    vlan_id=0):
     ip = IP6.IP6()
     ip.set_source_address(self.get_source_address())
     ip.set_destination_address(self.get_target_address())
     ip.set_traffic_class(0)
     ip.set_flow_label(0)
     ip.set_hop_limit(255)
     s = socket(AF_PACKET, SOCK_RAW, IPPROTO_ICMPV6)
     s.bind((self.network_card, N))
     payload = self.create_ns_message(source_link, target_address)
     print send_frequency
     for i in range(0, send_frequency):
         icmp = ICMP6.ICMP6()
         icmp.set_byte(0, 135)  # Put Type?
         icmp.set_byte(1, 00)  # Put Code?
         payloadObject = ImpactPacket.Data()
         payloadObject.set_data(payload)
         icmp.contains(payloadObject)
         ip.contains(icmp)
         ip.set_next_header(ip.child().get_ip_protocol_number())
         ip.set_payload_length(ip.child().get_size())
         eth = ImpactPacket.Ethernet(
             '\x33\x33\x00\x00\x00\x01\xff\xff\xff\xff\xff\xff\x81\x00')
         eth.pop_tag()
         if vlan_id != 0:
             vlan = ImpactPacket.EthernetTag()
             vlan.set_vid(vlan_id)
             eth.push_tag(vlan)
         icmp.calculate_checksum()
         eth.contains(ip)
         s.send(eth.get_packet())
Ejemplo n.º 5
0
 def sendpacket(self, data):
     ipe = ImpactPacket.Ethernet()
     ipe.set_ether_dhost(self.MACADDRESS)
     ipd = ImpactPacket.Data(data)
     ipd.ethertype = 0x86dd  # Ethertype for IPv6
     ipe.contains(ipd)
     p = ipe.get_packet()
     self.s.send(p)
Ejemplo n.º 6
0
    def buildAnswer(self, in_onion):
        eth = ImpactPacket.Ethernet()
        ip = ImpactPacket.IP()

        eth.contains(ip)

        eth.set_ether_shost(in_onion[O_ETH].get_ether_dhost())
        eth.set_ether_dhost(in_onion[O_ETH].get_ether_shost())

        ip.set_ip_src(in_onion[O_IP].get_ip_dst())
        ip.set_ip_dst(in_onion[O_IP].get_ip_src())
        ip.set_ip_id(self.machine.getIPID())

        return [eth, ip]
Ejemplo n.º 7
0
def main():
    signal.signal(signal.SIGALRM, lambda *args: handle_alarm())
    #build ethernet frame
    eth = ImpactPacket.Ethernet()
    eth.set_ether_type(0x88b5)
    eth.set_ether_shost(ETH_MY_MAC)
    eth.set_ether_dhost(ETH_MY_MAC)

    #build ip packet
    ip = ImpactPacket.IP()
    ip.set_ip_v(4)
    ip.set_ip_len(32)
    ip.set_ip_src("127.0.0.1")
    ip.set_ip_dst("127.0.0.1")

    #build UDP packet
    udp = ImpactPacket.UDP()
    udp.set_uh_sport(62000)
    udp.set_uh_dport(62001)
    udp.set_uh_ulen(12)

    inp1 = ''

    print "Client.... Port: " + str(udp.get_uh_sport())
    print "--------------------------------------------"

    while (len(inp1) != 4):
        inp1 = raw_input('Enter 4-bit ASCII nonce to send: ')
        if (len(inp1) != 4):
            print "Enter 4-bit ASCII"

    payload = inp1
    udp.contains(ImpactPacket.Data(payload))

    ip.contains(udp)
    eth.contains(ip)

    device = 'lo'

    s = socket.socket(socket.AF_PACKET, socket.SOCK_RAW, socket.htons(0x88b5))
    s.bind((device, 0))

    s.send(eth.get_packet())

    print "Sent: " + inp1

    receiveReply()
Ejemplo n.º 8
0
 def get_arp(self, sha, spa, tha, tpa, arp_type):
     ethernet_layer = ImpactPacket.Ethernet()
     arp_layer = ImpactPacket.ARP()
     ethernet_layer.contains(arp_layer)
     arp_layer.set_ar_hrd(1)  # Hardware type Ethernet
     arp_layer.set_ar_pro(0x800)  # IP
     arp_layer.set_ar_op(arp_type)
     arp_layer.set_ar_hln(6)
     arp_layer.set_ar_pln(4)
     arp_layer.set_ar_sha(
         self.addresses_helper.get_mac_in_list_format2(sha))
     arp_layer.set_ar_spa(self.addresses_helper.get_ip_in_list_format(spa))
     arp_layer.set_ar_tha(
         self.addresses_helper.get_mac_in_list_format2(tha))
     arp_layer.set_ar_tpa(self.addresses_helper.get_ip_in_list_format(tpa))
     ethernet_layer.set_ether_shost(arp_layer.get_ar_sha())
     ethernet_layer.set_ether_dhost(arp_layer.get_ar_tha())
     return ethernet_layer
Ejemplo n.º 9
0
    def buildAnswer(self, in_onion):
        eth = ImpactPacket.Ethernet()
        arp = ImpactPacket.ARP()
        eth.contains(arp)

        arp.set_ar_hrd(1)  # Hardward type Ethernet
        arp.set_ar_pro(0x800)  # IP
        arp.set_ar_op(2)  # REPLY
        arp.set_ar_hln(6)
        arp.set_ar_pln(4)
        arp.set_ar_sha(string2tuple(self.machine.macAddress))
        arp.set_ar_spa(string2tuple(self.machine.ipAddress))
        arp.set_ar_tha(in_onion[O_ARP].get_ar_sha())
        arp.set_ar_tpa(in_onion[O_ARP].get_ar_spa())

        eth.set_ether_shost(arp.get_ar_sha())
        eth.set_ether_dhost(arp.get_ar_tha())

        return [eth, arp]
Ejemplo n.º 10
0
    def arp_reply(self, arp_pkt):
        """Function creates and sends back an ARP reply
        Args:
            arp_pkt : received arp packet
        """
        # arp packet
        reply_arp = ImpactPacket.ARP()
        reply_arp.set_ar_hln(6)  # Ethernet size 6
        reply_arp.set_ar_pln(4)  # IPv4 size 4
        reply_arp.set_ar_hrd(
            1)  # 1:'ARPHRD ETHER', 6:'ARPHRD IEEE802', 15:'ARPHRD FRELAY'
        reply_arp.set_ar_op(
            2
        )  # 1:'REQUEST', 2:'REPLY', 3:'REVREQUEST', 4:'REVREPLY', 8:'INVREQUEST', 9:'INVREPLY'
        reply_arp.set_ar_pro(0x800)  # IPv4 0x800
        mac = [int(i, 16) for i in self.mac.split(':')]
        target_ip = unicode('.'.join(map(str, arp_pkt.get_ar_tpa())))
        for d in self.devices:
            if target_ip in d.bind_list:
                mac = [int(i, 16) for i in d.mac.split(':')]
                break
        reply_arp.set_ar_sha(mac)
        reply_arp.set_ar_tha(arp_pkt.get_ar_sha())
        reply_arp.set_ar_spa(arp_pkt.get_ar_tpa())
        reply_arp.set_ar_tpa(arp_pkt.get_ar_spa())

        # ethernet frame
        reply_eth = ImpactPacket.Ethernet()
        reply_eth.set_ether_type(0x800)
        reply_eth.set_ether_shost(mac)
        reply_eth.set_ether_dhost(arp_pkt.get_ar_sha())
        reply_eth.contains(reply_arp)

        logger.debug('Sending reply: %s', reply_eth)
        # send raw frame
        try:
            self.pcapy_object.sendpacket(reply_eth.get_packet())
        except pcapy.PcapError as ex:
            logger.exception('Exception: Cannot send reply packet: %s', ex)
Ejemplo n.º 11
0
    def packet(self, target, packet):
        """Function forging a packet for connection con. Only L1-3 get created.
        """
        ethhead = ImpactPacket.Ethernet()
        iphead = ImpactPacket.IP()
        if target == Connection.HEAD:
            # Set MACs:
            ethhead.set_ether_shost(self.tail.mac)
            ethhead.set_ether_dhost(self.head.mac)
            # Set IPs
            iphead.set_ip_src(self.tail.ipaddr)
            iphead.set_ip_dst(self.head.ipaddr)
        # target == TCPConnection.TAIL
        else:
            # Set MACs:
            ethhead.set_ether_dhost(self.tail.mac)
            ethhead.set_ether_shost(self.head.mac)
            # Set IPs
            iphead.set_ip_dst(self.tail.ipaddr)
            iphead.set_ip_src(self.head.ipaddr)

        iphead.contains(packet)
        ethhead.contains(iphead)
        return ethhead
Ejemplo n.º 12
0
def build_ethernet_reply(eth, proto):
    reply = ImpactPacket.Ethernet()
    reply.set_ether_dhost(eth.get_ether_shost())
    reply.set_ether_shost(OUR_MAC_ARRAY)
    reply.set_ether_type(proto)
    return reply
    def __init__(self,
                 max_rate=2500,
                 num_flows=10000,
                 pkt_size=100,
                 flow_size_cdf={
                     0.999: 10,
                     0.9999: 100,
                     0.99999: 1000,
                     1.0: 100000,
                 },
                 num_src_machines=100,
                 num_dst_machines=100,
                 iface="eth0",
                 batch_size=1,
                 entity='e',
                 workspace='w'):
        '''
        Initialize a packet generator instance with the specified
        parameters:
        
        - max_rate: maximum bitrate to gen packets in kbps
        - num_flows: total num of active flows at any given time
        - pkt_size: packet size
        - dst_ports_pdf: a dict mapping cdf -> port num
                         "random" can be used instead of port num.
        - flow_size_pdf: a dict mapping cdf -> flow sizes in packets
        - num_src/dst_machines: total number of machines this flow generator 
                        will simulate
        - src/dst_ip_prefix: subnet the machines will use as source and dst addresses
                     format: "x.x.x.x/int"
        - src/dst_mac_prefix: specify the macs for the machines. format:"xx:xx:xx:xx:xx:xx/int"
        - src/dst_mac_list: If specified, this will override the prefix
        - iface: name of interface to send packets on
        '''

        self.batch_size = batch_size

        self.max_flows = num_flows
        self.flow_size_cdf = flow_size_cdf
        self.pkt_size = pkt_size
        self.cdf_counter = 0

        self.workspace = workspace
        self.entity = entity

        # Calculate the delay between packets to maintain bitrate
        self.delay = self.batch_size * pkt_size * 8.0 / max_rate / 1000

        #print "Delay: %s ms" % (self.delay*1000)

        # maintains the active flow set
        self.flows = []

        # what flow should a packet come from?
        self.next_flow = 0

        # socket to use
        if AS_ROOT:
            e = dts.Entity(iface, entity, True)
            print 'Entity "{}" registered.'.format(e.title)

            w = dts.Workspace(iface, workspace)

            try:
                w.attach(e)
                print 'Attached to workspace "{}".'.format(w.title)
            except dts.DTSException:
                # Failed to attach, probably does not exists,
                # then try to create
                w.create_on_dts(e)
                print 'Created workspace "{}" and attached to it.'.format(
                    w.title)

        super(FlowGenerator, self).__init__()

        self.total_sent = 0

        # cache the creation of a packet
        self.eth = ImpactPacket.Ethernet()
        self.ip = ImpactPacket.IP()
        self.udp = ImpactPacket.UDP()

        data_len = (pkt_size - self.eth.get_header_size() -
                    self.ip.get_header_size() - self.udp.get_header_size())
        data = ImpactPacket.Data()
        data.set_bytes(array.array('B', [i % 0xff for i in range(data_len)]))

        self.udp.contains(data)
        self.ip.contains(self.udp)
        self.eth.contains(self.ip)

        self.calibrated = False
def randomMAC():
    mac = (random.randint(0x00, 0xff), random.randint(0x00, 0xff),
           random.randint(0x00, 0xff), random.randint(0x00, 0xff),
           random.randint(0x00, 0xff), random.randint(0x00, 0xff))
    return mac


#Generate arp packets with randomly
#s = socket(AF_INET, SOCK_RAW)
s = socket(AF_PACKET, SOCK_RAW)
s.bind(("h4-eth0", 0x0806))

pktid = 0
while (pktid <= 100000000):
    eth = ImpactPacket.Ethernet()
    forged_mac = randomMAC()
    eth.set_ether_shost(randomMAC())
    eth.set_ether_dhost(randomMAC())
    eth.set_ether_type(0x0806)
    print "send packet #", pktid, "with src_mac:", ':'.join(
        map(lambda x: "%02x" % x, forged_mac))
    arp = ImpactPacket.ARP(
    )  # create the arp packet that will be inside of layer 1
    arp.set_ar_hrd(0x0001)  #  set hardware type to  ARPHRD ETHER  (ethernet)
    arp.set_ar_op(
        0x01
    )  # Set tyoe to Arp Reply (0x02 = Reply, 0x04 = RevReply, 0x03 = RevRequest)
    arp.set_ar_pro(0x800)  # 2048 (Set to standard IP protocol)
    arp.set_ar_hln(6)  # Length should be 6 (octaves of mac address)
    arp.set_ar_pln(4)  # should be 4 (octaves of i.p. address)
Ejemplo n.º 15
0
def main():
    import sys
    DEFAULT_PROTOCOLS = ('tcp', )
    sockets = []

    print version.BANNER

    parser = argparse.ArgumentParser()
    parser.add_argument(
        "-i",
        metavar='FILE',
        help=
        'pcap file to read packets. If not specified the program sniffes traffic (only as root)'
    )
    parser.add_argument(
        "-o",
        metavar='FILE',
        help='pcap output file where the packets with errors will be written')

    options = parser.parse_args()

    outFile = options.o

    if options.i is None:
        sniffTraffic = True
        toListen = DEFAULT_PROTOCOLS
    else:
        sniffTraffic = False
        inFile = options.i

    packetNum = 0

    if outFile:
        f_out = open(outFile, 'wb')
        f_out.write(str(pcapfile.PCapFileHeader()))

    if sniffTraffic is False:
        f_in = open(inFile, 'rb')

        hdr = pcapfile.PCapFileHeader()
        hdr.fromString(f_in.read(len(hdr)))
        decoder = ImpactDecoder.EthDecoder()
    else:
        for protocol in toListen:
            try:
                protocol_num = socket.getprotobyname(protocol)
            except socket.error:
                print "Ignoring unknown protocol:", protocol
                toListen.remove(protocol)
                continue
            s = socket.socket(socket.AF_INET, socket.SOCK_RAW, protocol_num)
            s.setsockopt(socket.IPPROTO_IP, socket.IP_HDRINCL, 1)
            sockets.append(s)
            print "Listening on protocols:", toListen
        decoder = ImpactDecoder.IPDecoder()

    while 1:
        if sniffTraffic is False:
            pkt = pcapfile.PCapFilePacket()
            try:
                pkt.fromString(f_in.read(len(pkt)))
            except:
                break
            pkt['data'] = f_in.read(pkt['savedLength'])
            p = pkt['data']
        else:
            ready = select(sockets, [], [])[0]
            for s in ready:
                p = s.recvfrom(4096)[0]
                if 0 == len(p):
                    # Socket remotely closed. Discard it.
                    sockets.remove(s)
                    s.close()

        packet = decoder.decode(p)
        packetNum += 1
        if sniffTraffic is True:
            instance = packet.child()
        else:
            instance = packet.child().child()

        if isinstance(instance, ImpactPacket.TCP):
            tcppacket = instance
            if tcppacket.get_th_sport() == 445 or tcppacket.get_th_dport(
            ) == 445 or tcppacket.get_th_sport(
            ) == 139 or tcppacket.get_th_dport() == 139:
                data = tcppacket.child()
                if data.get_size() > 0:
                    logPacket = process(data, packetNum)
                    if logPacket is True:
                        pkt_out = pcapfile.PCapFilePacket()
                        if sniffTraffic is True:
                            eth = ImpactPacket.Ethernet()
                            eth.contains(packet)
                            eth.set_ether_type(0x800)
                            pkt_out['data'] = eth.get_packet()
                        else:
                            pkt_out['data'] = str(p)
                        if outFile:
                            f_out.write(str(pkt_out))
Ejemplo n.º 16
0
    def handle_packet(self, ethernet_packet, path, event, tunnels, cb_tunnel=None):
        """Forwards packet to the appropriate protocol handler based on configuration
        Args:
            ethernet_packet : intercepted packet
            path : length of the patch in the virtual network
            event : extracted attack-related information
            tunnels : opened network tunnels
            cb_tunnel : callback function for data extraction
        Return:
            constructed reply packet
        """
        reply = None
        ip_packet = ethernet_packet.child()
        eth_dst = ethernet_packet.get_ether_shost()

        for protocol_name, protocol_number, protocol_class in self.protocol_mapping:
            if event['protocol'] == protocol_number:
                # search for defined services
                for service in self.service_list:
                    if protocol_name == service[0] and event['port_dst'] == service[1]:
                        try:
                            if service[2] == 'filtered':
                                reply = protocol_class.filtered(
                                    ip_packet, path, self.personality, cb_ipid=self.get_ip_id, cb_icmpid=self.get_icmp_id)

                            elif service[2] == 'closed':
                                reply = protocol_class.closed(
                                    ip_packet,
                                    path,
                                    self.personality,
                                    cb_cipid=self.get_cip_id,
                                    cb_tcpseq=self.get_tcp_seq,
                                    cb_tcpts=self.get_tcp_ts)

                            elif service[2] == 'open':
                                reply = protocol_class.opened(
                                    ip_packet,
                                    path,
                                    self.personality,
                                    cb_ipid=self.get_ip_id,
                                    cb_tcpseq=self.get_tcp_seq,
                                    cb_tcpts=self.get_tcp_ts)

                            elif service[2] == 'block':
                                reply = protocol_class.blocked(ip_packet, path, self.personality)

                            elif service[2].startswith('proxy '):
                                proxy_data = service[2][len('proxy '):].split(':')
                                proxy_ip = ipaddress.ip_address(unicode(proxy_data[0]))
                                # proxy_mode = proxy_data[1]

                                # find configured tunnel interface
                                for tunnel_interface, remote_ip, tunnel_mode in tunnels:

                                    # self.interface, self.remote_ip, self.tunnel_mode
                                    if remote_ip == proxy_ip:

                                        # update ttl
                                        delta_ttl = ip_packet.get_ip_ttl() - path
                                        ip_packet.set_ip_ttl(delta_ttl)
                                        ip_packet.auto_checksum = 1

                                        # create tunnel outer encapsulation # IPPROTO_GRE || IPPROTO_IPIP
                                        if tunnel_mode == 'gre':
                                            s = gevent.socket.socket(
                                                gevent.socket.AF_PACKET, gevent.socket.SOCK_RAW, gevent.socket.IPPROTO_GRE)
                                            s.sendto(ip_packet.get_packet(), (tunnel_interface, 0x0800))
                                        else:
                                            s = gevent.socket.socket(
                                                gevent.socket.AF_PACKET, gevent.socket.SOCK_RAW, gevent.socket.IPPROTO_IPIP)
                                            s.sendto(ip_packet.get_packet(), (tunnel_interface, 0x0800))

                                        reply_ip = cb_tunnel(proxy_ip)
                                        if reply_ip is None:
                                            return None
                                        delta_ttl = reply_ip.get_ip_ttl() - path
                                        if delta_ttl < 1:
                                            logger.debug('Reply packet dropped: TTL reached 0 within virtual network.')
                                            return
                                        reply_ip.set_ip_ttl(delta_ttl)
                                        reply_ip.auto_checksum = 1
                                        reply_ip.set_ip_src(ip_packet.get_ip_dst())

                                        reply_eth = ImpactPacket.Ethernet()
                                        reply_eth.set_ether_type(0x800)
                                        reply_eth.set_ether_shost(self.ethernet)
                                        reply_eth.set_ether_dhost(eth_dst)

                                        reply_eth.contains(reply_ip)
                                        return reply_eth

                                else:
                                    logger.error('Error: No interface found for proxy IP %s', proxy_data[0])
                                    break
                                return None
                            else:
                                # script is excpected to provide proper IP packet as a reply as series of
                                # bytes through stdout
                                script = gevent.subprocess.Popen(
                                    service[2],
                                    shell=True,
                                    stdin=gevent.subprocess.PIPE,
                                    stdout=gevent.subprocess.PIPE,
                                    stderr=gevent.subprocess.PIPE)
                                try:
                                    output, error = script.communicate(input=ip_packet.get_packet(), timeout=10)
                                    if not len(output):
                                        return None
                                    try:
                                        reply = self.decoder.decode(output)
                                    except BaseException:
                                        try:
                                            reply = self.decoder_icmp.decode(output)
                                        except BaseException:
                                            logger.exception(
                                                'Exception: Cannot decode packet from script.')
                                            return None

                                    if len(error):
                                        logger.info('Service log: %s', error)

                                    inner_packet = reply.child()
                                    # TCP
                                    if reply.get_ip_p() == 6:
                                        inner_packet.set_th_sport(event['port_dst'])
                                        inner_packet.set_th_dport(event['port_src'])
                                        inner_packet.set_th_seq(self.get_tcp_seq())
                                        inner_packet.calculate_checksum()
                                        reply.contains(inner_packet)
                                    # UDP
                                    elif reply.get_ip_p() == 17:
                                        inner_packet.set_uh_sport(event['port_dst'])
                                        packet = ip_packet.child()
                                        inner_packet.set_uh_dport(event['port_src'])
                                        inner_packet.calculate_checksum()
                                        reply.contains(inner_packet)

                                    # IP
                                    reply.set_ip_id(self.get_ip_id())
                                    reply.set_ip_src(ip_packet.get_ip_dst())
                                    reply.set_ip_dst(ip_packet.get_ip_src())
                                    reply.auto_checksum = 1

                                except gevent.subprocess.TimeoutExpired:
                                    logger.exception('Exception: script timeout expired.')
                                    script.kill()
                                    return None
                                except BaseException:
                                    logger.exception('Exception: script subprocess error.')
                                    script.kill()
                                    return None

                        except Exception as ex:
                            # log exception
                            logger.exception('Exception: Device %s with issue: %s', self.name, ex)
                            return None

                        if reply is not None:
                            reply_eth = ImpactPacket.Ethernet()
                            reply_eth.set_ether_type(0x800)
                            reply_eth.set_ether_shost(self.ethernet)
                            reply_eth.set_ether_dhost(eth_dst)

                            reply_eth.contains(reply)
                            return reply_eth
                        return None

                # check default actions
                try:
                    if self.action_dictionary[protocol_name] == 'filtered':
                        reply = protocol_class.filtered(
                            ip_packet, path, self.personality, cb_ipid=self.get_ip_id, cb_icmpid=self.get_icmp_id)

                    elif self.action_dictionary[protocol_name] == 'closed':
                        reply = protocol_class.closed(
                            ip_packet,
                            path,
                            self.personality,
                            cb_cipid=self.get_cip_id,
                            cb_tcpseq=self.get_tcp_seq,
                            cb_tcpts=self.get_tcp_ts)

                    elif self.action_dictionary[protocol_name] == 'open':
                        reply = protocol_class.opened(
                            ip_packet,
                            path,
                            self.personality,
                            cb_ipid=self.get_ip_id,
                            cb_tcpseq=self.get_tcp_seq,
                            cb_tcpts=self.get_tcp_ts)

                    elif self.action_dictionary[protocol_name] == 'block':
                        reply = protocol_class.blocked(ip_packet, path, self.personality)

                    elif self.action_dictionary[protocol_name].startswith('proxy '):
                        proxy_data = self.action_dictionary[protocol_name][len('proxy '):].split(':')
                        proxy_ip = ipaddress.ip_address(unicode(proxy_data[0]))
                        proxy_mode = proxy_data[1]

                        # find configured tunnel interface
                        for tunnel_interface, remote_ip, tunnel_mode in tunnels:

                            # self.interface, self.remote_ip, self.tunnel_mode
                            if remote_ip == proxy_ip:

                                # update ttl
                                delta_ttl = ip_packet.get_ip_ttl() - path
                                ip_packet.set_ip_ttl(delta_ttl)
                                ip_packet.auto_checksum = 1

                                # create tunnel outer encapsulation # IPPROTO_GRE || IPPROTO_IPIP
                                if tunnel_mode == 'gre':
                                    s = gevent.socket.socket(
                                        gevent.socket.AF_PACKET, gevent.socket.SOCK_RAW, gevent.socket.IPPROTO_GRE)
                                    s.sendto(ip_packet.get_packet(), (tunnel_interface, 0x0800))
                                else:
                                    s = gevent.socket.socket(
                                        gevent.socket.AF_PACKET, gevent.socket.SOCK_RAW, gevent.socket.IPPROTO_IPIP)
                                    s.sendto(ip_packet.get_packet(), (tunnel_interface, 0x0800))

                                reply_ip = cb_tunnel()
                                if reply_ip is None:
                                    return None
                                delta_ttl = reply_ip.get_ip_ttl() - path
                                if delta_ttl < 1:
                                    logger.debug('Reply packet dropped: TTL reached 0 within virtual network.')
                                    return
                                reply_ip.set_ip_ttl(delta_ttl)
                                reply_ip.auto_checksum = 1
                                reply_ip.set_ip_src(ip_packet.get_ip_dst())
                                reply_ip.set_ip_dst(ip_packet.get_ip_src())
                                reply = reply_ip

                                break
                        else:
                            logger.error('Error: No interface found for proxy IP %s', proxy_data[0])
                        return None

                except Exception as ex:
                    # log exception
                    logger.exception('Exception: Device %s with issue: %s', self.name, ex)

                if reply is not None:
                    reply_eth = ImpactPacket.Ethernet()
                    reply_eth.set_ether_type(0x800)
                    try:
                        reply_eth.set_ether_shost(self.ethernet)
                    except IndexError:
                        logger.exception('Exception: Invalid ethernet format: %s', self.ethernet)
                    reply_eth.set_ether_dhost(eth_dst)

                    reply_eth.contains(reply)
                    return reply_eth
                return None