Beispiel #1
0
class coupler(app_manager.RyuApp):
    ''' This is the key to ryuretic: users should subclass the coupler in order
    to write their own programs. Look at the functions below: their definitions
    describe what should be done with each of the functions, and will note 
    whether or not that function is optional to override. '''
    OFP_VERSIONS = [ofproto_v1_3.OFP_VERSION]
    def __init__(self, *args, **kwargs):
        super(coupler, self).__init__(*args, **kwargs)
        
        #modules are added to the coupler as objects
        self.switch=SimpleSwitch()

    def get_proactive_rules(self,dp,parser,ofproto):
        ''' Proactive rules are installed here. By default, there are no 
        proactive rules. Users of Ryuretic should override this function if they
        have proactive rules to be installed. Optional.'''

        return None, None


    ######################################################################## 
    #This decorator calls initial_event for packet arrivals
    @set_ev_cls(ofp_event.EventOFPPacketIn, MAIN_DISPATCHER)
    def initial_event(self,ev):
        if ev.msg.msg_len < ev.msg.total_len:
            self.logger.debug("packet truncated: only %s of %s bytes",
                              ev.msg.msg_len, ev.msg.total_len)
        #Call <Pkt_Parse> to Build pkt object
        parsPkt = Pkt_Parse()
        pkt = parsPkt.handle_pkt(ev)
        
        # Call appropriate handler for arriving packets (add IPv6,DHCP,etc.)
        if pkt['udp'] != None:
            self.handle_udp(pkt)
        elif pkt['tcp'] != None:
            self.handle_tcp(pkt)
        elif pkt['icmp'] != None:
            self.handle_icmp(pkt)
        elif pkt['ip']!= None:
            self.handle_ip(pkt)
        elif pkt['arp']!=None:
            self.handle_arp(pkt)
        elif pkt['eth'] != None:
            self.handle_eth(pkt)
        else:
            print "Packet not identified"
            self.handle_unk(pkt)

    # The following functions all must be overridden. Some may be able to be
    # passed, but most will likely be overridden.

    def handle_eth(self,pkt):
        raise NotImplementedError("handle_eth must be overridden by child.")

    def handle_arp(self,pkt):
        raise NotImplementedError("handle_arp must be overridden by child.")

    def handle_ip(self,pkt):
        raise NotImplementedError("handle_ip must be overridden by child.")

    def handle_icmp(self,pkt):
        raise NotImplementedError("handle_ip must be overridden by child.")

    def handle_tcp(self,pkt):
        raise NotImplementedError("handle_ip must be overridden by child.")

    def handle_udp(self,pkt):
        raise NotImplementedError("handle_ip must be overridden by child.")

    def handle_unk(self,pkt):
        raise NotImplementedError("handle_ip must be overridden by child.")

    
                

	##################################################################
	# Supporting Code
	##################################################################
    #Initialize switch to send all packets to controller (lowest priority)
    # Adds a Table-miss flow entry (see page 8 of "Ryu: Using OpenFlow 1.3"
    @set_ev_cls(ofp_event.EventOFPSwitchFeatures, CONFIG_DISPATCHER)
    def switch_features_handler(self, ev):
        print "Received Switch features"
        datapath = ev.msg.datapath
        ofproto = datapath.ofproto
        parser = datapath.ofproto_parser
        
        # install table-miss flow entry
        match = parser.OFPMatch()
        actions = [parser.OFPActionOutput(ofproto.OFPP_CONTROLLER,
                                          ofproto.OFPCML_NO_BUFFER)]
	self.add_flow(datapath, 0, match, actions)
	fields, ops = self.get_proactive_rules(datapath,parser,ofproto)
        if (fields is not None) and (ops is not None):
            _add_proactive_flow(dp, parser, ofproto, fields, ops)

	def _add_proactive_flow(dp, parser, ofproto, fields,ops):
            actions = []
            if ops['op'] == 'drop':
                out_port = ofproto.OFPPC_NO_RECV
                actions.append(parser.OFPActionOutput(out_port))
            if ops == 'redir':
                out_port = ops['newport']
                actions.append(parser.OFPActionOutput(out_port))
                
	    match = parser.OFPMatch(eth_type=fields['eth_type'], 
					ip_proto=fields['proto'], 
					ipv4_src=fields['srcip'], 
                                        ipv4_dst=fields['dstip'],
                                        tcp_dst = fields['srctcp'])
	    
	    self.add_flow(dp, ops['priority'], match, actions)
    
    ########################################################################
    # Adds flow to the switch so future packets aren't sent to the cntrl 
    
    def add_flow(self, datapath, priority, match, actions, buffer_id=None):
        ofproto = datapath.ofproto
        parser = datapath.ofproto_parser

        inst = [parser.OFPInstructionActions(ofproto.OFPIT_APPLY_ACTIONS,
                                             actions)]
        if buffer_id:
            mod = parser.OFPFlowMod(datapath=datapath, buffer_id=buffer_id,
                                    priority=priority, match=match,
                                    instructions=inst)
        else:
            mod = parser.OFPFlowMod(datapath=datapath, priority=priority,
                                    match=match, instructions=inst)
        datapath.send_msg(mod)    
       
    ########################################################################
    # Adds flow to the switch so future packets are not sent to the
    # controller (requires priority, idle_t, and hard_t)
    def add_timeFlow(self, dp, ops, match, actions):
        ofproto = dp.ofproto
        parser = dp.ofproto_parser
            
        inst = [parser.OFPInstructionActions(ofproto.OFPIT_APPLY_ACTIONS,
                                             actions)]
        #fix switch mod to address 'idle_t'
        mod = parser.OFPFlowMod(datapath=dp,
                            priority=ops['priority'],
                            idle_timeout=ops['idle_t'],
                            hard_timeout=ops['hard_t'],
                            match=match, instructions=inst)
        dp.send_msg(mod) 
		

    ############################################################    
    # Choose the field and ops having the highest priority and 
    # assert it.    
    def _build_FldOps(xfields,xops):
        priority = 0
        for x in len(xfields):
            if xfields[x]['priority'] > priority:
                fields,ops = xfields[x],xops[x]
        return fields,ops  
               
    ##############################################################        
    #Imeplement mac-learning (switch_mod13.py) for ethernet packets.  
    def install_field_ops(self, pkt, fields, ops):
        #Build match from pkt and fields
        match = self.pkt_match(fields)
		#Build actions from pkt and ops
        actions = self.pkt_action(pkt,ops,fields)                            
        priority = ops['priority']
        msg = fields['msg']                          
        parser, ofproto = fields['dp'].ofproto_parser, fields['ofproto']

        # install temporary flow to avoid future packet_in. 
        # idle_t and hard_t must be set to something. 
        if ops['idle_t'] or ops['hard_t']:
            if out_port != ofproto.OFPP_FLOOD:
                self.add_timeFlow(dp, ops, match, actions)

        # For ping and wget, data = None
        data = None
        if msg.buffer_id == ofproto.OFP_NO_BUFFER:
            data = msg.data

        out = parser.OFPPacketOut(datapath=fields['dp'],
                                  buffer_id=msg.buffer_id,
                                  in_port=fields['inport'],
                                  actions=actions, data=data)

        fields['dp'].send_msg(out)

    #############################################################
    #Use fields to build match 
    def pkt_match(self, fields):
        parser = fields['dp'].ofproto_parser
        if fields['srcip'] != None and fields['srcip'] != None:
            match = parser.OFPMatch(ipv4_src=fields['srcip'], 
										ipv4_dst = fields['dst_ip'])
        elif fields['srcip'] != None or fields['srcip'] != None:
            matchfield=fields['srcip'] if fields['srcip'] !=None else fields['dstip']
            match = parser.OFPMatch(ipv4_src=matchfield)
        elif fields['srcmac'] == None:
            match = parser.OFPMatch(in_port=fields['inport'])
        else:
            match = parser.OFPMatch(in_port=fields['inport'],
                                    eth_dst=fields['dstmac'])
        return match

    ###############################################################
    #Determine action to be taken on packet ops={'op':None, 'newport':None}
    #User can forward , drop, redirect, mirror, or craft packets. 
    def pkt_action(self,pkt,ops,fields):
        actions = []
        parser = fields['dp'].ofproto_parser
        if ops['op'] == 'fwd':
            out_port = self.switch.handle_pkt(pkt)
            actions.append(parser.OFPActionOutput(out_port))
        elif ops['op'] == 'drop':
            out_port = fields['ofproto'].OFPPC_NO_RECV
            actions.append(parser.OFPActionOutput(out_port))
        elif ops == 'redir':
            out_port = ops['newport']
            actions.append(parser.OFPActionOutput(out_port))
        elif ops['op'] == 'mir':
            out_port = self.switch.handle_pkt(pkt)
            actions.append(parser.OFPActionOutput(out_port))
            mir_port = ops['newport']
            actions.append(parser.OFPActionOutput(mir_port))
        elif ops['op'] == 'craft':
            #create and send new pkt due to craft trigger
            self._build_pkt(ops, fields) ##need to remove pkt ##########
            #Now drop the arrived packet
            out_port = fields['ofproto'].OFPPC_NO_RECV
            actions.append(parser.OFPActionOutput(out_port))
                                                
        return actions

    #More work is required here to implement active testing for NATs etc.
    # Note fields object must be completely rewritten for crafted packet
    # Probably need to make fields['ptype'] = ['arp', 'ipv4']
    def _build_pkt(self, fields):
        pkt_out = packet.Packet()
        pkt_out.add_protocol(ethernet.ethernet(ethertype=fields['ethtype'],
                                               dst=fields['dstmac'],
                                               src=fields['srcmac']))
        # Add if ARP is required                           
                            
        if 'arp' in fields['ptype']:
            pkt_out.add_protocol(arp.arp(opcode=arp.ARP_REPLY,
                                 src_mac=fields['srcmac'],
                                 src_ip=fields['srcip'],
                                 dst_mac=fields['dstmac'],
                                 dst_ip=fields['dstip']))

        if ipv4 in fields['ptype']:
            pkt_out.add_protocol(ipv4.ipv4(dst=fields['dstip'],
                                 src=fields['srcip'],
                                 proto=fields['proto']))

        if 'icmp' in fields['ptype']:
            pkt_out.add_protocol(icmp.icmp(type_=icmp.ICMP_ECHO_REPLY,
                                 code=icmp.ICMP_ECHO_REPLY_CODE,
                                 csum=0,
                                 data=fields['data']))
								 
        if 'tcp' in fields['ptype']:
            pkt_out.add_protocol(tcp.tcp(dst_port=fields['dstport'],
				bits=fields['bits'],option=fields['opt'],
                                #=str('\\x00' * 4),
                                src_port=fields['srcport']))
                             
        #pkt.add_protocol('\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\
            #\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\
            #\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f')

        self._send_packet(fields['dp'], ops['newport'], pkt_out)
	
	#Receive crafted packet and send it to the switch
    def _send_packet(self, datapath, port, pkt_out):
        if port == None: print "Port not defined" 
        #This methods sends the crafted message to the switch
        ofproto = datapath.ofproto
        parser = datapath.ofproto_parser
        pkt_out.serialize()
        self.logger.info("packet-out %s" % (pkt_out,))
        data = pkt_out.data
        actions = [parser.OFPActionOutput(port=port)]
        out = parser.OFPPacketOut(datapath=datapath,
                                  buffer_id=ofproto.OFP_NO_BUFFER,
                                  in_port=ofproto.OFPP_CONTROLLER,
                                  actions=actions,
                                  data=data)
        datapath.send_msg(out)
		
    #Clean up and disconnect ports. Controller going down  
    @set_ev_cls(ofp_event.EventOFPPortStatus, MAIN_DISPATCHER)
    def handl_port_stat(self, ev):
        switch=SimpleSwitch()
        switch.port_status_handler(ev)
Beispiel #2
0
class coupler(app_manager.RyuApp):
    ''' This is the key to ryuretic: users should subclass the coupler
    in order to write their own programs. Look at the functions below:
    their definitions describe what should be done with each of the
    functions, and will note whether or not that function is optional
    to override. '''
    OFP_VERSIONS = [ofproto_v1_3.OFP_VERSION]
    def __init__(self, *args, **kwargs):
        super(coupler, self).__init__(*args, **kwargs)
        
        #modules are added to the coupler as objects
        self.switch=SimpleSwitch()

    def get_proactive_rules(self,dp,parser,ofproto):
        ''' Proactive rules are installed here. By default, there are no 
        proactive rules. Users of Ryuretic should override this function if they
        have proactive rules to be installed. Optional.'''

        return None, None


    ######################################################################## 
    #This decorator calls initial_event for packet arrivals
    @set_ev_cls(ofp_event.EventOFPPacketIn, MAIN_DISPATCHER)
    def initial_event(self,ev):
        if ev.msg.msg_len < ev.msg.total_len:
            self.logger.debug("packet truncated: only %s of %s bytes",
                              ev.msg.msg_len, ev.msg.total_len)
        #Call <Pkt_Parse> to Build pkt object
        parsPkt = Pkt_Parse()
        pkt = parsPkt.handle_pkt(ev)
        
        # Call appropriate handler for arriving packets (add IPv6,DHCP,etc.)
        if pkt['udp'] != None:
            self.handle_udp(pkt)
        elif pkt['tcp'] != None:
            self.handle_tcp(pkt)
        elif pkt['icmp'] != None:
            self.handle_icmp(pkt)
        elif pkt['ip']!= None:
            self.handle_ip(pkt)
        elif pkt['arp']!=None:
            self.handle_arp(pkt)
        elif pkt['eth'] != None:
            self.handle_eth(pkt)
        else:
            print "Packet not identified"
            self.handle_unk(pkt)

    # The following functions all must be overridden. Some may be able to be
    # passed, but most will likely be overridden.

    def handle_eth(self,pkt):
        raise NotImplementedError("handle_eth must be overridden by child.")

    def handle_arp(self,pkt):
        raise NotImplementedError("handle_arp must be overridden by child.")

    def handle_ip(self,pkt):
        raise NotImplementedError("handle_ip must be overridden by child.")

    def handle_icmp(self,pkt):
        raise NotImplementedError("handle_ip must be overridden by child.")

    def handle_tcp(self,pkt):
        raise NotImplementedError("handle_ip must be overridden by child.")

    def handle_udp(self,pkt):
        raise NotImplementedError("handle_ip must be overridden by child.")

    def handle_unk(self,pkt):
        raise NotImplementedError("handle_ip must be overridden by child.")


    ##################################################################
    # Supporting Code
    ##################################################################
    #Initialize switch to send all packets to controller (lowest priority)
    # Adds a Table-miss flow entry (see page 8 of "Ryu: Using OpenFlow 1.3"
    @set_ev_cls(ofp_event.EventOFPSwitchFeatures, CONFIG_DISPATCHER)
    def switch_features_handler(self, ev):
        print "Received Switch features"
        datapath = ev.msg.datapath
        ofproto = datapath.ofproto
        parser = datapath.ofproto_parser
        
        # install table-miss flow entry
        match = parser.OFPMatch()
        actions = [parser.OFPActionOutput(ofproto.OFPP_CONTROLLER,
                                          ofproto.OFPCML_NO_BUFFER)]
	self.add_flow(datapath, 0, match, actions)
        ############################################################
	"""Now decide whether to add proactive flows or not"""

	fields, ops = self.get_proactive_rules(datapath,parser,ofproto)
        if (fields is not None) and (ops is not None):
            self._add_proactive_flow(datapath, parser, ofproto, fields, ops)
        ################################################################
            
    def _bld_match_vals(self, fields):
        match_vals = {}     
        fields_keys = fields['keys']
        if 'inport' in fields_keys:
            match_vals['in_port'] = fields['inport']
        if 'eth_type' in fields_keys:
            match_vals['eth_type'] = fields['eth_type']
        if 'srcmac' in fields_keys:
            match_vals['eth_src'] = fields['srcmac']
        if 'dstmac' in fields_keys:
            match_vals['eth_dst'] = fields['dstmac']
        if 'srcip' in fields_keys:
            match_vals['ipv4_src']= fields['srcip']
        if 'dstip' in fields_keys:
            match_vals['ipv4_dst'] = fields['dstip']
        if 'proto' in fields_keys:
            match_vals['ip_proto'] = fields['proto']
        if 'srcport' in fields_keys:
            match_vals['tcp_src'] = fields['srcport']
        if 'dstport' in fields_keys:
            match_vals['tcp_dst'] = fields['dstport']
        if 'data' in fields_keys:
            match_vals['data'] = fields['data']
        return match_vals        

    def _add_proactive_flow(self, datapath, parser, ofproto, fields,ops):
        actions = []
        if ops['op'] == 'drop':
            out_port = ofproto.OFPPC_NO_RECV
            actions.append(parser.OFPActionOutput(out_port))
        if ops == 'redir':
            out_port = ops['newport']
            actions.append(parser.OFPActionOutput(out_port))

        match_vals = self._bld_match_vals(fields)
        
        match = parser.OFPMatch(**match_vals)
        self.add_flow(datapath, ops['priority'], match, actions)
    
    ########################################################################
    # Adds flow to the switch so future packets aren't sent to the cntrl 
    def add_flow(self, datapath, priority, match, actions, buffer_id=None):
        ofproto = datapath.ofproto
        parser = datapath.ofproto_parser

        inst = [parser.OFPInstructionActions(ofproto.OFPIT_APPLY_ACTIONS,
                                             actions)]
        if buffer_id:
            mod = parser.OFPFlowMod(datapath=datapath, buffer_id=buffer_id,
                                    priority=priority, match=match,
                                    instructions=inst)
        else:
            mod = parser.OFPFlowMod(datapath=datapath, priority=priority,
                                    match=match, instructions=inst)
        datapath.send_msg(mod)    
       
    ########################################################################
    # Adds flow to the switch so future packets are not sent to the
    # controller (requires priority, idle_t, and hard_t)
    def add_timeFlow(self, dp, ops, match, actions):
        ofproto = dp.ofproto
        parser = dp.ofproto_parser
            
        inst = [parser.OFPInstructionActions(ofproto.OFPIT_APPLY_ACTIONS,
                                             actions)]
        #fix switch mod to address 'idle_t'
        mod = parser.OFPFlowMod(datapath=dp,
                            priority=ops['priority'],
                            idle_timeout=ops['idle_t'],
                            hard_timeout=ops['hard_t'],
                            match=match, instructions=inst)
        dp.send_msg(mod)
		
    ############################################################    
    # Choose the field and ops having the highest priority and assert it.    
    def _build_FldOps(xfields,xops):
        priority = 0
        for x in len(xfields):
            if xfields[x]['priority'] > priority:
                fields,ops = xfields[x],xops[x]
        return fields,ops  
               
    ##############################################################        
    #Imeplement mac-learning (switch_mod13.py) for ethernet packets.  
    def install_field_ops(self, pkt, fields, ops):
        #Build match from pkt and fields
        match = self.pkt_match(fields)
		#Build actions from pkt and ops
        out_port, actions = self.pkt_action(pkt,ops,fields)
        priority = ops['priority']
        msg = fields['msg']                          
        parser, ofproto = fields['dp'].ofproto_parser, fields['ofproto']
        
        # install temporary flow to avoid future packet_in. 
        # idle_t and hard_t must be set to something. 
        if ops['idle_t'] or ops['hard_t']:
            if out_port != ofproto.OFPP_FLOOD:
                self.add_timeFlow(fields['dp'], ops, match, actions)

        # For ping and wget, data = None
        data = None
        try:
            if msg.buffer_id == ofproto.OFP_NO_BUFFER:
                data = msg.data
        except:
            pass
        
        out = parser.OFPPacketOut(datapath=fields['dp'],
                                  buffer_id=msg.buffer_id,
                                  in_port=fields['inport'],
                                  actions=actions, data=data)
        fields['dp'].send_msg(out)

    #############################################################
    #Use fields to build match
    def pkt_match(self, fields):
        def build_match(fields):
            match_vals = {}     
            #fields_keys = fields.keys()
            print "FIELDS ARE: ", fields
            fields_keys = fields['keys']
            if 'inport' in fields_keys:
                match_vals['in_port'] = fields['inport']
            if 'eth_type' in fields_keys:
                match_vals['eth_type'] = fields['eth_type']
            if 'srcmac' in fields_keys:
                match_vals['eth_src'] = fields['srcmac']
            if 'dstmac' in fields_keys:
                match_vals['eth_dst'] = fields['dstmac']
            if 'srcip' in fields_keys:
                match_vals['ipv4_src']= fields['srcip']
            if 'dstip' in fields_keys:
                match_vals['ipv4_dst'] = fields['dstip']
            if 'proto' in fields_keys:
                match_vals['ip_proto'] = fields['proto']
            if 'srcport' in fields_keys:
                match_vals['tcp_src'] = fields['srcport']
            if 'dstport' in fields_keys:
                match_vals['tcp_dst'] = fields['dstport']
            if 'data' in fields_keys:
                match_vals['data'] = fields['data']
            return match_vals
        
        parser = fields['dp'].ofproto_parser
        match_vals = {}
        match_vals = build_match(fields)
        match = parser.OFPMatch(**match_vals)        
        return match

    ###############################################################
    #Determine action to be taken on packet ops={'op':None, 'newport':None}
    #User can forward , drop, redirect, mirror, or craft packets. 
    def pkt_action(self,pkt,ops,fields):
        actions = []
        parser = fields['dp'].ofproto_parser
        if ops['op'] == 'fwd':
            out_port = self.switch.handle_pkt(pkt)
            actions.append(parser.OFPActionOutput(out_port))
        elif ops['op'] == 'drop':
            out_port = fields['ofproto'].OFPPC_NO_RECV
            actions.append(parser.OFPActionOutput(out_port))
        elif ops['op'] == 'redir':
            out_port = ops['newport']
            actions.append(parser.OFPActionOutput(out_port))
        elif ops['op'] == 'mir':
            out_port = self.switch.handle_pkt(pkt)
            actions.append(parser.OFPActionOutput(out_port))
            mir_port = ops['newport']
            actions.append(parser.OFPActionOutput(mir_port))
        elif ops['op'] == 'craft':
            #create and send new pkt due to craft trigger
            self._build_pkt(fields, ops) 
            #Now drop the arrived packet
            out_port = fields['ofproto'].OFPPC_NO_RECV
            actions.append(parser.OFPActionOutput(out_port))
                                                
        return out_port, actions
    
    #More work is required here to implement active testing for NATs etc.
    # Note fields object must be completely rewritten for crafted packet
    # Probably need to make fields['ptype'] = ['arp', 'ipv4']
    def _build_pkt(self, fields, ops):
        pkt_out = packet.Packet()
        pkt_ipv4 = pkt_out.get_protocol(ipv4.ipv4)
        pkt_icmp = pkt_out.get_protocol(icmp.icmp)

        def addIPv4(pkt_out, fields):
            pkt_out.add_protocol(ipv4.ipv4(dst=fields['dstip'],
                                 src=fields['srcip'],
                                 proto=fields['proto']))
            return pkt_out

        pkt_out.add_protocol(ethernet.ethernet(ethertype=fields['ethtype'],
                                               dst=fields['dstmac'],
                                               src=fields['srcmac']))
        # Add if ARP                                           
        if 'arp' in fields['ptype']:
            pkt_out.add_protocol(arp.arp(opcode=arp.ARP_REPLY,
                                 src_mac=fields['srcmac'],
                                 src_ip=fields['srcip'],
                                 dst_mac=fields['dstmac'],
                                 dst_ip=fields['dstip']))
        # Add if IPv4
        if 'ipv4' in fields['ptype']:
            pkt_out = addIPv4(pkt_out,fields)
            
        # Add if ICMP
        if 'icmp' in fields['ptype']:
            pkt_out = addIPv4(pkt_out,fields)
            
            pkt_out.add_protocol(icmp.icmp(type_=icmp.ICMP_ECHO_REPLY,
                                 code=icmp.ICMP_ECHO_REPLY_CODE,
                                 csum=0,
                                 data=None))
        # Add if UDP    
        if 'udp' in fields['ptype']:
            pkt_out = addIPv4(pkt_out,fields)
            pkt_out.add_protocol(udp.udp(dst_port=fields['dstport'],
				bits=fields['bits'],option=fields['opt'],
                                src_port=fields['srcport']))
        # Add if TCP                         	 
        if 'tcp' in fields['ptype']:
            pkt_out = addIPv4(pkt_out,fields)
            pkt_out.add_protocol(tcp.tcp(dst_port=fields['dstport'],
				bits=fields['bits'],option=fields['opt'],
                                src_port=fields['srcport']))
        #Add covert channel information                    
        if fields['com'] != None:
            pkt_out.add_protocol(fields['com'])
            
        #Send crafted packet            
        self._send_packet(fields['dp'], ops['newport'], pkt_out)
	
    #Receive crafted packet and send it to the switch
    def _send_packet(self, datapath, port, pkt_out):
        if port == None: print "Port not defined" 
        #This methods sends the crafted message to the switch
        ofproto = datapath.ofproto
        parser = datapath.ofproto_parser
        #print pkt_out
        pkt_out.serialize()
        #self.logger.info("packet-out %s" % (pkt_out,))
        data = pkt_out.data
        actions = [parser.OFPActionOutput(port=port)]
        out = parser.OFPPacketOut(datapath=datapath,
                                  buffer_id=ofproto.OFP_NO_BUFFER,
                                  in_port=ofproto.OFPP_CONTROLLER,
                                  actions=actions,
                                  data=data)
        print "\nout: ", out, "\n"
        datapath.send_msg(out)
		
    #Clean up and disconnect ports. Controller going down  
    @set_ev_cls(ofp_event.EventOFPPortStatus, MAIN_DISPATCHER)
    def handl_port_stat(self, ev):
        switch=SimpleSwitch()
        switch.port_status_handler(ev)
Beispiel #3
0
class coupler(app_manager.RyuApp):
    OFP_VERSIONS = [ofproto_v1_3.OFP_VERSION]
    def __init__(self, *args, **kwargs):
        super(coupler, self).__init__(*args, **kwargs)
        #modules are added to the coupler as objects
        self.switch=SimpleSwitch()
        #created address for crafted packets
        self.hw_addr = 'aa:bb:cc:dd:ee:11'
        self.ip_addr = '10.0.0.25'
        ##############################################################
        #[2] Add Additional modules or object variables here or add
        #    definitions to the provided NFG_13.py file
        self.NFG = NFG()

	#######################################################################
	#[3]Insert proactive rules provided by NFG library, follow format below
	# Only offers drop and redirect options
	def get_proactive_rules(self,dp,parser,ofproto):
		pass
		#fields, ops = self.NFG.simpleFW()
		#self._add_proactive_flow(dp, parser, ofproto, fields, ops)
		
    #####################################################################
    #[4] Use below handles to direct arriving packets to modules in NFG.py; 
    #    modules return match fields (fields) and operations (ops) 
    #    hashes (determined by programmer). Ensure that fields,ops
    #    are only set once in each handle (comment out default_Field_Ops).
    ######################################################################
    #fields contains the following keys:
    #  {'keys':['inport','srcport'], 'ptype':None, 'inport':pkt['inport'],
    #  'srcmac':pkt['srcmac'], 'dstmac':None, 'srcip':None, 'dstip':None,
    #  'srcport':None, 'dstport':None}
    ######################################################################
    #ops contains the following keys:
    # {'hard_t':None, 'idle_t':None, 'priority':None, 'op':'fwd',
    #  'newport':None}
    # set *_t to 0 for permanent or >0 for temporary,
    # set * 'priority' to 0 for lowest
    # 'op':{'fwd', 'drop', 'mir' (mirror), 'newport' (redirect), 'craft'}
    # 'newport': used for mirror and redirect, otherwise None
    ######################################################################
    
    def handle_eth(self,pkt):
        print "handle eth"
        fields, ops = self.NFG.default_Field_Ops(pkt)
        #print pkt['eth']
        #fields, ops = check_list(pkt)
        #fields, ops = self.NFG.Check_List(pkt)
        self._switch_mod(pkt,fields,ops)

    def handle_arp(self,pkt):
        print "handle ARP"
        print pkt
        fields, ops = self.NFG.default_Field_Ops(pkt)
        #print pkt['arp']
        self._switch_mod(pkt, fields, ops)
		
    #Apply the most restrictive fields,ops (based on priority) are applied
    #to each packet. We will use priority to select.    
    def handle_ip(self,pkt):
	#print pkt['ip']
	#fields, ops = self.NFG.default_Field_Ops(pkt)
        print "handle ip"
        #fields2,ops2 = self.NFG.Stateful_FW(pkt)
	##############################################################
        #Determine highest priority fields and ops pair, if needed
        #xfields = [fields0, fields1, fields2]
        #xops = [ops0, ops1, ops2]
        #fields,ops = self._build_FldOps(xfields,xops)
	##############################################################
        
        self._switch_mod(pkt,fields,ops)

    def handle_icmp(self,pkt):
        print "handle icmp"
        fields, ops = self.NFG.default_Field_Ops(pkt)
        #print pkt['icmp'], '\n', pkt['ip']
        #fields, ops = self.NFG.TTL_Check(pkt)
        self._switch_mod(pkt, fields, ops)

    def handle_tcp(self,pkt):
        print "handle tcp"
        #fields, ops = self.NFG.default_Field_Ops(pkt)
        #fields,ops = self.NFG.Simple_FW(pkt)
        #print pkt['tcp']
        fields, ops = self.NFG.TTL_Check(pkt)
        # users can also call modules with no return
        #self.NFG.displayTCPFields(pkt)
        self._switch_mod(pkt, fields, ops)

    def handle_udp(self,pkt):
        print "handle udp"
        fields, ops = self.NFG.default_Field_Ops(pkt)
        #fields, ops = self.NFG.TTL_Check(pkt)
        self._switch_mod(pkt, fields, ops)

    def handle_unk(self,pkt):
        print "handl unk"
        fields, ops = self.NFG.default_Field_Ops(pkt)
        self._switch_mod(pkt, fields, ops)
		
	##################################################################
	# Supporting Code
	##################################################################
    #Initialize switch to send all packets to controller (lowest priority)
    # Adds a Table-miss flow entry (see page 8 of "Ryu: Using OpenFlow 1.3"
    @set_ev_cls(ofp_event.EventOFPSwitchFeatures, CONFIG_DISPATCHER)
    def switch_features_handler(self, ev):
        print "Received Switch features"
        datapath = ev.msg.datapath
        ofproto = datapath.ofproto
        parser = datapath.ofproto_parser
        
        # install table-miss flow entry
        match = parser.OFPMatch()
        actions = [parser.OFPActionOutput(ofproto.OFPP_CONTROLLER,
                                          ofproto.OFPCML_NO_BUFFER)]
	self.add_flow(datapath, 0, match, actions)
	#self._get_proactive_rules(datapath,parser,ofproto)

	def _add_proactive_flow(self,dp, parser, ofproto, fields,ops):
            actions = []
            if ops['op'] == 'drop':
                out_port = ofproto.OFPPC_NO_RECV
                actions.append(parser.OFPActionOutput(out_port))
            if ops == 'redir':
                out_port = ops['newport']
                actions.append(parser.OFPActionOutput(out_port))
                
	    match = parser.OFPMatch(eth_type=fields['eth_type'], 
					ip_proto=fields['proto'], 
					ipv4_src=fields['srcip'], 
                                        ipv4_dst=fields['dstip'],
                                        tcp_dst = fields['srctcp'])
	    
	    self.add_flow(dp, ops['priority'], match, actions)
    
    ########################################################################
    # Adds flow to the switch so future packets aren't sent to the cntrl 
    
    def add_flow(self, datapath, priority, match, actions, buffer_id=None):
        ofproto = datapath.ofproto
        parser = datapath.ofproto_parser

        inst = [parser.OFPInstructionActions(ofproto.OFPIT_APPLY_ACTIONS,
                                             actions)]
        if buffer_id:
            mod = parser.OFPFlowMod(datapath=datapath, buffer_id=buffer_id,
                                    priority=priority, match=match,
                                    instructions=inst)
        else:
            mod = parser.OFPFlowMod(datapath=datapath, priority=priority,
                                    match=match, instructions=inst)
        datapath.send_msg(mod)    
       
    ########################################################################
    # Adds flow to the switch so future packets are not sent to the
    # controller (requires priority, idle_t, and hard_t)
    def add_timeFlow(self, dp, ops, match, actions):
        ofproto = dp.ofproto
        parser = dp.ofproto_parser
            
        inst = [parser.OFPInstructionActions(ofproto.OFPIT_APPLY_ACTIONS,
                                             actions)]
        #fix switch mod to address 'idle_t'
        mod = parser.OFPFlowMod(datapath=dp,
                            priority=ops['priority'],
                            idle_timeout=ops['idle_t'],
                            hard_timeout=ops['hard_t'],
                            match=match, instructions=inst)
        dp.send_msg(mod) 
		
    ######################################################################## 
    #This decorator calls initial_event for packet arrivals
    @set_ev_cls(ofp_event.EventOFPPacketIn, MAIN_DISPATCHER)
    def initial_event(self,ev):
        if ev.msg.msg_len < ev.msg.total_len:
            self.logger.debug("packet truncated: only %s of %s bytes",
                              ev.msg.msg_len, ev.msg.total_len)
        #Call <Pkt_Parse> to Build pkt object
        parsPkt = Pkt_Parse()
        pkt = parsPkt.handle_pkt(ev)
        
        # Call appropriate handler for arriving packets (add IPv6,DHCP,etc.)
        if pkt['udp'] != None:
            self.handle_udp(pkt)
        elif pkt['tcp'] != None:
            self.handle_tcp(pkt)
        elif pkt['icmp'] != None:
            self.handle_icmp(pkt)
        elif pkt['ip']!= None:
            self.handle_ip(pkt)
        elif pkt['arp']!=None:
            self.handle_arp(pkt)
        elif pkt['eth'] != None:
            self.handle_eth(pkt)
        else:
            print "Packet not identified"
            self.handle_unk(pkt)

    ############################################################    
    # Choose the field and ops having the highest priority and 
    # assert it.    
    def _build_FldOps(xfields,xops):
        priority = 0
        for x in len(xfields):
            if xfields[x]['priority'] > priority:
                fields,ops = xfields[x],xops[x]
        return fields,ops  
               
    ##############################################################        
    #Imeplement mac-learning (switch_mod13.py) for ethernet packets.  
    def _switch_mod(self, pkt, fields, ops):
        #Build match from pkt and fields
        match = self.pkt_match(fields)
		#Build actions from pkt and ops
        actions = self.pkt_action(pkt,ops,fields)                            
        priority = ops['priority']
        msg = fields['msg']                          
        parser, ofproto = fields['dp'].ofproto_parser, fields['ofproto']

        # install temporary flow to avoid future packet_in. 
        # idle_t and hard_t must be set to something. 
        if ops['idle_t'] or ops['hard_t']:
            if out_port != ofproto.OFPP_FLOOD:
                self.add_timeFlow(dp, ops, match, actions)

        # For ping and wget, data = None
        data = None
        if msg.buffer_id == ofproto.OFP_NO_BUFFER:
            data = msg.data

        out = parser.OFPPacketOut(datapath=fields['dp'],
                                  buffer_id=msg.buffer_id,
                                  in_port=fields['inport'],
                                  actions=actions, data=data)

        fields['dp'].send_msg(out)

    #############################################################
    #Use fields to build match 
    def pkt_match(self, fields):
        parser = fields['dp'].ofproto_parser
        if fields['srcip'] != None and fields['srcip'] != None:
            match = parser.OFPMatch(ipv4_src=fields['srcip'], 
										ipv4_dst = fields['dst_ip'])
        elif fields['srcip'] != None or fields['srcip'] != None:
            matchfield=fields['srcip'] if fields['srcip'] !=None else fields['dstip']
            match = parser.OFPMatch(ipv4_src=matchfield)
        elif fields['srcmac'] == None:
            match = parser.OFPMatch(in_port=fields['inport'])
        else:
            match = parser.OFPMatch(in_port=fields['inport'],
                                    eth_dst=fields['dstmac'])
        return match

    ###############################################################
    #Determine action to be taken on packet ops={'op':None, 'newport':None}
    #User can forward , drop, redirect, mirror, or craft packets. 
    def pkt_action(self,pkt,ops,fields):
        actions = []
        parser = fields['dp'].ofproto_parser
        if ops['op'] == 'fwd':
            out_port = self.switch.handle_pkt(pkt)
            actions.append(parser.OFPActionOutput(out_port))
        elif ops['op'] == 'drop':
            out_port = fields['ofproto'].OFPPC_NO_RECV
            actions.append(parser.OFPActionOutput(out_port))
        elif ops == 'redir':
            out_port = ops['newport']
            actions.append(parser.OFPActionOutput(out_port))
        elif ops['op'] == 'mir':
            out_port = self.switch.handle_pkt(pkt)
            actions.append(parser.OFPActionOutput(out_port))
            mir_port = ops['newport']
            actions.append(parser.OFPActionOutput(mir_port))
        elif ops['op'] == 'craft':
            #create and send new pkt due to craft trigger
            self._build_pkt(ops, fields) ##need to remove pkt ##########
            #Now drop the arrived packet
            out_port = fields['ofproto'].OFPPC_NO_RECV
            actions.append(parser.OFPActionOutput(out_port))
                                                
        return actions

    #More work is required here to implement active testing for NATs etc.
    # Note fields object must be completely rewritten for crafted packet
    # Probably need to make fields['ptype'] = ['arp', 'ipv4']
    def _build_pkt(self, fields):
        pkt_out = packet.Packet()
        pkt_out.add_protocol(ethernet.ethernet(ethertype=fields['ethtype'],
                                               dst=fields['dstmac'],
                                               src=fields['srcmac']))
        # Add if ARP is required                           
                            
        if 'arp' in fields['ptype']:
            pkt_out.add_protocol(arp.arp(opcode=arp.ARP_REPLY,
                                 src_mac=fields['srcmac'],
                                 src_ip=fields['srcip'],
                                 dst_mac=fields['dstmac'],
                                 dst_ip=fields['dstip']))

        if ipv4 in fields['ptype']:
            pkt_out.add_protocol(ipv4.ipv4(dst=fields['dstip'],
                                 src=fields['srcip'],
                                 proto=fields['proto']))

        if 'icmp' in fields['ptype']:
            pkt_out.add_protocol(icmp.icmp(type_=icmp.ICMP_ECHO_REPLY,
                                 code=icmp.ICMP_ECHO_REPLY_CODE,
                                 csum=0,
                                 data=fields['data']))
								 
        if 'tcp' in fields['ptype']:
            pkt_out.add_protocol(tcp.tcp(dst_port=fields['dstport'],
				bits=fields['bits'],option=fields['opt'],
                                #=str('\\x00' * 4),
                                src_port=fields['srcport']))
                             
        #pkt.add_protocol('\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\
            #\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\
            #\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f')

        self._send_packet(fields['dp'], ops['newport'], pkt_out)
	
	#Receive crafted packet and send it to the switch
    def _send_packet(self, datapath, port, pkt_out):
        if port == None: print "Port not defined" 
        #This methods sends the crafted message to the switch
        ofproto = datapath.ofproto
        parser = datapath.ofproto_parser
        pkt_out.serialize()
        self.logger.info("packet-out %s" % (pkt_out,))
        data = pkt_out.data
        actions = [parser.OFPActionOutput(port=port)]
        out = parser.OFPPacketOut(datapath=datapath,
                                  buffer_id=ofproto.OFP_NO_BUFFER,
                                  in_port=ofproto.OFPP_CONTROLLER,
                                  actions=actions,
                                  data=data)
        datapath.send_msg(out)
		
    #Clean up and disconnect ports. Controller going down  
    @set_ev_cls(ofp_event.EventOFPPortStatus, MAIN_DISPATCHER)
    def handl_port_stat(self, ev):
        switch=SimpleSwitch()
        switch.port_status_handler(ev)