-
Notifications
You must be signed in to change notification settings - Fork 287
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()