-
Notifications
You must be signed in to change notification settings - Fork 271
Scripting
C3 exposes an API that can be used to script various actions. Swagger information is provided at localhost:52935/swagger.
This example demonstrates how an operator would automate updating the sleep and jitter for all of the channels a gateway is listening on.
The first step involves using the gateway ID to construct a request that will provide the IDs of the channels the gateway has:
Command:
curl http://localhost:5001/api/gateway/5849b894363fdf63
Output:
{"relays":[],"connectors":[],"agentId":"5849b894363fdf63","buildId":"d5d0","name":"gateway","channels":[{**"iid":"1"**,"type":824915724,"isNegotiationChannel":true,"jitter":[60.0,120.0],"propertiesText":{"arguments":[{"name":"Negotiation Identifier","type":"string","value":"cjez10qv"},{"name":"Filesystem path","type":"string","value":"z:\\"},{"name":"Clear","type":"boolean","value":false}],"jitter":[60.0,120.0]}},{**"iid":"2"**,"type":824915724,"isNegotiationChannel":true,"jitter":[60.0,120.0],"propertiesText":{"arguments":[{"name":"Negotiation Identifier","type":"string","value":"udvbfru2"},{"name":"Filesystem path","type":"string","value":"z:\\"},{"name":"Clear","type":"boolean","value":false}],"jitter":[60.0,120.0]}}],"peripherals":[],"routes":[],"isActive":true,"timestamp":1588839629}
Next, we can extract the ID using grep and cut:
curl http://localhost:5001/api/gateway/5849b894363fdf63 -s | grep -o "\"iid\":\"[0-9]\"" | cut -d ":" -f 2 | tr -d "\""
1
2
Finally, we can use this request in a for loop as part of a command request:
for id in $(curl http://localhost:5001/api/gateway/5849b894363fdf63 -s | grep -o "\"iid\":\"[0-9]\"" | cut -d ":" -f 2 | tr -d "\""); do curl http://localhost:5001/api/gateway/5849b894363fdf63/channel/$id/command --data '{"name":"ChannelCommandGroup","data":{"id":65534,"name":"UncShareFile","command":"Set UpdateDelayJitter","arguments":[{"type":"float","name":"Min","value":"60"},{"type":"float","name":"Max","value":"120"}]}}' -H "Content-Type: application/json" -v ; done
This command will set all channels update delay jitter to min:60 max:120
The general process for identifying how to script actions in C3 is as follows:
- In the C3 Web UI open up developer tools, you should see periodic requests to the gateway similar to those shown in the next figure.
- In the Web UI, perform some action on the gateway or on a relay. In the next image, the AddPeripheralBeacon command was executed on a relay, the request and response can be viewed.
- Extract the request payload, in this case:
{"name":"RelayCommandGroup","data":{"id":65275,"name":"Command","command":"AddPeripheralBeacon","arguments":[{"type":"string","name":"Pipe name","value":"wke3"},{"type":"int16","name":"Connection trials","value":10},{"type":"int16","name":"Trials delay","value":1000}]}}
-
Use the Swagger docs to identify how to perform this request against multiple relays. In this case, we need the Relay AgentID, which can be retrieved by making a request to /api/gateway/gateway id/Relay:
curl http://localhost:5001/api/gateway/5849b894363fdf63/Relay -s | grep -o "\"agentId\":\"[0-9a-zA-Z]*\""
"agentId":"e0975ccb3cdab08"
"agentId":"7d9c22e9f71a8564"
- Finally, add the previous request to a for loop and insert the payload from the step before that:
for agent in $(curl http://localhost:5001/api/gateway/5849b894363fdf63/Relay -s | grep -o "\"agentId\":\"[0-9a-zA-Z]*\"" | cut -d ":" -f 2 | tr -d "\""); do sed -i "s/pipenameval/$agent/g" file.json; curl -s http://localhost:5001/api/gateway/5849b894363fdf63/relay/$agent/command --data @file.json -H "Content-Type: application/json" -v; sed -i "s/$agent/pipenameval/g" file.json ;done
- The following script demonstrates leveraging the API to send an SMS everytime a new relay calls home.
import requests import json import time import argparse import sys from clockwork import clockwork def main(): parser = argparse.ArgumentParser() parser.add_argument("-g", "--gateway", help="The gateway ID to run against, eg c0addf0d260b7d87") parser.add_argument("-t", "--target", help="The ip address or hostname of C3") parser.add_argument("-p", "--port", help="The port number of C3") parser.add_argument("-k", "--key", help="Clockwork API key") parser.add_argument("-m", "--mobiles", help="A single mobile number or csv list, format example 447772883948") args = parser.parse_args() if len(sys.argv) < 5: parser.print_help() sys.exit() c3_url = "http://{0}:{1}/api/gateway/{2}".format(args.target, args.port, args.gateway) mobiles = args.mobiles.split(',') start_loop(url, args.key, mobiles) def start_loop(url, gateway_id, api_key, mobiles): api = clockwork.API(api_key) r = requests.get(url) j = json.loads(r.text) current_relays = len(j["relays"]) current_ids = [] for relay in j["relays"]: current_ids.append(relay["agentId"]) while True: index = 0 r = requests.get(url) j = json.loads(r.text) curr_len = len(j["relays"]) if curr_len > current_relays: index = curr_len - current_relays for relay in j["relays"]: if relay["agentId"] not in current_ids: message_string = "" if is_admin(relay): message_string = "New ADMIN relay from {0} with name {1}".format(relay["hostInfo"]["computerName"], relay["name"]) else: message_string = "New relay from {0} with name {1}".format(relay["hostInfo"]["computerName"], relay["name"]) print("[Debug] {0}".format(message_string)) current_ids.append(relay["agentId"]) for number in mobiles: message = clockwork.SMS( to = number, message = message_string, from_name = 'C3SMS') response = api.send(message) if response.success: print (response.id) else: print (response.error_code) print (response.error_message) current_relays = curr_len print("[Debug] Current number of relays is {0}".format(curr_len)) time.sleep(30) def is_admin(relay): return relay["hostInfo"]["isElevated"] if __name__ == '__main__': main()