123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283 |
- #!/usr/bin/env python3
- #
- # Copyright 2008, 2009 (C) Jose Vasconcellos <jvasco@verizon.net>
- #
- # A script that can communicate with jungo-based routers
- # (such as MI424-WR, USR8200 and WRV54G) to backup the installed
- # firmware and replace the boot loader.
- #
- # Tested with Python 2.5 on Linux and Windows
- #
- """Usage: %s [options] <IP_address> [image.bin | url]
- Valid options:
- \t-h | --help: usage statement
- \t-d | --dump: create a flash dump
- \t-f | --file: use <filename> to store dump contents
- \t-u | --user: provide username (default admin)
- \t-p | --pass: provide password (default password1)
- \t --port: set port for http (default 8080)
- \t-q | --quiet: don't display unnecessary information
- \t-r | --reboot: reboot target on successful transfer
- \t-V | --version: display version information
- If no image (or url) is given, a flash dump is created.
- A built-in http server is used when an image file is provided.
- """
- import os
- import sys
- import getopt
- import getpass
- import telnetlib
- import string
- import binascii
- import socket
- import _thread
- import socketserver
- import http.server
- reboot = 0
- HOST = "192.168.1.1"
- PORT = 8080
- user = "admin"
- #password = getpass.getpass()
- password = "password1"
- proto = "http"
- url = ""
- imagefile = ""
- dumpfile = ""
- verbose = 1
- do_dump = 0
- dumplen = 0x10000
- flashsize=4*1024*1024
- #device="br0"
- device="ixp0"
- ####################
- def start_server(server):
- httpd = socketserver.TCPServer((server,PORT),http.server.SimpleHTTPRequestHandler)
- _thread.start_new_thread(httpd.serve_forever,())
- ####################
- def get_flash_size():
- # make sure we don't have an A0 stepping
- tn.write("cat /proc/cpuinfo\n")
- buf = tn.read_until("Returned 0", 3)
- if not buf:
- print("Unable to obtain CPU information; make sure to not use A0 stepping!")
- elif buf.find('rev 0') > 0:
- print("Warning: IXP42x stepping A0 detected!")
- if imagefile or url:
- print("Error: No linux support for A0 stepping!")
- sys.exit(2)
- # now get flash size
- tn.write("cat /proc/mtd\n")
- buf = tn.read_until("Returned 0", 3)
- if buf:
- i = buf.find('mtd0:')
- if i > 0:
- return int(buf[i+6:].split()[0],16)
- # use different command
- tn.write("flash_layout\n")
- buf = tn.read_until("Returned 0", 3)
- i = buf.rfind('Range ')
- if i > 0:
- return int(buf[i+17:].split()[0],16)
- print("Can't determine flash size!")
- else:
- print("Unable to obtain flash size!")
- sys.exit(2)
- def image_dump(tn, dumpfile):
- if not dumpfile:
- tn.write("ver\n");
- buf = tn.read_until("Returned 0",2)
- i = buf.find("Platform:")
- if i < 0:
- platform="jungo"
- else:
- line=buf[i+9:]
- i=line.find('\n')
- platform=line[:i].split()[-1]
- tn.write("rg_conf_print /dev/%s/mac\n" % device);
- buf = tn.read_until("Returned 0",3)
- i = buf.find("mac(")
- if i > 0:
- i += 4
- else:
- print("No MAC address found! (use -f option)")
- sys.exit(1)
- dumpfile = "%s-%s.bin" % (platform, buf[i:i+17].replace(':',''))
- else:
- tn.write("\n")
- print("Dumping flash contents (%dMB) to %s" % (flashsize/1048576, dumpfile))
- f = open(dumpfile, "wb")
- t=flashsize/dumplen
- for addr in range(t):
- if verbose:
- sys.stdout.write('\r%d%%'%(100*addr/t))
- sys.stdout.flush()
- tn.write("flash_dump -r 0x%x -l %d -4\n" % (addr*dumplen, dumplen))
- tn.read_until("\n")
- count = addr*dumplen
- while 1:
- buf = tn.read_until("\n")
- if buf.strip() == "Returned 0":
- break
- s = buf.split()
- if s and s[0][-1] == ':':
- a=int(s[0][:-1],16)
- if a != count:
- print("Format error: %x != %x"%(a,count))
- sys.exit(2)
- count += 16
- f.write(binascii.a2b_hex(string.join(s[1:],'')))
- tn.read_until(">",1)
- f.close()
- if verbose:
- print("")
- def telnet_option(sock,cmd,option):
- #print "Option: %d %d" % (ord(cmd), ord(option))
- if cmd == telnetlib.DO:
- c=telnetlib.WILL
- elif cmd == telnetlib.WILL:
- c=telnetlib.DO
- sock.sendall(telnetlib.IAC + c + option)
- def telnet_timeout():
- print("Fatal error: telnet timeout!")
- sys.exit(1)
- def usage():
- print(__doc__ % os.path.basename(sys.argv[0]))
- ####################
- try:
- opts, args = getopt.getopt(sys.argv[1:], "hdf:qp:P:rvV", \
- ["help", "dump", "file=", "user=", "pass=", "port=",
- "quiet=", "reboot", "verbose", "version"])
- except getopt.GetoptError:
- # print help information and exit:
- usage()
- sys.exit(1)
- for o, a in opts:
- if o in ("-h", "--help"):
- usage()
- sys.exit(1)
- elif o in ("-V", "--version"):
- print("%s: 0.11" % sys.argv[0])
- sys.exit(1)
- elif o in ("-d", "--no-dump"):
- do_dump = 1
- elif o in ("-f", "--file"):
- dumpfile = a
- elif o in ("-u", "--user"):
- user = a
- elif o in ("-p", "--pass"):
- password = a
- elif o == "--port":
- PORT = int(a)
- elif o in ("-q", "--quiet"):
- verbose = 0
- elif o in ("-r", "--reboot"):
- reboot = 1
- elif o in ("-v", "--verbose"):
- verbose = 1
- # make sure we have enough arguments
- if len(args) > 0:
- HOST = args[0]
- if len(args) == 2:
- if args[1].split(':')[0] in ("tftp", "http", "ftp"):
- url = args[1]
- else:
- imagefile = args[1]
- else:
- do_dump = 1;
- ####################
- # create a telnet session to the router
- try:
- tn = telnetlib.Telnet(HOST)
- except socket.error as msg:
- print("Unable to establish telnet session to %s: %s" % (HOST, msg))
- sys.exit(1)
- tn.set_option_negotiation_callback(telnet_option)
- buf = tn.read_until("Username: ", 3)
- if not buf:
- telnet_timeout()
- tn.write(user+"\n")
- if password:
- buf = tn.read_until("Password: ", 3)
- if not buf:
- telnet_timeout()
- tn.write(password+"\n")
- # wait for prompt
- buf = tn.read_until("> ", 3)
- if not buf:
- telnet_timeout()
- flashsize = get_flash_size()
- if do_dump:
- image_dump(tn, dumpfile)
- if imagefile or url:
- splitpath = os.path.split(imagefile)
- # create load command
- if url:
- cmd = "load -u %s -r 0\n" % (url)
- else:
- server = tn.get_socket().getsockname()[0]
- cmd = "load -u http://%s:%d/%s -r 0\n" % (server, PORT, splitpath[1])
- if not os.access(imagefile, os.R_OK):
- print("File access error: %s" % (imagefile))
- sys.exit(3)
- # make sure we're in the directory where the image is located
- if splitpath[0]:
- os.chdir(splitpath[0])
- start_server(server)
- if verbose:
- print("Unlocking flash...")
- tn.write("unlock 0 0x%x\n" % flashsize)
- buf = tn.read_until("Returned 0",5)
- if verbose:
- print("Writing new image...")
- print(cmd, end=' ')
- tn.write(cmd)
- buf = tn.read_until("Returned 0",10)
- # wait till the transfer completed
- buf = tn.read_until("Download completed successfully",20)
- if buf:
- print("Flash update complete!")
- if reboot:
- tn.write("reboot\n")
- print("Rebooting...")
- tn.write("exit\n")
- tn.close()
|