def ipa_handle_resp(x, tk, verbose=False, proc=None): s = data2str(x.recv(38)) if "0023fe040108010701020103010401050101010011" in s: retries = 3 while True: print("\tsending IPA identity(%s) at %s" % (tk, time.strftime("%T"))) try: x.send(IPA().id_resp( IPA().identity(name=(tk + '\0').encode('utf-8')))) print("\tdone sending IPA identity(%s) at %s" % (tk, time.strftime("%T"))) break except: print("\tfailed sending IPA identity at", time.strftime("%T")) if proc: print("\tproc.poll() = %r" % proc.poll()) if retries < 1: print("\tgiving up") raise print("\tretrying (%d attempts left)" % retries) retries -= 1 else: if (verbose): print("\tBSC <- NAT: ", s)
def process_chunk(self, data): """ Generic message dispatcher for IPA (sub)protocols based on protocol name, lambda default should never happen """ (_, proto, extension, content) = IPA().del_header(data) if content is not None: self.dbg('IPA received %s::%s [%d/%d] %s' % (IPA().proto(proto), IPA().ext_name(proto, extension), len(data), len(content), content)) method = getattr(self, 'handle_' + IPA().proto(proto), lambda: "protocol dispatch failure") method(content, proto, extension)
def testUssdSideChannelProvider(self): self.vty.command("end") self.vty.enable() self.vty.command("configure terminal") self.vty.command("nat") self.vty.command("ussd-token key") self.vty.command("end") res = self.vty.verify("show ussd-connection", [ 'The USSD side channel provider is not connected and not authorized.' ]) self.assertTrue(res) ussdSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) ussdSocket.connect(('127.0.0.1', 5001)) ussdSocket.settimeout(2.0) print("Connected to %s:%d" % ussdSocket.getpeername()) print("Expecting ID_GET request") data = ussdSocket.recv(4) self.assertEqual(data, b"\x00\x01\xfe\x04") print("Going to send ID_RESP response") res = ussdSocket.send(IPA().id_resp(IPA().tag_name('key' + '\0'))) self.assertEqual(res, 11) # initiating PING/PONG cycle to know, that the ID_RESP message has been processed print("Going to send PING request") res = ussdSocket.send(IPA().ping()) self.assertEqual(res, 4) print("Expecting PONG response") data = ussdSocket.recv(4) self.assertEqual(data, b"\x00\x01\xfe\x01") res = self.vty.verify( "show ussd-connection", ['The USSD side channel provider is connected and authorized.']) self.assertTrue(res) print("Going to shut down connection") ussdSocket.shutdown(socket.SHUT_WR) print("Expecting EOF") data = ussdSocket.recv(4) self.assertEqual(data, b"") ussdSocket.close() res = self.vty.verify("show ussd-connection", [ 'The USSD side channel provider is not connected and not authorized.' ]) self.assertTrue(res)
def recv_msgs(self): responses = {} data = self.sock.recv(4096) while (len(data)>0): (head, data) = IPA().split_combined(data) answer = Ctrl().rem_header(head).decode() if verbose: print("Got message:", answer) (mtype, id, msg) = answer.split(None, 2) id = int(id) rsp = {'mtype': mtype, 'id': id} if mtype == "ERROR": rsp['error'] = msg else: split = msg.split(None, 1) rsp['var'] = split[0] if len(split) > 1: rsp['value'] = split[1] else: rsp['value'] = None responses[id] = rsp if verbose: print("Decoded replies: ", responses) return responses
def handle_UNKNOWN(self, data, proto, extension): """ Default protocol handler """ self.dbg( 'IPA received message for %s (%s) protocol with attribute %s' % (IPA().proto(proto), proto, extension))
def handle_OSMO(self, data, proto, extension): """ Dispatcher point for OSMO subprotocols based on extension name, lambda default should never happen """ method = getattr(self, 'osmo_' + IPA().ext(extension), lambda: "extension dispatch failure") method(data)
class IPAFactory(ReconnectingClientFactory): """ Generic IPA Client Factory which can be used to store state for various subprotocols and manage connections Note: so far we do not really need separate Factory for acting as a server due to protocol simplicity """ protocol = IPACommon debug = False ccm_id = IPA().identity(unit=b'1515/0/1', mac=b'b0:0b:fa:ce:de:ad:be:ef', utype=b'sysmoBTS', name=b'StingRay', location=b'hell', sw=IPA.version.encode('utf-8')) def __init__(self, proto=None, debug=False, ccm_id=None): if proto: self.protocol = proto if debug: self.debug = debug if ccm_id: self.ccm_id = ccm_id def clientConnectionFailed(self, connector, reason): """ Only necessary for as debugging aid - if we can somehow set parent's class noisy attribute then we can omit this method """ if self.debug: print('IPAFactory connection failed:', reason.getErrorMessage()) ReconnectingClientFactory.clientConnectionFailed(self, connector, reason) def clientConnectionLost(self, connector, reason): """ Only necessary for as debugging aid - if we can somehow set parent's class noisy attribute then we can omit this method """ if self.debug: print('IPAFactory connection lost:', reason.getErrorMessage()) ReconnectingClientFactory.clientConnectionLost(self, connector, reason)
def create_full_IPA(self, parent, cells, type, subtype=None, test=False, mom=-1): try: if subtype is None: subtype = type for s in IPA.values(): if s.type != type and s.type != subtype: continue f = tk.Frame(parent) c = ["#009", "#666"] if test: c = ["#00F", "#000"] l = tk.Label(f, text=s.symb, state=tk.DISABLED, fg=c[0], disabledforeground=c[1], cursor="hand2", font=("Noto Sans", 12)) if not test: l.config(compound=tk.BOTTOM) # Store state of Symb l.bind("<Button-1>", self.add_IPA) else: l.bind("<Button-1>", self.play_IPA) l.bind("<Enter>", lambda e: self.change_IPA(e, True)) l.bind("<Leave>", lambda e: self.change_IPA(e, False)) l.grid() f.grid(column=s.col() + 1, row=s.row() + 1, sticky=s.anc()) cells[s.row()][s.col()] = f return cells except Exception as e: self.throw_err("#UR_FULL" + str(mom) + "ERR", e)
def connectionMade(self): """ Keep reconnection logic working by calling routine from CCM Initiate CCM upon connection """ print('IPA server connection made!') super(IPAServer, self).connectionMade() self.transport.write(IPA().id_get())
def dataReceived(self, data): """ Override for dataReceived from Int16StringReceiver because of inherently incompatible interpretation of length If default handler is used than we would always get off-by-1 error (Int16StringReceiver use equivalent of l + 2) """ if len(data): (head, tail) = IPA().split_combined(data) self.process_chunk(head) self.dataReceived(tail)
def ipa_handle_small(x, verbose=False): s = data2str(x.recv(4)) if len(s) != 4 * 2: raise Exception("expected to receive 4 bytes, but got %d (%r)" % (len(s) / 2, s)) if "0001fe00" == s: if (verbose): print("\tBSC <- NAT: PING?") x.send(IPA().pong()) elif "0001fe06" == s: if (verbose): print("\tBSC <- NAT: IPA ID ACK") x.send(IPA().id_ack()) elif "0001fe00" == s: if (verbose): print("\tBSC <- NAT: PONG!") else: if (verbose): print("\tBSC <- NAT: ", s)
def connectionMade(self): """ Keep reconnection logic working by calling routine from CCM Initiate CCM upon connection """ addr = self.transport.getPeer() self.factory.log.info('IPA server: connection from %s:%d client' % (addr.host, addr.port)) super(IPAServer, self).connectionMade() self.transport.write(IPA().id_get())
def handle_CCM(self, data, proto, msgt): """ CCM (IPA Connection Management) Only basic logic necessary for tests is implemented (ping-pong, id ack etc) """ if msgt == IPA.MSGT['ID_GET']: self.transport.getHandle().sendall(IPA().id_resp(self.factory.ccm_id)) # if we call # self.transport.write(IPA().id_resp(self.factory.test_id)) # instead, than we would have to also call # reactor.callLater(1, self.ack) # instead of self.ack() # otherwise the writes will be glued together - hence the necessity for ugly hack with 1s timeout # Note: this still might work depending on the IPA implementation details on the other side self.ack() # schedule PING in 4s reactor.callLater(4, self.ping) if msgt == IPA.MSGT['PING']: self.pong()
def pong(self): self.transport.write(IPA().pong())
def ack(self): self.transport.write(IPA().id_ack())