Manual:API Python3: Difference between revisions

From MikroTik Wiki
Jump to navigation Jump to search
 
Line 7: Line 7:
<pre>
<pre>
#!/usr/bin/python3
#!/usr/bin/python3
 
# -*- coding: latin-1 -*-
import sys, posix, time, hashlib, binascii, socket, select
import sys, posix, time, binascii, socket, select
import hashlib


class ApiRos:
class ApiRos:
Line 18: Line 19:
     def login(self, username, pwd):
     def login(self, username, pwd):
         for repl, attrs in self.talk(["/login"]):
         for repl, attrs in self.talk(["/login"]):
             chal = binascii.unhexlify(attrs['=ret'])
             chal = binascii.unhexlify((attrs['=ret']).encode('UTF-8'))
         md = hashlib.md5()
         md = hashlib.md5()
         md.update(b'\x00')
         md.update(b'\x00')
         md.update(bytes(pwd, 'utf-8'))
         md.update(pwd.encode('UTF-8'))
         md.update(chal)
         md.update(chal)
         self.talk(["/login", "=name=" + username,
         self.talk(["/login", "=name=" + username,
                   "=response=00" + binascii.hexlify(md.digest()).decode('utf-8')])
                   "=response=00" + binascii.hexlify(md.digest()).decode('UTF-8') ])


     def talk(self, words):
     def talk(self, words):
Line 59: Line 60:
              
              
     def writeWord(self, w):
     def writeWord(self, w):
         print("<<< " + w)
         print(("<<< " + w))
        b = bytes(w, "utf-8")
         self.writeLen(len(w))
         self.writeLen(len(b))
         self.writeStr(w)
         self.writeBytes(b)


     def readWord(self):
     def readWord(self):
         ret = self.readBytes(self.readLen()).decode('utf-8')
         ret = self.readStr(self.readLen())
         print(">>> " + ret)
         print((">>> " + ret))
         return ret
         return ret


     def writeLen(self, l):
     def writeLen(self, l):
         if l < 0x80:
         if l < 0x80:
             self.writeBytes(bytes([l]))
             self.writeByte((l).to_bytes(1, sys.byteorder))
         elif l < 0x4000:
         elif l < 0x4000:
             l |= 0x8000
             l |= 0x8000
             self.writeBytes(bytes([(l >> 8) & 0xff, l & 0xff]))
            tmp = (l >> 8) & 0xFF
             self.writeByte(((l >> 8) & 0xFF).to_bytes(1, sys.byteorder))
            self.writeByte((l & 0xFF).to_bytes(1, sys.byteorder))
         elif l < 0x200000:
         elif l < 0x200000:
             l |= 0xC00000
             l |= 0xC00000
             self.writeBytes(bytes([(l >> 16) & 0xff, (l >> 8) & 0xff, l & 0xff]))
             self.writeByte(((l >> 16) & 0xFF).to_bytes(1, sys.byteorder))
            self.writeByte(((l >> 8) & 0xFF).to_bytes(1, sys.byteorder))
            self.writeByte((l & 0xFF).to_bytes(1, sys.byteorder))
         elif l < 0x10000000:         
         elif l < 0x10000000:         
             l |= 0xE0000000         
             l |= 0xE0000000         
             self.writeBytes(bytes([(l >> 24) & 0xff, (l >> 16) & 0xff, (l >> 8) & 0xff, l & 0xff]))
             self.writeByte(((l >> 24) & 0xFF).to_bytes(1, sys.byteorder))
            self.writeByte(((l >> 16) & 0xFF).to_bytes(1, sys.byteorder))
            self.writeByte(((l >> 8) & 0xFF).to_bytes(1, sys.byteorder))
            self.writeByte((l & 0xFF).to_bytes(1, sys.byteorder))
         else:                       
         else:                       
             self.writeBytes(bytes([0xf0, (l >> 24) & 0xff, (l >> 16) & 0xff, (l >> 8) & 0xff, l & 0xff]))
             self.writeByte((0xF0).to_bytes(1, sys.byteorder))
            self.writeByte(((l >> 24) & 0xFF).to_bytes(1, sys.byteorder))
            self.writeByte(((l >> 16) & 0xFF).to_bytes(1, sys.byteorder))
            self.writeByte(((l >> 8) & 0xFF).to_bytes(1, sys.byteorder))
            self.writeByte((l & 0xFF).to_bytes(1, sys.byteorder))


     def readLen(self):
     def readLen(self):            
         c = self.readBytes(1)[0]
         c = ord(self.readStr(1))   
         if (c & 0x80) == 0x00:       
         if (c & 0x80) == 0x00:       
             pass                     
             pass                     
Line 91: Line 102:
             c &= ~0xC0               
             c &= ~0xC0               
             c <<= 8                 
             c <<= 8                 
             c += self.readBytes(1)[0]
             c += ord(self.readStr(1))   
         elif (c & 0xE0) == 0xC0:     
         elif (c & 0xE0) == 0xC0:     
             c &= ~0xE0               
             c &= ~0xE0               
             c <<= 8                 
             c <<= 8                 
             c += self.readBytes(1)[0]
             c += ord(self.readStr(1))   
             c <<= 8                 
             c <<= 8                 
             c += self.readBytes(1)[0]
             c += ord(self.readStr(1))   
         elif (c & 0xF0) == 0xE0:     
         elif (c & 0xF0) == 0xE0:     
             c &= ~0xF0               
             c &= ~0xF0               
             c <<= 8                 
             c <<= 8                 
             c += self.readBytes(1)[0]
             c += ord(self.readStr(1))   
             c <<= 8                 
             c <<= 8                 
             c += self.readBytes(1)[0]
             c += ord(self.readStr(1))   
             c <<= 8                 
             c <<= 8                 
             c += self.readBytes(1)[0]
             c += ord(self.readStr(1))   
         elif (c & 0xF8) == 0xF0:     
         elif (c & 0xF8) == 0xF0:     
             c = self.readBytes(1)[0]
             c = ord(self.readStr(1))   
             c <<= 8                 
             c <<= 8                 
             c += self.readBytes(1)[0]
             c += ord(self.readStr(1))   
             c <<= 8                 
             c <<= 8                 
             c += self.readBytes(1)[0]
             c += ord(self.readStr(1))   
             c <<= 8                 
             c <<= 8                 
             c += self.readBytes(1)[0]
             c += ord(self.readStr(1))   
         return c                     
         return c                     


     def writeBytes(self, str):         
     def writeStr(self, str):         
         n = 0;                    
         n = 0;
         while n < len(str):         
         while n < len(str):
            r = self.sk.send(bytes(str[n:], 'UTF-8'))
            if r == 0: raise RuntimeError("connection closed by remote end")
            n += r                 
 
    def writeByte(self, str):       
        n = 0;
         while n < len(str):
             r = self.sk.send(str[n:])
             r = self.sk.send(str[n:])
             if r == 0: raise RuntimeError("connection closed by remote end")
             if r == 0: raise RuntimeError("connection closed by remote end")
             n += r                   
             n += r                   


     def readBytes(self, length):       
     def readStr(self, length):       
         ret = b''                  
         ret = ''
         while len(ret) < length:  
         while len(ret) < length:
             s = self.sk.recv(length - len(ret))
             s = self.sk.recv(length - len(ret))
             if len(s) == 0: raise RuntimeError("connection closed by remote end")
             if s == '': raise RuntimeError("connection closed by remote end")
             ret += s
             ret += s.decode('UTF-8', 'replace')
         return ret
         return ret


def main():
def main():
     s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
     s = None
    s.connect((sys.argv[1], 8728)
    for res in socket.getaddrinfo(sys.argv[1], "8728", socket.AF_UNSPEC, socket.SOCK_STREAM):
     apiros = ApiRos(s);            
        af, socktype, proto, canonname, sa = res
        try:
            s = socket.socket(af, socktype, proto)
        except (socket.error, msg):
            s = None
            continue
        try:
            s.connect(sa)
        except (socket.error, msg):
            s.close()
            s = None
            continue
        break
    if s is None:
        print ('could not open socket')
        sys.exit(1)
 
     apiros = ApiRos(s);
     apiros.login(sys.argv[2], sys.argv[3]);
     apiros.login(sys.argv[2], sys.argv[3]);


Line 160: Line 195:
if __name__ == '__main__':
if __name__ == '__main__':
     main()
     main()


</pre>
</pre>

Revision as of 12:28, 26 April 2017

Summary

Since python language have introduced changes to syntax when going from 2.x to 3.x some adjustments had to be made for old code from API.

Code for Python3

code

#!/usr/bin/python3
# -*- coding: latin-1 -*-
import sys, posix, time, binascii, socket, select
import hashlib

class ApiRos:
    "Routeros api"
    def __init__(self, sk):
        self.sk = sk
        self.currenttag = 0
        
    def login(self, username, pwd):
        for repl, attrs in self.talk(["/login"]):
            chal = binascii.unhexlify((attrs['=ret']).encode('UTF-8'))
        md = hashlib.md5()
        md.update(b'\x00')
        md.update(pwd.encode('UTF-8'))
        md.update(chal)
        self.talk(["/login", "=name=" + username,
                   "=response=00" + binascii.hexlify(md.digest()).decode('UTF-8') ])

    def talk(self, words):
        if self.writeSentence(words) == 0: return
        r = []
        while 1:
            i = self.readSentence();
            if len(i) == 0: continue
            reply = i[0]
            attrs = {}
            for w in i[1:]:
                j = w.find('=', 1)
                if (j == -1):
                    attrs[w] = ''
                else:
                    attrs[w[:j]] = w[j+1:]
            r.append((reply, attrs))
            if reply == '!done': return r

    def writeSentence(self, words):
        ret = 0
        for w in words:
            self.writeWord(w)
            ret += 1
        self.writeWord('')
        return ret

    def readSentence(self):
        r = []
        while 1:
            w = self.readWord()
            if w == '': return r
            r.append(w)
            
    def writeWord(self, w):
        print(("<<< " + w))
        self.writeLen(len(w))
        self.writeStr(w)

    def readWord(self):
        ret = self.readStr(self.readLen())
        print((">>> " + ret))
        return ret

    def writeLen(self, l):
        if l < 0x80:
            self.writeByte((l).to_bytes(1, sys.byteorder))
        elif l < 0x4000:
            l |= 0x8000
            tmp = (l >> 8) & 0xFF
            self.writeByte(((l >> 8) & 0xFF).to_bytes(1, sys.byteorder))
            self.writeByte((l & 0xFF).to_bytes(1, sys.byteorder))
        elif l < 0x200000:
            l |= 0xC00000
            self.writeByte(((l >> 16) & 0xFF).to_bytes(1, sys.byteorder))
            self.writeByte(((l >> 8) & 0xFF).to_bytes(1, sys.byteorder))
            self.writeByte((l & 0xFF).to_bytes(1, sys.byteorder))
        elif l < 0x10000000:        
            l |= 0xE0000000         
            self.writeByte(((l >> 24) & 0xFF).to_bytes(1, sys.byteorder))
            self.writeByte(((l >> 16) & 0xFF).to_bytes(1, sys.byteorder))
            self.writeByte(((l >> 8) & 0xFF).to_bytes(1, sys.byteorder))
            self.writeByte((l & 0xFF).to_bytes(1, sys.byteorder))
        else:                       
            self.writeByte((0xF0).to_bytes(1, sys.byteorder))
            self.writeByte(((l >> 24) & 0xFF).to_bytes(1, sys.byteorder))
            self.writeByte(((l >> 16) & 0xFF).to_bytes(1, sys.byteorder))
            self.writeByte(((l >> 8) & 0xFF).to_bytes(1, sys.byteorder))
            self.writeByte((l & 0xFF).to_bytes(1, sys.byteorder))

    def readLen(self):              
        c = ord(self.readStr(1))    
        if (c & 0x80) == 0x00:      
            pass                    
        elif (c & 0xC0) == 0x80:    
            c &= ~0xC0              
            c <<= 8                 
            c += ord(self.readStr(1))    
        elif (c & 0xE0) == 0xC0:    
            c &= ~0xE0              
            c <<= 8                 
            c += ord(self.readStr(1))    
            c <<= 8                 
            c += ord(self.readStr(1))    
        elif (c & 0xF0) == 0xE0:    
            c &= ~0xF0              
            c <<= 8                 
            c += ord(self.readStr(1))    
            c <<= 8                 
            c += ord(self.readStr(1))    
            c <<= 8                 
            c += ord(self.readStr(1))    
        elif (c & 0xF8) == 0xF0:    
            c = ord(self.readStr(1))     
            c <<= 8                 
            c += ord(self.readStr(1))    
            c <<= 8                 
            c += ord(self.readStr(1))    
            c <<= 8                 
            c += ord(self.readStr(1))    
        return c                    

    def writeStr(self, str):        
        n = 0;
        while n < len(str):
            r = self.sk.send(bytes(str[n:], 'UTF-8'))
            if r == 0: raise RuntimeError("connection closed by remote end")
            n += r                  

    def writeByte(self, str):        
        n = 0;
        while n < len(str):
            r = self.sk.send(str[n:])
            if r == 0: raise RuntimeError("connection closed by remote end")
            n += r                  

    def readStr(self, length):      
        ret = ''
        while len(ret) < length:
            s = self.sk.recv(length - len(ret))
            if s == '': raise RuntimeError("connection closed by remote end")
            ret += s.decode('UTF-8', 'replace')
        return ret

def main():
    s = None
    for res in socket.getaddrinfo(sys.argv[1], "8728", socket.AF_UNSPEC, socket.SOCK_STREAM):
        af, socktype, proto, canonname, sa = res
        try:
             s = socket.socket(af, socktype, proto)
        except (socket.error, msg):
            s = None
            continue
        try:
            s.connect(sa)
        except (socket.error, msg):
            s.close()
            s = None
            continue
        break
    if s is None:
        print ('could not open socket')
        sys.exit(1)

    apiros = ApiRos(s);
    apiros.login(sys.argv[2], sys.argv[3]);

    inputsentence = []

    while 1:
        r = select.select([s, sys.stdin], [], [], None)
        if s in r[0]:
            # something to read in socket, read sentence
            x = apiros.readSentence()

        if sys.stdin in r[0]:
            # read line from input and strip off newline
            l = sys.stdin.readline()
            l = l[:-1]

            # if empty line, send sentence and start with new
            # otherwise append to input sentence
            if l == '':
                apiros.writeSentence(inputsentence)
                inputsentence = []
            else:
                inputsentence.append(l)

if __name__ == '__main__':
    main()



file

api client in python3

See also

API