Quantcast
Channel: AFPy's Planet
Viewing all articles
Browse latest Browse all 3786

Construire un C&C basique en python/FORTH au dessus de MQTT

$
0
0

Sommaire

Ingrédients

Cette recette nécessite : python, et en dépendances : paho-mqtt, confined, ainsi qu'un serveur MQTT (mosquitto avec ses utilitaires en ligne de commande) correctement configurés.

La pièce de résistance

Pour tout process que l'on veut piloter on va écrire du code python comme :

importpaho.mqtt.clientasmqttfromtimeimporttime,sleepfromconfinedimportparse,Value,popfromsubprocessimportPopen,PIPEimportpathlibimportosimportsocketstack=[]client_id=socket.gethostname()show_must_go=Falsedefon_connect(client,userdata,flags,reason_code,properties):print(f"Connected with result code {reason_code}")client.subscribe(f"BUS/{client_id}")client.subscribe(f"BUS")defon_lun(*a,**kw):kw["ctx"]["state"]="RAZ"defon_set_time_slice(*a,**kw):kw["ctx"]["time_slice"]=stack.pop().floatdefon_ping(*a,**kw):globalclient_idclient=kw["ctx"]["client"]client.publish("RES",f"'{client_id}':PONG")defon_sel(stack,**kw):globalclient_id,show_must_goifstack.pop().str==client_id:show_must_go=Truedefon_unsel(stack,**kw):globalclient_id,show_must_goifstack.pop().str==client_id:show_must_go=Falsedefon_test(stack,**kw):print("Yo")ctx=dict(cap=["www","forth"],time_slice=10,dispatch=dict(lun=on_lun,ping=on_ping,sel=on_sel,unsel=on_unsel,tsset=on_set_time_slice,_TEST=on_test,),)defon_message(client,userdata,msg):globalstack,ctxctx["client"]=clientclient.publish("RES",str(parse(ctx,msg.payload.decode(),data=stack,)))mqttc=mqtt.Client(mqtt.CallbackAPIVersion.VERSION2,client_id=client_id)mqttc.on_connect=on_connectmqttc.on_message=on_messagemqttc.username="pub"mqttc.password="pub"mqttc.tls_set(keyfile="./cfg/pub.key",certfile="./cfg/pub.crt",ca_certs="./cfg/RootCA.crt",tls_version=2)mqttc.connect("badass.home",8883,60)mqttc.loop_start()os.chdir(os.path.dirname(__file__))plugins=pathlib.Path("../plugin")whileTrue:start=time()ifshow_must_go:forpinplugins.glob("*_enabled"):withPopen([p,],stdout=PIPE,stdin=PIPE,stderr=PIPE,bufsize=0,)aswriter:whileres:=writer.stdout.read():writer.stdout.flush()formsginres.split():mqttc.publish(f"DATA/{client_id}",msg.decode())mqttc.publish("DATA/",f"{client_id}:core.processing_time:{time()-start}:GAUGE")iftime()-start<ctx["time_slice"]:sleep(ctx["time_slice"]-(time()-start))

Le client est en mode parano : TLS activé avec login/pass enforcé coté serveur par MQTT.

On va définir 2 commandes :

pub.sh

#!/usr/bin/env bashHERE=$( dirname $0)pushd$HERE

mosquitto_pub --cert ../cfg/4711.crt --key ../cfg/4711.key --cafile ../cfg/RootCA.crt -h badass.home -t BUS -u 4711 -P 4711 -m "$1"popd

qui publie en MQTT sur un canal BUS

et
listen.sh

#!/usr/bin/env bashHERE=$( dirname $0)pushd$HERE
mosquitto_sub -h badass.home -t RES/# &
mosquitto_sub -h badass.home -t DATA/# &popd

La recette

Pour pinger votre agent il vous suffit de faire

pub.sh PING

ce qui répond

'badass':PONG

Pour tester la fonction de test locale :

pub.sh _TEST

Normalement sur sortie standard du process python vous pouvez lire : 'Yo'.

pub.sh "'badass': SEL"

La sortie de LISTEN devrait montrer des lignes comme suit:

badass:cpu.load:1.39:GAUGEbadass:stat.procs_running:1:GAUGEbadass:stat.procs_blocked:1:GAUGEbadass:stat.intr:235643164:DERIVEbadass:stat.ctxt:474453646:DERIVEbadass:stat.processes:237036:DERIVEbadass:ps.processes:320:GAUGEbadass:ps.uninterruptible:1:GAUGEbadass:ps.runnable:1:GAUGEbadass:ps.sleeping:256:GAUGEbadass:ps.idle:62:GAUGEbadass:ps.stopped:0:GAUGEbadass:ps.paging:0:GAUGEbadass:ps.dead:0:GAUGEbadass:ps.zombie:0:GAUGEbadass:files.opened:17184:GAUGEbadass:core.processing_time:0.039983272552490234:GAUGE

Qui sont le résultat de l'enclenchement de la mesure qui se fait toutes les 10 secondes par défaut

pub.sh "20: TSSET"

Passe les mesures à 20 secondes d'écart.

pub.sh "'badass': UNSEL"

Arrête les mesures.

Diverses Questions Réponses

Un forth dans la boucle était il nécessaire ?

Non.

Mais il se trouve que j'en ai un en stock et que je rêvais de l'utiliser pour faire des tâches innocentes (principalement du templating).

Il est pas utilisé, mais disons que si vous faisiez :

pub.sh "2: 2: ADD"

en sortie vous auriez autant de 4: qu'il y a d'agents connectés sur le BUS.

Vous avez de base une calculette 4 opérations distribuées en prime.

Un vrai command & control préférerait un protocole plus passe partout comme https pour être moins visible

Ça tombe bien paho-mqtt et mosquito permettent de passer en websocket :)

Et si je voulais sécuriser ?

MQTT le permet avec des ACL par sujets.

Où est l'arborescente complète du projet il manque les plugins de mesure ?

Les plugins sont ici

Mais c'est bête en fait…

C'est pas faux, c'est pour ça que je sais pas quoi faire avec ce « projet »

Trop petit pour être un projet, ultra dur à tester, mais assez rigolo pour être utile

Des idées de futurs ?

Un projet « Bus Of Things » (BOT) qui standardiserait les commandes envoyées et leurs API pour faire comme une sorte d'ansible.

Une logique d'IPC/messaging générique pour des systèmes distribués (inclurais la gestion de process & co).

Un FORTH qui verrait toute fonction/agent comme reliée à un BUS MQTT et pour lequel les messages serait du FORTH qui agirait sur la fonction que s'appelerio objective FORTH. (Ça implique de sacrément développé la partie langage).

Pleins d'idées, trop d'idées …

Les sorties actuellement ressemblent au format d'entrée … C'est suspect non ?

Oui, j'ai envie de tester de laisser l'orchestrateur accepter des injections de code depuis les agents. Ex légitime, quand une sonde de mesure est en OVERRUN (trop de temps passé à mesurer comparé à une cadence attendue) qu'elle puisse changer la « clock » avec TSSET de l'orchestrateur.

J'ai envie d'expérimenter des systèmes scheduler less où chaque agent peut devenir le contrôleur et prendre la main et/ou modifier l'orchestrateur qui envoie les commandes.

Commentaires :voir le flux Atomouvrir dans le navigateur


Viewing all articles
Browse latest Browse all 3786

Trending Articles