def __call__(ctx, qname, qtype=A, qclass=IN, server=server[0]): ctx = type.__call__(ctx) transport = yield udp.connect(server, 'domain')() query = message() query.id = '\0\0' query.qr = 0 query.opcode = 0 query.aa = 0 query.tc = 0 query.rd = 1 query.ra = 0 query.z = 0 query.rcode = 0 query.question.append(question(qname, qtype, qclass)) transport.write(str(query)) ctx.recv = yield transport.recv() response = message() response.id = ctx.recv[:2] response.qr = ord(ctx.recv[2]) >> 7 response.opcode = ord(ctx.recv[2]) >> 3 & 0xf response.aa = ord(ctx.recv[2]) >> 2 & 1 response.tc = ord(ctx.recv[2]) >> 1 & 1 response.rd = ord(ctx.recv[2]) & 1 response.ra = ord(ctx.recv[3]) >> 7 response.z = ord(ctx.recv[3]) >> 4 & 7 response.rcode = ord(ctx.recv[3]) & 0xf qdcount = ord(ctx.recv[4]) << 8 | ord(ctx.recv[5]) ancount = ord(ctx.recv[6]) << 8 | ord(ctx.recv[7]) nscount = ord(ctx.recv[8]) << 8 | ord(ctx.recv[9]) arcount = ord(ctx.recv[10]) << 8 | ord(ctx.recv[11]) ctx.offset = 12 for _ in range(qdcount): response.question.append(ctx.question(ctx.offset)) for _ in range(ancount): response.answer.append(ctx.rr(ctx.offset)) for _ in range(nscount): response.authority.append(ctx.rr(ctx.offset)) for _ in range(arcount): response.additional.append(ctx.rr(ctx.offset)) if response.rcode: raise response #return ... raise StopIteration(response)
def client(method, requestUri, initiator): match = qwer(rfc3261.requestUri, '$').match(requestUri, '( host, hostname, maddrParam, port )') # We define TARGET as the value of the maddr parameter of the URI, if # present, otherwise, the host value of the hostport component of the URI if match.maddrParam: target = match.maddrParam.host else: target = match.host if match.port: port = match.port elif target.hostname: try: result = yield dns.lookup('_sip._udp.' + str(target), dns.SRV) except dns.message as e: if dns.nameError != e.rcode: raise port = 'sip' else: target = result.answer.target port = result.answer.port else: port = 'sip' transport = yield udp.connect(str(target), port)() asdf = request() asdf.method = method asdf.requestUri = requestUri asdf.sipVersion = 'SIP/2.0' asdf.header.append('To', requestUri) asdf.header.append( 'From', initiator + ';tag=' + untwisted.randstr( 6, '!%\'*+-.0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_`abcdefghijklmnopqrstuvwxyz~' )) asdf.header.append( 'Call-ID', untwisted.randstr( 6, '!"%\'()*+-./0123456789:<>?ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]_`abcdefghijklmnopqrstuvwxyz{}~' ) + '@' + domain) asdf.header.append('CSeq', '0 ' + method) # A UAC MUST insert a Max-Forwards header field into each request it # originates with a value that SHOULD be 70 asdf.header.append('Max-Forwards', '70') host, port = transport.socket.getsockname() sentBy = host + ':' + str(port) # The branch ID inserted by an element compliant with this specification MUST # always begin with the characters "z9hG4bK" #asdf.header.append('Via', 'SIP/2.0/UDP {};branch=z9hG4bK'.format(sentBy) + untwisted.randstr(6, '!%\'*+-.0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_`abcdefghijklmnopqrstuvwxyz~')) asdf.header.append( 'Via', 'SIP/2.0/UDP {0};branch=z9hG4bK'.format(sentBy) + untwisted.randstr( 6, '!%\'*+-.0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_`abcdefghijklmnopqrstuvwxyz~' )) asdf.content = '' transport.write(str(asdf)) while True: recv = yield transport.recv() match = rfc3261.response.match( recv, '( sipVersion, statusCode, reasonPhrase, messageBody )') if int(match.statusCode) not in range(100, 200): result = response() result.sipVersion = str(match.sipVersion) result.statusCode = int(match.statusCode) result.reasonPhrase = str(match.reasonPhrase) result.content = str(match.messageBody) if int(result) not in range(200, 300): raise result #return ... raise StopIteration(result)
def client(method, requestUri, initiator): match = qwer(rfc3261.requestUri, '$').match(requestUri, '( host, hostname, maddrParam, port )') # We define TARGET as the value of the maddr parameter of the URI, if # present, otherwise, the host value of the hostport component of the URI if match.maddrParam: target = match.maddrParam.host else: target = match.host if match.port: port = match.port elif target.hostname: try: result = yield dns.lookup('_sip._udp.' + str(target), dns.SRV) except dns.message as e: if dns.nameError != e.rcode: raise port = 'sip' else: target = result.answer.target port = result.answer.port else: port = 'sip' transport = yield udp.connect(str(target), port)() asdf = request() asdf.method = method asdf.requestUri = requestUri asdf.sipVersion = 'SIP/2.0' asdf.header.append('To', requestUri) asdf.header.append('From', initiator + ';tag=' + untwisted.randstr(6, '!%\'*+-.0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_`abcdefghijklmnopqrstuvwxyz~')) asdf.header.append('Call-ID', untwisted.randstr(6, '!"%\'()*+-./0123456789:<>?ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]_`abcdefghijklmnopqrstuvwxyz{}~') + '@' + domain) asdf.header.append('CSeq', '0 ' + method) # A UAC MUST insert a Max-Forwards header field into each request it # originates with a value that SHOULD be 70 asdf.header.append('Max-Forwards', '70') host, port = transport.socket.getsockname() sentBy = host + ':' + str(port) # The branch ID inserted by an element compliant with this specification MUST # always begin with the characters "z9hG4bK" #asdf.header.append('Via', 'SIP/2.0/UDP {};branch=z9hG4bK'.format(sentBy) + untwisted.randstr(6, '!%\'*+-.0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_`abcdefghijklmnopqrstuvwxyz~')) asdf.header.append('Via', 'SIP/2.0/UDP {0};branch=z9hG4bK'.format(sentBy) + untwisted.randstr(6, '!%\'*+-.0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_`abcdefghijklmnopqrstuvwxyz~')) asdf.content = '' transport.write(str(asdf)) while True: recv = yield transport.recv() match = rfc3261.response.match(recv, '( sipVersion, statusCode, reasonPhrase, messageBody )') if int(match.statusCode) not in range(100, 200): result = response() result.sipVersion = str(match.sipVersion) result.statusCode = int(match.statusCode) result.reasonPhrase = str(match.reasonPhrase) result.content = str(match.messageBody) if int(result) not in range(200, 300): raise result #return ... raise StopIteration(result)
def request(server, messageMethod=binding): try: transport = yield udp.connect(server, 'stun')() # Avoid error: service/proto not found except socket.error: transport = yield udp.connect(server, 3478)() request = message() request.messageMethod = messageMethod request.messageClass = 0x0000 request.magicCookie = '\x21\x12\xa4\x42' request.transactionId = os.urandom(12) transport.write(str(request)) recv = yield transport.recv() response = message() response.messageMethod = ord(recv[0]) << 6 & 0xf800 | ord(recv[1]) >> 1 & 0xf0 | ord(recv[1]) & 0xf response.messageClass = ord(recv[0]) << 8 & 0x100 | ord(recv[1]) & 0x10 response.magicCookie = recv[4:8] response.transactionId = recv[8:20] recv = recv[20:] while recv: type = ord(recv[0]) << 8 | ord(recv[1]) length = ord(recv[2]) << 8 | ord(recv[3]) itm = attribute(recv[4:4 + length]) # Each STUN attribute MUST end on a 32-bit boundary recv = recv[4 + length - length % -4:] if type in (MAPPED_ADDRESS, ALTERNATE_SERVER): # 0 1 2 3 4 5 6 7 8 9 A B C D E F 0 1 2 3 4 5 6 7 8 9 A B C D E F # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ # |0 0 0 0 0 0 0 0| Family | Port | # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ # | | # | Address (32 bits or 128 bits) | # | | # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ itm.family = ord(itm.value[1]) itm.port = ord(itm.value[2]) << 8 | ord(itm.value[3]) if IPv4 == itm.family: itm.address = socket.inet_ntop(socket.AF_INET, itm.value[4:]) elif IPv6 == itm.family: itm.address = socket.inet_ntop(socket.AF_INET6, itm.value[4:]) elif ERROR_CODE == type: # 0 1 2 3 4 5 6 7 8 9 A B C D E F 0 1 2 3 4 5 6 7 8 9 A B C D E F # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ # | Reserved, should be 0 |Class| Number | # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ # | Reason Phrase (variable) ... # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ itm['class'] = ord(itm.value[2]) itm.number = ord(itm.value[3]) itm.reasonPhrase = itm.value[4:] elif UNKNOWN_ATTRIBUTES == type: # 0 1 2 3 4 5 6 7 8 9 A B C D E F 0 1 2 3 4 5 6 7 8 9 A B C D E F # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ # | Attribute 1 Type | Attribute 2 Type | # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ # | Attribute 3 Type | Attribute 4 Type ... # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ itm.attributeType = untwisted.oneMany(*(ord(itm.value[offset]) << 8 | ord(itm.value[offset + 1]) for offset in range(0, len(itm.value), 2))) elif XOR_MAPPED_ADDRESS == type: # 0 1 2 3 4 5 6 7 8 9 A B C D E F 0 1 2 3 4 5 6 7 8 9 A B C D E F # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ # |0 0 0 0 0 0 0 0| Family | X-Port | # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ # | | # | X-Address (32 bits or 128 bits) | # | | # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ itm.family = ord(itm.value[1]) itm.port = (ord(itm.value[2]) ^ ord(response.magicCookie[0])) << 8 | ord(itm.value[3]) ^ ord(response.magicCookie[1]) if IPv4 == itm.family: itm.address = socket.inet_ntop(socket.AF_INET, ''.join(chr(ord(address) ^ ord(magicCookie)) for address, magicCookie in zip(itm.value[4:], response.magicCookie))) elif IPv6 == itm.family: itm.address = socket.inet_ntop(socket.AF_INET6, ''.join(chr(ord(address) ^ ord(magicCookie)) for address, magicCookie in zip(itm.value[4:], response.magicCookie + response.transactionId))) response.attribute.append(type, itm) if 0x0100 != response.messageClass: raise response #return ... raise StopIteration(response)
def request(server, messageMethod=binding): try: transport = yield udp.connect(server, 'stun')() # Avoid error: service/proto not found except socket.error: transport = yield udp.connect(server, 3478)() request = message() request.messageMethod = messageMethod request.messageClass = 0x0000 request.magicCookie = '\x21\x12\xa4\x42' request.transactionId = os.urandom(12) transport.write(str(request)) recv = yield transport.recv() response = message() response.messageMethod = ord(recv[0]) << 6 & 0xf800 | ord( recv[1]) >> 1 & 0xf0 | ord(recv[1]) & 0xf response.messageClass = ord(recv[0]) << 8 & 0x100 | ord(recv[1]) & 0x10 response.magicCookie = recv[4:8] response.transactionId = recv[8:20] recv = recv[20:] while recv: type = ord(recv[0]) << 8 | ord(recv[1]) length = ord(recv[2]) << 8 | ord(recv[3]) itm = attribute(recv[4:4 + length]) # Each STUN attribute MUST end on a 32-bit boundary recv = recv[4 + length - length % -4:] if type in (MAPPED_ADDRESS, ALTERNATE_SERVER): # 0 1 2 3 4 5 6 7 8 9 A B C D E F 0 1 2 3 4 5 6 7 8 9 A B C D E F # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ # |0 0 0 0 0 0 0 0| Family | Port | # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ # | | # | Address (32 bits or 128 bits) | # | | # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ itm.family = ord(itm.value[1]) itm.port = ord(itm.value[2]) << 8 | ord(itm.value[3]) if IPv4 == itm.family: itm.address = socket.inet_ntop(socket.AF_INET, itm.value[4:]) elif IPv6 == itm.family: itm.address = socket.inet_ntop(socket.AF_INET6, itm.value[4:]) elif ERROR_CODE == type: # 0 1 2 3 4 5 6 7 8 9 A B C D E F 0 1 2 3 4 5 6 7 8 9 A B C D E F # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ # | Reserved, should be 0 |Class| Number | # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ # | Reason Phrase (variable) ... # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ itm['class'] = ord(itm.value[2]) itm.number = ord(itm.value[3]) itm.reasonPhrase = itm.value[4:] elif UNKNOWN_ATTRIBUTES == type: # 0 1 2 3 4 5 6 7 8 9 A B C D E F 0 1 2 3 4 5 6 7 8 9 A B C D E F # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ # | Attribute 1 Type | Attribute 2 Type | # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ # | Attribute 3 Type | Attribute 4 Type ... # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ itm.attributeType = untwisted.oneMany( *(ord(itm.value[offset]) << 8 | ord(itm.value[offset + 1]) for offset in range(0, len(itm.value), 2))) elif XOR_MAPPED_ADDRESS == type: # 0 1 2 3 4 5 6 7 8 9 A B C D E F 0 1 2 3 4 5 6 7 8 9 A B C D E F # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ # |0 0 0 0 0 0 0 0| Family | X-Port | # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ # | | # | X-Address (32 bits or 128 bits) | # | | # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ itm.family = ord(itm.value[1]) itm.port = (ord(itm.value[2]) ^ ord(response.magicCookie[0])) << 8 | ord( itm.value[3]) ^ ord(response.magicCookie[1]) if IPv4 == itm.family: itm.address = socket.inet_ntop( socket.AF_INET, ''.join( chr(ord(address) ^ ord(magicCookie)) for address, magicCookie in zip( itm.value[4:], response.magicCookie))) elif IPv6 == itm.family: itm.address = socket.inet_ntop( socket.AF_INET6, ''.join( chr(ord(address) ^ ord(magicCookie)) for address, magicCookie in zip( itm.value[4:], response.magicCookie + response.transactionId))) response.attribute.append(type, itm) if 0x0100 != response.messageClass: raise response #return ... raise StopIteration(response)