in extensions/coap/protocols/CoapC2Protocol.cpp [193:295]
minifi::c2::C2Payload CoapProtocol::serialize(const minifi::c2::C2Payload &payload) {
if (nullptr == coap_service_) {
// return an error if we don't have a coap service
logger_->log_error("CoAP service requested without any configured hostname or port");
return {payload.getOperation(), state::UpdateState::READ_ERROR};
}
if (require_registration_) {
logger_->log_debug("Server requested agent registration, so attempting");
auto response = minifi::c2::RESTSender::consumePayload(rest_uri_, payload, minifi::c2::TRANSMIT, false);
if (response.getStatus().getState() == state::UpdateState::READ_ERROR) {
logger_->log_trace("Could not register");
return {payload.getOperation(), state::UpdateState::READ_COMPLETE};
} else {
logger_->log_trace("Registered agent.");
}
require_registration_ = false;
return {payload.getOperation(), state::UpdateState::READ_COMPLETE};
}
uint16_t version = 0;
uint8_t payload_type = 0;
uint16_t size = 0;
io::BufferStream stream;
stream.write(version);
std::string endpoint = "heartbeat";
switch (payload.getOperation()) {
case minifi::c2::Operation::acknowledge:
endpoint = "acknowledge";
payload_type = 0;
stream.write(&payload_type, 1);
if (writeAcknowledgement(&stream, payload) != 0) {
return {payload.getOperation(), state::UpdateState::READ_ERROR};
}
break;
case minifi::c2::Operation::heartbeat:
payload_type = 1;
stream.write(&payload_type, 1);
if (writeHeartbeat(&stream, payload) != 0) {
logger_->log_error("Could not write heartbeat");
return {payload.getOperation(), state::UpdateState::READ_ERROR};
}
break;
default:
logger_->log_error("Could not identify operation");
return {payload.getOperation(), state::UpdateState::READ_ERROR};
}
size_t bsize = stream.size();
CoapMessage msg;
msg.data_ = const_cast<uint8_t *>(utils::as_span<const uint8_t>(stream.getBuffer()).data());
msg.size_ = bsize;
coap::controllers::CoapResponse message = coap_service_->sendPayload(COAP_REQUEST_POST, endpoint, &msg);
const auto message_data = message.getData();
if (isRegistrationMessage(message)) {
require_registration_ = true;
} else if (!message_data.empty()) {
io::BufferStream responseStream(message_data);
responseStream.read(version);
responseStream.read(size);
logger_->log_trace("Received ack. version %d. number of operations %d", version, size);
minifi::c2::C2Payload new_payload(payload.getOperation(), state::UpdateState::NESTED);
for (int i = 0; i < size; i++) {
uint8_t operationType;
uint16_t argsize = 0;
std::string operand;
std::string id;
REQUIRE_SIZE_IF(1, responseStream.read(operationType))
REQUIRE_VALID(responseStream.read(id, false))
REQUIRE_VALID(responseStream.read(operand, false))
logger_->log_trace("Received op %d, with id %s and operand %s", operationType, id, operand);
auto newOp = getOperation(operationType);
minifi::c2::C2Payload nested_payload(newOp, state::UpdateState::READ_COMPLETE);
nested_payload.setIdentifier(id);
minifi::c2::C2ContentResponse new_command(newOp);
new_command.delay = 0;
new_command.required = true;
new_command.ttl = -1;
new_command.name = operand;
new_command.ident = id;
responseStream.read(argsize);
for (int j = 0; j < argsize; j++) {
std::string key;
std::string value;
REQUIRE_VALID(responseStream.read(key))
REQUIRE_VALID(responseStream.read(value))
new_command.operation_arguments[key] = value;
}
nested_payload.addContent(std::move(new_command));
new_payload.addPayload(std::move(nested_payload));
}
return new_payload;
}
return {payload.getOperation(), state::UpdateState::READ_ERROR};
}