Downloading a file from a python ftp server to cisco ios device - python

At the moment, my networking team is downloading a firmware version using an FTP server (Filezilla).
We create an account on the server, upload the firmware to the server and then on the cisco device we use the command copy ftp://username:password#server_ip/file_name storage_device: and the device is downloading the firmware from the ftp server.
Now, i have a website created with Flask in python, that has some scripts that my team uses, and i want to add a script that allows the user to upload a file to the website, supply the ip of the device, and the script will connect to the device and pull the file from the server.
While creating an ftp server using pyftpdlib, i have encounterd some issues, as the device is logging in with the supplied user, but does not download the file.
If i log in to the server using an FTP client (FileZilla client) i can download the file separately.
I guess the issue is with the cisco device trying to download the firmware directly while connecting.
The code I used to create the python server:
import os
from pyftpdlib.authorizers import DummyAuthorizer
from pyftpdlib.handlers import FTPHandler
from pyftpdlib.servers import FTPServer
def main():
authorizer = DummyAuthorizer()
authorizer.add_user('username', 'password', '/ftp', perm='elradfmwMT')
handler = FTPHandler
handler.authorizer = authorizer
handler.banner = "Test FTP server"
address = ('0.0.0.0', 21)
server = FTPServer(address, handler)
server.max_cons = 256
server.max_cons_per_ip = 10
server.serve_forever()
if __name__ == '__main__':
main()
If anyone has encounterd any issue like that, help would be appreciated.
Thank you!

Two possible issues:
1. Watch the diskspace on the IOS device. Some platforms have very little space for extra images, so good image hygiene is essential.
2. In my various experiments, I've found that pushing the image to the device is generally more reliable than asking the device to pull the image from elsewhere. You may need to add a configuration entry "ip scp server enable". Then you can write your script to push the images diretly.

Related

connecting to a FTP server using ftplib with a proxy in Python

i am getting really confused on how to connect to an ftp server while using a proxy in python. Some previous examples have confused me a lot as i am new to Python. Below are the variables i believe that will be needed in the code sample (the proxy is only a example for security reasons as is the username and password).
can someone please show me how to connect to the ftp server and download a file
the end goal is to use python to download files from this ftp server
import ftplib
proxy = {'http': "auth-proxy.xxxx.com:232", 'https': "auth-proxy.xxx.com:232"}
ftp_site = 'https://data.ftse.com'
username = 'xxxxxx'
password = 'yyyyyy'
#file path where the file is on the ftp server is below
filepath = 'https://data.ftse.com/filedownloadservlet?filename=eerf1808.csv&phyName=nXVi8I4q5Boy8gBpdpDg3jNBqfAZy0vfydRBHC3zs3qt6YadMA6xa9LM3QaIgx-g'

Uploading to an FTP server on the same wifi network (python)

I am trying to upload a file to an ftp server on my same wifi network to get a picture on to a digital picture frame. I succeeded in uploading through file explorer, but when uploading using a python script I get a 530 response.
Here is the code so far
import ftplib
ftp = ftplib.FTP()
ftp.connect("111.111.1.11", 1111) #dummy host and port
file = open('C:/path/to/file/test1.png','rb')
ftp.storbinary('test.png', file)
file.close()
ftp.quit()
The server does not requre me to log in with a username and password on file explorer, is there some sort of default I need?
530 error code means Authentication failed error so you are missing the authentication piece. Maybe you can do something like this:
ftp = FTP(source_address=("111.111.1.11", 1111))
ftp.login(user, password)
Note that if you don't provide a user and password it will login with:
user anonymous
password anonymous
as described here
Also I would recommend you reading about S-FTP (Secure FTP) because in FTP the credentials are passed in clear text in the login request.
S-FTP is a communication protocol similar to FTP but built on top of ssh.
Hope this helped you !

grpc client dns resolution failed when trying to access grpc server on same network

I'm trying to call a GRPC server running on a .Net Core project from a Python client.
When running against localhost:5001 it works fine, but running against the actual IP of the machine from within the same network like 192.168.1.230:5001 it doesn't work and I get an error DNS resolution failed.
I've downloaded the SSL cert and am at the moment reading it as a file from the client. It works when running against localhost so I don't think that is the problem.
Is there a better way to do this kind of testing of having clients run on separate devices but on the same network as the server? Hosting the GRPC server outside during development doesn't really seem like the best solution.
Python code:
import grpc
import datamessage_pb2 as datamessage
import datamessage_pb2_grpc as datamessageService
def main():
print("Calling grpc server")
with open("localhost.cer", "rb") as file:
cert = file.read()
credentials = grpc.ssl_channel_credentials(cert)
channel = grpc.secure_channel("https://192.168.1.230:5001", credentials)
# channel = grpc.secure_channel("localhost:5001", credentials)
stub = datamessageService.StationDataHandlerStub(channel)
request = datamessage.StationDataModel(
temperature=22.3, humidity=13.3, soilMoisture=35.0)
result = stub.RegisterNewStationData(request)
print(result)
main()
Server settings in Program.cs:
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseUrls("https://*:5001");
webBuilder.UseStartup<Startup>();
});
Settings in firewall:
Traceback:
grpc._channel._Rendezvous: <_Rendezvous of RPC that terminated with:
status = StatusCode.UNAVAILABLE
details = "DNS resolution failed"
debug_error_string = "{"created":"#1576101634.549000000","description":"Failed to pick subchannel","file":"src/core/ext/filters/client_channel/client_channel.cc","file_line":3934,"referenced_errors":[{"created":"#1576101634.549000000","description":"Resolver transient failure","file":"src/core/ext/filters/client_channel/resolving_lb_policy.cc","file_line":262,"referenced_errors":[{"created":"#1576101634.549000000","description":"DNS resolution failed","file":"src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.cc","file_line":202,"grpc_status":14,"referenced_errors":[{"created":"#1576101634.549000000","description":"OS Error","file":"src/core/lib/iomgr/resolve_address_windows.cc","file_line":96,"os_error":"No such host is known.\r\n","syscall":"getaddrinfo","wsa_error":11001}]}]}]}"
In Python gRPC client, calling channel without protocol (https:) is required. So, I called gRPC service in dotnet core framework with following and it worked. Note, dotnet gRPC server was listening on https://localhost:5001.
with open('localhost.crt', 'rb') as f:
credentials = grpc.ssl_channel_credentials(f.read())
with grpc.secure_channel('localhost:5001', credentials) as channel:
stub = pb2_grpc.GreeterStub(channel)
request = pb2.HelloRequest(name = "GreeterPythonClient")
response = stub.SayHello(request)

Accessing device on local network through server hosted webhook

I have a python script that acts as a webhook. A part of it is as follows:
import json
import os
import urllib
import socket
import _thread
from flask import Flask
from flask import request
from flask import make_response
app=Flask(__name__)
ip = ('192.168.1.75', 9050)
#app.route('/webhook',methods=['GET','POST'])
def webhook():
_thread.start_new_thread(sendDataToDevice,(ip))
req = request.get_json(silent=True,force=True)
print("Request:")
print(json.dumps(req,indent=4))
res=makeWebHookResult(req)
res=json.dumps(res,indent=4)
r=make_response(res)
r.headers['Content-Type']='application/json'
return r
if __name__ == '__main__':
app.run(port=8080,host='localhost')
The function of the script is to send some data to a device connected to the local network.
It works flawlessly when I open my web browser and type the following on the url bar:
http://localhost:8080/webhook
I want to host the script on a server, eg. Heroku. How can I access the local device in that case?
Note: I know I can run the script on my local machine and make it visible to the internet using ngrok, but I want to keep it accessible even when my computer is switched off. Also, want a fixed link, and the links given by ngrok change on every run.
I've faced a similar issue before with IoT. Unfortunately there is no simple way to make a device be visible online. Here's a simple solution I've used. It might not be the best, but it works.
DDNS + Port Forwarding + Static IP
If you have access to your local WiFi router, then you can setup something called as DDNS (Dynamic Domain Name System). Your router will then connect to a DDNS service provider like no-ip (www.noip.com) and it will be visible on the internet. You can give a custom URL like susmit-home.noip.com.
However susmit-home.noip.com will now point only to your WiFi router and not your WiFi network. So if you want to access the local device_ip and device_port such as "192.168.1.75", 9050. Then you can setup Port Forwarding on your router for that local IP-Port combination. Usually the setup looks like this:
Local IP: device_ip (e.g. 192.168.1.75)
Local Port: device_port (e.g. 9050)
Outbound Port: any_port (e.g. 9050)
Make sure that your device_ip is a static IP on your WiFi router so that it doesn't change.
Finally in your code you can just replace the line ip = ('192.168.1.75', 9050) with ip = ('susmit-home.noip.com', 9050).
Other solutions:
A slightly more complicated solution is setting up a VPN, such that your local network and your remote server (e.g. Heroku) will all be available to each other as if they were within the same local network.
If your device is a computer or a Raspberry Pi, then you can use SSH Remote Port Forwarding to have access to your local device from the remote server.

How to configure pyftpdlib to create an 'active' only FTP server?

I need to create a test case for a FTP client that involves connecting to a server that only accepts 'active' FTP connections. For other cases I am using pyftpdlib, and it works like charm, but I can't see an easy way to configure it to behave just in FTP active mode, and not passive.
Thanks.
If by what you wrote in the title you mean "literaly disable PASV (passive)" mode you can just tell pyftpdlib to not interpret that command. Not tested:
from pyftpdlib.ftpserver import FTPHandler
handler = FTPHandler
del handler.proto_cmds['PASV']
del handler.proto_cmds['EPSV']
...
This way pyftpdlib will reject any PASV/EPSV request with "550 Command PASV not understood.".

Categories