294 lines
12 KiB
C
294 lines
12 KiB
C
/*
|
|
Copyright (c) 2013, 2014 IOnU Security Inc. All rights reserved
|
|
Created August 2013 by Kendrick Webster
|
|
|
|
K2IPC.h - header for commmon IPC declarations for K2 socket
|
|
notifier UDP protocol. This header is shared with the client
|
|
and the daemon.
|
|
|
|
Protocol overview
|
|
-----------------
|
|
The messaging protocol uses UDP packets with ping-pong ACK,
|
|
retries, and sequence numbers for reliable in-order delivery.
|
|
*/
|
|
#pragma once
|
|
|
|
/*
|
|
Packets consist of the following fields:
|
|
|
|
octets description
|
|
--------------------------------------------------------------------------
|
|
7 nonce (random initialization vector)
|
|
2 protocol version
|
|
3 client instance (for multiple clients sharing a UDP port)
|
|
1 sequence number (echoed in ACK)
|
|
1 opcode
|
|
<n> body, per opcode, NUL-terminated string
|
|
6 message integrity code (MIC)
|
|
|
|
All fields after the nonce are encrypted using an auto-hashing stream
|
|
cipher with a hard-coded key. The decrypted MIC will match only for
|
|
properly encrypted packets. Spurious packets fail the MIC check. This
|
|
'encryption' is used only for spurious packet rejection (not security).
|
|
|
|
Multi-byte fields are in network byte order (big endian).
|
|
*/
|
|
#define K2IPC_UDP_OVERHEAD 28 /* 20 bytes IPv4 header, 8 bytes UDP header */
|
|
#define K2IPC_MTU 576 /* IPv4 minimum is 576 bytes, IPv6 is 1280 */
|
|
#define K2IPC_PROTOCOL_VERSION 1
|
|
#define K2IPC_NONCE_SIZE 7
|
|
#define K2IPC_MIC_SIZE 6
|
|
#define K2IPC_CRYPT_SIZE (5 + 3 + K2IPC_MIC_SIZE) /* 3 octets for seq_num, opcode, NUL */
|
|
#define K2IPC_OVERHEAD_SIZE (K2IPC_CRYPT_SIZE + K2IPC_NONCE_SIZE)
|
|
/*
|
|
Packets are smaller than legacy ethernet MTU to avoid fragmentation,
|
|
minimize latency, and keep the memory footprint small.
|
|
*/
|
|
#define K2IPC_MAX_PACKET_SIZE 1440
|
|
#define K2IPC_MAX_STRING_LENGTH (K2IPC_MAX_PACKET_SIZE - K2IPC_OVERHEAD_SIZE)
|
|
/*
|
|
Some networks (i.e. 4G) can only handle small packets (dropping any that
|
|
exceed their size limit). The safest minimum size is 512 bytes since
|
|
this is used by DNS and other well-established protocols that have to be
|
|
supported everywhere.
|
|
|
|
Currently (6/17/14) there are two packet types that may exceed 512 bytes:
|
|
1) SUBSCRIBE_OFFICE (sent from client to daemon), and 2) ACK_QUERY_STATS
|
|
(sent from daemon to client). Since SUBSCRIBE_OFFICE packets may also
|
|
exceed 1440 bytes, code is already in place to handle fragmenting and
|
|
reassembling these messages. The ACK_QUERY_STATS messages, however, are
|
|
just small enough to fit in a 1440 byte packet. No fragmentation code
|
|
is in place for them (or for any daemon-to-client packet).
|
|
|
|
The ACK_QUERY_STATS messages are only used for monitoring and testing,
|
|
and only by bots and clients that are connected via a wired network
|
|
(never 4G). There is no need to use the smaller packet size for them.
|
|
|
|
To avoid having to write packet fragmentation and re-assembly code for
|
|
the daemon-to-client direction, a different size limit is being added
|
|
for client-to-daemon packets.
|
|
*/
|
|
#define K2IPC_MAX_PACKET_SIZE_FROM_CLIENTS 512
|
|
#define K2IPC_MAX_STRING_LENGTH_FROM_CLIENTS (K2IPC_MAX_PACKET_SIZE_FROM_CLIENTS - K2IPC_OVERHEAD_SIZE)
|
|
|
|
#define K2IPC_PACKET_OPCODES \
|
|
X(CONNECT) /* client --> daemon, body = ClientURN */ \
|
|
X(ACK_CONNECT) /* daemon --> client, body = ClientURN */ \
|
|
X(NAK_CONNECT) /* daemon --> client, body = ClientURN */ \
|
|
X(MESSAGE) /* daemon --> client, see comments below */ \
|
|
X(ACK_MESSAGE) /* client --> daemon, body = ClientURN */ \
|
|
X(LOGOUT) /* client --> daemon, body = ClientURN */ \
|
|
X(ACK_LOGOUT) /* daemon --> client, body = ClientURN */ \
|
|
X(POLL_DB) /* client --> daemon, body = ClientURN */ \
|
|
X(ACK_POLL_DB) /* daemon --> client, body = ClientURN */ \
|
|
X(HEARTBEAT) /* client --> daemon, body = ClientURN */ \
|
|
X(ACK_HEARTBEAT) /* daemon --> client, body = ClientURN */ \
|
|
X(SUBSCRIBE_OFFICE) /* client --> daemon, see comments below */ \
|
|
X(ACK_SUBSCRIBE_OFFICE) /* daemon --> client, body = ClientURN */ \
|
|
X(DEVICE_STATUS) /* daemon --> client, see comments below */ \
|
|
X(ACK_DEVICE_STATUS) /* client --> daemon, body = ClientURN */ \
|
|
X(QUERY_STATS) /* client --> daemon, body = ClientURN */ \
|
|
X(ACK_QUERY_STATS) /* daemon --> client, see comments below */ \
|
|
X(PING) /* daemon --> client, body = ClientURN */ \
|
|
X(ACK_PING) /* client --> daemon, body = ClientURN */
|
|
|
|
enum
|
|
{
|
|
#define X(op) K2IPC_##op,
|
|
K2IPC_PACKET_OPCODES
|
|
#undef X
|
|
};
|
|
/*
|
|
Common packet body types:
|
|
-------------------------
|
|
ClientURN
|
|
Device URN for the client. It must be included in all packets sent to the
|
|
daemon since the daemon uses it to lookup the client's state data. It is
|
|
also included in all ACK packets as a sanity check (to quickly draw
|
|
attention to coding errors).
|
|
|
|
|
|
Packet types:
|
|
-------------------------
|
|
CONNECT (client --> daemon)
|
|
Initial connection from client, clears subscription lists (as a failsafe
|
|
in case a logout packet is dropped) and resets sequence numbers. Normally
|
|
the daemon replies with ACK_CONNECT. If the URN is already in use (is
|
|
associated with a different IP/port), the daemon replies with NAK_CONNECT
|
|
and sends a PING to the old IP/port for the URN. In response, the client
|
|
receiving the NAK_CONNECT should retry the CONNECT after enough time has
|
|
elapsed for the PING to result in success or a timeout. If the retry also
|
|
results in a NAK_CONNECT, this indicates that the URN is already in use on
|
|
another device. If the client that is attempting the CONNECT merely had
|
|
its IP/port changed (i.e. switching network connections on a mobile device),
|
|
the PING will timeout and the 2nd CONNECT will succeed.
|
|
|
|
ACK_CONNECT (daemon --> client)
|
|
Normal response to CONNECT (acknowledges receipt).
|
|
|
|
NAK_CONNECT (daemon --> client)
|
|
Exception response to CONNECT -- Indicates that URN may already be in use by
|
|
another client. Client should retry CONNECT once after waiting enough time
|
|
for the daemon's PING attempt to timeout. If it receives another
|
|
NAK_CONNECT, the URN is in use elsewhere.
|
|
|
|
MESSAGE (daemon --> client)
|
|
Body is a NUL-terminated string (ASCII or UTF-8) copied from the 'info' field
|
|
in the MongoDB notification queue.
|
|
|
|
ACK_MESSAGE (client --> daemon)
|
|
Acknowledges receipt of MESSAGE.
|
|
|
|
LOGOUT (client --> daemon)
|
|
Client disconnect. Sent without waiting for an ACK (to avoid keeping the
|
|
client awake when it is entering sleep or shutting down). If lost, the
|
|
disconnect occurs upon heartbeat timeout or failed message delivery attempt.
|
|
|
|
ACK_LOGOUT (daemon --> client)
|
|
Acknowledges receipt of LOGOUT.
|
|
|
|
POLL_DB (client --> daemon)
|
|
Only sent by the CloudGuard client. This message tells the daemon to poll
|
|
the notification queue in MongoDB. Repeated requests arriving within a 100ms
|
|
window are consolidated into a single poll.
|
|
|
|
ACK_POLL_DB (daemon --> client)
|
|
Acknowledges receipt of POLL_DB.
|
|
|
|
HEARTBEAT (client --> daemon)
|
|
Keepalive for "online" client status. Also keeps NAT forwarding open.
|
|
Other message types can substitute for a heartbeat. A heartbeat packet is
|
|
sent after an absence of any traffic for the heartbeat timer interval.
|
|
|
|
ACK_HEARTBEAT (daemon --> client)
|
|
Acknowledges receipt of HEARTBEAT.
|
|
|
|
SUBSCRIBE_OFFICE (client --> daemon)
|
|
Body consists of ClientURN string followed by K2IPC_URN_DELIMITER followed
|
|
by FragmentationDescriptor followed by OfficeURN_list. OfficeURN_list is a
|
|
comma-delimited list of office URNs. This string may be fragmented across
|
|
multiple packets as indicated by FragmentationDescriptor. When a complete
|
|
list of offices is received by the daemon, it "subscribes" the client to that
|
|
list of offices (replacing any previous subscriptions). An empty list
|
|
cancels subscriptions.
|
|
|
|
ACK_SUBSCRIBE_OFFICE (daemon --> client)
|
|
Acknowledges receipt of SUBSCRIBE_OFFICE.
|
|
|
|
DEVICE_STATUS (daemon --> client)
|
|
Body is a StatusString + K2IPC_STATUS_DELIMITER + DeviceURN, for example
|
|
"online:urn:sl:000000:F4685A6B:8F4D:". The status string may be either
|
|
"online" or "offline". Sent when the status of a device within a subscribed
|
|
office changes.
|
|
|
|
ACK_DEVICE_STATUS (client --> daemon)
|
|
Acknowledges receipt of DEVICE_STATUS.
|
|
|
|
QUERY_STATS (client --> daemon)
|
|
Requests daemon CPU and memory usage statistics.
|
|
|
|
ACK_QUERY_STATS (daemon --> client)
|
|
Acknowledges receipt of QUERY_STATS. Body is a JSON string containing daemon
|
|
CPU and memory usage statistics.
|
|
|
|
PING (daemon --> client)
|
|
Checks whether client is reachable.
|
|
|
|
ACK_PING (client --> daemon)
|
|
Acknowledges receipt of PING.
|
|
*/
|
|
|
|
/* FragmentationDescriptor */
|
|
enum
|
|
{
|
|
K2IPC_FRAGMENT_FIRST = 'A', /* first of multiple packets */
|
|
K2IPC_FRAGMENT_MIDDLE, /* one of multiple packets */
|
|
K2IPC_FRAGMENT_LAST, /* last of multiple packets */
|
|
K2IPC_FRAGMENT_SINGLE /* first and last packet (not fragmented) */
|
|
};
|
|
|
|
/* K2IPC_SUBSCRIBE_OFFICE */
|
|
#define K2CLI_CHAR_CONSTANTS_EXTRACT
|
|
#define K2IPC_URN_DELIMITER ','
|
|
#define K2IPC_OFFICE_DELIMITER ','
|
|
#undef K2CLI_CHAR_CONSTANTS_EXTRACT
|
|
|
|
/* K2IPC_DEVICE_STATUS */
|
|
#define K2CLI_CHAR_CONSTANTS_EXTRACT
|
|
#define K2IPC_STATUS_DELIMITER ':'
|
|
#undef K2CLI_CHAR_CONSTANTS_EXTRACT
|
|
#define K2CLI_STRING_CONSTANTS_EXTRACT
|
|
#define K2IPC_STATUS_ONLINE "online"
|
|
#define K2IPC_STATUS_OFFLINE "offline"
|
|
#undef K2CLI_STRING_CONSTANTS_EXTRACT
|
|
|
|
|
|
|
|
|
|
/*
|
|
---------------------------
|
|
Timing, retries, heartbeats
|
|
*/
|
|
|
|
/* how often the client sends a 'heartbeat' packet or other traffic */
|
|
#define K2CLI_HEARTBEAT_INTERVAL_SECONDS 27
|
|
|
|
/* for de-synchronization, heartbeats are sent at the nominal rate +/= <RANGE> chosen randomly */
|
|
#define K2CLI_HEARTBEAT_RANGE_SECONDS 2
|
|
|
|
/* how long the daemon waits for traffic before assuming that the client is gone */
|
|
#define K2CLI_HEARTBEAT_TIMEOUT_SECONDS 45
|
|
|
|
/*
|
|
tenths of seconds the client waits for an ACK before retrying
|
|
xxx_RETRY1_xxx is the delay from original packet to the first retry
|
|
xxx_RETRY2_xxx is the delay from original packet to the second retry
|
|
xxx_RETRY3_xxx is the delay from original packet to the third and final retry
|
|
*/
|
|
#define K2CLI_RETRY1_TENTHS_OF_SECONDS 7
|
|
#define K2CLI_RETRY2_TENTHS_OF_SECONDS 13
|
|
#define K2CLI_RETRY3_TENTHS_OF_SECONDS 25
|
|
|
|
/* how long the client waits for an ACK before reporting a lost connection */
|
|
#define K2CLI_RETRY3_TIMEOUT_TENTHS_OF_SECONDS 25
|
|
|
|
/*
|
|
tenths of seconds the daemon waits for an ACK before retrying
|
|
xxx_RETRY1_xxx is the delay from original packet to the first retry
|
|
xxx_RETRY2_xxx is the delay from original packet to the second retry
|
|
xxx_RETRY3_xxx is the delay from original packet to the third and final retry
|
|
*/
|
|
#define K2DMN_RETRY1_TENTHS_OF_SECONDS 7
|
|
#define K2DMN_RETRY2_TENTHS_OF_SECONDS 13
|
|
#define K2DMN_RETRY3_TENTHS_OF_SECONDS 25
|
|
|
|
/* how long the daemon waits for an ACK before assuming that the client is gone */
|
|
#define K2DMN_RETRY3_TIMEOUT_TENTHS_OF_SECONDS 25
|
|
|
|
|
|
|
|
|
|
/*
|
|
Default server port number
|
|
|
|
There is nothing special about this port number.
|
|
It can be overridden at runtime via command-line.
|
|
*/
|
|
#define K2CLI_INT_CONSTANTS_EXTRACT
|
|
#define K2IPC_DEFAULT_UDP_PORT 32000
|
|
#define K2IPC_DEFAULT_HTTP_PORT 8888
|
|
#define K2IPC_DEFAULT_HTTPS_PORT 8443
|
|
#undef K2CLI_INT_CONSTANTS_EXTRACT
|
|
|
|
|
|
/*
|
|
packet encryption/validation key and MIC
|
|
(for rejecting spurious packets from port scanners, etc)
|
|
*/
|
|
#define K2IPC_KEY_MIX_CYCLES 32
|
|
#define K2IPC_KEY_SIZE 32
|
|
#define K2IPC_KEY \
|
|
169, 208, 1, 214, 130, 153, 218, 176, 187, 115, 186, 84, 117, 25, 162, 197, \
|
|
173, 73, 161, 180, 68, 224, 62, 241, 192, 96, 152, 79, 148, 239, 20, 132
|
|
#define K2IPC_MIC 17, 44, 195, 238, 248, 76
|