def protocol_frame(protocol, source='unicast', vlans=[]): """ Create a frame that has the minimum fields to be recognized as a determined protocol. It's not intended to be a valid PDU, only to be seen as one by the switch filter. @param protocol Protocol name. Valid options are: * stp, lldp, lacp, marker, oam, lbd, cdp, pagp, udld, vtp, pvst, dtp, gvrp, gmrp, dot1x @param source Name of the source interface, or source MAC address. * 'unicast' to use a random unicast address as source MAC. @param vlans [optional] List of VLAN Tags. List can be composed by single integer representing VLAN, or tuple (int, int) for VLAN and prio. Ex: [(100, 3), 20] will add two tags, one with VLAN 100, prio 3 and another with VLAN 20, prio 0. """ if protocol not in pdu_info: raise Exception("Unknown protocol name {0}".format(protocol)) info = pdu_info[protocol] # Define source MAC address. if "eth" in source: src_mac = str(mac_address(source)) elif source == 'unicast': src_mac = str(random_mac('unicast')) else: src_mac = str(source) if protocol == 'eaps': src_mac = "00:e0:2b:00:00:01" if 'type' in info or vlans: pdu = Ether(src=src_mac, dst=info['mac']) for v in vlans: if type(v) == int: pdu = pdu / Dot1Q(vlan=v) elif type(v) == tuple: pdu = pdu / Dot1Q(vlan=v[0], prio=v[1]) else: raise TypeError( "Expected list with int or tuple for VLANs parameter.") if 'type' in info: pdu.lastlayer().type = info['type'] else: pdu = Dot3(src=src_mac, dst=info['mac']) pdu = pdu / info['load'] # Process PDU so length field is correctly calculated. pdu = Ether(str(pdu)) # Add Padding and return. padding = 64 - len(pdu) + 4 #FCS if padding > 0: pdu = pdu / Padding(load='\0' * padding) return pdu
def l2_frame_from_to(source, destination, vlans = [], seq = 10, size = 64, pattern = '\0', framing = "Ethernet II"): """ Create a frame using interfaces MACs. @param source Name of the source interface, or source MAC address. It can also be: * 'unicast' to use a random unicast address as source MAC. @param destination Name of the destination interface, or destination MAC address. It can also be: * 'broadcast' to use 'FF:FF:FF:FF:FF:FF' as destination MAC. * 'multicast' to use a random multicast address as destination MAC. * 'unicast' to use a random unicast address as destination MAC. @param vlans [optional] List of VLAN Tags. List can be composed by single integer representing VLAN, or tuple (int, int) for VLAN and prio. Ex: [(100, 3), 20] will add two tags, one with VLAN 100, prio 3 and another with VLAN 20, prio 0. @param seq [optional] Number of sequence @param size [optional] Size of created frame. A padding based on 'pattern' is added to complete the frame until size is reached (counting 4 bytes of FCS) @param pattern [optional] Pattern string used to fill payload. Default is '\0'. * 'random' to fill the payload with random bytes. @param framing [optional] Type of frame: * "Ethernet II" : Ethertype > 1535 and hold information about next layer. * "802.3" : Ethertype <= 1500 represent payload length. Next header is LLC. """ if "eth" in destination: dst_mac = mac_address(destination) elif destination == 'broadcast': dst_mac = 'FF:FF:FF:FF:FF:FF' elif destination == 'multicast': dst_mac = str(random_mac('multicast')) elif destination == 'unicast': dst_mac = str(random_mac('unicast')) else: dst_mac = str(destination) if "eth" in source: src_mac = str(mac_address(source)) elif source == 'unicast': src_mac = str(random_mac('unicast')) else: src_mac = str(source) # When the next layer is Dot1Q, Dot3 will be evaluated as Ether anyway (0x8100 > 1536), # To keep consistency between creation and dissection, already use Ether even for 802.3 framing. # The difference will be made as Dot1Q will be followed by LLC header. if framing == "Ethernet II" or vlans: frame = Ether(src = src_mac, dst = dst_mac) elif framing == "802.3": frame = Dot3(src = src_mac, dst = dst_mac) else: raise ValueError("Excpected only 'Ethernet II' or '802.3' as framing types.") for v in vlans: if type(v) == int: frame = frame / Dot1Q(vlan = v) elif type(v) == tuple: frame = frame / Dot1Q(vlan = v[0], prio = v[1]) else: raise TypeError("Expected list with int or tuple for VLANs parameter.") if framing == "802.3": frame = frame / LLC() / SNAP() if seq != None: frame = frame / L2T(l2t_seq = seq) return add_payload(frame, size, pattern)