1/2にPerlで作ったSIP ProxyをPythonに移植してみた
ついでにRecord-Routeをいれてみたり、いくつかのヘッダチェック処理も追加してみた。
あと、起動時にユーザの情報が書かれたCSVファイルを読み込むようにした。
CSVファイルは1カラム目がuser名、2カラム目が認証用パスワード、3カラム目がコンタクトアドレス。
2カラム目以降はなくともよい。
2カラム目が未設定か空文字の場合は認証しない。
3カラム目が書いてある場合はREGISTERしていなくてもリクエストを受信できる。
起動は、
このスクリプト ドメイン IPアドレス ポート番号 上記CSVファイル
って感じ。
IPv6未対応、TCP未対応、maddr未対応、など制限あり。
動かすと汚いログが標準出力にいっぱい出ます。ごめんなさい。気が向いたらこっそり直します。
ところで移植作業をしていてふと思ったのだけれど、あるロジックを考えたとき、複数の言語で容易に実装できるロジックは優れていることが多いんじゃないかと思った。特定の言語に依存しているロジックである場合、それはロジックそのものに難しさが潜んでいて、それを言語が吸収してくれているだけじゃないかと思う。
つまり、あるロジックがイケてるか悩んだら、複数の言語で容易に実装できるかを想像するといいのかもしれない。
以降ソース。いずれ組み込もうと思っている機能のソースが混ざっています。ご容赦ください。
※3月頭追記。SourceforgeにてRubyでそこそこまともなProxyを作る作業ばかりしているのでこのプログラムはたぶんもう修正しません。。
#!/usr/bin/python -O # encoding: utf-8 """ stateless sip proxy server """ import sys, re, socket, md5, csv, Queue ############################################################################# class NotFound(Exception): # ----------------------------------------------------------------------- def __init__(self, s): self.val = s # ----------------------------------------------------------------------- def __str__(self): return self.val ############################################################################# class SentResponse(Exception): # ----------------------------------------------------------------------- def __init__(self, s): self.val = s # ----------------------------------------------------------------------- def __str__(self): return self.val ############################################################################# class Parser: # ----------------------------------------------------------------------- def parse_addr_spec(self, buf): if __debug__: print 'Parser.parse_addr_spec(', buf, ')' m = re.match(r'sip:(([^@]+)@)?([^;:]+)(:(\d+))?', buf) if m.group(2) != None: user = m.group(2) else: user = '' if m.group(5) != None: port = int(m.group(5)) else: port = 5060 return user, m.group(3), port # ----------------------------------------------------------------------- def parse_name_addr(self, buf): if __debug__: print 'Parser.parse_name_addr(', buf, ')' m = re.search(r'<([^>]+)>', buf) if m != None: return buf[:m.start()], m.group(1), buf[m.end():] m = re.search(r'([^@]+@)?[^;]+', buf) return "", buf[:m.end()], buf[m.end():] ############################################################################# class SIPHeader: # ----------------------------------------------------------------------- def __init__(self, name = '', vals = []): self.name = name self.vals = vals # ----------------------------------------------------------------------- def __str__(self): return ''.join([self.name, ': ', ', '.join(self.vals), "\r\n"]) ############################################################################# class SIPMessage(Parser): # ----------------------------------------------------------------------- def __init__(self, buf=None): self.method = self.requri = self.stcode = self.reason = '' self.hdrs = [] self.body = "" if buf != None: self.parse(buf) # ----------------------------------------------------------------------- def parse(self, buf): buf, self.body = self.__parse_body(buf.lstrip()) buf = re.sub(r'\r\n?', '\n', buf) buf = re.sub(r"\n[ \t]", " ", buf) ary = re.split(r'\n', buf) self.method, self.requri, self.stcode, self.reason = \ self.__parse_start_line(ary[0]) self.hdrs = self.__parse_headers(ary[1:]) # ----------------------------------------------------------------------- def __parse_start_line(self, buf): if __debug__: print 'SIPMessage.parse_start_line(', buf, ')' m = re.match(r'([^ ]+) ([^ ]+) ', buf) if m.group(1) == 'SIP/2.0': return '', '', m.group(2), buf[m.end():] return m.group(1), m.group(2), '', '' # ----------------------------------------------------------------------- def __parse_headers(self, ary): if __debug__: print 'SIPMessage.parse_header(...)' hdrs = [] for hdr in ary: hdrs.append(self.__parse_header(hdr)) return hdrs # ----------------------------------------------------------------------- def __parse_header(self, buf): if __debug__: print 'SIPMessage.parse_header(', buf, ')' hname, buf = re.split(r'\s*:\s*', buf, 1) hvals = [] while buf != '': m = re.match(r'(([^,"]|"([^\\]|(\\"))*?")+)(\s*,\s*)?', buf) hvals.append(m.group(1)) buf = buf[m.end():] return SIPHeader(hname, hvals) # ----------------------------------------------------------------------- def __parse_body(self, buf): if __debug__: print 'SIPMessage.__parse_body(...)' m = re.search(r'(\r\n\r\n)|(\r\r)|(\n\n)', buf) return buf[:m.start()], buf[m.end():] # ----------------------------------------------------------------------- def __str__(self): if self.method != '': s = self.method + ' ' + self.requri + ' SIP/2.0\r\n' else: s = 'SIP/2.0 ' + self.stcode + " " + self.reason + '\r\n' for h in self.hdrs: s += str(h) s += '\r\n' + self.body return s # ----------------------------------------------------------------------- def insert_received(self, addr): if __debug__: print 'SIPMessage.insert_received(', addr[0], ')' pos = self.search('via', 'v') topvia = self.hdrs[pos].vals[0] topvia += ';received=' + str(addr[0]) m = re.search(r';rport', topvia) if m != None: topvia = topvia[:m.end()] + '=' + str(addr[1]) + topvia[m.end():] self.hdrs[pos].vals[0] = topvia # ----------------------------------------------------------------------- def search(self, name1, name2 = ''): if __debug__: print 'SIPMessage.search(', name1, ', ', name2, ')' for i, hdr in enumerate(self.hdrs): if hdr.name.lower() == name1 or hdr.name.lower() == name2: return i raise NotFound, 'header ' + name1 + ' ' + name2 + ' not found' # ----------------------------------------------------------------------- def rsearch(self, name1, name2 = ''): if __debug__: print 'SIPMessage.rsearch(', name1, ', ', name2, ')' i = 0 pos = -1 for hdr in slef.hdrs: if hdr.name.lower() == name1 or hdr.name.lower() == name2: pos = i i += 1 if pos == -1: raise NotFound, 'header ' + name1 + ' ' + name2 + ' not found' return pos # ----------------------------------------------------------------------- def search_addr_spec(self, name1, name2): if __debug__: print 'SIPMessage.search_addr_spec(', name1, ', ', name2, ')' tmp0, addr_spec, tmp1 = self.search_name_addr(name1, name2) return self.parse_addr_spec(addr_spec) # ----------------------------------------------------------------------- def search_name_addr(self, name1, name2): if __debug__: print 'SIPMessage.search_name_addr(', name1, ', ', name2, ')' pos = self.search(name1, name2) return self.parse_name_addr(self.hdrs[pos].vals[0]) # ----------------------------------------------------------------------- def delete_last(self, name1, name2 = ""): if __debug__: print 'SIPMessage.delete_last(', name1, ', ', name2, ')' hpos = self.rsearch(name1, name2) vpos = len(self.hdrs[hpos].vals) - 1 ret = self.hdrs[hpos].vals[vpos] del(self.hdrs[hpos].vals[vpos]) if len(self.hdrs[hpos].vals) == 0: del(self.hdrs[hpos]) return ret # ----------------------------------------------------------------------- def conv2resp(self, stcode, reason): if __debug__: print 'SIPMessage.conv2resp(', stcode, ', ', reason, ')' hnames = ['call-id', 'i', 'from', 'f', 'to', 't', 'via', 'v', 'cseq', 'max-forwards'] self.method = self.requri = self.body = '' self.stcode = stcode self.reason = reason new_hdrs = [] for hdr in self.hdrs: if hdr.name.lower() in hnames: new_hdrs.append(hdr) self.hdrs = new_hdrs # ----------------------------------------------------------------------- def get_dest(self): if __debug__: print 'SIPMessage.get_dest()' if self.method != '': return self.get_req_dest() return self.get_resp_dest() # ----------------------------------------------------------------------- def get_req_dest(self): if __debug__: print 'SIPMessage.get_req_dest()' user, host, port = self.parse_addr_spec(self.requri) return host, port # ----------------------------------------------------------------------- def get_resp_dest(self): if __debug__: print 'SIPMessage.get_resp_dest()' v = self.hdrs[self.search("via", "v")].vals[0] m = re.match(r'SIP\s*/\s*2\.0\s*/UDP\s+', v) v = v[m.end():] m = re.match(r'([^:;]+)(\s*:\s*(\d+))?', v) host = m.group(1) port = m.group(3) if port == None: port = 5060 m = re.search(r';received=([^;]+)', v) if m != None: host = m.group(1) m = re.search(r';rport=([\d]+)', v) if m != None: port = m.group(1) return host, int(port) ############################################################################# class Timer: # ----------------------------------------------------------------------- def __init__(self, type, interval, timeout, src): self.type = type self.interval = interval self.timeout = timeout self.dest = src self.src = "TIMER" ############################################################################# class TimerManager: # ----------------------------------------------------------------------- def __init__(self): self.list_interval = [ 0.5, 1.5, 3.5, 5.0, 7.5, 11.5, 15.5, 19.5, 23.5, 27.5, 31.5, 32.0, None] self.lists = [] for interval in self.list_interval: self.lists.append(Queue.Queue()) # ----------------------------------------------------------------------- def set_timer(self, type, interval, src): t = Timer(type, interval, interval + time.time(), src) ############################################################################# class SIPTransportLayer: # ----------------------------------------------------------------------- def __init__(self): pass ############################################################################# class SIPTransaction: # ----------------------------------------------------------------------- def __init__(self): pass # ----------------------------------------------------------------------- def sendmsg(self, msg, retransmit = [], timeout = None): if msg.method != '': if msg.method == 'INVITE': pass else: pass else: # get cseq value if cseq_method == 'INVITE': pass else: pass # ----------------------------------------------------------------------- def proc_ict_none(self, msg): if __debug__: print 'RFC3261 17.1.1 INVITE Clinet Transaction' self.set_timer_ab() self.sendmsg(msg) self.set_state('ICTCalling') # ----------------------------------------------------------------------- def proc_ict_calling(self, evt): self.proc_ict_proceeding(evt) # ----------------------------------------------------------------------- def proc_ict_proceeding(self, evt): if isnstance(evt, SIPMessage): if evt.stcode[:1] == '1': self.set_state('ICTProceeding') self.pass_to_tu(evt) elif evt.stcode != '': ack = evt.gen_ack() self.sendmsg(ack) self.set_state('ICTCompleted') self.set_timer('TimerD', 32, time.time() + 32) self.pass_to_tu(evt) elif isinstance(evt, SIPTimer) and self.state == 'ICTCalling': if evt.type == 'TimerA': self.sendbuf() elif evt.type == 'TimerB': self.set_state('') # ----------------------------------------------------------------------- def proc_ict_completed(self, evt): pass # ----------------------------------------------------------------------- def proc_nict_none(self, msg): if __debug__: print 'RFC3261 17.1.2 non-INVITE Clinet Transaction' self.set_timer_ef() self.sendmsg(msg) self.set_state('NICTTrying') # ----------------------------------------------------------------------- def proc_nict_trying(self, evt): self.proc_nict_proceeding(evt) # ----------------------------------------------------------------------- def proc_nict_proceeding(self, evt): if isinstance(evt, SIPMessage): if evt.stcode[:1] == '1': self.set_state('NICTProceeding') self.pass_to_tu(evt) elif evt.stcode != '': self.set_timer('TimerK', T4, time.time() + T4) self.set_state('NICTCompleted') self.pass_to_tu(evt) elif isinstance(evt, SIPTimer): if evt.type == 'TimerE': self.sendbuf() elif evt.type == 'TimerF': self.set_state('') self.pass_to_tu(evt) # ----------------------------------------------------------------------- def proc_nict_completed(self, evt): if isinstance(evt, SIPTimer): if evt.type == 'TimerK': self.set_state('') # ----------------------------------------------------------------------- def proc_ist_none(self, msg): if __debug__: print 'RFC3261 17.2.1 INVITE Server Transaction' resp = msg.gen_resp('100', 'Trying') self.sendmsg(resp) self.set_state('ISTProceeding') self.pass_to_tu(msg) # ----------------------------------------------------------------------- def proc_ist_proceeding(self, evt): if isinstance(evt, SIPMessage): if evt.method == 'INVITE': self.sendbuf(self.buf, self.destaddr) elif evt.stcode[:1] == '1': self.sendbuf(self.buf, self.destaddr) elif evt.stcode[:1] == '2': self.set_state(None) elif evt.stcode != '': self.set_state('ISTCompleted') self.set_timer_gh() self.send(evt) # ----------------------------------------------------------------------- def proc_ist_completed(self, evt): if isinstance(evt, SIPMessage): if evt.method == 'INVITE': self.sendbug(self.buf, self.destaddr) elif evt.method == 'ACK': self.sendmsg(evt, T4) self.set_state('ISTCompleted') elif isinstance(evt, SIPTimer): if evt.type == 'TimerG': self.retransmit() elif evt.type == 'TimerH': self.set_state('') self.inform_trpt_err_to_tu(evt) # ----------------------------------------------------------------------- def proc_ist_confirmed(self, evt): if isinstance(evt, SIPTimer): if evt.type == 'TimerI': self.set_state('') # ----------------------------------------------------------------------- def proc_nist_none(self, msg): if __debug__: print 'RFC3261 17.2.2 Non-INVITE Server Transaction' self.set_state('NISTTrying') self.pass_to_tu(msg) # ----------------------------------------------------------------------- def proc_nist_trying(self, evt): if isinstance(evt, SIPMessage): if evt.stcode[:1] == '1': self.set_state('NISTProceeding') self.sendmsg(evt) elif evt.stcode != '': self.set_state('NISTCompleted') self.set_timer('TimerJ') self.sendmsg(evt) # ----------------------------------------------------------------------- def proc_nist_proceeding(self, evt): if isinstance(evt, SIPMessage): if evt.stcode[:1] == '1': self.sendmsg(evt) elif evt.stcode != '': # 200-299 self.set_state('NISTCompleted') self.set_timer('TimerJ') self.sendmsg(evt) elif evt.method != '': self.sendbuf() # ----------------------------------------------------------------------- def proc_nist_completed(self, evt): if isinstance(evt, SIPTimer): if evt.type == 'TimerJ': self.set_state('') ############################################################################# class SIPTransactionManager: # ----------------------------------------------------------------------- def __init__(self): self.data = {} # ----------------------------------------------------------------------- def proc_evt(self, evt): id = evt.get_trx_id() if id in self.data: trx = self.data[id] else: trx = None if isinstance(evt, SIPMessage): if evt.method == 'ACK' or evt.method == '': if evt.src == 'TRANSPORT': self.pass_to_tu(evt) elif evt.src == 'TU': self.sendmsg(evt) else: trx = SIPTransaction() self.data[id] = trx else: if __debug__: print 'transaction already terminated, ignore event' if trx != None: trx.proc_evt(evt) if trx.get_state() == '': del self.date[id] ############################################################################# class UserData: # ----------------------------------------------------------------------- def __init__(self, data): self.name = data[0] self.passwd = self.aor = '' if len(data) > 1: self.passwd = data[1] if len(data) > 2: self.contacts = [data[2]] # ----------------------------------------------------------------------- def __str__(self): return ' '.join([self.name, self.passwd, ' '.join([self.contacts])]) ############################################################################# class Authenticate: # ----------------------------------------------------------------------- def authenticate(self, hdr, method, password, body = ''): if __debug__: print 'Authenticate.authenticate(...)' prm = {} prm['algorithm'] = 'md5' prm['username'] = prm['nonce'] = prm['nc'] = prm['cnonce'] = '' prm['realm'] = prm['uri'] = prm['qop'] = '' prm['method'] = method prm['passwd'] = password prm['body'] = body m = re.match( r'Auth((enticate)|(orization))\s*:\s*Digest\s+', hdr) buf = hdr[m.end():] while buf != '': m = re.match(r'([a-z]+)="?([^"\s,]+)"?\s*(,\s*)?', buf) prm[m.group(1)] = m.group(2) buf = buf[m.end():] return (prm['response'] == self.calc_request_digest(prm)) # ----------------------------------------------------------------------- def calc_request_digest(self, prm): if __debug__: print 'Authenticate.calc_request_digest(...)' ary = [self.h(self.a1(prm)), prm['nonce']] if prm.has_key('qop'): ary.append(prm['nc']) ary.append(prm['cnonce']) ary.append(prm['qop']) ary.append(self.h(self.a2(prm))) ret = self.h(':'.join(ary)) return ret # ----------------------------------------------------------------------- def a1(self, prm): if __debug__: print 'Authenticate.a1(...)' ret = ':'.join([prm['username'], prm['realm'], prm['passwd']]) if prm['algorithm'].lower() == 'md5-sess': ret = self.h(':'.join([ret, prm['nonce'], prm['cnonce']])) return ret # ----------------------------------------------------------------------- def a2(self, prm, body = ''): if __debug__: print 'Authenticate.a2(...)' if prm['qop'] == 'auth-int': ret = ':'.join([prm['method'], prm['uri'], self.h(body)]) else: ret = ':'.join([prm['method'], prm['uri']]) return ret # ----------------------------------------------------------------------- def h(self, data): if __debug__: print 'Authenticate.h(...)' return md5.new(data).hexdigest() ############################################################################# class Proxy(Authenticate, Parser): # ----------------------------------------------------------------------- def initialize(self, domain, host, port, user_data): if __debug__: print 'Proxy.initialize(', str(host), ', ', str(port), ')' self.locdata = {} self.load(user_data) self.mydomain = domain self.myhost = host self.myport = port self.aor = 'sip:proxy@' + self.myhost + ':' + str(self.myport) self.myrr = 'sip:' + self.myhost + ':' + str(self.myport) self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) self.sock.bind((host, port)) self.timer_manager = TimerManager() self.trx_layer = SIPTransactionManager() # ----------------------------------------------------------------------- def load(self, filename): if __debug__: print 'Proxy.load(', filename, ')' try: reader = csv.reader(open(filename, 'r')) for row in reader: if len(row) > 0: self.locdata[row[0]] = UserData(row) except: print 'exception occured, failed to load ' + filename # ----------------------------------------------------------------------- def run(self): if __debug__: print 'Proxy.run()' counter = 0 while True: try: buf, src = self.sock.recvfrom(0xffff) except KeyboardInterrupt: sys.exit(1) except: continue print '< ' * 5, 'rcvd ', src[0], ':', str(src[1]), ' <' * 5 print '#', counter print buf counter += 1 try: self.proc_message(buf, src) except SentResponse: continue except Exception, e: if __debug__: print 'exception occured:', e continue # ----------------------------------------------------------------------- def proc_message(self, buf, src): if __debug__: print 'Proxy.proc_message(...)' msg = SIPMessage(buf) if msg.method != '': msg.insert_received(src) self.proc_request(msg) else: self.proc_response(msg) # ----------------------------------------------------------------------- def ins_auth_hdr(self, msg, hname): if __debug__: print 'Proxy.ins_auth_hdr(...)' pos = msg.search('call-id', 'i') cid = msg.hdrs[pos].vals[0] nonce = md5.new(md5.new(cid).hexdigest()).hexdigest() hvals = [] hvals.append('Digest realm="' + self.myhost + ':' + str(self.myport) + '"') hvals.append('nonce="' + nonce + '"') hdr = SIPHeader(hname, hvals) msg.hdrs.append(hdr) return msg # ----------------------------------------------------------------------- def proc_register(self, msg): if __debug__: print 'Proxy.proc_register(...)' from_user, t0, t1 = msg.search_addr_spec('from', 'f') if not self.locdata.has_key(from_user): msg.conv2resp("403", "Forbidden") msg.hdrs.append(SIPHeader("Contact", [self.aor])) self.send(msg) return if self.locdata[from_user].passwd != '': if __debug__: print 'authentication required for ', from_user try: pos = msg.search('authorization') if not self.authenticate(str(msg.hdrs[pos]), 'REGISTER', self.locdata[from_user].passwd): msg.conv2resp('401', 'Unauthorized') msg.hdrs.append(SIPHeader('Contact', [self.aor])) msg = self.ins_auth_hdr(msg, 'WWW-Authenticate') self.send(msg) return except NotFound: if __debug__: print "WWW-Authenticate header not found" msg.conv2resp("401", "Unauthorized") msg.hdrs.append(SIPHeader("Contact", [self.aor])) msg = self.ins_auth_hdr(msg, "WWW-Authenticate") self.send(msg) return to_user, t0, t1 = msg.search_addr_spec("to", "t") if to_user != from_user: msg.conv2resp("403", "Forbidden") # shuld be 404? msg.hdrs.append(SIPHeader("Contact", [self.aor])) self.send(msg) return t0, contact_addr, t1 = msg.search_name_addr("contact", "m") if __debug__: print "register ", to_user, " -> ", contact_addr self.locdata[to_user].contacts = [contact_addr] msg.conv2resp("200", "OK") msg.hdrs.append(SIPHeader("Contact", [contact_addr])) self.send(msg) # ----------------------------------------------------------------------- def proc_request(self, msg): if __debug__: print "Proxy.proc_request(...)" user, host, port = self.parse_addr_spec(msg.requri) if __debug__: print user, host, port if((self.myhost == host and self.myport == port) or self.mydomain == host): if msg.method == "REGISTER": self.proc_register(msg) return msg = self.validate_request(msg) msg = self.preprocess_route_info(msg) if msg == None: return msg, targets = self.determine_request_targets(msg) if msg == None: return self.forward_request(msg, targets) # ----------------------------------------------------------------------- def validate_request(self, msg): if __debug__: print "Proxy.validate_request(...) RFC3261 16.3" msg = self.check_uri_scheme(msg) msg = self.check_max_forwards(msg) msg = self.check_proxy_require(msg) msg = self.check_proxy_authorization(msg) return msg # ----------------------------------------------------------------------- def check_uri_scheme(self, msg): if __debug__: print "Proxy.check_uri_scheme(...)" m = re.match(r'((sip)|(tel)):', msg.requri) if m == None: if msg.method != "ACK": msg.conv2resp("416", "Unsupported URI Scheme") msg.hdrs.append(SIPHeader("Contact", [self.aor])) self.send(msg) raise SentReponse, "416 Unsupported URI Scheme" return msg # ----------------------------------------------------------------------- def check_max_forwards(self, msg): if __debug__: print "Proxy.check_max_forwards(...)" try: pos = msg.search("max-forwards") if msg.hdrs[pos].vals[0] == "0": if __debug__: print "Max-Forwards value == 0" if msg.method != "ACK": msg.conv2resp("483", "Too Many Hops") msg.hdrs.append(SIPHeader("Contact", [self.aor])) self.send(msg) raise SentResponse, "483 Too Many Hops" msg.hdrs[pos].vals[0] = str(int(msg.hdrs[pos].vals[0]) - 1) except NotFound: msg.hdrs.append(SIPHeader("Max-Forwards", ["70"])) return msg # ----------------------------------------------------------------------- def check_proxy_require(self, msg): if __debug__: print "Proxy.check_proxy_require(...)" try: pos = msg.search("proxy-require") if __debug__: "Proxy-Require header found" if msg.method != "ACK": pr = msg.hdrs[pos] pr.name = "Unsupported" msg.conv2resp("420", "Bad Extension") msg.hdrs.append(SIPHeader("Contact", [self.aor])) msg.hdrs.append(pr) self.send(msg) raise SentReponse, "sent 420 Bad Extension" except NotFound: pass # do nothing return msg # ----------------------------------------------------------------------- def check_proxy_authorization(self, msg): if __debug__: print "Proxy.check_proxy_authorization(...)" if msg.method != "INVITE": return msg user, host, port = msg.search_addr_spec("from", "f") if host != self.myhost or port != self.myport: return msg if not self.locdata.has_key(user): msg.conv2resp("403", "Forbidden") msg.hdrs.append(SIPHeader("Contact", [self.aor])) self.send(msg) raise SentResponsee, "sent 403 Forbidden" passwd = self.locdata[user].passwd if passwd == "": return msg try: pos = msg.search("proxy-authorization") if self.authenticate(str(msg.hdrs[pos]), msg.method, passwd, msg.body): return msg except NotFound: pass msg.conv2resp("407", "Proxy Authentication Required") msg.hdrs.append(SIPHeader("Contact", [self.aor])) msg = self.ins_auth_hdr(msg, "Proxy-Authenticate") self.send(msg) raise SentResponse, "sent 407" # ----------------------------------------------------------------------- def preprocess_route_info(self, msg): if __debug__: print "Proxy.preprocess_route(...) RFC3261 16.4" if self.myrr == msg.requri: msg.requri = msg.delete_last("route") try: pos = msg.search("route") t0, top_route, t1 = self.parse_name_addr(msg.hdrs[pos].vals[0]) if self.myrr == top_route: del(msg.hdrs[pos].vals[0]) if len(msg.hdrs[pos]) == 0: del(msg.hdrs[pos]) except NotFound: pass return msg # ----------------------------------------------------------------------- def determine_request_targets(self, msg): if __debug__: print "Proxy.determine_request_targets(...) RFC3261 16.5" targets = [] user, host, port = self.parse_addr_spec(msg.requri) if host != self.myhost or port != self.myport: if __debug__: print "not to me.." return msg, [msg.requri] if user == '': if __debug__: print "cannot find the user" return None, [] if user in self.locdata: targets = self.locdata[user].contacts else: # not registered if __debug__: print "user not registered" if(msg.method != "ACK"): msg.conv2resp("404", "Not Found") msg.hdrs.append(SIPHeader("Contact", [self.aor])) self.send(msg) raise SentReponse, "404 Not Found" return msg, targets # ----------------------------------------------------------------------- def forward_request(self, msg, targets): if __debug__: print "Proxy.forward_request(...) RFC3261 16.6" org = msg for target in targets: msg.requri = target msg = self.insert_record_route(msg) msg = self.insert_via(msg, org.requri) self.send(msg) # ----------------------------------------------------------------------- def insert_record_route(self, msg): if __debug__: print "Proxy.insert_record_route(...) RFC3261 16.6.4" my_rr = "<" + self.myrr + ";lr>" try: pos = msg.search("record-route") msg.hdrs[pos].vals.insert(0, my_rr) except NotFound: msg.hdrs.append(SIPHeader("Record-Route", [my_rr])) return msg # ----------------------------------------------------------------------- def insert_via(self, msg, org_requri): if __debug__: print "Proxy.insert_via(...) RFC3261 16.6.8" branch = self.generate_branch(msg, org_requri) my_via = "SIP/2.0/UDP " + self.myhost + ":" + str(self.myport) + \ ";branch=z9hG4bK" + branch try: pos = msg.search("via", "v") msg.hdrs[pos].vals.insert(0, my_via) except NotFound: msg.hdrs.append(SIPHeader("Via", [my_via])) return msg # ----------------------------------------------------------------------- def generate_branch(self, msg, org_requri): pos = msg.search('via', 'v') via = msg.hdrs[pos].vals[0] m = re.search(r';branch=([^;]+)', via) if m != None: if m.group(1)[:7] == 'z9hG4bK': return md5.new(m.group(1)).hexdigest() pos = msg.search('from', 'f') buf = msg.hdrs[pos].vals[0] m = re.search(r';tag=([^;]+)', buf) if m != None: from_tag = m.group(1) else: from_tag = "" pos = msg.search("to", "t") buf = msg.hdrs[pos].vals[0] m = re.search(r";tag=([^;]+)", buf) if m != None: to_tag = m.group(1) else: to_tag = "" pos = msg.search("call-id", "i") cid = msg.hdrs[pos].vals[0] pos = msg.search("cseq") buf = msg.hdrs[pos].vals[0] m = re.match(r"(\d+)\s+[A-Z]+", buf) cseq_num = m.group(1) buf = ' '.join([via, from_tag, to_tag, cid, cseq_num, org_requri]) return md5.new(buf).hexdigest() # ----------------------------------------------------------------------- def proc_response(self, msg): if __debug__: print "Proxy.proc_response(...) RFC3261 16.7" pos = msg.search("via", "v") del msg.hdrs[pos].vals[0] if len(msg.hdrs[pos].vals) == 0: del msg.hdrs[pos] self.send(msg) # ----------------------------------------------------------------------- def send(self, msg): if __debug__: print "Proxy.send(...)" host, port = msg.get_dest() if host == self.myhost and port == self.myport: return buf = str(msg) try: self.sock.sendto(buf, (host, port)) except: if __debug__: print 'failede to sendto' return print "> " * 5 + "sent " + host + ":" + str(port) + " >" * 5 print buf ############################################################################# if __name__ == "__main__": if len(sys.argv) != 5: print "\nUSAGE:\n\tproxy.py domain host port user.dat\n\n" else: px = Proxy() px.initialize(sys.argv[1], sys.argv[2], int(sys.argv[3]), sys.argv[4]) print "ok" px.run()
ユーザデータファイルはこんな感じ。
1111,pasword,sip:1111@127.0.0.1:5061 2222,,sip:2222@127.0.0.1:5061