import logging import sys import KSR as KSR import requests # global variables corresponding to defined values (e.g., flags) in kamailio.cfg FLT_ACC=1 FLT_ACCMISSED=2 FLT_ACCFAILED=3 FLT_NATS=5 FLB_NATB=6 FLB_NATSIPPING=7 Max_Expires = 60 API_Key = "API_KEY" api_base = "http://ourbaseurl.com" # Set up logging def setup_logger(): logger = logging.getLogger('KamailioLogger') logger.setLevel(logging.INFO) handler = logging.FileHandler('/tmp/kemi.txt') formatter = logging.Formatter( '%(asctime)s - %(name)s - %(levelname)s - %(message)s') handler.setFormatter(formatter) logger.addHandler(handler) return logger # Global function to instantiate a kamailio class object # Executed when kamailio app_python module is initialized def mod_init(): logger = setup_logger() logger.info("===== from Python mod init\n") print("===== from Python mod init\n") # Instead of creating /tmp/status.txt, log a message logger.info("Hello World") return kamailio(logger) # SIP request routing # -- equivalent of request_route{} def ksr_request_route(): KSR.info("===== request - from kamailio python script\n") KSR.info("===== method [%s] r-uri [%s]\n" % (KSR.pv.get("$rm"), KSR.pv.get("$ru"))) print("===== request - from kamailio python script\n") print("===== method [%s] r-uri [%s]\n" % (KSR.pv.get("$rm"), KSR.pv.get("$ru"))) # Start defining kamailio class class kamailio: def __init__(self, logger): self.logger = logger self.logger.info('===== kamailio.__init__\n') print('===== kamailio.__init__\n') # Executed when kamailio child processes are initialized def child_init(self, rank): self.logger.info('===== kamailio.child_init(%d)\n' % rank) return 0 # SIP request routing - equivalent of request_route{} def ksr_request_route(self, msg): self.logger.info("===== request - from kamailio python script\n") self.logger.info("===== method [%s] r-uri [%s]\n" % (KSR.pv.get("$rm"), KSR.pv.get("$ru"))) print("===== request - from kamailio python script\n") print("===== method [%s] r-uri [%s]\n" % (KSR.pv.get("$rm"), KSR.pv.get("$ru"))) # NAT detection if self.ksr_route_natdetect(msg)==-255 : return 1 # CANCEL processing if KSR.is_CANCEL() : if KSR.tm.t_check_trans()>0 : self.ksr_route_relay(msg) return 1 # -- only initial requests (no To tag) # handle retransmissions if KSR.tmx.t_precheck_trans()>0 : KSR.tm.t_check_trans() return 1 if KSR.tm.t_check_trans()==0 : return 1 if self.ksr_app_auth(msg) == 1: return 1 # record routing for dialog forming requests (in case they are routed) # - remove preloaded route headers KSR.hdr.remove("Route") if KSR.is_method_in("IS") : KSR.rr.record_route() # handle requests within SIP dialogs if self.ksr_route_withindlg(msg)==-255 : return 1 # account only INVITEs if KSR.pv.get("$rm")=="INVITE" : KSR.setflag(FLT_ACC); # do accounting source_ip = KSR.pv.get("$si") source_port = KSR.pv.get("$sp") destination_ip = KSR.pv.get("$di") destination_port = KSR.pv.get("$dp") KSR.log("info", f"Debugging - Source IP: {source_ip}, Source Port: {source_port}") KSR.log("info", f"Debugging - Destination IP: {destination_ip}, Destination Port: {destination_port}") #Check if request is from dispatcher list if source_ip == "FREESWITCH_IP": KSR.log("info","Match found") # Request is from FreeSWITCH to client, perform a lookup location if not KSR.registrar.lookup("location"): KSR.log("info","No registered user found in the location table") KSR.sl.sl_send_reply(404, "Not Found") exit() elif KSR.pv.get("$du") is None: KSR.err("ALERT: this is broken registration!") KSR.sl.sl_send_reply(404, "Not Found") exit() else: if not KSR.dispatcher.ds_select_dst(1, 2): KSR.sl.sl_send_reply(503, "Service Unavailable") exit() KSR.err("ALERT: Updated request domain $du to " + KSR.pv.get("$du")) KSR.err("ALERT: Updated request domain $ru to " + KSR.pv.get("$ru")) # dispatch requests to foreign domains if self.ksr_route_sipout(msg)==-255 : return 1 if KSR.corex.has_ruri_user() < 0 : # request with no Username in RURI KSR.sl.sl_send_reply(484, "Address Incomplete") return 1 # user location service self.ksr_route_location(msg) return 1 def ksr_xhttp_event(self, evname, something): self.logger.info("===== xhttp module triggered event: " + str(evname) + str(something) + "\n") self.logger.info("L_DBG", "HTTP Request Received\n") KSR.websocket.handle_handshake() self.logger.info("===== made it past handle_handshake() \n") return 1 # wrapper around tm relay function def ksr_route_relay(self, msg): # enable additional event routes for forwarded requests # - serial forking, RTP relaying handling, a.s.o. if KSR.is_method_in("IBSU") : if KSR.tm.t_is_set("branch_route")<0 : KSR.tm.t_on_branch("ksr_branch_manage") if KSR.is_method_in("ISU") : if KSR.tm.t_is_set("onreply_route")<0 : KSR.tm.t_on_reply("ksr_onreply_manage") if KSR.is_INVITE() : if KSR.tm.t_is_set("failure_route")<0 : KSR.tm.t_on_failure("ksr_failure_manage") if KSR.tm.t_relay()<0 : KSR.sl.sl_reply_error() return -255 # Handle requests within SIP dialogs def ksr_route_withindlg(self, msg): if KSR.siputils.has_totag()<0 : return 1 # sequential request within a dialog should # take the path determined by record-routing if KSR.rr.loose_route()>0 : if self.ksr_route_dlguri(msg)==-255 : return -255 if KSR.is_BYE() : # do accounting ... KSR.setflag(FLT_ACC) # ... even if the transaction fails KSR.setflag(FLT_ACCFAILED) elif KSR.is_ACK() : # ACK is forwarded statelessly if self.ksr_route_natmanage(msg)==-255 : return -255 elif KSR.is_NOTIFY() : # Add Record-Route for in-dialog NOTIFY as per RFC 6665. KSR.rr.record_route() self.ksr_route_relay(msg) return -255 if KSR.is_ACK() : if KSR.tm.t_check_trans() >0 : # no loose-route, but stateful ACK # must be an ACK after a 487 # or e.g. 404 from upstream server self.ksr_route_relay(msg) return -255 else: # ACK without matching transaction ... ignore and discard return -255 KSR.sl.sl_send_reply(404, "Not here") return -255 # User location service def ksr_route_location(self, msg): # Commented this part to make the outbound call work #rc = KSR.registrar.lookup("location") #if rc<0 : # KSR.tm.t_newtran() # if rc==-1 or rc==-3 : # KSR.sl.send_reply(404, "Not Found") # return -255 # elif rc==-2 : # KSR.sl.send_reply(405, "Method Not Allowed") # return -255 # when routing via usrloc, log the missed calls also if KSR.is_INVITE() : KSR.setflag(FLT_ACCMISSED) self.ksr_route_relay(msg) return -255 # Caller NAT detection def ksr_route_natdetect(self, msg): KSR.force_rport() if KSR.nathelper.nat_uac_test(19)>0 : if KSR.is_REGISTER() : KSR.nathelper.fix_nated_register() elif KSR.siputils.is_first_hop()>0 : KSR.nathelper.set_contact_alias() KSR.setflag(FLT_NATS) return 1 # RTPProxy control def ksr_route_natmanage(self, msg): if KSR.siputils.is_request()>0 : if KSR.siputils.has_totag()>0 : if KSR.rr.check_route_param("nat=yes")>0 : KSR.setbflag(FLB_NATB) if (not (KSR.isflagset(FLT_NATS) or KSR.isbflagset(FLB_NATB))) : return 1 KSR.rtpproxy.rtpproxy_manage("co") if KSR.siputils.is_request()>0 : if not KSR.siputils.has_totag() : if KSR.tmx.t_is_branch_route()>0 : KSR.rr.add_rr_param(";nat=yes") if KSR.siputils.is_reply()>0 : if KSR.isbflagset(FLB_NATB) : KSR.nathelper.set_contact_alias() return 1 # URI update for dialog requests def ksr_route_dlguri(self, msg): if not KSR.isdsturiset() : KSR.nathelper.handle_ruri_alias() return 1 # Routing to foreign domains def ksr_route_sipout(self, msg): if KSR.is_myself_ruri() : return 1 KSR.hdr.append("P-Hint: outbound\r\n") self.ksr_route_relay(msg) return -255 # Manage outgoing branches # -- equivalent of branch_route[...]{} def ksr_branch_manage(self, msg): self.ksr_route_natmanage(msg) return 1 # Manage incoming replies # -- equivalent of onreply_route[...]{} def ksr_onreply_manage(self, msg): KSR.dbg("incoming reply\n") scode = KSR.pv.get("$rs") if scode>100 and scode<299 : self.ksr_route_natmanage(msg) return 1 # Manage failure routing cases # -- equivalent of failure_route[...]{} def ksr_failure_manage(self, msg): if self.ksr_route_natmanage(msg)==-255 : return 1 if KSR.tm.t_is_canceled()>0 : return 1 return 1 # SIP response handling # -- equivalent of reply_route{} def ksr_reply_route(self, msg): KSR.dbg("response handling - python script\n") if KSR.sanity.sanity_check(17604, 6)<0 : KSR.err("Malformed SIP response from " + KSR.pv.get("$si") + ":" + str(KSR.pv.get("$sp")) +"\n") KSR.set_drop() return -255 return 1 #app Auth Handling def ksr_app_auth(self, msg): # This is our custom python function that authenticates from our api.