def diff(ref_trace, check_trace, input_format="pcapng", tshark_path="", filters={}): """ Diff two pcapng or json files containing network captured data :param ref_trace: The first file. Considered as reference. :param check_trace: The second file. Checked to contain the same flow as the first file. :param input_format: Type of files to be checked. Can be "pcapng" (default) or "json" :param tshark_path: Needed in case the input type is "pcapng" so that the files can be converted to json format :param filters: A list of filters to remove noise from messages. :return: The result of a list of checks """ list1 = iter(get_msg_list_from_file(trace_file=ref_trace, tshark_path=tshark_path, input_format=input_format)) list2 = iter(get_msg_list_from_file(trace_file=check_trace, tshark_path=tshark_path, input_format=input_format)) if list1 is None or list2 is None: return None count = 0 if "Call-ID" not in filters: filters["Call-ID"] = [] for msg in list2: sip_msg = buildMessage(msg, {}) if msg_filter(sip_msg, filters) is None: if sip_msg.type == "Request": filters["Call-ID"].append(sip_msg["Call-ID"]) continue ref_msg = next(list1) ref_sip_msg = buildMessage(ref_msg, {}) while msg_filter(ref_sip_msg, filters) is None: if ref_sip_msg.type == "Request": filters["Call-ID"].append(ref_sip_msg["Call-ID"]) ref_msg = next(list1) ref_sip_msg = buildMessage(ref_msg, {}) ref_msg_template = make_sip_message_template(ref_msg) msg_template = make_sip_message_template(msg) if msg != ref_msg: print("{:-^60}".format(" Difference found in message #{} ".format(count))) print("{:#^60}".format(" Reference message ")) print(ref_msg) print("{:#^60}".format(" Matched message ")) print(msg) print("{:#^60}".format(" Diff analysis ")) d = Differ() for line in d.compare(ref_msg_template.splitlines(keepends=True), msg_template.splitlines(keepends=True)): print(line.strip()) return False count += 1 return True
def flow(users, pilot, param): parameters = copy(param) usera = next(users) parameters["userA"] = usera parameters["userB"] = pilot parameters["source_port"] = link[usera].port Invite = buildMessage(message["Invite_SDP_1"], parameters) #print(Invite) link[usera].send(Invite.contents()) inBytes = link[usera].waitForData() inmessage = handleDA(Invite, parseBytes(inBytes), user) #print("IN:",inmessage) assert inmessage.type=="Response" and inmessage.status=="100 Trying",\ "Sent:\n{}Received:\n{}".format(Invite,inmessage) inBytes = link[usera].waitForData() inmessage = parseBytes(inBytes) #print("IN:",inmessage) assert inmessage.type=="Response" and inmessage.status=="180 Ringing",\ "A side received Trying and then :\n{}".format(inmessage) inBytes = link[usera].waitForData() inmessage = parseBytes(inBytes) #print("IN:",inmessage) assert inmessage.type=="Response" and inmessage.status=="200 OK",\ "A side received Ringing and then:\n{}".format(inmessage) m = buildMessage(message["Ack_1"], parameters) for h in ("To", "From", "Call-ID"): m[h] = inmessage[h] #print(m) link[usera].send(m.contents()) sleep(parameters["talkDuration"]) m = buildMessage(message["Bye_1"], parameters) for h in ("To", "From", "Call-ID"): m[h] = inmessage[h] #print(m) link[usera].send(m.contents()) inBytes = link[usera].waitForData() inmessage = handleDA(m, parseBytes(inBytes), user) #print("IN:",inmessage) assert inmessage.type=="Response" and inmessage.status=="200 OK",\ "Sent:\n{}Received:\n{}".format(m,inmessage)
def flow(users, pilot): usera = next(users) data.parameters["userA"] = usera data.parameters["userB"] = pilot data.parameters["source_port"] = link[usera].port Invite = buildMessage(message["Invite_SDP_1"], data.parameters) #print(Invite) link[usera].send(Invite.contents()) inBytes = link[usera].waitForData() inmessage = parseBytes(inBytes) #print("IN:",inmessage) assert inmessage.type=="Response" and inmessage.status=="100 Trying",\ "Sent:\n{}Received:\n{}".format(Invite,inmessage) inBytes = link[usera].waitForData() inmessage = parseBytes(inBytes) #print("IN:",inmessage) assert inmessage.type=="Response" and inmessage.status=="180 Ringing",\ "B side sent:\n{}but A side received:\n{}".format(Ringing,inmessage) inBytes = link[usera].waitForData() inmessage = parseBytes(inBytes) #print("IN:",inmessage) assert inmessage.type=="Response" and inmessage.status=="200 OK",\ "B side got:\n{}but A side received:\n{}".format(ack,inmessage) data.parameters["source_port"] = link[usera].port m = buildMessage(message["Ack_1"], data.parameters) for h in ("To", "From", "Call-ID"): m[h] = inmessage[h] #print(m) link[usera].send(m.contents()) sleep(talkDuration) data.parameters["source_port"] = link[usera].port m = buildMessage(message["Bye_1"], data.parameters) for h in ("To", "From", "Call-ID"): m[h] = inmessage[h] #print(m) link[usera].send(m.contents()) inBytes = link[usera].waitForData() inmessage = parseBytes(inBytes) #print("IN:",inmessage) assert inmessage.type=="Response" and inmessage.status=="200 OK",\ "Sent:\n{}Received:\n{}".format(m,inmessage)
def send_new(self, target_sip_ep=None, message_string="", expected_response=None, ignore_messages=[]): """ Start a new dialog and send a message """ if target_sip_ep: self.parameters["userA"] = self.number self.parameters["userB"] = target_sip_ep.number else: # In cases like REGISTER, there is no B-side # Clear parameters to avoid unexpected results self.parameters.pop("userA", None) self.parameters.pop("userB", None) self.start_new_dialog() m = buildMessage(message_string, self.parameters) self.link.send(m.contents()) self.last_sent_message = m if expected_response: try: self.waitForMessage(expected_response, ignore_messages) except AssertionError: raise AssertionError('{}: "{}" response to "{}"\n{}'.format( self.number, self.last_received_message.status, self.last_sent_message.method, self.last_received_message))
def Register(user): parameters["user"] = user m = buildMessage(message["Register_1"], parameters) print(m) link[user].send(m.contents()) inBytes = link[user].waitForData() inmessage = parseBytes(inBytes) print(inmessage) assert inmessage.type == "Response" and inmessage.status == "200 OK"
def reg_user(sip_server, register_message, expiration_in_seconds=360): user, address = get_user_from_message(register_message, header="Contact").split("@") # replacement to overcome localhost silliness address = address.replace("localhost", "127.0.0.1") sip_server.set_parameter("expires", expiration_in_seconds) register_200 = buildMessage(message["200_OK_1"]) register_200.make_response_to(register_message) register_200["Contact"] = register_message["Contact"] sip_server.reply_to(register_message, register_200.contents()) sip_server.registered_addresses[user] = address
def Register(user): data.parameters["user"] = user L = link[user] data.parameters["source_port"] = L.port m = buildMessage(message["Register_1"], data.parameters) #print(m) L.send(m.contents()) inBytes = L.waitForData() inmessage = parseBytes(inBytes) #print(inmessage) assert inmessage.type == "Response" and inmessage.status == "200 OK", "{}\n{}".format( user, inmessage)
def summarize_trace(filename, *tests, applications=("sip", "http", "rtp"), input_format="pcapng", tshark_path=None, tshark_filter=None, delete_json=True): if not tshark_path and platform.system() == "Windows": tshark_path = r"C:\Program Files\Wireshark" if input_format == "json": with open(filename, "r") as j_file: j_obj = json.load(j_file) elif input_format == "pcapng": temp_file = open_cap_file(filename, tshark_path, tshark_filter) with open(temp_file, "r") as j_file: j_obj = json.load(j_file) if delete_json: os.remove(temp_file) else: print("Invalid input file type: {}. Supported formats are pcapng and json".format(input_format)) return None result = {} for application in applications: result[application] = {"count": 0} for j_msg in j_obj: frame_protocols = j_msg["_source"]["layers"]["frame"]["frame.protocols"] if not any([application in frame_protocols for application in applications]): continue ip_layer = frame_protocols.split(":")[2] transport_layer = frame_protocols.split(":")[3] for application in applications: if application in j_msg["_source"]["layers"]: src_addr = "{:<15}:{:>5}".format(j_msg["_source"]["layers"][ip_layer][ip_layer + ".src"], j_msg["_source"]["layers"][transport_layer][ transport_layer + ".srcport"]) dst_addr = "{:<15}:{:>5}".format(j_msg["_source"]["layers"][ip_layer][ip_layer + ".dst"], j_msg["_source"]["layers"][transport_layer][ transport_layer + ".dstport"]) if application == "sip": try: msg_raw = assemble_message_from_json(j_msg, appl=application) msg_obj = buildMessage(msg_raw) msg = check_in_trace(*tests, check_trace=[msg_obj], input_format="list") time_epoch = j_msg["_source"]["layers"]["frame"]["frame.time_epoch"] if not msg: expand = False else: expand = True result[application].setdefault("{}:{}".format(ip_layer, transport_layer), []) \ .append((time_epoch, src_addr, dst_addr, msg_obj, expand)) except: print("Unable to parse:") pprint(j_msg) # result[application]["stream_count"] = len(result[application][ip_layer+":"+transport_layer]) result[application]["count"] += 1 return result
def Register(user): parameters["user"] = user L = link[user] parameters["source_port"] = L.port parameters["source_ip"] = L.ip parameters["dest_ip"] = L.rip parameters["dest_port"] = L.rport parameters["epid"] = util.epid(user) m = buildMessage(message["Register_2"], parameters) #print(m) L.send(m.contents()) inBytes = L.waitForData() try: inmessage = handleDA(m, parseBytes(inBytes), user) assert inmessage.type == "Response" and inmessage.status == "200 OK", "{}\n{}".format( user, inmessage) except: traceback.print_exc()
def reply(self, message_string): """ Send a response to a previously received message """ if "callId" not in self.parameters or not self.parameters['callId']: raise Exception("Cannot reply when we are not in a dialog") m = buildMessage(message_string, self.parameters) for h in ("To", "From", "Via", "Call-ID"): m[h] = self.last_received_message[h] # do we need to set the to tag for all responses? check rfc3261 if "tag=" not in m['To']: m['To'] += ";tag=" + util.randStr(8) if message_string.strip().startswith("SIP"): # Sip response. Use received CSeq m["CSeq"] = self.last_received_message["CSeq"] else: # This is not a response, but a new request in the same dialog, so fix the CSeq # TODO: fix CSeq according to RFC3261 and ACK according to section 17.1.1.3 self.parameters["cseq"] += 1 m["CSeq"] = "{} {}".format(self.parameters["cseq"], m.method) self.link.send(m.contents())
def b2b_uas_establish(sip_server, invite): a = get_user_from_message(invite, header="Contact") b = get_user_from_message(invite) a_user, a_address = a.split("@") b_user = b.split("@")[0] b_address = sip_server.registered_addresses[b_user] if not sip_server.is_registered(a): sip_server.reply_to(invite, message["403_Forbidden"]) return if not sip_server.is_registered(b): sip_server.reply_to(invite, message["404_Not_Found"]) return sip_server.reply_to(invite, message["Trying_1"]) sip_server.set_parameter("userB", b_user) sip_server.set_parameter("userA", a_user) invite_b = buildMessage(message["Invite_SDP_1"], sip_server.sip_endpoint.parameters) invite_b.body = invite.body sip_server.send_new(b_address, b_user, invite_b.contents()) time.sleep(0.5) b_ringing = sip_server.wait_for_message("180 Ringing", ignore_messages=["100 Trying"]) leg_b_dialog = b_ringing.get_dialog() time.sleep(0.5) a_ringing = sip_server.reply_to(invite, b_ringing.contents()) leg_a_dialog = a_ringing.get_dialog() time.sleep(2) b_ok_invite = sip_server.wait_for_message("200 OK", dialog=leg_b_dialog) b_ok_invite["Contact"] = invite_b["Contact"] sip_server.reply_to(invite, b_ok_invite.contents()) time.sleep(0.5) sip_server.reply_to(b_ok_invite, message["Ack_1"]) time.sleep(0.5) sip_server.wait_for_message("ACK", dialog=leg_a_dialog) sip_server.active_calls.append((leg_a_dialog, leg_b_dialog))
def send_new(self, target_sip_ep=None, message_string="", expected_response=None, ignore_messages=[]): """ Start a new dialog and send a message """ self.parameters["userA"] = self.number if target_sip_ep: if isinstance(target_sip_ep, SipEndpoint): self.parameters["userB"] = target_sip_ep.number target_sip_ep.parameters["userB"] = self.number elif isinstance(target_sip_ep, str): self.parameters["userB"] = target_sip_ep else: raise Exception("target_sip_ep must be str or SipEndpoint, not {}".format(type(target_sip_ep))) else: # In cases like REGISTER, there is no B-side # Clear parameters to avoid unexpected results # self.parameters.pop("userA", None) # self.parameters.pop("userB", None) pass m = buildMessage(message_string, self.parameters) assert m.type == "Request", 'Tried to start a new dialog with a SIP Response' new_dialog = self.start_new_dialog() new_transaction = self.start_new_transaction(m.method) # m should always be a request m.set_dialog_from(new_dialog) m.set_transaction_from(new_transaction) self.link.send(m.contents()) self.save_message(m) if expected_response: # try: self.waitForMessage(message_type=expected_response, dialog=new_dialog, ignore_messages=ignore_messages) # except AssertionError: # raise AssertionError('{}: "{}" response to "{}"\n{}'.format(self.number, # self.get_last_message_in( # m.get_dialog()).get_status_or_method(), # m.method, # m)) return m
def reply(self, message_string, dialog=None): """ Send a response to a previously received message """ if dialog: dialog = self.set_dialog(dialog) else: dialog = self.current_dialog if "callId" not in self.parameters or not self.parameters['callId']: raise Exception("Cannot reply when we are not in a dialog") m = buildMessage(message_string, self.parameters) try: previous_message = self.get_last_message_in(dialog) m.make_response_to(previous_message) self.update_to_tag(m.get_dialog()) except: # New dialog, same call-id, eg NOTIFY after Keyset SUBSCRIBE. # Must be a SIP Response assert m.type == "Request", \ "Attempted to send a {} response in a new dialog".format(m.get_status_or_method()) m.set_dialog_from(dialog) if m.type == "Request": # This is a new request in the same dialog, so fix the CSeq # m.increase_cseq() self.start_new_transaction(m.method) self.save_message(m) m.set_transaction_from(self.current_transaction) # TODO: fix CSeq according to RFC3261 and ACK according to section 17.1.1.3 # self.parameters["cseq"] += 1 # m["CSeq"] = "{} {}".format(self.parameters["cseq"], m.method) self.link.send(m.contents()) return m
def WaitForCall(user): " Start an agent. Wait for INVITE messages" L = link[user] expectedMessage = "INVITE" while L: # Will stop when we set the link of the user to None try: inBytes = L.waitForData() inmessage = parseBytes(inBytes) assert inmessage.type==expectedEvent,\ "User {} expected {} but got {}".format(user,expectedEvent,inmessage.event) #print("User:{} received {}".format(user,inmessage)) except timeout: pass finally: L = link[user] try: data.parameters["userB"] = user data.parameters["source_port"] = link[user].port m = buildMessage(message["Trying_1"], data.parameters) for h in ("To", "From", "CSeq", "Via", "Call-ID"): m[h] = inmessageb[h] #print(m) link[user].send(m.contents()) data.parameters["source_port"] = link[user].port Ringing = buildMessage(message["Ringing_1"], data.parameters) for h in ("To", "From", "CSeq", "Via", "Call-ID"): Ringing[h] = inmessageb[h] toTag = ";tag=" + util.randStr(8) Ringing["To"] = Ringing["To"] + toTag #print(Ringing) link[user].send(Ringing.contents()) data.parameters["source_port"] = link[user].port m = buildMessage(message["200_OK_SDP_1"], data.parameters) for h in ("To", "From", "CSeq", "Via", "Call-ID"): m[h] = Ringing[h] m["To"] = m["To"] + toTag #print(m) link[user].send(m.contents()) inBytes = link[user].waitForData() ack = parseBytes(inBytes) #print("IN:",ack) assert ack.type=="Request" and ack.method=="ACK",\ "Sent:\n{}Received:\n{}".format(m,ack) inBytes = link[user].waitForData() Bye = parseBytes(inBytes) #print("IN:",Bye) assert Bye.type=="Request" and Bye.method=="BYE",\ "A side sent:\n{}B side received:\n{}".format(m,inmessage) data.parameters["source_port"] = link[user].port m = buildMessage(message["200_OK_1"], data.parameters) for h in ("To", "From", "CSeq", "Via", "Call-ID"): m[h] = Bye[h] #print(m) link[user].send(m.contents()) finally: # When call is done wait for next call AgentState(user)
from tshark_tools.lib import get_from_cap_file from sip.SipParser import buildMessage L = get_from_cap_file("only_sip.pcap", tshark_path=r"c:\Program Files\Wireshark") calls = [] for message in L: m = buildMessage(message, {}) if m.get_status_or_method() == "INVITE": calls.append(m.header["Call-ID"]) elif m["Call-ID"] in calls and m.type == "Response": assert m.status in ("200 OK", "100 Trying", "180 Ringing"), \ "Validation error: Received:\n{}".format(m.contents())
def flow(users): usera = next(users) userb = next(users) parameters["userA"] = usera parameters["userB"] = userb serverThreads.append( util.serverThread(WaitForCstaEvents, usera, assertLeg="A")) serverThreads.append( util.serverThread(WaitForCstaEvents, userb, assertLeg="B")) parameters["source_port"] = link[usera].port Invite = buildMessage(message["Invite_SDP_1"], parameters) # print(Invite) link[usera].send(Invite.contents()) inBytes = link[usera].waitForData() inmessage = parseBytes(inBytes) # print("IN:",inmessage) assert inmessage.type == "Response" and inmessage.status == "100 Trying", \ "Sent:\n{}Received:\n{}".format(Invite, inmessage) # inBytes=linkCsta[usera].waitForData() # cstaevent=parseBytes_csta(inBytes) # assert cstaevent.event=="ServiceInitiated", "Expected:{} Received:{}".format("ServiceInitiated",str(cstaevent)) inBytes = link[userb].waitForData() inmessageb = parseBytes(inBytes) # print("IN:",inmessageb) assert inmessageb.type == "Request" and inmessageb.method == "INVITE", \ "A side sent:\n{}and got Trying, but B side received:\n{}".format(Invite, inmessage) parameters["source_port"] = link[userb].port m = buildMessage(message["Trying_1"], parameters) for h in ("To", "From", "CSeq", "Via", "Call-ID"): m[h] = inmessageb[h] # print(m) link[userb].send(m.contents()) parameters["source_port"] = link[userb].port Ringing = buildMessage(message["Ringing_1"], parameters) for h in ("To", "From", "CSeq", "Via", "Call-ID"): Ringing[h] = inmessageb[h] toTag = ";tag=" + util.randStr(8) Ringing["To"] = Ringing["To"] + toTag # print(Ringing) link[userb].send(Ringing.contents()) inBytes = link[usera].waitForData() inmessage = parseBytes(inBytes) # print("IN:",inmessage) assert inmessage.type == "Response" and inmessage.status == "180 Ringing", \ "B side sent:\n{}but A side received:\n{}".format(Ringing, inmessage) parameters["source_port"] = link[userb].port m = buildMessage(message["200_OK_SDP_1"], parameters) for h in ("To", "From", "CSeq", "Via", "Call-ID"): m[h] = Ringing[h] m["To"] = m["To"] + toTag # print(m) link[userb].send(m.contents()) inBytes = link[userb].waitForData() ack = parseBytes(inBytes) # print("IN:",ack) assert ack.type == "Request" and ack.method == "ACK", \ "Sent:\n{}Received:\n{}".format(m, ack) inBytes = link[usera].waitForData() inmessage = parseBytes(inBytes) # print("IN:",inmessage) assert inmessage.type == "Response" and inmessage.status == "200 OK", \ "B side got:\n{}but A side received:\n{}".format(ack, inmessage) parameters["source_port"] = link[usera].port m = buildMessage(message["Ack_1"], parameters) for h in ("To", "From", "Call-ID"): m[h] = inmessage[h] # print(m) link[usera].send(m.contents()) sleep(talkDuration) parameters["source_port"] = link[usera].port m = buildMessage(message["Bye_1"], parameters) for h in ("To", "From", "Call-ID"): m[h] = inmessage[h] # print(m) link[usera].send(m.contents()) inBytes = link[usera].waitForData() inmessage = parseBytes(inBytes) # print("IN:",inmessage) assert inmessage.type == "Response" and inmessage.status == "200 OK", \ "Sent:\n{}Received:\n{}".format(m, inmessage) inBytes = link[userb].waitForData() Bye = parseBytes(inBytes) # print("IN:",Bye) assert Bye.type == "Request" and Bye.method == "BYE", \ "A side sent:\n{}B side received:\n{}".format(m, inmessage) parameters["source_port"] = link[userb].port m = buildMessage(message["200_OK_1"], parameters) for h in ("To", "From", "CSeq", "Via", "Call-ID"): m[h] = Bye[h] # print(m) link[userb].send(m.contents())
def WaitForCall(user, param): " Start an agent. Wait for INVITE messages" parameters = copy(param) parameters["number"] = 0 L = link[user] expectedMessage = "INVITE" while L: # Will stop when we set the link of the user to None try: inBytes = L.waitForData() invite = parseBytes(inBytes) assert invite.type=="Request" and invite.method==expectedMessage,\ "User {} expected {} but got:\n{}".format(user,expectedMessage,invite) #print("User:{} received {}".format(user,inmessage)) break except timeout: pass finally: L = link[user] if not L: return try: parameters["userB"] = user parameters["source_port"] = link[user].port m = buildMessage(message["Trying_1"], parameters) for h in ("To", "From", "CSeq", "Via", "Call-ID"): m[h] = invite[h] #print(m) link[user].send(m.contents()) Ringing = buildMessage(message["Ringing_1"], parameters) for h in ("To", "From", "CSeq", "Via", "Call-ID"): Ringing[h] = invite[h] for h in ("Allow", "Allow-Events", "X-Siemens-Call-Type"): if h in invite.headers: Ringing[h] = invite[h] toTag = ";tag=" + util.randStr(8) Ringing["To"] = Ringing["To"] + toTag #print(Ringing) link[user].send(Ringing.contents()) sleep(0.5) m = buildMessage(message["200_OK_SDP_1"], parameters) # Preserve Content-Length bkp = m["Content-Length"] for h in Ringing.headers: #("To", "From", "CSeq","Via","Call-ID","Contact"): m[h] = Ringing[h] m["Content-Length"] = bkp link[user].send(m.contents()) inBytes = link[user].waitForData() ack = parseBytes(inBytes) #print("IN:",ack) assert ack.type=="Request" and ack.method=="ACK",\ "Sent:\n{}Received:\n{}".format(m,ack) nobye = True acceptable = ("BYE", "UPDATE") while nobye: inBytes = link[user].waitForData(2 * parameters["talkDuration"]) inmessage = parseBytes(inBytes) nobye = not (inmessage.type == "Request" and inmessage.method == "BYE") assert inmessage.type=="Request" and inmessage.method in acceptable,\ "Expected one of {} but received :\n{}".format(str(acceptable),inmessage) m = buildMessage(message["200_OK_1"], parameters) for h in ("To", "From", "CSeq", "Via", "Call-ID"): m[h] = inmessage[h] #print(m) link[user].send(m.contents()) except: traceback.print_exc() finally: # When call is done wait for next call del parameters WaitForCall(user, param)
def flow(): parameters["userA"] = usera parameters["userB"] = userb parameters["expires"] = "0" Invite = buildMessage(message["Invite_SDP_1"], parameters) print(Invite) link[usera].send(Invite.contents()) inBytes = link[usera].waitForData() inmessage = parseBytes(inBytes) print("IN:", inmessage) assert inmessage.type == "Response" and inmessage.status == "100 Trying" inBytes = link[userb].waitForData() inmessageb = parseBytes(inBytes) print("IN:", inmessageb) assert inmessageb.type == "Request" and inmessageb.method == "INVITE" parameters["callId"] = inmessage["Call-ID"] m = buildMessage(message["Trying_1"], parameters) for h in ("To", "From", "CSeq", "Via", "Call-ID"): m[h] = inmessageb[h] print(m) link[userb].send(m.contents()) Ringing = buildMessage(message["Ringing_1"], parameters) for h in ("To", "From", "CSeq", "Via", "Call-ID"): Ringing[h] = inmessageb[h] toTag = ";tag=" + util.randStr(8) Ringing["To"] = Ringing["To"] + toTag print(Ringing) link[userb].send(Ringing.contents()) inBytes = link[usera].waitForData() inmessage = parseBytes(inBytes) print("IN:", inmessage) assert inmessage.type == "Response" and inmessage.status == "180 Ringing" m = buildMessage(message["200_OK_SDP_1"], parameters) for h in ("To", "From", "CSeq", "Via", "Call-ID"): m[h] = Ringing[h] m["To"] = m["To"] + toTag print(m) link[userb].send(m.contents()) inBytes = link[userb].waitForData() inmessage = parseBytes(inBytes) print("IN:", inmessage) assert inmessage.type == "Request" and inmessage.method == "ACK" inBytes = link[usera].waitForData() inmessage = parseBytes(inBytes) print("IN:", inmessage) assert inmessage.type == "Response" and inmessage.status == "200 OK" m = buildMessage(message["Ack_1"], parameters) for h in ("To", "From", "Call-ID"): m[h] = inmessage[h] print(m) link[usera].send(m.contents()) sleep(talkDuration) m = buildMessage(message["Bye_1"], parameters) for h in ("To", "From", "Call-ID"): m[h] = inmessage[h] print(m) link[usera].send(m.contents()) inBytes = link[usera].waitForData() inmessage = parseBytes(inBytes) print("IN:", inmessage) assert inmessage.type == "Response" and inmessage.status == "200 OK" inBytes = link[userb].waitForData() Bye = parseBytes(inBytes) print("IN:", Bye) assert Bye.type == "Request" and Bye.method == "BYE" m = buildMessage(message["200_OK_1"], parameters) for h in ("To", "From", "CSeq", "Via", "Call-ID"): m[h] = Bye[h] print(m) link[userb].send(m.contents())
def check_in_trace(*conditions_list, check_trace, input_format="pcapng", tshark_path=""): """ Look in the given trace file for a Message that matches the given conditions :param conditions_list: A list of dictionaries containing the conditions that a message in the trace should match. Best described by an example: {"Message": "INVITE", <- Message Req URI/Status Line should contain this string (re supported) "Headers": {"CSeq": "INVITE", <- Message Header CSeq must contain this string (re) "Supported": "timer"}, <- Message Header Supported must contain this string (re) "sdp": {"any": "PMCA", <- Message sdp body must contain this text anywhere "a_line": "PMCU", <- Message sdp body must contain this text in an (a) line (re) "o_line": "IP4"} <- Message sdp body must contain this text in an (o) line "xml": {"any": "ns:recording", <- Message xml body must contain this text anywhere "label tag": "audio", <- Message xml body must contain this text in an a "label" tag "label aor attr": "911@"} <- Message xml body must contain this text in an "aor" attribute of a "label" tag } :param check_trace: The trace containing the network capture under test :param input_format: Type of files to be checked. Can be "pcapng" (default) or "json" :param tshark_path: Needed in case the input type is "pcapng" so that the files can be converted to json format :return: """ result = [] if input_format == "list": msg_list = check_trace else: msg_list = get_msg_list_from_file(check_trace, input_format=input_format, tshark_path=tshark_path) if not conditions_list: return msg_list for conditions in conditions_list: for msg_str in msg_list: try: if isinstance(msg_str, SipMessage): msg = msg_str else: msg = buildMessage(msg_str) except: print("Failed to parse", msg_str) raise match = True for check in conditions: if check == "Message": if not re.search(conditions["Message"], msg.get_status_or_method(), re.IGNORECASE): match = False continue elif check == "Headers": for header in conditions["Headers"]: if header not in msg.headers: match = False continue elif not re.search(conditions["Headers"][header], msg[header], re.IGNORECASE): match = False continue elif check == "sdp": for sdpline in conditions["sdp"]: if sdpline == "any": if not re.search(conditions["sdp"]["any"], msg.body, re.IGNORECASE): match = False continue elif sdpline.endswith("_line"): line_type = sdpline[0] if not re.search(line_type + "=.*" + conditions["sdp"][sdpline], msg.body, re.IGNORECASE): match = False continue elif check == "xml": if "<?xml" not in msg.body: match = False continue xml_part_of_body = "<?xml" + msg.body.split("<?xml")[1].split("\r\n\r\n")[0] xml_body_obj = XmlBody(xml_part_of_body) for xmlelement in conditions["xml"]: if xmlelement == "any": if not re.search(conditions["xml"]["any"], msg.body, re.IGNORECASE): match = False continue elif xmlelement.endswith(" tag"): xml_tag = xmlelement.split(" ")[0] all_tags = xml_body_obj.get_all(xml_tag) if not all_tags: match = False continue elif not any(re.search(conditions["xml"][xmlelement], tag.text, re.IGNORECASE) for tag in all_tags): match = False continue elif xmlelement.endswith(" attr"): xml_tag = xmlelement.split(" ")[0] xml_attr = xmlelement.split(" ")[1] all_tags = xml_body_obj.get_all(xml_tag) if not all_tags: match = False continue elif not any(re.search(conditions["xml"][xmlelement], tag.get(xml_attr), re.IGNORECASE) for tag in all_tags if tag.get(xml_attr) is not None): match = False continue else: print("Unsupported check", check) raise if match: result.append(msg) break return result
def notify_ok(self, inmessage): notify_response = buildMessage(message["200_OK_Notify"]) notify_response.make_response_to(inmessage) notify_response["Contact"] = inmessage["Contact"] self.reply_to(inmessage, notify_response.contents())