Skip to content

Scripting

Grzegorz Rychlik edited this page Jan 18, 2021 · 1 revision

C3 exposes an API that can be used to script various actions. Swagger information is provided at localhost:52935/swagger.

Scripting UpdateDelayJitter

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

General Process

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.

dev-tools

  • 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.

add-beacon

  • 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

Example - C3 SMS Script

  • 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()
Clone this wiki locally