def test_default_args(self): du = icmp.dest_unreach() buf = du.serialize() res = struct.unpack(icmp.dest_unreach._PACK_STR, six.binary_type(buf)) eq_(res[0], 0) eq_(res[1], 0)
def setUp(self): self.mtu = 10 self.data = b"abc" self.data_len = len(self.data) self.dest_unreach = icmp.dest_unreach(data_len=self.data_len, mtu=self.mtu, data=self.data) self.buf = struct.pack("!xBH", self.data_len, self.mtu) self.buf += self.data
def setUp(self): self.mtu = 10 self.data = 'abc' self.data_len = len(self.data) self.dest_unreach = icmp.dest_unreach( data_len=self.data_len, mtu=self.mtu, data=self.data) self.buf = struct.pack('!xBH', self.data_len, self.mtu) self.buf += self.data
def _create_icmp_data(icmp_type, data_len, data): if icmp_type == icmp.ICMP_DEST_UNREACH: icmp_data = icmp.dest_unreach(data_len=data_len, data=data) elif icmp_type == icmp.ICMP_TIME_EXCEEDED: icmp_data = icmp.TimeExceeded(data_len=data_len, data=data) else: icmp_data = None return icmp_data
def send_icmp(self, datapath, dst_ip, src_mac, icmp_type, icmp_code, ip_ihl, icmp_data): self.logger.debug("Sending ICMP") proto = datapath.ofproto parser = datapath.ofproto_parser dpid = dpid_to_str(datapath.id) pkt = packet.Packet() out_port, hop_ip = self.get_route(dpid, dst_ip) out_mac = self.mac_from_port(dpid, out_port) dst_mac = src_mac self.logger.debug( "Router {} sending ICMP to {} with target MAC {} (from port {} hopping to {})" .format(dpid, dst_ip, dst_mac, out_port, hop_ip)) for interface in self.interface_table.get(dpid): if interface.get("port") == out_port: src_ip = interface.get("ip") offset = 14 + 8 + (ip_ihl * 4) payload = icmp_data[14:offset] if icmp_type == 3: self.logger.debug("TYPE 3 ICMP") payload = icmp.dest_unreach(data=payload) if icmp_type == 11: self.logger.debug("TYPE 11 ICMP") payload = icmp.TimeExceeded(data=payload) ## pkt.add_protocol(...) ## https://ryu.readthedocs.io/en/latest/library_packet_ref/packet_icmp.html pkt.add_protocol( ethernet.ethernet(dst=dst_mac, src=out_mac, ethertype=ethernet.ether.ETH_TYPE_IP)) pkt.add_protocol( ipv4.ipv4(dst=dst_ip, src=src_ip, ttl=64, proto=ipv4.inet.IPPROTO_ICMP)) pkt.add_protocol( icmp.icmp(type_=icmp_type, code=icmp_code, data=payload)) pkt.serialize() data = pkt.data actions = [datapath.ofproto_parser.OFPActionOutput(port=out_port)] out = datapath.ofproto_parser.OFPPacketOut( datapath=datapath, buffer_id=proto.OFP_NO_BUFFER, in_port=proto.OFPP_ANY, actions=actions, data=data) datapath.send_msg(out)
def send_icmp(self, in_port, icmp_type, icmp_code, datapath, ipv4_header=None, ethernet_header=None, icmp_data=None, msg_data=None, src_ip=None): # Generate ICMP reply packet csum = 0 offset = ethernet.ethernet._MIN_LEN ether_proto = ether.ETH_TYPE_IP eth = ethernet_header e = ethernet.ethernet(eth.src, eth.dst, ether_proto) if icmp_data is None and msg_data is not None: ip_datagram = msg_data[offset:] if icmp_type == icmp.ICMP_DEST_UNREACH: icmp_data = icmp.dest_unreach(data_len=len(ip_datagram), data=ip_datagram) elif icmp_type == icmp.ICMP_TIME_EXCEEDED: icmp_data = icmp.TimeExceeded(data_len=len(ip_datagram), data=ip_datagram) ic = icmp.icmp(icmp_type, icmp_code, csum, data=icmp_data) ip = ipv4_header if src_ip is None: src_ip = ip.dst ip_total_length = ip.header_length * 4 + ic._MIN_LEN if ic.data is not None: ip_total_length += ic.data._MIN_LEN if ic.data.data is not None: ip_total_length += +len(ic.data.data) i = ipv4.ipv4(ip.version, ip.header_length, ip.tos, ip_total_length, ip.identification, ip.flags, ip.offset, DEFAULT_TTL, inet.IPPROTO_ICMP, csum, src_ip, ip.src) pkt = packet.Packet() pkt.add_protocol(e) pkt.add_protocol(i) pkt.add_protocol(ic) pkt.serialize() # Send packet out self.send_packet_out(datapath, in_port, datapath.ofproto.OFPP_IN_PORT, pkt.data, data_str=str(pkt))
def setUp_with_dest_unreach(self): self.unreach_mtu = 10 self.unreach_data = b"abc" self.unreach_data_len = len(self.unreach_data) self.data = icmp.dest_unreach(data_len=self.unreach_data_len, mtu=self.unreach_mtu, data=self.unreach_data) self.type_ = icmp.ICMP_DEST_UNREACH self.code = icmp.ICMP_HOST_UNREACH_CODE self.ic = icmp.icmp(self.type_, self.code, self.csum, self.data) self.buf = bytearray(struct.pack(icmp.icmp._PACK_STR, self.type_, self.code, self.csum)) self.buf += self.data.serialize() self.csum_calc = packet_utils.checksum(self.buf) struct.pack_into("!H", self.buf, 2, self.csum_calc)
class Test_icmp_dest_unreach(unittest.TestCase): type_ = icmp.ICMP_DEST_UNREACH code = icmp.ICMP_HOST_UNREACH_CODE csum = 0 mtu = 10 data = 'abc' data_len = len(data) dst_unreach = icmp.dest_unreach(data_len=data_len, mtu=mtu, data=data) ic = icmp.icmp(type_, code, csum, data=dst_unreach) def setUp(self): pass def tearDown(self): pass def test_to_string(self): data_values = { 'data': self.data, 'data_len': self.data_len, 'mtu': self.mtu } _data_str = ','.join([ '%s=%s' % (k, repr(data_values[k])) for k, v in inspect.getmembers(self.dst_unreach) if k in data_values ]) data_str = '%s(%s)' % (icmp.dest_unreach.__name__, _data_str) icmp_values = { 'type': repr(self.type_), 'code': repr(self.code), 'csum': repr(self.csum), 'data': data_str } _ic_str = ','.join([ '%s=%s' % (k, icmp_values[k]) for k, v in inspect.getmembers(self.ic) if k in icmp_values ]) ic_str = '%s(%s)' % (icmp.icmp.__name__, _ic_str) eq_(str(self.ic), ic_str) eq_(repr(self.ic), ic_str)
def test_default_args(self): ic = icmp.icmp() buf = ic.serialize(bytearray(), None) res = struct.unpack(icmp.icmp._PACK_STR, six.binary_type(buf[:4])) eq_(res[0], 8) eq_(res[1], 0) eq_(buf[4:], b'\x00\x00\x00\x00') # with data ic = icmp.icmp(type_=icmp.ICMP_DEST_UNREACH, data=icmp.dest_unreach()) buf = ic.serialize(bytearray(), None) res = struct.unpack(icmp.icmp._PACK_STR, six.binary_type(buf[:4])) eq_(res[0], 3) eq_(res[1], 0) eq_(buf[4:], b'\x00\x00\x00\x00')
def setUp_with_dest_unreach(self): self.unreach_mtu = 10 self.unreach_data = 'abc' self.unreach_data_len = len(self.unreach_data) self.data = icmp.dest_unreach(data_len=self.unreach_data_len, mtu=self.unreach_mtu, data=self.unreach_data) self.type_ = icmp.ICMP_DEST_UNREACH self.code = icmp.ICMP_HOST_UNREACH_CODE self.ic = icmp.icmp(self.type_, self.code, self.csum, self.data) self.buf = struct.pack(icmp.icmp._PACK_STR, self.type_, self.code, self.csum) self.buf += self.data.serialize() self.csum_calc = packet_utils.checksum(str(self.buf)) struct.pack_into('!H', self.buf, 2, self.csum_calc)
def create_icmp_unrachalbe_packet(self, pkt, ipv4_pkt): eth_pkt = pkt.get_protocol(ethernet.ethernet) pkt = packet.Packet() pkt.add_protocol( ethernet.ethernet(dst=eth_pkt.src, ethertype=eth_pkt.ethertype) ) #src hardware addr is default = '00.00.00.00.00.00.00.00' pkt.add_protocol( ipv4.ipv4(src=ipv4_pkt.dst, dst=ipv4_pkt.src, proto=ipv4_pkt.proto)) pkt_payload = icmp.dest_unreach() pkt.add_protocol( icmp.icmp(type_=icmp.ICMP_DEST_UNREACH, code=icmp.ICMP_HOST_UNREACH_CODE, csum=0, data=pkt_payload)) pkt.serialize() return pkt.data
def send_icmp_port_unreachable(self, datapath, old_pkt, output): pkt = packet.Packet() datapkt = packet.Packet() dst_ip = None for protocol in old_pkt: if not hasattr(protocol, 'protocol_name'): datapkt.add_protocol(protocol) elif protocol.protocol_name == 'ethernet': e = ethernet.ethernet(src=protocol.dst, dst=protocol.src, ethertype=ether_types.ETH_TYPE_IP) pkt.add_protocol(e) elif protocol.protocol_name == 'ipv4': ip = ipv4.ipv4(dst=protocol.src, src=protocol.dst, proto=in_proto.IPPROTO_ICMP) dst_ip = protocol.src pkt.add_protocol(ip) datapkt.add_protocol(protocol) else: datapkt.add_protocol(protocol) datapkt.serialize() icm_data = icmp.dest_unreach(data=datapkt.data) icm = icmp.icmp(type_=icmp.ICMP_DEST_UNREACH, code=icmp.ICMP_PORT_UNREACH_CODE, csum=0, data=icm_data) pkt.add_protocol(icm) pkt.serialize() actions = [datapath.ofproto_parser.OFPActionOutput(output, 0)] ofp = datapath.ofproto ofp_parser = datapath.ofproto_parser res = ofp_parser.OFPPacketOut(datapath=datapath, buffer_id=ofp.OFP_NO_BUFFER, in_port=datapath.ofproto.OFPP_CONTROLLER, actions=actions, data=pkt.data) LOG.info('Sending ICMP Port unreachable message for %s', dst_ip) datapath.send_msg(res)
def send_icmp(self, in_port, protocol_list, vlan_id, icmp_type, icmp_code, icmp_data=None, msg_data=None, src_ip=None): # Generate ICMP reply packet csum = 0 offset = ethernet.ethernet._MIN_LEN if vlan_id != VLANID_NONE: ether_proto = ether.ETH_TYPE_8021Q pcp = 0 cfi = 0 vlan_ether = ether.ETH_TYPE_IP v = vlan.vlan(pcp, cfi, vlan_id, vlan_ether) offset += vlan.vlan._MIN_LEN else: ether_proto = ether.ETH_TYPE_IP eth = protocol_list[ETHERNET] e = ethernet.ethernet(eth.src, eth.dst, ether_proto) ip = protocol_list[IPV4] if icmp_data is None and msg_data is not None: # RFC 4884 says that we should send "at least 128 octets" # if we are using the ICMP Extension Structure. # We're not using the extension structure, but let's send # up to 128 bytes of the original msg_data. # # RFC 4884 also states that the length field is interpreted in # 32 bit units, so the length calculated in bytes needs to first # be divided by 4, then increased by 1 if the modulus is non-zero. # # Finally, RFC 4884 says, if we're specifying the length, we MUST # zero pad to the next 32 bit boundary. end_of_data = offset + len(ip) + 128 ip_datagram = bytearray() ip_datagram += msg_data[offset:end_of_data] data_len = int(len(ip_datagram) / 4) length_modulus = int(len(ip_datagram) % 4) if length_modulus: data_len += 1 ip_datagram += bytearray([0] * (4 - length_modulus)) if icmp_type == icmp.ICMP_DEST_UNREACH: icmp_data = icmp.dest_unreach(data_len=data_len, data=ip_datagram) elif icmp_type == icmp.ICMP_TIME_EXCEEDED: icmp_data = icmp.TimeExceeded(data_len=data_len, data=ip_datagram) ic = icmp.icmp(icmp_type, icmp_code, csum, data=icmp_data) if src_ip is None: src_ip = ip.dst ip_total_length = ip.header_length * 4 + ic._MIN_LEN if ic.data is not None: ip_total_length += ic.data._MIN_LEN if ic.data.data is not None: ip_total_length += +len(ic.data.data) i = ipv4.ipv4(ip.version, ip.header_length, ip.tos, ip_total_length, ip.identification, ip.flags, ip.offset, DEFAULT_TTL, inet.IPPROTO_ICMP, csum, src_ip, ip.src) pkt = packet.Packet() pkt.add_protocol(e) if vlan_id != VLANID_NONE: pkt.add_protocol(v) pkt.add_protocol(i) pkt.add_protocol(ic) pkt.serialize() # Send packet out self.send_packet_out(in_port, self.dp.ofproto.OFPP_IN_PORT, pkt.data, data_str=str(pkt))
def send_icmp(self, in_port, protocol_list, vlan_id, icmp_type, icmp_code, icmp_data=None, msg_data=None, src_ip=None): # Generate ICMP reply packet csum = 0 offset = ethernet.ethernet._MIN_LEN if vlan_id != VLANID_NONE: ether_proto = ether.ETH_TYPE_8021Q pcp = 0 cfi = 0 vlan_ether = ether.ETH_TYPE_IP v = vlan.vlan(pcp, cfi, vlan_id, vlan_ether) offset += vlan.vlan._MIN_LEN else: ether_proto = ether.ETH_TYPE_IP eth = protocol_list[ETHERNET] e = ethernet.ethernet(eth.src, eth.dst, ether_proto) if icmp_data is None and msg_data is not None: ip_datagram = msg_data[offset:] if icmp_type == icmp.ICMP_DEST_UNREACH: icmp_data = icmp.dest_unreach(data_len=len(ip_datagram), data=ip_datagram) elif icmp_type == icmp.ICMP_TIME_EXCEEDED: icmp_data = icmp.TimeExceeded(data_len=len(ip_datagram), data=ip_datagram) ic = icmp.icmp(icmp_type, icmp_code, csum, data=icmp_data) ip = protocol_list[IPV4] if src_ip is None: src_ip = ip.dst ip_total_length = ip.header_length * 4 + ic._MIN_LEN if ic.data is not None: ip_total_length += ic.data._MIN_LEN if ic.data.data is not None: ip_total_length += +len(ic.data.data) i = ipv4.ipv4(ip.version, ip.header_length, ip.tos, ip_total_length, ip.identification, ip.flags, ip.offset, DEFAULT_TTL, inet.IPPROTO_ICMP, csum, src_ip, ip.src) pkt = packet.Packet() pkt.add_protocol(e) if vlan_id != VLANID_NONE: pkt.add_protocol(v) pkt.add_protocol(i) pkt.add_protocol(ic) pkt.serialize() # Send packet out self.send_packet_out(in_port, self.dp.ofproto.OFPP_IN_PORT, pkt.data, data_str=str(pkt))
def generate_icmp_datagram(self, dpid, iface_port, msg, pkt, icmp_type, code) -> packet.Packet(): eth_hdr = pkt.protocols[0] # Link-Layer header ip_hdr = original_ip_hdr = pkt.protocols[1] # Network-Layer header iface_mac = self.interfaces[dpid][iface_port]['mac'] # The MAC address of this i/face iface_ip = self.interfaces[dpid][iface_port]['ip'] # The IP address of this i/face msg_data = msg.data # The data from the original datagram (received) # Configure Link-Layer header eth_hdr.dst = eth_hdr.src # The source mac address, will now be the recipient (destination mac) eth_hdr.src = iface_mac # This router's i/face mac address will be the sender (source mac) # Configure Network-Layer header ip_hdr.total_length = 0 # 0 means calculate automatically while encoding ip_hdr.dst = ip_hdr.src # Same as Link-Layer changes, but with IP address instead of MAC address ip_hdr.src = iface_ip # Same as Link-Layer changes, but with IP address instead of MAC address ip_hdr.proto = inet.IPPROTO_ICMP # proto could've been udp or tcp # Generate new ICMP header of type "destination unreachable" # Logic for construction of TTL EXCEEDED icmp header and network layer header bytes, taken from # https://github.com/osrg/ryu/blob/master/ryu/app/rest_router.py (see function send_icmp()) offset = ethernet.ethernet._MIN_LEN # Get the header offset end_of_data = offset + len(original_ip_hdr) + 128 ip_hdr_bytes = bytearray(msg_data[offset:end_of_data]) # Get IP header data of original pkt data_len = int(len(ip_hdr_bytes) / 4) # Get the length of the data length_mod = int(len(ip_hdr_bytes) % 4) if length_mod: data_len += 1 # add 1 more, if there is remainder to avoid sending less data and therefore invalid ip_hdr_bytes += bytearray([0] * (4 - length_mod)) # finally get ip header bytes # instantiate the icmp header based on type of icmp if icmp_type == icmp.ICMP_DEST_UNREACH: icmp_hdr = icmp.icmp( type_=icmp_type, code=code, csum=0, data=icmp.dest_unreach(data_len=data_len, data=ip_hdr_bytes) ) elif icmp_type == icmp.ICMP_ECHO_REPLY: original_icmp_hdr = pkt.protocols[2] icmp_hdr = icmp.icmp(type_=icmp_type, code=code, csum=0, data=original_icmp_hdr.data) elif icmp_type == icmp.ICMP_TIME_EXCEEDED: default_ttl = 64 icmp_hdr = icmp.icmp( type_=icmp_type, code=code, csum=0, data=icmp.TimeExceeded(data_len=data_len, data=ip_hdr_bytes) ) ip_total_length = ip_hdr.header_length * 4 + icmp_hdr._MIN_LEN ip_total_length += icmp_hdr.data._MIN_LEN ip_total_length += + len(icmp_hdr.data.data) # Generate new Network Layer header new_ip_hdr = ipv4.ipv4( header_length=ip_hdr.header_length, total_length=0, src=ip_hdr.src, dst=ip_hdr.dst, proto=ip_hdr.proto, tos=original_ip_hdr.tos, identification=original_ip_hdr.identification, flags=original_ip_hdr.flags, offset=original_ip_hdr.offset, ttl=default_ttl ) p = packet.Packet() p.add_protocol(eth_hdr) p.add_protocol(new_ip_hdr) p.add_protocol(icmp_hdr) return p else: return None # Return null for unsupported icmp packets destined to router # Replace headers in the packet pkt.protocols[0] = eth_hdr pkt.protocols[1] = ip_hdr pkt.protocols[2] = icmp_hdr # Return the packet containing the router's response to packet_in handler for forwarding return pkt